Tuesday, October 30, 2012

Using the XBee library

Recently Paul Stoffregen created a new software serial library for the Arduino, then he modified Andrew Rapp's XBee library to use it (as well as the older, but really great, SoftwareSerial libray).  Suddenly, the XBee library is something that could be really useful.

See, the XBee library has traditionally been hooked into the hardware serial lines on Arduino Pins 0 and 1.  That means getting debugging information out of the device combination of an Arduino and an XBee is an exercise in frustration and annoyance.  Sure, you can use blinking lights to tell you what is going on, but this is the 21st century.  I have always written my own code to handle the XBee interaction because I wanted the serial port to provide status and control when I was working on a project.  Additionally, Andrew's library is heavily c++ and all the classes, inheritance, and instances confused the heck out of me.

However, maybe with the inclusion of a modified software serial port, and the capability to use the additional ports on an Arduino Mega, now is the time to take a serious look at using it.  I mean, if you have a mega, you can now put the XBee on Serial1 and keep Serial and Serial 2 for other things; this is just the ticket for converting RS485 into XBee packets to send over the air where you don't have wires.  Heck, I can think of dozens of things.

So, here is my first voyage into the use of the library.  I haven't linked in Paul's new serial library yet, I will on a future example, but I just wanted to understand what was going on and how to, at least, receive a packet and do something with it.  I took one of Andrew's library examples and modified it substantially to include many of the things I need in using an XBee and commented the heck out of it so others stood a chance of understanding what was going on.  It's amazing how few examples are out there that actually show what you need to do to do something along these lines.


The Arduino Sketch

/**
I took Andrew Rapp's receive example and modified it to be completely
unrecognizable.

I wanted to experiment with and better understand how to use his XBee
library for an actual project.  With the inclusion of support for SoftwareSerial
so that the XBee can be put on digital pins leaving the Arduino serial port
available for debugging and status, the library's usefullness shot way up.

This is a HEAVILY commented example of how to grab a receive packet off the
air and do something with it using series 2 XBees.  Series 1 XBees are left as
and exercise for the student.
*/

#include <XBee.h>
#include <SoftwareSerial.h>

XBee xbee = XBee();
XBeeResponse response = XBeeResponse();
// create reusable response objects for responses we expect to handle
ZBRxResponse rx = ZBRxResponse();

// Define NewSoftSerial TX/RX pins
// Connect Arduino pin 2 to Tx and 3 to Rx of the XBee
// I know this sounds backwards, but remember that output
// from the Arduino is input to the Xbee
#define ssRX 2
#define ssTX 3
SoftwareSerial nss(ssRX, ssTX);


void setup() {
  // start serial
  Serial.begin(9600);
  // and the software serial port
  nss.begin(9600);
  // now that they are started, hook the XBee into
  // Software Serial
  xbee.setSerial(nss);
  // I think this is the only line actually left over
  // from Andrew's original example
  Serial.println("starting up yo!");
}

