#include "lwip/raw.h"
#include "lwip/err.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/init.h"
#include "lwipopts.h"
#include "lwip/err.h"
#include "lwipopts.h"
#include "netif/xadapter.h"

#include "xil_printf.h"
#include "sleep.h"
#include "stdlib.h"


struct raw_pcb * udpRawPcb, * tcpRawPcb;
struct netif* netif, server_netif;
ip_addr_t ipaddr, netmask, gw;
unsigned char mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 }; // MAC
uint32_t local_ip = 66;
uint32_t remote_ip = 106;



u8_t UdpRecvCallback(void *arg, struct raw_pcb *pcb, struct pbuf *p,
   const ip_addr_t *addr);

u8_t TcpRecvCallback(void *arg, struct raw_pcb *pcb, struct pbuf *p,
   const ip_addr_t *addr);


int main()
{
	netif = &server_netif;
	IP4_ADDR(&ipaddr, 192, 168, 1, local_ip);
	IP4_ADDR(&netmask, 255, 255, 255, 0);
	IP4_ADDR(&gw, 192, 168, 1, 1);

	lwip_init();
	if (!xemac_add(netif, &ipaddr, &netmask, &gw, mac_ethernet_address, XPAR_XEMACPS_0_BASEADDR))
	{
		xil_printf("Error adding N/W interface\r\n");
		return -1;
	} // add port
	netif_set_default(netif);
	netif_set_up(netif); // set up network

//
//	tcpRawPcb = raw_new(IP_PROTO_TCP);
//	if (!tcpRawPcb)
//	{
//		xil_printf("Error Creating TCP PCB.\r\n");
//		return -1;
//	}
//	udpRawPcb = raw_new(IP_PROTO_UDP);
//	raw_bind(udpRawPcb, IP_ADDR_ANY);
//	if (!udpRawPcb)
//	{
//		xil_printf("Error Creating UDP PCB.\r\n");
//		return -1;
//	}
//
//	raw_recv(udpRawPcb, UdpRecvCallback, NULL);
//	raw_recv(tcpRawPcb, TcpRecvCallback, NULL);


	// udp control
	struct udp_pcb * udpPcb = udp_new();
	// local port
	udp_bind(udpPcb,IP_ADDR_ANY,9000);

	uint8_t payload[1400];
	for(int i=0;i<1400;i++)
	{
		payload[i] = i ;
	}

	err_t err;
//	while(1)
//	{
//		usleep(1000);
////		struct pbuf* pbuf_to_be_sent = NULL;
////		pbuf_to_be_sent = pbuf_alloc(PBUF_IP, 1300, PBUF_POOL);
////		memcpy(pbuf_to_be_sent->payload , payload,1300);
//
//		struct pbuf* udp_pbuf_to_be_sent = NULL;
//		udp_pbuf_to_be_sent = pbuf_alloc(PBUF_TRANSPORT, 1300, PBUF_POOL);
//		memcpy(udp_pbuf_to_be_sent->payload , payload,1300);
//
//
////		err = raw_sendto(udpRawPcb,pbuf_to_be_sent,&addr_to_be_sent);
////		if (err != ERR_OK)
////		{
////			xil_printf("Error on udp send : %d\r\n", err);
////			pbuf_free(pbuf_to_be_sent);
////			return -1;
////		}
//		udp_sendto(udpPcb, udp_pbuf_to_be_sent, &addr_to_be_sent, 8090);
//		xemacif_input(netif);
//		pbuf_free(udp_pbuf_to_be_sent); // free pbuf
//        // push stack !!! this can't be delete, and must be in the while loop
//	}

	int data_num = 1024;
	while(1)
	{
		// pbuf
		struct pbuf* pbuf_to_be_sent = NULL;
		pbuf_to_be_sent = pbuf_alloc(PBUF_TRANSPORT, data_num, PBUF_POOL);
		memcpy(pbuf_to_be_sent->payload, (u8*)&paylaod, data_num);

		// send
		ip_addr_t addr_to_be_sent;
		IP4_ADDR(&addr_to_be_sent, 192, 168, 1, remote_ip);
		err = udp_sendto(udpPcb, pbuf_to_be_sent, &addr_to_be_sent, 8090);
		if (err != ERR_OK)
		{
			xil_printf("Error on udp send : %d\r\n", err);
			pbuf_free(pbuf_to_be_sent);
			return;
		}
		pbuf_free(pbuf_to_be_sent); // free pbuf
	}
	return 0;
}



u8_t UdpRecvCallback(void *arg, struct raw_pcb *pcb, struct pbuf *p,
   const ip_addr_t *addr)
{
	xil_printf("recv udp\r\n");
}

u8_t TcpRecvCallback(void *arg, struct raw_pcb *pcb, struct pbuf *p,
   const ip_addr_t *addr)
{
	xil_printf("recv tcp\r\n");
}
