//#define Checkoff_1
#define TestReceiveE128
//#define BoatDrive

// PS2=RECIEVE PS3=TRANSMIT

/***************************************************/

// Import Library
#include <hidef.h>      /* common defines and macros */
#include <mc9s12e128.h> /* derivative information */
#include "ME218_E128.h"	/* bit definitions */
#include "S12eVec.h"		/* interrupts */
#include <timers12.h>
#include <stdio.h>
#include "Communication.h"
#include "SCIMessage_H.h"
#include "E128_IO.h"
#include <math.h>

/*****************Module Defines**********************/

// Define Numerical Constants
#define   TRUE                1
#define   FALSE               0
#define   BOOST               10

// Timers
#define   SEND_TIME           0
#define   SEND_TIME_PERIOD    200    // Send messages every 5Hz
#define   REC_TIMEOUT         1
#define   REC_TIMEOUT_PERIOD  500    // Set time out for receiving messages to 0.5sec

/******************Module Types*********************/

/*******************MODULE VARIABLES********************/
static unsigned char NewMessageFlag;
static unsigned char checkSumError;
static unsigned char byteCounter;
static TMRS12Return_t TimeOutFlag;
static unsigned char messageArray[15];
static unsigned char Packet[17];
static unsigned char DataLength = 2;
static unsigned char k = 0;
//static Button_t Button;
static unsigned char readLength;
static unsigned char messageReceived = 0;
static signed char DriveSpeed = 0;
static unsigned char DriveHandle = 90;
static unsigned char Direction = 1;
static unsigned char DriveForward = 0;
static unsigned char DriveBackward = 0;
static unsigned char DriveRight = 0;
static unsigned char DriveLeft = 0;
/****************PRIVATE FUNCTION PROTOTYPES***************/

void InitSCI(void);
void InitIC(void);
void CheckSendTimer(void);
void CreatePacket(unsigned char Data_Length, unsigned char MessageAddressMSB, unsigned char MessageAddressLSB, unsigned char Options, unsigned char CommandType, unsigned char DataToSend[]);
void TransmitSM(void);
void ReceiveMessageSM(void);

/*******************INTERRUPT RESPONSES***********************/
/*************************FUNCTIONS***************************/


void InitSCI(void){
  // Set up SCI communication
  // Set Baud Rate 9600Hz = 24MHz / (16*156)
  SCI1BDH = 0x00; // 0
  SCI1BDL = 0x9C; // 156

  // Select Word Length and Wake Up
  SCI1CR1 = 0b00000000;
  // No Interrupts, Transmit/Receive Enabled
  SCI1CR2 = 0b00001100;
}

// This function check to see if new data can be sent at 5Hz
void CheckSendTimer(void){

  if (TMRS12_IsTimerExpired(SEND_TIME) == TMRS12_EXPIRED){

        (void) TMRS12_ClearTimerExpired(SEND_TIME);    //Clear timer flag
        (void) TMRS12_InitTimer(SEND_TIME,SEND_TIME_PERIOD);  //Reset 5Hz timer
        NewMessageFlag = TRUE;
    }
}


// This function puts together a packet to send
// Input Bytes: To Address MSB/LSB, Length, Options, Command Type, and Data Array
void CreatePacket(unsigned char Data_Length, unsigned char MessageAddressMSB, unsigned char MessageAddressLSB, unsigned char Options, unsigned char CommandType, unsigned char DataToSend[]){

    unsigned char i,Checksum;


    Packet[0] = START_MESSAGE;
    Packet[1] = 0x00;                    // Length High Byte
    Packet[2] = Data_Length + 6;          // FRAME LENGTH (Length Low Byte)
    Packet[3] = API_TRANSMIT;
    Packet[4] = 0x01;                    // Frame ID
    Packet[5] = MessageAddressMSB;
    Packet[6] = MessageAddressLSB;
    Packet[7] = Options;
    Packet[8] = CommandType;

    Checksum = API_TRANSMIT + 0x01 + MessageAddressMSB + MessageAddressLSB + Options + CommandType;

    DataLength = Data_Length;
    (void) printf("DatatoSend[0]: %d \r\n", DataToSend[0]);
    for(i=0;i<DataLength;i++){

        Packet[i+9] = DataToSend[i];
        Checksum += DataToSend[i];
    }
    Packet[DataLength+9] = 0xFF - Checksum;
    NewMessageFlag = TRUE;
}

