First commit
This commit is contained in:
commit
7ee6dc7527
|
|
@ -0,0 +1,2 @@
|
|||
Listings
|
||||
Objects
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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 ) ) */
|
||||
|
|
@ -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 ) */
|
||||
|
|
@ -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 ) */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 ) */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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.
|
||||
|
|
@ -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. */
|
||||
|
|
@ -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. */
|
||||
|
|
@ -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 ) );
|
||||
|
|
@ -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. */
|
||||
|
|
@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
;
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
|
|
@ -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 )
|
||||
|
|
@ -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 )
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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 */
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
|
@ -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
|
|
@ -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( Ð_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( Ð_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( Ð_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( Ð_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( Ð_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( Ð_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( Ð_MAC, MAC_ASYNC_RECEIVE_CB, ( FUNC_PTR ) xRxCallback );
|
||||
|
||||
/* Start the GMAC. */
|
||||
mac_async_enable( Ð_MAC );
|
||||
mac_async_enable_irq( Ð_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( Ð_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( Ð_MAC, xAddress, xRegister, pulValue );
|
||||
prvGMACEnablePHYManagementPort( false );
|
||||
return writeStatus;
|
||||
}
|
||||
|
||||
static inline bool bPHYGetLinkStatus( void )
|
||||
{
|
||||
return( xPhyObject.ulLinkStatusMask != 0 );
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
NetworkInterface.c:
|
||||
Requires NXP's LPCOpen library and was developed on an LPC1830 and LPC1835 Xplorer
|
||||
boards from NGX.
|
||||
|
|
@ -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 ];
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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 );
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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__ */
|
||||
|
|
@ -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.
|
||||
|
|
@ -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,
|
||||
ðer_receive_check_task_handle );
|
||||
|
||||
if( pdFALSE == return_code )
|
||||
{
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
return pdTRUE;
|
||||
} /* End of function InitializeNetwork() */
|
||||
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* Function Name: SendData ()
|
||||
* Description :
|
||||
* Arguments : pucBuffer, length
|
||||
* Return Value : 0 success, negative fail
|
||||
**********************************************************************************************************************/
|
||||
static int16_t SendData( uint8_t * pucBuffer,
|
||||
size_t length ) /*TODO complete stub function */
|
||||
{
|
||||
ether_return_t ret;
|
||||
uint8_t * pwrite_buffer;
|
||||
uint16_t write_buf_size;
|
||||
|
||||
/* (1) Retrieve the transmit buffer location controlled by the descriptor. */
|
||||
ret = R_ETHER_Write_ZC2_GetBuf( ETHER_CHANNEL_0, ( void ** ) &pwrite_buffer, &write_buf_size );
|
||||
|
||||
if( ETHER_SUCCESS == ret )
|
||||
{
|
||||
if( write_buf_size >= length )
|
||||
{
|
||||
memcpy( pwrite_buffer, pucBuffer, length );
|
||||
}
|
||||
|
||||
if( length < ETHER_BUFSIZE_MIN ) /*under minimum*/
|
||||
{
|
||||
memset( ( pwrite_buffer + length ), 0, ( ETHER_BUFSIZE_MIN - length ) ); /*padding*/
|
||||
length = ETHER_BUFSIZE_MIN; /*resize*/
|
||||
}
|
||||
|
||||
ret = R_ETHER_Write_ZC2_SetBuf( ETHER_CHANNEL_0, ( uint16_t ) length );
|
||||
ret = R_ETHER_CheckWrite( ETHER_CHANNEL_0 );
|
||||
}
|
||||
|
||||
if( ETHER_SUCCESS != ret )
|
||||
{
|
||||
return -5; /* XXX return meaningful value */
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
} /* End of function SendData() */
|
||||
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* Function Name: EINT_Trig_isr
|
||||
* Description : Standard frame received interrupt handler
|
||||
* Arguments : ectrl - EDMAC and ETHERC control structure
|
||||
* Return Value : None
|
||||
* Note : This callback function is executed when EINT0 interrupt occurred.
|
||||
***********************************************************************************************************************/
|
||||
void EINT_Trig_isr( void * ectrl )
|
||||
{
|
||||
ether_cb_arg_t * pdecode;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
pdecode = ( ether_cb_arg_t * ) ectrl;
|
||||
|
||||
if( pdecode->status_eesr & 0x00040000 ) /* EDMAC FR (Frame Receive Event) interrupt */
|
||||
{
|
||||
if( xTaskToNotify != NULL )
|
||||
{
|
||||
vTaskNotifyGiveFromISR( ether_receive_check_task_handle, &xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
/* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch
|
||||
* should be performed to ensure the interrupt returns directly to the highest
|
||||
* priority task. The macro used for this purpose is dependent on the port in
|
||||
* use and may be called portEND_SWITCHING_ISR(). */
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
/*TODO complete interrupt handler for other events. */
|
||||
}
|
||||
} /* End of function EINT_Trig_isr() */
|
||||
|
||||
|
||||
static void clear_all_ether_rx_discriptors( uint32_t event )
|
||||
{
|
||||
int32_t xBytesReceived;
|
||||
uint8_t * buffer_pointer;
|
||||
|
||||
/* Avoid compiler warning about unreferenced parameter. */
|
||||
( void ) event;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
/* See how much data was received. */
|
||||
xBytesReceived = R_ETHER_Read_ZC2( ETHER_CHANNEL_0, ( void ** ) &buffer_pointer );
|
||||
|
||||
if( 0 > xBytesReceived )
|
||||
{
|
||||
/* This is an error. Ignored. */
|
||||
}
|
||||
else if( 0 < xBytesReceived )
|
||||
{
|
||||
R_ETHER_Read_ZC2_BufRelease( ETHER_CHANNEL_0 );
|
||||
iptraceETHERNET_RX_EVENT_LOST();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* End of file "NetworkInterface.c"
|
||||
**********************************************************************************************************************/
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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
|
|
@ -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.
|
||||
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
Loading…
Reference in New Issue