#lorawan #iot #iot-device

no-std lorawan-device

A Rust LoRaWAN device stack implementation

5 releases (breaking)

0.11.0 Sep 25, 2023
0.10.0 Apr 25, 2023
0.9.0 Apr 17, 2023
0.8.0 Aug 26, 2022
0.7.1 Apr 26, 2022

#152 in Hardware support

Download history 80/week @ 2023-08-17 51/week @ 2023-08-24 64/week @ 2023-08-31 74/week @ 2023-09-07 69/week @ 2023-09-14 119/week @ 2023-09-21 82/week @ 2023-09-28 196/week @ 2023-10-05 305/week @ 2023-10-12 119/week @ 2023-10-19 74/week @ 2023-10-26 81/week @ 2023-11-02 113/week @ 2023-11-09 120/week @ 2023-11-16 99/week @ 2023-11-23 57/week @ 2023-11-30

402 downloads per month


6.5K SLoC


Gitter chat

This is an experimental LoRaWAN device stack. It can be tested by using the example in the sx12xx-rs repository. You may also consider the example from the Drogue Device framework.

The device stack supports two modes, both designed for concurrency in non-threaded environments:

  • A state machine implementation based off an article by Ana Hobden.
  • An async-await implementation that can be used with async radio interfaces.

State machine implementation

There are two super-states that the Device can be in:

  • NoSession: default state upon initialization
  • Session: achieved after successful OTAA

A state machine diagram is provided in src/state_machines/session

The following LoRaWAN features are implemented:

  • Class A device behavior
  • Over-the-Air Activation (OTAA) and Activation by Personalization (ABP)
  • Regional support for US915, and EU868
  • Supports CFList in JoinAccept for EU868
  • the stack starts deriving a new session when the FCnt maxes out the 32-bit counter; new session may also be created by any time by the user, as long the stack is not mid-transmit
  • MAC commands are minimally mocked, as a ADRReq is responded with an ADRResp, but not much is done with the actual payload

The following design features are implemented:

  • a radio abstraction layer by the following traits defined here: radio::PhyRxTx + Timings
  • the radio::PhyRxTx trait enables a state machine design by the implementor
  • a pass through for the LoRaWAN crypto abstraction provided by the lorawan crate, paving the way for secure elements and other hardware peripherals
  • RX windows for data and join accepts are implemented by Timeouts which are passed by Response up to the user, minimizing borrowing or owning of such bindings by the library
  • Timeouts can be adjusted by the radio abstraction layer thanks to the Timing trait

This is a work in progress and the notable limitations are:

  • Class A behavior only, not B or C
  • no retries on Joins or Confirmed packets and the user is instead given NoAck and NoJoinAccept responses

Async implementation

The async implementation uses the async-await capabilities of Rust to drive the state machine. It differs from the state machine implementation in the following ways:

  • Join, send and send_recv are all async methods that can be awaited until the state transition is complete.
  • When a session is expired, a SessionExpired error will be returned when attempting to send data. A new call to join must be made to establish a new session.
  • The radio implementation is fully async
  • A trait for an asynchronous timer is defined and must be implemented to use the async stack
  • Uses the RngCore trait for random number generation

In terms of features, the async stack supports the same set of features as the state machine driven implementation.


~26K SLoC