#include "stm32f4_discovery.h"
#include "stm32f4xx_conf.h" // again, added because ST didn't put it here ?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include "usart.h"
#include "delay.h"

#include "etherShield/enc28j60.h"
#include "etherShield/ip_arp_udp_tcp.h"
#include "etherShield/ip_config.h"
#include "etherShield/dnslkup.h"
#include "etherShield/websrv_help_functions.h"
#include "etherShield/net.h"


//ENC28J60 spi ethernet
//check by nc -lup 10001 at the destination specified below
//todo: do arp query to get mac, try tcp and http as well

int main(void)
{
usart2_init(115200);
inuart2line=inuart2len=0;

//while(1) 
	{print(USART2, "\nspi ethernet test\n"); 
	uint32_t *p;
	p=0x1fffc01c;
	char z[64];
	sprintf(z, "option = %08x\n", *p);
	print(USART2,z);
	}

#define BUFFER_SIZE 250
static uint8_t buf[BUFFER_SIZE+1];

static uint8_t mymac[6] = {0x54,0x55,0x58,0x10,0x00,0x25};
static uint8_t dstmac[6] = {0x68,0xb5,0x99,0xf2,0x0f,0x58};
static uint8_t myip[4] = {192,168,0,201};
static uint8_t destip[4] = {192,168,0,20};

        
        uint16_t plen;
        uint8_t i=0;
        
        delay_ms(20);
        

        /*initialize enc28j60*/
        enc28j60Init(mymac);
        //enc28j60clkout(2); // we do not use clockout 
        delay_ms(10);
        
	/* Magjack leds configuration, see enc28j60 datasheet, page 11 */
	// LEDA=greed LEDB=yellow
	//
	// 0x880 is PHLCON LEDB=on, LEDA=on
	// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
	enc28j60PhyWrite(PHLCON,0x880);
	delay_ms(250); delay_ms(250);
	//
	// 0x990 is PHLCON LEDB=off, LEDA=off
	// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
	enc28j60PhyWrite(PHLCON,0x990);
	delay_ms(250); delay_ms(250);
	//
	// 0x880 is PHLCON LEDB=on, LEDA=on
	// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
	enc28j60PhyWrite(PHLCON,0x880);
	delay_ms(250); delay_ms(250);
	//
	// 0x990 is PHLCON LEDB=off, LEDA=off
	// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
	enc28j60PhyWrite(PHLCON,0x990);
	delay_ms(250); delay_ms(250);
	//
        // 0x476 is PHLCON LEDA=links status, LEDB=receive/transmit
        // enc28j60PhyWrite(PHLCON,0b0000 0100 0111 01 10);
        enc28j60PhyWrite(PHLCON,0x476);
	delay_ms(100);

        print(USART2,"here.\n");
        
        //init the ethernet/ip layer:
        init_ip_arp_udp_tcp(mymac,myip,80);

        print(USART2,"Init done.\n");

uint32_t ii= (uint32_t)-1;

        while(1)
        {
	++ii;
	delay_ms(1);
		//unsoliocited UDP send:

		if((ii&1023)==0)
			{
			print(USART2,"u");
		        uint16_t ck;
		memset(buf,0x00,BUFFER_SIZE); //cleanup
		memcpy(&buf[ETH_DST_MAC],dstmac,6);	
		memcpy(&buf[ETH_SRC_MAC],mymac,6);	
		buf[ETH_TYPE_H_P]=ETHTYPE_IP_H_V;
		buf[ETH_TYPE_L_P]=ETHTYPE_IP_L_V;
		memcpy(&buf[IP_SRC_P],myip,4);
		memcpy(&buf[IP_DST_P],destip,4);
		buf[IP_HEADER_LEN_VER_P]=0x45;
		buf[IP_PROTO_P]=IP_PROTO_UDP_V;

		short port = 10001;
		short port2 = 20001;
			// total length field in the IP header must be set:
       		  	uint8_t datalen=12;
			buf[IP_TOTLEN_H_P]=0;
		        buf[IP_TOTLEN_L_P]=IP_HEADER_LEN+UDP_HEADER_LEN+datalen;
		fill_ip_hdr_checksum(buf);

			buf[UDP_DST_PORT_H_P]=port>>8;
			buf[UDP_DST_PORT_L_P]=port & 0xff;
			buf[UDP_SRC_PORT_H_P]=port2>>8;	
			buf[UDP_SRC_PORT_L_P]=port2 & 0xff;
			// calculte the udp length:
			buf[UDP_LEN_H_P]=0;
        		buf[UDP_LEN_L_P]=UDP_HEADER_LEN+datalen;
			// zero the checksum
			buf[UDP_CHECKSUM_H_P]=0;
        		buf[UDP_CHECKSUM_L_P]=0;
			char teststr[12];
			strcpy(teststr,"TEST 0    \n");
			teststr[5]+= (ii>>10)%10;	
			strncpy(&buf[UDP_DATA_P],teststr,datalen);
			ck=checksum(&buf[IP_SRC_P], 16 + datalen,1);
        		buf[UDP_CHECKSUM_H_P]=ck>>8;
        		buf[UDP_CHECKSUM_L_P]=ck& 0xff;
        		enc28j60PacketSend(UDP_HEADER_LEN+IP_HEADER_LEN+ETH_HEADER_LEN+datalen,buf);
			}

                // get the next new packet:
                plen = enc28j60PacketReceive(BUFFER_SIZE, buf);

                /*plen will be unequal to zero if there is a valid 
                 * packet (without crc error) */
                if(plen==0){
                        continue;
                }

		print(USART2,"!\n");
                // arp is broadcast if unknown but a host may also // verify the mac address by sending it to // a unicast address.
                if(eth_type_is_arp_and_my_ip(buf,plen))
                        {
			print(USART2,"A\n");
                        make_arp_answer_from_request(buf);
                        continue;
                        }

                // check if ip packets (icmp or udp) are for us:
                if(eth_type_is_ip_and_my_ip(buf,plen)==0) continue;
		print(USART2,"P\n");
                        
                if(buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V){
                        // a ping packet, let's send pong
                        make_echo_reply_from_request(buf,plen);
			print(USART2,"R\n");
                        continue;
                        }

                // udp replies:
                if (buf[IP_PROTO_P]==IP_PROTO_UDP_V){
			print(USART2,"U\n");
                        uint16_t payloadlen=buf[UDP_LEN_L_P]-UDP_HEADER_LEN;
                        // the received command has to start with t and be 4 char long
                        // e.g "test\0"
                        if (buf[UDP_DATA_P]=='t' && payloadlen==5){
                                make_udp_reply_from_request(buf,"hello",6,1200);
                        	}
                }
        }//while
}


