Skip to main content

Module mesh

Module mesh 

Source
Expand description

A pamoja transport over a LoRa radio, carrying topics in pamoja-mesh frames.

MeshRadio turns a radio into a [Transport] and a [Receive]. A message goes out as a broadcast [Frame] whose payload is the topic’s length in one byte, the topic, and the payload. Every node that hears it drops copies it has already seen, delivers what its subscriptions match, and relays the frame onward while hops remain, so a message crosses a mesh of radios that each hear only their neighbors. A DutyCycle holds the radio silent for the off time the region requires after each transmission, its own messages and its relays alike.

The radio is driven from the task that awaits the transport. It is read every POLL, with the tokio timer sleeping in between, so neither a frame’s airtime nor a quiet channel blocks the runtime. Topic filters follow MQTT, through [topic_matches].

§Examples

Two nodes whose air is a queue each, with the frame carried across by hand:

use std::collections::VecDeque;
use std::convert::Infallible;

use pamoja_core::{Receive, Transport};
use pamoja_lora::LinkSettings;
use pamoja_radios::mesh::{LoraRadio, MeshRadio};

#[derive(Default)]
struct Air(VecDeque<Vec<u8>>);

impl LoraRadio for Air {
    type Error = Infallible;

    fn link(&self) -> Option<LinkSettings> {
        Some(LinkSettings::new(7, 125_000))
    }

    fn start_transmit(&mut self, frame: &[u8]) -> Result<u64, Infallible> {
        self.0.push_back(frame.to_vec());
        Ok(LinkSettings::new(7, 125_000).airtime_us(frame.len()))
    }

    fn finish_transmit(&mut self) -> Result<bool, Infallible> {
        Ok(true)
    }

    fn listen(&mut self) -> Result<(), Infallible> {
        Ok(())
    }

    fn take_frame(&mut self, buffer: &mut [u8]) -> Result<Option<usize>, Infallible> {
        Ok(self.0.pop_front().map(|frame| {
            buffer[..frame.len()].copy_from_slice(&frame);
            frame.len()
        }))
    }
}

// A soil sensor on a 1% duty cycle, and a gateway that listens without relaying.
let mut sensor = MeshRadio::new(Air::default(), 0x0A, 10);
let mut gateway = MeshRadio::new(Air::default(), 0x0B, 10).without_relaying();
sensor.connect().await?;
gateway.connect().await?;
gateway.subscribe("garden/+/moisture").await?;

sensor.send_text("garden/bed-1/moisture", "28.5").await?;
let frame = sensor.radio_mut().0.pop_front().expect("the sensor transmitted");
gateway.radio_mut().0.push_back(frame);

let reading = gateway.recv().await?.expect("the gateway heard it");
assert_eq!(reading.topic, "garden/bed-1/moisture");
assert_eq!(reading.number()?, 28.5);

Structs§

MeshRadio
A node on a LoRa mesh: a radio, the node’s address, and the rules it keeps.

Constants§

MAX_MESSAGE
The most topic and payload bytes one message carries together: a frame’s payload less the byte that holds the topic’s length.
POLL
How often the transport reads the radio for a received frame or a finished transmission.
SEEN_CAPACITY
How many recent frames a node remembers, so copies arriving by other paths are dropped.
TRANSMIT_GRACE
How long past a frame’s airtime the transport waits for the radio to report it sent.

Traits§

LoraRadio
A radio a MeshRadio carries frames over.