use std::{io::{BufRead, BufReader, BufWriter, Read, Write}, net::TcpListener, sync::{Arc, Mutex}, thread::sleep, time::Duration}; use common::{Command, Telemetry}; use postcard::to_vec_cobs; use heapless::Vec; fn main() { let mut port = serialport::new("/dev/ttyACM0", 115200) .timeout(Duration::from_secs(1000)) .open().expect("port missing"); println!("connected over serial"); let command: Arc> = Arc::new(Mutex::new(Command { left: 0.0, right: 0.0, ultrasonic_enable: true})); let telemetry: Arc> = Arc::new(Mutex::new(Telemetry { distance: f32::NAN })); // LabVIEW communication thread { let command = command.clone(); let telemetry = telemetry.clone(); std::thread::spawn(move || server(command,telemetry)); } // Telemetry receive thread { let reader = port.try_clone().unwrap(); let reader = BufReader::new(reader); let telemetry = telemetry.clone(); std::thread::spawn(move || recv_telem(telemetry, reader)); } // Command transmit thread (main) loop { let command = command.lock().unwrap().clone(); let encoded: Vec = to_vec_cobs(&command).unwrap(); if port.write(&encoded).is_err() { println!("disconnected from robot"); return; }; sleep(Duration::from_millis(200)); } } fn recv_telem(telemetry: Arc>, mut reader: BufReader) { let mut recv_buf = std::vec::Vec::new(); loop { let Ok(len) = reader.read_until(0, &mut recv_buf) else {continue;}; if let Ok(telem) = postcard::from_bytes_cobs::(&mut recv_buf[0..len]) { *telemetry.lock().unwrap() = telem; } recv_buf.clear(); } } fn server(command: Arc>, telemetry: Arc>) { let listener = TcpListener::bind("0.0.0.0:4242").unwrap(); while let Ok((stream, _)) = listener.accept() { println!("connected over IP"); let command1 = command.clone(); let telemetry1 = telemetry.clone(); std::thread::spawn(move || { if let Err(e) = handle_connection(command1, telemetry1, stream) { println!("IP connection dropped: {}", e); } }); } } fn handle_connection(command: Arc>, telemetry: Arc>, stream: std::net::TcpStream) -> anyhow::Result<()> { let writer = stream.try_clone().unwrap(); let mut writer = BufWriter::new(writer); let mut reader = BufReader::new(stream); loop { let mut data_buf = std::vec::Vec::new(); let len = reader.read_until(b'\n', &mut data_buf)?; // eof if len == 0 { *command.lock().unwrap() = Command::default(); // stop motors println!("disconnected from LabVIEW"); return anyhow::Ok(()); } let Ok(new_command) = serde_json::from_slice::(&data_buf[0..len]) else {continue;}; *command.lock().unwrap() = new_command.clone(); println!("received l{} r{}", new_command.left, new_command.right); let mut telem = telemetry.lock().unwrap().clone(); if telem.distance.is_nan() { telem.distance = -1.0; } println!("sent d{}", telem.distance); serde_json::to_writer(&mut writer, &telem).unwrap(); writer.write_all(b"\r\n")?; writer.flush()?; } }