-1

At the top of my arduino sketch, I have the following :

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

Those are the DEFAULT ssid and password to connect to the soft AP. The soft AP is start in the setup() such as :

WiFi.softAP(softApSsid, softApPassword);

according to the github repo, that function indeed requires "const char*" as parameters (source: https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/src/ESP8266WiFiAP.cpp#L97)

Further in my sketch, I want to let the user edit the ssid and password. I wrote a function that reads the first byte of the eeprom. If it equals 255, we use the default credentials, if it equals to 1, it means the user set custom credentials, so we will use those to spawn the soft AP.

I wrote this :

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");
  }
}

this does compile but crashes and throws exceptions when I run the chip. I believe the issue is in getSoftApAuth() where i try to concatenate the string such as softApSsid += char(EEPROM.read(i));. I print the value of softApSsid in the Serial Monitor and it outputs garbage. I replaced everything with "String" type, and this time it outputs correct username/password stored in the eeprom, but it wont start the soft AP, I believe because I am now trying to pass String instead of const char* to the WiFi.softAP() function as I said earlier (it starts the soft AP with factory default SSID like ESP-AABBCCDDEE appending the MAC address and without any password).

So, basically, how can I modify my softApSsid down in my code, while i declared it at the top as a const char*, knowing it feeds a function that takes (exclusively?) a const char* (WiFi.softAP())

Or is there an other approach / design pattern to achieve this? That is to say: having default credentials hard-coded, but allowing the user to define custom credentials (and storing/retrieving them from the eeprom).

Thanks. Please be indulgent as I am mostly a webdev and not yet comfortable with the strongly typed languages (let alone pointers / references ...)

1
  • the esp8266 remembers the SSID and the password by itself. no need to use emulated eeprom for this. once you use beginAP(ssid, pass), next beginAP() will use the stored values (if you use WiFi.persistent(true))
    – Juraj
    Jan 12 at 4:46

2 Answers 2

6

that function indeed requires "const char*" as parameters

There seems to be a misunderstanding here. The method signature is:

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

Within this signature, the word const means the method makes the promise not to modify the ssid nor the psk strings. If you were implementing the method, you would indeed be required to honor the constness of these strings. As a user of the method, however, you are perfectly allowed to provide a modifiable string. You are not bound by any constness requirement. And indeed, you have to use modifiable strings if you want your user to be able to change them.

The simplest way to handle this situation is:

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

Note that you have to allocate enough room to store the longest strings you may need. Whereas 8 bytes would be enough to store "abcdefg", it may not suffice for other ssids.

Also note that C strings cannot be grown with the += operator. They are just arrays of characters and should be written to as such:

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

Edit: answering this comment:

Some research on SO also suggested the following:
const char *password = myString.c_str();
where myString is of String type.

Indeed. The c_str() method of the String class lets you directly access the C string buried within a String object, if you promise not to modify it (hence the const). Growing a String is easy, as the += operator takes care of handling the memory.

I would, however, advice against any unnecessary use of the String class, as it involves lots of heap memory allocation, especially if you build a string one character at a time with +=. This is not really friendly to your device's memory. See The Evils of Arduino Strings for details.

1
  • Thank you for the clarification and the detailed response. I learned something. Some research on SO also suggested the following: const char *password = myString.c_str(); where myString is of String type. I will try it both later today at home and accept the answer eventually.
    – Musa
    Jan 12 at 9:38
0

Always remember that a variable that is defined as a char array will not automatically grow if you concatenate something to it. Its size is fixed. When you used String, that did fix that problem. You can use the c_str() function of String to access the string itself. String operations will change that string, perhaps even allocating it at a different address. It might be wise just to define fixed sized char arrays for passing to the WIFI functions. I'd have to look inside the WIFI library to determine if the strings are copied for use internally. Make those fixed sizes large enough to take some editing, but do protect from over-filling by the editor.

1
  • Oh, you cast the const char str[] as needed for passing into a function by using (char *)str as the variable.
    – user81882
    Jan 12 at 1:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.