#define SECURITY_TEST

/*
Security PIC Module

This module:
(1) Takes an RFID message from the RFID PIC via SPI, converts ASCII->HEX
(2) Prepares a message with the serial # for the security controller
(3) Sends it via UART to the security controller
(4) Receives a security key back via UART
(5) Prepares a message with the serial # and security key for the Main PIC


*/


/*   PINOUT FOR SECURITY CONTROLLER PIC
******************************************
1  +5V         |VDD  VSS|   GND         20
2  OSC1        |A5    A0|               19
3  OSC2        |A4    A1|               18
4              |A3    A2|               17
5  RFID_READY  |C5    C0|  SS-MAIN		16
6              |C4    C1|               15
7     		   |C3    C2|               14
8  SS-RFID	   |C6    B4|  SPI-SDI      13
9  SPI-SDO     |C7    B5|  RX           12
10 TX          |B7    B6|  SPI-SCK      11
*/

#include <htc.h>
//#include "pic16f690.h" // for Eric's laptop
#include <stdio.h>
#define _LEGACY_HEADERS
#include "BITDEFS.h"
#include "TimerPIC.h"

#define		SS_RFID				RC0
#define		SS_MAIN				RC6
#define		DUMMY_BYTE			0xAA
#define		RFID_MESSAGE_LENGTH	14
#define		RFID_HEX_LENGTH		6
#define 	SK_SEND_LENGTH 		5
#define		SK_RECEIVE_LENGTH 	6
#define		MAIN_SEND_LENGTH	6


#ifdef SECURITY_TEST
__CONFIG(CP_OFF & WDTE_OFF & PWRTE_OFF & FOSC_HS);
#endif

typedef enum {
	WAITING_IDLE,
	WAITING_FOR_RFID,
	SENDING_TO_SECURITY_PIC,
	RECEIVING_FROM_SECURITY_PIC,
	SENDING_TO_MAIN_PIC
} state_t;

// Function prototypes
void interrupt Security_ISR(void);
void InitPins(void);
void InitFlags(void);
void InitSPI(void);
void InitSCI(void);
void InitInterrupts(void);
void Init(void);
void Update(void);
unsigned char ConvertASCIItoHEX(unsigned char upper, unsigned char lower);
unsigned char VerifyChecksum(void);
void MakeSecurityMessage(void);
void MakeMainMessage(void);

// Module variables
static unsigned char RFID_Ready;						// Flag = set when RFID message available
static unsigned char RFID_Message[RFID_MESSAGE_LENGTH];	// Incoming RFID message
static unsigned char RFID_Hex[RFID_HEX_LENGTH];			// RFID data converted to HEX
static unsigned char Security_TX[SK_SEND_LENGTH]; 		// Request to Security Controller
static unsigned char Security_RX[SK_RECEIVE_LENGTH]; 	// Response from Security Controller
static unsigned char Main_Message[MAIN_SEND_LENGTH];	// Message to Main PIC

