Programming XBee to transmit and receive data

Ok. I added my notes as comments to the source code. Here are the two listings:

Transmitter

#include <SoftwareSerial.h>
//#include <i2cmaster.h> // commented out temporarily because I don't have the sensor

SoftwareSerial XBeeTX(2, 3); // RX, TX

const byte dev = 0x5A<<1;  // This is a constant, so use the const keyword
const char data_start = '*';  // This is a constant, so use the const keyword

void setup()
{
  Serial.begin(9600);
  XBeeTX.begin(9600);
//  i2c_init(); //Initialise the i2c bus
//  PORTC = (1 << PORTC4) | (1 << PORTC5);//enable pullups
}

void loop()
{
  byte data_low;
  byte data_high;
  byte pec = 0;

//  i2c_start_wait(dev+I2C_WRITE);
//  i2c_write(0x07);

  // read
//  i2c_rep_start(dev+I2C_READ);
//  data_low = i2c_readAck(); //Read 1 byte and then send ack
//  data_high = i2c_readAck(); //Read 1 byte and then send ack
//  pec = i2c_readNak();
//  i2c_stop();
data_high = 0x3A; // I don't have an I2C temp sensor, so this is just dummy data
data_low = 0x26;

  XBeeTX.write(data_start); // method can be either write(var) or print(var) because data_start is of type char
  Serial.write(data_start); // should be exactly the same format as the preceeding XBeeTX output to exactly mirror what is being transmitted

  delay(1000); // Just to help illustrate cadence, remove once one understands

  XBeeTX.print(data_high, HEX); // method should only be print(var, HEX)
  Serial.print(data_high, HEX); // should be exactly the same format as the preceeding XBeeTX output to exactly mirror what is being transmitted

  delay(1000); // Just to help illustrate cadence, remove once one understands

  XBeeTX.print(data_low, HEX); // method can be either print(var, HEX) or println(var, HEX)
  Serial.print(data_low, HEX); // should be exactly the same format as the preceeding XBeeTX output to exactly mirror what is being transmitted

  delay(1000); // Just to help illustrate cadence, remove once one understands

  XBeeTX.println(); // Just to help illustrate cadence, remove once one understands
  Serial.println(); // should be exactly the same format as the preceeding XBeeTX output to exactly mirror what is being transmitted

  delay(1000); // This sets the actual cadence between transmitting temperatures. Adjust as needed.
}

Receiver

#include <SoftwareSerial.h>
//#include <ctype.h> // compiles w/o this include in ERW 1.0.5

SoftwareSerial XBeeRX(2, 3); // RX, TX

const char data_start = '*'; // This is a constant, so use the const keyword
boolean newReading = false; // Because we use this before explicitly setting it, just to make sure the default is false we set it here.
byte readPosition;
byte data_low;
byte data_high; 
char data_in;

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

void loop()
{
  if (XBeeRX.available())
  {
    data_in = XBeeRX.read();
    Serial.println(data_in, HEX); // Show the recieved HEX value immediately as recieved for diagnostics.
    switch(readPosition)
    {
    case 0: // Waiting for the start of data token to be received. Ignore any serial data until data_start is received.
      {
        if (data_in == data_start)
          readPosition++;
          break;
      }

    case 1: // data_start processed. Current character should be ASCII representation of the high nybble of data_high.
      {
        data_high = HexCharToValue(data_in)<<4;
        readPosition++;
        break;
      }

    case 2: // high nybble of data_high processed. Current character should be ASCII representation of the low nybble of data_high.
      {
        data_high = HexCharToValue(data_in)+data_high;
        readPosition++;
        break;
      }

    case 3: // low nybble of data_high processed. Current character should be ASCII representation of the high nybble of data_low.
      {
        data_low = HexCharToValue(data_in)<<4;
        readPosition++;
        break;
      }

    case 4: // high nybble of data_low processed. Current character should be ASCII representation of the low nybble of data_low.
      {
        data_low = HexCharToValue(data_in)+data_low;
        readPosition = 0; // Finished receiving expected data structure. Return readPosition to zero to wait for the next data_start token
        newReading = true;
      }
    }
  }

  if (newReading) // newReading is a boolean type, so this is the same as if (newReading == true)
  {
    Serial.println();
    Serial.write(data_start); // Exactly mirror the methods used to originally transmit this data as a diagnostic check to make sure we recombined the data correctly.
    Serial.print(data_high, HEX);
    Serial.println(data_low, HEX);  

    // This whole section of declarations should properly be at the top of either loop() as local variables, or at the top of the sketch as globals. If globals, tempFactor should be const
    double tempFactor = 0.02; // double and float are the same datatype. Only use one of the two to avoid confusion unless there is a really good reason not to.
    unsigned int tempData = 0x0000; // floating point math is executionally expensive on AVR processors. All we really need here is a 16-bit holding bin, polarity is not important.
    float kelvin; // after applying the tempFactor, this is what one really has, so why not indicate it with a descriptive variable name?
    float celcius;
    int frac; // what is this variable used for? Future use? Or can it be removed?

    tempData = ((data_high & 0x007F) << 8) + data_low; // come to think of it, the name data_word might be better for self-documenting code instead of tempData
    kelvin = (tempData * tempFactor)-0.01; // what is the -0.01 for? I don't remember seeing anything about this in the temperature sensor datasheet. But I may have missed it.

    celcius = kelvin - 273.15; // Wow... In how many text and reference books have I seen this formula? ;-)

    Serial.print("Celcius: ");
    Serial.println(celcius);
    Serial.println();
    newReading = false;
  }
}

byte HexCharToValue (char x)
{
  byte value;
  int upper;
  byte first_result;

  if(isxdigit(x))
  {
    upper = toupper(x);
    first_result = upper - 0x30;
    if (first_result < 0x0A)
    {
      value = first_result;
    }
    else
    {
      value = first_result - 0x10;
      value = value + 9; // My error. 'A' is 0x41. Subtracting 0x30 and then 0x10 will leave 0x01. To get that to be decimal 10, add decimal 9. (Head-palm at myself)
    }
  }
  else
  {
    value = 0;
  }

  return value;
}

Attached are screenshots of my Transmitter and Receiver windows. The Receiver window shows a potential problem just waiting to crop up. I'll explain and provide a fix in the next post.