Skip to main content

aprs_decode/
error.rs

1use thiserror::Error;
2
3#[derive(Debug, Error)]
4pub enum AprsError {
5    // --- Header parsing ---
6    #[error("packet is empty")]
7    EmptyPacket,
8
9    #[error("missing '>' in packet header (expected FROM>TO,VIA:DATA)")]
10    MissingDestinationDelimiter,
11
12    #[error("missing ':' in packet header (expected FROM>TO,VIA:DATA)")]
13    MissingInfoDelimiter,
14
15    #[error("invalid callsign: {raw:?}")]
16    InvalidCallsign { raw: Vec<u8> },
17
18    #[error("invalid via element: {raw:?}")]
19    InvalidVia { raw: Vec<u8> },
20
21    // --- AX.25 frame parsing ---
22    #[error("AX.25 frame too short (got {len} bytes, need at least 15)")]
23    Ax25FrameTooShort { len: usize },
24
25    #[error("AX.25 frame missing end-of-address bit in expected range")]
26    Ax25MissingEoa,
27
28    #[error("AX.25 control byte is not UI frame (0x03), got 0x{byte:02x}")]
29    Ax25NotUiFrame { byte: u8 },
30
31    #[error("AX.25 PID is not APRS (0xF0), got 0x{byte:02x}")]
32    Ax25NotAprsPid { byte: u8 },
33
34    // --- Position ---
35    #[error("invalid latitude: expected DDmm.mmN/S format, got {raw:?}")]
36    InvalidLatitude { raw: Vec<u8> },
37
38    #[error("invalid longitude: expected DDDmm.mmE/W format, got {raw:?}")]
39    InvalidLongitude { raw: Vec<u8> },
40
41    #[error("unsupported position format")]
42    UnsupportedPositionFormat,
43
44    // --- Timestamp ---
45    #[error("timestamp day {day} is out of range 1–31")]
46    TimestampDayOutOfRange { day: u8 },
47
48    #[error("timestamp hour {hour} is out of range 0–23")]
49    TimestampHourOutOfRange { hour: u8 },
50
51    #[error("timestamp minute {minute} is out of range 0–59")]
52    TimestampMinuteOutOfRange { minute: u8 },
53
54    #[error("timestamp second {second} is out of range 0–59")]
55    TimestampSecondOutOfRange { second: u8 },
56
57    #[error("invalid timestamp format: {raw:?}")]
58    InvalidTimestampFormat { raw: Vec<u8> },
59
60    // --- Message ---
61    #[error("invalid message: missing second ':' delimiter")]
62    InvalidMessageMissingDelimiter,
63
64    // --- Object / Item ---
65    #[error("invalid object: {detail}")]
66    InvalidObject { detail: &'static str },
67
68    #[error("invalid item: {detail}")]
69    InvalidItem { detail: &'static str },
70
71    // --- MIC-E ---
72    #[error("invalid MIC-E destination: {raw:?}")]
73    InvalidMicEDestination { raw: Vec<u8> },
74
75    #[error("MIC-E information field too short (got {len} bytes, need at least 8)")]
76    MicETooShort { len: usize },
77
78    // --- Compressed position ---
79    #[error("invalid base-91 compressed position byte: 0x{byte:02x}")]
80    InvalidCompressedByte { byte: u8 },
81
82    // --- General ---
83    #[error("truncated packet: expected at least {expected} bytes, got {got}")]
84    TruncatedPacket { expected: usize, got: usize },
85
86    #[error("non-ASCII byte in field that requires ASCII: 0x{byte:02x}")]
87    NonAsciiByte { byte: u8 },
88
89    // --- Encoding ---
90    #[error("cannot encode: {detail}")]
91    EncodeError { detail: &'static str },
92}