static void prvIPTask()

in FreeRTOS_IP.c [375:628]


static void prvIPTask( void * pvParameters )
{
    IPStackEvent_t xReceivedEvent;
    TickType_t xNextIPSleep;
    FreeRTOS_Socket_t * pxSocket;
    struct freertos_sockaddr xAddress;

    /* Just to prevent compiler warnings about unused parameters. */
    ( void ) pvParameters;

    /* A possibility to set some additional task properties. */
    iptraceIP_TASK_STARTING();

    /* Generate a dummy message to say that the network connection has gone
     *  down.  This will cause this task to initialise the network interface.  After
     *  this it is the responsibility of the network interface hardware driver to
     *  send this message if a previously connected network is disconnected. */
    FreeRTOS_NetworkDown();

    #if ( ipconfigUSE_TCP == 1 )
        {
            /* Initialise the TCP timer. */
            prvIPTimerReload( &xTCPTimer, pdMS_TO_TICKS( ipTCP_TIMER_PERIOD_MS ) );
        }
    #endif

    /* Mark the timer as inactive since we are not waiting on any ARP resolution as of now. */
    vIPSetARPResolutionTimerEnableState( pdFALSE );

    /* Initialisation is complete and events can now be processed. */
    xIPTaskInitialised = pdTRUE;

    FreeRTOS_debug_printf( ( "prvIPTask started\n" ) );

    /* Loop, processing IP events. */
    for( ; ; )
    {
        ipconfigWATCHDOG_TIMER();

        /* Check the ARP, DHCP and TCP timers to see if there is any periodic
         * or timeout processing to perform. */
        prvCheckNetworkTimers();

        /* Calculate the acceptable maximum sleep time. */
        xNextIPSleep = prvCalculateSleepTime();

        /* Wait until there is something to do. If the following call exits
         * due to a time out rather than a message being received, set a
         * 'NoEvent' value. */
        if( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep ) == pdFALSE )
        {
            xReceivedEvent.eEventType = eNoEvent;
        }

        #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
            {
                if( xReceivedEvent.eEventType != eNoEvent )
                {
                    UBaseType_t uxCount;

                    uxCount = uxQueueSpacesAvailable( xNetworkEventQueue );

                    if( uxQueueMinimumSpace > uxCount )
                    {
                        uxQueueMinimumSpace = uxCount;
                    }
                }
            }
        #endif /* ipconfigCHECK_IP_QUEUE_SPACE */

        iptraceNETWORK_EVENT_RECEIVED( xReceivedEvent.eEventType );

        switch( xReceivedEvent.eEventType )
        {
            case eNetworkDownEvent:
                /* Attempt to establish a connection. */
                xNetworkUp = pdFALSE;
                prvProcessNetworkDownEvent();
                break;

            case eNetworkRxEvent:

                /* The network hardware driver has received a new packet.  A
                 * pointer to the received buffer is located in the pvData member
                 * of the received event structure. */
                prvHandleEthernetPacket( ipCAST_PTR_TO_TYPE_PTR( NetworkBufferDescriptor_t, xReceivedEvent.pvData ) );
                break;

            case eNetworkTxEvent:

               {
                   NetworkBufferDescriptor_t * pxDescriptor = ipCAST_PTR_TO_TYPE_PTR( NetworkBufferDescriptor_t, xReceivedEvent.pvData );

                   /* Send a network packet. The ownership will  be transferred to
                    * the driver, which will release it after delivery. */
                   iptraceNETWORK_INTERFACE_OUTPUT( pxDescriptor->xDataLength, pxDescriptor->pucEthernetBuffer );
                   ( void ) xNetworkInterfaceOutput( pxDescriptor, pdTRUE );
               }

               break;

            case eARPTimerEvent:
                /* The ARP timer has expired, process the ARP cache. */
                vARPAgeCache();
                break;

            case eSocketBindEvent:

                /* FreeRTOS_bind (a user API) wants the IP-task to bind a socket
                 * to a port. The port number is communicated in the socket field
                 * usLocalPort. vSocketBind() will actually bind the socket and the
                 * API will unblock as soon as the eSOCKET_BOUND event is
                 * triggered. */
                pxSocket = ipCAST_PTR_TO_TYPE_PTR( FreeRTOS_Socket_t, xReceivedEvent.pvData );
                xAddress.sin_addr = 0U; /* For the moment. */
                xAddress.sin_port = FreeRTOS_ntohs( pxSocket->usLocalPort );
                pxSocket->usLocalPort = 0U;
                ( void ) vSocketBind( pxSocket, &xAddress, sizeof( xAddress ), pdFALSE );

                /* Before 'eSocketBindEvent' was sent it was tested that
                 * ( xEventGroup != NULL ) so it can be used now to wake up the
                 * user. */
                pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_BOUND;
                vSocketWakeUpUser( pxSocket );
                break;

            case eSocketCloseEvent:

                /* The user API FreeRTOS_closesocket() has sent a message to the
                 * IP-task to actually close a socket. This is handled in
                 * vSocketClose().  As the socket gets closed, there is no way to
                 * report back to the API, so the API won't wait for the result */
                ( void ) vSocketClose( ipCAST_PTR_TO_TYPE_PTR( FreeRTOS_Socket_t, xReceivedEvent.pvData ) );
                break;

            case eStackTxEvent:

                /* The network stack has generated a packet to send.  A
                 * pointer to the generated buffer is located in the pvData
                 * member of the received event structure. */
                vProcessGeneratedUDPPacket( ipCAST_PTR_TO_TYPE_PTR( NetworkBufferDescriptor_t, xReceivedEvent.pvData ) );
                break;

            case eDHCPEvent:
                /* The DHCP state machine needs processing. */
                #if ( ipconfigUSE_DHCP == 1 )
                    {
                        uintptr_t uxState;
                        eDHCPState_t eState;

                        /* Cast in two steps to please MISRA. */
                        uxState = ( uintptr_t ) xReceivedEvent.pvData;
                        eState = ( eDHCPState_t ) uxState;

                        /* Process DHCP messages for a given end-point. */
                        vDHCPProcess( pdFALSE, eState );
                    }
                #endif /* ipconfigUSE_DHCP */
                break;

            case eSocketSelectEvent:

                /* FreeRTOS_select() has got unblocked by a socket event,
                 * vSocketSelect() will check which sockets actually have an event
                 * and update the socket field xSocketBits. */
                #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
                    #if ( ipconfigSELECT_USES_NOTIFY != 0 )
                        {
                            SocketSelectMessage_t * pxMessage = ipCAST_PTR_TO_TYPE_PTR( SocketSelectMessage_t, xReceivedEvent.pvData );
                            vSocketSelect( pxMessage->pxSocketSet );
                            ( void ) xTaskNotifyGive( pxMessage->xTaskhandle );
                        }
                    #else
                        {
                            vSocketSelect( ipCAST_PTR_TO_TYPE_PTR( SocketSelect_t, xReceivedEvent.pvData ) );
                        }
                    #endif /* ( ipconfigSELECT_USES_NOTIFY != 0 ) */
                #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
                break;

            case eSocketSignalEvent:
                #if ( ipconfigSUPPORT_SIGNALS != 0 )

                    /* Some task wants to signal the user of this socket in
                     * order to interrupt a call to recv() or a call to select(). */
                    ( void ) FreeRTOS_SignalSocket( ipPOINTER_CAST( Socket_t, xReceivedEvent.pvData ) );
                #endif /* ipconfigSUPPORT_SIGNALS */
                break;

            case eTCPTimerEvent:
                #if ( ipconfigUSE_TCP == 1 )

                    /* Simply mark the TCP timer as expired so it gets processed
                     * the next time prvCheckNetworkTimers() is called. */
                    xTCPTimer.bExpired = pdTRUE_UNSIGNED;
                #endif /* ipconfigUSE_TCP */
                break;

            case eTCPAcceptEvent:

                /* The API FreeRTOS_accept() was called, the IP-task will now
                 * check if the listening socket (communicated in pvData) actually
                 * received a new connection. */
                #if ( ipconfigUSE_TCP == 1 )
                    pxSocket = ipCAST_PTR_TO_TYPE_PTR( FreeRTOS_Socket_t, xReceivedEvent.pvData );

                    if( xTCPCheckNewClient( pxSocket ) != pdFALSE )
                    {
                        pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_ACCEPT;
                        vSocketWakeUpUser( pxSocket );
                    }
                #endif /* ipconfigUSE_TCP */
                break;

            case eTCPNetStat:

                /* FreeRTOS_netstat() was called to have the IP-task print an
                 * overview of all sockets and their connections */
                #if ( ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_PRINTF == 1 ) )
                    vTCPNetStat();
                #endif /* ipconfigUSE_TCP */
                break;

            case eSocketSetDeleteEvent:
                #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
                    {
                        SocketSelect_t * pxSocketSet = ( SocketSelect_t * ) ( xReceivedEvent.pvData );

                        iptraceMEM_STATS_DELETE( pxSocketSet );
                        vEventGroupDelete( pxSocketSet->xSelectGroup );
                        vPortFree( ( void * ) pxSocketSet );
                    }
                #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
                break;

            case eNoEvent:
                /* xQueueReceive() returned because of a normal time-out. */
                break;

            default:
                /* Should not get here. */
                break;
        }

        if( xNetworkDownEventPending != pdFALSE )
        {
            /* A network down event could not be posted to the network event
             * queue because the queue was full.
             * As this code runs in the IP-task, it can be done directly by
             * calling prvProcessNetworkDownEvent(). */
            prvProcessNetworkDownEvent();
        }
    }
}