1- /* ******************************************************************************
2- SerialCommand - An Arduino library to tokenize and parse commands received over
3- a serial port.
4- Copyright (C) 2011 Steven Cogswell <steven.cogswell@gmail.com>
5- http://husks.wordpress.com
6-
7- Version 20110523B.
8-
9- See SerialCommand.h for version history.
10-
11- This library is free software; you can redistribute it and/or
12- modify it under the terms of the GNU Lesser General Public
13- License as published by the Free Software Foundation; either
14- version 2.1 of the License, or (at your option) any later version.
15-
16- This library is distributed in the hope that it will be useful,
17- but WITHOUT ANY WARRANTY; without even the implied warranty of
18- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19- Lesser General Public License for more details.
20-
21- You should have received a copy of the GNU Lesser General Public
22- License along with this library; if not, write to the Free Software
23- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24- ***********************************************************************************/
25-
26- #include " WProgram.h"
27- #include < string.h>
1+ /* *
2+ * SerialCommand - A Wiring/Arduino library to tokenize and parse commands
3+ * received over a serial port.
4+ *
5+ * Copyright (C) 2012 Stefan Rado
6+ * Copyright (C) 2011 Steven Cogswell <steven.cogswell@gmail.com>
7+ * http://husks.wordpress.com
8+ *
9+ * Version 20120522
10+ *
11+ * This library is free software: you can redistribute it and/or modify
12+ * it under the terms of the GNU Lesser General Public License as published by
13+ * the Free Software Foundation, either version 3 of the License, or
14+ * (at your option) any later version.
15+ *
16+ * This library is distributed in the hope that it will be useful,
17+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
18+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+ * GNU Lesser General Public License for more details.
20+ *
21+ * You should have received a copy of the GNU General Public License
22+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
23+ */
2824#include " SerialCommand.h"
2925
30- // Constructor makes sure some things are set.
26+ /* *
27+ * Constructor makes sure some things are set.
28+ */
3129SerialCommand::SerialCommand ()
30+ : commandList(NULL ),
31+ commandCount(0 ),
32+ defaultHandler(NULL ),
33+ term(' \n ' ), // default terminator for commands, newline character
34+ last(NULL )
3235{
33- strncpy (delim," " ,MAXDELIMETER ); // strtok_r needs a null-terminated string
34- term=' \r ' ; // return character, default terminator for commands
35- numCommand=0 ; // Number of callback handlers installed
36- clearBuffer ();
36+ strcpy (delim, " " ); // strtok_r needs a null-terminated string
37+ clearBuffer ();
3738}
3839
39- //
40- // Initialize the command buffer being processed to all null characters
41- //
42- void SerialCommand::clearBuffer ()
43- {
44- for (int i=0 ; i<SERIALCOMMANDBUFFER ; i++)
45- {
46- buffer[i]=' \0 ' ;
47- }
48- bufPos=0 ;
40+ /* *
41+ * Adds a "command" and a handler function to the list of available commands.
42+ * This is used for matching a found token in the buffer, and gives the pointer
43+ * to the handler function to deal with it.
44+ */
45+ void SerialCommand::addCommand (const char *command, void (*function)()) {
46+ #ifdef SERIALCOMMAND_DEBUG
47+ Serial.print (" Adding command (" );
48+ Serial.print (commandCount);
49+ Serial.print (" ): " );
50+ Serial.println (command);
51+ #endif
52+
53+ commandList = (SerialCommandCallback *) realloc (commandList, (commandCount + 1 ) * sizeof (SerialCommandCallback));
54+ strncpy (commandList[commandCount].command , command, SERIALCOMMAND_MAXCOMMANDLENGTH );
55+ commandList[commandCount].function = function;
56+ commandCount++;
4957}
5058
51- // Retrieve the next token ("word" or "argument") from the Command buffer.
52- // returns a NULL if no more tokens exist.
53- char *SerialCommand::next ()
54- {
55- char *nextToken;
56- nextToken = strtok_r (NULL , delim, &last);
57- return nextToken;
59+ /* *
60+ * This sets up a handler to be called in the event that the receveived command string
61+ * isn't in the list of commands.
62+ */
63+ void SerialCommand::setDefaultHandler (void (*function)(const char *)) {
64+ defaultHandler = function;
5865}
5966
60- // This checks the Serial stream for characters, and assembles them into a buffer.
61- // When the terminator character (default '\r') is seen, it starts parsing the
62- // buffer for a prefix command, and calls handlers setup by addCommand() member
63- void SerialCommand::readSerial ()
64- {
65- while (Serial.available () > 0 )
66- {
67- int i;
68- boolean matched;
69- inChar=Serial.read (); // Read single available character, there may be more waiting
70- #ifdef SERIALCOMMANDDEBUG
71- Serial.print (inChar); // Echo back to serial stream
72- #endif
73- if (inChar==term) { // Check for the terminator (default '\r') meaning end of command
74- #ifdef SERIALCOMMANDDEBUG
75- Serial.print (" Received: " );
76- Serial.println (buffer);
77- #endif
78- bufPos=0 ; // Reset to start of buffer
79- token = strtok_r (buffer,delim,&last); // Search for command at start of buffer
80- if (token == NULL ) return ;
81- matched=false ;
82- for (i=0 ; i<numCommand; i++) {
83- #ifdef SERIALCOMMANDDEBUG
84- Serial.print (" Comparing [" );
85- Serial.print (token);
86- Serial.print (" ] to [" );
87- Serial.print (CommandList[i].command );
88- Serial.println (" ]" );
89- #endif
90- // Compare the found command against the list of known commands for a match
91- if (strncmp (token,CommandList[i].command ,SERIALCOMMANDBUFFER ) == 0 )
92- {
93- #ifdef SERIALCOMMANDDEBUG
94- Serial.print (" Matched Command: " );
95- Serial.println (token);
96- #endif
97- // Execute the stored handler function for the command
98- (*CommandList[i].function )();
99- clearBuffer ();
100- matched=true ;
101- break ;
102- }
103- }
104- if (matched==false ) {
105- (*defaultHandler)();
106- clearBuffer ();
107- }
10867
109- }
110- if (isprint (inChar)) // Only printable characters into the buffer
111- {
112- buffer[bufPos++]=inChar; // Put character into buffer
113- buffer[bufPos]=' \0 ' ; // Null terminate
114- if (bufPos > SERIALCOMMANDBUFFER -1 ) bufPos=0 ; // wrap buffer around if full
115- }
116- }
68+ /* *
69+ * This checks the Serial stream for characters, and assembles them into a buffer.
70+ * When the terminator character (default '\n') is seen, it starts parsing the
71+ * buffer for a prefix command, and calls handlers setup by addCommand() member
72+ */
73+ void SerialCommand::readSerial () {
74+ while (Serial.available () > 0 ) {
75+ char inChar = Serial.read (); // Read single available character, there may be more waiting
76+ #ifdef SERIALCOMMAND_DEBUG
77+ Serial.print (inChar); // Echo back to serial stream
78+ #endif
79+
80+ if (inChar == term) { // Check for the terminator (default '\r') meaning end of command
81+ #ifdef SERIALCOMMAND_DEBUG
82+ Serial.print (" Received: " );
83+ Serial.println (buffer);
84+ #endif
85+
86+ char *command = strtok_r (buffer, delim, &last); // Search for command at start of buffer
87+ if (command != NULL ) {
88+ boolean matched = false ;
89+ for (int i = 0 ; i < commandCount; i++) {
90+ #ifdef SERIALCOMMAND_DEBUG
91+ Serial.print (" Comparing [" );
92+ Serial.print (command);
93+ Serial.print (" ] to [" );
94+ Serial.print (commandList[i].command );
95+ Serial.println (" ]" );
96+ #endif
97+
98+ // Compare the found command against the list of known commands for a match
99+ if (strncmp (command, commandList[i].command , SERIALCOMMAND_MAXCOMMANDLENGTH ) == 0 ) {
100+ #ifdef SERIALCOMMAND_DEBUG
101+ Serial.print (" Matched Command: " );
102+ Serial.println (command);
103+ #endif
104+
105+ // Execute the stored handler function for the command
106+ (*commandList[i].function )();
107+ matched = true ;
108+ break ;
109+ }
110+ }
111+ if (!matched && (defaultHandler != NULL )) {
112+ (*defaultHandler)(command);
113+ }
114+ }
115+ clearBuffer ();
116+ }
117+ else if (isprint (inChar)) { // Only printable characters into the buffer
118+ if (bufPos < SERIALCOMMAND_BUFFER ) {
119+ buffer[bufPos++] = inChar; // Put character into buffer
120+ buffer[bufPos] = ' \0 ' ; // Null terminate
121+ } else {
122+ #ifdef SERIALCOMMAND_DEBUG
123+ Serial.println (" Line buffer is full - increase SERIALCOMMAND_BUFFER" );
124+ #endif
125+ }
126+ }
127+ }
117128}
118129
119- // Adds a "command" and a handler function to the list of available commands.
120- // This is used for matching a found token in the buffer, and gives the pointer
121- // to the handler function to deal with it.
122- void SerialCommand::addCommand (char command[], void (*function)())
123- {
124- if (numCommand < MAXSERIALCOMMANDS ) {
125- #ifdef SERIALCOMMANDDEBUG
126- Serial.print (numCommand);
127- Serial.print (" -" );
128- Serial.print (" Adding command for " );
129- Serial.println (command);
130- #endif
131-
132- strncpy (CommandList[numCommand].command ,command,SERIALCOMMANDBUFFER );
133- CommandList[numCommand].function = function;
134- numCommand++;
135- } else {
136- // In this case, you tried to push more commands into the buffer than it is compiled to hold.
137- // Not much we can do since there is no real visible error assertion, we just ignore adding
138- // the command
139- #ifdef SERIALCOMMANDDEBUG
140- Serial.println (" Too many handlers - recompile changing MAXSERIALCOMMANDS" );
141- #endif
142- }
130+ /*
131+ * Clear the input buffer.
132+ */
133+ void SerialCommand::clearBuffer () {
134+ buffer[0 ] = ' \0 ' ;
135+ bufPos = 0 ;
143136}
144137
145- // This sets up a handler to be called in the event that the receveived command string
146- // isn't in the list of things with handlers.
147- void SerialCommand::addDefaultHandler (void (*function)())
148- {
149- defaultHandler = function;
150- }
138+ /* *
139+ * Retrieve the next token ("word" or "argument") from the command buffer.
140+ * Returns NULL if no more tokens exist.
141+ */
142+ char *SerialCommand::next () {
143+ return strtok_r (NULL , delim, &last);
144+ }
0 commit comments