May 25

Assembling an XBee API packet in PHP

In a previous post I showed how to parse an XBee API packet in C and PHP, for my project I needed both parsing and assembling of such packets. In case anyone would want to use it, here’s the PHP code for when you want to manipulate DIO pins.

function assemblePacket($module, $pin, $pinVal)
{
  $sum = 0; // checksum variable
  $packet = "<";
 
  if ($pinVal)
  { 
    $pinState = "05";
    $pinchk = 0x05;
  }
  else
  {
    $pinState = "04";
    $pinchk = 0x04;
  }
 
  $packet .= "7E"; // Start byte
  $packet .= "00"; // MSB length
  $packet .= "10"; // LSB length
 
  $packet .= "17"; // Remote AT command request
  $sum += 0x17;
  $packet .= "00"; // No response packet  
  $packet .= "00"; // 64bit address ignored Byte 1
  $packet .= "00"; // 64bit address ignored Byte 2
  $packet .= "00"; // 64bit address ignored Byte 3
  $packet .= "00"; // 64bit address ignored Byte 4
  $packet .= "00"; // 64bit address ignored Byte 5
  $packet .= "00"; // 64bit address ignored Byte 6
  $packet .= "00"; // 64bit address ignored Byte 7
  $packet .= "00"; // 64bit address ignored Byte 8
 
  $packet .= $module; // Module MSB and LSB
  $mbytes = str_split($module, 1);
  $sum += base_convert(getVal($mbytes[1]), 10, 16) + (base_convert(getVal($mbytes[0]), 10, 16) << 4);
  $sum += base_convert(getVal($mbytes[3]), 10, 16) + (base_convert(getVal($mbytes[2]), 10, 16) << 4); 
 
 
  $packet .= "02"; // Apply changes immediately
  $sum += 0x02;
  $packet .= "44"; // Character D in HEX
  $sum += 0x44;
  $packet .= (string)(30 + $pin); // Pin value, 0 in hex is 30
  $sum += dechex(30+$pin)+30;
  $packet .= $pinState; // Pinstate
  $sum += $pinchk;
  $checksum = 0xFF - ( $sum & 0xFF);
  $hack = str_split(dechex($checksum), 1);
  echo $hack[0];
  echo "     ";
  echo $hack[1];
  if(ctype_alpha($hack[0]))
    $packet .= strtoupper($hack[0]);
  else
    $packet .= $hack[0]; 
  if(ctype_alpha($hack[1]))
    $packet .= strtoupper($hack[1]);
  else
    $packet .= $hack[1];         
  $packet .= ">";
  return $packet;  
} 
 
function getVal($c)
{
   if($c >= '0' && $c <= '9')
     return ($c - '0');
   else
     return ($c-'A'+10);
}

You input the destination as a String, the pin as a number and the state as 0 or 1. Example:

$packet = assemblePacket("1337", 2, 1);

This would set pin DIO2 to high for the module with address 1337.

Update: Some things didn’t work before, especially if there were A-F values in the checksum, hence the dirty hack to get it to work. I know it’s not pretty but it works.

May 06

XBeeP, an XBee Packet Analyzer

I continued working on the XBee api frame (or packet, whatever you want to call it) analyzer and decided I should probably move on to something more suited for a computer program. I chose Java as I’ve had some classes on it in Uni, however the layout manager is still something I dislike as it took me quite a while to get a decent layout working (and it’s still a bit weird). I’m using the RXTX library to communicate with the COM port (Arduino does the same).

XBeeP v0.1

XBeeP v0.1

Here’s a screenshot of version 0.1 which can show you all incoming frames concerning sampling. I’ve used Java so I could make it crossplatform, however I’ll probably switch over to C# as building a decent GUI is easier as well as it has native support for COM ports and unsigned byte which Java does not (luckily a “signdByte & 0xFF” does the trick).

 

 

And lastly a short video of the program in action:

Once the program has some more functionality I’ll make it public. In case you would like to take a peek at the source code let me know.

May 04

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 &lt; 6; i++)
    adcVal[i] = 0;
 
  dioStatus = 0x0;
 
  if(Serial.available() &gt;= 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] &lt;&lt; 8);
       Serial.print(" --&gt; 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] &lt;&lt; 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] &lt;&lt; 8);
       Serial.print(" --&gt; 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;     
}