rbn_lib/
packet.rs

1//! Structures representing raw data as parsed from an RBN spotter
2
3use std::str::FromStr;
4
5use regex::Regex;
6use serde::{Deserialize, Serialize};
7
8// Regex pattern used for parsing raw data
9const REGEX_PATTERN: &str = r"DX de (?P<spotter>[A-Z\d\\/-]+)-#:\s*(?P<frequency>[\d.]+)\s+(?P<spotted>[A-Z\d\\/-]+)\s+(?P<mode>[A-Z\d]+)\s+(?P<snr>[\d-]+) dB\s+(?P<speed>\d+) [WPMBPS]+\s+(?P<message>[A-Za-z\\d ]+)\s*(?P<time>[0-9]{4})Z";
10
11/// A packet of data about a single spot
12#[derive(Debug, PartialEq, PartialOrd, Clone, Deserialize, Serialize)]
13pub struct RbnPacket {
14    /// Callsign of the spotter
15    pub spotter: String,
16    /// Frequency in KHz
17    pub frequency: f32,
18    /// Callsign of the spotted station
19    pub spotted: String,
20    /// Mode used
21    pub mode: String,
22    /// Signal strength in dB
23    pub snr: f32,
24    /// Signal speed
25    pub speed: u8,
26    /// Message
27    pub message: String,
28    /// Time in UTC of the packet
29    pub time: String,
30}
31
32impl RbnPacket {
33    /// Creates a string to identify a CQ call. Can be used to filter based on spotter (only record a CQ once, not N times due to multiple reports)
34    pub fn dirty_hash(&self) -> String {
35        format!(
36            "{}-{}-{}-{}",
37            self.spotted, self.frequency, self.mode, self.time
38        )
39    }
40}
41
42impl FromStr for RbnPacket {
43    type Err = ();
44
45    fn from_str(s: &str) -> Result<Self, Self::Err> {
46        let regex = Regex::new(REGEX_PATTERN).unwrap();
47        let mut captures = regex.captures_iter(s);
48        let first = captures.next();
49        if first.is_none() {
50            return Err(());
51        }
52        let first = first.unwrap();
53
54        // Build the output
55        Ok(Self {
56            spotter: first["spotter"].to_string(),
57            frequency: first["frequency"].parse().unwrap_or(0.0),
58            spotted: first["spotted"].to_string(),
59            mode: first["mode"].to_string(),
60            snr: first["snr"].parse().unwrap_or(0.0),
61            speed: first["speed"].parse().unwrap_or(0),
62            message: first["message"].to_string(),
63            time: first["time"].to_string(),
64        })
65    }
66}