use std::io::Write;
use std::os::unix::net::UnixStream;
use std::sync::{Mutex, OnceLock};
use std::time::{SystemTime, UNIX_EPOCH};
const SOCKET_PATH: &str = "/tmp/crazyflie-capture.sock";
pub const LINK_TYPE_RADIO: u8 = 1;
pub const LINK_TYPE_USB: u8 = 2;
pub const DIRECTION_TX: u8 = 0;
pub const DIRECTION_RX: u8 = 1;
static CAPTURE_SOCKET: OnceLock<Mutex<UnixStream>> = OnceLock::new();
pub fn init() {
if let Ok(stream) = UnixStream::connect(SOCKET_PATH) {
log::info!("Packet capture: connected to {}", SOCKET_PATH);
let _ = CAPTURE_SOCKET.set(Mutex::new(stream));
crazyradio::capture::set_callback(Box::new(|event| {
send_packet(
LINK_TYPE_RADIO,
event.direction,
event.address,
event.channel,
event.serial,
event.data,
);
}));
} else {
log::debug!("Packet capture: not available");
}
}
pub fn is_available() -> bool {
CAPTURE_SOCKET.get().is_some()
}
pub fn send_packet(
link_type: u8,
direction: u8,
address: &[u8],
channel: u8,
serial: &str,
data: &[u8],
) {
let Some(socket) = CAPTURE_SOCKET.get() else { return };
let Ok(mut stream) = socket.lock() else { return };
let timestamp_us = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_micros() as u64)
.unwrap_or(0);
let mut header = [0u8; 41];
header[0] = link_type;
header[1] = direction;
let addr_len = address.len().min(12);
header[2..2 + addr_len].copy_from_slice(&address[..addr_len]);
header[14] = channel;
let serial_bytes = serial.as_bytes();
let serial_len = serial_bytes.len().min(16);
header[15..15 + serial_len].copy_from_slice(&serial_bytes[..serial_len]);
header[31..39].copy_from_slice(×tamp_us.to_le_bytes());
header[39..41].copy_from_slice(&(data.len() as u16).to_le_bytes());
let _ = stream.write_all(&header);
let _ = stream.write_all(data);
}