Metadata-Version: 2.4
Name: zlgcan-macos
Version: 0.1.0
Summary: macOS native CLI for ZLG USBCANFD-100U-mini CAN FD analyzer
License: MIT
Requires-Python: >=3.10
Requires-Dist: click>=8.1
Requires-Dist: pycryptodome>=3.19
Requires-Dist: pyusb>=1.2.1
Description-Content-Type: text/markdown

# ZLG USBCANFD-100U-mini macOS 驱动方案

在 Mac (Apple Silicon) 上使用周立功 USBCANFD-100U-mini CAN FD 分析仪。
通过逆向工程实现了纯 Python 原生驱动，无需 Docker / VM / Windows。

## 方案一：原生驱动（推荐）

### 架构

```
Mac (Python + pyusb)
    │
    ├── AES-128 认证握手
    ├── UCFD_CMD 协议 (EP01 OUT → EP81 IN)
    └── CANFD 数据流   (EP83 IN)
           │
    USBCANFD-100U-mini (USB)
           │
       CAN FD 总线
```

纯 Python 直接通过 pyusb 操控 USB 设备，无中间层。

### 前提条件

```bash
brew install libusb
pip install pyusb pycryptodome
```

### 使用方法

```bash
# 插入 USBCANFD-100U-mini
cd ~/code/zlg-proxy
python3 zlg_native.py
```

### 核心文件

| 文件 | 说明 |
|------|------|
| `zlg_native.py` | **原生驱动**，直接 pyusb 收发 CANFD |

### 初始化序列（关键顺序）

```python
cmd(0x03, 0, aes_encrypt(random_16))  # 1. AES 认证
cmd(0x13, 0)                           # 2. Reset
cmd(0x01, 0)                           # 3. 启用数据转发 ← 关键！
cmd(0x06, 0)                           # 4. 清空缓冲
cmd(0x15, 0, u32(1))                   # 5. 使能 120Ω 终端电阻
cmd(0x11, 0, can_config)               # 6. InitCAN
cmd(0x12, 0)                           # 7. StartCAN
# 然后从 EP83 IN 持续读取 CANFD 数据包
```

### 命令发送方式

```python
# 每个命令拆成两次 EP01 写入：
dev.write(0x01, header_8bytes)      # 8B: magic + cmd_id + ch + idx + data_len
dev.write(0x01, padded_1024bytes)   # 1024B: data + CRC16 + 零填充

# 响应从 EP81 读取：
response = dev.read(0x81, 4096)     # 12B 头 + data + 2B CRC
```

---

## 方案二：Docker 桥接

当需要调用 ZLG 官方 VCI API（VCI_Transmit、VCI_ReceiveFD 等）时使用。

### 架构

```
┌─────────────────────────────────────────────────────┐
│                     Mac (ARM)                        │
│                                                      │
│   ┌───────────────┐    TCP:19876   ┌──────────────┐ │
│   │ Docker x86_64  │◄────────────►│ USB 代理       │ │
│   │                │              │ usb_proxy.py   │ │
│   │ libusbcanfd.so │              │   ↕ pyusb      │ │
│   │  (ZLG官方库)   │              │   ↕            │ │
│   │       ↕        │              │ USBCANFD       │ │
│   │ libusb_shim.so │              │ -100U-mini     │ │
│   │  (TCP转发)     │              └──────────────┘ │
│   └───────────────┘                                  │
└─────────────────────────────────────────────────────┘
```

### 使用方法

```bash
# 终端1: 启动 USB 代理
python3 usb_proxy.py

# 终端2: 构建并运行
docker build -t zlg-can .
docker run --rm --platform linux/amd64 \
  -e PROXY_HOST=host.docker.internal \
  -e PROXY_PORT=19876 \
  zlg-can
```

### 文件说明

| 文件 | 说明 |
|------|------|
| `usb_proxy.py` | Mac 端 USB-over-TCP 代理 |
| `libusb_shim.c` | 假 libusb-1.0.so，截获 USB 调用转发到代理 |
| `zlg_test.py` | Docker 内测试脚本，调用 ZLG VCI API |
| `Dockerfile` | x86_64 Linux 容器构建文件 |
| `library/` | ZLG 官方驱动库 |

