FreeRTOS-PLUS-TCP: Repeated eNetworkDownEvent events

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.

  1. It will call FreeRTOS_NetworkDown() for a every interface which is down
  2. This function will send a eNetworkDownEvent to the IP-task
  3. It will check all endpoint of mentioned interface
  4. For each endpoint, bEndPointUp will be cleared
  5. For each endpoint vApplicationIPNetworkEventHook_Multi() will be called with the parameter eNetworkDown
  6. 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:

  1. The macro ipINITIALISATION_RETRY_DELAY is defined locally in FreeRTOS_IP_Utils.c, but it is never used.
  2. 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. */
    }
}
/*-----------------------------------------------------------*/
1 Like