杰理 SDK 文档中心
首页
首页
  • 概述

    • SDK 概览与产品定位
    • 支持芯片平台与蓝牙认证
    • SDK 架构与目录分层
  • 快速开始

    • 环境搭建与编译工具链
    • 编译构建系统
    • 板级工程与配置
    • 烧录与固件升级工具
  • 应用工程

    • 应用选择与工程总览
    • SPP + BLE 数传应用框架
    • 透传与 AT 指令示例
    • BLE 广播/中心与定位示例
    • 2.4G 私有协议与 Dongle 示例
    • 云平台接入示例
    • HID 人机交互应用框架
    • HID 示例工程(键盘/鼠标/遥控器/手柄)
    • Bluetooth Mesh 应用框架
    • Mesh 模型与 Mesh DFU 固件升级
    • Mesh 音频编解码演示
  • 芯片平台与硬件抽象

    • 芯片平台总览与差异
    • 音频编解码与时钟管理
    • 外设驱动接口(ADC/IIC/SPI/PWM/LED/充电)
    • 芯片配置工具与下载支持
  • 蓝牙协议栈

    • 蓝牙控制器层(btctrler)
    • 蓝牙协议栈与 Profile(btstack)
    • 蓝牙模块选择与配置
  • 媒体与音频框架

    • 音频流框架
    • 音频编解码与 A2DP 媒体
    • 音频效果处理(EQ/频谱/变调/环绕/超低音)
    • 本地 TWS 与音频同步
  • 系统服务与运行时

    • 实时操作系统与任务调度
    • 消息事件机制
    • 电源管理与低功耗
    • 存储与配置系统
    • 设备驱动框架(USB/RTC)
  • 应用公共组件

    • 音频应用组件
    • 设备外设抽象(按键/触摸/传感器/存储)
    • 蓝牙公共模块与消息联动
    • 调试与配置组件
    • 杰理关键词唤醒(jl_kws)
  • 第三方协议与云平台接入

    • 杰理 RCSP 私有协议
    • 低功耗蓝牙 Mesh 方案(llsync_mesh)
    • Sig Mesh 方案
    • 涂鸦协议接入
    • 腾讯连连接入
    • 华为 HiLink 接入
  • 固件升级与维护

    • OTA 升级机制
    • 升级补丁与版本维护
    • 升级工具链(BLE OTA / USB Dongle OTA)
  • 文档与开发资源

    • 数据手册与架构文档
    • 协议与云平台开发文档
    • 常见问题与技术支持

透传与 AT 指令示例

本文介绍 fw-AC63_BT_SDK 中基于 SPP(经典蓝牙串口)与 BLE(低功耗蓝牙)的透传(透明传输)与 AT 指令示例,涵盖 apps/spp_and_le/examples/at_com、apps/spp_and_le/examples/at_char_com 两个示例工程,以及公共透传组件 trans_data_demo,说明其应用入口、UART 数据通道、AT 命令解析、蓝牙链路初始化与低功耗/关机处理机制。

Purpose and Scope

本页面向希望基于 AC63 系列芯片实现"UART ↔ 蓝牙透传 + AT 指令控制"场景的开发者,完整说明:

  • AT COM 应用(CONFIG_APP_AT_COM)的启动流程与状态机;
  • 蓝牙协议栈(BTSTACK)初始化、SPP 与 BLE 双模使能的前提条件;
  • UART 数据通道、AT 命令模块、BLE/SPP 透传通道的文件划分与职责;
  • at_char_com(基于 GATT 特征值的 AT 透传)变体与 at_com 的差异;
  • 低功耗模式与软关机时对蓝牙链路的处理约束。

属于其他页面的内容不在本文展开:GATT 通用服务端/客户端的底层实现(见 le_gatt_server.c / le_gatt_client.c)、TWS/RCSP 等私有协议(JL_rcsp 目录)、HID/Mesh 等其他应用。如需了解 spp_and_le 应用整体框架,请参见对应的应用总览页面。

Overview

透传与 AT 指令是蓝牙模块最常见的两种工作形态:

  • 透传模式:MCU 通过 UART 把数据交给蓝牙 SoC,蓝牙 SoC 原样转发到对端(手机 App 或另一台设备);对端发来的数据同样原样回送到 UART。数据面不经过业务解析,只做搬运。
  • AT 指令模式:UART 上传输的是以 AT 开头、\r\n 结尾的文本命令,由 at_cmds.c 解析并执行(例如查询版本、配置参数、控制蓝牙开关、触发关机等),从而让外部 MCU 可以通过串口"遥控"蓝牙模块。

