/********************************************************************
 * Project:    GNU-Port (STR9-comStick)
 * File:       Ethernet_main.c
 *
 * System:     ARM9TDMI 32 Bit (STR912FW44X)
 * Compiler:   GCC 4.0.3
 *
 * Date:       2006-12-20
 * Author:     Application@Hitex.de
 *
 * Rights:     Hitex Development Tools GmbH
 *             Greschbachstr. 12
 *             D-76229 Karlsruhe
 ********************************************************************
 * Description:
 *
 * This file is part of the GNU Example chain
 * The code is based on usage of the STmicro library functions
 * This is a small implementation of different features
 * The application runs in ARM mode with high optimization level.
 * used IP stack (uIP) is originated by Adam Dunkels.
 *
 ********************************************************************
 * History:
 *
 *    Revision 1.0    2007/02/19      Gn
 *    Revision 1.0    2006/12/20      Gn
 *    Initial revision
 ********************************************************************
 * This is a preliminary version.
 *
 * WARRANTY:  HITEX warrants that the media on which the SOFTWARE is
 * furnished is free from defects in materials and workmanship under
 * normal use and service for a period of ninety (90) days. HITEX entire
 * liability and your exclusive remedy shall be the replacement of the
 * SOFTWARE if the media is defective. This Warranty is void if failure
 * of the media resulted from unauthorized modification, accident, abuse,
 * or misapplication.
 *
 * DISCLAIMER:  OTHER THAN THE ABOVE WARRANTY, THE SOFTWARE IS FURNISHED
 * "AS IS" WITHOUT WARRANTY OF ANY KIND. HITEX DISCLAIMS ALL OTHER WARRANTIES,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * NEITHER HITEX NOR ITS AFFILIATES SHALL BE LIABLE FOR ANY DAMAGES ARISING
 * OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE, INCLUDING DAMAGES FOR
 * LOSS OF PROFITS, BUSINESS INTERRUPTION, OR ANY SPECIAL, INCIDENTAL, INDIRECT
 * OR CONSEQUENTIAL DAMAGES EVEN IF HITEX HAS BEEN ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGES.
 ********************************************************************/

#include "uip.h"
#include "uip_arp.h"
#include "httpd.h"
#include "91x_enet.h"
#include "uart.h"

// Define NULL
#ifndef NULL
#define NULL (void *)0
#endif

// Globals
extern  char gPacketReceived;
uip_eth_hdr *BUF = (uip_eth_hdr*)uip_buf;
u8_t arptimer;
uip_ipaddr_t ipaddr;

u8 def_IPaddr[4] = {192,168,16,20};
u8 def_DRIPaddr[4] = {192,168,16,1};

u8 def_Mask[4] = {255,255,255,0};

TaskInfo EthState;

/* The start of the uIP buffer, which will contain the frame headers. */
#define pucUIP_Buffer ( ( struct uip_eth_hdr * ) &uip_buf[ 0 ] )

/* uIP update frequencies. */
#define RT_CLOCK_SECOND      ( configTICK_RATE_HZ  )
#define uipARP_FREQUENCY     ( 20 )
#define uipMAX_BLOCK_TIME    ( RT_CLOCK_SECOND / 4 )

// Define Prototypes
void TransmitPacket(void);

