use std::io::ErrorKind; use std::time::Duration; use std::collections::HashMap; use std::sync::Mutex; use tauri::Manager; use once_cell::sync::Lazy; use crate::animation; #[derive(Default)] pub struct PortMap(Mutex>>); static PORT_MAP: Mutex>>> = Mutex::new(Lazy::new(|| HashMap::new())); static PORT_NAME: Mutex> = Mutex::new(Lazy::new(|| String::from("/dev/ttyUSB0"))); #[derive(Clone, serde::Serialize)] pub struct PayloadPortState { open: bool, } #[tauri::command] pub fn write_serial(input: &str) -> Result<(), String> { let port_name = PORT_NAME.lock().unwrap().to_string(); match PORT_MAP.lock().unwrap().get(&port_name) { Some(port) => { let mut clone = port.try_clone().expect("Failed to clone"); match clone.write(input.as_bytes()) { Ok(_) => { Ok(()) }, Err(err) => Err(err.to_string()), } } None => { Err(String::from("Port is closed")) } } } #[tauri::command] pub fn get_serial_ports() -> Vec { let ports = serialport::available_ports().expect("No ports found"); let mut vec: Vec = Vec::new(); for p in ports { vec.push(p.port_name); } vec } #[tauri::command] pub fn close_port(app_handle: tauri::AppHandle) { let port_name = PORT_NAME.lock().unwrap().to_string(); match PORT_MAP.lock().unwrap().remove(&port_name) { Some(_) => { println!("Port {:?} closed", port_name); app_handle.emit_all("port-state", PayloadPortState { open: false }).unwrap(); }, None => println!("Port {:?} was already closed", port_name), } } #[tauri::command] pub async fn open_port(app_handle: tauri::AppHandle, baud: u32) -> Result<(), String> { let port_name = PORT_NAME.lock().unwrap().to_string(); match serialport::new(&port_name, baud).timeout(Duration::from_millis(10)).open() { Ok(port) => { // port_map.0.lock().unwrap().insert(port_name.to_string(), port.try_clone().expect("Error cloning")); PORT_MAP.lock().unwrap().insert(port_name.clone(), port.try_clone().expect("Error cloning port")); let mut clone = port.try_clone().expect("Failed to clone"); let mut buffer: Vec = vec![0; 1024]; println!("Port {:?} is open", port_name); app_handle.emit_all("port-state", PayloadPortState { open: true }).unwrap(); loop { match clone.read(buffer.as_mut_slice()) { Ok(bytes_read) => { if bytes_read > 0 { let data = &buffer[..bytes_read]; let data = String::from_utf8_lossy(data).to_string(); if !data.trim().is_empty() { println!("{}", data.trim()); if data.trim() == "1" { animation::start(); app_handle.emit_all("button-on", PayloadPortState { open: true }).unwrap(); } } } }, Err(ref e) if e.kind() == ErrorKind::TimedOut => (), Err(e) => return Err(e.to_string()), }; } }, Err(err) => return Err(err.to_string()), } }