1use color_eyre::eyre::eyre;
2use futures::{SinkExt, StreamExt, lock::Mutex};
3use log::{debug, error, info, trace, warn};
4use tokio_serial::{self, SerialPort, SerialPortBuilderExt, SerialStream};
5use tokio_util::{bytes::{Bytes, BytesMut}, codec::{Decoder, Encoder}};
6use std::{fmt::Display, io::{self, stdout}, sync::{Arc, atomic::Ordering}, time::{Duration, SystemTime, UNIX_EPOCH}};
7use meshcore::{identity::Keystore, packet::Packet};
8use pcap_file::pcap::{PcapPacket, PcapWriter};
9use std::io::Write;
10
11use atomic_enum::atomic_enum;
12
13#[atomic_enum]
14#[derive(PartialEq)]
15enum MeshTncState {
16 Unknown = 0,
17 Starting = 1,
18 RadioSet = 2,
19 Idle = 3,
20 KISS = 4,
21}
22
23impl Display for MeshTncState {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 match self {
26 MeshTncState::Unknown => write!(f, "Unknown"),
27 MeshTncState::Starting => write!(f, "Starting"),
28 MeshTncState::RadioSet => write!(f, "RadioSet"),
29 MeshTncState::Idle => write!(f, "Idle"),
30 MeshTncState::KISS => write!(f, "KISS"),
31 }
32 }
33}
34
35struct KissCodec {
36 state: Arc<AtomicMeshTncState>
37}
38
39impl Default for KissCodec {
40 fn default() -> Self {
41 Self { state:
42 Arc::new(AtomicMeshTncState::new(MeshTncState::Starting))
43 }
44 }
45}
46
47impl KissCodec {
48 fn decode_ascii(&mut self, src: &mut BytesMut) -> Result<Option<Vec<u8>>, io::Error> {
49 let newline = src.as_ref().iter().position(|b| *b == b'\n');
51 if let Some(n) = newline {
52 let line = src.split_to(n + 1);
53 return match str::from_utf8(line.as_ref()) {
54 Ok(s) => {
55 trace!("Got ascii line: {}", s.trim_ascii());
56 Ok(Some(s.into()))
57 },
58 Err(_) => Err(
59 io::Error::new(io::ErrorKind::Other, "Invalid String")),
60 };
61 } else {
62 Ok(None)
63 }
64 }
65
66 fn decode_kiss(&mut self, _src: &mut BytesMut) -> Result<Option<Vec<u8>>, io::Error> {
67 Ok(None)
68 }
69
70 fn encode_ascii(&self, src: Vec<u8>, dst: &mut BytesMut) -> Result<(), io::Error> {
71 let string = String::from_utf8(src);
73 if let Err(e) = string {
74 warn!("Tried to send illegal string over port: {}", e);
75 return Err(io::Error::new(io::ErrorKind::Other, "Invalid string"));
76 } else if let Ok(string) = string {
77 let newline_string = format!("{}\n\r", string);
78 let string_length = newline_string.as_bytes().len();
79 dst.reserve(string_length);
80 dst.extend_from_slice(newline_string.as_bytes());
81 Ok(())
82 } else {
83 Ok(())
85 }
86 }
87
88 fn encode_kiss(&self, _src: Vec<u8>, _dst: &mut BytesMut) -> Result<(), io::Error> {
89 Ok(())
90 }
91}
92
93impl Decoder for KissCodec {
94 type Item = Vec<u8>;
95 type Error = io::Error;
96
97 fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
98 let state = self.state.load(Ordering::Relaxed);
108 match state {
109 MeshTncState::Starting => return self.decode_ascii(src),
110 MeshTncState::RadioSet => return self.decode_ascii(src),
111 MeshTncState::Idle => return self.decode_ascii(src),
112 MeshTncState::KISS => return self.decode_kiss(src),
113
114 MeshTncState::Unknown => {
119 src.clear();
120 return Ok(None);
121 }
122 }
123 }
124}
125
126impl Encoder<Vec<u8>> for KissCodec {
127 type Error = io::Error;
128
129 fn encode(&mut self, mut item: Vec<u8>, dst: &mut BytesMut) -> Result<(), Self::Error> {
130 let state = self.state.load(Ordering::Relaxed);
133 match state {
134 MeshTncState::Starting => return self.encode_ascii(item, dst),
135 MeshTncState::RadioSet => return self.encode_ascii(item, dst),
136 MeshTncState::Idle => return self.encode_ascii(item, dst),
137 MeshTncState::KISS => return self.encode_kiss(item, dst),
138
139 MeshTncState::Unknown => {
144 item.clear();
145 return Ok(());
146 }
147 }
148 }
149}
150pub struct MeshTNC {
151 pub port: Mutex<SerialStream>,
152 pub freq: f32,
153 pub bw: f32,
154 pub sf: u8,
155 pub cr: u8,
156 pub sb: String,
157 pub keystore: Keystore
158}
159
160impl MeshTNC {
161 pub fn new(port: String, freq: f32, bw: f32, sf: u8, cr: u8, sb: String, keystore: Keystore) -> color_eyre::eyre::Result<MeshTNC> {
162
163 let mut port = tokio_serial::new(port, 115_200)
165 .flow_control(tokio_serial::FlowControl::None)
166 .stop_bits(tokio_serial::StopBits::One)
167 .data_bits(tokio_serial::DataBits::Eight)
168 .open_native_async()?;
169
170 #[cfg(unix)]
174 if let Err(e) = port.set_exclusive(false) {
175 warn!("Unable to set non-exslusive use of this port. ¯\\_(ツ)_/¯: {}", e.description);
176 }
177
178 Ok(MeshTNC {
179 port: Mutex::new(port),
180 freq,
181 bw,
182 sf,
183 cr,
184 sb,
185 keystore,
186 })
187 }
188
189 pub async fn start<W>(&mut self, mut pcap_writer: Option<PcapWriter<W>>) -> color_eyre::eyre::Result<()>
190 where W: Write {
191 let port = self.port.get_mut();
193
194 info!("Attempting to reboot TNC");
199 port.write_request_to_send(false)?;
200 tokio::time::sleep(Duration::from_millis(10)).await;
201 port.write_request_to_send(true)?;
202
203 let codec = KissCodec::default();
205 let local_state = Arc::clone(&codec.state);
208 let framed = codec.framed(port);
210 let (mut writer, mut reader) = framed.split();
211
212 while let Some(line_result) = reader.next().await {
214 let line = line_result.expect("Failed to read line");
215
216 let state = local_state.load(Ordering::Relaxed);
222
223 if state == MeshTncState::KISS {
224 }
226
227 else {
228 let line = String::from_utf8(line)?;
230
231 match state {
232 MeshTncState::Starting => {
235 if line.trim_ascii() == "Starting!" {
236 let radio_set = format!(
238 "set radio {},{},{},{},{}",
239 self.freq,
240 self.bw,
241 self.sf,
242 self.cr,
243 self.sb
244 );
245 writer.send(radio_set.as_bytes().to_vec()).await?;
247 local_state.store(MeshTncState::RadioSet, Ordering::Relaxed);
248 debug!("Moved into the Radio Set state")
249 }
250 }
251 MeshTncState::RadioSet => {
252 if line.contains("OK") {
256 local_state.store(MeshTncState::Idle, Ordering::Relaxed);
258 debug!("Moved into idle state");
259 info!("Radio ready!");
260
261 if pcap_writer.is_none() {
262 println!(" ROUTE T | v1 | Transp Fl. | Route Summary | I | Pkt. Type | Summary....");
263 }
264 } else if line.contains("Error") {
265 error!("Radio parameters weren't accepted by the TNC. Please check them.");
268 return Err(eyre!("Unable to set radio parameters; they were rejected by the TNC."));
269 }
270 }
271 MeshTncState::Idle => {
272 let components: Vec<&str> = line.trim_ascii().split(",").collect();
277 if components[1] == "RXLOG" {
278 if components.len() == 5 {
279 let _timestamp: Result<u64, _> = components[0].parse();
280 let _: Option<f32> = components[2].parse().ok();
283 let _: Option<f32> = components[3].parse().ok();
284 let data: Result<Vec<u8>, _> = hex::decode(components[4]);
285
286 if let Ok(data) = data {
287 debug!("Got packet: {}", hex::encode_upper(&data));
288
289 let bytes = Bytes::copy_from_slice(&data);
290
291 if let Some(ref mut pcap_writer) = pcap_writer {
292 Self::write_packet_pcap(&bytes, pcap_writer).await?;
293 }
294
295 let mut packet = Packet::from(bytes);
296 packet.try_decrypt(&self.keystore);
297 println!("{}", packet);
298
299 } else if let Err(e) = data {
300 debug!("Got RXLOG packet with invalid HEX: \"{}\": {}", components[4], e);
301 }
302
303 continue;
304 }
305 debug!("Got a potentially mal-formed RXLOG packet: \n{}", line);
306 }
307 },
308 MeshTncState::KISS => break,
310 MeshTncState::Unknown => break,
313 }
314
315 }
316 }
317
318 Ok(())
319 }
320
321 pub async fn write_packet_pcap<W>(packet: &Bytes, pcap_writer: &mut PcapWriter<W>) -> color_eyre::eyre::Result<()>
322 where W: Write {
323 pcap_writer.write_packet(&PcapPacket::new(
324 SystemTime::now().duration_since(UNIX_EPOCH)?,
325 (packet.len() + 14 + 20) as u32,
326 packet,
327 ))?;
328
329 stdout().flush()?;
331
332 Ok(())
333 }
334
335}