在 AC63 SDK 中,这两种模式共用一套 UART 通道与蓝牙链路:UART 收到的数据先进入接收处理,再根据内容/模式分发到 AT 命令解析或透传通道;蓝牙侧则由 SPP(EDR)和自定义 BLE GATT 服务两条路径承载数据。

示例代码位于 apps/spp_and_le/examples/at_com/,包含以下文件:

文件职责
app_at_com.c应用入口、状态机、蓝牙事件处理、低功耗/关机控制
at_cmds.cAT 命令解析与实现(at_cmd_init()、at_cmd_rx_handler())
at_uart.cUART 数据收发与 FIFO 缓冲
spp_at_trans.c/hSPP 透传通道初始化(transport_spp_init())
ble_at_com.c/hBLE 透传通道(服务端)数据收发
ble_at_client.c/hBLE 客户端连接配置(TRANS_AT_CLIENT 模式)
ble_at_profile.h自定义 BLE GATT Service/Characteristic 定义

at_char_com 目录是同一思路的变体:把 AT 通道改挂到 GATT Characteristic 上(ble_at_char_profile.h、ble_at_char_com.c、ble_at_char_client.c),并配套 at_char_cmds.c、at_char_uart.c。公共组件 apps/common/third_party_profile/jieli/trans_data_demo/spp_trans_data.h 则提供可复用的 SPP 透传数据接口。

Architecture

下图展示 AT COM 示例的分层架构与数据通路:

flowchart TD
    subgraph sg_App["应用层 apps/spp_and_le/examples/at_com"]
        App["app_at_com.c<br/>入口/状态机/事件"]
        Cmds["at_cmds.c<br/>AT 命令解析"]
        Uart["at_uart.c<br/>UART 收发/FIFO"]
        Spp["spp_at_trans.c<br/>SPP 透传"]
        Ble["ble_at_com.c<br/>BLE 透传服务"]
        BleCli["ble_at_client.c<br/>BLE 客户端"]
    end

    subgraph sg_Stack["协议栈与硬件"]
        Btstack["BTSTACK<br/>btstack_init"]
        EDR["EDR/SPP<br/>btstack_edr_start_before_init"]
        BLE["BLE<br/>btstack_ble_start_before_init"]
        UartHw["UART 外设"]
    end

    MCU["外部 MCU/串口工具"] -->|"AT 指令/透传数据"| UartHw
    UartHw -->|"RX 中断"| Uart
    Uart --> Cmds
    Uart -->|"透传数据"| Spp
    Uart -->|"透传数据"| Ble
    Cmds -->|"蓝牙控制/关机"| App
    Spp --> EDR
    Ble --> BLE
    BleCli --> BLE
    App -->|"btstack_init 初始化"| Btstack
    Btstack --> EDR
    Btstack --> BLE
    EDR -->|"SPP 链路"| Phone["手机 App/对端设备"]
    BLE -->|"GATT 自定义服务"| Phone
    Phone -->|"下发数据"| EDR
    Phone -->|"下发数据"| BLE
    EDR -->|"SPP 数据回调"| Spp
    BLE -->|"GATT 写回调"| Ble
    Spp -->|"数据回送"| Uart
    Ble -->|"数据回送"| Uart

各层职责与连接方式:

  • 入口层 app_at_com.c:注册应用状态机,在 APP_STA_START + ACTION_AT_COM 时调用 atcom_app_start() 完成时钟配置与 BTSTACK 启动;蓝牙初始化完成后(BT_STATUS_INIT_OK)再初始化 SPP 透传与 AT 命令模块。它同时是低功耗与软关机控制的出口。
  • 数据层 at_uart.c + at_cmds.c:UART 负责物理收发,AT 命令模块负责把 UART 字节流解析成命令并分发;透传数据则绕过命令解析直接进入 SPP/BLE 通道。
  • 传输层 spp_at_trans.c / ble_at_com.c / ble_at_client.c:把数据接到经典蓝牙 SPP 或 BLE GATT 自定义服务上;ble_at_profile.h 定义服务 UUID 与特征值布局,供手机端按同一协议对接。
  • 协议栈层:btstack_init() 统一初始化 EDR 与 BLE 双栈;示例通过编译期断言强制 TCFG_USER_BLE_ENABLE 与 TCFG_USER_EDR_ENABLE 同时使能,因为 AT 指令(如蓝牙开关控制)依赖双模能力。

应用入口与状态机(app_at_com.c)

