First commit

This commit is contained in:
Alexey Bazlaev 2023-01-20 18:21:51 +07:00
commit 7ee6dc7527
178 changed files with 89881 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
Listings
Objects

9
EventRecorderStub.scvd Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<component_viewer schemaVersion="0.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="Component_Viewer.xsd">
<component name="EventRecorderStub" version="1.0.0"/> <!--name and version of the component-->
<events>
</events>
</component_viewer>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,833 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_DNS.c
* @brief Implements the Domain Name System for the FreeRTOS+TCP network stack.
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_DNS_Globals.h"
#include "FreeRTOS_IP.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_DNS.h"
#include "FreeRTOS_DHCP.h"
#include "NetworkBufferManagement.h"
#include "NetworkInterface.h"
#include "FreeRTOS_DNS_Cache.h"
#include "FreeRTOS_DNS_Parser.h"
#include "FreeRTOS_DNS_Networking.h"
#include "FreeRTOS_DNS_Callback.h"
/* Exclude the entire file if DNS is not enabled. */
#if ( ipconfigUSE_DNS != 0 )
/*
* 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 uxIdentifier );
/*
* Check if hostname is already known. If not, call prvGetHostByName() to send a DNS request.
*/
#if ( ipconfigDNS_USE_CALLBACKS == 1 )
static uint32_t prvPrepareLookup( const char * pcHostName,
FOnDNSEvent pCallback,
void * pvSearchID,
TickType_t uxTimeout );
#else
static uint32_t prvPrepareLookup( const char * pcHostName );
#endif
/*
* 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 uxIdentifier,
TickType_t uxReadTimeOut_ticks );
#if ( ipconfigUSE_LLMNR == 1 )
/** @brief The MAC address used for LLMNR. */
const MACAddress_t xLLMNR_MacAdress = { { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfc } };
#endif /* ipconfigUSE_LLMNR == 1 */
/*-----------------------------------------------------------*/
/**
* @brief A DNS query consists of a header, as described in 'struct xDNSMessage'
* It is followed by 1 or more queries, each one consisting of a name and a tail,
* with two fields: type and class
*/
#include "pack_struct_start.h"
struct xDNSTail
{
uint16_t usType; /**< Type of DNS message. */
uint16_t usClass; /**< Class of DNS message. */
}
#include "pack_struct_end.h"
typedef struct xDNSTail DNSTail_t;
/*-----------------------------------------------------------*/
#if ( ipconfigDNS_USE_CALLBACKS == 1 )
/**
* @brief Define FreeRTOS_gethostbyname() as a normal blocking call.
* @param[in] pcHostName: The hostname whose IP address is being searched for.
* @return The IP-address of the hostname.
*/
uint32_t FreeRTOS_gethostbyname( const char * pcHostName )
{
return FreeRTOS_gethostbyname_a( pcHostName, NULL, ( void * ) NULL, 0U );
}
/*-----------------------------------------------------------*/
/** @brief Initialise the list of call-back structures.
*/
void vDNSInitialise( void )
{
vDNSCallbackInitialise();
}
/*-----------------------------------------------------------*/
/**
* @brief Remove the entry defined by the search ID to cancel a DNS request.
* @param[in] pvSearchID: The search ID of the callback function associated with
* the DNS request being cancelled. Note that the value of
* the pointer matters, not the pointee.
*/
void FreeRTOS_gethostbyname_cancel( void * pvSearchID )
{
/* _HT_ Should better become a new API call to have the IP-task remove the callback */
vDNSCheckCallBack( pvSearchID );
}
/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
#endif /* ipconfigDNS_USE_CALLBACKS == 1 */
/*-----------------------------------------------------------*/
#if ( ipconfigDNS_USE_CALLBACKS == 0 )
/**
* @brief Get the IP-address corresponding to the given hostname.
* @param[in] pcHostName: The hostname whose IP address is being queried.
* @return The IP-address corresponding to the hostname. 0 is returned in
* case of failure.
*/
uint32_t FreeRTOS_gethostbyname( const char * pcHostName )
{
return prvPrepareLookup( pcHostName );
}
#else
/**
* @brief Get the IP-address corresponding to the given hostname.
* @param[in] pcHostName: The hostname whose IP address is being queried.
* @param[in] pCallback: The callback function which will be called upon DNS response.
* @param[in] pvSearchID: Search ID for the callback function.
* @param[in] uxTimeout: Timeout for the callback function.
* @return The IP-address corresponding to the hostname. 0 is returned in case of
* failure.
*/
uint32_t FreeRTOS_gethostbyname_a( const char * pcHostName,
FOnDNSEvent pCallback,
void * pvSearchID,
TickType_t uxTimeout )
{
return prvPrepareLookup( pcHostName, pCallback, pvSearchID, uxTimeout );
}
#endif /* if ( ipconfigDNS_USE_CALLBACKS == 0 ) */
#if ( ipconfigDNS_USE_CALLBACKS == 1 )
/**
* @brief Check if hostname is already known. If not, call prvGetHostByName() to send a DNS request.
*
* @param[in] pcHostName: The hostname whose IP address is being queried.
* @param[in] pCallback: The callback function which will be called upon DNS response.
* @param[in] pvSearchID: Search ID for the callback function.
* @param[in] uxTimeout: Timeout for the callback function.
* @return The IP-address corresponding to the hostname.
*/
static uint32_t prvPrepareLookup( const char * pcHostName,
FOnDNSEvent pCallback,
void * pvSearchID,
TickType_t uxTimeout )
#else
/**
* @brief Check if hostname is already known. If not, call prvGetHostByName() to send a DNS request.
* @param[in] pcHostName: The hostname whose IP address is being queried.
* @return The IP-address corresponding to the hostname.
*/
static uint32_t prvPrepareLookup( const char * pcHostName )
#endif
{
uint32_t ulIPAddress = 0U;
TickType_t uxReadTimeOut_ticks = ipconfigDNS_RECEIVE_BLOCK_TIME_TICKS;
/* Generate a unique identifier for this query. Keep it in a local variable
* as gethostbyname() may be called from different threads */
BaseType_t xHasRandom = pdFALSE;
TickType_t uxIdentifier = 0U;
BaseType_t xLengthOk = pdFALSE;
if( pcHostName != NULL )
{
size_t xLength = strlen( pcHostName ) + 1U;
#if ( ipconfigUSE_DNS_CACHE != 0 )
if( xLength <= ipconfigDNS_CACHE_NAME_LENGTH )
#else
if( xLength <= dnsMAX_HOSTNAME_LENGTH )
#endif
{
/* The name is not too long. */
xLengthOk = pdTRUE;
}
else
{
FreeRTOS_printf( ( "prvPrepareLookup: name is too long ( %lu > %lu )\n",
( uint32_t ) xLength,
( uint32_t ) ipconfigDNS_CACHE_NAME_LENGTH ) );
}
}
if( ( pcHostName != NULL ) && ( xLengthOk != pdFALSE ) )
{
/* 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 ( ipconfigUSE_DNS_CACHE == 1 )
/* Check the cache before issuing another DNS request. */
if( ulIPAddress == 0U )
{
ulIPAddress = FreeRTOS_dnslookup( pcHostName );
if( ulIPAddress != 0U )
{
FreeRTOS_debug_printf( ( "FreeRTOS_gethostbyname: found '%s' in cache: %lxip\n", pcHostName, ulIPAddress ) );
}
else
{
/* prvGetHostByName will be called to start a DNS lookup. */
}
}
#endif /* if ( ipconfigUSE_DNS_CACHE == 1 ) */
/* Generate a unique identifier. */
if( ulIPAddress == 0U )
{
uint32_t ulNumber;
xHasRandom = xApplicationGetRandomNumber( &( ulNumber ) );
/* DNS identifiers are 16-bit. */
uxIdentifier = ( TickType_t ) ( ulNumber & 0xffffU );
}
#if ( ipconfigDNS_USE_CALLBACKS == 1 )
{
if( pCallback != NULL )
{
if( ulIPAddress == 0U )
{
/* 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 );
}
}
}
#endif /* if ( ipconfigDNS_USE_CALLBACKS == 1 ) */
if( ( ulIPAddress == 0U ) && ( xHasRandom != pdFALSE ) )
{
ulIPAddress = prvGetHostByName( pcHostName,
uxIdentifier,
uxReadTimeOut_ticks );
}
}
return ulIPAddress;
}
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_LLMNR == 1 )
/*!
* @brief If LLMNR is being used then determine if the host name includes a '.'
* if not then LLMNR can be used as the lookup method.
* @param [in] pcHostName hostname to check
* @returns true if the hostname is a dotted format, else false
*
*/
static BaseType_t llmnr_has_dot( const char * pcHostName )
{
BaseType_t bHasDot = pdFALSE;
const char * pucPtr;
for( pucPtr = pcHostName; *pucPtr != ( char ) 0; pucPtr++ )
{
if( *pucPtr == '.' )
{
bHasDot = pdTRUE;
break;
}
}
return bHasDot;
}
#endif /* if ( ipconfigUSE_LLMNR == 1 ) */
/*!
* @brief create a payload buffer and return it through the parameter
* @param [out] ppxNetworkBuffer network buffer to create
* @param [in] pcHostName hostname to get its length
* @returns pointer address to the payload buffer
*
*/
static uint8_t * prvGetPayloadBuffer( NetworkBufferDescriptor_t ** ppxNetworkBuffer,
const char * pcHostName )
{
size_t uxExpectedPayloadLength;
uint8_t * pucUDPPayloadBuffer = NULL;
size_t uxHeaderBytes;
uxHeaderBytes = ipSIZE_OF_ETH_HEADER +
ipSIZE_OF_IPv4_HEADER +
ipSIZE_OF_UDP_HEADER;
uxExpectedPayloadLength = sizeof( DNSMessage_t ) +
strlen( pcHostName ) +
sizeof( uint16_t ) +
sizeof( uint16_t ) + 2U;
/* 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. */
*ppxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxExpectedPayloadLength +
uxHeaderBytes,
0U );
if( *ppxNetworkBuffer != NULL )
{
pucUDPPayloadBuffer = &( ( *ppxNetworkBuffer )->pucEthernetBuffer[ uxHeaderBytes ] );
}
return pucUDPPayloadBuffer;
}
/*!
* @brief fill pxAddress from pucUDPPayloadBuffer
* @param [out] pxAddress ip address and port ... structure
* @param [in] pcHostName hostname to get its length
*/
static void prvFillSockAddress( struct freertos_sockaddr * pxAddress,
const char * pcHostName )
{
uint32_t ulIPAddress = 0U;
#if ( ipconfigUSE_LLMNR != 1 )
( void ) pcHostName;
#endif
/* Obtain the DNS server address. */
FreeRTOS_GetAddressConfiguration( NULL, NULL, NULL, &ulIPAddress );
#if ( ipconfigUSE_LLMNR == 1 )
BaseType_t bHasDot = llmnr_has_dot( pcHostName );
if( bHasDot == pdFALSE )
{
/* Use LLMNR addressing. */
pxAddress->sin_addr = ipLLMNR_IP_ADDR; /* Is in network byte order. */
pxAddress->sin_port = ipLLMNR_PORT;
pxAddress->sin_port = FreeRTOS_ntohs( pxAddress->sin_port );
}
else
#endif /* if ( ipconfigUSE_LLMNR == 1 ) */
{
/* Use DNS server. */
pxAddress->sin_addr = ulIPAddress;
pxAddress->sin_port = dnsDNS_PORT;
}
}
/*!
* @brief return ip address from the dns reply message
* @param [in] pxReceiveBuffer received buffer from the DNS server
* @param [in] uxIdentifier matches sent and received packets
* @returns ip address or zero on error
*
*/
static uint32_t prvDNSReply( const struct xDNSBuffer * pxReceiveBuffer,
TickType_t uxIdentifier )
{
uint32_t ulIPAddress = 0U;
BaseType_t xExpected;
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
const DNSMessage_t * pxDNSMessageHeader =
( ( const DNSMessage_t * )
pxReceiveBuffer->pucPayloadBuffer );
/* See if the identifiers match. */
if( uxIdentifier == ( TickType_t ) pxDNSMessageHeader->usIdentifier )
{
xExpected = pdTRUE;
}
else
{
xExpected = pdFALSE;
}
/* The reply was received. Process it. */
#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 = DNS_ParseDNSReply( pxReceiveBuffer->pucPayloadBuffer,
pxReceiveBuffer->uxPayloadLength,
xExpected );
}
return ulIPAddress;
}
/*!
* @brief prepare the buffer before sending
* @param [in] pcHostName
* @param [in] uxIdentifier matches sent and received packets
* @param [in] xDNSSocket a valid socket
* @param [in] pxAddress address structure
* @returns pdTRUE if sending the data was successful, pdFALSE otherwise.
*/
static BaseType_t prvSendBuffer( const char * pcHostName,
TickType_t uxIdentifier,
Socket_t xDNSSocket,
const struct freertos_sockaddr * pxAddress )
{
BaseType_t uxReturn = pdFAIL;
struct xDNSBuffer xDNSBuf = { 0 };
NetworkBufferDescriptor_t * pxNetworkBuffer = NULL;
/*get dns message buffer */
xDNSBuf.pucPayloadBuffer = prvGetPayloadBuffer( &pxNetworkBuffer,
pcHostName );
if( xDNSBuf.pucPayloadBuffer != NULL )
{
xDNSBuf.uxPayloadSize = pxNetworkBuffer->xDataLength;
#if ( ipconfigUSE_LLMNR == 1 )
{
if( FreeRTOS_ntohs( pxAddress->sin_port ) == ipLLMNR_PORT )
{
( ( ( DNSMessage_t * ) xDNSBuf.pucPayloadBuffer ) )->usFlags = 0;
}
}
#endif
xDNSBuf.uxPayloadLength = prvCreateDNSMessage( xDNSBuf.pucPayloadBuffer,
pcHostName,
uxIdentifier );
/* send the dns message */
uxReturn = DNS_SendRequest( xDNSSocket,
pxAddress,
&xDNSBuf );
if( uxReturn == pdFAIL )
{
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
}
}
return uxReturn;
}
/*!
* @brief main dns operation description function
* @param [in] pcHostName hostname to get its ip address
* @param [in] uxIdentifier Identifier to match sent and received packets
* @param [in] xDNSSocket socket
* @returns ip address or zero on error
*/
static uint32_t prvGetHostByNameOp( const char * pcHostName,
TickType_t uxIdentifier,
Socket_t xDNSSocket )
{
uint32_t ulIPAddress = 0;
struct freertos_sockaddr xAddress;
DNSBuffer_t xReceiveBuffer = { 0 };
BaseType_t uxReturn = pdFAIL;
prvFillSockAddress( &xAddress, pcHostName );
do
{
uxReturn = prvSendBuffer( pcHostName,
uxIdentifier,
xDNSSocket,
&xAddress );
if( uxReturn == pdFAIL )
{
break;
}
/* Create the message in the obtained buffer. */
/* receive a dns reply message */
DNS_ReadReply( xDNSSocket,
&xAddress,
&xReceiveBuffer );
if( xReceiveBuffer.pucPayloadBuffer == NULL )
{
break;
}
ulIPAddress = prvDNSReply( &xReceiveBuffer, uxIdentifier );
/* Finished with the buffer. The zero copy interface
* is being used, so the buffer must be freed by the
* task. */
FreeRTOS_ReleaseUDPPayloadBuffer( xReceiveBuffer.pucPayloadBuffer );
} while( ipFALSE_BOOL );
return ulIPAddress;
}
/*!
* @brief helper function to prvGetHostByNameOP with multiple retries equal to
* ipconfigDNS_REQUEST_ATTEMPTS
*
* @param [in] pcHostName hostname to get its ip address
* @param [in] uxIdentifier Identifier to match sent and received packets
* @param [in] xDNSSocket socket
* @returns ip address or zero on error
*
*/
static uint32_t prvGetHostByNameOp_WithRetry( const char * pcHostName,
TickType_t uxIdentifier,
Socket_t xDNSSocket )
{
uint32_t ulIPAddress;
BaseType_t xAttempt;
for( xAttempt = 0; xAttempt < ipconfigDNS_REQUEST_ATTEMPTS; xAttempt++ )
{
ulIPAddress = prvGetHostByNameOp( pcHostName,
uxIdentifier,
xDNSSocket );
if( ulIPAddress != 0U )
{ /* ip found, no need to retry */
break;
}
}
return ulIPAddress;
}
/**
* @brief 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.
*
* @param[in] pcHostName The hostname for which an IP address is required.
* @param[in] uxIdentifier Identifier to match sent and received packets
* @param[in] uxReadTimeOut_ticks The timeout in ticks for waiting. In case the user has supplied
* a call-back function, this value should be zero.
* @return The IPv4 IP address for the hostname being queried. It will be zero if there is no reply.
*/
static uint32_t prvGetHostByName( const char * pcHostName,
TickType_t uxIdentifier,
TickType_t uxReadTimeOut_ticks )
{
Socket_t xDNSSocket;
uint32_t ulIPAddress = 0U;
xDNSSocket = DNS_CreateSocket( uxReadTimeOut_ticks );
if( xDNSSocket != NULL )
{
if( uxReadTimeOut_ticks == 0U )
{
ulIPAddress = prvGetHostByNameOp( pcHostName,
uxIdentifier,
xDNSSocket );
}
else
{
ulIPAddress = prvGetHostByNameOp_WithRetry( pcHostName,
uxIdentifier,
xDNSSocket );
}
/* Finished with the socket. */
DNS_CloseSocket( xDNSSocket );
}
return ulIPAddress;
}
/*-----------------------------------------------------------*/
/**
* @brief Create the DNS message in the zero copy buffer passed in the first parameter.
* @param[in,out] pucUDPPayloadBuffer The zero copy buffer where the DNS message will be created.
* @param[in] pcHostName Hostname to be looked up.
* @param[in] uxIdentifier Identifier to match sent and received packets
* @return Total size of the generated message, which is the space from the last written byte
* to the beginning of the buffer.
*/
_static size_t prvCreateDNSMessage( uint8_t * pucUDPPayloadBuffer,
const char * pcHostName,
TickType_t uxIdentifier )
{
DNSMessage_t * pxDNSMessageHeader;
size_t uxStart, uxIndex;
DNSTail_t const * 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. */
};
/* memcpy() helper variables for MISRA Rule 21.15 compliance*/
const void * pvCopySource;
void * pvCopyDest;
/* Copy in the const part of the header. Intentionally using different
* pointers with memcpy() to put the information in to correct place. */
/*
* Use helper variables for memcpy() to remain
* compliant with MISRA Rule 21.15. These should be
* optimized away.
*/
pvCopySource = &xDefaultPartDNSHeader;
pvCopyDest = pucUDPPayloadBuffer;
( void ) memcpy( pvCopyDest, pvCopySource, sizeof( xDefaultPartDNSHeader ) );
/* Write in a unique identifier. Cast the Payload Buffer to DNSMessage_t
* to easily access fields of the DNS Message. */
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
pxDNSMessageHeader = ( ( DNSMessage_t * ) pucUDPPayloadBuffer );
pxDNSMessageHeader->usIdentifier = ( uint16_t ) uxIdentifier;
/* Create the resource record at the end of the header. First
* find the end of the header. */
uxStart = sizeof( xDefaultPartDNSHeader );
/* Leave a gap for the first length byte. */
uxIndex = uxStart + 1U;
/* Copy in the host name. */
( void ) strcpy( ( char * ) &( pucUDPPayloadBuffer[ uxIndex ] ), pcHostName );
/* Walk through the string to replace the '.' characters with byte
* counts. pucStart holds the address of the byte count. Walking the
* string starts after the byte count position. */
uxIndex = uxStart;
do
{
size_t uxLength;
/* Skip the length byte. */
uxIndex++;
while( ( pucUDPPayloadBuffer[ uxIndex ] != ( uint8_t ) 0U ) &&
( pucUDPPayloadBuffer[ uxIndex ] != ( uint8_t ) ASCII_BASELINE_DOT ) )
{
uxIndex++;
}
/* Fill in the byte count, then move the pucStart pointer up to
* the found byte position. */
uxLength = uxIndex - ( uxStart + 1U );
pucUDPPayloadBuffer[ uxStart ] = ( uint8_t ) uxLength;
uxStart = uxIndex;
} while( pucUDPPayloadBuffer[ uxIndex ] != ( uint8_t ) 0U );
/* Finish off the record. Cast the record onto DNSTail_t structure to easily
* access the fields of the DNS Message. */
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
pxTail = ( ( DNSTail_t * ) &( pucUDPPayloadBuffer[ uxStart + 1U ] ) );
#if defined( _lint ) || defined( __COVERITY__ )
( void ) pxTail;
#else
vSetField16( pxTail, DNSTail_t, usType, dnsTYPE_A_HOST );
vSetField16( pxTail, DNSTail_t, usClass, dnsCLASS_IN );
#endif
/* Return the total size of the generated message, which is the space from
* the last written byte to the beginning of the buffer. */
return uxIndex + sizeof( DNSTail_t ) + 1U;
}
/*-----------------------------------------------------------*/
/* The function below will only be called :
* when ipconfigDNS_USE_CALLBACKS == 1
* when ipconfigUSE_LLMNR == 1
* for testing purposes, by the module test_freertos_tcp.c
*/
/**
* @brief Perform some preliminary checks and then parse the DNS packet.
*
* @param[in] pxNetworkBuffer: The network buffer to be parsed.
*
* @return pdFAIL Always to indicate that the packet was not consumed and must
* be released by the caller.
*/
uint32_t ulDNSHandlePacket( const NetworkBufferDescriptor_t * pxNetworkBuffer )
{
uint8_t * pucPayLoadBuffer;
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 ) )
{
pucPayLoadBuffer = &( pxNetworkBuffer->pucEthernetBuffer[ sizeof( UDPPacket_t ) ] );
/* The parameter pdFALSE indicates that the reply was not expected. */
( void ) DNS_ParseDNSReply( pucPayLoadBuffer,
uxPayloadSize,
pdFALSE );
}
}
/* The packet was not consumed. */
return pdFAIL;
}
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_NBNS == 1 )
/**
* @brief Handle an NBNS packet.
*
* @param[in] pxNetworkBuffer: The network buffer holding the NBNS packet.
*
* @return pdFAIL to show that the packet was not consumed.
*/
uint32_t ulNBNSHandlePacket( NetworkBufferDescriptor_t * pxNetworkBuffer )
{
UDPPacket_t * pxUDPPacket = ( ( UDPPacket_t * )
pxNetworkBuffer->pucEthernetBuffer );
uint8_t * pucUDPPayloadBuffer = &( pxNetworkBuffer->pucEthernetBuffer[ sizeof( *pxUDPPacket ) ] );
size_t uxBytesNeeded = sizeof( UDPPacket_t ) + sizeof( NBNSRequest_t );
/* Check for minimum buffer size. */
if( pxNetworkBuffer->xDataLength >= uxBytesNeeded )
{
DNS_TreatNBNS( pucUDPPayloadBuffer,
pxNetworkBuffer->xDataLength,
pxUDPPacket->xIPHeader.ulSourceIPAddress );
}
/* The packet was not consumed. */
return pdFAIL;
}
#endif /* ipconfigUSE_NBNS */
/*-----------------------------------------------------------*/
#endif /* ipconfigUSE_DNS != 0 */
/*-----------------------------------------------------------*/
/* Provide access to private members for testing. */
#ifdef FREERTOS_ENABLE_UNIT_TESTS
#include "freertos_tcp_test_access_dns_define.h"
#endif

View File

@ -0,0 +1,371 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_DNS_Cache.c
* @brief File that handles the DNS caching option
*/
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_DHCP.h"
#include "NetworkBufferManagement.h"
#include "NetworkInterface.h"
#include "FreeRTOS_DNS_Cache.h"
#include "FreeRTOS_DNS_Globals.h"
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#if ( ( ipconfigUSE_DNS != 0 ) && ( ipconfigUSE_DNS_CACHE == 1 ) )
/**
* @brief cache entry format structure
*/
typedef struct xDNS_CACHE_TABLE_ROW
{
uint32_t ulIPAddresses[ ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY ]; /*!< The IP address(es) 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; /*!< time at which the entry was added */
#if ( ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY > 1 )
uint8_t ucNumIPAddresses; /*!< number of ip addresses for the same entry */
uint8_t ucCurrentIPAddress; /*!< current ip address index */
#endif
} DNSCacheRow_t;
/*!
* @brief DNS cache structure instantiation
*/
static DNSCacheRow_t xDNSCache[ ipconfigDNS_CACHE_ENTRIES ] = { 0x0 };
/*!
* @brief indicates the index of a free entry in the cache structure
* \a DNSCacheRow_t
*/
static UBaseType_t uxFreeEntry = 0U;
static BaseType_t prvFindEntryIndex( const char * pcName,
UBaseType_t * uxResult );
static BaseType_t prvGetCacheIPEntry( UBaseType_t uxIndex,
uint32_t * pulIP,
uint32_t ulCurrentTimeSeconds );
static void prvUpdateCacheEntry( UBaseType_t uxIndex,
uint32_t ulTTL,
const uint32_t * pulIP,
uint32_t ulCurrentTimeSeconds );
static void prvInsertCacheEntry( const char * pcName,
uint32_t ulTTL,
const uint32_t * pulIP,
uint32_t ulCurrentTimeSeconds );
/**
* @brief perform a dns lookup in the local cache
* @param pcHostName the lookup name
* @return ulIPAddress with the value from the cache else returns a zero if the
* cache is not enabled or the lookup is not successful
* @post the global structure \a xDNSCache might be modified
*/
uint32_t FreeRTOS_dnslookup( const char * pcHostName )
{
uint32_t ulIPAddress = 0U;
( void ) FreeRTOS_ProcessDNSCache( pcHostName,
&ulIPAddress,
0,
pdTRUE );
return ulIPAddress;
}
/**
* @brief perform a dns update in the local cache
* @param pcName the lookup name
* @param pulIP the ip value to insert/replace
* @param ulTTL Time To live (in seconds)
* @return this is a dummy return, we are actually ignoring the return value
* from this function
* @post the global structure \a xDNSCache might be modified
*/
BaseType_t FreeRTOS_dns_update( const char * pcName,
uint32_t * pulIP,
uint32_t ulTTL )
{
( void ) FreeRTOS_ProcessDNSCache( pcName,
pulIP,
ulTTL,
pdFALSE );
return pdTRUE;
}
/**
* @brief perform a dns clear in the local cache
* @post the global structure \a xDNSCache is modified
*/
void FreeRTOS_dnsclear( void )
{
( void ) memset( xDNSCache, 0x0, sizeof( xDNSCache ) );
uxFreeEntry = 0U;
}
/**
* @brief process a DNS Cache request (get, update, or insert)
*
* @param[in] pcName: the name of the host
* @param[in,out] pulIP: when doing a lookup, will be set, when doing an update,
* will be read.
* @param[in] ulTTL: Time To Live (in seconds)
* @param[in] xLookUp: pdTRUE if a look-up is expected, pdFALSE, when the DNS cache must
* be updated.
* @return whether the operation was successful
* @post the global structure \a xDNSCache might be modified
*/
BaseType_t FreeRTOS_ProcessDNSCache( const char * pcName,
uint32_t * pulIP,
uint32_t ulTTL,
BaseType_t xLookUp )
{
UBaseType_t uxIndex;
BaseType_t xResult;
TickType_t xCurrentTickCount = xTaskGetTickCount();
uint32_t ulCurrentTimeSeconds;
configASSERT( ( pcName != NULL ) );
ulCurrentTimeSeconds = ( xCurrentTickCount / portTICK_PERIOD_MS ) / 1000U;
xResult = prvFindEntryIndex( pcName, &uxIndex );
if( xResult == pdTRUE )
{ /* Element found */
if( xLookUp == pdTRUE )
{
/* This statement can only be reached when xResult is true; which
* implies that the entry is present and a 'get' operation will result
* in success. Therefore, it is safe to ignore the return value of the
* below function. */
( void ) prvGetCacheIPEntry( uxIndex,
pulIP,
ulCurrentTimeSeconds );
}
else
{
prvUpdateCacheEntry( uxIndex,
ulTTL,
pulIP,
ulCurrentTimeSeconds );
}
}
else /* Element not Found xResult = pdFALSE */
{
if( xLookUp == pdTRUE )
{
*pulIP = 0U;
}
else
{
prvInsertCacheEntry( pcName,
ulTTL,
pulIP,
ulCurrentTimeSeconds );
}
}
if( ( xLookUp == pdFALSE ) || ( *pulIP != 0U ) )
{
FreeRTOS_debug_printf( ( "FreeRTOS_ProcessDNSCache: %s: '%s' @ %xip (TTL %u)\n",
( xLookUp != 0 ) ? "look-up" : "add",
pcName,
( unsigned ) FreeRTOS_ntohl( *pulIP ),
( unsigned ) FreeRTOS_ntohl( ulTTL ) ) );
}
return xResult;
}
/**
* @brief returns the index of the hostname entry in the dns cache.
* @param[in] pcName find it in the cache
* @param [out] xResult index number
* @returns res pdTRUE if index in found else pdFALSE
*/
static BaseType_t prvFindEntryIndex( const char * pcName,
UBaseType_t * uxResult )
{
BaseType_t xReturn = pdFALSE;
UBaseType_t uxIndex;
/* For each entry in the DNS cache table. */
for( uxIndex = 0; uxIndex < ipconfigDNS_CACHE_ENTRIES; uxIndex++ )
{
if( xDNSCache[ uxIndex ].pcName[ 0 ] == ( char ) 0 )
{ /* empty slot */
continue;
}
if( strcmp( xDNSCache[ uxIndex ].pcName, pcName ) == 0 )
{ /* hostname found */
xReturn = pdTRUE;
*uxResult = uxIndex;
break;
}
}
return xReturn;
}
/**
* @brief get entry at \p index from the cache
* @param[in] uxIndex : index in the cache
* @param[out] pulIP fill it with the result
* @param[in] ulCurrentTimeSeconds current time
* @returns \c pdTRUE if the value is valid \c pdFALSE otherwise
* @post the global structure \a xDNSCache might be modified
*
*/
static BaseType_t prvGetCacheIPEntry( UBaseType_t uxIndex,
uint32_t * pulIP,
uint32_t ulCurrentTimeSeconds )
{
BaseType_t isRead;
uint32_t ulIPAddressIndex = 0;
uint32_t ulAge = ulCurrentTimeSeconds - xDNSCache[ uxIndex ].ulTimeWhenAddedInSeconds;
/* Confirm that the record is still fresh.
* The field ulTTL was stored as network-endian. */
if( ulAge < FreeRTOS_ntohl( xDNSCache[ uxIndex ].ulTTL ) )
{
#if ( ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY > 1 )
uint8_t ucIndex;
/* The ucCurrentIPAddress value increments without bound and will rollover, */
/* modulo it by the number of IP addresses to keep it in range. */
/* Also perform a final modulo by the max number of IP addresses */
/* per DNS cache entry to prevent out-of-bounds access in the event */
/* that ucNumIPAddresses has been corrupted. */
ucIndex = xDNSCache[ uxIndex ].ucCurrentIPAddress % xDNSCache[ uxIndex ].ucNumIPAddresses;
ucIndex = ucIndex % ( uint8_t ) ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY;
ulIPAddressIndex = ucIndex;
xDNSCache[ uxIndex ].ucCurrentIPAddress++;
#endif /* if ( ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY > 1 ) */
*pulIP = xDNSCache[ uxIndex ].ulIPAddresses[ ulIPAddressIndex ];
isRead = pdTRUE;
}
else
{
/* Age out the old cached record. */
xDNSCache[ uxIndex ].pcName[ 0 ] = ( char ) 0;
isRead = pdFALSE;
}
return isRead;
}
/**
* @brief update entry at \p index in the cache
* @param[in] uxIndex : index in the cache
* @param[in] ulTTL time to live (in seconds)
* @param[in] pulIP ip to update the cache with
* @param[in] ulCurrentTimeSeconds current time
* @post the global structure \a xDNSCache is modified
*
*/
static void prvUpdateCacheEntry( UBaseType_t uxIndex,
uint32_t ulTTL,
const uint32_t * pulIP,
uint32_t ulCurrentTimeSeconds )
{
uint32_t ulIPAddressIndex = 0;
#if ( ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY > 1 )
if( xDNSCache[ uxIndex ].ucNumIPAddresses <
( uint8_t ) ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY )
{
/* If more answers exist than there are IP address storage
* slots they will overwrite entry 0 */
ulIPAddressIndex = xDNSCache[ uxIndex ].ucNumIPAddresses;
xDNSCache[ uxIndex ].ucNumIPAddresses++;
}
#endif
xDNSCache[ uxIndex ].ulIPAddresses[ ulIPAddressIndex ] = *pulIP;
xDNSCache[ uxIndex ].ulTTL = ulTTL;
xDNSCache[ uxIndex ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds;
}
/**
* @brief insert entry in the cache
* @param[in] pcName cache entry key
* @param[in] ulTTL time to live (in seconds)
* @param[in] pulIP ip address
* @param[in] ulCurrentTimeSeconds current time
* @post the global structure \a xDNSCache is modified
*/
static void prvInsertCacheEntry( const char * pcName,
uint32_t ulTTL,
const uint32_t * pulIP,
uint32_t ulCurrentTimeSeconds )
{
/* Add or update the item. */
if( strlen( pcName ) < ( size_t ) ipconfigDNS_CACHE_NAME_LENGTH )
{
( void ) strcpy( xDNSCache[ uxFreeEntry ].pcName, pcName );
xDNSCache[ uxFreeEntry ].ulIPAddresses[ 0 ] = *pulIP;
xDNSCache[ uxFreeEntry ].ulTTL = ulTTL;
xDNSCache[ uxFreeEntry ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds;
#if ( ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY > 1 )
xDNSCache[ uxFreeEntry ].ucNumIPAddresses = 1;
xDNSCache[ uxFreeEntry ].ucCurrentIPAddress = 0;
/* Initialize all remaining IP addresses in this entry to 0 */
( void ) memset( &xDNSCache[ uxFreeEntry ].ulIPAddresses[ 1 ],
0,
sizeof( xDNSCache[ uxFreeEntry ].ulIPAddresses[ 1 ] ) *
( ( uint32_t ) ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY - 1U ) );
#endif
uxFreeEntry++;
if( uxFreeEntry == ipconfigDNS_CACHE_ENTRIES )
{
uxFreeEntry = 0;
}
}
}
#endif /* if ( ( ipconfigUSE_DNS != 0 ) && ( ipconfigUSE_DNS_CACHE == 1 ) ) */

View File

@ -0,0 +1,203 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_DNS_Callback.c
* @brief File that handles the DNS Callback option
*/
#include "FreeRTOS_DNS_Callback.h"
#include "FreeRTOS_IP.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_DNS_Globals.h"
#include "FreeRTOS_IP_Timers.h"
#if ( ( ipconfigDNS_USE_CALLBACKS == 1 ) && ( ipconfigUSE_DNS != 0 ) )
/**
* @brief list of callbacks to send
*/
static List_t xCallbackList;
/**
* @brief A DNS reply was received, see if there is any matching entry and
* call the handler.
*
* @param[in] uxIdentifier: Identifier associated with the callback function.
* @param[in] pcName: The name associated with the callback function.
* @param[in] ulIPAddress: IP-address obtained from the DNS server.
*
* @return Returns pdTRUE if uxIdentifier was recognized.
*/
BaseType_t xDNSDoCallback( TickType_t uxIdentifier,
const char * pcName,
uint32_t ulIPAddress )
{
BaseType_t xResult = pdFALSE;
const ListItem_t * pxIterator;
const ListItem_t * xEnd = listGET_END_MARKER( &xCallbackList );
vTaskSuspendAll();
{
for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
pxIterator != ( const ListItem_t * ) xEnd;
pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
{
if( listGET_LIST_ITEM_VALUE( pxIterator ) == uxIdentifier )
{
DNSCallback_t * pxCallback = ( ( DNSCallback_t * )
listGET_LIST_ITEM_OWNER( pxIterator ) );
pxCallback->pCallbackFunction( pcName, pxCallback->pvSearchID,
ulIPAddress );
( void ) uxListRemove( &pxCallback->xListItem );
vPortFree( pxCallback );
if( listLIST_IS_EMPTY( &xCallbackList ) != pdFALSE )
{
/* The list of outstanding requests is empty. No need for periodic polling. */
vIPSetDNSTimerEnableState( pdFALSE );
}
xResult = pdTRUE;
break;
}
}
}
( void ) xTaskResumeAll();
return xResult;
}
/**
* @brief FreeRTOS_gethostbyname_a() was called along with callback parameters.
* Store them in a list for later reference.
*
* @param[in] pcHostName: The hostname whose IP address is being searched for.
* @param[in] pvSearchID: The search ID of the DNS callback function to set.
* @param[in] pCallbackFunction: The callback function pointer.
* @param[in] uxTimeout: Timeout of the callback function.
* @param[in] uxIdentifier: Random number used as ID in the DNS message.
*/
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 ) );
/* Translate from ms to number of clock ticks. */
uxTimeout /= portTICK_PERIOD_MS;
if( pxCallback != NULL )
{
if( listLIST_IS_EMPTY( &xCallbackList ) != pdFALSE )
{
/* This is the first one, start the DNS timer to check for timeouts */
vDNSTimerReload( FreeRTOS_min_uint32( 1000U, uxTimeout ) );
}
( void ) strcpy( pxCallback->pcName, pcHostName );
pxCallback->pCallbackFunction = pCallbackFunction;
pxCallback->pvSearchID = pvSearchID;
pxCallback->uxRemainingTime = uxTimeout;
vTaskSetTimeOutState( &pxCallback->uxTimeoutState );
listSET_LIST_ITEM_OWNER( &( pxCallback->xListItem ), ( void * ) pxCallback );
listSET_LIST_ITEM_VALUE( &( pxCallback->xListItem ), uxIdentifier );
vTaskSuspendAll();
{
vListInsertEnd( &xCallbackList, &pxCallback->xListItem );
}
( void ) xTaskResumeAll();
}
else
{
FreeRTOS_debug_printf( ( " vDNSSetCallBack : Could not allocate memory: %u bytes",
( unsigned ) ( sizeof( *pxCallback ) + lLength ) ) );
}
}
/**
* @brief Iterate through the list of call-back structures and remove
* old entries which have reached a timeout.
* As soon as the list has become empty, the DNS timer will be stopped.
* In case pvSearchID is supplied, the user wants to cancel a DNS request.
*
* @param[in] pvSearchID: The search ID of callback function whose associated
* DNS request is being cancelled. If non-ID specific checking of
* all requests is required, then this field should be kept as NULL.
*/
void vDNSCheckCallBack( void * pvSearchID )
{
const ListItem_t * pxIterator;
const ListItem_t * xEnd = listGET_END_MARKER( &xCallbackList );
vTaskSuspendAll();
{
for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
pxIterator != xEnd; )
{
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 );
if( ( pvSearchID != NULL ) && ( pvSearchID == pxCallback->pvSearchID ) )
{
( void ) uxListRemove( &( pxCallback->xListItem ) );
vPortFree( pxCallback );
}
else if( xTaskCheckForTimeOut( &pxCallback->uxTimeoutState, &pxCallback->uxRemainingTime ) != pdFALSE )
{
pxCallback->pCallbackFunction( pxCallback->pcName, pxCallback->pvSearchID, 0 );
( void ) uxListRemove( &( pxCallback->xListItem ) );
vPortFree( pxCallback );
}
else
{
/* This call-back is still waiting for a reply or a time-out. */
}
}
}
( void ) xTaskResumeAll();
if( listLIST_IS_EMPTY( &xCallbackList ) != pdFALSE )
{
vIPSetDNSTimerEnableState( pdFALSE );
}
}
/**
* @brief initialize the cache
* @post will modify global list xCallbackList
*/
void vDNSCallbackInitialise()
{
vListInitialise( &xCallbackList );
}
#endif /* if ( ipconfigDNS_USE_CALLBACKS == 1 ) */

View File

@ -0,0 +1,153 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_DNS_Networking.c
* @brief Implements the Domain Name System Networking
* for the FreeRTOS+TCP network stack.
*/
#include "FreeRTOS.h"
#include "FreeRTOS_DNS_Networking.h"
#if ( ipconfigUSE_DNS != 0 )
/**
* @brief Create a socket and bind it to the standard DNS port number.
*
* @return The created socket - or NULL if the socket could not be created or could not be bound.
*/
Socket_t DNS_CreateSocket( TickType_t uxReadTimeOut_ticks )
{
Socket_t xSocket;
struct freertos_sockaddr xAddress;
TickType_t uxWriteTimeOut_ticks = ipconfigDNS_SEND_BLOCK_TIME_TICKS;
BaseType_t xReturn;
/* This must be the first time this function has been called. Create
* the socket. */
xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
if( xSocketValid( xSocket ) == pdFALSE )
{
/* There was an error, return NULL. */
xSocket = NULL;
}
else
{
/* Auto bind the port. */
xAddress.sin_port = 0U;
xReturn = FreeRTOS_bind( xSocket, &xAddress, ( socklen_t ) sizeof( xAddress ) );
/* Check the bind was successful, and clean up if not. */
if( xReturn != 0 )
{
( void ) FreeRTOS_closesocket( xSocket );
xSocket = NULL;
}
else
{
/* Ideally we should check for the return value. But since we are passing
* correct parameters, and xSocket is != NULL, the return value is
* going to be '0' i.e. success. Thus, return value is discarded */
( void ) FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &( uxWriteTimeOut_ticks ), sizeof( TickType_t ) );
( void ) FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &( uxReadTimeOut_ticks ), sizeof( TickType_t ) );
}
}
return xSocket;
}
/**
* @brief perform a DNS network request
* @param xDNSSocket Created socket
* @param xAddress address structure (ip, port etc)
* @param pxDNSBuf buffer to send
* @return xReturn: true if the message could be sent
* false otherwise
*
*/
BaseType_t DNS_SendRequest( Socket_t xDNSSocket,
const struct freertos_sockaddr * xAddress,
const struct xDNSBuffer * pxDNSBuf )
{
BaseType_t xReturn = pdFALSE;
iptraceSENDING_DNS_REQUEST();
/* Send the DNS message. */
if( FreeRTOS_sendto( xDNSSocket,
pxDNSBuf->pucPayloadBuffer,
pxDNSBuf->uxPayloadLength,
FREERTOS_ZERO_COPY,
xAddress,
( socklen_t ) sizeof( *xAddress ) ) != 0 )
{
xReturn = pdTRUE;
}
else
{
/* The message was not sent so the stack will not be
* releasing the zero copy - it must be released here. */
xReturn = pdFALSE;
}
return xReturn;
}
/**
* @brief perform a DNS network read
* @param xDNSSocket socket
* @param xAddress address to read from
* @param pxReceiveBuffer buffer to fill with received data
*/
void DNS_ReadReply( const ConstSocket_t xDNSSocket,
struct freertos_sockaddr * xAddress,
struct xDNSBuffer * pxReceiveBuffer )
{
uint32_t ulAddressLength = ( uint32_t ) sizeof( struct freertos_sockaddr );
/* Wait for the reply. */
pxReceiveBuffer->uxPayloadLength = ( size_t ) FreeRTOS_recvfrom( xDNSSocket,
&pxReceiveBuffer->pucPayloadBuffer,
0,
FREERTOS_ZERO_COPY,
xAddress,
&ulAddressLength );
pxReceiveBuffer->uxPayloadSize = pxReceiveBuffer->uxPayloadLength;
}
/**
* @brief perform a DNS network close
* @param xDNSSocket
*/
void DNS_CloseSocket( Socket_t xDNSSocket )
{
( void ) FreeRTOS_closesocket( xDNSSocket );
}
#endif /* if ( ipconfigUSE_DNS != 0 ) */

View File

@ -0,0 +1,953 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_DNS_Parser.c
* @brief Implements the DNS message parser
*/
/* FreeRTOS includes. */
#include "FreeRTOS.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_DNS_Globals.h"
#include "FreeRTOS_DNS_Parser.h"
#include "FreeRTOS_DNS_Cache.h"
#include "FreeRTOS_DNS_Callback.h"
#include "NetworkBufferManagement.h"
#include <string.h>
#if ( ipconfigUSE_DNS != 0 )
/** @brief The list of all callback structures. */
/**
* @brief Read the Name field out of a DNS response packet.
*
* @param[in] pucByte: Pointer to the DNS response.
* @param[in] uxRemainingBytes: Length of the DNS response.
* @param[out] pcName: The pointer in which the name in the DNS response will be returned.
* @param[in] uxDestLen: Size of the pcName array.
*
* @return If a fully formed name was found, then return the number of bytes processed in pucByte.
*/
size_t DNS_ReadNameField( const uint8_t * pucByte,
size_t uxRemainingBytes,
char * pcName,
size_t uxDestLen )
{
size_t uxNameLen = 0U;
size_t uxIndex = 0U;
size_t uxSourceLen = uxRemainingBytes;
/* uxCount gets the values from pucByte and counts down to 0.
* No need to have a different type than that of pucByte */
size_t uxCount;
if( uxSourceLen == ( size_t ) 0U )
{
/* Return 0 value in case of error. */
uxIndex = 0U;
}
/* Determine if the name is the fully coded name, or an offset to the name
* elsewhere in the message. */
else if( ( pucByte[ uxIndex ] & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )
{
/* Jump over the two byte offset. */
if( uxSourceLen > sizeof( uint16_t ) )
{
uxIndex += sizeof( uint16_t );
}
else
{
uxIndex = 0U;
}
}
else
{
/* 'uxIndex' points to the full name. Walk over the string. */
while( ( uxIndex < uxSourceLen ) && ( pucByte[ uxIndex ] != ( uint8_t ) 0x00U ) )
{
/* If this is not the first time through the loop, then add a
* separator in the output. */
if( ( uxNameLen > 0U ) )
{
if( uxNameLen >= uxDestLen )
{
uxIndex = 0U;
/* coverity[break_stmt] : Break statement terminating the loop */
break;
}
pcName[ uxNameLen ] = '.';
uxNameLen++;
}
/* Process the first/next sub-string. */
uxCount = ( size_t ) pucByte[ uxIndex ];
uxIndex++;
if( ( uxIndex + uxCount ) > uxSourceLen )
{
uxIndex = 0U;
break;
}
while( uxCount-- != 0U )
{
if( uxNameLen >= uxDestLen )
{
uxIndex = 0U;
break;
/* break out of inner loop here
* break out of outer loop at the test uxNameLen >= uxDestLen. */
}
pcName[ uxNameLen ] = ( char ) pucByte[ uxIndex ];
uxNameLen++;
uxIndex++;
}
}
/* Confirm that a fully formed name was found. */
if( uxIndex > 0U )
{
/* Here, there is no need to check for pucByte[ uxindex ] == 0 because:
* When we break out of the above while loop, uxIndex is made 0 thereby
* failing above check. Whenever we exit the loop otherwise, either
* pucByte[ uxIndex ] == 0 (which makes the check here unnecessary) or
* uxIndex >= uxSourceLen (which makes sure that we do not go in the 'if'
* case).
*/
if( ( uxNameLen < uxDestLen ) && ( uxIndex < uxSourceLen ) )
{
pcName[ uxNameLen ] = '\0';
uxIndex++;
}
else
{
uxIndex = 0U;
}
}
}
return uxIndex;
}
/**
* @brief Simple routine that jumps over the NAME field of a resource record.
*
* @param[in] pucByte: The pointer to the resource record.
* @param[in] uxLength: Length of the resource record.
*
* @return It returns the number of bytes read, or zero when an error has occurred.
*/
size_t DNS_SkipNameField( const uint8_t * pucByte,
size_t uxLength )
{
size_t uxChunkLength;
size_t uxSourceLenCpy = uxLength;
size_t uxIndex = 0U;
if( uxSourceLenCpy == 0U )
{
uxIndex = 0U;
}
/* Determine if the name is the fully coded name, or an offset to the name
* elsewhere in the message. */
else if( ( pucByte[ uxIndex ] & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )
{
/* Jump over the two byte offset. */
if( uxSourceLenCpy > sizeof( uint16_t ) )
{
uxIndex += sizeof( uint16_t );
}
else
{
uxIndex = 0U;
}
}
else
{
/* pucByte points to the full name. Walk over the string. */
while( ( pucByte[ uxIndex ] != 0U ) && ( uxSourceLenCpy > 1U ) )
{
/* Conversion to size_t causes addition to be done
* in size_t */
uxChunkLength = ( ( size_t ) pucByte[ uxIndex ] ) + 1U;
if( uxSourceLenCpy > uxChunkLength )
{
uxSourceLenCpy -= uxChunkLength;
uxIndex += uxChunkLength;
}
else
{
uxIndex = 0U;
break;
}
}
/* Confirm that a fully formed name was found. */
if( uxIndex > 0U )
{
if( pucByte[ uxIndex ] == 0U )
{
uxIndex++;
}
else
{
uxIndex = 0U;
}
}
}
return uxIndex;
}
/**
* @brief Process a response packet from a DNS server, or an LLMNR reply.
*
* @param[in] pucUDPPayloadBuffer: The DNS response received as a UDP
* payload.
* @param[in] uxBufferLength: Length of the UDP payload buffer.
* @param[in] xExpected: indicates whether the identifier in the reply
* was expected, and thus if the DNS cache may be
* updated with the reply.
*
* @return The IP address in the DNS response if present and if xExpected is set to pdTRUE.
* An error code (dnsPARSE_ERROR) if there was an error in the DNS response.
* 0 if xExpected set to pdFALSE.
*/
uint32_t DNS_ParseDNSReply( uint8_t * pucUDPPayloadBuffer,
size_t uxBufferLength,
BaseType_t xExpected )
{
DNSMessage_t * pxDNSMessageHeader;
uint32_t ulIPAddress = 0U;
#if ( ipconfigUSE_LLMNR == 1 )
char * pcRequestedName = NULL;
#endif
uint8_t * pucByte;
size_t uxSourceBytesRemaining;
uint16_t x;
uint16_t usQuestions;
BaseType_t xReturn = pdTRUE;
#if ( ipconfigUSE_LLMNR == 1 )
uint16_t usType = 0U;
uint16_t usClass = 0U;
#endif
#if ( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 )
BaseType_t xDoStore = xExpected;
char pcName[ ipconfigDNS_CACHE_NAME_LENGTH ] = "";
#endif
/* Ensure that the buffer is of at least minimal DNS message length. */
if( uxBufferLength < sizeof( DNSMessage_t ) )
{
xReturn = pdFALSE;
}
else
{
uxSourceBytesRemaining = uxBufferLength;
/* Parse the DNS message header. Map the byte stream onto a structure
* for easier access. */
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
pxDNSMessageHeader = ( ( DNSMessage_t * )
pucUDPPayloadBuffer );
/* Introduce a do {} while (0) to allow the use of breaks. */
do
{
size_t uxBytesRead = 0U;
size_t uxResult;
/* Start at the first byte after the header. */
pucByte = &( pucUDPPayloadBuffer[ sizeof( DNSMessage_t ) ] );
uxSourceBytesRemaining -= sizeof( DNSMessage_t );
/* Skip any question records. */
usQuestions = FreeRTOS_ntohs( pxDNSMessageHeader->usQuestions );
for( x = 0U; x < usQuestions; x++ )
{
#if ( ipconfigUSE_LLMNR == 1 )
{
if( x == 0U )
{
pcRequestedName = ( char * ) pucByte;
}
}
#endif
#if ( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 )
if( x == 0U )
{
uxResult = DNS_ReadNameField( pucByte,
uxSourceBytesRemaining,
pcName,
sizeof( pcName ) );
}
else
#endif /* ipconfigUSE_DNS_CACHE || ipconfigDNS_USE_CALLBACKS */
{
/* Skip the variable length pcName field. */
uxResult = DNS_SkipNameField( pucByte,
uxSourceBytesRemaining );
}
/* Check for a malformed response. */
if( uxResult == 0U )
{
xReturn = pdFALSE;
break;
}
uxBytesRead += uxResult;
pucByte = &( pucByte[ uxResult ] );
uxSourceBytesRemaining -= uxResult;
/* Check the remaining buffer size. */
if( uxSourceBytesRemaining >= sizeof( uint32_t ) )
{
#if ( ipconfigUSE_LLMNR == 1 )
{
/* usChar2u16 returns value in host endianness. */
usType = usChar2u16( pucByte );
usClass = usChar2u16( &( pucByte[ 2 ] ) );
}
#endif /* ipconfigUSE_LLMNR */
/* Skip the type and class fields. */
pucByte = &( pucByte[ sizeof( uint32_t ) ] );
uxSourceBytesRemaining -= sizeof( uint32_t );
}
else
{
xReturn = pdFALSE;
break;
}
}
if( xReturn == pdFALSE )
{
/* No need to proceed. Break out of the do-while loop. */
break;
}
/* Search through the answer records. */
pxDNSMessageHeader->usAnswers =
FreeRTOS_ntohs( pxDNSMessageHeader->usAnswers );
if( ( pxDNSMessageHeader->usFlags & dnsRX_FLAGS_MASK )
== dnsEXPECTED_RX_FLAGS )
{
ulIPAddress = parseDNSAnswer( pxDNSMessageHeader,
pucByte,
uxSourceBytesRemaining,
&uxBytesRead
#if ( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 )
,
pcName,
xDoStore
#endif
);
}
#if ( ipconfigUSE_LLMNR == 1 )
/* No need to check that pcRequestedName != NULL since sQuestions != 0, then
* pcRequestedName is assigned with this statement
* "pcRequestedName = ( char * ) pucByte;" */
else if( ( usQuestions != ( uint16_t ) 0U ) &&
( 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 ] ) ) != pdFALSE )
{
int16_t usLength;
NetworkBufferDescriptor_t * pxNewBuffer = NULL;
NetworkBufferDescriptor_t * pxNetworkBuffer =
pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );
LLMNRAnswer_t * pxAnswer;
uint8_t * pucNewBuffer = NULL;
if( pxNetworkBuffer != NULL )
{
if( xBufferAllocFixedSize == pdFALSE )
{
size_t uxDataLength = uxBufferLength +
sizeof( UDPHeader_t ) +
sizeof( EthernetHeader_t ) +
sizeof( IPHeader_t );
/* Set the size of the outgoing packet. */
pxNetworkBuffer->xDataLength = uxDataLength;
pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer,
uxDataLength +
sizeof( LLMNRAnswer_t ) );
if( pxNewBuffer != NULL )
{
BaseType_t xOffset1, xOffset2;
xOffset1 = ( BaseType_t ) ( pucByte - pucUDPPayloadBuffer );
xOffset2 = ( BaseType_t ) ( ( ( uint8_t * ) pcRequestedName ) - pucUDPPayloadBuffer );
pxNetworkBuffer = pxNewBuffer;
pucNewBuffer = &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );
pucByte = &( pucNewBuffer[ xOffset1 ] );
pcRequestedName = ( char * ) &( pucNewBuffer[ xOffset2 ] );
pxDNSMessageHeader = ( ( DNSMessage_t * ) pucNewBuffer );
}
else
{
/* Just to indicate that the message may not be answered. */
pxNetworkBuffer = NULL;
}
}
else
{
pucNewBuffer = &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );
}
}
if( ( pxNetworkBuffer != NULL ) )
{
pxAnswer = ( ( LLMNRAnswer_t * ) pucByte );
/* We leave 'usIdentifier' and 'usQuestions' untouched */
#ifndef _lint
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 */
#endif /* lint */
pxAnswer->ucNameCode = dnsNAME_IS_OFFSET;
pxAnswer->ucNameOffset = ( uint8_t ) ( pcRequestedName - ( char * ) pucNewBuffer );
#ifndef _lint
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 ) );
#endif /* lint */
usLength = ( int16_t ) ( sizeof( *pxAnswer ) + ( size_t ) ( pucByte - pucNewBuffer ) );
prepareReplyDNSMessage( pxNetworkBuffer, usLength );
/* This function will fill in the eth addresses and send the packet */
vReturnEthernetFrame( pxNetworkBuffer, pdFALSE );
if( pxNewBuffer != NULL )
{
vReleaseNetworkBufferAndDescriptor( pxNewBuffer );
}
}
}
}
else
{
/* Not an expected reply. */
}
#endif /* ipconfigUSE_LLMNR == 1 */
( void ) uxBytesRead;
} while( ipFALSE_BOOL );
}
if( xReturn == pdFALSE )
{
/* There was an error while parsing the DNS response. Return error code. */
ulIPAddress = ( uint32_t ) dnsPARSE_ERROR;
}
else if( xExpected == pdFALSE )
{
/* Do not return a valid IP-address in case the reply was not expected. */
ulIPAddress = 0U;
}
else
{
/* The IP-address found will be returned. */
}
#if ( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 )
( void ) xDoStore;
#endif
return ulIPAddress;
}
/**
* @brief perform a dns lookup in the local cache
* @param[in] pxDNSMessageHeader DNS header
* @param pucByte buffer
* @param uxSourceBytesRemaining remaining bytes in pucByte
* @param[out] uxBytesRead total bytes consumed by the function
* @param pcName update the cache and /or send to callback
* @param xDoStore whether to update the cache
* @return ip address extracted from the frame or zero if not found
*/
uint32_t parseDNSAnswer( const DNSMessage_t * pxDNSMessageHeader,
uint8_t * pucByte,
size_t uxSourceBytesRemaining,
size_t * uxBytesRead
#if ( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 )
,
const char * pcName,
BaseType_t xDoStore
#endif
)
{
uint16_t x;
size_t uxResult;
const uint16_t usCount = ( uint16_t ) ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY;
uint16_t usNumARecordsStored = 0;
BaseType_t xReturn = pdTRUE;
uint16_t usType = 0U;
const DNSAnswerRecord_t * pxDNSAnswerRecord;
const void * pvCopySource;
void * pvCopyDest;
const size_t uxAddressLength = ipSIZE_OF_IPv4_ADDRESS;
uint32_t ulIPAddress = 0U;
uint32_t ulReturnIPAddress = 0U;
uint16_t usDataLength;
uint8_t * pucBuffer = pucByte;
size_t uxRxSourceByteRemaining = uxSourceBytesRemaining;
for( x = 0U; x < pxDNSMessageHeader->usAnswers; x++ )
{
BaseType_t xDoAccept;
if( usNumARecordsStored >= usCount )
{
/* Only count ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY number of records. */
break;
}
uxResult = DNS_SkipNameField( pucBuffer,
uxRxSourceByteRemaining );
/* Check for a malformed response. */
if( uxResult == 0U )
{
xReturn = pdFALSE;
break;
}
*uxBytesRead += uxResult;
pucBuffer = &( pucBuffer[ uxResult ] );
uxRxSourceByteRemaining -= uxResult;
/* Is there enough data for an IPv4 A record answer and, if so,
* is this an A record? */
if( uxRxSourceByteRemaining < sizeof( uint16_t ) )
{
xReturn = pdFALSE;
break;
}
usType = usChar2u16( pucBuffer );
if( usType == ( uint16_t ) dnsTYPE_A_HOST )
{
if( uxRxSourceByteRemaining >= ( sizeof( DNSAnswerRecord_t ) + uxAddressLength ) )
{
xDoAccept = pdTRUE;
}
else
{
xDoAccept = pdFALSE;
}
}
else
{
/* Unknown host type. */
xDoAccept = pdFALSE;
}
if( xDoAccept != pdFALSE )
{
/* This is the required record type and is of sufficient size. */
/* Mapping pucBuffer to a DNSAnswerRecord allows easy access of the
* fields of the structure. */
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
pxDNSAnswerRecord = ( ( DNSAnswerRecord_t * ) pucBuffer );
/* Sanity check the data length of an IPv4 answer. */
if( FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength ) ==
( uint16_t ) uxAddressLength )
{
/* Copy the IP address out of the record. Using different pointers
* to copy only the portion we want is intentional here. */
/*
* Use helper variables for memcpy() to remain
* compliant with MISRA Rule 21.15. These should be
* optimized away.
*/
pvCopySource = &pucBuffer[ sizeof( DNSAnswerRecord_t ) ];
pvCopyDest = &ulIPAddress;
( void ) memcpy( pvCopyDest, pvCopySource, uxAddressLength );
#if ( ipconfigDNS_USE_CALLBACKS == 1 )
{
/* 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 /* ipconfigDNS_USE_CALLBACKS == 1 */
#if ( ipconfigUSE_DNS_CACHE == 1 )
{
char cBuffer[ 16 ];
/* The reply will only be stored in the DNS cache when the
* request was issued by this device. */
if( xDoStore != pdFALSE )
{
( void ) FreeRTOS_dns_update(
pcName,
&ulIPAddress,
pxDNSAnswerRecord->ulTTL );
usNumARecordsStored++; /* Track # of A records stored */
}
( void ) FreeRTOS_inet_ntop( FREERTOS_AF_INET,
( const void * ) &( ulIPAddress ),
cBuffer,
( socklen_t ) sizeof( cBuffer ) );
/* Show what has happened. */
FreeRTOS_printf( ( "DNS[0x%04lX]: The answer to '%s' (%s) will%s be stored\n",
( UBaseType_t ) pxDNSMessageHeader->usIdentifier,
pcName,
cBuffer,
( xDoStore != 0 ) ? "" : " NOT" ) );
}
#endif /* ipconfigUSE_DNS_CACHE */
if( ( ulReturnIPAddress == 0U ) && ( ulIPAddress != 0U ) )
{
/* Remember the first IP-address that is found. */
ulReturnIPAddress = ulIPAddress;
}
}
pucBuffer = &( pucBuffer[ sizeof( DNSAnswerRecord_t ) + uxAddressLength ] );
uxRxSourceByteRemaining -= ( sizeof( DNSAnswerRecord_t ) + uxAddressLength );
}
else if( uxRxSourceByteRemaining >= sizeof( DNSAnswerRecord_t ) )
{
/* It's not an A record, so skip it. Get the header location
* and then jump over the header. */
/* Cast the response to DNSAnswerRecord for easy access to fields of the DNS response. */
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
pxDNSAnswerRecord = ( ( DNSAnswerRecord_t * ) pucBuffer );
pucBuffer = &( pucBuffer[ sizeof( DNSAnswerRecord_t ) ] );
uxRxSourceByteRemaining -= sizeof( DNSAnswerRecord_t );
/* Determine the length of the answer data from the header. */
usDataLength = FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength );
/* Jump over the answer. */
if( uxRxSourceByteRemaining >= usDataLength )
{
pucBuffer = &( pucBuffer[ usDataLength ] );
uxRxSourceByteRemaining -= usDataLength;
}
else
{
/* Malformed response. */
xReturn = pdFALSE;
break;
}
}
else
{
/* Do nothing */
}
}
return ( xReturn != 0 ) ? ulReturnIPAddress : 0U;
}
#if ( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) )
/**
* @brief Send a DNS message to be used in NBNS or LLMNR
*
* @param[in] pxNetworkBuffer: The network buffer descriptor with the DNS message.
* @param[in] lNetLength: The length of the DNS message.
*/
void prepareReplyDNSMessage( NetworkBufferDescriptor_t * pxNetworkBuffer,
BaseType_t lNetLength )
{
UDPPacket_t * pxUDPPacket;
IPHeader_t * pxIPHeader;
UDPHeader_t * pxUDPHeader;
size_t uxDataLength;
pxUDPPacket = ( ( UDPPacket_t * )
pxNetworkBuffer->pucEthernetBuffer );
pxIPHeader = &pxUDPPacket->xIPHeader;
pxUDPHeader = &pxUDPPacket->xUDPHeader;
/* HT: started using defines like 'ipSIZE_OF_xxx' */
pxIPHeader->usLength = FreeRTOS_htons( ( uint16_t ) lNetLength +
ipSIZE_OF_IPv4_HEADER +
ipSIZE_OF_UDP_HEADER );
/* HT:endian: should not be translated, copying from packet to packet */
pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
pxIPHeader->ucTimeToLive = ipconfigUDP_TIME_TO_LIVE;
pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
/* The stack doesn't support fragments, so the fragment offset field must always be zero.
* The header was never memset to zero, so set both the fragment offset and fragmentation flags in one go.
*/
#if ( ipconfigFORCE_IP_DONT_FRAGMENT != 0 )
pxIPHeader->usFragmentOffset = ipFRAGMENT_FLAGS_DONT_FRAGMENT;
#else
pxIPHeader->usFragmentOffset = 0U;
#endif
usPacketIdentifier++;
pxUDPHeader->usLength = FreeRTOS_htons( ( uint32_t ) lNetLength +
ipSIZE_OF_UDP_HEADER );
vFlip_16( pxUDPHeader->usSourcePort, pxUDPHeader->usDestinationPort );
/* Important: tell NIC driver how many bytes must be sent */
uxDataLength = ( ( size_t ) lNetLength ) + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER + ipSIZE_OF_ETH_HEADER;
#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
{
/* Calculate the IP header checksum. */
pxIPHeader->usHeaderChecksum = 0U;
pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
/* calculate the UDP checksum for outgoing package */
( void ) usGenerateProtocolChecksum( ( uint8_t * ) pxUDPPacket, uxDataLength, pdTRUE );
}
#endif
/* Important: tell NIC driver how many bytes must be sent */
pxNetworkBuffer->xDataLength = uxDataLength;
}
#endif /* ipconfigUSE_NBNS == 1 || ipconfigUSE_LLMNR == 1 */
#if ( ipconfigUSE_NBNS == 1 )
/**
* @brief Respond to an NBNS query or an NBNS reply.
*
* @param[in] pucPayload: the UDP payload of the NBNS message.
* @param[in] uxBufferLength: Length of the Buffer.
* @param[in] ulIPAddress: IP address of the sender.
*/
void DNS_TreatNBNS( uint8_t * pucPayload,
size_t uxBufferLength,
uint32_t ulIPAddress )
{
uint16_t usFlags;
uint16_t usType;
uint16_t usClass;
uint8_t * pucSource;
uint8_t * pucTarget;
uint8_t ucByte;
uint8_t ucNBNSName[ 17 ];
uint8_t * pucUDPPayloadBuffer = pucPayload;
NetworkBufferDescriptor_t * pxNetworkBuffer;
/* Read the request flags in host endianness. */
usFlags = usChar2u16( &( pucUDPPayloadBuffer[ offsetof( NBNSRequest_t, usFlags ) ] ) );
if( ( usFlags & dnsNBNS_FLAGS_OPCODE_MASK ) == dnsNBNS_FLAGS_OPCODE_QUERY )
{
usType = usChar2u16( &( pucUDPPayloadBuffer[ offsetof( NBNSRequest_t, usType ) ] ) );
usClass = usChar2u16( &( pucUDPPayloadBuffer[ offsetof( NBNSRequest_t, usClass ) ] ) );
/* Not used for now */
( 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 ) - 2U ] );
pucTarget[ 1 ] = ( uint8_t ) 0U;
/* Start with decoding the last 2 bytes. */
pucSource = &( pucUDPPayloadBuffer[ ( dnsNBNS_ENCODED_NAME_LENGTH - 2 ) +
offsetof( NBNSRequest_t, ucName ) ] );
for( ; ; )
{
const uint8_t ucCharA = ( uint8_t ) 0x41U;
ucByte = ( ( uint8_t ) ( ( pucSource[ 0 ] - ucCharA ) << 4 ) ) |
( pucSource[ 1 ] - ucCharA );
/* Make sure there are no trailing spaces in the name. */
if( ( ucByte == ( uint8_t ) ' ' ) && ( pucTarget[ 1 ] == 0U ) )
{
ucByte = 0U;
}
*pucTarget = ucByte;
if( pucTarget == ucNBNSName )
{
break;
}
pucTarget -= 1;
pucSource -= 2;
}
#if ( ipconfigUSE_DNS_CACHE == 1 )
{
if( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) != 0U )
{
/* If this is a response from another device,
* add the name to the DNS cache */
( void ) FreeRTOS_dns_update( ( char * ) ucNBNSName, &( ulIPAddress ), 0 );
}
}
#else
{
/* Avoid compiler warnings. */
( void ) ulIPAddress;
}
#endif /* ipconfigUSE_DNS_CACHE */
if( ( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) == 0U ) &&
( usType == dnsNBNS_TYPE_NET_BIOS ) &&
( xApplicationDNSQueryHook( ( const char * ) ucNBNSName ) != pdFALSE ) )
{
uint16_t usLength;
DNSMessage_t * pxMessage;
NBNSAnswer_t * pxAnswer;
NetworkBufferDescriptor_t * pxNewBuffer = NULL;
/* Someone is looking for a device with ucNBNSName,
* prepare a positive reply. */
pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );
if( ( xBufferAllocFixedSize == pdFALSE ) &&
( pxNetworkBuffer != NULL ) )
{
/* 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 ) ] );
pxNetworkBuffer = pxNewBuffer;
}
else
{
/* Just prevent that a reply will be sent */
pxNetworkBuffer = NULL;
}
}
/* Should not occur: pucUDPPayloadBuffer is part of a xNetworkBufferDescriptor */
if( pxNetworkBuffer != NULL )
{
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() */
#ifndef _lint
vSetField16( pxMessage, DNSMessage_t, usFlags, dnsNBNS_QUERY_RESPONSE_FLAGS ); /* 0x8500 */
vSetField16( pxMessage, DNSMessage_t, usQuestions, 0 );
vSetField16( pxMessage, DNSMessage_t, usAnswers, 1 );
vSetField16( pxMessage, DNSMessage_t, usAuthorityRRs, 0 );
vSetField16( pxMessage, DNSMessage_t, usAdditionalRRs, 0 );
#else
( void ) pxMessage;
#endif
pxAnswer = ( ( NBNSAnswer_t * ) &( pucUDPPayloadBuffer[ offsetof( NBNSRequest_t, usType ) ] ) );
#ifndef _lint
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, usNbFlags, dnsNBNS_NAME_FLAGS );
vSetField32( pxAnswer, NBNSAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) );
#else
( void ) pxAnswer;
#endif
usLength = ( uint16_t ) ( sizeof( NBNSAnswer_t ) + ( size_t ) offsetof( NBNSRequest_t, usType ) );
prepareReplyDNSMessage( pxNetworkBuffer, ( BaseType_t ) usLength );
/* This function will fill in the eth addresses and send the packet */
vReturnEthernetFrame( pxNetworkBuffer, pdFALSE );
if( pxNewBuffer != NULL )
{
vReleaseNetworkBufferAndDescriptor( pxNewBuffer );
}
}
}
}
}
#endif /* ipconfigUSE_NBNS */
#endif /* ipconfigUSE_DNS != 0 */

View File

@ -0,0 +1,240 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_ICMP.c
* @brief Implements the Internet Control Message Protocol for the FreeRTOS+TCP network stack.
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_ICMP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_ARP.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_DHCP.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
#include "FreeRTOS_DNS.h"
/*
* Turns around an incoming ping request to convert it into a ping reply.
*/
#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket,
const NetworkBufferDescriptor_t * const pxNetworkBuffer );
#endif /* ipconfigREPLY_TO_INCOMING_PINGS */
/*
* Processes incoming ping replies. The application callback function
* vApplicationPingReplyHook() is called with the results.
*/
#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket );
#endif /* ipconfigSUPPORT_OUTGOING_PINGS */
#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
/**
* @brief Process an ICMP packet. Only echo requests and echo replies are recognised and handled.
*
* @param[in,out] pxICMPPacket: The IP packet that contains the ICMP message.
*
* @return eReleaseBuffer when the message buffer should be released, or eReturnEthernetFrame
* when the packet should be returned.
*/
eFrameProcessingResult_t ProcessICMPPacket( const NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
eFrameProcessingResult_t eReturn = eReleaseBuffer;
iptraceICMP_PACKET_RECEIVED();
configASSERT( pxNetworkBuffer->xDataLength >= sizeof( ICMPPacket_t ) );
if( pxNetworkBuffer->xDataLength >= sizeof( ICMPPacket_t ) )
{
/* Map the buffer onto a ICMP-Packet struct to easily access the
* fields of ICMP packet. */
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
ICMPPacket_t * pxICMPPacket = ( ( ICMPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
switch( pxICMPPacket->xICMPHeader.ucTypeOfMessage )
{
case ipICMP_ECHO_REQUEST:
#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
{
eReturn = prvProcessICMPEchoRequest( pxICMPPacket, pxNetworkBuffer );
}
#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) */
break;
case ipICMP_ECHO_REPLY:
#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
{
prvProcessICMPEchoReply( pxICMPPacket );
}
#endif /* ipconfigSUPPORT_OUTGOING_PINGS */
break;
default:
/* Only ICMP echo packets are handled. */
break;
}
}
return eReturn;
}
#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
/*-----------------------------------------------------------*/
#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
/**
* @brief Process an ICMP echo request.
*
* @param[in,out] pxICMPPacket: The IP packet that contains the ICMP message.
*/
static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket,
const NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
ICMPHeader_t * pxICMPHeader;
IPHeader_t * pxIPHeader;
pxICMPHeader = &( pxICMPPacket->xICMPHeader );
pxIPHeader = &( pxICMPPacket->xIPHeader );
/* HT:endian: changed back */
iptraceSENDING_PING_REPLY( pxIPHeader->ulSourceIPAddress );
/* The checksum can be checked here - but a ping reply should be
* returned even if the checksum is incorrect so the other end can
* tell that the ping was received - even if the ping reply contains
* invalid data. */
pxICMPHeader->ucTypeOfMessage = ( uint8_t ) ipICMP_ECHO_REPLY;
pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
/* Update the TTL field. */
pxIPHeader->ucTimeToLive = ipconfigICMP_TIME_TO_LIVE;
/* The stack doesn't support fragments, so the fragment offset field must always be zero.
* The header was never memset to zero, so set both the fragment offset and fragmentation flags in one go.
*/
#if ( ipconfigFORCE_IP_DONT_FRAGMENT != 0 )
pxIPHeader->usFragmentOffset = ipFRAGMENT_FLAGS_DONT_FRAGMENT;
#else
pxIPHeader->usFragmentOffset = 0U;
#endif
#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
{
/* calculate the IP header checksum, in case the driver won't do that. */
pxIPHeader->usHeaderChecksum = 0x00U;
pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
/* calculate the ICMP checksum for an outgoing packet. */
( void ) usGenerateProtocolChecksum( ( uint8_t * ) pxICMPPacket, pxNetworkBuffer->xDataLength, pdTRUE );
}
#else
{
/* Many EMAC peripherals will only calculate the ICMP checksum
* correctly if the field is nulled beforehand. */
pxICMPHeader->usChecksum = 0U;
}
#endif /* if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) */
return eReturnEthernetFrame;
}
#endif /* ipconfigREPLY_TO_INCOMING_PINGS == 1 */
/*-----------------------------------------------------------*/
#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
/**
* @brief Process an ICMP echo reply.
*
* @param[in] pxICMPPacket: The IP packet that contains the ICMP message.
*/
static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket )
{
ePingReplyStatus_t eStatus = eSuccess;
uint16_t usDataLength, usCount;
uint8_t * pucByte;
/* Find the total length of the IP packet. */
usDataLength = pxICMPPacket->xIPHeader.usLength;
usDataLength = FreeRTOS_ntohs( usDataLength );
/* Remove the length of the IP headers to obtain the length of the ICMP
* message itself. */
usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_IPv4_HEADER );
/* Remove the length of the ICMP header, to obtain the length of
* data contained in the ping. */
usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_ICMP_HEADER );
/* Checksum has already been checked before in prvProcessIPPacket */
/* Find the first byte of the data within the ICMP packet. */
pucByte = ( uint8_t * ) pxICMPPacket;
pucByte = &( pucByte[ sizeof( ICMPPacket_t ) ] );
/* Check each byte. */
for( usCount = 0; usCount < usDataLength; usCount++ )
{
if( *pucByte != ( uint8_t ) ipECHO_DATA_FILL_BYTE )
{
eStatus = eInvalidData;
break;
}
pucByte++;
}
/* Call back into the application to pass it the result. */
vApplicationPingReplyHook( eStatus, pxICMPPacket->xICMPHeader.usIdentifier );
}
#endif /* if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
/*-----------------------------------------------------------*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,483 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_ICMP.c
* @brief Implements the Internet Control Message Protocol for the FreeRTOS+TCP network stack.
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_IP_Timers.h"
#include "FreeRTOS_IP_Utils.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_ARP.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_DHCP.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
#include "FreeRTOS_DNS.h"
/*
* Utility functions for the light weight IP timers.
*/
static void prvIPTimerStart( IPTimer_t * pxTimer,
TickType_t xTime );
static BaseType_t prvIPTimerCheck( IPTimer_t * pxTimer );
static void prvIPTimerReload( IPTimer_t * pxTimer,
TickType_t xTime );
/*
* A timer for each of the following processes, all of which need attention on a
* regular basis
*/
/** @brief Timer to limit the maximum time a packet should be stored while
* awaiting an ARP resolution. */
static IPTimer_t xARPResolutionTimer;
/** @brief ARP timer, to check its table entries. */
static IPTimer_t xARPTimer;
#if ( ipconfigUSE_DHCP != 0 )
/** @brief DHCP timer, to send requests and to renew a reservation. */
static IPTimer_t xDHCPTimer;
#endif
#if ( ipconfigUSE_TCP != 0 )
/** @brief TCP timer, to check for timeouts, resends. */
static IPTimer_t xTCPTimer;
#endif
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
/** @brief DNS timer, to check for timeouts when looking-up a domain. */
static IPTimer_t xDNSTimer;
#endif
/**
* @brief Calculate the maximum sleep time remaining. It will go through all
* timers to see which timer will expire first. That will be the amount
* of time to block in the next call to xQueueReceive().
*
* @return The maximum sleep time or ipconfigMAX_IP_TASK_SLEEP_TIME,
* whichever is smaller.
*/
TickType_t xCalculateSleepTime( void )
{
TickType_t uxMaximumSleepTime;
/* Start with the maximum sleep time, then check this against the remaining
* time in any other timers that are active. */
uxMaximumSleepTime = ipconfigMAX_IP_TASK_SLEEP_TIME;
if( xARPTimer.bActive != pdFALSE_UNSIGNED )
{
if( xARPTimer.ulRemainingTime < uxMaximumSleepTime )
{
uxMaximumSleepTime = xARPTimer.ulRemainingTime;
}
}
#if ( ipconfigUSE_DHCP == 1 )
{
if( xDHCPTimer.bActive != pdFALSE_UNSIGNED )
{
if( xDHCPTimer.ulRemainingTime < uxMaximumSleepTime )
{
uxMaximumSleepTime = xDHCPTimer.ulRemainingTime;
}
}
}
#endif /* ipconfigUSE_DHCP */
#if ( ipconfigUSE_TCP == 1 )
{
if( xTCPTimer.bActive != pdFALSE_UNSIGNED )
{
if( xTCPTimer.ulRemainingTime < uxMaximumSleepTime )
{
uxMaximumSleepTime = xTCPTimer.ulRemainingTime;
}
}
}
#endif
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
{
if( xDNSTimer.bActive != pdFALSE_UNSIGNED )
{
if( xDNSTimer.ulRemainingTime < uxMaximumSleepTime )
{
uxMaximumSleepTime = xDNSTimer.ulRemainingTime;
}
}
}
#endif
return uxMaximumSleepTime;
}
/*-----------------------------------------------------------*/
/**
* @brief Check the network timers (ARP/DHCP/DNS/TCP) and if they are
* expired, send an event to the IP-Task.
*/
void vCheckNetworkTimers( void )
{
/* Is it time for ARP processing? */
if( prvIPTimerCheck( &xARPTimer ) != pdFALSE )
{
( void ) xSendEventToIPTask( eARPTimerEvent );
}
/* Is the ARP resolution timer expired? */
if( prvIPTimerCheck( &xARPResolutionTimer ) != pdFALSE )
{
if( pxARPWaitingNetworkBuffer != NULL )
{
/* Disable the ARP resolution timer. */
vIPSetARPResolutionTimerEnableState( pdFALSE );
/* We have waited long enough for the ARP response. Now, free the network
* buffer. */
vReleaseNetworkBufferAndDescriptor( pxARPWaitingNetworkBuffer );
/* Clear the pointer. */
pxARPWaitingNetworkBuffer = NULL;
iptraceDELAYED_ARP_TIMER_EXPIRED();
}
}
#if ( ipconfigUSE_DHCP == 1 )
{
/* Is it time for DHCP processing? */
if( prvIPTimerCheck( &xDHCPTimer ) != pdFALSE )
{
( void ) xSendDHCPEvent();
}
}
#endif /* ipconfigUSE_DHCP */
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
{
/* Is it time for DNS processing? */
if( prvIPTimerCheck( &xDNSTimer ) != pdFALSE )
{
vDNSCheckCallBack( NULL );
}
}
#endif /* ipconfigDNS_USE_CALLBACKS */
#if ( ipconfigUSE_TCP == 1 )
{
BaseType_t xWillSleep;
TickType_t xNextTime;
BaseType_t xCheckTCPSockets;
/* If the IP task has messages waiting to be processed then
* it will not sleep in any case. */
if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0U )
{
xWillSleep = pdTRUE;
}
else
{
xWillSleep = pdFALSE;
}
/* Sockets need to be checked if the TCP timer has expired. */
xCheckTCPSockets = prvIPTimerCheck( &xTCPTimer );
/* Sockets will also be checked if there are TCP messages but the
* message queue is empty (indicated by xWillSleep being true). */
if( ( xProcessedTCPMessage != pdFALSE ) && ( xWillSleep != pdFALSE ) )
{
xCheckTCPSockets = pdTRUE;
}
if( xCheckTCPSockets != pdFALSE )
{
/* Attend to the sockets, returning the period after which the
* check must be repeated. */
xNextTime = xTCPTimerCheck( xWillSleep );
prvIPTimerStart( &xTCPTimer, xNextTime );
xProcessedTCPMessage = 0;
}
}
/* See if any socket was planned to be closed. */
vSocketCloseNextTime( NULL );
/* See if any reusable socket needs to go back to 'eTCP_LISTEN' state. */
vSocketListenNextTime( NULL );
#endif /* ipconfigUSE_TCP == 1 */
}
/*-----------------------------------------------------------*/
/**
* @brief Start an IP timer. The IP-task has its own implementation of a timer
* called 'IPTimer_t', which is based on the FreeRTOS 'TimeOut_t'.
*
* @param[in] pxTimer: Pointer to the IP timer. When zero, the timer is marked
* as expired.
* @param[in] xTime: Time to be loaded into the IP timer.
*/
static void prvIPTimerStart( IPTimer_t * pxTimer,
TickType_t xTime )
{
vTaskSetTimeOutState( &pxTimer->xTimeOut );
pxTimer->ulRemainingTime = xTime;
if( xTime == ( TickType_t ) 0 )
{
pxTimer->bExpired = pdTRUE_UNSIGNED;
}
else
{
pxTimer->bExpired = pdFALSE_UNSIGNED;
}
pxTimer->bActive = pdTRUE_UNSIGNED;
}
/*-----------------------------------------------------------*/
void vIPTimerStartARPResolution( TickType_t xTime )
{
prvIPTimerStart( &( xARPResolutionTimer ), xTime );
}
/*-----------------------------------------------------------*/
/**
* @brief Sets the reload time of an IP timer and restarts it.
*
* @param[in] pxTimer: Pointer to the IP timer.
* @param[in] xTime: Time to be reloaded into the IP timer.
*/
static void prvIPTimerReload( IPTimer_t * pxTimer,
TickType_t xTime )
{
pxTimer->ulReloadTime = xTime;
prvIPTimerStart( pxTimer, xTime );
}
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_TCP == 1 )
void vTCPTimerReload( TickType_t xTime )
{
prvIPTimerReload( &xTCPTimer, xTime );
}
#endif
/*-----------------------------------------------------------*/
void vARPTimerReload( TickType_t xTime )
{
prvIPTimerReload( &xARPTimer, xTime );
}
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_DHCP == 1 )
/**
* @brief Reload the DHCP timer.
*
* @param[in] ulLeaseTime: The reload value.
*/
void vDHCPTimerReload( TickType_t xLeaseTime )
{
prvIPTimerReload( &xDHCPTimer, xLeaseTime );
}
#endif /* ipconfigUSE_DHCP */
/*-----------------------------------------------------------*/
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
/**
* @brief Reload the DNS timer.
*
* @param[in] ulCheckTime: The reload value.
*/
void vDNSTimerReload( uint32_t ulCheckTime )
{
prvIPTimerReload( &xDNSTimer, ulCheckTime );
}
#endif /* ipconfigDNS_USE_CALLBACKS != 0 */
/*-----------------------------------------------------------*/
/**
* @brief Check the IP timer to see whether an IP event should be processed or not.
*
* @param[in] pxTimer: Pointer to the IP timer.
*
* @return If the timer is expired then pdTRUE is returned. Else pdFALSE.
*/
static BaseType_t prvIPTimerCheck( IPTimer_t * pxTimer )
{
BaseType_t xReturn;
if( pxTimer->bActive == pdFALSE_UNSIGNED )
{
/* The timer is not enabled. */
xReturn = pdFALSE;
}
else
{
/* The timer might have set the bExpired flag already, if not, check the
* value of xTimeOut against ulRemainingTime. */
if( pxTimer->bExpired == pdFALSE_UNSIGNED )
{
if( xTaskCheckForTimeOut( &( pxTimer->xTimeOut ), &( pxTimer->ulRemainingTime ) ) != pdFALSE )
{
pxTimer->bExpired = pdTRUE_UNSIGNED;
}
}
if( pxTimer->bExpired != pdFALSE_UNSIGNED )
{
prvIPTimerStart( pxTimer, pxTimer->ulReloadTime );
xReturn = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_TCP == 1 )
/**
* @brief Enable/disable the TCP timer.
*
* @param[in] xExpiredState: pdTRUE - set as expired; pdFALSE - set as non-expired.
*/
void vIPSetTCPTimerExpiredState( BaseType_t xExpiredState )
{
xTCPTimer.bActive = pdTRUE_UNSIGNED;
if( xExpiredState != pdFALSE )
{
xTCPTimer.bExpired = pdTRUE_UNSIGNED;
}
else
{
xTCPTimer.bExpired = pdFALSE_UNSIGNED;
}
}
/*-----------------------------------------------------------*/
#endif /* if ( ipconfigUSE_TCP == 1 ) */
/**
* @brief Enable/disable the ARP timer.
*
* @param[in] xEnableState: pdTRUE - enable timer; pdFALSE - disable timer.
*/
void vIPSetARPTimerEnableState( BaseType_t xEnableState )
{
if( xEnableState != pdFALSE )
{
xARPTimer.bActive = pdTRUE_UNSIGNED;
}
else
{
xARPTimer.bActive = pdFALSE_UNSIGNED;
}
}
/*-----------------------------------------------------------*/
/**
* @brief Enable or disable the ARP resolution timer.
*
* @param[in] xEnableState: pdTRUE if the timer must be enabled, pdFALSE otherwise.
*/
void vIPSetARPResolutionTimerEnableState( BaseType_t xEnableState )
{
if( xEnableState != pdFALSE )
{
xARPResolutionTimer.bActive = pdTRUE_UNSIGNED;
}
else
{
xARPResolutionTimer.bActive = pdFALSE_UNSIGNED;
}
}
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_DHCP == 1 )
/**
* @brief Enable/disable the DHCP timer.
*
* @param[in] xEnableState: pdTRUE - enable timer; pdFALSE - disable timer.
*/
void vIPSetDHCPTimerEnableState( BaseType_t xEnableState )
{
if( xEnableState != pdFALSE )
{
xDHCPTimer.bActive = pdTRUE_UNSIGNED;
}
else
{
xDHCPTimer.bActive = pdFALSE_UNSIGNED;
}
}
#endif /* ipconfigUSE_DHCP */
/*-----------------------------------------------------------*/
#if ( ipconfigDNS_USE_CALLBACKS == 1 )
/**
* @brief Enable/disable the DNS timer.
*
* @param[in] xEnableState: pdTRUE - enable timer; pdFALSE - disable timer.
*/
void vIPSetDNSTimerEnableState( BaseType_t xEnableState )
{
if( xEnableState != 0 )
{
xDNSTimer.bActive = pdTRUE_UNSIGNED;
}
else
{
xDNSTimer.bActive = pdFALSE_UNSIGNED;
}
}
#endif /* ipconfigDNS_USE_CALLBACKS == 1 */
/*-----------------------------------------------------------*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,436 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_Stream_Buffer.c
* @brief Provides the API for managing/creating the stream buffers in the FreeRTOS+TCP network stack.
*/
/* Standard includes. */
#include <stdint.h>
/* 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_Sockets.h"
#include "FreeRTOS_IP_Private.h"
/**
* @brief Get the space between lower and upper value provided to the function.
* @param[in] pxBuffer: The circular stream buffer.
* @param[in] uxLower: The lower value.
* @param[in] uxUpper: The upper value.
* @return The space between uxLower and uxUpper, which equals to the distance
* minus 1.
*/
size_t uxStreamBufferSpace( const StreamBuffer_t * pxBuffer,
const size_t uxLower,
const size_t uxUpper )
{
size_t uxCount;
uxCount = pxBuffer->LENGTH + uxUpper - uxLower - 1U;
if( uxCount >= pxBuffer->LENGTH )
{
uxCount -= pxBuffer->LENGTH;
}
return uxCount;
}
/**
* @brief Get the distance between lower and upper value provided to the function.
* @param[in] pxBuffer: The circular stream buffer.
* @param[in] uxLower: The lower value.
* @param[in] uxUpper: The upper value.
* @return The distance between uxLower and uxUpper.
*/
size_t uxStreamBufferDistance( const StreamBuffer_t * pxBuffer,
const size_t uxLower,
const size_t uxUpper )
{
size_t uxCount;
uxCount = pxBuffer->LENGTH + uxUpper - uxLower;
if( uxCount >= pxBuffer->LENGTH )
{
uxCount -= pxBuffer->LENGTH;
}
return uxCount;
}
/**
* @brief Get the number of items which can be added to the buffer at
* the head before reaching the tail.
* @param[in] pxBuffer: The circular stream buffer.
* @return The number of items which can still be added to uxHead
* before hitting on uxTail
*/
size_t uxStreamBufferGetSpace( const StreamBuffer_t * pxBuffer )
{
size_t uxHead = pxBuffer->uxHead;
size_t uxTail = pxBuffer->uxTail;
return uxStreamBufferSpace( pxBuffer, uxHead, uxTail );
}
/*-----------------------------------------------------------*/
/**
* @brief Get the distance between the pointer in free space and the tail.
* @param[in] pxBuffer: The circular stream buffer.
* @return Distance between uxFront and uxTail or the number of items
* which can still be added to uxFront, before hitting on uxTail.
*/
size_t uxStreamBufferFrontSpace( const StreamBuffer_t * pxBuffer )
{
size_t uxFront = pxBuffer->uxFront;
size_t uxTail = pxBuffer->uxTail;
return uxStreamBufferSpace( pxBuffer, uxFront, uxTail );
}
/*-----------------------------------------------------------*/
/**
* @brief Get the number of items which can be read from the tail before
* reaching the head.
* @param[in] pxBuffer: The circular stream buffer.
* @return The number of items which can be read from the tail before
* reaching the head.
*/
size_t uxStreamBufferGetSize( const StreamBuffer_t * pxBuffer )
{
size_t uxHead = pxBuffer->uxHead;
size_t uxTail = pxBuffer->uxTail;
return uxStreamBufferDistance( pxBuffer, uxTail, uxHead );
}
/*-----------------------------------------------------------*/
/**
* @brief Get the space between the mid pointer and the head in the stream
* buffer.
* @param[in] pxBuffer: The circular stream buffer.
* @return The space between the mid pointer and the head.
*/
size_t uxStreamBufferMidSpace( const StreamBuffer_t * pxBuffer )
{
size_t uxHead = pxBuffer->uxHead;
size_t uxMid = pxBuffer->uxMid;
return uxStreamBufferDistance( pxBuffer, uxMid, uxHead );
}
/*-----------------------------------------------------------*/
/**
* @brief Move Clear the stream buffer.
* @param[in] pxBuffer: The circular stream buffer.
*/
void vStreamBufferClear( StreamBuffer_t * pxBuffer )
{
/* Make the circular buffer empty */
pxBuffer->uxHead = 0U;
pxBuffer->uxTail = 0U;
pxBuffer->uxFront = 0U;
pxBuffer->uxMid = 0U;
}
/*-----------------------------------------------------------*/
/**
* @brief Move the mid pointer forward by given byte count
* @param[in] pxBuffer: The circular stream buffer.
* @param[in] uxCount: The byte count by which the mid pointer is to be moved.
*/
void vStreamBufferMoveMid( StreamBuffer_t * pxBuffer,
size_t uxCount )
{
/* Increment uxMid, but no further than uxHead */
size_t uxSize = uxStreamBufferMidSpace( pxBuffer );
size_t uxMid = pxBuffer->uxMid;
size_t uxMoveCount = uxCount;
if( uxMoveCount > uxSize )
{
uxMoveCount = uxSize;
}
uxMid += uxMoveCount;
if( uxMid >= pxBuffer->LENGTH )
{
uxMid -= pxBuffer->LENGTH;
}
pxBuffer->uxMid = uxMid;
}
/*-----------------------------------------------------------*/
/**
* @brief Check whether the value in left is less than or equal to the
* value in right from the perspective of the circular stream
* buffer.
* @param[in] pxBuffer: The circular stream buffer.
* @param[in] uxLeft: The left pointer in the stream buffer.
* @param[in] uxRight: The right value pointer in the stream buffer.
* @return pdTRUE if uxLeft <= uxRight, else pdFALSE.
*/
BaseType_t xStreamBufferLessThenEqual( const StreamBuffer_t * pxBuffer,
const size_t uxLeft,
const size_t uxRight )
{
BaseType_t xReturn = pdFALSE;
size_t uxTail = pxBuffer->uxTail;
/* Returns true if ( uxLeft <= uxRight ) */
if( ( uxLeft - uxTail ) <= ( uxRight - uxTail ) )
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
/**
* @brief Get the pointer to data and the amount of data which can be read in one go.
*
* @param[in] pxBuffer: The circular stream buffer.
* @param[out] ppucData: Pointer to the data pointer which will point to the
* data which can be read.
*
* @return The number of bytes which can be read in one go (which might be less than
* actual number of available bytes since this is a circular buffer and tail
* can loop back to the start of the buffer).
*/
size_t uxStreamBufferGetPtr( StreamBuffer_t * pxBuffer,
uint8_t ** ppucData )
{
size_t uxNextTail = pxBuffer->uxTail;
size_t uxSize = uxStreamBufferGetSize( pxBuffer );
*ppucData = pxBuffer->ucArray + uxNextTail;
return FreeRTOS_min_size_t( uxSize, pxBuffer->LENGTH - uxNextTail );
}
/*-----------------------------------------------------------*/
/**
* @brief Adds data to a stream buffer.
*
* @param[in,out] pxBuffer: The buffer to which the bytes will be added.
* @param[in] uxOffset: If uxOffset > 0, data will be written at an offset from uxHead
* while uxHead will not be moved yet.
* @param[in,out] pucData: A pointer to the data to be added. If 'pucData' equals NULL,
* the function is called to advance the 'Head' only.
* @param[in] uxByteCount: The number of bytes to add.
*
* @return The number of bytes added to the buffer.
*/
size_t uxStreamBufferAdd( StreamBuffer_t * pxBuffer,
size_t uxOffset,
const uint8_t * pucData,
size_t uxByteCount )
{
size_t uxSpace, uxNextHead, uxFirst;
size_t uxCount = uxByteCount;
uxSpace = uxStreamBufferGetSpace( pxBuffer );
/* If uxOffset > 0, items can be placed in front of uxHead */
if( uxSpace > uxOffset )
{
uxSpace -= uxOffset;
}
else
{
uxSpace = 0U;
}
/* The number of bytes that can be written is the minimum of the number of
* bytes requested and the number available. */
uxCount = FreeRTOS_min_size_t( uxSpace, uxCount );
if( uxCount != 0U )
{
uxNextHead = pxBuffer->uxHead;
if( uxOffset != 0U )
{
/* ( uxOffset > 0 ) means: write in front if the uxHead marker */
uxNextHead += uxOffset;
if( uxNextHead >= pxBuffer->LENGTH )
{
uxNextHead -= pxBuffer->LENGTH;
}
}
if( pucData != NULL )
{
/* Calculate the number of bytes that can be added in the first
* write - which may be less than the total number of bytes that need
* to be added if the buffer will wrap back to the beginning. */
uxFirst = FreeRTOS_min_size_t( pxBuffer->LENGTH - uxNextHead, uxCount );
/* Write as many bytes as can be written in the first write. */
( void ) memcpy( &( pxBuffer->ucArray[ uxNextHead ] ), pucData, uxFirst );
/* If the number of bytes written was less than the number that
* could be written in the first write... */
if( uxCount > uxFirst )
{
/* ...then write the remaining bytes to the start of the
* buffer. */
( void ) memcpy( pxBuffer->ucArray, &( pucData[ uxFirst ] ), uxCount - uxFirst );
}
}
/* The below update to the stream buffer members must happen
* atomically. */
vTaskSuspendAll();
{
if( uxOffset == 0U )
{
/* ( uxOffset == 0 ) means: write at uxHead position */
uxNextHead += uxCount;
if( uxNextHead >= pxBuffer->LENGTH )
{
uxNextHead -= pxBuffer->LENGTH;
}
pxBuffer->uxHead = uxNextHead;
}
if( xStreamBufferLessThenEqual( pxBuffer, pxBuffer->uxFront, uxNextHead ) != pdFALSE )
{
/* Advance the front pointer */
pxBuffer->uxFront = uxNextHead;
}
}
( void ) xTaskResumeAll();
}
return uxCount;
}
/*-----------------------------------------------------------*/
/**
* @brief Read bytes from stream buffer.
*
* @param[in] pxBuffer: The buffer from which the bytes will be read.
* @param[in] uxOffset: can be used to read data located at a certain offset from 'lTail'.
* @param[in,out] pucData: If 'pucData' equals NULL, the function is called to advance 'lTail' only.
* @param[in] uxMaxCount: The number of bytes to read.
* @param[in] xPeek: if 'xPeek' is pdTRUE, or if 'uxOffset' is non-zero, the 'lTail' pointer will
* not be advanced.
*
* @return The count of the bytes read.
*/
size_t uxStreamBufferGet( StreamBuffer_t * pxBuffer,
size_t uxOffset,
uint8_t * pucData,
size_t uxMaxCount,
BaseType_t xPeek )
{
size_t uxSize, uxCount, uxFirst, uxNextTail;
/* How much data is available? */
uxSize = uxStreamBufferGetSize( pxBuffer );
if( uxSize > uxOffset )
{
uxSize -= uxOffset;
}
else
{
uxSize = 0U;
}
/* Use the minimum of the wanted bytes and the available bytes. */
uxCount = FreeRTOS_min_size_t( uxSize, uxMaxCount );
if( uxCount > 0U )
{
uxNextTail = pxBuffer->uxTail;
if( uxOffset != 0U )
{
uxNextTail += uxOffset;
if( uxNextTail >= pxBuffer->LENGTH )
{
uxNextTail -= pxBuffer->LENGTH;
}
}
if( pucData != NULL )
{
/* Calculate the number of bytes that can be read - which may be
* less than the number wanted if the data wraps around to the start of
* the buffer. */
uxFirst = FreeRTOS_min_size_t( pxBuffer->LENGTH - uxNextTail, uxCount );
/* Obtain the number of bytes it is possible to obtain in the first
* read. */
( void ) memcpy( pucData, &( pxBuffer->ucArray[ uxNextTail ] ), uxFirst );
/* If the total number of wanted bytes is greater than the number
* that could be read in the first read... */
if( uxCount > uxFirst )
{
/*...then read the remaining bytes from the start of the buffer. */
( void ) memcpy( &( pucData[ uxFirst ] ), pxBuffer->ucArray, uxCount - uxFirst );
}
}
if( ( xPeek == pdFALSE ) && ( uxOffset == 0U ) )
{
/* Move the tail pointer to effectively remove the data read from
* the buffer. */
uxNextTail += uxCount;
if( uxNextTail >= pxBuffer->LENGTH )
{
uxNextTail -= pxBuffer->LENGTH;
}
pxBuffer->uxTail = uxNextTail;
}
}
return uxCount;
}

View File

@ -0,0 +1,925 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_TCP_IP.c
* @brief Module which handles the TCP connections for FreeRTOS+TCP.
* It depends on FreeRTOS_TCP_WIN.c, which handles the TCP windowing
* schemes.
*
* Endianness: in this module all ports and IP addresses are stored in
* host byte-order, except fields in the IP-packets
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_DHCP.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
#include "FreeRTOS_ARP.h"
#include "FreeRTOS_TCP_Reception.h"
#include "FreeRTOS_TCP_Transmission.h"
#include "FreeRTOS_TCP_State_Handling.h"
#include "FreeRTOS_TCP_Utils.h"
/* Just make sure the contents doesn't get compiled if TCP is not enabled. */
#if ipconfigUSE_TCP == 1
/** @brief When closing a socket an event is posted to the Network Event Queue.
* If the queue is full, then the event is not posted and the socket
* can be orphaned. To prevent this, the below variable is used to keep
* track of any socket which needs to be closed. This variable can be
* accessed by the IP task only. Thus, preventing any race condition.
*/
/* MISRA Ref 8.9.1 [File scoped variables] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
/* coverity[misra_c_2012_rule_8_9_violation] */
static FreeRTOS_Socket_t * xSocketToClose = NULL;
/** @brief When a connection is coming in on a reusable socket, and the
* SYN phase times out, the socket must be put back into eTCP_LISTEN
* mode, so it can accept a new connection again.
* This variable can be accessed by the IP task only. Thus, preventing any
* race condition.
*/
/* MISRA Ref 8.9.1 [File scoped variables] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
/* coverity[misra_c_2012_rule_8_9_violation] */
static FreeRTOS_Socket_t * xSocketToListen = NULL;
/*
* For anti-hang protection and TCP keep-alive messages. Called in two places:
* after receiving a packet and after a state change. The socket's alive timer
* may be reset.
*/
static void prvTCPTouchSocket( FreeRTOS_Socket_t * pxSocket );
/*
* Calculate when this socket needs to be checked to do (re-)transmissions.
*/
static TickType_t prvTCPNextTimeout( FreeRTOS_Socket_t * pxSocket );
#if ( ipconfigHAS_DEBUG_PRINTF != 0 )
/*
* For logging and debugging: make a string showing the TCP flags.
*/
const char * prvTCPFlagMeaning( UBaseType_t xFlags );
#endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
/*-----------------------------------------------------------*/
/** @brief Close the socket another time.
*
* @param[in] pxSocket: The socket to be checked.
*/
/* coverity[single_use] */
void vSocketCloseNextTime( FreeRTOS_Socket_t * pxSocket )
{
if( ( xSocketToClose != NULL ) && ( xSocketToClose != pxSocket ) )
{
( void ) vSocketClose( xSocketToClose );
}
xSocketToClose = pxSocket;
}
/*-----------------------------------------------------------*/
/** @brief Postpone a call to FreeRTOS_listen() to avoid recursive calls.
*
* @param[in] pxSocket: The socket to be checked.
*/
/* coverity[single_use] */
void vSocketListenNextTime( FreeRTOS_Socket_t * pxSocket )
{
if( ( xSocketToListen != NULL ) && ( xSocketToListen != pxSocket ) )
{
( void ) FreeRTOS_listen( ( Socket_t ) xSocketToListen, xSocketToListen->u.xTCP.usBacklog );
}
xSocketToListen = pxSocket;
}
/*-----------------------------------------------------------*/
/**
* @brief As soon as a TCP socket timer expires, this function will be called
* (from xTCPTimerCheck). It can send a delayed ACK or new data.
*
* @param[in] pxSocket: socket to be checked.
*
* @return 0 on success, a negative error code on failure. A negative value will be
* returned in case the hang-protection has put the socket in a wait-close state.
*
* @note Sequence of calling (normally) :
* IP-Task:
* xTCPTimerCheck() // Check all sockets ( declared in FreeRTOS_Sockets.c )
* xTCPSocketCheck() // Either send a delayed ACK or call prvTCPSendPacket()
* prvTCPSendPacket() // Either send a SYN or call prvTCPSendRepeated ( regular messages )
* prvTCPSendRepeated() // Send at most 8 messages on a row
* prvTCPReturnPacket() // Prepare for returning
* xNetworkInterfaceOutput() // Sends data to the NIC ( declared in portable/NetworkInterface/xxx )
*/
BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t * pxSocket )
{
BaseType_t xResult = 0;
BaseType_t xReady = pdFALSE;
if( ( pxSocket->u.xTCP.eTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.txStream != NULL ) )
{
/* The API FreeRTOS_send() might have added data to the TX stream. Add
* this data to the windowing system so it can be transmitted. */
prvTCPAddTxData( pxSocket );
}
#if ( ipconfigUSE_TCP_WIN == 1 )
{
if( pxSocket->u.xTCP.pxAckMessage != NULL )
{
/* The first task of this regular socket check is to send-out delayed
* ACK's. */
if( pxSocket->u.xTCP.bits.bUserShutdown == pdFALSE_UNSIGNED )
{
/* Earlier data was received but not yet acknowledged. This
* function is called when the TCP timer for the socket expires, the
* ACK may be sent now. */
if( pxSocket->u.xTCP.eTCPState != eCLOSED )
{
if( ( xTCPWindowLoggingLevel > 1 ) && ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) )
{
FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %u SEQ %u (len %u)\n",
pxSocket->usLocalPort,
pxSocket->u.xTCP.usRemotePort,
( unsigned ) ( pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ),
( unsigned ) ( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ),
( unsigned ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) );
}
prvTCPReturnPacket( pxSocket, pxSocket->u.xTCP.pxAckMessage, ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER, ipconfigZERO_COPY_TX_DRIVER );
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
/* The ownership has been passed to the SEND routine,
* clear the pointer to it. */
pxSocket->u.xTCP.pxAckMessage = NULL;
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
}
if( prvTCPNextTimeout( pxSocket ) > 1U )
{
/* Tell the code below that this function is ready. */
xReady = pdTRUE;
}
}
else
{
/* The user wants to perform an active shutdown(), skip sending
* the delayed ACK. The function prvTCPSendPacket() will send the
* FIN along with the ACK's. */
}
if( pxSocket->u.xTCP.pxAckMessage != NULL )
{
vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
pxSocket->u.xTCP.pxAckMessage = NULL;
}
}
}
#endif /* ipconfigUSE_TCP_WIN */
if( xReady == pdFALSE )
{
/* The second task of this regular socket check is sending out data. */
if( ( pxSocket->u.xTCP.eTCPState >= eESTABLISHED ) ||
( pxSocket->u.xTCP.eTCPState == eCONNECT_SYN ) )
{
( void ) prvTCPSendPacket( pxSocket );
}
/* Set the time-out for the next wakeup for this socket. */
( void ) prvTCPNextTimeout( pxSocket );
#if ( ipconfigTCP_HANG_PROTECTION == 1 )
{
/* In all (non-connected) states in which keep-alive messages can not be sent
* the anti-hang protocol will close sockets that are 'hanging'. */
xResult = prvTCPStatusAgeCheck( pxSocket );
}
#endif
}
return xResult;
}
/*-----------------------------------------------------------*/
/**
* @brief 'Touch' the socket to keep it alive/updated.
*
* @param[in] pxSocket: The socket to be updated.
*
* @note This is used for anti-hanging protection and TCP keep-alive messages.
* Called in two places: after receiving a packet and after a state change.
* The socket's alive timer may be reset.
*/
static void prvTCPTouchSocket( FreeRTOS_Socket_t * pxSocket )
{
#if ( ipconfigTCP_HANG_PROTECTION == 1 )
{
pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount();
}
#endif
#if ( ipconfigTCP_KEEP_ALIVE == 1 )
{
pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED;
pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
pxSocket->u.xTCP.ucKeepRepCount = 0U;
pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();
}
#endif
( void ) pxSocket;
}
/*-----------------------------------------------------------*/
/**
* @brief Changing to a new state. Centralised here to do specific actions such as
* resetting the alive timer, calling the user's OnConnect handler to notify
* that a socket has got (dis)connected, and setting bit to unblock a call to
* FreeRTOS_select().
*
* @param[in] pxSocket: The socket whose state we are trying to change.
* @param[in] eTCPState: The state to which we want to change to.
*/
void vTCPStateChange( FreeRTOS_Socket_t * pxSocket,
enum eTCP_STATE eTCPState )
{
FreeRTOS_Socket_t * xParent = pxSocket;
BaseType_t bBefore = tcpNOW_CONNECTED( ( BaseType_t ) pxSocket->u.xTCP.eTCPState ); /* Was it connected ? */
BaseType_t bAfter = tcpNOW_CONNECTED( ( BaseType_t ) eTCPState ); /* Is it connected now ? */
BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.eTCPState;
#if ( ipconfigUSE_CALLBACKS == 1 )
FreeRTOS_Socket_t * xConnected = NULL;
#endif
if( ( ( xPreviousState == eCONNECT_SYN ) ||
( xPreviousState == eSYN_FIRST ) ||
( xPreviousState == eSYN_RECEIVED ) ) &&
( eTCPState == eCLOSE_WAIT ) )
{
/* A socket was in the connecting phase but something
* went wrong and it should be closed. */
FreeRTOS_debug_printf( ( "Move from %s to %s\n",
FreeRTOS_GetTCPStateName( xPreviousState ),
FreeRTOS_GetTCPStateName( eTCPState ) ) );
/* Set the flag to show that it was connected before and that the
* status has changed now. This will cause the control flow to go
* in the below if condition.*/
bBefore = pdTRUE;
}
/* Has the connected status changed? */
if( bBefore != bAfter )
{
/* if bPassQueued is true, this socket is an orphan until it gets connected. */
if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
{
/* Find it's parent if the reuse bit is not set. */
if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
{
xParent = pxSocket->u.xTCP.pxPeerSocket;
configASSERT( xParent != NULL );
}
}
/* Is the socket connected now ? */
if( bAfter != pdFALSE )
{
/* if bPassQueued is true, this socket is an orphan until it gets connected. */
if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
{
if( xParent != NULL )
{
/* The child socket has got connected. See if the parent
* ( the listening socket ) should be signalled, or if a
* call-back must be made, in which case 'xConnected' will
* be set to the parent socket. */
if( xParent->u.xTCP.pxPeerSocket == NULL )
{
xParent->u.xTCP.pxPeerSocket = pxSocket;
}
xParent->xEventBits |= ( EventBits_t ) eSOCKET_ACCEPT;
#if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
{
/* Library support FreeRTOS_select(). Receiving a new
* connection is being translated as a READ event. */
if( ( xParent->xSelectBits & ( ( EventBits_t ) eSELECT_READ ) ) != 0U )
{
xParent->xEventBits |= ( ( EventBits_t ) eSELECT_READ ) << SOCKET_EVENT_BIT_COUNT;
}
}
#endif
#if ( ipconfigUSE_CALLBACKS == 1 )
{
if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) ) &&
( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) )
{
/* The listening socket does not become connected itself, in stead
* a child socket is created.
* Postpone a call the OnConnect event until the end of this function. */
xConnected = xParent;
}
}
#endif
}
/* Don't need to access the parent socket anymore, so the
* reference 'pxPeerSocket' may be cleared. */
pxSocket->u.xTCP.pxPeerSocket = NULL;
pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED;
/* When true, this socket may be returned in a call to accept(). */
pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
}
else
{
/* An active connect() has succeeded. In this case there is no
* ( listening ) parent socket. Signal the now connected socket. */
pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_CONNECT;
#if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
{
if( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_WRITE ) ) != 0U )
{
pxSocket->xEventBits |= ( ( EventBits_t ) eSELECT_WRITE ) << SOCKET_EVENT_BIT_COUNT;
}
}
#endif
}
}
else /* bAfter == pdFALSE, connection is closed. */
{
/* Notify/wake-up the socket-owner by setting the event bits. */
xParent->xEventBits |= ( EventBits_t ) eSOCKET_CLOSED;
#if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
{
if( ( xParent->xSelectBits & ( EventBits_t ) eSELECT_EXCEPT ) != 0U )
{
xParent->xEventBits |= ( ( EventBits_t ) eSELECT_EXCEPT ) << SOCKET_EVENT_BIT_COUNT;
}
}
#endif
}
#if ( ipconfigUSE_CALLBACKS == 1 )
{
if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) ) && ( xConnected == NULL ) )
{
/* The 'connected' state has changed, call the user handler. */
xConnected = pxSocket;
}
}
#endif /* ipconfigUSE_CALLBACKS */
if( prvTCPSocketIsActive( pxSocket->u.xTCP.eTCPState ) == 0 )
{
/* Now the socket isn't in an active state anymore so it
* won't need further attention of the IP-task.
* Setting time-out to zero means that the socket won't get checked during
* timer events. */
pxSocket->u.xTCP.usTimeout = 0U;
}
}
if( ( eTCPState == eCLOSED ) ||
( eTCPState == eCLOSE_WAIT ) )
{
/* Socket goes to status eCLOSED because of a RST.
* When nobody owns the socket yet, delete it. */
if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||
( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
{
FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) );
if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
{
configASSERT( xIsCallingFromIPTask() != pdFALSE );
vSocketCloseNextTime( pxSocket );
}
}
}
/* Fill in the new state. */
pxSocket->u.xTCP.eTCPState = eTCPState;
if( ( eTCPState == eCLOSE_WAIT ) && ( pxSocket->u.xTCP.bits.bReuseSocket == pdTRUE_UNSIGNED ) )
{
switch( xPreviousState )
{
case eSYN_FIRST: /* 3 (server) Just created, must ACK the SYN request */
case eSYN_RECEIVED: /* 4 (server) waiting for a confirming connection request */
FreeRTOS_debug_printf( ( "Restoring a reuse socket port %u\n", pxSocket->usLocalPort ) );
/* Go back into listening mode. Set the TCP status to 'eCLOSED',
* otherwise FreeRTOS_listen() will refuse the action. */
pxSocket->u.xTCP.eTCPState = eCLOSED;
/* vSocketListenNextTime() makes sure that FreeRTOS_listen() will be called
* before the IP-task handles any new message. */
vSocketListenNextTime( pxSocket );
break;
default:
/* Nothing to do. */
break;
}
}
/* Touch the alive timers because moving to another state. */
prvTCPTouchSocket( pxSocket );
#if ( ipconfigHAS_DEBUG_PRINTF == 1 )
{
if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) ) )
{
FreeRTOS_debug_printf( ( "Socket %u -> %xip:%u State %s->%s\n",
pxSocket->usLocalPort,
( unsigned ) pxSocket->u.xTCP.ulRemoteIP,
pxSocket->u.xTCP.usRemotePort,
FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ),
FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) );
}
}
#endif /* ipconfigHAS_DEBUG_PRINTF */
#if ( ipconfigUSE_CALLBACKS == 1 )
{
if( xConnected != NULL )
{
/* The 'connected' state has changed, call the OnConnect handler of the parent. */
xConnected->u.xTCP.pxHandleConnected( ( Socket_t ) xConnected, bAfter );
}
}
#endif
if( xParent != NULL )
{
vSocketWakeUpUser( xParent );
}
}
/*-----------------------------------------------------------*/
/**
* @brief Calculate after how much time this socket needs to be checked again.
*
* @param[in] pxSocket: The socket to be checked.
*
* @return The number of clock ticks before the timer expires.
*/
static TickType_t prvTCPNextTimeout( FreeRTOS_Socket_t * pxSocket )
{
TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
if( pxSocket->u.xTCP.eTCPState == eCONNECT_SYN )
{
/* The socket is actively connecting to a peer. */
if( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED )
{
/* Ethernet address has been found, use progressive timeout for
* active connect(). */
if( pxSocket->u.xTCP.ucRepCount < 3U )
{
ulDelayMs = ( ( ( uint32_t ) 3000U ) << ( pxSocket->u.xTCP.ucRepCount - 1U ) );
}
else
{
ulDelayMs = 11000U;
}
}
else
{
/* Still in the ARP phase: check every half second. */
ulDelayMs = 500U;
}
FreeRTOS_debug_printf( ( "Connect[%xip:%u]: next timeout %u: %u ms\n",
( unsigned ) pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort,
pxSocket->u.xTCP.ucRepCount, ( unsigned ) ulDelayMs ) );
pxSocket->u.xTCP.usTimeout = ( uint16_t ) ipMS_TO_MIN_TICKS( ulDelayMs );
}
else if( pxSocket->u.xTCP.usTimeout == 0U )
{
/* Let the sliding window mechanism decide what time-out is appropriate. */
BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs );
if( ulDelayMs == 0U )
{
if( xResult != ( BaseType_t ) 0 )
{
ulDelayMs = 1U;
}
else
{
ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
}
}
else
{
/* ulDelayMs contains the time to wait before a re-transmission. */
}
pxSocket->u.xTCP.usTimeout = ( uint16_t ) ipMS_TO_MIN_TICKS( ulDelayMs ); /* LCOV_EXCL_BR_LINE ulDelayMs will not be smaller than 1 */
}
else
{
/* field '.usTimeout' has already been set (by the
* keep-alive/delayed-ACK mechanism). */
}
/* Return the number of clock ticks before the timer expires. */
return ( TickType_t ) pxSocket->u.xTCP.usTimeout;
}
/*-----------------------------------------------------------*/
/**
* @brief Process the received TCP packet.
*
* @param[in] pxDescriptor: The descriptor in which the TCP packet is held.
*
* @return If the processing of the packet was successful, then pdPASS is returned
* or else pdFAIL.
*
* @note FreeRTOS_TCP_IP has only 2 public functions, this is the second one:
* xProcessReceivedTCPPacket()
* prvTCPHandleState()
* prvTCPPrepareSend()
* prvTCPReturnPacket()
* xNetworkInterfaceOutput() // Sends data to the NIC
* prvTCPSendRepeated()
* prvTCPReturnPacket() // Prepare for returning
* xNetworkInterfaceOutput() // Sends data to the NIC
*/
BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t * pxDescriptor )
{
/* Function might modify the parameter. */
NetworkBufferDescriptor_t * pxNetworkBuffer = pxDescriptor;
configASSERT( pxNetworkBuffer != NULL );
configASSERT( pxNetworkBuffer->pucEthernetBuffer != NULL );
/* Map the buffer onto a ProtocolHeaders_t struct for easy access to the fields. */
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
const ProtocolHeaders_t * pxProtocolHeaders = ( ( const ProtocolHeaders_t * )
&( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer ) ] ) );
FreeRTOS_Socket_t * pxSocket;
uint16_t ucTCPFlags = pxProtocolHeaders->xTCPHeader.ucTCPFlags;
uint32_t ulLocalIP;
uint16_t usLocalPort = FreeRTOS_htons( pxProtocolHeaders->xTCPHeader.usDestinationPort );
uint16_t usRemotePort = FreeRTOS_htons( pxProtocolHeaders->xTCPHeader.usSourcePort );
uint32_t ulRemoteIP;
uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxProtocolHeaders->xTCPHeader.ulSequenceNumber );
uint32_t ulAckNumber = FreeRTOS_ntohl( pxProtocolHeaders->xTCPHeader.ulAckNr );
BaseType_t xResult = pdPASS;
const IPHeader_t * pxIPHeader;
/* Check for a minimum packet size. */
if( pxNetworkBuffer->xDataLength < ( ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer ) + ipSIZE_OF_TCP_HEADER ) )
{
xResult = pdFAIL;
}
else
{
/* Map the ethernet buffer onto the IPHeader_t struct for easy access to the fields. */
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
pxIPHeader = ( ( const IPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) );
ulLocalIP = FreeRTOS_htonl( pxIPHeader->ulDestinationIPAddress );
ulRemoteIP = FreeRTOS_htonl( pxIPHeader->ulSourceIPAddress );
/* Find the destination socket, and if not found: return a socket listening to
* the destination PORT. */
pxSocket = ( FreeRTOS_Socket_t * ) pxTCPSocketLookup( ulLocalIP, usLocalPort, ulRemoteIP, usRemotePort );
if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( pxSocket->u.xTCP.eTCPState ) == pdFALSE ) )
{
/* A TCP messages is received but either there is no socket with the
* given port number or the there is a socket, but it is in one of these
* non-active states: eCLOSED, eCLOSE_WAIT, eFIN_WAIT_2, eCLOSING, or
* eTIME_WAIT. */
FreeRTOS_debug_printf( ( "TCP: No active socket on port %d (%xip:%d)\n", usLocalPort, ( unsigned ) ulRemoteIP, usRemotePort ) );
/* Send a RST to all packets that can not be handled. As a result
* the other party will get a ECONN error. There are two exceptions:
* 1) A packet that already has the RST flag set.
* 2) A packet that only has the ACK flag set.
* A packet with only the ACK flag set might be the last ACK in
* a three-way hand-shake that closes a connection. */
if( ( ( ucTCPFlags & tcpTCP_FLAG_CTRL ) != tcpTCP_FLAG_ACK ) &&
( ( ucTCPFlags & tcpTCP_FLAG_RST ) == 0U ) )
{
( void ) prvTCPSendReset( pxNetworkBuffer );
}
/* The packet can't be handled. */
xResult = pdFAIL;
}
else
{
pxSocket->u.xTCP.ucRepCount = 0U;
if( pxSocket->u.xTCP.eTCPState == eTCP_LISTEN )
{
/* The matching socket is in a listening state. Test if the peer
* has set the SYN flag. */
if( ( ucTCPFlags & tcpTCP_FLAG_CTRL ) != tcpTCP_FLAG_SYN )
{
/* What happens: maybe after a reboot, a client doesn't know the
* connection had gone. Send a RST in order to get a new connect
* request. */
#if ( ipconfigHAS_DEBUG_PRINTF == 1 )
{
FreeRTOS_debug_printf( ( "TCP: Server can't handle flags: %s from %xip:%u to port %u\n",
prvTCPFlagMeaning( ( UBaseType_t ) ucTCPFlags ), ( unsigned ) ulRemoteIP, usRemotePort, usLocalPort ) );
}
#endif /* ipconfigHAS_DEBUG_PRINTF */
if( ( ucTCPFlags & tcpTCP_FLAG_RST ) == 0U )
{
( void ) prvTCPSendReset( pxNetworkBuffer );
}
xResult = pdFAIL;
}
else
{
/* prvHandleListen() will either return a newly created socket
* (if bReuseSocket is false), otherwise it returns the current
* socket which will later get connected. */
pxSocket = prvHandleListen( pxSocket, pxNetworkBuffer );
if( pxSocket == NULL )
{
xResult = pdFAIL;
}
}
} /* if( pxSocket->u.xTCP.eTCPState == eTCP_LISTEN ). */
else
{
/* This is not a socket in listening mode. Check for the RST
* flag. */
if( ( ucTCPFlags & tcpTCP_FLAG_RST ) != 0U )
{
FreeRTOS_debug_printf( ( "TCP: RST received from %xip:%u for %u\n", ( unsigned ) ulRemoteIP, usRemotePort, usLocalPort ) );
/* Implement https://tools.ietf.org/html/rfc5961#section-3.2. */
if( pxSocket->u.xTCP.eTCPState == 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 + 1U ) )
{
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( ( xSequenceGreaterThan( ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber ) != pdFALSE ) &&
( xSequenceLessThan( ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber +
pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength ) != pdFALSE ) )
{
/* Send a challenge ACK. */
( void ) prvTCPSendChallengeAck( pxNetworkBuffer );
}
else
{
/* Nothing. */
}
}
/* Otherwise, do nothing. In any case, the packet cannot be handled. */
xResult = pdFAIL;
}
/* Check whether there is a pure SYN amongst the TCP flags while the connection is established. */
else if( ( ( ucTCPFlags & tcpTCP_FLAG_CTRL ) == tcpTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.eTCPState >= eESTABLISHED ) )
{
/* SYN flag while this socket is already connected. */
FreeRTOS_debug_printf( ( "TCP: SYN unexpected from %xip:%u\n", ( unsigned ) ulRemoteIP, usRemotePort ) );
/* The packet cannot be handled. */
xResult = pdFAIL;
}
else
{
/* Update the copy of the TCP header only (skipping eth and IP
* headers). It might be used later on, whenever data must be sent
* to the peer. */
const size_t uxOffset = ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket );
( void ) memcpy( ( void * ) ( &( pxSocket->u.xTCP.xPacket.u.ucLastPacket[ uxOffset ] ) ),
( const void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ uxOffset ] ) ),
ipSIZE_OF_TCP_HEADER );
/* Clear flags that are set by the peer, and set the ACK flag. */
pxSocket->u.xTCP.xPacket.u.ucLastPacket[ uxOffset + ipTCP_FLAGS_OFFSET ] = tcpTCP_FLAG_ACK;
}
}
}
if( xResult != pdFAIL )
{
uint16_t usWindow;
/* pxSocket is not NULL when xResult != pdFAIL. */
configASSERT( pxSocket != NULL ); /* LCOV_EXCL_LINE ,this branch will not be hit*/
/* Touch the alive timers because we received a message for this
* socket. */
prvTCPTouchSocket( pxSocket );
/* Parse the TCP option(s), if present. */
/* _HT_ : if we're in the SYN phase, and peer does not send a MSS option,
* then we MUST assume an MSS size of 536 bytes for backward compatibility. */
/* When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
* the number 5 (words) in the higher nibble of the TCP-offset byte. */
if( ( pxProtocolHeaders->xTCPHeader.ucTCPOffset & tcpTCP_OFFSET_LENGTH_BITS ) > tcpTCP_OFFSET_STANDARD_LENGTH )
{
xResult = prvCheckOptions( pxSocket, pxNetworkBuffer );
}
if( xResult != pdFAIL )
{
usWindow = FreeRTOS_ntohs( pxProtocolHeaders->xTCPHeader.usWindow );
pxSocket->u.xTCP.ulWindowSize = ( uint32_t ) usWindow;
#if ( ipconfigUSE_TCP_WIN == 1 )
{
/* rfc1323 : The Window field in a SYN (i.e., a <SYN> or <SYN,ACK>)
* segment itself is never scaled. */
if( ( ucTCPFlags & ( uint8_t ) tcpTCP_FLAG_SYN ) == 0U )
{
pxSocket->u.xTCP.ulWindowSize =
( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
}
}
#endif /* ipconfigUSE_TCP_WIN */
/* In prvTCPHandleState() the incoming messages will be handled
* depending on the current state of the connection. */
if( prvTCPHandleState( pxSocket, &pxNetworkBuffer ) > 0 )
{
/* prvTCPHandleState() has sent a message, see if there are more to
* be transmitted. */
#if ( ipconfigUSE_TCP_WIN == 1 )
{
( void ) prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
}
#endif /* ipconfigUSE_TCP_WIN */
}
if( pxNetworkBuffer != NULL )
{
/* We must check if the buffer is unequal to NULL, because the
* socket might keep a reference to it in case a delayed ACK must be
* sent. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
#ifndef _lint
/* Clear pointers that are freed. */
pxNetworkBuffer = NULL;
#endif
}
/* And finally, calculate when this socket wants to be woken up. */
( void ) prvTCPNextTimeout( pxSocket );
}
}
}
/* pdPASS being returned means the buffer has been consumed. */
return xResult;
}
/*-----------------------------------------------------------*/
/**
* @brief In the API accept(), the user asks is there is a new client? As API's can
* not walk through the xBoundTCPSocketsList the IP-task will do this.
*
* @param[in] pxSocket: The socket for which the bound socket list will be iterated.
*
* @return if there is a new client, then pdTRUE is returned or else, pdFALSE.
*/
BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t * pxSocket )
{
TickType_t uxLocalPort = ( TickType_t ) FreeRTOS_htons( pxSocket->usLocalPort );
const ListItem_t * pxIterator;
FreeRTOS_Socket_t * pxFound;
BaseType_t xResult = pdFALSE;
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
const ListItem_t * pxEndTCP = ( ( const ListItem_t * ) &( xBoundTCPSocketsList.xListEnd ) );
/* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one
* who has access. */
for( pxIterator = ( const ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
pxIterator != pxEndTCP;
pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
{
if( listGET_LIST_ITEM_VALUE( pxIterator ) == ( configLIST_VOLATILE TickType_t ) uxLocalPort )
{
pxFound = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
if( ( pxFound->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
{
pxSocket->u.xTCP.pxPeerSocket = pxFound;
FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) );
xResult = pdTRUE;
break;
}
}
}
return xResult;
}
/*-----------------------------------------------------------*/
#endif /* ipconfigUSE_TCP == 1 */
/* Provide access to private members for testing. */
#ifdef FREERTOS_ENABLE_UNIT_TESTS
#include "freertos_tcp_test_access_tcp_define.h"
#endif
/* Provide access to private members for verification. */
#ifdef FREERTOS_TCP_ENABLE_VERIFICATION
#include "aws_freertos_tcp_verification_access_tcp_define.h"
#endif

View File

@ -0,0 +1,616 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_TCP_Reception.c
* @brief Module which processes the packet received from a socket for FreeRTOS+TCP.
*
* Endianness: in this module all ports and IP addresses are stored in
* host byte-order, except fields in the IP-packets
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_DHCP.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
#include "FreeRTOS_ARP.h"
#include "FreeRTOS_TCP_Transmission.h"
#include "FreeRTOS_TCP_Reception.h"
/* Just make sure the contents doesn't get compiled if TCP is not enabled. */
#if ipconfigUSE_TCP == 1
/*
* 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 int32_t prvSingleStepTCPHeaderOptions( const uint8_t * const pucPtr,
size_t uxTotalLength,
FreeRTOS_Socket_t * const pxSocket,
BaseType_t xHasSYNFlag );
#if ( ipconfigUSE_TCP_WIN == 1 )
/*
* Skip past TCP header options when doing Selective ACK, until there are no
* more options left.
*/
static void prvReadSackOption( const uint8_t * const pucPtr,
size_t uxIndex,
FreeRTOS_Socket_t * const pxSocket );
#endif /* ( ipconfigUSE_TCP_WIN == 1 ) */
/**
* @brief Parse the TCP option(s) received, if present.
*
* @param[in] pxSocket: The socket handling the connection.
* @param[in] pxNetworkBuffer: The network buffer containing the TCP
* packet.
*
* @return: If the options are well formed and processed successfully
* then pdPASS is returned; else a pdFAIL is returned.
*
* @note It has already been verified that:
* ((pxTCPHeader->ucTCPOffset & 0xf0) > 0x50), meaning that
* the TP header is longer than the usual 20 (5 x 4) bytes.
*/
BaseType_t prvCheckOptions( FreeRTOS_Socket_t * pxSocket,
const NetworkBufferDescriptor_t * pxNetworkBuffer )
{
size_t uxTCPHeaderOffset = ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer );
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
const ProtocolHeaders_t * pxProtocolHeaders = ( ( ProtocolHeaders_t * )
&( pxNetworkBuffer->pucEthernetBuffer[ uxTCPHeaderOffset ] ) );
const TCPHeader_t * pxTCPHeader;
const uint8_t * pucPtr;
BaseType_t xHasSYNFlag;
BaseType_t xReturn = pdPASS;
/* Offset in the network packet where the first option byte is stored. */
size_t uxOptionOffset = uxTCPHeaderOffset + ( sizeof( TCPHeader_t ) - sizeof( pxTCPHeader->ucOptdata ) );
size_t uxOptionsLength;
int32_t lResult;
uint8_t ucLength;
pxTCPHeader = &( pxProtocolHeaders->xTCPHeader );
/* A character pointer to iterate through the option data */
pucPtr = pxTCPHeader->ucOptdata;
if( pxTCPHeader->ucTCPOffset <= ( 5U << 4U ) )
{
/* Avoid integer underflow in computation of ucLength. */
}
else
{
ucLength = ( ( ( pxTCPHeader->ucTCPOffset >> 4U ) - 5U ) << 2U );
uxOptionsLength = ( size_t ) ucLength;
if( pxNetworkBuffer->xDataLength > uxOptionOffset )
{
/* Validate options size calculation. */
if( uxOptionsLength <= ( pxNetworkBuffer->xDataLength - uxOptionOffset ) )
{
if( ( pxTCPHeader->ucTCPFlags & tcpTCP_FLAG_SYN ) != ( uint8_t ) 0U )
{
xHasSYNFlag = pdTRUE;
}
else
{
xHasSYNFlag = pdFALSE;
}
/* The length check is only necessary in case the option data are
* corrupted, we don't like to run into invalid memory and crash. */
for( ; ; )
{
if( uxOptionsLength == 0U )
{
/* coverity[break_stmt] : Break statement terminating the loop */
break;
}
lResult = prvSingleStepTCPHeaderOptions( pucPtr, uxOptionsLength, pxSocket, xHasSYNFlag );
if( lResult < 0 )
{
xReturn = pdFAIL;
break;
}
if( lResult == 0 )
{
break;
}
uxOptionsLength -= ( size_t ) lResult;
pucPtr = &( pucPtr[ lResult ] );
}
}
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
/**
* @brief Identify and deal with a single TCP header option, advancing the pointer to
* the header.
*
* @param[in] pucPtr: Pointer to the TCP packet options.
* @param[in] uxTotalLength: Length of the TCP packet options.
* @param[in] pxSocket: Socket handling the connection.
* @param[in] xHasSYNFlag: Whether the header has SYN flag or not.
*
* @return This function returns index of the next option if the current option is
* successfully processed and it is not the end of options whereafter the caller
* should continue to process more options.
* If the options have ended, this function will return a zero whereafter the
* caller should stop parsing options and continue further processing.
* If the current option has erroneous value, then the function returns a
* negative value wherein the calling function should not process this packet any
* further and drop it.
*/
static int32_t prvSingleStepTCPHeaderOptions( const uint8_t * const pucPtr,
size_t uxTotalLength,
FreeRTOS_Socket_t * const pxSocket,
BaseType_t xHasSYNFlag )
{
UBaseType_t uxNewMSS;
size_t uxRemainingOptionsBytes = uxTotalLength;
uint8_t ucLen;
int32_t lIndex = 0;
TCPWindow_t * pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
BaseType_t xReturn = pdFALSE;
if( pucPtr[ 0U ] == tcpTCP_OPT_END )
{
/* End of options. */
lIndex = 0;
}
else if( pucPtr[ 0U ] == tcpTCP_OPT_NOOP )
{
/* NOP option, inserted to make the length a multiple of 4. */
lIndex = 1;
}
else if( uxRemainingOptionsBytes < 2U )
{
/* Any other well-formed option must be at least two bytes: the option
* type byte followed by a length byte. */
lIndex = -1;
}
#if ( ipconfigUSE_TCP_WIN != 0 )
else if( pucPtr[ 0 ] == tcpTCP_OPT_WSOPT )
{
/* The TCP Window Scale Option. */
/* Confirm that the option fits in the remaining buffer space. */
if( ( uxRemainingOptionsBytes < tcpTCP_OPT_WSOPT_LEN ) || ( pucPtr[ 1 ] != tcpTCP_OPT_WSOPT_LEN ) )
{
lIndex = -1;
}
else
{
/* Option is only valid in SYN phase. */
if( xHasSYNFlag != 0 )
{
pxSocket->u.xTCP.ucPeerWinScaleFactor = pucPtr[ 2 ];
pxSocket->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED;
}
lIndex = ( int32_t ) tcpTCP_OPT_WSOPT_LEN;
}
}
#endif /* ipconfigUSE_TCP_WIN */
else if( pucPtr[ 0 ] == tcpTCP_OPT_MSS )
{
/* Confirm that the option fits in the remaining buffer space. */
if( ( uxRemainingOptionsBytes < tcpTCP_OPT_MSS_LEN ) || ( pucPtr[ 1 ] != tcpTCP_OPT_MSS_LEN ) )
{
lIndex = -1;
}
else
{
/* 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( pxSocket->u.xTCP.usMSS != uxNewMSS )
{
/* Perform a basic check on the the new MSS. */
if( uxNewMSS == 0U )
{
lIndex = -1;
/* Return Condition found. */
xReturn = pdTRUE;
}
else
{
FreeRTOS_debug_printf( ( "MSS change %u -> %u\n", pxSocket->u.xTCP.usMSS, ( unsigned ) uxNewMSS ) );
}
}
/* If a 'return' condition has not been found. */
if( xReturn == pdFALSE )
{
/* Restrict the minimum value of segment length to the ( Minimum IP MTU (576) - IP header(20) - TCP Header(20) ).
* See "RFC 791 section 3.1 Total Length" for more details. */
if( uxNewMSS < tcpMINIMUM_SEGMENT_LENGTH )
{
uxNewMSS = tcpMINIMUM_SEGMENT_LENGTH;
}
if( pxSocket->u.xTCP.usMSS > uxNewMSS )
{
/* our MSS was bigger than the MSS of the other party: adapt it. */
pxSocket->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED;
if( pxSocket->u.xTCP.usMSS > uxNewMSS )
{
/* The peer advertises a smaller MSS than this socket was
* using. Use that as well. */
FreeRTOS_debug_printf( ( "Change mss %d => %u\n", pxSocket->u.xTCP.usMSS, ( unsigned ) uxNewMSS ) );
}
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.usMSS = ( uint16_t ) uxNewMSS;
}
lIndex = ( int32_t ) tcpTCP_OPT_MSS_LEN;
}
}
}
else
{
/* All other options have a length field, so that we easily
* can skip past them. */
ucLen = pucPtr[ 1 ];
lIndex = 0;
if( ( ucLen < ( uint8_t ) 2U ) || ( uxRemainingOptionsBytes < ( size_t ) ucLen ) )
{
/* If the length field is too small or too big, the options are
* malformed, don't process them further.
*/
lIndex = -1;
}
else
{
#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( pucPtr[ 0U ] == tcpTCP_OPT_SACK_A )
{
ucLen -= 2U;
lIndex += 2;
while( ucLen >= ( uint8_t ) 8U )
{
prvReadSackOption( pucPtr, ( size_t ) lIndex, pxSocket );
lIndex += 8;
ucLen -= 8U;
}
/* ucLen should be 0 by now. */
}
}
#endif /* ipconfigUSE_TCP_WIN == 1 */
lIndex += ( int32_t ) ucLen;
}
}
#if ( ipconfigUSE_TCP_WIN == 0 )
/* Avoid compiler warnings when TCP window is not used. */
( void ) xHasSYNFlag;
#endif
return lIndex;
}
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_TCP_WIN == 1 )
/**
* @brief Skip past TCP header options when doing Selective ACK, until there are no
* more options left.
*
* @param[in] pucPtr: Pointer to the TCP packet options.
* @param[in] uxIndex: Index of options in the TCP packet options.
* @param[in] pxSocket: Socket handling the TCP connection.
*/
static void prvReadSackOption( const uint8_t * const pucPtr,
size_t uxIndex,
FreeRTOS_Socket_t * const pxSocket )
{
uint32_t ulFirst = ulChar2u32( &( pucPtr[ uxIndex ] ) );
uint32_t ulLast = ulChar2u32( &( pucPtr[ uxIndex + 4U ] ) );
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 > 0U ) )
{
/* Just advancing the tail index, 'ulCount' bytes have been confirmed. */
( void ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE );
pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_SEND;
#if ipconfigSUPPORT_SELECT_FUNCTION == 1
{
if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_WRITE ) != 0U )
{
/* 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 |= ( ( EventBits_t ) 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( pxSocket, ulCount );
}
}
#endif /* ipconfigUSE_CALLBACKS == 1 */
}
}
#endif /* ( ipconfigUSE_TCP_WIN != 0 ) */
/*-----------------------------------------------------------*/
/**
* @brief prvCheckRxData(): called from prvTCPHandleState(). The
* first thing that will be done is find the TCP payload data
* and check the length of this data.
*
* @param[in] pxNetworkBuffer: The network buffer holding the received data.
* @param[out] ppucRecvData: It will point to first byte of the TCP payload.
*
* @return Length of the received buffer.
*/
BaseType_t prvCheckRxData( const NetworkBufferDescriptor_t * pxNetworkBuffer,
uint8_t ** ppucRecvData )
{
/* Map the ethernet buffer onto the ProtocolHeader_t struct for easy access to the fields. */
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
const ProtocolHeaders_t * pxProtocolHeaders = ( ( ProtocolHeaders_t * )
&( pxNetworkBuffer->pucEthernetBuffer[ ( size_t ) ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer ) ] ) );
const TCPHeader_t * pxTCPHeader = &( pxProtocolHeaders->xTCPHeader );
int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength;
/* Map the buffer onto an IPHeader_t struct for easy access to fields. */
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
const IPHeader_t * pxIPHeader = ( ( const IPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) );
const size_t xIPHeaderLength = ipSIZE_OF_IPv4_HEADER;
uint16_t usLength;
uint8_t ucIntermediateResult = 0;
/* Determine the length and the offset of the user-data sent to this
* node.
*
* The size of the TCP header is given in a multiple of 4-byte words (single
* byte, needs no ntoh() translation). A shift-right 2: is the same as
* (offset >> 4) * 4. */
ucIntermediateResult = ( pxTCPHeader->ucTCPOffset & tcpVALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2;
lTCPHeaderLength = ( int32_t ) ucIntermediateResult;
/* Let pucRecvData point to the first byte received. */
*ppucRecvData = &( pxNetworkBuffer->pucEthernetBuffer[ ( size_t ) ipSIZE_OF_ETH_HEADER + xIPHeaderLength + ( size_t ) lTCPHeaderLength ] );
/* Calculate lReceiveLength - the length of the TCP data received. This is
* equal to the total packet length minus:
* ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/
lReceiveLength = ( int32_t ) pxNetworkBuffer->xDataLength;
lReceiveLength -= ( int32_t ) ipSIZE_OF_ETH_HEADER;
usLength = FreeRTOS_htons( pxIPHeader->usLength );
lLength = ( int32_t ) usLength;
if( lReceiveLength > lLength )
{
/* More bytes were received than the reported length, often because of
* padding bytes at the end. */
lReceiveLength = lLength;
}
/* Subtract the size of the TCP and IP headers and the actual data size is
* known. */
if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) xIPHeaderLength ) )
{
lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) xIPHeaderLength );
}
else
{
lReceiveLength = 0;
}
/* Urgent Pointer:
* This field communicates the current value of the urgent pointer as a
* positive offset from the sequence number in this segment. The urgent
* pointer points to the sequence number of the octet following the urgent
* data. This field is only be interpreted in segments with the URG control
* bit set. */
if( ( pxTCPHeader->ucTCPFlags & tcpTCP_FLAG_URG ) != 0U )
{
/* Although we ignore the urgent data, we have to skip it. */
lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent );
*ppucRecvData += lUrgentLength;
lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength );
}
return ( BaseType_t ) lReceiveLength;
}
/*-----------------------------------------------------------*/
/**
* @brief prvStoreRxData(): called from prvTCPHandleState().
* The second thing is to do is check if the payload data may
* be accepted. If so, they will be added to the reception queue.
*
* @param[in] pxSocket: The socket owning the connection.
* @param[in] pucRecvData: Pointer to received data.
* @param[in] pxNetworkBuffer: The network buffer descriptor.
* @param[in] ulReceiveLength: The length of the received data.
*
* @return 0 on success, -1 on failure of storing data.
*/
BaseType_t prvStoreRxData( FreeRTOS_Socket_t * pxSocket,
const uint8_t * pucRecvData,
NetworkBufferDescriptor_t * pxNetworkBuffer,
uint32_t ulReceiveLength )
{
/* Map the ethernet buffer onto the ProtocolHeader_t struct for easy access to the fields. */
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
const ProtocolHeaders_t * pxProtocolHeaders = ( ( const ProtocolHeaders_t * )
&( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer ) ] ) );
const TCPHeader_t * pxTCPHeader = &pxProtocolHeaders->xTCPHeader;
TCPWindow_t * pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
uint32_t ulSequenceNumber, ulSpace;
int32_t lOffset, lStored;
BaseType_t xResult = 0;
uint32_t ulRxLength = ulReceiveLength;
const uint8_t * pucRxBuffer = &( pucRecvData[ 0 ] );
ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
if( ( ulRxLength > 0U ) && ( pxSocket->u.xTCP.eTCPState >= eSYN_RECEIVED ) )
{
uint32_t ulSkipCount = 0;
/* See if way may accept the data contents and forward it to the socket
* owner.
*
* If it can't be "accept"ed it may have to be stored and send a selective
* ack (SACK) option to confirm it. In that case, lTCPAddRxdata() will be
* called later to store an out-of-order packet (in case lOffset is
* negative). */
if( pxSocket->u.xTCP.rxStream != NULL )
{
ulSpace = ( uint32_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.rxStream );
}
else
{
ulSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
}
lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulRxLength, ulSpace, &( ulSkipCount ) );
if( lOffset >= 0 )
{
/* New data has arrived and may be made available to the user. See
* if the head marker in rxStream may be advanced, only if lOffset == 0.
* In case the low-water mark is reached, bLowWater will be set
* "low-water" here stands for "little space". */
if( ulSkipCount != 0U )
{
/* A packet was received that starts before 'ulCurrentSequenceNumber',
* and that ends after it. The first 'ulSkipCount' bytes shall be
* skipped. */
ulRxLength -= ulSkipCount;
pucRxBuffer = &( pucRecvData[ ulSkipCount ] );
}
lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRxBuffer, ulRxLength );
if( lStored != ( int32_t ) ulRxLength )
{
FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %d / %u bytes? ?\n", ( int ) lStored, ( unsigned ) ulRxLength ) );
/* Received data could not be stored. The socket's flag
* bMallocError has been set. The socket now has the status
* eCLOSE_WAIT and a RST packet will be sent back. */
( void ) prvTCPSendReset( pxNetworkBuffer );
xResult = -1;
}
}
/* After a missing packet has come in, higher packets may be passed to
* the user. */
#if ( ipconfigUSE_TCP_WIN == 1 )
{
/* Now lTCPAddRxdata() will move the rxHead pointer forward
* so data becomes available to the user immediately
* In case the low-water mark is reached, bLowWater will be set. */
if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0U ) )
{
( void ) lTCPAddRxdata( pxSocket, 0U, NULL, pxTCPWindow->ulUserDataLength );
pxTCPWindow->ulUserDataLength = 0;
}
}
#endif /* ipconfigUSE_TCP_WIN */
}
else
{
pxTCPWindow->ucOptionLength = 0U;
}
return xResult;
}
/*-----------------------------------------------------------*/
#endif /* ipconfigUSE_TCP == 1 */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,118 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_TCP_Utils.c
* @brief Module contains utility functions used by FreeRTOS+TCP module.
*
* Endianness: in this module all ports and IP addresses are stored in
* host byte-order, except fields in the IP-packets
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_TCP_Utils.h"
/* Just make sure the contents doesn't get compiled if TCP is not enabled. */
#if ipconfigUSE_TCP == 1
/* For logging and debugging: make a string showing the TCP flags
*/
#if ( ipconfigHAS_DEBUG_PRINTF != 0 )
/**
* @brief Print out the value of flags in a human readable manner.
*
* @param[in] xFlags: The TCP flags.
*
* @return The string containing the flags.
*/
static char retString[ 10 ];
const char * prvTCPFlagMeaning( UBaseType_t xFlags )
{
size_t uxFlags = ( size_t ) xFlags;
( void ) snprintf( retString,
sizeof( retString ), "%c%c%c%c%c%c%c%c",
( ( uxFlags & ( size_t ) tcpTCP_FLAG_FIN ) != 0 ) ? 'F' : '.', /* 0x0001: No more data from sender */
( ( uxFlags & ( size_t ) tcpTCP_FLAG_SYN ) != 0 ) ? 'S' : '.', /* 0x0002: Synchronize sequence numbers */
( ( uxFlags & ( size_t ) tcpTCP_FLAG_RST ) != 0 ) ? 'R' : '.', /* 0x0004: Reset the connection */
( ( uxFlags & ( size_t ) tcpTCP_FLAG_PSH ) != 0 ) ? 'P' : '.', /* 0x0008: Push function: please push buffered data to the recv application */
( ( uxFlags & ( size_t ) tcpTCP_FLAG_ACK ) != 0 ) ? 'A' : '.', /* 0x0010: Acknowledgment field is significant */
( ( uxFlags & ( size_t ) tcpTCP_FLAG_URG ) != 0 ) ? 'U' : '.', /* 0x0020: Urgent pointer field is significant */
( ( uxFlags & ( size_t ) tcpTCP_FLAG_ECN ) != 0 ) ? 'E' : '.', /* 0x0040: ECN-Echo */
( ( uxFlags & ( size_t ) tcpTCP_FLAG_CWR ) != 0 ) ? 'C' : '.' ); /* 0x0080: Congestion Window Reduced */
return retString;
}
/*-----------------------------------------------------------*/
#endif /* ipconfigHAS_DEBUG_PRINTF */
/**
* @brief Set the MSS (Maximum segment size) associated with the given socket.
*
* @param[in] pxSocket: The socket whose MSS is to be set.
*/
void prvSocketSetMSS( FreeRTOS_Socket_t * pxSocket )
{
uint32_t ulMSS;
/* Do not allow MSS smaller than tcpMINIMUM_SEGMENT_LENGTH. */
#if ( ipconfigTCP_MSS >= tcpMINIMUM_SEGMENT_LENGTH )
{
ulMSS = ipconfigTCP_MSS;
}
#else
{
ulMSS = tcpMINIMUM_SEGMENT_LENGTH;
}
#endif
if( ( ( FreeRTOS_ntohl( pxSocket->u.xTCP.ulRemoteIP ) ^ *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) != 0U )
{
/* Data for this peer will pass through a router, and maybe through
* the internet. Limit the MSS to 1400 bytes or less. */
ulMSS = FreeRTOS_min_uint32( ( uint32_t ) tcpREDUCED_MSS_THROUGH_INTERNET, ulMSS );
}
FreeRTOS_debug_printf( ( "prvSocketSetMSS: %u bytes for %xip:%u\n", ( unsigned ) ulMSS, ( unsigned ) pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort ) );
pxSocket->u.xTCP.usMSS = ( uint16_t ) ulMSS;
}
/*-----------------------------------------------------------*/
#endif /* ipconfigUSE_TCP == 1 */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,501 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*=============================================================================
*
* ##### # ##### #### ######
* # # # # # # # # # # #
* # # # # # #
* # ### ##### # # # # # #
* # # # # # # # # #####
* # # # # # # #### # # #
* # # # # # # # # # #
* # # # # #### # # # #
* #### ##### # # # #### #### ####
* #
* ###
* Tiny-TCP: TCP without sliding windows.
*
*=============================================================================*/
/**
* @file FreeRTOS_TINY_TCP.c
* @brief Module which handles TCP when windowing is disabled
*
* In this module all ports and IP addresses and sequence numbers are
* being stored in host byte-order.
*/
/* Standard includes. */
#include <stdint.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#if ( ipconfigUSE_TCP == 1 )
#if ( ipconfigUSE_TCP_WIN == 0 )
/** @brief Logging verbosity level. */
BaseType_t xTCPWindowLoggingLevel = 0;
static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a,
uint32_t b );
/**
* @brief Test if a>=b. This function is required since the sequence numbers can roll over.
*
* @param[in] a: The first sequence number.
* @param[in] b: The second sequence number.
*
* @return pdTRUE if a>=b, else pdFALSE.
*/
static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a,
uint32_t b )
{
BaseType_t xResult = pdFALSE;
/* Test if a >= b */
if( ( ( a - b ) & 0x80000000U ) == 0U )
{
xResult = pdTRUE;
}
return xResult;
}
static portINLINE void vTCPTimerSet( TCPTimer_t * pxTimer );
/**
* @brief Set the timer's "born" time.
*
* @param[in] pxTimer: The TCP timer.
*/
static portINLINE void vTCPTimerSet( TCPTimer_t * pxTimer )
{
pxTimer->uxBorn = xTaskGetTickCount();
}
/*-----------------------------------------------------------*/
static portINLINE uint32_t ulTimerGetAge( const TCPTimer_t * pxTimer );
/**
* @brief Get the timer age in milliseconds.
*
* @param[in] pxTimer: The timer whose age is to be fetched.
*
* @return The time in milliseconds since the timer was born.
*/
static portINLINE uint32_t ulTimerGetAge( const TCPTimer_t * pxTimer )
{
TickType_t uxNow = xTaskGetTickCount();
TickType_t uxDiff = uxNow - pxTimer->uxBorn;
return uxDiff * portTICK_PERIOD_MS;
}
/*-----------------------------------------------------------*/
/**
* @brief Data was received at 'ulSequenceNumber'. See if it was expected
* and if there is enough space to store the new data.
*
* @param[in] pxWindow: The window to be checked.
* @param[in] ulSequenceNumber: Sequence number of the data received.
* @param[in] ulLength: Length of the data received.
* @param[in] ulSpace: Space in the buffer.
*
* @return A 0 is returned if there is enough space and the sequence number is correct,
* if not then a -1 is returned.
*
* @note if true may be passed directly to user (segment expected and window is empty).
* But pxWindow->ackno should always be used to set "BUF->ackno".
*/
int32_t lTCPWindowRxCheck( TCPWindow_t * pxWindow,
uint32_t ulSequenceNumber,
uint32_t ulLength,
uint32_t ulSpace,
uint32_t * pulSkipCount )
{
int32_t lReturn = -1;
*pulSkipCount = 0;
/* Data was received at 'ulSequenceNumber'. See if it was expected
* and if there is enough space to store the new data. */
if( ( pxWindow->rx.ulCurrentSequenceNumber != ulSequenceNumber ) || ( ulSpace < ulLength ) )
{
lReturn = -1;
}
else
{
pxWindow->rx.ulCurrentSequenceNumber += ( uint32_t ) ulLength;
lReturn = 0;
}
return lReturn;
}
#endif /* ipconfigUSE_TCP_WIN == 0 */
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_TCP_WIN == 0 )
/**
* @brief Add data to the Tx Window.
*
* @param[in] pxWindow: The window to which the data is to be added.
* @param[in] ulLength: The length of the data to be added.
* @param[in] lPosition: Position in the stream.
* @param[in] lMax: Size of the Tx stream.
*
* @return The data actually added.
*/
int32_t lTCPWindowTxAdd( TCPWindow_t * pxWindow,
uint32_t ulLength,
int32_t lPosition,
int32_t lMax )
{
TCPSegment_t * pxSegment = &( pxWindow->xTxSegment );
int32_t lResult;
/* Data is being scheduled for transmission. */
/* lMax would indicate the size of the txStream. */
( void ) lMax;
/* This is tiny TCP: there is only 1 segment for outgoing data.
* As long as 'lDataLength' is unequal to zero, the segment is still occupied. */
if( pxSegment->lDataLength > 0 )
{
lResult = 0L;
}
else
{
if( ulLength > ( uint32_t ) pxSegment->lMaxLength )
{
if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
{
FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: can only store %u / %d bytes\n", ( unsigned ) ulLength, ( int ) pxSegment->lMaxLength ) );
}
ulLength = ( uint32_t ) pxSegment->lMaxLength;
}
if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
{
FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: SeqNr %u (%u) Len %u\n",
( unsigned ) ( pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ),
( unsigned ) ( pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ),
( unsigned ) ulLength ) );
}
/* The sequence number of the first byte in this packet. */
pxSegment->ulSequenceNumber = pxWindow->ulNextTxSequenceNumber;
pxSegment->lDataLength = ( int32_t ) ulLength;
pxSegment->lStreamPos = lPosition;
pxSegment->u.ulFlags = 0U;
vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
/* Increase the sequence number of the next data to be stored for
* transmission. */
pxWindow->ulNextTxSequenceNumber += ulLength;
lResult = ( int32_t ) ulLength;
}
return lResult;
}
#endif /* ipconfigUSE_TCP_WIN == 0 */
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_TCP_WIN == 0 )
/**
* @brief Fetches data to be sent.
*
* @param[in] pxWindow: The window for the connection.
* @param[in] ulWindowSize: The size of the window.
* @param[out] plPosition: plPosition will point to a location with the circular data buffer: txStream.
*
* @return return the amount of data which may be sent along with the position in the txStream.
*/
uint32_t ulTCPWindowTxGet( TCPWindow_t * pxWindow,
uint32_t ulWindowSize,
int32_t * plPosition )
{
TCPSegment_t * pxSegment = &( pxWindow->xTxSegment );
uint32_t ulLength = ( uint32_t ) pxSegment->lDataLength;
uint32_t ulMaxTime;
if( ulLength != 0U )
{
/* _HT_ Still under investigation */
( void ) ulWindowSize;
if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
{
/* As 'ucTransmitCount' has a minimum of 1, take 2 * RTT */
ulMaxTime = ( ( uint32_t ) 1U ) << pxSegment->u.bits.ucTransmitCount;
ulMaxTime *= ( uint32_t ) pxWindow->lSRTT;
if( ulTimerGetAge( &( pxSegment->xTransmitTimer ) ) < ulMaxTime )
{
ulLength = 0U;
}
}
if( ulLength != 0U )
{
pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
pxSegment->u.bits.ucTransmitCount++;
vTCPTimerSet( &pxSegment->xTransmitTimer );
pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
*plPosition = pxSegment->lStreamPos;
}
}
return ulLength;
}
#endif /* ipconfigUSE_TCP_WIN == 0 */
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_TCP_WIN == 0 )
/**
* @brief Has the transmission completed.
*
* @param[in] pxWindow: The window whose transmission window is to be checked.
*
* @return If there is no outstanding data then pdTRUE is returned,
* else pdFALSE.
*/
BaseType_t xTCPWindowTxDone( const TCPWindow_t * pxWindow )
{
BaseType_t xReturn;
/* Has the outstanding data been sent because user wants to shutdown? */
if( pxWindow->xTxSegment.lDataLength == 0 )
{
xReturn = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
return xReturn;
}
#endif /* ipconfigUSE_TCP_WIN == 0 */
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_TCP_WIN == 0 )
static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t const * pxWindow,
uint32_t ulWindowSize );
/**
* @brief Check if the window has space for one message.
*
* @param[in] pxWindow: The window to be checked.
* @param[in] ulWindowSize: Size of the window.
*
* @return pdTRUE if the window has space, pdFALSE otherwise.
*/
static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t const * pxWindow,
uint32_t ulWindowSize )
{
BaseType_t xReturn;
if( ulWindowSize >= pxWindow->usMSSInit )
{
xReturn = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
return xReturn;
}
#endif /* ipconfigUSE_TCP_WIN == 0 */
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_TCP_WIN == 0 )
/**
* @brief Check data to be sent and calculate the time period the process may sleep.
*
* @param[in] pxWindow: The window to be checked.
* @param[in] ulWindowSize: Size of the window.
* @param[out] pulDelay: The time period (in ticks) that the process may sleep.
*
* @return pdTRUE if the process should sleep or pdFALSE.
*/
BaseType_t xTCPWindowTxHasData( TCPWindow_t const * pxWindow,
uint32_t ulWindowSize,
TickType_t * pulDelay )
{
TCPSegment_t const * pxSegment = &( pxWindow->xTxSegment );
BaseType_t xReturn;
TickType_t ulAge, ulMaxAge;
/* Check data to be sent. */
*pulDelay = ( TickType_t ) 0;
if( pxSegment->lDataLength == 0 )
{
/* Got nothing to send right now. */
xReturn = pdFALSE;
}
else
{
if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
{
ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer );
ulMaxAge = ( ( TickType_t ) 1U << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
if( ulMaxAge > ulAge )
{
*pulDelay = ulMaxAge - ulAge;
}
xReturn = pdTRUE;
}
else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
{
/* Too many outstanding messages. */
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
}
return xReturn;
}
#endif /* ipconfigUSE_TCP_WIN == 0 */
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_TCP_WIN == 0 )
/**
* @brief Receive a normal ACK.
*
* @param[in] pxWindow: The window for this particular connection.
* @param[in] ulSequenceNumber: The sequence number of the packet.
*
* @return Number of bytes to send.
*/
uint32_t ulTCPWindowTxAck( TCPWindow_t * pxWindow,
uint32_t ulSequenceNumber )
{
TCPSegment_t * pxSegment = &( pxWindow->xTxSegment );
uint32_t ulDataLength = ( uint32_t ) pxSegment->lDataLength;
/* Receive a normal ACK */
if( ulDataLength != 0U )
{
if( ulSequenceNumber < ( pxWindow->tx.ulCurrentSequenceNumber + ulDataLength ) )
{
if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE )
{
FreeRTOS_debug_printf( ( "win_tx_ack: acked %u expc %u len %u\n",
( unsigned ) ( ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ),
( unsigned ) ( pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ),
( unsigned ) ulDataLength ) );
}
/* Nothing to send right now. */
ulDataLength = 0U;
}
else
{
pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
{
FreeRTOS_debug_printf( ( "win_tx_ack: acked seqnr %u len %u\n",
( unsigned ) ( ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ),
( unsigned ) ulDataLength ) );
}
pxSegment->lDataLength = 0;
}
}
return ulDataLength;
}
#endif /* ipconfigUSE_TCP_WIN == 0 */
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_TCP_WIN == 0 )
/**
* @brief This function will be called as soon as a FIN is received to check
* whether all transmit queues are empty or not.
*
* @param[in] pxWindow: The window to be checked.
*
* @return It will return true if there are no 'open' reception segments.
*/
BaseType_t xTCPWindowRxEmpty( const TCPWindow_t * pxWindow )
{
/* Return true if 'ulCurrentSequenceNumber >= ulHighestSequenceNumber'
* 'ulCurrentSequenceNumber' is the highest sequence number stored,
* 'ulHighestSequenceNumber' is the highest sequence number seen. */
return xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber );
}
#endif /* ipconfigUSE_TCP_WIN == 0 */
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_TCP_WIN == 0 )
/**
* @brief Destroy a window.
*
* @param[in] pxWindow: Pointer to the window to be destroyed.
*
* @return Always returns a NULL.
*/
void vTCPWindowDestroy( const TCPWindow_t * pxWindow )
{
/* As in tiny TCP there are no shared segments descriptors, there is
* nothing to release. */
( void ) pxWindow;
}
#endif /* ipconfigUSE_TCP_WIN == 0 */
/*-----------------------------------------------------------*/
#endif /* ipconfigUSE_TCP == 1 */

View File

@ -0,0 +1,501 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_UDP_IP.c
* @brief This file has the source code for the UDP-IP functionality of the FreeRTOS+TCP
* network stack.
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"
#include "list.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_ARP.h"
#include "FreeRTOS_DNS.h"
#include "FreeRTOS_DHCP.h"
#include "FreeRTOS_IP_Utils.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
#if ( ipconfigUSE_DNS == 1 )
#include "FreeRTOS_DNS.h"
#endif
/** @brief The expected IP version and header length coded into the IP header itself. */
#define ipIP_VERSION_AND_HEADER_LENGTH_BYTE ( ( uint8_t ) 0x45 )
/** @brief Part of the Ethernet and IP headers are always constant when sending an IPv4
* UDP packet. This array defines the constant parts, allowing this part of the
* packet to be filled in using a simple memcpy() instead of individual writes. */
/*lint -e708 (Info -- union initialization). */
UDPPacketHeader_t xDefaultPartUDPPacketHeader =
{
/* .ucBytes : */
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source MAC address. */
0x08, 0x00, /* Ethernet frame type. */
ipIP_VERSION_AND_HEADER_LENGTH_BYTE, /* ucVersionHeaderLength. */
0x00, /* ucDifferentiatedServicesCode. */
0x00, 0x00, /* usLength. */
0x00, 0x00, /* usIdentification. */
0x00, 0x00, /* usFragmentOffset. */
ipconfigUDP_TIME_TO_LIVE, /* ucTimeToLive */
ipPROTOCOL_UDP, /* ucProtocol. */
0x00, 0x00, /* usHeaderChecksum. */
0x00, 0x00, 0x00, 0x00 /* Source IP address. */
}
};
/*-----------------------------------------------------------*/
/**
* @brief Process the generated UDP packet and do other checks before sending the
* packet such as ARP cache check and address resolution.
*
* @param[in] pxNetworkBuffer: The network buffer carrying the packet.
*/
void vProcessGeneratedUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
UDPPacket_t * pxUDPPacket;
IPHeader_t * pxIPHeader;
eARPLookupResult_t eReturned;
uint32_t ulIPAddress = pxNetworkBuffer->ulIPAddress;
size_t uxPayloadSize;
/* memcpy() helper variables for MISRA Rule 21.15 compliance*/
const void * pvCopySource;
void * pvCopyDest;
/* Map the UDP packet onto the start of the frame. */
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
pxUDPPacket = ( ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
#if ipconfigSUPPORT_OUTGOING_PINGS == 1
if( pxNetworkBuffer->usPort == ( uint16_t ) 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 ) );
if( eReturned != eCantSendPacket )
{
if( eReturned == eARPCacheHit )
{
#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
uint8_t ucSocketOptions;
#endif
iptraceSENDING_UDP_PACKET( pxNetworkBuffer->ulIPAddress );
/* Create short cuts to the data within the packet. */
pxIPHeader = &( pxUDPPacket->xIPHeader );
#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
/* Is it possible that the packet is not actually a UDP packet
* after all, but an ICMP packet. */
if( pxNetworkBuffer->usPort != ( uint16_t ) ipPACKET_CONTAINS_ICMP_DATA )
#endif /* ipconfigSUPPORT_OUTGOING_PINGS */
{
UDPHeader_t * pxUDPHeader;
pxUDPHeader = &( pxUDPPacket->xUDPHeader );
pxUDPHeader->usDestinationPort = pxNetworkBuffer->usPort;
pxUDPHeader->usSourcePort = pxNetworkBuffer->usBoundPort;
pxUDPHeader->usLength = ( uint16_t ) ( uxPayloadSize + sizeof( UDPHeader_t ) );
pxUDPHeader->usLength = FreeRTOS_htons( pxUDPHeader->usLength );
pxUDPHeader->usChecksum = 0U;
}
/* memcpy() the constant parts of the header information into
* the correct location within the packet. This fills in:
* xEthernetHeader.xSourceAddress
* xEthernetHeader.usFrameType
* xIPHeader.ucVersionHeaderLength
* xIPHeader.ucDifferentiatedServicesCode
* xIPHeader.usLength
* xIPHeader.usIdentification
* xIPHeader.usFragmentOffset
* xIPHeader.ucTimeToLive
* xIPHeader.ucProtocol
* and
* xIPHeader.usHeaderChecksum
*/
/* Save options now, as they will be overwritten by memcpy */
#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
{
ucSocketOptions = pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ];
}
#endif
/*
* Offset the memcpy by the size of a MAC address to start at the packet's
* Ethernet header 'source' MAC address; the preceding 'destination' should not be altered.
*/
/*
* Use helper variables for memcpy() to remain
* compliant with MISRA Rule 21.15. These should be
* optimized away.
*/
pvCopySource = xDefaultPartUDPPacketHeader.ucBytes;
/* The Ethernet source address is at offset 6. */
pvCopyDest = &pxNetworkBuffer->pucEthernetBuffer[ sizeof( MACAddress_t ) ];
( void ) memcpy( pvCopyDest, pvCopySource, sizeof( xDefaultPartUDPPacketHeader ) );
#if ipconfigSUPPORT_OUTGOING_PINGS == 1
if( pxNetworkBuffer->usPort == ( uint16_t ) ipPACKET_CONTAINS_ICMP_DATA )
{
pxIPHeader->ucProtocol = ipPROTOCOL_ICMP;
pxIPHeader->usLength = ( uint16_t ) ( uxPayloadSize + sizeof( IPHeader_t ) + sizeof( ICMPHeader_t ) );
}
else
#endif /* ipconfigSUPPORT_OUTGOING_PINGS */
{
pxIPHeader->usLength = ( uint16_t ) ( uxPayloadSize + sizeof( IPHeader_t ) + sizeof( UDPHeader_t ) );
}
pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength );
pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;
/* The stack doesn't support fragments, so the fragment offset field must always be zero.
* The header was never memset to zero, so set both the fragment offset and fragmentation flags in one go.
*/
#if ( ipconfigFORCE_IP_DONT_FRAGMENT != 0 )
pxIPHeader->usFragmentOffset = ipFRAGMENT_FLAGS_DONT_FRAGMENT;
#else
pxIPHeader->usFragmentOffset = 0U;
#endif
#if ( ipconfigUSE_LLMNR == 1 )
{
/* LLMNR messages are typically used on a LAN and they're
* not supposed to cross routers */
if( pxNetworkBuffer->ulIPAddress == ipLLMNR_IP_ADDR )
{
pxIPHeader->ucTimeToLive = 0x01;
}
}
#endif
#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
{
pxIPHeader->usHeaderChecksum = 0U;
pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
if( ( ucSocketOptions & ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT ) != 0U )
{
( void ) usGenerateProtocolChecksum( ( uint8_t * ) pxUDPPacket, pxNetworkBuffer->xDataLength, pdTRUE );
}
else
{
pxUDPPacket->xUDPHeader.usChecksum = 0U;
}
}
#endif /* if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) */
}
else if( eReturned == eARPCacheMiss )
{
/* Add an entry to the ARP table with a null hardware address.
* This allows the ARP timer to know that an ARP reply is
* outstanding, and perform retransmissions if necessary. */
vARPRefreshCacheEntry( NULL, ulIPAddress );
/* Generate an ARP for the required IP address. */
iptracePACKET_DROPPED_TO_GENERATE_ARP( pxNetworkBuffer->ulIPAddress );
pxNetworkBuffer->ulIPAddress = ulIPAddress;
vARPGenerateRequestPacket( pxNetworkBuffer );
}
else
{
/* The lookup indicated that an ARP request has already been
* sent out for the queried IP address. */
eReturned = eCantSendPacket;
}
}
if( eReturned != eCantSendPacket )
{
/* The network driver is responsible for freeing the network buffer
* after the packet has been sent. */
#if ( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 )
{
if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
{
BaseType_t xIndex;
for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
{
pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0U;
}
pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
}
}
#endif /* if( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 ) */
iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
( void ) xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );
}
else
{
/* The packet can't be sent (DHCP not completed?). Just drop the
* packet. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
}
}
/*-----------------------------------------------------------*/
/**
* @brief Process the received UDP packet.
*
* @param[in] pxNetworkBuffer: The network buffer carrying the UDP packet.
* @param[in] usPort: The port number on which this packet was received.
* @param[out] pxIsWaitingForARPResolution: If the packet is awaiting ARP resolution,
* this pointer will be set to pdTRUE. pdFALSE otherwise.
*
* @return pdPASS in case the UDP packet could be processed. Else pdFAIL is returned.
*/
BaseType_t xProcessReceivedUDPPacket( NetworkBufferDescriptor_t * pxNetworkBuffer,
uint16_t usPort,
BaseType_t * pxIsWaitingForARPResolution )
{
BaseType_t xReturn = pdPASS;
FreeRTOS_Socket_t * pxSocket;
configASSERT( pxNetworkBuffer != NULL );
configASSERT( pxNetworkBuffer->pucEthernetBuffer != NULL );
/* Map the ethernet buffer to the UDPPacket_t struct for easy access to the fields. */
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
const UDPPacket_t * pxUDPPacket = ( ( const UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
/* Caller must check for minimum packet size. */
pxSocket = pxUDPSocketLookup( usPort );
*pxIsWaitingForARPResolution = pdFALSE;
do
{
if( pxSocket != NULL )
{
if( *ipLOCAL_IP_ADDRESS_POINTER != 0U )
{
if( xCheckRequiresARPResolution( pxNetworkBuffer ) == pdTRUE )
{
/* Mark this packet as waiting for ARP resolution. */
*pxIsWaitingForARPResolution = pdTRUE;
/* Return a fail to show that the frame will not be processed right now. */
xReturn = pdFAIL;
break;
}
else
{
/* IP address is not on the same subnet, ARP table can be updated.
* When refreshing the ARP cache with received UDP packets we must be
* careful; hundreds of broadcast messages may pass and if we're not
* handling them, no use to fill the ARP cache with those IP addresses.
*/
vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
}
}
else
{
/* During DHCP, IP address is not assigned and therefore ARP verification
* is not possible. */
}
#if ( ipconfigUSE_CALLBACKS == 1 )
{
/* Did the owner of this socket register a reception handler ? */
if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleReceive ) )
{
struct freertos_sockaddr xSourceAddress, destinationAddress;
void * pcData = &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );
FOnUDPReceive_t xHandler = ( FOnUDPReceive_t ) pxSocket->u.xUDP.pxHandleReceive;
xSourceAddress.sin_port = pxNetworkBuffer->usPort;
xSourceAddress.sin_addr = pxNetworkBuffer->ulIPAddress;
destinationAddress.sin_port = usPort;
destinationAddress.sin_addr = pxUDPPacket->xIPHeader.ulDestinationIPAddress;
/* 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 ) ) != 0 )
{
xReturn = pdFAIL; /* xHandler has consumed the data, do not add it to .xWaitingPacketsList'. */
}
}
}
#endif /* ipconfigUSE_CALLBACKS */
#if ( ipconfigUDP_MAX_RX_PACKETS > 0U )
{
if( xReturn == pdPASS )
{
if( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) >= pxSocket->u.xUDP.uxMaxPackets )
{
FreeRTOS_debug_printf( ( "xProcessReceivedUDPPacket: buffer full %ld >= %ld port %u\n",
listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ),
pxSocket->u.xUDP.uxMaxPackets, pxSocket->usLocalPort ) );
xReturn = pdFAIL; /* we did not consume or release the buffer */
}
}
}
#endif /* if ( ipconfigUDP_MAX_RX_PACKETS > 0U ) */
#if ( ipconfigUSE_CALLBACKS == 1 ) || ( ipconfigUDP_MAX_RX_PACKETS > 0U )
if( xReturn == pdPASS ) /*lint !e774: Boolean within 'if' always evaluates to True, depending on configuration. [MISRA 2012 Rule 14.3, required. */
#else
/* xReturn is still pdPASS. */
#endif
{
vTaskSuspendAll();
{
taskENTER_CRITICAL();
{
/* Add the network packet to the list of packets to be
* processed by the socket. */
vListInsertEnd( &( pxSocket->u.xUDP.xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );
}
taskEXIT_CRITICAL();
}
( void ) xTaskResumeAll();
/* Set the socket's receive event */
if( pxSocket->xEventGroup != NULL )
{
( void ) xEventGroupSetBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_RECEIVE );
}
#if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
{
if( ( pxSocket->pxSocketSet != NULL ) && ( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_READ ) ) != 0U ) )
{
( void ) xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, ( EventBits_t ) eSELECT_READ );
}
}
#endif
#if ( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
{
if( pxSocket->pxUserSemaphore != NULL )
{
( void ) xSemaphoreGive( pxSocket->pxUserSemaphore );
}
}
#endif
#if ( ipconfigUSE_DHCP == 1 )
{
if( xIsDHCPSocket( pxSocket ) != 0 )
{
( void ) xSendDHCPEvent();
}
}
#endif
}
}
else
{
/* 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 ) == ( uint16_t ) 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 ) ) ||
( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) )
{
vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
xReturn = ( BaseType_t ) ulDNSHandlePacket( pxNetworkBuffer );
}
else
#endif /* ipconfigUSE_LLMNR */
#if ( ipconfigUSE_NBNS == 1 )
/* a NetBIOS request, check for the destination port */
if( ( usPort == FreeRTOS_ntohs( ipNBNS_PORT ) ) ||
( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipNBNS_PORT ) ) )
{
vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
xReturn = ( BaseType_t ) ulNBNSHandlePacket( pxNetworkBuffer );
}
else
#endif /* ipconfigUSE_NBNS */
{
xReturn = pdFAIL;
}
}
} while( ipFALSE_BOOL );
return xReturn;
}
/*-----------------------------------------------------------*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,159 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef FREERTOS_ARP_H
#define FREERTOS_ARP_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* Application level configuration options. */
#include "FreeRTOSIPConfig.h"
#include "FreeRTOSIPConfigDefaults.h"
#include "IPTraceMacroDefaults.h"
/*-----------------------------------------------------------*/
/* Miscellaneous structure and definitions. */
/*-----------------------------------------------------------*/
/**
* Structure for one row in the ARP cache table.
*/
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. */
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 */
} ARPCacheRow_t;
typedef enum
{
eARPCacheMiss = 0, /* 0 An ARP table lookup did not find a valid entry. */
eARPCacheHit, /* 1 An ARP table lookup found a valid entry. */
eCantSendPacket /* 2 There is no IP address, or an ARP is still in progress, so the packet cannot be sent. */
} eARPLookupResult_t;
/*
* If ulIPAddress is already in the ARP cache table then reset the age of the
* entry back to its maximum value. If ulIPAddress is not already in the ARP
* cache table then add it - replacing the oldest current entry if there is not
* a free space available.
*/
void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress,
const uint32_t ulIPAddress );
#if ( ipconfigARP_USE_CLASH_DETECTION != 0 )
/* Becomes non-zero if another device responded to a gratuitous ARP message. */
extern BaseType_t xARPHadIPClash;
/* MAC-address of the other device containing the same IP-address. */
extern MACAddress_t xARPClashMacAddress;
#endif /* ipconfigARP_USE_CLASH_DETECTION */
#if ( ipconfigUSE_ARP_REMOVE_ENTRY != 0 )
/*
* In some rare cases, it might be useful to remove a ARP cache entry of a
* known MAC address to make sure it gets refreshed.
*/
uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress );
#endif /* ipconfigUSE_ARP_REMOVE_ENTRY != 0 */
BaseType_t xIsIPInARPCache( uint32_t ulAddressToLookup );
BaseType_t xCheckRequiresARPResolution( const NetworkBufferDescriptor_t * pxNetworkBuffer );
/*
* Look for ulIPAddress in the ARP cache. If the IP address exists, copy the
* associated MAC address into pxMACAddress, refresh the ARP cache entry's
* age, and return eARPCacheHit. If the IP address does not exist in the ARP
* cache return eARPCacheMiss. If the packet cannot be sent for any reason
* (maybe DHCP is still in process, or the addressing needs a gateway but there
* isn't a gateway defined) then return eCantSendPacket.
*/
eARPLookupResult_t eARPGetCacheEntry( uint32_t * pulIPAddress,
MACAddress_t * const pxMACAddress );
#if ( ipconfigUSE_ARP_REVERSED_LOOKUP != 0 )
/* Lookup an IP-address if only the MAC-address is known */
eARPLookupResult_t eARPGetCacheEntryByMac( const MACAddress_t * const pxMACAddress,
uint32_t * pulIPAddress );
#endif
/*
* Reduce the age count in each entry within the ARP cache. An entry is no
* longer considered valid and is deleted if its age reaches zero.
*/
void vARPAgeCache( void );
/*
* Send out an ARP request for the IP address contained in pxNetworkBuffer, and
* add an entry into the ARP table that indicates that an ARP reply is
* outstanding so re-transmissions can be generated.
*/
void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
/*
* After DHCP is ready and when changing IP address, force a quick send of our new IP
* address
*/
void vARPSendGratuitous( void );
/* This function will check if the target IP-address belongs to this device.
* If so, the packet will be passed to the IP-stack, who will answer it.
* The function is to be called within the function xNetworkInterfaceOutput()
* in NetworkInterface.c as follows:
*
* 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.
* * /
* return pdTRUE;
* }
* / * Send the packet as usual. * /
*/
BaseType_t xCheckLoopback( NetworkBufferDescriptor_t * const pxDescriptor,
BaseType_t bReleaseAfterSend );
void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress );
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_ARP_H */

View File

@ -0,0 +1,250 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef FREERTOS_DHCP_H
#define FREERTOS_DHCP_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* Application level configuration options. */
#include "FreeRTOSIPConfig.h"
#include "IPTraceMacroDefaults.h"
#include "FreeRTOS_Sockets.h"
#if ( ipconfigUSE_DHCP != 0 ) && ( ipconfigNETWORK_MTU < 586U )
/* DHCP must be able to receive an options field of 312 bytes, the fixed
* part of the DHCP packet is 240 bytes, and the IP/UDP headers take 28 bytes. */
#error ipconfigNETWORK_MTU needs to be at least 586 to use DHCP
#endif
/* Parameter widths in the DHCP packet. */
#define dhcpCLIENT_HARDWARE_ADDRESS_LENGTH 16 /**< Client hardware address length.*/
#define dhcpSERVER_HOST_NAME_LENGTH 64 /**< Server host name length. */
#define dhcpBOOT_FILE_NAME_LENGTH 128 /**< Boot file name length. */
/* Timer parameters */
#ifndef dhcpINITIAL_TIMER_PERIOD
/** @brief The interval at which the DHCP state handler is called. */
#define dhcpINITIAL_TIMER_PERIOD ( pdMS_TO_TICKS( 250U ) )
#endif
#ifndef dhcpINITIAL_DHCP_TX_PERIOD
/** @brief The initial amount of time to wait for a DHCP reply. When repeating an
* unanswered request, this time-out shall be multiplied by 2. */
#define dhcpINITIAL_DHCP_TX_PERIOD ( pdMS_TO_TICKS( 5000U ) )
#endif
/* Codes of interest found in the DHCP options field. */
#define dhcpIPv4_ZERO_PAD_OPTION_CODE ( 0U ) /**< Used to pad other options to make them aligned. See RFC 2132. */
#define dhcpIPv4_SUBNET_MASK_OPTION_CODE ( 1U ) /**< Subnet mask. See RFC 2132. */
#define dhcpIPv4_GATEWAY_OPTION_CODE ( 3U ) /**< Available routers. See RFC 2132. */
#define dhcpIPv4_DNS_SERVER_OPTIONS_CODE ( 6U ) /**< Domain name server. See RFC 2132. */
#define dhcpIPv4_DNS_HOSTNAME_OPTIONS_CODE ( 12U ) /**< Host name. See RFC 2132. */
#define dhcpIPv4_REQUEST_IP_ADDRESS_OPTION_CODE ( 50U ) /**< Requested IP-address. See RFC 2132. */
#define dhcpIPv4_LEASE_TIME_OPTION_CODE ( 51U ) /**< IP-address lease time. See RFC 2132. */
#define dhcpIPv4_MESSAGE_TYPE_OPTION_CODE ( 53U ) /**< DHCP message type. See RFC 2132. */
#define dhcpIPv4_SERVER_IP_ADDRESS_OPTION_CODE ( 54U ) /**< Server Identifier. See RFC 2132. */
#define dhcpIPv4_PARAMETER_REQUEST_OPTION_CODE ( 55U ) /**< Parameter Request list. See RFC 2132. */
#define dhcpIPv4_CLIENT_IDENTIFIER_OPTION_CODE ( 61U ) /**< Client Identifier. See RFC 2132. */
/* The four DHCP message types of interest. */
#define dhcpMESSAGE_TYPE_DISCOVER ( 1 ) /**< DHCP discover message. */
#define dhcpMESSAGE_TYPE_OFFER ( 2 ) /**< DHCP offer message. */
#define dhcpMESSAGE_TYPE_REQUEST ( 3 ) /**< DHCP request message. */
#define dhcpMESSAGE_TYPE_ACK ( 5 ) /**< DHCP acknowledgement. */
#define dhcpMESSAGE_TYPE_NACK ( 6 ) /**< DHCP NACK. (Negative acknowledgement) */
/* Offsets into the transmitted DHCP options fields at which various parameters
* are located. */
#define dhcpCLIENT_IDENTIFIER_OFFSET ( 6U ) /**< Offset for the client ID option. */
#define dhcpREQUESTED_IP_ADDRESS_OFFSET ( 14U ) /**< Offset for the requested IP-address option. */
#define dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ( 20U ) /**< Offset for the server IP-address option. */
#define dhcpOPTION_50_OFFSET ( 12U ) /**< Offset of option-50. */
#define dhcpOPTION_50_SIZE ( 6U ) /**< Number of bytes included in option-50. */
/* Values used in the DHCP packets. */
#define dhcpREQUEST_OPCODE ( 1U ) /**< DHCP request opcode. */
#define dhcpREPLY_OPCODE ( 2U ) /**< DHCP reply opcode. */
#define dhcpADDRESS_TYPE_ETHERNET ( 1U ) /**< Address type: ethernet opcode. */
#define dhcpETHERNET_ADDRESS_LENGTH ( 6U ) /**< Ethernet address length opcode. */
/* The following define is temporary and serves to make the /single source
* code more similar to the /multi version. */
#define EP_DHCPData xDHCPData /**< Temporary define to make /single source similar to /multi version. */
#define EP_IPv4_SETTINGS xNetworkAddressing /**< Temporary define to make /single source similar to /multi version. */
/** @brief If a lease time is not received, use the default of two days (48 hours in ticks).
* Can not use pdMS_TO_TICKS() as integer overflow can occur. */
#define dhcpDEFAULT_LEASE_TIME ( ( 48UL * 60UL * 60UL ) * configTICK_RATE_HZ )
/** @brief Don't allow the lease time to be too short. */
#define dhcpMINIMUM_LEASE_TIME ( pdMS_TO_TICKS( 60000UL ) ) /* 60 seconds in ticks. */
/** @brief Marks the end of the variable length options field in the DHCP packet. */
#define dhcpOPTION_END_BYTE 0xffu
/** @brief Offset into a DHCP message at which the first byte of the options is
* located. */
#define dhcpFIRST_OPTION_BYTE_OFFSET ( 0xf0U )
/* Standard DHCP port numbers and magic cookie value.
* DHCPv4 uses UDP port number 68 for clients and port number 67 for servers.
*/
#if ( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
#define dhcpCLIENT_PORT_IPv4 0x4400U /**< Little endian representation of port 68. */
#define dhcpSERVER_PORT_IPv4 0x4300U /**< Little endian representation of port 67. */
#define dhcpCOOKIE 0x63538263UL /**< Little endian representation of magic cookie. */
#define dhcpBROADCAST 0x0080U /**< Little endian representation of broadcast flag. */
#else
#define dhcpCLIENT_PORT_IPv4 0x0044U /**< Big endian representation of port 68. */
#define dhcpSERVER_PORT_IPv4 0x0043U /**< Big endian representation of port 68. */
#define dhcpCOOKIE 0x63825363UL /**< Big endian representation of magic cookie. */
#define dhcpBROADCAST 0x8000U /**< Big endian representation of broadcast flag. */
#endif /* ( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) */
#include "pack_struct_start.h"
struct xDHCPMessage_IPv4
{
uint8_t ucOpcode; /**< Operation Code: Specifies the general type of message. */
uint8_t ucAddressType; /**< Hardware type used on the local network. */
uint8_t ucAddressLength; /**< Hardware Address Length: Specifies how long hardware
* addresses are in this message. */
uint8_t ucHops; /**< Hops. */
uint32_t ulTransactionID; /**< A 32-bit identification field generated by the client,
* to allow it to match up the request with replies received
* from DHCP servers. */
uint16_t usElapsedTime; /**< Number of seconds elapsed since a client began an attempt to acquire or renew a lease. */
uint16_t usFlags; /**< Just one bit used to indicate broadcast. */
uint32_t ulClientIPAddress_ciaddr; /**< Client's IP address if it has one or 0 is put in this field. */
uint32_t ulYourIPAddress_yiaddr; /**< The IP address that the server is assigning to the client. */
uint32_t ulServerIPAddress_siaddr; /**< The DHCP server address that the client should use. */
uint32_t ulRelayAgentIPAddress_giaddr; /**< Gateway IP address in case the server client are on different subnets. */
uint8_t ucClientHardwareAddress[ dhcpCLIENT_HARDWARE_ADDRESS_LENGTH ]; /**< The client hardware address. */
uint8_t ucServerHostName[ dhcpSERVER_HOST_NAME_LENGTH ]; /**< Server's hostname. */
uint8_t ucBootFileName[ dhcpBOOT_FILE_NAME_LENGTH ]; /**< Boot file full directory path. */
uint32_t ulDHCPCookie; /**< Magic cookie option. */
/* Option bytes from here on. */
}
#include "pack_struct_end.h"
typedef struct xDHCPMessage_IPv4 DHCPMessage_IPv4_t;
#if ( ipconfigUSE_DHCP_HOOK != 0 )
/* Used in the DHCP callback if ipconfigUSE_DHCP_HOOK is set to 1. */
typedef enum eDHCP_PHASE
{
eDHCPPhasePreDiscover, /**< Driver is about to send a DHCP discovery. */
eDHCPPhasePreRequest /**< Driver is about to request DHCP an IP address. */
} eDHCPCallbackPhase_t;
/** @brief Used in the DHCP callback if ipconfigUSE_DHCP_HOOK is set to 1. */
typedef enum eDHCP_ANSWERS
{
eDHCPContinue, /**< Continue the DHCP process */
eDHCPUseDefaults, /**< Stop DHCP and use the static defaults. */
eDHCPStopNoChanges, /**< Stop DHCP and continue with current settings. */
} eDHCPCallbackAnswer_t;
#endif /* #if( ipconfigUSE_DHCP_HOOK != 0 ) */
/** @brief DHCP state machine states. */
typedef enum
{
eInitialWait = 0, /**< Initial state: open a socket and wait a short time. */
eWaitingSendFirstDiscover, /**< Send a discover the first time it is called, and reset all timers. */
eWaitingOffer, /**< Either resend the discover, or, if the offer is forthcoming, send a request. */
eWaitingAcknowledge, /**< Either resend the request. */
eSendDHCPRequest, /**< Sendto failed earlier, resend the request to lease the IP-address offered. */
#if ( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
eGetLinkLayerAddress, /**< When DHCP didn't respond, try to obtain a LinkLayer address 168.254.x.x. */
#endif
eLeasedAddress, /**< Resend the request at the appropriate time to renew the lease. */
eNotUsingLeasedAddress /**< DHCP failed, and a default IP address is being used. */
} eDHCPState_t;
/** @brief Hold information in between steps in the DHCP state machine. */
struct xDHCP_DATA
{
uint32_t ulTransactionId; /**< The ID of the DHCP transaction */
uint32_t ulOfferedIPAddress; /**< The IP address offered by the DHCP server */
uint32_t ulPreferredIPAddress; /**< A preferred IP address */
uint32_t ulDHCPServerAddress; /**< The IP address of the DHCP server */
uint32_t ulLeaseTime; /**< The time for which the current IP address is leased */
TickType_t xDHCPTxTime; /**< The time at which a DHCP request was sent. */
TickType_t xDHCPTxPeriod; /**< The maximum time that the client will wait for a reply. */
BaseType_t xUseBroadcast; /**< Try both without and with the broadcast flag */
eDHCPState_t eDHCPState; /**< Maintains the DHCP state machine state. */
};
typedef struct xDHCP_DATA DHCPData_t;
/* Returns the current state of a DHCP process. */
eDHCPState_t eGetDHCPState( void );
/*
* NOT A PUBLIC API FUNCTION.
* It will be called when the DHCP timer expires, or when
* data has been received on the DHCP socket.
*/
void vDHCPProcess( BaseType_t xReset,
eDHCPState_t eExpectedState );
/* Internal call: returns true if socket is the current DHCP socket */
BaseType_t xIsDHCPSocket( const ConstSocket_t xSocket );
/* The application can indicate a preferred IP address by calling this function
* before FreeRTOS_IPInit() is called. */
uint32_t vDHCPSetPreferredIPAddress( uint32_t ulIPAddress );
#if ( ipconfigUSE_DHCP_HOOK != 0 )
/* Prototype of the hook (or callback) function that must be provided by the
* application if ipconfigUSE_DHCP_HOOK is set to 1. See the following URL for
* usage information:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html#ipconfigUSE_DHCP_HOOK
*/
eDHCPCallbackAnswer_t xApplicationDHCPHook( eDHCPCallbackPhase_t eDHCPPhase,
uint32_t ulIPAddress );
#endif /* ( ipconfigUSE_DHCP_HOOK != 0 ) */
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_DHCP_H */

View File

@ -0,0 +1,102 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://github.com/FreeRTOS
* https://www.FreeRTOS.org
*/
#ifndef FREERTOS_DNS_H
#define FREERTOS_DNS_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* Application level configuration options. */
#include "FreeRTOS_DNS_Globals.h"
#include "FreeRTOS_DNS_Callback.h"
#include "FreeRTOS_DNS_Cache.h"
/*
* LLMNR is very similar to DNS, so is handled by the DNS routines.
*/
uint32_t ulDNSHandlePacket( const NetworkBufferDescriptor_t * pxNetworkBuffer );
#if ( ipconfigUSE_LLMNR == 1 )
/* The LLMNR MAC address is 01:00:5e:00:00:fc */
extern const MACAddress_t xLLMNR_MacAdress;
#endif /* ipconfigUSE_LLMNR */
#if ( ipconfigUSE_NBNS != 0 )
/*
* Inspect a NetBIOS Names-Service message. If the name matches with ours
* (xApplicationDNSQueryHook returns true) an answer will be sent back.
* Note that LLMNR is a better protocol for name services on a LAN as it is
* less polluted
*/
uint32_t ulNBNSHandlePacket( NetworkBufferDescriptor_t * pxNetworkBuffer );
#endif /* ipconfigUSE_NBNS */
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
/*
* Asynchronous version of gethostbyname()
* xTimeout is in units of ms.
*/
uint32_t FreeRTOS_gethostbyname_a( const char * pcHostName,
FOnDNSEvent pCallback,
void * pvSearchID,
TickType_t uxTimeout );
void FreeRTOS_gethostbyname_cancel( void * pvSearchID );
#endif /* if ( ipconfigDNS_USE_CALLBACKS != 0 ) */
/*
* Lookup a IPv4 node in a blocking-way.
* It returns a 32-bit IP-address, 0 when not found.
* gethostbyname() is already deprecated.
*/
uint32_t FreeRTOS_gethostbyname( const char * pcHostName );
#if ( ipconfigDNS_USE_CALLBACKS == 1 )
/*
* The function vDNSInitialise() initialises the DNS module.
* It will be called "internally", by the IP-task.
*/
void vDNSInitialise( void );
#endif /* ( ipconfigDNS_USE_CALLBACKS == 1 ) */
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_DNS_H */

View File

@ -0,0 +1,56 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://github.com/FreeRTOS
* https://www.FreeRTOS.org
*/
#ifndef FREERTOS_DNS_CACHE_H
#define FREERTOS_DNS_CACHE_H
/* FreeRTOS includes. */
#include "FreeRTOS.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
/* Standard includes. */
#include <stdint.h>
#if ( ( ipconfigUSE_DNS_CACHE == 1 ) && ( ipconfigUSE_DNS != 0 ) )
uint32_t FreeRTOS_dnslookup( const char * pcHostName );
void FreeRTOS_dnsclear( void );
BaseType_t FreeRTOS_dns_update( const char * pcName,
uint32_t * pulIP,
uint32_t ulTTL );
BaseType_t FreeRTOS_ProcessDNSCache( const char * pcName,
uint32_t * pulIP,
uint32_t ulTTL,
BaseType_t xLookUp );
#endif /* if ( ipconfigUSE_DNS_CACHE == 1 ) */
#endif /* ifndef FREERTOS_DNS_CACHE_H */

View File

@ -0,0 +1,75 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://github.com/FreeRTOS
* https://www.FreeRTOS.org
*/
#ifndef FREERTOS_DNS_CALLBACK_H
#define FREERTOS_DNS_CALLBACK_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* FreeRTOS includes. */
#include "FreeRTOS.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_DNS_Globals.h"
/* Standard includes. */
#include <stdint.h>
/* Application level configuration options. */
#if ( ( ipconfigDNS_USE_CALLBACKS == 1 ) && ( ipconfigUSE_DNS != 0 ) )
BaseType_t xDNSDoCallback( TickType_t uxIdentifier,
const char * pcName,
uint32_t ulIPAddress );
void vDNSSetCallBack( const char * pcHostName,
void * pvSearchID,
FOnDNSEvent pCallbackFunction,
TickType_t uxTimeout,
TickType_t uxIdentifier );
void vDNSCheckCallBack( void * pvSearchID );
void vDNSCallbackInitialise();
#endif /* ipconfigDNS_USE_CALLBACKS && ipconfigUSE_DNS */
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* ifndef FREERTOS_DNS_CALLBACK_H */

View File

@ -0,0 +1,251 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef FREERTOS_DNS_GLOBALS_H
#define FREERTOS_DNS_GLOBALS_H
#include "FreeRTOS.h"
#include "FreeRTOSIPConfig.h"
#include "FreeRTOSIPConfigDefaults.h"
#include "IPTraceMacroDefaults.h"
/* Standard includes. */
#define dnsPARSE_ERROR 0UL
#if ( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
#define dnsDNS_PORT 0x3500U /**< Little endian: Port used for DNS. */
#define dnsONE_QUESTION 0x0100U /**< Little endian representation of a DNS question.*/
#define dnsOUTGOING_FLAGS 0x0001U /**< Little endian representation of standard query. */
#define dnsRX_FLAGS_MASK 0x0f80U /**< Little endian: The bits of interest in the flags field of incoming DNS messages. */
#define dnsEXPECTED_RX_FLAGS 0x0080U /**< Little Endian: Should be a response, without any errors. */
#else
#define dnsDNS_PORT 0x0035U /**< Big endian: Port used for DNS. */
#define dnsONE_QUESTION 0x0001U /**< Big endian representation of a DNS question.*/
#define dnsOUTGOING_FLAGS 0x0100U /**< Big endian representation of standard query. */
#define dnsRX_FLAGS_MASK 0x800fU /**< Big endian: The bits of interest in the flags field of incoming DNS messages. */
#define dnsEXPECTED_RX_FLAGS 0x8000U /**< Big endian: Should be a response, without any errors. */
#endif /* ipconfigBYTE_ORDER */
#if ( ipconfigUSE_DNS != 0 )
/** @brief 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 )
/** @brief 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
#endif
/* NBNS flags. */
#if ( ipconfigUSE_NBNS == 1 )
#define dnsNBNS_FLAGS_RESPONSE 0x8000U /**< NBNS response flag. */
#define dnsNBNS_FLAGS_OPCODE_MASK 0x7800U /**< NBNS opcode bitmask. */
#define dnsNBNS_FLAGS_OPCODE_QUERY 0x0000U /**< NBNS opcode query. */
#endif /* ( ipconfigUSE_NBNS == 1 ) */
/* Host types. */
#define dnsTYPE_A_HOST 0x01U /**< DNS type A host. */
#define dnsCLASS_IN 0x01U /**< DNS class IN (Internet). */
/* Maximum hostname length as defined in RFC 1035 section 3.1. */
#define dnsMAX_HOSTNAME_LENGTH 0xFFU
#ifndef _lint
/* LLMNR constants. */
#define dnsLLMNR_TTL_VALUE 300U /**< LLMNR time to live value of 5 minutes. */
#define dnsLLMNR_FLAGS_IS_REPONSE 0x8000U /**< LLMNR flag value for response. */
#endif /* _lint */
/* NBNS constants. */
#if ( ipconfigUSE_NBNS != 0 )
#define dnsNBNS_TTL_VALUE 3600UL /**< NBNS TTL: 1 hour valid. */
#define dnsNBNS_TYPE_NET_BIOS 0x0020U /**< NBNS Type: NetBIOS. */
#define dnsNBNS_CLASS_IN 0x01U /**< NBNS Class: IN (Internet). */
#define dnsNBNS_NAME_FLAGS 0x6000U /**< NBNS name flags. */
#define dnsNBNS_ENCODED_NAME_LENGTH 32 /**< NBNS encoded name length. */
/** @brief 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 ( 0x8500U )
#endif /* ( ipconfigUSE_NBNS != 0 ) */
#ifndef _lint
#if ( ipconfigUSE_DNS_CACHE == 0 )
#if ( ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY != 1 )
#error When DNS caching is disabled, please make ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY equal to 1.
#endif
#endif
#endif
/** @brief Define the ASCII value of '.' (Period/Full-stop). */
#define ASCII_BASELINE_DOT 46U
/* The Link-local Multicast Name Resolution (LLMNR)
* is included.
* Note that a special MAC address is required in addition to the NIC's actual
* MAC address: 01:00:5E:00:00:FC
*
* The target IP address will be 224.0.0.252
*/
#if ( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN )
#define ipLLMNR_IP_ADDR 0xE00000FCUL
#else
#define ipLLMNR_IP_ADDR 0xFC0000E0UL
#endif /* ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN */
#define ipLLMNR_PORT 5355 /* Standard LLMNR port. */
#define ipDNS_PORT 53 /* Standard DNS port. */
#define ipDHCP_CLIENT 67
#define ipDHCP_SERVER 68
#define ipNBNS_PORT 137 /* NetBIOS Name Service. */
#define ipNBDGM_PORT 138 /* Datagram Service, not included. */
/* DNS answer record header. */
#include "pack_struct_start.h"
struct xDNSAnswerRecord
{
uint16_t usType; /**< Type of DNS answer record. */
uint16_t usClass; /**< Class of DNS answer record. */
uint32_t ulTTL; /**< Number of seconds the result can be cached. */
uint16_t usDataLength; /**< Length of the data field. */
}
#include "pack_struct_end.h"
typedef struct xDNSAnswerRecord DNSAnswerRecord_t;
/* Below #include just tells the compiler to pack the structure.
* It is included in to make the code more readable */
#include "pack_struct_start.h"
struct xDNSMessage
{
uint16_t usIdentifier; /**< Query identifier. Used to match up replies to outstanding queries. */
uint16_t usFlags; /**< Flags. */
uint16_t usQuestions; /**< Number of questions asked in this query. */
uint16_t usAnswers; /**< Number of answers being provided in this query. */
uint16_t usAuthorityRRs; /**< Authoritative name server resource records. */
uint16_t usAdditionalRRs; /**< Additional resource records.*/
}
#include "pack_struct_end.h"
typedef struct xDNSMessage DNSMessage_t;
#if ( ipconfigUSE_LLMNR == 1 )
#include "pack_struct_start.h"
struct xLLMNRAnswer
{
uint8_t ucNameCode; /**< Name type. */
uint8_t ucNameOffset; /**< The name is not repeated in the answer, only the offset is given with "0xc0 <offs>" */
uint16_t usType; /**< Type of the Resource record. */
uint16_t usClass; /**< Class of the Resource record. */
uint32_t ulTTL; /**< Seconds till this entry can be cached. */
uint16_t usDataLength; /**< Length of the address in this record. */
uint32_t ulIPAddress; /**< The IP-address. */
}
#include "pack_struct_end.h"
typedef struct xLLMNRAnswer LLMNRAnswer_t;
#endif /* if ( ipconfigUSE_LLMNR == 1 ) */
#if ( ipconfigUSE_NBNS == 1 )
#include "pack_struct_start.h"
struct xNBNSRequest
{
uint16_t usRequestId; /**< NBNS request ID. */
uint16_t usFlags; /**< Flags of the DNS message. */
uint16_t ulRequestCount; /**< The number of requests/questions in this query. */
uint16_t usAnswerRSS; /**< The number of answers in this query. */
uint16_t usAuthRSS; /**< Number of authoritative resource records. */
uint16_t usAdditionalRSS; /**< Number of additional resource records. */
uint8_t ucNameSpace; /**< Length of name. */
uint8_t ucName[ dnsNBNS_ENCODED_NAME_LENGTH ]; /**< The domain name. */
uint8_t ucNameZero; /**< Terminator of the name. */
uint16_t usType; /**< Type of NBNS record. */
uint16_t usClass; /**< Class of NBNS request. */
}
#include "pack_struct_end.h"
typedef struct xNBNSRequest NBNSRequest_t;
#include "pack_struct_start.h"
struct xNBNSAnswer
{
uint16_t usType; /**< Type of NBNS answer. */
uint16_t usClass; /**< Class of NBNS answer. */
uint32_t ulTTL; /**< Time in seconds for which the answer can be cached. */
uint16_t usDataLength; /**< Data length. */
uint16_t usNbFlags; /**< NetBIOS flags 0x6000 : IP-address, big-endian. */
uint32_t ulIPAddress; /**< The IPv4 address. */
}
#include "pack_struct_end.h"
typedef struct xNBNSAnswer NBNSAnswer_t;
#endif /* if ( ipconfigUSE_NBNS == 1 ) */
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
/*
* Users may define this type of function as a callback.
* It will be called when a DNS reply is received or when a timeout has been reached.
*/
typedef void (* FOnDNSEvent ) ( const char * /* pcName */,
void * /* pvSearchID */,
uint32_t /* ulIPAddress */ );
/** @brief The structure to hold information for a DNS callback. */
typedef struct xDNS_Callback
{
TickType_t uxRemainingTime; /**< Timeout in ms */
FOnDNSEvent pCallbackFunction; /**< Function to be called when the address has been found or when a timeout has been reached */
TimeOut_t uxTimeoutState; /**< Timeout state. */
void * pvSearchID; /**< Search ID of the callback function. */
struct xLIST_ITEM xListItem; /**< List struct. */
char pcName[ 1 ]; /**< 1 character name. */
} DNSCallback_t;
#endif /* if ( ipconfigDNS_USE_CALLBACKS != 0 ) */
/**
* @brief structure to hold the buffer, its size and the data length
*/
typedef struct xDNSBuffer
{
uint8_t * pucPayloadBuffer; /**< Buffer pointer */
size_t uxPayloadLength; /**< Payload size */
size_t uxPayloadSize; /**< Total buffer size */
} DNSBuffer_t;
#if ( ipconfigUSE_LLMNR == 1 ) || ( ipconfigUSE_NBNS == 1 )
/*
* The following function should be provided by the user and return true if it
* matches the domain name.
*/
extern BaseType_t xApplicationDNSQueryHook( const char * pcName );
#endif /* ( ipconfigUSE_LLMNR == 1 ) || ( ipconfigUSE_NBNS == 1 ) */
#endif /* ipconfigUSE_DNS */
#endif /* ifndef FREERTOS_DNS_GLOBALS_H */

View File

@ -0,0 +1,51 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://github.com/FreeRTOS
* https://www.FreeRTOS.org
*/
#ifndef FREERTOS_DNS_NETWORKING_H
#define FREERTOS_DNS_NETWORKING_H
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_DNS_Globals.h"
#if ( ipconfigUSE_DNS != 0 )
/*
* Create a socket and bind it to the standard DNS port number. Return the
* the created socket - or NULL if the socket could not be created or bound.
*/
Socket_t DNS_CreateSocket( TickType_t uxReadTimeOut_ticks );
BaseType_t DNS_SendRequest( Socket_t xDNSSocket,
const struct freertos_sockaddr * xAddress,
const struct xDNSBuffer * pxDNSBuf );
void DNS_ReadReply( const ConstSocket_t xDNSSocket,
struct freertos_sockaddr * xAddress,
struct xDNSBuffer * pxReceiveBuffer );
void DNS_CloseSocket( Socket_t xDNSSocket );
#endif /* if ( ipconfigUSE_DNS != 0 ) */
#endif /* ifndef FREERTOS_DNS_NETWORKING_H */

View File

@ -0,0 +1,93 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://github.com/FreeRTOS
* https://www.FreeRTOS.org
*/
#ifndef FREERTOS_DNS_PARSER_H
#define FREERTOS_DNS_PARSER_H
/* FreeRTOS includes. */
#include "FreeRTOS.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_DNS_Globals.h"
/* Standard includes. */
#include <stdint.h>
#if ( ipconfigUSE_DNS != 0 )
/** @brief Flag DNS parsing errors in situations where an IPv4 address is the return
* type. */
#if ( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 )
size_t DNS_ReadNameField( const uint8_t * pucByte,
size_t uxRemainingBytes,
char * pcName,
size_t uxDestLen );
#endif /* ipconfigUSE_DNS_CACHE || ipconfigDNS_USE_CALLBACKS */
/*
* Simple routine that jumps over the NAME field of a resource record.
* It returns the number of bytes read.
*/
size_t DNS_SkipNameField( const uint8_t * pucByte,
size_t uxLength );
/*
* 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.
*/
uint32_t DNS_ParseDNSReply( uint8_t * pucUDPPayloadBuffer,
size_t uxBufferLength,
BaseType_t xExpected );
/*
* The NBNS and the LLMNR protocol share this reply function.
*/
#if ( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) )
void prepareReplyDNSMessage( NetworkBufferDescriptor_t * pxNetworkBuffer,
BaseType_t lNetLength );
#endif
#if ( ipconfigUSE_NBNS == 1 )
void DNS_TreatNBNS( uint8_t * pucPayload,
size_t uxBufferLength,
uint32_t ulIPAddress );
#endif
uint32_t parseDNSAnswer( const DNSMessage_t * pxDNSMessageHeader,
uint8_t * pucByte,
size_t uxSourceBytesRemaining,
size_t * uxBytesRead
#if ( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 )
,
const char * pcName,
BaseType_t xDoStore
#endif
);
#endif /* if ( ipconfigUSE_DNS != 0 ) */
#endif /* ifndef FREERTOS_DNS_PARSER_H */

View File

@ -0,0 +1,82 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_ICMP.h
* @brief Header file for Internet Control Message Protocol for the FreeRTOS+TCP network stack.
*/
#ifndef FREERTOS_ICMP_H
#define FREERTOS_ICMP_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_ARP.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_DHCP.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
#include "FreeRTOS_DNS.h"
/* ICMP protocol definitions. */
#define ipICMP_ECHO_REQUEST ( ( uint8_t ) 8 ) /**< ICMP echo request. */
#define ipICMP_ECHO_REPLY ( ( uint8_t ) 0 ) /**< ICMP echo reply. */
#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
/*
* Process incoming ICMP packets.
*/
eFrameProcessingResult_t ProcessICMPPacket( const NetworkBufferDescriptor_t * const pxNetworkBuffer );
#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_ICMP_H */

View File

@ -0,0 +1,456 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef FREERTOS_IP_H
#define FREERTOS_IP_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
#include "FreeRTOS.h"
#include "task.h"
/* Application level configuration options. */
#include "FreeRTOSIPConfig.h"
#include "FreeRTOSIPConfigDefaults.h"
#include "IPTraceMacroDefaults.h"
/* Constants defining the current version of the FreeRTOS+TCP
* network stack. */
#define ipFR_TCP_VERSION_NUMBER "V3.1.0"
#define ipFR_TCP_VERSION_MAJOR 3
#define ipFR_TCP_VERSION_MINOR 1
/* Development builds are always version 999. */
#define ipFR_TCP_VERSION_BUILD 0
/* Some constants defining the sizes of several parts of a packet.
* These defines come before including the configuration header files. */
/* The size of the Ethernet header is 14, meaning that 802.1Q VLAN tags
* are not ( yet ) supported. */
#define ipSIZE_OF_ETH_HEADER 14U
#define ipSIZE_OF_IPv4_HEADER 20U
#define ipSIZE_OF_IGMP_HEADER 8U
#define ipSIZE_OF_ICMP_HEADER 8U
#define ipSIZE_OF_UDP_HEADER 8U
#define ipSIZE_OF_TCP_HEADER 20U
#define ipSIZE_OF_IPv4_ADDRESS 4U
/*
* Generate a randomized TCP Initial Sequence Number per RFC.
* This function must be provided by the application builder.
*/
/* This function is defined generally by the application. */
extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress,
uint16_t usSourcePort,
uint32_t ulDestinationAddress,
uint16_t usDestinationPort );
/* The number of octets in the MAC and IP addresses respectively. */
#define ipMAC_ADDRESS_LENGTH_BYTES ( 6U )
#define ipIP_ADDRESS_LENGTH_BYTES ( 4U )
/* IP protocol definitions. */
#define ipPROTOCOL_ICMP ( 1U )
#define ipPROTOCOL_IGMP ( 2U )
#define ipPROTOCOL_TCP ( 6U )
#define ipPROTOCOL_UDP ( 17U )
/* The character used to fill ICMP echo requests, and therefore also the
* character expected to fill ICMP echo replies. */
#define ipECHO_DATA_FILL_BYTE 'x'
/* Dimensions the buffers that are filled by received Ethernet frames. */
#define ipSIZE_OF_ETH_CRC_BYTES ( 4UL )
#define ipSIZE_OF_ETH_OPTIONAL_802_1Q_TAG_BYTES ( 4UL )
#define ipTOTAL_ETHERNET_FRAME_SIZE ( ( ( uint32_t ) ipconfigNETWORK_MTU ) + ( ( uint32_t ) ipSIZE_OF_ETH_HEADER ) + ipSIZE_OF_ETH_CRC_BYTES + ipSIZE_OF_ETH_OPTIONAL_802_1Q_TAG_BYTES )
/* Space left at the beginning of a network buffer storage area to store a
* pointer back to the network buffer. Should be a multiple of 8 to ensure 8 byte
* alignment is maintained on architectures that require it.
*
* In order to get a 32-bit alignment of network packets, an offset of 2 bytes
* would be desirable, as defined by ipconfigPACKET_FILLER_SIZE. So the malloc'd
* buffer will have the following contents:
* uint32_t pointer; // word-aligned
* uchar_8 filler[6];
* << ETH-header >> // half-word-aligned
* uchar_8 dest[6]; // start of pucEthernetBuffer
* uchar_8 dest[6];
* uchar16_t type;
* << IP-header >> // word-aligned
* uint8_t ucVersionHeaderLength;
* etc
*/
#if ( ipconfigBUFFER_PADDING != 0 )
#define ipBUFFER_PADDING ipconfigBUFFER_PADDING
#else
#define ipBUFFER_PADDING ( 8U + ipconfigPACKET_FILLER_SIZE )
#endif
/* The offset of ucTCPFlags within the TCP header. */
#define ipTCP_FLAGS_OFFSET 13U
#define ipFIRST_LOOPBACK_IPv4 0x7F000000UL /**< Lowest IPv4 loopback address (including). */
#define ipLAST_LOOPBACK_IPv4 0x80000000UL /**< Highest IPv4 loopback address (excluding). */
/** @brief Returned to indicate a valid checksum. */
#define ipCORRECT_CRC 0xffffU
/** @brief Returned to indicate incorrect checksum. */
#define ipWRONG_CRC 0x0000U
/** @brief Returned as the (invalid) checksum when the length of the data being checked
* had an invalid length. */
#define ipINVALID_LENGTH 0x1234U
/** @brief Returned as the (invalid) checksum when the protocol being checked is not
* handled. The value is chosen simply to be easy to spot when debugging. */
#define ipUNHANDLED_PROTOCOL 0x4321U
/** @brief The maximum time the IP task is allowed to remain in the Blocked state if no
* events are posted to the network event queue. */
#ifndef ipconfigMAX_IP_TASK_SLEEP_TIME
#define ipconfigMAX_IP_TASK_SLEEP_TIME ( pdMS_TO_TICKS( 10000UL ) )
#endif
/* Trace macros to aid in debugging, disabled if ipconfigHAS_PRINTF != 1 */
#if ( ipconfigHAS_PRINTF == 1 )
#define DEBUG_DECLARE_TRACE_VARIABLE( type, var, init ) type var = ( init ) /**< Trace macro to set "type var = init". */
#define DEBUG_SET_TRACE_VARIABLE( var, value ) var = ( value ) /**< Trace macro to set var = value. */
#else
#define DEBUG_DECLARE_TRACE_VARIABLE( type, var, init ) /**< Empty definition since ipconfigHAS_PRINTF != 1. */
#define DEBUG_SET_TRACE_VARIABLE( var, value ) /**< Empty definition since ipconfigHAS_PRINTF != 1. */
#endif
/**
* The structure used to store buffers and pass them around the network stack.
* Buffers can be in use by the stack, in use by the network interface hardware
* driver, or free (not in use).
*/
typedef struct xNETWORK_BUFFER
{
ListItem_t xBufferListItem; /**< Used to reference the buffer form the free buffer list or a socket. */
uint32_t ulIPAddress; /**< Source or destination IP address, depending on usage scenario. */
uint8_t * pucEthernetBuffer; /**< Pointer to the start of the Ethernet frame. */
size_t xDataLength; /**< Starts by holding the total Ethernet frame length, then the UDP/TCP payload length. */
uint16_t usPort; /**< Source or destination port, depending on usage scenario. */
uint16_t usBoundPort; /**< The port to which a transmitting socket is bound. */
#if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
struct xNETWORK_BUFFER * pxNextBuffer; /**< Possible optimisation for expert users - requires network driver support. */
#endif
} NetworkBufferDescriptor_t;
#include "pack_struct_start.h"
/**
* MAC address structure.
*/
struct xMAC_ADDRESS
{
uint8_t ucBytes[ ipMAC_ADDRESS_LENGTH_BYTES ]; /**< Byte array of the MAC address */
}
#include "pack_struct_end.h"
typedef struct xMAC_ADDRESS MACAddress_t;
typedef enum eNETWORK_EVENTS
{
eNetworkUp, /* The network is configured. */
eNetworkDown /* The network connection has been lost. */
} eIPCallbackEvent_t;
/* MISRA check: some modules refer to this typedef even though
* ipconfigSUPPORT_OUTGOING_PINGS is not enabled. */
typedef enum ePING_REPLY_STATUS
{
eSuccess = 0, /**< A correct reply has been received for an outgoing ping. */
eInvalidChecksum, /**< A reply was received for an outgoing ping but the checksum of the reply was incorrect. */
eInvalidData /**< A reply was received to an outgoing ping but the payload of the reply was not correct. */
} ePingReplyStatus_t;
/**
* The software timer struct for various IP functions
*/
typedef struct xIP_TIMER
{
uint32_t
bActive : 1, /**< This timer is running and must be processed. */
bExpired : 1; /**< Timer has expired and a task must be processed. */
TimeOut_t xTimeOut; /**< The timeout value. */
TickType_t ulRemainingTime; /**< The amount of time remaining. */
TickType_t ulReloadTime; /**< The value of reload time. */
} IPTimer_t;
/* Endian related definitions. */
#if ( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
/* FreeRTOS_htons / FreeRTOS_htonl: some platforms might have built-in versions
* using a single instruction so allow these versions to be overridden. */
#ifndef FreeRTOS_htons
#define FreeRTOS_htons( usIn ) ( ( uint16_t ) ( ( ( usIn ) << 8U ) | ( ( usIn ) >> 8U ) ) )
#endif
#ifndef FreeRTOS_htonl
#define FreeRTOS_htonl( ulIn ) \
( \
( uint32_t ) \
( \
( ( ( ( uint32_t ) ( ulIn ) ) ) << 24 ) | \
( ( ( ( uint32_t ) ( ulIn ) ) & 0x0000ff00U ) << 8 ) | \
( ( ( ( uint32_t ) ( ulIn ) ) & 0x00ff0000U ) >> 8 ) | \
( ( ( ( uint32_t ) ( ulIn ) ) ) >> 24 ) \
) \
)
#endif /* ifndef FreeRTOS_htonl */
#else /* ipconfigBYTE_ORDER */
#define FreeRTOS_htons( x ) ( ( uint16_t ) ( x ) )
#define FreeRTOS_htonl( x ) ( ( uint32_t ) ( x ) )
#endif /* ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN */
#define FreeRTOS_ntohs( x ) FreeRTOS_htons( x )
#define FreeRTOS_ntohl( x ) FreeRTOS_htonl( x )
/* Some simple helper functions. */
int32_t FreeRTOS_max_int32( int32_t a,
int32_t b );
uint32_t FreeRTOS_max_uint32( uint32_t a,
uint32_t b );
size_t FreeRTOS_max_size_t( size_t a,
size_t b );
int32_t FreeRTOS_min_int32( int32_t a,
int32_t b );
uint32_t FreeRTOS_min_uint32( uint32_t a,
uint32_t b );
size_t FreeRTOS_min_size_t( size_t a,
size_t b );
uint32_t FreeRTOS_round_up( uint32_t a,
uint32_t d );
uint32_t FreeRTOS_round_down( uint32_t a,
uint32_t d );
#define ipMS_TO_MIN_TICKS( xTimeInMs ) ( ( pdMS_TO_TICKS( ( xTimeInMs ) ) < ( ( TickType_t ) 1U ) ) ? ( ( TickType_t ) 1U ) : pdMS_TO_TICKS( ( xTimeInMs ) ) )
/* For backward compatibility. */
#define pdMS_TO_MIN_TICKS( xTimeInMs ) ipMS_TO_MIN_TICKS( xTimeInMs )
#ifndef pdTRUE_SIGNED
/* Temporary solution: eventually the defines below will appear in 'Source\include\projdefs.h' */
#define pdTRUE_SIGNED pdTRUE
#define pdFALSE_SIGNED pdFALSE
#define pdTRUE_UNSIGNED ( 1U )
#define pdFALSE_UNSIGNED ( 0U )
#define ipTRUE_BOOL ( 1 == 1 )
#define ipFALSE_BOOL ( 1 == 2 )
#endif
/*
* FULL, UP-TO-DATE AND MAINTAINED REFERENCE DOCUMENTATION FOR ALL THESE
* FUNCTIONS IS AVAILABLE ON THE FOLLOWING URL:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/FreeRTOS_TCP_API_Functions.html
*/
BaseType_t FreeRTOS_IPInit( const uint8_t ucIPAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
const uint8_t ucNetMask[ ipIP_ADDRESS_LENGTH_BYTES ],
const uint8_t ucGatewayAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
const uint8_t ucDNSServerAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] );
TaskHandle_t FreeRTOS_GetIPTaskHandle( void );
void * FreeRTOS_GetUDPPayloadBuffer( size_t uxRequestedSizeBytes,
TickType_t uxBlockTimeTicks );
void FreeRTOS_GetAddressConfiguration( uint32_t * pulIPAddress,
uint32_t * pulNetMask,
uint32_t * pulGatewayAddress,
uint32_t * pulDNSServerAddress );
void FreeRTOS_SetAddressConfiguration( const uint32_t * pulIPAddress,
const uint32_t * pulNetMask,
const uint32_t * pulGatewayAddress,
const uint32_t * pulDNSServerAddress );
/* MISRA defining 'FreeRTOS_SendPingRequest' should be dependent on 'ipconfigSUPPORT_OUTGOING_PINGS'.
* In order not to break some existing project, define it unconditionally. */
BaseType_t FreeRTOS_SendPingRequest( uint32_t ulIPAddress,
size_t uxNumberOfBytesToSend,
TickType_t uxBlockTimeTicks );
void FreeRTOS_ReleaseUDPPayloadBuffer( void const * pvBuffer );
const uint8_t * FreeRTOS_GetMACAddress( void );
void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] );
#if ( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )
/* This function shall be defined by the application. */
void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent );
#endif
#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
void vApplicationPingReplyHook( ePingReplyStatus_t eStatus,
uint16_t usIdentifier );
#endif
uint32_t FreeRTOS_GetIPAddress( void );
void FreeRTOS_SetIPAddress( uint32_t ulIPAddress );
void FreeRTOS_SetNetmask( uint32_t ulNetmask );
void FreeRTOS_SetGatewayAddress( uint32_t ulGatewayAddress );
uint32_t FreeRTOS_GetGatewayAddress( void );
uint32_t FreeRTOS_GetDNSServerAddress( void );
uint32_t FreeRTOS_GetNetmask( void );
BaseType_t xARPWaitResolution( uint32_t ulIPAddress,
TickType_t uxTicksToWait );
BaseType_t FreeRTOS_IsNetworkUp( void );
#if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
UBaseType_t uxGetMinimumIPQueueSpace( void );
#endif
BaseType_t xIsNetworkDownEventPending( void );
/*
* Defined in FreeRTOS_Sockets.c
* //_RB_ Don't think this comment is correct. If this is for internal use only it should appear after all the public API functions and not start with FreeRTOS_.
* Socket has had activity, reset the timer so it will not be closed
* because of inactivity
*/
#if ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
const char * FreeRTOS_GetTCPStateName( UBaseType_t ulState );
#endif
/* _HT_ Temporary: show all valid ARP entries
*/
#if ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 )
void FreeRTOS_PrintARPCache( void );
#endif
void FreeRTOS_ClearARP( void );
/* Return pdTRUE if the IPv4 address is a multicast address. */
BaseType_t xIsIPv4Multicast( uint32_t ulIPAddress );
/* Set the MAC-address that belongs to a given IPv4 multi-cast address. */
void vSetMultiCastIPv4MacAddress( uint32_t ulIPAddress,
MACAddress_t * pxMACAddress );
#if ( ipconfigDHCP_REGISTER_HOSTNAME == 1 )
/* DHCP has an option for clients to register their hostname. It doesn't
* have much use, except that a device can be found in a router along with its
* name. If this option is used the callback below must be provided by the
* application writer to return a const string, denoting the device's name. */
/* Typically this function is defined in a user module. */
const char * pcApplicationHostnameHook( 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. */
/* "xApplicationGetRandomNumber" is declared but never defined, because it may
* be defined in a user module. */
BaseType_t xApplicationGetRandomNumber( uint32_t * pulNumber );
/** @brief The pointer to buffer with packet waiting for ARP resolution. This variable
* is defined in FreeRTOS_IP.c.
* This pointer is for internal use only. */
extern NetworkBufferDescriptor_t * pxARPWaitingNetworkBuffer;
/* For backward compatibility define old structure names to the newer equivalent
* structure name. */
#ifndef ipconfigENABLE_BACKWARD_COMPATIBILITY
#define ipconfigENABLE_BACKWARD_COMPATIBILITY 1
#endif
#if ( ipconfigENABLE_BACKWARD_COMPATIBILITY == 1 )
#define xIPStackEvent_t IPStackEvent_t
#define xNetworkBufferDescriptor_t NetworkBufferDescriptor_t
#define xMACAddress_t MACAddress_t
#define xWinProperties_t WinProperties_t
#define xSocket_t Socket_t
#define xSocketSet_t SocketSet_t
#define ipSIZE_OF_IP_HEADER ipSIZE_OF_IPv4_HEADER
/* Since August 2016, the public types and fields below have changed name:
* abbreviations TCP/UDP are now written in capitals, and type names now end with "_t". */
#define FOnConnected FOnConnected_t
#define FOnTcpReceive FOnTCPReceive_t
#define FOnTcpSent FOnTCPSent_t
#define FOnUdpReceive FOnUDPReceive_t
#define FOnUdpSent FOnUDPSent_t
#define pOnTcpConnected pxOnTCPConnected
#define pOnTcpReceive pxOnTCPReceive
#define pOnTcpSent pxOnTCPSent
#define pOnUdpReceive pxOnUDPReceive
#define pOnUdpSent pxOnUDPSent
#define FOnUdpSent FOnUDPSent_t
#define FOnTcpSent FOnTCPSent_t
#endif /* ipconfigENABLE_BACKWARD_COMPATIBILITY */
#if ( ipconfigHAS_PRINTF != 0 )
extern void vPrintResourceStats( void );
#else
#define vPrintResourceStats() do {} while( ipFALSE_BOOL ) /**< ipconfigHAS_PRINTF is not defined. Define vPrintResourceStats to a do-while( 0 ). */
#endif
#if ( ipconfigUSE_TCP != 0 )
/** @brief Set to a non-zero value if one or more TCP message have been processed
* within the last round. */
extern BaseType_t xProcessedTCPMessage;
#endif
#include "FreeRTOS_IP_Utils.h"
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_IP_H */

View File

@ -0,0 +1,857 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*/
#ifndef FREERTOS_IP_PRIVATE_H
#define FREERTOS_IP_PRIVATE_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* Application level configuration options. */
#include "FreeRTOSIPConfig.h"
#include "FreeRTOSIPConfigDefaults.h"
#include "FreeRTOS_Sockets.h"
#include "IPTraceMacroDefaults.h"
#include "FreeRTOS_Stream_Buffer.h"
#if ( ipconfigUSE_TCP == 1 )
#include "FreeRTOS_TCP_WIN.h"
#include "FreeRTOS_TCP_IP.h"
#endif
#include "semphr.h"
#include "event_groups.h"
#ifdef TEST
int ipFOREVER( void );
#else
#define ipFOREVER() 1
#endif
/**
* Structure to hold the information about the Network parameters.
*/
typedef struct xNetworkAddressingParameters
{
uint32_t ulDefaultIPAddress; /**< The default IP address */
uint32_t ulNetMask; /**< The netmask */
uint32_t ulGatewayAddress; /**< The gateway address */
uint32_t ulDNSServerAddress; /**< The DNS server address */
uint32_t ulBroadcastAddress; /**< The Broadcast address */
} NetworkAddressingParameters_t;
extern BaseType_t xTCPWindowLoggingLevel;
extern QueueHandle_t xNetworkEventQueue;
/*-----------------------------------------------------------*/
/* Protocol headers. */
/*-----------------------------------------------------------*/
#include "pack_struct_start.h"
struct xETH_HEADER
{
MACAddress_t xDestinationAddress; /**< Destination address 0 + 6 = 6 */
MACAddress_t xSourceAddress; /**< Source address 6 + 6 = 12 */
uint16_t usFrameType; /**< The EtherType field 12 + 2 = 14 */
}
#include "pack_struct_end.h"
typedef struct xETH_HEADER EthernetHeader_t;
#include "pack_struct_start.h"
struct xARP_HEADER
{
uint16_t usHardwareType; /**< Network Link Protocol type 0 + 2 = 2 */
uint16_t usProtocolType; /**< The internetwork protocol 2 + 2 = 4 */
uint8_t ucHardwareAddressLength; /**< Length in octets of a hardware address 4 + 1 = 5 */
uint8_t ucProtocolAddressLength; /**< Length in octets of the internetwork protocol 5 + 1 = 6 */
uint16_t usOperation; /**< Operation that the sender is performing 6 + 2 = 8 */
MACAddress_t xSenderHardwareAddress; /**< Media address of the sender 8 + 6 = 14 */
uint8_t ucSenderProtocolAddress[ 4 ]; /**< Internetwork address of sender 14 + 4 = 18 */
MACAddress_t xTargetHardwareAddress; /**< Media address of the intended receiver 18 + 6 = 24 */
uint32_t ulTargetProtocolAddress; /**< Internetwork address of the intended receiver 24 + 4 = 28 */
}
#include "pack_struct_end.h"
typedef struct xARP_HEADER ARPHeader_t;
#include "pack_struct_start.h"
struct xIP_HEADER
{
uint8_t ucVersionHeaderLength; /**< The version field + internet header length 0 + 1 = 1 */
uint8_t ucDifferentiatedServicesCode; /**< Differentiated services code point + ECN 1 + 1 = 2 */
uint16_t usLength; /**< Entire Packet size 2 + 2 = 4 */
uint16_t usIdentification; /**< Identification field 4 + 2 = 6 */
uint16_t usFragmentOffset; /**< Fragment flags and fragment offset 6 + 2 = 8 */
uint8_t ucTimeToLive; /**< Time to live field 8 + 1 = 9 */
uint8_t ucProtocol; /**< Protocol used in the IP-datagram 9 + 1 = 10 */
uint16_t usHeaderChecksum; /**< Checksum of the IP-header 10 + 2 = 12 */
uint32_t ulSourceIPAddress; /**< IP address of the source 12 + 4 = 16 */
uint32_t ulDestinationIPAddress; /**< IP address of the destination 16 + 4 = 20 */
}
#include "pack_struct_end.h"
typedef struct xIP_HEADER IPHeader_t;
#include "pack_struct_start.h"
struct xICMP_HEADER
{
uint8_t ucTypeOfMessage; /**< The ICMP type 0 + 1 = 1 */
uint8_t ucTypeOfService; /**< The ICMP subtype 1 + 1 = 2 */
uint16_t usChecksum; /**< The checksum of whole ICMP packet 2 + 2 = 4 */
uint16_t usIdentifier; /**< Used in some types of ICMP 4 + 2 = 6 */
uint16_t usSequenceNumber; /**< Used in some types of ICMP 6 + 2 = 8 */
}
#include "pack_struct_end.h"
typedef struct xICMP_HEADER ICMPHeader_t;
#include "pack_struct_start.h"
struct xUDP_HEADER
{
uint16_t usSourcePort; /**< The source port 0 + 2 = 2 */
uint16_t usDestinationPort; /**< The destination port 2 + 2 = 4 */
uint16_t usLength; /**< The size of the whole UDP packet 4 + 2 = 6 */
uint16_t usChecksum; /**< The checksum of the whole UDP Packet 6 + 2 = 8 */
}
#include "pack_struct_end.h"
typedef struct xUDP_HEADER UDPHeader_t;
#include "pack_struct_start.h"
struct xTCP_HEADER
{
uint16_t usSourcePort; /**< The Source port + 2 = 2 */
uint16_t usDestinationPort; /**< The destination port + 2 = 4 */
uint32_t ulSequenceNumber; /**< The Sequence number + 4 = 8 */
uint32_t ulAckNr; /**< The acknowledgement number + 4 = 12 */
uint8_t ucTCPOffset; /**< The value of TCP offset + 1 = 13 */
uint8_t ucTCPFlags; /**< The TCP-flags field + 1 = 14 */
uint16_t usWindow; /**< The size of the receive window + 2 = 15 */
uint16_t usChecksum; /**< The checksum of the header + 2 = 18 */
uint16_t usUrgent; /**< Pointer to the last urgent data byte + 2 = 20 */
#if ipconfigUSE_TCP == 1
uint8_t ucOptdata[ ipSIZE_TCP_OPTIONS ]; /**< The options + 12 = 32 */
#endif
}
#include "pack_struct_end.h"
typedef struct xTCP_HEADER TCPHeader_t;
/*-----------------------------------------------------------*/
/* Nested protocol packets. */
/*-----------------------------------------------------------*/
#include "pack_struct_start.h"
struct xARP_PACKET
{
EthernetHeader_t xEthernetHeader; /**< The ethernet header of an ARP Packet 0 + 14 = 14 */
ARPHeader_t xARPHeader; /**< The ARP header of an ARP Packet 14 + 28 = 42 */
}
#include "pack_struct_end.h"
typedef struct xARP_PACKET ARPPacket_t;
#include "pack_struct_start.h"
struct xIP_PACKET
{
EthernetHeader_t xEthernetHeader;
IPHeader_t xIPHeader;
}
#include "pack_struct_end.h"
typedef struct xIP_PACKET IPPacket_t;
#include "pack_struct_start.h"
struct xICMP_PACKET
{
EthernetHeader_t xEthernetHeader; /**< The Ethernet header of an ICMP packet. */
IPHeader_t xIPHeader; /**< The IP header of an ICMP packet. */
ICMPHeader_t xICMPHeader; /**< The ICMP header of an ICMP packet. */
}
#include "pack_struct_end.h"
typedef struct xICMP_PACKET ICMPPacket_t;
#include "pack_struct_start.h"
struct xUDP_PACKET
{
EthernetHeader_t xEthernetHeader; /**< UDP-Packet ethernet header 0 + 14 = 14 */
IPHeader_t xIPHeader; /**< UDP-Packet IP header 14 + 20 = 34 */
UDPHeader_t xUDPHeader; /**< UDP-Packet UDP header 34 + 8 = 42 */
}
#include "pack_struct_end.h"
typedef struct xUDP_PACKET UDPPacket_t;
#include "pack_struct_start.h"
struct xTCP_PACKET
{
EthernetHeader_t xEthernetHeader; /**< The ethernet header 0 + 14 = 14 */
IPHeader_t xIPHeader; /**< The IP header 14 + 20 = 34 */
TCPHeader_t xTCPHeader; /**< The TCP header 34 + 32 = 66 */
}
#include "pack_struct_end.h"
typedef struct xTCP_PACKET TCPPacket_t;
/**
* Union for the protocol packet to save space. Any packet cannot have more than one
* of the below protocol packets.
*/
typedef union XPROT_PACKET
{
ARPPacket_t xARPPacket; /**< Union member: ARP packet struct */
TCPPacket_t xTCPPacket; /**< Union member: TCP packet struct */
UDPPacket_t xUDPPacket; /**< Union member: UDP packet struct */
ICMPPacket_t xICMPPacket; /**< Union member: ICMP packet struct */
} ProtocolPacket_t;
/**
* Union for protocol headers to save space (RAM). Any packet cannot have more than one of
* the below protocols.
*/
typedef union xPROT_HEADERS
{
ICMPHeader_t xICMPHeader; /**< Union member: ICMP header */
UDPHeader_t xUDPHeader; /**< Union member: UDP header */
TCPHeader_t xTCPHeader; /**< Union member: TCP header */
} ProtocolHeaders_t;
/* The maximum UDP payload length. */
#define ipMAX_UDP_PAYLOAD_LENGTH ( ( ipconfigNETWORK_MTU - ipSIZE_OF_IPv4_HEADER ) - ipSIZE_OF_UDP_HEADER )
typedef enum
{
eReleaseBuffer = 0, /* Processing the frame did not find anything to do - just release the buffer. */
eProcessBuffer, /* An Ethernet frame has a valid address - continue process its contents. */
eReturnEthernetFrame, /* The Ethernet frame contains an ARP or ICMP packet that can be returned to its source. */
eFrameConsumed, /* Processing the Ethernet packet contents resulted in the payload being sent to the stack. */
eWaitingARPResolution /* Frame is awaiting ARP resolution. */
} eFrameProcessingResult_t;
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. */
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. */
eSocketSetDeleteEvent, /*13: A socket set must be deleted. */
} eIPEvent_t;
/**
* Structure for the information of the commands issued to the IP task.
*/
typedef struct IP_TASK_COMMANDS
{
eIPEvent_t eEventType; /**< The event-type enum */
void * pvData; /**< The data in the event */
} IPStackEvent_t;
#define ipBROADCAST_IP_ADDRESS 0xffffffffU
/* Offset into the Ethernet frame that is used to temporarily store information
* on the fragmentation status of the packet being sent. The value is important,
* as it is past the location into which the destination address will get placed. */
#define ipFRAGMENTATION_PARAMETERS_OFFSET ( 6 )
#define ipSOCKET_OPTIONS_OFFSET ( 6 )
/* The offset into a UDP packet at which the UDP data (payload) starts. */
#define ipUDP_PAYLOAD_OFFSET_IPv4 ( sizeof( UDPPacket_t ) )
/* The offset into an IP packet into which the IP data (payload) starts. */
#define ipIP_PAYLOAD_OFFSET ( sizeof( IPPacket_t ) )
#if ( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
/* Ethernet frame types. */
#define ipARP_FRAME_TYPE ( 0x0608U )
#define ipIPv4_FRAME_TYPE ( 0x0008U )
/* ARP related definitions. */
#define ipARP_PROTOCOL_TYPE ( 0x0008U )
#define ipARP_HARDWARE_TYPE_ETHERNET ( 0x0100U )
#define ipARP_REQUEST ( 0x0100U )
#define ipARP_REPLY ( 0x0200U )
/* The bits in the two byte IP header field that make up the fragment offset value. */
#define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0xff1fU )
/* The bits in the two byte IP header field that make up the flags value. */
#define ipFRAGMENT_FLAGS_BIT_MASK ( ( uint16_t ) 0x00e0U )
/* Don't Fragment Flag */
#define ipFRAGMENT_FLAGS_DONT_FRAGMENT ( ( uint16_t ) 0x0040U )
/* More Fragments Flag */
#define ipFRAGMENT_FLAGS_MORE_FRAGMENTS ( ( uint16_t ) 0x0020U )
#else /* if ( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) */
/* Ethernet frame types. */
#define ipARP_FRAME_TYPE ( 0x0806U )
#define ipIPv4_FRAME_TYPE ( 0x0800U )
/* ARP related definitions. */
#define ipARP_PROTOCOL_TYPE ( 0x0800U )
#define ipARP_HARDWARE_TYPE_ETHERNET ( 0x0001U )
#define ipARP_REQUEST ( 0x0001 )
#define ipARP_REPLY ( 0x0002 )
/* The bits in the two byte IP header field that make up the fragment offset value. */
#define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x1fffU )
/* The bits in the two byte IP header field that make up the flags value. */
#define ipFRAGMENT_FLAGS_BIT_MASK ( ( uint16_t ) 0xe000U )
/* Don't Fragment Flag */
#define ipFRAGMENT_FLAGS_DONT_FRAGMENT ( ( uint16_t ) 0x4000U )
/* More Fragments Flag */
#define ipFRAGMENT_FLAGS_MORE_FRAGMENTS ( ( uint16_t ) 0x2000U )
#endif /* ipconfigBYTE_ORDER */
/* For convenience, a MAC address of all zeros and another of all 0xffs are
* defined const for quick reference. */
extern const MACAddress_t xBroadcastMACAddress; /* all 0xff's */
extern uint16_t usPacketIdentifier;
/** @brief The list that contains mappings between sockets and port numbers.
* Accesses to this list must be protected by critical sections of
* some kind.
*/
extern List_t xBoundUDPSocketsList;
/**
* Define a default UDP packet header (declared in FreeRTOS_UDP_IP.c)
*/
typedef union xUDPPacketHeader
{
uint8_t ucBytes[ 24 ]; /**< Member: 8-bit array */
uint32_t ulWords[ 6 ]; /**< Member: 32-bit array */
} UDPPacketHeader_t;
extern UDPPacketHeader_t xDefaultPartUDPPacketHeader;
/* Structure that stores the netmask, gateway address and DNS server addresses. */
extern NetworkAddressingParameters_t xNetworkAddressing;
/* Structure that stores the defaults for netmask, gateway address and DNS.
* These values will be copied to 'xNetworkAddressing' in case DHCP is not used,
* and also in case DHCP does not lead to a confirmed request. */
/*lint -e9003*/
extern NetworkAddressingParameters_t xDefaultAddressing; /*lint !e9003 could define variable 'xDefaultAddressing' at block scope [MISRA 2012 Rule 8.9, advisory]. */
/* True when BufferAllocation_1.c was included, false for BufferAllocation_2.c */
extern const BaseType_t xBufferAllocFixedSize;
/* Defined in FreeRTOS_Sockets.c */
#if ( ipconfigUSE_TCP == 1 )
extern List_t xBoundTCPSocketsList;
#endif
/* The local IP address is accessed from within xDefaultPartUDPPacketHeader,
* rather than duplicated in its own variable. */
#define ipLOCAL_IP_ADDRESS_POINTER ( ( uint32_t * ) &( xDefaultPartUDPPacketHeader.ulWords[ 20U / sizeof( uint32_t ) ] ) )
/* The local MAC address is accessed from within xDefaultPartUDPPacketHeader,
* rather than duplicated in its own variable. */
#define ipLOCAL_MAC_ADDRESS ( xDefaultPartUDPPacketHeader.ucBytes )
/* ICMP packets are sent using the same function as UDP packets. The port
* number is used to distinguish between the two, as 0 is an invalid UDP port. */
#define ipPACKET_CONTAINS_ICMP_DATA ( 0 )
/* For now, the lower 8 bits in 'xEventBits' will be reserved for the above
* socket events. */
#define SOCKET_EVENT_BIT_COUNT 8
#define vSetField16( pxBase, xType, xField, usValue ) \
{ \
( ( uint8_t * ) ( pxBase ) )[ offsetof( xType, xField ) + 0 ] = ( uint8_t ) ( ( usValue ) >> 8 ); \
( ( uint8_t * ) ( pxBase ) )[ offsetof( xType, xField ) + 1 ] = ( uint8_t ) ( ( usValue ) & 0xffU ); \
}
#define vSetField32( pxBase, xType, xField, ulValue ) \
{ \
( ( uint8_t * ) ( pxBase ) )[ offsetof( xType, xField ) + 0 ] = ( uint8_t ) ( ( ulValue ) >> 24 ); \
( ( uint8_t * ) ( pxBase ) )[ offsetof( xType, xField ) + 1 ] = ( uint8_t ) ( ( ( ulValue ) >> 16 ) & 0xffU ); \
( ( uint8_t * ) ( pxBase ) )[ offsetof( xType, xField ) + 2 ] = ( uint8_t ) ( ( ( ulValue ) >> 8 ) & 0xffU ); \
( ( uint8_t * ) ( pxBase ) )[ offsetof( xType, xField ) + 3 ] = ( uint8_t ) ( ( ulValue ) & 0xffU ); \
}
#define vFlip_16( left, right ) \
do { \
uint16_t tmp = ( left ); \
( left ) = ( right ); \
( right ) = tmp; \
} while( ipFALSE_BOOL )
#define vFlip_32( left, right ) \
do { \
uint32_t tmp = ( left ); \
( left ) = ( right ); \
( right ) = tmp; \
} while( ipFALSE_BOOL )
/* WARNING: Do NOT use this macro when the array was received as a parameter. */
#ifndef ARRAY_SIZE
#define ARRAY_SIZE( x ) ( ( BaseType_t ) ( sizeof( x ) / sizeof( ( x )[ 0 ] ) ) )
#endif
#ifndef ARRAY_USIZE
#define ARRAY_USIZE( x ) ( ( UBaseType_t ) ( sizeof( x ) / sizeof( ( x )[ 0 ] ) ) )
#endif
/*
* Create a message that contains a command to initialise the network interface.
* This is used during initialisation, and at any time the network interface
* goes down thereafter. The network interface hardware driver is responsible
* for sending the message that contains the network interface down command/
* event.
*
* Only use the FreeRTOS_NetworkDownFromISR() version if the function is to be
* called from an interrupt service routine. If FreeRTOS_NetworkDownFromISR()
* returns a non-zero value then a context switch should be performed before
* the interrupt is exited.
*/
void FreeRTOS_NetworkDown( void );
BaseType_t FreeRTOS_NetworkDownFromISR( void );
/*
* Processes incoming ARP packets.
*/
eFrameProcessingResult_t eARPProcessPacket( ARPPacket_t * const pxARPFrame );
/*
* Inspect an Ethernet frame to see if it contains data that the stack needs to
* process. eProcessBuffer is returned if the frame should be processed by the
* stack. eReleaseBuffer is returned if the frame should be discarded.
*/
eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer );
/*
* Return the checksum generated over xDataLengthBytes from pucNextData.
*/
uint16_t usGenerateChecksum( uint16_t usSum,
const uint8_t * pucNextData,
size_t uxByteCount );
/* Socket related private functions. */
/*
* The caller must ensure that pxNetworkBuffer->xDataLength is the UDP packet
* payload size (excluding packet headers) and that the packet in pucEthernetBuffer
* is at least the size of UDPPacket_t.
*/
BaseType_t xProcessReceivedUDPPacket( NetworkBufferDescriptor_t * pxNetworkBuffer,
uint16_t usPort,
BaseType_t * pxIsWaitingForARPResolution );
/*
* Initialize the socket list data structures for TCP and UDP.
*/
void vNetworkSocketsInit( void );
/*
* Returns pdTRUE if the IP task has been created and is initialised. Otherwise
* returns pdFALSE.
*/
BaseType_t xIPIsNetworkTaskReady( void );
#if ( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK == 1 )
struct xSOCKET;
typedef void (* SocketWakeupCallback_t)( struct xSOCKET * pxSocket );
#endif
#if ( ipconfigUSE_TCP == 1 )
/*
* Actually a user thing, but because xBoundTCPSocketsList, let it do by the
* IP-task
*/
#if ( ipconfigHAS_PRINTF != 0 )
void vTCPNetStat( void );
#endif
/*
* At least one socket needs to check for timeouts
*/
TickType_t xTCPTimerCheck( BaseType_t xWillSleep );
/**
* Every TCP socket has a buffer space just big enough to store
* the last TCP header received.
* As a reference of this field may be passed to DMA, force the
* alignment to 8 bytes.
*/
typedef union
{
struct
{
uint64_t ullAlignmentWord; /**< Increase the alignment of this union by adding a 64-bit variable. */
} a; /**< A struct to increase alignment. */
struct
{
/* The next field only serves to give 'ucLastPacket' a correct
* alignment of 8 + 2. See comments in FreeRTOS_IP.h */
uint8_t ucFillPacket[ ipconfigPACKET_FILLER_SIZE ];
uint8_t ucLastPacket[ sizeof( TCPPacket_t ) ];
} u; /**< The structure to give an alignment of 8 + 2 */
} LastTCPPacket_t;
/**
* Note that the values of all short and long integers in these structs
* are being stored in the native-endian way
* Translation should take place when accessing any structure which defines
* network packets, such as IPHeader_t and TCPHeader_t
*/
typedef struct TCPSOCKET
{
uint32_t ulRemoteIP; /**< IP address of remote machine */
uint16_t usRemotePort; /**< Port on remote machine */
struct
{
/* Most compilers do like bit-flags */
uint32_t
bMssChange : 1, /**< This socket has seen a change in MSS */
bPassAccept : 1, /**< when true, this socket may be returned in a call to accept() */
bPassQueued : 1, /**< when true, this socket is an orphan until it gets connected
* Why an orphan? Because it may not be returned in a accept() call until it
* gets the state eESTABLISHED */
bReuseSocket : 1, /**< When a listening socket gets a connection, do not create a new instance but keep on using it */
bCloseAfterSend : 1, /**< As soon as the last byte has been transmitted, finalise the connection
* Useful in e.g. FTP connections, where the last data bytes are sent along with the FIN flag */
bUserShutdown : 1, /**< User requesting a graceful shutdown */
bCloseRequested : 1, /**< Request to finalise the connection */
bLowWater : 1, /**< high-water level has been reached. Cleared as soon as 'rx-count < lo-water' */
bWinChange : 1, /**< The value of bLowWater has changed, must send a window update */
bSendKeepAlive : 1, /**< When this flag is true, a TCP keep-alive message must be send */
bWaitKeepAlive : 1, /**< When this flag is true, a TCP keep-alive reply is expected */
bConnPrepared : 1, /**< Connecting socket: Message has been prepared */
#if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
bConnPassed : 1, /**< Connecting socket: Socket has been passed in a successful select() */
#endif /* ipconfigSUPPORT_SELECT_FUNCTION */
bFinAccepted : 1, /**< This socket has received (or sent) a FIN and accepted it */
bFinSent : 1, /**< We've sent out a FIN */
bFinRecv : 1, /**< We've received a FIN from our peer */
bFinAcked : 1, /**< Our FIN packet has been acked */
bFinLast : 1, /**< The last ACK (after FIN and FIN+ACK) has been sent or will be sent by the peer */
bRxStopped : 1, /**< Application asked to temporarily stop reception */
bMallocError : 1, /**< There was an error allocating a stream */
bWinScaling : 1; /**< A TCP-Window Scaling option was offered and accepted in the SYN phase. */
} bits; /**< The bits structure */
uint32_t ulHighestRxAllowed; /**< The highest sequence number that we can receive at any moment */
uint16_t usTimeout; /**< Time (in ticks) after which this socket needs attention */
uint16_t usMSS; /**< Current Maximum Segment Size */
uint16_t usChildCount; /**< In case of a listening socket: number of connections on this port number */
uint16_t usBacklog; /**< In case of a listening socket: maximum number of concurrent connections on this port number */
uint8_t ucRepCount; /**< Send repeat count, for retransmissions
* This counter is separate from the xmitCount in the
* TCP win segments */
eIPTCPState_t eTCPState; /**< TCP state: see eTCP_STATE */
struct xSOCKET * pxPeerSocket; /**< for server socket: child, for child socket: parent */
#if ( ipconfigTCP_KEEP_ALIVE == 1 )
uint8_t ucKeepRepCount;
TickType_t xLastAliveTime; /**< The last value of keepalive time.*/
#endif /* ipconfigTCP_KEEP_ALIVE */
#if ( ipconfigTCP_HANG_PROTECTION == 1 )
TickType_t xLastActTime; /**< The last time when hang-protection was done.*/
#endif /* ipconfigTCP_HANG_PROTECTION */
size_t uxLittleSpace; /**< The value deemed as low amount of space. */
size_t uxEnoughSpace; /**< The value deemed as enough space. */
size_t uxRxStreamSize; /**< The Receive stream size */
size_t uxTxStreamSize; /**< The transmit stream size */
StreamBuffer_t * rxStream; /**< The pointer to the receive stream buffer. */
StreamBuffer_t * txStream; /**< The pointer to the transmit stream buffer. */
#if ( ipconfigUSE_TCP_WIN == 1 )
NetworkBufferDescriptor_t * pxAckMessage; /**< The pointer to the ACK message */
#endif /* ipconfigUSE_TCP_WIN */
LastTCPPacket_t xPacket; /**< Buffer space to store the last TCP header received. */
uint8_t tcpflags; /**< TCP flags */
#if ( ipconfigUSE_TCP_WIN != 0 )
uint8_t ucMyWinScaleFactor; /**< Scaling factor of this device. */
uint8_t ucPeerWinScaleFactor; /**< Scaling factor of the peer. */
#endif
#if ( ipconfigUSE_CALLBACKS == 1 )
FOnTCPReceive_t pxHandleReceive; /**<
* In case of a TCP socket:
* typedef void (* FOnTCPReceive_t) (Socket_t xSocket, void *pData, size_t xLength );
*/
FOnTCPSent_t pxHandleSent; /**< Function pointer to handle a successful send event. */
FOnConnected_t pxHandleConnected; /**< Actually type: typedef void (* FOnConnected_t) (Socket_t xSocket, BaseType_t ulConnected ); */
#endif /* ipconfigUSE_CALLBACKS */
uint32_t ulWindowSize; /**< Current Window size advertised by peer */
size_t uxRxWinSize; /**< Fixed value: size of the TCP reception window */
size_t uxTxWinSize; /**< Fixed value: size of the TCP transmit window */
TCPWindow_t xTCPWindow; /**< The TCP window struct*/
} IPTCPSocket_t;
#endif /* ipconfigUSE_TCP */
/**
* Structure to hold the information about a UDP socket.
*/
typedef struct UDPSOCKET
{
List_t xWaitingPacketsList; /**< Incoming packets */
#if ( ipconfigUDP_MAX_RX_PACKETS > 0 )
UBaseType_t uxMaxPackets; /**< Protection: limits the number of packets buffered per socket */
#endif /* ipconfigUDP_MAX_RX_PACKETS */
#if ( ipconfigUSE_CALLBACKS == 1 )
FOnUDPReceive_t pxHandleReceive; /**<
* In case of a UDP socket:
* typedef void (* FOnUDPReceive_t) (Socket_t xSocket, void *pData, size_t xLength, struct freertos_sockaddr *pxAddr );
*/
FOnUDPSent_t pxHandleSent; /**< Function pointer to handle the events after a successful send. */
#endif /* ipconfigUSE_CALLBACKS */
} IPUDPSocket_t;
/* Formally typedef'd as eSocketEvent_t. */
enum eSOCKET_EVENT
{
eSOCKET_RECEIVE = 0x0001,
eSOCKET_SEND = 0x0002,
eSOCKET_ACCEPT = 0x0004,
eSOCKET_CONNECT = 0x0008,
eSOCKET_BOUND = 0x0010,
eSOCKET_CLOSED = 0x0020,
eSOCKET_INTR = 0x0040,
eSOCKET_ALL = 0x007F,
};
/**
* Structure to hold information for a socket.
*/
typedef struct xSOCKET
{
EventBits_t xEventBits; /**< The eventbits to keep track of events. */
EventGroupHandle_t xEventGroup; /**< The event group for this socket. */
ListItem_t xBoundSocketListItem; /**< Used to reference the socket from a bound sockets list. */
TickType_t xReceiveBlockTime; /**< if recv[to] is called while no data is available, wait this amount of time. Unit in clock-ticks */
TickType_t xSendBlockTime; /**< if send[to] is called while there is not enough space to send, wait this amount of time. Unit in clock-ticks */
uint16_t usLocalPort; /**< Local port on this machine */
uint8_t ucSocketOptions; /**< Socket options */
uint8_t ucProtocol; /**< choice of FREERTOS_IPPROTO_UDP/TCP */
#if ( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
SemaphoreHandle_t pxUserSemaphore; /**< The user semaphore */
#endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
#if ( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK == 1 )
SocketWakeupCallback_t pxUserWakeCallback; /**< Pointer to the callback function. */
#endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */
#if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
struct xSOCKET_SET * pxSocketSet; /**< Pointer to the socket set structure */
EventBits_t xSelectBits; /**< User may indicate which bits are interesting for this socket. */
EventBits_t xSocketBits; /**< These bits indicate the events which have actually occurred.
* They are maintained by the IP-task */
#endif /* ipconfigSUPPORT_SELECT_FUNCTION */
/* TCP/UDP specific fields: */
/* Before accessing any member of this structure, it should be confirmed */
/* that the protocol corresponds with the type of structure */
union
{
IPUDPSocket_t xUDP; /**< Union member: UDP socket*/
#if ( ipconfigUSE_TCP == 1 )
IPTCPSocket_t xTCP; /**< Union member: TCP socket */
uint64_t ullTCPAlignment; /**< Make sure that xTCP is 8-bytes aligned by
* declaring a 64-bit variable in the same union */
#endif /* ipconfigUSE_TCP */
} u; /**< Union of TCP/UDP socket */
} FreeRTOS_Socket_t;
#if ( ipconfigUSE_TCP == 1 )
/*
* Close the socket another time.
*/
void vSocketCloseNextTime( FreeRTOS_Socket_t * pxSocket );
/*
* Postpone a call to listen() by the IP-task.
*/
void vSocketListenNextTime( FreeRTOS_Socket_t * pxSocket );
/*
* Lookup a TCP socket, using a multiple matching: both port numbers and
* return IP address.
*/
FreeRTOS_Socket_t * pxTCPSocketLookup( uint32_t ulLocalIP,
UBaseType_t uxLocalPort,
uint32_t ulRemoteIP,
UBaseType_t uxRemotePort );
#endif /* ipconfigUSE_TCP */
/*
* Look up a local socket by finding a match with the local port.
*/
FreeRTOS_Socket_t * pxUDPSocketLookup( UBaseType_t uxLocalPort );
/*
* Calculate the upper-layer checksum
* Works both for UDP, ICMP and TCP packages
* bOut = true: checksum will be set in outgoing packets
* bOut = false: checksum will be calculated for incoming packets
* returning 0xffff means: checksum was correct
*/
uint16_t usGenerateProtocolChecksum( uint8_t * pucEthernetBuffer,
size_t uxBufferLength,
BaseType_t xOutgoingPacket );
/*
* An Ethernet frame has been updated (maybe it was an ARP request or a PING
* request?) and is to be sent back to its source.
*/
void vReturnEthernetFrame( NetworkBufferDescriptor_t * pxNetworkBuffer,
BaseType_t xReleaseAfterSend );
/*
* The internal version of bind()
* If 'ulInternal' is true, it is called by the driver
* The TCP driver needs to bind a socket at the moment a listening socket
* creates a new connected socket
*/
BaseType_t vSocketBind( FreeRTOS_Socket_t * pxSocket,
struct freertos_sockaddr * pxBindAddress,
size_t uxAddressLength,
BaseType_t xInternal );
/*
* Internal function to add streaming data to a TCP socket. If ulIn == true,
* data will be added to the rxStream, otherwise to the tXStream. Normally data
* will be written with ulOffset == 0, meaning: at the end of the FIFO. When
* packet come in out-of-order, an offset will be used to put it in front and
* the head will not change yet.
*/
int32_t lTCPAddRxdata( FreeRTOS_Socket_t * pxSocket,
size_t uxOffset,
const uint8_t * pcData,
uint32_t ulByteCount );
/*
* Currently called for any important event.
*/
void vSocketWakeUpUser( FreeRTOS_Socket_t * pxSocket );
/*
* Some helping function, their meaning should be clear.
* Going by MISRA rules, these utility functions should not be defined
* if they are not being used anywhere. But their use depends on the
* application and hence these functions are defined unconditionally.
*/
extern uint32_t ulChar2u32( const uint8_t * pucPtr );
extern uint16_t usChar2u16( const uint8_t * pucPtr );
/* Check a single socket for retransmissions and timeouts */
BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t * pxSocket );
BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t * pxSocket );
/* Defined in FreeRTOS_Sockets.c
* Close a socket
*/
void * vSocketClose( FreeRTOS_Socket_t * pxSocket );
/*
* Send the event eEvent to the IP task event queue, using a block time of
* zero. Return pdPASS if the message was sent successfully, otherwise return
* pdFALSE.
*/
BaseType_t xSendEventToIPTask( eIPEvent_t eEvent );
/*
* The same as above, but a struct as a parameter, containing:
* eIPEvent_t eEventType;
* void *pvData;
*/
BaseType_t xSendEventStructToIPTask( const IPStackEvent_t * pxEvent,
TickType_t uxTimeout );
/*
* Returns a pointer to the original NetworkBuffer from a pointer to a UDP
* payload buffer.
*/
NetworkBufferDescriptor_t * pxUDPPayloadBuffer_to_NetworkBuffer( const void * pvBuffer );
/*
* Internal: Sets a new state for a TCP socket and performs the necessary
* actions like calling a OnConnected handler to notify the socket owner.
*/
#if ( ipconfigUSE_TCP == 1 )
void vTCPStateChange( FreeRTOS_Socket_t * pxSocket,
enum eTCP_STATE eTCPState );
#endif /* ipconfigUSE_TCP */
/* Returns pdTRUE is this function is called from the IP-task */
BaseType_t xIsCallingFromIPTask( void );
#if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
/** @brief Structure for event groups of the Socket Select functions */
typedef struct xSOCKET_SET
{
/** @brief Event group for the socket select function.
*/
EventGroupHandle_t xSelectGroup;
} SocketSelect_t;
extern void vSocketSelect( const SocketSelect_t * pxSocketSet );
/** @brief Define the data that must be passed for a 'eSocketSelectEvent'. */
typedef struct xSocketSelectMessage
{
TaskHandle_t xTaskhandle; /**< Task handle for use in the socket select functionality. */
SocketSelect_t * pxSocketSet; /**< The event group for the socket select functionality. */
} SocketSelectMessage_t;
#endif /* ipconfigSUPPORT_SELECT_FUNCTION */
/* Send the network-up event and start the ARP timer. */
void vIPNetworkUpCalls( void );
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_IP_PRIVATE_H */

View File

@ -0,0 +1,118 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_IP_Timers.h
* @brief Header file for IP Timers on FreeRTOS+TCP network stack.
*/
#ifndef FREERTOS_IP_TIMERS_H
#define FREERTOS_IP_TIMERS_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_ARP.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_DHCP.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
#include "FreeRTOS_DNS.h"
/*
* Checks the ARP, DHCP and TCP timers to see if any periodic or timeout
* processing is required.
*/
void vCheckNetworkTimers( void );
/*
* Determine how long the IP task can sleep for, which depends on when the next
* periodic or timeout processing must be performed.
*/
TickType_t xCalculateSleepTime( void );
void vIPTimerStartARPResolution( TickType_t xTime );
void vIPSetTCPTimerExpiredState( BaseType_t xExpiredState );
void vIPSetARPTimerEnableState( BaseType_t xEnableState );
void vIPSetARPResolutionTimerEnableState( BaseType_t xEnableState );
#if ( ipconfigUSE_DHCP != 0 )
/**
* @brief Enable/disable the DHCP timer.
* @param[in] xEnableState: pdTRUE - enable timer; pdFALSE - disable timer.
*/
void vIPSetDHCPTimerEnableState( BaseType_t xEnableState );
#endif
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
/**
* @brief Enable/disable the DNS timer.
* @param[in] xEnableState: pdTRUE - enable timer; pdFALSE - disable timer.
*/
void vIPSetDNSTimerEnableState( BaseType_t xEnableState );
#endif
void vARPTimerReload( TickType_t xTime );
void vTCPTimerReload( TickType_t xTime );
#if ( ipconfigUSE_DHCP == 1 )
void vDHCPTimerReload( TickType_t xLeaseTime );
#endif
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
void vDNSTimerReload( uint32_t ulCheckTime );
#endif
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_IP_TIMERS_H */

View File

@ -0,0 +1,105 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef FREERTOS_IP_UTILS_H
#define FREERTOS_IP_UTILS_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/**
* @file FreeRTOS_IP_Utils.h
* @brief Implements the utility functions for FreeRTOS_IP.c
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_ARP.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_DHCP.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
#include "FreeRTOS_DNS.h"
#if ( ipconfigUSE_DHCP != 0 )
/**
* @brief Create a DHCP event.
*
* @return pdPASS or pdFAIL, depending on whether xSendEventStructToIPTask()
* succeeded.
*/
BaseType_t xSendDHCPEvent( void );
#endif
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) || ( ipconfigZERO_COPY_RX_DRIVER != 0 )
/**
* @brief Get the network buffer from the packet buffer.
*
* @param[in] pvBuffer: Pointer to the packet buffer.
*
* @return The network buffer if the alignment is correct. Else a NULL is returned.
*/
NetworkBufferDescriptor_t * pxPacketBuffer_to_NetworkBuffer( const void * pvBuffer );
#endif
/**
* @brief Check the values of configuration options and assert on it. Also verify that the IP-task
* has not already been initialized.
*/
void vPreCheckConfigs( void );
/**
* @brief Called to create a network connection when the stack is first
* started, or when the network connection is lost.
*/
void prvProcessNetworkDownEvent( void );
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_IP_UTILS_H */

View File

@ -0,0 +1,551 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef FREERTOS_SOCKETS_H
#define FREERTOS_SOCKETS_H
#ifdef __cplusplus
extern "C" {
#endif
/* Standard includes. */
#include <string.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
/* Application level configuration options. */
#include "FreeRTOSIPConfig.h"
#include "FreeRTOSIPConfigDefaults.h"
#ifndef FREERTOS_IP_CONFIG_H
#error FreeRTOSIPConfig.h has not been included yet
#endif
/* Event bit definitions are required by the select functions. */
#include "event_groups.h"
#ifndef INC_FREERTOS_H
#error FreeRTOS.h must be included before FreeRTOS_Sockets.h.
#endif
#ifndef INC_TASK_H
#ifndef TASK_H /* For compatibility with older FreeRTOS versions. */
#error The FreeRTOS header file task.h must be included before FreeRTOS_Sockets.h.
#endif
#endif
/* Assigned to an Socket_t variable when the socket is not valid, probably
* because it could not be created. */
#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.
*
* Like in errno.h, the error codes are defined as positive numbers.
* However, in case of an error, API 's will still negative values, e.g.
* return -pdFREERTOS_ERRNO_EWOULDBLOCK;
* in case an operation would block.
*
* The following defines are obsolete, please use -pdFREERTOS_ERRNO_Exxx. */
#define FREERTOS_SOCKET_ERROR ( -1 )
#define FREERTOS_EWOULDBLOCK ( -pdFREERTOS_ERRNO_EWOULDBLOCK )
#define FREERTOS_EINVAL ( -pdFREERTOS_ERRNO_EINVAL )
#define FREERTOS_EADDRNOTAVAIL ( -pdFREERTOS_ERRNO_EADDRNOTAVAIL )
#define FREERTOS_EADDRINUSE ( -pdFREERTOS_ERRNO_EADDRINUSE )
#define FREERTOS_ENOBUFS ( -pdFREERTOS_ERRNO_ENOBUFS )
#define FREERTOS_ENOPROTOOPT ( -pdFREERTOS_ERRNO_ENOPROTOOPT )
#define FREERTOS_ECLOSED ( -pdFREERTOS_ERRNO_ENOTCONN )
/* Values for the parameters to FreeRTOS_socket(), inline with the Berkeley
* standard. See the documentation of FreeRTOS_socket() for more information. */
#define FREERTOS_AF_INET ( 2 )
#define FREERTOS_AF_INET6 ( 10 )
#define FREERTOS_SOCK_DGRAM ( 2 )
#define FREERTOS_IPPROTO_UDP ( 17 )
#define FREERTOS_SOCK_STREAM ( 1 )
#define FREERTOS_IPPROTO_TCP ( 6 )
#define FREERTOS_SOCK_DEPENDENT_PROTO ( 0 )
/* Values for xFlags parameter of Receive/Send functions. */
#define FREERTOS_ZERO_COPY ( 1 ) /* Can be used with recvfrom(), sendto() and recv(),
* Indicates that the zero copy interface is being used.
* See the documentation for FreeRTOS_sockets() for more information. */
#define FREERTOS_MSG_OOB ( 2 ) /* Not used. */
#define FREERTOS_MSG_PEEK ( 4 ) /* Can be used with recvfrom() and recv(). */
#define FREERTOS_MSG_DONTROUTE ( 8 ) /* Not used. */
#define FREERTOS_MSG_DONTWAIT ( 16 ) /* Can be used with recvfrom(), sendto(), recv() and send(). */
/* Values that can be passed in the option name parameter of calls to
* FreeRTOS_setsockopt(). */
#define FREERTOS_SO_RCVTIMEO ( 0 ) /* Used to set the receive time out. */
#define FREERTOS_SO_SNDTIMEO ( 1 ) /* Used to set the send time out. */
#define FREERTOS_SO_UDPCKSUM_OUT ( 2 ) /* Used to turn the use of the UDP checksum
* by a socket on or off. This also doubles
* as part of an 8-bit bitwise socket option. */
#if ( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
#define FREERTOS_SO_SET_SEMAPHORE ( 3 ) /* Used to set a user's semaphore. */
#endif
#if ( ipconfigUSE_TCP == 1 )
#define FREERTOS_SO_SNDBUF ( 4 ) /* Set the size of the send buffer (TCP only). */
#define FREERTOS_SO_RCVBUF ( 5 ) /* Set the size of the receive buffer (TCP only). */
#endif
#if ( ipconfigUSE_CALLBACKS == 1 )
/* Supply pointer to 'F_TCP_UDP_Handler_t' for pvOptionValue parameter in
* FreeRTOS_setsockopt() */
#define FREERTOS_SO_TCP_CONN_HANDLER ( 6 ) /* Install a callback for (dis) connection events. */
#define FREERTOS_SO_TCP_RECV_HANDLER ( 7 ) /* Install a callback for receiving TCP data. */
#define FREERTOS_SO_TCP_SENT_HANDLER ( 8 ) /* Install a callback for sending TCP data. */
#define FREERTOS_SO_UDP_RECV_HANDLER ( 9 ) /* Install a callback for receiving UDP data. */
#define FREERTOS_SO_UDP_SENT_HANDLER ( 10 ) /* Install a callback for sending UDP data. */
#endif
#if ( ipconfigUSE_TCP == 1 )
#define FREERTOS_SO_REUSE_LISTEN_SOCKET ( 11 ) /* When a listening socket gets connected, do not create a new one but re-use it. */
#define FREERTOS_SO_CLOSE_AFTER_SEND ( 12 ) /* As soon as the last byte has been transmitted, finalise the connection. */
#define FREERTOS_SO_WIN_PROPERTIES ( 13 ) /* Set all buffer and window properties in one call, parameter is pointer to WinProperties_t. */
#define FREERTOS_SO_SET_FULL_SIZE ( 14 ) /* Refuse to send packets smaller than MSS. */
#define FREERTOS_SO_STOP_RX ( 15 ) /* Temporarily hold up reception, used by streaming client. */
#endif
#if ( ipconfigUDP_MAX_RX_PACKETS > 0 )
#define FREERTOS_SO_UDP_MAX_RX_PACKETS ( 16 ) /* This option helps to limit the maximum number of packets a UDP socket will buffer. */
#endif
#if ( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK == 1 )
#define FREERTOS_SO_WAKEUP_CALLBACK ( 17 )
#endif
#if ( ipconfigUSE_TCP == 1 )
#define FREERTOS_SO_SET_LOW_HIGH_WATER ( 18 )
#endif
#if ( 0 ) /* Not Used */
#define FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET ( 0x80 )
#define FREERTOS_FRAGMENTED_PACKET ( 0x40 )
#endif
#if ( ipconfigUSE_TCP == 1 )
/* Values for 'xHow' flag of FreeRTOS_shutdown(), currently ignored. */
#define FREERTOS_SHUT_RD ( 0 )
#define FREERTOS_SHUT_WR ( 1 )
#define FREERTOS_SHUT_RDWR ( 2 )
#endif
/* For compatibility with the expected Berkeley sockets naming. */
#define socklen_t uint32_t
/**
* For this limited implementation, only two members are required in the
* Berkeley style sockaddr structure.
*/
struct freertos_sockaddr
{
/* _HT_ On 32- and 64-bit architectures, the addition of the two uint8_t
* fields sin_len and sin_family doesn't make the structure bigger, due to alignment.
* These fields are only inserted as a preparation for IPv6
* and are not used in the IPv4-only release. */
uint8_t sin_len; /**< length of this structure. */
uint8_t sin_family; /**< FREERTOS_AF_INET. */
uint16_t sin_port; /**< The port. */
uint32_t sin_addr; /**< The IP address. */
};
/* The socket type itself. */
struct xSOCKET;
typedef struct xSOCKET * Socket_t;
typedef struct xSOCKET const * ConstSocket_t;
extern BaseType_t xSocketValid( const ConstSocket_t xSocket );
/**
* FULL, UP-TO-DATE AND MAINTAINED REFERENCE DOCUMENTATION FOR ALL THESE
* FUNCTIONS IS AVAILABLE ON THE FOLLOWING URL:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/FreeRTOS_TCP_API_Functions.html
*/
/* Common Socket Attributes. */
/* Create a TCP or UDP socket. */
Socket_t FreeRTOS_socket( BaseType_t xDomain,
BaseType_t xType,
BaseType_t xProtocol );
/* Binds a socket to a local port number. */
BaseType_t FreeRTOS_bind( Socket_t xSocket,
struct freertos_sockaddr const * pxAddress,
socklen_t xAddressLength );
/* Sets a socket option. */
BaseType_t FreeRTOS_setsockopt( Socket_t xSocket,
int32_t lLevel,
int32_t lOptionName,
const void * pvOptionValue,
size_t uxOptionLength );
/* Close a socket. */
BaseType_t FreeRTOS_closesocket( Socket_t xSocket );
#if ( ipconfigSUPPORT_SIGNALS != 0 )
/* Send a signal to the task which is waiting for a given socket. */
BaseType_t FreeRTOS_SignalSocket( Socket_t xSocket );
/* Send a signal to the task which reads from this socket (FromISR version). */
BaseType_t FreeRTOS_SignalSocketFromISR( Socket_t xSocket,
BaseType_t * pxHigherPriorityTaskWoken );
#endif
/* End Common Socket Attributes */
/* UDP Socket Attributes. */
/* Send data to a UDP socket. */
int32_t FreeRTOS_sendto( Socket_t xSocket,
const void * pvBuffer,
size_t uxTotalDataLength,
BaseType_t xFlags,
const struct freertos_sockaddr * pxDestinationAddress,
socklen_t xDestinationAddressLength );
/* Receive data from a UDP socket */
int32_t FreeRTOS_recvfrom( const ConstSocket_t xSocket,
void * pvBuffer,
size_t uxBufferLength,
BaseType_t xFlags,
struct freertos_sockaddr * pxSourceAddress,
const socklen_t * pxSourceAddressLength );
/* Function to get the local address and IP port. */
size_t FreeRTOS_GetLocalAddress( ConstSocket_t xSocket,
struct freertos_sockaddr * pxAddress );
#if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
/* Returns true if an UDP socket exists bound to mentioned port number. */
BaseType_t xPortHasUDPSocket( uint16_t usPortNr );
#endif
/* End UDP Socket Attributes */
#if ( ipconfigUSE_TCP == 1 )
/* TCP Socket Attributes. */
/**
* Structure to hold the properties of Tx/Rx buffers and windows.
*/
typedef struct xWIN_PROPS
{
/* Properties of the Tx buffer and Tx window. */
int32_t lTxBufSize; /**< Unit: bytes. */
int32_t lTxWinSize; /**< Unit: MSS. */
/* Properties of the Rx buffer and Rx window. */
int32_t lRxBufSize; /**< Unit: bytes. */
int32_t lRxWinSize; /**< Unit: MSS. */
} WinProperties_t;
/**
* Structure to pass for the 'FREERTOS_SO_SET_LOW_HIGH_WATER' option.
*/
typedef struct xLOW_HIGH_WATER
{
size_t uxLittleSpace; /**< Send a STOP when buffer space drops below X bytes */
size_t uxEnoughSpace; /**< Send a GO when buffer space grows above X bytes */
} LowHighWater_t;
/* Connect a TCP socket to a remote socket. */
BaseType_t FreeRTOS_connect( Socket_t xClientSocket,
const struct freertos_sockaddr * pxAddress,
socklen_t xAddressLength );
/* Places a TCP socket into a state where it is listening for and can accept
* incoming connection requests from remote sockets. */
BaseType_t FreeRTOS_listen( Socket_t xSocket,
BaseType_t xBacklog );
/* Accept a connection on a TCP socket. */
Socket_t FreeRTOS_accept( Socket_t xServerSocket,
struct freertos_sockaddr * pxAddress,
socklen_t * pxAddressLength );
/* Send data to a TCP socket. */
BaseType_t FreeRTOS_send( Socket_t xSocket,
const void * pvBuffer,
size_t uxDataLength,
BaseType_t xFlags );
/* Receive data from a TCP socket */
BaseType_t FreeRTOS_recv( Socket_t xSocket,
void * pvBuffer,
size_t uxBufferLength,
BaseType_t xFlags );
/* Disable reads and writes on a connected TCP socket. */
BaseType_t FreeRTOS_shutdown( Socket_t xSocket,
BaseType_t xHow );
#if ( ipconfigUSE_TCP == 1 )
/* Release a TCP payload buffer that was obtained by
* calling FreeRTOS_recv() with the FREERTOS_ZERO_COPY flag,
* and a pointer to a void pointer. */
BaseType_t FreeRTOS_ReleaseTCPPayloadBuffer( Socket_t xSocket,
void const * pvBuffer,
BaseType_t xByteCount );
#endif /* ( ipconfigUSE_TCP == 1 ) */
/* Returns the number of bytes available in the Rx buffer. */
BaseType_t FreeRTOS_rx_size( ConstSocket_t xSocket );
#define FreeRTOS_recvcount( xSocket ) FreeRTOS_rx_size( xSocket )
/* Returns the free space in the Tx buffer. */
BaseType_t FreeRTOS_tx_space( ConstSocket_t xSocket );
#define FreeRTOS_outstanding( xSocket ) FreeRTOS_tx_size( xSocket )
/* Returns the number of bytes stored in the Tx buffer. */
BaseType_t FreeRTOS_tx_size( ConstSocket_t xSocket );
/* Returns pdTRUE if TCP socket is connected. */
BaseType_t FreeRTOS_issocketconnected( ConstSocket_t xSocket );
/* Return the remote address and IP port of a connected TCP Socket. */
BaseType_t FreeRTOS_GetRemoteAddress( ConstSocket_t xSocket,
struct freertos_sockaddr * pxAddress );
/* Returns the number of bytes that may be added to txStream. */
BaseType_t FreeRTOS_maywrite( ConstSocket_t xSocket );
/* Returns the actual size of MSS being used. */
BaseType_t FreeRTOS_mss( ConstSocket_t xSocket );
/* For internal use only: return the connection status. */
BaseType_t FreeRTOS_connstatus( ConstSocket_t xSocket );
/* For advanced applications only:
* Get a direct pointer to the circular transmit buffer.
* '*pxLength' will contain the number of bytes that may be written. */
uint8_t * FreeRTOS_get_tx_head( ConstSocket_t xSocket,
BaseType_t * pxLength );
/* For the web server: borrow the circular Rx buffer for inspection
* HTML driver wants to see if a sequence of 13/10/13/10 is available. */
const struct xSTREAM_BUFFER * FreeRTOS_get_rx_buf( ConstSocket_t xSocket );
void FreeRTOS_netstat( void );
/* End TCP Socket Attributes. */
#endif /* ( ipconfigUSE_TCP == 1 ) */
#if ( ipconfigUSE_CALLBACKS == 1 )
/*
* Callback handlers for a socket
* User-provided functions will be called for each sockopt callback defined
* For example:
* static void xOnTCPConnect( Socket_t xSocket, BaseType_t ulConnected ) {}
* static BaseType_t xOnTCPReceive( Socket_t xSocket, void * pData, size_t uxLength )
* {
* // handle the message
* return pdFALSE; // Not Used
* }
* static void xOnTCPSent( Socket_t xSocket, size_t xLength ) {}
* static BaseType_t xOnUDPReceive( Socket_t xSocket, void * pData, size_t xLength, const struct freertos_sockaddr * pxFrom, const struct freertos_sockaddr * pxDest )
* {
* // handle the message
* return pdTRUE; // message processing is finished, don't store
* }
* static void xOnUDPSent( Socket_t xSocket, size_t xLength ) {}
* F_TCP_UDP_Handler_t xHand = { xOnTCPConnect, xOnTCPReceive, xOnTCPSent, xOnUDPReceive, xOnUDPSent };
* FreeRTOS_setsockopt( sock, 0, FREERTOS_SO_TCP_CONN_HANDLER, ( void * ) &xHand, 0 );
*/
/* Connected callback handler for a TCP Socket. */
typedef void (* FOnConnected_t )( Socket_t xSocket,
BaseType_t ulConnected );
/* Received callback handler for a TCP Socket.
* Return value is not currently used. */
typedef BaseType_t (* FOnTCPReceive_t )( Socket_t xSocket,
void * pData,
size_t xLength );
/* Sent callback handler for a TCP Socket. */
typedef void (* FOnTCPSent_t )( Socket_t xSocket,
size_t xLength );
/* Received callback handler for a UDP Socket.
* If a positive number is returned, the messages will not be stored in
* xWaitingPacketsList for later processing by recvfrom(). */
typedef BaseType_t (* FOnUDPReceive_t ) ( Socket_t xSocket,
void * pData,
size_t xLength,
const struct freertos_sockaddr * pxFrom,
const struct freertos_sockaddr * pxDest );
/* Sent callback handler for a UDP Socket */
typedef void (* FOnUDPSent_t )( Socket_t xSocket,
size_t xLength );
/* The following values are used in the lOptionName parameter of setsockopt()
* to set the callback handlers options. */
typedef struct xTCP_UDP_HANDLER
{
FOnConnected_t pxOnTCPConnected; /* FREERTOS_SO_TCP_CONN_HANDLER */
FOnTCPReceive_t pxOnTCPReceive; /* FREERTOS_SO_TCP_RECV_HANDLER */
FOnTCPSent_t pxOnTCPSent; /* FREERTOS_SO_TCP_SENT_HANDLER */
FOnUDPReceive_t pxOnUDPReceive; /* FREERTOS_SO_UDP_RECV_HANDLER */
FOnUDPSent_t pxOnUDPSent; /* FREERTOS_SO_UDP_SENT_HANDLER */
} F_TCP_UDP_Handler_t;
#endif /* ( ipconfigUSE_CALLBACKS == 1 ) */
/* Conversion Functions */
/* Converts an IP address expressed as a 32-bit number in network byte order
* to a string in decimal dot notation. */
extern const char * FreeRTOS_inet_ntoa( uint32_t ulIPAddress,
char * pcBuffer );
#if ( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
/* Converts an IP address expressed as four separate numeric octets into an
* IP address expressed as a 32-bit number in network byte order */
#define FreeRTOS_inet_addr_quick( ucOctet0, ucOctet1, ucOctet2, ucOctet3 ) \
( ( ( ( uint32_t ) ( ucOctet3 ) ) << 24UL ) | \
( ( ( uint32_t ) ( ucOctet2 ) ) << 16UL ) | \
( ( ( uint32_t ) ( ucOctet1 ) ) << 8UL ) | \
( ( uint32_t ) ( ucOctet0 ) ) )
#else /* ( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN ) */
#define FreeRTOS_inet_addr_quick( ucOctet0, ucOctet1, ucOctet2, ucOctet3 ) \
( ( ( ( uint32_t ) ( ucOctet0 ) ) << 24UL ) | \
( ( ( uint32_t ) ( ucOctet1 ) ) << 16UL ) | \
( ( ( uint32_t ) ( ucOctet2 ) ) << 8UL ) | \
( ( uint32_t ) ( ucOctet3 ) ) )
#endif /* ( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) */
/* Convert a null-terminated string in dot-decimal-notation (d.d.d.d)
* to a 32-bit unsigned integer. */
uint32_t FreeRTOS_inet_addr( const char * pcIPAddress );
BaseType_t FreeRTOS_inet_pton( BaseType_t xAddressFamily,
const char * pcSource,
void * pvDestination );
const char * FreeRTOS_inet_ntop( BaseType_t xAddressFamily,
const void * pvSource,
char * pcDestination,
socklen_t uxSize );
BaseType_t FreeRTOS_inet_pton4( const char * pcSource,
void * pvDestination );
const char * FreeRTOS_inet_ntop4( const void * pvSource,
char * pcDestination,
socklen_t uxSize );
/** @brief This function converts a human readable string, representing an 48-bit MAC address,
* into a 6-byte address. Valid inputs are e.g. "62:48:5:83:A0:b2" and "0-12-34-fe-dc-ba". */
BaseType_t FreeRTOS_EUI48_pton( const char * pcSource,
uint8_t * pucTarget );
/** @brief This function converts a 48-bit MAC address to a human readable string. */
void FreeRTOS_EUI48_ntop( const uint8_t * pucSource,
char * pcTarget,
char cTen,
char cSeparator );
/* End Conversion Functions */
#if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
/* The SocketSet_t type is the equivalent to the fd_set type used by the
* Berkeley API. */
struct xSOCKET_SET;
typedef struct xSOCKET_SET * SocketSet_t;
typedef struct xSOCKET_SET const * ConstSocketSet_t;
/* Create a socket set for use with the FreeRTOS_select() function */
SocketSet_t FreeRTOS_CreateSocketSet( void );
void FreeRTOS_DeleteSocketSet( SocketSet_t xSocketSet );
/* Block on a "socket set" until an event of interest occurs on a
* socket within the set. */
BaseType_t FreeRTOS_select( SocketSet_t xSocketSet,
TickType_t xBlockTimeTicks );
/* For FD_SET and FD_CLR, a combination of the following bits can be used: */
typedef enum eSELECT_EVENT
{
eSELECT_READ = 0x0001,
eSELECT_WRITE = 0x0002,
eSELECT_EXCEPT = 0x0004,
eSELECT_INTR = 0x0008,
eSELECT_ALL = 0x000F,
/* Reserved for internal use: */
eSELECT_CALL_IP = 0x0010,
/* end */
} eSelectEvent_t;
/* Add a socket to a socket set, and set the event bits of interest
* for the added socket. */
void FreeRTOS_FD_SET( Socket_t xSocket,
SocketSet_t xSocketSet,
EventBits_t xBitsToSet );
/* Clear a set event bit of interest for a socket of the socket set.
* If all the event bits are clear then the socket will be removed
* from the socket set. */
void FreeRTOS_FD_CLR( Socket_t xSocket,
SocketSet_t xSocketSet,
EventBits_t xBitsToClear );
/* Check if a socket in a socket set has an event bit set. */
EventBits_t FreeRTOS_FD_ISSET( const ConstSocket_t xSocket,
const ConstSocketSet_t xSocketSet );
#endif /* ( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* FREERTOS_SOCKETS_H */

View File

@ -0,0 +1,131 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*
* FreeRTOS_Stream_Buffer.h
*
* A circular character buffer
* An implementation of a circular buffer without a length field
* If LENGTH defines the size of the buffer, a maximum of (LENGTH-1) bytes can be stored
* In order to add or read data from the buffer, memcpy() will be called at most 2 times
*/
#ifndef FREERTOS_STREAM_BUFFER_H
#define FREERTOS_STREAM_BUFFER_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/**
* structure to store all the details of a stream buffer.
*/
typedef struct xSTREAM_BUFFER
{
volatile size_t uxTail; /**< next item to read */
volatile size_t uxMid; /**< iterator within the valid items */
volatile size_t uxHead; /**< next position store a new item */
volatile size_t uxFront; /**< iterator within the free space */
size_t LENGTH; /**< const value: number of reserved elements */
uint8_t ucArray[ sizeof( size_t ) ]; /**< array big enough to store any pointer address */
} StreamBuffer_t;
void vStreamBufferClear( StreamBuffer_t * pxBuffer );
/*-----------------------------------------------------------*/
size_t uxStreamBufferSpace( const StreamBuffer_t * pxBuffer,
const size_t uxLower,
const size_t uxUpper );
/*-----------------------------------------------------------*/
size_t uxStreamBufferDistance( const StreamBuffer_t * pxBuffer,
const size_t uxLower,
const size_t uxUpper );
/*-----------------------------------------------------------*/
size_t uxStreamBufferGetSpace( const StreamBuffer_t * pxBuffer );
/*-----------------------------------------------------------*/
size_t uxStreamBufferFrontSpace( const StreamBuffer_t * pxBuffer );
/*-----------------------------------------------------------*/
size_t uxStreamBufferGetSize( const StreamBuffer_t * pxBuffer );
/*-----------------------------------------------------------*/
size_t uxStreamBufferMidSpace( const StreamBuffer_t * pxBuffer );
/*-----------------------------------------------------------*/
void vStreamBufferMoveMid( StreamBuffer_t * pxBuffer,
size_t uxCount );
/*-----------------------------------------------------------*/
BaseType_t xStreamBufferLessThenEqual( const StreamBuffer_t * pxBuffer,
const size_t uxLeft,
const size_t uxRight );
/*-----------------------------------------------------------*/
size_t uxStreamBufferGetPtr( StreamBuffer_t * pxBuffer,
uint8_t ** ppucData );
/*
* Add bytes to a stream buffer.
*
* pxBuffer - The buffer to which the bytes will be added.
* uxOffset - If uxOffset > 0, data will be written at an offset from uxHead
* while uxHead will not be moved yet.
* pucData - A pointer to the data to be added.
* uxCount - The number of bytes to add.
*/
size_t uxStreamBufferAdd( StreamBuffer_t * pxBuffer,
size_t uxOffset,
const uint8_t * pucData,
size_t uxByteCount );
/*
* Read bytes from a stream buffer.
*
* pxBuffer - The buffer from which the bytes will be read.
* uxOffset - Can be used to read data located at a certain offset from 'uxTail'.
* pucData - A pointer to the buffer into which data will be read.
* uxMaxCount - The number of bytes to read.
* xPeek - If set to pdTRUE the data will remain in the buffer.
*/
size_t uxStreamBufferGet( StreamBuffer_t * pxBuffer,
size_t uxOffset,
uint8_t * pucData,
size_t uxMaxCount,
BaseType_t xPeek );
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* !defined( FREERTOS_STREAM_BUFFER_H ) */

View File

@ -0,0 +1,175 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef FREERTOS_TCP_IP_H
#define FREERTOS_TCP_IP_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t * pxDescriptor );
typedef enum eTCP_STATE
{
/* Comments about the TCP states are borrowed from the very useful
* Wiki page:
* http://en.wikipedia.org/wiki/Transmission_Control_Protocol */
eCLOSED = 0U, /* 0 (server + client) no connection state at all. */
eTCP_LISTEN, /* 1 (server) waiting for a connection request
* from any remote TCP and port. */
eCONNECT_SYN, /* 2 (client) internal state: socket wants to send
* a connect */
eSYN_FIRST, /* 3 (server) Just created, must ACK the SYN request. */
eSYN_RECEIVED, /* 4 (server) waiting for a confirming connection request
* acknowledgement after having both received and sent a connection request. */
eESTABLISHED, /* 5 (server + client) an open connection, data received can be
* delivered to the user. The normal state for the data transfer phase of the connection. */
eFIN_WAIT_1, /* 6 (server + client) waiting for a connection termination request from the remote TCP,
* or an acknowledgement of the connection termination request previously sent. */
eFIN_WAIT_2, /* 7 (server + client) waiting for a connection termination request from the remote TCP. */
eCLOSE_WAIT, /* 8 (server + client) waiting for a connection termination request from the local user. */
eCLOSING, /* 9 (server + client) waiting for a connection termination request acknowledgement from the remote TCP. */
eLAST_ACK, /*10 (server + client) waiting for an acknowledgement of the connection termination request
* previously sent to the remote TCP
* (which includes an acknowledgement of its connection termination request). */
eTIME_WAIT, /*11 (either server or client) waiting for enough time to pass to be sure the remote TCP received the
* acknowledgement of its connection termination request. [According to RFC 793 a connection can
* stay in TIME-WAIT for a maximum of four minutes known as a MSL (maximum segment lifetime).] */
} eIPTCPState_t;
/*
* The meaning of the TCP flags:
*/
#define tcpTCP_FLAG_FIN ( ( uint8_t ) 0x01U ) /**< No more data from sender. */
#define tcpTCP_FLAG_SYN ( ( uint8_t ) 0x02U ) /**< Synchronize sequence numbers. */
#define tcpTCP_FLAG_RST ( ( uint8_t ) 0x04U ) /**< Reset the connection. */
#define tcpTCP_FLAG_PSH ( ( uint8_t ) 0x08U ) /**< Push function: please push buffered data to the recv application. */
#define tcpTCP_FLAG_ACK ( ( uint8_t ) 0x10U ) /**< Acknowledgment field is significant. */
#define tcpTCP_FLAG_URG ( ( uint8_t ) 0x20U ) /**< Urgent pointer field is significant. */
#define tcpTCP_FLAG_ECN ( ( uint8_t ) 0x40U ) /**< ECN-Echo. */
#define tcpTCP_FLAG_CWR ( ( uint8_t ) 0x80U ) /**< Congestion Window Reduced. */
#define tcpTCP_FLAG_CTRL ( ( uint8_t ) 0x1FU ) /**< A mask to filter all protocol flags. */
/*
* A few values of the TCP options:
*/
#define tcpTCP_OPT_END 0U /**< End of TCP options list. */
#define tcpTCP_OPT_NOOP 1U /**< "No-operation" TCP option. */
#define tcpTCP_OPT_MSS 2U /**< Maximum segment size TCP option. */
#define tcpTCP_OPT_WSOPT 3U /**< TCP Window Scale Option (3-byte long). */
#define tcpTCP_OPT_SACK_P 4U /**< Advertise that SACK is permitted. */
#define tcpTCP_OPT_SACK_A 5U /**< SACK option with first/last. */
#define tcpTCP_OPT_TIMESTAMP 8U /**< Time-stamp option. */
#define tcpTCP_OPT_MSS_LEN 4U /**< Length of TCP MSS option. */
#define tcpTCP_OPT_WSOPT_LEN 3U /**< Length of TCP WSOPT option. */
#define tcpTCP_OPT_TIMESTAMP_LEN 10 /**< fixed length of the time-stamp option. */
/** @brief
* Minimum segment length as outlined by RFC 791 section 3.1.
* Minimum segment length ( 536 ) = Minimum MTU ( 576 ) - IP Header ( 20 ) - TCP Header ( 20 ).
*/
#define tcpMINIMUM_SEGMENT_LENGTH 536U
/** @brief
* The macro tcpNOW_CONNECTED() is use to determine if the connection makes a
* transition from connected to non-connected and vice versa.
* tcpNOW_CONNECTED() returns true when the status has one of these values:
* eESTABLISHED, eFIN_WAIT_1, eFIN_WAIT_2, eCLOSING, eLAST_ACK, eTIME_WAIT
* Technically the connection status is closed earlier, but the library wants
* to prevent that the socket will be deleted before the last ACK has been
* and thus causing a 'RST' packet on either side.
*/
#define tcpNOW_CONNECTED( status ) \
( ( ( ( status ) >= ( BaseType_t ) eESTABLISHED ) && ( ( status ) != ( BaseType_t ) eCLOSE_WAIT ) ) ? 1 : 0 )
/** @brief
* The highest 4 bits in the TCP offset byte indicate the total length of the
* TCP header, divided by 4.
*/
#define tcpVALID_BITS_IN_TCP_OFFSET_BYTE ( 0xF0U )
/*
* Acknowledgements to TCP data packets may be delayed as long as more is being expected.
* A normal delay would be 200ms. Here a much shorter delay of 20 ms is being used to
* gain performance.
*/
#define tcpDELAYED_ACK_SHORT_DELAY_MS ( 2 ) /**< Should not become smaller than 1. */
#define tcpDELAYED_ACK_LONGER_DELAY_MS ( 20 ) /**< Longer delay for ACK. */
/** @brief
* The MSS (Maximum Segment Size) will be taken as large as possible. However, packets with
* an MSS of 1460 bytes won't be transported through the internet. The MSS will be reduced
* to 1400 bytes.
*/
#define tcpREDUCED_MSS_THROUGH_INTERNET ( 1400 )
/** @brief
* When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
* the number 5 (words) in the higher nibble of the TCP-offset byte.
*/
#define tcpTCP_OFFSET_LENGTH_BITS ( 0xf0U )
#define tcpTCP_OFFSET_STANDARD_LENGTH ( 0x50U ) /**< Standard TCP packet offset. */
/** @brief
* Each TCP socket is checked regularly to see if it can send data packets.
* By default, the maximum number of packets sent during one check is limited to 8.
* This amount may be further limited by setting the socket's TX window size.
*/
#if ( !defined( SEND_REPEATED_COUNT ) )
#define SEND_REPEATED_COUNT ( 8 )
#endif /* !defined( SEND_REPEATED_COUNT ) */
/** @brief
* Define a maximum period of time (ms) to leave a TCP-socket unattended.
* When a TCP timer expires, retries and keep-alive messages will be checked.
*/
#ifndef tcpMAXIMUM_TCP_WAKEUP_TIME_MS
#define tcpMAXIMUM_TCP_WAKEUP_TIME_MS 20000U
#endif
/* Two macro's that were introduced to work with both IPv4 and IPv6. */
#define xIPHeaderSize( pxNetworkBuffer ) ( ipSIZE_OF_IPv4_HEADER ) /**< Size of IP Header. */
#define uxIPHeaderSizeSocket( pxSocket ) ( ipSIZE_OF_IPv4_HEADER ) /**< Size of IP Header socket. */
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_TCP_IP_H */

View File

@ -0,0 +1,66 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef FREERTOS_TCP_RECEPTION_H
#define FREERTOS_TCP_RECEPTION_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/*
* Called from xProcessReceivedTCPPacket. Parse the TCP option(s) received,
* if present. This function returns pdFALSE if the options are not well formed.
*/
BaseType_t prvCheckOptions( FreeRTOS_Socket_t * pxSocket,
const NetworkBufferDescriptor_t * pxNetworkBuffer );
/*
* Called from prvTCPHandleState(). Find the TCP payload data and check and
* return its length.
*/
BaseType_t prvCheckRxData( const NetworkBufferDescriptor_t * pxNetworkBuffer,
uint8_t ** ppucRecvData );
/*
* Called from prvTCPHandleState(). Check if the payload data may be accepted.
* If so, it will be added to the socket's reception queue.
*/
BaseType_t prvStoreRxData( FreeRTOS_Socket_t * pxSocket,
const uint8_t * pucRecvData,
NetworkBufferDescriptor_t * pxNetworkBuffer,
uint32_t ulReceiveLength );
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_TCP_RECEPTION_H */

View File

@ -0,0 +1,74 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef FREERTOS_TCP_STATE_HANDLING_H
#define FREERTOS_TCP_STATE_HANDLING_H
#include "FreeRTOS_TCP_IP.h"
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/*
* Returns true if the socket must be checked. Non-active sockets are waiting
* for user action, either connect() or close().
*/
BaseType_t prvTCPSocketIsActive( eIPTCPState_t eStatus );
/*
* prvTCPStatusAgeCheck() will see if the socket has been in a non-connected
* state for too long. If so, the socket will be closed, and -1 will be
* returned.
*/
#if ( ipconfigTCP_HANG_PROTECTION == 1 )
BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t * pxSocket );
#endif
/*
* The heart of all: check incoming packet for valid data and acks and do what
* is necessary in each state.
*/
BaseType_t prvTCPHandleState( FreeRTOS_Socket_t * pxSocket,
NetworkBufferDescriptor_t ** ppxNetworkBuffer );
/*
* Return either a newly created socket, or the current socket in a connected
* state (depends on the 'bReuseSocket' flag).
*/
FreeRTOS_Socket_t * prvHandleListen( FreeRTOS_Socket_t * pxSocket,
NetworkBufferDescriptor_t * pxNetworkBuffer );
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_TCP_STATE_HANDLING_H */

View File

@ -0,0 +1,124 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef FREERTOS_TCP_TRANSMISSION_H
#define FREERTOS_TCP_TRANSMISSION_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/*
* Either sends a SYN or calls prvTCPSendRepeated (for regular messages).
*/
int32_t prvTCPSendPacket( FreeRTOS_Socket_t * pxSocket );
/*
* Try to send a series of messages.
*/
int32_t prvTCPSendRepeated( FreeRTOS_Socket_t * pxSocket,
NetworkBufferDescriptor_t ** ppxNetworkBuffer );
/*
* Return or send a packet to the other party.
*/
void prvTCPReturnPacket( FreeRTOS_Socket_t * pxSocket,
NetworkBufferDescriptor_t * pxDescriptor,
uint32_t ulLen,
BaseType_t xReleaseAfterSend );
/*
* Initialise the data structures which keep track of the TCP windowing system.
*/
void prvTCPCreateWindow( FreeRTOS_Socket_t * pxSocket );
/*
* Set the initial properties in the options fields, like the preferred
* value of MSS and whether SACK allowed. Will be transmitted in the state
* 'eCONNECT_SYN'.
*/
UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t * pxSocket,
TCPHeader_t * pxTCPHeader );
/*
* Prepare an outgoing message, if anything has to be sent.
*/
int32_t prvTCPPrepareSend( FreeRTOS_Socket_t * pxSocket,
NetworkBufferDescriptor_t ** ppxNetworkBuffer,
UBaseType_t uxOptionsLength );
/*
* The API FreeRTOS_send() adds data to the TX stream. Add
* this data to the windowing system to it can be transmitted.
*/
void prvTCPAddTxData( FreeRTOS_Socket_t * pxSocket );
/*
* Set the TCP options (if any) for the outgoing packet.
*/
UBaseType_t prvSetOptions( FreeRTOS_Socket_t * pxSocket,
const NetworkBufferDescriptor_t * pxNetworkBuffer );
/*
* Called from prvTCPHandleState(). There is data to be sent.
* If ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will
* be checked if it would better be postponed for efficiency.
*/
BaseType_t prvSendData( FreeRTOS_Socket_t * pxSocket,
NetworkBufferDescriptor_t ** ppxNetworkBuffer,
uint32_t ulReceiveLength,
BaseType_t xByteCount );
/*
* A "challenge ACK" is as per https://tools.ietf.org/html/rfc5961#section-3.2,
* case #3. In summary, an RST was received with a sequence number that is
* unexpected but still within the window.
*/
BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t * pxNetworkBuffer );
/*
* Reply to a peer with the RST flag on, in case a packet can not be handled.
*/
BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t * pxNetworkBuffer );
/*
* Check if the size of a network buffer is big enough to hold the outgoing message.
* Allocate a new bigger network buffer when necessary.
*/
NetworkBufferDescriptor_t * prvTCPBufferResize( const FreeRTOS_Socket_t * pxSocket,
NetworkBufferDescriptor_t * pxNetworkBuffer,
int32_t lDataLen,
UBaseType_t uxOptionsLength );
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_TCP_TRANSMISSION_H */

View File

@ -0,0 +1,56 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef FREERTOS_TCP_UTILS_H
#define FREERTOS_TCP_UTILS_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/*
* For logging and debugging: make a string showing the TCP flags.
*/
#if ( ipconfigHAS_DEBUG_PRINTF != 0 )
const char * prvTCPFlagMeaning( UBaseType_t xFlags );
#endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
/*
* Set the initial value for MSS (Maximum Segment Size) to be used.
*/
void prvSocketSetMSS( FreeRTOS_Socket_t * pxSocket );
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_TCP_UTILS_H */

View File

@ -0,0 +1,258 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*
* FreeRTOS_TCP_WIN.c
* Module which handles the TCP windowing schemes for FreeRTOS-PLUS-TCP
*/
#ifndef FREERTOS_TCP_WIN_H
#define FREERTOS_TCP_WIN_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/** @brief A very simple timer that registers the time that a packet was sent. It is used to trigger re-sending. */
typedef struct xTCPTimerStruct
{
TickType_t uxBorn; /**< The time at which a packet was sent ( using xTaskGetTickCount() ). */
} TCPTimer_t;
/** @brief This struct collects the properties of a TCP segment. A segment is a chunk of data which
* is sent in a single TCP packet, at most 1460 bytes. */
typedef struct xTCP_SEGMENT
{
uint32_t ulSequenceNumber; /**< The sequence number of the first byte in this packet */
int32_t lMaxLength; /**< Maximum space, number of bytes which can be stored in this segment */
int32_t lDataLength; /**< Actual number of bytes */
int32_t lStreamPos; /**< reference to the [t|r]xStream of the socket */
TCPTimer_t xTransmitTimer; /**< saves a timestamp at the moment this segment gets transmitted (TX only) */
union
{
struct
{
uint32_t
ucTransmitCount : 8, /**< Number of times the segment has been transmitted, used to calculate the RTT */
ucDupAckCount : 8, /**< Counts the number of times that a higher segment was ACK'd. After 3 times a Fast Retransmission takes place */
bOutstanding : 1, /**< It the peer's turn, we're just waiting for an ACK */
bAcked : 1, /**< This segment has been acknowledged */
bIsForRx : 1; /**< pdTRUE if segment is used for reception */
} bits;
uint32_t ulFlags;
} u; /**< A collection of boolean flags. */
#if ( ipconfigUSE_TCP_WIN != 0 )
struct xLIST_ITEM xQueueItem; /**< TX only: segments can be linked in one of three queues: xPriorityQueue, xTxQueue, and xWaitQueue */
struct xLIST_ITEM xSegmentItem; /**< With this item the segment can be connected to a list, depending on who is owning it */
#endif
} TCPSegment_t;
/** @brief This struct describes the windows sizes, both for incoming and outgoing. */
typedef struct xTCP_WINSIZE
{
uint32_t ulRxWindowLength; /**< The TCP window size of the incoming stream. */
uint32_t ulTxWindowLength; /**< The TCP window size of the outgoing stream. */
} TCPWinSize_t;
/** @brief If TCP time-stamps are being used, they will occupy 12 bytes in
* each packet, and thus the message space will become smaller.
* Keep this as a multiple of 4 */
#if ( ipconfigUSE_TCP_WIN == 1 )
#define ipSIZE_TCP_OPTIONS 16U
#else
#define ipSIZE_TCP_OPTIONS 12U
#endif
/** @brief Every TCP connection owns a TCP window for the administration of all packets
* It owns two sets of segment descriptors, incoming and outgoing
*/
typedef struct xTCP_WINDOW
{
union
{
struct
{
uint32_t
bHasInit : 1, /**< The window structure has been initialised */
bSendFullSize : 1, /**< May only send packets with a size equal to MSS (for optimisation) */
bTimeStamps : 1; /**< Socket is supposed to use TCP time-stamps. This depends on the */
} bits; /**< party which opens the connection */
uint32_t ulFlags;
} u; /**< A collection of boolean flags. */
TCPWinSize_t xSize; /**< The TCP window sizes of the incoming and outgoing streams. */
struct
{
uint32_t ulFirstSequenceNumber; /**< Logging & debug: the first segment received/sent in this connection
* for Tx: initial send sequence number (ISS)
* for Rx: initial receive sequence number (IRS) */
uint32_t ulCurrentSequenceNumber; /**< Tx/Rx: the oldest sequence number not yet confirmed, also SND.UNA / RCV.NXT
* In other words: the sequence number of the left side of the sliding window */
uint32_t ulFINSequenceNumber; /**< The sequence number which carried the FIN flag */
uint32_t ulHighestSequenceNumber; /**< Sequence number of the right-most byte + 1 */
} rx, /**< Sequence number of the incoming data stream. */
tx; /**< Sequence number of the outgoing data stream. */
uint32_t ulOurSequenceNumber; /**< The SEQ number we're sending out */
uint32_t ulUserDataLength; /**< Number of bytes in Rx buffer which may be passed to the user, after having received a 'missing packet' */
uint32_t ulNextTxSequenceNumber; /**< The sequence number given to the next byte to be added for transmission */
int32_t lSRTT; /**< Smoothed Round Trip Time, it may increment quickly and it decrements slower */
uint8_t ucOptionLength; /**< Number of valid bytes in ulOptionsData[] */
#if ( ipconfigUSE_TCP_WIN == 1 )
List_t xPriorityQueue; /**< Priority queue: segments which must be sent immediately */
List_t xTxQueue; /**< Transmit queue: segments queued for transmission */
List_t xWaitQueue; /**< Waiting queue: outstanding segments */
TCPSegment_t * pxHeadSegment; /**< points to a segment which has not been transmitted and it's size is still growing (user data being added) */
uint32_t ulOptionsData[ ipSIZE_TCP_OPTIONS / sizeof( uint32_t ) ]; /**< Contains the options we send out */
List_t xTxSegments; /**< A linked list of all transmission segments, sorted on sequence number */
List_t xRxSegments; /**< A linked list of reception segments, order depends on sequence of arrival */
#else
/* For tiny TCP, there is only 1 outstanding TX segment */
TCPSegment_t xTxSegment; /**< Priority queue */
#endif
uint16_t usOurPortNumber; /**< Mostly for debugging/logging: our TCP port number */
uint16_t usPeerPortNumber; /**< debugging/logging: the peer's TCP port number */
uint16_t usMSS; /**< Current accepted MSS */
uint16_t usMSSInit; /**< MSS as configured by the socket owner */
} TCPWindow_t;
/*=============================================================================
*
* Creation and destruction
*
*=============================================================================*/
/* Create and initialize a window */
void vTCPWindowCreate( TCPWindow_t * pxWindow,
uint32_t ulRxWindowLength,
uint32_t ulTxWindowLength,
uint32_t ulAckNumber,
uint32_t ulSequenceNumber,
uint32_t ulMSS );
/* Destroy a window (always returns NULL)
* It will free some resources: a collection of segments */
void vTCPWindowDestroy( TCPWindow_t const * pxWindow );
/* Initialize a window */
void vTCPWindowInit( TCPWindow_t * pxWindow,
uint32_t ulAckNumber,
uint32_t ulSequenceNumber,
uint32_t ulMSS );
/* Clean up allocated segments. Should only be called when FreeRTOS+TCP will no longer be used. */
void vTCPSegmentCleanup( void );
/*=============================================================================
*
* Rx functions
*
*=============================================================================*/
/* if true may be passed directly to user (segment expected and window is empty)
* But pxWindow->ackno should always be used to set "BUF->ackno" */
int32_t lTCPWindowRxCheck( TCPWindow_t * pxWindow,
uint32_t ulSequenceNumber,
uint32_t ulLength,
uint32_t ulSpace,
uint32_t * pulSkipCount );
/* This function will be called as soon as a FIN is received. It will return true
* if there are no 'open' reception segments */
BaseType_t xTCPWindowRxEmpty( const TCPWindow_t * pxWindow );
/*=============================================================================
*
* Tx functions
*
*=============================================================================*/
/* Adds data to the Tx-window */
int32_t lTCPWindowTxAdd( TCPWindow_t * pxWindow,
uint32_t ulLength,
int32_t lPosition,
int32_t lMax );
/* Check data to be sent and calculate the time period we may sleep */
BaseType_t xTCPWindowTxHasData( TCPWindow_t const * pxWindow,
uint32_t ulWindowSize,
TickType_t * pulDelay );
/* See if anything is left to be sent
* Function will be called when a FIN has been received. Only when the TX window is clean,
* it will return pdTRUE */
BaseType_t xTCPWindowTxDone( const TCPWindow_t * pxWindow );
/* Fetches data to be sent.
* 'plPosition' will point to a location with the circular data buffer: txStream */
uint32_t ulTCPWindowTxGet( TCPWindow_t * pxWindow,
uint32_t ulWindowSize,
int32_t * plPosition );
/* Receive a normal ACK */
uint32_t ulTCPWindowTxAck( TCPWindow_t * pxWindow,
uint32_t ulSequenceNumber );
/* Receive a SACK option */
uint32_t ulTCPWindowTxSack( TCPWindow_t * pxWindow,
uint32_t ulFirst,
uint32_t ulLast );
/**
* @brief Check if a > b, where a and b are rolling counters.
*
* @param[in] a: The value on the left-hand side.
* @param[in] b: The value on the right-hand side.
*
* @return pdTRUE if a > b, otherwise pdFALSE.
*
* @note GreaterThan is calculated as "( a - ( b + 1U ) ) < 0x80000000".
*/
BaseType_t xSequenceGreaterThan( uint32_t a,
uint32_t b );
/**
* @brief Check if a < b, where a and b are rolling counters.
*
* @param[in] a: The value on the left-hand side.
* @param[in] b: The value on the right-hand side.
*
* @return pdTRUE if a < b, otherwise pdFALSE.
*
* @note LessThan is implemented as "( b - ( a + 1 ) ) < 0x80000000".
*/
BaseType_t xSequenceLessThan( uint32_t a,
uint32_t b );
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_TCP_WIN_H */

View File

@ -0,0 +1,55 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef FREERTOS_UDP_IP_H
#define FREERTOS_UDP_IP_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* Application level configuration options. */
#include "FreeRTOSIPConfig.h"
#include "FreeRTOSIPConfigDefaults.h"
#include "IPTraceMacroDefaults.h"
#include "FreeRTOS_IP.h"
/*
* Called when the application has generated a UDP packet to send.
*/
void vProcessGeneratedUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* FREERTOS_UDP_IP_H */

View File

@ -0,0 +1,98 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef FREERTOS_ERRNO_TCP
#define FREERTOS_ERRNO_TCP
/* The following definitions will be included in the core FreeRTOS code in
* future versions of FreeRTOS - hence the 'pd' (ProjDefs) prefix - at which time
* this file will be removed. */
/* The following errno values are used by FreeRTOS+ components, not FreeRTOS
* itself. */
/* For future compatibility (see comment above), check the definitions have not
* already been made. */
#ifndef pdFREERTOS_ERRNO_NONE
#define pdFREERTOS_ERRNO_NONE 0 /* No errors */
#define pdFREERTOS_ERRNO_ENOENT 2 /* No such file or directory */
#define pdFREERTOS_ERRNO_EINTR 4 /* Interrupted system call */
#define pdFREERTOS_ERRNO_EIO 5 /* I/O error */
#define pdFREERTOS_ERRNO_ENXIO 6 /* No such device or address */
#define pdFREERTOS_ERRNO_EBADF 9 /* Bad file number */
#define pdFREERTOS_ERRNO_EAGAIN 11 /* No more processes */
#define pdFREERTOS_ERRNO_EWOULDBLOCK 11 /* Operation would block */
#define pdFREERTOS_ERRNO_ENOMEM 12 /* Not enough memory */
#define pdFREERTOS_ERRNO_EACCES 13 /* Permission denied */
#define pdFREERTOS_ERRNO_EFAULT 14 /* Bad address */
#define pdFREERTOS_ERRNO_EBUSY 16 /* Mount device busy */
#define pdFREERTOS_ERRNO_EEXIST 17 /* File exists */
#define pdFREERTOS_ERRNO_EXDEV 18 /* Cross-device link */
#define pdFREERTOS_ERRNO_ENODEV 19 /* No such device */
#define pdFREERTOS_ERRNO_ENOTDIR 20 /* Not a directory */
#define pdFREERTOS_ERRNO_EISDIR 21 /* Is a directory */
#define pdFREERTOS_ERRNO_EINVAL 22 /* Invalid argument */
#define pdFREERTOS_ERRNO_ENOSPC 28 /* No space left on device */
#define pdFREERTOS_ERRNO_ESPIPE 29 /* Illegal seek */
#define pdFREERTOS_ERRNO_EROFS 30 /* Read only file system */
#define pdFREERTOS_ERRNO_EUNATCH 42 /* Protocol driver not attached */
#define pdFREERTOS_ERRNO_EBADE 50 /* Invalid exchange */
#define pdFREERTOS_ERRNO_EFTYPE 79 /* Inappropriate file type or format */
#define pdFREERTOS_ERRNO_ENMFILE 89 /* No more files */
#define pdFREERTOS_ERRNO_ENOTEMPTY 90 /* Directory not empty */
#define pdFREERTOS_ERRNO_ENAMETOOLONG 91 /* File or path name too long */
#define pdFREERTOS_ERRNO_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define pdFREERTOS_ERRNO_EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define pdFREERTOS_ERRNO_ENOBUFS 105 /* No buffer space available */
#define pdFREERTOS_ERRNO_ENOPROTOOPT 109 /* Protocol not available */
#define pdFREERTOS_ERRNO_EADDRINUSE 112 /* Address already in use */
#define pdFREERTOS_ERRNO_ETIMEDOUT 116 /* Connection timed out */
#define pdFREERTOS_ERRNO_EINPROGRESS 119 /* Connection already in progress */
#define pdFREERTOS_ERRNO_EALREADY 120 /* Socket already connected */
#define pdFREERTOS_ERRNO_EADDRNOTAVAIL 125 /* Address not available */
#define pdFREERTOS_ERRNO_EISCONN 127 /* Socket is already connected */
#define pdFREERTOS_ERRNO_ENOTCONN 128 /* Socket is not connected */
#define pdFREERTOS_ERRNO_ENOMEDIUM 135 /* No medium inserted */
#define pdFREERTOS_ERRNO_EILSEQ 138 /* An invalid UTF-16 sequence was encountered. */
#define pdFREERTOS_ERRNO_ECANCELED 140 /* Operation canceled. */
/* The following endian values are used by FreeRTOS+ components, not FreeRTOS
* itself. */
#define pdFREERTOS_LITTLE_ENDIAN 0
#define pdFREERTOS_BIG_ENDIAN 1
#else /* ifndef pdFREERTOS_ERRNO_NONE */
#ifndef pdFREERTOS_ERRNO_EAFNOSUPPORT
#define pdFREERTOS_ERRNO_EAFNOSUPPORT 97 /* Address family not supported by protocol */
#endif /* pdFREERTOS_ERRNO_EAFNOSUPPORT */
#endif /* pdFREERTOS_ERRNO_NONE */
/* Translate a pdFREERTOS_ERRNO code to a human readable string. */
const char * FreeRTOS_strerror_r( BaseType_t xErrnum,
char * pcBuffer,
size_t uxLength );
#endif /* FREERTOS_ERRNO_TCP */

View File

@ -0,0 +1,277 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/* This file provides default (empty) implementations for any IP trace macros
* that are not defined by the user. See
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Trace.html */
#ifndef UDP_TRACE_MACRO_DEFAULTS_H
#define UDP_TRACE_MACRO_DEFAULTS_H
#ifndef iptraceNETWORK_DOWN
#define iptraceNETWORK_DOWN()
#endif
#ifndef iptraceNETWORK_BUFFER_RELEASED
#define iptraceNETWORK_BUFFER_RELEASED( pxBufferAddress )
#endif
#ifndef iptraceNETWORK_BUFFER_OBTAINED
#define iptraceNETWORK_BUFFER_OBTAINED( pxBufferAddress )
#endif
#ifndef iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR
#define iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxBufferAddress )
#endif
#ifndef iptraceNETWORK_INTERFACE_INPUT
/* An Ethernet packet has been received. */
#define iptraceNETWORK_INTERFACE_INPUT( uxDataLength, pucEthernetBuffer )
#endif
#ifndef iptraceNETWORK_INTERFACE_OUTPUT
/* An Ethernet packet will be sent. */
#define iptraceNETWORK_INTERFACE_OUTPUT( uxDataLength, pucEthernetBuffer )
#endif
#ifndef iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER
#define iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER()
#endif
#ifndef iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR
#define iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR()
#endif
#ifndef iptraceDROPPED_INVALID_ARP_PACKET
#define iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader )
#endif
#ifndef iptraceCREATING_ARP_REQUEST
#define iptraceCREATING_ARP_REQUEST( ulIPAddress )
#endif
/* A packet came in from an unknown IPv4 address.
* An ARP request has been sent and the network
* buffer is stored for processing later.*/
#ifndef iptraceDELAYED_ARP_REQUEST_STARTED
#define iptraceDELAYED_ARP_REQUEST_STARTED()
#endif
/* A packet has come in from an unknown IPv4 address.
* An ARP request has been sent, but the queue is
* still filled with a different packet. */
#ifndef iptraceDELAYED_ARP_BUFFER_FULL
#define iptraceDELAYED_ARP_BUFFER_FULL()
#endif
/* An ARP request has been sent, and a matching
* reply is received. Now the original
* packet will be processed by the IP-task. */
#ifndef iptrace_DELAYED_ARP_REQUEST_REPLIED
#define iptrace_DELAYED_ARP_REQUEST_REPLIED()
#endif
/* A packet was stored for delayed processing, but
* there is no ARP reply. The network buffer will
* be released without being processed. */
#ifndef iptraceDELAYED_ARP_TIMER_EXPIRED
#define iptraceDELAYED_ARP_TIMER_EXPIRED()
#endif
#ifndef iptraceARP_TABLE_ENTRY_WILL_EXPIRE
#define iptraceARP_TABLE_ENTRY_WILL_EXPIRE( ulIPAddress )
#endif
#ifndef iptraceARP_TABLE_ENTRY_EXPIRED
#define iptraceARP_TABLE_ENTRY_EXPIRED( ulIPAddress )
#endif
#ifndef iptraceARP_TABLE_ENTRY_CREATED
#define iptraceARP_TABLE_ENTRY_CREATED( ulIPAddress, ucMACAddress )
#endif
#ifndef iptraceSENDING_UDP_PACKET
#define iptraceSENDING_UDP_PACKET( ulIPAddress )
#endif
#ifndef iptracePACKET_DROPPED_TO_GENERATE_ARP
#define iptracePACKET_DROPPED_TO_GENERATE_ARP( ulIPAddress )
#endif
#ifndef iptraceICMP_PACKET_RECEIVED
#define iptraceICMP_PACKET_RECEIVED()
#endif
#ifndef iptraceSENDING_PING_REPLY
#define iptraceSENDING_PING_REPLY( ulIPAddress )
#endif
#ifndef traceARP_PACKET_RECEIVED
#define traceARP_PACKET_RECEIVED()
#endif
#ifndef iptracePROCESSING_RECEIVED_ARP_REPLY
#define iptracePROCESSING_RECEIVED_ARP_REPLY( ulIPAddress )
#endif
#ifndef iptraceSENDING_ARP_REPLY
#define iptraceSENDING_ARP_REPLY( ulIPAddress )
#endif
#ifndef iptraceFAILED_TO_CREATE_SOCKET
#define iptraceFAILED_TO_CREATE_SOCKET()
#endif
#ifndef iptraceFAILED_TO_CREATE_EVENT_GROUP
#define iptraceFAILED_TO_CREATE_EVENT_GROUP()
#endif
#ifndef iptraceRECVFROM_DISCARDING_BYTES
#define iptraceRECVFROM_DISCARDING_BYTES( xNumberOfBytesDiscarded )
#endif
#ifndef iptraceETHERNET_RX_EVENT_LOST
#define iptraceETHERNET_RX_EVENT_LOST()
#endif
#ifndef iptraceSTACK_TX_EVENT_LOST
#define iptraceSTACK_TX_EVENT_LOST( xEvent )
#endif
#ifndef iptraceNETWORK_EVENT_RECEIVED
#define iptraceNETWORK_EVENT_RECEIVED( eEvent )
#endif
#ifndef iptraceBIND_FAILED
#define iptraceBIND_FAILED( xSocket, usPort )
#endif
#ifndef iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS
#define iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS( ulIPAddress )
#endif
#ifndef iptraceSENDING_DHCP_DISCOVER
#define iptraceSENDING_DHCP_DISCOVER()
#endif
#ifndef iptraceSENDING_DHCP_REQUEST
#define iptraceSENDING_DHCP_REQUEST()
#endif
#ifndef iptraceDHCP_SUCCEDEED
#define iptraceDHCP_SUCCEDEED( address )
#endif
#ifndef iptraceNETWORK_INTERFACE_TRANSMIT
#define iptraceNETWORK_INTERFACE_TRANSMIT()
#endif
#ifndef iptraceNETWORK_INTERFACE_RECEIVE
#define iptraceNETWORK_INTERFACE_RECEIVE()
#endif
#ifndef iptraceSENDING_DNS_REQUEST
#define iptraceSENDING_DNS_REQUEST()
#endif
#ifndef iptraceWAITING_FOR_TX_DMA_DESCRIPTOR
#define iptraceWAITING_FOR_TX_DMA_DESCRIPTOR()
#endif
#ifndef ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS
#define ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS 0
#endif
#ifndef iptraceFAILED_TO_NOTIFY_SELECT_GROUP
#define iptraceFAILED_TO_NOTIFY_SELECT_GROUP( xSocket )
#endif
#ifndef pvPortMallocSocket
#define pvPortMallocSocket( xSize ) pvPortMalloc( ( xSize ) )
#endif
#ifndef iptraceRECVFROM_TIMEOUT
#define iptraceRECVFROM_TIMEOUT()
#endif
#ifndef iptraceRECVFROM_INTERRUPTED
#define iptraceRECVFROM_INTERRUPTED()
#endif
#ifndef iptraceNO_BUFFER_FOR_SENDTO
#define iptraceNO_BUFFER_FOR_SENDTO()
#endif
#ifndef iptraceSENDTO_SOCKET_NOT_BOUND
#define iptraceSENDTO_SOCKET_NOT_BOUND()
#endif
#ifndef iptraceSENDTO_DATA_TOO_LONG
#define iptraceSENDTO_DATA_TOO_LONG()
#endif
#ifndef ipconfigUSE_TCP_MEM_STATS
#define ipconfigUSE_TCP_MEM_STATS 0
#endif
#if ( ipconfigUSE_TCP_MEM_STATS == 0 )
/* See tools/tcp_mem_stat.c */
#ifndef iptraceMEM_STATS_CREATE
#define iptraceMEM_STATS_CREATE( xMemType, pxObject, uxSize )
#endif
#ifndef iptraceMEM_STATS_DELETE
#define iptraceMEM_STATS_DELETE( pxObject )
#endif
#ifndef iptraceMEM_STATS_CLOSE
#define iptraceMEM_STATS_CLOSE()
#endif
#endif /* ( ipconfigUSE_TCP_MEM_STATS != 0 ) */
#ifndef ipconfigUSE_DUMP_PACKETS
#define ipconfigUSE_DUMP_PACKETS 0
#endif
#if ( ipconfigUSE_DUMP_PACKETS == 0 )
/* See tools/tcp_dump_packets.c */
#ifndef iptraceDUMP_INIT
#define iptraceDUMP_INIT( pcFileName, pxEntries )
#endif
#ifndef iptraceDUMP_PACKET
#define iptraceDUMP_PACKET( pucBuffer, uxLength, xIncoming )
#endif
#endif /* ( ipconfigUSE_DUMP_PACKETS != 0 ) */
#endif /* UDP_TRACE_MACRO_DEFAULTS_H */

View File

@ -0,0 +1,83 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef NETWORK_BUFFER_MANAGEMENT_H
#define NETWORK_BUFFER_MANAGEMENT_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* NOTE PUBLIC API FUNCTIONS. */
BaseType_t xNetworkBuffersInitialise( void );
NetworkBufferDescriptor_t * pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes,
TickType_t xBlockTimeTicks );
/* The definition of the below function is only available if BufferAllocation_2.c has been linked into the source. */
NetworkBufferDescriptor_t * pxNetworkBufferGetFromISR( size_t xRequestedSizeBytes );
void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer );
/* The definition of the below function is only available if BufferAllocation_2.c has been linked into the source. */
BaseType_t vNetworkBufferReleaseFromISR( NetworkBufferDescriptor_t * const pxNetworkBuffer );
uint8_t * pucGetNetworkBuffer( size_t * pxRequestedSizeBytes );
void vReleaseNetworkBuffer( uint8_t * pucEthernetBuffer );
/* Get the current number of free network buffers. */
UBaseType_t uxGetNumberOfFreeNetworkBuffers( void );
/* Get the lowest number of free network buffers. */
UBaseType_t uxGetMinimumFreeNetworkBuffers( void );
/* Copy a network buffer into a bigger buffer. */
NetworkBufferDescriptor_t * pxDuplicateNetworkBufferWithDescriptor( const NetworkBufferDescriptor_t * const pxNetworkBuffer,
size_t uxNewLength );
/* Increase the size of a Network Buffer.
* In case BufferAllocation_2.c is used, the new space must be allocated. */
NetworkBufferDescriptor_t * pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer,
size_t xNewSizeBytes );
#if ipconfigTCP_IP_SANITY
/*
* Check if an address is a valid pointer to a network descriptor
* by looking it up in the array of network descriptors
*/
UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );
BaseType_t prvIsFreeBuffer( const NetworkBufferDescriptor_t * pxDescr );
#endif
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* NETWORK_BUFFER_MANAGEMENT_H */

View File

@ -0,0 +1,54 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef NETWORK_INTERFACE_H
#define NETWORK_INTERFACE_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* INTERNAL API FUNCTIONS. */
BaseType_t xNetworkInterfaceInitialise( void );
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer,
BaseType_t xReleaseAfterSend );
/* The following function is defined only when BufferAllocation_1.c is linked in the project. */
void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] );
/* The following function is defined only when BufferAllocation_1.c is linked in the project. */
BaseType_t xGetPhyLinkStatus( void );
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* NETWORK_INTERFACE_H */

View File

@ -0,0 +1,440 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/******************************************************************************
*
* See the following web page for essential buffer allocation scheme usage and
* configuration details:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html
*
******************************************************************************/
/* Standard includes. */
#include <stdint.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_IP_Private.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
/* For an Ethernet interrupt to be able to obtain a network buffer there must
* be at least this number of buffers available. */
#define baINTERRUPT_BUFFER_GET_THRESHOLD ( 3 )
/* A list of free (available) NetworkBufferDescriptor_t structures. */
static List_t xFreeBuffersList;
/* Some statistics about the use of buffers. */
static UBaseType_t uxMinimumFreeNetworkBuffers = 0U;
/* 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 xNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];
/* This constant is defined as true to let FreeRTOS_TCP_IP.c know that the
* network buffers have constant size, large enough to hold the biggest Ethernet
* packet. No resizing will be done. */
const BaseType_t xBufferAllocFixedSize = pdTRUE;
/* The semaphore used to obtain network buffers. */
static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;
#if ( ipconfigTCP_IP_SANITY != 0 )
static char cIsLow = pdFALSE;
UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );
#else
static UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );
#endif /* ipconfigTCP_IP_SANITY */
static void prvShowWarnings( void );
/* The user can define their own ipconfigBUFFER_ALLOC_LOCK() and
* ipconfigBUFFER_ALLOC_UNLOCK() macros, especially for use form an ISR. If these
* are not defined then default them to call the normal enter/exit critical
* section macros. */
#if !defined( ipconfigBUFFER_ALLOC_LOCK )
#define ipconfigBUFFER_ALLOC_INIT() do {} while( ipFALSE_BOOL )
#define ipconfigBUFFER_ALLOC_LOCK_FROM_ISR() \
UBaseType_t uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \
{
#define ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR() \
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
}
#define ipconfigBUFFER_ALLOC_LOCK() taskENTER_CRITICAL()
#define ipconfigBUFFER_ALLOC_UNLOCK() taskEXIT_CRITICAL()
#endif /* ipconfigBUFFER_ALLOC_LOCK */
/*-----------------------------------------------------------*/
#if ( ipconfigTCP_IP_SANITY != 0 )
/* HT: SANITY code will be removed as soon as the library is stable
* and and ready to become public
* Function below gives information about the use of buffers */
#define WARN_LOW ( 2 )
#define WARN_HIGH ( ( 5 * ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) / 10 )
#endif /* ipconfigTCP_IP_SANITY */
/*-----------------------------------------------------------*/
#if ( ipconfigTCP_IP_SANITY != 0 )
BaseType_t prvIsFreeBuffer( const NetworkBufferDescriptor_t * pxDescr )
{
return ( bIsValidNetworkDescriptor( pxDescr ) != 0 ) &&
( listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxDescr->xBufferListItem ) ) != 0 );
}
/*-----------------------------------------------------------*/
static void prvShowWarnings( void )
{
UBaseType_t uxCount = uxGetNumberOfFreeNetworkBuffers();
if( ( ( cIsLow == 0 ) && ( uxCount <= WARN_LOW ) ) || ( ( cIsLow != 0 ) && ( uxCount >= WARN_HIGH ) ) )
{
cIsLow = !cIsLow;
FreeRTOS_debug_printf( ( "*** Warning *** %s %lu buffers left\n", cIsLow ? "only" : "now", uxCount ) );
}
}
/*-----------------------------------------------------------*/
UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc )
{
uint32_t offset = ( uint32_t ) ( ( ( const char * ) pxDesc ) - ( ( const char * ) xNetworkBuffers ) );
if( ( offset >= sizeof( xNetworkBuffers ) ) ||
( ( offset % sizeof( xNetworkBuffers[ 0 ] ) ) != 0 ) )
{
return pdFALSE;
}
return ( UBaseType_t ) ( pxDesc - xNetworkBuffers ) + 1;
}
/*-----------------------------------------------------------*/
#else /* if ( ipconfigTCP_IP_SANITY != 0 ) */
static UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc )
{
( void ) pxDesc;
return ( UBaseType_t ) pdTRUE;
}
/*-----------------------------------------------------------*/
static void prvShowWarnings( void )
{
}
/*-----------------------------------------------------------*/
#endif /* ipconfigTCP_IP_SANITY */
BaseType_t xNetworkBuffersInitialise( void )
{
BaseType_t xReturn;
uint32_t x;
/* Only initialise the buffers and their associated kernel objects if they
* have not been initialised before. */
if( xNetworkBufferSemaphore == NULL )
{
/* In case alternative locking is used, the mutexes can be initialised
* here */
ipconfigBUFFER_ALLOC_INIT();
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
{
static StaticSemaphore_t xNetworkBufferSemaphoreBuffer;
xNetworkBufferSemaphore = xSemaphoreCreateCountingStatic(
( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS,
( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS,
&xNetworkBufferSemaphoreBuffer );
}
#else
{
xNetworkBufferSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
configASSERT( xNetworkBufferSemaphore != NULL );
if( xNetworkBufferSemaphore != NULL )
{
vListInitialise( &xFreeBuffersList );
/* Initialise all the network buffers. The buffer storage comes
* from the network interface, and different hardware has different
* requirements. */
vNetworkInterfaceAllocateRAMToBuffers( xNetworkBuffers );
for( x = 0U; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
{
/* Initialise and set the owner of the buffer list items. */
vListInitialiseItem( &( xNetworkBuffers[ x ].xBufferListItem ) );
listSET_LIST_ITEM_OWNER( &( xNetworkBuffers[ x ].xBufferListItem ), &xNetworkBuffers[ x ] );
/* Currently, all buffers are available for use. */
vListInsert( &xFreeBuffersList, &( xNetworkBuffers[ x ].xBufferListItem ) );
}
uxMinimumFreeNetworkBuffers = ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;
}
}
if( xNetworkBufferSemaphore == NULL )
{
xReturn = pdFAIL;
}
else
{
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/
NetworkBufferDescriptor_t * pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes,
TickType_t xBlockTimeTicks )
{
NetworkBufferDescriptor_t * pxReturn = NULL;
BaseType_t xInvalid = pdFALSE;
UBaseType_t uxCount;
/* The current implementation only has a single size memory block, so
* the requested size parameter is not used (yet). */
( void ) xRequestedSizeBytes;
if( xNetworkBufferSemaphore != NULL )
{
/* 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. */
ipconfigBUFFER_ALLOC_LOCK();
{
pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
if( ( bIsValidNetworkDescriptor( pxReturn ) != pdFALSE_UNSIGNED ) &&
listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxReturn->xBufferListItem ) ) )
{
( void ) uxListRemove( &( pxReturn->xBufferListItem ) );
}
else
{
xInvalid = pdTRUE;
}
}
ipconfigBUFFER_ALLOC_UNLOCK();
if( xInvalid == pdTRUE )
{
/* _RB_ Can printf() be called from an interrupt? (comment
* above says this can be called from an interrupt too) */
/* _HT_ The function shall not be called from an ISR. Comment
* was indeed misleading. Hopefully clear now?
* So the printf()is OK here. */
FreeRTOS_debug_printf( ( "pxGetNetworkBufferWithDescriptor: INVALID BUFFER: %p (valid %lu)\n",
pxReturn, bIsValidNetworkDescriptor( pxReturn ) ) );
pxReturn = NULL;
}
else
{
/* Reading UBaseType_t, no critical section needed. */
uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );
/* For stats, latch the lowest number of network buffers since
* booting. */
if( uxMinimumFreeNetworkBuffers > uxCount )
{
uxMinimumFreeNetworkBuffers = uxCount;
}
pxReturn->xDataLength = xRequestedSizeBytes;
#if ( ipconfigTCP_IP_SANITY != 0 )
{
prvShowWarnings();
}
#endif /* ipconfigTCP_IP_SANITY */
#if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
{
/* make sure the buffer is not linked */
pxReturn->pxNextBuffer = NULL;
}
#endif /* ipconfigUSE_LINKED_RX_MESSAGES */
}
iptraceNETWORK_BUFFER_OBTAINED( pxReturn );
}
else
{
/* lint wants to see at least a comment. */
iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
}
}
return pxReturn;
}
/*-----------------------------------------------------------*/
NetworkBufferDescriptor_t * pxNetworkBufferGetFromISR( size_t xRequestedSizeBytes )
{
NetworkBufferDescriptor_t * pxReturn = NULL;
/* The current implementation only has a single size memory block, so
* the requested size parameter is not used (yet). */
( void ) xRequestedSizeBytes;
/* If there is a semaphore available then there is a buffer available, but,
* as this is called from an interrupt, only take a buffer if there are at
* least baINTERRUPT_BUFFER_GET_THRESHOLD buffers remaining. This prevents,
* to a certain degree at least, a rapidly executing interrupt exhausting
* buffer and in so doing preventing tasks from continuing. */
if( uxQueueMessagesWaitingFromISR( ( QueueHandle_t ) xNetworkBufferSemaphore ) > ( UBaseType_t ) baINTERRUPT_BUFFER_GET_THRESHOLD )
{
if( xSemaphoreTakeFromISR( xNetworkBufferSemaphore, NULL ) == pdPASS )
{
/* Protect the structure as it is accessed from tasks and interrupts. */
ipconfigBUFFER_ALLOC_LOCK_FROM_ISR();
{
pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
uxListRemove( &( pxReturn->xBufferListItem ) );
}
ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR();
iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxReturn );
}
}
if( pxReturn == NULL )
{
iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR();
}
return pxReturn;
}
/*-----------------------------------------------------------*/
BaseType_t vNetworkBufferReleaseFromISR( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* Ensure the buffer is returned to the list of free buffers before the
* counting semaphore is 'given' to say a buffer is available. */
ipconfigBUFFER_ALLOC_LOCK_FROM_ISR();
{
vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
}
ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR();
( void ) xSemaphoreGiveFromISR( xNetworkBufferSemaphore, &xHigherPriorityTaskWoken );
iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
return xHigherPriorityTaskWoken;
}
/*-----------------------------------------------------------*/
void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
BaseType_t xListItemAlreadyInFreeList;
if( bIsValidNetworkDescriptor( pxNetworkBuffer ) == pdFALSE_UNSIGNED )
{
FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: Invalid buffer %p\n", pxNetworkBuffer ) );
}
else
{
/* Ensure the buffer is returned to the list of free buffers before the
* counting semaphore is 'given' to say a buffer is available. */
ipconfigBUFFER_ALLOC_LOCK();
{
{
xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
if( xListItemAlreadyInFreeList == pdFALSE )
{
vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
}
}
}
ipconfigBUFFER_ALLOC_UNLOCK();
if( xListItemAlreadyInFreeList )
{
FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: %p ALREADY RELEASED (now %lu)\n",
pxNetworkBuffer, uxGetNumberOfFreeNetworkBuffers() ) );
}
else
{
( void ) xSemaphoreGive( xNetworkBufferSemaphore );
prvShowWarnings();
}
iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
}
}
/*-----------------------------------------------------------*/
UBaseType_t uxGetMinimumFreeNetworkBuffers( void )
{
return uxMinimumFreeNetworkBuffers;
}
/*-----------------------------------------------------------*/
UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )
{
return listCURRENT_LIST_LENGTH( &xFreeBuffersList );
}
NetworkBufferDescriptor_t * pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer,
size_t xNewSizeBytes )
{
/* In BufferAllocation_1.c all network buffer are allocated with a
* maximum size of 'ipTOTAL_ETHERNET_FRAME_SIZE'.No need to resize the
* network buffer. */
pxNetworkBuffer->xDataLength = xNewSizeBytes;
return pxNetworkBuffer;
}
/*#endif */ /* ipconfigINCLUDE_TEST_CODE */

View File

@ -0,0 +1,434 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/******************************************************************************
*
* 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 <stdint.h>
/* 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"
/* 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 */
/* Compile time assertion with zero runtime effects
* it will assert on 'e' not being zero, as it tries to divide by it,
* will also print the line where the error occured in case of failure */
/* MISRA Ref 20.10.1 [Lack of sizeof operator and compile time error checking] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-2010 */
/* coverity[misra_c_2012_rule_20_10_violation] */
#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;
/* 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;
/*-----------------------------------------------------------*/
BaseType_t xNetworkBuffersInitialise( void )
{
/* 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 ];
BaseType_t xReturn;
uint32_t x;
/* Only initialise the buffers and their associated kernel objects if they
* have not been initialised before. */
if( xNetworkBufferSemaphore == NULL )
{
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
{
static StaticSemaphore_t xNetworkBufferSemaphoreBuffer;
xNetworkBufferSemaphore = xSemaphoreCreateCountingStatic(
ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS,
ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS,
&xNetworkBufferSemaphoreBuffer );
}
#else
{
xNetworkBufferSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
configASSERT( xNetworkBufferSemaphore != NULL );
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 = 0U; 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). */
pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xSize + ipBUFFER_PADDING );
configASSERT( pucEthernetBuffer != NULL );
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. */
pucEthernetBuffer += ipBUFFER_PADDING;
}
return pucEthernetBuffer;
}
/*-----------------------------------------------------------*/
void vReleaseNetworkBuffer( uint8_t * pucEthernetBuffer )
{
uint8_t * pucEthernetBufferCopy = 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. */
if( pucEthernetBufferCopy != NULL )
{
pucEthernetBufferCopy -= ipBUFFER_PADDING;
vPortFree( ( void * ) pucEthernetBufferCopy );
}
}
/*-----------------------------------------------------------*/
NetworkBufferDescriptor_t * pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes,
TickType_t xBlockTimeTicks )
{
NetworkBufferDescriptor_t * pxReturn = NULL;
size_t uxCount;
size_t uxMaxAllowedBytes = ( SIZE_MAX >> 1 );
size_t xRequestedSizeBytesCopy = xRequestedSizeBytes;
if( ( xRequestedSizeBytesCopy <= uxMaxAllowedBytes ) && ( xNetworkBufferSemaphore != NULL ) )
{
/* 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 );
( void ) 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( xRequestedSizeBytesCopy > 0U )
{
if( ( xRequestedSizeBytesCopy < ( size_t ) baMINIMAL_BUFFER_SIZE ) )
{
/* ARP packets can replace application packets, so the storage must be
* at least large enough to hold an ARP. */
xRequestedSizeBytesCopy = baMINIMAL_BUFFER_SIZE;
}
/* Add 2 bytes to xRequestedSizeBytesCopy and round up xRequestedSizeBytesCopy
* to the nearest multiple of N bytes, where N equals 'sizeof( size_t )'. */
xRequestedSizeBytesCopy += 2U;
if( ( xRequestedSizeBytesCopy & ( sizeof( size_t ) - 1U ) ) != 0U )
{
xRequestedSizeBytesCopy = ( xRequestedSizeBytesCopy | ( sizeof( size_t ) - 1U ) ) + 1U;
}
/* Extra space is obtained so a pointer to the network buffer can
* be stored at the beginning of the buffer. */
pxReturn->pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xRequestedSizeBytesCopy + ipBUFFER_PADDING );
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. */
/* MISRA Ref 11.3.1 [Misaligned access] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
/* coverity[misra_c_2012_rule_11_3_violation] */
*( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer ) ) = pxReturn;
pxReturn->pucEthernetBuffer += ipBUFFER_PADDING;
/* Store the actual size of the allocated buffer, which may be
* greater than the original requested size. */
pxReturn->xDataLength = xRequestedSizeBytesCopy;
#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
{
/* No action. */
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;
pxNetworkBuffer->xDataLength = 0U;
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
{
/* No action. */
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;
size_t uxSizeBytes = xNewSizeBytes;
NetworkBufferDescriptor_t * pxNetworkBufferCopy = pxNetworkBuffer;
xOriginalLength = pxNetworkBufferCopy->xDataLength + ipBUFFER_PADDING;
uxSizeBytes = uxSizeBytes + ipBUFFER_PADDING;
pucBuffer = pucGetNetworkBuffer( &( uxSizeBytes ) );
if( pucBuffer == NULL )
{
/* In case the allocation fails, return NULL. */
pxNetworkBufferCopy = NULL;
}
else
{
pxNetworkBufferCopy->xDataLength = uxSizeBytes;
if( uxSizeBytes > xOriginalLength )
{
uxSizeBytes = xOriginalLength;
}
( void ) memcpy( pucBuffer - ipBUFFER_PADDING,
pxNetworkBufferCopy->pucEthernetBuffer - ipBUFFER_PADDING,
uxSizeBytes );
vReleaseNetworkBuffer( pxNetworkBufferCopy->pucEthernetBuffer );
pxNetworkBufferCopy->pucEthernetBuffer = pucBuffer;
}
return pxNetworkBufferCopy;
}

View File

@ -0,0 +1,30 @@
/**
* @file: pack_struct_end.h
* @author: jscott
* @date: Feb 1, 2022
* @copyright: Hotstart 2022 Hotstart Thermal Management. 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.
*
* @brief: TI's Code Generation Tools do not add a trailing directive for packing structures
*
* Contains a semicolon to end the wrapped structure,
* and resets warnings that were supressed in pack_struct_start.h.
*/
;
#pragma diag_pop

View File

@ -0,0 +1,31 @@
/**
* @file: pack_struct_start.h
* @author: jscott
* @date: Feb 1, 2022
* @copyright: Hotstart 2022 Hotstart Thermal Management. 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.
*
* @brief: The leading compiler directive to pack the following structure to 1 byte
*
* Also suppress an incorrect warning from the CCS compiler:
* error #1916-D: definition at end of file not followed by a semicolon or a declarator
*/
#pragma diag_push
#pragma diag_suppress=1916
#pragma pack(1)

View File

@ -0,0 +1,3 @@
Update pack_struct_start.h and pack_struct_end.h for your architecure.
These files define the specifiers needed by your compiler to properly pack struct data
need by FreeRTOS+TCP.

View File

@ -0,0 +1,34 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
; /* FIX ME. Update for the compiler specifier needed at end of a struct declaration to pack the struct. */

View File

@ -0,0 +1,34 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
/* FIX ME. Update for the compiler specifier needed at the start of a struct declaration to pack the struct. */

View File

@ -0,0 +1,34 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
__attribute__( ( packed ) );

View File

@ -0,0 +1,35 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
/* Nothing to do here. */

View File

@ -0,0 +1,35 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
;

View File

@ -0,0 +1,35 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
__packed

View File

@ -0,0 +1,35 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
;
#pragma pack(pop)

View File

@ -0,0 +1,35 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
#pragma pack(push,1)

View File

@ -0,0 +1,36 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
;
#pragma pack( pop )

View File

@ -0,0 +1,35 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
#pragma pack( push, 1 )

View File

@ -0,0 +1,47 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
#ifdef _SH
#ifdef __RENESAS__
;
#pragma unpack
#endif
#endif
#ifdef __RX
#ifdef __CCRX__
;
#pragma packoption
#endif
#endif

View File

@ -0,0 +1,45 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
#ifdef _SH
#ifdef __RENESAS__
#pragma pack 1
#endif
#endif
#ifdef __RX
#ifdef __CCRX__
#pragma pack
#endif
#endif

View File

@ -0,0 +1,654 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "NetworkBufferManagement.h"
#include "NetworkInterface.h"
/* Some files from the Atmel Software Framework */
/*_RB_ The SAM4E portable layer has three different header files called gmac.h! */
#include "instance/gmac.h"
#include <sysclk.h>
#include <ethernet_phy.h>
#ifndef BMSR_LINK_STATUS
#define BMSR_LINK_STATUS 0x0004 /*!< Link status */
#endif
#ifndef PHY_LS_HIGH_CHECK_TIME_MS
/* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
* receiving packets. */
#define PHY_LS_HIGH_CHECK_TIME_MS 15000
#endif
#ifndef PHY_LS_LOW_CHECK_TIME_MS
/* Check if the LinkSStatus in the PHY is still low every second. */
#define PHY_LS_LOW_CHECK_TIME_MS 1000
#endif
/* Interrupt events to process. Currently only the Rx event is processed
* although code for other events is included to allow for possible future
* expansion. */
#define EMAC_IF_RX_EVENT 1UL
#define EMAC_IF_TX_EVENT 2UL
#define EMAC_IF_ERR_EVENT 4UL
#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
#define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR
#define HZ_PER_MHZ ( 1000000UL )
#ifndef EMAC_MAX_BLOCK_TIME_MS
#define EMAC_MAX_BLOCK_TIME_MS 100ul
#endif
#if !defined( GMAC_USES_TX_CALLBACK ) || ( GMAC_USES_TX_CALLBACK != 1 )
#error Please define GMAC_USES_TX_CALLBACK as 1
#endif
/* Default the size of the stack used by the EMAC deferred handler task to 4x
* the size of the stack used by the idle task - but allow this to be overridden in
* FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
#ifndef configEMAC_TASK_STACK_SIZE
#define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
#endif
/*-----------------------------------------------------------*/
/*
* Wait a fixed time for the link status to indicate the network is up.
*/
static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
void vGMACGenerateChecksum( uint8_t * apBuffer );
#endif
/*
* Called from the ASF GMAC driver.
*/
static void prvRxCallback( uint32_t ulStatus );
static void prvTxCallback( uint32_t ulStatus,
uint8_t * puc_buffer );
/*
* A deferred interrupt handler task that processes GMAC interrupts.
*/
static void prvEMACHandlerTask( void * pvParameters );
/*
* Initialise the ASF GMAC driver.
*/
static BaseType_t prvGMACInit( void );
/*
* Try to obtain an Rx packet from the hardware.
*/
static uint32_t prvEMACRxPoll( void );
/*-----------------------------------------------------------*/
/* Bit map of outstanding ETH interrupt events for processing. Currently only
* the Rx interrupt is handled, although code is included for other events to
* enable future expansion. */
static volatile uint32_t ulISREvents;
/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
static uint32_t ulPHYLinkStatus = 0;
static volatile BaseType_t xGMACSwitchRequired;
/* ethernet_phy_addr: the address of the PHY in use.
* Atmel was a bit ambiguous about it so the address will be stored
* in this variable, see ethernet_phy.c */
extern int ethernet_phy_addr;
/* LLMNR multicast address. */
static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
/* The GMAC object as defined by the ASF drivers. */
static gmac_device_t gs_gmac_dev;
/* Holds the handle of the task used as a deferred interrupt processor. The
* handle is used so direct notifications can be sent to the task for all EMAC/DMA
* related interrupts. */
TaskHandle_t xEMACTaskHandle = NULL;
static QueueHandle_t xTxBufferQueue;
int tx_release_count[ 4 ];
/* xTXDescriptorSemaphore is a counting semaphore with
* a maximum count of GMAC_TX_BUFFERS, which is the number of
* DMA TX descriptors. */
static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
/*-----------------------------------------------------------*/
/*
* GMAC interrupt handler.
*/
void GMAC_Handler( void )
{
xGMACSwitchRequired = pdFALSE;
/* gmac_handler() may call prvRxCallback() which may change
* the value of xGMACSwitchRequired. */
gmac_handler( &gs_gmac_dev );
if( xGMACSwitchRequired != pdFALSE )
{
portEND_SWITCHING_ISR( xGMACSwitchRequired );
}
}
/*-----------------------------------------------------------*/
static void prvRxCallback( uint32_t ulStatus )
{
if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
{
/* let the prvEMACHandlerTask know that there was an RX event. */
ulISREvents |= EMAC_IF_RX_EVENT;
/* Only an RX interrupt can wakeup prvEMACHandlerTask. */
vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
}
}
/*-----------------------------------------------------------*/
static void prvTxCallback( uint32_t ulStatus,
uint8_t * puc_buffer )
{
if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
{
/* let the prvEMACHandlerTask know that there was an RX event. */
ulISREvents |= EMAC_IF_TX_EVENT;
vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
tx_release_count[ 2 ]++;
}
}
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceInitialise( void )
{
const TickType_t x5_Seconds = 5000UL;
if( xEMACTaskHandle == NULL )
{
prvGMACInit();
/* Wait at most 5 seconds for a Link Status in the PHY. */
xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
/* The handler task is created at the highest possible priority to
* ensure the interrupt handler can return directly to it. */
xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
configASSERT( xEMACTaskHandle != NULL );
}
if( xTxBufferQueue == NULL )
{
xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
configASSERT( xTxBufferQueue != NULL );
}
if( xTXDescriptorSemaphore == NULL )
{
xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
configASSERT( xTXDescriptorSemaphore != NULL );
}
/* When returning non-zero, the stack will become active and
* start DHCP (in configured) */
return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;
}
/*-----------------------------------------------------------*/
BaseType_t xGetPhyLinkStatus( void )
{
BaseType_t xResult;
/* This function returns true if the Link Status in the PHY is high. */
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
{
xResult = pdTRUE;
}
else
{
xResult = pdFALSE;
}
return xResult;
}
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor,
BaseType_t bReleaseAfterSend )
{
/* Do not wait too long for a free TX DMA buffer. */
const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
do
{
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
{
/* Do not attempt to send packets as long as the Link Status is low. */
break;
}
if( xTXDescriptorSemaphore == NULL )
{
/* Semaphore has not been created yet? */
break;
}
if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
{
/* Time-out waiting for a free TX descriptor. */
tx_release_count[ 3 ]++;
break;
}
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
/* Confirm that the pxDescriptor may be kept by the driver. */
configASSERT( bReleaseAfterSend != pdFALSE );
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
gmac_dev_write( &gs_gmac_dev, ( void * ) pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback );
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
/* Confirm that the pxDescriptor may be kept by the driver. */
bReleaseAfterSend = pdFALSE;
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
/* Not interested in a call-back after TX. */
iptraceNETWORK_INTERFACE_TRANSMIT();
} while( ipFALSE_BOOL );
if( bReleaseAfterSend != pdFALSE )
{
vReleaseNetworkBufferAndDescriptor( pxDescriptor );
}
return pdTRUE;
}
/*-----------------------------------------------------------*/
static BaseType_t prvGMACInit( void )
{
uint32_t ncfgr;
gmac_options_t gmac_option;
memset( &gmac_option, '\0', sizeof( gmac_option ) );
gmac_option.uc_copy_all_frame = 0;
gmac_option.uc_no_boardcast = 0;
memcpy( gmac_option.uc_mac_addr, ipLOCAL_MAC_ADDRESS, sizeof( gmac_option.uc_mac_addr ) );
gs_gmac_dev.p_hw = GMAC;
gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );
NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );
NVIC_EnableIRQ( GMAC_IRQn );
/* Contact the Ethernet PHY and store it's address in 'ethernet_phy_addr' */
ethernet_phy_init( GMAC, ETHERNET_CONF_PHY_ADDR, sysclk_get_cpu_hz() );
ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr );
ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 );
/* The GMAC driver will call a hook prvRxCallback(), which
* in turn will wake-up the task by calling vTaskNotifyGiveFromISR() */
gmac_dev_set_rx_callback( &gs_gmac_dev, prvRxCallback );
gmac_set_address( GMAC, 1, ( uint8_t * ) llmnr_mac_address );
ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD;
GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr;
return 1;
}
/*-----------------------------------------------------------*/
static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress )
{
uint32_t ulValue, ulReturn;
int rc;
gmac_enable_management( GMAC, 1 );
rc = gmac_phy_read( GMAC, ethernet_phy_addr, usAddress, &ulValue );
gmac_enable_management( GMAC, 0 );
if( rc == GMAC_OK )
{
ulReturn = ulValue;
}
else
{
ulReturn = 0UL;
}
return ulReturn;
}
/*-----------------------------------------------------------*/
static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
{
TickType_t xStartTime = xTaskGetTickCount();
TickType_t xEndTime;
BaseType_t xReturn;
const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );
for( ; ; )
{
xEndTime = xTaskGetTickCount();
if( ( xEndTime - xStartTime ) > xMaxTime )
{
/* Waited more than xMaxTime, return. */
xReturn = pdFALSE;
break;
}
/* Check the link status again. */
ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
{
/* Link is up - return. */
xReturn = pdTRUE;
break;
}
/* Link is down - wait in the Blocked state for a short while (to allow
* other tasks to execute) before checking again. */
vTaskDelay( xShortTime );
}
FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n",
xReturn,
ethernet_phy_addr,
sysclk_get_cpu_hz() / HZ_PER_MHZ ) );
return xReturn;
}
/*-----------------------------------------------------------*/
/*#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 ) */
void vGMACGenerateChecksum( uint8_t * apBuffer )
{
ProtocolPacket_t * xProtPacket = ( ProtocolPacket_t * ) apBuffer;
if( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
{
IPHeader_t * pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader );
/* Calculate the IP header checksum. */
pxIPHeader->usHeaderChecksum = 0x00;
pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
/* Calculate the TCP checksum for an outgoing packet. */
usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE );
}
}
/*#endif */
/*-----------------------------------------------------------*/
static uint32_t prvEMACRxPoll( void )
{
unsigned char * pucUseBuffer;
uint32_t ulReceiveCount, ulResult, ulReturnValue = 0;
static NetworkBufferDescriptor_t * pxNextNetworkBufferDescriptor = NULL;
const UBaseType_t xMinDescriptorsToLeave = 2UL;
const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL );
static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
for( ; ; )
{
/* If pxNextNetworkBufferDescriptor was not left pointing at a valid
* descriptor then allocate one now. */
if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) )
{
pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );
}
if( pxNextNetworkBufferDescriptor != NULL )
{
/* Point pucUseBuffer to the buffer pointed to by the descriptor. */
pucUseBuffer = ( unsigned char * ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
}
else
{
/* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
* messages will be flushed and ignored. */
pucUseBuffer = NULL;
}
/* Read the next packet from the hardware into pucUseBuffer. */
ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount );
if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )
{
/* No data from the hardware. */
break;
}
if( pxNextNetworkBufferDescriptor == NULL )
{
/* Data was read from the hardware, but no descriptor was available
* for it, so it will be dropped. */
iptraceETHERNET_RX_EVENT_LOST();
continue;
}
iptraceNETWORK_INTERFACE_RECEIVE();
pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;
xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;
/* Send the descriptor to the IP task for processing. */
if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )
{
/* The buffer could not be sent to the stack so must be released
* again. */
vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );
iptraceETHERNET_RX_EVENT_LOST();
FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
}
/* Now the buffer has either been passed to the IP-task,
* or it has been released in the code above. */
pxNextNetworkBufferDescriptor = NULL;
ulReturnValue++;
}
return ulReturnValue;
}
/*-----------------------------------------------------------*/
static void prvEMACHandlerTask( void * pvParameters )
{
TimeOut_t xPhyTime;
TickType_t xPhyRemTime;
UBaseType_t uxLastMinBufferCount = 0, uxCount;
UBaseType_t uxCurrentCount;
#if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
UBaseType_t uxLastMinQueueSpace;
#endif
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
NetworkBufferDescriptor_t * pxBuffer;
#endif
uint8_t * pucBuffer;
BaseType_t xResult = 0;
uint32_t xStatus;
const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
/* Remove compiler warnings about unused parameters. */
( void ) pvParameters;
configASSERT( xEMACTaskHandle != NULL );
vTaskSetTimeOutState( &xPhyTime );
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
for( ; ; )
{
uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
if( uxLastMinBufferCount != uxCurrentCount )
{
/* The logging produced below may be helpful
* while tuning +TCP: see how many buffers are in use. */
uxLastMinBufferCount = uxCurrentCount;
FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
}
#if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
{
uxCurrentCount = uxGetMinimumIPQueueSpace();
if( uxLastMinQueueSpace != uxCurrentCount )
{
/* The logging produced below may be helpful
* while tuning +TCP: see how many buffers are in use. */
uxLastMinQueueSpace = uxCurrentCount;
FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
}
}
#endif /* ipconfigCHECK_IP_QUEUE_SPACE */
if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
{
/* No events to process now, wait for the next. */
ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
}
if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
{
ulISREvents &= ~EMAC_IF_RX_EVENT;
/* Wait for the EMAC interrupt to indicate that another packet has been
* received. */
xResult = prvEMACRxPoll();
}
if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
{
/* Future extension: code to release TX buffers if zero-copy is used. */
ulISREvents &= ~EMAC_IF_TX_EVENT;
while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )
{
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
if( pxBuffer != NULL )
{
vReleaseNetworkBufferAndDescriptor( pxBuffer );
tx_release_count[ 0 ]++;
}
else
{
tx_release_count[ 1 ]++;
}
}
#else /* if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) */
{
tx_release_count[ 0 ]++;
}
#endif /* if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) */
uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
if( uxCount < GMAC_TX_BUFFERS )
{
/* Tell the counting semaphore that one more TX descriptor is available. */
xSemaphoreGive( xTXDescriptorSemaphore );
}
}
}
if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
{
/* Future extension: logging about errors that occurred. */
ulISREvents &= ~EMAC_IF_ERR_EVENT;
}
if( xResult > 0 )
{
/* A packet was received. No need to check for the PHY status now,
* but set a timer to check it later on. */
vTaskSetTimeOutState( &xPhyTime );
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
xResult = 0;
}
else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
{
/* Check the link status again. */
xStatus = ulReadMDIO( PHY_REG_01_BMSR );
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
{
ulPHYLinkStatus = xStatus;
FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
}
vTaskSetTimeOutState( &xPhyTime );
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
{
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
}
else
{
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
}
}
}
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,748 @@
/**
* \file
*
* Copyright (c) 2012 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* 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. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
*
* \asf_license_stop
*
*/
#ifndef _SAM4E_GMAC_COMPONENT_
#define _SAM4E_GMAC_COMPONENT_
/* ============================================================================= */
/** SOFTWARE API DEFINITION FOR Gigabit Ethernet MAC */
/* ============================================================================= */
/** \addtogroup SAM4E_GMAC Gigabit Ethernet MAC */
/*@{*/
#if !( defined( __ASSEMBLY__ ) || defined( __IAR_SYSTEMS_ASM__ ) )
/** \brief GmacSa hardware registers */
typedef struct
{
RwReg GMAC_SAB; /**< \brief (GmacSa Offset: 0x0) Specific Address 1 Bottom [31:0] Register */
RwReg GMAC_SAT; /**< \brief (GmacSa Offset: 0x4) Specific Address 1 Top [47:32] Register */
} GmacSa;
/** \brief Gmac hardware registers */
#define GMACSA_NUMBER 4
typedef struct
{
RwReg GMAC_NCR; /**< \brief (Gmac Offset: 0x000) Network Control Register */
RwReg GMAC_NCFGR; /**< \brief (Gmac Offset: 0x004) Network Configuration Register */
RoReg GMAC_NSR; /**< \brief (Gmac Offset: 0x008) Network Status Register */
RwReg GMAC_UR; /**< \brief (Gmac Offset: 0x00C) User Register */
RwReg GMAC_DCFGR; /**< \brief (Gmac Offset: 0x010) DMA Configuration Register */
RwReg GMAC_TSR; /**< \brief (Gmac Offset: 0x014) Transmit Status Register */
RwReg GMAC_RBQB; /**< \brief (Gmac Offset: 0x018) Receive Buffer Queue Base Address */
RwReg GMAC_TBQB; /**< \brief (Gmac Offset: 0x01C) Transmit Buffer Queue Base Address */
RwReg GMAC_RSR; /**< \brief (Gmac Offset: 0x020) Receive Status Register */
RoReg GMAC_ISR; /**< \brief (Gmac Offset: 0x024) Interrupt Status Register */
WoReg GMAC_IER; /**< \brief (Gmac Offset: 0x028) Interrupt Enable Register */
WoReg GMAC_IDR; /**< \brief (Gmac Offset: 0x02C) Interrupt Disable Register */
RoReg GMAC_IMR; /**< \brief (Gmac Offset: 0x030) Interrupt Mask Register */
RwReg GMAC_MAN; /**< \brief (Gmac Offset: 0x034) PHY Maintenance Register */
RoReg GMAC_RPQ; /**< \brief (Gmac Offset: 0x038) Received Pause Quantum Register */
RwReg GMAC_TPQ; /**< \brief (Gmac Offset: 0x03C) Transmit Pause Quantum Register */
RwReg GMAC_TPSF; /**< \brief (Gmac Offset: 0x040) TX Partial Store and Forward Register */
RwReg GMAC_RPSF; /**< \brief (Gmac Offset: 0x044) RX Partial Store and Forward Register */
RoReg Reserved1[ 14 ];
RwReg GMAC_HRB; /**< \brief (Gmac Offset: 0x080) Hash Register Bottom [31:0] */
RwReg GMAC_HRT; /**< \brief (Gmac Offset: 0x084) Hash Register Top [63:32] */
GmacSa GMAC_SA[ GMACSA_NUMBER ]; /**< \brief (Gmac Offset: 0x088) 1 .. 4 */
RwReg GMAC_TIDM[ 4 ]; /**< \brief (Gmac Offset: 0x0A8) Type ID Match 1 Register */
RwReg GMAC_WOL; /**< \brief (Gmac Offset: 0x0B8) Wake on LAN Register */
RwReg GMAC_IPGS; /**< \brief (Gmac Offset: 0x0BC) IPG Stretch Register */
RwReg GMAC_SVLAN; /**< \brief (Gmac Offset: 0x0C0) Stacked VLAN Register */
RwReg GMAC_TPFCP; /**< \brief (Gmac Offset: 0x0C4) Transmit PFC Pause Register */
RwReg GMAC_SAMB1; /**< \brief (Gmac Offset: 0x0C8) Specific Address 1 Mask Bottom [31:0] Register */
RwReg GMAC_SAMT1; /**< \brief (Gmac Offset: 0x0CC) Specific Address 1 Mask Top [47:32] Register */
RoReg Reserved2[ 12 ];
RoReg GMAC_OTLO; /**< \brief (Gmac Offset: 0x100) Octets Transmitted [31:0] Register */
RoReg GMAC_OTHI; /**< \brief (Gmac Offset: 0x104) Octets Transmitted [47:32] Register */
RoReg GMAC_FT; /**< \brief (Gmac Offset: 0x108) Frames Transmitted Register */
RoReg GMAC_BCFT; /**< \brief (Gmac Offset: 0x10C) Broadcast Frames Transmitted Register */
RoReg GMAC_MFT; /**< \brief (Gmac Offset: 0x110) Multicast Frames Transmitted Register */
RoReg GMAC_PFT; /**< \brief (Gmac Offset: 0x114) Pause Frames Transmitted Register */
RoReg GMAC_BFT64; /**< \brief (Gmac Offset: 0x118) 64 Byte Frames Transmitted Register */
RoReg GMAC_TBFT127; /**< \brief (Gmac Offset: 0x11C) 65 to 127 Byte Frames Transmitted Register */
RoReg GMAC_TBFT255; /**< \brief (Gmac Offset: 0x120) 128 to 255 Byte Frames Transmitted Register */
RoReg GMAC_TBFT511; /**< \brief (Gmac Offset: 0x124) 256 to 511 Byte Frames Transmitted Register */
RoReg GMAC_TBFT1023; /**< \brief (Gmac Offset: 0x128) 512 to 1023 Byte Frames Transmitted Register */
RoReg GMAC_TBFT1518; /**< \brief (Gmac Offset: 0x12C) 1024 to 1518 Byte Frames Transmitted Register */
RoReg GMAC_GTBFT1518; /**< \brief (Gmac Offset: 0x130) Greater Than 1518 Byte Frames Transmitted Register */
RoReg GMAC_TUR; /**< \brief (Gmac Offset: 0x134) Transmit Under Runs Register */
RoReg GMAC_SCF; /**< \brief (Gmac Offset: 0x138) Single Collision Frames Register */
RoReg GMAC_MCF; /**< \brief (Gmac Offset: 0x13C) Multiple Collision Frames Register */
RoReg GMAC_EC; /**< \brief (Gmac Offset: 0x140) Excessive Collisions Register */
RoReg GMAC_LC; /**< \brief (Gmac Offset: 0x144) Late Collisions Register */
RoReg GMAC_DTF; /**< \brief (Gmac Offset: 0x148) Deferred Transmission Frames Register */
RoReg GMAC_CSE; /**< \brief (Gmac Offset: 0x14C) Carrier Sense Errors Register */
RoReg GMAC_ORLO; /**< \brief (Gmac Offset: 0x150) Octets Received [31:0] Received */
RoReg GMAC_ORHI; /**< \brief (Gmac Offset: 0x154) Octets Received [47:32] Received */
RoReg GMAC_FR; /**< \brief (Gmac Offset: 0x158) Frames Received Register */
RoReg GMAC_BCFR; /**< \brief (Gmac Offset: 0x15C) Broadcast Frames Received Register */
RoReg GMAC_MFR; /**< \brief (Gmac Offset: 0x160) Multicast Frames Received Register */
RoReg GMAC_PFR; /**< \brief (Gmac Offset: 0x164) Pause Frames Received Register */
RoReg GMAC_BFR64; /**< \brief (Gmac Offset: 0x168) 64 Byte Frames Received Register */
RoReg GMAC_TBFR127; /**< \brief (Gmac Offset: 0x16C) 65 to 127 Byte Frames Received Register */
RoReg GMAC_TBFR255; /**< \brief (Gmac Offset: 0x170) 128 to 255 Byte Frames Received Register */
RoReg GMAC_TBFR511; /**< \brief (Gmac Offset: 0x174) 256 to 511Byte Frames Received Register */
RoReg GMAC_TBFR1023; /**< \brief (Gmac Offset: 0x178) 512 to 1023 Byte Frames Received Register */
RoReg GMAC_TBFR1518; /**< \brief (Gmac Offset: 0x17C) 1024 to 1518 Byte Frames Received Register */
RoReg GMAC_TMXBFR; /**< \brief (Gmac Offset: 0x180) 1519 to Maximum Byte Frames Received Register */
RoReg GMAC_UFR; /**< \brief (Gmac Offset: 0x184) Undersize Frames Received Register */
RoReg GMAC_OFR; /**< \brief (Gmac Offset: 0x188) Oversize Frames Received Register */
RoReg GMAC_JR; /**< \brief (Gmac Offset: 0x18C) Jabbers Received Register */
RoReg GMAC_FCSE; /**< \brief (Gmac Offset: 0x190) Frame Check Sequence Errors Register */
RoReg GMAC_LFFE; /**< \brief (Gmac Offset: 0x194) Length Field Frame Errors Register */
RoReg GMAC_RSE; /**< \brief (Gmac Offset: 0x198) Receive Symbol Errors Register */
RoReg GMAC_AE; /**< \brief (Gmac Offset: 0x19C) Alignment Errors Register */
RoReg GMAC_RRE; /**< \brief (Gmac Offset: 0x1A0) Receive Resource Errors Register */
RoReg GMAC_ROE; /**< \brief (Gmac Offset: 0x1A4) Receive Overrun Register */
RoReg GMAC_IHCE; /**< \brief (Gmac Offset: 0x1A8) IP Header Checksum Errors Register */
RoReg GMAC_TCE; /**< \brief (Gmac Offset: 0x1AC) TCP Checksum Errors Register */
RoReg GMAC_UCE; /**< \brief (Gmac Offset: 0x1B0) UDP Checksum Errors Register */
RoReg Reserved3[ 5 ];
RwReg GMAC_TSSS; /**< \brief (Gmac Offset: 0x1C8) 1588 Timer Sync Strobe Seconds Register */
RwReg GMAC_TSSN; /**< \brief (Gmac Offset: 0x1CC) 1588 Timer Sync Strobe Nanoseconds Register */
RwReg GMAC_TS; /**< \brief (Gmac Offset: 0x1D0) 1588 Timer Seconds Register */
RwReg GMAC_TN; /**< \brief (Gmac Offset: 0x1D4) 1588 Timer Nanoseconds Register */
WoReg GMAC_TA; /**< \brief (Gmac Offset: 0x1D8) 1588 Timer Adjust Register */
RwReg GMAC_TI; /**< \brief (Gmac Offset: 0x1DC) 1588 Timer Increment Register */
RoReg GMAC_EFTS; /**< \brief (Gmac Offset: 0x1E0) PTP Event Frame Transmitted Seconds */
RoReg GMAC_EFTN; /**< \brief (Gmac Offset: 0x1E4) PTP Event Frame Transmitted Nanoseconds */
RoReg GMAC_EFRS; /**< \brief (Gmac Offset: 0x1E8) PTP Event Frame Received Seconds */
RoReg GMAC_EFRN; /**< \brief (Gmac Offset: 0x1EC) PTP Event Frame Received Nanoseconds */
RoReg GMAC_PEFTS; /**< \brief (Gmac Offset: 0x1F0) PTP Peer Event Frame Transmitted Seconds */
RoReg GMAC_PEFTN; /**< \brief (Gmac Offset: 0x1F4) PTP Peer Event Frame Transmitted Nanoseconds */
RoReg GMAC_PEFRS; /**< \brief (Gmac Offset: 0x1F8) PTP Peer Event Frame Received Seconds */
RoReg GMAC_PEFRN; /**< \brief (Gmac Offset: 0x1FC) PTP Peer Event Frame Received Nanoseconds */
RoReg Reserved4[ 128 ];
RoReg GMAC_ISRPQ[ 7 ]; /**< \brief (Gmac Offset: 0x400) Interrupt Status Register Priority Queue */
RoReg Reserved5[ 9 ];
RwReg GMAC_TBQBAPQ[ 7 ]; /**< \brief (Gmac Offset: 0x440) Transmit Buffer Queue Base Address Priority Queue */
RoReg Reserved6[ 9 ];
RwReg GMAC_RBQBAPQ[ 7 ]; /**< \brief (Gmac Offset: 0x480) Receive Buffer Queue Base Address Priority Queue */
RoReg Reserved7[ 1 ];
RwReg GMAC_RBSRPQ[ 7 ]; /**< \brief (Gmac Offset: 0x4A0) Receive Buffer Size Register Priority Queue */
RoReg Reserved8[ 17 ];
RwReg GMAC_ST1RPQ[ 16 ]; /**< \brief (Gmac Offset: 0x500) Screening Type1 Register Priority Queue */
RwReg GMAC_ST2RPQ[ 16 ]; /**< \brief (Gmac Offset: 0x540) Screening Type2 Register Priority Queue */
RoReg Reserved9[ 32 ];
WoReg GMAC_IERPQ[ 7 ]; /**< \brief (Gmac Offset: 0x600) Interrupt Enable Register Priority Queue */
RoReg Reserved10[ 1 ];
WoReg GMAC_IDRPQ[ 7 ]; /**< \brief (Gmac Offset: 0x620) Interrupt Disable Register Priority Queue */
RoReg Reserved11[ 1 ];
RwReg GMAC_IMRPQ[ 7 ]; /**< \brief (Gmac Offset: 0x640) Interrupt Mask Register Priority Queue */
} Gmac;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- GMAC_NCR : (GMAC Offset: 0x000) Network Control Register -------- */
#define GMAC_NCR_LB ( 0x1u << 0 ) /**< \brief (GMAC_NCR) Loop Back */
#define GMAC_NCR_LBL ( 0x1u << 1 ) /**< \brief (GMAC_NCR) Loop Back Local */
#define GMAC_NCR_RXEN ( 0x1u << 2 ) /**< \brief (GMAC_NCR) Receive Enable */
#define GMAC_NCR_TXEN ( 0x1u << 3 ) /**< \brief (GMAC_NCR) Transmit Enable */
#define GMAC_NCR_MPE ( 0x1u << 4 ) /**< \brief (GMAC_NCR) Management Port Enable */
#define GMAC_NCR_CLRSTAT ( 0x1u << 5 ) /**< \brief (GMAC_NCR) Clear Statistics Registers */
#define GMAC_NCR_INCSTAT ( 0x1u << 6 ) /**< \brief (GMAC_NCR) Increment Statistics Registers */
#define GMAC_NCR_WESTAT ( 0x1u << 7 ) /**< \brief (GMAC_NCR) Write Enable for Statistics Registers */
#define GMAC_NCR_BP ( 0x1u << 8 ) /**< \brief (GMAC_NCR) Back pressure */
#define GMAC_NCR_TSTART ( 0x1u << 9 ) /**< \brief (GMAC_NCR) Start Transmission */
#define GMAC_NCR_THALT ( 0x1u << 10 ) /**< \brief (GMAC_NCR) Transmit Halt */
#define GMAC_NCR_TXPF ( 0x1u << 11 ) /**< \brief (GMAC_NCR) Transmit Pause Frame */
#define GMAC_NCR_TXZQPF ( 0x1u << 12 ) /**< \brief (GMAC_NCR) Transmit Zero Quantum Pause Frame */
#define GMAC_NCR_RDS ( 0x1u << 14 ) /**< \brief (GMAC_NCR) Read Snapshot */
#define GMAC_NCR_SRTSM ( 0x1u << 15 ) /**< \brief (GMAC_NCR) Store Receive Time Stamp to Memory */
#define GMAC_NCR_ENPBPR ( 0x1u << 16 ) /**< \brief (GMAC_NCR) Enable PFC Priority-based Pause Reception */
#define GMAC_NCR_TXPBPF ( 0x1u << 17 ) /**< \brief (GMAC_NCR) Transmit PFC Priority-based Pause Frame */
#define GMAC_NCR_FNP ( 0x1u << 18 ) /**< \brief (GMAC_NCR) Flush Next Packet */
/* -------- GMAC_NCFGR : (GMAC Offset: 0x004) Network Configuration Register -------- */
#define GMAC_NCFGR_SPD ( 0x1u << 0 ) /**< \brief (GMAC_NCFGR) Speed */
#define GMAC_NCFGR_FD ( 0x1u << 1 ) /**< \brief (GMAC_NCFGR) Full Duplex */
#define GMAC_NCFGR_DNVLAN ( 0x1u << 2 ) /**< \brief (GMAC_NCFGR) Discard Non-VLAN FRAMES */
#define GMAC_NCFGR_JFRAME ( 0x1u << 3 ) /**< \brief (GMAC_NCFGR) Jumbo Frame Size */
#define GMAC_NCFGR_CAF ( 0x1u << 4 ) /**< \brief (GMAC_NCFGR) Copy All Frames */
#define GMAC_NCFGR_NBC ( 0x1u << 5 ) /**< \brief (GMAC_NCFGR) No Broadcast */
#define GMAC_NCFGR_MTIHEN ( 0x1u << 6 ) /**< \brief (GMAC_NCFGR) Multicast Hash Enable */
#define GMAC_NCFGR_UNIHEN ( 0x1u << 7 ) /**< \brief (GMAC_NCFGR) Unicast Hash Enable */
#define GMAC_NCFGR_MAXFS ( 0x1u << 8 ) /**< \brief (GMAC_NCFGR) 1536 Maximum Frame Size */
#define GMAC_NCFGR_GBE ( 0x1u << 10 ) /**< \brief (GMAC_NCFGR) Gigabit Mode Enable */
#define GMAC_NCFGR_PIS ( 0x1u << 11 ) /**< \brief (GMAC_NCFGR) Physical Interface Select */
#define GMAC_NCFGR_RTY ( 0x1u << 12 ) /**< \brief (GMAC_NCFGR) Retry Test */
#define GMAC_NCFGR_PEN ( 0x1u << 13 ) /**< \brief (GMAC_NCFGR) Pause Enable */
#define GMAC_NCFGR_RXBUFO_Pos 14
#define GMAC_NCFGR_RXBUFO_Msk ( 0x3u << GMAC_NCFGR_RXBUFO_Pos ) /**< \brief (GMAC_NCFGR) Receive Buffer Offset */
#define GMAC_NCFGR_RXBUFO( value ) ( ( GMAC_NCFGR_RXBUFO_Msk & ( ( value ) << GMAC_NCFGR_RXBUFO_Pos ) ) )
#define GMAC_NCFGR_LFERD ( 0x1u << 16 ) /**< \brief (GMAC_NCFGR) Length Field Error Frame Discard */
#define GMAC_NCFGR_RFCS ( 0x1u << 17 ) /**< \brief (GMAC_NCFGR) Remove FCS */
#define GMAC_NCFGR_CLK_Pos 18
#define GMAC_NCFGR_CLK_Msk ( 0x7u << GMAC_NCFGR_CLK_Pos ) /**< \brief (GMAC_NCFGR) MDC CLock Division */
#define GMAC_NCFGR_CLK_MCK_8 ( 0x0u << 18 ) /**< \brief (GMAC_NCFGR) MCK divided by 8 (MCK up to 20 MHz) */
#define GMAC_NCFGR_CLK_MCK_16 ( 0x1u << 18 ) /**< \brief (GMAC_NCFGR) MCK divided by 16 (MCK up to 40 MHz) */
#define GMAC_NCFGR_CLK_MCK_32 ( 0x2u << 18 ) /**< \brief (GMAC_NCFGR) MCK divided by 32 (MCK up to 80 MHz) */
#define GMAC_NCFGR_CLK_MCK_48 ( 0x3u << 18 ) /**< \brief (GMAC_NCFGR) MCK divided by 48 (MCK up to 120MHz) */
#define GMAC_NCFGR_CLK_MCK_64 ( 0x4u << 18 ) /**< \brief (GMAC_NCFGR) MCK divided by 64 (MCK up to 160 MHz) */
#define GMAC_NCFGR_CLK_MCK_96 ( 0x5u << 18 ) /**< \brief (GMAC_NCFGR) MCK divided by 96 (MCK up to 240 MHz) */
#define GMAC_NCFGR_CLK_MCK_128 ( 0x6u << 18 ) /**< \brief (GMAC_NCFGR) MCK divided by 128 (MCK up to 320 MHz) */
#define GMAC_NCFGR_CLK_MCK_224 ( 0x7u << 18 ) /**< \brief (GMAC_NCFGR) MCK divided by 224 (MCK up to 540 MHz) */
#define GMAC_NCFGR_DBW_Pos 21
#define GMAC_NCFGR_DBW_Msk ( 0x3u << GMAC_NCFGR_DBW_Pos ) /**< \brief (GMAC_NCFGR) Data Bus Width */
#define GMAC_NCFGR_DBW_DBW32 ( 0x0u << 21 ) /**< \brief (GMAC_NCFGR) 32-bit data bus width */
#define GMAC_NCFGR_DBW_DBW64 ( 0x1u << 21 ) /**< \brief (GMAC_NCFGR) 64-bit data bus width */
#define GMAC_NCFGR_DCPF ( 0x1u << 23 ) /**< \brief (GMAC_NCFGR) Disable Copy of Pause Frames */
#define GMAC_NCFGR_RXCOEN ( 0x1u << 24 ) /**< \brief (GMAC_NCFGR) Receive Checksum Offload Enable */
#define GMAC_NCFGR_EFRHD ( 0x1u << 25 ) /**< \brief (GMAC_NCFGR) Enable Frames Received in Half Duplex */
#define GMAC_NCFGR_IRXFCS ( 0x1u << 26 ) /**< \brief (GMAC_NCFGR) Ignore RX FCS */
#define GMAC_NCFGR_IPGSEN ( 0x1u << 28 ) /**< \brief (GMAC_NCFGR) IP Stretch Enable */
#define GMAC_NCFGR_RXBP ( 0x1u << 29 ) /**< \brief (GMAC_NCFGR) Receive Bad Preamble */
#define GMAC_NCFGR_IRXER ( 0x1u << 30 ) /**< \brief (GMAC_NCFGR) Ignore IPG rx_er */
/* -------- GMAC_NSR : (GMAC Offset: 0x008) Network Status Register -------- */
#define GMAC_NSR_MDIO ( 0x1u << 1 ) /**< \brief (GMAC_NSR) MDIO Input Status */
#define GMAC_NSR_IDLE ( 0x1u << 2 ) /**< \brief (GMAC_NSR) PHY Management Logic Idle */
/* -------- GMAC_UR : (GMAC Offset: 0x00C) User Register -------- */
#define GMAC_UR_RGMII ( 0x1u << 0 ) /**< \brief (GMAC_UR) RGMII Mode */
#define GMAC_UR_HDFC ( 0x1u << 6 ) /**< \brief (GMAC_UR) Half Duplex Flow Control */
#define GMAC_UR_BPDG ( 0x1u << 7 ) /**< \brief (GMAC_UR) BPDG Bypass Deglitchers */
/* -------- GMAC_DCFGR : (GMAC Offset: 0x010) DMA Configuration Register -------- */
#define GMAC_DCFGR_FBLDO_Pos 0
#define GMAC_DCFGR_FBLDO_Msk ( 0x1fu << GMAC_DCFGR_FBLDO_Pos ) /**< \brief (GMAC_DCFGR) Fixed Burst Length for DMA Data Operations: */
#define GMAC_DCFGR_FBLDO_SINGLE ( 0x1u << 0 ) /**< \brief (GMAC_DCFGR) 00001: Always use SINGLE AHB bursts */
#define GMAC_DCFGR_FBLDO_INCR4 ( 0x4u << 0 ) /**< \brief (GMAC_DCFGR) 001xx: Attempt to use INCR4 AHB bursts (Default) */
#define GMAC_DCFGR_FBLDO_INCR8 ( 0x8u << 0 ) /**< \brief (GMAC_DCFGR) 01xxx: Attempt to use INCR8 AHB bursts */
#define GMAC_DCFGR_FBLDO_INCR16 ( 0x10u << 0 ) /**< \brief (GMAC_DCFGR) 1xxxx: Attempt to use INCR16 AHB bursts */
#define GMAC_DCFGR_ESMA ( 0x1u << 6 ) /**< \brief (GMAC_DCFGR) Endian Swap Mode Enable for Management Descriptor Accesses */
#define GMAC_DCFGR_ESPA ( 0x1u << 7 ) /**< \brief (GMAC_DCFGR) Endian Swap Mode Enable for Packet Data Accesses */
#define GMAC_DCFGR_RXBMS_Pos 8
#define GMAC_DCFGR_RXBMS_Msk ( 0x3u << GMAC_DCFGR_RXBMS_Pos ) /**< \brief (GMAC_DCFGR) Receiver Packet Buffer Memory Size Select */
#define GMAC_DCFGR_RXBMS_EIGHTH ( 0x0u << 8 ) /**< \brief (GMAC_DCFGR) 1 Kbyte Memory Size */
#define GMAC_DCFGR_RXBMS_QUARTER ( 0x1u << 8 ) /**< \brief (GMAC_DCFGR) 2 Kbytes Memory Size */
#define GMAC_DCFGR_RXBMS_HALF ( 0x2u << 8 ) /**< \brief (GMAC_DCFGR) 4 Kbytes Memory Size */
#define GMAC_DCFGR_RXBMS_FULL ( 0x3u << 8 ) /**< \brief (GMAC_DCFGR) 8 Kbytes Memory Size */
#define GMAC_DCFGR_TXPBMS ( 0x1u << 10 ) /**< \brief (GMAC_DCFGR) Transmitter Packet Buffer Memory Size Select */
#define GMAC_DCFGR_TXCOEN ( 0x1u << 11 ) /**< \brief (GMAC_DCFGR) Transmitter Checksum Generation Offload Enable */
#define GMAC_DCFGR_DRBS_Pos 16
#define GMAC_DCFGR_DRBS_Msk ( 0xffu << GMAC_DCFGR_DRBS_Pos ) /**< \brief (GMAC_DCFGR) DMA Receive Buffer Size */
#define GMAC_DCFGR_DRBS( value ) ( ( GMAC_DCFGR_DRBS_Msk & ( ( value ) << GMAC_DCFGR_DRBS_Pos ) ) )
#define GMAC_DCFGR_DDRP ( 0x1u << 24 ) /**< \brief (GMAC_DCFGR) DMA Discard Receive Packets */
/* -------- GMAC_TSR : (GMAC Offset: 0x014) Transmit Status Register -------- */
#define GMAC_TSR_UBR ( 0x1u << 0 ) /**< \brief (GMAC_TSR) Used Bit Read */
#define GMAC_TSR_COL ( 0x1u << 1 ) /**< \brief (GMAC_TSR) Collision Occurred */
#define GMAC_TSR_RLE ( 0x1u << 2 ) /**< \brief (GMAC_TSR) Retry Limit Exceeded */
#define GMAC_TSR_TXGO ( 0x1u << 3 ) /**< \brief (GMAC_TSR) Transmit Go */
#define GMAC_TSR_TFC ( 0x1u << 4 ) /**< \brief (GMAC_TSR) Transmit Frame Corruption due to AHB error */
#define GMAC_TSR_TXCOMP ( 0x1u << 5 ) /**< \brief (GMAC_TSR) Transmit Complete */
#define GMAC_TSR_UND ( 0x1u << 6 ) /**< \brief (GMAC_TSR) Transmit Under Run */
#define GMAC_TSR_LCO ( 0x1u << 7 ) /**< \brief (GMAC_TSR) Late Collision Occurred */
#define GMAC_TSR_HRESP ( 0x1u << 8 ) /**< \brief (GMAC_TSR) HRESP Not OK */
/* -------- GMAC_RBQB : (GMAC Offset: 0x018) Receive Buffer Queue Base Address -------- */
#define GMAC_RBQB_ADDR_Pos 2
#define GMAC_RBQB_ADDR_Msk ( 0x3fffffffu << GMAC_RBQB_ADDR_Pos ) /**< \brief (GMAC_RBQB) Receive buffer queue base address */
#define GMAC_RBQB_ADDR( value ) ( ( GMAC_RBQB_ADDR_Msk & ( ( value ) << GMAC_RBQB_ADDR_Pos ) ) )
/* -------- GMAC_TBQB : (GMAC Offset: 0x01C) Transmit Buffer Queue Base Address -------- */
#define GMAC_TBQB_ADDR_Pos 2
#define GMAC_TBQB_ADDR_Msk ( 0x3fffffffu << GMAC_TBQB_ADDR_Pos ) /**< \brief (GMAC_TBQB) Transmit Buffer Queue Base Address */
#define GMAC_TBQB_ADDR( value ) ( ( GMAC_TBQB_ADDR_Msk & ( ( value ) << GMAC_TBQB_ADDR_Pos ) ) )
/* -------- GMAC_RSR : (GMAC Offset: 0x020) Receive Status Register -------- */
#define GMAC_RSR_BNA ( 0x1u << 0 ) /**< \brief (GMAC_RSR) Buffer Not Available */
#define GMAC_RSR_REC ( 0x1u << 1 ) /**< \brief (GMAC_RSR) Frame Received */
#define GMAC_RSR_RXOVR ( 0x1u << 2 ) /**< \brief (GMAC_RSR) Receive Overrun */
#define GMAC_RSR_HNO ( 0x1u << 3 ) /**< \brief (GMAC_RSR) HRESP Not OK */
/* -------- GMAC_ISR : (GMAC Offset: 0x024) Interrupt Status Register -------- */
#define GMAC_ISR_MFS ( 0x1u << 0 ) /**< \brief (GMAC_ISR) Management Frame Sent */
#define GMAC_ISR_RCOMP ( 0x1u << 1 ) /**< \brief (GMAC_ISR) Receive Complete */
#define GMAC_ISR_RXUBR ( 0x1u << 2 ) /**< \brief (GMAC_ISR) RX Used Bit Read */
#define GMAC_ISR_TXUBR ( 0x1u << 3 ) /**< \brief (GMAC_ISR) TX Used Bit Read */
#define GMAC_ISR_TUR ( 0x1u << 4 ) /**< \brief (GMAC_ISR) Transmit Under Run */
#define GMAC_ISR_RLEX ( 0x1u << 5 ) /**< \brief (GMAC_ISR) Retry Limit Exceeded or Late Collision */
#define GMAC_ISR_TFC ( 0x1u << 6 ) /**< \brief (GMAC_ISR) Transmit Frame Corruption due to AHB error */
#define GMAC_ISR_TCOMP ( 0x1u << 7 ) /**< \brief (GMAC_ISR) Transmit Complete */
#define GMAC_ISR_ROVR ( 0x1u << 10 ) /**< \brief (GMAC_ISR) Receive Overrun */
#define GMAC_ISR_HRESP ( 0x1u << 11 ) /**< \brief (GMAC_ISR) HRESP Not OK */
#define GMAC_ISR_PFNZ ( 0x1u << 12 ) /**< \brief (GMAC_ISR) Pause Frame with Non-zero Pause Quantum Received */
#define GMAC_ISR_PTZ ( 0x1u << 13 ) /**< \brief (GMAC_ISR) Pause Time Zero */
#define GMAC_ISR_PFTR ( 0x1u << 14 ) /**< \brief (GMAC_ISR) Pause Frame Transmitted */
#define GMAC_ISR_EXINT ( 0x1u << 15 ) /**< \brief (GMAC_ISR) External Interrupt */
#define GMAC_ISR_DRQFR ( 0x1u << 18 ) /**< \brief (GMAC_ISR) PTP Delay Request Frame Received */
#define GMAC_ISR_SFR ( 0x1u << 19 ) /**< \brief (GMAC_ISR) PTP Sync Frame Received */
#define GMAC_ISR_DRQFT ( 0x1u << 20 ) /**< \brief (GMAC_ISR) PTP Delay Request Frame Transmitted */
#define GMAC_ISR_SFT ( 0x1u << 21 ) /**< \brief (GMAC_ISR) PTP Sync Frame Transmitted */
#define GMAC_ISR_PDRQFR ( 0x1u << 22 ) /**< \brief (GMAC_ISR) PDelay Request Frame Received */
#define GMAC_ISR_PDRSFR ( 0x1u << 23 ) /**< \brief (GMAC_ISR) PDelay Response Frame Received */
#define GMAC_ISR_PDRQFT ( 0x1u << 24 ) /**< \brief (GMAC_ISR) PDelay Request Frame Transmitted */
#define GMAC_ISR_PDRSFT ( 0x1u << 25 ) /**< \brief (GMAC_ISR) PDelay Response Frame Transmitted */
#define GMAC_ISR_SRI ( 0x1u << 26 ) /**< \brief (GMAC_ISR) TSU Seconds Register Increment */
#define GMAC_ISR_WOL ( 0x1u << 28 ) /**< \brief (GMAC_ISR) Wake On LAN */
/* -------- GMAC_IER : (GMAC Offset: 0x028) Interrupt Enable Register -------- */
#define GMAC_IER_MFS ( 0x1u << 0 ) /**< \brief (GMAC_IER) Management Frame Sent */
#define GMAC_IER_RCOMP ( 0x1u << 1 ) /**< \brief (GMAC_IER) Receive Complete */
#define GMAC_IER_RXUBR ( 0x1u << 2 ) /**< \brief (GMAC_IER) RX Used Bit Read */
#define GMAC_IER_TXUBR ( 0x1u << 3 ) /**< \brief (GMAC_IER) TX Used Bit Read */
#define GMAC_IER_TUR ( 0x1u << 4 ) /**< \brief (GMAC_IER) Transmit Under Run */
#define GMAC_IER_RLEX ( 0x1u << 5 ) /**< \brief (GMAC_IER) Retry Limit Exceeded or Late Collision */
#define GMAC_IER_TFC ( 0x1u << 6 ) /**< \brief (GMAC_IER) Transmit Frame Corruption due to AHB error */
#define GMAC_IER_TCOMP ( 0x1u << 7 ) /**< \brief (GMAC_IER) Transmit Complete */
#define GMAC_IER_ROVR ( 0x1u << 10 ) /**< \brief (GMAC_IER) Receive Overrun */
#define GMAC_IER_HRESP ( 0x1u << 11 ) /**< \brief (GMAC_IER) HRESP Not OK */
#define GMAC_IER_PFNZ ( 0x1u << 12 ) /**< \brief (GMAC_IER) Pause Frame with Non-zero Pause Quantum Received */
#define GMAC_IER_PTZ ( 0x1u << 13 ) /**< \brief (GMAC_IER) Pause Time Zero */
#define GMAC_IER_PFTR ( 0x1u << 14 ) /**< \brief (GMAC_IER) Pause Frame Transmitted */
#define GMAC_IER_EXINT ( 0x1u << 15 ) /**< \brief (GMAC_IER) External Interrupt */
#define GMAC_IER_DRQFR ( 0x1u << 18 ) /**< \brief (GMAC_IER) PTP Delay Request Frame Received */
#define GMAC_IER_SFR ( 0x1u << 19 ) /**< \brief (GMAC_IER) PTP Sync Frame Received */
#define GMAC_IER_DRQFT ( 0x1u << 20 ) /**< \brief (GMAC_IER) PTP Delay Request Frame Transmitted */
#define GMAC_IER_SFT ( 0x1u << 21 ) /**< \brief (GMAC_IER) PTP Sync Frame Transmitted */
#define GMAC_IER_PDRQFR ( 0x1u << 22 ) /**< \brief (GMAC_IER) PDelay Request Frame Received */
#define GMAC_IER_PDRSFR ( 0x1u << 23 ) /**< \brief (GMAC_IER) PDelay Response Frame Received */
#define GMAC_IER_PDRQFT ( 0x1u << 24 ) /**< \brief (GMAC_IER) PDelay Request Frame Transmitted */
#define GMAC_IER_PDRSFT ( 0x1u << 25 ) /**< \brief (GMAC_IER) PDelay Response Frame Transmitted */
#define GMAC_IER_SRI ( 0x1u << 26 ) /**< \brief (GMAC_IER) TSU Seconds Register Increment */
#define GMAC_IER_WOL ( 0x1u << 28 ) /**< \brief (GMAC_IER) Wake On LAN */
/* -------- GMAC_IDR : (GMAC Offset: 0x02C) Interrupt Disable Register -------- */
#define GMAC_IDR_MFS ( 0x1u << 0 ) /**< \brief (GMAC_IDR) Management Frame Sent */
#define GMAC_IDR_RCOMP ( 0x1u << 1 ) /**< \brief (GMAC_IDR) Receive Complete */
#define GMAC_IDR_RXUBR ( 0x1u << 2 ) /**< \brief (GMAC_IDR) RX Used Bit Read */
#define GMAC_IDR_TXUBR ( 0x1u << 3 ) /**< \brief (GMAC_IDR) TX Used Bit Read */
#define GMAC_IDR_TUR ( 0x1u << 4 ) /**< \brief (GMAC_IDR) Transmit Under Run */
#define GMAC_IDR_RLEX ( 0x1u << 5 ) /**< \brief (GMAC_IDR) Retry Limit Exceeded or Late Collision */
#define GMAC_IDR_TFC ( 0x1u << 6 ) /**< \brief (GMAC_IDR) Transmit Frame Corruption due to AHB error */
#define GMAC_IDR_TCOMP ( 0x1u << 7 ) /**< \brief (GMAC_IDR) Transmit Complete */
#define GMAC_IDR_ROVR ( 0x1u << 10 ) /**< \brief (GMAC_IDR) Receive Overrun */
#define GMAC_IDR_HRESP ( 0x1u << 11 ) /**< \brief (GMAC_IDR) HRESP Not OK */
#define GMAC_IDR_PFNZ ( 0x1u << 12 ) /**< \brief (GMAC_IDR) Pause Frame with Non-zero Pause Quantum Received */
#define GMAC_IDR_PTZ ( 0x1u << 13 ) /**< \brief (GMAC_IDR) Pause Time Zero */
#define GMAC_IDR_PFTR ( 0x1u << 14 ) /**< \brief (GMAC_IDR) Pause Frame Transmitted */
#define GMAC_IDR_EXINT ( 0x1u << 15 ) /**< \brief (GMAC_IDR) External Interrupt */
#define GMAC_IDR_DRQFR ( 0x1u << 18 ) /**< \brief (GMAC_IDR) PTP Delay Request Frame Received */
#define GMAC_IDR_SFR ( 0x1u << 19 ) /**< \brief (GMAC_IDR) PTP Sync Frame Received */
#define GMAC_IDR_DRQFT ( 0x1u << 20 ) /**< \brief (GMAC_IDR) PTP Delay Request Frame Transmitted */
#define GMAC_IDR_SFT ( 0x1u << 21 ) /**< \brief (GMAC_IDR) PTP Sync Frame Transmitted */
#define GMAC_IDR_PDRQFR ( 0x1u << 22 ) /**< \brief (GMAC_IDR) PDelay Request Frame Received */
#define GMAC_IDR_PDRSFR ( 0x1u << 23 ) /**< \brief (GMAC_IDR) PDelay Response Frame Received */
#define GMAC_IDR_PDRQFT ( 0x1u << 24 ) /**< \brief (GMAC_IDR) PDelay Request Frame Transmitted */
#define GMAC_IDR_PDRSFT ( 0x1u << 25 ) /**< \brief (GMAC_IDR) PDelay Response Frame Transmitted */
#define GMAC_IDR_SRI ( 0x1u << 26 ) /**< \brief (GMAC_IDR) TSU Seconds Register Increment */
#define GMAC_IDR_WOL ( 0x1u << 28 ) /**< \brief (GMAC_IDR) Wake On LAN */
/* -------- GMAC_IMR : (GMAC Offset: 0x030) Interrupt Mask Register -------- */
#define GMAC_IMR_MFS ( 0x1u << 0 ) /**< \brief (GMAC_IMR) Management Frame Sent */
#define GMAC_IMR_RCOMP ( 0x1u << 1 ) /**< \brief (GMAC_IMR) Receive Complete */
#define GMAC_IMR_RXUBR ( 0x1u << 2 ) /**< \brief (GMAC_IMR) RX Used Bit Read */
#define GMAC_IMR_TXUBR ( 0x1u << 3 ) /**< \brief (GMAC_IMR) TX Used Bit Read */
#define GMAC_IMR_TUR ( 0x1u << 4 ) /**< \brief (GMAC_IMR) Transmit Under Run */
#define GMAC_IMR_RLEX ( 0x1u << 5 ) /**< \brief (GMAC_IMR) Retry Limit Exceeded or Late Collision */
#define GMAC_IMR_TFC ( 0x1u << 6 ) /**< \brief (GMAC_IMR) Transmit Frame Corruption due to AHB error */
#define GMAC_IMR_TCOMP ( 0x1u << 7 ) /**< \brief (GMAC_IMR) Transmit Complete */
#define GMAC_IMR_ROVR ( 0x1u << 10 ) /**< \brief (GMAC_IMR) Receive Overrun */
#define GMAC_IMR_HRESP ( 0x1u << 11 ) /**< \brief (GMAC_IMR) HRESP Not OK */
#define GMAC_IMR_PFNZ ( 0x1u << 12 ) /**< \brief (GMAC_IMR) Pause Frame with Non-zero Pause Quantum Received */
#define GMAC_IMR_PTZ ( 0x1u << 13 ) /**< \brief (GMAC_IMR) Pause Time Zero */
#define GMAC_IMR_PFTR ( 0x1u << 14 ) /**< \brief (GMAC_IMR) Pause Frame Transmitted */
#define GMAC_IMR_EXINT ( 0x1u << 15 ) /**< \brief (GMAC_IMR) External Interrupt */
#define GMAC_IMR_DRQFR ( 0x1u << 18 ) /**< \brief (GMAC_IMR) PTP Delay Request Frame Received */
#define GMAC_IMR_SFR ( 0x1u << 19 ) /**< \brief (GMAC_IMR) PTP Sync Frame Received */
#define GMAC_IMR_DRQFT ( 0x1u << 20 ) /**< \brief (GMAC_IMR) PTP Delay Request Frame Transmitted */
#define GMAC_IMR_SFT ( 0x1u << 21 ) /**< \brief (GMAC_IMR) PTP Sync Frame Transmitted */
#define GMAC_IMR_PDRQFR ( 0x1u << 22 ) /**< \brief (GMAC_IMR) PDelay Request Frame Received */
#define GMAC_IMR_PDRSFR ( 0x1u << 23 ) /**< \brief (GMAC_IMR) PDelay Response Frame Received */
#define GMAC_IMR_PDRQFT ( 0x1u << 24 ) /**< \brief (GMAC_IMR) PDelay Request Frame Transmitted */
#define GMAC_IMR_PDRSFT ( 0x1u << 25 ) /**< \brief (GMAC_IMR) PDelay Response Frame Transmitted */
/* -------- GMAC_MAN : (GMAC Offset: 0x034) PHY Maintenance Register -------- */
#define GMAC_MAN_DATA_Pos 0
#define GMAC_MAN_DATA_Msk ( 0xffffu << GMAC_MAN_DATA_Pos ) /**< \brief (GMAC_MAN) PHY Data */
#define GMAC_MAN_DATA( value ) ( ( GMAC_MAN_DATA_Msk & ( ( value ) << GMAC_MAN_DATA_Pos ) ) )
#define GMAC_MAN_WTN_Pos 16
#define GMAC_MAN_WTN_Msk ( 0x3u << GMAC_MAN_WTN_Pos ) /**< \brief (GMAC_MAN) Write Ten */
#define GMAC_MAN_WTN( value ) ( ( GMAC_MAN_WTN_Msk & ( ( value ) << GMAC_MAN_WTN_Pos ) ) )
#define GMAC_MAN_REGA_Pos 18
#define GMAC_MAN_REGA_Msk ( 0x1fu << GMAC_MAN_REGA_Pos ) /**< \brief (GMAC_MAN) Register Address */
#define GMAC_MAN_REGA( value ) ( ( GMAC_MAN_REGA_Msk & ( ( value ) << GMAC_MAN_REGA_Pos ) ) )
#define GMAC_MAN_PHYA_Pos 23
#define GMAC_MAN_PHYA_Msk ( 0x1fu << GMAC_MAN_PHYA_Pos ) /**< \brief (GMAC_MAN) PHY Address */
#define GMAC_MAN_PHYA( value ) ( ( GMAC_MAN_PHYA_Msk & ( ( value ) << GMAC_MAN_PHYA_Pos ) ) )
#define GMAC_MAN_OP_Pos 28
#define GMAC_MAN_OP_Msk ( 0x3u << GMAC_MAN_OP_Pos ) /**< \brief (GMAC_MAN) Operation */
#define GMAC_MAN_OP( value ) ( ( GMAC_MAN_OP_Msk & ( ( value ) << GMAC_MAN_OP_Pos ) ) )
#define GMAC_MAN_CLTTO ( 0x1u << 30 ) /**< \brief (GMAC_MAN) Clause 22 Operation */
#define GMAC_MAN_WZO ( 0x1u << 31 ) /**< \brief (GMAC_MAN) Write ZERO */
/* -------- GMAC_RPQ : (GMAC Offset: 0x038) Received Pause Quantum Register -------- */
#define GMAC_RPQ_RPQ_Pos 0
#define GMAC_RPQ_RPQ_Msk ( 0xffffu << GMAC_RPQ_RPQ_Pos ) /**< \brief (GMAC_RPQ) Received Pause Quantum */
/* -------- GMAC_TPQ : (GMAC Offset: 0x03C) Transmit Pause Quantum Register -------- */
#define GMAC_TPQ_TPQ_Pos 0
#define GMAC_TPQ_TPQ_Msk ( 0xffffu << GMAC_TPQ_TPQ_Pos ) /**< \brief (GMAC_TPQ) Transmit Pause Quantum */
#define GMAC_TPQ_TPQ( value ) ( ( GMAC_TPQ_TPQ_Msk & ( ( value ) << GMAC_TPQ_TPQ_Pos ) ) )
/* -------- GMAC_TPSF : (GMAC Offset: 0x040) TX Partial Store and Forward Register -------- */
#define GMAC_TPSF_TPB1ADR_Pos 0
#define GMAC_TPSF_TPB1ADR_Msk ( 0xfffu << GMAC_TPSF_TPB1ADR_Pos ) /**< \brief (GMAC_TPSF) tx_pbuf_addr-1:0 */
#define GMAC_TPSF_TPB1ADR( value ) ( ( GMAC_TPSF_TPB1ADR_Msk & ( ( value ) << GMAC_TPSF_TPB1ADR_Pos ) ) )
#define GMAC_TPSF_ENTXP ( 0x1u << 31 ) /**< \brief (GMAC_TPSF) Enable TX Partial Store and Forward Operation */
/* -------- GMAC_RPSF : (GMAC Offset: 0x044) RX Partial Store and Forward Register -------- */
#define GMAC_RPSF_RPB1ADR_Pos 0
#define GMAC_RPSF_RPB1ADR_Msk ( 0xfffu << GMAC_RPSF_RPB1ADR_Pos ) /**< \brief (GMAC_RPSF) rx_pbuf_addr-1:0 */
#define GMAC_RPSF_RPB1ADR( value ) ( ( GMAC_RPSF_RPB1ADR_Msk & ( ( value ) << GMAC_RPSF_RPB1ADR_Pos ) ) )
#define GMAC_RPSF_ENRXP ( 0x1u << 31 ) /**< \brief (GMAC_RPSF) Enable RX Partial Store and Forward Operation */
/* -------- GMAC_HRB : (GMAC Offset: 0x080) Hash Register Bottom [31:0] -------- */
#define GMAC_HRB_ADDR_Pos 0
#define GMAC_HRB_ADDR_Msk ( 0xffffffffu << GMAC_HRB_ADDR_Pos ) /**< \brief (GMAC_HRB) Hash Address */
#define GMAC_HRB_ADDR( value ) ( ( GMAC_HRB_ADDR_Msk & ( ( value ) << GMAC_HRB_ADDR_Pos ) ) )
/* -------- GMAC_HRT : (GMAC Offset: 0x084) Hash Register Top [63:32] -------- */
#define GMAC_HRT_ADDR_Pos 0
#define GMAC_HRT_ADDR_Msk ( 0xffffffffu << GMAC_HRT_ADDR_Pos ) /**< \brief (GMAC_HRT) Hash Address */
#define GMAC_HRT_ADDR( value ) ( ( GMAC_HRT_ADDR_Msk & ( ( value ) << GMAC_HRT_ADDR_Pos ) ) )
/* -------- GMAC_SAB1 : (GMAC Offset: 0x088) Specific Address 1 Bottom [31:0] Register -------- */
#define GMAC_SAB1_ADDR_Pos 0
#define GMAC_SAB1_ADDR_Msk ( 0xffffffffu << GMAC_SAB1_ADDR_Pos ) /**< \brief (GMAC_SAB1) Specific Address 1 */
#define GMAC_SAB1_ADDR( value ) ( ( GMAC_SAB1_ADDR_Msk & ( ( value ) << GMAC_SAB1_ADDR_Pos ) ) )
/* -------- GMAC_SAT1 : (GMAC Offset: 0x08C) Specific Address 1 Top [47:32] Register -------- */
#define GMAC_SAT1_ADDR_Pos 0
#define GMAC_SAT1_ADDR_Msk ( 0xffffu << GMAC_SAT1_ADDR_Pos ) /**< \brief (GMAC_SAT1) Specific Address 1 */
#define GMAC_SAT1_ADDR( value ) ( ( GMAC_SAT1_ADDR_Msk & ( ( value ) << GMAC_SAT1_ADDR_Pos ) ) )
/* -------- GMAC_SAB2 : (GMAC Offset: 0x090) Specific Address 2 Bottom [31:0] Register -------- */
#define GMAC_SAB2_ADDR_Pos 0
#define GMAC_SAB2_ADDR_Msk ( 0xffffffffu << GMAC_SAB2_ADDR_Pos ) /**< \brief (GMAC_SAB2) Specific Address 2 */
#define GMAC_SAB2_ADDR( value ) ( ( GMAC_SAB2_ADDR_Msk & ( ( value ) << GMAC_SAB2_ADDR_Pos ) ) )
/* -------- GMAC_SAT2 : (GMAC Offset: 0x094) Specific Address 2 Top [47:32] Register -------- */
#define GMAC_SAT2_ADDR_Pos 0
#define GMAC_SAT2_ADDR_Msk ( 0xffffu << GMAC_SAT2_ADDR_Pos ) /**< \brief (GMAC_SAT2) Specific Address 2 */
#define GMAC_SAT2_ADDR( value ) ( ( GMAC_SAT2_ADDR_Msk & ( ( value ) << GMAC_SAT2_ADDR_Pos ) ) )
/* -------- GMAC_SAB3 : (GMAC Offset: 0x098) Specific Address 3 Bottom [31:0] Register -------- */
#define GMAC_SAB3_ADDR_Pos 0
#define GMAC_SAB3_ADDR_Msk ( 0xffffffffu << GMAC_SAB3_ADDR_Pos ) /**< \brief (GMAC_SAB3) Specific Address 3 */
#define GMAC_SAB3_ADDR( value ) ( ( GMAC_SAB3_ADDR_Msk & ( ( value ) << GMAC_SAB3_ADDR_Pos ) ) )
/* -------- GMAC_SAT3 : (GMAC Offset: 0x09C) Specific Address 3 Top [47:32] Register -------- */
#define GMAC_SAT3_ADDR_Pos 0
#define GMAC_SAT3_ADDR_Msk ( 0xffffu << GMAC_SAT3_ADDR_Pos ) /**< \brief (GMAC_SAT3) Specific Address 3 */
#define GMAC_SAT3_ADDR( value ) ( ( GMAC_SAT3_ADDR_Msk & ( ( value ) << GMAC_SAT3_ADDR_Pos ) ) )
/* -------- GMAC_SAB4 : (GMAC Offset: 0x0A0) Specific Address 4 Bottom [31:0] Register -------- */
#define GMAC_SAB4_ADDR_Pos 0
#define GMAC_SAB4_ADDR_Msk ( 0xffffffffu << GMAC_SAB4_ADDR_Pos ) /**< \brief (GMAC_SAB4) Specific Address 4 */
#define GMAC_SAB4_ADDR( value ) ( ( GMAC_SAB4_ADDR_Msk & ( ( value ) << GMAC_SAB4_ADDR_Pos ) ) )
/* -------- GMAC_SAT4 : (GMAC Offset: 0x0A4) Specific Address 4 Top [47:32] Register -------- */
#define GMAC_SAT4_ADDR_Pos 0
#define GMAC_SAT4_ADDR_Msk ( 0xffffu << GMAC_SAT4_ADDR_Pos ) /**< \brief (GMAC_SAT4) Specific Address 4 */
#define GMAC_SAT4_ADDR( value ) ( ( GMAC_SAT4_ADDR_Msk & ( ( value ) << GMAC_SAT4_ADDR_Pos ) ) )
/* -------- GMAC_TIDM[4] : (GMAC Offset: 0x0A8) Type ID Match 1 Register -------- */
#define GMAC_TIDM_TID_Pos 0
#define GMAC_TIDM_TID_Msk ( 0xffffu << GMAC_TIDM_TID_Pos ) /**< \brief (GMAC_TIDM[4]) Type ID Match 1 */
#define GMAC_TIDM_TID( value ) ( ( GMAC_TIDM_TID_Msk & ( ( value ) << GMAC_TIDM_TID_Pos ) ) )
/* -------- GMAC_WOL : (GMAC Offset: 0x0B8) Wake on LAN Register -------- */
#define GMAC_WOL_IP_Pos 0
#define GMAC_WOL_IP_Msk ( 0xffffu << GMAC_WOL_IP_Pos ) /**< \brief (GMAC_WOL) ARP Request IP Address */
#define GMAC_WOL_IP( value ) ( ( GMAC_WOL_IP_Msk & ( ( value ) << GMAC_WOL_IP_Pos ) ) )
#define GMAC_WOL_MAG ( 0x1u << 16 ) /**< \brief (GMAC_WOL) Magic Packet Event Enable */
#define GMAC_WOL_ARP ( 0x1u << 17 ) /**< \brief (GMAC_WOL) ARP Request IP Address */
#define GMAC_WOL_SA1 ( 0x1u << 18 ) /**< \brief (GMAC_WOL) Specific Address Register 1 Event Enable */
#define GMAC_WOL_MTI ( 0x1u << 19 ) /**< \brief (GMAC_WOL) Multicast Hash Event Enable */
/* -------- GMAC_IPGS : (GMAC Offset: 0x0BC) IPG Stretch Register -------- */
#define GMAC_IPGS_FL_Pos 0
#define GMAC_IPGS_FL_Msk ( 0xffffu << GMAC_IPGS_FL_Pos ) /**< \brief (GMAC_IPGS) Frame Length */
#define GMAC_IPGS_FL( value ) ( ( GMAC_IPGS_FL_Msk & ( ( value ) << GMAC_IPGS_FL_Pos ) ) )
/* -------- GMAC_SVLAN : (GMAC Offset: 0x0C0) Stacked VLAN Register -------- */
#define GMAC_SVLAN_VLAN_TYPE_Pos 0
#define GMAC_SVLAN_VLAN_TYPE_Msk ( 0xffffu << GMAC_SVLAN_VLAN_TYPE_Pos ) /**< \brief (GMAC_SVLAN) User Defined VLAN_TYPE Field */
#define GMAC_SVLAN_VLAN_TYPE( value ) ( ( GMAC_SVLAN_VLAN_TYPE_Msk & ( ( value ) << GMAC_SVLAN_VLAN_TYPE_Pos ) ) )
#define GMAC_SVLAN_ESVLAN ( 0x1u << 31 ) /**< \brief (GMAC_SVLAN) Enable Stacked VLAN Processing Mode */
/* -------- GMAC_TPFCP : (GMAC Offset: 0x0C4) Transmit PFC Pause Register -------- */
#define GMAC_TPFCP_PEV_Pos 0
#define GMAC_TPFCP_PEV_Msk ( 0xffu << GMAC_TPFCP_PEV_Pos ) /**< \brief (GMAC_TPFCP) Priority Enable Vector */
#define GMAC_TPFCP_PEV( value ) ( ( GMAC_TPFCP_PEV_Msk & ( ( value ) << GMAC_TPFCP_PEV_Pos ) ) )
#define GMAC_TPFCP_PQ_Pos 8
#define GMAC_TPFCP_PQ_Msk ( 0xffu << GMAC_TPFCP_PQ_Pos ) /**< \brief (GMAC_TPFCP) Pause Quantum */
#define GMAC_TPFCP_PQ( value ) ( ( GMAC_TPFCP_PQ_Msk & ( ( value ) << GMAC_TPFCP_PQ_Pos ) ) )
/* -------- GMAC_SAMB1 : (GMAC Offset: 0x0C8) Specific Address 1 Mask Bottom [31:0] Register -------- */
#define GMAC_SAMB1_ADDR_Pos 0
#define GMAC_SAMB1_ADDR_Msk ( 0xffffffffu << GMAC_SAMB1_ADDR_Pos ) /**< \brief (GMAC_SAMB1) Specific Address 1 Mask */
#define GMAC_SAMB1_ADDR( value ) ( ( GMAC_SAMB1_ADDR_Msk & ( ( value ) << GMAC_SAMB1_ADDR_Pos ) ) )
/* -------- GMAC_SAMT1 : (GMAC Offset: 0x0CC) Specific Address 1 Mask Top [47:32] Register -------- */
#define GMAC_SAMT1_ADDR_Pos 0
#define GMAC_SAMT1_ADDR_Msk ( 0xffffu << GMAC_SAMT1_ADDR_Pos ) /**< \brief (GMAC_SAMT1) Specific Address 1 Mask */
#define GMAC_SAMT1_ADDR( value ) ( ( GMAC_SAMT1_ADDR_Msk & ( ( value ) << GMAC_SAMT1_ADDR_Pos ) ) )
/* -------- GMAC_OTLO : (GMAC Offset: 0x100) Octets Transmitted [31:0] Register -------- */
#define GMAC_OTLO_TXO_Pos 0
#define GMAC_OTLO_TXO_Msk ( 0xffffffffu << GMAC_OTLO_TXO_Pos ) /**< \brief (GMAC_OTLO) Transmitted Octets */
/* -------- GMAC_OTHI : (GMAC Offset: 0x104) Octets Transmitted [47:32] Register -------- */
#define GMAC_OTHI_TXO_Pos 0
#define GMAC_OTHI_TXO_Msk ( 0xffffu << GMAC_OTHI_TXO_Pos ) /**< \brief (GMAC_OTHI) Transmitted Octets */
/* -------- GMAC_FT : (GMAC Offset: 0x108) Frames Transmitted Register -------- */
#define GMAC_FT_FTX_Pos 0
#define GMAC_FT_FTX_Msk ( 0xffffffffu << GMAC_FT_FTX_Pos ) /**< \brief (GMAC_FT) Frames Transmitted without Error */
/* -------- GMAC_BCFT : (GMAC Offset: 0x10C) Broadcast Frames Transmitted Register -------- */
#define GMAC_BCFT_BFTX_Pos 0
#define GMAC_BCFT_BFTX_Msk ( 0xffffffffu << GMAC_BCFT_BFTX_Pos ) /**< \brief (GMAC_BCFT) Broadcast Frames Transmitted without Error */
/* -------- GMAC_MFT : (GMAC Offset: 0x110) Multicast Frames Transmitted Register -------- */
#define GMAC_MFT_MFTX_Pos 0
#define GMAC_MFT_MFTX_Msk ( 0xffffffffu << GMAC_MFT_MFTX_Pos ) /**< \brief (GMAC_MFT) Multicast Frames Transmitted without Error */
/* -------- GMAC_PFT : (GMAC Offset: 0x114) Pause Frames Transmitted Register -------- */
#define GMAC_PFT_PFTX_Pos 0
#define GMAC_PFT_PFTX_Msk ( 0xffffu << GMAC_PFT_PFTX_Pos ) /**< \brief (GMAC_PFT) Pause Frames Transmitted Register */
/* -------- GMAC_BFT64 : (GMAC Offset: 0x118) 64 Byte Frames Transmitted Register -------- */
#define GMAC_BFT64_NFTX_Pos 0
#define GMAC_BFT64_NFTX_Msk ( 0xffffffffu << GMAC_BFT64_NFTX_Pos ) /**< \brief (GMAC_BFT64) 64 Byte Frames Transmitted without Error */
/* -------- GMAC_TBFT127 : (GMAC Offset: 0x11C) 65 to 127 Byte Frames Transmitted Register -------- */
#define GMAC_TBFT127_NFTX_Pos 0
#define GMAC_TBFT127_NFTX_Msk ( 0xffffffffu << GMAC_TBFT127_NFTX_Pos ) /**< \brief (GMAC_TBFT127) 65 to 127 Byte Frames Transmitted without Error */
/* -------- GMAC_TBFT255 : (GMAC Offset: 0x120) 128 to 255 Byte Frames Transmitted Register -------- */
#define GMAC_TBFT255_NFTX_Pos 0
#define GMAC_TBFT255_NFTX_Msk ( 0xffffffffu << GMAC_TBFT255_NFTX_Pos ) /**< \brief (GMAC_TBFT255) 128 to 255 Byte Frames Transmitted without Error */
/* -------- GMAC_TBFT511 : (GMAC Offset: 0x124) 256 to 511 Byte Frames Transmitted Register -------- */
#define GMAC_TBFT511_NFTX_Pos 0
#define GMAC_TBFT511_NFTX_Msk ( 0xffffffffu << GMAC_TBFT511_NFTX_Pos ) /**< \brief (GMAC_TBFT511) 256 to 511 Byte Frames Transmitted without Error */
/* -------- GMAC_TBFT1023 : (GMAC Offset: 0x128) 512 to 1023 Byte Frames Transmitted Register -------- */
#define GMAC_TBFT1023_NFTX_Pos 0
#define GMAC_TBFT1023_NFTX_Msk ( 0xffffffffu << GMAC_TBFT1023_NFTX_Pos ) /**< \brief (GMAC_TBFT1023) 512 to 1023 Byte Frames Transmitted without Error */
/* -------- GMAC_TBFT1518 : (GMAC Offset: 0x12C) 1024 to 1518 Byte Frames Transmitted Register -------- */
#define GMAC_TBFT1518_NFTX_Pos 0
#define GMAC_TBFT1518_NFTX_Msk ( 0xffffffffu << GMAC_TBFT1518_NFTX_Pos ) /**< \brief (GMAC_TBFT1518) 1024 to 1518 Byte Frames Transmitted without Error */
/* -------- GMAC_GTBFT1518 : (GMAC Offset: 0x130) Greater Than 1518 Byte Frames Transmitted Register -------- */
#define GMAC_GTBFT1518_NFTX_Pos 0
#define GMAC_GTBFT1518_NFTX_Msk ( 0xffffffffu << GMAC_GTBFT1518_NFTX_Pos ) /**< \brief (GMAC_GTBFT1518) Greater than 1518 Byte Frames Transmitted without Error */
/* -------- GMAC_TUR : (GMAC Offset: 0x134) Transmit Under Runs Register -------- */
#define GMAC_TUR_TXUNR_Pos 0
#define GMAC_TUR_TXUNR_Msk ( 0x3ffu << GMAC_TUR_TXUNR_Pos ) /**< \brief (GMAC_TUR) Transmit Under Runs */
/* -------- GMAC_SCF : (GMAC Offset: 0x138) Single Collision Frames Register -------- */
#define GMAC_SCF_SCOL_Pos 0
#define GMAC_SCF_SCOL_Msk ( 0x3ffffu << GMAC_SCF_SCOL_Pos ) /**< \brief (GMAC_SCF) Single Collision */
/* -------- GMAC_MCF : (GMAC Offset: 0x13C) Multiple Collision Frames Register -------- */
#define GMAC_MCF_MCOL_Pos 0
#define GMAC_MCF_MCOL_Msk ( 0x3ffffu << GMAC_MCF_MCOL_Pos ) /**< \brief (GMAC_MCF) Multiple Collision */
/* -------- GMAC_EC : (GMAC Offset: 0x140) Excessive Collisions Register -------- */
#define GMAC_EC_XCOL_Pos 0
#define GMAC_EC_XCOL_Msk ( 0x3ffu << GMAC_EC_XCOL_Pos ) /**< \brief (GMAC_EC) Excessive Collisions */
/* -------- GMAC_LC : (GMAC Offset: 0x144) Late Collisions Register -------- */
#define GMAC_LC_LCOL_Pos 0
#define GMAC_LC_LCOL_Msk ( 0x3ffu << GMAC_LC_LCOL_Pos ) /**< \brief (GMAC_LC) Late Collisions */
/* -------- GMAC_DTF : (GMAC Offset: 0x148) Deferred Transmission Frames Register -------- */
#define GMAC_DTF_DEFT_Pos 0
#define GMAC_DTF_DEFT_Msk ( 0x3ffffu << GMAC_DTF_DEFT_Pos ) /**< \brief (GMAC_DTF) Deferred Transmission */
/* -------- GMAC_CSE : (GMAC Offset: 0x14C) Carrier Sense Errors Register -------- */
#define GMAC_CSE_CSR_Pos 0
#define GMAC_CSE_CSR_Msk ( 0x3ffu << GMAC_CSE_CSR_Pos ) /**< \brief (GMAC_CSE) Carrier Sense Error */
/* -------- GMAC_ORLO : (GMAC Offset: 0x150) Octets Received [31:0] Received -------- */
#define GMAC_ORLO_RXO_Pos 0
#define GMAC_ORLO_RXO_Msk ( 0xffffffffu << GMAC_ORLO_RXO_Pos ) /**< \brief (GMAC_ORLO) Received Octets */
/* -------- GMAC_ORHI : (GMAC Offset: 0x154) Octets Received [47:32] Received -------- */
#define GMAC_ORHI_RXO_Pos 0
#define GMAC_ORHI_RXO_Msk ( 0xffffu << GMAC_ORHI_RXO_Pos ) /**< \brief (GMAC_ORHI) Received Octets */
/* -------- GMAC_FR : (GMAC Offset: 0x158) Frames Received Register -------- */
#define GMAC_FR_FRX_Pos 0
#define GMAC_FR_FRX_Msk ( 0xffffffffu << GMAC_FR_FRX_Pos ) /**< \brief (GMAC_FR) Frames Received without Error */
/* -------- GMAC_BCFR : (GMAC Offset: 0x15C) Broadcast Frames Received Register -------- */
#define GMAC_BCFR_BFRX_Pos 0
#define GMAC_BCFR_BFRX_Msk ( 0xffffffffu << GMAC_BCFR_BFRX_Pos ) /**< \brief (GMAC_BCFR) Broadcast Frames Received without Error */
/* -------- GMAC_MFR : (GMAC Offset: 0x160) Multicast Frames Received Register -------- */
#define GMAC_MFR_MFRX_Pos 0
#define GMAC_MFR_MFRX_Msk ( 0xffffffffu << GMAC_MFR_MFRX_Pos ) /**< \brief (GMAC_MFR) Multicast Frames Received without Error */
/* -------- GMAC_PFR : (GMAC Offset: 0x164) Pause Frames Received Register -------- */
#define GMAC_PFR_PFRX_Pos 0
#define GMAC_PFR_PFRX_Msk ( 0xffffu << GMAC_PFR_PFRX_Pos ) /**< \brief (GMAC_PFR) Pause Frames Received Register */
/* -------- GMAC_BFR64 : (GMAC Offset: 0x168) 64 Byte Frames Received Register -------- */
#define GMAC_BFR64_NFRX_Pos 0
#define GMAC_BFR64_NFRX_Msk ( 0xffffffffu << GMAC_BFR64_NFRX_Pos ) /**< \brief (GMAC_BFR64) 64 Byte Frames Received without Error */
/* -------- GMAC_TBFR127 : (GMAC Offset: 0x16C) 65 to 127 Byte Frames Received Register -------- */
#define GMAC_TBFR127_NFRX_Pos 0
#define GMAC_TBFR127_NFRX_Msk ( 0xffffffffu << GMAC_TBFR127_NFRX_Pos ) /**< \brief (GMAC_TBFR127) 65 to 127 Byte Frames Received without Error */
/* -------- GMAC_TBFR255 : (GMAC Offset: 0x170) 128 to 255 Byte Frames Received Register -------- */
#define GMAC_TBFR255_NFRX_Pos 0
#define GMAC_TBFR255_NFRX_Msk ( 0xffffffffu << GMAC_TBFR255_NFRX_Pos ) /**< \brief (GMAC_TBFR255) 128 to 255 Byte Frames Received without Error */
/* -------- GMAC_TBFR511 : (GMAC Offset: 0x174) 256 to 511Byte Frames Received Register -------- */
#define GMAC_TBFR511_NFRX_Pos 0
#define GMAC_TBFR511_NFRX_Msk ( 0xffffffffu << GMAC_TBFR511_NFRX_Pos ) /**< \brief (GMAC_TBFR511) 256 to 511 Byte Frames Received without Error */
/* -------- GMAC_TBFR1023 : (GMAC Offset: 0x178) 512 to 1023 Byte Frames Received Register -------- */
#define GMAC_TBFR1023_NFRX_Pos 0
#define GMAC_TBFR1023_NFRX_Msk ( 0xffffffffu << GMAC_TBFR1023_NFRX_Pos ) /**< \brief (GMAC_TBFR1023) 512 to 1023 Byte Frames Received without Error */
/* -------- GMAC_TBFR1518 : (GMAC Offset: 0x17C) 1024 to 1518 Byte Frames Received Register -------- */
#define GMAC_TBFR1518_NFRX_Pos 0
#define GMAC_TBFR1518_NFRX_Msk ( 0xffffffffu << GMAC_TBFR1518_NFRX_Pos ) /**< \brief (GMAC_TBFR1518) 1024 to 1518 Byte Frames Received without Error */
/* -------- GMAC_TMXBFR : (GMAC Offset: 0x180) 1519 to Maximum Byte Frames Received Register -------- */
#define GMAC_TMXBFR_NFRX_Pos 0
#define GMAC_TMXBFR_NFRX_Msk ( 0xffffffffu << GMAC_TMXBFR_NFRX_Pos ) /**< \brief (GMAC_TMXBFR) 1519 to Maximum Byte Frames Received without Error */
/* -------- GMAC_UFR : (GMAC Offset: 0x184) Undersize Frames Received Register -------- */
#define GMAC_UFR_UFRX_Pos 0
#define GMAC_UFR_UFRX_Msk ( 0x3ffu << GMAC_UFR_UFRX_Pos ) /**< \brief (GMAC_UFR) Undersize Frames Received */
/* -------- GMAC_OFR : (GMAC Offset: 0x188) Oversize Frames Received Register -------- */
#define GMAC_OFR_OFRX_Pos 0
#define GMAC_OFR_OFRX_Msk ( 0x3ffu << GMAC_OFR_OFRX_Pos ) /**< \brief (GMAC_OFR) Oversized Frames Received */
/* -------- GMAC_JR : (GMAC Offset: 0x18C) Jabbers Received Register -------- */
#define GMAC_JR_JRX_Pos 0
#define GMAC_JR_JRX_Msk ( 0x3ffu << GMAC_JR_JRX_Pos ) /**< \brief (GMAC_JR) Jabbers Received */
/* -------- GMAC_FCSE : (GMAC Offset: 0x190) Frame Check Sequence Errors Register -------- */
#define GMAC_FCSE_FCKR_Pos 0
#define GMAC_FCSE_FCKR_Msk ( 0x3ffu << GMAC_FCSE_FCKR_Pos ) /**< \brief (GMAC_FCSE) Frame Check Sequence Errors */
/* -------- GMAC_LFFE : (GMAC Offset: 0x194) Length Field Frame Errors Register -------- */
#define GMAC_LFFE_LFER_Pos 0
#define GMAC_LFFE_LFER_Msk ( 0x3ffu << GMAC_LFFE_LFER_Pos ) /**< \brief (GMAC_LFFE) Length Field Frame Errors */
/* -------- GMAC_RSE : (GMAC Offset: 0x198) Receive Symbol Errors Register -------- */
#define GMAC_RSE_RXSE_Pos 0
#define GMAC_RSE_RXSE_Msk ( 0x3ffu << GMAC_RSE_RXSE_Pos ) /**< \brief (GMAC_RSE) Receive Symbol Errors */
/* -------- GMAC_AE : (GMAC Offset: 0x19C) Alignment Errors Register -------- */
#define GMAC_AE_AER_Pos 0
#define GMAC_AE_AER_Msk ( 0x3ffu << GMAC_AE_AER_Pos ) /**< \brief (GMAC_AE) Alignment Errors */
/* -------- GMAC_RRE : (GMAC Offset: 0x1A0) Receive Resource Errors Register -------- */
#define GMAC_RRE_RXRER_Pos 0
#define GMAC_RRE_RXRER_Msk ( 0x3ffffu << GMAC_RRE_RXRER_Pos ) /**< \brief (GMAC_RRE) Receive Resource Errors */
/* -------- GMAC_ROE : (GMAC Offset: 0x1A4) Receive Overrun Register -------- */
#define GMAC_ROE_RXOVR_Pos 0
#define GMAC_ROE_RXOVR_Msk ( 0x3ffu << GMAC_ROE_RXOVR_Pos ) /**< \brief (GMAC_ROE) Receive Overruns */
/* -------- GMAC_IHCE : (GMAC Offset: 0x1A8) IP Header Checksum Errors Register -------- */
#define GMAC_IHCE_HCKER_Pos 0
#define GMAC_IHCE_HCKER_Msk ( 0xffu << GMAC_IHCE_HCKER_Pos ) /**< \brief (GMAC_IHCE) IP Header Checksum Errors */
/* -------- GMAC_TCE : (GMAC Offset: 0x1AC) TCP Checksum Errors Register -------- */
#define GMAC_TCE_TCKER_Pos 0
#define GMAC_TCE_TCKER_Msk ( 0xffu << GMAC_TCE_TCKER_Pos ) /**< \brief (GMAC_TCE) TCP Checksum Errors */
/* -------- GMAC_UCE : (GMAC Offset: 0x1B0) UDP Checksum Errors Register -------- */
#define GMAC_UCE_UCKER_Pos 0
#define GMAC_UCE_UCKER_Msk ( 0xffu << GMAC_UCE_UCKER_Pos ) /**< \brief (GMAC_UCE) UDP Checksum Errors */
/* -------- GMAC_TSSS : (GMAC Offset: 0x1C8) 1588 Timer Sync Strobe Seconds Register -------- */
#define GMAC_TSSS_VTS_Pos 0
#define GMAC_TSSS_VTS_Msk ( 0xffffffffu << GMAC_TSSS_VTS_Pos ) /**< \brief (GMAC_TSSS) Value of Timer Seconds Register Capture */
#define GMAC_TSSS_VTS( value ) ( ( GMAC_TSSS_VTS_Msk & ( ( value ) << GMAC_TSSS_VTS_Pos ) ) )
/* -------- GMAC_TSSN : (GMAC Offset: 0x1CC) 1588 Timer Sync Strobe Nanoseconds Register -------- */
#define GMAC_TSSN_VTN_Pos 0
#define GMAC_TSSN_VTN_Msk ( 0x3fffffffu << GMAC_TSSN_VTN_Pos ) /**< \brief (GMAC_TSSN) Value Timer Nanoseconds Register Capture */
#define GMAC_TSSN_VTN( value ) ( ( GMAC_TSSN_VTN_Msk & ( ( value ) << GMAC_TSSN_VTN_Pos ) ) )
/* -------- GMAC_TS : (GMAC Offset: 0x1D0) 1588 Timer Seconds Register -------- */
#define GMAC_TS_TCS_Pos 0
#define GMAC_TS_TCS_Msk ( 0xffffffffu << GMAC_TS_TCS_Pos ) /**< \brief (GMAC_TS) Timer Count in Seconds */
#define GMAC_TS_TCS( value ) ( ( GMAC_TS_TCS_Msk & ( ( value ) << GMAC_TS_TCS_Pos ) ) )
/* -------- GMAC_TN : (GMAC Offset: 0x1D4) 1588 Timer Nanoseconds Register -------- */
#define GMAC_TN_TNS_Pos 0
#define GMAC_TN_TNS_Msk ( 0x3fffffffu << GMAC_TN_TNS_Pos ) /**< \brief (GMAC_TN) Timer Count in Nanoseconds */
#define GMAC_TN_TNS( value ) ( ( GMAC_TN_TNS_Msk & ( ( value ) << GMAC_TN_TNS_Pos ) ) )
/* -------- GMAC_TA : (GMAC Offset: 0x1D8) 1588 Timer Adjust Register -------- */
#define GMAC_TA_ITDT_Pos 0
#define GMAC_TA_ITDT_Msk ( 0x3fffffffu << GMAC_TA_ITDT_Pos ) /**< \brief (GMAC_TA) Increment/Decrement */
#define GMAC_TA_ITDT( value ) ( ( GMAC_TA_ITDT_Msk & ( ( value ) << GMAC_TA_ITDT_Pos ) ) )
#define GMAC_TA_ADJ ( 0x1u << 31 ) /**< \brief (GMAC_TA) Adjust 1588 Timer */
/* -------- GMAC_TI : (GMAC Offset: 0x1DC) 1588 Timer Increment Register -------- */
#define GMAC_TI_CNS_Pos 0
#define GMAC_TI_CNS_Msk ( 0xffu << GMAC_TI_CNS_Pos ) /**< \brief (GMAC_TI) Count Nanoseconds */
#define GMAC_TI_CNS( value ) ( ( GMAC_TI_CNS_Msk & ( ( value ) << GMAC_TI_CNS_Pos ) ) )
#define GMAC_TI_ACNS_Pos 8
#define GMAC_TI_ACNS_Msk ( 0xffu << GMAC_TI_ACNS_Pos ) /**< \brief (GMAC_TI) Alternative Count Nanoseconds */
#define GMAC_TI_ACNS( value ) ( ( GMAC_TI_ACNS_Msk & ( ( value ) << GMAC_TI_ACNS_Pos ) ) )
#define GMAC_TI_NIT_Pos 16
#define GMAC_TI_NIT_Msk ( 0xffu << GMAC_TI_NIT_Pos ) /**< \brief (GMAC_TI) Number of Increments */
#define GMAC_TI_NIT( value ) ( ( GMAC_TI_NIT_Msk & ( ( value ) << GMAC_TI_NIT_Pos ) ) )
/* -------- GMAC_EFTS : (GMAC Offset: 0x1E0) PTP Event Frame Transmitted Seconds -------- */
#define GMAC_EFTS_RUD_Pos 0
#define GMAC_EFTS_RUD_Msk ( 0xffffffffu << GMAC_EFTS_RUD_Pos ) /**< \brief (GMAC_EFTS) Register Update */
/* -------- GMAC_EFTN : (GMAC Offset: 0x1E4) PTP Event Frame Transmitted Nanoseconds -------- */
#define GMAC_EFTN_RUD_Pos 0
#define GMAC_EFTN_RUD_Msk ( 0x3fffffffu << GMAC_EFTN_RUD_Pos ) /**< \brief (GMAC_EFTN) Register Update */
/* -------- GMAC_EFRS : (GMAC Offset: 0x1E8) PTP Event Frame Received Seconds -------- */
#define GMAC_EFRS_RUD_Pos 0
#define GMAC_EFRS_RUD_Msk ( 0xffffffffu << GMAC_EFRS_RUD_Pos ) /**< \brief (GMAC_EFRS) Register Update */
/* -------- GMAC_EFRN : (GMAC Offset: 0x1EC) PTP Event Frame Received Nanoseconds -------- */
#define GMAC_EFRN_RUD_Pos 0
#define GMAC_EFRN_RUD_Msk ( 0x3fffffffu << GMAC_EFRN_RUD_Pos ) /**< \brief (GMAC_EFRN) Register Update */
/* -------- GMAC_PEFTS : (GMAC Offset: 0x1F0) PTP Peer Event Frame Transmitted Seconds -------- */
#define GMAC_PEFTS_RUD_Pos 0
#define GMAC_PEFTS_RUD_Msk ( 0xffffffffu << GMAC_PEFTS_RUD_Pos ) /**< \brief (GMAC_PEFTS) Register Update */
/* -------- GMAC_PEFTN : (GMAC Offset: 0x1F4) PTP Peer Event Frame Transmitted Nanoseconds -------- */
#define GMAC_PEFTN_RUD_Pos 0
#define GMAC_PEFTN_RUD_Msk ( 0x3fffffffu << GMAC_PEFTN_RUD_Pos ) /**< \brief (GMAC_PEFTN) Register Update */
/* -------- GMAC_PEFRS : (GMAC Offset: 0x1F8) PTP Peer Event Frame Received Seconds -------- */
#define GMAC_PEFRS_RUD_Pos 0
#define GMAC_PEFRS_RUD_Msk ( 0xffffffffu << GMAC_PEFRS_RUD_Pos ) /**< \brief (GMAC_PEFRS) Register Update */
/* -------- GMAC_PEFRN : (GMAC Offset: 0x1FC) PTP Peer Event Frame Received Nanoseconds -------- */
#define GMAC_PEFRN_RUD_Pos 0
#define GMAC_PEFRN_RUD_Msk ( 0x3fffffffu << GMAC_PEFRN_RUD_Pos ) /**< \brief (GMAC_PEFRN) Register Update */
/* -------- GMAC_ISRPQ[7] : (GMAC Offset: 0x400) Interrupt Status Register Priority Queue -------- */
#define GMAC_ISRPQ_RCOMP ( 0x1u << 1 ) /**< \brief (GMAC_ISRPQ[7]) Receive Complete */
#define GMAC_ISRPQ_RXUBR ( 0x1u << 2 ) /**< \brief (GMAC_ISRPQ[7]) RX Used Bit Read */
#define GMAC_ISRPQ_RLEX ( 0x1u << 5 ) /**< \brief (GMAC_ISRPQ[7]) Retry Limit Exceeded or Late Collision */
#define GMAC_ISRPQ_TFC ( 0x1u << 6 ) /**< \brief (GMAC_ISRPQ[7]) Transmit Frame Corruption due to AHB error */
#define GMAC_ISRPQ_TCOMP ( 0x1u << 7 ) /**< \brief (GMAC_ISRPQ[7]) Transmit Complete */
#define GMAC_ISRPQ_ROVR ( 0x1u << 10 ) /**< \brief (GMAC_ISRPQ[7]) Receive Overrun */
#define GMAC_ISRPQ_HRESP ( 0x1u << 11 ) /**< \brief (GMAC_ISRPQ[7]) HRESP Not OK */
/* -------- GMAC_TBQBAPQ[7] : (GMAC Offset: 0x440) Transmit Buffer Queue Base Address Priority Queue -------- */
#define GMAC_TBQBAPQ_TXBQBA_Pos 2
#define GMAC_TBQBAPQ_TXBQBA_Msk ( 0x3fu << GMAC_TBQBAPQ_TXBQBA_Pos ) /**< \brief (GMAC_TBQBAPQ[7]) Transmit Buffer Queue Base Address */
#define GMAC_TBQBAPQ_TXBQBA( value ) ( ( GMAC_TBQBAPQ_TXBQBA_Msk & ( ( value ) << GMAC_TBQBAPQ_TXBQBA_Pos ) ) )
/* -------- GMAC_RBQBAPQ[7] : (GMAC Offset: 0x480) Receive Buffer Queue Base Address Priority Queue -------- */
#define GMAC_RBQBAPQ_RXBQBA_Pos 2
#define GMAC_RBQBAPQ_RXBQBA_Msk ( 0x3fu << GMAC_RBQBAPQ_RXBQBA_Pos ) /**< \brief (GMAC_RBQBAPQ[7]) Receive Buffer Queue Base Address */
#define GMAC_RBQBAPQ_RXBQBA( value ) ( ( GMAC_RBQBAPQ_RXBQBA_Msk & ( ( value ) << GMAC_RBQBAPQ_RXBQBA_Pos ) ) )
/* -------- GMAC_RBSRPQ[7] : (GMAC Offset: 0x4A0) Receive Buffer Size Register Priority Queue -------- */
#define GMAC_RBSRPQ_RBS_Pos 0
#define GMAC_RBSRPQ_RBS_Msk ( 0xffffu << GMAC_RBSRPQ_RBS_Pos ) /**< \brief (GMAC_RBSRPQ[7]) Receive Buffer Size */
#define GMAC_RBSRPQ_RBS( value ) ( ( GMAC_RBSRPQ_RBS_Msk & ( ( value ) << GMAC_RBSRPQ_RBS_Pos ) ) )
/* -------- GMAC_ST1RPQ[16] : (GMAC Offset: 0x500) Screening Type1 Register Priority Queue -------- */
#define GMAC_ST1RPQ_QNB_Pos 0
#define GMAC_ST1RPQ_QNB_Msk ( 0xfu << GMAC_ST1RPQ_QNB_Pos ) /**< \brief (GMAC_ST1RPQ[16]) Que Number (0->7) */
#define GMAC_ST1RPQ_QNB( value ) ( ( GMAC_ST1RPQ_QNB_Msk & ( ( value ) << GMAC_ST1RPQ_QNB_Pos ) ) )
#define GMAC_ST1RPQ_DSTCM_Pos 4
#define GMAC_ST1RPQ_DSTCM_Msk ( 0xffu << GMAC_ST1RPQ_DSTCM_Pos ) /**< \brief (GMAC_ST1RPQ[16]) Differentiated Services or Traffic Class Match */
#define GMAC_ST1RPQ_DSTCM( value ) ( ( GMAC_ST1RPQ_DSTCM_Msk & ( ( value ) << GMAC_ST1RPQ_DSTCM_Pos ) ) )
#define GMAC_ST1RPQ_UDPM_Pos 12
#define GMAC_ST1RPQ_UDPM_Msk ( 0xffffu << GMAC_ST1RPQ_UDPM_Pos ) /**< \brief (GMAC_ST1RPQ[16]) UDP Port Match */
#define GMAC_ST1RPQ_UDPM( value ) ( ( GMAC_ST1RPQ_UDPM_Msk & ( ( value ) << GMAC_ST1RPQ_UDPM_Pos ) ) )
#define GMAC_ST1RPQ_DSTCE ( 0x1u << 28 ) /**< \brief (GMAC_ST1RPQ[16]) Differentiated Services or Traffic Class Match Enable */
#define GMAC_ST1RPQ_UDPE ( 0x1u << 29 ) /**< \brief (GMAC_ST1RPQ[16]) UDP Port Match Enable */
/* -------- GMAC_ST2RPQ[16] : (GMAC Offset: 0x540) Screening Type2 Register Priority Queue -------- */
#define GMAC_ST2RPQ_QNB_Pos 0
#define GMAC_ST2RPQ_QNB_Msk ( 0xfu << GMAC_ST2RPQ_QNB_Pos ) /**< \brief (GMAC_ST2RPQ[16]) Que Number (0->7) */
#define GMAC_ST2RPQ_QNB( value ) ( ( GMAC_ST2RPQ_QNB_Msk & ( ( value ) << GMAC_ST2RPQ_QNB_Pos ) ) )
#define GMAC_ST2RPQ_VLANP_Pos 4
#define GMAC_ST2RPQ_VLANP_Msk ( 0xfu << GMAC_ST2RPQ_VLANP_Pos ) /**< \brief (GMAC_ST2RPQ[16]) VLAN Priority */
#define GMAC_ST2RPQ_VLANP( value ) ( ( GMAC_ST2RPQ_VLANP_Msk & ( ( value ) << GMAC_ST2RPQ_VLANP_Pos ) ) )
#define GMAC_ST2RPQ_VLANE ( 0x1u << 8 ) /**< \brief (GMAC_ST2RPQ[16]) VLAN Enable */
/* -------- GMAC_IERPQ[7] : (GMAC Offset: 0x600) Interrupt Enable Register Priority Queue -------- */
#define GMAC_IERPQ_RCOMP ( 0x1u << 1 ) /**< \brief (GMAC_IERPQ[7]) Receive Complete */
#define GMAC_IERPQ_RXUBR ( 0x1u << 2 ) /**< \brief (GMAC_IERPQ[7]) RX Used Bit Read */
#define GMAC_IERPQ_RLEX ( 0x1u << 5 ) /**< \brief (GMAC_IERPQ[7]) Retry Limit Exceeded or Late Collision */
#define GMAC_IERPQ_TFC ( 0x1u << 6 ) /**< \brief (GMAC_IERPQ[7]) Transmit Frame Corruption due to AHB error */
#define GMAC_IERPQ_TCOMP ( 0x1u << 7 ) /**< \brief (GMAC_IERPQ[7]) Transmit Complete */
#define GMAC_IERPQ_ROVR ( 0x1u << 10 ) /**< \brief (GMAC_IERPQ[7]) Receive Overrun */
#define GMAC_IERPQ_HRESP ( 0x1u << 11 ) /**< \brief (GMAC_IERPQ[7]) HRESP Not OK */
/* -------- GMAC_IDRPQ[7] : (GMAC Offset: 0x620) Interrupt Disable Register Priority Queue -------- */
#define GMAC_IDRPQ_RCOMP ( 0x1u << 1 ) /**< \brief (GMAC_IDRPQ[7]) Receive Complete */
#define GMAC_IDRPQ_RXUBR ( 0x1u << 2 ) /**< \brief (GMAC_IDRPQ[7]) RX Used Bit Read */
#define GMAC_IDRPQ_RLEX ( 0x1u << 5 ) /**< \brief (GMAC_IDRPQ[7]) Retry Limit Exceeded or Late Collision */
#define GMAC_IDRPQ_TFC ( 0x1u << 6 ) /**< \brief (GMAC_IDRPQ[7]) Transmit Frame Corruption due to AHB error */
#define GMAC_IDRPQ_TCOMP ( 0x1u << 7 ) /**< \brief (GMAC_IDRPQ[7]) Transmit Complete */
#define GMAC_IDRPQ_ROVR ( 0x1u << 10 ) /**< \brief (GMAC_IDRPQ[7]) Receive Overrun */
#define GMAC_IDRPQ_HRESP ( 0x1u << 11 ) /**< \brief (GMAC_IDRPQ[7]) HRESP Not OK */
/* -------- GMAC_IMRPQ[7] : (GMAC Offset: 0x640) Interrupt Mask Register Priority Queue -------- */
#define GMAC_IMRPQ_RCOMP ( 0x1u << 1 ) /**< \brief (GMAC_IMRPQ[7]) Receive Complete */
#define GMAC_IMRPQ_RXUBR ( 0x1u << 2 ) /**< \brief (GMAC_IMRPQ[7]) RX Used Bit Read */
#define GMAC_IMRPQ_RLEX ( 0x1u << 5 ) /**< \brief (GMAC_IMRPQ[7]) Retry Limit Exceeded or Late Collision */
#define GMAC_IMRPQ_AHB ( 0x1u << 6 ) /**< \brief (GMAC_IMRPQ[7]) AHB Error */
#define GMAC_IMRPQ_TCOMP ( 0x1u << 7 ) /**< \brief (GMAC_IMRPQ[7]) Transmit Complete */
#define GMAC_IMRPQ_ROVR ( 0x1u << 10 ) /**< \brief (GMAC_IMRPQ[7]) Receive Overrun */
#define GMAC_IMRPQ_HRESP ( 0x1u << 11 ) /**< \brief (GMAC_IMRPQ[7]) HRESP Not OK */
/*@}*/
#endif /* _SAM4E_GMAC_COMPONENT_ */

View File

@ -0,0 +1,518 @@
/**
* \file
*
* \brief API driver for KSZ8051MNL PHY component.
*
* Copyright (c) 2013 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* 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. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
*
* \asf_license_stop
*
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "FreeRTOSIPConfig.h"
#include "ethernet_phy.h"
#include "instance/gmac.h"
/*/ @cond 0 */
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/*/ @endcond */
/**
* \defgroup ksz8051mnl_ethernet_phy_group PHY component (KSZ8051MNL)
*
* Driver for the ksz8051mnl component. This driver provides access to the main
* features of the PHY.
*
* \section dependencies Dependencies
* This driver depends on the following modules:
* - \ref gmac_group Ethernet Media Access Controller (GMAC) module.
*
* @{
*/
SPhyProps phyProps;
/* Max PHY number */
#define ETH_PHY_MAX_ADDR 31
/* Ethernet PHY operation max retry count */
#define ETH_PHY_RETRY_MAX 1000000
/* Ethernet PHY operation timeout */
#define ETH_PHY_TIMEOUT 10
/**
* \brief Find a valid PHY Address ( from addrStart to 31 ).
*
* \param p_gmac Pointer to the GMAC instance.
* \param uc_phy_addr PHY address.
* \param uc_start_addr Start address of the PHY to be searched.
*
* \return 0xFF when no valid PHY address is found.
*/
int ethernet_phy_addr = 0;
static uint8_t ethernet_phy_find_valid( Gmac * p_gmac,
uint8_t uc_phy_addr,
uint8_t uc_start_addr )
{
uint32_t ul_value = 0;
uint8_t uc_cnt;
uint8_t uc_phy_address = uc_phy_addr;
gmac_enable_management( p_gmac, true );
/*
#define GMII_OUI_MSB 0x0022
#define GMII_OUI_LSB 0x05
*
* PHYID1 = 0x0022
* PHYID2 = 0x1550
* 0001_0101_0101_0000 = 0x1550 <= mask should be 0xFFF0
*/
/* Check the current PHY address */
gmac_phy_read( p_gmac, uc_phy_addr, GMII_PHYID1, &ul_value );
/* Find another one */
if( ul_value != GMII_OUI_MSB )
{
ethernet_phy_addr = 0xFF;
for( uc_cnt = uc_start_addr; uc_cnt <= ETH_PHY_MAX_ADDR; uc_cnt++ )
{
uc_phy_address = ( uc_phy_address + 1 ) & 0x1F;
ul_value = 0;
gmac_phy_read( p_gmac, uc_phy_address, GMII_PHYID1, &ul_value );
if( ul_value == GMII_OUI_MSB )
{
ethernet_phy_addr = uc_phy_address;
break;
}
}
}
gmac_enable_management( p_gmac, false );
if( ethernet_phy_addr != 0xFF )
{
gmac_phy_read( p_gmac, uc_phy_address, GMII_BMSR, &ul_value );
}
return ethernet_phy_addr;
}
/**
* \brief Perform a HW initialization to the PHY and set up clocks.
*
* This should be called only once to initialize the PHY pre-settings.
* The PHY address is the reset status of CRS, RXD[3:0] (the emacPins' pullups).
* The COL pin is used to select MII mode on reset (pulled up for Reduced MII).
* The RXDV pin is used to select test mode on reset (pulled up for test mode).
* The above pins should be predefined for corresponding settings in resetPins.
* The GMAC peripheral pins are configured after the reset is done.
*
* \param p_gmac Pointer to the GMAC instance.
* \param uc_phy_addr PHY address.
* \param ul_mck GMAC MCK.
*
* Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
*/
uint8_t ethernet_phy_init( Gmac * p_gmac,
uint8_t uc_phy_addr,
uint32_t mck )
{
uint8_t uc_rc = GMAC_TIMEOUT;
uint8_t uc_phy;
ethernet_phy_reset( GMAC, uc_phy_addr );
/* Configure GMAC runtime clock */
uc_rc = gmac_set_mdc_clock( p_gmac, mck );
if( uc_rc != GMAC_OK )
{
return 0;
}
/* Check PHY Address */
uc_phy = ethernet_phy_find_valid( p_gmac, uc_phy_addr, 0 );
if( uc_phy == 0xFF )
{
return 0;
}
if( uc_phy != uc_phy_addr )
{
ethernet_phy_reset( p_gmac, uc_phy_addr );
}
phy_props.phy_chn = uc_phy;
return uc_phy;
}
/**
* \brief Get the Link & speed settings, and automatically set up the GMAC with the
* settings.
*
* \param p_gmac Pointer to the GMAC instance.
* \param uc_phy_addr PHY address.
* \param uc_apply_setting_flag Set to 0 to not apply the PHY configurations, else to apply.
*
* Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
*/
uint8_t ethernet_phy_set_link( Gmac * p_gmac,
uint8_t uc_phy_addr,
uint8_t uc_apply_setting_flag )
{
uint32_t ul_stat1;
uint32_t ul_stat2;
uint8_t uc_phy_address, uc_speed = true, uc_fd = true;
uint8_t uc_rc = GMAC_TIMEOUT;
gmac_enable_management( p_gmac, true );
uc_phy_address = uc_phy_addr;
uc_rc = gmac_phy_read( p_gmac, uc_phy_address, GMII_BMSR, &ul_stat1 );
if( uc_rc != GMAC_OK )
{
/* Disable PHY management and start the GMAC transfer */
gmac_enable_management( p_gmac, false );
return uc_rc;
}
if( ( ul_stat1 & GMII_LINK_STATUS ) == 0 )
{
/* Disable PHY management and start the GMAC transfer */
gmac_enable_management( p_gmac, false );
return GMAC_INVALID;
}
if( uc_apply_setting_flag == 0 )
{
/* Disable PHY management and start the GMAC transfer */
gmac_enable_management( p_gmac, false );
return uc_rc;
}
/* Read advertisement */
uc_rc = gmac_phy_read( p_gmac, uc_phy_address, GMII_ANAR, &ul_stat2 );
phy_props.phy_stat1 = ul_stat1;
phy_props.phy_stat2 = ul_stat2;
if( uc_rc != GMAC_OK )
{
/* Disable PHY management and start the GMAC transfer */
gmac_enable_management( p_gmac, false );
return uc_rc;
}
if( ( ul_stat1 & GMII_100BASE_TX_FD ) && ( ul_stat2 & GMII_100TX_FDX ) )
{
/* Set GMAC for 100BaseTX and Full Duplex */
uc_speed = true;
uc_fd = true;
}
else
if( ( ul_stat1 & GMII_100BASE_T4_HD ) && ( ul_stat2 & GMII_100TX_HDX ) )
{
/* Set MII for 100BaseTX and Half Duplex */
uc_speed = true;
uc_fd = false;
}
else
if( ( ul_stat1 & GMII_10BASE_T_FD ) && ( ul_stat2 & GMII_10_FDX ) )
{
/* Set MII for 10BaseT and Full Duplex */
uc_speed = false;
uc_fd = true;
}
else
if( ( ul_stat1 & GMII_10BASE_T_HD ) && ( ul_stat2 & GMII_10_HDX ) )
{
/* Set MII for 10BaseT and Half Duplex */
uc_speed = false;
uc_fd = false;
}
gmac_set_speed( p_gmac, uc_speed );
gmac_enable_full_duplex( p_gmac, uc_fd );
/* Start the GMAC transfers */
gmac_enable_management( p_gmac, false );
return uc_rc;
}
PhyProps_t phy_props;
/**
* \brief Issue an auto negotiation of the PHY.
*
* \param p_gmac Pointer to the GMAC instance.
* \param uc_phy_addr PHY address.
*
* Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
*/
uint8_t ethernet_phy_auto_negotiate( Gmac * p_gmac,
uint8_t uc_phy_addr )
{
uint32_t ul_retry_max = ETH_PHY_RETRY_MAX;
uint32_t ul_value;
uint32_t ul_phy_anar;
uint32_t ul_retry_count = 0;
uint8_t uc_speed = 0;
uint8_t uc_fd = 0;
uint8_t uc_rc = GMAC_TIMEOUT;
gmac_enable_management( p_gmac, true );
/* Set up control register */
uc_rc = gmac_phy_read( p_gmac, uc_phy_addr, GMII_BMCR, &ul_value );
if( uc_rc != GMAC_OK )
{
gmac_enable_management( p_gmac, false );
phy_props.phy_result = -1;
return uc_rc;
}
ul_value &= ~( uint32_t ) GMII_AUTONEG; /* Remove auto-negotiation enable */
ul_value &= ~( uint32_t ) ( GMII_LOOPBACK | GMII_POWER_DOWN );
ul_value |= ( uint32_t ) GMII_ISOLATE; /* Electrically isolate PHY */
uc_rc = gmac_phy_write( p_gmac, uc_phy_addr, GMII_BMCR, ul_value );
if( uc_rc != GMAC_OK )
{
gmac_enable_management( p_gmac, false );
phy_props.phy_result = -2;
return uc_rc;
}
/*
* Set the Auto_negotiation Advertisement Register.
* MII advertising for Next page.
* 100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3.
*/
ul_phy_anar = GMII_100TX_FDX | GMII_100TX_HDX | GMII_10_FDX | GMII_10_HDX |
GMII_AN_IEEE_802_3;
uc_rc = gmac_phy_write( p_gmac, uc_phy_addr, GMII_ANAR, ul_phy_anar );
if( uc_rc != GMAC_OK )
{
gmac_enable_management( p_gmac, false );
phy_props.phy_result = -3;
return uc_rc;
}
/* Read & modify control register */
uc_rc = gmac_phy_read( p_gmac, uc_phy_addr, GMII_BMCR, &ul_value );
if( uc_rc != GMAC_OK )
{
gmac_enable_management( p_gmac, false );
phy_props.phy_result = -4;
return uc_rc;
}
ul_value |= GMII_SPEED_SELECT | GMII_AUTONEG | GMII_DUPLEX_MODE;
uc_rc = gmac_phy_write( p_gmac, uc_phy_addr, GMII_BMCR, ul_value );
if( uc_rc != GMAC_OK )
{
gmac_enable_management( p_gmac, false );
phy_props.phy_result = -5;
return uc_rc;
}
/* Restart auto negotiation */
ul_value |= ( uint32_t ) GMII_RESTART_AUTONEG;
ul_value &= ~( uint32_t ) GMII_ISOLATE;
uc_rc = gmac_phy_write( p_gmac, uc_phy_addr, GMII_BMCR, ul_value );
if( uc_rc != GMAC_OK )
{
gmac_enable_management( p_gmac, false );
phy_props.phy_result = -6;
return uc_rc;
}
/* Check if auto negotiation is completed */
while( 1 )
{
uc_rc = gmac_phy_read( p_gmac, uc_phy_addr, GMII_BMSR, &ul_value );
if( uc_rc != GMAC_OK )
{
gmac_enable_management( p_gmac, false );
phy_props.phy_result = -7;
return uc_rc;
}
/* Done successfully */
if( ul_value & GMII_AUTONEG_COMP )
{
break;
}
/* Timeout check */
if( ul_retry_max )
{
if( ++ul_retry_count >= ul_retry_max )
{
gmac_enable_management( p_gmac, false );
phy_props.phy_result = -8;
return GMAC_TIMEOUT;
}
}
}
/* Get the auto negotiate link partner base page */
uc_rc = gmac_phy_read( p_gmac, uc_phy_addr, GMII_PCR1, &phy_props.phy_params );
if( uc_rc != GMAC_OK )
{
gmac_enable_management( p_gmac, false );
phy_props.phy_result = -9;
return uc_rc;
}
/* Set up the GMAC link speed */
if( ( ul_phy_anar & phy_props.phy_params ) & GMII_100TX_FDX )
{
/* Set MII for 100BaseTX and Full Duplex */
uc_speed = true;
uc_fd = true;
}
else if( ( ul_phy_anar & phy_props.phy_params ) & GMII_10_FDX )
{
/* Set MII for 10BaseT and Full Duplex */
uc_speed = false;
uc_fd = true;
}
else if( ( ul_phy_anar & phy_props.phy_params ) & GMII_100TX_HDX )
{
/* Set MII for 100BaseTX and half Duplex */
uc_speed = true;
uc_fd = false;
}
else if( ( ul_phy_anar & phy_props.phy_params ) & GMII_10_HDX )
{
/* Set MII for 10BaseT and half Duplex */
uc_speed = false;
uc_fd = false;
}
gmac_set_speed( p_gmac, uc_speed );
gmac_enable_full_duplex( p_gmac, uc_fd );
/* Select Media Independent Interface type */
gmac_select_mii_mode( p_gmac, ETH_PHY_MODE );
gmac_enable_transmit( GMAC, true );
gmac_enable_receive( GMAC, true );
gmac_enable_management( p_gmac, false );
phy_props.phy_result = 1;
return uc_rc;
}
/**
* \brief Issue a SW reset to reset all registers of the PHY.
*
* \param p_gmac Pointer to the GMAC instance.
* \param uc_phy_addr PHY address.
*
* \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
*/
uint8_t ethernet_phy_reset( Gmac * p_gmac,
uint8_t uc_phy_addr )
{
uint32_t ul_bmcr = GMII_RESET;
uint8_t uc_phy_address = uc_phy_addr;
uint32_t ul_timeout = ETH_PHY_TIMEOUT;
uint8_t uc_rc = GMAC_TIMEOUT;
gmac_enable_management( p_gmac, true );
ul_bmcr = GMII_RESET;
gmac_phy_write( p_gmac, uc_phy_address, GMII_BMCR, ul_bmcr );
do
{
gmac_phy_read( p_gmac, uc_phy_address, GMII_BMCR, &ul_bmcr );
ul_timeout--;
} while( ( ul_bmcr & GMII_RESET ) && ul_timeout );
gmac_enable_management( p_gmac, false );
if( !ul_timeout )
{
uc_rc = GMAC_OK;
}
return( uc_rc );
}
/*/ @cond 0 */
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/*/ @endcond */
/**
* \}
*/

View File

@ -0,0 +1,287 @@
/**
* \file
*
* \brief KSZ8051MNL (Ethernet PHY) driver for SAM.
*
* Copyright (c) 2013 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* 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. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
*
* \asf_license_stop
*
*/
#ifndef ETHERNET_PHY_H_INCLUDED
#define ETHERNET_PHY_H_INCLUDED
#include "compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
/* IEEE defined Registers */
#define GMII_BMCR 0x00 /* Basic Control */
#define GMII_BMSR 0x01 /* Basic Status */
#define GMII_PHYID1 0x02 /* PHY Identifier 1 */
#define GMII_PHYID2 0x03 /* PHY Identifier 2 */
#define GMII_ANAR 0x04 /* Auto_Negotiation Advertisement */
#define GMII_ANLPAR 0x05 /* Auto_negotiation Link Partner Ability */
#define GMII_ANER 0x06 /* Auto-negotiation Expansion */
#define GMII_ANNPR 0x07 /* Auto-negotiation Next Page */
#define GMII_ANLPNPAR 0x08 /* Link Partner Next Page Ability */
/*#define GMII_1000BTCR 9 // 1000Base-T Control // Reserved */
/*#define GMII_1000BTSR 10 // 1000Base-T Status // Reserved */
#define GMII_AFECR1 0x11 /* AFE Control 1 */
/*#define GMII_ERDWR 12 // Extend Register - Data Write Register */
/*#define GMII_ERDRR 13 // Extend Register - Data Read Register */
/*14 reserved */
#define GMII_RXERCR 0x15 /* RXER Counter */
#define PHY_REG_01_BMSR 0x01 /* Basic mode status register */
#define PHY_REG_02_PHYSID1 0x02 /* PHYS ID 1 */
#define PHY_REG_03_PHYSID2 0x03 /* PHYS ID 2 */
#define PHY_REG_04_ADVERTISE 0x04 /* Advertisement control reg */
#define PHY_REG_05_LPA 0x05 /* Link partner ability reg */
#define PHY_REG_06_ANER 0x06 /* 6 RW Auto-Negotiation Expansion Register */
#define PHY_REG_07_ANNPTR 0x07 /* 7 RW Auto-Negotiation Next Page TX */
#define PHY_REG_08_RESERVED0 0x08 /* 0x08..0x0Fh 8-15 RW RESERVED */
#define PHY_REG_10_PHYSTS 0x10 /* 16 RO PHY Status Register */
#define PHY_REG_11_MICR 0x11 /* 17 RW MII Interrupt Control Register */
#define PHY_REG_12_MISR 0x12 /* 18 RO MII Interrupt Status Register */
#define PHY_REG_13_RESERVED1 0x13 /* 19 RW RESERVED */
#define PHY_REG_14_FCSCR 0x14 /* 20 RO False Carrier Sense Counter Register */
#define PHY_REG_15_RECR 0x15 /* 21 RO Receive Error Counter Register */
#define PHY_REG_16_PCSR 0x16 /* 22 RW PCS Sub-Layer Configuration and Status Register */
#define PHY_REG_17_RBR 0x17 /* 23 RW RMII and Bypass Register */
#define PHY_REG_18_LEDCR 0x18 /* 24 RW LED Direct Control Register */
#define PHY_REG_19_PHYCR 0x19 /* 25 RW PHY Control Register */
#define PHY_REG_1A_10BTSCR 0x1A /* 26 RW 10Base-T Status/Control Register */
#define PHY_REG_1B_CDCTRL1 0x1B /* 27 RW CD Test Control Register and BIST Extensions Register */
#define PHY_REG_1B_INT_CTRL 0x1B /* 27 RW KSZ8041NL interrupt control */
#define PHY_REG_1C_RESERVED2 0x1C /* 28 RW RESERVED */
#define PHY_REG_1D_EDCR 0x1D /* 29 RW Energy Detect Control Register */
#define PHY_REG_1E_RESERVED3 0x1E /* */
#define PHY_REG_1F_RESERVED4 0x1F /* 30-31 RW RESERVED */
#define PHY_REG_1E_PHYCR_1 0x1E /* */
#define PHY_REG_1F_PHYCR_2 0x1F /* */
#define PHY_SPEED_10 1
#define PHY_SPEED_100 2
#define PHY_SPEED_AUTO ( PHY_SPEED_10 | PHY_SPEED_100 )
#define PHY_MDIX_DIRECT 1
#define PHY_MDIX_CROSSED 2
#define PHY_MDIX_AUTO ( PHY_MDIX_CROSSED | PHY_MDIX_DIRECT )
#define PHY_DUPLEX_HALF 1
#define PHY_DUPLEX_FULL 2
#define PHY_DUPLEX_AUTO ( PHY_DUPLEX_FULL | PHY_DUPLEX_HALF )
typedef struct _SPhyProps
{
unsigned char speed;
unsigned char mdix;
unsigned char duplex;
unsigned char spare;
} SPhyProps;
const char * phyPrintable( const SPhyProps * apProps );
extern SPhyProps phyProps;
#define GMII_OMSOR 0x16 /* Operation Mode Strap Override */
#define GMII_OMSSR 0x17 /* Operation Mode Strap Status */
#define GMII_ECR 0x18 /* Expanded Control */
/*#define GMII_DPPSR 19 // Digital PMA/PCS Status */
/*20 reserved */
/*#define GMII_RXERCR 21 // RXER Counter Register */
/*22-26 reserved */
#define GMII_ICSR 0x1B /* Interrupt Control/Status */
/*#define GMII_DDC1R 28 // Digital Debug Control 1 Register */
#define GMII_LCSR 0x1D /* LinkMD Control/Status */
/*29-30 reserved */
#define GMII_PCR1 0x1E /* PHY Control 1 */
#define GMII_PCR2 0x1F /* PHY Control 2 */
/*
* //Extend Registers
#define GMII_CCR 256 // Common Control Register
#define GMII_SSR 257 // Strap Status Register
#define GMII_OMSOR 258 // Operation Mode Strap Override Register
#define GMII_OMSSR 259 // Operation Mode Strap Status Register
#define GMII_RCCPSR 260 // RGMII Clock and Control Pad Skew Register
#define GMII_RRDPSR 261 // RGMII RX Data Pad Skew Register
#define GMII_ATR 263 // Analog Test Register
*/
/* Bit definitions: GMII_BMCR 0x00 Basic Control */
#define GMII_RESET ( 1 << 15 ) /* 1= Software Reset; 0=Normal Operation */
#define GMII_LOOPBACK ( 1 << 14 ) /* 1=loopback Enabled; 0=Normal Operation */
#define GMII_SPEED_SELECT ( 1 << 13 ) /* 1=100Mbps; 0=10Mbps */
#define GMII_AUTONEG ( 1 << 12 ) /* Auto-negotiation Enable */
#define GMII_POWER_DOWN ( 1 << 11 ) /* 1=Power down 0=Normal operation */
#define GMII_ISOLATE ( 1 << 10 ) /* 1 = Isolates 0 = Normal operation */
#define GMII_RESTART_AUTONEG ( 1 << 9 ) /* 1 = Restart auto-negotiation 0 = Normal operation */
#define GMII_DUPLEX_MODE ( 1 << 8 ) /* 1 = Full duplex operation 0 = Normal operation */
#define GMII_COLLISION_TEST ( 1 << 7 ) /* 1 = Enable COL test; 0 = Disable COL test */
/*#define GMII_SPEED_SELECT_MSB (1 << 6) // Reserved */
/* Reserved 6 to 0 // Read as 0, ignore on write */
/* Bit definitions: GMII_BMSR 0x01 Basic Status */
#define GMII_100BASE_T4 ( 1 << 15 ) /* 100BASE-T4 Capable */
#define GMII_100BASE_TX_FD ( 1 << 14 ) /* 100BASE-TX Full Duplex Capable */
#define GMII_100BASE_T4_HD ( 1 << 13 ) /* 100BASE-TX Half Duplex Capable */
#define GMII_10BASE_T_FD ( 1 << 12 ) /* 10BASE-T Full Duplex Capable */
#define GMII_10BASE_T_HD ( 1 << 11 ) /* 10BASE-T Half Duplex Capable */
/* Reserved 10 to79 // Read as 0, ignore on write */
/*#define GMII_EXTEND_STATUS (1 << 8) // 1 = Extend Status Information In Reg 15 */
/* Reserved 7 */
#define GMII_MF_PREAMB_SUPPR ( 1 << 6 ) /* MII Frame Preamble Suppression */
#define GMII_AUTONEG_COMP ( 1 << 5 ) /* Auto-negotiation Complete */
#define GMII_REMOTE_FAULT ( 1 << 4 ) /* Remote Fault */
#define GMII_AUTONEG_ABILITY ( 1 << 3 ) /* Auto Configuration Ability */
#define GMII_LINK_STATUS ( 1 << 2 ) /* Link Status */
#define GMII_JABBER_DETECT ( 1 << 1 ) /* Jabber Detect */
#define GMII_EXTEND_CAPAB ( 1 << 0 ) /* Extended Capability */
/* Bit definitions: GMII_PHYID1 0x02 PHY Identifier 1 */
/* Bit definitions: GMII_PHYID2 0x03 PHY Identifier 2 */
#define GMII_LSB_MASK 0x3F
#define GMII_OUI_MSB 0x0022
#define GMII_OUI_LSB 0x05
/* Bit definitions: GMII_ANAR 0x04 Auto_Negotiation Advertisement */
/* Bit definitions: GMII_ANLPAR 0x05 Auto_negotiation Link Partner Ability */
#define GMII_NP ( 1 << 15 ) /* Next page Indication */
/* Reserved 7 */
#define GMII_RF ( 1 << 13 ) /* Remote Fault */
/* Reserved 12 // Write as 0, ignore on read */
#define GMII_PAUSE_MASK ( 3 << 11 ) /* 0,0 = No Pause 1,0 = Asymmetric Pause(link partner) */
/* 0,1 = Symmetric Pause 1,1 = Symmetric&Asymmetric Pause(local device) */
#define GMII_100T4 ( 1 << 9 ) /* 100BASE-T4 Support */
#define GMII_100TX_FDX ( 1 << 8 ) /* 100BASE-TX Full Duplex Support */
#define GMII_100TX_HDX ( 1 << 7 ) /* 100BASE-TX Support */
#define GMII_10_FDX ( 1 << 6 ) /* 10BASE-T Full Duplex Support */
#define GMII_10_HDX ( 1 << 5 ) /* 10BASE-T Support */
/* Selector 4 to 0 // Protocol Selection Bits */
#define GMII_AN_IEEE_802_3 0x0001 /* [00001] = IEEE 802.3 */
/* Bit definitions: GMII_ANER 0x06 Auto-negotiation Expansion */
/* Reserved 15 to 5 // Read as 0, ignore on write */
#define GMII_PDF ( 1 << 4 ) /* Local Device Parallel Detection Fault */
#define GMII_LP_NP_ABLE ( 1 << 3 ) /* Link Partner Next Page Able */
#define GMII_NP_ABLE ( 1 << 2 ) /* Local Device Next Page Able */
#define GMII_PAGE_RX ( 1 << 1 ) /* New Page Received */
#define GMII_LP_AN_ABLE ( 1 << 0 ) /* Link Partner Auto-negotiation Able */
/**
* \brief Perform a HW initialization to the PHY and set up clocks.
*
* This should be called only once to initialize the PHY pre-settings.
* The PHY address is the reset status of CRS, RXD[3:0] (the GmacPins' pullups).
* The COL pin is used to select MII mode on reset (pulled up for Reduced MII).
* The RXDV pin is used to select test mode on reset (pulled up for test mode).
* The above pins should be predefined for corresponding settings in resetPins.
* The GMAC peripheral pins are configured after the reset is done.
*
* \param p_gmac Pointer to the GMAC instance.
* \param uc_phy_addr PHY address.
* \param ul_mck GMAC MCK.
*
* Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
*/
uint8_t ethernet_phy_init( Gmac * p_gmac,
uint8_t uc_phy_addr,
uint32_t ul_mck );
/**
* \brief Get the Link & speed settings, and automatically set up the GMAC with the
* settings.
*
* \param p_gmac Pointer to the GMAC instance.
* \param uc_phy_addr PHY address.
* \param uc_apply_setting_flag Set to 0 to not apply the PHY configurations, else to apply.
*
* Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
*/
uint8_t ethernet_phy_set_link( Gmac * p_gmac,
uint8_t uc_phy_addr,
uint8_t uc_apply_setting_flag );
/**
* \brief Issue an auto negotiation of the PHY.
*
* \param p_gmac Pointer to the GMAC instance.
* \param uc_phy_addr PHY address.
*
* Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
*/
uint8_t ethernet_phy_auto_negotiate( Gmac * p_gmac,
uint8_t uc_phy_addr );
/**
* \brief Issue a SW reset to reset all registers of the PHY.
*
* \param p_gmac Pointer to the GMAC instance.
* \param uc_phy_addr PHY address.
*
* \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
*/
uint8_t ethernet_phy_reset( Gmac * p_gmac,
uint8_t uc_phy_addr );
typedef struct xPHY_PROPS
{
signed char phy_result;
uint32_t phy_params;
uint32_t phy_stat1;
uint32_t phy_stat2;
unsigned char phy_chn;
} PhyProps_t;
extern PhyProps_t phy_props;
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* #ifndef ETHERNET_PHY_H_INCLUDED */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,574 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/* This driver is made to work with Atmel START's ASF4 GMAC driver.
* The START generated GMAC initialization code should be commented out,
* since this driver will take care of initializing the GMAC peripheral itself.
*
* Optimal performance is obtained with:
* - CRC offloading enabled for both RX and TX
* - "Copy all frames" set to zero / off
*/
/* Atmel ASF includes */
#include "hal_mac_async.h"
#include "hpl_gmac_config.h"
/* Include MAC initialization function here: */
#include "driver_init.h"
/* FreeRTOS includes */
#include "FreeRTOS.h"
#include "task.h"
/* FreeRTOS+TCP includes */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_IP_Private.h"
#include "NetworkBufferManagement.h"
#include "phyHandling.h"
/***********************************************/
/* Configuration variables */
/***********************************************/
/* Check for optimal performance parameters */
#if ( CONF_GMAC_NCFGR_RXCOEN == 0 )
#warning This driver works best with RX CRC offloading enabled.
#endif
#if ( CONF_GMAC_DCFGR_TXCOEN == 0 )
#warning This driver works best with TX CRC offloading enabled.
#endif
#if ( CONF_GMAC_NCFGR_CAF != 0 )
#warning This driver includes GMAC hardware frame filtering for better performance.
#endif
/* Make sure someone takes care of the CRC calculation */
#if ( ( CONF_GMAC_NCFGR_RXCOEN == 0 ) && ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 ) )
#error Receive CRC offloading should be enabled.
#endif
#if ( ( CONF_GMAC_DCFGR_TXCOEN == 0 ) && ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) )
#error Transmit CRC offloading should be enabled.
#endif
/* Setup LLMNR specific multicast address. */
#if ( defined( ipconfigUSE_LLMNR ) && ( ipconfigUSE_LLMNR == 1 ) )
static const uint8_t ucLLMNR_MAC_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
#endif
/* Receive task refresh time */
#define RECEIVE_BLOCK_TIME_MS 100
/***********************************************/
/* FreeRTOS variables */
/***********************************************/
/* Copied from FreeRTOS_IP.c. Used for ICMP CRC calculation */
#define ipCORRECT_CRC 0xffffU
/* Also copied from FreeRTOS_IP.c */
/** @brief 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. In this case ipCONSIDER_FRAME_FOR_PROCESSING() can
* be #-defined away. If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0
* then the Ethernet driver will pass all received packets to the stack, and the
* stack must do the filtering itself. In this case ipCONSIDER_FRAME_FOR_PROCESSING
* needs to call eConsiderFrameForProcessing.
*/
#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
#else
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
#endif
/* Ethernet buffers for BufferAllocation_1.c scheme.
* Set ipUSE_STATIC_ALLOCATION to 1 if using BufferAllocation_1.c,
* otherwise to 0, to save RAM. From Iperf testing, there is no point in using
* static allocation with a non zero-copy driver.
*/
#define ipUSE_STATIC_ALLOCATION 0
#if ( defined( ipUSE_STATIC_ALLOCATION ) && ( ipUSE_STATIC_ALLOCATION == 1 ) )
/* 1536 bytes is more than needed, 1524 would be enough.
* But 1536 is a multiple of 32, which gives a great alignment for cached memories. */
#define NETWORK_BUFFER_SIZE 1536
static uint8_t ucBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ][ NETWORK_BUFFER_SIZE ];
#endif /* ( defined( ipUSE_STATIC_ALLOCATION ) && ( ipUSE_STATIC_ALLOCATION == 1 )) */
/* Holds the handle of the task used as a deferred interrupt processor. The
* handle is used so direct notifications can be sent to the task for all EMAC/DMA
* related interrupts. */
TaskHandle_t xEMACTaskHandle = NULL;
/* The PING response queue */
#if ( defined( ipconfigSUPPORT_OUTGOING_PINGS ) && ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) )
QueueHandle_t xPingReplyQueue = NULL;
#endif
/* GMAC interrupt callbacks. */
void xRxCallback( void );
static void prvEMACDeferredInterruptHandlerTask( void * pvParameters );
/***********************************************/
/* GMAC variables */
/***********************************************/
/* The Ethernet MAC instance created by ASF4 */
extern struct mac_async_descriptor ETH_MAC;
static void prvGMACInit( void );
/* Enable/Disable MDC and MDIO ports for PHY register management. */
static inline void prvGMACEnablePHYManagementPort( bool enable );
/* GMAC registers configuration functions. */
static inline void prvGMACEnable100Mbps( bool enable );
static inline void prvGMACEnableFullDuplex( bool enable );
/***********************************************/
/* PHY variables */
/***********************************************/
/* All PHY handling code has now been separated from the NetworkInterface.c,
* see "../Common/phyHandling.c". */
static EthernetPhy_t xPhyObject;
/* PHY link preferences. */
/* Set both speed and Duplex to AUTO, or give them BOTH manual values. */
const PhyProperties_t xPHYProperties =
{
.ucSpeed = PHY_SPEED_AUTO,
.ucDuplex = PHY_DUPLEX_AUTO,
.ucMDI_X = PHY_MDIX_AUTO,
};
static void prvPHYLinkReset( void );
static void prvPHYInit( void );
static inline bool bPHYGetLinkStatus( void );
/* PHY read and write functions. */
static BaseType_t xPHYRead( BaseType_t xAddress,
BaseType_t xRegister,
uint32_t * pulValue );
static BaseType_t xPHYWrite( BaseType_t xAddress,
BaseType_t xRegister,
uint32_t pulValue );
/*********************************************************************/
/* FreeRTOS+TCP functions */
/*********************************************************************/
BaseType_t xNetworkInterfaceInitialise( void )
{
/*
* Perform the hardware specific network initialization here. Typically
* that will involve using the Ethernet driver library to initialize the
* Ethernet (or other network) hardware, initialize DMA descriptors, and
* perform a PHY auto-negotiation to obtain a network link. */
if( xEMACTaskHandle == NULL )
{
/* Initialize MAC and PHY */
prvGMACInit();
prvPHYInit();
/* (Re)set PHY link */
prvPHYLinkReset();
/* Initialize PING capability */
#if ( defined( ipconfigSUPPORT_OUTGOING_PINGS ) && ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) )
xPingReplyQueue = xQueueCreate( ipconfigPING_QUEUE_SIZE, sizeof( uint16_t ) );
#endif
/* Create event handler task */
xTaskCreate( prvEMACDeferredInterruptHandlerTask, /* Function that implements the task. */
"EMACInt", /* Text name for the task. */
256, /* Stack size in words, not bytes. */
( void * ) 1, /* Parameter passed into the task. */
configMAX_PRIORITIES - 1, /* Priority at which the task is created. */
&xEMACTaskHandle ); /* Used to pass out the created task's handle. */
configASSERT( xEMACTaskHandle );
}
return bPHYGetLinkStatus();
}
static void prvEMACDeferredInterruptHandlerTask( void * pvParameters )
{
NetworkBufferDescriptor_t * pxBufferDescriptor;
size_t xBytesReceived = 0, xBytesRead = 0;
uint16_t xICMPChecksumResult = ipCORRECT_CRC;
const IPPacket_t * pxIPPacket;
/* Used to indicate that xSendEventStructToIPTask() is being called because
* of an Ethernet receive event. */
IPStackEvent_t xRxEvent;
for( ; ; )
{
/* Wait for the Ethernet MAC interrupt to indicate that another packet
* has been received. The task notification is used in a similar way to a
* counting semaphore to count Rx events, but is a lot more efficient than
* a semaphore. */
ulTaskNotifyTake( pdFALSE, pdMS_TO_TICKS( RECEIVE_BLOCK_TIME_MS ) );
/* See how much data was received. Here it is assumed ReceiveSize() is
* a peripheral driver function that returns the number of bytes in the
* received Ethernet frame. */
xBytesReceived = mac_async_read_len( &ETH_MAC );
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( 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. */
xBytesRead = mac_async_read( &ETH_MAC, pxBufferDescriptor->pucEthernetBuffer, xBytesReceived );
pxBufferDescriptor->xDataLength = xBytesRead;
#if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 )
{
/* the Atmel SAM GMAC peripheral does not support hardware CRC offloading for ICMP packets.
* It must therefore be implemented in software. */
pxIPPacket = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( IPPacket_t, pxBufferDescriptor->pucEthernetBuffer );
if( pxIPPacket->xIPHeader.ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )
{
xICMPChecksumResult = usGenerateProtocolChecksum( pxBufferDescriptor->pucEthernetBuffer, pxBufferDescriptor->xDataLength, pdFALSE );
}
else
{
xICMPChecksumResult = ipCORRECT_CRC; /* Reset the result value in case this is not an ICMP packet. */
}
}
#endif /* if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) */
/* 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( ( ipCONSIDER_FRAME_FOR_PROCESSING( pxBufferDescriptor->pucEthernetBuffer ) == eProcessBuffer ) &&
( xICMPChecksumResult == ipCORRECT_CRC ) )
{
/* 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();
}
}
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();
}
}
prvGMACEnablePHYManagementPort( true );
if( xPhyCheckLinkStatus( &xPhyObject, xBytesReceived ) )
{
prvPHYLinkReset();
}
prvGMACEnablePHYManagementPort( false );
}
}
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor,
BaseType_t xReleaseAfterSend )
{
/* 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( bPHYGetLinkStatus() )
{
#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 )
{
/* the Atmel SAM GMAC peripheral does not support hardware CRC offloading for ICMP packets.
* It must therefore be implemented in software. */
const IPPacket_t * pxIPPacket = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( IPPacket_t, pxDescriptor->pucEthernetBuffer );
if( pxIPPacket->xIPHeader.ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )
{
( void ) usGenerateProtocolChecksum( pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, pdTRUE );
}
}
#endif
mac_async_write( &ETH_MAC, pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength );
/* 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 );
}
return pdTRUE;
}
void xRxCallback( void )
{
vTaskNotifyGiveFromISR( xEMACTaskHandle, 0 );
}
#if ( defined( ipUSE_STATIC_ALLOCATION ) && ( ipUSE_STATIC_ALLOCATION == 1 ) )
/* Next provide the vNetworkInterfaceAllocateRAMToBuffers() function, which
* simply fills in the pucEthernetBuffer member of each descriptor. */
void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
{
BaseType_t x;
for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
{
/* pucEthernetBuffer is set to point ipBUFFER_PADDING bytes in from the
* beginning of the allocated buffer. */
pxNetworkBuffers[ x ].pucEthernetBuffer = &( ucBuffers[ x ][ ipBUFFER_PADDING ] );
/* The following line is also required, but will not be required in
* future versions. */
*( ( uint32_t * ) &ucBuffers[ x ][ 0 ] ) = ( uint32_t ) &( pxNetworkBuffers[ x ] );
}
}
#endif /* ( defined( ipUSE_STATIC_ALLOCATION ) && ( ipUSE_STATIC_ALLOCATION == 1 )) */
/*********************************************************************/
/* GMAC functions */
/*********************************************************************/
/* Initializes the GMAC peripheral. This function is based on ASF4 GMAC initialization
* and uses the Atmel START- generated code, typically located in "driver_init.h".
* Make sure the initialization function is not called twice, e.g. comment out the call in "driver_init.c".
* It is compatible with modifications made in Atmel START afterwards because the
* configuration is saved in "hpl_gmac_config.h". */
static void prvGMACInit()
{
/* Call MAC initialization function here: */
vGMACInit();
prvGMACEnablePHYManagementPort( false );
mac_async_disable_irq( &ETH_MAC );
/* Set GMAC Filtering for own MAC address */
struct mac_async_filter mac_filter;
memcpy( mac_filter.mac, ipLOCAL_MAC_ADDRESS, ipMAC_ADDRESS_LENGTH_BYTES );
mac_filter.tid_enable = false;
mac_async_set_filter( &ETH_MAC, 0, &mac_filter );
/* Set GMAC filtering for LLMNR, if defined. */
#if ( defined( ipconfigUSE_LLMNR ) && ( ipconfigUSE_LLMNR == 1 ) )
{
memcpy( mac_filter.mac, ucLLMNR_MAC_address, ipMAC_ADDRESS_LENGTH_BYTES );
/* LLMNR requires responders to listen to both TCP and UDP protocols. */
mac_filter.tid_enable = false;
mac_async_set_filter( &ETH_MAC, 1, &mac_filter );
}
#endif
/* Set GMAC interrupt priority to be compatible with FreeRTOS API */
NVIC_SetPriority( GMAC_IRQn, configMAX_SYSCALL_INTERRUPT_PRIORITY >> ( 8 - configPRIO_BITS ) );
/* Register callback(s). Currently only RX callback is implemented, but TX callback can be added the same way. */
mac_async_register_callback( &ETH_MAC, MAC_ASYNC_RECEIVE_CB, ( FUNC_PTR ) xRxCallback );
/* Start the GMAC. */
mac_async_enable( &ETH_MAC );
mac_async_enable_irq( &ETH_MAC );
}
static inline void prvGMACEnablePHYManagementPort( bool enable )
{
if( enable )
{
( ( Gmac * ) ETH_MAC.dev.hw )->NCR.reg |= GMAC_NCR_MPE;
}
else
{
( ( Gmac * ) ETH_MAC.dev.hw )->NCR.reg &= ~GMAC_NCR_MPE;
}
}
static inline void prvGMACEnable100Mbps( bool enable )
{
if( enable )
{
( ( Gmac * ) ETH_MAC.dev.hw )->NCFGR.reg |= GMAC_NCFGR_SPD;
}
else
{
( ( Gmac * ) ETH_MAC.dev.hw )->NCFGR.reg &= ~GMAC_NCFGR_SPD;
}
}
static inline void prvGMACEnableFullDuplex( bool enable )
{
if( enable )
{
( ( Gmac * ) ETH_MAC.dev.hw )->NCFGR.reg |= GMAC_NCFGR_FD;
}
else
{
( ( Gmac * ) ETH_MAC.dev.hw )->NCFGR.reg &= ~GMAC_NCFGR_FD;
}
}
/*********************************************************************/
/* PHY functions */
/*********************************************************************/
/* Initializes the PHY hardware. Based on ASF4 generated code. */
static void prvPHYInit()
{
prvGMACEnablePHYManagementPort( true );
vPhyInitialise( &xPhyObject, &xPHYRead, &xPHYWrite );
xPhyDiscover( &xPhyObject );
xPhyConfigure( &xPhyObject, &xPHYProperties );
prvGMACEnablePHYManagementPort( false );
}
/* Start a new link negotiation on the PHY and wait until link is up. */
static void prvPHYLinkReset()
{
/* Restart an auto-negotiation */
prvGMACEnablePHYManagementPort( true );
if( ( xPHYProperties.ucDuplex == PHY_DUPLEX_AUTO ) && ( xPHYProperties.ucSpeed == PHY_SPEED_AUTO ) && ( xPHYProperties.ucMDI_X == PHY_MDIX_AUTO ) )
{
/* Auto-negotiation */
xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) );
/* Update the MAC with the auto-negotiation result parameters. */
prvGMACEnableFullDuplex( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL );
prvGMACEnable100Mbps( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_100 );
}
else
{
/* Fixed values */
xPhyObject.xPhyPreferences.ucDuplex = xPHYProperties.ucDuplex;
xPhyObject.xPhyPreferences.ucSpeed = xPHYProperties.ucSpeed;
xPhyObject.xPhyPreferences.ucMDI_X = xPHYProperties.ucMDI_X;
xPhyFixedValue( &xPhyObject, xPhyGetMask( &xPhyObject ) );
/* Update the MAC with the auto-negotiation result parameters. */
prvGMACEnableFullDuplex( xPHYProperties.ucDuplex == PHY_DUPLEX_FULL );
prvGMACEnable100Mbps( xPHYProperties.ucSpeed == PHY_SPEED_100 );
}
prvGMACEnablePHYManagementPort( false );
}
static BaseType_t xPHYRead( BaseType_t xAddress,
BaseType_t xRegister,
uint32_t * pulValue )
{
prvGMACEnablePHYManagementPort( true );
BaseType_t readStatus = mac_async_read_phy_reg( &ETH_MAC, xAddress, xRegister, ( ( uint16_t * ) pulValue ) );
prvGMACEnablePHYManagementPort( false );
return readStatus;
}
static BaseType_t xPHYWrite( BaseType_t xAddress,
BaseType_t xRegister,
uint32_t pulValue )
{
prvGMACEnablePHYManagementPort( true );
BaseType_t writeStatus = mac_async_write_phy_reg( &ETH_MAC, xAddress, xRegister, pulValue );
prvGMACEnablePHYManagementPort( false );
return writeStatus;
}
static inline bool bPHYGetLinkStatus( void )
{
return( xPhyObject.ulLinkStatusMask != 0 );
}

View File

@ -0,0 +1,827 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @brief
* Handling of Ethernet PHY's
* PHY's communicate with an EMAC either through
* a Media-Independent Interface (MII), or a Reduced Media-Independent Interface (RMII).
* The EMAC can poll for PHY ports on 32 different addresses. Each of the PHY ports
* shall be treated independently.
*
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "phyHandling.h"
#define phyMIN_PHY_ADDRESS 0
#define phyMAX_PHY_ADDRESS 31
#if defined( PHY_LS_HIGH_CHECK_TIME_MS ) || defined( PHY_LS_LOW_CHECK_TIME_MS )
#warning please use the new defines with 'ipconfig' prefix
#endif
#ifndef ipconfigPHY_LS_HIGH_CHECK_TIME_MS
/* Check if the LinkStatus in the PHY is still high after 15 seconds of not
* receiving packets. */
#define ipconfigPHY_LS_HIGH_CHECK_TIME_MS 15000U
#endif
#ifndef ipconfigPHY_LS_LOW_CHECK_TIME_MS
/* Check if the LinkStatus in the PHY is still low every second. */
#define ipconfigPHY_LS_LOW_CHECK_TIME_MS 1000U
#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 1000U
#endif
#ifndef phyPHY_MAX_NEGOTIATE_TIME_MS
#define phyPHY_MAX_NEGOTIATE_TIME_MS 3000U
#endif
#ifndef phySHORT_DELAY_MS
#define phySHORT_DELAY_MS 50U
#endif
/* Naming and numbering of basic PHY registers. */
#define phyREG_00_BMCR 0x00U /* Basic Mode Control Register. */
#define phyREG_01_BMSR 0x01U /* Basic Mode Status Register. */
#define phyREG_02_PHYSID1 0x02U /* PHYS ID 1 */
#define phyREG_03_PHYSID2 0x03U /* PHYS ID 2 */
#define phyREG_04_ADVERTISE 0x04U /* Advertisement control reg */
/* Naming and numbering of extended PHY registers. */
#define PHYREG_10_PHYSTS 0x10U /* 16 PHY status register Offset */
#define phyREG_19_PHYCR 0x19U /* 25 RW PHY Control Register */
#define phyREG_1F_PHYSPCS 0x1FU /* 31 RW PHY Special Control Status */
/* Bit fields for 'phyREG_00_BMCR', the 'Basic Mode Control Register'. */
#define phyBMCR_FULL_DUPLEX 0x0100U /* Full duplex. */
#define phyBMCR_AN_RESTART 0x0200U /* Auto negotiation restart. */
#define phyBMCR_ISOLATE 0x0400U /* 1 = Isolates 0 = Normal operation. */
#define phyBMCR_AN_ENABLE 0x1000U /* Enable auto negotiation. */
#define phyBMCR_SPEED_100 0x2000U /* Select 100Mbps. */
#define phyBMCR_RESET 0x8000U /* Reset the PHY. */
/* Bit fields for 'phyREG_19_PHYCR', the 'PHY Control Register'. */
#define PHYCR_MDIX_EN 0x8000U /* Enable Auto MDIX. */
#define PHYCR_MDIX_FORCE 0x4000U /* Force MDIX crossed. */
#define phyBMSR_AN_COMPLETE 0x0020U /* Auto-Negotiation process completed */
#define phyBMSR_LINK_STATUS 0x0004U
#define phyPHYSTS_LINK_STATUS 0x0001U /* PHY Link mask */
#define phyPHYSTS_SPEED_STATUS 0x0002U /* PHY Speed mask */
#define phyPHYSTS_DUPLEX_STATUS 0x0004U /* PHY Duplex mask */
/* Bit fields for 'phyREG_1F_PHYSPCS
* 001 = 10BASE-T half-duplex
* 101 = 10BASE-T full-duplex
* 010 = 100BASE-TX half-duplex
* 110 = 100BASE-TX full-duplex
*/
#define phyPHYSPCS_SPEED_MASK 0x000CU
#define phyPHYSPCS_SPEED_10 0x0004U
#define phyPHYSPCS_FULL_DUPLEX 0x0010U
/*
* Description of all capabilities that can be advertised to
* the peer (usually a switch or router).
*/
#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_CSMA )
/* 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 )
{
BaseType_t xResult = pdFALSE;
switch( ulPhyID )
{
case PHY_ID_LAN8720:
case PHY_ID_LAN8742A:
case PHY_ID_KSZ8041:
/*
* case PHY_ID_KSZ8051: // same ID as 8041
* case PHY_ID_KSZ8081: // same ID as 8041
*/
case PHY_ID_KSZ8081MNXIA:
case PHY_ID_KSZ8863:
default:
/* Most PHY's have a 1F_PHYSPCS */
xResult = pdTRUE;
break;
case PHY_ID_DP83848I:
case PHY_ID_DP83TC811S:
case PHY_ID_TM4C129X:
case PHY_ID_MV88E6071:
/* Has no 0x1F register "PHY Special Control Status". */
break;
}
return xResult;
}
/*-----------------------------------------------------------*/
static BaseType_t xHas_19_PHYCR( uint32_t ulPhyID )
{
BaseType_t xResult = pdFALSE;
switch( ulPhyID )
{
case PHY_ID_LAN8742A:
case PHY_ID_DP83848I:
case PHY_ID_TM4C129X:
xResult = pdTRUE;
break;
case PHY_ID_MV88E6071: /* Marvell 88E6071 */
default:
/* Most PHY's do not have a 19_PHYCR */
break;
}
return xResult;
}
/*-----------------------------------------------------------*/
/* Initialise the struct and assign a PHY-read and -write function. */
void vPhyInitialise( EthernetPhy_t * pxPhyObject,
xApplicationPhyReadHook_t fnPhyRead,
xApplicationPhyWriteHook_t fnPhyWrite )
{
memset( ( void * ) pxPhyObject, 0, sizeof( *pxPhyObject ) );
pxPhyObject->fnPhyRead = fnPhyRead;
pxPhyObject->fnPhyWrite = fnPhyWrite;
}
/*-----------------------------------------------------------*/
/* Discover all PHY's connected by polling 32 indexes ( zero-based ) */
BaseType_t xPhyDiscover( EthernetPhy_t * pxPhyObject )
{
BaseType_t xPhyAddress;
pxPhyObject->xPortCount = 0;
for( xPhyAddress = phyMIN_PHY_ADDRESS; xPhyAddress <= phyMAX_PHY_ADDRESS; xPhyAddress++ )
{
uint32_t ulLowerID = 0U;
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_03_PHYSID2, &ulLowerID );
/* A valid PHY id can not be all zeros or all ones. */
if( ( ulLowerID != ( uint16_t ) ~0U ) && ( ulLowerID != ( uint16_t ) 0U ) )
{
uint32_t ulUpperID;
uint32_t ulPhyID;
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_02_PHYSID1, &ulUpperID );
ulPhyID = ( ( ( uint32_t ) ulUpperID ) << 16 ) | ( ulLowerID & 0xFFF0U );
pxPhyObject->ucPhyIndexes[ pxPhyObject->xPortCount ] = xPhyAddress;
pxPhyObject->ulPhyIDs[ pxPhyObject->xPortCount ] = ulPhyID;
pxPhyObject->xPortCount++;
/* See if there is more storage space. */
if( pxPhyObject->xPortCount == ipconfigPHY_MAX_PORTS )
{
break;
}
}
}
if( pxPhyObject->xPortCount > 0 )
{
FreeRTOS_printf( ( "PHY ID %lX\n", pxPhyObject->ulPhyIDs[ 0 ] ) );
}
return pxPhyObject->xPortCount;
}
/*-----------------------------------------------------------*/
/* Send a reset command to a set of PHY-ports. */
static uint32_t xPhyReset( EthernetPhy_t * pxPhyObject,
uint32_t ulPhyMask )
{
uint32_t ulDoneMask, ulConfig;
TickType_t xRemainingTime;
TimeOut_t xTimer;
BaseType_t xPhyIndex;
/* A bit-mask of PHY ports that are ready. */
ulDoneMask = 0U;
/* Set the RESET bits high. */
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
/* Read Control register. */
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulConfig | phyBMCR_RESET );
}
xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( phyPHY_MAX_RESET_TIME_MS );
vTaskSetTimeOutState( &xTimer );
/* The reset should last less than a second. */
for( ; ; )
{
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
if( ( ulConfig & phyBMCR_RESET ) == 0 )
{
FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET %d ready\n", ( int ) xPhyIndex ) );
ulDoneMask |= ( 1U << xPhyIndex );
}
}
if( ulDoneMask == ulPhyMask )
{
break;
}
if( xTaskCheckForTimeOut( &xTimer, &xRemainingTime ) != pdFALSE )
{
FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET timed out ( done 0x%02lX )\n", ulDoneMask ) );
break;
}
/* Block for a while */
vTaskDelay( pdMS_TO_TICKS( phySHORT_DELAY_MS ) );
}
/* Clear the reset bits. */
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
{
if( ( ulDoneMask & ( 1U << xPhyIndex ) ) == 0U )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
/* 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( phySHORT_DELAY_MS ) );
return ulDoneMask;
}
/*-----------------------------------------------------------*/
BaseType_t xPhyConfigure( EthernetPhy_t * pxPhyObject,
const PhyProperties_t * pxPhyProperties )
{
uint32_t ulConfig, ulAdvertise;
BaseType_t xPhyIndex;
if( pxPhyObject->xPortCount < 1 )
{
FreeRTOS_printf( ( "xPhyConfigure: No PHY's detected.\n" ) );
return -1;
}
/* The expected ID for the 'LAN8742A' is 0x0007c130. */
/* The expected ID for the 'LAN8720' is 0x0007c0f0. */
/* The expected ID for the 'DP83848I' is 0x20005C90. */
/* Set advertise register. */
if( ( pxPhyProperties->ucSpeed == ( uint8_t ) PHY_SPEED_AUTO ) && ( pxPhyProperties->ucDuplex == ( uint8_t ) PHY_DUPLEX_AUTO ) )
{
ulAdvertise = phyADVERTISE_ALL;
/* Reset auto-negotiation capability. */
}
else
{
/* Always select protocol 802.3u. */
ulAdvertise = phyADVERTISE_CSMA;
if( pxPhyProperties->ucSpeed == ( uint8_t ) PHY_SPEED_AUTO )
{
if( pxPhyProperties->ucDuplex == ( uint8_t ) PHY_DUPLEX_FULL )
{
ulAdvertise |= phyADVERTISE_10FULL | phyADVERTISE_100FULL;
}
else
{
ulAdvertise |= phyADVERTISE_10HALF | phyADVERTISE_100HALF;
}
}
else if( pxPhyProperties->ucDuplex == ( uint8_t ) PHY_DUPLEX_AUTO )
{
if( pxPhyProperties->ucSpeed == ( uint8_t ) PHY_SPEED_10 )
{
ulAdvertise |= phyADVERTISE_10FULL | phyADVERTISE_10HALF;
}
else
{
ulAdvertise |= phyADVERTISE_100FULL | phyADVERTISE_100HALF;
}
}
else if( pxPhyProperties->ucSpeed == ( uint8_t ) PHY_SPEED_100 )
{
if( pxPhyProperties->ucDuplex == ( uint8_t ) PHY_DUPLEX_FULL )
{
ulAdvertise |= phyADVERTISE_100FULL;
}
else
{
ulAdvertise |= phyADVERTISE_100HALF;
}
}
else
{
if( pxPhyProperties->ucDuplex == ( uint8_t ) PHY_DUPLEX_FULL )
{
ulAdvertise |= phyADVERTISE_10FULL;
}
else
{
ulAdvertise |= phyADVERTISE_10HALF;
}
}
}
/* Send a reset command to a set of PHY-ports. */
xPhyReset( pxPhyObject, xPhyGetMask( pxPhyObject ) );
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ];
/* Write advertise register. */
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_04_ADVERTISE, ulAdvertise );
/*
* AN_EN AN1 AN0 Forced Mode
* 0 0 0 10BASE-T, Half-Duplex
* 0 0 1 10BASE-T, Full-Duplex
* 0 1 0 100BASE-TX, Half-Duplex
* 0 1 1 100BASE-TX, Full-Duplex
* AN_EN AN1 AN0 Advertised Mode
* 1 0 0 10BASE-T, Half/Full-Duplex
* 1 0 1 100BASE-TX, Half/Full-Duplex
* 1 1 0 10BASE-T Half-Duplex
* 100BASE-TX, Half-Duplex
* 1 1 1 10BASE-T, Half/Full-Duplex
* 100BASE-TX, Half/Full-Duplex
*/
/* Read Control register. */
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
ulConfig &= ~( phyBMCR_SPEED_100 | phyBMCR_FULL_DUPLEX );
ulConfig |= phyBMCR_AN_ENABLE;
if( ( pxPhyProperties->ucSpeed == ( uint8_t ) PHY_SPEED_100 ) || ( pxPhyProperties->ucSpeed == ( uint8_t ) PHY_SPEED_AUTO ) )
{
ulConfig |= phyBMCR_SPEED_100;
}
else if( pxPhyProperties->ucSpeed == ( uint8_t ) PHY_SPEED_10 )
{
ulConfig &= ~phyBMCR_SPEED_100;
}
if( ( pxPhyProperties->ucDuplex == ( uint8_t ) PHY_DUPLEX_FULL ) || ( pxPhyProperties->ucDuplex == ( uint8_t ) PHY_DUPLEX_AUTO ) )
{
ulConfig |= phyBMCR_FULL_DUPLEX;
}
else if( pxPhyProperties->ucDuplex == ( uint8_t ) PHY_DUPLEX_HALF )
{
ulConfig &= ~phyBMCR_FULL_DUPLEX;
}
if( xHas_19_PHYCR( ulPhyID ) )
{
uint32_t ulPhyControl;
/* Read PHY Control register. */
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_19_PHYCR, &ulPhyControl );
/* Clear bits which might get set: */
ulPhyControl &= ~( PHYCR_MDIX_EN | PHYCR_MDIX_FORCE );
if( pxPhyProperties->ucMDI_X == PHY_MDIX_AUTO )
{
ulPhyControl |= PHYCR_MDIX_EN;
}
else if( pxPhyProperties->ucMDI_X == PHY_MDIX_CROSSED )
{
/* Force direct link = Use crossed RJ45 cable. */
ulPhyControl &= ~PHYCR_MDIX_FORCE;
}
else
{
/* Force crossed link = Use direct RJ45 cable. */
ulPhyControl |= PHYCR_MDIX_FORCE;
}
/* update PHY Control Register. */
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_19_PHYCR, ulPhyControl );
}
FreeRTOS_printf( ( "+TCP: advertise: %04lX config %04lX\n", ulAdvertise, ulConfig ) );
}
/* Keep these values for later use. */
pxPhyObject->ulBCRValue = ulConfig & ~phyBMCR_ISOLATE;
pxPhyObject->ulACRValue = ulAdvertise;
return 0;
}
/*-----------------------------------------------------------*/
/* 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;
uint32_t ulValue, ulBitMask = ( uint32_t ) 1U;
ulValue = ( uint32_t ) 0U;
if( pxPhyObject->xPhyPreferences.ucDuplex == PHY_DUPLEX_FULL )
{
ulValue |= phyBMCR_FULL_DUPLEX;
}
if( pxPhyObject->xPhyPreferences.ucSpeed == PHY_SPEED_100 )
{
ulValue |= phyBMCR_SPEED_100;
}
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
{
if( ( ulPhyMask & ulBitMask ) != 0lu )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
/* Enable Auto-Negotiation. */
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulValue );
}
}
return 0;
}
/*-----------------------------------------------------------*/
/* 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;
uint32_t ulPHYLinkStatus, ulRegValue;
TickType_t xRemainingTime;
TimeOut_t xTimer;
if( ulPhyMask == ( uint32_t ) 0U )
{
return 0;
}
for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++ )
{
if( ( ulPhyMask & ( 1lu << xPhyIndex ) ) != 0lu )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
/* Enable Auto-Negotiation. */
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_04_ADVERTISE, pxPhyObject->ulACRValue );
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, pxPhyObject->ulBCRValue | phyBMCR_AN_RESTART );
}
}
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 < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
{
if( ( ulPhyMask & ulBitMask ) != 0lu )
{
if( ( ulDoneMask & ulBitMask ) == 0lu )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulRegValue );
if( ( ulRegValue & phyBMSR_AN_COMPLETE ) != 0 )
{
ulDoneMask |= ulBitMask;
}
}
}
}
if( ulPhyMask == ulDoneMask )
{
break;
}
if( xTaskCheckForTimeOut( &xTimer, &xRemainingTime ) != pdFALSE )
{
FreeRTOS_printf( ( "xPhyStartAutoNegotiation: phyBMSR_AN_COMPLETE timed out ( done 0x%02lX )\n", ulDoneMask ) );
break;
}
vTaskDelay( pdMS_TO_TICKS( phySHORT_DELAY_MS ) );
}
if( ulDoneMask != ( uint32_t ) 0U )
{
ulBitMask = ( uint32_t ) 1U;
pxPhyObject->ulLinkStatusMask &= ~( ulDoneMask );
for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ];
if( ( ulDoneMask & ulBitMask ) == ( uint32_t ) 0U )
{
continue;
}
/* Clear the 'phyBMCR_AN_RESTART' bit. */
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, pxPhyObject->ulBCRValue );
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulRegValue );
if( ( ulRegValue & phyBMSR_LINK_STATUS ) != 0 )
{
ulPHYLinkStatus |= phyBMSR_LINK_STATUS;
pxPhyObject->ulLinkStatusMask |= ulBitMask;
}
else
{
ulPHYLinkStatus &= ~( phyBMSR_LINK_STATUS );
}
if( ulPhyID == PHY_ID_KSZ8081MNXIA )
{
uint32_t ulControlStatus;
pxPhyObject->fnPhyRead( xPhyAddress, 0x1E, &ulControlStatus );
switch( ulControlStatus & 0x07 )
{
case 0x01:
case 0x05:
/* [001] = 10BASE-T half-duplex */
/* [101] = 10BASE-T full-duplex */
/* 10 Mbps. */
ulRegValue |= phyPHYSTS_SPEED_STATUS;
break;
case 0x02:
case 0x06:
/* [010] = 100BASE-TX half-duplex */
/* [110] = 100BASE-TX full-duplex */
break;
}
switch( ulControlStatus & 0x07 )
{
case 0x05:
case 0x06:
/* [101] = 10BASE-T full-duplex */
/* [110] = 100BASE-TX full-duplex */
/* Full duplex. */
ulRegValue |= phyPHYSTS_DUPLEX_STATUS;
break;
case 0x01:
case 0x02:
/* [001] = 10BASE-T half-duplex */
/* [010] = 100BASE-TX half-duplex */
break;
}
}
else if( ulPhyID == PHY_ID_KSZ8795 )
{
/* KSZ8795 has a different mapping for the Port Operation Mode Indication field
* in the phyREG_1F_PHYSPCS than other similar PHYs:
* 010 = 10BASE-T half-duplex
* 101 = 10BASE-T full-duplex
* 011 = 100BASE-TX half-duplex
* 110 = 100BASE-TX full-duplex
*/
uint32_t ulControlStatus = 0u;
uint32_t ulPortOperationMode = 0u;
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_1F_PHYSPCS, &ulControlStatus );
ulPortOperationMode = ( ulControlStatus >> 8u ) & 0x07u;
ulRegValue = 0;
/* Detect 10baseT operation */
if( ( 0x02u == ulPortOperationMode ) || ( 0x05u == ulPortOperationMode ) )
{
ulRegValue |= phyPHYSTS_SPEED_STATUS;
}
/* Detect full duplex operation */
if( ( 0x05u == ulPortOperationMode ) || ( 0x06u == ulPortOperationMode ) )
{
ulRegValue |= phyPHYSTS_DUPLEX_STATUS;
}
}
else if( xHas_1F_PHYSPCS( ulPhyID ) )
{
/* 31 RW PHY Special Control Status */
uint32_t ulControlStatus;
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_1F_PHYSPCS, &ulControlStatus );
ulRegValue = 0;
if( ( ulControlStatus & phyPHYSPCS_FULL_DUPLEX ) != 0 )
{
ulRegValue |= phyPHYSTS_DUPLEX_STATUS;
}
if( ( ulControlStatus & phyPHYSPCS_SPEED_MASK ) == phyPHYSPCS_SPEED_10 )
{
ulRegValue |= phyPHYSTS_SPEED_STATUS;
}
}
else
{
/* Read the result of the auto-negotiation. */
pxPhyObject->fnPhyRead( xPhyAddress, PHYREG_10_PHYSTS, &ulRegValue );
}
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,
( ( ulPHYLinkStatus |= phyBMSR_LINK_STATUS ) != 0 ) ? "high" : "low" ) );
if( ( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) != ( uint32_t ) 0U )
{
pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_FULL;
}
else
{
pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_HALF;
}
if( ( ulRegValue & phyPHYSTS_SPEED_STATUS ) != 0 )
{
pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_10;
}
else
{
pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_100;
}
}
} /* if( ulDoneMask != ( uint32_t) 0U ) */
return 0;
}
/*-----------------------------------------------------------*/
BaseType_t xPhyCheckLinkStatus( EthernetPhy_t * pxPhyObject,
BaseType_t xHadReception )
{
uint32_t ulStatus, ulBitMask = 1U;
BaseType_t xPhyIndex;
BaseType_t xNeedCheck = pdFALSE;
if( xHadReception > 0 )
{
/* A packet was received. No need to check for the PHY status now,
* but set a timer to check it later on. */
vTaskSetTimeOutState( &( pxPhyObject->xLinkStatusTimer ) );
pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS );
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
{
if( ( pxPhyObject->ulLinkStatusMask & ulBitMask ) == 0UL )
{
pxPhyObject->ulLinkStatusMask |= ulBitMask;
FreeRTOS_printf( ( "xPhyCheckLinkStatus: PHY LS now %02lX\n", pxPhyObject->ulLinkStatusMask ) );
xNeedCheck = pdTRUE;
}
}
}
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 ];
if( pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulStatus ) == 0 )
{
if( !!( pxPhyObject->ulLinkStatusMask & ulBitMask ) != !!( ulStatus & phyBMSR_LINK_STATUS ) )
{
if( ( ulStatus & phyBMSR_LINK_STATUS ) != 0 )
{
pxPhyObject->ulLinkStatusMask |= ulBitMask;
}
else
{
pxPhyObject->ulLinkStatusMask &= ~( ulBitMask );
}
FreeRTOS_printf( ( "xPhyCheckLinkStatus: PHY LS now %02lX\n", pxPhyObject->ulLinkStatusMask ) );
xNeedCheck = pdTRUE;
}
}
}
vTaskSetTimeOutState( &( pxPhyObject->xLinkStatusTimer ) );
if( ( pxPhyObject->ulLinkStatusMask & ( ulBitMask >> 1 ) ) != 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 );
}
}
return xNeedCheck;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,950 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_ARP.h"
#include "NetworkBufferManagement.h"
#include "NetworkInterface.h"
/* Some files from the Atmel Software Framework */
/* gmac_SAM.[ch] is a combination of the gmac.[ch] for both SAM4E and SAME70. */
#include "gmac_SAM.h"
#include <sysclk.h>
#include "phyHandling.h"
/* This file is included to see if 'CONF_BOARD_ENABLE_CACHE' is defined. */
#include "conf_board.h"
/* Interrupt events to process. Currently only the Rx event is processed
* although code for other events is included to allow for possible future
* expansion. */
#define EMAC_IF_RX_EVENT 1UL
#define EMAC_IF_TX_EVENT 2UL
#define EMAC_IF_ERR_EVENT 4UL
#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
/* 1536 bytes is more than needed, 1524 would be enough.
* But 1536 is a multiple of 32, which gives a great alignment for
* cached memories. */
#define NETWORK_BUFFER_SIZE 1536
#ifndef EMAC_MAX_BLOCK_TIME_MS
/* The task 'prvEMACHandlerTask()' will wake-up every 100 ms, to see
* if something has to be done, mostly checking if the PHY has a
* change in Link Status. */
#define EMAC_MAX_BLOCK_TIME_MS 100ul
#endif
#if ( ipconfigZERO_COPY_RX_DRIVER == 0 )
#error This driver works optimal if ipconfigZERO_COPY_RX_DRIVER is defined as 1
#endif
#if ( ipconfigZERO_COPY_TX_DRIVER == 0 )
#error This driver works optimal if ipconfigZERO_COPY_TX_DRIVER is defined as 1
#endif
/* Default the size of the stack used by the EMAC deferred handler task to 4x
* the size of the stack used by the idle task - but allow this to be overridden in
* FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
#ifndef configEMAC_TASK_STACK_SIZE
#define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
#endif
#ifndef niEMAC_HANDLER_TASK_PRIORITY
#define niEMAC_HANDLER_TASK_PRIORITY configMAX_PRIORITIES - 1
#endif
#if ( __DCACHE_PRESENT != 0 ) && defined( CONF_BOARD_ENABLE_CACHE )
#include "core_cm7.h"
#warning This driver assumes the presence of DCACHE
#define NETWORK_BUFFERS_CACHED 1
#define CACHE_LINE_SIZE 32
#define NETWORK_BUFFER_HEADER_SIZE ( ipconfigPACKET_FILLER_SIZE + 8 )
static void cache_clean_invalidate()
{
/* If you application crashes here, make sure that SCB_EnableDCache() has been called. */
SCB_CleanInvalidateDCache();
}
/*-----------------------------------------------------------*/
static void cache_clean_invalidate_by_addr( uint32_t addr,
uint32_t size )
{
/* SAME70 does not have clean/invalidate per area. */
/* SCB_CleanInvalidateDCache_by_Addr( ( uint32_t * )addr, size); */
SCB_CleanInvalidateDCache();
}
/*-----------------------------------------------------------*/
static void cache_invalidate_by_addr( addr,
size ) \
{
/* SAME70 does not have clean/invalidate per area. */
/* SCB_InvalidateDCache_by_Addr( ( uint32_t * )addr, size); */
SCB_InvalidateDCache();
}
/*-----------------------------------------------------------*/
#else /* if ( __DCACHE_PRESENT != 0 ) && defined( CONF_BOARD_ENABLE_CACHE ) */
#warning Sure there is no caching?
#define cache_clean_invalidate() do {} while( 0 )
#define cache_clean_invalidate_by_addr( addr, size ) do {} while( 0 )
#define cache_invalidate_by_addr( addr, size ) do {} while( 0 )
#endif /* if ( __DCACHE_PRESENT != 0 ) && defined( CONF_BOARD_ENABLE_CACHE ) */
/*-----------------------------------------------------------*/
/*
* Update settings in GMAC for speed and duplex.
*/
static void prvEthernetUpdateConfig( BaseType_t xForce );
/*
* Access functions to the PHY's: read() and write() to be used by
* phyHandling.c.
*/
static BaseType_t xPHY_Read( BaseType_t xAddress,
BaseType_t xRegister,
uint32_t * pulValue );
static BaseType_t xPHY_Write( BaseType_t xAddress,
BaseType_t xRegister,
uint32_t ulValue );
#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
void vGMACGenerateChecksum( uint8_t * apBuffer,
size_t uxLength );
#endif
/*
* Called from the ASF GMAC driver.
*/
void xRxCallback( uint32_t ulStatus );
void xTxCallback( uint32_t ulStatus,
uint8_t * puc_buffer );
/*
* A deferred interrupt handler task that processes GMAC interrupts.
*/
static void prvEMACHandlerTask( void * pvParameters );
/*
* Initialise the ASF GMAC driver.
*/
static BaseType_t prvGMACInit( void );
/*
* Try to obtain an Rx packet from the hardware.
*/
static uint32_t prvEMACRxPoll( void );
/*
* Handle transmission errors.
*/
static void hand_tx_errors( void );
/*-----------------------------------------------------------*/
/* Bit map of outstanding ETH interrupt events for processing. Currently only
* the Rx interrupt is handled, although code is included for other events to
* enable future expansion. */
static volatile uint32_t ulISREvents;
/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
static volatile BaseType_t xGMACSwitchRequired;
/* LLMNR multicast address. */
static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
/* The GMAC object as defined by the ASF drivers. */
static gmac_device_t gs_gmac_dev;
/* Holds the handle of the task used as a deferred interrupt processor. The
* handle is used so direct notifications can be sent to the task for all EMAC/DMA
* related interrupts. */
TaskHandle_t xEMACTaskHandle = NULL;
static QueueHandle_t xTxBufferQueue;
int tx_release_count[ 4 ];
/* xTXDescriptorSemaphore is a counting semaphore with
* a maximum count of GMAC_TX_BUFFERS, which is the number of
* DMA TX descriptors. */
static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
/* For local use only: describe the PHY's properties: */
const PhyProperties_t xPHYProperties =
{
#if ( ipconfigETHERNET_AN_ENABLE != 0 )
.ucSpeed = PHY_SPEED_AUTO,
.ucDuplex = PHY_DUPLEX_AUTO,
#else
#if ( ipconfigETHERNET_USE_100MB != 0 )
.ucSpeed = PHY_SPEED_100,
#else
.ucSpeed = PHY_SPEED_10,
#endif
#if ( ipconfigETHERNET_USE_FULL_DUPLEX != 0 )
.ucDuplex = PHY_DUPLEX_FULL,
#else
.ucDuplex = PHY_DUPLEX_HALF,
#endif
#endif /* if ( ipconfigETHERNET_AN_ENABLE != 0 ) */
#if ( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 )
.ucMDI_X = PHY_MDIX_AUTO,
#elif ( ipconfigETHERNET_CROSSED_LINK != 0 )
.ucMDI_X = PHY_MDIX_CROSSED,
#else
.ucMDI_X = PHY_MDIX_DIRECT,
#endif
};
/* All PHY handling code has now been separated from the NetworkInterface.c,
* see "../Common/phyHandling.c". */
static EthernetPhy_t xPhyObject;
/*-----------------------------------------------------------*/
/*
* GMAC interrupt handler.
*/
void GMAC_Handler( void )
{
xGMACSwitchRequired = pdFALSE;
/* gmac_handler() may call xRxCallback() which may change
* the value of xGMACSwitchRequired. */
gmac_handler( &gs_gmac_dev );
if( xGMACSwitchRequired != pdFALSE )
{
portEND_SWITCHING_ISR( xGMACSwitchRequired );
}
}
/*-----------------------------------------------------------*/
void xRxCallback( uint32_t ulStatus )
{
if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
{
/* let the prvEMACHandlerTask know that there was an RX event. */
ulISREvents |= EMAC_IF_RX_EVENT;
/* Only an RX interrupt can wakeup prvEMACHandlerTask. */
vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
}
}
/*-----------------------------------------------------------*/
void returnTxBuffer( uint8_t * puc_buffer )
{
/* Called from a non-ISR context. */
if( xTxBufferQueue != NULL )
{
xQueueSend( xTxBufferQueue, &puc_buffer, 0 );
xTaskNotifyGive( xEMACTaskHandle );
ulISREvents |= EMAC_IF_TX_EVENT;
}
}
void xTxCallback( uint32_t ulStatus,
uint8_t * puc_buffer )
{
if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
{
/* let the prvEMACHandlerTask know that there was an TX event. */
ulISREvents |= EMAC_IF_TX_EVENT;
/* Wakeup prvEMACHandlerTask. */
vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
tx_release_count[ 2 ]++;
}
}
/*-----------------------------------------------------------*/
/*
* The two standard defines 'GMAC_MAN_RW_TYPE' and 'GMAC_MAN_READ_ONLY'
* are incorrect.
* Therefore, use the following:
*/
#define GMAC_MAINTENANCE_READ_ACCESS ( 2 )
#define GMAC_MAINTENANCE_WRITE_ACCESS ( 1 )
static BaseType_t xPHY_Read( BaseType_t xAddress,
BaseType_t xRegister,
uint32_t * pulValue )
{
BaseType_t xReturn;
UBaseType_t uxWasEnabled;
/* Wait until bus idle */
while( ( GMAC->GMAC_NSR & GMAC_NSR_IDLE ) == 0 )
{
}
/* Write maintain register */
/*
* OP: Operation: 10 is read. 01 is write.
*/
uxWasEnabled = ( GMAC->GMAC_NCR & GMAC_NCR_MPE ) != 0u;
if( uxWasEnabled == 0u )
{
/* Enable further GMAC maintenance. */
GMAC->GMAC_NCR |= GMAC_NCR_MPE;
}
GMAC->GMAC_MAN = GMAC_MAN_WTN( GMAC_MAN_CODE_VALUE )
| GMAC_MAN_CLTTO
| GMAC_MAN_PHYA( xAddress )
| GMAC_MAN_REGA( xRegister )
| GMAC_MAN_OP( GMAC_MAINTENANCE_READ_ACCESS )
| GMAC_MAN_DATA( ( uint16_t ) 0u );
if( gmac_wait_phy( GMAC, MAC_PHY_RETRY_MAX ) == GMAC_TIMEOUT )
{
*pulValue = ( uint32_t ) 0xffffu;
xReturn = -1;
}
else
{
/* Wait until bus idle */
while( ( GMAC->GMAC_NSR & GMAC_NSR_IDLE ) == 0 )
{
}
/* Return data */
*pulValue = ( uint32_t ) ( GMAC->GMAC_MAN & GMAC_MAN_DATA_Msk );
xReturn = 0;
}
if( uxWasEnabled == 0u )
{
/* Disable further GMAC maintenance. */
GMAC->GMAC_NCR &= ~GMAC_NCR_MPE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
static BaseType_t xPHY_Write( BaseType_t xAddress,
BaseType_t xRegister,
uint32_t ulValue )
{
BaseType_t xReturn;
UBaseType_t uxWasEnabled;
/* Wait until bus idle */
while( ( GMAC->GMAC_NSR & GMAC_NSR_IDLE ) == 0 )
{
}
/* Write maintain register */
uxWasEnabled = ( GMAC->GMAC_NCR & GMAC_NCR_MPE ) != 0u;
if( uxWasEnabled == 0u )
{
/* Enable further GMAC maintenance. */
GMAC->GMAC_NCR |= GMAC_NCR_MPE;
}
GMAC->GMAC_MAN = GMAC_MAN_WTN( GMAC_MAN_CODE_VALUE )
| GMAC_MAN_CLTTO
| GMAC_MAN_PHYA( xAddress )
| GMAC_MAN_REGA( xRegister )
| GMAC_MAN_OP( GMAC_MAINTENANCE_WRITE_ACCESS )
| GMAC_MAN_DATA( ( uint16_t ) ulValue );
if( gmac_wait_phy( GMAC, MAC_PHY_RETRY_MAX ) == GMAC_TIMEOUT )
{
xReturn = -1;
}
else
{
xReturn = 0;
}
if( uxWasEnabled == 0u )
{
/* Disable further GMAC maintenance. */
GMAC->GMAC_NCR &= ~GMAC_NCR_MPE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceInitialise( void )
{
const TickType_t x5_Seconds = 5000UL;
if( xEMACTaskHandle == NULL )
{
prvGMACInit();
cache_clean_invalidate();
/* The handler task is created at the highest possible priority to
* ensure the interrupt handler can return directly to it. */
xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle );
configASSERT( xEMACTaskHandle );
}
if( xTxBufferQueue == NULL )
{
xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
configASSERT( xTxBufferQueue );
}
if( xTXDescriptorSemaphore == NULL )
{
xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
configASSERT( xTXDescriptorSemaphore );
}
/* When returning non-zero, the stack will become active and
* start DHCP (in configured) */
return xGetPhyLinkStatus();
}
/*-----------------------------------------------------------*/
BaseType_t xGetPhyLinkStatus( void )
{
BaseType_t xReturn;
if( xPhyObject.ulLinkStatusMask != 0 )
{
xReturn = pdPASS;
}
else
{
xReturn = pdFAIL;
}
return xReturn;
}
/*-----------------------------------------------------------*/
/** The GMAC TX errors to handle */
#define GMAC_TX_ERRORS ( GMAC_TSR_TFC | GMAC_TSR_HRESP )
static void hand_tx_errors( void )
{
/* Handle GMAC underrun or AHB errors. */
if( gmac_get_tx_status( GMAC ) & GMAC_TX_ERRORS )
{
gmac_enable_transmit( GMAC, false );
/* Reinit TX descriptors. */
/* gmac_tx_init(ps_gmac_dev); */
gmac_reset_tx_mem( &gs_gmac_dev );
/* Clear error status. */
gmac_clear_tx_status( GMAC, GMAC_TX_ERRORS );
gmac_enable_transmit( GMAC, true );
}
}
volatile IPPacket_t * pxSendPacket;
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor,
BaseType_t bReleaseAfterSend )
{
/* Do not wait too long for a free TX DMA buffer. */
const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
uint32_t ulTransmitSize;
ulTransmitSize = pxDescriptor->xDataLength;
pxSendPacket = ( IPPacket_t * ) pxDescriptor->pucEthernetBuffer;
if( ulTransmitSize > NETWORK_BUFFER_SIZE )
{
ulTransmitSize = NETWORK_BUFFER_SIZE;
}
/* A do{}while(0) loop is introduced to allow the use of multiple break
* statement. */
do
{
if( xPhyObject.ulLinkStatusMask == 0ul )
{
/* Do not attempt to send packets as long as the Link Status is low. */
break;
}
if( xTXDescriptorSemaphore == NULL )
{
/* Semaphore has not been created yet? */
break;
}
hand_tx_errors();
if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
{
/* Time-out waiting for a free TX descriptor. */
tx_release_count[ 3 ]++;
break;
}
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
/* Confirm that the pxDescriptor may be kept by the driver. */
configASSERT( bReleaseAfterSend != pdFALSE );
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
#if ( NETWORK_BUFFERS_CACHED != 0 )
{
uint32_t xlength = CACHE_LINE_SIZE * ( ( ulTransmitSize + NETWORK_BUFFER_HEADER_SIZE + CACHE_LINE_SIZE - 1 ) / CACHE_LINE_SIZE );
uint32_t xAddress = ( uint32_t ) ( pxDescriptor->pucEthernetBuffer - NETWORK_BUFFER_HEADER_SIZE );
cache_clean_invalidate_by_addr( xAddress, xlength );
}
#endif
gmac_dev_write( &gs_gmac_dev, ( void * ) pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength );
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
/* Confirm that the pxDescriptor may be kept by the driver. */
bReleaseAfterSend = pdFALSE;
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
/* Not interested in a call-back after TX. */
iptraceNETWORK_INTERFACE_TRANSMIT();
} while( ipFALSE_BOOL );
if( bReleaseAfterSend != pdFALSE )
{
vReleaseNetworkBufferAndDescriptor( pxDescriptor );
}
return pdTRUE;
}
/*-----------------------------------------------------------*/
static BaseType_t prvGMACInit( void )
{
uint32_t ncfgr;
gmac_options_t gmac_option;
gmac_enable_management( GMAC, true );
/* Enable further GMAC maintenance. */
GMAC->GMAC_NCR |= GMAC_NCR_MPE;
memset( &gmac_option, '\0', sizeof( gmac_option ) );
gmac_option.uc_copy_all_frame = 0;
gmac_option.uc_no_boardcast = 0;
memcpy( gmac_option.uc_mac_addr, ipLOCAL_MAC_ADDRESS, sizeof( gmac_option.uc_mac_addr ) );
gs_gmac_dev.p_hw = GMAC;
gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );
NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );
NVIC_EnableIRQ( GMAC_IRQn );
{
/* Set MDC clock divider. */
gmac_set_mdc_clock( GMAC, sysclk_get_cpu_hz() );
vPhyInitialise( &xPhyObject, xPHY_Read, xPHY_Write );
xPhyDiscover( &xPhyObject );
xPhyConfigure( &xPhyObject, &xPHYProperties );
/* For a reset / reconfigure of the EMAC. */
prvEthernetUpdateConfig( pdTRUE );
/* Select Media Independent Interface type */
#if ( SAME70 != 0 )
{
/* Selecting RMII mode. */
GMAC->GMAC_UR &= ~GMAC_UR_RMII;
}
#else
{
gmac_select_mii_mode( GMAC, ETH_PHY_MODE );
}
#endif
gmac_enable_transmit( GMAC, true );
gmac_enable_receive( GMAC, true );
}
gmac_enable_management( GMAC, true );
gmac_set_address( GMAC, 1, ( uint8_t * ) llmnr_mac_address );
gmac_enable_management( GMAC, false );
/* Disable further GMAC maintenance. */
GMAC->GMAC_NCR &= ~GMAC_NCR_MPE;
return 1;
}
/*-----------------------------------------------------------*/
static void prvEthernetUpdateConfig( BaseType_t xForce )
{
FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS mask %02lX Force %d\n",
xPhyObject.ulLinkStatusMask,
( int ) xForce ) );
if( ( xForce != pdFALSE ) || ( xPhyObject.ulLinkStatusMask != 0 ) )
{
#if ( ipconfigETHERNET_AN_ENABLE != 0 )
{
UBaseType_t uxWasEnabled;
/* Restart the auto-negotiation. */
uxWasEnabled = ( GMAC->GMAC_NCR & GMAC_NCR_MPE ) != 0u;
if( uxWasEnabled == 0u )
{
/* Enable further GMAC maintenance. */
GMAC->GMAC_NCR |= GMAC_NCR_MPE;
}
xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) );
/* Configure the MAC with the Duplex Mode fixed by the
* auto-negotiation process. */
if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL )
{
gmac_enable_full_duplex( GMAC, pdTRUE );
}
else
{
gmac_enable_full_duplex( GMAC, pdFALSE );
}
/* Configure the MAC with the speed fixed by the
* auto-negotiation process. */
if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 )
{
gmac_set_speed( GMAC, pdFALSE );
}
else
{
gmac_set_speed( GMAC, pdTRUE );
}
if( uxWasEnabled == 0u )
{
/* Enable further GMAC maintenance. */
GMAC->GMAC_NCR &= ~GMAC_NCR_MPE;
}
}
#else /* if ( ipconfigETHERNET_AN_ENABLE != 0 ) */
{
if( xPHYProperties.ucDuplex == PHY_DUPLEX_FULL )
{
xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_FULL;
gmac_enable_full_duplex( GMAC, pdTRUE );
}
else
{
xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_HALF;
gmac_enable_full_duplex( GMAC, pdFALSE );
}
if( xPHYProperties.ucSpeed == PHY_SPEED_100 )
{
xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_100;
gmac_set_speed( GMAC, pdTRUE );
}
else
{
xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_10;
gmac_set_speed( GMAC, pdFALSE );
}
xPhyObject.xPhyPreferences.ucMDI_X = PHY_MDIX_AUTO;
/* Use predefined (fixed) configuration. */
xPhyFixedValue( &xPhyObject, xPhyGetMask( &xPhyObject ) );
}
#endif /* if ( ipconfigETHERNET_AN_ENABLE != 0 ) */
}
}
/*-----------------------------------------------------------*/
void vGMACGenerateChecksum( uint8_t * pucBuffer,
size_t uxLength )
{
ProtocolPacket_t * xProtPacket = ( ProtocolPacket_t * ) pucBuffer;
if( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
{
IPHeader_t * pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader );
/* Calculate the IP header checksum. */
pxIPHeader->usHeaderChecksum = 0x00;
pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
/* Calculate the TCP checksum for an outgoing packet. */
usGenerateProtocolChecksum( pucBuffer, uxLength, pdTRUE );
}
}
/*-----------------------------------------------------------*/
static uint32_t prvEMACRxPoll( void )
{
unsigned char * pucUseBuffer;
uint32_t ulReceiveCount, ulResult, ulReturnValue = 0;
static NetworkBufferDescriptor_t * pxNextNetworkBufferDescriptor = NULL;
const UBaseType_t xMinDescriptorsToLeave = 2UL;
const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL );
static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
uint8_t * pucDMABuffer = NULL;
for( ; ; )
{
/* If pxNextNetworkBufferDescriptor was not left pointing at a valid
* descriptor then allocate one now. */
if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) )
{
pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );
}
if( pxNextNetworkBufferDescriptor != NULL )
{
/* Point pucUseBuffer to the buffer pointed to by the descriptor. */
pucUseBuffer = ( unsigned char * ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
}
else
{
/* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
* messages will be flushed and ignored. */
pucUseBuffer = NULL;
}
/* Read the next packet from the hardware into pucUseBuffer. */
ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount, &pucDMABuffer );
if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )
{
/* No data from the hardware. */
break;
}
if( pxNextNetworkBufferDescriptor == NULL )
{
/* Data was read from the hardware, but no descriptor was available
* for it, so it will be dropped. */
iptraceETHERNET_RX_EVENT_LOST();
continue;
}
iptraceNETWORK_INTERFACE_RECEIVE();
#if ( ipconfigZERO_COPY_RX_DRIVER != 0 )
{
pxNextNetworkBufferDescriptor = pxPacketBuffer_to_NetworkBuffer( pucDMABuffer );
if( pxNextNetworkBufferDescriptor == NULL )
{
/* Strange: can not translate from a DMA buffer to a Network Buffer. */
break;
}
}
#endif /* ipconfigZERO_COPY_RX_DRIVER */
pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;
xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;
/* Send the descriptor to the IP task for processing. */
if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )
{
/* The buffer could not be sent to the stack so must be released
* again. */
vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );
iptraceETHERNET_RX_EVENT_LOST();
FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
}
/* Now the buffer has either been passed to the IP-task,
* or it has been released in the code above. */
pxNextNetworkBufferDescriptor = NULL;
ulReturnValue++;
}
return ulReturnValue;
}
/*-----------------------------------------------------------*/
extern uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * NETWORK_BUFFER_SIZE ];
void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
{
uint8_t * ucRAMBuffer = ucNetworkPackets;
uint32_t ulIndex;
for( ulIndex = 0; ulIndex < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ulIndex++ )
{
pxNetworkBuffers[ ulIndex ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
*( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ulIndex ] ) );
ucRAMBuffer += NETWORK_BUFFER_SIZE;
}
cache_clean_invalidate();
}
/*-----------------------------------------------------------*/
static void prvEMACHandlerTask( void * pvParameters )
{
UBaseType_t uxCount;
UBaseType_t uxLowestSemCount = 0;
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
NetworkBufferDescriptor_t * pxBuffer;
#endif
uint8_t * pucBuffer;
BaseType_t xResult = 0;
uint32_t xStatus;
const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
/* Remove compiler warnings about unused parameters. */
( void ) pvParameters;
configASSERT( xEMACTaskHandle );
for( ; ; )
{
xResult = 0;
#if ( ipconfigHAS_PRINTF != 0 )
{
/* Call a function that monitors resources: the amount of free network
* buffers and the amount of free space on the heap. See FreeRTOS_IP.c
* for more detailed comments. */
vPrintResourceStats();
if( xTXDescriptorSemaphore != NULL )
{
UBaseType_t uxCurrentSemCount = uxSemaphoreGetCount( xTXDescriptorSemaphore );
if( uxLowestSemCount > uxCurrentSemCount )
{
uxLowestSemCount = uxCurrentSemCount;
FreeRTOS_printf( ( "TX DMA buffers: lowest %lu\n", uxLowestSemCount ) );
}
}
}
#endif /* ( ipconfigHAS_PRINTF != 0 ) */
if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
{
/* No events to process now, wait for the next. */
ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
}
if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
{
ulISREvents &= ~EMAC_IF_RX_EVENT;
/* Wait for the EMAC interrupt to indicate that another packet has been
* received. */
xResult = prvEMACRxPoll();
}
if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
{
/* Future extension: code to release TX buffers if zero-copy is used. */
ulISREvents &= ~EMAC_IF_TX_EVENT;
while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )
{
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
if( pxBuffer != NULL )
{
vReleaseNetworkBufferAndDescriptor( pxBuffer );
tx_release_count[ 0 ]++;
}
else
{
tx_release_count[ 1 ]++;
}
}
#else /* if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) */
{
tx_release_count[ 0 ]++;
}
#endif /* if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) */
uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
if( uxCount < GMAC_TX_BUFFERS )
{
/* Tell the counting semaphore that one more TX descriptor is available. */
xSemaphoreGive( xTXDescriptorSemaphore );
}
}
}
if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
{
/* Future extension: logging about errors that occurred. */
ulISREvents &= ~EMAC_IF_ERR_EVENT;
}
gmac_enable_management( GMAC, true );
if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 )
{
/* Something has changed to a Link Status, need re-check. */
prvEthernetUpdateConfig( pdFALSE );
}
gmac_enable_management( GMAC, false );
}
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,997 @@
/**
* \file
*
* \brief GMAC (Ethernet MAC) driver for SAM.
*
* Copyright (c) 2015-2016 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* 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. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "FreeRTOSIPConfig.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_ARP.h"
#include "NetworkBufferManagement.h"
#include "NetworkInterface.h"
#include "compiler.h"
#include "gmac_SAM.h"
#if ( SAME70 != 0 )
/* This file is included to see if 'CONF_BOARD_ENABLE_CACHE' is defined. */
#include "conf_board.h"
#include "core_cm7.h"
#endif
/*/ @cond 0 */
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/*/ @endcond */
#ifndef ARRAY_SIZE
#define ARRAY_SIZE( x ) ( int ) ( sizeof( x ) / sizeof( x )[ 0 ] )
#endif
#if ( GMAC_RX_BUFFERS <= 1 )
#error Configuration error
#endif
#if ( GMAC_TX_BUFFERS <= 1 )
#error Configuration error
#endif
/**
* \defgroup gmac_group Ethernet Media Access Controller
*
* See \ref gmac_quickstart.
*
* Driver for the GMAC (Ethernet Media Access Controller).
* This file contains basic functions for the GMAC, with support for all modes, settings
* and clock speeds.
*
* \section dependencies Dependencies
* This driver does not depend on other modules.
*
* @{
*/
#define NETWORK_BUFFER_SIZE 1536
__attribute__( ( aligned( 32 ) ) )
__attribute__( ( section( ".first_data" ) ) )
uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * NETWORK_BUFFER_SIZE ];
/** TX descriptor lists */
__attribute__( ( section( ".first_data" ) ) )
COMPILER_ALIGNED( 8 )
static gmac_tx_descriptor_t gs_tx_desc[ GMAC_TX_BUFFERS ];
#if ( SAME70 != 0 )
__attribute__( ( section( ".first_data" ) ) )
COMPILER_ALIGNED( 8 )
static gmac_tx_descriptor_t gs_tx_desc_null;
#endif
/** RX descriptors lists */
__attribute__( ( section( ".first_data" ) ) )
COMPILER_ALIGNED( 8 )
static gmac_rx_descriptor_t gs_rx_desc[ GMAC_RX_BUFFERS ];
#if ( ipconfigZERO_COPY_TX_DRIVER == 0 )
/** Send Buffer. Section 3.6 of AMBA 2.0 spec states that burst should not cross the
* 1K Boundaries. Receive buffer manager write operations are burst of 2 words => 3 lsb bits
* of the address shall be set to 0.
*/
__attribute__( ( section( ".first_data" ) ) )
COMPILER_ALIGNED( 8 )
static uint8_t gs_uc_tx_buffer[ GMAC_TX_BUFFERS * GMAC_TX_UNITSIZE ];
#endif /* ipconfigZERO_COPY_TX_DRIVER */
#if ( ipconfigZERO_COPY_RX_DRIVER == 0 )
/** Receive Buffer */
__attribute__( ( section( ".first_data" ) ) )
COMPILER_ALIGNED( 8 )
static uint8_t gs_uc_rx_buffer[ GMAC_RX_BUFFERS * GMAC_RX_UNITSIZE ];
#endif /* ipconfigZERO_COPY_RX_DRIVER */
/** Return count in buffer */
#define CIRC_CNT( head, tail, size ) ( ( ( head ) - ( tail ) ) % ( size ) )
/*
* Return space available, from 0 to size-1.
* Always leave one free char as a completely full buffer that has (head == tail),
* which is the same as empty.
*/
#define CIRC_SPACE( head, tail, size ) CIRC_CNT( ( tail ), ( ( head ) + 1 ), ( size ) )
/** Circular buffer is empty ? */
#define CIRC_EMPTY( head, tail ) ( ( head ) == ( tail ) )
/** Clear circular buffer */
#define CIRC_CLEAR( head, tail ) do { ( head ) = 0; ( tail ) = 0; } while( 0 )
/* Two call-back functions that should be defined in NetworkInterface.c */
extern void xRxCallback( uint32_t ulStatus );
extern void xTxCallback( uint32_t ulStatus,
uint8_t * puc_buffer );
extern void returnTxBuffer( uint8_t * puc_buffer );
/** Increment head or tail */
static __inline void circ_inc32( int32_t * lHeadOrTail,
uint32_t ulSize )
{
( *lHeadOrTail )++;
if( ( *lHeadOrTail ) >= ( int32_t ) ulSize )
{
( *lHeadOrTail ) = 0;
}
}
/**
* \brief Wait PHY operation to be completed.
*
* \param p_gmac HW controller address.
* \param ul_retry The retry times, 0 to wait forever until completeness.
*
* Return GMAC_OK if the operation is completed successfully.
*/
uint8_t gmac_wait_phy( Gmac * p_gmac,
const uint32_t ul_retry )
{
volatile uint32_t ul_retry_count = 0;
const uint32_t xPHYPollDelay = pdMS_TO_TICKS( 1ul );
while( !gmac_is_phy_idle( p_gmac ) )
{
if( ul_retry == 0 )
{
continue;
}
ul_retry_count++;
if( ul_retry_count >= ul_retry )
{
return GMAC_TIMEOUT;
}
/* Block the task to allow other tasks to execute while the PHY
* is not connected. */
vTaskDelay( xPHYPollDelay );
}
return GMAC_OK;
}
/**
* \brief Disable transfer, reset registers and descriptor lists.
*
* \param p_dev Pointer to GMAC driver instance.
*
*/
void gmac_reset_tx_mem( gmac_device_t * p_dev )
{
Gmac * p_hw = p_dev->p_hw;
uint32_t ul_index;
uint32_t ul_address;
/* Disable TX */
gmac_enable_transmit( p_hw, 0 );
{
for( ul_index = 0; ul_index < ARRAY_SIZE( gs_tx_desc ); ul_index++ )
{
uint32_t ulAddr = gs_tx_desc[ ul_index ].addr;
if( ulAddr )
{
returnTxBuffer( ( uint8_t * ) ulAddr );
}
}
}
/* Set up the TX descriptors */
CIRC_CLEAR( p_dev->l_tx_head, p_dev->l_tx_tail );
for( ul_index = 0; ul_index < GMAC_TX_BUFFERS; ul_index++ )
{
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
ul_address = ( uint32_t ) 0u;
}
#else
{
ul_address = ( uint32_t ) ( &( gs_uc_tx_buffer[ ul_index * GMAC_TX_UNITSIZE ] ) );
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
gs_tx_desc[ ul_index ].addr = ul_address;
gs_tx_desc[ ul_index ].status.val = GMAC_TXD_USED;
}
/* Set the WRAP bit in the last descriptor. */
gs_tx_desc[ GMAC_TX_BUFFERS - 1 ].status.val = GMAC_TXD_USED | GMAC_TXD_WRAP;
/* Set transmit buffer queue */
gmac_set_tx_queue( p_hw, ( uint32_t ) gs_tx_desc );
#if ( SAME70 != 0 )
{
gmac_set_tx_priority_queue( p_hw, ( uint32_t ) &gs_tx_desc_null, GMAC_QUE_1 );
gmac_set_tx_priority_queue( p_hw, ( uint32_t ) &gs_tx_desc_null, GMAC_QUE_2 );
/* Note that SAME70 REV B had 6 priority queues. */
gmac_set_tx_priority_queue( p_hw, ( uint32_t ) &gs_tx_desc_null, GMAC_QUE_3 );
gmac_set_tx_priority_queue( p_hw, ( uint32_t ) &gs_tx_desc_null, GMAC_QUE_4 );
gmac_set_tx_priority_queue( p_hw, ( uint32_t ) &gs_tx_desc_null, GMAC_QUE_5 );
}
#endif
}
/**
* \brief Disable receiver, reset registers and descriptor list.
*
* \param p_dev Pointer to GMAC Driver instance.
*/
static void gmac_reset_rx_mem( gmac_device_t * p_dev )
{
Gmac * p_hw = p_dev->p_hw;
uint32_t ul_index;
uint32_t ul_address;
/* Disable RX */
gmac_enable_receive( p_hw, 0 );
/* Set up the RX descriptors */
p_dev->ul_rx_idx = 0;
for( ul_index = 0; ul_index < GMAC_RX_BUFFERS; ul_index++ )
{
#if ( ipconfigZERO_COPY_RX_DRIVER != 0 )
{
NetworkBufferDescriptor_t * pxNextNetworkBufferDescriptor;
pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( GMAC_RX_UNITSIZE, 0ul );
configASSERT( pxNextNetworkBufferDescriptor != NULL );
ul_address = ( uint32_t ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer );
}
#else
{
ul_address = ( uint32_t ) ( &( gs_uc_rx_buffer[ ul_index * GMAC_RX_UNITSIZE ] ) );
}
#endif /* ipconfigZERO_COPY_RX_DRIVER */
gs_rx_desc[ ul_index ].addr.val = ul_address & GMAC_RXD_ADDR_MASK;
gs_rx_desc[ ul_index ].status.val = 0;
}
/* Set the WRAP bit in the last descriptor. */
gs_rx_desc[ GMAC_RX_BUFFERS - 1 ].addr.bm.b_wrap = 1;
/* Set receive buffer queue */
gmac_set_rx_queue( p_hw, ( uint32_t ) gs_rx_desc );
}
/**
* \brief Initialize the allocated buffer lists for GMAC driver to transfer data.
* Must be invoked after gmac_dev_init() but before RX/TX starts.
*
* \note If input address is not 8-byte aligned, the address is automatically
* adjusted and the list size is reduced by one.
*
* \param p_gmac Pointer to GMAC instance.
* \param p_gmac_dev Pointer to GMAC device instance.
* \param p_dev_mm Pointer to the GMAC memory management control block.
*
* \return GMAC_OK or GMAC_PARAM.
*/
static uint8_t gmac_init_mem( Gmac * p_gmac,
gmac_device_t * p_gmac_dev )
{
/* Assign TX buffers */
#if ( ipconfigZERO_COPY_TX_DRIVER == 0 )
if( ( ( ( uint32_t ) gs_uc_tx_buffer ) & 0x7 ) ||
( ( uint32_t ) p_dev_mm->p_tx_dscr & 0x7 ) )
{
p_dev_mm->ul_tx_size--;
}
p_gmac_dev->p_tx_buffer =
( uint8_t * ) ( ( ( uint32_t ) gs_uc_tx_buffer ) & 0xFFFFFFF8 );
#endif
/* Reset TX & RX Memory */
gmac_reset_rx_mem( p_gmac_dev );
gmac_reset_tx_mem( p_gmac_dev );
/* Enable Rx and Tx, plus the statistics register */
gmac_enable_transmit( p_gmac, true );
gmac_enable_receive( p_gmac, true );
gmac_enable_statistics_write( p_gmac, true );
/* Set up the interrupts for transmission and errors */
gmac_enable_interrupt( p_gmac,
GMAC_IER_RLEX | /* Enable retry limit exceeded interrupt. */
GMAC_IER_RXUBR | /* Enable receive used bit read interrupt. */
GMAC_IER_ROVR | /* Enable receive overrun interrupt. */
GMAC_IER_TCOMP | /* Enable transmit complete interrupt. */
GMAC_IER_TUR | /* Enable transmit underrun interrupt. */
GMAC_IER_TFC | /* Enable transmit buffers exhausted in mid-frame interrupt. */
GMAC_IER_HRESP | /* Enable Hresp not OK interrupt. */
GMAC_IER_PFNZ | /* Enable pause frame received interrupt. */
GMAC_IER_PTZ | /* Enable pause time zero interrupt. */
GMAC_IER_RCOMP ); /* Enable receive complete interrupt. */
return GMAC_OK;
}
/**
* \brief Initialize the GMAC driver.
*
* \param p_gmac Pointer to the GMAC instance.
* \param p_gmac_dev Pointer to the GMAC device instance.
* \param p_opt GMAC configure options.
*/
void gmac_dev_init( Gmac * p_gmac,
gmac_device_t * p_gmac_dev,
gmac_options_t * p_opt )
{
/* Disable TX & RX and more */
gmac_network_control( p_gmac, 0 );
gmac_disable_interrupt( p_gmac, ~0u );
gmac_clear_statistics( p_gmac );
/* Clear all status bits in the receive status register. */
gmac_clear_rx_status( p_gmac, GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA
| GMAC_RSR_HNO );
#ifndef GMAC_TSR_UND
/* GMAC_TSR_UND is only defined by SAM4E. */
#define GMAC_TSR_UND 0ul
#endif
/* Clear all status bits in the transmit status register */
gmac_clear_tx_status( p_gmac, GMAC_TSR_UBR | GMAC_TSR_COL | GMAC_TSR_RLE
| GMAC_TSR_TFC | GMAC_TSR_TXCOMP | GMAC_TSR_UND );
/* Clear interrupts */
gmac_get_interrupt_status( p_gmac );
#if !defined( ETHERNET_CONF_DATA_OFFSET )
/* Receive Buffer Offset
* Indicates the number of bytes by which the received data
* is offset from the start of the receive buffer
* which can be handy for alignment reasons */
/* Note: FreeRTOS+TCP wants to have this offset set to 2 bytes */
#error ETHERNET_CONF_DATA_OFFSET not defined, assuming 0
#endif
/* Enable the copy of data into the buffers
* ignore broadcasts, and not copy FCS. */
gmac_set_config( p_gmac,
( gmac_get_config( p_gmac ) & ~GMAC_NCFGR_RXBUFO_Msk ) |
GMAC_NCFGR_RFCS | /* Remove FCS, frame check sequence (last 4 bytes) */
GMAC_NCFGR_PEN | /* Pause Enable */
GMAC_NCFGR_RXBUFO( ETHERNET_CONF_DATA_OFFSET ) | /* Set Ethernet Offset */
GMAC_RXD_RXCOEN ); /* RXCOEN related function */
/*
* GMAC_DCFGR_TXCOEN: (GMAC_DCFGR) Transmitter Checksum Generation Offload Enable.
* Note: SAM4E/SAME70 do have RX checksum offloading
* but TX checksum offloading has NOT been implemented,
* at least on a SAM4E.
* http://community.atmel.com/forum/sam4e-gmac-transmit-checksum-offload-enablesolved
*/
{
uint32_t ulValue = gmac_get_dma( p_gmac );
/* Let the GMAC set TX checksum's. */
ulValue |= GMAC_DCFGR_TXCOEN;
#if ( SAME70 != 0 )
{
/* Transmitter Packet Buffer Memory Size Select:
* Use full configured addressable space (4 Kbytes). */
ulValue |= GMAC_DCFGR_TXPBMS;
}
#endif
/* Clear the DMA Receive Buffer Size (DRBS) field: */
ulValue &= ~( GMAC_DCFGR_DRBS_Msk );
/* And set it: */
ulValue |= ( GMAC_RX_UNITSIZE / 64 ) << GMAC_DCFGR_DRBS_Pos;
gmac_set_dma( p_gmac, ulValue );
}
/* Enable/Disable Copy(Receive) All Valid Frames. */
gmac_enable_copy_all( p_gmac, p_opt->uc_copy_all_frame );
/* Disable/Enable broadcast receiving */
gmac_disable_broadcast( p_gmac, p_opt->uc_no_boardcast );
/* Initialize memory */
gmac_init_mem( p_gmac, p_gmac_dev );
/* Set Mac Address */
gmac_set_address( p_gmac, 0, p_opt->uc_mac_addr );
}
/**
* \brief Frames can be read from the GMAC in multiple sections.
*
* Returns > 0 if a complete frame is available
* It also it cleans up incomplete older frames
*/
static uint32_t gmac_dev_poll( gmac_device_t * p_gmac_dev )
{
uint32_t ulReturn = 0;
int32_t ulIndex = p_gmac_dev->ul_rx_idx;
gmac_rx_descriptor_t * pxHead = &gs_rx_desc[ ulIndex ];
/* #warning Just for debugging */
/* if((pxHead->addr.val & GMAC_RXD_OWNERSHIP) != 0) */
/* { */
/* NVIC_DisableIRQ( GMAC_IRQn ); */
/* } */
#if ( ipconfigZERO_COPY_RX_DRIVER == 0 )
{
/* Discard any incomplete frames */
while( ( pxHead->addr.val & GMAC_RXD_OWNERSHIP ) &&
( pxHead->status.val & GMAC_RXD_SOF ) == 0 )
{
pxHead->addr.val &= ~( GMAC_RXD_OWNERSHIP );
circ_inc32( &ulIndex, GMAC_RX_BUFFERS );
pxHead = &gs_rx_desc[ ulIndex ];
p_gmac_dev->ul_rx_idx = ulIndex;
#if ( GMAC_STATS != 0 )
{
gmacStats.incompCount++;
}
#endif
}
}
#endif /* ipconfigZERO_COPY_RX_DRIVER == 0 */
while( ( pxHead->addr.val & GMAC_RXD_OWNERSHIP ) != 0 )
{
#if ( ipconfigZERO_COPY_RX_DRIVER == 0 )
{
if( ( pxHead->status.val & GMAC_RXD_EOF ) != 0 )
{
/* Here a complete frame has been seen with SOF and EOF */
ulReturn = pxHead->status.bm.b_len;
break;
}
circ_inc32( &ulIndex, GMAC_RX_BUFFERS );
pxHead = &gs_rx_desc[ ulIndex ];
if( ( pxHead->addr.val & GMAC_RXD_OWNERSHIP ) == 0 )
{
/* CPU is not the owner (yet) */
break;
}
if( ( pxHead->status.val & GMAC_RXD_SOF ) != 0 )
{
/* Strange, we found a new Start Of Frame
* discard previous segments */
int32_t ulPrev = p_gmac_dev->ul_rx_idx;
pxHead = &gs_rx_desc[ ulPrev ];
do
{
pxHead->addr.val &= ~( GMAC_RXD_OWNERSHIP );
circ_inc32( &ulPrev, GMAC_RX_BUFFERS );
pxHead = &gs_rx_desc[ ulPrev ];
#if ( GMAC_STATS != 0 )
{
gmacStats.truncCount++;
}
#endif
} while( ulPrev != ulIndex );
p_gmac_dev->ul_rx_idx = ulIndex;
}
}
#else /* ipconfigZERO_COPY_RX_DRIVER */
{
if( ( pxHead->status.val & ( GMAC_RXD_SOF | GMAC_RXD_EOF ) ) == ( GMAC_RXD_SOF | GMAC_RXD_EOF ) )
{
/* Here a complete frame in a single segment. */
ulReturn = pxHead->status.bm.b_len;
break;
}
/* Return the buffer to DMA. */
pxHead->addr.bm.b_ownership = 0;
/* Let ulIndex/pxHead point to the next buffer. */
circ_inc32( &ulIndex, GMAC_RX_BUFFERS );
pxHead = &gs_rx_desc[ ulIndex ];
/* And remember this index. */
p_gmac_dev->ul_rx_idx = ulIndex;
}
#endif /* ipconfigZERO_COPY_RX_DRIVER */
}
return ulReturn;
}
/**
* \brief Frames can be read from the GMAC in multiple sections.
* Read ul_frame_size bytes from the GMAC receive buffers to pcTo.
* p_rcv_size is the size of the entire frame. Generally gmac_read
* will be repeatedly called until the sum of all the ul_frame_size equals
* the value of p_rcv_size.
*
* \param p_gmac_dev Pointer to the GMAC device instance.
* \param p_frame Address of the frame buffer.
* \param ul_frame_size Length of the frame.
* \param p_rcv_size Received frame size.
*
* \return GMAC_OK if receiving frame successfully, otherwise failed.
*/
uint32_t gmac_dev_read( gmac_device_t * p_gmac_dev,
uint8_t * p_frame,
uint32_t ul_frame_size,
uint32_t * p_rcv_size,
uint8_t ** pp_recv_frame )
{
int32_t nextIdx; /* A copy of the Rx-index 'ul_rx_idx' */
int32_t bytesLeft = gmac_dev_poll( p_gmac_dev );
gmac_rx_descriptor_t * pxHead;
if( bytesLeft == 0 )
{
return GMAC_RX_NO_DATA;
}
/* gmac_dev_poll has confirmed that there is a complete frame at
* the current position 'ul_rx_idx'
*/
nextIdx = p_gmac_dev->ul_rx_idx;
/* Read +2 bytes because buffers are aligned at -2 bytes */
bytesLeft = min( bytesLeft + 2, ( int32_t ) ul_frame_size );
#if ( __DCACHE_PRESENT != 0 ) && defined( CONF_BOARD_ENABLE_CACHE )
SCB_InvalidateDCache();
#endif
#if ( ipconfigZERO_COPY_RX_DRIVER == 0 )
{
/* The frame will be copied in 1 or 2 memcpy's */
if( ( p_frame != NULL ) && ( bytesLeft != 0 ) )
{
const uint8_t * source;
int32_t left;
int32_t toCopy;
source = gs_uc_rx_buffer + nextIdx * GMAC_RX_UNITSIZE;
left = bytesLeft;
toCopy = ( GMAC_RX_BUFFERS - nextIdx ) * GMAC_RX_UNITSIZE;
if( toCopy > left )
{
toCopy = left;
}
memcpy( p_frame, source, toCopy );
left -= toCopy;
if( left != 0ul )
{
memcpy( p_frame + toCopy, ( void * ) gs_uc_rx_buffer, left );
}
}
}
#else /* ipconfigZERO_COPY_RX_DRIVER */
{
if( p_frame != NULL )
{
/* Return a pointer to the earlier DMA buffer. */
*( pp_recv_frame ) = ( uint8_t * )
( ( ( gs_rx_desc[ nextIdx ].addr.val ) & ~( 0x03ul ) ) + 2 );
/* Set the new DMA-buffer. */
gs_rx_desc[ nextIdx ].addr.bm.addr_dw = ( ( uint32_t ) p_frame ) / 4;
}
else
{
/* The driver could not allocate a buffer to receive a packet.
* Leave the current DMA buffer in place. */
}
}
#endif /* ipconfigZERO_COPY_RX_DRIVER */
do
{
pxHead = &gs_rx_desc[ nextIdx ];
pxHead->addr.val &= ~( GMAC_RXD_OWNERSHIP );
circ_inc32( &nextIdx, GMAC_RX_BUFFERS );
} while( ( pxHead->status.val & GMAC_RXD_EOF ) == 0 );
p_gmac_dev->ul_rx_idx = nextIdx;
*p_rcv_size = bytesLeft;
/* #warning Just for debugging */
/* NVIC_EnableIRQ( GMAC_IRQn ); */
return GMAC_OK;
}
extern void vGMACGenerateChecksum( uint8_t * apBuffer,
size_t uxLength );
/**
* \brief Send ulLength bytes from pcFrom. This copies the buffer to one of the
* GMAC Tx buffers, and then indicates to the GMAC that the buffer is ready.
* If lEndOfFrame is true then the data being copied is the end of the frame
* and the frame can be transmitted.
*
* \param p_gmac_dev Pointer to the GMAC device instance.
* \param p_buffer Pointer to the data buffer.
* \param ul_size Length of the frame.
*
* \return Length sent.
*/
uint32_t gmac_dev_write( gmac_device_t * p_gmac_dev,
void * p_buffer,
uint32_t ul_size )
{
volatile gmac_tx_descriptor_t * p_tx_td;
Gmac * p_hw = p_gmac_dev->p_hw;
/* Check parameter */
if( ul_size > GMAC_TX_UNITSIZE )
{
return GMAC_PARAM;
}
/* Pointers to the current transmit descriptor */
p_tx_td = &gs_tx_desc[ p_gmac_dev->l_tx_head ];
/* If no free TxTd, buffer can't be sent, schedule the wakeup callback */
if( ( p_tx_td->status.val & GMAC_TXD_USED ) == 0 )
{
return GMAC_TX_BUSY;
}
/* Set up/copy data to transmission buffer */
if( p_buffer && ul_size )
{
/* Driver manages the ring buffer */
/* Calculating the checksum here is faster than calculating it from the GMAC buffer
* because within p_buffer, it is well aligned */
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
/* Zero-copy... */
p_tx_td->addr = ( uint32_t ) p_buffer;
}
#else
{
/* Or memcopy... */
memcpy( ( void * ) p_tx_td->addr, p_buffer, ul_size );
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
vGMACGenerateChecksum( ( uint8_t * ) p_tx_td->addr, ( size_t ) ul_size );
}
/*#warning Trying out */
gmac_start_transmission( p_hw );
/* Update transmit descriptor status */
/* The buffer size defined is the length of ethernet frame,
* so it's always the last buffer of the frame. */
if( p_gmac_dev->l_tx_head == ( int32_t ) ( GMAC_TX_BUFFERS - 1 ) )
{
/* No need to 'and' with GMAC_TXD_LEN_MASK because ul_size has been checked
* GMAC_TXD_USED will now be cleared. */
p_tx_td->status.val =
ul_size | GMAC_TXD_LAST | GMAC_TXD_WRAP;
}
else
{
/* GMAC_TXD_USED will now be cleared. */
p_tx_td->status.val =
ul_size | GMAC_TXD_LAST;
}
circ_inc32( &p_gmac_dev->l_tx_head, GMAC_TX_BUFFERS );
/* Now start to transmit if it is still not done */
gmac_start_transmission( p_hw );
return GMAC_OK;
}
/**
* \brief Get current load of transmit.
*
* \param p_gmac_dev Pointer to the GMAC device instance.
*
* \return Current load of transmit.
*/
uint32_t gmac_dev_get_tx_load( gmac_device_t * p_gmac_dev )
{
uint16_t us_head = p_gmac_dev->l_tx_head;
uint16_t us_tail = p_gmac_dev->l_tx_tail;
return CIRC_CNT( us_head, us_tail, GMAC_TX_BUFFERS );
}
/**
* \brief Register/Clear TX wakeup callback.
*
* When gmac_dev_write() returns GMAC_TX_BUSY (all transmit descriptor busy), the application
* task calls gmac_dev_set_tx_wakeup_callback() to register func_wakeup() callback and
* enters suspend state. The callback is in charge to resume the task once
* several transmit descriptors have been released. The next time gmac_dev_write() will be called,
* it shall be successful.
*
* This function is usually invoked with NULL callback from the TX wakeup
* callback itself, to unregister. Once the callback has resumed the
* application task, there is no need to invoke the callback again.
*
* \param p_gmac_dev Pointer to GMAC device instance.
* \param func_wakeup Pointer to wakeup callback function.
* \param uc_threshold Number of free transmit descriptor before wakeup callback invoked.
*
* \return GMAC_OK, GMAC_PARAM on parameter error.
*/
#if ( GMAC_USES_WAKEUP_CALLBACK )
uint8_t gmac_dev_set_tx_wakeup_callback( gmac_device_t * p_gmac_dev,
gmac_dev_wakeup_cb_t func_wakeup_cb,
uint8_t uc_threshold )
{
if( func_wakeup_cb == NULL )
{
p_gmac_dev->func_wakeup_cb = NULL;
}
else
{
if( uc_threshold <= GMAC_TX_BUFFERS )
{
p_gmac_dev->func_wakeup_cb = func_wakeup_cb;
p_gmac_dev->ul_wakeup_threshold = ( uint32_t ) uc_threshold;
}
else
{
return GMAC_PARAM;
}
}
return GMAC_OK;
}
#endif /* GMAC_USES_WAKEUP_CALLBACK */
/**
* \brief Reset TX & RX queue & statistics.
*
* \param p_gmac_dev Pointer to GMAC device instance.
*/
void gmac_dev_reset( gmac_device_t * p_gmac_dev )
{
Gmac * p_hw = p_gmac_dev->p_hw;
gmac_reset_rx_mem( p_gmac_dev );
gmac_reset_tx_mem( p_gmac_dev );
gmac_network_control( p_hw, GMAC_NCR_TXEN | GMAC_NCR_RXEN
| GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT );
}
void gmac_dev_halt( Gmac * p_gmac );
void gmac_dev_halt( Gmac * p_gmac )
{
gmac_network_control( p_gmac, GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT );
gmac_disable_interrupt( p_gmac, ~0u );
}
/**
* \brief GMAC Interrupt handler.
*
* \param p_gmac_dev Pointer to GMAC device instance.
*/
#if ( GMAC_STATS != 0 )
extern int logPrintf( const char * pcFormat,
... );
void gmac_show_irq_counts()
{
int index;
for( index = 0; index < ARRAY_SIZE( intPairs ); index++ )
{
if( gmacStats.intStatus[ intPairs[ index ].index ] )
{
logPrintf( "%s : %6u\n", intPairs[ index ].name, gmacStats.intStatus[ intPairs[ index ].index ] );
}
}
}
#endif /* if ( GMAC_STATS != 0 ) */
void gmac_handler( gmac_device_t * p_gmac_dev )
{
Gmac * p_hw = p_gmac_dev->p_hw;
gmac_tx_descriptor_t * p_tx_td;
uint32_t ul_tx_status_flag;
#if ( GMAC_STATS != 0 )
int index;
#endif
uint32_t ul_isr = gmac_get_interrupt_status( p_hw );
uint32_t ul_rsr = gmac_get_rx_status( p_hw );
uint32_t ul_tsr = gmac_get_tx_status( p_hw );
#if ( GMAC_STATS != 0 )
{
for( index = 0; index < ARRAY_SIZE( intPairs ); index++ )
{
if( ul_isr & intPairs[ index ].mask )
{
gmacStats.intStatus[ intPairs[ index ].index ]++;
}
}
}
#endif /* GMAC_STATS != 0 */
/* RX packet */
if( ( ul_isr & GMAC_ISR_RCOMP ) || ( ul_rsr & ( GMAC_RSR_REC | GMAC_RSR_RXOVR | GMAC_RSR_BNA ) ) )
{
/* Clear status */
gmac_clear_rx_status( p_hw, ul_rsr );
if( ul_isr & GMAC_ISR_RCOMP )
{
ul_rsr |= GMAC_RSR_REC;
}
/* Invoke callbacks which can be useful to wake up a task */
xRxCallback( ul_rsr );
}
/* TX packet */
if( ( ul_isr & GMAC_ISR_TCOMP ) || ( ul_tsr & ( GMAC_TSR_TXCOMP | GMAC_TSR_COL | GMAC_TSR_RLE | GMAC_TSR_UND ) ) )
{
ul_tx_status_flag = GMAC_TSR_TXCOMP;
/* A frame transmitted */
/* Check RLE */
if( ul_tsr & GMAC_TSR_RLE )
{
/* Status RLE & Number of discarded buffers */
ul_tx_status_flag = GMAC_TSR_RLE | CIRC_CNT( p_gmac_dev->l_tx_head,
p_gmac_dev->l_tx_tail, GMAC_TX_BUFFERS );
gmac_reset_tx_mem( p_gmac_dev );
gmac_enable_transmit( p_hw, 1 );
}
/* Clear status */
gmac_clear_tx_status( p_hw, ul_tsr );
if( !CIRC_EMPTY( p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail ) )
{
/* Check the buffers */
do
{
p_tx_td = &gs_tx_desc[ p_gmac_dev->l_tx_tail ];
/* Any error? Exit if buffer has not been sent yet */
if( ( p_tx_td->status.val & GMAC_TXD_USED ) == 0 )
{
break;
}
/* Notify upper layer that a packet has been sent */
xTxCallback( ul_tx_status_flag, ( void * ) p_tx_td->addr ); /* Function call prvTxCallback */
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
p_tx_td->addr = 0ul;
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
circ_inc32( &p_gmac_dev->l_tx_tail, GMAC_TX_BUFFERS );
} while( CIRC_CNT( p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,
GMAC_TX_BUFFERS ) );
}
if( ul_tsr & GMAC_TSR_RLE )
{
/* Notify upper layer RLE */
xTxCallback( ul_tx_status_flag, NULL );
}
#if ( GMAC_USES_WAKEUP_CALLBACK )
/* If a wakeup has been scheduled, notify upper layer that it can
* send other packets, and the sending will be successful. */
if( ( CIRC_SPACE( p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,
GMAC_TX_BUFFERS ) >= p_gmac_dev->ul_wakeup_threshold ) &&
p_gmac_dev->func_wakeup_cb )
{
p_gmac_dev->func_wakeup_cb();
}
#endif
}
}
/*@} */
/*/ @cond 0 */
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/*/ @endcond */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,270 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/* Standard includes. */
#include <stdint.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* Hardware abstraction. */
#include "FreeRTOS_IO.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_Sockets.h"
#include "NetworkBufferManagement.h"
/* Driver includes. */
#include "lpc17xx_emac.h"
#include "lpc17xx_pinsel.h"
/* Demo includes. */
#include "NetworkInterface.h"
#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
#else
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
#endif
/* When a packet is ready to be sent, if it cannot be sent immediately then the
* task performing the transmit will block for niTX_BUFFER_FREE_WAIT
* milliseconds. It will do this a maximum of niMAX_TX_ATTEMPTS before giving
* up. */
#define niTX_BUFFER_FREE_WAIT ( pdMS_TO_TICKS( 2UL ) )
#define niMAX_TX_ATTEMPTS ( 5 )
/* The length of the queue used to send interrupt status words from the
* interrupt handler to the deferred handler task. */
#define niINTERRUPT_QUEUE_LENGTH ( 10 )
/*-----------------------------------------------------------*/
/*
* A deferred interrupt handler task that processes
*/
static void prvEMACHandlerTask( void * pvParameters );
/*-----------------------------------------------------------*/
/* The queue used to communicate Ethernet events with the IP task. */
extern QueueHandle_t xNetworkEventQueue;
/* The semaphore used to wake the deferred interrupt handler task when an Rx
* interrupt is received. */
static SemaphoreHandle_t xEMACRxEventSemaphore = NULL;
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceInitialise( void )
{
EMAC_CFG_Type Emac_Config;
PINSEL_CFG_Type xPinConfig;
BaseType_t xStatus, xReturn;
/* Enable Ethernet Pins */
boardCONFIGURE_ENET_PINS( xPinConfig );
Emac_Config.Mode = EMAC_MODE_AUTO;
Emac_Config.pbEMAC_Addr = ipLOCAL_MAC_ADDRESS;
xStatus = EMAC_Init( &Emac_Config );
LPC_EMAC->IntEnable &= ~( EMAC_INT_TX_DONE );
if( xStatus != ERROR )
{
vSemaphoreCreateBinary( xEMACRxEventSemaphore );
configASSERT( xEMACRxEventSemaphore != NULL );
/* The handler task is created at the highest possible priority to
* ensure the interrupt handler can return directly to it. */
xTaskCreate( prvEMACHandlerTask, "EMAC", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );
/* Enable the interrupt and set its priority to the minimum
* interrupt priority. */
NVIC_SetPriority( ENET_IRQn, configMAC_INTERRUPT_PRIORITY );
NVIC_EnableIRQ( ENET_IRQn );
xReturn = pdPASS;
}
else
{
xReturn = pdFAIL;
}
configASSERT( xStatus != ERROR );
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
BaseType_t xReturn = pdFAIL;
int32_t x;
extern void EMAC_StartTransmitNextBuffer( uint32_t ulLength );
extern void EMAC_SetNextPacketToSend( uint8_t * pucBuffer );
/* Attempt to obtain access to a Tx buffer. */
for( x = 0; x < niMAX_TX_ATTEMPTS; x++ )
{
if( EMAC_CheckTransmitIndex() == TRUE )
{
/* Will the data fit in the Tx buffer? */
if( pxNetworkBuffer->xDataLength < EMAC_ETH_MAX_FLEN ) /*_RB_ The size needs to come from FreeRTOSIPConfig.h. */
{
/* Assign the buffer to the Tx descriptor that is now known to
* be free. */
EMAC_SetNextPacketToSend( pxNetworkBuffer->pucBuffer );
/* The EMAC now owns the buffer. */
pxNetworkBuffer->pucBuffer = NULL;
/* Initiate the Tx. */
EMAC_StartTransmitNextBuffer( pxNetworkBuffer->xDataLength );
iptraceNETWORK_INTERFACE_TRANSMIT();
/* The Tx has been initiated. */
xReturn = pdPASS;
}
break;
}
else
{
vTaskDelay( niTX_BUFFER_FREE_WAIT );
}
}
/* Finished with the network buffer. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
return xReturn;
}
/*-----------------------------------------------------------*/
void ENET_IRQHandler( void )
{
uint32_t ulInterruptCause;
while( ( ulInterruptCause = LPC_EMAC->IntStatus ) != 0 )
{
/* Clear the interrupt. */
LPC_EMAC->IntClear = ulInterruptCause;
/* Clear fatal error conditions. NOTE: The driver does not clear all
* errors, only those actually experienced. For future reference, range
* errors are not actually errors so can be ignored. */
if( ( ulInterruptCause & EMAC_INT_TX_UNDERRUN ) != 0U )
{
LPC_EMAC->Command |= EMAC_CR_TX_RES;
}
/* Unblock the deferred interrupt handler task if the event was an
* Rx. */
if( ( ulInterruptCause & EMAC_INT_RX_DONE ) != 0UL )
{
xSemaphoreGiveFromISR( xEMACRxEventSemaphore, NULL );
}
}
/* ulInterruptCause is used for convenience here. A context switch is
* wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a
* compiler warning. */
portEND_SWITCHING_ISR( ulInterruptCause );
}
/*-----------------------------------------------------------*/
static void prvEMACHandlerTask( void * pvParameters )
{
size_t xDataLength;
const uint16_t usCRCLength = 4;
NetworkBufferDescriptor_t * pxNetworkBuffer;
IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
/* This is not included in the header file for some reason. */
extern uint8_t * EMAC_NextPacketToRead( void );
( void ) pvParameters;
configASSERT( xEMACRxEventSemaphore != NULL );
for( ; ; )
{
/* Wait for the EMAC interrupt to indicate that another packet has been
* received. The while() loop is only needed if INCLUDE_vTaskSuspend is
* set to 0 in FreeRTOSConfig.h. */
while( xSemaphoreTake( xEMACRxEventSemaphore, portMAX_DELAY ) == pdFALSE )
{
}
/* At least one packet has been received. */
while( EMAC_CheckReceiveIndex() != FALSE )
{
/* Obtain the length, minus the CRC. The CRC is four bytes
* but the length is already minus 1. */
xDataLength = ( size_t ) EMAC_GetReceiveDataSize() - ( usCRCLength - 1U );
if( xDataLength > 0U )
{
/* Obtain a network buffer to pass this data into the
* stack. No storage is required as the network buffer
* will point directly to the buffer that already holds
* the received data. */
pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( 0, ( TickType_t ) 0 );
if( pxNetworkBuffer != NULL )
{
pxNetworkBuffer->pucBuffer = EMAC_NextPacketToRead();
pxNetworkBuffer->xDataLength = xDataLength;
xRxEvent.pvData = ( void * ) pxNetworkBuffer;
/* Data was received and stored. Send a message to the IP
* task to let it know. */
if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
{
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
iptraceETHERNET_RX_EVENT_LOST();
}
}
else
{
iptraceETHERNET_RX_EVENT_LOST();
}
iptraceNETWORK_INTERFACE_RECEIVE();
}
/* Release the frame. */
EMAC_UpdateRxConsumeIndex();
}
}
}
/*-----------------------------------------------------------*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
NetworkInterface.c:
Requires NXP's LPCOpen library and was developed on an LPC1830 and LPC1835 Xplorer
boards from NGX.

View File

@ -0,0 +1,382 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/* FreeRTOS includes. */
#include "LPC54018.h"
#include "FreeRTOS.h"
#include "list.h"
#include <stdbool.h>
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_IP_Private.h"
#include "NetworkBufferManagement.h"
#include "fsl_enet.h"
#include "fsl_phy.h"
#include "fsl_enet_mdio.h"
#include "fsl_phylan8720a.h"
#include "fsl_debug_console.h"
#define PHY_ADDRESS ( 0x00U )
/* MDIO operations. */
#define EXAMPLE_MDIO_OPS lpc_enet_ops
/* PHY operations. */
#define EXAMPLE_PHY_OPS phylan8720a_ops
#define ENET_RXBD_NUM ( 4 )
#define ENET_TXBD_NUM ( 4 )
#define ENET_RXBUFF_SIZE ( ENET_FRAME_MAX_FRAMELEN )
#define ENET_BuffSizeAlign( n ) ENET_ALIGN( n, ENET_BUFF_ALIGNMENT )
#define ENET_ALIGN( x, align ) ( ( unsigned int ) ( ( x ) + ( ( align ) - 1 ) ) & ( unsigned int ) ( ~( unsigned int ) ( ( align ) - 1 ) ) )
#if defined( __GNUC__ )
#ifndef __ALIGN_END
#define __ALIGN_END __attribute__( ( aligned( ENET_BUFF_ALIGNMENT ) ) )
#endif
#ifndef __ALIGN_BEGIN
#define __ALIGN_BEGIN
#endif
#else
#ifndef __ALIGN_END
#define __ALIGN_END
#endif
#ifndef __ALIGN_BEGIN
#if defined( __CC_ARM ) || defined( __ARMCC_VERSION )
#define __ALIGN_BEGIN __attribute__( ( aligned( ENET_BUFF_ALIGNMENT ) ) )
#elif defined( __ICCARM__ )
#define __ALIGN_BEGIN
#endif
#endif
#endif /* if defined( __GNUC__ ) */
/* 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
#ifndef NETWORK_INTERFACE_RX_PRIORITY
#define NETWORK_INTERFACE_RX_PRIORITY ( configMAX_PRIORITIES - 1 )
#endif
/*******************************************************************************
* Variables
******************************************************************************/
#if defined( __ICCARM__ )
#pragma data_alignment = ENET_BUFF_ALIGNMENT
#endif
__ALIGN_BEGIN enet_rx_bd_struct_t g_rxBuffDescrip[ ENET_RXBD_NUM ] __ALIGN_END;
#if defined( __ICCARM__ )
#pragma data_alignment = ENET_BUFF_ALIGNMENT
#endif
__ALIGN_BEGIN enet_tx_bd_struct_t g_txBuffDescrip[ ENET_TXBD_NUM ] __ALIGN_END;
enet_handle_t g_handle = { 0 };
/* The MAC address for ENET device. */
uint8_t g_macAddr[ 6 ] = { 0xde, 0xad, 0x00, 0xbe, 0xef, 0x01 };
bool g_linkStatus = false;
/*! @brief Enet PHY and MDIO interface handler. */
static mdio_handle_t mdioHandle = { .ops = &EXAMPLE_MDIO_OPS };
static phy_handle_t phyHandle = { .phyAddr = PHY_ADDRESS, .mdioHandle = &mdioHandle, .ops = &EXAMPLE_PHY_OPS };
__ALIGN_BEGIN uint32_t receiveBuffer[ ENET_RXBD_NUM ][ ENET_RXBUFF_SIZE / sizeof( uint32_t ) + 1 ] __ALIGN_END;
uint32_t rxbuffer[ ENET_RXBD_NUM ];
TaskHandle_t receiveTaskHandle;
void ENET_IntCallback( ENET_Type * base,
enet_handle_t * handle,
enet_event_t event,
uint8_t channel,
void * param )
{
BaseType_t needsToYield = pdFALSE;
switch( event )
{
case kENET_TxIntEvent:
break;
case kENET_RxIntEvent:
vTaskNotifyGiveFromISR( receiveTaskHandle, &needsToYield );
portEND_SWITCHING_ISR( needsToYield );
break;
default:
break;
}
}
static void prvProcessFrame( int length )
{
NetworkBufferDescriptor_t * pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( length, 0 );
if( pxBufferDescriptor != NULL )
{
ENET_ReadFrame( ENET, &g_handle, pxBufferDescriptor->pucEthernetBuffer, length, 0 );
pxBufferDescriptor->xDataLength = length;
if( ipCONSIDER_FRAME_FOR_PROCESSING( pxBufferDescriptor->pucEthernetBuffer ) == eProcessBuffer )
{
IPStackEvent_t xRxEvent;
xRxEvent.eEventType = eNetworkRxEvent;
xRxEvent.pvData = ( void * ) pxBufferDescriptor;
if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE )
{
vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
iptraceETHERNET_RX_EVENT_LOST();
PRINTF( "RX Event Lost\n" );
}
}
else
{
PRINTF( "RX Event not to be considered\n" );
vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
/* Not sure if a trace is required. The stack did not want this message */
}
}
else
{
PRINTF( "RX No Buffer Available\n" );
ENET_ReadFrame( ENET, &g_handle, NULL, 0, 0 );
/* No buffer available to receive this message */
iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
}
}
static void rx_task( void * parameter )
{
while( pdTRUE )
{
if( ulTaskNotifyTake( pdTRUE, pdMS_TO_TICKS( 500 ) ) == pdFALSE ) /* no RX packets for a bit so check for a link */
{
PHY_GetLinkStatus( &phyHandle, &g_linkStatus );
}
else
{
BaseType_t receiving = pdTRUE;
while( receiving == pdTRUE )
{
uint32_t length;
const status_t status = ENET_GetRxFrameSize( ENET, &g_handle, &length, 0 );
switch( status )
{
case kStatus_Success: /* there is a frame. process it */
if( length )
{
prvProcessFrame( length );
}
break;
case kStatus_ENET_RxFrameEmpty: /* Received an empty frame. Ignore it */
receiving = pdFALSE;
break;
case kStatus_ENET_RxFrameError: /* Received an error frame. Read & drop it */
PRINTF( "RX Receive Error\n" );
ENET_ReadFrame( ENET, &g_handle, NULL, 0, 0 );
/* Not sure if a trace is required. The MAC had an error and needed to dump bytes */
break;
default:
PRINTF( "RX Receive default\n" );
break;
}
}
}
}
}
BaseType_t xGetPhyLinkStatus( void )
{
return g_linkStatus ? pdTRUE : pdFALSE;
}
BaseType_t xNetworkInterfaceInitialise( void )
{
BaseType_t returnValue = pdFAIL;
static enum
{
initPhy, waitForLink, startReceiver, configurePhy
}
networkInitialisePhase = initPhy;
switch( networkInitialisePhase )
{
default:
networkInitialisePhase = initPhy;
/* fall through */
case initPhy:
{
phy_config_t phyConfig;
phyConfig.phyAddr = PHY_ADDRESS;
phyConfig.autoNeg = true;
mdioHandle.resource.base = ENET;
status_t status = PHY_Init( &phyHandle, &phyConfig );
if( status == kStatus_PHY_AutoNegotiateFail )
{
PRINTF( "\nPHY Auto-negotiation failed. Please check the cable connection and link partner setting.\n" );
break;
}
}
case startReceiver:
networkInitialisePhase = startReceiver;
if( xTaskCreate( rx_task, "rx_task", 512, NULL, NETWORK_INTERFACE_RX_PRIORITY, &receiveTaskHandle ) != pdPASS )
{
PRINTF( "Network Receive Task creation failed!.\n" );
break;
}
/* fall through */
case waitForLink:
networkInitialisePhase = waitForLink;
{
if( !xGetPhyLinkStatus() )
{
PRINTF( "No Link\n" );
break;
}
}
/* fall through */
case configurePhy:
{
networkInitialisePhase = configurePhy;
enet_config_t config;
phy_speed_t speed;
phy_duplex_t duplex;
PHY_GetLinkSpeedDuplex( &phyHandle, &speed, &duplex );
/* Get default configuration 100M RMII. */
ENET_GetDefaultConfig( &config );
/* Use the actual speed and duplex when phy success to finish the autonegotiation. */
config.miiSpeed = ( enet_mii_speed_t ) speed;
config.miiDuplex = ( enet_mii_duplex_t ) duplex;
/* Initialize ENET. */
uint32_t refClock = 50000000; /* 50MHZ for rmii reference clock. */
ENET_Init( ENET, &config, g_macAddr, refClock );
/* Enable the rx interrupt. */
ENET_EnableInterrupts( ENET, ( kENET_DmaRx ) );
/* Initialize Descriptor. */
int bufferIndex;
for( bufferIndex = 0; bufferIndex < ENET_RXBD_NUM; bufferIndex++ )
{
rxbuffer[ bufferIndex ] = ( uint32_t ) &receiveBuffer[ bufferIndex ];
}
/* prepare the buffer configuration. */
enet_buffer_config_t buffConfig[ 1 ] =
{
{
ENET_RXBD_NUM, ENET_TXBD_NUM,
&g_txBuffDescrip[ 0 ], &g_txBuffDescrip[ 0 ],
&g_rxBuffDescrip[ 0 ], &g_rxBuffDescrip[ ENET_RXBD_NUM ],
&rxbuffer[ 0 ], ENET_BuffSizeAlign( ENET_RXBUFF_SIZE ),
}
};
ENET_DescriptorInit( ENET, &config, &buffConfig[ 0 ] );
/* Create the handler. */
ENET_CreateHandler( ENET, &g_handle, &config, &buffConfig[ 0 ], ENET_IntCallback, NULL );
NVIC_SetPriority( 65 - 16, 4 ); /* TODO this is a hack and I would expect a nice ENET API for priority. */
/* Active TX/RX. */
ENET_StartRxTx( ENET, 1, 1 );
}
returnValue = pdPASS;
break;
}
return returnValue;
}
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer,
BaseType_t xReleaseAfterSend )
{
BaseType_t response = pdFALSE;
status_t status;
if( xGetPhyLinkStatus() )
{
status = ENET_SendFrame( ENET, &g_handle, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
switch( status )
{
default: /* anything not Success will be a failure */
case kStatus_ENET_TxFrameBusy:
PRINTF( "TX Frame Busy\n" );
break;
case kStatus_Success:
iptraceNETWORK_INTERFACE_TRANSMIT();
response = pdTRUE;
break;
}
}
if( xReleaseAfterSend != pdFALSE )
{
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
}
return response;
}
/* statically allocate the buffers */
/* allocating them as uint32_t's to force them into word alignment, a requirement of the DMA. */
__ALIGN_BEGIN static uint32_t buffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ][ ( ipBUFFER_PADDING + ENET_RXBUFF_SIZE ) / sizeof( uint32_t ) + 1 ] __ALIGN_END;
void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
{
for( int x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
{
pxNetworkBuffers[ x ].pucEthernetBuffer = ( uint8_t * ) &buffers[ x ][ 0 ] + ipBUFFER_PADDING;
buffers[ x ][ 0 ] = ( uint32_t ) &pxNetworkBuffers[ x ];
}
}

View File

@ -0,0 +1,355 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "list.h"
#include "queue.h"
#include "semphr.h"
#include "task.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "NetworkBufferManagement.h"
#include "NetworkInterface.h"
#include "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;
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 );
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;
}
}

View File

@ -0,0 +1,497 @@
/**************************************************************************//**
* @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 ];
}
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 ];
}
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 because we just RESET EMAC... */
/* 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 occurred */
{
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 );
}

View File

@ -0,0 +1,171 @@
/**************************************************************************//**
* @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 /* Power down 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 TIME_STAMPING */
#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_ */

View File

@ -0,0 +1,370 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://github.com/FreeRTOS
* https://www.FreeRTOS.org
*/
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "list.h"
#include "task.h"
#include "semphr.h"
/* Standard library definitions */
#include <string.h>
#include <limits.h>
/* FreeRTOS+TCP includes. */
#include <FreeRTOS_IP.h>
#include <FreeRTOS_IP_Private.h>
#include <NetworkInterface.h>
#include <NetworkBufferManagement.h>
/* PHY includes. */
#include "SMM_MPS2.h"
#include "ether_lan9118/smsc9220_eth_drv.h"
#include "ether_lan9118/smsc9220_emac_config.h"
/* Sets the size of the stack (in words, not bytes) of the task that reads bytes
* from the network. */
#ifndef nwRX_TASK_STACK_SIZE
#define nwRX_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE * 2 )
#endif
#ifndef nwETHERNET_RX_HANDLER_TASK_PRIORITY
#define nwETHERNET_RX_HANDLER_TASK_PRIORITY ( configMAX_PRIORITIES - 3 )
#endif
/* The number of attempts to get a successful call to smsc9220_send_by_chunks()
* when transmitting a packet before giving up. */
#define niMAX_TX_ATTEMPTS ( 5 )
/* Address of ISER and ICER registers in the Cortex-M NVIC. */
#define nwNVIC_ISER ( *( ( volatile uint32_t * ) 0xE000E100UL ) )
#define nwNVIC_ICER ( *( ( volatile uint32_t * ) 0xE000E180UL ) )
/*-----------------------------------------------------------*/
/*
* The task that processes incoming Ethernet packets. It is unblocked by the
* Ethernet Rx interrupt.
*/
static void prvRxTask( void * pvParameters );
/*
* Performs low level reads to obtain data from the Ethernet hardware.
*/
static uint32_t prvLowLevelInput( NetworkBufferDescriptor_t ** pxNetworkBuffer );
static void prvWait_ms( uint32_t ulSleep_ms );
static void prvSetMACAddress( void );
/*-----------------------------------------------------------*/
static const struct smsc9220_eth_dev_cfg_t SMSC9220_ETH_DEV_CFG =
{
.base = SMSC9220_BASE
};
static struct smsc9220_eth_dev_data_t SMSC9220_ETH_DEV_DATA =
{
.state = 0
};
static const struct smsc9220_eth_dev_t SMSC9220_ETH_DEV =
{
&( SMSC9220_ETH_DEV_CFG ),
&( SMSC9220_ETH_DEV_DATA )
};
static TaskHandle_t xRxTaskHandle = NULL;
/*-----------------------------------------------------------*/
static void prvWait_ms( uint32_t ulSleep_ms )
{
vTaskDelay( pdMS_TO_TICKS( ulSleep_ms ) );
}
/*-----------------------------------------------------------*/
static void prvSetMACAddress( void )
{
const struct smsc9220_eth_dev_t * dev = &SMSC9220_ETH_DEV;
uint32_t ucMACLow = 0;
uint32_t ucMACHigh = 0;
/* Using local variables to make sure the right alignment is used. The MAC
* address is 6 bytes, hence the copy of 4 bytes followed by 2 bytes. */
memcpy( ( void * ) &ucMACLow, ( void * ) ipLOCAL_MAC_ADDRESS, 4 );
memcpy( ( void * ) &ucMACHigh, ( void * ) ( ipLOCAL_MAC_ADDRESS + 4 ), 2 );
if( smsc9220_mac_regwrite( dev, SMSC9220_MAC_REG_OFFSET_ADDRL, ucMACLow ) != 0 )
{
smsc9220_mac_regwrite( dev, SMSC9220_MAC_REG_OFFSET_ADDRH, ucMACHigh );
}
}
/*-----------------------------------------------------------*/
static void prvRxTask( void * pvParameters )
{
const TickType_t xBlockTime = pdMS_TO_TICKS( 1500UL );
const struct smsc9220_eth_dev_t * dev = &SMSC9220_ETH_DEV;
IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
NetworkBufferDescriptor_t * pxNetworkBuffer = NULL;
uint32_t ulDataRead;
( void ) pvParameters;
for( ; ; )
{
/* Wait for the Ethernet ISR to receive a packet. */
ulTaskNotifyTake( pdFALSE, xBlockTime );
while( ( ulDataRead = prvLowLevelInput( &pxNetworkBuffer ) ) != 0UL )
{
xRxEvent.pvData = ( void * ) pxNetworkBuffer;
if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
{
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
}
}
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL ); /*_RB_ Can this move up. */
}
}
/*-----------------------------------------------------------*/
static uint32_t prvLowLevelInput( NetworkBufferDescriptor_t ** pxNetworkBuffer )
{
const struct smsc9220_eth_dev_t * dev = &SMSC9220_ETH_DEV;
const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250UL );
uint32_t ulMessageLength = 0, ulReceivedBytes = 0;
ulMessageLength = smsc9220_peek_next_packet_size( dev );
if( ulMessageLength != 0 )
{
*pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ulMessageLength,
xDescriptorWaitTime );
if( *pxNetworkBuffer != NULL )
{
( *pxNetworkBuffer )->xDataLength = ulMessageLength;
ulReceivedBytes = smsc9220_receive_by_chunks( dev,
( char * ) ( ( *pxNetworkBuffer )->pucEthernetBuffer ),
ulMessageLength ); /* not used */
( *pxNetworkBuffer )->xDataLength = ulReceivedBytes;
}
else
{
FreeRTOS_printf( ( "pxNetworkBuffer = NULL\n" ) );
}
}
return ulReceivedBytes;
}
/*-----------------------------------------------------------*/
void EthernetISR( void )
{
const struct smsc9220_eth_dev_t * dev = &SMSC9220_ETH_DEV;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
uint32_t ulIRQStatus;
const uint32_t ulRXFifoStatusIRQBit = 1UL << SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL;
extern uint32_t get_irq_status( const struct smsc9220_eth_dev_t * dev );
/* Should not enable this interrupt until after the handler task has been
* created. */
configASSERT( xRxTaskHandle );
ulIRQStatus = get_irq_status( dev );
if( ( ulIRQStatus & ulRXFifoStatusIRQBit ) != 0 )
{
/* Unblock the task that will process this interrupt. */
vTaskNotifyGiveFromISR( xRxTaskHandle, &xHigherPriorityTaskWoken );
smsc9220_clear_interrupt( dev, SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL );
/* Re-enabled by the task that handles the incoming packet. */ /*_RB_ Is this necessary? */
smsc9220_disable_interrupt( dev, SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL );
}
smsc9220_clear_all_interrupts( dev );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceInitialise( void )
{
const struct smsc9220_eth_dev_t * dev = &SMSC9220_ETH_DEV;
const uint32_t ulEthernetIRQ = 13UL;
BaseType_t xReturn = pdFAIL;
enum smsc9220_error_t err;
if( xRxTaskHandle == NULL )
{
/* Task has not been created before. */
xReturn = xTaskCreate( prvRxTask,
"EMAC",
nwRX_TASK_STACK_SIZE,
NULL,
nwETHERNET_RX_HANDLER_TASK_PRIORITY,
&xRxTaskHandle );
configASSERT( xReturn != pdFALSE );
}
if( xReturn == pdPASS )
{
err = smsc9220_init( dev, prvWait_ms );
if( err != SMSC9220_ERROR_NONE )
{
FreeRTOS_debug_printf( ( "%s: %d\n", "smsc9220_init failed", err ) );
xReturn = pdFAIL;
}
else
{
/* Disable the Ethernet interrupt in the NVIC. */
nwNVIC_ICER = ( uint32_t ) ( 1UL << ( ulEthernetIRQ & 0x1FUL ) );
smsc9220_disable_all_interrupts( dev );
smsc9220_clear_all_interrupts( dev );
smsc9220_set_fifo_level_irq( dev, SMSC9220_FIFO_LEVEL_IRQ_RX_STATUS_POS,
SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MIN );
smsc9220_set_fifo_level_irq( dev, SMSC9220_FIFO_LEVEL_IRQ_TX_STATUS_POS,
SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MIN );
smsc9220_set_fifo_level_irq( dev, SMSC9220_FIFO_LEVEL_IRQ_TX_DATA_POS,
SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MAX );
prvSetMACAddress();
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_GPIO0 );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_GPIO1 );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_GPIO2 );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_RX_STATUS_FIFO_FULL );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_RX_DROPPED_FRAME );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_TX_STATUS_FIFO_LEVEL );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_TX_STATUS_FIFO_FULL );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_TX_DATA_FIFO_AVAILABLE );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_TX_DATA_FIFO_OVERRUN );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_TX_ERROR );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_RX_ERROR );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_RX_WATCHDOG_TIMEOUT );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_TX_STATUS_OVERFLOW );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_TX_POWER_MANAGEMENT );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_PHY );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_GP_TIMER );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_RX_DMA );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_TX_IOC );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_RX_DROPPED_FRAME_HALF );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_RX_STOPPED );
smsc9220_enable_interrupt( dev, SMSC9220_INTERRUPT_TX_STOPPED );
/* Enable the Ethernet interrupt in the NVIC. */
nwNVIC_ISER = ( uint32_t ) ( 1UL << ( ulEthernetIRQ & 0x1FUL ) );
xReturn = pdPASS;
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer,
BaseType_t xReleaseAfterSend )
{
const struct smsc9220_eth_dev_t * dev = &SMSC9220_ETH_DEV;
enum smsc9220_error_t error = SMSC9220_ERROR_NONE;
BaseType_t xReturn = pdFAIL, x;
for( x = 0; x < niMAX_TX_ATTEMPTS; x++ )
{
if( pxNetworkBuffer->xDataLength < SMSC9220_ETH_MAX_FRAME_SIZE )
{
error = smsc9220_send_by_chunks( dev,
pxNetworkBuffer->xDataLength,
true,
( char * ) ( pxNetworkBuffer->pucEthernetBuffer ),
pxNetworkBuffer->xDataLength );
if( error == SMSC9220_ERROR_NONE )
{
xReturn = pdPASS;
break;
}
else
{
xReturn = pdFAIL;
FreeRTOS_debug_printf( ( "Error send by chuncks: %d\n",
error ) );
}
}
else
{
xReturn = pdFAIL;
FreeRTOS_debug_printf( ( "Packet size too large:%d\n",
pxNetworkBuffer->xDataLength ) );
break;
}
}
if( xReleaseAfterSend == pdTRUE )
{
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
}
return xReturn;
}
/*-----------------------------------------------------------*/
void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
{
/* FIX ME if you want to use BufferAllocation_1.c, which uses statically
* allocated network buffers. */
/* Hard force an assert as this driver cannot be used with BufferAllocation_1.c
* without implementing this function. */
configASSERT( xRxTaskHandle == ( TaskHandle_t ) 1 );
( void ) pxNetworkBuffers;
}
/*-----------------------------------------------------------*/
BaseType_t xGetPhyLinkStatus( void )
{
const struct smsc9220_eth_dev_t * dev = &SMSC9220_ETH_DEV;
uint32_t ulPHYBasicStatusValue;
BaseType_t xLinkStatusUp;
/* Get current status */
smsc9220_phy_regread( dev, SMSC9220_PHY_REG_OFFSET_BSTATUS,
&ulPHYBasicStatusValue );
xLinkStatusUp = ( bool ) ( ulPHYBasicStatusValue &
( 1ul << ( PHY_REG_BSTATUS_LINK_STATUS_INDEX ) ) );
return xLinkStatusUp;
}

View File

@ -0,0 +1,615 @@
/*
* copyright (c) 2006-2016 ARM Limited
* SPDX-License-Identifier: BSD-3-Clause
* 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 the copyright holder 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.
*******************************************************************************
* File: smm_mps2.h
* Release: Version 1.1
*******************************************************************************/
#ifndef __SMM_MPS2_H
#define __SMM_MPS2_H
#if defined( __CC_ARM )
#pragma anon_unions
#endif
/******************************************************************************/
/* FPGA System Register declaration */
/******************************************************************************/
typedef struct
{
volatile uint32_t LED; /* Offset: 0x000 (R/W) LED connections */
/* [31:2] : Reserved */
/* [1:0] : LEDs */
uint32_t RESERVED1[ 1 ];
volatile uint32_t BUTTON; /* Offset: 0x008 (R/W) Buttons */
/* [31:2] : Reserved */
/* [1:0] : Buttons */
uint32_t RESERVED2[ 1 ];
volatile uint32_t CLK1HZ; /* Offset: 0x010 (R/W) 1Hz up counter */
volatile uint32_t CLK100HZ; /* Offset: 0x014 (R/W) 100Hz up counter */
volatile uint32_t COUNTER; /* Offset: 0x018 (R/W) Cycle Up Counter */
/* Increments when 32-bit prescale counter reach zero */
uint32_t RESERVED3[ 1 ];
volatile uint32_t PRESCALE; /* Offset: 0x020 (R/W) Prescaler */
/* Bit[31:0] : reload value for prescale counter */
volatile uint32_t PSCNTR; /* Offset: 0x024 (R/W) 32-bit Prescale counter */
/* current value of the pre-scaler counter */
/* The Cycle Up Counter increment when the prescale down counter reach 0 */
/* The pre-scaler counter is reloaded with PRESCALE after reaching 0. */
uint32_t RESERVED4[ 9 ];
volatile uint32_t MISC; /* Offset: 0x04C (R/W) Misc control * / */
/* [31:10] : Reserved */
/* [9] : SHIELD_1_SPI_nCS */
/* [8] : SHIELD_0_SPI_nCS */
/* [7] : ADC_SPI_nCS */
/* [6] : CLCD_BL_CTRL */
/* [5] : CLCD_RD */
/* [4] : CLCD_RS */
/* [3] : CLCD_RESET */
/* [2] : RESERVED */
/* [1] : SPI_nSS */
/* [0] : CLCD_CS */
} MPS2_FPGAIO_TypeDef;
/* MISC register bit definitions */
#define CLCD_CS_Pos 0
#define CLCD_CS_Msk ( 1UL << CLCD_CS_Pos )
#define SPI_nSS_Pos 1
#define SPI_nSS_Msk ( 1UL << SPI_nSS_Pos )
#define CLCD_RESET_Pos 3
#define CLCD_RESET_Msk ( 1UL << CLCD_RESET_Pos )
#define CLCD_RS_Pos 4
#define CLCD_RS_Msk ( 1UL << CLCD_RS_Pos )
#define CLCD_RD_Pos 5
#define CLCD_RD_Msk ( 1UL << CLCD_RD_Pos )
#define CLCD_BL_Pos 6
#define CLCD_BL_Msk ( 1UL << CLCD_BL_Pos )
#define ADC_nCS_Pos 7
#define ADC_nCS_Msk ( 1UL << ADC_nCS_Pos )
#define SHIELD_0_nCS_Pos 8
#define SHIELD_0_nCS_Msk ( 1UL << SHIELD_0_nCS_Pos )
#define SHIELD_1_nCS_Pos 9
#define SHIELD_1_nCS_Msk ( 1UL << SHIELD_1_nCS_Pos )
/******************************************************************************/
/* SCC Register declaration */
/******************************************************************************/
typedef struct /* */
{
volatile uint32_t CFG_REG0; /* Offset: 0x000 (R/W) Remaps block RAM to ZBT */
/* [31:1] : Reserved */
/* [0] 1 : REMAP BlockRam to ZBT */
volatile uint32_t LEDS; /* Offset: 0x004 (R/W) Controls the MCC user LEDs */
/* [31:8] : Reserved */
/* [7:0] : MCC LEDs */
uint32_t RESERVED0[ 1 ];
volatile uint32_t SWITCHES; /* Offset: 0x00C (R/ ) Denotes the state of the MCC user switches */
/* [31:8] : Reserved */
/* [7:0] : These bits indicate state of the MCC switches */
volatile uint32_t CFG_REG4; /* Offset: 0x010 (R/ ) Denotes the board revision */
/* [31:4] : Reserved */
/* [3:0] : Used by the MCC to pass PCB revision. 0 = A 1 = B */
uint32_t RESERVED1[ 35 ];
volatile uint32_t SYS_CFGDATA_RTN; /* Offset: 0x0A0 (R/W) User data register */
/* [31:0] : Data */
volatile uint32_t SYS_CFGDATA_OUT; /* Offset: 0x0A4 (R/W) User data register */
/* [31:0] : Data */
volatile uint32_t SYS_CFGCTRL; /* Offset: 0x0A8 (R/W) Control register */
/* [31] : Start (generates interrupt on write to this bit) */
/* [30] : R/W access */
/* [29:26] : Reserved */
/* [25:20] : Function value */
/* [19:12] : Reserved */
/* [11:0] : Device (value of 0/1/2 for supported clocks) */
volatile uint32_t SYS_CFGSTAT; /* Offset: 0x0AC (R/W) Contains status information */
/* [31:2] : Reserved */
/* [1] : Error */
/* [0] : Complete */
volatile uint32_t RESERVED2[ 20 ];
volatile uint32_t SCC_DLL; /* Offset: 0x100 (R/W) DLL Lock Register */
/* [31:24] : DLL LOCK MASK[7:0] - Indicate if the DLL locked is masked */
/* [23:16] : DLL LOCK MASK[7:0] - Indicate if the DLLs are locked or unlocked */
/* [15:1] : Reserved */
/* [0] : This bit indicates if all enabled DLLs are locked */
uint32_t RESERVED3[ 957 ];
volatile uint32_t SCC_AID; /* Offset: 0xFF8 (R/ ) SCC AID Register */
/* [31:24] : FPGA build number */
/* [23:20] : V2M-MPS2 target board revision (A = 0, B = 1) */
/* [19:11] : Reserved */
/* [10] : if "1" SCC_SW register has been implemented */
/* [9] : if "1" SCC_LED register has been implemented */
/* [8] : if "1" DLL lock register has been implemented */
/* [7:0] : number of SCC configuration register */
volatile uint32_t SCC_ID; /* Offset: 0xFFC (R/ ) Contains information about the FPGA image */
/* [31:24] : Implementer ID: 0x41 = ARM */
/* [23:20] : Application note IP variant number */
/* [19:16] : IP Architecture: 0x4 =AHB */
/* [15:4] : Primary part number: 386 = AN386 */
/* [3:0] : Application note IP revision number */
} MPS2_SCC_TypeDef;
/******************************************************************************/
/* SSP Peripheral declaration */
/******************************************************************************/
typedef struct /* Document DDI0194G_ssp_pl022_r1p3_trm.pdf */
{
volatile uint32_t CR0; /* Offset: 0x000 (R/W) Control register 0 */
/* [31:16] : Reserved */
/* [15:8] : Serial clock rate */
/* [7] : SSPCLKOUT phase, applicable to Motorola SPI frame format only */
/* [6] : SSPCLKOUT polarity, applicable to Motorola SPI frame format only */
/* [5:4] : Frame format */
/* [3:0] : Data Size Select */
volatile uint32_t CR1; /* Offset: 0x004 (R/W) Control register 1 */
/* [31:4] : Reserved */
/* [3] : Slave-mode output disable */
/* [2] : Master or slave mode select */
/* [1] : Synchronous serial port enable */
/* [0] : Loop back mode */
volatile uint32_t DR; /* Offset: 0x008 (R/W) Data register */
/* [31:16] : Reserved */
/* [15:0] : Transmit/Receive FIFO */
volatile uint32_t SR; /* Offset: 0x00C (R/ ) Status register */
/* [31:5] : Reserved */
/* [4] : PrimeCell SSP busy flag */
/* [3] : Receive FIFO full */
/* [2] : Receive FIFO not empty */
/* [1] : Transmit FIFO not full */
/* [0] : Transmit FIFO empty */
volatile uint32_t CPSR; /* Offset: 0x010 (R/W) Clock prescale register */
/* [31:8] : Reserved */
/* [8:0] : Clock prescale divisor */
volatile uint32_t IMSC; /* Offset: 0x014 (R/W) Interrupt mask set or clear register */
/* [31:4] : Reserved */
/* [3] : Transmit FIFO interrupt mask */
/* [2] : Receive FIFO interrupt mask */
/* [1] : Receive timeout interrupt mask */
/* [0] : Receive overrun interrupt mask */
volatile uint32_t RIS; /* Offset: 0x018 (R/ ) Raw interrupt status register */
/* [31:4] : Reserved */
/* [3] : raw interrupt state, prior to masking, of the SSPTXINTR interrupt */
/* [2] : raw interrupt state, prior to masking, of the SSPRXINTR interrupt */
/* [1] : raw interrupt state, prior to masking, of the SSPRTINTR interrupt */
/* [0] : raw interrupt state, prior to masking, of the SSPRORINTR interrupt */
volatile uint32_t MIS; /* Offset: 0x01C (R/ ) Masked interrupt status register */
/* [31:4] : Reserved */
/* [3] : transmit FIFO masked interrupt state, after masking, of the SSPTXINTR interrupt */
/* [2] : receive FIFO masked interrupt state, after masking, of the SSPRXINTR interrupt */
/* [1] : receive timeout masked interrupt state, after masking, of the SSPRTINTR interrupt */
/* [0] : receive over run masked interrupt status, after masking, of the SSPRORINTR interrupt */
volatile uint32_t ICR; /* Offset: 0x020 ( /W) Interrupt clear register */
/* [31:2] : Reserved */
/* [1] : Clears the SSPRTINTR interrupt */
/* [0] : Clears the SSPRORINTR interrupt */
volatile uint32_t DMACR; /* Offset: 0x024 (R/W) DMA control register */
/* [31:2] : Reserved */
/* [1] : Transmit DMA Enable */
/* [0] : Receive DMA Enable */
} MPS2_SSP_TypeDef;
/* SSP_CR0 Control register 0 */
#define SSP_CR0_DSS_Pos 0 /* Data Size Select */
#define SSP_CR0_DSS_Msk ( 0xF << SSP_CR0_DSS_Pos )
#define SSP_CR0_FRF_Pos 4 /* Frame Format Select */
#define SSP_CR0_FRF_Msk ( 3UL << SSP_CR0_FRM_Pos )
#define SSP_CR0_SPO_Pos 6 /* SSPCLKOUT polarity */
#define SSP_CR0_SPO_Msk ( 1UL << SSP_CR0_SPO_Pos )
#define SSP_CR0_SPH_Pos 7 /* SSPCLKOUT phase */
#define SSP_CR0_SPH_Msk ( 1UL << SSP_CR0_SPH_Pos )
#define SSP_CR0_SCR_Pos 8 /* Serial Clock Rate (divide) */
#define SSP_CR0_SCR_Msk ( 0xFF << SSP_CR0_SCR_Pos )
#define SSP_CR0_SCR_DFLT 0x0300 /* Serial Clock Rate (divide), default set at 3 */
#define SSP_CR0_FRF_MOT 0x0000 /* Frame format, Motorola */
#define SSP_CR0_DSS_8 0x0007 /* Data packet size, 8bits */
#define SSP_CR0_DSS_16 0x000F /* Data packet size, 16bits */
/* SSP_CR1 Control register 1 */
#define SSP_CR1_LBM_Pos 0 /* Loop Back Mode */
#define SSP_CR1_LBM_Msk ( 1UL << SSP_CR1_LBM_Pos )
#define SSP_CR1_SSE_Pos 1 /* Serial port enable */
#define SSP_CR1_SSE_Msk ( 1UL << SSP_CR1_SSE_Pos )
#define SSP_CR1_MS_Pos 2 /* Master or Slave mode */
#define SSP_CR1_MS_Msk ( 1UL << SSP_CR1_MS_Pos )
#define SSP_CR1_SOD_Pos 3 /* Slave Output mode Disable */
#define SSP_CR1_SOD_Msk ( 1UL << SSP_CR1_SOD_Pos )
/* SSP_SR Status register */
#define SSP_SR_TFE_Pos 0 /* Transmit FIFO empty */
#define SSP_SR_TFE_Msk ( 1UL << SSP_SR_TFE_Pos )
#define SSP_SR_TNF_Pos 1 /* Transmit FIFO not full */
#define SSP_SR_TNF_Msk ( 1UL << SSP_SR_TNF_Pos )
#define SSP_SR_RNE_Pos 2 /* Receive FIFO not empty */
#define SSP_SR_RNE_Msk ( 1UL << SSP_SR_RNE_Pos )
#define SSP_SR_RFF_Pos 3 /* Receive FIFO full */
#define SSP_SR_RFF_Msk ( 1UL << SSP_SR_RFF_Pos )
#define SSP_SR_BSY_Pos 4 /* Busy */
#define SSP_SR_BSY_Msk ( 1UL << SSP_SR_BSY_Pos )
/* SSP_CPSR Clock prescale register */
#define SSP_CPSR_CPD_Pos 0 /* Clock prescale divisor */
#define SSP_CPSR_CPD_Msk ( 0xFF << SSP_CPSR_CDP_Pos )
#define SSP_CPSR_DFLT 0x0008 /* Clock prescale (use with SCR), default set at 8 */
/* SSPIMSC Interrupt mask set and clear register */
#define SSP_IMSC_RORIM_Pos 0 /* Receive overrun not Masked */
#define SSP_IMSC_RORIM_Msk ( 1UL << SSP_IMSC_RORIM_Pos )
#define SSP_IMSC_RTIM_Pos 1 /* Receive timeout not Masked */
#define SSP_IMSC_RTIM_Msk ( 1UL << SSP_IMSC_RTIM_Pos )
#define SSP_IMSC_RXIM_Pos 2 /* Receive FIFO not Masked */
#define SSP_IMSC_RXIM_Msk ( 1UL << SSP_IMSC_RXIM_Pos )
#define SSP_IMSC_TXIM_Pos 3 /* Transmit FIFO not Masked */
#define SSP_IMSC_TXIM_Msk ( 1UL << SSP_IMSC_TXIM_Pos )
/* SSPRIS Raw interrupt status register */
#define SSP_RIS_RORRIS_Pos 0 /* Raw Overrun interrupt flag */
#define SSP_RIS_RORRIS_Msk ( 1UL << SSP_RIS_RORRIS_Pos )
#define SSP_RIS_RTRIS_Pos 1 /* Raw Timemout interrupt flag */
#define SSP_RIS_RTRIS_Msk ( 1UL << SSP_RIS_RTRIS_Pos )
#define SSP_RIS_RXRIS_Pos 2 /* Raw Receive interrupt flag */
#define SSP_RIS_RXRIS_Msk ( 1UL << SSP_RIS_RXRIS_Pos )
#define SSP_RIS_TXRIS_Pos 3 /* Raw Transmit interrupt flag */
#define SSP_RIS_TXRIS_Msk ( 1UL << SSP_RIS_TXRIS_Pos )
/* SSPMIS Masked interrupt status register */
#define SSP_MIS_RORMIS_Pos 0 /* Masked Overrun interrupt flag */
#define SSP_MIS_RORMIS_Msk ( 1UL << SSP_MIS_RORMIS_Pos )
#define SSP_MIS_RTMIS_Pos 1 /* Masked Timemout interrupt flag */
#define SSP_MIS_RTMIS_Msk ( 1UL << SSP_MIS_RTMIS_Pos )
#define SSP_MIS_RXMIS_Pos 2 /* Masked Receive interrupt flag */
#define SSP_MIS_RXMIS_Msk ( 1UL << SSP_MIS_RXMIS_Pos )
#define SSP_MIS_TXMIS_Pos 3 /* Masked Transmit interrupt flag */
#define SSP_MIS_TXMIS_Msk ( 1UL << SSP_MIS_TXMIS_Pos )
/* SSPICR Interrupt clear register */
#define SSP_ICR_RORIC_Pos 0 /* Clears Overrun interrupt flag */
#define SSP_ICR_RORIC_Msk ( 1UL << SSP_ICR_RORIC_Pos )
#define SSP_ICR_RTIC_Pos 1 /* Clears Timemout interrupt flag */
#define SSP_ICR_RTIC_Msk ( 1UL << SSP_ICR_RTIC_Pos )
/* SSPDMACR DMA control register */
#define SSP_DMACR_RXDMAE_Pos 0 /* Enable Receive FIFO DMA */
#define SSP_DMACR_RXDMAE_Msk ( 1UL << SSP_DMACR_RXDMAE_Pos )
#define SSP_DMACR_TXDMAE_Pos 1 /* Enable Transmit FIFO DMA */
#define SSP_DMACR_TXDMAE_Msk ( 1UL << SSP_DMACR_TXDMAE_Pos )
/******************************************************************************/
/* Audio and Touch Screen (I2C) Peripheral declaration */
/******************************************************************************/
typedef struct
{
union
{
volatile uint32_t CONTROLS; /* Offset: 0x000 CONTROL Set Register ( /W) */
volatile uint32_t CONTROL; /* Offset: 0x000 CONTROL Status Register (R/ ) */
};
volatile uint32_t CONTROLC; /* Offset: 0x004 CONTROL Clear Register ( /W) */
} MPS2_I2C_TypeDef;
#define SDA 1 << 1
#define SCL 1 << 0
/******************************************************************************/
/* Audio I2S Peripheral declaration */
/******************************************************************************/
typedef struct
{
/*!< Offset: 0x000 CONTROL Register (R/W) */
volatile uint32_t CONTROL; /* <h> CONTROL </h> */
/* <o.0> TX Enable */
/* <0=> TX disabled */
/* <1=> TX enabled */
/* <o.1> TX IRQ Enable */
/* <0=> TX IRQ disabled */
/* <1=> TX IRQ enabled */
/* <o.2> RX Enable */
/* <0=> RX disabled */
/* <1=> RX enabled */
/* <o.3> RX IRQ Enable */
/* <0=> RX IRQ disabled */
/* <1=> RX IRQ enabled */
/* <o.10..8> TX Buffer Water Level */
/* <0=> / IRQ triggers when any space available */
/* <1=> / IRQ triggers when more than 1 space available */
/* <2=> / IRQ triggers when more than 2 space available */
/* <3=> / IRQ triggers when more than 3 space available */
/* <4=> Undefined! */
/* <5=> Undefined! */
/* <6=> Undefined! */
/* <7=> Undefined! */
/* <o.14..12> RX Buffer Water Level */
/* <0=> Undefined! */
/* <1=> / IRQ triggers when less than 1 space available */
/* <2=> / IRQ triggers when less than 2 space available */
/* <3=> / IRQ triggers when less than 3 space available */
/* <4=> / IRQ triggers when less than 4 space available */
/* <5=> Undefined! */
/* <6=> Undefined! */
/* <7=> Undefined! */
/* <o.16> FIFO reset */
/* <0=> Normal operation */
/* <1=> FIFO reset */
/* <o.17> Audio Codec reset */
/* <0=> Normal operation */
/* <1=> Assert audio Codec reset */
/*!< Offset: 0x004 STATUS Register (R/ ) */
volatile uint32_t STATUS; /* <h> STATUS </h> */
/* <o.0> TX Buffer alert */
/* <0=> TX buffer don't need service yet */
/* <1=> TX buffer need service */
/* <o.1> RX Buffer alert */
/* <0=> RX buffer don't need service yet */
/* <1=> RX buffer need service */
/* <o.2> TX Buffer Empty */
/* <0=> TX buffer have data */
/* <1=> TX buffer empty */
/* <o.3> TX Buffer Full */
/* <0=> TX buffer not full */
/* <1=> TX buffer full */
/* <o.4> RX Buffer Empty */
/* <0=> RX buffer have data */
/* <1=> RX buffer empty */
/* <o.5> RX Buffer Full */
/* <0=> RX buffer not full */
/* <1=> RX buffer full */
union
{
/*!< Offset: 0x008 Error Status Register (R/ ) */
volatile uint32_t ERROR; /* <h> ERROR </h> */
/* <o.0> TX error */
/* <0=> Okay */
/* <1=> TX overrun/underrun */
/* <o.1> RX error */
/* <0=> Okay */
/* <1=> RX overrun/underrun */
/*!< Offset: 0x008 Error Clear Register ( /W) */
volatile uint32_t ERRORCLR; /* <h> ERRORCLR </h> */
/* <o.0> TX error */
/* <0=> Okay */
/* <1=> Clear TX error */
/* <o.1> RX error */
/* <0=> Okay */
/* <1=> Clear RX error */
};
/*!< Offset: 0x00C Divide ratio Register (R/W) */
volatile uint32_t DIVIDE; /* <h> Divide ratio for Left/Right clock </h> */
/* <o.9..0> TX error (default 0x80) */
/*!< Offset: 0x010 Transmit Buffer ( /W) */
volatile uint32_t TXBUF; /* <h> Transmit buffer </h> */
/* <o.15..0> Right channel */
/* <o.31..16> Left channel */
/*!< Offset: 0x014 Receive Buffer (R/ ) */
volatile uint32_t RXBUF; /* <h> Receive buffer </h> */
/* <o.15..0> Right channel */
/* <o.31..16> Left channel */
uint32_t RESERVED1[ 186 ];
volatile uint32_t ITCR; /* <h> Integration Test Control Register </h> */
/* <o.0> ITEN */
/* <0=> Normal operation */
/* <1=> Integration Test mode enable */
volatile uint32_t ITIP1; /* <h> Integration Test Input Register 1</h> */
/* <o.0> SDIN */
volatile uint32_t ITOP1; /* <h> Integration Test Output Register 1</h> */
/* <o.0> SDOUT */
/* <o.1> SCLK */
/* <o.2> LRCK */
/* <o.3> IRQOUT */
} MPS2_I2S_TypeDef;
#define I2S_CONTROL_TXEN_Pos 0
#define I2S_CONTROL_TXEN_Msk ( 1UL << I2S_CONTROL_TXEN_Pos )
#define I2S_CONTROL_TXIRQEN_Pos 1
#define I2S_CONTROL_TXIRQEN_Msk ( 1UL << I2S_CONTROL_TXIRQEN_Pos )
#define I2S_CONTROL_RXEN_Pos 2
#define I2S_CONTROL_RXEN_Msk ( 1UL << I2S_CONTROL_RXEN_Pos )
#define I2S_CONTROL_RXIRQEN_Pos 3
#define I2S_CONTROL_RXIRQEN_Msk ( 1UL << I2S_CONTROL_RXIRQEN_Pos )
#define I2S_CONTROL_TXWLVL_Pos 8
#define I2S_CONTROL_TXWLVL_Msk ( 7UL << I2S_CONTROL_TXWLVL_Pos )
#define I2S_CONTROL_RXWLVL_Pos 12
#define I2S_CONTROL_RXWLVL_Msk ( 7UL << I2S_CONTROL_RXWLVL_Pos )
/* FIFO reset*/
#define I2S_CONTROL_FIFORST_Pos 16
#define I2S_CONTROL_FIFORST_Msk ( 1UL << I2S_CONTROL_FIFORST_Pos )
/* Codec reset*/
#define I2S_CONTROL_CODECRST_Pos 17
#define I2S_CONTROL_CODECRST_Msk ( 1UL << I2S_CONTROL_CODECRST_Pos )
#define I2S_STATUS_TXIRQ_Pos 0
#define I2S_STATUS_TXIRQ_Msk ( 1UL << I2S_STATUS_TXIRQ_Pos )
#define I2S_STATUS_RXIRQ_Pos 1
#define I2S_STATUS_RXIRQ_Msk ( 1UL << I2S_STATUS_RXIRQ_Pos )
#define I2S_STATUS_TXEmpty_Pos 2
#define I2S_STATUS_TXEmpty_Msk ( 1UL << I2S_STATUS_TXEmpty_Pos )
#define I2S_STATUS_TXFull_Pos 3
#define I2S_STATUS_TXFull_Msk ( 1UL << I2S_STATUS_TXFull_Pos )
#define I2S_STATUS_RXEmpty_Pos 4
#define I2S_STATUS_RXEmpty_Msk ( 1UL << I2S_STATUS_RXEmpty_Pos )
#define I2S_STATUS_RXFull_Pos 5
#define I2S_STATUS_RXFull_Msk ( 1UL << I2S_STATUS_RXFull_Pos )
#define I2S_ERROR_TXERR_Pos 0
#define I2S_ERROR_TXERR_Msk ( 1UL << I2S_ERROR_TXERR_Pos )
#define I2S_ERROR_RXERR_Pos 1
#define I2S_ERROR_RXERR_Msk ( 1UL << I2S_ERROR_RXERR_Pos )
/******************************************************************************/
/* SMSC9220 Register Definitions */
/******************************************************************************/
typedef struct /* SMSC LAN9220 */
{
volatile uint32_t RX_DATA_PORT; /* Receive FIFO Ports (offset 0x0) */
uint32_t RESERVED1[ 0x7 ];
volatile uint32_t TX_DATA_PORT; /* Transmit FIFO Ports (offset 0x20) */
uint32_t RESERVED2[ 0x7 ];
volatile uint32_t RX_STAT_PORT; /* Receive FIFO status port (offset 0x40) */
volatile uint32_t RX_STAT_PEEK; /* Receive FIFO status peek (offset 0x44) */
volatile uint32_t TX_STAT_PORT; /* Transmit FIFO status port (offset 0x48) */
volatile uint32_t TX_STAT_PEEK; /* Transmit FIFO status peek (offset 0x4C) */
volatile uint32_t ID_REV; /* Chip ID and Revision (offset 0x50) */
volatile uint32_t IRQ_CFG; /* Main Interrupt Configuration (offset 0x54) */
volatile uint32_t INT_STS; /* Interrupt Status (offset 0x58) */
volatile uint32_t INT_EN; /* Interrupt Enable Register (offset 0x5C) */
uint32_t RESERVED3; /* Reserved for future use (offset 0x60) */
volatile uint32_t BYTE_TEST; /* Read-only byte order testing register 87654321h (offset 0x64) */
volatile uint32_t FIFO_INT; /* FIFO Level Interrupts (offset 0x68) */
volatile uint32_t RX_CFG; /* Receive Configuration (offset 0x6C) */
volatile uint32_t TX_CFG; /* Transmit Configuration (offset 0x70) */
volatile uint32_t HW_CFG; /* Hardware Configuration (offset 0x74) */
volatile uint32_t RX_DP_CTL; /* RX Datapath Control (offset 0x78) */
volatile uint32_t RX_FIFO_INF; /* Receive FIFO Information (offset 0x7C) */
volatile uint32_t TX_FIFO_INF; /* Transmit FIFO Information (offset 0x80) */
volatile uint32_t PMT_CTRL; /* Power Management Control (offset 0x84) */
volatile uint32_t GPIO_CFG; /* General Purpose IO Configuration (offset 0x88) */
volatile uint32_t GPT_CFG; /* General Purpose Timer Configuration (offset 0x8C) */
volatile uint32_t GPT_CNT; /* General Purpose Timer Count (offset 0x90) */
uint32_t RESERVED4; /* Reserved for future use (offset 0x94) */
volatile uint32_t ENDIAN; /* WORD SWAP Register (offset 0x98) */
volatile uint32_t FREE_RUN; /* Free Run Counter (offset 0x9C) */
volatile uint32_t RX_DROP; /* RX Dropped Frames Counter (offset 0xA0) */
volatile uint32_t MAC_CSR_CMD; /* MAC CSR Synchronizer Command (offset 0xA4) */
volatile uint32_t MAC_CSR_DATA; /* MAC CSR Synchronizer Data (offset 0xA8) */
volatile uint32_t AFC_CFG; /* Automatic Flow Control Configuration (offset 0xAC) */
volatile uint32_t E2P_CMD; /* EEPROM Command (offset 0xB0) */
volatile uint32_t E2P_DATA; /* EEPROM Data (offset 0xB4) */
} SMSC9220_TypeDef;
/* SMSC9220 MAC Registers Indices */
#define SMSC9220_MAC_CR 0x1
#define SMSC9220_MAC_ADDRH 0x2
#define SMSC9220_MAC_ADDRL 0x3
#define SMSC9220_MAC_HASHH 0x4
#define SMSC9220_MAC_HASHL 0x5
#define SMSC9220_MAC_MII_ACC 0x6
#define SMSC9220_MAC_MII_DATA 0x7
#define SMSC9220_MAC_FLOW 0x8
#define SMSC9220_MAC_VLAN1 0x9
#define SMSC9220_MAC_VLAN2 0xA
#define SMSC9220_MAC_WUFF 0xB
#define SMSC9220_MAC_WUCSR 0xC
/* SMSC9220 PHY Registers Indices */
#define SMSC9220_PHY_BCONTROL 0x0
#define SMSC9220_PHY_BSTATUS 0x1
#define SMSC9220_PHY_ID1 0x2
#define SMSC9220_PHY_ID2 0x3
#define SMSC9220_PHY_ANEG_ADV 0x4
#define SMSC9220_PHY_ANEG_LPA 0x5
#define SMSC9220_PHY_ANEG_EXP 0x6
#define SMSC9220_PHY_MCONTROL 0x17
#define SMSC9220_PHY_MSTATUS 0x18
#define SMSC9220_PHY_CSINDICATE 0x27
#define SMSC9220_PHY_INTSRC 0x29
#define SMSC9220_PHY_INTMASK 0x30
#define SMSC9220_PHY_CS 0x31
/******************************************************************************/
/* Peripheral memory map */
/******************************************************************************/
#define MPS2_SSP1_BASE ( 0x40020000ul ) /* User SSP Base Address */
#define MPS2_SSP0_BASE ( 0x40021000ul ) /* CLCD SSP Base Address */
#define MPS2_TSC_I2C_BASE ( 0x40022000ul ) /* Touch Screen I2C Base Address */
#define MPS2_AAIC_I2C_BASE ( 0x40023000ul ) /* Audio Interface I2C Base Address */
#define MPS2_AAIC_I2S_BASE ( 0x40024000ul ) /* Audio Interface I2S Base Address */
#define MPS2_SSP2_BASE ( 0x40025000ul ) /* adc SSP Base Address */
#define MPS2_SSP3_BASE ( 0x40026000ul ) /* Shield 0 SSP Base Address */
#define MPS2_SSP4_BASE ( 0x40027000ul ) /* Shield 1 SSP Base Address */
#define MPS2_FPGAIO_BASE ( 0x40028000ul ) /* FPGAIO Base Address */
#define MPS2_SHIELD0_I2C_BASE ( 0x40029000ul ) /* Shield 0 I2C Base Address */
#define MPS2_SHIELD1_I2C_BASE ( 0x4002A000ul ) /* Shield 1 I2C Base Address */
#define MPS2_SCC_BASE ( 0x4002F000ul ) /* SCC Base Address */
#ifdef CORTEX_M7
#define SMSC9220_BASE ( 0xA0000000ul ) /* Ethernet SMSC9220 Base Address */
#else
#define SMSC9220_BASE ( 0x40200000ul ) /* Ethernet SMSC9220 Base Address */
#endif
#define MPS2_VGA_TEXT_BUFFER ( 0x41000000ul ) /* VGA Text Buffer Address */
#define MPS2_VGA_BUFFER ( 0x41100000ul ) /* VGA Buffer Base Address */
/******************************************************************************/
/* Peripheral declaration */
/******************************************************************************/
#define SMSC9220 ( ( SMSC9220_TypeDef * ) SMSC9220_BASE )
#define MPS2_TS_I2C ( ( MPS2_I2C_TypeDef * ) MPS2_TSC_I2C_BASE )
#define MPS2_AAIC_I2C ( ( MPS2_I2C_TypeDef * ) MPS2_AAIC_I2C_BASE )
#define MPS2_SHIELD0_I2C ( ( MPS2_I2C_TypeDef * ) MPS2_SHIELD0_I2C_BASE )
#define MPS2_SHIELD1_I2C ( ( MPS2_I2C_TypeDef * ) MPS2_SHIELD1_I2C_BASE )
#define MPS2_AAIC_I2S ( ( MPS2_I2S_TypeDef * ) MPS2_AAIC_I2S_BASE )
#define MPS2_FPGAIO ( ( MPS2_FPGAIO_TypeDef * ) MPS2_FPGAIO_BASE )
#define MPS2_SCC ( ( MPS2_SCC_TypeDef * ) MPS2_SCC_BASE )
#define MPS2_SSP0 ( ( MPS2_SSP_TypeDef * ) MPS2_SSP0_BASE )
#define MPS2_SSP1 ( ( MPS2_SSP_TypeDef * ) MPS2_SSP1_BASE )
#define MPS2_SSP2 ( ( MPS2_SSP_TypeDef * ) MPS2_SSP2_BASE )
#define MPS2_SSP3 ( ( MPS2_SSP_TypeDef * ) MPS2_SSP3_BASE )
#define MPS2_SSP4 ( ( MPS2_SSP_TypeDef * ) MPS2_SSP4_BASE )
/******************************************************************************/
/* General Function Definitions */
/******************************************************************************/
/******************************************************************************/
/* General MACRO Definitions */
/******************************************************************************/
#endif /* __SMM_MPS2_H */

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2019 Arm Limited
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#ifndef SMSC9220_EMAC_CONFIG_H
#define SMSC9220_EMAC_CONFIG_H
#define SMSC9220_HWADDR_SIZE 6U
#define SMSC9220_BUFF_ALIGNMENT 4U
/*
* Maximum Transfer Unit
* The IEEE 802.3 specification limits the data portion of the 802.3 frame
* to a minimum of 46 and a maximum of 1522 bytes, this is on L2 level.
*/
#define SMSC9220_ETH_MTU_SIZE 1500U
#define SMSC9220_ETH_IF_NAME "smsc9220"
#define SMSC9220_ETH_MAX_FRAME_SIZE 1522U
/** \brief Defines for receiver thread */
#define FLAG_RX 1U
#define LINK_STATUS_THREAD_PRIORITY ( osPriorityNormal )
#define LINK_STATUS_THREAD_STACKSIZE 512U
#define LINK_STATUS_TASK_PERIOD_MS 200U
#define PHY_STATE_LINK_DOWN false
#define PHY_STATE_LINK_UP true
#define CRC_LENGTH_BYTES 4U
#endif /* SMSC9220_EMAC_CONFIG_H */

View File

@ -0,0 +1,547 @@
/*
* Copyright (c) 2016-2019 Arm Limited
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
/**
* \file smsc9220_drv.h
* \brief Generic driver for SMSC9220 Ethernet controller
*/
#ifndef __SMSC9220_ETH_H__
#define __SMSC9220_ETH_H__
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** SMSC9220 device configuration structure */
struct smsc9220_eth_dev_cfg_t
{
const uint32_t base; /*!< SMSC9220 base address */
};
/** SMSC9220 device data structure */
struct smsc9220_eth_dev_data_t
{
uint32_t state; /*!< Indicates if the SMSC9220 driver
* is initialized and enabled */
void (* wait_ms) ( uint32_t ); /*!< function pointer to system's millisec delay
* function, will be used for delays */
uint32_t ongoing_packet_length; /*!< size in bytes of the packet
* is being sent */
uint32_t ongoing_packet_length_sent; /*!< size in bytes of the packet
* has been sent */
uint32_t current_rx_size_words; /*!< Data length in words,
* currently is being read */
};
/** SMSC9220 device structure */
struct smsc9220_eth_dev_t
{
const struct smsc9220_eth_dev_cfg_t * const cfg; /*!< configuration */
struct smsc9220_eth_dev_data_t * const data; /*!< data */
};
/**
* \brief Error code definitions
*
*/
enum smsc9220_error_t
{
SMSC9220_ERROR_NONE = 0U, /*!< no error */
SMSC9220_ERROR_TIMEOUT = 1U, /*!< timeout */
SMSC9220_ERROR_BUSY = 2U, /*!< no error */
SMSC9220_ERROR_PARAM = 3U, /*!< invalid parameter */
SMSC9220_ERROR_INTERNAL = 4U /*!< internal error */
};
/**
* \brief Interrupt source definitions
*
*/
enum smsc9220_interrupt_source
{
SMSC9220_INTERRUPT_GPIO0 = 0U,
SMSC9220_INTERRUPT_GPIO1 = 1U,
SMSC9220_INTERRUPT_GPIO2 = 2U,
SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL = 3U,
SMSC9220_INTERRUPT_RX_STATUS_FIFO_FULL = 4U,
/* 5 Reserved according to Datasheet */
SMSC9220_INTERRUPT_RX_DROPPED_FRAME = 6U,
SMSC9220_INTERRUPT_TX_STATUS_FIFO_LEVEL = 7U,
SMSC9220_INTERRUPT_TX_STATUS_FIFO_FULL = 8U,
SMSC9220_INTERRUPT_TX_DATA_FIFO_AVAILABLE = 9U,
SMSC9220_INTERRUPT_TX_DATA_FIFO_OVERRUN = 10U,
/* 11, 12 Reserved according to Datasheet */
SMSC9220_INTERRUPT_TX_ERROR = 13U,
SMSC9220_INTERRUPT_RX_ERROR = 14U,
SMSC9220_INTERRUPT_RX_WATCHDOG_TIMEOUT = 15U,
SMSC9220_INTERRUPT_TX_STATUS_OVERFLOW = 16U,
SMSC9220_INTERRUPT_TX_POWER_MANAGEMENT = 17U,
SMSC9220_INTERRUPT_PHY = 18U,
SMSC9220_INTERRUPT_GP_TIMER = 19U,
SMSC9220_INTERRUPT_RX_DMA = 20U,
SMSC9220_INTERRUPT_TX_IOC = 21U,
/* 22 Reserved according to Datasheet*/
SMSC9220_INTERRUPT_RX_DROPPED_FRAME_HALF = 23U,
SMSC9220_INTERRUPT_RX_STOPPED = 24U,
SMSC9220_INTERRUPT_TX_STOPPED = 25U,
/* 26 - 30 Reserved according to Datasheet*/
SMSC9220_INTERRUPT_SW = 31U
};
/**
* \brief MAC register offset definitions
*
*/
enum smsc9220_mac_reg_offsets_t
{
SMSC9220_MAC_REG_OFFSET_CR = 0x1U,
SMSC9220_MAC_REG_OFFSET_ADDRH = 0x2U,
SMSC9220_MAC_REG_OFFSET_ADDRL = 0x3U,
SMSC9220_MAC_REG_OFFSET_HASHH = 0x4U,
SMSC9220_MAC_REG_OFFSET_HASHL = 0x5U,
SMSC9220_MAC_REG_OFFSET_MII_ACC = 0x6U,
SMSC9220_MAC_REG_OFFSET_MII_DATA = 0x7U,
SMSC9220_MAC_REG_OFFSET_FLOW = 0x8U,
SMSC9220_MAC_REG_OFFSET_VLAN1 = 0x9U,
SMSC9220_MAC_REG_OFFSET_VLAN2 = 0xAU,
SMSC9220_MAC_REG_OFFSET_WUFF = 0xBU,
SMSC9220_MAC_REG_OFFSET_WUCSR = 0xCU,
SMSC9220_MAC_REG_OFFSET_COE_CR = 0xDU
};
/**
* \brief PHY register offset definitions
*
*/
enum phy_reg_offsets_t
{
SMSC9220_PHY_REG_OFFSET_BCTRL = 0U,
SMSC9220_PHY_REG_OFFSET_BSTATUS = 1U,
SMSC9220_PHY_REG_OFFSET_ID1 = 2U,
SMSC9220_PHY_REG_OFFSET_ID2 = 3U,
SMSC9220_PHY_REG_OFFSET_ANEG_ADV = 4U,
SMSC9220_PHY_REG_OFFSET_ANEG_LPA = 5U,
SMSC9220_PHY_REG_OFFSET_ANEG_EXP = 6U,
SMSC9220_PHY_REG_OFFSET_MCONTROL = 17U,
SMSC9220_PHY_REG_OFFSET_MSTATUS = 18U,
SMSC9220_PHY_REG_OFFSET_CSINDICATE = 27U,
SMSC9220_PHY_REG_OFFSET_INTSRC = 29U,
SMSC9220_PHY_REG_OFFSET_INTMASK = 30U,
SMSC9220_PHY_REG_OFFSET_CS = 31U
};
/* Bit definitions for PHY Basic Status Register */
#define PHY_REG_BSTATUS_EXTENDED_CAPABILITIES_INDEX 0U
#define PHY_REG_BSTATUS_JABBER_DETECT_INDEX 1U
#define PHY_REG_BSTATUS_LINK_STATUS_INDEX 2U
#define PHY_REG_BSTATUS_AUTO_NEG_ABILITY_INDEX 3U
#define PHY_REG_BSTATUS_REMOTE_FAULT_INDEX 4U
#define PHY_REG_BSTATUS_AUTO_NEG_COMPLETE_INDEX 5U
#define PHY_REG_BSTATUS_10BASE_T_HALF_DUPLEX_INDEX 11U
#define PHY_REG_BSTATUS_10BASE_T_FULL_DUPLEX_INDEX 12U
#define PHY_REG_BSTATUS_100BASE_TX_HALF_DUPLEX_INDEX 13U
#define PHY_REG_BSTATUS_100BASE_TX_FULL_DUPLEX_INDEX 14U
#define PHY_REG_BSTATUS_100BASE_T4_INDEX 15U
/**
* \brief FIFO Level Interrupt bit definitions
*
*/
enum smsc9220_fifo_level_irq_pos_t
{
SMSC9220_FIFO_LEVEL_IRQ_RX_STATUS_POS = 0U,
SMSC9220_FIFO_LEVEL_IRQ_TX_STATUS_POS = 16U,
SMSC9220_FIFO_LEVEL_IRQ_TX_DATA_POS = 24U
};
/**
* \brief FIFO Level Interrupt limits
*
*/
#define SMSC9220_FIFO_LEVEL_IRQ_MASK 0xFFU
#define SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MIN 0U
#define SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MAX SMSC9220_FIFO_LEVEL_IRQ_MASK
/**
* \brief Initializes SMSC9220 Ethernet controller to a known default state:
* - device ID is checked
* - global interrupt is enabled, but all irq sources are disabled
* - all capabilities are advertised
* - 10Mbps able
* - 10Mbps with full duplex
* - 100Mbps Tx able
* - 100Mbps with full duplex
* - Symmetric Pause
* - Asymmetric Pause
* - Establish link enabled
* - Rx enabled
* - Tx enabled
* Init should be called prior to any other process and
* it's the caller's responsibility to follow proper call order.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
* \param[in] wait_ms_function function pointer to a millisec delay function
* for proper timing of some processes
*
* \return error code /ref smsc9220_error_t
*/
enum smsc9220_error_t smsc9220_init( const struct smsc9220_eth_dev_t * dev,
void ( * wait_ms_function )( uint32_t ) );
/**
* \brief Reads the MAC register.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
* \param[in] regoffset Register offset
* \param[in, out] data Pointer to register will be read
*
* \return error code /ref smsc9220_error_t
*/
enum smsc9220_error_t smsc9220_mac_regread( const struct smsc9220_eth_dev_t * dev,
enum smsc9220_mac_reg_offsets_t regoffset,
uint32_t * data );
/**
* \brief Writes the MAC register.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
* \param[in] regoffset Register offset
* \param[in] data Register value to write
*
* \return error code /ref smsc9220_error_t
*/
enum smsc9220_error_t smsc9220_mac_regwrite( const struct smsc9220_eth_dev_t * dev,
enum smsc9220_mac_reg_offsets_t regoffset,
uint32_t data );
/**
* \brief Reads the PHY register.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
* \param[in] regoffset Register offset
* \param[out] data Register value is read
*
* \return error code /ref smsc9220_error_t
*/
enum smsc9220_error_t smsc9220_phy_regread( const struct smsc9220_eth_dev_t * dev,
enum phy_reg_offsets_t,
uint32_t * data );
/**
* \brief Writes the PHY register.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
* \param[in] regoffset Register offset
* \param[in] data Register value to write
*
* \return error code /ref smsc9220_error_t
*/
enum smsc9220_error_t smsc9220_phy_regwrite( const struct smsc9220_eth_dev_t * dev,
enum phy_reg_offsets_t,
uint32_t data );
/**
* \brief Reads the Ethernet Controller's ID.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*
* \return ID number
*/
uint32_t smsc9220_read_id( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Initiates a soft reset, returns failure or success.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*
* \return error code /ref smsc9220_error_t
*/
enum smsc9220_error_t smsc9220_soft_reset( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Sets the Maximum Transmission Unit by Tx fifo size.
* Note: The MTU will be smaller by 512 bytes,
* whis is used by the status.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
* \param[in] val Size of the fifo in kbytes
* \ref HW_CFG_REG_TX_FIFO_SIZE_MIN
* \ref HW_CFG_REG_TX_FIFO_SIZE_MAX
*/
void smsc9220_set_txfifo( const struct smsc9220_eth_dev_t * dev,
uint32_t val );
/**
* \brief Sets the FIFO level interrupt for a given source.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
* \param[in] irq_level_pos Bit position of the FIFO to set
* \ref smsc9220_fifo_level_irq_pos_t
* \param[in] level Level of the FIFO, when the FIFO used space is greater
* than this value, corresponding interrupt will be generated.
*
* \return error code /ref smsc9220_error_t
*/
enum smsc9220_error_t smsc9220_set_fifo_level_irq( const struct smsc9220_eth_dev_t * dev,
enum smsc9220_fifo_level_irq_pos_t irq_level_pos,
uint32_t level );
/**
* \brief Waits for EEPROM to be ready to use.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*
* \return error code /ref smsc9220_error_t
*/
enum smsc9220_error_t smsc9220_wait_eeprom( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Initializes irqs by clearing and disabling all interrupt sources
* and enable interrupts. Since all interrupt sources are disabled,
* interrupt won't be triggered, until interrupt sources won't be
* enabled by \ref smsc9220_enable_interrupt
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*/
void smsc9220_init_irqs( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Checks PHY ID registers.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*
* \return error code /ref smsc9220_error_t
*/
enum smsc9220_error_t smsc9220_check_phy( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Resets PHY.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*
* \return error code /ref smsc9220_error_t
*/
enum smsc9220_error_t smsc9220_reset_phy( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Advertises all speeds and pauses capabilities.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*/
void smsc9220_advertise_cap( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Enables transmission.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*/
void smsc9220_enable_xmit( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Disables transmission.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*/
void smsc9220_disable_xmit( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Enables MAC Transmitter.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*/
void smsc9220_enable_mac_xmit( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Disables MAC Transmitter.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*/
void smsc9220_disable_mac_xmit( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Enables receiving.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*/
void smsc9220_enable_mac_recv( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Disables receiving.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*/
void smsc9220_disable_mac_recv( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Enables the given interrupt source.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
* \param[in] source Enum of the interrupt source.
*/
void smsc9220_enable_interrupt( const struct smsc9220_eth_dev_t * dev,
enum smsc9220_interrupt_source source );
/**
* \brief Disables the given interrupt source.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
* \param[in] source Enum of the interrupt source.
*/
void smsc9220_disable_interrupt( const struct smsc9220_eth_dev_t * dev,
enum smsc9220_interrupt_source source );
/**
* \brief Disables all interrupt sources.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*/
void smsc9220_disable_all_interrupts( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Clears the given interrupt source.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
* \param[in] source Enum of the interrupt source.
*/
void smsc9220_clear_interrupt( const struct smsc9220_eth_dev_t * dev,
enum smsc9220_interrupt_source source );
/**
* \brief Clears all interrupt sources.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*/
void smsc9220_clear_all_interrupts( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Gets the status of the given interrupt source.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
* \param[in] source Enum of the interrupt source.
*
* \return non-zero if the given interrupt source is triggered, zero otherwise
*/
int smsc9220_get_interrupt( const struct smsc9220_eth_dev_t * dev,
enum smsc9220_interrupt_source source );
/**
* \brief Establishes link
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*/
void smsc9220_establish_link( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Reads the Ethernet Controller's MAC address from its EEPROM.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
* \param[in,out] mac array will include the read MAC address in
* 6 bytes hexadecimal format.
* It should be allocated by the caller to 6 bytes.
*
* \return error code /ref smsc9220_error_t
*/
enum smsc9220_error_t smsc9220_read_mac_address( const struct smsc9220_eth_dev_t * dev,
char * mac );
/**
* \brief Check device ID.
*
* \return error code /ref smsc9220_error_t
*/
int smsc9220_check_id( const struct smsc9220_eth_dev_t * dev );
/**
* \brief Gets the data size of the Tx buffer, aka Maximum Trasmission Unit
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*
* \return Fifo data size in bytes
*/
uint32_t smsc9220_get_tx_data_fifo_size( const struct
smsc9220_eth_dev_t * dev );
/**
* \brief Sends data from the given buffer as an Ethernet packet.
* The full packet length must be specified at the beginning
* of a new packet transmission.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
* \param[in] total_payload_length Length of the ethernet payload.
* Should be equal to the sum of passed buffers within a packet.
* \param[in] is_new_packet Should be set to true if the input buffer has to
* be sent as the start of a new packet or as a full packet.
* \param[in] data Pointer to the data buffer to be sent.
* \param[in] current_size Size of the data in bytes.
*
* \return error code /ref smsc9220_error_t
*/
enum smsc9220_error_t smsc9220_send_by_chunks( const struct smsc9220_eth_dev_t * dev,
uint32_t total_payload_length,
bool is_new_packet,
const char * data,
uint32_t current_size );
/**
* \brief Reads an incoming Ethernet packet into the given buffer.
* Stops reading at packet border.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
* \param[in,out] data Pointer to a pre-allocated input buffer.
* Allocating sufficient memory space is the caller's
* responsibility, which is typically done by calling
* \ref smsc9220_peek_next_packet_size.
* \param[in] dlen Length of the allocated data in bytes.
*
* \return Number of bytes read from the Rx FIFO into the given buffer.
*/
uint32_t smsc9220_receive_by_chunks( const struct smsc9220_eth_dev_t * dev,
char * data,
uint32_t dlen );
/**
* \brief Get the used space of Rx fifo in bytes.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*
* \return Data received and waiting for read in bytes
*/
uint32_t smsc9220_get_rxfifo_data_used_space( const struct
smsc9220_eth_dev_t * dev );
/**
* \brief Gets the size of next unread packet in Rx buffer, using the peak
* register, which is not destructive so can be read asynchronously.
* Warning: In case of heavy receiving loads, this register may not
* be in perfect sync.
*
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
*
* \return Size of the next packet in bytes, read from the Rx Peek register.
*/
uint32_t smsc9220_peek_next_packet_size( const struct
smsc9220_eth_dev_t * dev );
#ifdef __cplusplus
}
#endif
#endif /* __SMSC9220_ETH_H__ */

View File

@ -0,0 +1,10 @@
Network drivers are provided as examples only, and do not form part of the
FreeRTOS+TCP stack itself. They:
+ May be based on driver code provided by the chip vendors,
+ May not have been tested in all possible configurations,
+ Will not necessarily be optimised.
+ May have a dependency on a particular PHY part number.
+ May not necessarily comply with any particular coding standard.
+ May have dependencies on chip company libraries.
+ May include other hardware board dependencies.

View File

@ -0,0 +1,571 @@
/***********************************************************************************************************************
* 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) 2020 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 <System Includes> , "Project Includes"
***********************************************************************************************************************/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 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 ) || defined( BSP_MCU_RX72M )
#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 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 );
/***********************************************************************************************************************
* 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() */
/***********************************************************************************************************************
* 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 )
{
/* Call a function that monitors resources: the amount of free network
* buffers and the amount of free space on the heap. See FreeRTOS_IP.c
* for more detailed comments. */
vPrintResourceStats();
}
#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. */
FreeRTOS_printf( ( "R_ETHER_Read_ZC2: rc = %d\n", xBytesReceived ) );
}
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_BSP_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( ETHER_CHANNEL_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_BSP_SECTION_OPERATORS_INIT( B_ETHERNET_BUFFERS_1 )
buffer_address = R_BSP_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 )
{
FreeRTOS_printf( ( "prvLinkStatusChange( %d )\n", 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,
&ether_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"
**********************************************************************************************************************/

View File

@ -0,0 +1,182 @@
/***********************************************************************************************************************
* 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 <System 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 */

View File

@ -0,0 +1,118 @@
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/* Standard includes. */
#include <stdint.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_Sockets.h"
#include "NetworkBufferManagement.h"
/* Hardware includes. */
#include "hwEthernet.h"
/* Demo includes. */
#include "NetworkInterface.h"
#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
#else
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
#endif
/* When a packet is ready to be sent, if it cannot be sent immediately then the
* task performing the transmit will block for niTX_BUFFER_FREE_WAIT
* milliseconds. It will do this a maximum of niMAX_TX_ATTEMPTS before giving
* up. */
#define niTX_BUFFER_FREE_WAIT ( ( TickType_t ) 2UL / portTICK_PERIOD_MS )
#define niMAX_TX_ATTEMPTS ( 5 )
/* The length of the queue used to send interrupt status words from the
* interrupt handler to the deferred handler task. */
#define niINTERRUPT_QUEUE_LENGTH ( 10 )
/*-----------------------------------------------------------*/
/*
* A deferred interrupt handler task that processes
*/
extern void vEMACHandlerTask( void * pvParameters );
/*-----------------------------------------------------------*/
/* The queue used to communicate Ethernet events with the IP task. */
extern QueueHandle_t xNetworkEventQueue;
/* The semaphore used to wake the deferred interrupt handler task when an Rx
* interrupt is received. */
SemaphoreHandle_t xEMACRxEventSemaphore = NULL;
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceInitialise( void )
{
BaseType_t xStatus, xReturn;
/* Initialise the MAC. */
vInitEmac();
while( lEMACWaitForLink() != pdPASS )
{
vTaskDelay( 20 );
}
vSemaphoreCreateBinary( xEMACRxEventSemaphore );
configASSERT( xEMACRxEventSemaphore );
/* The handler task is created at the highest possible priority to
* ensure the interrupt handler can return directly to it. */
xTaskCreate( vEMACHandlerTask, "EMAC", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );
xReturn = pdPASS;
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
extern void vEMACCopyWrite( uint8_t * pucBuffer,
uint16_t usLength );
vEMACCopyWrite( pxNetworkBuffer->pucBuffer, pxNetworkBuffer->xDataLength );
/* Finished with the network buffer. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
return pdTRUE;
}
/*-----------------------------------------------------------*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,139 @@
This is a FreeeRTOS+TCP driver that works for STM32Fxx parts.
CONFIGURATION AND RUNNING
=========================
The code of stm32fxx_hal_eth.c is based on the ETH drivers as provided by ST.
These modules should be included:
- portable/NetworkInterface/STM32Fxx/NetworkInterface.c
- portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.c
When initialising the EMAC, the driver will call the function `HAL_ETH_MspInit()`, which should do the following:
- Enable the Ethernet interface clock using:
```cpp
__HAL_RCC_ETHMAC_CLK_ENABLE();
__HAL_RCC_ETHMACTX_CLK_ENABLE();
__HAL_RCC_ETHMACRX_CLK_ENABLE();
```
- Initialize the related GPIO clocks
- Configure Ethernet pin-out
Please check the schematic of your hardware to see which pins are used.
Also check if either MII or RMII is used ( define `ipconfigUSE_RMII`
as 0 or 1 ).
- Configure Ethernet NVIC interrupt (IT mode)
Choose a proper interrupt priority, defined in FreeRTOSIPConfig.h as e.g. :
```cpp
#define ipconfigMAC_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY )
```
The function `HAL_ETH_MspInit()` must be provided by the application. Make sure that your copy of the function is called,
and not a dummy defined as "weak".
It is assumed that one of these macros is defined at the highest level:
STM32F1xx
STM32F2xx
STM32F4xx
STM32F7xx
For instance, you can pass it to the compiler with the `-D` option:
gcc ... -D STM32F4xx=1
And sub-models may also be indicated, such as `STM32F401xC` or `STM32F407xx`.
The driver has been tested on both Eval and Discovery boards with STM32F1, STM32F2, STM32F4 and STM32F7. The F1 and F2 boards
have only be tested by customers who reported about it on the FreeRTOS forum.
Note that it is required to define `HAL_ETH_MODULE_ENABLED` in your STM32 configuration file. The name of this file is one out
of:
stm32f1xx_hal_conf.h
stm32f2xx_hal_conf.h
stm32f4xx_hal_conf.h
stm32f7xx_hal_conf.h
This configuration file defines the HAL modules that will be used. Here are some examples of the module macros:
~~~c
#define HAL_MODULE_ENABLED
#define HAL_ETH_MODULE_ENABLED /* <= this one is needed to get Ethernet. */
#define HAL_SRAM_MODULE_ENABLED
#define HAL_RNG_MODULE_ENABLED
#define HAL_RTC_MODULE_ENABLED
/* etc. */
~~~
Recommended settings for STM32Fxx Network Interface:
**Defined in FreeRTOSIPConfig.h**
```cpp
#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**
```cpp
#define ETH_RXBUFNB 3 or 4
#define ETH_TXBUFNB 1 or 2
#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".
STM32F7xx only:
NetworkInterface.c will place the 2 DMA tables in a special section called 'first_data'.
In case 'BufferAllocation_1.c' is used, the network packets will also be declared in this section 'first_data'.
As long as the part has no caching, this section can be placed anywhere in RAM.
On an STM32F7 with an L1 data cache, it shall be placed in the first 64KB of RAM, which is always uncached.
The linker script must be changed for this, for instance as follows:
```assembly
.data :
{
. = ALIGN(4);
_sdata = .; // create a global symbol at data start
+ *(.first_data) // .first_data sections
*(.data) // .data sections
*(.data*) // .data* sections
. = ALIGN(4);
_edata = .; // define a global symbol at data end
} >RAM AT> FLASH
```
The driver contains these files:
- NetworkInterface.c
- 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.

View File

@ -0,0 +1,6 @@
/*
* The Ethernet header files for STM32F2, STM32F4 and STM32F7 have been merged to
* a single module that works for both parts: "stm32fxx_hal_eth"
*/
#include "stm32fxx_hal_eth.h"

View File

@ -0,0 +1,6 @@
/*
* The Ethernet header files for STM32F2, STM32F4 and STM32F7 have been merged to
* a single module that works for both parts: "stm32fxx_hal_eth"
*/
#include "stm32fxx_hal_eth.h"

View File

@ -0,0 +1,6 @@
/*
* The Ethernet header files for STM32F2, STM32F4 and STM32F7 have been merged to
* a single module that works for both parts: "stm32fxx_hal_eth"
*/
#include "stm32fxx_hal_eth.h"

Some files were not shown because too many files have changed in this diff Show More