#include <htc.h>
#include "pic16f690.h"
#include <stdio.h>
#include "bitdefs.h"

__CONFIG(CP_OFF & WDTE_OFF & PWRTE_ON & FOSC_HS);


/*------------------- Module Defines --------------------*/
// Port Definitions
#define RFID_RequestBit RC3
#define SS_RFID RC6
#define SS_Xbee RC4
#define DebugBit RC0

// Transmission Bytes
#define RFID_DummyByte 0xB9
#define Start_Color 0xCC
#define Start_Atoll 0xAA

// State Machine States
typedef enum {
    Security_Idle = 0,
    Security_RFID,
    Security_SC,
    Security_Xbee
} SecurityState_t;

/*------------------ Module Functions -------------------*/
static void SPIInit(void);
static void SecurityInit(void);
static void UpdateTimer(void);
static unsigned char CheckRFIDColor(void);

/*------------------ Module Variables -------------------*/
// State Machine Variables
static SecurityState_t SecurityState = Security_Idle;
static unsigned char StateTimer = 0;

// Transmission Variables
static unsigned char RFIDColorFlag = 0;
static unsigned char RFID_Index = 0;
static unsigned char Xbee_Index = 0;
static unsigned char RFID_Data[5];
static unsigned char Xbee_Data[10];


/*-------------------- Module Code ----------------------*/

/**********************************************************
Function:   UARTInit
Parameters: none
Returns:    none
Description:
    Initializes UART to 9600,N,8,1
**********************************************************/
void UARTInit(void){
	//TRIS registers for UART
	TRISB5 = 1; //RX input
	TRISB7 = 0; //TX output

    //9600 baud rate:
    SPBRG = 129;
    BRGH = 1;
    //asynch mode:
    SYNC = 0;
    SPEN = 1;
    //enable tx and rx:
    TXEN = 1;
	CREN = 1;
}

/**********************************************************
Function:   SPIInit
Parameters: none
Returns:    none
Description:
    Initializes SPI as Master, timed by Timer 2
**********************************************************/
static void SPIInit(void){
    //Deselect both slaves initially
    SS_RFID = 1;
    SS_Xbee = 1;

    //TRIS registers for SPI
    TRISC7 = 0; //SDO output
    TRISB6 = 0; //clock output
    TRISB4 = 1; //SDI input

    TRISC6 = 0; //RFID SS output
    TRISC4 = 0; //Xbee SS output
    TRISC3 = 1; //RFID ready input

    //Configure SPI Status register
    SSPSTAT = 0b00000000;
            //  0xxxxxxx    Input data sampled at middle of ouput time
            //  x0xxxxxx    CKE - Data transmitted on rising edge of SCK

    //setup SPI Control register
    SSPCON =  0b00110011;
            //  xx1xxxxx    Enables SPI
            //  xxx1xxxx    CKP - clock idles high
            //  xxxx0011    SPI master, clock = TMR2 output / 2
}

/**********************************************************
Function:   SecurityInit
Parameters: none
Returns:    none
Description:
    General initialization for this module, including timer
    initialization.
**********************************************************/
static void SecurityInit(void){
	//Clear ANSEL registers
	ANSEL = 0;
	ANSELH = 0;

    //Timer0 Init (overflows at 76 Hz)
    T0CS = 0;   //use Fosc/4
    PSA = 0;    //prescale for T0
    PS0 = 1;    //Set Prescale to 256.
    PS1 = 1;
    PS2 = 1;

    //Timer2 Init for SPI
    PR2 = 125;  //10kHz SPI rate, with 1:4 prescale below
    T2CON =   0b00000101;
            //  x0000xxx    1:1 postscale
            //  xxxxx1xx    TMR2 on
            //  xxxxxx01    1:4 prescale

    //Debug Pin
    DebugBit = 1;
    TRISC0 = 0;   //debug LED output
}

