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