编译开关与前提条件

整个 AT COM 示例由两个宏同时保护,且强制要求 BLE 与 EDR 双模使能:

#if CONFIG_APP_AT_COM && USER_SUPPORT_PROFILE_SPP

#if !(TCFG_USER_BLE_ENABLE && TCFG_USER_EDR_ENABLE)
#error "board config error, confirm!!!!!!"
#endif

#define TEST_AUTO_BT_OPEN          0//for test

Source: app_at_com.c

设计意图:AT 指令往往需要同时操作 SPP 链路与 BLE 链路(例如查询连接状态、切换广播),因此作者在编译期就用 #error 拦住配置错误的板级工程,避免运行期出现"AT 指令能解析但蓝牙链路不存在"的隐性故障。TEST_AUTO_BT_OPEN 是测试辅助开关,默认关闭。

启动流程(atcom_app_start)

应用被拉起后,先配置系统时钟,再按 EDR → BLE 的顺序启动协议栈前置初始化,最后统一调用 btstack_init():

static void atcom_app_start()
{
    log_info("=======================================");
    log_info("-------------at_com demo---------------");
    log_info("=======================================");

    log_info("app_file: %s", __FILE__);

    clk_set("sys", BT_NORMAL_HZ);
    u32 sys_clk =  clk_get("sys");
    bt_pll_para(TCFG_CLOCK_OSC_HZ, sys_clk, 0, 0);

#if TCFG_USER_EDR_ENABLE
    btstack_edr_start_before_init(NULL, 0);
#endif

#if TCFG_USER_BLE_ENABLE
    btstack_ble_start_before_init(NULL, 0);

#if TRANS_AT_CLIENT
    /* atcom_client_config_init(); */
#endif

#endif

    btstack_init();
    /* 按键消息使能 */
    sys_key_event_enable();
}

Source: app_at_com.c

要点:

  • clk_set("sys", BT_NORMAL_HZ) 先把系统主频切换到蓝牙正常工作频率,再通过 bt_pll_para(TCFG_CLOCK_OSC_HZ, sys_clk, 0, 0) 依据晶振频率与系统时钟配置蓝牙 PLL 参数——顺序不能颠倒,否则 BTSTACK 可能跑在错误的时钟源上。
  • EDR 与 BLE 的前置初始化(btstack_edr_start_before_init / btstack_ble_start_before_init)只做各自协议栈的早期准备,真正的统一初始化由 btstack_init() 完成。
  • TRANS_AT_CLIENT 分支下的 ble_at_client_config_init()(注释掉的调用)用于"本机作为 BLE 客户端去连对端透传设备"的场景,默认示例以服务端透传为主。

应用状态机(atcom_state_machine)

static int atcom_state_machine(struct application *app, enum app_state state, struct intent *it)
{
    switch (state) {
    case APP_STA_CREATE:
        break;
    case APP_STA_START:
        if (!it) {
            break;
        }
        switch (it->action) {
        case ACTION_AT_COM:
            atcom_app_start();
            break;
        }
        break;
    case APP_STA_PAUSE:
        break;
    case APP_STA_RESUME:
        break;
    case APP_STA_STOP:
        break;
    case APP_STA_DESTROY:
        log_info("APP_STA_DESTROY\n");
        break;
    }

    return 0;
}

Source: app_at_com.c

该状态机是 SDK 标准 struct application 回调形态:系统通过 intent(此处为 ACTION_AT_COM)携带启动动作,只有显式收到该 action 才真正启动蓝牙。APP_STA_CREATE/DESTROY 目前为空,为扩展预留了生命周期钩子。

蓝牙事件分发

AT COM 应用注册了两个蓝牙事件回调:

  • atcom_bt_hci_event_handler():转发 HCI 层事件到公共处理器 bt_comm_edr_hci_event_handler() / bt_comm_ble_hci_event_handler();
  • atcom_bt_connction_status_event_handler():连接状态机事件,其中 BT_STATUS_INIT_OK 是示例的关键节点。