void loop() {
    // doing the read without a timer makes it non-blocking, so
    // you can do other stuff in loop() as well.
    xbee.readPacket();
    // so the read above will set the available up to
    // work when you check it.
    if (xbee.getResponse().isAvailable()) {
      // got something
      Serial.println();
      Serial.print("Frame Type is ");
      // Andrew call the frame type ApiId, it's the first byte
      // of the frame specific data in the packet.
      Serial.println(xbee.getResponse().getApiId(), HEX);
   
      if (xbee.getResponse().getApiId() == ZB_RX_RESPONSE) {
        // got a zb rx packet, the kind this code is looking for
     
        // now that you know it's a receive packet
        // fill in the values
        xbee.getResponse().getZBRxResponse(rx);
     
        // this is how you get the 64 bit address out of
        // the incoming packet so you know which device
        // it came from
        Serial.print("Got an rx packet from: ");
        XBeeAddress64 senderLongAddress = rx.getRemoteAddress64();
        print32Bits(senderLongAddress.getMsb());
        Serial.print(" ");
        print32Bits(senderLongAddress.getLsb());
     
        // this is how to get the sender's
        // 16 bit address and show it
        uint16_t senderShortAddress = rx.getRemoteAddress16();
        Serial.print(" (");
        print16Bits(senderShortAddress);
        Serial.println(")");
     
        // The option byte is a bit field
        if (rx.getOption() & ZB_PACKET_ACKNOWLEDGED)
            // the sender got an ACK
          Serial.println("packet acknowledged");
        if (rx.getOption() & ZB_BROADCAST_PACKET)
          // This was a broadcast packet
          Serial.println("broadcast Packet");
       
        Serial.print("checksum is ");
        Serial.println(rx.getChecksum(), HEX);
     
        // this is the packet length
        Serial.print("packet length is ");
        Serial.print(rx.getPacketLength(), DEC);
     
        // this is the payload length, probably
        // what you actually want to use
        Serial.print(", data payload length is ");
        Serial.println(rx.getDataLength(),DEC);
     
        // this is the actual data you sent
        Serial.println("Received Data: ");
        for (int i = 0; i < rx.getDataLength(); i++) {
          print8Bits(rx.getData()[i]);
          Serial.print(' ');
        }
     
        // and an ascii representation for those of us
        // that send text through the XBee
        Serial.println();
        for (int i= 0; i < rx.getDataLength(); i++){
          Serial.write(' ');
          if (iscntrl(rx.getData()[i]))
            Serial.write(' ');
          else
            Serial.write(rx.getData()[i]);
          Serial.write(' ');
        }
        Serial.println();
     
        // So, for example, you could do something like this:
        handleXbeeRxMessage(rx.getData(), rx.getDataLength());
/*
        // I commented out the printing of the entire frame, but
        // left the code in place in case you want to see it for
        // debugging or something
        Serial.println("frame data:");
        for (int i = 0; i < xbee.getResponse().getFrameDataLength(); i++) {
          print8Bits(xbee.getResponse().getFrameData()[i]);
          Serial.print(' ');
        }
        Serial.println();
        for (int i= 0; i < xbee.getResponse().getFrameDataLength(); i++){
          Serial.write(' ');
          if (iscntrl(xbee.getResponse().getFrameData()[i]))
            Serial.write(' ');
          else
            Serial.write(xbee.getResponse().getFrameData()[i]);
          Serial.write(' ');
        }
        Serial.println();
*/
      }
    }
    else if (xbee.getResponse().isError()) {
      // some kind of error happened, I put the stars in so
      // it could easily be found
      Serial.print("************************************* error code:");
      Serial.println(xbee.getResponse().getErrorCode(),DEC);
    }
    else {
      // I hate else statements that don't have some kind
      // ending.  This is where you handle other things
    }
}

void handleXbeeRxMessage(uint8_t *data, uint8_t length){
  // this is just a stub to show how to get the data,
  // and is where you put your code to do something with
  // it.
  for (int i = 0; i < length; i++){
//    Serial.print(data[i]);
  }
//  Serial.println();
}

// these routines are just to print the data with
// leading zeros and allow formatting such that it
// will be easy to read.
void print32Bits(uint32_t dw){
  print16Bits(dw >> 16);
  print16Bits(dw & 0xFFFF);
}

void print16Bits(uint16_t w){
  print8Bits(w >> 8);
  print8Bits(w & 0x00FF);
}

void print8Bits(byte c){
  uint8_t nibble = (c >> 4);
  if (nibble <= 9)
    Serial.write(nibble + 0x30);
  else
    Serial.write(nibble + 0x37);
     
  nibble = (uint8_t) (c & 0x0F);
  if (nibble <= 9)
    Serial.write(nibble + 0x30);
  else
    Serial.write(nibble + 0x37);
}

I tried to get all the major items out of the packet so they could be displayed and even included a tiny routine to illustrate using the received data.  This is what it looks like running:


You have to use the scrollbar at the bottom to see all of the message, but I wanted it that way instead of worrying about wrapping around.  I also put in print routines for the hex data; I love being able to see it in both hex and ascii.

Grab it, modify it to your purpose, and have fun.

