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
70 /* Standard includes. */
\r
75 /* FreeRTOS includes. */
\r
76 #include "FreeRTOS.h"
\r
80 /* FreeRTOS+CLI includes. */
\r
81 #include "FreeRTOS_CLI.h"
\r
83 /* FreeRTOS+TCP includes. */
\r
84 #include "FreeRTOS_IP.h"
\r
85 #include "FreeRTOS_Sockets.h"
\r
87 /* Demo app includes. */
\r
88 #include "TCPCommandConsole.h"
\r
90 /* Dimensions the buffer into which input characters are placed. */
\r
91 #define cmdMAX_INPUT_SIZE 60
\r
93 /* Dimensions the buffer into which string outputs can be placed. */
\r
94 #define cmdMAX_OUTPUT_SIZE 1024
\r
96 /* Dimensions the buffer passed to the recv() call. */
\r
97 #define cmdSOCKET_INPUT_BUFFER_SIZE 60
\r
99 /* DEL acts as a backspace. */
\r
100 #define cmdASCII_DEL ( 0x7F )
\r
102 /* The maximum time to wait for a closing socket to close. */
\r
103 #define cmdSHUTDOWN_DELAY ( pdMS_TO_TICKS( 5000 ) )
\r
106 * The task that runs FreeRTOS+CLI.
\r
108 static void prvTCPCommandInterpreterTask( void *pvParameters );
\r
111 * Open and configure the TCP socket.
\r
113 static Socket_t prvOpenTCPServerSocket( uint16_t usPort );
\r
116 * A connected socket is being closed. Ensure the socket is closed at both ends
\r
119 static void prvGracefulShutdown( Socket_t xSocket );
\r
121 /*-----------------------------------------------------------*/
\r
124 * Various buffers used by the command lin interpreter.
\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
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
134 /*-----------------------------------------------------------*/
\r
136 void vStartTCPCommandInterpreterTask( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority )
\r
138 xTaskCreate( prvTCPCommandInterpreterTask, "TCP CLI", usStackSize, ( void * ) ulPort, uxPriority, NULL );
\r
140 /*-----------------------------------------------------------*/
\r
142 void prvTCPCommandInterpreterTask( void *pvParameters )
\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
151 memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
\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
163 /* Nothing for this task to do if the socket cannot be created. */
\r
164 if( xListeningSocket == FREERTOS_INVALID_SOCKET )
\r
166 vTaskDelete( NULL );
\r
169 /* Wait for an incoming connection. */
\r
170 xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize );
\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
176 /* Send the welcome message. */
\r
177 lSent = FreeRTOS_send( xConnectedSocket, ( void * ) pcWelcomeMessage, strlen( pcWelcomeMessage ), 0 );
\r
179 /* Process the socket as long as it remains connected. */
\r
180 while( lSent >= 0 )
\r
182 /* Receive data on the socket. */
\r
183 lBytes = FreeRTOS_recv( xConnectedSocket, cLocalBuffer, sizeof( cLocalBuffer ), 0 );
\r
187 /* Process each received byte in turn. */
\r
189 while( lByte < lBytes )
\r
191 /* The next character in the input buffer. */
\r
192 cRxedChar = cLocalBuffer[ lByte ];
\r
195 /* Newline characters are taken as the end of the command
\r
197 if( cRxedChar == '\n' )
\r
199 /* Just to space the output from the input. */
\r
200 FreeRTOS_send( xConnectedSocket, pcNewLine, strlen( pcNewLine ), 0 );
\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
206 /* Copy the last command back into the input string. */
\r
207 strcpy( cInputString, cLastInputString );
\r
210 /* If the command was "quit" then close the console. */
\r
211 if( strcasecmp( cInputString, "quit" ) == 0 )
\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
220 /* Process the input string received prior to the
\r
224 /* Pass the string to FreeRTOS+CLI. */
\r
225 cOutputString[ 0 ] = 0x00;
\r
226 xMoreDataToFollow = FreeRTOS_CLIProcessCommand( cInputString, cOutputString, cmdMAX_OUTPUT_SIZE );
\r
228 /* Send the output generated by the command's
\r
230 lSent = FreeRTOS_send( xConnectedSocket, cOutputString, strlen( ( const char * ) cOutputString ), 0 );
\r
232 /* Until the command does not generate any more output. */
\r
233 } while( ( xMoreDataToFollow != pdFALSE ) && ( lSent >= 0 ) );
\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
244 memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
\r
246 /* Transmit a spacer to make the console easier to
\r
248 lSent = FreeRTOS_send( xConnectedSocket, ( void * ) pcEndOfOutputMessage, strlen( pcEndOfOutputMessage ), 0 );
\r
253 /* Socket closed? */
\r
259 if( cRxedChar == '\r' )
\r
261 /* Ignore the character. Newlines are used to
\r
262 detect the end of the input string. */
\r
264 else if( ( cRxedChar == '\b' ) || ( cRxedChar == cmdASCII_DEL ) )
\r
266 /* Backspace was pressed. Erase the last character
\r
267 in the string - if any. */
\r
268 if( cInputIndex > 0 )
\r
271 cInputString[ ( int ) cInputIndex ] = '\0';
\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
281 if( ( cRxedChar >= ' ' ) && ( cRxedChar <= '~' ) )
\r
283 cInputString[ ( int ) cInputIndex ] = cRxedChar;
\r
293 /* Socket closed? */
\r
298 /* Close the socket correctly. */
\r
299 prvGracefulShutdown( xListeningSocket );
\r
302 /*-----------------------------------------------------------*/
\r
304 static void prvGracefulShutdown( Socket_t xSocket )
\r
306 TickType_t xTimeOnShutdown;
\r
308 /* Initiate a shutdown in case it has not already been initiated. */
\r
309 FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR );
\r
311 /* Wait for the shutdown to take effect, indicated by FreeRTOS_recv()
\r
312 returning an error. */
\r
313 xTimeOnShutdown = xTaskGetTickCount();
\r
316 if( FreeRTOS_recv( xSocket, cInputString, ipconfigTCP_MSS, 0 ) < 0 )
\r
320 } while( ( xTaskGetTickCount() - xTimeOnShutdown ) < cmdSHUTDOWN_DELAY );
\r
322 /* Finished with the socket and the task. */
\r
323 FreeRTOS_closesocket( xSocket );
\r
325 /*-----------------------------------------------------------*/
\r
327 static Socket_t prvOpenTCPServerSocket( uint16_t usPort )
\r
329 struct freertos_sockaddr xBindAddress;
\r
331 static const TickType_t xReceiveTimeOut = portMAX_DELAY;
\r
332 const BaseType_t xBacklog = 20;
\r
333 BaseType_t xReuseSocket = pdTRUE;
\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
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
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
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
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
361 /*-----------------------------------------------------------*/
\r