1use super::{Message, MessageDescriptor};
9
10pub const DESCRIPTORS: &[&MessageDescriptor<'static>] = &[
15 <Heartbeat as Message>::DESCRIPTOR,
16 <SysStatus as Message>::DESCRIPTOR,
17 <SystemTime as Message>::DESCRIPTOR,
18 <Ping as Message>::DESCRIPTOR,
19 <SetMode as Message>::DESCRIPTOR,
20 <ParamRequestRead as Message>::DESCRIPTOR,
21 <ParamRequestList as Message>::DESCRIPTOR,
22 <ParamValue as Message>::DESCRIPTOR,
23 <ParamSet as Message>::DESCRIPTOR,
24 <GpsRawInt as Message>::DESCRIPTOR,
25 <Attitude as Message>::DESCRIPTOR,
26 <AttitudeQuaternion as Message>::DESCRIPTOR,
27 <LocalPositionNed as Message>::DESCRIPTOR,
28 <GlobalPositionInt as Message>::DESCRIPTOR,
29 <ServoOutputRaw as Message>::DESCRIPTOR,
30 <MissionRequest as Message>::DESCRIPTOR,
31 <MissionCurrent as Message>::DESCRIPTOR,
32 <MissionRequestList as Message>::DESCRIPTOR,
33 <MissionCount as Message>::DESCRIPTOR,
34 <MissionClearAll as Message>::DESCRIPTOR,
35 <MissionAck as Message>::DESCRIPTOR,
36 <MissionRequestInt as Message>::DESCRIPTOR,
37 <RcChannels as Message>::DESCRIPTOR,
38 <ManualControl as Message>::DESCRIPTOR,
39 <MissionItemInt as Message>::DESCRIPTOR,
40 <VfrHud as Message>::DESCRIPTOR,
41 <CommandInt as Message>::DESCRIPTOR,
42 <CommandLong as Message>::DESCRIPTOR,
43 <CommandAck as Message>::DESCRIPTOR,
44 <SetPositionTargetLocalNed as Message>::DESCRIPTOR,
45 <SetPositionTargetGlobalInt as Message>::DESCRIPTOR,
46 <BatteryStatus as Message>::DESCRIPTOR,
47 <AutopilotVersion as Message>::DESCRIPTOR,
48 <HomePosition as Message>::DESCRIPTOR,
49 <ExtendedSysState as Message>::DESCRIPTOR,
50 <Statustext as Message>::DESCRIPTOR,
51];
52
53message! {
54 Heartbeat = 0, crc = 50, name = "HEARTBEAT";
57 custom_mode: u32,
58 type_: u8,
59 autopilot: u8,
60 base_mode: u8,
61 system_status: u8,
62 mavlink_version: u8,
63}
64
65message! {
66 SysStatus = 1, crc = 124, name = "SYS_STATUS";
68 onboard_control_sensors_present: u32,
69 onboard_control_sensors_enabled: u32,
70 onboard_control_sensors_health: u32,
71 load: u16,
72 voltage_battery: u16,
73 current_battery: i16,
74 drop_rate_comm: u16,
75 errors_comm: u16,
76 errors_count1: u16,
77 errors_count2: u16,
78 errors_count3: u16,
79 errors_count4: u16,
80 battery_remaining: i8;
81 ext {
82 onboard_control_sensors_present_extended: u32,
83 onboard_control_sensors_enabled_extended: u32,
84 onboard_control_sensors_health_extended: u32,
85 }
86}
87
88message! {
89 SystemTime = 2, crc = 137, name = "SYSTEM_TIME";
91 time_unix_usec: u64,
92 time_boot_ms: u32,
93}
94
95message! {
96 Ping = 4, crc = 237, name = "PING";
98 time_usec: u64,
99 seq: u32,
100 target_system: u8,
101 target_component: u8,
102}
103
104message! {
105 Attitude = 30, crc = 39, name = "ATTITUDE";
107 time_boot_ms: u32,
108 roll: f32,
109 pitch: f32,
110 yaw: f32,
111 rollspeed: f32,
112 pitchspeed: f32,
113 yawspeed: f32,
114}
115
116message! {
117 GlobalPositionInt = 33, crc = 104, name = "GLOBAL_POSITION_INT";
119 time_boot_ms: u32,
120 lat: i32,
121 lon: i32,
122 alt: i32,
123 relative_alt: i32,
124 vx: i16,
125 vy: i16,
126 vz: i16,
127 hdg: u16,
128}
129
130message! {
131 CommandLong = 76, crc = 152, name = "COMMAND_LONG";
133 param1: f32,
134 param2: f32,
135 param3: f32,
136 param4: f32,
137 param5: f32,
138 param6: f32,
139 param7: f32,
140 command: u16,
141 target_system: u8,
142 target_component: u8,
143 confirmation: u8,
144}
145
146message! {
147 CommandAck = 77, crc = 143, name = "COMMAND_ACK";
154 command: u16,
155 result: u8;
156 ext {
157 progress: u8,
158 result_param2: i32,
159 target_system: u8,
160 target_component: u8,
161 }
162}
163
164message! {
165 CommandInt = 75, crc = 158, name = "COMMAND_INT";
167 param1: f32,
168 param2: f32,
169 param3: f32,
170 param4: f32,
171 x: i32,
172 y: i32,
173 z: f32,
174 command: u16,
175 target_system: u8,
176 target_component: u8,
177 frame: u8,
178 current: u8,
179 autocontinue: u8,
180}
181
182message! {
183 SetMode = 11, crc = 89, name = "SET_MODE";
185 custom_mode: u32,
186 target_system: u8,
187 base_mode: u8,
188}
189
190message! {
191 ManualControl = 69, crc = 243, name = "MANUAL_CONTROL";
193 x: i16,
194 y: i16,
195 z: i16,
196 r: i16,
197 buttons: u16,
198 target: u8;
199 ext {
200 buttons2: u16,
201 enabled_extensions: u8,
202 s: i16,
203 t: i16,
204 aux1: i16,
205 aux2: i16,
206 aux3: i16,
207 aux4: i16,
208 aux5: i16,
209 aux6: i16,
210 }
211}
212
213message! {
214 ParamRequestRead = 20, crc = 214, name = "PARAM_REQUEST_READ";
216 param_index: i16,
217 target_system: u8,
218 target_component: u8,
219 param_id: [char; 16],
220}
221
222message! {
223 ParamRequestList = 21, crc = 159, name = "PARAM_REQUEST_LIST";
225 target_system: u8,
226 target_component: u8,
227}
228
229message! {
230 ParamValue = 22, crc = 220, name = "PARAM_VALUE";
232 param_value: f32,
233 param_count: u16,
234 param_index: u16,
235 param_id: [char; 16],
236 param_type: u8,
237}
238
239message! {
240 ParamSet = 23, crc = 168, name = "PARAM_SET";
242 param_value: f32,
243 target_system: u8,
244 target_component: u8,
245 param_id: [char; 16],
246 param_type: u8,
247}
248
249message! {
250 GpsRawInt = 24, crc = 24, name = "GPS_RAW_INT";
252 time_usec: u64,
253 lat: i32,
254 lon: i32,
255 alt: i32,
256 eph: u16,
257 epv: u16,
258 vel: u16,
259 cog: u16,
260 fix_type: u8,
261 satellites_visible: u8;
262 ext { alt_ellipsoid: i32, h_acc: u32, v_acc: u32, vel_acc: u32, hdg_acc: u32, yaw: u16 }
263}
264
265message! {
266 AttitudeQuaternion = 31, crc = 246, name = "ATTITUDE_QUATERNION";
268 time_boot_ms: u32,
269 q1: f32,
270 q2: f32,
271 q3: f32,
272 q4: f32,
273 rollspeed: f32,
274 pitchspeed: f32,
275 yawspeed: f32;
276 ext { repr_offset_q: [f32; 4] }
277}
278
279message! {
280 LocalPositionNed = 32, crc = 185, name = "LOCAL_POSITION_NED";
282 time_boot_ms: u32,
283 x: f32,
284 y: f32,
285 z: f32,
286 vx: f32,
287 vy: f32,
288 vz: f32,
289}
290
291message! {
292 ServoOutputRaw = 36, crc = 222, name = "SERVO_OUTPUT_RAW";
294 time_usec: u32,
295 servo1_raw: u16,
296 servo2_raw: u16,
297 servo3_raw: u16,
298 servo4_raw: u16,
299 servo5_raw: u16,
300 servo6_raw: u16,
301 servo7_raw: u16,
302 servo8_raw: u16,
303 port: u8;
304 ext {
305 servo9_raw: u16,
306 servo10_raw: u16,
307 servo11_raw: u16,
308 servo12_raw: u16,
309 servo13_raw: u16,
310 servo14_raw: u16,
311 servo15_raw: u16,
312 servo16_raw: u16,
313 }
314}
315
316message! {
317 RcChannels = 65, crc = 118, name = "RC_CHANNELS";
319 time_boot_ms: u32,
320 chan1_raw: u16,
321 chan2_raw: u16,
322 chan3_raw: u16,
323 chan4_raw: u16,
324 chan5_raw: u16,
325 chan6_raw: u16,
326 chan7_raw: u16,
327 chan8_raw: u16,
328 chan9_raw: u16,
329 chan10_raw: u16,
330 chan11_raw: u16,
331 chan12_raw: u16,
332 chan13_raw: u16,
333 chan14_raw: u16,
334 chan15_raw: u16,
335 chan16_raw: u16,
336 chan17_raw: u16,
337 chan18_raw: u16,
338 chancount: u8,
339 rssi: u8,
340}
341
342message! {
343 VfrHud = 74, crc = 20, name = "VFR_HUD";
345 airspeed: f32,
346 groundspeed: f32,
347 alt: f32,
348 climb: f32,
349 heading: i16,
350 throttle: u16,
351}
352
353message! {
354 BatteryStatus = 147, crc = 154, name = "BATTERY_STATUS";
356 current_consumed: i32,
357 energy_consumed: i32,
358 temperature: i16,
359 voltages: [u16; 10],
360 current_battery: i16,
361 id: u8,
362 battery_function: u8,
363 type_: u8,
364 battery_remaining: i8;
365 ext {
366 time_remaining: i32,
367 charge_state: u8,
368 voltages_ext: [u16; 4],
369 mode: u8,
370 fault_bitmask: u32,
371 }
372}
373
374message! {
375 MissionRequestList = 43, crc = 132, name = "MISSION_REQUEST_LIST";
378 target_system: u8,
379 target_component: u8;
380 ext { mission_type: u8 }
381}
382
383message! {
384 MissionCount = 44, crc = 221, name = "MISSION_COUNT";
387 count: u16,
388 target_system: u8,
389 target_component: u8;
390 ext { mission_type: u8, opaque_id: u32 }
391}
392
393message! {
394 MissionRequestInt = 51, crc = 196, name = "MISSION_REQUEST_INT";
397 seq: u16,
398 target_system: u8,
399 target_component: u8;
400 ext { mission_type: u8 }
401}
402
403message! {
404 MissionRequest = 40, crc = 230, name = "MISSION_REQUEST";
407 seq: u16,
408 target_system: u8,
409 target_component: u8;
410 ext { mission_type: u8 }
411}
412
413message! {
414 MissionItemInt = 73, crc = 38, name = "MISSION_ITEM_INT";
416 param1: f32,
417 param2: f32,
418 param3: f32,
419 param4: f32,
420 x: i32,
421 y: i32,
422 z: f32,
423 seq: u16,
424 command: u16,
425 target_system: u8,
426 target_component: u8,
427 frame: u8,
428 current: u8,
429 autocontinue: u8;
430 ext { mission_type: u8 }
431}
432
433message! {
434 MissionCurrent = 42, crc = 28, name = "MISSION_CURRENT";
436 seq: u16;
437 ext {
438 total: u16,
439 mission_state: u8,
440 mission_mode: u8,
441 mission_id: u32,
442 fence_id: u32,
443 rally_points_id: u32,
444 }
445}
446
447message! {
448 MissionClearAll = 45, crc = 232, name = "MISSION_CLEAR_ALL";
450 target_system: u8,
451 target_component: u8;
452 ext { mission_type: u8 }
453}
454
455message! {
456 MissionAck = 47, crc = 153, name = "MISSION_ACK";
458 target_system: u8,
459 target_component: u8,
460 type_: u8;
461 ext { mission_type: u8, opaque_id: u32 }
462}
463
464message! {
465 SetPositionTargetLocalNed = 84, crc = 143, name = "SET_POSITION_TARGET_LOCAL_NED";
468 time_boot_ms: u32,
469 x: f32,
470 y: f32,
471 z: f32,
472 vx: f32,
473 vy: f32,
474 vz: f32,
475 afx: f32,
476 afy: f32,
477 afz: f32,
478 yaw: f32,
479 yaw_rate: f32,
480 type_mask: u16,
481 target_system: u8,
482 target_component: u8,
483 coordinate_frame: u8,
484}
485
486message! {
487 SetPositionTargetGlobalInt = 86, crc = 5, name = "SET_POSITION_TARGET_GLOBAL_INT";
490 time_boot_ms: u32,
491 lat_int: i32,
492 lon_int: i32,
493 alt: f32,
494 vx: f32,
495 vy: f32,
496 vz: f32,
497 afx: f32,
498 afy: f32,
499 afz: f32,
500 yaw: f32,
501 yaw_rate: f32,
502 type_mask: u16,
503 target_system: u8,
504 target_component: u8,
505 coordinate_frame: u8,
506}
507
508message! {
509 HomePosition = 242, crc = 104, name = "HOME_POSITION";
511 latitude: i32,
512 longitude: i32,
513 altitude: i32,
514 x: f32,
515 y: f32,
516 z: f32,
517 q: [f32; 4],
518 approach_x: f32,
519 approach_y: f32,
520 approach_z: f32;
521 ext { time_usec: u64 }
522}
523
524message! {
525 AutopilotVersion = 148, crc = 178, name = "AUTOPILOT_VERSION";
527 capabilities: u64,
528 uid: u64,
529 flight_sw_version: u32,
530 middleware_sw_version: u32,
531 os_sw_version: u32,
532 board_version: u32,
533 vendor_id: u16,
534 product_id: u16,
535 flight_custom_version: [u8; 8],
536 middleware_custom_version: [u8; 8],
537 os_custom_version: [u8; 8];
538 ext { uid2: [u8; 18] }
539}
540
541message! {
542 ExtendedSysState = 245, crc = 130, name = "EXTENDED_SYS_STATE";
544 vtol_state: u8,
545 landed_state: u8,
546}
547
548message! {
549 Statustext = 253, crc = 83, name = "STATUSTEXT";
551 severity: u8,
552 text: [char; 50];
553 ext { id: u16, chunk_seq: u8 }
554}
555
556#[cfg(test)]
557mod tests {
558 use super::*;
559 use crate::dialect::{crc_extra, Message};
560 use crate::message_crc_extra;
561
562 fn verify<M: Message>() {
566 assert_eq!(
567 message_crc_extra(M::NAME, M::BASE_FIELDS),
568 M::CRC_EXTRA,
569 "derived CRC_EXTRA disagrees with the dialect for {}",
570 M::NAME
571 );
572 assert_eq!(
573 crc_extra(M::ID),
574 Some(M::CRC_EXTRA),
575 "registry disagrees for {}",
576 M::NAME
577 );
578 }
579
580 #[test]
581 fn every_message_crc_extra_matches_the_dialect() {
582 verify::<Heartbeat>();
583 verify::<SysStatus>();
584 verify::<SystemTime>();
585 verify::<Ping>();
586 verify::<Attitude>();
587 verify::<GlobalPositionInt>();
588 verify::<CommandLong>();
589 verify::<CommandAck>();
590 verify::<CommandInt>();
591 verify::<SetMode>();
592 verify::<ManualControl>();
593 verify::<ParamRequestRead>();
594 verify::<ParamRequestList>();
595 verify::<ParamValue>();
596 verify::<ParamSet>();
597 verify::<GpsRawInt>();
598 verify::<AttitudeQuaternion>();
599 verify::<LocalPositionNed>();
600 verify::<ServoOutputRaw>();
601 verify::<RcChannels>();
602 verify::<VfrHud>();
603 verify::<BatteryStatus>();
604 verify::<MissionRequestList>();
605 verify::<MissionCount>();
606 verify::<MissionRequestInt>();
607 verify::<MissionRequest>();
608 verify::<MissionItemInt>();
609 verify::<MissionCurrent>();
610 verify::<MissionClearAll>();
611 verify::<MissionAck>();
612 verify::<SetPositionTargetLocalNed>();
613 verify::<SetPositionTargetGlobalInt>();
614 verify::<HomePosition>();
615 verify::<AutopilotVersion>();
616 verify::<ExtendedSysState>();
617 verify::<Statustext>();
618 }
619
620 #[test]
621 fn a_heartbeat_encodes_to_the_documented_frame() {
622 let heartbeat = Heartbeat {
627 custom_mode: 0,
628 type_: 2,
629 autopilot: 3,
630 base_mode: 0x51,
631 system_status: 4,
632 mavlink_version: 3,
633 };
634 let mut payload = [0u8; 255];
635 let len = heartbeat.encode(&mut payload);
636 let frame = crate::Frame::encode_v1(
637 crate::Header::new(1, 1, 0x4E),
638 Heartbeat::ID,
639 &payload[..len],
640 Heartbeat::CRC_EXTRA,
641 )
642 .unwrap();
643 let expected = [
644 0xFE, 0x09, 0x4E, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x51, 0x04,
645 0x03, 0x1C, 0x7F,
646 ];
647 assert_eq!(frame.as_bytes(), &expected);
648 }
649
650 #[test]
651 fn a_heartbeat_round_trips_through_its_payload() {
652 let heartbeat = Heartbeat {
653 custom_mode: 0x0A0B0C0D,
654 type_: 2,
655 autopilot: 12,
656 base_mode: 0x81,
657 system_status: 4,
658 mavlink_version: 3,
659 };
660 let mut buf = [0u8; 255];
661 let len = heartbeat.encode(&mut buf);
662 assert_eq!(len, Heartbeat::WIRE_LEN);
663 assert_eq!(Heartbeat::decode(&buf[..len]).unwrap(), heartbeat);
664 }
665
666 #[test]
667 fn a_command_long_round_trips_through_field_reordering() {
668 let command = CommandLong {
671 param1: 1.0,
672 param2: 0.0,
673 param3: 0.0,
674 param4: 0.0,
675 param5: 12.34,
676 param6: 56.78,
677 param7: 100.0,
678 command: 400, target_system: 1,
680 target_component: 1,
681 confirmation: 0,
682 };
683 let mut buf = [0u8; 255];
684 let len = command.encode(&mut buf);
685 assert_eq!(len, CommandLong::WIRE_LEN);
686 assert_eq!(CommandLong::decode(&buf[..len]).unwrap(), command);
687 }
688
689 #[test]
690 fn an_extension_field_round_trips_after_the_base_fields() {
691 let count = MissionCount {
694 count: 7,
695 target_system: 1,
696 target_component: 1,
697 mission_type: crate::dialect::mav_mission_type::FENCE,
698 opaque_id: 0xDEAD_BEEF,
699 };
700 let mut buf = [0u8; 255];
701 let len = count.encode(&mut buf);
702 assert_eq!(len, MissionCount::WIRE_LEN);
703 assert_eq!(len, 4 + 1 + 4);
705 assert_eq!(MissionCount::decode(&buf[..len]).unwrap(), count);
706 }
707
708 #[test]
709 fn a_base_only_payload_decodes_extensions_as_zero() {
710 let base_only = [7u8, 0, 1, 1]; let decoded = MissionCount::decode(&base_only).unwrap();
715 assert_eq!(decoded.count, 7);
716 assert_eq!(decoded.mission_type, 0);
717 assert_eq!(decoded.opaque_id, 0);
718 }
719
720 #[test]
721 fn command_ack_keeps_its_seed_after_gaining_extensions() {
722 assert_eq!(
725 message_crc_extra("COMMAND_ACK", CommandAck::BASE_FIELDS),
726 CommandAck::CRC_EXTRA
727 );
728 assert_eq!(CommandAck::CRC_EXTRA, 143);
729 assert_eq!(CommandAck::BASE_FIELDS.len(), 2);
731 }
732
733 #[test]
734 fn decode_zero_extends_a_truncated_payload() {
735 let decoded = Heartbeat::decode(&[0]).unwrap();
738 assert_eq!(decoded, Heartbeat::default_zeroed());
739 }
740
741 impl Heartbeat {
742 fn default_zeroed() -> Self {
743 Heartbeat {
744 custom_mode: 0,
745 type_: 0,
746 autopilot: 0,
747 base_mode: 0,
748 system_status: 0,
749 mavlink_version: 0,
750 }
751 }
752 }
753}