/*********************************************************************
 *                  Flowcode CAL I2C File
 *
 * File: PIC_CAL_I2C.c
 *
 * (c) 2011 Matrix Multimedia Ltd.
 * http://www.matrixmultimedia.com
 *
 * Software License Agreement
 *
 * The software supplied herewith by Matrix Multimedia Ltd (the
 * “Company”) for its Flowcode graphical programming language is
 * intended and supplied to you, the Company’s customer, for use
 * solely and exclusively on the Company's products. The software
 * is owned by the Company, 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 licence.
 *
 * 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.
 *
 * Changelog:
 *
 *  date  | by | description
 * -------+----+-----------------------------------------------------
 * 210911 | BR | Created
 * 021211 | BR | Converted to new dynamic defines mechanism
 * 310512 | BR | Minor bug fix when using SW I2C on a device with no I2C peripheral
 * 120912 | BR | Minor bug fix to remove a bug with remappable I2C channel 2
 * 120912 | BR | Minor bug fix to remove a bug with register ssp2con
 * 090413 | LM | removed I2C HW port overrides, all come from CAL component for V6
 * 140613 | BR | Minor mod to error message to say not available or not supported
 * 020713 | LM | Standard API calls
 * 260914 | LM | Implemented Slave functionality
 */


#define MX_I2C_CHANNEL_X		CAL_APPEND(MX_I2C_CHANNEL_, MX_I2C_NUM)
#define MX_I2C_SDA_PIN_X		CAL_APPEND(MX_I2C_SDA_PIN_, MX_I2C_NUM)
#define MX_I2C_SDA_PORT_X		CAL_APPEND(MX_I2C_SDA_PORT_, MX_I2C_NUM)
#define MX_I2C_SDA_TRIS_X		CAL_APPEND(MX_I2C_SDA_TRIS_, MX_I2C_NUM)
#define MX_I2C_SCL_PIN_X		CAL_APPEND(MX_I2C_SCL_PIN_, MX_I2C_NUM)
#define MX_I2C_SCL_PORT_X		CAL_APPEND(MX_I2C_SCL_PORT_, MX_I2C_NUM)
#define MX_I2C_SCL_TRIS_X		CAL_APPEND(MX_I2C_SCL_TRIS_, MX_I2C_NUM)
#define MX_I2C_BMODE_X			CAL_APPEND(MX_I2C_BMODE_, MX_I2C_NUM)
#define MX_I2C_BAUD_X			CAL_APPEND(MX_I2C_BAUD_, MX_I2C_NUM)
#define MX_I2C_INT_X			CAL_APPEND(MX_I2C_INT_, MX_I2C_NUM)


//Function Prototypes
CALFUNCTION(void, FC_CAL_I2C_Master_Init_, (void));
CALFUNCTION(void, FC_CAL_I2C_Master_Uninit_, (void));
CALFUNCTION(void, FC_CAL_I2C_Master_Start_, (void));
CALFUNCTION(void, FC_CAL_I2C_Master_Restart_, (void));
CALFUNCTION(void, FC_CAL_I2C_Master_Stop_, (void));
CALFUNCTION(MX_UINT8, FC_CAL_I2C_Master_TxByte_, (MX_UINT8 Data));
CALFUNCTION(MX_UINT8, FC_CAL_I2C_Master_RxByte_, (MX_UINT8 Last));

CALFUNCTION(void, FC_CAL_I2C_Slave_Init_, (MX_UINT8 Address, MX_UINT8 Mask));
CALFUNCTION(void, FC_CAL_I2C_Slave_Uninit_, (void));
CALFUNCTION(MX_UINT8, FC_CAL_I2C_Slave_TxByte_, (MX_UINT8 Data));
CALFUNCTION(MX_UINT8, FC_CAL_I2C_Slave_RxByte_, (MX_UINT8 Last));
CALFUNCTION(MX_UINT8, FC_CAL_I2C_Slave_Status_, (void));


