十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Flipper Zero 上的 Wii 扩展控制器协议分析仪:从接线、识别到校准的完整实战指南

Flipper Zero 上的 Wii 扩展控制器协议分析仪:从接线、识别到校准的完整实战指南 Flipper Zero 上的 Wii 扩展控制器协议分析仪从接线、识别到校准的完整实战指南【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper本篇文章基于 Flipper 仓库 Applications/Official/source-OLDER/grnch/wii_ec_anal 目录下的 Wii Extension Controller Protocol AnalyserWii 扩展控制器协议分析仪项目文档结合其完整 C 源码展开。你将掌握如何在 Flipper Zero 上通过 I2C 连接 Wii 外设Nunchuck、Classic Controller 等、协议分析仪的每个屏幕与按键功能、模拟量校准机制以及底层 I2C 寄存器级通信原理。项目是什么Wii Extension Controller Protocol Analyser 是一个跑在 Flipper Zero 上的协议分析仪插件提供了一套完整的Test测试与 Calibrate校准系统用于连接和调试 Wii 扩展控制器Wii Extension Controller。它属于本项目仓库作者 stuff I make or modify for the Flipper Zero 的收集内容之一位于Applications/Official/source-OLDER目录即官方来源的早期版本归档区。项目在 application.fam 中注册为外部应用appidWii_EC_Analyser nameWii EC Analyser apptypeFlipperAppType.EXTERNAL entry_pointwii_ec_anal requires[gui] stack_size2 * 1024 sources[wii_*.c, gfx/*.c] fap_categoryMisc插件入口函数为wii_ec_anal()实现在 wii_anal.c它创建一个 20 条消息的事件队列、一个 GUI ViewPort、一个周期性定时器然后进入主事件循环。启动后会先显示 SPLASH 屏3.5 秒超时或任意按键短按后进入 WAIT 屏并开始扫描 I2C 总线。免责声明原文档明确强调使用本插件、尤其是将扩展控制器连接到 Flipper Zero 的操作完全由使用者自担风险。请务必在确认接线正确后再上电。硬件接线WAIT 屏与引脚映射插件启动并进入 WAIT 屏后屏幕上会直接绘制出需要连接的引脚示意图。接线前请先确认所有连接都已断开电源。从扩展控制器插头的露出面观察凹槽朝下各引脚定义如下表EC 引脚号EC 位置EC 引脚 ID功能FZ GPIO 引脚名FZ GPIO 引脚号1左上3v3电源3v392左下SCLI2C 时钟C0163上中EN疑似检测脚未验证——4下中-x-无连接——5右上SDAI2C 数据C1156右下Gnd电源地Gnd18也就是说实际只需连接4 根线3v3 → 3v3、C0 → SCL、C1 → SDA、Gnd → Gnd。顶部居中的 EN 脚作者认为是存在检测presence detect功能但尚未验证本插件不需要该引脚设备检测完全依靠 I2C 握手完成。WAIT 屏的按键Left左键回到 SPLASH 屏Back返回键退出插件WAIT 屏的实际绘制代码在 wii_anal.c 的SCENE_WAIT分支中它把 3v3、C1/SDA、Gnd、C0/SCL 的图形和文字标注逐像素画到屏幕上。适配器选择与接线警告最省事的连接方案是使用现成的WiiChuck或Nunchucky适配器原文给出了两者购买渠道此处不赘述外链。但必须注意警告WiiChuck 与 Nunchucky 都没有防反接的极性机构。如果插反你会把电压以错误的方向加到控制器上作者表示无法确认这是否会永久损坏控制器——没人愿意去试。对常见的 WiiChuck 适配器作者观察到WiiChuck 一侧有3 个连接器另一侧有2 个连接器有 2 个连接器的一侧应对准控制器插头上带大凹槽的一侧。即便如此强烈建议在插入前核对适配器各引脚的实际定义。加密与加密绕过策略Wii 扩展控制器支持 I2C 加密通信但本插件中加密相关的代码虽然存在却是未使用、未测试的并且已知部分不工作。当前插件只支持实现加密绕过encryption-bypass策略的扩展控制器即上电初始化时执行i2c_write(0xf0, 0x55); i2c_write(0xfb, 0x00);这在源码 wii_i2c.c 中对应static const uint8_t cmdInit1[] {regInit1, 0x55}; // regInit1 0xF0 static const uint8_t cmdInit2[] {regInit2, 0x00}; // regInit2 0xFB即先向寄存器0xF0写入0x55再向0xFB写入0x00让控制器进入不加密模式。若你需要加密支持作者建议到上游仓库提交 Issue或者更好——提交 Pull Request。wii_i2c.c中还保留了一个decrypt()函数见 wii_i2c.c它实现decrypted_byte (encrypted_byte XOR encKey[1][addr%8]) encKey[2][addr%8]的标准解密算法但由于加密链路本身未打通该函数实际上不会被可靠调用。设备识别I2C 握手与 PID 表当设备连接后插件会立即识别。如果识别失败可能的原因有二控制器没有正确连接——也许只是一根线断了控制器板卡本身故障——修复超出了本文档范围。识别流程在ecInit()wii_i2c.c中实现先检查设备是否在线furi_hal_i2c_is_device_ready发送初始化命令然后从寄存器0xFA..0xFF读取6 字节的外设 IDPID最后在已知设备表中逐条memcmp匹配匹配失败则归为PID_UNKNOWN。运行./info.sh脚本即仓库内的 info.sh可以查看已知控制器列表。作者写文档时返回如下注意info.sh第一行就自嘲地输出MARKED AS TODO说明项目仍处于开发中状态[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,可见共8 个已知设备1 个是未知设备的默认项7 个设备按名字识别其中 2 个Nunchuck 与 Classic Controller拥有定制的场景scene即SCENE_NUNCHUCK与SCENE_CLASSIC。其余设备Balance Board、Guitar Hero 吉他、鼓、DJ Hero 转盘、太鼓虽然能被 PID 识别但只使用通用的 DUMP 屏。这一 PID 表在源码中对应 wii_ec.c 的ecId[PID_CNT]全局数组。每个条目是一个ecId_t结构定义见 wii_ec.h包含id[6]6 字节 PID 字符串name友好名称scene默认场景init额外的初始化回调如 uDraw 平板需要decode解码函数check检查动作函数calib软件校准函数show绘制场景函数keys按键解释函数Nunchuck 条目挂接的是nunchuck_decode / nunchuck_msg / nunchuck_calib / nunchuck_show / nunchuck_keyClassic Controller 条目挂接的是classic_decode / classic_msg / classic_calib / classic_show / classic_key——这种函数指针表设计让新增设备支持变得非常简单。此外ecId表中还能看到两个 README 中未列出的条目PID_NUNCHUCK_R2{0xFF, 0x00, 0xA4, 0x20, 0x00, 0x00}Nunchuck (rev2)与PID_CLASSIC_PRO{0x01, 0x00, 0xA4, 0x20, 0x01, 0x01}Classic Controller Pro说明源码较 README 又前进了一步。屏幕详解插件基于场景scene驱动 UI场景枚举定义在 wii_anal.hSCENE_SPLASH / SCENE_RIP / SCENE_WAIT / SCENE_DEBUG / SCENE_DUMP / SCENE_CLASSIC / SCENE_CLASSIC_N / SCENE_NUNCHUCK / SCENE_NUNCHUCK_ACC。SPLASH 屏插件启动时显示 SPLASH 屏。按任意键可立即清除否则3.5 秒后自动清除并进入扫描状态对应 wii_anal.c 中的tmo 3.5 * 1000超时逻辑。NUNCHUCK 主屏连接 Nunchuck 后主屏显示加速度计Accelerometer {X, Y, Z}数值摇杆Joystick {X, Y}数值摇杆位置图形按键Button {C, Z}状态按键Left前往 DUMP 屏Right前往加速度计屏Up / Down / OK见下文Peak Meters峰值表短按 Back复位控制器长按 Back退出插件NUNCHUCK 加速度计屏加速度计屏以波形图方式实时绘制三轴读数。轴的移动方向语义如下表轴移动低值高值X左 / 右左右Y前 / 后前后Z下 / 上下上要点沿某轴平移会改变该轴的读数绕某轴扭转/倾斜会改变另外两轴的读数例如向左平移沿 X 轴影响 X向左转身绕 Y 轴旋转影响 X 和 Z。源码 wii_ec_nunchuck.c 的nunchuck_showAcc()中实现了带死区dead 1 5的三段式归一化中值附近归为中间区上下极限归为端点其余按剩余区间均分为 6 档映射到屏幕上的绘图高度。注释里还提到存在滚动显示的代码但LCD 刷新率太低看起来糟透了因此实际没有启用滚动。按键Left返回 NUNCHUCK 主屏Up三态切换——Auto-Pause 已禁用 → 启用 Auto-Pause在一页末尾暂停 → 重新开始扫描Auto-Pause 启用中运行 → 禁用 Auto-PauseNunchuck-Z切换暂停Nunchuck-C切换自动暂停长按 OK进入软件校准模式见下文校准在加速度计屏上进入校准只会校准加速度计短按 OK退出软件校准模式并校准 CENTRE中心位置短按 Back复位控制器长按 Back退出插件CLASSIC 屏连接 Classic Controller [Pro] 后屏幕上会绘制一个经典手柄图形手柄会跟随控制器事件实时动画按键按下、摇杆移动、扳机深浅都会反映在图形上扫描率设为30fps但实际 LCD 有一定延迟所以实际帧率因人而异YMMV。按键Left前往 DUMP 屏Right显示模拟量读数再按一次 Left 隐藏Up / Down / OK见Peak Meters短按 Back复位控制器长按 Back退出插件Classic Controller 的字节解码逻辑在 wii_ec_classic.c 的classic_decode()中。从 6 字节原始数据中拆出 2 个 6 位摇杆、2 个 5 位摇杆、2 个 5 位扳机trgZL/trgZR、方向键、A/B/X/Y、L/R、/-/Home等全部输入。作者注释特别指出左摇杆比右摇杆多 1 位精度且trgZL/trgZR在对应数字按键btnZL/btnZR触发后仍会继续增长。绘制部分使用了一整套手柄素材图gfx/images.h 中如img_cc_Main、img_cc_trg_L1..L4、img_cc_pad_UD1、img_cc_btn_X1等根据当前解码值选择性地叠印按键/摇杆/扳机图层。DUMP 屏DUMP 屏显示设备原始读数。任何没有专属_decode()等函数的设备连接后都只会看到这个屏幕。屏幕内容SIDString ID——来自info表的可读名称PIDPeripheral ID——标识设备的 6 个字节Cal校准数据——16 字节底部的六字节十六进制为控制器数据每个十六进制数字下方是对应的二进制位表示例连接 Nunchuck 时按 Z 键观察最右侧的那一位会翻转按键Right返回控制器专属屏幕如果有短按 Back复位控制器长按 Back退出插件DUMP 屏绘制函数ec_show()在 wii_ec.c它把 SID、PID、Cal 与 6 字节读数逐位bit-by-bit画出来ec_key()同文件 L286-L297则处理 Right 键返回上一场景的逻辑。这也从源码角度印证了 README 的说法未知设备PID_UNKNOWN的默认场景就是SCENE_DUMP其show函数同样复用ec_show。Peak Meters峰值表 / 校准值显示在任何带有 Peak/Trough 菜单的控制器专属屏幕上Up切换为只显示峰值peakDown切换为只显示谷值trough长按 OK进入软件校准模式见下文校准短按 OK退出软件校准模式 / 校准 CENTRE 位置状态变量state-hold见 wii_anal.h负责记录显示模式-1表示谷值保持、0表示实时值、1表示峰值保持。校准Calibration这是本项目最有价值的部分。原文特别强调本项目处理模拟量控制的校准但目前对加速度计数值没有任何理解yet。要点数字按键不需要校准部分校准数据由出厂时计算好并存储在控制器内存疑似 OTP中每种设备的校准数据解读方式不同——例如 Nunchuck 有 1 个摇杆 加速度计而 Classic Controller 有 2 个摇杆 2 个模拟扳机作者实测发现出厂校准数据往往不准猜测控制器常年漂移所致。若出厂值限制了行程很容易通过在线扩展解决但如果出厂数据给出的极限比摇杆实际可达范围更远就需要对控制器做完全重新校准。推荐的校准方法在控制器**静止且水平at rest**时采集若干读数将控制器移动到所有极限位置记录极限 {peak/trough} 值。据称任天堂会在控制器刚连接后立即取一次静止读数并且同时按住 {A, B, , -} 至少 3 秒即可随时重新校准作者没有掌握该操作的具体内部细节。本工具的校准流程控制器首次被识别时用出厂校准数据决定每个模拟控制的中心/中间位置与极限值如最左、最右。长按 OKFlipper Zero 上进入软件校准模式。按下期间不要触碰任何模拟控制器校准图标开始闪烁取当前读数为中心位置将范围极限设为无范围现在你需要把控制器在各个极限之间来回移动让代码计算出新的校准/范围/peaktrough 值完成后按短按 OK退出软件校准模式。短按 OKFlipper Zero 上按下期间不要触碰任何模拟控制器停止校准图标闪烁校准所有模拟控制的中心位置加速度计暂不支持。校准的底层实现在每个设备的*_calib()函数中核心是 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;以 Nunchuck 为例wii_ec_nunchuck.cCAL_RESET把 LO 预置为最大值以便被调低、HI 预置为零以便被调高对摇杆8 位与加速度计10 位分别初始化CAL_FACTORY从 16 字节出厂校准数据pec-calF[]恢复各轴中心与 0G/1G 参考点摇杆则取calF[8..13]中的 X/Y 低-中-高值Nunchuck 出厂摇杆数据格式为{maxX, minX, midX, maxY, minY, midY}即代码中的FACTORY_HI(joyX, calF[8])、FACTORY_LO(joyX, calF[9])、FACTORY_MID(joyX, calF[10])等对应关系加速度计的 0G/1G 参考点则由calF[0..7]按位拼装为 10 位值CAL_TRACK持续跟踪实际见到的最大/最小值CAL_RANGE在软件校准模式下按用户操作重算范围CAL_CENTRE把当前读数写回中心点。Classic Controller 的校准wii_ec_classic.c与之类似但摇杆量程不同左摇杆是 6 位出厂数据2对齐右摇杆是 5 位出厂数据3对齐扳机trgZL/trgZR出厂校准策略目前未知代码里用经验值0x03下限与0x1B中点兜底。DEBUG 屏与日志调试在任何屏幕SPLASH 除外按长按 Down即可进入 Debug 模式。进入 DEBUG 屏后实时扫描器会停止此时可用按键Up尝试初始化已连接的控制器OK对控制器采一次读数长按 Down重启实时扫描器并返回 WAIT 屏你可以在任意时刻通过 USB 连接 Flipper Zero 的串口控制台minicom、putty等开启log功能查看调试消息。日志输出量可在编译期参见info.sh它通过grep LOG_LEVEL *.h列出可调整的日志级别宏或运行期Flipper 菜单Settings - System - LogLevel进行限制。原文特别注明这可能在 FAP 支持引入后已经过时——如果遇到内存问题编译期限制日志可以让插件体积更小但限制越多发给日志系统的调试信息就越少。底层 I2C 协议与已知缺陷wii_i2c.c头部注释完整记录了 Wii 扩展控制器的寄存器布局总线地址0x52读操作后寄存器自动递增0x00..0x05 ( 6 bytes) ... [r] 控制器数据 (Controller Data) 0x20..0x2F (16 bytes) ... [r] 校准数据 (Calibration Data) 0x30..0x3F (16 bytes) ... [r] 校准数据副本 0x40..0x4F (16 bytes) ... [w] 加密密钥 0xFA..0xFF ( 6 bytes) ... [r] 外设 ID (Peripheral ID)对应的常量定义在 wii_i2c.cregJoy 0x00、regCal 0x20、regEnc 0x40、regPid 0xFA。值得一提的实现细节可作扩展控制器开发参考轮询模型主循环通过定时器消息触发ecPoll()wii_ec.c它维护一个有限状态机未初始化则尝试ecInit()成功发WIIEC_CONN事件已初始化则ecRead()设备消失返回 2 发WIIEC_DISCONN事件读失败返回 3 则暂时忽略可能只是瞬时问题事件驱动ecPoll()产生的WIIEC_CONN / DISCONN / PRESS / RELEASE / ANALOG / ACCEL事件枚举见 wii_ec.h与按键事件、定时器事件统一走消息队列由主循环分发i2c_workaround原文档 TODO 提到写文档时 FZ 的 i2c 函数存在问题。对应的修复思路记录在 i2c_workaround.h 中它用宏把furi_hal_i2c_*系列调用替换为furi_hal_Wi2c_*包装函数每次操作前后显式acquire/release总线同时提供furi_hal_i2c_trxd()——在设地址与读数据之间插入furi_delay_us(us)延迟因为有些设备需要一点时间才能响应读请求。相关上游问题为 flipperzero-firmware issue #1670原文注释提及此处不展开外链。结语Wii Extension Controller Protocol Analyser 是一份结构清晰、开箱即用的 Flipper Zero 外设协议分析示例它完整覆盖了接线 → I2C 识别 → 解码 → 屏幕可视化 → 软件校准 → 串口调试的整条链路。得益于ecId_t函数指针表的架构wii_ec.h扩展新控制器只需在表中新增条目并实现decode/msg/calib/show/keys五个回调。如果你正打算在 Flipper Zero 上折腾 Wii 外设或想研究裸 I2C 外设的插件开发范式这个项目的源码wii_i2c.c、wii_ec.c、wii_ec_nunchuck.c、wii_ec_classic.c与配套图片资源_images都是绝佳的参考资料。需要提醒的是加密支持、加速度计校准仍是 TODO接线上电前务必再读一遍接线警告。【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表