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}