An experilemtal tool to configure XBee modems

Hi,

I just published an experimental tool to configure XBee modems for wireless programming.

http://funnel.googlecode.com/files/XBeeConfigTool_r541.dmg
http://funnel.googlecode.com/files/XBeeConfigTool_r541.zip

First of all, thank you very much to Limor for proposing a smart way to do programming wirelessly.

Xbee Adapter - wireless Arduino programming
http://www.ladyada.net/make/xbee/arduino.html

I slightly modified settings on a coordinator side (set IC as 0x8 instead of 0xFF to do not confuse a RSSI LED on end devices side), but basically same as Limor's. I developed this tool for FIO (Funnel I/O), but might be useful for other platforms such as XBee Adapter kit or (hacked) Arduino XBee Shield.

I just tested on Mac OS X 10.5.5 with a XBee USB Explorer. I'm sorry for trouble you, but it would be much appreciated if you give me a bug report and/or suggestions about this tool.

Best,
Shigeru

Shigeru, Nice job!

I have run a quick test on XP SP3 and it seems to work nicely. I have not run the xbee's after configuring with the tool (that will take some time to set up) but it looks like it has worked. Sure is a lot easier than entering the commands by hand, many thanks for your handwork.

One suggestion that immediately came to mind is a facility for a button to read and display the fields set. This provides more feedback than just the 'Configured successfully' message and could be useful if one later forgets the id settings.

Hi,

Thank you very much for your suggestion. I just updated the tools to add "Read" button to read written settings.

http://funnel.googlecode.com/files/XBeeConfigTool_r544.zip
http://funnel.googlecode.com/files/XBeeConfigTool_r544.dmg

I have to improve the UI, but please give it a try.

Best,
Shigeru

Hi Shigeru, I have made some additions to the code to display more status information that you may find useful.

import processing.serial.*;
import interfascia.*;

final int COORDINATOR = 0;
final int END_DEVICES = 1;

GUIController gui;
IFRadioController portRadioButtons;
IFLabel l;

IFRadioButton[] b;

IFLabel idLabel;
IFLabel myLabel;
IFTextField idTextField;
IFTextField myTextField;

IFRadioController modeRadioButtons;
IFLabel modeButtonsLabel;
IFRadioButton[] modeButton;

IFButton configureButton;
IFButton exitButton;
IFButton readButton;

IFLabel statusTextLabel;

IFLabel statusBaudRate;
IFLabel statusSerialNumberHigh;
IFLabel statusSerialNumberLow;
IFLabel statusFirmwareVersion;


Serial serialPort;

final String[] AT_COMMANDS = {
  "BD", "ID", "MY", "DL", "D3", "IC", "IU", "IA"};

final String[] AT_READ = {   // commands sent to read xbee data
  "BD", "ID", "MY", "DL", "SH", "SL", "VR"};
  
final String[] BAUD_RATES = {
  "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200"};

void setup() {
  size(500, 400);
  background(150);

  int y = 20;

  gui = new GUIController(this);
  portRadioButtons = new IFRadioController("Mode Selector");
  l = new IFLabel("Serial Port", 20, y, 12);
  gui.add(l);

  String[] portList = Serial.list();

  y += 14;
  b = new IFRadioButton[portList.length];
  for (int i = 0; i < portList.length; i++) {
    b[i] = new IFRadioButton(portList[i], 20, y, portRadioButtons);
    gui.add(b[i]);
    y += 20;
  }

  y += 8;
  idLabel = new IFLabel ("PAN ID", 20, y);
  gui.add(idLabel);
  y += 14;
  idTextField = new IFTextField("ID", 20, y, 60, "1234");
  gui.add(idTextField);
  y += 38;
  myLabel = new IFLabel ("MY ID", 20, y);
  gui.add(myLabel);
  y += 14;
  myTextField = new IFTextField("MY", 20, y, 60, "0000");
  gui.add(myTextField);
  y += 38;

  modeRadioButtons = new IFRadioController("Mode Selector");
  modeRadioButtons.addActionListener(this);
  modeButtonsLabel = new IFLabel("Mode", 20, y, 12);
  gui.add(modeButtonsLabel);
  y += 14;
  modeButton = new IFRadioButton[2];
  modeButton[0] = new IFRadioButton("Coordinator", 20, y, modeRadioButtons);
  //  modeButton[0].addActionListener(this);
  gui.add(modeButton[0]);
  y += 20;
  modeButton[1] = new IFRadioButton("End Devices", 20, y, modeRadioButtons);
  //  modeButton[1].addActionListener(this);
  gui.add(modeButton[1]);
  y += 20;

  y += 16;
  configureButton = new IFButton("Configure", 20, y, 80, 20);
  configureButton.addActionListener(this);
  gui.add(configureButton);
  readButton = new IFButton("Read", 108, y, 80, 20);
  readButton.addActionListener(this);
  gui.add(readButton);
  exitButton = new IFButton("Exit", 196, y, 80, 20);
  exitButton.addActionListener(this);
  gui.add(exitButton);

  y += 38;
  statusTextLabel = new IFLabel("", 20, y, 12);
  gui.add(statusTextLabel);
  
  y = 20; 
  statusBaudRate = new IFLabel("", 250, y, 12);
  gui.add(statusBaudRate);

  y += 32;
  statusSerialNumberHigh = new IFLabel("", 250, y, 12);
  gui.add(statusSerialNumberHigh);  
  y += 16;
  statusSerialNumberLow = new IFLabel("", 250, y, 12);
  gui.add(statusSerialNumberLow);  

  y += 32;
  statusFirmwareVersion = new IFLabel("", 250, y, 12);
  gui.add(statusFirmwareVersion);
  
}

