/*
Tim Sharpe, 8 Apr 2009. This is free software and comes with no warranty whatsoever.
This is an Arduino sketch that uses Andrew Rapp's XBee-Arduino Zigbee library. The sketch
combinescode from his Zigbee receive and transmit sketch (ZBRxExample and ZBTxExample) to
create a single sketch that data from a received packet back to the node that sent it.
Mr. Rapp's sketches were helpful, but didn't explain how to extract data from a received packet
and use the data create a response to the sending node. This sketch is an attempt to demonstrate
how to accomplish this and is commented to expalin some of the "whys". I don't pronise it's a great
solution, but it works (at least for me).
I developed this sketch using the Ardunio 0014 IDE, an Adafruit Boarduino (Arduino clone that works
nicely with solderless breadboards) and a Series 2 XBee Module (ZNET 2.5) running "Router/End Device API"
firmware running in ATAP2 API mode per Mr. Rapp's Web Site.
I tested the setup using another Series 2 XBee Module (ZNET 2.5) running "Router/End Device AT" firmware,
connected to a terminal emulator and configured with the API-mode Xbee as its Destination Node. The goal
was to enter characters or strings into the terminal emulator and have the Arduino/API-mode Xbee echo the
data back to the terminal emulator. This was a test to understand Mr. Rapp's library well enough to create
an API-mode, fully-networked (vice modem type communication) Zigbee application.
Portions of this sketch were copied from Mr. Rapp's ZBRxExample and ZBTxExample sketches and modified to
function as desired. I used Mr. Rapp's XBee-Arduino Zigbee library (v0.1.1) was used without modification.
As Mr. Rapp has GPL'd his sample sketches, please note his GPL license info below.
I hope you find this as useful as I did for my projects.
*/
/**
* Copyright (c) 2009 Andrew Rapp. All rights reserved.
*
* This file is part of XBee-Arduino.
*
* XBee-Arduino is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* XBee-Arduino is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBee-Arduino. If not, see .
*/
//We're going to need string handling to feed received data back to the transmit object.
#include
//Mr. Rapp's library. I put it in quotes as I dropped XBee.h and XBee.cpp in the sketch folder
// rather than storing it with the Arduino libraries.
#include "XBee.h"
//Using a software serial port to monitor how the sketch interprets received packets. Just listen
// on Arduino pin D2 and 9600bps
#include
#define rxPin 2
#define txPin 3
SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);
/*
Receives a ZB RX packet and sets a PWM value based on packet data.
Error led is flashed if an unexpected packet is received
*/
//This instantiates the XBee library
XBee xbee = XBee();
//This creates object instance "response" to process Xbee Packets
XBeeResponse response = XBeeResponse();
//This creates object instance "rx" to process Xbee Series 2 API packets
ZBRxResponse rx = ZBRxResponse();
//This creates object instance "msr" to process associate/disassociate packets (PAN membership)
ModemStatusResponse msr = ModemStatusResponse();
//This creates object instance "txStatus" to process acknowledgements for sent Xbee Series 2 API packets
ZBTxStatusResponse txStatus = ZBTxStatusResponse();
//Declare some variables we'll need to hold received packet data so we can use it to transmit
//The two 32-bit halves of th4 64-bit address
long XBee_Addr64_MS;
long XBee_Addr64_LS;
//The 16-bit address
int XBee_Addr16;
//We need a string to hold incoming data bytes from received packets. I chose a 20 byte string as my
// transmit needs are short. I suggest you make this at least 3 btes longer than the longest data
// block you'll receive.
char XBee_Data[20];
//We need to make sure we're not overwriting the string, so we'll name its length to use later
#define XBee_Data_len 20
//An integer varailbe for temporary use
int dummy;
//Mr. Rapp's sketches used LED's on Arduino pins D10, D11, and D12 to indicate activity and status.
// I found them quite helpful after reading all the code where they're triggered. I used small LED's
// connected to the ATMEGA168 through 1K resisitors.
int statusLed = 11;
int errorLed = 12;
int dataLed = 10;
//We're going to need a counter to bring in received data byte-by-byte (how the library delivers it)
int count=0;
//Mr. Rapp uses this function to flash the LED's in certain ways to indicate different conditions.
void flashLed(int pin, int times, int wait) {
for (int i = 0; i < times; i++) {
digitalWrite(pin, HIGH);
delay(wait);
digitalWrite(pin, LOW);
if (i + 1 < times) {
delay(wait);
}
}
}
void setup() {
//Set up and start the Software Serial port
pinMode(rxPin, INPUT);
pinMode(txPin, OUTPUT);
// set the data rate for the SoftwareSerial port
mySerial.begin(9600);
//Set up the LED indicator pins
pinMode(statusLed, OUTPUT);
pinMode(errorLed, OUTPUT);
pinMode(dataLed, OUTPUT);
//The Xbee Library starts the hardware serial port.
xbee.begin(9600);
//This just signals that the setup phase is complete.
flashLed(statusLed, 3, 50);
}
// continuously reads packets, looking for ZB Receive or Modem Status
void loop() {
//Attempt to read an API packet from the ZBee Module
xbee.readPacket();
//If we found a packet...
if (xbee.getResponse().isAvailable()) {
// got something
//If it's a Zigbee Receive packet (API ID 0x90)...
if (xbee.getResponse().getApiId() == ZB_RX_RESPONSE) {
// got a zb rx packet
//Populate our "rx" object with info from the received packet (Data, Addresses, etc)
xbee.getResponse().getZBRxResponse(rx);
//Flash an LED if receipt was acknowleged to the sending node, or maybe not
if (rx.getOption() == ZB_PACKET_ACKNOWLEDGED) {
// the sender got an ACK
flashLed(statusLed, 1, 10);
} else {
// we got it (obviously) but sender didn't get an ACK
flashLed(errorLed, 2, 20);
}
// set dataLed PWM to value of the first byte in the data
analogWrite(dataLed, rx.getData(0));
//Here I'm extracting some of the information I'll need to create a packet to reply back to the
// sender.
//This one obtains the upper 32-bit word of the 64-bit address. The 64-bit address is the 802.15.4 MAC
// layer address (i.e, the "burned in" one).
XBee_Addr64_MS=(uint32_t(rx.getFrameData()[0]) << 24) + (uint32_t(rx.getFrameData()[1]) << 16) + (uint16_t(rx.getFrameData()[2]) << 8) + rx.getFrameData()[3];
//This one obtains the lower 32-bit word...
XBee_Addr64_LS=(uint32_t(rx.getFrameData()[4]) << 24) + (uint32_t(rx.getFrameData()[5]) << 16) + (uint16_t(rx.getFrameData()[6]) << 8) + rx.getFrameData()[7];
//Send the two parts of the address to the software serial port
mySerial.print("Addr64 MS: ");
mySerial.print(XBee_Addr64_MS,HEX);
mySerial.print('\n');
mySerial.print("Addr64 LS: ");
mySerial.print(XBee_Addr64_LS,HEX);
mySerial.print('\n');
//Now we extract the 16-bit address. This is the Zigbee Network address of the node in the PAN, analogous to
// an IP address in TCP/IP.
XBee_Addr16=rx.getRemoteAddress16();
mySerial.print("Addr16: ");
//I'm not displaying the extracted result as the Arduino print "HEX" represenation prepends FFFF to the front of the address.
// You can comment the rx.getRemoteAddress16() line and uncomment the XBee_Addr16 and see for yourself. Only the output is
// wrong. The address is correctly extracted.
//mySerial.print(XBee_Addr16,HEX);
mySerial.print(rx.getRemoteAddress16(),HEX);
mySerial.print('\n');
//We're just going to display the number of bytes of data we'll receive, but not extract it.
mySerial.print("DataLength: ");
mySerial.print(rx.getDataLength(),DEC);
mySerial.print('\n');
//Need to make sure we don't overrun the string. Enforce it's length
if (rx.getDataLength()>=XBee_Data_len) {dummy=XBee_Data_len;}
else {dummy=rx.getDataLength();}
//Now we read the data. Note that we read from the start of the buffer to position DataLength-1.
mySerial.print("Data: ");
for (count=0;count<=dummy-1;count++)
{
mySerial.print(rx.getData(count));
XBee_Data[count]=rx.getData(count);
}
//We may be sending back less data than the length of the XBee_Data string. We'll send the data by
// providing a string and a data length that will work just like the way we read the data before. In
// order to only send the actual received data back, we need to indicate where the data ends. I did this
// by appending a NULL at position DataLength. This makes the strlen function see a string that looks shorter
// than the original declared string. C uses "Null-terminated strings", remember?
XBee_Data[dummy]='\0';
mySerial.print('\n');
//Now we'll send data what we received to the node that sent it
//Create a 64-bit address data structure from the extracted address
XBeeAddress64 XBee_Addr64 = XBeeAddress64(XBee_Addr64_MS, XBee_Addr64_LS);
//Build the Packet. Note the following (in order of ZBTxRequest arguments):
// -The first one is the 64-bit address data structure we just created
// -The second one is the 16-bit address
// -The next one defines how many nodes a broadcast can pass through while looking for the destination node. I'm
// using the defined Zigbee maximum network radius so we have a number as I don't have any reason to make it shorter.
// -The next one says this is a transmit Unicast packet, as opposed to a broadcast or multicast
// -Next is the data to be sent in the packet. ZBTxRequest requires a uint8_t* string pointer, but strlen
// only works with "char" strings. I made a "char" string and am "casting" it as uint8_t* for the library
// -The next one tells the library how many bytes of the data string will be sent. This is why I did the
// NULL termination after getting the last recevied packet - So I could use "strlen" to provide the length of
// data up to the inserted NULL.
// -The last one tells the library to increment the FrameID before sending the packet.
//Note that we didn't declare the "zbTX" object up front with the other objects. Unlike the others that can be reused, we
// have to feed this one new data every time we use it, so we create it on the fly each time.
ZBTxRequest zbTx = ZBTxRequest(XBee_Addr64, XBee_Addr16, ZB_BROADCAST_RADIUS_MAX_HOPS, ZB_TX_UNICAST, (uint8_t*) XBee_Data, strlen(XBee_Data), xbee.getNextFrameId());
//Send the packet
xbee.send(zbTx);
// flash TX indicator
flashLed(statusLed, 1, 100);
//Now we figure out if the destination node received the packet...
// after sending a tx request, we expect a status response
// wait up to half second for the status response
if (xbee.readPacket(500)) {
// got a response!
// should be a znet tx status
if (xbee.getResponse().getApiId() == ZB_TX_STATUS_RESPONSE) {
xbee.getResponse().getZBTxStatusResponse(txStatus);
// get the delivery status, the fifth byte
if (txStatus.getDeliveryStatus() == SUCCESS) {
// success. time to celebrate
flashLed(statusLed, 5, 50);
} else {
// the remote XBee did not receive our packet. is it powered on?
flashLed(errorLed, 3, 500);
}
}
} else {
// local XBee did not provide a timely TX Status Response -- should not happen
flashLed(errorLed, 2, 50);
}
//*****END OF DATA PACKET PROCESSING******
//*****This part detects associate/disassociate packets*****
} else if (xbee.getResponse().getApiId() == MODEM_STATUS_RESPONSE) {
xbee.getResponse().getModemStatusResponse(msr);
// the local XBee sends this response on certain events, like association/dissociation
if (msr.getStatus() == ASSOCIATED) {
// yay this is great. flash led
flashLed(statusLed, 10, 10);
} else if (msr.getStatus() == DISASSOCIATED) {
// this is awful.. flash led to show our discontent
flashLed(errorLed, 10, 10);
} else {
// another status
flashLed(statusLed, 5, 10);
}
} else {
// not something we were expecting
flashLed(errorLed, 1, 25);
}
}
}