uf_crsf/packets/
flight_mode.rs

1use crate::packets::CrsfPacket;
2use crate::packets::PacketType;
3use crate::CrsfParsingError;
4use heapless::String;
5
6const MAX_FLIGHT_MODE_LEN: usize = 59;
7
8/// Represents a Flight Mode packet.
9///
10/// Contains the flight mode as a null-terminated string.
11#[derive(Clone, Debug, PartialEq)]
12pub struct FlightMode {
13    /// The flight mode string.
14    flight_mode: String<MAX_FLIGHT_MODE_LEN>,
15}
16
17impl FlightMode {
18    /// Creates a new FlightMode packet from a string slice.
19    ///
20    /// The flight mode string must not be longer than 59 bytes.
21    pub fn new(flight_mode: &str) -> Result<Self, CrsfParsingError> {
22        if flight_mode.len() > MAX_FLIGHT_MODE_LEN {
23            return Err(CrsfParsingError::InvalidPayloadLength);
24        }
25        let mut s = String::new();
26        s.push_str(flight_mode)
27            .map_err(|_| CrsfParsingError::InvalidPayloadLength)?;
28        Ok(Self { flight_mode: s })
29    }
30
31    /// Returns the flight mode as a string slice.
32    pub fn flight_mode(&self) -> &str {
33        self.flight_mode.as_str()
34    }
35}
36
37#[cfg(feature = "defmt")]
38impl defmt::Format for FlightMode {
39    fn format(&self, fmt: defmt::Formatter) {
40        defmt::write!(fmt, "FlightMode {{ flight_mode: {} }}", self.flight_mode())
41    }
42}
43
44impl CrsfPacket for FlightMode {
45    const PACKET_TYPE: PacketType = PacketType::FlightMode;
46    // An empty flight mode is a single null byte
47    const MIN_PAYLOAD_SIZE: usize = 1;
48
49    fn to_bytes(&self, buffer: &mut [u8]) -> Result<usize, CrsfParsingError> {
50        let bytes = self.flight_mode().as_bytes();
51        let len_with_null = bytes.len() + 1;
52        if buffer.len() < len_with_null {
53            return Err(CrsfParsingError::BufferOverflow);
54        }
55        buffer[..bytes.len()].copy_from_slice(bytes);
56        buffer[bytes.len()] = 0; // Null terminator
57        Ok(len_with_null)
58    }
59
60    fn from_bytes(data: &[u8]) -> Result<Self, CrsfParsingError> {
61        let null_pos = data.iter().position(|&b| b == 0).unwrap_or(data.len());
62        let s = core::str::from_utf8(&data[..null_pos])
63            .map_err(|_| CrsfParsingError::InvalidPayload)?;
64        let mut flight_mode = String::new();
65        flight_mode
66            .push_str(s)
67            .map_err(|_e| CrsfParsingError::InvalidPayloadLength)?;
68        Ok(Self { flight_mode })
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn test_flight_mode_to_bytes() {
78        let flight_mode = FlightMode::new("ACRO").unwrap();
79
80        let mut buffer = [0u8; 60];
81        let len = flight_mode.to_bytes(&mut buffer).unwrap();
82
83        let expected_bytes: [u8; 5] = [b'A', b'C', b'R', b'O', 0];
84
85        assert_eq!(len, 5);
86        assert_eq!(&buffer[..len], &expected_bytes);
87    }
88
89    #[test]
90    fn test_flight_mode_to_bytes_buffer_too_small() {
91        let flight_mode = FlightMode::new("LONG FLIGHT MODE").unwrap();
92
93        let mut buffer = [0u8; 10];
94        let result = flight_mode.to_bytes(&mut buffer);
95        assert!(matches!(result, Err(CrsfParsingError::BufferOverflow)));
96    }
97
98    #[test]
99    fn test_flight_node_from_bytes_too_small() {
100        let data: [u8; 0] = [];
101        let result = FlightMode::from_bytes(&data);
102        assert_eq!(
103            result.unwrap().flight_mode,
104            String::<MAX_FLIGHT_MODE_LEN>::new()
105        );
106    }
107
108    #[test]
109    fn test_flight_mode_from_bytes() {
110        let data: [u8; 5] = [b'A', b'C', b'R', b'O', 0];
111        let flight_mode = FlightMode::from_bytes(&data).unwrap();
112
113        assert_eq!(flight_mode.flight_mode(), "ACRO");
114    }
115
116    #[test]
117    fn test_flight_mode_from_bytes_no_null() {
118        let data: [u8; 4] = [b'A', b'C', b'R', b'O'];
119        let flight_mode = FlightMode::from_bytes(&data).unwrap();
120
121        assert_eq!(flight_mode.flight_mode(), "ACRO");
122    }
123
124    #[test]
125    fn test_flight_mode_round_trip() {
126        let flight_mode = FlightMode::new("STABILIZE").unwrap();
127
128        let mut buffer = [0u8; 60];
129        let len = flight_mode.to_bytes(&mut buffer).unwrap();
130
131        let round_trip_flight_mode = FlightMode::from_bytes(&buffer[..len]).unwrap();
132
133        assert_eq!(flight_mode, round_trip_flight_mode);
134    }
135
136    #[test]
137    fn test_empty_flight_mode() {
138        let flight_mode = FlightMode::new("").unwrap();
139
140        let mut buffer = [0u8; 60];
141        let len = flight_mode.to_bytes(&mut buffer).unwrap();
142        let round_trip_flight_mode = FlightMode::from_bytes(&buffer[..len]).unwrap();
143        assert_eq!(flight_mode, round_trip_flight_mode);
144        assert_eq!(len, 1);
145        assert_eq!(buffer[0], 0);
146    }
147}