understanding xbee and arduino serial

I have managed to get my xbee series one units arranged in a network of sorts.

One xbee acts as a remote sensor with nothing but a power supply and a couple of analog sensors. The other xbee is connected via an adafruit shield to my arduino.

That remote xbee monitors it's ADC pins, and broadcasts the pins states , along with a lot of other crap, to the "coordinator" xbee.

I tried using the xbee api library, and i got no where with that at all. I couldn't even get the xbees to talk to each other at all.

In transparent mode, I can see the broadcast of the data , 22 bytes of it, but i can't figure out how to get the parts out of it that I need.

All I really want is the remote sensor address, and the values of the three sensors.

I can see the values when i print them out via the arduino serial, but am totally confused as to how to get what i want out of the string and into a usable value.

Can anyone tell me how to pull that string into an array and get the parts out that I want?

Thanks to any one that can help.

It's hard to give any specifics without seeing your string or your code....

The key concept here is parsing a string. The easiest way to do that is as the characters are received, in my own experience.
Two possible scenarios: variable length data, fixed length data.
With fixed length data it is very straight forward, with variable length you need to have a delineator between fields, like a space, comma, or tab. Each time you detect a delineator, increment your array index and start adding characters to the next array element. That's how I would parse a command line where you end up with a command and an array of parameters.
If you are sending data, there is the question of how is the data being sent: is it in binary form, or is everything converted to strings. Example: sending an integer - if the integer is sent in binary form, then it will always be two bytes (fixed length). Sending code breaks the integer up into it's upper and lower bytes, and the recieving code puts these back together and assigns the value to a variable. If the integer is sent by using Serial.print(i,DEC) then the receiving code will have to detect the end of data field string and use atoi() to convert the string back into an integer.
It sounds like you may have a fixed length situation currently (22 bytes), but I don't know if field lengths vary within that. I would suggest creating a structure and reading into that.

Here's a snippet I extracted from some code that I was using to send packets over I2C that should work for serial too. You might want some more code to zero things out before the read:

struct MyData {
  byte addr;
  byte cmd;
  byte flag;
  short return_bytes;
  int parm1;
  int parm2;
} mydata;

void receiveData()
{
  byte* p = (byte*)(void*)&mydata;
  int i;
  for (i = 0; i < sizeof(mydata); i++)
  {
    if (Serial.available())
      *p++ = Serial.read();
    else
      break;
  }
  while (Serial.available()) Serial.read(); // eat anything more than mydata
  }

Here's another little snippet that I used for parsing a command line received. This may be useful for you with some modifications:

