Z-Stack协议中命令的概念

命令就是为了实现某种特定的通信而指定的一种强制性的通信方式。在SimpleApp的例子中定义了一个命令:在SimpleApp.h

#define TOGGLE_LIGHT_CMD_ID               1

    这个是灯状态切换的一个命令,也可以说是一个串或者簇,ID1.

作为灯设备来说,该命令是输入命令,所以定义在输入命令 列表中:在文件SimpleController.c

const cId_t zb_InCmdList[NUM_IN_CMD_CONTROLLER] =

{

  TOGGLE_LIGHT_CMD_ID

};

该设备的简单描述符定义为:

const SimpleDescriptionFormat_t zb_SimpleDesc =

{

  MY_ENDPOINT_ID,             //  端点(2

  MY_PROFILE_ID,              //  Profile ID 0x0F10

  DEV_ID_CONTROLLER,          //  设备ID

  DEVICE_VERSION_CONTROLLER,  //  设备版本

  0,                          //  保留

  NUM_IN_CMD_CONTROLLER,      //  输入命令数量(1

  (cId_t *) zb_InCmdList,     //  输入命令列表

  NUM_OUT_CMD_CONTROLLER,     //  输出命令数量(2

  (cId_t *) NULL              //  输出命令列表(空)

};

 

作为开头设备,该命令为输出命令,所以定义在输入命令列表中:

const cId_t zb_OutCmdList[NUM_OUT_CMD_SWITCH] =

{

  TOGGLE_LIGHT_CMD_ID

};

该设备的简单描述符定义为:

const SimpleDescriptionFormat_t zb_SimpleDesc =

{

  MY_ENDPOINT_ID,             //  端点(2

  MY_PROFILE_ID,              //  Profile ID

  DEV_ID_SWITCH,              //  设备ID

  DEVICE_VERSION_SWITCH,      //  设备版本

  0,                          //  保留

  NUM_IN_CMD_SWITCH,          //  输入命令数量(0

  (cId_t *) NULL,             //输入命令列表(空)

  NUM_OUT_CMD_SWITCH,         //  输出命令数量(1

  (cId_t *) zb_OutCmdList               //  输出命令列表

};

 

描述符定义好后,需要调用函数afRegister()登记一个EP描述符

afStatus_t afRegister( endPointDesc_t *epDesc )

{

  epList_t *ep = afRegisterExtended( epDesc, NULL );

  return ((ep == NULL) ? afStatus_MEM_FAIL : afStatus_SUCCESS);

}

 

     该函数是在任务初始化函数中SAPI_Init()中被调用的。这样就可以使用该端点了,从而可以使用该命令。命令的发送是通过函数zb_SendDataRequest()发送。

//参数:目的地址,命令ID,数据长度,数据,句柄,发送选项,半径

void zb_SendDataRequest ( uint16 destination, uint16 commandId, uint8 len,

                          uint8 *pData, uint8 handle, uint8 txOptions, uint8 radius )

{

  afStatus_t status;

  afAddrType_t dstAddr;

 

  txOptions |= AF_DISCV_ROUTE;

 

  // 设置目的地址

  if (destination == ZB_BINDING_ADDR)

  {

    // 绑定的模式

    dstAddr.addrMode = afAddrNotPresent;

  }

  else

  {

    // 使用短地址

    dstAddr.addr.shortAddr = destination;

    dstAddr.addrMode = afAddr16Bit;

 

    if ( ADDR_NOT_BCAST != NLME_IsAddressBroadcast( destination ) )

    {

      txOptions &= ~AF_ACK_REQUEST;

    }

  }

 

  // 设置目的端点

  dstAddr.endPoint = sapi_epDesc.simpleDesc->EndPoint;

 

  // 发送信息

  status = AF_DataRequest(&dstAddr, &sapi_epDesc, commandId, len,

                          pData, &handle, txOptions, radius);

 

  if (status != afStatus_SUCCESS)

  {

    SAPI_SendCback( SAPICB_DATA_CNF, status, handle );

  }

}

         在代码中可以知道,发送数据调用了AF_DataRequest()函数。由于该实验是基于绑定的命令传输,所以目的地址为指定的0xFFFE,这样设备将自动地去绑定表格中的查找真正的目的地址,如果绑定表格中有多于一个的目的地址,那么该信息将被复制多次分别发送出去。那这里为什么是0xFFFE呢,在Simple API for Z-Stack 文档中,可看到下面的一段话,也许可以说明这个问题。