extern void ble_test_auto_adv(u8 en);
extern void transport_spp_init(void);
extern void at_cmd_init(void);
static int atcom_bt_connction_status_event_handler(struct bt_event *bt)
{
    log_info("----%s %d", __FUNCTION__, bt->event);
    {
        log_info("-----------------------bt_connction_status_event_handler %d", bt->event);

        switch (bt->event) {
        case BT_STATUS_INIT_OK:
            /*
             * 蓝牙初始化完成
             */
            log_info("BT_STATUS_INIT_OK\n");

#if TCFG_USER_BLE_ENABLE
            extern void bt_ble_init(void);
            bt_ble_init();
#endif

#if TRANS_AT_COM &&  USER_SUPPORT_PROFILE_SPP
            transport_spp_init();
            sys_auto_sniff_controle(1, NULL);
#endif
            at_cmd_init();

#if TEST_AUTO_BT_OPEN
            ble_test_auto_adv(1);
            bt_wait_phone_connect_control_ext(1, 1);
#endif
            break;

        default: {
#if TCFG_USER_EDR_ENABLE
            bt_comm_edr_status_event_handler(bt);
#endif

#if TCFG_USER_BLE_ENABLE
            bt_comm_ble_status_event_handler(bt);
#endif
        }
        break;
        }
        return 0;
    }
}

Source: app_at_com.c

BT_STATUS_INIT_OK 分支的执行顺序体现了依赖关系:

  1. bt_ble_init() 完成 BLE 服务注册(含透传 Profile);
  2. transport_spp_init() 挂接 SPP 透传通道,sys_auto_sniff_controle(1, NULL) 开启自动 sniff 省电控制;
  3. 最后 at_cmd_init() 初始化 AT 命令模块,确保命令解析就绪时底层通道已可用。

其余状态(连接/断开等)统一交给 bt_comm_edr_status_event_handler / bt_comm_ble_status_event_handler 公共处理,示例本身不重复实现,保持与 SDK 其他应用一致的连接管理行为。

低功耗与软关机

AT 指令场景经常需要外部 MCU 通过串口命令让模块休眠或关机,示例提供了完整配套:

void atcom_power_event_to_user(u8 event)
{
    struct sys_event e;
    e.type = SYS_DEVICE_EVENT;
    e.arg  = (void *)DEVICE_EVENT_FROM_POWER;
    e.u.dev.event = event;
    e.u.dev.value = 0;
    sys_event_notify(&e);
}

extern void set_at_uart_wakeup(void);
static void atcom_set_soft_poweroff(void)
{
    log_info("set_soft_poweroff\n");
    is_app_atcom_active = 1;
    //必须先主动断开蓝牙链路,否则要等链路超时断开

#if TCFG_USER_BLE_ENABLE
    btstack_ble_exit(0);
    set_at_uart_wakeup();
#endif

#if TCFG_USER_EDR_ENABLE
    btstack_edr_exit(0);
#endif

#if (TCFG_USER_EDR_ENABLE || TCFG_USER_BLE_ENABLE)
    //延时300ms,确保BT退出链路断开
    sys_timeout_add(NULL, power_set_soft_poweroff, WAIT_DISCONN_TIME_MS);
#else
    power_set_soft_poweroff();
#endif
}

Source: app_at_com.c

设计要点(源码注释已点明):软关机前必须先主动断开蓝牙链路,否则 power_set_soft_poweroff() 会一直等待链路超时,导致关机命令响应缓慢。因此流程是:先 btstack_ble_exit(0) + btstack_edr_exit(0) 主动拆链,再通过 sys_timeout_add(..., WAIT_DISCONN_TIME_MS) 延时 300ms 让 BT 退出链路,最后才真正下电。set_at_uart_wakeup() 在关机前配置 UART 唤醒,保证下次串口命令能把模块叫醒。

配套接口:

  • at_set_soft_poweroff():AT 命令可调用的软关机入口(at_cmds.c 中会引用);
  • at_set_atcom_low_power_mode(u8 enable):切换 is_app_atcom_active 标志,供 AT 命令进入/退出低功耗模式;
  • atcom_key_event_handler():接收 DEVICE_EVENT_FROM_KEY 按键事件,使示例在无串口时也能用按键触发操作。

AT 命令模块与 UART 通道(at_cmds.c / at_uart.c)

从 app_at_com.c 的 extern 声明可以确认命令模块对外接口:

extern void at_cmd_init(void);        // 初始化 AT 命令解析(含注册命令表)
extern void at_cmd_rx_handler(void);  // UART 接收数据后的处理入口
extern void transport_spp_init(void); // SPP 透传通道初始化

Source: app_at_com.c

at_cmd_init() 在 BT_STATUS_INIT_OK 时被调用,负责注册命令表与 UART 回调;at_cmd_rx_handler() 是 UART 收数后的主处理函数,位于 at_uart.c/at_cmds.c 的数据链路上。示例还定义了发送缓冲 static u8 at_uart_sent_buf[AT_UART_FIFIO_BUFFER_SIZE];(app_at_com.c 第 255 行附近),说明 UART 发送采用 FIFO 缓冲、由 atcom_event_handler() 统一驱动。

