欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Z-Stack 学习 -- 调用自定义事件

程序员文章站 2022-03-07 09:34:25
...

    总结一下调用事件的流程,做一个调用事件的实验。

一、调用事件流程

     上篇我们说了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. 编译下载,用串口调试助手查看

                                                                   Z-Stack 学习 -- 调用自定义事件

     可知,系统初始化后启动定时器,3秒后触发 zclSampleTemperatureSensor_TaskID 任务的 ZQW_UART_PRINTF 事件,然后由于osal_start_timerEx() 函数为 events 赋值,OSAL 跳出循环,开始处理事件。

相关标签: 协议栈