c195234771511b9407d9286215088e4895ec0871
- Separate DeviceState (connection lifecycle) and DeviceMode (Command/Streaming) - Add stream: Option<StreamRuntime> to EskinDeviceInner - Wire up start_stream/stop_stream with StreamRuntime (worker thread) - Add StreamingBusy error for command-mode guard - Fix stream frame total_len calculation (was double-counting status byte) - Add ensure_command_mode() check on read_register/write_register - close() now auto-stops stream if active - Add stream_demo() in main.rs with Enter-to-stop loop - Add finger_addr config to StreamConfig
Eskin Finger SDK
E-Skin 手指力传感器 Rust SDK,提供串口通信、寄存器读写、流式采集能力,支持 Rust / C/C++ / Python 调用。
目录结构
src/
lib.rs — Rust 库入口
device.rs — 设备管理(open/close/read/write)
stream.rs — 流式采集(PollingSampleCollector)
protocol.rs — 协议帧编解码(CRC-8/X25)
register.rs — 寄存器地址定义与解析
transport.rs — 串口传输抽象
channel.rs — 线程间 Channel
config.rs — 配置与设备信息
error.rs — 错误类型
types.rs — 数据类型定义
ffi/mod.rs — C FFI 导出函数
include/
eskin_ffi.h — C/C++ 头文件
example/
cpp/main.cpp — C++ 使用示例
python/ — Python 使用示例
快速开始(Rust)
use eskin_finger_sdk::config::DeviceConfig;
use eskin_finger_sdk::device::{EskinDevice, EskinDeviceInner};
use eskin_finger_sdk::transport::SerialPortTransport;
let transport = SerialPortTransport::new("/dev/ttyUSB0", 921600);
let config = DeviceConfig::default();
let mut device = EskinDeviceInner::new(config, Box::new(transport));
device.open().unwrap();
// 读寄存器(原始字节)
let data = device.read_register(0x0000, 4).unwrap();
println!("Serial: {:?}", data);
// 写寄存器
let count = device.write_register(0x0030, &[0x01, 0x00, 0x00, 0x00]).unwrap();
println!("Wrote {} bytes", count);
device.close().unwrap();
使用 C/C++
构建动态库
# 安装依赖(Ubuntu)
sudo apt install pkg-config libudev-dev
# 构建
cargo build --release
# 输出: target/release/libeskin_finger_sdk.so
编译 C++ 示例
g++ example/cpp/main.cpp -I include -L target/release -leskin_finger_sdk -o example_cpp
LD_LIBRARY_PATH=target/release ./example_cpp
C++ 代码示例
#include "eskin_ffi.h"
#include <cstdio>
int main() {
EskinDeviceHandle dev = eskin_open("/dev/ttyUSB0", nullptr);
if (!dev) return 1;
uint8_t buf[256];
uint32_t actual;
if (eskin_read_register(dev, 0x0000, 4, buf, sizeof(buf), &actual) == ESkinSuccess) {
printf("Serial: %02X %02X %02X %02X\n", buf[0], buf[1], buf[2], buf[3]);
}
eskin_close(dev);
return 0;
}
使用 Python
构建 & 准备
cargo build --release
# 将生成的 .so 文件复制到 python 示例目录下
cp target/release/libeskin_finger_sdk.so example/python/
cd example/python
python3 example.py
注意: Python 示例默认从当前目录加载
libeskin_finger_sdk.so,请确保.so文件已复制到example/python/目录下,或修改example.py中的LIB_PATH指向正确的路径。
from eskin_ffi import EskinDevice
with EskinDevice("libeskin_finger_sdk.so") as dev:
dev.open("/dev/ttyUSB0")
# 读取硬件版本
print(f"Hardware version: {dev.read_hdw_version()}")
# 读取矩阵尺寸
print(f"Matrix: {dev.read_matrix_row()} x {dev.read_matrix_col()}")
# 读寄存器
data = dev.read_register(0x0000, 4)
print(f"Serial: {data.hex()}")
# 写寄存器
dev.write_register(0x0030, bytes([0x01, 0x00, 0x00, 0x00]))
FFI 接口一览
| 函数 | 说明 |
|---|---|
eskin_version() |
获取 SDK 版本 |
eskin_open(path, config) |
打开串口设备,返回 handle |
eskin_close(handle) |
关闭设备,释放 handle |
eskin_read_register(handle, addr, length, buf, buf_len, actual_len) |
读寄存器原始字节 |
eskin_write_register(handle, addr, data, data_len, return_count) |
写寄存器原始字节 |
eskin_read_hdw_version(handle, buf, buf_len, actual_len) |
读取硬件版本号 |
eskin_read_matrix_row(handle, out) |
读取矩阵行数 |
eskin_read_matrix_col(handle, out) |
读取矩阵列数 |
eskin_read_device_config1(handle, out) |
读取设备配置寄存器1 |
eskin_read_device_config2(handle, out) |
读取设备配置寄存器2 |
eskin_write_device_config1(handle, enable, return_count) |
写入设备配置寄存器1 |
eskin_write_device_config2(handle, enable, return_count) |
写入设备配置寄存器2 |
eskin_write_matrix_row(handle, row, return_count) |
写入矩阵行数 |
eskin_write_matrix_col(handle, col, return_count) |
写入矩阵列数 |
协议格式
Request 帧
[start:2B] [data_len:2B LE] [dev_addr:1B] [reserved:1B] [func:1B]
[start_addr:4B LE] [read/write_len:2B LE] [payload:NB] [crc:1B]
start = [0x55, 0xAA]
func: READ=0xFB, WRITE=0x79
Response 帧
[start:2B] [data_len:2B LE] [dev_addr:1B] [reserved:1B] [func:1B]
[start_addr:4B LE] [read/write_len:2B LE] [payload:NB] [status:1B] [crc:1B]
start = [0x55, 0xAA] (注: 0xAA55 LE)
func: RESPONSE_READ=0xFF, RESPONSE_WRITE=0xF9
status: 0x00=Success
错误码
| 名称 | 值 | 说明 |
|---|---|---|
Success |
0 | 成功 |
InvalidPointer |
1 | 空指针 |
DeviceNotFound |
2 | 设备未找到 |
DeviceAlreadyOpen |
3 | 设备已打开 |
NotInitialized |
4 | 未初始化 |
AlreadyStreaming |
5 | 已在采集中 |
NotStreaming |
6 | 未在采集 |
Timeout |
9 | 读超时 |
ChannelClosed |
10 | 通道断开 |
CrcError |
14 | CRC 校验失败 |
FrameError |
15 | 帧格式错误 |
DeviceError |
17 | 设备返回错误 |
测试
cargo test # 全部测试
cargo test protocol::tests # 仅协议层
架构
User / C / Python
↓ FFI
DeviceWrapper (handle)
↓
EskinDeviceInner
↓ read_register / write_register
EskinProtocolCodec (encode/decode + CRC8)
↓
SerialTransport (write/read bytes)
↓
Hardware (UART)
详细设计见 docs/PROGRESS.md 和 docs/ARCHITECTURE.md。
依赖
serialport— 串口访问(需要pkg-config+libudev-dev)crc— CRC-8/X25 校验crossbeam-channel— 高性能线程间通信chrono— 时间戳serde/serde_json— 序列化(可选)
Description