/**********************************************************
Function:   main
Parameters: none
Returns:    none
Description:
    Calls initialization functions, then enters state
    machine loop.  State machine consists of a switch on
    the current state, at which point the relevant events
    are checked (equivalent to local event checkers).
    Only one state is called per loop and only one state
    transmission is feasible per loop.
**********************************************************/
void main(void){
    SecurityInit();
    UARTInit();
    SPIInit();

    while(1){
        UpdateTimer();

        switch (SecurityState){

// State: Idle
            case Security_Idle:
    // Event: RFID PIC has new data to send
                if (RFID_RequestBit == 1){
                    SS_Xbee = 1; //ensure Xbee slave deselected
                    SS_RFID = 0; //select RFID slave

                    RFID_Index = 0; //reset byte counter

                    SSPBUF = RFID_DummyByte; //Start transmission

                    SecurityState = Security_RFID; //change states
                    StateTimer = 0;
                }
                break;

// State: Reading from RFID PIC
            case Security_RFID:
    // Event: New byte received over SPI
                if (SSPIF == 1){
                    SSPIF = 0;  //clear SPI flag
                    //store byte for transmission to SC:
                    RFID_Data[RFID_Index] = SSPBUF;
                    //store byte for transmission to Xbee PIC:
                    Xbee_Data[RFID_Index] = RFID_Data[RFID_Index];

                    RFID_Index++;   //increment index
                    // make sure index doesn't leave array:
                    RFID_Index = ((RFID_Index > 4) ? 4 : RFID_Index);

                    //If there is more data to send (request line still high)
                    if (RFID_RequestBit == 1){
                        SSPBUF = RFID_DummyByte; //get next byte
                        StateTimer = 0;
                    }
                    //Otherwise, no more data
                    else{
                        SS_RFID = 0; //deselect RFID slave

                        RFID_Data[0] = 0x04; //start and end bytes for SC message
                        RFID_Data[4] = 0x08;


                        SS_RFID = 1; //Ensure RFID slave deselected
                        if (CheckRFIDColor() == 1){ //If card was a color card
                            SS_Xbee = 0; //Select Xbee slave

                            RFIDColorFlag = 1;

                            RFID_Index = 1;  //include header byte below
                            Xbee_Index = 1; //include header byte below

                            SSPIF = 0;
                            SSPBUF = Start_Color; //Xbee_Header;

                            SecurityState = Security_Xbee;  //send direct to xbee
                            StateTimer = 0;
                        }
                        else {    //If card was not a color card
                            RFIDColorFlag = 0;

                            RFID_Index = 0; //start at 0 to include header byte
                            Xbee_Index = 4; //start at 4 for SC data

                            SecurityState = Security_SC; //send to Security controller
                            StateTimer = 0;
                        }
                    }
                }
                break;

// State: Communicating with Security controller
            case Security_SC:
    //Event: Transmission of byte complete
                if ((TXIF == 1) && (RFID_Index <= 4)){
                    //Send next byte:
                    TXREG = RFID_Data[RFID_Index];
                    RFID_Index++;
                    StateTimer = 0;
                }
    //Event: Received data from security controller
                if (RCIF == 1){
                    //Store data for transmission to Xbee PIC
                    Xbee_Data[Xbee_Index] = RCREG;
                    Xbee_Index++;
                    StateTimer = 0;

                    //If we have all the data from the SC, start xmit to Xbee PIC
                    if (Xbee_Index == 10){
                        SS_RFID = 1; //Ensure RFID slave deselected
                        SS_Xbee = 0; //Select Xbee slave

                        Xbee_Index = 1; //start at 1 since header sent below
                        RFID_Index = 1;

                        SSPIF = 0;
                        SSPBUF = Start_Atoll; //Send Xbee_Header;

                        SecurityState = Security_Xbee; //change states
                    }
                }
                break;

// State: Communicating with Xbee PIC
            case Security_Xbee:
    //Event: Data received over SPI (i.e. byte sent)
                if (SSPIF == 1){
                    SSPIF = 0; //clear flag

                    //If we have finished our transmission
                    if (((Xbee_Index >= 4) && (RFIDColorFlag == 1)) ||
                        ((Xbee_Index >= 10) && (RFIDColorFlag == 0))){
                        //Deselect slaves:
                        SS_RFID = 1;
                        SS_Xbee = 1;

                        //Reenter idle state:
                        SecurityState = Security_Idle;
                        StateTimer = 0;

                        // Toggle debug bit
                        DebugBit ^= 1;
                    }
                    //If we haven't finished our transmission
                    else{
                        //Send next byte:
                        SSPBUF = Xbee_Data[Xbee_Index];

                        //Increment Xbee data index
                        if (Xbee_Index >= 4){
                            Xbee_Index++; //skip every other SC byte
                        }
                        Xbee_Index++;
                        StateTimer = 0;
                    }
                }
                break;
        }
    }
}

/**********************************************************
Function:   CheckRFIDColor
Parameters: none
Returns:    unsigned char, 1 if card might be color card,
                           0 otherwise
Description:
    Checks if the first byte of the serial number is less
    than 0x40, since all color cards and no atoll cards
    have this property.
**********************************************************/
static unsigned char CheckRFIDColor(void){
    return (RFID_Data[1] < 0x40); //since all color cards are less than 0x40
}

/**********************************************************
Function:   UpdateTimer
Parameters: none
Returns:    none
Description:
    If timer0 has overflowed, the state timer is
    incremented.  If it has overflowed 16 times (200ms)
    then the state machine is reset to Idle.
**********************************************************/
static void UpdateTimer(void){
   if (T0IF == 1){ //if timer 0 overflows
        T0IF = 0;
        StateTimer++;
        if (StateTimer >= 16){
            StateTimer = 0;
            SecurityState = Security_Idle;//run reset function
        }
    }
}