update ignore
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use crate::serial_core::calibration_session::*;
|
||||
use crate::serial_core::calibration_session::*;
|
||||
use crate::serial_core::codec::Codec;
|
||||
use crate::serial_core::codecs::tactile_a::TactileACodec;
|
||||
use crate::serial_core::frame::{FrameHandler, TactileAFrame, TestFrame};
|
||||
@@ -164,9 +164,9 @@ impl PollRequester<TactileAFrame> for TactileAPollRequester {
|
||||
|
||||
pub async fn run_serial<C, H, T, F>(
|
||||
app: AppHandle,
|
||||
mut port: SerialStream,
|
||||
mut codec: C,
|
||||
mut handler: H,
|
||||
port: SerialStream,
|
||||
codec: C,
|
||||
handler: H,
|
||||
session_started_at: Instant,
|
||||
recording: Arc<Mutex<Recording<F>>>,
|
||||
cancel: CancellationToken,
|
||||
@@ -294,111 +294,218 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// 在 src-tauri/src/serial_core/serial.rs 中添加
|
||||
// 鍦?src-tauri/src/serial_core/serial.rs 涓坊鍔?
|
||||
pub async fn run_serial_with_calibration(
|
||||
app: AppHandle,
|
||||
mut port: SerialStream,
|
||||
session_started_at: Instant,
|
||||
cancel: CancellationToken,
|
||||
mut calibration_session: CalibrationSession,
|
||||
calibration_session: SharedCalibrationSession,
|
||||
) -> Result<()> {
|
||||
let mut codec = TactileACodec::new(DEFAULT_TACTILE_COLS, DEFAULT_TACTILE_ROWS);
|
||||
let mut handler = TactileAHandler;
|
||||
let mut requester = TactileAPollRequester::new(
|
||||
Duration::from_millis(DEFAULT_TACTILE_POLL_INTERVAL_MS),
|
||||
DEFAULT_TACTILE_COLS,
|
||||
DEFAULT_TACTILE_ROWS,
|
||||
Duration::from_millis(DEFAULT_TACTILE_REPLY_TIMEOUT_MS),
|
||||
);
|
||||
info!("run_serial_with_calibration begin");
|
||||
emit_calibration_status(&app, &calibration_session)?;
|
||||
|
||||
let mut poll_interval = time::interval(Duration::from_millis(DEFAULT_TACTILE_POLL_INTERVAL_MS));
|
||||
poll_interval.set_missed_tick_behavior(MissedTickBehavior::Skip);
|
||||
let run_result = async {
|
||||
let mut codec = TactileACodec::new(DEFAULT_TACTILE_COLS, DEFAULT_TACTILE_ROWS);
|
||||
let mut handler = TactileAHandler;
|
||||
let mut requester = TactileAPollRequester::new(
|
||||
Duration::from_millis(DEFAULT_TACTILE_POLL_INTERVAL_MS),
|
||||
DEFAULT_TACTILE_COLS,
|
||||
DEFAULT_TACTILE_ROWS,
|
||||
Duration::from_millis(DEFAULT_TACTILE_REPLY_TIMEOUT_MS),
|
||||
);
|
||||
|
||||
let mut buffer = [0u8; 1024];
|
||||
let recording = Arc::new(Mutex::new(Recording::new()));
|
||||
let mut chart_state = HudChartState::new();
|
||||
let mut prune_interval = time::interval(Duration::from_millis(450));
|
||||
prune_interval.set_missed_tick_behavior(MissedTickBehavior::Delay);
|
||||
let mut poll_interval =
|
||||
time::interval(Duration::from_millis(DEFAULT_TACTILE_POLL_INTERVAL_MS));
|
||||
poll_interval.set_missed_tick_behavior(MissedTickBehavior::Skip);
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = cancel.cancelled() => break,
|
||||
_ = poll_interval.tick() => {
|
||||
if requester.should_request() {
|
||||
if let Some(req) = requester.next_request()? {
|
||||
let bytes = codec.encode(&req)?;
|
||||
port.write_all(&bytes).await?;
|
||||
let mut buffer = [0u8; 1024];
|
||||
let recording = Arc::new(Mutex::new(Recording::new()));
|
||||
let mut chart_state = HudChartState::new();
|
||||
let mut prune_interval = time::interval(Duration::from_millis(450));
|
||||
prune_interval.set_missed_tick_behavior(MissedTickBehavior::Delay);
|
||||
let mut next_round_at: Option<Instant> = None;
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = cancel.cancelled() => break,
|
||||
_ = poll_interval.tick() => {
|
||||
if let Some(deadline) = next_round_at {
|
||||
if Instant::now() >= deadline {
|
||||
next_round_at = None;
|
||||
begin_next_calibration_round(&app, &calibration_session)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = prune_interval.tick() => {
|
||||
if let Some(packet) = chart_state.prune_stale() {
|
||||
app.emit("hud_stream", packet)?;
|
||||
}
|
||||
}
|
||||
read_result = port.read(&mut buffer) => {
|
||||
let n = read_result?;
|
||||
if n == 0 {
|
||||
tokio::task::yield_now().await;
|
||||
continue;
|
||||
}
|
||||
|
||||
let frames = codec.decode(&buffer[..n], session_started_at)?;
|
||||
for frame in frames {
|
||||
requester.on_rx_frame(&frame);
|
||||
|
||||
let decode_res = handler
|
||||
.on_frame(&frame)
|
||||
.await?
|
||||
.map(|vals| vals.into_iter().map(Into::into).collect::<Vec<i32>>());
|
||||
|
||||
let recorded_frame = RecordedFrame {
|
||||
timing: FrameTiming { pts_ms: None, dts_ms: frame.dts_ms() },
|
||||
frame: frame.clone(),
|
||||
};
|
||||
|
||||
if calibration_is_collecting(&calibration_session)?
|
||||
&& requester.should_request()
|
||||
{
|
||||
let mut record = recording
|
||||
.lock()
|
||||
.map_err(|_| anyhow::anyhow!("recording state poisoned"))?;
|
||||
record.push(recorded_frame.clone());
|
||||
if let Some(req) = requester.next_request()? {
|
||||
let bytes = codec.encode(&req)?;
|
||||
port.write_all(&bytes).await?;
|
||||
}
|
||||
}
|
||||
|
||||
let display_values = if let Some(vals) = decode_res.as_ref() {
|
||||
let summary = vals.iter().copied().sum::<i32>();
|
||||
chart_state.record_summary(summary as f32);
|
||||
chart_state.record_pressure_matrix(vals.as_slice());
|
||||
Some(vec![summary])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(packet) = frame.to_hud_packet(&mut chart_state, display_values.as_deref()) {
|
||||
}
|
||||
_ = prune_interval.tick() => {
|
||||
if let Some(packet) = chart_state.prune_stale() {
|
||||
app.emit("hud_stream", packet)?;
|
||||
}
|
||||
}
|
||||
read_result = port.read(&mut buffer) => {
|
||||
let n = read_result?;
|
||||
if n == 0 {
|
||||
tokio::task::yield_now().await;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查是否达到目标帧数
|
||||
let should_export = calibration_session.add_frame(recorded_frame);
|
||||
let frames = codec.decode(&buffer[..n], session_started_at)?;
|
||||
for frame in frames {
|
||||
requester.on_rx_frame(&frame);
|
||||
|
||||
if should_export {
|
||||
// 导出数据
|
||||
export_calibration_data(&app, &calibration_session, &recording).await?;
|
||||
let decode_res = handler
|
||||
.on_frame(&frame)
|
||||
.await?
|
||||
.map(|vals| vals.into_iter().map(Into::into).collect::<Vec<i32>>());
|
||||
|
||||
// 发送语音提示(这里用事件代替,前端可以播放语音)
|
||||
app.emit("calibration_voice_prompt", "请添加配重")?;
|
||||
let display_values = if let Some(vals) = decode_res.as_ref() {
|
||||
let summary = vals.iter().copied().sum::<i32>();
|
||||
let val_summary = summary - vals[vals.len() - 1];
|
||||
if val_summary < 8400 {
|
||||
continue;
|
||||
}
|
||||
chart_state.record_summary(summary as f32);
|
||||
chart_state.record_pressure_matrix(vals.as_slice());
|
||||
Some(vec![summary])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// 更新状态
|
||||
calibration_session.export_completed();
|
||||
let recorded_frame = RecordedFrame {
|
||||
timing: FrameTiming { pts_ms: None, dts_ms: frame.dts_ms() },
|
||||
frame: frame.clone(),
|
||||
};
|
||||
|
||||
if let Ok(mut record) = recording.lock() {
|
||||
record.frames.clear();
|
||||
{
|
||||
let mut record = recording
|
||||
.lock()
|
||||
.map_err(|_| anyhow::anyhow!("recording state poisoned"))?;
|
||||
record.push(recorded_frame.clone());
|
||||
}
|
||||
|
||||
if let Some(packet) = frame.to_hud_packet(&mut chart_state, display_values.as_deref()) {
|
||||
app.emit("hud_stream", packet)?;
|
||||
}
|
||||
|
||||
let should_export = {
|
||||
let mut session = calibration_session
|
||||
.lock()
|
||||
.map_err(|_| anyhow::anyhow!("calibration session poisoned"))?;
|
||||
session.add_frame(recorded_frame)
|
||||
};
|
||||
|
||||
if should_export {
|
||||
let current_round = {
|
||||
let session = calibration_session
|
||||
.lock()
|
||||
.map_err(|_| anyhow::anyhow!("calibration session poisoned"))?;
|
||||
session.current_round
|
||||
};
|
||||
|
||||
export_calibration_data(&app, current_round, &recording).await?;
|
||||
|
||||
let (progress, round_interval_ms) = {
|
||||
let mut session = calibration_session
|
||||
.lock()
|
||||
.map_err(|_| anyhow::anyhow!("calibration session poisoned"))?;
|
||||
session.export_completed();
|
||||
(session.get_progress(), session.round_interval_ms)
|
||||
};
|
||||
app.emit("calibration_status", progress.clone())?;
|
||||
|
||||
if let Ok(mut record) = recording.lock() {
|
||||
record.frames.clear();
|
||||
}
|
||||
|
||||
if progress.state == CalibrationState::Completed {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if round_interval_ms == 0 {
|
||||
begin_next_calibration_round(&app, &calibration_session)?;
|
||||
} else {
|
||||
next_round_at =
|
||||
Some(Instant::now() + Duration::from_millis(round_interval_ms));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
.await;
|
||||
|
||||
if cancel.is_cancelled() {
|
||||
stop_calibration_session(&app, &calibration_session)?;
|
||||
}
|
||||
|
||||
run_result
|
||||
}
|
||||
|
||||
fn calibration_is_collecting(calibration_session: &SharedCalibrationSession) -> Result<bool> {
|
||||
let session = calibration_session
|
||||
.lock()
|
||||
.map_err(|_| anyhow::anyhow!("calibration session poisoned"))?;
|
||||
Ok(session.state == CalibrationState::CollectingData)
|
||||
}
|
||||
|
||||
fn begin_next_calibration_round(
|
||||
app: &AppHandle,
|
||||
calibration_session: &SharedCalibrationSession,
|
||||
) -> Result<()> {
|
||||
{
|
||||
let mut session = calibration_session
|
||||
.lock()
|
||||
.map_err(|_| anyhow::anyhow!("calibration session poisoned"))?;
|
||||
if session.state == CalibrationState::WaitingForNextRound {
|
||||
session
|
||||
.begin_next_round()
|
||||
.map_err(|error| anyhow::anyhow!(error))?;
|
||||
}
|
||||
}
|
||||
|
||||
emit_calibration_status(app, calibration_session)
|
||||
}
|
||||
|
||||
fn stop_calibration_session(
|
||||
app: &AppHandle,
|
||||
calibration_session: &SharedCalibrationSession,
|
||||
) -> Result<()> {
|
||||
{
|
||||
let mut session = calibration_session
|
||||
.lock()
|
||||
.map_err(|_| anyhow::anyhow!("calibration session poisoned"))?;
|
||||
if session.state != CalibrationState::Completed {
|
||||
session.stop();
|
||||
}
|
||||
}
|
||||
|
||||
emit_calibration_status(app, calibration_session)
|
||||
}
|
||||
|
||||
fn emit_calibration_status(
|
||||
app: &AppHandle,
|
||||
calibration_session: &SharedCalibrationSession,
|
||||
) -> Result<()> {
|
||||
let progress = {
|
||||
let session = calibration_session
|
||||
.lock()
|
||||
.map_err(|_| anyhow::anyhow!("calibration session poisoned"))?;
|
||||
session.get_progress()
|
||||
};
|
||||
|
||||
app.emit("calibration_status", progress)?;
|
||||
Ok(())
|
||||
}
|
||||
use crate::serial_core::codecs::tactile_a::TactileACsvExporter;
|
||||
@@ -407,7 +514,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use tauri::Manager;
|
||||
async fn export_calibration_data(
|
||||
app: &AppHandle,
|
||||
calibration_session: &CalibrationSession,
|
||||
current_round: usize,
|
||||
recording: &Arc<Mutex<Recording<TactileAFrame>>>,
|
||||
) -> Result<()> {
|
||||
let timestamp = SystemTime::now()
|
||||
@@ -415,12 +522,8 @@ async fn export_calibration_data(
|
||||
.map(|duration| duration.as_millis())
|
||||
.unwrap_or_default();
|
||||
|
||||
let filename = format!(
|
||||
"calibration_round{}_{}.csv",
|
||||
calibration_session.current_round, timestamp
|
||||
);
|
||||
let filename = format!("calibration_round{}_{}.csv", current_round, timestamp);
|
||||
|
||||
// 创建导出目录
|
||||
let mut output_dir = match app.path().desktop_dir() {
|
||||
Ok(path) => path,
|
||||
Err(_) => std::env::current_dir()?,
|
||||
@@ -431,7 +534,6 @@ async fn export_calibration_data(
|
||||
let output_path = output_dir.join(&filename);
|
||||
let file = File::create(&output_path)?;
|
||||
|
||||
// 使用现有的导出逻辑
|
||||
let recording_lock = recording
|
||||
.lock()
|
||||
.map_err(|_| anyhow::anyhow!("Recording poisoned"))?;
|
||||
@@ -442,6 +544,5 @@ async fn export_calibration_data(
|
||||
|
||||
write_csv(&recording_lock, &exporter, file)?;
|
||||
|
||||
info!("标定数据已导出到: {}", output_path.display());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user