Maku-hub/TrikiScope
GitHub: Maku-hub/TrikiScope
一款基于终端的 BLE 设备检查工具,用于逆向分析 Żabka Triki 纽扣控制器的 IMU 数据流、3D 姿态及 GATT 协议。
Stars: 1 | Forks: 0
# TrikiScope
[](LICENSE)
[](https://www.python.org/)
[](https://github.com/Maku-hub/TrikiScope/actions/workflows/tests.yml)
一个开源的终端 (TUI) BLE 读取器和检查器,专为 **Żabka Triki** 设备设计,
使用 Python 编写——旨在获取关于该设备的**最大量信息**。
Żabka 的 **Triki** 是一款外形像纽扣的微型移动游戏控制器,
可与 Żappka 应用程序配合使用。它通过动作控制游戏(根据成绩可获得 żappsy、
折扣以及 Żabka 生态系统中的奖励)。其内部带有一个 IMU 传感器(陀螺仪 + 加速度计),
因此能够检测旋转、倾斜和抛掷动作。它通过
Bluetooth Low Energy 与智能手机进行连接。
TrikiScope 通过 BLE 连接到该纽扣设备,读取所有可读取的数据,解码
IMU 数据流,并实时可视化 3D 姿态。

## 功能展示
丰富的终端仪表盘(基于 Textual/Rich),包含以下标签页:
- **Overview** — 连接状态、连接运行时间 (uptime)、BLE 广播数据
(RSSI、发射功率、带有 Company ID 解码的 `manufacturer data`、service
UUIDs、service data)、完整的设备信息(制造商、型号、序列号、
firmware/hardware/software 版本、System ID、PnP ID、MTU、从名称解析的 Device ID)、电池电量以及 LED 指示灯状态。
- **GATT** — 完整的 GATT 数据库清查:services (服务) → characteristics (特征) →
descriptors (描述符),包含其属性(read/write/notify/indicate)、句柄以及
读取到的值(文本 + 十六进制)。部分选定值会解码为
“人类可读”的形式(连接参数、PnP ID、appearance、电池等)。
- **IMU** — 实时数据流:原始的 `int16` 以及转换后的陀螺仪
(deg/s) 和加速度计 值、向量大小 (magnitudes)、活动状态 sparkline 图表、流统计信息
(通知数、帧数、丢失字节数、中断间隔、采样频率、
数据包大小直方图、带宽)以及最新一帧的十六进制数据。
**Motion** 面板:按钮状态 + 按压计数、检测到的手势
(TAP/IMPACT、FREE-FALL/THROW、SHAKE、SPIN)以及陀螺仪/加速度计的峰值数据。
- **Orientation** — 通过 **Madgwick AHRS**(或
互补滤波器)计算的 3D 姿态,并通过旋转的 ASCII 立方体骨架进行可视化显示,
包含 pitch/roll/yaw 角度和四元数。在数据流启动时进行自动校准。
- **Games** — 几款由纽扣设备实时控制的简单 ASCII 游戏(基于
同一个 IMU 数据流):**Tilt Maze**(通过倾斜引导小球到达目标)、
**Spin Meter**(尽快旋转纽扣——测量峰值旋转
速度)和 **Reflex Catch**(反应测试:在出现信号时通过点击/按键作出反应)。使用 `[` / `]` 键切换游戏,`g` 键重启当前游戏。
- **Log** — 可滚动的事件日志(连接、按键、手势、LED 等)。
数据可以保存为 **CSV**(IMU 数据流 + 角度 + 按钮状态)和
**事件日志**。可以通过按 `l` 键控制纽扣设备上的 LED 指示灯。
## 系统要求
- 开启了蓝牙的 Windows 10/11(得益于 `bleak`,也可在 Linux/macOS 上运行),
- Python 3.10+,
- 开启状态的 Triki 设备且在附近(如果处于休眠状态——在进行连接前
请按一下纽扣设备上的按钮)。
## 安装说明
```
cd TrikiScope
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
```
## 运行说明
最简单的方法是使用启动器(无需手动激活 venv):
```
.\run.ps1 # PowerShell – z auto-połączeniem
```
```
run.bat :: cmd / dwuklik w Eksploratorze – z auto-połączeniem
```
或者直接通过模块运行:
```
.\.venv\Scripts\python.exe -m trikiscope --auto-connect
```
不自动连接(在应用程序中按 `c` 键进行连接):
```
.\.venv\Scripts\python.exe -m trikiscope
```
如果纽扣设备处于休眠状态——在连接前按下其按钮以唤醒设备。
### 快捷键
| 按键 | 操作 |
|--------|-------|
| `c` | 连接(扫描 + 连接) |
| `d` | 断开连接 |
| `r` | 在当前姿态下重置方向 |
| `z` | 重新校准(请保持静止) |
| `m` | 切换方向滤波器(Madgwick / 互补滤波器) |
| `s` | 开启/关闭 CSV 录制 |
| `l` | 点亮/熄灭纽扣设备上的 LED |
| `1`–`6` | 切换标签页 (Overview / GATT / IMU / Orientation / Games / Log) |
| `[` / `]` | (Games) 上一个 / 下一个游戏 |
| `g` | (Games) 重启当前游戏 |
| `q` | 退出 |
### 扫描模式(无 TUI)
列出所有正在广播的 BLE 设备(有助于查找设备名称/地址):
```
.\run.ps1 --scan
```
### 常用选项
```
--name TEXT fragment nazwy urządzenia (domyślnie "Triki")
--scan-timeout SEC czas skanowania (domyślnie 30)
--gyro-scale FLOAT LSB na deg/s (domyślnie 131.0)
--accel-scale FLOAT LSB na g (domyślnie 2048.0)
--settle-delay SEC odczekaj N s przed wysłaniem komendy startowej (domyślnie 0)
--discard N liczba początkowych próbek do odrzucenia (domyślnie 20)
--start-command HEX komenda startowa na NUS RX (domyślnie 201000D007680003)
--no-start nie wysyłaj komendy startowej automatycznie
--auto-connect połącz się zaraz po starcie
--mode {madgwick,complementary} filtr orientacji (domyślnie madgwick)
--record nagrywaj od razu
--csv PATH / --log PATH ścieżki plików wyjściowych
--scan wypisz urządzenia BLE i zakończ (bez TUI)
```
通过 `.\run.ps1 --help` 查看完整列表。
## BLE 规范
该设备使用 **Nordic UART Service** 进行通信:
- Service UUID: `6e400001-b5a3-f393-e0a9-e50e24dcca9e`
- RX Characteristic (写入,手机 → 设备): `6e400002-b5a3-f393-e0a9-e50e24dcca9e`
- TX Characteristic (通知,设备 → 手机): `6e400003-b5a3-f393-e0a9-e50e24dcca9e`
应用程序订阅来自 TX 的通知,并向 RX 发送初始化数据传输的命令:
```
20 10 00 D0 07 68 00 03
```
此外,在 NUS 服务中还有一个 `6e400004-…` 特征(支持 read/write)。我们通过
实时的实验发现,其 **bit 0 控制着** 纽扣设备上的 **LED 指示灯**(`01` = 亮起,
`00` = 熄灭;该值会被掩码处理为 1 个 bit)。在应用程序中按下 `l` 键即可点亮/熄灭 LED。
## IMU 数据格式
IMU 数据以带有 `22 00` 标头的 **14 字节** 数据帧形式传入:
```
22 00 | gyroX | gyroY | gyroZ | accelX | accelY | accelZ
```
每个轴均为采用 little-endian 格式的带符号 16 位整数。
默认的硬件缩放转换系数为:陀螺仪 `131.0`(LSB 转换为 deg/s)
以及加速度计 `2048.0`(LSB 转换为 g)。
**标头的第二个字节是按钮标志**(通过在监听 BLE 时按下按钮发现):`22 00` = 按钮释放,`22 01` = 按钮按下。在这两种情况下,payload 是
完全相同的。TrikiScope 会对这两种标头进行解析,因此在
按下操作期间不会丢失数据帧,并能显示按钮状态以及按压计数。
对捕获的 BLE 通信以及 Żappka `4.37.0` 应用程序的分析表明,该数据流
以 BLE burst(突发传输)的形式到达,通常在短数据包中包含多个数据帧。TrikiScope 使用
BLE 通知的 timestamp 作为采样时间源(因为在实际应用中,实验性的约
`104 Hz` 的固定时钟效果较差)。解析器会在标头
(`22 00` 或 `22 01`)之后重新同步,因此在出现粘连/截断的通知后能够恢复数据流
并且不会丢失按下按钮时的数据帧。
在数据流启动时,设备会发出短暂的“噪音”——最初的几个采样(默认为 20 个)
会被丢弃。
## 方向姿态
姿态通过两种可互换的滤波器进行计算(通过 `m` 键切换):
- **Madgwick AHRS** — 将陀螺仪和加速度计数据进行融合以转换为四元数,带有自动校准(静止时 auto-zero)、
SLERP 平滑处理以及视觉盲区。
- **互补滤波器** — 直接从互补滤波器中提取 pitch/roll/yaw 数据
(“Zappka-like”模式)。
## 硬件
Triki 基于:
- **MCU:** Nordic Semiconductor nRF52810 (BLE),
- **IMU:** ST LSM6DSL (加速度计 + 陀螺仪),
- **外部 Flash:** Macronix MX25R8035F (8 Mbit / 1 MB, SPI),
- **DEBUG:** PCB 上的 SWD 引脚;设备受 **Nordic APPROTECT** 保护
(在不完全擦除芯片的情况下,读取 firmware/debug 将被阻止)。
详细的硬件说明(引脚分配、PCB 照片、OpenOCD/SWD、Flash 转储)位于
独立的项目中:。
## 诊断工具 (`tools/`)
在对设备进行逆向工程时使用的辅助脚本(需在
TUI 应用程序关闭时单独运行):
- `diagnose.py` — 完整转储:广播数据、带值的 GATT、数据流分析。
- `probe_button.py` — 用于检测按钮数据帧 (`22 01`) 的交互式测试。
- `probe_led.py` — 确认 LED 控制(闪烁模式)。
- `probe_write_vendor.py` — 针对 `6e400004` 的安全测试。
- `probe_ble_layer.py` — 生产级 BLE 端到端层测试。
```
.\.venv\Scripts\python.exe tools\diagnose.py
```
## 测试
```
.\.venv\Scripts\python.exe -m pip install pytest
.\.venv\Scripts\python.exe -m pytest
```
## 姊妹项目 — TrikiEmu
**[TrikiEmu](https://github.com/Maku-hub/TrikiEmu)** 是 TrikiScope 的逆向项目:它不是去*读取*纽扣设备,而是**模拟**该设备。由 ESP32 充当
BLE *peripheral*,重现 Triki 的身份和配置文件(广播、NUS、IMU 数据流),从而使得
Żappka 应用程序像连接真实的纽扣设备一样连接到它,并且动作数据可从计算机端输入。
TrikiScope 是 BLE *central*(客户端),而 TrikiEmu 是 *peripheral*(服务端);所有关于协议的知识
均来源于此处完成的逆向工程工作。TrikiScope 还充当
**验证仿真器的已知良好 central 端**,然后才会将其接入 Żabka 应用程序中。
## 免责声明
本项目出于教育和文档说明目的。与 Żabka 公司无任何关联。
标签:GATT协议, Python, 传感器数据分析, 安全规则引擎, 无后门, 物联网, 物联网设备调试, 终端用户界面(TUI), 蓝牙低功耗(BLE), 逆向工具