32 comments:

  1. Hello,
    I was delighted to find your example as there don't seem to be many people using XBees on a software serial port.

    I have a lilypad main board connected to an XBee breakout board using conductive thread.
    I am using digital pins 2 and 3 on the Lilypad just like you as I'm keeping the hardware serial pins 0 and 1 free
    for use by the FTDI which I use for either a USB connection to my PC or a Bluetooth wireless connection to my laptop
    - I have a bluetooth modem with a FTDI header that I can connect to the lilypad for this. Output from Serial.print() etc.
    is then either displayed in a serial terminal window on the PC or laptop as expected.

    The laptop is running a Processing sketch that is broadcasting all the time, although I really only want this sender
    to broadcast every minute. I have a series 2 XBee radio (with coordinator firmware) connected to the laptop using an
    Explorer module. Here is an example of one of the transmit requests being broadcast:

    0x7e,0x00,0x1b,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xfe,0x00,0x08,0x45,0x41,0x01,0x00,0x50,0x52,0x49,0x4d,0x41,0x52,0x59,0x47,0x57,0x9b

    The only thing in this frame that I am unsure about is the 0x08 Options. the RF data and address fields look good.

    The red Tx led is on nearly all the time on the sender's Explorer as expected.
    On the lilypad's XBee breakout board, the power led is on and hte green rssi led only comes on occasionally.

    My big problem is that NONE of the XBee messages are getting through to the Lilypad!
    The lilypad is running your sketch from http://www.desert-home.com/2012/10/using-xbee-library.html
    I just put in an extra Serial.print to the else clause that you hate and of course it is being executed
    which indicated to me that the xbee.readPacket() is not working. No data is being received and there are
    no errors! Just as if the sender wasn't running at all....

    If you have any ideas about what might be wrong please let me know.

    Thanks in advance,
    Jackie.

    ReplyDelete
  2. First check two things for me, First make sure that both of the XBees are set for API mode and that they are using API mode 2. I've had a number of people have trouble and seek advice when that was their problem. Next, put a delay in the processing code to only transmit every couple of seconds. Using SoftwareSerial can chew up a lot of processing power on the little arduino and things get backed up and dropped on the floor.

    I had this happen big time on a project where things were coming in so fast that I couldn't process them on the board. Slowing down the conversation a tiny bit made it work perfectly every single time. I was getting behind and missing things like the checksum, start sentinel, etc and never managing to construct a complete packet.

    Try these two things and let me know

    ReplyDelete
  3. Thank you very much for getting back to me so quickly.

    I was very careful configuring each radio in X-CTU but I double-checked again and AP=2 on each radio.
    They each have the same PAN ID = 12345
    I also did a "Network Discovery" from the MoltoSenso Network Manager on the same laptop as the XBee coordinator.
    The other radio on the Lilypad was successfully discovered so it looks like the network is set up ok.

    I changed the delay between broadcasts from the sender (on the laptop).
    I tried a few different intervals like 0 (continuously broadcasting), 10, 30 and 60 seconds.
    No errors are ever reported by the sender but the XBee on the Lilypad never gets a message!

    Here is an example of a Transmit Status that the sender receives after a broadcast:

    [com.rapplogic.xbee.api.InputStreamThread] Received packet: int[] packet = {0x00, 0x07, 0x8b, 0x31, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x46};

    The delivery status and discovery status are both 0x00 for success.
    The 16-bit destination address is 0xFFFE which I assume is OK as it matches what I had in the Transmit Request that was broadcast.

    I don't know what to change on the Lilypad to get it to receive a message....

    ReplyDelete
  4. I agree with you about the options byte that is being sent by the processing code. According to the XBee user's guide, that's an undefined value and I don't have a clue if it matters or not. However, the transmit response indicates it found an XBee and actually delivered the message to it.

    So, everything indicates you sent something and it should have popped out the serial port of the XBee to the LilyPad you're using. Try checking the obvious: did you get the pins backwards such that output is hooked to output? Try switching them while it's running; that doesn't hurt anything. Did one or both of the wires from the XBee to the serial input break? You can also reverse the two XBees so that the coordinator is on the lilypad and the router is on the pc to see if something strange is going on.

    You can get the code to transmit I have on this blog and send from the lilypad to the pc; you'll have to modify it a tiny bit to use softwareserial, I think my example used a mega2560 with multiple serial ports. By transmitting you may turn up a clue what's going on.

    You can maybe try using different digital ports to see if there is a possible problem with either pin 2 or 3. Maybe temporarily hook the XBee to pins 0 and 1 so you have the leds on the board to tell you if data is coming in. If you have an arduino around, try plugging the XBee into it and running the same code to see if there's a difference.

    In a fit of desperation, look at the processing library to see if changing that darn 80 into 0 is possible; although I don't think it's a problem, I haven't seen that before.

    Let me know how it goes.

    ReplyDelete
    Replies
    1. Oh, one other thing. The else statement you mentioned doesn't indicate that the read failed, it just indicates that there is not an available packet nor was there an error. If you take out all the chaff I put in there, it will look like this:

      void loop() {
      xbee.readPacket();
      if (xbee.getResponse().isAvailable()) {
      }
      else if (xbee.getResponse().isError()) {
      }
      else {
      // I hate else statements that don't have some kind
      // ending. This is where you handle other things
      }
      }

      I intentionally did that to allow the little computer to be doing something besides just hanging looking for a packet from the XBee. So, what you're seeing with a debug statement in the else is perfectly normal.

      I should probably get that out of there to keep from confusing folk.

      Delete
    2. Ok, fine, I just can't seem to get it together today. When I looked on the web for clues to this a lot of people have problems doing what you're doing. Most of them seem to have problems getting enough power to run both the lilypad and the XBee. In this case, the XBee will be the big power user and when it transmits, it could starve your power supply. I haven't worked with a lilypad, but it was designed to work off a small battery and the XBee needs more than that to transmit.

      You probably already know all this, if so, just ignore me.

      Delete
  5. Hi Dave,

    Thanks for all your suggestions. I am worried about the power supply for the lilypad alright as I only have a 3.7v lipo:
    https://www.sparkfun.com/products/341
    I try to keep it fully charged and the xbee's power led is on. I also run the lilypad when it is getting extra power from my PC via USB.
    The tx and rx connections are sewn with conductive thread so it is not easy for me to switch these around while running a sketch.
    I wish that Options byte wasn't 0x08 but nevertheless I am fairly confident that the msg from the laptop is reaching the lilypad's xbee breakout board as its RSSI led comes on when the sender's TX is on.
    Although, having said that, the RSSI led is never very bright.

    However I did modify that dreaded else clause on the lilypad to send a message to the coordinator on the laptop and those msgs are working!
    So I have one-way communication out of the lilypad but not in...

    I do have an Uno as well so I will try to do some further testing with that although it was exhibiting similar behaviour as the lilypad when I last checked.

    Thks v much for your help,
    Jackie

    ReplyDelete
  6. Jackie, having one-way comm eliminates a lot of stuff. Could the conductive thread from the XBee to the Lilypad have broken? It appears power, setup and every thing else is ok or it wouldn't transmit. A simple broken connection could be your problem.. Time for an ohm meter check between the boards. If that works, then there may be a hardware problem with the XBee, its board or the serial input pin you're using. Since you're using broadcast and not addresses, you can reverse the two XBees and see if the problem moves with the XBee, which would likely mean a bad XBee.

    You're getting closer, and some testing on the UNO should narrow it down a lot.

    ReplyDelete
  7. Hello Dave,

    I appreciate too much your xbee examples!!! It helped me a lot to make my Xbee API network. I was having problems to get the RSSI data. I am using the Xbee series 2 and have tried use rx.getRssi() but it didnt work, then I thats happens because I am using wrong function for this series. Andrew suggested use rx16.getRssi() on his site, but i think this function is for series 1. Would you help me on this mattter?

    Tks too much for your help,

    Alipio Carvalho

    ReplyDelete
  8. Alipio,

    As I understand it, the only way to get the rssi value from a series two XBee is to use an AT command which is frame type 8 and it will return an AT command response, frame type 88 that holds the register contents. The relevant API frames are on pages 103 and 110 of the User's guide.

    The command to send in the AT command is "DB" and is described on page 132. So you should be able use the XBee library's AT command interface and get the value back.

    The XBee document is at: http://ftp1.digi.com/support/documentation/90000976_G.pdf

    In theory, there is a way to get it using the digital pins I/O interface, but I've never heard of anyone successfully using it.

    You can even set an XBee up in AT mode, hook it to a PC, and use XCTU to test this before you try and program the frame construction on an Arduino.

    ReplyDelete
  9. Hello Dave,

    Thank you very much for your suggestion!!

    Alipio Carvalho

    ReplyDelete
  10. Hi Dave,

    My problem is fixed! My supervisor suggested using the AltSoftSerial library instead of SoftwareSerial. This involved switching to pins 8 and 9 on the lilypad. It has done the trick! I finally have 2-way ZigBee communication. I should have paid more attention to this recommendation on http://code.google.com/p/xbee-arduino/wiki/SoftwareSerialReleaseNotes

    Thank you very much for your help and great suggestions. Best of luck with your projects,
    Jackie

    ReplyDelete
  11. Jackie,

    That's great, but I wonder why you need to use the alt. Your description didn't indicate that you were running anything that would interfere with the software serial that comes with 1.0.1 or above.

    But, then again, it works! That's the important part.

    ReplyDelete
  12. Thanks to everyone for all this great information!

    Jackie -- perhaps the reason that switching pins worked has to do with the particular way in which softserial is setup on the Lilypad. The latest lilypad uses the same processor as the Leonardo does, and only particular pins on the Leonardo (including 8 and 9) are capable of software serial, I believe. This fellow provides a bunch of relevant detail on the issue in a blog post here:

    http://vort.org/2012/05/25/trouble-softserial-arduino-leonardo/

    I'll be using all this great info you've all collected here soon myself. Thanks again so much for posting.

    ReplyDelete
  13. Hello,
    I am working on designing an XBEE pro to form a mesh networking for image transmission. Could any body explain how i can achieve this? first i want to know if it is possible? I have 9 arduino uno board and 10xbee pro and a USB dongle connected to the computer. Can any one help with the codes, i am ready to pay. Thanks....................mail: ay4real@hotmail.ca

    ReplyDelete
    Replies
    1. Not sure what you mean by image transmission, but it's very likely that the XBees won't do it for you. They're designed for real time transmission of small packets over a mesh network to monitor and control devices. That doesn't include the large amounts of data that images require. You could easily flood an XBee network with a single image for several minutes. Yes, minutes.

      Images need a high rate of data transfer and you just can't get that from an XBee. Start looking at wireless ethernet techniques.

      Delete
  14. Hi Dave,

    Your site has made my efforts sooo much easier. Many Thanks. But I could use a little help.

    I'm trying to send data between two Arduino Uno's. From your examples, I've been able to make Arduino A talk to Arduino B with your "Hello world" and "I saw...". Yippee!

    I've looked around your site but have not seen where you send float, long and int type data. In my case I'm sending a variable - micros() of Arduino A to Arduino B so that the two are kinda time synced. Arduino B then does some calculations with external sensor inputs. Arduino B then sends back a variable (probably an unsigned long) to arduino A.

    Could you point me in the right direction as to how I would substitute your "Hello World" with these types of variables?

    Thanks

    Bill

    ReplyDelete
  15. There's a huge discussion of this on one of the pages ... somewhere in the comments. Basically what I do is to convert it to text then send it. When I get it at the other end, I convert it back to whatever I need. For integers, I use the c routine itoa() to get an ascii numeric representation and then atoi() to turn it back into an integer. Then, I found out that printf() actually worked on the arduino and I mostly converted everything to use that. A simple statement like:

    sprintf(Dbuf,"Power,%d.%02d,%d.%02d,%d.%02d,%d.%02d,%d.%02d,%d.%02d\r",
    (int)realPower, frac(realPower),
    (int)apparentPower, frac(apparentPower),
    (int)powerFactor, frac(powerFactor),
    (int)Vrms, frac(Vrms),
    (int)Irms, frac(Irms),
    (int)freq, frac(freq));

    should be a reasonable illustration of what can be done. the things like (int)variable, frac(variable) are taking the integer and fractional part of a float apart and converting it to ascii in the %d.%2d parts of the format string sent to printf. There are many ways of doing this, but I chose this one because it was easy. To get it back, you do something like:

    realPower = atof(strtok(0, ","));
    apparentPower = atof(strtok(0, ","));
    powerFactor = atof(strtok(0, ","));
    rmsVoltage = atof(strtok(0, ","));
    rmsCurrent = atof(strtok(0, ","));
    frequency = atof(strtok(0, ","));

    The sttrtok() call is used to separate the values and then atof() is used to turn them back into floats. I did it this way so I could monitor the traffic and actually see the values. Instead of trying to figure out what the values were from binary data, it's clearly readable. It also helps in debugging the code while you're working on it because you can print the string to the terminal and take a look at it, then at the other end look at it as it comes out of the XBee and see that it got there ok.

    Hope this helps.

    ReplyDelete
    Replies
    1. Thank you... I will try that tomorrow. I'm calling it a night.

      I just finished fiddling with code that broke a long into separate "parts" then reassembling them on the receiver end. I got it to sorta work. But since I'm a real beginner, my methodology is to try something then see what happens.

      But no doubt, your website has been of tremendous help. There is NO WAY I would have gotten this far with just the Xbee library docs, etc.

      I'll let you know

      Thanks again

      Bill

      Delete
    2. Floats are the problem since the arduino library doesn't handle them as well as other datatypes. It's a little confusing, but you'll get it in a couple of tries.

      And don't worry about trial and error programming. That's the way it's done these days.

      Delete
  16. Good evening Dave,

    I've been messing around with different types of variables and arrays all day. It seems I could have saved a great deal of time just listening to your comments about arrays.... way to slow...

    So thanks to your help, I've been able to convert a long to a string and successfully send the string. But I'm stuck on the receiving end. Your examples can println the string, but I don't know how to make it into a variable. Do you have an example somewhere of how to reconstruct a string variable on the receiving end. Once I get that string variable, I can convert it to a long.

    Thanks for all your help,

    Bill

    ReplyDelete
    Replies
    1. Bill, I decided to put together a blog post on this so I could include the code easily. I've gotten many questions on how to send this kind of data over an XBee or a serial connection of some sort, and now seems like a good time to address it in a way that people can cut and paste from. So, hit the button up top for the main page and take a look. Here's URL if that doesn't work http://www.desert-home.com/2013/10/floats-and-strings-over-serial-link.html

      Delete
    2. Good afternoon Dave,

      I still seem to be stuck on the receiver end, particularly around how to get the string from the rx.getdata() array.

      This is what I use to send my string... i.e. real simple

      unsigned long basetime = micros();
      ltoa(basetime, buf, 10);
      ZBTxRequest zbtx = ZBTxRequest(Broadcast, (uint8_t *)buf, strlen(buf));
      xbee.send(zbtx);

      On the receiving end, I can print all the data along with your other cool information print outs... but my basetime variable (as a string) seems to be only accessible by using the following -

      for (int i= 0; i < rx.getDataLength(); i++){
      //Serial.write(' ');
      if (iscntrl(rx.getData()[i]))
      Serial.write(' ');
      else
      Serial.write(rx.getData()[i]);
      Serial.write(' ');

      Is this "for" loop the only way to get the data. I studied your new blog code (thank you!) but ...well... am I missing something right in front of me?

      Thanks

      Bill

      Delete
  17. Nope, you're not missing anything that I can think of. Notice up there in my example how I print the text from the payload in a loop? That's because the data isn't guaranteed to have a null at the end of it to make it into a 'c' string.

    Let me 'splain what the loop you're using is actually doing. It's taking the characters out of the packet that was returned one at a time, checking to make sure the character isn't control character because that might mess up the display and the printing it using 'write' so there isn't any formatting done by Serial.print(). Since we don't know how long the buffer is and if it is safe to just stuff a null at the end of it, we have to copy it out into another place and stick the null at the end ourselves.

    so make a buffer to hold it and copy it character by character into the buffer and stick a null at the end. Then it's a real string and you can Serial.println( thenewbuffer); just fine. Actually, the code is almost there:

    char buffer[50];

    for (int 1=0; i<rx.getDataLength(); i++){
    buffer[i] = rx.getData()[i];
    }
    buffer[i] = 0;
    Serial.println(buffer);

    Taa Daa, buffer will now hold a string (if I didn't mess something up above). You can now use the new string any way a string can normally be used.

    Did this help?

    ReplyDelete
  18. Hi Dave,

    Yes that made all the difference. I did make that i=0; instead 1=0 and I took out the buffer[i]=0 ... but it seems to be ok. Now I'm working to reduce latency... more fun :-)

    Thanks again for all your help.

    Bill
    Thanks

    ReplyDelete
    Replies
    1. oops ...

      Be careful about not using the last buffer[i]=0; What can happen is that you put something longer in the buffer like "Hello World" then later put a number in it, you'll get something like "1.23o World" in the buffer which can cause you trouble. That's why most programmers stuff a null explicitly at the end of the text they're copying to be darn sure there's a null to terminate the string.

      Delete
  19. Hi Dave,

    Thanks for the advise. I've been redesigning the whole system and found a great way to simplify ... The biggest headache was getting the data transmitted with the correct time attached... time being accurate to a millisecond. I recently discovered the PPS signal from an Adafruits GPS. So now my arduinos are all synced and I can transmit much simpler data.

    ReplyDelete
    Replies
    1. I spent a couple of months messing around with time trying to get it right. Although I only want (not need) accuracy to the second, I couldn't get it. Finally I got one of Adafruit's GPS chips, combined it with an arduino and an XBee and put it in the attic. Now I have a time standard for the house that everything uses. They each sync their clock code to the house clock on boot and every time a new clock packet comes over the XBee network.

      I even have a tab for the clock up there somewhere. That was one of my best ideas.

      Delete
  20. I have a question. Will this code work on a Xbee Series 2 coordinator in API with 2 Xbee Series 2 routers in AT mode?

    ReplyDelete
    Replies
    1. Yes, but you have to be aware of what you'll get out. The routers, being in AT mode will only output the payload data to the serial port. Going the other way, what ever you send will come out the serial port in an API packet and have to be taken apart by the library.

      Delete
    2. Thanks for the reply! I got the code working & it works greats! But This still leaves me with a few other problems:

      In my network, there are 2 routers & 1 coordinator
      1. Error code 3 & Error code 1 comes up, & I think it may be due to my routers being in AT mode. My theory is they are both trying to talk to my coordinator at the same time & this creates a deadlock.
      2. Even when one of my routers are disconnected, I get to one Error code 1 message & 1 Error code 3 message momentarily.

      So here's my questions:
      First, to prevent deadlock, is it at all possible to program the coordinator in Arduino-C to tell each router to "wait"? Or can I do that straight from X-CTU?
      Second, what is the possible cause of the Error codes coming up when I only have only one of the routers connected? When I have the coordinator (in API mode) & one of the routers (in AT mode) connected to the network, it still displays Error code 1 & 3. The great thing is that the network displays those error print statements for short periods of time & goes back to normal, displaying the data as it should. I think both routers are walking all over each.

      Delete
    3. Error code 1 is a bad checksum and error code 3 is an unexpected start byte. So it sounds like you're using API mode 1 instead of API mode 2. Check your configuration, it's the AP command and it should be set to 2. In XCTU it's under the serial interface.

      The XBees don't deadlock. They may well transmit over the top of one another, but they automatically retry to take care of that. On an incredibly busy network, the collision rate can get high, but they do their best to correct for it. The way it works is they enable the radio and listen for a quiet spot and then try to transmit, if it gets clobbered by some other device, they will do it again. The times that they wait are semi random, so they will recover really well. There's no locking to worry about.

      Delete