透传与 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.c | AT 命令解析与实现(at_cmd_init()、at_cmd_rx_handler()) |
at_uart.c | UART 数据收发与 FIFO 缓冲 |
spp_at_trans.c/h | SPP 透传通道初始化(transport_spp_init()) |
ble_at_com.c/h | BLE 透传通道(服务端)数据收发 |
ble_at_client.c/h | BLE 客户端连接配置(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 分支的执行顺序体现了依赖关系:
bt_ble_init()完成 BLE 服务注册(含透传 Profile);transport_spp_init()挂接 SPP 透传通道,sys_auto_sniff_controle(1, NULL)开启自动 sniff 省电控制;- 最后
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_com | at_char_com | 差异 |
|---|---|---|
app_at_com.c | app_at_char_com.c | 应用入口,工程宏不同(CONFIG_APP_AT_CHAR_COM) |
at_cmds.c | at_char_cmds.c | 命令实现,命令名前缀/集合可按产品裁剪 |
at_uart.c | at_char_uart.c | UART 收发 |
ble_at_com.c/h | ble_at_char_com.c/h | BLE 特征值透传 |
ble_at_client.c/h | ble_at_char_client.c/h | BLE 客户端 |
ble_at_profile.h | ble_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_CMDlog 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 的独立自动化测试工程;该示例以"可编译运行的参考实现"形式提供,验证方式为:
- 板级工程使能
CONFIG_APP_AT_COM并保持 BLE/EDR 双模后编译(编译期#error可提前暴露配置错误); - 串口工具发送 AT 命令观察回显/执行(需打开对应 log tag);
- 手机串口类 App(SPP)或厂商 App(BLE 自定义服务)收发数据验证透传。