aprs_parser/
lib.rs

1//! [APRS] message parser for [Rust]
2//!
3//! [APRS]: http://www.aprs.org/
4//! [Rust]: https://www.rust-lang.org/
5//!
6//! # Usage
7//!
8//! ```rust
9//! extern crate aprs_parser;
10//!
11//! use aprs_parser::{AprsCst, AprsData, AprsPacket, AprsPosition, Callsign, Latitude, Longitude, Precision, Timestamp, Via, QConstruct};
12//!
13//! fn main() {
14//!     let result = AprsPacket::decode_textual(
15//!         br"ICA3D2>APRS,qAS,dl4mea:/074849h4821.61N\01224.49E^322/103/A=003054"
16//!     );
17//!
18//!     assert_eq!(
19//!         result,
20//!         Ok(
21//!             AprsPacket {
22//!                 from: Callsign::new_no_ssid("ICA3D2"),
23//!                 via: vec![
24//!                     Via::QConstruct(QConstruct::AS),
25//!                     Via::Callsign(Callsign::new_no_ssid("dl4mea"), false),
26//!                 ],
27//!                 data: AprsData::Position(
28//!                     AprsPosition {
29//!                         to: Callsign::new_no_ssid("APRS"),
30//!                         timestamp: Some(
31//!                             Timestamp::HHMMSS(
32//!                                 7,
33//!                                 48,
34//!                                 49
35//!                             )
36//!                         ),
37//!                         messaging_supported: false,
38//!                         latitude: Latitude::new(48.36016666666667).unwrap(),
39//!                         longitude: Longitude::new(12.408166666666666).unwrap(),
40//!                         precision: Precision::HundredthMinute,
41//!                         symbol_table: '\\',
42//!                         symbol_code: '^',
43//!                         comment: b"322/103/A=003054".to_vec(),
44//!                         cst: AprsCst::Uncompressed,
45//!                     }
46//!                 )
47//!             }
48//!        )
49//!    );
50//! }
51//! ```
52
53// `!(-90. ..=90.).contains(&value)` seems worse than `value > 90. || value < -90.`
54#![allow(clippy::manual_range_contains)]
55
56extern crate thiserror;
57
58#[cfg(test)]
59#[macro_use]
60extern crate approx;
61
62mod base91;
63mod bytes;
64mod callsign;
65mod compressed_cs;
66pub mod compression_type;
67mod error;
68mod lonlat;
69mod message;
70pub mod mic_e;
71mod packet;
72mod position;
73mod status;
74mod timestamp;
75mod via;
76
77pub use callsign::Callsign;
78pub use compressed_cs::{AprsAltitude, AprsCompressedCs, AprsCourseSpeed, AprsRadioRange};
79pub use compression_type::AprsCompressionType;
80pub use error::{DecodeError, EncodeError};
81pub use lonlat::{Latitude, Longitude};
82pub use message::AprsMessage;
83pub use mic_e::AprsMicE;
84pub use packet::{AprsData, AprsPacket};
85pub use position::{AprsCst, AprsPosition, Precision};
86pub use status::AprsStatus;
87pub use timestamp::{DhmTimestamp, Timestamp};
88pub use via::{QConstruct, Via};
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn overall() {
96        let original =
97            &b"ICA3D2>Aprs,qAO,dl4mea::DEST     :Hello World! This msg has a : colon {3a2B975"[..];
98
99        let mut buf = vec![];
100        AprsPacket::decode_textual(original)
101            .unwrap()
102            .encode_textual(&mut buf)
103            .unwrap();
104        assert_eq!(original, &buf);
105    }
106}