// This function will send a message when one is ready
void TransmitSM(void){

    static TransmitState_t CurrentState = WAITING_FOR_PACKET;
    static unsigned char Counter = 0;

    switch(CurrentState){

        case WAITING_FOR_PACKET:

            if(NewMessageFlag == TRUE){

                NewMessageFlag = FALSE;   //Clear flag
                Counter = 0;
                CurrentState = WAITING_FOR_TRANSMIT;
            }

        break;

        case WAITING_FOR_TRANSMIT:

            if (Counter < (DataLength+10)){
                if ((SCI1SR1 & _S12_TDRE) == _S12_TDRE){

          	        // Send next byte
          	        SCI1DRL = Packet[Counter];
          	        Counter++;
                }
            }
            else
                CurrentState = WAITING_FOR_PACKET;

        break;
    }
}


void ReceiveMessageSM(void) {
	static ReceiveMessageState currentState = WAITING_FOR_START_BYTE;
	static unsigned char checkSum;
	static unsigned char messageLength;

	ReceiveMessageState nextState;
	nextState = currentState;

	switch(currentState) {

		case WAITING_FOR_START_BYTE:
			// If Byte Read is 7E
			if ((SCI1DRL == 0x7E) && (SCI1SR1 != FALSE)){
				// Message Received, Wait for the MSB
				nextState = WAITING_FOR_MSB;
				//(void) printf("REC: 0x %X\r\n",SCI1DRL);
				// Start Timeout Timer
                (void) TMRS12_InitTimer(REC_TIMEOUT,REC_TIMEOUT_PERIOD);    // Start a timer to expire if the next byte is not recieved in 0.5sec
			}
			// Otherwise do nothing, and keep waiting for start byte
		break;

		case WAITING_FOR_MSB:
			TimeOutFlag = TMRS12_IsTimerExpired(REC_TIMEOUT);
			if (TimeOutFlag == TMRS12_EXPIRED){
				// Timeout Timer has Timed Out
				(void) TMRS12_ClearTimerExpired(REC_TIMEOUT);    //Clear timer flag
				nextState = WAITING_FOR_START_BYTE;
			}
			else if(SCI1SR1_RDRF != FALSE){ // If we received a byte
				if(SCI1DRL == 0x00){ // We received a 0
    				// Start Timeout Timer
                    (void) TMRS12_InitTimer(REC_TIMEOUT,REC_TIMEOUT_PERIOD);    // Start a timer to expire if the next byte is not recieved in 0.5sec
    				// Wait for the LSB
    				nextState = WAITING_FOR_LSB;
				    //(void) printf("REC: 0x %X\r\n",SCI1DRL);
				} else{
				    nextState = WAITING_FOR_START_BYTE;
				}
			}
		break;

		case WAITING_FOR_LSB:
			TimeOutFlag =  TMRS12_IsTimerExpired(REC_TIMEOUT);
			if (TimeOutFlag == TMRS12_EXPIRED){
				// Timeout Timer has Timed Out
		        (void) TMRS12_ClearTimerExpired(REC_TIMEOUT);    //Clear timer flag
				nextState = WAITING_FOR_START_BYTE;
			}
			else if (SCI1SR1_RDRF != FALSE){ // If we received a byte
				nextState = WAITING_FOR_DATA;
				// Restart Timeout Timer
                (void) TMRS12_InitTimer(REC_TIMEOUT,REC_TIMEOUT_PERIOD);    // Start a timer to expire if the next byte is not recieved in 0.5sec
				// Initialize the CheckSum and Save the Size of Message
				checkSum = 0;
				messageLength = SCI1DRL;
				readLength = messageLength; // For debug
				//(void) printf("REC: 0x %X\r\n",SCI1DRL);
				byteCounter = 0;
			}
		break;

		case WAITING_FOR_DATA:
			TimeOutFlag =  TMRS12_IsTimerExpired(REC_TIMEOUT);
			if (TimeOutFlag == TMRS12_EXPIRED){
				// Timeout Timer has Timed Out
				(void) TMRS12_ClearTimerExpired(REC_TIMEOUT);    //Clear timer flag
				nextState = WAITING_FOR_START_BYTE;
			}
			else if(SCI1SR1_RDRF != FALSE){
				// Restart Timeout Timer
                (void) TMRS12_InitTimer(REC_TIMEOUT,REC_TIMEOUT_PERIOD);    // Start a timer to expire if the next byte is not recieved in 0.5sec
				if (messageLength == 0)
					nextState = WAITING_FOR_CHECKSUM;
				else{
					nextState = WAITING_FOR_DATA;
					messageLength--;
					checkSum += SCI1DRL;
					messageArray[byteCounter] = SCI1DRL;
				    //(void) printf("REC: 0x %X\r\n",SCI1DRL);
				    //(void) printf("Message Length %d\r\n",messageLength);
					byteCounter++;
				}
			}
		break;

		case WAITING_FOR_CHECKSUM:
			TimeOutFlag = TMRS12_IsTimerExpired(REC_TIMEOUT);
			if (TimeOutFlag  == TMRS12_EXPIRED){
				// Timeout Timer has Timed Out
				(void) TMRS12_ClearTimerExpired(REC_TIMEOUT);    //Clear timer flag
				nextState = WAITING_FOR_START_BYTE;
			}
			else if (SCI1SR1_RDRF != FALSE)
				nextState = WAITING_FOR_START_BYTE;
				if (SCI1DRL == (0xFF - checkSum)){
				    // Good CheckSum Received
					checkSumError = 0;
				(void) printf("New Message\r\n");
				messageReceived = 1;
				}
				else
					// Bad CheckSum
					checkSumError = 1;
		break;

	}

	currentState = nextState;
}