/*-----------------------------------------------------------------------------------*/
void uIPStart(void)
{
 
   /* Initialize the uIP TCP/IP stack. */
   uip_init();
   /* Initialize the uIP TCP/IP stack. */
   uip_ipaddr(ipaddr,def_IPaddr[0],def_IPaddr[1],def_IPaddr[2],def_IPaddr[3]);
   uip_sethostaddr(ipaddr);
   uip_ipaddr(ipaddr,def_DRIPaddr[0],def_DRIPaddr[1],def_DRIPaddr[2],def_DRIPaddr[3]);
   uip_setdraddr(ipaddr);
   uip_ipaddr(ipaddr,def_Mask[0],def_Mask[1],def_Mask[2],def_Mask[3]);
   uip_setnetmask(ipaddr);
   uip_arp_init();
   /* Initialize the HTTP server. */
   httpd_init();

   arptimer = 0;
   EthState.enabled = TRUE;
}
void Ethernet (void)
{
//   while (1)//if (EthState.enabled)
   {
      u8_t i = 0;
      u32 size;
      /* Let the tapdev network device driver read an entire IP packet
       into the uip_buf. If it must wait for more than 0.5 seconds, it
       will return with the return value 0. If so, we know that it is
       time to call upon the uip_periodic(). Otherwise, the tapdev has
       received an IP packet that is to be processed by uIP. */

      size = ENET_HandleRxPkt(uip_buf);

      if (size > 0)
        uip_len = size;

      if(uip_len <= 0x0)
      {
         for(i = 0; i < UIP_CONNS; i++)
         {
            uip_periodic(i);

            /* If the above function invocation resulted in data that
            should be sent out on the network, the global variable
            uip_len is set to a value > 0. */

            if(uip_len > 0)
            {
               uip_arp_out();
               TransmitPacket();
            }
         }

#if UIP_UDP
      for(i = 0; i < UIP_UDP_CONNS; i++)
      {
         uip_udp_periodic(i);
         /* If the above function invocation resulted in data that
         should be sent out on the network, the global variable
         uip_len is set to a value > 0. */
         if(uip_len > 0)
         {
            uip_arp_out();
            TransmitPacket();
         }
      }
#endif /* UIP_UDP */

         /* Call the ARP timer function every 10 seconds. */
         if(++arptimer == 20)
         {   
            uip_arp_timer();
            arptimer = 0;
         }
      }

      else
      {
         if(BUF->type == htons(UIP_ETHTYPE_IP))
         {
            uip_arp_ipin();
            uip_input();

            /* If the above function invocation resulted in data that
            should be sent out on the network, the global variable
            uip_len is set to a value > 0. */
            if(uip_len > 0)
            {
               uip_arp_out();
               TransmitPacket();
            }
         }
         else if(BUF->type == htons(UIP_ETHTYPE_ARP))
         {
            uip_arp_arpin();

            /* If the above function invocation resulted in data that
            should be sent out on the network, the global variable
            uip_len is set to a value > 0. */   
            if(uip_len > 0)
            {
               TransmitPacket();
            }
         }
      }
   }
}


/*-----------------------------------------------------------------------------------*/

void TransmitPacket(void)
{
   int i;
   u8 data[1500];

   // Copy the header portion part
   for(i=0; i < (UIP_LLH_LEN + 40); ++i) {
      data[i] =  uip_buf[i];
   }

   // Copy the data portion part
   for(; i < uip_len; ++i) {
      data[i] =  uip_appdata[i - UIP_LLH_LEN - 40 ];
   }

   ENET_TxPkt(&data,uip_len);
}

/*-----------------------------------------------------------------------------------*/
void uip_log(char *m)
{
  //printf("uIP log message: %s\n", m);
}

void udp_appcall(void)
{
}


/*-----------------------------------------------------------------------------------*/