void draw() {
  background(200);
}

void actionPerformed(GUIEvent e) {
  if (e.getSource() == configureButton) {
    configureXBeeModem();
  } 
  else if (e.getSource() == readButton) {
    readSettingsFromXBeeModem();
  }
  else if (e.getSource() == exitButton) {
    exit();
  }
  else if (e.getSource() == modeButton[0]) {
    myTextField.setValue("0000");
  }
  else if (e.getSource() == modeButton[1]) {
    if (Integer.parseInt(myTextField.getValue(), 16) == 0) {
      myTextField.setValue("0001");
    }
  }
}

void configureXBeeModem() {
  if (portRadioButtons.getSelectedIndex() < 0) {
    statusTextLabel.setLabel("Please select a proper serial port.");
    return;
  }

  if (modeRadioButtons.getSelectedIndex() < 0) {
    statusTextLabel.setLabel("Please select a proper mode.");
    return;
  }

  int id = Integer.parseInt(idTextField.getValue(), 16);
  int my = Integer.parseInt(myTextField.getValue(), 16);

  if (id < 0 || id > 0xFFFE) {
    statusTextLabel.setLabel("ID should be between 0 to FFFE.");
    return;
  }

  if (my < 0 || my > 0xFFFE) {
    statusTextLabel.setLabel("MY should be between 0 to FFFE.");
    return;
  }

  statusTextLabel.setLabel("Entering command mode...");

  String portName = portRadioButtons.getSelected().getLabel();
  if (!enterCommandMode(portName)) {
    statusTextLabel.setLabel("Can't enter command mode.");
    return;
  }
  statusTextLabel.setLabel("Entered command mode.");

  int mode = modeRadioButtons.getSelectedIndex();

  switch (mode) {
  case COORDINATOR:
    serialPort.write("ATRE,BD4,");
    serialPort.write("ID" + Integer.toString(id, 16) + ",");
    serialPort.write("MY" + Integer.toString(my, 16) + ",");
    print("writing my as ");
    println(Integer.toString(my, 16));
    serialPort.write("DLFFFF,D33,IC8,WR\r");  
    if (!gotOkayFromXBeeModem()) {
      statusTextLabel.setLabel("Can't configure.");
      return;
    }
    break;
  case END_DEVICES:
    serialPort.write("ATRE,BD4,");
    serialPort.write("ID" + Integer.toString(id, 16) + ",");
    serialPort.write("MY" + Integer.toString(my, 16) + ",");
    serialPort.write("DL0,D35,IU0,IAFFFF,WR\r");
    if (!gotOkayFromXBeeModem()) {
      statusTextLabel.setLabel("Can't configure.");
      return;
    }
    break;
  }

  if (!exitCommandMode()) {
    statusTextLabel.setLabel("Can't exit command mode.");
    return;
  }

  statusTextLabel.setLabel("Configured successfully.");
}

