# 串口协议（MAKCU）

> 📥 **下载此API文档**：<a href="/api/serial-api.md" download>serial-api.md</a>

设备的 UART 串口（GPIO2/3，8N1）使用 **MAKCU 协议族**。设备开机默认 115200；主机先发送 `DE AD 05 00 A5 <baud LE32>` 握手帧，再切换到目标工作波特率（常用 4M）。握手、`km.version()`、`km.baud(n)` 和 V2 `0xB1` 属于传输控制，不受授权状态阻断；这样未激活设备仍能被网页发现、切速和连接。MAKCU 文本/V2 的实际键鼠注入、配置与调度命令受授权门控；网页使用的 55 AA 控制路径保持可用。运行期切速后重启恢复 115200。协议提供鼠标/键盘注入、连点、定时按压、字符串输入、平滑移动、按键锁定与物理输入屏蔽、状态遥测等能力。

## 与 HID 控制的区别

| | HID（Device 模式） | 串口（MAKCU 协议） |
|---|---|---|
| 物理链路 | PIO-USB-C 口的 HID OUT/IN 端点 | GPIO2/3 UART（经 USB-TTL 或板载转串口） |
| 帧格式 | `55 AA` 命令帧（见 [HIDAPI](/api/hid-api)） | `km.*` 文本、`DE AD`、`0x50` V2、`55 AA` 私有扩展帧 |
| 命令集 | 触屏 / 鼠标 / 键盘 / core_input 调度 / vmouse / Lua 自定义事件 | 上述全部能力 + 连点 / 打字 / 平滑移动 / 锁定屏蔽 / 遥测 |
| 生态 | 自定义上位机 | MAKCU 文本/V2 客户端；可使用仓库 `pytester/test_makcu.py` 回归 |

两个通道最终进入同一套设备控制路径，功能语义一致；区别只在传输与命令集广度。

## 握手与帧格式概要

握手时以 115200 打开串口，发送：

```
DE AD 05 00 A5 <baud:uint32 little-endian>
```

设备不回复握手帧；主机等待短暂的 TX 排空时间后盲切到相同波特率。由于运行期可以用 `km.baud(n)` 改成任意支持值，健壮的上位机应逐档尝试已知速率，并在切到工作速率后发送 `km.version()` 确认，不能只凭握手帧判断成功。当前 Web Serial 工具依次探测 `115200`、`921600`、`2000000`、`4000000`，确认 `km.MAKCU_V1.0` 后才显示连接成功；若设备被改成探测表之外的自定义速率，需要把该速率加入客户端探测表。

工具提供「**串口低延迟模式**」开关（localStorage 记忆）：开启后工作速率改用 **6M**（探测表末尾追加 6M 档，板子已被留在 6M 时重连无需重启）。6M 实测可用但**可能出现不稳定**；开关的生效点是**连接时刻**——会话中途切换会断开当前连接，提示用户重启开发板后重连（板子回到 115200 再由工具切到新速率）。文本命令以 `\r` 或 `\n` 结束，例如 `km.version()`、`km.move(10,20)`、`km.baud()`。V2 帧格式为 `[50][CMD][LEN:u16 LE][payload]`；MAKCU 私有扩展帧格式为 `[55][AA][LEN:u8][CMD][payload]`。

## 按钮状态流（km.buttons）

`km.buttons(mode[,period_ms])` 开启鼠标按钮状态流（物理 + 注入合并可见掩码，变化即上报）。位序 bit0=左 / bit1=右 / bit2=中 / bit3=侧1 / bit4=侧2，掩码恒 `0x00–0x1F`。本固件为**事件驱动**上报（掩码变化即发，不做周期采样），`period_ms`（1–1000）仅作参数兼容。

线上格式按 mode 区分（对齐官方 V4.036+ 语义）：

| mode | 流帧格式 | 适用客户端 |
|---|---|---|
| 1 / 2 | `6B 6D 2E <mask> 0D 0A`（`"km."` + 掩码 + CRLF） | 现行官方固件形态；**WhizKid 等"扫描 `km.` 前缀"的上位机只认这一种** |
| 3 | 裸 `<mask>` 单字节 | 老固件（V4.024–035）形态，保留给 makcu-py-lib 类旧解析客户端 |

`km.axis(mode[,period_ms])` 的 mode 语义不变（仅 1/2）。

## 键盘数字注入（km.key）

`km.key(code,state)` 按数字 HID 码注入键盘（state：1=按下，0=释放）。`code` 接受 `0x04–0x73`（主键区至 F24）与 `0xE0–0xE7`（修饰键），其余值静默忽略但照常应答。按键名注入仍走 `km.down('name')` / `km.up('name')`；两条路径相互独立（数字码不经过键名表与上档 shift 展开）。

## 55 AA 私有扩展帧

串口保留 **MAKCU 私有扩展帧 `55 AA`**，格式与 HID 控制帧相同，用于把 [HIDAPI](/api/hid-api) 的控制指令复用到串口：

- 帧格式：`[55 AA][LEN][CMD][payload...]`，LEN 为 CMD 与 payload 的总长度
- 例：`55 AA 0E FC FF <dx:i32><dy:i32><wheel:i32>` 注入一次相对移动
- 固件收到后在设备侧重放同一控制路径，语义与 HID 通道一致

## 噪声处理说明

串口只解析上述 MAKCU 帧型。无法组成完整帧的字节会按噪声消费；二进制半帧超过 50ms 未继续接收时复位解析状态。文本行必须以换行结束，非 `km.*` 文本静默消费。

## 示例

```text
115200: DE AD 05 00 A5 00 09 3D 00   # 请求切到 4000000
4000000: km.version()\r\n           # 收到 km.MAKCU_V1.0 才确认链路
4000000: km.baud(921600)\r\n          # 收到 ACK 后主机切到 921600
921600:  km.baud()\r\n
```
