Hi TCP-newbie, thank you for your interest in FreeRTOS+TCP.
Here is a summary about the network-down events:
The function vCheckNetworkTimers()
will be called in every IP-task loop. As long as one or more interfaces are not up, it will initiate a network down event.
- It will call
FreeRTOS_NetworkDown()
for a every interface which is down
- This function will send a
eNetworkDownEvent
to the IP-task
- It will check all endpoint of mentioned interface
- For each endpoint,
bEndPointUp
will be cleared
- For each endpoint
vApplicationIPNetworkEventHook_Multi()
will be called with the parameter eNetworkDown
- And then, most importantly,
pxInterface->pfInitialise()
is called to check the interface.
So it is normal that the down-event is repeated as long as pxInterface->pfInitialise()
fails.
The interval at which the event is repeated can be configured with:
/** @brief Time delay between repeated attempts to
* initialise the network hardware. */
#ifndef ipINITIALISATION_RETRY_DELAY
#define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000U ) )
#endif
PS. there are two minor issues:
- The macro
ipINITIALISATION_RETRY_DELAY
is defined locally in FreeRTOS_IP_Utils.c, but it is never used.
- In FreeRTOS_IP.c, the macro definition uses
pdMS_TO_TICKS()
, and when applying, again pdMS_TO_TICKS()
In all newer code, timing macro’s have an extension _TICKS
or _MS
, which makes clear if pdMS_TO_TICKS()
has to be called.
About the network interface. Many developers think that pfInitialise()
will be called only once, right after start-up. That is not true.
The function xxx_NetworkInterfaceInitialise()
will be called as long as it returns pdFAIL
.
Here is an example, borrowe dfrom the STM32Fx driver:
static BaseType_t xSTM32F_NetworkInterfaceInitialise( NetworkInterface_t * pxInterface )
{
if( xMacInitStatus == eMACInit )
{
/* Initialisation is only done once. */
if( ethernet_init() == pdPASS )
{
xMacInitStatus = eMACPass;
}
else
{
xMacInitStatus = eMACFailed;
}
} /* if( xMacInitStatus == eMACInit ) */
if( xMacInitStatus != eMACPass )
{
/* EMAC initialisation failed, return pdFAIL.
* This interface will not get into a working state anymore. */
xResult = pdFAIL;
}
else
{
if( xPhyObject.ulLinkStatusMask != 0U )
{
xResult = pdPASS;
}
else
{
/* For now pdFAIL will be returned. But prvEMACHandlerTask() is running
* and it will keep on checking the PHY and set 'ulLinkStatusMask' when necessary. */
xResult = pdFAIL;
}
}
/* When returning pdPASS, the stack will become active and
* start DHCP (in configured).
* Otherwise, this function will be called again. */
return xResult;
}
If you want, you can ignore the repeated events like eg. here:
static volatile BaseType_t xServerCanStart; /* Becomes true when the internet service can start-up. */
void vApplicationIPNetworkEventHook_Multi( eIPCallbackEvent_t eNetworkEvent,
struct xNetworkEndPoint * pxEndPoint )
{
static BaseType_t xLastEvent = -1;
if( xLastEvent != ( BaseType_t ) eNetworkEvent )
{
xLastEvent = ( BaseType_t ) eNetworkEvent;
if( eNetworkEvent == eNetworkUp )
{
xServerCanStart = pdTRUE;
}
}
else
{
/* Ignore this repeated event. */
}
}
/*-----------------------------------------------------------*/