Skip to main content

Module device

Module device 

Source
Expand description

A LoRaWAN Class A end device, without a radio.

EndDevice is what a node runs to take part in a network: it joins, chooses a channel and data rate for each uplink, says when and where to listen for the answer, reads what comes back, and does what the network’s MAC commands ask. It owns no radio and no clock. Every step takes the time in microseconds and hands back what to put on the air, so the same logic drives an SX1276 on a microcontroller, an SX1262 on a Linux board, or a test with no hardware at all.

One exchange runs like this:

  1. join or send returns a Transmission: the frame, the carrier, the link, the power, and the two receive windows, each timed from the end of the transmission.
  2. The radio sends it, then listens in the first window and, if nothing for this device arrived, in the second.
  3. A frame heard in either window goes to heard_in, which knows the window, or to heard. If neither window held one, nothing_heard says whether to send the same frame again, with repeat, or move on.

What it follows, and from where:

  • Receive windows: TS001-1.0.4 section 3.3 and RP002-1.0.5 section 3.3, one second and two after an uplink and five and six after a join request unless the network moves them.
  • Channels and data rates: the region’s plan from pamoja-lora, a join accept’s channel list, and LinkADRReq, NewChannelReq and DlChannelReq. A fixed plan answers each channel on the downlink channel it names, and reads ChMaskCntl by its own table.
  • Joining: a random join channel with the data rate stepping down across attempts, or on US902-928 and AU915-928 the passes of RP002-1.0.5 section 3.5.2, eight 125 kHz channels from successive groups and then a 500 kHz one. On CN470-510 the common join channel that answered puts the device on its plan, section 3.9.2.
  • MAC commands: every command of TS001-1.0.4 section 5 a device receives, answered in order, with the four that change how it listens repeated until a downlink arrives.
  • Downlinks: TS001-1.0.4 section 4, with a frame whose MACPayload is longer than the receive window’s data rate carries discarded, and a repeated counter ignored.
  • Repetition: NbTrans transmissions of each uplink, stopped by any Class A downlink, and a retransmission timeout before the next uplink whenever a confirmed one went unacknowledged.
  • Staying reachable: the adaptive data rate back-off of adr.
  • Sharing the air: the region’s sub-band duty cycles, the network’s DutyCycleReq, and the join back-off of TS001-1.0.4 section 7.
  • Sleeping: save and resume carry a joined device across a loss of power, so a node that sleeps between readings keeps its session, its counters and everything its network set.
  • Out of a gateway’s reach: use_relay sends through a LoRaWAN relay, TS011-1.0.1. Each uplink then goes out behind a wake-on-radio frame, Transmission::relay says when and with how long a preamble, and a third receive window carries what the relay forwards back.

This covers every published plan: the dynamic EU868, EU433, AS923, KR920, IN865 and RU864, and the fixed US915, AU915 and CN470, the last in all four of its RP002-1.0.5 plans and the 96-channel plan before them. KR920, CN470, and AS923 where ARIB STD-T108 applies also require listening before talking, which is the radio’s to do.

§Examples

A device joins a European network the test plays the part of:

use pamoja_lora::region::Region;
use pamoja_lorawan::device::{EndDevice, Heard, Settings};
use pamoja_lorawan::{Device, JoinGrant};

const APP_KEY: [u8; 16] = [0x2B; 16];
let credentials = Device::new([0x11; 8], [0x22; 8], APP_KEY);
let mut device = EndDevice::new(Region::Eu868.plan(), credentials, Settings::new(2, 14))?;

// The request goes out on a European default channel, and the answer is due five and
// six seconds after it.
let request = device.join(1, 0)?;
assert!([868_100_000, 868_300_000, 868_500_000].contains(&request.frequency_hz));
assert_eq!(request.rx1.delay_us, 5_000_000);
assert_eq!(request.rx2.frequency_hz, 869_525_000);

// The network's accept arrives in the first window.
let accept = JoinGrant::new(0x01, 0x13, 0x2601_2E43).accept(&APP_KEY, 1);
let heard = device.heard(accept.as_bytes(), 7)?;
assert_eq!(heard, Heard::Joined { dev_addr: 0x2601_2E43 });

// And the first reading goes out, answered a second after it ends.
let reading = device.send(2, b"21.5", false, 7_000_000)?;
assert_eq!(reading.rx1.delay_us, 1_000_000);
assert!(reading.carries_payload);

Structs§

AckWindow
When and where a relay’s acknowledgment would arrive.
Channel
One channel a device can transmit on.
Delivery
A downlink, read and acted on.
DeviceTime
The time a network gave a device.
EndDevice
A LoRaWAN Class A end device.
LinkCheck
How well the network heard a link check.
RelayExchange
The wake-on-radio exchange an uplink under a relay goes out behind.
RelayStatus
What a relay’s last acknowledgment said about itself, TS011-1.0.1 table 14.
Saved
A device’s state as bytes to keep across a loss of power.
Settings
What a device’s radio can do, and how it takes part.
Transmission
A frame to put on the air, and where to listen afterward.
WakeUp
The wake-on-radio frame an uplink goes out behind, and where it is heard, TS011-1.0.1 section 5.
Window
When and where to listen for a downlink.

Enums§

Battery
How a device reports its battery when a network asks.
DeviceError
Why a device could not do what it was asked.
Heard
What a frame heard in a receive window turned out to be.
Next
What to do once both receive windows have closed with nothing for the device.
ReceiveWindow
Which receive window a frame arrived in.
StateError
Why a saved state could not be resumed.
WorNext
What an end device does once its wake-on-radio frame went unanswered.

Constants§

MAX_CHANNELS
How many channels a device keeps.
SAVED_LEN
How many bytes a saved state takes.