Skip to main content

pamoja_mavlink/
error.rs

1//! The error model for the MAVLink wire layer.
2//!
3//! A single [`MavlinkError`] keeps framing, checksum, and signing faults uniform, the
4//! way [`pamoja-modbus`](https://docs.rs/pamoja-modbus) and
5//! [`pamoja-lorawan`](https://docs.rs/pamoja-lorawan) each carry their own protocol
6//! error type ahead of the transport layer.
7
8use core::fmt;
9
10/// A fault encountered while building, parsing, signing, or verifying a frame.
11///
12/// This enum is `#[non_exhaustive]`: new variants may be added without a breaking
13/// change, so a downstream `match` must include a wildcard arm.
14#[derive(Clone, Copy, Debug, PartialEq, Eq)]
15#[non_exhaustive]
16pub enum MavlinkError {
17    /// The bytes are shorter than the smallest valid frame of their version.
18    FrameTooShort,
19
20    /// The first byte is neither the v1 (`0xFE`) nor the v2 (`0xFD`) start marker.
21    BadMagic(u8),
22
23    /// The buffer ended before the frame its length field promised was complete.
24    Truncated,
25
26    /// The trailing checksum did not match the one computed over the frame.
27    CrcMismatch {
28        /// The checksum computed over the received bytes.
29        expected: u16,
30        /// The checksum the frame carried.
31        found: u16,
32    },
33
34    /// A message id has no known `CRC_EXTRA`, so its checksum cannot be validated and
35    /// its payload cannot be decoded.
36    UnknownMessage(u32),
37
38    /// A payload, frame, or field array was larger than the protocol or buffer allows.
39    PayloadTooLong,
40
41    /// A signature was required but the frame was not signed.
42    Unsigned,
43
44    /// The frame's signature did not match the one computed with the key.
45    BadSignature,
46
47    /// The frame's signing timestamp was older than the link's replay window allows.
48    ReplayedTimestamp,
49
50    /// A typed message was decoded from a payload of the wrong size or shape.
51    BadPayload,
52
53    /// The message has no field of the requested name.
54    UnknownField,
55
56    /// A field type name is not one MAVLink defines.
57    UnknownFieldType,
58
59    /// A message shape names the same field twice.
60    DuplicateField,
61
62    /// A field was read or written as a kind its type is not.
63    FieldTypeMismatch,
64
65    /// An array element index is past the end of the field.
66    FieldIndexOutOfRange,
67
68    /// A value does not fit the field's type.
69    ValueOutOfRange,
70
71    /// The link reached end of input before a frame could be read.
72    Closed,
73}
74
75impl fmt::Display for MavlinkError {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        match self {
78            Self::FrameTooShort => f.write_str("frame is shorter than a valid frame"),
79            Self::BadMagic(byte) => write!(f, "unrecognized start marker: {byte:#04x}"),
80            Self::Truncated => f.write_str("frame is shorter than its length field promises"),
81            Self::CrcMismatch { expected, found } => {
82                write!(
83                    f,
84                    "checksum mismatch: expected {expected:#06x}, found {found:#06x}"
85                )
86            }
87            Self::UnknownMessage(id) => write!(f, "no CRC_EXTRA known for message id {id}"),
88            Self::PayloadTooLong => f.write_str("payload exceeds the maximum frame size"),
89            Self::Unsigned => f.write_str("frame is not signed"),
90            Self::BadSignature => f.write_str("signature does not verify"),
91            Self::ReplayedTimestamp => f.write_str("signing timestamp is too old"),
92            Self::BadPayload => f.write_str("payload does not match the message layout"),
93            Self::UnknownField => f.write_str("message has no field of that name"),
94            Self::UnknownFieldType => f.write_str("unrecognized MAVLink field type"),
95            Self::DuplicateField => f.write_str("message names the same field twice"),
96            Self::FieldTypeMismatch => f.write_str("field is not of the requested kind"),
97            Self::FieldIndexOutOfRange => f.write_str("array index is past the end of the field"),
98            Self::ValueOutOfRange => f.write_str("value does not fit the field type"),
99            Self::Closed => f.write_str("link reached end of input"),
100        }
101    }
102}
103
104#[cfg(feature = "std")]
105impl std::error::Error for MavlinkError {}
106
107/// A specialized [`core::result::Result`] whose error type is [`MavlinkError`].
108pub type Result<T> = core::result::Result<T, MavlinkError>;