// Written in C    justin downs  johnhenryshammer.com
// Code that will parse a XBEE API Series2 receive packet
// started from Rob Faludis/Dan Shiftman API series 1 library
 
// It is broken into functions for Debugging and for easier use with a time out
// for program flow. It is not needed for raw parsing and
//runs faster without funcs. Just decomment.
 
//** There is also code for transmitting serial as ASCII you don't have to use those
//funcs for the XBEE, just disregard and don't use the ArrayLookChars(byte* _array) func.
 
 
//function decs
int checkHeader(int timeout);
char getIdentifier(int _timeOut);
byte* getLongAdress(int _timeOut, byte* _address);
int getLocaladdress(int _timeOut);
byte getOptions(int _timeOut);
byte* getInfo(int _packetLength, int _timeOut);
char getCheckSum(int _timeOut);
 
//software serial stuff this is for debuging only take out if not used
#include <SoftwareSerial.h>
#define rxPin 2
#define txPin 3
#define ledPin 13
// end softserial 
 
// set up a new serial port
SoftwareSerial DeBug =  SoftwareSerial(rxPin, txPin);
byte pinState = 0;
 
 
void setup() {
  // define pin modes for tx, rx, led pins:
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  // set the data rate for the SoftwareSerial port
  DeBug.begin(9600);
   
  Serial.begin(9600);
 
 
}
 
 
void loop() {
//DeBug.println("hello");
 getData();
 
}
 
 
   
 
/* Function that receives API2 data which was sent using 16-bit addressing
   broken into functions for microcontroler timeout blocks. not needed on pc 
   runs slower.
 
*/
 
void getData() {
  int timeout=100;// bail out time
  int packetLength = 0;
  packetLength = checkHeader(timeout); // START BYTE AND PACKET LENGTH
  if (packetLength > 0 ) { // if we have a packet continue
    int apiIdentifier = getIdentifier(timeout); // GET ID
    byte Adress[8];// array for 64 bit address
    byte* adress = getLongAdress(timeout,Adress);//GET LONG ADRESS don't really need pointer
     /*char addrByte=0;
     while( port.available() < 8); // stop for bits
     char adress[]= new char[8];// array for address
     for (int i = 0; i<8; i++){
     addrByte =char( port.read());
     adress[i]=addrByte;
     // print(hex(addrByte));
     }
     */
 
    int localAdress = getLocaladdress(timeout);// GET LOCAL ADDRESS
    /*  while (port.available() < 2); // wait for at least two bytes to be available
     int localAd = port.read(); // read the most significant length byte
     int localAd2 = port.read(); // read the least significant length byte
     int localAdress = (localAd << 8) + localAd2; // put the two bytes together
     */
 
    byte options = getOptions(timeout);//GET OPTION 
    /* while (port.available() < 1);
     char options = char(port.read()); // get the options 1 packet ack returned 2 brodcast
     */
    
    byte* dataIn = getInfo(packetLength,timeout);//GET INFO
    
    /*
     //info packet
     char[] dataIn = new char[30];
     while (port.available() < (packetLength - 12));
     // println("packetLength22  "+packetLength);
     for (int i= 0; i < (packetLength - 12); i++) { // take out other info in packet + checksu
     println("packetLength  "+ packetLength);
      dataIn[i] = char(port.read()); // get a byte of data
     // println(hex(dataIn[i]));
     }
   */
    char checksum = getCheckSum(timeout); //GET CHECKSUM
    /*
    while (port.available() < 1);
     char checksum = char(port.read());
     */
 
 
   /* //printall 
     DeBug.println("packetLength  "+packetLength);
     DeBug.println("sent long address");
    for (int i = 0; i<8; i++){
       DeBug.print(adress[i]);
    }
     DeBug.println();
     DeBug.println ("local adress  "+localAdress);
     DeBug.println("options  "+options);    
     DeBug.println("info");
    for (int i= 0; i < (packetLength - 12); i++) { // take out other info in packet + checksum
       DeBug.println(dataIn[i]);
    }
      DeBug.println("checksum  "+checksum);
    */
  
     //  for (int i= 0; i < (packetLength - 12); i++) { // take out other info in packet + checksum
     // DeBug.println(dataIn[i]);
   // }
   // DeBug.println("data");
   
   // For ASCCII  //**optional***
    DeBug.println(ArrayLookChars(dataIn));
    free(dataIn); // free block after use
  }
 
 
}
 
int checkHeader(int timeout) { // timeout is in milliseconds
  long startTime = millis();
  int Length = 0;
  int inByte = 0;
  
  // during the timeout period, if we haven't gotten the start byte yet...
  while (((millis() - startTime) < timeout) && (inByte != 0x7E)) {
    if (Serial.available() > 0) { // if a byte is waiting in the buffer
      inByte = Serial.read(); // read a byte from the buffer 
    }
  }
 
  // look at byte
  if (inByte == 0x7E) { // if we got the API start byte
    while (Serial.available() < 2); // wait for at least two bytes to be available
    int lengthMSB = Serial.read(); // read the most significant length byte
    int lengthLSB = Serial.read(); // read the least significant length byte
    Length = (lengthMSB << 8) + lengthLSB; // put the two bytes together
  }
 
  return Length;
}
 
 
    
    
 char getCheckSum(int _timeOut){
    char checksum ='Z';
    long startTime = millis();
    while (Serial.available() < 1 && ((millis() - startTime) <  _timeOut)); // wait for at least two bytes to be available
    if (Serial.available() > 0) { // if a byte is waiting in the buffer
    checksum = char(Serial.read());
    return checksum; // returns null if timed out
   }
  /// println("checksum");
    return '0'; // returns null if timed out
 }
 
 
 
 
 
 
