Application implementation with FreeRTOS-Plus-TCP

Hello,

I’m starting new development using FreeRTOS and FreeRTOS-Plus-TCP. Basic function are working ( creation of the socket, TCP send and receive…), but I am questioning myself about the best way to efficiently use the lib

The STM32 I am using is connected to a device using a telnet link. The STM32 will be the client, sending commands to the device and waiting for answers. The main “problem” is that for some commands, the return length is not known.

Here are the (basics?) questions I have:

  • Does is make sense to call multiple time FreeRTOS_recv with an expected length of 1 until there is no more data, or should it call it less but waiting for longer buffer?

  • When checking the frame with Wireshark, the device always respond with a single frame to a single command. Is there a way in FreeRTOS-Plus-TCP lib to read the header of the frame, with the data length, and than call a FreeRTOS_recv with the length of the frame?

  • In other way, is it possible to receive the complete next TCP frame?

Any other informations on how to implement a question/response over telnet with unknown return length would be appreciate.

Thank you all
Antoine

Hi @AntoineN
The FreeRTOS_recv API is not guaranteed to return the required amount of bytes, as passed in the argument. It is expected to return any number of bytes <= maximum buffer length. You can read more about this here
In order to read the response packet with unknown length, you can use the FreeRTOS_recv twice , once with expected length of packet header size , using which you can extract the payload buffer length and then use the FreeRTOS_recv, a second time for reading the entire TCP frame.

Hi,

Thank you for your response

When using the FreeRTOS_recv function, the pvBuffer receive contain only the “Data” part of the frame. The Header of the TCP frame is not in the buffer. I guess is must be decode by the internal functions of the FreeRTOS_Plus_TCP lib.

How to “read” the header of the frame?

You need a custom message/frame format for your user protocol (received as payload) when using a TCP socket based communication. Otherwise you don’t know where a message starts or ends.

2 Likes

As pointed out by @hs2, TCP is a stream of data and you need to write parser for your message/packet format. Out of the approaches you mentioned, receiving one byte at a time will work but it is not the most efficient way of doing it. I’d recommend to read as much as data as possible and then pass it to a parser - the parser should maintain the state where it is (start/stop/in the middle) in a message.

Yes, I was not sure how bad it was, but indeed it do not seem efficient.

It is a stream, but when checking the frame with Wireshark, I can see that the device reply with one TCP frame, containing among other things the header with the length, and then the data.

The data I read with FreeRTOS_recv does not contain any length or other useful information, except the text that is displayed on the telnet screen (and for which the length is unknown)

You can’t rely on that and it’s out of your hands how the data is transferred over the wire or air.
Again TCP is just a stream of bytes.
In case you try to implement kind of a text/line based terminal you’ve to parse for line ending to know that the commandline typed in is completely received.

That information is TCP header and the recv call only returns payload. Parsing the header and delivering the payload correctly to the application is the job of the TCP stack. In other words, it is working as expected.

Ok. I was not telling that the function was not working as expected. And I understand that this is part of the TCP stack (and I do not want to get in it!! :slight_smile: )

I was just wondering if there was a way to get the whole frame but it seems not. I will parse all the data to decode the receive frame.

Thank you

I’m sorry that I noticed this thread very late.

The data I read with FreeRTOS_recv does not contain any length or other useful information

In FreeRTOS+TCP there are 3 helper functions:

/* Return the number of bytes that can be read. */
BaseType_t FreeRTOS_rx_size( ConstSocket_t xSocket );
#define FreeRTOS_recvcount( xSocket )    FreeRTOS_rx_size( xSocket )

/* Return the number of bytes that are queued to be sent. */
BaseType_t FreeRTOS_tx_size( ConstSocket_t xSocket );
#define FreeRTOS_outstanding( xSocket )  FreeRTOS_tx_size( xSocket )

/* Return the number of bytes that can be sent. */
BaseType_t FreeRTOS_tx_space( ConstSocket_t xSocket );

There is also the option FREERTOS_MSG_PEEK: it allows you to peek in the data that are available. The data remained stored in the socket’s stream buffer.

In a second call to FreeRTOS_recv() without the peek option, you can actually read the data.

The above things can help you build a parser: call FreeRTOS_recv() to “read” all available bytes with the FREERTOS_MSG_PEEK option.

size_t xSize = FreeRTOS_recvcount( xSocket );

if( xSize > sizeof( pcBuffer ) )
{
    xSize = sizeof( pcBuffer );
}
BaseType_t xCount = FreeRTOS_recv( xSocket,
                                   pcBuffer,
                                   xSize,
                                   FREERTOS_MSG_PEEK );
if( xCount )
{    
    size_t xEaten = telnet_parse( pcBuffer );
    if( xEaten > 0 )
    {
        /* When reading to NULL the data won't be copied to a buffer. */
        FreeRTOS_recv( xSocket,
                       NULL,
                       xEaten,
                       FREERTOS_MSG_PEEK );
    }
}

Note that this code can get stuck when the buffer gets full, and it contains no newline character. I leave that up to you.

1 Like