4.6.3 Sending ZDP Requests
Zigbee Device Profile (ZDP) requests offer a set of functionalities to manage the network, discover devices and services, and more.
The ZDO_ZdpReq() function sends out a ZDP request. The reqCluster
field within a ZDO_ZdpReq_t type instance, which represents the request parameters, determines the specific action the function performs. The function accepts additional request parameters in the req.reqPayload
field. This field is a union, allowing the same memory space to accommodate parameters for different types of requests.
The following sections provide some examples of issuing ZDP requests of various types. For additional sample application code examples that come with the SDK, go to wireless_apps_pic32cxbz2_wbz45.
Device Discovery Requests
In Zigbee application development, two common tasks include retrieving the extended address of a remote device using a known short address and finding the short address of a device with a known extended address. The user accomplishes these tasks using ZDP requests of the IEEE_ADDR_CLID
and NWK_ADDR_CLID
types, respectively. For instance, to retrieve the extended address, the user can employ the following code:
ZDO_IeeeAddrReq_t *ieeeAddrReq = &zdpReq.req.reqPayload.ieeeAddrReq; zdpReq.ZDO_ZdpResp = zdpIeeeAddrResp; //confirmation callback function zdpReq.reqCluster = IEEE_ADDR_CLID; //type of request ieeeAddrReq->nwkAddrOfInterest = nwkAddr; //the destination short address ieeeAddrReq->reqType = SINGLE_RESPONSE_REQUESTTYPE; //indicate that response is expected from//one node only - and not from its children ieeeAddrReq->startIndex = 0; ZDO_ZdpReq()(&zdpReq); //send the request
static void zdpIeeeAddrResp(ZDO_ZdpResp_t *resp) { //Convert the response to the appropriate type ZDO_IeeeAddrResp_t *ieeeAddrResp = (ZDO_IeeeAddrResp_t *) &resp->respPayload.ieeeAddrResp; //Check whether the operation is a success if (ZDO_SUCCESS_STATUS == resp->respPayload.status) { //The desired extended address is contained in ieeeAddrResp->ieeeAddrRemote field ... //Perform actions that required obtaining the address //Post a task to notify the stack that for an appropriate task to be executed SYS_PostTask(...); } else { //Execute required logic, e.g. perform IEEE request again } }
respPayload
field.Service Discovery Requests
Service discovery stands for the procedures of collecting information about the network devices and functionality (clusters) they support. With service discovery, the application on the current node discovers short addresses of devices that support certain input or output clusters and accomplish some other similar tasks.
A crucial ZDP request for implementing service discovery, commonly required in applications, is the MATCH_DESCRIPTOR_CLID
type. This request initiates a search for devices with registered endpoints that support the designated clusters. The application sends the request to a particular node using its short address or to a broadcast address. While the application can list multiple input and output clusters, it typically proves unnecessary to mention more than one cluster. This is because the target node replies with a list of all its endpoints that support any of the input or output clusters mentioned in the request.
The following code issues a match descriptor request:
//define global variables static ZDO_ZdpReq_t zdpReq; ... ZDO_MatchDescReq_t *matchDescReq = &zdpReq.req.reqPayload.matchDescReq; zdpReq.ZDO_ZdpResp = zdpMatchDescResp; //confirmation callback zdpReq.reqCluster = MATCH_DESCRIPTOR_CLID; //set request type matchDescReq->nwkAddrOfInterest = CPU_TO_LE16(BROADCAST_SHORT_ADDRESS); matchDescReq->profileId = CPU_TO_LE16(APP_PROFILE); //set profile ID matchDescReq->numInClusters = 1; //number of clusters matchDescReq->inClusterList[0] = APP_CLUSTER; //set cluster ID ZDO_ZdpReq(&zdpReq); //send the request
Each reply from a discovered device received by the request's originator causes the confirmation callback to be called. As soon as the request is issued, the stack starts a timer and waits for replies during a period of time specified in the CS_ZDP_RESPONSE_TIMEOUT
parameter. When the timer elapses, the stack fires the callback with the ZDO_CMD_COMPLETED_STATUS
status code. The stack calculates the default CS_ZDP_RESPONSE_TIMEOUT
value in such a way that the devices sleeping at the moment the request is sent are not expected to have time to awake and answer the request. The request reaches only active devices.
Each response contains the short address, the number of matching endpoints and the list of matching endpoints. The confirmation callback’s implementation can be like this:
When the request’s originator receives a reply from a discovered device, it triggers the confirmation callback. The stack initiates a timer immediately after issuing the request and waits for responses within the timeframe set by the CS_ZDP_RESPONSE_TIMEOUT
parameter. After the timeframe elapses, the stack activates the callback with the ZDO_CMD_COMPLETED_STATUS
status code. The stack calculates the default value of CS_ZDP_RESPONSE_TIMEOUT
to exclude devices that are asleep at the time of the request as they are unlikely to wake up and respond in time. Therefore, the request typically reaches only active devices.
Each response includes the short address, the number of matching endpoints and the list of those endpoints. The implementation of the confirmation callback looks as follows:
//A callback function for the ZDP match descriptor request static void zdpMatchDescResp(ZDO_ZdpResp_t *resp) { ZDO_MatchDescResp_t *matchResp = &resp->respPayload.matchDescResp; if (ZDO_CMD_COMPLETED_STATUS == resp->respPayload.status) { //timeout has expired; this is the last time the callback is called //for the current request } else if (ZDO_SUCCESS_STATUS == resp->respPayload.status) { //process another response from the network: for example, the application //can immediately send a ZDP request to obtain the extended address of the device doIeeeAddrReq(); } else { //process failure statuses } }
Leaving the Network
To force a device to exit the network, send a ZDP request of the MGMT_LEAVE_CLID
type. This request also serves to make a remote node leave the network. A node that exits the network becomes unreachable by remote data requests and cannot send data to remote nodes from the application layer. To rejoin the network, the node must initiate a network start request. To increase the likelihood of selecting the same network during network scan procedures, save the PANID value of the previous network before exiting and specify it as predefined during the rejoining process.
The following example shows how to configure parameters for the MGMT_LEAVE_CLID
request to force the current node to leave the network:
static ZDO_ZdpReq_t zdpLeaveReq; //globally defined variable ... //set corresponding cluster ID zdpLeaveReq.reqCluster = MGMT_LEAVE_CLID; zdpLeaveReq.dstAddrMode = EXT_ADDR_MODE; zdpLeaveReq.dstExtAddr = 0; // for own node address shall be 0 zdpLeaveReq.ZDO_ZdpResp = ZDO_ZdpLeaveResp; // callback//for own node address shall be 0 zdpLeaveReq.req.reqPayload.mgmtLeaveReq.deviceAddr = 0; //specify whether to force children leave or not zdpLeaveReq.req.reqPayload.mgmtLeaveReq.removeChildren = 0; //specify whether to perform rejoin procedure after network leave zdpLeaveReq.req.reqPayload.mgmtLeaveReq.rejoin = 0; ZDO_ZdpReq(&zdpLeaveReq); // request for network leave
static ZDO_ZdpReq_t zdpLeaveReq; //globally defined variable ... //set corresponding cluster ID zdpLeaveReq.reqCluster = MGMT_LEAVE_CLID; zdpLeaveReq.dstAddrMode = EXT_ADDR_MODE; zdpLeaveReq.dstExtAddr = DST_EXT_ADDRESS; //for own node address shall be 0 zdpLeaveReq.ZDO_ZdpResp = ZDO_ZdpLeaveResp; //confirmation callback//for own node should be 0 (or equal own address) zdpLeaveReq.req.reqPayload.mgmtLeaveReq.deviceAddr = DST_EXT_ADDRESS; //specify whether to force children leave or not zdpLeaveReq.req.reqPayload.mgmtLeaveReq.removeChildren = 1; //specify whether to perform rejoin procedure after network leave zdpLeaveReq.req.reqPayload.mgmtLeaveReq.rejoin = 0; ZDO_ZdpReq(&zdpLeaveReq); // request for network leave
rejoin
field is set to 1
, then a destination node attempts to join the network again after the completing the network leave process. Use this to force a device to change its parent or to join with a different short address.