C++ SDK - Revo 1 灵巧手
系统要求
- Linux: Ubuntu 20.04/22.04 LTS (x86_64/aarch64), glibc ≥ 2.31
- macOS: 10.15+
- Windows: 10/11
快速开始
克隆仓库
shell
git clone git@github.com:BrainCoTech/brainco-hand-sdk.git安装与配置
shell
# 安装依赖
# 需要: build-essential, cmake, make, gcc, g++ 等
# 安装 SDK 依赖库
./download-lib.sh
# 配置设备权限
# Linux 系统中,串口设备(如 /dev/ttyUSB0)通常归属于 dialout 或 tty 用户组
# 只有该组成员才能访问设备,例如:
# crw-rw---- 1 root dialout 188, 0 Aug 14 12:00 /dev/ttyUSB0
# 将当前用户添加到 dialout 组
sudo usermod -aG dialout $USER
# 注意:添加后需要重新登录才能生效
# 编译并运行示例(跨平台统一目录)
cd c && make
cd demo && ./hand_demo.exe # 自动检测设备并运行shell
# 安装 Xcode 或 Xcode Command Line Tools
xcode-select --install
# 安装 SDK 依赖库
./download-lib.sh
# 编译并运行示例(跨平台统一目录)
cd c && make
cd demo && ./hand_demo.exe # 自动检测设备并运行shell
# 需要 MinGW 或 MSVC 编译环境
# 安装 SDK 依赖库
./download-lib.sh
# 编译并运行示例(跨平台统一目录)
cd c && make
cd demo && hand_demo.exe # 自动检测设备并运行示例代码
SDK 提供了丰富的示例代码,涵盖不同通信协议和应用场景。
跨平台示例(推荐)⭐
统一的跨平台示例,支持自动检测设备和多种通信协议。
shell
cd c
make
cd demo
./hand_demo.exe # 自动检测设备并运行演示| 示例 | 说明 |
|---|---|
| hand_demo.cpp | 综合演示(8种模式:位置/速度/电流控制、动作序列、触觉传感器等) |
| hand_monitor.cpp | 实时数据监控(电机状态、触觉数据) |
| hand_dfu.cpp | 固件升级 |
| auto_detect.cpp | 设备自动检测 |
支持的初始化方式:
shell
./hand_demo.exe # 自动检测(推荐)
./hand_demo.exe -m /dev/ttyUSB0 115200 1 # Modbus
./hand_demo.exe -p /dev/ttyUSB0 10 # Protobuf
./hand_demo.exe -c /dev/cu.usbmodem14201 1000000 1 # CAN 2.0 (ZQWL)
./hand_demo.exe -s can0 1 # SocketCAN CAN 2.0 (外部适配)
./hand_demo.exe -b can0 1 # SocketCAN CAN 2.0 (SDK 内置)传统协议示例(已归档)
⚠️ 以下示例已归档至
archive/目录,建议使用上方 跨平台示例 (c/demo/),支持自动检测多种协议和设备。
Modbus-RTU 协议
触觉传感器
CAN 2.0 协议
- 自定义 CAN 设备 - C++ 示例
- ZLG USBCAN 设备 - C++ 示例
- ZQWL USBCAN 设备 - C++ 示例
API 参考
C/C++ API 查阅建议以 SDK 2.x 发布包随附的完整 C ABI 头文件为准。
展开查看 C/C++ 头文件 (stark-sdk.h)
c
#ifndef STARK_SDK_H
#define STARK_SDK_H
/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
#include <cstdarg>
#include <cstdint>
#include <cstdlib>
#include <ostream>
#include <new>
/// Built‑in gestures 1~6: open hand, fist, two‑finger pinch, three‑finger pinch,
/// side pinch, single‑finger point.
/// Revo1 supports up to 6 custom action sequences: IDs 10~15.
/// Revo2 supports up to 24 custom action sequences: IDs 7~30.
enum ActionSequenceId : uint8_t {
ACTION_SEQUENCE_ID_DEFAULT_GESTURE_OPEN = 1,
ACTION_SEQUENCE_ID_DEFAULT_GESTURE_FIST = 2,
ACTION_SEQUENCE_ID_DEFAULT_GESTURE_PINCH_TWO = 3,
ACTION_SEQUENCE_ID_DEFAULT_GESTURE_PINCH_THREE = 4,
ACTION_SEQUENCE_ID_DEFAULT_GESTURE_PINCH_SIDE = 5,
ACTION_SEQUENCE_ID_DEFAULT_GESTURE_POINT = 6,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE22 = 7,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE23 = 8,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE24 = 9,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE1 = 10,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE2 = 11,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE3 = 12,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE4 = 13,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE5 = 14,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE6 = 15,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE7 = 16,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE8 = 17,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE9 = 18,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE10 = 19,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE11 = 20,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE12 = 21,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE13 = 22,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE14 = 23,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE15 = 24,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE16 = 25,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE17 = 26,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE18 = 27,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE19 = 28,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE20 = 29,
ACTION_SEQUENCE_ID_CUSTOM_GESTURE21 = 30,
};
/// DFU (Device Firmware Update) state
/// Used in DFU state callback to indicate current upgrade status
enum DfuState : uint8_t {
/// DFU not started
DFU_STATE_IDLE = 0,
/// Preparing to start DFU
DFU_STATE_STARTING = 1,
/// DFU started, ready to transfer
DFU_STATE_STARTED = 2,
/// Transferring firmware data
DFU_STATE_TRANSFER = 3,
/// DFU completed successfully
DFU_STATE_COMPLETED = 4,
/// DFU aborted or failed
DFU_STATE_ABORTED = 5,
};
/// EtherCAT FoE (File over EtherCAT) firmware type
/// Used for firmware upgrade over EtherCAT
enum EtherCATFoeType : uint8_t {
/// Wrist module firmware
ETHER_CAT_FOE_TYPE_WRIST = 1,
/// Main controller firmware
ETHER_CAT_FOE_TYPE_CONTROL = 2,
};
/// Finger control unit mode
/// Determines how position/speed/current values are interpreted
enum FingerUnitMode : uint8_t {
/// Normalized mode: values in range 0-1000 (default)
FINGER_UNIT_MODE_NORMALIZED = 0,
/// Physical mode: values in physical units (degrees, °/s, mA)
FINGER_UNIT_MODE_PHYSICAL = 1,
};
enum ForceLevel : uint8_t {
FORCE_LEVEL_SMALL = 1,
FORCE_LEVEL_NORMAL = 2,
FORCE_LEVEL_FULL = 3,
};
enum HandType : uint8_t {
HAND_TYPE_LEFT = 0,
HAND_TYPE_RIGHT = 1,
};
enum LedColor : uint8_t {
LED_COLOR_UNCHANGED = 0,
LED_COLOR_R = 1,
LED_COLOR_G = 2,
LED_COLOR_RG = 3,
LED_COLOR_B = 4,
LED_COLOR_RB = 5,
LED_COLOR_GB = 6,
LED_COLOR_RGB = 7,
};
enum LedMode : uint8_t {
LED_MODE_NONE = 0,
LED_MODE_SHUTDOWN = 1,
LED_MODE_KEEP = 2,
LED_MODE_BLINK = 3,
LED_MODE_ONE_SHOT = 4,
LED_MODE_BLINK0_5HZ = 5,
LED_MODE_BLINK2HZ = 6,
};
enum LogLevel : uint8_t {
LOG_LEVEL_ERROR = 0,
LOG_LEVEL_WARN = 1,
LOG_LEVEL_INFO = 2,
LOG_LEVEL_DEBUG = 3,
LOG_LEVEL_TRACE = 4,
};
/// Motor state
/// Indicates the current operating state of a finger motor
enum MotorState : uint8_t {
/// Motor is idle (not moving)
MOTOR_STATE_IDLE = 0,
/// Motor is running (moving)
MOTOR_STATE_RUNNING = 1,
/// Motor is stalled (blocked or reached limit)
MOTOR_STATE_STALL = 2,
/// Motor is in turbo mode (continuous force)
MOTOR_STATE_TURBO = 3,
/// Unknown state
MOTOR_STATE_UNKNOWN = 255,
};
/// Button press state
/// Used in button event callbacks
enum PressState : uint8_t {
/// No button event
PRESS_STATE_NONE = 0,
/// Button pressed down
PRESS_STATE_DOWN = 1,
/// Button released
PRESS_STATE_UP = 2,
};
/// SKU type (device hand type)
/// Identifies the hand side (left/right). Size is determined by hardware_type.
/// Note: Currently only Medium size is available. Small size values are reserved.
enum SkuType : uint8_t {
/// Medium size, right hand
SKU_TYPE_MEDIUM_RIGHT = 1,
/// Medium size, left hand
SKU_TYPE_MEDIUM_LEFT = 2,
/// Small size, right hand (reserved, not currently used)
SKU_TYPE_SMALL_RIGHT = 3,
/// Small size, left hand (reserved, not currently used)
SKU_TYPE_SMALL_LEFT = 4,
};
/// Finger identifier
/// Used to specify which finger to control or query
enum StarkFingerId : uint8_t {
/// Thumb (main joint)
STARK_FINGER_ID_THUMB = 1,
/// Thumb auxiliary (rotation joint, Revo2 only)
STARK_FINGER_ID_THUMB_AUX = 2,
/// Index finger
STARK_FINGER_ID_INDEX = 3,
/// Middle finger
STARK_FINGER_ID_MIDDLE = 4,
/// Ring finger
STARK_FINGER_ID_RING = 5,
/// Pinky finger
STARK_FINGER_ID_PINKY = 6,
};
/// Stark hardware type
/// Identifies the device generation and capabilities
///
/// Value ranges:
/// Revo1: 0~9
/// Revo2: 10~19
enum StarkHardwareType : uint8_t {
/// Revo1 with legacy Protobuf protocol
STARK_HARDWARE_TYPE_REVO1_PROTOBUF = 0,
/// Revo1 Basic (no touch sensor)
STARK_HARDWARE_TYPE_REVO1_BASIC = 1,
/// Revo1 with capacitive touch sensor
STARK_HARDWARE_TYPE_REVO1_TOUCH = 2,
/// Revo1 Advanced: wide voltage, multi-interface support
STARK_HARDWARE_TYPE_REVO1_ADVANCED = 3,
/// Revo1 Advanced with capacitive touch sensor
STARK_HARDWARE_TYPE_REVO1_ADVANCED_TOUCH = 4,
/// Revo2 Basic (no touch sensor)
STARK_HARDWARE_TYPE_REVO2_BASIC = 10,
/// Revo2 with capacitive touch sensor
STARK_HARDWARE_TYPE_REVO2_TOUCH = 11,
/// Revo2 with pressure/modulus touch sensor
STARK_HARDWARE_TYPE_REVO2_TOUCH_PRESSURE = 12,
/// Revo2 with 3D force matrix touch sensor
STARK_HARDWARE_TYPE_REVO2_TOUCH_FORCE3D = 13,
/// Revo2 with array pressure touch sensor
STARK_HARDWARE_TYPE_REVO2_TOUCH_ARRAY_PRESSURE = 14,
};
/// Communication protocol type
/// Determines how the SDK communicates with the device
enum StarkProtocolType : uint8_t {
/// Auto-detect protocol (used in stark_auto_detect)
STARK_PROTOCOL_TYPE_AUTO = 0,
/// Modbus RTU over RS485 serial
STARK_PROTOCOL_TYPE_MODBUS = 1,
/// CAN 2.0 protocol (1Mbps)
STARK_PROTOCOL_TYPE_CAN = 2,
/// CAN FD protocol (1Mbps arbitration, 5Mbps data)
STARK_PROTOCOL_TYPE_CAN_FD = 3,
/// EtherCAT protocol (Linux only)
STARK_PROTOCOL_TYPE_ETHER_CAT = 4,
/// Legacy Protobuf protocol (Revo1 only)
STARK_PROTOCOL_TYPE_PROTOBUF = 5,
};
/// Touch sensor status
/// Indicates the health status of a touch sensor
enum TouchSensorStatus : uint8_t {
/// Sensor data is valid
TOUCH_SENSOR_STATUS_NORMAL = 0,
/// Sensor data is abnormal
TOUCH_SENSOR_STATUS_ABNORMAL = 1,
/// Communication error with sensor
TOUCH_SENSOR_STATUS_COMMUNICATION_ERROR = 2,
/// Unknown state
TOUCH_SENSOR_STATUS_UNKNOWN = 255,
};
/// Opaque handle for ArrayPressureTouchDataBuffer
struct CArrayPressureTouchItemBuffer;
/// Opaque handle for DataCollector
struct CDataCollector;
/// Opaque handle for MotorStatusBuffer
struct CMotorStatusBuffer;
/// Opaque handle for PressureDetailedBuffer
struct CPressureDetailedBuffer;
/// Opaque handle for PressureSummaryBuffer
struct CPressureSummaryBuffer;
/// Opaque handle for TouchStatusBuffer
struct CTouchStatusBuffer;
/// Device handler for C API
/// This is an opaque handle that wraps the internal device context.
/// Use `modbus_open` or `init_device_handler` to create, and `modbus_close`
/// or `close_device_handler` to release.
struct DeviceHandler;
/// Motor status data for all 6 finger joints.
/// Returned by `stark_get_motor_status`. Call `free_motor_status_data` to release.
/// Array order: [Thumb, ThumbAux, Index, Middle, Ring, Pinky]
struct CMotorStatusData {
/// Position values in unified range 0-1000 (0=open, 1000=closed)
uint16_t positions[6];
/// Speed values in unified range -1000 to +1000 (positive=closing)
int16_t speeds[6];
/// Current values in unified range -1000 to +1000 (positive=closing)
int16_t currents[6];
/// Motor states (see MotorState enum)
uint8_t states[6];
};
/// Tactile sensor data (C API)
/// 3D force values, self-capacitance, mutual-capacitance values, and sensor status.
/// Revo2 touch hand only has normal force, tangential force, tangential force
/// direction, and proximity; other fields are zero.
struct CTouchFingerItem {
uint16_t normal_force1;
uint16_t normal_force2;
uint16_t normal_force3;
uint16_t tangential_force1;
uint16_t tangential_force2;
uint16_t tangential_force3;
uint16_t tangential_direction1;
uint16_t tangential_direction2;
uint16_t tangential_direction3;
uint32_t self_proximity1;
uint32_t self_proximity2;
uint32_t mutual_proximity;
uint16_t status;
};
/// Pressure sensor detailed data (Detailed mode)
///
/// For Modulus pressure touch sensor detailed sensor point data
/// - Fingers: 9 sensor points
/// - Palm: 46 sensor points
struct PressureDetailedItem {
/// Number of sensor points (thumb/index/middle/ring/pinky: 9, palm: 46)
uint8_t sensor_count;
/// Sensor data (up to 46 sensor points)
uint16_t sensors_data[46];
};
/// ArrayPressure sensor status.
struct CArrayPressureStatus {
/// Sensor status (5 bits, one per finger, 1=abnormal)
uint16_t sensor_status;
/// Warmup status (0=warming up, 1=complete)
uint8_t warmup_complete;
};
/// ArrayPressure touch data (25 registers = 50 bytes).
/// Call `free_array_pressure_touch_data` to release.
struct CArrayPressureTouchData {
CArrayPressureStatus status;
uint16_t data[25];
uint16_t data_len;
};
/// Device configuration returned by auto-detect functions.
/// Contains the detected protocol, port, baudrate, and slave ID.
/// Call `free_device_config` to release memory.
struct CDeviceConfig {
/// Communication protocol type
StarkProtocolType protocol;
/// Serial port name (e.g., "/dev/ttyUSB0" or "COM3")
const char *port_name;
/// Baud rate in bps
uint32_t baudrate;
/// Slave ID on the bus
uint8_t slave_id;
};
/// ZQWL device info struct (C interface)
struct CZqwlDeviceInfo {
/// Device type (0x0100=dual-channel CANFD, 0x0101=single-channel CANFD, 0x0102=dual-channel CAN, etc.)
uint16_t device_type;
/// Serial port name
char *port_name;
/// USB VID
uint16_t vid;
/// USB PID
uint16_t pid;
/// Whether CANFD is supported
bool supports_canfd;
/// Number of channels
uint8_t channel_count;
};
/// ZQWL device list struct (C interface)
struct ZqwlDeviceList {
/// Device array pointer
CZqwlDeviceInfo *devices;
/// Device count
uintptr_t count;
};
/// SocketCAN device info struct (C interface)
struct CSocketCanDeviceInfo {
/// Interface name (e.g. "can0")
char *iface;
/// Whether CANFD is supported
bool supports_canfd;
/// Whether interface is up
bool is_up;
};
/// SocketCAN device list struct (C interface)
struct SocketCanDeviceList {
/// Device array pointer
CSocketCanDeviceInfo *devices;
/// Device count
uintptr_t count;
};
/// Detected device information (C interface)
struct CDetectedDevice {
/// Protocol type
StarkProtocolType protocol;
/// Port name (serial port or CAN adapter port)
char *port_name;
/// Slave ID on the bus
uint8_t slave_id;
/// Baudrate (for Modbus/serial protocols, or CAN arbitration baudrate)
uint32_t baudrate;
/// Data baudrate (for CANFD only, 0 for other protocols)
uint32_t data_baudrate;
/// Hardware type
StarkHardwareType hardware_type;
/// SKU type
SkuType sku_type;
/// Serial number (NULL if not detected)
char *serial_number;
/// Firmware version (NULL if not detected)
char *firmware_version;
};
/// Detected device list (C interface)
struct CDetectedDeviceList {
/// Device array pointer
CDetectedDevice *devices;
/// Device count
uintptr_t count;
};
/// Modbus async read/write result callback.
/// This callback processes results of asynchronous Modbus operations.
/// Return value: 0 on success, non‑zero on failure.
using ModbusOperationResultCallback = void(*)(uint8_t*, int, int, void*);
/// Modbus async read/write callback type.
/// Return value: 0 on success, non‑zero on failure.
using ModbusOperationCallback = int32_t(*)(const uint8_t *values,
int len,
ModbusOperationResultCallback callback,
void *user_data);
/// Custom Modbus RX callback.
/// Return value: 0 on success, non‑zero on failure.
using ModbusRxCallback = int32_t(*)(uint8_t slave_id,
uint16_t register_address,
uint16_t *data_out,
uint16_t count);
/// Custom Modbus TX callback.
/// Return value: 0 on success, non‑zero on failure.
using ModbusTxCallback = int32_t(*)(uint8_t slave_id,
uint16_t register_address,
const uint16_t *data,
uint16_t count);
/// CAN/CANFD RX callback.
///
/// # Parameters
/// - `slave_id`: Slave ID
/// - `expected_can_id`: Expected CAN ID to filter responses
/// - CAN 2.0: `= 0` for DFU mode (accept any), `> 0` for normal filtering
/// - CANFD: Always `> 0`, matches by slave_id and master_id
/// - `expected_frames`: `0` = auto-detect multi-frame, `> 0` = specific frame count
/// - `can_id_out`: Output CAN ID
/// - `data_out`: Output data buffer (at least 512 bytes for multi-frame)
/// - `data_len_out`: Output data length
///
/// # Return value
/// 0 on success, non‑zero on failure.
using CanRxCallback = int32_t(*)(uint8_t slave_id,
uint32_t expected_can_id,
uint8_t expected_frames,
uint32_t *can_id_out,
uint8_t *data_out,
uintptr_t *data_len_out);
/// CAN/CANFD TX callback.
/// Return value: 0 on success, non‑zero on failure.
using CanTxCallback = int32_t(*)(uint8_t slave_id,
uint32_t can_id,
const uint8_t *data,
uintptr_t data_len);
/// DFU state callback, `state` corresponds to `DfuState`.
using DfuStateCallback = void(*)(uint8_t slave_id, uint8_t state);
/// DFU progress callback.
using DfuProgressCallback = void(*)(uint8_t slave_id, float progress);
/// Device information returned by `stark_get_device_info`.
/// Contains device identification and version information.
/// Call `free_device_info` to release memory.
struct CDeviceInfo {
/// Device SKU (hand side: left/right) (Deprecated, use hand_type instead)
SkuType sku_type;
/// Device hand type (left/right)
HandType hand_type;
/// Hardware type (device generation and capabilities)
StarkHardwareType hardware_type;
/// Serial number string (null-terminated)
const char *serial_number;
/// Firmware version string (null-terminated)
const char *firmware_version;
/// Hardware version string (reserved; empty for current devices)
const char *hardware_version;
};
/// Raw capacitance data from touch sensors.
/// Contains raw ADC values for each sensor channel.
/// Call `free_touch_raw_data` to release.
struct CTouchRawData {
/// Thumb sensor channels (7 channels)
uint32_t thumb[7];
/// Index finger sensor channels (11 channels)
uint32_t index[11];
/// Middle finger sensor channels (11 channels)
uint32_t middle[11];
/// Ring finger sensor channels (11 channels)
uint32_t ring[11];
/// Pinky finger sensor channels (7 channels)
uint32_t pinky[7];
};
/// Touch data for all 5 fingers.
/// Returned by `stark_get_touch_status`. Call `free_touch_finger_data` to release.
/// Array order: [Thumb, Index, Middle, Ring, Pinky]
struct CTouchFingerData {
/// Touch data for each finger
CTouchFingerItem items[5];
};
/// 3D force data for a single measurement point.
/// Fx, Fy are signed (-128 ~ +127), Fz is unsigned (0 ~ 255).
struct CForce3DPoint {
int8_t fx;
int8_t fy;
uint16_t fz;
};
/// Force3D summary data for 4 fingers (no thumb).
/// Call `free_force3d_touch_summary` to release.
struct CForce3DTouchSummary {
CForce3DPoint index;
CForce3DPoint middle;
CForce3DPoint ring;
CForce3DPoint pinky;
};
/// Force3D array data for a single finger (31 measurement points).
/// Call `free_force3d_finger_array` to release.
struct CForce3DFingerArray {
CForce3DPoint points[31];
uint16_t count;
};
/// Turbo mode configuration.
/// Turbo mode enables continuous gripping force.
/// Call `free_turbo_config` to release.
struct CTurboConfig {
/// Interval between turbo pulses in milliseconds
uint16_t interval;
/// Duration of each turbo pulse in milliseconds
uint16_t duration;
};
/// LED information returned by `stark_get_led_info`.
/// Call `free_led_info` to release.
struct CLedInfo {
/// Current LED color
LedColor color;
/// Current LED mode (blinking pattern)
LedMode mode;
};
/// Button press event returned by `stark_get_button_event`.
/// Call `free_button_event` to release.
struct CButtonPressEvent {
/// Event timestamp in milliseconds
int32_t timestamp;
/// Button identifier
int32_t button_id;
/// Press state (down/up)
PressState press_state;
};
extern "C" {
/// Create a new motor status buffer
///
/// @param max_size Maximum buffer capacity (default 1000)
/// @return Pointer to CMotorStatusBuffer, or NULL on failure
CMotorStatusBuffer *motor_buffer_new(uintptr_t max_size);
/// Free a motor status buffer
///
/// @param buffer Pointer to CMotorStatusBuffer
void motor_buffer_free(CMotorStatusBuffer *buffer);
/// Get all motor status data from buffer
///
/// @param buffer Pointer to CMotorStatusBuffer
/// @param out_data Pointer to array to store data (caller must allocate, no need to free returned data)
/// @param max_count Maximum number of items to return (size of out_data array)
/// @param out_count Pointer to store the number of items actually returned
/// @return 0 on success, -1 on failure
///
/// @note Data is copied to caller-allocated buffer. Caller is responsible for
/// allocating out_data array before calling, but does NOT need to free
/// the returned data (it's stack/heap memory owned by caller).
int motor_buffer_pop_all(CMotorStatusBuffer *buffer,
CMotorStatusData *out_data,
uintptr_t max_count,
uintptr_t *out_count);
/// Get the number of items in the buffer
///
/// @param buffer Pointer to CMotorStatusBuffer
/// @return Number of items, or 0 if buffer is NULL
uintptr_t motor_buffer_len(const CMotorStatusBuffer *buffer);
/// Check if buffer is empty
///
/// @param buffer Pointer to CMotorStatusBuffer
/// @return 1 if empty, 0 if not empty, -1 if buffer is NULL
int motor_buffer_is_empty(const CMotorStatusBuffer *buffer);
/// Clear all data from buffer
///
/// @param buffer Pointer to CMotorStatusBuffer
void motor_buffer_clear(CMotorStatusBuffer *buffer);
/// Create a new touch status buffer
///
/// @param max_size Maximum buffer capacity per finger (default 1000)
/// @return Pointer to CTouchStatusBuffer, or NULL on failure
CTouchStatusBuffer *touch_buffer_new(uintptr_t max_size);
/// Free a touch status buffer
///
/// @param buffer Pointer to CTouchStatusBuffer
void touch_buffer_free(CTouchStatusBuffer *buffer);
/// Get all touch data for all fingers
///
/// @param buffer Pointer to CTouchStatusBuffer
/// @param out_data Pointer to array of 5 arrays to store data (caller must allocate, no need to free returned data)
/// @param max_counts Pointer to array of 5 max sizes (capacity of each out_data array)
/// @param out_counts Pointer to array of 5 sizes to store actual counts per finger
/// @return 0 on success, -1 on failure
///
/// @note Data is copied to caller-allocated buffers. Caller is responsible for
/// allocating out_data arrays before calling, but does NOT need to free
/// the returned data (it's stack/heap memory owned by caller).
int touch_buffer_pop_all(CTouchStatusBuffer *buffer,
CTouchFingerItem **out_data,
const uintptr_t *max_counts,
uintptr_t *out_counts);
/// Get touch data for a single finger
///
/// @param buffer Pointer to CTouchStatusBuffer
/// @param finger_index Finger index (0-4)
/// @param out_data Pointer to array to store data (caller must allocate, no need to free returned data)
/// @param max_count Maximum number of items to return (size of out_data array)
/// @param out_count Pointer to store the number of items actually returned
/// @return 0 on success, -1 on failure
///
/// @note Data is copied to caller-allocated buffer. Caller is responsible for
/// allocating out_data array before calling, but does NOT need to free
/// the returned data (it's stack/heap memory owned by caller).
int touch_buffer_pop_finger(CTouchStatusBuffer *buffer,
uintptr_t finger_index,
CTouchFingerItem *out_data,
uintptr_t max_count,
uintptr_t *out_count);
/// Get buffer lengths for all fingers
///
/// @param buffer Pointer to CTouchStatusBuffer
/// @param out_lengths Pointer to array of 5 sizes
/// @return 0 on success, -1 on failure
int touch_buffer_len_all(const CTouchStatusBuffer *buffer, uintptr_t *out_lengths);
/// Clear all touch buffers
///
/// @param buffer Pointer to CTouchStatusBuffer
void touch_buffer_clear(CTouchStatusBuffer *buffer);
/// Create a new pressure summary buffer
///
/// @param max_size Maximum buffer capacity per finger (default 1000)
/// @return Pointer to CPressureSummaryBuffer, or NULL on failure
CPressureSummaryBuffer *pressure_summary_buffer_new(uintptr_t max_size);
/// Free a pressure summary buffer
///
/// @param buffer Pointer to CPressureSummaryBuffer
void pressure_summary_buffer_free(CPressureSummaryBuffer *buffer);
/// Get all pressure summary data for all fingers
///
/// @param buffer Pointer to CPressureSummaryBuffer
/// @param out_data Pointer to array of 6 arrays to store data (caller must allocate, no need to free returned data)
/// @param max_counts Pointer to array of 6 max sizes (capacity of each out_data array)
/// @param out_counts Pointer to array of 6 sizes to store actual counts per finger
/// @return 0 on success, -1 on failure
///
/// @note Data is copied to caller-allocated buffers. Caller is responsible for
/// allocating out_data arrays before calling, but does NOT need to free
/// the returned data (it's stack/heap memory owned by caller).
int pressure_summary_buffer_pop_all(CPressureSummaryBuffer *buffer,
uint16_t **out_data,
const uintptr_t *max_counts,
uintptr_t *out_counts);
/// Get pressure summary data for a single part (finger or palm)
///
/// @param buffer Pointer to CPressureSummaryBuffer
/// @param finger_index Part index (0-5: 0-4=fingers, 5=palm)
/// @param out_data Pointer to array to store data (caller must allocate, no need to free returned data)
/// @param max_count Maximum number of items to return (size of out_data array)
/// @param out_count Pointer to store the number of items actually returned
/// @return 0 on success, -1 on failure
///
/// @note Data is copied to caller-allocated buffer. Caller is responsible for
/// allocating out_data array before calling, but does NOT need to free
/// the returned data (it's stack/heap memory owned by caller).
int pressure_summary_buffer_pop_finger(CPressureSummaryBuffer *buffer,
uintptr_t finger_index,
uint16_t *out_data,
uintptr_t max_count,
uintptr_t *out_count);
/// Clear all pressure summary buffers
///
/// @param buffer Pointer to CPressureSummaryBuffer
void pressure_summary_buffer_clear(CPressureSummaryBuffer *buffer);
/// Create a new pressure detailed buffer
///
/// @param max_size Maximum buffer capacity per finger (default 1000)
/// @return Pointer to CPressureDetailedBuffer, or NULL on failure
CPressureDetailedBuffer *pressure_detailed_buffer_new(uintptr_t max_size);
/// Free a pressure detailed buffer
///
/// @param buffer Pointer to CPressureDetailedBuffer
void pressure_detailed_buffer_free(CPressureDetailedBuffer *buffer);
/// Get all pressure detailed data for all fingers
///
/// @param buffer Pointer to CPressureDetailedBuffer
/// @param out_data Pointer to array of 6 arrays to store data (caller must allocate, no need to free returned data)
/// @param max_counts Pointer to array of 6 max sizes (capacity of each out_data array)
/// @param out_counts Pointer to array of 6 sizes to store actual counts per finger
/// @return 0 on success, -1 on failure
///
/// @note Data is copied to caller-allocated buffers. Caller is responsible for
/// allocating out_data arrays before calling, but does NOT need to free
/// the returned data (it's stack/heap memory owned by caller).
int pressure_detailed_buffer_pop_all(CPressureDetailedBuffer *buffer,
PressureDetailedItem **out_data,
const uintptr_t *max_counts,
uintptr_t *out_counts);
/// Get pressure detailed data for a single part (finger or palm)
///
/// @param buffer Pointer to CPressureDetailedBuffer
/// @param finger_index Part index (0-5: 0-4=fingers, 5=palm)
/// @param out_data Pointer to array to store data (caller must allocate, no need to free returned data)
/// @param max_count Maximum number of items to return (size of out_data array)
/// @param out_count Pointer to store the number of items actually returned
/// @return 0 on success, -1 on failure
///
/// @note Data is copied to caller-allocated buffer. Caller is responsible for
/// allocating out_data array before calling, but does NOT need to free
/// the returned data (it's stack/heap memory owned by caller).
int pressure_detailed_buffer_pop_finger(CPressureDetailedBuffer *buffer,
uintptr_t finger_index,
PressureDetailedItem *out_data,
uintptr_t max_count,
uintptr_t *out_count);
/// Clear all pressure detailed buffers
///
/// @param buffer Pointer to CPressureDetailedBuffer
void pressure_detailed_buffer_clear(CPressureDetailedBuffer *buffer);
CArrayPressureTouchItemBuffer *array_pressure_touch_buffer_new(uintptr_t max_size);
void array_pressure_touch_buffer_free(CArrayPressureTouchItemBuffer *buffer);
int array_pressure_touch_buffer_pop_all(CArrayPressureTouchItemBuffer *buffer,
CArrayPressureTouchData *out_data,
uintptr_t max_count);
uintptr_t array_pressure_touch_buffer_len(const CArrayPressureTouchItemBuffer *buffer);
void array_pressure_touch_buffer_clear(CArrayPressureTouchItemBuffer *buffer);
/// Create a new data collector - Basic version (motor only)
///
/// @param handle Device handler
/// @param motor_buffer Motor status buffer
/// @param slave_id Slave ID (default 1)
/// @param motor_frequency Motor sampling frequency in Hz (default 1000)
/// @param enable_stats Whether to print statistics (1=true, 0=false)
/// @return Pointer to CDataCollector, or NULL on failure
CDataCollector *data_collector_new_basic(DeviceHandler *handle,
CMotorStatusBuffer *motor_buffer,
unsigned char slave_id,
uint32_t motor_frequency,
int enable_stats);
/// Create a new data collector - Capacitive touch version
///
/// @param handle Device handler
/// @param motor_buffer Motor status buffer
/// @param touch_buffer Touch status buffer
/// @param slave_id Slave ID (default 1)
/// @param motor_frequency Motor sampling frequency in Hz (default 1000)
/// @param touch_frequency Touch sampling frequency in Hz (default 100)
/// @param enable_stats Whether to print statistics (1=true, 0=false)
/// @return Pointer to CDataCollector, or NULL on failure
CDataCollector *data_collector_new_capacitive(DeviceHandler *handle,
CMotorStatusBuffer *motor_buffer,
CTouchStatusBuffer *touch_buffer,
unsigned char slave_id,
uint32_t motor_frequency,
uint32_t touch_frequency,
int enable_stats);
/// Create a new data collector - Pressure Summary version
///
/// @param handle Device handler
/// @param motor_buffer Motor status buffer
/// @param pressure_summary_buffer Pressure summary buffer
/// @param slave_id Slave ID (default 1)
/// @param motor_frequency Motor sampling frequency in Hz (default 1000)
/// @param touch_frequency Touch sampling frequency in Hz (default 100)
/// @param enable_stats Whether to print statistics (1=true, 0=false)
/// @return Pointer to CDataCollector, or NULL on failure
CDataCollector *data_collector_new_pressure_summary(DeviceHandler *handle,
CMotorStatusBuffer *motor_buffer,
CPressureSummaryBuffer *pressure_summary_buffer,
unsigned char slave_id,
uint32_t motor_frequency,
uint32_t touch_frequency,
int enable_stats);
/// Create a new data collector - Pressure Detailed version
///
/// @param handle Device handler
/// @param motor_buffer Motor status buffer
/// @param pressure_detailed_buffer Pressure detailed buffer
/// @param slave_id Slave ID (default 1)
/// @param motor_frequency Motor sampling frequency in Hz (default 1000)
/// @param touch_frequency Touch sampling frequency in Hz (default 10)
/// @param enable_stats Whether to print statistics (1=true, 0=false)
/// @return Pointer to CDataCollector, or NULL on failure
CDataCollector *data_collector_new_pressure_detailed(DeviceHandler *handle,
CMotorStatusBuffer *motor_buffer,
CPressureDetailedBuffer *pressure_detailed_buffer,
unsigned char slave_id,
uint32_t motor_frequency,
uint32_t touch_frequency,
int enable_stats);
/// Create a new data collector - Pressure Hybrid version (Summary + Detailed)
///
/// @param handle Device handler
/// @param motor_buffer Motor status buffer
/// @param pressure_summary_buffer Pressure summary buffer
/// @param pressure_detailed_buffer Pressure detailed buffer
/// @param slave_id Slave ID (default 1)
/// @param motor_frequency Motor sampling frequency in Hz (default 1000)
/// @param summary_frequency Summary sampling frequency in Hz (default 100)
/// @param detailed_frequency Detailed sampling frequency in Hz (default 10)
/// @param enable_stats Whether to print statistics (1=true, 0=false)
/// @return Pointer to CDataCollector, or NULL on failure
CDataCollector *data_collector_new_pressure_hybrid(DeviceHandler *handle,
CMotorStatusBuffer *motor_buffer,
CPressureSummaryBuffer *pressure_summary_buffer,
CPressureDetailedBuffer *pressure_detailed_buffer,
unsigned char slave_id,
uint32_t motor_frequency,
uint32_t summary_frequency,
uint32_t detailed_frequency,
int enable_stats);
/// Create a new data collector - ArrayPressure touch version
CDataCollector *data_collector_new_array_pressure(DeviceHandler *handle,
CMotorStatusBuffer *motor_buffer,
CArrayPressureTouchItemBuffer *touch_buffer,
unsigned char slave_id,
uint32_t motor_frequency,
uint32_t touch_frequency,
int enable_stats);
int data_collector_start(CDataCollector *collector);
int data_collector_stop(CDataCollector *collector);
int data_collector_wait(CDataCollector *collector);
int data_collector_is_running(const CDataCollector *collector);
void data_collector_free(CDataCollector *collector);
/// Initialize SDK logging.
/// log_level: Log level (Debug, Info, Warn, Error). Default is Info.
void init_logging(LogLevel log_level);
/// List all available Stark serial ports.
void list_available_ports();
/// Automatically detect a Stark device on a serial port.
/// It first tries Revo2 hands and then Revo1 hands.
/// port: Serial port name; when NULL, the function will auto‑detect ports.
/// quick: Whether to use quick detection. Default is true, which only checks
/// a subset of baudrates and slave IDs.
/// Returns a pointer to `DeviceConfig` (protocol, port, baudrate, slave ID);
/// call `free_device_config` to free the memory.
/// On failure, returns NULL.
/// Note: When `quick` is false, this function scans slave IDs in [1, 247],
/// which may take a long time.
///
/// @deprecated Use `stark_auto_detect` + `init_from_detected` instead for better
/// multi-protocol support (Modbus, CAN, CANFD).
CDeviceConfig *auto_detect_device(const char *port, bool quick);
/// Automatically detect a Revo1 hand over Modbus.
/// port: Serial port name; when NULL, the function will auto‑detect ports.
/// quick: Whether to use quick detection. Default is true, which only checks
/// a subset of baudrates and slave IDs.
/// Returns a pointer to `DeviceConfig` (protocol, port, baudrate, slave ID);
/// call `free_device_config` to free the memory.
/// On failure, returns NULL.
/// Note: When `quick` is false, this function scans slave IDs in [1, 247],
/// which may take a long time.
///
/// @deprecated Use `stark_auto_detect` + `init_from_detected` instead for better
/// multi-protocol support (Modbus, CAN, CANFD).
CDeviceConfig *auto_detect_modbus_revo1(const char *port, bool quick);
/// Automatically detect a Revo2 hand over Modbus.
/// port: Serial port name; when NULL, the function will auto‑detect ports.
/// quick: Whether to use quick detection. Default is true, which only checks
/// a subset of baudrates and slave IDs.
/// Returns a pointer to `DeviceConfig` (protocol, port, baudrate, slave ID);
/// call `free_device_config` to free the memory.
/// On failure, returns NULL.
/// Note: When `quick` is false, this function scans slave IDs in [1, 247],
/// which may take a long time.
///
/// @deprecated Use `stark_auto_detect` + `init_from_detected` instead for better
/// multi-protocol support (Modbus, CAN, CANFD).
CDeviceConfig *auto_detect_modbus_revo2(const char *port, bool quick);
/// Open a serial port.
/// port: Serial port name, for example "/dev/ttyUSB0" or "COM1".
/// baudrate: Baud rate, one of 115200, 57600, 19200, 460800.
/// Revo1 default is 115200; Revo2 default is 460800, and Revo2 also
/// supports 1M, 2M, 5M.
/// Returns a pointer to `DeviceHandler`; call `modbus_close` to free it.
/// On failure, returns NULL.
DeviceHandler *modbus_open(const char *port, uint32_t baudrate);
/// Close serial port
void modbus_close(DeviceHandler *handle);
/// Open a Protobuf protocol serial port.
///
/// Protobuf protocol uses default baudrate 115200 and default slave_id 10.
/// Position range is 0-100 (not 0-1000 like Modbus/CAN).
///
/// @param port Serial port name, for example "/dev/ttyUSB0" or "COM1".
/// @param slave_id Device slave ID (default is 10)
/// @param baudrate Baudrate (pass 0 to use default 115200)
/// @return Pointer to `DeviceHandler`; call `protobuf_close` to free it.
/// On failure, returns NULL.
DeviceHandler *protobuf_open(const char *port, uint8_t slave_id, uint32_t baudrate);
/// Close Protobuf serial port
void protobuf_close(DeviceHandler *handle);
/// @brief Create a device handler with specified protocol and optional master ID.
/// @param protocol_type Protocol type (Modbus, CAN, CanFd, EtherCAT, Protobuf)
/// @param master_id Master ID (required for CanFd and EtherCAT, 0 for others)
/// @return Pointer to the newly created `DeviceHandler`. Call
/// `close_device_handler` to release it.
DeviceHandler *init_device_handler(StarkProtocolType protocol_type, uint8_t master_id);
/// @brief Create a device handler for CAN/CANFD protocol.
///
/// This function creates a device handler and stores the CAN baudrate information.
///
/// @param protocol_type Protocol type (STARK_PROTOCOL_TYPE_CAN or STARK_PROTOCOL_TYPE_CAN_FD)
/// @param master_id Master ID (typically 1)
/// @param arb_baudrate Arbitration baudrate in bps (e.g., 1000000 for 1 Mbps)
/// @param data_baudrate Data baudrate in bps (for CANFD; equals arb_baudrate for CAN 2.0)
/// @return Pointer to the newly created `DeviceHandler`. Call
/// `close_device_handler` to release it.
DeviceHandler *init_device_handler_can(StarkProtocolType protocol_type,
uint8_t master_id,
uint32_t arb_baudrate,
uint32_t data_baudrate);
/// @brief Create a device handler for CAN/CANFD protocol with hardware type pre-set.
///
/// @param protocol_type Protocol type (STARK_PROTOCOL_TYPE_CAN or STARK_PROTOCOL_TYPE_CAN_FD)
/// @param master_id Master ID (typically 1)
/// @param slave_id Slave ID to set hardware type for
/// @param arb_baudrate Arbitration baudrate in bps (e.g., 1000000 for 1 Mbps)
/// @param data_baudrate Data baudrate in bps (for CANFD; equals arb_baudrate for CAN 2.0)
/// @param hw_type Hardware type (StarkHardwareType enum value)
/// @return Pointer to the newly created `DeviceHandler`. Call
/// `close_device_handler` to release it.
DeviceHandler *init_device_handler_can_with_hw_type(StarkProtocolType protocol_type,
uint8_t master_id,
uint8_t slave_id,
uint32_t arb_baudrate,
uint32_t data_baudrate,
StarkHardwareType hw_type);
/// @brief Create a device handler with hardware type pre-set.
///
/// This is useful when you already know the hardware type (e.g., from auto_detect)
/// and want to avoid an extra get_device_info call.
///
/// @param protocol_type Protocol type (Modbus, CAN, CanFd, EtherCAT, Protobuf)
/// @param master_id Master ID (required for CanFd and EtherCAT, 0 for others)
/// @param slave_id Slave ID to set hardware type for
/// @param hw_type Hardware type (StarkHardwareType enum value)
/// @return Pointer to the newly created `DeviceHandler`. Call
/// `close_device_handler` to release it.
DeviceHandler *init_device_handler_with_hw_type(StarkProtocolType protocol_type,
uint8_t master_id,
uint8_t slave_id,
StarkHardwareType hw_type);
/// List all ZQWL USB CAN/CANFD devices
///
/// Returns device list pointer. Call `free_zqwl_device_list` to free memory after use.
/// Returns list with count=0 if no devices found.
///
/// @note This is a low-level API. Recommend using high-level API `stark_auto_detect` + `init_from_detected`
/// for automatic device detection and initialization. Low-level API is for advanced users
/// who need manual control of CAN adapter.
ZqwlDeviceList *list_zqwl_devices();
/// Free ZQWL device list memory
void free_zqwl_device_list(ZqwlDeviceList *list);
/// Initialize ZQWL CAN device (CAN 2.0 mode)
///
/// For Revo1 devices, baudrate is typically 1Mbps
///
/// @param port_name Serial port name, e.g. "/dev/cu.usbmodem*" (macOS) or "COM3" (Windows)
/// @param arb_baudrate Arbitration baudrate (bps), typically 1000000
/// @return 0: success, -1: failure
///
/// @note This is a low-level API. Recommend using high-level API `stark_auto_detect` + `init_from_detected`
/// for automatic device detection and initialization. Low-level API is for advanced users
/// who need manual control of CAN adapter.
int init_zqwl_can(const char *port_name,
uint32_t arb_baudrate);
/// Initialize ZQWL CANFD device
///
/// For Revo2 devices, arbitration baudrate is typically 1Mbps, data baudrate is typically 5Mbps
///
/// @param port_name Serial port name
/// @param arb_baudrate Arbitration baudrate (bps), typically 1000000
/// @param data_baudrate Data baudrate (bps), typically 5000000
/// @return 0: success, -1: failure
///
/// @note This is a low-level API. Recommend using high-level API `stark_auto_detect` + `init_from_detected`
/// for automatic device detection and initialization. Low-level API is for advanced users
/// who need manual control of CAN adapter.
int init_zqwl_canfd(const char *port_name,
uint32_t arb_baudrate,
uint32_t data_baudrate);
/// Close ZQWL CAN/CANFD device
///
/// @note This is a low-level API. If device was initialized with `init_from_detected`,
/// use `close_device_handler` instead, which automatically handles ZQWL resource cleanup.
void close_zqwl();
/// List all SocketCAN interfaces (Linux only)
///
/// Scans /sys/class/net/ for CAN interfaces.
/// Returns device list pointer. Call `free_socketcan_device_list` to free memory.
/// Returns list with count=0 on non-Linux platforms or if no interfaces found.
SocketCanDeviceList *list_socketcan_devices();
/// Free SocketCAN device list memory
void free_socketcan_device_list(SocketCanDeviceList *list);
/// Initialize SocketCAN CAN 2.0 device (Linux only)
///
/// @param iface Interface name (e.g. "can0"). If NULL, uses STARK_SOCKETCAN_IFACE env var or "can0"
/// @return 0: success, -1: failure (or non-Linux platform)
int init_socketcan_can(const char *iface);
/// Initialize SocketCAN CANFD device (Linux only)
///
/// @param iface Interface name (e.g. "can0"). If NULL, uses STARK_SOCKETCAN_IFACE env var or "can0"
/// @return 0: success, -1: failure (or non-Linux platform)
int init_socketcan_canfd(const char *iface);
/// Close SocketCAN device (Linux only)
void close_socketcan();
/// Check if a SocketCAN interface is available and up (Linux only)
///
/// @param iface Interface name (e.g. "can0")
/// @return true if interface exists and is up, false otherwise
bool is_socketcan_available(const char *iface);
/// Scan CAN bus for devices (simple version)
///
/// Uses get_can_params to read SkuType for device detection
///
/// @param candidate_ids Pointer to array of candidate device IDs
/// @param candidate_count Number of candidate device IDs
/// @param timeout_ms Timeout in milliseconds
/// @return Found device ID (1-255), or 0 if no device found
uint8_t scan_can_devices(const uint8_t *candidate_ids,
uintptr_t candidate_count,
uint64_t timeout_ms);
/// Auto-detect Stark devices across all protocols
///
/// Scans for devices in priority order:
/// 1. ZQWL CANFD (IDs 0x7E, 0x7F) → CAN 2.0 (IDs 1, 2) (USB CDC, cross-platform)
/// 2. SocketCAN CANFD (IDs 0x7E, 0x7F) → CAN 2.0 (IDs 1, 2) (Linux only)
/// 3. Modbus/RS485 (IDs 0x7E, 0x7F, 1, 2 at 460800/115200/1Mbps/2Mbps)
/// 4. Protobuf (legacy RS485, ID 10, 115200 baud)
///
/// When a specific protocol is requested, only that protocol is scanned.
///
/// # Parameters
/// - scan_all: If true, scan for all devices. If false, stop at first found.
/// - port: Optional port name to scan. If NULL, scans all available ports.
/// - protocol: Protocol filter:
/// - STARK_PROTOCOL_TYPE_AUTO: Auto-detect all protocols (recommended)
/// - STARK_PROTOCOL_TYPE_MODBUS: Modbus only
/// - STARK_PROTOCOL_TYPE_CAN: CAN 2.0 only
/// - STARK_PROTOCOL_TYPE_CAN_FD: CANFD only
/// - STARK_PROTOCOL_TYPE_PROTOBUF: Protobuf only
///
/// # Returns
/// Pointer to CDetectedDeviceList. Call `free_detected_device_list` to free.
/// Returns empty list (count=0) if no devices found.
CDetectedDeviceList *stark_auto_detect(bool scan_all, const char *port, StarkProtocolType protocol);
/// Free detected device list memory
void free_detected_device_list(CDetectedDeviceList *list);
/// Initialize device handler from detected device info.
///
/// This function initializes the appropriate transport (Modbus, CAN, CANFD)
/// based on the detected device's protocol and returns a ready-to-use handler.
///
/// # Parameters
/// - device: Pointer to CDetectedDevice from stark_auto_detect()
///
/// # Returns
/// - Pointer to DeviceHandler on success
/// - NULL on failure
///
/// # Notes
/// - For CAN/CANFD: Initializes BrainCo/ZQWL/SocketCAN adapter automatically
/// - For Modbus: Opens serial port with detected baudrate
/// - Call `close_from_detected` to cleanup
DeviceHandler *init_from_detected(const CDetectedDevice *device);
/// Close device handler based on protocol type.
///
/// Convenience function that handles cleanup for any protocol type.
/// Automatically closes ZQWL adapter for CAN/CANFD protocols.
///
/// # Parameters
/// - handle: Device handler to close
/// - protocol: Protocol type (from CDetectedDevice.protocol)
void close_device_handler(DeviceHandler *handle, uint8_t protocol);
/// Configure SDO for an EtherCAT slave device.
void ethercat_setup_sdo(DeviceHandler *handle, uint16_t slave_pos);
void ethercat_reserve_master(DeviceHandler *handle);
/// Start EtherCAT cyclic loop with PDO communication (control & read).
/// dc_assign_activate: DC flags; 0x0000 means DC is not enabled.
/// sync0_cycle_time: SYNC0 cycle time in nanoseconds. The loop period matches
/// SYNC0 cycle time.
/// sync0_shift_time: SYNC0 phase shift in nanoseconds.
/// sync1_cycle_time: SYNC1 cycle time in nanoseconds.
/// sync1_shift_time: SYNC1 phase shift in nanoseconds.
void ethercat_start_loop(DeviceHandler *handle,
const uint16_t *slave_positions,
int count,
uint16_t dc_assign_activate,
uint32_t sync0_cycle_time,
int32_t sync0_shift_time,
uint32_t sync1_cycle_time,
int32_t sync1_shift_time);
/// Stop the EtherCAT cyclic loop.
void ethercat_stop_loop(DeviceHandler *handle);
/// EtherCAT DFU: upgrade firmware via FoE protocol.
/// slave_pos: Slave position.
/// dfu_type: DFU type, Control or Wrist.
/// file_path: Firmware file path.
void ethercat_start_dfu(DeviceHandler *handle,
uint16_t slave_pos,
EtherCATFoeType dfu_type,
const char *file_path);
/// Set Modbus async read/write callback.
void set_modbus_operation_callback(ModbusOperationCallback cb);
/// Set Modbus read callback for input registers.
void set_modbus_read_input_callback(ModbusRxCallback cb);
/// Set Modbus read callback for holding registers.
void set_modbus_read_holding_callback(ModbusRxCallback cb);
/// Set Modbus write callback.
void set_modbus_write_callback(ModbusTxCallback cb);
/// Set CAN/CANFD RX callback.
void set_can_rx_callback(CanRxCallback cb);
/// Set CAN/CANFD TX callback.
void set_can_tx_callback(CanTxCallback cb);
/// Set DFU state callback.
void set_dfu_state_callback(DfuStateCallback cb);
/// Set DFU progress callback.
void set_dfu_progress_callback(DfuProgressCallback cb);
/// Get device information.
/// Returns a pointer to `DeviceInfo`; you must call `free_device_info` to free
/// it. Returns NULL on failure.
///
/// NOTE: Hardware type is determined by SN prefix. If the SN is not recognized,
/// hardware_type defaults to Revo2Basic. Use `stark_set_hardware_type()` to
/// manually override if needed.
CDeviceInfo *stark_get_device_info(DeviceHandler *handle, uint8_t slave_id);
/// Set hardware type for a specific slave device.
///
/// Use this to manually override the hardware type when SN-based auto-detection
/// in `stark_get_device_info()` returns an incorrect result (e.g. device SN not
/// yet programmed, defaults to Revo2Basic).
///
/// Can also be used to modify `CDetectedDevice.hardware_type` before calling
/// `init_from_detected()`, or to override after initialization.
///
/// # Parameters
/// - handle: Device handler
/// - slave_id: The slave ID
/// - hw_type: StarkHardwareType enum value
void stark_set_hardware_type(DeviceHandler *handle, uint8_t slave_id, StarkHardwareType hw_type);
/// Read holding registers (fast, no retry).
/// address: Start register address.
/// count: Number of registers to read.
/// out_data: Pointer to array to store data (caller must allocate enough space).
/// Returns 0 on success, -1 on failure.
int32_t stark_read_holding_registers(DeviceHandler *handle,
uint8_t slave_id,
uint16_t address,
uint16_t count,
uint16_t *out_data);
/// Read input registers (fast, no retry).
/// address: Start register address.
/// count: Number of registers to read.
/// out_data: Pointer to array to store data (caller must allocate enough space).
/// Returns 0 on success, -1 on failure.
int32_t stark_read_input_registers(DeviceHandler *handle,
uint8_t slave_id,
uint16_t address,
uint16_t count,
uint16_t *out_data);
/// Get the protocol type of the device handler.
/// Returns: StarkProtocolType enum value:
/// - STARK_PROTOCOL_TYPE_MODBUS = 1
/// - STARK_PROTOCOL_TYPE_CAN = 2
/// - STARK_PROTOCOL_TYPE_CAN_FD = 3
/// - STARK_PROTOCOL_TYPE_ETHER_CAT = 4
/// - STARK_PROTOCOL_TYPE_PROTOBUF = 5
StarkProtocolType stark_get_protocol_type(DeviceHandler *handle);
/// Get the serial port name of the device handler.
/// Returns: Port name string (e.g., "/dev/ttyUSB0" or "COM3"), or NULL if not available.
/// The returned string is owned by the DeviceHandler and should not be freed.
/// For CAN/CANFD protocols, this may return an empty string.
const char *stark_get_port_name(DeviceHandler *handle);
/// Get the baudrate of the device handler.
/// Returns: Baudrate in bps (e.g., 115200, 460800), or 0 if not applicable.
/// For Modbus/Protobuf: returns serial baudrate
/// For CAN/CANFD/EtherCAT: returns 0 (use stark_get_can_arb_baudrate/stark_get_can_data_baudrate instead)
///
/// Note: This function only returns serial port baudrate.
/// For CAN baudrate information, use:
/// - stark_get_can_arb_baudrate() - Get CAN arbitration baudrate
/// - stark_get_can_data_baudrate() - Get CAN data baudrate (CANFD only)
uint32_t stark_get_baudrate(DeviceHandler *handle);
/// Get the CAN arbitration baudrate.
/// Returns: Arbitration baudrate in bps (e.g., 1000000 for 1 Mbps), or 0 if not CAN/CANFD protocol.
/// For CAN 2.0: This is the only baudrate
/// For CANFD: This is the arbitration phase baudrate
uint32_t stark_get_can_arb_baudrate(DeviceHandler *handle);
/// Get the CAN data baudrate.
/// Returns: Data baudrate in bps (e.g., 5000000 for 5 Mbps), or 0 if not CANFD protocol.
/// For CAN 2.0: Returns the same as arbitration baudrate
/// For CANFD: Returns the data phase baudrate
uint32_t stark_get_can_data_baudrate(DeviceHandler *handle);
/// Get touch sensor vendor type by reading register 970.
/// Returns: 0=Unknown, 1=Capacitive, 2=Pressure
/// This should be called for Revo2 Touch devices to determine the actual touch sensor type.
uint8_t stark_get_touch_vendor(DeviceHandler *handle, uint8_t slave_id);
/// Set force level (only supported on Revo1 Basic).
///
/// @deprecated This function is deprecated and only works on Revo1 Basic devices.
/// Use `stark_set_finger_current` or `stark_set_finger_currents` instead for
/// more precise force control on all device types.
void stark_set_force_level(DeviceHandler *handle, uint8_t slave_id, ForceLevel level);
/// Get force level (only supported on Revo1 Basic).
///
/// @deprecated This function is deprecated and only works on Revo1 Basic devices.
/// Use `stark_get_motor_status` instead to get current values for all device types.
uint8_t stark_get_force_level(DeviceHandler *handle, uint8_t slave_id);
/// Get device supply voltage in mV.
uint16_t stark_get_voltage(DeviceHandler *handle, uint8_t slave_id);
/// Get LED enabled state.
bool get_led_enabled(DeviceHandler *handle, uint8_t slave_id);
/// Get buzzer enabled state.
bool get_buzzer_enabled(DeviceHandler *handle, uint8_t slave_id);
/// Get vibration enabled state.
bool get_vibration_enabled(DeviceHandler *handle, uint8_t slave_id);
/// Set LED enabled state.
void set_led_enabled(DeviceHandler *handle, uint8_t slave_id, bool enabled);
/// Set buzzer enabled state.
void set_buzzer_enabled(DeviceHandler *handle, uint8_t slave_id, bool enabled);
/// Set vibration enabled state.
void set_vibration_enabled(DeviceHandler *handle, uint8_t slave_id, bool enabled);
/// Configure unit mode and finger parameters for Revo2.
/// This setting is reset after power‑cycle.
/// Parameter ranges are documented here:
/// https://brainco.yuque.com/tykrbo/hws0nr/pynh5qnmfa1bgamc
/// Sets the control unit mode:
/// normalized mode or physical‑quantity mode.
void stark_set_finger_unit_mode(DeviceHandler *handle, uint8_t slave_id, FingerUnitMode mode);
/// Get the current control unit mode.
/// Returns `FingerUnitMode`; on failure returns `FingerUnitMode::Normalized`.
FingerUnitMode stark_get_finger_unit_mode(DeviceHandler *handle, uint8_t slave_id);
/// Set maximum angle for a finger.
/// max_pos: Maximum angle value; default is 60 87 84 84 84 84.
void stark_set_finger_max_position(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id,
uint16_t max_pos);
/// Set minimum angle for a finger.
/// min_pos: Minimum angle in degrees; default is 0 0 0 0 0 0.
void stark_set_finger_min_position(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id,
uint16_t min_pos);
/// Set maximum speed for a finger.
/// max_speed: Maximum speed in °/s; default is 145 150 130 130 130 130.
void stark_set_finger_max_speed(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id,
uint16_t max_speed);
/// Set maximum current for a finger.
/// max_current: Maximum current in mA; default is 1000.
void stark_set_finger_max_current(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id,
uint16_t max_current);
/// Set protection current for a finger.
/// protected_current: Protection current in mA, range 100~1500, default
/// 500 500 500 500 500 500.
void stark_set_finger_protected_current(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id,
uint16_t protected_current);
/// Read maximum angle for a finger.
/// Returns 0 on failure.
uint16_t stark_get_finger_max_position(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id);
/// Read minimum angle for a finger.
/// min_pos: Minimum angle in degrees; default is 0 0 0 0 0 0.
uint16_t stark_get_finger_min_position(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id);
/// Read maximum speed for a finger.
/// max_speed: Maximum speed in °/s; default is 145 150 130 130 130 130.
/// Returns 0 on failure.
uint16_t stark_get_finger_max_speed(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id);
/// Read maximum current for a finger.
/// max_current: Maximum current in mA; default is 1000.
/// Returns 0 on failure.
uint16_t stark_get_finger_max_current(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id);
/// Read protection current for a finger.
/// protected_current: Protection current in mA, range 100~1500, default
/// 500 500 500 500 500 500.
/// Returns 0 on failure.
uint16_t stark_get_finger_protected_current(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id);
/// Configure thumb AUX lock current.
/// aux_lock_current: in mA, range 100~500, default 200.
/// Only supported on Revo2.
void stark_set_thumb_aux_lock_current(DeviceHandler *handle,
uint8_t slave_id,
uint16_t aux_lock_current);
/// Read thumb AUX lock current.
/// Only supported on Revo2.
uint16_t stark_get_thumb_aux_lock_current(DeviceHandler *handle, uint8_t slave_id);
/// Set the position of a single finger.
///
/// # Parameters
/// - `position`: Position in the unified range **0~1000** (all devices,
/// all protocols).
/// - The SDK converts this internally based on device type and protocol.
/// - 0 means fully open, 1000 means fully closed.
///
/// # Unified range
/// For both Revo1 and Revo2, and for Modbus, CAN 2.0, and CANFD, the public
/// API always uses the 0~1000 range; the SDK handles conversion internally.
void stark_set_finger_position(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id,
uint16_t position);
/// Set the speed of a single finger.
///
/// # Parameters
/// - `speed`: Speed in the unified range **-1000~+1000** (all devices,
/// all protocols).
/// - The SDK converts this internally based on device type and protocol.
/// - Positive: closing direction; negative: opening direction.
/// - 0: stop.
///
/// # Unified range
/// For both Revo1 and Revo2, and for Modbus, CAN 2.0, and CANFD, the public
/// API always uses the -1000~+1000 range; the SDK handles conversion internally.
void stark_set_finger_speed(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id,
int16_t speed);
/// Set the current of a single finger.
///
/// # Parameters
/// - `current`: Current in the unified range **-1000~+1000** (all devices,
/// all protocols).
/// - The SDK converts this internally based on device type and protocol.
/// - Positive: closing direction; negative: opening direction.
///
/// # Unified range
/// For both Revo1 and Revo2, and for Modbus, CAN 2.0, and CANFD, the public
/// API always uses the -1000~+1000 range; the SDK handles conversion internally.
void stark_set_finger_current(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id,
int16_t current);
/// Set the PWM of a single finger (Revo2 only).
///
/// # Parameters
/// - `pwm`: PWM value in the unified range **-1000~+1000** (all protocols).
/// - The SDK converts this internally based on protocol.
/// - Positive: closing direction; negative: opening direction.
///
/// # Unified range
/// For Modbus, CAN 2.0, and CANFD, the public API always uses the
/// -1000~+1000 range; the SDK handles conversion internally.
void stark_set_finger_pwm(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id,
int16_t pwm);
/// Set position + desired time for a single finger (Revo2 only).
///
/// # Parameters
/// - `position`: Position in the unified range **0~1000** (all protocols).
/// - `millis`: Desired time in milliseconds, range 1~2000.
///
/// # Unified range
/// Position always uses the 0~1000 range; the SDK handles conversion internally.
void stark_set_finger_position_with_millis(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id,
uint16_t position,
uint16_t millis);
/// Set position + desired speed for a single finger (Revo2 only).
///
/// # Parameters
/// - `position`: Position in the unified range **0~1000** (all protocols).
/// - `speed`: Speed value, range 1~1000.
///
/// # Unified range
/// Position always uses the 0~1000 range; the SDK handles conversion internally.
void stark_set_finger_position_with_speed(DeviceHandler *handle,
uint8_t slave_id,
StarkFingerId finger_id,
uint16_t position,
uint16_t speed);
/// Set positions for multiple fingers.
///
/// # Parameters
/// - `positions`: Array of length 6, positions in the unified range
/// **0~1000** (all devices, all protocols).
/// - The SDK converts this internally based on device type and protocol.
/// - 0 means fully open, 1000 means fully closed.
///
/// # Unified range
/// For both Revo1 and Revo2, and for Modbus, CAN 2.0, and CANFD, the public
/// API always uses the 0~1000 range; the SDK handles conversion internally.
void stark_set_finger_positions(DeviceHandler *handle,
uint8_t slave_id,
const uint16_t *positions,
uintptr_t len);
/// Set speeds for multiple fingers.
///
/// # Parameters
/// - `speeds`: Array of length 6, speeds in the unified range **-1000~+1000**
/// (all devices, all protocols).
/// - The SDK converts this internally based on device type and protocol.
/// - Positive: closing direction; negative: opening direction.
/// - 0: stop.
///
/// # Unified range
/// For both Revo1 and Revo2, and for Modbus, CAN 2.0, and CANFD, the public
/// API always uses the -1000~+1000 range; the SDK handles conversion internally.
void stark_set_finger_speeds(DeviceHandler *handle,
uint8_t slave_id,
const int16_t *speeds,
uintptr_t len);
/// Set currents for multiple fingers.
///
/// # Parameters
/// - `currents`: Array of length 6, currents in the unified range
/// **-1000~+1000** (all devices, all protocols).
/// - The SDK converts this internally based on device type and protocol.
/// - Positive: closing direction; negative: opening direction.
///
/// # Unified range
/// For both Revo1 and Revo2, and for Modbus, CAN 2.0, and CANFD, the public
/// API always uses the -1000~+1000 range; the SDK handles conversion internally.
void stark_set_finger_currents(DeviceHandler *handle,
uint8_t slave_id,
const int16_t *currents,
uintptr_t len);
/// Set PWM values for multiple fingers (Revo2 only).
///
/// # Parameters
/// - `pwms`: Array of length 6, PWM values in the unified range
/// **-1000~+1000** (all protocols).
/// - The SDK converts this internally based on protocol.
/// - Positive: closing direction; negative: opening direction.
///
/// # Unified range
/// For Modbus, CAN 2.0, and CANFD, the public API always uses the
/// -1000~+1000 range; the SDK handles conversion internally.
void stark_set_finger_pwms(DeviceHandler *handle,
uint8_t slave_id,
const int16_t *pwms,
uintptr_t len);
/// Set positions + desired times for multiple fingers (Revo2 only).
///
/// # Parameters
/// - `positions`: Array of length 6, positions in the unified range
/// **0~1000** (all protocols).
/// - `millis`: Array of length 6, desired times in milliseconds, range 1~2000.
///
/// # Unified range
/// Position always uses the 0~1000 range; the SDK handles conversion internally.
void stark_set_finger_positions_and_durations(DeviceHandler *handle,
uint8_t slave_id,
const uint16_t *positions,
const uint16_t *millis,
uintptr_t len);
/// Set positions + desired speeds for multiple fingers (Revo2 only).
///
/// # Parameters
/// - `positions`: Array of length 6, positions in the unified range
/// **0~1000** (all protocols).
/// - `speeds`: Array of length 6, speeds in the range 1~1000.
///
/// # Unified range
/// Position always uses the 0~1000 range; the SDK handles conversion internally.
void stark_set_finger_positions_and_speeds(DeviceHandler *handle,
uint8_t slave_id,
const uint16_t *positions,
const uint16_t *speeds,
uintptr_t len);
/// Get finger motor status.
///
/// # Return value
/// Returns a pointer to `MotorStatusData`, which contains:
/// - `positions`: Position array, unified range **0~1000** (all devices,
/// all protocols).
/// - `speeds`: Speed array, unified range **-1000~+1000** (all devices,
/// all protocols).
/// - `currents`: Current array, unified range **-1000~+1000** (all devices,
/// all protocols).
/// - `states`: Motor state array.
///
/// # Unified range
/// For both Revo1 and Revo2, and for Modbus, CAN 2.0, and CANFD, the returned
/// data is always converted to the unified ranges above; the SDK handles
/// conversion internally.
///
/// # Memory management
/// You must call `free_motor_status_data` to free the result.
/// Returns NULL on failure.
CMotorStatusData *stark_get_motor_status(DeviceHandler *handle, uint8_t slave_id);
/// Run an action sequence.
/// action_id: Action sequence ID.
void stark_run_action_sequence(DeviceHandler *handle, uint8_t slave_id, ActionSequenceId action_id);
/// Transfer action sequences to the device.
///
/// This function sends multiple action sequences. Each sequence is represented
/// by a fixed‑length array of `u16` parameters.
///
/// - `slave_id`: Slave device ID.
/// - `uses_revo2_motor_api`: Whether the device uses Revo2 Motor API.
/// (Revo1 Advanced/AdvancedTouch and all Revo2 use Revo2 Motor API)
/// - `action_id`: ID that uniquely identifies the action sequence.
/// - `sequences`: Flattened parameter array containing multiple sequences.
///
/// For Revo1, each action sequence contains 20 `u16` elements:
/// - Sequence index (u16): index of the sequence in the queue.
/// - Duration (u16): execution time in milliseconds.
/// - Finger positions (6 × u16): values in range 0~100.
/// - Finger speeds (6 × u16): values in range 0~100.
/// - Finger forces (6 × u16): values in range 0~100.
///
/// Example sequence array:
/// [0, 2000, 0, 0, 100, 100, 100, 100, 10, 20, 30, 40, 50, 60, 5, 10, 15, 20, 25, 30]
///
/// Meaning:
/// - `0`: sequence index.
/// - `2000`: duration in milliseconds.
/// - `0, 0, 100, 100, 100, 100`: 6 finger positions.
/// - `10, 20, 30, 40, 50, 60`: 6 finger speeds.
/// - `5, 10, 15, 20, 25, 30`: 6 finger forces.
///
/// For Revo2, each action sequence contains 27 `u16` elements:
/// - Sequence index (u16): index of the sequence in the queue.
/// - Duration (u16): execution time in milliseconds.
/// - Control mode (u16): 1=position+time, 2=position+speed,
/// 3=current, 4=speed.
/// - Finger positions (6 × u16): physical angle in degrees; 65535 (0xFFFF)
/// means keep current angle.
/// - Finger speeds (6 × u16): physical rotational speed in °/s.
/// - Finger currents (6 × u16): physical current in mA.
///
/// - `len`: Number of sequences, i.e. number of rows in the flattened array.
///
/// # Parameters
/// - `action_id`: Action sequence ID.
/// - `sequences`: Pointer to the flattened sequence array.
/// - `len`: Number of sequences.
///
/// # Error handling
/// - If `handle` or `sequences` is NULL, the function returns immediately.
/// - If `len` exceeds the maximum allowed steps (Revo1: 32, Revo2: 8), a
/// warning is logged and the function returns.
void stark_set_action_sequence(DeviceHandler *handle,
uint8_t slave_id,
bool uses_revo2_motor_api,
ActionSequenceId action_id,
const uint16_t *sequences,
uintptr_t len);
/// Enable tactile sensors.
/// bits: Bitmask of sensors to enable, range 0~31.
/// For example: 0b00000001 enables only the thumb sensor.
void stark_enable_touch_sensor(DeviceHandler *handle, uint8_t slave_id, uint8_t bits);
/// Get raw channel data from the tactile sensors.
/// Returns a pointer to `TouchRawData`; call `free_touch_raw_data` to free it.
/// Returns NULL on failure.
CTouchRawData *stark_get_touch_raw_data(DeviceHandler *handle, uint8_t slave_id);
/// Read 3D force, proximity and status for a single finger.
/// Returns a pointer to `TouchFingerItem`.
/// index: 0~4 for thumb, index, middle, ring, pinky.
/// Call `free_touch_finger_item` to free the result. Returns NULL on failure.
CTouchFingerItem *stark_get_single_touch_status(DeviceHandler *handle,
uint8_t slave_id,
uint8_t index);
/// Read 3D force, proximity and status for all five fingers.
/// Returns a pointer to `TouchFingerData` containing all fingers.
/// Call `free_touch_finger_data` to free the result. Returns NULL on failure.
CTouchFingerData *stark_get_touch_status(DeviceHandler *handle, uint8_t slave_id);
/// Reset tactile sensor measurement channels.
/// Try to keep the fingers unloaded (no force) when executing this command.
/// bits: Bitmask of sensors to reset, range 0~31.
/// For example: 0b00000001 resets the first sensor.
void stark_reset_touch_sensor(DeviceHandler *handle, uint8_t slave_id, uint8_t bits);
/// Get touch sensor type from hardware type.
/// Returns: 0=None, 1=Capacitive, 2=Pressure
/// This is a pure function based on hardware type classification.
uint8_t stark_get_touch_sensor_type(uint8_t hw_type);
/// Check if hardware type has touch sensor.
/// Returns: true if device has touch sensor, false otherwise.
bool stark_is_touch_device(uint8_t hw_type);
/// Check if hardware type is Revo1 device (motor API perspective).
/// Check if hardware type uses Revo1 Motor API.
/// Revo1 Basic/Touch use Revo1 Motor API.
/// Revo1 Advanced/AdvancedTouch and all Revo2 use Revo2 Motor API.
/// Note: Revo1Protobuf is legacy firmware, also uses Revo1 Motor API.
/// Returns: true if uses Revo1 Motor API, false if uses Revo2 Motor API.
bool stark_uses_revo1_motor_api(uint8_t hw_type);
/// Check if hardware type uses Revo1 Touch API.
/// Revo1 Touch API has different sensor counts per finger (capacitive).
/// Returns: true if uses Revo1 Touch API, false otherwise.
bool stark_uses_revo1_touch_api(uint8_t hw_type);
/// Calibrate tactile sensor parameters.
/// bits: Bitmask of sensors to calibrate, range 0~31.
/// For example: 0b00000001 calibrates the first sensor.
/// Use this when 3D force values are non‑zero in idle state.
/// https://www.brainco-hz.com/docs/revolimb-hand/protocol/stark_protocol_touch.html#_5-3-%E5%8F%82%E6%95%B0%E6%A0%A1%E5%87%864105
void stark_calibrate_touch_sensor(DeviceHandler *handle,
uint8_t slave_id,
uint8_t bits);
/// Check if hardware type uses Revo2 Touch API.
/// Revo2 Touch API has uniform sensor counts per finger (capacitive).
/// Returns: true if uses Revo2 Touch API, false otherwise.
bool stark_uses_revo2_touch_api(uint8_t hw_type);
/// Check if hardware type uses Pressure/Modulus Touch API.
/// Pressure Touch API uses completely different data structure (pressure sensors).
/// Returns: true if uses Pressure Touch API, false otherwise.
bool stark_uses_pressure_touch_api(uint8_t hw_type);
/// Get RS485 serial baud rate.
/// Valid values: 115200, 57600, 19200, 460800.
uint32_t stark_get_rs485_baudrate(DeviceHandler *handle, uint8_t slave_id);
/// Set RS485 serial baud rate.
/// Supported values: 115200, 57600, 19200, 460800.
void stark_set_rs485_baudrate(DeviceHandler *handle, uint8_t slave_id, uint32_t baudrate);
/// Get CANFD baud rate.
/// Supported values: 1M, 2M, 4M, 5M.
uint32_t stark_get_canfd_baudrate(DeviceHandler *handle, uint8_t slave_id);
/// Set CANFD baud rate.
/// Supported values: 1M, 2M, 4M, 5M.
void stark_set_canfd_baudrate(DeviceHandler *handle, uint8_t slave_id, uint32_t baudrate);
/// Set device slave ID.
/// Default is 1, valid range 1~247; 0 is the broadcast address.
/// Revo1 default ID is 1; Revo2 default left/right IDs are 0x7E and 0x7F.
/// When controlling multiple devices on the same bus, assign different IDs,
/// e.g. left=1, right=2.
/// Using broadcast ID 0 controls all devices on the bus; per Modbus spec,
/// broadcast commands do not receive responses.
void stark_set_slave_id(DeviceHandler *handle, uint8_t slave_id, uint8_t new_id);
/// Get Force3D touch summary data (4 fingers, no thumb).
/// Returns a pointer to `CForce3DTouchSummary`; call `free_force3d_touch_summary` to free it.
/// Returns NULL on failure.
CForce3DTouchSummary *stark_get_force3d_touch_summary(DeviceHandler *handle, uint8_t slave_id);
/// Free Force3D touch summary data.
void free_force3d_touch_summary(CForce3DTouchSummary *ptr);
/// Get Force3D finger array data (31 measurement points).
/// finger: 0=index, 1=middle, 2=ring, 3=pinky
/// Returns a pointer to `CForce3DFingerArray`; call `free_force3d_finger_array` to free it.
/// Returns NULL on failure.
CForce3DFingerArray *stark_get_force3d_finger_array(DeviceHandler *handle,
uint8_t slave_id,
uint8_t finger);
/// Free Force3D finger array data.
void free_force3d_finger_array(CForce3DFingerArray *ptr);
/// Check if device uses Revo2 Motor API.
///
/// Revo1 Advanced/AdvancedTouch and all Revo2 use Revo2 Motor API.
/// Revo1 Basic/Touch use Revo1 Motor API.
bool device_info_uses_revo2_motor_api(const CDeviceInfo *info);
/// Check if device uses Revo2 Touch API.
///
/// Includes capacitive (Revo2Touch), pressure (Revo2TouchPressure),
/// force3D (Revo2TouchForce3D), and array pressure (Revo2TouchArrayPressure) sensors.
bool device_info_uses_revo2_touch_api(const CDeviceInfo *info);
/// Check if device has any touch sensor
bool device_info_is_touch(const CDeviceInfo *info);
void free_motor_status_data(CMotorStatusData *data);
void free_touch_raw_data(CTouchRawData *data);
void free_touch_finger_data(CTouchFingerData *status);
void free_touch_finger_item(CTouchFingerItem *item);
void free_turbo_config(CTurboConfig *config);
void free_led_info(CLedInfo *info);
void free_button_event(CButtonPressEvent *event);
/// Get ArrayPressure touch data (status + 25 registers).
/// Returns a pointer to `CArrayPressureTouchData`; call `free_array_pressure_touch_data` to free it.
/// Returns NULL on failure.
CArrayPressureTouchData *stark_get_array_pressure_touch_data(DeviceHandler *handle,
uint8_t slave_id);
/// Free ArrayPressure touch data.
void free_array_pressure_touch_data(CArrayPressureTouchData *ptr);
/// Set ArrayPressure device sleep mode.
/// enable: 1=sleep, 0=wake
void stark_set_array_pressure_sleep(DeviceHandler *handle, uint8_t slave_id, bool enable);
/// Get finger backlash compensation values (6 values, unit °×10).
/// Returns pointer to array of 6 u16 values; caller must free with `free_u16_array`.
/// Returns NULL on failure.
uint16_t *stark_factory_get_backlash(DeviceHandler *handle, uint8_t slave_id, uint16_t *out_len);
/// Set finger backlash compensation values (6 values, unit °×10).
/// Requires factory key to be set first.
void stark_factory_set_backlash(DeviceHandler *handle,
uint8_t slave_id,
const uint16_t *values,
uint16_t len);
/// Trigger finger backlash self-check.
/// finger_id: 0=thumb_tip, 1=thumb_root, 2=index, 3=middle, 4=ring, 5=pinky
/// Requires factory key to be set first.
void stark_factory_backlash_self_check(DeviceHandler *handle, uint8_t slave_id, uint8_t finger_id);
/// Query whether automatic position calibration on power‑up is enabled.
bool stark_get_auto_calibration(DeviceHandler *handle, uint8_t slave_id);
/// Enable or disable automatic position calibration on power‑up.
void stark_set_auto_calibration(DeviceHandler *handle, uint8_t slave_id, bool enabled);
/// Send manual position‑calibration command.
void stark_send_calibrate_position(DeviceHandler *handle, uint8_t slave_id);
/// Reset default gestures to factory settings.
void stark_reset_default_gesture(DeviceHandler *handle, uint8_t slave_id);
/// Reset all settings to factory defaults.
/// ● Default IDs: left hand → 0x7E (126); right hand → 0x7F (127).
/// ● RS485 baud rate: 460800 bps.
/// ● CAN FD baud rate: 5 Mbps.
void stark_reset_default_settings(DeviceHandler *handle, uint8_t slave_id);
/// Check whether Turbo mode is enabled.
/// When enabled, the hand will keep squeezing continuously.
bool stark_get_turbo_mode_enabled(DeviceHandler *handle, uint8_t slave_id);
/// Enable or disable Turbo mode.
void stark_set_turbo_mode_enabled(DeviceHandler *handle, uint8_t slave_id, bool enabled);
/// Get Turbo mode configuration.
/// Returns a pointer to `TurboConfig`; call `free_turbo_config` to free it.
/// Returns NULL on failure.
CTurboConfig *stark_get_turbo_config(DeviceHandler *handle, uint8_t slave_id);
/// Get LED information.
/// Returns a pointer to `LedInfo`; call `free_led_info` to free it.
/// Returns NULL on failure.
CLedInfo *stark_get_led_info(DeviceHandler *handle, uint8_t slave_id);
/// Get button press event.
/// Returns a pointer to `ButtonPressEvent`; call `free_button_event` to free it.
/// Returns NULL on failure.
CButtonPressEvent *stark_get_button_event(DeviceHandler *handle, uint8_t slave_id);
/// Start the DFU (Device Firmware Update) process.
/// - `handle`: Device handler pointer.
/// - `slave_id`: Slave device ID.
/// - `dfu_file_path`: DFU file path, as a C string.
/// - `wait_secs`: Timeout for entering DFU mode, in seconds (default 5).
void start_dfu(DeviceHandler *handle,
uint8_t slave_id,
const char *dfu_file_path,
uintptr_t wait_secs);
/// Stop the DFU process.
///
/// - `slave_id`: Slave device ID.
///
/// This stops an ongoing DFU session.
///
/// Note: If DFU has not started or has already completed, this function has no effect.
void stop_dfu(uint8_t slave_id);
void free_device_config(CDeviceConfig *config);
void free_device_info(CDeviceInfo *info);
/// Check if device uses Revo1 Motor API.
///
/// Revo1 Basic/Touch use Revo1 Motor API.
/// Revo1 Advanced/AdvancedTouch and all Revo2 use Revo2 Motor API.
bool device_info_uses_revo1_motor_api(const CDeviceInfo *info);
/// Check if device uses Revo1 Touch API.
///
/// Revo1 Touch API has different sensor counts per finger (4 sensors per finger).
/// Includes Revo1Touch and Revo1AdvancedTouch.
bool device_info_uses_revo1_touch_api(const CDeviceInfo *info);
} // extern "C"
#endif // STARK_SDK_HAPI 快速参考
初始化与配置
| API | 说明 |
|---|---|
init_logging() | 初始化 SDK 日志 |
连接管理
| API | 说明 |
|---|---|
stark_auto_detect() | 自动检测设备(推荐,支持所有协议) |
init_from_detected() | 从检测结果初始化设备 |
close_device_handler() | 关闭设备连接(推荐) |
list_zqwl_devices() | 列出 ZQWL CAN 适配器 |
init_zqwl_can() | 初始化 ZQWL CAN 适配器 |
close_zqwl() | 关闭 ZQWL 适配器 |
modbus_open() | 打开 Modbus 连接 |
modbus_close() | 关闭 Modbus 连接 |
init_device_handler() | 创建设备处理器(CAN/CANFD,需手动管理适配器) |
init_device_handler_with_hw_type() | 创建设备处理器并预设硬件类型(跳过 get_device_info)⭐ |
auto_detect_device() | 自动检测设备(已弃用) |
auto_detect_modbus_revo1() | 自动检测 Revo 1 设备(已弃用) |
list_available_ports() | 列出可用串口 |
设备信息
| API | 说明 |
|---|---|
stark_get_device_info() | 获取设备完整信息 |
stark_get_device_sn() | 获取设备序列号 |
stark_get_device_fw_version() | 获取固件版本 |
stark_get_sku_type() | 获取 SKU 类型 |
stark_get_voltage() | 获取电池电压 |
stark_get_serialport_cfg() | 获取串口配置 |
stark_set_serialport_baudrate() | 设置波特率 |
stark_set_slave_id() | 设置从站 ID |
设备配置
| API | 说明 |
|---|---|
stark_get_force_level() | 获取力度等级 |
stark_set_force_level() | 设置力度等级 |
stark_get_auto_calibration_enabled() | 获取自动校准状态 |
stark_set_auto_calibration() | 设置自动校准 |
stark_calibrate_position() | 手动校准位置 |
stark_get_turbo_mode_enabled() | 获取 Turbo 模式状态 |
stark_set_turbo_mode_enabled() | 设置 Turbo 模式 |
stark_get_turbo_config() | 获取 Turbo 配置 |
stark_set_turbo_config() | 设置 Turbo 配置 |
stark_reboot() | 重启设备 |
设备类型检查
| API | 说明 |
|---|---|
stark_is_touch_device() | 检查是否有触觉传感器 |
stark_uses_revo1_motor_api() | 检查是否使用 Revo 1 电机 API |
stark_uses_revo1_touch_api() | 检查是否使用 Revo 1 触觉 API |
stark_uses_revo2_touch_api() | 检查是否使用 Revo 2 触觉 API |
stark_uses_pressure_touch_api() | 检查是否使用压力触觉 API |
stark_get_touch_sensor_type() | 获取触觉传感器类型 |
电机控制 - 位置
| API | 说明 |
|---|---|
stark_set_finger_position() | 设置单个手指位置(0~1000) |
stark_set_finger_positions() | 设置所有手指位置 |
stark_get_finger_positions() | 获取所有手指位置 |
电机控制 - 速度
| API | 说明 |
|---|---|
stark_set_finger_speed() | 设置单个手指速度(-1000~+1000) |
stark_set_finger_speeds() | 设置所有手指速度 |
stark_get_finger_speeds() | 获取所有手指速度 |
电机控制 - 电流
| API | 说明 |
|---|---|
stark_set_finger_current() | 设置单个手指电流(-1000~+1000) |
stark_set_finger_currents() | 设置所有手指电流 |
stark_get_finger_currents() | 获取所有手指电流 |
电机状态
| API | 说明 |
|---|---|
stark_get_motor_status() | 获取电机综合状态 |
stark_get_motor_state() | 获取电机运行状态 |
触觉传感器
| API | 说明 |
|---|---|
stark_get_touch_sensor_enabled() | 获取触觉传感器启用状态 |
stark_get_touch_sensor_fw_versions() | 获取触觉传感器固件版本 |
stark_get_touch_sensor_raw_data() | 获取触觉原始数据 |
stark_get_touch_sensor_status() | 获取触觉传感器状态 |
stark_touch_sensor_setup() | 设置触觉传感器 |
stark_touch_sensor_reset() | 重置触觉传感器 |
stark_touch_sensor_calibrate() | 校准触觉传感器 |
LED 和按钮
| API | 说明 |
|---|---|
stark_get_led_info() | 获取 LED 状态 |
stark_set_led_info() | 设置 LED 状态 |
stark_get_button_event() | 获取按钮事件 |
动作序列
| API | 说明 |
|---|---|
stark_get_action_sequence() | 获取动作序列 |
stark_transfer_action_sequence() | 上传动作序列 |
stark_run_action_sequence() | 执行动作序列 |
固件升级
| API | 说明 |
|---|---|
stark_start_dfu() | 启动固件升级 |