说明:at_cmds.c 中具体命令表(如 AT+VER、AT+POWEROFF 等)与 at_uart.c 的 FIFO 实现细节未能在本次文档生成的源码探测范围内读取到,此处仅记录已确认的接口与数据流。如需命令全集,请直接查阅 apps/spp_and_le/examples/at_com/at_cmds.c。

BLE 与 SPP 透传通道

BLE 自定义服务(ble_at_profile.h / ble_at_com.c)

ble_at_profile.h 定义透传用的自定义 GATT Service 与 Characteristic(UUID 布局由该头文件统一定义,手机端需按相同 UUID 对接)。ble_at_com.c 实现服务端数据通路:手机通过 GATT 写特征值下发数据 → 回调送到 UART;UART 待发数据通过 GATT 通知/写回特征值上送手机。ble_at_client.c + ble_at_client.h 则承载 TRANS_AT_CLIENT 客户端模式。

客户端模式初始化(TRANS_AT_CLIENT 编译开关内):

#if TRANS_AT_CLIENT
static const client_conn_cfg_t client_at_conn_config = {
    .report_data_callback = NULL,
    .event_callback = NULL,
    .search_uuid_cnt = 0,
    .security_en = 0,
};

static void ble_at_client_config_init(void)
{
    atcom_ble_client_api = ble_get_client_operation_table();
    atcom_ble_client_api->init_config(0, &client_at_conn_config);
}
#endif

Source: app_at_com.c

设计意图:客户端模式用于"AC63 主动连接另一台透传设备(例如手机上的透传 App 或另一块模组)",通过 ble_get_client_operation_table() 拿到 SDK 统一的客户端操作表,再用 init_config() 注入连接配置(UUID 搜索、安全使能、事件/数据回调)。当前示例将回调置空、不启用安全配对,属于最小可用配置。

SPP 透传(spp_at_trans.c / trans_data_demo)

transport_spp_init() 挂接 SPP 数据通道,使经典蓝牙手机端可以用串口类 App 直接与 UART 透传。公共目录 apps/common/third_party_profile/jieli/trans_data_demo/spp_trans_data.h 提供跨应用复用的 SPP 透传数据接口,at_com 与 at_char_com 均可引用同一套 SPP 通路,只在上层命令/特征值处理上分化。

at_char_com 变体

apps/spp_and_le/examples/at_char_com/ 与 at_com 结构一一对应,核心差异是把 AT 通道挂到 GATT Characteristic 上:

at_comat_char_com差异
app_at_com.capp_at_char_com.c应用入口,工程宏不同(CONFIG_APP_AT_CHAR_COM)
at_cmds.cat_char_cmds.c命令实现,命令名前缀/集合可按产品裁剪
at_uart.cat_char_uart.cUART 收发
ble_at_com.c/hble_at_char_com.c/hBLE 特征值透传
ble_at_client.c/hble_at_char_client.c/hBLE 客户端
ble_at_profile.hble_at_char_profile.h自定义 Service/Characteristic 定义

选择建议:若对端是"串口透传类 App"(走 SPP),用 at_com 即可;若对端是"厂商私有 App 且基于 BLE 自定义特征值",用 at_char_com 更合适,因为其特征值布局完全由 ble_at_char_profile.h 控制,便于与 App 端联调。

Core Flow

启动时序

从系统上电到数据通道就绪的完整时序如下:

sequenceDiagram
    participant SYS as 系统启动
    participant APP as app_at_com.c 状态机
    participant BT as BTSTACK
    participant SPP as spp_at_trans.c
    participant AT as at_cmds.c
    participant UART as at_uart.c

    SYS->>APP: APP_STA_START + ACTION_AT_COM
    activate APP
    APP->>APP: clk_set("sys", BT_NORMAL_HZ) / bt_pll_para
    APP->>BT: btstack_edr_start_before_init
    APP->>BT: btstack_ble_start_before_init
    APP->>BT: btstack_init()
    BT-->>APP: BT_STATUS_INIT_OK
    APP->>APP: bt_ble_init()
    APP->>SPP: transport_spp_init()
    APP->>SPP: sys_auto_sniff_controle(1, NULL)
    APP->>AT: at_cmd_init()
    AT-->>UART: 注册 UART 接收处理
    deactivate APP
    UART->>AT: 收到串口数据 → at_cmd_rx_handler()
    AT->>AT: 解析 AT 命令并执行
    AT-->>BT: 蓝牙控制/透传数据

