#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;
uint16_t local_port = 8090;
uint16_t remote_port = 8090;


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

	err_t err;
	// udp control
	struct udp_pcb * udpPcb = udp_new();
	if (!udpPcb)
	{
		xil_printf("Error Creating PCB.\r\n");
		return -1;
	}
	// local port
	// local port
	err = udp_bind(udpPcb, IP_ADDR_ANY, local_port);
	if (err != ERR_OK)
	{
		xil_printf("Unable to bind to port %d\r\n", local_port);
		return -1;
	}

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

	int data_num = 1024;
	while(1)
	{
		usleep(100);
		// 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*)payload, 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  -1;
		}
		pbuf_free(pbuf_to_be_sent); // free pbuf
		xemacif_input(netif);
	}
	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");
}
