Skip to content

Commit

Permalink
ok
Browse files Browse the repository at this point in the history
  • Loading branch information
ngohuynhngockhanh committed Feb 26, 2017
0 parents commit f4bb4ed
Show file tree
Hide file tree
Showing 8 changed files with 734 additions and 0 deletions.
42 changes: 42 additions & 0 deletions README.txt
@@ -0,0 +1,42 @@
An Arduino library to tokenize and parse commands received over a serial port.

Initially documented here: http://awtfy.com/2011/05/23/a-minimal-arduino-library-for-processing-serial-commands/

An alternate version of this library is available as https://github.com/kroimon/Arduino-SerialCommand

This version is the one on Github.

/*******************************************************************************
SerialCommand - An Arduino library to tokenize and parse commands received over
a serial port.
Copyright (C) 2011-2013 Steven Cogswell <steven.cogswell@gmail.com>
http://awtfy.com

Version 20131021A.

Version History:
May 11 2011 - Initial version
May 13 2011 - Prevent overwriting bounds of SerialCommandCallback[] array in addCommand()
defaultHandler() for non-matching commands
Mar 2012 - Some const char * changes to make compiler happier about deprecated warnings.
Arduino 1.0 compatibility (Arduino.h header)
Oct 2013 - SerialCommand object can be created using a SoftwareSerial object, for SoftwareSerial
support. Requires #include <SoftwareSerial.h> in your sketch even if you don't use
a SoftwareSerial port in the project. sigh. See Example Sketch for usage.
Oct 2013 - Conditional compilation for the SoftwareSerial support, in case you really, really
hate it and want it removed.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
***********************************************************************************/
211 changes: 211 additions & 0 deletions SerialCommand.cpp
@@ -0,0 +1,211 @@
/*******************************************************************************
SerialCommand - An Arduino library to tokenize and parse commands received over
a serial port.
Copyright (C) 2011-2013 Steven Cogswell <steven.cogswell@gmail.com>
http://awtfy.com
See SerialCommand.h for version history.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
***********************************************************************************/

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include "SerialCommand.h"


#include <string.h>
#ifndef SERIALCOMMAND_HARDWAREONLY
#include <SoftwareSerial.h>
#endif

// Constructor makes sure some things are set.
SerialCommand::SerialCommand()
{
usingSoftwareSerial=0;
nowReading = false; //means read eventName
strncpy(delim," ",MAXDELIMETER); // strtok_r needs a null-terminated string
term='\r'; // return character, default terminator for commands
numCommand=0; // Number of callback handlers installed
clearBuffer();
}

#ifndef SERIALCOMMAND_HARDWAREONLY
// Constructor to use a SoftwareSerial object
SerialCommand::SerialCommand(SoftwareSerial &_SoftSer)
{
usingSoftwareSerial=1;
SoftSerial = &_SoftSer;
nowReading = false; //means read eventName
strncpy(delim," ",MAXDELIMETER); // strtok_r needs a null-terminated string
term='\r'; // return character, default terminator for commands
numCommand=0; // Number of callback handlers installed
clearBuffer();
}
#endif


//
// Initialize the command buffer being processed to all null characters
//
void SerialCommand::clearBuffer(char type)
{
if (type == 0 || type == 2) {
for (int i=0; i<SERIALCOMMANDBUFFER; i++)
{
buffer[i]='\0';
}
bufPos=0;
}
if (type == 1 || type == 2) {
for (int i=0; i<ARGUMENTBUFFER; i++)
{
bufferArg[i]='\0';
}
bufArgPos = 0;
}


}

// Retrieve the next token ("word" or "argument") from the Command buffer.
// returns a NULL if no more tokens exist.
char *SerialCommand::next()
{
char *nextToken = bufferArg;
return nextToken;
}

