zigbee协议栈 任务、事件与轮询机制

zigbee协议栈 任务、事件与轮询机制typedefunsignedcharuint8  只占一个字节,即二进制的8位,0b00000000,16进制的两位0x00;typedefunsignedshortuint16只占两个字节,即二进制的16位,0b0000000000000000,16进制的四位0x0000 协议栈中有三个变量至关重要:l tasksCnt保存了任务的总个数uint8ta

大家好,又见面了,我是你们的朋友全栈君。

typedef unsigned char uint8   只占一个字节,即二进制的8位,0b00000000,16进制的两位0x00;

typedef unsigned short uint16 只占两个字节,即二进制的16位,0b0000000000000000,16进制的四位 0x0000

 

协议栈中有三个变量至关重要:

tasksCnt保存了任务的总个数

uint8 tasksCnt    

tasksEvents这是一个指针(可以看做数组),作为事件表,数组的索引是任务ID号,每一元素对应了该任务下的所有事件,这个事件可以拆分为小事件;

uint16 *tasksEvents 

tasksArr——这是一个数组,数组中的每一项都是一个函数指针,指向了任务事件的处理函数。数组的索引是任务的ID号,该ID号下的元素就是对应任务的事件处理函数,事件处理函数利用switch将该任务下的所有事件处理;

pTaskEventHandlerFntasksArr[] ,pTaskEventHandlerFn 是函数指针

typedef unsignedshort (*pTaskEventHandlerFn) (unsigned char task_id, unsigned short event)

表明,pTaskEventHandlerFn是一个指向返回值为(unsigned short)形参为(unsigned char task_id ,unsigned short event)的函数的指针

 

tasksEvents中的元素为一个16位二进制数,zigbee协议栈用一位二进制来定义事件,为1表示有事件,为0表示无事件,如任务ZDAppTaskID下的事件为

事件

十六进制

二进制

ZDO_NETWORK_INIT

0x0001

0b0000000000000001

ZDO_NETWORK_START

0x0002

0b0000000000000010

ZDO_DEVIEC_RESET

0x0004

0b0000000000000100

ZDO_COMMAND_CNF

0x0008

0b0000000000001000

ZDO_START_CHANGE_EVT

0x0010

0b0000000000010000

ZDO_ROUTER_START

0x0020

0b0000000000100000

ZDO_NEW_DEVICE

0x0040

0b0000000001000000

ZDO_DEVICE_AUTH

0x0080

0b0000000010000000

ZDO_SCEMGR_EVENT

0x0100

0b0000000100000000

ZDO_NWK_UPDATE_NV

0x0200

0b0000001000000000

ZDO_FRAMECOUNTER_CHANGE

0x0400

0b0000010000000000

如上图,这样二进制的每一位的1可以定义为一个事件,理论上一个任务下可以定义16个事件。这样的好处是,事件与事件之间可以用二进制加法处理即异或算法相加。

比如:tasksEvents[ZDAppTaskID]=0x0003 ,由于 0x0003=0x0001^0x0002,所以可以看做ZDO_NETWORK_INT+ZDO_NETWORK_START,所以此时该任务下的事件有两个,即ZDO_NETWORK_INT和ZDO_NETWORK_START。提取的时候可以利用与运算来提取。 “与”运算能用来判断二进制数的某一位是否为1。由于二进制的减法运算与加法运算相同,所以也可以通过加法异或运算来清零某一已经处理过的事件。

 

全zigbee协议栈最重要的就是  void osal_start_system( void )函数,整个轮询机制也在这个函数中被完成

zigbee协议栈 任务、事件与轮询机制

第5行,定义了一个变量idx,用来标识任务,(如任务0),用来在事件表和函数表中索引;

第6、7行,更新系统时钟,同时查看硬件方面是否有事件发生,如串口是否接收到数据、是否有按键按下等信息,这部分内容在此暂不考虑;

第9~15行,idx从零增大到tasksCnt,依次遍历事件表,查看哪个任务idx对应的事件不为空,当找到任务idx的事件不为空时停止遍历,转而去调用该任务的事件处理函数,不妨设此时的idx = 8;

第19~22行,将该任务8的事件取出来放到events变量中,由于事件值被取出来了,所以对应事件表中的元素值要清零,即tasksEvents[8] = 0;

第25行,由于任务事件处理函数表的元素索引与任务事件表的索引一一对应,所以直接将8作为索引带入任务事件处理函数表就可以调用任务8的事件处理函数(tasksArr[8])(8,events),而且由于函数表中的事件处理函数是以函数指针的形式给出的,所以还需要填写形参,分别是任务id号8,和从任务8的事件events。形参中有events天经地义,因为需要分辨events中含有哪些具体事件,形参中为什么有任务id号呢?是因为,在处理任务的时候可能需要调用其他与任务绑定的函数。同时,任务处理函数的返回值也是任务值,UINT16,返回的是未被处理的具体事件。

第32行,将任务8未被处理的具体事件放回事件表中任务8对应的事件元素中。

 

然而,以上的机制可以解释Zigbee是怎样处理一个任务下面的事件的,但处理后的事件表是被清零的,那是谁来给任务的这些事件来置一呢?

