heinbali01 wrote on Tuesday, April 09, 2019:
In other words is there anyway of having a non-blocking
FreeRTOS_recv? Or a blocking FreeRTOS_recv for say 1 second?
maybe using FreeRTOS_setsockopt()?
Yes you can set the maximum time that FreeRTOS_recv()
will wait by setting the socket option FREERTOS_SO_RCVTIMEO
.
There are three different possibilities to handle multiple socket within a single task:
Method 1) Semaphores
Method 2) Socket call-backs
Method 3) Use select
What you can do is call FreeRTOS_recv()
and FreeRTOS_send()
in a non-blocking way, and let the task block in a central place, either on a semaphore, or a task-notification, or a call to select().
Method 1) Semaphores
Give the task a semaphore and anyone can wake-up your task by giving to the semaphore ( xSemaphoreGive()
or xSemaphoreGiveFromISR()
).
The IP-task can also give to the semaphore if you bind a socket to that semaphore ( on reception of data, on TX space available, on disconnect etc. )
Define in FreeRTOSIPConfig.h:
#define ipconfigSOCKET_HAS_USER_SEMAPHORE 1
and bind the semaphore to every socket owned by the task. There is a NTP-demo (Network Time Protocol) which uses a semaphore:
// Declare it
static SemaphoreHandle_t xNTPWakeupSem = NULL;
// Create it
xNTPWakeupSem = xSemaphoreCreateBinary();
// Bind it
FreeRTOS_setsockopt(
xUDPSocket,
0,
FREERTOS_SO_SET_SEMAPHORE,
( void * ) &xNTPWakeupSem, sizeof( xNTPWakeupSem ) );
This is a UDP socket, but it works the same for TCP sockets. The IP-task will give to the semaphore for any relevant event:
- Data has arrived
- Data has been sent and TX space is available ( TCP-only )
- A connection is established ( either
accept()
or connect()
)
- A connection is broken ( or an error occurred )
for( ;; )
{
// Sleep for 10 seconds
xSemaphoreTake( xNTPWakeupSem, pdMS_TO_TICKS( 10000ul ) );
/* Check sockets and messages in a non-blocking way. */
}
Method 2) Socket call-backs
Define ipconfigUSE_CALLBACKS
as 1 in FreeRTOSIPConfig.h
Now you can bind call-back ( application hooks ) to each of the sockets:
FREERTOS_SO_TCP_CONN_HANDLER ( 6 ) /* Install a callback for (dis) connection events. */
FREERTOS_SO_TCP_RECV_HANDLER ( 7 ) /* Install a callback for receiving TCP data. */
FREERTOS_SO_TCP_SENT_HANDLER ( 8 ) /* Install a callback for sending TCP data. */
FREERTOS_SO_UDP_RECV_HANDLER ( 9 ) /* Install a callback for receiving UDP data. */
FREERTOS_SO_UDP_SENT_HANDLER ( 10 ) /* Install a callback for sending UDP data. */
Define a handler, e.g. on-tcp-receive
BaseType_t xOnTcpReceive( Socket_t xSocket, void * pData, size_t xLength )
{
xSemaphoreGive( myTaskSemaphore );
// or
xTaskNotifyGive( myTaskHandle );
return 0; // KEEP the packet, it will be stored in the RX buffer of the socket
// FreeRTOS_recv() must be called later-on
// or
return 1; // DISCARD the packet, it will not be stored
}
F_TCP_UDP_Handler_t handler;
handler.pxOnTcpReceive = xOnTcpReceive;
FreeRTOS_setsockopt( sock, 0, FREERTOS_SO_TCP_RECV_HANDLER,
( void * ) &handler, sizeof( handler ) );
Call-backs ( Application Hooks ) are always error-prone: it looks like user code, but in fact the code is run ( called ) from the IP-task. Thus most +TCP API’s can not be called from within the call-back.
Method 3) Use select
Define ipconfigSUPPORT_SELECT_FUNCTION
as 1 in your FreeRTOSIPConfig.h
And now you can use the select() functions. Here you find documentation.
Using select() is less flexible: you can only wake-up the task if you can access the sockets.
You could use:
#define ipconfigSUPPORT_SIGNALS 1
and interrupt a select() buy calling :
FreeRTOS_SignalSocket()
Most compatible is 3) select(), while 2) semaphore is by far the easiest.
The FTP/HTTP demo servers use a single task. It blocks in a call to select(). It can handle an unlimited number of FTP- or HTTP-clients, only limited by the amount of available RAM.