杰理 SDK 文档中心
首页
首页
  • 项目概览

    • 项目概述与能力地图
    • 构建系统与编译流程
    • 芯片系列与规格
  • 应用示例

    • SPP 与 BLE 双模透传
    • AT 指令串口协议
    • HID 设备应用
    • 蓝牙 Mesh 应用
    • 公共组件与第三方协议
  • 芯片平台支持

    • 外设驱动
    • 电源与充电管理
    • 启动与链接脚本
    • 配置工具与 OTA 资源
  • 协议栈与系统库

    • 蓝牙控制器
    • BTStack 协议栈接口
    • 系统内核与服务
    • OTA 升级机制
  • 文档与参考

    • 蓝牙 AT 协议参考
    • 开发文档与认证信息

系统内核与服务

本文档介绍杰理 AC630N 蓝牙 SoC SDK 中 include_lib/system 层提供的系统内核与服务能力:实时操作系统(RTOS)抽象层、任务管理、任务队列(消息/事件传递)、信号量、互斥锁与消息队列等同步原语,以及它们在蓝牙协议栈应用中的典型用法。

Purpose and Scope

本页面覆盖 系统内核与服务 这一完整能力面,包括:

  • OS 抽象层设计(uC/OS 与 FreeRTOS 双内核可裁剪切换)
  • 任务(Task)的创建、删除、延时与自查询
  • 任务队列(Task Queue)机制:消息(Q_MSG)、事件(Q_EVENT)、回调(Q_CALLBACK)、用户消息(Q_USER)四种投递类型
  • 同步原语:信号量(OS_SEM)、互斥锁(OS_MUTEX)、消息队列(OS_QUEUE)
  • 系统节拍(tick)与时间服务(OS_TICKS_PER_SEC = 100)

以下内容属于其他目录页,不在本页展开:蓝牙协议栈各 Profile(SPP/LE/HOGP/Mesh)实现、按键/外设驱动、低功耗电源管理。本 SDK 的内核实现以预编译库形式发布,include_lib/system 下的头文件是应用与内核之间的正式契约(API 表面),本文所有 API 签名均提取自该契约头文件。

Overview

AC630N 系列芯片(AC6311A/AC6313A/AC6318A/AC6319A)是 32bit@120MHz 的蓝牙音频/透传 SoC,SDK 在协议栈之下内置了一个可裁剪的 RTOS 内核。SDK 通过 CONFIG_UCOS_ENABLE 或 CONFIG_FREE_RTOS_ENABLE 两个编译宏选择底层内核实现,而对应用层暴露统一的 API 表面(os_* 前缀函数),使得上层蓝牙协议栈、应用框架无需关心内核差异。

系统服务层位于应用与内核之间,承担三类核心职责:

  1. 调度与生命周期:os_task_create 创建任务、os_task_del_req/res/del 协作式删除、os_time_dly 时间片延时;
  2. 任务间通信(IPC):os_taskq_post/pend 系列是 SDK 中最核心的通信原语——所有蓝牙事件(连接、断开、配对、数据到达)都通过任务队列投递到对应任务的处理循环;
  3. 资源互斥:os_sem_*(计数信号量)与 os_mutex_*(互斥锁)保护共享资源,os_q_* 提供原始消息队列。

理解这套服务层是阅读 SDK 应用代码(如 apps/common/third_party_profile/jieli/ 下的协议栈示例)的前提:几乎所有上层模块都以 os_taskq_post_msg/os_taskq_post_event 驱动。

Architecture

下图展示了系统内核与服务在 SDK 中的分层位置及与周边组件的关系:

flowchart TD
    subgraph sg_App["应用层 apps/"]
        App["蓝牙应用/协议栈示例<br/>(SPP/LE/HOGP/Mesh)"]
        Dev["外设驱动<br/>(按键/传感器/Codec)"]
    end

    subgraph sg_Svc["系统服务层 include_lib/system"]
        TaskMgr["任务管理<br/>os_task_create / os_task_del"]
        TaskQ["任务队列<br/>os_taskq_post / pend / accept"]
        Sync["同步原语<br/>os_sem_* / os_mutex_* / os_q_*"]
        Tick["节拍服务<br/>os_time_dly / os_init_tick"]
    end

    subgraph sg_Kernel["RTOS 内核(预编译库)"]
        UCOS["uC/OS<br/>CONFIG_UCOS_ENABLE"]
        FREERTOS["FreeRTOS<br/>CONFIG_FREE_RTOS_ENABLE"]
    end

    subgraph sg_HW["硬件层"]
        CPU["AC630N SoC<br/>32bit@120MHz"]
        BLE["蓝牙射频/基带"]
    end

    App -->|"os_taskq_post_msg / post_event"| TaskQ
    Dev -->|"os_sem_post / os_mutex_pend"| Sync
    TaskMgr --> UCOS
    TaskMgr --> FREERTOS
    TaskQ --> UCOS
    TaskQ --> FREERTOS
    Sync --> UCOS
    Sync --> FREERTOS
    Tick --> UCOS
    Tick --> FREERTOS
    UCOS --> CPU
    FREERTOS --> CPU
    CPU --> BLE

架构要点:

  • 统一 API 表面:os_api.h 中所有 os_* 函数不区分底层内核,os_type.h 通过宏切换类型定义(uC/OS 的自定义结构体 vs FreeRTOS 的 StaticSemaphore_t/StaticQueue_t),应用层源码零改动即可换核。
  • 任务队列是协议栈的中枢:蓝牙协议栈的事件循环普遍采用"一个任务一个队列、os_taskq_pend 阻塞等待、按消息类型分发"的模式,os_taskq_post_event 是跨任务投递蓝牙事件的统一通道。
  • 内核为预编译库:实际调度算法、优先级管理、上下文切换在闭源库中实现,头文件即契约;因此本页以 API 语义 + 应用侧调用方式为主线。

内核抽象层:双 RTOS 设计

os_type.h 是内核抽象的根基。它先用 OS_TICKS_PER_SEC 定义系统节拍,再按编译宏选择内核类型:

#define OS_TICKS_PER_SEC          100

#if defined CONFIG_UCOS_ENABLE

#define  OS_EVENT_TYPE_UNUSED         0u
#define  OS_EVENT_TYPE_Q              1u
#define  OS_EVENT_TYPE_SEM            2u
#define  OS_EVENT_TYPE_MUTEX          3u

typedef struct {
    unsigned char OSEventType;
    int aa;
    void *bb;
    unsigned char value;
    unsigned char prio;
    unsigned short cc;
} OS_SEM, OS_MUTEX, OS_QUEUE;

#elif defined CONFIG_FREE_RTOS_ENABLE

#include "FreeRTOS/FreeRTOS.h"
#include "FreeRTOS/semphr.h"

typedef StaticSemaphore_t OS_SEM, OS_MUTEX;
typedef StaticQueue_t OS_QUEUE;

#else
#error "no_os_defined"
#endif

来源:os_type.h

设计意图:

  • 节拍 100Hz:OS_TICKS_PER_SEC = 100 意味着 1 个 tick = 10ms。所有 os_*_pend 的超时参数、os_time_dly 的延时参数均以 tick 为单位,调用时需按此换算(例如 500ms 超时 = 50 ticks)。
  • 类型三合一(uC/OS 模式):uC/OS 分支中 OS_SEM、OS_MUTEX、OS_QUEUE 是同一个结构体,仅靠 OSEventType 字段区分类型,这是 uC/OS-II 经典的事件控制块(ECB)设计;FreeRTOS 分支则映射到各自的静态类型(StaticSemaphore_t/StaticQueue_t),静态分配避免动态堆依赖,适合资源受限的蓝牙 SoC。
  • 强制二选一:两个宏都不定义时直接 #error "no_os_defined",把配置错误提前到编译期暴露,防止运行时因内核符号缺失产生难排查的链接错误。

