- 添加 README.md 项目文档 - 更新 .gitignore 排除 JE-Skin/、eskin-finger-sdk/ 及构建产物 - 从 git 跟踪中移除 JE-Skin 和 eskin-finger-sdk Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
97 lines
3.0 KiB
Rust
97 lines
3.0 KiB
Rust
use crate::serial_core::codec::Codec;
|
|
use crate::serial_core::codecs::tactile_a::TactileACodec;
|
|
use crate::serial_core::frame::TactileAFrame;
|
|
use crate::serial_core::utils::elapsed_millis;
|
|
use crossbeam_channel::{Receiver, Sender, TryRecvError};
|
|
use std::io::{Read, Write};
|
|
use std::time::{Duration, Instant};
|
|
|
|
const POLL_INTERVAL_MS: u64 = 10;
|
|
|
|
/// Runs the serial polling loop on the calling (background) thread.
|
|
/// Sends decoded pressure matrix data (Vec<i32>) to the output channel.
|
|
pub fn run_serial_loop(
|
|
port: &mut dyn ReadWrite,
|
|
rows: usize,
|
|
cols: usize,
|
|
cancel_rx: &Receiver<()>,
|
|
sample_tx: &Sender<Vec<i32>>,
|
|
) {
|
|
let session_started_at = Instant::now();
|
|
let mut codec = TactileACodec::new(cols, rows);
|
|
let req_frame = TactileACodec::build_req_frame(cols, rows);
|
|
let mut buffer = [0u8; 1024];
|
|
let mut poll_interval = Duration::from_millis(POLL_INTERVAL_MS);
|
|
|
|
loop {
|
|
// Check cancel
|
|
if cancel_rx.try_recv().is_ok() {
|
|
break;
|
|
}
|
|
|
|
// Send poll request
|
|
if let Ok(req_bytes) = codec.encode(&req_frame) {
|
|
let _ = port.write_all(&req_bytes);
|
|
}
|
|
|
|
// Read response with poll interval
|
|
let deadline = Instant::now() + poll_interval;
|
|
loop {
|
|
if Instant::now() >= deadline {
|
|
break;
|
|
}
|
|
|
|
match port.read(&mut buffer) {
|
|
Ok(n) if n > 0 => {
|
|
if let Ok(frames) = codec.decode(&buffer[..n], session_started_at) {
|
|
for frame in frames {
|
|
if let TactileAFrame::Rep(rep) = frame {
|
|
if let Ok(vals) = TactileACodec::parse_data_frame(&rep.payload) {
|
|
let _ = sample_tx.try_send(vals);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Ok(_) => {
|
|
std::thread::sleep(Duration::from_millis(1));
|
|
}
|
|
Err(ref e) if e.kind() == std::io::ErrorKind::TimedOut => {
|
|
continue;
|
|
}
|
|
Err(e) => {
|
|
eprintln!("[serial] read error: {e}");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Trait abstracting read+write for the serial port
|
|
pub trait ReadWrite: Send {
|
|
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>;
|
|
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()>;
|
|
}
|
|
|
|
/// Wrapper for serialport's Box<dyn SerialPort>
|
|
pub struct SerialPortReadWrite {
|
|
inner: Box<dyn serialport::SerialPort>,
|
|
}
|
|
|
|
impl SerialPortReadWrite {
|
|
pub fn new(port: Box<dyn serialport::SerialPort>) -> Self {
|
|
Self { inner: port }
|
|
}
|
|
}
|
|
|
|
impl ReadWrite for SerialPortReadWrite {
|
|
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
|
self.inner.read(buf)
|
|
}
|
|
|
|
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
|
|
self.inner.write_all(buf)
|
|
}
|
|
}
|