cu_crsf/
messages.rs

1use bincode::de::Decoder;
2use bincode::enc::Encoder;
3use bincode::error::{DecodeError, EncodeError};
4use bincode::{Decode, Encode};
5use crsf::{LinkStatistics, RcChannels};
6use serde::{Deserialize, Serialize};
7
8/// Copper-friendly wrapper for CRSF RC channel data.
9#[derive(Clone, Debug)]
10pub struct RcChannelsPayload(pub RcChannels);
11
12impl RcChannelsPayload {
13    /// Returns immutable access to the inner CRSF structure.
14    pub fn inner(&self) -> &RcChannels {
15        &self.0
16    }
17
18    /// Returns mutable access to the inner CRSF structure.
19    pub fn inner_mut(&mut self) -> &mut RcChannels {
20        &mut self.0
21    }
22}
23
24impl From<RcChannels> for RcChannelsPayload {
25    fn from(value: RcChannels) -> Self {
26        Self(value)
27    }
28}
29
30impl From<RcChannelsPayload> for RcChannels {
31    fn from(value: RcChannelsPayload) -> Self {
32        value.0
33    }
34}
35
36impl Default for RcChannelsPayload {
37    fn default() -> Self {
38        Self(RcChannels([0; 16]))
39    }
40}
41
42impl PartialEq for RcChannelsPayload {
43    fn eq(&self, other: &Self) -> bool {
44        self.0.0 == other.0.0
45    }
46}
47
48impl Eq for RcChannelsPayload {}
49
50impl Encode for RcChannelsPayload {
51    fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
52        for value in self.0.0.iter() {
53            value.encode(encoder)?;
54        }
55        Ok(())
56    }
57}
58
59impl Decode<()> for RcChannelsPayload {
60    fn decode<D: Decoder<Context = ()>>(decoder: &mut D) -> Result<Self, DecodeError> {
61        let mut channels = [0u16; 16];
62        for slot in channels.iter_mut() {
63            *slot = u16::decode(decoder)?;
64        }
65        Ok(Self(RcChannels(channels)))
66    }
67}
68
69impl Serialize for RcChannelsPayload {
70    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
71    where
72        S: serde::Serializer,
73    {
74        self.inner().0.serialize(serializer)
75    }
76}
77
78impl<'de> Deserialize<'de> for RcChannelsPayload {
79    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
80    where
81        D: serde::Deserializer<'de>,
82    {
83        let channels = <[u16; 16]>::deserialize(deserializer)?;
84        Ok(Self(RcChannels(channels)))
85    }
86}
87
88/// Copper-friendly wrapper for CRSF link statistics packets.
89#[derive(Clone, Debug)]
90pub struct LinkStatisticsPayload(pub LinkStatistics);
91
92impl LinkStatisticsPayload {
93    pub fn inner(&self) -> &LinkStatistics {
94        &self.0
95    }
96}
97
98impl From<LinkStatistics> for LinkStatisticsPayload {
99    fn from(value: LinkStatistics) -> Self {
100        Self(value)
101    }
102}
103
104impl From<LinkStatisticsPayload> for LinkStatistics {
105    fn from(value: LinkStatisticsPayload) -> Self {
106        value.0
107    }
108}
109
110impl PartialEq for LinkStatisticsPayload {
111    fn eq(&self, other: &Self) -> bool {
112        let LinkStatisticsPayload(link_a) = self;
113        let LinkStatisticsPayload(link_b) = other;
114        link_a.uplink_rssi_1 == link_b.uplink_rssi_1
115            && link_a.uplink_rssi_2 == link_b.uplink_rssi_2
116            && link_a.uplink_link_quality == link_b.uplink_link_quality
117            && link_a.uplink_snr == link_b.uplink_snr
118            && link_a.active_antenna == link_b.active_antenna
119            && link_a.rf_mode == link_b.rf_mode
120            && link_a.uplink_tx_power == link_b.uplink_tx_power
121            && link_a.downlink_rssi == link_b.downlink_rssi
122            && link_a.downlink_link_quality == link_b.downlink_link_quality
123            && link_a.downlink_snr == link_b.downlink_snr
124    }
125}
126
127impl Eq for LinkStatisticsPayload {}
128
129impl Default for LinkStatisticsPayload {
130    fn default() -> Self {
131        Self(LinkStatistics {
132            uplink_rssi_1: 0,
133            uplink_rssi_2: 0,
134            uplink_link_quality: 0,
135            uplink_snr: 0,
136            active_antenna: 0,
137            rf_mode: 0,
138            uplink_tx_power: 0,
139            downlink_rssi: 0,
140            downlink_link_quality: 0,
141            downlink_snr: 0,
142        })
143    }
144}
145impl Encode for LinkStatisticsPayload {
146    fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
147        let stats = &self.0;
148        stats.uplink_rssi_1.encode(encoder)?;
149        stats.uplink_rssi_2.encode(encoder)?;
150        stats.uplink_link_quality.encode(encoder)?;
151        stats.uplink_snr.encode(encoder)?;
152        stats.active_antenna.encode(encoder)?;
153        stats.rf_mode.encode(encoder)?;
154        stats.uplink_tx_power.encode(encoder)?;
155        stats.downlink_rssi.encode(encoder)?;
156        stats.downlink_link_quality.encode(encoder)?;
157        stats.downlink_snr.encode(encoder)?;
158        Ok(())
159    }
160}
161
162impl Decode<()> for LinkStatisticsPayload {
163    fn decode<D: Decoder<Context = ()>>(decoder: &mut D) -> Result<Self, DecodeError> {
164        Ok(Self(LinkStatistics {
165            uplink_rssi_1: u8::decode(decoder)?,
166            uplink_rssi_2: u8::decode(decoder)?,
167            uplink_link_quality: u8::decode(decoder)?,
168            uplink_snr: i8::decode(decoder)?,
169            active_antenna: u8::decode(decoder)?,
170            rf_mode: u8::decode(decoder)?,
171            uplink_tx_power: u8::decode(decoder)?,
172            downlink_rssi: u8::decode(decoder)?,
173            downlink_link_quality: u8::decode(decoder)?,
174            downlink_snr: i8::decode(decoder)?,
175        }))
176    }
177}
178
179impl Serialize for LinkStatisticsPayload {
180    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
181    where
182        S: serde::Serializer,
183    {
184        let stats = &self.0;
185        (
186            stats.uplink_rssi_1,
187            stats.uplink_rssi_2,
188            stats.uplink_link_quality,
189            stats.uplink_snr,
190            stats.active_antenna,
191            stats.rf_mode,
192            stats.uplink_tx_power,
193            stats.downlink_rssi,
194            stats.downlink_link_quality,
195            stats.downlink_snr,
196        )
197            .serialize(serializer)
198    }
199}
200
201impl<'de> Deserialize<'de> for LinkStatisticsPayload {
202    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
203    where
204        D: serde::Deserializer<'de>,
205    {
206        let (
207            uplink_rssi_1,
208            uplink_rssi_2,
209            uplink_link_quality,
210            uplink_snr,
211            active_antenna,
212            rf_mode,
213            uplink_tx_power,
214            downlink_rssi,
215            downlink_link_quality,
216            downlink_snr,
217        ) = <(u8, u8, u8, i8, u8, u8, u8, u8, u8, i8)>::deserialize(deserializer)?;
218        Ok(Self(LinkStatistics {
219            uplink_rssi_1,
220            uplink_rssi_2,
221            uplink_link_quality,
222            uplink_snr,
223            active_antenna,
224            rf_mode,
225            uplink_tx_power,
226            downlink_rssi,
227            downlink_link_quality,
228            downlink_snr,
229        }))
230    }
231}
232
233#[cfg(test)]
234mod tests {
235    use super::*;
236    use bincode::{config, decode_from_slice, encode_to_vec};
237
238    #[test]
239    fn rc_channels_round_trip() {
240        let mut channels = [0u16; 16];
241        for (idx, value) in channels.iter_mut().enumerate() {
242            *value = (idx as u16) * 42;
243        }
244        let payload = RcChannelsPayload(RcChannels(channels));
245        let cfg = config::standard();
246
247        let encoded = encode_to_vec(&payload, cfg).expect("RC encode");
248        let (decoded, consumed): (RcChannelsPayload, usize) =
249            decode_from_slice(&encoded, cfg).expect("RC decode");
250
251        assert_eq!(consumed, encoded.len());
252        assert_eq!(payload, decoded);
253        assert_eq!(decoded.0.0, channels);
254    }
255
256    #[test]
257    fn link_statistics_round_trip() {
258        let stats = LinkStatistics {
259            uplink_rssi_1: 100,
260            uplink_rssi_2: 98,
261            uplink_link_quality: 95,
262            uplink_snr: -12,
263            active_antenna: 1,
264            rf_mode: 2,
265            uplink_tx_power: 5,
266            downlink_rssi: 110,
267            downlink_link_quality: 90,
268            downlink_snr: -9,
269        };
270        let payload = LinkStatisticsPayload(stats);
271        let cfg = config::standard();
272
273        let encoded = encode_to_vec(&payload, cfg).expect("Link encode");
274        let (decoded, consumed): (LinkStatisticsPayload, usize) =
275            decode_from_slice(&encoded, cfg).expect("Link decode");
276
277        assert_eq!(consumed, encoded.len());
278        assert_eq!(payload, decoded);
279    }
280}