Skip to main content

nmea_kit/nmea/sentences/
tlb.rs

1use crate::nmea::field::{FieldReader, FieldWriter, NmeaEncodable};
2
3/// A single tracked target entry within a TLB sentence.
4#[derive(Debug, Clone, PartialEq)]
5pub struct TlbTarget {
6    /// Target number.
7    pub number: Option<u8>,
8    /// Target label.
9    pub label: Option<String>,
10}
11
12/// TLB — Target Label.
13///
14/// Wire: repeating pairs `number,label[,number,label,…]`
15#[derive(Debug, Clone, PartialEq)]
16pub struct Tlb {
17    /// Target number/label pairs (variable length).
18    pub targets: Vec<TlbTarget>,
19}
20
21impl Tlb {
22    /// Parse fields from a decoded NMEA frame.
23    /// Always returns `Some`; missing or malformed fields become `None`.
24    pub fn parse(fields: &[&str]) -> Option<Self> {
25        let mut r = FieldReader::new(fields);
26        let mut targets = Vec::new();
27        loop {
28            let number = r.u8();
29            if number.is_none() {
30                break;
31            }
32            targets.push(TlbTarget {
33                number,
34                label: r.string(),
35            });
36        }
37        Some(Self { targets })
38    }
39}
40
41impl NmeaEncodable for Tlb {
42    const SENTENCE_TYPE: &str = "TLB";
43
44    fn encode(&self) -> Result<Vec<String>, crate::EncodeError> {
45        let mut w = FieldWriter::new();
46        for t in &self.targets {
47            w.u8(t.number);
48            w.string(t.label.as_deref());
49        }
50        w.finish()
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57    use crate::parse_frame;
58
59    #[test]
60    fn tlb_empty() {
61        let s = Tlb { targets: vec![] }.to_sentence("RA").expect("encode");
62        let f = parse_frame(s.trim()).expect("valid");
63        let t = Tlb::parse(&f.fields).expect("parse");
64        assert!(t.targets.is_empty());
65    }
66
67    #[test]
68    fn tlb_encode_roundtrip() {
69        let original = Tlb {
70            targets: vec![
71                TlbTarget {
72                    number: Some(1),
73                    label: Some("ALPHA".to_string()),
74                },
75                TlbTarget {
76                    number: Some(2),
77                    label: Some("BETA".to_string()),
78                },
79            ],
80        };
81        let sentence = original.to_sentence("RA").expect("encode");
82        let frame = parse_frame(sentence.trim()).expect("re-parse");
83        let parsed = Tlb::parse(&frame.fields).expect("parse");
84        assert_eq!(original, parsed);
85    }
86
87    #[test]
88    fn tlb_ratlb_gonmea() {
89        let f = parse_frame("$RATLB,1,XXX*20").expect("valid TLB");
90        let t = Tlb::parse(&f.fields).expect("parse TLB");
91        assert_eq!(t.targets.len(), 1);
92        assert_eq!(t.targets[0].number, Some(1));
93        assert_eq!(t.targets[0].label, Some("XXX".to_string()));
94    }
95}