#if (MX_I2C_CHANNEL_X > 0)

	//Ensure SSPCON register is defined correctly
	#ifndef SSPCON
	  #ifdef SSPCON1
		#define sspcon	sspcon1
	  #else
		#ifdef SSP1CON1
			#define sspcon	ssp1con1
		#endif
	  #endif
	#endif

	//Ensure SSPIF register is defined correctly
	#ifndef SSPIF
	  #ifdef SSP1IF
		#define SSPIF	SSP1IF
	  #else
		#error "I2C does not have the SSPIF defined on this chip - does your chip support this feature?"
	  #endif
	#endif


	//Ensure SSPCON1 register is defined correctly
	#ifndef SSPCON1
	  #ifdef SSP1CON1
		#define sspcon1	ssp1con1
	  #endif
	#endif


	//Ensure SSPCON2 register is defined correctly
	#ifndef SSPCON2
	  #ifdef SSP1CON2
		#define sspcon2	ssp1con2
	  #endif
	#endif


	//Ensure SSPCON3 register is defined correctly
	#ifndef SSPCON3
	  #ifdef SSP1CON3
		#define sspcon3	ssp1con3
	  #endif
	#endif


	//Ensure SSPSTAT register is defined correctly
	#ifndef SSPSTAT
	  #ifdef SSP1STAT
		#define sspstat	ssp1stat
	  #endif
	#endif


	//Ensure SSPADD register is defined correctly
	#ifndef SSPADD
	  #ifdef SSP1ADD
		#define sspadd	ssp1add
	  #endif
	#endif


	//Ensure SSPBUFF register is defined correctly
	#ifndef SSPBUF
	  #ifdef SSP1BUF
		#define sspbuf	ssp1buf
	  #endif
	#endif


	//Ensure SSPMSK register is defined correctly
	#ifndef SSPMSK
	  #ifdef SSP1MSK
		#define sspmsk	ssp1msk
	  #endif
	#endif


	#if (MX_I2C_CHANNEL_X > 1)

		#ifndef SSP2CON
			#define ssp2con ssp2con1
		#endif

	#endif

#else

  #ifndef MX_I2C_SW_DEL
	#define MX_I2C_SW_DEL
	#define MX_I2C_SW_BAUD	((500000 / MX_I2C_BAUD_X)-1)

	#if (MX_I2C_SW_BAUD < 1)
		#define MX_I2C_DELAY	delay_us(1);
	#else
		#define MX_I2C_DELAY	delay_us(MX_I2C_SW_BAUD);
	#endif

  #endif

#endif


CALFUNCTION(void, FC_CAL_I2C_Master_Init_, (void))
{

	#if (MX_I2C_CHANNEL_X == 0)															//Use Master I2C Software
		FC_CAL_Bit_In_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);		//Configure SDA as Input
		FC_CAL_Bit_In_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);		//Configure SCL as Input
	#endif

	#if (MX_I2C_CHANNEL_X == 1)												//Use Master I2C Hardware 1
		#ifndef MX_MI2C
			#error "This chip does not have Master I2C capability or Flowcode does not currently support it"
		#else

			#ifndef MX_I2C_1
				#error "This chip does not have Master I2C channel 1"
			#endif

			#if (MX_I2C_BMODE_X & 0x01)
				cr_bit (sspstat,SMP);										//Slew Rate Control Enabled
			#else
				st_bit (sspstat,SMP);										//Slew Rate Control Disabled
		    #endif

			#if (MX_I2C_BMODE_X & 0x02)
				st_bit (sspstat,CKE);										//Enable SMBus specific inputs
			#else
				cr_bit (sspstat,CKE);										//Disable SMBus specific inputs
			#endif

			sspcon = 0x28;													//Setup I2C into Master Mode
			sspadd = ((MX_CLK_SPEED / 4)/ MX_I2C_BAUD_X) - 1;				//Set the Baud Rate
			sspcon2 = 0x00;													//Clear the control bits
			st_bit(intcon, GIE);
			FC_CAL_Bit_In_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);		//Configure SDA as Input
			FC_CAL_Bit_In_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);		//Configure SCL as Input
		#endif
	#endif

	#if (MX_I2C_CHANNEL_X == 2)												//Use Master I2C Hardware 2
		#ifndef MX_MI2C
			#error "This chip does not have Master I2C capability or Flowcode does not currently support it"
		#else

			#ifndef MX_I2C_2
				#error "This chip does not have Master I2C channel 2"
			#endif

			#if (MX_I2C_BMODE_X & 0x01)
				cr_bit (ssp2stat,SMP);										//Slew Rate Control Enabled
			#else
				st_bit (ssp2stat,SMP);										//Slew Rate Control Disabled
			#endif

			#if (MX_I2C_BMODE_X & 0x02)
				st_bit (ssp2stat,CKE);										//Enable SMBus specific inputs
			#else
				cr_bit (ssp2stat,CKE);										//Disable SMBus specific inputs
			#endif

			ssp2con = 0x28;													//Setup I2C into Master Mode
			ssp2add = ((MX_CLK_SPEED / 4)/ MX_I2C_BAUD_X) - 1;				//Set the Baud Rate
			ssp2con2 = 0x00;												//Clear the control bits
			st_bit(intcon, GIE);
			FC_CAL_Bit_In_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);			//Configure SDA as Input
			FC_CAL_Bit_In_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);			//Configure SCL as Input
		#endif
	#endif
}

