1use std::io::{self, Read, Write};
7use std::thread;
8use std::time::Duration;
9
10use rns_core::transport::types::InterfaceId;
11
12use crate::event::{Event, EventSender};
13use crate::hdlc;
14use crate::interface::Writer;
15use crate::serial::{Parity, SerialConfig, SerialPort};
16
17#[derive(Debug, Clone)]
19pub struct SerialIfaceConfig {
20 pub name: String,
21 pub port: String,
22 pub speed: u32,
23 pub data_bits: u8,
24 pub parity: Parity,
25 pub stop_bits: u8,
26 pub interface_id: InterfaceId,
27}
28
29impl Default for SerialIfaceConfig {
30 fn default() -> Self {
31 SerialIfaceConfig {
32 name: String::new(),
33 port: String::new(),
34 speed: 9600,
35 data_bits: 8,
36 parity: Parity::None,
37 stop_bits: 1,
38 interface_id: InterfaceId(0),
39 }
40 }
41}
42
43struct SerialWriter {
45 file: std::fs::File,
46}
47
48impl Writer for SerialWriter {
49 fn send_frame(&mut self, data: &[u8]) -> io::Result<()> {
50 self.file.write_all(&hdlc::frame(data))
51 }
52}
53
54pub fn start(config: SerialIfaceConfig, tx: EventSender) -> io::Result<Box<dyn Writer>> {
57 let serial_config = SerialConfig {
58 path: config.port.clone(),
59 baud: config.speed,
60 data_bits: config.data_bits,
61 parity: config.parity,
62 stop_bits: config.stop_bits,
63 };
64
65 let port = SerialPort::open(&serial_config)?;
66 let reader_file = port.reader()?;
67 let writer_file = port.writer()?;
68
69 let id = config.interface_id;
70
71 let _ = tx.send(Event::InterfaceUp(id, None, None));
73
74 thread::sleep(Duration::from_millis(500));
76
77 thread::Builder::new()
79 .name(format!("serial-reader-{}", id.0))
80 .spawn(move || {
81 reader_loop(reader_file, id, config, tx);
82 })?;
83
84 Ok(Box::new(SerialWriter { file: writer_file }))
85}
86
87fn reader_loop(
89 mut reader: std::fs::File,
90 id: InterfaceId,
91 config: SerialIfaceConfig,
92 tx: EventSender,
93) {
94 let mut decoder = hdlc::Decoder::new();
95 let mut buf = [0u8; 4096];
96
97 loop {
98 match reader.read(&mut buf) {
99 Ok(0) => {
100 log::warn!("[{}] serial port closed", config.name);
102 let _ = tx.send(Event::InterfaceDown(id));
103 match reconnect(&config, &tx) {
104 Some(new_reader) => {
105 reader = new_reader;
106 decoder = hdlc::Decoder::new();
107 continue;
108 }
109 None => return,
110 }
111 }
112 Ok(n) => {
113 for frame in decoder.feed(&buf[..n]) {
114 if tx
115 .send(Event::Frame {
116 interface_id: id,
117 data: frame,
118 })
119 .is_err()
120 {
121 return; }
123 }
124 }
125 Err(e) => {
126 log::warn!("[{}] serial read error: {}", config.name, e);
127 let _ = tx.send(Event::InterfaceDown(id));
128 match reconnect(&config, &tx) {
129 Some(new_reader) => {
130 reader = new_reader;
131 decoder = hdlc::Decoder::new();
132 continue;
133 }
134 None => return,
135 }
136 }
137 }
138 }
139}
140
141fn reconnect(config: &SerialIfaceConfig, tx: &EventSender) -> Option<std::fs::File> {
143 loop {
144 thread::sleep(Duration::from_secs(5));
145 log::info!(
146 "[{}] attempting to reconnect serial port {}...",
147 config.name,
148 config.port
149 );
150
151 let serial_config = SerialConfig {
152 path: config.port.clone(),
153 baud: config.speed,
154 data_bits: config.data_bits,
155 parity: config.parity,
156 stop_bits: config.stop_bits,
157 };
158
159 match SerialPort::open(&serial_config) {
160 Ok(port) => match (port.reader(), port.writer()) {
161 (Ok(reader), Ok(writer_file)) => {
162 log::info!("[{}] serial port reconnected", config.name);
163 let new_writer: Box<dyn Writer> = Box::new(SerialWriter { file: writer_file });
164 let _ = tx.send(Event::InterfaceUp(
165 config.interface_id,
166 Some(new_writer),
167 None,
168 ));
169 thread::sleep(Duration::from_millis(500));
170 return Some(reader);
171 }
172 _ => {
173 log::warn!(
174 "[{}] failed to get reader/writer from serial port",
175 config.name
176 );
177 }
178 },
179 Err(e) => {
180 log::warn!("[{}] serial reconnect failed: {}", config.name, e);
181 }
182 }
183 }
184}
185
186use super::{InterfaceConfigData, InterfaceFactory, StartContext, StartResult};
189use rns_core::transport::types::InterfaceInfo;
190use std::collections::HashMap;
191
192pub struct SerialFactory;
194
195impl InterfaceFactory for SerialFactory {
196 fn type_name(&self) -> &str {
197 "SerialInterface"
198 }
199
200 fn default_ifac_size(&self) -> usize {
201 8
202 }
203
204 fn parse_config(
205 &self,
206 name: &str,
207 id: InterfaceId,
208 params: &HashMap<String, String>,
209 ) -> Result<Box<dyn InterfaceConfigData>, String> {
210 let port = params
211 .get("port")
212 .cloned()
213 .ok_or_else(|| "SerialInterface requires 'port'".to_string())?;
214
215 let speed = params
216 .get("speed")
217 .and_then(|v| v.parse().ok())
218 .unwrap_or(9600u32);
219
220 let data_bits = params
221 .get("databits")
222 .and_then(|v| v.parse().ok())
223 .unwrap_or(8u8);
224
225 let parity = params
226 .get("parity")
227 .map(|v| match v.to_lowercase().as_str() {
228 "e" | "even" => crate::serial::Parity::Even,
229 "o" | "odd" => crate::serial::Parity::Odd,
230 _ => crate::serial::Parity::None,
231 })
232 .unwrap_or(crate::serial::Parity::None);
233
234 let stop_bits = params
235 .get("stopbits")
236 .and_then(|v| v.parse().ok())
237 .unwrap_or(1u8);
238
239 Ok(Box::new(SerialIfaceConfig {
240 name: name.to_string(),
241 port,
242 speed,
243 data_bits,
244 parity,
245 stop_bits,
246 interface_id: id,
247 }))
248 }
249
250 fn start(
251 &self,
252 config: Box<dyn InterfaceConfigData>,
253 ctx: StartContext,
254 ) -> std::io::Result<StartResult> {
255 let serial_config = *config
256 .into_any()
257 .downcast::<SerialIfaceConfig>()
258 .map_err(|_| {
259 std::io::Error::new(std::io::ErrorKind::InvalidData, "wrong config type")
260 })?;
261
262 let id = serial_config.interface_id;
263 let name = serial_config.name.clone();
264 let bitrate = Some(serial_config.speed as u64);
265
266 let info = InterfaceInfo {
267 id,
268 name,
269 mode: ctx.mode,
270 out_capable: true,
271 in_capable: true,
272 bitrate,
273 airtime_profile: None,
274 announce_rate_target: None,
275 announce_rate_grace: 0,
276 announce_rate_penalty: 0.0,
277 announce_cap: rns_core::constants::ANNOUNCE_CAP,
278 is_local_client: false,
279 wants_tunnel: false,
280 tunnel_id: None,
281 mtu: rns_core::constants::MTU as u32,
282 ingress_control: rns_core::transport::types::IngressControlConfig::disabled(),
283 ia_freq: 0.0,
284 started: crate::time::now(),
285 };
286
287 let writer = start(serial_config, ctx.tx)?;
288
289 Ok(StartResult::Simple {
290 id,
291 info,
292 writer,
293 interface_type_name: "SerialInterface".to_string(),
294 })
295 }
296}
297
298#[cfg(test)]
299mod tests {
300 use super::*;
301 use crate::serial::open_pty_pair;
302 use std::os::unix::io::{AsRawFd, FromRawFd};
303 use std::sync::mpsc;
304 use std::time::Duration;
305
306 fn poll_read(fd: i32, timeout_ms: i32) -> bool {
308 let mut pfd = libc::pollfd {
309 fd,
310 events: libc::POLLIN,
311 revents: 0,
312 };
313 let ret = unsafe { libc::poll(&mut pfd, 1, timeout_ms) };
314 ret > 0
315 }
316
317 #[test]
318 fn serial_hdlc_roundtrip() {
319 let (master_fd, slave_fd) = open_pty_pair().unwrap();
320 let mut master_file = unsafe { std::fs::File::from_raw_fd(master_fd) };
321 let mut slave_file = unsafe { std::fs::File::from_raw_fd(slave_fd) };
322
323 let payload: Vec<u8> = (0..32).collect();
325 let framed = hdlc::frame(&payload);
326 master_file.write_all(&framed).unwrap();
327 master_file.flush().unwrap();
328
329 assert!(
331 poll_read(slave_file.as_raw_fd(), 2000),
332 "should have data available"
333 );
334
335 let mut decoder = hdlc::Decoder::new();
336 let mut buf = [0u8; 4096];
337 let n = slave_file.read(&mut buf).unwrap();
338 let frames = decoder.feed(&buf[..n]);
339 assert_eq!(frames.len(), 1);
340 assert_eq!(frames[0], payload);
341 }
342
343 #[test]
344 fn serial_writer_frames() {
345 let (master_fd, slave_fd) = open_pty_pair().unwrap();
346
347 let writer_file = unsafe { std::fs::File::from_raw_fd(slave_fd) };
348 let mut writer = SerialWriter { file: writer_file };
349
350 let payload = vec![0x01, 0x02, 0x7E, 0x7D, 0x03]; writer.send_frame(&payload).unwrap();
352
353 let mut master_file = unsafe { std::fs::File::from_raw_fd(master_fd) };
355 assert!(poll_read(master_file.as_raw_fd(), 2000), "should have data");
356
357 let expected = hdlc::frame(&payload);
358 let mut buf = [0u8; 256];
359 let n = master_file.read(&mut buf).unwrap();
360 assert_eq!(&buf[..n], &expected[..]);
361 }
362
363 #[test]
364 fn serial_fragmented_read() {
365 let (master_fd, slave_fd) = open_pty_pair().unwrap();
366 let mut master_file = unsafe { std::fs::File::from_raw_fd(master_fd) };
367 let slave_file = unsafe { std::fs::File::from_raw_fd(slave_fd) };
368
369 let (tx, rx) = mpsc::channel::<Event>();
370
371 let payload: Vec<u8> = (0..32).collect();
373 let framed = hdlc::frame(&payload);
374 let mid = framed.len() / 2;
375
376 let reader_thread = thread::spawn(move || {
378 let mut reader = slave_file;
379 let mut decoder = hdlc::Decoder::new();
380 let mut buf = [0u8; 4096];
381
382 loop {
383 match reader.read(&mut buf) {
384 Ok(n) if n > 0 => {
385 if let Some(frame) = decoder.feed(&buf[..n]).into_iter().next() {
386 let _ = tx.send(Event::Frame {
387 interface_id: InterfaceId(0),
388 data: frame,
389 });
390 return;
391 }
392 }
393 _ => return,
394 }
395 }
396 });
397
398 master_file.write_all(&framed[..mid]).unwrap();
400 master_file.flush().unwrap();
401
402 thread::sleep(Duration::from_millis(50));
404 master_file.write_all(&framed[mid..]).unwrap();
405 master_file.flush().unwrap();
406
407 let event = rx.recv_timeout(Duration::from_secs(2)).unwrap();
408 match event {
409 Event::Frame { data, .. } => assert_eq!(data, payload),
410 other => panic!("expected Frame, got {:?}", other),
411 }
412
413 let _ = reader_thread.join();
414 }
415
416 #[test]
417 fn serial_reconnect_on_close() {
418 let (master_fd, slave_fd) = open_pty_pair().unwrap();
419
420 let (tx, rx) = mpsc::channel::<Event>();
421 let id = InterfaceId(42);
422
423 let slave_file = unsafe { std::fs::File::from_raw_fd(slave_fd) };
425 let reader_thread = thread::spawn(move || {
426 let mut reader = slave_file;
427 let mut buf = [0u8; 4096];
428 let mut decoder = hdlc::Decoder::new();
429 loop {
430 match reader.read(&mut buf) {
431 Ok(0) => {
432 let _ = tx.send(Event::InterfaceDown(id));
433 return;
434 }
435 Ok(n) => {
436 for frame in decoder.feed(&buf[..n]) {
437 let _ = tx.send(Event::Frame {
438 interface_id: id,
439 data: frame,
440 });
441 }
442 }
443 Err(_) => {
444 let _ = tx.send(Event::InterfaceDown(id));
445 return;
446 }
447 }
448 }
449 });
450
451 unsafe { libc::close(master_fd) };
453
454 let event = rx.recv_timeout(Duration::from_secs(2)).unwrap();
455 assert!(matches!(event, Event::InterfaceDown(InterfaceId(42))));
456
457 let _ = reader_thread.join();
458 }
459}