杰理 SDK 文档中心
首页
首页
  • 项目概览与快速开始

    • 项目概述与芯片支持
    • 环境搭建与工具链
    • 工程与构建系统
    • 烧录与升级工具
    • 文档与硬件资料
  • 系统架构与芯片平台

    • 芯片平台与启动流程
    • 预编译库与头文件体系
    • 消息、定时器与中断服务
    • 通用外设驱动
  • 存储与文件系统

    • 文件系统实现
    • 存储设备驱动
    • VM 参数存储系统
  • 音频处理

    • 音频解码器
    • 音频编码器
    • MIDI 合成与播放
    • 音效、变速变调与降噪
  • 语音玩具应用

    • 应用框架与状态机
    • 音乐播放与外部音源
    • MIDI 乐器模式
    • 录音应用
    • 待机、电源管理与 USB 从机
  • 小音箱应用

    • 应用框架与模式管理
    • 播放源:音乐、FM、录音与 LineIn
  • 应用层与示例工程

    • 通用 MCU 应用
  • 固件更新与补丁

    • 固件升级机制
    • AD14N 主动降噪补丁

应用框架与状态机

本文档描述 voice-toy 应用(applications/voice-toy/framework)中的应用框架与状态机机制:框架如何组织事件循环、消息分发、状态管理与动作回调,以及这些机制如何支撑语音玩具类产品的交互逻辑。

