update ignore
This commit is contained in:
@@ -1,25 +1,16 @@
|
||||
// src-tauri/src/commands/calibration.rs
|
||||
use crate::commands::serial::SerialConnectionState;
|
||||
use crate::serial_core::calibration_session::{CalibrationProgress, CalibrationSession};
|
||||
use crate::serial_core::codecs::tactile_a::TactileACsvExporter;
|
||||
use crate::commands::serial::{CalibrationRuntime, SerialConnectionState};
|
||||
use crate::serial_core::calibration_session::{
|
||||
CalibrationProgress, CalibrationSession, SharedCalibrationSession,
|
||||
};
|
||||
use crate::serial_core::error::SerialError;
|
||||
use crate::serial_core::record::{write_csv, CsvExporter};
|
||||
use crate::serial_core::serial::{run_serial_with_calibration, PollMode, TactileAPollRequester};
|
||||
use log::info;
|
||||
use crate::serial_core::serial::run_serial_with_calibration;
|
||||
use serde::Serialize;
|
||||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||
use tauri::{async_runtime::JoinHandle, AppHandle, Manager, State};
|
||||
use std::time::Instant;
|
||||
use tauri::{AppHandle, Manager, State};
|
||||
use tokio_serial::SerialPortBuilderExt;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
const DEFAULT_TACTILE_COLS: usize = 7;
|
||||
const DEFAULT_TACTILE_ROWS: usize = 12;
|
||||
const DEFAULT_TACTILE_POLL_INTERVAL_MS: u64 = 10;
|
||||
const DEFAULT_TACTILE_REPLY_TIMEOUT_MS: u64 = 140;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CalibrationResponse {
|
||||
@@ -28,9 +19,11 @@ pub struct CalibrationResponse {
|
||||
pub progress: Option<CalibrationProgress>,
|
||||
}
|
||||
|
||||
struct CalibrationSessionData {
|
||||
cancel: CancellationToken,
|
||||
task: JoinHandle<()>,
|
||||
fn snapshot_progress(
|
||||
session: &SharedCalibrationSession,
|
||||
) -> Result<CalibrationProgress, SerialError> {
|
||||
let session = session.lock().map_err(|_| SerialError::StateError)?;
|
||||
Ok(session.get_progress())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -39,111 +32,170 @@ pub async fn serial_calibrate_with_coarse(
|
||||
port: String,
|
||||
target_frames: usize,
|
||||
max_rounds: usize,
|
||||
round_interval_ms: u64,
|
||||
state: State<'_, SerialConnectionState>,
|
||||
) -> Result<CalibrationResponse, SerialError> {
|
||||
let port_name = port.trim().to_string();
|
||||
if port_name.is_empty() {
|
||||
if port_name.is_empty() || target_frames == 0 || max_rounds == 0 {
|
||||
return Err(SerialError::InvalidConfig);
|
||||
}
|
||||
|
||||
// 检查是否有活跃的标定会话
|
||||
{
|
||||
let calibration_session = state
|
||||
.calibration_session
|
||||
.lock()
|
||||
.map_err(|_| SerialError::StateError)?;
|
||||
if calibration_session.is_some() {
|
||||
return Err(SerialError::AlreadyConnected);
|
||||
}
|
||||
if state.has_active_serial_session()? || state.has_active_calibration()? {
|
||||
return Err(SerialError::AlreadyConnected);
|
||||
}
|
||||
|
||||
// 创建新的标定会话
|
||||
let mut session = CalibrationSession::new(target_frames, max_rounds);
|
||||
let mut session = CalibrationSession::new(target_frames, max_rounds, round_interval_ms);
|
||||
session.start();
|
||||
let session = Arc::new(Mutex::new(session));
|
||||
let progress = snapshot_progress(&session)?;
|
||||
|
||||
let cancel = CancellationToken::new();
|
||||
let session_started_at = Instant::now();
|
||||
|
||||
let task_cancel = cancel.clone();
|
||||
let task_app = app.clone();
|
||||
// let task_port_name = port_name.clone();
|
||||
let progress = session.get_progress();
|
||||
let session_for_state = session.clone();
|
||||
let task_session = session.clone();
|
||||
let session_started_at = Instant::now();
|
||||
|
||||
let port = tokio_serial::new(&port_name, 921600)
|
||||
.open_native_async()
|
||||
.map_err(|_| SerialError::OpenError)?;
|
||||
|
||||
let _ = tauri::async_runtime::spawn(async move {
|
||||
// 这里调用新的标定处理函数
|
||||
let task = tauri::async_runtime::spawn(async move {
|
||||
if let Err(error) = run_serial_with_calibration(
|
||||
task_app.clone(),
|
||||
port,
|
||||
session_started_at,
|
||||
task_cancel,
|
||||
session,
|
||||
task_session.clone(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
eprintln!("标定任务异常退出: {error}");
|
||||
eprintln!("calibration task exited with error: {error}");
|
||||
}
|
||||
|
||||
{
|
||||
let manager = task_app.state::<SerialConnectionState>();
|
||||
let Ok(mut runtime) = manager.calibration_runtime.lock() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let should_clear = runtime
|
||||
.as_ref()
|
||||
.map(|current: &CalibrationRuntime| Arc::ptr_eq(¤t.session, &task_session))
|
||||
.unwrap_or(false);
|
||||
|
||||
if should_clear {
|
||||
runtime.take();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 保存标定会话状态
|
||||
let mut calibration_session = state
|
||||
.calibration_session
|
||||
let mut runtime = state
|
||||
.calibration_runtime
|
||||
.lock()
|
||||
.map_err(|_| SerialError::StateError)?;
|
||||
*calibration_session = Some(session_for_state);
|
||||
if runtime.is_some() {
|
||||
cancel.cancel();
|
||||
task.abort();
|
||||
return Err(SerialError::AlreadyConnected);
|
||||
}
|
||||
|
||||
*runtime = Some(CalibrationRuntime {
|
||||
session,
|
||||
cancel,
|
||||
task,
|
||||
});
|
||||
|
||||
Ok(CalibrationResponse {
|
||||
success: true,
|
||||
message: "标定已开始".to_string(),
|
||||
message: "calibration started".to_string(),
|
||||
progress: Some(progress),
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn serial_calibrate_stop(
|
||||
state: State<'_, SerialConnectionState>,
|
||||
) -> Result<CalibrationResponse, SerialError> {
|
||||
let runtime = {
|
||||
let mut runtime = state
|
||||
.calibration_runtime
|
||||
.lock()
|
||||
.map_err(|_| SerialError::StateError)?;
|
||||
runtime.take()
|
||||
};
|
||||
|
||||
let Some(CalibrationRuntime {
|
||||
session,
|
||||
cancel,
|
||||
task,
|
||||
}) = runtime
|
||||
else {
|
||||
return Ok(CalibrationResponse {
|
||||
success: false,
|
||||
message: "no active calibration".to_string(),
|
||||
progress: None,
|
||||
});
|
||||
};
|
||||
|
||||
cancel.cancel();
|
||||
let _ = task.await;
|
||||
let progress = snapshot_progress(&session).ok();
|
||||
|
||||
Ok(CalibrationResponse {
|
||||
success: true,
|
||||
message: "calibration stopped".to_string(),
|
||||
progress,
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn serial_calibrate_add_weight(
|
||||
state: State<'_, SerialConnectionState>,
|
||||
) -> Result<CalibrationResponse, SerialError> {
|
||||
let mut calibration_session = state
|
||||
.calibration_session
|
||||
let runtime = state
|
||||
.calibration_runtime
|
||||
.lock()
|
||||
.map_err(|_| SerialError::StateError)?;
|
||||
|
||||
if let Some(session) = calibration_session.as_mut() {
|
||||
match session.weight_added() {
|
||||
Ok(_) => Ok(CalibrationResponse {
|
||||
success: true,
|
||||
message: "配重已添加,继续标定".to_string(),
|
||||
progress: Some(session.get_progress()),
|
||||
}),
|
||||
Err(e) => Err(SerialError::StateError),
|
||||
}
|
||||
} else {
|
||||
Err(SerialError::StateError)
|
||||
}
|
||||
let Some(runtime) = runtime.as_ref() else {
|
||||
return Err(SerialError::StateError);
|
||||
};
|
||||
|
||||
let mut session = runtime
|
||||
.session
|
||||
.lock()
|
||||
.map_err(|_| SerialError::StateError)?;
|
||||
session
|
||||
.weight_added()
|
||||
.map_err(|_| SerialError::StateError)?;
|
||||
|
||||
Ok(CalibrationResponse {
|
||||
success: true,
|
||||
message: "calibration advanced".to_string(),
|
||||
progress: Some(session.get_progress()),
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn serial_calibrate_status(
|
||||
state: State<'_, SerialConnectionState>,
|
||||
) -> Result<CalibrationResponse, SerialError> {
|
||||
let calibration_session = state
|
||||
.calibration_session
|
||||
let runtime = state
|
||||
.calibration_runtime
|
||||
.lock()
|
||||
.map_err(|_| SerialError::StateError)?;
|
||||
|
||||
if let Some(session) = calibration_session.as_ref() {
|
||||
if let Some(runtime) = runtime.as_ref() {
|
||||
let progress = snapshot_progress(&runtime.session)?;
|
||||
Ok(CalibrationResponse {
|
||||
success: true,
|
||||
message: "标定状态".to_string(),
|
||||
progress: Some(session.get_progress()),
|
||||
message: "calibration active".to_string(),
|
||||
progress: Some(progress),
|
||||
})
|
||||
} else {
|
||||
Ok(CalibrationResponse {
|
||||
success: false,
|
||||
message: "没有活跃的标定会话".to_string(),
|
||||
message: "no active calibration".to_string(),
|
||||
progress: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -94,7 +94,9 @@ pub fn file_explorer_list(
|
||||
|
||||
Ok(FileExplorerListResponse {
|
||||
current_path: current_path.display().to_string(),
|
||||
parent_path: current_path.parent().map(|parent| parent.display().to_string()),
|
||||
parent_path: current_path
|
||||
.parent()
|
||||
.map(|parent| parent.display().to_string()),
|
||||
roots: collect_roots(&app),
|
||||
entries,
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::serial_core::calibration_session::CalibrationSession;
|
||||
use crate::serial_core::calibration_session::SharedCalibrationSession;
|
||||
use crate::serial_core::codecs::tactile_a::{
|
||||
export_recording_csv, TactileACodec, TactileACsvImporter, TactileAHandler,
|
||||
};
|
||||
@@ -71,11 +71,32 @@ struct SerialSession {
|
||||
current_record: SharedTactileRecording,
|
||||
}
|
||||
|
||||
pub struct CalibrationRuntime {
|
||||
pub session: SharedCalibrationSession,
|
||||
pub cancel: CancellationToken,
|
||||
pub task: JoinHandle<()>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SerialConnectionState {
|
||||
session: Mutex<Option<SerialSession>>,
|
||||
last_record: Mutex<Option<SharedTactileRecording>>,
|
||||
pub calibration_session: Mutex<Option<CalibrationSession>>,
|
||||
pub calibration_runtime: Mutex<Option<CalibrationRuntime>>,
|
||||
}
|
||||
|
||||
impl SerialConnectionState {
|
||||
pub(crate) fn has_active_serial_session(&self) -> Result<bool, SerialError> {
|
||||
let session = self.session.lock().map_err(|_| SerialError::StateError)?;
|
||||
Ok(session.is_some())
|
||||
}
|
||||
|
||||
pub(crate) fn has_active_calibration(&self) -> Result<bool, SerialError> {
|
||||
let runtime = self
|
||||
.calibration_runtime
|
||||
.lock()
|
||||
.map_err(|_| SerialError::StateError)?;
|
||||
Ok(runtime.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -100,11 +121,8 @@ pub async fn serial_connect(
|
||||
return Err(SerialError::InvalidConfig);
|
||||
}
|
||||
|
||||
{
|
||||
let session = state.session.lock().map_err(|_| SerialError::StateError)?;
|
||||
if session.is_some() {
|
||||
return Err(SerialError::AlreadyConnected);
|
||||
}
|
||||
if state.has_active_serial_session()? || state.has_active_calibration()? {
|
||||
return Err(SerialError::AlreadyConnected);
|
||||
}
|
||||
|
||||
let cancel = CancellationToken::new();
|
||||
|
||||
@@ -26,7 +26,10 @@ pub fn win_toggle_maximize(app: AppHandle) -> Result<(), String> {
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn win_close(app: AppHandle, state: State<'_, SerialConnectionState>) -> Result<(), String> {
|
||||
pub async fn win_close(
|
||||
app: AppHandle,
|
||||
state: State<'_, SerialConnectionState>,
|
||||
) -> Result<(), String> {
|
||||
disconnect_active_session(state.inner())
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
|
||||
Reference in New Issue
Block a user