Skip to main content

Module fragment

Module fragment 

Source
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_line and prbs23 build the matrix rows those coded fragments come from.
  • Fragmenter cuts a block up and produces any fragment of the session, coded or not.
  • Defragmenter puts one back together from whatever arrives, in storage the caller provides: it never allocates, and it tells you how much it needs.
  • FragCommand carries the session setup, status, delete and acknowledgment commands on port PORT, and data_block_int_key with BlockMic check 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§

BlockMic
The integrity code over a whole data block, section 3.3.
BlockMicKey
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.
SetupStatus
What a device makes of a session setup, table 14.

Enums§

FragCommand
One command of the fragmented data block transport package.
FragError
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.