#ifdef SECURITY_TEST
// Rising edge
void interrupt Security_ISR(void) {
	// New RFID message ready
	if (CCP1IE && CCP1IF) {
		CCP1IF = 0;
		RFID_Ready = 1;
	}
#endif

void InitPins(void) {
	// Turn off analog inputs
	ANSEL = 0;
	ANSELH = 0;

	// Set C0 and C6 to be outputs (low)
	TRISC0 = 0;	// SS (Main)
	TRISC6 = 0;	// SS (RFID)
	TRISB6 = 0;	// SCK
	TRISC7 = 0;	// SDO
	TRISB7 = 0;	// TX
	// Don't select either slave yet
	SS_RFID = 1;
	SS_MAIN = 1;
}

void InitFlags(void) {
	RFID_Ready = 0;
}

void InitSPI(void) {

	// Set up timer 2 for 19.53kHz
	TMR2ON = 1;
	// Prescaler = 1
	T2CKPS0 = 0;
	T2CKPS1 = 0;

	// Configure SPI
	/* SPI port
	0xxxxxxx = No write collision detect
	x0xxxxxx = No receive overflow indicator
	xx1xxxxx = Enable serial port, SCK, SDO, SDI as serial pins
	xxx1xxxx = Clock idles high
	xxxx0011 = SPI Master, clock = timer2 output/2 (about 10kHz)
	*/
	SSPCON = 0b00110011;

	/* SPI status register
	0xxxxxxx = Data sampled in middle of output
	x0xxxxxx = Data transmitted on falling edge of SCK
	xxXXXXXX = Read only
	*/
	SSPSTAT = 0b00000000;

	SSPIE = 0;		// Turn off SPI interrupt
  	SSPBUF = 0;		// Clear buffer
}

void InitSCI(void) {

	unsigned char temp;

	TXEN = 1;		// Enable transmit
  	SYNC = 0;		// Turn off synchronous mode
  	TX9 = 0;		// Disable 9-bit transmission
  	SPEN = 1;		// Serial port enabled (configures RX/TX as serial port pins)
  	CREN = 1;		// Continuous receive
  	RX9 = 0;		// Disable 9-bit receive
  	ADDEN = 0;		// Turn off address detection
  	BRGH = 1;		// High data rate mode
  	SPBRG = 0x81;	// Set baud rate to 9600
  	SPBRGH = 0;		// Clear high baud rate bits

  	temp = RCREG;	// Clear flag in case RCREG was full
  	SSPIF = 0;		// Clear before we can send over UART
}

void InitInterrupts(void) {
	// Capture on every rising edge
	// CCP1CON
	CCP1M0 = 1;
	CCP1M2 = 1;
	// Enable input capture
	CCP1IE = 1;
	// Enable Peripheral and Global Interrupts
	INTCON = 0;
	PEIE = 1;
	GIE = 1;
}

void Init(void) {
	InitPins();
	InitFlags();
	InitSPI();
	InitSCI();
	InitInterrupts();
}

void Update(void) {
	static state_t currState = WAITING_IDLE; 	// Initial state
	static state_t nextState;
	static unsigned int counter = 0;			// Initial counter

	// Assume we stay in the same state unless our SM says otherwise
	nextState = currState;

	switch(currState) {

		case WAITING_IDLE:
			// If we get a new RFID message
			if(RFID_Ready) {
				// Clear flag for next time throughwe
				RFID_Ready = 0;
				// Select RFID PIC as slave
				SS_RFID = 0;
				// Send a dummy byte to enable transfer
				SSPBUF = DUMMY_BYTE;
				counter++;
				nextState = WAITING_FOR_RFID;
			}
		break;

		case WAITING_FOR_RFID:
			// Once we get a response from RFID PIC
			if(BF) {
				// If it's not our last byte
				if(counter < RFID_MESSAGE_LENGTH) {
					// Get byte, clears BF
					RFID_Message[counter-1] = SSPBUF;
					// Send a dummy byte to enable transfer
					SSPBUF = DUMMY_BYTE;
					counter++;
				}
				// If we got our last byte
				else {
					// Get byte, clears BF
					RFID_Message[counter-1] = SSPBUF;
					// Done
					counter = 0;
					// De-select RFID PIC as slave
					SS_RFID = 1;
					// If checksum passes, return 0,
					// VerifyCheckSum also converts the ASCII data to HEX
					if(VerifyChecksum() == 0) {
						// Prepare message to Security Controller
						MakeSecurityMessage();
						// Wait for xmit register to empty, technically blocking code,
						// but TXIF should never be 0 here
						while(!TXIF);
						// Send out the first byte
						TXREG = Security_TX[0];
						counter++;
						nextState = SENDING_TO_SECURITY_PIC;
					}
					else
						nextState = WAITING_IDLE;
				}
				BF = 0;		// probably not needed
				SSPIF = 0;	// Clear so that Main PIC message sends
			}
		break;

		case SENDING_TO_SECURITY_PIC:
			// If Xmit register empty
			if(TXIF) {
				// Send out message
				if(counter < SK_SEND_LENGTH) {
					TXREG = Security_TX[counter];
					counter++;
				}
				// Done sending out message
				else {
					counter = 0;
					nextState = RECEIVING_FROM_SECURITY_PIC;
				}
			}
		break;

		case RECEIVING_FROM_SECURITY_PIC:
			// If we got another byte from Security Controller
			if(RCIF) {
				// Get the bytes, clears RCIF
				Security_RX[counter] = RCREG;
				// Not done yet
				if(counter < (SK_RECEIVE_LENGTH - 1))
					counter++;
				// Get the last (6th) byte
				else if (counter == SK_RECEIVE_LENGTH-1) {

					counter = 0;
					// Select SS of Main PIC
					SS_MAIN = 0;
					// Prepare message to Main PIC
					MakeMainMessage();
					SSPBUF = Main_Message[0];
					counter++;
					nextState = SENDING_TO_MAIN_PIC;
				}
			}
		break;

		case SENDING_TO_MAIN_PIC:
			// If finished last transmission
			if(SSPIF && BF) {
				// Read SSPBUF garbage to clear BF
				SSPBUF;
				// Manually clear flag
				SSPIF = 0;
				// Send the rest of the message
				if(counter < MAIN_SEND_LENGTH) {
					SSPBUF = Main_Message[counter];
					counter++;
				}
				else {
					counter = 0;
					// Deselect SS of Main PIC
					SS_MAIN = 1;
					nextState = WAITING_IDLE;
				}
				// Done
			}
		break;
	}
	currState = nextState;
}

unsigned char ConvertASCIItoHEX(unsigned char upper, unsigned char lower) {

	static unsigned char hex, lower_hex;

	// Upper nibble: if < 0x40, AND w/ 0x0F, otherwise subtract 0x37, then bit shift
	hex = (upper < 0x40)?(upper & 0x0F):(upper - 0x37);
	hex = hex<<4;
	// Lower nibble: same as above, without bit shift, add to upper to get full HEX
	lower_hex = (lower < 0x40)?(lower & 0x0F):(lower - 0x37);
	hex += lower_hex;
	return hex;
}

unsigned char VerifyChecksum(void) {

	static unsigned char i, checksum;

	// Convert received ASCII characters to HEX
	for(i=0; i<RFID_HEX_LENGTH; i++)
		RFID_Hex[i] = ConvertASCIItoHEX(RFID_Message[2*i+1], RFID_Message[2*i+2]);
	// Calculate the checksum:
	// XOR all the converted HEX values after the start of data ASCII charactr (0x02)
	checksum = RFID_Hex[0];
	for(i=1; i<RFID_HEX_LENGTH; i++)
		checksum ^= RFID_Hex[i];
 	// Should return 0 if we had a valid checksum since our last operation was XOR w/ checksum
	return checksum;
}

void MakeSecurityMessage(void) {

	static unsigned char i;

	Security_TX[0] = 0x04;
	for (i=1; i<4; i++)
		Security_TX[i]= RFID_Hex[i+1];
	Security_TX[4] = 0x08;
}

void MakeMainMessage(void) {

	// S1-S3
	Main_Message[0] = Security_TX[1];
	Main_Message[1] = Security_TX[2];
	Main_Message[2] = Security_TX[3];
	// SK1-SK3
	Main_Message[3] = Security_RX[0];
	Main_Message[4] = Security_RX[2];
	Main_Message[5] = Security_RX[4];
}

#ifdef SECURITY_TEST

void main(void) {

	Init();
	TimerPIC_Init();
	GIE = 1;
	TRISA1 = 0;	// test output

	//TimerPIC_InitTimer(7,200);
	RA1 = 1;

	while(1) {
		Update();
		/*
		if(TimerPIC_IsTimerExpired(7) == TimerPIC_EXPIRED){
			TimerPIC_ClearTimerExpired(7);
			TimerPIC_InitTimer(7,200);
			RA1 ^= 1;
		}
*/
	}
}

#endif