---

## CAN FD 配置参数

设备类型: `43` (ZCAN_USBCANFD_MINI)

### 1Mbps 仲裁域

```
clock = 60000000  (60MHz)
mode  = 0         (Normal + ISO CANFD)
tseg1 = 22, tseg2 = 5, sjw = 3, smp = 0, brp = 1
```

### 5Mbps 数据域

```
tseg1 = 7, tseg2 = 2, sjw = 2, smp = 0, brp = 0
```

> 注意：brp=0 表示预分频=1，ZLG API 中 brp 值 = 实际预分频 - 1

---

## 逆向工程协议文档

### USB 端点

| 端点 | 方向 | 用途 |
|------|------|------|
| EP 0x01 | OUT | 命令发送（8B 头 + 1024B 数据） |
| EP 0x81 | IN | 命令响应（12B 头 + data + CRC） |
| EP 0x02 | OUT | CAN 帧发送（Send 通道） |
| EP 0x82 | IN | 8B ACK（回显端点） |
| EP 0x83 | IN | **CAN FD 数据接收**（UCFD 格式） |

### UCFD_CMD 命令格式

```
偏移  大小  说明
0     1B    0x55 (magic)
1     1B    cmd_id
2     1B    channel
3     1B    sync_idx (递增)
4-7   4B    data_len (u32 LE)
8+    NB    data
8+N   2B    CRC16-IBM
```

**发送方式**：拆成两次 EP01 写入
1. 8 字节头部
2. 1024 字节数据块（data + CRC + 零填充到 1024）

### 命令 ID 表

| ID | 功能 | 数据 |
|----|------|------|
| 0x01 | 启用数据转发 | 无 |
| 0x03 | AES-128 认证 | 16B 加密数据 |
| 0x06 | 清空缓冲区 | 无 |
| 0x11 | InitCAN | 20B 配置结构 |
| 0x12 | StartCAN | 无 |
| 0x13 | ResetCAN | 无 |
| 0x15 | SetReference | 4B u32 值 |
| 0x41 | ReadBoardInfo | 无 |
| 0x44 | ReadCANStatus | 无 |

### AES-128-ECB 认证

- 密钥: `3f7d935c80a3443fcdb4280614ef9d05`
- 流程: 生成 16B 随机数 → AES 加密 → 作为 cmd=0x03 的数据发送
- 设备验证后返回 16B 加密响应

### CRC16-IBM

- 多项式: 0x8005
- 初始值: 0xFFFF
- 反射模式（LSB first）
- 覆盖范围: UCFD_CMD 头部 + 数据（不含 CRC 本身）

### EP83 CAN 数据包格式

```
偏移  大小  说明
0     1B    0x55 (magic)
1     1B    0xF2 (CAN数据标记) / 0xF3 (CANFD数据标记)
2-3   2B    包序号
4-7   4B    总大小
8-11  4B    帧数量
12-15 4B    时间戳基准
16-19 4B    其他标记
20+   NB    CAN 帧数组
```

---

## 已验证功能

- [x] AES 认证握手
- [x] 设备打开 (SYS 绿灯)
- [x] 120Ω 终端电阻使能 (软件控制, ref_type=0x18)
- [x] CAN FD 初始化 (1Mbps/5Mbps)
- [x] CAN 控制器启动 (CAN 绿灯)
- [x] 自发自收 CAN/CANFD 帧
- [x] **外部 CAN FD 总线实时接收** (原生 + Docker 两种方案)
- [ ] 帧解析器优化（EP83 数据偏移校准）
- [ ] CAN 帧发送到外部总线

## 注意事项

1. **初始化顺序关键**：必须 Resistance → InitCAN → StartCAN，否则 StartCAN 返回 err=3
2. **cmd=0x01 不可省略**：这个"启用数据转发"命令是固件开始推送 CAN 数据到 EP83 的开关
3. 终端电阻通过软件使能 (VCI_SetReference, ref_type=0x18, value=u32(1))
4. 设备断开后需要重新拔插 USB 才能重连
5. Docker 方案需要 Colima/OrbStack 的 `host.docker.internal` 网络支持
