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}
82
83message! {
84 SystemTime = 2, crc = 137, name = "SYSTEM_TIME";
86 time_unix_usec: u64,
87 time_boot_ms: u32,
88}
89
90message! {
91 Ping = 4, crc = 237, name = "PING";
93 time_usec: u64,
94 seq: u32,
95 target_system: u8,
96 target_component: u8,
97}
98
99message! {
100 Attitude = 30, crc = 39, name = "ATTITUDE";
102 time_boot_ms: u32,
103 roll: f32,
104 pitch: f32,
105 yaw: f32,
106 rollspeed: f32,
107 pitchspeed: f32,
108 yawspeed: f32,
109}
110
111message! {
112 GlobalPositionInt = 33, crc = 104, name = "GLOBAL_POSITION_INT";
114 time_boot_ms: u32,
115 lat: i32,
116 lon: i32,
117 alt: i32,
118 relative_alt: i32,
119 vx: i16,
120 vy: i16,
121 vz: i16,
122 hdg: u16,
123}
124
125message! {
126 CommandLong = 76, crc = 152, name = "COMMAND_LONG";
128 param1: f32,
129 param2: f32,
130 param3: f32,
131 param4: f32,
132 param5: f32,
133 param6: f32,
134 param7: f32,
135 command: u16,
136 target_system: u8,
137 target_component: u8,
138 confirmation: u8,
139}
140
141message! {
142 CommandAck = 77, crc = 143, name = "COMMAND_ACK";
149 command: u16,
150 result: u8;
151 ext {
152 progress: u8,
153 result_param2: i32,
154 target_system: u8,
155 target_component: u8,
156 }
157}
158
159message! {
160 CommandInt = 75, crc = 158, name = "COMMAND_INT";
162 param1: f32,
163 param2: f32,
164 param3: f32,
165 param4: f32,
166 x: i32,
167 y: i32,
168 z: f32,
169 command: u16,
170 target_system: u8,
171 target_component: u8,
172 frame: u8,
173 current: u8,
174 autocontinue: u8,
175}
176
177message! {
178 SetMode = 11, crc = 89, name = "SET_MODE";
180 custom_mode: u32,
181 target_system: u8,
182 base_mode: u8,
183}
184
185message! {
186 ManualControl = 69, crc = 243, name = "MANUAL_CONTROL";
188 x: i16,
189 y: i16,
190 z: i16,
191 r: i16,
192 buttons: u16,
193 target: u8,
194}
195
196message! {
197 ParamRequestRead = 20, crc = 214, name = "PARAM_REQUEST_READ";
199 param_index: i16,
200 target_system: u8,
201 target_component: u8,
202 param_id: [char; 16],
203}
204
205message! {
206 ParamRequestList = 21, crc = 159, name = "PARAM_REQUEST_LIST";
208 target_system: u8,
209 target_component: u8,
210}
211
212message! {
213 ParamValue = 22, crc = 220, name = "PARAM_VALUE";
215 param_value: f32,
216 param_count: u16,
217 param_index: u16,
218 param_id: [char; 16],
219 param_type: u8,
220}
221
222message! {
223 ParamSet = 23, crc = 168, name = "PARAM_SET";
225 param_value: f32,
226 target_system: u8,
227 target_component: u8,
228 param_id: [char; 16],
229 param_type: u8,
230}
231
232message! {
233 GpsRawInt = 24, crc = 24, name = "GPS_RAW_INT";
235 time_usec: u64,
236 lat: i32,
237 lon: i32,
238 alt: i32,
239 eph: u16,
240 epv: u16,
241 vel: u16,
242 cog: u16,
243 fix_type: u8,
244 satellites_visible: u8,
245}
246
247message! {
248 AttitudeQuaternion = 31, crc = 246, name = "ATTITUDE_QUATERNION";
250 time_boot_ms: u32,
251 q1: f32,
252 q2: f32,
253 q3: f32,
254 q4: f32,
255 rollspeed: f32,
256 pitchspeed: f32,
257 yawspeed: f32,
258}
259
260message! {
261 LocalPositionNed = 32, crc = 185, name = "LOCAL_POSITION_NED";
263 time_boot_ms: u32,
264 x: f32,
265 y: f32,
266 z: f32,
267 vx: f32,
268 vy: f32,
269 vz: f32,
270}
271
272message! {
273 ServoOutputRaw = 36, crc = 222, name = "SERVO_OUTPUT_RAW";
275 time_usec: u32,
276 servo1_raw: u16,
277 servo2_raw: u16,
278 servo3_raw: u16,
279 servo4_raw: u16,
280 servo5_raw: u16,
281 servo6_raw: u16,
282 servo7_raw: u16,
283 servo8_raw: u16,
284 port: u8,
285}
286
287message! {
288 RcChannels = 65, crc = 118, name = "RC_CHANNELS";
290 time_boot_ms: u32,
291 chan1_raw: u16,
292 chan2_raw: u16,
293 chan3_raw: u16,
294 chan4_raw: u16,
295 chan5_raw: u16,
296 chan6_raw: u16,
297 chan7_raw: u16,
298 chan8_raw: u16,
299 chan9_raw: u16,
300 chan10_raw: u16,
301 chan11_raw: u16,
302 chan12_raw: u16,
303 chan13_raw: u16,
304 chan14_raw: u16,
305 chan15_raw: u16,
306 chan16_raw: u16,
307 chan17_raw: u16,
308 chan18_raw: u16,
309 chancount: u8,
310 rssi: u8,
311}
312
313message! {
314 VfrHud = 74, crc = 20, name = "VFR_HUD";
316 airspeed: f32,
317 groundspeed: f32,
318 alt: f32,
319 climb: f32,
320 heading: i16,
321 throttle: u16,
322}
323
324message! {
325 BatteryStatus = 147, crc = 154, name = "BATTERY_STATUS";
327 current_consumed: i32,
328 energy_consumed: i32,
329 temperature: i16,
330 voltages: [u16; 10],
331 current_battery: i16,
332 id: u8,
333 battery_function: u8,
334 type_: u8,
335 battery_remaining: i8,
336}
337
338message! {
339 MissionRequestList = 43, crc = 132, name = "MISSION_REQUEST_LIST";
342 target_system: u8,
343 target_component: u8;
344 ext { mission_type: u8 }
345}
346
347message! {
348 MissionCount = 44, crc = 221, name = "MISSION_COUNT";
351 count: u16,
352 target_system: u8,
353 target_component: u8;
354 ext { mission_type: u8, opaque_id: u32 }
355}
356
357message! {
358 MissionRequestInt = 51, crc = 196, name = "MISSION_REQUEST_INT";
361 seq: u16,
362 target_system: u8,
363 target_component: u8;
364 ext { mission_type: u8 }
365}
366
367message! {
368 MissionRequest = 40, crc = 230, name = "MISSION_REQUEST";
371 seq: u16,
372 target_system: u8,
373 target_component: u8;
374 ext { mission_type: u8 }
375}
376
377message! {
378 MissionItemInt = 73, crc = 38, name = "MISSION_ITEM_INT";
380 param1: f32,
381 param2: f32,
382 param3: f32,
383 param4: f32,
384 x: i32,
385 y: i32,
386 z: f32,
387 seq: u16,
388 command: u16,
389 target_system: u8,
390 target_component: u8,
391 frame: u8,
392 current: u8,
393 autocontinue: u8;
394 ext { mission_type: u8 }
395}
396
397message! {
398 MissionCurrent = 42, crc = 28, name = "MISSION_CURRENT";
400 seq: u16,
401}
402
403message! {
404 MissionClearAll = 45, crc = 232, name = "MISSION_CLEAR_ALL";
406 target_system: u8,
407 target_component: u8;
408 ext { mission_type: u8 }
409}
410
411message! {
412 MissionAck = 47, crc = 153, name = "MISSION_ACK";
414 target_system: u8,
415 target_component: u8,
416 type_: u8;
417 ext { mission_type: u8, opaque_id: u32 }
418}
419
420message! {
421 SetPositionTargetLocalNed = 84, crc = 143, name = "SET_POSITION_TARGET_LOCAL_NED";
424 time_boot_ms: u32,
425 x: f32,
426 y: f32,
427 z: f32,
428 vx: f32,
429 vy: f32,
430 vz: f32,
431 afx: f32,
432 afy: f32,
433 afz: f32,
434 yaw: f32,
435 yaw_rate: f32,
436 type_mask: u16,
437 target_system: u8,
438 target_component: u8,
439 coordinate_frame: u8,
440}
441
442message! {
443 SetPositionTargetGlobalInt = 86, crc = 5, name = "SET_POSITION_TARGET_GLOBAL_INT";
446 time_boot_ms: u32,
447 lat_int: i32,
448 lon_int: i32,
449 alt: f32,
450 vx: f32,
451 vy: f32,
452 vz: f32,
453 afx: f32,
454 afy: f32,
455 afz: f32,
456 yaw: f32,
457 yaw_rate: f32,
458 type_mask: u16,
459 target_system: u8,
460 target_component: u8,
461 coordinate_frame: u8,
462}
463
464message! {
465 HomePosition = 242, crc = 104, name = "HOME_POSITION";
467 latitude: i32,
468 longitude: i32,
469 altitude: i32,
470 x: f32,
471 y: f32,
472 z: f32,
473 q: [f32; 4],
474 approach_x: f32,
475 approach_y: f32,
476 approach_z: f32,
477}
478
479message! {
480 AutopilotVersion = 148, crc = 178, name = "AUTOPILOT_VERSION";
482 capabilities: u64,
483 uid: u64,
484 flight_sw_version: u32,
485 middleware_sw_version: u32,
486 os_sw_version: u32,
487 board_version: u32,
488 vendor_id: u16,
489 product_id: u16,
490 flight_custom_version: [u8; 8],
491 middleware_custom_version: [u8; 8],
492 os_custom_version: [u8; 8],
493}
494
495message! {
496 ExtendedSysState = 245, crc = 130, name = "EXTENDED_SYS_STATE";
498 vtol_state: u8,
499 landed_state: u8,
500}
501
502message! {
503 Statustext = 253, crc = 83, name = "STATUSTEXT";
505 severity: u8,
506 text: [char; 50],
507}
508
509#[cfg(test)]
510mod tests {
511 use super::*;
512 use crate::dialect::{crc_extra, Message};
513 use crate::message_crc_extra;
514
515 fn verify<M: Message>() {
519 assert_eq!(
520 message_crc_extra(M::NAME, M::BASE_FIELDS),
521 M::CRC_EXTRA,
522 "derived CRC_EXTRA disagrees with the dialect for {}",
523 M::NAME
524 );
525 assert_eq!(
526 crc_extra(M::ID),
527 Some(M::CRC_EXTRA),
528 "registry disagrees for {}",
529 M::NAME
530 );
531 }
532
533 #[test]
534 fn every_message_crc_extra_matches_the_dialect() {
535 verify::<Heartbeat>();
536 verify::<SysStatus>();
537 verify::<SystemTime>();
538 verify::<Ping>();
539 verify::<Attitude>();
540 verify::<GlobalPositionInt>();
541 verify::<CommandLong>();
542 verify::<CommandAck>();
543 verify::<CommandInt>();
544 verify::<SetMode>();
545 verify::<ManualControl>();
546 verify::<ParamRequestRead>();
547 verify::<ParamRequestList>();
548 verify::<ParamValue>();
549 verify::<ParamSet>();
550 verify::<GpsRawInt>();
551 verify::<AttitudeQuaternion>();
552 verify::<LocalPositionNed>();
553 verify::<ServoOutputRaw>();
554 verify::<RcChannels>();
555 verify::<VfrHud>();
556 verify::<BatteryStatus>();
557 verify::<MissionRequestList>();
558 verify::<MissionCount>();
559 verify::<MissionRequestInt>();
560 verify::<MissionRequest>();
561 verify::<MissionItemInt>();
562 verify::<MissionCurrent>();
563 verify::<MissionClearAll>();
564 verify::<MissionAck>();
565 verify::<SetPositionTargetLocalNed>();
566 verify::<SetPositionTargetGlobalInt>();
567 verify::<HomePosition>();
568 verify::<AutopilotVersion>();
569 verify::<ExtendedSysState>();
570 verify::<Statustext>();
571 }
572
573 #[test]
574 fn a_heartbeat_encodes_to_the_documented_frame() {
575 let heartbeat = Heartbeat {
580 custom_mode: 0,
581 type_: 2,
582 autopilot: 3,
583 base_mode: 0x51,
584 system_status: 4,
585 mavlink_version: 3,
586 };
587 let mut payload = [0u8; 255];
588 let len = heartbeat.encode(&mut payload);
589 let frame = crate::Frame::encode_v1(
590 crate::Header::new(1, 1, 0x4E),
591 Heartbeat::ID,
592 &payload[..len],
593 Heartbeat::CRC_EXTRA,
594 )
595 .unwrap();
596 let expected = [
597 0xFE, 0x09, 0x4E, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x51, 0x04,
598 0x03, 0x1C, 0x7F,
599 ];
600 assert_eq!(frame.as_bytes(), &expected);
601 }
602
603 #[test]
604 fn a_heartbeat_round_trips_through_its_payload() {
605 let heartbeat = Heartbeat {
606 custom_mode: 0x0A0B0C0D,
607 type_: 2,
608 autopilot: 12,
609 base_mode: 0x81,
610 system_status: 4,
611 mavlink_version: 3,
612 };
613 let mut buf = [0u8; 255];
614 let len = heartbeat.encode(&mut buf);
615 assert_eq!(len, Heartbeat::WIRE_LEN);
616 assert_eq!(Heartbeat::decode(&buf[..len]).unwrap(), heartbeat);
617 }
618
619 #[test]
620 fn a_command_long_round_trips_through_field_reordering() {
621 let command = CommandLong {
624 param1: 1.0,
625 param2: 0.0,
626 param3: 0.0,
627 param4: 0.0,
628 param5: 12.34,
629 param6: 56.78,
630 param7: 100.0,
631 command: 400, target_system: 1,
633 target_component: 1,
634 confirmation: 0,
635 };
636 let mut buf = [0u8; 255];
637 let len = command.encode(&mut buf);
638 assert_eq!(len, CommandLong::WIRE_LEN);
639 assert_eq!(CommandLong::decode(&buf[..len]).unwrap(), command);
640 }
641
642 #[test]
643 fn an_extension_field_round_trips_after_the_base_fields() {
644 let count = MissionCount {
647 count: 7,
648 target_system: 1,
649 target_component: 1,
650 mission_type: crate::dialect::mav_mission_type::FENCE,
651 opaque_id: 0xDEAD_BEEF,
652 };
653 let mut buf = [0u8; 255];
654 let len = count.encode(&mut buf);
655 assert_eq!(len, MissionCount::WIRE_LEN);
656 assert_eq!(len, 4 + 1 + 4);
658 assert_eq!(MissionCount::decode(&buf[..len]).unwrap(), count);
659 }
660
661 #[test]
662 fn a_base_only_payload_decodes_extensions_as_zero() {
663 let base_only = [7u8, 0, 1, 1]; let decoded = MissionCount::decode(&base_only).unwrap();
668 assert_eq!(decoded.count, 7);
669 assert_eq!(decoded.mission_type, 0);
670 assert_eq!(decoded.opaque_id, 0);
671 }
672
673 #[test]
674 fn command_ack_keeps_its_seed_after_gaining_extensions() {
675 assert_eq!(
678 message_crc_extra("COMMAND_ACK", CommandAck::BASE_FIELDS),
679 CommandAck::CRC_EXTRA
680 );
681 assert_eq!(CommandAck::CRC_EXTRA, 143);
682 assert_eq!(CommandAck::BASE_FIELDS.len(), 2);
684 }
685
686 #[test]
687 fn decode_zero_extends_a_truncated_payload() {
688 let decoded = Heartbeat::decode(&[0]).unwrap();
691 assert_eq!(decoded, Heartbeat::default_zeroed());
692 }
693
694 impl Heartbeat {
695 fn default_zeroed() -> Self {
696 Heartbeat {
697 custom_mode: 0,
698 type_: 0,
699 autopilot: 0,
700 base_mode: 0,
701 system_status: 0,
702 mavlink_version: 0,
703 }
704 }
705 }
706}