feat:增加点和数字切换,减小点最大尺寸,增加range配色方案

This commit is contained in:
lenn
2026-04-09 09:17:07 +08:00
parent 1c3a811154
commit a3cefc3c79
78 changed files with 786 additions and 296 deletions

View File

@@ -77,6 +77,40 @@ pub struct SerialConnectionState {
last_record: Mutex<Option<SharedTactileRecording>>
}
pub async fn shutdown_active_session(
state: &SerialConnectionState,
) -> Result<Option<(String, SharedTactileRecording)>, SerialError> {
let session = {
let mut guard = state.session.lock().map_err(|_| SerialError::StateError)?;
guard.take()
};
let Some(SerialSession {
port,
cancel,
task,
current_record,
}) = session else {
return Ok(None);
};
cancel.cancel();
let _ = task.await;
let frame_count = current_record
.lock()
.map(|record| record.frames.len())
.unwrap_or(0);
info!("last_record has {} frames", frame_count);
if let Ok(mut last_record) = state.last_record.lock() {
*last_record = Some(current_record.clone());
}
Ok(Some((port, current_record)))
}
#[tauri::command]
pub fn serial_enum() -> Result<Vec<String>, SerialError> {
let ports = available_ports()
@@ -190,17 +224,7 @@ pub async fn serial_connect(
pub async fn serial_disconnect(
state: State<'_, SerialConnectionState>,
) -> Result<SerialConnectResponse, SerialError> {
let session = {
let mut guard = state.session.lock().map_err(|_| SerialError::StateError)?;
guard.take()
};
let Some(SerialSession {
port,
cancel,
task,
current_record,
}) = session
let Some((port, _current_record)) = shutdown_active_session(&state).await?
else {
return Ok(SerialConnectResponse {
port: String::new(),
@@ -209,19 +233,6 @@ pub async fn serial_disconnect(
});
};
cancel.cancel();
let _ = task.await;
let frame_count = current_record.lock().map(|record| {
record.frames.len()
}).unwrap_or(0);
info!("last_record has {} frames", frame_count);
if let Ok(mut last_record) = state.last_record.lock() {
*last_record = Some(current_record);
}
Ok(SerialConnectResponse {
port,
connected: false,

View File

@@ -1,4 +1,6 @@
use tauri::{AppHandle, Manager, WebviewWindow};
use super::serial::SerialConnectionState;
use crate::commands::serial::shutdown_active_session;
use tauri::{AppHandle, Manager, State, WebviewWindow};
fn main_window(app: &AppHandle) -> Result<WebviewWindow, String> {
app.get_webview_window("main")
@@ -25,8 +27,14 @@ pub fn win_toggle_maximize(app: AppHandle) -> Result<(), String> {
}
#[tauri::command]
pub fn win_close(app: AppHandle) -> Result<(), String> {
main_window(&app)?
.close()
.map_err(|error| error.to_string())
pub async fn win_close(
app: AppHandle,
state: State<'_, SerialConnectionState>,
) -> Result<(), String> {
shutdown_active_session(&state)
.await
.map_err(|error| error.to_string())?;
app.exit(0);
Ok(())
}

View File

@@ -1,6 +1,6 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use log::{debug, error, info, trace, warn};
use log::debug;
use tauri_demo_lib::log::setup_logger;
fn main() {

View File

@@ -18,7 +18,6 @@ const FRAME_BUFFER_MIN_LENGTH: usize = 15;
pub struct TactileACodec {
buffer: Vec<u8>,
frame_nb: u64,
expected_data_len: usize,
}
@@ -65,7 +64,6 @@ impl TactileACodec {
pub fn new(cols: usize, rows: usize) -> TactileACodec {
Self {
buffer: Vec::new(),
frame_nb: 0,
expected_data_len: cols * rows * 2,
}
}
@@ -77,7 +75,14 @@ impl TactileACodec {
let vals: Vec<i32> = data
.chunks_exact(2)
.map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]) as i32)
.map(|chunk| {
let raw = u16::from_le_bytes([chunk[0], chunk[1]]) as i32;
if raw < 15 {
0
} else {
raw
}
})
.collect::<Vec<i32>>();
Ok(vals)
@@ -236,7 +241,6 @@ impl FrameHandler<TactileAFrame, i32> for TactileAHandler {
match frame {
TactileAFrame::Rep(rep) => {
let vals = TactileACodec::parse_data_frame(&rep.payload)?;
debug!("vals is {:?}", vals);
Ok(Some(vals))
}
_ => Ok(None),
@@ -252,7 +256,7 @@ impl TactileACsvExporter {
impl CsvExporter<TactileARepFrame> for TactileACsvExporter {
type Error = CodecError;
fn csv_header(&self, recording: &Recording<TactileARepFrame>) -> Vec<String> {
fn csv_header(&self, _recording: &Recording<TactileARepFrame>) -> Vec<String> {
let mut header: Vec<String> = Vec::new();
for i in 0..self.channels {
header.push(format!("channel{}", i + 1));

View File

@@ -12,7 +12,6 @@ use tokio_util::sync::CancellationToken;
use std::future::pending;
use std::sync::{Arc, Mutex};
use std::time::Instant;
use log::{info, debug};
use crate::serial_core::record::{FrameTiming, RecordedFrame};
pub enum PollMode<F> {
@@ -158,9 +157,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,
@@ -265,7 +264,8 @@ where
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);
let force = raw_to_g1(summary as u32);
chart_state.record_summary(force as f32);
chart_state.record_pressure_matrix(vals.as_slice());
Some(vec![summary])
} else {
@@ -281,3 +281,36 @@ where
}
Ok(())
}
fn raw_to_g1(raw: u32) -> f64 {
const X: [u32; 11] = [
0, 74602, 105503, 131459, 153512, 172041, 193794, 218947, 240580, 295118, 332346,
];
const Y: [f64; 11] = [
0.0, 160.0, 260.0, 360.0, 460.0, 560.0, 660.0, 860.0, 1060.0, 1560.0, 2060.0,
];
let n = X.len();
if raw <= X[0] {
return Y[0] / 100.0;
}
if raw >= X[n - 1] {
return Y[n - 1] / 100.0;
}
let mut left = 0;
let mut right = n - 1;
while left + 1 < right {
let mid = (left + right) / 2;
if raw < X[mid] {
right = mid;
} else {
left = mid;
}
}
let ratio = (raw - X[left]) as f64 / (X[right] - X[left]) as f64;
Y[left] / 100.0 + ratio * (Y[right] - Y[left]) / 100.0
}