XBee in API mode, preparing data to be send and parsing received data

Based on Andrew Rapp XBEE.h library. I have been able to get my 2 Arduino with XBee (in API 2 mode) to exchange data in both direction and received confirmation of reception. I have been sending only one byte of data and I have been able to get each Arduino to execute a function based on the content of this byte (multiple LED are turn on/off).

The data used so far is very simplle. Everything is down to 1 byte which I put into the array variable payload[]. In Adnrew's sketch example, he provides an example how to convert an integer into 2 byte of HEX at the Tx end.

int pin5 = 0; .... pin5 = analogRead(5); payload[0] = pin5 >> 8 & 0xff; payload[1] = pin5 & 0xff;

However at the Rx end, only the first byte is used.

data = rx16.getData(0); ...... // set dataLed PWM to value of the first byte in the data analogWrite(dataLed, data);

My question (programming); how do I populate the array payload with other data type "char", "unsinged int:, "float" data type variable ?

At the Rx end, how do I reconstruct these data types. I would know exactly how many byte each variable used and their position will not vary in the array. For example in Andrew's program, if the int being send is something else greater than int "254" , let say "678" for example, how do I parse and reconstruct this int ?

Finally, is there a way to pass data structure to the XBee in API mode?

I need programming hints, suggestions or even better an example using Ardrew's library but with more complex set of data types being used.

Any help would be greatly appreciated, I have been struggling with this problem for many days. I din't find useful information so far in Google. Probably because, I don't know how to ask the question.

However at the Rx end, only the first byte is used.

data = rx16.getData(0);

How is data defined?

My question (programming); how do I populate the array payload with other data type "char", "unsinged int:, "float" data type variable ?

It would depend on how payload[] is defined. You need to share (more) code.

If payload is a byte array, you can copy chars into it directly. For ints, highByte() and lowByte() are useful. For larger types, such as long and float, a union works well to extract the individual bytes. Set the float; get the bytes.

Reconstructing the value on the other end is equally easy. Copy chars directly. Use the word() function to create the int from the high and low bytes. For larger types, the same union can be used. Set the bytes; get the float/long.

Finally, is there a way to pass data structure to the XBee in API mode?

Clearly there is. You say you are doing it now.

Thank you Paul for your answer.

You have already given me a useful information. Using word() to reconstruct an integer at the Rx end.

The examples that I provided were copied from Andrew Rapp’s examples program.

Data is defined, in the Rx sketch as follow : “uint8_t data = 0” . This variable is populated by “data = rx16.getData(0);”

Payload is defined, in the Tx sketch as follow: “uint8_t payload = { 0, 0 };” . It is populated as stated in my original question

int pin5 = 0;

pin5 = analogRead(5);
payload[0] = pin5 >> 8 & 0xff;
payload[1] = pin5 & 0xff;

For larger types, such as long and float, a union works well to extract the individual bytes. Set the float; get the bytes.

What is a “union” ? This is not a data type. Could you provide an example how to set and get the bytes as well as how to reconstruct the long or float at the Rx end.

I did not know that I was using a structure, this is good news. However. following is an example of one structure that I used in another program

typedef struct THERMOMETER 
{
  byte location;
  byte post;
  byte object;
  byte high_Alarm;
  byte low_Alarm;
  float current_temp_Value;
  float previous_temp_Value;
  boolean temp_Changed;
};

With XBee.h library, do you know if I must transmit data into a byte array or if I can send any data type without conversion to byte ?
Where multiple data types can be mixed and matched. In the best word, I would like to send my structure directly without conversion.

Thank you, Gaston

What is a "union" ? This is not a data type. Could you provide an example how to set and get the bytes as well as how to reconstruct the long or float at the Rx end.

It is a C feature.

   union {
      float f;
      byte b[4];
   } stuff;

stuff.f = "3.14159";

payload[0] = stuff.b[0];
payload[1] = stuff.b[1];
payload[2] = stuff.b[2];
payload[3] = stuff.b[3];

