Arduino std::map, возвращающий случайные значения

c++ map

Я работаю с Arduino UNO. Я хотел бы иметь возможность отправлять ему команды set и get через последовательный порт и обновлять члены класса данных класса соответственно по паре значений ключа. Я разговаривал с пользователями в комнате cpp, и они предложили мне попробовать использовать карту для сопоставления каждого ключа со значением.

структура команды команда:ключ:значение

пр. set:key1:20 бывший. get:key2

Я создал класс Uno, назначил все свои ключи частным членам данных и определил функции set и get. Однако у меня наблюдается непредвиденное поведение.

Непреднамеренное поведение В конечном итоге функция set устанавливает для key1 и key2 одно и то же значение, а функция get возвращает случайное целочисленное значение, которое не было присвоено.

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

class Uno{
  //частный
    int key1;
    int key2;
    std::map<String, int Uno::*> keys;
  public:
  //Конструктор
    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 = "";      // строка для хранения входящих данных
bool stringComplete = false;  // является ли строка полной
bool scan = false;            // выполняется ли сканирование
Uno myMS;                      // глобальное объявление класса Mass Spec

void setup() {
  // инициализируем серийный номер:
  Serial.begin(9600);
  // резервируем 250 байт для входной строки:
  inputString.reserve(250);
}

void loop() {
  if (stringComplete) {
    t(inputString); // токенизация и обработка строки

    //СБРОС СТРОКИ
    inputString = "";
    stringComplete = false;
  }
}


void serialEvent() {
  while (Serial.available()) {
    // получаем новый байт:
    char inChar = (char)Serial.read();
    // добавляем его во входную строку:
    inputString += inChar;
    // если входящий символ является новой строкой, установите флаг, чтобы основной цикл мог
    // делаем что-нибудь с этим:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}



void t(String inputString) {
    //получить команду
    String command = getValue(inputString, ':', 0);

    if(command == "set"){
      // получаем ключ, получаем значение
       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]) : "";
}

РЕДАКТИРОВАТЬ: Вот рабочая демонстрация концепции REPL IT, предоставленная nwp. https://repl.it/repls/AntiqueProductiveMineral

Пример вывода

set:key1:10 ===> 1 (GOOD)
get:key1 ===> 32512

, 👍2

Обсуждение

почему вы думаете, что это вопрос Arduino? ... похоже, это вопрос C/C++, @jsotola

@jsotola Это вопрос об Arduino, потому что я запускаю код на Arduino, используя тип String arduino. Я также использую Serial на Arduino. Я открыт для других методов Arduino для хранения пар ключ-значение., @ex080

32512 — это возвращаемое значение getKey, если он не нашел ключ, @Juraj

Хорошо, но это сбивает с толку, потому что я использую тот же метод для установки. Я знаю, что функция set работает правильно, потому что если я выполню Serial.println(key1); изнутри класса, она напечатает правильное значение., @ex080


1 ответ


Лучший ответ:

3

Вы получаете случайные значения, потому что, если ключ не найден в getKey, оператор возврата отсутствует.

Вы прикрепляете \n к ключу в SerialEvent(), тогда ключом для getKey является «key1\n», и он не найден.

void serialEvent() {
  while (Serial.available()) {
    // получаем новый байт:
    char inChar = (char)Serial.read();
    if (inChar == '\n') {
      stringComplete = true;
    } else {
      inputString += inChar;
    }
  }
}

Если в последовательном мониторе установлен CR/LF, то также отправляется символ \r и анализируемый ключ — «key1\r\n».

В вашем коде есть устаревшие элементы, например this->* или Uno::. Создайте карту std::map<String, int> клавиши;, потому что теперь вы смешиваете указатели и целые числа.

,

У меня есть только Newline, и он все равно не работает, @KIIV

измените серийное событие, чтобы не прикреплять \n к строке, @Juraj

Да, он не пропускает это в этом парсере :D, @KIIV

Хорошо, мне нравится ваш подход, он работает!, @ex080