sericom_core/
debug.rs

1//! As of now, there is only one function, [`run_debug_output`], which is meant
2//! to debug the data being received over the serial connection. In future
3//! updates, this module is intended to be used for running tracing events with
4//! the [`tracing`](https://docs.rs/tracing/latest/tracing/) crate.
5
6use crate::serial_actor::SerialEvent;
7
8/// This function is used for debugging the data that is sent from a device.
9/// It will create a file "debug.txt" and print the data received from the device
10/// as the actual bytes received along with the corresponding ascii characters.
11///
12/// Data is sent from the [`SerialActor`][crate::serial_actor::SerialActor] to this function in batches,
13/// therefore a line written to "debug.txt" may look like this:
14///
15/// "\[04:41:27.550\] RX 9 bytes: \[0D, 0A, 53, 77, 69, 74, 63, 68\]... UTF8: ^M Switch#"
16///
17/// Each line will only print a maximum of 8 bytes, after 8 it will simply write "...".
18pub async fn run_debug_output(mut rx: tokio::sync::broadcast::Receiver<SerialEvent>) {
19    use std::io::{BufWriter, Write};
20    use std::path::Path;
21
22    let (write_tx, write_rx) = std::sync::mpsc::channel::<Vec<u8>>();
23    let write_handle = tokio::task::spawn_blocking(move || {
24        let path = Path::new("./debug.txt");
25        let file = match std::fs::File::create(path) {
26            Ok(f) => f,
27            Err(e) => {
28                eprintln!("Failed to create file: {e}");
29                return;
30            }
31        };
32        let mut writer = BufWriter::with_capacity(48 * 1024, file);
33        let mut last_flush = std::time::Instant::now();
34
35        writeln!(writer, "Session started at: {}", chrono::Utc::now()).ok();
36        while let Ok(data) = write_rx.recv() {
37            writeln!(
38                writer,
39                "[{}] RX {} bytes: {:02X?}{} UTF8: {}",
40                chrono::Utc::now().format("%H:%M:%S%.3f"),
41                data.len(),
42                &data[..std::cmp::min(8, data.len())],
43                if data.len() > 8 { "..." } else { "" },
44                String::from_utf8_lossy(&data)
45            )
46            .ok();
47
48            let now = std::time::Instant::now();
49            if now.duration_since(last_flush) > std::time::Duration::from_millis(100)
50                || writer.buffer().len() > 32 * 1024
51            {
52                let _ = writer.flush();
53                last_flush = now;
54            }
55        }
56        let _ = writer.flush();
57    });
58
59    let data_streamer = tokio::spawn(async move {
60        let mut write_buf = Vec::with_capacity(4096);
61        let mut batch_timer = tokio::time::interval(tokio::time::Duration::from_millis(200));
62
63        loop {
64            tokio::select! {
65                event = rx.recv() => {
66                    match event {
67                        Ok(SerialEvent::Data(data)) => {
68                            write_buf.extend_from_slice(&data);
69                            if write_buf.len() >= 4096 && write_tx.send(std::mem::take(&mut write_buf)).is_err() {
70                                    break;
71                            }
72                        }
73                        Err(tokio::sync::broadcast::error::RecvError::Lagged(skipped)) => {
74                            eprintln!("File writer lagged, skipped {skipped} messages");
75                            continue; // Don't break on lag
76                        }
77                        _ => break,
78                    }
79                }
80                _ = batch_timer.tick() => {
81                    if !write_buf.is_empty() && write_tx.send(std::mem::take(&mut write_buf)).is_err() {
82                            break;
83                    }
84                }
85            }
86        }
87        if !write_buf.is_empty() {
88            let _ = write_tx.send(std::mem::take(&mut write_buf));
89        }
90        drop(write_tx);
91    });
92
93    let _ = data_streamer.await;
94    let _ = write_handle.await;
95}