Send payload, then.

On receipt, reverse the process.

stuff.b[0] = rx16.getData(0);
stuff.b[1] = rx16.getData(1);
stuff.b[2] = rx16.getData(2);
stuff.b[3] = rx16.getData(3);

Serial.print("pi = ");
Serial.println(stuff.f);

I did not know that I was using a structure, this is good news.

I must have misunderstood your question.

With XBee.h library, do you know if I must transmit data into a byte array or if I can send any data type without conversion to byte ?

The TxNNRequest class takes a byte array as the payload, so conversion of float/long/int/etc. is required. You can, of course, convert any data type from/to bytes.

Thanks to you Paul, I got it all to work.

I am attaching both sketches, hoping that someone else can learn from it.

Tx sketch

/**
 * Basis communication text for xBEEe-Arduino.
 * set the ADDRESS for the destination xBee 
 * LED will flash to confirm the test or the error
 */
 
#include <XBee.h>


/*
This example is for Series 1 XBee
Sends a TX16 or TX64 request with the value of analogRead(pin5) and checks the status response for success
*/

XBee xbee = XBee();

unsigned long start = millis();

// allocate two bytes for to hold a 10-bit analog reading
uint8_t payload[] = { 0, 0,0,0,0,0,0,0 };

// with Series 1 you can use either 16-bit or 64-bit addressing

// 16-bit addressing: Enter address of remote XBee, typically the coordinator
Tx16Request tx = Tx16Request(0x1111, payload, sizeof(payload));

// 64-bit addressing: This is the SH + SL address of remote XBee
//XBeeAddress64 addr64 = XBeeAddress64(0x0013a200, 0x4008b490);
// unless you have MY on the receiving radio set to FFFF, this will be received as a RX16 packet
//Tx64Request tx = Tx64Request(addr64, payload, sizeof(payload));

TxStatusResponse txStatus = TxStatusResponse();

int pin5 = 0;

int statusLed = 13;

union {
      float f;
      byte b[4];
   } stuff;

void setup() {
  pinMode(statusLed, OUTPUT);
  
  xbee.begin(9600);  // start serial
  
  flashLed(statusLed, 30, 50);
}

void loop() {
   
   // start transmitting after a startup delay.  Note: this will rollover to 0 eventually so not best way to handle
    if (millis() - start > 15000) {
      
      // Sending a byte 
      byte test_byte = 9;
      payload[0] = test_byte;
      // Sending a char
      char test_char  = 'a';
      payload[1] = test_char;                 // Non conversion needed, just sent the ASCII value
      // Sending an int
      int test_int = 1232;
      payload[2] = test_int >> 8 & 0xff;      // Converting int to hex could also used highByte() lowByte()
      payload[3] = test_int & 0xff;
      // Sending a float
      stuff.f = 3.14159;
      payload[4] = stuff.b[0];                // Converting using the data type defined in "union"
      payload[5] = stuff.b[1];
      payload[6] = stuff.b[2];
      payload[7] = stuff.b[3];
      
      xbee.send(tx);
      delay(2000);               // Delay to allow reading of the message

      // flash TX indicator
      flashLed(statusLed, 5, 100);
    }
  
    // after sending a tx request, we expect a status response
    // wait up to 5 seconds for the status response
    if (xbee.readPacket(5000)) {
        // got a response!

        // should be a znet tx status            	
    	if (xbee.getResponse().getApiId() == TX_STATUS_RESPONSE) {
    	   xbee.getResponse().getZBTxStatusResponse(txStatus);
    		
    	   // get the delivery status, the fifth byte
           if (txStatus.getStatus() == 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);
               flashLed(statusLed, 3, 1000);
           }
        }      
    } else if (xbee.getResponse().isError()) {
      //nss.print("Error reading packet.  Error code: ");  
      //nss.println(xbee.getResponse().getErrorCode());
      // or flash error led
    } else {
      // local XBee did not provide a timely TX Status Response.  Radio is not configured properly or connected
      //flashLed(errorLed, 2, 50);
      flashLed(statusLed, 5, 1000);
    }
    
    delay(3000);
}

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);
      }
    }
}

