thiagolegrand/FX30-Controller
GitHub: thiagolegrand/FX30-Controller
一个运行在 M5Stack Cardputer 上的 Sony FX30 摄影机无线遥控器,通过 Wi-Fi Direct 和 PTP-IP 协议在片场实现录制、参数调整与状态监控。
Stars: 1 | Forks: 0
# FX30 控制器 — M5Stack Cardputer ADV
运行在 **M5Stack Cardputer ADV**
(ESP32-S3) 上的 **Sony FX30 (ILME-FX30)** 控制器,
通过 **Wi-Fi Direct → PTP-IP (TCP 15740)** 进行通信。
这是一款口袋大小的摄影机控制器,专为片场设计:开机,从列表中选择摄影机,即可
直接掌控 REC、ISO、shutter、iris、WB、timecode、电池及存储卡剩余时间——
无需打开 FX30 的菜单。
**状态:已在真实摄影机上正常运行**(FX30 固件 6.00 / 协议 v300)——
连接稳定,实时状态显示,REC 开始/停止以及各项设置均已在片场得到行为验证。
当前版本:**v3.8**(2026-07-15)。
### v3.6 → v3.8 更新内容
- **v3.8 — 首屏 = 已注册摄影机列表。** 每台摄影机在 NVS 中都有
别名和凭据,支持**一键**连接。`Enter` 连接,
`k` 重命名,`del` 忘记设备;*+ 新建摄影机* 会扫描 Wi-Fi,并要求输入密码和
别名。如果**仅有一台**已注册的摄影机,开机时将自动连接。
- **v3.7.x — 真实的 timecode、电池和存储卡信息。** 移除了本地 TC 合成(不再有“虚假”的 TC):顶部仅显示从摄影机读取的 TC。
底部显示**摄影机**自身的电池电量(`0xD218`)以及 Cardputer 的电量,
低于 15% 时会显示红色警告,在 ≤5% 时图标闪烁,同时显示格式化后的存储卡
剩余时间(`0xD24A`,以秒为单位),与摄影机的显示方式一致。
- **v3.6.x — 通过 enum-walk 调整 ISO/shutter/iris**(`0x9205`,协议 v300),并修复了 shutter **角度** 调整方向的问题。
- **v3.5 — 人体工学改进:** 使用 `[`/`]` 进行 zoom,在主屏幕通过方向键(`;/. ,//`)进行导航,实现无闪烁屏幕(sprite/double-buffer),以及实验性的 Playback
功能(`i`),无需触碰摄影机即可查看存储卡内容。
各版本的详细更新请见 [`PROGRESS.md`](PROGRESS.md)。
项目的真实数据来源:[`docs/FX30_Cardputer_Relatorio.md`](docs/FX30_Cardputer_Relatorio.md)。
各里程碑状态:[`PROGRESS.md`](PROGRESS.md)。
逆向工程发现(真实的 property/control codes):[`docs/RE_FX30.md`](docs/RE_FX30.md)
以及 [`docs/RE_FX30_v300.md`](docs/RE_FX30_v300.md)。
## ⚠️ 摄影机端的前置条件
该控制器使用**无加密的 PTP-IP** 进行通信。在 FX30 上:
当设置为 **ON** 时,通道会经过 SSH 加密,导致所有功能失效(表现为:日志中出现 `cmd:init-ack-timeout`)。此外需设置:`网络 → PC Remote → 方法 = Wi-Fi Direct`,固件版本需为 **3.00+**,
并且摄影机的 AP 上**只能有一个客户端**(请断开手机连接)。
**凭据 (v3.8):直接在 Cardputer 上注册,无需重新编译。**
初始屏幕是保存在 NVS 中的**摄影机列表**。在 *+ 新建摄影机* 下,
固件会扫描网络,您选择摄影机的 `DIRECT-…`,输入密码
(位于 FX30 的 "Wi-Fi Direct Info." 中)并提供一个**别名**("A-cam", "B-cam")。
此后:`Enter` 连接,`k` 重命名,`del` 忘记。如果仅注册了一台摄影机,
开机将自动连接。
## 按键说明 (Cardputer)
| 按键 | 操作 | 状态 |
|---|---|---|
| `a` | REC 开始/停止 | ✅ 已在 FX30 上确认 |
| `b` / `n` | ISO +1 / −1 档 | ✅ 已确认 |
| `c` / `v` | Shutter +1 / −1 档(若模式为 Angle,则为角度) | ✅ 已确认(*speed* 模式;在角度模式下无响应) |
| `d` / `f` | Iris +1 / −1 档 | 机制相同;等待电子 iris 镜头测试 |
| `w` / `q` | WB Kelvin +100 / −100 | ✅ |
| `[` / `]` | Zoom OUT / IN (v3.5;原为 `u`/`z`) | 机制与已使用的 D25C 相同 |
| `;` `.` `,` `/` | **方向键** (v3.5):`;/.` 在主屏幕上切换所选字段(ISO→SH→Iris→WB),`,//` 对所选字段进行 -1/+1 调整。这些按键此前已用于 Wi-Fi/Config/Video/起始界面的“方向”控制——现在同样适用于主屏幕 | 尚未在 FX30 上测试 |
| `x` | 自动对焦(半按 800 ms) | 协议已接受 |
| `s` | Still | 已接受,**在视频模式下无效** |
| `r` | VIDEO 菜单 (fps/格式/rec/LUT/SteadyShot/TC/角度) | ✅ |
| `g` | **Live View** (~3 fps) | ✅ |
| `i` | **Playback** (v3.5,实验性):通过标准 PTP(非 Sony opcode)对存储卡中的照片/视频进行只读浏览 — `` ` `` 退出,`;/.`/`,//` 导航 | **尚未在 FX30 上测试** — 请参阅 PROGRESS.md |
| `m` | **属性浏览器**(设备端逆向工程;高亮显示变更) | ✅ |
| `k` | **摄影机** (v3.8):注册新设备 / 在起始屏幕重命名所选设备 | ✅ |
| `e` | 设置(亮度、颜色、休眠) | ✅ |
| `?` | **帮助**(按键映射) | ✅ |
| `h` | 导出 props (SD + 串口) | ✅ |
| `o` | **SDIO 探测** (v3.7):以只读方式触发 opcodes `0x9203/04/06/08/0B/0C/0D` 并记录 rc + 32 B 的返回数据 — 用于追踪 TC 来源的逆向工程工具 | 逆向工程工具 |
| `p` | 开启/关闭串口逆向工程数据输出 | ✅ |
| `3` | 兼容 SDIO 协议 v200/v300 | 实验性 |
| `G0` (侧边按钮) | 显示屏开启/关闭(省电) | ✅ |
| `` ` `` | 重新连接 / 返回起始屏幕(关闭 Live View/Playback) | ✅ |
长按调整按键(`b/n c/v d/f w/q [ ]`)可**自动重复**。
**无闪烁 (v3.5):** 绘图过程现在会输出到 RAM 中的离屏 sprite
(`M5Canvas`,见 `hal/Display.h`),然后仅通过(`present()`)一次性发送到物理面板 ——
此前每次重绘都会直接在 LCD 上执行 `fillScreen`,当状态轮询、REC 计时等数据发生变化时,会明显看到黑色闪烁。
## 架构(摘要)
```
src/
├─ main.cpp # bootstrap; task de rede (core 0) + loop de UI (core 1)
├─ core/ Transport.h Time.h AppState.h Events.h # interfaces + estado + fila
├─ hal/ Display Keyboard Power # Cardputer (M5)
├─ net/ WiFiManager WiFiTransport # Wi-Fi + ITransport no device
├─ protocol/
│ ├─ ptpip/ Framing.h PtpIp.* # transporte PTP-IP (framework-agnóstico)
│ ├─ ptp/ Ptp.* # containers/parsers ISO 15740
│ └─ sony/ SonyCamera.* # handshake SDIO + props/controls reais da FX30
├─ controller/ CameraController.* # cola UI<->protocolo (task de rede)
├─ ui/ ScreenMain.* Menus.h # telas
└─ storage/ Store.* # NVS (credenciais) + SD (dumps)
test/native/ # mock PTP-IP + testes; RealCaptures.h = blobs REAIS da FX30
tools/ # pcap_ptp_decode.py, parse_prop_dump.py, serial_dump_reassemble.py
docs/ # relatório (fonte de verdade) + RE_FX30 (códigos confirmados)
```
`protocol/` 层**不依赖 Arduino**:它可在 PC 上编译并针对
mock 以及**从 FX30 捕获的真实 blobs** 进行测试(真实的回归测试)。
## 连接工作原理(已在 FX30 上验证)
1. 加入摄影机的 Wi-Fi AP(`WiFi.setSleep(false)` — 若无此项,AP 会断开客户端连接)。
2. PTP-IP 握手(InitCommand + InitEvent,TCP 15740)。
3. Sony SDIO 握手:`0x9201(1) → 0x9201(2) → 0x9202(0xC8) → 0x9201(3)`。
4. `0x9202` 广播 props 和 **control codes**(REC=`0xD2C8`,AF=`0xD2C1`,……)。
5. 每 2 秒轮询一次 `0x9209` = 屏幕上的状态显示 **以及** keep-alive(若无流量,
摄影机将在约 30 秒后断开连接)。
6. 调整:通过 `0x9207` + i8 ±1 以**步进**方式进行设置(通过 0x9205 进行绝对值设置在 ISO 上
无效 — 会触发限制/AUTO)。
## 构建与测试
```
# 主机测试(clang++/g++,无硬件)— 包括使用真实 blob 的回归测试:
make test
# 固件(PlatformIO):
pio run -e cardputer-adv
pio run -e cardputer-adv -t upload # upload via USB
# 如果上传失败并提示 "No serial data received"(S3 的 USB-JTAG stub):
python3 ~/.platformio/packages/tool-esptoolpy/esptool.py --chip esp32s3 \
--port /dev/cu.usbmodemXXXX --no-stub write_flash 0x10000 \
.pio/build/cardputer-adv/firmware.bin
# RE 工具(离线):
python3 tools/pcap_ptp_decode.py sua_captura.pcapng # captura Wireshark
python3 tools/parse_prop_dump.py props.bin # dump 0x9209 (SD)
python3 tools/serial_dump_reassemble.py cap.txt --tag D -o props.bin # dump serial
```
串口监视器(115200):输出 `[net]`(连接),`[stat]`(状态),`[ctrl]`
(命令)日志。在 macOS 上,`pio device monitor` 可能会因缺少 TTY 而失败 —— 请使用
`stty -f /dev/cu.usbmodemXXXX 115200 raw -echo -hupcl && cat /dev/cu.usbmodemXXXX`
(被动连接,不会重置开发板)。
## 伦理 / 合法性
本项目的目的是实现与自有硬件的互操作性,使用的是**摄影机自身有明确记录的设置**(Autent. Acesso OFF),并基于 **open-source** 知识(Alpha-Fairy,
libgphoto2,sequoia-ptpy)。不涉及绕过 DRM,也未重新分发 Sony 的二进制文件。
本项目为**独立**项目,与 Sony 或 M5Stack 没有任何关联。"Sony"、
"FX30" 和 "Cardputer" 均为各自所有者的商标。本产品不提供任何形式的保证:
您将此固件用于您的摄影机,需自行承担风险。
## 许可证
[MIT](LICENSE) © 2026 Thiago Falkenberg.
标签:ESP32, PTP协议, 云资产清单, 嵌入式开发, 摄影器材, 物联网, 硬件控制, 逆向工程