use crate::serial_actor::SerialEvent;
pub async fn run_debug_output(mut rx: tokio::sync::broadcast::Receiver<SerialEvent>) {
use std::io::{BufWriter, Write};
use std::path::Path;
let (write_tx, write_rx) = std::sync::mpsc::channel::<Vec<u8>>();
let write_handle = tokio::task::spawn_blocking(move || {
let path = Path::new("./debug.txt");
let file = match std::fs::File::create(path) {
Ok(f) => f,
Err(e) => {
eprintln!("Failed to create file: {e}");
return;
}
};
let mut writer = BufWriter::with_capacity(48 * 1024, file);
let mut last_flush = std::time::Instant::now();
writeln!(writer, "Session started at: {}", chrono::Utc::now()).ok();
while let Ok(data) = write_rx.recv() {
writeln!(
writer,
"[{}] RX {} bytes: {:02X?}{} UTF8: {}",
chrono::Utc::now().format("%H:%M:%S%.3f"),
data.len(),
&data[..std::cmp::min(20, data.len())],
if data.len() > 10 { "..." } else { "" },
String::from_utf8_lossy(&data)
)
.ok();
let now = std::time::Instant::now();
if now.duration_since(last_flush) > std::time::Duration::from_millis(100)
|| writer.buffer().len() > 32 * 1024
{
let _ = writer.flush();
last_flush = now;
}
}
let _ = writer.flush();
});
let data_streamer = tokio::spawn(async move {
let mut write_buf = Vec::with_capacity(4096);
let mut batch_timer = tokio::time::interval(tokio::time::Duration::from_millis(200));
loop {
tokio::select! {
event = rx.recv() => {
match event {
Ok(SerialEvent::Data(data)) => {
write_buf.extend_from_slice(&data);
if write_buf.len() >= 4096 && write_tx.send(std::mem::take(&mut write_buf)).is_err() {
break;
}
}
Err(tokio::sync::broadcast::error::RecvError::Lagged(skipped)) => {
eprintln!("File writer lagged, skipped {skipped} messages");
continue; }
_ => break,
}
}
_ = batch_timer.tick() => {
if !write_buf.is_empty() && write_tx.send(std::mem::take(&mut write_buf)).is_err() {
break;
}
}
}
}
if !write_buf.is_empty() {
let _ = write_tx.send(std::mem::take(&mut write_buf));
}
drop(write_tx);
});
let _ = data_streamer.await;
let _ = write_handle.await;
}