diff --git a/source/portable/NetworkInterface/CMakeLists.txt b/source/portable/NetworkInterface/CMakeLists.txt index a822434b7..0defa6dec 100644 --- a/source/portable/NetworkInterface/CMakeLists.txt +++ b/source/portable/NetworkInterface/CMakeLists.txt @@ -47,6 +47,7 @@ add_subdirectory(MPS4_CS315) add_subdirectory(NXP1060) add_subdirectory(mw300_rd) add_subdirectory(pic32mzef) +add_subdirectory(pic32mx) add_subdirectory(RX) add_subdirectory(SH2A) add_subdirectory(STM32Fxx) diff --git a/source/portable/NetworkInterface/pic32mx/BufferAllocation_2.c b/source/portable/NetworkInterface/pic32mx/BufferAllocation_2.c new file mode 100644 index 000000000..622a9b84f --- /dev/null +++ b/source/portable/NetworkInterface/pic32mx/BufferAllocation_2.c @@ -0,0 +1,634 @@ +/* + * FreeRTOS+TCP + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * 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 + */ + +/****************************************************************************** +* +* See the following web page for essential buffer allocation scheme usage and +* configuration details: +* https://freertos.org/Documentation/03-Libraries/02-FreeRTOS-plus/02-FreeRTOS-plus-TCP/05-Buffer-management +* +******************************************************************************/ + +/* THIS FILE SHOULD NOT BE USED IF THE PROJECT INCLUDES A MEMORY ALLOCATOR + * THAT WILL FRAGMENT THE HEAP MEMORY. For example, heap_2 must not be used, + * heap_4 can be used. */ + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkInterface.h" +#include "NetworkBufferManagement.h" + +#include "tcpip/tcpip.h" +#include "tcpip/src/tcpip_private.h" + +#include "NetworkConfig.h" + +/* The obtained network buffer must be large enough to hold a packet that might + * replace the packet that was requested to be sent. */ +#if ipconfigUSE_TCP == 1 + #define baMINIMAL_BUFFER_SIZE sizeof( TCPPacket_t ) +#else + #define baMINIMAL_BUFFER_SIZE sizeof( ARPPacket_t ) +#endif /* ipconfigUSE_TCP == 1 */ + +STATIC_ASSERT( ipconfigETHERNET_MINIMUM_PACKET_BYTES <= baMINIMAL_BUFFER_SIZE ); + +#define baALIGNMENT_BYTES ( sizeof( size_t ) ) +#define baALIGNMENT_MASK ( baALIGNMENT_BYTES - 1U ) +#define baADD_WILL_OVERFLOW( a, b ) ( ( a ) > ( SIZE_MAX - ( b ) ) ) + +/* A list of free (available) NetworkBufferDescriptor_t structures. */ +static List_t xFreeBuffersList; + +/* Some statistics about the use of buffers. */ +static size_t uxMinimumFreeNetworkBuffers; + +/* Declares the pool of NetworkBufferDescriptor_t structures that are available + * to the system. All the network buffers referenced from xFreeBuffersList exist + * in this array. The array is not accessed directly except during initialisation, + * when the xFreeBuffersList is filled (as all the buffers are free when the system + * is booted). */ +static NetworkBufferDescriptor_t xNetworkBufferDescriptors[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ]; + +/* This constant is defined as false to let FreeRTOS_TCP_IP.c know that the + * network buffers have a variable size: resizing may be necessary */ +const BaseType_t xBufferAllocFixedSize = pdFALSE; + +/* The semaphore used to obtain network buffers. */ +static SemaphoreHandle_t xNetworkBufferSemaphore = NULL; + +/*-----------------------------------------------------------*/ + +#ifdef PIC32_USE_ETHERNET + +/* PIC32 specific stuff */ +/* */ + +/* MAC packet acknowledgment, once MAC is done with it */ + static bool PIC32_MacPacketAcknowledge( TCPIP_MAC_PACKET * pPkt, + const void * param ); + +/* allocates a MAC packet that holds a data buffer that can be used by both: */ +/* - the FreeRTOSIP (NetworkBufferDescriptor_t->pucEthernetBuffer) */ +/* - the Harmony MAC driver: TCPIP_MAC_PACKET->pDSeg->segLoad */ +/* from the beginning of the buffer: */ +/* - 4 bytes pointer to the network descriptor (FreeRTOS) */ +/* - 4 bytes pointer to the MAC packet (pic32_NetworkInterface.c) */ +/* - 2 bytes offset from the MAC packet (Harmony MAC driver: segLoadOffset) */ +/* */ +/* NOTE: segLoadLen should NOT include: */ +/* - the TCPIP_MAC_FRAME_OFFSET (== ipBUFFER_PADDING which should be == 10!) */ +/* - the sizeof(TCPIP_MAC_ETHERNET_HEADER) */ +/* These are added by the MAC packet allocation! */ +/* */ + static uint8_t * PIC32_PktAlloc( uint16_t pktLen, + uint16_t segLoadLen, + TCPIP_MAC_PACKET_ACK_FUNC ackF, + TCPIP_MAC_PACKET ** pPtrPkt ) + { + uint8_t * pBuff = 0; + + /* allocate standard packet */ + TCPIP_MAC_PACKET * pPkt = TCPIP_PKT_PacketAlloc( pktLen, segLoadLen, 0 ); + + /* set the MAC packet pointer in the packet */ + if( pPkt != 0 ) + { + pBuff = pPkt->pDSeg->segLoad; + TCPIP_MAC_PACKET ** ppkt = ( TCPIP_MAC_PACKET ** ) ( pBuff - PIC32_BUFFER_PKT_PTR_OSSET ); + configASSERT( ( ( uint32_t ) ppkt & ( sizeof( uint32_t ) - 1 ) ) == 0 ); + *ppkt = pPkt; /* store the packet it comes from */ + pPkt->ackFunc = ackF; + pPkt->ackParam = 0; + } + + if( pPtrPkt != 0 ) + { + *pPtrPkt = pPkt; + } + + return pBuff; + } + + + +/* standard PIC32 MAC allocation function for a MAC packet */ +/* this packet saves room for the FreeRTOS network descriptor */ +/* at the beginning of the data buffer */ +/* see NetworkBufferAllocate */ +/* Note: flags parameter is ignored since that's used in the Harmony stack only */ + TCPIP_MAC_PACKET * PIC32_MacPacketAllocate( uint16_t pktLen, + uint16_t segLoadLen, + TCPIP_MAC_PACKET_FLAGS flags ) + { + TCPIP_MAC_PACKET * pPkt; + + PIC32_PktAlloc( pktLen, segLoadLen, 0, &pPkt ); + + return pPkt; + } + +/* standard PIC32 MAC packet acknowledgment */ +/* function called once MAC is done with it */ + static bool PIC32_MacPacketAcknowledge( TCPIP_MAC_PACKET * pPkt, + const void * param ) + { + configASSERT( ( pPkt != 0 ) ); + + TCPIP_PKT_PacketFree( pPkt ); + + return false; + } + +/* associates the current MAC packet with a network descriptor */ +/* mainly for RX packet */ + void PIC32_MacAssociate( TCPIP_MAC_PACKET * pRxPkt, + NetworkBufferDescriptor_t * pxBufferDescriptor, + size_t pktLength ) + { + uint8_t * pPktBuff = pRxPkt->pDSeg->segLoad; + + pxBufferDescriptor->pucEthernetBuffer = pPktBuff; + pxBufferDescriptor->xDataLength = pktLength; + + /* make sure this is a properly allocated packet */ + TCPIP_MAC_PACKET ** ppkt = ( TCPIP_MAC_PACKET ** ) ( pPktBuff - PIC32_BUFFER_PKT_PTR_OSSET ); + + configASSERT( ( ( uint32_t ) ppkt & ( sizeof( uint32_t ) - 1 ) ) == 0 ); + + if( *ppkt != pRxPkt ) + { + configASSERT( false ); + } + + /* set the proper descriptor info */ + NetworkBufferDescriptor_t ** ppDcpt = ( NetworkBufferDescriptor_t ** ) ( pPktBuff - ipBUFFER_PADDING ); + + configASSERT( ( ( uint32_t ) ppDcpt & ( sizeof( uint32_t ) - 1 ) ) == 0 ); + *ppDcpt = pxBufferDescriptor; + } + +/* debug functionality */ + void PIC32_MacPacketOrphan( TCPIP_MAC_PACKET * pPkt ) + { + TCPIP_PKT_PacketFree( pPkt ); + configASSERT( false ); + } + +/* FreeRTOS allocation functions */ + +/* allocates a buffer that can be used by both: */ +/* - the FreeRTOSIP (NetworkBufferDescriptor_t->pucEthernetBuffer) */ +/* - the Harmony MAC driver: TCPIP_MAC_PACKET */ +/* See PIC32_PktAlloc for details */ +/* */ +/* NOTE: reqLength should NOT include the ipBUFFER_PADDING (which should be == 10!) */ +/* or the sizeof(TCPIP_MAC_ETHERNET_HEADER) */ +/* These are added by the MAC packet allocation! */ +/* */ + uint8_t * NetworkBufferAllocate( size_t reqLength ) + { + return PIC32_PktAlloc( sizeof( TCPIP_MAC_PACKET ), reqLength, PIC32_MacPacketAcknowledge, 0 ); + } + +/* deallocates a network buffer previously allocated */ +/* with NetworkBufferAllocate */ + void NetworkBufferFree( uint8_t * pNetworkBuffer ) + { + if( pNetworkBuffer != 0 ) + { + TCPIP_MAC_PACKET ** ppkt = ( TCPIP_MAC_PACKET ** ) ( pNetworkBuffer - PIC32_BUFFER_PKT_PTR_OSSET ); + configASSERT( ( ( uint32_t ) ppkt & ( sizeof( uint32_t ) - 1 ) ) == 0 ); + TCPIP_MAC_PACKET * pPkt = *ppkt; + configASSERT( ( pPkt != 0 ) ); + + if( pPkt->ackFunc != 0 ) + { + ( *pPkt->ackFunc )( pPkt, pPkt->ackParam ); + } + else + { /* ??? */ + PIC32_MacPacketOrphan( pPkt ); + } + } + } + +#endif /* #ifdef PIC32_USE_ETHERNET */ + +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkBuffersInitialise( void ) +{ + BaseType_t xReturn, x; + + /* Only initialise the buffers and their associated kernel objects if they + * have not been initialised before. */ + if( xNetworkBufferSemaphore == NULL ) + { + xNetworkBufferSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ); + configASSERT( xNetworkBufferSemaphore ); + + if( xNetworkBufferSemaphore != NULL ) + { + #if ( configQUEUE_REGISTRY_SIZE > 0 ) + { + vQueueAddToRegistry( xNetworkBufferSemaphore, "NetBufSem" ); + } + #endif /* configQUEUE_REGISTRY_SIZE */ + + /* If the trace recorder code is included name the semaphore for viewing + * in FreeRTOS+Trace. */ + #if ( ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 ) + { + extern QueueHandle_t xNetworkEventQueue; + vTraceSetQueueName( xNetworkEventQueue, "IPStackEvent" ); + vTraceSetQueueName( xNetworkBufferSemaphore, "NetworkBufferCount" ); + } + #endif /* ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 */ + + vListInitialise( &xFreeBuffersList ); + + /* Initialise all the network buffers. No storage is allocated to + * the buffers yet. */ + for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ ) + { + /* Initialise and set the owner of the buffer list items. */ + xNetworkBufferDescriptors[ x ].pucEthernetBuffer = NULL; + vListInitialiseItem( &( xNetworkBufferDescriptors[ x ].xBufferListItem ) ); + listSET_LIST_ITEM_OWNER( &( xNetworkBufferDescriptors[ x ].xBufferListItem ), &xNetworkBufferDescriptors[ x ] ); + + /* Currently, all buffers are available for use. */ + vListInsert( &xFreeBuffersList, &( xNetworkBufferDescriptors[ x ].xBufferListItem ) ); + } + + uxMinimumFreeNetworkBuffers = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; + } + } + + if( xNetworkBufferSemaphore == NULL ) + { + xReturn = pdFAIL; + } + else + { + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +uint8_t * pucGetNetworkBuffer( size_t * pxRequestedSizeBytes ) +{ + uint8_t * pucEthernetBuffer; + size_t xSize = *pxRequestedSizeBytes; + + if( xSize < baMINIMAL_BUFFER_SIZE ) + { + /* Buffers must be at least large enough to hold a TCP-packet with + * headers, or an ARP packet, in case TCP is not included. */ + xSize = baMINIMAL_BUFFER_SIZE; + } + + /* Round up xSize to the nearest multiple of N bytes, + * where N equals 'sizeof( size_t )'. */ + if( ( xSize & ( sizeof( size_t ) - 1u ) ) != 0u ) + { + xSize = ( xSize | ( sizeof( size_t ) - 1u ) ) + 1u; + } + + *pxRequestedSizeBytes = xSize; + + /* Allocate a buffer large enough to store the requested Ethernet frame size + * and a pointer to a network buffer structure (hence the addition of + * ipBUFFER_PADDING bytes). */ + + #ifdef PIC32_USE_ETHERNET + pucEthernetBuffer = NetworkBufferAllocate( xSize - sizeof( TCPIP_MAC_ETHERNET_HEADER ) ); + #else + pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xSize + ipBUFFER_PADDING ); + #endif /* #ifdef PIC32_USE_ETHERNET */ + + configASSERT( pucEthernetBuffer ); + + if( pucEthernetBuffer != NULL ) + { + /* Enough space is left at the start of the buffer to place a pointer to + * the network buffer structure that references this Ethernet buffer. + * Return a pointer to the start of the Ethernet buffer itself. */ + #ifndef PIC32_USE_ETHERNET + pucEthernetBuffer += ipBUFFER_PADDING; + #endif /* #ifndef PIC32_USE_ETHERNET */ + } + + return pucEthernetBuffer; +} +/*-----------------------------------------------------------*/ + +void vReleaseNetworkBuffer( uint8_t * pucEthernetBuffer ) +{ + /* There is space before the Ethernet buffer in which a pointer to the + * network buffer that references this Ethernet buffer is stored. Remove the + * space before freeing the buffer. */ + #ifdef PIC32_USE_ETHERNET + NetworkBufferFree( pucEthernetBuffer ); + #else + if( pucEthernetBuffer != NULL ) + { + pucEthernetBuffer -= ipBUFFER_PADDING; + vPortFree( ( void * ) pucEthernetBuffer ); + } + #endif /* #ifdef PIC32_USE_ETHERNET */ +} +/*-----------------------------------------------------------*/ + +NetworkBufferDescriptor_t * pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, + TickType_t xBlockTimeTicks ) +{ + NetworkBufferDescriptor_t * pxReturn = NULL; + size_t uxCount; + size_t xBytesRequiredForAlignment, xAllocatedBytes; + BaseType_t xIntegerOverflowed = pdFALSE; + + if( ( xRequestedSizeBytes != 0u ) && ( xRequestedSizeBytes < ( size_t ) baMINIMAL_BUFFER_SIZE ) ) + { + /* ARP packets can replace application packets, so the storage must be + * at least large enough to hold an ARP. */ + xRequestedSizeBytes = baMINIMAL_BUFFER_SIZE; + } + + #ifdef PIC32_USE_ETHERNET + if( xRequestedSizeBytes != 0u ) + { + #endif /* #ifdef PIC32_USE_ETHERNET */ + + if( baADD_WILL_OVERFLOW( xRequestedSizeBytes, 2 ) == 0 ) + { + xRequestedSizeBytes += 2U; + } + else + { + xIntegerOverflowed = pdTRUE; + } + + if( ( xRequestedSizeBytes & baALIGNMENT_MASK ) != 0U ) + { + xBytesRequiredForAlignment = baALIGNMENT_BYTES - ( xRequestedSizeBytes & baALIGNMENT_MASK ); + + if( baADD_WILL_OVERFLOW( xRequestedSizeBytes, xBytesRequiredForAlignment ) == 0 ) + { + xRequestedSizeBytes += xBytesRequiredForAlignment; + } + else + { + xIntegerOverflowed = pdTRUE; + } + } + + #ifdef PIC32_USE_ETHERNET + ( void ) xAllocatedBytes; + #else + if( baADD_WILL_OVERFLOW( xRequestedSizeBytes, ipBUFFER_PADDING ) == 0 ) + { + xAllocatedBytes = xRequestedSizeBytes + ipBUFFER_PADDING; + } + else + { + xIntegerOverflowed = pdTRUE; + } + #endif /* #ifndef PIC32_USE_ETHERNET */ + + #ifdef PIC32_USE_ETHERNET +} + #endif /* #ifdef PIC32_USE_ETHERNET */ + + /* If there is a semaphore available, there is a network buffer available. */ + if( ( xIntegerOverflowed == pdFALSE ) && ( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS ) ) + { + /* Protect the structure as it is accessed from tasks and interrupts. */ + taskENTER_CRITICAL(); + { + pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList ); + uxListRemove( &( pxReturn->xBufferListItem ) ); + } + taskEXIT_CRITICAL(); + + /* Reading UBaseType_t, no critical section needed. */ + uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList ); + + if( uxMinimumFreeNetworkBuffers > uxCount ) + { + uxMinimumFreeNetworkBuffers = uxCount; + } + + /* Allocate storage of exactly the requested size to the buffer. */ + configASSERT( pxReturn->pucEthernetBuffer == NULL ); + + if( xRequestedSizeBytes > 0 ) + { + /* Extra space is obtained so a pointer to the network buffer can + * be stored at the beginning of the buffer. */ + + #ifdef PIC32_USE_ETHERNET + pxReturn->pucEthernetBuffer = NetworkBufferAllocate( xRequestedSizeBytes - sizeof( TCPIP_MAC_ETHERNET_HEADER ) ); + #else + pxReturn->pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xAllocatedBytes ); + #endif /* #ifdef PIC32_USE_ETHERNET */ + + if( pxReturn->pucEthernetBuffer == NULL ) + { + /* The attempt to allocate storage for the buffer payload failed, + * so the network buffer structure cannot be used and must be + * released. */ + vReleaseNetworkBufferAndDescriptor( pxReturn ); + pxReturn = NULL; + } + else + { + /* Store a pointer to the network buffer structure in the + * buffer storage area, then move the buffer pointer on past the + * stored pointer so the pointer value is not overwritten by the + * application when the buffer is used. */ + #ifdef PIC32_USE_ETHERNET + *( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer - ipBUFFER_PADDING ) ) = pxReturn; + #else + *( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer ) ) = pxReturn; + pxReturn->pucEthernetBuffer += ipBUFFER_PADDING; + #endif /* #ifdef PIC32_USE_ETHERNET */ + + /* Store the actual size of the allocated buffer, which may be + * greater than the original requested size. */ + pxReturn->xDataLength = xRequestedSizeBytes; + + #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + { + /* make sure the buffer is not linked */ + pxReturn->pxNextBuffer = NULL; + } + #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ + } + } + else + { + /* A descriptor is being returned without an associated buffer being + * allocated. */ + } + } + + if( pxReturn == NULL ) + { + iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER(); + } + else + { + iptraceNETWORK_BUFFER_OBTAINED( pxReturn ); + } + + return pxReturn; +} +/*-----------------------------------------------------------*/ + +void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ + BaseType_t xListItemAlreadyInFreeList; + + /* Ensure the buffer is returned to the list of free buffers before the + * counting semaphore is 'given' to say a buffer is available. Release the + * storage allocated to the buffer payload. THIS FILE SHOULD NOT BE USED + * IF THE PROJECT INCLUDES A MEMORY ALLOCATOR THAT WILL FRAGMENT THE HEAP + * MEMORY. For example, heap_2 must not be used, heap_4 can be used. */ + vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer ); + pxNetworkBuffer->pucEthernetBuffer = NULL; + + taskENTER_CRITICAL(); + { + xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); + + if( xListItemAlreadyInFreeList == pdFALSE ) + { + vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); + } + } + taskEXIT_CRITICAL(); + + /* + * Update the network state machine, unless the program fails to release its 'xNetworkBufferSemaphore'. + * The program should only try to release its semaphore if 'xListItemAlreadyInFreeList' is false. + */ + if( xListItemAlreadyInFreeList == pdFALSE ) + { + if( xSemaphoreGive( xNetworkBufferSemaphore ) == pdTRUE ) + { + iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); + } + } + else + { + iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); + } +} +/*-----------------------------------------------------------*/ + +/* + * Returns the number of free network buffers + */ +UBaseType_t uxGetNumberOfFreeNetworkBuffers( void ) +{ + return listCURRENT_LIST_LENGTH( &xFreeBuffersList ); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxGetMinimumFreeNetworkBuffers( void ) +{ + return uxMinimumFreeNetworkBuffers; +} +/*-----------------------------------------------------------*/ + +NetworkBufferDescriptor_t * pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, + size_t xNewSizeBytes ) +{ + size_t xOriginalLength; + uint8_t * pucBuffer = NULL; + BaseType_t xIntegerOverflowed = pdFALSE; + + #ifdef PIC32_USE_ETHERNET + xOriginalLength = pxNetworkBuffer->xDataLength; + #else + xOriginalLength = pxNetworkBuffer->xDataLength + ipBUFFER_PADDING; + + if( baADD_WILL_OVERFLOW( xNewSizeBytes, ipBUFFER_PADDING ) == 0 ) + { + xNewSizeBytes = xNewSizeBytes + ipBUFFER_PADDING; + } + else + { + xIntegerOverflowed = pdTRUE; + } + #endif /* #ifdef PIC32_USE_ETHERNET */ + + if( xIntegerOverflowed == pdFALSE ) + { + pucBuffer = pucGetNetworkBuffer( &( xNewSizeBytes ) ); + } + + if( pucBuffer == NULL ) + { + /* In case the allocation fails, return NULL. */ + pxNetworkBuffer = NULL; + } + else + { + pxNetworkBuffer->xDataLength = xNewSizeBytes; + + if( xNewSizeBytes > xOriginalLength ) + { + xNewSizeBytes = xOriginalLength; + } + + #ifdef PIC32_USE_ETHERNET + memcpy( pucBuffer, pxNetworkBuffer->pucEthernetBuffer, xNewSizeBytes ); + *( ( NetworkBufferDescriptor_t ** ) ( pucBuffer - ipBUFFER_PADDING ) ) = pxNetworkBuffer; + #else + memcpy( pucBuffer - ipBUFFER_PADDING, pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING, xNewSizeBytes ); + #endif /* #ifdef PIC32_USE_ETHERNET */ + + vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer ); + pxNetworkBuffer->pucEthernetBuffer = pucBuffer; + } + + return pxNetworkBuffer; +} diff --git a/source/portable/NetworkInterface/pic32mx/CMakeLists.txt b/source/portable/NetworkInterface/pic32mx/CMakeLists.txt new file mode 100644 index 000000000..3e133a47c --- /dev/null +++ b/source/portable/NetworkInterface/pic32mx/CMakeLists.txt @@ -0,0 +1,20 @@ +if (NOT (FREERTOS_PLUS_TCP_NETWORK_IF STREQUAL "PIC32MX_ETH")) + return() +endif() + +#------------------------------------------------------------------------------ +add_library( freertos_plus_tcp_network_if STATIC ) + +target_sources( freertos_plus_tcp_network_if + PRIVATE + NetworkInterface_eth.c +) + +target_link_libraries( freertos_plus_tcp_network_if + PUBLIC + freertos_plus_tcp_port + freertos_plus_tcp_network_if_common + PRIVATE + freertos_kernel + freertos_plus_tcp +) diff --git a/source/portable/NetworkInterface/pic32mx/NetworkInterface_eth.c b/source/portable/NetworkInterface/pic32mx/NetworkInterface_eth.c new file mode 100644 index 000000000..b7ebdfd58 --- /dev/null +++ b/source/portable/NetworkInterface/pic32mx/NetworkInterface_eth.c @@ -0,0 +1,763 @@ +/* + * FreeRTOS+TCP + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * 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 "peripheral/eth/plib_eth.h" +#include "system_config.h" +#include "system/console/sys_console.h" +#include "system/debug/sys_debug.h" +#include "system/command/sys_command.h" +#include "driver/ethmac/drv_ethmac.h" +#include "driver/miim/drv_miim.h" +#include "tcpip/tcpip.h" +#include "tcpip/src/tcpip_private.h" +#include "tcpip/src/link_list.h" + +#ifdef PIC32_USE_ETHERNET + +/* local definitions and data */ + +/* debug messages */ +#if (PIC32_MAC_DEBUG_MESSAGES != 0) +#define PIC32_MAC_DbgPrint(format, ...) SYS_CONSOLE_PRINT(format, ##__VA_ARGS__) +#else +#define PIC32_MAC_DbgPrint(format, ...) +#endif /* (PIC32_MAC_DEBUG_MESSAGES != 0) */ + +typedef enum +{ + PIC32_MAC_EVENT_INIT_NONE = 0x000, /* no event/invalid */ + PIC32_MAC_EVENT_INIT_DONE = 0x001, /* initialization done event */ + PIC32_MAC_EVENT_TIMEOUT = 0x002, /* periodic timeout event */ + PIC32_MAC_EVENT_IF_PENDING = 0x004, /* an interface event signal: RX, TX, errors. etc. */ +} PIC32_MAC_EVENT_TYPE; + +typedef enum +{ + eMACInit, /* Must initialise MAC. */ + eMACPass, /* Initialisation was successful. */ + eMACFailed, /* Initialisation failed. */ +} eMAC_INIT_STATUS_TYPE; + +static TCPIP_STACK_HEAP_HANDLE macHeapHandle; +static const TCPIP_MAC_OBJECT *macObject; /* the one and only MAC object; */ +static SYS_MODULE_OBJ macObjHandle; /* the MAC object instance, obtained at initialization */ +static TCPIP_MAC_HANDLE macCliHandle; /* client handle */ +static volatile SYS_STATUS macObjStatus; /* current MAC status */ +static TaskHandle_t macTaskHandle; +static TimerHandle_t macTmrHandle; +static bool macLinkStatus; /* true if link is ON */ +static eMAC_INIT_STATUS_TYPE xMacInitStatus = eMACInit; + +/* local prototypes */ +static bool StartInitMac(NetworkInterface_t *pxInterface); +static void StartInitCleanup(void); +static void SetMacCtrl(TCPIP_MAC_MODULE_CTRL *pMacCtrl); +static bool MacSyncFunction(void *synchHandle, TCPIP_MAC_SYNCH_REQUEST req); +static void MacHandlerTask(void *params); +static void MAC_EventFunction(TCPIP_MAC_EVENT event, const void *eventParam); +static void MacTmrCallback(TimerHandle_t xTimer); +static void MacRxPackets(void); +static void MacProcessRxPacket(TCPIP_MAC_PACKET *pRxPkt); + +static NetworkInterface_t *pxMyInterface; +static BaseType_t xPIC32_Eth_NetworkInterfaceInitialise(NetworkInterface_t *pxInterface); +static BaseType_t xPIC32_Eth_NetworkInterfaceOutput(NetworkInterface_t *pxInterface, NetworkBufferDescriptor_t *const pxDescriptor, BaseType_t xReleaseAfterSend); +static BaseType_t xPIC32_Eth_GetPhyLinkStatus(NetworkInterface_t *pxInterface); + +NetworkInterface_t *pxPIC32_Eth_FillInterfaceDescriptor(BaseType_t xEMACIndex, NetworkInterface_t *pxInterface); + +/* memory allocation mapping to FreeRTOS */ +static void *_malloc(size_t nBytes) +{ + return pvPortMalloc(nBytes); +} + +static void *_calloc(size_t nElems, size_t elemSize) +{ + size_t nBytes = nElems * elemSize; + void *ptr = pvPortMalloc(nBytes); + + if (ptr != 0) + { + memset(ptr, 0, nBytes); + } + + return ptr; +} + +static void _free(void *pBuff) +{ + vPortFree(pBuff); +} + +/* extern references */ +extern const TCPIP_NETWORK_CONFIG TCPIP_HOSTS_CONFIGURATION[]; +extern TCPIP_MAC_PACKET *PIC32_MacPacketAllocate(uint16_t pktLen, uint16_t segLoadLen, TCPIP_MAC_PACKET_FLAGS flags); +extern void PIC32_MacAssociate(TCPIP_MAC_PACKET *pRxPkt, NetworkBufferDescriptor_t *pxBufferDescriptor, size_t pktLength); +extern void PIC32_MacPacketOrphan(TCPIP_MAC_PACKET *pPkt); + +static const TCPIP_STACK_HEAP_EXTERNAL_CONFIG tcpipHeapConfig = +{ + .heapType = TCPIP_STACK_HEAP_TYPE_EXTERNAL_HEAP, + .heapFlags = TCPIP_STACK_HEAP_FLAG_ALLOC_UNCACHED | TCPIP_STACK_HEAP_FLAG_NO_MTHREAD_SYNC, + .heapUsage = TCPIP_STACK_HEAP_USE_DEFAULT, + .malloc_fnc = _malloc, + .calloc_fnc = _calloc, + .free_fnc = _free, +}; + +#if (PIC32_MAC_DEBUG_COMMANDS != 0) +static int _Command_MacInfo(SYS_CMD_DEVICE_NODE *pCmdIO, int argc, char **argv); +static int _Command_NetInfo(SYS_CMD_DEVICE_NODE *pCmdIO, int argc, char **argv); +static int _Command_Version(SYS_CMD_DEVICE_NODE *pCmdIO, int argc, char **argv); + +static const SYS_CMD_DESCRIPTOR macCmdTbl[] = +{ + { "macinfo", _Command_MacInfo, ": Check MAC statistics" }, + { "netinfo", _Command_NetInfo, ": Net info" }, + { "version", _Command_Version, ": Version info" }, +}; +#endif /* (PIC32_MAC_DEBUG_COMMANDS != 0) */ + +#if (ipconfigIPv4_BACKWARD_COMPATIBLE != 0) +NetworkInterface_t *pxFillInterfaceDescriptor(BaseType_t xEMACIndex, NetworkInterface_t *pxInterface) +{ + return pxPIC32_Eth_FillInterfaceDescriptor(xEMACIndex, pxInterface); +} +#endif + +NetworkInterface_t *pxPIC32_Eth_FillInterfaceDescriptor(BaseType_t xEMACIndex, NetworkInterface_t *pxInterface) +{ + static char pcName[8]; + + snprintf(pcName, sizeof(pcName), "eth%ld", xEMACIndex); + + memset(pxInterface, '\0', sizeof(*pxInterface)); + pxInterface->pcName = pcName; + pxInterface->pvArgument = (void *)xEMACIndex; + pxInterface->pfInitialise = xPIC32_Eth_NetworkInterfaceInitialise; + pxInterface->pfOutput = xPIC32_Eth_NetworkInterfaceOutput; + pxInterface->pfGetPhyLinkStatus = xPIC32_Eth_GetPhyLinkStatus; + + FreeRTOS_AddNetworkInterface(pxInterface); + pxMyInterface = pxInterface; + + return pxInterface; +} + +static BaseType_t xPIC32_Eth_NetworkInterfaceInitialise(NetworkInterface_t *pxInterface) +{ + BaseType_t xResult; + + if (xMacInitStatus == eMACInit) + { + if (StartInitMac(pxInterface) != false) + { + xMacInitStatus = eMACPass; + } + else + { + xMacInitStatus = eMACFailed; + } + } + + if (xMacInitStatus == eMACPass) + { + xResult = xPIC32_Eth_GetPhyLinkStatus(pxMyInterface); + } + else + { + xResult = pdFAIL; + } + + PIC32_MAC_DbgPrint("xNetworkInterfaceInitialise: %d %d\r\n", (int)xMacInitStatus, (int)xResult); + + return xResult; +} + +static BaseType_t xPIC32_Eth_NetworkInterfaceOutput(NetworkInterface_t *pxInterface, NetworkBufferDescriptor_t *const pxDescriptor, BaseType_t xReleaseAfterSend) +{ + BaseType_t xEMACIndex = (BaseType_t)pxInterface->pvArgument; + TCPIP_MAC_RES macRes; + TCPIP_MAC_PACKET *pTxPkt; + BaseType_t retRes = pdFALSE; + + if ((pxDescriptor != 0) && (pxDescriptor->pucEthernetBuffer != 0) && (pxDescriptor->xDataLength != 0)) + { + TCPIP_MAC_PACKET **ppkt = (TCPIP_MAC_PACKET **)(pxDescriptor->pucEthernetBuffer - PIC32_BUFFER_PKT_PTR_OSSET); + configASSERT(((uint32_t)ppkt & (sizeof(uint32_t) - 1)) == 0); + pTxPkt = *ppkt; + configASSERT(pTxPkt != 0); + + pTxPkt->pDSeg->segLen = pxDescriptor->xDataLength; + pTxPkt->next = 0; + macRes = (macObject->TCPIP_MAC_PacketTx)(macCliHandle, pTxPkt); + + if (macRes >= 0) + { + retRes = pdTRUE; + pxDescriptor->pucEthernetBuffer = 0; + iptraceNETWORK_INTERFACE_TRANSMIT(); + } + + if (xReleaseAfterSend != pdFALSE) + { + vReleaseNetworkBufferAndDescriptor(pxDescriptor); + } + } + + return retRes; +} + +void PIC32_GetMACAddress(uint8_t macAdd[6]) +{ +#if defined(__PIC32MZ__) || defined(__PIC32MX__) + PLIB_ETH_MACGetAddress(ETH_ID_0, macAdd); +#else +#error "MAC Address: not supported architecture!" +#endif +} + +const void *const PIC32_GetMacConfigData(void) +{ +#if defined(__PIC32MZ__) || defined(__PIC32MX__) + extern const TCPIP_MODULE_MAC_PIC32INT_CONFIG tcpipMACPIC32INTInitData; + return &tcpipMACPIC32INTInitData; +#else +#error "MAC Address: not supported architecture!" +#endif +} + +static bool StartInitMac(NetworkInterface_t *pxInterface) +{ + TCPIP_MAC_MODULE_CTRL macCtrl; + SYS_MODULE_INIT moduleInit; + EventBits_t evBits; + NetworkEndPoint_t *pxEndPoint; + + macHeapHandle = 0; + macObjHandle = 0; + macCliHandle = 0; + macTmrHandle = 0; + macTaskHandle = 0; + macObject = TCPIP_HOSTS_CONFIGURATION[0].pMacObject; + macObjStatus = SYS_STATUS_UNINITIALIZED; + macLinkStatus = false; + + int netUpFail = 0; + + while (true) + { + macHeapHandle = TCPIP_HEAP_Create((const TCPIP_STACK_HEAP_CONFIG *)&tcpipHeapConfig, 0); + + if (macHeapHandle == 0) + { + netUpFail = 1; + break; + } + + if (TCPIP_PKT_Initialize(macHeapHandle, 0, 0) == false) + { + netUpFail = 2; + break; + } + + moduleInit.sys.powerState = SYS_MODULE_POWER_RUN_FULL; + SetMacCtrl(&macCtrl); + + for (pxEndPoint = FreeRTOS_FirstEndPoint(pxInterface); pxEndPoint != NULL; pxEndPoint = FreeRTOS_NextEndPoint(pxInterface, pxEndPoint)) + { + memcpy(pxEndPoint->xMACAddress.ucBytes, macCtrl.ifPhyAddress.v, ipMAC_ADDRESS_LENGTH_BYTES); + } + + TCPIP_MAC_INIT macInit = + { + .moduleInit = { moduleInit.value }, + .macControl = &macCtrl, + .moduleData = PIC32_GetMacConfigData(), + }; + + macObjHandle = (macObject->TCPIP_MAC_Initialize)(TCPIP_MODULE_MAC_PIC32INT, &macInit.moduleInit); + + if (macObjHandle == SYS_MODULE_OBJ_INVALID) + { + macObjHandle = 0; + netUpFail = 4; + break; + } + + macCliHandle = (macObject->TCPIP_MAC_Open)(TCPIP_MODULE_MAC_PIC32INT, DRV_IO_INTENT_READWRITE); + + if (macCliHandle == DRV_HANDLE_INVALID) + { + macCliHandle = 0; + netUpFail = 5; + break; + } + + if (!(macObject->TCPIP_MAC_EventMaskSet)(macCliHandle, (TCPIP_MAC_EV_RX_DONE | TCPIP_MAC_EV_TX_DONE | TCPIP_MAC_EV_RXTX_ERRORS), true)) + { + netUpFail = 6; + break; + } + + macTmrHandle = xTimerCreate(PIC32_MAC_TIMER_NAME, PIC32_MAC_TIMER_PERIOD, pdTRUE, 0, MacTmrCallback); + + if ((macTmrHandle == 0) || (xTimerStart(macTmrHandle, 0) != pdPASS)) + { + netUpFail = 8; + break; + } + + macObjStatus = SYS_STATUS_BUSY; + + if (xTaskCreate(MacHandlerTask, PIC32_MAC_TASK_NAME, PIC32_MAC_TASK_STACK_SIZE, xTaskGetCurrentTaskHandle(), PIC32_MAC_TASK_PRI, &macTaskHandle) != pdPASS) + { + netUpFail = 9; + break; + } + + xTaskNotifyWait(PIC32_MAC_EVENT_INIT_DONE, PIC32_MAC_EVENT_INIT_DONE, &evBits, PIC32_MAC_INIT_TIMEOUT); + + if ((evBits & PIC32_MAC_EVENT_INIT_DONE) == 0) + { + netUpFail = 10; + break; + } + + if (macObjStatus != SYS_STATUS_READY) + { + netUpFail = 11; + break; + } + + netUpFail = 0; + break; + } + + if (netUpFail == 0) + { + PIC32_MAC_DbgPrint(" MAC Init success!\r\n"); + +#if (PIC32_MAC_DEBUG_COMMANDS != 0) + if (!SYS_CMD_ADDGRP(macCmdTbl, sizeof(macCmdTbl) / sizeof(*macCmdTbl), "mac", ": mac commands")) + { + PIC32_MAC_DbgPrint("Failed to create MAC Commands\r\n"); + } +#endif /* (PIC32_MAC_DEBUG_COMMANDS != 0) */ + + return true; + } + else + { + StartInitCleanup(); + PIC32_MAC_DbgPrint("MAC Init failed: %d!\r\n", netUpFail); + + return false; + } +} + +static void StartInitCleanup(void) +{ + if (macHeapHandle != 0) + { + TCPIP_HEAP_Delete(macHeapHandle); + macHeapHandle = 0; + } + + if (macObjHandle != 0) + { + (macObject->TCPIP_MAC_Deinitialize)(macObjHandle); + macObjHandle = 0; + } + + if (macTmrHandle != 0) + { + xTimerDelete(macTmrHandle, portMAX_DELAY); + macTmrHandle = 0; + } + + if (macTaskHandle != 0) + { + vTaskDelete(macTaskHandle); + macTaskHandle = 0; + } +} + +static void SetMacCtrl(TCPIP_MAC_MODULE_CTRL *pMacCtrl) +{ + TCPIP_MAC_ADDR macAdd; + uint8_t unsetMACAddr[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + pMacCtrl->nIfs = 1; + pMacCtrl->mallocF = TCPIP_HEAP_MallocOutline; + pMacCtrl->callocF = TCPIP_HEAP_CallocOutline; + pMacCtrl->freeF = TCPIP_HEAP_FreeOutline; + pMacCtrl->memH = macHeapHandle; + pMacCtrl->pktAllocF = PIC32_MacPacketAllocate; + pMacCtrl->pktFreeF = (TCPIP_MAC_PKT_FreeF)_TCPIP_PKT_FREE_FNC; + pMacCtrl->pktAckF = (TCPIP_MAC_PKT_AckF)_TCPIP_PKT_ACK_FNC; + pMacCtrl->synchF = MacSyncFunction; + pMacCtrl->eventF = MAC_EventFunction; + pMacCtrl->eventParam = 0; + pMacCtrl->moduleId = TCPIP_MODULE_MAC_PIC32INT; + pMacCtrl->netIx = 0; + pMacCtrl->macAction = TCPIP_MAC_ACTION_INIT; + pMacCtrl->powerMode = TCPIP_MAC_POWER_FULL; + + macAdd.v[0] = configMAC_ADDR0; + macAdd.v[1] = configMAC_ADDR1; + macAdd.v[2] = configMAC_ADDR2; + macAdd.v[3] = configMAC_ADDR3; + macAdd.v[4] = configMAC_ADDR4; + macAdd.v[5] = configMAC_ADDR5; + + if (memcmp(macAdd.v, unsetMACAddr, sizeof(unsetMACAddr)) == 0) + { + PIC32_GetMACAddress(pMacCtrl->ifPhyAddress.v); + } + else + { + memcpy(pMacCtrl->ifPhyAddress.v, macAdd.v, sizeof(macAdd)); + } +} + +static bool MacSyncFunction(void *synchHandle, TCPIP_MAC_SYNCH_REQUEST req) +{ + switch (req) + { + case TCPIP_MAC_SYNCH_REQUEST_OBJ_CREATE: + vSemaphoreCreateBinary(*(SemaphoreHandle_t *)synchHandle); + return (*(SemaphoreHandle_t *)synchHandle == NULL) ? false : true; + + case TCPIP_MAC_SYNCH_REQUEST_OBJ_DELETE: + vSemaphoreDelete(*(SemaphoreHandle_t *)synchHandle); + *(SemaphoreHandle_t *)synchHandle = NULL; + return true; + + case TCPIP_MAC_SYNCH_REQUEST_OBJ_LOCK: + return (xSemaphoreTake(*(SemaphoreHandle_t *)synchHandle, portMAX_DELAY) == pdTRUE) ? true : false; + + case TCPIP_MAC_SYNCH_REQUEST_OBJ_UNLOCK: + return (xSemaphoreGive(*(SemaphoreHandle_t *)synchHandle) == pdTRUE) ? true : false; + + case TCPIP_MAC_SYNCH_REQUEST_CRIT_ENTER: + vTaskSuspendAll(); + return true; + + case TCPIP_MAC_SYNCH_REQUEST_CRIT_LEAVE: + xTaskResumeAll(); + return true; + + default: + return false; + } +} + +static void MacHandlerTask(void *params) +{ + EventBits_t evBits; + + while (macObjStatus == SYS_STATUS_BUSY) + { + (macObject->TCPIP_MAC_Tasks)(macObjHandle); + SYS_STATUS macStatus = (macObject->TCPIP_MAC_Status)(macObjHandle); + + if (macStatus == SYS_STATUS_BUSY) + { + vTaskDelay(PIC32_MAC_TASK_INIT_PENDING_DELAY); + } + else + { + macObjStatus = macStatus; + xTaskNotify((TaskHandle_t)params, PIC32_MAC_EVENT_INIT_DONE, eSetBits); + + if (macStatus != SYS_STATUS_READY) + { + vTaskDelete(0); + } + } + } + + while (true) + { + xTaskNotifyWait(PIC32_MAC_EVENT_TIMEOUT | PIC32_MAC_EVENT_IF_PENDING, PIC32_MAC_EVENT_TIMEOUT | PIC32_MAC_EVENT_IF_PENDING, &evBits, portMAX_DELAY); + + if ((evBits & PIC32_MAC_EVENT_TIMEOUT) != 0) + { + (macObject->TCPIP_MAC_Tasks)(macObjHandle); + bool linkCurr = (macObject->TCPIP_MAC_LinkCheck)(macCliHandle); + + if (macLinkStatus != linkCurr) + { + PIC32_MAC_DbgPrint(" MAC link: %s!\r\n", linkCurr ? "ON" : "OFF"); + macLinkStatus = linkCurr; + } + } + + if ((evBits & PIC32_MAC_EVENT_IF_PENDING) != 0) + { + TCPIP_MAC_EVENT activeEvents = (macObject->TCPIP_MAC_EventPendingGet)(macCliHandle); + + if (activeEvents != TCPIP_MAC_EV_NONE) + { + (macObject->TCPIP_MAC_EventAcknowledge)(macCliHandle, activeEvents); + + if ((activeEvents & (TCPIP_MAC_EV_RX_DONE | TCPIP_MAC_EV_RX_OVFLOW | TCPIP_MAC_EV_RX_BUFNA)) != 0) + { + MacRxPackets(); + } + + (macObject->TCPIP_MAC_Process)(macCliHandle); + } + } + } +} + +static void MacTmrCallback(TimerHandle_t xTimer) +{ + xTaskNotify(macTaskHandle, PIC32_MAC_EVENT_TIMEOUT, eSetBits); +} + +static void MAC_EventFunction(TCPIP_MAC_EVENT event, const void *eventParam) +{ + BaseType_t xHigherPriorityTaskWoken; + + if ((event & (TCPIP_MAC_EV_RX_DONE | TCPIP_MAC_EV_TX_DONE | TCPIP_MAC_EV_RXTX_ERRORS)) != 0) + { + xHigherPriorityTaskWoken = pdFALSE; + xTaskNotifyFromISR(macTaskHandle, PIC32_MAC_EVENT_IF_PENDING, eSetBits, &xHigherPriorityTaskWoken); + + if (xHigherPriorityTaskWoken) + { + portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); + } + } +} + +static BaseType_t xPIC32_Eth_GetPhyLinkStatus(NetworkInterface_t *pxInterface) +{ + return (macLinkStatus == true) ? pdPASS : pdFAIL; +} + +static void MacRxPackets(void) +{ + TCPIP_MAC_PACKET *pRxPkt; + + while ((pRxPkt = (macObject->TCPIP_MAC_PacketRx)(macCliHandle, 0, 0)) != 0) + { + MacProcessRxPacket(pRxPkt); + } +} + +static void MacProcessRxPacket(TCPIP_MAC_PACKET *pRxPkt) +{ + bool pktSuccess, pktLost; + size_t pktLength; + TCPIP_MAC_DATA_SEGMENT *pSeg; + uint8_t *pPktBuff; + NetworkBufferDescriptor_t *pxBufferDescriptor; + IPStackEvent_t xRxEvent; + + pxBufferDescriptor = 0; + pktSuccess = pktLost = false; + + while (true) + { + pktLength = 0; + int nSegs = 0; + pSeg = pRxPkt->pDSeg; + pPktBuff = pSeg->segLoad; + + do + { + pktLength += pSeg->segLen; + pSeg = pSeg->next; + nSegs++; + } while (pSeg != 0); + + if (nSegs > 1) + { + break; + } + + pktLength += sizeof(TCPIP_MAC_ETHERNET_HEADER); + + if (eConsiderFrameForProcessing(pPktBuff) != eProcessBuffer) + { + break; + } + + pxBufferDescriptor = pxGetNetworkBufferWithDescriptor(0, 0); + + if (pxBufferDescriptor == 0) + { + pktLost = true; + break; + } + + PIC32_MacAssociate(pRxPkt, pxBufferDescriptor, pktLength); + pxBufferDescriptor->pxInterface = pxMyInterface; + pxBufferDescriptor->pxEndPoint = FreeRTOS_MatchingEndpoint(pxMyInterface, pxBufferDescriptor->pucEthernetBuffer); + + xRxEvent.eEventType = eNetworkRxEvent; + xRxEvent.pvData = (void *)pxBufferDescriptor; + + if (xSendEventStructToIPTask(&xRxEvent, 0) == pdFALSE) + { + pktLost = true; + } + else + { + pktSuccess = true; + iptraceNETWORK_INTERFACE_RECEIVE(); + } + + break; + } + + if (!pktSuccess) + { + if (pxBufferDescriptor != 0) + { + pxBufferDescriptor->pucEthernetBuffer = 0; + vReleaseNetworkBufferAndDescriptor(pxBufferDescriptor); + } + + if (pktLost) + { + iptraceETHERNET_RX_EVENT_LOST(); + } + + if (pRxPkt->ackFunc) + { + (*pRxPkt->ackFunc)(pRxPkt, pRxPkt->ackParam); + } + else + { + PIC32_MacPacketOrphan(pRxPkt); + } + } +} + +#if (PIC32_MAC_DEBUG_COMMANDS != 0) +static int _Command_MacInfo(SYS_CMD_DEVICE_NODE *pCmdIO, int argc, char **argv) +{ + TCPIP_MAC_RES macRes; + TCPIP_MAC_RX_STATISTICS rxStatistics; + TCPIP_MAC_TX_STATISTICS txStatistics; + TCPIP_MAC_STATISTICS_REG_ENTRY regEntries[8]; + TCPIP_MAC_STATISTICS_REG_ENTRY *pRegEntry; + int jx, hwEntries; + char entryName[sizeof(pRegEntry->registerName) + 1]; + const void *cmdIoParam = pCmdIO->cmdIoParam; + + if (argc != 1) + { + (*pCmdIO->pCmdApi->msg)(cmdIoParam, "Usage: macinfo \r\n"); + (*pCmdIO->pCmdApi->msg)(cmdIoParam, "Ex: macinfo \r\n"); + return false; + } + + (*pCmdIO->pCmdApi->print)(cmdIoParam, "Interface: %s driver statistics\r\n", macObject->macName); + macRes = (macObject->TCPIP_MAC_StatisticsGet)(macCliHandle, &rxStatistics, &txStatistics); + + if (macRes == TCPIP_MAC_RES_OK) + { + (*pCmdIO->pCmdApi->print)(cmdIoParam, "\tnRxOkPackets: %d, nRxPendBuffers: %d, nRxSchedBuffers: %d, ", rxStatistics.nRxOkPackets, rxStatistics.nRxPendBuffers, rxStatistics.nRxSchedBuffers); + (*pCmdIO->pCmdApi->print)(cmdIoParam, "nRxErrorPackets: %d, nRxFragmentErrors: %d\r\n", rxStatistics.nRxErrorPackets, rxStatistics.nRxFragmentErrors); + (*pCmdIO->pCmdApi->print)(cmdIoParam, "\tnTxOkPackets: %d, nTxPendBuffers: %d, nTxErrorPackets: %d, nTxQueueFull: %d\r\n", txStatistics.nTxOkPackets, txStatistics.nTxPendBuffers, txStatistics.nTxErrorPackets, txStatistics.nTxQueueFull); + } + else + { + (*pCmdIO->pCmdApi->msg)(cmdIoParam, "\tnot supported\r\n"); + } + + (*pCmdIO->pCmdApi->print)(cmdIoParam, "Interface: %s hardware statistics\r\n", macObject->macName); + macRes = (macObject->TCPIP_MAC_RegisterStatisticsGet)(macCliHandle, regEntries, sizeof(regEntries) / sizeof(*regEntries), &hwEntries); + + if (macRes == TCPIP_MAC_RES_OK) + { + entryName[sizeof(entryName) - 1] = 0; + + for (jx = 0, pRegEntry = regEntries; jx < hwEntries && jx < sizeof(regEntries) / sizeof(*regEntries); jx++, pRegEntry++) + { + strncpy(entryName, pRegEntry->registerName, sizeof(entryName) - 1); + (*pCmdIO->pCmdApi->print)(cmdIoParam, "\t%s: 0x%8x\r\n", entryName, pRegEntry->registerValue); + } + } + else + { + (*pCmdIO->pCmdApi->msg)(cmdIoParam, "\tnot supported\r\n"); + } + + return true; +} + +static int _Command_NetInfo(SYS_CMD_DEVICE_NODE *pCmdIO, int argc, char **argv) +{ + const void *cmdIoParam = pCmdIO->cmdIoParam; + + union + { + uint32_t ul; + uint8_t b[4]; + } sUl; + + sUl.ul = FreeRTOS_GetIPAddress(); + bool linkUp = FreeRTOS_IsNetworkUp() == pdTRUE; + + (*pCmdIO->pCmdApi->print)(cmdIoParam, "IP address: %d.%d.%d.%d\r\n", sUl.b[0], sUl.b[1], sUl.b[2], sUl.b[3]); + (*pCmdIO->pCmdApi->print)(cmdIoParam, "Link is: %s\r\n", linkUp ? "Up" : "Down"); + + return true; +} + +#include "aws_application_version.h" + +static int _Command_Version(SYS_CMD_DEVICE_NODE *pCmdIO, int argc, char **argv) +{ + configPRINTF(("App version - maj: %d, min: %d, build: %d\r\n", xAppFirmwareVersion.u.x.ucMajor, xAppFirmwareVersion.u.x.ucMinor, xAppFirmwareVersion.u.x.usBuild)); + return 0; +} +#endif /* (PIC32_MAC_DEBUG_COMMANDS != 0) */ + +#endif /* #ifdef PIC32_USE_ETHERNET */