Files
eskin-player/src/serial_core/serial.rs
lennlouisgeek 5f1c217853 feat: 添加 README,更新 .gitignore,移除 JE-Skin/eskin-finger-sdk
- 添加 README.md 项目文档
- 更新 .gitignore 排除 JE-Skin/、eskin-finger-sdk/ 及构建产物
- 从 git 跟踪中移除 JE-Skin 和 eskin-finger-sdk

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 03:15:16 +08:00

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)
}
}