CALFUNCTION(void, FC_CAL_I2C_Master_Uninit_, (void))
{
	#if (MX_I2C_CHANNEL_X == 0)																//Use Master I2C Software
		FC_CAL_Bit_In_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);			//Configure SDA as Input
		FC_CAL_Bit_In_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);			//Configure SCL as Input
	#endif

	#if (MX_I2C_CHANNEL_X == 1)												//Use Master I2C Hardware 1
		cr_bit(sspcon, SSPEN);												//Disable SSP
	#endif

	#if (MX_I2C_CHANNEL_X == 2)												//Use Master I2C Hardware 2
		cr_bit(ssp2con, SSPEN);												//Disable SSP
	#endif
}

CALFUNCTION(void, FC_CAL_I2C_Master_Start_, (void))
{
	#if (MX_I2C_CHANNEL_X == 0)															//Use Master I2C Software
		FC_CAL_Bit_In_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);		//Make Sure SCL is Set
		FC_CAL_Bit_In_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);		//Make Sure SDA is Set
		MX_I2C_DELAY;																	//Small Delay
		FC_CAL_Bit_Low_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);		//Clear SDA
		MX_I2C_DELAY;																	//Small Delay
		FC_CAL_Bit_Low_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);		//Clear SCL
		//MX_I2C_DELAY;																	//Small Delay //Removed 050613 - BR
	#endif

	#if (MX_I2C_CHANNEL_X == 1)												//Use Master I2C Hardware 1
		cr_bit(pir1, SSPIF);												//Clear SSP interrupt flag
		st_bit(sspcon2,SEN);												//Initiate start condition
		while(ts_bit(sspcon2,SEN));											//Wait for start bit to be generated
	#endif

	#if (MX_I2C_CHANNEL_X == 2)												//Use Master I2C Hardware 2
		cr_bit(pir3, SSP2IF);												//Clear SSP interrupt flag
		st_bit(ssp2con2,SEN);												//Initiate start condition
		while(ts_bit(ssp2con2,SEN));										//Wait for start bit to be generated
	#endif
}

CALFUNCTION(void, FC_CAL_I2C_Master_Restart_, (void))
{
	#if (MX_I2C_CHANNEL_X == 0)															//Use Master I2C Software
		FC_CAL_Bit_In_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);		//Set SDA High
		MX_I2C_DELAY;
		FC_CAL_Bit_In_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);		//Set SCL High
		MX_I2C_DELAY;
		FC_CAL_Bit_Low_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);		//Set SDA Low
		MX_I2C_DELAY;
		FC_CAL_Bit_Low_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);		//Set SCL Low
		//MX_I2C_DELAY;																	//Removed 050613 - BR
	#endif

	#if (MX_I2C_CHANNEL_X == 1)												//Use Master I2C Hardware 1
		cr_bit(pir1, SSPIF);												//Clear SSP interrupt flag
		st_bit(sspcon2,RSEN);												//Initiate restart condition
		while(ts_bit(sspcon2,RSEN));										//Wait for restart bit to be generated
	#endif

	#if (MX_I2C_CHANNEL_X == 2)												//Use Master I2C Hardware 2
		cr_bit(pir3, SSP2IF);												//Clear SSP interrupt flag
		st_bit(ssp2con2,RSEN);												//Initiate restart condition
		while(ts_bit(ssp2con2,RSEN));										//Wait for restart bit to be generated
	#endif
}

