该project实现了按键发送的功能。
同时实现了信息的广播和组播:
SampleApp_SendPeriodicMessage( void ); //阶段发送,广播形式
SampleApp_SendFlashMessage(); //闪烁发送,组播形式
同时按键up键可以进行控制信息的发送,即控制Group1中所有设备的LED1灯的闪烁时间。
按键right键进行设备加入/退出Group1的切换。
由于在SampleApp_Init( uint8 task_id )中添加了SampleApp_Init( taskID );(最后一个任务)
在操作系统启动的过程中,调用SampleApp_Init( uint8 task_id )
调用顺序:main( void )->osal_init_system();->osalInitTasks()->SampleApp_Init( taskID );
void SampleApp_Init( uint8 task_id )
{
SampleApp_TaskID = task_id;
SampleApp_NwkState = DEV_INIT;
SampleApp_TransID = 0;
// Device hardware initialization can be added here or in main() (Zmain.c).
// If the hardware is application specific - add it here.
// If the hardware is other parts of the device add it in main().
#if defined ( BUILD_ALL_DEVICES )
// The "Demo" target is setup to have BUILD_ALL_DEVICES and HOLD_AUTO_START
// We are looking at a jumper (defined in SampleAppHw.c) to be jumpered
// together - if they are - we will start up a coordinator. Otherwise,
// the device will start as a router.
if ( readCoordinatorJumper() ) //根据P02和P03是否有跳线来判断是协调器还是路由器
zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
else
zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;
#endif // BUILD_ALL_DEVICES
#if defined ( HOLD_AUTO_START )
// HOLD_AUTO_START is a compile option that will surpress ZDApp
// from starting the device and wait for the application to
// start the device.
ZDOInitDevice(0); //开始启动设备,协调器建立网络此时LED3闪烁,别的设备加入网络,加入后LED3一直亮着,说明加入成功
#endif
// Setup for the periodic message's destination address //这儿设置了组播和广播的短地址以及填写了端点号
// Broadcast to everyone
SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;
SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF;
// Setup for the flash command's destination address - Group 1
SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup;
SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;
// Fill out the endpoint description.
SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_epDesc.task_id = &SampleApp_TaskID;
SampleApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc;
SampleApp_epDesc.latencyReq = noLatencyReqs;
// Register the endpoint description with the AF
afRegister( &SampleApp_epDesc ); //将填写好的端点向AF层进行注册,以便收到符合的消息时可以送到应用层
// Register for all key events - This app will handle all key events
RegisterForKeys( SampleApp_TaskID ); //注册所有的按键信息,由SampleApp_TaskID对应的SampleApp_ProcessEvent()进行处理
// By default, all devices start out in Group 1 //这儿填写的组的内容,如组名,组标识,然后加入SAMPLEAPP_ENDPOINT组中
SampleApp_Group.ID = 0x0001;
osal_memcpy( SampleApp_Group.name, "Group 1", 7 );
aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );
#if defined ( LCD_SUPPORTED )
HalLcdWriteString( "SampleApp", HAL_LCD_LINE_1 );
#endif
}
这样的初始工作就已经完成了,接下来的就是分析按键事件及响应过程了
首先当网络形成时,下层会向应用层发送消息ZDO_STATE_CHANGE它由SampleApp_ProcessEvent()进行处理
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;
可以看出它启动了一个定时器,每次时间到时会触发SAMPLEAPP_SEND_PERIODIC_MSG_EVT事件,它由SampleApp_ProcessEvent()进行处理
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_ProcessEvent()进行处理
case KEY_CHANGE:
SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );//进行本函数进行处理
break;
void SampleApp_HandleKeys( uint8 shift, uint8 keys )
{
(void)shift; // Intentionally unreferenced parameter
if ( keys & HAL_KEY_SW_1 )
{
SampleApp_SendFlashMessage( SAMPLEAPP_FLASH_DURATION ); //发送闪烁控制信息
}
if ( keys & HAL_KEY_SW_2 )
{
/* The Flashr Command is sent to Group 1.
* This key toggles this device in and out of group 1.
* If this device doesn't belong to group 1, this application
* will not receive the Flash command sent to group 1.
*/
aps_Group_t *grp;
grp = aps_FindGroup( SAMPLEAPP_ENDPOINT, SAMPLEAPP_FLASH_GROUP );//若已经加入组中,则退出组,若没有加入则加入
if ( grp )
{
// Remove from the group
aps_RemoveGroup( SAMPLEAPP_ENDPOINT, SAMPLEAPP_FLASH_GROUP ); //(该函数的源码不公开,只公布接口)
}
else
{
// Add to the flash group
aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );
}
}
}
再看 SampleApp_SendFlashMessage函数
void SampleApp_SendFlashMessage( uint16 flashTime ) //主要调用AF_DataRequest()函数发送
{
uint8 buffer[3];
buffer[0] = (uint8)(SampleAppFlashCounter++);
buffer[1] = LO_UINT16( flashTime );
buffer[2] = HI_UINT16( flashTime );
if ( AF_DataRequest( &SampleApp_Flash_DstAddr, &SampleApp_epDesc,
SAMPLEAPP_FLASH_CLUSTERID,
3,
buffer,
&SampleApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
{
}
else
{
// Error occurred in request to send.
}
}
别的设备在接受到后,仍然由SampleApp_ProcessEvent()进行处理
case AF_INCOMING_MSG_CMD:
SampleApp_MessageMSGCB( MSGpkt );
break;
可见它由 SampleApp_MessageMSGCB( MSGpkt );处理
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
uint16 flashTime;
switch ( pkt->clusterId )
{
case SAMPLEAPP_PERIODIC_CLUSTERID: //对于收到的广播信息,忽略
break;
case SAMPLEAPP_FLASH_CLUSTERID:
flashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] ); //对接受到的组播信息,控制LED4即LED1的闪烁
HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) );
break;
}
}
这样的话我们就搞清楚了其中的脉络,总之,他就是举了一个按键发送的简单的例子,循环发送广播信息,按UP发送组播信息。
对接收到的广播信息不予理睬,对收到的组播信息控制LED1的闪烁。
同时按键Right时进行设备加入/退出组的切换。