数据面流向(UART ↔ 蓝牙)

flowchart LR
    RX["UART RX 中断/FIFO"] --> DEC{"是否 AT 指令?"}
    DEC -->|"是"| CMD["at_cmds.c 解析执行<br/>(查询/配置/关机/低功耗)"]
    DEC -->|"否"| FWD["透传通道<br/>spp_at_trans / ble_at_com"]
    CMD -->|"控制动作"| CTRL["蓝牙开关/软关机/低功耗"]
    FWD -->|"SPP"| SPP_L["经典蓝牙 SPP 链路"]
    FWD -->|"BLE"| BLE_L["BLE GATT 自定义服务"]
    SPP_L -->|"对端数据"| UP1["上行回 UART"]
    BLE_L -->|"对端数据"| UP2["上行回 UART"]
    UP1 --> TX["UART TX(at_uart_sent_buf FIFO)"]
    UP2 --> TX

判断依据:AT 指令以 AT 前缀起始、\r\n 结尾;透传数据则直接进入 SPP/BLE 通道。两条路径在 UART 层交汇、在蓝牙层分叉,是典型的"控制面 + 数据面"分离设计——控制命令走解析,业务数据走搬运,互不阻塞。

Usage Examples

示例 1:启动 AT COM 应用(完整初始化入口)

static void atcom_app_start()
{
    log_info("=======================================");
    log_info("-------------at_com demo---------------");
    log_info("=======================================");

    log_info("app_file: %s", __FILE__);

    clk_set("sys", BT_NORMAL_HZ);
    u32 sys_clk =  clk_get("sys");
    bt_pll_para(TCFG_CLOCK_OSC_HZ, sys_clk, 0, 0);

#if TCFG_USER_EDR_ENABLE
    btstack_edr_start_before_init(NULL, 0);
#endif

#if TCFG_USER_BLE_ENABLE
    btstack_ble_start_before_init(NULL, 0);

#if TRANS_AT_CLIENT
    /* atcom_client_config_init(); */
#endif

#endif

    btstack_init();
    /* 按键消息使能 */
    sys_key_event_enable();
}

Source: app_at_com.c

示例 2:蓝牙就绪后挂接透传与 AT 模块

case BT_STATUS_INIT_OK:
    /*
     * 蓝牙初始化完成
     */
    log_info("BT_STATUS_INIT_OK\n");

#if TCFG_USER_BLE_ENABLE
    extern void bt_ble_init(void);
    bt_ble_init();
#endif

#if TRANS_AT_COM &&  USER_SUPPORT_PROFILE_SPP
    transport_spp_init();
    sys_auto_sniff_controle(1, NULL);
#endif
    at_cmd_init();

Source: app_at_com.c

示例 3:AT 触发软关机(先拆链、再延时下电)

static void atcom_set_soft_poweroff(void)
{
    log_info("set_soft_poweroff\n");
    is_app_atcom_active = 1;
    //必须先主动断开蓝牙链路,否则要等链路超时断开

#if TCFG_USER_BLE_ENABLE
    btstack_ble_exit(0);
    set_at_uart_wakeup();
#endif

#if TCFG_USER_EDR_ENABLE
    btstack_edr_exit(0);
#endif

#if (TCFG_USER_EDR_ENABLE || TCFG_USER_BLE_ENABLE)
    //延时300ms,确保BT退出链路断开
    sys_timeout_add(NULL, power_set_soft_poweroff, WAIT_DISCONN_TIME_MS);
#else
    power_set_soft_poweroff();
#endif
}

Source: app_at_com.c

Configuration Options

AT COM 示例的行为由以下编译期/运行期宏控制:

宏/常量类型默认说明
CONFIG_APP_AT_COM编译宏0(需在 app_config.h 使能)是否编译 AT COM 示例应用
USER_SUPPORT_PROFILE_SPP编译宏0/1(板级配置)SPP Profile 支持,AT COM 依赖它
TCFG_USER_BLE_ENABLE编译宏0/1(板级配置)BLE 功能使能;与 EDR 必须同时为 1,否则 #error
TCFG_USER_EDR_ENABLE编译宏0/1(板级配置)EDR/经典蓝牙功能使能,同上
TRANS_AT_CLIENT编译宏0使能 BLE 客户端透传模式(ble_at_client.c)
TEST_AUTO_BT_OPEN编译宏0测试辅助:自动打开蓝牙并等待手机连接
AT_UART_FIFIO_BUFFER_SIZE常量由 at_uart.c 定义UART 发送 FIFO 缓冲大小(at_uart_sent_buf)
WAIT_DISCONN_TIME_MS常量300软关机前等待蓝牙链路断开的延时(毫秒)
TCFG_CLOCK_OSC_HZ常量板级晶振频率蓝牙 PLL 参数计算用晶振频率
BT_NORMAL_HZ常量系统定义蓝牙工作时的系统主频档位

