]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c
Update version number in readiness for V10.3.0 release. Sync SVN with reviewed releas...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / LPC18xx / NetworkInterface.c
index ac01d41af47d865905094c6edafdaad777c99609..0b1f74d075554b9580f7ca5f489e263c0fff85a9 100644 (file)
-/*\r
-FreeRTOS+TCP V2.0.11\r
-Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
-\r
-Permission is hereby granted, free of charge, to any person obtaining a copy of\r
-this software and associated documentation files (the "Software"), to deal in\r
-the Software without restriction, including without limitation the rights to\r
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
-the Software, and to permit persons to whom the Software is furnished to do so,\r
-subject to the following conditions:\r
-\r
-The above copyright notice and this permission notice shall be included in all\r
-copies or substantial portions of the Software.\r
-\r
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-\r
- http://aws.amazon.com/freertos\r
- http://www.FreeRTOS.org\r
-*/\r
-\r
-/* Standard includes. */\r
-#include <stdint.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-\r
-/* FreeRTOS includes. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "queue.h"\r
-#include "semphr.h"\r
-\r
-/* FreeRTOS+TCP includes. */\r
-#include "FreeRTOS_IP.h"\r
-#include "FreeRTOS_Sockets.h"\r
-#include "FreeRTOS_IP_Private.h"\r
-#include "NetworkBufferManagement.h"\r
-#include "NetworkInterface.h"\r
-\r
-/* LPCOpen includes. */\r
-#include "chip.h"\r
-#include "lpc_phy.h"\r
-\r
-/* The size of the stack allocated to the task that handles Rx packets. */\r
-#define nwRX_TASK_STACK_SIZE   140\r
-\r
-#ifndef        PHY_LS_HIGH_CHECK_TIME_MS\r
-       /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not\r
-       receiving packets. */\r
-       #define PHY_LS_HIGH_CHECK_TIME_MS       15000\r
-#endif\r
-\r
-#ifndef        PHY_LS_LOW_CHECK_TIME_MS\r
-       /* Check if the LinkSStatus in the PHY is still low every second. */\r
-       #define PHY_LS_LOW_CHECK_TIME_MS        1000\r
-#endif\r
-\r
-#ifndef configUSE_RMII\r
-       #define configUSE_RMII 1\r
-#endif\r
-\r
-#ifndef configNUM_RX_DESCRIPTORS\r
-       #error please define configNUM_RX_DESCRIPTORS in your FreeRTOSIPConfig.h\r
-#endif\r
-\r
-#ifndef configNUM_TX_DESCRIPTORS\r
-       #error please define configNUM_TX_DESCRIPTORS in your FreeRTOSIPConfig.h\r
-#endif\r
-\r
-#ifndef NETWORK_IRQHandler\r
-       #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
-#endif\r
-\r
-#if !defined( MAC_FF_HMC )\r
-       /* Hash for multicast. */\r
-       #define MAC_FF_HMC     ( 1UL << 2UL )\r
-#endif\r
-\r
-#ifndef iptraceEMAC_TASK_STARTING\r
-       #define iptraceEMAC_TASK_STARTING()     do { } while( 0 )\r
-#endif\r
-\r
-/* Define the bits of .STATUS that indicate a reception error. */\r
-#define nwRX_STATUS_ERROR_BITS \\r
-       ( RDES_CE  /* CRC Error */                        | \\r
-         RDES_RE  /* Receive Error */                    | \\r
-         RDES_DE  /* Descriptor Error */                 | \\r
-         RDES_RWT /* Receive Watchdog Timeout */         | \\r
-         RDES_LC  /* Late Collision */                   | \\r
-         RDES_OE  /* Overflow Error */                   | \\r
-         RDES_SAF /* Source Address Filter Fail */       | \\r
-         RDES_AFM /* Destination Address Filter Fail */  | \\r
-         RDES_LE  /* Length Error */                     )\r
-\r
-/* Define the EMAC status bits that should trigger an interrupt. */\r
-#define nwDMA_INTERRUPT_MASK \\r
-       ( DMA_IE_TIE  /* Transmit interrupt enable */         | \\r
-         DMA_IE_TSE  /* Transmit stopped enable */           | \\r
-         DMA_IE_OVE  /* Overflow interrupt enable */         | \\r
-         DMA_IE_RIE  /* Receive interrupt enable */          | \\r
-         DMA_IE_NIE  /* Normal interrupt summary enable */   | \\r
-         DMA_IE_AIE  /* Abnormal interrupt summary enable */ | \\r
-         DMA_IE_RUE  /* Receive buffer unavailable enable */ | \\r
-         DMA_IE_UNE  /* Underflow interrupt enable. */       | \\r
-         DMA_IE_TJE  /* Transmit jabber timeout enable */    | \\r
-         DMA_IE_RSE  /* Received stopped enable */           | \\r
-         DMA_IE_RWE  /* Receive watchdog timeout enable */   | \\r
-         DMA_IE_FBE )/* Fatal bus error enable */\r
-\r
-/* Interrupt events to process.  Currently only the RX/TX events are processed\r
-although code for other events is included to allow for possible future\r
-expansion. */\r
-#define EMAC_IF_RX_EVENT        1UL\r
-#define EMAC_IF_TX_EVENT        2UL\r
-#define EMAC_IF_ERR_EVENT       4UL\r
-#define EMAC_IF_ALL_EVENT       ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )\r
-\r
- /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet\r
- driver will filter incoming packets and only pass the stack those packets it\r
- considers need processing. */\r
- #if( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )\r
-       #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer\r
- #else\r
-       #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )\r
- #endif\r
-\r
-#if( ipconfigZERO_COPY_RX_DRIVER == 0 ) || ( ipconfigZERO_COPY_TX_DRIVER == 0 )\r
-       #warning It is adviced to enable both macros\r
-#endif\r
-\r
-#ifndef configPLACE_IN_SECTION_RAM\r
-       #define configPLACE_IN_SECTION_RAM\r
-/*\r
-       #define configPLACE_IN_SECTION_RAM      __attribute__ ((section(".ramfunc")))\r
-*/\r
-#endif\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Delay function passed into the library.  The implementation uses FreeRTOS\r
- * calls so the scheduler must be started before the driver can be used.\r
- */\r
-static void prvDelay( uint32_t ulMilliSeconds );\r
-\r
-/*\r
- * Initialises the Tx and Rx descriptors respectively.\r
- */\r
-static void prvSetupTxDescriptors( void );\r
-static void prvSetupRxDescriptors( void );\r
-\r
-/*\r
- * A task that processes received frames.\r
- */\r
-static void prvEMACHandlerTask( void *pvParameters );\r
-\r
-/*\r
- * Sets up the MAC with the results of an auto-negotiation.\r
- */\r
-static BaseType_t prvSetLinkSpeed( void );\r
-\r
-/*\r
- * Generates a CRC for a MAC address that is then used to generate a hash index.\r
- */\r
-static uint32_t prvGenerateCRC32( const uint8_t *ucAddress );\r
-\r
-/*\r
- * Generates a hash index when setting a filter to permit a MAC address.\r
- */\r
-static uint32_t prvGetHashIndex( const uint8_t *ucAddress );\r
-\r
-/*\r
- * Update the hash table to allow a MAC address.\r
- */\r
-static void prvAddMACAddress( const uint8_t* ucMacAddress );\r
-\r
-/*\r
- * Sometimes the DMA will report received data as being longer than the actual\r
- * received from length.  This function checks the reported length and corrects\r
- * if if necessary.\r
- */\r
-static void prvRemoveTrailingBytes( NetworkBufferDescriptor_t *pxDescriptor );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Bit map of outstanding ETH interrupt events for processing.  Currently only\r
-the Rx and Tx interrupt is handled, although code is included for other events\r
-to enable future expansion. */\r
-static volatile uint32_t ulISREvents;\r
-\r
-/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */\r
-static uint32_t ulPHYLinkStatus = 0;\r
-\r
-/* Tx descriptors and index. */\r
-static ENET_ENHTXDESC_T xDMATxDescriptors[ configNUM_TX_DESCRIPTORS ];\r
-\r
-/* ulNextFreeTxDescriptor is declared volatile, because it is accessed from\r
-to different tasks. */\r
-static volatile uint32_t ulNextFreeTxDescriptor;\r
-static uint32_t ulTxDescriptorToClear;\r
-\r
-/* Rx descriptors and index. */\r
-static ENET_ENHRXDESC_T xDMARxDescriptors[ configNUM_RX_DESCRIPTORS ];\r
-static uint32_t ulNextRxDescriptorToProcess;\r
-\r
-/* Must be defined externally - the demo applications define this in main.c. */\r
-extern uint8_t ucMACAddress[ 6 ];\r
-\r
-/* The handle of the task that processes Rx packets.  The handle is required so\r
-the task can be notified when new packets arrive. */\r
-static TaskHandle_t xRxHanderTask = NULL;\r
-\r
-#if( ipconfigUSE_LLMNR == 1 )\r
-       static const uint8_t xLLMNR_MACAddress[] = { '\x01', '\x00', '\x5E', '\x00', '\x00', '\xFC' };\r
-#endif /* ipconfigUSE_LLMNR == 1 */\r
-\r
-/* xTXDescriptorSemaphore is a counting semaphore with\r
-a maximum count of ETH_TXBUFNB, which is the number of\r
-DMA TX descriptors. */\r
-static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-\r
-BaseType_t xNetworkInterfaceInitialise( void )\r
-{\r
-BaseType_t xReturn = pdPASS;\r
-\r
-       /* The interrupt will be turned on when a link is established. */\r
-       NVIC_DisableIRQ( ETHERNET_IRQn );\r
-\r
-       /* Disable receive and transmit DMA processes. */\r
-       LPC_ETHERNET->DMA_OP_MODE &= ~( DMA_OM_ST | DMA_OM_SR );\r
-\r
-       /* Disable packet reception. */\r
-       LPC_ETHERNET->MAC_CONFIG &= ~( MAC_CFG_RE | MAC_CFG_TE );\r
-\r
-       /* Call the LPCOpen function to initialise the hardware. */\r
-       Chip_ENET_Init( LPC_ETHERNET );\r
-\r
-       /* Save MAC address. */\r
-       Chip_ENET_SetADDR( LPC_ETHERNET, ucMACAddress );\r
-\r
-       /* Clear all MAC address hash entries. */\r
-       LPC_ETHERNET->MAC_HASHTABLE_HIGH = 0;\r
-       LPC_ETHERNET->MAC_HASHTABLE_LOW = 0;\r
-\r
-       #if( ipconfigUSE_LLMNR == 1 )\r
-       {\r
-               prvAddMACAddress( xLLMNR_MACAddress );\r
-       }\r
-       #endif /* ipconfigUSE_LLMNR == 1 */\r
-\r
-       /* Promiscuous flag (PR) and Receive All flag (RA) set to zero.  The\r
-       registers MAC_HASHTABLE_[LOW|HIGH] will be loaded to allow certain\r
-       multi-cast addresses. */\r
-       LPC_ETHERNET->MAC_FRAME_FILTER = MAC_FF_HMC;\r
-\r
-       #if( configUSE_RMII == 1 )\r
-       {\r
-               if( lpc_phy_init( pdTRUE, prvDelay ) != SUCCESS )\r
-               {\r
-                       xReturn = pdFAIL;\r
-               }\r
-       }\r
-       #else\r
-       {\r
-               #warning This path has not been tested.\r
-               if( lpc_phy_init( pdFALSE, prvDelay ) != SUCCESS )\r
-               {\r
-                       xReturn = pdFAIL;\r
-               }\r
-       }\r
-       #endif\r
-\r
-       if( xReturn == pdPASS )\r
-       {\r
-               /* Guard against the task being created more than once and the\r
-               descriptors being initialised more than once. */\r
-               if( xRxHanderTask == NULL )\r
-               {\r
-                       xReturn = xTaskCreate( prvEMACHandlerTask, "EMAC", nwRX_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xRxHanderTask );\r
-                       configASSERT( xReturn );\r
-               }\r
-\r
-               if( xTXDescriptorSemaphore == NULL )\r
-               {\r
-                       /* Create a counting semaphore, with a value of 'configNUM_TX_DESCRIPTORS'\r
-                       and a maximum of 'configNUM_TX_DESCRIPTORS'. */\r
-                       xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) configNUM_TX_DESCRIPTORS, ( UBaseType_t ) configNUM_TX_DESCRIPTORS );\r
-                       configASSERT( xTXDescriptorSemaphore );\r
-               }\r
-\r
-               /* Enable MAC interrupts. */\r
-               LPC_ETHERNET->DMA_INT_EN = nwDMA_INTERRUPT_MASK;\r
-       }\r
-\r
-       if( xReturn != pdFAIL )\r
-       {\r
-               /* Auto-negotiate was already started.  Wait for it to complete. */\r
-               xReturn = prvSetLinkSpeed();\r
-\r
-               if( xReturn == pdPASS )\r
-               {\r
-                       /* Initialise the descriptors. */\r
-                       prvSetupTxDescriptors();\r
-                       prvSetupRxDescriptors();\r
-\r
-                       /* Clear all interrupts. */\r
-                       LPC_ETHERNET->DMA_STAT = DMA_ST_ALL;\r
-\r
-                       /* Enable receive and transmit DMA processes. */\r
-                       LPC_ETHERNET->DMA_OP_MODE |= DMA_OM_ST | DMA_OM_SR;\r
-\r
-                       /* Set Receiver / Transmitter Enable. */\r
-                       LPC_ETHERNET->MAC_CONFIG |= MAC_CFG_RE | MAC_CFG_TE;\r
-\r
-                       /* Start receive polling. */\r
-                       LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1;\r
-\r
-                       /* Enable interrupts in the NVIC. */\r
-                       NVIC_SetPriority( ETHERNET_IRQn, configMAC_INTERRUPT_PRIORITY );\r
-                       NVIC_EnableIRQ( ETHERNET_IRQn );\r
-               }\r
-       }\r
-\r
-       return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#define niBUFFER_1_PACKET_SIZE         1536\r
-\r
-static __attribute__ ((section("._ramAHB32"))) uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) );\r
-\r
-void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )\r
-{\r
-\r
-uint8_t *ucRAMBuffer = ucNetworkPackets;\r
-uint32_t ul;\r
-\r
-       for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )\r
-       {\r
-               pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;\r
-               *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );\r
-               ucRAMBuffer += niBUFFER_1_PACKET_SIZE;\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-configPLACE_IN_SECTION_RAM\r
-static void vClearTXBuffers()\r
-{\r
-uint32_t ulLastDescriptor = ulNextFreeTxDescriptor;\r
-size_t uxCount = ( ( size_t ) configNUM_TX_DESCRIPTORS ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );\r
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-       NetworkBufferDescriptor_t *pxNetworkBuffer;\r
-       uint8_t *ucPayLoad;\r
-#endif\r
-\r
-       /* This function is called after a TX-completion interrupt.\r
-       It will release each Network Buffer used in xNetworkInterfaceOutput().\r
-       'uxCount' represents the number of descriptors given to DMA for transmission.\r
-       After sending a packet, the DMA will clear the 'TDES_OWN' bit. */\r
-       while( ( uxCount > ( size_t ) 0u ) && ( ( xDMATxDescriptors[ ulTxDescriptorToClear ].CTRLSTAT & TDES_OWN ) == 0 ) )\r
-       {\r
-               if( ( ulTxDescriptorToClear == ulLastDescriptor ) && ( uxCount != ( size_t ) configNUM_TX_DESCRIPTORS ) )\r
-               {\r
-                       break;\r
-               }\r
-\r
-\r
-               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-               {\r
-                       ucPayLoad = ( uint8_t * )xDMATxDescriptors[ ulTxDescriptorToClear ].B1ADD;\r
-                       if( ucPayLoad != NULL )\r
-                       {\r
-                               /* B1ADD points to a pucEthernetBuffer of a Network Buffer descriptor. */\r
-                               pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );\r
-\r
-                               configASSERT( pxNetworkBuffer != NULL );\r
-\r
-                               vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ;\r
-                               xDMATxDescriptors[ ulTxDescriptorToClear ].B1ADD = ( uint32_t )0u;\r
-                       }\r
-               }\r
-               #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
-\r
-               /* Move onto the next descriptor, wrapping if necessary. */\r
-               ulTxDescriptorToClear++;\r
-               if( ulTxDescriptorToClear >= configNUM_TX_DESCRIPTORS )\r
-               {\r
-                       ulTxDescriptorToClear = 0;\r
-               }\r
-\r
-               uxCount--;\r
-               /* Tell the counting semaphore that one more TX descriptor is available. */\r
-               xSemaphoreGive( xTXDescriptorSemaphore );\r
-       }\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-configPLACE_IN_SECTION_RAM\r
-BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )\r
-{\r
-BaseType_t xReturn = pdFAIL;\r
-const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50 );\r
-\r
-       /* Attempt to obtain access to a Tx descriptor. */\r
-       do\r
-       {\r
-               if( xTXDescriptorSemaphore == NULL )\r
-               {\r
-                       break;\r
-               }\r
-               if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )\r
-               {\r
-                       /* Time-out waiting for a free TX descriptor. */\r
-                       break;\r
-               }\r
-\r
-               /* If the descriptor is still owned by the DMA it can't be used. */\r
-               if( ( xDMATxDescriptors[ ulNextFreeTxDescriptor ].CTRLSTAT & TDES_OWN ) != 0 )\r
-               {\r
-                       /* The semaphore was taken, the TX DMA-descriptor is still not available.\r
-                       Actually that should not occur, the 'TDES_OWN' was already confirmed low in vClearTXBuffers(). */\r
-                       xSemaphoreGive( xTXDescriptorSemaphore );\r
-               }\r
-               else\r
-               {\r
-                       #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-                       {\r
-                               /* bReleaseAfterSend should always be set when using the zero\r
-                               copy driver. */\r
-                               configASSERT( bReleaseAfterSend != pdFALSE );\r
-\r
-                               /* The DMA's descriptor to point directly to the data in the\r
-                               network buffer descriptor.  The data is not copied. */\r
-                               xDMATxDescriptors[ ulNextFreeTxDescriptor ].B1ADD = ( uint32_t ) pxDescriptor->pucEthernetBuffer;\r
-\r
-                               /* The DMA descriptor will 'own' this Network Buffer,\r
-                               until it has been sent.  So don't release it now. */\r
-                               bReleaseAfterSend = false;\r
-                       }\r
-                       #else\r
-                       {\r
-                               /* The data is copied from the network buffer descriptor into\r
-                               the DMA's descriptor. */\r
-                               memcpy( ( void * ) xDMATxDescriptors[ ulNextFreeTxDescriptor ].B1ADD, ( void * ) pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength );\r
-                       }\r
-                       #endif\r
-\r
-                       xDMATxDescriptors[ ulNextFreeTxDescriptor ].BSIZE = ( uint32_t ) TDES_ENH_BS1( pxDescriptor->xDataLength );\r
-\r
-                       /* This descriptor is given back to the DMA. */\r
-                       xDMATxDescriptors[ ulNextFreeTxDescriptor ].CTRLSTAT |= TDES_OWN;\r
-\r
-                       /* Ensure the DMA is polling Tx descriptors. */\r
-                       LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1;\r
-\r
-            iptraceNETWORK_INTERFACE_TRANSMIT();\r
-\r
-                       /* Move onto the next descriptor, wrapping if necessary. */\r
-                       ulNextFreeTxDescriptor++;\r
-                       if( ulNextFreeTxDescriptor >= configNUM_TX_DESCRIPTORS )\r
-                       {\r
-                               ulNextFreeTxDescriptor = 0;\r
-                       }\r
-\r
-                       /* The Tx has been initiated. */\r
-                       xReturn = pdPASS;\r
-               }\r
-       } while( 0 );\r
-\r
-       /* The buffer has been sent so can be released. */\r
-       if( bReleaseAfterSend != pdFALSE )\r
-       {\r
-               vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
-       }\r
-\r
-       return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvDelay( uint32_t ulMilliSeconds )\r
-{\r
-       /* Ensure the scheduler was started before attempting to use the scheduler to\r
-       create a delay. */\r
-       configASSERT( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING );\r
-\r
-       vTaskDelay( pdMS_TO_TICKS( ulMilliSeconds ) );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvSetupTxDescriptors( void )\r
-{\r
-BaseType_t x;\r
-\r
-       /* Start with Tx descriptors clear. */\r
-       memset( ( void * ) xDMATxDescriptors, 0, sizeof( xDMATxDescriptors ) );\r
-\r
-       /* Index to the next Tx descriptor to use. */\r
-       ulNextFreeTxDescriptor = 0ul;\r
-\r
-       /* Index to the next Tx descriptor to clear ( after transmission ). */\r
-       ulTxDescriptorToClear = 0ul;\r
-\r
-       for( x = 0; x < configNUM_TX_DESCRIPTORS; x++ )\r
-       {\r
-               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-               {\r
-                       /* Nothing to do, B1ADD will be set when data is ready to transmit.\r
-                       Currently the memset above will have set it to NULL. */\r
-               }\r
-               #else\r
-               {\r
-                       /* Allocate a buffer to the Tx descriptor.  This is the most basic\r
-                       way of creating a driver as the data is then copied into the\r
-                       buffer. */\r
-                       xDMATxDescriptors[ x ].B1ADD = ( uint32_t ) pvPortMalloc( ipTOTAL_ETHERNET_FRAME_SIZE );\r
-\r
-                       /* Use an assert to check the allocation as +TCP applications will\r
-                       often not use a malloc() failed hook as the TCP stack will recover\r
-                       from allocation failures. */\r
-                       configASSERT( xDMATxDescriptors[ x ].B1ADD );\r
-               }\r
-               #endif\r
-\r
-               /* Buffers hold an entire frame so all buffers are both the start and\r
-               end of a frame. */\r
-               /* TDES_ENH_TCH     Second Address Chained. */\r
-               /* TDES_ENH_CIC(n)  Checksum Insertion Control, tried but it does not work for the LPC18xx... */\r
-               /* TDES_ENH_FS      First Segment. */\r
-               /* TDES_ENH_LS      Last Segment. */\r
-               /* TDES_ENH_IC      Interrupt on Completion. */\r
-               xDMATxDescriptors[ x ].CTRLSTAT = TDES_ENH_TCH | TDES_ENH_CIC( 3 ) | TDES_ENH_FS | TDES_ENH_LS | TDES_ENH_IC;\r
-               xDMATxDescriptors[ x ].B2ADD = ( uint32_t ) &xDMATxDescriptors[ x + 1 ];\r
-       }\r
-\r
-       xDMATxDescriptors[ configNUM_TX_DESCRIPTORS - 1 ].CTRLSTAT |= TDES_ENH_TER;\r
-       xDMATxDescriptors[ configNUM_TX_DESCRIPTORS - 1 ].B2ADD = ( uint32_t ) &xDMATxDescriptors[ 0 ];\r
-\r
-       /* Point the DMA to the base of the descriptor list. */\r
-       LPC_ETHERNET->DMA_TRANS_DES_ADDR = ( uint32_t ) xDMATxDescriptors;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvSetupRxDescriptors( void )\r
-{\r
-BaseType_t x;\r
-#if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
-       NetworkBufferDescriptor_t *pxNetworkBuffer;\r
-#endif\r
-\r
-       /* Index to the next Rx descriptor to use. */\r
-       ulNextRxDescriptorToProcess = 0;\r
-\r
-       /* Clear RX descriptor list. */\r
-       memset( ( void * )  xDMARxDescriptors, 0, sizeof( xDMARxDescriptors ) );\r
-\r
-       for( x = 0; x < configNUM_RX_DESCRIPTORS; x++ )\r
-       {\r
-               /* Allocate a buffer of the largest     possible frame size as it is not\r
-               known what size received frames will be. */\r
-\r
-               #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
-               {\r
-                       pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, 0 );\r
-\r
-                       /* During start-up there should be enough Network Buffers available,\r
-                       so it is safe to use configASSERT().\r
-                       In case this assert fails, please check: configNUM_RX_DESCRIPTORS,\r
-                       ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, and in case BufferAllocation_2.c\r
-                       is included, check the amount of available heap. */\r
-                       configASSERT( pxNetworkBuffer != NULL );\r
-\r
-                       /* Pass the actual buffer to DMA. */\r
-                       xDMARxDescriptors[ x ].B1ADD = ( uint32_t ) pxNetworkBuffer->pucEthernetBuffer;\r
-               }\r
-               #else\r
-               {\r
-                       /* All DMA descriptors are populated with permanent memory blocks.\r
-                       Their contents will be copy to Network Buffers. */\r
-                       xDMARxDescriptors[ x ].B1ADD = ( uint32_t ) pvPortMalloc( ipTOTAL_ETHERNET_FRAME_SIZE );\r
-               }\r
-               #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
-\r
-               /* Use an assert to check the allocation as +TCP applications will often\r
-               not use a malloc failed hook as the TCP stack will recover from\r
-               allocation failures. */\r
-               configASSERT( xDMARxDescriptors[ x ].B1ADD );\r
-\r
-               xDMARxDescriptors[ x ].B2ADD = ( uint32_t ) &( xDMARxDescriptors[ x + 1 ] );\r
-               xDMARxDescriptors[ x ].CTRL = ( uint32_t ) RDES_ENH_BS1( ipTOTAL_ETHERNET_FRAME_SIZE ) | RDES_ENH_RCH;\r
-\r
-               /* The descriptor is available for use by the DMA. */\r
-               xDMARxDescriptors[ x ].STATUS = RDES_OWN;\r
-       }\r
-\r
-       /* RDES_ENH_RER  Receive End of Ring. */\r
-       xDMARxDescriptors[ ( configNUM_RX_DESCRIPTORS - 1 ) ].CTRL |= RDES_ENH_RER;\r
-       xDMARxDescriptors[ configNUM_RX_DESCRIPTORS - 1 ].B2ADD = ( uint32_t ) &( xDMARxDescriptors[ 0 ] );\r
-\r
-       /* Point the DMA to the base of the descriptor list. */\r
-       LPC_ETHERNET->DMA_REC_DES_ADDR = ( uint32_t ) xDMARxDescriptors;\r
-}\r
-/*-----------------------------------------------------------*/\r
-configPLACE_IN_SECTION_RAM\r
-static void prvRemoveTrailingBytes( NetworkBufferDescriptor_t *pxDescriptor )\r
-{\r
-size_t xExpectedLength;\r
-IPPacket_t *pxIPPacket;\r
-\r
-       pxIPPacket = ( IPPacket_t * ) pxDescriptor->pucEthernetBuffer;\r
-       /* Look at the actual length of the packet, translate it to a host-endial notation. */\r
-       xExpectedLength = sizeof( EthernetHeader_t ) + ( size_t ) FreeRTOS_htons( pxIPPacket->xIPHeader.usLength );\r
-\r
-       if( xExpectedLength == ( pxDescriptor->xDataLength + 4 ) )\r
-       {\r
-               pxDescriptor->xDataLength -= 4;\r
-       }\r
-       else\r
-       {\r
-               if( pxDescriptor->xDataLength > xExpectedLength )\r
-               {\r
-                       pxDescriptor->xDataLength = ( size_t ) xExpectedLength;\r
-               }\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-configPLACE_IN_SECTION_RAM\r
-BaseType_t xGetPhyLinkStatus( void )\r
-{\r
-BaseType_t xReturn;\r
-\r
-       if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) == 0 )\r
-       {\r
-               xReturn = pdFALSE;\r
-       }\r
-       else\r
-       {\r
-               xReturn = pdTRUE;\r
-       }\r
-\r
-       return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-uint32_t ulDataAvailable;\r
-\r
-configPLACE_IN_SECTION_RAM\r
-static BaseType_t prvNetworkInterfaceInput()\r
-{\r
-BaseType_t xResult = pdFALSE;\r
-uint32_t ulStatus;\r
-eFrameProcessingResult_t eResult;\r
-const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 );\r
-const UBaseType_t uxMinimumBuffersRemaining = 3UL;\r
-uint16_t usLength;\r
-NetworkBufferDescriptor_t *pxDescriptor;\r
-#if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
-       NetworkBufferDescriptor_t *pxNewDescriptor;\r
-#endif /* ipconfigZERO_COPY_RX_DRIVER */\r
-#if( ipconfigUSE_LINKED_RX_MESSAGES == 0 )\r
-       IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };\r
-#endif\r
-\r
-       /* Process each descriptor that is not still in use by the DMA. */\r
-       ulStatus = xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS;\r
-       if( ( ulStatus & RDES_OWN ) == 0 )\r
-       {\r
-               /* Check packet for errors */\r
-               if( ( ulStatus & nwRX_STATUS_ERROR_BITS ) != 0 )\r
-               {\r
-                       /* There is some reception error. */\r
-                       intCount[ 3 ]++;\r
-                       /* Clear error bits. */\r
-                       ulStatus &= ~( ( uint32_t )nwRX_STATUS_ERROR_BITS );\r
-               }\r
-               else\r
-               {\r
-                       xResult++;\r
-\r
-                       eResult = ipCONSIDER_FRAME_FOR_PROCESSING( ( const uint8_t * const ) ( xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD ) );\r
-                       if( eResult == eProcessBuffer )\r
-                       {\r
-                               if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) == 0 )\r
-                               {\r
-                                       ulPHYLinkStatus |= PHY_LINK_CONNECTED;\r
-                                       FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d (message received)\n", ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 ) );\r
-                               }\r
-\r
-                       #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
-                               if( uxGetNumberOfFreeNetworkBuffers() > uxMinimumBuffersRemaining )\r
-                               {\r
-                                       pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xDescriptorWaitTime );\r
-                               }\r
-                               else\r
-                               {\r
-                                       /* Too risky to allocate a new Network Buffer. */\r
-                                       pxNewDescriptor = NULL;\r
-                               }\r
-                               if( pxNewDescriptor != NULL )\r
-                       #else\r
-                               if( uxGetNumberOfFreeNetworkBuffers() > uxMinimumBuffersRemaining )\r
-                       #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
-                               {\r
-                       #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
-                               const uint8_t *pucBuffer;\r
-                       #endif\r
-\r
-                                       /* Get the actual length. */\r
-                                       usLength = RDES_FLMSK( ulStatus );\r
-\r
-                                       #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
-                                       {\r
-                                               /* Replace the character buffer 'B1ADD'. */\r
-                                               pucBuffer = ( const uint8_t * const ) ( xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD );\r
-                                               xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD = ( uint32_t ) pxNewDescriptor->pucEthernetBuffer;\r
-\r
-                                               /* 'B1ADD' contained the address of a 'pucEthernetBuffer' that\r
-                                               belongs to a Network Buffer.  Find the original Network Buffer. */\r
-                                               pxDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer );\r
-                                               /* This zero-copy driver makes sure that every 'xDMARxDescriptors' contains\r
-                                               a reference to a Network Buffer at any time.\r
-                                               In case it runs out of Network Buffers, a DMA buffer won't be replaced,\r
-                                               and the received messages is dropped. */\r
-                                               configASSERT( pxDescriptor != NULL );\r
-                                       }\r
-                                       #else\r
-                                       {\r
-                                               /* Create a buffer of exactly the required length. */\r
-                                               pxDescriptor = pxGetNetworkBufferWithDescriptor( usLength, xDescriptorWaitTime );\r
-                                       }\r
-                                       #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
-\r
-                                       if( pxDescriptor != NULL )\r
-                                       {\r
-                                               pxDescriptor->xDataLength = ( size_t ) usLength;\r
-                                               #if( ipconfigZERO_COPY_RX_DRIVER == 0 )\r
-                                               {\r
-                                                       /* Copy the data into the allocated buffer. */\r
-                                                       memcpy( ( void * ) pxDescriptor->pucEthernetBuffer, ( void * ) xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD, usLength );\r
-                                               }\r
-                                               #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
-                                               /* It is possible that more data was copied than\r
-                                               actually makes up the frame.  If this is the case\r
-                                               adjust the length to remove any trailing bytes. */\r
-                                               prvRemoveTrailingBytes( pxDescriptor );\r
-\r
-                                               /* Pass the data to the TCP/IP task for processing. */\r
-                                               xRxEvent.pvData = ( void * ) pxDescriptor;\r
-                                               if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE )\r
-                                               {\r
-                                                       /* Could not send the descriptor into the TCP/IP\r
-                                                       stack, it must be released. */\r
-                                                       vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
-                                               }\r
-                                               else\r
-                                               {\r
-                                                       iptraceNETWORK_INTERFACE_RECEIVE();\r
-\r
-                                                       /* The data that was available at the top of this\r
-                                                       loop has been sent, so is no longer available. */\r
-                                                       ulDataAvailable = pdFALSE;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               /* The packet is discarded as uninteresting. */\r
-                               ulDataAvailable = pdFALSE;\r
-                       }\r
-                       /* Got here because received data was sent to the IP task or the\r
-                       data contained an error and was discarded.  Give the descriptor\r
-                       back to the DMA. */\r
-                       xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS = ulStatus | RDES_OWN;\r
-\r
-                       /* Move onto the next descriptor. */\r
-                       ulNextRxDescriptorToProcess++;\r
-                       if( ulNextRxDescriptorToProcess >= configNUM_RX_DESCRIPTORS )\r
-                       {\r
-                               ulNextRxDescriptorToProcess = 0;\r
-                       }\r
-\r
-                       ulStatus = xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS;\r
-               } /* if( ( ulStatus & nwRX_STATUS_ERROR_BITS ) != 0 ) */\r
-       } /* if( ( ulStatus & RDES_OWN ) == 0 ) */\r
-\r
-       /* Restart receive polling. */\r
-       LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1;\r
-\r
-       return xResult;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-configPLACE_IN_SECTION_RAM\r
-void NETWORK_IRQHandler( void )\r
-{\r
-BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
-uint32_t ulDMAStatus;\r
-const uint32_t ulRxInterruptMask =\r
-       DMA_ST_RI |             /* Receive interrupt */\r
-       DMA_ST_RU;              /* Receive buffer unavailable */\r
-const uint32_t ulTxInterruptMask =\r
-       DMA_ST_TI |             /* Transmit interrupt */\r
-       DMA_ST_TPS;             /* Transmit process stopped */\r
-\r
-       configASSERT( xRxHanderTask );\r
-\r
-       /* Get pending interrupts. */\r
-       ulDMAStatus = LPC_ETHERNET->DMA_STAT;\r
-\r
-       /* RX group interrupt(s). */\r
-       if( ( ulDMAStatus & ulRxInterruptMask ) != 0x00 )\r
-       {\r
-               /* Remember that an RX event has happened. */\r
-               ulISREvents |= EMAC_IF_RX_EVENT;\r
-               vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken );\r
-               intCount[ 0 ]++;\r
-       }\r
-\r
-       /* TX group interrupt(s). */\r
-       if( ( ulDMAStatus & ulTxInterruptMask ) != 0x00 )\r
-       {\r
-               /* Remember that a TX event has happened. */\r
-               ulISREvents |= EMAC_IF_TX_EVENT;\r
-               vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken );\r
-               intCount[ 1 ]++;\r
-       }\r
-\r
-       /* Test for 'Abnormal interrupt summary'. */\r
-       if( ( ulDMAStatus & DMA_ST_AIE ) != 0x00 )\r
-       {\r
-               /* The trace macro must be written such that it can be called from\r
-               an interrupt. */\r
-               iptraceETHERNET_RX_EVENT_LOST();\r
-       }\r
-\r
-       /* Clear pending interrupts */\r
-       LPC_ETHERNET->DMA_STAT = ulDMAStatus;\r
-\r
-       /* Context switch needed? */\r
-       portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static BaseType_t prvSetLinkSpeed( void )\r
-{\r
-BaseType_t xReturn = pdFAIL;\r
-TickType_t xTimeOnEntering;\r
-uint32_t ulPhyStatus;\r
-const TickType_t xAutoNegotiateDelay = pdMS_TO_TICKS( 5000UL );\r
-\r
-       /* Ensure polling does not starve lower priority tasks by temporarily\r
-       setting the priority of this task to that of the idle task. */\r
-       vTaskPrioritySet( NULL, tskIDLE_PRIORITY );\r
-\r
-       xTimeOnEntering = xTaskGetTickCount();\r
-       do\r
-       {\r
-               ulPhyStatus = lpcPHYStsPoll();\r
-               if( ( ulPhyStatus & PHY_LINK_CONNECTED ) != 0x00 )\r
-               {\r
-                       /* Set interface speed and duplex. */\r
-                       if( ( ulPhyStatus & PHY_LINK_SPEED100 ) != 0x00 )\r
-                       {\r
-                               Chip_ENET_SetSpeed( LPC_ETHERNET, 1 );\r
-                       }\r
-                       else\r
-                       {\r
-                               Chip_ENET_SetSpeed( LPC_ETHERNET, 0 );\r
-                       }\r
-\r
-                       if( ( ulPhyStatus & PHY_LINK_FULLDUPLX ) != 0x00 )\r
-                       {\r
-                               Chip_ENET_SetDuplex( LPC_ETHERNET, true );\r
-                       }\r
-                       else\r
-                       {\r
-                               Chip_ENET_SetDuplex( LPC_ETHERNET, false );\r
-                       }\r
-\r
-                       xReturn = pdPASS;\r
-                       break;\r
-               }\r
-       } while( ( xTaskGetTickCount() - xTimeOnEntering ) < xAutoNegotiateDelay );\r
-\r
-       /* Reset the priority of this task back to its original value. */\r
-       vTaskPrioritySet( NULL, ipconfigIP_TASK_PRIORITY );\r
-\r
-       return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static uint32_t prvGenerateCRC32( const uint8_t *ucAddress )\r
-{\r
-unsigned int j;\r
-const uint32_t Polynomial = 0xEDB88320;\r
-uint32_t crc = ~0ul;\r
-const uint8_t *pucCurrent = ( const uint8_t * ) ucAddress;\r
-const uint8_t *pucLast = pucCurrent + 6;\r
-\r
-    /* Calculate  normal CRC32 */\r
-    while( pucCurrent < pucLast )\r
-    {\r
-        crc ^= *( pucCurrent++ );\r
-        for( j = 0; j < 8; j++ )\r
-        {\r
-            if( ( crc & 1 ) != 0 )\r
-            {\r
-                crc = (crc >> 1) ^ Polynomial;\r
-            }\r
-            else\r
-            {\r
-                crc >>= 1;\r
-            }\r
-        }\r
-    }\r
-    return ~crc;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static uint32_t prvGetHashIndex( const uint8_t *ucAddress )\r
-{\r
-uint32_t ulCrc = prvGenerateCRC32( ucAddress );\r
-uint32_t ulIndex = 0ul;\r
-BaseType_t xCount = 6;\r
-\r
-    /* Take the lowest 6 bits of the CRC32 and reverse them */\r
-    while( xCount-- )\r
-    {\r
-        ulIndex <<= 1;\r
-        ulIndex |= ( ulCrc & 1 );\r
-        ulCrc >>= 1;\r
-    }\r
-\r
-    /* This is the has value of 'ucAddress' */\r
-    return ulIndex;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvAddMACAddress( const uint8_t* ucMacAddress )\r
-{\r
-BaseType_t xIndex;\r
-\r
-    xIndex = prvGetHashIndex( ucMacAddress );\r
-    if( xIndex >= 32 )\r
-    {\r
-        LPC_ETHERNET->MAC_HASHTABLE_HIGH |= ( 1u << ( xIndex - 32 ) );\r
-    }\r
-    else\r
-    {\r
-        LPC_ETHERNET->MAC_HASHTABLE_LOW |= ( 1u << xIndex );\r
-    }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-configPLACE_IN_SECTION_RAM\r
-static void prvEMACHandlerTask( void *pvParameters )\r
-{\r
-TimeOut_t xPhyTime;\r
-TickType_t xPhyRemTime;\r
-UBaseType_t uxLastMinBufferCount = 0;\r
-UBaseType_t uxCurrentCount;\r
-BaseType_t xResult = 0;\r
-uint32_t ulStatus;\r
-const TickType_t xBlockTime = pdMS_TO_TICKS( 5000ul );\r
-\r
-       /* Remove compiler warning about unused parameter. */\r
-       ( void ) pvParameters;\r
-\r
-       /* A possibility to set some additional task properties. */\r
-       iptraceEMAC_TASK_STARTING();\r
-\r
-       vTaskSetTimeOutState( &xPhyTime );\r
-       xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );\r
-\r
-       for( ;; )\r
-       {\r
-               uxCurrentCount = uxGetMinimumFreeNetworkBuffers();\r
-               if( uxLastMinBufferCount != uxCurrentCount )\r
-               {\r
-                       /* The logging produced below may be helpful\r
-                       while tuning +TCP: see how many buffers are in use. */\r
-                       uxLastMinBufferCount = uxCurrentCount;\r
-                       FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",\r
-                               uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );\r
-               }\r
-\r
-               #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
-               {\r
-               static UBaseType_t uxLastMinQueueSpace = 0;\r
-\r
-                       uxCurrentCount = uxGetMinimumIPQueueSpace();\r
-                       if( uxLastMinQueueSpace != uxCurrentCount )\r
-                       {\r
-                               /* The logging produced below may be helpful\r
-                               while tuning +TCP: see how many buffers are in use. */\r
-                               uxLastMinQueueSpace = uxCurrentCount;\r
-                               FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );\r
-                       }\r
-               }\r
-               #endif /* ipconfigCHECK_IP_QUEUE_SPACE */\r
-\r
-               ulTaskNotifyTake( pdTRUE, xBlockTime );\r
-\r
-               xResult = ( BaseType_t ) 0;\r
-\r
-               if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )\r
-               {\r
-                       /* Code to release TX buffers if zero-copy is used. */\r
-                       ulISREvents &= ~EMAC_IF_TX_EVENT;\r
-                       {\r
-                               /* Check if DMA packets have been delivered. */\r
-                               vClearTXBuffers();\r
-                       }\r
-               }\r
-\r
-               if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )\r
-               {\r
-                       ulISREvents &= ~EMAC_IF_RX_EVENT;\r
-\r
-                       xResult = prvNetworkInterfaceInput();\r
-                       if( xResult > 0 )\r
-                       {\r
-                               while( prvNetworkInterfaceInput() > 0 )\r
-                               {\r
-                               }\r
-                       }\r
-               }\r
-\r
-               if( xResult > 0 )\r
-               {\r
-                       /* A packet was received. No need to check for the PHY status now,\r
-                       but set a timer to check it later on. */\r
-                       vTaskSetTimeOutState( &xPhyTime );\r
-                       xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );\r
-                       xResult = 0;\r
-               }\r
-               else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )\r
-               {\r
-                       ulStatus = lpcPHYStsPoll();\r
-\r
-                       if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != ( ulStatus & PHY_LINK_CONNECTED ) )\r
-                       {\r
-                               ulPHYLinkStatus = ulStatus;\r
-                               FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d (polled PHY)\n", ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 ) );\r
-                       }\r
-\r
-                       vTaskSetTimeOutState( &xPhyTime );\r
-                       if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 )\r
-                       {\r
-                               xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );\r
-                       }\r
-                       else\r
-                       {\r
-                               xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );\r
-                       }\r
-               }\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
+/*
+FreeRTOS+TCP V2.0.11
+Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ http://aws.amazon.com/freertos
+ http://www.FreeRTOS.org
+*/
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_IP_Private.h"
+#include "NetworkBufferManagement.h"
+#include "NetworkInterface.h"
+
+/* LPCOpen includes. */
+#include "chip.h"
+#include "lpc_phy.h"
+
+/* The size of the stack allocated to the task that handles Rx packets. */
+#define nwRX_TASK_STACK_SIZE   140
+
+#ifndef        PHY_LS_HIGH_CHECK_TIME_MS
+       /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
+       receiving packets. */
+       #define PHY_LS_HIGH_CHECK_TIME_MS       15000
+#endif
+
+#ifndef        PHY_LS_LOW_CHECK_TIME_MS
+       /* Check if the LinkSStatus in the PHY is still low every second. */
+       #define PHY_LS_LOW_CHECK_TIME_MS        1000
+#endif
+
+#ifndef configUSE_RMII
+       #define configUSE_RMII 1
+#endif
+
+#ifndef configNUM_RX_DESCRIPTORS
+       #error please define configNUM_RX_DESCRIPTORS in your FreeRTOSIPConfig.h
+#endif
+
+#ifndef configNUM_TX_DESCRIPTORS
+       #error please define configNUM_TX_DESCRIPTORS in your FreeRTOSIPConfig.h
+#endif
+
+#ifndef NETWORK_IRQHandler
+       #error NETWORK_IRQHandler must be defined to the name of the function that is installed in the interrupt vector table to handle Ethernet interrupts.
+#endif
+
+#if !defined( MAC_FF_HMC )
+       /* Hash for multicast. */
+       #define MAC_FF_HMC     ( 1UL << 2UL )
+#endif
+
+#ifndef iptraceEMAC_TASK_STARTING
+       #define iptraceEMAC_TASK_STARTING()     do { } while( 0 )
+#endif
+
+/* Define the bits of .STATUS that indicate a reception error. */
+#define nwRX_STATUS_ERROR_BITS \
+       ( RDES_CE  /* CRC Error */                        | \
+         RDES_RE  /* Receive Error */                    | \
+         RDES_DE  /* Descriptor Error */                 | \
+         RDES_RWT /* Receive Watchdog Timeout */         | \
+         RDES_LC  /* Late Collision */                   | \
+         RDES_OE  /* Overflow Error */                   | \
+         RDES_SAF /* Source Address Filter Fail */       | \
+         RDES_AFM /* Destination Address Filter Fail */  | \
+         RDES_LE  /* Length Error */                     )
+
+/* Define the EMAC status bits that should trigger an interrupt. */
+#define nwDMA_INTERRUPT_MASK \
+       ( DMA_IE_TIE  /* Transmit interrupt enable */         | \
+         DMA_IE_TSE  /* Transmit stopped enable */           | \
+         DMA_IE_OVE  /* Overflow interrupt enable */         | \
+         DMA_IE_RIE  /* Receive interrupt enable */          | \
+         DMA_IE_NIE  /* Normal interrupt summary enable */   | \
+         DMA_IE_AIE  /* Abnormal interrupt summary enable */ | \
+         DMA_IE_RUE  /* Receive buffer unavailable enable */ | \
+         DMA_IE_UNE  /* Underflow interrupt enable. */       | \
+         DMA_IE_TJE  /* Transmit jabber timeout enable */    | \
+         DMA_IE_RSE  /* Received stopped enable */           | \
+         DMA_IE_RWE  /* Receive watchdog timeout enable */   | \
+         DMA_IE_FBE )/* Fatal bus error enable */
+
+/* Interrupt events to process.  Currently only the RX/TX events are processed
+although code for other events is included to allow for possible future
+expansion. */
+#define EMAC_IF_RX_EVENT        1UL
+#define EMAC_IF_TX_EVENT        2UL
+#define EMAC_IF_ERR_EVENT       4UL
+#define EMAC_IF_ALL_EVENT       ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
+
+ /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
+ driver will filter incoming packets and only pass the stack those packets it
+ considers need processing. */
+ #if( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )
+       #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
+ #else
+       #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
+ #endif
+
+#if( ipconfigZERO_COPY_RX_DRIVER == 0 ) || ( ipconfigZERO_COPY_TX_DRIVER == 0 )
+       #warning It is adviced to enable both macros
+#endif
+
+#ifndef configPLACE_IN_SECTION_RAM
+       #define configPLACE_IN_SECTION_RAM
+/*
+       #define configPLACE_IN_SECTION_RAM      __attribute__ ((section(".ramfunc")))
+*/
+#endif
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Delay function passed into the library.  The implementation uses FreeRTOS
+ * calls so the scheduler must be started before the driver can be used.
+ */
+static void prvDelay( uint32_t ulMilliSeconds );
+
+/*
+ * Initialises the Tx and Rx descriptors respectively.
+ */
+static void prvSetupTxDescriptors( void );
+static void prvSetupRxDescriptors( void );
+
+/*
+ * A task that processes received frames.
+ */
+static void prvEMACHandlerTask( void *pvParameters );
+
+/*
+ * Sets up the MAC with the results of an auto-negotiation.
+ */
+static BaseType_t prvSetLinkSpeed( void );
+
+/*
+ * Generates a CRC for a MAC address that is then used to generate a hash index.
+ */
+static uint32_t prvGenerateCRC32( const uint8_t *ucAddress );
+
+/*
+ * Generates a hash index when setting a filter to permit a MAC address.
+ */
+static uint32_t prvGetHashIndex( const uint8_t *ucAddress );
+
+/*
+ * Update the hash table to allow a MAC address.
+ */
+static void prvAddMACAddress( const uint8_t* ucMacAddress );
+
+/*
+ * Sometimes the DMA will report received data as being longer than the actual
+ * received from length.  This function checks the reported length and corrects
+ * if if necessary.
+ */
+static void prvRemoveTrailingBytes( NetworkBufferDescriptor_t *pxDescriptor );
+
+/*-----------------------------------------------------------*/
+
+/* Bit map of outstanding ETH interrupt events for processing.  Currently only
+the Rx and Tx interrupt is handled, although code is included for other events
+to enable future expansion. */
+static volatile uint32_t ulISREvents;
+
+/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
+static uint32_t ulPHYLinkStatus = 0;
+
+/* Tx descriptors and index. */
+static ENET_ENHTXDESC_T xDMATxDescriptors[ configNUM_TX_DESCRIPTORS ];
+
+/* ulNextFreeTxDescriptor is declared volatile, because it is accessed from
+to different tasks. */
+static volatile uint32_t ulNextFreeTxDescriptor;
+static uint32_t ulTxDescriptorToClear;
+
+/* Rx descriptors and index. */
+static ENET_ENHRXDESC_T xDMARxDescriptors[ configNUM_RX_DESCRIPTORS ];
+static uint32_t ulNextRxDescriptorToProcess;
+
+/* Must be defined externally - the demo applications define this in main.c. */
+extern uint8_t ucMACAddress[ 6 ];
+
+/* The handle of the task that processes Rx packets.  The handle is required so
+the task can be notified when new packets arrive. */
+static TaskHandle_t xRxHanderTask = NULL;
+
+#if( ipconfigUSE_LLMNR == 1 )
+       static const uint8_t xLLMNR_MACAddress[] = { '\x01', '\x00', '\x5E', '\x00', '\x00', '\xFC' };
+#endif /* ipconfigUSE_LLMNR == 1 */
+
+/* xTXDescriptorSemaphore is a counting semaphore with
+a maximum count of ETH_TXBUFNB, which is the number of
+DMA TX descriptors. */
+static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
+
+/*-----------------------------------------------------------*/
+
+
+BaseType_t xNetworkInterfaceInitialise( void )
+{
+BaseType_t xReturn = pdPASS;
+
+       /* The interrupt will be turned on when a link is established. */
+       NVIC_DisableIRQ( ETHERNET_IRQn );
+
+       /* Disable receive and transmit DMA processes. */
+       LPC_ETHERNET->DMA_OP_MODE &= ~( DMA_OM_ST | DMA_OM_SR );
+
+       /* Disable packet reception. */
+       LPC_ETHERNET->MAC_CONFIG &= ~( MAC_CFG_RE | MAC_CFG_TE );
+
+       /* Call the LPCOpen function to initialise the hardware. */
+       Chip_ENET_Init( LPC_ETHERNET );
+
+       /* Save MAC address. */
+       Chip_ENET_SetADDR( LPC_ETHERNET, ucMACAddress );
+
+       /* Clear all MAC address hash entries. */
+       LPC_ETHERNET->MAC_HASHTABLE_HIGH = 0;
+       LPC_ETHERNET->MAC_HASHTABLE_LOW = 0;
+
+       #if( ipconfigUSE_LLMNR == 1 )
+       {
+               prvAddMACAddress( xLLMNR_MACAddress );
+       }
+       #endif /* ipconfigUSE_LLMNR == 1 */
+
+       /* Promiscuous flag (PR) and Receive All flag (RA) set to zero.  The
+       registers MAC_HASHTABLE_[LOW|HIGH] will be loaded to allow certain
+       multi-cast addresses. */
+       LPC_ETHERNET->MAC_FRAME_FILTER = MAC_FF_HMC;
+
+       #if( configUSE_RMII == 1 )
+       {
+               if( lpc_phy_init( pdTRUE, prvDelay ) != SUCCESS )
+               {
+                       xReturn = pdFAIL;
+               }
+       }
+       #else
+       {
+               #warning This path has not been tested.
+               if( lpc_phy_init( pdFALSE, prvDelay ) != SUCCESS )
+               {
+                       xReturn = pdFAIL;
+               }
+       }
+       #endif
+
+       if( xReturn == pdPASS )
+       {
+               /* Guard against the task being created more than once and the
+               descriptors being initialised more than once. */
+               if( xRxHanderTask == NULL )
+               {
+                       xReturn = xTaskCreate( prvEMACHandlerTask, "EMAC", nwRX_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xRxHanderTask );
+                       configASSERT( xReturn );
+               }
+
+               if( xTXDescriptorSemaphore == NULL )
+               {
+                       /* Create a counting semaphore, with a value of 'configNUM_TX_DESCRIPTORS'
+                       and a maximum of 'configNUM_TX_DESCRIPTORS'. */
+                       xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) configNUM_TX_DESCRIPTORS, ( UBaseType_t ) configNUM_TX_DESCRIPTORS );
+                       configASSERT( xTXDescriptorSemaphore );
+               }
+
+               /* Enable MAC interrupts. */
+               LPC_ETHERNET->DMA_INT_EN = nwDMA_INTERRUPT_MASK;
+       }
+
+       if( xReturn != pdFAIL )
+       {
+               /* Auto-negotiate was already started.  Wait for it to complete. */
+               xReturn = prvSetLinkSpeed();
+
+               if( xReturn == pdPASS )
+               {
+                       /* Initialise the descriptors. */
+                       prvSetupTxDescriptors();
+                       prvSetupRxDescriptors();
+
+                       /* Clear all interrupts. */
+                       LPC_ETHERNET->DMA_STAT = DMA_ST_ALL;
+
+                       /* Enable receive and transmit DMA processes. */
+                       LPC_ETHERNET->DMA_OP_MODE |= DMA_OM_ST | DMA_OM_SR;
+
+                       /* Set Receiver / Transmitter Enable. */
+                       LPC_ETHERNET->MAC_CONFIG |= MAC_CFG_RE | MAC_CFG_TE;
+
+                       /* Start receive polling. */
+                       LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1;
+
+                       /* Enable interrupts in the NVIC. */
+                       NVIC_SetPriority( ETHERNET_IRQn, configMAC_INTERRUPT_PRIORITY );
+                       NVIC_EnableIRQ( ETHERNET_IRQn );
+               }
+       }
+
+       return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+#define niBUFFER_1_PACKET_SIZE         1536
+
+static __attribute__ ((section("._ramAHB32"))) uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) );
+
+void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
+{
+
+uint8_t *ucRAMBuffer = ucNetworkPackets;
+uint32_t ul;
+
+       for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
+       {
+               pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
+               *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
+               ucRAMBuffer += niBUFFER_1_PACKET_SIZE;
+       }
+}
+/*-----------------------------------------------------------*/
+
+configPLACE_IN_SECTION_RAM
+static void vClearTXBuffers()
+{
+uint32_t ulLastDescriptor = ulNextFreeTxDescriptor;
+size_t uxCount = ( ( size_t ) configNUM_TX_DESCRIPTORS ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+       NetworkBufferDescriptor_t *pxNetworkBuffer;
+       uint8_t *ucPayLoad;
+#endif
+
+       /* This function is called after a TX-completion interrupt.
+       It will release each Network Buffer used in xNetworkInterfaceOutput().
+       'uxCount' represents the number of descriptors given to DMA for transmission.
+       After sending a packet, the DMA will clear the 'TDES_OWN' bit. */
+       while( ( uxCount > ( size_t ) 0u ) && ( ( xDMATxDescriptors[ ulTxDescriptorToClear ].CTRLSTAT & TDES_OWN ) == 0 ) )
+       {
+               if( ( ulTxDescriptorToClear == ulLastDescriptor ) && ( uxCount != ( size_t ) configNUM_TX_DESCRIPTORS ) )
+               {
+                       break;
+               }
+
+
+               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+               {
+                       ucPayLoad = ( uint8_t * )xDMATxDescriptors[ ulTxDescriptorToClear ].B1ADD;
+                       if( ucPayLoad != NULL )
+                       {
+                               /* B1ADD points to a pucEthernetBuffer of a Network Buffer descriptor. */
+                               pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );
+
+                               configASSERT( pxNetworkBuffer != NULL );
+
+                               vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ;
+                               xDMATxDescriptors[ ulTxDescriptorToClear ].B1ADD = ( uint32_t )0u;
+                       }
+               }
+               #endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+               /* Move onto the next descriptor, wrapping if necessary. */
+               ulTxDescriptorToClear++;
+               if( ulTxDescriptorToClear >= configNUM_TX_DESCRIPTORS )
+               {
+                       ulTxDescriptorToClear = 0;
+               }
+
+               uxCount--;
+               /* Tell the counting semaphore that one more TX descriptor is available. */
+               xSemaphoreGive( xTXDescriptorSemaphore );
+       }
+}
+
+/*-----------------------------------------------------------*/
+
+configPLACE_IN_SECTION_RAM
+BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
+{
+BaseType_t xReturn = pdFAIL;
+const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50 );
+
+       /* Attempt to obtain access to a Tx descriptor. */
+       do
+       {
+               if( xTXDescriptorSemaphore == NULL )
+               {
+                       break;
+               }
+               if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
+               {
+                       /* Time-out waiting for a free TX descriptor. */
+                       break;
+               }
+
+               /* If the descriptor is still owned by the DMA it can't be used. */
+               if( ( xDMATxDescriptors[ ulNextFreeTxDescriptor ].CTRLSTAT & TDES_OWN ) != 0 )
+               {
+                       /* The semaphore was taken, the TX DMA-descriptor is still not available.
+                       Actually that should not occur, the 'TDES_OWN' was already confirmed low in vClearTXBuffers(). */
+                       xSemaphoreGive( xTXDescriptorSemaphore );
+               }
+               else
+               {
+                       #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+                       {
+                               /* bReleaseAfterSend should always be set when using the zero
+                               copy driver. */
+                               configASSERT( bReleaseAfterSend != pdFALSE );
+
+                               /* The DMA's descriptor to point directly to the data in the
+                               network buffer descriptor.  The data is not copied. */
+                               xDMATxDescriptors[ ulNextFreeTxDescriptor ].B1ADD = ( uint32_t ) pxDescriptor->pucEthernetBuffer;
+
+                               /* The DMA descriptor will 'own' this Network Buffer,
+                               until it has been sent.  So don't release it now. */
+                               bReleaseAfterSend = false;
+                       }
+                       #else
+                       {
+                               /* The data is copied from the network buffer descriptor into
+                               the DMA's descriptor. */
+                               memcpy( ( void * ) xDMATxDescriptors[ ulNextFreeTxDescriptor ].B1ADD, ( void * ) pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength );
+                       }
+                       #endif
+
+                       xDMATxDescriptors[ ulNextFreeTxDescriptor ].BSIZE = ( uint32_t ) TDES_ENH_BS1( pxDescriptor->xDataLength );
+
+                       /* This descriptor is given back to the DMA. */
+                       xDMATxDescriptors[ ulNextFreeTxDescriptor ].CTRLSTAT |= TDES_OWN;
+
+                       /* Ensure the DMA is polling Tx descriptors. */
+                       LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1;
+
+            iptraceNETWORK_INTERFACE_TRANSMIT();
+
+                       /* Move onto the next descriptor, wrapping if necessary. */
+                       ulNextFreeTxDescriptor++;
+                       if( ulNextFreeTxDescriptor >= configNUM_TX_DESCRIPTORS )
+                       {
+                               ulNextFreeTxDescriptor = 0;
+                       }
+
+                       /* The Tx has been initiated. */
+                       xReturn = pdPASS;
+               }
+       } while( 0 );
+
+       /* The buffer has been sent so can be released. */
+       if( bReleaseAfterSend != pdFALSE )
+       {
+               vReleaseNetworkBufferAndDescriptor( pxDescriptor );
+       }
+
+       return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static void prvDelay( uint32_t ulMilliSeconds )
+{
+       /* Ensure the scheduler was started before attempting to use the scheduler to
+       create a delay. */
+       configASSERT( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING );
+
+       vTaskDelay( pdMS_TO_TICKS( ulMilliSeconds ) );
+}
+/*-----------------------------------------------------------*/
+
+static void prvSetupTxDescriptors( void )
+{
+BaseType_t x;
+
+       /* Start with Tx descriptors clear. */
+       memset( ( void * ) xDMATxDescriptors, 0, sizeof( xDMATxDescriptors ) );
+
+       /* Index to the next Tx descriptor to use. */
+       ulNextFreeTxDescriptor = 0ul;
+
+       /* Index to the next Tx descriptor to clear ( after transmission ). */
+       ulTxDescriptorToClear = 0ul;
+
+       for( x = 0; x < configNUM_TX_DESCRIPTORS; x++ )
+       {
+               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+               {
+                       /* Nothing to do, B1ADD will be set when data is ready to transmit.
+                       Currently the memset above will have set it to NULL. */
+               }
+               #else
+               {
+                       /* Allocate a buffer to the Tx descriptor.  This is the most basic
+                       way of creating a driver as the data is then copied into the
+                       buffer. */
+                       xDMATxDescriptors[ x ].B1ADD = ( uint32_t ) pvPortMalloc( ipTOTAL_ETHERNET_FRAME_SIZE );
+
+                       /* Use an assert to check the allocation as +TCP applications will
+                       often not use a malloc() failed hook as the TCP stack will recover
+                       from allocation failures. */
+                       configASSERT( xDMATxDescriptors[ x ].B1ADD );
+               }
+               #endif
+
+               /* Buffers hold an entire frame so all buffers are both the start and
+               end of a frame. */
+               /* TDES_ENH_TCH     Second Address Chained. */
+               /* TDES_ENH_CIC(n)  Checksum Insertion Control, tried but it does not work for the LPC18xx... */
+               /* TDES_ENH_FS      First Segment. */
+               /* TDES_ENH_LS      Last Segment. */
+               /* TDES_ENH_IC      Interrupt on Completion. */
+               xDMATxDescriptors[ x ].CTRLSTAT = TDES_ENH_TCH | TDES_ENH_CIC( 3 ) | TDES_ENH_FS | TDES_ENH_LS | TDES_ENH_IC;
+               xDMATxDescriptors[ x ].B2ADD = ( uint32_t ) &xDMATxDescriptors[ x + 1 ];
+       }
+
+       xDMATxDescriptors[ configNUM_TX_DESCRIPTORS - 1 ].CTRLSTAT |= TDES_ENH_TER;
+       xDMATxDescriptors[ configNUM_TX_DESCRIPTORS - 1 ].B2ADD = ( uint32_t ) &xDMATxDescriptors[ 0 ];
+
+       /* Point the DMA to the base of the descriptor list. */
+       LPC_ETHERNET->DMA_TRANS_DES_ADDR = ( uint32_t ) xDMATxDescriptors;
+}
+/*-----------------------------------------------------------*/
+
+static void prvSetupRxDescriptors( void )
+{
+BaseType_t x;
+#if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+       NetworkBufferDescriptor_t *pxNetworkBuffer;
+#endif
+
+       /* Index to the next Rx descriptor to use. */
+       ulNextRxDescriptorToProcess = 0;
+
+       /* Clear RX descriptor list. */
+       memset( ( void * )  xDMARxDescriptors, 0, sizeof( xDMARxDescriptors ) );
+
+       for( x = 0; x < configNUM_RX_DESCRIPTORS; x++ )
+       {
+               /* Allocate a buffer of the largest     possible frame size as it is not
+               known what size received frames will be. */
+
+               #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+               {
+                       pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, 0 );
+
+                       /* During start-up there should be enough Network Buffers available,
+                       so it is safe to use configASSERT().
+                       In case this assert fails, please check: configNUM_RX_DESCRIPTORS,
+                       ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, and in case BufferAllocation_2.c
+                       is included, check the amount of available heap. */
+                       configASSERT( pxNetworkBuffer != NULL );
+
+                       /* Pass the actual buffer to DMA. */
+                       xDMARxDescriptors[ x ].B1ADD = ( uint32_t ) pxNetworkBuffer->pucEthernetBuffer;
+               }
+               #else
+               {
+                       /* All DMA descriptors are populated with permanent memory blocks.
+                       Their contents will be copy to Network Buffers. */
+                       xDMARxDescriptors[ x ].B1ADD = ( uint32_t ) pvPortMalloc( ipTOTAL_ETHERNET_FRAME_SIZE );
+               }
+               #endif /* ipconfigZERO_COPY_RX_DRIVER */
+
+               /* Use an assert to check the allocation as +TCP applications will often
+               not use a malloc failed hook as the TCP stack will recover from
+               allocation failures. */
+               configASSERT( xDMARxDescriptors[ x ].B1ADD );
+
+               xDMARxDescriptors[ x ].B2ADD = ( uint32_t ) &( xDMARxDescriptors[ x + 1 ] );
+               xDMARxDescriptors[ x ].CTRL = ( uint32_t ) RDES_ENH_BS1( ipTOTAL_ETHERNET_FRAME_SIZE ) | RDES_ENH_RCH;
+
+               /* The descriptor is available for use by the DMA. */
+               xDMARxDescriptors[ x ].STATUS = RDES_OWN;
+       }
+
+       /* RDES_ENH_RER  Receive End of Ring. */
+       xDMARxDescriptors[ ( configNUM_RX_DESCRIPTORS - 1 ) ].CTRL |= RDES_ENH_RER;
+       xDMARxDescriptors[ configNUM_RX_DESCRIPTORS - 1 ].B2ADD = ( uint32_t ) &( xDMARxDescriptors[ 0 ] );
+
+       /* Point the DMA to the base of the descriptor list. */
+       LPC_ETHERNET->DMA_REC_DES_ADDR = ( uint32_t ) xDMARxDescriptors;
+}
+/*-----------------------------------------------------------*/
+configPLACE_IN_SECTION_RAM
+static void prvRemoveTrailingBytes( NetworkBufferDescriptor_t *pxDescriptor )
+{
+size_t xExpectedLength;
+IPPacket_t *pxIPPacket;
+
+       pxIPPacket = ( IPPacket_t * ) pxDescriptor->pucEthernetBuffer;
+       /* Look at the actual length of the packet, translate it to a host-endial notation. */
+       xExpectedLength = sizeof( EthernetHeader_t ) + ( size_t ) FreeRTOS_htons( pxIPPacket->xIPHeader.usLength );
+
+       if( xExpectedLength == ( pxDescriptor->xDataLength + 4 ) )
+       {
+               pxDescriptor->xDataLength -= 4;
+       }
+       else
+       {
+               if( pxDescriptor->xDataLength > xExpectedLength )
+               {
+                       pxDescriptor->xDataLength = ( size_t ) xExpectedLength;
+               }
+       }
+}
+/*-----------------------------------------------------------*/
+configPLACE_IN_SECTION_RAM
+BaseType_t xGetPhyLinkStatus( void )
+{
+BaseType_t xReturn;
+
+       if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) == 0 )
+       {
+               xReturn = pdFALSE;
+       }
+       else
+       {
+               xReturn = pdTRUE;
+       }
+
+       return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+uint32_t ulDataAvailable;
+
+configPLACE_IN_SECTION_RAM
+static BaseType_t prvNetworkInterfaceInput()
+{
+BaseType_t xResult = pdFALSE;
+uint32_t ulStatus;
+eFrameProcessingResult_t eResult;
+const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 );
+const UBaseType_t uxMinimumBuffersRemaining = 3UL;
+uint16_t usLength;
+NetworkBufferDescriptor_t *pxDescriptor;
+#if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+       NetworkBufferDescriptor_t *pxNewDescriptor;
+#endif /* ipconfigZERO_COPY_RX_DRIVER */
+#if( ipconfigUSE_LINKED_RX_MESSAGES == 0 )
+       IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
+#endif
+
+       /* Process each descriptor that is not still in use by the DMA. */
+       ulStatus = xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS;
+       if( ( ulStatus & RDES_OWN ) == 0 )
+       {
+               /* Check packet for errors */
+               if( ( ulStatus & nwRX_STATUS_ERROR_BITS ) != 0 )
+               {
+                       /* There is some reception error. */
+                       intCount[ 3 ]++;
+                       /* Clear error bits. */
+                       ulStatus &= ~( ( uint32_t )nwRX_STATUS_ERROR_BITS );
+               }
+               else
+               {
+                       xResult++;
+
+                       eResult = ipCONSIDER_FRAME_FOR_PROCESSING( ( const uint8_t * const ) ( xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD ) );
+                       if( eResult == eProcessBuffer )
+                       {
+                               if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) == 0 )
+                               {
+                                       ulPHYLinkStatus |= PHY_LINK_CONNECTED;
+                                       FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d (message received)\n", ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 ) );
+                               }
+
+                       #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+                               if( uxGetNumberOfFreeNetworkBuffers() > uxMinimumBuffersRemaining )
+                               {
+                                       pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xDescriptorWaitTime );
+                               }
+                               else
+                               {
+                                       /* Too risky to allocate a new Network Buffer. */
+                                       pxNewDescriptor = NULL;
+                               }
+                               if( pxNewDescriptor != NULL )
+                       #else
+                               if( uxGetNumberOfFreeNetworkBuffers() > uxMinimumBuffersRemaining )
+                       #endif /* ipconfigZERO_COPY_RX_DRIVER */
+                               {
+                       #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+                               const uint8_t *pucBuffer;
+                       #endif
+
+                                       /* Get the actual length. */
+                                       usLength = RDES_FLMSK( ulStatus );
+
+                                       #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+                                       {
+                                               /* Replace the character buffer 'B1ADD'. */
+                                               pucBuffer = ( const uint8_t * const ) ( xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD );
+                                               xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD = ( uint32_t ) pxNewDescriptor->pucEthernetBuffer;
+
+                                               /* 'B1ADD' contained the address of a 'pucEthernetBuffer' that
+                                               belongs to a Network Buffer.  Find the original Network Buffer. */
+                                               pxDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
+                                               /* This zero-copy driver makes sure that every 'xDMARxDescriptors' contains
+                                               a reference to a Network Buffer at any time.
+                                               In case it runs out of Network Buffers, a DMA buffer won't be replaced,
+                                               and the received messages is dropped. */
+                                               configASSERT( pxDescriptor != NULL );
+                                       }
+                                       #else
+                                       {
+                                               /* Create a buffer of exactly the required length. */
+                                               pxDescriptor = pxGetNetworkBufferWithDescriptor( usLength, xDescriptorWaitTime );
+                                       }
+                                       #endif /* ipconfigZERO_COPY_RX_DRIVER */
+
+                                       if( pxDescriptor != NULL )
+                                       {
+                                               pxDescriptor->xDataLength = ( size_t ) usLength;
+                                               #if( ipconfigZERO_COPY_RX_DRIVER == 0 )
+                                               {
+                                                       /* Copy the data into the allocated buffer. */
+                                                       memcpy( ( void * ) pxDescriptor->pucEthernetBuffer, ( void * ) xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD, usLength );
+                                               }
+                                               #endif /* ipconfigZERO_COPY_RX_DRIVER */
+                                               /* It is possible that more data was copied than
+                                               actually makes up the frame.  If this is the case
+                                               adjust the length to remove any trailing bytes. */
+                                               prvRemoveTrailingBytes( pxDescriptor );
+
+                                               /* Pass the data to the TCP/IP task for processing. */
+                                               xRxEvent.pvData = ( void * ) pxDescriptor;
+                                               if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE )
+                                               {
+                                                       /* Could not send the descriptor into the TCP/IP
+                                                       stack, it must be released. */
+                                                       vReleaseNetworkBufferAndDescriptor( pxDescriptor );
+                                               }
+                                               else
+                                               {
+                                                       iptraceNETWORK_INTERFACE_RECEIVE();
+
+                                                       /* The data that was available at the top of this
+                                                       loop has been sent, so is no longer available. */
+                                                       ulDataAvailable = pdFALSE;
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               /* The packet is discarded as uninteresting. */
+                               ulDataAvailable = pdFALSE;
+                       }
+                       /* Got here because received data was sent to the IP task or the
+                       data contained an error and was discarded.  Give the descriptor
+                       back to the DMA. */
+                       xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS = ulStatus | RDES_OWN;
+
+                       /* Move onto the next descriptor. */
+                       ulNextRxDescriptorToProcess++;
+                       if( ulNextRxDescriptorToProcess >= configNUM_RX_DESCRIPTORS )
+                       {
+                               ulNextRxDescriptorToProcess = 0;
+                       }
+
+                       ulStatus = xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS;
+               } /* if( ( ulStatus & nwRX_STATUS_ERROR_BITS ) != 0 ) */
+       } /* if( ( ulStatus & RDES_OWN ) == 0 ) */
+
+       /* Restart receive polling. */
+       LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1;
+
+       return xResult;
+}
+/*-----------------------------------------------------------*/
+
+configPLACE_IN_SECTION_RAM
+void NETWORK_IRQHandler( void )
+{
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+uint32_t ulDMAStatus;
+const uint32_t ulRxInterruptMask =
+       DMA_ST_RI |             /* Receive interrupt */
+       DMA_ST_RU;              /* Receive buffer unavailable */
+const uint32_t ulTxInterruptMask =
+       DMA_ST_TI |             /* Transmit interrupt */
+       DMA_ST_TPS;             /* Transmit process stopped */
+
+       configASSERT( xRxHanderTask );
+
+       /* Get pending interrupts. */
+       ulDMAStatus = LPC_ETHERNET->DMA_STAT;
+
+       /* RX group interrupt(s). */
+       if( ( ulDMAStatus & ulRxInterruptMask ) != 0x00 )
+       {
+               /* Remember that an RX event has happened. */
+               ulISREvents |= EMAC_IF_RX_EVENT;
+               vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken );
+               intCount[ 0 ]++;
+       }
+
+       /* TX group interrupt(s). */
+       if( ( ulDMAStatus & ulTxInterruptMask ) != 0x00 )
+       {
+               /* Remember that a TX event has happened. */
+               ulISREvents |= EMAC_IF_TX_EVENT;
+               vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken );
+               intCount[ 1 ]++;
+       }
+
+       /* Test for 'Abnormal interrupt summary'. */
+       if( ( ulDMAStatus & DMA_ST_AIE ) != 0x00 )
+       {
+               /* The trace macro must be written such that it can be called from
+               an interrupt. */
+               iptraceETHERNET_RX_EVENT_LOST();
+       }
+
+       /* Clear pending interrupts */
+       LPC_ETHERNET->DMA_STAT = ulDMAStatus;
+
+       /* Context switch needed? */
+       portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvSetLinkSpeed( void )
+{
+BaseType_t xReturn = pdFAIL;
+TickType_t xTimeOnEntering;
+uint32_t ulPhyStatus;
+const TickType_t xAutoNegotiateDelay = pdMS_TO_TICKS( 5000UL );
+
+       /* Ensure polling does not starve lower priority tasks by temporarily
+       setting the priority of this task to that of the idle task. */
+       vTaskPrioritySet( NULL, tskIDLE_PRIORITY );
+
+       xTimeOnEntering = xTaskGetTickCount();
+       do
+       {
+               ulPhyStatus = lpcPHYStsPoll();
+               if( ( ulPhyStatus & PHY_LINK_CONNECTED ) != 0x00 )
+               {
+                       /* Set interface speed and duplex. */
+                       if( ( ulPhyStatus & PHY_LINK_SPEED100 ) != 0x00 )
+                       {
+                               Chip_ENET_SetSpeed( LPC_ETHERNET, 1 );
+                       }
+                       else
+                       {
+                               Chip_ENET_SetSpeed( LPC_ETHERNET, 0 );
+                       }
+
+                       if( ( ulPhyStatus & PHY_LINK_FULLDUPLX ) != 0x00 )
+                       {
+                               Chip_ENET_SetDuplex( LPC_ETHERNET, true );
+                       }
+                       else
+                       {
+                               Chip_ENET_SetDuplex( LPC_ETHERNET, false );
+                       }
+
+                       xReturn = pdPASS;
+                       break;
+               }
+       } while( ( xTaskGetTickCount() - xTimeOnEntering ) < xAutoNegotiateDelay );
+
+       /* Reset the priority of this task back to its original value. */
+       vTaskPrioritySet( NULL, ipconfigIP_TASK_PRIORITY );
+
+       return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static uint32_t prvGenerateCRC32( const uint8_t *ucAddress )
+{
+unsigned int j;
+const uint32_t Polynomial = 0xEDB88320;
+uint32_t crc = ~0ul;
+const uint8_t *pucCurrent = ( const uint8_t * ) ucAddress;
+const uint8_t *pucLast = pucCurrent + 6;
+
+    /* Calculate  normal CRC32 */
+    while( pucCurrent < pucLast )
+    {
+        crc ^= *( pucCurrent++ );
+        for( j = 0; j < 8; j++ )
+        {
+            if( ( crc & 1 ) != 0 )
+            {
+                crc = (crc >> 1) ^ Polynomial;
+            }
+            else
+            {
+                crc >>= 1;
+            }
+        }
+    }
+    return ~crc;
+}
+/*-----------------------------------------------------------*/
+
+static uint32_t prvGetHashIndex( const uint8_t *ucAddress )
+{
+uint32_t ulCrc = prvGenerateCRC32( ucAddress );
+uint32_t ulIndex = 0ul;
+BaseType_t xCount = 6;
+
+    /* Take the lowest 6 bits of the CRC32 and reverse them */
+    while( xCount-- )
+    {
+        ulIndex <<= 1;
+        ulIndex |= ( ulCrc & 1 );
+        ulCrc >>= 1;
+    }
+
+    /* This is the has value of 'ucAddress' */
+    return ulIndex;
+}
+/*-----------------------------------------------------------*/
+
+static void prvAddMACAddress( const uint8_t* ucMacAddress )
+{
+BaseType_t xIndex;
+
+    xIndex = prvGetHashIndex( ucMacAddress );
+    if( xIndex >= 32 )
+    {
+        LPC_ETHERNET->MAC_HASHTABLE_HIGH |= ( 1u << ( xIndex - 32 ) );
+    }
+    else
+    {
+        LPC_ETHERNET->MAC_HASHTABLE_LOW |= ( 1u << xIndex );
+    }
+}
+/*-----------------------------------------------------------*/
+
+configPLACE_IN_SECTION_RAM
+static void prvEMACHandlerTask( void *pvParameters )
+{
+TimeOut_t xPhyTime;
+TickType_t xPhyRemTime;
+UBaseType_t uxLastMinBufferCount = 0;
+UBaseType_t uxCurrentCount;
+BaseType_t xResult = 0;
+uint32_t ulStatus;
+const TickType_t xBlockTime = pdMS_TO_TICKS( 5000ul );
+
+       /* Remove compiler warning about unused parameter. */
+       ( void ) pvParameters;
+
+       /* A possibility to set some additional task properties. */
+       iptraceEMAC_TASK_STARTING();
+
+       vTaskSetTimeOutState( &xPhyTime );
+       xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+
+       for( ;; )
+       {
+               uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
+               if( uxLastMinBufferCount != uxCurrentCount )
+               {
+                       /* The logging produced below may be helpful
+                       while tuning +TCP: see how many buffers are in use. */
+                       uxLastMinBufferCount = uxCurrentCount;
+                       FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
+                               uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
+               }
+
+               #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+               {
+               static UBaseType_t uxLastMinQueueSpace = 0;
+
+                       uxCurrentCount = uxGetMinimumIPQueueSpace();
+                       if( uxLastMinQueueSpace != uxCurrentCount )
+                       {
+                               /* The logging produced below may be helpful
+                               while tuning +TCP: see how many buffers are in use. */
+                               uxLastMinQueueSpace = uxCurrentCount;
+                               FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
+                       }
+               }
+               #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
+
+               ulTaskNotifyTake( pdTRUE, xBlockTime );
+
+               xResult = ( BaseType_t ) 0;
+
+               if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
+               {
+                       /* Code to release TX buffers if zero-copy is used. */
+                       ulISREvents &= ~EMAC_IF_TX_EVENT;
+                       {
+                               /* Check if DMA packets have been delivered. */
+                               vClearTXBuffers();
+                       }
+               }
+
+               if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
+               {
+                       ulISREvents &= ~EMAC_IF_RX_EVENT;
+
+                       xResult = prvNetworkInterfaceInput();
+                       if( xResult > 0 )
+                       {
+                               while( prvNetworkInterfaceInput() > 0 )
+                               {
+                               }
+                       }
+               }
+
+               if( xResult > 0 )
+               {
+                       /* A packet was received. No need to check for the PHY status now,
+                       but set a timer to check it later on. */
+                       vTaskSetTimeOutState( &xPhyTime );
+                       xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+                       xResult = 0;
+               }
+               else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
+               {
+                       ulStatus = lpcPHYStsPoll();
+
+                       if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != ( ulStatus & PHY_LINK_CONNECTED ) )
+                       {
+                               ulPHYLinkStatus = ulStatus;
+                               FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d (polled PHY)\n", ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 ) );
+                       }
+
+                       vTaskSetTimeOutState( &xPhyTime );
+                       if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 )
+                       {
+                               xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+                       }
+                       else
+                       {
+                               xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+                       }
+               }
+       }
+}
+/*-----------------------------------------------------------*/