#![allow(dead_code)]
mod header;
mod neighbor;
mod router;
mod seen;
pub use header::{MeshFlags, MeshHeader, MESH_HEADER_SIZE};
pub use neighbor::{Neighbor, NeighborTable};
pub use router::{MeshConfig, MeshRouter, RelayDecision};
pub use seen::SeenCache;
use crate::error::{Error, Result};
use crate::transport::Transport;
pub const MAX_TTL: u8 = 7;
pub const DEFAULT_TTL: u8 = 3;
pub struct MeshTransport<T: Transport, const NEIGHBORS: usize, const SEEN: usize> {
inner: T,
router: MeshRouter<NEIGHBORS, SEEN>,
node_id: u8,
seq: u16,
rx_buf: [u8; 256],
}
impl<T: Transport, const NEIGHBORS: usize, const SEEN: usize> MeshTransport<T, NEIGHBORS, SEEN> {
pub fn new(inner: T, node_id: u8, config: MeshConfig) -> Self {
Self {
inner,
router: MeshRouter::new(node_id, config),
node_id,
seq: 0,
rx_buf: [0u8; 256],
}
}
pub fn node_id(&self) -> u8 {
self.node_id
}
fn next_seq(&mut self) -> u16 {
let seq = self.seq;
self.seq = self.seq.wrapping_add(1);
seq
}
pub fn send_mesh(&mut self, payload: &[u8]) -> Result<()> {
if payload.len() > 255 - MESH_HEADER_SIZE {
return Err(Error::BufferTooSmall);
}
let header = MeshHeader {
src: self.node_id,
dst: 0xFF, seq: self.next_seq(),
ttl: self.router.config().default_ttl,
flags: MeshFlags::empty(),
hop_count: 0,
};
self.send_with_header(&header, payload)
}
pub fn send_to(&mut self, dest: u8, payload: &[u8]) -> Result<()> {
if payload.len() > 255 - MESH_HEADER_SIZE {
return Err(Error::BufferTooSmall);
}
let header = MeshHeader {
src: self.node_id,
dst: dest,
seq: self.next_seq(),
ttl: self.router.config().default_ttl,
flags: MeshFlags::empty(),
hop_count: 0,
};
self.send_with_header(&header, payload)
}
fn send_with_header(&mut self, header: &MeshHeader, payload: &[u8]) -> Result<()> {
let mut buf = [0u8; 256];
let header_len = header.encode(&mut buf)?;
let total_len = header_len + payload.len();
if total_len > buf.len() {
return Err(Error::BufferTooSmall);
}
buf[header_len..total_len].copy_from_slice(payload);
let locator = crate::rtps::Locator::udpv4([255, 255, 255, 255], 0);
self.inner.send(&buf[..total_len], &locator)?;
Ok(())
}
pub fn recv_mesh(&mut self, buf: &mut [u8]) -> Result<Option<(u8, usize)>> {
let (len, _locator) = match self.inner.try_recv(&mut self.rx_buf) {
Ok(result) => result,
Err(Error::ResourceExhausted) => return Ok(None),
Err(e) => return Err(e),
};
if len < MESH_HEADER_SIZE {
return Ok(None); }
let header = match MeshHeader::decode(&self.rx_buf[..len]) {
Ok(h) => h,
Err(_) => return Ok(None), };
let rssi = self.inner.last_rssi();
let decision = self.router.process_received(&header, rssi);
match decision {
RelayDecision::Deliver => {
let payload_start = MESH_HEADER_SIZE;
let payload_len = len - payload_start;
if payload_len > buf.len() {
return Err(Error::BufferTooSmall);
}
buf[..payload_len].copy_from_slice(&self.rx_buf[payload_start..len]);
Ok(Some((header.src, payload_len)))
}
RelayDecision::Relay(new_header) => {
let payload_start = MESH_HEADER_SIZE;
let payload_len = len - payload_start;
let is_for_us = header.dst == 0xFF || header.dst == self.node_id;
let should_deliver = is_for_us && payload_len <= buf.len();
if should_deliver {
buf[..payload_len].copy_from_slice(&self.rx_buf[payload_start..len]);
}
let mut relay_buf = [0u8; 256];
relay_buf[..payload_len].copy_from_slice(&self.rx_buf[payload_start..len]);
let _ = self.send_with_header(&new_header, &relay_buf[..payload_len]);
if should_deliver {
Ok(Some((header.src, payload_len)))
} else {
Ok(None)
}
}
RelayDecision::Drop => {
Ok(None)
}
}
}
pub fn neighbors(&self) -> &NeighborTable<NEIGHBORS> {
self.router.neighbors()
}
pub fn stats(&self) -> MeshStats {
self.router.stats()
}
pub fn inner_mut(&mut self) -> &mut T {
&mut self.inner
}
pub fn inner(&self) -> &T {
&self.inner
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct MeshStats {
pub tx_originated: u32,
pub tx_relayed: u32,
pub rx_delivered: u32,
pub rx_duplicate: u32,
pub rx_ttl_expired: u32,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::transport::NullTransport;
#[test]
fn test_mesh_transport_creation() {
let inner = NullTransport::default();
let config = MeshConfig::default();
let mesh: MeshTransport<_, 8, 32> = MeshTransport::new(inner, 1, config);
assert_eq!(mesh.node_id(), 1);
}
#[test]
fn test_mesh_sequence_increment() {
let inner = NullTransport::default();
let config = MeshConfig::default();
let mut mesh: MeshTransport<_, 8, 32> = MeshTransport::new(inner, 1, config);
assert_eq!(mesh.next_seq(), 0);
assert_eq!(mesh.next_seq(), 1);
assert_eq!(mesh.next_seq(), 2);
}
}