00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 extern "C" {
00045 #include <stdlib.h>
00046 #include <stdarg.h>
00047 }
00048 #include <stdio.h>
00049 #include <CmdMessenger.h>
00050
00051 #define _CMDMESSENGER_VERSION 3_6 // software version of this library
00052
00053
00054
00058 CmdMessenger::CmdMessenger(Stream &ccomms, const char fld_separator, const char cmd_separator, const char esc_character)
00059 {
00060 init(ccomms,fld_separator,cmd_separator, esc_character);
00061 }
00062
00066 void CmdMessenger::init(Stream &ccomms, const char fld_separator, const char cmd_separator, const char esc_character)
00067 {
00068 default_callback = NULL;
00069 comms = &ccomms;
00070 print_newlines = false;
00071 field_separator = fld_separator;
00072 command_separator = cmd_separator;
00073 escape_character = esc_character;
00074 bufferLength = MESSENGERBUFFERSIZE;
00075 bufferLastIndex = MESSENGERBUFFERSIZE -1;
00076 reset();
00077
00078 default_callback = NULL;
00079 for (int i = 0; i < MAXCALLBACKS; i++)
00080 callbackList[i] = NULL;
00081
00082 pauseProcessing = false;
00083 }
00084
00088 void CmdMessenger::reset()
00089 {
00090 bufferIndex = 0;
00091 current = NULL;
00092 last = NULL;
00093 dumped = true;
00094 }
00095
00099 void CmdMessenger::printLfCr(bool addNewLine)
00100 {
00101 print_newlines = addNewLine;
00102 }
00103
00107 void CmdMessenger::attach(messengerCallbackFunction newFunction)
00108 {
00109 default_callback = newFunction;
00110 }
00111
00115 void CmdMessenger::attach(byte msgId, messengerCallbackFunction newFunction)
00116 {
00117 if (msgId >= 0 && msgId < MAXCALLBACKS)
00118 callbackList[msgId] = newFunction;
00119 }
00120
00121
00122
00126 void CmdMessenger::feedinSerialData()
00127 {
00128 while ( !pauseProcessing && comms->available() )
00129 {
00130
00131
00132
00133 size_t bytesAvailable = min(comms->available(),MAXSTREAMBUFFERSIZE);
00134 comms->readBytes(streamBuffer, bytesAvailable);
00135
00136
00137 for (size_t byteNo = 0; byteNo < bytesAvailable ; byteNo++)
00138 {
00139 int messageState = processLine(streamBuffer[byteNo]);
00140
00141
00142 if ( messageState == kEndOfMessage )
00143 {
00144 handleMessage();
00145 }
00146 }
00147 }
00148 }
00149
00153 uint8_t CmdMessenger::processLine(char serialChar)
00154 {
00155 messageState = kProccesingMessage;
00156
00157 bool escaped = isEscaped(&serialChar,escape_character,&CmdlastChar);
00158 if((serialChar == command_separator) && !escaped) {
00159 commandBuffer[bufferIndex]=0;
00160 if(bufferIndex > 0) {
00161 messageState = kEndOfMessage;
00162 current = commandBuffer;
00163 CmdlastChar='\0';
00164 }
00165 reset();
00166 } else {
00167 commandBuffer[bufferIndex]=serialChar;
00168 bufferIndex++;
00169 if (bufferIndex >= bufferLastIndex) reset();
00170 }
00171 return messageState;
00172 }
00173
00177 void CmdMessenger::handleMessage()
00178 {
00179 lastCommandId = readInt16Arg();
00180
00181 if (lastCommandId >= 0 && lastCommandId < MAXCALLBACKS && ArgOk && callbackList[lastCommandId] != NULL)
00182 (*callbackList[lastCommandId])();
00183 else
00184 if (default_callback!=NULL) (*default_callback)();
00185 }
00186
00190 bool CmdMessenger::blockedTillReply(unsigned long timeout, int ackCmdId)
00191 {
00192 unsigned long time = millis();
00193 unsigned long start = time;
00194 bool receivedAck = false;
00195 while( (time - start ) < timeout && !receivedAck) {
00196 time = millis();
00197 receivedAck = CheckForAck(ackCmdId);
00198 }
00199 return receivedAck;
00200 }
00201
00205 bool CmdMessenger::CheckForAck(int AckCommand)
00206 {
00207 while ( comms->available() ) {
00208
00209 int messageState = processLine(comms->read());
00210 if ( messageState == kEndOfMessage ) {
00211 int id = readInt16Arg();
00212 if (AckCommand==id && ArgOk) {
00213 return true;
00214 } else {
00215 return false;
00216 }
00217 }
00218 return false;
00219 }
00220 return false;
00221 }
00222
00226 bool CmdMessenger::next()
00227 {
00228 char * temppointer= NULL;
00229
00230 switch (messageState) {
00231 case kProccesingMessage:
00232 return false;
00233 case kEndOfMessage:
00234 temppointer = commandBuffer;
00235 messageState = kProcessingArguments;
00236 default:
00237 if (dumped)
00238 current = split_r(temppointer,field_separator,&last);
00239 if (current != NULL) {
00240 dumped = true;
00241 return true;
00242 }
00243 }
00244 return false;
00245 }
00246
00250 bool CmdMessenger::available()
00251 {
00252 return next();
00253 }
00254
00258 bool CmdMessenger::isArgOk ()
00259 {
00260 return ArgOk;
00261 }
00262
00266 uint8_t CmdMessenger::CommandID()
00267 {
00268 return lastCommandId;
00269 }
00270
00271
00272
00276 void CmdMessenger::sendCmdStart(int cmdId)
00277 {
00278 if (!startCommand) {
00279 startCommand = true;
00280 pauseProcessing = true;
00281 comms->print(cmdId);
00282 }
00283 }
00284
00288 void CmdMessenger::sendCmdEscArg(char* arg)
00289 {
00290 if (startCommand) {
00291 comms->print(field_separator);
00292 printEsc(arg);
00293 }
00294 }
00295
00300 void CmdMessenger::sendCmdfArg(char *fmt, ...)
00301 {
00302 const int maxMessageSize = 128;
00303 if (startCommand) {
00304 char msg[maxMessageSize];
00305 va_list args;
00306 va_start (args, fmt );
00307 vsnprintf(msg, maxMessageSize, fmt, args);
00308 va_end (args);
00309
00310 comms->print(field_separator);
00311 comms->print(msg);
00312 }
00313 }
00314
00319 void CmdMessenger::sendCmdSciArg (double arg, int n)
00320 {
00321 if (startCommand)
00322 {
00323 comms->print (field_separator);
00324 printSci (arg, n);
00325 }
00326 }
00327
00331 bool CmdMessenger::sendCmdEnd(bool reqAc, int ackCmdId, int timeout)
00332 {
00333 bool ackReply = false;
00334 if (startCommand) {
00335 comms->print(command_separator);
00336 if(print_newlines)
00337 comms->println();
00338 if (reqAc) {
00339 ackReply = blockedTillReply(timeout, ackCmdId);
00340 }
00341 }
00342 pauseProcessing = false;
00343 startCommand = false;
00344 return ackReply;
00345 }
00346
00350 bool CmdMessenger::sendCmd (int cmdId, bool reqAc, int ackCmdId)
00351 {
00352 if (!startCommand) {
00353 sendCmdStart (cmdId);
00354 return sendCmdEnd (reqAc, ackCmdId, DEFAULT_TIMEOUT);
00355 }
00356 return false;
00357 }
00358
00362 bool CmdMessenger::sendCmd (int cmdId)
00363 {
00364 if (!startCommand) {
00365 sendCmdStart (cmdId);
00366 return sendCmdEnd (false, 1, DEFAULT_TIMEOUT);
00367 }
00368 return false;
00369 }
00370
00371
00372
00376 int CmdMessenger::findNext(char *str, char delim)
00377 {
00378 int pos = 0;
00379 bool escaped = false;
00380 bool EOL = false;
00381 ArglastChar = '\0';
00382 while (true) {
00383 escaped = isEscaped(str,escape_character,&ArglastChar);
00384 EOL = (*str == '\0' && !escaped);
00385 if (EOL) {
00386 return pos;
00387 }
00388 if (*str==field_separator && !escaped) {
00389 return pos;
00390 } else {
00391 str++;
00392 pos++;
00393 }
00394 }
00395 return pos;
00396 }
00397
00401 int16_t CmdMessenger::readInt16Arg()
00402 {
00403 if (next()) {
00404 dumped = true;
00405 ArgOk = true;
00406 return atoi(current);
00407 }
00408 ArgOk = false;
00409 return 0;
00410 }
00411
00415 int32_t CmdMessenger::readInt32Arg()
00416 {
00417 if (next()) {
00418 dumped = true;
00419 ArgOk = true;
00420 return atol(current);
00421 }
00422 ArgOk = false;
00423 return 0L;
00424 }
00425
00429 bool CmdMessenger::readBoolArg()
00430 {
00431 return (readInt16Arg()!=0)?true:false;
00432 }
00433
00437 char CmdMessenger::readCharArg()
00438 {
00439 if (next()) {
00440 dumped = true;
00441 ArgOk = true;
00442 return current[0];
00443 }
00444 ArgOk = false;
00445 return 0;
00446 }
00447
00451 float CmdMessenger::readFloatArg()
00452 {
00453 if (next()) {
00454 dumped = true;
00455 ArgOk = true;
00456
00457 return strtod(current,NULL);
00458 }
00459 ArgOk = false;
00460 return 0;
00461 }
00462
00466 double CmdMessenger::readDoubleArg()
00467 {
00468 if (next()) {
00469 dumped = true;
00470 ArgOk = true;
00471 return strtod(current,NULL);
00472 }
00473 ArgOk = false;
00474 return 0;
00475 }
00476
00481 char* CmdMessenger::readStringArg()
00482 {
00483 if (next()) {
00484 dumped = true;
00485 ArgOk = true;
00486 return current;
00487 }
00488 ArgOk = false;
00489 return '\0';
00490 }
00491
00496 void CmdMessenger::copyStringArg(char *string, uint8_t size)
00497 {
00498 if (next()) {
00499 dumped = true;
00500 ArgOk = true;
00501 strlcpy(string,current,size);
00502 } else {
00503 ArgOk = false;
00504 if ( size ) string[0] = '\0';
00505 }
00506 }
00507
00511 uint8_t CmdMessenger::compareStringArg(char *string)
00512 {
00513 if (next()) {
00514 if ( strcmp(string,current) == 0 ) {
00515 dumped = true;
00516 ArgOk = true;
00517 return 1;
00518 } else {
00519 ArgOk = false;
00520 return 0;
00521 }
00522 }
00523 return 0;
00524 }
00525
00526
00527
00532 void CmdMessenger::unescape(char *fromChar)
00533 {
00534
00535 char *toChar = fromChar;
00536 while (*fromChar != '\0') {
00537 if (*fromChar==escape_character) {
00538 fromChar++;
00539 }
00540 *toChar++=*fromChar++;
00541 }
00542
00543 for (; toChar<fromChar; toChar++) {
00544 *toChar='\0';
00545 }
00546 }
00547
00552 char* CmdMessenger::split_r(char *str, const char delim, char **nextp)
00553 {
00554 char *ret;
00555
00556 if (str == NULL) {
00557 str = *nextp;
00558 }
00559
00560 while (findNext(str, delim)==0 && *str) {
00561 str++;
00562 }
00563
00564 if (*str == '\0') {
00565 return NULL;
00566 }
00567
00568 ret = str;
00569
00570 str += findNext(str, delim);
00571
00572 if (*str) {
00573 *str++ = '\0';
00574 }
00575
00576 *nextp = str;
00577
00578 return ret;
00579 }
00580
00584 bool CmdMessenger::isEscaped(char *currChar, const char escapeChar, char *lastChar)
00585 {
00586 bool escaped;
00587 escaped = (*lastChar==escapeChar);
00588 *lastChar = *currChar;
00589
00590
00591 if (*lastChar == escape_character && escaped) {
00592 *lastChar = '\0';
00593 }
00594 return escaped;
00595 }
00596
00600 void CmdMessenger::printEsc(char *str)
00601 {
00602 while (*str != '\0') {
00603 printEsc(*str++);
00604 }
00605 }
00606
00610 void CmdMessenger::printEsc(char str)
00611 {
00612 if (str==field_separator || str==command_separator || str==escape_character || str=='\0') {
00613 comms->print(escape_character);
00614 }
00615 comms->print(str);
00616 }
00617
00621 void CmdMessenger::printSci(double f, unsigned int digits)
00622 {
00623
00624 if (f < 0.0)
00625 {
00626 Serial.print('-');
00627 f = -f;
00628 }
00629
00630
00631 if (isinf(f))
00632 {
00633 Serial.print("INF");
00634 return;
00635 }
00636
00637 if (isnan(f))
00638 {
00639 Serial.print("NaN");
00640 return;
00641 }
00642
00643
00644 if (digits > 6) digits = 6;
00645 long multiplier = pow(10, digits);
00646
00647 int exponent;
00648 if (abs(f) < 10.0) {
00649 exponent = 0;
00650 } else {
00651 exponent = int(log10(f));
00652 }
00653 float g = f / pow(10, exponent);
00654 if ((g < 1.0) && (g != 0.0))
00655 {
00656 g *= 10;
00657 exponent--;
00658 }
00659
00660 long whole = long(g);
00661 long part = long((g-whole)*multiplier+0.5);
00662
00663 if (part == 100) {
00664 whole++;
00665 part = 0;
00666 }
00667 char format[16];
00668 sprintf(format, "%%ld.%%0%dldE%%+d", digits);
00669 char output[16];
00670 sprintf(output,format, whole, part, exponent);
00671 comms->print(output);
00672 }