Ошибка разбора ArduinoJson при чтении строки из EEPROM

Прежде чем кто-то пометит это как дубликат, я нашел эти две ссылки, и ни одна из них не применима полностью, хотя я реализовал по крайней мере часть из них.

Буфер перезаписывается

Arduino читает json из EEPROM / конвертирует uint8_t в char

Моя проблема вот в чем. Я пытаюсь прочитать и записать строку JSON в EEPROM Arduinos с помощью библиотеки ArduinoJson (https://github.com/bblanchon/ArduinoJson). В приведенном ниже коде я генерирую JsonObject из жестко закодированной строки JSON (это работает). Затем я записываю его в EEPROM (это работает). Затем он считывается из EEPROM (это работает), но когда я пытаюсь проанализировать вторую строку с помощью ArduinoJSON, я получаю сбой синтаксического анализа.

В целях тестирования я также очищаю EEPROM каждый раз на всякий случай, хотя со временем это будет удалено.

Код компилируется без ошибок. Я надеюсь, что кто-то более сведущий в C ++, чем я, заметит что-то действительно очевидное. Я компилирую это на NodeMCU (esp8266).

#include <ArduinoJson.h>
#include <EEPROM.h>

StaticJsonBuffer<400> jsonBuffer;
JsonObject *jsonObject;
JsonObject *config;

String dummyJson = "{\"name\":\"RGB LED 1\",\"io\":[\"pwm1\",\"pwm2\",\"pwm3\"],\"io_type\":\"output\",\"device\":\"pwm_output\",\"uuid\":\"5a81f424aaf8d1e951ae78d270668337\",\"ip\":\"255.255.255.255\"}";

void setup()
{
  Serial.begin(9600);
  while (!Serial)
  {
    continue;
  }
  EEPROM.begin(512);

  Serial.println("\n\n");
  clearEEPROM();
  createDummyJsonObject();
  writeJsonToEEPROM();
  readJsonFromEEPROM();
}

void createDummyJsonObject()
{
  jsonObject = &jsonBuffer.parseObject(dummyJson);
  if (!jsonObject->success())
  {
    Serial.println("jsonBuffer.parseObject() failed");
    return;
  }
  else
  {
    Serial.println("JSON object generated from dummy string");
    jsonObject->prettyPrintTo(Serial);
    Serial.println("\n\n");
  }
}

void loop()
{
  // not used
}

void clearEEPROM()
{
  for (int i = 0; i < 512 + 1; i++)
  {
    EEPROM.write(i, 0);
  }
  EEPROM.commit();
}

void writeJsonToEEPROM()
{
  String jsonStr;
  jsonObject->printTo(jsonStr);

  for (int i = 0; i < jsonStr.length(); ++i)
  {
    EEPROM.write(i, jsonStr[i]);
  }

  EEPROM.write(jsonStr.length(), byte(0));
  EEPROM.commit();
}

void readJsonFromEEPROM()
{
  String jsonStr;

  for (int i = 0; i < 512; ++i)
  {
    char c = char(EEPROM.read(i));
    if (c != 0)
    {
      jsonStr += c;
      delay(1);
    }
    else
    {
      break;
    }
  }
  Serial.println(jsonStr);

  char charBuf[jsonStr.length()];
  jsonStr.toCharArray(charBuf, jsonStr.length());
  config = &jsonBuffer.parseObject(charBuf);

  if (!config->success())
  {
    Serial.println("jsonObject.parseObject() failed ");
    return;
  }
  else
  {
    // Never reaches this point! 
    Serial.println("\nJSON object generated from EEPROM data");
    config->prettyPrintTo(Serial);
    Serial.println("\n\n");
  }
}

person Noel Drew    schedule 10.07.2018    source источник


Ответы (2)


Размер, выделенный для charBuf, должен быть jsonStr.length() + 1, потому что вам нужно место для признака конца строки. Поэтому вы также должны добавить что-то вроде charBuf[jsonStr.length()] = '\0';, чтобы предоставить этот терминатор строки:

int const jsonStringLengh = jsonStr.length();
char charBuf[jsonStringLengh + 1];
jsonStr.toCharArray(charBuf, jsonStringLengh);
charBuf[jsonStringLengh] = '\0';
person Adrian W    schedule 10.07.2018
comment
Ах хорошо, спасибо за это. Я добавил это, но все равно не повезло. Я сделал правильные изменения? char charBuf[jsonStr.length() + 1]; jsonStr.toCharArray(charBuf, jsonStr.length() + 1); charBuf[jsonStr.length()] = '\0'; - person Noel Drew; 11.07.2018
comment
Буферу требуется на один байт больше, который должен быть установлен в '\0'. Количество символов, которые вы вводите в toCharArray(), не меняется. Я обновил ответ, чтобы прояснить это. И действительно, невозможно отформатировать комментарии для правильного отображения кода. - person Adrian W; 11.07.2018
comment
АааааааааааааааааааааааЯ Спасибо. Я думаю, что меня смущало количество символов для копирования и индекс массива, в который нужно писать. Я на самом деле решил это, создав еще один StaticJsonBuffer (я могу только предположить, что они очищаются после использования), но я кое-что узнал о строках и массивах символов, поэтому спасибо - person Noel Drew; 11.07.2018

Хорошо, так что это решило это. Все, что мне нужно было сделать, это создать новый StaticJsonBuffer для анализа второй строки. Для тех, у кого есть аналогичная проблема, вот рабочий код.

    #include <ArduinoJson.h>
#include <EEPROM.h>

StaticJsonBuffer<512> jsonBuffer;
JsonObject *jsonObject;
JsonObject *config;

String dummyJson = "{\"name\":\"RGB LED 1\",\"io\":[\"pwm1\",\"pwm2\",\"pwm3\"],\"io_type\":\"output\",\"device\":\"pwm_output\",\"uuid\":\"5a81f424aaf8d1e951ae78d270668337\",\"ip\":\"255.255.255.255\"}";

void setup()
{
  Serial.begin(9600);
  while (!Serial)
  {
    continue;
  }
  EEPROM.begin(512);

  clearEEPROM();
  createDummyJsonObject();
  writeJsonToEEPROM();
  readJsonFromEEPROM();
}

void createDummyJsonObject()
{
  jsonObject = &jsonBuffer.parseObject(dummyJson);
  if (!jsonObject->success())
  {
    Serial.println("jsonBuffer.parseObject() failed");
    return;
  }
  else
  {
    Serial.println("JSON object generated from dummy string");
  }
}

void loop()
{
  // not used
}

void clearEEPROM()
{
  for (int i = 0; i < 512 + 1; i++)
  {
    EEPROM.write(i, 0);
  }
  EEPROM.commit();
}

void writeJsonToEEPROM()
{
  String jsonStr;
  jsonObject->printTo(jsonStr);
  for (int i = 0; i < jsonStr.length(); ++i)
  {
    EEPROM.write(i, jsonStr[i]);
  }
  EEPROM.write(jsonStr.length(), byte(0));
  EEPROM.commit();
}

void readJsonFromEEPROM()
{
  String jsonStr;
  for (int i = 0; i < 512; ++i)
  {
    char c = char(EEPROM.read(i));
    if (c != 0)
    {
      jsonStr += c;
      delay(1);
    }
    else
    {
      break;
    }
  }

  StaticJsonBuffer<512> jsonBuffer2;
  config = &jsonBuffer2.parseObject(jsonStr);
  if (!config->success())
  {
    Serial.println("jsonObject.parseObject() failed ");
    return;
  }
  else
  {
    Serial.println("\nJSON object generated from EEPROM data");
    config->prettyPrintTo(Serial);
    Serial.println("\n\n");
  }
}
person Noel Drew    schedule 11.07.2018