任务管理服务

任务管理 API 全部声明在 os_api.h,是系统服务层最基础的能力:

void os_init();                        // 内核初始化(BR25 芯片返回 void*)
void os_start(void);                   // 启动内核调度
void os_init_tick(int);                // 初始化系统节拍

int os_task_create(void (*task)(void *p_arg),
                   void *p_arg,
                   u8 prio,
                   u32 stksize,
                   int qsize,
                   const char *name);

const char *os_current_task();         // 获取当前任务名
void os_task_exit();                   // 当前任务退出
int os_task_del_req(const char *name); // 请求删除任务
int os_task_del_res(const char *name); // 响应删除请求
int os_task_del(const char *name);     // 直接删除任务

void os_time_dly(int time_tick);       // 按 tick 延时

来源:os_api.h

关键语义:

  • os_task_create 的第 4 个参数 qsize 是任务消息队列深度——任务创建时即预分配一条专属消息队列,这是后续 os_taskq_post* 能定向投递到该任务的前提。任务入口函数原型固定为 void (*task)(void *p_arg)。
  • 任务删除采用协作式(del_req/del_res 成对出现):任务 A 调用 os_task_del_req("taskB") 发出删除请求,任务 B 在自己的循环里调用 os_task_del_res 响应后才真正退出。这是嵌入式 RTOS 避免"删除正在使用共享资源的任务"导致死锁/资源泄漏的经典做法。
  • OS_TASK_SELF / OS_TASK_FATHER 两个特殊句柄((char *)0x1 / (char *)0x2)允许任务在不知道对方名字的情况下引用自身或父任务,相关删除宏状态定义在 os_api.h。

任务生命周期:

stateDiagram-v2
    [*] --> Ready: os_task_create
    Ready --> Running: 内核调度
    Running --> Ready: 时间片耗尽/被抢占
    Running --> Blocked: os_taskq_pend / os_sem_pend / os_mutex_pend
    Blocked --> Ready: 消息到达 / 信号量post / 超时
    Running --> Ready: os_time_dly 到期
    Running --> [*]: os_task_exit / os_task_del_res

任务队列:SDK 的核心 IPC 机制

任务队列(Task Queue)是系统服务层最核心的通信原语,蓝牙协议栈的所有事件分发都建立在它之上。os_api.h 定义了四种队列消息类型与全套投递/接收 API:

#define Q_MSG           0x100000
#define Q_EVENT         0x200000
#define Q_CALLBACK      0x300000
#define Q_USER          0x400000

int __os_taskq_post(const char *name, int type, int argc, int *argv);
int __os_taskq_pend(int *argv, int argc, int tick);

int os_taskq_accept(int, int *);                 // 非阻塞接收
int os_taskq_pend(const char *fmt, int *argv, int argc);  // 阻塞接收
int os_task_pend(const char *fmt, int *argv, int argc);   // 任务级接收
int os_taskq_post(const char *name, int argc, ...);       // 变参投递
int os_taskq_del(const char *name, int type);            // 按类型删除
int os_taskq_post_type(const char *name, int type, int argc, int *argv);
int task_queue_post_event(const char *name, void *data, int len);
int os_taskq_post_msg(const char *name, int argc, ...);
int os_taskq_post_event(const char *name, int argc, ...);
int os_taskq_del_type(const char *name, int type);
int os_taskq_flush();

来源:os_api.h、os_api.h

四种消息类型的语义:

类型宏值用途
Q_MSG0x100000普通消息,如协议栈内部状态机迁移、数据指示
Q_EVENT0x200000异步事件,如蓝牙连接/断开/配对完成通知
Q_CALLBACK0x300000回调执行请求,跨任务触发某个函数
Q_USER0x400000用户自定义消息,扩展协议栈私有命令

