From f984f330e897d86d33b3b7c71fc06db1eba2f015 Mon Sep 17 00:00:00 2001 From: lenn Date: Wed, 6 May 2026 17:16:51 +0800 Subject: [PATCH] fix: protocol frame parsing, add debug feature, refactor read logic --- Cargo.toml | 4 ++++ src/config.rs | 2 +- src/device.rs | 26 ++++++++++++++++++----- src/lib.rs | 13 ++++++++++++ src/main.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++---- src/protocol.rs | 38 ++++++++++++++++++---------------- src/stream.rs | 16 +++++++++++--- 7 files changed, 123 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7a9fb91..72e6c4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,10 @@ edition = "2024" name = "eskin_finger_sdk" crate-type = ["lib", "cdylib", "staticlib"] +[features] +default = [] +debug = [] + [dependencies] chrono = "0.4.44" crc = "3.4.0" diff --git a/src/config.rs b/src/config.rs index 6596976..4a034bc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,7 +23,7 @@ impl Default for DeviceConfig { sample_capacity: 1024, command_capacity: 64, event_capacity: 128, - read_timeout_ms: 100, + read_timeout_ms: 1000, } } } diff --git a/src/device.rs b/src/device.rs index 9b43bce..7a04f5e 100644 --- a/src/device.rs +++ b/src/device.rs @@ -6,7 +6,7 @@ use crate::{ config::{DeviceConfig, DeviceInfo}, error::SdkError, protocol::{ - EskinProtocolCodec, FRAME_CRC_LEN, FRAME_START_RESPONSE, FRAME_STATUS_LEN, ProtocolCodec, + EskinProtocolCodec, FRAME_START_RESPONSE, ProtocolCodec, ReadRequest, WriteRequest, }, stream::StreamRuntime, @@ -73,9 +73,19 @@ impl EskinDeviceInner { buf: &mut [u8], timeout: Duration, ) -> Result<(), SdkError> { + let deadline = std::time::Instant::now() + + timeout + .to_std() + .map_err(|_| SdkError::InvalidParameter("timeout must be non-negative".into()))?; + let mut offset = 0; while offset < buf.len() { - let n = transport.read(&mut buf[offset..], timeout)?; + let remaining = deadline + .checked_duration_since(std::time::Instant::now()) + .unwrap_or(std::time::Duration::from_millis(1)); + debug_println!("[device] read_exact: need {} bytes, have {} so far, remaining timeout: {:?}", buf.len() - offset, offset, remaining); + let n = transport.read(&mut buf[offset..], Duration::from_std(remaining).unwrap())?; + debug_println!("[device] read_exact: got {} bytes: {:02X?}", n, &buf[offset..offset + n]); if n == 0 { return Err(SdkError::Timeout); @@ -94,19 +104,25 @@ impl EskinDeviceInner { let timeout = Duration::milliseconds(self.config.read_timeout_ms as i64); let mut header = [0u8; 4]; Self::read_exact_from_transport(transport, &mut header, timeout)?; + debug_println!("[device] recv header: {:02X?}", header); - let start = u16::from_be_bytes([header[0], header[1]]); + // let start = u16::from_be_bytes([header[0], header[1]]); + let start = [header[0], header[1]]; if start != FRAME_START_RESPONSE { return Err(SdkError::FrameError(format!( - "invalid response start: 0x{start:04X}" + "invalid response start: 0x{start:02X?}" ))); } + debug_println!("h2: {:02X}, h3: {:02X}", header[2], header[3]); let data_len = u16::from_le_bytes([header[2], header[3]]) as usize; - let total_len = 4 + data_len + FRAME_STATUS_LEN + FRAME_CRC_LEN; + debug_println!("data_len: {data_len}"); + let total_len = 5 + data_len; + // let total_len = data_len + 1; let mut frame = vec![0u8; total_len]; frame[..4].copy_from_slice(&header); Self::read_exact_from_transport(transport, &mut frame[4..], timeout)?; + debug_println!("[device] recv frame: {:02X?}", frame); Ok(frame) } diff --git a/src/lib.rs b/src/lib.rs index 290f76e..3907a35 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,16 @@ +/// Debug-only print macro. Only outputs when compiled with `--features debug`. +#[cfg(feature = "debug")] +#[macro_export] +macro_rules! debug_println { + ($($arg:tt)*) => { println!($($arg)*) }; +} + +#[cfg(not(feature = "debug"))] +#[macro_export] +macro_rules! debug_println { + ($($arg:tt)*) => {}; +} + pub mod channel; pub mod config; pub mod device; diff --git a/src/main.rs b/src/main.rs index f465a71..a580f75 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,60 @@ use eskin_finger_sdk::{config::DeviceConfig, device::{EskinDevice, EskinDeviceInner}, transport::SerialPortTransport}; - fn main() { - let transport = SerialPortTransport::new("/dev/ttyUSB0", 921600); + let transport = SerialPortTransport::new("COM10", 921600); let config = DeviceConfig::default(); let mut device = EskinDeviceInner::new(config, Box::new(transport)); device.open().unwrap(); - let data = device.read_register(0x1C00, 168).unwrap(); - println!("Serial: {:?}", data); + // let data = device.read_register(0x1C00, 168).unwrap(); + // print_payload_data(&data); + + read_hdv(&mut device); + read_check_group(&mut device); + read_row(&mut device); + write_col(&mut device, &[0x08]); + read_col(&mut device); + read_config(&mut device); device.close().unwrap(); } + +fn read_hdv(device: &mut EskinDeviceInner) { + let series_id = device.read_register(0, 2).unwrap(); + print_payload_data(&series_id); +} + +fn read_check_group(device: &mut EskinDeviceInner) { + let group = device.read_register(0x000F, 1).unwrap(); + print_payload_data(&group); +} + + +fn read_row(device: &mut EskinDeviceInner) { + let row = device.read_register(0x0015, 1).unwrap(); + print_payload_data(&row); +} + +fn write_col(device: &mut EskinDeviceInner, col: &[u8]) { + device.write_register(0x0014, col).unwrap(); +} + +fn read_col(device: &mut EskinDeviceInner) { + let col = device.read_register(0x0014, 1).unwrap(); + print_payload_data(&col); +} + +fn read_config(device: &mut EskinDeviceInner) { + let conf = device.read_register(0x0017, 1).unwrap(); + print_payload_data(&conf); +} + +fn print_payload_data(data: &[u8]) { + for (i, chunk) in data.chunks(2).enumerate() { + if chunk.len() == 2 { + let val = u16::from_le_bytes([chunk[0], chunk[1]]); + println!(" [{:3}] [{:02X}] [{:02X}] => {}", i, chunk[0], chunk[1], val); + } else { + println!(" [{:3}] [{:02X}] (odd byte)", i, chunk[0]); + } + } +} diff --git a/src/protocol.rs b/src/protocol.rs index b752fec..14a8eb6 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -3,11 +3,11 @@ use serde::{Deserialize, Serialize}; use crate::error::SdkError; pub const FRAME_START_REQUEST: [u8; 2] = [0x55, 0xAA]; -pub const FRAME_START_RESPONSE: u16 = 0xAA55; +pub const FRAME_START_RESPONSE: [u8; 2] = [0xAA, 0x55]; pub const FUNC_READ: u8 = 0xFB; pub const FUNC_WRITE: u8 = 0x79; -pub const FUNC_RESPONSE_READ: u8 = 0xFF; +pub const FUNC_RESPONSE_READ: u8 = 0xFB; pub const FUNC_RESPONSE_WRITE: u8 = 0xF9; pub const FRAME_HEADER_LEN: usize = 13; @@ -45,7 +45,7 @@ pub enum FrameFunction { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ProtocolFrame { - pub start: u16, + pub start: [u8; 2], pub device_addr: u8, pub function: u8, pub start_addr: u32, @@ -154,7 +154,7 @@ impl ProtocolCodec for EskinProtocolCodec { let crc = self.crc8(&frame); frame.push(crc); - println!("send: {:02X?}", frame); + debug_println!("send: {:02X?}", frame); Ok(frame) } @@ -197,15 +197,17 @@ impl ProtocolCodec for EskinProtocolCodec { return Err(SdkError::FrameError("read response too short".into())); } - let start = Self::read_u16_le(frame, 0)?; + // let start = Self::read_u16_le(frame, 0)?; + let start = &frame[0..2]; if start != FRAME_START_RESPONSE { return Err(SdkError::FrameError(format!( - "invalid response start: 0x{start:04X}" + "invalid response start: 0x{start:02X?}" ))); } + debug_println!("get resp"); let data_len = Self::read_u16_le(frame, 2)? as usize; - let expected_len = 2 + 2 + data_len + FRAME_STATUS_LEN + FRAME_CRC_LEN; + let expected_len = 2 + 2 + 1 + data_len; if frame.len() != expected_len { return Err(SdkError::FrameError(format!( @@ -234,13 +236,13 @@ impl ProtocolCodec for EskinProtocolCodec { let start_addr = Self::read_u32_le(frame, 7)?; let read_len = Self::read_u16_le(frame, 11)? as usize; - if data_len != 9 + read_len { + if data_len != 10 + read_len { return Err(SdkError::FrameError(format!( "read response data length mismatch: header data_len {data_len}, payload len {read_len}" ))); } - let payload_start = 13; + let payload_start = 14; let payload_end = payload_start + read_len; let data = frame @@ -248,7 +250,7 @@ impl ProtocolCodec for EskinProtocolCodec { .ok_or_else(|| SdkError::FrameError("read response payload missing".into()))? .to_vec(); - let status_offset = 4 + data_len; + let status_offset = 13; let status_raw = *frame .get(status_offset) .ok_or_else(|| SdkError::FrameError("read response status missing".into()))?; @@ -271,15 +273,15 @@ impl ProtocolCodec for EskinProtocolCodec { return Err(SdkError::FrameError("write response too short".into())); } - let start = Self::read_u16_le(frame, 0)?; + let start = &frame[..2]; if start != FRAME_START_RESPONSE { return Err(SdkError::FrameError(format!( - "invalid response start: 0x{start:04X}" + "invalid response start: 0x{start:02X?}" ))); } let data_len = Self::read_u16_le(frame, 2)? as usize; - let expected_len = 2 + 2 + data_len + FRAME_STATUS_LEN + FRAME_CRC_LEN; + let expected_len = 2 + 2 + 1 + data_len; if frame.len() != expected_len { return Err(SdkError::FrameError(format!( @@ -307,13 +309,13 @@ impl ProtocolCodec for EskinProtocolCodec { let start_addr = Self::read_u32_le(frame, 7)?; let return_byte_count = Self::read_u16_le(frame, 11)?; - if data_len != 9 { + if data_len != 10 { return Err(SdkError::FrameError(format!( "write response data length mismatch: expected 9, got {data_len}" ))); } - let status_offset = 4 + data_len; + let status_offset = 13; let status_raw = *frame .get(status_offset) .ok_or_else(|| SdkError::FrameError("write response status missing".into()))?; @@ -336,10 +338,10 @@ impl ProtocolCodec for EskinProtocolCodec { return Err(SdkError::FrameError("stream frame too short".into())); } - let start = Self::read_u16_le(frame, 0)?; + let start: [u8; 2] = frame[..2].try_into().unwrap(); if start != FRAME_START_RESPONSE { return Err(SdkError::FrameError(format!( - "invalid stream frame start: 0x{start:04X}" + "invalid stream frame start: 0x{start:02X?}" ))); } @@ -373,7 +375,7 @@ impl ProtocolCodec for EskinProtocolCodec { .ok_or_else(|| SdkError::FrameError("stream payload missing".into()))? .to_vec(); - let status_offset = 4 + data_len; + let status_offset = 13; let status_raw = *frame .get(status_offset) .ok_or_else(|| SdkError::FrameError("stream status missing".into()))?; diff --git a/src/stream.rs b/src/stream.rs index e8c63d9..ef1292e 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -238,9 +238,17 @@ impl PollingSampleCollector { buf: &mut [u8], timeout: Duration, ) -> Result<(), SdkError> { + let deadline = std::time::Instant::now() + + timeout + .to_std() + .map_err(|_| SdkError::InvalidParameter("timeout must be non-negative".into()))?; + let mut offset = 0; while offset < buf.len() { - let n = transport.read(&mut buf[offset..], timeout)?; + let remaining = deadline + .checked_duration_since(std::time::Instant::now()) + .unwrap_or(std::time::Duration::from_millis(1)); + let n = transport.read(&mut buf[offset..], Duration::from_std(remaining).unwrap())?; if n == 0 { return Err(SdkError::Timeout); @@ -259,11 +267,12 @@ impl PollingSampleCollector { let mut header = [0u8; 4]; Self::read_exact_from_transport(transport, &mut header, timeout)?; + debug_println!("[stream] recv header: {:02X?}", header); - let start = u16::from_be_bytes([header[0], header[1]]); + let start = [header[0], header[1]]; if start != FRAME_START_RESPONSE { return Err(SdkError::FrameError(format!( - "invalid response start: 0x{start:04X}" + "invalid response start: 0x{start:02X?}" ))); } @@ -274,6 +283,7 @@ impl PollingSampleCollector { frame[..4].copy_from_slice(&header); Self::read_exact_from_transport(transport, &mut frame[4..], timeout)?; + debug_println!("[stream] recv frame: {:02X?}", frame); Ok(frame) }