/*****************************************************************************
 *
 * I2C scanning.
 *
 *****************************************************************************
 * FileName:        I2Cmain.c
 * Dependencies:    
 * Processor:       PIC18F with CAN
 * Compiler:       	C18 02.30.00 or higher
 * Linker:          MPLINK 03.20.01 or higher
 * Company:         Microchip Technology Incorporated
 *
 * Software License Agreement
 *
 * The software supplied herewith by Microchip Technology Incorporated
 * (the "Company") is intended and supplied to you, the Company's
 * customer, for use solely and exclusively with products manufactured
 * by the Company. 
 *
 * The software is owned by the Company and/or its supplier, and is 
 * protected under applicable copyright laws. All rights are reserved. 
 * Any use in violation of the foregoing restrictions may subject the 
 * user to criminal sanctions under applicable laws, as well as to 
 * civil liability for the breach of the terms and conditions of this 
 * license.
 *
 * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, 
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED 
 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, 
 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR 
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 *
 *
 * This is a simple timer function used within the DeviceNet Stack for
 * demonstration.
 * 
 *
 *
 * Author               Date        Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Ross Fosler			08/13/04	...	
 * 
 *****************************************************************************/

#include	<P18cxxx.H>
#include	"TYPES.H"
#include	"IO.H"
#include	"strings.h"
#include	"I2Cmain.h"


UCHAR 		_uI2CAddr;
UCHAR 		_uI2CCmd;
UCHAR 		_uI2CData;
I2CFLAGS	_bI2CFlags;
I2CSTATES	_bI2CStates;


void I2C_Init(UCHAR bitrate)
{
	_bI2CFlags.byte = 0;
	_bI2CStates.byte = 0;

	LATCbits.LATC3 = 1;
	LATCbits.LATC4 = 1;
	TRISCbits.TRISC3 = 1;		// I2C SCL pin is input (will be controlled by SSP)
	TRISCbits.TRISC4 = 1;		// I2C SDA pin is input (will be controlled by SSP)

	// configure SSP for hardware master mode I2C
	SSPSTATbits.SMP = 1;		// I2C slew rate control disabled
	SSPCON1 = 0b00101000;
	SSPSTATbits.CKE = 1;		//Enable SMBus specific inputs
//	SSPCON1bits.SSPM3 = 1;		// I2C master mode in hardware
//	SSPCON1bits.SSPEN = 1;		// enable SSP module
					
	SSPADD = bitrate;			// set I2C clock rate to 100kHz

	PIR1bits.SSPIF = 0;			// remove any interrupt condition
}




