When X-CTU can see your device, read the modem parameters and firmware, change the function set to Coordinator API, and write the firmware back to the device. (If the firmware version on the chip does not support the Coordinator API function set, you will have to pick one which does. Unfortunately, as far as I can tell, the only way to do this is by trial and error: it seems that X-CTU will happily write firmware which doesn't run properly on the XBee. Luckily, Digi's technical support is excellent.)
To send an AT command to a remote device, it must be wrapped in a remote-AT command-frame addressed to the end device and transmitted to it via the coordinator. This is tricky! Eventually I found some Perl bindings which did the trick but before that I had some fun crafting the packets by hand, aided by a handy packet-checker. (That site also hosts a useful FAQ.)
The little script below shows how to set up the end device to read its sensors periodically and transmit them to the coordinator. This is attached to the machine on which this script runs, on a USB-Serial port. Received frames are written to the console.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use warnings; | |
use Xbee::API; | |
use Data::Dumper; | |
my $port = "/dev/ttyUSB0"; | |
my $end_device = "0013a20040769646"; | |
my $remaddr = pack( "H*", $end_device ); | |
my $devaddr = pack( "H4", "fffe" ); | |
my $sp = pack( "n", 2400 ); # 24s | |
my $sn = pack( "n", 4 ); | |
my $st = pack( "n", 5000 ); # 5s | |
my $ir = pack( "n", 5100 ); # > $st -> 1 sample | |
my $xbee = Xbee::API->new( { port => $port, debug => 0, speed => 9600 } ); | |
sub remote_send_wait | |
{ | |
($cmd, $data) = @_; | |
$id = $xbee->at_command_remote( $remaddr, $devaddr, $cmd, $data ); | |
$frame = $xbee->read_api; | |
if (defined $frame && $frame->{status} == 0 && $frame->{id} == $id ) { | |
print "received reply to $cmd OK\n"; | |
} else { | |
print "$cmd failed!\n"; | |
print Dumper($frame); | |
} | |
} | |
remote_send_wait( "SP", $sp ); # sleep period (10mS units) | |
remote_send_wait( "SN", $sn ); # sleep multiplier | |
remote_send_wait( "ST", $st ); # time before sleep (1mS units) | |
remote_send_wait( "IR", $ir ); # I/O read | |
remote_send_wait( "SO", pack( "C", "06") ); # sleep options: extended sleep | |
remote_send_wait( "SM", pack( "C", "04") ); # sleep mode periodic | |
start: while (1) { | |
my $frame = $xbee->read_api; | |
next start if !defined $frame; | |
print Dumper($frame); | |
} |