]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/TCPCommandConsole.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Demo / Common / FreeRTOS_Plus_CLI_Demos / TCPCommandConsole.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 /* Standard includes. */\r
71 #include <stdint.h>\r
72 #include <stdio.h>\r
73 #include <stdarg.h>\r
74 \r
75 /* FreeRTOS includes. */\r
76 #include "FreeRTOS.h"\r
77 #include "task.h"\r
78 #include "semphr.h"\r
79 \r
80 /* FreeRTOS+CLI includes. */\r
81 #include "FreeRTOS_CLI.h"\r
82 \r
83 /* FreeRTOS+TCP includes. */\r
84 #include "FreeRTOS_IP.h"\r
85 #include "FreeRTOS_Sockets.h"\r
86 \r
87 /* Demo app includes. */\r
88 #include "TCPCommandConsole.h"\r
89 \r
90 /* Dimensions the buffer into which input characters are placed. */\r
91 #define cmdMAX_INPUT_SIZE       60\r
92 \r
93 /* Dimensions the buffer into which string outputs can be placed. */\r
94 #define cmdMAX_OUTPUT_SIZE      1024\r
95 \r
96 /* Dimensions the buffer passed to the recv() call. */\r
97 #define cmdSOCKET_INPUT_BUFFER_SIZE 60\r
98 \r
99 /* DEL acts as a backspace. */\r
100 #define cmdASCII_DEL            ( 0x7F )\r
101 \r
102 /* The maximum time to wait for a closing socket to close. */\r
103 #define cmdSHUTDOWN_DELAY       ( pdMS_TO_TICKS( 5000 ) )\r
104 \r
105 /*\r
106  * The task that runs FreeRTOS+CLI.\r
107  */\r
108 static void prvTCPCommandInterpreterTask( void *pvParameters );\r
109 \r
110 /*\r
111  * Open and configure the TCP socket.\r
112  */\r
113 static Socket_t prvOpenTCPServerSocket( uint16_t usPort );\r
114 \r
115 /*\r
116  * A connected socket is being closed.  Ensure the socket is closed at both ends\r
117  * properly.\r
118  */\r
119 static void prvGracefulShutdown( Socket_t xSocket );\r
120 \r
121 /*-----------------------------------------------------------*/\r
122 \r
123 /*\r
124  * Various buffers used by the command lin interpreter.\r
125  */\r
126 static char cOutputString[ cmdMAX_OUTPUT_SIZE ], cLocalBuffer[ cmdSOCKET_INPUT_BUFFER_SIZE ];\r
127 static char cInputString[ cmdMAX_INPUT_SIZE ], cLastInputString[ cmdMAX_INPUT_SIZE ];\r
128 \r
129 /* Const messages output by the command console. */\r
130 static const char * const pcWelcomeMessage = "FreeRTOS command server.\r\nType help to view a list of registered commands.\r\nType quit to end a session.\r\n\r\n>";\r
131 static const char * const pcEndOfOutputMessage = "\r\n[Press ENTER to execute the previous command again]\r\n>";\r
132 static const char * const pcNewLine = "\r\n";\r
133 \r
134 /*-----------------------------------------------------------*/\r
135 \r
136 void vStartTCPCommandInterpreterTask( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority )\r
137 {\r
138         xTaskCreate( prvTCPCommandInterpreterTask, "TCP CLI", usStackSize, ( void * ) ulPort, uxPriority, NULL );\r
139 }\r
140 /*-----------------------------------------------------------*/\r
141 \r
142 void prvTCPCommandInterpreterTask( void *pvParameters )\r
143 {\r
144 int32_t lBytes, lByte, lSent;\r
145 char cRxedChar, cInputIndex = 0;\r
146 BaseType_t xMoreDataToFollow;\r
147 struct freertos_sockaddr xClient;\r
148 Socket_t xListeningSocket, xConnectedSocket;\r
149 socklen_t xSize = sizeof( xClient );\r
150 \r
151         memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );\r
152 \r
153         for( ;; )\r
154         {\r
155                 /* Attempt to open the socket.  The port number is passed in the task\r
156                 parameter.  The strange casting is to remove compiler warnings on 32-bit\r
157                 machines.  NOTE:  The FREERTOS_SO_REUSE_LISTEN_SOCKET option is used,\r
158                 so the listening and connecting socket are the same - meaning only one\r
159                 connection will be accepted at a time, and that xListeningSocket must\r
160                 be created on each iteration. */\r
161                 xListeningSocket = prvOpenTCPServerSocket( ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL );\r
162 \r
163                 /* Nothing for this task to do if the socket cannot be created. */\r
164                 if( xListeningSocket == FREERTOS_INVALID_SOCKET )\r
165                 {\r
166                         vTaskDelete( NULL );\r
167                 }\r
168 \r
169                 /* Wait for an incoming connection. */\r
170                 xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize );\r
171 \r
172                 /* The FREERTOS_SO_REUSE_LISTEN_SOCKET option is set, so the\r
173                 connected and listening socket should be the same socket. */\r
174                 configASSERT( xConnectedSocket == xListeningSocket );\r
175 \r
176                 /* Send the welcome message. */\r
177                 lSent = FreeRTOS_send( xConnectedSocket,  ( void * ) pcWelcomeMessage,  strlen( pcWelcomeMessage ), 0 );\r
178 \r
179                 /* Process the socket as long as it remains connected. */\r
180                 while( lSent >= 0 )\r
181                 {\r
182                         /* Receive data on the socket. */\r
183                         lBytes = FreeRTOS_recv( xConnectedSocket, cLocalBuffer, sizeof( cLocalBuffer ), 0 );\r
184 \r
185                         if( lBytes >= 0 )\r
186                         {\r
187                                 /* Process each received byte in turn. */\r
188                                 lByte = 0;\r
189                                 while( lByte < lBytes )\r
190                                 {\r
191                                         /* The next character in the input buffer. */\r
192                                         cRxedChar = cLocalBuffer[ lByte ];\r
193                                         lByte++;\r
194 \r
195                                         /* Newline characters are taken as the end of the command\r
196                                         string. */\r
197                                         if( cRxedChar == '\n' )\r
198                                         {\r
199                                                 /* Just to space the output from the input. */\r
200                                                 FreeRTOS_send( xConnectedSocket, pcNewLine,  strlen( pcNewLine ), 0 );\r
201 \r
202                                                 /* See if the command is empty, indicating that the last\r
203                                                 command is to be executed again. */\r
204                                                 if( cInputIndex == 0 )\r
205                                                 {\r
206                                                         /* Copy the last command back into the input string. */\r
207                                                         strcpy( cInputString, cLastInputString );\r
208                                                 }\r
209 \r
210                                                 /* If the command was "quit" then close the console. */\r
211                                                 if( strcasecmp( cInputString, "quit" ) == 0 )\r
212                                                 {\r
213                                                         /* Fake an error code so the outer loop exits on the\r
214                                                         assumption there was an error on the socket.  The\r
215                                                         socket will then be shut down gracefully. */\r
216                                                         lSent = -1;\r
217                                                         break;\r
218                                                 }\r
219 \r
220                                                 /* Process the input string received prior to the\r
221                                                 newline. */\r
222                                                 do\r
223                                                 {\r
224                                                         /* Pass the string to FreeRTOS+CLI. */\r
225                                                         cOutputString[ 0 ] = 0x00;\r
226                                                         xMoreDataToFollow = FreeRTOS_CLIProcessCommand( cInputString, cOutputString, cmdMAX_OUTPUT_SIZE );\r
227 \r
228                                                         /* Send the output generated by the command's\r
229                                                         implementation. */\r
230                                                         lSent = FreeRTOS_send( xConnectedSocket, cOutputString,  strlen( ( const char * ) cOutputString ), 0 );\r
231 \r
232                                                   /* Until the command does not generate any more output. */\r
233                                                 } while( ( xMoreDataToFollow != pdFALSE ) && ( lSent >= 0 ) );\r
234 \r
235                                                 if( lSent >= 0 )\r
236                                                 {\r
237                                                         /* All the strings generated by the command\r
238                                                         processing have been sent.  Clear the input string\r
239                                                         ready to receive the next command.  Remember the\r
240                                                         previous command so it can be executed again by\r
241                                                         pressing [ENTER]. */\r
242                                                         strcpy( cLastInputString, cInputString );\r
243                                                         cInputIndex = 0;\r
244                                                         memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );\r
245 \r
246                                                         /* Transmit a spacer to make the console easier to\r
247                                                         read. */\r
248                                                         lSent = FreeRTOS_send( xConnectedSocket, ( void * ) pcEndOfOutputMessage,  strlen( pcEndOfOutputMessage ), 0 );\r
249                                                 }\r
250 \r
251                                                 if( lSent < 0 )\r
252                                                 {\r
253                                                         /* Socket closed? */\r
254                                                         break;\r
255                                                 }\r
256                                         }\r
257                                         else\r
258                                         {\r
259                                                 if( cRxedChar == '\r' )\r
260                                                 {\r
261                                                         /* Ignore the character.  Newlines are used to\r
262                                                         detect the end of the input string. */\r
263                                                 }\r
264                                                 else if( ( cRxedChar == '\b' ) || ( cRxedChar == cmdASCII_DEL ) )\r
265                                                 {\r
266                                                         /* Backspace was pressed.  Erase the last character\r
267                                                         in the string - if any. */\r
268                                                         if( cInputIndex > 0 )\r
269                                                         {\r
270                                                                 cInputIndex--;\r
271                                                                 cInputString[ ( int ) cInputIndex ] = '\0';\r
272                                                         }\r
273                                                 }\r
274                                                 else\r
275                                                 {\r
276                                                         /* A character was entered.  Add it to the string\r
277                                                         entered so far.  When a \n is entered the complete\r
278                                                         string will be passed to the command interpreter. */\r
279                                                         if( cInputIndex < cmdMAX_INPUT_SIZE )\r
280                                                         {\r
281                                                                 if( ( cRxedChar >= ' ' ) && ( cRxedChar <= '~' ) )\r
282                                                                 {\r
283                                                                         cInputString[ ( int ) cInputIndex ] = cRxedChar;\r
284                                                                         cInputIndex++;\r
285                                                                 }\r
286                                                         }\r
287                                                 }\r
288                                         }\r
289                                 }\r
290                         }\r
291                         else\r
292                         {\r
293                                 /* Socket closed? */\r
294                                 break;\r
295                         }\r
296                 }\r
297 \r
298                 /* Close the socket correctly. */\r
299                 prvGracefulShutdown( xListeningSocket );\r
300         }\r
301 }\r
302 /*-----------------------------------------------------------*/\r
303 \r
304 static void prvGracefulShutdown( Socket_t xSocket )\r
305 {\r
306 TickType_t xTimeOnShutdown;\r
307 \r
308         /* Initiate a shutdown in case it has not already been initiated. */\r
309         FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR );\r
310 \r
311         /* Wait for the shutdown to take effect, indicated by FreeRTOS_recv()\r
312         returning an error. */\r
313         xTimeOnShutdown = xTaskGetTickCount();\r
314         do\r
315         {\r
316                 if( FreeRTOS_recv( xSocket, cInputString, ipconfigTCP_MSS, 0 ) < 0 )\r
317                 {\r
318                         break;\r
319                 }\r
320         } while( ( xTaskGetTickCount() - xTimeOnShutdown ) < cmdSHUTDOWN_DELAY );\r
321 \r
322         /* Finished with the socket and the task. */\r
323         FreeRTOS_closesocket( xSocket );\r
324 }\r
325 /*-----------------------------------------------------------*/\r
326 \r
327 static Socket_t prvOpenTCPServerSocket( uint16_t usPort )\r
328 {\r
329 struct freertos_sockaddr xBindAddress;\r
330 Socket_t xSocket;\r
331 static const TickType_t xReceiveTimeOut = portMAX_DELAY;\r
332 const BaseType_t xBacklog = 20;\r
333 BaseType_t xReuseSocket = pdTRUE;\r
334 \r
335         /* Attempt to open the socket. */\r
336         xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );\r
337         configASSERT( xSocket != FREERTOS_INVALID_SOCKET );\r
338 \r
339         /* Set a time out so accept() will just wait for a connection. */\r
340         FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );\r
341 \r
342         /* Only one connection will be used at a time, so re-use the listening\r
343         socket as the connected socket.  See SimpleTCPEchoServer.c for an example\r
344         that accepts multiple connections. */\r
345         FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_REUSE_LISTEN_SOCKET, &xReuseSocket, sizeof( xReuseSocket ) );\r
346 \r
347         /* NOTE:  The CLI is a low bandwidth interface (typing characters is slow),\r
348         so the TCP window properties are left at their default.  See\r
349         SimpleTCPEchoServer.c for an example of a higher throughput TCP server that\r
350         uses are larger RX and TX buffer. */\r
351 \r
352         /* Bind the socket to the port that the client task will send to, then\r
353         listen for incoming connections. */\r
354         xBindAddress.sin_port = usPort;\r
355         xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );\r
356         FreeRTOS_bind( xSocket, &xBindAddress, sizeof( xBindAddress ) );\r
357         FreeRTOS_listen( xSocket, xBacklog );\r
358 \r
359         return xSocket;\r
360 }\r
361 /*-----------------------------------------------------------*/\r
362 \r
363 \r
364 \r
365 \r