FREE RTOS + TCP on renesas RA6M3 development board

Hi
I tried implementing FREE RTOS + TCP on renesas RA6M3 development board.
The process which i am following is

  1. DHCP assigns the IP address to my board.
  2. Therafter I opened a socket and binded it with a port number and installed a callback function using setsockopt() function forn connection handling.
  3. Then I set the socket in listen mode and wait for incoming connections.

I called the TCP_Server_Task() after the DHCP assigns the IP address to the development board.

The issue which i am facing is when i initiate a connection request from my pc to the development board the breakpoint does not hits at the callback function where it accepts the incoming connection.

I have attached the code for the same.

typedef enum
{
  Callback_Connect_Disconnect = 0,       /* Connect or disconnect */
  Callback_Receive                       /* Data Receive State */
} connectionState_t;

typedef struct
{
  Socket_t xSocket;
  uint8_t is_Connected;
}Tcp_Socket_t;

typedef struct
{
  Socket_t xSocket;
  uint8_t *pData;
  uint32_t xLength;

}Receive_t;

typedef struct
{
  uint8_t type;
  Tcp_Socket_t Connect_Disconnect;
  Receive_t Receive;
}Callback_Message_t;


static void Callback_OnConnectDisconnect ( Socket_t xSocket, BaseType_t ulConnected )
{
    Callback_Message_t Callback_Message;
    Callback_Message.type = Callback_Connect_Disconnect;
    Callback_Message.Connect_Disconnect.xSocket = xSocket;
    Callback_Message.Connect_Disconnect.is_Connected = 1u;

    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 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;
   static uint8_t Data [1000];
   int32_t receivedData;
   receivedData = FreeRTOS_recv ( Callback_Message.Receive.xSocket, Data/*pvBuffer*/, sizeof(Data)/*xBufferLength*/, 0/*xFlags*/ );
   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 TCP_Server_Task ( void *pvParameters )
{

    //Socket_t IPaccept_Socket, IPreceiver_Socket;
    //struct freertos_sockaddr xClient, xBindAddress;
    const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 20000 );
    //const TickType_t xZeroTimeOut = 0;
    const BaseType_t xBacklog = 20;
    socklen_t xSize = sizeof (struct freertos_sockaddr);
    F_TCP_UDP_Handler_t Handler_OnConnectDisconnect;

    /* 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 )
    {
       APP_PRINT ( "ERROR - task_IPaccept[] - FreeRTOS_socket failed" );
    }

    /* Set the listening port to 5050. */
    xBindAddress.sin_port = ( uint16_t ) 5050;
    xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );
    xBindAddress.sin_addr = FreeRTOS_GetIPAddress();
    /* Bind the socket to the port that the client RTOS task will send to. */

    if( FreeRTOS_bind( IPaccept_Socket, &xBindAddress, sizeof( xBindAddress ) ) == -1 )
    {
       FreeRTOS_closesocket( IPaccept_Socket );
       IPaccept_Socket = FREERTOS_INVALID_SOCKET;
    }
    /* Set the socket into a listening state so it can accept connections.
       The maximum number of simultaneous connections is limited to 20. */
    Handler_OnConnectDisconnect.pxOnTCPConnected = Callback_OnConnectDisconnect;
    FreeRTOS_setsockopt (IPaccept_Socket, 0, FREERTOS_SO_TCP_CONN_HANDLER, (void *) &Handler_OnConnectDisconnect, sizeof(Handler_OnConnectDisconnect) );
    FreeRTOS_listen( IPaccept_Socket, xBacklog );
    //Callback_OnConnectDisconnect ( IPaccept_Socket, 0 );
    
    //IPconnections_Initialise();

    for (;;)
    {
      //Callback_Message_t Callback_Message_Queue;

      if ( xQueue_Callback_Errors != xQueue_Callback_Errors_prev )
      {
        APP_PRINT ( "WARNING - task_IPreceiver[] - xQueue_Callback_Errors %d", xQueue_Callback_Errors );
        xQueue_Callback_Errors_prev = xQueue_Callback_Errors;
      }
      if ( xQueueReceive ( xQueue_Callback, &Callback_Message_Queue, portMAX_DELAY ) )
      {
        switch ( Callback_Message_Queue.type )
        {
          case Callback_Connect_Disconnect:
          {
            F_TCP_UDP_Handler_t Handler_OnReceive;
            if(Callback_Message_Queue.Connect_Disconnect.is_Connected)
            {
              IPreceiver_Socket = FreeRTOS_accept ( IPaccept_Socket, &xClient, &xSize );

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

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

              APP_PRINT ( "Connection closed %d", Callback_Message_Queue.Connect_Disconnect.xSocket );
             }
           }break;

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

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

            APP_PRINT ( "Callback_Receive Callback_Message.Receive.xSocket %d Callback_Message.Receive.xLength %d receivedData %d",
                    Callback_Message_Queue.Receive.xSocket, Callback_Message_Queue.Receive.xLength, receivedData );
          }break;
          default:
          {
              APP_PRINT( "Queue Empty" );

          }
              break;
        }

      }

   }
}

