/**************************************************************************************************
*
*  StringSerialProtocol
*
*   Version:      1.1.4 - April 2009
*   Author:       Christoph Wartmann / chair for caad - ETH Zürich  /  wartmann[at]arch.ethz.ch
*                 Etienne Ribeiro    / tutorial assistant caad      /  eribeiro[at]ethz.ch
*
*   Desc:         A Protocoll to communicate through the Serial Interface. All data will be
*                 converted to Ascii-Code. This means an int number (2 bytes) now needs up to
*                 6 bytes and must be coded and decoded. On the other hand this protocol is very
*                 reliable even if you reset the board during communication.
*
*   Protocoll:    bits 0 to 8: command
*                 bits 8 to ...: message
*                 last bits: CR, LF or CR LF or LF CR
*
*   Methodes:     void Serial_Initialize (int boud)
*                   boud = Boud rate. use 9600
*                 void Serial_setID (char ID)
*                   If this function is called, the specified ID will be sent wenn calling Serial_sendMessage
*                   ID: a value from 0 to 254
*                 void Serial_sendMessage (char cmd, char* message)
*                   Send a string message through serial.
*                   cmd = a char to seperate different commands. Don't use char with ascii 10 and 13
*                   message = string message to send
*                 void Serial_sendMessage (char cmd, int message)
*                   Send an int number through serial.
*                   cmd = a char to seperate different commands. Don't use char with ascii 10 and 13
*                   message = int number to send (-32768 to 32767)
*                 void Serial_sendMessage (char cmd, long message)
*                   Send an long number through serial.
*                   cmd = a char to seperate different commands. Don't use char with ascii 10 and 13
*                   message = long number to send (-2147483648 to 2147483647)
*                 void Serial_check ()
*                   Check if something is coming in. Must be called in LOOP.
*                 int Serial_parseInteger (char* val)
*                   Parse string value to int. (-32768 to 32767)
*                 long Serial_parseLong (char* val)
*                   Parse string value to long. (-2147483648 to 2147483647)
*
*   Not implemented:
*      - Sending float and double values
*      - unsigned values
*
***************************************************************************************************/


// const

const int serial_MAX_COMMAND_LENGTH = 50;
const int serial_LF = 10;
const int serial_CR = 13;


// var

char serial_buffer[serial_MAX_COMMAND_LENGTH];
int serial_cBuffer = 0;
int serial_current_bytescount = 0; // length of current Command
char serial_current_command;
//
boolean serial_useID = false;
int serial_ID = 0;



// ------------------
// Functions



// Initialize
void Serial_Initialize (int boud) {

        // Serial
        Serial.begin(boud);

}



// Set Id
//   ID: a value from 0 to 254
void Serial_setID (char ID) {

        serial_useID = true;
        serial_ID = ID;

}


// Send Message

void Serial_sendMessage (char cmd, char* message) { if (serial_useID == true) Serial.print(serial_ID, BYTE); Serial.print(cmd); Serial.println ( message); } // Strings
void Serial_sendMessage (char cmd, char* msg1, char* msg2) { if (serial_useID == true) Serial.print(serial_ID, BYTE); Serial.print(cmd); Serial.print(msg1); Serial.println (msg2); } // Strings
void Serial_sendMessage (char cmd, char* msg1, int msg2) { if (serial_useID == true) Serial.print(serial_ID, BYTE); Serial.print(cmd); Serial.print(msg1); Serial.println (msg2, DEC); } // Strings
void Serial_sendMessage (char cmd, long message) { if (serial_useID == true) Serial.print(serial_ID, BYTE); Serial.print(cmd); Serial.println ( message); }
void Serial_sendMessage (char cmd, long val1, char* seperator1, long val2, char* seperator2, long val3, char* seperator3, long val4) { if (serial_useID == true) Serial.print(serial_ID, BYTE); Serial.print(cmd); Serial.print (val1, DEC); Serial.print(seperator1); Serial.print (val2, DEC); Serial.print(seperator2); Serial.print (val3, DEC); Serial.print(seperator3); Serial.println (val4, DEC); }



// Check if something is coming in. Must be called in loop.

void Serial_check () {

        while (Serial.available() > 0) {

                // Fill buffer
                byte val = Serial.read();
                if (serial_cBuffer < serial_MAX_COMMAND_LENGTH - 1)
                serial_buffer [serial_cBuffer] = val; // store all bytes (excepting first = type)


                // Message complete
                if (val == serial_LF || val == serial_CR) {

                        if (serial_cBuffer > 0) {// if cBuffer == 0, no data sent (if you send LF CR or ...)


                                if (
                                serial_useID == false // no ids are used
                                || (serial_useID == true && serial_buffer [0] == serial_ID) // message for this node
                                || (serial_useID == true && serial_buffer [0] == 0) // message for all nodes
                                || (serial_ID == 0) // this node receives all messages
                                ){

                                        // First Byte
                                        int firstByte = 1;
                                        if (serial_useID == true)
                                        firstByte = 2;


                                        // Fire Event
                                        int buffSize = serial_cBuffer;
                                        if (serial_cBuffer-firstByte > 0)
                                        buffSize = serial_cBuffer-firstByte;
                                        char tmp [buffSize + 1];
                                        tmp [buffSize] = 0;
                                        for (int i=firstByte;i<serial_cBuffer;i++)
                                        tmp [i-firstByte] = serial_buffer[i];
                                        serial_cBuffer = 0;
                                        SerialEvent (serial_buffer[firstByte-1], tmp);

                                }

                        }

                        serial_cBuffer = 0;
                        return;

                }


                // ++
                if (serial_cBuffer < serial_MAX_COMMAND_LENGTH - 1)
                serial_cBuffer += 1;

        }

}




// Get length of a char array

int Serial_getLength (char *word) {

        int count = 0;
        char *p = word;
        while (*p != '\0') {
                p++;
                count++;
        }
        return count;

}










long Serial_parseLong (char* val) {

        long ival = 0;
        int sign = 1;
        int len = Serial_getLength(val);


        for (int i=0;i<len;i++) {

                if (val[i] == '-')
                sign = -1;
                if (val[i] >= 48 && val[i] <= 57)
                ival += sign * (val[i]-48) * Serial_pow(len-i-1);

        }


        // return
        return ival;

}


// Serial_pow (there is an issu with pow (10, 2) when looping in wiring 0018, so lets do it from hand)

long Serial_pow (int x) {

        long val = 1;
        for (int i=0;i<x;i++)
        val *= 10;
        return val;

}