【免费下载链接】muse-gadget-sdk
Open source SDK to build Muse gadgets
本文介绍 muse-gadget-sdk 仓库中的 UI 模拟器(esp32/simulator/):它如何直接编译生产环境的muse_ui.c、状态机与像素头像渲染代码,在 412 x 412 的 SenseCAP Watcher 窗口里完成桌面预览;并覆盖构建、依赖解析、交互式操作、脚本化/无头渲染与自动化测试的完整流程,帮助你掌握“不改一行 UI 代码就能复现设备画面、可回归、可截图”的桌面验证方案。
一、模拟器是什么、不是什么
模拟器是 Muse 接口的桌面预览:它在 412 x 412 的 SenseCAP Watcher 窗口中渲染生产代码——包括muse_ui.c、状态与文本代码以及头像渲染器(muse_pixel.c)。SDL 负责显示、鼠标输入和计时,而一组小型主机适配层(host adapters)替代 ESP-IDF、FreeRTOS、Wi-Fi、蓝牙、Link、设置与电源服务。
需要明确的边界(来自 esp32/simulator/README.md):
- 它不模拟 ESP32-S3 CPU、Watcher 的 Himax 摄像头、音频硬件、蓝牙射频、内存压力或电源时序;
- 这些路径仍需固件构建并在真机上做最终测试;
- 它的定位是快速 UI 迭代与可重复截图,不是硬件仿真器。
从源码结构看,可执行文件muse_simulator只包含五个源文件与四个生产文件(见 CMakeLists.txt):
| 来源 | 文件 | 角色 |
|---|---|---|
| 模拟器 | src/main.c | 命令行解析、SDL 事件、场景执行、截图 |
| 模拟器 | src/sim_board.c | 412x412 桌面板级配置 + SDL 显示/触摸 |
| 模拟器 | src/sim_platform.c | ESP-IDF/FreeRTOS/mbedTLS API 的主机替身(含可推进的假时钟) |
| 模拟器 | src/sim_services.c | 内存态 Wi-Fi/BLE/Link/Chat/亮度/扬声器服务 |
| 生产代码 | components/muse/muse_ui.c、muse_state.c、muse_text.c、esp32/avatar/muse_pixel.c | 与真机完全相同的 UI 逻辑 |
compat/目录提供了esp_err.h、freertos/、mbedtls/base64.h等桩头文件,让生产代码无需 ESP-IDF 即可在桌面编译。
二、构建环境与依赖解析
2.1 主机要求
模拟器支持 Linux 与 macOS。主机需要:
- CMake 3.24 或更新版本;
- Ninja;
- 支持 C11 的 GCC 或 Clang(CMakeLists.txt 明确拒绝其他编译器,且仅支持 Unix 平台);
- Python 3.9 或更新(仅测试需要);
- 不需要 ESP-IDF。
Debian/Ubuntu 安装构建工具:
sudo apt-get update sudo apt-get install -y build-essential cmake ninja-build python3macOS 安装 Xcode 命令行工具与其余工具:
xcode-select --install brew install cmake ninja pythonxcode-select --install可能提示工具已安装,可忽略。Apple Silicon 与 Intel Mac 均可构建出原生二进制,无需 Rosetta。
2.2 SDL2 与 LVGL 的解析策略
这是构建中最容易出错的环节。CMakeLists.txt 的解析顺序为:
SDL2(优先级从高到低):
- CMake CONFIG 包
SDL2::SDL2或SDL2::SDL2-static(要求 >= 2.0.18); - pkg-config 的
sdl2>=2.0.18; - 以上都不满足且
MUSE_SIM_FETCH_DEPS=ON(默认)时,下载固定版本SDL 2.32.10源码(SHA256 校验),且只构建静态运行时(关闭 audio/haptic/hidapi/joystick/等子系统,SDL2_DISABLE_SDL2MAIN=ON)。
LVGL(总是锁定版本):默认始终下载固定版本 LVGL 9.5.0,因为生产 UI 依赖版本特定的私有 API 以及本目录lv_conf.h中启用的字体与驱动。lv_conf.h 的关键配置包括LV_COLOR_DEPTH 16(16 位色,对应设备屏幕)、LV_USE_SDL 1(启用 SDL 驱动)、Montserrat 14/16/20/28 与 Unscii 字体,默认字体为lv_font_montserrat_20。
只有在系统同时装有兼容的 SDL2 与按本配置编译的LVGL 时,才设置-DMUSE_SIM_FETCH_DEPS=OFF改用系统包;关闭后 CMake 会检查系统 LVGL 是否暴露私有头文件(src/draw/lv_image_decoder_private.h、src/misc/lv_area_private.h),不满足即报错退出。首次拉取成功后,可用-DFETCHCONTENT_FULLY_DISCONNECTED=ON复用已填充的依赖缓存,脱离网络。Homebrew 安装 SDL2 是可选的。
2.3 构建命令
从仓库根目录执行:
cmake -S esp32/simulator -B esp32/simulator/build -G Ninja \ -DCMAKE_BUILD_TYPE=Debug cmake --build esp32/simulator/build --parallel其他 CMake 选项:
| 选项 | 默认 | 说明 |
|---|---|---|
MUSE_SIM_FETCH_DEPS | ON | 无合适系统包时拉取固定版本 LVGL/SDL2 源码 |
MUSE_SIM_SANITIZERS | OFF | 以 ASan + UBSan 构建 |
MUSE_SIM_WARNINGS_AS_ERRORS | OFF | 将警告视为错误(默认已开启-Wall -Wextra -Wpedantic) |
构建完成时会打印实际选用的LVGL target与SDL2 target,可用于核对依赖解析结果。macOS 上会自动链接 IOKit 框架(SDL 的 Cocoa 显示/屏保后端即使在禁用可选电源子系统时也会使用 IOKit)。
三、交互式预览与键盘控制
在已登录的 Linux/macOS 桌面会话的终端中运行:
./esp32/simulator/build/muse_simulator鼠标输入作为触摸。键盘控制常用 UI 状态(main.c 中通过SDL_AddEventWatch注册的事件监听实现):
| 按键 | 动作 |
|---|---|
| F1 ... F7 | Boot、idle、listening、thinking、speaking、error、off 七个状态 |
| H | 触发 happy idle 动画 |
| Space(按住) | 按住时进入 listening,松开切换为 thinking |
+/- | 提高/降低音频电平(每步 0.1) |
[/] | 降低/提高回合进度(每步 0.1) |
| S | 切换睡眠 |
| P | 在当前目录保存muse-simulator.ppm |
| Esc | 退出 |
muse_simulator --help会输出同样的控制说明与全部命令行选项。MacBook 上若系统未将 F1–F7 配置为标准功能键,需按住 Fn 或地球键再按。
源码中有一个值得注意的细节:生产端关闭流程之后只允许进入 Idle 模式,而模拟器为了让预览可控,在选择任意状态前会先强制回到MUSE_MODE_IDLE再切换到目标模式(main.c 的 select_mode),注释里明确这是“Preview controls should still be able to select any state after showing Off”的设计取舍。
3.1 手工冒烟测试清单
README 给出的一套快速验证流程:
- 确认打开固定尺寸 412 x 412 的
Muse Gadget Simulator窗口; - 按 F3 进入 listening,用
+/-调节电平表; - 按住 Space 进入 listening,松开进入 thinking,进度环应变成移动段;
- 按 F5 进入 speaking,用
+/-让嘴部动画; - 按 H 确认头像执行 happy 动画;
- 按 S 睡眠,点击黑屏唤醒;
- 向左拖拽打开设置占位页,向右拖拽回到头像(模拟器未实现设置控件);
- 按 P 确认当前目录出现
muse-simulator.ppm,然后按 Esc 退出。
场景文件同样可以初始化一个可见的交互会话:
./esp32/simulator/build/muse_simulator \ --scenario esp32/simulator/tests/scenarios/pairing.txt例如仓库自带的 pairing.txt 会呈现含六位配对码(passkey=123456)的配对提示界面。交互式窗口需要显示会话;SSH 或 CI 环境请加--headless。
四、脚本化与无头渲染
4.1 场景文件格式
场景是一个文本文件,每行一条key=value设置;空行与以#开头的行被忽略;设置按文件顺序应用,因此advance可以在下一项变更之前渲染出中间状态。main.c 的 run_scenario 负责逐行解析。
一个完整示例(对应仓库 thinking.txt 风格):
face=thinking caption=Finding a good answer... progress=0.65 battery=72 usb=false wifi=connected ble=connected paired=true link=online advance=8004.2 无头渲染命令
无需显示服务器即可渲染,并把最终合成画面存为二进制 PPM 图像(P6 格式,见 write_snapshot):
./esp32/simulator/build/muse_simulator \ --headless \ --scenario esp32/simulator/tests/scenarios/thinking.txt \ --run-ms 250 \ --screenshot thinking.ppm命令行选项(解析见 main.c):
| 选项 | 说明 |
|---|---|
--headless | 设置SDL_VIDEODRIVER=dummy与SDL_AUDIODRIVER=dummy后运行,结束前渲染--run-ms时长 |
--scenario FILE | 按序应用场景设置;无显示时也可配合使用来初始化可见会话 |
--run-ms N | 总渲染毫秒数,范围 0..3600000,非法值退出码 2 |
--screenshot FILE.ppm | 渲染结束后捕获 SDL 渲染器像素写出 PPM |
-h/--help | 输出用法 |
4.3 场景键全集与取值范围
README 列出支持的键,结合 apply_setting 的解析逻辑可以补充精确的取值范围:
| 键 | 取值 / 范围 |
|---|---|
face | boot、idle、listening、thinking、speaking、error、off或happy(happy先切 idle 再触发 muse_state_make_happy) |
caption | 任意文本,经muse_state_set_caption写入 |
level | 0..1 浮点(非法值如nan会被拒) |
progress | 0..1 浮点 |
battery | -1..100 整数(-1 表示无电池/未知) |
battery_mv | 0..6000 整数 |
usb/charging/asleep | true\|false(parse_bool同时接受on/1、off/0) |
wifi | off、no_network、connecting、connected、failed或not_nearby(connected 时 SSID 置为 "Muse Simulator") |
ble | off、advertising或connected;另有passkey(0..999999)与paired(true/false) |
link | boot、unpaired、pairing、confirm、connecting、online、offline或error |
speaker | true/false |
brightness | 10..100 整数 |
advance | 0..3600000 毫秒,推进模拟时钟并渲染对应时长 |
错误处理:非法命令行选项与非法场景值都会返回非零退出状态,并在 stderr 中指明坏行,格式为文件:行号: unsupported or invalid setting: key=value(退出码 2)。仓库测试 test_simulator.py 正是用face=definitely-not-a-mode与level=nan两条坏场景断言了该行为。
仓库自带 5 个场景,分别覆盖错误态、待机、聆听、配对与思考(tests/scenarios/):error.txt、idle.txt、listening.txt、pairing.txt、thinking.txt。
五、自动化测试与 Sanitizer 构建
5.1 无头确定性测试
构建完成后运行:
ctest --test-dir esp32/simulator/build --output-on-failure测试由 tests/test_simulator.py 实现(CMake 以muse_simulator_headless注册,超时 60 秒),使用 SDL 的 dummy 视频驱动,具体验证:
- 校验命令行与场景错误处理(非法键值 → 退出码 2 + stderr 定位);
- 渲染每一个自带场景两次(
--run-ms 200+--screenshot),要求两次 framebuffer 逐字节一致(SHA256 相同),证明渲染是确定性的; - 要求不同场景渲染出的画面互不相同(颜色数 > 8、尺寸恒为 412x412 的 PPM 头校验);
- 追加一条
face=off后接listening场景的渲染,断言其画面与单独渲染 listening 一致——即“显示关机画面后不能锁死后续预览状态选择”,与 select_mode 的解锁逻辑对应。
5.2 ASan/UBSan 构建
cmake -S esp32/simulator -B esp32/simulator/build-asan -G Ninja \ -DCMAKE_BUILD_TYPE=Debug \ -DMUSE_SIM_SANITIZERS=ON cmake --build esp32/simulator/build-asan --parallel ctest --test-dir esp32/simulator/build-asan --output-on-failure开启后测试环境会注入ASAN_OPTIONS与UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1。平台差异:macOS 上 Apple Clang 的 ASan 运行时不支持泄漏检测,故detect_leaks=0;Linux 上启用detect_leaks=1(见 CMakeLists.txt)。
六、实现要点:为什么渲染是可重复的
模拟器“可复现截图”的能力来自三处设计,均能在源码中直接核对:
- 假时钟注入 LVGL。sim_platform.c 实现了一套可切换真实/虚构时间轴的
esp_timer_get_time()替身:sim_time_advance_us直接推进虚拟时钟;sim_board.c 在创建 SDL 窗口后调用lv_tick_set_cb(sim_time_tick_ms),替换 SDL 驱动默认安装的SDL_GetTicks——注释说明其目的正是“scripted runs can advance time without sleeping and render repeatably”。无头/截图模式下render_for以 5ms 步长推进假时钟并调用lv_timer_handler(),不真实睡眠(real_time=false)。 - 生产 UI 走生产全局变量。sim_board.c 定义生产全局
muse_board指向桌面板级配置(412x412、round=true、touch=true、frame_ms=40、1.45 英寸对角线),muse_ui.c无需任何修改即可读取它;power_off直接返回ESP_FAIL,set_brightness/panel_sleep为空实现,即桌面版不提供真实电源语义。 - 内存态服务替身。sim_services.h 声明了
sim_services_set_wifi/ble/paired/chat_status/link_state/brightness/speaker等函数,注释明确 setter 设计为在模拟器 LVGL/事件循环线程的下一个 tick 前运行——场景文件里的wifi=、ble=、link=等键最终都通过这些 setter 更新内存态,供生产 UI 读取显示。
截图路径同样简单透明:lv_refr_now强制刷新后,经lv_sdl_window_get_renderer拿到 SDL 渲染器,SDL_RenderReadPixels读出 RGB24 像素,写出P6头 PPM 文件(write_snapshot)。
七、延伸阅读与相关路径
- 模拟器文档主体:esp32/simulator/README.md
- 依赖版本与许可证:esp32/simulator/THIRD_PARTY.md(LVGL 9.5.0 MIT、SDL 2.32.10 zlib)
- 构建与依赖解析:esp32/simulator/CMakeLists.txt
- 模拟器配置:esp32/simulator/lv_conf.h
- 入口与场景解析:esp32/simulator/src/main.c
- 板级/显示/时钟替身:esp32/simulator/src/sim_board.c、esp32/simulator/src/sim_platform.c
- 服务替身接口:esp32/simulator/src/sim_services.h
- 测试与场景:esp32/simulator/tests/test_simulator.py、esp32/simulator/tests/scenarios/
适用前提与限制再次强调:该模拟器面向 Linux/macOS 桌面,用于 UI 迭代与截图回归;任何涉及摄像头、音频、蓝牙射频、内存与功耗的行为验证,仍须走esp32/下的固件构建并在真机完成。
【免费下载链接】muse-gadget-sdk
Open source SDK to build Muse gadgets
相关推荐
X-TRACK 在 Linux 下的 SDL2 桌面模拟:编译、运行与配置指南
X TRACK 在 Linux 下的 SDL2 桌面模拟:编译、运行与配置指南 X TRACK 是一款支持离线地图与轨迹记录的 GPS 自行车码表固件,其代码库
智能硬件嵌入式硬件开发如何编译 Go 并在 iOS 模拟器与真机上运行标准库测试?
如何编译 Go 并在 iOS 模拟器与真机上运行标准库测试? 如果你的任务是把 Go 源码树编译到 iOS 目标上,并验证标准库测试能在 iOS 模拟器或真机上
编程语言编译器语言运行时标准库并发编程抖音批量下载开源工具上手实测:四步跑通,素材归档不再靠手动
抖音批量下载开源工具上手实测:四步跑通,素材归档不再靠手动 你有没有过这种经历:收藏夹里攒了几百条抖音链接,想整理成自己的素材库,结果卡在"一条条复制、打开、保
网页爬虫CLI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考