博客
关于我
浅谈ZigBee消息机制
阅读量:133 次
发布时间:2019-02-26

本文共 3895 字,大约阅读时间需要 12 分钟。

本章简单的介绍一下ZigBee的消息机制,如果说的有问题还请多多指正。

通俗的说,ZigBee的消息机制就好比这有一排抽屉,当我要向某个任务或者事件发送消息时,就把该消息和对应的数据放到抽屉中,在任务轮训时,某个任务轮训按个查看抽屉中是否有自己需要的消息,有就取出并且处理,没有就结束,等待下一次轮训。

ZigBee消息链表如下图所示:(注:消息机制实现代码在osal.c中)


图1 ZigBee消息队列

值得注意的是,消息队列中每条消息都有一个系统消息头,结构体为osal_msg_hdr_t,包括三个数据类型,包括下一条消息的指针、消息长度和任务ID。消息头下有一个事件消息头,结构体为osal_event_hdr_t,该消息头包括事件的掩码和状态。使用过程中特别注意,通过系统函数获取的消息指针为事件消息头(osal_event_hdr_t)对应的地址,具体可看图1。

 

下面以串口接收到数据解包后将数据发到应用层为例,来介绍一下ZigBee的消息机制是怎么实现的。

【MT_UART.c】串口接收到数据后,首先要申请该消息对应的空间内存,申请多少要看数据有多少。

App_pMsg = (mtOSALSerialData_t *)osal_msg_allocate( sizeof (mtOSALSerialData_t) + MT_RPC_FRAME_HDR_SZ + App_LEN_Token );


其中 [MT_RPC_FRAME_HDR_SZ + App_LEN_Token]为串口数据长度,MT_RPC_FRAME_HDR_SZ包括数据长度、命令码0、命令码1三个数据,App_LEN_Token表示应用层数据,在此不再赘述。申请的该指针返回的为mtOSALSerialData_t,对应的图2中event的地址。

 

再看osal_msg_allocate( uint16 len )这个函数。


<span style="font-family: Arial, Helvetica, sans-serif;">uint8 * osal_msg_allocate( uint16 len )</span>
{  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 );}

该函数在申请内存时,添加了sizeof( osal_msg_hdr_t )长度,该长度及图1中消息时间头,并且赋予了该消息头的next指针,长度len和dest_id任务ID。函数返回的指针为hdr+1,从我们正常的角度看,即申请了一片内存,返回内存指针,在内存指针前加上了任务消息头。因此这就是在处理任务消息头时都要-1的原因。


图3 任务消息处理函数

 

这样就生成一条消息。但是该工作并没有完成,需要将该消息放入消息对垒并且通知对应的任务ID取出该消息。

 

通过查看串口代码,可发现当数据校验正确后,要调用该函数。

osal_msg_send( App_TaskID, (byte *)App_pMsg );

该函数代码如下:

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 );}

除去一些判断信息,该函数最重要的操作有三个,赋值任务ID、消息入队列和设置任务事件。

赋值任务ID不在赘述,即将 该条消息中的dest_id赋值为要通知的任务ID。

消息入队列的操作也比较简单,结合图1,通过查找链表的链尾,将该条消息的event地址赋值给链尾消息的*next即可。

设置任务事件即置位相应的任务ID和事件掩码。

 

 

将消息如队列后,对应的取消息即为该过程的逆操作。以应用层取串口数据为例。

【sampleApp.c】应用层调用函数

MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );

该函数代码如下:

uint8 *osal_msg_receive( uint8 task_id ){  osal_msg_hdr_t *listHdr;  osal_msg_hdr_t *prevHdr = NULL;  osal_msg_hdr_t *foundHdr = NULL;  halIntState_t   intState;  // Hold off interrupts  HAL_ENTER_CRITICAL_SECTION(intState);  // Point to the top of the queue  listHdr = osal_qHead;  // Look through the queue for a message that belongs to the asking task  while ( listHdr != NULL )  {    if ( (listHdr - 1)->dest_id == task_id )    {      if ( foundHdr == NULL )      {        // Save the first one        foundHdr = listHdr;      }      else      {        // Second msg found, stop looking        break;      }    }    if ( foundHdr == NULL )    {      prevHdr = listHdr;    }    listHdr = OSAL_MSG_NEXT( listHdr );  }  // Is there more than one?  if ( listHdr != NULL )  {    // Yes, Signal the task that a message is waiting    osal_set_event( task_id, SYS_EVENT_MSG );  }  else  {    // No more    osal_clear_event( task_id, SYS_EVENT_MSG );  }  // Did we find a message?  if ( foundHdr != NULL )  {    // Take out of the link list    osal_msg_extract( &osal_qHead, foundHdr, prevHdr );  }  // Release interrupts  HAL_EXIT_CRITICAL_SECTION(intState);  return ( (uint8*) foundHdr );}

该函数就不在一一翻译了,大体意思为:

查找消息链表,链表头为osal_qHead,查看链表中消息的任务消息头,如果消息头为查找的任务ID,则跳出循环,并且将该条消息 从链表中剔除,如果没有找到,返回NULL。找到该条消息后下一步就是进行处理了。

 

到此ZigBee的消息机制基本就结束了,其中还有一些消息处理的其它函数,也比较简单,就不在一一描述了,有需要的可以自行查看。


你可能感兴趣的文章
NIFI1.23.2_最新版_性能优化通用_技巧积累_使用NIFI表达式过滤表_随时更新---大数据之Nifi工作笔记0063
查看>>
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_根据binlog实现update数据实时同步_实际操作05---大数据之Nifi工作笔记0044
查看>>
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_根据binlog实现数据实时delete同步_实际操作04---大数据之Nifi工作笔记0043
查看>>
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置binlog_使用处理器抓取binlog数据_实际操作01---大数据之Nifi工作笔记0040
查看>>
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置数据路由_实现数据插入数据到目标数据库_实际操作03---大数据之Nifi工作笔记0042
查看>>
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置数据路由_生成插入Sql语句_实际操作02---大数据之Nifi工作笔记0041
查看>>
NIFI从MySql中离线读取数据再导入到MySql中_03_来吧用NIFI实现_数据分页获取功能---大数据之Nifi工作笔记0038
查看>>
NIFI从MySql中离线读取数据再导入到MySql中_不带分页处理_01_QueryDatabaseTable获取数据_原0036---大数据之Nifi工作笔记0064
查看>>
NIFI从MySql中离线读取数据再导入到MySql中_无分页功能_02_转换数据_分割数据_提取JSON数据_替换拼接SQL_添加分页---大数据之Nifi工作笔记0037
查看>>
NIFI从Oracle11G同步数据到Mysql_亲测可用_解决数据重复_数据跟源表不一致的问题---大数据之Nifi工作笔记0065
查看>>
NIFI从PostGresql中离线读取数据再导入到MySql中_带有数据分页获取功能_不带分页不能用_NIFI资料太少了---大数据之Nifi工作笔记0039
查看>>
nifi使用过程-常见问题-以及入门总结---大数据之Nifi工作笔记0012
查看>>
NIFI分页获取Mysql数据_导入到Hbase中_并可通过phoenix客户端查询_含金量很高的一篇_搞了好久_实际操作05---大数据之Nifi工作笔记0045
查看>>
NIFI分页获取Postgresql数据到Hbase中_实际操作---大数据之Nifi工作笔记0049
查看>>
NIFI同步MySql数据_到SqlServer_错误_驱动程序无法通过使用安全套接字层(SSL)加密与SQL Server_Navicat连接SqlServer---大数据之Nifi工作笔记0047
查看>>
NIFI同步MySql数据源数据_到原始库hbase_同时对数据进行实时分析处理_同步到清洗库_实际操作06---大数据之Nifi工作笔记0046
查看>>
Nifi同步过程中报错create_time字段找不到_实际目标表和源表中没有这个字段---大数据之Nifi工作笔记0066
查看>>
NIFI大数据进阶_FlowFile拓扑_对FlowFile内容和属性的修改删除添加_介绍和描述_以及实际操作---大数据之Nifi工作笔记0023
查看>>
NIFI大数据进阶_FlowFile生成器_GenerateFlowFile处理器_ReplaceText处理器_处理器介绍_处理过程说明---大数据之Nifi工作笔记0019
查看>>
NIFI大数据进阶_FlowFile生成器_GenerateFlowFile处理器_ReplaceText处理器_实际操作---大数据之Nifi工作笔记0020
查看>>