char cmd_line[80];  //entire input command line
char cmd_str[8];   //first word of command line
char cmd_parm_str[60]; // rest of the line parsed out
#define max_params 6
#define max_param_len 10
char cmd_parm[max_params][max_param_len];//up to six parameters, of twelve characters each, separated by commas or spaces
int cmd_n_parms;    //populated size of cmd_parm up to max_params

  if (Serial.available())
  {
    lcd.clear();
    lcd.cursorTo(1,0);
    lcd.printIn("Recieving....");
    delay(500);
    i=0;
    j=0;
    k=0;
    l=0;
    cmd_parm_str[0]=0;                              // clear param string
    for (int x;x<max_params;x++) cmd_parm[x][0]=0; // clear out previous parameters

    //get a command line
    boolean first_word=true;
    while (Serial.available())
    {
      in_ch = upper(Serial.read());
      cmd_line[i] = in_ch;
      if (first_word && (in_ch == ' '))
      {
        first_word=false;
        cmd_str[i]=0; // add null terminator
        i++;
        continue;
      }
      if (first_word) cmd_str[i]=in_ch;
      else // build cmd_parm_str
      { cmd_parm_str[j++]=in_ch;
        if (in_ch==' ' || in_ch==',')
        { cmd_parm[k][l]=0;
          k++;
          l=0;
        }
        else
        {
          cmd_parm[k][l++]=in_ch;
        }
      }
      i++;
    } // end while
    if (!first_word)
    {                      // we had parameters so...
      cmd_parm_str[j]=0;   // null terminate param string
      cmd_parm[k][l]=0;    // and the last param
      cmd_n_parms = k+1;   // remember number of parameters (k doesn't get a chance to increment for last parm so add 1
    }
    else
      cmd_str[i]=0;        // terminate command str which normally happens when we start parsing parameters

Thanks for the reply, sorry it took me so long to reply, been out of town.

I had stated I received 22 bytes.. that's incorrect .

I am using this simple code at present just to see what data is being received by my base arduino:

#include <NewSoftSerial.h>

NewSoftSerial Xbee(2/*TX ON XBEE */,3/*RX ON XBEE */);


void setup()
{
Serial.begin(9600);
Xbee.begin(9600);
}

void loop()
{
if (Xbee.available()) {
byte incomingByte = Xbee.read();
Serial.print(incomingByte, HEX);
Serial.print(" , ");

}
 
}

I am sure that the data being sent by the remote xbee is hexadecimal, and I know for sure that the very first byte of each string sent is :0x7E

Here is a sample of the output from the serial monitor when I have the units setup:
7E , 0 , A , 83 , 0 , 0 , 26 , 0 , 1 , 2 , 0 , 3 , FF , 51
I think that the last two bytes are the ones I need.. at least that's what I can tell by reading through the data a maxstream.

The main things I don't understand is how to parse through that string to the bits at the end, which should be my analog sensor reading. And then translate that reading back to a usable value.

Any help is appreciated.

This is the Xbee API mode, and is detailed in the corresponding manual from Digi.

I was able to get it to work without using api mode. As a matter of fact, I could not get the api library to do what i want it to do. I talked with andrew rapp that wrote that library, and he said that he has not implemented the type of process that I am asking about.

So, the api library will not do it. Api mode in general may be capable, but that is above my scope.

Using a simple array, I can now get whatever information I want from the packet, api mode not needed.

I thought that the Xbee only broadcast pin information in API mode, or are you using a MC with it at the sensor end?

I liked transparent mode too, unfortunately when you start getting multiple messages from multiple clients at once they can clash and be indistinguishable. API mode should fix that.

No, it's a standalone setup. On the sensor end, i have only the xbee, a 3.3volt regulator, and currently, a switch. The switch will eventually be replaced with a real sensor, but for my purpose right now, it works fine.

The switch is connected via a 4.7k resistor to 3.3volt, and the other side of the switch is connected to ground. I have adc 4 watching the pin and transmitting on a 1.5 second basis.

I am using a simple sketch on the receiver end to catch the serial output of the base xbee, and suck it into an array. I then can parse through the array any way I want. Getting the value of the switches present state is not a problem.

You can see the sketch on my site here:
http://www.grinanbarrett.com/index.php?option=com_content&view=article&id=61:xbee-remote-standalone-sensor-and-arduino-xbee There is also a schematic there of the sensor side.

I also agree that it could possibly be a problem for me when i have multiple xbees running, but, i think using some scripting to catch the serial messages, and then parse out the sender address and sensor value should be fairly easy.

Cool. I assume you are running the sensor end in API mode then as I don't believe they send sensor data in transparent mode? As far as I know they also don't send their address etc. which is where you come into trouble trying to differentiate multiple nodes.

well, from all that I have seen, they do broadcast those things.

I also have the rssi strength as well..

I am not, and I swear, using api mode.

Using x-ctu, I wiped before I started.. All of my values are at default on the sender unit except for:
d4 under i/o settings, it is set to 3, which is digital input
ic- which is set as FF which watches all enabled pins for changes and then broadcasts.

On this unit, the remote, the AP setting is 0-api disabled.

On the base unit, (receiver w/e), All of the settings are default out of the box settings. Nothing is changed at all. Which means api mode is set as 0-api disabled.

I have another sketch that watches the serial port on the xbee, and just relays what comes through over the serial monitor.. when i fire up the xbee's with this setup, i get the following string:
7E , 0 , A , 83 , 0 , 0 , 26 , 0 , 1 , 2 , 0 , 3 , FF , 51 whenever the pin state changes.

I don't think that that is api mode. I am not using the api library, there are no api calls in my code, both xbees are set to 0-api disabled.

If you have some series ones, hook em up and run my code.. set up one with the setup above, and see what happens. Maybe my xbees are messed up! ;D

That's odd. That is an API frame you are describing. Transparent mode just sends whatever string you put into the Xbee out, no hex packets or anything.

well, i just noticed something odder than that.. I have got it set to transmit when it detects changes on pin 4, and it turns out it's transmitting constantly.. which makes no sense.. so further investigation is needed.

Ok, I worked with my xbees for a while last night.. I am not sure what was happening with them, but i have it all sorted out now.

I am now using the xbees in api mode 2, and things work soooo much better now.

I am using the following config on the sender xbee, and it is standalone:
DL-1234
MY-5678
CE- 0-end device
NI- SENSOR

AP- 2

DIO4- 3-digital input

IC- 10 (watches pin 4 only for changes and broadcasts only when the state changes)

On the base unit, i have the following settings:

MY - 1234
CE - 1 (coordinator)
NI - COORDINATOR
AP - 2

Now, here is the sketch that I am using on the base unit.

Currently, it catches the API string when it's sent from the remote sensor, and broadcasts it through the serial monitor. It shows the sensor id when it does receive an "alarm" state.

#include <NewSoftSerial.h>
/*
Basic Xbee Remote Sensor Alarm
 This sketch reads the state of a string sent by a remote "sensor" xbee series 1.
 The "Sensor" xbee is just an xbee series 1 on an adafruit xbee breakoutboard, it supplies 3.3v
 to a switch, when the switch is depressed, ie, goes low, the packet changes that is sent.
 
 This sketch checks that packet for a change and reports it to the serial monitor.
 */

int incomingByte=0; // to catch the incoming bytes
int PacketArray[14] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1}; // to store the validated xbee packet
int Alarms; // to store the number of times the alarm has been sent by the remote xbee.

