HID 私有协议
本示例用两个工程分别扮演HID 私有协议用户指南中的master和slave两个角色,他们之间可以互相发送消息,演示该协议的基本使用方法:
Master首次使用或者按键触发时自动配对,Slave首次使用或者上电时自动配对。
Master和Slave自动回连。
Master自动按照上报率上报数据,按键切换上报率、开关上报。
Slave按键下发指令。
连线、数据发送的led指示。
环境需求
该示例支持以下开发工具包:
Hardware Platforms |
Board Name |
---|---|
RTL87x2G HDK |
RTL87x2G EVB |
更多要求,请参考 快速入门。
硬件连线
示例会用到3个LED显示相关状态,参考下表:
类型 |
说明 |
led名 |
pin |
---|---|---|---|
link status |
连接点亮/断线熄灭 |
LED4 |
P3_0 |
data transmit |
master向slave方向的数据传输每1000笔翻转一次 |
LED3 |
P3_1 |
slave cmd |
slave的slave cmd按键按下翻转一次 |
LED2 |
P1_0 |
master示例会用到3个按键,参考下表:
类型 |
说明 |
按键名 |
pin |
---|---|---|---|
pair |
触发配对 |
KEY5 |
P1_2 |
switch report rate |
切换上报率 |
KEY4 |
P0_6 |
switch report |
开关上报 |
KEY3 |
P0_2 |
slave示例会用到1个按键,参考下表:
类型 |
说明 |
按键名 |
pin |
---|---|---|---|
slave cmd |
翻转master和slave的LED |
KEY5 |
P1_2 |
配置选项
APP_MSG_COUNT_BLINK_TH
修改master向slave方向的数据传输时的LED闪烁频率。APP_PAIR_TIME
修改master按键配对时间和slave上电配对时间。编译和下载
该示例可以在SDK文件夹中找到:
Project file:
samples\ppt\ppt_sync\proj_master\rtl87x2g\mdk
samples\ppt\ppt_sync\proj_slave\rtl87x2g\mdk
Project file:
samples\ppt\ppt_sync\proj_master\rtl87x2g\gcc
samples\ppt\ppt_sync\proj_slave\rtl87x2g\gcc
编译和运行该示例请遵循以下步骤:
打开项目文件。
要编译目标文件, 请参考 快速入门 中 编译APP Image 中列出的步骤。
编译成功后,项目文件所在目录的子目录
bin
下会生成app bin文件app_MP_sdk_xxx.bin
。在EVB板上按下reset按钮,程序将开始运行。
测试验证
将两个示例工程分别烧录到两个EVB板后,用按键控制,然后使用 Debug Analyzer
工具获取日志、观察LED状态,查看运行结果。
测试阶段
首次使用此示例时,没有绑定信息,按下reset按钮后,两端都会自动进入配对状态,打印下面的日志。
[APP] !**app_sync_start: pair
配对成功后会打印下面的日志,并且点亮link status led。
[APP] !**app_sync_event_cb: paired
Master连上之后默认会打开数据上报,此时master和slave会以相同的频率闪烁data transmit led。 按下master的switch report rate按键,切换master上报率,会看到master和slave的data transmit led闪烁频率改变。 上报率切换顺序为125, 250, 500, 1000, 2000, 4000的循环,默认1000。 led在默认闪烁频率下,1K时1s翻转一次,4K时0.25s翻转一次,125时8s翻转一次,其他依次类推。
按下master的switch report按键一次,开关master数据上报。当上报关闭时,master和slave的data transmit led停止闪烁。
按下slave的slave cmd按键一次,master和slave的slave cmd led同时翻转。
按下master的pair按键一次,master会重新进入配对模式。重启slave,slave也会重新进入配对模式。重新配对成功后,会打印下面的日志,并且点亮link status led。
[APP] !**app_sync_event_cb: paired
代码介绍
本章的主要目的是帮助APP开发人员熟悉相关的开发流程。本章将按照以下几个部分进行介绍:
源码路径
Project directory:
samples\ppt\ppt_sync\proj_xxx
Source code directory:
samples\ppt\ppt_sync\src
应用程序项目中的源文件当前被分为几个组,如下所示。
└── Project: master(slave)
└── secure_only_app
├── Device includes startup code
├── CMSE Library Non-secure callable lib
├── Lib includes all binary symbol files that user application is built on
├── ROM_NS.lib
├── lowerstack.lib
├── rtl87x2g_sdk.lib
├── rtl87x2g_io.lib
└── ppt_sync_master(slave).lib includes the sync protocol stack lib
├── Peripheral includes all peripheral drivers and module code used by the application
└── APP includes the ble_peripheral user application implementation
├── main_ns.c includes the io, os and platform initialization
├── app_task.c includes app task initialization and main loop
├── app_bsp.c includes the button, led and timer etc. functions
└── app_sync_master(slave).c includes sync protocol state machine management and button/led handle
初始化
当EVB板启动并且芯片被重置时,main函数将被调用,它执行以下初始化函数:
int main(void)
{
/* increase cpu clock to support 4k report rate */
uint32_t actual_mhz = 0;
pm_cpu_freq_set(125, &actual_mhz);
DBG_DIRECT("Non-Secure World: main, clock %dMHz", actual_mhz);
app_task_init();
/* Start scheduler. */
os_sched_start();
/* Should not reach here as the scheduler is already started. */
for (; ;)
{
}
}
pm_cpu_freq_set()
用于提升CPU频率,让4K高上报率时来得及处理。app_task_init()
用于初始化app task,注册task主函数app_main_task()
。os_sched_start()
用于启动os scheduler。当调度器启动后,app task的主函数app_main_task()
会得到调度。app_main_task()
执行sync protocol和相关内容的初始化。
void app_main_task(void *p_param)
{
/* This task calls secure side functions. So allocate a secure context for
* it. */
//must locate at the first line
os_alloc_secure_ctx(configMINIMAL_SECURE_STACK_SIZE);
/* avoid ppt initialization conflict with ble psd procedure */
os_delay(1000);
/* init the basic peripheral */
swd_pin_disable(); // On EVB, led pin reuse the swd pin, so need disable the swd
led_init();
app_hw_timer_init();
/* init sync protocol */
app_sync_init();
app_sync_start();
/* init button after app_sync_start since button may trigger interrupt to change the FSM */
btn_init(app_handle_btn);
#if DLPS_EN
/* call pwr_mgr_init last to make sure sync_dlps_init (app_sync_init) execute before DLPS_IORegister (pwr_mgr_init) */
void pwr_mgr_init(void);
pwr_mgr_init();
#endif
while (1)
{
/* nothing to do */
os_delay(1000000);
}
}
注意
io、sync protocol和平台power manager的初始化有一些依赖关系,注意先后顺序。
app_sync_init()
会按角色初始化协议,并注册各类回调:
事件回调
app_sync_event_cb()
接收回调
app_sync_receive_msg_cb()
心跳回调
app_sync_hb_cb()
而在sync_msg_send()
时都会注册消息发送回调app_sync_send_msg_cb()
。
状态机和事件处理
状态机运转的主要函数是app_sync_start()
,它会根据绑定信息和按键(上电状态)等信息决定是执行配对还是连接。
当配对和连接触发后,会产生各类事件,在app_sync_event_cb()
处理。例如配对失败事件,会重新执行app_sync_start()
。
另外按键也会产生事件,app_handle_btn()
根据按键类型执行不同的动作,例如执行重新配对、发送数据等。
当master停止数据上报时,会进入heartbeat低功耗状态,这时会执行心跳回调app_sync_hb_cb()
,通知心跳状态的进出。
数据收发
master和slave之间会相互发送数据。master打开上报时,会按照上报率定时持续发送消息,双方分别会根据发送和接收的消息数量来闪烁led。 slave只有按键按下时,才会发送控制led的消息。
定义格式如下,用户可以根据实际需要修改和扩充。
master上报函数为app_report_data()
,数据格式如下:
/* Data send from master to slave */
typedef struct
{
uint8_t opcode;
uint32_t pkt_id;
uint8_t data[0];
} __attribute__((packed)) app_master_pdu_t;
slave下发的控制双方led状态函数为app_send_cmd()
,数据格式如下:
/* Data send from slave to master */
typedef struct
{
uint8_t opcode;
bool state;
} __attribute__((packed)) app_slave_pdu_t;