29 | #include "SerialCmd.h"
30 | #include "credential.h"
31 |
32 | #define LED_ON HIGH // set following your hardware
33 | #define LED_OFF LOW // set following your hardware
34 |
35 | WiFiServer server ( 80 );
36 | const char* ssid = NET_SSID; // Your network SSID in credential.h file
37 | const char* password = NET_PSW; // Your network PSW in credential.h file
38 |
39 | SerialCmd mySerCmd ( Serial );
40 | bool isBlinking = false; // Indicates whether blinking is active or not
41 | uint8_t ledStatus = LED_OFF; // BUILTIN_LED status (OFF/ON)
42 | uint8_t blinkingCnt = 0; // Number of led status changes before turning off blinking
43 | uint32_t blinkingTime = 0; // Time of led status change
44 | uint32_t blinkingLast = 0; // Last millis() in which the status of the led was changed
45 |
46 | // ------------------------------------------------------------------
47 |
48 | void set_LEDON ( void ) {
49 | isBlinking = false;
50 | ledStatus = LED_ON;
51 | digitalWrite ( LED_BUILTIN, LED_ON );
52 | }
53 |
54 | void set_LEDOF ( void ) {
55 | isBlinking = false;
56 | ledStatus = LED_OFF;
57 | digitalWrite ( LED_BUILTIN, LED_OFF );
58 | }
59 |
60 | void set_LEDBL ( void ) {
61 | char * sParam;
62 | //
63 | sParam = mySerCmd.ReadNext();
64 | if ( sParam == NULL ) {
65 | return;
66 | }
67 | blinkingCnt = 0;
68 | blinkingTime = strtoul ( sParam, NULL, 10 );
69 | blinkingLast = millis();
70 | isBlinking = true;
71 | }
72 |
73 | // ------------------------------------------------------------------
74 |
75 |
76 | char* checkWiFiCommand ( void ) {
77 | static const uint8_t BUF_LNG = 200; // HTML buffer max lenght
78 | static const uint8_t CMD_LNG = 128; // Command buffer max lenght
79 | static const uint16_t NET_TIMEOUT = 2000; // Browser session timeout
80 | static char clientBuffer[BUF_LNG]; // HTML buffer
81 | static char clientCommand[CMD_LNG]; // Command buffer for SerialCmd
82 | //
83 | uint8_t buf_idx = 0;
84 | int8_t lstCmdStatus = -1; // indicate the last command status -1:none, 0:NOT valid, 1:valid
85 | uint32_t lastMillis = 0;
86 | char c = 0;
87 | char* cmdStart = NULL;
88 | char* cmdStop = NULL;
89 | char* retVal = NULL;
90 | //
91 | WiFiClient client = server.available();
92 | if ( client ) {
93 | // Client connected ...
94 | memset ( clientBuffer, 0x00, BUF_LNG );
95 | memset ( clientCommand, 0x00, CMD_LNG );
96 | buf_idx = 0;
97 | lastMillis = millis();
98 | //
99 | while ( client.connected() ) {
100 | if ( client.available() ) {
101 | c = client.read();
102 | lastMillis = millis();
103 | //
104 | if ( c == '\n' ) {
105 | //
106 | // New Line received ...
107 | if ( strlen ( clientBuffer ) == 0 ) {
108 | //
109 | // ... empty line, send response to client
110 | client.println ( "HTTP/1.1 200 OK" );
111 | client.println ( "Content-type:text/html" );
112 | client.println ( "Connection: close" );
113 | client.println();
114 | //
115 | // Display the HTML web page
116 | client.println ( "" );
117 | client.println ( "ESP SerialCmd Server
" );
118 | client.println ( "Please, enter a valid command using the following syntax: http://" );
119 | client.print ( WiFi.localIP() );
120 | client.println ( "/command,parameters
" );
121 | //
122 | if ( SERIALCMD_FORCEUC != 0 ) {
123 | client.println ( "Note: lower case characters will be converted to upper case.
" );
124 | }
125 | //
126 | if ( lstCmdStatus == 0 ) {
127 | client.println ( "Last entered command was NOT recognized.
" );
128 | lstCmdStatus = -1;
129 | retVal = NULL;
130 | } else if ( lstCmdStatus == 1 ) {
131 | client.println ( "Last entered command WAS recognized and will be executed.
" );
132 | lstCmdStatus = -1;
133 | }
134 | client.println ( "" );
135 | //
136 | client.println();
137 | break;
138 | } else {
139 | //
140 | // ... search for HTTP GET line
141 | cmdStart = strstr ( clientBuffer, "GET /" );
142 | if ( cmdStart != NULL ) {
143 | cmdStop = strstr ( clientBuffer, "HTTP" );
144 | if ( cmdStop != NULL ) {
145 | if ( ( int ) ( cmdStop - cmdStart - 5 ) < CMD_LNG ) {
146 | strlcpy ( clientCommand, ( cmdStart + 5 ), ( int ) ( cmdStop - cmdStart - 5 ) );
147 | if ( strcmp ( "favicon.ico", clientCommand ) != 0 ) {
148 | retVal = clientCommand;
149 | lstCmdStatus = mySerCmd.ReadString ( retVal, true );
150 | }
151 | }
152 | }
153 | }
154 | memset ( clientBuffer, 0x00, BUF_LNG );
155 | buf_idx = 0;
156 | }
157 | } else {
158 | if ( c != '\r' ) {
159 | if ( buf_idx < ( BUF_LNG - 1 ) )
160 | clientBuffer[buf_idx++] = c;
161 | }
162 | }
163 | }
164 | if ( millis() - lastMillis > NET_TIMEOUT ) break;
165 | }
166 | client.stop();
167 | }
168 | return retVal;
169 | }
170 |
171 | // ------------------------------------------------------------------
172 |
173 | void setup() {
174 | delay ( 500 );
175 | //
176 | ledStatus = LED_OFF;
177 | pinMode ( LED_BUILTIN, OUTPUT );
178 | digitalWrite ( LED_BUILTIN, ledStatus );
179 | //
180 | Serial.begin ( 115200 );
181 | Serial.println();
182 | Serial.println();
183 | Serial.print ( "Connecting to " );
184 | Serial.print ( NET_SSID );
185 | Serial.print ( " " );
186 | //
187 | WiFi.begin ( ssid, password );
188 | //
189 | while ( WiFi.status() != WL_CONNECTED ) {
190 | delay ( 500 );
191 | Serial.print ( "." );
192 | }
193 | Serial.println();
194 | //
195 | Serial.println ( "WiFi connected." );
196 | Serial.print ( "IP address: " );
197 | Serial.println ( WiFi.localIP() );
198 | //
199 | mySerCmd.AddCmd ( "LEDON", SERIALCMD_FROMALL, set_LEDON );
200 | mySerCmd.AddCmd ( "LEDOF", SERIALCMD_FROMALL, set_LEDOF );
201 | mySerCmd.AddCmd ( "LEDBL", SERIALCMD_FROMALL, set_LEDBL );
202 | //
203 | Serial.println();
204 | Serial.print ( "You are using SerialCmd ver. " );
205 | Serial.println ( SERIALCMD_VER );
206 | Serial.println ( "Valid commands are:" );
207 | Serial.println ( " LEDON" );
208 | Serial.println ( " LEDOF" );
209 | Serial.println ( " LEDBL,msec" );
210 | Serial.println();
211 | //
212 | server.begin();
213 | }
214 |
215 | // ------------------------------------------------------------------
216 |
217 | void loop() {
218 | char* retVal;
219 | int8_t cmdStatus;
220 | //
221 | retVal = checkWiFiCommand();
222 | if ( retVal != NULL ) {
223 | Serial.print ( "HTTP received command: " );
224 | Serial.println ( retVal );
225 | cmdStatus = mySerCmd.ReadString ( retVal );
226 | }
227 | //
228 | if ( isBlinking && ( millis() - blinkingLast > blinkingTime ) ) {
229 | ledStatus = !ledStatus;
230 | digitalWrite ( LED_BUILTIN, ledStatus );
231 | blinkingCnt++;
232 | blinkingLast += blinkingTime;
233 | }
234 | if ( blinkingCnt >= 10 ) {
235 | blinkingCnt = 0;
236 | mySerCmd.ReadString ( ( char * ) "LEDOF" );
237 | }
238 | //
239 | cmdStatus = mySerCmd.ReadSer();
240 | if ( cmdStatus == false )
241 | mySerCmd.Print ( ( char * ) "ERROR: Urecognized command. \r\n" );
242 | //
243 | yield();
244 | }
245 |
--------------------------------------------------------------------------------
/examples/ESP_SerialCmd/credential.h:
--------------------------------------------------------------------------------
1 | #ifndef _CREDENTIAL
2 | #define _CREDENTIAL
3 |
4 | #define NET_SSID "Your_SSID"
5 | #define NET_PSW "Your_PSW"
6 |
7 | #endif
8 |
--------------------------------------------------------------------------------
/examples/SD_LB_SerialCmd/LABEL.TXT:
--------------------------------------------------------------------------------
1 | LABEL,0
2 | PRINT,1
3 | DELAY,1000
4 | IFPIN,2,0,1
5 | LABEL,1
6 | PRINT,2
7 |
--------------------------------------------------------------------------------
/examples/SD_LB_SerialCmd/SD_LB_SerialCmd.ino:
--------------------------------------------------------------------------------
1 | /*
2 | SD_LB_SerialCmd - A simple program to demostrate the use of SerialCmd
3 | library to show the capability to receive commands via text file on SD.
4 |
5 | Copyright (C) 2013 - 2022 Guglielmo Braguglia
6 |
7 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
8 |
9 | This is free software: you can redistribute it and/or modify it under
10 | the terms of the GNU Lesser General Public License as published by
11 | the Free Software Foundation, either version 3 of the License, or
12 | (at your option) any later version.
13 |
14 | This software is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | GNU Lesser General Public License for more details.
18 |
19 | */
20 |
21 | #include
22 | #include
23 | #include
24 |
25 | #if ( SERIALCMD_VER_NUM < 10103 )
26 | #error "This program can compile only with SerialCmd version 1.1.3 or greater"
27 | #endif
28 |
29 | #define SD_CS 10 // Pin where the SD CS is connected
30 | #define MAX_LBL 5 // Maximun number of labels in text file
31 |
32 | File dataFile;
33 | SerialCmd mySerCmd ( dataFile, SERIALCMD_LF );
34 |
35 | uint32_t labelPtr[MAX_LBL];
36 |
37 | // --------------- Functions for SerialCmd ---------------
38 |
39 | void f_LABEL ( void ) {
40 | char * sParam;
41 | uint8_t numLbl;
42 | //
43 | sParam = mySerCmd.ReadNext();
44 | if ( sParam == NULL ) {
45 | Serial.println ( "ERROR: Missing first paramemter on LABEL command" );
46 | while ( true ) delay ( 500 );
47 | }
48 | numLbl = atoi ( sParam );
49 | if ( numLbl >= MAX_LBL ) {
50 | Serial.println ( "ERROR: First paramemter on LABEL command too big" );
51 | while ( true ) delay ( 500 );
52 | }
53 | //
54 | labelPtr[numLbl] = dataFile.position();
55 | //
56 | Serial.print ( "Label " );
57 | Serial.print ( numLbl );
58 | Serial.print ( " set to " );
59 | Serial.println ( labelPtr[numLbl] );
60 | }
61 |
62 | void f_PRINT ( void ) {
63 | uint8_t prtNum;
64 | //
65 | prtNum = atoi ( mySerCmd.ReadNext() );
66 | Serial.print ( "PRINT command value: " );
67 | Serial.println ( prtNum );
68 | }
69 |
70 | void f_DELAY ( void ) {
71 | char * sParam;
72 | uint32_t delayTime;
73 | //
74 | sParam = mySerCmd.ReadNext();
75 | if ( sParam == NULL )
76 | return;
77 | delayTime = strtoul ( sParam, NULL, 10 );
78 | Serial.print ( "DELAY," );
79 | Serial.println ( delayTime );
80 | delay ( delayTime );
81 | }
82 |
83 | void f_IFPIN ( void ) {
84 | uint8_t pinNum, trueLbl, falseLbl;
85 | //
86 | pinNum = atoi ( mySerCmd.ReadNext() );
87 | trueLbl = atoi ( mySerCmd.ReadNext() );
88 | falseLbl = atoi ( mySerCmd.ReadNext() );
89 | //
90 | if ( ( trueLbl >= MAX_LBL ) || ( falseLbl >= MAX_LBL ) ) {
91 | Serial.println ( "ERROR: true/false paramemter on IFPIN command too big" );
92 | while ( true ) delay ( 500 );
93 | }
94 | //
95 | pinMode ( pinNum, INPUT_PULLUP );
96 | delay ( 50 );
97 | if ( digitalRead ( pinNum ) ) {
98 | // Jump to the true label
99 | dataFile.seek ( labelPtr[trueLbl] );
100 | Serial.print ( "Jumping to the true label : " );
101 | Serial.println ( trueLbl );
102 | } else {
103 | // jump to the false label
104 | dataFile.seek ( labelPtr[falseLbl] );
105 | Serial.print ( "Jumping to the false label : " );
106 | Serial.println ( falseLbl );
107 | }
108 | }
109 |
110 | // ----------------------- setup() -----------------------
111 |
112 | void setup() {
113 | int8_t retval;
114 | //
115 | delay ( 500 );
116 | //
117 | Serial.begin ( 9600 );
118 | while ( !Serial ) {
119 | delay ( 500 );
120 | }
121 | Serial.println();
122 | Serial.println ( "Program started ..." );
123 | //
124 | if ( !SD.begin ( SD_CS ) ) {
125 | Serial.println ( "Initialization failed!" );
126 | while ( 1 ) delay ( 500 );
127 | }
128 | //
129 | dataFile = SD.open ( "LABEL.TXT", FILE_READ );
130 | if ( !dataFile ) {
131 | Serial.println ( "File open in READ failed!" );
132 | while ( 1 ) delay ( 500 );
133 | }
134 | //
135 | // Set the SerialCmd to execute only LABEL command
136 | mySerCmd.AddCmd ( "LABEL", SERIALCMD_FROMALL, f_LABEL );
137 | mySerCmd.AddCmd ( "PRINT", SERIALCMD_FROMALL, NULL );
138 | mySerCmd.AddCmd ( "DELAY", SERIALCMD_FROMALL, NULL );
139 | mySerCmd.AddCmd ( "IFPIN", SERIALCMD_FROMALL, NULL );
140 | //
141 | delay ( 500 );
142 | //
143 | // Read one first time all the file searcing for LABELs
144 | Serial.println();
145 | Serial.println ( "Reading lables ..." );
146 | while ( dataFile.available() ) {
147 | retval = mySerCmd.ReadSer();
148 | if ( !retval )
149 | Serial.println ( ( char * ) "ERROR: Urecognized command. \r\n" );
150 | }
151 | //
152 | // Set the SerialCmd to execute all commands but NOT LABELs
153 | mySerCmd.AddCmd ( "LABEL", SERIALCMD_FROMALL, NULL );
154 | mySerCmd.AddCmd ( "PRINT", SERIALCMD_FROMALL, f_PRINT );
155 | mySerCmd.AddCmd ( "DELAY", SERIALCMD_FROMALL, f_DELAY );
156 | mySerCmd.AddCmd ( "IFPIN", SERIALCMD_FROMALL, f_IFPIN );
157 | //
158 | // Return to the begin of file
159 | dataFile.seek ( 0 );
160 | delay ( 100 );
161 | //
162 | // Read a second time the file executing commands
163 | Serial.println();
164 | Serial.println ( "Executing commands ..." );
165 | while ( dataFile.available() ) {
166 | retval = mySerCmd.ReadSer();
167 | if ( !retval )
168 | Serial.println ( ( char * ) "ERROR: Urecognized command. \r\n" );
169 | }
170 | dataFile.close();
171 | //
172 | Serial.println ( "Program ended." );
173 | }
174 |
175 | // ----------------------- loop() ------------------------
176 |
177 | void loop() {
178 |
179 | }
180 |
--------------------------------------------------------------------------------
/examples/SD_SerialCmd/BLINK.TXT:
--------------------------------------------------------------------------------
1 | LEDON
2 | DELAY,1000
3 | LEDOF
4 | DELAY,1000
5 | LEDON
6 | DELAY,1000
7 | LEDOF
8 | DELAY,1000
9 | LEDON
10 | DELAY,1000
11 | LEDOF
12 | DELAY,1000
13 | LEDON
14 | DELAY,1000
15 | LEDOF
16 | DELAY,1000
17 | LEDON
18 | DELAY,1000
19 | LEDOF
20 | DELAY,1000
21 | LEDON
22 | DELAY,1000
23 | LEDOF
24 | DELAY,1000
25 | LEDON
26 | DELAY,1000
27 | LEDOF
28 | DELAY,1000
29 | LEDON
30 | DELAY,1000
31 | LEDOF
32 | DELAY,1000
33 | LEDON
34 | DELAY,1000
35 | LEDOF
36 | DELAY,1000
37 | LEDON
38 | DELAY,1000
39 | LEDOF
40 |
--------------------------------------------------------------------------------
/examples/SD_SerialCmd/SD_SerialCmd.ino:
--------------------------------------------------------------------------------
1 | /*
2 | SD_SerialCmd - A simple program to demostrate the use of SerialCmd
3 | library to show the capability to receive commands via text file on SD.
4 |
5 | Copyright (C) 2013 - 2022 Guglielmo Braguglia
6 |
7 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
8 |
9 | This is free software: you can redistribute it and/or modify it under
10 | the terms of the GNU Lesser General Public License as published by
11 | the Free Software Foundation, either version 3 of the License, or
12 | (at your option) any later version.
13 |
14 | This software is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | GNU Lesser General Public License for more details.
18 |
19 | */
20 |
21 | #include
22 | #include
23 | #include
24 |
25 | #define LED_OFF LOW // Adjust for your board
26 | #define LED_ON HIGH // Adjust for your board
27 | #define LED_PIN 7 // Pin where a LED is connected
28 | #define SD_CS 10 // Pin where the SD CS is connected
29 |
30 | File dataFile;
31 | SerialCmd mySerCmd ( dataFile );
32 |
33 | // --------------- Functions for SerialCmd ---------------
34 |
35 | void set_LEDON ( void ) {
36 | digitalWrite ( LED_PIN, LED_ON );
37 | Serial.println ( "LEDON" );
38 | }
39 |
40 | void set_LEDOF ( void ) {
41 | digitalWrite ( LED_PIN, LED_OFF );
42 | Serial.println ( "LEDOF" );
43 | }
44 |
45 | void set_DELAY ( void ) {
46 | char * sParam;
47 | uint32_t delayTime;
48 | //
49 | sParam = mySerCmd.ReadNext();
50 | if ( sParam == NULL )
51 | return;
52 | delayTime = strtoul ( sParam, NULL, 10 );
53 | Serial.print ( "DELAY," );
54 | Serial.println ( delayTime );
55 | delay ( delayTime );
56 | }
57 |
58 | // ----------------------- setup() -----------------------
59 |
60 | void setup() {
61 | int8_t retval;
62 | //
63 | delay ( 500 );
64 | pinMode ( LED_PIN, OUTPUT );
65 | //
66 | Serial.begin ( 9600 );
67 | while ( !Serial ) {
68 | delay ( 500 );
69 | }
70 | Serial.println();
71 | Serial.println ( "Program started ..." );
72 | //
73 | if ( !SD.begin ( SD_CS ) ) {
74 | Serial.println ( "Initialization failed!" );
75 | while ( 1 ) delay ( 500 );
76 | }
77 | //
78 | dataFile = SD.open ( "BLINK.TXT", FILE_READ );
79 | if ( !dataFile ) {
80 | Serial.println ( "File open in READ failed!" );
81 | while ( 1 ) delay ( 500 );
82 | }
83 | //
84 | mySerCmd.AddCmd ( "LEDON", SERIALCMD_FROMALL, set_LEDON );
85 | mySerCmd.AddCmd ( "LEDOF", SERIALCMD_FROMALL, set_LEDOF );
86 | mySerCmd.AddCmd ( "DELAY", SERIALCMD_FROMALL, set_DELAY );
87 | //
88 | delay ( 500 );
89 | //
90 | while ( dataFile.available() ) {
91 | retval = mySerCmd.ReadSer();
92 | if ( !retval )
93 | Serial.println ( ( char * ) "ERROR: Urecognized command. \r\n" );
94 | }
95 | dataFile.close();
96 | //
97 | Serial.println ( "Program ended." );
98 | }
99 |
100 | // ----------------------- loop() ------------------------
101 |
102 | void loop() {
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/keywords.txt:
--------------------------------------------------------------------------------
1 | SerialCmd KEYWORD1
2 | lastLine KEYWORD1
3 |
4 | ReadSer KEYWORD2
5 | AddCmd KEYWORD2
6 | ReadNext KEYWORD2
7 | ReadString KEYWORD2
8 | Print KEYWORD2
9 |
10 | SERIALCMD_FORCEUC LITERAL1
11 | SERIALCMD_MAXCMDNUM LITERAL1
12 | SERIALCMD_MAXCMDLNG LITERAL1
13 | SERIALCMD_MAXBUFFER LITERAL1
14 | SERIALCMD_PUBBUFFER LITERAL1
15 | SERIALCMD_FROMSTRING LITERAL1
16 | SERIALCMD_FROMALL LITERAL1
17 | SERIALCMD_FROMSERIAL LITERAL1
18 | SERIALCMD_CR LITERAL1
19 | SERIALCMD_LF LITERAL1
20 | SERIALCMD_NULL LITERAL1
21 | SERIALCMD_COMMA LITERAL1
22 | SERIALCMD_SEMICOL LITERAL1
23 | SERIALCMD_DOT LITERAL1
24 | SERIALCMD_SPACE LITERAL1
--------------------------------------------------------------------------------
/library.properties:
--------------------------------------------------------------------------------
1 | name=SerialCmd
2 | version=1.1.6
3 | author=Guglielmo Braguglia
4 | maintainer=Guglielmo Braguglia
5 | sentence=Just another library to tokenize and parse commands.
6 | paragraph=A Wiring/Arduino library to tokenize and parse commands received over a phisical/software serial port or buffer. From the original work of Stefan Rado & Steven Cogswell.
7 | category=Communication
8 | url=https://github.com/gpb01/SerialCmd
9 | architectures=*
10 |
--------------------------------------------------------------------------------
/src/SerialCmd.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | SerialCmd - A Wiring/Arduino library to tokenize and parse commands
3 | received over a phisical/software serial port and optimized to run
4 | also on ATtiny series.
5 |
6 | Copyright (C) 2013 - 2023 Guglielmo Braguglia
7 |
8 | Based on the SerialCommand library :
9 | Copyright (C) 2012 Stefan Rado
10 | Copyright (C) 2011 Steven Cogswell
11 | http://husks.wordpress.com
12 |
13 | Version 20231009
14 |
15 | Please note:
16 |
17 | 1. Adjust the #define(s) following your requirements :
18 | Use the real necessary values for SERIALCMD_MAXCMDNUM, SERIALCMD_MAXCMDLNG
19 | and SERIALCMD_MAXBUFFER to minimize the memory usage.
20 | If you need a second, program-accessible buffer, containing the command
21 | received before being processed, set SERIALCMD_PUBBUFFER to 1 otherwise leave
22 | it to 0.
23 |
24 | 2. Allowed string terminator from serial are:
25 | SERIALCMD_CR : Carriage Return (0x0D - char - default)
26 | SERIALCMD_LF : Line Feed (0x0A - char)
27 | SERIALCMD_NULL : NULL (0x00 - char)
28 |
29 | 3. Allowed command source parameter are:
30 | SERIALCMD_FROMSTRING (or -1) : valid only as ReadString command
31 | SERIALCMD_FROMALL : always valid - default
32 | SERIALCMD_FROMSERIAL : valid only as ReadSer command
33 |
34 | 4. You MUST initialize the serial port (phisical or virtual) on your Setup()
35 | and pass the Stream as parameter to the class constructor.
36 |
37 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
38 |
39 | This library is free software: you can redistribute it and/or modify
40 | it under the terms of the GNU Lesser General Public License as published by
41 | the Free Software Foundation, either version 3 of the License, or
42 | (at your option) any later version.
43 |
44 | This library is distributed in the hope that it will be useful,
45 | but WITHOUT ANY WARRANTY; without even the implied warranty of
46 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47 | GNU Lesser General Public License for more details.
48 |
49 | You should have received a copy of the GNU General Public License
50 | along with this library. If not, see .
51 | */
52 |
53 | #include "SerialCmd.h"
54 |
55 | /*
56 | --- Private methods ---
57 | */
58 |
59 | void SerialCmd::ClearBuffer() {
60 | memset ( SerialCmd_Buffer, 0x00, SERIALCMD_MAXBUFFER + 1 );
61 | SerialCmd_BufferIdx = 0;
62 | }
63 |
64 | void SerialCmd::ConvertUC() {
65 | for ( uint8_t i = 0; i < strlen ( SerialCmd_Command ); i++ ) {
66 | if ( ( SerialCmd_Command[i] >= 'a' ) && ( SerialCmd_Command[i] <= 'z' ) ) {
67 | SerialCmd_Command[i] -= 32;
68 | }
69 | }
70 | }
71 |
72 | void SerialCmd::ReadStringCommon () {
73 | SerialCmd_Command = strtok_r ( SerialCmd_Buffer, SerialCmd_Sep, &SerialCmd_Last );
74 | SerialCmd_Found = 0;
75 | if ( SerialCmd_Command != NULL ) {
76 | if ( SERIALCMD_FORCEUC ) ConvertUC();
77 | for ( SerialCmd_Idx = 0; SerialCmd_Idx < SerialCmd_CmdCount; SerialCmd_Idx++ ) {
78 | if ( strncmp ( SerialCmd_Command, SerialCmd_CmdList[SerialCmd_Idx].command, SERIALCMD_MAXCMDLNG ) == 0 ) {
79 | if ( SerialCmd_CmdList[SerialCmd_Idx].allowedSource <= 0 ) {
80 | if ( SerialCmd_CmdList[SerialCmd_Idx].function != NULL ) {
81 | ( *SerialCmd_CmdList[SerialCmd_Idx].function ) ();
82 | }
83 | SerialCmd_Found = 1;
84 | break;
85 | }
86 | }
87 | }
88 | }
89 | ClearBuffer();
90 | }
91 |
92 | uint8_t SerialCmd::AddCmdCommon ( const char *command, char allowedSource, void ( *function ) () ) {
93 | for ( SerialCmd_Idx = 0; SerialCmd_Idx < SerialCmd_CmdCount; SerialCmd_Idx++ ) {
94 | if ( strncmp ( command, SerialCmd_CmdList[SerialCmd_Idx].command, strlen ( command ) ) == 0 ) {
95 | SerialCmd_CmdList[SerialCmd_Idx].allowedSource = allowedSource;
96 | SerialCmd_CmdList[SerialCmd_Idx].function = function;
97 | return 1;
98 | }
99 | }
100 | //
101 | if ( SerialCmd_CmdCount < SERIALCMD_MAXCMDNUM ) {
102 | strncpy ( SerialCmd_CmdList[SerialCmd_CmdCount].command, command, SERIALCMD_MAXCMDLNG );
103 | SerialCmd_CmdList[SerialCmd_CmdCount].allowedSource = allowedSource;
104 | SerialCmd_CmdList[SerialCmd_CmdCount].function = function;
105 | SerialCmd_CmdCount++;
106 | return 1;
107 | } else {
108 | return 0;
109 | }
110 | }
111 |
112 | void SerialCmd::ValidateCommand () {
113 | uint8_t i = 0;
114 | //
115 | SerialCmd_Found = 0;
116 | if ( strlen ( SerialCmd_Buffer ) == 0 ) return;
117 | memset ( SerialCmd_BuffCmd, 0x00, SERIALCMD_MAXCMDLNG + 1 );
118 | //
119 | for ( i = 0; i < strlen ( SerialCmd_Buffer ); i++ ) {
120 | if ( ( SerialCmd_Buffer[i] == SerialCmd_Sep[0] ) || ( SerialCmd_Buffer[i] == 0x00 ) ) break;
121 | }
122 | if ( i > SERIALCMD_MAXCMDLNG ) i = SERIALCMD_MAXCMDLNG;
123 | strncpy ( SerialCmd_BuffCmd, SerialCmd_Buffer, i );
124 | //
125 | for ( SerialCmd_Idx = 0; SerialCmd_Idx < SerialCmd_CmdCount; SerialCmd_Idx++ ) {
126 | #if ( SERIALCMD_FORCEUC == 0 )
127 | if ( strcmp ( SerialCmd_BuffCmd, SerialCmd_CmdList[SerialCmd_Idx].command ) == 0 ) {
128 | #else
129 | if ( strcasecmp ( SerialCmd_BuffCmd, SerialCmd_CmdList[SerialCmd_Idx].command ) == 0 ) {
130 | #endif
131 | if ( SerialCmd_CmdList[SerialCmd_Idx].allowedSource <= 0 ) {
132 | SerialCmd_Found = 1;
133 | break;
134 | }
135 | }
136 | }
137 | }
138 |
139 | /*
140 | --- Public methods ---
141 | */
142 |
143 | SerialCmd::SerialCmd ( Stream &mySerial, char TermCh, char * SepCh ) {
144 | ClearBuffer();
145 | SerialCmd_CmdCount = 0;
146 | theSerial = &mySerial;
147 | SerialCmd_Term = TermCh;
148 |
149 | #if defined ( ARDUINO_ARCH_RENESAS )
150 | /*
151 | Aug, 2023 - gpb01
152 | Since Renesas compiler does NOT implement the strlcpy() we can't use:
153 | strlcpy ( SerialCmd_Sep, SepCh, 2 );
154 | and we replaced it with strncpy().
155 | */
156 | strncpy ( SerialCmd_Sep, SepCh, 1 );
157 | strncpy ( (SerialCmd_Sep + 1 ), ( char * ) SERIALCMD_NULL, 1 );
158 | #else
159 | strlcpy ( SerialCmd_Sep, SepCh, 2 );
160 | #endif
161 | }
162 |
163 | uint8_t SerialCmd::AddCmd ( const char *command, char allowedSource, void ( *function ) () ) {
164 | return AddCmdCommon ( command, allowedSource, function );
165 | }
166 |
167 | #ifdef __AVR__
168 | uint8_t SerialCmd::AddCmd ( const __FlashStringHelper *command, char allowedSource, void ( *function ) () ) {
169 | char myCommand[SERIALCMD_MAXCMDLNG + 1];
170 | //
171 | memset ( myCommand, 0x00, SERIALCMD_MAXCMDLNG + 1 );
172 | strncpy_P ( myCommand, ( const char* ) command, SERIALCMD_MAXCMDLNG );
173 | return AddCmdCommon ( myCommand, allowedSource, function );
174 | }
175 | #endif
176 |
177 | int8_t SerialCmd::ReadSer() {
178 | SerialCmd_Found = -1;
179 | while ( theSerial->available() > 0 ) {
180 | SerialCmd_InChar = theSerial->read();
181 | if ( SerialCmd_InChar == SerialCmd_Term ) {
182 | #if ( SERIALCMD_PUBBUFFER == 1)
183 | strcpy(lastLine, SerialCmd_Buffer); // copy to public buffer
184 | #endif
185 | SerialCmd_Command = strtok_r ( SerialCmd_Buffer, SerialCmd_Sep, &SerialCmd_Last );
186 | SerialCmd_Found = 0;
187 | if ( SerialCmd_Command != NULL ) {
188 | if ( SERIALCMD_FORCEUC ) ConvertUC();
189 | for ( SerialCmd_Idx = 0; SerialCmd_Idx < SerialCmd_CmdCount; SerialCmd_Idx++ ) {
190 | if ( strncmp ( SerialCmd_Command, SerialCmd_CmdList[SerialCmd_Idx].command, SERIALCMD_MAXCMDLNG ) == 0 ) {
191 | if ( SerialCmd_CmdList[SerialCmd_Idx].allowedSource >= 0 ) {
192 | if ( SerialCmd_CmdList[SerialCmd_Idx].function != NULL ) {
193 | ( *SerialCmd_CmdList[SerialCmd_Idx].function ) ();
194 | }
195 | SerialCmd_Found = 1;
196 | break;
197 | }
198 | }
199 | }
200 | }
201 | ClearBuffer();
202 | } else {
203 | if ( SerialCmd_BufferIdx < SERIALCMD_MAXBUFFER ) {
204 | if ( ( SerialCmd_InChar != SERIALCMD_CR ) && ( SerialCmd_InChar != SERIALCMD_LF ) ) {
205 | SerialCmd_Buffer[SerialCmd_BufferIdx++] = SerialCmd_InChar;
206 | SerialCmd_Buffer[SerialCmd_BufferIdx] = 0x00;
207 | }
208 | } else {
209 | ClearBuffer();
210 | }
211 | }
212 | }
213 | return SerialCmd_Found;
214 | }
215 |
216 | int8_t SerialCmd::ReadString ( char * theCmd, uint8_t fValidate ) {
217 | if ( strlen ( theCmd ) >= SERIALCMD_MAXBUFFER ) return 0;
218 | //
219 | strcpy ( SerialCmd_Buffer, theCmd );
220 | if ( fValidate ) {
221 | ValidateCommand ();
222 | } else {
223 | ReadStringCommon();
224 | }
225 | return SerialCmd_Found;
226 | }
227 |
228 | #ifdef __AVR__
229 | int8_t SerialCmd::ReadString ( const __FlashStringHelper * theCmd, uint8_t fValidate ) {
230 | if ( strlen_P ( ( const char* ) theCmd ) >= SERIALCMD_MAXBUFFER ) return 0;
231 | //
232 | strcpy_P ( SerialCmd_Buffer, ( const char* ) theCmd );
233 | if ( fValidate ) {
234 | ValidateCommand ();
235 | } else {
236 | ReadStringCommon();
237 | }
238 | return SerialCmd_Found;
239 | }
240 | #endif
241 |
242 | char * SerialCmd::ReadNext() {
243 | return strtok_r ( NULL, SerialCmd_Sep, &SerialCmd_Last );
244 | }
245 |
246 | void SerialCmd::Print ( String &theClassString ) {
247 | if ( ( theSerial ) )
248 | theSerial->write ( theClassString.c_str(), theClassString.length() );
249 | }
250 |
251 | void SerialCmd::Print ( char theString[] ) {
252 | if ( ( theSerial ) )
253 | theSerial->write ( theString );
254 | }
255 |
256 | #ifdef __AVR__
257 | void SerialCmd::Print ( const __FlashStringHelper * theString ) {
258 | if ( ( theSerial ) )
259 | theSerial->print ( theString );
260 | }
261 | #endif
262 |
263 | void SerialCmd::Print ( char theChar ) {
264 | if ( ( theSerial ) )
265 | theSerial->write ( theChar );
266 | }
267 |
268 | void SerialCmd::Print ( unsigned char theUChar ) {
269 | if ( ( theSerial ) )
270 | theSerial->print ( theUChar );
271 | }
272 |
273 | void SerialCmd::Print ( int theInt ) {
274 | if ( ( theSerial ) )
275 | theSerial->print ( theInt );
276 | }
277 |
278 | void SerialCmd::Print ( unsigned int theUInt ) {
279 | if ( ( theSerial ) )
280 | theSerial->print ( theUInt );
281 | }
282 |
283 | void SerialCmd::Print ( long theLong ) {
284 | if ( ( theSerial ) )
285 | theSerial->print ( theLong );
286 | }
287 |
288 | void SerialCmd::Print ( unsigned long theULong ) {
289 | if ( ( theSerial ) )
290 | theSerial->print ( theULong );
291 | }
292 |
293 | void SerialCmd::Print ( float theFloat, int numDec ) {
294 | if ( ( theSerial ) )
295 | theSerial->print ( theFloat, numDec );
296 | }
297 |
298 | void SerialCmd::Print ( double theDouble, int numDec ) {
299 | if ( ( theSerial ) )
300 | theSerial->print ( theDouble, numDec );
301 | }
302 |
--------------------------------------------------------------------------------
/src/SerialCmd.h:
--------------------------------------------------------------------------------
1 | /*
2 | SerialCmd - A Wiring/Arduino library to tokenize and parse commands
3 | received over a phisical/software serial port and optimized to run
4 | also on ATtiny series.
5 |
6 | Copyright (C) 2013 - 2023 Guglielmo Braguglia
7 |
8 | Based on the SerialCommand library :
9 | Copyright (C) 2012 Stefan Rado
10 | Copyright (C) 2011 Steven Cogswell
11 | http://husks.wordpress.com
12 |
13 | Version 20231009
14 |
15 | Please note:
16 |
17 | 1. Adjust the #define(s) following your requirements :
18 | Use the real necessary values for SERIALCMD_MAXCMDNUM, SERIALCMD_MAXCMDLNG
19 | and SERIALCMD_MAXBUFFER to minimize the memory usage.
20 | If you need a second, program-accessible buffer, containing the command
21 | received before being processed, set SERIALCMD_PUBBUFFER to 1 otherwise leave
22 | it to 0.
23 |
24 | 2. Allowed string terminator from serial are:
25 | SERIALCMD_CR : Carriage Return (0x0D - char - default)
26 | SERIALCMD_LF : Line Feed (0x0A - char)
27 | SERIALCMD_NULL : NULL (0x00 - char)
28 |
29 | 3. Allowed command source parameter are:
30 | SERIALCMD_FROMSTRING (or -1) : valid only as ReadString command
31 | SERIALCMD_FROMALL : always valid - default
32 | SERIALCMD_FROMSERIAL : valid only as ReadSer command
33 |
34 | 4. You MUST initialize the serial port (phisical or virtual) on your Setup()
35 | and pass the Stream as parameter to the class constructor.
36 |
37 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
38 |
39 | This library is free software: you can redistribute it and/or modify
40 | it under the terms of the GNU Lesser General Public License as published by
41 | the Free Software Foundation, either version 3 of the License, or
42 | (at your option) any later version.
43 |
44 | This library is distributed in the hope that it will be useful,
45 | but WITHOUT ANY WARRANTY; without even the implied warranty of
46 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47 | GNU Lesser General Public License for more details.
48 |
49 | You should have received a copy of the GNU General Public License
50 | along with this library. If not, see .
51 | */
52 |
53 | #ifndef SERIALCMD
54 | #define SERIALCMD
55 |
56 | #if defined(WIRING) && WIRING >= 100
57 | #include
58 | #elif defined(ARDUINO) && ARDUINO >= 100
59 | #include
60 | #else
61 | #include
62 | #endif
63 |
64 | #include
65 | #ifdef __AVR__
66 | #include
67 | #endif
68 |
69 | // SerialCmd version
70 |
71 | #define SERIALCMD_VER "1.1.5" // SerialCmd library internal string version
72 | #define SERIALCMD_VER_NUM 10105 // SerialCmd library internal numeric version
73 | #define SERIALCMD_VER_MAJ 1 // SerialCmd library internal major version
74 | #define SERIALCMD_VER_MIN 1 // SerialCmd library internal minor version
75 | #define SERIALCMD_VER_REV 5 // SerialCmd library internal revision version
76 |
77 | // SerialCmd configuration. Adjust following your needs
78 |
79 | #define SERIALCMD_FORCEUC 0 // If set to 1 force uppercase for serial command
80 | #define SERIALCMD_MAXCMDNUM 8 // Max Number of Command
81 | #define SERIALCMD_MAXCMDLNG 6 // Max Command Length
82 | #define SERIALCMD_MAXBUFFER 30 // Max Buffer Length
83 |
84 | #define SERIALCMD_PUBBUFFER 0 // If set to 1 create a public double buffer to read lines
85 |
86 | // Command source validity
87 | #define SERIALCMD_FROMSTRING -1 // Valid only as SerialCmd_ReadString command
88 | #define SERIALCMD_FROMALL 0 // Always valid
89 | #define SERIALCMD_FROMSERIAL 1 // Valid only as SerialCmd_ReadSer command
90 |
91 | // End Command possible characters
92 | #define SERIALCMD_CR 0x0D // Carriage Return (char)
93 | #define SERIALCMD_LF 0x0A // Line Feed (char)
94 | #define SERIALCMD_NULL 0x00 // NULL (char)
95 |
96 | // Parameter separators possible strings
97 | #define SERIALCMD_COMMA "," // COMMA (C string)
98 | #define SERIALCMD_SEMICOL ";" // SEMI COLUMN (C string)
99 | #define SERIALCMD_DOT "." // DOT (C string)
100 | #define SERIALCMD_SPACE " " // SPACE (C string)
101 |
102 | // SerialCmd class definition
103 |
104 | class SerialCmd {
105 | public:
106 |
107 | SerialCmd ( Stream &mySerial, char TermCh = SERIALCMD_CR, char * SepCh = ( char * ) SERIALCMD_COMMA ); // Constructor
108 | int8_t ReadSer ( void );
109 | uint8_t AddCmd ( const char *, char, void ( * ) () );
110 | char * ReadNext ( void );
111 | int8_t ReadString ( char *, uint8_t fValidate = false );
112 | void Print ( String & );
113 | void Print ( char[] );
114 | void Print ( char );
115 | void Print ( unsigned char );
116 | void Print ( int );
117 | void Print ( unsigned int );
118 | void Print ( long );
119 | void Print ( unsigned long );
120 | void Print ( float, int numDec = 2 );
121 | void Print ( double, int numDec = 2 );
122 | #ifdef __AVR__
123 | uint8_t AddCmd ( const __FlashStringHelper *, char, void ( * ) () );
124 | int8_t ReadString ( const __FlashStringHelper *, uint8_t fValidate = false );
125 | void Print ( const __FlashStringHelper * );
126 | #endif
127 |
128 | #if ( SERIALCMD_PUBBUFFER == 1 )
129 | char lastLine[SERIALCMD_MAXBUFFER + 1]; // Create a double buffer read lines public
130 | #endif
131 |
132 | private:
133 |
134 | struct SerialCmd_Callback { // Structure to record Command/Function pairs
135 | char command[SERIALCMD_MAXCMDLNG + 1];
136 | signed char allowedSource;
137 | void ( *function ) ();
138 | };
139 |
140 | SerialCmd_Callback SerialCmd_CmdList[SERIALCMD_MAXCMDNUM]; // Definition for Command/Function array
141 | uint8_t SerialCmd_CmdCount; // Number of defined Command/Function
142 |
143 | char SerialCmd_Buffer[SERIALCMD_MAXBUFFER + 1]; // Serial buffer for Command
144 | char SerialCmd_BuffCmd[SERIALCMD_MAXCMDLNG + 1]; // Buffer for ONLY the commend part of the Buffer (NO parameters)
145 | char SerialCmd_InChar; // Serial input character
146 | char * SerialCmd_Command = NULL; // Working variable used by strtok_r
147 | char * SerialCmd_Last = NULL; // State variable used by strtok_r
148 |
149 | char SerialCmd_Term; // Default terminator for command (default CR)
150 | char SerialCmd_SepCh[2] = ","; // Allocate spece for separator characther (default = COMMA)
151 | char * SerialCmd_Sep = SerialCmd_SepCh; // Pointer to separator character
152 |
153 | uint8_t SerialCmd_Idx; // General index for FOR loops
154 | uint8_t SerialCmd_BufferIdx; // Serial buffer Index
155 | int8_t SerialCmd_Found; // Valid command found
156 |
157 | Stream* theSerial; // Serial stream in use
158 |
159 | void ClearBuffer ( void ); // Clear the SerialCmd_Buffer filling with 0x00
160 | void ConvertUC ( void ); // Convert the lower case characters of SerialCmd_Command to upper case
161 | void ReadStringCommon ( void ); // Common function used by the two version of ReadString to EXECUTE a command
162 | void ValidateCommand ( void ); // Common function used by the two version of ReadString to VALIDATE a command
163 | uint8_t AddCmdCommon ( const char *command, char allowedSource, void ( *function ) () ); // Common function used by the two version of AddCmd to ADD/MOD a command
164 | };
165 | #endif
166 |
--------------------------------------------------------------------------------