NewSoftSerial xBee = NewSoftSerial(2, 3);

void setup()
{
  Serial.begin(9600);
  xBee.begin(9600);
  Serial.println("Connected to Xbee Remote");
  pinMode(10, OUTPUT);

}

void loop()
{
  if (xBee.available()>13) { //checks to make sure that we have received at least one frame worth of bytes
    incomingByte=xBee.read();
    if(incomingByte== 0x7E){
      PacketArray[0]=0x7E;
      for(int i=1; i<14; i=i ++) {
        PacketArray[i] = xBee.read();
      } 
}else{
  int junk = xBee.read();
}
}
if(PacketArray[12]==0){
  digitalWrite(10,HIGH);
  Serial.print("Alarm detected on sensor ");
  Serial.print(PacketArray[4], HEX);
  Serial.print(PacketArray[5], HEX);
  Serial.print("!");
  Serial.println(" ");

}
else{
  digitalWrite(10,LOW);
}
}

I can not explain why it was broadcasting api strings when it was not in api mode, but it does. Since changing to api it broadcasts only when it detects a change, and it broadcasts that same api string.

Who knows.. it works now and thats' all that matters to me.

hmm I used your setup but without success. I don't get any data from the Sensor Xbee it doesn't send any data. I think there is still a problem with the configuration of those Xbee's could you send me the hole config from the X-CTU program?

EDIT: Oooops sorry now it does work hmm can't remeber what I've changed :slight_smile:

thx

Remember that I am waiting for a change on dio4 before broadcasting.

before I went to api mode, it was broadcasting nonstop.. now with api, it broadcasts when i press a switch connected to the remote xbee and pull adc4 low.

Yes I know, thx. Now it should be easy to read out the Analog Sensor Data.

byte 1: 0x7E, the start byte value
byte 2-3: packet size, a 2-byte value
byte 4: API identifier value, a code that says what this response is
byte 5-6: Sender's address
byte 7: RSSI, Received Signal Strength Indicator
byte 8: Broadcast options
byte 9: Number of samples to follow
byte 10-11: Active channels indicator
byte 12-21: 5 10-bit values, each ADC samples from the sender

You should be able to use the xbee-arduino library to do this. Although it doesn't implement i/o samples yet, it should parse any valid xbee packet.

In your loop:

xbee.readPacket();
if (xbee.getResponse().isAvailable()) {

if (xbee.getResponse().getApiId() == RX_16_IO_RESPONSE) {
// got a i/o sample
// now we just need to pick out the relevant parts
// we can access the packet with xbee.getResponse().getFrameData()
// per the doc http://xbee-arduino.googlecode.com/svn/trunk/docs/api/class_x_bee_response.html#d958f0b5200138545bdd762111299a94
// the frame data starts with the byte that follows the api id
// now open your manual to page 62 http://ftp1.digi.com/support/documentation/90000982_A.pdf
// we can see the fifth byte takes us to the RF data -- the meat of the packet.
// now go to page 12. the first byte is # samples, then the channel indicators. you're looking for dio4 and that's the fifth bit of the fifth byte (not making this up). So really byte # 9. So this should do it:
if ((xbee.getResponse().getFrameData()[9] & (1 << 4)) {
// it's on
}
}
}
Let me know if this works. Hopefully I got the correct byte. I can look into adding this feature to the library if there's enough interest.

sorry, that should be

if ((xbee.getResponse().getFrameData()[8] & (1 << 4)) {
// it's on

}

of course arrays start at 0

I'm about to waltz into the same situation as described here, but I was unable to see the diagram link mentioned earlier.
Grinan, are you pressing a switch to drop adc4 to 0V? How do you
then measure anything on it?

FYI, I have since updated the xbee-arduino library (GitHub - andrewrapp/xbee-arduino: Arduino library for communicating with XBee radios in API mode) to support i/o samples. See this example for series 1:

and this one for series 2:

Rappa, I downloaded and installed the Xbee library for V15; but there is trouble: I am getting "does not name a type" for ZBRxIoSampleResponse(), which is right after XBee() in Series2IoSamples example.

Got it - a badly named old file caused the problem.