lorawan-device 0.8.0

A Rust LoRaWAN device stack implementation
Documentation

lorawan-device

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, EU868, and CN470
  • Supports CFList in JoinAccept for EU868 and CN470
  • 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.