void CommmEth (void)
{
   CommTask->CommandNew = FALSE;
   switch (CommTask->Command) {
    case Cmd_Get_req_Eth : /* GUI   Status request of the Eth enabled */
                           SendTask->ReplyNew = TRUE;
                           SendTask->Command = Rep_Info_Eth;  /* App   Eth state */
                           SendTask->DataLength = 1;
                           SendTask->Data[0] = (u8)EthState.enabled+1;
                           break;
    case Cmd_Get_req_MAC : /* GUI   Status request of the MAC address */
                           SendTask->ReplyNew = TRUE;
                           SendTask->Command = Rep_Info_MAC;  /*   App   Eth MAC settings */
                           SendTask->DataLength = 6;
                           SendTask->Data[0] = uip_ethaddr.addr[0];
                           SendTask->Data[1] = uip_ethaddr.addr[1];
                           SendTask->Data[2] = uip_ethaddr.addr[2];
                           SendTask->Data[3] = uip_ethaddr.addr[3];
                           SendTask->Data[4] = uip_ethaddr.addr[4];
                           SendTask->Data[5] = uip_ethaddr.addr[5];
                           break;
    case Cmd_Get_req_IP  : /* GUI   Status request of the IP address */
                           SendTask->ReplyNew = TRUE;
                           SendTask->Command = Rep_Info_IP; /* App   Eth IP settings */
                           SendTask->DataLength = 4;
                           SendTask->Data[0] = def_IPaddr[0];
                           SendTask->Data[1] = def_IPaddr[1];
                           SendTask->Data[2] = def_IPaddr[2];
                           SendTask->Data[3] = def_IPaddr[3];
                           break;
    case Cmd_Get_req_Mask: /* GUI   Status request of the SubnetMask */
                           SendTask->ReplyNew = TRUE;
                           SendTask->Command = Rep_Info_Mask; /*   App   Subnet mask settings */
                           SendTask->DataLength = 4;
                           SendTask->Data[0] = def_Mask[0];
                           SendTask->Data[1] = def_Mask[1];
                           SendTask->Data[2] = def_Mask[2];
                           SendTask->Data[3] = def_Mask[3];
                           break;
    case Cmd_Set_MAC     : /*   GUI   Set the MAC address */
                           SendTask->ReplyNew = FALSE;
                           uip_ethaddr.addr[0] = CommTask->Data[0];
                           uip_ethaddr.addr[1] = CommTask->Data[1];
                           uip_ethaddr.addr[2] = CommTask->Data[2];
                           uip_ethaddr.addr[3] = CommTask->Data[3];
                           uip_ethaddr.addr[4] = CommTask->Data[4];
                           uip_ethaddr.addr[5] = CommTask->Data[5];
                           break;
    case Cmd_Set_Mask    : /*   GUI   Set the Subnet mask */
                           SendTask->ReplyNew = FALSE;
                           uip_ipaddr(ipaddr,CommTask->Data[0],CommTask->Data[1],CommTask->Data[2],CommTask->Data[3]);
                           uip_setnetmask(ipaddr);
                           break;
    case Cmd_Set_IP      : /* GUI   Set the IP address */
                           SendTask->ReplyNew = FALSE;
                           uip_ipaddr(ipaddr,CommTask->Data[0],CommTask->Data[1],CommTask->Data[2],CommTask->Data[3]);
                           uip_sethostaddr(ipaddr);
                           def_IPaddr[0] = CommTask->Data[0];
                           def_IPaddr[1] = CommTask->Data[1];
                           def_IPaddr[2] = CommTask->Data[2];
                           def_IPaddr[3] = CommTask->Data[3];
                           break;
    case Cmd_Enable_Eth  : /* GUI   Start/Stop the Ethernet */
                           SendTask->ReplyNew = FALSE;
                           if (CommTask->Data[0] == TaskSwitchOn)
                              {
                              uIPStart();
                              }
                           else
                              {
                              EthState.enabled = FALSE;
                              }
                           break;
    case Cmd_Get_DefRoute : 
                           SendTask->ReplyNew = TRUE;
                           SendTask->Command = Rep_Info_DefRoute; /*   App   default router settings */
                           SendTask->DataLength = 4;
                           SendTask->Data[0] = def_DRIPaddr[0];
                           SendTask->Data[1] = def_DRIPaddr[1];
                           SendTask->Data[2] = def_DRIPaddr[2];
                           SendTask->Data[3] = def_DRIPaddr[3];
                           break;
    case Cmd_Set_DefRoute :
                           SendTask->ReplyNew = FALSE;
                           def_DRIPaddr[0] = CommTask->Data[0];
                           def_DRIPaddr[1] = CommTask->Data[1];
                           def_DRIPaddr[2] = CommTask->Data[2];
                           def_DRIPaddr[3] = CommTask->Data[3];
                           uip_ipaddr(ipaddr, CommTask->Data[0],CommTask->Data[1],CommTask->Data[2],CommTask->Data[3]);
                           uip_setnetmask(ipaddr);
                           break;                       
    default :              break;                       
    }
}
