FreeRTOS IP callbacks

Hi I’ve written some code (see below) that implements a connect/disconnet/receiver using IP sockets and callback functions. Somehow this ends in the Dummy_Handler()… Essentialy a socket is created, a callback function is associated with this socket to process events Connect and Disconnect. When a connect happens an accept is called and a receiving socket is created and associated with another callback function. When a disconnect happens the receiving socket is closed. When data arrives some information is printed. ALl the communication between the callback functions and the main task is done through a message Queue. Could someone validate this code? It may happen that the code is not using the FreeRTOS IP functions correctly… I’ve placed several breakpoints and I cannot figure out what makes the code crash. ~~~ static void CallbackOnConnectDisconnect ( Sockett xSocket, BaseTypet ulConnected ) { CallbackMessaget CallbackMessage;
Callback_Message.type = Callback_Connect_Disconnect;
Callback_Message.Connect_Disconnect.xSocket = xSocket;
Callback_Message.Connect_Disconnect.ulConnected = ulConnected;

if ( xQueueSend ( xQueue_Callback, (void*) &Callback_Message, 0 ) != pdPASS )
    /* In case there is no space in the Queue,
     * we should print something to the service port but we are inside FreeRTOS IP so it's better just increment a counter.
     * The printing will take place in the main loop.
     */
    xQueue_Callback_Errors++;
} static BaseTypet CallbackOnReceive ( Sockett xSocket, void * pData, sizet xLength ) { CallbackMessaget Callback_Message;
Callback_Message.type = Callback_Receive;
Callback_Message.Receive.xSocket = xSocket;
Callback_Message.Receive.pData   = pData;
Callback_Message.Receive.xLength = xLength;

if ( xQueueSend ( xQueue_Callback, (void*) &Callback_Message, 0 ) != pdPASS )
    /* In case there is no space in the Queue,
     * we should print something to the service port but we are inside FreeRTOS IP so it's better just increment a counter.
     * The printing will take place in the main loop.
     */
    xQueue_Callback_Errors++;

return 1;
} void taskIPreceiver ( void *pvParameters ) { Sockett IPacceptSocket, IPreceiverSocket; struct freertossockaddr xClient, xBindAddress; const TickTypet xTimeOut = pdMSTOTICKS( 2000 ); const TickTypet xZeroTimeOut = 0; socklent xSize = sizeof (struct freertossockaddr); FTCPUDPHandlert HandlerOnConnectDisconnect;
SP_Printf ( "task_IPreceiver[] running..." );

/* Create a queue capable of containing 10 callback messages. */
xQueue_Callback = xQueueCreate ( 10, sizeof(Callback_Message_t) );

IPaccept_Socket = FreeRTOS_socket ( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
if ( IPaccept_Socket == NULL )
    SP_Printf_h ( "ERROR - task_IPaccept[] - FreeRTOS_socket failed" );

xBindAddress.sin_port = FreeRTOS_htons ( VDUI_SERVER_PORT );

FreeRTOS_bind ( IPaccept_Socket, &xBindAddress, sizeof(xBindAddress) );

FreeRTOS_listen ( IPaccept_Socket, IP_MAX_CONNECTIONS );


/* Install a callback for connection and disconnection events. */
Handler_OnConnectDisconnect.pxOnTCPConnected = Callback_OnConnectDisconnect;
FreeRTOS_setsockopt ( IPaccept_Socket, 0, FREERTOS_SO_TCP_CONN_HANDLER, (void *) &Handler_OnConnectDisconnect, sizeof(Handler_OnConnectDisconnect) );

//IPconnections_Initialise();

for (;;)
{
    Callback_Message_t Callback_Message;

    if ( xQueue_Callback_Errors != xQueue_Callback_Errors_prev )
    {
        SP_Printf ( "WARNING - task_IPreceiver[] - xQueue_Callback_Errors %d", xQueue_Callback_Errors );
        xQueue_Callback_Errors_prev = xQueue_Callback_Errors;
    }

    if ( xQueueReceive ( xQueue_Callback, &Callback_Message, portMAX_DELAY ) )
    {
        switch ( Callback_Message.type )
        {
            case Callback_Connect_Disconnect:
            {
                F_TCP_UDP_Handler_t Handler_OnReceive;

                if ( Callback_Message.Connect_Disconnect.ulConnected )
                {
                    IPreceiver_Socket = FreeRTOS_accept ( IPaccept_Socket, &xClient, &xSize );

                    SP_Printf ( "Connection accepted %d", IPreceiver_Socket );

                    /* Install a callback for receiving TCP data. */
                    Handler_OnConnectDisconnect.pxOnTCPReceive = Callback_OnReceive;
                    FreeRTOS_setsockopt ( IPreceiver_Socket, 0, FREERTOS_SO_TCP_RECV_HANDLER, (void *) &Handler_OnReceive, sizeof(Handler_OnReceive) );
                }
                else
                {
                    FreeRTOS_shutdown ( Callback_Message.Connect_Disconnect.xSocket, FREERTOS_SHUT_RDWR );
                    FreeRTOS_closesocket ( Callback_Message.Connect_Disconnect.xSocket );

                    SP_Printf ( "Connection closed %d", Callback_Message.Connect_Disconnect.xSocket );
                }
            }break;

            case Callback_Receive:
            {
                static uint8_t Data [1000];
                int32_t receivedData;

                receivedData = FreeRTOS_recv ( Callback_Message.Receive.xSocket, Data/*pvBuffer*/, sizeof(Data)/*xBufferLength*/, 0/*xFlags*/ );

                SP_Printf ( "Callback_Receive Callback_Message.Receive.xSocket %d Callback_Message.Receive.xLength %d receivedData %d",
                                    Callback_Message.Receive.xSocket, Callback_Message.Receive.xLength, receivedData );
            }break;
        }
    }
}
} ~~~

FreeRTOS IP callbacks

The code looks perfect to me. It is an original approach! Isn’t the Dummy_Handler() called as a default handler, in case no other exception handler is defined? The problem might be unrelated to the code that you show here. Maybe it is an interrupt from a peripheral that you forgot to implement? Well, one remark regarding the code: ~~~ FreeRTOSshutdown ( CallbackMessage.ConnectDisconnect.xSocket, FREERTOSSHUTRDWR ); FreeRTOSclosesocket ( CallbackMessage.ConnectDisconnect.xSocket ); ~~~ Here a disconnect was detected, and therefore it makes no sense to call FreeRTOS_shutdown(). It is enough to close the socket. This is unrelated to the crash though.

FreeRTOS IP callbacks

In case you’re interest in using FreeRTOS_shutdown(). Here is an example where it is useful, e.g. to initiate a graceful close of a TCP connection: +TCP – How force a close on a TCP connection on a Remote Server And here is a more complicated example: data is still being sent while the closure has been initiated: FreeRTOSrecv returns pdFREERTOSERRNO_ENOTCONN but also all the data

FreeRTOS IP callbacks

thanks for the answer. I would prefered to have used semaphores. As you suggested in this thread: https://sourceforge.net/p/freertos/discussion/382005/thread/cc5add6c85/?limit=25 But I coudn’t figure out after Take the semaphore which functions to call to find the reason for the Give on the semaphore. – A connection is established ( either accept() or connect() ) – A connection is broken ( or an error occurred ) – Data has arrived I don’t think there are any other interrupts happening! The default handler for interrupts in the DummyHandler() as defined in startupsame70.c. I think I can find in some registers info about what generated the crash. I’ll investigate…

FreeRTOS IP callbacks

I found where it crashes: FreeRTOS_Sockets.c, version FreeRTOS+TCP V2.0.7 line 3021, pxSocket->u.xTCP.pxHandleReceive( (Sockett *)pxSocket, ( void* )ucReadPtr, ( sizet ) ulCount ); pxHandleReceive has the impossible value of 0xA5A5A5A5, which must be stack related since the stack is filled with 0xA5s… (See attachment, please.) Any ideas? Thanks.

FreeRTOS IP callbacks

Ah bugs… 🙂 Handler_OnConnectDisconnect.pxOnTCPReceive = CallbackOnReceive; should be instead: Handler_OnReceive.pxOnTCPReceive = CallbackOnReceive;

FreeRTOS IP callbacks

A copy & paste error 🙂
I would preferred to have used semaphores.
When using semaphores, you would have to check all sockets that are owned by the task. I would embed each socket in an object that describes exactly the current status. If you look at the FTP/HTTP server on freertos/tcp, it will become clear what I mean. The status can be:
  • Wait for connect
  • Receiving a file
  • Sending a file
  • Idle state, waiting for a new command
  • Waiting for a closure

FreeRTOS IP callbacks

thanks for the answer I cannot find that example! The only place that I cand find using FREERTOSSOSET_SEMAPHORE is: 160919FreeRTOSLabs/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/NTP/NTPDemo.c Nevertheless, now that thye callbacks are almost working maybe I’ll stick with them 🙂 I still have a problem which may be the result of my misunderstanding. This is the callback for Receiving: ~~~ static BaseTypet CallbackOnReceive ( Sockett xSocket, void * pData, sizet xLength ) { CallbackMessaget Callback_Message;
Callback_Message.type = Callback_Receive;
Callback_Message.Receive.xSocket = xSocket;
Callback_Message.Receive.pData   = pData;
Callback_Message.Receive.xLength = xLength;

if ( xQueueSend ( xQueue_Callback, (void*) &Callback_Message, 0 ) != pdPASS )
    /* In case there is no space in the Queue,
     * we should print something to the service port but we are inside FreeRTOS IP so it's better just increment a counter.
     * The printing will take place in the main loop.
     */
    xQueue_Callback_Errors++;

return 1;
} ~~~ I just put the pointer for the data and the size of the data into a message queue. On the main task then: ~~~ case CallbackReceive: { static uint8t Data [1000]; int32_t receivedData;
                receivedData = FreeRTOS_recv ( Callback_Message.Receive.xSocket, Data/*pvBuffer*/, sizeof(Data)/*xBufferLength*/, 0/*xFlags*/ );

                if ( receivedData == FREERTOS_ECLOSED )
                    SP_Printf ( "Socket %d is not connected", Callback_Message.Receive.xSocket );
                else
                    SP_Printf ( "Callback_Receive Callback_Message.Receive.xSocket %d Callback_Message.Receive.xLength %d receivedData %d",
                                    Callback_Message.Receive.xSocket, Callback_Message.Receive.xLength, receivedData );
            }break;
~~~ I call FreeRTOS_recv to get the data out. Is this correct? I can only see receivedData with -128 (connection closed) or 0 (zero bytes). Should I retrieve the data inside the callback? That would mean allocating a buffer of the size of the message, copy the data and free it after processing… Is this the right approach? How does FreeRTOS IP know that the data received has been used and therefor can be discarded? thanks

FreeRTOS IP callbacks

I cannot find that example!
Sorry, you’re right: the example doesn’t use a semaphore but FreeRTOS_select(). The implementation is the same however: every socket is embedded in a structure that stores the status of the connection. All sockets are checked in every loop.
160919FreeRTOSLabs
Please note that the +TCP sources in that distribution are very old. It is still there because of the old demo’s that used +FAT, and the FTP/HTTP servers. The latest release of +FAT can be found on the /labs download page. +TCP can be found on e.g. github/aws
This is the callback for Receiving: static BaseType_t Callback_OnReceive ( Socket_t xSocket, void * pData, size_t xLength ) { Callback_Message_t Callback_Message; Callback_Message.type = Callback_Receive; Callback_Message.Receive.xSocket = xSocket; Callback_Message.Receive.pData = pData; Callback_Message.Receive.xLength = xLength;
Oops: the pointer pData will become invalid after the function returns. So you only access it from within this function.
I call FreeRTOS_recv to get the data out. Is this correct?
Yes that is OK.
I can only see receivedData with -128 (connection closed) or 0 (zero bytes).
The data were flushed ( not stored ) because your function Callback_OnReceive() returned a positive value. When it returns zero, the data will be stored in the RX stream buffer of the socket.
Should I retrieve the data inside the callback?
No let the socket store it and you retrieve it later.
How does FreeRTOS IP know that the data received has been used and therefore can be discarded?
So yes, it looks at the return value: 1 = data consumed, 0 = please store data
if ( receivedData == FREERTOS_ECLOSED )
Note that there are two error codes that are not fatal: -pdFREERTOS_ERRNO_EAGAIN and -pdFREERTOS_ERRNO_EINTR. All other negative values must be treated in the same way as -pdFREERTOS_ERRNO_ENOTCONN: call closesocket().

FreeRTOS IP callbacks

I had some feeling about the return 1; on the callback function. So I followed the code after returning and in fact on the file: FreeRTOSSockets.c, version V2.0.7, line 3021 ~~~ pxSocket->u.xTCP.pxHandleReceive( (Sockett )pxSocket, ( void )ucReadPtr, ( size_t ) ulCount ); ~~~ Nothing is done with the value returned!!! Is there any ‘#define’ trick here? Could I have an outdated file? I have checked in FreeRTOS 10.2.0, V2.0.11 that I have downloaded and the line is the same. The return value is also not used. Could the feature: value 1 = data consumed, 0 = please store data be not yet implemented? thanks

FreeRTOS IP callbacks

Oops, my bad: there has been an earlier version in which the return code was used. But there was a problem with that solution and then we decided to always remove the data from the RX stream buffer: ~~~ pxSocket->u.xTCP.pxHandleReceive( (Sockett *)pxSocket, ( void* )ucReadPtr, ( sizet ) ulCount ); uxStreamBufferGet( pxStream, 0ul, NULL, ( size_t ) ulCount, pdFALSE ); ~~~ It was a theretical problem: suppose that the Receive handler function returns 0, 1, 0, 1, The wrong data would be kept in the RX buffer. You can either consume the data within the handler, or copy/store it in a separate circular buffer, and pass it to the task. I’m sorry about that.

FreeRTOS IP callbacks

Got it 🙂 Could I suggest that maybe it is better to do it the other way. Never to take the data out. In this way no buffer needs to be allocated by using pvPortMalloc in the callback function: ~~~ pDatanew = pvPortMalloc ( xLength ); memcpy ( pDatanew, pData, xLength ); ~~~ Instead this is done in the receiver task: ~~~ pDatanew = pvPortMalloc ( CallbackMessage.Receive.xLength ); receivedData = FreeRTOSrecv ( CallbackMessage.Receive.xSocket, pDatanew/*pvBuffer*/, CallbackMessage.Receive.xLength, 0/xFlags/ ); ~~~ This would make the time inside the callback function smaller and deterministic. The allocation method can be time underterministic (I think there are some heap management methods in FreeRTOS that are deterministic but others aren’t…). Instead of allocating memory one could declare a static variable of say 100 bytes, big enough to conatin any legal message. This would make the code faster and deterministic. Another way would be to use a setsockopt call: ~~~ reeRTOSsetsockopt ( IPreceiverSocket, 0, FREERTOSSOTCPRECVHANDLERCONSUMEDATA, 0 or 1 … ); ~~~ Before setting the callback function change FREERTOSSOTCPRECVHANDLERCONSUMEDATA to 0, don’t consume or 1, consume. If this is called after setting the callback function, it has no effect. Default value could be 0, don’t consume.

FreeRTOS IP callbacks

Hi Eduardo, personally I would not make a new socket option, just introduce a new macro ipconfigTCP_RECV_HANDLER_CONSUMES_DATA, which is non-zero by default. I’m afraid that I don’t have enough time to transform this proposal into a pull-request. It needs a bit of study within the function lTCPAddRxdata(), and good testing. If I were you, I would either use select() or associate a semaphore with the sockets, and store each socket handle in a struct. The struct’s will tell in what stage the connection is.

FreeRTOS IP callbacks

It seems however there is a timing problem. We are running FreeRTOS+IP on a Atmel Cortex M7. The other end is a Linux system with a much faster processor. Using the callback mechanism it seems that the first message sent just after establishing connection, is lost. When a connection is established the callback function is called: ~~~ static void CallbackOnConnectDisconnect ( Sockett xSocket, BaseTypet ulConnected ) { CallbackMessaget CallbackMessage;
Callback_Message.type = Callback_Connect_Disconnect;
Callback_Message.Connect_Disconnect.xSocket = xSocket;
Callback_Message.Connect_Disconnect.ulConnected = ulConnected;

if ( xQueueSend ( xQueue_Callback, (void*) &Callback_Message, 0 ) != pdPASS )
    /* In case there is no space in the Queue,
     * we should print something to the service port but we are inside FreeRTOS IP so it's better just increment a counter.
     * The printing will take place in the main loop.
     */
    xQueue_Callback_Errors++;
} ~~~ Which creates a message to be processed by the IP receiver task that is waiting on a queue ~~~ if ( xQueueReceive ( xQueueCallback, &CallbackMessage, portMAXDELAY ) ) { switch ( CallbackMessage.type ) { case CallbackConnectDisconnect: { FTCPUDPHandlert HandlerOnReceive; if ( CallbackMessage.ConnectDisconnect.ulConnected ) { IPreceiverSocket = FreeRTOSaccept ( IPacceptSocket, &xClient, &xSize );
                    /* Install a callback for receiving TCP data. */
                    Handler_OnReceive.pxOnTCPReceive = Callback_OnReceive;
                    FreeRTOS_setsockopt ( IPreceiver_Socket, 0, FREERTOS_SO_TCP_RECV_HANDLER, (void *) &Handler_OnReceive, sizeof(Handler_OnReceive) );
~~~ So there is some time until FreeRTOSsetsockopt is called to set the callback function for FREERTOSSOTCPRECV_HANDLER. If on the Linux system a put a delay of 1 second before sending the message it works fine. It seems that a message sent before FreeRTOS_setsockopt is called, is lost. Any ideas how to solve this? thanks

FreeRTOS IP callbacks

Eduardo, I’m attaching the source code for a telnet server. It doesn’t use any blocking code, in stead, it blocks on a semaphore. Only xTelnet.xParentSocket is attached to the semaphore. All child sockets will inherit this setting. I just tested the module with real hardware, and it works well. I hope that this gives ideas for a different approach.

FreeRTOS IP callbacks

About your last post: it is possible that the first packet comes immediately after the SYN/ACK, and that the first data packet gets lost because the recv handler isn’t set yet. Solution: set the socket option FREERTOS_SO_TCP_RECV_HANDLER on the parent socket. It will be automatically inherited by all child sockets. That should solve the “timing problem”.

FreeRTOS IP callbacks

While 2 posts are waiting for moderation…, I try it from a different IP-address. Please apply FREERTOS_SO_TCP_RECV_HANDLER to the parent socket. It will be inherited by the child sockets and you won’t loose the first packet. Also I attached a ZIP file as an example of using semaphores.

FreeRTOS IP callbacks

It works, thanks. Another bug bites the dust 🙂