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
1 Answer 1
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.
-
I have Newline only and it's not working anywaysKIIV– KIIV09/26/2018 20:08:01Commented Sep 26, 2018 at 20:08
-
change the serialEvent to not to attach the \n to the string09/26/2018 20:09:31Commented Sep 26, 2018 at 20:09
-
Right, he's not skipping it in that parser :DKIIV– KIIV09/26/2018 20:15:17Commented Sep 26, 2018 at 20:15
-
Ok, I like your approach, it works!ex080– ex08009/27/2018 16:56:47Commented Sep 27, 2018 at 16:56
set
. I know the set function is working correctly, because if I doSerial.println(key1);
from inside the class it prints the correct value.