zb_SendDataRequest( 0xFFFE, TOGGLE_LIGHT_CMD_ID, 0,

                        (uint8 *)NULL, myAppSeqNumber, 0, 0 );

Once a binding is created on the source device, the application can send data without specifying a destination address (in the call to zb_SendDataRequest(), the invalid address - 0xFFFE should be used as the destination ). This will cause the stack to look up the destination in its internal binding table based on the command identifier of the packet. 

 只要在源设备上建立绑定后,应用就可以在不指定目的地址的情况下发送数据。(这时候用无效地址0xfffe)这时候协议栈将会依据数据包的命令标识符来寻找内部的绑定表。

    一个簇实际上是一些相关命令和属性的集合,这些命令和属性一起定义为指定的功能。典型地,簇的属性存储实体是作为服务器,而属性采集或处理实体被作为客机。但是,如果需要,属性可以在簇客机上被呈现。  

    这里有一个例子:读和写属性命令,它允许设备处理属性,从客机设备发送该属性,服务器设备接收,任何对于该命令的应答(读和写属性响应命令)都是从服务器发送,客机接收,反之,动态的属性报告命令从服务器设备发送,客机接收 

     该例子中的TOGGLE_LIGHT_CMD_ID命令和SENSOR_REPORT_CMD_ID命令,实际上就是两个簇。

         ZCLZigBee cluster librara)。在ZigBee中,ZCL担当一个仓库的角色。通过ZCL的应用,可以直接通过命令控制各个功能的实现,在系统中首先对簇库进行设置,根据不同的ID设置不同的功能。这样ID和功能形成了一一对应的关系,在无线控制的过程中,就不 需要传输大量的命令,只需要传输簇ID,然后通过簇ID,判断需要执行的命令就可以了,这样,既保证了数据的安全性和通信可靠性,又提高了通信的效率。

     簇也是ZigBee协议中比较重要的概念,也是比较难理解的一个概念,这里的簇也就是我们上面定义的命令,不过不仅仅包括这,还有和它一起的属性值。那这些属性就会包括输入族的数目,输出簇的数目,输入簇,输出簇的列表等。那这样为什么又能提高通信的质量呢?我们通过簇ID可以看出,在设备中都定义了簇库,簇ID和其中的功能一一对应,这样我们只需要传输簇ID,当接收到簇ID时,接收端根据簇ID查找其对应的功能,执行相应的操作。在程序中我们也可以看到,下面是数据的发送函数,无线数据的发送都是通过下面的函数发送的,我们可以看到其中之一的参数 cID ,就是簇ID

afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP,

                           uint16 cID, uint16 len, uint8 *buf, uint8 *transID,

                           uint8 options, uint8 radius )

下面是发送命令其中的簇ID就是定义过的TOGGLE_LIGHT_CMD_ID。其原型如下:

zb_SendDataRequest ( uint16 destination, uint16 commandId, uint8 len,

                          uint8 *pData, uint8 handle, uint8 txOptions, uint8 radius )

下面是调用该函数的参数状态。

  zb_SendDataRequest( 0xFFFE, TOGGLE_LIGHT_CMD_ID, 0,

                        (uint8 *)NULL, myAppSeqNumber, 0, 0 );

最后调用真正的发送函数AF_DataRequest()函数,其中的commandId也就是上面的TOGGLE_LIGHT_CMD_ID命令

AF_DataRequest(&dstAddr, &sapi_epDesc, commandId, len,

                          pData, &handle, txOptions, radius);

那么在接收方我们也命令了这个命令,只不过是作为输入命令定义的。这样就可以和发送端的簇ID一一对应了。在接收端点,也就是灯。可以看到接收到簇ID的后,就可以看到下面的处理。

void zb_ReceiveDataIndication( uint16 source, uint16 command, uint16 len, uint8 *pData  )

{

  if (command == TOGGLE_LIGHT_CMD_ID)

  {

    // Received application command to toggle the LED

    HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE);

  }

}

 


 

 结束

你可能感兴趣的:(stack)