From d80157b5b8b89983fbec70d27dde2c70b32202f3 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Tue, 29 Oct 2024 17:07:46 -0400 Subject: [PATCH 1/7] style: #endif needs comment in radio_*.c --- src/lmic/radio_sx126x.c | 4 ++-- src/lmic/radio_sx127x.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lmic/radio_sx126x.c b/src/lmic/radio_sx126x.c index 512bf602..1b28cf2b 100644 --- a/src/lmic/radio_sx126x.c +++ b/src/lmic/radio_sx126x.c @@ -32,7 +32,7 @@ #include "lmic.h" -#if (CFG_sx1261_radio || CFG_sx1262_radio) +#if defined(CFG_sx1261_radio) || defined(CFG_sx1262_radio) // This driver is based on Rev. 2.1 of the Semtech SX1261/2 Data Sheet DS.SX1261-2.W.APP // ---------------------------------------- // Command Mapping ** Chapter 11 List of Commands @@ -1465,4 +1465,4 @@ void os_radio(u1_t mode) { ostime_t os_getRadioRxRampup(void) { return RX_RAMPUP_DEFAULT + us2osticks(12480); // SX126x is 780 ticks slower than SX127x to wake from sleep @ 240MHz } -#endif \ No newline at end of file +#endif // defined(CFG_sx1261_radio) || defined(CFG_sx1262_radio) diff --git a/src/lmic/radio_sx127x.c b/src/lmic/radio_sx127x.c index 31f02455..02ec41e8 100644 --- a/src/lmic/radio_sx127x.c +++ b/src/lmic/radio_sx127x.c @@ -31,7 +31,7 @@ #define LMIC_DR_LEGACY 0 #include "lmic.h" -#if (CFG_sx1272_radio || CFG_sx1276_radio) +#if defined(CFG_sx1272_radio) || defined(CFG_sx1276_radio) // ---------------------------------------- // Registers Mapping // // -type- 1272 vs 1276 @@ -1441,4 +1441,4 @@ void os_radio (u1_t mode) { ostime_t os_getRadioRxRampup (void) { return RX_RAMPUP_DEFAULT; } -#endif \ No newline at end of file +#endif // defined(CFG_sx1272_radio) || defined(CFG_sx1276_radio) From 39fd535ccd4795af7c7611840366b3685612a2ab Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Tue, 29 Oct 2024 18:53:23 -0400 Subject: [PATCH 2/7] Refactor README and put little-used config in separate file --- README.md | 260 +------------------------------- doc/HOWTO-Manually-Configure.md | 256 +++++++++++++++++++++++++++++++ 2 files changed, 259 insertions(+), 257 deletions(-) create mode 100644 doc/HOWTO-Manually-Configure.md diff --git a/README.md b/README.md index 7887337c..6e44057d 100644 --- a/README.md +++ b/README.md @@ -60,17 +60,6 @@ - [Supported hardware](#supported-hardware) - [Pre-Integrated Boards](#pre-integrated-boards) - [PlatformIO](#platformio) -- [Manual configuration](#manual-configuration) - - [Power](#power) - - [SPI](#spi) - - [DIO pins](#dio-pins) - - [Reset](#reset) - - [RXTX](#rxtx) - - [RXTX Polarity](#rxtx-polarity) - - [Pin mapping](#pin-mapping) - - [Advanced initialization](#advanced-initialization) - - [HalConfiguration_t methods](#halconfiguration_t-methods) - - [LoRa Nexus by Ideetron](#lora-nexus-by-ideetron) - [Example Sketches](#example-sketches) - [Timing](#timing) - [Controlling protocol timing](#controlling-protocol-timing) @@ -505,6 +494,8 @@ The following boards are pre-integrated. > To help you know if you have to worry, we'll call such boards "pre-integrated" and prefix each section with suitable guidance. +If your board is not pre-integrated, refer to [`HOWTO-Manually-Configure.md`](doc/HOWTO-Manually-Configure.md). + ## PlatformIO For use with PlatformIO, the `lmic_project_config.h` has to be disabled with the flag `ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS`. @@ -520,252 +511,6 @@ build_flags = -D CFG_sx1276_radio=1 ``` -## Manual configuration - -If your desired transceiver board is not pre-integrated, you need to provide the library with the required information. - -You may need to wire up your transceiver. The exact -connections are a bit dependent on the transceiver board and Arduino -used, so this section tries to explain what each connection is for and -in what cases it is (not) required. - -Note that the SX127x module runs at 3.3V and likely does not like 5V on -its pins (though the datasheet is not say anything about this, and my -transceiver did not obviously break after accidentally using 5V I/O for -a few hours). To be safe, make sure to use a level shifter, or an -Arduino running at 3.3V. The Semtech evaluation board has 100 ohm resistors in -series with all data lines that might prevent damage, but I would not -count on that. - -### Power - -> If you're using a [pre-integrated board](#pre-integrated-boards), you can skip this section. - -The SX127x transceivers need a supply voltage between 1.8V and 3.9V. -Using a 3.3V supply is typical. Some modules have a single power pin -(like the HopeRF modules, labeled 3.3V) but others expose multiple power -pins for different parts (like the Semtech evaluation board that has -`VDD_RF`, `VDD_ANA` and `VDD_FEM`), which can all be connected together. -Any *GND* pins need to be connected to the Arduino *GND* pin(s). - -### SPI - -> If you're using a [pre-integrated board](#pre-integrated-boards), you can skip this section. - -The primary way of communicating with the transceiver is through SPI -(Serial Peripheral Interface). This uses four pins: MOSI, MISO, SCK and -SS. The former three need to be directly connected: so MOSI to MOSI, -MISO to MISO, SCK to SCK. Where these pins are located on your Arduino -varies, see for example the "Connections" section of the [Arduino SPI -documentation](SPI). - -The SS (slave select) connection is a bit more flexible. On the SPI -slave side (the transceiver), this must be connected to the pin -(typically) labeled *NSS*. On the SPI master (Arduino) side, this pin -can connect to any I/O pin. Most Arduinos also have a pin labeled "SS", -but this is only relevant when the Arduino works as an SPI slave, which -is not the case here. Whatever pin you pick, you need to tell the -library what pin you used through the pin mapping (see [below](#pin-mapping)). - -[SPI]: https://www.arduino.cc/en/Reference/SPI - -### DIO pins - -> If you're using a [pre-integrated board](#pre-integrated-boards), you can skip this section. - -The DIO (digital I/O) pins on the SX127x can be configured -for various functions. The LMIC library uses them to get instant status -information from the transceiver. For example, when a LoRa transmission -starts, the DIO0 pin is configured as a TxDone output. When the -transmission is complete, the DIO0 pin is made high by the transceiver, -which can be detected by the LMIC library. - -The LMIC library needs only access to DIO0, DIO1 and DIO2, the other -DIOx pins can be left disconnected. On the Arduino side, they can -connect to any I/O pin. If interrupts are used, the accuracy of timing -will be improved, particularly the rest of your `loop()` function has -lengthy calculations; but in that case, the enabled DIO pins must all -support rising-edge interrupts. See the [Timing](#timing) section below. - -In LoRa mode the DIO pins are used as follows: - -* DIO0: TxDone and RxDone -* DIO1: RxTimeout - -In FSK mode they are used as follows:: - -* DIO0: PayloadReady and PacketSent -* DIO2: TimeOut - -Both modes need only 2 pins, but the transceiver does not allow mapping -them in such a way that all needed interrupts map to the same 2 pins. -So, if both LoRa and FSK modes are used, all three pins must be -connected. - -The pins used on the Arduino side should be configured in the pin -mapping in your sketch, by setting the values of `lmic_pinmap::dio[0]`, `[1]`, and `[2]` (see [below](#pin-mapping)). - -### Reset - -> If you're using a [pre-integrated board](#pre-integrated-boards), you can skip this section. - -The transceiver has a reset pin that can be used to explicitly reset -it. The LMIC library uses this to ensure the chip is in a consistent -state at startup. In practice, this pin can be left disconnected, since -the transceiver will already be in a sane state on power-on, but -connecting it might prevent problems in some cases. - -On the Arduino side, any I/O pin can be used. The pin number used must -be configured in the pin mapping `lmic_pinmap::rst` field (see [below](#pin-mapping)). - -### RXTX - -> If you're using a [pre-integrated board](#pre-integrated-boards), you can skip this section. - -The transceiver contains two separate antenna connections: One for RX -and one for TX. A typical transceiver board contains an antenna switch -chip, that allows switching a single antenna between these RX and TX -connections. Such a antenna switcher can typically be told what -position it should be through an input pin, often labeled *RXTX*. - -The easiest way to control the antenna switch is to use the *RXTX* pin -on the SX127x transceiver. This pin is automatically set high during TX -and low during RX. For example, the HopeRF boards seem to have this -connection in place, so they do not expose any *RXTX* pins and the pin -can be marked as unused in the pin mapping. - -Some boards do expose the antenna switcher pin, and sometimes also the -SX127x *RXTX* pin. For example, the SX1272 evaluation board calls the -former *FEM_CTX* and the latter *RXTX*. Again, simply connecting these -together with a jumper wire is the easiest solution. - -Alternatively, or if the SX127x *RXTX* pin is not available, LMIC can be -configured to control the antenna switch. Connect the antenna switch -control pin (e.g. *FEM_CTX* on the Semtech evaluation board) to any I/O -pin on the Arduino side, and configure the pin used in the pin map (see -[below](#pin-mapping)). - -The configuration entry `lmic_pinmap::rxtx` configures the pin to be used for the *RXTX* control function, in terms of the Arduino `wire.h` digital pin number. If set to `LMIC_UNUSED_PIN`, then the library assumes that software does not need to control the antenna switch. - -### RXTX Polarity - -> If you're using a [pre-integrated board](#pre-integrated-boards), you can skip this section. - -If an external switch is used, you also must specify the polarity. Some modules want *RXTX* to be high for transmit, low for receive; Others want it to be low for transmit, high for receive. The Murata module, for example, requires that *RXTX* be *high* for receive, *low* for transmit. - -The configuration entry `lmic_pinmap::rxtx_rx_active` should be set to the state to be written to the *RXTX* pin to make the receiver active. The opposite state is written to make the transmitter active. If `lmic_pinmap::rxtx` is `LMIC_UNUSED_PIN`, then the value of `lmic_pinmap::rxtx_rx_active` is ignored. - -### Pin mapping - -> If you're using a [pre-integrated board](#pre-integrated-boards), you can skip this section. - -Refer to the documentation on your board for the required settings. - -Remember, for pre-integrated boards, you don't worry about this. - -We have details for the following manually-configured boards here: - -- [LoRa Nexus by Ideetron](#lora-nexus-by-ideetron) - -If your board is not configured, you need at least to provide your own `lmic_pinmap`. As described above, a variety of configurations are possible. To tell the LMIC library how your board is configured, you must declare a variable containing a pin mapping struct in your sketch file. If you call `os_init()` to initialize the LMIC, you must name this structure `lmic_pins`. If you call `os_init_ex()`, you may name the structure what you like, but you pass a pointer as the parameter to `os_init_ex()`. - -Here's an example of a simple initialization: - -```c++ - lmic_pinmap lmic_pins = { - .nss = 6, - .rxtx = LMIC_UNUSED_PIN, - .rst = 5, - .dio = {2, 3, 4}, - // optional: set polarity of rxtx pin. - .rxtx_rx_active = 0, - // optional: set RSSI cal for listen-before-talk - // this value is in dB, and is added to RSSI - // measured prior to decision. - // Must include noise guardband! Ignored in US, - // EU, IN, other markets where LBT is not required. - .rssi_cal = 0, - // optional: override LMIC_SPI_FREQ if non-zero - .spi_freq = 0, - }; -``` - -The names refer to the pins on the transceiver side, the numbers refer -to the Arduino pin numbers (to use the analog pins, use constants like -`A0`). For the DIO pins, the three numbers refer to DIO0, DIO1 and DIO2 -respectively. Any pins that are not needed should be specified as -`LMIC_UNUSED_PIN`. The NSS and dio0 pins are required. The others can -potentially left out (depending on the environments and requirements, -see the notes above for when a pin can or cannot be left out). - -#### Advanced initialization - -In some boards require much more advanced management. The LMIC has a very flexible framework to support this, but it requires you to do some C++ work. - -1. You must define a new class derived from `Arduino_LMIC::HalConfiguration_t`. (We'll call this `cMyHalConfiguration_t`). - -2. This class *may* define overrides for several methods (discussed below). - -3. You must create an instance of your class, e.g. - - ```c++ - cMyHalConfiguration_t myHalConfigInstance; - ``` - -4. You add another entry in your `lmic_pinmap`, `pConfig = &myHalConfigInstance`, to link your pin-map to your object. - -The full example looks like this: - -```c++ -class cMyHalConfiguration_t : public Arduino_LMIC::HalConfiguration_t - { -public: - // ... - // put your method function override declarations here. - - // this example uses RFO at 10 dBm or less, PA_BOOST up to 17 dBm, - // or the high-power mode above 17 dBm. In other words, it lets the - // LMIC-determined policy determine what's to be done. - - virtual TxPowerPolicy_t getTxPowerPolicy( - TxPowerPolicy_t policy, - int8_t requestedPower, - uint32_t frequency - ) override - { - return policy; - } - }; -``` - -#### HalConfiguration_t methods - -- `ostime_t setModuleActive(bool state)` is called by the LMIC to make the module active or to deactivate it (the value of `state` is true to activate). The implementation must turn power to the module on and otherwise prepare for it to go to work, and must return the number of OS ticks to wait before starting to use the radio. - -- `void begin(void)` is called during initialization, and is your code's chance to do any early setup. - -- `void end(void)` is (to be) called during late shutdown. (Late shutdown is not implemented yet; but we wanted to add the API for consistency.) - -- `bool queryUsingTcxo(void)` shall return `true` if the module uses a TCXO; `false` otherwise. - -- `TxPowerPolicy_t getTxPowerPolicy(TxPowerPolicy_t policy, int8_t requestedPower, uint32_t frequency)` allows you to override the LMIC's selection of transmit power. If not provided, the default method forces the LMIC to use PA_BOOST mode. (We chose to do this because we found empirically that the Hope RF module doesn't support RFO, and because legacy LMIC code never used anything except PA_BOOST mode.) - -Caution: the LMIC has no way of knowing whether the mode you return makes sense. Use of 20 dBm mode without limiting duty cycle can over-stress your module. The LMIC currently does not have any code to duty-cycle US transmissions at 20 dBm. If properly limiting transmissions to 400 milliseconds, a 1% duty-cycle means at most one message every 40 seconds. This shouldn't be a problem in practice, but buggy upper level software still might do things more rapidly. - - -#### LoRa Nexus by Ideetron - -This board uses the following pin mapping: - -```c++ - const lmic_pinmap lmic_pins = { - .nss = 10, - .rxtx = LMIC_UNUSED_PIN, - .rst = LMIC_UNUSED_PIN, // hardwired to AtMega RESET - .dio = {4, 5, 7}, - }; -``` - ## Example Sketches This library provides several examples. @@ -1247,6 +992,7 @@ function uflt12f(rawUflt12) - HEAD has the following changes. - Enable device time request by default in config file ([#840](https://github.com/mcci-catena/arduino-lmic/issues/840)). + - Refactor `README.md` a little and put little used configuration info in a separate file. - v4.1.1 is a patch release. diff --git a/doc/HOWTO-Manually-Configure.md b/doc/HOWTO-Manually-Configure.md new file mode 100644 index 00000000..cfc31649 --- /dev/null +++ b/doc/HOWTO-Manually-Configure.md @@ -0,0 +1,256 @@ +# Manual configuration + +If your desired transceiver board is not pre-integrated, you need to provide the library with the required information. + +> If you're using a [pre-integrated board](../README.md#pre-integrated-boards), you can skip this document. + +## Transceiver Wiring + +> If you're using a [pre-integrated board](../README.md#pre-integrated-boards), ignore this section. + +You may need to wire up your transceiver. The exact +connections are a bit dependent on the transceiver board and Arduino +used, so this section tries to explain what each connection is for and +in what cases it is (not) required. + +Note that the SX127x module runs at 3.3V and likely does not like 5V on +its pins (though the datasheet is not say anything about this, and my +transceiver did not obviously break after accidentally using 5V I/O for +a few hours). To be safe, make sure to use a level shifter, or an +Arduino running at 3.3V. The Semtech evaluation board has 100 ohm resistors in +series with all data lines that might prevent damage, but I would not +count on that. + +You must select the proper radio for your board in [`lmic_project_config.h`](../project_config/lmic_project_config.h), using a `#define` to define the appropriate symbol chosen from `CFG_sx1272_radio`, `CFG_sx1276_radio`, `CFG_sx1261_radio` or `CFG_sx1262_radio`. + +## Power + +> If you're using a [pre-integrated board](../README.md#pre-integrated-boards), ignore this section. + +The SX127x transceivers need a supply voltage between 1.8V and 3.9V. +Using a 3.3V supply is typical. Some modules have a single power pin +(like the HopeRF modules, labeled 3.3V) but others expose multiple power +pins for different parts (like the Semtech evaluation board that has +`VDD_RF`, `VDD_ANA` and `VDD_FEM`), which can all be connected together. +Any *GND* pins need to be connected to the Arduino *GND* pin(s). + +### SPI + +> If you're using a [pre-integrated board](../README.md#pre-integrated-boards), ignore this section. + +The primary way of communicating with the transceiver is through SPI +(Serial Peripheral Interface). This uses four pins: MOSI, MISO, SCK and +SS. The former three need to be directly connected: so MOSI to MOSI, +MISO to MISO, SCK to SCK. Where these pins are located on your Arduino +varies, see for example the "Connections" section of the [Arduino SPI +documentation](SPI). + +The SS (slave select) connection is a bit more flexible. On the SPI +slave side (the transceiver), this must be connected to the pin +(typically) labeled *NSS*. On the SPI master (Arduino) side, this pin +can connect to any I/O pin. Most Arduinos also have a pin labeled "SS", +but this is only relevant when the Arduino works as an SPI slave, which +is not the case here. Whatever pin you pick, you need to tell the +library what pin you used through the pin mapping (see [below](#pin-mapping)). + +[SPI]: https://www.arduino.cc/en/Reference/SPI + +## DIO pins + +> If you're using a [pre-integrated board](../README.md#pre-integrated-boards), ignore this section. + +The DIO (digital I/O) pins on the SX127x can be configured +for various functions. The LMIC library uses them to get instant status +information from the transceiver. For example, when a LoRa transmission +starts, the DIO0 pin is configured as a TxDone output. When the +transmission is complete, the DIO0 pin is made high by the transceiver, +which can be detected by the LMIC library. + +The LMIC library needs only access to DIO0, DIO1 and DIO2, the other +DIOx pins can be left disconnected. On the Arduino side, they can +connect to any I/O pin. If interrupts are used, the accuracy of timing +will be improved, particularly the rest of your `loop()` function has +lengthy calculations; but in that case, the enabled DIO pins must all +support rising-edge interrupts. See the [Timing](#timing) section below. + +In LoRa mode the DIO pins are used as follows: + +* DIO0: TxDone and RxDone +* DIO1: RxTimeout + +In FSK mode they are used as follows:: + +* DIO0: PayloadReady and PacketSent +* DIO2: TimeOut + +Both modes need only 2 pins, but the transceiver does not allow mapping +them in such a way that all needed interrupts map to the same 2 pins. +So, if both LoRa and FSK modes are used, all three pins must be +connected. + +The pins used on the Arduino side should be configured in the pin +mapping in your sketch, by setting the values of `lmic_pinmap::dio[0]`, `[1]`, and `[2]` (see [below](#pin-mapping)). + +## Reset + +> If you're using a [pre-integrated board](../README.md#pre-integrated-boards), ignore this section. + +The transceiver has a reset pin that can be used to explicitly reset +it. The LMIC library uses this to ensure the chip is in a consistent +state at startup. In practice, this pin can be left disconnected, since +the transceiver will already be in a sane state on power-on, but +connecting it might prevent problems in some cases. + +On the Arduino side, any I/O pin can be used. The pin number used must +be configured in the pin mapping `lmic_pinmap::rst` field (see [below](#pin-mapping)). + +## RXTX + +> If you're using a [pre-integrated board](../README.md#pre-integrated-boards), ignore this section. + + +The transceiver contains two separate antenna connections: One for RX +and one for TX. A typical transceiver board contains an antenna switch +chip, that allows switching a single antenna between these RX and TX +connections. Such a antenna switcher can typically be told what +position it should be through an input pin, often labeled *RXTX*. + +The easiest way to control the antenna switch is to use the *RXTX* pin +on the SX127x transceiver. This pin is automatically set high during TX +and low during RX. For example, the HopeRF boards seem to have this +connection in place, so they do not expose any *RXTX* pins and the pin +can be marked as unused in the pin mapping. + +Some boards do expose the antenna switcher pin, and sometimes also the +SX127x *RXTX* pin. For example, the SX1272 evaluation board calls the +former *FEM_CTX* and the latter *RXTX*. Again, simply connecting these +together with a jumper wire is the easiest solution. + +Alternatively, or if the SX127x *RXTX* pin is not available, LMIC can be +configured to control the antenna switch. Connect the antenna switch +control pin (e.g. *FEM_CTX* on the Semtech evaluation board) to any I/O +pin on the Arduino side, and configure the pin used in the pin map (see +[below](#pin-mapping)). + +The configuration entry `lmic_pinmap::rxtx` configures the pin to be used for the *RXTX* control function, in terms of the Arduino `wire.h` digital pin number. If set to `LMIC_UNUSED_PIN`, then the library assumes that software does not need to control the antenna switch. + +## RXTX Polarity + +> If you're using a [pre-integrated board](../README.md#pre-integrated-boards), ignore this section. + +If an external switch is used, you also must specify the polarity. Some modules want *RXTX* to be high for transmit, low for receive; Others want it to be low for transmit, high for receive. The Murata module, for example, requires that *RXTX* be *high* for receive, *low* for transmit. + +The configuration entry `lmic_pinmap::rxtx_rx_active` should be set to the state to be written to the *RXTX* pin to make the receiver active. The opposite state is written to make the transmitter active. If `lmic_pinmap::rxtx` is `LMIC_UNUSED_PIN`, then the value of `lmic_pinmap::rxtx_rx_active` is ignored. + +## Pin mapping + +> If you're using a [pre-integrated board](../README.md#pre-integrated-boards), ignore this section. + +Refer to the documentation on your board for the required settings. + +Remember, for pre-integrated boards, you don't worry about this. + +We have details for the following manually-configured boards here: + +- [LoRa Nexus by Ideetron](#lora-nexus-by-ideetron) + +If your board is not configured, you need at least to provide your own `lmic_pinmap`. As described above, a variety of configurations are possible. To tell the LMIC library how your board is configured, you must declare a variable containing a pin mapping struct in your sketch file. If you call `os_init()` to initialize the LMIC, you must name this structure `lmic_pins`. If you call `os_init_ex()`, you may name the structure what you like, but you pass a pointer as the parameter to `os_init_ex()`. + +Here's an example of a simple initialization: + +```c++ + lmic_pinmap lmic_pins = { + .nss = 6, + .rxtx = LMIC_UNUSED_PIN, + .rst = 5, + .dio = {2, 3, 4}, + // optional: set polarity of rxtx pin. + .rxtx_rx_active = 0, + // optional: set RSSI cal for listen-before-talk + // this value is in dB, and is added to RSSI + // measured prior to decision. + // Must include noise guardband! Ignored in US, + // EU, IN, other markets where LBT is not required. + .rssi_cal = 0, + // optional: override LMIC_SPI_FREQ if non-zero + .spi_freq = 0, + }; +``` + +The names refer to the pins on the transceiver side, the numbers refer +to the Arduino pin numbers (to use the analog pins, use constants like +`A0`). For the DIO pins, the three numbers refer to DIO0, DIO1 and DIO2 +respectively. Any pins that are not needed should be specified as +`LMIC_UNUSED_PIN`. The NSS and dio0 pins are required. The others can +potentially left out (depending on the environments and requirements, +see the notes above for when a pin can or cannot be left out). + +## Advanced initialization + +> If you're using a [pre-integrated board](../README.md#pre-integrated-boards), ignore this section. + +In some boards require much more advanced management. The LMIC has a very flexible framework to support this, but it requires you to do some C++ work. + +1. You must define a new class derived from `Arduino_LMIC::HalConfiguration_t`. (We'll call this `cMyHalConfiguration_t`). + +2. This class *may* define overrides for several methods (discussed below). + +3. You must create an instance of your class, e.g. + + ```c++ + cMyHalConfiguration_t myHalConfigInstance; + ``` + +4. You add another entry in your `lmic_pinmap`, `pConfig = &myHalConfigInstance`, to link your pin-map to your object. + +The full example looks like this: + +```c++ +class cMyHalConfiguration_t : public Arduino_LMIC::HalConfiguration_t + { +public: + // ... + // put your method function override declarations here. + + // this example uses RFO at 10 dBm or less, PA_BOOST up to 17 dBm, + // or the high-power mode above 17 dBm. In other words, it lets the + // LMIC-determined policy determine what's to be done. + + virtual TxPowerPolicy_t getTxPowerPolicy( + TxPowerPolicy_t policy, + int8_t requestedPower, + uint32_t frequency + ) override + { + return policy; + } + }; +``` + +## HalConfiguration_t methods + +- `ostime_t setModuleActive(bool state)` is called by the LMIC to make the module active or to deactivate it (the value of `state` is true to activate). The implementation must turn power to the module on and otherwise prepare for it to go to work, and must return the number of OS ticks to wait before starting to use the radio. + +- `void begin(void)` is called during initialization, and is your code's chance to do any early setup. + +- `void end(void)` is (to be) called during late shutdown. (Late shutdown is not implemented yet; but we wanted to add the API for consistency.) + +- `bool queryUsingTcxo(void)` shall return `true` if the module uses a TCXO; `false` otherwise. + +- `TxPowerPolicy_t getTxPowerPolicy(TxPowerPolicy_t policy, int8_t requestedPower, uint32_t frequency)` allows you to override the LMIC's selection of transmit power. If not provided, the default method forces the LMIC to use PA_BOOST mode. (We chose to do this because we found empirically that the Hope RF module doesn't support RFO, and because legacy LMIC code never used anything except PA_BOOST mode.) + +Caution: the LMIC has no way of knowing whether the mode you return makes sense. Use of 20 dBm mode without limiting duty cycle can over-stress your module. The LMIC currently does not have any code to duty-cycle US transmissions at 20 dBm. If properly limiting transmissions to 400 milliseconds, a 1% duty-cycle means at most one message every 40 seconds. This shouldn't be a problem in practice, but buggy upper level software still might do things more rapidly. + + +## Example: LoRa Nexus by Ideetron + +This board uses the following pin mapping: + +```c++ + const lmic_pinmap lmic_pins = { + .nss = 10, + .rxtx = LMIC_UNUSED_PIN, + .rst = LMIC_UNUSED_PIN, // hardwired to AtMega RESET + .dio = {4, 5, 7}, + }; +``` From 2878896d65ed7917c08ecd896bf6b9e1a30f4e05 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Tue, 29 Oct 2024 18:54:50 -0400 Subject: [PATCH 3/7] #949: document support for SX126x --- README.md | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6e44057d..fffed022 100644 --- a/README.md +++ b/README.md @@ -299,6 +299,14 @@ Configures the library for use with an sx1272 transceiver. Configures the library for use with an sx1276 transceiver. +`#define CFG_sx1261_radio 1` + +Configures the library for use with an sx1261 transceiver. + +`#define CFG_sx1262_radio 1` + +Configures the library for use with an sx1262 transceiver. + ### Controlling use of interrupts `#define LMIC_USE_INTERRUPTS` @@ -441,13 +449,15 @@ The compliance test script includes a suitable logging implementation; the other ## Supported hardware This library is intended to be used with plain LoRa transceivers, -connecting to them using SPI. In particular, the SX1272 and SX1276 +connected to the Arduino CPU using a SPI bus. In particular: + +* The SX1272, SX1276 families are supported (which should include SX1273, SX1277, SX1278 and SX1279 which only differ in the available frequencies, bandwidths and spreading factors). It has been tested with both SX1272 and SX1276 -chips, using the Semtech SX1272 evaluation board and the HopeRF RFM92 -and RFM95 boards (which supposedly contain an SX1272 and SX1276 chip -respectively). +chips on a variety of platforms. + +* The SX1261 and SX1262 families are supported. This has been tested with Heltec and TTGo boards. This library contains a full LoRaWAN stack and is intended to drive these Transceivers directly. It is *not* intended to be used with @@ -992,6 +1002,7 @@ function uflt12f(rawUflt12) - HEAD has the following changes. - Enable device time request by default in config file ([#840](https://github.com/mcci-catena/arduino-lmic/issues/840)). + - Add support for SX126x radios ([#949](https://github.com/mcci-catena/arduino-lmic/pull/949)). - Refactor `README.md` a little and put little used configuration info in a separate file. - v4.1.1 is a patch release. @@ -1115,6 +1126,8 @@ This library started from the IBM V1.5 open-source code. - [`@ngraziano`](https://github.com/ngraziano) did extensive testing and contributed numerous ADR-related patches. +- [`@TristanWebber`](https://github.com/TristanWebber) contributed sx1261 and sx1262 support. + There are many others, who have contributed code and also participated in discussions, performed testing, reported problems and results. Thanks to all who have participated. We hope to use something like [All Contributors](https://https://allcontributors.org/) to help keep this up to date, but so far the automation isn't working. ## Trademark Acknowledgements From e85f8b192171a2631f66c1aeb9dd6ce8cb4544e0 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Tue, 29 Oct 2024 18:55:10 -0400 Subject: [PATCH 4/7] Minor doc touchups --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fffed022..bf3afbe6 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ - [Controlling use of interrupts](#controlling-use-of-interrupts) - [Disabling PING](#disabling-ping) - [Disabling Beacons](#disabling-beacons) - - [Enabling Network Time Support](#enabling-network-time-support) + - [Enabling/Disabling Network Time Support](#enablingdisabling-network-time-support) - [Rarely changed variables](#rarely-changed-variables) - [Changing debug output](#changing-debug-output) - [Getting debug from the RF library](#getting-debug-from-the-rf-library) @@ -332,7 +332,7 @@ Enabling beacon handling allows tracking of network time, and is required if you By default, beacon support is included in the library. -### Enabling Network Time Support +### Enabling/Disabling Network Time Support `#define LMIC_ENABLE_DeviceTimeReq number /* boolean: 0 or non-zero */` @@ -467,9 +467,9 @@ LoRaWAN stack and exposes a high-level serial interface instead of the low-level SPI transceiver interface. This library is intended to be used inside the Arduino environment. It -should be architecture-independent. Users have tested this on AVR, ARM, Xtensa-based, and RISC-V based system. +should be architecture-independent. Users have tested this on AVR, ARM, Xtensa-based, ESP32, and RISC-V based systems. -This library can be quite heavy on small systems, especially if the fairly small ATmega +This library can be quite heavy on 8-bit systems, especially if the fairly small ATmega 328p (such as in the Arduino Uno) is used. In the default configuration, the available 32K flash space is nearly filled up (this includes some debug output overhead, though). By disabling some features in `project_config/lmic_project_config.h` From 12d9669874c0ada3548bd12954abcd1c0f126608 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Tue, 29 Oct 2024 18:56:29 -0400 Subject: [PATCH 5/7] Code doc: describe `jacc` flag meaning --- src/lmic/lmic.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lmic/lmic.c b/src/lmic/lmic.c index 98d18ca5..9bfdb214 100644 --- a/src/lmic/lmic.c +++ b/src/lmic/lmic.c @@ -2570,7 +2570,10 @@ static void engineUpdate_inner (void) { if( (LMIC.opmode & (OP_JOINING|OP_REJOIN|OP_TXDATA|OP_POLL)) != 0 ) { // Assuming txChnl points to channel which first becomes available again. + + // set jacc true if we'll transmit a join-accept rather than user data bit_t jacc = ((LMIC.opmode & (OP_JOINING|OP_REJOIN)) != 0 ? 1 : 0); + // Find next suitable channel and return availability time if( (LMIC.opmode & OP_NEXTCHNL) != 0 ) { txbeg = LMIC.txend = LMICbandplan_nextTx(now); From b6d2be2a0f2b5dc10214d989a30849936fce21eb Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Tue, 29 Oct 2024 19:07:26 -0400 Subject: [PATCH 6/7] Fix #972: rename `is_busy()` to `hal_radio_spi_is_busy()` --- src/hal/hal.cpp | 13 +++++++++---- src/lmic/hal.h | 2 +- src/lmic/radio_sx126x.c | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/hal/hal.cpp b/src/hal/hal.cpp index 2a20e100..be5d5e56 100644 --- a/src/hal/hal.cpp +++ b/src/hal/hal.cpp @@ -192,11 +192,16 @@ static void hal_spi_init () { } #if (defined(CFG_sx1261_radio) || defined(CFG_sx1262_radio)) -bit_t is_busy() { +bit_t hal_radio_spi_is_busy() { // SX126x uses BUSY pin return digitalRead(pHalConfig->queryBusyPin()) ? true : false; } -#endif +#else +// supply a definition just in case, because the declaration is not conditional +bit_t hal_radio_spi_is_busy() { + return false; +} +#endif // (defined(CFG_sx1261_radio) || defined(CFG_sx1262_radio)) static void hal_spi_trx(u1_t cmd, u1_t* buf, size_t len, bit_t is_read) { uint32_t spi_freq; @@ -211,7 +216,7 @@ static void hal_spi_trx(u1_t cmd, u1_t* buf, size_t len, bit_t is_read) { // SX126x modems use BUSY pin. Only interact with SPI when BUSY goes LOW #if (defined(CFG_sx1261_radio) || defined(CFG_sx1262_radio)) - while (is_busy()); + while (hal_radio_spi_is_busy()); #endif SPI.transfer(cmd); @@ -248,7 +253,7 @@ void hal_spi_read_sx126x(u1_t cmd, u1_t* addr, size_t addr_len, u1_t* buf, size_ SPI.beginTransaction(settings); digitalWrite(nss, 0); - while (is_busy()); + while (hal_radio_spi_is_busy()); SPI.transfer(cmd); diff --git a/src/lmic/hal.h b/src/lmic/hal.h index 6195e2b0..fd92a840 100644 --- a/src/lmic/hal.h +++ b/src/lmic/hal.h @@ -191,7 +191,7 @@ uint8_t hal_getTxPowerPolicy( void hal_pollPendingIRQs_helper(); void hal_processPendingIRQs(void); -bit_t is_busy(); +bit_t hal_radio_spi_is_busy(); /// \brief check for any pending interrupts: stub if interrupts are enabled. static inline void hal_pollPendingIRQs(void) diff --git a/src/lmic/radio_sx126x.c b/src/lmic/radio_sx126x.c index 1b28cf2b..ec571fd9 100644 --- a/src/lmic/radio_sx126x.c +++ b/src/lmic/radio_sx126x.c @@ -766,7 +766,7 @@ void radio_config(void) { // Perform necessary operations from STDBY_RC mode if ((getStatus() | SX126x_GETSTATUS_CHIPMODE_MASK) != SX126x_CHIPMODE_STDBY_RC) { // Assume we've woken from sleep - while (is_busy()); + while (hal_radio_spi_is_busy()); setStandby(STDBY_RC); } @@ -1145,7 +1145,7 @@ int radio_init(void) { hal_waitUntil(os_getTime()+ms2osticks(1)); // wait >100us hal_pin_rst(2); // configure RST pin floating! hal_waitUntil(os_getTime()+ms2osticks(5)); // wait 5ms - while(is_busy()); // wait for busy pin to go low + while(hal_radio_spi_is_busy()); // wait for busy pin to go low // Check default LoRa sync word to verify the reset was successful u1_t syncWordMSB = readRegister(LoRaSyncWordMSB); From 975abaedd05eabf8709c1744f1510a81ca2e5623 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Tue, 29 Oct 2024 19:14:41 -0400 Subject: [PATCH 7/7] This is 4.2.0-pre3 --- src/lmic/lmic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lmic/lmic.h b/src/lmic/lmic.h index ba4d15a1..04ce416c 100644 --- a/src/lmic/lmic.h +++ b/src/lmic/lmic.h @@ -106,7 +106,7 @@ extern "C"{ ((((major)*UINT32_C(1)) << 24) | (((minor)*UINT32_C(1)) << 16) | (((patch)*UINT32_C(1)) << 8) | (((local)*UINT32_C(1)) << 0)) #define ARDUINO_LMIC_VERSION \ - ARDUINO_LMIC_VERSION_CALC(4, 2, 0, 2) /* 4.2.0-pre2 */ + ARDUINO_LMIC_VERSION_CALC(4, 2, 0, 3) /* 4.2.0-pre3 */ #define ARDUINO_LMIC_VERSION_GET_MAJOR(v) \ ((((v)*UINT32_C(1)) >> 24u) & 0xFFu)