Z-Stack 学习 -- 调用自定义事件
总结一下调用事件的流程,做一个调用事件的实验。
一、调用事件流程
上篇我们说了Z-Stack处理事件的流程,这个流程可以总结成以下几步:
1. 在操作系统运行的函数中,下列程序对编号为 idx 的任务的 events 事件进行处理
activeTaskID = idx;
events = (tasksArr[idx])( idx, events );
activeTaskID = TASK_NO_TASK;
2. 进入 tasksArr[idx] 数组,将第 idx 个元素作为需要调用的事件处理函数:
const pTaskEventHandlerFn tasksArr[] = {
macEventLoop,
nwk_event_loop,
Hal_ProcessEvent,
#if defined( MT_TASK )
MT_ProcessEvent,
#endif
APS_event_loop,
#if defined ( ZIGBEE_FRAGMENTATION )
APSF_ProcessEvent,
#endif
ZDApp_event_loop,
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
ZDNwkMgr_event_loop,
#endif
zcl_event_loop,
zclSampleTemperatureSensor_event_loop
};
3. 以用户自定义的一个函数为例(上段程序的最后一各函数),进入 uint16 zclSampleTemperatureSensor_event_loop( uint8 task_id, uint16 events ) 函数,可以看到函数的两个输入量就是任务号和需处理的事件events。
uint16 zclSampleTemperatureSensor_event_loop( uint8 task_id, uint16 events )
{
afIncomingMSGPacket_t *MSGpkt;
(void)task_id; // Intentionally unreferenced parameter
if ( events & SYS_EVENT_MSG )
{
while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( zclSampleTemperatureSensor_TaskID )) )
{
switch ( MSGpkt->hdr.event )
{
case KEY_CHANGE:
zclSampleTemperatureSensor_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
break;
从这段程序中可以看到事件处理函数首先定义了一个结构体指针,然后有一句 if ( events & SYS_EVENT_MSG ) 这是因为我们使用的 osal_msg_send() 函数会触发 SYS_EVENT_MSG 这个事件。
之后程序调用 osal_msg_receive( zclSampleTemperatureSensor_TaskID ) 并将它转化为一个 afIncomingMSGPacket_t 型的指针,判断接收到的信息中需要处理的事件,这个信息在afIncomingMSGPacket_t 结构体的 hdr 中,hdr也是一个结构体,hdr中的 events 存储了需要处理的事件 events 。
二、 调用自定义事件实验
我们在事件处理函数的初始化中加入一个调用的定时器,然后在相应的事件中再次用定时器调用自身就可以完成一个事件的反复调用。
1. 首先我们需要定义一个自定义的事件,上篇说过 Z-Stack 中的事件数组 tasksEvents[idx] 中的元素都是16位的,最高位定义为系统事件,其余的可以自定义。我们以TI的官方例程 SampleTemperatureSensor 为例。
// Application Events
#define SAMPLETEMPERATURESENSOR_IDENTIFY_TIMEOUT_EVT 0x0001
#define SAMPLETEMPERATURESENSOR_EZMODE_TIMEOUT_EVT 0x0002
#define SAMPLETEMPERATURESENSOR_EZMODE_NEXTSTATE_EVT 0x0004
#define SAMPLETEMPERATURESENSOR_MAIN_SCREEN_EVT 0x0008
#define SAMPLETEMPERATURESENSOR_TEMP_SEND_EVT 0x0010
#define ZQW_UART_PRINTF 0x0020
在协议栈的Sampletemperaturesor.h文件中定义一个事件 #define ZQW_UART_PRINTF 0x0020 (如上段程序所示)。也就是说将 ZQW_UART_PRINTF 这个事件定义成0x0020。然后我们在事件处理函数的初始化函数中加入一个启动项。
2. 在初始化中加入一段程序。
void zclSampleTemperatureSensor_Init( byte task_id )//这里分配的任务号为 8,所以task_id=8
{
// 省略
osal_start_timerEx(zclSampleTemperatureSensor_TaskID,ZQW_UART_PRINTF,3*SAMPLETEMPERATURESENSOR_REPORT_INTERVAL );
OLED_P8x16Str(0,6,(unsigned char *)sClrLine);
OLED_P8x16Str(0,6,(unsigned char *)sDeviceName);
// 省略
}
osal_start_timerEx(zclSampleTemperatureSensor_TaskID,ZQW_UART_PRINTF,3*SAMPLETEMPERATURESENSOR_REPORT_INTERVAL ),一共有三个参数目标任务ID(zclSampleTemperatureSensor_TaskID 是在任务初始化的时候用传入的参数赋值),事件号为 ZQW_UART_PRINTF ,最后一个是以毫秒为单位的延时。
3. 在事件处理函数的 events 的判断上加入以下语句;
if ( events & ZQW_UART_PRINTF )
{
osal_start_timerEx( zclSampleTemperatureSensor_TaskID, ZQW_UART_PRINTF, SAMPLETEMPERATURESENSOR_REPORT_INTERVAL );
HalUARTWrite(0, "555\n" ,5); //提示收到数据
return ( events ^ ZQW_UART_PRINTF );
}
4. 编译下载,用串口调试助手查看
可知,系统初始化后启动定时器,3秒后触发 zclSampleTemperatureSensor_TaskID 任务的 ZQW_UART_PRINTF 事件,然后由于osal_start_timerEx() 函数为 events 赋值,OSAL 跳出循环,开始处理事件。
下一篇: iOS 面试题
推荐阅读
-
C#中在多个地方调用同一个触发器从而触发同一个自定义委托的事件
-
微信小程序页面调用自定义组件内的事件详解
-
C#中在多个地方调用同一个触发器从而触发同一个自定义委托的事件
-
学习记录:python 调用模块,自定义模块,跨目录调用文件
-
微信小程序页面调用自定义组件内的事件详解
-
VUE的事件绑定修饰符练习及vue列表渲染及条件渲染练习,vue键盘事件+数组方式参数的传递学习及vue的计算属性访问器属性及侦听属性练习以及vue注册组件自定义标签及子组件向父组件传参及父组件向父组件传参
-
学习mysql事件如何调用存储过程的方法
-
VUE的事件绑定修饰符练习及vue列表渲染及条件渲染练习,vue键盘事件+数组方式参数的传递学习及vue的计算属性访问器属性及侦听属性练习以及vue注册组件自定义标签及子组件向父组件传参及父组件向父组件传参
-
学习mysql事件如何调用存储过程的方法
-
Z-Stack 学习 -- 调用自定义事件