ebyte_e32/parameters/
mod.rs1pub 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#[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}