706 lines
20 KiB
Markdown
706 lines
20 KiB
Markdown
# TQ Cat 固件整体架构与运行工作流
|
||
|
||
本文档基于 `feature/st7789p3-new-board` 分支的代码,面向项目接手、问题定位和后续重构。内容以实际函数调用关系为准。
|
||
|
||
## 1. 系统定位
|
||
|
||
项目运行在 ESP32-S3 上,主要负责:
|
||
|
||
- ST7789P3 LCD 表情播放;
|
||
- ES8311 音频采集与播放;
|
||
- Opus 编解码与 WebSocket 多模态对话;
|
||
- TTP223 PTT、SW1、SW2 按键处理;
|
||
- ULN2003 步进电机和转盘校准;
|
||
- Wi-Fi 连接、重连和配置热点;
|
||
- 设备身份、JWT 和会话令牌;
|
||
- 用户出生资料、每日运势和财富方向;
|
||
- NVS、LittleFS 和工厂 CLI。
|
||
|
||
## 2. 分层架构
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
Main["main / app_main"]
|
||
App["app_composition<br/>启动顺序与应用装配"]
|
||
CP["control_plane<br/>策略、状态机、任务、重试"]
|
||
Domain["domain<br/>方向、校准、运势、表情语义"]
|
||
Platform["platform<br/>GPIO、LCD、音频、网络、存储"]
|
||
HW["ESP32-S3 新板硬件"]
|
||
|
||
Main --> App --> CP --> Domain --> Platform --> HW
|
||
```
|
||
|
||
各层职责:
|
||
|
||
| 层 | 主要职责 | 典型内容 |
|
||
| --- | --- | --- |
|
||
| `main` | 固件入口 | 只调用 composition 入口 |
|
||
| `app_composition` | 决定启动顺序 | 存储、音频、LCD、校准、联网、workers |
|
||
| `control_plane` | 产品策略和生命周期 | Wi-Fi、PTT、多模态、任务、重试、异常恢复 |
|
||
| `domain` | 业务语义和状态 | 方向、角度、校准、运势、LCD 表情映射 |
|
||
| `platform` | 硬件与传输原语 | GPIO、I2S、I2C、SPI、WebSocket、NVS、HTTP |
|
||
|
||
## 3. 启动总流程
|
||
|
||
入口:
|
||
|
||
```text
|
||
app_main()
|
||
└── app_composition_start_default_runtime()
|
||
└── app_composition_run_plan_a_boot_sequence()
|
||
```
|
||
|
||
主要文件:
|
||
|
||
- `main/main.c`
|
||
- `components/app_composition/src/runtime/app_composition_default_runtime.c`
|
||
|
||
启动阶段:
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Entry["app_main"]
|
||
Storage["准备 NVS / 文件系统"]
|
||
Audio["初始化音频并播放开机音"]
|
||
LCD["初始化 LCD 和渲染任务"]
|
||
Core["初始化 platform / domain"]
|
||
Expression["请求默认 LCD 表情"]
|
||
Calibration["执行转盘原点校准"]
|
||
WiFi["连接 Wi-Fi 或启动配置 AP"]
|
||
Workers["启动运行时 workers"]
|
||
|
||
Entry --> Storage --> Audio --> LCD --> Core --> Expression --> Calibration --> WiFi --> Workers
|
||
```
|
||
|
||
### 3.1 存储初始化
|
||
|
||
```text
|
||
control_plane_prepare_runtime_storage()
|
||
└── domain_runtime_prepare_storage()
|
||
└── platform_prepare_storage()
|
||
├── nvs_flash_init()
|
||
├── 必要时 nvs_flash_erase()
|
||
├── 再次 nvs_flash_init()
|
||
└── platform_log_nvs_stats()
|
||
```
|
||
|
||
默认 NVS namespace 包括 `wifi`、`ota`、`auth`、`auth_key` 和 `fortune`。
|
||
|
||
### 3.2 音频与开机音
|
||
|
||
```text
|
||
control_plane_play_boot_sound(timeout)
|
||
├── domain_runtime_multimodal_audio_init()
|
||
│ └── platform_multimodal_audio_init()
|
||
│ └── multimodal_audio_init()
|
||
└── domain_runtime_behavior_play_prompt_file(path)
|
||
```
|
||
|
||
`multimodal_audio_init()` 的主要步骤:
|
||
|
||
```text
|
||
fill_codec_sample_info()
|
||
→ audio_init_heap_guard_passed()
|
||
→ init_opus_codec()
|
||
→ init_i2c_bus()
|
||
→ init_i2s_bus()
|
||
→ create_codec_path()
|
||
→ open_codec_device()
|
||
→ apply_codec_default_controls()
|
||
→ ensure_uplink_worker_tasks()
|
||
→ ensure_downstream_playback_task()
|
||
```
|
||
|
||
开机音失败只记录 warning,不会终止启动。
|
||
|
||
### 3.3 LCD 初始化
|
||
|
||
```text
|
||
control_plane_init_lcd_device()
|
||
└── domain_runtime_init_lcd_device()
|
||
└── platform_init_lcd_device()
|
||
└── lcd_direct_init_device()
|
||
├── lcd_direct_gpio_init()
|
||
└── lcd_direct_panel_init()
|
||
```
|
||
|
||
渲染任务:
|
||
|
||
```text
|
||
control_plane_start_lcd_render_worker()
|
||
└── control_plane_lcd_render_loop_task()
|
||
└── control_plane_start_lcd_render_loop()
|
||
└── domain_runtime_start_lcd_render_loop()
|
||
└── platform_start_lcd_render_loop()
|
||
└── lcd_direct_start_render_loop()
|
||
```
|
||
|
||
### 3.4 platform/domain 初始化
|
||
|
||
```text
|
||
control_plane_init()
|
||
├── domain_direction_default_axis_config()
|
||
├── domain_direction_default_calibration()
|
||
└── domain_init(axis_config, calibration)
|
||
├── domain_runtime_platform_init()
|
||
│ └── platform_init()
|
||
│ ├── platform_power_hold_init()
|
||
│ ├── platform_io_effects_init()
|
||
│ ├── platform_stepper_driver_init()
|
||
│ └── platform_stepper_driver_power_off()
|
||
├── 初始化方向状态
|
||
└── domain_calibration_store_set()
|
||
```
|
||
|
||
注意:启动日志将 power hold 描述为已提前拉起,但实际 `platform_power_hold_init()` 位于 `platform_init()` 中。新板应真机验证 GPIO9 拉高时机是否足够早。
|
||
|
||
## 4. 新板关键 GPIO
|
||
|
||
| 功能 | GPIO | 电气语义 |
|
||
| --- | ---: | --- |
|
||
| Power Hold | 9 | 高有效 |
|
||
| LCD CLK | 8 | SPI clock |
|
||
| LCD MOSI | 18 | SPI data |
|
||
| LCD CS | 15 | 低有效 |
|
||
| LCD DC | 16 | 数据/命令 |
|
||
| LCD RESET | 17 | 低有效 reset |
|
||
| LCD Backlight | 7 | 高有效 |
|
||
| TTP223 / PTT | 3 | 高有效,无内部上下拉 |
|
||
| SW1 校准开关 | 12 | 低有效,上拉 |
|
||
| SW2 功能开关 | 13 | 低有效,上拉 |
|
||
| Stepper IN1/2/3/4 | 45/48/47/21 | ULN2003 相线 |
|
||
| Audio PA | 11 | 功放使能 |
|
||
| ES8311 I2C SDA/SCL | 1/2 | codec 控制 |
|
||
| I2S MCLK/BCLK/DOUT/WS/DIN | 38/39/40/41/42 | 音频数据 |
|
||
|
||
## 5. 转盘校准与旋转
|
||
|
||
启动校准调用链:
|
||
|
||
```text
|
||
control_plane_calibrate()
|
||
└── control_plane_calibrate_with_timeout()
|
||
└── control_plane_direction_calibrate_internal()
|
||
└── domain_calibrate_with_timeout()
|
||
```
|
||
|
||
`domain_calibrate_with_timeout()`:
|
||
|
||
```text
|
||
锁定方向状态
|
||
→ prepare_calibration_switch()
|
||
→ 检查 SW1 是否已有效
|
||
→ 循环执行 calibration_rotate_and_track()
|
||
→ calibration_settle()
|
||
→ 再次读取 SW1
|
||
→ 触发后 calibration_return_from_limit()
|
||
→ domain_set_current_angle(home_angle)
|
||
→ domain_runtime_stepper_power_off()
|
||
```
|
||
|
||
底层旋转:
|
||
|
||
```text
|
||
domain_runtime_stepper_rotate_angle_with_accel_timeout()
|
||
└── platform_stepper_rotate_angle_with_accel_timeout()
|
||
└── platform_stepper_driver_rotate_angle_with_accel()
|
||
└── rotate_with_accel()
|
||
├── calculate_motion_segments()
|
||
├── stepper_advance_phase()
|
||
└── precise_delay_us()
|
||
```
|
||
|
||
绝对角度旋转:
|
||
|
||
```text
|
||
control_plane_rotate_to_angle()
|
||
└── domain_rotate_to_angle_with_timeout()
|
||
├── domain_angle_normalize()
|
||
├── domain_angle_shortest_rotation()
|
||
├── 执行电机旋转
|
||
└── 更新 s_current_angle
|
||
```
|
||
|
||
## 6. Wi-Fi 启动与恢复
|
||
|
||
启动入口:
|
||
|
||
```text
|
||
control_plane_bootstrap_connectivity(seed_ssid, seed_password, timeout, "TQ-CAT")
|
||
```
|
||
|
||
调用链:
|
||
|
||
```text
|
||
control_plane_register_wifi_behavior_hooks()
|
||
→ domain_runtime_wifi_portal_init_defaults()
|
||
→ wifi_portal_init_defaults()
|
||
→ 检查已保存凭据
|
||
→ control_plane_connect_sta_with_feedback()
|
||
→ 最多三次 STA 连接
|
||
→ 成功则播放提示音
|
||
→ 失败则按错误类型保留或清除凭据
|
||
→ 必要时启动 TQ-CAT 配置 AP
|
||
```
|
||
|
||
运行时由 `control_plane_wifi_state_task()` 负责:
|
||
|
||
- 检测 Wi-Fi 断开;
|
||
- 等待短暂 disconnect grace;
|
||
- 停止多模态 client 和用户配置 server;
|
||
- 请求断网表情;
|
||
- 按指数退避重连;
|
||
- 重连后恢复 idle 表情、WebSocket 和配置 server;
|
||
- 同时驱动 PTT 状态机。
|
||
|
||
## 7. 运行时任务拓扑
|
||
|
||
入口:
|
||
|
||
```text
|
||
control_plane_start_runtime_workers()
|
||
```
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
Start["control_plane_start_runtime_workers"]
|
||
Model["cp_model_cmd<br/>模型设备命令"]
|
||
WiFi["cp_wifi_state<br/>Wi-Fi、WS、PTT"]
|
||
LCD["cp_lcd_render<br/>LCD 启动"]
|
||
Events["cp_system_event<br/>事件分发"]
|
||
Keys["cp_key_input<br/>GPIO 与消抖"]
|
||
Fortune["cp_fortune<br/>每日运势"]
|
||
Monitor["cp_task_monitor<br/>可选诊断"]
|
||
|
||
Start --> Model
|
||
Start --> WiFi
|
||
Start --> LCD
|
||
Start --> Events
|
||
Start --> Keys
|
||
Start --> Fortune
|
||
Start --> Monitor
|
||
```
|
||
|
||
`control_plane_schedule_websocket_wait_task()` 当前只设置 `s_ws_start_requested = true`,实际 WebSocket 启动由 `cp_wifi_state` 执行。
|
||
|
||
## 8. 按键和系统事件
|
||
|
||
按键中断链路:
|
||
|
||
```text
|
||
GPIO edge
|
||
→ control_plane_key_gpio_isr_handler()
|
||
→ xQueueSendFromISR(s_gpio_irq_queue)
|
||
→ control_plane_key_input_task()
|
||
→ control_plane_process_key_timers()
|
||
→ control_plane_handle_debounced_transition()
|
||
→ control_plane_emit_key_event()
|
||
→ control_plane_post_system_event()
|
||
→ control_plane_system_event_task()
|
||
→ control_plane_dispatch_system_event()
|
||
→ control_plane_dispatch_key_event()
|
||
```
|
||
|
||
事件包括:
|
||
|
||
- `PRESSED`;
|
||
- `RELEASED`;
|
||
- `SHORT_PRESS`;
|
||
- `LONG_PRESS_START`;
|
||
- `LONG_PRESS_RELEASE`;
|
||
- `DOUBLE_CLICK`。
|
||
|
||
行为映射:
|
||
|
||
| 输入 | 行为 |
|
||
| --- | --- |
|
||
| PTT 短按 | `control_plane_set_ptt_active(true)` |
|
||
| PTT 在服务端回复时按下 | `control_plane_multimodal_send_request_to_speak()` |
|
||
| PTT 双击 | 请求 `DOMAIN_EXPRESSION_MUYU` |
|
||
| SW2 单击 | 请求 `DOMAIN_EXPRESSION_CHOUQIAN` |
|
||
| SW2 双击 | 请求 `DOMAIN_EXPRESSION_WUXING` |
|
||
|
||
## 9. PTT 状态机
|
||
|
||
状态:
|
||
|
||
```text
|
||
IDLE
|
||
WAIT_WIFI
|
||
WAIT_WS
|
||
WAIT_START_SENT
|
||
WAIT_LISTENING
|
||
WAIT_SPEECH_STARTED
|
||
STREAMING
|
||
TEARDOWN_LOCAL
|
||
TEARDOWN_REMOTE
|
||
DENIED
|
||
```
|
||
|
||
状态机由 `control_plane_drive_ptt_state_machine()` 在 `cp_wifi_state` 中周期驱动:
|
||
|
||
```text
|
||
无 Wi-Fi → WAIT_WIFI
|
||
无 WebSocket → WAIT_WS
|
||
无 active task → WAIT_START_SENT
|
||
服务端未 Listening → WAIT_LISTENING
|
||
未发送 SendSpeech → WAIT_SPEECH_STARTED
|
||
uplink 已运行 → STREAMING
|
||
释放/超时 → TEARDOWN_LOCAL → TEARDOWN_REMOTE → IDLE
|
||
```
|
||
|
||
每次推进调用 `control_plane_multimodal_handle_ptt_press_step()`,根据当前会话状态选择:
|
||
|
||
- `control_plane_multimodal_send_start()`;
|
||
- `control_plane_multimodal_send_request_to_speak()`;
|
||
- `control_plane_multimodal_send_speech_start()`;
|
||
- `control_plane_multimodal_start_uplink()`。
|
||
|
||
## 10. 设备认证和 WebSocket
|
||
|
||
启动链:
|
||
|
||
```text
|
||
cp_wifi_state
|
||
→ control_plane_try_start_multimodal_from_state_machine()
|
||
→ control_plane_start_multimodal_client()
|
||
→ control_plane_multimodal_start()
|
||
```
|
||
|
||
`control_plane_start_multimodal_client()`:
|
||
|
||
```text
|
||
control_plane_prepare_for_multimodal_start()
|
||
→ 注册 event callback
|
||
→ 注册 downstream audio callback
|
||
→ 创建 mm_watchdog
|
||
→ control_plane_multimodal_start()
|
||
```
|
||
|
||
认证链:
|
||
|
||
```text
|
||
control_plane_multimodal_auth_fetch()
|
||
├── resolve_device_identity()
|
||
├── control_plane_multimodal_device_auth_ensure()
|
||
│ ├── control_plane_multimodal_device_auth_init()
|
||
│ ├── 检查已有 JWT 和 scope
|
||
│ └── refresh_jwt_internal()
|
||
├── control_plane_multimodal_device_auth_copy_jwt()
|
||
├── HTTP POST token endpoint
|
||
├── 401/403 时 invalidate JWT 并重试
|
||
└── parse_token_response()
|
||
```
|
||
|
||
WebSocket 链:
|
||
|
||
```text
|
||
domain_runtime_multimodal_transport_start()
|
||
└── platform_multimodal_transport_start()
|
||
└── multimodal_ws_start()
|
||
├── 停止旧 client
|
||
├── 构造 Authorization 和 Workspace headers
|
||
├── 创建 send mutex
|
||
├── create_worker_pipeline()
|
||
└── start_websocket_client_with_fallback()
|
||
```
|
||
|
||
## 11. 一次完整语音会话
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant User as 用户/PTT
|
||
participant CP as Control Plane
|
||
participant Session as Session Service
|
||
participant Audio as Audio Pipeline
|
||
participant WS as WebSocket
|
||
participant Server as 服务端
|
||
|
||
User->>CP: 短按
|
||
CP->>Session: send_start()
|
||
Session->>WS: run-task / Start
|
||
Server-->>Session: DialogStateChanged(Listening)
|
||
CP->>Session: send_speech_start()
|
||
CP->>Audio: start_uplink()
|
||
Audio->>WS: Opus binary frames
|
||
Server-->>Session: SpeechEnded / RespondingStarted
|
||
Session->>Audio: stop uplink / begin response
|
||
Server-->>Audio: Opus binary frames
|
||
Audio-->>User: 扬声器播放
|
||
Server-->>Session: RespondingEnded
|
||
Audio-->>Session: playback completed
|
||
Session->>WS: LocalRespondingEnded
|
||
```
|
||
|
||
### 11.1 Start
|
||
|
||
```text
|
||
control_plane_multimodal_send_start()
|
||
→ 生成 task UUID
|
||
→ 构造 run-task / Start JSON
|
||
→ 设置 upstream/downstream Opus 参数
|
||
→ domain_runtime_multimodal_transport_send_text()
|
||
→ 保存 s_task_id
|
||
```
|
||
|
||
### 11.2 开始采集和上行
|
||
|
||
```text
|
||
control_plane_multimodal_send_speech_start()
|
||
→ send_directive("continue-task", "SendSpeech")
|
||
→ control_plane_multimodal_start_uplink()
|
||
→ domain_runtime_multimodal_audio_start_uplink()
|
||
→ multimodal_audio_start_uplink()
|
||
```
|
||
|
||
实时音频:
|
||
|
||
```text
|
||
I2S capture task
|
||
→ PCM 整理
|
||
→ Opus encode
|
||
→ uplink send queue
|
||
→ uplink_send_task
|
||
→ control_plane_audio_uplink_send_cb()
|
||
→ control_plane_multimodal_send_audio_realtime()
|
||
→ multimodal_ws_send_binary_realtime()
|
||
```
|
||
|
||
### 11.3 下行播放
|
||
|
||
```text
|
||
WebSocket binary frame
|
||
→ transport_event_bridge()
|
||
→ control_plane_downstream_audio_bridge()
|
||
→ control_plane_multimodal_play_downstream_audio()
|
||
→ multimodal_audio_handle_downstream_opus()
|
||
→ downstream playback queue
|
||
→ Opus decode
|
||
→ I2S / ES8311 播放
|
||
```
|
||
|
||
服务端 `RespondingEnded` 和本地播放完成都满足后,才发送 `LocalRespondingEnded`。
|
||
|
||
## 12. 服务端事件解析
|
||
|
||
所有文本帧进入 `process_text_json()`,主要处理:
|
||
|
||
- `task-failed`;
|
||
- `task-started`;
|
||
- `DialogStateChanged`;
|
||
- `RequestAccepted`;
|
||
- `RespondingStarted`;
|
||
- `RespondingContent`;
|
||
- `RespondingEnded`;
|
||
- `SpeechStarted`;
|
||
- `SpeechContent`;
|
||
- `SpeechEnded`;
|
||
- `Stopped`;
|
||
- `Error`。
|
||
|
||
回复文本还会进入:
|
||
|
||
```text
|
||
notify_responding_text()
|
||
→ control_plane_responding_text_bridge()
|
||
→ control_plane_extract_model_command()
|
||
→ control_plane_on_model_command()
|
||
→ model command queue
|
||
→ control_plane_model_command_task()
|
||
```
|
||
|
||
设备命令包括方向、校准动作和抽签。
|
||
|
||
## 13. LCD 表情工作流
|
||
|
||
```text
|
||
domain_runtime_request_expression()
|
||
├── domain_resolve_expression_platform_request()
|
||
└── platform_lcd_request_presentation()
|
||
└── lcd_direct_request_presentation()
|
||
```
|
||
|
||
domain 负责把业务语义映射成 platform 播放请求:
|
||
|
||
```text
|
||
IDLE
|
||
SERVER_ERROR
|
||
WIFI_DISCONNECTED
|
||
WEALTH_SPIN
|
||
WEALTH_DIRECTION
|
||
MUYU
|
||
CHOUQIAN
|
||
WUXING
|
||
```
|
||
|
||
platform 只处理:
|
||
|
||
- asset directory;
|
||
- frame index;
|
||
- frame interval;
|
||
- priority;
|
||
- interrupt policy;
|
||
- repeat count;
|
||
- return-to-idle。
|
||
|
||
渲染循环:
|
||
|
||
```text
|
||
lcd_direct_take_pending()
|
||
→ lcd_direct_play_asset_sequence() 或 lcd_direct_play_step_sequence()
|
||
→ lcd_direct_signal_completion()
|
||
→ 无 pending 时播放 basic idle face
|
||
```
|
||
|
||
## 14. 财富方向与运势
|
||
|
||
财富方向动作:
|
||
|
||
```text
|
||
control_plane_apply_wealth_direction()
|
||
├── domain_runtime_preheat_expression(reveal)
|
||
├── 阻塞播放 WEALTH_SPIN
|
||
├── 请求 WEALTH_DIRECTION reveal
|
||
├── 记录 start_angle
|
||
├── 旋转固定角度
|
||
├── 延时
|
||
└── 返回 start_angle
|
||
```
|
||
|
||
当前 `direction_index` 主要选择 LCD 方向资源,电机仍执行固定角度转出再返回,并非直接旋转到方向目录的绝对角度。
|
||
|
||
每日运势 worker:
|
||
|
||
```text
|
||
control_plane_daily_fortune_task()
|
||
├── 等待 birth profile
|
||
├── 等待 Wi-Fi
|
||
├── control_plane_wait_for_synced_time()
|
||
├── 等待 WebSocket TLS 握手稳定
|
||
├── 计算本地日期
|
||
├── control_plane_fortune_fetch()
|
||
├── domain_fortune_result_store_set()
|
||
└── control_plane_apply_wealth_direction()
|
||
```
|
||
|
||
运势 HTTPS 与 WebSocket TLS 握手被有意串行化,以避免内部 DMA RAM 不足。
|
||
|
||
## 15. 局域网用户配置
|
||
|
||
联网后 `control_plane_wifi_state_task()` 启动用户配置 server:
|
||
|
||
```text
|
||
control_plane_ensure_user_config_server()
|
||
└── domain_user_config_server_start()
|
||
└── platform_lan_http_server_start()
|
||
```
|
||
|
||
路由:
|
||
|
||
| 方法 | 路径 | 处理函数 |
|
||
| --- | --- | --- |
|
||
| GET | `/` | `handle_index()` |
|
||
| GET | `/api/profile` | `handle_get_profile()` |
|
||
| POST | `/api/profile` | `handle_post_profile()` |
|
||
| GET | `/api/fortune` | `handle_get_fortune()` |
|
||
|
||
资料更新后:
|
||
|
||
```text
|
||
domain_birth_profile_store_set()
|
||
→ birth profile observer
|
||
→ control_plane_request_fortune_refresh()
|
||
→ 唤醒 cp_fortune
|
||
```
|
||
|
||
## 16. Watchdog 和异常恢复
|
||
|
||
`multimodal_watchdog_task()` 每秒检查:
|
||
|
||
- WebSocket 是否连接;
|
||
- 是否存在 active task;
|
||
- heartbeat 是否到期;
|
||
- 是否长时间没有下行;
|
||
- transport 是否空闲超过 30 秒。
|
||
|
||
处理:
|
||
|
||
```text
|
||
heartbeat 到期
|
||
→ control_plane_multimodal_send_heartbeat()
|
||
|
||
无下行超时
|
||
→ control_plane_multimodal_send_stop("NoResponseTimeout")
|
||
→ stop uplink
|
||
|
||
transport 空闲 30 秒
|
||
→ control_plane_multimodal_stop()
|
||
```
|
||
|
||
WebSocket 断开或错误时,会停止 uplink,并由 `cp_wifi_state` 安排后续重连。
|
||
|
||
## 17. 停止流程
|
||
|
||
```text
|
||
control_plane_stop_runtime_workers()
|
||
├── 设置 runtime stop flag
|
||
├── 停止用户配置 server
|
||
├── 注销模型命令和 profile observer
|
||
├── 停止 key task 和 system event task
|
||
├── 停止 LCD render loop
|
||
├── bounded wait 各 worker
|
||
├── 必要时强制删除 task
|
||
├── 删除 model command queue
|
||
└── control_plane_stop_multimodal_client()
|
||
├── stop_watchdog_task()
|
||
└── control_plane_multimodal_stop()
|
||
├── stop uplink
|
||
├── 停止本地 responding worker
|
||
├── 注销 callbacks
|
||
├── transport_stop(2000)
|
||
└── reset_session_state_locked()
|
||
```
|
||
|
||
## 18. 调试索引
|
||
|
||
遇到问题时先判断属于哪个状态机:
|
||
|
||
1. `control_plane_wifi_state_task()`:Wi-Fi、WebSocket 启动、PTT;
|
||
2. multimodal session:task、Listening、Speech、Responding;
|
||
3. audio pipeline:capture、send queue、decode、playback。
|
||
|
||
推荐排查路径:
|
||
|
||
| 现象 | 优先检查 |
|
||
| --- | --- |
|
||
| 上电后掉电 | GPIO9、`platform_power_hold_init()` 调用时机 |
|
||
| LCD 无显示 | GPIO、`lcd_direct_init_device()`、背光和 SPI |
|
||
| 电机不动 | `platform_stepper_driver_init()`、相序、限位状态 |
|
||
| 开机校准超时 | GPIO12、有效电平、最大 sweep、旋转方向 |
|
||
| PTT 无反应 | ISR queue、消抖、system event、PTT state |
|
||
| 有按键但没录音 | Listening、SendSpeech、audio init、uplink task |
|
||
| 有录音但服务端收不到 | Opus queue、uplink callback、WS binary send |
|
||
| 服务端回复但没声音 | binary callback、decode queue、I2S、PA GPIO11 |
|
||
| 第二轮对话失败 | `s_task_id`、Listening、speech flags、playback completion |
|
||
| 断网不恢复 | `cp_wifi_state`、saved credentials、backoff、WS start request |
|
||
|
||
## 19. 关键源码入口
|
||
|
||
- `main/main.c`
|
||
- `components/app_composition/src/runtime/app_composition_default_runtime.c`
|
||
- `components/control_plane/src/runtime/control_plane_runtime_workers.c`
|
||
- `components/control_plane/src/runtime/control_plane_connectivity_runtime.c`
|
||
- `components/control_plane/src/runtime/control_plane_key_input.c`
|
||
- `components/control_plane/src/runtime/control_plane_system_events.c`
|
||
- `components/control_plane/src/multimodal/control_plane_multimodal_runtime.c`
|
||
- `components/control_plane/src/multimodal/control_plane_multimodal_session_service.c`
|
||
- `components/control_plane/src/multimodal/control_plane_multimodal_auth_service.c`
|
||
- `components/control_plane/src/multimodal/control_plane_multimodal_device_auth.c`
|
||
- `components/domain/src/direction/domain_direction_service.c`
|
||
- `components/domain/src/calibration/domain_calibration_service.c`
|
||
- `components/domain/src/runtime/domain_runtime_adapters.c`
|
||
- `components/platform/src/multimodal/audio_pipeline/audio_pipeline_runtime_impl.c`
|
||
- `components/platform/src/multimodal/transport_ws/transport_ws_runtime_impl.c`
|
||
- `components/platform/src/lcd_direct.c`
|
||
- `components/platform/src/platform_stepper_driver.c`
|