1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
//! Invalid messages. This message type should be created out of two errors:
//! The SbpMsgParseError, & the CrcError. They correspond to two cases
//! 1) the Frame is invalid because either it either has an invalid CRC or
//! it is missing some metadata like msg_type or similar.
//! 2) The message is invalid because the payload is not large enough and cannot be
//! parsed into a message. This is the SbpMsgParseError.
use bytes::{Buf, BufMut};
use crate::{de::CrcError, messages::SbpMsgParseError, wire_format::WireFormat, SbpMessage};
/// Invalid messages occur when either the frame or message payload doesn't have enough bytes or
/// the CRC does not match the messages payload. If the message is well formed with a message
/// id and CRC and payload that all are consistent, but its message type is unknown, it should be
/// parsed into a Unknown message.
///
/// There is something unique about Invalid messages that the payload is actually the entire frame.
/// This is because it is possible to be able to create invalid messages from invalid frames, that
/// may not even contain a message payload.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Invalid {
/// The message id of the message.
#[cfg_attr(feature = "serde", serde(default, skip_serializing))]
pub msg_id: Option<u16>,
/// The message sender_id.
#[cfg_attr(feature = "serde", serde(default, skip_serializing, alias = "sender"))]
pub sender_id: Option<u16>,
/// The crc that was in the frame
#[cfg_attr(feature = "serde", serde(default, skip_serializing))]
pub crc: Option<u16>,
#[cfg_attr(feature = "serde", serde(default, skip))]
pub invalid_frame: Vec<u8>,
}
impl SbpMessage for Invalid {
fn message_name(&self) -> &'static str {
"INVALID"
}
fn message_type(&self) -> Option<u16> {
self.msg_id
}
fn sender_id(&self) -> Option<u16> {
self.sender_id
}
fn set_sender_id(&mut self, new_id: u16) {
self.sender_id = Some(new_id);
}
fn encoded_len(&self) -> usize {
// note here we don't add the header and crc etc because the
// invalid message holds the entire frame in
// its payload
WireFormat::len(self)
}
fn is_valid(&self) -> bool {
// Invalid messages can never be valid
false
}
fn into_valid_msg(self) -> Result<Self, Self> {
// Invalid messages can never be valid
Err(self)
}
}
impl WireFormat for Invalid {
/// because this is an invalid message, the length may disagree
/// with what you would expect from parsing the frame itself
fn len(&self) -> usize {
self.invalid_frame.len()
}
fn write<B: BufMut>(&self, buf: &mut B) {
self.invalid_frame.write(buf)
}
/// In general it is better to construct invalid messages
/// from thrown errors, not to directly parse to them
fn parse_unchecked<B: Buf>(buf: &mut B) -> Self {
Invalid {
msg_id: None,
sender_id: None,
crc: None,
invalid_frame: WireFormat::parse_unchecked(buf),
}
}
}
impl From<SbpMsgParseError> for Invalid {
fn from(
SbpMsgParseError {
msg_type,
sender_id,
invalid_payload: msg_payload,
}: SbpMsgParseError,
) -> Self {
// payload here is the whole frame
let mut payload =
Vec::with_capacity(msg_payload.len() + crate::HEADER_LEN + crate::CRC_LEN);
crate::PREAMBLE.write(&mut payload);
msg_type.write(&mut payload);
sender_id.write(&mut payload);
(msg_payload.len() as u8).write(&mut payload);
msg_payload.write(&mut payload);
let crc =
crc16::State::<crc16::XMODEM>::calculate(payload.get(1..).expect("vec has capacity"));
crc.write(&mut payload);
Self {
msg_id: Some(msg_type),
sender_id: Some(sender_id),
invalid_frame: payload,
crc: Some(crc),
}
}
}
impl From<CrcError> for Invalid {
fn from(
CrcError {
msg_type,
sender_id,
invalid_frame,
crc,
}: CrcError,
) -> Self {
Self {
msg_id: msg_type,
sender_id,
invalid_frame,
crc,
}
}
}