Regards
Sudhanshu Shekhar

I’m not sure that the features of the TCP/IP stack you are using are actually documented - did you copy some example code from us? Or maybe here FreeRTOS IP callbacks ?

Yes I reffered from the https://forums.freertos.org/t/freertos-ip-callbacks/7786/2
query.
There are no documents as such provided but a guide on how to implement TCP/IP server or client and perform communication is present on the FREE Rtos site.
The steps mentioned there are same as of those implemented here.

The +TCP call-back functions have a very brief description on this page, where it says:

FREERTOS_SO_TCP_CONNECT_HANDLER Advanced users only.
Only valid for TCP sockets.
Stores the address of a function to call on connect and disconnect events on the TCP socket.

@sudhanshu : you make a mistake here:

Handler_OnReceive.pxOnTCPReceive = Callback_OnReceive;
FreeRTOS_setsockopt ( IPreceiver_Socket,
                      0,
                      FREERTOS_SO_TCP_CONN_HANDLER,
                      (void *) &Handler_OnReceive,
                      sizeof(Handler_OnReceive) );

You want to set the reception handler but you set the TCP on-connect handler.
You want to use this option: FREERTOS_SO_TCP_RECV_HANDLER.

Here is a simple telnet server in which I tested both TCP socket options: telnet.zip (3.1 KB)

here is another mistake:

static void Callback_OnConnectDisconnect ( Socket_t xSocket, BaseType_t ulConnected )
{
	Callback_Message_t Callback_Message;
	Callback_Message.type = Callback_Connect_Disconnect;
	Callback_Message.Connect_Disconnect.xSocket = xSocket;
	Callback_Message.Connect_Disconnect.is_Connected = 1u;

The last line should have been:
Callback_Message.Connect_Disconnect.is_Connected = ulConnected;

Note that the on-connect handler must be set on the parent socket IPaccept_Socket, and not on the connected child socket IPreceiver_Socket.
If you set the handler for the child socket, you’re too late, the connect-event has already taken place :slight_smile:

I will send some information about socket options in my next post.

Handler_OnConnectDisconnect.pxOnTCPConnected = Callback_OnConnectDisconnect;
FreeRTOS_setsockopt (IPaccept_Socket, 0, FREERTOS_SO_TCP_CONN_HANDLER, (void *) &Handler_OnConnectDisconnect, sizeof(Handler_OnConnectDisconnect) );
FreeRTOS_listen( IPaccept_Socket, xBacklog );

When I initialize the callback function for FREERTOS_SO_TCP_CONN_HANDLER argument, i.e. if i initiate a connection request from my PC the above callback function should be called.

On connect handler is set to on the parent socket only and data receive handler is set to the child socket.

correct me if i am wrong.

When I initialize the callback function for FREERTOS_SO_TCP_CONN_HANDLER
argument, i.e. if i initiate a connection request from my PC the above
callback function should be called.

That is true, it will be called with the new socket as an argument. Note that the function will be called twice for every connection: once when getting connected, once when getting disconnected.

On connect handler is set to on the parent socket only and data
receive handler is set to the child socket.

If you set the data reception handler for the parent socket only, it will also work properly. All properties will be inherited by the child socket.

About socket options:

There are two ways of getting a TCP connection:

1 ) Active, by calling connect(), also called a client-connection
2 ) Passive, by setting up a server socket and calling accept()

