1use crate::adsb::AdsbMessage;
2
3pub mod adsb;
4
5#[derive(Clone, PartialEq, Eq)]
6pub struct DF17Message {
7 pub capability: u8,
8 pub icao: u32,
9 pub tc: u8,
10 pub msg: AdsbMessage,
11}
12
13impl std::fmt::Debug for DF17Message {
14 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15 f.debug_struct("DF17Message")
16 .field("capability", &self.capability)
17 .field("icao", &format_args!("{:06X}", self.icao))
18 .field("tc", &self.tc)
19 .field("msg", &self.msg)
20 .finish()
21 }
22}
23
24impl DF17Message {
25 pub fn decode(data: Vec<u8>) -> DF17Message {
26 let capability = data[0] & 0x07;
27 let icao = u32::from_be_bytes([0, data[1], data[2], data[3]]);
28 let tc = (data[4] >> 3) & 0x1F;
29 let msg = AdsbMessage::decode(data);
30 DF17Message { capability, icao, tc, msg }
31 }
32}
33
34#[derive(Clone, PartialEq, Eq)]
35pub struct DF18Message {
36 pub control: u8,
37 pub icao: u32,
38 pub tc: Option<u8>,
39 pub msg: Option<AdsbMessage>,
40}
41
42impl std::fmt::Debug for DF18Message {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 f.debug_struct("DF18Message")
45 .field("control", &self.control)
46 .field("icao", &format_args!("{:06X}", self.icao))
47 .field("tc", &self.tc)
48 .field("msg", &self.msg)
49 .finish()
50 }
51}
52
53impl DF18Message {
54 pub fn decode(data: Vec<u8>) -> DF18Message {
55 let control = data[0] & 0x07;
56 let icao = u32::from_be_bytes([0, data[1], data[2], data[3]]);
57 let (tc, msg) = if control == 0 {
58 let tc = (data[4] >> 3) & 0x1F;
59 let msg = AdsbMessage::decode(data);
60 (Some(tc), Some(msg))
61 } else {
62 (None, None)
63 };
64 DF18Message { control, icao, tc, msg }
65 }
66}
67
68#[derive(Clone, PartialEq, Eq)]
69pub struct DF19Message {
70 pub application: u8,
71 pub icao: u32,
72 pub tc: Option<u8>,
73 pub msg: Option<AdsbMessage>,
74}
75
76impl std::fmt::Debug for DF19Message {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 f.debug_struct("DF19Message")
79 .field("application", &self.application)
80 .field("icao", &format_args!("{:06X}", self.icao))
81 .field("tc", &self.tc)
82 .field("msg", &self.msg)
83 .finish()
84 }
85}
86
87impl DF19Message {
88 pub fn decode(data: Vec<u8>) -> DF19Message {
89 let application = data[0] & 0x07;
90 let icao = u32::from_be_bytes([0, data[1], data[2], data[3]]);
91 let (tc, msg) = if application == 0 {
92 let tc = (data[4] >> 3) & 0x1F;
93 let msg = AdsbMessage::decode(data);
94 (Some(tc), Some(msg))
95 } else {
96 (None, None)
97 };
98 DF19Message { application, icao, tc, msg }
99 }
100}
101
102#[derive(Debug, Clone, PartialEq, Eq)]
103pub enum ModeSMessage {
104 DF17(DF17Message),
105 DF18(DF18Message),
106 DF19(DF19Message),
107 Other(Vec<u8>),
108}
109
110impl ModeSMessage {
111 pub fn decode(data: Vec<u8>) -> Option<ModeSMessage> {
112 if !matches!(data.len(), 7 | 14) {
113 return None;
114 }
115
116 let df: u8 = (data[0] & 0xF8) >> 3;
117
118 match df {
119 17 => Some(ModeSMessage::DF17(DF17Message::decode(data))),
120 18 => Some(ModeSMessage::DF18(DF18Message::decode(data))),
121 19 => Some(ModeSMessage::DF19(DF19Message::decode(data))),
122 _ => Some(ModeSMessage::Other(data)),
123 }
124 }
125}