-unsigned long ulRxed = 0, ulRxISR = 0, ulTxed = 0, ulTxISR = 0;\r
/*\r
FreeRTOS V7.0.0 - Copyright (C) 2011 Real Time Engineers Ltd.\r
\r
#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
*/\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
*/\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
/* 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
void vuIP_Task( void *pvParameters )\r
{\r
portBASE_TYPE i;\r
-unsigned long ulNewEvent;\r
+unsigned long ulNewEvent = 0UL;\r
+unsigned long ulUIP_Events = 0UL;\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
-\r
- /* Is there received data ready to be processed? */\r
- uip_len = MSS_MAC_rx_packet();\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( ( uip_len > 0 ) && ( uip_buf != NULL ) )\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
\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
+ ( 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
+ ( 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
long lHigherPriorityTaskWoken = pdFALSE;\r
unsigned long ulUIPEvents = 0UL;\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_CheckTxBufferStatus();\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
+ /* An Ethernet Rx event has occurred. */\r
ulUIPEvents |= uipETHERNET_RX_EVENT;\r
}\r
\r
if( ulUIPEvents != 0UL )\r
{\r
+ /* Send any events that have occurred to the uIP stack (the uIP task in\r
+ this case). */\r
xQueueSendFromISR( xEMACEventQueue, &ulUIPEvents, &lHigherPriorityTaskWoken );\r
}\r
\r
{\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
long lAttempt;\r
const portTickType xShortDelay = ( 10 / 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
}\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