// This checks the Serial stream for characters, and assembles them into a buffer.
// When the terminator character (default '\r') is seen, it starts parsing the
// buffer for a prefix command, and calls handlers setup by addCommand() member
void SerialCommand::readSerial()
{
// If we're using the Hardware port, check it. Otherwise check the user-created SoftwareSerial Port
#ifdef SERIALCOMMAND_HARDWAREONLY
while (Serial.available() > 0)
#else
while ((usingSoftwareSerial==0 && Serial.available() > 0) || (usingSoftwareSerial==1 && SoftSerial->available() > 0) )
#endif
{
int i;
boolean matched;
if (usingSoftwareSerial==0) {
// Hardware serial port
inChar=Serial.read(); // Read single available character, there may be more waiting
} else {
#ifndef SERIALCOMMAND_HARDWAREONLY
// SoftwareSerial port
inChar = SoftSerial->read(); // Read single available character, there may be more waiting
#endif
}
#ifdef SERIALCOMMANDDEBUG
Serial.print(inChar); // Echo back to serial stream
#endif
if (inChar==term) { // Check for the terminator (default '\r') meaning end of command
#ifdef SERIALCOMMANDDEBUG
Serial.print("Received: ");
Serial.println(buffer);
#endif
bufPos=0; // Reset to start of buffer
#ifdef SERIALCOMMANDDEBUG
Serial.print("nowReading: ");
Serial.println(nowReading);
#endif
if (!nowReading) { //read buffer
token = strtok_r(buffer,delim,&last); // Search for command at start of buffer
if (token == NULL) return;
matched=false;
} else {
for (i=0; i<numCommand; i++) {
#ifdef SERIALCOMMANDDEBUG
Serial.print("Comparing [");
Serial.print(token);
Serial.print("] to [");
Serial.print(CommandList[i].command);
Serial.println("]");
#endif
// Compare the found command against the list of known commands for a match
if (strncmp(token,CommandList[i].command,SERIALCOMMANDBUFFER) == 0)
{
#ifdef SERIALCOMMANDDEBUG
Serial.print("Matched Command: ");
Serial.println(token);
#endif
// Execute the stored handler function for the command
(*CommandList[i].function)();
clearBuffer();
matched=true;
break;
}
}
if (matched==false) {
(*defaultHandler)();
clearBuffer();
}
}
nowReading = !nowReading;//hoasn vij laij ahihi
}
if (isprint(inChar)) // Only printable characters into the buffer
{
if (!nowReading) {
buffer[bufPos++]=inChar; // Put character into buffer
buffer[bufPos]='\0'; // Null terminate
if (bufPos > SERIALCOMMANDBUFFER-1) bufPos=0; // wrap buffer around if full
} else {
bufferArg[bufArgPos++]=inChar; // Put character into bufferArg
bufferArg[bufArgPos]='\0'; // Null terminate
if (bufArgPos > ARGUMENTBUFFER-1) bufArgPos=0; // wrap buffer around if full
}
}
}
}

// Adds a "command" and a handler function to the list of available commands.
// This is used for matching a found token in the buffer, and gives the pointer
// to the handler function to deal with it.
void SerialCommand::addCommand(const char *command, void (*function)())
{
if (numCommand < MAXSERIALCOMMANDS) {
#ifdef SERIALCOMMANDDEBUG
Serial.print(numCommand);
Serial.print("-");
Serial.print("Adding command for ");
Serial.println(command);
#endif

strncpy(CommandList[numCommand].command,command,SERIALCOMMANDBUFFER);
CommandList[numCommand].function = function;
numCommand++;
} else {
// In this case, you tried to push more commands into the buffer than it is compiled to hold.
// Not much we can do since there is no real visible error assertion, we just ignore adding
// the command
#ifdef SERIALCOMMANDDEBUG
Serial.println("Too many handlers - recompile changing MAXSERIALCOMMANDS");
#endif
}
}