类型值的高位作为"消息类别"标识,低位(通过 os_taskq_post_type 的 type 参数或 os_taskq_post_msg 的变参首参)携带具体消息号。消息号常量(如 OS_MSG_KEY=1、OS_MSG_TOUCH=2、OS_MSG_EVENT=3、OS_MSG_CALLBACK=4、OS_MSG_DEL_REQ=5、OS_MSG_MSG=6)定义于 os_api.h,SDK 用它们区分任务循环内要处理的不同消息来源。

投递与接收的完整流程:

sequenceDiagram
    participant Sender as 发送任务(如协议栈)
    participant Kernel as 内核任务队列
    participant Receiver as 接收任务(如应用主任务)
    Sender->>Kernel: os_taskq_post("app_task", argc, args...)
    activate Kernel
    Kernel->>Kernel: 按任务名查队列,Q_MSG/Q_EVENT 分类入队
    Kernel-->>Receiver: 唤醒阻塞中的接收任务
    deactivate Kernel
    Receiver->>Receiver: os_taskq_pend(fmt, argv, argc) 返回
    Receiver->>Receiver: 按消息号分发处理(switch-case)
    Receiver-->>Sender: 处理完成(可选回包)

设计意图与关键细节:

  • 生产者-消费者解耦:发送方 os_taskq_post_msg 只负责入队并唤醒目标任务,不阻塞、不等待处理结果,天然适合中断上下文(如蓝牙 RF 中断 → 协议栈任务)与多任务异步事件上报。
  • 阻塞 vs 非阻塞接收:os_taskq_pend 在没有消息时让出 CPU(任务进入 Blocked 状态),os_taskq_accept 则立即返回,适合轮询式模块;__os_taskq_pend(argv, argc, tick) 支持超时参数,避免任务因消息缺失永久挂起。
  • 按任务名寻址:投递函数第一参数是任务名字符串,内核根据 os_task_create 时登记的名字定位目标队列——这也是任务名必须全局唯一的原因。
  • flush 清理:os_taskq_flush 清空队列,常用于任务退出前或系统休眠前丢弃积压消息,防止陈旧事件在唤醒后被误处理。

同步原语:信号量、互斥锁与消息队列

计数信号量(OS_SEM)

int os_sem_create(OS_SEM *, int);       // 创建,初始计数值
int os_sem_accept(OS_SEM *);            // 非阻塞获取
int os_sem_pend(OS_SEM *, int timeout); // 阻塞获取(tick 超时)
int os_sem_post(OS_SEM *);              // 释放
int os_sem_del(OS_SEM *, int block);    // 删除(OS_DEL_NO_PEND=0 / OS_DEL_ALWAYS=1)
int os_sem_set(OS_SEM *, u16 cnt);      // 重置计数值
int os_sem_valid(OS_SEM *);             // 有效性检查
int os_sem_query(OS_SEM *);             // 查询计数值

来源:os_api.h

信号量适合"事件计数"场景:中断/低层服务通过 os_sem_post 通知高层任务,高层 os_sem_pend 等待。os_sem_set 用于异常恢复时重置计数,os_sem_del 的 block 参数选择删除时是否等待持有者释放。

互斥锁(OS_MUTEX)

int os_mutex_create(OS_MUTEX *);
int os_mutex_accept(OS_MUTEX *);
int os_mutex_pend(OS_MUTEX *, int timeout);
int os_mutex_post(OS_MUTEX *);
int os_mutex_del(OS_MUTEX *, int block);
int os_mutex_valid(OS_MUTEX *);

来源:os_api.h

互斥锁保护独占资源(如 Flash 擦写、编解码器、RF 寄存器配置)。与信号量不同,互斥锁具备所有权语义与优先级继承(uC/OS 内核实现),可缓解优先级反转问题——这正是蓝牙协议栈中高优先级 RF 任务与低优先级应用任务共享外设时的关键保障。

消息队列(OS_QUEUE)

