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::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
78/// Copper-friendly wrapper for CRSF link statistics packets.
79#[derive(Clone, Debug)]
80pub struct LinkStatisticsPayload(pub LinkStatistics);
81
82impl LinkStatisticsPayload {
83    pub fn inner(&self) -> &LinkStatistics {
84        &self.0
85    }
86}
87
88impl From<LinkStatistics> for LinkStatisticsPayload {
89    fn from(value: LinkStatistics) -> Self {
90        Self(value)
91    }
92}
93
94impl From<LinkStatisticsPayload> for LinkStatistics {
95    fn from(value: LinkStatisticsPayload) -> Self {
96        value.0
97    }
98}
99
100impl PartialEq for LinkStatisticsPayload {
101    fn eq(&self, other: &Self) -> bool {
102        let LinkStatisticsPayload(link_a) = self;
103        let LinkStatisticsPayload(link_b) = other;
104        link_a.uplink_rssi_1 == link_b.uplink_rssi_1
105            && link_a.uplink_rssi_2 == link_b.uplink_rssi_2
106            && link_a.uplink_link_quality == link_b.uplink_link_quality
107            && link_a.uplink_snr == link_b.uplink_snr
108            && link_a.active_antenna == link_b.active_antenna
109            && link_a.rf_mode == link_b.rf_mode
110            && link_a.uplink_tx_power == link_b.uplink_tx_power
111            && link_a.downlink_rssi == link_b.downlink_rssi
112            && link_a.downlink_link_quality == link_b.downlink_link_quality
113            && link_a.downlink_snr == link_b.downlink_snr
114    }
115}
116
117impl Eq for LinkStatisticsPayload {}
118
119impl Default for LinkStatisticsPayload {
120    fn default() -> Self {
121        Self(LinkStatistics {
122            uplink_rssi_1: 0,
123            uplink_rssi_2: 0,
124            uplink_link_quality: 0,
125            uplink_snr: 0,
126            active_antenna: 0,
127            rf_mode: 0,
128            uplink_tx_power: 0,
129            downlink_rssi: 0,
130            downlink_link_quality: 0,
131            downlink_snr: 0,
132        })
133    }
134}
135impl Encode for LinkStatisticsPayload {
136    fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
137        let stats = &self.0;
138        stats.uplink_rssi_1.encode(encoder)?;
139        stats.uplink_rssi_2.encode(encoder)?;
140        stats.uplink_link_quality.encode(encoder)?;
141        stats.uplink_snr.encode(encoder)?;
142        stats.active_antenna.encode(encoder)?;
143        stats.rf_mode.encode(encoder)?;
144        stats.uplink_tx_power.encode(encoder)?;
145        stats.downlink_rssi.encode(encoder)?;
146        stats.downlink_link_quality.encode(encoder)?;
147        stats.downlink_snr.encode(encoder)?;
148        Ok(())
149    }
150}
151
152impl Decode<()> for LinkStatisticsPayload {
153    fn decode<D: Decoder<Context = ()>>(decoder: &mut D) -> Result<Self, DecodeError> {
154        Ok(Self(LinkStatistics {
155            uplink_rssi_1: u8::decode(decoder)?,
156            uplink_rssi_2: u8::decode(decoder)?,
157            uplink_link_quality: u8::decode(decoder)?,
158            uplink_snr: i8::decode(decoder)?,
159            active_antenna: u8::decode(decoder)?,
160            rf_mode: u8::decode(decoder)?,
161            uplink_tx_power: u8::decode(decoder)?,
162            downlink_rssi: u8::decode(decoder)?,
163            downlink_link_quality: u8::decode(decoder)?,
164            downlink_snr: i8::decode(decoder)?,
165        }))
166    }
167}
168
169impl Serialize for LinkStatisticsPayload {
170    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
171    where
172        S: serde::Serializer,
173    {
174        let stats = &self.0;
175        (
176            stats.uplink_rssi_1,
177            stats.uplink_rssi_2,
178            stats.uplink_link_quality,
179            stats.uplink_snr,
180            stats.active_antenna,
181            stats.rf_mode,
182            stats.uplink_tx_power,
183            stats.downlink_rssi,
184            stats.downlink_link_quality,
185            stats.downlink_snr,
186        )
187            .serialize(serializer)
188    }
189}
190
191#[cfg(test)]
192mod tests {
193    use super::*;
194    use bincode::{config, decode_from_slice, encode_to_vec};
195
196    #[test]
197    fn rc_channels_round_trip() {
198        let mut channels = [0u16; 16];
199        for (idx, value) in channels.iter_mut().enumerate() {
200            *value = (idx as u16) * 42;
201        }
202        let payload = RcChannelsPayload(RcChannels(channels));
203        let cfg = config::standard();
204
205        let encoded = encode_to_vec(&payload, cfg).expect("RC encode");
206        let (decoded, consumed): (RcChannelsPayload, usize) =
207            decode_from_slice(&encoded, cfg).expect("RC decode");
208
209        assert_eq!(consumed, encoded.len());
210        assert_eq!(payload, decoded);
211        assert_eq!(decoded.0 .0, channels);
212    }
213
214    #[test]
215    fn link_statistics_round_trip() {
216        let stats = LinkStatistics {
217            uplink_rssi_1: 100,
218            uplink_rssi_2: 98,
219            uplink_link_quality: 95,
220            uplink_snr: -12,
221            active_antenna: 1,
222            rf_mode: 2,
223            uplink_tx_power: 5,
224            downlink_rssi: 110,
225            downlink_link_quality: 90,
226            downlink_snr: -9,
227        };
228        let payload = LinkStatisticsPayload(stats);
229        let cfg = config::standard();
230
231        let encoded = encode_to_vec(&payload, cfg).expect("Link encode");
232        let (decoded, consumed): (LinkStatisticsPayload, usize) =
233            decode_from_slice(&encoded, cfg).expect("Link decode");
234
235        assert_eq!(consumed, encoded.len());
236        assert_eq!(payload, decoded);
237    }
238}