Skip to main content

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