int os_q_create(OS_QUEUE *pevent, QS size);
int os_q_del(OS_QUEUE *pevent, u8 opt);
int os_q_flush(OS_QUEUE *pevent);
int os_q_pend(OS_QUEUE *pevent, int timeout, void *msg);
int os_q_post(OS_QUEUE *pevent, void *msg);
int os_q_query(OS_QUEUE *pevent);
int os_q_valid(OS_QUEUE *pevent);

来源:os_api.h

os_q_* 是面向任意数据指针的原始队列:os_q_post 投递指针、os_q_pend 阻塞接收。与任务队列的区别在于:任务队列按任务名定向投递并预置在任务内部,而 os_q_* 由调用方显式创建、独立于任务生命周期,适合在多个任务间共享一条数据管道(如音频数据帧缓冲、AT 命令流)。

同步原语选型速查:

场景推荐原语理由
事件通知(计数)os_sem_post/pend不携带数据,仅通知"有事发生"
独占资源保护os_mutex_pend/post所有权 + 优先级继承,防优先级反转
跨任务数据传递os_taskq_post_msg/event定向投递、带消息号、与任务绑定
多任务共享数据管道os_q_post/pend显式创建、指针传递、生命周期独立

Usage Examples

以下示例均基于 include_lib/system 头文件中的真实 API 契约,展示系统服务层的典型调用方式。

示例 1:创建任务并投递事件

任务创建时指定优先级、栈大小与队列深度;创建后其他任务即可用 os_taskq_post_event 向它投递事件:

#include "os/os_api.h"

/* 任务入口:阻塞等待事件,按消息号分发 */
static void app_main_task(void *p_arg)
{
    int msg[4];
    while (1) {
        /* 阻塞接收,消息写入 msg 数组 */
        os_taskq_pend(NULL, msg, 4);          /* fmt 为 NULL 时按原始参数接收 */
        switch (msg[0]) {
        case OS_MSG_EVENT:                    /* 蓝牙事件 */
            /* 处理连接/断开/数据事件 */
            break;
        case OS_MSG_MSG:                      /* 普通消息 */
            break;
        default:
            break;
        }
    }
}

/* 系统初始化:创建任务(prio=5,栈 1KB,队列深度 8) */
void sys_init(void)
{
    os_task_create(app_main_task, NULL, 5, 1024, 8, "app_task");
}

/* 任意上下文向 app_task 投递事件(Q_EVENT 类型) */
void notify_bt_connected(void)
{
    os_taskq_post_event("app_task", 2, OS_MSG_EVENT, 1 /* connect */);
}

来源:os_api.h、os_api.h

说明:os_taskq_post_event("app_task", 2, OS_MSG_EVENT, 1) 中 2 是参数个数(消息号 + 数据),OS_MSG_EVENT 是消息号常量,1 为事件数据;接收侧 os_taskq_pend 将 argv[0]=OS_MSG_EVENT、argv[1]=1。

示例 2:信号量同步与互斥锁保护

#include "os/os_api.h"

static OS_SEM  data_ready;      /* 事件信号量 */
static OS_MUTEX flash_lock;     /* Flash 独占锁 */

void init_sync(void)
{
    os_sem_create(&data_ready, 0);          /* 初始计数 0 */
    os_mutex_create(&flash_lock);
}

/* 中断/低层服务:数据就绪时通知 */
void isr_data_ready(void)
{
    os_sem_post(&data_ready);
}

/* 高层任务:等待数据 */
void consumer_task(void *p_arg)
{
    os_sem_pend(&data_ready, 50);           /* 超时 500ms(50 ticks) */
    os_mutex_pend(&flash_lock, OS_WAIT_FOREVER);
    /* 独占写 Flash ... */
    os_mutex_post(&flash_lock);
}

来源:os_api.h、os_type.h

说明:os_sem_create(&data_ready, 0) 创建计数为 0 的信号量,os_sem_pend 的第二个参数 50 表示 50 个 tick(10ms/tick,即 500ms),体现 OS_TICKS_PER_SEC=100 的时间换算规则。

