OSAL在Zigbee的应用详解入门级Word格式.docx
《OSAL在Zigbee的应用详解入门级Word格式.docx》由会员分享,可在线阅读,更多相关《OSAL在Zigbee的应用详解入门级Word格式.docx(37页珍藏版)》请在冰点文库上搜索。
![OSAL在Zigbee的应用详解入门级Word格式.docx](https://file1.bingdoc.com/fileroot1/2023-5/4/bf92923c-82eb-4de4-a3af-19420835e183/bf92923c-82eb-4de4-a3af-19420835e1831.gif)
(对于本例子来说,任务数组里只有七个任务,tasksEvents[0]~tasksEvents[6],tasksEvents[6]就是用户自已添加的任务,idx随着用户添加任务的增多而增大)
do{
if(tasksEvents[idx])
//Taskishighestprioritythatisready.
{
break;
}
}while(++idx<
tasksCnt);
//tasksCnt=7(针对本例子,随着用户应用任务增多而增大)
if(idx<
tasksCnt)
{
uint16events;
halIntState_tintState;
//中断位状态
HAL_ENTER_CRITICAL_SECTION(intState);
//中断临界状态:
保存先前中断状态,然后关中断
events=tasksEvents[idx];
//uint16events;
对应有事件发生的任务的数组
tasksEvents[idx]=0;
//CleartheEventsforthistask.
NULL
HAL_EXIT_CRITICAL_SECTION(intState);
//跳出中断临界状态:
恢复先前中断状态
events=(tasksArr[idx])(idx,events);
//调用相对应的任务事件处理函数处理,各类事件处理函
//数M(task_id,event)返回的都是这个任务未被处理的事件
HAL_ENTER_CRITICAL_SECTION(intState);
tasksEvents[idx]|=events;
//Addbackunprocessedeventstothecurrenttask.
//把刚才返回未处理的任务事件添加加当前任务中再进行处理
//(跳出此if(idx<
tasksCnt)循环再进行if(tasksEvents[idx])判断并处理)
HAL_EXIT_CRITICAL_SECTION(intState);
#ifdefined(POWER_SAVING)
else
//Completepassthroughalltaskeventswithnoactivity?
osal_pwrmgr_powerconserve();
//Puttheprocessor/systemintosleep
}
说明:
(1)OSAL调用Hal_ProcessPoll();
来轮询UART与TIMER,涉及HAL层,晚点总结.
(2)HAL_ENTER_CRITICAL_SECTION(intState);
与HAL_EXIT_CRITICAL_SECTION(intState);
见1;
(3)events=tasksEvents[idx];
见2;
(4)events=(tasksArr[idx])(idx,events);
见3;
(5)tasksEvents[idx]|=events;
见4;
1、HAL_ENTER_CRITICAL_SECTION(intState)与HAL_EXIT_CRITICAL_SECTION(intState)
定义在hal_mcu.h中,如下:
/********************************************
*
InterruptMacros
********************************************/
#defineHAL_ENABLE_INTERRUPTS()
st(EA=1;
)
//开中断
#defineHAL_DISABLE_INTERRUPTS()
st(EA=0;
//关中断
#defineHAL_INTERRUPTS_ARE_ENABLED()
(EA)
typedefunsignedcharhalIntState_t;
//中断临界状态:
把原先中断状态EA赋给X,然后关中断;
以便后面可以恢复原先的中断状态
#defineHAL_ENTER_CRITICAL_SECTION(x)
st(x=EA;
HAL_DISABLE_INTERRUPTS();
)
//跳出上面的中断临界状态,恢复先前的中断状态
#defineHAL_EXIT_CRITICAL_SECTION(x)
st(EA=x;
//中断临界状态以及跳出临界状态的全过程:
#defineHAL_CRITICAL_STATEMENT(x)
st(halIntState_ts;
HAL_ENTER_CRITICAL_SECTION(s);
x;
HAL_EXIT_CRITICAL_SECTION(s);
st()函数,定义在hal_defs.h中:
ThismacroisforusebyothermacrostoformafullyvalidCstatement.
Withoutthis,theif/elseconditionalscouldshowunexpectedbehavior.
#definest(x)
do{x}while(__LINE__==-1)
/*-------------------------------------------------------------------------------------------------------------
*#definest(x)do{x}while(__LINE__==-1)
*1,__LINE__是个宏,它代表当前代码在源文件的行号,它是大于0的,所以__LINE__==-1等同于0,化简为:
*#definest(x)do{x}while(0)
*2,do{}while(0)通常用于宏中,为的是避免如下情况:
*#definest(x)x
*那么我们在调用if(0)st(a=b;
b=c;
)时会被解释成
*if(0)
*a=b;
*b=c;
*可见if只对a=b;
起作用
--------------------------------------------------------------------------------------------------------------*/
2、events=tasksEvents[idx];
个人认为,tasksEvents[]是一个指针数组(但是在协议栈里对这个“数组”的定义我还没有找到,只是在OSAL_SampleApp.c下有这么一个声明:
uint16*tasksEvents;
以及系统任务初始函数下对tasksEvents的定义),内部各元素都是指向uint16类型变量的指针变量(对于本例子来说内部各元素即tasksEvents[0]~tasksEvents[6];
tasksEvents[0]指向任务1的存储空间……),对events的声明也是uint16events;
。
这里把有事件发生的任务idx的存储空间的地址赋给events。
然后清除任务idx的事件tasksEvents[idx]=0,(指针变量值为NULL).
3、events=(tasksArr[idx])(idx,events);
——任务idx的事件处理函数
首先看下对tasksArr[]的定义:
constpTaskEventHandlerFntasksArr[]=//数组tasksArr[]有7个元素(MTdefined)
macEventLoop,
//MAC层任务事件处理函数
nwk_event_loop,
//NWK层任务事件处理函数
Hal_ProcessEvent,
//PHY层事件处理函数
#ifdefined(MT_TASK)
MT_ProcessEvent,//MT任务事件处理函数
APS_event_loop,
//APS层任务事件处理函数
ZDApp_event_loop,
//ZDO任务事件处理函数
SampleApp_ProcessEvent
//用户应用任务事件处理函数
};
再来看下对pTaskEventHandlerFn的定义:
(OSAL_Tasks.h中)
typedefunsignedshort(*pTaskEventHandlerFn)(unsignedchartask_id,unsignedshortevent);
//前面有个typedef,把pTaskEventHandlerFn声明成一种函数指针类型的别名
//这种函数指针指向M(task_id,event)这种类型的函数(即各任务的事件处理函数)
//如果用这个别名来生成一个指向函数的指针X,则当X获得函数的地址后,就可以像调用
//原来函数一样来使用这个函数指针X(task_id,event),如上面的pTaskEventHandlerFntasksArr[]
//因此tasksArr[]是一个指针数组,其内部的各元素都是指针,从OSAL_SampleApp.c中对tasksArr[]
//的定义我们可以知道macEventLoop,nwk_event_loop一直到SampleApp_ProcessEvent这些元素都是
//指针变量,最终都是指向M(task_id,event)这种类型的函数,也就是各层的事件处理函数。
//另外我觉得,就像pTaskEventHandlerFntasksArr[];
之后可以通过tasksArr[]直接
//调用tasksArr[](task_id,event),也可以通过tasksArr[]里面的元素直接调用
//macEventLoop(task_id,event)...SampleApp_ProcessEvent(task_id,event),而这些任务事件处理
//函数都是uint16类型的.因此osal_start_system()里可以events=(tasksArr[idx])(idx,events);
events也是uint16类型的。
……………………语法上来解释我自己都一团雾水了,个人想法,不一定正确~
//typedefunsignedshort
uint16;
//typedefunsignedchar
uint8;
这里events=(tasksArr[idx])(idx,events);
是因为每一个任务的事件处理函数返回的都是这个任务没有被处理完成的事件。
比如说用户应用任务的事件处理函数:
SampleApp_ProcessEvent(uint8task_id,uint16events),如下:
每个任务都有不同的事件,因此在进行事件的处理前要进行判断,对于SampleApp
大事件1_接收系统消息:
(a)_按键小事件(包含了组发送flash消息事件和进组退组事件)
(b)_接收数据小事件
(c)_设备网络状态变化小事件
大事件2_向外发送消息:
(a)_发送periodic消息
下面的SampleApp_ProcessEvent()就是通过上面的顺序对用户添加的应用任务进行事件的轮询:
uint16SampleApp_ProcessEvent(uint8task_id,uint16events)
afIncomingMSGPacket_t*MSGpkt;
//接收到的消息
/*如果大事件是接收系统消息*/
//则接收系统消息再进行判断
if(events&
SYS_EVENT_MSG)
MSGpkt=(afIncomingMSGPacket_t*)osal_msg_receive(SampleApp_TaskID);
//接收属于本应用任务SampleApp的消息(SampleApp_TaskID标记。
while(MSGpkt)
//接收到
{
switch(MSGpkt->
hdr.event)//系统消息的进一步判断
//Receivedwhenakeyispressed
/*小事件:
按键事件*/
//
如果一个OSAL任务已经被登记注册,那么任何键盘事件都将接受一个KEY_CHANGE事件信息。
caseKEY_CHANGE:
//#defineKEY_CHANGE
0xC0
--KeyEvents
SampleApp_HandleKeys(((keyChange_t*)MSGpkt)->
state,((keyChange_t*)MSGpkt)->
keys);
break;
//执行具体的按键处理函数,定义在sampleAPP.c中
//Receivedwhenamessagesisreceived(OTA:
overtheair)forthisendpoint
接收数据事件*/
接收数据事件,调用函数AF_DataRequest()接收数据
caseAF_INCOMING_MSG_CMD:
//#defineAF_INCOMING_MSG_CMD
0x1A
--IncomingMSGtypemessage
SampleApp_MessageMSGCB(MSGpkt);
//调用回调函数对收到的数据进行处理
//Receivedwheneverthedevicechangesstateinthenetwork
/*小事件:
设备网络状态变化事件*/
只要网络状态发生改变,就通过ZDO_STATE_CHANGE事件通知所有的任务,注意,是所有任务都会收到这消息。
caseZDO_STATE_CHANGE:
//#defineZDO_STATE_CHANGE
0xD1
--ZDOhaschangedthedevice'
snetworkstate
SampleApp_NwkState=(devStates_t)(MSGpkt->
hdr.status);
//获取设备当前状态
if((SampleApp_NwkState==DEV_ZB_COORD)
||(SampleApp_NwkState==DEV_ROUTER)
||(SampleApp_NwkState==DEV_END_DEVICE))
//Startsendingtheperiodicmessageinaregularinterval.
/*按一定间隔启动定时器*/
//这个定时器是为发送周期信息设置的,我觉得因为在这个例子中,用户自己添加的任务,只有两个事件是用于向外发送消息的,一个是发送flash闪烁消息,属于组寻址,而另一个是发送periodic周期消息,属于广播;
这里是一个设备的网络状态发生了变化,必须要告诉同一网络中的其它设备,因此要进行广播通知其它设备…发送的消息中应该会包括本设备的类型。
……不知道这样理解对不对~管它的,以后会明白的~
//更新:
这个定时器只是为发送周期信息开启的,设备启动初始化后从这里开始触发第一个周期信息的发送,然后周而复始下去.
osal_start_timerEx(SampleApp_TaskID,
SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT);
else
//Deviceisnolongerinthenetwork
default:
//Releasethememory
//以上把收到系统消息这个大事件处理完了,释放消息占用的内存
osal_msg_deallocate((uint8*)MSGpkt);
//Next-ifoneisavailable
/*指针指向下一个"
已接收到的”[程序在while(MSGpkt)内]放在缓冲区的待处理的事件,与
//SampleApp_ProcessEvent处理多个事件相对应,返回while(MSGpkt)重新处理事件,
//直到缓冲区没有等待处理事件为止。
*/
MSGpkt=(afIncomingMSGPacket_t*)osal_msg_receive(SampleApp_TaskID);
//returnunprocessedevents
//两者相异或,返回未处理的事件,return到osal_start_system()下的events=(tasksArr[idx])(idx,events)语句中,重新在osal_start_system()下轮询再进入此函数进行处理。
return(events^SYS_EVENT_MSG);
//Sendamessageout-Thiseventisgeneratedbyatimer
/*如果大事件是向外发送信息,该事件由定时器产生*/
//
(setupinSampleApp_Init()).
SAMPLEAPP_SEND_PERIODIC_MSG_EVT)
//发送周期消息事件
//Sendtheperiodicmessage
SampleApp_SendPeriodicMessage();
//Setuptosendmessageagaininnormalperiod(+alittlejitter)
//这里为任务SampleApp_TaskID的事件SAMPLEAPP_SEND_PERIODIC_MSG_EVT设定一个定时器,定时时间为
(SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT+(osal_rand()&
0x00FF)),当时间一到,该运行的任务将被通报有事件发生。
osal_start_timerEx(SampleApp_TaskID,SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
(SAMPLEAPP_SEND_PERIOD