#ifdef TestReceiveE128

void main (void){
    int j;
    unsigned char DataToSend[7];
    unsigned char SendingFlag = 0;
    char checksum = 0;
    char press;

    (void) printf("Test Receive Function");
    // Initialize:
    InitSCI();                        // Initialize Communications
    InitIC();                         // Initialize Input Capture for Boost Button
    InitPins();
    TMRS12_Init(TMRS12_RATE_1MS);     // Initialize 1ms timer
    AtollLEDOff();
    InitBoostServo();
    InitDebug();

    byteCounter = 0;
    TimeOutFlag = 0;

    DataToSend[0] = 0x01;
    DataToSend[1] = 0x02;
    DataToSend[2] = 0x03;
    //DataToSend[3] = 0x04;
    //DataToSend[4] = 0x04;
    //DataToSend[5] = 0x05;
    //DataToSend[6] = 0x06;




    /*
    CreatePacket(ACV_ADDRESS_MSB,ACV_ADDRESS_LSB,DIRECT_MESSAGE,COMMAND_ACV,DataToSend);
    // include start + length MSB/LSB + data frame+checksum
    for(i=0 ; i<DataLength+10 ; i++){
        (void) printf("TX: 0x %X\r\n",Packet[i]);
    }
    // NewMessageFlag = TRUE;

    // 7E, 00, 9, 01, 01, 20, 8E, 02, CD, 01, 02, 03, 7A
    */

    (void) TMRS12_InitTimer(7,200);

    while(1){
    	(void) TransmitSM();
    	(void) ReceiveMessageSM();
    	CheckSensorTimeout();
    	CheckBoostRecharge();
    	UpdateDebug();


    	// If message received
    	if (messageReceived == 1){
    	  messageReceived = 0;
    	  // Check if it was a message from another XBEE
    	      if (messageArray[API] == API_RECEIVE){
      	  // Check if it was a broadcast message
      	        if (messageArray[RECEIVE_OPTION] == BROADCAST_MESSAGE){
      	        // Check if it was an atoll capture
      	            if(messageArray[COMMAND_TYPE] == BROADCAST_CAPTURE){
      	                // Light the Appripriate LEDs
      	                AtollLED(messageArray[ATOLL_NUMBER], messageArray[TEAM_COLOR]);
      	            }
      	        }
      	        else if(messageArray[ADDRESS_MSB] == ACV_ADDRESS_MSB && messageArray[ADDRESS_LSB] == ACV_ADDRESS_LSB){
      	            (void)printf("Directed Message to ACV /r/n");
      	            // Check if it was an atoll capture
      	            if(messageArray[COMMAND_TYPE] == COMMAND_B2C && messageArray[ATOLL_NUMBER] == 0){
      	                // Turn off all LEDs
      	                (void) printf("Boat To Controller Command /r/n");
      	                AtollLEDOff();
      	            }
      	        }
    	      }
    	}

      // if( TMRS12_IsTimerExpired(7) == TMRS12_EXPIRED && SendingFlag == 1 ) {
      if( TMRS12_IsTimerExpired(7) == TMRS12_EXPIRED) {
      	    (void) TMRS12_ClearTimerExpired(7);
      	    DataToSend[0] = ReadWheelSpeed();
      	    DataToSend[1] = ReadWheelDirection();
      	    if (ReadHandlebar() > 60)
      	      DataToSend[2] = ReadHandlebar();
      	    else
      	      DataToSend[2] = 60;

      	    (void) printf("Speed: %d Direction: %d Heading: %d  Old: %d AD: %d \r\n", DataToSend[0], DataToSend[1], DataToSend[2], ReadHandlebarOld(), ADS12_ReadADPin(0) );
      	    CreatePacket(3, ACV_ADDRESS_MSB,ACV_ADDRESS_LSB,DIRECT_MESSAGE,COMMAND_C2B,DataToSend);
      	    (void) TMRS12_InitTimer(7,200);
      	    //printf("200ms timer expired \r\n");
      	}


      	 if(kbhit() == 1) {
			    press = (char)getchar();
			    switch(press) {
				    case 'r':

				        for(j=0 ; j<readLength; j++){
                            (void) printf("REC: 0x %X\r\n",messageArray[j]);
				        }
			    	break;

			        case 's':
			            (void)printf("Toggling send flag \r\n");
			            if(SendingFlag == 0)
			                 SendingFlag = 1;
			            else
			                SendingFlag = 0;
			        break;
			    }
      	 }


    }

}   //Main Bracket


