Setting APN from EEPROM stored value

OK, I am having a bit of an issue here.

I would like to be able to set the APN for used with a 3rd party SIM stored in the emulated EEPROM section in an Electron. This design was chosen so that I would not be tieing the firmware that I may deploy in the future to a specific APN that is hard-coded in.

To further complication that, the electron needs to start up, pause briefly to see if a connection is made quickly, but otherwise progress on and continue the rest of its tasks (display, calculation) without a connection.

The issue that I am having is that the APN is apparently not set correctly, even though the correct APN is being loaded from EEPROM and set with cellular_credentials_set. The cell connection is never made.
If I flash the exact same firmware but using the STARTUP line with the hard-coded APN and the EEPROM one commented, then the Electron does connect properly.

What is going wrong here?

Dammit, as I am writing this, I do now realize that I am not verifying that the credentials have been set with cellular_credentials_get, and there is indeed a TODO in cellular_hal_constants.h about string storage :\

I’ll try it in hardware tomorrow morning, but just looking at it now my reading is that the fields of CellularCredentials will end up pointing to the autovar EEPROM data struct in set_APN_from_eeprom(), whose lifetime is limited.
Doing it the hard-coded way gives us a global scope string literal with forever lifetime. :cry:

The only workarounds I see are: using the absolute flash address for EEPROM to refer to the string literal there, or using a static struct in set_APN_from_eeprom() and keeping a RAM copy of the EEPROM data.

The code is summarized as:

SYSTEM_THREAD(ENABLED); 
SYSTEM_MODE(SEMI_AUTOMATIC);
STARTUP(set_APN_from_eeprom());  //APN from eeprom
//STARTUP(cellular_credentials_set("my.apn.com","","",NULL); //alternate hard coded APN

void set_APN_from_eeprom(){
  eeprom_data_t eeprom; //structure
  EPROM.get(0, eeprom);
  print_eeprom_data_contents(&eeprom);
  cellular_credentials_set(eeprom.apn, eeprom.apn_username, eeprom.apn_password, NULL);
}

void setup(){
 //stuff
  Particle.connect();
}

void loop(){
  display_loop();
  calculation_loop();
  if(Particle.connected()){
    open_socket();
  }
}

So, do we consider your “question” as “self-resolved”?

Not until I try it in hardware!

And tbh it would be pretty nice to get one of the experts to sound off on this… particularly if there are implications about needing to reset the cell module, or issue a special AT command, any contraindications with SYSTEM_THREAD(ENABLED), etc.

I wouldn’t try to do it from STARTUP. The only reason the examples show it that way is so they can be used from AUTOMATIC system mode; setup() is too late to cellular_credentials_set() in AUTOMATIC mode.

If you’re using SEMI_AUTOMATIC or MANUAL mode, you can do cellular_credentials_set() from setup() or even loop() as long as you do it before the first Particle.connect() or Cellular.connect().

OK, I have now had success on this issue. Phew.

It is certainly up to the user to establish a permanent lifetime for the APN strings, per the above note.

The one rub is that it seems that I could only get the APN to be set properly by doing a Cellular.on() and .off() after setting the credentials, but before Particle.connect().