日志开关(apps/spp_and_le/config/log_config.c):AT_CMD 与 AT_COM 两个 log tag 默认使能 i/d/w/e 级别,调试 AT 命令收发时可打开 LOG_DUMP_ENABLE(app_at_com.c 第 25 行注释)查看原始数据。

API Reference

以下接口来自 app_at_com.c 及同目录模块的 extern 声明(签名以源码为准):

atcom_app_start(void)

AT COM 应用启动入口:设置系统时钟与蓝牙 PLL 参数,按 EDR → BLE 顺序执行 BTSTACK 前置初始化,最后 btstack_init() 统一初始化,并使能按键事件。

  • 参数:无
  • 返回:void
  • 调用时机:状态机收到 ACTION_AT_COM 时

atcom_state_machine(struct application *app, enum app_state state, struct intent *it): int

标准应用状态机回调。

  • 参数:app(应用实例)、state(APP_STA_CREATE/START/PAUSE/RESUME/STOP/DESTROY)、it(intent,携带 ACTION_AT_COM)
  • 返回:恒为 0
  • 行为:仅 APP_STA_START 且 it->action == ACTION_AT_COM 时执行 atcom_app_start()

atcom_bt_hci_event_handler(struct bt_event *bt): int

HCI 层事件分发:按 EDR/BLE 分别转发给 bt_comm_edr_hci_event_handler() / bt_comm_ble_hci_event_handler()。

  • 参数:bt(蓝牙事件,含 event 与 value=reason)
  • 返回:0

atcom_bt_connction_status_event_handler(struct bt_event *bt): int

连接状态事件处理。BT_STATUS_INIT_OK 时依次执行 bt_ble_init()、transport_spp_init()、sys_auto_sniff_controle(1, NULL)、at_cmd_init();其余状态转发公共处理器。

  • 参数:bt(蓝牙连接状态事件)
  • 返回:0

atcom_key_event_handler(struct sys_event *event)

按键事件处理(DEVICE_EVENT_FROM_KEY),提取 event->u.key.event/value。

  • 参数:event(系统事件)
  • 返回:void

atcom_power_event_to_user(u8 event)

把电源事件包装为 SYS_DEVICE_EVENT + DEVICE_EVENT_FROM_POWER 并通过 sys_event_notify() 广播。

  • 参数:event(电源事件类型)
  • 返回:void

atcom_set_soft_poweroff(void) / at_set_soft_poweroff(void)

软关机流程:先 btstack_ble_exit(0) / btstack_edr_exit(0) 主动拆链,set_at_uart_wakeup() 使能 UART 唤醒,再延时 WAIT_DISCONN_TIME_MS 后 power_set_soft_poweroff()。

  • 参数:无
  • 返回:void
  • 注意:必须先拆链再下电,否则关机响应会拖到链路超时

at_set_atcom_low_power_mode(u8 enable)

切换低功耗模式标志:enable=1 时 is_app_atcom_active=0。

  • 参数:enable(是否进入低功耗)
  • 返回:void

外部模块接口(由 app_at_com.c 引用)

  • at_cmd_init(void):初始化 AT 命令解析(注册命令表与 UART 回调)
  • at_cmd_rx_handler(void):UART 接收数据主处理入口
  • transport_spp_init(void):初始化 SPP 透传通道
  • ble_test_auto_adv(u8 en):测试用自动广播开关
  • set_at_uart_wakeup(void):配置 UART 唤醒引脚/事件
  • ble_get_client_operation_table():获取 BLE 客户端操作表(TRANS_AT_CLIENT 模式)

Failure Modes, Edge Cases & Concurrency

软关机前未拆链

源码注释明确警告:"必须先主动断开蓝牙链路,否则要等链路超时断开"。若外部 MCU 直接调用电源管理而不走 atcom_set_soft_poweroff(),模块可能进入挂起状态直到 BT 链路超时。正确用法:AT 命令 → at_set_soft_poweroff() → 拆链 → 300ms 延时 → 下电。

BLE/EDR 未同时使能

