遥控器示例
本页面介绍 AW33N BLE SDK 中基于 BLE HID(人机交互设备)的遥控器(Remote Control)示例应用,涵盖其 HID 报告映射、按键处理、红外(IR)联动、低功耗关机、BLE 重连与配对等完整实现机制。
Purpose and Scope
本文档面向希望在 AW33N 平台上快速实现遥控器类产品(如电视遥控器、机顶盒遥控器)的嵌入式开发者,完整说明 apps/demo/hid/examples/remote_control/app_remote_control.c 的实现:
- 本页覆盖:BLE HID Consumer 报告定义、按键→消费类按键码映射、BLE/IR 双通道发送策略、自动关机定时、BLE 配对/断开逻辑、应用状态机与消息循环、相关板级配置。
- 不在本页范围:BLE HOGP 协议栈底层实现(见
ble_hogp模块)、红外编码器硬件驱动(ir_encoder)、通用 HID 协议(standard_hid)以及 LED 控制框架(led_control)——这些由各自的模块文档说明。 - 相关示例:同目录下还有鼠标(mouse)、键盘(keyboard)等其他 HID 示例,本页仅聚焦遥控器示例。
概述
遥控器示例是 SDK 中一个可直接编译运行的 BLE HID 应用:设备以 BLE_APPEARANCE_GENERIC_REMOTE_CONTROL 外观广播,通过 Consumer Control(消费类控制,Usage Page 0x0C) 报告向主机(电视/机顶盒/手机)发送音量、播放暂停、静音、切歌、快进快退等按键,同时支持 红外(IR)发射(示例中码表匹配海信电视),实现"BLE 优先、IR 兜底"的双模遥控方案。
设计上该示例解决了遥控器产品的几个核心诉求:
- 低功耗:无操作一段时间后自动软关机(
TCFG_HID_AUTO_SHUTDOWN_TIME),软关机前确保蓝牙链路断开。 - 双通道兼容:BLE 未连接时用 IR 控制旧设备,BLE 已连接时优先走 BLE(电源键除外,始终走 IR)。
- 易配对:双击指定按键触发断开并重新进入可配对状态;三击进入软关机。
- 平台无关的按键抽象:通过
hidrc_click_table/hidrc_hold_table把 AD 按键值映射为消费类按键码,换按键矩阵只需改表。
架构
flowchart TD
subgraph sg_HW["硬件层"]
KEY["AD按键 (TCFG_ADKEY_VALUEx)"]
LED["LED指示灯"]
IR_TX["红外发射管"]
BLE_RF["BLE射频"]
end
subgraph sg_APP["遥控器应用 (app_remote_control.c)"]
SM["hidrc_state_machine<br/>APP状态机"]
MSG["消息循环<br/>get_msg + app_comm_process_handler"]
KEY_DEAL["hidrc_app_key_deal_test<br/>按键分发"]
IR_DEAL["hidrc_ir_key_deal<br/>IR按键处理"]
BLE_SEND["ble_hid_data_send<br/>HID上报"]
PWR["hidrc_set_soft_poweroff<br/>软关机"]
TIMER["hidrc_auto_shutdown_timer<br/>自动关机定时器"]
end
subgraph sg_SDK["SDK服务"]
HOGP["HOGP (ble_hogp)"]
BTSTACK["btstack (btstack_task)"]
IR_ENC["ir_encoder"]
LED_CTL["led_control"]
PWR_MG["app_power_mg"]
SYS_TMR["sys_timer"]
end
KEY --> KEY_DEAL
KEY_DEAL --> BLE_SEND
KEY_DEAL --> IR_DEAL
IR_DEAL --> IR_ENC
IR_ENC --> IR_TX
BLE_SEND --> HOGP
HOGP --> BTSTACK
BTSTACK --> BLE_RF
SM --> MSG
MSG --> KEY_DEAL
MSG --> PWR
TIMER --> PWR
PWR --> BTSTACK
PWR --> PWR_MG
KEY_DEAL --> LED_CTL
LED_CTL --> LED
架构说明
- 应用层(本页主体):
app_remote_control.c定义了一个完整应用,包含状态机、消息循环、按键分发、BLE 配置与 IR 配置。它不直接操作寄存器,而是通过 SDK 服务模块完成功能。 - HOGP 服务:负责 BLE HID over GATT Profile 的初始化(
hogp_bt_ble_init)与广播(hogp_bt_ble_before_start_init),应用通过ble_hid_data_send()发送报告、le_hogp_*系列接口控制配对与断开。 - IR 编码器:
ir_encoder负责把操作码编码为红外波形,ir_encoder_tx_hx(0, cmd, is_long)是发送入口,ir_encoder_repeat_stop()停止重复发送。 - 电源管理:自动关机定时器到期后投递
POWER_EVENT_POWER_SOFTOFF事件,软关机流程区分SOFT_MODE(不必等待断链)与SOFT_BY_POWER_MODE(必须等待断链)两种低功耗模式。 - LED 控制:按键反馈(
LED_KEY_UP)与开机闪灯(LED_INIT_FLASH)由led_control服务统一调度。
核心实现分析
1. HID 消费类报告映射表
报告描述符定义在 hidrc_report_map 中,仅 35 字节,使用 Consumer 页(0x0C),Report ID 为 1,16 个 1-bit 开关量分别对应音量加/减、播放暂停、静音、上一曲/下一曲、快进/快退:
static const uint8_t hidrc_report_map[] = {
0x05, 0x0C, // Usage Page (Consumer)
0x09, 0x01, // Usage (Consumer Control)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x09, 0xE9, // Usage (Volume Increment)
0x09, 0xEA, // Usage (Volume Decrement)
0x09, 0xCD, // Usage (Play/Pause)
0x09, 0xE2, // Usage (Mute)
0x09, 0xB6, // Usage (Scan Previous Track)
0x09, 0xB5, // Usage (Scan Next Track)
0x09, 0xB3, // Usage (Fast Forward)
0x09, 0xB4, // Usage (Rewind)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x10, // Report Count (16)
0x81, 0x02, // Input (Data,Var,Abs,...)
0xC0, // End Collection
// 35 bytes
};
Source: app_remote_control.c
设计意图:每个消费类按键占用 1 bit,报告长度为 2 字节(16 bit),按键按下时置位对应 bit,松开时清零,通过 ble_hid_data_send(1, &key_msg, 2) 以 Report ID=1 发送。这种"位图"式报告比 8-bit 数组更紧凑,且天然支持多键同时按下(组合键)。
2. 按键码映射表
hidrc_click_table(单击)与 hidrc_hold_table(长按)把 AD 按键的物理序号映射为消费类按键码,下标即键值 key_value:
static const uint16_t hidrc_click_table[10] = {
0, // 0: 无功能
CONSUMER_SCAN_PREV_TRACK, // 1: 上一曲
CONSUMER_MUTE, // 2: 静音
CONSUMER_VOLUME_DEC, // 3: 音量减
CONSUMER_PLAY_PAUSE, // 4: 播放/暂停
CONSUMER_VOLUME_INC, // 5: 音量加
0,
CONSUMER_SCAN_NEXT_TRACK, // 7: 下一曲
0,
0,
};
static const uint16_t hidrc_hold_table[10] = {
0, 0, 0,
CONSUMER_VOLUME_DEC, // 3: 长按连续音量减
0,
CONSUMER_VOLUME_INC, // 5: 长按连续音量加
0, 0, 0, 0,
};
Source: app_remote_control.c
设计意图:将"物理按键"与"功能"解耦——产品改键位时只改表不改逻辑。长按表只对音量键生效(持续发送音量码实现连续调节),其余键长按不重复发送。
3. 红外码表与 BLE/IR 联动策略
hidrc_ir_cmd_tab 是匹配海信电视的红外 cmd 码表,与 click_table 的键位一一对应;IR_POWER_CMD_VALUE (0x0d) 是电源键特殊值:
const uint8_t hidrc_ir_cmd_tab[] = { // 红外cmd码表,匹配海信电视
0x14, // menu
0x16, // up
0,
/* 0x19, // left */
/* 0x18, // right */
0x43, // vol down
0x15, // confirm
0x44, // vol up
0x48, // return
0x17, // down
0x94, // main page
0,
0x0d, // power
};
static void hidrc_ir_key_deal(uint8_t key_value, uint8_t key_type)
{
// ir test
uint8_t cmd = hidrc_ir_cmd_tab[key_value];
if (!cmd) {
return;
}
// use ble control if connected,except power cmd
if (cmd != IR_POWER_CMD_VALUE && ble_hid_is_connected()) {
return;
}
if (key_type == KEY_EVENT_CLICK) {
hidrc_send_ir_key(cmd, 0);
} else if (key_type == KEY_EVENT_HOLD) {
hidrc_send_ir_key(cmd, 1);
} else if (key_type == KEY_EVENT_UP) {
ir_encoder_repeat_stop();
}
}
Source: app_remote_control.c
设计意图:这是典型的"BLE 优先、IR 兜底"策略——BLE 已连接时除电源键外全部走 BLE(IR 码表只用于兼容无 BLE 的老电视),电源键永远走 IR(保证电视可被"物理"关机)。KEY_EVENT_UP 时调用 ir_encoder_repeat_stop() 停止长按导致的重复波形。
4. 按键综合处理与配对/关机快捷操作
hidrc_app_key_deal_test 是按键事件的总入口,按 key_type(单击/长按/抬起/双击/三击)分发:
static void hidrc_app_key_deal_test(uint8_t key_type, uint8_t key_value)
{
uint16_t key_msg = 0;
uint16_t key_msg_up = 0;
#if TCFG_IR_ENABLE
hidrc_ir_key_deal(key_value, key_type);
#endif
#if TCFG_LED_ENABLE
led_operate(LED_KEY_UP);
#endif
if (key_type == KEY_EVENT_CLICK) {
key_msg = hidrc_click_table[key_value];
} else if (key_type == KEY_EVENT_HOLD) {
key_msg = hidrc_hold_table[key_value];
} else if (key_type == KEY_EVENT_UP) {
log_info("key_up_val = %02x\n", key_value);
ble_hid_data_send(1, (uint8_t *)&key_msg_up, 2); // 松开:发送全0报告
return;
}
if (key_msg) {
log_info("key_msg = %02x\n", key_msg);
ble_hid_data_send(1, (uint8_t *)&key_msg, 2); // 按下:发送置位报告
if (KEY_EVENT_HOLD != key_type) {
ble_hid_data_send(1, (uint8_t *)&key_msg_up, 2); // 单击:立即补发松开
}
return;
}
if (key_type == KEY_EVENT_DOUBLE_CLICK && key_value == TCFG_ADKEY_VALUE1) {
if (ble_hid_is_connected()) {
le_hogp_disconnect();
}
le_hogp_set_pair_allow(); // 进入可配对
return;
}
if (key_type == KEY_EVENT_TRIPLE_CLICK
&& (key_value == TCFG_ADKEY_VALUE3 || key_value == TCFG_ADKEY_VALUE0)) {
app_power_event_to_user(POWER_EVENT_POWER_SOFTOFF); // 三击软关机
return;
}
}
Source: app_remote_control.c
关键行为梳理:
- 单击:发送置位报告后立即补发全 0 报告,模拟"按下→松开"的完整键动作,避免主机认为按键被卡住。
- 长按:只发送一次置位报告(不补松开),由主机侧按重复扫描处理连续调节;松开时在
KEY_EVENT_UP分支发送全 0。 - 双击(键值 1):先断开当前 BLE 连接再允许配对——这是重新配对(re-pair)的标准流程。
- 三击(键值 3 或 0):投递
POWER_EVENT_POWER_SOFTOFF软关机事件。
5. 应用启动、BLE 初始化与自动关机
hidrc_app_start() 是应用真正入口:设置系统/低速/SPI Flash 时钟、初始化蓝牙与 IR/LED,注册自动关机定时器,然后进入消息循环:
static void hidrc_app_start()
{
log_info("-------------HID_RC DEMO-----------------");
clk_set("sys", TCFG_CLOCK_SYS_HZ);
clk_set("lsb", TCFG_CLOCK_LSB_HZ);
clk_set("sfc", TCFG_CLOCK_SFC_HZ);
clock_bt_init();
hidrc_app_bt_start();
#if TCFG_LED_ENABLE
led_operate(LED_INIT_FLASH);
#endif
#if TCFG_IR_ENABLE
ir_encoder_init(IR_KEY_IO, IR_WORK_FRQ, IR_WORK_DUTY);
#endif
#if (TCFG_HID_AUTO_SHUTDOWN_TIME)
//无操作定时软关机
hidrc_auto_shutdown_timer = sys_timeout_add((void *)POWER_EVENT_POWER_SOFTOFF,
(void *)app_power_event_to_user,
TCFG_HID_AUTO_SHUTDOWN_TIME * 1000);
#endif
int msg[4] = {0};
while (1) {
get_msg(sizeof(msg) / sizeof(int), msg);
app_comm_process_handler(msg);
}
}
Source: app_remote_control.c
BLE 初始化细节在 hidrc_app_bt_start() 中,其中 hidrc_ble_config 把 HOGP 的初始化/广播/退出钩子与遥控器报告绑定在一起:
static const ble_init_cfg_t hidrc_ble_config = {
.same_address = 0,
.appearance = BLE_APPEARANCE_GENERIC_REMOTE_CONTROL,
.report_map = hidrc_report_map,
.report_map_size = sizeof(hidrc_report_map),
.ble_profile_init = comm_ble_profile_init,
.bt_ble_init = hogp_bt_ble_init,
.bt_ble_before_start_init = hogp_bt_ble_before_start_init,
.bt_ble_exit = hogp_bt_ble_exit,
.ble_module_enable = hogp_ble_module_enable,
};
static void hidrc_app_bt_start()
{
u32 sys_clk = clk_get("sys");
bt_pll_para(TCFG_CLOCK_OSC_HZ, sys_clk, 0, 0);
btstack_ble_start_before_init(&hidrc_ble_config, 0);
le_hogp_set_reconnect_adv_cfg(ADV_DIRECT_IND_LOW, 5000); // 回连广播
le_hogp_set_output_callback(hidrc_recv_callback);
btstack_init();
}
Source: [app_remote_control.c](https://gitee.com/Jieli-Tech/fw-AW33N_BLE_SDK/blob/master/apps/demo/hid/examples/remote_control/app_remote_control.c#L134-L144, L312-L323)
要点:
appearance声明为通用遥控器外观,主机(如电视)据此显示正确的图标与配对界面。le_hogp_set_reconnect_adv_cfg(ADV_DIRECT_IND_LOW, 5000):断链后以定向广播(仅对已配对主机可见)回连,持续 5000 ms。le_hogp_set_output_callback(hidrc_recv_callback):注册下行通道(主机→设备,如电视向遥控器回传数据)回调。- 自动关机定时器使用
sys_timeout_add,回调直接复用app_power_event_to_user,到期即投递软关机事件;hidrc_auto_shutdown_disable()可删除该定时器。
核心流程
按键→发送 完整时序
sequenceDiagram
participant K as "AD按键中断"
participant APP as "hidrc_app_key_deal_test"
participant IR as "ir_encoder"
participant LED as "led_control"
participant HID as "HOGP (ble_hogp)"
participant HOST as "BLE主机(电视/机顶盒)"
K->>APP: 按键事件(key_type, key_value)
APP->>LED: led_operate(LED_KEY_UP)
alt TCFG_IR_ENABLE
APP->>IR: hidrc_ir_key_deal(key_value, key_type)
alt BLE已连接且非电源键
IR-->>APP: 跳过(return)
else BLE未连接或电源键
IR->>IR: ir_encoder_tx_hx(0, cmd, is_long)
end
end
alt KEY_EVENT_CLICK
APP->>HID: ble_hid_data_send(1, &key_msg, 2)
HID->>HOST: 置位报告(bit=1)
APP->>HID: ble_hid_data_send(1, &key_msg_up, 2)
HID->>HOST: 全0报告(bit=0)
else KEY_EVENT_HOLD
APP->>HID: ble_hid_data_send(1, &key_msg, 2)
HID->>HOST: 置位报告(持续)
else KEY_EVENT_UP
APP->>HID: ble_hid_data_send(1, &key_msg_up, 2)
HID->>HOST: 全0报告(bit=0)
end
流程要点:按键事件先并行触发 LED 反馈与 IR 处理(IR 受"BLE 已连接且非电源键则跳过"约束),随后按事件类型决定 HID 报告的发送组合。单击必须补发全 0 报告,这是 HID 消费类按键的"瞬时触发"语义,否则主机认为按键被持续按住。
应用状态机与蓝牙事件流
flowchart TD
subgraph sg_APP_LIFE["应用生命周期 (hidrc_state_machine)"]
CREATE["APP_STA_CREATE"]
START["APP_STA_START<br/>ACTION_REMOTE_CONTROL → hidrc_app_start"]
RUN["消息循环 get_msg + app_comm_process_handler"]
PAUSE["APP_STA_PAUSE"]
RESUME["APP_STA_RESUME"]
STOP["APP_STA_STOP"]
DESTROY["APP_STA_DESTROY"]
end
subgraph sg_BT_EVT["蓝牙事件"]
INIT_OK["BT_STATUS_INIT_OK"]
CONN["连接/断开事件"]
end
CREATE --> START --> RUN
RUN --> PAUSE --> RESUME --> RUN
RUN --> STOP --> DESTROY
INIT_OK -->|"btstack_ble_start_after_init"| RUN
CONN -->|"bt_comm_ble_status_event_handler"| RUN
蓝牙事件处理拆分为两个回调:hidrc_bt_hci_event_handler(HCI 层事件,统一转交 bt_comm_ble_hci_event_handler)与 hidrc_bt_connction_status_event_handler(连接状态事件,BT_STATUS_INIT_OK 时调用 btstack_ble_start_after_init(0) 真正开始广播,其余转交公共处理):
static int hidrc_bt_connction_status_event_handler(struct bt_event *bt)
{
log_info("----%s %d", __FUNCTION__, bt->event);
switch (bt->event) {
case BT_STATUS_INIT_OK:
// 蓝牙初始化完成
log_info("BT_STATUS_INIT_OK\n");
btstack_ble_start_after_init(0);
break;
default:
bt_comm_ble_status_event_handler(bt);
break;
}
return 0;
}
Source: app_remote_control.c
设计意图:BLE 初始化分为"开始前(配置)→ 开始后(广播)"两个阶段,中间由 BT_STATUS_INIT_OK 事件同步——这保证了协议栈完全就绪后才进入可发现/可连接状态,避免竞态。hidrc_state_machine 中 APP_STA_START 只在 it->action == ACTION_REMOTE_CONTROL 时启动应用,说明该 Demo 由外部 action 触发,可被框架按需拉起。
软关机时序
sequenceDiagram
participant T as "sys_timer"
participant PWR as "app_power_mg"
participant APP as "hidrc_set_soft_poweroff"
participant BT as "btstack"
participant HOST as "BLE主机"
T->>PWR: 定时到期 → POWER_EVENT_POWER_SOFTOFF
PWR->>APP: app_power_set_soft_poweroff 流程
APP->>BT: btstack_ble_exit(0)
alt 已连接
alt SOFT_MODE
APP->>PWR: 延时 WAIT_DISCONN_TIME_MS 后软关机(不等断链)
else SOFT_BY_POWER_MODE
APP->>PWR: app_power_soft.wait_disconn = 1 (必须等断链)
HOST-->>BT: 断开连接
BT-->>PWR: 断链完成 → 执行软关机
end
else 未连接
APP->>PWR: 立即软关机
end
hidrc_set_soft_poweroff() 是低功耗设计的核心:软关机前先 btstack_ble_exit(0) 关闭协议栈;已连接时按低功耗模式决定"等不等断链"——SOFT_MODE 下用 sys_timeout_add 延时 WAIT_DISCONN_TIME_MS 后直接关机(省电优先),SOFT_BY_POWER_MODE 下置 wait_disconn = 1 由电源模块等待链路断开(可靠性优先)。
板级配置
遥控器示例对应板级目录 apps/demo/hid/board/bd57/,其中 board_aw33n_rc_cfg.h(宏开关)与 board_aw33n_rc_global_build_cfg.h(构建/Flash 布局)配套使用,宏开关包括:
| 宏 | 说明 |
|---|---|
TCFG_IR_ENABLE | 使能红外发射(配套 IR_KEY_IO、IR_WORK_FRQ、IR_WORK_DUTY 配置) |
TCFG_LED_ENABLE | 使能 LED 反馈(LED_KEY_UP、LED_INIT_FLASH) |
TCFG_HID_AUTO_SHUTDOWN_TIME | 无操作自动软关机秒数,0 表示关闭 |
TCFG_ADKEY_VALUE0/1/3 | AD 按键对应的键值,用于双击配对、三击关机判断 |
TCFG_LOWPOWER_PATTERN | 低功耗模式(SOFT_MODE / SOFT_BY_POWER_MODE) |
构建配置(board_aw33n_rc_global_build_cfg.h)中针对遥控器产品形态的关键取舍:
#define CONFIG_DOUBLE_BANK_ENABLE 0 // 单备份结构(无第三方OTA双备份需求)
#define CONFIG_FLASH_SIZE FLASH_SIZE_256K
#define CONFIG_VM_LEAST_SIZE 0x2000 // VM区最小尺寸
#define CONFIG_BTIF_LEN 0x1000
#define UPDATE_V2_EN 1 // 升级功能使能
#define TESTBOX_BT_UPDATE_EN 1 // 测试盒升级
#define CONFIG_APP_OTA_EN 0 // 不使能 RCSP(JL-OTA) 升级
#define HAS_USB_EN 0
#define HAS_NORFS_EN 0
设计意图:遥控器 Flash 通常较小(256K),且无需 USB 与 NORFS;保留测试盒 BT 升级通道便于产线烧录与售后维护,关闭 RCSP OTA 以精简代码体积。若需接入第三方 OTA 协议,需同时打开 CONFIG_DOUBLE_BANK_ENABLE 并按实际 Flash 大小配置 CONFIG_FLASH_SIZE。
API 参考
以下为本示例直接调用的 SDK 接口(签名取自实际调用点,完整声明见对应 SDK 头文件)。
ble_hid_data_send(report_id, data, len)
发送 HID 输入报告(设备→主机方向)。
参数:
report_id(uint8_t):报告 ID,示例固定传1,对应报告描述符中Report ID (1)。data(uint8_t *):报告数据指针,2 字节消费类位图。len(uint16_t):数据长度,示例传2。
说明: 按下时传置位值(如 CONSUMER_VOLUME_INC = 0x0001),松开时传 0。
ble_hid_is_connected()
返回当前 BLE HID 链路是否已连接,供 IR 联动策略判断(连接时除电源键外跳过 IR)。
le_hogp_disconnect() / le_hogp_set_pair_allow()
le_hogp_disconnect():主动断开当前 HOGP 连接。le_hogp_set_pair_allow():设置设备允许配对(进入可配对状态)。- 组合用法:双击键值 1 时先断开再允许配对,实现重新配对。
le_hogp_set_reconnect_adv_cfg(type, timeout_ms)
配置断链回连广播参数。示例:le_hogp_set_reconnect_adv_cfg(ADV_DIRECT_IND_LOW, 5000) —— 使用低占空比定向广播,持续 5000 ms。
le_hogp_set_output_callback(cb)
注册下行通道回调(主机→设备数据),示例回调 hidrc_recv_callback 仅打印收到的数据(ble_hid_data_receive:size=%d + put_buf)。
btstack_ble_start_before_init(cfg, flag) / btstack_ble_start_after_init(flag) / btstack_ble_exit(flag)
btstack_ble_start_before_init:加载 BLE 配置(ble_init_cfg_t,含外观、报告映射、HOGP 钩子)并完成初始化前准备。btstack_ble_start_after_init:在BT_STATUS_INIT_OK事件后调用,真正启动广播/扫描。btstack_ble_exit(0):关闭 BLE 协议栈(软关机前调用)。
ir_encoder_init(io, freq, duty) / ir_encoder_tx_hx(ch, cmd, is_long) / ir_encoder_repeat_stop()
ir_encoder_init:初始化红外发射 IO、载波频率与占空比(示例:IR_KEY_IO、IR_WORK_FRQ、IR_WORK_DUTY)。ir_encoder_tx_hx(0, cmd, is_long):发送 HX 编码红外码,cmd为操作码,is_long为是否持续发送(长按重复)。ir_encoder_repeat_stop():停止长按重复发送(KEY_EVENT_UP时调用)。
sys_timeout_add(arg, func, msec) / sys_timeout_del(timer_id)
- 添加系统软定时器:
sys_timeout_add((void *)POWER_EVENT_POWER_SOFTOFF, (void *)app_power_event_to_user, ms)实现自动关机;sys_timeout_del(hidrc_auto_shutdown_timer)取消。
app_power_event_to_user(POWER_EVENT_POWER_SOFTOFF) / app_power_set_soft_poweroff(NULL)
投递软关机事件 / 直接请求软关机。示例在未连接时直接调用后者,已连接时按低功耗模式走延时或等断链路径。
led_operate(LED_KEY_UP | LED_INIT_FLASH)
LED 控制接口,按键反馈与开机闪灯。
app_comm_process_handler(msg) / get_msg(count, msg)
消息循环:get_msg 阻塞获取消息,app_comm_process_handler 分发处理(按键、蓝牙等事件均由框架投递到该循环)。
故障模式、边界情况与并发
按键事件与 HID 发送的竞态
ble_hid_data_send 与 ir_encoder_tx_hx 在按键回调上下文中同步调用,不涉及跨任务共享状态;但单击补发全 0 报告依赖主机在收到置位报告后及时处理——若两次发送间隔过近(< 连接间隔),主机可能合并为单次报告导致按键丢失。量产时若出现丢键,需按连接参数(connection interval)调整补发节奏或使用重复发送。
长按报告缺失的边界
hidrc_hold_table 中值为 0 的键(如上一曲/下一曲)在长按时 key_msg = 0,此时既不发 HID 报告,也不会进入双击/三击分支——即长按无功能键被静默忽略,属预期行为。但若误将需要长按的键配为 0,排查时需先确认两张表。
IR 与 BLE 同时按下
IR 键处理先于 BLE 发送执行;当 BLE 已连接且按键非电源键时 IR 被跳过,因此同一按键只会走一个通道,不会双发。电源键例外(始终 IR),保证电视可被强制关机。
软关机与断链的时序依赖
SOFT_MODE 下软关机不等待链路断开(延时 WAIT_DISCONN_TIME_MS 后直接关),若此时主机仍在收发数据,可能出现收尾数据丢失;SOFT_BY_POWER_MODE 通过 wait_disconn = 1 强制等断链,更可靠但关机延迟更长。两者取舍取决于产品对"关机延迟 vs 数据完整性"的偏好。
自动关机定时器与手动关机的交互
三击软关机(POWER_EVENT_POWER_SOFTOFF)与自动关机定时器共用同一事件,若两者同时触发(如定时器到期瞬间用户三击),hidrc_set_soft_poweroff 会执行两次——由于 btstack_ble_exit 幂等且软关机状态机可重入,通常无害;但如需严格单次,应在 hidrc_auto_shutdown_disable() 中统一取消定时器。
配对失败/回连超时
回连广播使用 ADV_DIRECT_IND_LOW 持续 5000 ms,若主机不在范围内则超时静默。设备保持可发现状态由框架层管理;用户可通过双击键值 1 强制重新进入可配对状态。
性能与运维考量
- 时钟配置前置:
hidrc_app_start在初始化蓝牙前显式设置sys/lsb/sfc时钟(clk_set),并调用clock_bt_init()与bt_pll_para(TCFG_CLOCK_OSC_HZ, sys_clk, 0, 0)配置 PLL。若系统时钟与晶振参数不匹配,BLE 射频将无法通过认证,这是联调时最先应检查的项。 - 报告体积极小:HID 报告仅 2 字节,每次按键产生 ≤2 个通知,BLE 带宽占用可忽略;功耗主要由广播占空比(
ADV_DIRECT_IND_LOW)与连接间隔决定。 - 低功耗关键点:
hidrc_is_active标志在SOFT_MODE下置 1,标识"软关机临界点"(禁止系统进入低功耗)——软关机流程完成前系统不允许休眠,避免在蓝牙未完全关闭时掉入深睡。 - 日志开关:模块使用
LOG_TAG "[HID_RC]",默认开启 ERROR/DEBUG/INFO/CLI;量产可关闭LOG_DEBUG_ENABLE/LOG_INFO_ENABLE减小代码与运行开销。 - 产线升级:
TESTBOX_BT_UPDATE_EN = 1使能测试盒 BT 升级,TCFG_UART_UPDATE_PORT = IO_PORTA_00需与isd_config.ini的UTRX匹配;串口升级默认关闭。
扩展点
1. 增加按键功能
修改 hidrc_click_table/hidrc_hold_table(长度需覆盖键值上限),并同步扩展 hidrc_report_map 中的 Usage 与 Report Count。例如增加"语音助手"键:在报告映射中追加 0x09, 0x01, // Usage (Voice Command) 并增大 0x95 的 count,再在表中加入对应消费类码。
2. 更换红外协议/电视品牌
替换 hidrc_ir_cmd_tab 的 cmd 码表(当前匹配海信电视),或改写 hidrc_send_ir_key 使用其它 ir_encoder_* 发送接口(NEC/HX 等编码由 ir_encoder 模块支持情况决定)。IR_POWER_CMD_VALUE 常量用于识别电源键,换码表时需同步更新。
3. 适配不同按键矩阵
按键事件由框架按 TCFG_ADKEY_VALUEx 上报;本示例以固定键值表索引取码。若改用矩阵扫描(GPIO 行列),只需替换按键事件来源,hidrc_app_key_deal_test 的映射逻辑可复用。
4. 定制软关机策略
hidrc_set_soft_poweroff 中的 SOFT_MODE / SOFT_BY_POWER_MODE 分支是低功耗策略扩展点:可在 wait_disconn = 1 路径中追加"保存用户配置到 VM"或"上报关机状态给主机"等收尾动作。
5. 下行数据响应
le_hogp_set_output_callback(hidrc_recv_callback) 目前只打印数据;如需响应主机下发的指令(如电视回传频道信息、固件升级数据),在此回调内扩展协议解析即可。
测试与验证建议
SDK 中未提供该示例的独立单元测试文件(HID 应用依赖硬件外设与协议栈,通常以整机联调为主)。建议的验证矩阵:
| 验证项 | 方法 | 预期 |
|---|---|---|
| 按键上报 | 连接手机/PC BLE 调试工具查看 HID 报告 | 单击出现置位+清零两帧,长按仅置位帧 |
| IR 兜底 | 断开 BLE 后按键对准海信电视 | 电视响应且无 BLE 帧发出 |
| 电源键 | BLE 连接状态下按电源键 | 电视关机(IR 通道) |
| 自动关机 | 设置 TCFG_HID_AUTO_SHUTDOWN_TIME 后静置 | 定时器到期软关机,日志打印 hidrc_set_soft_poweroff |
| 重新配对 | 双击键值 1 | 断开旧连接并进入可配对广播 |
| 回连 | 断开后 5 s 内靠近主机 | 定向广播回连成功 |
相关链接
- app_remote_control.c(本示例完整源码)
- board_aw33n_rc_global_build_cfg.h(遥控器板级构建配置)
- board_aw33n_rc_cfg.h(遥控器板级宏开关)
- board_aw33n_rc.c(遥控器板级驱动)
- app_main.c(HID 应用入口)
- 相关模块文档:BLE HOGP(
ble_hogp)、红外编码器(ir_encoder)、LED 控制(led_control)、电源管理(app_power_mg) - 同目录其他 HID 示例:鼠标示例、键盘示例