byte* getLongAdress(int _timeOut, byte* _address){
  
  long startTime = millis();
   char addrByte = 'Z';
  while( Serial.available() < 8 && ((millis() - startTime) < _timeOut)); // stop for bits 
    
  if (Serial.available() > 0) { // if a byte is waiting in the buffer
       for (int i = 0; i<8; i++){
       addrByte =byte( Serial.read());
       _address[i]=addrByte;
       }
      return _address; //returns null if timed out
  }
      //println("Adresslong");//ERROR happend
        return NULL;
}
 
 
 
 
 
int getLocaladdress(int _timeOut){
 int localAdress =0;
 long startTime = millis();
    while (Serial.available() < 2 && ((millis() - startTime) <  _timeOut)); // wait for at least two bytes to be available
    if (Serial.available() > 0) { // if a byte is waiting in the buffer
    int localAd = Serial.read(); // read the most significant length byte
    int localAd2 = Serial.read(); // read the least significant length byte
    localAdress = (localAd << 8) + localAd2; // put the two bytes together
     return localAdress; // returns null if timed out
  }
   ///println("location");
    return '0'; // returns null if timed out
 }
 
 
 
 
 
// function that checks to see for the API Identifier 
char getIdentifier(int _timeOut) {
  long startTime = millis();
 char apiIdentifier = 'Z'; // set apiIdentifier to an impossible value
  while (Serial.available() < 1 && (millis() - startTime) <  _timeOut) ; // wait for a byte or timeout
  if (Serial.available() > 0) { // if a byte is waiting in the buffer
    apiIdentifier = char(Serial.read());
    return apiIdentifier; // returns null if timed out
  }
    /// println("Identifier");
    return 'N'; // returns null if timed out
 
}
 
 
 
// this is your info packet
byte* getInfo(int _packetLength, int _timeOut){
  
  long startTime = millis();
  byte addrByte = 0x00;
  while (Serial.available() < (_packetLength - 12) && millis() - startTime < _timeOut); // stop for bits 
      byte* dataIn = (byte*) malloc(_packetLength - 12);// get memory, be sure to call free in sendData or it blows real quick 
      if (dataIn==NULL){ DeBug.println( "brainDamaged"); return NULL;} // bail out
  if (Serial.available() > 0) { // if a byte is waiting in the buffer
     
      for (int i= 0; i < (_packetLength - 12); i++) { // take out other info in packet + checksu
        dataIn[i] = byte(Serial.read()); // get a byte of data
        // DeBug.println( dataIn[i]);    
       }
    return dataIn; //returns null if timed out
  }
       /// println("info packet");
 return NULL;
}
 
 
 byte getOptions(int _timeOut){
 byte options =0x00;
 long startTime = millis();
    while (Serial.available() < 1 && ((millis() - startTime) <  _timeOut)); // wait for at least two bytes to be available
    if (Serial.available() > 0) { // if a byte is waiting in the buffer
     options = byte(Serial.read()); // get the options 1 packet ack returned 2 brodcast
     return options; // returns null if timed out
  }
  ////println("Options");
    return '0'; // returns null if timed out
 }
 



///////DEPackagedata  ***optional****
 
long ArrayLookChars(byte* _array) {
char ASCIIString [100]; // in string
char inByte ='z';
long number = 0; // return number
int stringPos = 0; // keeps track of places in number
 
if ('a' == _array[1] ){ // for id parsing of serial 
int i = 2; // change back to 1 if not using tag
while(_array[i] !='b'){ 
inByte =_array[i]; 
i++;
// save ASCII numeric characters in string:
if ((inByte >= '0') && (inByte <= '9')){
ASCIIString [stringPos] = inByte;
stringPos++;
//DeBug.println( "true");
}
}
}
 
number = SerialToInt( ASCIIString,stringPos ); /// convert captured string to an int
//free(_array); //for Debug
stringPos = 0; //reset count num 
//if (number !=0)Serial.println(number);//DEBUG
return number;
}
 
/*****************
the important parts of the function conversions 
are to have a inverting for loop go 
from last in array to first and call the plusBaseTen()function
each time.
*******************/
 
// hits up the number by base ten powered
long timesBaseTen(int _move){ // the
long place = 1; //base 10
int n = 0;
if( _move < 1){ return 1;}//ones place no change
else{
for( n= 0; n<_move; n++){ place = place*10;}
}return place;
} 
 
// converts a ten digit ASCII to int
long SerialToInt(char *_input, int _arrayLength){
long number=0;
long total=0;
int arrayLook=0;
int i = 0;
char s[]={"h"};	// work around 
int arrayLength =_arrayLength-1; // need one less than actual length 0 is 1
// call invert string for proper string power order
for(i =arrayLength; i >= 0;i--){ 
// Serial.println(i);
// Serial.println(_input[i]); 
// picks out ASCII numbers for error check
if ((_input[i] >= '0') && (_input[i]<= '9')){ 
s[0] = _input[i];// work around to get string arg
number = atoi(s);// ASCII to converts number
number = (number * (timesBaseTen(arrayLook))); // puts number in its place
arrayLook++;
total = number+total;
}
}
return total; 
}