以按键事件为例阐述消息传递机制

以按键事件为例阐述消息传递机制

这里主要想说的是按键事件发生后,app层是怎么收到消息的一些想法。
main.c:
        执行InitBoard( OB_COLD )           // OB_COLD宏定义为0
        { 
            if ( level == OB_COLD )
                {
                *(uint8 *)0x0 = 0;
                 osal_int_disable( INTS_ALL ) 
                }
        } 

这个函数执行完毕系统关禁止中断

    然后执行HalDriverInit (void)    //头文件有#define HAL_KEY TRUE
            {   
            ......          
            #if (defined HAL_KEY) && (HAL_KEY == TRUE)
             HalKeyInit();
            #endif  
            .....           
            }   

———————————————————————————————————————
hal_key.c:

    执行HalKeyInit( void )  //这是关于按键初始化的配置,比如回调函数,按键储存变量
            {
                halKeySavedKeys = 0;
                .......
                pHalKeyProcessFunction  = NULL;//回调函数为空
                HalKeyConfigured = FALSE;   //按键还没有配置
            }

执行完返回main.c

———————————————————————————————————————
顺着main函数的函数体往下执行,再次遇到

InitBoard(  OB_READY  );            // #define OB_READY 2
        {
            ......
        else  
         {
           HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE, OnBoard_KeyCallback);
         }
        }

hal_key.c:
// #define HAL_KEY_INTERRUPT_DISABLE 0x00

    执行  HalKeyConfig ( bool  interruptEnable , halKeyCBack_t   cback )
        {
          Hal_KeyIntEnable = interruptEnable;  //将0x00赋值给Hal_KeyIntEnable

          pHalKeyProcessFunction = cback;    
        /*回调函数赋值给 pHalKeyProcessFunction,往上查定义得到
        static  halKeyCBack_t  pHalKeyProcessFunction,再往上查得到
        typedef  void  (*halKeyCBack_t) (uint8 keys, uint8 state); 
        说白了pHalKeyProcessFunction就是个函数指针*/

        ......
        else    
      {
       HAL_KEY_SW_6_ICTL &= ~(HAL_KEY_SW_6_ICTLBIT); /* don't generate interrupt */
       HAL_KEY_SW_6_IEN &= ~(HAL_KEY_SW_6_IENBIT);   /* Clear interrupt enable bit */

       osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_POLLING_VALUE);        
        //       #define HAL_KEY_EVENT         0x0001 


HAL_KEY_POLLING_VALUE定义为500ms,开始计时任务,每100ms触发一次。意思就是HAL_KEY_EVENT这个事件100ms发生一次
  }
    HalKeyConfigured = TRUE;
}

——————————————————————————————————————
到此为止,按键相关的初始化都搞完了。接下来就是等第一个100ms
现在第一个100ms来了。

main.c:
    osal_start_system()
        for(;;)
    {  osal_run_system();}

________________________________________________________________________________________________

执行  osal_run_system();
    {
        osalTimeUpdate();
         Hal_ProcessPoll();
        //上面两个函数实现了计时和事件置位

        ......
        events = tasksEvents[idx];
        tasksEvents[idx] = 0;
        events = (tasksArr[idx])( idx, events );
    }

主循环里面检测到Hal_TaskID这个任务被置位(至于osal_start_timerEx是怎么让任务置位这个问题我还没弄懂,暂且当做已知…),保存在event,然后把任务清0。进入事件处理函数(这里为什么叫事件处理函数而不是叫任务处理函数呢?我想是因为一个任务可以接受处理很多个事件,这个函数只是个入口,函数体里面是会具体区分什么事件的)。
———————————————————————————————————————

hal_drivers.c
    Hal_ProcessEvent( uint8 task_id, uint16 events )
    {
        if (events & HAL_KEY_EVENT)
         {
            #if (defined HAL_KEY) && (HAL_KEY == TRUE)
                HalKeyPoll();
           if (!Hal_KeyIntEnable)
            {
              osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);
            }
           #endif // HAL_KEY

        return events ^ HAL_KEY_EVENT;
        }
  }

这里想说,osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_POLLING_VALUE)传递给Hal_TaskID这个任务的事件是HAL_KEY_EVENT。(events & HAL_KEY_EVENT)的结果就是1,进入if判断,HalKeyPoll()获得是哪个按键按下了。然后继续osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100),为什么要这样做呢?因为在osal_run_system()里面有tasksEvents[idx] = 0 意味着这个事件被处理过了,但是谁知道什么时候有人要按键呢,所以只能不停的查询。
——————————————————————————————————————————
看到这里,好像还是没说怎么通知app层啊?仔细找找,原来在HalKeyPoll();里hal_key.c:

HalKeyPoll()
{
if (!Hal_KeyIntEnable)
  {
    if (keys == halKeySavedKeys)
    {
           return;
    }
       halKeySavedKeys = keys;
  }
  else
  {
/* Key interrupt handled here */
  }  
    if (keys && (pHalKeyProcessFunction))
  {
    (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
  }

创建halKeySavedKeys变量是为了下一次触发事件的时候和keys进行比较,如果相同则说明
这一次轮询没有按键,就return回去(橙色代码)。如果keys有值并且回调函数已经定义了的话就调用回调函数。
#define HAL_KEY_STATE_NORMAL 0x00
———————————————————————————————————————
Onboard.c:
回调函数前面说了是个函数指针,实际上调用:

OnBoard_KeyCallback ( uint8 keys, uint8 state )
{
    ......
    if ( OnBoard_SendKeys( keys, shift ) != ZSuccess )
    .......
}


OnBoard_SendKeys( uint8 keys, uint8 state )
{
    //在这里正式填充消息结构体(不是那种无线消息),而是“keyChange_t”,我觉得是这个层次向app层发消息的特定的结构体,是不是别的层向app层发送的话有别的结构体样式?

    if ( registeredKeysTaskID != NO_TASK_ID )  
  {
        msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) );
    if ( msgPtr )
    {
      msgPtr->hdr.event = KEY_CHANGE;
      msgPtr->state = state;
      msgPtr->keys = keys;

      osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );
    }
    return ( ZSuccess );
  }

在文件开头有static uint8 registeredKeysTaskID = NO_TASK_ID;
在这个文件里有函数RegisterForKeys( uint8 task_id ) 。函数实现了registeredKeysTaskID = task_id。 那么到底谁调用了这个函数呢?全局查找之后发现在sampleapp.c里面调用了它,这里就明白了很多教程说使用按键就一定要先调用按键注册函数,因为如果不这样做的话if循环根本进不去….

define KEY_CHANGE 0xC0 这是一个事件的编号,猜想应该还有很多事件的宏定义散落在不同的文件里,但是好像记得说过事件是独热码编码的,那怎么会有0xc0这种东西,暂时保留疑问….

———————————————————————————————————————————

OSAL.c:
    osal_msg_send(destination_task, (uint8 *)msgPtr )
    {
        ......
        osal_msg_enqueue( &osal_qHead, msg_ptr );
        osal_set_event( destination_task, SYS_EVENT_MSG );
        ......
    }

// destination_task就是app层的id
//这里就正式将消息传给destination_task,也就是SampleApp_TaskID。其实我们口中说的将消息传给谁,程序中的实现是这样的:将这个消息加入消息队列(所有任务都能访问的一个队列),然后那个消息传给了哪个任务,就将那个任务事件标志位置1(main循环就能轮询到),那个任务对应的事件处理函数里面就会去取属于自己的消息(函数是不知道属于自己的消息放在哪里的,所以它一定要将整个消息队列遍历一次,这个说法在osal_msg_receive( SampleApp_TaskID )的函数体中可以证实)

————————————————————————————————————————————

OSAL.c:
osal_set_event( uint8 task_id, uint16 event_flag )
{
.......
tasksEvents[task_id] |= event_flag;
......
}

这句话牛逼啦,event_flag就是传递的参数SYS_EVENT_MSG,也就是0x8000.
task¬_id下标对应的tasksevents就变成了0x8000。为什么要这样?理由 1.统一规定一个强制的参数作为事件发生的标志,清晰明了 2.后面的事件处理函数好判断

_ ____________________________________________________________________
sampleapp.c:
现在任务已经被置位,并进入了事件处理函数

SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{   
    ......
    if ( events & SYS_EVENT_MSG )  //没有上面的event_flag,这个if是进不去的。
    {
        ........
    while ( MSGpkt )
    {
      switch ( MSGpkt->hdr.event )
      {
        ......

          case KEY_CHANGE:
          SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );

            break;
        }

        ......
  }
}

SYS_EVENT_MSG告诉你有事件发生了,发生的事什么事件通过(MSGpkt->hdr.event)来判断,通过switch语句跳转到不同的处理函数上。
———————————————————————————————————————
关于消息从产生到传递到处理暂时只能理解这个份上了….

你可能感兴趣的:(zigbee相关)