CALFUNCTION(void, FC_CAL_I2C_Master_Stop_, (void))
{
	#if (MX_I2C_CHANNEL_X == 0)															//Use Master I2C Software
		FC_CAL_Bit_Low_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);		//Set SCL Low
		FC_CAL_Bit_Low_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);		//Set SDA Low
		MX_I2C_DELAY;
		FC_CAL_Bit_In_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);		//Set SCL High
		MX_I2C_DELAY;
		FC_CAL_Bit_In_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);		//Set SDA High
	#endif

	#if (MX_I2C_CHANNEL_X == 1)												//Use Master I2C Hardware 1
		cr_bit(pir1,SSPIF);													//Clear SSP interrupt flag
		st_bit(sspcon2,PEN);												//Initiate stop condition
		while(ts_bit(sspcon2,PEN));											//Wait for stop bit to be generated

  		delay_ms(10);														//Wait before reusing the I2C BUS -  avoids lockup problem exibited on some PICs
	#endif

	#if (MX_I2C_CHANNEL_X == 2)												//Use Master I2C Hardware 2
		cr_bit(pir3,SSP2IF);												//Clear SSP interrupt flag
		st_bit(ssp2con2,PEN);												//Initiate stop condition
		while(ts_bit(ssp2con2,PEN));										//Wait for stop bit to be generated

		delay_ms(10);														//Wait before reusing the I2C BUS -  avoids lockup problem exibited on some PICs
	#endif
}

CALFUNCTION(MX_UINT8, FC_CAL_I2C_Master_TxByte_, (MX_UINT8 Data))
{
	#if (MX_I2C_CHANNEL_X == 0)												//Use Master I2C Software
		char bit_mask;
		char local_ack = 0;
		for(bit_mask=0x80;bit_mask;bit_mask=bit_mask>>1)
		{
			if(Data & bit_mask)
			{
				FC_CAL_Bit_In_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);	//Set SDA High
			}
			else
			{
				FC_CAL_Bit_Low_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);	//Set SDA Low
			}
			MX_I2C_DELAY;
			FC_CAL_Bit_In_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);		//Set SCL High
			MX_I2C_DELAY;
			FC_CAL_Bit_Low_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);		//Set SCL Low
			//MX_I2C_DELAY;																	//Removed 050613 - BR
		}
		FC_CAL_Bit_In_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);			//Set SDA High
		MX_I2C_DELAY;
		FC_CAL_Bit_In_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);			//Set SCL High
		MX_I2C_DELAY;
		FC_CAL_Bit_In_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);
		if (FC_CAL_Bit_In(MX_I2C_SDA_PORT_X, MX_I2C_SDA_PIN_X))		//Get the Status Bit
			local_ack = 1;
		//MX_I2C_DELAY;																	//Small Delay //Removed 050613 - BR
		FC_CAL_Bit_Low_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);			//Set SCL Low
		//MX_I2C_DELAY;																		//Removed 050613 - BR
		return (local_ack);													//0 = Ack received : 1 = Ack not received
	#endif

	#if (MX_I2C_CHANNEL_X == 1)												//Use Master I2C Hardware 1
		cr_bit(pir1,SSPIF);													//Clear SSP interrupt flag
		sspbuf=Data;														//Send byte
		while(ts_bit(pir1,SSPIF) == 0);										//Wait for control bit to be sent
		if(ts_bit(sspcon2,ACKSTAT))											//Check Acknowledgement
			return (1);														//No Acknowledgement
		else return (0);													//Acknowledgement received
	#endif

	#if (MX_I2C_CHANNEL_X == 2)												//Use Master I2C Hardware 2
		cr_bit(pir3,SSP2IF);												//Clear SSP interrupt flag
		ssp2buf=Data;														//Send byte
		while(ts_bit(pir3,SSP2IF) == 0);									//Wait for control bit to be sent
		if(ts_bit(ssp2con2,ACKSTAT))										//Check Acknowledgement
			return (1);														//No Acknowledgement
		else return (0);													//Acknowledgement received
	#endif
}

