// *** CommandMessengerTest *** // This project runs unit tests on several parts on the mayor parts of the CmdMessenger library // Note that the primary function is not to serve as an example, so the code may be less documented // and clean than the example projects. #include <CmdMessenger.h> // CmdMessenger char field_separator = ','; char command_separator = ';'; char escape_separator = '/'; // Blinking led variables unsigned long previousToggleLed = 0; // Last time the led was toggled bool ledState = 0; // Current state of Led const int kBlinkLed = 13; // Pin of internal Led int seriesLength; int seriesLengthCount; // Attach a new CmdMessenger object to the default Serial port CmdMessenger cmdMessenger = CmdMessenger(Serial, field_separator, command_separator); // ------------------ C M D L I S T I N G ( T X / R X ) --------------------- // We can define up to a default of 50 cmds total, including both directions (send + receive) // and including also the first 4 default command codes for the generic error handling. // If you run out of message slots, then just increase the value of MAXCALLBACKS in CmdMessenger.h // This is the list of recognized commands. These can be commands that can either be sent or received. // In order to receive, attach a callback function to these events // // Note that commands work both directions: // - All commands can be sent // - Commands that have callbacks attached can be received // // This means that both sides should have an identical command list: // both sides can either send it or receive it (or even both) enum { // General commands kCommError , // Command reports serial port comm error (only works for some comm errors) kComment , // Command to sent comment in argument // Setup connection test kAcknowledge , // Command to acknowledge that cmd was received kAreYouReady , // Command to ask if other side is ready kError , // Command to report errors // Acknowledge test kAskUsIfReady , // Command to ask other side to ask if ready kYouAreReady , // Command to acknowledge that other is ready // Clear & Binary text data test kValuePing , // Command to send value to other side kValuePong , // Command to return value received with pong // Multiple Arguments test kMultiValuePing , // Command to send value to other side kMultiValuePong , // Command to return value received with pong // Benchmarks kRequestReset , // Command Request reset kRequestResetAcknowledge , // Command to acknowledge reset kRequestSeries , // Command Request to send series in plain text kReceiveSeries , // Command to send an item in plain text kDoneReceiveSeries, kPrepareSendSeries , // Command to tell other side to prepare for receiving a series of text float commands kSendSeries , // Command to send a series of text float commands kAckSendSeries , // Command to acknowledge the send series of text float commands }; // Needed for ping-pong function enum { kBool, kInt16, kInt32, kFloat, kFloatSci, kDouble, kDoubleSci, kChar, kString, kBBool, kBInt16, kBInt32, kBFloat, kBDouble, kBChar, kEscString, }; void attachCommandCallbacks() { // Attach callback methods //cmdMessenger.attach(OnUnknownCommand); cmdMessenger.attach(kAreYouReady, OnArduinoReady); cmdMessenger.attach(kAskUsIfReady, OnAskUsIfReady); // Clear & Binary text data test cmdMessenger.attach(kValuePing, OnValuePing); cmdMessenger.attach(kMultiValuePing, OnMultiValuePing); // Benchmarks cmdMessenger.attach(OnUnknownCommand); cmdMessenger.attach(kRequestReset, OnRequestReset); cmdMessenger.attach(kRequestSeries, OnRequestSeries); cmdMessenger.attach(kPrepareSendSeries, OnPrepareSendSeries); cmdMessenger.attach(kSendSeries, OnSendSeries); } // ------------------ C A L L B A C K S ----------------------- void OnArduinoReady() { // In response to ping. We just send a throw-away Acknowledgment to say "i'm ready" cmdMessenger.sendCmd(kAcknowledge,"Arduino ready"); } void OnUnknownCommand() { // Default response for unknown commands and corrupt messages cmdMessenger.sendCmd(kError,"Unknown command"); cmdMessenger.sendCmdStart(kYouAreReady); cmdMessenger.sendCmdArg("Command without attached callback"); cmdMessenger.sendCmdArg(cmdMessenger.CommandID()); cmdMessenger.sendCmdEnd(); } void OnAskUsIfReady() { // The other side asks us to send kAreYouReady command, wait for //acknowledge int isAck = cmdMessenger.sendCmd(kAreYouReady, "Asking PC if ready", true, kAcknowledge,1000 ); // Now we send back whether or not we got an acknowledgments cmdMessenger.sendCmd(kYouAreReady,isAck?1:0); } void OnValuePing() { int dataType = cmdMessenger.readInt16Arg(); switch (dataType) { // Plain text case kBool: { bool value = cmdMessenger.readBoolArg(); cmdMessenger.sendCmd(kValuePong, value); break; } case kInt16: { int value = cmdMessenger.readInt16Arg(); cmdMessenger.sendCmd(kValuePong, value); break; } case kInt32: { long value = cmdMessenger.readInt32Arg(); cmdMessenger.sendCmd(kValuePong, value); break; } case kFloat: { float value = cmdMessenger.readFloatArg(); cmdMessenger.sendCmd(kValuePong, value); break; } case kDouble: { double value = cmdMessenger.readDoubleArg(); cmdMessenger.sendCmd(kValuePong, value); break; } case kChar: { char value = cmdMessenger.readCharArg(); cmdMessenger.sendCmd(kValuePong, value); break; } case kString: { char * value = cmdMessenger.readStringArg(); cmdMessenger.sendCmd(kValuePong, value); break; } // Binary values case kBBool: { bool value = cmdMessenger.readBinArg<bool>(); cmdMessenger.sendBinCmd(kValuePong, value); break; } case kBInt16: { int16_t value = cmdMessenger.readBinArg<int16_t>(); cmdMessenger.sendBinCmd(kValuePong, value); break; } case kBInt32: { int32_t value = cmdMessenger.readBinArg<int32_t>(); cmdMessenger.sendBinCmd(kValuePong, value); break; } case kBFloat: { float value = cmdMessenger.readBinArg<float>(); cmdMessenger.sendBinCmd(kValuePong, value); break; } case kFloatSci: { float value = cmdMessenger.readFloatArg(); cmdMessenger.sendCmdStart(kValuePong); cmdMessenger.sendCmdSciArg(value,2); cmdMessenger.sendCmdEnd(); break; } case kBDouble: { double value = cmdMessenger.readBinArg<double>(); cmdMessenger.sendBinCmd(kValuePong, value); break; } case kDoubleSci: { double value = cmdMessenger.readDoubleArg(); cmdMessenger.sendCmdStart(kValuePong); cmdMessenger.sendCmdSciArg(value,4); cmdMessenger.sendCmdEnd(); break; } case kBChar: { char value = cmdMessenger.readBinArg<char>(); cmdMessenger.sendBinCmd(kValuePong, value); break; } case kEscString: { char * value = cmdMessenger.readStringArg(); cmdMessenger.unescape(value); cmdMessenger.sendCmdStart(kValuePong); cmdMessenger.sendCmdEscArg(value); cmdMessenger.sendCmdEnd(); break; } default: cmdMessenger.sendCmd(kError,"Unsupported type for valuePing!"); break; } } void OnMultiValuePing() { int16_t valueInt16 = cmdMessenger.readBinArg<int16_t>(); int32_t valueInt32 = cmdMessenger.readBinArg<int32_t>(); double valueDouble = cmdMessenger.readBinArg<double>(); cmdMessenger.sendCmdStart(kMultiValuePong); cmdMessenger.sendCmdBinArg(valueInt16); cmdMessenger.sendCmdBinArg(valueInt32); cmdMessenger.sendCmdBinArg(valueDouble); cmdMessenger.sendCmdEnd(); } //--------------- Benchmarks ---------------------- void OnRequestReset() { seriesLengthCount = 0; cmdMessenger.sendCmd(kRequestResetAcknowledge,""); } // Callback function calculates the sum of the two received float values void OnRequestSeries() { // Get series length from 1st parameter int seriesLength = cmdMessenger.readInt16Arg(); float seriesBase = cmdMessenger.readFloatArg(); // Send back series of floats for(int i=0;i< seriesLength;i++) { cmdMessenger.sendCmdStart (kReceiveSeries); cmdMessenger.sendCmdArg<float>(((float)i*(float)seriesBase),6); cmdMessenger.sendCmdEnd (); } cmdMessenger.sendCmd(kDoneReceiveSeries,""); } void OnPrepareSendSeries() { seriesLength = cmdMessenger.readInt16Arg(); seriesLengthCount = 0; } void OnSendSeries() { seriesLengthCount++; //float seriesBase = cmdMessenger.readFloatArg(); if (seriesLengthCount == seriesLength) { cmdMessenger.sendCmd(kAckSendSeries,""); } } // ------------------ M A I N ( ) ---------------------- void setup() { // Listen on serial connection for messages from the pc //Serial.begin(57600); // Arduino Duemilanove, FTDI Serial // 115200 is the max speed on Arduino Uno, Mega, with AT8u2 USB // SERIAL_8N1 is the default config, but we want to make certain // that we have 8 bits to our disposal Serial.begin(115200); // Makes output more readable whilst debugging in Arduino Serial Monitor, // but uses more bytes cmdMessenger.printLfCr(); // Attach my application's user-defined callback methods attachCommandCallbacks(); // Set command to PC to say we're ready //OnArduinoReady(); cmdMessenger.sendCmd(kAcknowledge,"Arduino has resetted!"); // set pin for blink LED pinMode(kBlinkLed, OUTPUT); } bool hasExpired(unsigned long &prevTime, unsigned long interval) { if ( millis() - prevTime > interval ) { prevTime = millis(); return true; } else return false; } void loop() { // Process incoming serial data, and perform callbacks cmdMessenger.feedinSerialData(); // toggle LED. If the LED does not toggle every timeoutInterval, // this means the callbacks my the Messenger are taking a longer time than that if (hasExpired(previousToggleLed,2000)) // Every 2 secs { toggleLed(); } } // Toggle led state void toggleLed() { ledState = !ledState; digitalWrite(kBlinkLed, ledState?HIGH:LOW); }