mavio/protocol/update.rs
1use crate::protocol::{Checksum, CrcExtra, Header, Signature};
2
3use crate::prelude::*;
4
5/// <sup>`⚠`</sup>
6/// Implementors of this trait can update frame data in-place.
7///
8/// This trait contains blanket implementations for utility methods, that rely on the
9/// [`UpdateFrameUnsafe`]. The latter has to be implemented in order to update frames.
10///
11/// # Examples
12///
13/// Create a frame updater, that inverts bits of a payload.
14///
15/// ```rust
16/// use mavio::prelude::*;
17/// use mavio::protocol::{Checksum, Header, Signature, UpdateFrame, UpdateFrameUnsafe};
18///
19/// struct Flipper;
20///
21/// impl<V: MaybeVersioned> UpdateFrameUnsafe<V> for Flipper {
22/// unsafe fn update_unsafe(
23/// &mut self,
24/// header: Header<V>,
25/// payload: &mut [u8],
26/// checksum: &mut Checksum,
27/// signature: &mut Option<Signature>
28/// ) {
29/// for i in 0..payload.len() {
30/// payload[i] = payload[i] ^ 0xff;
31/// }
32/// }
33/// }
34/// impl<V: MaybeVersioned> UpdateFrame<V> for Flipper {}
35///
36/// let mut frame = Frame::builder()
37/// .version(V2)
38/// /* frame settings */
39/// # .sequence(0)
40/// # .system_id(0)
41/// # .component_id(0)
42/// # .message_id(0)
43/// .payload(&[0, 1, 255])
44/// # .crc_extra(0)
45/// .build();
46///
47/// let mut flipper = Flipper;
48/// flipper.update(&mut frame, 42);
49///
50/// assert_eq!(frame.payload().bytes(), &[255, 254, 0]);
51/// ```
52pub trait UpdateFrame<V: MaybeVersioned>: UpdateFrameUnsafe<V> {
53 /// <sup>`⚠`</sup>
54 /// Updates a frame.
55 ///
56 /// **⚠** This method relies on the access to internal frame state and can't be reimplemented!
57 ///
58 /// The `crc_extra` parameter will be used to calculate a correct checksum.
59 ///
60 /// If frame updater adds a signature, then `MAVLink 2` frame will be considered signed (and
61 /// vice versa). For `MAVLink 1` frames adding signature won't have any effect on a frame.
62 ///
63 /// **⚠** If the underlying [`UpdateFrameUnsafe::update_unsafe`] does not re-calculate
64 /// [`Frame::signature`], then it may be potentially corrupted. Make sure, that you know, how to
65 /// sign the updated frame afterward.
66 fn update(&mut self, frame: &mut Frame<V>, crc_extra: CrcExtra) {
67 unsafe {
68 self.update_unchecked(frame);
69 }
70
71 frame.checksum = frame.calculate_crc(crc_extra);
72 }
73
74 /// <sup>`⚠`</sup>
75 /// Updates frame without changing [`Frame::checksum`] to the correct value.
76 ///
77 /// **⚠** This method relies on the access to internal frame state and can't be reimplemented!
78 ///
79 /// If frame updater adds a signature, then `MAVLink 2` frame will be considered signed (and
80 /// vice versa). For `MAVLink 1` frames adding signature won't have any effect on a frame.
81 ///
82 /// **⚠** The implementor of the trait has a full responsibility for providing a correct
83 /// checksum and signature. Always use [UpdateFrame::update], if you know `CRC_EXTRA` to
84 /// calculate a correct checksum.
85 unsafe fn update_unchecked(&mut self, frame: &mut Frame<V>) {
86 self.update_unsafe(
87 frame.header.clone(),
88 frame.payload.bytes_mut(),
89 &mut frame.checksum,
90 &mut frame.signature,
91 );
92
93 match frame.version() {
94 MavLinkVersion::V1 => frame.signature = None,
95 MavLinkVersion::V2 => {
96 frame.header.set_is_signed(frame.signature.is_some());
97 }
98 }
99 }
100}
101
102/// <sup>`⚠`</sup>
103/// This trait should be implemented in order to use [`UpdateFrame`] trait and update frames
104/// in-place.
105///
106/// **⚠** This trait contains unsafe and dangerous methods, that may corrupt frames and lead to
107/// undefined behavior. In general, you would never need such low-level access to frame internals.
108/// However, in some scenarios this may be the only way to provide a desired functionality. For
109/// example, if you want to encrypt frames keeping them compatible with existing MAVLink
110/// network infrastructure.
111pub trait UpdateFrameUnsafe<V: MaybeVersioned> {
112 /// <sup>`⚠`</sup>
113 /// Updates frame payload bytes in-place, checksum, and signature.
114 ///
115 /// **⚠** The method is considered unsafe, as it may lead to data corruption and undefined
116 /// behavior. You should almost never use it directly. Instead, use [`UpdateFrame`] trait, that
117 /// contains blanket implementations for most of the cases, when you may expect sane results.
118 ///
119 /// If you just want to update an existing frame with data from a MAVLink message, then it is
120 /// always safer to use [`Frame::try_update_from`].
121 unsafe fn update_unsafe(
122 &mut self,
123 header: Header<V>,
124 payload: &mut [u8],
125 checksum: &mut Checksum,
126 signature: &mut Option<Signature>,
127 );
128}