ad 1) In the first case, you only need 1 socket. The socket options can be set before calling connect().
Options that determine the buffer sizes and the TCP window size, must be set before getting connected, otherwise it is too late, and the default values will be used.

ad 2) This method needs 2 sockets: a listening socket, and a child socket. The listening socket is bound to a well-known port number, and its only function is to receive new connections. The listening socket itself never gets connected. The function accept() returns a handle to a new child socket. The child socket is bound to the same well-known port number.
The options for the child socket can be set through the server socket: all time-outs, call-back functions, buffer- and window-sizes. All these options will be inherited by the child socket.

There is something about FREERTOS_SO_TCP_RECV_HANDLER: for every bit of data, the reception handler will be called with a pointer to the data, and the length. This data pointer is only valid within the handler. Once it returns, the same buffer may be overwritten. So if you want to keep the data, you must make a copy of it.
When you use a reception handler, you can not receive data with FreeRTOS_recv(). You can still call it though. It informs you if a socket is still OK and connected:

xResult = FreeRTOS_recv( xSocket, pucBuffer, sizeof( pucBuffer ), 0 );
if( ( xResult < 0 ) && ( xResult != -pdFREERTOS_ERRNO_EAGAIN ) )
{
    /* Socket is disconnected and may have an error. */
}

For platforms where RAM is scarce, and when a server will never get more that 1 client, the server socket can be reused to become a connected socket.

BaseType_t xTrueValue = pdTRUE;
FreeRTOS_setsockopt( xSocket,
                     0,
                     FREERTOS_SO_REUSE_LISTEN_SOCKET,
                     ( void * ) &( xTrueValue ),
                     sizeof( xTrueValue ) );

Remember that after the connection, the socket must be deleted ( FreeRTOS_closesocket() ). After that a new server socket can be created and bound to the server port.

Thank you sir for clarifying .
I tried implementing the Telnet server.
When i initiate the connection for the ip address assigned by the dhcp and the port number the connection is not getting established and the terminal says TCP connection timeout.

i have attached my main.telnet_debug.c (29.8 KB)

Are you sure that:

xTelnetCreate( &myTelnet, TELNET_PORT_NUMBER );

will be called after vApplicationIPNetworkEventHook() was called with eNetworkUp?

Can you check if xTelnetCreate() was successful?

Do you also have this define?

#define TELNET_PORT_NUMBER       23

There is great information here - I wonder where we can store the telnet zip file so it doesn’t get lost?

@sudhanshu is it possible for you to put this file and a brief readme in its own GitHub repo and share the link here? Or just share the file in it’s own GitHub repo and I’ll send you a pull request with the readme and anything else?

That would be a huge help.

Yes sir xTelnetCreate() was successful and it keeps on polling at
BaseType_t xResult = xTelnetRecv( &( myTelnet ), &( peer_address ), pcBuffer, sizeof pcBuffer );
if( xResult > 0 )
{
xResult = APP_PRINT( pcBuffer, sizeof pcBuffer, “Thank you\n” );
xTelnetSend( &( myTelnet ), &( peer_address ), pcBuffer, xResult );
}
i.e. if i initiate a connection from my P.C the above condition should satisfy.

