]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TCPEchoClient_SeparateTasks.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Demo / FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator / DemoTasks / TCPEchoClient_SeparateTasks.c
1 /*\r
2     FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.\r
3     All rights reserved\r
4 \r
5     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     This file is part of the FreeRTOS distribution.\r
8 \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
12 \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
19 \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
24 \r
25     ***************************************************************************\r
26      *                                                                       *\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
31      *                                                                       *\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
36      *                                                                       *\r
37     ***************************************************************************\r
38 \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
42 \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
46 \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
51 \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
55 \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
58 \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
62 \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
66 \r
67     1 tab == 4 spaces!\r
68 */\r
69 \r
70 /*\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
75  *\r
76  * See the following web page for essential demo usage and configuration\r
77  * details:\r
78  * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html\r
79  */\r
80 \r
81 /* Standard includes. */\r
82 #include <stdint.h>\r
83 #include <stdio.h>\r
84 #include <stdlib.h>\r
85 \r
86 /* FreeRTOS includes. */\r
87 #include "FreeRTOS.h"\r
88 #include "task.h"\r
89 #include "queue.h"\r
90 #include "event_groups.h"\r
91 \r
92 /* FreeRTOS+TCP includes. */\r
93 #include "FreeRTOS_IP.h"\r
94 #include "FreeRTOS_Sockets.h"\r
95 \r
96 /* Exclude the whole file if FreeRTOSIPConfig.h is configured to use UDP only. */\r
97 #if( ipconfigUSE_TCP == 1 )\r
98 \r
99 /* Short delay used between demo cycles to ensure the network does not get too\r
100 congested. */\r
101 #define echoLOOP_DELAY  pdMS_TO_TICKS( 500UL )\r
102 \r
103 /* The echo server is assumed to be on port 7, which is the standard echo\r
104 protocol port. */\r
105 #define echoECHO_PORT   ( 7 )\r
106 \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
110 \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
116 \r
117 /*-----------------------------------------------------------*/\r
118 \r
119 /*\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
123  */\r
124 static void prvEchoClientTxTask( void *pvParameters );\r
125 \r
126 /*\r
127  * Uses the socket created in prvEchoClientTxTask() to receive the data sent\r
128  * to the echo server by the prvEchoClientTxTask().\r
129  */\r
130 static void prvEchoClientRxTask( void *pvParameters );\r
131 \r
132 /* Rx and Tx time outs are used to ensure the sockets do not wait too long for\r
133 missing data. */\r
134 static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 500 );\r
135 static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 2000 );\r
136 \r
137 /* Counters for each task created - for inspection only. */\r
138 static uint32_t ulTxTaskCycles = 0,     ulRxTaskCycles = 0;\r
139 \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
143 \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
147 \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
150 \r
151 /*-----------------------------------------------------------*/\r
152 \r
153 void vStartTCPEchoClientTasks_SeparateTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority )\r
154 {\r
155         /* Create the queue used to pass the socket to use from the Tx task to the\r
156         Rx task. */\r
157         xSocketPassingQueue = xQueueCreate( 1, sizeof( Socket_t ) );\r
158         configASSERT( xSocketPassingQueue );\r
159 \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
164 \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
173 \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
177 }\r
178 /*-----------------------------------------------------------*/\r
179 \r
180 static void prvEchoClientTxTask( void *pvParameters )\r
181 {\r
182 Socket_t xSocket;\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
188 size_t xLenToSend;\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
193 \r
194         /* Avoid warning about unused parameter. */\r
195         ( void ) pvParameters;\r
196 \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
202 \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
211 \r
212         /* Create the string that is sent to the echo server. */\r
213         for( ulTxCount = 0; ulTxCount < echoLARGE_BUFFER_SIZE_MULTIPLIER; ulTxCount++ )\r
214         {\r
215                 /* Generate character. */\r
216                 lCharacter = ( int32_t ) '0' + ulTxCount;\r
217 \r
218                 /* Write a whole ipconfigTCP_MSS block of the character into the Tx\r
219                 buffer. */\r
220                 memset( ( void * ) &( cTransmittedString[ ipconfigTCP_MSS * ulTxCount ] ), lCharacter, ipconfigTCP_MSS );\r
221         }\r
222 \r
223         for( ;; )\r
224         {\r
225                 ulTxCount = 0;\r
226 \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
230 \r
231                 /* Set a time out so a missing reply does not cause the task to block\r
232                 indefinitely. */\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
235 \r
236                 /* Set the buffer and window sizes. */\r
237                 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps,     sizeof( xWinProps ) );\r
238 \r
239                 /* Attempt to connect to the echo server. */\r
240                 if( FreeRTOS_connect( xSocket, &xEchoServerAddress, sizeof( xEchoServerAddress ) ) == 0 )\r
241                 {\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
246 \r
247                         while( ulTxCount < ulNumTxPerSocket )\r
248                         {\r
249                                 lTransmitted = 0;\r
250 \r
251                                 /* Keep sending until the entire buffer has been sent. */\r
252                                 while( lTransmitted < lStringLength )\r
253                                 {\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
256                                         MSS). */\r
257                                         xLenToSend = lStringLength - lTransmitted;\r
258 \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
263 \r
264                                         if( lReturned >= 0 )\r
265                                         {\r
266                                                 /* Data was sent successfully. */\r
267                                                 lTransmitted += lReturned;\r
268                                         }\r
269                                         else\r
270                                         {\r
271                                                 /* Error - close the socket. */\r
272                                                 break;\r
273                                         }\r
274                                 }\r
275 \r
276                                 if( lReturned < 0 )\r
277                                 {\r
278                                         /* The data was not sent for some reason - close the\r
279                                         socket. */\r
280                                         break;\r
281                                 }\r
282                                 else\r
283                                 {\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
288                                         ulTxTaskCycles++;\r
289 \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
293                                         ulTxCount++;\r
294                                 }\r
295                         }\r
296 \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
300                         {\r
301                                 vTaskDelay( xTxEmptyDelay );\r
302 \r
303                                 if( ( xTaskGetTickCount() - xTimeEnteringLoop ) > xSendTimeOut )\r
304                                 {\r
305                                         /* Give up waiting. */\r
306                                         break;\r
307                                 }\r
308                         }\r
309 \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
313 \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
322 \r
323                         xTimeEnteringLoop = xTaskGetTickCount();\r
324 \r
325                         /* Initiate graceful shut down. */\r
326                         FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR );\r
327 \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
331                         do\r
332                         {\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
336                                         0 );\r
337 \r
338                                 if( lReturned < 0 )\r
339                                 {\r
340                                         break;\r
341                                 }\r
342 \r
343                         } while( ( xTaskGetTickCount() - xTimeEnteringLoop ) < ( xReceiveTimeOut * 2 ) );\r
344                 }\r
345 \r
346                 /* The Rx task is no longer using the socket so the socket can be\r
347                 closed. */\r
348                 FreeRTOS_closesocket( xSocket );\r
349 \r
350                 /* Pause for a short while to ensure the network is not too\r
351                 congested. */\r
352                 vTaskDelay( echoLOOP_DELAY );\r
353         }\r
354 }\r
355 /*-----------------------------------------------------------*/\r
356 \r
357 static void prvEchoClientRxTask( void *pvParameters )\r
358 {\r
359 Socket_t xSocket;\r
360 static char cReceivedString[ ipconfigTCP_MSS ], cExpectedString[ ipconfigTCP_MSS ];\r
361 BaseType_t lReceived, lReturned = 0, lExpectedCharacter;\r
362 \r
363         ( void ) pvParameters;\r
364 \r
365         for( ;; )\r
366         {\r
367                 lExpectedCharacter = 0;\r
368 \r
369                 /* Wait to receive the socket that will be used from the Tx task. */\r
370                 xQueueReceive( xSocketPassingQueue, &xSocket, portMAX_DELAY );\r
371 \r
372                 for( ;; )\r
373                 {\r
374                         /* Clear down the Rx buffer. */\r
375                         memset( ( void * ) cReceivedString, 0x00, ipconfigTCP_MSS );\r
376 \r
377                         /* Fill the buffer that contains the expected string with the next\r
378                         expected value. */\r
379                         memset( ( void * ) cExpectedString, ( int32_t ) '0' + lExpectedCharacter, ipconfigTCP_MSS );\r
380                         lExpectedCharacter++;\r
381 \r
382                         if( lExpectedCharacter >= echoLARGE_BUFFER_SIZE_MULTIPLIER )\r
383                         {\r
384                                 lExpectedCharacter = 0;\r
385                         }\r
386 \r
387                         /* Nothing received yet. */\r
388                         lReceived = 0;\r
389 \r
390                         /* Receive MSS bytes at a time as the data changes each MSS size. */\r
391                         while( lReceived < ipconfigTCP_MSS )\r
392                         {\r
393                                 lReturned = FreeRTOS_recv( xSocket, &( cReceivedString[ lReceived ] ), ipconfigTCP_MSS - lReceived, 0 );\r
394 \r
395                                 if( ( lReturned == 0 ) && ( lShuttingDown == pdTRUE ) )\r
396                                 {\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
400                                         lReturned = -1;\r
401                                         break;\r
402                                 }\r
403                                 else if( lReturned >= 0 )\r
404                                 {\r
405                                         /* Data was received. */\r
406                                         lReceived += lReturned;\r
407                                 }\r
408                                 else\r
409                                 {\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
412                                         break;\r
413                                 }\r
414                         }\r
415 \r
416                         if( lReturned < 0 )\r
417                         {\r
418                                 /* Socket is probably being shut down. */\r
419                                 break;\r
420                         }\r
421                         else\r
422                         {\r
423                                 /* Check the string actually received matches the string\r
424                                 expected. */\r
425                                 configASSERT( memcmp( ( void * ) cReceivedString, ( void * ) cExpectedString, ipconfigTCP_MSS ) == 0 );\r
426                                 ulRxTaskCycles++;\r
427                         }\r
428                 }\r
429 \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
437         }\r
438 }\r
439 /*-----------------------------------------------------------*/\r
440 \r
441 BaseType_t xAreSeparateTaskTCPEchoClientsStillRunning( void )\r
442 {\r
443 static uint32_t ulLastTxTaskCycles = 0, ulLastRxTaskCycles = 0;\r
444 BaseType_t xReturn = pdPASS;\r
445 \r
446         if( ulTxTaskCycles == ulLastTxTaskCycles )\r
447         {\r
448                 xReturn = pdFAIL;\r
449         }\r
450         else\r
451         {\r
452                 ulLastTxTaskCycles = ulTxTaskCycles;\r
453         }\r
454 \r
455         if( ulRxTaskCycles == ulLastRxTaskCycles )\r
456         {\r
457                 xReturn = pdFAIL;\r
458         }\r
459         else\r
460         {\r
461                 ulLastRxTaskCycles = ulRxTaskCycles;\r
462         }\r
463 \r
464         return xReturn;\r
465 }\r
466 \r
467 #endif /* ipconfigUSE_TCP */\r
468 \r