CmdMessenger  3.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-Code-and-Libraries/Libraries/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 maximum length of the buffer (default: 64)
00045 #define MAXSTREAMBUFFERSIZE 32   // The maximum length of the buffer (default: 32)
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 class CmdMessenger
00057 {
00058 private:
00059 
00060   // **** Private variables *** 
00061   
00062   bool    startCommand;            // Indicates if sending of a command is underway
00063   uint8_t lastCommandId;            // ID of last received command 
00064   uint8_t bufferIndex;              // Index where to write data in buffer
00065   uint8_t bufferLength;             // Is set to MESSENGERBUFFERSIZE
00066   uint8_t bufferLastIndex;          // The last index of the buffer
00067   char ArglastChar;                 // Bookkeeping of argument escape char 
00068   char CmdlastChar;                 // Bookkeeping of command escape char 
00069   bool pauseProcessing;             // pauses processing of new commands, during sending
00070   bool print_newlines;              // Indicates if \r\n should be added after send command
00071   char commandBuffer[MESSENGERBUFFERSIZE]; // Buffer that holds the data
00072   char streamBuffer[MAXSTREAMBUFFERSIZE]; // Buffer that holds the data
00073   uint8_t messageState;             // Current state of message processing
00074   bool dumped;                      // Indicates if last argument has been externally read 
00075   bool ArgOk;                       // Indicated if last fetched argument could be read
00076   char *current;                    // Pointer to current buffer position
00077   char *last;                       // Pointer to previous buffer position
00078   char prevChar;                    // Previous char (needed for unescaping)
00079   Stream *comms;                    // Serial data stream
00080   
00081   char command_separator;           // Character indicating end of command (default: ';')
00082   char field_separator;             // Character indicating end of argument (default: ',')
00083   char escape_character;            // Character indicating escaping of special chars
00084     
00085   messengerCallbackFunction default_callback;            // default callback function  
00086   messengerCallbackFunction callbackList[MAXCALLBACKS];  // list of attached callback functions 
00087   
00088   // ****** Private functions ******   
00089   
00090   // **** Initialize ****
00091   
00092   void init (Stream & comms, const char fld_separator, const char cmd_separator, const char esc_character);
00093   void reset ();
00094   
00095   // **** Command processing ****
00096   
00097   inline uint8_t processLine (char serialChar) __attribute__((always_inline));
00098   inline void handleMessage() __attribute__((always_inline));
00099   inline bool blockedTillReply (unsigned long timeout = DEFAULT_TIMEOUT, int ackCmdId = 1) __attribute__((always_inline));
00100   inline bool CheckForAck (int AckCommand) __attribute__((always_inline));
00101 
00102   // **** Command sending ****
00103    
00107   template < class T > 
00108     void writeBin (const T & value)
00109   {
00110     const byte *bytePointer = (const byte *) (const void *) &value;
00111     for (unsigned int i = 0; i < sizeof (value); i++)
00112       {
00113         printEsc (*bytePointer); 
00114         *bytePointer++;
00115       }
00116   }
00117     
00118   // **** Command receiving ****
00119   
00120   int findNext (char *str, char delim);
00121 
00125   template < class T > 
00126     T readBin (char *str)
00127   {
00128     T value;
00129     unescape (str);
00130     byte *bytePointer = (byte *) (const void *) &value;
00131     for (unsigned int i = 0; i < sizeof (value); i++)
00132       {
00133         *bytePointer = str[i];
00134         *bytePointer++;
00135       }
00136     return value;
00137   }
00138   
00139   // **** Escaping tools ****
00140   
00141   char *split_r (char *str, const char delim, char **nextp);
00142   bool isEscaped (char *currChar, const char escapeChar, char *lastChar);
00143   
00144   void printEsc (char *str);
00145   void printEsc (char str); 
00146   
00147 public:
00148 
00149   // ****** Public functions ******
00150 
00151   // **** Initialization ****
00152   
00153   CmdMessenger (Stream & comms, const char fld_separator = ',', 
00154                 const char cmd_separator = ';', 
00155                 const char esc_character = '/');
00156   
00157   void printLfCr (bool addNewLine=true);
00158   void attach (messengerCallbackFunction newFunction);
00159   void attach (byte msgId, messengerCallbackFunction newFunction);
00160   
00161   // **** Command processing ****
00162   
00163   void feedinSerialData ();
00164   bool next ();
00165   bool available ();
00166   bool isArgOk ();
00167   uint8_t CommandID ();
00168   
00169   // ****  Command sending ****
00170   
00175   template < class T >
00176     bool sendCmd (int cmdId, T arg, bool reqAc = false, int ackCmdId = 1, 
00177                   int timeout = DEFAULT_TIMEOUT)
00178   {
00179     if (!startCommand) {
00180         sendCmdStart (cmdId);
00181         sendCmdArg (arg);
00182         return sendCmdEnd (reqAc, ackCmdId, timeout);
00183     }
00184     return false;
00185   }
00186   
00191   template < class T >
00192     bool sendBinCmd (int cmdId, T arg, bool reqAc = false, int ackCmdId = 1,
00193                      int timeout = DEFAULT_TIMEOUT)
00194   {
00195     if (!startCommand) {
00196         sendCmdStart (cmdId);
00197         sendCmdBinArg (arg);
00198         return sendCmdEnd (reqAc, ackCmdId, timeout);
00199     }
00200     return false;
00201   }
00202 
00203   // **** Command sending with multiple arguments ****
00204   
00205   void sendCmdStart (int cmdId);
00206   void sendCmdEscArg (char *arg);
00207   void sendCmdfArg (char *fmt, ...);
00208   bool sendCmdEnd (bool reqAc = false, int ackCmdId = 1, int timeout = DEFAULT_TIMEOUT);
00209   
00214   template < class T > void sendCmdArg (T arg)
00215   {
00216     if (startCommand)
00217       {
00218         comms->print (field_separator);
00219         comms->print (arg);
00220       }
00221   }
00222   
00227   template < class T > void sendCmdArg (T arg, int n)
00228   {
00229     if (startCommand)
00230       {
00231         comms->print (field_separator);
00232         comms->print (arg, n);
00233       }
00234   }
00235   
00240   template < class T > void sendCmdBinArg (T arg)
00241   {
00242     if (startCommand)
00243       {
00244         comms->print (field_separator);
00245         writeBin (arg);
00246       }
00247   }  
00248 
00249   // **** Command receiving ****
00250   bool readBoolArg();
00251   int readIntArg ();
00252   long readLongArg ();
00253   char readCharArg ();
00254   float readFloatArg ();
00255   char *readStringArg ();
00256   void copyStringArg (char *string, uint8_t size);
00257   uint8_t compareStringArg (char *string);
00258  
00262   template < class T > T readBinArg ()
00263   {
00264     if (next ())
00265       {
00266         dumped = true;
00267         return readBin < T > (current);
00268       }
00269       return (T)0;
00270   }
00271 
00272   // **** Escaping tools ****
00273   
00274   void unescape (char *fromChar);   
00275 };
00276 #endif