/*---------------------------------------------------------------------------------

	Adapted from Wntrmute's wifi demo

---------------------------------------------------------------------------------*/
#include "nds.h"
#include <nds/arm9/console.h> //basic print funcionality
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

#include "wifi.h"

//---------------------------------------------------------------------------------
// Dswifi stub functions
void * sgIP_malloc(int size) { return malloc(size); }
void sgIP_free(void * ptr) { free(ptr); }

// sgIP_dbgprint only needed in debug version
void sgIP_dbgprint(char * txt, ...) {
}

// wifi timer function, to update internals of sgIP
void Timer_50ms(void) {
   Wifi_Timer(50);
}

// notification function to send fifo message to arm7
void arm9_synctoarm7() { // send fifo message
   REG_IPC_FIFO_TX=0x87654321;
}

// interrupt handler to receive fifo messages from arm7
void arm9_fifo() { // check incoming fifo messages
   u32 value = REG_IPC_FIFO_RX;
   if(value == 0x87654321) Wifi_Sync();
}

//---------------------------------------------------------------------------------
void init_wifi(void) {
//---------------------------------------------------------------------------------

	{ // send fifo message to initialize the arm7 wifi
		REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_SEND_CLEAR; // enable & clear FIFO
		
		u32 Wifi_pass= Wifi_Init(WIFIINIT_OPTION_USELED);
	   	REG_IPC_FIFO_TX=0x12345678;
	   	REG_IPC_FIFO_TX=Wifi_pass;
   		
		*((volatile u16 *)0x0400010E) = 0; // disable timer3
		
		irqSet(IRQ_TIMER3, Timer_50ms); // setup timer IRQ
		irqEnable(IRQ_TIMER3);
	   	irqSet(IRQ_FIFO_NOT_EMPTY, arm9_fifo); // setup fifo IRQ
	   	irqEnable(IRQ_FIFO_NOT_EMPTY);
   		
	   	REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_RECV_IRQ; // enable FIFO IRQ
   		
	   	Wifi_SetSyncHandler(arm9_synctoarm7); // tell wifi lib to use our handler to notify arm7
		
		// set timer3
		*((volatile u16 *)0x0400010C) = -6553; // 6553.1 * 256 cycles = ~50ms;
		*((volatile u16 *)0x0400010E) = 0x00C2; // enable, irq, 1/256 clock
		
		while(Wifi_CheckInit()==0) { // wait for arm7 to be initted successfully
			while(VCOUNT>192); // wait for vblank
			while(VCOUNT<192);
		}
		
	} // wifi init complete - wifi lib can now be used!
	
	iprintf("Connecting using WFC data...\n");
	{ // simple WFC connect:
		int i;
		Wifi_AutoConnect(); // request connect
		while(1) {
			i=Wifi_AssocStatus(); // check status
			if(i==ASSOCSTATUS_ASSOCIATED) {
				iprintf("Connected successfully!\n");
				break;
			}
			if(i==ASSOCSTATUS_CANNOTCONNECT) {
				iprintf("Could not connect!\n");
				break;
			}
		}
	} // if connected, you can now use the berkley sockets interface to connect to the internet!
}

struct sockaddr_in ser_addr;
int conn;
void init_udp_connection(void)
{
	struct hostent *hp;
	char buf[16];
	uint32 my_ip;
	
	bzero((char *)&ser_addr, sizeof(ser_addr));
	ser_addr.sin_family = AF_INET;
	ser_addr.sin_port = htons(1234);
	// get the broadcast address of my network
	my_ip = Wifi_GetIP();
	sprintf(buf, "%d.%d.%d.255", my_ip & 0xFF, (my_ip >> 8) & 0xFF, (my_ip >> 16) & 0xFF);
	hp = gethostbyname(buf);
	ser_addr.sin_addr = *(struct in_addr *)hp->h_addr_list[0];
	conn = socket(PF_INET, SOCK_DGRAM, 0);
}

void sendpacket(char *packet)
{
	sendto(conn, packet, strlen(packet), 0, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
}

void my_ip(char *addr)
{
	uint32 my_ip;
	my_ip = Wifi_GetIP();
	sprintf(addr, "%d.%d.%d.%d", my_ip & 0xFF, (my_ip >> 8) & 0xFF, (my_ip >> 16) & 0xFF, (my_ip >> 24) & 0xFF);
}

struct sockaddr_in ser_addr2;
int conn2;
void init_udp_connection_out(void)
{
	int stuff = 1;
	bzero((char *)&ser_addr2, sizeof(ser_addr2));
	ser_addr2.sin_family = AF_INET;
	ser_addr2.sin_port = htons(1235);
	ser_addr2.sin_addr.s_addr = htonl(INADDR_ANY);
	conn2 = socket(PF_INET, SOCK_DGRAM, 0);
	// use ioctl rather than fcntl to set non-blocking
	if (ioctl(conn2, FIONBIO, &stuff) < 0)
	{
     		iprintf("\x1b[10;0HSocket flag set failed: %d\n", FIONBIO);
		while(1);
	}
	bind(conn2, (struct sockaddr *)&ser_addr2, sizeof(ser_addr2));
}

#define BUFF_LEN 1024
char buffIn[BUFF_LEN];
int len;
int nr=0;
int sain_len;
struct sockaddr_in sender;
void receivepackets(char *args[])
{
	int rv;
	fd_set readfds;
	struct timeval tv;
	
	FD_ZERO(&readfds);
	FD_SET(conn2, &readfds);
	
	tv.tv_sec = 0;
	tv.tv_usec = 0;
	rv = select(conn2 + 1, &readfds, NULL, NULL, &tv);
	
	if (rv == -1)
	{
		iprintf("Socket polling error.\n"); // error occurred in poll()
	}
	else if (rv > 0)
	{
		if (FD_ISSET(conn2, &readfds))
		{
			sain_len=sizeof(sender);
			nr = recvfrom(conn2, buffIn, sizeof(buffIn), 0, (struct sockaddr *)&sender, &sain_len);
			
			if (nr > 0)
			{
				buffIn[nr] = '\0';
				tokenise(buffIn, args);
			}
			else
			{
				buffIn[0] = '\0';
				args[0] = NULL;
			}
		}
	}
}