CALFUNCTION(MX_UINT8, FC_CAL_I2C_Master_RxByte_, (MX_UINT8 Last))
{
	#if (MX_I2C_CHANNEL_X == 0)												//Use Master I2C Software
		char bit_mask;
		char Data = 0;
		char local_ack;
		FC_CAL_Bit_In_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);			//Set SDA High
		MX_I2C_DELAY;
		for(bit_mask=0x80;bit_mask;bit_mask=bit_mask>>1)
		{
			FC_CAL_Bit_In_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);		//Set SCL High
			MX_I2C_DELAY;
			FC_CAL_Bit_In_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);
			if(FC_CAL_Bit_In(MX_I2C_SDA_PORT_X, MX_I2C_SDA_PIN_X))	//Read Incoming Bit
				Data = Data | bit_mask;														//Add data to variable
			FC_CAL_Bit_Low_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);		//Set SCL Low
			MX_I2C_DELAY;																	//Small Delay
		}
		if (Last)																		//Acknowledge?
		{
			FC_CAL_Bit_In_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);	//Send Nack
		}
		else
		{
			FC_CAL_Bit_Low_DDR(MX_I2C_SDA_PORT_X, MX_I2C_SDA_TRIS_X, MX_I2C_SDA_PIN_X);	//Send Ack
		}
		MX_I2C_DELAY;
		FC_CAL_Bit_In_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);		//Set SCL High
		MX_I2C_DELAY;
		FC_CAL_Bit_Low_DDR(MX_I2C_SCL_PORT_X, MX_I2C_SCL_TRIS_X, MX_I2C_SCL_PIN_X);		//Set SCL Low
		//MX_I2C_DELAY;																	//Removed 050613 - BR
		return (Data);
	#endif

	#if (MX_I2C_CHANNEL_X == 1)						//Use Master I2C Hardware 1
		cr_bit(pir1,SSPIF);							//Clear SSP interrupt flag
		st_bit(sspcon2,RCEN);						//Initiate Read
		while(ts_bit(pir1,3) == 0);					//Wait for data read
		if (Last)
			st_bit(sspcon2,ACKDT);					//Send Nack
		else cr_bit(sspcon2,ACKDT);					//Send Ack
		st_bit(sspcon2,ACKEN);						//Initiate Nack
		while(ts_bit(sspcon2,ACKEN));				//Wait for data read
		return(sspbuf);								//Store incoming data
	#endif

	#if (MX_I2C_CHANNEL_X == 2)						//Use Master I2C Hardware 2
		cr_bit(pir3,SSP2IF);						//Clear SSP interrupt flag
		st_bit(ssp2con2,RCEN);						//Initiate Read
		while(ts_bit(pir3,SSP2IF) == 0);			//Wait for data read
		if (Last)
			st_bit(ssp2con2,ACKDT);					//Send Nack
		else cr_bit(ssp2con2,ACKDT);				//Send Ack
		st_bit(ssp2con2,ACKEN);						//Initiate Nack
		while(ts_bit(ssp2con2,ACKEN));				//Wait for data read
		return(ssp2buf);							//Store incoming data
	#endif
}



/*********************************************
Slave functions, only support 7 bit addressing
*********************************************/

CALFUNCTION(void, FC_CAL_I2C_Slave_Init_, (MX_UINT8 Address, MX_UINT8 Mask))
{
	#if (MX_I2C_CHANNEL_X == 1)
		#if (MX_I2C_BMODE_X & 0x01)
			cr_bit(sspstat, SMP);	// Slew Rate Control Enabled
		#else
			st_bit(sspstat, SMP);	// Slew Rate Control Disabled
	    #endif
		sspcon = 0x36;				// SSPEN=1, CKP=1, SSPM<3:0>=0110  = I2C Slave mode, 7-bit address
		sspcon2 = 1;				// SEN=1 Clock stretching is enabled
		#ifdef SSPCON3
			sspcon3 = 3;			// set AHEN and DHEN
		#endif
		#ifdef SSPMSK
			sspmsk = Mask;
		#endif
		sspadd = Address;
	#endif
	#if (MX_I2C_CHANNEL_X == 2)
		#if (MX_I2C_BMODE_X & 0x01)
			cr_bit(ssp2stat, SMP);	// Slew Rate Control Enabled
		#else
			st_bit(ssp2stat, SMP);	// Slew Rate Control Disabled
	    #endif
		ssp2con1 = 0x36;			// SSPEN=1, CKP=1, SSPM<3:0>=0110  = I2C Slave mode, 7-bit address
		ssp2con2 = 1;				// SEN=1 Clock stretching is enabled
		#ifdef SSPCON3
			ssp2con3 = 3;			// set AHEN and DHEN
		#endif
		#ifdef SSPMSK
			ssp2msk = Mask;
		#endif
		ssp2add = Address;
	#endif
}

// Returns I2C status byte (SSPSTAT = SMP CKE D/A P S R/W UA BF)
// Bit 0 = 1 Indicates address/data byte available in the buffer to read
// Bit 5 = 1 Indicates that the last byte received or transmitted was data (else address)
CALFUNCTION(MX_UINT8, FC_CAL_I2C_Slave_Status_, (void))
{
	#if (MX_I2C_CHANNEL_X == 1)
		return sspstat;
	#endif
	#if (MX_I2C_CHANNEL_X == 2)
		return ssp2stat;
	#endif
}

