Expand description
Fragmented data block transport, TS004-2.0.0.
A firmware image does not fit in a LoRaWAN frame, so it goes across in pieces. The server
cuts the block into nb_frag fragments of frag_size bytes and sends them one per
downlink, then keeps sending: every fragment after the first nb_frag is a coded one,
the exclusive-or of a pseudo-random half of the originals. A device that missed some of
the originals can solve for them from any nb_frag independent fragments it did hear, so
a session survives losses without anyone asking for a retransmission.
parity_lineandprbs23build the matrix rows those coded fragments come from.Fragmentercuts a block up and produces any fragment of the session, coded or not.Defragmenterputs one back together from whatever arrives, in storage the caller provides: it never allocates, and it tells you how much it needs.FragCommandcarries the session setup, status, delete and acknowledgment commands on portPORT, anddata_block_int_keywithBlockMiccheck the reassembled block against the code the setup carried.
The coded fragments a device must agree with its server about are seeded from the index among the coded fragments, not the index within the whole session. That is what Semtech’s LoRa Basics Modem and ChirpStack’s fragmentation server both do, and the two have to agree for any of this to work. The MATLAB in the specification’s appendix reads as though the whole-session index were the seed.
§Examples
A block goes across in five fragments, two are lost, and two coded fragments rebuild it:
use pamoja_lorawan::packages::fragment::{Defragmenter, Fragmenter};
let block = b"the quick brown fox jumps!";
let sender = Fragmenter::new(block, 6)?;
assert_eq!((sender.nb_frag(), sender.padding()), (5, 4));
let mut store = [0u8; 30];
let mut matrix = [0u8; 64];
let mut receiver = Defragmenter::new(sender.nb_frag(), 6, &mut store, &mut matrix)?;
// Fragments 3 and 4 never arrive; the coded ones that follow stand in for them.
let mut piece = [0u8; 6];
for n in [1, 2, 5, 6, 8] {
sender.fragment(n, &mut piece)?;
receiver.fragment(n, &piece)?;
}
assert!(receiver.done());
assert_eq!(&receiver.block()[..block.len()], block);Structs§
- Block
Mic - The integrity code over a whole data block, section 3.3.
- Block
MicKey - The cipher a block code is taken under, which the code borrows.
- Defragmenter
- Puts a data block back together from the fragments that arrive, TS004-2.0.0 appendix A.2.
- Fragmenter
- Cuts a data block into the fragments of a session, and builds the coded ones.
- Progress
- How far a fragmentation session has got, small enough to write down.
- Setup
Status - What a device makes of a session setup, table 14.
Enums§
- Frag
Command - One command of the fragmented data block transport package.
- Frag
Error - Why a fragmentation session could not be put back together.
Constants§
- MAX_
COMMAND - The longest command of this package other than a data fragment, in bytes.
- MAX_
FRAGMENTS - The most fragments one session carries, which the fourteen-bit index bounds.
- PACKAGE
- The identifier of this package, section 3.
- PORT
- The port the fragmented data block transport package is spoken on, section 3.
- SESSIONS
- How many fragmentation sessions a device may hold at once, section 3.3.
- VERSION
- The version of this package implemented here, section 3.
Functions§
- data_
block_ int_ key - Derives the key that signs a data block, section 3.3.
- parity_
line - Builds one row of the parity matrix: which uncoded fragments a coded one is made of.
- prbs23
- Steps the 23-bit pseudo-random sequence the parity matrix is drawn from, appendix A.1.