#ifndef __I2C_C__
#define __I2C_C__


#include <p18cxxx.h>
#include <string.h>
#include <delays.h>
#include <stdio.h>
#include "typedefs.h"
#include "vars.h"
#include "i2c.h"


volatile U8 i2cdataReady = 0;

volatile U8 i2caddressRx = 0;
volatile U8 bufferRx[64];
volatile U8 bufferRxPos;

volatile U8 i2caddressTx = 0;
volatile U8 bufferTx[64];
volatile U8 bufferTxPos;

U8 buf[16];

void i2c_config(void)
{
	//init buffer
	bufferRxPos = 0;
	memset((char*)&bufferRx, 0, sizeof(bufferRx));
	
	bufferTxPos = 0;
	memset((char*)&bufferTx, 0, sizeof(bufferTx));

	//Configure I2C
	SCL_TRIS = 1; 	//configure as input
	SDA_TRIS = 1;	//configure as input
 
	//Reseting MSSP registers 
	SSPCON1 = 0x00;
	SSPCON2 = 0x00; 
	SSPCON1bits.SSPM3 = 1; //I2C SLAVE mode, 7 bit address, with Start & Stop bits interrupts enabled 
	SSPCON1bits.SSPM2 = 1; 
	SSPCON1bits.SSPM1 = 1; 
	SSPCON1bits.SSPM0 = 0;    
	SSPCON1bits.SSPEN = 1; //Enable I2C port            
	SSPCON1bits.SSPOV = 0; //Clear Buffer Overflow 
	
	SSPADD = 54;       //SLAVE address is (7bit). LSB bit is set to 1 for read 
	SSPSTATbits.SMP = 1; //Slew rate set to NORMAL speed @ 100kHz    
	SSPSTATbits.CKE = 0; //Disable SMBus 

	PIR1bits.SSPIF = 0;
	PIE1bits.SSPIE = 1;
	SSPCON1bits.CKP = 1; //Clock Released
}



void HighPriorityISRCode(void);

#pragma code highVector=0x008 
void InterruptHigh(void)
{
	_asm GOTO HighPriorityISRCode _endasm
}

#pragma code
#pragma interrupt HighPriorityISRCode 
void HighPriorityISRCode(void)
{
	if (PIR1bits.SSPIF)
	{
		//----------------------------------------------------------------
		// SSPSTAT register:
		//	7    6    5    4    3    2    1    0
		//	SMP  CKE  D_A  P    S    R_W  UA   BF
		//-----------------------------------------------------------------
	
		if (SSPSTATbits.S) //Start bit
		{
			i2cdataReady = 0;
			
			//WRITE
			if      (!SSPSTATbits.R_W &&  SSPSTATbits.BF && !SSPSTATbits.D_A) // State 1: I2C write operation, last byte was an address byte
			{
				//receive address
				i2caddressRx = SSPBUF;
				bufferRxPos = 0;
				memset((char*)&bufferRx, 0, sizeof(bufferRx));
			}
			else if (!SSPSTATbits.R_W &&  SSPSTATbits.BF &&  SSPSTATbits.D_A) // State 2: I2C write operation, last byte was a data byte
			{
				//receive data
				bufferRx[bufferRxPos] = SSPBUF;
				if (++bufferRxPos >= sizeof(bufferRx)) bufferRxPos = 0;
			}	
			//READ
			else if ( SSPSTATbits.R_W &&  SSPSTATbits.BF && !SSPSTATbits.D_A) // State 3: I2C read operation, last byte was an address byte
			{
				//receive address, send data
				i2caddressTx = SSPBUF;
				while(SSPSTATbits.BF); //Wait until buffer cleared
				
				bufferTxPos = 0;
				do
				{
					SSPCON1bits.WCOL = 0; //Clear the WCOL flag.
					SSPBUF = bufferTx[bufferTxPos];
				} while (SSPCON1bits.WCOL); //Wait until WCOL cleared
				if (++bufferTxPos >= sizeof(bufferTx)) bufferTxPos = 0;
			}	
			else if ( SSPSTATbits.R_W &&  !SSPSTATbits.BF &&  SSPSTATbits.D_A) // State 4: I2C read operation, last byte was a data byte
			{
				//send data
				do
				{
					SSPCON1bits.WCOL = 0; //Clear the WCOL flag.
					SSPBUF = bufferTx[bufferTxPos];
				} while (SSPCON1bits.WCOL); //Wait until WCOL cleared
				if (++bufferTxPos >= sizeof(bufferTx)) bufferTxPos = 0;
			}
			//Other
			else if (SSPCON1bits.CKP  && !SSPSTATbits.BF &&  SSPSTATbits.D_A) // State 5: Slave I2C logic reset by NACK from master
			{
				// Slave I2C logic reset by NACK from master
			}
			else
			{
				//Other states
			}	
		}

		if (SSPSTATbits.P) //Stop bit
		{
			i2cdataReady = 1;
		}
			
		SSPCON1bits.CKP = 1; //Clock Released
		PIR1bits.SSPIF = 0;

		if(!i2cdataReady) return;
		i2cdataReady = 0;

		switch(bufferRx[ 0])
		{
			case I2CCMD_SETTINGS1:
			{
				AxesCnt = bufferRx[1];
				memcpy((void*)&AxisStepsPerMM, (void*)&bufferRx[2], AxesCnt<<2);
				break;
			}
			case I2CCMD_SETTINGS2:
			{
				break;
			}
			case I2CCMD_POSITION:
			{
				memcpy((void*)&Position, (void*)&bufferRx[1], AxesCnt<<2);
				break;
			}
		}



	}
}


#endif


