add missing Error impls

This commit is contained in:
Robin Mueller
2025-09-10 17:48:10 +02:00
parent 4e153e0b68
commit a5dcba7d63
3 changed files with 46 additions and 83 deletions

View File

@@ -88,17 +88,10 @@ pub const CCSDS_HEADER_LEN: usize = core::mem::size_of::<crate::zc::SpHeader>();
pub const MAX_APID: u11 = u11::MAX; pub const MAX_APID: u11 = u11::MAX;
pub const MAX_SEQ_COUNT: u14 = u14::MAX; pub const MAX_SEQ_COUNT: u14 = u14::MAX;
#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)] #[inline]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub fn packet_type_in_raw_packet_id(packet_id: u16) -> PacketType {
#[cfg_attr(feature = "defmt", derive(defmt::Format))] PacketType::try_from((packet_id >> 12) as u8 & 0b1).unwrap()
#[error("apid is out of range, maximum value is {MAX_APID}")] }
pub struct ApidOutOfRangeError(u16);
#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[error("apid is out of range, maximum value is {MAX_SEQ_COUNT}")]
pub struct SequenceCountOutOfRangeError(u16);
/// Generic error type when converting to and from raw byte slices. /// Generic error type when converting to and from raw byte slices.
#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)] #[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
@@ -136,10 +129,6 @@ pub enum PacketType {
Tc = 1, Tc = 1,
} }
pub fn packet_type_in_raw_packet_id(packet_id: u16) -> PacketType {
PacketType::try_from((packet_id >> 12) as u8 & 0b1).unwrap()
}
#[derive(Debug, PartialEq, Eq, num_enum::TryFromPrimitive)] #[derive(Debug, PartialEq, Eq, num_enum::TryFromPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -203,22 +192,16 @@ impl Default for PacketId {
} }
impl PacketId { impl PacketId {
/// This constructor will panic if the passed APID exceeds [MAX_APID].
/// Use the checked constructor variants to avoid panics.
#[inline] #[inline]
pub const fn new_for_tc(sec_header: bool, apid: u11) -> Self { pub const fn new_for_tc(sec_header: bool, apid: u11) -> Self {
Self::new(PacketType::Tc, sec_header, apid) Self::new(PacketType::Tc, sec_header, apid)
} }
/// This constructor will panic if the passed APID exceeds [MAX_APID].
/// Use the checked constructor variants to avoid panics.
#[inline] #[inline]
pub const fn new_for_tm(sec_header: bool, apid: u11) -> Self { pub const fn new_for_tm(sec_header: bool, apid: u11) -> Self {
Self::new(PacketType::Tm, sec_header, apid) Self::new(PacketType::Tm, sec_header, apid)
} }
/// This constructor will panic if the passed APID exceeds [MAX_APID].
/// Use the checked variants to avoid panics.
#[inline] #[inline]
pub const fn new(ptype: PacketType, sec_header: bool, apid: u11) -> Self { pub const fn new(ptype: PacketType, sec_header: bool, apid: u11) -> Self {
PacketId { PacketId {

View File

@@ -5,11 +5,10 @@ use crate::{crc::CRC_CCITT_FALSE, ByteConversionError};
pub const USLP_VERSION_NUMBER: u8 = 0b1100; pub const USLP_VERSION_NUMBER: u8 = 0b1100;
/// Identifies the association of the data contained in the transfer frame. /// Identifies the association of the data contained in the transfer frame.
#[derive( #[derive(Debug, PartialEq, Eq, num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
Debug, Copy, Clone, PartialEq, Eq, num_enum::TryFromPrimitive, num_enum::IntoPrimitive,
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[bitbybit::bitenum(u1, exhaustive = true)]
#[repr(u8)] #[repr(u8)]
pub enum SourceOrDestField { pub enum SourceOrDestField {
/// SCID refers to the source of the transfer frame. /// SCID refers to the source of the transfer frame.
@@ -18,11 +17,10 @@ pub enum SourceOrDestField {
Dest = 1, Dest = 1,
} }
#[derive( #[derive(Debug, PartialEq, Eq, num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
Debug, Copy, Clone, PartialEq, Eq, num_enum::TryFromPrimitive, num_enum::IntoPrimitive,
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[bitbybit::bitenum(u1, exhaustive = true)]
#[repr(u8)] #[repr(u8)]
pub enum BypassSequenceControlFlag { pub enum BypassSequenceControlFlag {
/// Acceptance of this frame on the receiving end is subject to normal frame acceptance /// Acceptance of this frame on the receiving end is subject to normal frame acceptance
@@ -43,24 +41,26 @@ pub enum ProtocolControlCommandFlag {
TfdfContainsProtocolInfo = 1, TfdfContainsProtocolInfo = 1,
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
pub enum UslpError { pub enum UslpError {
ByteConversion(ByteConversionError), #[error("byte conversion error: {0}")]
ByteConversion(#[from] ByteConversionError),
#[error("header is truncated, which is not supported")]
HeaderIsTruncated, HeaderIsTruncated,
#[error("invalid protocol id: {0}")]
InvalidProtocolId(u8), InvalidProtocolId(u8),
#[error("invalid construction rule: {0}")]
InvalidConstructionRule(u8), InvalidConstructionRule(u8),
#[error("invalid version number: {0}")]
InvalidVersionNumber(u8), InvalidVersionNumber(u8),
InvalidVcid(u8), #[error("invalid virtual channel ID: {0}")]
InvalidVcId(u8),
#[error("invalid MAP ID: {0}")]
InvalidMapId(u8), InvalidMapId(u8),
#[error("checksum failure")]
ChecksumFailure(u16), ChecksumFailure(u16),
} }
impl From<ByteConversionError> for UslpError {
fn from(value: ByteConversionError) -> Self {
Self::ByteConversion(value)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -94,7 +94,7 @@ impl PrimaryHeader {
frame_len: u16, frame_len: u16,
) -> Result<Self, UslpError> { ) -> Result<Self, UslpError> {
if vc_id > 0b111111 { if vc_id > 0b111111 {
return Err(UslpError::InvalidVcid(vc_id)); return Err(UslpError::InvalidVcId(vc_id));
} }
if map_id > 0b1111 { if map_id > 0b1111 {
return Err(UslpError::InvalidMapId(map_id)); return Err(UslpError::InvalidMapId(map_id));
@@ -271,11 +271,10 @@ impl PartialEq for PrimaryHeader {
} }
} }
#[derive( #[derive(Debug, PartialEq, Eq, num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
Debug, Copy, Clone, PartialEq, Eq, num_enum::TryFromPrimitive, num_enum::IntoPrimitive,
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[bitbybit::bitenum(u5, exhaustive = false)]
#[repr(u8)] #[repr(u8)]
#[non_exhaustive] #[non_exhaustive]
pub enum UslpProtocolId { pub enum UslpProtocolId {
@@ -293,11 +292,10 @@ pub enum UslpProtocolId {
Idle = 0b11111, Idle = 0b11111,
} }
#[derive( #[derive(Debug, PartialEq, Eq, num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
Debug, Copy, Clone, PartialEq, Eq, num_enum::TryFromPrimitive, num_enum::IntoPrimitive,
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[bitbybit::bitenum(u3, exhaustive = true)]
#[repr(u8)] #[repr(u8)]
pub enum ConstructionRule { pub enum ConstructionRule {
/// Indicated fixed-length TFDZ whose contents are CCSDS packets concatenated together, which /// Indicated fixed-length TFDZ whose contents are CCSDS packets concatenated together, which
@@ -339,7 +337,8 @@ pub struct TransferFrameDataFieldHeader {
} }
impl TransferFrameDataFieldHeader { impl TransferFrameDataFieldHeader {
pub fn len_header(&self) -> usize { #[inline]
pub const fn len_header(&self) -> usize {
if self.construction_rule.applicable_to_fixed_len_tfdz() { if self.construction_rule.applicable_to_fixed_len_tfdz() {
3 3
} else { } else {
@@ -347,15 +346,18 @@ impl TransferFrameDataFieldHeader {
} }
} }
pub fn construction_rule(&self) -> ConstructionRule { #[inline]
pub const fn construction_rule(&self) -> ConstructionRule {
self.construction_rule self.construction_rule
} }
pub fn uslp_protocol_id(&self) -> UslpProtocolId { #[inline]
pub const fn uslp_protocol_id(&self) -> UslpProtocolId {
self.uslp_protocol_id self.uslp_protocol_id
} }
pub fn fhp_or_lvo(&self) -> Option<u16> { #[inline]
pub const fn fhp_or_lvo(&self) -> Option<u16> {
self.fhp_or_lvo self.fhp_or_lvo
} }
@@ -449,22 +451,27 @@ impl<'buf> TransferFrameReader<'buf> {
}) })
} }
#[inline]
pub fn len_frame(&self) -> usize { pub fn len_frame(&self) -> usize {
self.primary_header.len_frame() self.primary_header.len_frame()
} }
#[inline]
pub fn primary_header(&self) -> &PrimaryHeader { pub fn primary_header(&self) -> &PrimaryHeader {
&self.primary_header &self.primary_header
} }
#[inline]
pub fn data_field_header(&self) -> &TransferFrameDataFieldHeader { pub fn data_field_header(&self) -> &TransferFrameDataFieldHeader {
&self.data_field_header &self.data_field_header
} }
#[inline]
pub fn data(&self) -> &'buf [u8] { pub fn data(&self) -> &'buf [u8] {
self.data self.data
} }
#[inline]
pub fn operational_control_field(&self) -> &Option<u32> { pub fn operational_control_field(&self) -> &Option<u32> {
&self.operational_control_field &self.operational_control_field
} }
@@ -669,7 +676,7 @@ mod tests {
); );
assert!(error.is_err()); assert!(error.is_err());
let error = error.unwrap_err(); let error = error.unwrap_err();
matches!(error, UslpError::InvalidVcid(0b1101011)); matches!(error, UslpError::InvalidVcId(0b1101011));
} }
#[test] #[test]

View File

@@ -1,9 +1,7 @@
use crate::ByteConversionError; use crate::ByteConversionError;
use core::fmt::{Debug, Display, Formatter}; use core::fmt::Debug;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use std::error::Error;
pub trait ToBeBytes { pub trait ToBeBytes {
type ByteArray: AsRef<[u8]>; type ByteArray: AsRef<[u8]>;
@@ -100,49 +98,24 @@ pub trait UnsignedEnum {
pub trait UnsignedEnumExt: UnsignedEnum + Debug + Copy + Clone + PartialEq + Eq {} pub trait UnsignedEnumExt: UnsignedEnum + Debug + Copy + Clone + PartialEq + Eq {}
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum UnsignedByteFieldError { pub enum UnsignedByteFieldError {
/// Value is too large for specified width of byte field. /// Value is too large for specified width of byte field.
ValueTooLargeForWidth { #[error("value {value} too large for width {width}")]
width: usize, ValueTooLargeForWidth { width: usize, value: u64 },
value: u64,
},
/// Only 1, 2, 4 and 8 are allow width values. Optionally contains the expected width if /// Only 1, 2, 4 and 8 are allow width values. Optionally contains the expected width if
/// applicable, for example for conversions. /// applicable, for example for conversions.
#[error("invalid width {found}, expected {expected:?}")]
InvalidWidth { InvalidWidth {
found: usize, found: usize,
expected: Option<usize>, expected: Option<usize>,
}, },
ByteConversionError(ByteConversionError), #[error("byte conversion error: {0}")]
ByteConversionError(#[from] ByteConversionError),
} }
impl From<ByteConversionError> for UnsignedByteFieldError {
#[inline]
fn from(value: ByteConversionError) -> Self {
Self::ByteConversionError(value)
}
}
impl Display for UnsignedByteFieldError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
Self::ByteConversionError(e) => {
write!(f, "low level byte conversion error: {e}")
}
Self::InvalidWidth { found, .. } => {
write!(f, "invalid width {found}, only 1, 2, 4 and 8 are allowed.")
}
Self::ValueTooLargeForWidth { width, value } => {
write!(f, "value {value} too large for width {width}")
}
}
}
}
#[cfg(feature = "std")]
impl Error for UnsignedByteFieldError {}
/// Type erased variant. /// Type erased variant.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]