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