]> git.sur5r.net Git - freertos/blobdiff - Demo/CORTEX_A2F200_IAR_and_Keil/uIP_Task.c
Move the MSVC/lwIP code into the main line.
[freertos] / Demo / CORTEX_A2F200_IAR_and_Keil / uIP_Task.c
index 914e570a54be53b36d4bfab7657ae7cc7bc24f28..58e0ca9a9f0cabad1fca317240d1f6eb798d8fd3 100644 (file)
@@ -1,6 +1,5 @@
-unsigned long ulRxed = 0, ulRxISR = 0, ulTxed = 0, ulTxISR = 0;\r
 /*\r
-    FreeRTOS V7.0.0 - Copyright (C) 2011 Real Time Engineers Ltd.\r
+    FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
        \r
 \r
     ***************************************************************************\r
@@ -75,27 +74,25 @@ unsigned long ulRxed = 0, ulRxISR = 0, ulTxed = 0, ulTxISR = 0;
 #include "mss_ethernet_mac_regs.h"\r
 #include "mss_ethernet_mac.h"\r
 \r
-/* The buffer used by the uIP stack to both receive and send.  This points to\r
-one of the Ethernet buffers when its actually in use. */\r
+/* The buffer used by the uIP stack to both receive and send.  In this case,\r
+because the Ethernet driver has been modified to be zero copy - the uip_buf\r
+variable is just a pointer to an Ethernet buffer, and not a buffer in its own\r
+right. */\r
 extern unsigned char *uip_buf;\r
 \r
-static const unsigned char ucMACAddress[] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 };\r
-\r
+/* The ARP timer and the periodic timer share a callback function, so the\r
+respective timer IDs are used to determine which timer actually expired.  These\r
+constants are assigned to the timer IDs. */\r
 #define uipARP_TIMER                           0\r
 #define uipPERIODIC_TIMER                      1\r
 \r
+/* The length of the queue used to send events from timers or the Ethernet\r
+driver to the uIP stack. */\r
 #define uipEVENT_QUEUE_LENGTH          10\r
 \r
-#define uipETHERNET_RX_EVENT           0x01UL\r
-#define        uipETHERNET_TX_EVENT            0x02UL\r
-#define uipARP_TIMER_EVENT                     0x04UL\r
-#define uipPERIODIC_TIMER_EVENT                0x08UL\r
-#define uipAPPLICATION_SEND_EVENT      0x10UL\r
-\r
+/* A block time of zero simply means "don't block". */\r
 #define uipDONT_BLOCK                          0UL\r
 \r
-/*-----------------------------------------------------------*/\r
-\r
 /* How long to wait before attempting to connect the MAC again. */\r
 #define uipINIT_WAIT    ( 100 / portTICK_RATE_MS )\r
 \r
@@ -123,6 +120,10 @@ static void prvInitialise_uIP( void );
  */\r
 static void prvEMACEventListener( unsigned long ulISREvents );\r
 \r
+/*\r
+ * The callback function that is assigned to both the periodic timer and the\r
+ * ARP timer.\r
+ */\r
 static void prvUIPTimerCallback( xTimerHandle xTimer );\r
 \r
 /*\r
@@ -130,14 +131,16 @@ static void prvUIPTimerCallback( xTimerHandle xTimer );
  */\r
 static void prvInitEmac( void );\r
 \r
+/*\r
+ * Write data to the Ethener.  Note that this actually writes data twice for the\r
+ * to get around delayed ack issues when communicating with a non real-time\r
+ * peer (for example, a Windows machine).\r
+ */\r
 void vEMACWrite( void );\r
 \r
-long lEMACWaitForLink( void );\r
-\r
 /*\r
  * Port functions required by the uIP stack.\r
  */\r
-void clock_init( void );\r
 clock_time_t clock_time( void );\r
 \r
 /*-----------------------------------------------------------*/\r
