uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )代码分析

来源:互联网 发布:网络信息化建设需求 编辑:程序博客网 时间:2024/05/29 06:54

uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )

{

afIncomingMSGPacket_t *MSGpkt;

//系统事件号 SYS_EVENT_MSG = 0x8000

if ( events & SYS_EVENT_MSG )

{

//检索收到的命令,没有收到返回NULL

MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );

while ( MSGpkt ) //如果不为空时,判断消息的类型

{

switch ( MSGpkt->hdr.event ) //这里是判断SYS_EVENT_MSG事件类型,不同的SYS_EVENT_MSG类型需要不同的处理。

{

/* Received when a key is pressed这里判断是否是键盘事件,如果键盘事件就调用键盘处理函数。
如果一个OSAL任务已经被登记组侧,那么任何键盘事件都将接受一个KEY_CHANGE事件信息。可能有如下几种方式得到键盘事件信息
1)、HAL检测到键盘按下(中断或者查询检测)
2)、HALOSAL任务检测到一个键盘状态改变调用回叫函数产生
3)、OSAL键盘改变回叫函数发送一个OSAL系统事件信息(KEY_CHANGE)。*/

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;

// Received whenever the device changes state in the network 网络中的设备状态发生改变时,产生的事件消息

case ZDO_STATE_CHANGE:

SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status); //获得当前的状态

if ( (SampleApp_NwkState == DEV_ZB_COORD) //判断其类型

|| (SampleApp_NwkState == DEV_ROUTER)

|| (SampleApp_NwkState == DEV_END_DEVICE) )

{

// Start sending the periodic message in a regular interval. 发送周期信息

osal_start_timerEx(SampleApp_TaskID, 

SAMPLEAPP_SEND_PERIODIC_MSG_EVT,

SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );

}

else

{

// Device is no longer in the network

}

break;

default:

break;

}

// Release the memory 释放内存

osal_msg_deallocate( (uint8 *)MSGpkt );

// Next - if one is available 得到任务中下一个等待处理的事件

MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );

}

// return unprocessed events 返回没有处理的事件

return (events ^ SYS_EVENT_MSG);

}

// Send a message out - This event is generated by a timer

// (setup in SampleApp_Init()). 向外发送信息,该事件是由定时器产生

if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )

{

// Send the periodic message 发送周期信息

SampleApp_SendPeriodicMessage();

// Setup to send message again in normal period (+ a little jitter) 第三个参数是定时的时间

osal_start_timerEx(SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,

(SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );

// return unprocessed events 返回没有处理的事件

return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);

}

// Discard unknown events

return 0;

}

说明:(1)afIncomingMSGPacket_t *MSGpkt; 其中afIncomingMSGPacket_t是一个结构体,这个结构体中包括传输的帧的格式。

typedefstruct

{

osal_event_hdr_thdr;

uint16groupId;

uint16clusterId;

afAddrType_tsrcAddr;

byteendPoint;

bytewasBroadcast;

byteLinkQuality;

byteSecurityUse;

uint32 timestamp;

afMSGCommandFormat_tcmd;

} afIncomingMSGPacket_t;

(2) 这里的SYS_EVENT_MSG是系统事件,也是协议栈已经定义好的系统事件,在文件ZcomDef.h中,事件号是一个16bit的常量,使用叫作独热码(one-hot code)编码,也是一个位表示一个事件,方便进行event的提取,这样一个task最多可以有16eventSYS_EVENT_MSG已经占用了0x8000,故自定义的个事件只能有15个,事件的提取和清除可以用简单的位操作指令实现,事件的提取可以用位与操作 events & SYS_EVENT_MSG,事件的清除可以用异或操作实现,evets ^ SYS_EVENT_MSG ,系统事件包括了各种系统消息(message,系统事件中的消息号是一个8bit常量,也就是一事件可以包括255个消息,定义在ZcomDef.h中。

#define SYS_EVENT_MSG 0x8000 // A message is waiting event

/*

* Global System Messages

*/

#define SPI_INCOMING_ZTOOL_PORT 0x21 // Raw data from ZTool Port (not implemented)

#define SPI_INCOMING_ZAPP_DATA 0x22 // Raw data from the ZAPP port (see serialApp.c)

#define MT_SYS_APP_MSG 0x23 // Raw data from an MT Sys message

#define MT_SYS_APP_RSP_MSG 0x24 // Raw data output for an MT Sys message

#define AF_DATA_CONFIRM_CMD 0xFD // Data confirmation

#define AF_INCOMING_MSG_CMD 0x1A // Incoming MSG type message

#define AF_INCOMING_KVP_CMD 0x1B // Incoming KVP type message

#define AF_INCOMING_GRP_KVP_CMD 0x1C // Incoming Group KVP type message

#define KEY_CHANGE 0xC0 // Key Events

#define ZDO_NEW_DSTADDR 0xD0 // ZDO has received a new DstAddr for this app

#define ZDO_STATE_CHANGE 0xD1 // ZDO has changed the device's network state

#define ZDO_MATCH_DESC_RSP_SENT 0xD2 // ZDO match descriptor response was sent

#define ZDO_CB_MSG 0xD3 // ZDO incoming message callback

用户自己定义的系统事件的消息范围为0xE0—0xFF,下面是几个比较常用的系统事件的消息。

 AF_DATA_CONFIRM_CMD
调用AF_DataRequest()函数数据请求成功的指示。Zsuccess确认数据请求传输成功,如果数据请求设置AF_ACK_REQUEST标志位,那么,只有最终目的地址成功接收后,Zsuccess确认才返回。如果如果数据请求没有设置AF_ACK_REQUEST标志位,那么,数据请求只要成功传输到下跳节点就返回Zsuccess确认信息。

 AF_INCOMING_MSG_CMD 收到MSG消息,通知任务进行处理

 KEY_CHANGE 按键处理事件

 ZDO_NEW_DSTADDR 新的目标地址接收到指示自动匹配请求绑定时经常使用

 ZDO_STATE_CHANGE 设备状态变化指示

3osal_start_timerEx( SampleApp_TaskID,

SAMPLEAPP_SEND_PERIODIC_MSG_EVT,

SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );

osal_start_timerEx()的作用是启动一系统定时器,当其溢出 SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT)时,会触发tasSampleApp_TaskID)的事件 SAMPLEAPP_SEND_PERIODIC_MSG_EVT)。看到事件SAMPLEAPP_SEND_PERIODIC_MSG_EVT了,它是用户定义的事件,分析之

