feat: add FFI layer, protocol tests, mock transport, README
- FFI: eskin_open/close/read_register/write_register for C/C++/Python - Protocol: encode/decode tests with golden bytes verification - Stream: implement PollingSampleCollector producing FingerSample - Register: add parse_combined_forces/parse_module_errors - Transport: add MockSerialTransport for testing - Include: add C header file eskin_ffi.h - Examples: C++ and Python usage examples - README: full usage guide for Rust/C++/Python - Exclude docs/ from repo (internal only)
This commit is contained in:
214
README.md
214
README.md
@@ -1,2 +1,214 @@
|
||||
# eskin-finger-sdk
|
||||
# Eskin Finger SDK
|
||||
|
||||
E-Skin 手指力传感器 Rust SDK,提供串口通信、寄存器读写、流式采集能力,支持 Rust / C/C++ / Python 调用。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```text
|
||||
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)
|
||||
|
||||
```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++
|
||||
|
||||
### 构建动态库
|
||||
|
||||
```bash
|
||||
# 安装依赖(Ubuntu)
|
||||
sudo apt install pkg-config libudev-dev
|
||||
|
||||
# 构建
|
||||
cargo build --release
|
||||
# 输出: target/release/libeskin_finger_sdk.so
|
||||
```
|
||||
|
||||
### 编译 C++ 示例
|
||||
|
||||
```bash
|
||||
g++ example/cpp/main.cpp -I include -L target/release -leskin_finger_sdk -o example_cpp
|
||||
LD_LIBRARY_PATH=target/release ./example_cpp
|
||||
```
|
||||
|
||||
### C++ 代码示例
|
||||
|
||||
```cpp
|
||||
#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
|
||||
|
||||
```bash
|
||||
cargo build --release
|
||||
cd example/python
|
||||
LD_LIBRARY_PATH=../../target/release python3 example.py
|
||||
```
|
||||
|
||||
```python
|
||||
from eskin_ffi import EskinDevice
|
||||
|
||||
with EskinDevice("target/release/libeskin_finger_sdk.so") as dev:
|
||||
dev.open("/dev/ttyUSB0")
|
||||
|
||||
# 读寄存器
|
||||
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)` | 写寄存器原始字节 |
|
||||
|
||||
---
|
||||
|
||||
## 协议格式
|
||||
|
||||
### Request 帧
|
||||
|
||||
```text
|
||||
[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 帧
|
||||
|
||||
```text
|
||||
[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 | 设备返回错误 |
|
||||
|
||||
---
|
||||
|
||||
## 测试
|
||||
|
||||
```bash
|
||||
cargo test # 全部测试
|
||||
cargo test protocol::tests # 仅协议层
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 架构
|
||||
|
||||
```text
|
||||
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` — 序列化(可选)
|
||||
Reference in New Issue
Block a user