我是靠谱客的博主 冷静月饼,最近开发中收集的这篇文章主要介绍ZStack OSAL的事件(event)与消息(message)——part 2,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

ZStack OSAL的事件(event)与消息(message)——part 1 (有关event的那些事)

在这里 http://blog.csdn.net/ceci_prayer/article/details/9787349


二、消息

消息可以理解为带有附加信息的事件。最典型的一类便是按键消息,它同时产生了一个哪个按键被按下了附加信息。所以在OnBoard_SendKeys这个

数中,不仅向GenericApp发送了事件,还通过调用osal_msg_send函数向GenericApp发送了一个消息,这个消息记录了这个事件的附加信息

一般来说,一个消息总是和一个事件对应。当协议栈接收到消息后,在ProcessEvent函数中有以下语句:

if ( events & SYS_EVENT_MSG )
  {
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
    while ( MSGpkt )
    {
      switch ( MSGpkt->hdr.event )

     {

case ……

     }

可以看出,消息是被当作系统事件接收的,接收到之后会找到消息对应的event,之后进行相应的处理。

消息的使用与事件类似,但是使用了不同的函数触发:

byte osal_msg_send( byte destination_task, byte *msg_ptr ) 

这个函数有两个参数分别为接收事件任务的ID,另一个是指向消息的指针。它的功能是向一个任务发送命令或数据消息,此外,这个函数也会触发目标任务的SYS_EVENT_MSG(系统消息任务)。


----------------------------以上是之前学习内容的分割线-----------------------------------


之前对于消息的分析是正确的,但过于笼统了。今天我重新梳理了一下关于消息(message)的思路,在这里记录一下。

首先我们需要明确一个概念,,msg是用来干什么的?msg和event有什么不同?

我们已经知道了,event是一个事件,当这个事件发生以后,会触发相应的事件处理函数。即event是事先定义好的,但不知道会在哪个确定时间点被触发。

而消息不同。顾名思义,消息是用来传递信息的,即有两个主体(如下图中的task1和task2),在这两个主体想要通信的时候,就会用到消息。


上面这个图是我自已总结的有关zstack中消息的用法(如果有不正确的地方希望大家指正^_^)。

step1:osal_msg_allocate

可以看出,task1想要给task2发送消息(这两个任务可能属于一个设备,也可能属于不同的设备,这一点稍后再说),于是task1就得先产生一个msg,这时候就要用到osal_msg_allocation给这个消息分配一个缓存:

uint8 * osal_msg_allocate( uint16 len
{
  osal_msg_hdr_t *hdr;

  if ( len == 0 )
    return ( NULL );

 hdr = (osal_msg_hdr_t *) osal_mem_alloc( (short)(len + sizeof( osal_msg_hdr_t )) );
  if ( hdr )
  {
    hdr->next = NULL;
    hdr->len = len;
    hdr->dest_id = TASK_NO_TASK;
    return ( (uint8 *) (hdr + 1) );
  }
  else
    return ( NULL );
}

注意加粗的代码。首先看一下这个函数的参数len,是什么呢?查手册可以知道,len是msg的长度。那osal_msg_hdr_t *hdr又是什么呢?看一下osal_msg_hdr_t这个数据结构的定义:

typedef struct
{
  void   *next;
  uint16 len;
  uint8  dest_id;
} osal_msg_hdr_t;

这个实际上是消息的头部。再看下一句:

hdr = (osal_msg_hdr_t *) osal_mem_alloc( (short)(len + sizeof( osal_msg_hdr_t )) );

这句代码是给消息分配缓存区的,而缓存区的大小是len + sizeof( osal_msg_hdr_t )),也就是消息的大小+消息头的大小。

到这里我们隐约能感觉到,一个消息应该是由两部分组成:消息头和消息的实际内容,消息头是协议栈定义好的,而消息的内容则应该是我们自己添加的。大家再关注一下osal_msg_allocate的代码,可以看出,除了分配缓存以外,它还赋给了消息头一个初始值,但是却没有对消息本身做什么处理。因为消息是要留给大家自己定义的,所以osal_msg_allocate将指向消息头hdr下一位的指针做为函数的返回值,以便大家添加自己的消息代码。

至于消息的具体定义,可以分为两种:系统消息和用户消息。系统消息什么的拜托协议栈就好啦,而用户消息就需要大家根据实际的要求动手了^0^

(在接下来的内容中,完整的消息被认为是已经定义好的,直接拿来用就可以了。)

step2:osal_msg_send
send函数有两个参数,一个是目标task的地址,另一个是指向消息的指针。
uint8 osal_msg_send( uint8 destination_task, uint8 *msg_ptr ) 
{
  if ( msg_ptr == NULL )
    return ( INVALID_MSG_POINTER );

  if ( destination_task >= tasksCnt )
  {
    osal_msg_deallocate( msg_ptr );
    return ( INVALID_TASK );
  }

  // Check the message header
  if ( OSAL_MSG_NEXT( msg_ptr ) != NULL ||
       OSAL_MSG_ID( msg_ptr ) != TASK_NO_TASK )
  {
    osal_msg_deallocate( msg_ptr );
    return ( INVALID_MSG_POINTER );
  }

  OSAL_MSG_ID( msg_ptr ) = destination_task;

  // queue message
  osal_msg_enqueue( &osal_qHead, msg_ptr );

  // Signal the task that a message is waiting
  osal_set_event( destination_task, SYS_EVENT_MSG );

  return ( SUCCESS );
}

其他内容就不用过过关注了,看看加粗的代码: osal_msg_enqueue  
这句看起来是入栈操作,嗯嗯,就是这样^0^~其实在协议栈内部维护着一个消息队列,也就是说,消息是按照队列的方式被操作的,所以就有了入栈出栈的内容,具体实现就不关注了,这里只要明白发送的消息被放到(应该是目标任务的)消息队列里就好啦,别的东西用到的时候再说吧。

再看一下  osal_set_event( destination_task, SYS_EVENT_MSG );这句很重要啊,因为它告诉我们,在发送了一个消息之后,会触发目标协议栈的系统事件SYS_EVENT_MSG,也就是说,虽然消息的处理方式与事件类似,但是有关消息的事件是系统事件哦~想要处理消息的话知道去哪找了吧?
step3:osal_msg_receive
又是一个重量级的API,这个API关系到我们怎么取出消息。先看看在哪里会调用这个API,预告一下,会是我们十分熟悉的地方哦~

uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
  afIncomingMSGPacket_t *MSGpkt;

  if ( events & SYS_EVENT_MSG )
  {
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
    while ( MSGpkt )
    {
      switch ( MSGpkt->hdr.event )
      {
        // Received when a key is pressed
        case KEY_CHANGE:
          SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
          break;

        // Received when a messages is received (OTA) for this endpoint
        case AF_INCOMING_MSG_CMD:
          SampleApp_MessageMSGCB( MSGpkt );
          break;

ProcessEvent!这个是大家最早熟悉的部分了吧?在这个API中,首先定义了一个数据结构:afIncomingMSGPacket_t *MSGpkt,具体看一下:

typedef struct
{
  osal_event_hdr_t hdr;     /* OSAL Message header */
  uint16 groupId;           /* Message's group ID - 0 if not set */
  uint16 clusterId;         /* Message's cluster ID */
  afAddrType_t srcAddr;     /* Source Address, if endpoint is STUBAPS_INTER_PAN_EP,
                               it's an InterPAN message */
  uint16 macDestAddr;       /* MAC header destination short address */
  uint8 endPoint;           /* destination endpoint */
  uint8 wasBroadcast;       /* TRUE if network destination was a broadcast address */
  uint8 LinkQuality;        /* The link quality of the received data frame */
  uint8 correlation;        /* The raw correlation value of the received data frame */
  int8  rssi;               /* The received RF power in units dBm */
  uint8 SecurityUse;        /* deprecated */
  uint32 timestamp;         /* receipt timestamp from MAC */
  afMSGCommandFormat_t cmd; /* Application Data */
} afIncomingMSGPacket_t;


有点吓人啊!不过仔细看一眼,除了第一句osal_event_hdr_t hdr之外,别的好像都不是很重要嘛~对的,以af_开头,说明这个数据是经过无线传输后收到的,也就是由另一个设备上的task发送给本设备的,所以必然会在我们原来消息的基础上层层打包,加上许多其他内容了。

再来看一下关键的osal_event_hdr_t结构体:
typedef struct
{
  uint8  event;
  uint8  status;
} osal_event_hdr_t;
并不是很复杂,只包括了一个事件发生的标志(event)和状态(status)。那它又是用来做什么的呢?
答案是,它是用来找到事件对应的消息的。

前面说过,在发送一个消息之后osal_mem_send,会触发一个系统事件。我们现在遇到的情况是,有了这个事件之后,怎么找到它对应的消息,这时就需要上门介绍的机制了,定义一个指向osal_event_hdr_t类型的指针,然后用osal_msg_receive找到这个消息并让前面的指针MSGpkt指向它。(在代码给出的例子中指向消息的指针类型是afIncomingMSGPacket_t,但是从刚才的分析可以看出,如果是在同一个设备中的两个task通信的话,也就是不需要无线传输的时候,用osal_event_hdr_t类型的指针就可以满足要求了)。

至于这一步所说的重要的函数osal_msg_receive,它的功能就是从协议栈维护的消息队列中取出相应的消息,想要了解就看看源代码吧~

现在我们既有事件,又有消息,接下来就进入愉快的处理带有消息的事件部分吧~
以case AF_INCOMING_MSG_CMD为例,嗯嗯,只要以MSGpkt为参数,调用相应的处理函数就好啦:SampleApp_MessageMSGCB( MSGpkt );很愉快哦~


呼,终于结束了,写出来居然有这么长~最后附上前一篇有关event的地址,方便学习咯~
http://blog.csdn.net/ceci_prayer/article/details/9787349

最后

以上就是冷静月饼为你收集整理的ZStack OSAL的事件(event)与消息(message)——part 2的全部内容,希望文章能够帮你解决ZStack OSAL的事件(event)与消息(message)——part 2所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(46)

评论列表共有 0 条评论

立即
投稿
返回
顶部