Skip to main content

korri_n2k/
error.rs

1//! Error definitions shared across library modules.
2//! Each type models a specific failure scenario (CAN ID construction,
3//! address management, serialization/deserialization, etc.).
4use crate::core::FieldKind;
5use thiserror_no_std::Error;
6
7#[derive(Error, Debug)]
8/// Errors that can occur while building a 29-bit CAN identifier.
9pub enum CanIdBuildError {
10    /// Provided parameters do not produce a valid identifier.
11    #[error("Invalid data")]
12    InvalidData,
13
14    /// The destination address violates protocol constraints.
15    #[error("Invalid destination")]
16    InvalidDestination,
17
18    /// Attempt to build a broadcast message (PDU2) with PF < 240.
19    #[error("Invalid for broadcast message: PF is too low")]
20    InvalidForBroadcast,
21
22    /// Attempt to send an addressed message (PDU1) with PF ≥ 240.
23    #[error("Invalid for addressed message: PF is too high: {pgn}")]
24    InvalidForFocusedMessage { pgn: u8 },
25
26    /// In PDU1 the lower 8 bits of the PGN must remain zero.
27    #[error("PDU1 PGNs require PS = 0")]
28    PsFocusMessageMustBeNull,
29
30    /// No payload available to build the frame.
31    #[error("Payload is empty: unable to build")]
32    EmptyPayload,
33}
34
35#[derive(Error, Debug)]
36/// Errors encountered while claiming or defending an address.
37pub enum ClaimError<E: core::fmt::Debug> {
38    /// CAN bus rejected the frame during transmission.
39    #[error("CAN bus send error: {0:?}")]
40    SendError(E),
41
42    /// Unable to receive frames from the bus.
43    #[error("CAN bus receive error: {0:?}")]
44    ReceiveError(E),
45
46    /// The protocol logic rejected the claim; the bus is not involved;
47    #[error(transparent)]
48    Fault(#[from] ClaimFault),
49}
50
51#[derive(Error, Debug)]
52/// Claim failure decided from frame content alone. No I/O, fully reproducible.
53pub enum ClaimFault {
54    /// IsoName and Address Claim Strategy are inconsistents.
55    #[error("Inconsistent match between IsoName and Address Claim Strategy")]
56    InconsistentStrategy,
57
58    /// Failed to gather the information required to claim an address.
59    #[error("Request address claim error")]
60    RequestAddressClaimErr,
61
62    /// Failed to extract business data.
63    #[error(transparent)]
64    Extraction(#[from] ExtractionError),
65}
66
67#[derive(Debug, Error)]
68/// Failures while extracting information from a raw CAN frame.
69pub enum ExtractionError {
70    /// The frame does not conform to the NMEA 2000 specification.
71    #[error("Invalid incoming N2K frame")]
72    InvalidIncomingFrame,
73
74    /// Payload length does not match the PGN descriptor.
75    #[error("Invalid data length for PGN")]
76    InvalidDataLen,
77}
78
79//================================================================================CODEC_ERROR
80#[derive(Debug, Error)]
81/// Issues encountered while serializing a PGN into a buffer.
82pub enum SerializationError {
83    /// Provided buffer is too small for the payload.
84    #[error("Buffer too small")]
85    BufferTooSmall,
86
87    /// Data does not satisfy the descriptor constraints.
88    #[error("Invalid data")]
89    InvalidData,
90
91    /// Code generator detected a malformed repeating PGN definition.
92    #[error("Invalid repetitive PGN definition for {data}")]
93    RepeatitiveError { data: u32 },
94
95    /// Field length is not an acceptable bit multiple.
96    #[error("Invalid field bit length for {field_name}")]
97    InvalidFieldBits { field_name: &'static str },
98
99    /// Failed while writing bits into the output buffer.
100    #[error("BitWrite error: {err}")]
101    BitWriteError { err: BitWriterError },
102
103    /// Field type not supported by the serialization engine.
104    #[error("Unsupported field kind")]
105    UnsupportedFieldKind,
106
107    /// Expected field was missing from the domain structure.
108    #[error("Field {field_id} not found")]
109    FieldNotFound { field_id: &'static str },
110
111    /// Generic conversion error bubbling up from the codec module.
112    #[error("Codec Error: {source}")]
113    CodecError { source: CodecError },
114}
115
116#[derive(Error, Debug)]
117/// Errors raised while deserializing a CAN buffer into a PGN structure.
118pub enum DeserializationError {
119    /// Payload size does not match the expected schema.
120    #[error("Invalid data length")]
121    InvalidDataLength,
122
123    /// Bits read from the buffer cannot be interpreted according to the descriptor.
124    #[error("Malformed data")]
125    MalformedData,
126
127    /// Feature not implemented for this PGN yet.
128    #[error("Functionality not implemented for this PGN")]
129    NotImplemented,
130
131    /// Indirect field depends on a lookup table that is missing.
132    #[error("Missing Indirect Lookup Reference for descriptor {desc}: {pgn}")]
133    MissingIndirectLookupRef { desc: u32, pgn: &'static str },
134
135    /// Dependent field is missing or was not populated.
136    #[error("Dependency field not found {dep} for pgn {desc}")]
137    DependencyFieldNotFound { dep: &'static str, desc: u32 },
138
139    /// Field kind not supported by the parser.
140    #[error("Unsupported field kind {field_kind:?}")]
141    UnsupportedFieldKind { field_kind: FieldKind },
142
143    /// Could not assign value into the target structure.
144    #[error("Field assignment failed {desc}")]
145    FieldAssignmentFailed { desc: &'static str },
146
147    /// Field descriptor defines an invalid bit length.
148    #[error("Invalid field bit length for {field_name}")]
149    InvalidFieldBits { field_name: &'static str },
150
151    /// Error bubbled up from the generic codec engine.
152    #[error("Codec Error: {source}")]
153    CodecError { source: CodecError },
154
155    /// Bit-level access on the buffer failed (out of bounds, misalignment…).
156    #[error("BitReader error: {err}")]
157    BitReaderError { err: BitReaderError },
158}
159
160#[derive(Error, Debug)]
161/// Shared error abstraction for conversion helpers.
162pub enum CodecError {
163    /// Value type is incompatible with the algorithm.
164    #[error("Data type mismatch for {value_kind}, function: {func}")]
165    DataTypeMismatch {
166        value_kind: &'static str,
167        func: &'static str,
168    },
169}
170
171//==================================================================================SEND_ERROR
172#[derive(Debug, Error)]
173/// Errors encountered when sending a PGN (build + transmit).
174pub enum SendPgnError<E: core::fmt::Debug> {
175    /// PGN serialization failed.
176    #[error("Serialization failed")]
177    Serialization,
178
179    /// CAN identifier could not be built.
180    #[error("Frame build failed: {0:?}")]
181    Build(CanIdBuildError),
182
183    /// CAN layer refused or failed to send the frame.
184    #[error("CAN bus send error: {0:?}")]
185    Send(E),
186
187    /// No address acquired yet: nothing may be emitted.
188    #[error("No address claimed")]
189    NotClaimed,
190}
191
192//==================================================================================BITREADER_ERRORS
193#[derive(Debug, Error)]
194/// Errors raised during bitwise buffer reads.
195pub enum BitReaderError {
196    /// Attempted to read past the end of the buffer.
197    #[error("Attempted to read out of bounds -> asked: {asked}, available: {available}")]
198    OutOfBounds { asked: usize, available: usize },
199
200    /// Requested more bits than the target type can hold.
201    #[error("Cannot read more than {max} bits. Requested: {asked}")]
202    TooLongForType { max: u8, asked: u8 },
203
204    /// Cursor is not aligned on a byte boundary when required.
205    #[error("Non aligned bit. Cursor: {cursor}")]
206    NonAlignedBit { cursor: usize },
207}
208//==================================================================================BITREADER_ERRORS
209#[derive(Debug, Error)]
210/// Errors raised during bitwise writes into a buffer.
211pub enum BitWriterError {
212    /// Attempted to write beyond the provided capacity.
213    #[error("Attempted to write out of bounds -> asked: {asked}, available: {available}")]
214    OutOfBounds { asked: usize, available: usize },
215
216    /// Field is too large for the provided type.
217    #[error("Cannot write more than {max} bits. Requested: {asked}")]
218    TooLongForType { max: u8, asked: u8 },
219
220    /// Cursor is not aligned on a byte boundary when the operation requires it.
221    #[error("Non aligned bit. Cursor: {cursor}")]
222    NonAlignedBit { cursor: usize },
223}
224
225// These errors cross every `?` in the codec, on targets with 20 KB of RAM.
226// A failure here means a variant carries data by value again.
227// The limit fits both widths: 40 bytes on a 64-bit host, about 20 on a 32-bit target.
228const _: () = assert!(core::mem::size_of::<DeserializationError>() <= 48);
229const _: () = assert!(core::mem::size_of::<SerializationError>() <= 48);