// This sets up a handler to be called in the event that the receveived command string
// isn't in the list of things with handlers.
void SerialCommand::addDefaultHandler(void (*function)())
{
defaultHandler = function;
}
114 changes: 114 additions & 0 deletions SerialCommand.h
@@ -0,0 +1,114 @@
/*******************************************************************************
SerialCommand - An Arduino library to tokenize and parse commands received over
a serial port.
Based on 2011-2013 Steven Cogswell <steven.cogswell@gmail.com>
Copyright 2017 Ngo Huynh Ngoc Khanh <ngohuynhngockhanh@gmail.com>
http://arduino.vn
Version 2017.
Version History:
May 11 2011 - Initial version
May 13 2011 - Prevent overwriting bounds of SerialCommandCallback[] array in addCommand()
defaultHandler() for non-matching commands
Mar 2012 - Some const char * changes to make compiler happier about deprecated warnings.
Arduino 1.0 compatibility (Arduino.h header)
Oct 2013 - SerialCommand object can be created using a SoftwareSerial object, for SoftwareSerial
support. Requires #include <SoftwareSerial.h> in your sketch even if you don't use
a SoftwareSerial port in the project. sigh. See Example Sketch for usage.
Oct 2013 - Conditional compilation for the SoftwareSerial support, in case you really, really
hate it and want it removed.
Feb 2017 - Allow command and arguments into two buffers
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
***********************************************************************************/
#ifndef SerialCommand_h
#define SerialCommand_h

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

// If you want to use SerialCommand with the hardware serial port only, and want to disable
// SoftwareSerial support, and thus don't have to use "#include <SoftwareSerial.h>" in your
// sketches, then uncomment this define for SERIALCOMMAND_HARDWAREONLY, and comment out the
// corresponding #undef line.
//
// You don't have to use SoftwareSerial features if this is not defined, you can still only use
// the Hardware serial port, just that this way lets you get out of having to include
// the SoftwareSerial.h header.
//#define SERIALCOMMAND_HARDWAREONLY 1
#undef SERIALCOMMAND_HARDWAREONLY

#ifdef SERIALCOMMAND_HARDWAREONLY
#warning "Warning: Building SerialCommand without SoftwareSerial Support"
#endif

#ifndef SERIALCOMMAND_HARDWAREONLY
#include <SoftwareSerial.h>
#endif

#include <string.h>


#define SERIALCOMMANDBUFFER 10
#define ARGUMENTBUFFER 256
#define MAXSERIALCOMMANDS 10
#define MAXDELIMETER 2

#define SERIALCOMMANDDEBUG 1
#undef SERIALCOMMANDDEBUG // Comment this out to run the library in debug mode (verbose messages)

class SerialCommand
{
public:
SerialCommand(); // Constructor
#ifndef SERIALCOMMAND_HARDWAREONLY
SerialCommand(SoftwareSerial &SoftSer); // Constructor for using SoftwareSerial objects
#endif

void clearBuffer(char type = 2); // Sets the command buffer to all '\0' (nulls)
char *next(); // returns pointer to next token found in command buffer (for getting arguments to commands)
void readSerial(); // Main entry point.
void addCommand(const char *, void(*)()); // Add commands to processing dictionary
void addDefaultHandler(void (*function)()); // A handler to call when no valid command received.

private:
char inChar; // A character read from the serial stream
char buffer[SERIALCOMMANDBUFFER]; // Buffer of stored characters while waiting for terminator character
char bufferArg[ARGUMENTBUFFER]; // Buffer for arguments
bool nowReading;
int bufPos; // Current position in the buffer
int bufArgPos; // current possiotion in the buffer arg
char delim[MAXDELIMETER]; // null-terminated list of character to be used as delimeters for tokenizing (default " ")
char term; // Character that signals end of command (default '\r')
char *token; // Returned token from the command buffer as returned by strtok_r
char *last; // State variable used by strtok_r during processing
typedef struct _callback {
char command[SERIALCOMMANDBUFFER];
void (*function)();
} SerialCommandCallback; // Data structure to hold Command/Handler function key-value pairs
int numCommand;
SerialCommandCallback CommandList[MAXSERIALCOMMANDS]; // Actual definition for command/handler array
void (*defaultHandler)(); // Pointer to the default handler function
int usingSoftwareSerial; // Used as boolean to see if we're using SoftwareSerial object or not
#ifndef SERIALCOMMAND_HARDWAREONLY
SoftwareSerial *SoftSerial; // Pointer to a user-created SoftwareSerial object
#endif
};

#endif //SerialCommand_h

0 comments on commit f4bb4ed

Please sign in to comment.