How to use built-in xbee programmable ZDO/ZCL support

I had similar questions to what was asked here. I am finding bits and pieces of documentation like:

http://xbee-sdk-doc.readthedocs.org/en/1.5.7/api_doc/

http://exsilium.github.io/xbee-sdk-doc/group__zcl__time.html

http://ftp1.digi.com/support/images/APP_NOTE_XBee_ZigBee_Device_Profile.pdf

that all give me a hint that there’s some ZDO/ZCL support that I don’t know how to use. For basic ZCL attributes, it seems like I can set up a table of objects and just have my code update the values, and then underlying software will handle things like ZDO requests (read, write, subscriptions, etc.).

I can’t really find examples of how that’s done, though.

That is because the functions you are referring to are external to the radio and need to exist within your application. Your best source for that is www.zigbee.org

Oh, I see. Aren’t these functions in the XBee Programmable API? For example, the API has a file zcl_time.c which has a Digi International copyright notice on it … inside that are methods like zcl_time_set(). I’m just trying to figure out how to use them …

The Basic and Identify cluster examples might be a little simpler or more straightforward to use as a reference.

The ZDO/ZCL support is powerful enough that you can implement whatever custom attribute/command/cluster/endpoint functionality you need but can get a little involved.

Is there a specific problem you’re trying to solve?

Sure, I can explain. I bought one of these:

Rainwise Tipping Bucket

and put an Xbee ZB Programmable inside the waterproof cylinder inside. I wrote a small, simple program to count pulses (and debounce them in software). To send data, I’ve taken a few liberties with ZDO and ZCL -mainly that I’m using a Report Attributes command but with no subscription requirement. There’s an implied “subscription” that changes should be sent as a Report Attribute to the coordinator.

To formulate the messages I built a little ZCL message builder library. It works like this:

void send() {
	int rc;
	int add_result;
	
	
	init_assembly_buffer(&asy, buf, sizeof(buf));
	
	add_zcl_header_with_mfg(&asy,
			0, /* frame control */
			0xBEEF, /* manufacturer id */
			seq++,
			ZCL_CMD_REPORT_ATTRIB);

        /* ADD AS MANY OF THESE AS WE WANT ATTRS IN THIS MESSAGE */
	add_result = add_zcl_attribute_float(&asy, 5, 123.4f);
	if(add_result == SIMPLE_ZCL_OK) {
		printf("Add float OK
");
	}
	
	
	/*
	 * Fill in the envelope
	 */
	wpan_envelope_create(&envelope, &xdev.wpan_dev, WPAN_IEEE_ADDR_COORDINATOR,
													WPAN_NET_ADDR_UNDEFINED);
	envelope.options = 0x00;
	envelope.cluster_id = 0x9999;
	envelope.profile_id = 0xAAAA;
	envelope.dest_endpoint = 0x40;
	envelope.source_endpoint = 0x40;
	envelope.payload = buf;
	envelope.length = zcl_builder_buflen(&asy);
	
	rc = wpan_envelope_send(&envelope);
	printf("send wpan_envelope_send() returned %d
", rc);	
}

So to answer your question: I have the feeling I shouldn’t have to do any of this … because the XBAee Programmable libraries will just let me declare that I have these attributes, and then the normal read/write/subscribe ZDO commands will just work.

is that true?

The declaration can be complicated.

You need to build up a structure going all the way from your attribute definition (with a callback to return its read value), to a list of attributes for your custom cluster, the cluster itself containing your attributes, the endpoint containing your cluster, and finally the overall endpoint structure for your node.

The best example to work from in the given source code for your case is likely identify.c/h.

Does a little more than you need (custom commands in addition to custom attribute) but it has a single attribute with read callback. Check out ZCL_CLUST_ENTRY_IDENTIFY_SERVER and zcl_identify_attribute_tree for your primary hooks in.

I’d recommend trying to integrate the identify server into your code, make sure you can read its attribute then morph it into something that fits with your specific needs. Change attribute type, callbacks, etc.

Suppose you set up a callback for a certain endpoint or cluster, like this:

const wpan_cluster_table_entry_t custom_ep_clusters[] = {
		{ 0x40, 
		cluster_40_handler,
		NULL,
		WPAN_CLUST_FLAG_INOUT },
		WPAN_CLUST_ENTRY_LIST_END
};

When the callback gets called, does the normal response generation still work if it’s a standard ZDO request like “read attribute”? Or am I responsible for generating the response?

#define ZCL_CLUST_ENTRY_IDENTIFY_SERVER
{ ZCL_CLUST_IDENTIFY,
&zcl_identify_command,
zcl_identify_attribute_tree,
WPAN_CLUST_FLAG_SERVER }

Where you have NULL is the attribute tree that defines your attribute. With that in place you wouldn’t need the custom handler unless, like the Identify cluster, you are adding additional custom commands. All of the attributes are automatically handled as specified in the attribute tree.

Take a look at how the attribute tree is defined for the Identify cluster and you should be able to piece together how to do something similar for your use-case.

Cool.

What happens if someone tries to use a command not supported by the SDK ZCL/ZDO layer? For example:

#define ZCL_CMD_CONFIGURE_REPORT				0x06

It looks like in zigbee_zcl.c in this function:

zigbee_zcl_debug
int zcl_general_command( const wpan_envelope_t FAR *envelope, void FAR *context)

that it falls through to:

return zcl_invalid_command( envelope);

Is it possible to have your callback handle this? Or, if I want to use subscriptions (reporting) would it be better to just have my callback handle everything?

I don’t believe the library comes with support for reporting. However, you can definitely add your own support especially if only for a limited subset of the functionality to make life simpler.

Refer to the zcl_identify_command() function that is provided for the Identify cluster I’ve been referencing so far. That shows a custom handler to peel off and handle certain commands. Any commands that aren’t processed it then passes into the default zcl_general_command() function.

So define something similar to catch and process reporting commands and add it to your cluster definition.

It is true that Digi does not provide examples nor good documentation when it comes to ZigBee ZDO/ZCL support. I suspect this could be a licensing related issue as ZigBee specification is provided publicly only for non-commercial purposes. In any case wanted to add an example to get ZDO support working in the Programmable XBee using the built in ZDO code. Hope this is of help to someone.

By default if your AO parameter is either 0 or 1, the XBee radio firmware will respond to the ZDO requests. The easiest to try this out is by sending “Active Endpoints Request” (Cluster ID 0x0005) to the module. The module will respond with E8 (Digi Endpoint) and E6 (Digi Command) being available. When AO is set to 3 or if you have one of the following defined in your project:


- ENABLE_XBEE_HANDLE_RX
- ENABLE_OTA_UPDATE
- ENABLE_XBEE_HANDLE_ND_RESPONSE_FRAMES

or directly ENABLE_XBEE_HANDLE_RX_ZCL_FRAMES which sets AO=3 at boot, you will notice that you will not receive any reply for the ZDO Active Endpoints Request - because by default ZDO endpoint is not added to active list. To do so, you need to:

  1. Create a global for ZDO transaction tracking.
wpan_ep_state_t zdo_ep_state;
  1. Add the ZDO endpoint to the list in custom.h (based on xbee_custom_endpoint example):

#include 

extern wpan_ep_state_t zdo_ep_state;

#define CUSTOM_ENDPOINT			0x13
#define CUSTOM_EP_PROFILE		0x5EBA

#define EP_INCLUDE_DECLARATIONS	extern const wpan_cluster_table_entry_t custom_ep_clusters[]; int custom_ep_default_cluster(const wpan_envelope_t FAR *, void FAR *);

#define ADDITIONAL_ENDPOINTS	{CUSTOM_ENDPOINT, CUSTOM_EP_PROFILE, custom_ep_default_cluster, NULL, 0x0000, 0x00, custom_ep_clusters}, \
                              ZDO_ENDPOINT(zdo_ep_state)

If you resend the “Active Endpoints Request” you’ll notice that E8 (Digi Endpoint) and 13 (your custom endpoint) will be sent back in the reply.

So this might be a silly question, but where is this “xbee_custom_endpoint” example ? Googling it only returns this very page.
Thanks

Hi Ulrar.

The xbee_custom_endpoint example project is shipped as part of the Programmable XBee SDK package - http://ftp1.digi.com/support/sampleapplications/40003003_D.exe

Hi,

that’s an .exe file, is there a place I can find that code without requiring windows ?
Thanks

Hi.

To my knowledge, that is still the only way - officially. For Programmable XBee Development, the SDK is delivered in form of CodeWarrior IDE for MCUs (v10.2), which is Windows Only. On top of that you need the actual SDK containing the necessary source code, documentation and samples - everything wrapped in an installer (.exe)

I’m not a Windows user myself so I went ahead and:

a) Made a sample application buildable without needing CW or Windows (can be used as a boilerplate) - https://github.com/exsilium/pxbee-blink-led
b) Extracted the documentation from the SDK https://github.com/exsilium/xbee-sdk-doc

For the particular sample application you requested, I’ve gone and zip’ed it for you, if you are interested (Generated for S2C Through-Hole module) (Link valid for the following 24h - https://www.dropbox.com/s/tp0i9kpw2vw6nai/xbee_custom_endpoint.zip?dl=0 )

Having said that there are options to work with Programmable XBee’s without Windows, all the sample applications are generated via a simple wizard and majority of the project defines are generated through a smart editor available only on the CodeWarrior. It will be a bigger challenge to work with the platform on any other OS.

Cheers!

Hi,

I’ll give this all a try next week, but I went ahead and downloaded the file now, looks good.
This is great, thanks a lot for this ! Much appreciated.