08 April 2009

XBee Series 2 - Reading Data in API Mode

After I finally got a ZNET 2.5 Coordinator AT associated with a ZNET 2.5 ROUTER / END DEVICE by figuring out that the default JV Channel Verification parameter was key, I stumbled again.

I can send character data from end device to coordinator and see it come out of the UART.

But when I have an end device with the ADC enabled (ATD1=2) and the IO Sampling Rate (ATIR=4E20) set to 20 seconds, I see the coordinator's red LED flicker as data is being received. But nothing appears to come out of the coordinator's UART.

Back to drawing board with Mr Google. I searched websites, blogs, forums. Some are claiming it works great, others are having issues. I'm on the issue side.

Then came across this in the XBee ZNET 2.5 Product Manual, section 4.5.3. Periodic IO Sampling :
Periodic sampling allows an XBee / XBee-PRO module to take an IO sample and transmit it to a remote device at a periodic rate. The periodic sample rate is set by the IR command. If IR is set to 0, periodic sampling is disabled. For all other values of IR, data will be sampled after IR milliseconds have elapsed and transmitted to a remote device. The DH and DL commands determine the destination address of the IO samples. DH and DL can be set to 0 to transmit to the coordinator, or to the 64-bit address of the remote device (SH and SL). Only devices running API firmware can send IO data samples out their Uart. Devices running AT firmware will discard received IO data samples.
I swear that when I searched around, I found people claiming to receive IO data in AT mode. I surely can't so maybe the manual is on to something. I'll try API mode. Bet it's a boatload of fun.

TIP: When writing API firmware to a device that currently has AT firmware on it (or visa-versa), after the write, X-CTU complains that it failed to enter command mode. This is because the "Enable API" setting on the PC Settings / Host Setup tabs need to be toggled.

After putting ZNET 2.5 COORDINATOR API on, I did start to seem to receive data. But not what I expected. With AT Transparent Mode, I could just read a string straight from the UART and parse away. Now in API Mode I'm getting some weird gook that sure doesn't print very nice. Probably that API Frame thing that I skimmed past in the manual. Darnit, I gotta just sit down and read that thing.

Section 6 API Operations goes into detail about how life has now changed and the free ride is over. It says "API operation requires that communication with the module be done through a structured interface (data is communicated in frames in a defined order)". Oh Joy.

I started hacking my Python app to see what kinda data I was getting myself into. The frame starts with a start byte of 0x7E and then followed by a two byte length. The IO data that I'm trying to get to is locked away in the Frame Data block that doesn't seem too bad.

Luckily before I started to make a career out of writing a API Frame parsing mess, I went back to Google to see what the trail blazers have done for me. I found the xbee.py file that ladyada used for her tweet-a-watt. Too bad it's for Series 1 and not a lot of help. But the header notes the author as Amit Snyderman. Wonder if he has a Series 2 version. Woo Hoo, he's got some google code at http://code.google.com/p/python-xbee But wait. The page says: The XBee API code is incomplete, missing support for valid checksums and an implementation for working with the Series 2 API. Darn it. Another bad lead.

Well, I'm on the Python Xbee page, I might as well be nosey and poke around. Maybe I can use the Series 1 code as a starting point and hack it up enough to get my single channel ADC data. Let's look it the Subversion source. What's that under the trunk? An XBee 2.5 folder. Woo Hoo!

Grab the xbee_api.py file, save it to your project folder and then for a quick test, write a second file like this:
#!/usr/bin/env python

from xbee_api import *

# replace first param with your serial port
a=XbeeApi("/dev/tts/0",9600)

Save this in a file called coord.py, make it executable (chmod +x coord.py), and run it (./coord.py). Now when sampled IO data is received, this is printed. Do I hear a Woo Hoo?
onData() ->{'code': 146, 'data': {'asamples': [3, 255], 'dsamples': [[0, 0, 0, 0, 0, 0, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]], 'dmask': [[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]], 'mac': [0, 19, 162, 0, 64, 62, 33, 116], 'samples': [1], 'address': [60, 237], 'amask': [[0, 0, 0, 0, 0, 0, 1, 1]], 'options': [1]}}
data {'asamples': [3, 255], 'dsamples': [[0, 0, 0, 0, 0, 0, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]], 'dmask': [[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]], 'mac': [0, 19, 162, 0, 64, 62, 33, 116], 'samples': [1], 'address': [60, 237], 'amask': [[0, 0, 0, 0, 0, 0, 1, 1]], 'options': [1]}
Now I need to figure out to interpret the data 'asamples'. But this is looking very promising. FYI, I'm going down this path to hook a thermistor to an XBee for my pool thermometer. More details to follow as I make more progress.

