summaryrefslogtreecommitdiff
path: root/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c')
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c1274
1 files changed, 637 insertions, 637 deletions
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c
index 83c96a07c..3528269bd 100644
--- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c
@@ -1,637 +1,637 @@
-/*
-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"
-
-/* Some files from the Atmel Software Framework */
-/*_RB_ The SAM4E portable layer has three different header files called gmac.h! */
-#include "instance/gmac.h"
-#include <sysclk.h>
-#include <ethernet_phy.h>
-
-#ifndef BMSR_LINK_STATUS
- #define BMSR_LINK_STATUS 0x0004 //!< Link status
-#endif
-
-#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
-
-/* Interrupt events to process. Currently only the Rx event is 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 )
-
-#define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR
-
-#define HZ_PER_MHZ ( 1000000UL )
-
-#ifndef EMAC_MAX_BLOCK_TIME_MS
- #define EMAC_MAX_BLOCK_TIME_MS 100ul
-#endif
-
-#if !defined( GMAC_USES_TX_CALLBACK ) || ( GMAC_USES_TX_CALLBACK != 1 )
- #error Please define GMAC_USES_TX_CALLBACK as 1
-#endif
-
-/* Default the size of the stack used by the EMAC deferred handler task to 4x
-the size of the stack used by the idle task - but allow this to be overridden in
-FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
-#ifndef configEMAC_TASK_STACK_SIZE
- #define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
-#endif
-
-/*-----------------------------------------------------------*/
-
-/*
- * Wait a fixed time for the link status to indicate the network is up.
- */
-static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
-
-#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
- void vGMACGenerateChecksum( uint8_t *apBuffer );
-#endif
-
-/*
- * Called from the ASF GMAC driver.
- */
-static void prvRxCallback( uint32_t ulStatus );
-static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer );
-
-/*
- * A deferred interrupt handler task that processes GMAC interrupts.
- */
-static void prvEMACHandlerTask( void *pvParameters );
-
-/*
- * Initialise the ASF GMAC driver.
- */
-static BaseType_t prvGMACInit( void );
-
-/*
- * Try to obtain an Rx packet from the hardware.
- */
-static uint32_t prvEMACRxPoll( void );
-
-/*-----------------------------------------------------------*/
-
-/* Bit map of outstanding ETH interrupt events for processing. Currently only
-the Rx 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;
-static volatile BaseType_t xGMACSwitchRequired;
-
-/* ethernet_phy_addr: the address of the PHY in use.
-Atmel was a bit ambiguous about it so the address will be stored
-in this variable, see ethernet_phy.c */
-extern int ethernet_phy_addr;
-
-/* LLMNR multicast address. */
-static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
-
-/* The GMAC object as defined by the ASF drivers. */
-static gmac_device_t gs_gmac_dev;
-
-/* MAC address to use. */
-extern const uint8_t ucMACAddress[ 6 ];
-
-/* Holds the handle of the task used as a deferred interrupt processor. The
-handle is used so direct notifications can be sent to the task for all EMAC/DMA
-related interrupts. */
-TaskHandle_t xEMACTaskHandle = NULL;
-
-static QueueHandle_t xTxBufferQueue;
-int tx_release_count[ 4 ];
-
-/* xTXDescriptorSemaphore is a counting semaphore with
-a maximum count of GMAC_TX_BUFFERS, which is the number of
-DMA TX descriptors. */
-static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
-
-/*-----------------------------------------------------------*/
-
-/*
- * GMAC interrupt handler.
- */
-void GMAC_Handler(void)
-{
- xGMACSwitchRequired = pdFALSE;
-
- /* gmac_handler() may call prvRxCallback() which may change
- the value of xGMACSwitchRequired. */
- gmac_handler( &gs_gmac_dev );
-
- if( xGMACSwitchRequired != pdFALSE )
- {
- portEND_SWITCHING_ISR( xGMACSwitchRequired );
- }
-}
-/*-----------------------------------------------------------*/
-
-static void prvRxCallback( uint32_t ulStatus )
-{
- if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
- {
- /* let the prvEMACHandlerTask know that there was an RX event. */
- ulISREvents |= EMAC_IF_RX_EVENT;
- /* Only an RX interrupt can wakeup prvEMACHandlerTask. */
- vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
- }
-}
-/*-----------------------------------------------------------*/
-
-static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer )
-{
- if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
- {
- /* let the prvEMACHandlerTask know that there was an RX event. */
- ulISREvents |= EMAC_IF_TX_EVENT;
-
- vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
- xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
- tx_release_count[ 2 ]++;
- }
-}
-/*-----------------------------------------------------------*/
-
-BaseType_t xNetworkInterfaceInitialise( void )
-{
-const TickType_t x5_Seconds = 5000UL;
-
- if( xEMACTaskHandle == NULL )
- {
- prvGMACInit();
-
- /* Wait at most 5 seconds for a Link Status in the PHY. */
- xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
-
- /* The handler task is created at the highest possible priority to
- ensure the interrupt handler can return directly to it. */
- xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
- configASSERT( xEMACTaskHandle );
- }
-
- if( xTxBufferQueue == NULL )
- {
- xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
- configASSERT( xTxBufferQueue );
- }
-
- if( xTXDescriptorSemaphore == NULL )
- {
- xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
- configASSERT( xTXDescriptorSemaphore );
- }
- /* When returning non-zero, the stack will become active and
- start DHCP (in configured) */
- return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;
-}
-/*-----------------------------------------------------------*/
-
-BaseType_t xGetPhyLinkStatus( void )
-{
-BaseType_t xResult;
-
- /* This function returns true if the Link Status in the PHY is high. */
- if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
- {
- xResult = pdTRUE;
- }
- else
- {
- xResult = pdFALSE;
- }
-
- return xResult;
-}
-/*-----------------------------------------------------------*/
-
-BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
-{
-/* Do not wait too long for a free TX DMA buffer. */
-const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
-
- do {
- if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
- {
- /* Do not attempt to send packets as long as the Link Status is low. */
- break;
- }
- if( xTXDescriptorSemaphore == NULL )
- {
- /* Semaphore has not been created yet? */
- break;
- }
- if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
- {
- /* Time-out waiting for a free TX descriptor. */
- tx_release_count[ 3 ]++;
- break;
- }
- #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
- {
- /* Confirm that the pxDescriptor may be kept by the driver. */
- configASSERT( bReleaseAfterSend != pdFALSE );
- }
- #endif /* ipconfigZERO_COPY_TX_DRIVER */
-
- gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback );
-
- #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
- {
- /* Confirm that the pxDescriptor may be kept by the driver. */
- bReleaseAfterSend = pdFALSE;
- }
- #endif /* ipconfigZERO_COPY_TX_DRIVER */
- /* Not interested in a call-back after TX. */
- iptraceNETWORK_INTERFACE_TRANSMIT();
- } while( 0 );
-
- if( bReleaseAfterSend != pdFALSE )
- {
- vReleaseNetworkBufferAndDescriptor( pxDescriptor );
- }
- return pdTRUE;
-}
-/*-----------------------------------------------------------*/
-
-static BaseType_t prvGMACInit( void )
-{
-uint32_t ncfgr;
-
- gmac_options_t gmac_option;
-
- memset( &gmac_option, '\0', sizeof( gmac_option ) );
- gmac_option.uc_copy_all_frame = 0;
- gmac_option.uc_no_boardcast = 0;
- memcpy( gmac_option.uc_mac_addr, ucMACAddress, sizeof( gmac_option.uc_mac_addr ) );
-
- gs_gmac_dev.p_hw = GMAC;
- gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );
-
- NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );
- NVIC_EnableIRQ( GMAC_IRQn );
-
- /* Contact the Ethernet PHY and store it's address in 'ethernet_phy_addr' */
- ethernet_phy_init( GMAC, ETHERNET_CONF_PHY_ADDR, sysclk_get_cpu_hz() );
-
- ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr );
- ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 );
-
- /* The GMAC driver will call a hook prvRxCallback(), which
- in turn will wake-up the task by calling vTaskNotifyGiveFromISR() */
- gmac_dev_set_rx_callback( &gs_gmac_dev, prvRxCallback );
- gmac_set_address( GMAC, 1, (uint8_t*)llmnr_mac_address );
-
- ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD;
-
- GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr;
-
- return 1;
-}
-/*-----------------------------------------------------------*/
-
-static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress )
-{
-uint32_t ulValue, ulReturn;
-int rc;
-
- gmac_enable_management( GMAC, 1 );
- rc = gmac_phy_read( GMAC, ethernet_phy_addr, usAddress, &ulValue );
- gmac_enable_management( GMAC, 0 );
- if( rc == GMAC_OK )
- {
- ulReturn = ulValue;
- }
- else
- {
- ulReturn = 0UL;
- }
-
- return ulReturn;
-}
-/*-----------------------------------------------------------*/
-
-static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
-{
-TickType_t xStartTime = xTaskGetTickCount();
-TickType_t xEndTime;
-BaseType_t xReturn;
-const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );
-
- for( ;; )
- {
- xEndTime = xTaskGetTickCount();
-
- if( ( xEndTime - xStartTime ) > xMaxTime )
- {
- /* Wated more than xMaxTime, return. */
- xReturn = pdFALSE;
- break;
- }
-
- /* Check the link status again. */
- ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
-
- if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
- {
- /* Link is up - return. */
- xReturn = pdTRUE;
- break;
- }
-
- /* Link is down - wait in the Blocked state for a short while (to allow
- other tasks to execute) before checking again. */
- vTaskDelay( xShortTime );
- }
-
- FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n",
- xReturn,
- ethernet_phy_addr,
- sysclk_get_cpu_hz() / HZ_PER_MHZ ) );
-
- return xReturn;
-}
-/*-----------------------------------------------------------*/
-
-//#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
-
- void vGMACGenerateChecksum( uint8_t *apBuffer )
- {
- ProtocolPacket_t *xProtPacket = (ProtocolPacket_t *)apBuffer;
-
- if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
- {
- IPHeader_t *pxIPHeader = &(xProtPacket->xTCPPacket.xIPHeader);
-
- /* Calculate the IP header checksum. */
- pxIPHeader->usHeaderChecksum = 0x00;
- pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
- pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
-
- /* Calculate the TCP checksum for an outgoing packet. */
- usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE );
- }
- }
-
-//#endif
-/*-----------------------------------------------------------*/
-
-static uint32_t prvEMACRxPoll( void )
-{
-unsigned char *pucUseBuffer;
-uint32_t ulReceiveCount, ulResult, ulReturnValue = 0;
-static NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL;
-const UBaseType_t xMinDescriptorsToLeave = 2UL;
-const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL );
-static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
-
- for( ;; )
- {
- /* If pxNextNetworkBufferDescriptor was not left pointing at a valid
- descriptor then allocate one now. */
- if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) )
- {
- pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );
- }
-
- if( pxNextNetworkBufferDescriptor != NULL )
- {
- /* Point pucUseBuffer to the buffer pointed to by the descriptor. */
- pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
- }
- else
- {
- /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
- messages will be flushed and ignored. */
- pucUseBuffer = NULL;
- }
-
- /* Read the next packet from the hardware into pucUseBuffer. */
- ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount );
-
- if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )
- {
- /* No data from the hardware. */
- break;
- }
-
- if( pxNextNetworkBufferDescriptor == NULL )
- {
- /* Data was read from the hardware, but no descriptor was available
- for it, so it will be dropped. */
- iptraceETHERNET_RX_EVENT_LOST();
- continue;
- }
-
- iptraceNETWORK_INTERFACE_RECEIVE();
- pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;
- xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;
-
- /* Send the descriptor to the IP task for processing. */
- if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )
- {
- /* The buffer could not be sent to the stack so must be released
- again. */
- vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );
- iptraceETHERNET_RX_EVENT_LOST();
- FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
- }
-
- /* Now the buffer has either been passed to the IP-task,
- or it has been released in the code above. */
- pxNextNetworkBufferDescriptor = NULL;
- ulReturnValue++;
- }
-
- return ulReturnValue;
-}
-/*-----------------------------------------------------------*/
-
-static void prvEMACHandlerTask( void *pvParameters )
-{
-TimeOut_t xPhyTime;
-TickType_t xPhyRemTime;
-UBaseType_t uxLastMinBufferCount = 0, uxCount;
-UBaseType_t uxCurrentCount;
-#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
- UBaseType_t uxLastMinQueueSpace;
-#endif
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
- NetworkBufferDescriptor_t *pxBuffer;
-#endif
-uint8_t *pucBuffer;
-BaseType_t xResult = 0;
-uint32_t xStatus;
-const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
-
- /* Remove compiler warnings about unused parameters. */
- ( void ) pvParameters;
-
- configASSERT( xEMACTaskHandle );
-
- 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 )
- {
- 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 */
-
- if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
- {
- /* No events to process now, wait for the next. */
- ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
- }
-
- if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
- {
- ulISREvents &= ~EMAC_IF_RX_EVENT;
-
- /* Wait for the EMAC interrupt to indicate that another packet has been
- received. */
- xResult = prvEMACRxPoll();
- }
-
- if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
- {
- /* Future extension: code to release TX buffers if zero-copy is used. */
- ulISREvents &= ~EMAC_IF_TX_EVENT;
- while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )
- {
- #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
- {
- pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
- if( pxBuffer != NULL )
- {
- vReleaseNetworkBufferAndDescriptor( pxBuffer );
- tx_release_count[ 0 ]++;
- }
- else
- {
- tx_release_count[ 1 ]++;
- }
- }
- #else
- {
- tx_release_count[ 0 ]++;
- }
- #endif
- uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
- if( uxCount < GMAC_TX_BUFFERS )
- {
- /* Tell the counting semaphore that one more TX descriptor is available. */
- xSemaphoreGive( xTXDescriptorSemaphore );
- }
- }
- }
-
- if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
- {
- /* Future extension: logging about errors that occurred. */
- ulISREvents &= ~EMAC_IF_ERR_EVENT;
- }
-
- 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 )
- {
- /* Check the link status again. */
- xStatus = ulReadMDIO( PHY_REG_01_BMSR );
-
- if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
- {
- ulPHYLinkStatus = xStatus;
- FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
- }
-
- vTaskSetTimeOutState( &xPhyTime );
- if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
- {
- xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
- }
- else
- {
- xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
- }
- }
- }
-}
-/*-----------------------------------------------------------*/
+/*
+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"
+
+/* Some files from the Atmel Software Framework */
+/*_RB_ The SAM4E portable layer has three different header files called gmac.h! */
+#include "instance/gmac.h"
+#include <sysclk.h>
+#include <ethernet_phy.h>
+
+#ifndef BMSR_LINK_STATUS
+ #define BMSR_LINK_STATUS 0x0004 //!< Link status
+#endif
+
+#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
+
+/* Interrupt events to process. Currently only the Rx event is 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 )
+
+#define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR
+
+#define HZ_PER_MHZ ( 1000000UL )
+
+#ifndef EMAC_MAX_BLOCK_TIME_MS
+ #define EMAC_MAX_BLOCK_TIME_MS 100ul
+#endif
+
+#if !defined( GMAC_USES_TX_CALLBACK ) || ( GMAC_USES_TX_CALLBACK != 1 )
+ #error Please define GMAC_USES_TX_CALLBACK as 1
+#endif
+
+/* Default the size of the stack used by the EMAC deferred handler task to 4x
+the size of the stack used by the idle task - but allow this to be overridden in
+FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
+#ifndef configEMAC_TASK_STACK_SIZE
+ #define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
+#endif
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Wait a fixed time for the link status to indicate the network is up.
+ */
+static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
+
+#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
+ void vGMACGenerateChecksum( uint8_t *apBuffer );
+#endif
+
+/*
+ * Called from the ASF GMAC driver.
+ */
+static void prvRxCallback( uint32_t ulStatus );
+static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer );
+
+/*
+ * A deferred interrupt handler task that processes GMAC interrupts.
+ */
+static void prvEMACHandlerTask( void *pvParameters );
+
+/*
+ * Initialise the ASF GMAC driver.
+ */
+static BaseType_t prvGMACInit( void );
+
+/*
+ * Try to obtain an Rx packet from the hardware.
+ */
+static uint32_t prvEMACRxPoll( void );
+
+/*-----------------------------------------------------------*/
+
+/* Bit map of outstanding ETH interrupt events for processing. Currently only
+the Rx 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;
+static volatile BaseType_t xGMACSwitchRequired;
+
+/* ethernet_phy_addr: the address of the PHY in use.
+Atmel was a bit ambiguous about it so the address will be stored
+in this variable, see ethernet_phy.c */
+extern int ethernet_phy_addr;
+
+/* LLMNR multicast address. */
+static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
+
+/* The GMAC object as defined by the ASF drivers. */
+static gmac_device_t gs_gmac_dev;
+
+/* MAC address to use. */
+extern const uint8_t ucMACAddress[ 6 ];
+
+/* Holds the handle of the task used as a deferred interrupt processor. The
+handle is used so direct notifications can be sent to the task for all EMAC/DMA
+related interrupts. */
+TaskHandle_t xEMACTaskHandle = NULL;
+
+static QueueHandle_t xTxBufferQueue;
+int tx_release_count[ 4 ];
+
+/* xTXDescriptorSemaphore is a counting semaphore with
+a maximum count of GMAC_TX_BUFFERS, which is the number of
+DMA TX descriptors. */
+static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
+
+/*-----------------------------------------------------------*/
+
+/*
+ * GMAC interrupt handler.
+ */
+void GMAC_Handler(void)
+{
+ xGMACSwitchRequired = pdFALSE;
+
+ /* gmac_handler() may call prvRxCallback() which may change
+ the value of xGMACSwitchRequired. */
+ gmac_handler( &gs_gmac_dev );
+
+ if( xGMACSwitchRequired != pdFALSE )
+ {
+ portEND_SWITCHING_ISR( xGMACSwitchRequired );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvRxCallback( uint32_t ulStatus )
+{
+ if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
+ {
+ /* let the prvEMACHandlerTask know that there was an RX event. */
+ ulISREvents |= EMAC_IF_RX_EVENT;
+ /* Only an RX interrupt can wakeup prvEMACHandlerTask. */
+ vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer )
+{
+ if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
+ {
+ /* let the prvEMACHandlerTask know that there was an RX event. */
+ ulISREvents |= EMAC_IF_TX_EVENT;
+
+ vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
+ xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
+ tx_release_count[ 2 ]++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceInitialise( void )
+{
+const TickType_t x5_Seconds = 5000UL;
+
+ if( xEMACTaskHandle == NULL )
+ {
+ prvGMACInit();
+
+ /* Wait at most 5 seconds for a Link Status in the PHY. */
+ xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
+
+ /* The handler task is created at the highest possible priority to
+ ensure the interrupt handler can return directly to it. */
+ xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
+ configASSERT( xEMACTaskHandle );
+ }
+
+ if( xTxBufferQueue == NULL )
+ {
+ xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
+ configASSERT( xTxBufferQueue );
+ }
+
+ if( xTXDescriptorSemaphore == NULL )
+ {
+ xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
+ configASSERT( xTXDescriptorSemaphore );
+ }
+ /* When returning non-zero, the stack will become active and
+ start DHCP (in configured) */
+ return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xGetPhyLinkStatus( void )
+{
+BaseType_t xResult;
+
+ /* This function returns true if the Link Status in the PHY is high. */
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ xResult = pdTRUE;
+ }
+ else
+ {
+ xResult = pdFALSE;
+ }
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
+{
+/* Do not wait too long for a free TX DMA buffer. */
+const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
+
+ do {
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
+ {
+ /* Do not attempt to send packets as long as the Link Status is low. */
+ break;
+ }
+ if( xTXDescriptorSemaphore == NULL )
+ {
+ /* Semaphore has not been created yet? */
+ break;
+ }
+ if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
+ {
+ /* Time-out waiting for a free TX descriptor. */
+ tx_release_count[ 3 ]++;
+ break;
+ }
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ /* Confirm that the pxDescriptor may be kept by the driver. */
+ configASSERT( bReleaseAfterSend != pdFALSE );
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+ gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback );
+
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ /* Confirm that the pxDescriptor may be kept by the driver. */
+ bReleaseAfterSend = pdFALSE;
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+ /* Not interested in a call-back after TX. */
+ iptraceNETWORK_INTERFACE_TRANSMIT();
+ } while( 0 );
+
+ if( bReleaseAfterSend != pdFALSE )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxDescriptor );
+ }
+ return pdTRUE;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvGMACInit( void )
+{
+uint32_t ncfgr;
+
+ gmac_options_t gmac_option;
+
+ memset( &gmac_option, '\0', sizeof( gmac_option ) );
+ gmac_option.uc_copy_all_frame = 0;
+ gmac_option.uc_no_boardcast = 0;
+ memcpy( gmac_option.uc_mac_addr, ucMACAddress, sizeof( gmac_option.uc_mac_addr ) );
+
+ gs_gmac_dev.p_hw = GMAC;
+ gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );
+
+ NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );
+ NVIC_EnableIRQ( GMAC_IRQn );
+
+ /* Contact the Ethernet PHY and store it's address in 'ethernet_phy_addr' */
+ ethernet_phy_init( GMAC, ETHERNET_CONF_PHY_ADDR, sysclk_get_cpu_hz() );
+
+ ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr );
+ ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 );
+
+ /* The GMAC driver will call a hook prvRxCallback(), which
+ in turn will wake-up the task by calling vTaskNotifyGiveFromISR() */
+ gmac_dev_set_rx_callback( &gs_gmac_dev, prvRxCallback );
+ gmac_set_address( GMAC, 1, (uint8_t*)llmnr_mac_address );
+
+ ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD;
+
+ GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr;
+
+ return 1;
+}
+/*-----------------------------------------------------------*/
+
+static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress )
+{
+uint32_t ulValue, ulReturn;
+int rc;
+
+ gmac_enable_management( GMAC, 1 );
+ rc = gmac_phy_read( GMAC, ethernet_phy_addr, usAddress, &ulValue );
+ gmac_enable_management( GMAC, 0 );
+ if( rc == GMAC_OK )
+ {
+ ulReturn = ulValue;
+ }
+ else
+ {
+ ulReturn = 0UL;
+ }
+
+ return ulReturn;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
+{
+TickType_t xStartTime = xTaskGetTickCount();
+TickType_t xEndTime;
+BaseType_t xReturn;
+const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );
+
+ for( ;; )
+ {
+ xEndTime = xTaskGetTickCount();
+
+ if( ( xEndTime - xStartTime ) > xMaxTime )
+ {
+ /* Wated more than xMaxTime, return. */
+ xReturn = pdFALSE;
+ break;
+ }
+
+ /* Check the link status again. */
+ ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
+
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ /* Link is up - return. */
+ xReturn = pdTRUE;
+ break;
+ }
+
+ /* Link is down - wait in the Blocked state for a short while (to allow
+ other tasks to execute) before checking again. */
+ vTaskDelay( xShortTime );
+ }
+
+ FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n",
+ xReturn,
+ ethernet_phy_addr,
+ sysclk_get_cpu_hz() / HZ_PER_MHZ ) );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+//#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
+
+ void vGMACGenerateChecksum( uint8_t *apBuffer )
+ {
+ ProtocolPacket_t *xProtPacket = (ProtocolPacket_t *)apBuffer;
+
+ if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
+ {
+ IPHeader_t *pxIPHeader = &(xProtPacket->xTCPPacket.xIPHeader);
+
+ /* Calculate the IP header checksum. */
+ pxIPHeader->usHeaderChecksum = 0x00;
+ pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
+ pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
+
+ /* Calculate the TCP checksum for an outgoing packet. */
+ usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE );
+ }
+ }
+
+//#endif
+/*-----------------------------------------------------------*/
+
+static uint32_t prvEMACRxPoll( void )
+{
+unsigned char *pucUseBuffer;
+uint32_t ulReceiveCount, ulResult, ulReturnValue = 0;
+static NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL;
+const UBaseType_t xMinDescriptorsToLeave = 2UL;
+const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL );
+static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
+
+ for( ;; )
+ {
+ /* If pxNextNetworkBufferDescriptor was not left pointing at a valid
+ descriptor then allocate one now. */
+ if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) )
+ {
+ pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );
+ }
+
+ if( pxNextNetworkBufferDescriptor != NULL )
+ {
+ /* Point pucUseBuffer to the buffer pointed to by the descriptor. */
+ pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
+ }
+ else
+ {
+ /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
+ messages will be flushed and ignored. */
+ pucUseBuffer = NULL;
+ }
+
+ /* Read the next packet from the hardware into pucUseBuffer. */
+ ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount );
+
+ if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )
+ {
+ /* No data from the hardware. */
+ break;
+ }
+
+ if( pxNextNetworkBufferDescriptor == NULL )
+ {
+ /* Data was read from the hardware, but no descriptor was available
+ for it, so it will be dropped. */
+ iptraceETHERNET_RX_EVENT_LOST();
+ continue;
+ }
+
+ iptraceNETWORK_INTERFACE_RECEIVE();
+ pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;
+ xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;
+
+ /* Send the descriptor to the IP task for processing. */
+ if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )
+ {
+ /* The buffer could not be sent to the stack so must be released
+ again. */
+ vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );
+ iptraceETHERNET_RX_EVENT_LOST();
+ FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
+ }
+
+ /* Now the buffer has either been passed to the IP-task,
+ or it has been released in the code above. */
+ pxNextNetworkBufferDescriptor = NULL;
+ ulReturnValue++;
+ }
+
+ return ulReturnValue;
+}
+/*-----------------------------------------------------------*/
+
+static void prvEMACHandlerTask( void *pvParameters )
+{
+TimeOut_t xPhyTime;
+TickType_t xPhyRemTime;
+UBaseType_t uxLastMinBufferCount = 0, uxCount;
+UBaseType_t uxCurrentCount;
+#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+ UBaseType_t uxLastMinQueueSpace;
+#endif
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ NetworkBufferDescriptor_t *pxBuffer;
+#endif
+uint8_t *pucBuffer;
+BaseType_t xResult = 0;
+uint32_t xStatus;
+const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
+
+ /* Remove compiler warnings about unused parameters. */
+ ( void ) pvParameters;
+
+ configASSERT( xEMACTaskHandle );
+
+ 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 )
+ {
+ 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 */
+
+ if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
+ {
+ /* No events to process now, wait for the next. */
+ ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
+ }
+
+ if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
+ {
+ ulISREvents &= ~EMAC_IF_RX_EVENT;
+
+ /* Wait for the EMAC interrupt to indicate that another packet has been
+ received. */
+ xResult = prvEMACRxPoll();
+ }
+
+ if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
+ {
+ /* Future extension: code to release TX buffers if zero-copy is used. */
+ ulISREvents &= ~EMAC_IF_TX_EVENT;
+ while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )
+ {
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
+ if( pxBuffer != NULL )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxBuffer );
+ tx_release_count[ 0 ]++;
+ }
+ else
+ {
+ tx_release_count[ 1 ]++;
+ }
+ }
+ #else
+ {
+ tx_release_count[ 0 ]++;
+ }
+ #endif
+ uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
+ if( uxCount < GMAC_TX_BUFFERS )
+ {
+ /* Tell the counting semaphore that one more TX descriptor is available. */
+ xSemaphoreGive( xTXDescriptorSemaphore );
+ }
+ }
+ }
+
+ if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
+ {
+ /* Future extension: logging about errors that occurred. */
+ ulISREvents &= ~EMAC_IF_ERR_EVENT;
+ }
+
+ 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 )
+ {
+ /* Check the link status again. */
+ xStatus = ulReadMDIO( PHY_REG_01_BMSR );
+
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
+ {
+ ulPHYLinkStatus = xStatus;
+ FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
+ }
+
+ vTaskSetTimeOutState( &xPhyTime );
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+ }
+ else
+ {
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------*/