Как изменить const char*

В верхней части моего скетча arduino у меня есть следующее :

// softAp
const char *softApSsid = "abcdefg";
const char *softApPassword = "123456";

Это SSID и пароль по умолчанию для подключения к мягкой точке доступа. Soft AP запускается в setup (), например :

WiFi.softAP(softApSsid, softApPassword);

согласно репо github, эта функция действительно требует "const char*" в качестве параметров (источник: https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/src/ESP8266WiFiAP.cpp#L97)

Далее в моем скетче я хочу позволить пользователю редактировать ssid и пароль. Я написал функцию, которая считывает первый байт eeprom. Если он равен 255, мы используем учетные данные по умолчанию, если он равен 1, это означает, что пользователь установил пользовательские учетные данные, поэтому мы будем использовать их для создания мягкой точки доступа.

Я написал вот что :

void getSoftApAuth() {
  bool isDefaultSoftApAuth = 255 == EEPROM.read(0);

  if (! isDefaultSoftApAuth) {
    softApSsid = "";
    softApPassword = "";

    int i = 1;
    while ('\0' != EEPROM.read(i)) {
      softApSsid += char(EEPROM.read(i));
      i++;
    }

    i = 65;
    while ('\0' != EEPROM.read(i)) {
      softApPassword += char(EEPROM.read(i));
      i++;
    }
  }
}

void setSoftApAuth(const char* ssid, const char* passphrase) {
  EEPROM.write(0, 1);

  // ssid
  int positionOfSsid = 1;
  int lengthOfSsid = strlen(ssid);
  for (int i = 0; i < lengthOfSsid; i++) {
    EEPROM.write(positionOfSsid + i, ssid[i]);
  }
  EEPROM.write(positionOfSsid + lengthOfSsid, '\0');

  // passphrase
  int positionOfPassphrase = 65;
  int lengthOfPassphrase = strlen(passphrase);
  for (int i = 0; i < lengthOfPassphrase; i++) {
    EEPROM.write(positionOfPassphrase + i, passphrase[i]);
  }
  EEPROM.write(positionOfPassphrase + lengthOfPassphrase, '\0');

  if (EEPROM.commit()) {
    Serial.println("Successful EEPROM write");
  } else {
    Serial.println("Failed EEPROM write");
  }
}

void resetSoftApAuth() {
  EEPROM.write(0, 255);

  if (EEPROM.commit()) {
    Serial.println("Successful EEPROM reset");
  } else {
    Serial.println("Failed EEPROM reset");
  }
}

это компилируется, но вылетает и выдает исключения, когда я запускаю чип. Я считаю, что проблема заключается в getSoftApAuth (), где я пытаюсь объединить строку, такую как softApSsid += char(EEPROM.read(i));. Я печатаю значение softApSsid в последовательном мониторе, и он выводит мусор. Я заменил все типом "String", и на этот раз он выводит правильное имя пользователя/пароль, хранящийся в eeprom, но он не запускает soft AP, я полагаю, потому что теперь я пытаюсь передать String вместо const char* в функцию WiFi.SoftAP (), как я уже говорил ранее (it запускает мягкую точку доступа с заводским SSID по умолчанию, например ESP-AABBCCDDEE, добавляя MAC-адрес и без пароля).

Итак, в принципе, как я могу изменить свой SOFTAPSID в своем коде, в то время как я объявил его вверху как const char*, зная, что он передает функцию, которая принимает (исключительно?) const char* (WiFi.SoftAP())

Или есть другой подход / шаблон проектирования для достижения этой цели? То есть иметь жестко закодированные учетные данные по умолчанию, но позволять пользователю определять пользовательские учетные данные (и хранить/извлекать их из eeprom).

Спасибо. Пожалуйста, будьте снисходительны, так как я в основном веб-разработчик и еще не освоился с строго типизированными языками (не говоря уже об указателях / ссылках ...)

, 👍-1

Обсуждение

esp8266 запоминает SSID и пароль сам по себе. для этого не нужно использовать эмулированный eeprom. как только вы используете beginAP(ssid, pass), next beginAP() будет использовать сохраненные значения (если вы используете WiFi.persistent(true))., @Juraj


2 ответа


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

7

эта функция действительно требует "const char*" в качестве параметров

Похоже, здесь какое-то недоразумение. Сигнатура метода такова:

bool ESP8266WiFiAPClass::softAP(const char* ssid, const char* psk,
    int channel, int ssid_hidden, int max_connection);

В этой сигнатуре слово const означает, что метод обещает не изменять ни ssid, ни строки psk. Если бы вы реализовывали этот метод, то действительно должны были бы соблюдать постоянство этих строк. Однако, как пользователь метода, вы вполне можете предоставить изменяемую строку. Вы не связаны никакими требованиями к постоянству. И действительно, вы должны использовать изменяемые строки, если хотите, чтобы ваш пользователь мог их изменить.

Самый простой способ справиться с этой ситуацией:

char softApSsid[MAX_SSID_LENGTH] = "abcdefg";
char softApPassword[MAX_PWD_LENGTH] = "123456";

Обратите внимание, что вы должны выделить достаточно места для хранения самых длинных строк , которые вам могут понадобиться. В то время как 8 байт было бы достаточно для хранения "abcdefg", этого может быть недостаточно для других SSID.

Также обратите внимание, что строки C не могут быть выращены с помощью оператора+=. Они представляют собой просто массивы символов и должны быть записаны как таковые:

i = 0;
do {
    char c = EEPROM.read(1+i);
    softApSsid[i++] = c;
} while (c != '\0');

Edit: отвечая на этот комментарий:

Некоторые исследования по SO также показали следующее:
const char *password = myString.c_str();
где myString имеет строковый тип.

Действительно. Метод c_str() класса String позволяет вам напрямую получить доступ к строке C, скрытой внутри объекта String, если вы обещаете не изменять ее (отсюда и const). Выращивание строки несложно, так как оператор += заботится об обработке памяти.

Однако я бы посоветовал воздержаться от любого ненужного использования Строки класс, так как он включает в себя много выделения памяти кучи, особенно если вы строите строку по одному символу за раз с помощью +=. Это не очень дружелюбно к памяти вашего устройства. Посмотрите на Зло Arduino Строки для деталей.

,

Спасибо за разъяснение и подробный ответ. Я кое-чему научился. Некоторые исследования SO также показали следующее: `const char *password = myString.c_str(); где myString имеет тип String. Я попробую это сделать позже сегодня дома и в конце концов приму ответ., @Musa


0

Всегда помните, что переменная, определенная как массив char, не будет автоматически расти, если вы что-то к ней присоедините. Его размер фиксирован. Когда вы использовали String, это действительно решало эту проблему. Вы можете использовать функцию c_str() String для доступа к самой строке. Строковые операции изменят эту строку, возможно, даже выделив ее по другому адресу. Возможно, было бы разумно просто определить массивы символов фиксированного размера для передачи функциям Wi-Fi. Мне пришлось бы заглянуть в библиотеку Wi-Fi, чтобы определить, копируются ли строки для внутреннего использования. Сделайте эти фиксированные размеры достаточно большими, чтобы их можно было немного отредактировать, но защитите от чрезмерного заполнения редактором.

,