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