示例 3:任务协作式删除

#include "os/os_api.h"

void worker_task(void *p_arg)
{
    int msg[4];
    while (1) {
        os_taskq_pend(NULL, msg, 4);
        if (msg[0] == OS_MSG_DEL_REQ) {      /* 收到删除请求 */
            /* 清理占用的资源 ... */
            os_task_del_res("worker_task");  /* 响应删除,任务退出 */
            return;
        }
        /* 正常工作 ... */
    }
}

void stop_worker(void)
{
    os_task_del_req("worker_task");          /* 请求删除,由对方自行清理 */
}

来源:os_api.h、os_api.h

说明:OS_TASK_DEL_REQ/RES/OK(0x01/0x02/0x03)构成删除协议的三态,os_task_del_res 只在任务自身上下文中调用,确保资源清理发生在拥有者线程内。

Configuration Options

系统内核与服务的配置通过编译宏控制,定义与选择逻辑集中在 os_type.h:

编译宏可选值默认/作用说明
CONFIG_UCOS_ENABLE定义/未定义SDK 默认(uC/OS)启用 uC/OS 内核,OS_SEM/MUTEX/QUEUE 使用统一 ECB 结构体
CONFIG_FREE_RTOS_ENABLE定义/未定义未定义启用 FreeRTOS 内核,类型映射到 StaticSemaphore_t/StaticQueue_t
OS_TICKS_PER_SEC100(常量)100系统节拍频率,1 tick = 10ms;所有超时/延时参数以此换算
OS_DEL_NO_PEND / OS_DEL_ALWAYS0 / 1—os_sem_del/os_mutex_del 删除选项:不等待/无条件删除
OS_TASK_DEL_REQ/RES/OK0x01/0x02/0x03—协作式删除协议状态码
Q_MSG/Q_EVENT/Q_CALLBACK/Q_USER0x100000~0x400000—任务队列消息类别标识
OS_MSG_KEY~OS_MSG_MSG1~6—任务循环内消息号常量(按键/触摸/事件/回调/删除/消息)

注意:两个内核宏必须且只能定义一个,否则编译期报 #error "no_os_defined"。宏配置一般在工程级头文件或构建脚本中定义,os_type.h 仅负责消费这些宏。

芯片平台相关约束(来自 doc/README.md):

芯片CPURAM特性
AC6311A32bit@120MHz48~56KB蓝牙防丢/Beacon/HID/透传,支持 1M/2M/Coded PHY
AC6313A32bit@120MHz48~56KB同上
AC6318A32bit@120MHz48~56KB同上(无 DCDC)
AC6319A32bit@120MHz48~56KB同上

任务栈与队列深度需按芯片 RAM 预算分配(典型任务栈 512B~2KB),任务数量与蓝牙协议栈 Profile 数成正比。

API Reference

以下 API 全部声明于 os_api.h,是系统服务层的公共契约。

内核启动

void os_init()

初始化内核(含中断、节拍源)。在创建任何任务之前调用一次;CONFIG_CPU_BR25 平台返回 void*(兼容旧 SDK 签名)。

void os_start(void)

启动内核调度器。此调用不返回,进入多任务调度后由首个就绪任务接管执行流。因此 os_init 之后的所有静态初始化必须在 os_start 之前完成。

void os_init_tick(int)

配置系统节拍定时器。参数为节拍源频率/分频配置,与 OS_TICKS_PER_SEC=100 配合确定 10ms 调度粒度。

任务管理

int os_task_create(void (*task)(void *p_arg), void *p_arg, u8 prio, u32 stksize, int qsize, const char *name)

  • 参数:task 任务入口函数;p_arg 入口参数;prio 优先级(数值越小优先级越高,uC/OS 约定);stksize 栈大小(字节);qsize 任务消息队列容量(决定 os_taskq_post* 可积压消息数);name 全局唯一任务名。
  • 返回:0 成功,非 0 失败(错误码见 os_error.h,如 OS_TASK_NOT_EXIST)。