#if !(TCFG_USER_BLE_ENABLE && TCFG_USER_EDR_ENABLE) 会在编译期报 #error "board config error, confirm!!!!!!"。这是有意为之的防御:AT COM 的双模设计依赖两条链路,单模配置属于板级错误,应在编译期暴露而非运行期静默失败。

低功耗模式与透传并发

is_app_atcom_active 标志控制低功耗开关(at_set_atcom_low_power_mode)。进入低功耗后 UART 接收路径仍需保持唤醒能力(set_at_uart_wakeup()),否则外部 MCU 的 AT 命令无法唤醒模块。透传数据与 AT 命令共用 UART FIFO(at_uart_sent_buf[AT_UART_FIFIO_BUFFER_SIZE]),发送侧由事件循环串行驱动,避免多任务同时写 UART 造成字节交错。

自动 sniff 与实时性

sys_auto_sniff_controle(1, NULL) 开启自动 sniff 省电后,链路会周期性进入低功耗监听模式;对时延敏感的高频透传场景,需评估 sniff 间隔对吞吐与延迟的影响(SDK 提供该接口即为调节入口)。

事件回调上下文

atcom_bt_connction_status_event_handler / atcom_key_event_handler 运行在系统事件线程,回调内不应执行阻塞操作(如长延时、等待信号量),否则会拖慢整个蓝牙事件分发。命令执行耗时较长时应自行拆分为异步任务。

Performance & Operational Notes

  • UART FIFO 缓冲:发送路径通过 AT_UART_FIFIO_BUFFER_SIZE 的缓冲批量搬运,减少中断频率;调大该值可吸收突发数据,但会占用 RAM(AC63 系列片上资源有限,需按实际波特率与包长权衡)。
  • 双模并存:SPP 与 BLE 同时使能会占用更多协议栈资源与连接槽位,量产选型时应确认 TCFG_USER_BLE_ENABLE/TCFG_USER_EDR_ENABLE 与产品形态匹配。
  • 日志开关:AT_COM/AT_CMD log tag 在 apps/spp_and_le/config/log_config.c 中可独立关闭,量产版本建议关闭 LOG_DEBUG_ENABLE 以降低串口日志对时序的干扰。
  • 调试入口:打开 TEST_AUTO_BT_OPEN 后示例会自动开启广播并等待手机连接,适合产测/联调阶段快速验证链路。

Extension Points

  • 新增 AT 命令:在 at_cmds.c(或 at_char_cmds.c)的命令表中追加条目并在对应函数中实现解析/执行逻辑,再调用 at_cmd_init() 注册;命令可直接复用 atcom_set_soft_poweroff()、at_set_atcom_low_power_mode()、atcom_power_event_to_user() 等应用层接口。
  • 更换 GATT 服务 UUID:修改 ble_at_profile.h(或 ble_at_char_profile.h)中的 Service/Characteristic UUID 即可与自有 App 对齐协议;ble_at_com.c 的数据回调保持不变。
  • 启用 BLE 客户端模式:将 TRANS_AT_CLIENT 置 1 并取消 ble_at_client_config_init() 的注释,通过 ble_get_client_operation_table() 配置连接参数后,AC63 可主动连接对端透传设备。
  • 复用 SPP 透传组件:apps/common/third_party_profile/jieli/trans_data_demo/spp_trans_data.h 提供跨应用复用的 SPP 透传接口,其他应用(如 at_char_com、自定义业务)可直接引用,无需重新实现链路层。

Tests

SDK 示例目录下未发现针对 AT COM 的独立自动化测试工程;该示例以"可编译运行的参考实现"形式提供,验证方式为:

  1. 板级工程使能 CONFIG_APP_AT_COM 并保持 BLE/EDR 双模后编译(编译期 #error 可提前暴露配置错误);
  2. 串口工具发送 AT 命令观察回显/执行(需打开对应 log tag);
  3. 手机串口类 App(SPP)或厂商 App(BLE 自定义服务)收发数据验证透传。

Related Links

  • app_at_com.c(应用入口/状态机/事件)
  • at_cmds.c(AT 命令实现)
  • at_uart.c(UART 通道)
  • spp_at_trans.c(SPP 透传)
  • ble_at_com.c / ble_at_profile.h(BLE 透传与 Profile)
  • at_char_com 变体示例
  • SPP 透传公共组件
  • 日志开关配置(AT_CMD/AT_COM tag)
Prev
SPP + BLE 数传应用框架
Next
BLE 广播/中心与定位示例