⚠️ 源码可验证性说明:在撰写本文档时,通过工具检索(ListFiles/Grep/ReadFile)未能定位到 applications/voice-toy/framework 下的源码文件——当前仓库快照的根目录仅包含 README.md、README-en.md、LICENSE 与 jl_ad_chip.png,对 *.c/*.h 的搜索也未返回任何匹配。这通常意味着应用代码托管于 SDK 的子模块或独立仓库中。因此,本文档中除仓库根级文件外的一切内容均基于目录命名与嵌入式 SDK 通用惯例的合理推断,并明确标注「未能从源码验证」。任何具体 API 签名、函数名与代码示例均不在本页虚构,请以实际源码为准。

Purpose and Scope

本页聚焦于 voice-toy 应用侧框架层的两大职责:

  1. 应用框架(Application Framework):应用启动、事件循环、消息分发、定时任务与模块生命周期管理,为上层业务提供统一的运行环境。
  2. 状态机(State Machine):将语音玩具的运行行为(待机、播放、录音、配对、充电等)建模为有限状态集合与转移规则,使复杂交互逻辑可配置、可追踪、可测试。

本页不覆盖(属于兄弟页面/其他目录的职责):

  • 底层芯片驱动、BSP 与 OS 适配(如 SDK 的 sdk/、cpu/ 目录)——相关文档请参见对应驱动目录页。
  • 具体业务玩法与内容(如特定语音资源、按键语义)——属于上层业务应用页。
  • 量产配置、烧录与工具链——属于工具链/量产相关页面。

Overview

为什么需要应用框架与状态机

语音玩具类产品(如故事机、早教机、对话玩具)的固件具有以下特征:

  • 事件驱动:几乎所有行为都由外部事件触发——按键、串口命令、充电插拔、定时器到期、音频播完中断。
  • 状态依赖:同一事件在不同状态下含义不同。例如「播放键」在待机态是开始播放,在播放态可能是暂停,在充电态可能被忽略。
  • 资源受限:MCU 上 RAM/Flash 有限,不能使用重型 RTOS 或脚本引擎,框架必须轻量、低开销。
  • 可维护性:产品迭代频繁,需要把「状态-事件-动作」的映射从业务代码中剥离,形成可读的转移表。

因此,applications/voice-toy/framework 的设计意图(推断)是:提供一个轻量的、表驱动的、事件驱动的状态机框架,叠加在芯片 SDK 的事件系统之上,让业务开发者只关心「在某个状态下收到某个事件时做什么」。

关键概念

概念说明(推断,未能从源码验证)
事件(Event)外部输入的统一抽象:按键消息、系统消息、定时器消息、命令帧等
状态(State)一组稳定的运行阶段,如 IDLE/PLAYING/PAUSED/CHARGING
转移表(Transition Table)状态 × 事件 → (下一状态, 动作) 的映射,是状态机的核心数据
动作(Action)状态进入/退出/转移时执行的函数回调,如开始播放、关灯、发串口帧
事件循环(Event Loop)从消息队列取事件并驱动状态机运转的主循环

Architecture

下图是概念性架构示意:反映 voice-toy 框架层的预期分层与数据流,但各模块命名与连接关系未能从源码验证,仅作阅读与后续核对源码时的参考框架。

flowchart TD
    subgraph sg_App["应用层 applications/voice-toy"]
        Main["启动入口 main"]
        Biz["业务模块<br/>(玩法/内容)"]
    end

    subgraph sg_Framework["应用框架 framework"]
        EventLoop["事件循环 EventLoop"]
        Dispatcher["消息分发 Dispatcher"]
        SM["状态机 StateMachine"]
        Actions["动作回调 Actions"]
        Timer["定时器/任务管理"]
    end

    subgraph sg_SDK["芯片 SDK 层"]
        OS["OS / 中断 / 消息队列"]
        HW["硬件驱动<br/>(按键/音频/充电)"]
    end

    Main --> EventLoop
    HW -->|"事件/消息"| OS
    OS --> EventLoop
    EventLoop --> Dispatcher
    Dispatcher --> SM
    SM --> Actions
    Actions --> Biz
    Timer --> EventLoop
    Biz --> Actions

分层职责(推断):

  • SDK 层:提供消息队列、中断、定时器与硬件驱动;按键、充电、音频完成中断等被转换为消息投递到队列。
  • 框架层:EventLoop 持续消费队列中的事件;Dispatcher 根据事件类型路由到目标模块;StateMachine 依据当前状态查询转移表,决定是否转移并触发 Actions。
  • 应用层:业务模块注册动作回调,实现具体行为(播放哪段音频、显示什么灯光等)。

这种分层把「事件怎么来」(SDK)、「事件怎么分发」(框架)、「事件怎么响应」(业务)解耦,是嵌入式事件驱动框架的典型设计取舍:以固定的小开销换取可扩展性与可测试性。

框架核心机制(推断性描述)

以下小节描述框架应当具备的机制。因源码未在工具可见快照中出现,所有函数名、表结构与调用方式均为推断,请在核对实际源码后修正。

事件循环与消息分发

预期流程:应用启动时初始化各模块并创建消息队列;主循环(或主任务)阻塞等待队列,收到消息后调用分发器。分发器维护「消息类型 → 处理函数」的注册表,支持业务模块在初始化时注册自己的消息处理入口。

状态机模型

预期采用有限状态机(FSM),核心为一张转移表:

  • 表项:(当前状态, 事件) → (下一状态, 进入动作, 退出动作)
  • 转移动作顺序(惯例):先执行旧状态的退出动作(exit action),更新当前状态,再执行新状态的进入动作(entry action)。
  • 未匹配的事件:丢弃或记录日志,状态保持不变——这是防御性设计,避免未知事件破坏状态一致性。

与 SDK 消息的衔接

SDK 的消息(如 SYS_KEY_EVENT、充电插拔、音频播完)由 SDK 层投递;框架层负责将其映射为状态机可识别的事件,从而把「硬件事件命名空间」与「业务状态命名空间」隔离。

Core Flow — 事件驱动与状态转移

下图描述预期的事件流转时序(概念性,未能从源码验证)。实际调用链以源码为准。

sequenceDiagram
    participant HW as 硬件/按键驱动
    participant OS as SDK 消息队列
    participant EL as 事件循环 EventLoop
    participant DP as 分发器 Dispatcher
    participant SM as 状态机 StateMachine
    participant AC as 动作回调 Actions

    HW->>OS: 产生消息(如按键按下)
    OS->>EL: 投递消息
    EL->>EL: 从队列取出消息
    EL->>DP: 路由到目标模块
    DP->>SM: 转换为状态机事件
    SM->>SM: 查询转移表 (cur_state, event)
    alt 转移表匹配
        SM->>AC: 执行旧状态退出动作
        SM->>SM: 更新当前状态
        SM->>AC: 执行新状态进入动作
        AC-->>SM: 动作完成
        SM-->>DP: 转移完成
    else 未匹配事件
        SM-->>DP: 忽略/记录日志
    end
    DP-->>EL: 处理完成,继续取下一事件

状态转移示意

语音玩具常见状态集(概念性示意,状态命名与集合以实际产品源码为准):

stateDiagram-v2
    [*] --> IDLE
    IDLE --> PLAYING: 播放事件
    PLAYING --> PAUSED: 暂停事件
    PAUSED --> PLAYING: 恢复事件
    PLAYING --> IDLE: 停止/播完
    PAUSED --> IDLE: 停止
    IDLE --> CHARGING: 充电插入
    CHARGING --> IDLE: 充电拔出

设计意图(推断):状态集合刻意保持小而正交——每个状态代表一类互斥的稳定行为;转移只由事件触发,不在业务代码中直接「跳转」,从而保证任何时刻系统处于明确定义的状态,便于调试与异常恢复(如看门狗复位后回到 IDLE)。

Usage Examples

源码示例

No code example available.

在本次文档生成过程中,工具未能定位到 applications/voice-toy/framework 下的任何源码文件(ListFiles 对 applications/voice-toy/framework/**/*.c、**/*.h 及 applications/* 均返回空;Grep 在 **/*.c 中搜索 state_machine 亦无匹配)。仓库根目录仅包含:

  • README.md — 项目总览(中文)
  • README-en.md — 项目总览(英文)
  • LICENSE — 许可证

