uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )

来源:互联网 发布:万能网络监控客户端 编辑:程序博客网 时间:2024/05/22 13:22


/*

* @fnSampleApp_ProcessEvent

* @brief Generic Application Task event processor. This function

* is called to process all events for the task. Events

* include timers, messages and any other user defined events.

* @paramtask_id - The OSAL assigned task ID.任务ID

* @param events - events to process. This is a bit map and can

* contain more than one event. 处理的事件,这是一个位图

* @return none

*/

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