osal_set_event(uint8 task_id , uint16 event_flag ) ;由它来给事件表中的元素赋值。

函数原型为:

uint8osal_set_event( uint8 task_id , uint16 event_flag )

{

 if( task_id < tasksCnt)

{

  halIntState_t   intState ;

  HAL_ENTER_CRITICALL_SECTION( inState ) ;   //关中断

  tasksEvents[task_id] |= event_falg ;           //给任务task_id设置事件event_flag

   HAL_EXTI_CRITICALL_SECTION(inState ) ;     //开中断

   return( SUCCESS )

}

else

{

  return( INVALID_TASK )

}

 

}

 

如,原来的tasksEvents[ZDAppTaskID] = 0x0000,即此任务下无事件可以处理,当我调用

osal_set_event(uint8 ZDAppTaskID , ZDO_NETWORK_INIT ) tasksEvents[ZDAppTaskID] = 0x0001,这样当进入轮询时就会调用事件处理函数处理该事件。

 

 

知道了任务下的事件是如何被设置、处理的,我们知道任务ID是将事件表和事件处理函数联系起来的关键,那么任务本身是怎样被设置的呢?

添加任务的关键是

新任务的初始化函数

新任务的事件处理函数

如要添加任务GenericApp则其初始化函数GenericApp_Init( taskID ),事件处理函数GenericApp_ProcessEvent应该分别放在osalInitTasks函数、事件处理函数表tasksArr[]的最后,而tasksEvent[]的大小会随着tasksArr[]的大小一起变化,即当在tasksArr[]最后一位加入GenericApp_ProcessEvent时,tasksEvent[]也随着增加一个元素用来安放对应的事件。

       为了方便看出原理,将taskArr[]、osalInitTasks()简化处理得到

zigbee协议栈 任务、事件与轮询机制

值得一提的是,taskArr[]是先于tasksEvents[]声明定义的,所以可以根据taskArr[]的长度来设置tasksEvents[]的长度与任务相匹配。

由osalInitTask(),任务ID号从0开始,按先后顺序分别分配给各个任务,所以这个ID号与数组的索引也是相匹配的,设备必须的任务优先,从上图看到,用户自定义的任务ID应该是8。正是借助这个ID号将任务事件表中的事件元素和事件处理函数表中的事件处理函数对应了起来。

zigbee协议栈 任务、事件与轮询机制

                                                                                                  2018年1月22日星期一

                                                                                                         武汉大学青楼

本文参考自:《ZigBee无线传感器网络设计与实现》      王小强等人编著化学工业出版社

                                                                                                  

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/140472.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java大数据培训[通俗易懂]

    java大数据培训[通俗易懂]从近几年的发展来看,大数据已经可以说是当之无愧的热门了,大数据在越来越多的行业实现落地,也就需要更多的专业人才来支持。很多人都看好大数据行业,想要转向大数据发展,其中也不乏Java一类的技术开发人员。今天的大数据课程学习培训分享,我们来聊聊Java转大数据的那些事儿。因为大数据本身也与Java开发存在着紧密的关联性,行业当中现有的大数据从业者,其中也不乏Java资深开发者,在实际的工作当中,抓住大数据机遇,从Java开发转向了大数据开发,薪资待遇和发展空间,都有了明显的增长和拓宽。Java转大数

    2022年8月30日
    5
  • vue中使用input file上传文件

    vue中使用input file上传文件刚刚学习前端的时候还是觉得这个东西好难的样子,后来第一家公司由于没有这个需求就没用过,现在这家公司由于要求很完美的组件,我就是用的vue组件vue-image-crop-upload(适用于pc端的比较好的组件),先在这里记录用法下次再去把vue-images-crop-upload这个组件记录下…

    2022年7月17日
    76
  • vue页面刷新方法_vue返回上一页怎么实时刷新

    vue页面刷新方法_vue返回上一页怎么实时刷新一、通过js原始方法刷新<template><div><divclass=”header”><button@click=”update()”>刷新页面</button></div></div></template><script>exportdefault{data(){return{}},methods

    2022年10月11日
    2
  • cv2 imread()函数[通俗易懂]

    Reason    这两天学习OpenCV-Python时,也就是cv2库,读取图像时不时出现和预料之外的结果。于是作者从源头来考究一下cv2.imread(filename,flags)Result这里参考文章cv2.imread(filename,flags)cv2.imread(filename,flags)参数:filepath:读入imge的完整路径flags:标志位,{cv2.IMREAD_COLOR,cv2.IMREAD_GRAYSC

    2022年4月14日
    61
  • HDU 4920 Matrix multiplication(矩阵相乘)

    HDU 4920 Matrix multiplication(矩阵相乘)

    2022年2月7日
    40
  • 登录页面的代码

    登录页面的代码开发工具与关键技术:MVC/JavaScript作者:邱慧敏撰写时间:2019/06/25在把页面和数据库做好之后,我的登录页面只需要用户名和密码,所以代码比较简单。先找到登录按钮,给一个点击事件,然后再获取他们的表单值,然后对用户名和密码进行判断,判断是否填写了资料和是否是正确的账户和密码,在这之前还要检查登录页面是否是属于外层页面。dataValidationFo…

    2022年4月4日
    55

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号