Skip to main content

cu_msp_lib/
structs.rs

1//! MSP structures
2
3use packed_struct::derive::{PackedStruct, PrimitiveEnum};
4use serde::{Deserialize, Serialize};
5
6use crate::MspPacketDirection::{FromFlightController, ToFlightController};
7use crate::commands::MspCommandCode;
8use crate::{MSP_MAX_PAYLOAD_LEN, MspPacket, MspPacketData, MspPacketDataBuffer};
9
10use alloc::{borrow::ToOwned, string::String, vec::Vec};
11
12#[cfg(feature = "bincode")]
13use bincode::{Decode, Encode};
14use packed_struct::types::bits::ByteArray;
15use packed_struct::{PackedStruct, PackingError, PrimitiveEnum};
16
17#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
18#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
19pub struct MspApiVersion {
20    pub protocol_version: u8,
21    pub api_version_major: u8,
22    pub api_version_minor: u8,
23}
24
25#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
26#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
27pub struct MspFlightControllerVariant {
28    pub identifier: [u8; 4],
29}
30
31#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
32#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
33pub struct MspFlightControllerVersion {
34    pub major: u8,
35    pub minor: u8,
36    pub patch: u8,
37}
38
39#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
40#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
41#[packed_struct(endian = "lsb")]
42pub struct MspBoardInfo {
43    pub board_id: [u8; 4],
44    pub hardware_revision: u16,
45    pub fc_type: u8,
46}
47
48#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
49#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
50pub struct MspBuildInfo {
51    pub date_str: [u8; 11],
52    pub time_str: [u8; 8],
53    pub git_str: [u8; 7],
54}
55
56#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
57#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
58pub struct MspUniqueId {
59    pub uid: [u8; 12],
60}
61
62#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
63#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
64#[packed_struct(bytes = "1", endian = "lsb", bit_numbering = "msb0")]
65pub struct MspAvailableSensors {
66    #[packed_field(bits = "2")]
67    pub sonar: bool,
68    #[packed_field(bits = "4")]
69    pub gps: bool,
70    #[packed_field(bits = "5")]
71    pub mag: bool,
72    #[packed_field(bits = "6")]
73    pub baro: bool,
74    #[packed_field(bits = "7")]
75    pub acc: bool,
76}
77
78#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
79#[derive(Serialize, Deserialize, Debug, Copy, Clone, Default, PartialEq, Eq)]
80pub struct MspStatusSensors {
81    pub acc: bool,
82    pub baro: bool,
83    pub mag: bool,
84    pub gps: bool,
85    pub rangefinder: bool,
86    pub gyro: bool,
87    pub optical_flow: bool,
88}
89
90impl MspStatusSensors {
91    pub fn from_bits(bits: u16) -> Self {
92        Self {
93            acc: bits & (1 << 0) != 0,
94            baro: bits & (1 << 1) != 0,
95            mag: bits & (1 << 2) != 0,
96            gps: bits & (1 << 3) != 0,
97            rangefinder: bits & (1 << 4) != 0,
98            gyro: bits & (1 << 5) != 0,
99            optical_flow: bits & (1 << 6) != 0,
100        }
101    }
102
103    pub fn to_bits(self) -> u16 {
104        (self.acc as u16)
105            | (self.baro as u16) << 1
106            | (self.mag as u16) << 2
107            | (self.gps as u16) << 3
108            | (self.rangefinder as u16) << 4
109            | (self.gyro as u16) << 5
110            | (self.optical_flow as u16) << 6
111    }
112}
113
114impl From<u16> for MspStatusSensors {
115    fn from(bits: u16) -> Self {
116        Self::from_bits(bits)
117    }
118}
119
120impl From<MspStatusSensors> for u16 {
121    fn from(value: MspStatusSensors) -> Self {
122        value.to_bits()
123    }
124}
125
126#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
127#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
128pub struct MspStatus {
129    pub cycle_time: u16,
130    pub i2c_errors: u16,
131    pub sensors: MspStatusSensors,
132    pub flight_mode_flags: u32,
133    pub current_pid_profile_index: u8,
134    pub average_system_load_percent: u16,
135    pub gyro_cycle_time: u16,
136    pub extra_flight_mode_flags: Vec<u8>,
137    pub arming_disable_flags_count: u8,
138    pub arming_disable_flags: u32,
139    pub config_state_flags: u8,
140    pub core_temp_celsius: u16,
141    pub control_rate_profile_count: u8,
142}
143
144#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
145#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
146pub struct MspStatusEx {
147    pub cycle_time: u16,
148    pub i2c_errors: u16,
149    pub sensors: MspStatusSensors,
150    pub flight_mode_flags: u32,
151    pub current_pid_profile_index: u8,
152    pub average_system_load_percent: u16,
153    pub max_profile_count: u8,
154    pub current_control_rate_profile_index: u8,
155    pub extra_flight_mode_flags: Vec<u8>,
156    pub arming_disable_flags_count: u8,
157    pub arming_disable_flags: u32,
158    pub config_state_flags: u8,
159    pub core_temp_celsius: u16,
160    pub control_rate_profile_count: u8,
161}
162
163impl MspStatus {
164    pub fn from_bytes(data: &[u8]) -> Result<Self, PackingError> {
165        let mut offset = 0;
166        let cycle_time = read_u16(data, &mut offset)?;
167        let i2c_errors = read_u16(data, &mut offset)?;
168        let sensors = MspStatusSensors::from(read_u16(data, &mut offset)?);
169        let flight_mode_flags = read_u32(data, &mut offset)?;
170        let current_pid_profile_index = read_u8(data, &mut offset)?;
171        let average_system_load_percent = read_u16(data, &mut offset)?;
172        let gyro_cycle_time = read_u16(data, &mut offset)?;
173        let extra_flight_mode_flags_len = read_u8(data, &mut offset)? as usize;
174        let extra_flight_mode_flags = read_bytes(data, &mut offset, extra_flight_mode_flags_len)?;
175        let arming_disable_flags_count = read_u8(data, &mut offset)?;
176        let arming_disable_flags = read_u32(data, &mut offset)?;
177        let config_state_flags = read_u8(data, &mut offset)?;
178        let core_temp_celsius = read_u16(data, &mut offset)?;
179        let control_rate_profile_count = read_u8(data, &mut offset)?;
180
181        Ok(Self {
182            cycle_time,
183            i2c_errors,
184            sensors,
185            flight_mode_flags,
186            current_pid_profile_index,
187            average_system_load_percent,
188            gyro_cycle_time,
189            extra_flight_mode_flags,
190            arming_disable_flags_count,
191            arming_disable_flags,
192            config_state_flags,
193            core_temp_celsius,
194            control_rate_profile_count,
195        })
196    }
197
198    pub fn to_packet_data(&self) -> Result<MspPacketData, PackingError> {
199        if self.extra_flight_mode_flags.len() > 15 {
200            return Err(PackingError::InvalidValue);
201        }
202        let mut data = MspPacketDataBuffer::new();
203        extend_payload(&mut data, &self.cycle_time.to_le_bytes())?;
204        extend_payload(&mut data, &self.i2c_errors.to_le_bytes())?;
205        extend_payload(&mut data, &u16::from(self.sensors).to_le_bytes())?;
206        extend_payload(&mut data, &self.flight_mode_flags.to_le_bytes())?;
207        push_payload(&mut data, self.current_pid_profile_index)?;
208        extend_payload(&mut data, &self.average_system_load_percent.to_le_bytes())?;
209        extend_payload(&mut data, &self.gyro_cycle_time.to_le_bytes())?;
210        push_payload(&mut data, self.extra_flight_mode_flags.len() as u8)?;
211        extend_payload(&mut data, &self.extra_flight_mode_flags)?;
212        push_payload(&mut data, self.arming_disable_flags_count)?;
213        extend_payload(&mut data, &self.arming_disable_flags.to_le_bytes())?;
214        push_payload(&mut data, self.config_state_flags)?;
215        extend_payload(&mut data, &self.core_temp_celsius.to_le_bytes())?;
216        push_payload(&mut data, self.control_rate_profile_count)?;
217
218        Ok(MspPacketData(data))
219    }
220}
221
222impl MspStatusEx {
223    pub fn from_bytes(data: &[u8]) -> Result<Self, PackingError> {
224        let mut offset = 0;
225        let cycle_time = read_u16(data, &mut offset)?;
226        let i2c_errors = read_u16(data, &mut offset)?;
227        let sensors = MspStatusSensors::from(read_u16(data, &mut offset)?);
228        let flight_mode_flags = read_u32(data, &mut offset)?;
229        let current_pid_profile_index = read_u8(data, &mut offset)?;
230        let average_system_load_percent = read_u16(data, &mut offset)?;
231        let max_profile_count = read_u8(data, &mut offset)?;
232        let current_control_rate_profile_index = read_u8(data, &mut offset)?;
233        let extra_flight_mode_flags_len = read_u8(data, &mut offset)? as usize;
234        let extra_flight_mode_flags = read_bytes(data, &mut offset, extra_flight_mode_flags_len)?;
235        let arming_disable_flags_count = read_u8(data, &mut offset)?;
236        let arming_disable_flags = read_u32(data, &mut offset)?;
237        let config_state_flags = read_u8(data, &mut offset)?;
238        let core_temp_celsius = read_u16(data, &mut offset)?;
239        let control_rate_profile_count = read_u8(data, &mut offset)?;
240
241        Ok(Self {
242            cycle_time,
243            i2c_errors,
244            sensors,
245            flight_mode_flags,
246            current_pid_profile_index,
247            average_system_load_percent,
248            max_profile_count,
249            current_control_rate_profile_index,
250            extra_flight_mode_flags,
251            arming_disable_flags_count,
252            arming_disable_flags,
253            config_state_flags,
254            core_temp_celsius,
255            control_rate_profile_count,
256        })
257    }
258
259    pub fn to_packet_data(&self) -> Result<MspPacketData, PackingError> {
260        if self.extra_flight_mode_flags.len() > 15 {
261            return Err(PackingError::InvalidValue);
262        }
263        let mut data = MspPacketDataBuffer::new();
264        extend_payload(&mut data, &self.cycle_time.to_le_bytes())?;
265        extend_payload(&mut data, &self.i2c_errors.to_le_bytes())?;
266        extend_payload(&mut data, &u16::from(self.sensors).to_le_bytes())?;
267        extend_payload(&mut data, &self.flight_mode_flags.to_le_bytes())?;
268        push_payload(&mut data, self.current_pid_profile_index)?;
269        extend_payload(&mut data, &self.average_system_load_percent.to_le_bytes())?;
270        push_payload(&mut data, self.max_profile_count)?;
271        push_payload(&mut data, self.current_control_rate_profile_index)?;
272        push_payload(&mut data, self.extra_flight_mode_flags.len() as u8)?;
273        extend_payload(&mut data, &self.extra_flight_mode_flags)?;
274        push_payload(&mut data, self.arming_disable_flags_count)?;
275        extend_payload(&mut data, &self.arming_disable_flags.to_le_bytes())?;
276        push_payload(&mut data, self.config_state_flags)?;
277        extend_payload(&mut data, &self.core_temp_celsius.to_le_bytes())?;
278        push_payload(&mut data, self.control_rate_profile_count)?;
279
280        Ok(MspPacketData(data))
281    }
282}
283
284fn push_payload(data: &mut MspPacketDataBuffer, value: u8) -> Result<(), PackingError> {
285    let next_len = data.len() + 1;
286    if next_len > MSP_MAX_PAYLOAD_LEN {
287        return Err(PackingError::BufferSizeMismatch {
288            expected: MSP_MAX_PAYLOAD_LEN,
289            actual: next_len,
290        });
291    }
292    data.push(value)
293        .map_err(|_| PackingError::BufferSizeMismatch {
294            expected: MSP_MAX_PAYLOAD_LEN,
295            actual: next_len,
296        })?;
297    Ok(())
298}
299
300fn extend_payload(data: &mut MspPacketDataBuffer, bytes: &[u8]) -> Result<(), PackingError> {
301    let next_len = data.len() + bytes.len();
302    if next_len > MSP_MAX_PAYLOAD_LEN {
303        return Err(PackingError::BufferSizeMismatch {
304            expected: MSP_MAX_PAYLOAD_LEN,
305            actual: next_len,
306        });
307    }
308    data.extend_from_slice(bytes)
309        .map_err(|_| PackingError::BufferSizeMismatch {
310            expected: MSP_MAX_PAYLOAD_LEN,
311            actual: next_len,
312        })?;
313    Ok(())
314}
315
316fn read_u8(data: &[u8], offset: &mut usize) -> Result<u8, PackingError> {
317    if *offset + 1 > data.len() {
318        return Err(PackingError::BufferSizeMismatch {
319            expected: *offset + 1,
320            actual: data.len(),
321        });
322    }
323    let value = data[*offset];
324    *offset += 1;
325    Ok(value)
326}
327
328fn read_u16(data: &[u8], offset: &mut usize) -> Result<u16, PackingError> {
329    if *offset + 2 > data.len() {
330        return Err(PackingError::BufferSizeMismatch {
331            expected: *offset + 2,
332            actual: data.len(),
333        });
334    }
335    let value = u16::from_le_bytes([data[*offset], data[*offset + 1]]);
336    *offset += 2;
337    Ok(value)
338}
339
340fn read_u32(data: &[u8], offset: &mut usize) -> Result<u32, PackingError> {
341    if *offset + 4 > data.len() {
342        return Err(PackingError::BufferSizeMismatch {
343            expected: *offset + 4,
344            actual: data.len(),
345        });
346    }
347    let value = u32::from_le_bytes([
348        data[*offset],
349        data[*offset + 1],
350        data[*offset + 2],
351        data[*offset + 3],
352    ]);
353    *offset += 4;
354    Ok(value)
355}
356
357fn read_bytes(data: &[u8], offset: &mut usize, len: usize) -> Result<Vec<u8>, PackingError> {
358    if *offset + len > data.len() {
359        return Err(PackingError::BufferSizeMismatch {
360            expected: *offset + len,
361            actual: data.len(),
362        });
363    }
364    let bytes = data[*offset..*offset + len].to_vec();
365    *offset += len;
366    Ok(bytes)
367}
368
369#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
370#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
371#[packed_struct(endian = "lsb")]
372pub struct MspBfConfig {
373    pub mixer_configuration: u8,
374    pub features: u32,
375    pub serial_rx_provider: u8,
376    pub board_align_roll: i16,
377    pub board_align_pitch: i16,
378    pub board_align_yaw: i16,
379    pub current_scale: i16,
380    pub current_offset: i16,
381}
382
383#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
384#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
385#[packed_struct(endian = "lsb")]
386pub struct MspRawImu {
387    pub acc_x: i16,
388    pub acc_y: i16,
389    pub acc_z: i16,
390    pub gyro_x: i16,
391    pub gyro_y: i16,
392    pub gyro_z: i16,
393    pub mag_x: i16,
394    pub mag_y: i16,
395    pub mag_z: i16,
396}
397
398#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
399#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
400#[packed_struct(bytes = "1", endian = "lsb", bit_numbering = "msb0")]
401pub struct MspDataFlashSummaryReply {
402    #[packed_field(bits = "6")]
403    pub supported: bool,
404    #[packed_field(bits = "7")]
405    pub ready: bool,
406    pub sectors: u32,
407    pub total_size_bytes: u32,
408    pub used_size_bytes: u32,
409}
410
411#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
412#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
413#[packed_struct(bytes = "1", endian = "lsb", bit_numbering = "msb0")]
414pub struct MspDataFlashReply {
415    pub read_address: u32,
416    // pub payload: Vec<u8>, // TODO: packed_struct should support dynamic size too the end
417}
418
419#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
420#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
421#[packed_struct(bytes = "6", endian = "lsb", bit_numbering = "msb0")]
422pub struct MspDataFlashRead {
423    pub read_address: u32,
424    pub read_length: u16,
425}
426
427#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
428#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
429#[packed_struct(endian = "lsb")]
430pub struct MspAccTrim {
431    pub pitch: u16,
432    pub roll: u16,
433}
434
435#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
436#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
437#[packed_struct(endian = "lsb")]
438pub struct MspIdent {
439    pub version: u8,
440    pub mixer_mode: u8,
441    pub protocol_version: u8,
442    pub capability: u32,
443}
444
445#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
446#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
447#[packed_struct(endian = "lsb")]
448pub struct MspMisc {
449    pub rx_mid_rc: u16,
450    pub min_throttle: u16,
451    pub max_throttle: u16,
452    pub min_command: u16,
453    pub failsafe_throttle: u16,
454
455    pub gps_type: u8,
456    pub gps_baudrate: u8,
457    pub gps_sbas_mode: u8,
458
459    pub current_meter_output: u8,
460    pub rssi_channel: u8,
461    pub null1: u8,
462
463    pub compass_mag_declination: u16,
464}
465
466#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
467#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
468#[packed_struct(endian = "lsb")]
469pub struct MspAttitude {
470    pub roll: i16,
471    pub pitch: i16,
472    pub yaw: i16,
473}
474
475#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
476#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
477#[packed_struct(endian = "lsb")]
478pub struct MspAltitude {
479    /// [centimeters]
480    pub altitude: i32,
481    /// variometer [cm/s]
482    pub vario: i16,
483}
484
485#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
486#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
487#[packed_struct(endian = "lsb")]
488pub struct MspSensorRangefinder {
489    pub quality: u8,
490    pub distance_mm: i32,
491}
492
493#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
494#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
495#[packed_struct(endian = "lsb")]
496pub struct MspSensorOpticFlow {
497    pub quality: u8,
498    pub motion_x: i32,
499    pub motion_y: i32,
500}
501
502#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
503#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
504#[packed_struct(endian = "lsb")]
505pub struct MspBatteryConfig {
506    pub vbat_min_cell_voltage: u8,
507    pub vbat_max_cell_voltage: u8,
508    pub vbat_warning_cell_voltage: u8,
509    pub battery_capacity: u16,
510    pub voltage_meter_source: u8,
511    pub current_meter_source: u8,
512    pub vbat_min_cell_voltage_mv: u16,
513    pub vbat_max_cell_voltage_mv: u16,
514    pub vbat_warning_cell_voltage_mv: u16,
515}
516
517#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
518#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
519#[packed_struct(endian = "lsb")]
520pub struct MspVoltageMeterConfig {
521    pub sensor_count: u8,
522    pub subframe_len: u8,
523    pub id: u8,
524    pub sensor_type: u8,
525    pub vbat_scale: u8,
526    pub vbat_res_div_val: u8,
527    pub vbat_res_div_mult: u8,
528}
529
530#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
531#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
532#[packed_struct(endian = "lsb")]
533pub struct MspAnalog {
534    pub battery_voltage: u8,
535    pub mah_drawn: u16,
536    pub rssi: u16,
537    /// Current in 0.01A steps, range is -320A to 320A
538    pub amperage: i16,
539    /// Battery voltage in 0.01V steps
540    pub battery_voltage_mv: u16,
541}
542
543#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
544#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
545#[packed_struct(endian = "lsb")]
546pub struct MspRssiConfig {
547    pub rssi_channel: u8,
548}
549
550#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
551#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
552pub struct MspVoltageMeter {
553    pub id: u8,
554    pub value: u8,
555}
556
557#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
558#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
559#[packed_struct(endian = "lsb")]
560pub struct MspCurrentMeter {
561    pub id: u8,
562    pub mah_drawn: u16,
563    /// In 0.001A steps (mA)
564    pub amperage: u16,
565}
566
567#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
568#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
569#[packed_struct(endian = "lsb")]
570pub struct MspBatteryState {
571    pub battery_cell_count: u8,
572    /// mAh
573    pub battery_capacity: u16,
574
575    pub battery_voltage: u8,
576    pub mah_drawn: u16,
577    /// 0.01A
578    pub amperage: i16,
579
580    pub alerts: u8,
581    /// Battery voltage in 0.01V steps
582    pub battery_voltage_mv: u16,
583}
584
585impl MspBatteryState {
586    pub fn cell_voltage(&self) -> f32 {
587        self.battery_voltage as f32 / (10 * self.battery_cell_count) as f32
588    }
589}
590
591#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
592#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
593#[packed_struct(endian = "lsb")]
594pub struct MspRcTuning {
595    pub rc_rate8: u8,
596    pub rc_expo8: u8,
597
598    pub rate_roll: u8,
599    pub rate_pitch: u8,
600    pub rate_yaw: u8,
601
602    pub dyn_thr_pid: u8,
603    pub thr_mid8: u8,
604    pub thr_expo8: u8,
605    pub tpa_breakpoint: u16,
606    pub rc_yaw_expo8: u8,
607    pub rc_yaw_rate8: u8,
608}
609
610#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
611#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
612#[packed_struct(endian = "lsb")]
613pub struct MspRxConfig {
614    pub serialrx_provider: u8,
615    pub maxcheck: u16,
616    pub midrc: u16,
617    pub mincheck: u16,
618    pub spektrum_sat_bind: u8,
619    pub rx_min_usec: u16,
620    pub rx_max_usec: u16,
621    pub rc_interpolation: u8,
622    pub rc_interpolation_interval: u8,
623    pub air_mode_activate_threshold: u16,
624    pub rx_spi_protocol: u8,
625    pub rx_spi_id: u32,
626    pub rx_spi_rf_channel_count: u8,
627    pub fpv_cam_angle_degrees: u8,
628}
629
630#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
631#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
632#[packed_struct(endian = "lsb")]
633pub struct MspRcChannelValue {
634    pub value: u16,
635}
636
637#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
638#[derive(PrimitiveEnum, Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Default)]
639pub enum MspRcChannel {
640    /// Ailerons
641    #[default]
642    Roll = 0,
643    /// Elevators
644    Pitch = 1,
645    /// Rudder
646    Yaw = 2,
647    Throttle = 3,
648    Aux1 = 4,
649    Aux2 = 5,
650    Aux3 = 6,
651    Aux4 = 7,
652    Aux5 = 8,
653    Aux6 = 9,
654    Aux7 = 10,
655    Aux8 = 11,
656    Aux9 = 12,
657    Aux10 = 13,
658    Aux11 = 14,
659    Aux12 = 15,
660    Aux13 = 16,
661    Aux14 = 17,
662    Aux15 = 18,
663    Aux16 = 19,
664}
665
666#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
667#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
668pub struct MspRcMappedChannel {
669    #[packed_field(size_bits = "8", ty = "enum")]
670    pub channel: MspRcChannel,
671}
672
673#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
674#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
675pub struct MspFeatures {
676    pub features: [bool; 32],
677}
678
679#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
680#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
681#[packed_struct(endian = "lsb")]
682pub struct MspMotor {
683    pub motors: [u16; 8],
684}
685
686#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
687#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
688#[packed_struct(endian = "lsb")]
689pub struct MspMotor3DConfig {
690    pub deadband_3d_low: u16,
691    pub deadband_3d_high: u16,
692    pub neutral_3d: u16,
693}
694
695#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
696#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
697#[packed_struct(endian = "lsb")]
698pub struct MspMotorConfig {
699    pub min_throttle: u16,
700    pub max_throttle: u16,
701    pub min_command: u16,
702}
703
704#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
705#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
706#[packed_struct(endian = "lsb")]
707pub struct MspRcDeadband {
708    pub deadband: u8,
709    pub yaw_deadband: u8,
710    pub alt_hold_deadband: u8,
711    pub deadband_3d_throttle: u16,
712}
713
714#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
715#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
716#[packed_struct(endian = "lsb")]
717pub struct MspSensorAlignment {
718    pub gyro_alignment: u8,
719    pub acc_alignment: u8,
720    pub mag_alignment: u8,
721}
722
723#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
724#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
725#[packed_struct(endian = "lsb")]
726pub struct MspAdvancedConfig {
727    pub gyro_sync_denom: u8,
728    pub pid_process_denom: u8,
729    pub use_unsynced_pwm: u8,
730    pub motor_pwm_protocol: u8,
731    pub motor_pwm_rate: u16,
732    pub digital_idle_offset_percent: u16,
733    pub gyro_use_32khz: u8,
734    pub motor_pwm_inversion: u8,
735}
736
737#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
738#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
739#[packed_struct(endian = "lsb")]
740pub struct MspFilterConfig {
741    pub gyro_soft_lpf_hz: u8,
742    pub dterm_lpf_hz: u16,
743    pub yaw_lpf_hz: u16,
744    pub gyro_soft_notch_hz_1: u16,
745    pub gyro_soft_notch_cutoff_1: u16,
746    pub dterm_notch_hz: u16,
747    pub dterm_notch_cutoff: u16,
748    pub gyro_soft_notch_hz_2: u16,
749    pub gyro_soft_notch_cutoff_2: u16,
750}
751
752#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
753#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
754#[packed_struct(endian = "lsb")]
755pub struct MspPidAdvanced {
756    pub _r1: u16,
757    pub _r2: u16,
758    pub _r3: u16,
759    pub _r4: u8,
760    pub vbat_pid_compensation: u8,
761    pub setpoint_relax_ratio: u8,
762    pub dterm_setpoint_weight: u8,
763    pub _r5: u8,
764    pub _r6: u8,
765    pub _r7: u8,
766    pub rate_accel_limit: u16,
767    pub yaw_rate_accel_limit: u16,
768    pub level_angle_limit: u8,
769    pub level_sensitivity: u8,
770}
771
772#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
773#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
774#[packed_struct(endian = "lsb")]
775pub struct MspSensorConfig {
776    pub acc_hardware: u8,
777    pub baro_hardware: u8,
778    pub mag_hardware: u8,
779}
780
781#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
782#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
783#[packed_struct(endian = "lsb")]
784pub struct MspServos {
785    pub servos: [u16; 8],
786}
787
788#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
789#[derive(PackedStruct, Debug, Copy, Clone, Default)]
790#[packed_struct(bytes = "14", endian = "lsb", bit_numbering = "msb0")]
791pub struct MspServoConfig {
792    pub min: u16,
793    pub max: u16,
794    pub middle: u16,
795    pub rate: i8,
796    pub unused1: u8,
797    pub unused2: u8,
798    pub forward_from_channel: u8, // Deprecated, set to 255 for backward compatibility
799    pub reverse_input: u32, // Deprecated, Input reversing is not required since it can be done on mixer level
800}
801
802#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
803#[derive(PackedStruct, Debug, Copy, Clone, Default)]
804#[packed_struct(bytes = "1", endian = "lsb", bit_numbering = "msb0")]
805pub struct MspSetServoConfig {
806    pub index: u8,
807    #[packed_field(size_bytes = "14")]
808    pub servo_config: MspServoConfig,
809}
810
811#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
812#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
813#[packed_struct(endian = "lsb")]
814pub struct MspMixerConfig {
815    #[packed_field(size_bits = "8", ty = "enum")]
816    pub mixer_mode: MixerMode,
817}
818
819#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
820#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
821#[packed_struct(bytes = "4", endian = "lsb", bit_numbering = "msb0")]
822pub struct MspModeRange {
823    pub box_id: u8,
824    #[packed_field(size_bits = "8", ty = "enum")]
825    pub aux_channel_index: MspRcChannel,
826    pub start_step: u8,
827    pub end_step: u8,
828}
829
830#[cfg_attr(feature = "bincode", derive(Decode, Encode, Default))]
831#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone)]
832#[packed_struct(bytes = "5", endian = "lsb", bit_numbering = "msb0")]
833pub struct MspSetModeRange {
834    pub index: u8,
835    #[packed_field(size_bytes = "4")]
836    pub mode_range: MspModeRange,
837}
838
839#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
840#[derive(PrimitiveEnum, Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Default)]
841pub enum MixerMode {
842    Tri = 1,
843    QuadPlus = 2,
844    #[default]
845    QuadX = 3,
846    Bicopter = 4,
847    Gimbal = 5,
848    Y6 = 6,
849    Hex6 = 7,
850    FlyingWing = 8,
851    Y4 = 9,
852    Hex6X = 10,
853    OctoX8 = 11,
854}
855
856#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
857#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
858#[packed_struct(bytes = "8", endian = "lsb", bit_numbering = "msb0")]
859pub struct MspMotorMixer {
860    pub throttle: u16,
861    pub roll: u16,
862    pub pitch: u16,
863    pub yaw: u16,
864}
865
866#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
867#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
868#[packed_struct(bytes = "9", endian = "lsb", bit_numbering = "msb0")]
869pub struct MspSetMotorMixer {
870    pub index: u8,
871    #[packed_field(size_bytes = "8")]
872    pub motor_mixer: MspMotorMixer,
873}
874
875pub const MSP_DP_HEARTBEAT: u8 = 0;
876pub const MSP_DP_RELEASE: u8 = 1;
877pub const MSP_DP_CLEAR_SCREEN: u8 = 2;
878pub const MSP_DP_WRITE_STRING: u8 = 3;
879pub const MSP_DP_DRAW_SCREEN: u8 = 4;
880pub const MSP_DP_OPTIONS: u8 = 5;
881pub const MSP_DP_SYS: u8 = 6;
882pub const MSP_DP_FONTCHAR_WRITE: u8 = 7;
883
884#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
885#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq)]
886pub struct MspDisplayPort {
887    pub payload: Vec<u8>,
888}
889
890impl MspDisplayPort {
891    pub fn new(payload: Vec<u8>) -> Self {
892        Self { payload }
893    }
894
895    pub fn heartbeat() -> Self {
896        Self {
897            payload: Vec::from([MSP_DP_HEARTBEAT]),
898        }
899    }
900
901    pub fn release() -> Self {
902        Self {
903            payload: Vec::from([MSP_DP_RELEASE]),
904        }
905    }
906
907    pub fn clear_screen() -> Self {
908        Self {
909            payload: Vec::from([MSP_DP_CLEAR_SCREEN]),
910        }
911    }
912
913    pub fn draw_screen() -> Self {
914        Self {
915            payload: Vec::from([MSP_DP_DRAW_SCREEN]),
916        }
917    }
918
919    pub fn write_string(row: u8, col: u8, attr: u8, text: &str) -> Self {
920        let mut payload = Vec::with_capacity(4 + text.len());
921        payload.push(MSP_DP_WRITE_STRING);
922        payload.push(row);
923        payload.push(col);
924        payload.push(attr);
925        payload.extend_from_slice(text.as_bytes());
926        Self { payload }
927    }
928
929    pub fn write_bytes(row: u8, col: u8, attr: u8, bytes: &[u8]) -> Self {
930        let mut payload = Vec::with_capacity(4 + bytes.len());
931        payload.push(MSP_DP_WRITE_STRING);
932        payload.push(row);
933        payload.push(col);
934        payload.push(attr);
935        payload.extend_from_slice(bytes);
936        Self { payload }
937    }
938
939    pub fn sys(row: u8, col: u8, element: u8) -> Self {
940        Self {
941            payload: Vec::from([MSP_DP_SYS, row, col, element]),
942        }
943    }
944
945    pub fn as_bytes(&self) -> &[u8] {
946        &self.payload
947    }
948}
949
950#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
951#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
952#[packed_struct(bytes = "13", endian = "lsb", bit_numbering = "msb0")]
953pub struct MspOsdConfig {
954    pub video_system: u8,
955    pub units: u8,
956    pub rssi_alarm: u8,
957    pub capacity_warning: u16,
958    pub time_alarm: u16,
959    pub alt_alarm: u16,
960    pub dist_alarm: u16,
961    pub neg_alt_alarm: u16,
962}
963
964#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
965#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
966#[packed_struct(bytes = "1", endian = "lsb", bit_numbering = "msb0")]
967pub struct MspSetGetOsdConfig {
968    pub item_index: u8,
969    #[packed_field(size_bytes = "13")]
970    pub config: MspOsdConfig,
971}
972
973#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
974#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
975#[packed_struct(bytes = "2", endian = "lsb", bit_numbering = "msb0")]
976pub struct MspOsdItemPosition {
977    pub col: u8,
978    pub row: u8,
979}
980
981#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
982#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
983#[packed_struct(bytes = "1", endian = "lsb", bit_numbering = "msb0")]
984pub struct MspSetOsdLayout {
985    pub item_index: u8,
986    #[packed_field(size_bytes = "2")]
987    pub item: MspOsdItemPosition,
988}
989
990// inav msp layout item
991#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
992#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
993#[packed_struct(bytes = "1", endian = "lsb", bit_numbering = "msb0")]
994pub struct MspSetOsdLayoutItem {
995    pub layout_index: u8,
996    #[packed_field(size_bytes = "3")]
997    pub item: MspSetOsdLayout,
998}
999
1000#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1001#[derive(Debug, Serialize, Deserialize, Clone, Default)]
1002pub struct MspOsdSettings {
1003    pub osd_support: u8,
1004    pub config: MspOsdConfig,
1005    pub item_positions: Vec<MspOsdItemPosition>,
1006}
1007
1008#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1009#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
1010#[packed_struct(bytes = "2", endian = "lsb", bit_numbering = "msb0")]
1011pub struct MspOsdLayouts {
1012    pub layout_count: u8,
1013    pub item_count: u8,
1014}
1015
1016#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1017#[derive(PrimitiveEnum, Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Default)]
1018pub enum SerialIdentifier {
1019    #[default]
1020    None = 255,
1021    USART1 = 0,
1022    USART2 = 1,
1023    USART3 = 2,
1024    USART4 = 3,
1025    USART5 = 4,
1026    USART6 = 5,
1027    USART7 = 6,
1028    USART8 = 7,
1029    UsbVcp = 20,
1030    SoftSerial1 = 30,
1031    SoftSerial2 = 31,
1032}
1033
1034impl TryFrom<u8> for SerialIdentifier {
1035    type Error = &'static str;
1036
1037    fn try_from(value: u8) -> Result<Self, Self::Error> {
1038        let serial = match value {
1039            255 => SerialIdentifier::None,
1040            0 => SerialIdentifier::USART1,
1041            1 => SerialIdentifier::USART2,
1042            2 => SerialIdentifier::USART3,
1043            3 => SerialIdentifier::USART4,
1044            4 => SerialIdentifier::USART5,
1045            5 => SerialIdentifier::USART6,
1046            6 => SerialIdentifier::USART7,
1047            7 => SerialIdentifier::USART8,
1048            20 => SerialIdentifier::UsbVcp,
1049            30 => SerialIdentifier::SoftSerial1,
1050            31 => SerialIdentifier::SoftSerial2,
1051            _ => return Err("Serial identifier not found"),
1052        };
1053
1054        Ok(serial)
1055    }
1056}
1057
1058#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1059#[derive(PrimitiveEnum, Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Default)]
1060pub enum Baudrate {
1061    #[default]
1062    BaudAuto = 0,
1063    Baud1200 = 1,
1064    Baud2400 = 2,
1065    Baud4800 = 3,
1066    Baud9600 = 4,
1067    Baud19200 = 5,
1068    Baud38400 = 6,
1069    Baud57600 = 7,
1070    Baud115200 = 8,
1071    Baud230400 = 9,
1072    Baud250000 = 10,
1073    Baud460800 = 11,
1074    Baud921600 = 12,
1075    Baud1000000 = 13,
1076    Baud1500000 = 14,
1077    Baud2000000 = 15,
1078    Baud2470000 = 16,
1079}
1080
1081impl TryFrom<&str> for Baudrate {
1082    type Error = &'static str;
1083
1084    fn try_from(value: &str) -> Result<Self, Self::Error> {
1085        let baudrate = match value {
1086            "0" => Baudrate::BaudAuto,
1087            "1200" => Baudrate::Baud1200,
1088            "2400" => Baudrate::Baud2400,
1089            "4800" => Baudrate::Baud4800,
1090            "9600" => Baudrate::Baud9600,
1091            "19200" => Baudrate::Baud19200,
1092            "38400" => Baudrate::Baud38400,
1093            "57600" => Baudrate::Baud57600,
1094            "115200" => Baudrate::Baud115200,
1095            "230400" => Baudrate::Baud230400,
1096            "250000" => Baudrate::Baud250000,
1097            "460800" => Baudrate::Baud460800,
1098            "921600" => Baudrate::Baud921600,
1099            "1000000" => Baudrate::Baud1000000,
1100            "1500000" => Baudrate::Baud1500000,
1101            "2000000" => Baudrate::Baud2000000,
1102            "2470000" => Baudrate::Baud2470000,
1103            _ => return Err("Baudrate identifier not found"),
1104        };
1105
1106        Ok(baudrate)
1107    }
1108}
1109
1110impl From<Baudrate> for String {
1111    fn from(value: Baudrate) -> Self {
1112        match value {
1113            Baudrate::BaudAuto => "0",
1114            Baudrate::Baud1200 => "1200",
1115            Baudrate::Baud2400 => "2400",
1116            Baudrate::Baud4800 => "4800",
1117            Baudrate::Baud9600 => "9600",
1118            Baudrate::Baud19200 => "19200",
1119            Baudrate::Baud38400 => "38400",
1120            Baudrate::Baud57600 => "57600",
1121            Baudrate::Baud115200 => "115200",
1122            Baudrate::Baud230400 => "230400",
1123            Baudrate::Baud250000 => "250000",
1124            Baudrate::Baud460800 => "460800",
1125            Baudrate::Baud921600 => "921600",
1126            Baudrate::Baud1000000 => "1000000",
1127            Baudrate::Baud1500000 => "1500000",
1128            Baudrate::Baud2000000 => "2000000",
1129            Baudrate::Baud2470000 => "2470000",
1130        }
1131        .to_owned()
1132    }
1133}
1134
1135#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1136#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
1137#[packed_struct(endian = "lsb", bit_numbering = "msb0")]
1138pub struct MspSerialSetting {
1139    #[packed_field(size_bits = "8", ty = "enum")]
1140    pub identifier: SerialIdentifier,
1141    pub function_mask: u32,
1142    #[packed_field(size_bits = "8", ty = "enum")]
1143    pub msp_baudrate_index: Baudrate,
1144    #[packed_field(size_bits = "8", ty = "enum")]
1145    pub gps_baudrate_index: Baudrate,
1146    #[packed_field(size_bits = "8", ty = "enum")]
1147    pub telemetry_baudrate_index: Baudrate,
1148    #[packed_field(size_bits = "8", ty = "enum")]
1149    pub peripheral_baudrate_index: Baudrate,
1150}
1151
1152#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1153#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
1154#[packed_struct(bytes = "1", endian = "lsb", bit_numbering = "msb0")]
1155pub struct MspSetServoMixRule {
1156    pub index: u8,
1157    #[packed_field(size_bytes = "8")]
1158    pub servo_rule: MspServoMixRule,
1159}
1160
1161#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1162#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
1163#[packed_struct(bytes = "8", endian = "lsb", bit_numbering = "msb0")]
1164pub struct MspServoMixRule {
1165    pub target_channel: u8,
1166    pub input_source: u8,
1167    pub rate: u16,
1168    pub speed: u8,
1169    pub min: u8,
1170    pub max: u8,
1171    pub box_id: u8,
1172}
1173
1174#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1175#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
1176#[packed_struct(bytes = "1", endian = "lsb", bit_numbering = "msb0")]
1177pub struct MspSetServoMixer {
1178    pub index: u8,
1179    #[packed_field(size_bytes = "6")]
1180    pub servo_rule: MspServoMixer,
1181}
1182
1183#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1184#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
1185#[packed_struct(bytes = "6", endian = "lsb", bit_numbering = "msb0")]
1186pub struct MspServoMixer {
1187    pub target_channel: u8,
1188    pub input_source: u8,
1189    pub rate: i16,
1190    pub speed: u8,
1191    pub condition_id: i8,
1192}
1193
1194#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1195#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
1196#[packed_struct(endian = "lsb", bit_numbering = "msb0")]
1197pub struct MspRxMap {
1198    pub map: [u8; 4], // MAX_MAPPABLE_RX_INPUTS
1199}
1200
1201#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1202#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
1203#[packed_struct(endian = "lsb", bit_numbering = "msb0")]
1204pub struct MspSettingGroup {
1205    pub group_id: u16,
1206    pub start_id: u16,
1207    pub end_id: u16,
1208}
1209
1210#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1211#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
1212#[packed_struct(endian = "lsb", bit_numbering = "msb0")]
1213pub struct MspSettingInfoRequest {
1214    pub null: u8,
1215    pub id: u16,
1216}
1217
1218#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1219#[derive(PrimitiveEnum, Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Default)]
1220pub enum SettingMode {
1221    #[default]
1222    ModeDirect = 0,
1223    ModeLookup = 0x40,
1224}
1225
1226#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1227#[derive(PrimitiveEnum, Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Default)]
1228pub enum SettingType {
1229    #[default]
1230    VarUint8 = 0,
1231    VarInt8,
1232    VarUint16,
1233    VarInt16,
1234    VarUint32,
1235    VarInt32,
1236    VarFloat,
1237    VarString,
1238}
1239
1240#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1241#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone, Default)]
1242#[packed_struct(bytes = "15", endian = "lsb", bit_numbering = "msb0")]
1243pub struct MspSettingInfo {
1244    // pub name: [u8; ?], null terminated strings
1245
1246    // Parameter Group ID
1247    pub group_id: u16,
1248
1249    // Type, section and mode
1250    #[packed_field(size_bits = "8", ty = "enum")]
1251    pub setting_type: SettingType,
1252    pub setting_section: u8,
1253    #[packed_field(size_bits = "8", ty = "enum")]
1254    pub setting_mode: SettingMode,
1255
1256    pub min: u32,
1257    pub max: u32,
1258
1259    // Absolute setting index
1260    pub absolute_index: u16,
1261
1262    // If the setting is profile based, send the current one
1263    // and the count, both as uint8_t. For MASTER_VALUE, we
1264    // send two zeroes, so the MSP client can assume there
1265    pub profile_id: u8,
1266    pub profile_count: u8,
1267    // if setting uses enum values, it will be written here
1268    // pub enum_names: [String; ?] // TODO: packed_struct should support null terminated string parsing
1269    // pub value: [u8; ?]
1270}
1271
1272#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1273#[derive(PackedStruct, Serialize, Deserialize, Debug, Copy, Clone)]
1274#[packed_struct(endian = "lsb")]
1275pub struct MspRc {
1276    pub channels: [u16; 16], // 16 RC channels
1277}
1278
1279impl Default for MspRc {
1280    fn default() -> Self {
1281        Self::new()
1282    }
1283}
1284
1285impl MspRc {
1286    pub fn new() -> Self {
1287        MspRc { channels: [0; 16] }
1288    }
1289
1290    pub fn set_roll(&mut self, value: u16) {
1291        self.channels[0] = value;
1292    }
1293
1294    pub fn set_pitch(&mut self, value: u16) {
1295        self.channels[1] = value;
1296    }
1297
1298    pub fn set_throttle(&mut self, value: u16) {
1299        self.channels[2] = value;
1300    }
1301
1302    pub fn set_yaw(&mut self, value: u16) {
1303        self.channels[3] = value;
1304    }
1305
1306    pub fn set_aux1(&mut self, value: u16) {
1307        self.channels[4] = value;
1308    }
1309    pub fn set_aux2(&mut self, value: u16) {
1310        self.channels[5] = value;
1311    }
1312    pub fn set_aux3(&mut self, value: u16) {
1313        self.channels[6] = value;
1314    }
1315    pub fn set_aux4(&mut self, value: u16) {
1316        self.channels[7] = value;
1317    }
1318}
1319
1320// Gather all the commands in a common enum we can use as a higher level protocol
1321#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1322#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1323pub enum MspRequest {
1324    #[default]
1325    Unknown,
1326    MspApiVersionRequest,
1327    MspApiVersion(MspApiVersion),
1328    MspFcVersionRequest,
1329    MspFlightControllerVersion(MspFlightControllerVersion),
1330    MspBatteryConfigRequest,
1331    MspBatteryConfig(MspBatteryConfig),
1332    MspBatteryStateRequest,
1333    MspBatteryState(MspBatteryState),
1334    MspAnalogRequest,
1335    MspAnalog(MspAnalog),
1336    MspVoltageMeterConfigRequest,
1337    MspVoltageMeterConfig(MspVoltageMeterConfig),
1338    MspVoltageMetersRequest,
1339    MspVoltageMeter(MspVoltageMeter),
1340    MspRc,
1341    MspSetRawRc(MspRc),
1342    MspRawImu,
1343    MspStatus(MspStatus),
1344    MspStatusEx(MspStatusEx),
1345    MspDisplayPort(MspDisplayPort),
1346    MspSensorRangefinder(MspSensorRangefinder),
1347    MspSensorOpticFlow(MspSensorOpticFlow),
1348}
1349
1350impl MspRequest {
1351    pub fn command_code(&self) -> MspCommandCode {
1352        match self {
1353            MspRequest::MspApiVersionRequest => MspCommandCode::MSP_API_VERSION,
1354            MspRequest::MspApiVersion(_) => MspCommandCode::MSP_API_VERSION,
1355            MspRequest::MspFcVersionRequest => MspCommandCode::MSP_FC_VERSION,
1356            MspRequest::MspFlightControllerVersion(_) => MspCommandCode::MSP_FC_VERSION,
1357            MspRequest::MspBatteryConfigRequest => MspCommandCode::MSP_BATTERY_CONFIG,
1358            MspRequest::MspBatteryConfig(_) => MspCommandCode::MSP_BATTERY_CONFIG,
1359            MspRequest::MspBatteryStateRequest => MspCommandCode::MSP_BATTERY_STATE,
1360            MspRequest::MspBatteryState(_) => MspCommandCode::MSP_BATTERY_STATE,
1361            MspRequest::MspAnalogRequest => MspCommandCode::MSP_ANALOG,
1362            MspRequest::MspAnalog(_) => MspCommandCode::MSP_ANALOG,
1363            MspRequest::MspVoltageMeterConfigRequest => MspCommandCode::MSP_VOLTAGE_METER_CONFIG,
1364            MspRequest::MspVoltageMeterConfig(_) => MspCommandCode::MSP_VOLTAGE_METER_CONFIG,
1365            MspRequest::MspVoltageMetersRequest => MspCommandCode::MSP_VOLTAGE_METERS,
1366            MspRequest::MspVoltageMeter(_) => MspCommandCode::MSP_VOLTAGE_METERS,
1367            MspRequest::MspRc => MspCommandCode::MSP_RC,
1368            MspRequest::MspSetRawRc(_) => MspCommandCode::MSP_SET_RAW_RC,
1369            MspRequest::MspRawImu => MspCommandCode::MSP_RAW_IMU,
1370            MspRequest::MspStatus(_) => MspCommandCode::MSP_STATUS,
1371            MspRequest::MspStatusEx(_) => MspCommandCode::MSP_STATUS_EX,
1372            MspRequest::MspDisplayPort(_) => MspCommandCode::MSP_DISPLAYPORT,
1373            MspRequest::MspSensorRangefinder(_) => MspCommandCode::MSP2_SENSOR_RANGEFINDER,
1374            MspRequest::MspSensorOpticFlow(_) => MspCommandCode::MSP2_SENSOR_OPTIC_FLOW,
1375            _ => MspCommandCode::MSP_API_VERSION,
1376        }
1377    }
1378
1379    pub fn from_command_code(cmd: MspCommandCode) -> Option<Self> {
1380        match cmd {
1381            MspCommandCode::MSP_API_VERSION => Some(MspRequest::MspApiVersionRequest),
1382            MspCommandCode::MSP_FC_VERSION => Some(MspRequest::MspFcVersionRequest),
1383            MspCommandCode::MSP_BATTERY_CONFIG => Some(MspRequest::MspBatteryConfigRequest),
1384            MspCommandCode::MSP_BATTERY_STATE => Some(MspRequest::MspBatteryStateRequest),
1385            MspCommandCode::MSP_ANALOG => Some(MspRequest::MspAnalogRequest),
1386            MspCommandCode::MSP_VOLTAGE_METER_CONFIG => {
1387                Some(MspRequest::MspVoltageMeterConfigRequest)
1388            }
1389            MspCommandCode::MSP_VOLTAGE_METERS => Some(MspRequest::MspVoltageMetersRequest),
1390            MspCommandCode::MSP_RC => Some(MspRequest::MspRc),
1391            MspCommandCode::MSP_RAW_IMU => Some(MspRequest::MspRawImu),
1392            _ => None,
1393        }
1394    }
1395
1396    pub fn from_command_id(cmd: u16) -> Option<Self> {
1397        let cmd = MspCommandCode::from_primitive(cmd)?;
1398        Self::from_command_code(cmd)
1399    }
1400
1401    pub fn from_packet(packet: &MspPacket) -> Option<Self> {
1402        let cmd = MspCommandCode::from_primitive(packet.cmd)?;
1403        match cmd {
1404            MspCommandCode::MSP2_SENSOR_RANGEFINDER => packet
1405                .decode_as::<MspSensorRangefinder>()
1406                .ok()
1407                .map(MspRequest::MspSensorRangefinder),
1408            MspCommandCode::MSP2_SENSOR_OPTIC_FLOW => packet
1409                .decode_as::<MspSensorOpticFlow>()
1410                .ok()
1411                .map(MspRequest::MspSensorOpticFlow),
1412            _ => Self::from_command_code(cmd),
1413        }
1414    }
1415}
1416
1417fn pack_or_empty<T: PackedStruct>(value: Option<&T>) -> Result<MspPacketData, PackingError> {
1418    if let Some(value) = value {
1419        let packed = value.pack()?;
1420        Ok(MspPacketData::from(packed.as_bytes_slice()))
1421    } else {
1422        Ok(MspPacketData::default())
1423    }
1424}
1425
1426impl From<MspRequest> for MspPacket {
1427    fn from(request: MspRequest) -> Self {
1428        match request {
1429            MspRequest::MspApiVersionRequest => MspPacket {
1430                cmd: MspCommandCode::MSP_API_VERSION.to_primitive(),
1431                direction: ToFlightController,
1432                data: MspPacketData::new(),
1433            },
1434            MspRequest::MspApiVersion(version) => MspPacket {
1435                cmd: MspCommandCode::MSP_API_VERSION.to_primitive(),
1436                direction: FromFlightController,
1437                data: pack_or_empty(Some(&version)).unwrap_or_default(),
1438            },
1439            MspRequest::MspFcVersionRequest => MspPacket {
1440                cmd: MspCommandCode::MSP_FC_VERSION.to_primitive(),
1441                direction: ToFlightController,
1442                data: MspPacketData::new(),
1443            },
1444            MspRequest::MspFlightControllerVersion(version) => MspPacket {
1445                cmd: MspCommandCode::MSP_FC_VERSION.to_primitive(),
1446                direction: FromFlightController,
1447                data: pack_or_empty(Some(&version)).unwrap_or_default(),
1448            },
1449            MspRequest::MspBatteryConfigRequest => MspPacket {
1450                cmd: MspCommandCode::MSP_BATTERY_CONFIG.to_primitive(),
1451                direction: ToFlightController,
1452                data: MspPacketData::new(),
1453            },
1454            MspRequest::MspBatteryConfig(config) => MspPacket {
1455                cmd: MspCommandCode::MSP_BATTERY_CONFIG.to_primitive(),
1456                direction: FromFlightController,
1457                data: pack_or_empty(Some(&config)).unwrap_or_default(),
1458            },
1459            MspRequest::MspBatteryStateRequest => MspPacket {
1460                cmd: MspCommandCode::MSP_BATTERY_STATE.to_primitive(),
1461                direction: ToFlightController,
1462                data: MspPacketData::new(), // empty
1463            },
1464            MspRequest::MspBatteryState(state) => MspPacket {
1465                cmd: MspCommandCode::MSP_BATTERY_STATE.to_primitive(),
1466                direction: FromFlightController,
1467                data: pack_or_empty(Some(&state)).unwrap_or_default(),
1468            },
1469            MspRequest::MspAnalogRequest => MspPacket {
1470                cmd: MspCommandCode::MSP_ANALOG.to_primitive(),
1471                direction: ToFlightController,
1472                data: MspPacketData::new(), // empty
1473            },
1474            MspRequest::MspAnalog(analog) => MspPacket {
1475                cmd: MspCommandCode::MSP_ANALOG.to_primitive(),
1476                direction: FromFlightController,
1477                data: pack_or_empty(Some(&analog)).unwrap_or_default(),
1478            },
1479            MspRequest::MspVoltageMeterConfigRequest => MspPacket {
1480                cmd: MspCommandCode::MSP_VOLTAGE_METER_CONFIG.to_primitive(),
1481                direction: ToFlightController,
1482                data: MspPacketData::new(),
1483            },
1484            MspRequest::MspVoltageMeterConfig(config) => MspPacket {
1485                cmd: MspCommandCode::MSP_VOLTAGE_METER_CONFIG.to_primitive(),
1486                direction: FromFlightController,
1487                data: pack_or_empty(Some(&config)).unwrap_or_default(),
1488            },
1489            MspRequest::MspVoltageMetersRequest => MspPacket {
1490                cmd: MspCommandCode::MSP_VOLTAGE_METERS.to_primitive(),
1491                direction: ToFlightController,
1492                data: MspPacketData::new(), // empty
1493            },
1494            MspRequest::MspVoltageMeter(meter) => MspPacket {
1495                cmd: MspCommandCode::MSP_VOLTAGE_METERS.to_primitive(),
1496                direction: FromFlightController,
1497                data: pack_or_empty(Some(&meter)).unwrap_or_default(),
1498            },
1499            MspRequest::MspRc => MspPacket {
1500                cmd: MspCommandCode::MSP_RC.to_primitive(),
1501                direction: ToFlightController,
1502                data: MspPacketData::new(), // empty
1503            },
1504            MspRequest::MspSetRawRc(rc) => {
1505                let data = rc.pack().unwrap();
1506                MspPacket {
1507                    cmd: MspCommandCode::MSP_SET_RAW_RC.to_primitive(),
1508                    direction: ToFlightController,
1509                    data: MspPacketData::from(data.as_slice()),
1510                }
1511            }
1512            MspRequest::MspRawImu => MspPacket {
1513                cmd: MspCommandCode::MSP_RAW_IMU.to_primitive(),
1514                direction: ToFlightController,
1515                data: MspPacketData::new(), // empty
1516            },
1517            MspRequest::MspStatus(status) => MspPacket {
1518                cmd: MspCommandCode::MSP_STATUS.to_primitive(),
1519                direction: FromFlightController,
1520                data: status.to_packet_data().unwrap(),
1521            },
1522            MspRequest::MspStatusEx(status) => MspPacket {
1523                cmd: MspCommandCode::MSP_STATUS_EX.to_primitive(),
1524                direction: FromFlightController,
1525                data: status.to_packet_data().unwrap(),
1526            },
1527            MspRequest::MspDisplayPort(displayport) => MspPacket {
1528                cmd: MspCommandCode::MSP_DISPLAYPORT.to_primitive(),
1529                direction: FromFlightController,
1530                data: MspPacketData::from(displayport.as_bytes()),
1531            },
1532            MspRequest::MspSensorRangefinder(data) => MspPacket {
1533                cmd: MspCommandCode::MSP2_SENSOR_RANGEFINDER.to_primitive(),
1534                direction: ToFlightController,
1535                data: pack_or_empty(Some(&data)).unwrap_or_default(),
1536            },
1537            MspRequest::MspSensorOpticFlow(data) => MspPacket {
1538                cmd: MspCommandCode::MSP2_SENSOR_OPTIC_FLOW.to_primitive(),
1539                direction: ToFlightController,
1540                data: pack_or_empty(Some(&data)).unwrap_or_default(),
1541            },
1542            _ => MspPacket {
1543                cmd: MspCommandCode::MSP_API_VERSION.to_primitive(),
1544                direction: ToFlightController,
1545                data: MspPacketData::new(), // empty
1546            },
1547        }
1548    }
1549}
1550
1551impl From<&MspRequest> for MspPacket {
1552    fn from(request: &MspRequest) -> Self {
1553        match request {
1554            MspRequest::MspApiVersionRequest => MspPacket {
1555                cmd: MspCommandCode::MSP_API_VERSION.to_primitive(),
1556                direction: ToFlightController,
1557                data: MspPacketData::new(),
1558            },
1559            MspRequest::MspApiVersion(version) => MspPacket {
1560                cmd: MspCommandCode::MSP_API_VERSION.to_primitive(),
1561                direction: FromFlightController,
1562                data: pack_or_empty(Some(version)).unwrap_or_default(),
1563            },
1564            MspRequest::MspFcVersionRequest => MspPacket {
1565                cmd: MspCommandCode::MSP_FC_VERSION.to_primitive(),
1566                direction: ToFlightController,
1567                data: MspPacketData::new(),
1568            },
1569            MspRequest::MspFlightControllerVersion(version) => MspPacket {
1570                cmd: MspCommandCode::MSP_FC_VERSION.to_primitive(),
1571                direction: FromFlightController,
1572                data: pack_or_empty(Some(version)).unwrap_or_default(),
1573            },
1574            MspRequest::MspBatteryConfigRequest => MspPacket {
1575                cmd: MspCommandCode::MSP_BATTERY_CONFIG.to_primitive(),
1576                direction: ToFlightController,
1577                data: MspPacketData::new(),
1578            },
1579            MspRequest::MspBatteryConfig(config) => MspPacket {
1580                cmd: MspCommandCode::MSP_BATTERY_CONFIG.to_primitive(),
1581                direction: FromFlightController,
1582                data: pack_or_empty(Some(config)).unwrap_or_default(),
1583            },
1584            MspRequest::MspBatteryStateRequest => MspPacket {
1585                cmd: MspCommandCode::MSP_BATTERY_STATE.to_primitive(),
1586                direction: ToFlightController,
1587                data: MspPacketData::new(), // empty
1588            },
1589            MspRequest::MspBatteryState(state) => MspPacket {
1590                cmd: MspCommandCode::MSP_BATTERY_STATE.to_primitive(),
1591                direction: FromFlightController,
1592                data: pack_or_empty(Some(state)).unwrap_or_default(),
1593            },
1594            MspRequest::MspAnalogRequest => MspPacket {
1595                cmd: MspCommandCode::MSP_ANALOG.to_primitive(),
1596                direction: ToFlightController,
1597                data: MspPacketData::new(), // empty
1598            },
1599            MspRequest::MspAnalog(analog) => MspPacket {
1600                cmd: MspCommandCode::MSP_ANALOG.to_primitive(),
1601                direction: FromFlightController,
1602                data: pack_or_empty(Some(analog)).unwrap_or_default(),
1603            },
1604            MspRequest::MspVoltageMeterConfigRequest => MspPacket {
1605                cmd: MspCommandCode::MSP_VOLTAGE_METER_CONFIG.to_primitive(),
1606                direction: ToFlightController,
1607                data: MspPacketData::new(),
1608            },
1609            MspRequest::MspVoltageMeterConfig(config) => MspPacket {
1610                cmd: MspCommandCode::MSP_VOLTAGE_METER_CONFIG.to_primitive(),
1611                direction: FromFlightController,
1612                data: pack_or_empty(Some(config)).unwrap_or_default(),
1613            },
1614            MspRequest::MspVoltageMetersRequest => MspPacket {
1615                cmd: MspCommandCode::MSP_VOLTAGE_METERS.to_primitive(),
1616                direction: ToFlightController,
1617                data: MspPacketData::new(), // empty
1618            },
1619            MspRequest::MspVoltageMeter(meter) => MspPacket {
1620                cmd: MspCommandCode::MSP_VOLTAGE_METERS.to_primitive(),
1621                direction: FromFlightController,
1622                data: pack_or_empty(Some(meter)).unwrap_or_default(),
1623            },
1624            MspRequest::MspRc => MspPacket {
1625                cmd: MspCommandCode::MSP_RC.to_primitive(),
1626                direction: ToFlightController,
1627                data: MspPacketData::new(), // empty
1628            },
1629            MspRequest::MspSetRawRc(rc) => MspPacket {
1630                cmd: MspCommandCode::MSP_SET_RAW_RC.to_primitive(),
1631                direction: ToFlightController,
1632                data: MspPacketData::from(rc.pack().unwrap().as_slice()),
1633            },
1634            MspRequest::MspRawImu => MspPacket {
1635                cmd: MspCommandCode::MSP_RAW_IMU.to_primitive(),
1636                direction: ToFlightController,
1637                data: MspPacketData::new(), // empty
1638            },
1639            MspRequest::MspStatus(status) => MspPacket {
1640                cmd: MspCommandCode::MSP_STATUS.to_primitive(),
1641                direction: FromFlightController,
1642                data: status.to_packet_data().unwrap(),
1643            },
1644            MspRequest::MspStatusEx(status) => MspPacket {
1645                cmd: MspCommandCode::MSP_STATUS_EX.to_primitive(),
1646                direction: FromFlightController,
1647                data: status.to_packet_data().unwrap(),
1648            },
1649            MspRequest::MspDisplayPort(displayport) => MspPacket {
1650                cmd: MspCommandCode::MSP_DISPLAYPORT.to_primitive(),
1651                direction: FromFlightController,
1652                data: MspPacketData::from(displayport.as_bytes()),
1653            },
1654            MspRequest::MspSensorRangefinder(data) => MspPacket {
1655                cmd: MspCommandCode::MSP2_SENSOR_RANGEFINDER.to_primitive(),
1656                direction: ToFlightController,
1657                data: pack_or_empty(Some(data)).unwrap_or_default(),
1658            },
1659            MspRequest::MspSensorOpticFlow(data) => MspPacket {
1660                cmd: MspCommandCode::MSP2_SENSOR_OPTIC_FLOW.to_primitive(),
1661                direction: ToFlightController,
1662                data: pack_or_empty(Some(data)).unwrap_or_default(),
1663            },
1664            _ => MspPacket {
1665                cmd: MspCommandCode::MSP_API_VERSION.to_primitive(),
1666                direction: ToFlightController,
1667                data: MspPacketData::new(), // empty
1668            },
1669        }
1670    }
1671}
1672
1673// Gather all the commands in a common enum we can use as a higher level protocol
1674#[cfg_attr(feature = "bincode", derive(Decode, Encode))]
1675#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1676pub enum MspResponse {
1677    #[default]
1678    Unknown,
1679    MspApiVersion(MspApiVersion),
1680    MspFlightControllerVariant(MspFlightControllerVariant),
1681    MspStatus(MspStatus),
1682    MspStatusEx(MspStatusEx),
1683    MspBfConfig(MspBfConfig),
1684    MspRawImu(MspRawImu),
1685    MspDataFlashSummaryReply(MspDataFlashSummaryReply),
1686    MspDataFlashReply(MspDataFlashReply),
1687    MspDataFlashRead(MspDataFlashRead),
1688    MspAccTrim(MspAccTrim),
1689    MspIdent(MspIdent),
1690    MspMisc(MspMisc),
1691    MspAttitude(MspAttitude),
1692    MspAltitude(MspAltitude),
1693    MspBatteryConfig(MspBatteryConfig),
1694    MspVoltageMeterConfig(MspVoltageMeterConfig),
1695    MspAnalog(MspAnalog),
1696    MspRssiConfig(MspRssiConfig),
1697    MspVoltageMeter(MspVoltageMeter),
1698    MspCurrentMeter(MspCurrentMeter),
1699    MspBatteryState(MspBatteryState),
1700    MspRcTuning(MspRcTuning),
1701    MspRxConfig(MspRxConfig),
1702    MspRcChannelValue(MspRcChannelValue),
1703    MspRcMappedChannel(MspRcMappedChannel),
1704    MspFeatures(MspFeatures),
1705    MspMotor(MspMotor),
1706    MspMotor3DConfig(MspMotor3DConfig),
1707    MspMotorConfig(MspMotorConfig),
1708    MspRcDeadband(MspRcDeadband),
1709    MspSensorAlignment(MspSensorAlignment),
1710    MspAdvancedConfig(MspAdvancedConfig),
1711    MspFilterConfig(MspFilterConfig),
1712    MspPidAdvanced(MspPidAdvanced),
1713    MspSensorConfig(MspSensorConfig),
1714    MspServos(MspServos),
1715    MspMixerConfig(MspMixerConfig),
1716    MspModeRange(MspModeRange),
1717    MspSetModeRange(MspSetModeRange),
1718    MspOsdConfig(MspOsdConfig),
1719    MspSetGetOsdConfig(MspSetGetOsdConfig),
1720    MspSetOsdLayout(MspSetOsdLayout),
1721    MspSetOsdLayoutItem(MspSetOsdLayoutItem),
1722    MspOsdLayouts(MspOsdLayouts),
1723    MspSerialSetting(MspSerialSetting),
1724    MspSettingInfoRequest(MspSettingInfoRequest),
1725    MspSettingInfo(MspSettingInfo),
1726    MspRc(MspRc),
1727}
1728
1729macro_rules! msp_response_command_map {
1730    ($($variant:ident => $cmd:ident),* $(,)?) => {
1731        fn response_command_code(resp: &MspResponse) -> MspCommandCode {
1732            match resp {
1733                $(MspResponse::$variant(_) => MspCommandCode::$cmd,)*
1734                MspResponse::Unknown => MspCommandCode::MSP_API_VERSION,
1735            }
1736        }
1737    };
1738}
1739
1740macro_rules! msp_response_decode_map {
1741    ($($cmd:ident => $variant:ident : $ty:ty => |$packet:ident| $decode:expr),* $(,)?) => {
1742        fn decode_response(cmd: MspCommandCode, packet: &MspPacket) -> MspResponse {
1743            match cmd {
1744                $(
1745                    MspCommandCode::$cmd => {
1746                        let $packet = packet;
1747                        $decode
1748                            .map(MspResponse::$variant)
1749                            .unwrap_or(MspResponse::Unknown)
1750                    }
1751                )*
1752                _ => MspResponse::Unknown,
1753            }
1754        }
1755    };
1756}
1757
1758msp_response_command_map!(
1759    MspApiVersion => MSP_API_VERSION,
1760    MspFlightControllerVariant => MSP_FC_VARIANT,
1761    MspStatus => MSP_STATUS,
1762    MspStatusEx => MSP_STATUS_EX,
1763    MspBfConfig => MSP_BF_CONFIG,
1764    MspRawImu => MSP_RAW_IMU,
1765    MspDataFlashSummaryReply => MSP_DATAFLASH_SUMMARY,
1766    MspDataFlashReply => MSP_DATAFLASH_READ,
1767    MspDataFlashRead => MSP_DATAFLASH_READ,
1768    MspAccTrim => MSP_ACC_TRIM,
1769    MspIdent => MSP_IDENT,
1770    MspMisc => MSP_MISC,
1771    MspAttitude => MSP_ATTITUDE,
1772    MspAltitude => MSP_ALTITUDE,
1773    MspBatteryConfig => MSP_BATTERY_CONFIG,
1774    MspVoltageMeterConfig => MSP_VOLTAGE_METER_CONFIG,
1775    MspAnalog => MSP_ANALOG,
1776    MspRssiConfig => MSP_RSSI_CONFIG,
1777    MspVoltageMeter => MSP_VOLTAGE_METERS,
1778    MspCurrentMeter => MSP_AMPERAGE_METER_CONFIG,
1779    MspBatteryState => MSP_BATTERY_STATE,
1780    MspRcTuning => MSP_RC_TUNING,
1781    MspRxConfig => MSP_RX_CONFIG,
1782    MspRcChannelValue => MSP_RX_MAP,
1783    MspRcMappedChannel => MSP_SET_RX_MAP,
1784    MspFeatures => MSP_FEATURE,
1785    MspMotor => MSP_MOTOR,
1786    MspMotor3DConfig => MSP_MOTOR_3D_CONFIG,
1787    MspMotorConfig => MSP_MOTOR_CONFIG,
1788    MspRcDeadband => MSP_RC_DEADBAND,
1789    MspSensorAlignment => MSP_BOARD_ALIGNMENT,
1790    MspAdvancedConfig => MSP_ADVANCED_CONFIG,
1791    MspFilterConfig => MSP_FILTER_CONFIG,
1792    MspPidAdvanced => MSP_PID_ADVANCED,
1793    MspSensorConfig => MSP_SENSOR_CONFIG,
1794    MspServos => MSP_SERVO,
1795    MspMixerConfig => MSP_MIXER,
1796    MspModeRange => MSP_MODE_RANGES,
1797    MspSetModeRange => MSP_SET_MODE_RANGE,
1798    MspOsdConfig => MSP_OSD_CONFIG,
1799    MspSetGetOsdConfig => MSP_OSD_CONFIG,
1800    MspSetOsdLayout => MSP_OSD_LAYOUT_CONFIG,
1801    MspSetOsdLayoutItem => MSP2_INAV_OSD_SET_LAYOUT_ITEM,
1802    MspOsdLayouts => MSP2_INAV_OSD_LAYOUTS,
1803    MspSerialSetting => MSP2_SET_SERIAL_CONFIG,
1804    MspSettingInfoRequest => MSP2_COMMON_SETTING,
1805    MspSettingInfo => MSP2_COMMON_SETTING_INFO,
1806    MspRc => MSP_RC,
1807);
1808
1809msp_response_decode_map!(
1810    MSP_API_VERSION => MspApiVersion: MspApiVersion => |packet| packet.decode_as::<MspApiVersion>(),
1811    MSP_FC_VARIANT => MspFlightControllerVariant: MspFlightControllerVariant => |packet| {
1812        packet.decode_as::<MspFlightControllerVariant>()
1813    },
1814    MSP_STATUS => MspStatus: MspStatus => |packet| MspStatus::from_bytes(packet.data.as_slice()),
1815    MSP_STATUS_EX => MspStatusEx: MspStatusEx => |packet| {
1816        MspStatusEx::from_bytes(packet.data.as_slice())
1817    },
1818    MSP_BF_CONFIG => MspBfConfig: MspBfConfig => |packet| packet.decode_as::<MspBfConfig>(),
1819    MSP_RAW_IMU => MspRawImu: MspRawImu => |packet| packet.decode_as::<MspRawImu>(),
1820    MSP_DATAFLASH_SUMMARY => MspDataFlashSummaryReply: MspDataFlashSummaryReply => |packet| {
1821        packet.decode_as::<MspDataFlashSummaryReply>()
1822    },
1823    MSP_DATAFLASH_READ => MspDataFlashReply: MspDataFlashReply => |packet| {
1824        packet.decode_as::<MspDataFlashReply>()
1825    },
1826    MSP_ACC_TRIM => MspAccTrim: MspAccTrim => |packet| packet.decode_as::<MspAccTrim>(),
1827    MSP_IDENT => MspIdent: MspIdent => |packet| packet.decode_as::<MspIdent>(),
1828    MSP_MISC => MspMisc: MspMisc => |packet| packet.decode_as::<MspMisc>(),
1829    MSP_ATTITUDE => MspAttitude: MspAttitude => |packet| packet.decode_as::<MspAttitude>(),
1830    MSP_ALTITUDE => MspAltitude: MspAltitude => |packet| packet.decode_as::<MspAltitude>(),
1831    MSP_BATTERY_CONFIG => MspBatteryConfig: MspBatteryConfig => |packet| {
1832        packet.decode_as::<MspBatteryConfig>()
1833    },
1834    MSP_VOLTAGE_METER_CONFIG => MspVoltageMeterConfig: MspVoltageMeterConfig => |packet| {
1835        packet.decode_as::<MspVoltageMeterConfig>()
1836    },
1837    MSP_ANALOG => MspAnalog: MspAnalog => |packet| packet.decode_as::<MspAnalog>(),
1838    MSP_RSSI_CONFIG => MspRssiConfig: MspRssiConfig => |packet| {
1839        packet.decode_as::<MspRssiConfig>()
1840    },
1841    MSP_VOLTAGE_METERS => MspVoltageMeter: MspVoltageMeter => |packet| {
1842        packet.decode_as::<MspVoltageMeter>()
1843    },
1844    MSP_AMPERAGE_METER_CONFIG => MspCurrentMeter: MspCurrentMeter => |packet| {
1845        packet.decode_as::<MspCurrentMeter>()
1846    },
1847    MSP_BATTERY_STATE => MspBatteryState: MspBatteryState => |packet| {
1848        packet.decode_as::<MspBatteryState>()
1849    },
1850    MSP_RC_TUNING => MspRcTuning: MspRcTuning => |packet| packet.decode_as::<MspRcTuning>(),
1851    MSP_RX_CONFIG => MspRxConfig: MspRxConfig => |packet| packet.decode_as::<MspRxConfig>(),
1852    MSP_RX_MAP => MspRcChannelValue: MspRcChannelValue => |packet| {
1853        packet.decode_as::<MspRcChannelValue>()
1854    },
1855    MSP_SET_RX_MAP => MspRcMappedChannel: MspRcMappedChannel => |packet| {
1856        packet.decode_as::<MspRcMappedChannel>()
1857    },
1858    MSP_FEATURE => MspFeatures: MspFeatures => |packet| packet.decode_as::<MspFeatures>(),
1859    MSP_MOTOR => MspMotor: MspMotor => |packet| packet.decode_as::<MspMotor>(),
1860    MSP_MOTOR_3D_CONFIG => MspMotor3DConfig: MspMotor3DConfig => |packet| {
1861        packet.decode_as::<MspMotor3DConfig>()
1862    },
1863    MSP_MOTOR_CONFIG => MspMotorConfig: MspMotorConfig => |packet| {
1864        packet.decode_as::<MspMotorConfig>()
1865    },
1866    MSP_RC_DEADBAND => MspRcDeadband: MspRcDeadband => |packet| packet.decode_as::<MspRcDeadband>(),
1867    MSP_BOARD_ALIGNMENT => MspSensorAlignment: MspSensorAlignment => |packet| {
1868        packet.decode_as::<MspSensorAlignment>()
1869    },
1870    MSP_ADVANCED_CONFIG => MspAdvancedConfig: MspAdvancedConfig => |packet| {
1871        packet.decode_as::<MspAdvancedConfig>()
1872    },
1873    MSP_FILTER_CONFIG => MspFilterConfig: MspFilterConfig => |packet| {
1874        packet.decode_as::<MspFilterConfig>()
1875    },
1876    MSP_PID_ADVANCED => MspPidAdvanced: MspPidAdvanced => |packet| {
1877        packet.decode_as::<MspPidAdvanced>()
1878    },
1879    MSP_SENSOR_CONFIG => MspSensorConfig: MspSensorConfig => |packet| {
1880        packet.decode_as::<MspSensorConfig>()
1881    },
1882    MSP_SERVO => MspServos: MspServos => |packet| packet.decode_as::<MspServos>(),
1883    MSP_MIXER => MspMixerConfig: MspMixerConfig => |packet| packet.decode_as::<MspMixerConfig>(),
1884    MSP_MODE_RANGES => MspModeRange: MspModeRange => |packet| packet.decode_as::<MspModeRange>(),
1885    MSP_SET_MODE_RANGE => MspSetModeRange: MspSetModeRange => |packet| {
1886        packet.decode_as::<MspSetModeRange>()
1887    },
1888    MSP_OSD_CONFIG => MspOsdConfig: MspOsdConfig => |packet| packet.decode_as::<MspOsdConfig>(),
1889    MSP_OSD_LAYOUT_CONFIG => MspSetOsdLayout: MspSetOsdLayout => |packet| {
1890        packet.decode_as::<MspSetOsdLayout>()
1891    },
1892    MSP2_INAV_OSD_SET_LAYOUT_ITEM => MspSetOsdLayoutItem: MspSetOsdLayoutItem => |packet| {
1893        packet.decode_as::<MspSetOsdLayoutItem>()
1894    },
1895    MSP2_INAV_OSD_LAYOUTS => MspOsdLayouts: MspOsdLayouts => |packet| {
1896        packet.decode_as::<MspOsdLayouts>()
1897    },
1898    MSP2_SET_SERIAL_CONFIG => MspSerialSetting: MspSerialSetting => |packet| {
1899        packet.decode_as::<MspSerialSetting>()
1900    },
1901    MSP2_COMMON_SETTING => MspSettingInfoRequest: MspSettingInfoRequest => |packet| {
1902        packet.decode_as::<MspSettingInfoRequest>()
1903    },
1904    MSP2_COMMON_SETTING_INFO => MspSettingInfo: MspSettingInfo => |packet| {
1905        packet.decode_as::<MspSettingInfo>()
1906    },
1907    MSP_RC => MspRc: MspRc => |packet| packet.decode_as::<MspRc>(),
1908);
1909
1910impl MspResponse {
1911    pub fn command_code(&self) -> MspCommandCode {
1912        // TODO: Not sure about all those mapping recheck them.
1913        response_command_code(self)
1914    }
1915
1916    pub fn to_bytes(&self) -> Result<MspPacketData, PackingError> {
1917        fn pack_into_packet_data<T: PackedStruct>(
1918            value: &T,
1919        ) -> Result<MspPacketData, PackingError> {
1920            let packed = value.pack()?;
1921            Ok(MspPacketData::from(packed.as_bytes_slice()))
1922        }
1923
1924        match self {
1925            MspResponse::MspApiVersion(data) => pack_into_packet_data(data),
1926            MspResponse::MspFlightControllerVariant(data) => pack_into_packet_data(data),
1927            MspResponse::MspStatus(data) => data.to_packet_data(),
1928            MspResponse::MspStatusEx(data) => data.to_packet_data(),
1929            MspResponse::MspBfConfig(data) => pack_into_packet_data(data),
1930            MspResponse::MspRawImu(data) => pack_into_packet_data(data),
1931            MspResponse::MspDataFlashSummaryReply(data) => pack_into_packet_data(data),
1932            MspResponse::MspDataFlashReply(data) => pack_into_packet_data(data),
1933            MspResponse::MspDataFlashRead(data) => pack_into_packet_data(data),
1934            MspResponse::MspAccTrim(data) => pack_into_packet_data(data),
1935            MspResponse::MspIdent(data) => pack_into_packet_data(data),
1936            MspResponse::MspMisc(data) => pack_into_packet_data(data),
1937            MspResponse::MspAttitude(data) => pack_into_packet_data(data),
1938            MspResponse::MspAltitude(data) => pack_into_packet_data(data),
1939            MspResponse::MspBatteryConfig(data) => pack_into_packet_data(data),
1940            MspResponse::MspVoltageMeterConfig(data) => pack_into_packet_data(data),
1941            MspResponse::MspAnalog(data) => pack_into_packet_data(data),
1942            MspResponse::MspRssiConfig(data) => pack_into_packet_data(data),
1943            MspResponse::MspVoltageMeter(data) => pack_into_packet_data(data),
1944            MspResponse::MspCurrentMeter(data) => pack_into_packet_data(data),
1945            MspResponse::MspBatteryState(data) => pack_into_packet_data(data),
1946            MspResponse::MspRcTuning(data) => pack_into_packet_data(data),
1947            MspResponse::MspRxConfig(data) => pack_into_packet_data(data),
1948            MspResponse::MspRcChannelValue(data) => pack_into_packet_data(data),
1949            MspResponse::MspRcMappedChannel(data) => pack_into_packet_data(data),
1950            MspResponse::MspFeatures(data) => pack_into_packet_data(data),
1951            MspResponse::MspMotor(data) => pack_into_packet_data(data),
1952            MspResponse::MspMotor3DConfig(data) => pack_into_packet_data(data),
1953            MspResponse::MspMotorConfig(data) => pack_into_packet_data(data),
1954            MspResponse::MspRcDeadband(data) => pack_into_packet_data(data),
1955            MspResponse::MspSensorAlignment(data) => pack_into_packet_data(data),
1956            MspResponse::MspAdvancedConfig(data) => pack_into_packet_data(data),
1957            MspResponse::MspFilterConfig(data) => pack_into_packet_data(data),
1958            MspResponse::MspPidAdvanced(data) => pack_into_packet_data(data),
1959            MspResponse::MspSensorConfig(data) => pack_into_packet_data(data),
1960            MspResponse::MspServos(data) => pack_into_packet_data(data),
1961            MspResponse::MspMixerConfig(data) => pack_into_packet_data(data),
1962            MspResponse::MspModeRange(data) => pack_into_packet_data(data),
1963            MspResponse::MspSetModeRange(data) => pack_into_packet_data(data),
1964            MspResponse::MspOsdConfig(data) => pack_into_packet_data(data),
1965            MspResponse::MspSetGetOsdConfig(data) => pack_into_packet_data(data),
1966            MspResponse::MspSetOsdLayout(data) => pack_into_packet_data(data),
1967            MspResponse::MspSetOsdLayoutItem(data) => pack_into_packet_data(data),
1968            MspResponse::MspOsdLayouts(data) => pack_into_packet_data(data),
1969            MspResponse::MspSerialSetting(data) => pack_into_packet_data(data),
1970            MspResponse::MspSettingInfoRequest(data) => pack_into_packet_data(data),
1971            MspResponse::MspSettingInfo(data) => pack_into_packet_data(data),
1972            MspResponse::MspRc(data) => pack_into_packet_data(data),
1973            MspResponse::Unknown => Err(PackingError::InvalidValue),
1974        }
1975    }
1976}
1977
1978impl From<MspResponse> for MspPacket {
1979    fn from(command: MspResponse) -> Self {
1980        MspPacket {
1981            cmd: command.command_code().to_primitive(),
1982            direction: FromFlightController,
1983            data: command.to_bytes().unwrap(), // should always be able to serialize a constructed MSPCommand
1984        }
1985    }
1986}
1987impl From<MspPacket> for MspResponse {
1988    fn from(packet: MspPacket) -> Self {
1989        let Some(cmd) = MspCommandCode::from_primitive(packet.cmd) else {
1990            return MspResponse::Unknown;
1991        };
1992        decode_response(cmd, &packet)
1993    }
1994}
1995
1996#[cfg(test)]
1997mod msp_status_tests {
1998    use super::*;
1999
2000    #[test]
2001    fn msp_status_serialization_roundtrip() {
2002        let status = MspStatus {
2003            cycle_time: 1234,
2004            i2c_errors: 5,
2005            sensors: MspStatusSensors {
2006                acc: true,
2007                baro: true,
2008                mag: false,
2009                gps: false,
2010                rangefinder: false,
2011                gyro: true,
2012                optical_flow: false,
2013            },
2014            flight_mode_flags: 0x11223344,
2015            current_pid_profile_index: 2,
2016            average_system_load_percent: 100,
2017            gyro_cycle_time: 250,
2018            extra_flight_mode_flags: vec![0xAA, 0xBB],
2019            arming_disable_flags_count: 29,
2020            arming_disable_flags: 0xDEADBEEF,
2021            config_state_flags: 1,
2022            core_temp_celsius: 42,
2023            control_rate_profile_count: 3,
2024        };
2025
2026        let data = status.to_packet_data().expect("serialize MSP_STATUS");
2027        let expected = vec![
2028            0xD2, 0x04, // cycle_time
2029            0x05, 0x00, // i2c_errors
2030            0x23, 0x00, // sensors
2031            0x44, 0x33, 0x22, 0x11, // flight_mode_flags
2032            0x02, // current_pid_profile_index
2033            0x64, 0x00, // average_system_load_percent
2034            0xFA, 0x00, // gyro_cycle_time
2035            0x02, // extra_flight_mode_flags_len
2036            0xAA, 0xBB, // extra_flight_mode_flags
2037            0x1D, // arming_disable_flags_count
2038            0xEF, 0xBE, 0xAD, 0xDE, // arming_disable_flags
2039            0x01, // config_state_flags
2040            0x2A, 0x00, // core_temp_celsius
2041            0x03, // control_rate_profile_count
2042        ];
2043
2044        assert_eq!(data.as_slice(), expected.as_slice());
2045
2046        let decoded = MspStatus::from_bytes(data.as_slice()).expect("decode MSP_STATUS");
2047        assert_eq!(decoded, status);
2048    }
2049
2050    #[test]
2051    fn msp_status_ex_serialization_roundtrip() {
2052        let status = MspStatusEx {
2053            cycle_time: 321,
2054            i2c_errors: 1,
2055            sensors: MspStatusSensors {
2056                acc: true,
2057                baro: false,
2058                mag: true,
2059                gps: false,
2060                rangefinder: false,
2061                gyro: true,
2062                optical_flow: true,
2063            },
2064            flight_mode_flags: 0xAABBCCDD,
2065            current_pid_profile_index: 1,
2066            average_system_load_percent: 250,
2067            max_profile_count: 3,
2068            current_control_rate_profile_index: 2,
2069            extra_flight_mode_flags: vec![],
2070            arming_disable_flags_count: 29,
2071            arming_disable_flags: 0,
2072            config_state_flags: 0,
2073            core_temp_celsius: 0,
2074            control_rate_profile_count: 3,
2075        };
2076
2077        let data = status.to_packet_data().expect("serialize MSP_STATUS_EX");
2078        let decoded = MspStatusEx::from_bytes(data.as_slice()).expect("decode MSP_STATUS_EX");
2079        assert_eq!(decoded, status);
2080    }
2081}
2082
2083#[cfg(test)]
2084mod tests {
2085    use super::*;
2086    #[test]
2087    fn test_mixer() {
2088        use packed_struct::prelude::*;
2089
2090        let m = MspMixerConfig {
2091            mixer_mode: MixerMode::QuadX,
2092        };
2093        assert_eq!(3, m.mixer_mode.to_primitive());
2094        let r = m.pack().unwrap();
2095        assert_eq!(3, r.as_slice()[0]);
2096    }
2097
2098    #[test]
2099    #[cfg(feature = "bincode")]
2100    fn test_command_enum_with_bincode() {
2101        let command = MspResponse::MspApiVersion(MspApiVersion {
2102            protocol_version: 1,
2103            api_version_major: 2,
2104            api_version_minor: 3,
2105        });
2106
2107        let encoded = bincode::encode_to_vec(&command, bincode::config::standard()).unwrap();
2108        let decoded: MspResponse =
2109            bincode::decode_from_slice(&encoded, bincode::config::standard())
2110                .unwrap()
2111                .0;
2112
2113        match (command, decoded) {
2114            (MspResponse::MspApiVersion(c1), MspResponse::MspApiVersion(c2)) => {
2115                assert_eq!(c1.protocol_version, c2.protocol_version);
2116                assert_eq!(c1.api_version_major, c2.api_version_major);
2117                assert_eq!(c1.api_version_minor, c2.api_version_minor);
2118            }
2119            _ => panic!("Decoded command does not match the original command"),
2120        }
2121    }
2122}