应用框架源码很可能托管于该 SDK 的子模块仓库或独立仓库中。请拉取对应子模块后,以实际源码补充状态机注册、事件投递与转移表定义等示例。

Configuration Options

未找到配置项。 由于框架源码未在工具可见快照中暴露,无法枚举配置文件(如 app_config.h、消息/状态注册表)中的选项及其默认值。核对源码时,建议优先查找:

推断配置点预期作用(推断)
消息队列长度事件循环可缓冲的消息数量,影响吞吐与内存占用
状态/事件枚举定义业务可用的状态集合与事件集合
转移表大小/数量状态机容量限制
日志开关状态转移调试日志的编译期开关

API Reference

未找到 API 定义。 遵循「不虚构 API」原则,此处不列出未经源码验证的函数签名。核对实际源码时,预期框架对外暴露以下类别接口(推断,请以源码为准):

  • 初始化/反初始化:注册各业务模块、创建消息队列、启动事件循环。
  • 事件投递:向框架投递异步事件(可能由中断/任务上下文调用)。
  • 状态机注册:注册状态、事件与转移表条目。
  • 状态查询/强制转移:供业务查询当前状态或在特殊场景(如故障恢复)下强制切换。

Failure Modes, Edge Cases & Concurrency

以下为状态机/事件驱动框架的通用工程风险清单(推断),用于核对源码时逐项确认框架是否处理了这些情况:

  1. 未处理事件:转移表中无 (状态, 事件) 匹配项。防御做法:丢弃并记录日志;避免默认转移掩盖配置错误。
  2. 重复进入/离开动作:状态更新与动作执行的顺序若实现不当,可能在重入(如中断中投递事件)时导致动作重复执行。需确认事件投递是否为原子操作、动作是否可重入。
  3. 中断上下文限制:硬件事件可能在中断中产生;若动作回调涉及阻塞操作(如 I2C/Flash 写),必须在任务上下文执行,框架需做上下文切换保护。
  4. 状态一致性:多任务并发投递事件时,状态机的「查询-更新」必须互斥(关中断或加锁),否则可能丢失转移。
  5. 异常恢复:看门狗复位或异常重启后,框架应从持久化(或默认)状态重新初始化,避免进入非法组合状态。
  6. 消息队列溢出:高频事件(如快速连按按键)可能填满队列;需定义溢出策略(丢弃新事件或丢弃旧事件)。

Performance & Operational Notes

  • 轻量优先(推断):嵌入式框架通常避免动态内存分配与重型调度,事件循环单线程化以降低竞争。
  • 热点路径:消息出队与状态转移查询是每事件必经路径,转移表宜用数组/查表实现而非链表,保证 O(1) 或 O(n) 小常数查找。
  • 可观测性:状态转移日志(进入/退出状态、事件、耗时)对现场问题定位至关重要,建议保留可编译开关的日志钩子。

Extension Points

框架的预期扩展方式(推断,待源码确认):

  • 新增状态/事件:扩展状态与事件枚举,并在转移表中登记条目——不改动框架核心。
  • 新增业务模块:遵循「注册-回调」模型,在初始化阶段向分发器注册消息处理入口与动作回调。
  • 自定义动作:动作回调是业务注入点;建议动作保持短小、非阻塞,长任务交给定时器或异步流程。

Related Links

  • README.md — 仓库总览(中文)
  • README-en.md — 仓库总览(英文)
  • LICENSE — 许可证

说明:本页为 applications/voice-toy/framework 的目录文档。由于源码未在当前工具可见快照中暴露,以上架构、流程与 API 描述均为基于目录命名与嵌入式 SDK 惯例的推断,并在各处以「未能从源码验证」明确标注。待源码(含子模块)可访问后,请以实际实现为准更新本文档,并补充真实代码示例。

Next
音乐播放与外部音源