#endif


#ifdef BoatDrive

void main (void){
    int j;
    unsigned char DataToSend[7];
    unsigned char SendingFlag = 0;
    char checksum = 0;
    char press;

    (void) printf("Test Receive Function");
    // Initialize:
    InitSCI();                        // Initialize Communications
    InitIC();                         // Initialize Input Capture for Boost Button
    InitPins();
    TMRS12_Init(TMRS12_RATE_1MS);     // Initialize 1ms timer
    AtollLEDOff();

    byteCounter = 0;
    TimeOutFlag = 0;

    DataToSend[0] = 0x01;
    DataToSend[1] = 0x02;
    DataToSend[2] = 0x03;
    //DataToSend[3] = 0x04;
    //DataToSend[4] = 0x04;
    //DataToSend[5] = 0x05;
    //DataToSend[6] = 0x06;




    /*
    CreatePacket(ACV_ADDRESS_MSB,ACV_ADDRESS_LSB,DIRECT_MESSAGE,COMMAND_ACV,DataToSend);
    // include start + length MSB/LSB + data frame+checksum
    for(i=0 ; i<DataLength+10 ; i++){
        (void) printf("TX: 0x %X\r\n",Packet[i]);
    }
    // NewMessageFlag = TRUE;

    // 7E, 00, 9, 01, 01, 20, 8E, 02, CD, 01, 02, 03, 7A
    */

    (void) TMRS12_InitTimer(7,200);
    (void) TMRS12_InitTimer(6,25);

    while(1){
    	(void) TransmitSM();
    	(void) ReceiveMessageSM();
    	CheckSensorTimeout();

    	// If message received
    	if (messageReceived == 1){
    	  messageReceived = 0;
    	  // Check if it was a message from another XBEE
    	      if (messageArray[API] == API_RECEIVE){
      	  // Check if it was a broadcast message
      	        if (messageArray[RECEIVE_OPTION] == BROADCAST_MESSAGE){
      	        // Check if it was an atoll capture
      	            if(messageArray[COMMAND_TYPE] == BROADCAST_CAPTURE){
      	                // Light the Appripriate LEDs
      	                AtollLED(messageArray[ATOLL_NUMBER], messageArray[TEAM_COLOR]);
      	            }
      	        }
    	      }
    	}

    	if( TMRS12_IsTimerExpired(6) == TMRS12_EXPIRED){
    	    (void) TMRS12_ClearTimerExpired(6);
    	    if (DriveForward == 1){
      	        DriveForward = 0;
      	        if (DriveSpeed < 100){
        	        DriveSpeed++;
      	        }
      	    }
      	    if (DriveBackward == 1){
      	        DriveBackward = 0;
      	        if (DriveSpeed > -100){
      	            DriveSpeed--;
      	        }
      	    }
      	    if (DriveLeft == 1){
      	        DriveLeft = 0;
      	        if (DriveHandle > 40){
      	            DriveHandle--;
      	        }

      	    }
      	    if (DriveRight == 1){
      	      DriveRight = 0;
      	      if (DriveHandle < 140){
      	        DriveHandle++;
      	      }
      	    }

      	    // Set Direction
      	    if(DriveSpeed >= 0){
      	      Direction = 1;
      	    } else{
      	      Direction = 0;
      	    }
      	    (void) TMRS12_InitTimer(6,25);
    	}


      	if( TMRS12_IsTimerExpired(7) == TMRS12_EXPIRED && SendingFlag == 1 ) {
      	    (void) TMRS12_ClearTimerExpired(7);

      	    if (DriveSpeed < 0)
      	        DataToSend[0] = - DriveSpeed;
      	    else
      	        DataToSend[0] = DriveSpeed;

      	    DataToSend[1] = Direction;
      	    DataToSend[2] = DriveHandle;
      	    (void)printf("Speed: %d Direction: %d Heading: %d \r\n", DataToSend[0], DataToSend[1], DataToSend[2]);
      	    CreatePacket(3, ACV_ADDRESS_MSB,ACV_ADDRESS_LSB,DIRECT_MESSAGE,COMMAND_C2B,DataToSend);
      	    (void) TMRS12_InitTimer(7,200);
      	    //printf("200ms timer expired \r\n");
      	}


      	 if(kbhit() == 1) {
			    press = (char)getchar();
			    switch(press) {
				    case 'r':

				        for(j=0 ; j<readLength; j++){
                            (void) printf("REC: 0x %X\r\n",messageArray[j]);
				        }
			    	break;

			        case 'm':
			            (void)printf("Toggling send flag \r\n");
			            if(SendingFlag == 0)
			                 SendingFlag = 1;
			            else
			                SendingFlag = 0;
			        break;

			        case 'w': // Drive Forward
			           DriveForward = 1;
			    	  break;

			    	  case 's':  // Drive Backward
			    	     DriveBackward = 1;
			    	  break;

			    	  case 'a':  // Drive Left
			    	     DriveLeft = 1;

			    	  break;

			    	  case 'd': // Drive Right
				         DriveRight = 1;
			    	  break;
			    }
      	 }


    }

}   //Main Bracket

#endif