RadioLib icon indicating copy to clipboard operation
RadioLib copied to clipboard

Rework of begin methods

Open jgromes opened this issue 3 months ago • 2 comments

Currently, all the begin* methods for all modules have a rather extensive list of arguments, which set basic radio properties like carrier frequency, LoRa spreading factor, FSK bit rate etc. This is unwieldy, leads to the default values being copy-pasted everywhere, is not futureproof as changing the order of arguments can cause silent failures, and overall just not being used as a lot of users will instead opt into calling the default no-argument version and then modifying whatever actually interests them.

I have written down the options discussed so far with examples of the API calls. Fruther proposals can be added.

  1. Named arguments - proposed by @cleishm in #1607. This approach uses a flat config structure as the only argument of the begin methods. Values for this structure can be provided by designated initialization directly in the begin method call, so from the perspective of most users, the only thing that changes is that now they can specify just a single argument in a very clean way.

    int state = radio.begin({.spreadingFactor = 9});
    
  2. Config structs with inheritance - proposed by @jgromes. This approach is similar to the one above, except that the configuration structure is no longer flat and inherits from a base struct which contains all the common configuration. This limits the copy-paste, connects the configuration to existing config structures like DataRate_t and would allow us to get rid of the different variants of begin, like beginFSK or beginLRFHSS. It also allows more advanced users to easily switch between different modems and configurations. The downside is that the user API is more complicated.

    SX126xConfig_t cfg(RADIOLIB_MODEM_LORA);
    cfg.dataRate.lora.spreadingFactor = 9;
    int state = radio.begin(&cfg);
    
  3. Removing unnecessary configuration from begin - most of the configuration arguments in begin calls are not actually needed to start the module. There are exceptions (for example TCXO on SX126x), but the list of arguments in begin can be actually removed most of the time. This would necessitate the user to configure the arguments themselves, which some already do anyway. The advantage here that this is the simplest solution, the clear disadvantage is that it pushes all the configuration onto the user, leaving the radio in a weird semi-configured state between the end of begin and completed initialization. It will also discourage users from checking all of the error codes, as every call to config method will need to be checked, which is currently done by the library.

    int state = radio.begin();
    RADIOLIB_ASSERT(state);
    state = radio.setFrequency(434);
    RADIOLIB_ASSERT(state);
    state = radio.setSpreadingFactor(9);
    
  4. Configure modem and use named arguments - proposed by @StevenCellist. This proposal uses the existing setModem() (possibly renamed) followed by approach 1 above with named arguments. The user must first (re)set the module to a specific modem (LoRa, FSK, ..) which does the usual findChip() stuff to make sure that the radio is connected properly. After that, the user calls begin() with named arguments with possible default values as in the proposal by @cleishm. This argument list is selectively interpreted based on the configured modem. As a side-effect, this also tackles the 'wake-up from deepsleeping ESP32'-problem as then the user can skip the call to setModem().

    int state = radio.setModem(RADIOLIB_MODEM_LORA);
    RADIOLIB_ASSERT(state);
    state = radio.begin({.spreadingFactor = 9});
    

As this is a major breaking change, it will be rolled out gradually over the next library releases. The original list of arguments will be removed in 8.0.0, breaking backwards compatibility there.

jgromes avatar Oct 05 '25 06:10 jgromes

How about a reset(modem) required as a first call and then a flat begin({}) argument that only looks at the relevant arguments based on the modem? So essentially people need to call one additional function which does the findChip() etc. This also means you can easily ignore this on wake for devices that lose RAM. But it doesn't use the structures that exist for datarate and packet config as a sort of downside.

StevenCellist avatar Oct 05 '25 21:10 StevenCellist

@StevenCellist could you add it into my original post as another propsoed approach, with an example of what the public API would look like, so that we can compare everything side-by-side? Thanks!

jgromes avatar Oct 06 '25 05:10 jgromes