]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c
c90c401db579f790bd254bfcff52e42821734b2c
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / LPC18xx / NetworkInterface.c
1 /*\r
2  * FreeRTOS+TCP V2.0.3\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 \r
27 /* Standard includes. */\r
28 #include <stdint.h>\r
29 #include <stdio.h>\r
30 #include <stdlib.h>\r
31 \r
32 /* FreeRTOS includes. */\r
33 #include "FreeRTOS.h"\r
34 #include "task.h"\r
35 #include "queue.h"\r
36 #include "semphr.h"\r
37 \r
38 /* FreeRTOS+TCP includes. */\r
39 #include "FreeRTOS_IP.h"\r
40 #include "FreeRTOS_Sockets.h"\r
41 #include "FreeRTOS_IP_Private.h"\r
42 #include "NetworkBufferManagement.h"\r
43 #include "NetworkInterface.h"\r
44 \r
45 /* LPCOpen includes. */\r
46 #include "chip.h"\r
47 #include "lpc_phy.h"\r
48 \r
49 /* The size of the stack allocated to the task that handles Rx packets. */\r
50 #define nwRX_TASK_STACK_SIZE    140\r
51 \r
52 #ifndef PHY_LS_HIGH_CHECK_TIME_MS\r
53         /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not\r
54         receiving packets. */\r
55         #define PHY_LS_HIGH_CHECK_TIME_MS       15000\r
56 #endif\r
57 \r
58 #ifndef PHY_LS_LOW_CHECK_TIME_MS\r
59         /* Check if the LinkSStatus in the PHY is still low every second. */\r
60         #define PHY_LS_LOW_CHECK_TIME_MS        1000\r
61 #endif\r
62 \r
63 #ifndef configUSE_RMII\r
64         #define configUSE_RMII 1\r
65 #endif\r
66 \r
67 #ifndef configNUM_RX_DESCRIPTORS\r
68         #error please define configNUM_RX_DESCRIPTORS in your FreeRTOSIPConfig.h\r
69 #endif\r
70 \r
71 #ifndef configNUM_TX_DESCRIPTORS\r
72         #error please define configNUM_TX_DESCRIPTORS in your FreeRTOSIPConfig.h\r
73 #endif\r
74 \r
75 #ifndef NETWORK_IRQHandler\r
76         #error NETWORK_IRQHandler must be defined to the name of the function that is installed in the interrupt vector table to handle Ethernet interrupts.\r
77 #endif\r
78 \r
79 #if !defined( MAC_FF_HMC )\r
80         /* Hash for multicast. */\r
81         #define MAC_FF_HMC     ( 1UL << 2UL )\r
82 #endif\r
83 \r
84 #ifndef iptraceEMAC_TASK_STARTING\r
85         #define iptraceEMAC_TASK_STARTING()     do { } while( 0 )\r
86 #endif\r
87 \r
88 /* Define the bits of .STATUS that indicate a reception error. */\r
89 #define nwRX_STATUS_ERROR_BITS \\r
90         ( RDES_CE  /* CRC Error */                        | \\r
91           RDES_RE  /* Receive Error */                    | \\r
92           RDES_DE  /* Descriptor Error */                 | \\r
93           RDES_RWT /* Receive Watchdog Timeout */         | \\r
94           RDES_LC  /* Late Collision */                   | \\r
95           RDES_OE  /* Overflow Error */                   | \\r
96           RDES_SAF /* Source Address Filter Fail */       | \\r
97           RDES_AFM /* Destination Address Filter Fail */  | \\r
98           RDES_LE  /* Length Error */                     )\r
99 \r
100 /* Define the EMAC status bits that should trigger an interrupt. */\r
101 #define nwDMA_INTERRUPT_MASK \\r
102         ( DMA_IE_TIE  /* Transmit interrupt enable */         | \\r
103           DMA_IE_TSE  /* Transmit stopped enable */           | \\r
104           DMA_IE_OVE  /* Overflow interrupt enable */         | \\r
105           DMA_IE_RIE  /* Receive interrupt enable */          | \\r
106           DMA_IE_NIE  /* Normal interrupt summary enable */   | \\r
107           DMA_IE_AIE  /* Abnormal interrupt summary enable */ | \\r
108           DMA_IE_RUE  /* Receive buffer unavailable enable */ | \\r
109           DMA_IE_UNE  /* Underflow interrupt enable. */       | \\r
110           DMA_IE_TJE  /* Transmit jabber timeout enable */    | \\r
111           DMA_IE_RSE  /* Received stopped enable */           | \\r
112           DMA_IE_RWE  /* Receive watchdog timeout enable */   | \\r
113           DMA_IE_FBE )/* Fatal bus error enable */\r
114 \r
115 /* Interrupt events to process.  Currently only the RX/TX events are processed\r
116 although code for other events is included to allow for possible future\r
117 expansion. */\r
118 #define EMAC_IF_RX_EVENT        1UL\r
119 #define EMAC_IF_TX_EVENT        2UL\r
120 #define EMAC_IF_ERR_EVENT       4UL\r
121 #define EMAC_IF_ALL_EVENT       ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )\r
122 \r
123  /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet\r
124  driver will filter incoming packets and only pass the stack those packets it\r
125  considers need processing. */\r
126  #if( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )\r
127         #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer\r
128  #else\r
129         #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )\r
130  #endif\r
131 \r
132 #if( ipconfigZERO_COPY_RX_DRIVER == 0 ) || ( ipconfigZERO_COPY_TX_DRIVER == 0 )\r
133         #warning It is adviced to enable both macros\r
134 #endif\r
135 \r
136 #ifndef configPLACE_IN_SECTION_RAM\r
137         #define configPLACE_IN_SECTION_RAM\r
138 /*\r
139         #define configPLACE_IN_SECTION_RAM      __attribute__ ((section(".ramfunc")))\r
140 */\r
141 #endif\r
142 \r
143 /*-----------------------------------------------------------*/\r
144 \r
145 /*\r
146  * Delay function passed into the library.  The implementation uses FreeRTOS\r
147  * calls so the scheduler must be started before the driver can be used.\r
148  */\r
149 static void prvDelay( uint32_t ulMilliSeconds );\r
150 \r
151 /*\r
152  * Initialises the Tx and Rx descriptors respectively.\r
153  */\r
154 static void prvSetupTxDescriptors( void );\r
155 static void prvSetupRxDescriptors( void );\r
156 \r
157 /*\r
158  * A task that processes received frames.\r
159  */\r
160 static void prvEMACHandlerTask( void *pvParameters );\r
161 \r
162 /*\r
163  * Sets up the MAC with the results of an auto-negotiation.\r
164  */\r
165 static BaseType_t prvSetLinkSpeed( void );\r
166 \r
167 /*\r
168  * Generates a CRC for a MAC address that is then used to generate a hash index.\r
169  */\r
170 static uint32_t prvGenerateCRC32( const uint8_t *ucAddress );\r
171 \r
172 /*\r
173  * Generates a hash index when setting a filter to permit a MAC address.\r
174  */\r
175 static uint32_t prvGetHashIndex( const uint8_t *ucAddress );\r
176 \r
177 /*\r
178  * Update the hash table to allow a MAC address.\r
179  */\r
180 static void prvAddMACAddress( const uint8_t* ucMacAddress );\r
181 \r
182 /*\r
183  * Sometimes the DMA will report received data as being longer than the actual\r
184  * received from length.  This function checks the reported length and corrects\r
185  * if if necessary.\r
186  */\r
187 static void prvRemoveTrailingBytes( NetworkBufferDescriptor_t *pxDescriptor );\r
188 \r
189 /*-----------------------------------------------------------*/\r
190 \r
191 /* Bit map of outstanding ETH interrupt events for processing.  Currently only\r
192 the Rx and Tx interrupt is handled, although code is included for other events\r
193 to enable future expansion. */\r
194 static volatile uint32_t ulISREvents;\r
195 \r
196 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */\r
197 static uint32_t ulPHYLinkStatus = 0;\r
198 \r
199 /* Tx descriptors and index. */\r
200 static ENET_ENHTXDESC_T xDMATxDescriptors[ configNUM_TX_DESCRIPTORS ];\r
201 \r
202 /* ulNextFreeTxDescriptor is declared volatile, because it is accessed from\r
203 to different tasks. */\r
204 static volatile uint32_t ulNextFreeTxDescriptor;\r
205 static uint32_t ulTxDescriptorToClear;\r
206 \r
207 /* Rx descriptors and index. */\r
208 static ENET_ENHRXDESC_T xDMARxDescriptors[ configNUM_RX_DESCRIPTORS ];\r
209 static uint32_t ulNextRxDescriptorToProcess;\r
210 \r
211 /* Must be defined externally - the demo applications define this in main.c. */\r
212 extern uint8_t ucMACAddress[ 6 ];\r
213 \r
214 /* The handle of the task that processes Rx packets.  The handle is required so\r
215 the task can be notified when new packets arrive. */\r
216 static TaskHandle_t xRxHanderTask = NULL;\r
217 \r
218 #if( ipconfigUSE_LLMNR == 1 )\r
219         static const uint8_t xLLMNR_MACAddress[] = { '\x01', '\x00', '\x5E', '\x00', '\x00', '\xFC' };\r
220 #endif  /* ipconfigUSE_LLMNR == 1 */\r
221 \r
222 /* xTXDescriptorSemaphore is a counting semaphore with\r
223 a maximum count of ETH_TXBUFNB, which is the number of\r
224 DMA TX descriptors. */\r
225 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;\r
226 \r
227 /*-----------------------------------------------------------*/\r
228 \r
229 \r
230 BaseType_t xNetworkInterfaceInitialise( void )\r
231 {\r
232 BaseType_t xReturn = pdPASS;\r
233 static BaseType_t xHasInitialised = pdFALSE;\r
234 \r
235         if( xHasInitialised == pdFALSE )\r
236         {\r
237                 xHasInitialised = pdTRUE;\r
238 \r
239                 /* The interrupt will be turned on when a link is established. */\r
240                 NVIC_DisableIRQ( ETHERNET_IRQn );\r
241 \r
242                 /* Disable receive and transmit DMA processes. */\r
243                 LPC_ETHERNET->DMA_OP_MODE &= ~( DMA_OM_ST | DMA_OM_SR );\r
244 \r
245                 /* Disable packet reception. */\r
246                 LPC_ETHERNET->MAC_CONFIG &= ~( MAC_CFG_RE | MAC_CFG_TE );\r
247 \r
248                 /* Call the LPCOpen function to initialise the hardware. */\r
249                 Chip_ENET_Init( LPC_ETHERNET );\r
250 \r
251                 /* Save MAC address. */\r
252                 Chip_ENET_SetADDR( LPC_ETHERNET, ucMACAddress );\r
253 \r
254                 /* Clear all MAC address hash entries. */\r
255                 LPC_ETHERNET->MAC_HASHTABLE_HIGH = 0;\r
256                 LPC_ETHERNET->MAC_HASHTABLE_LOW = 0;\r
257 \r
258                 #if( ipconfigUSE_LLMNR == 1 )\r
259                 {\r
260                         prvAddMACAddress( xLLMNR_MACAddress );\r
261                 }\r
262                 #endif /* ipconfigUSE_LLMNR == 1 */\r
263 \r
264                 /* Promiscuous flag (PR) and Receive All flag (RA) set to zero.  The\r
265                 registers MAC_HASHTABLE_[LOW|HIGH] will be loaded to allow certain\r
266                 multi-cast addresses. */\r
267                 LPC_ETHERNET->MAC_FRAME_FILTER = MAC_FF_HMC;\r
268 \r
269                 #if( configUSE_RMII == 1 )\r
270                 {\r
271                         if( lpc_phy_init( pdTRUE, prvDelay ) != SUCCESS )\r
272                         {\r
273                                 xReturn = pdFAIL;\r
274                         }\r
275                 }\r
276                 #else\r
277                 {\r
278                         #warning This path has not been tested.\r
279                         if( lpc_phy_init( pdFALSE, prvDelay ) != SUCCESS )\r
280                         {\r
281                                 xReturn = pdFAIL;\r
282                         }\r
283                 }\r
284                 #endif\r
285 \r
286                 if( xReturn == pdPASS )\r
287                 {\r
288                         if( xTXDescriptorSemaphore == NULL )\r
289                         {\r
290                                 /* Create a counting semaphore, with a value of 'configNUM_TX_DESCRIPTORS'\r
291                                 and a maximum of 'configNUM_TX_DESCRIPTORS'. */\r
292                                 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) configNUM_TX_DESCRIPTORS, ( UBaseType_t ) configNUM_TX_DESCRIPTORS );\r
293                                 configASSERT( xTXDescriptorSemaphore );\r
294                         }\r
295 \r
296                         /* Enable MAC interrupts. */\r
297                         LPC_ETHERNET->DMA_INT_EN = nwDMA_INTERRUPT_MASK;\r
298 \r
299                         /* Auto-negotiate was already started.  Wait for it to complete. */\r
300                         xReturn = prvSetLinkSpeed();\r
301 \r
302                         if( xReturn == pdPASS )\r
303                         {\r
304                                 /* Initialise the descriptors. */\r
305                                 prvSetupTxDescriptors();\r
306                                 prvSetupRxDescriptors();\r
307 \r
308                                 /* Clear all interrupts. */\r
309                                 LPC_ETHERNET->DMA_STAT = DMA_ST_ALL;\r
310 \r
311                                 /* Enable receive and transmit DMA processes. */\r
312                                 LPC_ETHERNET->DMA_OP_MODE |= DMA_OM_ST | DMA_OM_SR;\r
313 \r
314                                 /* Set Receiver / Transmitter Enable. */\r
315                                 LPC_ETHERNET->MAC_CONFIG |= MAC_CFG_RE | MAC_CFG_TE;\r
316 \r
317                                 /* Start receive polling. */\r
318                                 LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1;\r
319 \r
320                                 /* Enable interrupts in the NVIC. */\r
321                                 NVIC_SetPriority( ETHERNET_IRQn, configMAC_INTERRUPT_PRIORITY );\r
322                                 NVIC_EnableIRQ( ETHERNET_IRQn );\r
323                         }\r
324                         /* Guard against the task being created more than once and the\r
325                         descriptors being initialised more than once. */\r
326                         if( xRxHanderTask == NULL )\r
327                         {\r
328                                 xReturn = xTaskCreate( prvEMACHandlerTask, "EMAC", nwRX_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xRxHanderTask );\r
329                                 configASSERT( xReturn );\r
330                         }\r
331                 }\r
332         }\r
333 \r
334         /* Once prvEMACHandlerTask() has started, the variable\r
335         'ulPHYLinkStatus' will be updated by that task. \r
336         The IP-task will keep on calling this function untill\r
337         it finally returns pdPASS.\r
338         Only then can the DHCP-procedure start (if configured). */\r
339         if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 )\r
340         {\r
341                 xReturn = pdPASS;\r
342         }\r
343         else\r
344         {\r
345                 xReturn = pdFAIL;\r
346         }\r
347 \r
348         return xReturn;\r
349 }\r
350 /*-----------------------------------------------------------*/\r
351 \r
352 #define niBUFFER_1_PACKET_SIZE          1536\r
353 \r
354 static __attribute__ ((section("._ramAHB32"))) uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) );\r
355 \r
356 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )\r
357 {\r
358 \r
359 uint8_t *ucRAMBuffer = ucNetworkPackets;\r
360 uint32_t ul;\r
361 \r
362         for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )\r
363         {\r
364                 pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;\r
365                 *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );\r
366                 ucRAMBuffer += niBUFFER_1_PACKET_SIZE;\r
367         }\r
368 }\r
369 /*-----------------------------------------------------------*/\r
370 \r
371 configPLACE_IN_SECTION_RAM\r
372 static void vClearTXBuffers()\r
373 {\r
374 uint32_t ulLastDescriptor = ulNextFreeTxDescriptor;\r
375 size_t uxCount = ( ( size_t ) configNUM_TX_DESCRIPTORS ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );\r
376 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
377         NetworkBufferDescriptor_t *pxNetworkBuffer;\r
378         uint8_t *ucPayLoad;\r
379 #endif\r
380 \r
381         /* This function is called after a TX-completion interrupt.\r
382         It will release each Network Buffer used in xNetworkInterfaceOutput().\r
383         'uxCount' represents the number of descriptors given to DMA for transmission.\r
384         After sending a packet, the DMA will clear the 'TDES_OWN' bit. */\r
385         while( ( uxCount > ( size_t ) 0u ) && ( ( xDMATxDescriptors[ ulTxDescriptorToClear ].CTRLSTAT & TDES_OWN ) == 0 ) )\r
386         {\r
387                 if( ( ulTxDescriptorToClear == ulLastDescriptor ) && ( uxCount != ( size_t ) configNUM_TX_DESCRIPTORS ) )\r
388                 {\r
389                         break;\r
390                 }\r
391 \r
392 \r
393                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
394                 {\r
395                         ucPayLoad = ( uint8_t * )xDMATxDescriptors[ ulTxDescriptorToClear ].B1ADD;\r
396                         if( ucPayLoad != NULL )\r
397                         {\r
398                                 /* B1ADD points to a pucEthernetBuffer of a Network Buffer descriptor. */\r
399                                 pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );\r
400 \r
401                                 configASSERT( pxNetworkBuffer != NULL );\r
402 \r
403                                 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ;\r
404                                 xDMATxDescriptors[ ulTxDescriptorToClear ].B1ADD = ( uint32_t )0u;\r
405                         }\r
406                 }\r
407                 #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
408 \r
409                 /* Move onto the next descriptor, wrapping if necessary. */\r
410                 ulTxDescriptorToClear++;\r
411                 if( ulTxDescriptorToClear >= configNUM_TX_DESCRIPTORS )\r
412                 {\r
413                         ulTxDescriptorToClear = 0;\r
414                 }\r
415 \r
416                 uxCount--;\r
417                 /* Tell the counting semaphore that one more TX descriptor is available. */\r
418                 xSemaphoreGive( xTXDescriptorSemaphore );\r
419         }\r
420 }\r
421 \r
422 /*-----------------------------------------------------------*/\r
423 \r
424 configPLACE_IN_SECTION_RAM\r
425 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )\r
426 {\r
427 BaseType_t xReturn = pdFAIL;\r
428 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50 );\r
429 \r
430         /* Attempt to obtain access to a Tx descriptor. */\r
431         do\r
432         {\r
433                 if( xTXDescriptorSemaphore == NULL )\r
434                 {\r
435                         break;\r
436                 }\r
437                 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )\r
438                 {\r
439                         /* Time-out waiting for a free TX descriptor. */\r
440                         break;\r
441                 }\r
442 \r
443                 /* If the descriptor is still owned by the DMA it can't be used. */\r
444                 if( ( xDMATxDescriptors[ ulNextFreeTxDescriptor ].CTRLSTAT & TDES_OWN ) != 0 )\r
445                 {\r
446                         /* The semaphore was taken, the TX DMA-descriptor is still not available.\r
447                         Actually that should not occur, the 'TDES_OWN' was already confirmed low in vClearTXBuffers(). */\r
448                         xSemaphoreGive( xTXDescriptorSemaphore );\r
449                 }\r
450                 else\r
451                 {\r
452                         #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
453                         {\r
454                                 /* bReleaseAfterSend should always be set when using the zero\r
455                                 copy driver. */\r
456                                 configASSERT( bReleaseAfterSend != pdFALSE );\r
457 \r
458                                 /* The DMA's descriptor to point directly to the data in the\r
459                                 network buffer descriptor.  The data is not copied. */\r
460                                 xDMATxDescriptors[ ulNextFreeTxDescriptor ].B1ADD = ( uint32_t ) pxDescriptor->pucEthernetBuffer;\r
461 \r
462                                 /* The DMA descriptor will 'own' this Network Buffer,\r
463                                 until it has been sent.  So don't release it now. */\r
464                                 bReleaseAfterSend = pdFALSE;\r
465                         }\r
466                         #else\r
467                         {\r
468                                 /* The data is copied from the network buffer descriptor into\r
469                                 the DMA's descriptor. */\r
470                                 memcpy( ( void * ) xDMATxDescriptors[ ulNextFreeTxDescriptor ].B1ADD, ( void * ) pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength );\r
471                         }\r
472                         #endif\r
473 \r
474                         xDMATxDescriptors[ ulNextFreeTxDescriptor ].BSIZE = ( uint32_t ) TDES_ENH_BS1( pxDescriptor->xDataLength );\r
475 \r
476                         /* This descriptor is given back to the DMA. */\r
477                         xDMATxDescriptors[ ulNextFreeTxDescriptor ].CTRLSTAT |= TDES_OWN;\r
478 \r
479                         /* Ensure the DMA is polling Tx descriptors. */\r
480                         LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1;\r
481 \r
482             iptraceNETWORK_INTERFACE_TRANSMIT();\r
483 \r
484                         /* Move onto the next descriptor, wrapping if necessary. */\r
485                         ulNextFreeTxDescriptor++;\r
486                         if( ulNextFreeTxDescriptor >= configNUM_TX_DESCRIPTORS )\r
487                         {\r
488                                 ulNextFreeTxDescriptor = 0;\r
489                         }\r
490 \r
491                         /* The Tx has been initiated. */\r
492                         xReturn = pdPASS;\r
493                 }\r
494         } while( 0 );\r
495 \r
496         /* The buffer has been sent so can be released. */\r
497         if( bReleaseAfterSend != pdFALSE )\r
498         {\r
499                 vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
500         }\r
501 \r
502         return xReturn;\r
503 }\r
504 /*-----------------------------------------------------------*/\r
505 \r
506 static void prvDelay( uint32_t ulMilliSeconds )\r
507 {\r
508         /* Ensure the scheduler was started before attempting to use the scheduler to\r
509         create a delay. */\r
510         configASSERT( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING );\r
511 \r
512         vTaskDelay( pdMS_TO_TICKS( ulMilliSeconds ) );\r
513 }\r
514 /*-----------------------------------------------------------*/\r
515 \r
516 static void prvSetupTxDescriptors( void )\r
517 {\r
518 BaseType_t x;\r
519 \r
520         /* Start with Tx descriptors clear. */\r
521         memset( ( void * ) xDMATxDescriptors, 0, sizeof( xDMATxDescriptors ) );\r
522 \r
523         /* Index to the next Tx descriptor to use. */\r
524         ulNextFreeTxDescriptor = 0ul;\r
525 \r
526         /* Index to the next Tx descriptor to clear ( after transmission ). */\r
527         ulTxDescriptorToClear = 0ul;\r
528 \r
529         for( x = 0; x < configNUM_TX_DESCRIPTORS; x++ )\r
530         {\r
531                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
532                 {\r
533                         /* Nothing to do, B1ADD will be set when data is ready to transmit.\r
534                         Currently the memset above will have set it to NULL. */\r
535                 }\r
536                 #else\r
537                 {\r
538                         /* Allocate a buffer to the Tx descriptor.  This is the most basic\r
539                         way of creating a driver as the data is then copied into the\r
540                         buffer. */\r
541                         xDMATxDescriptors[ x ].B1ADD = ( uint32_t ) pvPortMalloc( ipTOTAL_ETHERNET_FRAME_SIZE );\r
542 \r
543                         /* Use an assert to check the allocation as +TCP applications will\r
544                         often not use a malloc() failed hook as the TCP stack will recover\r
545                         from allocation failures. */\r
546                         configASSERT( xDMATxDescriptors[ x ].B1ADD );\r
547                 }\r
548                 #endif\r
549 \r
550                 /* Buffers hold an entire frame so all buffers are both the start and\r
551                 end of a frame. */\r
552                 /* TDES_ENH_TCH     Second Address Chained. */\r
553                 /* TDES_ENH_CIC(n)  Checksum Insertion Control, tried but it does not work for the LPC18xx... */\r
554                 /* TDES_ENH_FS      First Segment. */\r
555                 /* TDES_ENH_LS      Last Segment. */\r
556                 /* TDES_ENH_IC      Interrupt on Completion. */\r
557                 xDMATxDescriptors[ x ].CTRLSTAT = TDES_ENH_TCH | TDES_ENH_CIC( 3 ) | TDES_ENH_FS | TDES_ENH_LS | TDES_ENH_IC;\r
558                 xDMATxDescriptors[ x ].B2ADD = ( uint32_t ) &xDMATxDescriptors[ x + 1 ];\r
559         }\r
560 \r
561         xDMATxDescriptors[ configNUM_TX_DESCRIPTORS - 1 ].CTRLSTAT |= TDES_ENH_TER;\r
562         xDMATxDescriptors[ configNUM_TX_DESCRIPTORS - 1 ].B2ADD = ( uint32_t ) &xDMATxDescriptors[ 0 ];\r
563 \r
564         /* Point the DMA to the base of the descriptor list. */\r
565         LPC_ETHERNET->DMA_TRANS_DES_ADDR = ( uint32_t ) xDMATxDescriptors;\r
566 }\r
567 /*-----------------------------------------------------------*/\r
568 \r
569 static void prvSetupRxDescriptors( void )\r
570 {\r
571 BaseType_t x;\r
572 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
573         NetworkBufferDescriptor_t *pxNetworkBuffer;\r
574 #endif\r
575 \r
576         /* Index to the next Rx descriptor to use. */\r
577         ulNextRxDescriptorToProcess = 0;\r
578 \r
579         /* Clear RX descriptor list. */\r
580         memset( ( void * )  xDMARxDescriptors, 0, sizeof( xDMARxDescriptors ) );\r
581 \r
582         for( x = 0; x < configNUM_RX_DESCRIPTORS; x++ )\r
583         {\r
584                 /* Allocate a buffer of the largest     possible frame size as it is not\r
585                 known what size received frames will be. */\r
586 \r
587                 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
588                 {\r
589                         pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, 0 );\r
590 \r
591                         /* During start-up there should be enough Network Buffers available,\r
592                         so it is safe to use configASSERT().\r
593                         In case this assert fails, please check: configNUM_RX_DESCRIPTORS,\r
594                         ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, and in case BufferAllocation_2.c\r
595                         is included, check the amount of available heap. */\r
596                         configASSERT( pxNetworkBuffer != NULL );\r
597 \r
598                         /* Pass the actual buffer to DMA. */\r
599                         xDMARxDescriptors[ x ].B1ADD = ( uint32_t ) pxNetworkBuffer->pucEthernetBuffer;\r
600                 }\r
601                 #else\r
602                 {\r
603                         /* All DMA descriptors are populated with permanent memory blocks.\r
604                         Their contents will be copy to Network Buffers. */\r
605                         xDMARxDescriptors[ x ].B1ADD = ( uint32_t ) pvPortMalloc( ipTOTAL_ETHERNET_FRAME_SIZE );\r
606                 }\r
607                 #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
608 \r
609                 /* Use an assert to check the allocation as +TCP applications will often\r
610                 not use a malloc failed hook as the TCP stack will recover from\r
611                 allocation failures. */\r
612                 configASSERT( xDMARxDescriptors[ x ].B1ADD );\r
613 \r
614                 xDMARxDescriptors[ x ].B2ADD = ( uint32_t ) &( xDMARxDescriptors[ x + 1 ] );\r
615                 xDMARxDescriptors[ x ].CTRL = ( uint32_t ) RDES_ENH_BS1( ipTOTAL_ETHERNET_FRAME_SIZE ) | RDES_ENH_RCH;\r
616 \r
617                 /* The descriptor is available for use by the DMA. */\r
618                 xDMARxDescriptors[ x ].STATUS = RDES_OWN;\r
619         }\r
620 \r
621         /* RDES_ENH_RER  Receive End of Ring. */\r
622         xDMARxDescriptors[ ( configNUM_RX_DESCRIPTORS - 1 ) ].CTRL |= RDES_ENH_RER;\r
623         xDMARxDescriptors[ configNUM_RX_DESCRIPTORS - 1 ].B2ADD = ( uint32_t ) &( xDMARxDescriptors[ 0 ] );\r
624 \r
625         /* Point the DMA to the base of the descriptor list. */\r
626         LPC_ETHERNET->DMA_REC_DES_ADDR = ( uint32_t ) xDMARxDescriptors;\r
627 }\r
628 /*-----------------------------------------------------------*/\r
629 configPLACE_IN_SECTION_RAM\r
630 static void prvRemoveTrailingBytes( NetworkBufferDescriptor_t *pxDescriptor )\r
631 {\r
632 size_t xExpectedLength;\r
633 IPPacket_t *pxIPPacket;\r
634 \r
635         pxIPPacket = ( IPPacket_t * ) pxDescriptor->pucEthernetBuffer;\r
636         /* Look at the actual length of the packet, translate it to a host-endial notation. */\r
637         xExpectedLength = sizeof( EthernetHeader_t ) + ( size_t ) FreeRTOS_htons( pxIPPacket->xIPHeader.usLength );\r
638 \r
639         if( xExpectedLength == ( pxDescriptor->xDataLength + 4 ) )\r
640         {\r
641                 pxDescriptor->xDataLength -= 4;\r
642         }\r
643         else\r
644         {\r
645                 if( pxDescriptor->xDataLength > xExpectedLength )\r
646                 {\r
647                         pxDescriptor->xDataLength = ( size_t ) xExpectedLength;\r
648                 }\r
649         }\r
650 }\r
651 /*-----------------------------------------------------------*/\r
652 configPLACE_IN_SECTION_RAM\r
653 BaseType_t xGetPhyLinkStatus( void )\r
654 {\r
655 BaseType_t xReturn;\r
656 \r
657         if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) == 0 )\r
658         {\r
659                 xReturn = pdFALSE;\r
660         }\r
661         else\r
662         {\r
663                 xReturn = pdTRUE;\r
664         }\r
665 \r
666         return xReturn;\r
667 }\r
668 /*-----------------------------------------------------------*/\r
669 \r
670 configPLACE_IN_SECTION_RAM\r
671 static BaseType_t prvNetworkInterfaceInput()\r
672 {\r
673 BaseType_t xResult = pdFALSE;\r
674 uint32_t ulStatus;\r
675 eFrameProcessingResult_t eResult;\r
676 const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 );\r
677 const UBaseType_t uxMinimumBuffersRemaining = 3UL;\r
678 uint16_t usLength;\r
679 NetworkBufferDescriptor_t *pxDescriptor;\r
680 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
681         NetworkBufferDescriptor_t *pxNewDescriptor;\r
682 #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
683 IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };\r
684 \r
685         /* Process each descriptor that is not still in use by the DMA. */\r
686         ulStatus = xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS;\r
687         if( ( ulStatus & RDES_OWN ) == 0 )\r
688         {\r
689                 /* Check packet for errors */\r
690                 if( ( ulStatus & nwRX_STATUS_ERROR_BITS ) != 0 )\r
691                 {\r
692                         /* There is some reception error. */\r
693                         /* Clear error bits. */\r
694                         ulStatus &= ~( ( uint32_t )nwRX_STATUS_ERROR_BITS );\r
695                 }\r
696                 else\r
697                 {\r
698                         xResult++;\r
699 \r
700                         eResult = ipCONSIDER_FRAME_FOR_PROCESSING( ( const uint8_t * const ) ( xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD ) );\r
701                         if( eResult == eProcessBuffer )\r
702                         {\r
703                                 if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) == 0 )\r
704                                 {\r
705                                         ulPHYLinkStatus |= PHY_LINK_CONNECTED;\r
706                                         FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d (message received)\n", ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 ) );\r
707                                 }\r
708 \r
709                         #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
710                                 if( uxGetNumberOfFreeNetworkBuffers() > uxMinimumBuffersRemaining )\r
711                                 {\r
712                                         pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xDescriptorWaitTime );\r
713                                 }\r
714                                 else\r
715                                 {\r
716                                         /* Too risky to allocate a new Network Buffer. */\r
717                                         pxNewDescriptor = NULL;\r
718                                 }\r
719                                 if( pxNewDescriptor != NULL )\r
720                         #else\r
721                                 if( uxGetNumberOfFreeNetworkBuffers() > uxMinimumBuffersRemaining )\r
722                         #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
723                                 {\r
724                         #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
725                                 const uint8_t *pucBuffer;\r
726                         #endif\r
727 \r
728                                         /* Get the actual length. */\r
729                                         usLength = RDES_FLMSK( ulStatus );\r
730 \r
731                                         #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
732                                         {\r
733                                                 /* Replace the character buffer 'B1ADD'. */\r
734                                                 pucBuffer = ( const uint8_t * const ) ( xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD );\r
735                                                 xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD = ( uint32_t ) pxNewDescriptor->pucEthernetBuffer;\r
736 \r
737                                                 /* 'B1ADD' contained the address of a 'pucEthernetBuffer' that\r
738                                                 belongs to a Network Buffer.  Find the original Network Buffer. */\r
739                                                 pxDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer );\r
740                                                 /* This zero-copy driver makes sure that every 'xDMARxDescriptors' contains\r
741                                                 a reference to a Network Buffer at any time.\r
742                                                 In case it runs out of Network Buffers, a DMA buffer won't be replaced,\r
743                                                 and the received messages is dropped. */\r
744                                                 configASSERT( pxDescriptor != NULL );\r
745                                         }\r
746                                         #else\r
747                                         {\r
748                                                 /* Create a buffer of exactly the required length. */\r
749                                                 pxDescriptor = pxGetNetworkBufferWithDescriptor( usLength, xDescriptorWaitTime );\r
750                                         }\r
751                                         #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
752 \r
753                                         if( pxDescriptor != NULL )\r
754                                         {\r
755                                                 pxDescriptor->xDataLength = ( size_t ) usLength;\r
756                                                 #if( ipconfigZERO_COPY_RX_DRIVER == 0 )\r
757                                                 {\r
758                                                         /* Copy the data into the allocated buffer. */\r
759                                                         memcpy( ( void * ) pxDescriptor->pucEthernetBuffer, ( void * ) xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD, usLength );\r
760                                                 }\r
761                                                 #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
762                                                 /* It is possible that more data was copied than\r
763                                                 actually makes up the frame.  If this is the case\r
764                                                 adjust the length to remove any trailing bytes. */\r
765                                                 prvRemoveTrailingBytes( pxDescriptor );\r
766 \r
767                                                 /* Pass the data to the TCP/IP task for processing. */\r
768                                                 xRxEvent.pvData = ( void * ) pxDescriptor;\r
769                                                 if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE )\r
770                                                 {\r
771                                                         /* Could not send the descriptor into the TCP/IP\r
772                                                         stack, it must be released. */\r
773                                                         vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
774                                                 }\r
775                                                 else\r
776                                                 {\r
777                                                         iptraceNETWORK_INTERFACE_RECEIVE();\r
778                                                 }\r
779                                         }\r
780                                 }\r
781                         }\r
782                         /* Got here because received data was sent to the IP task or the\r
783                         data contained an error and was discarded.  Give the descriptor\r
784                         back to the DMA. */\r
785                         xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS = ulStatus | RDES_OWN;\r
786 \r
787                         /* Move onto the next descriptor. */\r
788                         ulNextRxDescriptorToProcess++;\r
789                         if( ulNextRxDescriptorToProcess >= configNUM_RX_DESCRIPTORS )\r
790                         {\r
791                                 ulNextRxDescriptorToProcess = 0;\r
792                         }\r
793 \r
794                         ulStatus = xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS;\r
795                 } /* if( ( ulStatus & nwRX_STATUS_ERROR_BITS ) != 0 ) */\r
796         } /* if( ( ulStatus & RDES_OWN ) == 0 ) */\r
797 \r
798         /* Restart receive polling. */\r
799         LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1;\r
800 \r
801         return xResult;\r
802 }\r
803 /*-----------------------------------------------------------*/\r
804 \r
805 configPLACE_IN_SECTION_RAM\r
806 void NETWORK_IRQHandler( void )\r
807 {\r
808 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
809 uint32_t ulDMAStatus;\r
810 const uint32_t ulRxInterruptMask =\r
811         DMA_ST_RI |             /* Receive interrupt */\r
812         DMA_ST_RU;              /* Receive buffer unavailable */\r
813 const uint32_t ulTxInterruptMask =\r
814         DMA_ST_TI |             /* Transmit interrupt */\r
815         DMA_ST_TPS;             /* Transmit process stopped */\r
816 \r
817         configASSERT( xRxHanderTask );\r
818 \r
819         /* Get pending interrupts. */\r
820         ulDMAStatus = LPC_ETHERNET->DMA_STAT;\r
821 \r
822         /* RX group interrupt(s). */\r
823         if( ( ulDMAStatus & ulRxInterruptMask ) != 0x00 )\r
824         {\r
825                 /* Remember that an RX event has happened. */\r
826                 ulISREvents |= EMAC_IF_RX_EVENT;\r
827                 vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken );\r
828         }\r
829 \r
830         /* TX group interrupt(s). */\r
831         if( ( ulDMAStatus & ulTxInterruptMask ) != 0x00 )\r
832         {\r
833                 /* Remember that a TX event has happened. */\r
834                 ulISREvents |= EMAC_IF_TX_EVENT;\r
835                 vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken );\r
836         }\r
837 \r
838         /* Test for 'Abnormal interrupt summary'. */\r
839         if( ( ulDMAStatus & DMA_ST_AIE ) != 0x00 )\r
840         {\r
841                 /* The trace macro must be written such that it can be called from\r
842                 an interrupt. */\r
843                 iptraceETHERNET_RX_EVENT_LOST();\r
844         }\r
845 \r
846         /* Clear pending interrupts */\r
847         LPC_ETHERNET->DMA_STAT = ulDMAStatus;\r
848 \r
849         /* Context switch needed? */\r
850         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
851 }\r
852 /*-----------------------------------------------------------*/\r
853 \r
854 static BaseType_t prvSetLinkSpeed( void )\r
855 {\r
856 BaseType_t xReturn = pdFAIL;\r
857 TickType_t xTimeOnEntering;\r
858 uint32_t ulPhyStatus;\r
859 const TickType_t xAutoNegotiateDelay = pdMS_TO_TICKS( 5000UL );\r
860 \r
861         /* Ensure polling does not starve lower priority tasks by temporarily\r
862         setting the priority of this task to that of the idle task. */\r
863         vTaskPrioritySet( NULL, tskIDLE_PRIORITY );\r
864 \r
865         xTimeOnEntering = xTaskGetTickCount();\r
866         do\r
867         {\r
868                 ulPhyStatus = lpcPHYStsPoll();\r
869                 if( ( ulPhyStatus & PHY_LINK_CONNECTED ) != 0x00 )\r
870                 {\r
871                         /* Set interface speed and duplex. */\r
872                         if( ( ulPhyStatus & PHY_LINK_SPEED100 ) != 0x00 )\r
873                         {\r
874                                 Chip_ENET_SetSpeed( LPC_ETHERNET, 1 );\r
875                         }\r
876                         else\r
877                         {\r
878                                 Chip_ENET_SetSpeed( LPC_ETHERNET, 0 );\r
879                         }\r
880 \r
881                         if( ( ulPhyStatus & PHY_LINK_FULLDUPLX ) != 0x00 )\r
882                         {\r
883                                 Chip_ENET_SetDuplex( LPC_ETHERNET, pdTRUE );\r
884                         }\r
885                         else\r
886                         {\r
887                                 Chip_ENET_SetDuplex( LPC_ETHERNET, pdFALSE );\r
888                         }\r
889 \r
890                         xReturn = pdPASS;\r
891                         break;\r
892                 }\r
893         } while( ( xTaskGetTickCount() - xTimeOnEntering ) < xAutoNegotiateDelay );\r
894 \r
895         /* Reset the priority of this task back to its original value. */\r
896         vTaskPrioritySet( NULL, ipconfigIP_TASK_PRIORITY );\r
897 \r
898         return xReturn;\r
899 }\r
900 /*-----------------------------------------------------------*/\r
901 \r
902 static uint32_t prvGenerateCRC32( const uint8_t *ucAddress )\r
903 {\r
904 unsigned int j;\r
905 const uint32_t Polynomial = 0xEDB88320;\r
906 uint32_t crc = ~0ul;\r
907 const uint8_t *pucCurrent = ( const uint8_t * ) ucAddress;\r
908 const uint8_t *pucLast = pucCurrent + 6;\r
909 \r
910     /* Calculate  normal CRC32 */\r
911     while( pucCurrent < pucLast )\r
912     {\r
913         crc ^= *( pucCurrent++ );\r
914         for( j = 0; j < 8; j++ )\r
915         {\r
916             if( ( crc & 1 ) != 0 )\r
917             {\r
918                 crc = (crc >> 1) ^ Polynomial;\r
919             }\r
920             else\r
921             {\r
922                 crc >>= 1;\r
923             }\r
924         }\r
925     }\r
926     return ~crc;\r
927 }\r
928 /*-----------------------------------------------------------*/\r
929 \r
930 static uint32_t prvGetHashIndex( const uint8_t *ucAddress )\r
931 {\r
932 uint32_t ulCrc = prvGenerateCRC32( ucAddress );\r
933 uint32_t ulIndex = 0ul;\r
934 BaseType_t xCount = 6;\r
935 \r
936     /* Take the lowest 6 bits of the CRC32 and reverse them */\r
937     while( xCount-- )\r
938     {\r
939         ulIndex <<= 1;\r
940         ulIndex |= ( ulCrc & 1 );\r
941         ulCrc >>= 1;\r
942     }\r
943 \r
944     /* This is the has value of 'ucAddress' */\r
945     return ulIndex;\r
946 }\r
947 /*-----------------------------------------------------------*/\r
948 \r
949 static void prvAddMACAddress( const uint8_t* ucMacAddress )\r
950 {\r
951 BaseType_t xIndex;\r
952 \r
953     xIndex = prvGetHashIndex( ucMacAddress );\r
954     if( xIndex >= 32 )\r
955     {\r
956         LPC_ETHERNET->MAC_HASHTABLE_HIGH |= ( 1u << ( xIndex - 32 ) );\r
957     }\r
958     else\r
959     {\r
960         LPC_ETHERNET->MAC_HASHTABLE_LOW |= ( 1u << xIndex );\r
961     }\r
962 }\r
963 /*-----------------------------------------------------------*/\r
964 \r
965 configPLACE_IN_SECTION_RAM\r
966 static void prvEMACHandlerTask( void *pvParameters )\r
967 {\r
968 TimeOut_t xPhyTime;\r
969 TickType_t xPhyRemTime;\r
970 UBaseType_t uxLastMinBufferCount = 0;\r
971 UBaseType_t uxCurrentCount;\r
972 BaseType_t xResult = 0;\r
973 uint32_t ulStatus;\r
974 const TickType_t xBlockTime = pdMS_TO_TICKS( 5000ul );\r
975 \r
976         /* Remove compiler warning about unused parameter. */\r
977         ( void ) pvParameters;\r
978 \r
979         /* A possibility to set some additional task properties. */\r
980         iptraceEMAC_TASK_STARTING();\r
981 \r
982         vTaskSetTimeOutState( &xPhyTime );\r
983         xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );\r
984 \r
985         for( ;; )\r
986         {\r
987                 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();\r
988                 if( uxLastMinBufferCount != uxCurrentCount )\r
989                 {\r
990                         /* The logging produced below may be helpful\r
991                         while tuning +TCP: see how many buffers are in use. */\r
992                         uxLastMinBufferCount = uxCurrentCount;\r
993                         FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",\r
994                                 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );\r
995                 }\r
996 \r
997                 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
998                 {\r
999                 static UBaseType_t uxLastMinQueueSpace = 0;\r
1000 \r
1001                         uxCurrentCount = uxGetMinimumIPQueueSpace();\r
1002                         if( uxLastMinQueueSpace != uxCurrentCount )\r
1003                         {\r
1004                                 /* The logging produced below may be helpful\r
1005                                 while tuning +TCP: see how many buffers are in use. */\r
1006                                 uxLastMinQueueSpace = uxCurrentCount;\r
1007                                 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );\r
1008                         }\r
1009                 }\r
1010                 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */\r
1011 \r
1012                 ulTaskNotifyTake( pdTRUE, xBlockTime );\r
1013 \r
1014                 xResult = ( BaseType_t ) 0;\r
1015 \r
1016                 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )\r
1017                 {\r
1018                         /* Code to release TX buffers if zero-copy is used. */\r
1019                         ulISREvents &= ~EMAC_IF_TX_EVENT;\r
1020                         {\r
1021                                 /* Check if DMA packets have been delivered. */\r
1022                                 vClearTXBuffers();\r
1023                         }\r
1024                 }\r
1025 \r
1026                 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )\r
1027                 {\r
1028                         ulISREvents &= ~EMAC_IF_RX_EVENT;\r
1029 \r
1030                         xResult = prvNetworkInterfaceInput();\r
1031                         if( xResult > 0 )\r
1032                         {\r
1033                                 while( prvNetworkInterfaceInput() > 0 )\r
1034                                 {\r
1035                                 }\r
1036                         }\r
1037                 }\r
1038 \r
1039                 if( xResult > 0 )\r
1040                 {\r
1041                         /* A packet was received. No need to check for the PHY status now,\r
1042                         but set a timer to check it later on. */\r
1043                         vTaskSetTimeOutState( &xPhyTime );\r
1044                         xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );\r
1045                         xResult = 0;\r
1046                 }\r
1047                 else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )\r
1048                 {\r
1049                         ulStatus = lpcPHYStsPoll();\r
1050 \r
1051                         if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != ( ulStatus & PHY_LINK_CONNECTED ) )\r
1052                         {\r
1053                                 ulPHYLinkStatus = ulStatus;\r
1054                                 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d (polled PHY)\n", ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 ) );\r
1055                         }\r
1056 \r
1057                         vTaskSetTimeOutState( &xPhyTime );\r
1058                         if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 )\r
1059                         {\r
1060                                 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );\r
1061                         }\r
1062                         else\r
1063                         {\r
1064                                 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );\r
1065                         }\r
1066                 }\r
1067         }\r
1068 }\r
1069 /*-----------------------------------------------------------*/\r