const char *os_current_task()

返回当前运行任务名,用于日志与调试。

void os_task_exit() / int os_task_del_req(const char *name) / int os_task_del_res(const char *name) / int os_task_del(const char *name)

  • os_task_exit:当前任务自行结束(不再调度)。
  • os_task_del_req:向目标任务发删除请求(消息 OS_MSG_DEL_REQ),返回请求是否受理。
  • os_task_del_res:目标任务确认删除、释放资源后调用,使删除流程完成。
  • os_task_del:强制删除,慎用——目标任务持有的信号量/互斥锁/队列可能遗留脏状态。

void os_time_dly(int time_tick)

当前任务按 tick 延时(1 tick = 10ms),延时期间让出 CPU 供低优先级任务运行。

任务队列

int os_taskq_post(const char *name, int argc, ...)

  • 参数:name 目标任务名;argc 可变参数个数;后续为消息参数(首参常为消息号,如 OS_MSG_MSG)。
  • 返回:0 成功;OS_TASKQ/OS_TASK_NOT_EXIST 等错误码。
  • 说明:消息按 Q_MSG 类别入队,唤醒目标任务的 os_taskq_pend。

int os_taskq_post_msg(const char *name, int argc, ...) / int os_taskq_post_event(const char *name, int argc, ...)

语义同 os_taskq_post,但分别以 Q_MSG、Q_EVENT 类别入队,便于接收端按类别区分消息来源。

int os_taskq_post_type(const char *name, int type, int argc, int *argv) / int __os_taskq_post(const char *name, int type, int argc, int *argv)

显式指定消息类别(Q_MSG/Q_EVENT/Q_CALLBACK/Q_USER)的数组式投递;argv 指向消息参数数组。

int os_taskq_pend(const char *fmt, int *argv, int argc) / int __os_taskq_pend(int *argv, int argc, int tick)

  • 参数:argv 输出缓冲区;argc 期望参数个数;tick 超时(__os_taskq_pend)。
  • 返回:0 收到消息;超时/错误返回非 0。
  • 说明:阻塞式接收,任务无消息时挂起。fmt 为格式串(可传 NULL 按原始 int 数组接收)。

int os_taskq_accept(int, int *)

非阻塞接收:队列有消息立即取出并返回 0,无消息立即返回非 0,适合轮询型任务。

int os_taskq_del(const char *name, int type) / int os_taskq_del_type(const char *name, int type) / int os_taskq_flush()

按消息类别删除目标队列中的消息,或清空整个队列。常用于休眠/复位前的状态清理。

信号量(OS_SEM)

函数语义
os_sem_create(OS_SEM *sem, int cnt)创建信号量,初始计数值 cnt
os_sem_accept(OS_SEM *sem)非阻塞获取,成功返回 0
os_sem_pend(OS_SEM *sem, int timeout)阻塞获取,timeout tick 超时
os_sem_post(OS_SEM *sem)释放(计数 +1),唤醒等待者
os_sem_del(OS_SEM *sem, int block)删除,OS_DEL_NO_PEND/OS_DEL_ALWAYS
os_sem_set(OS_SEM *sem, u16 cnt)重置计数
os_sem_valid(OS_SEM *sem) / os_sem_query(OS_SEM *sem)有效性检查 / 查询计数

互斥锁(OS_MUTEX)

函数语义
os_mutex_create(OS_MUTEX *mutex)创建互斥锁
os_mutex_accept(OS_MUTEX *mutex)非阻塞尝试加锁
os_mutex_pend(OS_MUTEX *mutex, int timeout)加锁,超时 tick
os_mutex_post(OS_MUTEX *mutex)解锁(仅持有者可调用)
os_mutex_del(OS_MUTEX *mutex, int block) / os_mutex_valid(OS_MUTEX *mutex)删除 / 有效性检查

消息队列(OS_QUEUE)

