| /* |
| FreeRTOS+TCP V2.0.11 |
| Copyright (C) 2018 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 |
| */ |
| |
| /* FreeRTOS includes. */ |
| #include "FreeRTOS.h" |
| #include "list.h" |
| #include "queue.h" |
| #include "semphr.h" |
| #include "task.h" |
| |
| /* FreeRTOS+TCP includes. */ |
| #include "FreeRTOS_IP.h" |
| #include "FreeRTOS_Sockets.h" |
| #include "FreeRTOS_IP_Private.h" |
| #include "NetworkBufferManagement.h" |
| #include "NetworkInterface.h" |
| |
| |
| #include "m480_eth.h" |
| |
| /* 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 |
| |
| /* Default the size of the stack used by the EMAC deferred handler task to twice |
| 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 ( 2 * configMINIMAL_STACK_SIZE ) |
| #endif |
| |
| |
| static SemaphoreHandle_t xTXMutex = NULL; |
| |
| /* 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; |
| static TimerHandle_t xPhyHandlerTask = NULL; |
| /* |
| * A task that processes received frames. |
| */ |
| static void prvEMACHandlerTask( void *pvParameters ); |
| static void prvPhyTmrCallback( TimerHandle_t xTimer ); |
| |
| /* The size of each buffer when BufferAllocation_1 is used: |
| http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html */ |
| |
| #define niBUFFER_1_PACKET_SIZE 1536 |
| #ifdef __ICCARM__ |
| #pragma data_alignment=4 |
| static uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] |
| #else |
| static uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ((aligned(4))); |
| #endif |
| |
| BaseType_t xNetworkInterfaceInitialise( void ) |
| { |
| uint8_t hwaddr[6]; |
| BaseType_t xReturn = pdPASS; |
| |
| /* Init ETH */ |
| numaker_mac_address(hwaddr); |
| FreeRTOS_UpdateMACAddress(hwaddr); |
| FreeRTOS_printf( ("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", hwaddr[0], hwaddr[1],hwaddr[2],hwaddr[3],hwaddr[4],hwaddr[5]) ); |
| /* Enable clock & set EMAC configuration */ |
| /* Enable MAC and DMA transmission and reception */ |
| if( numaker_eth_init(hwaddr) < 0) |
| { |
| xReturn = pdFAIL; |
| } else { |
| xReturn = pdPASS; |
| /* Guard against the task being created more than once and the |
| descriptors being initialized more than once. */ |
| /* Timer task to monitor PHY Link status */ |
| if( xPhyHandlerTask == NULL ) |
| { |
| xPhyHandlerTask = xTimerCreate( "TimerPhy", pdMS_TO_TICKS( 1000 ), pdTRUE, 0, prvPhyTmrCallback ); |
| configASSERT(xPhyHandlerTask); |
| xReturn = xTimerStart( xPhyHandlerTask, 0 ) ; |
| configASSERT( xReturn ); |
| } |
| /* Rx task */ |
| if( xRxHanderTask == NULL ) |
| { |
| xReturn = xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xRxHanderTask ); |
| configASSERT( xReturn ); |
| } |
| |
| if( xTXMutex == NULL ) |
| { |
| xTXMutex = xSemaphoreCreateMutex(); |
| configASSERT( xTXMutex ); |
| } |
| } |
| |
| NVIC_SetPriority( EMAC_RX_IRQn, configMAC_INTERRUPT_PRIORITY ); |
| NVIC_SetPriority( EMAC_TX_IRQn, configMAC_INTERRUPT_PRIORITY ); |
| |
| numaker_eth_enable_interrupts(); |
| |
| FreeRTOS_printf( ("ETH-RX priority:%d\n",NVIC_GetPriority( EMAC_RX_IRQn)) ); |
| |
| return xReturn; |
| } |
| |
| BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t xReleaseAfterSend ) |
| { |
| uint8_t *buffer=NULL; |
| // FreeRTOS_printf(("<-- dataLength=%d\n",pxDescriptor->xDataLength)); |
| if( pxDescriptor->xDataLength >= PACKET_BUFFER_SIZE ) |
| { |
| FreeRTOS_printf(("TX buffer length %d over %d\n", pxDescriptor->xDataLength, PACKET_BUFFER_SIZE)); |
| return pdFALSE; |
| } |
| |
| buffer = numaker_eth_get_tx_buf(); |
| if( buffer == NULL ) |
| { |
| NU_DEBUGF(("Eth TX slots are busy\n")); |
| return pdFALSE; |
| } |
| |
| /* Get exclusive access */ |
| xSemaphoreTake(xTXMutex, portMAX_DELAY); |
| NU_DEBUGF(("%s ... buffer=0x%x\r\n",__FUNCTION__, buffer)); |
| //SendData: pt = pxDescriptor->pucBuffer, length = pxDescriptor->xDataLength |
| memcpy(buffer, pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength); |
| numaker_eth_trigger_tx(pxDescriptor->xDataLength, NULL); |
| /* Call the standard trace macro to log the send event. */ |
| iptraceNETWORK_INTERFACE_TRANSMIT(); |
| |
| if( xReleaseAfterSend != pdFALSE ) |
| { |
| /* It is assumed SendData() copies the data out of the FreeRTOS+TCP Ethernet |
| buffer. The Ethernet buffer is therefore no longer needed, and must be |
| freed for re-use. */ |
| vReleaseNetworkBufferAndDescriptor( pxDescriptor ); |
| } |
| |
| xSemaphoreGive(xTXMutex); |
| |
| return pdTRUE; |
| } |
| |
| |
| 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; |
| } |
| } |
| |
| |
| BaseType_t xGetPhyLinkStatus( void ) |
| { |
| BaseType_t xReturn; |
| |
| if( numaker_eth_link_ok() ) |
| { |
| xReturn = pdPASS; |
| } |
| else |
| { |
| xReturn = pdFAIL; |
| } |
| |
| return xReturn; |
| } |
| |
| static void prvPhyTmrCallback( TimerHandle_t xTimer ) |
| { |
| IPStackEvent_t xRxEvent; |
| static BaseType_t lastLink = pdFAIL; |
| BaseType_t currLink = xGetPhyLinkStatus(); |
| if( currLink != lastLink ) |
| { |
| FreeRTOS_printf(("PHY Link %s\n", (currLink) ? "Up" : "Down")); |
| if( !currLink ) |
| { |
| xRxEvent.eEventType = eNetworkDownEvent; |
| xSendEventStructToIPTask( &xRxEvent, 0 ); |
| } |
| lastLink = currLink; |
| } |
| |
| } |
| |
| |
| 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; |
| uint16_t dataLength = 0; |
| uint8_t *buffer = NULL; |
| NetworkBufferDescriptor_t *pxBufferDescriptor = NULL; |
| IPStackEvent_t xRxEvent; |
| const TickType_t xBlockTime = pdMS_TO_TICKS( 5000ul ); |
| |
| /* Remove compiler warnings about unused parameters. */ |
| ( void ) pvParameters; |
| /* A possibility to set some additional task properties. */ |
| |
| 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 ) ); |
| } |
| |
| /* No events to process now, wait for the next. */ |
| ulTaskNotifyTake( pdFALSE, portMAX_DELAY ); |
| while(1) |
| { |
| /* get received frame */ |
| if ( numaker_eth_get_rx_buf(&dataLength, &buffer) != 0) { |
| /* The event was lost because a network buffer was not available. |
| Call the standard trace macro to log the occurrence. */ |
| iptraceETHERNET_RX_EVENT_LOST(); |
| break; |
| } |
| |
| /* Allocate a network buffer descriptor that points to a buffer |
| large enough to hold the received frame. As this is the simple |
| rather than efficient example the received data will just be copied |
| into this buffer. */ |
| |
| pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( PACKET_BUFFER_SIZE, 0 ); |
| |
| if( pxBufferDescriptor != NULL ) |
| { |
| memcpy( pxBufferDescriptor->pucEthernetBuffer, buffer, dataLength ); |
| // FreeRTOS_printf(("--> dataLength=%d\n",dataLength)); |
| pxBufferDescriptor->xDataLength = dataLength; |
| } else { |
| numaker_eth_rx_next(); |
| iptraceETHERNET_RX_EVENT_LOST(); |
| break; |
| } |
| /* The event about to be sent to the TCP/IP is an Rx event. */ |
| xRxEvent.eEventType = eNetworkRxEvent; |
| |
| /* pvData is used to point to the network buffer descriptor that |
| now references the received data. */ |
| xRxEvent.pvData = ( void * ) pxBufferDescriptor; |
| |
| /* Send the data to the TCP/IP stack. */ |
| if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE ) |
| { |
| /* The buffer could not be sent to the IP task so the buffer |
| must be released. */ |
| vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor ); |
| |
| /* Make a call to the standard trace macro to log the |
| occurrence. */ |
| |
| iptraceETHERNET_RX_EVENT_LOST(); |
| } else |
| { |
| /* The message was successfully sent to the TCP/IP stack. |
| Call the standard trace macro to log the occurrence. */ |
| iptraceNETWORK_INTERFACE_RECEIVE(); |
| } |
| numaker_eth_rx_next(); |
| } |
| numaker_eth_trigger_rx(); |
| } |
| } |
| |
| void xNetworkCallback(char event) |
| { |
| BaseType_t xHigherPriorityTaskWoken = pdFALSE; |
| switch (event) |
| { |
| case 'R': //For RX event |
| /* Wakeup the prvEMACHandlerTask. */ |
| if( xRxHanderTask != NULL ) |
| { |
| vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken ); |
| portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); |
| } |
| break; |
| case 'T': //For TX event |
| // ack of tx done, no-op in this stage |
| break; |
| default: |
| break; |
| } |
| } |