2 FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 This file is part of the FreeRTOS distribution.
\r
9 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
10 the terms of the GNU General Public License (version 2) as published by the
\r
11 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
13 ***************************************************************************
\r
14 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
15 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
16 >>! obliged to provide the source code for proprietary components !<<
\r
17 >>! outside of the FreeRTOS kernel. !<<
\r
18 ***************************************************************************
\r
20 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
22 FOR A PARTICULAR PURPOSE. Full license text is available on the following
\r
23 link: http://www.freertos.org/a00114.html
\r
25 ***************************************************************************
\r
27 * FreeRTOS provides completely free yet professionally developed, *
\r
28 * robust, strictly quality controlled, supported, and cross *
\r
29 * platform software that is more than just the market leader, it *
\r
30 * is the industry's de facto standard. *
\r
32 * Help yourself get started quickly while simultaneously helping *
\r
33 * to support the FreeRTOS project by purchasing a FreeRTOS *
\r
34 * tutorial book, reference manual, or both: *
\r
35 * http://www.FreeRTOS.org/Documentation *
\r
37 ***************************************************************************
\r
39 http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
\r
40 the FAQ page "My application does not run, what could be wrong?". Have you
\r
41 defined configASSERT()?
\r
43 http://www.FreeRTOS.org/support - In return for receiving this top quality
\r
44 embedded software for free we request you assist our global community by
\r
45 participating in the support forum.
\r
47 http://www.FreeRTOS.org/training - Investing in training allows your team to
\r
48 be as productive as possible as early as possible. Now you can receive
\r
49 FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
\r
50 Ltd, and the world's leading authority on the world's leading RTOS.
\r
52 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
53 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
54 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
56 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
\r
57 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
\r
59 http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
\r
60 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
61 licenses offer ticketed support, indemnification and commercial middleware.
\r
63 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
64 engineered and independently SIL3 certified version for use in safety and
\r
65 mission critical applications that require provable dependability.
\r
71 * A set of Tx and a set of Rx tasks are created. The Tx tasks send TCP echo
\r
72 * requests to the standard echo port (port 7) on the IP address set by the
\r
73 * configECHO_SERVER_ADDR0 to configECHO_SERVER_ADDR3 constants. The Rx tasks
\r
74 * then use the same socket to receive and validate the echoed reply.
\r
76 * See the following web page for essential demo usage and configuration
\r
78 * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html
\r
81 /* Standard includes. */
\r
86 /* FreeRTOS includes. */
\r
87 #include "FreeRTOS.h"
\r
90 #include "event_groups.h"
\r
92 /* FreeRTOS+TCP includes. */
\r
93 #include "FreeRTOS_IP.h"
\r
94 #include "FreeRTOS_Sockets.h"
\r
96 /* Exclude the whole file if FreeRTOSIPConfig.h is configured to use UDP only. */
\r
97 #if( ipconfigUSE_TCP == 1 )
\r
99 /* Short delay used between demo cycles to ensure the network does not get too
\r
101 #define echoLOOP_DELAY pdMS_TO_TICKS( 500UL )
\r
103 /* The echo server is assumed to be on port 7, which is the standard echo
\r
105 #define echoECHO_PORT ( 7 )
\r
107 /* Dimensions the buffer used by prvEchoClientTxTask() to send a multiple of
\r
108 MSS bytes at once. */
\r
109 #define echoLARGE_BUFFER_SIZE_MULTIPLIER ( 10 )
\r
111 /* Bit definitions used with the xSyncEventGroup event group to allow the
\r
112 prvEchoClientTxTask() and prvEchoClientRxTask() tasks to synchronise before
\r
113 commencing a new cycle with a different socket. */
\r
114 #define echoTX_TASK_BIT ( 0x01 << 1 )
\r
115 #define echoRX_TASK_BIT ( 0x01 << 2 )
\r
117 /*-----------------------------------------------------------*/
\r
120 * Uses a socket to send more than MSS bytes in one go to the standard echo
\r
121 * port number 7. The echoed data is received on the same socket but in a
\r
122 * different task (see prvEchoClientRxTask() below).
\r
124 static void prvEchoClientTxTask( void *pvParameters );
\r
127 * Uses the socket created in prvEchoClientTxTask() to receive the data sent
\r
128 * to the echo server by the prvEchoClientTxTask().
\r
130 static void prvEchoClientRxTask( void *pvParameters );
\r
132 /* Rx and Tx time outs are used to ensure the sockets do not wait too long for
\r
134 static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 500 );
\r
135 static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 2000 );
\r
137 /* Counters for each task created - for inspection only. */
\r
138 static uint32_t ulTxTaskCycles = 0, ulRxTaskCycles = 0;
\r
140 /* The queue used by prvEchoClientTxTask() to send the next socket to use to
\r
141 prvEchoClientRxTask(). */
\r
142 static QueueHandle_t xSocketPassingQueue = NULL;
\r
144 /* The event group used by the prvEchoClientTxTask() and prvEchoClientRxTask()
\r
145 to synchronise prior to commencing a cycle using a new socket. */
\r
146 static EventGroupHandle_t xSyncEventGroup = NULL;
\r
148 /* Flag used to inform the Rx task that the socket is about to be shut down. */
\r
149 int32_t lShuttingDown = pdFALSE;
\r
151 /*-----------------------------------------------------------*/
\r
153 void vStartTCPEchoClientTasks_SeparateTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority )
\r
155 /* Create the queue used to pass the socket to use from the Tx task to the
\r
157 xSocketPassingQueue = xQueueCreate( 1, sizeof( Socket_t ) );
\r
158 configASSERT( xSocketPassingQueue );
\r
160 /* Create the event group used by the Tx and Rx tasks to synchronise prior
\r
161 to commencing a cycle using a new socket. */
\r
162 xSyncEventGroup = xEventGroupCreate();
\r
163 configASSERT( xSyncEventGroup );
\r
165 /* Create the task that sends to an echo server, but lets a different task
\r
166 receive the reply on the same socket. */
\r
167 xTaskCreate( prvEchoClientTxTask, /* The function that implements the task. */
\r
168 "Echo0", /* Just a text name for the task to aid debugging. */
\r
169 usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */
\r
170 NULL, /* The task parameter, not used in this case. */
\r
171 uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */
\r
172 NULL ); /* The task handle is not used. */
\r
174 /* Create the task that receives the reply to echos initiated by the
\r
175 prvEchoClientTxTask() task. */
\r
176 xTaskCreate( prvEchoClientRxTask, "EchoRx", configMINIMAL_STACK_SIZE, NULL, uxTaskPriority + 1, NULL );
\r
178 /*-----------------------------------------------------------*/
\r
180 static void prvEchoClientTxTask( void *pvParameters )
\r
183 struct freertos_sockaddr xEchoServerAddress;
\r
184 static char cTransmittedString[ ipconfigTCP_MSS * echoLARGE_BUFFER_SIZE_MULTIPLIER ];
\r
185 uint32_t ulTxCount = 0UL, ulJunk;
\r
186 BaseType_t lTransmitted, lReturned = 0, lCharacter;
\r
187 const BaseType_t lStringLength = ipconfigTCP_MSS * echoLARGE_BUFFER_SIZE_MULTIPLIER;
\r
189 const uint32_t ulNumTxPerSocket = 5UL;
\r
190 WinProperties_t xWinProps;
\r
191 const TickType_t xTxEmptyDelay = 20 / portTICK_PERIOD_MS;
\r
192 TickType_t xTimeEnteringLoop;
\r
194 /* Avoid warning about unused parameter. */
\r
195 ( void ) pvParameters;
\r
197 /* Fill in the required buffer and window sizes. */
\r
198 xWinProps.lTxBufSize = 6 * ipconfigTCP_MSS;
\r
199 xWinProps.lTxWinSize = 3;
\r
200 xWinProps.lRxBufSize = 6 * ipconfigTCP_MSS;
\r
201 xWinProps.lRxWinSize = 3;
\r
203 /* Echo requests are sent to the echo server. The address of the echo
\r
204 server is configured by the constants configECHO_SERVER_ADDR0 to
\r
205 configECHO_SERVER_ADDR3 in FreeRTOSConfig.h. */
\r
206 xEchoServerAddress.sin_port = FreeRTOS_htons( echoECHO_PORT );
\r
207 xEchoServerAddress.sin_addr = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0,
\r
208 configECHO_SERVER_ADDR1,
\r
209 configECHO_SERVER_ADDR2,
\r
210 configECHO_SERVER_ADDR3 );
\r
212 /* Create the string that is sent to the echo server. */
\r
213 for( ulTxCount = 0; ulTxCount < echoLARGE_BUFFER_SIZE_MULTIPLIER; ulTxCount++ )
\r
215 /* Generate character. */
\r
216 lCharacter = ( int32_t ) '0' + ulTxCount;
\r
218 /* Write a whole ipconfigTCP_MSS block of the character into the Tx
\r
220 memset( ( void * ) &( cTransmittedString[ ipconfigTCP_MSS * ulTxCount ] ), lCharacter, ipconfigTCP_MSS );
\r
227 /* Create a socket. */
\r
228 xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
\r
229 configASSERT( xSocket != FREERTOS_INVALID_SOCKET );
\r
231 /* Set a time out so a missing reply does not cause the task to block
\r
233 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
\r
234 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) );
\r
236 /* Set the buffer and window sizes. */
\r
237 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) );
\r
239 /* Attempt to connect to the echo server. */
\r
240 if( FreeRTOS_connect( xSocket, &xEchoServerAddress, sizeof( xEchoServerAddress ) ) == 0 )
\r
242 /* Send the connected socket to the Rx task so it can receive the
\r
243 echoed replies from a different task. */
\r
244 lReturned = xQueueSend( xSocketPassingQueue, &xSocket, portMAX_DELAY );
\r
245 configASSERT( lReturned == pdPASS );
\r
247 while( ulTxCount < ulNumTxPerSocket )
\r
251 /* Keep sending until the entire buffer has been sent. */
\r
252 while( lTransmitted < lStringLength )
\r
254 /* How many bytes are left to send? Attempt to send them
\r
255 all at once (so the length is potentially greater than the
\r
257 xLenToSend = lStringLength - lTransmitted;
\r
259 lReturned = FreeRTOS_send( xSocket, /* The socket being sent to. */
\r
260 ( void * ) &( cTransmittedString[ lTransmitted ] ), /* The data being sent. */
\r
261 xLenToSend, /* The length of the data being sent. */
\r
262 0 ); /* ulFlags. */
\r
264 if( lReturned >= 0 )
\r
266 /* Data was sent successfully. */
\r
267 lTransmitted += lReturned;
\r
271 /* Error - close the socket. */
\r
276 if( lReturned < 0 )
\r
278 /* The data was not sent for some reason - close the
\r
284 /* Keep a count of how many echo requests have been transmitted
\r
285 so it can be compared to the number of echo replies received.
\r
286 It would be expected to loose at least one to an ARP message
\r
287 the first time the connection is created. */
\r
290 /* Increment the number of times the message has been sent
\r
291 to this socket - after so many cycles the socket will be
\r
292 closed and a new one opened. */
\r
297 /* Wait until all Tx data has left the buffer. */
\r
298 xTimeEnteringLoop = xTaskGetTickCount();
\r
299 while( ( FreeRTOS_tx_size( xSocket ) > 0 ) && ( FreeRTOS_issocketconnected( xSocket ) == pdTRUE ) )
\r
301 vTaskDelay( xTxEmptyDelay );
\r
303 if( ( xTaskGetTickCount() - xTimeEnteringLoop ) > xSendTimeOut )
\r
305 /* Give up waiting. */
\r
310 /* Inform the other task that is using the same socket that this
\r
311 task is waiting to shut the socket. */
\r
312 lShuttingDown = pdTRUE;
\r
314 /* Wait for the Rx task to recognise the socket is closing and stop
\r
315 using it. NOTE: This should really have a time out but for simplicity
\r
316 of demonstration the time out is omitted. */
\r
317 xEventGroupSync( xSyncEventGroup, /* The event group used for the rendezvous. */
\r
318 echoTX_TASK_BIT, /* The bit representing the Tx task reaching the rendezvous. */
\r
319 ( echoTX_TASK_BIT | echoRX_TASK_BIT ), /* Also wait for the Rx task. */
\r
320 portMAX_DELAY ); /* See comment above about lack of time out. */
\r
321 lShuttingDown = pdFALSE;
\r
323 xTimeEnteringLoop = xTaskGetTickCount();
\r
325 /* Initiate graceful shut down. */
\r
326 FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR );
\r
328 /* Wait for the receive calls to return an error - indicating that
\r
329 the socket is no longer connected. */
\r
330 xTimeEnteringLoop = xTaskGetTickCount();
\r
333 lReturned = FreeRTOS_recv( xSocket, /* The socket being received from. */
\r
334 &ulJunk, /* The buffer into which the received data will be written. */
\r
335 sizeof( ulJunk ), /* The size of the buffer provided to receive the data. */
\r
338 if( lReturned < 0 )
\r
343 } while( ( xTaskGetTickCount() - xTimeEnteringLoop ) < ( xReceiveTimeOut * 2 ) );
\r
346 /* The Rx task is no longer using the socket so the socket can be
\r
348 FreeRTOS_closesocket( xSocket );
\r
350 /* Pause for a short while to ensure the network is not too
\r
352 vTaskDelay( echoLOOP_DELAY );
\r
355 /*-----------------------------------------------------------*/
\r
357 static void prvEchoClientRxTask( void *pvParameters )
\r
360 static char cReceivedString[ ipconfigTCP_MSS ], cExpectedString[ ipconfigTCP_MSS ];
\r
361 BaseType_t lReceived, lReturned = 0, lExpectedCharacter;
\r
363 ( void ) pvParameters;
\r
367 lExpectedCharacter = 0;
\r
369 /* Wait to receive the socket that will be used from the Tx task. */
\r
370 xQueueReceive( xSocketPassingQueue, &xSocket, portMAX_DELAY );
\r
374 /* Clear down the Rx buffer. */
\r
375 memset( ( void * ) cReceivedString, 0x00, ipconfigTCP_MSS );
\r
377 /* Fill the buffer that contains the expected string with the next
\r
379 memset( ( void * ) cExpectedString, ( int32_t ) '0' + lExpectedCharacter, ipconfigTCP_MSS );
\r
380 lExpectedCharacter++;
\r
382 if( lExpectedCharacter >= echoLARGE_BUFFER_SIZE_MULTIPLIER )
\r
384 lExpectedCharacter = 0;
\r
387 /* Nothing received yet. */
\r
390 /* Receive MSS bytes at a time as the data changes each MSS size. */
\r
391 while( lReceived < ipconfigTCP_MSS )
\r
393 lReturned = FreeRTOS_recv( xSocket, &( cReceivedString[ lReceived ] ), ipconfigTCP_MSS - lReceived, 0 );
\r
395 if( ( lReturned == 0 ) && ( lShuttingDown == pdTRUE ) )
\r
397 /* No bytes received but the Tx task is waiting to shut the
\r
398 socket. Set lReturned to a negative number so the logic
\r
399 below breaks out of the loop. */
\r
403 else if( lReturned >= 0 )
\r
405 /* Data was received. */
\r
406 lReceived += lReturned;
\r
410 /* Error. The socket has probably been shut down already by
\r
411 the Tx task, but try again just in case not. */
\r
416 if( lReturned < 0 )
\r
418 /* Socket is probably being shut down. */
\r
423 /* Check the string actually received matches the string
\r
425 configASSERT( memcmp( ( void * ) cReceivedString, ( void * ) cExpectedString, ipconfigTCP_MSS ) == 0 );
\r
430 /* Rendezvous with the Tx task ready to start a new cycle with a
\r
431 different socket. NOTE: This should really have a time out but for
\r
432 simplicity of demonstration the time out is omitted. */
\r
433 xEventGroupSync( xSyncEventGroup, /* The event group used for the rendezvous. */
\r
434 echoRX_TASK_BIT, /* The bit representing the Rx task reaching the rendezvous. */
\r
435 ( echoTX_TASK_BIT | echoRX_TASK_BIT ), /* Also wait for the Tx task. */
\r
436 portMAX_DELAY ); /* See comment above about lack of time out. */
\r
439 /*-----------------------------------------------------------*/
\r
441 BaseType_t xAreSeparateTaskTCPEchoClientsStillRunning( void )
\r
443 static uint32_t ulLastTxTaskCycles = 0, ulLastRxTaskCycles = 0;
\r
444 BaseType_t xReturn = pdPASS;
\r
446 if( ulTxTaskCycles == ulLastTxTaskCycles )
\r
452 ulLastTxTaskCycles = ulTxTaskCycles;
\r
455 if( ulRxTaskCycles == ulLastRxTaskCycles )
\r
461 ulLastRxTaskCycles = ulRxTaskCycles;
\r
467 #endif /* ipconfigUSE_TCP */
\r