aprs/
status.rs

1//! APRS status report (APRS 1.0.1 ch. 16).
2
3use crate::error::AprsError;
4
5/// An APRS status report (data type `>`).
6///
7/// Contains free-form text, optionally prefixed with a Maidenhead
8/// grid locator (6 chars) or a timestamp (7 chars DHM/HMS).
9#[derive(Debug, Clone, PartialEq, Eq, Default)]
10pub struct AprsStatus {
11    /// Status text.
12    pub text: String,
13}
14
15/// Parse an APRS status report (`>text`).
16///
17/// # Errors
18///
19/// Returns [`AprsError::InvalidFormat`] if the info field does not begin
20/// with `>`.
21pub fn parse_aprs_status(info: &[u8]) -> Result<AprsStatus, AprsError> {
22    if info.first() != Some(&b'>') {
23        return Err(AprsError::InvalidFormat);
24    }
25    let body = info.get(1..).unwrap_or(&[]);
26    let text = String::from_utf8_lossy(body).trim().to_string();
27    Ok(AprsStatus { text })
28}
29
30// ---------------------------------------------------------------------------
31// Tests
32// ---------------------------------------------------------------------------
33
34#[cfg(test)]
35mod tests {
36    use super::*;
37
38    type TestResult = Result<(), Box<dyn std::error::Error>>;
39
40    #[test]
41    fn parse_status_basic() -> TestResult {
42        let info = b">Operating on 144.390";
43        let status = parse_aprs_status(info)?;
44        assert_eq!(status.text, "Operating on 144.390");
45        Ok(())
46    }
47
48    #[test]
49    fn parse_status_empty() -> TestResult {
50        let info = b">";
51        let status = parse_aprs_status(info)?;
52        assert_eq!(status.text, "");
53        Ok(())
54    }
55}