FreeRTOS+TCP applications must provide a FreeRTOSIPConfig.h header file -
in which the parameters described on this page can be defined.
The Configuration Examples page demonstrates how to set key configuration parameters for systems that need to minimise RAM consumption and systems that need to maximise throughput.
The priority is a standard FreeRTOS task priority so can take any value from 0 (the lowest priority) to (configMAX_PRIORITIES - 1) (the highest priority). configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in FreeRTOSConfig.h, not FreeRTOSIPConfig.h.
Consideration needs to be given as to the priority assigned to the RTOS task executing the TCP/IP stack relative to the priority assigned to tasks that use the TCP/IP stack.
Do not define FreeRTOS_debug_printf if ipconfigHAS_DEBUG_PRINTF is set to 0.
The following code is taken from the FreeRTOS+TCP example for the RTOS's Win32 simulator, which has the ability to output debugging messages to a UDP port, standard out, and to a disk file:
/* Prototype for the function function that actually performs the output. */ extern void vLoggingPrintf( const char *pcFormatString, ... ); /* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to 1 then FreeRTOS_debug_printf should be defined to the function used to print out the debugging messages. */ #define ipconfigHAS_DEBUG_PRINTF 0 #if( ipconfigHAS_DEBUG_PRINTF == 1 ) #define FreeRTOS_debug_printf(X) vLoggingPrintf X #endif Defining ipconfigHAS_DEBUG_PRINTF and FreeRTOS_debug_printf in FreeRTOSIPConfig.h
The function that performs the output (vLoggingPrintf() in the code above) must be reentrant.
Do not define FreeRTOS_printf if ipconfigHAS_PRINTF is set to 0.
The following code is taken from the FreeRTOS+TCP example for the RTOS's Win32 simulator, which has the ability to output application messages to a UDP port, standard out, and to a disk file:
/* Prototype for the function function that actually performs the output. */ extern void vLoggingPrintf( const char *pcFormatString, ... ); /* Set to 1 to print out application messages. If ipconfigHAS_PRINTF is set to 1 then FreeRTOS_printf should be defined to the function used to print out the application messages. */ #define ipconfigHAS_PRINTF 0 #if( ipconfigHAS_PRINTF == 1 ) #define FreeRTOS_printf(X) vLoggingPrintf X #endif Defining ipconfigHAS_PRINTF and FreeRTOS_printf in FreeRTOSIPConfig.h
The function that performs the output (vLoggingPrintf() in the code above) must be reentrant.
#define ipconfigTCP_MAY_LOG_PORT(xPort) ( ( ( xPort ) != 23 ) && ( ( xPort ) != 2402 ) ) Filtering Log Messages
UBaseType_t uxGetMinimumIPQueueSpace( void ); uxGetMinimumIPQueueSpace() function prototype
ipconfigWATCHDOG_TIMER() can be defined to perform any action desired by the application writer. If ipconfigWATCHDOG_TIMER() is left undefined then it will be removed completely by the pre-processor (it will default to an empty macro).
Throughput and processor load are greatly improved by implementing drivers that make use of hardware checksum calculations.
Throughput and processor load are greatly improved by implementing drivers that make use of hardware checksum calculations.
Throughput and processor load are greatly improved by implementing network address filtering in hardware. Most network interfaces allow multiple MAC addresses to be defined so filtering can allow through the unique hardware address of the node, the broadcast address, and various multicast addresses.
Whereas ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is used to specify whether or not the network driver or hardware filters Ethernet frames, ipconfigETHERNET_DRIVER_FILTERS_PACKETS is used to specify whether or not the network driver filters the IP, UDP or TCP data within the Ethernet frame.
The TCP/IP stack is only interested in receiving data that is either addresses to a socket (IP address and port number) on the local node, or is a broadcast or multicast packet. Throughput and process load can be greatly improved by preventing packets that do not meet these criteria from being sent to the TCP/IP stack. FreeRTOS provides some features that allow such filtering to take place in the network driver. For example, xPortHasUDPSocket() can be used as follows: if( ( xPortHasUdpSocket( xUDPHeader->usDestinationPort ) ) #if( ipconfigUSE_DNS == 1 )/* DNS is also UDP. */ || ( xUDPHeader->usSourcePort == FreeRTOS_ntohs( ipDNS_PORT ) ) #endif #if( ipconfigUSE_LLMNR == 1 ) /* LLMNR is also UDP. */ || ( xUDPHeader->usDestinationPort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) #endif #if( ipconfigUSE_NBNS == 1 ) /* NBNS is also UDP. */ || ( xUDPHeader->usDestinationPort == FreeRTOS_ntohs( ipNBNS_PORT ) ) #endif ) { /* Forward packet to the IP-stack. */ } else { /* Discard the UDP packet. */ } Example of filtering UDP packets
If ipconfigNETWORK_MTU is not defined then the following defaults will be applied: #ifndef ipconfigNETWORK_MTU #ifdef( ipconfigUSE_TCP_WIN == 1 ) #define ipconfigNETWORK_MTU ( 1526 ) #else #define ipconfigNETWORK_MTU ( 1514 ) #endif #endif
More information on network buffers and network buffer descriptors is provided on the pages that describe porting FreeRTOS+TCP to other hardware and the pxGetNetworkBufferWithDescriptor() porting specific API function.
When ipconfigUSE_LINKED_RX_MESSAGES is set to 1 it is possible to reduce CPU load during periods of heavy network traffic by linking multiple received packets together, then passing all the linked packets to the IP RTOS task in one go.
If ipconfigZERO_COPY_TX_DRIVER is set to 1 then the driver function xNetworkInterfaceOutput() will always be called with its bReleaseAfterSend parameter set to pdTRUE - meaning it is always the driver that is responsible for freeing the network buffer and network buffer descriptor.
This is useful if the driver implements a zero-copy scheme whereby the packet data is sent directly from within the network buffer (for example by pointing a DMA descriptor at the data within the network buffer), instead of copying the data out of the network buffer before the data is sent (for example by copying the data into a separate pre-allocated DMA descriptor). In such cases the driver needs to take ownership of the network buffer because the network buffer can only be freed after the data has actually been transmitted - which might be some time after the xNetworkInterfaceOutput() function returns. See the examples on the Porting FreeRTOS to a Different Microcontroller documentation page for worked examples.
When the application requests a network buffer, the size of the network buffer is specified by the application writer, but the size of the network buffer actually obtained is increased by ipconfigBUFFER_PADDING bytes. The first ipconfigBUFFER_PADDING bytes of the buffer is then used to hold metadata about the buffer, and the area that actually stores the data follows the metadata. This mechanism is transparent to the user as the user only see a pointer to the area within the buffer actually used to hold network data.
Some network hardware has very specific byte alignment requirements, so ipconfigBUFFER_PADDING is provided as a configurable parameter to allow the writer of the network driver to influence the alignment of the start of the data that follows the metadata.
The default buffer size is (4 * ipconfigTCP_MSS).
FreeRTOS_setsockopt() can be used with the FREERTOS_SO_RCVBUF and FREERTOS_SO_SNDBUF parameters to set the receive and send buffer sizes respectively - but this must be done between the socket being created and the buffers used by the socket being created. The receive buffer is not created until data is actually received, and the transmit buffer is not created until data is actually sent to the socket for transmission. Once the buffers have been created their size cannot be changed.
If a listening socket creates a new socket in response to an incoming connect request then the new socket will inherit the buffers sizes of the listening socket.
Set ipconfigUSE_TCP_WIN to 1 to include sliding window behaviour in TCP sockets. Set ipconfigUSE_TCP_WIN to 0 to exclude sliding window behaviour in TCP sockets.
Sliding windows can increase throughput while minimising network traffic at the expense of consuming more RAM.
The size of the sliding window can be changed from its default using the FREERTOS_SO_WIN_PROPERTIES parameter to FreeRTOS_setsockopt(). The sliding window size is specified in units of MSS (so if the MSS is set to 200 bytes then a sliding window size of 2 is equal to 400 bytes) and must always be smaller than or equal to the size of the internal buffers in both directions.
If a listening socket creates a new socket in response to an incoming connect request then the new socket will inherit the sliding window sizes of the listening socket.
A pool of descriptors is allocated when the first TCP connection is made. The descriptors are shared between all the sockets. ipconfigTCP_WIN_SEG_COUNT set the number of descriptors in the pool, and each descriptor is approximately 64 bytes.
As an example: If a system will have at most 16 simultaneous TCP connections, and each connection will have an Rx and Tx window of at most 8 segments, then the worst case maximum number of descriptors that will be required is 256 ( 16 * 2 * 8 ). However, the practical worst case is normally much lower than this as most packets will arrive in order.
Set ipconfigUSE_TCP_TIMESTAMPS to 1 to include TCP time stamp functionality. Set ipconfigUSE_TCP_TIMESTAMPS to 0 to exclude TCP time stamp functionality.
Note that FreeRTOS+TCP contains checks that the defined ipconfigNETWORK_MTU and ipconfigTCP_MSS values are consistent with each other.
Set ipconfigTCP_KEEP_ALIVE to 1 to have FreeRTOS+TCP periodically send keep alive messages on connected but dormant sockets. Set ipconfigTCP_KEEP_ALIVE to 0 to prevent the automatic transmission of keep alive messages.
If FreeRTOS+TCP does not receive a reply to a keep alive message then the connection will be broken and the socket will be marked as closed. Subsequent FreeRTOS_recv() calls on the socket will return -pdFREERTOS_ERRNO_ENOTCONN.
The maximum allowable send block time is capped to the value set by ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS. Capping the maximum allowable send block time prevents prevents a deadlock occurring when all the network buffers are in use and the tasks that process (and subsequently free) the network buffers are themselves blocked waiting for a network buffer.
ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in milliseconds can be converted to a time in ticks by dividing the time in milliseconds by portTICK_PERIOD_MS.
ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME is specified in ticks. The macros pdMS_TO_TICKS() and portTICK_PERIOD_MS can both be used to convert a time specified in milliseconds to a time specified in ticks.
The time out time can be changed at any time using the FREERTOS_SO_RCVTIMEO parameter with FreeRTOS_setsockopt(). Note: Infinite block times should be used with extreme care in order to avoid a situation where all tasks are blocked indefinitely to wait for another RTOS task (which is also blocked indefinitely) to free a network buffer.
A socket can be set to non-blocking mode by setting both the send and receive block time to 0. This might be desirable when an RTOS task is using more than one socket - in which case blocking can instead by performed on all the sockets at once using FreeRTOS_select(), or the RTOS task can set ipconfigSOCKET_HAS_USER_SEMAPHORE to one then block on its own semaphore.
ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME is specified in ticks. The macros pdMS_TO_TICKS() and portTICK_PERIOD_MS can both be used to convert a time specified in milliseconds to a time specified in ticks.
The time out time can be changed at any time using the FREERTOS_SO_SNDTIMEO parameter with FreeRTOS_setsockopt(). Note: Infinite block times should be used with extreme care in order to avoid a situation where all tasks are blocked indefinitely to wait for another RTOS task (which is also blocked indefinitely) to free a network buffer.
A socket can be set to non-blocking mode by setting both the send and receive block time to 0. This might be desirable when an RTOS task is using more than one socket - in which case blocking can instead by performed on all the sockets at once using FreeRTOS_select(), or the RTOS task can set ipconfigSOCKET_HAS_USER_SEMAPHORE to one then block on its own semaphore.
A socket can be set to non-blocking mode by setting both the send and receive block time to 0.
If an RTOS task is using multiple sockets and cannot block on one socket at a time then the sockets can be set into non-blocking mode, and the RTOS task can block on all the sockets at once by either using the FreeRTOS_select() function or by setting ipconfigSOCKET_HAS_USER_SEMAPHORE to 1, using the FREERTOS_SO_SET_SEMAPHORE parameter with FreeRTOS_setsockopt() to provide a semaphore to the socket, and then blocking on the semaphore. The semaphore will be given when any of the sockets are able to proceed - at which time the RTOS task can inspect all the sockets individually using non blocking API calls to determine which socket caused it to unblock.
The IP stack can only send a UDP message to a remove IP address if it knowns the MAC address associated with the IP address, or the MAC address of the router used to contact the remote IP address. When a UDP message is received from a remote IP address the MAC address and IP address are added to the ARP cache. When a UDP message is sent to a remote IP address that does not already appear in the ARP cache then the UDP message is replaced by a ARP message that solicits the required MAC address information.
ipconfigARP_CACHE_ENTRIES defines the maximum number of entries that can exist in the ARP table at any one time.
ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is equal to 1500 seconds (or 25 minutes).
If ipconfigARP_REVERSED_LOOKUP is set to 1 then the xGetARPCacheEntryByMac() function is available for use. xGetARPCacheEntryByMac() performs an IP address look up from a MAC address.
ipconfigARP_STORES_REMOTE_ADDRESSES is provided for the case when a message that requires a reply arrives from the Internet, but from a computer attached to a LAN rather than via the defined gateway. Before replying to the message the TCP/IP stack RTOS task will loop up the message's IP address in the ARP table - but if ipconfigARP_STORES_REMOTE_ADDRESSES is set to 0 then ARP will return the MAC address of the defined gateway because the destination address is outside of the netmask. That might prevent the reply reaching its intended destination.
If ipconfigARP_STORES_REMOTE_ADDRESSES is set to 1 then remote addresses will also be stored in the ARP table, along with the MAC address from which the message was received. This can allow the message in the scenario above to be routed and delivered correctly.
Normally ARP will look up an IP address from a MAC address. If ipconfigUSE_ARP_REVERSED_LOOKUP is set to 1 then a function that does the reverse is also available. eARPGetCacheEntryByMac() looks up a MAC address from an IP address.
eARPLookupResult_t eARPGetCacheEntryByMac( MACAddress_t * const pxMACAddress, uint32_t *pulIPAddress ); eARPGetCacheEntryByMac() function prototype
If ipconfigUSE_ARP_REMOVE_ENTRY is set to 1 then ulARPRemoveCacheEntryByMac() is included in the build. ulARPRemoveCacheEntryByMac() uses a MAC address to look up, and then remove, an entry from the ARP cache. If the MAC address is found in the ARP cache then the IP address associated with the MAC address is returned. If the MAC address is not found in the ARP cache then 0 is returned.
uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress ); ulARPRemoveCacheEntryByMac() function prototype
If ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will not attempt to obtain its address information from a DHCP server, and instead immediately use the defined static address information.
If ipconfigUSE_DHCP_HOOK is set to 1 then FreeRTOS+TCP will call an application provided hook (or 'callback') function called xApplicationDHCPUserHook() both before the initial discovery packet is sent, and after a DHCP offer has been received - the hook function can be used to terminate the DHCP process at either one of these two phases in the DHCP sequence. For example, the application writer can effectively disable DHCP, even when ipconfigUSE_DHCP is set to 1, by terminating the DHCP process before the initial discovery packet is sent. As another example, the application writer can check a static IP address is compatible with the network to which the device is connected by receiving an IP address offer from a DHCP server, but then terminating the DHCP process without sending a request packet to claim the offered IP address.
If ipconfigUSE_DHCP_HOOK is set to 1 then the application writer must provide a hook (callback) function with the following name and prototype: eDHCPCallbackAnswer_t xApplicationDHCPHook( eDHCPCallbackPhase_t eDHCPPhase, uint32_t ulIPAddress ); The name and prototype of the DHCP application hook function
Where eDHCPCallbackQuestion_t and eDHCPCallbackAnswer_t are defined as follows
typedef enum eDHCP_QUESTIONS
{
/* About to send discover packet. */
eDHCPPhasePreDiscover,
/* About to send a request packet. */
eDHCPPhasePreRequest,
} eDHCPCallbackQuestion_t;
typedef enum eDHCP_ANSWERS
{
/* Continue the DHCP process as normal. */
eDHCPContinue,
/* Stop the DHCP process, and use the static defaults. */
eDHCPUseDefaults,
/* Stop the DHCP process, and continue with current settings. */
eDHCPStopNoChanges,
} eDHCPCallbackAnswer_t;
The eDHCPCallbackQuestion_t and eDHCPCallbackAnswer_t definitions
For example purposes only, below is a reference xApplicationDHCPHook implementation
that allows the DHCP sequence to proceed up to the point where an IP address is
offered, at which point the offered IP address is compared to the statically
configured IP address. If the offered and statically configured IP addresses are
on the same subnet then the statically configured IP address is used. If the
offered and statically configured IP addresses are not on the same subnet then
the IP address offered by the DHCP server is used.
eDHCPCallbackAnswer_t xApplicationDHCPHook( eDHCPCallbackPhase_t eDHCPPhase,
uint32_t ulIPAddress )
{
eDHCPCallbackAnswer_t eReturn;
uint32_t ulStaticIPAddress, ulStaticNetMask;
/* This hook is called in a couple of places during the DHCP process, as
identified by the eDHCPPhase parameter. */
switch( eDHCPPhase )
{
case eDHCPPhasePreDiscover :
/* A DHCP discovery is about to be sent out. eDHCPContinue is
returned to allow the discovery to go out.
If eDHCPUseDefaults had been returned instead then the DHCP process
would be stopped and the statically configured IP address would be
used.
If eDHCPStopNoChanges had been returned instead then the DHCP
process would be stopped and whatever the current network
configuration was would continue to be used. */
eReturn = eDHCPContinue;
break;
case eDHCPPhasePreRequest :
/* An offer has been received from the DHCP server, and the offered
IP address is passed in the ulIPAddress parameter. Convert the
offered and statically allocated IP addresses to 32-bit values. */
ulStaticIPAddress = FreeRTOS_inet_addr_quick( configIP_ADDR0,
configIP_ADDR1,
configIP_ADDR2,
configIP_ADDR3 );
ulStaticNetMask = FreeRTOS_inet_addr_quick( configNET_MASK0,
configNET_MASK1,
configNET_MASK2,
configNET_MASK3 );
/* Mask the IP addresses to leave just the sub-domain octets. */
ulStaticIPAddress &= ulStaticNetMask;
ulIPAddress &= ulStaticNetMask;
/* Are the sub-domains the same? */
if( ulStaticIPAddress == ulIPAddress )
{
/* The sub-domains match, so the default IP address can be
used. The DHCP process is stopped at this point. */
eReturn = eDHCPUseDefaults;
}
else
{
/* The sub-domains don't match, so continue with the DHCP
process so the offered IP address is used. */
eReturn = eDHCPContinue;
}
break;
default :
/* Cannot be reached, but set eReturn to prevent compiler warnings
where compilers are disposed to generating one. */
eReturn = eDHCPContinue;
break;
}
return eReturn;
}
A reference xApplicationDHCPHook() implementation
When the eDHCPPhase parameter is set to eDHCPPhasePreDiscover the ulIPAddress
parameter is set to the IP address already in use. When the
eDHCPPhase parameter is set to eDHCPPhasePreRequest the ulIPAddress parameter is set to
the IP address offered by the DHCP server.
When ipconfigDHCP_REGISTER_HOSTNAME is set to 1 the application must provide a hook (callback) function with the following name and prototype: const char *pcApplicationHostnameHook( void ); The name and prototype of the application provided hook function that returns the devices name
Note: The random number generator must be seeded before the TCP/IP stack is started, so before FreeRTOS_IPInit() is called.