ESP8266 получение данных мусора из массива char - PullRequest
0 голосов
/ 08 декабря 2018

Я, честно говоря, растерялся здесь.Я пытаюсь сохранить SSID и пароль, которые пользователь отправляет через почтовый запрос в разделе флэш-ЭСППЗУ.Для этого я конвертирую данные, отправленные из запроса post, в массив char и индексирую их в EEPROM.SSID работает без проблем, но пароль всегда заканчивается ненужными данными, прежде чем он даже попадает в EEPROM.Вот фрагмент кода, о котором идет речь:

// Recieve data from the HTTP server
void changeConfig(String parameter, String value){
  int memoffset = 0;
  if(parameter == "ssid")
    memoffset = 0;
  else if(parameter == "pass")
    memoffset = 32;
  else
    return;
  #ifdef DEBUG
  Serial.println("Updating Data");
  Serial.print("Param: ");
  Serial.println(parameter);
  Serial.print("Value: ");
  Serial.println(value);
  #endif
  EEPROM.begin(64);
  char _data[sizeof(value)];
  value.toCharArray(_data, sizeof(value));
  for(int i = memoffset; i < memoffset + sizeof(value); i++)
  {
    #ifdef DEBUG
      Serial.print("addr ");
      Serial.print(i);
      Serial.print(" data ");
      Serial.println(_data[i]);
      #endif 
      EEPROM.write(i,_data[i]);
  }
  EEPROM.end();
}

И выход последовательного монитора:
Параметр записи: ssid, Значение: имя_сети
Обновление данных
Параметр: ssid
Значение: NetworkName
адрес 0 данных N
адрес 1 данных e
адрес 2 данных t
адрес 3 данных w
адрес 4 данных o
адрес 5 данных r
адрес 6 данныхk
данные addr 7 N
данные addr 8 a
данные addr 9 m
данные addr 10 e
данные addr 11 ␀
параметр Post: pass, значение: Networkpass
Обновление данных
Параметр: pass
Значение: Networkpass
данные addr 32 |
данные addr 33 (
данные addr 34 �
данные addr 35?
данные addr 36 L
данные addr 37 ␛
данные addr 38 �
данные addr 39?
данные addr 40 ␁
данные addr 41 ␀
данные addr 42 ␀
данные addr 43 ␀

Как вы можете видеть, когда имя параметра POST - ssid, оно работает нормально. С другой стороны, с помощью pass массив char просто наполняется бредом. Любое пониманиебыло бы полезно.Я использую platformio в среде Arduino.Универсальный ESP01 с 1М вспышкой.Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 08 декабря 2018

У вас две проблемы с вашим кодом.

Во-первых, вы используете sizeof неправильно.Sizeof возвращает размер объекта String, но вы пытаетесь получить длину содержащейся строки.Sizeof не является подходящим инструментом для этого, вместо этого вы должны использовать все, что API String предлагает для считывания размера строки.

Следующая проблема - использование смещений.Следующий фрагмент кода неверен:

char _data[sizeof(value)];
value.toCharArray(_data, sizeof(value));
for(int i = memoffset; i < memoffset + sizeof(value); i++)
{
  ...
  EEPROM.write(i,_data[i]);

Ваш i начинается со смещения 32, поэтому вы пытаетесь получить доступ к элементу с индексом 32 в вашем массиве _data.Но _data хранит символы, начиная с индекса 0, и поскольку длина массива на самом деле равна 12 (размер String всегда равен 12), получая доступ к элементу с индексом 32, вы выходите за его пределы и, очевидно, находите там мусор (на языке C ++ это называется неопределенным поведением).

И последнее, но не менее важное: C ++ - чрезвычайно сложный язык, который невозможно выучить методом проб и ошибок.Вместо этого вам нужно методично учиться, желательно используя одну из хороших книг по С ++.Список их можно найти здесь: Подробное руководство и список книг C ++

0 голосов
/ 08 декабря 2018

Вы используете sizeof() неправильно.

sizeof() сообщает размер объекта во время компиляции.

Попробуйте этот эксперимент - запуститеэтот код:

#include <Arduino.h>

void setup() {
  String x("");
  String y("abc");
  String z("abcdef");

  Serial.begin(115200);

  delay(1000);

  Serial.println(sizeof(x));
  Serial.println(sizeof(y));
  Serial.println(sizeof(z));
}

void loop() {
}

На моем ESP8266 это выводит:

12
12
12

Это потому, что требуется 12 байтов, используя эту среду разработки для представления String объекта (он может отличаться надругой процессор и компилятор).Класс String динамически распределяет хранилище, поэтому sizeof не может ничего сказать о длине самой строки, только размер объекта во время компиляции.

Для класса String вам следуетиспользуйте метод length().Ваши строки:

char _data[sizeof(value)];
value.toCharArray(_data, sizeof(value));
for(int i = memoffset; i < memoffset + sizeof(value); i++)

должны быть записаны как

char _data[value.length()];
value.toCharArray(_data, value.length());
for(int i = memoffset; i < memoffset + value.length(); i++)

Для получения дополнительной информации см. Документацию для класса String .

You 'Скорее всего, все еще будут проблемы со строковыми ограничителями.C и C ++ заканчивают строки массива char нулевым символом '\ 0', добавляя дополнительный байт к длине строк.Таким образом, ваш код должен быть более вероятным:

void changeConfig(String parameter, String value){
  int memoffset = 0;
  if(parameter == "ssid")
    memoffset = 0;
  else if(parameter == "pass")
    memoffset = 33;
  else
    return;
  #ifdef DEBUG
  Serial.println("Updating Data");
  Serial.print("Param: ");
  Serial.println(parameter);
  Serial.print("Value: ");
  Serial.println(value);
  #endif
  EEPROM.begin(66);
  char _data[value.length() + 1];
  value.toCharArray(_data, value.length() + 1);
  for(int i = memoffset; i < memoffset + value.length() + 1; i++)
  {
    #ifdef DEBUG
      Serial.print("addr ");
      Serial.print(i);
      Serial.print(" data ");
      Serial.println(_data[i]);
      #endif 
      EEPROM.write(i,_data[i]);
  }
  EEPROM.end();
}

, чтобы позволить терминаторам строки работать правильно для 32-символьных идентификаторов SSID и паролей.Но фундаментальная проблема, которая нарушает ваш код, заключается в неправильном использовании sizeof.

...