#include <m8c.h>
#include "PSoCAPI.h"
#include <string.h>
#include "SPIS.h"

#define MAX_BUFFER_SIZE 20 //maximum buffer size

BYTE tx_buffer[MAX_BUFFER_SIZE]; // tx buffer
BYTE rx_buffer[MAX_BUFFER_SIZE]; // rx buffer
BYTE buffSize; //number of bytes received during last transaction

BYTE Led_ShadowReg; //shadow register of PRT2DR, due to open drain-low

#define PRT_SS (PRT3DR & 0x01) //state of SS line

void ClearLCD(void)
{
	char theStrClear[] = "                ";
	LCD_Position(0, 0);
	LCD_PrString(theStrClear); // Clear screen
	LCD_Position(1, 0);
	LCD_PrString(theStrClear); // Clear screen
}

void LCDPrintMsg(char* msg)
{
	ClearLCD();
	LCD_Position(0, 0);
	LCD_PrString(msg);
}

void SetLEDs(BYTE state)
{
	//Using shadow register because of OpenDrainLow drive mode	
	Led_ShadowReg = state; 
	//Direct writing to PRT2DR because of drive mode
	PRT2DR = Led_ShadowReg;
}

BYTE GetS1ButtonStates(void) // Get state of S1 button
{
	int s1 = -1;
	if(PRT0DR & 0x01)
		s1 = 1;
	else
		s1 = 0;
	return s1;
}

BYTE GetS2ButtonStates(void) // Get state of S2 button
{
	int s2 = -1;
	if(PRT0DR & 0x02)
		s2 = 1;
	else
		s2 = 0;
	return s2;
}

BOOL SPI_Transaction(BYTE* tx_buff, BYTE* rx_buff, BYTE* size)
{
	BYTE temp;
	BOOL result = 1;
	BYTE tx_i = 0, rx_i = 0;
	
	//Initialize SPIS for transaction. This method used to reset TX/Shift registers
	//It helps to transmit first byte correctly, not loaded from previous transaction in hw "Tx Register"
	SPIS_Stop();
	SPIS_Start(SPIS_SPIS_MODE_0 | SPIS_SPIS_MSB_FIRST);
	SPIS_SetupTxData(tx_buff[tx_i]); // put data into shift register
	
	while(PRT_SS); //wait until master initiate transaction
	//Receive all bytes master sends us
	while(1)
	{	
		tx_i++;
		if(tx_i >= MAX_BUFFER_SIZE)
			SPIS_SetupTxData(0xFF); //send any byte if "Tx Buffer"
		else
			SPIS_SetupTxData(tx_buff[tx_i]); //put data into "Tx Buffer"
		
		//wait for SPI_DONE 
		while(!( SPIS_bReadStatus() & SPIS_SPIS_SPI_COMPLETE ))
		{
		   if (PRT_SS) goto ss_done;
		}
		temp = SPIS_bReadRxData(); //read byte from hw "RX register"
		if(rx_i >= MAX_BUFFER_SIZE) 
			result = 0; //ignore just read byte, indicate buffer "overrun"
		else
			rx_buff[rx_i] = temp; //write correct byte to fw "Rx Buffer"
		
		rx_i++;
	}
	ss_done:
	*size = rx_i;
	return result;
}

char CmdExecute_LCD(BYTE* rx_buff)
{
	int i;
	i = 0;	
	ClearLCD();
	LCD_Position(rx_buff[1], rx_buff[2]);
	for(i = 3; i < buffSize; i++)
	{		
		LCD_WriteData(rx_buff[i]);
	}
	return 0;
}

char CmdExecute_LED(BYTE* rx_buff)
{
	BYTE val, mask;	
	BYTE i = 1;
	val = Led_ShadowReg; //get current port state from shadow reg
	while(i < buffSize)
	{
		if (rx_buff[i] <= 4)
		{
			mask = 1 << (rx_buff[i]-1);
			if (rx_buff[i+1] == 0)
				val |= mask;		//shutdown LED
			else
				val &= ~mask;		//turn on LED
		}
		i = i + 2;
	}
	//Update port state
	SetLEDs(val);
	return 0;
}

