ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Flipper Zero Wii 扩展控制器协议分析器(wii_ec_anal)完全指南:接线、i2c 协议、屏幕场景与校准体系

2026/9/14 11:49:04 拓冰建站 浏览量
Flipper Zero Wii 扩展控制器协议分析器(wii_ec_anal)完全指南:接线、i2c 协议、屏幕场景与校准体系 Flipper Zero Wii 扩展控制器协议分析器wii_ec_anal完全指南接线、i2c 协议、屏幕场景与校准体系【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper导读本文围绕 Flipper Zero 上的Wii Extension Controller Protocol Analyserwii_ec_anal插件展开全面讲解如何将任天堂 Wii 双节棍Nunchuck、经典手柄Classic Controller等扩展控制器接入 Flipper Zero通过 i2c 总线完成协议解析、实时数据显示、原始数据转储与软件校准。读完本文你将掌握扩展控制器 6 针脚接线规范、i2c 初始化握手与寄存器布局、插件各屏幕场景的操作逻辑、完整的模拟量校准流程以及如何基于源码结构扩展支持新的控制器类型。插件定位一个完整的测试 校准协议分析系统该插件Flipper 应用 IDwii_ec_anal参见 application.fam不是一个简单的读数据工具而是一套全功能的 Wii 扩展控制器测试与校准系统实时解析将原始 i2c 字节流解码为可读的摇杆、按钮、加速度计数据场景化显示为 Nunchuck、Classic Controller 提供专属可视化界面SCENE_NUNCHUCK、SCENE_CLASSIC未知设备则统一进入原始数据 DUMP 界面软件校准可在运行时对模拟量摇杆、加速度计、扳机键进行中心点与行程极值的重新校准调试支撑内置 DEBUG 屏幕与串口日志系统便于协议逆向与问题排查。需要强调的是原文档明确给出免责声明使用本插件尤其是将扩展控制器连接到 Flipper Zero的风险完全由使用者自行承担。截至文档写作时插件仅在官方任天堂 Nunchuck 与 Classic Controller 上验证过。关联文档README.md本文所有实操细节均以此为主干并结合仓库源码进行展开。硬件接线WAIT 屏幕与 6 针脚映射插件启动后首先进入SPLASH 启动画面可按键清除或 3.5 秒后自动消失随后进入WAIT 等待画面。WAIT 屏幕会直接绘制出 Flipper Zero 与 Wii 扩展控制器之间的接线示意对照扩展控制器插头从暴露面观察、凹口朝下引脚定义如下EC 引脚 #EC 位置EC 引脚标识引脚功能FZ GPIO 名称FZ GPIO 编号1左上3v3电源3v392左下SCLi2c 时钟C0163上中EN疑似存在检测4下中-x-无连接5右上SDAi2c 数据C1156右下Gnd电源地Gnd18接线要点实际必须接线的只有 4 根3v3、Gnd、SCLC0、SDAC1上中引脚EN被作者推测为存在检测presence detect功能但尚未验证且本插件并不需要它——设备检测是通过 i2c 握手完成的见下文初始化握手一节设备连接成功后会被立即识别。若识别失败通常有两种原因控制器未正确连接可能只是断线或控制器内部电路板损坏超出本插件排查范围。WAIT 画面按键Left左键— 回到 SPLASH 启动画面Back返回键— 退出插件。适配器WiiChuck / Nunchucky与方向警示对于大多数玩家最省事的连接方式是使用WiiChuck或Nunchucky一类的转接板将扩展控制器插头转为杜邦线排针。但这两类适配器都没有防反插机制——一旦插反会以错误的极性向控制器供电。作者给出的经验法则适用于见过的所有 WiiChuckWiiChuck 一侧有 3 个连接器另一侧有 2 个有 2 个连接器的一侧应对准控制器插头上带大凹槽的一侧插头示意图注意缺失的引脚与凹槽------------- | _________ | | | | | | |_______| | -- notice missing pin | ___ | | | | | -- notice indent ---- ----作者同时强调强烈建议在接线前自行核对适配器引脚定义因为接反电压可能永久损坏控制器。上方的缺失引脚即 EN 检测脚在插头上并不连通。i2c 协议基础从寄存器布局到初始化握手理解了接线后我们来剖析插件底层真正的核心——wii_i2c.c中实现的 i2c 通信层wii_i2c.c。总线参数与地址总线Flipper Zero 的外部 i2c 总线furi_hal_i2c_handle_external见 wii_i2c.h设备地址0x52注意 FZ 的 read/write 函数需要传入(7bitAddress 1)即实际调用时使用0x52 1超时i2cTimeout 3ms读等待i2cReadWait 300µs在写地址与读数据之间插入延时部分设备对读请求响应较慢。寄存器映射Wii 扩展控制器的寄存器布局读取时寄存器地址自动递增寄存器段长度方向含义0x00..0x056 字节读控制器实时数据摇杆/按钮/加速度原始值0x20..0x2F16 字节读出厂校准数据0x30..0x3F16 字节读出厂校准数据的副本0x40..0x4F16 字节写加密密钥PSK2×8 字节0xFA..0xFF6 字节读外设 IDPID用于识别设备类型对应到源码中的常量见 wii_ec.h#define ENC_LEN (2*8) // 加密密钥长度寄存器 0x40..0x4F #define JOY_LEN (6) // 控制器状态数据寄存器 0x00..0x05 #define CAL_LEN (16) // 校准数据寄存器 0x20..0x2F #define PID_LEN (6) // 控制器 ID寄存器 0xFA..0xFF初始化握手encryption-bypass 策略ecInit()wii_i2c.c的完整流程为探测设备furi_hal_i2c_is_device_ready()检查0x52是否在线发送两条初始化命令这是让控制器进入未加密直通模式的关键static const uint8_t regInit1 0xF0; static const uint8_t regInit2 0xFB; static const uint8_t cmdInit1[] {regInit1, 0x55}; // i2c_write(0xf0, 0x55) static const uint8_t cmdInit2[] {regInit2, 0x00}; // i2c_write(0xfb, 0x00)即文档中所说的i2c_write(0xf0, 0x55); i2c_write(0xfb, 0x00)——这是本插件正常工作的前提读取 6 字节 PID寄存器0xFA与已知设备表比对确定控制器类型读取 16 字节出厂校准数据寄存器0x20并调用ecCalibrate(pec, CAL_RESET | CAL_FACTORY)加载工厂校准初始化解码双缓冲并做首次读取使新旧两份解码数据一致便于后续变化检测。加密Encryption的现状与限制Wii 官方加密协议使用位于0x40..0x4F的 2×8 字节 PSK 密钥解密算法为// decrypted_byte (encrypted_byte XOR encKey[1][address%8]) encKey[2][address%8] *p (*p ^ encKey[(reg (p - buf)) % 8]) encKey[8 ((reg (p - buf)) % 8)];请务必注意原文档明确声明——本插件有部分加密处理代码但未使用、未测试且已知其中部分无法工作。插件目前仅支持实现加密绕过策略encryption-bypass的扩展控制器。如果你确实需要加密通信支持应通过 Issue 或 Pull Request 参与完善源码中ecInit()的加密分支已标注多处//! this encryption code fails注释。设备识别已知控制器表与 info.sh设备识别基于ecId[]查找表定义于 wii_ec.c类型定义见 wii_ec.h。每个条目由 6 字节 ID、可读名称、默认场景以及一组函数指针init/decode/check/calib/show/keys组成。运行./info.shinfo.sh可查看当前支持的控制器输出如下[PID_UNKNOWN ] { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, Unknown Perhipheral, SCENE_DUMP, [PID_NUNCHUCK ] { {0x00, 0x00, 0xA4, 0x20, 0x00, 0x00}, Nunchuck, SCENE_NUNCHUCK, [PID_CLASSIC ] { {0x00, 0x00, 0xA4, 0x20, 0x01, 0x01}, Classic Controller, SCENE_CLASSIC, [PID_BALANCE ] { {0x00, 0x00, 0xA4, 0x20, 0x04, 0x02}, Balance Board, SCENE_DUMP, [PID_GH_GUITAR ] { {0x00, 0x00, 0xA4, 0x20, 0x01, 0x03}, Guitar Hero Guitar, SCENE_DUMP, [PID_GH_DRUMS ] { {0x01, 0x00, 0xA4, 0x20, 0x01, 0x03}, Guitar Hero World Tour Drums, SCENE_DUMP, [PID_TURNTABLE ] { {0x03, 0x00, 0xA4, 0x20, 0x01, 0x03}, DJ Hero Turntable, SCENE_DUMP, [PID_TAIKO_DRUMS] { {0x00, 0x00, 0xA4, 0x20, 0x01, 0x11}, Taiko Drum Controller), SCENE_DUMP,结合源码可以看到ecId[]实际包含的条目更多、也更完整除上述设备外还有PID_NUNCHUCK_R2Nunchuck rev2ID 首字节为0xFF、PID_CLASSIC_PROClassic Controller ProID 首字节为0x01、PID_UDRAWuDraw 平板仅有udraw_init而无 decode/scene、PID_ERROR读错误与PID_NULL表尾哨兵。设备类型枚举ecPid及场景枚举scene分别定义于 wii_ec.h 与 wii_anal.h。识别结论共 8 个已知 IDPID_UNKNOWN为未知设备兜底7 个具名设备中只有 Nunchuck 与 Classic Controller 两个拥有专属场景SCENE_NUNCHUCK/SCENE_CLASSIC其余设备统一落入SCENE_DUMP原始数据界面。匹配逻辑位于ecInit()从PID_FIRST遍历到PID_ERRORmemcmp比对 6 字节 ID未命中则标记为PID_UNKNOWN。屏幕场景体系与按键操作插件采用多场景 GUI 架构场景枚举scene_twii_anal.h包含SCENE_NONE、SCENE_SPLASH、SCENE_RIP、SCENE_WAIT、SCENE_DEBUG、SCENE_DUMP、SCENE_CLASSIC、SCENE_CLASSIC_N、SCENE_NUNCHUCK、SCENE_NUNCHUCK_ACC。SPLASH 启动画面插件启动时显示按任意键清除否则 3.5 秒后自动消失。WAIT 等待画面已在上文硬件接线一节详述显示引脚映射并等待控制器接入。NUNCHUCK 主界面连接 Nunchuck 后进入实时显示加速度计Accelerometer{X,Y,Z}值摇杆Joystick{X,Y}值与摇杆位置图形按钮Button{C,Z}状态。按键映射按键功能Left进入 DUMP 原始数据界面Right进入 NUNCHUCK_ACC 加速度计界面Up / Down / OK参见下文Peak Meters短按 Back重置控制器长按 Back退出插件NUNCHUCK 加速度计界面NUNCHUCK_ACC轴方向约定轴运动方向较低读数较高读数X左 / 右左右Y前 / 后前后Z下 / 上下上解读规则沿某轴平动 → 改变该轴读数绕某轴转动/倾斜 → 改变另外两轴的读数例向左平移沿 X 轴只影响 X向左转绕 Y 轴旋转则同时影响 X 与 Z。按键映射按键功能Left返回 NUNCHUCK 主界面UpAuto-Pause 已禁用 → 启用页面末尾暂停时 → 重启扫描Auto-Pause 已启用时运行中 → 禁用Nunchuck-Z切换暂停PauseNunchuck-C切换自动暂停Auto-Pause长按 OK进入软件校准模式加速度计界面下仅校准加速度计短按 OK退出软件校准模式并校准 CENTRE 中心位置短按 Back重置控制器长按 Back退出插件说明源码中确实存在屏幕滚动显示代码但 LCD 刷新率过低、效果不佳因此未启用见 notes.txt 中的波形绘制代码注释。CLASSIC 经典手柄界面连接 Classic ControllerPro后屏幕绘制一个经典手柄图形并随控制器事件实时动画。扫描率设定为 30fps但受 LCD 延迟影响实际体验因人而异。按键功能Left进入 DUMP 界面Right显示模拟量读数再次按 Left 隐藏Up / Down / OK参见Peak Meters短按 Back重置控制器长按 Back退出插件DUMP 原始数据界面所有未知设备以及无专属_decode()的设备只能看到此界面。它展示SIDString ID设备可读名称来自ecId表PIDPeripheral ID识别设备的 6 字节 IDCal16 字节出厂校准数据底部六字节控制器实时数据每字节十六进制上方是对应的二进制位图形。例如连接 Nunchuck 时按下 Z 按钮可观察最右侧位的变化Z 按钮位于 joy[5] 的 bit0见 wii_ec_nunchuck.c。按键按键功能Right返回控制器专属界面若存在短按 Back重置控制器长按 Back退出插件Peak Meters峰值/谷值视图在任何带 Peak/Trough 菜单的控制器专属界面上按键功能Up切换仅显示峰值peakDown切换仅显示谷值trough长按 OK进入软件校准模式短按 OK退出软件校准模式 / 校准 CENTRE 中心位置校准体系工厂校准与软件校准为什么需要校准数字按钮无需校准部分控制器带出厂校准数据疑似存储于控制器 OTP 中例如 Classic Controller有出厂校准而 Classic Controller Pro没有不同设备对校准数据的解读方式不同Nunchuck 是 1 摇杆 加速度计Classic Controller 是 2 摇杆 2 模拟扳机作者实测发现出厂校准数据可能不准确控制器用久了会漂移。若工厂值限制了行程可通过在运行时扩展来解决但若工厂数据给出的行程超出摇杆物理可达范围就必须对控制器做完整重校准。推荐的校准方法控制器静止、水平放置时采集读数作为基准将控制器推到所有方向极限记录各轴的极值peak/trough。背景知识文档提及任天堂据称会在控制器刚连接时采集静止读数且在任何时刻同时按住 {A、B、、-} 至少 3 秒可触发重校准但文档作者并未掌握其具体行为细节。本工具的实际校准流程设备首次识别时使用工厂校准数据决定每个模拟控制的中心/中间位置与极值如最左、最右长按 OKFlipperZero 端——进入软件校准模式注意按下期间不要触碰任何模拟控制校准按钮开始闪烁取当前读数作为中心位置将范围极限设为无范围现在需要在各控制的两个极限之间移动让代码记录新的校准/范围/峰谷值完成后按短按 OK退出软件校准模式短按 OKFlipperZero 端——同样不要触碰模拟控制停止校准按钮闪烁校准所有模拟控制的中心位置加速度计暂不支持中心校准。从源码看校准策略由ecCalib枚举wii_ec.h驱动typedef enum ecCalib { CAL_FACTORY 0x01, // (re)set to factory defaults CAL_TRACK 0x02, // track maximum and minimum values seen CAL_RESET 0x04, // initialise ready for software calibration CAL_RANGE 0x08, // perform software calibration step CAL_CENTRE 0x10, // reset centre point of joystick CAL_NOTJOY 0x20, // do NOT calibrate the joystick } ecCalib_t;软件校准数据在每个设备中以 5 个槽位组织0最低见过值1min2mid3max4最高见过值见 wii_ec.h 的ecCal联合体注释。Nunchuck 的校准实现wii_ec_nunchuck.c在CAL_RESET时会将 LO 置为最大值10bit 值上限、HI 置为零以便后续通过扫描逐步收敛到真实行程。事件驱动架构从轮询到消息队列插件并非简单死循环读寄存器而是由定时器驱动的事件驱动架构状态结构体state_twii_anal.h包含定时器timer/timerHz/fps、当前/前一场景、校准状态、暂停标志、通知队列用于拍打背光看门狗与wiiEC_t控制器状态轮询核心是ecPoll()wii_ec.c未初始化时尝试ecInit()成功后向消息队列投递WIIEC_CONN连接事件已初始化时调用ecRead()根据返回值处理2 设备断开投递WIIEC_DISCONN0 读取成功调用设备专属check()函数3 瞬时读失败直接忽略其余为不应发生的 bug 分支事件类型枚举wiiEcEventTypewii_ec.hWIIEC_NONE、WIIEC_CONN、WIIEC_DISCONN、WIIEC_PRESS、WIIEC_RELEASE、WIIEC_ANALOG摇杆/扳机变化、WIIEC_ACCEL加速度变化Nunchuck 的nunchuck_msg()通过宏BUTTON()/ANALOG()/ACCEL()将新老解码数据逐项比对仅在变化时投递对应事件wii_ec_nunchuck.c。Nunchuck 原始字节的解码逻辑nunchuck_decode()很值得参考6 字节中joy[0]/joy[1]直接对应摇杆 XYjoy[5]的低 2 位是按钮 C/Z取反低电平有效而加速度计的 10bit 精度由高 8 位字节与joy[5]中的高位拼接而来p-accX ((uint16_t)joy[2] 2) | ((joy[5] 2) 0x03); // {10} p-accY ((uint16_t)joy[3] 2) | ((joy[5] 4) 0x03); // {10} p-accZ ((uint16_t)joy[4] 2) | ((joy[5] 6) 0x03); // {10}DEBUG 屏幕与日志系统在除 SPLASH 外的任意屏幕长按 Down进入 Debug 模式进入后实时扫描停止Up— 尝试初始化已连接的控制器OK— 从控制器读取一次数据长按 Down— 重启实时扫描并返回 WAIT 屏幕。日志查看方式通过 USB 连接 Flipper Zero使用串口终端minicom、putty等启动log功能即可看到调试消息。日志级别可在编译期通过LOG_LEVEL限制bc_logging.h也可在运行期通过FZ - Settings - System - LogLevel调整FURI 日志共 6 级1None2Errors3Warnings4Information5Debug6TraceLOG_LEVEL N时对应宏会被替换为空操作从而减小插件体积文档特别提示自 FAP 支持引入后编译期裁剪对体积的意义可能已经不大源码默认#define LOG_LEVEL 4且注释警告若同时将编译期与运行期日志都开到 TRACE6插件退出时可能导致 FZ 崩溃。用./info.sh可一键查看源码中所有LOG_LEVEL的使用点与 TODO 标记。源码结构从文件清单到新增一款控制器仓库 wii_ec_anal 目录开发笔记见 README.txt组织如下文件职责README.md /_images/用户手册正文与配图application.famFAP 清单appidwii_ec_anal类别GPIO_Extra图标WiiEC.png源码通配wii_*.cgfx/*.c栈 2KBwii_anal.c /.h主应用场景机、事件循环、状态管理wii_anal_ec.c /.h扩展控制器相关动作wii_anal_keys.c /.h按键处理wii_anal_lcd.c /.hLCD 绘制函数wii_i2c.c /.hi2c 通信层初始化/读取/解密wii_ec.c /.h扩展控制器通用函数与ecId[]设备表wii_ec_nunchuck.c /.hNunchuck 专属场景wii_ec_classic.c /.hClassic Controller Pro 专属场景wii_ec_udraw.c /.huDraw 场景未完成i2c_workaround.hFZ i2c 库 bug 的临时绕行方案bc_logging.h / err.h日志宏与错误定义info.sh从源码提取支持列表/日志级别/TODO为插件添加新的扩展控制器类型开发笔记README.txt给出了标准扩展流程以新增 mydev 为例新建wii_ec_mydev.c与wii_ec_mydev.h实现以下函数含原型bool mydev_init(wiiEC_t*)— 额外初始化代码void mydev_decode(wiiEC_t*)— 解码控制器输入数据void mydev_msg(wiiEC_t*, FuriMessageQueue*)— 向事件队列投递消息void mydev_calib(wiiEC_t*, ecCalib_t)— 校准函数void mydev_show(Canvas*, state_t*)— 场景 LCD 绘制bool mydev_key(const eventMsg_t*, state_t*)— 场景按键处理在 wii_ec.h 中#include wii_ec_mydev.h并在enum ecPid增加PID_MYDEV在 wii_anal.h 的enum scene中增加SCENE_MYDEV在 wii_ec.c 的ecId[]表中注册设备[PID_MYDEV] { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, My Device, SCENE_MYDEV, mydev_init, mydev_decode, mydev_msg, mydev_calib, mydev_show, mydev_key },这就是ecId_t中那组函数指针init/decode/check/calib/show/keys的实际用法——插件正是通过这张设备驱动表实现了解码、消息、校准、绘制与按键的多态分发顶层ecDecode()/ecCalibrate()先判断对应函数指针是否存在再调用见 wii_ec.c。已知问题与限制TODO原文档在 TODO 一节记录了一个重要问题并在源码中留有对应证据FZ i2c bug写作当时 FlipperZero 固件的 i2c 库存在缺陷本插件通过 i2c_workaround.h 提供临时绕行——所有 i2c 调用被包装为acquire → 操作 → release的形式furi_hal_Wi2c_is_device_ready/tx/rx/trx并额外提供带读延时的furi_hal_i2c_trxd()。notes.txt中还保留了完整的修复参考代码与region locking的固件定位线索。其余已知限制文档与源码交叉确认加密功能未使用、未测试且部分不可用仅支持 encryption-bypass 控制器仅官方 Nunchuck 与 Classic Controller 得到实际验证uDraw 设备仅注册了udraw_init场景未编写LCD 滚动显示因刷新率不足被禁用加速度计暂不支持软件校准中心点CAL_CENTRE注释为 accelerometers not supported (yet)。结语一份可复用的 i2c 外设分析范本wii_ec_anal 的价值不仅在于能读双节棍数据它的多场景 GUI 事件驱动轮询 设备驱动表 双缓冲解码 工厂/软件双层校准设计为在 Flipper Zero 上逆向与调试任何 i2c 外设提供了一个高完成度的参考范本。无论你是想直接用它测试手中的 Nunchuck/Classic 手柄还是想照葫芦画瓢为自己的扩展控制器写一个专属场景本文结合 README.md 与源码给出的接线表、寄存器映射、初始化握手与校准流程都能作为你起步的地图。【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考