]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/SimpleUDPClientAndServer.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 / SimpleUDPClientAndServer.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  * Creates two transmitting tasks and two receiving tasks.  The transmitting\r
72  * tasks send values that are received by the receiving tasks.  One set of tasks\r
73  * uses the standard API.  The other set of tasks uses the zero copy API.\r
74  *\r
75  * See the following web page for essential demo usage and configuration\r
76  * details:\r
77  * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html\r
78  */\r
79 \r
80 /* Standard includes. */\r
81 #include <stdint.h>\r
82 #include <stdio.h>\r
83 \r
84 /* FreeRTOS includes. */\r
85 #include "FreeRTOS.h"\r
86 #include "task.h"\r
87 \r
88 /* FreeRTOS+TCP includes. */\r
89 #include "FreeRTOS_IP.h"\r
90 #include "FreeRTOS_Sockets.h"\r
91 \r
92 #define simpTINY_DELAY  ( ( TickType_t ) 2 )\r
93 \r
94 /*\r
95  * Uses a socket to send data without using the zero copy option.\r
96  * prvSimpleServerTask() will receive the data.\r
97  */\r
98 static void prvSimpleClientTask( void *pvParameters );\r
99 \r
100 /*\r
101  * Uses a socket to receive the data sent by the prvSimpleClientTask() task.\r
102  * Does not use the zero copy option.\r
103  */\r
104 static void prvSimpleServerTask( void *pvParameters );\r
105 \r
106 /*\r
107  * Uses a socket to send data using the zero copy option.\r
108  * prvSimpleZeroCopyServerTask() will receive the data.\r
109  */\r
110 static void prvSimpleZeroCopyUDPClientTask( void *pvParameters );\r
111 \r
112 /*\r
113  * Uses a socket to receive the data sent by the prvSimpleZeroCopyUDPClientTask()\r
114  * task.  Uses the zero copy option.\r
115  */\r
116 static void prvSimpleZeroCopyServerTask( void *pvParameters );\r
117 \r
118 /*-----------------------------------------------------------*/\r
119 \r
120 void vStartSimpleUDPClientServerTasks( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority )\r
121 {\r
122         /* Create the client and server tasks that do not use the zero copy\r
123         interface. */\r
124         xTaskCreate( prvSimpleClientTask, "SimpCpyClnt", usStackSize, ( void * ) ulPort, uxPriority, NULL );\r
125         xTaskCreate( prvSimpleServerTask, "SimpCpySrv", usStackSize, ( void * ) ulPort, uxPriority + 1, NULL );\r
126 \r
127         /* Create the client and server tasks that do use the zero copy interface. */\r
128         xTaskCreate( prvSimpleZeroCopyUDPClientTask, "SimpZCpyClnt", usStackSize, ( void * ) ( ulPort + 1 ), uxPriority, NULL );\r
129         xTaskCreate( prvSimpleZeroCopyServerTask, "SimpZCpySrv", usStackSize, ( void * ) ( ulPort + 1 ), uxPriority + 1, NULL );\r
130 }\r
131 /*-----------------------------------------------------------*/\r
132 \r
133 static void prvSimpleClientTask( void *pvParameters )\r
134 {\r
135 Socket_t xClientSocket;\r
136 struct freertos_sockaddr xDestinationAddress;\r
137 uint8_t cString[ 50 ];\r
138 BaseType_t lReturned;\r
139 uint32_t ulCount = 0UL, ulIPAddress;\r
140 const uint32_t ulLoopsPerSocket = 10UL;\r
141 const TickType_t x150ms = 150UL / portTICK_PERIOD_MS;\r
142 \r
143         /* Remove compiler warning about unused parameters. */\r
144         ( void ) pvParameters;\r
145 \r
146         /* It is assumed that this task is not created until the network is up,\r
147         so the IP address can be obtained immediately.  store the IP address being\r
148         used in ulIPAddress.  This is done so the socket can send to a different\r
149         port on the same IP address. */\r
150         FreeRTOS_GetAddressConfiguration( &ulIPAddress, NULL, NULL, NULL );\r
151 \r
152         /* This test sends to itself, so data sent from here is received by a server\r
153         socket on the same IP address.  Setup the freertos_sockaddr structure with\r
154         this nodes IP address, and the port number being sent to.  The strange\r
155         casting is to try and remove compiler warnings on 32 bit machines. */\r
156         xDestinationAddress.sin_addr = ulIPAddress;\r
157         xDestinationAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL;\r
158         xDestinationAddress.sin_port = FreeRTOS_htons( xDestinationAddress.sin_port );\r
159 \r
160         for( ;; )\r
161         {\r
162                 /* Create the socket. */\r
163                 xClientSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );\r
164                 configASSERT( xClientSocket != FREERTOS_INVALID_SOCKET );\r
165 \r
166                 /* The count is used to differentiate between different messages sent to\r
167                 the server, and to break out of the do while loop below. */\r
168                 ulCount = 0UL;\r
169 \r
170                 do\r
171                 {\r
172                         /* Create the string that is sent to the server. */\r
173                         sprintf( ( char * ) cString, "Server received (not zero copy): Message number %lu\r\n", ulCount );\r
174 \r
175                         /* Send the string to the socket.  ulFlags is set to 0, so the zero\r
176                         copy option is not selected.  That means the data from cString[] is\r
177                         copied into a network buffer inside FreeRTOS_sendto(), and cString[]\r
178                         can be reused as soon as FreeRTOS_sendto() has returned. */\r
179                         lReturned = FreeRTOS_sendto( xClientSocket, ( void * ) cString, strlen( ( const char * ) cString ), 0, &xDestinationAddress, sizeof( xDestinationAddress ) );\r
180 \r
181                         ulCount++;\r
182 \r
183                 } while( ( lReturned != FREERTOS_SOCKET_ERROR ) && ( ulCount < ulLoopsPerSocket ) );\r
184 \r
185                 FreeRTOS_closesocket( xClientSocket );\r
186 \r
187                 /* A short delay to prevent the messages printed by the server task\r
188                 scrolling off the screen too quickly, and to prevent reduce the network\r
189                 loading. */\r
190                 vTaskDelay( x150ms );\r
191         }\r
192 }\r
193 /*-----------------------------------------------------------*/\r
194 \r
195 static void prvSimpleServerTask( void *pvParameters )\r
196 {\r
197 int32_t lBytes;\r
198 uint8_t cReceivedString[ 60 ];\r
199 struct freertos_sockaddr xClient, xBindAddress;\r
200 uint32_t xClientLength = sizeof( xClient );\r
201 Socket_t xListeningSocket;\r
202 \r
203         /* Just to prevent compiler warnings. */\r
204         ( void ) pvParameters;\r
205 \r
206         /* Attempt to open the socket. */\r
207         xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );\r
208         configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );\r
209 \r
210         /* This test receives data sent from a different port on the same IP\r
211         address.  Configure the freertos_sockaddr structure with the address being\r
212         bound to.  The strange casting is to try and remove     compiler warnings on 32\r
213         bit machines.  Note that this task is only created after the network is up,\r
214         so the IP address is valid here. */\r
215         xBindAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL;\r
216         xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );\r
217 \r
218         /* Bind the socket to the port that the client task will send to. */\r
219         FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );\r
220 \r
221         for( ;; )\r
222         {\r
223                 /* Zero out the receive array so there is NULL at the end of the string\r
224                 when it is printed out. */\r
225                 memset( cReceivedString, 0x00, sizeof( cReceivedString ) );\r
226 \r
227                 /* Receive data on the socket.  ulFlags is zero, so the zero copy option\r
228                 is not set and the received data is copied into the buffer pointed to by\r
229                 cReceivedString.  By default the block time is\r
230                 ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME.  xClientLength is not actually\r
231                 used by FreeRTOS_recvfrom(), but is set appropriately in case future\r
232                 versions do use it. */\r
233                 lBytes = FreeRTOS_recvfrom( xListeningSocket, cReceivedString, sizeof( cReceivedString ), 0, &xClient, &xClientLength );\r
234 \r
235                 /* Error check. */\r
236                 configASSERT( lBytes == ( BaseType_t ) strlen( ( const char * ) cReceivedString ) );\r
237         }\r
238 }\r
239 /*-----------------------------------------------------------*/\r
240 \r
241 static void prvSimpleZeroCopyUDPClientTask( void *pvParameters )\r
242 {\r
243 Socket_t xClientSocket;\r
244 uint8_t *pucUDPPayloadBuffer;\r
245 struct freertos_sockaddr xDestinationAddress;\r
246 BaseType_t lReturned;\r
247 uint32_t ulCount = 0UL, ulIPAddress;\r
248 const uint32_t ulLoopsPerSocket = 10UL;\r
249 const char *pcStringToSend = "Server received (using zero copy): Message number ";\r
250 const TickType_t x150ms = 150UL / portTICK_PERIOD_MS;\r
251 /* 15 is added to ensure the number, \r\n and terminating zero fit. */\r
252 const size_t xStringLength = strlen( pcStringToSend ) + 15;\r
253 \r
254         /* Remove compiler warning about unused parameters. */\r
255         ( void ) pvParameters;\r
256 \r
257         /* It is assumed that this task is not created until the network is up,\r
258         so the IP address can be obtained immediately.  store the IP address being\r
259         used in ulIPAddress.  This is done so the socket can send to a different\r
260         port on the same IP address. */\r
261         FreeRTOS_GetAddressConfiguration( &ulIPAddress, NULL, NULL, NULL );\r
262 \r
263         /* This test sends to itself, so data sent from here is received by a server\r
264         socket on the same IP address.  Setup the freertos_sockaddr structure with\r
265         this nodes IP address, and the port number being sent to.  The strange\r
266         casting is to try and remove compiler warnings on 32 bit machines. */\r
267         xDestinationAddress.sin_addr = ulIPAddress;\r
268         xDestinationAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL;\r
269         xDestinationAddress.sin_port = FreeRTOS_htons( xDestinationAddress.sin_port );\r
270 \r
271         for( ;; )\r
272         {\r
273                 /* Create the socket. */\r
274                 xClientSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );\r
275                 configASSERT( xClientSocket != FREERTOS_INVALID_SOCKET );\r
276 \r
277                 /* The count is used to differentiate between different messages sent to\r
278                 the server, and to break out of the do while loop below. */\r
279                 ulCount = 0UL;\r
280 \r
281                 do\r
282                 {\r
283                         /* This task is going to send using the zero copy interface.  The\r
284                         data being sent is therefore written directly into a buffer that is\r
285                         passed into, rather than copied into, the FreeRTOS_sendto()\r
286                         function.\r
287 \r
288                         First obtain a buffer of adequate length from the IP stack into which\r
289                         the string will be written.  Although a max delay is used, the actual\r
290                         delay will be capped to ipconfigMAX_SEND_BLOCK_TIME_TICKS, hence\r
291                         the do while loop is used to ensure a buffer is obtained. */\r
292                         do\r
293                         {\r
294                         } while( ( pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xStringLength, portMAX_DELAY ) ) == NULL );\r
295 \r
296                         /* A buffer was successfully obtained.  Create the string that is\r
297                         sent to the server.  First the string is filled with zeros as this will\r
298                         effectively be the null terminator when the string is received at the other\r
299                         end.  Note that the string is being written directly into the buffer\r
300                         obtained from the IP stack above. */\r
301                         memset( ( void * ) pucUDPPayloadBuffer, 0x00, xStringLength );\r
302                         sprintf( ( char * ) pucUDPPayloadBuffer, "%s%lu\r\n", pcStringToSend, ulCount );\r
303 \r
304                         /* Pass the buffer into the send function.  ulFlags has the\r
305                         FREERTOS_ZERO_COPY bit set so the IP stack will take control of the\r
306                         buffer rather than copy data out of the buffer. */\r
307                         lReturned = FreeRTOS_sendto( xClientSocket,                             /* The socket being sent to. */\r
308                                                                                 ( void * ) pucUDPPayloadBuffer, /* A pointer to the the data being sent. */\r
309                                                                                 strlen( ( const char * ) pucUDPPayloadBuffer ) + 1, /* The length of the data being sent - including the string's null terminator. */\r
310                                                                                 FREERTOS_ZERO_COPY,                     /* ulFlags with the FREERTOS_ZERO_COPY bit set. */\r
311                                                                                 &xDestinationAddress,                   /* Where the data is being sent. */\r
312                                                                                 sizeof( xDestinationAddress ) );\r
313 \r
314                         if( lReturned == 0 )\r
315                         {\r
316                                 /* The send operation failed, so this task is still responsible\r
317                                 for the buffer obtained from the IP stack.  To ensure the buffer\r
318                                 is not lost it must either be used again, or, as in this case,\r
319                                 returned to the IP stack using FreeRTOS_ReleaseUDPPayloadBuffer().\r
320                                 pucUDPPayloadBuffer can be safely re-used after this call. */\r
321                                 FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer );\r
322                         }\r
323                         else\r
324                         {\r
325                                 /* The send was successful so the IP stack is now managing the\r
326                                 buffer pointed to by pucUDPPayloadBuffer, and the IP stack will\r
327                                 return the buffer once it has been sent.  pucUDPPayloadBuffer can\r
328                                 be safely re-used. */\r
329                         }\r
330 \r
331                         ulCount++;\r
332 \r
333                 } while( ( lReturned != FREERTOS_SOCKET_ERROR ) && ( ulCount < ulLoopsPerSocket ) );\r
334 \r
335                 FreeRTOS_closesocket( xClientSocket );\r
336 \r
337                 /* A short delay to prevent the messages scrolling off the screen too\r
338                 quickly. */\r
339                 vTaskDelay( x150ms );\r
340         }\r
341 }\r
342 /*-----------------------------------------------------------*/\r
343 \r
344 static void prvSimpleZeroCopyServerTask( void *pvParameters )\r
345 {\r
346 int32_t lBytes;\r
347 uint8_t *pucUDPPayloadBuffer;\r
348 struct freertos_sockaddr xClient, xBindAddress;\r
349 uint32_t xClientLength = sizeof( xClient ), ulIPAddress;\r
350 Socket_t xListeningSocket;\r
351 \r
352         /* Just to prevent compiler warnings. */\r
353         ( void ) pvParameters;\r
354 \r
355         /* Attempt to open the socket. */\r
356         xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );\r
357         configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );\r
358 \r
359         /* This test receives data sent from a different port on the same IP address.\r
360         Obtain the nodes IP address.  Configure the freertos_sockaddr structure with\r
361         the address being bound to.  The strange casting is to try and remove\r
362         compiler warnings on 32 bit machines.  Note that this task is only created\r
363         after the network is up, so the IP address is valid here. */\r
364         FreeRTOS_GetAddressConfiguration( &ulIPAddress, NULL, NULL, NULL );\r
365         xBindAddress.sin_addr = ulIPAddress;\r
366         xBindAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL;\r
367         xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );\r
368 \r
369         /* Bind the socket to the port that the client task will send to. */\r
370         FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );\r
371 \r
372         for( ;; )\r
373         {\r
374                 /* Receive data on the socket.  ulFlags has the zero copy bit set\r
375                 (FREERTOS_ZERO_COPY) indicating to the stack that a reference to the\r
376                 received data should be passed out to this task using the second\r
377                 parameter to the FreeRTOS_recvfrom() call.  When this is done the\r
378                 IP stack is no longer responsible for releasing the buffer, and\r
379                 the task *must* return the buffer to the stack when it is no longer\r
380                 needed.  By default the block time is portMAX_DELAY. */\r
381                 lBytes = FreeRTOS_recvfrom( xListeningSocket, ( void * ) &pucUDPPayloadBuffer, 0, FREERTOS_ZERO_COPY, &xClient, &xClientLength );\r
382 \r
383                 /* Print the received characters. */\r
384                 if( lBytes > 0 )\r
385                 {\r
386                         /* It is expected to receive one more byte than the string length as\r
387                         the NULL terminator is also transmitted. */\r
388                         configASSERT( lBytes == ( ( BaseType_t ) strlen( ( const char * ) pucUDPPayloadBuffer ) + 1 ) );\r
389                 }\r
390 \r
391                 if( lBytes >= 0 )\r
392                 {\r
393                         /* The buffer *must* be freed once it is no longer needed. */\r
394                         FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );\r
395                 }\r
396         }\r
397 }\r
398 \r