@@ -145,14 +148,6 @@ clock_time_t clock_time( void );
 /* The queue used to send TCP/IP events to the uIP stack. */\r
 xQueueHandle xEMACEventQueue = NULL;\r
 \r
-static unsigned long ulUIP_Events = 0UL;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void clock_init(void)\r
-{\r
-       /* This is done when the scheduler starts. */\r
-}\r
 /*-----------------------------------------------------------*/\r
 \r
 clock_time_t clock_time( void )\r
@@ -164,84 +159,94 @@ clock_time_t clock_time( void )
 void vuIP_Task( void *pvParameters )\r
 {\r
 portBASE_TYPE i;\r
-unsigned long ulNewEvent;\r
+unsigned long ulNewEvent = 0UL, ulUIP_Events = 0UL;\r
+long lPacketLength;\r
 \r
+       /* Just to prevent compiler warnings about the unused parameter. */\r
        ( void ) pvParameters;\r
 \r
        /* Initialise the uIP stack, configuring for web server usage. */\r
        prvInitialise_uIP();\r
 \r
-       /* Initialise the MAC. */\r
+       /* Initialise the MAC and PHY. */\r
        prvInitEmac();\r
 \r
        for( ;; )\r
        {\r
-               if( ( ulUIP_Events & uipETHERNET_RX_EVENT ) != 0UL )\r
-               {\r
-                       ulUIP_Events &= ~uipETHERNET_RX_EVENT;\r
+               /* Is there received data ready to be processed? */\r
+               lPacketLength = MSS_MAC_rx_packet();\r
 \r
-                       /* Is there received data ready to be processed? */\r
-                       uip_len = MSS_MAC_rx_packet();\r
-\r
-                       if( ( uip_len > 0 ) && ( uip_buf != NULL ) )\r
+               /* Statements to be executed if data has been received on the Ethernet. */\r
+               if( ( lPacketLength > 0 ) && ( uip_buf != NULL ) )\r
+               {\r
+                       uip_len = ( u16_t ) lPacketLength;\r
+                       \r
+                       /* Standard uIP loop taken from the uIP manual. */\r
+                       if( xHeader->type == htons( UIP_ETHTYPE_IP ) )\r
                        {\r
-                               ulRxed++;\r
-                               /* Standard uIP loop taken from the uIP manual. */\r
-                               if( xHeader->type == htons( UIP_ETHTYPE_IP ) )\r
-                               {\r
-                                       uip_arp_ipin();\r
-                                       uip_input();\r
+                               uip_arp_ipin();\r
+                               uip_input();\r
 \r
-                                       /* If the above function invocation resulted in data that\r
-                                       should be sent out on the network, the global variable\r
-                                       uip_len is set to a value > 0. */\r
-                                       if( uip_len > 0 )\r
-                                       {\r
-                                               uip_arp_out();\r
-                                               vEMACWrite();\r
-                                       }\r
-                               }\r
-                               else if( xHeader->type == htons( UIP_ETHTYPE_ARP ) )\r
+                               /* If the above function invocation resulted in data that\r
+                               should be sent out on the network, the global variable\r
+                               uip_len is set to a value > 0. */\r
+                               if( uip_len > 0 )\r
                                {\r
-                                       uip_arp_arpin();\r
+                                       uip_arp_out();\r
+                                       vEMACWrite();\r
+                               }\r
+                       }\r
+                       else if( xHeader->type == htons( UIP_ETHTYPE_ARP ) )\r
+                       {\r
+                               uip_arp_arpin();\r
 \r
-                                       /* If the above function invocation resulted in data that\r
-                                       should be sent out on the network, the global variable\r
-                                       uip_len is set to a value > 0. */\r
-                                       if( uip_len > 0 )\r
-                                       {\r
-                                               vEMACWrite();\r
-                                       }\r
+                               /* If the above function invocation resulted in data that\r
+                               should be sent out on the network, the global variable\r
+                               uip_len is set to a value > 0. */\r
+                               if( uip_len > 0 )\r
+                               {\r
+                                       vEMACWrite();\r
                                }\r
                        }\r
                }\r
+               else\r
+               {\r
+                       /* Clear the RX event latched in ulUIP_Events - if one was latched. */\r
+                       ulUIP_Events &= ~uipETHERNET_RX_EVENT;\r
+               }\r
 \r
+               /* Statements to be executed if the TCP/IP period timer has expired. */\r
                if( ( ulUIP_Events & uipPERIODIC_TIMER_EVENT ) != 0UL )\r
                {\r
                        ulUIP_Events &= ~uipPERIODIC_TIMER_EVENT;\r
 \r
-                       for( i = 0; i < UIP_CONNS; i++ )\r
+                       if( uip_buf != NULL )\r
                        {\r
-                               uip_periodic( i );\r
-\r
-                               /* If the above function invocation resulted in data that\r
-                               should be sent out on the network, the global variable\r
-                               uip_len is set to a value > 0. */\r
-                               if( uip_len > 0 )\r
+                               for( i = 0; i < UIP_CONNS; i++ )\r
                                {\r
-                                       uip_arp_out();\r
-                                       vEMACWrite();\r
+                                       uip_periodic( i );\r
+       \r
+                                       /* If the above function invocation resulted in data that\r
+                                       should be sent out on the network, the global variable\r
+                                       uip_len is set to a value > 0. */\r
+                                       if( uip_len > 0 )\r
+                                       {\r
+                                               uip_arp_out();\r
+                                               vEMACWrite();\r
+                                       }\r
                                }\r
                        }\r
                }\r
 \r
-               /* Call the ARP timer function every 10 seconds. */\r
+               /* Statements to be executed if the ARP timer has expired. */\r
                if( ( ulUIP_Events & uipARP_TIMER_EVENT ) != 0 )\r
                {\r
                        ulUIP_Events &= ~uipARP_TIMER_EVENT;\r
                        uip_arp_timer();\r
                }\r
 \r
+               /* If all latched events have been cleared - block until another event\r
+               occurs. */\r
                if( ulUIP_Events == pdFALSE )\r
                {\r
                        xQueueReceive( xEMACEventQueue, &ulNewEvent, portMAX_DELAY );\r
@@ -266,49 +271,6 @@ struct uip_eth_addr xAddr;
 }\r
 /*-----------------------------------------------------------*/\r
 \r
-void vApplicationProcessFormInput( char *pcInputString )\r
-{\r
-char *c;\r
-\r
-       /* Only interested in processing form input if this is the IO page. */\r
-       c = strstr( pcInputString, "io.shtml" );\r
-       \r
-       if( c )\r
-       {\r
-               /* Is there a command in the string? */\r
-               c = strstr( pcInputString, "?" );\r
-           if( c )\r
-           {\r
-                       /* Turn the LED's on or off in accordance with the check box status. */\r
-                       if( strstr( c, "LED0=1" ) != NULL )\r
-                       {\r
-                               /* Turn the LEDs on. */\r
-                               vParTestSetLED( 7, 1 );\r
-                               vParTestSetLED( 8, 1 );\r
-                               vParTestSetLED( 9, 1 );\r
-                               vParTestSetLED( 10, 1 );\r
-                       }\r
-                       else\r
-                       {\r
-                               /* Turn the LEDs off. */\r
-                               vParTestSetLED( 7, 0 );\r
-                               vParTestSetLED( 8, 0 );\r
-                               vParTestSetLED( 9, 0 );\r
-                               vParTestSetLED( 10, 0 );\r
-                       }\r
-           }\r
-               else\r
-               {\r
-                       /* Commands to turn LEDs off are not always explicit. */\r
-                       vParTestSetLED( 7, 0 );\r
-                       vParTestSetLED( 8, 0 );\r
-                       vParTestSetLED( 9, 0 );\r
-                       vParTestSetLED( 10, 0 );\r
-               }\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
 static void prvInitialise_uIP( void )\r
 {\r
 uip_ipaddr_t xIPAddr;\r
@@ -326,23 +288,26 @@ xTimerHandle xARPTimer, xPeriodicTimer;
        xEMACEventQueue = xQueueCreate( uipEVENT_QUEUE_LENGTH, sizeof( unsigned long ) );\r
 \r
        /* Create and start the uIP timers. */\r
-       xARPTimer = xTimerCreate(       ( const signed char * const ) "ARPTimer", /* Just a name that is helpful for debugging, not used by the kernel. */\r
-                                                               ( 500 / portTICK_RATE_MS ), /* Timer period. */\r
+       xARPTimer = xTimerCreate(       ( signed char * ) "ARPTimer", /* Just a name that is helpful for debugging, not used by the kernel. */\r
+                                                               ( 10000UL / portTICK_RATE_MS ), /* Timer period. */\r
                                                                pdTRUE, /* Autor-reload. */\r
                                                                ( void * ) uipARP_TIMER,\r
                                                                prvUIPTimerCallback\r
                                                        );\r
 \r
-       xPeriodicTimer = xTimerCreate(  ( const signed char * const ) "PeriodicTimer",\r
-                                                                       ( 5000 / portTICK_RATE_MS ),\r
+       xPeriodicTimer = xTimerCreate(  ( signed char * ) "PeriodicTimer",\r
+                                                                       ( 500UL / portTICK_RATE_MS ),\r
                                                                        pdTRUE, /* Autor-reload. */\r
                                                                        ( void * ) uipPERIODIC_TIMER,\r
                                                                        prvUIPTimerCallback\r
                                                                );\r
 \r
+       /* Sanity check that the timers were indeed created. */\r
        configASSERT( xARPTimer );\r
        configASSERT( xPeriodicTimer );\r
 \r
+       /* These commands will block indefinitely until they succeed, so there is\r
+       no point in checking their return values. */\r
        xTimerStart( xARPTimer, portMAX_DELAY );\r
        xTimerStart( xPeriodicTimer, portMAX_DELAY );\r
 }\r
@@ -351,26 +316,21 @@ xTimerHandle xARPTimer, xPeriodicTimer;
 static void prvEMACEventListener( unsigned long ulISREvents )\r
 {\r
 long lHigherPriorityTaskWoken = pdFALSE;\r
-unsigned long ulUIPEvents = 0UL;\r
+const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;\r
 \r
+       /* Sanity check that the event queue was indeed created. */\r
        configASSERT( xEMACEventQueue );\r
 \r
        if( ( ulISREvents & MSS_MAC_EVENT_PACKET_SEND ) != 0UL )\r
        {\r
-               ulTxISR++;\r
-               MSS_MAC_TxBufferCompleted();\r
+               /* An Ethernet Tx event has occurred. */\r
+               MSS_MAC_FreeTxBuffers();\r
        }\r
 \r
        if( ( ulISREvents & MSS_MAC_EVENT_PACKET_RECEIVED ) != 0UL )\r
        {\r
-               ulRxISR++;\r
-               /* Wake the uIP task as new data has arrived. */\r
-               ulUIPEvents |= uipETHERNET_RX_EVENT;\r
-       }\r
-\r
-       if( ulUIPEvents != 0UL )\r
-       {\r
-               xQueueSendFromISR( xEMACEventQueue, &ulUIPEvents, &lHigherPriorityTaskWoken );\r
+               /* An Ethernet Rx event has occurred. */\r
+               xQueueSendFromISR( xEMACEventQueue, &ulRxEvent, &lHigherPriorityTaskWoken );\r
        }\r
 \r
        portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );\r
@@ -381,8 +341,11 @@ static void prvInitEmac( void )
 {\r
 const unsigned char ucPHYAddress = 1;\r
 \r
+       /* Initialise the MAC and PHY hardware. */\r
        MSS_MAC_init( ucPHYAddress );\r
 \r
+       /* Register the event listener.  The Ethernet interrupt handler will call\r
+       this listener whenever an Rx or a Tx interrupt occurs. */\r
        MSS_MAC_set_callback( ( MSS_MAC_callback_t ) prvEMACEventListener );\r
 \r
     /* Setup the EMAC and the NVIC for MAC interrupts. */\r
@@ -395,13 +358,16 @@ void vEMACWrite( void )
 {\r
 const long lMaxAttempts = 10;\r
 long lAttempt;\r
-const portTickType xShortDelay = ( 10 / portTICK_RATE_MS );\r
+const portTickType xShortDelay = ( 5 / portTICK_RATE_MS );\r
 \r
+       /* Try to send data to the Ethernet.  Keep trying for a while if data cannot\r
+       be sent immediately.  Note that this will actually cause the data to be sent\r
+       twice to get around delayed ACK problems when communicating with non real-\r
+       time TCP/IP stacks (such as a Windows machine). */\r
        for( lAttempt = 0; lAttempt < lMaxAttempts; lAttempt++ )\r
        {\r
                if( MSS_MAC_tx_packet( uip_len ) != 0 )\r
                {\r
-                       ulTxed++;\r
                        break;\r
                }\r
                else\r
@@ -412,28 +378,14 @@ const portTickType xShortDelay = ( 10 / portTICK_RATE_MS );
 }\r
 /*-----------------------------------------------------------*/\r
 \r
-long lEMACWaitForLink( void )\r
-{\r
-long lReturn = pdFAIL;\r
-unsigned long ulStatus;\r
-\r
-       ulStatus = MSS_MAC_link_status();\r
-       if( ( ulStatus & ( unsigned long ) MSS_MAC_LINK_STATUS_LINK ) != 0UL )\r
-       {\r
-               lReturn = pdPASS;\r
-       }\r
-\r
-       return lReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
 static void prvUIPTimerCallback( xTimerHandle xTimer )\r
 {\r
 static const unsigned long ulARPTimerExpired = uipARP_TIMER_EVENT;\r
 static const unsigned long ulPeriodicTimerExpired = uipPERIODIC_TIMER_EVENT;\r
 \r
        /* This is a time callback, so calls to xQueueSend() must not attempt to\r
-       block. */\r
+       block.  As this callback is assigned to both the ARP and Periodic timers, the\r
+       first thing to do is ascertain which timer it was that actually expired. */\r
        switch( ( int ) pvTimerGetTimerID( xTimer ) )\r
        {\r
                case uipARP_TIMER               :       xQueueSend( xEMACEventQueue, &ulARPTimerExpired, uipDONT_BLOCK );\r
@@ -447,3 +399,40 @@ static const unsigned long ulPeriodicTimerExpired = uipPERIODIC_TIMER_EVENT;
        }\r
 }\r
 /*-----------------------------------------------------------*/\r
+\r
+void vApplicationProcessFormInput( char *pcInputString )\r
+{\r
+char *c;\r
+\r
+       /* Only interested in processing form input if this is the IO page. */\r
+       c = strstr( pcInputString, "io.shtml" );\r
+       \r
+       if( c )\r
+       {\r
+               /* Is there a command in the string? */\r
+               c = strstr( pcInputString, "?" );\r
+           if( c )\r
+           {\r
+                       /* Turn the LED's on or off in accordance with the check box status. */\r
+                       if( strstr( c, "LED0=1" ) != NULL )\r
+                       {\r
+                               /* Turn the LEDs on. */\r
+                               vParTestSetLED( 3, 1 );\r
+                               vParTestSetLED( 4, 1 );\r
+                       }\r
+                       else\r
+                       {\r
+                               /* Turn the LEDs off. */\r
+                               vParTestSetLED( 3, 0 );\r
+                               vParTestSetLED( 4, 0 );\r
+                       }\r
+           }\r
+               else\r
+               {\r
+                       /* Commands to turn LEDs off are not always explicit. */\r
+                       vParTestSetLED( 3, 0 );\r
+                       vParTestSetLED( 4, 0 );\r
+               }\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r