Basic Arduino-based XBee Packet Reader

A few days ago I was messing around with an Arduino board and a wireless shield mounted on it with a Series 1 XBee. Along with that another XBee was acting as a stand alone actuator. Unfortunately I had some troubles with reading the API packets the standalone XBee was sending back (X-CTU and any terminal really) displays the incoming data in a pretty much unreadable format for humans to directly interpret it. Garbled ASCII or HEX values aren’t particularly easy on the not-so-well trained eye. That’s why I decided to quickly whip up a packet interpreter program in the Arduino IDE.

Here’s my first basic version:

float vref = 3.3;
int resolution = 1024;
float result = 0;
 
byte join[2] = {0,0};
int numOfBytes = 0;
int sourceAddr = 0;
int numOfSamples = 0;
int data = 0;
 
byte adcStatus = 0x0;
float adcVal[6] = {0,0,0,0,0,0};
 
byte dioStatus = 0x0;
byte dioVal = 0x0;
 
void setup() {
  Serial.begin(9600);
}
 
void loop()
{
  numOfBytes = 0;
  sourceAddr = 0;
  numOfSamples = 0;
  data = 0;
 
  adcStatus = 0x0;
  for(int i = 0; i < 6; i++)
    adcVal[i] = 0;
 
  dioStatus = 0x0;
 
  if(Serial.available() >= 28) // Check for at least one complete frame
     if(Serial.read() == 0x7E) // Start at beginning of frame
     {
       Serial.print("Start Byte: 0x7E");
 
//-------------- Number of Bytes in Frame ---------//       
 
       Serial.print("\nNr Of Bytes: ");
       join[0] = Serial.read();
       Serial.print(join[0], HEX); // MSB length
       Serial.print(" ");
       join[1] = Serial.read();
       Serial.print(join[1], HEX); // LSB length
       numOfBytes = join[1] + (join[0] << 8);
       Serial.print(" --> DEC Value: ");
       Serial.print(numOfBytes);      
 
//-------------- Source Address Checking ---------//       
 
       Serial.print("\nAddress Mode: ");
       Serial.print(Serial.read(), HEX); // 83 = 16bit address
       Serial.print("\nSource Address: ");
       join[0] = Serial.read();
       Serial.print(join[0], HEX); // MSB Address
       Serial.print(" ");
       join[1] = Serial.read();
       Serial.print(join[1], HEX); // LSB Address
       sourceAddr = join[1] + (join[0] << 8);       
 
//-------------- RSSI Checking ---------//  
 
       Serial.print("\nRSSI (signal strength in -dBm): ");
       Serial.print(Serial.read(), DEC); 
 
//-------------- Number of Samples in Frame ---------//   
 
       Serial.print("\nNr of Samples: ");
       join[0] = Serial.read();
       Serial.print(join[0], HEX); // MSB samples
       Serial.print(" ");
       join[1] = Serial.read();
       Serial.print(join[1], HEX); // LSB samples
       numOfSamples = join[1] + (join[0] << 8);
       Serial.print(" --> DEC Value: ");
       Serial.print(numOfSamples);       
 
//-------------- Channel Indicator  ---------//
 
       Serial.print("\nChannel Bitfield: ");
       adcStatus = Serial.read();
       Serial.print(adcStatus, BIN); // Neglecting D8
       Serial.print(" ");
       dioStatus = Serial.read();
       Serial.print(dioStatus, BIN);              
 
//-------------- Fetching Data word DIO ---------//     
 
       if(dioStatus > 0x0)
       {
         Serial.print("\nData DIO: ");       
         Serial.print(Serial.read(), BIN);       
         Serial.print(" ");
         dioVal = Serial.read(); // Neglecting D8       
         Serial.print(dioVal, BIN);              
         Serial.print(" --> ");
 
         for(int i = 0; i <= 7; i++)
         {
           Serial.print("D");
           Serial.print(i);           
           if(bitRead(dioVal, i))
             Serial.print("H");
           else
             Serial.print("L");
           Serial.print("  ");
         } 
 
       }
       else
         Serial.print("\nNo DIO data in frame");         
 
//-------------- Fetching Data word ADC ---------//
 
       if(adcStatus > 0x0)
       {
         for(int i = 1; i <= 6; i++)
         {
           if(bitRead(adcStatus, i))
           {         
             //Serial.print("\nData ADC #");
             //Serial.print(i);
             //Serial.print(": ");         
             join[0] = Serial.read();     
             //Serial.print(join[0], BIN); // MSB Data
             //Serial.print(" ");
             join[1] = Serial.read();
             //Serial.print(join[1], BIN); // LSB Data               
             data = join[1] + (join[0] << 8); 
             //Serial.print(" --> DEC Value: ");
             //Serial.print(data);          
             result = (vref/resolution)*data;
             adcVal[i-1] = result;
             //Serial.print(" - Voltage: ");
             //Serial.print(result);
           }
         }
         Serial.print("\nData ADC: ");         
         for(int i = 0; i < 6; i++)
         {
           if(bitRead(adcStatus, i+1))
           {
             Serial.print("ADC");
             Serial.print(i);
             Serial.print(": ");
             Serial.print(adcVal[i]);
             Serial.print("  ");
           }
         }
       }
       else
         Serial.print("\nNo ADC data in frame");          
 
 
 
       Serial.print("\n------------------\n");        
     }
 
}

This will output something like the following:

Start Byte: 0x7E
Nr Of Bytes: 0 10 –> DEC Value: 16
Address Mode: 83
Source Address: 50 0
RSSI (signal strength in -dBm): 35
Nr of Samples: 0 1 –> DEC Value: 1
Channel Bitfield: 100110 11101000
Data DIO: 0 10001000 –> D0L D1L D2L D3H D4L D5L D6L D7H
Data ADC: ADC0: 2.31 ADC1: 1.80 ADC4: 1.41
——————

 

Personally, I like this layout, you can quickly see what the status is of every XBee IO pin. I was thinking of adding a graphical interface but then again the gain is little and it’s not really worth the effort.

If you have any questions, suggestions or feedback, please let me know and I’ll get back to you.

Update: Check out my GUI version, XBeeP.

Update 2: And just because I can, an improved version in PHP (the Arduino version contains some small errors in the logic).

$packet = "835678220005060002C003FF"; // Example input (only payload)
 
function parsePacket($packet)
{
   $bytes = str_split($packet, 2);
   foreach($bytes as $val)
    echo $val . " ";
 
   //$api_type = $bytes[0]; // ----> SHOULD ALWAYS BE 83!   
   $source = dechex(intval($bytes[2], 16) + (intval($bytes[1], 16) << 8));
   //$rssi = $bytes[3];
   //$samples = $bytes[5] + ($bytes[4] << 8);
   $adcStatus = (intval($bytes[6], 16) >> 1);
   $dioStatus = intval($bytes[7], 16);
 
   $c = 8;
 
   if($dioStatus > 0)
   {
    $dioMSB = $bytes[$c++];
    $dioVal = intval($bytes[$c++], 16);
   }
 
   if($adcStatus > 0)
   {
      for($i = 0; $i <= 5; $i++)
      {
 
        if($adcStatus & (1 << $i))
        {    
          $adcVal[$i] = (intval($bytes[$c+1+$i], 16) + (intval($bytes[$c+$i], 16) << 8));
          $adcString .= "ADC" . $i . " " . $adcVal[$i]/1024*3.3;
          $c++;
        }
      }  
   }
   echo "Source " .
        $source . " ADC " .
        decbin($adcStatus) . " DIO " .
        decbin($dioStatus) . " dioVal" .
        $dioVal . " adcval" .
        $adcString;     
}