ebyte_e32/parameters/
mod.rs

1pub use self::{
2    air_baudrate::AirBaudRate,
3    baudrate::BaudRate,
4    option::{
5        fec_mode::ForwardErrorCorrectionMode, io_drive_mode::IoDriveMode,
6        transmission_power::TransmissionPower, wakeup_time::WakeupTime, TransmissionMode,
7    },
8    uart_parity::Parity,
9};
10pub use error::Error;
11pub use typed_builder::TypedBuilder;
12
13#[cfg(feature = "value_enum")]
14use clap::ValueEnum;
15
16mod air_baudrate;
17mod baudrate;
18mod error;
19mod option;
20mod uart_parity;
21
22#[cfg(test)]
23mod read;
24#[cfg(test)]
25mod write;
26
27#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
28#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
29#[cfg_attr(feature = "value_enum", derive(ValueEnum))]
30pub enum Persistence {
31    #[default]
32    Temporary,
33    Permanent,
34}
35
36#[mutants::skip]
37impl From<Persistence> for u8 {
38    fn from(mode: Persistence) -> Self {
39        match mode {
40            Persistence::Temporary => 0xC2,
41            Persistence::Permanent => 0xC0,
42        }
43    }
44}
45
46#[derive(Clone, Debug, PartialEq, Eq, TypedBuilder)]
47#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
48pub struct Parameters {
49    pub address: u16,
50    pub channel: u8,
51    #[builder(default)]
52    pub uart_parity: Parity,
53    #[builder(default)]
54    pub uart_rate: BaudRate,
55    #[builder(default)]
56    pub air_rate: AirBaudRate,
57    #[builder(default)]
58    pub transmission_mode: TransmissionMode,
59    #[builder(default)]
60    pub io_drive_mode: IoDriveMode,
61    #[builder(default)]
62    pub wakeup_time: WakeupTime,
63    #[builder(default)]
64    pub fec: ForwardErrorCorrectionMode,
65    #[builder(default)]
66    pub transmission_power: TransmissionPower,
67}
68
69impl Parameters {
70    pub fn to_bytes(&self) -> [u8; 5] {
71        let mut bytes = [0u8; 5];
72        bytes[0] = ((0xFF00 & self.address) >> 8) as u8;
73        bytes[1] = (0x00FF & self.address) as u8;
74
75        let parity = u8::from(self.uart_parity);
76        let uart_rate = u8::from(self.uart_rate);
77        let air_rate = u8::from(self.air_rate);
78        let speed_byte = (parity << 6) | (uart_rate << 3) | air_rate;
79        bytes[2] = speed_byte;
80
81        bytes[3] = self.channel;
82
83        let transmission_mode = u8::from(self.transmission_mode);
84        let io_drive_mode = u8::from(self.io_drive_mode);
85        let wakeup_time = u8::from(self.wakeup_time);
86        let fec = u8::from(self.fec);
87        let transmission_power = u8::from(self.transmission_power);
88        let options = (transmission_mode << 7)
89            | (io_drive_mode << 6)
90            | (wakeup_time << 3)
91            | (fec << 2)
92            | transmission_power;
93        bytes[4] = options;
94
95        bytes
96    }
97
98    pub fn from_bytes(bytes: &[u8; 5]) -> Result<Self, Error> {
99        let address_high = bytes[0];
100        let address_low = bytes[1];
101        let speed = bytes[2];
102        let channel = bytes[3];
103        let options = bytes[4];
104        let address = (address_high as u16) << 8 | address_low as u16;
105        let uart_parity = Parity::try_from((speed & 0xC0) >> 6)?;
106        let uart_rate = BaudRate::try_from((speed & 0x38) >> 3)?;
107        let air_rate = AirBaudRate::try_from(speed & 0x7)?;
108
109        let transmission_mode = TransmissionMode::try_from((options & 0x80) >> 7)?;
110        let io_drive_mode = IoDriveMode::try_from((options & 0x40) >> 6)?;
111        let wakeup_time = WakeupTime::try_from((options & 0x38) >> 3)?;
112        let fec = ForwardErrorCorrectionMode::try_from((options & 0x07) >> 2)?;
113        let transmission_power = TransmissionPower::try_from(options & 0x3)?;
114
115        Ok(Self {
116            address,
117            channel,
118            uart_parity,
119            uart_rate,
120            air_rate,
121            transmission_mode,
122            io_drive_mode,
123            wakeup_time,
124            fec,
125            transmission_power,
126        })
127    }
128}
129
130/*
131/// Only valid for 433MHz modules.
132pub fn channel_to_freq_mhz(channel: u8) -> u32 {
133    assert!((0..31).contains(&channel));
134    410 + channel as u32
135}
136*/
137
138#[cfg(test)]
139mod test {
140    use super::*;
141    use proptest::prelude::*;
142
143    proptest! {
144        #![proptest_config(ProptestConfig {
145            cases: 10000,
146            .. ProptestConfig::default()
147        })]
148
149        #[test]
150        fn from_to_bytes_roundtrip(params in any::<Parameters>()) {
151            let bytes = params.to_bytes();
152            let decoded = Parameters::from_bytes(&bytes).unwrap();
153            assert_eq!(decoded, params);
154        }
155    }
156}
157
158#[cfg(all(feature = "value_enum", test))]
159mod value_enum_test {
160    #[test]
161    fn value_enum_persistence() {
162        let persistence = <crate::Persistence as clap::ValueEnum>::value_variants();
163        assert_eq!(
164            persistence,
165            [crate::Persistence::Temporary, crate::Persistence::Permanent]
166        );
167    }
168}