CmdMessenger  4.0.0
CmdMessenger is a messaging library for the Arduino Platform. It has uses the serial port as its transport layer
D:/My Documents/Github/Arduino/Own Arduino libraries/CmdMessenger/Arduino-CmdMessenger/CmdMessenger.h
00001 /*
00002   CmdMessenger - library that provides command based messaging
00003 
00004   Permission is hereby granted, free of charge, to any person obtaining
00005   a copy of this software and associated documentation files (the
00006   "Software"), to deal in the Software without restriction, including
00007   without limitation the rights to use, copy, modify, merge, publish,
00008   distribute, sublicense, and/or sell copies of the Software, and to
00009   permit persons to whom the Software is furnished to do so, subject to
00010   the following conditions:
00011 
00012   The above copyright notice and this permission notice shall be
00013   included in all copies or substantial portions of the Software.
00014 
00015   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00016   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00017   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00018   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00019   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00020   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00021   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00022 
00023   */
00024 
00025 #ifndef CmdMessenger_h
00026 #define CmdMessenger_h
00027 
00028 #include <inttypes.h>
00029 #if ARDUINO >= 100
00030 #include <Arduino.h> 
00031 #else
00032 #include <WProgram.h> 
00033 #endif
00034 
00035 //#include "Stream.h"
00036 
00037 extern "C"
00038 {
00039     // callback functions always follow the signature: void cmd(void);
00040     typedef void(*messengerCallbackFunction) (void);
00041 }
00042 
00043 #define MAXCALLBACKS        50   // The maximum number of commands   (default: 50)
00044 #define MESSENGERBUFFERSIZE 64   // The length of the commandbuffer  (default: 64)
00045 #define MAXSTREAMBUFFERSIZE 512  // The length of the streambuffer   (default: 64)
00046 #define DEFAULT_TIMEOUT     5000 // Time out on unanswered messages. (default: 5s)
00047 
00048 // Message States
00049 enum
00050 {
00051     kProccesingMessage,            // Message is being received, not reached command separator
00052     kEndOfMessage,               // Message is fully received, reached command separator
00053     kProcessingArguments,            // Message is received, arguments are being read parsed
00054 };
00055 
00056 #define white_space(c) ((c) == ' ' || (c) == '\t')
00057 #define valid_digit(c) ((c) >= '0' && (c) <= '9')
00058 
00059 class CmdMessenger
00060 {
00061 private:
00062     // **** Private variables *** 
00063 
00064     bool    startCommand;            // Indicates if sending of a command is underway
00065     uint8_t lastCommandId;          // ID of last received command 
00066     uint8_t bufferIndex;              // Index where to write data in buffer
00067     uint8_t bufferLength;             // Is set to MESSENGERBUFFERSIZE
00068     uint8_t bufferLastIndex;          // The last index of the buffer
00069     char ArglastChar;                 // Bookkeeping of argument escape char 
00070     char CmdlastChar;                 // Bookkeeping of command escape char 
00071     bool pauseProcessing;             // pauses processing of new commands, during sending
00072     bool print_newlines;              // Indicates if \r\n should be added after send command
00073     char commandBuffer[MESSENGERBUFFERSIZE]; // Buffer that holds the data
00074     char streamBuffer[MAXSTREAMBUFFERSIZE]; // Buffer that holds the data
00075     uint8_t messageState;             // Current state of message processing
00076     bool dumped;                      // Indicates if last argument has been externally read 
00077     bool ArgOk;                     // Indicated if last fetched argument could be read
00078     char *current;                    // Pointer to current buffer position
00079     char *last;                       // Pointer to previous buffer position
00080     char prevChar;                    // Previous char (needed for unescaping)
00081     Stream *comms;                    // Serial data stream
00082 
00083     char command_separator;           // Character indicating end of command (default: ';')
00084     char field_separator;               // Character indicating end of argument (default: ',')
00085     char escape_character;          // Character indicating escaping of special chars
00086 
00087     messengerCallbackFunction default_callback;            // default callback function  
00088     messengerCallbackFunction callbackList[MAXCALLBACKS];  // list of attached callback functions 
00089 
00090 
00091     // **** Initialize ****
00092 
00093     void init(Stream & comms, const char fld_separator, const char cmd_separator, const char esc_character);
00094     void reset();
00095 
00096     // **** Command processing ****
00097 
00098     inline uint8_t processLine(char serialChar) __attribute__((always_inline));
00099     inline void handleMessage() __attribute__((always_inline));
00100     inline bool blockedTillReply(unsigned int timeout = DEFAULT_TIMEOUT, byte ackCmdId = 1) __attribute__((always_inline));
00101     inline bool checkForAck(byte AckCommand) __attribute__((always_inline));
00102 
00103     // **** Command sending ****
00104 
00108     template < class T >
00109     void writeBin(const T & value)
00110     {
00111         const byte *bytePointer = (const byte *)(const void *)&value;
00112         for (unsigned int i = 0; i < sizeof(value); i++)
00113         {
00114             printEsc(*bytePointer);
00115             bytePointer++;
00116         }
00117     }
00118 
00119     // **** Command receiving ****
00120 
00121     int findNext(char *str, char delim);
00122 
00126     template < class T >
00127     T readBin(char *str)
00128     {
00129         T value;
00130         unescape(str);
00131         byte *bytePointer = (byte *)(const void *)&value;
00132         for (unsigned int i = 0; i < sizeof(value); i++)
00133         {
00134             *bytePointer = str[i];
00135             bytePointer++;
00136         }
00137         return value;
00138     }
00139 
00140     template < class T >
00141     T empty()
00142     {
00143         T value;
00144         byte *bytePointer = (byte *)(const void *)&value;
00145         for (unsigned int i = 0; i < sizeof(value); i++)
00146         {
00147             *bytePointer = '\0';
00148             bytePointer++;
00149         }
00150         return value;
00151     }
00152 
00153     // **** Escaping tools ****
00154 
00155     char *split_r(char *str, const char delim, char **nextp);
00156     bool isEscaped(char *currChar, const char escapeChar, char *lastChar);
00157 
00158     void printEsc(char *str);
00159     void printEsc(char str);
00160 
00161 public:
00162 
00163     // ****** Public functions ******
00164 
00165     // **** Initialization ****
00166 
00167     CmdMessenger(Stream & comms, const char fld_separator = ',',
00168         const char cmd_separator = ';',
00169         const char esc_character = '/');
00170 
00171     void printLfCr(bool addNewLine = true);
00172     void attach(messengerCallbackFunction newFunction);
00173     void attach(byte msgId, messengerCallbackFunction newFunction);
00174 
00175     // **** Command processing ****
00176 
00177     void feedinSerialData();
00178     bool next();
00179     bool available();
00180     bool isArgOk();
00181     uint8_t commandID();
00182 
00183     // ****  Command sending ****
00184 
00189     template < class T >
00190     bool sendCmd(byte cmdId, T arg, bool reqAc = false, byte ackCmdId = 1,
00191         unsigned int timeout = DEFAULT_TIMEOUT)
00192     {
00193         if (!startCommand) {
00194             sendCmdStart(cmdId);
00195             sendCmdArg(arg);
00196             return sendCmdEnd(reqAc, ackCmdId, timeout);
00197         }
00198         return false;
00199     }
00200 
00205     template < class T >
00206     bool sendBinCmd(byte cmdId, T arg, bool reqAc = false, byte ackCmdId = 1,
00207         unsigned int timeout = DEFAULT_TIMEOUT)
00208     {
00209         if (!startCommand) {
00210             sendCmdStart(cmdId);
00211             sendCmdBinArg(arg);
00212             return sendCmdEnd(reqAc, ackCmdId, timeout);
00213         }
00214         return false;
00215     }
00216 
00217     bool sendCmd(byte cmdId);
00218     bool sendCmd(byte cmdId, bool reqAc, byte ackCmdId);
00219     // **** Command sending with multiple arguments ****
00220 
00221     void sendCmdStart(byte cmdId);
00222     void sendCmdEscArg(char *arg);
00223     void sendCmdfArg(char *fmt, ...);
00224     bool sendCmdEnd(bool reqAc = false, byte ackCmdId = 1, unsigned int timeout = DEFAULT_TIMEOUT);
00225 
00230     template < class T > void sendCmdArg(T arg)
00231     {
00232         if (startCommand) {
00233             comms->print(field_separator);
00234             comms->print(arg);
00235         }
00236     }
00237 
00242     template < class T > void sendCmdArg(T arg, unsigned int n)
00243     {
00244         if (startCommand) {
00245             comms->print(field_separator);
00246             comms->print(arg, n);
00247         }
00248     }
00249 
00254     void sendCmdSciArg(double arg, unsigned int n = 6);
00255 
00256 
00261     template < class T > void sendCmdBinArg(T arg)
00262     {
00263         if (startCommand) {
00264             comms->print(field_separator);
00265             writeBin(arg);
00266         }
00267     }
00268 
00269     // **** Command receiving ****
00270     bool readBoolArg();
00271     int16_t readInt16Arg();
00272     int32_t readInt32Arg();
00273     char readCharArg();
00274     float readFloatArg();
00275     double readDoubleArg();
00276     char *readStringArg();
00277     void copyStringArg(char *string, uint8_t size);
00278     uint8_t compareStringArg(char *string);
00279 
00283     template < class T > T readBinArg()
00284     {
00285         if (next()) {
00286             dumped = true;
00287             return readBin < T >(current);
00288         }
00289         else {
00290             return empty < T >();
00291         }
00292     }
00293 
00294     // **** Escaping tools ****
00295 
00296     void unescape(char *fromChar);
00297     void printSci(double f, unsigned int digits);
00298 
00299 
00300 };
00301 #endif