void I2C_ProcessEvents(void)
{	

	// If a valid MSSP event has happened
	if (PIR1bits.SSPIF)
	{
		// Remove the interrupt condition
		PIR1bits.SSPIF = 0;

		// If in the send command only state
		if (_bI2CFlags.bits.tx_c)
		{
			if (!_bI2CFlags.bits.i2cif)
			{
				// If not started then start
				if (!_bI2CStates.bits.start)
				{
					SSPCON2bits.SEN = 1;		// Issue a start
					_bI2CStates.bits.start = 1;
				}
				else 
				
				// If the address has yet to be sent
				if (!_bI2CStates.bits.addr)
				{
					SSPBUF = _uI2CAddr;
					_bI2CStates.bits.addr = 1;
				}
				else
		
				// If the command has yet to be sent
				if (!_bI2CStates.bits.data1)
				{
					// If an acknowledge was received from previous state
					if (!SSPCON2bits.ACKSTAT)
					{
						SSPBUF = _uI2CCmd;
						_bI2CStates.bits.data1 = 1;
					}
					else
					{
						// Adjust the states back and restart
						_bI2CStates.bits.addr = 0;
						SSPCON2bits.RSEN = 1;
					}
				}
				else
		
				// If the stop has yet to be sent
				if (!_bI2CStates.bits.stop)
				{
					// If an acknowledge was received from previous state
					if (!SSPCON2bits.ACKSTAT)
					{
						// Issue a stop
						SSPCON2bits.PEN = 1;
						_bI2CStates.bits.stop = 1;
					}
					else
					{
						// Adjust the states back and restart
						_bI2CStates.bits.addr = 0;
						_bI2CStates.bits.data1 = 0;
						SSPCON2bits.RSEN = 1;
					}
				}
				else

				// Last state, remove busy and set soft int flag
				{
					_bI2CFlags.bits.i2cif = 1;
					_bI2CFlags.bits.busy = 0;
				}
			}
		}
	
		// else send a command and data
		else if (_bI2CFlags.bits.tx_cd)
		{
			if (!_bI2CFlags.bits.i2cif)
			{
				// If not started then start
				if (!_bI2CStates.bits.start)
				{
					SSPCON2bits.SEN = 1;		// Issue a start
					_bI2CStates.bits.start = 1;
				}
				else 
				
				// If the address has yet to be sent
				if (!_bI2CStates.bits.addr)
				{
					SSPBUF = _uI2CAddr;
					_bI2CStates.bits.addr = 1;
				}
				else
		
				// If the command has yet to be sent
				if (!_bI2CStates.bits.data1)
				{
					// If an acknowledge was received from previous state
					if (!SSPCON2bits.ACKSTAT)
					{
						SSPBUF = _uI2CCmd;
						_bI2CStates.bits.data1 = 1;
					}
					else
					{
						// Adjust the states back and restart
						_bI2CStates.bits.addr = 0;
						SSPCON2bits.RSEN = 1;
					}
				}
				else

				// If the command has yet to be sent
				if (!_bI2CStates.bits.data2)
				{
					// If an acknowledge was received from previous state
					if (!SSPCON2bits.ACKSTAT)
					{
						SSPBUF = _uI2CData;
						_bI2CStates.bits.data2 = 1;
					}
					else
					{
						// Adjust the states back and restart
						_bI2CStates.bits.addr = 0;
						_bI2CStates.bits.data1 = 0;
						SSPCON2bits.RSEN = 1;
					}
				}
				else
		
				// If the stop has yet to be sent
				if (!_bI2CStates.bits.stop)
				{
					// If an acknowledge was received from previous state
					if (!SSPCON2bits.ACKSTAT)
					{
						// Issue a stop
						SSPCON2bits.PEN = 1;
						_bI2CStates.bits.stop = 1;
					}
					else
					{
						// Adjust the states back and restart
						_bI2CStates.bits.addr = 0;
						_bI2CStates.bits.data1 = 0;
						_bI2CStates.bits.data2 = 0;
						SSPCON2bits.RSEN = 1;
					}
				}
				else

				// Last state, remove busy and set soft int flag
				{
					_bI2CFlags.bits.i2cif = 1;
					_bI2CFlags.bits.busy = 0;
				}
			}
		}

		// else receive a byte of data
		else if (_bI2CFlags.bits.rx_d)
		{
			if (!_bI2CFlags.bits.i2cif)
			{
				// If not started then start
				if (!_bI2CStates.bits.start)
				{
					SSPCON2bits.SEN = 1;			// Issue a start
					_bI2CStates.bits.start = 1;
				}
				else
				
				// If the address has yet to be sent
				if (!_bI2CStates.bits.addr)
				{
					SSPBUF = _uI2CAddr;				// Send the address
					_bI2CStates.bits.addr = 1;
				}
				else
		
				// If the data has yet to be sent
				if (!_bI2CStates.bits.data2)
				{

					// If an acknowledge was received from previous state
					if (!SSPCON2bits.ACKSTAT)
					{
						SSPCON2bits.RCEN = 1;		// Receive the data
						_bI2CStates.bits.data2 = 1;
					}
					else
					{
						// Adjust the states back and restart
						_bI2CStates.bits.addr = 0;	// else restart
						SSPCON2bits.RSEN = 1;
					}
				}
				else
		
				// If the ack has yet to be sent
				if (!_bI2CStates.bits.ack)
				{
					SSPCON2bits.RCEN = 0;			// Back to transmit mode and send NACK
					SSPCON2bits.ACKDT = 1;			//	; NACK
					SSPCON2bits.ACKEN = 1;			//	; send ACKDT bit
					_bI2CStates.bits.ack = 1;
				}
				else

				// If the stop has yet to be sent
				if (!_bI2CStates.bits.stop)
				{
					SSPCON2bits.PEN = 1;			// Issue a stop
					_bI2CStates.bits.stop = 1;
				}
				else

				{
					_uI2CData = SSPBUF;				// Copy the data
					_bI2CFlags.bits.i2cif = 1;
					_bI2CFlags.bits.busy = 0;
				}
			}
		}		
	}
}






void I2C_WriteCmd(UCHAR uI2CAddr, UCHAR uI2Cmd)
{
	_uI2CAddr = uI2CAddr & 0b11111110;
	_uI2CCmd = uI2Cmd;
//	_uI2CData = uI2CData;
	_bI2CStates.byte = 0;				// Reset all state flags
	_bI2CFlags.byte = 0;	
	_bI2CFlags.bits.busy = 1;			
	_bI2CFlags.bits.tx_c = 1;			// Indicate send command
	PIR1bits.SSPIF = 1;					// Start the first state
}

void I2C_WriteCmdAndData(UCHAR uI2CAddr, UCHAR uI2Cmd, UCHAR uI2CData)
{
	_uI2CAddr = uI2CAddr & 0b11111110;
	_uI2CCmd = uI2Cmd;
	_uI2CData = uI2CData;
	_bI2CStates.byte = 0;				// Reset all state flags
	_bI2CFlags.byte = 0;
	_bI2CFlags.bits.busy = 1;				
	_bI2CFlags.bits.tx_cd = 1;			// Indicate send command
	PIR1bits.SSPIF = 1;					// Start the first state
}



void I2C_ReadData(UCHAR uI2CAddr)
{
	_uI2CAddr = uI2CAddr | 0b00000001;
	_bI2CStates.byte = 0;
	_bI2CFlags.byte = 0;				// Reset all state flags
	_bI2CFlags.bits.busy = 1;
	_bI2CFlags.bits.rx_d = 1;			// Indicate read command 
	PIR1bits.SSPIF = 1;					// Start the first state
}


