Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
659ed40
Major rework for Secure Element support
terrillmoore May 27, 2020
e85c253
Add preliminary doxygen support
terrillmoore May 27, 2020
42fd308
Improve documents
terrillmoore Jun 2, 2020
12eee94
Improve constexpr to find root of file name
terrillmoore Jul 14, 2020
0166513
Fix typo in docs
terrillmoore Jul 14, 2020
3ff8ea7
LMIC should init secure element; add missing APIs
terrillmoore Jul 14, 2020
628f4f2
Fix typos in comments
terrillmoore Jul 14, 2020
a8b39af
Fix error (if input buffer diff than output buffer, NG)
terrillmoore Jul 19, 2020
58c506b
added function calls to get session keys from lmic secure element
dhineshkumarmcci Jul 22, 2020
b027b4d
implemented LMIC_SecureElement APIs to get session keys and modified …
dhineshkumarmcci Jul 22, 2020
868f6eb
replaced constant 0 with the defined constant
dhineshkumarmcci Jul 23, 2020
83015a7
replace constant 16 with sizeof data in the function call
dhineshkumarmcci Jul 23, 2020
db5b7e3
validate the keyselector in imeplementation of get session key APIs
dhineshkumarmcci Jul 23, 2020
8686b48
removed usage of LMIC.artKey and LMIC.nwkKey to store session keys fr…
dhineshkumarmcci Jul 23, 2020
ca2077e
Fix #578: Update README.md change log
terrillmoore Feb 19, 2022
cd8bb41
Fix #841: refer to bandplan for max Rx1DrOffset value
terrillmoore Feb 19, 2022
50de95c
Fix #208: Planning and first steps for Class C
terrillmoore Feb 19, 2022
658055c
Improve change log in README.md
terrillmoore Feb 26, 2022
741a49c
Adjust Doxygen settings; especially TYPEDEF_HIDES_STRUCT=NO
terrillmoore Feb 28, 2022
c381b43
Adapt patch from #481 b7bee3f @sualko
terrillmoore Feb 28, 2022
943d155
Fix #208: complete the Class C implementation
terrillmoore Feb 28, 2022
ab0180b
Update LMIC-FSM.pdf to match .cdd
terrillmoore Mar 5, 2022
8a3f6e1
Change deveui/appeui to 1/1
terrillmoore Mar 5, 2022
3a9a0c9
Fix #208: get proper message len when loading LMIC.radio.dataLen
terrillmoore Mar 5, 2022
03a1d20
Improve docs in assert-handler in compliance sketch
terrillmoore Mar 18, 2022
95a10d0
Display whether Class C is configured at startup
terrillmoore Mar 18, 2022
cd24678
compliance: enable class C during startup if configured
terrillmoore Mar 18, 2022
1bada6c
add LMIC_isConfiguredClassC() API
terrillmoore Mar 18, 2022
5c18f92
Remove unused OPMODE bit definition
terrillmoore Mar 18, 2022
ee02f5c
Don't clobber frame buffer for class B schedule computation
terrillmoore Jun 22, 2022
4cc884f
Fix GCC -Wall warning
terrillmoore Jun 22, 2022
c8143bb
Bug fix: Missing return <value> in non-void fns
terrillmoore Jun 22, 2022
33f9b4e
Bugfix: missing return <v> in SecureElement library
terrillmoore Jun 22, 2022
e5b9cc7
Lots of class-c debugging
terrillmoore Jul 28, 2022
b530f4e
Improve radio driver docs
terrillmoore May 31, 2023
ae3337f
Add Class C support to SX126x and SX127x radio drivers
Beetix Jan 28, 2026
6115ce1
Add Class C regression compile tests to CI
Beetix Jan 29, 2026
96bdabf
Update documentation for Class C support
Beetix Jan 29, 2026
e9921ec
Fix SX1262 radio driver and add regression tests
Beetix Jan 29, 2026
b2ab317
Fix Class C downlink decoding using wrong frame buffer
Beetix Mar 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,539 changes: 2,539 additions & 0 deletions Doxyfile

Large diffs are not rendered by default.