// Disables the I2C peripheral
CALFUNCTION(void, FC_CAL_I2C_Slave_Uninit_, (void))
{
	#if (MX_I2C_CHANNEL_X == 1)
			cr_bit(sspcon, SSPEN);
	#endif
	#if (MX_I2C_CHANNEL_X == 2)
			cr_bit(ssp2con1, SSPEN);
	#endif
}

// Loads the Data byte into the shift buffer and releases SCL ready for sending
// Returns Master Ack/Nak (0=Ack=More, 1=Nak=Last)
CALFUNCTION(MX_UINT8, FC_CAL_I2C_Slave_TxByte_, (MX_UINT8 Data))
{
	#if (MX_I2C_CHANNEL_X == 1)
		cr_bit(pir1, SSPIF);					// clear SSPIF
		sspbuf = Data;							// load the data to send
		st_bit(sspcon, CKP);					// release SCL
		while (ts_bit(pir1, SSPIF)==0);			// wait for SSPIF to go high before we read the Ack
		cr_bit(pir1, SSPIF);					// clear SSPIF
		return ts_bit(sspcon2, ACKSTAT)?1:0;	// return ACKSTAT
	#endif
	#if (MX_I2C_CHANNEL_X == 2)
		cr_bit(pir3, SSP2IF);					// clear SSPIF
		ssp2buf = Data;							// load the data to send
		st_bit(ssp2con1, CKP);					// release SCL
		while (ts_bit(pir3, SSP2IF)==0);		// wait for SSPIF to go high before we read the Ack
		cr_bit(pir3, SSP2IF);					// clear SSPIF
		return ts_bit(ssp2con2, ACKSTAT)?1:0;	// return ACKSTAT
	#endif
}

// Returns the byte from the shift buffer
// and sends Ack or Nak (0=Ack=More, 1=Nak=Last)
// nb. First check FC_CAL_I2C_Slave_Status() & 1
CALFUNCTION(MX_UINT8, FC_CAL_I2C_Slave_RxByte_, (MX_UINT8 Last))
{
	#if (MX_I2C_CHANNEL_X == 1)
		MX_UINT8 Data;
		Data = sspbuf;
		if (ts_bit(sspstat, 2))		//Was R_NOT_W but caused compile errors on 877A
		{
			#ifdef SSPCON3
				// It's a read from Slave by Master
				if (ts_bit(sspcon3, AHEN))
				{
					Last ? st_bit(sspcon2, ACKDT) : cr_bit(sspcon2, ACKDT);	// Ack or Nak
					st_bit(sspcon1, CKP);									// release SCL
					while (ts_bit(sspcon1, CKP));							// wait for CKP to go low again indicating that the Ack has been sent
				}
			#endif
		}
		else
		{
			// It's a write from Master to Slave
			Last ? st_bit(sspcon2, ACKDT) : cr_bit(sspcon2, ACKDT);	// Ack or Nak
			st_bit(sspcon, CKP);									// release SCL
			if (0 == Last)
			{
				while (ts_bit(sspcon, CKP));						// wait for CKP to go low again indicating that the Ack has been sent
				st_bit(sspcon, CKP);								// release SCL (again)
			}
		}
		return Data;			// return the received data
	#endif
	#if (MX_I2C_CHANNEL_X == 2)
		MX_UINT8 Data;
		Data = ssp2buf;
		if (ts_bit(ssp2stat, R_NOT_W))
		{
			// It's a read from Slave by Master
			if (ts_bit(ssp2con3, AHEN))
			{
				Last ? st_bit(ssp2con2, ACKDT) : cr_bit(ssp2con2, ACKDT);	// Ack or Nak
				st_bit(ssp2con1, CKP);									// release SCL
				while (ts_bit(ssp2con1, CKP));							// wait for CKP to go low again indicating that the Ack has been sent
			}
		}
		else
		{
			// It's a write from Master to Slave
			Last ? st_bit(ssp2con2, ACKDT) : cr_bit(ssp2con2, ACKDT);	// Ack or Nak
			st_bit(ssp2con1, CKP);									// release SCL
			if (0 == Last)
			{
				while (ts_bit(ssp2con1, CKP));						// wait for CKP to go low again indicating that the Ack has been sent
				st_bit(ssp2con1, CKP);								// release SCL (again)
			}
		}
		return Data;			// return the received data
	#endif
}



