Metadata-Version: 2.1
Name: spi-proto
Version: 0.1.0
Summary: Jetson SPI 电机控制协议库（libspi_proto.so）的 Python 绑定，内置共享库，pip install 后即可使用。
Home-page: UNKNOWN
License: UNKNOWN
Description: # spi-proto：SPI 电机控制库的 Python 包
        
        把 C++ 工程编译出的 `libspi_proto.so`（aarch64 / Jetson）封装为可直接
        `pip install` 的 Python 库。包内自带共享库，安装后无需再手动管理 `.so`
        路径，所有硬件命令、协议造帧/解析、CRC、浮点转换都有对应的 Python API。
        
        对应 C 接口见 `../c_api.h`，协议细节见 `../通讯协议.md`。
        
        ## 平台要求
        
        - Linux aarch64（Jetson 等），因为 `libspi_proto.so` 是 aarch64 ELF；
        - Python 3.8+；
        - 硬件命令需要 `/dev/spidev*` 节点（纯协议接口 / `selftest` 不需要硬件）。
        
        在其他架构上安装会正常完成，但导入时会抛出明确的架构错误提示。
        
        ## 安装
        
        ### 方式一：从源码目录直接安装
        
        ```sh
        cd python
        pip install .
        ```
        
        ### 方式二：构建 wheel 后安装（推荐分发给其他 Jetson）
        
        ```sh
        cd python
        bash build_wheel.sh
        pip install dist/spi_proto-0.1.0-py3-none-linux_aarch64.whl
        ```
        
        `build_wheel.sh` 会同时生成 sdist 和平台 wheel。wheel 的平台标签必须是
        `linux_aarch64`（`.so` 是 aarch64 的 ELF，不能当作 `py3-none-any`
        跨平台包发布）。
        
        ### 方式三：直接安装 sdist
        
        ```sh
        pip install python/dist/spi_proto-0.1.0.tar.gz
        ```
        
        ### 验证安装
        
        ```sh
        python3 -c "import spi_proto; print(spi_proto.__version__)"
        spi-demo selftest        # 无硬件自检，全部 [PASS] 即正常
        ```
        
        ## 快速开始
        
        安装后自带 `spi-demo` 命令行（也可 `python -m spi_proto.demo`，源码目录
        下还可以直接 `python3 demo_python.py`）：
        
        ```sh
        spi-demo selftest                    # 不访问硬件，自检协议
        spi-demo enable                      # 0x01 使能（默认全选）
        spi-demo enable --motor-id 1 2       # 只使能电机 1、2
        spi-demo disable --motor-id 3        # 只失能电机 3
        spi-demo zero                        # 0x04 设置零位（默认全选）
        spi-demo zero --motor-id 3 --motor-id 7
        spi-demo setmode --mode 0            # 全部电机设为 MIT 模式
        spi-demo pos --motor 1 0.5 0 0       # 控制电机 1：pos=0.5, vel=0, tor=0
        spi-demo pos --motor 1 0.5 0 0 --motor 9 -0.2 0 0 --loop 10
        spi-demo test                        # 0x0F 回环测试（调试）
        ```
        
        硬件命令默认打开 `/dev/spidev0.0`（不存在时自动选择第一个
        `/dev/spidev*`），20 MHz，SPI 模式 0，可用 `--device` / `--speed` 覆盖。
        
        ## Python API 示例
        
        ### 硬件控制
        
        ```python
        from spi_proto import SpiClient
        
        with SpiClient() as client:            # 默认 /dev/spidev0.0, 20MHz, mode 0
            fb = client.enable()               # 整机使能，返回 Feedback
            fb = client.enable_motor(1)        # 只使能电机 1
            fb = client.disable()              # 整机失能
            fb = client.set_zero()             # 全选标零
            fb = client.set_zero_motor(3)      # 只标零电机 3
            fb = client.set_mode(0)            # 全部电机 MIT 模式（0/1/2）
            fb = client.set_mode([1, 2] + [0] * 30)   # 按电机分别设置
            fb = client.position([0.5] * 16, [0.0] * 16, [0.0] * 16)  # 全 16 路
            fb = client.position_ids([1, 9], [0.5, -0.2], [0.0, 0.0], [0.0, 0.0])
            fb = client.stop()                 # 0x03 读电机状态
        
            print(fb.valid, fb.crc_ok, fb.cmd)          # True True 0x82
            for m in fb.motors:
                print(m.id, m.pos, m.vel, m.tor)        # 位置 rad / 速度 rad/s / 力矩 Nm
        ```
        
        所有硬件方法成功返回 `Feedback`，失败抛 `SpiError`（可 `client.last_error()`
        查看 C 层错误信息）。
        
        ### 纯协议（不访问硬件）
        
        ```python
        from spi_proto import (
            crc16, frame_enable, frame_position_ids, parse_feedback,
        )
        
        frame = frame_enable(0xFFFFFFFF)       # bytes，长度 255
        frame = frame_position_ids([1], [0.5], [0.0], [0.0])
        
        assert crc16(b"123456789") == 0x4B37
        
        fb = parse_feedback(rx_bytes)          # rx_bytes 必须是 255 字节
        ```
        
        ## API 参考
        
        ### 常量
        
        | 常量 | 值 | 说明 |
        | --- | --- | --- |
        | `MOTOR_NUM` | 16 | 全 16 路控制时的电机数 |
        | `MODE_MOTOR_NUM` | 32 | 设置模式帧的槽位数 |
        | `MOTOR_ID_MAX` | 32 | 位图类命令的电机 ID 上限 |
        | `FRAME_LEN` | 255 | 帧长度 |
        | `MASK_ALL` | `0xFFFFFFFF` | 使能/失能/标零/读状态全选位图 |
        | `MODE_MIT` / `MODE_POSITION` / `MODE_VELOCITY` | 0 / 1 / 2 | set_mode 取值 |
        
        ### `SpiClient`
        
        构造参数：`device=None, speed_hz=20_000_000, mode=0, bits_per_word=8`。
        支持 `with` 语句，`close()` / `closed`。
        
        | 方法 | 命令 | 说明 |
        | --- | --- | --- |
        | `enable(on=True)` | 0x01 | 使能，默认全选 |
        | `disable()` | 0x00 | 失能，默认全选 |
        | `enable_mask(mask)` / `disable_mask(mask)` | 0x01/0x00 | 按 32 位位图 |
        | `enable_motor(id)` / `disable_motor(id)` | 0x01/0x00 | 单电机（1..32） |
        | `stop()` / `stop_mask(mask)` | 0x03 | 读电机状态 |
        | `set_zero(mask=0xFFFFFFFF)` / `set_zero_motor(id)` | 0x04 | 标零 |
        | `set_mode(modes)` | 0x05 | int 或 32 字节序列 |
        | `loopback(byte=0x5A)` | 0x0F | 回环测试 |
        | `position(pos, vel, tor)` | 0x02 | 全 16 路，数组长度 16，可传 None |
        | `position_ids(ids, pos, vel, tor)` | 0x02 | 变长控制，ids 1..16 个 |
        | `last_error()` | - | C 层最近错误信息 |
        
        ### 协议函数
        
        `crc16(data)`、`float_to_uint(x, min, max, bits)`、
        `uint_to_float(x, min, max, bits)`、`parse_feedback(frame)`，以及返回
        `bytes`（255 字节）的帧构造：`frame_enable` / `frame_disable` /
        `frame_stop` / `frame_set_zero` / `frame_set_mode` / `frame_test` /
        `frame_position` / `frame_position_ids`。
        
        ### 数据结构
        
        - `Feedback`：`valid`、`crc_ok`、`cmd`、`raw`（bytes）、`motors`
        - `MotorFeedback`：`id`、`state`、`pos`、`vel`、`tor`、`mos_temp`、`coil_temp`
        
        ## 协议要点
        
        - 使能/失能/读状态/标零：32 位位图写入 `frame[4..7]`（小端），
          `bit(id-1)=1` 对应电机 id（1..32）；
        - 设置模式（0x05）：32 字节，每电机一字节（0=MIT、1=位置、2=速度）；
        - 运动控制（0x02 / 回传 0x82）为变长帧，长度字节 = 数据长度（9×N）；
        - CRC-16/MODBUS 覆盖“长度+命令+数据”，紧随数据存放。
        
        ## 注意事项
        
        - SPI 设备节点可能需要 root 或 dialout 组权限，报 `open 失败` 时先检查
          `ls -l /dev/spidev*` 与权限；
        - `libspi_proto.so` 是 aarch64 的，wheel 只能装在 Linux aarch64 上；
        - MCU 0x0F 回环存在固件特性：回传帧携带上一拍状态、回环字节写在 CRC
          计算之后。`spi-demo test` 已兼容（连发两拍 + 按 `raw[5]=0` 复核 CRC），
          普通命令（stop 等）回传帧 CRC 正常；
        - 纯协议接口和 `selftest` 不需要硬件，可在任意 aarch64 机器上跑。
        
        ## 打包与分发
        
        ```sh
        bash build_wheel.sh
        ```
        
        产物在 `dist/`：
        
        - `spi_proto-0.1.0-py3-none-linux_aarch64.whl`：把 `.so` 打进 wheel，
          目标 Jetson 上 `pip install <wheel>` 即可；
        - `spi_proto-0.1.0.tar.gz`：sdist，目标机器上 `pip install <tar.gz>`。
        
        包内模块：`spi_proto`（API 入口）、`spi_proto.client`（SpiClient）、
        `spi_proto.protocol`（造帧/解析/CRC）、`spi_proto.selftest`、
        `spi_proto.demo`（CLI demo）。
        
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: POSIX :: Linux
Classifier: Topic :: Software Development :: Embedded Systems
Classifier: Topic :: System :: Hardware
Requires-Python: >=3.8
Description-Content-Type: text/markdown
