From: yuhzheng Date: Fri, 31 Jan 2020 00:07:53 +0000 (+0000) Subject: Sync FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP with the version in GitHub at (23665258ca... X-Git-Tag: V10.3.0~9 X-Git-Url: https://git.sur5r.net/?p=freertos;a=commitdiff_plain;h=e9388d7834fdede42a6cf93794dab4f3a302fcde Sync FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP with the version in GitHub at (23665258cabe49d5d68ba23968b6845a7c80eb34). Notes: - header has version 2.2.0. - This sync did not bring in ./test directory, though we should. - New NetworkInterfaces are introduced by this merge. - Keil compiler support. - FreeRTOS_IP.h new API xApplicationGetRandomNumber(). - FreeRTOS_IP_Private.h new eIPEvent_t eNetworkTxEvent. - FreeRTOS_Stream_Buffer.h removing static xStreamBufferIsEmpty() and xStreamBufferIsFull(). - FreeRTOSConfigDefaults.h provides default ipconfigDNS_RECEIVE_BLOCK_TIME_TICKS. - other type changes. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2814 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c index ed34d9aac..c98a7e870 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -580,8 +580,24 @@ NetworkBufferDescriptor_t *pxNetworkBuffer; } } #endif + if( xIsCallingFromIPTask() != 0 ) + { + /* Only the IP-task is allowed to call this function directly. */ + xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE ); + } + else + { + IPStackEvent_t xSendEvent; - xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE ); + /* Send a message to the IP-task to send this ARP packet. */ + xSendEvent.eEventType = eNetworkTxEvent; + xSendEvent.pvData = ( void * ) pxNetworkBuffer; + if( xSendEventStructToIPTask( &xSendEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL ) + { + /* Failed to send the message, so release the network buffer. */ + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + } } } @@ -589,6 +605,12 @@ void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffe { ARPPacket_t *pxARPPacket; + /* Buffer allocation ensures that buffers always have space + for an ARP packet. See buffer allocation implementations 1 + and 2 under portable/BufferManagement. */ + configASSERT( pxNetworkBuffer ); + configASSERT( pxNetworkBuffer->xDataLength >= sizeof(ARPPacket_t) ); + pxARPPacket = ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer; /* memcpy the const part of the header information into the correct diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c index 78efbf7be..9180426df 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -84,9 +84,9 @@ /* Offsets into the transmitted DHCP options fields at which various parameters are located. */ -#define dhcpCLIENT_IDENTIFIER_OFFSET ( 5 ) -#define dhcpREQUESTED_IP_ADDRESS_OFFSET ( 13 ) -#define dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ( 19 ) +#define dhcpCLIENT_IDENTIFIER_OFFSET ( 6 ) +#define dhcpREQUESTED_IP_ADDRESS_OFFSET ( 14 ) +#define dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ( 20 ) /* Values used in the DHCP packets. */ #define dhcpREQUEST_OPCODE ( 1 ) @@ -354,9 +354,7 @@ BaseType_t xGivingUp = pdFALSE; if( xDHCPData.xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD ) { - xDHCPData.ulTransactionId = ipconfigRAND32( ); - - if( 0 != xDHCPData.ulTransactionId ) + if( xApplicationGetRandomNumber( &( xDHCPData.ulTransactionId ) ) != pdFALSE ) { xDHCPData.xDHCPTxTime = xTaskGetTickCount( ); xDHCPData.xUseBroadcast = !xDHCPData.xUseBroadcast; @@ -589,10 +587,9 @@ static void prvInitialiseDHCP( void ) /* Initialise the parameters that will be set by the DHCP process. Per https://www.ietf.org/rfc/rfc2131.txt, Transaction ID should be a random value chosen by the client. */ - xDHCPData.ulTransactionId = ipconfigRAND32(); /* Check for random number generator API failure. */ - if( 0 != xDHCPData.ulTransactionId ) + if( xApplicationGetRandomNumber( &( xDHCPData.ulTransactionId ) ) != pdFALSE ) { xDHCPData.xUseBroadcast = 0; xDHCPData.ulOfferedIPAddress = 0UL; @@ -604,6 +601,10 @@ static void prvInitialiseDHCP( void ) FreeRTOS_debug_printf( ( "prvInitialiseDHCP: start after %lu ticks\n", dhcpINITIAL_TIMER_PERIOD ) ); vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD ); } + else + { + /* There was a problem with the randomiser. */ + } } /*-----------------------------------------------------------*/ @@ -642,8 +643,8 @@ const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct /* Walk through the options until the dhcpOPTION_END_BYTE byte is found, taking care not to walk off the end of the options. */ pucByte = &( pxDHCPMessage->ucFirstOptionByte ); - /* Maintain a pointer to the last valid byte (i.e. not the first - invalid byte). */ + /* Maintain a pointer to the last valid byte (i.e. not the first + invalid byte). */ pucLastByte = pucUDPPayload + lBytes - 1; while( pucByte <= pucLastByte ) @@ -665,7 +666,7 @@ const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct /* Stop if the response is malformed. */ if( pucByte < pucLastByte ) { - /* There are at least two bytes left. */ + /* There are at least two bytes left. */ ucLength = pucByte[ 1 ]; pucByte += 2; @@ -904,7 +905,7 @@ static const uint8_t ucDHCPRequestOptions[] = dhcpCLIENT_IDENTIFIER_OFFSET, dhcpREQUESTED_IP_ADDRESS_OFFSET and dhcpDHCP_SERVER_IP_ADDRESS_OFFSET. */ dhcpMESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_REQUEST, /* Message type option. */ - dhcpCLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0, /* Client identifier. */ + dhcpCLIENT_IDENTIFIER_OPTION_CODE, 7, 1, 0, 0, 0, 0, 0, 0, /* Client identifier. */ dhcpREQUEST_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address being requested. */ dhcpSERVER_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address of the DHCP server. */ dhcpOPTION_END_BYTE @@ -942,7 +943,7 @@ static const uint8_t ucDHCPDiscoverOptions[] = { /* Do not change the ordering without also changing dhcpCLIENT_IDENTIFIER_OFFSET. */ dhcpMESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_DISCOVER, /* Message type option. */ - dhcpCLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0, /* Client identifier. */ + dhcpCLIENT_IDENTIFIER_OPTION_CODE, 7, 1, 0, 0, 0, 0, 0, 0, /* Client identifier. */ dhcpPARAMETER_REQUEST_OPTION_CODE, 3, dhcpSUBNET_MASK_OPTION_CODE, dhcpGATEWAY_OPTION_CODE, dhcpDNS_SERVER_OPTIONS_CODE, /* Parameter request option. */ dhcpOPTION_END_BYTE }; @@ -968,13 +969,16 @@ size_t xOptionsLength = sizeof( ucDHCPDiscoverOptions ); static void prvPrepareLinkLayerIPLookUp( void ) { uint8_t ucLinkLayerIPAddress[ 2 ]; + uint32_t ulNumbers[ 2 ]; /* After DHCP has failed to answer, prepare everything to start trying-out LinkLayer IP-addresses, using the random method. */ xDHCPData.xDHCPTxTime = xTaskGetTickCount(); - ucLinkLayerIPAddress[ 0 ] = ( uint8_t )1 + ( uint8_t )( ipconfigRAND32() % 0xFDu ); /* get value 1..254 for IP-address 3rd byte of IP address to try. */ - ucLinkLayerIPAddress[ 1 ] = ( uint8_t )1 + ( uint8_t )( ipconfigRAND32() % 0xFDu ); /* get value 1..254 for IP-address 4th byte of IP address to try. */ + xApplicationGetRandomNumber( &( ulNumbers[ 0 ] ) ); + xApplicationGetRandomNumber( &( ulNumbers[ 1 ] ) ); + ucLinkLayerIPAddress[ 0 ] = ( uint8_t )1 + ( uint8_t )( ulNumbers[ 0 ] % 0xFDu ); /* get value 1..254 for IP-address 3rd byte of IP address to try. */ + ucLinkLayerIPAddress[ 1 ] = ( uint8_t )1 + ( uint8_t )( ulNumbers[ 1 ] % 0xFDu ); /* get value 1..254 for IP-address 4th byte of IP address to try. */ xNetworkAddressing.ulGatewayAddress = FreeRTOS_htonl( 0xA9FE0203 ); @@ -995,9 +999,15 @@ size_t xOptionsLength = sizeof( ucDHCPDiscoverOptions ); xNetworkAddressing.ulBroadcastAddress = ( xDHCPData.ulOfferedIPAddress & xNetworkAddressing.ulNetMask ) | ~xNetworkAddressing.ulNetMask; /* Close socket to ensure packets don't queue on it. not needed anymore as DHCP failed. but still need timer for ARP testing. */ - vSocketClose( xDHCPData.xDHCPSocket ); - xDHCPData.xDHCPSocket = NULL; - xDHCPData.xDHCPTxPeriod = pdMS_TO_TICKS( 3000ul + ( ipconfigRAND32() & 0x3fful ) ); /* do ARP test every (3 + 0-1024mS) seconds. */ + if( xDHCPData.xDHCPSocket != NULL ) + { + /* Close socket to ensure packets don't queue on it. */ + vSocketClose( xDHCPData.xDHCPSocket ); + xDHCPData.xDHCPSocket = NULL; + } + + xApplicationGetRandomNumber( &( ulNumbers[ 0 ] ) ); + xDHCPData.xDHCPTxPeriod = pdMS_TO_TICKS( 3000ul + ( ulNumbers[ 0 ] & 0x3ffuL ) ); /* do ARP test every (3 + 0-1024mS) seconds. */ xARPHadIPClash = pdFALSE; /* reset flag that shows if have ARP clash. */ vARPSendGratuitous(); diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c index 465bdd3f1..43b246d26 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -47,58 +47,58 @@ #if( ipconfigUSE_DNS != 0 ) #if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) - #define dnsDNS_PORT 0x3500 - #define dnsONE_QUESTION 0x0100 - #define dnsOUTGOING_FLAGS 0x0001 /* Standard query. */ - #define dnsRX_FLAGS_MASK 0x0f80 /* The bits of interest in the flags field of incoming DNS messages. */ - #define dnsEXPECTED_RX_FLAGS 0x0080 /* Should be a response, without any errors. */ + #define dnsDNS_PORT 0x3500u + #define dnsONE_QUESTION 0x0100u + #define dnsOUTGOING_FLAGS 0x0001u /* Standard query. */ + #define dnsRX_FLAGS_MASK 0x0f80u /* The bits of interest in the flags field of incoming DNS messages. */ + #define dnsEXPECTED_RX_FLAGS 0x0080u /* Should be a response, without any errors. */ #else - #define dnsDNS_PORT 0x0035 - #define dnsONE_QUESTION 0x0001 - #define dnsOUTGOING_FLAGS 0x0100 /* Standard query. */ - #define dnsRX_FLAGS_MASK 0x800f /* The bits of interest in the flags field of incoming DNS messages. */ - #define dnsEXPECTED_RX_FLAGS 0x8000 /* Should be a response, without any errors. */ + #define dnsDNS_PORT 0x0035u + #define dnsONE_QUESTION 0x0001u + #define dnsOUTGOING_FLAGS 0x0100u /* Standard query. */ + #define dnsRX_FLAGS_MASK 0x800fu /* The bits of interest in the flags field of incoming DNS messages. */ + #define dnsEXPECTED_RX_FLAGS 0x8000u /* Should be a response, without any errors. */ #endif /* ipconfigBYTE_ORDER */ /* The maximum number of times a DNS request should be sent out if a response is not received, before giving up. */ #ifndef ipconfigDNS_REQUEST_ATTEMPTS - #define ipconfigDNS_REQUEST_ATTEMPTS 5 + #define ipconfigDNS_REQUEST_ATTEMPTS 5 #endif /* If the top two bits in the first character of a name field are set then the name field is an offset to the string, rather than the string itself. */ -#define dnsNAME_IS_OFFSET ( ( uint8_t ) 0xc0 ) +#define dnsNAME_IS_OFFSET ( ( uint8_t ) 0xc0 ) /* NBNS flags. */ -#define dnsNBNS_FLAGS_RESPONSE 0x8000 -#define dnsNBNS_FLAGS_OPCODE_MASK 0x7800 -#define dnsNBNS_FLAGS_OPCODE_QUERY 0x0000 -#define dnsNBNS_FLAGS_OPCODE_REGISTRATION 0x2800 +#define dnsNBNS_FLAGS_RESPONSE 0x8000u +#define dnsNBNS_FLAGS_OPCODE_MASK 0x7800u +#define dnsNBNS_FLAGS_OPCODE_QUERY 0x0000u +#define dnsNBNS_FLAGS_OPCODE_REGISTRATION 0x2800u /* Host types. */ -#define dnsTYPE_A_HOST 0x01 -#define dnsCLASS_IN 0x01 +#define dnsTYPE_A_HOST 0x01u +#define dnsCLASS_IN 0x01u /* LLMNR constants. */ -#define dnsLLMNR_TTL_VALUE 300000 -#define dnsLLMNR_FLAGS_IS_REPONSE 0x8000 +#define dnsLLMNR_TTL_VALUE 300000uL +#define dnsLLMNR_FLAGS_IS_REPONSE 0x8000u /* NBNS constants. */ -#define dnsNBNS_TTL_VALUE 3600 /* 1 hour valid */ -#define dnsNBNS_TYPE_NET_BIOS 0x0020 -#define dnsNBNS_CLASS_IN 0x01 -#define dnsNBNS_NAME_FLAGS 0x6000 -#define dnsNBNS_ENCODED_NAME_LENGTH 32 +#define dnsNBNS_TTL_VALUE 3600uL /* 1 hour valid */ +#define dnsNBNS_TYPE_NET_BIOS 0x0020u +#define dnsNBNS_CLASS_IN 0x01u +#define dnsNBNS_NAME_FLAGS 0x6000u +#define dnsNBNS_ENCODED_NAME_LENGTH 32 /* If the queried NBNS name matches with the device's name, the query will be responded to with these flags: */ -#define dnsNBNS_QUERY_RESPONSE_FLAGS ( 0x8500 ) +#define dnsNBNS_QUERY_RESPONSE_FLAGS ( 0x8500u ) /* Flag DNS parsing errors in situations where an IPv4 address is the return type. */ -#define dnsPARSE_ERROR 0UL +#define dnsPARSE_ERROR 0uL /* * Create a socket and bind it to the standard DNS port number. Return the @@ -109,44 +109,66 @@ static Socket_t prvCreateDNSSocket( void ); /* * Create the DNS message in the zero copy buffer passed in the first parameter. */ -static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, const char *pcHostName, TickType_t xIdentifier ); +static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, + const char *pcHostName, + TickType_t uxIdentifier ); /* * Simple routine that jumps over the NAME field of a resource record. */ -static uint8_t *prvSkipNameField( uint8_t *pucByte, size_t xSourceLen ); +static uint8_t * prvSkipNameField( uint8_t *pucByte, + size_t uxSourceLen ); /* * Process a response packet from a DNS server. + * The parameter 'xExpected' indicates whether the identifier in the reply + * was expected, and thus if the DNS cache may be updated with the reply. */ -static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, TickType_t xIdentifier ); +static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, + size_t uxBufferLength, + BaseType_t xExpected ); /* - * Prepare and send a message to a DNS server. 'xReadTimeOut_ms' will be passed as + * Prepare and send a message to a DNS server. 'uxReadTimeOut_ticks' will be passed as * zero, in case the user has supplied a call-back function. */ -static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier, TickType_t xReadTimeOut_ms ); +static uint32_t prvGetHostByName( const char *pcHostName, + TickType_t uxIdentifier, + TickType_t uxReadTimeOut_ticks ); /* * The NBNS and the LLMNR protocol share this reply function. */ #if( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) ) - static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer, BaseType_t lNetLength ); + static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer, + BaseType_t lNetLength ); #endif #if( ipconfigUSE_NBNS == 1 ) - static portINLINE void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, uint32_t ulIPAddress ); + static portINLINE void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, + size_t uxBufferLength, + uint32_t ulIPAddress ); #endif /* ipconfigUSE_NBNS */ + +#if( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 ) + static uint8_t * prvReadNameField( uint8_t *pucByte, + size_t uxSourceLen, + char *pcName, + size_t uxLen ); +#endif /* ipconfigUSE_DNS_CACHE || ipconfigDNS_USE_CALLBACKS */ + #if( ipconfigUSE_DNS_CACHE == 1 ) - static uint8_t *prvReadNameField( uint8_t *pucByte, size_t xSourceLen, char *pcName, size_t xLen ); - static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, uint32_t ulTTL, BaseType_t xLookUp ); + static void prvProcessDNSCache( const char *pcName, + uint32_t *pulIP, + uint32_t ulTTL, + BaseType_t xLookUp ); typedef struct xDNS_CACHE_TABLE_ROW { - uint32_t ulIPAddress; /* The IP address of an ARP cache entry. */ - char pcName[ ipconfigDNS_CACHE_NAME_LENGTH ]; /* The name of the host */ - uint32_t ulTTL; /* Time-to-Live (in seconds) from the DNS server. */ + uint32_t ulIPAddress; /* The IP address of an ARP cache entry. */ + char pcName[ ipconfigDNS_CACHE_NAME_LENGTH ]; /* The name of the host */ + uint32_t ulTTL; /* Time-to-Live (in seconds) from the DNS server. */ uint32_t ulTimeWhenAddedInSeconds; } DNSCacheRow_t; @@ -160,7 +182,7 @@ static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier #if( ipconfigUSE_LLMNR == 1 ) const MACAddress_t xLLMNR_MacAdress = { { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfc } }; -#endif /* ipconfigUSE_LLMNR == 1 */ +#endif /* ipconfigUSE_LLMNR == 1 */ /*-----------------------------------------------------------*/ @@ -208,7 +230,7 @@ typedef struct xDNSAnswerRecord DNSAnswerRecord_t; struct xLLMNRAnswer { uint8_t ucNameCode; - uint8_t ucNameOffset; /* The name is not repeated in the answer, only the offset is given with "0xc0 " */ + uint8_t ucNameOffset; /* The name is not repeated in the answer, only the offset is given with "0xc0 " */ uint16_t usType; uint16_t usClass; uint32_t ulTTL; @@ -247,32 +269,34 @@ typedef struct xDNSAnswerRecord DNSAnswerRecord_t; uint16_t usClass; uint32_t ulTTL; uint16_t usDataLength; - uint16_t usNbFlags; /* NetBIOS flags 0x6000 : IP-address, big-endian */ + uint16_t usNbFlags; /* NetBIOS flags 0x6000 : IP-address, big-endian */ uint32_t ulIPAddress; } #include "pack_struct_end.h" typedef struct xNBNSAnswer NBNSAnswer_t; -#endif /* ipconfigUSE_NBNS == 1 */ + #endif /* ipconfigUSE_NBNS == 1 */ /*-----------------------------------------------------------*/ #if( ipconfigUSE_DNS_CACHE == 1 ) uint32_t FreeRTOS_dnslookup( const char *pcHostName ) { - uint32_t ulIPAddress = 0UL; + uint32_t ulIPAddress = 0uL; + prvProcessDNSCache( pcHostName, &ulIPAddress, 0, pdTRUE ); return ulIPAddress; } #endif /* ipconfigUSE_DNS_CACHE == 1 */ /*-----------------------------------------------------------*/ -#if( ipconfigDNS_USE_CALLBACKS != 0 ) +#if( ipconfigDNS_USE_CALLBACKS == 1 ) - typedef struct xDNS_Callback { - TickType_t xRemaningTime; /* Timeout in ms */ + typedef struct xDNS_Callback + { + TickType_t uxRemaningTime; /* Timeout in ms */ FOnDNSEvent pCallbackFunction; /* Function to be called when the address has been found or when a timeout has beeen reached */ - TimeOut_t xTimeoutState; + TimeOut_t uxTimeoutState; void *pvSearchID; struct xLIST_ITEM xListItem; char pcName[ 1 ]; @@ -283,7 +307,7 @@ typedef struct xDNSAnswerRecord DNSAnswerRecord_t; /* Define FreeRTOS_gethostbyname() as a normal blocking call. */ uint32_t FreeRTOS_gethostbyname( const char *pcHostName ) { - return FreeRTOS_gethostbyname_a( pcHostName, ( FOnDNSEvent ) NULL, ( void* )NULL, 0 ); + return FreeRTOS_gethostbyname_a( pcHostName, ( FOnDNSEvent ) NULL, ( void * ) NULL, 0 ); } /*-----------------------------------------------------------*/ @@ -304,23 +328,25 @@ typedef struct xDNSAnswerRecord DNSAnswerRecord_t; void vDNSCheckCallBack( void *pvSearchID ) { const ListItem_t *pxIterator; - const MiniListItem_t* xEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xCallbackList ); + const MiniListItem_t * xEnd = ( const MiniListItem_t * ) listGET_END_MARKER( &xCallbackList ); vTaskSuspendAll(); { for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd ); pxIterator != ( const ListItem_t * ) xEnd; - ) + ) { - DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + /* Move to the next item because we might remove this item */ - pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ); + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ); + if( ( pvSearchID != NULL ) && ( pvSearchID == pxCallback->pvSearchID ) ) { uxListRemove( &pxCallback->xListItem ); vPortFree( pxCallback ); } - else if( xTaskCheckForTimeOut( &pxCallback->xTimeoutState, &pxCallback->xRemaningTime ) != pdFALSE ) + else if( xTaskCheckForTimeOut( &pxCallback->uxTimeoutState, &pxCallback->uxRemaningTime ) != pdFALSE ) { pxCallback->pCallbackFunction( pxCallback->pcName, pxCallback->pvSearchID, 0 ); uxListRemove( &pxCallback->xListItem ); @@ -346,28 +372,38 @@ typedef struct xDNSAnswerRecord DNSAnswerRecord_t; /* FreeRTOS_gethostbyname_a() was called along with callback parameters. Store them in a list for later reference. */ - static void vDNSSetCallBack( const char *pcHostName, void *pvSearchID, FOnDNSEvent pCallbackFunction, TickType_t xTimeout, TickType_t xIdentifier ); - static void vDNSSetCallBack( const char *pcHostName, void *pvSearchID, FOnDNSEvent pCallbackFunction, TickType_t xTimeout, TickType_t xIdentifier ) + static void vDNSSetCallBack( const char *pcHostName, + void *pvSearchID, + FOnDNSEvent pCallbackFunction, + TickType_t uxTimeout, + TickType_t uxIdentifier ); + static void vDNSSetCallBack( const char *pcHostName, + void *pvSearchID, + FOnDNSEvent pCallbackFunction, + TickType_t uxTimeout, + TickType_t uxIdentifier ) { - size_t lLength = strlen( pcHostName ); - DNSCallback_t *pxCallback = ( DNSCallback_t * )pvPortMalloc( sizeof( *pxCallback ) + lLength ); + size_t lLength = strlen( pcHostName ); + DNSCallback_t *pxCallback = ( DNSCallback_t * ) pvPortMalloc( sizeof( *pxCallback ) + lLength ); /* Translate from ms to number of clock ticks. */ - xTimeout /= portTICK_PERIOD_MS; + uxTimeout /= portTICK_PERIOD_MS; + if( pxCallback != NULL ) { if( listLIST_IS_EMPTY( &xCallbackList ) ) { /* This is the first one, start the DNS timer to check for timeouts */ - vIPReloadDNSTimer( FreeRTOS_min_uint32( 1000U, xTimeout ) ); + vIPReloadDNSTimer( FreeRTOS_min_uint32( 1000U, uxTimeout ) ); } + strcpy( pxCallback->pcName, pcHostName ); pxCallback->pCallbackFunction = pCallbackFunction; pxCallback->pvSearchID = pvSearchID; - pxCallback->xRemaningTime = xTimeout; - vTaskSetTimeOutState( &pxCallback->xTimeoutState ); - listSET_LIST_ITEM_OWNER( &( pxCallback->xListItem ), ( void* ) pxCallback ); - listSET_LIST_ITEM_VALUE( &( pxCallback->xListItem ), xIdentifier ); + pxCallback->uxRemaningTime = uxTimeout; + vTaskSetTimeOutState( &pxCallback->uxTimeoutState ); + listSET_LIST_ITEM_OWNER( &( pxCallback->xListItem ), ( void * ) pxCallback ); + listSET_LIST_ITEM_VALUE( &( pxCallback->xListItem ), uxIdentifier ); vTaskSuspendAll(); { vListInsertEnd( &xCallbackList, &pxCallback->xListItem ); @@ -378,12 +414,17 @@ typedef struct xDNSAnswerRecord DNSAnswerRecord_t; /*-----------------------------------------------------------*/ /* A DNS reply was received, see if there is any matching entry and - call the handler. */ - static void vDNSDoCallback( TickType_t xIdentifier, const char *pcName, uint32_t ulIPAddress ); - static void vDNSDoCallback( TickType_t xIdentifier, const char *pcName, uint32_t ulIPAddress ) + call the handler. Returns pdTRUE if uxIdentifier was recognised. */ + static BaseType_t xDNSDoCallback( TickType_t uxIdentifier, + const char *pcName, + uint32_t ulIPAddress ); + static BaseType_t xDNSDoCallback( TickType_t uxIdentifier, + const char *pcName, + uint32_t ulIPAddress ) { - const ListItem_t *pxIterator; - const MiniListItem_t* xEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xCallbackList ); + BaseType_t xResult = pdFALSE; + const ListItem_t *pxIterator; + const MiniListItem_t * xEnd = ( const MiniListItem_t * ) listGET_END_MARKER( &xCallbackList ); vTaskSuspendAll(); { @@ -391,111 +432,132 @@ typedef struct xDNSAnswerRecord DNSAnswerRecord_t; pxIterator != ( const ListItem_t * ) xEnd; pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) ) { - if( listGET_LIST_ITEM_VALUE( pxIterator ) == xIdentifier ) + /* The cast will take away the 'configLIST_VOLATILE' */ + if( uxIdentifier == ( TickType_t ) listGET_LIST_ITEM_VALUE( pxIterator ) ) { - DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + pxCallback->pCallbackFunction( pcName, pxCallback->pvSearchID, ulIPAddress ); uxListRemove( &pxCallback->xListItem ); vPortFree( pxCallback ); + if( listLIST_IS_EMPTY( &xCallbackList ) ) { + /* The list of outstanding requests is empty. No need for periodic polling. */ vIPSetDnsTimerEnableState( pdFALSE ); } + + xResult = pdTRUE; break; } } } xTaskResumeAll(); + return xResult; } -#endif /* ipconfigDNS_USE_CALLBACKS != 0 */ +#endif /* ipconfigDNS_USE_CALLBACKS == 1 */ /*-----------------------------------------------------------*/ #if( ipconfigDNS_USE_CALLBACKS == 0 ) -uint32_t FreeRTOS_gethostbyname( const char *pcHostName ) + uint32_t FreeRTOS_gethostbyname( const char *pcHostName ) #else -uint32_t FreeRTOS_gethostbyname_a( const char *pcHostName, FOnDNSEvent pCallback, void *pvSearchID, TickType_t xTimeout ) + uint32_t FreeRTOS_gethostbyname_a( const char *pcHostName, + FOnDNSEvent pCallback, + void *pvSearchID, + TickType_t uxTimeout ) #endif { -uint32_t ulIPAddress = 0UL; -TickType_t xReadTimeOut_ms = ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME; -TickType_t xIdentifier = 0; +uint32_t ulIPAddress = 0uL; +TickType_t uxReadTimeOut_ticks = ipconfigDNS_RECEIVE_BLOCK_TIME_TICKS; +TickType_t uxIdentifier = 0u; +BaseType_t xHasRandom = pdFALSE; - /* If the supplied hostname is IP address, convert it to uint32_t - and return. */ - #if( ipconfigINCLUDE_FULL_INET_ADDR == 1 ) + if( pcHostName != NULL ) { - ulIPAddress = FreeRTOS_inet_addr( pcHostName ); - } - #endif /* ipconfigINCLUDE_FULL_INET_ADDR == 1 */ + /* If the supplied hostname is IP address, convert it to uint32_t + and return. */ + #if( ipconfigINCLUDE_FULL_INET_ADDR == 1 ) + { + ulIPAddress = FreeRTOS_inet_addr( pcHostName ); + } + #endif /* ipconfigINCLUDE_FULL_INET_ADDR == 1 */ - /* If a DNS cache is used then check the cache before issuing another DNS - request. */ - #if( ipconfigUSE_DNS_CACHE == 1 ) - { - if( ulIPAddress == 0UL ) + /* If a DNS cache is used then check the cache before issuing another DNS + request. */ + #if( ipconfigUSE_DNS_CACHE == 1 ) { - ulIPAddress = FreeRTOS_dnslookup( pcHostName ); - if( ulIPAddress != 0 ) + if( ulIPAddress == 0uL ) { - FreeRTOS_debug_printf( ( "FreeRTOS_gethostbyname: found '%s' in cache: %lxip\n", pcHostName, ulIPAddress ) ); - } - else - { - /* prvGetHostByName will be called to start a DNS lookup */ + ulIPAddress = FreeRTOS_dnslookup( pcHostName ); + + if( ulIPAddress != 0 ) + { + FreeRTOS_debug_printf( ( "FreeRTOS_gethostbyname: found '%s' in cache: %lxip\n", pcHostName, ulIPAddress ) ); + } + else + { + /* prvGetHostByName will be called to start a DNS lookup. */ + } } } - } - #endif /* ipconfigUSE_DNS_CACHE == 1 */ + #endif /* ipconfigUSE_DNS_CACHE == 1 */ - /* Generate a unique identifier. */ - if( 0 == ulIPAddress ) - { - xIdentifier = ( TickType_t )ipconfigRAND32( ); - } + /* Generate a unique identifier. */ + if( ulIPAddress == 0uL ) + { + uint32_t ulNumber; - #if( ipconfigDNS_USE_CALLBACKS != 0 ) - { - if( pCallback != NULL ) + xHasRandom = xApplicationGetRandomNumber( &( ulNumber ) ); + /* DNS identifiers are 16-bit. */ + uxIdentifier = ( TickType_t ) ( ulNumber & 0xffffu ); + /* ipconfigRAND32() may not return a non-zero value. */ + } + + #if( ipconfigDNS_USE_CALLBACKS == 1 ) { - if( ulIPAddress == 0UL ) + if( pCallback != NULL ) { - /* The user has provided a callback function, so do not block on recvfrom() */ - if( 0 != xIdentifier ) + if( ulIPAddress == 0uL ) { - xReadTimeOut_ms = 0; - vDNSSetCallBack( pcHostName, pvSearchID, pCallback, xTimeout, ( TickType_t )xIdentifier ); + /* The user has provided a callback function, so do not block on recvfrom() */ + if( xHasRandom != pdFALSE ) + { + uxReadTimeOut_ticks = 0u; + vDNSSetCallBack( pcHostName, pvSearchID, pCallback, uxTimeout, uxIdentifier ); + } + } + else + { + /* The IP address is known, do the call-back now. */ + pCallback( pcHostName, pvSearchID, ulIPAddress ); } - } - else - { - /* The IP address is known, do the call-back now. */ - pCallback( pcHostName, pvSearchID, ulIPAddress ); } } - } - #endif + #endif /* if ( ipconfigDNS_USE_CALLBACKS == 1 ) */ - if( ( ulIPAddress == 0UL ) && ( 0 != xIdentifier ) ) - { - ulIPAddress = prvGetHostByName( pcHostName, xIdentifier, xReadTimeOut_ms ); + if( ( ulIPAddress == 0uL ) && ( xHasRandom != pdFALSE ) ) + { + ulIPAddress = prvGetHostByName( pcHostName, uxIdentifier, uxReadTimeOut_ticks ); + } } - return ulIPAddress; } /*-----------------------------------------------------------*/ -static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier, TickType_t xReadTimeOut_ms ) +static uint32_t prvGetHostByName( const char *pcHostName, + TickType_t uxIdentifier, + TickType_t uxReadTimeOut_ticks ) { struct freertos_sockaddr xAddress; Socket_t xDNSSocket; -uint32_t ulIPAddress = 0UL; +uint32_t ulIPAddress = 0uL; uint8_t *pucUDPPayloadBuffer; uint32_t ulAddressLength = sizeof( struct freertos_sockaddr ); BaseType_t xAttempt; int32_t lBytes; -size_t xPayloadLength, xExpectedPayloadLength; -TickType_t xWriteTimeOut_ms = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME; +size_t uxPayloadLength, uxExpectedPayloadLength; +TickType_t uxWriteTimeOut_ticks = ipconfigDNS_SEND_BLOCK_TIME_TICKS; #if( ipconfigUSE_LLMNR == 1 ) BaseType_t bHasDot = pdFALSE; @@ -505,7 +567,8 @@ TickType_t xWriteTimeOut_ms = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME; if not then LLMNR can be used as the lookup method. */ #if( ipconfigUSE_LLMNR == 1 ) { - const char *pucPtr; + const char *pucPtr; + for( pucPtr = pcHostName; *pucPtr; pucPtr++ ) { if( *pucPtr == '.' ) @@ -519,26 +582,26 @@ TickType_t xWriteTimeOut_ms = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME; /* Two is added at the end for the count of characters in the first subdomain part and the string end byte. */ - xExpectedPayloadLength = sizeof( DNSMessage_t ) + strlen( pcHostName ) + sizeof( uint16_t ) + sizeof( uint16_t ) + 2u; + uxExpectedPayloadLength = sizeof( DNSMessage_t ) + strlen( pcHostName ) + sizeof( uint16_t ) + sizeof( uint16_t ) + 2u; xDNSSocket = prvCreateDNSSocket(); if( xDNSSocket != NULL ) { - FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xWriteTimeOut_ms, sizeof( TickType_t ) ); - FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xReadTimeOut_ms, sizeof( TickType_t ) ); + FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &uxWriteTimeOut_ticks, sizeof( TickType_t ) ); + FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &uxReadTimeOut_ticks, sizeof( TickType_t ) ); for( xAttempt = 0; xAttempt < ipconfigDNS_REQUEST_ATTEMPTS; xAttempt++ ) { /* Get a buffer. This uses a maximum delay, but the delay will be capped to ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS so the return value still needs to be tested. */ - pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xExpectedPayloadLength, portMAX_DELAY ); + pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( uxExpectedPayloadLength, portMAX_DELAY ); if( pucUDPPayloadBuffer != NULL ) { /* Create the message in the obtained buffer. */ - xPayloadLength = prvCreateDNSMessage( pucUDPPayloadBuffer, pcHostName, xIdentifier ); + uxPayloadLength = prvCreateDNSMessage( pucUDPPayloadBuffer, pcHostName, uxIdentifier ); iptraceSENDING_DNS_REQUEST(); @@ -550,8 +613,8 @@ TickType_t xWriteTimeOut_ms = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME; if( bHasDot == pdFALSE ) { /* Use LLMNR addressing. */ - ( ( DNSMessage_t * ) pucUDPPayloadBuffer) -> usFlags = 0; - xAddress.sin_addr = ipLLMNR_IP_ADDR; /* Is in network byte order. */ + ( ( DNSMessage_t * ) pucUDPPayloadBuffer )->usFlags = 0; + xAddress.sin_addr = ipLLMNR_IP_ADDR; /* Is in network byte order. */ xAddress.sin_port = FreeRTOS_ntohs( ipLLMNR_PORT ); } else @@ -562,24 +625,45 @@ TickType_t xWriteTimeOut_ms = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME; xAddress.sin_port = dnsDNS_PORT; } - ulIPAddress = 0UL; + ulIPAddress = 0uL; - if( FreeRTOS_sendto( xDNSSocket, pucUDPPayloadBuffer, xPayloadLength, FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) != 0 ) + if( FreeRTOS_sendto( xDNSSocket, pucUDPPayloadBuffer, uxPayloadLength, FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) != 0 ) { /* Wait for the reply. */ lBytes = FreeRTOS_recvfrom( xDNSSocket, &pucUDPPayloadBuffer, 0, FREERTOS_ZERO_COPY, &xAddress, &ulAddressLength ); if( lBytes > 0 ) { + BaseType_t xExpected; + DNSMessage_t *pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer; + + /* See if the identifiers match. */ + if( uxIdentifier == ( TickType_t ) pxDNSMessageHeader->usIdentifier ) + { + xExpected = pdTRUE; + } + else + { + /* The reply was not expected. */ + xExpected = pdFALSE; + } + /* The reply was received. Process it. */ - ulIPAddress = prvParseDNSReply( pucUDPPayloadBuffer, lBytes, xIdentifier ); + #if( ipconfigDNS_USE_CALLBACKS == 0 ) + /* It is useless to analyse the unexpected reply + unless asynchronous look-ups are enabled. */ + if( xExpected != pdFALSE ) + #endif /* ipconfigDNS_USE_CALLBACKS == 0 */ + { + ulIPAddress = prvParseDNSReply( pucUDPPayloadBuffer, ( size_t ) lBytes, xExpected ); + } /* Finished with the buffer. The zero copy interface is being used, so the buffer must be freed by the task. */ FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer ); - if( ulIPAddress != 0UL ) + if( ulIPAddress != 0uL ) { /* All done. */ break; @@ -593,6 +677,13 @@ TickType_t xWriteTimeOut_ms = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME; FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer ); } } + + if( uxReadTimeOut_ticks == 0u ) + { + /* This DNS lookup is asynchronous, using a call-back: + send the request only once. */ + break; + } } /* Finished with the socket. */ @@ -603,19 +694,21 @@ TickType_t xWriteTimeOut_ms = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME; } /*-----------------------------------------------------------*/ -static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, const char *pcHostName, TickType_t xIdentifier ) +static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, + const char *pcHostName, + TickType_t uxIdentifier ) { DNSMessage_t *pxDNSMessageHeader; uint8_t *pucStart, *pucByte; DNSTail_t *pxTail; static const DNSMessage_t xDefaultPartDNSHeader = { - 0, /* The identifier will be overwritten. */ - dnsOUTGOING_FLAGS, /* Flags set for standard query. */ - dnsONE_QUESTION, /* One question is being asked. */ - 0, /* No replies are included. */ - 0, /* No authorities. */ - 0 /* No additional authorities. */ + 0, /* The identifier will be overwritten. */ + dnsOUTGOING_FLAGS, /* Flags set for standard query. */ + dnsONE_QUESTION, /* One question is being asked. */ + 0, /* No replies are included. */ + 0, /* No authorities. */ + 0 /* No additional authorities. */ }; /* Copy in the const part of the header. */ @@ -623,7 +716,7 @@ static const DNSMessage_t xDefaultPartDNSHeader = /* Write in a unique identifier. */ pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer; - pxDNSMessageHeader->usIdentifier = ( uint16_t ) xIdentifier; + pxDNSMessageHeader->usIdentifier = ( uint16_t ) uxIdentifier; /* Create the resource record at the end of the header. First find the end of the header. */ @@ -659,15 +752,14 @@ static const DNSMessage_t xDefaultPartDNSHeader = ( *pucStart )--; pucStart = pucByte; - } while( *pucByte != 0x00 ); /* Finish off the record. */ - pxTail = (DNSTail_t *)( pucByte + 1 ); + pxTail = ( DNSTail_t * ) ( pucByte + 1 ); - vSetField16( pxTail, DNSTail_t, usType, dnsTYPE_A_HOST ); /* Type A: host */ - vSetField16( pxTail, DNSTail_t, usClass, dnsCLASS_IN ); /* 1: Class IN */ + vSetField16( pxTail, DNSTail_t, usType, dnsTYPE_A_HOST ); /* Type A: host */ + vSetField16( pxTail, DNSTail_t, usClass, dnsCLASS_IN ); /* 1: Class IN */ /* Return the total size of the generated message, which is the space from the last written byte to the beginning of the buffer. */ @@ -675,14 +767,17 @@ static const DNSMessage_t xDefaultPartDNSHeader = } /*-----------------------------------------------------------*/ -#if( ipconfigUSE_DNS_CACHE == 1 ) +#if( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 ) - static uint8_t *prvReadNameField( uint8_t *pucByte, size_t xSourceLen, char *pcName, size_t xDestLen ) + static uint8_t * prvReadNameField( uint8_t *pucByte, + size_t uxSourceLen, + char *pcName, + size_t uxDestLen ) { - size_t xNameLen = 0; + size_t uxNameLen = 0; BaseType_t xCount; - if( 0 == xSourceLen ) + if( 0 == uxSourceLen ) { return NULL; } @@ -692,7 +787,7 @@ static const DNSMessage_t xDefaultPartDNSHeader = if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET ) { /* Jump over the two byte offset. */ - if( xSourceLen > sizeof( uint16_t ) ) + if( uxSourceLen > sizeof( uint16_t ) ) { pucByte += sizeof( uint16_t ); } @@ -704,23 +799,23 @@ static const DNSMessage_t xDefaultPartDNSHeader = else { /* pucByte points to the full name. Walk over the string. */ - while( ( NULL != pucByte ) && ( *pucByte != 0x00 ) && ( xSourceLen > 1 ) ) + while( ( NULL != pucByte ) && ( *pucByte != 0x00u ) && ( uxSourceLen > 1u ) ) { /* If this is not the first time through the loop, then add a separator in the output. */ - if( ( xNameLen > 0 ) && ( xNameLen < ( xDestLen - 1 ) ) ) + if( ( uxNameLen > 0 ) && ( uxNameLen < ( uxDestLen - 1u ) ) ) { - pcName[ xNameLen++ ] = '.'; + pcName[ uxNameLen++ ] = '.'; } /* Process the first/next sub-string. */ - for( xCount = *(pucByte++), xSourceLen--; - xCount-- && xSourceLen > 1; - pucByte++, xSourceLen-- ) + for( xCount = *( pucByte++ ), uxSourceLen--; + xCount-- && uxSourceLen > 1u; + pucByte++, uxSourceLen-- ) { - if( xNameLen < xDestLen - 1 ) + if( uxNameLen < uxDestLen - 1u ) { - pcName[ xNameLen++ ] = *( ( char * )pucByte ); + pcName[ uxNameLen++ ] = *( ( char * ) pucByte ); } else { @@ -737,8 +832,8 @@ static const DNSMessage_t xDefaultPartDNSHeader = if( 0x00 == *pucByte ) { pucByte++; - xSourceLen--; - pcName[ xNameLen++ ] = '\0'; + uxSourceLen--; + pcName[ uxNameLen++ ] = '\0'; } else { @@ -749,14 +844,15 @@ static const DNSMessage_t xDefaultPartDNSHeader = return pucByte; } -#endif /* ipconfigUSE_DNS_CACHE == 1 */ +#endif /* ipconfigUSE_DNS_CACHE || ipconfigDNS_USE_CALLBACKS */ /*-----------------------------------------------------------*/ -static uint8_t *prvSkipNameField( uint8_t *pucByte, size_t xSourceLen ) +static uint8_t * prvSkipNameField( uint8_t *pucByte, + size_t uxSourceLen ) { - size_t xChunkLength; +size_t uxChunkLength; - if( 0 == xSourceLen ) + if( 0u == uxSourceLen ) { return NULL; } @@ -766,7 +862,7 @@ static uint8_t *prvSkipNameField( uint8_t *pucByte, size_t xSourceLen ) if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET ) { /* Jump over the two byte offset. */ - if( xSourceLen > sizeof( uint16_t ) ) + if( uxSourceLen > sizeof( uint16_t ) ) { pucByte += sizeof( uint16_t ); } @@ -778,14 +874,14 @@ static uint8_t *prvSkipNameField( uint8_t *pucByte, size_t xSourceLen ) else { /* pucByte points to the full name. Walk over the string. */ - while( ( *pucByte != 0x00 ) && ( xSourceLen > 1 ) ) + while( ( *pucByte != 0x00u ) && ( uxSourceLen > 1u ) ) { - xChunkLength = *pucByte + 1; + uxChunkLength = *pucByte + 1u; - if( xSourceLen > xChunkLength ) + if( uxSourceLen > uxChunkLength ) { - xSourceLen -= xChunkLength; - pucByte += xChunkLength; + uxSourceLen -= uxChunkLength; + pucByte += uxChunkLength; } else { @@ -797,7 +893,7 @@ static uint8_t *prvSkipNameField( uint8_t *pucByte, size_t xSourceLen ) /* Confirm that a fully formed name was found. */ if( NULL != pucByte ) { - if( 0x00 == *pucByte ) + if( 0x00u == *pucByte ) { pucByte++; } @@ -812,19 +908,33 @@ static uint8_t *prvSkipNameField( uint8_t *pucByte, size_t xSourceLen ) } /*-----------------------------------------------------------*/ +/* The function below will only be called : +when ipconfigDNS_USE_CALLBACKS == 1 +when ipconfigUSE_LLMNR == 1 +for testing purposes, by the module iot_test_freertos_tcp.c +*/ uint32_t ulDNSHandlePacket( NetworkBufferDescriptor_t *pxNetworkBuffer ) { DNSMessage_t *pxDNSMessageHeader; - - if( pxNetworkBuffer->xDataLength >= sizeof( DNSMessage_t ) ) - { - pxDNSMessageHeader = - ( DNSMessage_t * )( pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t ) ); - - prvParseDNSReply( ( uint8_t * )pxDNSMessageHeader, - pxNetworkBuffer->xDataLength, - ( uint32_t )pxDNSMessageHeader->usIdentifier ); - } +size_t uxPayloadSize; + + /* Only proceed if the payload length indicated in the header + appears to be valid. */ + if( pxNetworkBuffer->xDataLength >= sizeof( UDPPacket_t ) ) + { + uxPayloadSize = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t ); + + if( uxPayloadSize >= sizeof( DNSMessage_t ) ) + { + pxDNSMessageHeader = + ( DNSMessage_t * ) ( pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t ) ); + + /* The parameter pdFALSE indicates that the reply was not expected. */ + prvParseDNSReply( ( uint8_t * ) pxDNSMessageHeader, + uxPayloadSize, + pdFALSE ); + } + } /* The packet was not consumed. */ return pdFAIL; @@ -833,15 +943,16 @@ DNSMessage_t *pxDNSMessageHeader; #if( ipconfigUSE_NBNS == 1 ) - uint32_t ulNBNSHandlePacket (NetworkBufferDescriptor_t *pxNetworkBuffer ) + uint32_t ulNBNSHandlePacket( NetworkBufferDescriptor_t * pxNetworkBuffer ) { UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer; uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t ); + size_t uxPayloadSize = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t ); - /* The network buffer data length has already been set to the + /* The network buffer data length has already been set to the length of the UDP payload. */ prvTreatNBNS( pucUDPPayloadBuffer, - pxNetworkBuffer->xDataLength, + uxPayloadSize, pxUDPPacket->xIPHeader.ulSourceIPAddress ); /* The packet was not consumed. */ @@ -851,45 +962,48 @@ DNSMessage_t *pxDNSMessageHeader; #endif /* ipconfigUSE_NBNS */ /*-----------------------------------------------------------*/ -static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, TickType_t xIdentifier ) +static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, + size_t uxBufferLength, + BaseType_t xExpected ) { DNSMessage_t *pxDNSMessageHeader; DNSAnswerRecord_t *pxDNSAnswerRecord; -uint32_t ulIPAddress = 0UL; +uint32_t ulIPAddress = 0uL; #if( ipconfigUSE_LLMNR == 1 ) char *pcRequestedName = NULL; #endif uint8_t *pucByte; -size_t xSourceBytesRemaining; +size_t uxSourceBytesRemaining; uint16_t x, usDataLength, usQuestions; +BaseType_t xDoStore = xExpected; #if( ipconfigUSE_LLMNR == 1 ) uint16_t usType = 0, usClass = 0; #endif -#if( ipconfigUSE_DNS_CACHE == 1 ) +#if( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 ) char pcName[ ipconfigDNS_CACHE_NAME_LENGTH ] = ""; #endif /* Ensure that the buffer is of at least minimal DNS message length. */ - if( xBufferLength < sizeof( DNSMessage_t ) ) + if( uxBufferLength < sizeof( DNSMessage_t ) ) { return dnsPARSE_ERROR; } - else - { - xSourceBytesRemaining = xBufferLength; - } + + uxSourceBytesRemaining = uxBufferLength; /* Parse the DNS message header. */ pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer; - if( pxDNSMessageHeader->usIdentifier == ( uint16_t ) xIdentifier ) + /* Introduce a do {} while (0) to allow the use of breaks. */ + do { /* Start at the first byte after the header. */ pucByte = pucUDPPayloadBuffer + sizeof( DNSMessage_t ); - xSourceBytesRemaining -= sizeof( DNSMessage_t ); + uxSourceBytesRemaining -= sizeof( DNSMessage_t ); /* Skip any question records. */ usQuestions = FreeRTOS_ntohs( pxDNSMessageHeader->usQuestions ); + for( x = 0; x < usQuestions; x++ ) { #if( ipconfigUSE_LLMNR == 1 ) @@ -901,11 +1015,11 @@ uint16_t x, usDataLength, usQuestions; } #endif -#if( ipconfigUSE_DNS_CACHE == 1 ) +#if( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 ) if( x == 0 ) { pucByte = prvReadNameField( pucByte, - xSourceBytesRemaining, + uxSourceBytesRemaining, pcName, sizeof( pcName ) ); @@ -914,35 +1028,32 @@ uint16_t x, usDataLength, usQuestions; { return dnsPARSE_ERROR; } - else - { - xSourceBytesRemaining = ( pucUDPPayloadBuffer + xBufferLength ) - pucByte; - } + + uxSourceBytesRemaining = ( pucUDPPayloadBuffer + uxBufferLength ) - pucByte; } else -#endif /* ipconfigUSE_DNS_CACHE */ +#endif /* ipconfigUSE_DNS_CACHE || ipconfigDNS_USE_CALLBACKS */ { /* Skip the variable length pcName field. */ pucByte = prvSkipNameField( pucByte, - xSourceBytesRemaining ); + uxSourceBytesRemaining ); /* Check for a malformed response. */ if( NULL == pucByte ) { return dnsPARSE_ERROR; } - else - { - xSourceBytesRemaining = pucUDPPayloadBuffer + xBufferLength - pucByte; - } + + uxSourceBytesRemaining = ( size_t ) + ( pucUDPPayloadBuffer + uxBufferLength - pucByte ); } /* Check the remaining buffer size. */ - if( xSourceBytesRemaining >= sizeof( uint32_t ) ) + if( uxSourceBytesRemaining >= sizeof( uint32_t ) ) { #if( ipconfigUSE_LLMNR == 1 ) { - /* usChar2u16 returns value in host endianness */ + /* usChar2u16 returns value in host endianness. */ usType = usChar2u16( pucByte ); usClass = usChar2u16( pucByte + 2 ); } @@ -950,7 +1061,7 @@ uint16_t x, usDataLength, usQuestions; /* Skip the type and class fields. */ pucByte += sizeof( uint32_t ); - xSourceBytesRemaining -= sizeof( uint32_t ); + uxSourceBytesRemaining -= sizeof( uint32_t ); } else { @@ -967,25 +1078,24 @@ uint16_t x, usDataLength, usQuestions; for( x = 0; x < pxDNSMessageHeader->usAnswers; x++ ) { pucByte = prvSkipNameField( pucByte, - xSourceBytesRemaining ); + uxSourceBytesRemaining ); /* Check for a malformed response. */ if( NULL == pucByte ) { return dnsPARSE_ERROR; } - else - { - xSourceBytesRemaining = pucUDPPayloadBuffer + xBufferLength - pucByte; - } + + uxSourceBytesRemaining = ( size_t ) + ( pucUDPPayloadBuffer + uxBufferLength - pucByte ); /* Is there enough data for an IPv4 A record answer and, if so, is this an A record? */ - if( xSourceBytesRemaining >= sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ) && - usChar2u16( pucByte ) == dnsTYPE_A_HOST ) + if( ( uxSourceBytesRemaining >= ( sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ) ) ) && + ( usChar2u16( pucByte ) == dnsTYPE_A_HOST ) ) { /* This is the required record type and is of sufficient size. */ - pxDNSAnswerRecord = ( DNSAnswerRecord_t * )pucByte; + pxDNSAnswerRecord = ( DNSAnswerRecord_t * ) pucByte; /* Sanity check the data length of an IPv4 answer. */ if( FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength ) == sizeof( uint32_t ) ) @@ -995,39 +1105,56 @@ uint16_t x, usDataLength, usQuestions; pucByte + sizeof( DNSAnswerRecord_t ), sizeof( uint32_t ) ); - #if( ipconfigUSE_DNS_CACHE == 1 ) + #if( ipconfigDNS_USE_CALLBACKS == 1 ) { - prvProcessDNSCache( pcName, &ulIPAddress, pxDNSAnswerRecord->ulTTL, pdFALSE ); + /* See if any asynchronous call was made to FreeRTOS_gethostbyname_a() */ + if( xDNSDoCallback( ( TickType_t ) pxDNSMessageHeader->usIdentifier, pcName, ulIPAddress ) != pdFALSE ) + { + /* This device has requested this DNS look-up. + The result may be stored in the DNS cache. */ + xDoStore = pdTRUE; + } } - #endif /* ipconfigUSE_DNS_CACHE */ - #if( ipconfigDNS_USE_CALLBACKS != 0 ) + #endif /* ipconfigDNS_USE_CALLBACKS == 1 */ + #if( ipconfigUSE_DNS_CACHE == 1 ) { - /* See if any asynchronous call was made to FreeRTOS_gethostbyname_a() */ - vDNSDoCallback( ( TickType_t ) pxDNSMessageHeader->usIdentifier, pcName, ulIPAddress ); + /* The reply will only be stored in the DNS cache when the + request was issued by this device. */ + if( xDoStore != pdFALSE ) + { + prvProcessDNSCache( pcName, &ulIPAddress, pxDNSAnswerRecord->ulTTL, pdFALSE ); + } + + /* Show what has happened. */ + FreeRTOS_printf( ( "DNS[0x%04X]: The answer to '%s' (%xip) will%s be stored\n", + ( unsigned ) pxDNSMessageHeader->usIdentifier, + pcName, + ( unsigned ) FreeRTOS_ntohl( ulIPAddress ), + ( xDoStore != 0 ) ? "" : " NOT" ) ); } - #endif /* ipconfigDNS_USE_CALLBACKS != 0 */ + #endif /* ipconfigUSE_DNS_CACHE */ } pucByte += sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ); - xSourceBytesRemaining -= ( sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ) ); + uxSourceBytesRemaining -= ( sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ) ); break; } - else if( xSourceBytesRemaining >= sizeof( DNSAnswerRecord_t ) ) + else if( uxSourceBytesRemaining >= sizeof( DNSAnswerRecord_t ) ) { /* It's not an A record, so skip it. Get the header location and then jump over the header. */ - pxDNSAnswerRecord = ( DNSAnswerRecord_t * )pucByte; + pxDNSAnswerRecord = ( DNSAnswerRecord_t * ) pucByte; pucByte += sizeof( DNSAnswerRecord_t ); - xSourceBytesRemaining -= sizeof( DNSAnswerRecord_t ); + uxSourceBytesRemaining -= sizeof( DNSAnswerRecord_t ); /* Determine the length of the answer data from the header. */ usDataLength = FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength ); /* Jump over the answer. */ - if( xSourceBytesRemaining >= usDataLength ) + if( uxSourceBytesRemaining >= usDataLength ) { pucByte += usDataLength; - xSourceBytesRemaining -= usDataLength; + uxSourceBytesRemaining -= usDataLength; } else { @@ -1037,12 +1164,13 @@ uint16_t x, usDataLength, usQuestions; } } } + #if( ipconfigUSE_LLMNR == 1 ) else if( usQuestions && ( usType == dnsTYPE_A_HOST ) && ( usClass == dnsCLASS_IN ) ) { /* If this is not a reply to our DNS request, it might an LLMNR request. */ - if( xApplicationDNSQueryHook ( ( pcRequestedName + 1 ) ) ) + if( xApplicationDNSQueryHook( ( pcRequestedName + 1 ) ) ) { int16_t usLength; NetworkBufferDescriptor_t *pxNewBuffer = NULL; @@ -1051,13 +1179,12 @@ uint16_t x, usDataLength, usQuestions; if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) ) { - BaseType_t xDataLength = xBufferLength + sizeof( UDPHeader_t ) + sizeof( EthernetHeader_t ) + sizeof( IPHeader_t ); + BaseType_t xDataLength = uxBufferLength + sizeof( UDPHeader_t ) + sizeof( EthernetHeader_t ) + sizeof( IPHeader_t ); - /* The field xDataLength was set to the length of the UDP payload. - The answer (reply) will be longer than the request, so the packet - must be duplicaed into a bigger buffer */ + /* Set the size of the outgoing packet. */ pxNetworkBuffer->xDataLength = xDataLength; - pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + 16 ); + pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + sizeof( LLMNRAnswer_t ) ); + if( pxNewBuffer != NULL ) { BaseType_t xOffset1, xOffset2; @@ -1071,7 +1198,6 @@ uint16_t x, usDataLength, usQuestions; pucByte = pucUDPPayloadBuffer + xOffset1; pcRequestedName = ( char * ) ( pucUDPPayloadBuffer + xOffset2 ); pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer; - } else { @@ -1079,21 +1205,22 @@ uint16_t x, usDataLength, usQuestions; pxNetworkBuffer = NULL; } } + if( pxNetworkBuffer != NULL ) { - pxAnswer = (LLMNRAnswer_t *)pucByte; + pxAnswer = ( LLMNRAnswer_t * ) pucByte; /* We leave 'usIdentifier' and 'usQuestions' untouched */ - vSetField16( pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_REPONSE ); /* Set the response flag */ - vSetField16( pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 ); /* Provide a single answer */ - vSetField16( pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 ); /* No authority */ - vSetField16( pxDNSMessageHeader, DNSMessage_t, usAdditionalRRs, 0 ); /* No additional info */ + vSetField16( pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_REPONSE ); /* Set the response flag */ + vSetField16( pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 ); /* Provide a single answer */ + vSetField16( pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 ); /* No authority */ + vSetField16( pxDNSMessageHeader, DNSMessage_t, usAdditionalRRs, 0 ); /* No additional info */ pxAnswer->ucNameCode = dnsNAME_IS_OFFSET; - pxAnswer->ucNameOffset = ( uint8_t )( pcRequestedName - ( char * ) pucUDPPayloadBuffer ); + pxAnswer->ucNameOffset = ( uint8_t ) ( pcRequestedName - ( char * ) pucUDPPayloadBuffer ); - vSetField16( pxAnswer, LLMNRAnswer_t, usType, dnsTYPE_A_HOST ); /* Type A: host */ - vSetField16( pxAnswer, LLMNRAnswer_t, usClass, dnsCLASS_IN ); /* 1: Class IN */ + vSetField16( pxAnswer, LLMNRAnswer_t, usType, dnsTYPE_A_HOST ); /* Type A: host */ + vSetField16( pxAnswer, LLMNRAnswer_t, usClass, dnsCLASS_IN ); /* 1: Class IN */ vSetField32( pxAnswer, LLMNRAnswer_t, ulTTL, dnsLLMNR_TTL_VALUE ); vSetField16( pxAnswer, LLMNRAnswer_t, usDataLength, 4 ); vSetField32( pxAnswer, LLMNRAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) ); @@ -1110,6 +1237,12 @@ uint16_t x, usDataLength, usQuestions; } } #endif /* ipconfigUSE_LLMNR == 1 */ + } while( 0 ); + + if( xExpected == pdFALSE ) + { + /* Do not return a valid IP-address in case the reply was not expected. */ + ulIPAddress = 0uL; } return ulIPAddress; @@ -1118,15 +1251,17 @@ uint16_t x, usDataLength, usQuestions; #if( ipconfigUSE_NBNS == 1 ) - static void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, uint32_t ulIPAddress ) + static void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, + size_t uxBufferLength, + uint32_t ulIPAddress ) { - uint16_t usFlags, usType, usClass; - uint8_t *pucSource, *pucTarget; - uint8_t ucByte; - uint8_t ucNBNSName[ 17 ]; + uint16_t usFlags, usType, usClass; + uint8_t *pucSource, *pucTarget; + uint8_t ucByte; + uint8_t ucNBNSName[ 17 ]; /* Check for minimum buffer size. */ - if( xBufferLength < sizeof( NBNSRequest_t ) ) + if( uxBufferLength < sizeof( NBNSRequest_t ) ) { return; } @@ -1140,10 +1275,11 @@ uint16_t x, usDataLength, usQuestions; usClass = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usClass ) ); /* Not used for now */ - ( void )usClass; + ( void ) usClass; + /* For NBNS a name is 16 bytes long, written with capitals only. Make sure that the copy is terminated with a zero. */ - pucTarget = ucNBNSName + sizeof(ucNBNSName ) - 2; + pucTarget = ucNBNSName + sizeof( ucNBNSName ) - 2; pucTarget[ 1 ] = '\0'; /* Start with decoding the last 2 bytes. */ @@ -1201,14 +1337,11 @@ uint16_t x, usDataLength, usQuestions; if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) ) { NetworkBufferDescriptor_t *pxNewBuffer; - BaseType_t xDataLength = pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) + - sizeof( EthernetHeader_t ) + sizeof( IPHeader_t ); - /* The field xDataLength was set to the length of the UDP payload. - The answer (reply) will be longer than the request, so the packet - must be duplicated into a bigger buffer */ - pxNetworkBuffer->xDataLength = xDataLength; - pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + 16 ); + /* The field xDataLength was set to the total length of the UDP packet, + i.e. the payload size plus sizeof( UDPPacket_t ). */ + pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, pxNetworkBuffer->xDataLength + sizeof( NBNSAnswer_t ) ); + if( pxNewBuffer != NULL ) { pucUDPPayloadBuffer = pxNewBuffer->pucEthernetBuffer + sizeof( UDPPacket_t ); @@ -1224,7 +1357,7 @@ uint16_t x, usDataLength, usQuestions; /* Should not occur: pucUDPPayloadBuffer is part of a xNetworkBufferDescriptor */ if( pxNetworkBuffer != NULL ) { - pxMessage = (DNSMessage_t *)pucUDPPayloadBuffer; + pxMessage = ( DNSMessage_t * ) pucUDPPayloadBuffer; /* As the fields in the structures are not word-aligned, we have to copy the values byte-by-byte using macro's vSetField16() and vSetField32() */ @@ -1234,12 +1367,12 @@ uint16_t x, usDataLength, usQuestions; vSetField16( pxMessage, DNSMessage_t, usAuthorityRRs, 0 ); vSetField16( pxMessage, DNSMessage_t, usAdditionalRRs, 0 ); - pxAnswer = (NBNSAnswer_t *)( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) ); + pxAnswer = ( NBNSAnswer_t * ) ( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) ); - vSetField16( pxAnswer, NBNSAnswer_t, usType, usType ); /* Type */ - vSetField16( pxAnswer, NBNSAnswer_t, usClass, dnsNBNS_CLASS_IN ); /* Class */ + vSetField16( pxAnswer, NBNSAnswer_t, usType, usType ); /* Type */ + vSetField16( pxAnswer, NBNSAnswer_t, usClass, dnsNBNS_CLASS_IN ); /* Class */ vSetField32( pxAnswer, NBNSAnswer_t, ulTTL, dnsNBNS_TTL_VALUE ); - vSetField16( pxAnswer, NBNSAnswer_t, usDataLength, 6 ); /* 6 bytes including the length field */ + vSetField16( pxAnswer, NBNSAnswer_t, usDataLength, 6 ); /* 6 bytes including the length field */ vSetField16( pxAnswer, NBNSAnswer_t, usNbFlags, dnsNBNS_NAME_FLAGS ); vSetField32( pxAnswer, NBNSAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) ); @@ -1251,7 +1384,7 @@ uint16_t x, usDataLength, usQuestions; } } -#endif /* ipconfigUSE_NBNS */ +#endif /* ipconfigUSE_NBNS */ /*-----------------------------------------------------------*/ static Socket_t prvCreateDNSSocket( void ) @@ -1259,7 +1392,6 @@ static Socket_t prvCreateDNSSocket( void ) Socket_t xSocket = NULL; struct freertos_sockaddr xAddress; BaseType_t xReturn; -TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 ); /* This must be the first time this function has been called. Create the socket. */ @@ -1277,9 +1409,7 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 ); } else { - /* Set the send and receive timeouts. */ - FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) ); - FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) ); + /* The send and receive timeouts will be set later on. */ } return xSocket; @@ -1288,13 +1418,14 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 ); #if( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) ) - static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer, BaseType_t lNetLength ) + static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer, + BaseType_t lNetLength ) { UDPPacket_t *pxUDPPacket; IPHeader_t *pxIPHeader; UDPHeader_t *pxUDPHeader; - pxUDPPacket = (UDPPacket_t *) pxNetworkBuffer->pucEthernetBuffer; + pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer; pxIPHeader = &pxUDPPacket->xIPHeader; pxUDPHeader = &pxUDPPacket->xUDPHeader; /* HT: started using defines like 'ipSIZE_OF_xxx' */ @@ -1314,9 +1445,9 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 ); #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) { /* calculate the IP header checksum */ - pxIPHeader->usHeaderChecksum = 0x00; - pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER ); - pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); + pxIPHeader->usHeaderChecksum = 0x00; + pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0uL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER ); + pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); /* calculate the UDP checksum for outgoing package */ usGenerateProtocolChecksum( ( uint8_t* ) pxUDPPacket, pxNetworkBuffer->xDataLength, pdTRUE ); @@ -1332,14 +1463,16 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 ); #if( ipconfigUSE_DNS_CACHE == 1 ) - static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, uint32_t ulTTL, BaseType_t xLookUp ) + static void prvProcessDNSCache( const char *pcName, + uint32_t *pulIP, + uint32_t ulTTL, + BaseType_t xLookUp ) { BaseType_t x; BaseType_t xFound = pdFALSE; uint32_t ulCurrentTimeSeconds = ( xTaskGetTickCount() / portTICK_PERIOD_MS ) / 1000; static BaseType_t xFreeEntry = 0; - configASSERT(pcName); - + configASSERT(pcName); /* For each entry in the DNS cache table. */ for( x = 0; x < ipconfigDNS_CACHE_ENTRIES; x++ ) @@ -1395,6 +1528,7 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 ); xDNSCache[ xFreeEntry ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds; xFreeEntry++; + if( xFreeEntry == ipconfigDNS_CACHE_ENTRIES ) { xFreeEntry = 0; diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c index e4798381b..c94f55dd7 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -65,7 +65,9 @@ a constant. */ /* Time delay between repeated attempts to initialise the network hardware. */ -#define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000 ) ) +#ifndef ipINITIALISATION_RETRY_DELAY + #define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000 ) ) +#endif /* Defines how often the ARP timer callback function is executed. The time is shorted in the Windows simulator as simulated time is not real time. */ @@ -394,6 +396,12 @@ struct freertos_sockaddr xAddress; prvHandleEthernetPacket( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) ); break; + case eNetworkTxEvent: + /* Send a network packet. The ownership will be transferred to + the driver, which will release it after delivery. */ + xNetworkInterfaceOutput( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ), pdTRUE ); + break; + case eARPTimerEvent : /* The ARP timer has expired, process the ARP cache. */ vARPAgeCache(); @@ -820,20 +828,20 @@ void *pvReturn; /*-----------------------------------------------------------*/ NetworkBufferDescriptor_t *pxDuplicateNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer, - BaseType_t xNewLength ) + size_t uxNewLength ) { NetworkBufferDescriptor_t * pxNewBuffer; /* This function is only used when 'ipconfigZERO_COPY_TX_DRIVER' is set to 1. The transmit routine wants to have ownership of the network buffer descriptor, because it will pass the buffer straight to DMA. */ - pxNewBuffer = pxGetNetworkBufferWithDescriptor( ( size_t ) xNewLength, ( TickType_t ) 0 ); + pxNewBuffer = pxGetNetworkBufferWithDescriptor( uxNewLength, ( TickType_t ) 0 ); if( pxNewBuffer != NULL ) { /* Set the actual packet size in case a bigger buffer than requested was returned. */ - pxNewBuffer->xDataLength = xNewLength; + pxNewBuffer->xDataLength = uxNewLength; /* Copy the original packet information. */ pxNewBuffer->ulIPAddress = pxNetworkBuffer->ulIPAddress; @@ -986,7 +994,10 @@ BaseType_t xReturn = pdFALSE; /* Added to prevent ARP flood to gateway. Ensure the gateway is on the same subnet as the IP address. */ - configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) ); + if( xNetworkAddressing.ulGatewayAddress != 0ul ) + { + configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) ); + } } #endif /* ipconfigUSE_DHCP == 1 */ @@ -1111,7 +1122,8 @@ void FreeRTOS_SetAddressConfiguration( const uint32_t *pulIPAddress, const uint3 pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = FREERTOS_SO_UDPCKSUM_OUT; pxNetworkBuffer->ulIPAddress = ulIPAddress; pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA; - pxNetworkBuffer->xDataLength = xNumberOfBytesToSend + sizeof( ICMPHeader_t ); + /* xDataLength is the size of the total packet, including the Ethernet header. */ + pxNetworkBuffer->xDataLength = xNumberOfBytesToSend + sizeof( ICMPPacket_t ); /* Send to the stack. */ xStackTxEvent.pvData = pxNetworkBuffer; @@ -1600,23 +1612,24 @@ uint8_t ucProtocol; /* Only proceed if the payload length indicated in the header appears to be valid. */ - if ( pxNetworkBuffer->xDataLength >= sizeof( UDPPacket_t ) ) + if ( ( pxNetworkBuffer->xDataLength >= sizeof( UDPPacket_t ) ) && ( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) >= sizeof( UDPHeader_t ) ) ) { - /* Ensure that downstream UDP packet handling has the lesser - * of: the actual network buffer Ethernet frame length, or - * the sender's UDP packet header payload length, minus the - * size of the UDP header. - * - * The size of the UDP packet structure in this implementation - * includes the size of the Ethernet header, the size of - * the IP header, and the size of the UDP header. + size_t uxPayloadSize_1, uxPayloadSize_2; + /* The UDP payload size can be calculated by subtracting the + * header size from `xDataLength`. + * However, the `xDataLength` may be longer that expected, + * e.g. when a small packet is padded with zero's. + * The UDP header contains a field `usLength` reflecting + * the payload size plus the UDP header ( 8 bytes ). + * Set `xDataLength` to the size of the headers, + * plus the lower of the two calculated payload sizes. */ - pxNetworkBuffer->xDataLength -= sizeof( UDPPacket_t ); - if( ( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t ) ) < - pxNetworkBuffer->xDataLength ) + uxPayloadSize_1 = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t ); + uxPayloadSize_2 = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t ); + if( uxPayloadSize_1 > uxPayloadSize_2 ) { - pxNetworkBuffer->xDataLength = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t ); + pxNetworkBuffer->xDataLength = uxPayloadSize_2 + sizeof( UDPPacket_t ); } /* Fields in pxNetworkBuffer (usPort, ulIPAddress) are network order. */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c index 0bc5d82be..e15834849 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -385,7 +385,7 @@ Socket_t xReturn; } } - return ( SocketSet_t * ) pxSocketSet; + return ( SocketSet_t ) pxSocketSet; } #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ @@ -702,9 +702,11 @@ EventBits_t xEventBits = ( EventBits_t ) 0; } taskEXIT_CRITICAL(); - /* The returned value is the data length, which may have been capped to - the receive buffer size. */ - lReturn = ( int32_t ) pxNetworkBuffer->xDataLength; + /* The returned value is the length of the payload data, which is + calculated at the total packet size minus the headers. + The validity of `xDataLength` prvProcessIPPacket has been confirmed + in 'prvProcessIPPacket()'. */ + lReturn = ( int32_t ) ( pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t ) ); if( pxSourceAddress != NULL ) { @@ -833,7 +835,8 @@ FreeRTOS_Socket_t *pxSocket; if( pxNetworkBuffer != NULL ) { - pxNetworkBuffer->xDataLength = xTotalDataLength; + /* xDataLength is the size of the total packet, including the Ethernet header. */ + pxNetworkBuffer->xDataLength = xTotalDataLength + sizeof( UDPPacket_t ); pxNetworkBuffer->usPort = pxDestinationAddress->sin_port; pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_PORT( pxSocket ); pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr; @@ -854,7 +857,7 @@ FreeRTOS_Socket_t *pxSocket; { if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleSent ) ) { - pxSocket->u.xUDP.pxHandleSent( (Socket_t *)pxSocket, xTotalDataLength ); + pxSocket->u.xUDP.pxHandleSent( ( Socket_t )pxSocket, xTotalDataLength ); } } #endif /* ipconfigUSE_CALLBACKS */ @@ -1654,7 +1657,6 @@ const uint16_t usEphemeralPortCount = uint16_t usIterations = usEphemeralPortCount; uint32_t ulRandomSeed = 0; uint16_t usResult = 0; -BaseType_t xGotZeroOnce = pdFALSE; const List_t *pxList; #if ipconfigUSE_TCP == 1 @@ -1675,21 +1677,10 @@ const List_t *pxList; point. */ do { - /* Generate a random seed. */ - ulRandomSeed = ipconfigRAND32( ); - /* Only proceed if the random number generator succeeded. */ - if( 0 == ulRandomSeed ) + if( xApplicationGetRandomNumber( &( ulRandomSeed ) ) == pdFALSE ) { - if( pdFALSE == xGotZeroOnce ) - { - xGotZeroOnce = pdTRUE; - continue; - } - else - { - break; - } + break; } /* Map the random to a candidate port. */ @@ -2413,8 +2404,8 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ) xResult = -pdFREERTOS_ERRNO_ENOMEM; } else if( pxSocket->u.xTCP.ucTCPState == eCLOSED || - pxSocket->u.xTCP.ucTCPState == eCLOSE_WAIT || - pxSocket->u.xTCP.ucTCPState == eCLOSING ) + pxSocket->u.xTCP.ucTCPState == eCLOSE_WAIT || + pxSocket->u.xTCP.ucTCPState == eCLOSING ) { xResult = -pdFREERTOS_ERRNO_ENOTCONN; } @@ -2453,25 +2444,25 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ) '*pxLength' will contain the number of bytes that may be written. */ uint8_t *FreeRTOS_get_tx_head( Socket_t xSocket, BaseType_t *pxLength ) { - uint8_t *pucReturn = NULL; + uint8_t *pucReturn = NULL; FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; StreamBuffer_t *pxBuffer = NULL; - *pxLength = 0; + *pxLength = 0; - /* Confirm that this is a TCP socket before dereferencing structure - member pointers. */ - if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE ) - { - pxBuffer = pxSocket->u.xTCP.txStream; - if( pxBuffer != NULL ) - { - BaseType_t xSpace = ( BaseType_t )uxStreamBufferGetSpace( pxBuffer ); - BaseType_t xRemain = ( BaseType_t )( pxBuffer->LENGTH - pxBuffer->uxHead ); + /* Confirm that this is a TCP socket before dereferencing structure + member pointers. */ + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE ) + { + pxBuffer = pxSocket->u.xTCP.txStream; + if( pxBuffer != NULL ) + { + BaseType_t xSpace = ( BaseType_t )uxStreamBufferGetSpace( pxBuffer ); + BaseType_t xRemain = ( BaseType_t )( pxBuffer->LENGTH - pxBuffer->uxHead ); - *pxLength = FreeRTOS_min_BaseType( xSpace, xRemain ); - pucReturn = pxBuffer->ucArray + pxBuffer->uxHead; - } + *pxLength = FreeRTOS_min_BaseType( xSpace, xRemain ); + pucReturn = pxBuffer->ucArray + pxBuffer->uxHead; + } } return pucReturn; @@ -2904,20 +2895,20 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ) #if( ipconfigUSE_TCP == 1 ) - const struct xSTREAM_BUFFER *FreeRTOS_get_rx_buf( Socket_t xSocket ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * )xSocket; - struct xSTREAM_BUFFER *pxReturn = NULL; + const struct xSTREAM_BUFFER *FreeRTOS_get_rx_buf( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * )xSocket; + struct xSTREAM_BUFFER *pxReturn = NULL; - /* Confirm that this is a TCP socket before dereferencing structure - member pointers. */ - if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE ) - { - pxReturn = pxSocket->u.xTCP.rxStream; - } + /* Confirm that this is a TCP socket before dereferencing structure + member pointers. */ + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE ) + { + pxReturn = pxSocket->u.xTCP.rxStream; + } - return pxReturn; - } + return pxReturn; + } #endif /* ipconfigUSE_TCP */ /*-----------------------------------------------------------*/ @@ -3081,7 +3072,7 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ) break; } - pxSocket->u.xTCP.pxHandleReceive( (Socket_t *)pxSocket, ( void* )ucReadPtr, ( size_t ) ulCount ); + pxSocket->u.xTCP.pxHandleReceive( ( Socket_t )pxSocket, ( void* )ucReadPtr, ( size_t ) ulCount ); uxStreamBufferGet( pxStream, 0ul, NULL, ( size_t ) ulCount, pdFALSE ); } } else diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c index f903fadc1..53a5c69c6 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c index 5eee18917..d26756589 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -227,6 +227,19 @@ static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket ); */ static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer ); +/* + * Identify and deal with a single TCP header option, advancing the pointer to + * the header. This function returns pdTRUE or pdFALSE depending on whether the + * caller should continue to parse more header options or break the loop. + */ +static BaseType_t prvSingleStepTCPHeaderOptions( const unsigned char ** const ppucPtr, const unsigned char ** const ppucLast, FreeRTOS_Socket_t ** const ppxSocket, TCPWindow_t ** const ppxTCPWindow); + +/* + * Skip past TCP header options when doing Selective ACK, until there are no + * more options left. + */ +static void prvSkipPastRemainingOptions( const unsigned char ** const ppucPtr, FreeRTOS_Socket_t ** const ppxSocket, unsigned char * const ppucLen ); + /* * Set the initial properties in the options fields, like the preferred * value of MSS and whether SACK allowed. Will be transmitted in the state @@ -312,7 +325,7 @@ static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferD * payload, just flags). */ static BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t *pxNetworkBuffer, - uint8_t ucTCPFlags ); + uint8_t ucTCPFlags ); /* * A "challenge ACK" is as per https://tools.ietf.org/html/rfc5961#section-3.2, @@ -1151,7 +1164,7 @@ TCPHeader_t * pxTCPHeader; const unsigned char *pucPtr; const unsigned char *pucLast; TCPWindow_t *pxTCPWindow; -UBaseType_t uxNewMSS; +BaseType_t xShouldContinueLoop; pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); pxTCPHeader = &pxTCPPacket->xTCPHeader; @@ -1169,162 +1182,184 @@ UBaseType_t uxNewMSS; /* The comparison with pucLast is only necessary in case the option data are corrupted, we don't like to run into invalid memory and crash. */ - while( pucPtr < pucLast ) + xShouldContinueLoop = pdTRUE; + while( ( pucPtr < pucLast ) && ( xShouldContinueLoop == pdTRUE ) ) { - UBaseType_t xRemainingOptionsBytes = pucLast - pucPtr; + xShouldContinueLoop = prvSingleStepTCPHeaderOptions( &pucPtr, &pucLast, &pxSocket, &pxTCPWindow ); + } +} - if( pucPtr[ 0 ] == TCP_OPT_END ) - { - /* End of options. */ - break; - } - if( pucPtr[ 0 ] == TCP_OPT_NOOP) +/*-----------------------------------------------------------*/ + +static BaseType_t prvSingleStepTCPHeaderOptions( const unsigned char ** const ppucPtr, const unsigned char ** const ppucLast, FreeRTOS_Socket_t ** const ppxSocket, TCPWindow_t ** const ppxTCPWindow) +{ + UBaseType_t uxNewMSS; + UBaseType_t xRemainingOptionsBytes = ( *ppucLast ) - ( *ppucPtr ); + unsigned char ucLen; + + if( ( *ppucPtr )[ 0 ] == TCP_OPT_END ) + { + /* End of options. */ + return pdFALSE; + } + if( ( *ppucPtr )[ 0 ] == TCP_OPT_NOOP) + { + /* NOP option, inserted to make the length a multiple of 4. */ + ( *ppucPtr )++; + return pdTRUE; + } + + /* Any other well-formed option must be at least two bytes: the option + type byte followed by a length byte. */ + if( xRemainingOptionsBytes < 2 ) + { + return pdFALSE; + } +#if( ipconfigUSE_TCP_WIN != 0 ) + else if( ( *ppucPtr )[ 0 ] == TCP_OPT_WSOPT ) + { + /* Confirm that the option fits in the remaining buffer space. */ + if( ( xRemainingOptionsBytes < TCP_OPT_WSOPT_LEN ) || ( ( *ppucPtr )[ 1 ] != TCP_OPT_WSOPT_LEN ) ) { - /* NOP option, inserted to make the length a multiple of 4. */ - pucPtr++; - continue; + return pdFALSE; } - /* Any other well-formed option must be at least two bytes: the option - type byte followed by a length byte. */ - if( xRemainingOptionsBytes < 2 ) + ( *ppxSocket )->u.xTCP.ucPeerWinScaleFactor = ( *ppucPtr )[ 2 ]; + ( *ppxSocket )->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED; + ( *ppucPtr ) += TCP_OPT_WSOPT_LEN; + } +#endif /* ipconfigUSE_TCP_WIN */ + else if( ( *ppucPtr )[ 0 ] == TCP_OPT_MSS ) + { + /* Confirm that the option fits in the remaining buffer space. */ + if( ( xRemainingOptionsBytes < TCP_OPT_MSS_LEN )|| ( ( *ppucPtr )[ 1 ] != TCP_OPT_MSS_LEN ) ) { - break; + return pdFALSE; } -#if( ipconfigUSE_TCP_WIN != 0 ) - else if( pucPtr[ 0 ] == TCP_OPT_WSOPT ) + + /* An MSS option with the correct option length. FreeRTOS_htons() + is not needed here because usChar2u16() already returns a host + endian number. */ + uxNewMSS = usChar2u16( ( *ppucPtr ) + 2 ); + + if( ( *ppxSocket )->u.xTCP.usInitMSS != uxNewMSS ) { - /* Confirm that the option fits in the remaining buffer space. */ - if( ( xRemainingOptionsBytes < TCP_OPT_WSOPT_LEN ) || ( pucPtr[ 1 ] != TCP_OPT_WSOPT_LEN ) ) + /* Perform a basic check on the the new MSS. */ + if( uxNewMSS == 0 ) { - break; + return pdFALSE; } - pxSocket->u.xTCP.ucPeerWinScaleFactor = pucPtr[ 2 ]; - pxSocket->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED; - pucPtr += TCP_OPT_WSOPT_LEN; + FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", ( *ppxSocket )->u.xTCP.usInitMSS, uxNewMSS ) ); } -#endif /* ipconfigUSE_TCP_WIN */ - else if( pucPtr[ 0 ] == TCP_OPT_MSS ) + + if( ( *ppxSocket )->u.xTCP.usInitMSS > uxNewMSS ) { - /* Confirm that the option fits in the remaining buffer space. */ - if( ( xRemainingOptionsBytes < TCP_OPT_MSS_LEN )|| ( pucPtr[ 1 ] != TCP_OPT_MSS_LEN ) ) + /* our MSS was bigger than the MSS of the other party: adapt it. */ + ( *ppxSocket )->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED; + if( ( ( *ppxTCPWindow ) != NULL ) && ( ( *ppxSocket )->u.xTCP.usCurMSS > uxNewMSS ) ) { - break; + /* The peer advertises a smaller MSS than this socket was + using. Use that as well. */ + FreeRTOS_debug_printf( ( "Change mss %d => %lu\n", ( *ppxSocket )->u.xTCP.usCurMSS, uxNewMSS ) ); + ( *ppxSocket )->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS; } + ( *ppxTCPWindow )->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( ( *ppxTCPWindow )->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) ); + ( *ppxTCPWindow )->usMSSInit = ( uint16_t ) uxNewMSS; + ( *ppxTCPWindow )->usMSS = ( uint16_t ) uxNewMSS; + ( *ppxSocket )->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS; + ( *ppxSocket )->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS; + } - /* An MSS option with the correct option length. FreeRTOS_htons() - is not needed here because usChar2u16() already returns a host - endian number. */ - uxNewMSS = usChar2u16( pucPtr + 2 ); + #if( ipconfigUSE_TCP_WIN != 1 ) + /* Without scaled windows, MSS is the only interesting option. */ + return pdFALSE; + #else + /* Or else we continue to check another option: selective ACK. */ + ( *ppucPtr ) += TCP_OPT_MSS_LEN; + #endif /* ipconfigUSE_TCP_WIN != 1 */ + } + else + { + /* All other options have a length field, so that we easily + can skip past them. */ + ucLen = ( *ppucPtr )[ 1 ]; + if( ( ucLen < 2 ) || ( ucLen > xRemainingOptionsBytes ) ) + { + /* If the length field is too small or too big, the options are + * malformed, don't process them further. + */ + return pdFALSE; + } - if( pxSocket->u.xTCP.usInitMSS != uxNewMSS ) + #if( ipconfigUSE_TCP_WIN == 1 ) + { + /* Selective ACK: the peer has received a packet but it is missing + * earlier packets. At least this packet does not need retransmission + * anymore. ulTCPWindowTxSack( ) takes care of this administration. + */ + if( ( *ppucPtr )[0] == TCP_OPT_SACK_A ) { - /* Perform a basic check on the the new MSS. */ - if( uxNewMSS == 0 ) - { - break; - } - - FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", pxSocket->u.xTCP.usInitMSS, uxNewMSS ) ); - } + ucLen -= 2; + ( *ppucPtr ) += 2; - if( pxSocket->u.xTCP.usInitMSS > uxNewMSS ) - { - /* our MSS was bigger than the MSS of the other party: adapt it. */ - pxSocket->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED; - if( ( pxTCPWindow != NULL ) && ( pxSocket->u.xTCP.usCurMSS > uxNewMSS ) ) + while( ucLen >= 8 ) { - /* The peer advertises a smaller MSS than this socket was - using. Use that as well. */ - FreeRTOS_debug_printf( ( "Change mss %d => %lu\n", pxSocket->u.xTCP.usCurMSS, uxNewMSS ) ); - pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS; + prvSkipPastRemainingOptions( ppucPtr, ppxSocket, &ucLen ); } - pxTCPWindow->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( pxTCPWindow->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) ); - pxTCPWindow->usMSSInit = ( uint16_t ) uxNewMSS; - pxTCPWindow->usMSS = ( uint16_t ) uxNewMSS; - pxSocket->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS; - pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS; + /* ucLen should be 0 by now. */ } - - #if( ipconfigUSE_TCP_WIN != 1 ) - /* Without scaled windows, MSS is the only interesting option. */ - break; - #else - /* Or else we continue to check another option: selective ACK. */ - pucPtr += TCP_OPT_MSS_LEN; - #endif /* ipconfigUSE_TCP_WIN != 1 */ } - else + #endif /* ipconfigUSE_TCP_WIN == 1 */ + + ( *ppucPtr ) += ucLen; + } + return pdTRUE; +} + +/*-----------------------------------------------------------*/ + +static void prvSkipPastRemainingOptions( const unsigned char ** const ppucPtr, FreeRTOS_Socket_t ** const ppxSocket, unsigned char * const pucLen ) +{ +uint32_t ulFirst = ulChar2u32( ( *ppucPtr ) ); +uint32_t ulLast = ulChar2u32( ( *ppucPtr ) + 4 ); +uint32_t ulCount = ulTCPWindowTxSack( &( *ppxSocket )->u.xTCP.xTCPWindow, ulFirst, ulLast ); + /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked + * starting from the head position. Advance the tail pointer in txStream. + */ + if( ( ( *ppxSocket )->u.xTCP.txStream != NULL ) && ( ulCount > 0 ) ) + { + /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */ + uxStreamBufferGet( ( *ppxSocket )->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE ); + ( *ppxSocket )->xEventBits |= eSOCKET_SEND; + + #if ipconfigSUPPORT_SELECT_FUNCTION == 1 { - /* All other options have a length field, so that we easily - can skip past them. */ - unsigned char len = pucPtr[ 1 ]; - if( ( len < 2 ) || ( len > xRemainingOptionsBytes ) ) + if( ( *ppxSocket )->xSelectBits & eSELECT_WRITE ) { - /* If the length field is too small or too big, the options are malformed. - Don't process them further. */ - break; + /* The field 'xEventBits' is used to store regular socket events + * (at most 8), as well as 'select events', which will be left-shifted. + */ + ( *ppxSocket )->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT ); } + } + #endif - #if( ipconfigUSE_TCP_WIN == 1 ) + /* In case the socket owner has installed an OnSent handler, call it now. + */ + #if( ipconfigUSE_CALLBACKS == 1 ) + { + if( ipconfigIS_VALID_PROG_ADDRESS( ( *ppxSocket )->u.xTCP.pxHandleSent ) ) { - /* Selective ACK: the peer has received a packet but it is missing earlier - packets. At least this packet does not need retransmission anymore - ulTCPWindowTxSack( ) takes care of this administration. */ - if( pucPtr[0] == TCP_OPT_SACK_A ) - { - len -= 2; - pucPtr += 2; - - while( len >= 8 ) - { - uint32_t ulFirst = ulChar2u32( pucPtr ); - uint32_t ulLast = ulChar2u32( pucPtr + 4 ); - uint32_t ulCount = ulTCPWindowTxSack( &pxSocket->u.xTCP.xTCPWindow, ulFirst, ulLast ); - /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked - starting from the head position. - Advance the tail pointer in txStream. */ - if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0 ) ) - { - /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */ - uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE ); - pxSocket->xEventBits |= eSOCKET_SEND; - - #if ipconfigSUPPORT_SELECT_FUNCTION == 1 - { - if( pxSocket->xSelectBits & eSELECT_WRITE ) - { - /* The field 'xEventBits' is used to store regular socket events (at most 8), - as well as 'select events', which will be left-shifted */ - pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT ); - } - } - #endif - - /* In case the socket owner has installed an OnSent handler, - call it now. */ - #if( ipconfigUSE_CALLBACKS == 1 ) - { - if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) ) - { - pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount ); - } - } - #endif /* ipconfigUSE_CALLBACKS == 1 */ - } - pucPtr += 8; - len -= 8; - } - /* len should be 0 by now. */ - } + ( *ppxSocket )->u.xTCP.pxHandleSent( (Socket_t )( *ppxSocket ), ulCount ); } - #endif /* ipconfigUSE_TCP_WIN == 1 */ - - pucPtr += len; } + #endif /* ipconfigUSE_CALLBACKS == 1 */ } + ( *ppucPtr ) += 8; + ( *pucLen ) -= 8; } + /*-----------------------------------------------------------*/ #if( ipconfigUSE_TCP_WIN != 0 ) @@ -1599,7 +1634,7 @@ BaseType_t bAfter = ( BaseType_t ) NOW_CONNECTED( eTCPState ); /* Is it co if( xConnected != NULL ) { /* The 'connected' state has changed, call the OnConnect handler of the parent. */ - xConnected->u.xTCP.pxHandleConnected( ( Socket_t * ) xConnected, bAfter ); + xConnected->u.xTCP.pxHandleConnected( ( Socket_t ) xConnected, bAfter ); } } #endif @@ -2416,7 +2451,7 @@ int32_t lDistance, lSendResult; { if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) ) { - pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount ); + pxSocket->u.xTCP.pxHandleSent( ( Socket_t )pxSocket, ulCount ); } } #endif /* ipconfigUSE_CALLBACKS == 1 */ @@ -2836,41 +2871,41 @@ TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow ); } /*-----------------------------------------------------------*/ -static BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t *pxNetworkBuffer, - uint8_t ucTCPFlags ) +static BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t *pxNetworkBuffer, + uint8_t ucTCPFlags ) { #if( ipconfigIGNORE_UNKNOWN_PACKETS == 0 ) - { - TCPPacket_t *pxTCPPacket = ( TCPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer ); - const BaseType_t xSendLength = ( BaseType_t ) - ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + 0u ); /* Plus 0 options. */ + { + TCPPacket_t *pxTCPPacket = ( TCPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer ); + const BaseType_t xSendLength = ( BaseType_t ) + ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + 0u ); /* Plus 0 options. */ - pxTCPPacket->xTCPHeader.ucTCPFlags = ucTCPFlags; - pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER + 0u ) << 2; + pxTCPPacket->xTCPHeader.ucTCPFlags = ucTCPFlags; + pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER + 0u ) << 2; - prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t )xSendLength, pdFALSE ); - } + prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t )xSendLength, pdFALSE ); + } #endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */ - /* Remove compiler warnings if ipconfigIGNORE_UNKNOWN_PACKETS == 1. */ - ( void )pxNetworkBuffer; - ( void )ucTCPFlags; + /* Remove compiler warnings if ipconfigIGNORE_UNKNOWN_PACKETS == 1. */ + ( void )pxNetworkBuffer; + ( void )ucTCPFlags; - /* The packet was not consumed. */ - return pdFAIL; + /* The packet was not consumed. */ + return pdFAIL; } /*-----------------------------------------------------------*/ static BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t *pxNetworkBuffer ) { - return prvTCPSendSpecialPacketHelper( pxNetworkBuffer, ipTCP_FLAG_ACK ); + return prvTCPSendSpecialPacketHelper( pxNetworkBuffer, ipTCP_FLAG_ACK ); } /*-----------------------------------------------------------*/ static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer ) { - return prvTCPSendSpecialPacketHelper( pxNetworkBuffer, - ipTCP_FLAG_ACK | ipTCP_FLAG_RST ); + return prvTCPSendSpecialPacketHelper( pxNetworkBuffer, + ipTCP_FLAG_ACK | ipTCP_FLAG_RST ); } /*-----------------------------------------------------------*/ @@ -2914,9 +2949,8 @@ uint16_t xRemotePort; uint32_t ulSequenceNumber; uint32_t ulAckNumber; BaseType_t xResult = pdPASS; - - configASSERT( pxNetworkBuffer ); - configASSERT( pxNetworkBuffer->pucEthernetBuffer ); +configASSERT(pxNetworkBuffer); +configASSERT(pxNetworkBuffer->pucEthernetBuffer); /* Check for a minimum packet size. */ if( pxNetworkBuffer->xDataLength >= ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) @@ -2926,8 +2960,8 @@ BaseType_t xResult = pdPASS; xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort ); ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress ); xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort ); - ulSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber ); - ulAckNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ); + ulSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber ); + ulAckNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ); /* Find the destination socket, and if not found: return a socket listing to the destination PORT. */ @@ -3007,36 +3041,36 @@ BaseType_t xResult = pdPASS; flag. */ if( ( ucTCPFlags & ipTCP_FLAG_RST ) != 0u ) { - FreeRTOS_debug_printf( ( "TCP: RST received from %lxip:%u for %u\n", ulRemoteIP, xRemotePort, xLocalPort ) ); - - /* Implement https://tools.ietf.org/html/rfc5961#section-3.2. */ - if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) - { - /* Per the above RFC, "In the SYN-SENT state ... the RST is - acceptable if the ACK field acknowledges the SYN." */ - if( ulAckNumber == pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber + 1 ) - { - vTCPStateChange( pxSocket, eCLOSED ); - } - } - else - { - /* Check whether the packet matches the next expected sequence number. */ - if( ulSequenceNumber == pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber ) - { - vTCPStateChange( pxSocket, eCLOSED ); - } - /* Otherwise, check whether the packet is within the receive window. */ - else if( ulSequenceNumber > pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber && - ulSequenceNumber < ( pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber + - pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength ) ) - { - /* Send a challenge ACK. */ - prvTCPSendChallengeAck( pxNetworkBuffer ); - } - } - - /* Otherwise, do nothing. In any case, the packet cannot be handled. */ + FreeRTOS_debug_printf( ( "TCP: RST received from %lxip:%u for %u\n", ulRemoteIP, xRemotePort, xLocalPort ) ); + + /* Implement https://tools.ietf.org/html/rfc5961#section-3.2. */ + if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) + { + /* Per the above RFC, "In the SYN-SENT state ... the RST is + acceptable if the ACK field acknowledges the SYN." */ + if( ulAckNumber == pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber + 1 ) + { + vTCPStateChange( pxSocket, eCLOSED ); + } + } + else + { + /* Check whether the packet matches the next expected sequence number. */ + if( ulSequenceNumber == pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber ) + { + vTCPStateChange( pxSocket, eCLOSED ); + } + /* Otherwise, check whether the packet is within the receive window. */ + else if( ulSequenceNumber > pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber && + ulSequenceNumber < ( pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber + + pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength ) ) + { + /* Send a challenge ACK. */ + prvTCPSendChallengeAck( pxNetworkBuffer ); + } + } + + /* Otherwise, do nothing. In any case, the packet cannot be handled. */ xResult = pdFAIL; } else if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) ) diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c index 784eb48aa..cda8acd1c 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -675,17 +675,17 @@ const int32_t l500ms = 500; #if( ipconfigUSE_TCP_WIN == 1 ) - void vTCPSegmentCleanup( void ) - { - /* Free and clear the TCP segments pointer. This function should only be called - * once FreeRTOS+TCP will no longer be used. No thread-safety is provided for this - * function. */ - if( xTCPSegments != NULL ) - { - vPortFreeLarge( xTCPSegments ); - xTCPSegments = NULL; - } - } + void vTCPSegmentCleanup( void ) + { + /* Free and clear the TCP segments pointer. This function should only be called + * once FreeRTOS+TCP will no longer be used. No thread-safety is provided for this + * function. */ + if( xTCPSegments != NULL ) + { + vPortFreeLarge( xTCPSegments ); + xTCPSegments = NULL; + } + } #endif /* ipconfgiUSE_TCP_WIN == 1 */ /*-----------------------------------------------------------*/ @@ -805,20 +805,20 @@ const int32_t l500ms = 500; { ulSavedSequenceNumber = ulCurrentSequenceNumber; - /* Clean up all sequence received between ulSequenceNumber and ulSequenceNumber + ulLength since they are duplicated. - If the server is forced to retransmit packets several time in a row it might send a batch of concatenated packet for speed. - So we cannot rely on the packets between ulSequenceNumber and ulSequenceNumber + ulLength to be sequential and it is better to just - clean them out. */ - do - { - pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength ); - - if ( pxFound != NULL ) - { - /* Remove it because it will be passed to user directly. */ - vTCPWindowFree( pxFound ); - } - } while ( pxFound ); + /* Clean up all sequence received between ulSequenceNumber and ulSequenceNumber + ulLength since they are duplicated. + If the server is forced to retransmit packets several time in a row it might send a batch of concatenated packet for speed. + So we cannot rely on the packets between ulSequenceNumber and ulSequenceNumber + ulLength to be sequential and it is better to just + clean them out. */ + do + { + pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength ); + + if ( pxFound != NULL ) + { + /* Remove it because it will be passed to user directly. */ + vTCPWindowFree( pxFound ); + } + } while ( pxFound ); /* Check for following segments that are already in the queue and increment ulCurrentSequenceNumber. */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c index 8112e3358..c8de69790 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -78,10 +78,22 @@ UDPPacket_t *pxUDPPacket; IPHeader_t *pxIPHeader; eARPLookupResult_t eReturned; uint32_t ulIPAddress = pxNetworkBuffer->ulIPAddress; +size_t uxPayloadSize; /* Map the UDP packet onto the start of the frame. */ pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer; +#if ipconfigSUPPORT_OUTGOING_PINGS == 1 + if( pxNetworkBuffer->usPort == ipPACKET_CONTAINS_ICMP_DATA ) + { + uxPayloadSize = pxNetworkBuffer->xDataLength - sizeof( ICMPPacket_t ); + } + else +#endif + { + uxPayloadSize = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t ); + } + /* Determine the ARP cache status for the requested IP address. */ eReturned = eARPGetCacheEntry( &( ulIPAddress ), &( pxUDPPacket->xEthernetHeader.xDestinationAddress ) ); @@ -109,7 +121,7 @@ uint32_t ulIPAddress = pxNetworkBuffer->ulIPAddress; pxUDPHeader->usDestinationPort = pxNetworkBuffer->usPort; pxUDPHeader->usSourcePort = pxNetworkBuffer->usBoundPort; - pxUDPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) ); + pxUDPHeader->usLength = ( uint16_t ) ( uxPayloadSize + sizeof( UDPHeader_t ) ); pxUDPHeader->usLength = FreeRTOS_htons( pxUDPHeader->usLength ); pxUDPHeader->usChecksum = 0u; } @@ -143,16 +155,14 @@ uint32_t ulIPAddress = pxNetworkBuffer->ulIPAddress; if( pxNetworkBuffer->usPort == ipPACKET_CONTAINS_ICMP_DATA ) { pxIPHeader->ucProtocol = ipPROTOCOL_ICMP; - pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( IPHeader_t ) ); + pxIPHeader->usLength = ( uint16_t ) ( uxPayloadSize + sizeof( IPHeader_t ) + sizeof( ICMPHeader_t ) ); } else #endif /* ipconfigSUPPORT_OUTGOING_PINGS */ { - pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( IPHeader_t ) + sizeof( UDPHeader_t ) ); + pxIPHeader->usLength = ( uint16_t ) ( uxPayloadSize + sizeof( IPHeader_t ) + sizeof( UDPHeader_t ) ); } - /* The total transmit size adds on the Ethernet header. */ - pxNetworkBuffer->xDataLength = pxIPHeader->usLength + sizeof( EthernetHeader_t ); pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength ); /* HT:endian: changed back to network endian */ pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress; @@ -240,13 +250,12 @@ BaseType_t xProcessReceivedUDPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer { BaseType_t xReturn = pdPASS; FreeRTOS_Socket_t *pxSocket; -UDPPacket_t *pxUDPPacket; +configASSERT(pxNetworkBuffer); +configASSERT(pxNetworkBuffer->pucEthernetBuffer); - configASSERT( pxNetworkBuffer ); - configASSERT( pxNetworkBuffer->pucEthernetBuffer ); - pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer; - +UDPPacket_t *pxUDPPacket = (UDPPacket_t *) pxNetworkBuffer->pucEthernetBuffer; + /* Caller must check for minimum packet size. */ pxSocket = pxUDPSocketLookup( usPort ); @@ -271,7 +280,8 @@ UDPPacket_t *pxUDPPacket; destinationAddress.sin_port = usPort; destinationAddress.sin_addr = pxUDPPacket->xIPHeader.ulDestinationIPAddress; - if( xHandler( ( Socket_t * ) pxSocket, ( void* ) pcData, ( size_t ) pxNetworkBuffer->xDataLength, + /* The value of 'xDataLength' was proven to be at least the size of a UDP packet in prvProcessIPPacket(). */ + if( xHandler( ( Socket_t ) pxSocket, ( void* ) pcData, ( size_t ) ( pxNetworkBuffer->xDataLength - ipUDP_PAYLOAD_OFFSET_IPv4 ), &xSourceAddress, &destinationAddress ) ) { xReturn = pdFAIL; /* FAIL means that we did not consume or release the buffer */ @@ -351,6 +361,19 @@ UDPPacket_t *pxUDPPacket; /* There is no socket listening to the target port, but still it might be for this node. */ + #if( ipconfigUSE_DNS == 1 ) && ( ipconfigDNS_USE_CALLBACKS == 1 ) + /* A DNS reply, check for the source port. Although the DNS client + does open a UDP socket to send a messages, this socket will be + closed after a short timeout. Messages that come late (after the + socket is closed) will be treated here. */ + if( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usSourcePort ) == ipDNS_PORT ) + { + vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress ); + xReturn = ( BaseType_t )ulDNSHandlePacket( pxNetworkBuffer ); + } + else + #endif + #if( ipconfigUSE_LLMNR == 1 ) /* a LLMNR request, check for the destination port. */ if( ( usPort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) || diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/History.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/History.txt index 07ad698a2..52565cc86 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/History.txt +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/History.txt @@ -1,7 +1,3 @@ -Changes in V2.0.11 - - + Updates some drivers in the portable layer. - Changes between 160919 and 180821 releases: + Multiple security improvements and fixes in packet parsing routines, DNS @@ -9,17 +5,7 @@ Changes between 160919 and 180821 releases: + Disable NBNS and LLMNR by default. + Add TCP hang protection by default. - We thank Ori Karliner of Zimperium zLabs Team for reporting these issues. - - + Update FreeRTOS_gethostbyname() to allow an IP address to be passed in - - in which case it is just returned as a uint32_t. - + Introduce ipconfigSOCKET_HAS_USER_WAKE_CALLBACK to FreeRTOS_Sockets.c to - allow a user supposed callback function to be executed when socket events - occur in the same way that the socket semaphore is currently used. - + Update xNetworkBuffersInitialise() to ensure the semaphore created by the - function is not accessed until after the NULL check. - + Improve print messages output by the Win32 port layer version of - prvPrintAvailableNetworkInterfaces(). +We thank Ori Karliner of Zimperium zLabs Team for reporting these issues. Changes between 160908 and 160919 releases: @@ -188,4 +174,4 @@ Changes between 141019 and 150825 + Fix: Previously if a listening socket was reused, and a connection failed, the TCP/IP stack closed the socket, now the socket is correctly left unclosed as it is owned by the application. - + Various other formatting and minor fix alterations. \ No newline at end of file + + Various other formatting and minor fix alterations. diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h index ebe531ea0..20cdf739f 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -169,6 +169,14 @@ from the FreeRTOSIPConfig.h configuration header file. */ #define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME portMAX_DELAY #endif + +#ifndef ipconfigDNS_RECEIVE_BLOCK_TIME_TICKS + #define ipconfigDNS_RECEIVE_BLOCK_TIME_TICKS pdMS_TO_TICKS( 500u ) +#endif + +#ifndef ipconfigDNS_SEND_BLOCK_TIME_TICKS + #define ipconfigDNS_SEND_BLOCK_TIME_TICKS pdMS_TO_TICKS( 500u ) +#endif /* * FreeRTOS debug logging routine (proposal) * The macro will be called in the printf() style. Users can define @@ -375,6 +383,14 @@ from the FreeRTOSIPConfig.h configuration header file. */ #endif /* _WINDOWS_ */ #endif /* ipconfigMAXIMUM_DISCOVER_TX_PERIOD */ +#if( ipconfigUSE_DNS == 0 ) + /* The DNS module will not be included. */ + #if( ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) ) + /* LLMNR and NBNS depend on DNS because those protocols share a lot of code. */ + #error When either LLMNR or NBNS is used, ipconfigUSE_DNS must be defined + #endif +#endif + #ifndef ipconfigUSE_DNS #define ipconfigUSE_DNS 1 #endif @@ -408,13 +424,6 @@ from the FreeRTOSIPConfig.h configuration header file. */ #define ipconfigUSE_LLMNR ( 0 ) #endif -#if( !defined( ipconfigUSE_DNS ) ) - #if( ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) ) - /* LLMNR and NBNS depend on DNS because those protocols share a lot of code. */ - #error When either LLMNR or NBNS is used, ipconfigUSE_DNS must be defined - #endif -#endif - #ifndef ipconfigREPLY_TO_INCOMING_PINGS #define ipconfigREPLY_TO_INCOMING_PINGS 1 #endif diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h index 563236b7b..166bf3a97 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -42,9 +42,9 @@ extern "C" { typedef struct xARP_CACHE_TABLE_ROW { uint32_t ulIPAddress; /* The IP address of an ARP cache entry. */ - MACAddress_t xMACAddress; /* The MAC address of an ARP cache entry. */ + MACAddress_t xMACAddress; /* The MAC address of an ARP cache entry. */ uint8_t ucAge; /* A value that is periodically decremented but can also be refreshed by active communication. The ARP cache entry is removed if the value reaches zero. */ - uint8_t ucValid; /* pdTRUE: xMACAddress is valid, pdFALSE: waiting for ARP reply */ + uint8_t ucValid; /* pdTRUE: xMACAddress is valid, pdFALSE: waiting for ARP reply */ } ARPCacheRow_t; typedef enum diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h index 64421e5ff..6a6d372b6 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h index 67257daac..449fa514f 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -84,12 +84,12 @@ uint32_t ulDNSHandlePacket( NetworkBufferDescriptor_t *pxNetworkBuffer ); #if( ipconfigUSE_DNS_CACHE != 0 ) - /* Look for the indicated host name in the DNS cache. Returns the IPv4 - address if present, or 0x0 otherwise. */ + /* Look for the indicated host name in the DNS cache. Returns the IPv4 + address if present, or 0x0 otherwise. */ uint32_t FreeRTOS_dnslookup( const char *pcHostName ); - /* Remove all entries from the DNS cache. */ - void FreeRTOS_dnsclear(); + /* Remove all entries from the DNS cache. */ + void FreeRTOS_dnsclear(); #endif /* ipconfigUSE_DNS_CACHE != 0 */ #if( ipconfigDNS_USE_CALLBACKS != 0 ) diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h index 1ac4ed77c..6bfb4ad42 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -275,6 +275,15 @@ void FreeRTOS_ClearARP( void ); #endif /* ipconfigDHCP_REGISTER_HOSTNAME */ +/* This xApplicationGetRandomNumber() will set *pulNumber to a random number, +and return pdTRUE. When the random number generator is broken, it shall return +pdFALSE. +The function is defined in 'iot_secure_sockets.c'. +If that module is not included in the project, the application must provide an +implementation of it. +The macro's ipconfigRAND32() and configRAND32() are not in use anymore. */ +BaseType_t xApplicationGetRandomNumber( uint32_t *pulNumber ); + /* For backward compatibility define old structure names to the newer equivalent structure name. */ #ifndef ipconfigENABLE_BACKWARD_COMPATIBILITY diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h index 641539ea0..8604abed0 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -41,10 +41,6 @@ extern "C" { #include "FreeRTOS_TCP_IP.h" #endif -#if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 ) - #include "semphr.h" -#endif - #include "event_groups.h" typedef struct xNetworkAddressingParameters @@ -248,16 +244,17 @@ typedef enum eNoEvent = -1, eNetworkDownEvent, /* 0: The network interface has been lost and/or needs [re]connecting. */ eNetworkRxEvent, /* 1: The network interface has queued a received Ethernet frame. */ - eARPTimerEvent, /* 2: The ARP timer expired. */ - eStackTxEvent, /* 3: The software stack has queued a packet to transmit. */ - eDHCPEvent, /* 4: Process the DHCP state machine. */ - eTCPTimerEvent, /* 5: See if any TCP socket needs attention. */ - eTCPAcceptEvent, /* 6: Client API FreeRTOS_accept() waiting for client connections. */ - eTCPNetStat, /* 7: IP-task is asked to produce a netstat listing. */ - eSocketBindEvent, /* 8: Send a message to the IP-task to bind a socket to a port. */ - eSocketCloseEvent, /* 9: Send a message to the IP-task to close a socket. */ - eSocketSelectEvent, /*10: Send a message to the IP-task for select(). */ - eSocketSignalEvent, /*11: A socket must be signalled. */ + eNetworkTxEvent, /* 2: Let the IP-task send a network packet. */ + eARPTimerEvent, /* 3: The ARP timer expired. */ + eStackTxEvent, /* 4: The software stack has queued a packet to transmit. */ + eDHCPEvent, /* 5: Process the DHCP state machine. */ + eTCPTimerEvent, /* 6: See if any TCP socket needs attention. */ + eTCPAcceptEvent, /* 7: Client API FreeRTOS_accept() waiting for client connections. */ + eTCPNetStat, /* 8: IP-task is asked to produce a netstat listing. */ + eSocketBindEvent, /* 9: Send a message to the IP-task to bind a socket to a port. */ + eSocketCloseEvent, /*10: Send a message to the IP-task to close a socket. */ + eSocketSelectEvent, /*11: Send a message to the IP-task for select(). */ + eSocketSignalEvent, /*12: A socket must be signalled. */ } eIPEvent_t; typedef struct IP_TASK_COMMANDS @@ -460,8 +457,8 @@ BaseType_t vNetworkSocketsInit( void ); BaseType_t xIPIsNetworkTaskReady( void ); #if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK == 1 ) - struct XSOCKET; - typedef void (*SocketWakeupCallback_t)( struct XSOCKET * pxSocket ); + struct xSOCKET; + typedef void (*SocketWakeupCallback_t)( struct xSOCKET * pxSocket ); #endif #if( ipconfigUSE_TCP == 1 ) @@ -548,7 +545,7 @@ BaseType_t xIPIsNetworkTaskReady( void ); * This counter is separate from the xmitCount in the * TCP win segments */ uint8_t ucTCPState; /* TCP state: see eTCP_STATE */ - struct XSOCKET *pxPeerSocket; /* for server socket: child, for child socket: parent */ + struct xSOCKET *pxPeerSocket; /* for server socket: child, for child socket: parent */ #if( ipconfigTCP_KEEP_ALIVE == 1 ) uint8_t ucKeepRepCount; TickType_t xLastAliveTime; @@ -615,7 +612,7 @@ typedef enum eSOCKET_EVENT { eSOCKET_ALL = 0x007F, } eSocketEvent_t; -typedef struct XSOCKET +typedef struct xSOCKET { EventBits_t xEventBits; EventGroupHandle_t xEventGroup; diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h index 92c251942..88d3bba65 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -55,7 +55,7 @@ extern "C" { /* Assigned to an Socket_t variable when the socket is not valid, probably because it could not be created. */ -#define FREERTOS_INVALID_SOCKET ( ( void * ) ~0U ) +#define FREERTOS_INVALID_SOCKET ( ( Socket_t ) ~0U ) /* API function error values. As errno is supported, the FreeRTOS sockets functions return error codes rather than just a pass or fail indication. */ @@ -213,11 +213,13 @@ struct freertos_sockaddr #endif /* ipconfigBYTE_ORDER */ /* The socket type itself. */ -typedef void *Socket_t; +struct xSOCKET; +typedef struct xSOCKET *Socket_t; /* The SocketSet_t type is the equivalent to the fd_set type used by the Berkeley API. */ -typedef void *SocketSet_t; +struct xSOCKET_SET; +typedef struct xSOCKET_SET *SocketSet_t; /** * FULL, UP-TO-DATE AND MAINTAINED REFERENCE DOCUMENTATION FOR ALL THESE diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h index 1ebb86d8d..95bbbdf0a 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -157,31 +157,6 @@ size_t uxSize = uxStreamBufferMidSpace( pxBuffer ); } } /*-----------------------------------------------------------*/ -static portINLINE BaseType_t xStreamBufferIsEmpty( const StreamBuffer_t *pxBuffer ); -static portINLINE BaseType_t xStreamBufferIsEmpty( const StreamBuffer_t *pxBuffer ) -{ -BaseType_t xReturn; - - /* True if no item is available */ - if( pxBuffer->uxHead == pxBuffer->uxTail ) - { - xReturn = pdTRUE; - } - else - { - xReturn = pdFALSE; - } - return xReturn; -} -/*-----------------------------------------------------------*/ - -static portINLINE BaseType_t xStreamBufferIsFull( const StreamBuffer_t *pxBuffer ); -static portINLINE BaseType_t xStreamBufferIsFull( const StreamBuffer_t *pxBuffer ) -{ - /* True if the available space equals zero. */ - return ( BaseType_t ) ( uxStreamBufferGetSpace( pxBuffer ) == 0u ); -} -/*-----------------------------------------------------------*/ static portINLINE BaseType_t xStreamBufferLessThenEqual( const StreamBuffer_t *pxBuffer, const size_t uxLeft, const size_t uxRight ); static portINLINE BaseType_t xStreamBufferLessThenEqual( const StreamBuffer_t *pxBuffer, const size_t uxLeft, const size_t uxRight ) diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h index 503fa101b..76738c460 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h index 691332289..9532fd159 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h index 991595216..a7463fcee 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h index fffe22df0..534f5261d 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h index 3fa8eab8b..316e18f56 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h index 8e4f90315..0fcde3439 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 @@ -47,7 +47,7 @@ UBaseType_t uxGetMinimumFreeNetworkBuffers( void ); /* Copy a network buffer into a bigger buffer. */ NetworkBufferDescriptor_t *pxDuplicateNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer, - BaseType_t xNewLength); + size_t uxNewLength); /* Increase the size of a Network Buffer. In case BufferAllocation_2.c is used, the new space must be allocated. */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h index 2924b7976..c3d3fb4bc 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.11 + * FreeRTOS+TCP V2.2.0 * 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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c index 3540b15c2..fa3f4333f 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c @@ -280,13 +280,6 @@ UBaseType_t uxCount; pxReturn->pxNextBuffer = NULL; } #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ - - if( xTCPWindowLoggingLevel > 3 ) - { - FreeRTOS_debug_printf( ( "BUF_GET[%ld]: %p (%p)\n", - bIsValidNetworkDescriptor( pxReturn ), - pxReturn, pxReturn->pucEthernetBuffer ) ); - } } iptraceNETWORK_BUFFER_OBTAINED( pxReturn ); } @@ -390,11 +383,6 @@ BaseType_t xListItemAlreadyInFreeList; { xSemaphoreGive( xNetworkBufferSemaphore ); prvShowWarnings(); - if( xTCPWindowLoggingLevel > 3 ) - FreeRTOS_debug_printf( ( "BUF_PUT[%ld]: %p (%p) (now %lu)\n", - bIsValidNetworkDescriptor( pxNetworkBuffer ), - pxNetworkBuffer, pxNetworkBuffer->pucEthernetBuffer, - uxGetNumberOfFreeNetworkBuffers( ) ) ); } iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); } diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Keil/pack_struct_end.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Keil/pack_struct_end.h new file mode 100644 index 000000000..816b0b3b6 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Keil/pack_struct_end.h @@ -0,0 +1,33 @@ +/* +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 +*/ + +/***************************************************************************** + * + * See the following URL for an explanation of this file: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html + * + *****************************************************************************/ +; +#pragma pack(pop) diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Keil/pack_struct_start.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Keil/pack_struct_start.h new file mode 100644 index 000000000..29ea9ae3e --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Keil/pack_struct_start.h @@ -0,0 +1,48 @@ +/* +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 +*/ + +/***************************************************************************** + * + * See the following URL for an explanation of this file: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html + * + *****************************************************************************/ + +#pragma pack(push,1) + + + + + + + + + + + + + + + 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 4b549b084..83c96a07c 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,28 +1,27 @@ /* - * 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 - */ - +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 @@ -83,10 +82,6 @@ expansion. */ #error Please define GMAC_USES_TX_CALLBACK as 1 #endif -#if( ipconfigZERO_COPY_RX_DRIVER != 0 ) - #warning The EMAC of SAM4E has fixed-size RX buffers so ZERO_COPY_RX is not possible -#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. */ @@ -239,7 +234,7 @@ const TickType_t x5_Seconds = 5000UL; configASSERT( xTXDescriptorSemaphore ); } /* When returning non-zero, the stack will become active and - start DHCP (in configured) */ + start DHCP (in configured) */ return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0; } /*-----------------------------------------------------------*/ @@ -418,11 +413,11 @@ const TickType_t xShortTime = pdMS_TO_TICKS( 100UL ); if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) { - IPHeader_t *pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader ); + IPHeader_t *pxIPHeader = &(xProtPacket->xTCPPacket.xIPHeader); /* Calculate the IP header checksum. */ pxIPHeader->usHeaderChecksum = 0x00; - pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0u, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER ); + 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. */ @@ -504,43 +499,15 @@ static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; } /*-----------------------------------------------------------*/ -void vCheckBuffersAndQueue( void ) -{ -static UBaseType_t uxLastMinBufferCount = 0; -#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) - static UBaseType_t uxLastMinQueueSpace; -#endif -static UBaseType_t 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 */ - 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 ) ); - } - -} - static void prvEMACHandlerTask( void *pvParameters ) { TimeOut_t xPhyTime; TickType_t xPhyRemTime; -UBaseType_t uxCount; +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 @@ -559,7 +526,28 @@ const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS ); for( ;; ) { - vCheckBuffersAndQueue(); + 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 ) { diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c index fe73a73ac..948f9a661 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c @@ -429,7 +429,6 @@ void gmac_dev_init(Gmac* p_gmac, gmac_device_t* p_gmac_dev, * GMAC_DCFGR_TXCOEN: (GMAC_DCFGR) Transmitter Checksum Generation Offload Enable. * Note: tha SAM4E does have RX checksum offloading * but TX checksum offloading has NOT been implemented. - * http://community.atmel.com/forum/sam4e-gmac-transmit-checksum-offload-enablesolved */ gmac_set_dma(p_gmac, @@ -658,7 +657,7 @@ uint32_t gmac_dev_write(gmac_device_t* p_gmac_dev, void *p_buffer, } #else { - /* Or memcopy... */ + /* Or Memcopy... */ memcpy((void *)p_tx_td->addr, p_buffer, ul_size); } #endif /* ipconfigZERO_COPY_TX_DRIVER */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Common/phyHandling.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Common/phyHandling.c index bf44d981b..fa7695942 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Common/phyHandling.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Common/phyHandling.c @@ -1,28 +1,3 @@ -/* - * 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 - */ - /* * Handling of Ethernet PHY's * PHY's communicate with an EMAC either through @@ -57,14 +32,29 @@ #endif #ifndef ipconfigPHY_LS_HIGH_CHECK_TIME_MS - /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not + /* Check if the LinkStatus in the PHY is still high after 15 seconds of not receiving packets. */ - #define ipconfigPHY_LS_HIGH_CHECK_TIME_MS 15000 + #define ipconfigPHY_LS_HIGH_CHECK_TIME_MS 15000uL #endif #ifndef ipconfigPHY_LS_LOW_CHECK_TIME_MS - /* Check if the LinkSStatus in the PHY is still low every second. */ - #define ipconfigPHY_LS_LOW_CHECK_TIME_MS 1000 + /* Check if the LinkStatus in the PHY is still low every second. */ + #define ipconfigPHY_LS_LOW_CHECK_TIME_MS 1000uL +#endif + +/* As the following 3 macro's are OK in most situations, and so they're not +included in 'FreeRTOSIPConfigDefaults.h'. +Users can change their values in the project's 'FreeRTOSIPConfig.h'. */ +#ifndef phyPHY_MAX_RESET_TIME_MS + #define phyPHY_MAX_RESET_TIME_MS 1000uL +#endif + +#ifndef phyPHY_MAX_NEGOTIATE_TIME_MS + #define phyPHY_MAX_NEGOTIATE_TIME_MS 3000uL +#endif + +#ifndef phySHORT_DELAY_MS + #define phySHORT_DELAY_MS 50uL #endif /* Naming and numbering of basic PHY registers. */ @@ -113,16 +103,18 @@ * Description of all capabilities that can be advertised to * the peer (usually a switch or router). */ -#define phyADVERTISE_CSMA 0x0001u /* Only selector supported. */ + +#define phyADVERTISE_CSMA 0x0001u /* Supports IEEE 802.3u: Fast Ethernet at 100 Mbit/s */ #define phyADVERTISE_10HALF 0x0020u /* Try for 10mbps half-duplex. */ #define phyADVERTISE_10FULL 0x0040u /* Try for 10mbps full-duplex. */ #define phyADVERTISE_100HALF 0x0080u /* Try for 100mbps half-duplex. */ #define phyADVERTISE_100FULL 0x0100u /* Try for 100mbps full-duplex. */ #define phyADVERTISE_ALL ( phyADVERTISE_10HALF | phyADVERTISE_10FULL | \ - phyADVERTISE_100HALF | phyADVERTISE_100FULL ) + phyADVERTISE_100HALF | phyADVERTISE_100FULL | \ + phyADVERTISE_CSMA ) -/* Send a reset commando to a set of PHY-ports. */ +/* Send a reset command to a set of PHY-ports. */ static uint32_t xPhyReset( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask ); static BaseType_t xHas_1F_PHYSPCS( uint32_t ulPhyID ) @@ -224,7 +216,7 @@ BaseType_t xPhyAddress; } /*-----------------------------------------------------------*/ -/* Send a reset commando to a set of PHY-ports. */ +/* Send a reset command to a set of PHY-ports. */ static uint32_t xPhyReset( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask ) { uint32_t ulDoneMask, ulConfig; @@ -232,7 +224,7 @@ TickType_t xRemainingTime; TimeOut_t xTimer; BaseType_t xPhyIndex; - /* A bit-mask ofPHY ports that are ready. */ + /* A bit-mask of PHY ports that are ready. */ ulDoneMask = 0ul; /* Set the RESET bits high. */ @@ -245,7 +237,7 @@ BaseType_t xPhyIndex; pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulConfig | phyBMCR_RESET ); } - xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( 1000UL ); + xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( phyPHY_MAX_RESET_TIME_MS ); vTaskSetTimeOutState( &xTimer ); /* The reset should last less than a second. */ @@ -272,19 +264,23 @@ BaseType_t xPhyIndex; break; } /* Block for a while */ - vTaskDelay( pdMS_TO_TICKS( 50ul ) ); + vTaskDelay( pdMS_TO_TICKS( phySHORT_DELAY_MS ) ); } /* Clear the reset bits. */ for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ ) { - BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ]; + if( ( ulDoneMask & ( 1ul << xPhyIndex ) ) == 0uL ) + { + BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ]; - pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig ); - pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulConfig & ~phyBMCR_RESET ); + /* The reset operation timed out, clear the bit manually. */ + pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig ); + pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulConfig & ~phyBMCR_RESET ); + } } - vTaskDelay( pdMS_TO_TICKS( 50ul ) ); + vTaskDelay( pdMS_TO_TICKS( phySHORT_DELAY_MS ) ); return ulDoneMask; } @@ -297,7 +293,7 @@ BaseType_t xPhyIndex; if( pxPhyObject->xPortCount < 1 ) { - FreeRTOS_printf( ( "xPhyResetAll: No PHY's detected.\n" ) ); + FreeRTOS_printf( ( "xPhyConfigure: No PHY's detected.\n" ) ); return -1; } @@ -308,11 +304,12 @@ BaseType_t xPhyIndex; /* Set advertise register. */ if( ( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO ) && ( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO ) ) { - ulAdvertise = phyADVERTISE_CSMA | phyADVERTISE_ALL; + ulAdvertise = phyADVERTISE_ALL; /* Reset auto-negotiation capability. */ } else { + /* Always select protocol 802.3u. */ ulAdvertise = phyADVERTISE_CSMA; if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO ) @@ -361,7 +358,7 @@ BaseType_t xPhyIndex; } } - /* Send a reset commando to a set of PHY-ports. */ + /* Send a reset command to a set of PHY-ports. */ xPhyReset( pxPhyObject, xPhyGetMask( pxPhyObject ) ); for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ ) @@ -450,6 +447,10 @@ BaseType_t xPhyIndex; } /*-----------------------------------------------------------*/ +/* xPhyFixedValue(): this function is called in case auto-negotiation is disabled. +The caller has set the values in 'xPhyPreferences' (ucDuplex and ucSpeed). +The PHY register phyREG_00_BMCR will be set for every connected PHY that matches +with ulPhyMask. */ BaseType_t xPhyFixedValue( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask ) { BaseType_t xPhyIndex; @@ -480,6 +481,9 @@ uint32_t ulValue, ulBitMask = ( uint32_t )1u; } /*-----------------------------------------------------------*/ +/* xPhyStartAutoNegotiation() is the alternative xPhyFixedValue(): +It sets the BMCR_AN_RESTART bit and waits for the auto-negotiation completion +( phyBMSR_AN_COMPLETE ). */ BaseType_t xPhyStartAutoNegotiation( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask ) { uint32_t xPhyIndex, ulDoneMask, ulBitMask; @@ -491,7 +495,7 @@ TimeOut_t xTimer; { return 0; } - for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ ) + for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++ ) { if( ( ulPhyMask & ( 1lu << xPhyIndex ) ) != 0lu ) { @@ -502,14 +506,14 @@ TimeOut_t xTimer; pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, pxPhyObject->ulBCRValue | phyBMCR_AN_RESTART ); } } - xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( 3000UL ); + xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( phyPHY_MAX_NEGOTIATE_TIME_MS ); vTaskSetTimeOutState( &xTimer ); ulDoneMask = 0; /* Wait until the auto-negotiation will be completed */ for( ;; ) { ulBitMask = ( uint32_t )1u; - for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 ) + for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 ) { if( ( ulPhyMask & ulBitMask ) != 0lu ) { @@ -531,17 +535,17 @@ TimeOut_t xTimer; } if( xTaskCheckForTimeOut( &xTimer, &xRemainingTime ) != pdFALSE ) { - FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET timed out ( done 0x%02lX )\n", ulDoneMask ) ); + FreeRTOS_printf( ( "xPhyStartAutoNegotiation: phyBMCR_RESET timed out ( done 0x%02lX )\n", ulDoneMask ) ); break; } - vTaskDelay( pdMS_TO_TICKS( 50 ) ); + vTaskDelay( pdMS_TO_TICKS( phySHORT_DELAY_MS ) ); } if( ulDoneMask != ( uint32_t)0u ) { ulBitMask = ( uint32_t )1u; pxPhyObject->ulLinkStatusMask &= ~( ulDoneMask ); - for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 ) + for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 ) { BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ]; uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ]; @@ -623,7 +627,7 @@ TimeOut_t xTimer; pxPhyObject->fnPhyRead( xPhyAddress, PHYREG_10_PHYSTS, &ulRegValue); } - FreeRTOS_printf( ( ">> Autonego ready: %08lx: %s duplex %u mbit %s status\n", + FreeRTOS_printf( ( "Autonego ready: %08lx: %s duplex %u mbit %s status\n", ulRegValue, ( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) ? "full" : "half", ( ulRegValue & phyPHYSTS_SPEED_STATUS ) ? 10 : 100, @@ -676,6 +680,9 @@ BaseType_t xNeedCheck = pdFALSE; } else if( xTaskCheckForTimeOut( &( pxPhyObject->xLinkStatusTimer ), &( pxPhyObject->xLinkStatusRemaining ) ) != pdFALSE ) { + /* Frequent checking the PHY Link Status can affect for the performance of Ethernet controller. + As long as packets are received, no polling is needed. + Otherwise, polling will be done when the 'xLinkStatusTimer' expires. */ for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 ) { BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ]; @@ -700,10 +707,12 @@ BaseType_t xNeedCheck = pdFALSE; vTaskSetTimeOutState( &( pxPhyObject->xLinkStatusTimer ) ); if( ( pxPhyObject->ulLinkStatusMask & phyBMSR_LINK_STATUS ) != 0 ) { + /* The link status is high, so don't poll the PHY too often. */ pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS ); } else { + /* The link status is low, polling may be done more frequently. */ pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_LOW_CHECK_TIME_MS ); } } diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/NetworkInterface.c new file mode 100644 index 000000000..e759141cc --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/NetworkInterface.c @@ -0,0 +1,331 @@ +/* +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; + } +} diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/m480_eth.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/m480_eth.c new file mode 100644 index 000000000..2d45661d0 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/m480_eth.c @@ -0,0 +1,448 @@ +/**************************************************************************//** + * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of Nuvoton Technology Corp. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*****************************************************************************/ +#include "FreeRTOS.h" +#include "list.h" +#include "FreeRTOS_IP.h" + +#include "m480_eth.h" + +#define ETH_TRIGGER_RX() do{EMAC->RXST = 0;}while(0) +#define ETH_TRIGGER_TX() do{EMAC->TXST = 0;}while(0) +#define ETH_ENABLE_TX() do{EMAC->CTL |= EMAC_CTL_TXON;}while(0) +#define ETH_ENABLE_RX() do{EMAC->CTL |= EMAC_CTL_RXON;}while(0) +#define ETH_DISABLE_TX() do{EMAC->CTL &= ~EMAC_CTL_TXON;}while(0) +#define ETH_DISABLE_RX() do{EMAC->CTL &= ~EMAC_CTL_RXON;}while(0) + + +struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] __attribute__ ((aligned(4))); +struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] __attribute__ ((aligned(4))); +#ifdef __ICCARM__ +#pragma data_alignment=4 +struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM]; +struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM]; +uint8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE]; +uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE]; +#else +struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] __attribute__ ((aligned(4))); +struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] __attribute__ ((aligned(4))); +uint8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE] __attribute__ ((aligned(4))); +uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE] __attribute__ ((aligned(4))); +#endif +struct eth_descriptor volatile *cur_tx_desc_ptr, *cur_rx_desc_ptr, *fin_tx_desc_ptr; + + +// PTP source clock is 84MHz (Real chip using PLL). Each tick is 11.90ns +// Assume we want to set each tick to 100ns. +// Increase register = (100 * 2^31) / (10^9) = 214.71 =~ 215 = 0xD7 +// Addend register = 2^32 * tick_freq / (84MHz), where tick_freq = (2^31 / 215) MHz +// From above equation, addend register = 2^63 / (84M * 215) ~= 510707200 = 0x1E70C600 + + + +static void mdio_write(uint8_t addr, uint8_t reg, uint16_t val) +{ + + EMAC->MIIMDAT = val; + EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_WRITE_Msk | EMAC_MIIMCTL_MDCON_Msk; + + while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk); + +} + + +static uint16_t mdio_read(uint8_t addr, uint8_t reg) +{ + EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk; + while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk); + + return(EMAC->MIIMDAT); +} + +static int reset_phy(void) +{ + + uint16_t reg; + uint32_t delayCnt; + + + mdio_write(CONFIG_PHY_ADDR, MII_BMCR, BMCR_RESET); + + delayCnt = 2000; + while(delayCnt-- > 0) { + if((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0) + break; + + } + + if(delayCnt == 0) { + NU_DEBUGF(("Reset phy failed\n")); + return(-1); + } + + mdio_write(CONFIG_PHY_ADDR, MII_ADVERTISE, ADVERTISE_CSMA | + ADVERTISE_10HALF | + ADVERTISE_10FULL | + ADVERTISE_100HALF | + ADVERTISE_100FULL); + + reg = mdio_read(CONFIG_PHY_ADDR, MII_BMCR); + mdio_write(CONFIG_PHY_ADDR, MII_BMCR, reg | BMCR_ANRESTART); + + delayCnt = 200000; + while(delayCnt-- > 0) { + if((mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) + == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) + break; + } + + if(delayCnt == 0) { + NU_DEBUGF(("AN failed. Set to 100 FULL\n")); + EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk); + return(-1); + } else { + reg = mdio_read(CONFIG_PHY_ADDR, MII_LPA); + + if(reg & ADVERTISE_100FULL) { + NU_DEBUGF(("100 full\n")); + EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk); + } else if(reg & ADVERTISE_100HALF) { + NU_DEBUGF(("100 half\n")); + EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_FUDUP_Msk) | EMAC_CTL_OPMODE_Msk; + } else if(reg & ADVERTISE_10FULL) { + NU_DEBUGF(("10 full\n")); + EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk; + } else { + NU_DEBUGF(("10 half\n")); + EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk); + } + } + FreeRTOS_printf(("PHY ID 1:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID1))); + FreeRTOS_printf(("PHY ID 2:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID2))); + + return(0); +} + + +static void init_tx_desc(void) +{ + uint32_t i; + + + cur_tx_desc_ptr = fin_tx_desc_ptr = &tx_desc[0]; + + for(i = 0; i < TX_DESCRIPTOR_NUM; i++) { + tx_desc[i].status1 = TXFD_PADEN | TXFD_CRCAPP | TXFD_INTEN; + tx_desc[i].buf = &tx_buf[i][0]; + tx_desc[i].status2 = 0; + tx_desc[i].next = &tx_desc[(i + 1) % TX_DESCRIPTOR_NUM]; + + } + EMAC->TXDSA = (unsigned int)&tx_desc[0]; + return; +} + +static void init_rx_desc(void) +{ + uint32_t i; + + + cur_rx_desc_ptr = &rx_desc[0]; + + for(i = 0; i < RX_DESCRIPTOR_NUM; i++) { + rx_desc[i].status1 = OWNERSHIP_EMAC; + rx_desc[i].buf = &rx_buf[i][0]; + rx_desc[i].status2 = 0; + rx_desc[i].next = &rx_desc[(i + 1) % TX_DESCRIPTOR_NUM]; + } + EMAC->RXDSA = (unsigned int)&rx_desc[0]; + return; +} + +void numaker_set_mac_addr(uint8_t *addr) +{ + + EMAC->CAM0M = (addr[0] << 24) | + (addr[1] << 16) | + (addr[2] << 8) | + addr[3]; + + EMAC->CAM0L = (addr[4] << 24) | + (addr[5] << 16); + + +} + +static void __eth_clk_pin_init() +{ + /* Unlock protected registers */ + SYS_UnlockReg(); + + /* Enable IP clock */ + CLK_EnableModuleClock(EMAC_MODULE); + + // Configure MDC clock rate to HCLK / (127 + 1) = 1.25 MHz if system is running at 160 MH + CLK_SetModuleClock(EMAC_MODULE, 0, CLK_CLKDIV3_EMAC(127)); + + /* Update System Core Clock */ + SystemCoreClockUpdate(); + + /*---------------------------------------------------------------------------------------------------------*/ + /* Init I/O Multi-function */ + /*---------------------------------------------------------------------------------------------------------*/ + // Configure RMII pins + SYS->GPA_MFPL &= ~(SYS_GPA_MFPL_PA6MFP_Msk | SYS_GPA_MFPL_PA7MFP_Msk); + SYS->GPA_MFPL |= SYS_GPA_MFPL_PA6MFP_EMAC_RMII_RXERR | SYS_GPA_MFPL_PA7MFP_EMAC_RMII_CRSDV; + SYS->GPC_MFPL &= ~(SYS_GPC_MFPL_PC6MFP_Msk | SYS_GPC_MFPL_PC7MFP_Msk); + SYS->GPC_MFPL |= SYS_GPC_MFPL_PC6MFP_EMAC_RMII_RXD1 | SYS_GPC_MFPL_PC7MFP_EMAC_RMII_RXD0; + SYS->GPC_MFPH &= ~SYS_GPC_MFPH_PC8MFP_Msk; + SYS->GPC_MFPH |= SYS_GPC_MFPH_PC8MFP_EMAC_RMII_REFCLK; + SYS->GPE_MFPH &= ~(SYS_GPE_MFPH_PE8MFP_Msk | SYS_GPE_MFPH_PE9MFP_Msk | SYS_GPE_MFPH_PE10MFP_Msk | + SYS_GPE_MFPH_PE11MFP_Msk | SYS_GPE_MFPH_PE12MFP_Msk); + SYS->GPE_MFPH |= SYS_GPE_MFPH_PE8MFP_EMAC_RMII_MDC | + SYS_GPE_MFPH_PE9MFP_EMAC_RMII_MDIO | + SYS_GPE_MFPH_PE10MFP_EMAC_RMII_TXD0 | + SYS_GPE_MFPH_PE11MFP_EMAC_RMII_TXD1 | + SYS_GPE_MFPH_PE12MFP_EMAC_RMII_TXEN; + + // Enable high slew rate on all RMII TX output pins + PE->SLEWCTL = (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN10_Pos) | + (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN11_Pos) | + (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN12_Pos); + + + /* Lock protected registers */ + SYS_LockReg(); + + +} + +int numaker_eth_init(uint8_t *mac_addr) +{ + int ret = 0; + // init CLK & pins + __eth_clk_pin_init(); + + // Reset MAC + EMAC->CTL = EMAC_CTL_RST_Msk; + while(EMAC->CTL & EMAC_CTL_RST_Msk) {} + + init_tx_desc(); + init_rx_desc(); + + numaker_set_mac_addr(mac_addr); // need to reconfigure hardware address 'cos we just RESET emc... + + + /* Configure the MAC interrupt enable register. */ + EMAC->INTEN = EMAC_INTEN_RXIEN_Msk | + EMAC_INTEN_TXIEN_Msk | + EMAC_INTEN_RXGDIEN_Msk | + EMAC_INTEN_TXCPIEN_Msk | + EMAC_INTEN_RXBEIEN_Msk | + EMAC_INTEN_TXBEIEN_Msk | + EMAC_INTEN_RDUIEN_Msk | + EMAC_INTEN_TSALMIEN_Msk | + EMAC_INTEN_WOLIEN_Msk; + + /* Configure the MAC control register. */ + EMAC->CTL = EMAC_CTL_STRIPCRC_Msk | EMAC_CTL_RMIIEN_Msk; + + /* Accept packets for us and all broadcast and multicast packets */ + EMAC->CAMCTL = EMAC_CAMCTL_CMPEN_Msk | + EMAC_CAMCTL_AMP_Msk | + EMAC_CAMCTL_ABP_Msk; + EMAC->CAMEN = 1; // Enable CAM entry 0 + + ret= reset_phy(); + + EMAC_ENABLE_RX(); + EMAC_ENABLE_TX(); + return ret; +} + + + +void ETH_halt(void) +{ + + EMAC->CTL &= ~(EMAC_CTL_RXON_Msk | EMAC_CTL_TXON_Msk); +} + +unsigned int m_status; + +void EMAC_RX_IRQHandler(void) +{ +// NU_DEBUGF(("%s ... \r\n", __FUNCTION__)); + m_status = EMAC->INTSTS & 0xFFFF; + EMAC->INTSTS = m_status; + if (m_status & EMAC_INTSTS_RXBEIF_Msk) { + // Shouldn't goes here, unless descriptor corrupted + NU_DEBUGF(("RX descriptor corrupted \r\n")); + //return; + } + // FIX ME: for rx-event, to ack rx_isr into event queue + xNetworkCallback('R'); +} + + +void numaker_eth_trigger_rx(void) +{ + ETH_TRIGGER_RX(); +} + +int numaker_eth_get_rx_buf(uint16_t *len, uint8_t **buf) +{ + unsigned int cur_entry, status; + + cur_entry = EMAC->CRXDSA; + if ((cur_entry == (uint32_t)cur_rx_desc_ptr) && (!(m_status & EMAC_INTSTS_RDUIF_Msk))) // cur_entry may equal to cur_rx_desc_ptr if RDU occures + return -1; + status = cur_rx_desc_ptr->status1; + + if(status & OWNERSHIP_EMAC) + return -1; + + if (status & RXFD_RXGD) { + *buf = cur_rx_desc_ptr->buf; + *len = status & 0xFFFF; + } + return 0; +} + +void numaker_eth_rx_next(void) +{ + cur_rx_desc_ptr->status1 = OWNERSHIP_EMAC; + cur_rx_desc_ptr = cur_rx_desc_ptr->next; +} + +void EMAC_TX_IRQHandler(void) +{ + unsigned int cur_entry, status; + + status = EMAC->INTSTS & 0xFFFF0000; + EMAC->INTSTS = status; + if(status & EMAC_INTSTS_TXBEIF_Msk) { + // Shouldn't goes here, unless descriptor corrupted + return; + } + + cur_entry = EMAC->CTXDSA; + + while (cur_entry != (uint32_t)fin_tx_desc_ptr) { + + fin_tx_desc_ptr = fin_tx_desc_ptr->next; + } + // FIX ME: for tx-event, no-op at this stage + xNetworkCallback('T'); +} + +uint8_t *numaker_eth_get_tx_buf(void) +{ + if(cur_tx_desc_ptr->status1 & OWNERSHIP_EMAC) + return(NULL); + else + return(cur_tx_desc_ptr->buf); +} + +void numaker_eth_trigger_tx(uint16_t length, void *p) +{ + struct eth_descriptor volatile *desc; + cur_tx_desc_ptr->status2 = (unsigned int)length; + desc = cur_tx_desc_ptr->next; // in case TX is transmitting and overwrite next pointer before we can update cur_tx_desc_ptr + cur_tx_desc_ptr->status1 |= OWNERSHIP_EMAC; + cur_tx_desc_ptr = desc; + + ETH_TRIGGER_TX(); + +} + +int numaker_eth_link_ok(void) +{ + /* first, a dummy read to latch */ + mdio_read(CONFIG_PHY_ADDR, MII_BMSR); + if(mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & BMSR_LSTATUS) + return 1; + return 0; +} + +//void numaker_eth_set_cb(eth_callback_t eth_cb, void *userData) +//{ +// nu_eth_txrx_cb = eth_cb; +// nu_userData = userData; +//} + +// Provide ethernet devices with a semi-unique MAC address +void numaker_mac_address(uint8_t *mac) +{ + uint32_t uID1; + // Fetch word 0 + uint32_t word0 = *(uint32_t *)0x7F804; // 2KB Data Flash at 0x7F800 + // Fetch word 1 + // we only want bottom 16 bits of word1 (MAC bits 32-47) + // and bit 9 forced to 1, bit 8 forced to 0 + // Locally administered MAC, reduced conflicts + // http://en.wikipedia.org/wiki/MAC_address + uint32_t word1 = *(uint32_t *)0x7F800; // 2KB Data Flash at 0x7F800 + + if( word0 == 0xFFFFFFFF ) // Not burn any mac address at 1st 2 words of Data Flash + { + // with a semi-unique MAC address from the UUID + /* Enable FMC ISP function */ + SYS_UnlockReg(); + FMC_Open(); + // = FMC_ReadUID(0); + uID1 = FMC_ReadUID(1); + word1 = (uID1 & 0x003FFFFF) | ((uID1 & 0x030000) << 6) >> 8; + word0 = ((FMC_ReadUID(0) >> 4) << 20) | ((uID1 & 0xFF)<<12) | (FMC_ReadUID(2) & 0xFFF); + /* Disable FMC ISP function */ + FMC_Close(); + /* Lock protected registers */ + SYS_LockReg(); + } + + word1 |= 0x00000200; + word1 &= 0x0000FEFF; + + mac[0] = (word1 & 0x0000ff00) >> 8; + mac[1] = (word1 & 0x000000ff); + mac[2] = (word0 & 0xff000000) >> 24; + mac[3] = (word0 & 0x00ff0000) >> 16; + mac[4] = (word0 & 0x0000ff00) >> 8; + mac[5] = (word0 & 0x000000ff); + + NU_DEBUGF(("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", mac[0], mac[1],mac[2],mac[3],mac[4],mac[5])); +} + +void numaker_eth_enable_interrupts(void) { + EMAC->INTEN |= EMAC_INTEN_RXIEN_Msk | + EMAC_INTEN_TXIEN_Msk ; + NVIC_EnableIRQ(EMAC_RX_IRQn); + NVIC_EnableIRQ(EMAC_TX_IRQn); +} + +void numaker_eth_disable_interrupts(void) { + NVIC_DisableIRQ(EMAC_RX_IRQn); + NVIC_DisableIRQ(EMAC_TX_IRQn); +} diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/m480_eth.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/m480_eth.h new file mode 100644 index 000000000..4e4d98d6d --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/m480_eth.h @@ -0,0 +1,164 @@ +/**************************************************************************//** + * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of Nuvoton Technology Corp. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*****************************************************************************/ +#include "M480.h" +#ifndef _M480_ETH_ +#define _M480_ETH_ + +/* Generic MII registers. */ + +#define MII_BMCR 0x00 /* Basic mode control register */ +#define MII_BMSR 0x01 /* Basic mode status register */ +#define MII_PHYSID1 0x02 /* PHYS ID 1 */ +#define MII_PHYSID2 0x03 /* PHYS ID 2 */ +#define MII_ADVERTISE 0x04 /* Advertisement control reg */ +#define MII_LPA 0x05 /* Link partner ability reg */ +#define MII_EXPANSION 0x06 /* Expansion register */ +#define MII_DCOUNTER 0x12 /* Disconnect counter */ +#define MII_FCSCOUNTER 0x13 /* False carrier counter */ +#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */ +#define MII_RERRCOUNTER 0x15 /* Receive error counter */ +#define MII_SREVISION 0x16 /* Silicon revision */ +#define MII_RESV1 0x17 /* Reserved... */ +#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */ +#define MII_PHYADDR 0x19 /* PHY address */ +#define MII_RESV2 0x1a /* Reserved... */ +#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */ +#define MII_NCONFIG 0x1c /* Network interface config */ + +/* Basic mode control register. */ +#define BMCR_RESV 0x007f /* Unused... */ +#define BMCR_CTST 0x0080 /* Collision test */ +#define BMCR_FULLDPLX 0x0100 /* Full duplex */ +#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */ +#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */ +#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */ +#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ +#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ +#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ +#define BMCR_RESET 0x8000 /* Reset the DP83840 */ + +/* Basic mode status register. */ +#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ +#define BMSR_JCD 0x0002 /* Jabber detected */ +#define BMSR_LSTATUS 0x0004 /* Link status */ +#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ +#define BMSR_RFAULT 0x0010 /* Remote fault detected */ +#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ +#define BMSR_RESV 0x07c0 /* Unused... */ +#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ +#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ +#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ +#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */ +#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */ + +/* Advertisement control register. */ +#define ADVERTISE_SLCT 0x001f /* Selector bits */ +#define ADVERTISE_CSMA 0x0001 /* Only selector supported */ +#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ +#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ +#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ +#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ +#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ +#define ADVERTISE_RESV 0x1c00 /* Unused... */ +#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ +#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ +#define ADVERTISE_NPAGE 0x8000 /* Next page bit */ + +#define RX_DESCRIPTOR_NUM 4 //8 // Max Number of Rx Frame Descriptors +#define TX_DESCRIPTOR_NUM 2 //4 // Max number of Tx Frame Descriptors + +#define PACKET_BUFFER_SIZE 1520 + +#define CONFIG_PHY_ADDR 1 + + +// Frame Descriptor's Owner bit +#define OWNERSHIP_EMAC 0x80000000 // 1 = EMAC +//#define OWNERSHIP_CPU 0x7fffffff // 0 = CPU + + + +// Rx Frame Descriptor Status +#define RXFD_RXGD 0x00100000 // Receiving Good Packet Received +#define RXFD_RTSAS 0x00800000 // RX Time Stamp Available + + +// Tx Frame Descriptor's Control bits +#define TXFD_TTSEN 0x08 // Tx Time Stamp Enable +#define TXFD_INTEN 0x04 // Interrupt Enable +#define TXFD_CRCAPP 0x02 // Append CRC +#define TXFD_PADEN 0x01 // Padding Enable + +// Tx Frame Descriptor Status +#define TXFD_TXCP 0x00080000 // Transmission Completion +#define TXFD_TTSAS 0x08000000 // TX Time Stamp Available + +// Tx/Rx buffer descriptor structure +struct eth_descriptor; +struct eth_descriptor { + uint32_t status1; + uint8_t *buf; + uint32_t status2; + struct eth_descriptor *next; +#ifdef TIME_STAMPING + uint32_t backup1; + uint32_t backup2; + uint32_t reserved1; + uint32_t reserved2; +#endif +}; + +#ifdef TIME_STAMPING + +#define ETH_TS_ENABLE() do{EMAC->TSCTL = EMAC_TSCTL_TSEN_Msk;}while(0) +#define ETH_TS_START() do{EMAC->TSCTL |= (EMAC_TSCTL_TSMODE_Msk | EMAC_TSCTL_TSIEN_Msk);}while(0) +s32_t ETH_settime(u32_t sec, u32_t nsec); +s32_t ETH_gettime(u32_t *sec, u32_t *nsec); +s32_t ETH_updatetime(u32_t neg, u32_t sec, u32_t nsec); +s32_t ETH_adjtimex(int ppm); +void ETH_setinc(void); + +#endif + +#ifdef NU_TRACE +#define NU_DEBUGF(x) { printf x; } +#else +#define NU_DEBUGF(x) +#endif + +void numaker_set_mac_addr(uint8_t *addr); +int numaker_eth_init(uint8_t *mac_addr); +uint8_t *numaker_eth_get_tx_buf(void); +void numaker_eth_trigger_tx(uint16_t length, void *p); +int numaker_eth_get_rx_buf(uint16_t *len, uint8_t **buf); +void numaker_eth_rx_next(void); +void numaker_eth_trigger_rx(void); +int numaker_eth_link_ok(void); +void numaker_mac_address(uint8_t *mac); +void numaker_eth_enable_interrupts(void); +void numaker_eth_disable_interrupts(void); + +#endif /* _M480_ETH_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/RX/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/RX/NetworkInterface.c new file mode 100644 index 000000000..5a605af9b --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/RX/NetworkInterface.c @@ -0,0 +1,629 @@ +/*********************************************************************************************************************** +* DISCLAIMER +* This software is supplied by Renesas Electronics Corporation and is only intended for use with Renesas products. No +* other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all +* applicable laws, including copyright laws. +* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING +* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED. TO THE MAXIMUM +* EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES +* SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON RELATED TO THIS +* SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +* Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability of +* this software. By using this software, you agree to the additional terms and conditions found by accessing the +* following link: +* http://www.renesas.com/disclaimer +* +* Copyright (C) 2018 Renesas Electronics Corporation. All rights reserved. +***********************************************************************************************************************/ + +/*********************************************************************************************************************** +* File Name : NetworkInterface.c +* Device(s) : RX +* Description : Interfaces FreeRTOS TCP/IP stack to RX Ethernet driver. +***********************************************************************************************************************/ + +/*********************************************************************************************************************** +* History : DD.MM.YYYY Version Description +* : 07.03.2018 0.1 Development +***********************************************************************************************************************/ + +/*********************************************************************************************************************** +* Includes , "Project Includes" +***********************************************************************************************************************/ +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "FreeRTOS_IP.h" +#include "FreeRTOS_IP_Private.h" +/*#include "FreeRTOS_DNS.h" */ +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" + +#include "r_ether_rx_if.h" +#include "r_pinset.h" + +/*********************************************************************************************************************** + * Macro definitions + **********************************************************************************************************************/ +#define ETHER_BUFSIZE_MIN 60 + +#if defined( BSP_MCU_RX65N ) || defined( BSP_MCU_RX64M ) || defined( BSP_MCU_RX71M ) + #if ETHER_CFG_MODE_SEL == 0 + #define R_ETHER_PinSet_CHANNEL_0() R_ETHER_PinSet_ETHERC0_MII() + #elif ETHER_CFG_MODE_SEL == 1 + #define R_ETHER_PinSet_CHANNEL_0() R_ETHER_PinSet_ETHERC0_RMII() + #endif +#elif defined( BSP_MCU_RX63N ) + #if ETHER_CFG_MODE_SEL == 0 + #define R_ETHER_PinSet_CHANNEL_0() R_ETHER_PinSet_ETHERC_MII() + #elif ETHER_CFG_MODE_SEL == 1 + #define R_ETHER_PinSet_CHANNEL_0() R_ETHER_PinSet_ETHERC_RMII() + #endif +#endif /* if defined( BSP_MCU_RX65N ) || defined( BSP_MCU_RX64M ) || defined( BSP_MCU_RX71M ) */ + +#ifndef PHY_LS_HIGH_CHECK_TIME_MS + +/* Check if the LinkSStatus in the PHY is still high after 2 seconds of not + * receiving packets. */ + #define PHY_LS_HIGH_CHECK_TIME_MS 2000 +#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 + +/*********************************************************************************************************************** + * Private global variables and functions + **********************************************************************************************************************/ +typedef enum +{ + eMACInit, /* Must initialise MAC. */ + eMACPass, /* Initialisation was successful. */ + eMACFailed, /* Initialisation failed. */ +} eMAC_INIT_STATUS_TYPE; + +static TaskHandle_t ether_receive_check_task_handle = 0; +static TaskHandle_t ether_link_check_task_handle = 0; +static TaskHandle_t xTaskToNotify = NULL; +static BaseType_t xPHYLinkStatus; +static BaseType_t xReportedStatus; +static eMAC_INIT_STATUS_TYPE xMacInitStatus = eMACInit; + +static int16_t SendData( uint8_t * pucBuffer, + size_t length ); +static int InitializeNetwork( void ); +static void prvEMACDeferredInterruptHandlerTask( void * pvParameters ); +static void clear_all_ether_rx_discriptors( uint32_t event ); + +int32_t callback_ether_regist( void ); +void EINT_Trig_isr( void * ); +void get_random_number( uint8_t * data, + uint32_t len ); + +void prvLinkStatusChange( BaseType_t xStatus ); +#if ( ipconfigHAS_PRINTF != 0 ) + static void prvMonitorResources( void ); +#endif + +/*********************************************************************************************************************** + * Function Name: xNetworkInterfaceInitialise () + * Description : Initialization of Ethernet driver. + * Arguments : none + * Return Value : pdPASS, pdFAIL + **********************************************************************************************************************/ +BaseType_t xNetworkInterfaceInitialise( void ) +{ + BaseType_t xReturn; + + if( xMacInitStatus == eMACInit ) + { + /* + * Perform the hardware specific network initialization here using the Ethernet driver library to initialize the + * Ethernet hardware, initialize DMA descriptors, and perform a PHY auto-negotiation to obtain a network link. + * + * InitialiseNetwork() uses Ethernet peripheral driver library function, and returns 0 if the initialization fails. + */ + if( InitializeNetwork() == pdFALSE ) + { + xMacInitStatus = eMACFailed; + } + else + { + /* Indicate that the MAC initialisation succeeded. */ + xMacInitStatus = eMACPass; + } + + FreeRTOS_printf( ( "InitializeNetwork returns %s\n", ( xMacInitStatus == eMACPass ) ? "OK" : " Fail" ) ); + } + + if( xMacInitStatus == eMACPass ) + { + xReturn = xPHYLinkStatus; + } + else + { + xReturn = pdFAIL; + } + + FreeRTOS_printf( ( "xNetworkInterfaceInitialise returns %d\n", xReturn ) ); + + return xReturn; +} /* End of function xNetworkInterfaceInitialise() */ + + +/*********************************************************************************************************************** + * Function Name: xNetworkInterfaceOutput () + * Description : Simple network output interface. + * Arguments : pxDescriptor, xReleaseAfterSend + * Return Value : pdTRUE, pdFALSE + **********************************************************************************************************************/ +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, + BaseType_t xReleaseAfterSend ) +{ + BaseType_t xReturn = pdFALSE; + + /* Simple network interfaces (as opposed to more efficient zero copy network + * interfaces) just use Ethernet peripheral driver library functions to copy + * data from the FreeRTOS+TCP buffer into the peripheral driver's own buffer. + * This example assumes SendData() is a peripheral driver library function that + * takes a pointer to the start of the data to be sent and the length of the + * data to be sent as two separate parameters. The start of the data is located + * by pxDescriptor->pucEthernetBuffer. The length of the data is located + * by pxDescriptor->xDataLength. */ + if( xPHYLinkStatus != 0 ) + { + if( SendData( pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength ) >= 0 ) + { + xReturn = pdTRUE; + /* Call the standard trace macro to log the send event. */ + iptraceNETWORK_INTERFACE_TRANSMIT(); + } + } + else + { + /* As the PHY Link Status is low, it makes no sense trying to deliver a packet. */ + } + + 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 ); + } + + return xReturn; +} /* End of function xNetworkInterfaceOutput() */ + + +#if ( ipconfigHAS_PRINTF != 0 ) + static void prvMonitorResources() + { + static UBaseType_t uxLastMinBufferCount = 0u; + static UBaseType_t uxCurrentBufferCount = 0u; + static size_t uxMinLastSize = 0uL; + static size_t uxCurLastSize = 0uL; + size_t uxMinSize; + size_t uxCurSize; + + uxCurrentBufferCount = uxGetMinimumFreeNetworkBuffers(); + + if( uxLastMinBufferCount != uxCurrentBufferCount ) + { + /* The logging produced below may be helpful + * while tuning +TCP: see how many buffers are in use. */ + uxLastMinBufferCount = uxCurrentBufferCount; + FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n", + uxGetNumberOfFreeNetworkBuffers(), uxCurrentBufferCount ) ); + } + + uxMinSize = xPortGetMinimumEverFreeHeapSize(); + uxCurSize = xPortGetFreeHeapSize(); + + if( uxMinLastSize != uxMinSize ) + { + uxCurLastSize = uxCurSize; + uxMinLastSize = uxMinSize; + FreeRTOS_printf( ( "Heap: current %lu lowest %lu\n", uxCurSize, uxMinSize ) ); + } + + #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + { + static UBaseType_t uxLastMinQueueSpace = 0; + UBaseType_t uxCurrentCount = 0u; + + 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 */ + } +#endif /* ( ipconfigHAS_PRINTF != 0 ) */ + +/*********************************************************************************************************************** + * Function Name: prvEMACDeferredInterruptHandlerTask () + * Description : The deferred interrupt handler is a standard RTOS task. + * Arguments : pvParameters + * Return Value : none + **********************************************************************************************************************/ +static void prvEMACDeferredInterruptHandlerTask( void * pvParameters ) +{ + NetworkBufferDescriptor_t * pxBufferDescriptor; + int32_t xBytesReceived = 0; + + /* Avoid compiler warning about unreferenced parameter. */ + ( void ) pvParameters; + + /* Used to indicate that xSendEventStructToIPTask() is being called because + * of an Ethernet receive event. */ + IPStackEvent_t xRxEvent; + + uint8_t * buffer_pointer; + + /* Some variables related to monitoring the PHY. */ + TimeOut_t xPhyTime; + TickType_t xPhyRemTime; + const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL ); + + vTaskSetTimeOutState( &xPhyTime ); + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS ); + + FreeRTOS_printf( ( "Deferred Interrupt Handler Task started\n" ) ); + xTaskToNotify = ether_receive_check_task_handle; + + for( ; ; ) + { + #if ( ipconfigHAS_PRINTF != 0 ) + { + prvMonitorResources(); + } + #endif /* ipconfigHAS_PRINTF != 0 ) */ + + /* Wait for the Ethernet MAC interrupt to indicate that another packet + * has been received. */ + if( xBytesReceived <= 0 ) + { + ulTaskNotifyTake( pdFALSE, ulMaxBlockTime ); + } + + /* See how much data was received. */ + xBytesReceived = R_ETHER_Read_ZC2( ETHER_CHANNEL_0, ( void ** ) &buffer_pointer ); + + if( xBytesReceived < 0 ) + { + /* This is an error. Logged. */ + if( xBytesReceived == ETHER_ERR_LINK ) + { + /* Auto-negotiation is not completed, and transmission/ + reception is not enabled. Will be logged elsewhere. */ + } + else + { + FreeRTOS_printf( ( "R_ETHER_Read_ZC2: rc = %d not %d\n", xBytesReceived, ETHER_ERR_LINK ) ); + } + } + else if( xBytesReceived > 0 ) + { + /* 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( ( size_t ) xBytesReceived, 0 ); + + if( pxBufferDescriptor != NULL ) + { + /* pxBufferDescriptor->pucEthernetBuffer now points to an Ethernet + * buffer large enough to hold the received data. Copy the + * received data into pcNetworkBuffer->pucEthernetBuffer. Here it + * is assumed ReceiveData() is a peripheral driver function that + * copies the received data into a buffer passed in as the function's + * parameter. Remember! While is is a simple robust technique - + * it is not efficient. An example that uses a zero copy technique + * is provided further down this page. */ + memcpy( pxBufferDescriptor->pucEthernetBuffer, buffer_pointer, ( size_t ) xBytesReceived ); + /*ReceiveData( pxBufferDescriptor->pucEthernetBuffer ); */ + + /* Set the actual packet length, in case a larger buffer was returned. */ + pxBufferDescriptor->xDataLength = ( size_t ) xBytesReceived; + + R_ETHER_Read_ZC2_BufRelease( ETHER_CHANNEL_0 ); + + /* See if the data contained in the received Ethernet frame needs + * to be processed. NOTE! It is preferable to do this in + * the interrupt service routine itself, which would remove the need + * to unblock this task for packets that don't need processing. */ + if( eConsiderFrameForProcessing( pxBufferDescriptor->pucEthernetBuffer ) == eProcessBuffer ) + { + /* 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(); + clear_all_ether_rx_discriptors( 0 ); + } + else + { + /* The message was successfully sent to the TCP/IP stack. + * Call the standard trace macro to log the occurrence. */ + iptraceNETWORK_INTERFACE_RECEIVE(); + R_NOP(); + } + } + else + { + /* The Ethernet frame can be dropped, but the Ethernet buffer must be released. */ + vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor ); + } + } + else + { + /* The event was lost because a network buffer was not available. + * Call the standard trace macro to log the occurrence. */ + iptraceETHERNET_RX_EVENT_LOST(); + clear_all_ether_rx_discriptors( 1 ); + FreeRTOS_printf( ( "R_ETHER_Read_ZC2: Cleared descriptors\n" ) ); + } + } + + if( xBytesReceived > 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 ); + + /* Indicate that the Link Status is high, so that + * xNetworkInterfaceOutput() can send packets. */ + if( xPHYLinkStatus == 0 ) + { + xPHYLinkStatus = 1; + FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS assume %d\n", xPHYLinkStatus ) ); + } + } + else if( ( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ) || ( FreeRTOS_IsNetworkUp() == pdFALSE ) ) + { + R_ETHER_LinkProcess( 0 ); + + if( xPHYLinkStatus != xReportedStatus ) + { + xPHYLinkStatus = xReportedStatus; + FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", xPHYLinkStatus ) ); + } + + vTaskSetTimeOutState( &xPhyTime ); + + if( xPHYLinkStatus != 0 ) + { + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS ); + } + else + { + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS ); + } + } + } +} /* End of function prvEMACDeferredInterruptHandlerTask() */ + + +/*********************************************************************************************************************** + * Function Name: vNetworkInterfaceAllocateRAMToBuffers () + * Description : . + * Arguments : pxNetworkBuffers + * Return Value : none + **********************************************************************************************************************/ +void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) +{ + uint32_t ul; + uint8_t * buffer_address; + + R_EXTERN_SEC( B_ETHERNET_BUFFERS_1 ) + + buffer_address = R_SECTOP( B_ETHERNET_BUFFERS_1 ); + + for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ ) + { + pxNetworkBuffers[ ul ].pucEthernetBuffer = ( buffer_address + ( ETHER_CFG_BUFSIZE * ul ) ); + } +} /* End of function vNetworkInterfaceAllocateRAMToBuffers() */ + + +/*********************************************************************************************************************** + * Function Name: prvLinkStatusChange () + * Description : Function will be called when the Link Status of the phy has changed ( see ether_callback.c ) + * Arguments : xStatus : true when statyus has become high + * Return Value : void + **********************************************************************************************************************/ +void prvLinkStatusChange( BaseType_t xStatus ) +{ + if( xReportedStatus != xStatus ) + { + xReportedStatus = xStatus; + } +} + +/*********************************************************************************************************************** + * Function Name: InitializeNetwork () + * Description : + * Arguments : none + * Return Value : pdTRUE, pdFALSE + **********************************************************************************************************************/ +static int InitializeNetwork( void ) +{ + ether_return_t eth_ret; + BaseType_t return_code = pdFALSE; + ether_param_t param; + uint8_t myethaddr[ 6 ] = + { + configMAC_ADDR0, + configMAC_ADDR1, + configMAC_ADDR2, + configMAC_ADDR3, + configMAC_ADDR4, + configMAC_ADDR5 + }; /*XXX Fix me */ + + R_ETHER_PinSet_CHANNEL_0(); + R_ETHER_Initial(); + callback_ether_regist(); + + param.channel = ETHER_CHANNEL_0; + eth_ret = R_ETHER_Control( CONTROL_POWER_ON, param ); /* PHY mode settings, module stop cancellation */ + + if( ETHER_SUCCESS != eth_ret ) + { + return pdFALSE; + } + + eth_ret = R_ETHER_Open_ZC2( ETHER_CHANNEL_0, myethaddr, ETHER_FLAG_OFF ); + + if( ETHER_SUCCESS != eth_ret ) + { + return pdFALSE; + } + + return_code = xTaskCreate( prvEMACDeferredInterruptHandlerTask, + "ETHER_RECEIVE_CHECK_TASK", + 512u, + 0, + configMAX_PRIORITIES - 1, + ðer_receive_check_task_handle ); + + if( pdFALSE == return_code ) + { + return pdFALSE; + } + + return pdTRUE; +} /* End of function InitializeNetwork() */ + + +/*********************************************************************************************************************** + * Function Name: SendData () + * Description : + * Arguments : pucBuffer, length + * Return Value : 0 success, negative fail + **********************************************************************************************************************/ +static int16_t SendData( uint8_t * pucBuffer, + size_t length ) /*TODO complete stub function */ +{ + ether_return_t ret; + uint8_t * pwrite_buffer; + uint16_t write_buf_size; + + /* (1) Retrieve the transmit buffer location controlled by the descriptor. */ + ret = R_ETHER_Write_ZC2_GetBuf( ETHER_CHANNEL_0, ( void ** ) &pwrite_buffer, &write_buf_size ); + + if( ETHER_SUCCESS == ret ) + { + if( write_buf_size >= length ) + { + memcpy( pwrite_buffer, pucBuffer, length ); + } + + if( length < ETHER_BUFSIZE_MIN ) /*under minimum*/ + { + memset( ( pwrite_buffer + length ), 0, ( ETHER_BUFSIZE_MIN - length ) ); /*padding*/ + length = ETHER_BUFSIZE_MIN; /*resize*/ + } + + ret = R_ETHER_Write_ZC2_SetBuf( ETHER_CHANNEL_0, ( uint16_t ) length ); + ret = R_ETHER_CheckWrite( ETHER_CHANNEL_0 ); + } + + if( ETHER_SUCCESS != ret ) + { + return -5; /* XXX return meaningful value */ + } + else + { + return 0; + } +} /* End of function SendData() */ + + +/*********************************************************************************************************************** +* Function Name: EINT_Trig_isr +* Description : Standard frame received interrupt handler +* Arguments : ectrl - EDMAC and ETHERC control structure +* Return Value : None +* Note : This callback function is executed when EINT0 interrupt occurred. +***********************************************************************************************************************/ +void EINT_Trig_isr( void * ectrl ) +{ + ether_cb_arg_t * pdecode; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + pdecode = ( ether_cb_arg_t * ) ectrl; + + if( pdecode->status_eesr & 0x00040000 ) /* EDMAC FR (Frame Receive Event) interrupt */ + { + if( xTaskToNotify != NULL ) + { + vTaskNotifyGiveFromISR( ether_receive_check_task_handle, &xHigherPriorityTaskWoken ); + } + + /* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch + * should be performed to ensure the interrupt returns directly to the highest + * priority task. The macro used for this purpose is dependent on the port in + * use and may be called portEND_SWITCHING_ISR(). */ + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + /*TODO complete interrupt handler for other events. */ + } +} /* End of function EINT_Trig_isr() */ + + +static void clear_all_ether_rx_discriptors( uint32_t event ) +{ + int32_t xBytesReceived; + uint8_t * buffer_pointer; + + /* Avoid compiler warning about unreferenced parameter. */ + ( void ) event; + + while( 1 ) + { + /* See how much data was received. */ + xBytesReceived = R_ETHER_Read_ZC2( ETHER_CHANNEL_0, ( void ** ) &buffer_pointer ); + + if( 0 > xBytesReceived ) + { + /* This is an error. Ignored. */ + } + else if( 0 < xBytesReceived ) + { + R_ETHER_Read_ZC2_BufRelease( ETHER_CHANNEL_0 ); + iptraceETHERNET_RX_EVENT_LOST(); + } + else + { + break; + } + } +} + +/*********************************************************************************************************************** + * End of file "NetworkInterface.c" + **********************************************************************************************************************/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/RX/ether_callback.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/RX/ether_callback.c new file mode 100644 index 000000000..c42d8a20b --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/RX/ether_callback.c @@ -0,0 +1,177 @@ +/*********************************************************************************************************************** +* DISCLAIMER +* This software is supplied by Renesas Electronics Corporation and is only intended for use with Renesas products. No +* other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all +* applicable laws, including copyright laws. +* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING +* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED. TO THE MAXIMUM +* EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES +* SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON RELATED TO THIS +* SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +* Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability of +* this software. By using this software, you agree to the additional terms and conditions found by accessing the +* following link: +* http://www.renesas.com/disclaimer +* +* Copyright (C) 2015 Renesas Electronics Corporation. All rights reserved. +***********************************************************************************************************************/ +/*********************************************************************************************************************** +* File Name : ether_callback.c +* Version : ---- +* Description : This module solves all the world's problems +***********************************************************************************************************************/ +/********************************************************************************************************************** +* History : DD.MM.YYYY Version Description +* : 05.01.2015 ---- Clean up source code. +***********************************************************************************************************************/ + +/*********************************************************************************************************************** +Includes , "Project Includes" +***********************************************************************************************************************/ +#include "r_ether_rx_if.h" + +/*********************************************************************************************************************** +Private global variables and functions +***********************************************************************************************************************/ +int32_t callback_ether_regist(void); +void callback_ether(void * pparam); +static void callback_wakeon_lan(uint32_t channel); +static void callback_link_on(uint32_t channel); +static void callback_link_off(uint32_t channel); + +volatile uint8_t pause_enable = ETHER_FLAG_OFF; +volatile uint8_t magic_packet_detect[ETHER_CHANNEL_MAX]; +volatile uint8_t link_detect[ETHER_CHANNEL_MAX]; + +void EINT_Trig_isr(void *); + +/* + * When that Link Status changes, the following function will be called: + */ +void prvLinkStatusChange( BaseType_t xStatus ); + +/*********************************************************************************************************************** +* Function Name: callback_ether +* Description : Regist of callback function +* Arguments : - +* Return Value : 0: success, -1:failed +***********************************************************************************************************************/ +int32_t callback_ether_regist(void) +{ + ether_param_t param; + ether_cb_t cb_func; + + int32_t ret; + + /* Set the callback function (LAN cable connect/disconnect event) */ + cb_func.pcb_func = &callback_ether; + param.ether_callback = cb_func; + ret = R_ETHER_Control(CONTROL_SET_CALLBACK, param); + if (ETHER_SUCCESS != ret) + { + return -1; + } + + /* Set the callback function (Ether interrupt event) */ + cb_func.pcb_int_hnd = &EINT_Trig_isr; + param.ether_callback = cb_func; + ret = R_ETHER_Control(CONTROL_SET_INT_HANDLER, param); + if (ETHER_SUCCESS != ret) + { + return -1; + } + return 0; +} /* End of function callback_ether_regist() */ + +/*********************************************************************************************************************** +* Function Name: callback_ether +* Description : Sample of the callback function +* Arguments : pparam - +* +* Return Value : none +***********************************************************************************************************************/ +void callback_ether(void * pparam) +{ + ether_cb_arg_t * pdecode; + uint32_t channel; + + pdecode = (ether_cb_arg_t *)pparam; + channel = pdecode->channel; /* Get Ethernet channel number */ + + switch (pdecode->event_id) + { + /* Callback function that notifies user to have detected magic packet. */ + case ETHER_CB_EVENT_ID_WAKEON_LAN: + callback_wakeon_lan(channel); + break; + + /* Callback function that notifies user to have become Link up. */ + case ETHER_CB_EVENT_ID_LINK_ON: + callback_link_on(channel); + break; + + /* Callback function that notifies user to have become Link down. */ + case ETHER_CB_EVENT_ID_LINK_OFF: + callback_link_off(channel); + break; + + default: + break; + } +} /* End of function callback_ether() */ + +/*********************************************************************************************************************** +* Function Name: callback_wakeon_lan +* Description : +* Arguments : channel - +* Ethernet channel number +* Return Value : none +***********************************************************************************************************************/ +static void callback_wakeon_lan(uint32_t channel) +{ + if (ETHER_CHANNEL_MAX > channel) + { + magic_packet_detect[channel] = 1; + + /* Please add necessary processing when magic packet is detected. */ + } +} /* End of function callback_wakeon_lan() */ + +/*********************************************************************************************************************** +* Function Name: callback_link_on +* Description : +* Arguments : channel - +* Ethernet channel number +* Return Value : none +***********************************************************************************************************************/ +static void callback_link_on(uint32_t channel) +{ + if (ETHER_CHANNEL_MAX > channel) + { + link_detect[channel] = ETHER_FLAG_ON_LINK_ON; + + /* Please add necessary processing when becoming Link up. */ + prvLinkStatusChange( 1 ); + } +} /* End of function callback_link_on() */ + +/*********************************************************************************************************************** +* Function Name: callback_link_off +* Description : +* Arguments : channel - +* Ethernet channel number +* Return Value : none +***********************************************************************************************************************/ +static void callback_link_off(uint32_t channel) +{ + if (ETHER_CHANNEL_MAX > channel) + { + link_detect[channel] = ETHER_FLAG_ON_LINK_OFF; + + /* Please add necessary processing when becoming Link down. */ + prvLinkStatusChange( 0 ); + } +} /* End of function ether_cb_link_off() */ + +/* End of File */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c index d95165a04..6fad9216e 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c @@ -4,28 +4,28 @@ */ /* - * 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 +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. */ @@ -44,12 +44,11 @@ #include "FreeRTOS_Sockets.h" #include "FreeRTOS_IP_Private.h" #include "FreeRTOS_DNS.h" +#include "FreeRTOS_ARP.h" #include "NetworkBufferManagement.h" #include "NetworkInterface.h" #include "phyHandling.h" -#define __STM32_HAL_LEGACY 1 - /* ST includes. */ #if defined( STM32F7xx ) #include "stm32f7xx_hal.h" @@ -57,7 +56,7 @@ #include "stm32f4xx_hal.h" #elif defined( STM32F2xx ) #include "stm32f2xx_hal.h" -#else +#elif !defined( _lint ) /* Lint does not like an #error */ #error What part? #endif @@ -82,6 +81,14 @@ expansion. */ #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */ +#if( ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) || ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) ) + #warning Consider enabling checksum offloading +#endif + +#ifndef niDESCRIPTOR_WAIT_TIME_MS + #define niDESCRIPTOR_WAIT_TIME_MS 250uL +#endif + /* * Most users will want a PHY that negotiates about * the connection properties: speed, dmix and duplex. @@ -139,6 +146,15 @@ and the index of the PHY in use ( between 0 and 31 ). */ #warning Using MII, make sure if this is correct #endif +typedef enum +{ + eMACInit, /* Must initialise MAC. */ + eMACPass, /* Initialisation was successful. */ + eMACFailed, /* Initialisation failed. */ +} eMAC_INIT_STATUS_TYPE; + +static eMAC_INIT_STATUS_TYPE xMacInitStatus = eMACInit; + /*-----------------------------------------------------------*/ /* @@ -179,9 +195,9 @@ static void prvDMATxDescListInit( void ); */ static void prvDMARxDescListInit( void ); - /* After packets have been sent, the network - buffers will be released. */ - static void vClearTXBuffers( void ); +/* After packets have been sent, the network +buffers will be released. */ +static void vClearTXBuffers( void ); /*-----------------------------------------------------------*/ @@ -199,10 +215,10 @@ static EthernetPhy_t xPhyObject; /* Ethernet handle. */ static ETH_HandleTypeDef xETH; - /* xTXDescriptorSemaphore is a counting semaphore with - a maximum count of ETH_TXBUFNB, which is the number of - DMA TX descriptors. */ - static SemaphoreHandle_t xTXDescriptorSemaphore = NULL; +/* xTXDescriptorSemaphore is a counting semaphore with +a maximum count of ETH_TXBUFNB, which is the number of +DMA TX descriptors. */ +static SemaphoreHandle_t xTXDescriptorSemaphore = NULL; /* * Note: it is adviced to define both @@ -242,11 +258,9 @@ __attribute__ ((section(".first_data"))) __ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END; #endif -#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) - /* DMATxDescToClear points to the next TX DMA descriptor - that must be cleared by vClearTXBuffers(). */ - static __IO ETH_DMADescTypeDef *DMATxDescToClear; -#endif +/* DMATxDescToClear points to the next TX DMA descriptor +that must be cleared by vClearTXBuffers(). */ +static __IO ETH_DMADescTypeDef *DMATxDescToClear; /* 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 @@ -267,9 +281,9 @@ const PhyProperties_t xPHYProperties = #endif #if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 ) - .duplex = PHY_DUPLEX_FULL, + .ucDuplex = PHY_DUPLEX_FULL, #else - .duplex = PHY_DUPLEX_HALF, + .ucDuplex = PHY_DUPLEX_HALF, #endif #endif @@ -288,6 +302,8 @@ void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef *heth ) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; + ( void ) heth; + /* Ethernet RX-Complete callback function, elsewhere declared as weak. */ ulISREvents |= EMAC_IF_RX_EVENT; /* Wakeup the prvEMACHandlerTask. */ @@ -299,43 +315,44 @@ BaseType_t xHigherPriorityTaskWoken = pdFALSE; } /*-----------------------------------------------------------*/ - void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth ) - { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - /* This call-back is only useful in case packets are being sent - zero-copy. Once they're sent, the buffers will be released - by the function vClearTXBuffers(). */ - ulISREvents |= EMAC_IF_TX_EVENT; - /* Wakeup the prvEMACHandlerTask. */ - if( xEMACTaskHandle != NULL ) - { - vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken ); - portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); - } +void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth ) +{ +BaseType_t xHigherPriorityTaskWoken = pdFALSE; + ( void ) heth; + + /* This call-back is only useful in case packets are being sent + zero-copy. Once they're sent, the buffers will be released + by the function vClearTXBuffers(). */ + ulISREvents |= EMAC_IF_TX_EVENT; + /* Wakeup the prvEMACHandlerTask. */ + if( xEMACTaskHandle != NULL ) + { + vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken ); + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } +} /*-----------------------------------------------------------*/ - static void vClearTXBuffers() - { - __IO ETH_DMADescTypeDef *txLastDescriptor = xETH.TxDesc; +static void vClearTXBuffers() +{ +__IO ETH_DMADescTypeDef *txLastDescriptor = xETH.TxDesc; size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore ); #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) NetworkBufferDescriptor_t *pxNetworkBuffer; uint8_t *ucPayLoad; #endif - /* This function is called after a TX-completion interrupt. - It will release each Network Buffer used in xNetworkInterfaceOutput(). - 'uxCount' represents the number of descriptors given to DMA for transmission. - After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */ - while( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) ) + /* This function is called after a TX-completion interrupt. + It will release each Network Buffer used in xNetworkInterfaceOutput(). + 'uxCount' represents the number of descriptors given to DMA for transmission. + After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */ + while( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) ) + { + if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) ) { - if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) ) - { - break; - } + break; + } #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) { ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr; @@ -352,13 +369,13 @@ size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescr } #endif /* ipconfigZERO_COPY_TX_DRIVER */ - DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr ); + DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr ); - uxCount--; - /* Tell the counting semaphore that one more TX descriptor is available. */ - xSemaphoreGive( xTXDescriptorSemaphore ); - } + uxCount--; + /* Tell the counting semaphore that one more TX descriptor is available. */ + xSemaphoreGive( xTXDescriptorSemaphore ); } +} /*-----------------------------------------------------------*/ BaseType_t xNetworkInterfaceInitialise( void ) @@ -366,91 +383,117 @@ BaseType_t xNetworkInterfaceInitialise( void ) HAL_StatusTypeDef hal_eth_init_status; BaseType_t xResult; - if( xEMACTaskHandle == NULL ) + if( xMacInitStatus == eMACInit ) { - if( xTXDescriptorSemaphore == NULL ) - { - xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB ); - configASSERT( xTXDescriptorSemaphore ); - } - - /* Initialise ETH */ + xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB ); + if( xTXDescriptorSemaphore == NULL ) + { + xMacInitStatus = eMACFailed; + } + else + { + /* Initialise ETH */ - xETH.Instance = ETH; - xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE; - xETH.Init.Speed = ETH_SPEED_100M; - xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX; - /* Value of PhyAddress doesn't matter, will be probed for. */ - xETH.Init.PhyAddress = 0; + xETH.Instance = ETH; + xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE; + xETH.Init.Speed = ETH_SPEED_100M; + xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX; + /* Value of PhyAddress doesn't matter, will be probed for. */ + xETH.Init.PhyAddress = 0; - xETH.Init.MACAddr = ( uint8_t *)FreeRTOS_GetMACAddress(); - xETH.Init.RxMode = ETH_RXINTERRUPT_MODE; + xETH.Init.MACAddr = ( uint8_t * ) FreeRTOS_GetMACAddress(); + xETH.Init.RxMode = ETH_RXINTERRUPT_MODE; - /* using the ETH_CHECKSUM_BY_HARDWARE option: - both the IP and the protocol checksums will be calculated - by the peripheral. */ - xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE; + #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) + { + /* using the ETH_CHECKSUM_BY_HARDWARE option: + both the IP and the protocol checksums will be calculated + by the peripheral. */ + xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE; + } + #else + { + xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_SOFTWARE; + } + #endif - #if( ipconfigUSE_RMII != 0 ) - { - xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII; - } - #else - { - xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII; - } - #endif /* ipconfigUSE_RMII */ + #if( ipconfigUSE_RMII != 0 ) + { + xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII; + } + #else + { + xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII; + } + #endif /* ipconfigUSE_RMII */ - hal_eth_init_status = HAL_ETH_Init( &xETH ); + hal_eth_init_status = HAL_ETH_Init( &xETH ); - /* Only for inspection by debugger. */ - ( void ) hal_eth_init_status; + /* Only for inspection by debugger. */ + ( void ) hal_eth_init_status; - /* Set the TxDesc and RxDesc pointers. */ - xETH.TxDesc = DMATxDscrTab; - xETH.RxDesc = DMARxDscrTab; + /* Set the TxDesc and RxDesc pointers. */ + xETH.TxDesc = DMATxDscrTab; + xETH.RxDesc = DMARxDscrTab; - /* Make sure that all unused fields are cleared. */ - memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) ); - memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) ); + /* Make sure that all unused fields are cleared. */ + memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) ); + memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) ); /* Initialize Tx Descriptors list: Chain Mode */ DMATxDescToClear = DMATxDscrTab; - /* Initialise TX-descriptors. */ - prvDMATxDescListInit(); + /* Initialise TX-descriptors. */ + prvDMATxDescListInit(); - /* Initialise RX-descriptors. */ - prvDMARxDescListInit(); + /* Initialise RX-descriptors. */ + prvDMARxDescListInit(); - #if( ipconfigUSE_LLMNR != 0 ) - { - /* Program the LLMNR address at index 1. */ - prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress ); - } - #endif + #if( ipconfigUSE_LLMNR != 0 ) + { + /* Program the LLMNR address at index 1. */ + prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress ); + } + #endif - /* Force a negotiation with the Switch or Router and wait for LS. */ - prvEthernetUpdateConfig( pdTRUE ); + /* Force a negotiation with the Switch or Router and wait for LS. */ + prvEthernetUpdateConfig( pdTRUE ); - /* The deferred interrupt handler task is created at the highest - possible priority to ensure the interrupt handler can return directly - to it. The task's handle is stored in xEMACTaskHandle so interrupts can - notify the task when there is something to process. */ - xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle ); + /* The deferred interrupt handler task is created at the highest + possible priority to ensure the interrupt handler can return directly + to it. The task's handle is stored in xEMACTaskHandle so interrupts can + notify the task when there is something to process. */ + if( xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle ) == pdPASS ) + { + /* The xTXDescriptorSemaphore and the task are created successfully. */ + xMacInitStatus = eMACPass; + } + else + { + xMacInitStatus = eMACFailed; + } + } } /* if( xEMACTaskHandle == NULL ) */ - if( xPhyObject.ulLinkStatusMask != 0 ) + if( xMacInitStatus != eMACPass ) { - xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS; - xResult = pdPASS; - FreeRTOS_printf( ( "Link Status is high\n" ) ) ; + /* EMAC initialisation failed, return pdFAIL. */ + xResult = pdFAIL; } else { - /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running - and it will keep on checking the PHY and set 'ulLinkStatusMask' when necessary. */ - xResult = pdFAIL; + if( xPhyObject.ulLinkStatusMask != 0uL ) + { + xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS; + xResult = pdPASS; + FreeRTOS_printf( ( "Link Status is high\n" ) ) ; + } + else + { + /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running + and it will keep on checking the PHY and set 'ulLinkStatusMask' when necessary. */ + xResult = pdFAIL; + } } /* When returning non-zero, the stack will become active and start DHCP (in configured) */ @@ -484,6 +527,10 @@ BaseType_t xIndex; /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */ pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL; } + else + { + pxDMADescriptor->Status &= ~( ( uint32_t ) ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL ); + } /* Initialize the next descriptor with the Next Descriptor Polling Enable */ if( xIndex < ETH_TXBUFNB - 1 ) @@ -567,6 +614,8 @@ static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8 { uint32_t ulTempReg; + ( void ) heth; + /* Calculate the selected MAC address high register. */ ulTempReg = 0x80000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ]; @@ -592,21 +641,23 @@ const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u ); /* Open a do {} while ( 0 ) loop to be able to call break. */ do { + if( xCheckLoopback( pxDescriptor, bReleaseAfterSend ) != 0 ) + { + /* The packet has been sent back to the IP-task. + The IP-task will further handle it. + Do not release the descriptor. */ + bReleaseAfterSend = pdFALSE; + break; + } #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) { ProtocolPacket_t *pxPacket; - #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) - { - configASSERT( bReleaseAfterSend != 0 ); - } - #endif /* ipconfigZERO_COPY_RX_DRIVER */ - /* If the peripheral must calculate the checksum, it wants the protocol checksum to have a value of zero. */ pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer ); - if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP ) + if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) { pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u; } @@ -644,6 +695,8 @@ const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u ); } #else { + configASSERT( bReleaseAfterSend != 0 ); + /* Move the buffer. */ pxDmaTxDesc->Buffer1Addr = ( uint32_t )pxDescriptor->pucEthernetBuffer; /* The Network Buffer has been passed to DMA, no need to release it. */ @@ -653,7 +706,17 @@ const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u ); /* Ask to set the IPv4 checksum. Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */ - pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC; + #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) + { + pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC; + } + #else + { + pxDmaTxDesc->Status &= ~( ( uint32_t ) ETH_DMATXDESC_CIC ); + pxDmaTxDesc->Status |= ETH_DMATXDESC_IC; + } + #endif + /* Prepare transmit descriptors to give to DMA. */ @@ -751,20 +814,24 @@ const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer; if( pxIPHeader->ucProtocol == ipPROTOCOL_UDP ) { - uint16_t port = pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort; + uint16_t usSourcePort = FreeRTOS_ntohs( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort ); + uint16_t usDestinationPort = FreeRTOS_ntohs( pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort ); - if( ( xPortHasUDPSocket( port ) == pdFALSE ) + if( ( xPortHasUDPSocket( pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort ) == pdFALSE ) #if ipconfigUSE_LLMNR == 1 - && ( port != FreeRTOS_ntohs( ipLLMNR_PORT ) ) + && ( usDestinationPort != ipLLMNR_PORT ) + && ( usSourcePort != ipLLMNR_PORT ) #endif #if ipconfigUSE_NBNS == 1 - && ( port != FreeRTOS_ntohs( ipNBNS_PORT ) ) + && ( usDestinationPort != ipNBNS_PORT ) + && ( usSourcePort != ipNBNS_PORT ) #endif #if ipconfigUSE_DNS == 1 - && ( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort != FreeRTOS_ntohs( ipDNS_PORT ) ) + && ( usSourcePort != ipDNS_PORT ) #endif ) { /* Drop this packet, not for this device. */ + /* FreeRTOS_printf( ( "Drop: UDP port %d -> %d\n", usSourcePort, usDestinationPort ) ); */ return pdFALSE; } } @@ -774,20 +841,59 @@ const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer; } /*-----------------------------------------------------------*/ +static void prvPassEthMessages( NetworkBufferDescriptor_t *pxDescriptor ) +{ +IPStackEvent_t xRxEvent; + + xRxEvent.eEventType = eNetworkRxEvent; + xRxEvent.pvData = ( void * ) pxDescriptor; + + if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS ) + { + /* The buffer could not be sent to the stack so must be released again. + This is a deferred handler taskr, not a real interrupt, so it is ok to + use the task level function here. */ + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + { + do + { + NetworkBufferDescriptor_t *pxNext = pxDescriptor->pxNextBuffer; + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + pxDescriptor = pxNext; + } while( pxDescriptor != NULL ); + } + #else + { + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + } + #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ + iptraceETHERNET_RX_EVENT_LOST(); + FreeRTOS_printf( ( "prvPassEthMessages: Can not queue return packet!\n" ) ); + } + else + { + iptraceNETWORK_INTERFACE_RECEIVE(); + } +} + static BaseType_t prvNetworkInterfaceInput( void ) { NetworkBufferDescriptor_t *pxCurDescriptor; NetworkBufferDescriptor_t *pxNewDescriptor = NULL; -BaseType_t xReceivedLength, xAccepted; +#if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + NetworkBufferDescriptor_t *pxFirstDescriptor = NULL; + NetworkBufferDescriptor_t *pxLastDescriptor = NULL; +#endif +BaseType_t xReceivedLength = 0; __IO ETH_DMADescTypeDef *pxDMARxDescriptor; -xIPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; -const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 ); +const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( niDESCRIPTOR_WAIT_TIME_MS ); uint8_t *pucBuffer; pxDMARxDescriptor = xETH.RxDesc; - if( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN) == 0 ) + while( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN ) == 0u ) { + BaseType_t xAccepted = pdTRUE; /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */ xReceivedLength = ( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4; @@ -797,19 +903,9 @@ uint8_t *pucBuffer; /* Chained Mode */ /* Selects the next DMA Rx descriptor list for next buffer to read */ xETH.RxDesc = ( ETH_DMADescTypeDef* )pxDMARxDescriptor->Buffer2NextDescAddr; - } - else - { - xReceivedLength = 0; - } - /* Obtain the size of the packet and put it into the "usReceivedLength" variable. */ - - /* get received frame */ - if( xReceivedLength > 0ul ) - { - /* In order to make the code easier and faster, only packets in a single buffer - will be accepted. This can be done by making the buffers large enough to + /* In order to make the code easier and faster, only packets in a single buffer + will be accepted. This can be done by making the buffers large enough to hold a complete Ethernet packet (1536 bytes). Therefore, two sanity checks: */ configASSERT( xReceivedLength <= ETH_RX_BUF_SIZE ); @@ -859,20 +955,28 @@ uint8_t *pucBuffer; if( xAccepted != pdFALSE ) { pxCurDescriptor->xDataLength = xReceivedLength; - xRxEvent.pvData = ( void * ) pxCurDescriptor; - - /* Pass the data to the TCP/IP task for processing. */ - if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE ) + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) { - /* Could not send the descriptor into the TCP/IP stack, it - must be released. */ - vReleaseNetworkBufferAndDescriptor( pxCurDescriptor ); - iptraceETHERNET_RX_EVENT_LOST(); + pxCurDescriptor->pxNextBuffer = NULL; + + if( pxFirstDescriptor == NULL ) + { + // Becomes the first message + pxFirstDescriptor = pxCurDescriptor; + } + else if( pxLastDescriptor != NULL ) + { + // Add to the tail + pxLastDescriptor->pxNextBuffer = pxCurDescriptor; + } + + pxLastDescriptor = pxCurDescriptor; } - else + #else { - iptraceNETWORK_INTERFACE_RECEIVE(); + prvPassEthMessages( pxCurDescriptor ); } + #endif } /* Release descriptors to DMA */ @@ -907,15 +1011,25 @@ uint8_t *pucBuffer; /* Resume DMA reception. */ xETH.Instance->DMARPDR = 0; } + pxDMARxDescriptor = xETH.RxDesc; } + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + { + if( pxFirstDescriptor != NULL ) + { + prvPassEthMessages( pxFirstDescriptor ); + } + } + #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ + return ( xReceivedLength > 0 ); } /*-----------------------------------------------------------*/ BaseType_t xSTM32_PhyRead( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue ) - { +{ uint16_t usPrevAddress = xETH.Init.PhyAddress; BaseType_t xResult; HAL_StatusTypeDef xHALResult; @@ -933,11 +1047,11 @@ HAL_StatusTypeDef xHALResult; xResult = -1; } return xResult; - } +} /*-----------------------------------------------------------*/ BaseType_t xSTM32_PhyWrite( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue ) - { +{ uint16_t usPrevAddress = xETH.Init.PhyAddress; BaseType_t xResult; HAL_StatusTypeDef xHALResult; @@ -947,15 +1061,15 @@ HAL_StatusTypeDef xHALResult; xETH.Init.PhyAddress = usPrevAddress; if( xHALResult == HAL_OK ) - { + { xResult = 0; - } - else - { + } + else + { xResult = -1; - } - return xResult; } + return xResult; +} /*-----------------------------------------------------------*/ void vMACBProbePhy( void ) @@ -979,27 +1093,27 @@ static void prvEthernetUpdateConfig( BaseType_t xForce ) { xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) ); - /* Configure the MAC with the Duplex Mode fixed by the - auto-negotiation process. */ + /* Configure the MAC with the Duplex Mode fixed by the + auto-negotiation process. */ if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL ) - { - xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX; - } - else - { - xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX; - } + { + xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX; + } + else + { + xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX; + } - /* Configure the MAC with the speed fixed by the - auto-negotiation process. */ + /* Configure the MAC with the speed fixed by the + auto-negotiation process. */ if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 ) - { - xETH.Init.Speed = ETH_SPEED_10M; - } - else - { - xETH.Init.Speed = ETH_SPEED_100M; - } + { + xETH.Init.Speed = ETH_SPEED_10M; + } + else + { + xETH.Init.Speed = ETH_SPEED_100M; + } } else /* AutoNegotiation Disable */ { @@ -1064,11 +1178,9 @@ BaseType_t xReturn; /* Uncomment this in case BufferAllocation_1.c is used. */ -#define niBUFFER_1_PACKET_SIZE 1536 - void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) { -static __attribute__ ((section(".first_data"))) uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) ); +static __attribute__ ((section(".first_data"))) uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * ETH_MAX_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) ); uint8_t *ucRAMBuffer = ucNetworkPackets; uint32_t ul; @@ -1076,7 +1188,7 @@ uint32_t ul; { pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING; *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) ); - ucRAMBuffer += niBUFFER_1_PACKET_SIZE; + ucRAMBuffer += ETH_MAX_PACKET_SIZE; } } /*-----------------------------------------------------------*/ @@ -1144,21 +1256,15 @@ const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL ); ulISREvents &= ~EMAC_IF_RX_EVENT; xResult = prvNetworkInterfaceInput(); - if( xResult > 0 ) - { - while( prvNetworkInterfaceInput() > 0 ) - { - } - } } if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 ) { /* Code to release TX buffers if zero-copy is used. */ ulISREvents &= ~EMAC_IF_TX_EVENT; - /* Check if DMA packets have been delivered. */ - vClearTXBuffers(); - } + /* Check if DMA packets have been delivered. */ + vClearTXBuffers(); + } if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 ) { @@ -1166,10 +1272,10 @@ const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL ); ulISREvents &= ~EMAC_IF_ERR_EVENT; } if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 ) - { + { /* Something has changed to a Link Status, need re-check. */ - prvEthernetUpdateConfig( pdFALSE ); - } + prvEthernetUpdateConfig( pdFALSE ); + } } } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/readme.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/readme.txt index 73fd553a0..51170c041 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/readme.txt +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/readme.txt @@ -18,3 +18,43 @@ It is assumed that one of these words are defined: STM32F439xx The driver has been tested on both Eval and Discovery boards with both STM32F4 and STM32F7. + +Recommened settings for STM32Fxx Network Interface: + +// Defined in FreeRTOSIPConfig.h + +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 +#define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM 1 +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 +#define ipconfigZERO_COPY_RX_DRIVER 1 +#define ipconfigZERO_COPY_TX_DRIVER 1 +#define ipconfigUSE_LINKED_RX_MESSAGES 1 + +// Defined in stm32f4xx_hal_conf.h +#define ETH_RXBUFNB 3 or 4 +#define ETH_TXBUFNB 2 or 3 +#define ETH_RX_BUF_SIZE ( ipconfigNETWORK_MTU + 36 ) +#define ETH_TX_BUF_SIZE ( ipconfigNETWORK_MTU + 36 ) + +The best size for 'ETH_RXBUFNB' and 'ETH_TXBUFNB' depends on the speed of the CPU. These macro's define the number of DMA buffers for reception and for transmission. +In general, if the CPU is very fast, you will need less buffers. You can obtain an estimate empirically. + +The optimal value of 'ETH_RX_BUF_SIZE' and 'ETH_TX_BUF_SIZE' depends on the actual value of 'ipconfigNETWORK_MTU'. +When MTU is 1500, MTU+36 becomes a well-aligned buffer of 1536 bytes ( 0x600 ). +When MTU is 1200, MTU+48 will make 1248 ( 0x4E0 ), which is also well aligned. + +Having well aligned buffers is important for CPU with memory cache. Often the caching system divides memory in blocks of 32 bytes. When two buffers share the same cache buffer, you are bound to see data errors. + +Without memory caching, let the size be at least a multiple of 8 ( for DMA ), and make it at least "ipconfigNETWORK_MTU + 14". + +The driver contains these files: + + stm32fxx_hal_eth.c + stm32f2xx_hal_eth.h + stm32f4xx_hal_eth.h + stm32f7xx_hal_eth.h + stm32fxx_hal_eth.h + +These files are copied from ST's HAL library. These work both for STM32F4 and STM32F7. +Please remove or rename these files from the HAL distribution that you are using. + diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.c index c67ad1901..dad16aaf8 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.c @@ -99,19 +99,15 @@ */ /* Includes ------------------------------------------------------------------*/ -#define __STM32_HAL_LEGACY 1 #if defined(STM32F7xx) #include "stm32f7xx_hal.h" - #include "stm32f7xx_hal_def.h" #define stm_is_F7 1 #elif defined(STM32F407xx) || defined(STM32F417xx) || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) #include "stm32f4xx_hal.h" - #include "stm32f4xx_hal_def.h" #define stm_is_F4 1 #elif defined(STM32F2xx) #include "stm32f2xx_hal.h" - #include "stm32f2xx_hal_def.h" #define stm_is_F2 1 #else #error For what part should this be compiled? @@ -197,8 +193,8 @@ extern void vMACBProbePhy ( void ); */ HAL_StatusTypeDef HAL_ETH_Init(ETH_HandleTypeDef *heth) { - uint32_t tmpreg = 0; - uint32_t hclk = 60000000; + uint32_t tmpreg = 0uL; + uint32_t hclk = 60000000uL; uint32_t err = ETH_SUCCESS; /* Check the ETH peripheral state */ @@ -244,33 +240,33 @@ HAL_StatusTypeDef HAL_ETH_Init(ETH_HandleTypeDef *heth) /* Clear CSR Clock Range CR[2:0] bits */ tmpreg &= ETH_MACMIIAR_CR_MASK; - /* Get hclk frequency value (168,000,000) */ + /* Get hclk frequency value (e.g. 168,000,000) */ hclk = HAL_RCC_GetHCLKFreq(); /* Set CR bits depending on hclk value */ - if( ( hclk >= 20000000 ) && ( hclk < 35000000 ) ) + if(( hclk >= 20000000uL ) && ( hclk < 35000000uL ) ) { /* CSR Clock Range between 20-35 MHz */ - tmpreg |= (uint32_t) ETH_MACMIIAR_CR_Div16; + tmpreg |= ( uint32_t) ETH_MACMIIAR_CR_Div16; } - else if( ( hclk >= 35000000 ) && ( hclk < 60000000 ) ) + else if( ( hclk >= 35000000uL ) && ( hclk < 60000000uL ) ) { /* CSR Clock Range between 35-60 MHz */ tmpreg |= ( uint32_t ) ETH_MACMIIAR_CR_Div26; } - else if((hclk >= 60000000 ) && ( hclk < 100000000 ) ) + else if( ( hclk >= 60000000uL ) && ( hclk < 100000000uL ) ) { /* CSR Clock Range between 60-100 MHz */ tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div42; } - else if((hclk >= 100000000 ) && ( hclk < 150000000)) + else if( ( hclk >= 100000000uL ) && ( hclk < 150000000uL ) ) { /* CSR Clock Range between 100-150 MHz */ tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div62; } - else /* ((hclk >= 150000000 ) && ( hclk <= 168000000)) */ + else /* ( ( hclk >= 150000000uL ) && ( hclk <= 183000000uL ) ) */ { - /* CSR Clock Range between 150-168 MHz */ + /* CSR Clock Range between 150-183 MHz */ tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div102; } @@ -314,161 +310,6 @@ HAL_StatusTypeDef HAL_ETH_DeInit(ETH_HandleTypeDef *heth) return HAL_OK; } -/** - * @brief Initializes the DMA Tx descriptors in chain mode. - * @param heth: pointer to a ETH_HandleTypeDef structure that contains - * the configuration information for ETHERNET module - * @param DMATxDescTab: Pointer to the first Tx desc list - * @param TxBuff: Pointer to the first TxBuffer list - * @param TxBuffCount: Number of the used Tx desc in the list - * @retval HAL status - */ -HAL_StatusTypeDef HAL_ETH_DMATxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *pxDMATable, uint8_t *ucDataBuffer, uint32_t ulBufferCount) -{ - uint32_t i = 0; - ETH_DMADescTypeDef *pxDMADescriptor; - - /* Process Locked */ - __HAL_LOCK( heth ); - - /* Set the ETH peripheral state to BUSY */ - heth->State = HAL_ETH_STATE_BUSY; - - /* Set the TxDesc pointer with the first one of the pxDMATable list */ - heth->TxDesc = pxDMATable; - - /* Fill each DMA descriptor with the right values */ - for( i=0; i < ulBufferCount; i++ ) - { - /* Get the pointer on the ith member of the descriptor list */ - pxDMADescriptor = pxDMATable + i; - - /* Set Second Address Chained bit */ - pxDMADescriptor->Status = ETH_DMATXDESC_TCH; - - pxDMADescriptor->ControlBufferSize = 0; - - /* Set Buffer1 address pointer */ - if( ucDataBuffer != NULL ) - { - pxDMADescriptor->Buffer1Addr = ( uint32_t )( &ucDataBuffer[ i * ETH_TX_BUF_SIZE ] ); - } - else - { - /* Buffer space is not provided because it uses zero-copy transmissions. */ - pxDMADescriptor->Buffer1Addr = ( uint32_t )0u; - } - - if (heth->Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE) - { - /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */ - pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL; - } - - /* Initialize the next descriptor with the Next Descriptor Polling Enable */ - if(i < ( ulBufferCount - 1 ) ) - { - /* Set next descriptor address register with next descriptor base address */ - pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMATable + i + 1 ); - } - else - { - /* For last descriptor, set next descriptor address register equal to the first descriptor base address */ - pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) pxDMATable; - } - } - - /* Set Transmit Descriptor List Address Register */ - heth->Instance->DMATDLAR = ( uint32_t ) pxDMATable; - - /* Set ETH HAL State to Ready */ - heth->State= HAL_ETH_STATE_READY; - - /* Process Unlocked */ - __HAL_UNLOCK( heth ); - - /* Return function status */ - return HAL_OK; -} - -/** - * @brief Initializes the DMA Rx descriptors in chain mode. - * @param heth: pointer to a ETH_HandleTypeDef structure that contains - * the configuration information for ETHERNET module - * @param DMARxDescTab: Pointer to the first Rx desc list - * @param RxBuff: Pointer to the first RxBuffer list - * @param RxBuffCount: Number of the used Rx desc in the list - * @retval HAL status - */ -HAL_StatusTypeDef HAL_ETH_DMARxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *pxDMATable, uint8_t *ucDataBuffer, uint32_t ulBufferCount) -{ - uint32_t i = 0; - ETH_DMADescTypeDef *pxDMADescriptor; - - /* Process Locked */ - __HAL_LOCK( heth ); - - /* Set the ETH peripheral state to BUSY */ - heth->State = HAL_ETH_STATE_BUSY; - - /* Set the RxDesc pointer with the first one of the pxDMATable list */ - heth->RxDesc = pxDMATable; - - /* Fill each DMA descriptor with the right values */ - for(i=0; i < ulBufferCount; i++) - { - /* Get the pointer on the ith member of the descriptor list */ - pxDMADescriptor = pxDMATable+i; - - /* Set Own bit of the Rx descriptor Status */ - pxDMADescriptor->Status = ETH_DMARXDESC_OWN; - - /* Set Buffer1 size and Second Address Chained bit */ - pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | ETH_RX_BUF_SIZE; - - /* Set Buffer1 address pointer */ - if( ucDataBuffer != NULL ) - { - pxDMADescriptor->Buffer1Addr = ( uint32_t )( &ucDataBuffer[ i * ETH_RX_BUF_SIZE ] ); - } - else - { - /* Buffer space is not provided because it uses zero-copy reception. */ - pxDMADescriptor->Buffer1Addr = ( uint32_t )0u; - } - - if( heth->Init.RxMode == ETH_RXINTERRUPT_MODE ) - { - /* Enable Ethernet DMA Rx Descriptor interrupt */ - pxDMADescriptor->ControlBufferSize &= ~ETH_DMARXDESC_DIC; - } - - /* Initialize the next descriptor with the Next Descriptor Polling Enable */ - if(i < (ulBufferCount-1)) - { - /* Set next descriptor address register with next descriptor base address */ - pxDMADescriptor->Buffer2NextDescAddr = (uint32_t)(pxDMATable+i+1); - } - else - { - /* For last descriptor, set next descriptor address register equal to the first descriptor base address */ - pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) pxDMATable; - } - } - - /* Set Receive Descriptor List Address Register */ - heth->Instance->DMARDLAR = ( uint32_t ) pxDMATable; - - /* Set ETH HAL State to Ready */ - heth->State= HAL_ETH_STATE_READY; - - /* Process Unlocked */ - __HAL_UNLOCK( heth ); - - /* Return function status */ - return HAL_OK; -} - /** * @brief Initializes the ETH MSP. * @param heth: pointer to a ETH_HandleTypeDef structure that contains @@ -480,6 +321,7 @@ __weak void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) /* NOTE : This function Should not be modified, when the callback is needed, the HAL_ETH_MspInit could be implemented in the user file */ + ( void ) heth; } /** @@ -493,6 +335,7 @@ __weak void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) /* NOTE : This function Should not be modified, when the callback is needed, the HAL_ETH_MspDeInit could be implemented in the user file */ + ( void ) heth; } /** @@ -522,209 +365,6 @@ __weak void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) * @{ */ -/** - * @brief Sends an Ethernet frame. - * @param heth: pointer to a ETH_HandleTypeDef structure that contains - * the configuration information for ETHERNET module - * @param FrameLength: Amount of data to be sent - * @retval HAL status - */ -HAL_StatusTypeDef HAL_ETH_TransmitFrame(ETH_HandleTypeDef *heth, uint32_t FrameLength) -{ - uint32_t bufcount = 0, size = 0, i = 0; - __IO ETH_DMADescTypeDef *pxDmaTxDesc = heth->TxDesc; - /* Process Locked */ - __HAL_LOCK( heth ); - - /* Set the ETH peripheral state to BUSY */ - heth->State = HAL_ETH_STATE_BUSY; - - if( FrameLength == 0 ) - { - /* Set ETH HAL state to READY */ - heth->State = HAL_ETH_STATE_READY; - - /* Process Unlocked */ - __HAL_UNLOCK( heth ); - - return HAL_ERROR; - } - - /* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */ - if( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) != ( uint32_t ) RESET ) - { - /* OWN bit set */ - heth->State = HAL_ETH_STATE_BUSY_TX; - - /* Process Unlocked */ - __HAL_UNLOCK( heth ); - - return HAL_ERROR; - } - - /* Get the number of needed Tx buffers for the current frame, rounding up. */ - bufcount = ( FrameLength + ETH_TX_BUF_SIZE - 1 ) / ETH_TX_BUF_SIZE; - - if (bufcount == 1) - { - /* Set LAST and FIRST segment */ - pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS; - /* Set frame size */ - pxDmaTxDesc->ControlBufferSize = ( FrameLength & ETH_DMATXDESC_TBS1 ); - /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ - pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN; - /* Point to next descriptor */ - heth->TxDesc = ( ETH_DMADescTypeDef * ) ( heth->TxDesc->Buffer2NextDescAddr ); - } - else - { - for( i = 0; i < bufcount; i++ ) - { - /* Clear FIRST and LAST segment bits */ - uint32_t ulStatus = heth->TxDesc->Status & ~( ETH_DMATXDESC_FS | ETH_DMATXDESC_LS ); - - if( i == 0 ) - { - /* Setting the first segment bit */ - heth->TxDesc->Status = ulStatus | ETH_DMATXDESC_FS; - } - - /* Program size */ - if (i < (bufcount-1)) - { - heth->TxDesc->ControlBufferSize = (ETH_TX_BUF_SIZE & ETH_DMATXDESC_TBS1); - } - else - { - /* Setting the last segment bit */ - heth->TxDesc->Status = ulStatus | ETH_DMATXDESC_LS; - size = FrameLength - (bufcount-1)*ETH_TX_BUF_SIZE; - heth->TxDesc->ControlBufferSize = (size & ETH_DMATXDESC_TBS1); - } - - /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ - heth->TxDesc->Status |= ETH_DMATXDESC_OWN; - /* point to next descriptor */ - heth->TxDesc = (ETH_DMADescTypeDef *)( heth->TxDesc->Buffer2NextDescAddr ); - } - } - - __DSB(); - - /* When Tx Buffer unavailable flag is set: clear it and resume transmission */ - if( ( heth->Instance->DMASR & ETH_DMASR_TBUS ) != ( uint32_t )RESET ) - { - heth->Instance->DMACHTDR = ( uint32_t )pxDmaTxDesc; - - /* Clear TBUS ETHERNET DMA flag */ - heth->Instance->DMASR = ETH_DMASR_TBUS; - /* Resume DMA transmission*/ - heth->Instance->DMATPDR = 0; - } - - /* Set ETH HAL State to Ready */ - heth->State = HAL_ETH_STATE_READY; - - /* Process Unlocked */ - __HAL_UNLOCK( heth ); - - /* Return function status */ - return HAL_OK; -} - -/** - * @brief Checks for received frames. - * @param heth: pointer to a ETH_HandleTypeDef structure that contains - * the configuration information for ETHERNET module - * @retval HAL status - */ -HAL_StatusTypeDef HAL_ETH_GetReceivedFrame_IT( ETH_HandleTypeDef *heth ) -{ - return HAL_ETH_GetReceivedFrame( heth ); -} - -HAL_StatusTypeDef HAL_ETH_GetReceivedFrame( ETH_HandleTypeDef *heth ) -{ -uint32_t ulCounter = 0; -ETH_DMADescTypeDef *pxDescriptor = heth->RxDesc; -HAL_StatusTypeDef xResult = HAL_ERROR; - - /* Process Locked */ - __HAL_LOCK( heth ); - - /* Check the ETH state to BUSY */ - heth->State = HAL_ETH_STATE_BUSY; - - /* Scan descriptors owned by CPU */ - while( ( ( pxDescriptor->Status & ETH_DMARXDESC_OWN ) == 0ul ) && ( ulCounter < ETH_RXBUFNB ) ) - { - uint32_t ulStatus = pxDescriptor->Status; - - /* Just for security. */ - ulCounter++; - - if( ( ulStatus & ( ETH_DMARXDESC_FS | ETH_DMARXDESC_LS ) ) == ( uint32_t )ETH_DMARXDESC_FS ) - { - /* First segment in frame, but not the last. */ - heth->RxFrameInfos.FSRxDesc = pxDescriptor; - heth->RxFrameInfos.LSRxDesc = ( ETH_DMADescTypeDef *)NULL; - heth->RxFrameInfos.SegCount = 1; - /* Point to next descriptor. */ - pxDescriptor = (ETH_DMADescTypeDef*) (pxDescriptor->Buffer2NextDescAddr); - heth->RxDesc = pxDescriptor; - } - else if( ( ulStatus & ( ETH_DMARXDESC_LS | ETH_DMARXDESC_FS ) ) == 0ul ) - { - /* This is an intermediate segment, not first, not last. */ - /* Increment segment count. */ - heth->RxFrameInfos.SegCount++; - /* Move to the next descriptor. */ - pxDescriptor = ( ETH_DMADescTypeDef * ) ( pxDescriptor->Buffer2NextDescAddr ); - heth->RxDesc = pxDescriptor; - } - /* Must be a last segment */ - else - { - /* This is the last segment. */ - /* Check if last segment is first segment: one segment contains the frame */ - if( heth->RxFrameInfos.SegCount == 0 ) - { - /* Remember the first segment. */ - heth->RxFrameInfos.FSRxDesc = pxDescriptor; - } - - /* Increment segment count */ - heth->RxFrameInfos.SegCount++; - - /* Remember the last segment. */ - heth->RxFrameInfos.LSRxDesc = pxDescriptor; - - /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */ - heth->RxFrameInfos.length = - ( ( ulStatus & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4; - - /* Get the address of the buffer start address */ - heth->RxFrameInfos.buffer = heth->RxFrameInfos.FSRxDesc->Buffer1Addr; - - /* Point to next descriptor */ - heth->RxDesc = ( ETH_DMADescTypeDef * ) pxDescriptor->Buffer2NextDescAddr; - - /* Return OK status: a packet was received. */ - xResult = HAL_OK; - break; - } - } - - /* Set ETH HAL State to Ready */ - heth->State = HAL_ETH_STATE_READY; - - /* Process Unlocked */ - __HAL_UNLOCK( heth ); - - /* Return function status */ - return xResult; -} - #define ETH_DMA_ALL_INTS \ ( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | ETH_DMA_IT_AIS | ETH_DMA_IT_ER | \ ETH_DMA_IT_FBE | ETH_DMA_IT_ET | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \ @@ -772,6 +412,7 @@ __weak void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth) /* NOTE : This function Should not be modified, when the callback is needed, the HAL_ETH_TxCpltCallback could be implemented in the user file */ + ( void ) heth; } /** @@ -785,6 +426,7 @@ __weak void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth) /* NOTE : This function Should not be modified, when the callback is needed, the HAL_ETH_TxCpltCallback could be implemented in the user file */ + ( void ) heth; } /** @@ -798,6 +440,7 @@ __weak void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth) /* NOTE : This function Should not be modified, when the callback is needed, the HAL_ETH_TxCpltCallback could be implemented in the user file */ + ( void ) heth; } /** @@ -814,8 +457,8 @@ __weak void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth) */ HAL_StatusTypeDef HAL_ETH_ReadPHYRegister(ETH_HandleTypeDef *heth, uint16_t PHYReg, uint32_t *RegValue) { -uint32_t tmpreg = 0; -uint32_t tickstart = 0; +uint32_t tmpreg = 0uL; +uint32_t tickstart = 0uL; HAL_StatusTypeDef xResult; /* Check parameters */ @@ -856,7 +499,7 @@ HAL_StatusTypeDef xResult; { tmpreg = heth->Instance->MACMIIAR; - if( ( tmpreg & ETH_MACMIIAR_MB ) == 0ul ) + if( ( tmpreg & ETH_MACMIIAR_MB ) == 0uL ) { /* Get MACMIIDR value */ *RegValue = ( uint32_t ) heth->Instance->MACMIIDR; @@ -1067,6 +710,28 @@ HAL_StatusTypeDef HAL_ETH_Stop(ETH_HandleTypeDef *heth) return HAL_OK; } +static void vRegisterDelay() +{ +uint32_t uxCount; + /* + * Regarding the HAL delay functions, I noticed that HAL delay is being used to workaround the + * "Successive write operations to the same register might not be fully taken into account" errata. + * The workaround requires a delay of four TX_CLK/RX_CLK clock cycles. For a 10 Mbit connection, + * these clocks are running at 2.5 MHz, so this delay would be at most 1.6 microseconds. + * 180 Mhz = 288 loops + * 168 Mhz = 269 loops + * 100 Mhz = 160 loops + * 84 Mhz = 134 loops + */ + #define WAIT_TIME_NS 1600uL /* 1.6 microseconds */ + #define CPU_MAX_FREQ SystemCoreClock /* 84, 100, 168 or 180 MHz */ + uint32_t NOP_COUNT = ( WAIT_TIME_NS * ( CPU_MAX_FREQ / 1000uL ) ) / 1000000uL; + for( uxCount = NOP_COUNT; uxCount > 0uL; uxCount-- ) + { + __NOP(); + } +} + static void prvWriteMACFCR( ETH_HandleTypeDef *heth, uint32_t ulValue) { /* Enable the MAC transmission */ @@ -1077,7 +742,7 @@ static void prvWriteMACFCR( ETH_HandleTypeDef *heth, uint32_t ulValue) Read it back, wait a ms and */ ( void ) heth->Instance->MACFCR; - HAL_Delay( ETH_REG_WRITE_DELAY ); + vRegisterDelay(); heth->Instance->MACFCR = ulValue; } @@ -1092,7 +757,7 @@ static void prvWriteDMAOMR( ETH_HandleTypeDef *heth, uint32_t ulValue) Read it back, wait a ms and */ ( void ) heth->Instance->DMAOMR; - HAL_Delay( ETH_REG_WRITE_DELAY ); + vRegisterDelay(); heth->Instance->DMAOMR = ulValue; } @@ -1107,7 +772,7 @@ static void prvWriteMACCR( ETH_HandleTypeDef *heth, uint32_t ulValue) Read it back, wait a ms and */ ( void ) heth->Instance->MACCR; - HAL_Delay( ETH_REG_WRITE_DELAY ); + vRegisterDelay(); heth->Instance->MACCR = ulValue; } @@ -1121,7 +786,7 @@ static void prvWriteMACCR( ETH_HandleTypeDef *heth, uint32_t ulValue) */ HAL_StatusTypeDef HAL_ETH_ConfigMAC(ETH_HandleTypeDef *heth, ETH_MACInitTypeDef *macconf) { - uint32_t tmpreg = 0; + uint32_t tmpreg = 0uL; /* Process Locked */ __HAL_LOCK( heth ); @@ -1202,7 +867,7 @@ HAL_StatusTypeDef HAL_ETH_ConfigMAC(ETH_HandleTypeDef *heth, ETH_MACInitTypeDef /* Wait until the write operation will be taken into account : at least four TX_CLK/RX_CLK clock cycles */ tmpreg = heth->Instance->MACFFR; - HAL_Delay(ETH_REG_WRITE_DELAY); + vRegisterDelay(); heth->Instance->MACFFR = tmpreg; /*--------------- ETHERNET MACHTHR and MACHTLR Configuration ---------------*/ @@ -1236,7 +901,7 @@ HAL_StatusTypeDef HAL_ETH_ConfigMAC(ETH_HandleTypeDef *heth, ETH_MACInitTypeDef /* Wait until the write operation will be taken into account : at least four TX_CLK/RX_CLK clock cycles */ tmpreg = heth->Instance->MACVLANTR; - HAL_Delay(ETH_REG_WRITE_DELAY); + vRegisterDelay(); heth->Instance->MACVLANTR = tmpreg; } else /* macconf == NULL : here we just configure Speed and Duplex mode */ @@ -1246,7 +911,7 @@ HAL_StatusTypeDef HAL_ETH_ConfigMAC(ETH_HandleTypeDef *heth, ETH_MACInitTypeDef tmpreg = heth->Instance->MACCR; /* Clear FES and DM bits */ - tmpreg &= ~((uint32_t)0x00004800); + tmpreg &= ~( ( uint32_t ) 0x00004800uL ); tmpreg |= (uint32_t)(heth->Init.Speed | heth->Init.DuplexMode); @@ -1273,7 +938,7 @@ HAL_StatusTypeDef HAL_ETH_ConfigMAC(ETH_HandleTypeDef *heth, ETH_MACInitTypeDef */ HAL_StatusTypeDef HAL_ETH_ConfigDMA(ETH_HandleTypeDef *heth, ETH_DMAInitTypeDef *dmaconf) { - uint32_t tmpreg = 0; + uint32_t tmpreg = 0uL; /* Process Locked */ __HAL_LOCK( heth ); @@ -1332,7 +997,7 @@ HAL_StatusTypeDef HAL_ETH_ConfigDMA(ETH_HandleTypeDef *heth, ETH_DMAInitTypeDef /* Wait until the write operation will be taken into account: at least four TX_CLK/RX_CLK clock cycles */ tmpreg = heth->Instance->DMABMR; - HAL_Delay(ETH_REG_WRITE_DELAY); + vRegisterDelay(); heth->Instance->DMABMR = tmpreg; /* Set the ETH state to Ready */ @@ -1402,7 +1067,7 @@ static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err) { ETH_MACInitTypeDef macinit; ETH_DMAInitTypeDef dmainit; - uint32_t tmpreg = 0; + uint32_t tmpreg = 0uL; if (err != ETH_SUCCESS) /* Auto-negotiation failed */ { @@ -1440,16 +1105,16 @@ static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err) macinit.PromiscuousMode = ETH_PROMISCUOUS_MODE_DISABLE; macinit.MulticastFramesFilter = ETH_MULTICASTFRAMESFILTER_PERFECT; macinit.UnicastFramesFilter = ETH_UNICASTFRAMESFILTER_PERFECT; - macinit.HashTableHigh = 0x0; - macinit.HashTableLow = 0x0; - macinit.PauseTime = 0x0; + macinit.HashTableHigh = 0x0uL; + macinit.HashTableLow = 0x0uL; + macinit.PauseTime = 0x0uL; macinit.ZeroQuantaPause = ETH_ZEROQUANTAPAUSE_DISABLE; macinit.PauseLowThreshold = ETH_PAUSELOWTHRESHOLD_MINUS4; macinit.UnicastPauseFrameDetect = ETH_UNICASTPAUSEFRAMEDETECT_DISABLE; macinit.ReceiveFlowControl = ETH_RECEIVEFLOWCONTROL_DISABLE; macinit.TransmitFlowControl = ETH_TRANSMITFLOWCONTROL_DISABLE; macinit.VLANTagComparison = ETH_VLANTAGCOMPARISON_16BIT; - macinit.VLANTagIdentifier = 0x0; + macinit.VLANTagIdentifier = 0x0uL; /*------------------------ ETHERNET MACCR Configuration --------------------*/ /* Get the ETHERNET MACCR value */ @@ -1508,7 +1173,7 @@ static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err) /* Wait until the write operation will be taken into account: at least four TX_CLK/RX_CLK clock cycles */ tmpreg = heth->Instance->MACFFR; - HAL_Delay(ETH_REG_WRITE_DELAY); + vRegisterDelay(); heth->Instance->MACFFR = tmpreg; /*--------------- ETHERNET MACHTHR and MACHTLR Configuration --------------*/ @@ -1549,7 +1214,7 @@ static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err) /* Wait until the write operation will be taken into account: at least four TX_CLK/RX_CLK clock cycles */ tmpreg = heth->Instance->MACVLANTR; - HAL_Delay(ETH_REG_WRITE_DELAY); + vRegisterDelay(); heth->Instance->MACVLANTR = tmpreg; /* Ethernet DMA default initialization ************************************/ @@ -1567,7 +1232,7 @@ static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err) dmainit.RxDMABurstLength = ETH_RXDMABURSTLENGTH_32BEAT; dmainit.TxDMABurstLength = ETH_TXDMABURSTLENGTH_32BEAT; dmainit.EnhancedDescriptorFormat = ETH_DMAENHANCEDDESCRIPTOR_ENABLE; - dmainit.DescriptorSkipLength = 0x0; + dmainit.DescriptorSkipLength = 0x0uL; dmainit.DMAArbitration = ETH_DMAARBITRATION_ROUNDROBIN_RXTX_1_1; /* Get the ETHERNET DMAOMR value */ @@ -1617,7 +1282,7 @@ static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err) /* Wait until the write operation will be taken into account: at least four TX_CLK/RX_CLK clock cycles */ tmpreg = heth->Instance->DMABMR; - HAL_Delay(ETH_REG_WRITE_DELAY); + vRegisterDelay(); heth->Instance->DMABMR = tmpreg; if(heth->Init.RxMode == ETH_RXINTERRUPT_MODE) @@ -1647,11 +1312,14 @@ static void ETH_MACAddressConfig(ETH_HandleTypeDef *heth, uint32_t MacAddr, uint { uint32_t tmpreg; + ( void ) heth; + /* Check the parameters */ assert_param( IS_ETH_MAC_ADDRESS0123( MacAddr ) ); /* Calculate the selected MAC address high register */ - tmpreg = 0x80000000ul | ( ( uint32_t )Addr[ 5 ] << 8) | (uint32_t)Addr[ 4 ]; + /* Register ETH_MACA0HR: Bit 31 MO: Always 1. */ + tmpreg = 0x80000000uL | ( ( uint32_t )Addr[ 5 ] << 8) | (uint32_t)Addr[ 4 ]; /* Load the selected MAC address high register */ ( * ( __IO uint32_t * ) ( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + MacAddr ) ) ) = tmpreg; /* Calculate the selected MAC address low register */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.h index f4b74d226..f91122594 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.h @@ -44,6 +44,14 @@ #define __STM32F4xx_HAL_ETH_H #define __STM32F7xx_HAL_ETH_H +#if defined(STM32F7xx) + #include "stm32f7xx_hal_def.h" +#elif defined(STM32F407xx) || defined(STM32F417xx) || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) + #include "stm32f4xx_hal_def.h" +#elif defined(STM32F2xx) + #include "stm32f2xx_hal_def.h" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -367,6 +375,33 @@ * @} */ +#ifdef _lint + #ifdef __IO + #undef __IO + #endif + #define __IO + + #ifdef ETH_TypeDef + #undef ETH_TypeDef + #endif + #define ETH_TypeDef void + + #ifdef HAL_LockTypeDef + #undef HAL_LockTypeDef + #endif + #define HAL_LockTypeDef unsigned + + #ifdef ETH_RX_BUF_SIZE + #undef ETH_RX_BUF_SIZE + #endif + #define ETH_RX_BUF_SIZE 1536 + + #ifdef ETH_TX_BUF_SIZE + #undef ETH_TX_BUF_SIZE + #endif + #define ETH_TX_BUF_SIZE 1536 +#endif + /* Exported types ------------------------------------------------------------*/ /** @defgroup ETH_Exported_Types ETH Exported Types * @{ @@ -1244,33 +1279,37 @@ typedef struct /** @defgroup ETH_MAC_Debug_flags ETH MAC Debug flags * @{ */ -#define ETH_MAC_TXFIFO_FULL ((uint32_t)0x02000000) /* Tx FIFO full */ -#define ETH_MAC_TXFIFONOT_EMPTY ((uint32_t)0x01000000) /* Tx FIFO not empty */ -#define ETH_MAC_TXFIFO_WRITE_ACTIVE ((uint32_t)0x00400000) /* Tx FIFO write active */ -#define ETH_MAC_TXFIFO_IDLE ((uint32_t)0x00000000) /* Tx FIFO read status: Idle */ -#define ETH_MAC_TXFIFO_READ ((uint32_t)0x00100000) /* Tx FIFO read status: Read (transferring data to the MAC transmitter) */ -#define ETH_MAC_TXFIFO_WAITING ((uint32_t)0x00200000) /* Tx FIFO read status: Waiting for TxStatus from MAC transmitter */ -#define ETH_MAC_TXFIFO_WRITING ((uint32_t)0x00300000) /* Tx FIFO read status: Writing the received TxStatus or flushing the TxFIFO */ -#define ETH_MAC_TRANSMISSION_PAUSE ((uint32_t)0x00080000) /* MAC transmitter in pause */ -#define ETH_MAC_TRANSMITFRAMECONTROLLER_IDLE ((uint32_t)0x00000000) /* MAC transmit frame controller: Idle */ -#define ETH_MAC_TRANSMITFRAMECONTROLLER_WAITING ((uint32_t)0x00020000) /* MAC transmit frame controller: Waiting for Status of previous frame or IFG/backoff period to be over */ -#define ETH_MAC_TRANSMITFRAMECONTROLLER_GENRATING_PCF ((uint32_t)0x00040000) /* MAC transmit frame controller: Generating and transmitting a Pause control frame (in full duplex mode) */ -#define ETH_MAC_TRANSMITFRAMECONTROLLER_TRANSFERRING ((uint32_t)0x00060000) /* MAC transmit frame controller: Transferring input frame for transmission */ -#define ETH_MAC_MII_TRANSMIT_ACTIVE ((uint32_t)0x00010000) /* MAC MII transmit engine active */ -#define ETH_MAC_RXFIFO_EMPTY ((uint32_t)0x00000000) /* Rx FIFO fill level: empty */ -#define ETH_MAC_RXFIFO_BELOW_THRESHOLD ((uint32_t)0x00000100) /* Rx FIFO fill level: fill-level below flow-control de-activate threshold */ -#define ETH_MAC_RXFIFO_ABOVE_THRESHOLD ((uint32_t)0x00000200) /* Rx FIFO fill level: fill-level above flow-control activate threshold */ -#define ETH_MAC_RXFIFO_FULL ((uint32_t)0x00000300) /* Rx FIFO fill level: full */ -#define ETH_MAC_READCONTROLLER_IDLE ((uint32_t)0x00000060) /* Rx FIFO read controller IDLE state */ -#define ETH_MAC_READCONTROLLER_READING_DATA ((uint32_t)0x00000060) /* Rx FIFO read controller Reading frame data */ -#define ETH_MAC_READCONTROLLER_READING_STATUS ((uint32_t)0x00000060) /* Rx FIFO read controller Reading frame status (or time-stamp) */ -#define ETH_MAC_READCONTROLLER_ FLUSHING ((uint32_t)0x00000060) /* Rx FIFO read controller Flushing the frame data and status */ -#define ETH_MAC_RXFIFO_WRITE_ACTIVE ((uint32_t)0x00000010) /* Rx FIFO write controller active */ -#define ETH_MAC_SMALL_FIFO_NOTACTIVE ((uint32_t)0x00000000) /* MAC small FIFO read / write controllers not active */ -#define ETH_MAC_SMALL_FIFO_READ_ACTIVE ((uint32_t)0x00000002) /* MAC small FIFO read controller active */ -#define ETH_MAC_SMALL_FIFO_WRITE_ACTIVE ((uint32_t)0x00000004) /* MAC small FIFO write controller active */ -#define ETH_MAC_SMALL_FIFO_RW_ACTIVE ((uint32_t)0x00000006) /* MAC small FIFO read / write controllers active */ -#define ETH_MAC_MII_RECEIVE_PROTOCOL_ACTIVE ((uint32_t)0x00000001) /* MAC MII receive protocol engine active */ +#ifndef ETH_MAC_TXFIFO_FULL + #define ETH_MAC_TXFIFO_FULL ((uint32_t)0x02000000) /* Tx FIFO full */ + #define ETH_MAC_TXFIFONOT_EMPTY ((uint32_t)0x01000000) /* Tx FIFO not empty */ + #define ETH_MAC_TXFIFO_WRITE_ACTIVE ((uint32_t)0x00400000) /* Tx FIFO write active */ + #define ETH_MAC_TXFIFO_IDLE ((uint32_t)0x00000000) /* Tx FIFO read status: Idle */ + #define ETH_MAC_TXFIFO_READ ((uint32_t)0x00100000) /* Tx FIFO read status: Read (transferring data to the MAC transmitter) */ + #define ETH_MAC_TXFIFO_WAITING ((uint32_t)0x00200000) /* Tx FIFO read status: Waiting for TxStatus from MAC transmitter */ + #define ETH_MAC_TXFIFO_WRITING ((uint32_t)0x00300000) /* Tx FIFO read status: Writing the received TxStatus or flushing the TxFIFO */ + #define ETH_MAC_TRANSMISSION_PAUSE ((uint32_t)0x00080000) /* MAC transmitter in pause */ + #define ETH_MAC_TRANSMITFRAMECONTROLLER_IDLE ((uint32_t)0x00000000) /* MAC transmit frame controller: Idle */ + #define ETH_MAC_TRANSMITFRAMECONTROLLER_WAITING ((uint32_t)0x00020000) /* MAC transmit frame controller: Waiting for Status of previous frame or IFG/backoff period to be over */ + #define ETH_MAC_TRANSMITFRAMECONTROLLER_GENRATING_PCF ((uint32_t)0x00040000) /* MAC transmit frame controller: Generating and transmitting a Pause control frame (in full duplex mode) */ + #define ETH_MAC_TRANSMITFRAMECONTROLLER_TRANSFERRING ((uint32_t)0x00060000) /* MAC transmit frame controller: Transferring input frame for transmission */ + #define ETH_MAC_MII_TRANSMIT_ACTIVE ((uint32_t)0x00010000) /* MAC MII transmit engine active */ + #define ETH_MAC_RXFIFO_EMPTY ((uint32_t)0x00000000) /* Rx FIFO fill level: empty */ + #define ETH_MAC_RXFIFO_BELOW_THRESHOLD ((uint32_t)0x00000100) /* Rx FIFO fill level: fill-level below flow-control de-activate threshold */ + #define ETH_MAC_RXFIFO_ABOVE_THRESHOLD ((uint32_t)0x00000200) /* Rx FIFO fill level: fill-level above flow-control activate threshold */ + #define ETH_MAC_RXFIFO_FULL ((uint32_t)0x00000300) /* Rx FIFO fill level: full */ + #define ETH_MAC_READCONTROLLER_IDLE ((uint32_t)0x00000060) /* Rx FIFO read controller IDLE state */ + #define ETH_MAC_READCONTROLLER_READING_DATA ((uint32_t)0x00000060) /* Rx FIFO read controller Reading frame data */ + #define ETH_MAC_READCONTROLLER_READING_STATUS ((uint32_t)0x00000060) /* Rx FIFO read controller Reading frame status (or time-stamp) */ + #define ETH_MAC_READCONTROLLER_ FLUSHING ((uint32_t)0x00000060) /* Rx FIFO read controller Flushing the frame data and status */ + #define ETH_MAC_RXFIFO_WRITE_ACTIVE ((uint32_t)0x00000010) /* Rx FIFO write controller active */ + #define ETH_MAC_SMALL_FIFO_NOTACTIVE ((uint32_t)0x00000000) /* MAC small FIFO read / write controllers not active */ + #define ETH_MAC_SMALL_FIFO_READ_ACTIVE ((uint32_t)0x00000002) /* MAC small FIFO read controller active */ + #define ETH_MAC_SMALL_FIFO_WRITE_ACTIVE ((uint32_t)0x00000004) /* MAC small FIFO write controller active */ + #define ETH_MAC_SMALL_FIFO_RW_ACTIVE ((uint32_t)0x00000006) /* MAC small FIFO read / write controllers active */ + #define ETH_MAC_MII_RECEIVE_PROTOCOL_ACTIVE ((uint32_t)0x00000001) /* MAC MII receive protocol engine active */ +#else + /* stm32_hal_legacy.h has probably been included. That file defines 'ETH_MAC_TXFIFO_FULL' and all macro's here below. */ +#endif /** * @} */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/FaultInjection.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/FaultInjection.c index e100a4e97..502fbd661 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/FaultInjection.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/FaultInjection.c @@ -77,7 +77,8 @@ return pxNetworkBufferIn; if( ulCallCount > ulNextFaultCallCount ) { - ulNextFaultCallCount = ipconfigRAND32() % xMAX_FAULT_INJECTION_RATE; + xApplicationGetRandomNumber( &( ulNextFaultCallCount ) ); + ulNextFaultCallCount = ulNextFaultCallCount % xMAX_FAULT_INJECTION_RATE; if( ulNextFaultCallCount < xMIN_FAULT_INJECTION_RATE ) { ulNextFaultCallCount = xMIN_FAULT_INJECTION_RATE; @@ -85,7 +86,8 @@ return pxNetworkBufferIn; ulCallCount = 0; - ulFault = ipconfigRAND32() % xNUM_FAULT_TYPES; + xApplicationGetRandomNumber( &( ulFault ) ); + ulFault = ulFault % xNUM_FAULT_TYPES; if( ulFaultLogIndex < xFAULT_LOG_SIZE ) { diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c index bbc0a8c72..1c11976cb 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c @@ -1,27 +1,27 @@ /* - * 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 - */ +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 @@ -50,12 +50,10 @@ /* Provided memory configured as uncached. */ #include "uncached_memory.h" -#ifndef niEMAC_HANDLER_TASK_PRIORITY - #define niEMAC_HANDLER_TASK_PRIORITY configMAX_PRIORITIES - 1 +#ifndef BMSR_LINK_STATUS + #define BMSR_LINK_STATUS 0x0004UL #endif -#define niBMSR_LINK_STATUS 0x0004UL - #ifndef PHY_LS_HIGH_CHECK_TIME_MS /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not receiving packets. */ @@ -190,7 +188,7 @@ const TickType_t xWaitLinkDelay = pdMS_TO_TICKS( 7000UL ), xWaitRelinkDelay = pd possible priority to ensure the interrupt handler can return directly to it. The task's handle is stored in xEMACTaskHandle so interrupts can notify the task when there is something to process. */ - xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle ); + xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle ); } else { @@ -208,27 +206,7 @@ const TickType_t xWaitLinkDelay = pdMS_TO_TICKS( 7000UL ), xWaitRelinkDelay = pd BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxBuffer, BaseType_t bReleaseAfterSend ) { - #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) - { - ProtocolPacket_t *pxPacket; - - /* If the peripheral must calculate the checksum, it wants - the protocol checksum to have a value of zero. */ - pxPacket = ( ProtocolPacket_t * ) ( pxBuffer->pucEthernetBuffer ); - if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP ) - { - IPHeader_t *pxIPHeader = &( pxPacket->xUDPPacket.xIPHeader ); - - pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u; - pxIPHeader->usHeaderChecksum = 0u; - pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER ); - pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); - - usGenerateProtocolChecksum( (uint8_t*)&( pxPacket->xUDPPacket ), pxBuffer->xDataLength, pdTRUE ); - } - } - #endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */ - if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 ) + if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) { iptraceNETWORK_INTERFACE_TRANSMIT(); emacps_send_message( &xEMACpsif, pxBuffer, bReleaseAfterSend ); @@ -271,7 +249,7 @@ BaseType_t xReturn; } ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR ); - if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 ) + if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) { xReturn = pdTRUE; break; @@ -303,7 +281,7 @@ BaseType_t xGetPhyLinkStatus( void ) { BaseType_t xReturn; - if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) == 0 ) + if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 ) { xReturn = pdFALSE; } @@ -320,12 +298,11 @@ static void prvEMACHandlerTask( void *pvParameters ) { TimeOut_t xPhyTime; TickType_t xPhyRemTime; +UBaseType_t uxLastMinBufferCount = 0; UBaseType_t uxCurrentCount; BaseType_t xResult = 0; uint32_t xStatus; const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL ); -UBaseType_t uxLastMinBufferCount = 0; -UBaseType_t uxCurrentBufferCount = 0; /* Remove compiler warnings about unused parameters. */ ( void ) pvParameters; @@ -339,14 +316,14 @@ UBaseType_t uxCurrentBufferCount = 0; for( ;; ) { - uxCurrentBufferCount = uxGetMinimumFreeNetworkBuffers(); - if( uxLastMinBufferCount != uxCurrentBufferCount ) + uxCurrentCount = uxGetMinimumFreeNetworkBuffers(); + if( uxLastMinBufferCount != uxCurrentCount ) { /* The logging produced below may be helpful while tuning +TCP: see how many buffers are in use. */ - uxLastMinBufferCount = uxCurrentBufferCount; + uxLastMinBufferCount = uxCurrentCount; FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n", - uxGetNumberOfFreeNetworkBuffers(), uxCurrentBufferCount ) ); + uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) ); } #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) @@ -395,22 +372,19 @@ UBaseType_t uxCurrentBufferCount = 0; vTaskSetTimeOutState( &xPhyTime ); xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS ); xResult = 0; - /* Indicate that the Link Status is high, so that - xNetworkInterfaceOutput() can send packets. */ - ulPHYLinkStatus |= niBMSR_LINK_STATUS; } else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ) { xStatus = ulReadMDIO( PHY_REG_01_BMSR ); - if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != ( xStatus & niBMSR_LINK_STATUS ) ) + if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) ) { ulPHYLinkStatus = xStatus; - FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 ) ); + FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) ); } vTaskSetTimeOutState( &xPhyTime ); - if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 ) + if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) { xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS ); } diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif.h index a38ec81d7..823dee0d3 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif.h @@ -35,6 +35,7 @@ extern "C" { #include "xil_exception.h" #include "xpseudo_asm.h" #include "xil_cache.h" +#include "xil_printf.h" #include "xuartps.h" #include "xscugic.h" #include "xemacps.h" /* defines XEmacPs API */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c index e92c9c21f..fc09d2183 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c @@ -1,27 +1,36 @@ /* - * 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 - */ +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 +*/ + +#include "Zynq/x_emacpsif.h" +#include "Zynq/x_topology.h" +#include "xstatus.h" + +#include "xparameters.h" +#include "xparameters_ps.h" +#include "xil_exception.h" +#include "xil_mmu.h" #include "FreeRTOS.h" #include "task.h" @@ -34,15 +43,6 @@ #include "FreeRTOS_IP_Private.h" #include "NetworkBufferManagement.h" -#include "Zynq/x_emacpsif.h" -#include "Zynq/x_topology.h" -#include "xstatus.h" - -#include "xparameters.h" -#include "xparameters_ps.h" -#include "xil_exception.h" -#include "xil_mmu.h" - #include "uncached_memory.h" /* Two defines used to set or clear the EMAC interrupt */ @@ -56,6 +56,8 @@ #endif #define TX_OFFSET ipconfigPACKET_FILLER_SIZE +#define RX_BUFFER_ALIGNMENT 14 + /* Defined in NetworkInterface.c */ extern TaskHandle_t xEMACTaskHandle; @@ -119,6 +121,7 @@ size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount break; } #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) +#warning ipconfigZERO_COPY_TX_DRIVER is defined { void *pvBuffer = pxDMA_tx_buffers[ tail ]; NetworkBufferDescriptor_t *pxBuffer; @@ -289,8 +292,6 @@ TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u ); /* Start transmit */ xemacpsif->txBusy = pdTRUE; XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) ); - /* Reading it back is important compiler is optimised. */ - XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET ); } dsb(); @@ -313,35 +314,33 @@ void emacps_recv_handler(void *arg) portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } -static void prvPassEthMessages( NetworkBufferDescriptor_t *pxDescriptor ) +static NetworkBufferDescriptor_t *ethMsg = NULL; +static NetworkBufferDescriptor_t *ethLast = NULL; + +static void passEthMessages( void ) { IPStackEvent_t xRxEvent; xRxEvent.eEventType = eNetworkRxEvent; - xRxEvent.pvData = ( void * ) pxDescriptor; + xRxEvent.pvData = ( void * ) ethMsg; if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS ) { /* The buffer could not be sent to the stack so must be released again. This is a deferred handler taskr, not a real interrupt, so it is ok to use the task level function here. */ - #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) - { - do - { - NetworkBufferDescriptor_t *pxNext = pxDescriptor->pxNextBuffer; - vReleaseNetworkBufferAndDescriptor( pxDescriptor ); - pxDescriptor = pxNext; - } while( pxDescriptor != NULL ); - } - #else + do { - vReleaseNetworkBufferAndDescriptor( pxDescriptor ); - } - #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ + NetworkBufferDescriptor_t *xNext = ethMsg->pxNextBuffer; + vReleaseNetworkBufferAndDescriptor( ethMsg ); + ethMsg = xNext; + } while( ethMsg != NULL ); + iptraceETHERNET_RX_EVENT_LOST(); - FreeRTOS_printf( ( "prvPassEthMessages: Can not queue return packet!\n" ) ); + FreeRTOS_printf( ( "passEthMessages: Can not queue return packet!\n" ) ); } + + ethMsg = ethLast = NULL; } int emacps_check_rx( xemacpsif_s *xemacpsif ) @@ -350,10 +349,6 @@ NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer; int rx_bytes; volatile int msgCount = 0; int head = xemacpsif->rxHead; -#if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) - NetworkBufferDescriptor_t *pxFirstDescriptor = NULL; - NetworkBufferDescriptor_t *pxLastDescriptor = NULL; -#endif /* ipconfigUSE_LINKED_RX_MESSAGES */ /* There seems to be an issue (SI# 692601), see comments below. */ resetrx_on_no_rxdata(xemacpsif); @@ -369,7 +364,7 @@ int head = xemacpsif->rxHead; break; } - pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 ); + pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT, ( TickType_t ) 0 ); if( pxNewBuffer == NULL ) { /* A packet has been received, but there is no replacement for this Network Buffer. @@ -390,6 +385,7 @@ int head = xemacpsif->rxHead; rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK; pxBuffer->xDataLength = rx_bytes; + if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 ) { Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)rx_bytes ); @@ -398,35 +394,26 @@ int head = xemacpsif->rxHead; /* store it in the receive queue, where it'll be processed by a different handler. */ iptraceNETWORK_INTERFACE_RECEIVE(); - #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) - { - pxBuffer->pxNextBuffer = NULL; + pxBuffer->pxNextBuffer = NULL; - if( pxFirstDescriptor == NULL ) - { - // Becomes the first message - pxFirstDescriptor = pxBuffer; - } - else if( pxLastDescriptor != NULL ) - { - // Add to the tail - pxLastDescriptor->pxNextBuffer = pxBuffer; - } - - pxLastDescriptor = pxBuffer; + if( ethMsg == NULL ) + { + // Becomes the first message + ethMsg = pxBuffer; } - #else + else if( ethLast != NULL ) { - prvPassEthMessages( pxBuffer ); + // Add to the tail + ethLast->pxNextBuffer = pxBuffer; } - #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ + ethLast = pxBuffer; msgCount++; } { if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 ) { - Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE ); + Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT); } { uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK; @@ -435,12 +422,8 @@ int head = xemacpsif->rxHead; addr |= XEMACPS_RXBUF_WRAP_MASK; } /* Clearing 'XEMACPS_RXBUF_NEW_MASK' 0x00000001 *< Used bit.. */ - xemacpsif->rxSegments[ head ].flags = 0; xemacpsif->rxSegments[ head ].address = addr; - if (xemacpsif->rxSegments[ head ].address) - { - // Just to read it - } + xemacpsif->rxSegments[ head ].flags = 0; } } @@ -451,14 +434,10 @@ int head = xemacpsif->rxHead; xemacpsif->rxHead = head; } - #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + if( ethMsg != NULL ) { - if( pxFirstDescriptor != NULL ) - { - prvPassEthMessages( pxFirstDescriptor ); - } + passEthMessages( ); } - #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ return msgCount; } @@ -477,9 +456,9 @@ unsigned char *ucTxBuffer; xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer; xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK; #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) - pxDMA_tx_buffers[ index ] = ( unsigned char * )NULL; + pxDMA_tx_buffers[ index ] = ( void* )NULL; #else - pxDMA_tx_buffers[ index ] = ( unsigned char * )( ucTxBuffer + TX_OFFSET ); + pxDMA_tx_buffers[ index ] = ( void* )( ucTxBuffer + TX_OFFSET ); #endif ucTxBuffer += xemacpsif->uTxUnitSize; } @@ -528,7 +507,7 @@ XStatus init_dma(xemacpsif_s *xemacpsif) pxBuffer = pxDMA_rx_buffers[ iIndex ]; if( pxBuffer == NULL ) { - pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 ); + pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT, ( TickType_t ) 0 ); if( pxBuffer == NULL ) { FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) ); @@ -544,7 +523,7 @@ XStatus init_dma(xemacpsif_s *xemacpsif) if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 ) { Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, - (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE ); + (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT); } } diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.c index 3d835d9a2..e9443cda8 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.c @@ -22,19 +22,19 @@ #include #include +#include "Zynq/x_emacpsif.h" + /* FreeRTOS includes. */ #include "FreeRTOS.h" #include "task.h" #include "queue.h" +///* FreeRTOS+TCP includes. */ /* FreeRTOS+TCP includes. */ #include "FreeRTOS_IP.h" #include "FreeRTOS_Sockets.h" #include "FreeRTOS_IP_Private.h" #include "NetworkBufferManagement.h" -#include "NetworkInterface.h" - -#include "Zynq/x_emacpsif.h" extern TaskHandle_t xEMACTaskHandle; @@ -42,6 +42,8 @@ extern TaskHandle_t xEMACTaskHandle; *** to run it on a PEEP board ***/ +unsigned int link_speed = 100; + void setup_isr( xemacpsif_s *xemacpsif ) { /* @@ -139,6 +141,8 @@ int xResult; return xResult; } +BaseType_t xNetworkInterfaceInitialise( void ); + static void emacps_handle_error(void *arg, u8 Direction, u32 ErrorWord) { xemacpsif_s *xemacpsif; @@ -214,6 +218,8 @@ static void emacps_handle_error(void *arg, u8 Direction, u32 ErrorWord) } } +extern XEmacPs_Config mac_config; + void HandleTxErrors(xemacpsif_s *xemacpsif) { u32 netctrlreg; diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c index d1999a73e..12b8c60c8 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c @@ -53,23 +53,24 @@ #include #include +#include "Zynq/x_emacpsif.h" +//#include "lwipopts.h" +#include "xparameters_ps.h" +#include "xparameters.h" + /* FreeRTOS includes. */ #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "semphr.h" +///* FreeRTOS+TCP includes. */ /* FreeRTOS+TCP includes. */ #include "FreeRTOS_IP.h" #include "FreeRTOS_Sockets.h" #include "FreeRTOS_IP_Private.h" #include "NetworkBufferManagement.h" -#include "Zynq/x_emacpsif.h" -#include "xparameters_ps.h" -#include "xparameters.h" - - int phy_detected = 0; /*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c @@ -98,8 +99,6 @@ int phy_detected = 0; #define IEEE_CONTROL_REG_OFFSET 0 #define IEEE_STATUS_REG_OFFSET 1 -#define IEEE_PHYSID1_OFFSET 2 -#define IEEE_PHYSID2_OFFSET 3 #define IEEE_AUTONEGO_ADVERTISE_REG 4 #define IEEE_PARTNER_ABILITIES_1_REG_OFFSET 5 #define IEEE_1000_ADVERTISE_REG_OFFSET 9 @@ -136,6 +135,9 @@ int phy_detected = 0; #define IEEE_PAUSE_MASK 0x0400 #define IEEE_AUTONEG_ERROR_MASK 0x8000 +#define PHY_DETECT_REG 1 +#define PHY_DETECT_MASK 0x1808 + #define XEMACPS_GMII2RGMII_SPEED1000_FD 0x140 #define XEMACPS_GMII2RGMII_SPEED100_FD 0x2100 #define XEMACPS_GMII2RGMII_SPEED10_FD 0x100 @@ -161,17 +163,19 @@ int phy_detected = 0; static int detect_phy(XEmacPs *xemacpsp) { - u16 id_lower, id_upper; - u32 phy_addr, id; - - for (phy_addr = 0; phy_addr < 32; phy_addr++) { - XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PHYSID1_OFFSET, &id_lower); - - if ((id_lower != ( u16 )0xFFFFu) && (id_lower != ( u16 )0x0u)) { - - XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PHYSID2_OFFSET, &id_upper); - id = ( ( ( uint32_t ) id_upper ) << 16 ) | ( id_lower & 0xFFF0 ); - FreeRTOS_printf( ("XEmacPs detect_phy: %04lX at address %d.\n", id, phy_addr ) ); + u16 phy_reg; + u32 phy_addr; + + for (phy_addr = 31; phy_addr > 0; phy_addr--) { + XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_DETECT_REG, + &phy_reg); + + if ((phy_reg != 0xFFFF) && + ((phy_reg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { + /* Found a valid PHY address */ + FreeRTOS_printf( ("XEmacPs detect_phy: PHY detected at address %d.\r\n", + phy_addr)); + FreeRTOS_printf( ("XEmacPs detect_phy: PHY detected.\n" ) ); phy_detected = phy_addr; return phy_addr; } @@ -234,8 +238,8 @@ unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp) if (partner_capabilities & IEEE_AN1_ABILITY_MASK_10MBPS) return 10; - FreeRTOS_printf( ( "%s: unknown PHY link speed, setting TEMAC speed to be 10 Mbps\n", - __FUNCTION__ ) ); + xil_printf("%s: unknown PHY link speed, setting TEMAC speed to be 10 Mbps\r\n", + __FUNCTION__); return 10; } else { @@ -253,8 +257,8 @@ unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp) case (IEEE_CTRL_LINKSPEED_10M): return 10; default: - FreeRTOS_printf( ( "%s: unknown PHY link speed (%d), setting TEMAC speed to be 10 Mbps\n", - __FUNCTION__, phylinkspeed ) ); + xil_printf("%s: unknown PHY link speed (%d), setting TEMAC speed to be 10 Mbps\r\n", + __FUNCTION__, phylinkspeed); return 10; } @@ -278,7 +282,7 @@ unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp) #else u32 phy_addr = detect_phy(xemacpsp); #endif - FreeRTOS_printf( ( "Start PHY autonegotiation \n" ) ); + xil_printf("Start PHY autonegotiation \r\n"); #if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1 #else @@ -334,24 +338,24 @@ unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp) break; } #endif - FreeRTOS_printf( ( "Waiting for PHY to complete autonegotiation.\n" ) ); + xil_printf("Waiting for PHY to complete autonegotiation.\r\n"); XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status); while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) { - vTaskDelay(1); + sleep(1); #if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1 #else XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2, &temp); if (temp & IEEE_AUTONEG_ERROR_MASK) { - FreeRTOS_printf( ( "Auto negotiation error \n" ) ); + xil_printf("Auto negotiation error \r\n"); } #endif XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status); } - FreeRTOS_printf( ( "autonegotiation complete \n" ) ); + xil_printf("autonegotiation complete \r\n"); #if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1 #else @@ -359,7 +363,7 @@ unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp) #endif #if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1 - FreeRTOS_printf( ( "Waiting for Link to be up; Polling for SGMII core Reg \n" ) ); + xil_printf("Waiting for Link to be up; Polling for SGMII core Reg \r\n"); XEmacPs_PhyRead(xemacpsp, phy_addr, 5, &temp); while(!(temp & 0x8000)) { XEmacPs_PhyRead(xemacpsp, phy_addr, 5, &temp); @@ -376,7 +380,7 @@ unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp) XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp); return 10; } else { - FreeRTOS_printf( ( "get_IEEE_phy_speed(): Invalid speed bit value, Deafulting to Speed = 10 Mbps\n" ) ); + xil_printf("get_IEEE_phy_speed(): Invalid speed bit value, Deafulting to Speed = 10 Mbps\r\n"); XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp); XEmacPs_PhyWrite(xemacpsp, phy_addr, 0, 0x0100); return 10; @@ -556,26 +560,26 @@ unsigned Phy_Setup (XEmacPs *xemacpsp) link_speed = 1000; configure_IEEE_phy_speed(xemacpsp, link_speed); convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD; - vTaskDelay(1); + sleep(1); #elif defined(ipconfigNIC_LINKSPEED100) SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100); link_speed = 100; configure_IEEE_phy_speed(xemacpsp, link_speed); convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD; - vTaskDelay(1); + sleep(1); #elif defined(ipconfigNIC_LINKSPEED10) SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10); link_speed = 10; configure_IEEE_phy_speed(xemacpsp, link_speed); convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD; - vTaskDelay(1); + sleep(1); #endif if (conv_present) { XEmacPs_PhyWrite(xemacpsp, convphyaddr, XEMACPS_GMII2RGMII_REG_NUM, convspeeddupsetting); } - FreeRTOS_printf( ( "link speed: %d\n", link_speed ) ); + xil_printf("link speed: %d\r\n", link_speed); return link_speed; } diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/board_family/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/board_family/NetworkInterface.c new file mode 100644 index 000000000..aa0a646b4 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/board_family/NetworkInterface.c @@ -0,0 +1,63 @@ +/* +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" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.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 + +BaseType_t xNetworkInterfaceInitialise( void ) +{ + /* FIX ME. */ + return pdFALSE; +} + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t xReleaseAfterSend ) +{ + /* FIX ME. */ + return pdFALSE; +} + +void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) +{ + /* FIX ME. */ +} + +BaseType_t xGetPhyLinkStatus( void ) +{ + /* FIX ME. */ + return pdFALSE; +} \ No newline at end of file diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/board_family/ReadMe.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/board_family/ReadMe.txt new file mode 100644 index 000000000..441cdbd2a --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/board_family/ReadMe.txt @@ -0,0 +1 @@ +Update NetworkInterface.c and include other files needed by FreeRTOS+TCP here. \ No newline at end of file diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/esp32/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/esp32/NetworkInterface.c new file mode 100644 index 000000000..0b34edf7b --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/esp32/NetworkInterface.c @@ -0,0 +1,193 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* Standard includes. */ +#include +#include +#include + +/* 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 "FreeRTOS_DNS.h" +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" + +#include "esp_log.h" +#include "esp_wifi.h" +#include "esp_wifi_internal.h" +#include "tcpip_adapter.h" + +enum if_state_t { + INTERFACE_DOWN = 0, + INTERFACE_UP, +}; + +static const char *TAG = "NetInterface"; +volatile static uint32_t xInterfaceState = INTERFACE_DOWN; + +#if ( ipconfigHAS_PRINTF != 0 ) + static void prvMonitorResources(); +#endif + +BaseType_t xNetworkInterfaceInitialise( void ) +{ + static BaseType_t xMACAdrInitialized = pdFALSE; + uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ]; + + if (xInterfaceState == INTERFACE_UP) { + if (xMACAdrInitialized == pdFALSE) { + esp_wifi_get_mac(ESP_IF_WIFI_STA, ucMACAddress); + FreeRTOS_UpdateMACAddress(ucMACAddress); + xMACAdrInitialized = pdTRUE; + } + return pdTRUE; + } + return pdFALSE; +} + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t *const pxNetworkBuffer, BaseType_t xReleaseAfterSend ) +{ + if (pxNetworkBuffer == NULL || pxNetworkBuffer->pucEthernetBuffer == NULL || pxNetworkBuffer->xDataLength == 0) { + ESP_LOGE(TAG, "Invalid params"); + return pdFALSE; + } + + esp_err_t ret; + if (xInterfaceState == INTERFACE_DOWN) { + ESP_LOGD(TAG, "Interface down"); + ret = ESP_FAIL; + } else { + ret = esp_wifi_internal_tx(ESP_IF_WIFI_STA, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to tx buffer %p, len %d, err %d", pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength, ret); + } + } + +#if ( ipconfigHAS_PRINTF != 0 ) + prvMonitorResources(); +#endif + if (xReleaseAfterSend == pdTRUE) { + vReleaseNetworkBufferAndDescriptor(pxNetworkBuffer); + } + + return ret == ESP_OK ? pdTRUE : pdFALSE; +} + +void vNetworkNotifyIFDown() +{ + IPStackEvent_t xRxEvent = { eNetworkDownEvent, NULL }; + if (xInterfaceState != INTERFACE_DOWN) { + xInterfaceState = INTERFACE_DOWN; + xSendEventStructToIPTask( &xRxEvent, 0 ); + } +} + +void vNetworkNotifyIFUp() +{ + xInterfaceState = INTERFACE_UP; +} + +esp_err_t wlanif_input(void *netif, void *buffer, uint16_t len, void *eb) +{ + NetworkBufferDescriptor_t *pxNetworkBuffer; + IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; + const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 ); + +#if ( ipconfigHAS_PRINTF != 0 ) + prvMonitorResources(); +#endif + + if( eConsiderFrameForProcessing( buffer ) != eProcessBuffer ) { + ESP_LOGD(TAG, "Dropping packet"); + esp_wifi_internal_free_rx_buffer(eb); + return ESP_OK; + } + + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor(len, xDescriptorWaitTime); + if (pxNetworkBuffer != NULL) { + + /* Set the packet size, in case a larger buffer was returned. */ + pxNetworkBuffer->xDataLength = len; + + /* Copy the packet data. */ + memcpy(pxNetworkBuffer->pucEthernetBuffer, buffer, len); + xRxEvent.pvData = (void *) pxNetworkBuffer; + + if ( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime) == pdFAIL ) { + ESP_LOGE(TAG, "Failed to enqueue packet to network stack %p, len %d", buffer, len); + vReleaseNetworkBufferAndDescriptor(pxNetworkBuffer); + return ESP_FAIL; + } + esp_wifi_internal_free_rx_buffer(eb); + return ESP_OK; + } else { + ESP_LOGE(TAG, "Failed to get buffer descriptor"); + return ESP_FAIL; + } +} + +#if ( ipconfigHAS_PRINTF != 0 ) + static void prvMonitorResources() + { + static UBaseType_t uxLastMinBufferCount = 0u; + static UBaseType_t uxCurrentBufferCount = 0u; + static size_t uxMinLastSize = 0uL; + size_t uxMinSize; + + uxCurrentBufferCount = uxGetMinimumFreeNetworkBuffers(); + + if( uxLastMinBufferCount != uxCurrentBufferCount ) + { + /* The logging produced below may be helpful + * while tuning +TCP: see how many buffers are in use. */ + uxLastMinBufferCount = uxCurrentBufferCount; + FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n", + uxGetNumberOfFreeNetworkBuffers(), uxCurrentBufferCount ) ); + } + + uxMinSize = xPortGetMinimumEverFreeHeapSize(); + + if( uxMinLastSize != uxMinSize ) + { + uxMinLastSize = uxMinSize; + FreeRTOS_printf( ( "Heap: current %lu lowest %lu\n", xPortGetFreeHeapSize(), uxMinSize ) ); + } + + #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + { + static UBaseType_t uxLastMinQueueSpace = 0; + UBaseType_t uxCurrentCount = 0u; + + 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 */ + } +#endif /* ( ipconfigHAS_PRINTF != 0 ) */ +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/include/phyHandling.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/include/phyHandling.h index ba50ae834..9e8a11387 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/include/phyHandling.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/include/phyHandling.h @@ -1,28 +1,3 @@ -/* - * 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 - */ - /* * Handling of Ethernet PHY's * PHY's communicate with an EMAC either through @@ -47,11 +22,11 @@ extern "C" { #endif /* A generic user-provided function that reads from the PHY-port at 'xAddress'( 0-based ). A 16-bit value shall be stored in - '*pusValue'. xRegister is the register number ( 0 .. 31 ). In fact all PHY registers are 16-bit. + '*pulValue'. xRegister is the register number ( 0 .. 31 ). In fact all PHY registers are 16-bit. Return non-zero in case the action failed. */ typedef BaseType_t ( *xApplicationPhyReadHook_t )( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue ); -/* A generic user-provided function that writes 'usValue' to the +/* A generic user-provided function that writes 'ulValue' to the PHY-port at 'xAddress' ( 0-based ). xRegister is the register number ( 0 .. 31 ). Return non-zero in case the action failed. */ typedef BaseType_t ( *xApplicationPhyWriteHook_t )( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue ); @@ -118,10 +93,10 @@ void vPhyInitialise( EthernetPhy_t *pxPhyObject, xApplicationPhyReadHook_t fnPhy /* Discover all PHY's connected by polling 32 indexes ( zero-based ) */ BaseType_t xPhyDiscover( EthernetPhy_t *pxPhyObject ); -/* Send a reset commando to the connected PHY ports and send configuration. */ +/* Send a reset command to the connected PHY ports and send configuration. */ BaseType_t xPhyConfigure( EthernetPhy_t *pxPhyObject, const PhyProperties_t *pxPhyProperties ); -/* Give a commando to start auto negotiation on a set of PHY port's. */ +/* Give a command to start auto negotiation on a set of PHY port's. */ BaseType_t xPhyStartAutoNegotiation( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask ); /* Do not use auto negotiation but use predefined values from 'pxPhyObject->xPhyPreferences'. */ @@ -132,10 +107,9 @@ BaseType_t xPhyFixedValue( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask ); last call to this function. */ BaseType_t xPhyCheckLinkStatus( EthernetPhy_t *pxPhyObject, BaseType_t xHadReception ); -static __inline uint32_t xPhyGetMask( EthernetPhy_t *pxPhyObject ) -{ - return ( ( ( uint32_t ) 1u ) << pxPhyObject-> xPortCount ) - 1; -} +/* Get the bitmask of a given 'EthernetPhy_t'. */ +#define xPhyGetMask( pxPhyObject ) \ + ( ( ( ( uint32_t ) 1u ) << ( pxPhyObject )->xPortCount ) - 1u ) #ifdef __cplusplus } /* extern "C" */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/mw300_rd/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/mw300_rd/NetworkInterface.c new file mode 100644 index 000000000..87161fd39 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/mw300_rd/NetworkInterface.c @@ -0,0 +1,217 @@ +/* +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" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_DNS.h" +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" + +#include "wifi-decl.h" +#include "wmerrno.h" +#include "wifi.h" + +#include + +#define net_e(...) \ + wmlog_e("freertos_tcp", ##__VA_ARGS__) +#define net_w(...) \ + wmlog_w("freertos_tcp", ##__VA_ARGS__) +#define net_d(...) \ + wmlog("freertos_tcp", ##__VA_ARGS__) + +#if 0 //this is lwip structure. +#define MAX_INTERFACES_SUPPORTED 3 +static struct netif *netif_arr[MAX_INTERFACES_SUPPORTED]; +#endif + +/* 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 + +#define IP_ADDR_ANY ((ip_addr_t *)&ip_addr_any) +#define IP_ADDR_BROADCAST ((ip_addr_t *)&ip_addr_broadcast) + +/** 255.255.255.255 */ +#define IPADDR_NONE ((u32_t)0xffffffffUL) +/** 127.0.0.1 */ +#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL) +/** 0.0.0.0 */ +#define IPADDR_ANY ((u32_t)0x00000000UL) +/** 255.255.255.255 */ +#define IPADDR_BROADCAST ((u32_t)0xffffffffUL) + +/** 255.255.255.255 */ +#define INADDR_NONE IPADDR_NONE +/** 127.0.0.1 */ +#define INADDR_LOOPBACK IPADDR_LOOPBACK +/** 0.0.0.0 */ +#define INADDR_ANY IPADDR_ANY +/** 255.255.255.255 */ +#define INADDR_BROADCAST IPADDR_BROADCAST + +enum if_state_t { + INTERFACE_DOWN = 0, + INTERFACE_UP, +}; +struct ip_addr { + u32_t addr; +}; + +#define MLAN_BSS_TYPE_STA 0 + +extern uint8_t outbuf[2048]; +extern bool mlan_is_amsdu(const t_u8 *rcvdata); +extern t_u8 *mlan_get_payload(const t_u8 *rcvdata, t_u16 *payload_len, int *interface); +extern int wrapper_wlan_handle_amsdu_rx_packet(const t_u8 *rcvdata, const t_u16 datalen); +extern int wrapper_wlan_handle_rx_packet(const t_u16 datalen, const t_u8 *rcvdata, NetworkBufferDescriptor_t *pxNetworkBuffer); +static volatile uint32_t xInterfaceState = INTERFACE_DOWN; + +static int process_data_packet(const t_u8 *databuf, const t_u16 datalen) +{ + int interface = BSS_TYPE_STA; + t_u8 *payload = NULL; + t_u16 payload_len = 0; + const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 ); + + NetworkBufferDescriptor_t *pxNetworkBuffer; + IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; + + payload = (t_u8 *)mlan_get_payload(databuf, &payload_len, &interface); + + if( eConsiderFrameForProcessing( payload ) != eProcessBuffer ) { + net_d("Dropping packet\r\n"); + return WM_SUCCESS; + } + + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor(/*payload_len*/datalen, xDescriptorWaitTime); + + if (pxNetworkBuffer != NULL) { + /* Set the packet size, in case a larger buffer was returned. */ + pxNetworkBuffer->xDataLength = payload_len; + + /* Copy the packet data. */ + memcpy(pxNetworkBuffer->pucEthernetBuffer, payload, payload_len); + + xRxEvent.pvData = (void *) pxNetworkBuffer; + if ( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime) == pdFAIL ) { + wmprintf("Failed to enqueue packet to network stack %p, len %d", payload, payload_len); + vReleaseNetworkBufferAndDescriptor(pxNetworkBuffer); + return WM_FAIL; + } + } + return WM_SUCCESS; +} + +/* Callback function called from the wifi module */ +void handle_data_packet(const t_u8 interface, const t_u8 *rcvdata, + const t_u16 datalen) +{ + if (interface == BSS_TYPE_STA) + process_data_packet(rcvdata, datalen); +} + +BaseType_t xNetworkInterfaceInitialise( void ) +{ + uint8_t ret; + mac_addr_t mac_addr; + + ret = wifi_get_device_mac_addr(&mac_addr); + if (ret != WM_SUCCESS) { + net_d("Failed to get mac address"); + } + + FreeRTOS_UpdateMACAddress(mac_addr.mac); + + return ( xInterfaceState == INTERFACE_UP && ret == WM_SUCCESS ) ? pdTRUE : pdFALSE; +} + +void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) +{ + /* FIX ME. */ +} + +BaseType_t xGetPhyLinkStatus( void ) +{ + /* FIX ME. */ + return pdFALSE; +} +void vNetworkNotifyIFDown() +{ + IPStackEvent_t xRxEvent = { eNetworkDownEvent, NULL }; + xInterfaceState = INTERFACE_DOWN; + if( xSendEventStructToIPTask( &xRxEvent, 0 ) != pdPASS ) { + /* Could not send the message, so it is still pending. */ + net_e("Could not send network down event"); + } + else { + /* Message was sent so it is not pending. */ + net_d("Sent network down event"); + } +} + +void vNetworkNotifyIFUp() +{ + xInterfaceState = INTERFACE_UP; +} + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t *const pxNetworkBuffer, BaseType_t xReleaseAfterSend ) +{ + uint8_t pkt_len; + + if (pxNetworkBuffer == NULL || + pxNetworkBuffer->pucEthernetBuffer == NULL || + pxNetworkBuffer->xDataLength == 0) { + net_d("Incorrect params"); + return pdFALSE; + } + memset(outbuf, 0x00, sizeof(outbuf)); + pkt_len = 22 + 4; /* sizeof(TxPD) + INTF_HEADER_LEN */ + memcpy((u8_t *) outbuf + pkt_len, (u8_t *) pxNetworkBuffer->pucEthernetBuffer, + pxNetworkBuffer->xDataLength); + int ret = wifi_low_level_output(BSS_TYPE_STA, outbuf + pkt_len, pxNetworkBuffer->xDataLength); + if (ret != WM_SUCCESS) { + net_e("Failed output %p, length %d, error %d \r\n", pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength, ret); + } + + if (xReleaseAfterSend != pdFALSE) { + vReleaseNetworkBufferAndDescriptor(pxNetworkBuffer); + } + + return ret == WM_SUCCESS ? pdTRUE : pdFALSE; +} diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/BufferAllocation_2.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/BufferAllocation_2.c new file mode 100644 index 000000000..531e878ea --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/BufferAllocation_2.c @@ -0,0 +1,620 @@ +/* + * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd. + * Authors include Hein Tibosch and Richard Barry + * + ******************************************************************************* + ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE *** + *** *** + *** *** + *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP *** + *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs *** + *** download): *** + *** *** + *** FreeRTOS+TCP is functional and has been used in commercial products *** + *** for some time. Be aware however that we are still refining its *** + *** design, the source code does not yet quite conform to the strict *** + *** coding and style standards mandated by Real Time Engineers ltd., and *** + *** the documentation and testing is not necessarily complete. *** + *** *** + *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE *** + *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at *** + *** the sole discretion of Real Time Engineers Ltd., be offered versions *** + *** under a license other than that described below. *** + *** *** + *** *** + ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE *** + ******************************************************************************* + * + * FreeRTOS+TCP can be used under two different free open source licenses. The + * license that applies is dependent on the processor on which FreeRTOS+TCP is + * executed, as follows: + * + * If FreeRTOS+TCP is executed on one of the processors listed under the Special + * License Arrangements heading of the FreeRTOS+TCP license information web + * page, then it can be used under the terms of the FreeRTOS Open Source + * License. If FreeRTOS+TCP is used on any other processor, then it can be used + * under the terms of the GNU General Public License V2. Links to the relevant + * licenses follow: + * + * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license + * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license + * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt + * + * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot + * use FreeRTOS+TCP unless you agree that you use the software 'as is'. + * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied + * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they + * implied, expressed, or statutory. + * + * 1 tab == 4 spaces! + * + * http://www.FreeRTOS.org + * http://www.FreeRTOS.org/plus + * http://www.FreeRTOS.org/labs + * + */ + +/****************************************************************************** +* +* See the following web page for essential buffer allocation scheme usage and +* configuration details: +* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html +* +******************************************************************************/ + +/* 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 */ + +/*_RB_ This is too complex not to have an explanation. */ +#if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES ) + #define ASSERT_CONCAT_( a, b ) a ## b + #define ASSERT_CONCAT( a, b ) ASSERT_CONCAT_( a, b ) + #define STATIC_ASSERT( e ) \ + ; enum { ASSERT_CONCAT( assert_line_, __LINE__ ) = 1 / ( !!( e ) ) } + + STATIC_ASSERT( ipconfigETHERNET_MINIMUM_PACKET_BYTES <= baMINIMAL_BUFFER_SIZE ); +#endif + +/* 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; + + 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 */ + xRequestedSizeBytes += 2u; + + if( ( xRequestedSizeBytes & ( sizeof( size_t ) - 1u ) ) != 0u ) + { + xRequestedSizeBytes = ( xRequestedSizeBytes | ( sizeof( size_t ) - 1u ) ) + 1u; + } + #ifdef PIC32_USE_ETHERNET + } + #endif /* #ifdef PIC32_USE_ETHERNET */ + + /* If there is a semaphore available, there is a network buffer available. */ + if( 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( xRequestedSizeBytes + ipBUFFER_PADDING ); + #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; + + #ifdef PIC32_USE_ETHERNET + xOriginalLength = pxNetworkBuffer->xDataLength; + #else + xOriginalLength = pxNetworkBuffer->xDataLength + ipBUFFER_PADDING; + xNewSizeBytes = xNewSizeBytes + ipBUFFER_PADDING; + #endif /* #ifdef PIC32_USE_ETHERNET */ + + 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/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/NetworkInterface_eth.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/NetworkInterface_eth.c new file mode 100644 index 000000000..1b7584c44 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/NetworkInterface_eth.c @@ -0,0 +1,889 @@ +/******************************************************************************* +* Network Interface file +* +* Summary: +* Network Interface file for FreeRTOS-Plus-TCP stack +* +* Description: +* - Interfaces PIC32 to the FreeRTOS TCP/IP stack +*******************************************************************************/ + +/******************************************************************************* +* File Name: pic32_NetworkInterface.c +* Copyright 2017 Microchip Technology Incorporated and its subsidiaries. +* +* 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 +*******************************************************************************/ +#include + +#include "FreeRTOS.h" +#include "semphr.h" +#include "event_groups.h" +#include "FreeRTOS_IP.h" +#include "FreeRTOS_IP_Private.h" + +#include "NetworkInterface.h" +#include "NetworkBufferManagement.h" + + +#include "NetworkInterface.h" +#include "NetworkConfig.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( void ); + static void StartInitCleanup( void ); + + static void SetMacCtrl( TCPIP_MAC_MODULE_CTRL * pMacCtrl ); + + static bool MacSyncFunction( void * synchHandle, + TCPIP_MAC_SYNCH_REQUEST req ); + + /* the PIC32 MAC task function */ + static void MacHandlerTask( void * params ); + + /* MAC interrupt event function */ + static void MAC_EventFunction( TCPIP_MAC_EVENT event, + const void * eventParam ); + + /* timer callback for link maintenance, etc; */ + static void MacTmrCallback( TimerHandle_t xTimer ); + + /* MAC RX packets functions */ + static void MacRxPackets( void ); + static void MacProcessRxPacket( TCPIP_MAC_PACKET * pRxPkt ); + + + /* 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 */ + /* */ + /* use the configuration data from the system_init.c */ + extern const TCPIP_NETWORK_CONFIG TCPIP_HOSTS_CONFIGURATION[]; + + /* BufferAllocation_2.c:: packet allocation function */ + 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 ); + + /* cannot use the system_init.c::tcpipHeapConfig because FreeRTOS does not have a calloc function! */ + /* we build it here! */ + + /* make sure we're running with external heap! Redirect to FreeRTOS. */ + #if !defined( TCPIP_STACK_USE_EXTERNAL_HEAP ) || defined( TCPIP_STACK_USE_INTERNAL_HEAP ) || defined( TCPIP_STACK_USE_INTERNAL_HEAP_POOL ) + #error "TCPIP_STACK_USE_EXTERNAL_HEAP should be defined for this project!" + #endif + + 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) */ + + + /* FreeRTOS implementation functions */ + BaseType_t xNetworkInterfaceInitialise( void ) + { + BaseType_t xResult; + + if( xMacInitStatus == eMACInit ) + { + /* This is the first time this function is called. */ + if( StartInitMac() != false ) + { + /* Indicate that the MAC initialisation succeeded. */ + xMacInitStatus = eMACPass; + } + else + { + xMacInitStatus = eMACFailed; + } + } + + if( xMacInitStatus == eMACPass ) + { + xResult = xGetPhyLinkStatus(); + } + else + { + xResult = pdFAIL; + } + + PIC32_MAC_DbgPrint( "xNetworkInterfaceInitialise: %d %d\r\n", ( int ) xMacInitStatus, ( int ) xResult ); + + return xResult; + } + + + /*-----------------------------------------------------------*/ + + BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, + BaseType_t xReleaseAfterSend ) + { + 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 ); + + /* prepare the packet for transmission */ + /* set the correct data length: */ + configASSERT( pTxPkt->pDSeg->segSize >= pTxPkt->pDSeg->segLen ); + pTxPkt->pDSeg->segLen = pxDescriptor->xDataLength; + pTxPkt->next = 0; /* unlink it */ + macRes = ( macObject->TCPIP_MAC_PacketTx )( macCliHandle, pTxPkt ); + + if( macRes >= 0 ) + { + retRes = pdTRUE; + pxDescriptor->pucEthernetBuffer = 0; /* it will be released by the MAC driver once it's transmitted */ + iptraceNETWORK_INTERFACE_TRANSMIT(); + } + + /* else same error occurred; this normally should not happen! But the buffer is left in there so it shold be freed! */ + + /* The buffer has been sent so can be released. */ + if( xReleaseAfterSend != pdFALSE ) + { + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + } + } + + return retRes; + } + + + /************************************* Section: helper functions ************************************************** */ + /* */ + + 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 + } + + /************************************* Section: worker code ************************************************** */ + /* */ + + + static bool StartInitMac( void ) + { + TCPIP_MAC_MODULE_CTRL macCtrl; + SYS_MODULE_INIT moduleInit; + EventBits_t evBits; + + + /* perform some initialization of all variables so that we can cleanup what failed */ + /* if something failed, the routine will be called again and again by FreeRTOS! */ + macHeapHandle = 0; + macObjHandle = 0; + macCliHandle = 0; + macTmrHandle = 0; + macTaskHandle = 0; + macObject = TCPIP_HOSTS_CONFIGURATION[ 0 ].pMacObject; /* the MAC object we use */ + macObjStatus = SYS_STATUS_UNINITIALIZED; + macLinkStatus = false; + + int netUpFail = 0; + + while( true ) + { + /* start the allocator */ + 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; + + /* Initialize the MAC. MAC address is defined to 0x000000000000 in + * FreeRTOSConfig.h and therefore it will be initialized to the + * factory programmed MAC address. */ + SetMacCtrl( &macCtrl ); + /* Set the mac address in the FreeRTOS+TCP stack. */ + FreeRTOS_UpdateMACAddress( macCtrl.ifPhyAddress.v ); + + 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; + } + + /* open the MAC */ + 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; + } + + /* completed the MAC initialization */ + /* continue the initialization */ + macTmrHandle = xTimerCreate( PIC32_MAC_TIMER_NAME, PIC32_MAC_TIMER_PERIOD, pdTRUE, 0, MacTmrCallback ); + + if( ( macTmrHandle == 0 ) || ( xTimerStart( macTmrHandle, 0 ) != pdPASS ) ) + { + netUpFail = 8; + break; + } + + /* spawn the PIC32 MAC task function */ + /* and wait for its event signal */ + macObjStatus = SYS_STATUS_BUSY; + + if( xTaskCreate( MacHandlerTask, PIC32_MAC_TASK_NAME, PIC32_MAC_TASK_STACK_SIZE, xTaskGetCurrentTaskHandle(), PIC32_MAC_TASK_PRI, &macTaskHandle ) != pdPASS ) + { /* failed */ + 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 ) + { /* timed out */ + netUpFail = 10; + break; + } + + if( macObjStatus != SYS_STATUS_READY ) + { /* failed somehow ??? */ + netUpFail = 11; + break; + } + + netUpFail = 0; + break; + } + + if( netUpFail == 0 ) + { + PIC32_MAC_DbgPrint( " MAC Init success!\r\n" ); + + #if ( PIC32_MAC_DEBUG_COMMANDS != 0 ) + /* create command group */ + 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 }; /* not set MAC address */ + + 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 ) + { /* if unspecified we use the factory pre-programmed address */ + PIC32_GetMACAddress( pMacCtrl->ifPhyAddress.v ); + } + else + { /* use the config suggested one */ + 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; + + /* perform the MAC initialization */ + while( macObjStatus == SYS_STATUS_BUSY ) + { + /* process the underlying MAC module tasks */ + ( macObject->TCPIP_MAC_Tasks )( macObjHandle ); + + SYS_STATUS macStatus = ( macObject->TCPIP_MAC_Status )( macObjHandle ); + + if( macStatus == SYS_STATUS_BUSY ) + { /* still pending */ + vTaskDelay( PIC32_MAC_TASK_INIT_PENDING_DELAY ); + } + else + { /* completed ...somehow */ + macObjStatus = macStatus; + + xTaskNotify( ( TaskHandle_t ) params, PIC32_MAC_EVENT_INIT_DONE, eSetBits ); + + if( macStatus != SYS_STATUS_READY ) + { /* failed miserably */ + vTaskDelete( 0 ); + } + + /* done, up and running */ + } + } + + 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 ) + { /* timeout occurred... */ + ( macObject->TCPIP_MAC_Tasks )( macObjHandle ); + bool linkCurr = ( macObject->TCPIP_MAC_LinkCheck )( macCliHandle ); /* check link status */ + + if( macLinkStatus != linkCurr ) + { /* link status changed; some event could ve fired here if needed */ + PIC32_MAC_DbgPrint( " MAC link: %s!\r\n", linkCurr ? "ON" : "OFF" ); + macLinkStatus = linkCurr; + } + } + + if( ( evBits & PIC32_MAC_EVENT_IF_PENDING ) != 0 ) + { /* IF events signal */ + TCPIP_MAC_EVENT activeEvents = ( macObject->TCPIP_MAC_EventPendingGet )( macCliHandle ); + + if( activeEvents != TCPIP_MAC_EV_NONE ) + { + /* acknowledge the events */ + ( macObject->TCPIP_MAC_EventAcknowledge )( macCliHandle, activeEvents ); + + /* check for RX */ + if( ( activeEvents & ( TCPIP_MAC_EV_RX_DONE | TCPIP_MAC_EV_RX_OVFLOW | TCPIP_MAC_EV_RX_BUFNA ) ) != 0 ) + { /* RX packets available */ + MacRxPackets(); + } + + /* call the driver process function; */ + /* PIC32 driver requests it through TCPIP_MAC_ParametersGet() which is bypassed here! */ + ( macObject->TCPIP_MAC_Process )( macCliHandle ); + } + } + + /* do what you have to do and then wait for another event... */ + } + } + + /*-----------------------------------------------------------*/ + + static void MacTmrCallback( TimerHandle_t xTimer ) + { + xTaskNotify( macTaskHandle, PIC32_MAC_EVENT_TIMEOUT, eSetBits ); + } + + /* MAC interrupt event function */ + /* MAC signals an event, probably from within ISR */ + /* we care just for RX related events */ + 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 ); + } + } + } + + /*-----------------------------------------------------------*/ + + BaseType_t xGetPhyLinkStatus( void ) + { + return macLinkStatus == true ? pdPASS : pdFAIL; + } + + + /* receive packets from the MAC driver */ + static void MacRxPackets( void ) + { + TCPIP_MAC_PACKET * pRxPkt; + + /* get all the new MAC packets */ + 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; + + /* calculate the packet size */ + do + { + pktLength += pSeg->segLen; + pSeg = pSeg->next; + nSegs++; + } while( pSeg != 0 ); + + if( nSegs > 1 ) + { /* no support in FreeRTOS for multi segment packets! */ + break; + } + + /* sizeof(TCPIP_MAC_ETHERNET_HEADER) is subtracted by the driver */ + /* but FreeRTOS needs the whole frame! */ + pktLength += sizeof( TCPIP_MAC_ETHERNET_HEADER ); + + if( eConsiderFrameForProcessing( pPktBuff ) != eProcessBuffer ) + { + break; + } + + /* get the network descriptor (no data buffer) to hold this packet */ + pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( 0, 0 ); + + if( pxBufferDescriptor == 0 ) + { + pktLost = true; + break; + } + + PIC32_MacAssociate( pRxPkt, pxBufferDescriptor, pktLength ); + + xRxEvent.eEventType = eNetworkRxEvent; + xRxEvent.pvData = ( void * ) pxBufferDescriptor; + + /* Send the data to the TCP/IP stack */ + if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE ) + { /* failed */ + pktLost = true; + } + else + { /* success */ + pktSuccess = true; + iptraceNETWORK_INTERFACE_RECEIVE(); + } + + break; + } + + if( !pktSuccess ) + { /* smth went wrong; nothing sent to the */ + if( pxBufferDescriptor != 0 ) + { + pxBufferDescriptor->pucEthernetBuffer = 0; + vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor ); + } + + if( pktLost ) + { + iptraceETHERNET_RX_EVENT_LOST(); + } + + /* acknowledge the packet to the MAC driver */ + 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 */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/NetworkInterface_wifi.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/NetworkInterface_wifi.c new file mode 100644 index 000000000..a24cfe8ad --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/NetworkInterface_wifi.c @@ -0,0 +1,192 @@ +/******************************************************************************* +* Network Interface file +* +* Summary: +* Network Interface file for FreeRTOS-Plus-TCP stack +* +* Description: +* - Interfaces PIC32 to the FreeRTOS TCP/IP stack +*******************************************************************************/ + +/******************************************************************************* +* File Name: pic32_NetworkInterface.c +* Copyright 2017 Microchip Technology Incorporated and its subsidiaries. +* +* 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 +*******************************************************************************/ +#ifndef PIC32_USE_ETHERNET +#include + +#include "FreeRTOS.h" +#include "semphr.h" +#include "event_groups.h" +#include "FreeRTOS_IP.h" +#include "FreeRTOS_IP_Private.h" + +#include "NetworkInterface.h" +#include "NetworkBufferManagement.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 "m2m_types.h" + +#include "tcpip/tcpip.h" +#include "tcpip/src/tcpip_private.h" +#include "tcpip/src/link_list.h" +#include "wilc1000_task.h" + +#include "NetworkConfig.h" + + + #include "iot_wifi.h" + + /* local definitions and data */ + + + /* FreeRTOS implementation functions */ + BaseType_t xNetworkInterfaceInitialise( void ) + { + WIFINetworkParams_t xNetworkParams; + + xNetworkParams.pcSSID = clientcredentialWIFI_SSID; + xNetworkParams.ucSSIDLength = sizeof( clientcredentialWIFI_SSID ); + xNetworkParams.pcPassword = clientcredentialWIFI_PASSWORD; + xNetworkParams.ucPasswordLength = sizeof( clientcredentialWIFI_PASSWORD ); + xNetworkParams.xSecurity = clientcredentialWIFI_SECURITY; + xNetworkParams.cChannel = M2M_WIFI_CH_ALL; /* Scan all channels (255) */ + + /*Turn WiFi ON */ + if( WIFI_On() != eWiFiSuccess ) + { + return pdFAIL; + } + + /* Connect to the AP */ + if( WIFI_ConnectAP( &xNetworkParams ) != eWiFiSuccess ) + { + return pdFAIL; + } + + return pdPASS; + } + + + /*-----------------------------------------------------------*/ + + BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, + BaseType_t xReleaseAfterSend ) + { + BaseType_t retRes = pdFALSE; + + if( ( pxDescriptor != 0 ) && ( pxDescriptor->pucEthernetBuffer != 0 ) && ( pxDescriptor->xDataLength != 0 ) ) + { + /* There you go */ + if( WDRV_EXT_DataSend( pxDescriptor->xDataLength, pxDescriptor->pucEthernetBuffer ) == 0 ) + { + retRes = pdTRUE; + } + + /* The buffer has been sent so can be released. */ + if( xReleaseAfterSend != pdFALSE ) + { + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + } + } + + return retRes; + } + + + /************************************* Section: helper functions ************************************************** */ + /* */ + + + + /************************************* Section: worker code ************************************************** */ + /* */ + + void xNetworkFrameReceived( uint32_t len, + uint8_t const * const frame ) + { + bool pktSuccess, pktLost; + NetworkBufferDescriptor_t * pxNetworkBuffer = NULL; + IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; + + pktSuccess = pktLost = false; + + while( true ) + { + if( eConsiderFrameForProcessing( frame ) != eProcessBuffer ) + { + break; + } + + /* get the network descriptor (no data buffer) to hold this packet */ + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( len, 0 ); + + if( pxNetworkBuffer == NULL ) + { + pktLost = true; + break; + } + + /* Set the actual packet length, in case a larger buffer was + returned. */ + pxNetworkBuffer->xDataLength = len; + + /* Copy the packet. */ + memcpy( pxNetworkBuffer->pucEthernetBuffer, frame, len ); + + /* Send the data to the TCP/IP stack. */ + xRxEvent.pvData = ( void * ) pxNetworkBuffer; + + if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE ) + { /* failed */ + pktLost = true; + } + else + { /* success */ + pktSuccess = true; + iptraceNETWORK_INTERFACE_RECEIVE(); + } + + break; + } + + if( !pktSuccess ) + { /* smth went wrong; nothing sent to the */ + if( pxNetworkBuffer != NULL ) + { + pxNetworkBuffer->pucEthernetBuffer = 0; + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + + if( pktLost ) + { + iptraceETHERNET_RX_EVENT_LOST(); + } + } + } + +#endif /* #ifndef PIC32_USE_ETHERNET */