radio/
lib.rs

1//! Abstract packet radio interfaces
2//!
3//! This package defines traits for packet radio devices, as well as blocking and async
4//! implementations using these traits, and a mock device to support application level testing.
5//!
6//! ## <https://github.com/rust-iot/radio-hal>
7//! ## Copyright 2020-2022 Ryan Kurte
8
9// Set `no_std` where `std` feature is disabled
10#![cfg_attr(not(feature = "std"), no_std)]
11
12use core::convert::TryFrom;
13use core::fmt::Debug;
14
15pub mod blocking;
16pub mod config;
17
18#[cfg(feature = "helpers")]
19pub mod helpers;
20#[cfg(feature = "mock")]
21pub mod mock;
22#[cfg(feature = "nonblocking")]
23pub mod nonblocking;
24
25/// Radio trait combines Base, Configure, Send and Receive for a generic radio object
26pub trait Radio: Transmit + Receive + State {}
27
28/// Transmit trait for radios that can transmit packets
29///
30/// `start_transmit` should be called to load data into the radio, with `check_transmit` called
31/// periodically (or using interrupts) to continue and finalise the transmission.
32pub trait Transmit {
33    /// Radio error
34    type Error: Debug;
35
36    /// Start sending a packet on the provided channel
37    ///
38    /// Returns an error if send was not started
39    fn start_transmit(&mut self, data: &[u8]) -> Result<(), Self::Error>;
40
41    /// Check for send completion
42    ///
43    /// Returns true for send complete, false otherwise
44    fn check_transmit(&mut self) -> Result<bool, Self::Error>;
45}
46
47/// Receive trait for radios that can receive packets
48///
49/// `start_receive` should be used to setup the radio in receive mode, with `check_receive` called
50/// periodically (or using interrupts) to poll for packet reception. Once a packet has been received,
51/// `get_received` fetches the received packet (and associated info) from the radio.
52pub trait Receive {
53    /// Radio error
54    type Error: Debug;
55    /// Packet received info
56    type Info: ReceiveInfo;
57
58    /// Set receiving on the specified channel
59    ///
60    /// Returns an error if receive mode was not entered
61    fn start_receive(&mut self) -> Result<(), Self::Error>;
62
63    /// Check for reception
64    ///
65    /// The restart flag indicates on (recoverable) error conditions (such as invalid CRC)
66    /// the radio should re-enter receive mode if required and continue reception.
67    ///
68    /// This returns true for received, false for not received, or the provided error
69    fn check_receive(&mut self, restart: bool) -> Result<bool, Self::Error>;
70
71    /// Fetch a received packet if rx is complete
72    ///
73    /// This copies received data into the provided buffer and returns the number of bytes received
74    /// as well as information about the received packet
75    fn get_received(&mut self, buff: &mut [u8]) -> Result<(usize, Self::Info), Self::Error>;
76}
77
78/// ReceiveInfo trait for receive information objects
79///
80/// This sup[ports the constraint of generic `Receive::Info`, allowing generic middleware
81/// to access the rssi of received packets
82pub trait ReceiveInfo: Debug + Default {
83    fn rssi(&self) -> i16;
84}
85
86/// Default / Standard packet information structure for radio devices that provide only rssi
87/// and lqi information
88#[derive(Debug, Clone, PartialEq)]
89pub struct BasicInfo {
90    /// Received Signal Strength Indicator (RSSI) of received packet in dBm
91    rssi: i16,
92    /// Link Quality Indicator (LQI) of received packet
93    lqi: u16,
94}
95
96impl Default for BasicInfo {
97    fn default() -> Self {
98        Self {
99            rssi: core::i16::MIN,
100            lqi: core::u16::MIN,
101        }
102    }
103}
104
105impl BasicInfo {
106    pub fn new(rssi: i16, lqi: u16) -> Self {
107        Self { rssi, lqi }
108    }
109}
110
111/// Default / Standard radio channel object for radio devices with simple integer channels
112impl ReceiveInfo for BasicInfo {
113    fn rssi(&self) -> i16 {
114        self.rssi
115    }
116}
117
118/// Default / Standard radio channel object for radio devices with integer channels
119#[derive(Debug, Clone, PartialEq)]
120pub struct BasicChannel(pub u16);
121
122impl From<u16> for BasicChannel {
123    fn from(u: u16) -> Self {
124        BasicChannel(u)
125    }
126}
127
128impl From<BasicChannel> for u16 {
129    fn from(val: BasicChannel) -> Self {
130        val.0
131    }
132}
133
134/// Channel trait for configuring radio channelization
135pub trait Channel {
136    /// Channel information
137    type Channel: Debug;
138    /// Radio error type
139    type Error: Debug;
140
141    /// Set the radio channel for future transmit and receive operations
142    fn set_channel(&mut self, channel: &Self::Channel) -> Result<(), Self::Error>;
143}
144
145/// Power trait for configuring radio power
146pub trait Power {
147    /// Radio error type
148    type Error: Debug;
149
150    /// Set the radio power in dBm
151    fn set_power(&mut self, power: i8) -> Result<(), Self::Error>;
152}
153
154/// Rssi trait allows polling for RSSI on the current channel
155///
156/// Note that the radio should be in receive mode prior to polling for this.
157pub trait Rssi {
158    /// Radio error
159    type Error: Debug;
160
161    /// Fetch the current RSSI value from the radio
162    /// Note that the radio MUST be in RX mode (or capable of measuring RSSI) when this is called
163    /// or an error should be returned
164    fn poll_rssi(&mut self) -> Result<i16, Self::Error>;
165}
166
167/// State trait for configuring and reading radio states
168///
169/// Note that drivers will internally configure and read radio states to manage
170/// radio operations.
171pub trait State {
172    /// Radio state
173    type State: RadioState;
174    /// Radio error type
175    type Error: Debug;
176
177    /// Set the radio to a specified state
178    fn set_state(&mut self, state: Self::State) -> Result<(), Self::Error>;
179
180    /// Fetch the current radio state
181    fn get_state(&mut self) -> Result<Self::State, Self::Error>;
182}
183
184pub trait RadioState: Debug {
185    fn idle() -> Self;
186
187    fn sleep() -> Self;
188}
189
190/// Busy trait for checking whether the radio is currently busy
191/// and should not be interrupted
192pub trait Busy {
193    /// Radio error type
194    type Error: Debug;
195
196    /// Indicates the radio is busy in the current state
197    /// (for example, currently transmitting or receiving)
198    fn is_busy(&mut self) -> Result<bool, Self::Error>;
199}
200
201/// Interrupts trait allows for reading interrupt state from the device,
202/// as well as configuring interrupt pins.
203///
204/// Note that drivers may internally use interrupts and interrupt states
205/// to manage radio operations.
206pub trait Interrupts {
207    /// Interrupt object
208    type Irq: Debug;
209    /// Radio error
210    type Error: Debug;
211
212    /// Fetch any pending interrupts from the device
213    /// If the clear option is set, this will also clear any returned flags
214    fn get_interrupts(&mut self, clear: bool) -> Result<Self::Irq, Self::Error>;
215}
216
217/// Register contains the address and value of a register.
218///
219/// It is primarily intended as a type constraint for the [Registers] trait.
220pub trait Register:
221    Copy + TryFrom<Self::Word, Error = <Self as Register>::Error> + Into<Self::Word>
222{
223    type Word;
224    type Error;
225    const ADDRESS: u8;
226}
227
228/// Registers trait provides register level access to the radio device.
229///
230/// This is generally too low level for use by higher abstractions, however,
231/// is provided for completeness.
232pub trait Registers<Word> {
233    type Error: Debug;
234
235    /// Read a register value
236    fn read_register<R: Register<Word = Word>>(&mut self) -> Result<R, Self::Error>;
237
238    /// Write a register value
239    fn write_register<R: Register<Word = Word>>(&mut self, value: R) -> Result<(), Self::Error>;
240
241    /// Update a register value
242    fn update_register<R: Register<Word = Word>, F: Fn(R) -> R>(
243        &mut self,
244        f: F,
245    ) -> Result<R, Self::Error> {
246        let existing = self.read_register()?;
247        let updated = f(existing);
248        self.write_register(updated)?;
249        Ok(updated)
250    }
251}
252
253#[cfg(feature = "std")]
254use std::str::FromStr;
255
256#[cfg(feature = "std")]
257fn duration_from_str(s: &str) -> Result<core::time::Duration, humantime::DurationError> {
258    let d = humantime::Duration::from_str(s)?;
259    Ok(*d)
260}
261
262#[cfg(test)]
263mod tests {
264    use crate::{Register, Registers};
265
266    use core::convert::{Infallible, TryInto};
267
268    #[derive(Clone, Copy, Debug, PartialEq)]
269    struct TestRegister1 {
270        value: u8,
271    }
272
273    impl From<u8> for TestRegister1 {
274        fn from(value: u8) -> Self {
275            Self { value }
276        }
277    }
278
279    impl From<TestRegister1> for u8 {
280        fn from(reg: TestRegister1) -> Self {
281            reg.value
282        }
283    }
284
285    impl Register for TestRegister1 {
286        type Word = u8;
287        type Error = Infallible;
288        const ADDRESS: u8 = 0;
289    }
290
291    #[derive(Clone, Copy, Debug, PartialEq)]
292    struct TestRegister2 {
293        value: [u8; 2],
294    }
295
296    impl From<[u8; 2]> for TestRegister2 {
297        fn from(value: [u8; 2]) -> Self {
298            Self { value }
299        }
300    }
301
302    impl From<TestRegister2> for [u8; 2] {
303        fn from(reg: TestRegister2) -> Self {
304            reg.value
305        }
306    }
307
308    impl Register for TestRegister2 {
309        type Word = [u8; 2];
310        type Error = Infallible;
311        const ADDRESS: u8 = 1;
312    }
313
314    struct TestDevice {
315        device_register: [u8; 3],
316    }
317
318    impl Registers<u8> for TestDevice {
319        type Error = ();
320        fn read_register<R: Register<Word = u8>>(&mut self) -> Result<R, Self::Error> {
321            self.device_register[R::ADDRESS as usize]
322                .try_into()
323                .map_err(|_| ())
324        }
325
326        fn write_register<R: Register<Word = u8>>(&mut self, value: R) -> Result<(), Self::Error> {
327            self.device_register[R::ADDRESS as usize] = value.into();
328            Ok(())
329        }
330    }
331
332    impl Registers<[u8; 2]> for TestDevice {
333        type Error = ();
334        fn read_register<R: Register<Word = [u8; 2]>>(&mut self) -> Result<R, Self::Error> {
335            let addr = R::ADDRESS as usize;
336            let mut result = [0u8; 2];
337            result.copy_from_slice(&self.device_register[addr..addr + 2]);
338            result.try_into().map_err(|_| ())
339        }
340
341        fn write_register<R: Register<Word = [u8; 2]>>(
342            &mut self,
343            value: R,
344        ) -> Result<(), Self::Error> {
345            let addr = R::ADDRESS as usize;
346            self.device_register[addr..addr + 2].copy_from_slice(&value.into());
347            Ok(())
348        }
349    }
350
351    #[test]
352    fn update_register1() {
353        let mut device = TestDevice {
354            device_register: [0; 3],
355        };
356        device.write_register(TestRegister1 { value: 1 }).unwrap();
357        device
358            .update_register(|r: TestRegister1| (if r.value == 1 { 2 } else { 3 }).into())
359            .unwrap();
360        assert_eq!(
361            device.read_register::<TestRegister1>().unwrap(),
362            TestRegister1 { value: 2 }
363        );
364    }
365
366    #[test]
367    fn update_register2() {
368        let mut device = TestDevice {
369            device_register: [0; 3],
370        };
371        device
372            .write_register(TestRegister2 { value: [1, 2] })
373            .unwrap();
374        device
375            .update_register(|r: TestRegister2| {
376                (if r.value == [1, 2] { [2, 3] } else { [3, 4] }).into()
377            })
378            .unwrap();
379        assert_eq!(
380            device.read_register::<TestRegister2>().unwrap(),
381            TestRegister2 { value: [2, 3] }
382        );
383    }
384}