CmdMessenger
4.0.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 // **** 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