Rework of begin methods
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.
-
Named arguments - proposed by @cleishm in #1607. This approach uses a flat config structure as the only argument of the
beginmethods. Values for this structure can be provided by designated initialization directly in thebeginmethod 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}); -
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_tand would allow us to get rid of the different variants ofbegin, likebeginFSKorbeginLRFHSS. 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); -
Removing unnecessary configuration from begin - most of the configuration arguments in
begincalls are not actually needed to start the module. There are exceptions (for example TCXO on SX126x), but the list of arguments inbegincan 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 ofbeginand 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); -
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 usualfindChip()stuff to make sure that the radio is connected properly. After that, the user callsbegin()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 tosetModem().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.
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 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!