char CmdExecute_Scan(BYTE* tx_buff)
{
	BYTE bVal,i;
	WORD data;

	// Measure voltage on Port_0[4]
	ABF_CR0 &= ~0x80;
	
	DelSig_StartAD();  //start ADC sampling
	
	for (i=0; i<5; i++){
		while(!DelSig_fIsDataAvailable());
		data = DelSig_wGetDataClearFlag();
	}
	
	//Update tx_buffer by DelSig value
	bVal = data & 0xFF;
	tx_buff[0] = bVal;  // lsb
	data = data >> 8;	
	bVal = data & 0xFF;
	tx_buff[1] = bVal; // msb
	
	// Measure voltage on Port_0[5]
	ABF_CR0 |= 0x80;
		
	for (i=0; i<5;i++){
		while(!DelSig_fIsDataAvailable());	
		data = DelSig_wGetDataClearFlag();
	}
	
	DelSig_StopAD(); //stop ADC sampling
	
	//Update tx_buffer by DelSig value
	bVal = data & 0xFF;
	tx_buff[2] = bVal;  // lsb
	data = data >> 8;	
	bVal = data & 0xFF;
	tx_buff[3] = bVal; // msb

	//Update tx_buffer by Button s1/s2 values
	if(GetS1ButtonStates() == 1)
		bVal = 0x01;
	else
		bVal = 0x00;	
	tx_buff[4] = bVal;
	
	if(GetS2ButtonStates() == 1)
		bVal = 0x01;
	else
		bVal = 0x00;
	tx_buff[5] = bVal;
		
	return 0;
}

char CmdExecute_Read(BYTE* tx_buff)
{
	return 0;
}

void main(void)
{
	BYTE size = 0;
	int i = 0;
	char badCmd[] = "Bad Command!";
	char badParams[] = "Bad Cmd params!";

	SPIS_Start(SPIS_SPIS_MODE_0 | SPIS_SPIS_MSB_FIRST); //Start slave device
	LCD_Start(); // Enable LCD
	PGA_Start(3); // Enable PGA
	DelSig_Start(3); // Enable DelSig
	M8C_EnableGInt; // Turn on interrupts

	SetLEDs(0xFF);  //all LEDs Off
	LCD_Position(0,1);
	LCD_PrCString("-SPI Example-");
	LCD_Position(1,1);
	LCD_PrCString("Slave  Device");

	//Put any data in the TX/RX buffers
	for (i=0; i<MAX_BUFFER_SIZE; i++) {
		tx_buffer[i]=255-i;
		rx_buffer[i]=i;
	}

	//Wait for master to get initialized
	while (!PRT_SS); 
	//Start SPI communication and commands processing
	while(1)
	{
		//Execute SPI transaction
		SPI_Transaction(tx_buffer, rx_buffer, &size);
		buffSize = size;
		//Interpret Command
		if(rx_buffer[0] == 0x10)
		{
			if(buffSize < 3)
				LCDPrintMsg(badParams);
			else
				CmdExecute_LCD(rx_buffer);
		}
		else
		if(rx_buffer[0] == 0x20)
		{
			if((buffSize < 3) || !(buffSize & 0x01) || (buffSize > 9))
				LCDPrintMsg(badParams);
			else
				CmdExecute_LED(rx_buffer);
		}
		else
		if(rx_buffer[0] == 0x30)
		{
			if(buffSize != 1)
				LCDPrintMsg(badParams);
			else
				CmdExecute_Scan(tx_buffer);
		}
		else
		if(rx_buffer[0] == 0x40)
			CmdExecute_Read(tx_buffer);
		else
			LCDPrintMsg(badCmd);
	}
}