void readSettingsFromXBeeModem() {
  if (portRadioButtons.getSelectedIndex() < 0) {
    statusTextLabel.setLabel("Please select a proper serial port.");
    return;
  }

  String portName = portRadioButtons.getSelected().getLabel();
  if (!enterCommandMode(portName)) {
    statusTextLabel.setLabel("Can't enter command mode.");
    return;
  }
  statusTextLabel.setLabel("Entered command mode.");

  String resultString = "";
  for (int i = 0; i < AT_READ.length; i++) {
    String reply = getReplyFromXBeeModemFor(AT_READ[i]);
    showSetting(i, reply); 
  }

  if (!exitCommandMode()) {
    statusTextLabel.setLabel("Can't exit command mode.");
    return;
  }

  statusTextLabel.setLabel(resultString);
}

void showSetting(int command, String  reply){
  
  switch(command){
  case 0: // baud
    statusBaudRate.setLabel("Baud rate: " + BAUD_RATES[Integer.parseInt(reply)]);     
    break;      
  case 1: // ID
   idTextField.setValue(reply);       
    break;      
  case 2: // MY ID
   myTextField.setValue(reply);     
    break;
  case 3: // DL  
    break;
  case 4: // SH
    statusSerialNumberHigh.setLabel("S/N  High: " + reply );      
    break;
  case 5: // SL
    statusSerialNumberLow.setLabel("S/N  low: " + reply );        
    break;
  case 6: // VR   
    statusFirmwareVersion.setLabel("Firmware: " + reply) ;
  }      
}

boolean gotOkayFromXBeeModem() {
  delay(500);

  for (int i = 0; i < 30; i++) {
    if (serialPort.available() >= 3) {
      break;
    }
    delay(200);
  }

  String reply = serialPort.readStringUntil(13);
  if (reply == null || !reply.equals("OK\r")) {
    return false;
  }

  return true;
}

String getReplyFromXBeeModemFor(String atCommand) {
  serialPort.write("AT" + atCommand + "\r");
  delay(50);
  String reply = serialPort.readStringUntil(13);
  return reply.substring(0, reply.length() - 1);
}

boolean enterCommandMode(String portName) {
  if (serialPort != null) {
    serialPort.stop();
    serialPort = null;
  }

  serialPort = new Serial(this, portName, 9600);
  serialPort.clear();
  serialPort.write("+++");

  if (!gotOkayFromXBeeModem()) {
    serialPort.stop();
    serialPort = null;
    serialPort = new Serial(this, portName, 19200);
    serialPort.clear();
    serialPort.write("+++");
    if (!gotOkayFromXBeeModem()) {
      return false;
    }
  }

  return true;
}

boolean exitCommandMode() {
  serialPort.write("ATCN\r");
  return gotOkayFromXBeeModem();
}

Hi mem,

I have made some additions to the code to display more status information that you may find useful.

Thank you very much. I just included your suggestion, and modified to ignore tty devices on OS X.

http://funnel.googlecode.com/files/XBeeConfigTool_r545.zip
http://funnel.googlecode.com/files/XBeeConfigTool_r545.dmg

Best,
Shigeru

greetings,

Ive got a pair of xbee 2.5s with the sparkfun explorer and the sparkfun FIO board. I've made the jumper changes as described on the FIO hardware page and in using XBeeConfigTool_r545 i get FFFE for the ID when reading both xbees after configuring them.

The pan ID is able to stay what I set but the MY ID always says FFFE when reading either xbee. I'm presuming this is why I can't send my sketch to the FIO board. I get "avrdude: stk500_recv(): programmer is not responding" when trying to send the sketch. any ideas where to resolve this issue?

thanks. love the FIO board btw. I have a few hundred ideas I'd like to try :slight_smile:

using OSX 10.4.11

Ahh, I finally figured out that the 2.5 version of the xbee's have a different set of instructions and the MYID isn't changeable. It requires things I apparently can only from windows as well.

On the Phys-Comp group I asked if the XBees could be configured in Linux.
Rob Faludi responded that he heard it was possible and sent this link ---

I have not tried it yet.

(* jcl *)

What's the Phys-Comp group?

thx

What's the Phys-Comp group?

Mailing list at NYU

(* jcl *)

Dear all,

Just for your reference, I just uploaded a new version with stupid firmware version checker function.

http://funnel.googlecode.com/files/XBeeConfigTool_r574.zip

Will be included into Funnel 009 release version.

Best,
Shigeru