函数语义
os_q_create(OS_QUEUE *q, QS size)创建容量 size 的队列
os_q_pend(OS_QUEUE *q, int timeout, void *msg)阻塞接收指针到 msg
os_q_post(OS_QUEUE *q, void *msg)投递数据指针
os_q_flush(OS_QUEUE *q) / os_q_query(OS_QUEUE *q) / os_q_valid(OS_QUEUE *q) / os_q_del(OS_QUEUE *q, u8 opt)清空 / 查询 / 校验 / 删除

Professional Notes

失败模式与边界情况

  • 队列溢出:os_taskq_post* 在目标队列已满(qsize 耗尽)时返回错误或丢弃消息。高频事件源(如 RF 中断)向慢速消费任务投递时必须评估峰值速率,必要时在接收端用 os_taskq_flush 丢弃过期事件,避免消息积压拖垮 RAM。
  • 协作式删除的悬挂风险:若目标任务阻塞在 os_taskq_pend 且队列中已无 OS_MSG_DEL_REQ,删除请求可能无法及时被响应;SDK 约定任务循环每次唤醒都检查删除请求消息,确保清理路径可达。
  • 超时参数单位:所有 timeout/delay 参数以 tick 为单位(10ms),误按毫秒传参会造成 10 倍时间偏差——这是移植 SDK 时最常见的隐性 bug。
  • os_q_* 指针悬垂:os_q_post 只传递指针不拷贝数据,发送方栈上变量出作用域后接收方读取即为未定义行为;跨任务传递必须使用静态或堆内存。

并发与一致性

  • 中断上下文:os_sem_post、os_taskq_post_msg/event 设计为可在中断中调用(内核关中断临界区保护队列),但禁止在中断中调用 os_mutex_pend(可能阻塞)与 os_taskq_pend。
  • 优先级反转:互斥锁依赖 uC/OS 的优先级继承机制缓解反转;若使用 FreeRTOS 内核,需确认内核配置启用了 INHERIT_PRIORITY 等价选项。
  • 任务优先级规划:蓝牙 RF 任务优先级最高(数据实时性),协议栈任务次之,应用 UI/外设任务最低;prio 数值越小优先级越高,与常见 RTOS 约定一致。

性能与运维

  • 栈预算:每任务栈 512B~2KB,全系统任务栈总和受 48~56KB RAM 约束;os_task_create 的 stksize 过小会导致栈溢出(通常表现为随机崩溃/看门狗复位),需结合任务调用深度评估。
  • 节拍开销:100Hz 节拍(10ms)在功耗与响应之间取平衡;若需更快响应可调整 OS_TICKS_PER_SEC,但会线性增加内核调度开销。
  • 调试手段:os_current_task() 可用于崩溃现场确认当前任务上下文;os_taskq_accept 非阻塞模式便于在单步调试时观察队列状态。

扩展点

  • 新增系统服务任务:遵循"os_task_create + os_taskq_pend 循环 + os_taskq_post_event 对外接口"模式即可接入现有架构,无需改动内核。
  • 自定义消息类别:Q_USER(0x400000)为上层预留,可扩展私有协议命令(如厂商 AT 指令),接收端按类别宏 + 消息号双重分发。
  • 内核替换:保持 os_api.h 契约不变,切换 CONFIG_UCOS_ENABLE/CONFIG_FREE_RTOS_ENABLE 即可更换内核;移植新内核时需为 os_type.h 补充类型映射与错误码对齐。

Related Links

  • os_api.h — 系统内核 API 契约
  • os_type.h — 双内核类型抽象与节拍配置
  • os_error.h — 内核错误码定义
  • doc/README.md — 芯片平台参数表
  • 协议栈上层应用:蓝牙 SPP/LE/HOGP/Mesh 各 Profile 的实现位于 apps/common/third_party_profile/,其事件循环均基于本页所述任务队列机制(见目录页「协议栈」相关文档)。
Prev
BTStack 协议栈接口
Next
OTA 升级机制