Skip to main content

hdds_micro/transport/
mod.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2// Copyright (c) 2025-2026 naskel.com
3
4//! Transport abstraction for HDDS Micro
5//!
6//! Defines a generic transport trait that can be implemented for:
7//! - WiFi UDP (ESP32, RP2040W)
8//! - LoRa (SX1276/78)
9//! - Serial (UART, USB CDC)
10//! - CAN bus
11//!
12//! ## Design Principles
13//!
14//! - **No heap allocations** - uses fixed buffers
15//! - **Blocking I/O** - simpler for embedded (async optional via features)
16//! - **Zero-copy** - borrow slices instead of copying
17//! - **Error handling** - Result-based, no panics
18
19use crate::error::{Error, Result};
20use crate::rtps::Locator;
21
22pub mod cc1101;
23pub mod hc12;
24pub mod lora;
25pub mod mesh;
26pub mod nrf24;
27pub mod udp;
28
29pub use cc1101::{Cc1101Band, Cc1101Config, Cc1101DataRate, Cc1101Power, Cc1101Transport};
30pub use mesh::{MeshConfig, MeshHeader, MeshStats, MeshTransport};
31pub use nrf24::{Nrf24Config, Nrf24DataRate, Nrf24Power, Nrf24Transport};
32
33/// Transport trait for sending/receiving RTPS packets
34///
35/// Implementors must handle:
36/// - Network initialization
37/// - Packet send/receive
38/// - Address translation (Locator <-> platform-specific address)
39pub trait Transport {
40    /// Initialize transport
41    ///
42    /// Called once during participant setup.
43    fn init(&mut self) -> Result<()>;
44
45    /// Send packet to destination
46    ///
47    /// # Arguments
48    ///
49    /// * `data` - RTPS packet (header + submessages)
50    /// * `dest` - Destination locator
51    ///
52    /// # Returns
53    ///
54    /// Number of bytes sent
55    fn send(&mut self, data: &[u8], dest: &Locator) -> Result<usize>;
56
57    /// Receive packet (blocking)
58    ///
59    /// # Arguments
60    ///
61    /// * `buf` - Buffer to receive into (must be >= MAX_PACKET_SIZE)
62    ///
63    /// # Returns
64    ///
65    /// (bytes_received, source_locator)
66    fn recv(&mut self, buf: &mut [u8]) -> Result<(usize, Locator)>;
67
68    /// Receive packet (non-blocking)
69    ///
70    /// Returns `Err(Error::ResourceExhausted)` if no packet available.
71    fn try_recv(&mut self, buf: &mut [u8]) -> Result<(usize, Locator)>;
72
73    /// Get local locator (own address)
74    fn local_locator(&self) -> Locator;
75
76    /// Get MTU (maximum transmission unit)
77    fn mtu(&self) -> usize;
78
79    /// Get last received packet RSSI (for radio transports)
80    ///
81    /// Returns None if RSSI is not available (e.g., UDP transport).
82    fn last_rssi(&self) -> Option<i16> {
83        None
84    }
85
86    /// Shutdown transport
87    fn shutdown(&mut self) -> Result<()>;
88}
89
90/// Null transport (for testing)
91///
92/// Discards all packets, never receives anything.
93pub struct NullTransport {
94    local_locator: Locator,
95}
96
97impl NullTransport {
98    /// Create a new null transport
99    pub const fn new(local_locator: Locator) -> Self {
100        Self { local_locator }
101    }
102}
103
104impl Default for NullTransport {
105    fn default() -> Self {
106        Self {
107            local_locator: Locator::udpv4([127, 0, 0, 1], 7400),
108        }
109    }
110}
111
112impl Transport for NullTransport {
113    fn init(&mut self) -> Result<()> {
114        Ok(())
115    }
116
117    fn send(&mut self, data: &[u8], _dest: &Locator) -> Result<usize> {
118        // Discard packet
119        Ok(data.len())
120    }
121
122    fn recv(&mut self, _buf: &mut [u8]) -> Result<(usize, Locator)> {
123        // Never receive anything
124        Err(Error::TransportError)
125    }
126
127    fn try_recv(&mut self, _buf: &mut [u8]) -> Result<(usize, Locator)> {
128        Err(Error::ResourceExhausted)
129    }
130
131    fn local_locator(&self) -> Locator {
132        self.local_locator
133    }
134
135    fn mtu(&self) -> usize {
136        1024
137    }
138
139    fn shutdown(&mut self) -> Result<()> {
140        Ok(())
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147
148    #[test]
149    fn test_null_transport() {
150        let mut transport = NullTransport::default();
151
152        transport.init().unwrap();
153
154        let data = b"hello";
155        let dest = Locator::udpv4([192, 168, 1, 100], 7400);
156        let sent = transport.send(data, &dest).unwrap();
157        assert_eq!(sent, data.len());
158
159        let mut buf = [0u8; 64];
160        let result = transport.try_recv(&mut buf);
161        assert_eq!(result, Err(Error::ResourceExhausted));
162    }
163}