18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
- [Controlling use of interrupts](#controlling-use-of-interrupts)
- [Disabling PING](#disabling-ping)
- [Disabling Beacons](#disabling-beacons)
- [Enabling Class C](#enabling-class-c)
- [Enabling/Disabling Network Time Support](#enablingdisabling-network-time-support)
- [Rarely changed variables](#rarely-changed-variables)
- [Changing debug output](#changing-debug-output)
Expand Down Expand Up @@ -135,7 +136,7 @@ Raise a GitHub issue at [`github.com/mcci-catena/arduino-lmic`](https://github.c

## Features

The LMIC library provides a fairly complete LoRaWAN Class A and Class B
The LMIC library provides a fairly complete LoRaWAN Class A, Class B, and Class C
implementation, supporting the EU-868, US-915, AU-921, AS-923, and IN-866 bands. Only a limited
number of features was tested using this port on Arduino hardware, so be careful when using any of the untested features.

Expand All @@ -149,6 +150,7 @@ What certainly works:
- Over-the-air activation (OTAA / joining).
- Receiving downlink packets in the RX1 and RX2 windows.
- MAC command processing.
- Class C continuous reception (must be explicitly enabled at compile time and runtime).

What has not been tested:

Expand Down Expand Up @@ -333,6 +335,16 @@ Enabling beacon handling allows tracking of network time, and is required if you

By default, beacon support is included in the library.

### Enabling Class C

`#define LMIC_ENABLE_class_c 1`

If defined to a non-zero value, enables Class C continuous reception support. Class C devices keep the receiver active whenever not transmitting, allowing them to receive downlink messages at any time (not just during the RX1/RX2 windows after an uplink).

When enabled, you must also call `LMIC_enableClassC(1)` at runtime (typically in your `EV_JOINED` event handler) to activate Class C mode. See [doc/CLASS-C.md](doc/CLASS-C.md) for detailed usage information.

By default, Class C support is disabled (`LMIC_ENABLE_class_c` is 0) to minimize code size and RAM usage on constrained devices.

### Enabling/Disabling Network Time Support

`#define LMIC_ENABLE_DeviceTimeReq number /* boolean: 0 or non-zero */`
Expand Down Expand Up @@ -1014,6 +1026,10 @@ function uflt12f(rawUflt12)
- Initialize DHT sensor in ttn-abp-feather-us915-dht22 example ([#902](https://github.com/mcci-catena/arduino-lmic/pull/902))
- Fix configPower for sx1272 ([#894](https://github.com/mcci-catena/arduino-lmic/pull/894))
- Enable device time by request ([#840](https://github.com/mcci-catena/arduino-lmic/pull/840))
- Correct bug in MAC Rx1DrOffset error checking for regions other than US ([#841](https://github.com/mcci-catena/arduino-lmic/issues/841)). Thanks to @GitTibbe for finding this.
- Refactor the LMIC to enable secure element support ([#578](https://github.com/mcci-catena/arduino-lmic/issues/578)).
- Add Class C support ([#323](https://github.com/mcci-catena/arduino-lmic/issues/323)).
- Start resurrecting Doxygen support.

- v4.1.1 is a patch release.

Expand Down
34 changes: 32 additions & 2 deletions ci/platformio.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,21 @@ then
PLATFORMIO_BUILD_FLAGS='-D CFG_us915 -D CFG_sx1276_radio -D LMIC_ENABLE_DeviceTimeReq=0 -D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS' platformio ci --lib . --board heltec_wifi_lora_32 'examples/ttn-otaa/ttn-otaa.ino'
PLATFORMIO_BUILD_FLAGS='-D CFG_eu868 -D CFG_sx1276_radio -D LMIC_ENABLE_DeviceTimeReq=0 -D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS' platformio ci --lib . --board heltec_wifi_lora_32 'examples/ttn-otaa/ttn-otaa.ino'

# Compile "ttn-otaa" example with Class C enabled (SX1276 radio)
PLATFORMIO_BUILD_FLAGS='-D CFG_us915 -D CFG_sx1276_radio -D LMIC_ENABLE_class_c=1 -D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS' platformio ci --lib . --board heltec_wifi_lora_32 'examples/ttn-otaa/ttn-otaa.ino'
PLATFORMIO_BUILD_FLAGS='-D CFG_eu868 -D CFG_sx1276_radio -D LMIC_ENABLE_class_c=1 -D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS' platformio ci --lib . --board heltec_wifi_lora_32 'examples/ttn-otaa/ttn-otaa.ino'

# Compile "ttn-otaa" example with SX1262 radio
PLATFORMIO_BUILD_FLAGS='-D CFG_us915 -D CFG_sx1262_radio -D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS' platformio ci --lib . --board heltec_wifi_lora_32 'examples/ttn-otaa/ttn-otaa.ino'
PLATFORMIO_BUILD_FLAGS='-D CFG_eu868 -D CFG_sx1262_radio -D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS' platformio ci --lib . --board heltec_wifi_lora_32 'examples/ttn-otaa/ttn-otaa.ino'

# Compile "ttn-otaa" example with Class C enabled (SX1262 radio)
PLATFORMIO_BUILD_FLAGS='-D CFG_us915 -D CFG_sx1262_radio -D LMIC_ENABLE_class_c=1 -D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS' platformio ci --lib . --board heltec_wifi_lora_32 'examples/ttn-otaa/ttn-otaa.ino'
PLATFORMIO_BUILD_FLAGS='-D CFG_eu868 -D CFG_sx1262_radio -D LMIC_ENABLE_class_c=1 -D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS' platformio ci --lib . --board heltec_wifi_lora_32 'examples/ttn-otaa/ttn-otaa.ino'

# Compile "ttn-otaa" example with Class C and debug output
PLATFORMIO_BUILD_FLAGS='-D CFG_us915 -D CFG_sx1276_radio -D LMIC_ENABLE_class_c=1 -D LMIC_DEBUG_LEVEL=1 -D LMIC_PRINTF_TO=Serial -D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS' platformio ci --lib . --board heltec_wifi_lora_32 'examples/ttn-otaa/ttn-otaa.ino'

# Compile "ttn-otaa" example in US with debugging to Serial interface
PLATFORMIO_BUILD_FLAGS='-D COMPILE_REGRESSION_TEST -D LMIC_DEBUG_LEVEL=2 -D LMIC_PRINTF_TO=Serial' platformio ci --lib . --board heltec_wifi_lora_32 'examples/ttn-otaa/ttn-otaa.ino'

Expand Down Expand Up @@ -145,12 +160,27 @@ then

# Check build with deprecated CFG_au921 flag
PLATFORMIO_BUILD_FLAGS='-D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS -D CFG_au921 -D CFG_sx1276_radio' platformio ci --lib . --board feather32u4 'examples/ttn-otaa-feather-us915/ttn-otaa-feather-us915.ino'

# Compile with Class C enabled (US915 only - the feather-us915 example uses LMIC_selectSubBand)
PLATFORMIO_BUILD_FLAGS='-D COMPILE_REGRESSION_TEST -D LMIC_ENABLE_class_c=1' platformio ci --lib . --board feather32u4 'examples/ttn-otaa-feather-us915/ttn-otaa-feather-us915.ino'

elif [ "$TARGET" == "samd" ]
then
echo "WARNING: target '$TARGET' is not configured yet."
################################################################################
# TESTS FOR TARGET "samd", i.e. BOARD adafruit_feather_m0

# Compile "ttn-otaa" example with Class C enabled
PLATFORMIO_BUILD_FLAGS='-D CFG_us915 -D CFG_sx1276_radio -D LMIC_ENABLE_class_c=1 -D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS' platformio ci --lib . --board adafruit_feather_m0 'examples/ttn-otaa/ttn-otaa.ino'
PLATFORMIO_BUILD_FLAGS='-D CFG_eu868 -D CFG_sx1276_radio -D LMIC_ENABLE_class_c=1 -D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS' platformio ci --lib . --board adafruit_feather_m0 'examples/ttn-otaa/ttn-otaa.ino'

elif [ "$TARGET" == "stm32l0" ]
then
echo "WARNING: target '$TARGET' is not configured yet."
################################################################################
# TESTS FOR TARGET "stm32l0", i.e. BOARD disco_l072cz_lrwan1

# Compile "ttn-otaa" example with Class C enabled
PLATFORMIO_BUILD_FLAGS='-D CFG_us915 -D CFG_sx1276_radio -D LMIC_ENABLE_class_c=1 -D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS' platformio ci --lib . --board disco_l072cz_lrwan1 'examples/ttn-otaa/ttn-otaa.ino'
PLATFORMIO_BUILD_FLAGS='-D CFG_eu868 -D CFG_sx1276_radio -D LMIC_ENABLE_class_c=1 -D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS' platformio ci --lib . --board disco_l072cz_lrwan1 'examples/ttn-otaa/ttn-otaa.ino'
else
echo "ERROR: target '$TARGET' is not supported"
exit 1
Expand Down
186 changes: 186 additions & 0 deletions doc/CLASS-C.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
# Class C Support

This document describes the Class C implementation in the LMIC library.

## Overview

LoRaWAN Class C devices keep their receiver active whenever they are not transmitting. This allows them to receive downlink messages at any time, rather than only during the RX1 and RX2 windows after an uplink transmission (as with Class A devices).

Class C reception uses the RX2 channel parameters (frequency and spreading factor) for continuous reception.

## Enabling Class C

Class C support must be enabled at both compile time and runtime.

### Compile-time Configuration

Add the following to your `project_config/lmic_project_config.h`:

```c
#define LMIC_ENABLE_class_c 1
```

Or pass it as a build flag:

```shell
-D LMIC_ENABLE_class_c=1
```

**Note:** Class C support increases code size and RAM usage. Only enable it if your application requires Class C operation.

### Runtime Activation

After a successful OTAA join (or ABP session setup), call `LMIC_enableClassC()` to activate Class C mode:

```c
void onEvent(ev_t ev) {
switch(ev) {
case EV_JOINED:
// Enable Class C after successful join
LMIC_enableClassC(1);
break;
// ... other events
}
}
```

To disable Class C mode and return to Class A operation:

```c
LMIC_enableClassC(0);
```

## API Reference

### LMIC_isConfiguredClassC()

```c
static inline bit_t LMIC_isConfiguredClassC(void);
```

Returns `1` if Class C support is compiled in (`LMIC_ENABLE_class_c` is non-zero), `0` otherwise. This is a compile-time check that can be used for conditional code.

### LMIC_enableClassC()

```c
bit_t LMIC_enableClassC(bit_t fOnIfTrue);
```

Enables or disables Class C mode at runtime.

- **Parameters:**
- `fOnIfTrue`: Set to `1` to enable Class C, `0` to disable.
- **Returns:** The previous state (1 if Class C was enabled, 0 if disabled).

When Class C is enabled:
- The radio will start continuous reception on the RX2 channel after completing any Class A transaction.
- Downlink messages can be received at any time when the device is not transmitting.

When Class C is disabled:
- The device returns to Class A operation.
- The radio is only active during scheduled RX windows after uplink transmissions.

### LMIC_txrxFlags_isClassC()

```c
static inline bit_t LMIC_txrxFlags_isClassC(u1_t flags);
```

Checks if the received message was a Class C downlink (received outside the normal RX1/RX2 windows).

- **Parameters:**
- `flags`: The `LMIC.txrxFlags` value.
- **Returns:** `1` if this was a Class C reception, `0` otherwise.

Example usage in event handler:

```c
case EV_RXCOMPLETE:
if (LMIC_txrxFlags_isClassC(LMIC.txrxFlags)) {
// This was a Class C downlink
Serial.println("Class C downlink received!");
}
// Process LMIC.frame, LMIC.dataLen, etc.
break;
```

## Example Usage

```c
#include <arduino_lmic.h>

void onEvent(ev_t ev) {
switch(ev) {
case EV_JOINED:
Serial.println("Joined network");
// Enable Class C after successful join
if (LMIC_isConfiguredClassC()) {
LMIC_enableClassC(1);
Serial.println("Class C enabled");
}
break;

case EV_RXCOMPLETE:
Serial.print("Received ");
Serial.print(LMIC.dataLen);
Serial.println(" bytes");

if (LMIC_txrxFlags_isClassC(LMIC.txrxFlags)) {
Serial.println("(Class C downlink)");
}

// Process received data
for (int i = 0; i < LMIC.dataLen; i++) {
Serial.print(LMIC.frame[LMIC.dataBeg + i], HEX);
Serial.print(" ");
}
Serial.println();
break;

// ... handle other events
}
}
```

## Power Considerations

Class C operation significantly increases power consumption because the radio receiver is continuously active. This makes Class C unsuitable for battery-powered devices that need long battery life. Class C is typically used for:

- Mains-powered devices
- Devices requiring low-latency downlink communication
- Actuators that need to respond quickly to commands

## Known Limitations

- **Class B Interaction:** Class C and Class B features should not be used simultaneously.
- **Frame Counters:** As with all LoRaWAN operation, frame counters must be preserved across reboots for production deployments.

## Building for Class C

### Arduino IDE

Add to your `project_config/lmic_project_config.h`:

```c
#define CFG_us915 1 // or your region
#define CFG_sx1276_radio 1 // SX1276 recommended for Class C
#define LMIC_ENABLE_class_c 1
```

### PlatformIO

Add to your `platformio.ini`:

```ini
build_flags =
-D CFG_us915=1
-D CFG_sx1276_radio=1
-D LMIC_ENABLE_class_c=1
```

Or to compile with Class C and test:

```bash
PLATFORMIO_BUILD_FLAGS='-D CFG_us915 -D CFG_sx1276_radio -D LMIC_ENABLE_class_c=1 -D COMPILE_REGRESSION_TEST -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS' \
platformio ci --lib . --board heltec_wifi_lora_32 'examples/ttn-otaa/ttn-otaa.ino'
```
Loading