if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )

{

// Send the periodic message

SampleApp_SendPeriodicMessage();

// Setup to send message again(为什么重新发送) in normal period (+ a little jitter)

osal_start_timerEx(SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,

(SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );

// return unprocessed events

return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT); }

以上就是SAMPLEAPP_SEND_PERIODIC_MSG_EVT的处理函数,先分析总的流程,SampleApp_SendPeriodicMessage();发送信息,osal_start_timerEx()重新启动一系统定时 器,同样是指向taskSampleApp_TaskID)的事件(SAMPLEAPP_SEND_PERIODIC_MSG_EVT),返回时要注意清除当前事件 (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT),否则会反复处理同一个事件,陷入死循环

SampleApp.h中定义

#define SAMPLEAPP_SEND_PERIODIC_MSG_EVT 0x0001

在这个例子中,调用了osal_start_timerEx()函数来定时产生发送周期信息事件,而定时器的运行是设备一旦加入网络就不停的运行,用函数SampleApp_SendPeriodicMessage();发送周期信息,而用函数osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,

(SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );

来继续运行定时器定时发送一个周期信息,osal_start_timerEx()函数,第一个参数是处理事件的任务ID号,第二个参数是事件的类型,也就是事件是一个什么事件,第三个参数是需要定时时间,发送周期信息的时间周期。

 

4void SampleApp_SendPeriodicMessage(void)定时器发送周期信息的函数里调用了AF_DataRequest()函数用来发送数据,发送数据的过程是把数据从应用层传到网络层,再传到MAC,再传到物理层,最后通过OTA发送出去,接收的过程是相反的过程,在接收到消息后在应用层的反应就是,会发送一个AF_INCOMING_MSG_CMD消息事件,case AF_INCOMING_MSG_CMD:

SampleApp_MessageSGCB(MSGpkt);

Break;

这里表示收到某个信息,然后在里面调用了收到信息后的处理函数。SampleApp_MessageSGCB(MSGpkt);

void SampleApp_SendPeriodicMessage(void)这个函数主要就是调用发送数据的函数AF_DataRequest()对数据进行发送。

/*

* @fnSampleApp_SendPeriodicMessage

* @brief Send the periodic message.

* @param none

* @return none

*/

voidSampleApp_SendPeriodicMessage( void )

{

if ( AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc,

SAMPLEAPP_PERIODIC_CLUSTERID,

1,

(uint8*)&SampleAppPeriodicCounter,

&SampleApp_TransID,

AF_DISCV_ROUTE,

AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )

{

}

else

{

// Error occurred in request to send.

}

}

5case AF_INCOMING_MSG_CMD: 
SampleApp_MessageMSGCB( MSGpkt ); 
break; 
这里表示收到某个信息,然后在里面调用了收到信息的信息处理函数SampleApp_MessageMSGCB( MSGpkt )

/*

* @fnSampleApp_MessageMSGCB

* @brief Data message processor callback. This function processes

* any incoming data - probably from other devices. So, based

* on cluster ID, perform the intended action.

* @param none

* @return none

*/

voidSampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )

{

uint16flashTime;

switch ( pkt->clusterId )

{

case SAMPLEAPP_PERIODIC_CLUSTERID:

break;

case SAMPLEAPP_FLASH_CLUSTERID:

flashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] );

HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) );

break; 

}

}

这里判断了两种信息:周期信息;闪灯信息,根据它们的簇ID号的不同做出不同的处理。不同的信息就相当于收到了不同的命令,然后根据不同的命令做出了不同的处理

 

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 埋汰人的句子 埋汰一个人什么意思 埋汰人的话 走路依旧深埋在她里面 我曾深埋相思意 若爱深埋于岁月 走路还深埋在里面h 舌头濡湿深埋炙热甜梦 楼梯走路还深埋在里面h 基础埋深 总裁深埋在她身体里 红颜深埋这座城 深埋 走路还深埋体内总裁 我曾深埋相思意全文免费阅读 若爱深埋于岁月 莫问 若爱深埋于岁月沈知夏 天然气管道埋深 立柱埋深检测仪 基础埋深怎么确定 若爱深埋于岁月免费阅读 我曾深埋相思意免费 天然气管道埋深要求 幸福魔方孽债深埋 幸福魔方孽债深埋的爱 总裁走路依旧深埋体内 标准地线的接法深埋地下图 埋点 埋珠 双珠 卫生间排水管预埋尺寸 埋管双眼皮 直缝双面埋弧焊管 预制直埋式保温管厂家 空调预埋管 直埋式预制保温管 直埋预制蒸汽保温管 聚氨酯直埋保温管厂家 预埋管 直埋管 预制聚氨酯直埋保温管