2

I'm working with an arduino UNO. I would like to be able to send it set and get commands over serial and have it update class data class members accordingly by key value pair. I spoke to users in the cpp room, and they suggested I try using map to map every key to value.

command structure command:key:value

ex. set:key1:20 ex. get:key2

I created a class called Uno, assigned all my keys to private data members, and defined set and get functions. However, I am experiencing unintended behavior.

Unintended behavior The set function ends up setting key1 and key2 to the same value, and the get function returns a random integer value that wasn't assigned.

  #include <ArduinoSTL.h>
  #include <string.h>
  #include <map>

class Uno{
  //private
    int key1;
    int key2;
    std::map<String, int Uno::*> keys;
  public:
  //Constructor
    Uno(){
      key1 = 0;
      key2 = 0;
      keys["key1"] = &Uno::key1;
      keys["key2"] = &Uno::key2;
    }
    bool setKey(String key, int value){
      if (keys.count(key)) {
          this->*keys[key] = value;
          return true;
      }
      return false;
    }
    int getKey(String key){
      if (keys.count(key)) {
          return this->*keys[key];
      }
    }
};


String inputString = "";      // a String to hold incoming data
bool stringComplete = false;  // whether the string is complete
bool scan = false;            // whether a scan is in progress
Uno myMS;                      // global declaration of Mass Spec Class

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 250 bytes for the inputString:
  inputString.reserve(250);
}

void loop() {
  if (stringComplete) {
    t(inputString); // tokenize and process string

    //RESET STRING
    inputString = "";
    stringComplete = false;
  }
}


void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag so the main loop can
    // do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}



void t(String inputString) {
    //get command
    String command = getValue(inputString, ':', 0);

    if(command == "set"){
      // get key, get value
       String key = getValue(inputString, ':', 1);
       int value = (getValue(inputString, ':', 2)).toInt();
       Serial.println(myMS.setKey(key,value));
    }
    else if(command == "get"){
       String key = getValue(inputString, ':', 1);
       int value = myMS.getKey(key);
       Serial.println(value);
    }
    else if(command == "stop"){
       scan = false; 
    }
    else if(command == "scan"){
       scan = true;
       while(scan){
//        Serial.println(myMS.scan());
       }
    }
    else{
       Serial.println("not recognized");
    }
}


String getValue(String data, char separator, int index)
{
  int found = 0;
  int strIndex[] = {0, -1};
  int maxIndex = data.length()-1;

  for(int i=0; i<=maxIndex && found<=index; i++){
    if(data.charAt(i)==separator || i==maxIndex){
        found++;
        strIndex[0] = strIndex[1]+1;
        strIndex[1] = (i == maxIndex) ? i+1 : i;
    }
  }
  return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}

EDIT: Here is a REPL IT working demo of concept provided by nwp. https://repl.it/repls/AntiqueProductiveMineral

Sample output

set:key1:10 ===> 1 (GOOD)
get:key1 ===> 32512
ex080
  • 23
  • 1
  • 5

1 Answers1

3

You get random values because if the key is not found in getKey, then there is no return statement.

You attach the \n to the key in serialEvent(), then the key for getKey is "key1\n" and it is not found.

void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    if (inChar == '\n') {
      stringComplete = true;
    } else {
      inputString += inChar;
    }
  }
}

If you have CR/LF set in Serial Monitor, then the \r character is send too and the parsed key is "key1\r\n".

There are obsolete things in your code, like the this->* or Uno::. Make the map std::map<String, int> keys;, because now you mix pointers and ints.

Juraj
  • 18,264
  • 4
  • 31
  • 49