More FYI. I'm running this with OpenWRT on a wl-520gu hacked for my tweet-a-w/e. The receiving XBee is named BLUE. The second XBee is name WHITE and is connected to my laptop with an adafruit XBee Adapter that has ADC pin 2 setup for 20 second periodic IO sampling.

I've saved the today's version of my X-CTU config files here:
BLUE with ZNET 2.5 COORDINATOR API

WHITE with ZNET 2.5 ROUTER / END DEVICE AT with ADC pin 1 enabled and 20 second IO sampling.

What do you think? Leave a comment.

XBee Series 2 - JV Channel Verification

Damn it. Why do the simplest things always take hours to complete? I'm using XBee Series 2 cause I really didn't know what I was buying. Series 1 or Series 2? To a newb, sounds like 2 is the shiny. Why buy an out-dated series 1? Nobody wants last year's model.

If I would've done my homework, the series 1 (also called 802.15.4) are the most reliable, easiest to use. So of course, I'm using Series 2.

I first attempted to use them as described in the ZNet 2.5 Modules Product Manual, one as a coordinator, one as an end device. No luck. I followed every instruction I could find on the web. Nada.

Just by dumb luck, I found that if I flashed two radios as ZNET 2.5 ROUTER / END DEVICE AT and then set the Destination Address of each to point to the other, it appeared to work. I could send data to and from the serial ports. I used them in this way for the tweet-a-w/e foundation and had good success.

For an end device called WHITE that will talk to another end device named PINK, use X-CTU and load the ZNET 2.5 Router / End Device AT firmware. Go to the X-CTU Terminal tab and type:
+++
ATRE
ATNIWHITE
ATDNPINK
ATWR
Here's the X-CTU file for WHITE.

But now I'm trying to send analog data from one to the other and I'm back to nada. The data receive light blinks and it appears to read data, but nada bit comes out of the UART.

I decided to go back to square one and reconfigure as coordinator and end device. Sounds easy? Right. Took me two nights to get the devices associated. What's associated? From page 14 of the 802.15.4 manual (and not in the series 2 manual):
Association is the establishment of membership between End Devices and a Coordinator. The establishment of membership is useful in scenarios that require a central unit (Coordinator) to relay messages to or gather data from several remote units (End Devices), assign channels or assign PAN ID.
The series 2 manual seems pretty decent. I've read many sections and need to sit down and attempt to read more. Too bad though that it doesn't mention parameter JV Channel Verification. Which is the parameter that finally made a difference.
[update] maybe I was looking at the wrong manual. The one I ref'd above is the Series 2 Manual. The JV parameter is mentioned in the ZNET 2.5 manual.

When setting up a coordinator and associated end devices, there's a few things that you need to do:
  • After writing the firmware, go to the terminal and do a ATRE to reset to factory values. I would've saved lots of time if I realized that previous values were not being overwritten between firmware loads.
  • Make sure that the PAN ID is set the same on both devices. I suggest that while debugging, you have both devices connected to your computer via an adafruit XBee Adapter or SparkFun XBee Explorer and use X-CTU to monitor. You need to verify that the Operating PAN IDs are the same when they're trying to associate.
  • Set each device to a unique Node ID
  • The coordinator destination address should be set to DH=0, DL=FFFF
  • The end device destination address should be set to DH=0, DL=0
And for basic communications, that should be it. No need to set destination address of the end device explicitly to the coordinator. The 0's do that for you.

My problem though was my coordinator was on channel F and my end device was channel D. I could see this while watching them start up, but I could not figure out WTF.

Finally by going thru every parameter on both devices using X-CTU, I realized that JV Channel Verification was the ticket. This is described in the X-CTU tool as:
Set/read the channel verification setting. If enabled, a router will verify a coordinator exists on the same channel after joining or power cycling to ensure it is operating on a valid channel, and will leave if a coordinator cannot be found (if NJ=0xFF). If disabled, the router will remain on the same channel through power cycles.
In English, this means that if your devices are on different channels and JV is disabled, you're fricked cause the router won't go to another channel to associate.

Change JV to enabled and reboot the device:

+++
ATJV1
ATWR
ATFR

I've uploaded the configuration to my coordinator named BLUE that has ZNET 2.5 COORDINATOR API firmware. And an end device named PINK that has ZNET 2.5 ROUTER / END DEVICE AT firmware.

What do you think? Leave a comment.