use std::io::{Write, ErrorKind};
|
use tauri::Emitter;
|
use std::time::Duration;
|
use serialport::{self, SerialPort};
|
|
use once_cell::sync::Lazy;
|
use tokio::sync::{Mutex, broadcast};
|
|
|
// 用于发送停止信号的通道
|
static STOP_SIGNAL_SENDER: Lazy<Mutex<Option<broadcast::Sender<()>>>> = Lazy::new(|| Mutex::new(None));
|
|
// 使用Lazy和Mutex来安全地共享串口实例
|
static SERIAL_PORT: Lazy<Mutex<Option<Box<dyn SerialPort>>>> = Lazy::new(|| Mutex::new(None));
|
|
#[tauri::command]
|
pub async fn open_serial_port(app_handle: tauri::AppHandle, port_name: String, baud_rate: u32) -> Result<String, String> {
|
// 输出 串口名称
|
println!("打开串口: {}", port_name);
|
// 输出 波特率
|
println!("波特率: {}", baud_rate);
|
let mut serial_port_guard = SERIAL_PORT.lock().await;
|
if serial_port_guard.is_some() {
|
return Err("串口已打开".into());
|
}
|
|
match serialport::new(&port_name, baud_rate)
|
.timeout(Duration::from_millis(10))
|
.open()
|
{
|
Ok(port) => {
|
*serial_port_guard = Some(port);
|
|
// 创建停止信号通道
|
let (tx, _rx) = broadcast::channel(1);
|
*STOP_SIGNAL_SENDER.lock().await = Some(tx.clone());
|
|
let app_handle_clone = app_handle.clone();
|
let mut rx_stop = tx.subscribe();
|
|
tokio::spawn(async move {
|
let mut buffer: Vec<u8> = vec![0; 1024];
|
let mut data_buffer: Vec<u8> = Vec::new(); // Buffer to accumulate incoming data
|
loop {
|
tokio::select! {
|
_ = rx_stop.recv() => {
|
println!("停止串口数据读取任务");
|
break;
|
}
|
_ = tokio::time::sleep(Duration::from_millis(100)) => {
|
// 定期尝试读取,避免长时间阻塞
|
let mut serial_port_guard = SERIAL_PORT.lock().await;
|
if let Some(port) = serial_port_guard.as_mut() {
|
match port.read(buffer.as_mut_slice()) {
|
Ok(bytes_read) => {
|
if bytes_read > 0 {
|
data_buffer.extend_from_slice(&buffer[..bytes_read]);
|
|
// Process data_buffer to extract complete 22-byte packets
|
while data_buffer.len() >= 22 {
|
let data = data_buffer.drain(..22).collect::<Vec<u8>>();
|
if let Err(e) = app_handle_clone.emit("serial_data", data) {
|
eprintln!("发射事件失败: {}", e);
|
}
|
}
|
}
|
}
|
Err(ref e) if e.kind() == ErrorKind::TimedOut => { /* 超时,继续 */ }
|
Err(e) => {
|
eprintln!("读取串口数据失败: {}", e);
|
break; // 读取失败,退出循环
|
}
|
}
|
} else {
|
eprintln!("串口未打开,停止读取任务");
|
break;
|
}
|
}
|
}
|
}
|
});
|
let log_message = format!("成功打开串口: {}", port_name);
|
crate::log_data(app_handle, log_message.clone()).map_err(|e| e.to_string())?;
|
Ok(log_message)
|
}
|
Err(e) => Err(format!("打开串口失败: {}", e)),
|
}
|
}
|
|
#[tauri::command]
|
pub async fn close_serial_port() -> Result<String, String> {
|
let mut serial_port_guard = SERIAL_PORT.lock().await;
|
if serial_port_guard.is_none() {
|
return Err("串口未打开".into());
|
}
|
|
// 发送停止信号
|
if let Some(tx) = STOP_SIGNAL_SENDER.lock().await.take() {
|
if let Err(e) = tx.send(()) {
|
eprintln!("发送停止信号失败: {}", e);
|
}
|
}
|
|
*serial_port_guard = None;
|
Ok("串口已关闭".into())
|
}
|
|
// 移除 read_serial_data 命令,因为读取逻辑已集成到 open_serial_port 中
|
// #[tauri::command]
|
// pub async fn read_serial_data(app_handle: tauri::AppHandle) -> Result<Vec<u8>, String> {
|
// let mut serial_port_guard = SERIAL_PORT.lock().await;
|
// if let Some(port) = serial_port_guard.as_mut() {
|
// let mut buffer: Vec<u8> = vec![0; 128]; // 假设每次最多读取128字节
|
// match port.read(buffer.as_mut_slice()) {
|
// Ok(bytes_read) => {
|
// let data = buffer[..bytes_read].to_vec();
|
// // 可以在这里发射事件到前端,如果需要实时显示
|
// // app_handle.emit_all("serial_data", &data).unwrap();
|
// Ok(data)
|
// }
|
// Err(ref e) if e.kind() == ErrorKind::TimedOut => Ok(vec![]), // 超时不是错误
|
// Err(e) => Err(format!("读取串口数据失败: {}", e)),
|
// }
|
// } else {
|
// Err("串口未打开".into())
|
// }
|
// }
|
|
#[tauri::command]
|
pub async fn write_serial_data(data: Vec<u8>) -> Result<usize, String> {
|
let mut serial_port_guard = SERIAL_PORT.lock().await;
|
if let Some(port) = serial_port_guard.as_mut() {
|
match port.write_all(&data) {
|
Ok(_) => Ok(data.len()),
|
Err(e) => Err(format!("写入串口数据失败: {}", e)),
|
}
|
} else {
|
Err("串口未打开".into())
|
}
|
}
|
|
#[tauri::command]
|
pub fn list_serial_ports() -> Result<Vec<String>, String> {
|
match serialport::available_ports() {
|
Ok(ports) => {
|
let port_names = ports.into_iter().map(|p| p.port_name).collect();
|
Ok(port_names)
|
}
|
Err(e) => Err(format!("列出串口失败: {}", e)),
|
}
|
}
|