Rx

/**
 * Basis communication text for xBEEe-Arduino.
 * LED will flash to confirm the test or the error 
 */
 

#include <XBee.h>
#include <SoftwareSerial.h> // to be used for LCD Display

/*
This example is for Series 1 XBee (802.15.4)
Receives either a RX16 or RX64 packet and sets a PWM value based on packet data.
Error led is flashed if an unexpected packet is received
*/

XBee xbee = XBee();
XBeeResponse response = XBeeResponse();
// create reusable response objects for responses we expect to handle 
Rx16Response rx16 = Rx16Response();
Rx64Response rx64 = Rx64Response();

int statusLed = 13;


uint8_t option = 0;
uint8_t data = 0;

union {
      float f;
      byte b[4];
   } stuff;

SoftwareSerial myLCD(9,10);

void setup() {
  pinMode(statusLed, OUTPUT);
  
 
  xbee.begin(9600);  // start serial
  myLCD.begin(9600);
  flashLed(statusLed, 30, 50);
}

// continuously reads packets, looking for RX16 or RX64
void loop() {
    
    xbee.readPacket();
    
    if (xbee.getResponse().isAvailable()) {
      // got something
      flashLed(statusLed, 10, 50);
      if (xbee.getResponse().getApiId() == RX_16_RESPONSE || xbee.getResponse().getApiId() == RX_64_RESPONSE) {
        // got a rx packet
        
        if (xbee.getResponse().getApiId() == RX_16_RESPONSE) {
                xbee.getResponse().getRx16Response(rx16);
        	option = rx16.getOption();
        	data = rx16.getData(0);
        } else {
                xbee.getResponse().getRx64Response(rx64);
        	option = rx64.getOption();
        	data = rx64.getData(0);
        }
        
        flashLed(statusLed, 10, 50);
        
        myLCD.write(0xFE); myLCD.write(0x01);  // Clear Screen
        myLCD.print("Getting message");
          delay(15);  
        myLCD.write(0x0A); // Line Feed 
        
        // Receiving and printing a byte
        myLCD.print(rx16.getData(0));  myLCD.print(" ");
        
        // Receiving and printing a char
        myLCD.print(char(rx16.getData(1))); myLCD.print(" ");
        
        // Receiving and printing an int
         byte unite1 = rx16.getData(2);
         byte unite2 = rx16.getData(3);
         myLCD.print(word(unite1,unite2)); myLCD.print(" ");
         
         // Receiving and printing a float
         stuff.b[0] = rx16.getData(4);
         stuff.b[1] = rx16.getData(5);
         stuff.b[2] = rx16.getData(6);
         stuff.b[3] = rx16.getData(7);
         myLCD.print(stuff.f);
         
         

         flashLed(statusLed, 10, 50);
        myLCD.write(0xFE); myLCD.write(0x01);  // Clear Screen
        
      } else {
      	// not something we were expecting
        flashLed(statusLed, 3, 1000);    
      }
    } else if (xbee.getResponse().isError()) {
      flashLed(statusLed, 3, 1000);    
    } 
}

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);
      }
    }
}

Thanks to Andrew Rapp for writing the XBee library and Paul for providing guidance how to use it.

1 Like
// allocate two bytes for to hold a 10-bit analog reading
uint8_t payload[] = { 0, 0,0,0,0,0,0,0 };

The code and comment do not match. The default initializer for a uint8_t item is 0, so explicitly defining the size, and allowing the compiler to determine how many initializers are needed is a better idea.

   // start transmitting after a startup delay.  Note: this will rollover to 0 eventually so not best way to handle
    if (millis() - start > 15000) {

Yes, it is. Except that should probably be >=, not >.

hi, I know this is an old post but please reply...

Using the same method you have used please can you give me a sample code both transmission and receiving for 2 integer values and 1 boolean value. Please help me its very important.

1 Like