
#ifndef __MAIN_C__
#define __MAIN_C__

#include <p18cxxx.h>
#include <p18f2550.h>
#include <string.h>
#include <delays.h>
#include <stdio.h>
#include <i2c.h>
#include "lcd.h"

#pragma config PLLDIV   = 2 		//Divide by 2 (8 MHz oscillator input)	(0xF9)
#pragma config CPUDIV   = OSC1_PLL2 //[OSC1/OSC2 Src: /1][96 MHz PLL Src: /2]	(0xE7)
#pragma config USBDIV   = 2 		//USB clock source comes from the 96 MHz PLL divided by 2	(0xFF)
#pragma config FOSC     = HSPLL_HS 	//HS oscillator, PLL enabled, HS used by USB	(0xFE)
#pragma config FCMEN    = OFF 		//Fail-Safe Clock Monitor disabled	(0xBF)
#pragma config IESO     = OFF 		//Oscillator Switchover mode disabled	(0x7F)
#pragma config PWRT     = ON		//PWRT enabled
#pragma config BOR      = ON		//Brown-out Reset enabled in hardware only (SBOREN is disabled)
#pragma config BORV 	= 1			//4.33V 
#pragma config VREGEN   = ON		//USB voltage regulator enabled
#pragma config WDT      = OFF		//Watchdog Timer Disabled
#pragma config WDTPS    = 512		//Watchdog Timer Postscale 1:512
#pragma config MCLRE    = ON		//MCLR pin enabled// RE3 input pin disabled
#pragma config LPT1OSC  = OFF		//Timer1 configured for higher power operation
#pragma config PBADEN   = OFF		//PORTB<4:0> pins are configured as digital I/O on Reset
#pragma config CCP2MX   = OFF		//CCP2 input/output is multiplexed with RB3
#pragma config STVREN   = ON		//Stack full/underflow will cause Reset
#pragma config LVP      = OFF		//Single-Supply ICSP disabled
#pragma config XINST    = OFF		//Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
#pragma config DEBUG    = OFF		//Background debugger disabled, RB6 and RB7 configured as general purpose I/O pins


/////////////////////////////////////////////////
#define SCL       PORTBbits.RB1   	// SCL output pin
#define SCL_TRIS  TRISBbits.TRISB1  // SCL direction pin
#define SDA       PORTBbits.RB0   	// SDA output pin
#define SDA_TRIS  TRISBbits.TRISB0  // SDA direction pin


unsigned char loopCnt = 0;
volatile unsigned char i2cdataReady = 0;
volatile unsigned char i2cdata = 0;

volatile unsigned char i2caddressRx = 0;
volatile unsigned char bufferRx[64];
volatile unsigned char bufferRxPos;

volatile unsigned char i2caddressTx = 0;
volatile unsigned char bufferTx[4];
volatile unsigned char bufferTxPos;

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
				i2cdata = SSPBUF;
				
				bufferRx[bufferRxPos] = i2cdata;
				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; 
	}
}

void main(void)
{
	char line[]= "       "; // 7 blanks
	unsigned char reg = 0; 	// command register
	signed long A = 0; 		// steps
	signed long B = 0;
	signed long C = 0;
	signed long D = 0;
	signed short long Aspu = 0; //steps per unit
	signed short long Bspu = 0;
	signed short long Cspu = 0;
	signed short long Dspu = 0;
	
	INTCON  = 0x00;		// disable all interrupts
	INTCON2 = 0xF0;
	INTCON3 = 0x00;
	ADCON1 = 0b00001111;  // configure analog inputs and Vref
	
	TRISA = 0x00; LATA = 0x00;
	TRISB = 0x00; LATB = 0x00;
	TRISC = 0x00; LATC = 0x00;
	
	Delay10KTCYx(120); //100ms
	Delay10KTCYx(120); //100ms
	lcd_init();	
	
	//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 = 0x36;       //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    

	PIR1 = 0x00; 
	PIR1bits.SSPIF = 0;
	PIE1 = 0x00; 
	PIE1bits.SSPIE = 1;

	SSPCON1bits.CKP = 1; //Clock Released

	INTCON = 0x00;
	INTCONbits.PEIE = 1;
	INTCONbits.GIE = 1;
	while(1)
	{
		if (!PIR1bits.SSPIF && i2cdataReady)
		{
			PIE1bits.SSPIE = 0; //disable interrupt
			reg = bufferRx[ 0];
			if (reg == 20) //command register 20 for coordinate display
			{
				memcpy((void*)&A, (void*)&bufferRx[ 0+1], 4);
				memcpy((void*)&B, (void*)&bufferRx[ 4+1], 4);
				memcpy((void*)&C, (void*)&bufferRx[ 8+1], 4);
				memcpy((void*)&D, (void*)&bufferRx[12+1], 4);
			
				memcpy((void*)&Aspu, (void*)&bufferRx[16+1], 3);
				memcpy((void*)&Bspu, (void*)&bufferRx[19+1], 3);
				memcpy((void*)&Cspu, (void*)&bufferRx[22+1], 3);
				memcpy((void*)&Dspu, (void*)&bufferRx[25+1], 3);
			}
			PIE1bits.SSPIE = 1; //enable interrupt
						
			if (reg == 20) //command register 20 for coordinate display
			{
				A = 100*A / Aspu ;
				B = 100*B / Bspu;
				C = 100*C / Cspu;
				D = 100*D / Dspu;
					
				lcd_line1();
				Delay10TCYx(48); //40us
				
				//printf((const rom far char*)"%8ld%8ld", A, B);
				sprintf((void*)&line, (const rom far char*)"%7ld", A);
				lcd_putsDec(line, 5);
				sprintf((void*)&line, (const rom far char*)"%7ld", B);
				lcd_putsDec(line, 5);
				
				lcd_line2();
				Delay10TCYx(48); //40us
				//printf((const rom far char*)"%8ld%8ld", C, D);
				sprintf((void*)&line, (const rom far char*)"%7ld", C);
				lcd_putsDec(line, 5);
				sprintf((void*)&line, (const rom far char*)"%7ld", D);
				lcd_putsDec(line, 5);
			}
		}	
		
		LATCbits.LATC6 = ~LATCbits.LATC6; //blinking LED
		Delay10KTCYx(120); //100ms
	}		
}	

#endif 