Yes the port number is defined in the header file.

@rashed I have uploaded the files in the GitHub repository. The link for the repository is https://github.com/sudhanshushekhar-ctrl/TelNet-TCP-IP-Free-RTOS-.git

@sudhanshu, could you define ipconfigUSE_NETWORK_EVENT_HOOK in your FreeRTOSIPConfig.h and define this function in your application: vApplicationIPNetworkEventHook().

Where did you get a NetworkInterface for RA6M3 development board?
Can I find that somewhere?

Are you sure that the DHCP negotiation works well?

Can you ping your board?

Can you ping your laptop from the board ( using FreeRTOS_SendPingRequest() ) ?

here is an example of how to use vApplicationIPNetworkEventHook() :

static BaseType_t xDoInitialiseSockets;

void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
{
static BaseType_t xNetworkIsUp = pdFALSE;

    /* If the network has just come up...*/
    if( eNetworkEvent == eNetworkUp )
    {
        xNetworkIsUp = pdTRUE;
        xDoInitialiseSockets = pdTRUE;
    }
}

void net_thread_entry(void *pvParameters)
{
    for( ;; )
    {
        if( xDoInitialiseSockets == pdTRUE )
        {
            xDoInitialiseSockets = pdFALSE;
            xTelnetCreate( &myTelnet, TELNET_PORT_NUMBER );
            /* Create other sockets. */
        }
    }
}

@htibosch, yes I defined vApplicationIPNetworkEventHook() in my application.

“Where did you get a NetworkInterface for RA6M3 development board?”
Can you please elaborate what i have to do for NetworkInterface?

Yes DHCP negotiation works well.

I am able to ping my board and my laptop from the board.

I had one query that how can i verify that the connection request that i am sending from my PC to the board is actually reaching there?

how can i verify that the connection request that i am
sending from my PC to the board is actually reaching there?

If you have a routine that can send logging to you PC, you could show that there is a packet.

And if you have a way to send logging, other than through the network, you can define 2 macros:

extern void xSerialWrite( const char *pcFormat, ... );

#define 	ipconfigHAS_DEBUG_PRINTF    1
#define FreeRTOS_debug_printf( X )      ( void ) xSerialWrite X

#define ipconfigHAS_PRINTF              1
#define FreeRTOS_printf(X)              ( void ) xSerialWrite X

If you have no ways of sending logging, you will have to use the debugger, put breaks at certain statements and check the variables.

Yes DHCP negotiation works well.

How have you checked that? With WireShark?

Where did you get a NetworkInterface for RA6M3 development board? Can I see the source code of it?

DHCP works fine as after the network gets UP the IP credentials that gets assigned are being printed on RTT viewer.

I took the network interface source code from the example project bundle.


Inside the example project bundle I took the ethernet example as the base code and then I integrated the TCP/IP server over it.

Also when I initially ping my board i.e. before creating the server socket on the development board it successfully pings but after creating the socket and putting it in listening mode the ping fails.

@htibosch when i am initiating a connection request from hercules to the development board( server ) ip address and port number the breakpoint hits xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer ) but it isn’t returning pdPASS.

It sounds like there is a problem with resources ( memory, network buffers ).
In FreeRTOS_IP.c, there is a function called vPrintResourceStats().
In other drivers, that function will be called after every received packet. It will print warnings when a resource has dropped significantly.
Please also define configUSE_MALLOC_FAILED_HOOK in your FeeeRTOSConfig.h file, and define the following application hook:

void vApplicationMallocFailedHook( void )
{
    taskDISABLE_INTERRUPTS();
    {
        while( ulBlockVariable == 0UL )
        {
            __asm volatile( "NOP" );
        }
    }
    taskENABLE_INTERRUPTS();
}

and please define a proper configASSERT() macro in the same way.

I downloaded the ZIP file from Renesas, but I can not find a network driver. What is it called?