事件捕捉流程

       事件是如何被捕获的?直观一些来说就是,tasksEvents这个数组里的元素是什么时候被设定为非零数,来表示有事件需要处理的?为了详细的说明这个过程,我将以GenericApp这个例程中响应按键的过程来进行说明。其他的事件虽然稍有差别,却是大同小异。


  按键属于硬件资源,OSAL提供使用和管理这些硬件的服务。tasksArr这样一个数组,它保存了所有任务的事件处理函数。我们从中发现了一个很重要的信息:Hal_ProcessEventHALHardware Abstraction Layer)翻译为硬件抽象层。许多人在这里经常把将Z-Stack的硬件抽象层与ZigBee的物理层混为一谈。在这里,我们应该将Z-Stack的硬件抽象层与ZigBee的物理层区分开来。硬件抽象层所包含的范围是我们当前硬件电路上面所有对于系统可用的设备资源。而ZigBee中的物理层则是针对无线通信而言,它所包含的仅限于支持无线通讯的硬件设备。
  

从main()函数开始运行,InitBoard()调用函数HalKeyConfig()

 HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE, OnBoard_KeyCallback(回调函数));判断用中断方式还是查询方式,使用查询方式时,调用osal_set_event(Hal_TaskID, HAL_KEY_EVENT);发送一个HAL_KEY_EVEN事件

将事件HAL_KEY_EVENT交给任务Hal_TaskID处理,即taskEvents中的与Hal_TaskID相对的元素就被置为了非0,从而调用了

uint16 Hal_ProcessEvent( uint8 task_id, uint16 events )

        通过这个Hal_ProcessEvent重要的信息,可以得出这样一个结论:OSAL将硬件的管理也作为一个任务来处理。那么我们很自然的去寻找Hal_ProcessEvent这个事件处理函数,看看它究竟是如何管理硬件资源的。
  在“HAL\Commen\ hal_drivers.c”这个文件中,直接分析与按键有关的一部分。
  {
        if (events & HAL_KEY_EVENT)
        {
                #if (defined HAL_KEY) && (HAL_KEY == TRUE)
                /* Check for keys */
                HalKeyPoll();
                /* if interrupt disabled, do next polling */
                if (!Hal_KeyIntEnable)
                {
                        osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);
                }
                #endif // HAL_KEY
                return events ^ HAL_KEY_EVENT;
        }
  }
  在事件处理函数接收到HAL_KEY_EVENT这样一个事件后,首先执行HalKeyPoll()函数。由于这个例程的按键采用查询的方法获取,所以是禁止中断的,于是表达式(!Hal_KeyIntEnable)的值为真。那么osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100)得以执行。osal_start_timerEx这是一个很常用的函数,它在这里的功能是经过100毫秒后,向Hal_TaskID这个ID所标示的任务(也就是其本身)发送一个HAL_KEY_EVENT事件。这样以来,每经过100毫秒,Hal_ProcessEvent这个事件处理函数都会至少执行一次来处理HAL_KEY_EVENT事件。也就是说每隔100毫秒都会执行HalKeyPoll()函数。
  那么我们来看看HalKeyPoll函数:
  代码中给的注释为:
  /* Check for keys */
  HalKeyPoll();
  这个函数的作用是检查当前的按键情况。在接近函数末尾的地方, keys变量(在函数起始位置定义的)获得了当前按键的状态。最后,有一个十分重要的函数调用。
  (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
  pHalKeyProcessFunction这个函数指针指向了哪个函数我们现在依然不清楚,但是为了我们有个清晰而不间断的思路,我在这里先告诉大家。在这里调用的是
  void OnBoard_KeyCallback ( uint8 keys, uint8 state )

  此函数在“ZMain\OnBoard .c

文件中可以找到。

在这个函数中,又调用了
  void OnBoard_SendKeys ( )构造信息包,



  在这个函数中,按键的状态信息被封装到了一个消息结构体中(对于消息,我们稍后再说)。最后有一个极其重要的函数被调用了。
  osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );
  与前面的pHalKeyProcessFunction相同,我先直接告诉大家registeredKeysTaskID所指示的任务正我们需要响应按键的GenericApp这个任务。
  那么也就是说,在这里我们向任务GenericApp发送了一个附带按键信息的消息。在osal_msg_send函数中
  osal_set_event( destination_task, SYS_EVENT_MSG );
  被调用,它在这里的作用是设destination_task这个任务的事件为SYS_EVENT_MSG而这个destination_task正式由osal_msg_send这个函数通过参数传递而来的,它也指示的是GenericApp这个任务。在osal_set_event这个函数中,有这样一个语句:
  {
        tasksEvents[task_id] |= event_flag;
  }
  
  首先,OSAL专门建立了一个任务来对硬件资源进行管理,这个任务的事件处理函数是Hal_ProcessEvent。在这个函数中通过调用osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);这个函数使得每隔100毫秒就会执行一次HalKeyPoll()函数。HalKeyPoll()获取当前按键的状态,并且通过调用OnBoard_KeyCallback函数向GenericApp任务发送一个按键消息,并且设置tasksEventsGenericApp所对应的值为非零。如此,当main函数里这样一段代码
  {
        do
        {
                if (tasksEvents[idx])
                {
                        break;
                }
        } while (++idx < tasksCnt);
  }
  执行了以后,GenericApp这个任务就会被挑选出来。然后通过
  events = (tasksArr[idx])( idx, events )
  这个函数调用其事件处理函数,完成事件的响应。

现在,我们回过头来处理我们之前遗留下来的问题。
  第一、pHalKeyProcessFunction这个函数指针为何指向了OnBoard_KeyCallback函数。
  在HAL\Commen\ hal_drivers.c这个文件中,我们找到了HalDriverInit这个函数,在这个函数中,按键的初始化函数HalKeyInit被调用。在HalKeyInit中有这样的语句:
  {
        pHalKeyProcessFunction  = NULL;
  }
  这说明在初始化以后pHalKeyProcessFunction并没有指向任何一个函数。那pHalKeyProcessFunction是什么时候被赋值的呢?
  就在HalKeyInit的下方有一个这样的函数HalKeyConfig。其中有这样一条语句:
  pHalKeyProcessFunction = cback
  cbackHalKeyConfig所传进来的参数,所以,想要知道它所指向的函数,必须找到其调用的地方。经过简单的搜索我们不难找出答案。在main函数中有这样一个函数调用:InitBoard( OB_READY );此函数中做了如下调用:
  {
        HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);
  }
  第二registeredKeysTaskID为什么标识了GenericApp这个任务?
  由于OSAL是一个支持多任务的调度机制,所以在同一时间内将会有多个任务同时运行。但是从逻辑上来讲,一个事件只能由一个任务来处理。按键事件也不例外。
  那么如何向OSAL声明处理按键事件的任务是GenericApp呢?
  在GenericApp_InitGenericApp的任务初始化函数)中有这么一个语句:
  {
        RegisterForKeys( GenericApp_TaskID );
  }
  RegisterForKeys函数向OSAL声明按键事件将由GenericApp任务来处理。在RegisterForKeys函数中:
  {
        registeredKeysTaskID = task_id;
  }
 

 


 
 





  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值