static void zclProcessMessageMSG( afIncomingMSGPacket_t *pkt )<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
{
…………
//首先检查命令域的数据长度,如果没有数据则直接退出
if ( pkt->cmd.DataLength == 0 )
return; // Error, ignore the message
…………
//然后检查消息的目的终端是否存在于节点上,若不是发送给此节点的则退出
epDesc = afFindEndPointDesc( pkt->endPoint );
if ( epDesc == NULL )
return; // Error, ignore the message
//将簇ID转换到逻辑簇ID,如果为0xFFFF则退出
logicalClusterID = zclConvertClusterID( pkt->clusterId, epDesc->simpleDesc->AppProfId, TRUE );
if ( logicalClusterID == ZCL_INVALID_CLUSTER_ID )
return; // Error, ignore the message
//检查设备是否可操作,即检查DEVICE_ENABLED属性
if ( zcl_DeviceOperational( pkt->endPoint, pkt->clusterId,
inMsg.hdr.fc.type, inMsg.hdr.commandID ) == FALSE )
{
return; // Error, ignore the message
}
//一下是处理和解析收到的命令
if ( zcl_ProfileCmd( inMsg.hdr.fc.type ) )
{//收到的是针对剖面的命令比如读写属性,报告属性,身份认证等
if ( inMsg.hdr.fc.manuSpecific )
{
// We don't support any manufacturer specific command
//不支持生产商的特定命令
status = ZCL_STATUS_UNSUP_MANU_GENERAL_COMMAND;
}
else if ( ( inMsg.hdr.commandID <= ZCL_CMD_MAX ) &&
( zclCmdTable[inMsg.hdr.commandID].pfnParseInProfile != NULL ) )
{//接收到的命令ID小于最大命令ID,并且命令表中此命令定义了解析函数,则解析并处理此命令
zclParseCmd_t parseCmd;
parseCmd.endpoint = pkt->endPoint;
parseCmd.dataLen = inMsg.pDataLen;
parseCmd.pData = inMsg.pData;
// Parse the command, remember that the return value is a pointer to allocated memory
inMsg.attrCmd = zclParseCmd( inMsg.hdr.commandID, &parseCmd );
if ( (inMsg.attrCmd != NULL) && (zclCmdTable[inMsg.hdr.commandID].pfnProcessInProfile != NULL) )
{
// Process the command
if ( zclProcessCmd( inMsg.hdr.commandID, &inMsg ) == FALSE )
{//处理此命令不成功
// Couldn't find attribute in the table.
}
………………
}
else
{//处理此簇ID的特殊命令
// Nope, must be specific to the cluster ID
//为实际的簇ID查找合适的插头
// Find the appropriate plugin
pInPlugin = zclFindPlugin( pkt->clusterId, epDesc->simpleDesc->AppProfId );
//在这个查找插头的函数中关联了一个静态变量plugins,这个变量中指明了插头的范围以及处理输入消息的函数,其数据结构定义为:【zcl.c】
typedef struct zclLibPlugin
{
struct zclLibPlugin *next;
uint16 startLogCluster; // starting logical cluster ID
uint16 endLogCluster; // ending logical cluster ID
zclInHdlr_t pfnIncomingHdlr; // function to handle incoming message
} zclLibPlugin_t;
//在zclSampleLight_Init()中我们通过调用zclGeneral_RegisterCmdCallbacks()来注册了插头:
//…………
// zcl_registerPlugin( ZCL_GEN_LOGICAL_CLUSTER_ID_BASIC,
// ZCL_GEN_LOGICAL_CLUSTER_ID_LOCATION,
// zclGeneral_HdlIncoming );
//…………
ZStatus_t zcl_registerPlugin( uint16 startLogCluster,
uint16 endLogCluster, zclInHdlr_t pfnIncomingHdlr )
{
…………
// Find spot in list
//在这个函数中我们对静态变量plugins进行了填充
if ( plugins == NULL )
{
plugins = pNewItem;
}
else
{
// Look for end of list
pLoop = plugins;
while ( pLoop->next != NULL )
pLoop = pLoop->next;
// Put new item at end of list
pLoop->next = pNewItem;
}
return ( ZSuccess );
}
//对应的回调函数zclGeneral_HdlIncoming()首先检查接收的消息是否是簇的特定命令,然后调用zclGeneral_HdlInSpecificCommands()来处理不同的命令:
static ZStatus_t zclGeneral_HdlInSpecificCommands( zclIncoming_t *pInMsg, uint16 logicalClusterID )
{
ZStatus_t stat;
switch ( logicalClusterID )
{//逻辑簇ID存在是进行判断的基础
………………
#ifdef ZCL_ON_OFF
//调用处理开关簇的处理函数
case ZCL_GEN_LOGICAL_CLUSTER_ID_ON_OFF:
stat = zclGeneral_ProcessInOnOff( pInMsg );
static ZStatus_t zclGeneral_ProcessInOnOff( zclIncoming_t *pInMsg )
{
zclGeneral_AppCallbacks_t *pCBs;
if ( zcl_ServerCmd( pInMsg->hdr.fc.direction ) )
{//只处理服务器方向,因为对于开关簇来说,灯是作为服务端,被其他设备控制的
if ( pInMsg->hdr.commandID > COMMAND_TOGGLE )
return ( ZFailure ); // Error ignore the command
pCBs = zclGeneral_FindCallbacks( pInMsg->msg->endPoint );
//通过终端号来查找相应的命令回调函数,在这个查找命令回调函数的函数中又调用了一个静态变量zclGenCBs,这个变量保存着终端与命令回调函数的对应,其数据结构如下:
typedef struct zclGenCBRec
{
struct zclGenCBRec *next;
uint8 endpoint; // Used to link it into the endpoint descriptor
zclGeneral_AppCallbacks_t *CBs; // Pointer to Callback function
} zclGenCBRec_t;
//这个变量在zcl应用任务初始化注册回调函数时也同时注册了:
ZStatus_t zclGeneral_RegisterCmdCallbacks( uint8 endpoint, zclGeneral_AppCallbacks_t *callbacks )
{
………………
// Fill in the new profile list
pNewItem = osal_mem_alloc( sizeof( zclGenCBRec_t ) );
if ( pNewItem == NULL )
return (ZMemError);
pNewItem->next = (zclGenCBRec_t *)NULL;
pNewItem->endpoint = endpoint;
pNewItem->CBs = callbacks;
// Find spot in list
if ( zclGenCBs == NULL )
{
zclGenCBs = pNewItem;
}
else
{
// Look for end of list
pLoop = zclGenCBs;
while ( pLoop->next != NULL )
pLoop = pLoop->next;
// Put new item at end of list
pLoop->next = pNewItem;
}
return ( ZSuccess );
}
//这些注册的命令回调函数都是属于一个终端的,一个终端中有多个命令回调函数,那么如何区分到底应该调用哪个回调函数呢?接着往下看:
if ( pCBs && pCBs->pfnOnOff )
pCBs->pfnOnOff( pInMsg->hdr.commandID );
//上面两句进行判断和调用,如果开关簇的命令回调函数存在则进行调用。所以在对回调函数数据结构zclGeneral_AppCallbacks_t进行填充时需要把用到的簇的回调函数填充,没有用到的填为NULL,而且要安全按照定义中簇的顺序来填充。
}
// no Client command
return ( ZSuccess );
}
break;
#endif // ZCL_ON_OFF
………………
default:
stat = ZFailure;
break;
}
return ( stat );
}
if ( pInPlugin && pInPlugin->pfnIncomingHdlr )
{
zclInHdlrMsg_t inHdlrMsg;
inHdlrMsg.msg = &inMsg;
inHdlrMsg.logicalClusterID = logicalClusterID;
status = pInPlugin->pfnIncomingHdlr( &inHdlrMsg );
if ( status == ZCL_STATUS_CMD_HAS_RSP )
return; // We're done
}
if ( status != ZSuccess )
{
// Unsupported message
if ( inMsg.hdr.fc.manuSpecific )
status = ZCL_STATUS_UNSUP_MANU_CLUSTER_COMMAND;
else
status = ZCL_STATUS_UNSUP_CLUSTER_COMMAND;
}
}
……………………
}
//总结一下:应用层收到数据——ZCL事件处理循环zcl_event_loop收到系统事件消息AF_INCOMING_MSG_CMD——调用消息处理函数zclProcessMessageMSG()——根据命令中帧控制域指示的命令类型分别进入剖面命令或簇命令处理,首先在其数据结构中查找是否有相接收到的命令想匹配的命令项『剖面命令通过zclCmdTable查找相应的回调函数,调用回调函数处理;簇命令通过zclInHdlrMsg_t查找相应的插头』——在zclCmdTable或者plugins中找到对应的项——检查相应的项中是否有回调函数——调用相应项中的回调函数对设备进行操作——如果需要发送应答则发送应答
文章评论(0条评论)
登录后参与讨论