
/***********************************************************************************************
*
*					Instituto Tecnologico de Costa Rica	
*					 Escuela de Ingenieria Electronica
*				
*
*					Archivo de Funciones de I2C (1 y 2)
*
*
*	Archivo: 		io_i2c.c
*	Programador: 	Daniel Castro Molina
*
*	Version:		1.0		Diciembre/2007
*	
************************************************************************************************/

/*
***********************************************************************************************
*					Configuracion del puerto I2C 1
*
*	Direccion de memoria base: 0x0400
*
*
***********************************************************************************************
*/
      
#define I2C1_EN_PERIPH		1		/* IO_Config[0.0]: Habilita el modulo I2C1 */
#define I2C1_IPMIEN			0		/* IO_Config[0.1]: Intelligent Peripheral Management Ack, 0: Dis, 1: Ena */
#define I2C1_A10M			0		/* IO_Config[0.2]: 10 bit Slave Add bit, 0: Dis, 1: Ena */
#define I2C1_DISSLW			0		/* IO_Config[0.3]: Slew rate, 0: Dis, 1: En */
#define I2C1_SMEN			0		/* IO_Config[0.4]: SMBus input levels bit, 0: Dis, 1: Ena */
#define I2C1_GCEN			0		/* IO_Config[0.5]: General Call, 0: Dis, 1: Ena */
#define I2C1_FCLK			100		/* IO_Config[0.7-6]:IO_Config[1] */
									/* Serial Clock Rate, in kHz */

/*
***********************************************************************************************
*					Configuracion del puerto I2C 2
*
*	Direccion de memoria base: 0x0410
*
***********************************************************************************************
*/

#define I2C2_EN_PERIPH		1		/* Habilita el modulo I2C1 */
#define I2C2_IPMIEN			0		/* Intelligent Peripheral Management Ack, 0: Dis, 1: Ena */
#define I2C2_A10M			0		/* 10 bit Slave Add bit, 0: Dis, 1: Ena */
#define I2C2_DISSLW			0		/* Slew rate, 0: Dis, 1: En */
#define I2C2_SMEN			0		/* SMBus input levels bit, 0: Dis, 1: Ena */
#define I2C2_GCEN			1		/* General Call, 0: Dis, 1: Ena */
#define I2C2_FCLK			100		/* Serial Clock Rate, in kHz */




#include <includes.h>

extern	OS_EVENT*		I2C1_Sem;		// Semaforo I2C1
extern	OS_EVENT*		I2C2_Sem;		// Semaforo I2C2

extern INT8U Slave_Buffer[];

extern INT8U IO_Config_I2C1[];
extern INT8U IO_Config_I2C2[];

INT16U dir;


/*
*********************************************************************************************************
*
*				Rutina de configuracion del modulo I2C 1
*
*	
*	Utilize el archivo IO_CFG.H para cambiar la configuracion
*
*********************************************************************************************************
*/
									/* Serial Clock Rate, in kHz */
void IO_I2Cconfig_dflt( void )
{
	
	IO_Config_I2C1[0] = I2C1_EN_PERIPH;
	IO_Config_I2C1[0] += I2C1_IPMIEN * 2;
	IO_Config_I2C1[0] += I2C1_A10M * 4;
	IO_Config_I2C1[0] += I2C1_DISSLW * 8;
	IO_Config_I2C1[0] += I2C1_SMEN * 16;
	IO_Config_I2C1[0] += I2C1_GCEN * 32;
	IO_Config_I2C1[0] += ( I2C1_FCLK / 4 ) & 0xC0;
	IO_Config_I2C1[1] =  I2C1_FCLK - ( IO_Config_I2C1[0] >> 6 )*256;

	IO_Config_I2C2[0] = I2C2_EN_PERIPH;
	IO_Config_I2C2[0] += I2C2_IPMIEN * 2;
	IO_Config_I2C2[0] += I2C2_A10M * 4;
	IO_Config_I2C2[0] += I2C2_DISSLW * 8;
	IO_Config_I2C2[0] += I2C2_SMEN * 16;
	IO_Config_I2C2[0] += I2C2_GCEN * 32;
	IO_Config_I2C2[0] += ( I2C2_FCLK / 4 ) & 0xC0;
	IO_Config_I2C2[1] =  I2C2_FCLK - ( IO_Config_I2C2[0] >> 6 )*256;

	IO_I2Cconfig( );
}
					
void IO_I2Cconfig( void )
{
	
	INT16U clock_rate = (IO_Config_I2C1[0] >> 6)*256 + IO_Config_I2C1[1];
	
	#if ( pin_RG2 != 0 )
	#error "I2C1: EL pin RG2/SCL1 no esta configurado como salida "
	#endif
	
	ODCGbits.ODCG2 = 1;
	ODCGbits.ODCG3 = 1;
	
	I2C1CON = 0x0000;

	I2C1CONbits.IPMIEN = IO_Config_I2C1[0] >> 1;
	I2C1CONbits.A10M = IO_Config_I2C1[0] >> 2;
	I2C1CONbits.DISSLW = !(IO_Config_I2C1[0] >> 3);
	I2C1CONbits.SMEN = IO_Config_I2C1[0] >> 4;
	I2C1CONbits.GCEN = IO_Config_I2C1[0] >> 5;
	I2C1CONbits.STREN = 0;
	
	I2C1BRG = ((CPU_MIPS * 1000) / clock_rate) - (CPU_MIPS/10) - 1;
	
	I2C1RCV = 0x0000;
	I2C1TRN = 0x0000;
		
	I2C1CONbits.I2CEN = IO_Config_I2C1[0];

	
	clock_rate = (IO_Config_I2C2[0] >> 6)*256 + IO_Config_I2C2[1];
	
	#if ( pin_RA2 != 0 )
	#error "I2C2: EL pin RA2/SCL2 no esta configurado como salida "
	#endif
	
	ODCAbits.ODCA2 = 1;
	ODCAbits.ODCA3 = 1;
	
	I2C2CON = 0x0000;

	I2C2CONbits.IPMIEN = IO_Config_I2C2[0] >> 1;
	I2C2CONbits.A10M = IO_Config_I2C2[0] >> 2;
	I2C2CONbits.DISSLW = !(IO_Config_I2C2[0] >> 3);
	I2C2CONbits.SMEN = IO_Config_I2C2[0] >> 4;
	I2C2CONbits.GCEN = IO_Config_I2C2[0] >> 5;
	I2C2CONbits.STREN = 0;
	
	I2C2BRG = ((CPU_MIPS * 1000) / clock_rate) - (CPU_MIPS/10) - 1;
	
	I2C2ADD = I2C_MAC >> 1;
	
	I2C2RCV = 0x0000;
	I2C2TRN = 0x0000;
		
	I2C2CONbits.I2CEN = IO_Config_I2C2[0];


	IFS3bits.SI2C2IF = 0;
	IEC3bits.SI2C2IE = IO_Config_I2C2[0];

}


/*********************************************************************
* Function:		IO_I2C1Read()
*
* Input:		add 	-> direccion de dispositivo, 
*				*rdptr 	-> puntero del buffer de datos leidos
*				length	-> cantidad de datos
*
* Output:		None.
*
* Overview:		Realiza una lectura secuencial de datos
*
* Note:			None
********************************************************************/

unsigned int IO_I2C1read(INT8U add, INT8U *rdptr, INT8U length)
{
	
	INT8U err;
	OSSemPend( I2C1_Sem, 0, &err );
	
	IdleI2C1();						//Ensure Module is Idle
	StartI2C1();					//Initiate start condition
	WriteI2C1( add | 0x01 );		//write 1 byte
	IdleI2C1();						//Ensure module is Idle

	getsI2C1(rdptr, length);		//Read in multiple bytes

	NotAckI2C1();					//Send Not Ack
	StopI2C1();						//Send stop condition
	
	err = OSSemPost( I2C1_Sem );
	
	return(0);
}

/*********************************************************************
* Function:		IO_I2C1Write()
*
* Input:		add 	-> direccion de dispositivo, 
*				*rdptr 	-> puntero del buffer de datos a escribir
*				length	-> cantidad de datos
*
* Output:		None.
*
* Overview:		Realiza una escritura secuencial de datos
*
* Note:			None
********************************************************************/

unsigned int IO_I2C1write(unsigned char add, unsigned char *wrptr, unsigned char length)
{

	INT8U err;
	OSSemPend( I2C1_Sem, 0, &err );

	IdleI2C1();				//wait for bus Idle
	StartI2C1();				//Generate Start condition
	WriteI2C1( add & 0xFE );	//send controlbyte for a write
	IdleI2C1();				//wait for bus Idle

	putsI2C1(wrptr, length);	//Send data

	IdleI2C1();				//wait for bus Idle
	StopI2C1();				//Generate a stop

	err = OSSemPost( I2C1_Sem );

	return(0);
}

/*********************************************************************
* Function:        IO_I2C1PageHDRead
*
* Input:		add 	-> direccion de dispositivo,
*				dir		-> direccion de memoria ( 16 bits )
*				*rdptr 	-> puntero del buffer de datos leidos
*				length	-> cantidad de datos
*
* Output:		None.
*
* Overview:		Realiza una lectura secuencial de datos a un area de memoria especifico
*
* Note:			None
********************************************************************/

unsigned int IO_I2C1pageHDread(unsigned char add, unsigned int dir, unsigned char *rdptr, unsigned char length)
{
	
	INT8U err, i2c_err;
	INT8U retry = 4;
	
	OSSemPend( I2C1_Sem, 0, &err );
	
	do{
	
		i2c_err = 0;
		
		IdleI2C1();												//wait for bus Idle
		StartI2C1();											//Generate Start condition
	
		if( WriteI2C1( add & 0xFE ) != 0 ) i2c_err++;			//send device address for a write
	
		IdleI2C1();												//wait for bus Idle
	
		if( WriteI2C1( (dir >> 8) & 0x00FF ) != 0 )	i2c_err++;					//send memory address 	
	
		IdleI2C1();												//wait for bus Idle
	
		if( WriteI2C1( ( dir ) & 0x00FF   ) != 0 ) i2c_err++;					//send memory address 	
	
		IdleI2C1();	
	
		RestartI2C1();											//Generate I2C Restart Condition
	
		if( WriteI2C1( add | 0x01 ) != 0 ) i2c_err++;			//send memory address ( READ )	
	
		IdleI2C1();												//wait for bus Idle
	
		getsI2C1(rdptr, length);			//Read in multiple bytes
		NotAckI2C1();					//send Not Ack
	
		StopI2C1();				//Generate a stop

	}
	while( i2c_err & retry );
	
	err = OSSemPost( I2C1_Sem );

	if( retry ) return 0;
	else return 1;

}

/*********************************************************************
* Function:        IO_I2C1PageLDRead
*
* Input:		add 	-> direccion de dispositivo,
*				dir		-> direccion de memoria ( 8 bits )
*				*rdptr 	-> puntero del buffer de datos leidos
*				length	-> cantidad de datos
*
* Output:		None.
*
* Overview:		Realiza una lectura secuencial de datos a un area de memoria especifico
*
* Note:			None
********************************************************************/

unsigned int IO_I2C1pageLDread(unsigned char add, unsigned char dir, unsigned char *rdptr, unsigned char length)
{
	
	INT8U err, i2c_err;
	INT8U retry = 4;
	
	OSSemPend( I2C1_Sem, 0, &err );
	
	do{
		
		i2c_err = 0;
		
		IdleI2C1();												//wait for bus Idle
		StartI2C1();											//Generate Start condition
	
		if( WriteI2C1( add & 0xFE ) != 0 ) i2c_err++;			//send device address for a write
	
		IdleI2C1();												//wait for bus Idle
	
		if( WriteI2C1( dir ) != 0 ) i2c_err++;					//send memory address 	
	
		IdleI2C1();												//wait for bus Idle
	
		RestartI2C1();											//Generate I2C Restart Condition
	
		if( WriteI2C1( add | 0x01 ) != 0 ) i2c_err++;			//send memory address ( READ )	
	
		IdleI2C1();												//wait for bus Idle
	
		getsI2C1(rdptr, length);			//Read in multiple bytes
		NotAckI2C1();					//send Not Ack
	
		StopI2C1();				//Generate a stop

	}
	while( i2c_err & retry );
	
	err = OSSemPost( I2C1_Sem );

	if( retry ) return 0;
	else return 1;

}

/*********************************************************************
* Function:        IO_I2C1PageHDWrite
*
* Input:		add 	-> direccion de dispositivo,
*				dir		-> direccion de memoria ( 16 bits )
*				*rdptr 	-> puntero del buffer de datos a escribir
*				length	-> cantidad de datos
*
* Output:		None.
*
* Overview:		Realiza una escritura secuencial de datos a un area de memoria especifico
*
* Note:			None
********************************************************************/

unsigned int IO_I2C1pageHDwrite(unsigned char add, unsigned int dir, unsigned char *wrptr, unsigned char length)
{
	
	INT8U err, i2c_err;
	INT8U retry = 4;
	
	OSSemPend( I2C1_Sem, 0, &err );
	
	do{
	
		i2c_err = 0;
		
		IdleI2C1();												//wait for bus Idle
		StartI2C1();											//Generate Start condition
		
		if( WriteI2C1( add & 0xFE ) != 0 ) i2c_err++;			//send device address for a write
	
		IdleI2C1();												//wait for bus Idle
	
		if( WriteI2C1( (dir >> 8) & 0x00FF ) != 0 )	i2c_err++;	//send device address for a write
	
		IdleI2C1();												//wait for bus Idle
	
		if( WriteI2C1( ( dir ) & 0x00FF  ) != 0 ) i2c_err++;	//send device address for a write
	
		IdleI2C1();	
	
		if( putsI2C1( wrptr, length ) != 0 ) i2c_err++;	//Send data
	
		IdleI2C1();												//wait for bus Idle
		StopI2C1();												//Generate a stop
	}
	while( i2c_err & retry );

	err = OSSemPost( I2C1_Sem );
	
	if( retry ) return 0;
	else return 1;

}

/*********************************************************************
* Function:        IO_I2C1PageLDWrite
*
* Input:		add 	-> direccion de dispositivo,
*				dir		-> direccion de memoria ( 8 bits )
*				*rdptr 	-> puntero del buffer de datos a escribir
*				length	-> cantidad de datos
*
* Output:		None.
*
* Overview:		Realiza una escritura secuencial de datos a un area de memoria especifico
*
* Note:			None
********************************************************************/

unsigned int IO_I2C1pageLDwrite(unsigned char add, unsigned char dir, unsigned char *wrptr, unsigned char length)
{
	
	INT8U err, i2c_err;
	INT8U retry;
	
	OSSemPend( I2C1_Sem, 0, &err );
	
	retry = 4;

	do{
		
		i2c_err = 0;
		
		IdleI2C1();												//wait for bus Idle
		StartI2C1();											//Generate Start condition
	
		if( WriteI2C1( add & 0xFE ) != 0 ) i2c_err++;			//send device address for a write
	
		IdleI2C1();												//wait for bus Idle
		
		if( WriteI2C1( dir ) != 0 )	i2c_err++;					//send memory address 	
	
		IdleI2C1();												//wait for bus Idle
	
		if( putsI2C1( wrptr, length ) != 0 ) i2c_err++;	//Send data
	
		IdleI2C1();												//wait for bus Idle
		StopI2C1();												//Generate a stop
	
	}
	while( i2c_err & retry );
	
	err = OSSemPost( I2C1_Sem );
	
	if( retry ) return 0;
	else return 1;
	
}














/*********************************************************************
* Function:		IO_I2C2Read()
*
* Input:		add 	-> direccion de dispositivo, 
*				*rdptr 	-> puntero del buffer de datos leidos
*				length	-> cantidad de datos
*
* Output:		None.
*
* Overview:		Realiza una lectura secuencial de datos
*
* Note:			None
********************************************************************/

unsigned int IO_I2C2read(unsigned char add, unsigned char *rdptr, unsigned char length)
{
	
	INT8U err;
	OSSemPend( I2C2_Sem, 0, &err );
	
	IdleI2C2();						//Ensure Module is Idle
	StartI2C2();					//Initiate start condition
	WriteI2C2( add | 0x01 );		//write 1 byte
	IdleI2C2();						//Ensure module is Idle

	getsI2C2(rdptr, length);		//Read in multiple bytes

	NotAckI2C2();					//Send Not Ack
	StopI2C2();						//Send stop condition
	
	err = OSSemPost( I2C2_Sem );
	
	return(0);
}

/*********************************************************************
* Function:		IO_I2C2Write()
*
* Input:		add 	-> direccion de dispositivo, 
*				*rdptr 	-> puntero del buffer de datos a escribir
*				length	-> cantidad de datos
*
* Output:		None.
*
* Overview:		Realiza una escritura secuencial de datos
*
* Note:			None
********************************************************************/

unsigned int IO_I2C2write(unsigned char add, unsigned char *wrptr, unsigned char length)
{

	INT8U err;
	OSSemPend( I2C2_Sem, 0, &err );

	IdleI2C2();				//wait for bus Idle
	StartI2C2();				//Generate Start condition
	WriteI2C2( add & 0xFE );	//send controlbyte for a write
	IdleI2C2();				//wait for bus Idle

	putsI2C2(wrptr, length);	//Send data

	IdleI2C2();				//wait for bus Idle
	StopI2C2();				//Generate a stop

	err = OSSemPost( I2C2_Sem );

	return(0);
}

/*********************************************************************
* Function:        IO_I2C2PageHDRead
*
* Input:		add 	-> direccion de dispositivo,
*				dir		-> direccion de memoria ( 16 bits )
*				*rdptr 	-> puntero del buffer de datos leidos
*				length	-> cantidad de datos
*
* Output:		None.
*
* Overview:		Realiza una lectura secuencial de datos a un area de memoria especifico
*
* Note:			None
********************************************************************/

unsigned int IO_I2C2pageHDread(unsigned char add, unsigned int dir, unsigned char *rdptr, unsigned char length)
{
	
	INT8U err, i2c_err;
	INT8U retry = 4;
	
	OSSemPend( I2C2_Sem, 0, &err );
	
	do{
		
		i2c_err = 0;
		
		IdleI2C2();												//wait for bus Idle
		StartI2C2();											//Generate Start condition
	
		if( WriteI2C2( add & 0xFE ) != 0 )	i2c_err++;			//send device address for a write
	
		IdleI2C2();												//wait for bus Idle
	
		if( WriteI2C2( (dir >> 8) & 0x00FF ) != 0 )	i2c_err++;	//send memory address 	
	
		IdleI2C2();												//wait for bus Idle
	
		if( WriteI2C2( ( dir ) & 0x00FF   ) != 0 )	i2c_err++;	//send memory address 	
	
		IdleI2C2();	
	
		RestartI2C2();											//Generate I2C Restart Condition
	
		if( WriteI2C2( add | 0x01 ) != 0 )	i2c_err++;			//send memory address ( READ )	
	
		IdleI2C2();												//wait for bus Idle
	
		getsI2C2(rdptr, length);								//Read in multiple bytes
		NotAckI2C2();											//send Not Ack
	
		StopI2C2();												//Generate a stop
	
		retry--;	
													
	}
	while( i2c_err & retry );
	
	err = OSSemPost( I2C2_Sem );
	
	if( retry ) return 0;
	else return 1;
	
}


/*********************************************************************
* Function:        IO_I2C2PageLDRead
*
* Input:		add 	-> direccion de dispositivo,
*				dir		-> direccion de memoria ( 8 bits )
*				*rdptr 	-> puntero del buffer de datos leidos
*				length	-> cantidad de datos
*
* Output:		None.
*
* Overview:		Realiza una lectura secuencial de datos a un area de memoria especifico
*
* Note:			None
********************************************************************/

unsigned int IO_I2C2pageLDread(unsigned char add, unsigned char dir, unsigned char *rdptr, unsigned char length)
{
	
	INT8U err, i2c_err;
	INT8U retry = 4;
	
	OSSemPend( I2C2_Sem, 0, &err );
	
	do{
		
		i2c_err = 0;
		
		IdleI2C2();												//wait for bus Idle
		StartI2C2();											//Generate Start condition
	
		if( WriteI2C2( add & 0xFE ) != 0 ) i2c_err++;			//send device address for a write
	
		IdleI2C2();												//wait for bus Idle
	
		if( WriteI2C2( dir ) != 0 )	i2c_err++;					//send memory address 	
	
		IdleI2C2();												//wait for bus Idle
	
		RestartI2C2();											//Generate I2C Restart Condition
	
		if( WriteI2C2( add | 0x01 ) != 0 )	i2c_err++;		
		//send memory address ( READ )	
	
		IdleI2C2();												//wait for bus Idle
	
		getsI2C2(rdptr, length);								//Read in multiple bytes
		NotAckI2C2();											//send Not Ack
	
		StopI2C2();												//Generate a stop
		
		retry--;
	}
	while( i2c_err & retry );
	
	err = OSSemPost( I2C2_Sem );
	
	if( retry ) return 0;
	else return 1;
	
}						


/*********************************************************************
* Function:        IO_I2C2PageHDWrite
*
* Input:		add 	-> direccion de dispositivo,
*				dir		-> direccion de memoria ( 16 bits )
*				*rdptr 	-> puntero del buffer de datos a escribir
*				length	-> cantidad de datos
*
* Output:		None.
*
* Overview:		Realiza una escritura secuencial de datos a un area de memoria especifico
*
* Note:			None
********************************************************************/

unsigned int IO_I2C2pageHDwrite(unsigned char add, unsigned int dir, unsigned char *wrptr, unsigned char length)
{
	
	INT8U err, i2c_err;
	INT8U retry = 4;
	
	OSSemPend( I2C2_Sem, 0, &err );
	
	do{
	
		i2c_err = 0;
		
		IdleI2C2();												//wait for bus Idle
		StartI2C2();											//Generate Start condition
		
		if( WriteI2C2( add & 0xFE ) != 0 )	i2c_err++;			//send device address for a write
	
		IdleI2C2();												//wait for bus Idle
	
		if( WriteI2C2( (dir >> 8) & 0x00FF ) != 0 )	i2c_err++;	//send device address for a write
	
		IdleI2C2();												//wait for bus Idle
	
		if( WriteI2C2( ( dir ) & 0x00FF  ) != 0 ) i2c_err++;	//send device address for a write
	
		IdleI2C2();	
	
		if( putsI2C2( wrptr, length ) != 0 ) i2c_err++;			//Send data
	
		IdleI2C2();												//wait for bus Idle
		StopI2C2();												//Generate a stop
	
		retry--;
	 
	}
	while( i2c_err & retry );
	
	err = OSSemPost( I2C2_Sem );
	
	if( retry ) return 0;
	else return 1;
	
}

/*********************************************************************
* Function:        IO_I2C2PageLDWrite
*
* Input:		add 	-> direccion de dispositivo,
*				dir		-> direccion de memoria ( 8 bits )
*				*rdptr 	-> puntero del buffer de datos a escribir
*				length	-> cantidad de datos
*
* Output:		None.
*
* Overview:		Realiza una escritura secuencial de datos a un area de memoria especifico
*
* Note:			None
********************************************************************/

unsigned int IO_I2C2pageLDwrite(unsigned char add, unsigned char dir, unsigned char *wrptr, unsigned char length)
{
	
	INT8U err, i2c_err;
	INT8U retry = 4;
	
	OSSemPend( I2C2_Sem, 0, &err );
	
	do{
	
		i2c_err = 0;
		
		IdleI2C2();												//wait for bus Idle
		StartI2C2();											//Generate Start condition
	
		if( WriteI2C2( add & 0xFE ) != 0 )	i2c_err++;			//send device address for a write
	
		IdleI2C2();												//wait for bus Idle
		
		if( WriteI2C2( dir ) != 0 )	return -1;					//send memory address 	
	
		IdleI2C2();												//wait for bus Idle
	
		if( putsI2C2( wrptr, length ) != 0 ) i2c_err++;	//Send data
	
		IdleI2C2();												//wait for bus Idle
		StopI2C2();												//Generate a stop
	
		err = OSSemPost( I2C2_Sem );
		
		retry--;
	 
	}
	while( i2c_err & retry );
	
	err = OSSemPost( I2C2_Sem );
	
	if( retry ) return 0;
	else return 1;
	
}










/*********************************************************************
* 			RUTINAS SECUNDARIAS, NO MODIFICAR!!!
********************************************************************/











/*********************************************************************
* Function:        StartI2C1()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates an I2C Start Condition
*
* Note:			None
********************************************************************/
unsigned int StartI2C1(void)
{
	//This function generates an I2C start condition and returns status 
	//of the Start.

	unsigned int time = I2C_TIMEOUT;

	I2C1STATbits.I2COV = 0;

	I2C1CONbits.SEN = 1;		//Generate Start Condition
	
	while( I2C1CONbits.SEN )		//Espera ACK del SLAVE sino salir
	{
		if( time == 0 )	return -1;
		else time--;
	
		if(I2C1STATbits.BCL) return -1;		/* If bus collision occurs,return -1 */
	};
	
	return 0;

}


/*********************************************************************
* Function:        RestartI2C1()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates a restart condition and optionally returns status
*
* Note:			None
********************************************************************/
unsigned int RestartI2C1(void)
{
	//This function generates an I2C Restart condition and returns status 
	//of the Restart.

	unsigned int time = I2C_TIMEOUT;

	I2C1STATbits.I2COV = 0;

	I2C1CONbits.RSEN = 1;		//Generate Restart		
	
	while( I2C1CONbits.RSEN )		//Espera ACK del SLAVE sino salir
	{
		if( time == 0 )	return -1;
		else time--;
	
		if(I2C1STATbits.BCL) return -1;		/* If bus collision occurs,return -1 */
	};
	
	return 0;

}


/*********************************************************************
* Function:        StopI2C1()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates a bus stop condition
*
* Note:			None
********************************************************************/
unsigned int StopI2C1(void)
{
	//This function generates an I2C stop condition and returns status 
	//of the Stop.

	unsigned int time = I2C_TIMEOUT;

	I2C1STATbits.I2COV = 0;

	I2C1CONbits.PEN = 1;							//Generate Stop Condition
	
	while( I2C1CONbits.PEN )		//Espera ACK del SLAVE sino salir
	{
		if( time == 0 )	return -1;
		else time--;
		
		if( I2C1STATbits.BCL ) return -1;
	};
	
	return 0;
}


/*********************************************************************
* Function:        ReadI2C1()
*
* Input:		None.
*
* Output:		contents of I2C1 receive buffer.
*
* Overview:		Read a single byte from Bus
*
* Note:			None
********************************************************************/
unsigned int ReadI2C1(void)
{

	unsigned int time = I2C_TIMEOUT;
	
	I2C1CONbits.RCEN = 1;			//Enable Master receive
	
	I2C1STATbits.I2COV = 0;

	while( !I2C1STATbits.RBF )		//Espera ACK del SLAVE sino salir
	{
		if( time == 0 )	return -1;
		else time--;
		
		if( I2C1STATbits.BCL ) return -1;
	};
	
	return(I2C1RCV);

}

/*********************************************************************
* Function:        WriteI2C1()
*
* Input:		Byte to write.
*
* Output:		None.
*
* Overview:		Writes a byte out to the bus
*
* Note:			None
********************************************************************/
unsigned int WriteI2C1(unsigned char byte)
{

	unsigned int time = I2C_TIMEOUT;

	I2C1TRN = byte;					//Load byte to I2C1 Transmit buffer
	while (I2C1STATbits.TBF)		//wait for data transmission
	{
		if( time == 0 )	return -3;
		else time--;
		
		if( I2C1STATbits.BCL ) return -4;
	}
	
	time = I2C_TIMEOUT;
	
    if(I2C1STATbits.IWCOL) return -1;	/* If write collision occurs,return -1 */
    if(I2C1STATbits.BCL) return -2;		/* If bus collision occurs,return -1 */
    
	while( I2C1STATbits.ACKSTAT )		//Espera ACK del SLAVE sino salir
	{
		if( time == 0 )	return -3;
		else time--;
		
		if( I2C1STATbits.BCL ) return -4;
	};
	
	return 0;

}


/*********************************************************************
* Function:        IdleI2C1()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Waits for bus to become Idle
*
* Note:			None
********************************************************************/
unsigned int IdleI2C1(void)
{

	unsigned int time = I2C_TIMEOUT;

	I2C1STATbits.I2COV = 0;

    /* Wait until I2C Bus is Inactive */
    while( I2C1CONbits.SEN || I2C1CONbits.PEN || I2C1CONbits.RCEN || 
           I2C1CONbits.ACKEN || I2C1STATbits.TRSTAT )
	{
		if( time == 0 )	return -1;
		else time--;
		
		if( I2C1STATbits.BCL ) return -1;
	};
	
	return 0;
}




/*********************************************************************
* Function:        ACKStatus()
*
* Input:		None.
*
* Output:		Acknowledge Status.
*
* Overview:		Return the Acknowledge status on the bus
*
* Note:			None
********************************************************************/
/*
unsigned int ACKStatusI2C1(void)
{
	return (!I2C1STATbits.ACKSTAT);		//Return Ack Status
}
*/

/*********************************************************************
* Function:        NotAckI2C1()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates a NO Acknowledge on the Bus
*
* Note:			None
********************************************************************/
unsigned int NotAckI2C1(void)
{
	
	unsigned int time = I2C_TIMEOUT;

	I2C1CONbits.ACKDT = 1;			//Set for NotACk
	I2C1CONbits.ACKEN = 1;

	while( I2C1CONbits.ACKEN )		//wait for ACK to complete
	{
		if( time == 0 )	return -1;
		else time--;
		
		if( I2C1STATbits.BCL ) return -1;
	};
	
	return 0;
}



/*********************************************************************
* Function:     AckI2C1()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates an Acknowledge.
*
* Note:			None
********************************************************************/
unsigned int AckI2C1(void)
{

	unsigned int time = I2C_TIMEOUT;

	I2C1CONbits.ACKDT = 0;			//Set for ACk
	I2C1CONbits.ACKEN = 1;

	while( I2C1CONbits.ACKEN )		//wait for ACK to complete
	{
		if( time == 0 )	return -1;
		else time--;
		
		if( I2C1STATbits.BCL ) return -1;
	};
	
	return 0;
}


/*********************************************************************
* Function:       getsI2C1()
*
* Input:		array pointer, Length.
*
* Output:		the number of bytes recived
*
* Overview:		read Length number of Bytes into array
*
* Note:			None
********************************************************************/
unsigned int getsI2C1(unsigned char *rdptr, unsigned char length)
{
	
	unsigned char i;

	I2C1CONbits.RCEN = 1;			//Enable Master receive

	while ( length -- )
	{
		*rdptr++ = ReadI2C1();		//get a single byte
		
		if( I2C1STATbits.BCL )		//Test for Bus collision
		{
			return -1;
		}

		if( length )
		{
			i++;
			AckI2C1( );				//Acknowledge until all read
		}
	}

	return i;
}



/*********************************************************************
* Function:        putsI2C()
*
* Input:		pointer to array.
*
* Output:		None.
*
* Overview:		writes a string of data upto PAGESIZE from array
*
* Note:			None
********************************************************************/
unsigned int putsI2C1( unsigned char *wrptr, unsigned char length )
{
	int temp;

	while ( length -- )		//Transmit Data 
	{	
		temp = WriteI2C1( *wrptr );
 
		if( temp )		//Write 1 byte
		{
			return temp;					//Error
		}

		if( IdleI2C1( ) )				//Wait for idle
		{
			return -1;					//Error
		}

		wrptr++;
	}

	return 0;						// todo salio bien

}











/*********************************************************************
* Function:        StartI2C2()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates an I2C Start Condition
*
* Note:			None
********************************************************************/
unsigned int StartI2C2(void)
{
	//This function generates an I2C start condition and returns status 
	//of the Start.

	unsigned int time = I2C_TIMEOUT;

	I2C2STATbits.I2COV = 0;

	I2C2CONbits.SEN = 1;		//Generate Start Condition
	
	while( I2C2CONbits.SEN )		//Espera ACK del SLAVE sino salir
	{
		if( time == 0 )	return -1;
		else time--;
	
		if(I2C2STATbits.BCL) return -1;		/* If bus collision occurs,return -1 */
	};
	
	return 0;

}


/*********************************************************************
* Function:        RestartI2C2()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates a restart condition and optionally returns status
*
* Note:			None
********************************************************************/
unsigned int RestartI2C2(void)
{
	//This function generates an I2C Restart condition and returns status 
	//of the Restart.

	unsigned int time = I2C_TIMEOUT;

	I2C2STATbits.I2COV = 0;

	I2C2CONbits.RSEN = 1;		//Generate Restart		
	
	while( I2C2CONbits.RSEN )		//Espera ACK del SLAVE sino salir
	{
		if( time == 0 )	return -1;
		else time--;
	
		if(I2C2STATbits.BCL) return -1;		/* If bus collision occurs,return -1 */
	};
	
	return 0;

}


/*********************************************************************
* Function:        StopI2C2()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates a bus stop condition
*
* Note:			None
********************************************************************/
unsigned int StopI2C2(void)
{
	//This function generates an I2C stop condition and returns status 
	//of the Stop.

	unsigned int time = I2C_TIMEOUT;

	I2C2STATbits.I2COV = 0;

	I2C2CONbits.PEN = 1;							//Generate Stop Condition
	
	while( I2C2CONbits.PEN )		//Espera ACK del SLAVE sino salir
	{
		if( time == 0 )	return -1;
		else time--;
		
		if( I2C2STATbits.BCL ) return -1;
	};
	
	return 0;
}


/*********************************************************************
* Function:        ReadI2C2()
*
* Input:		None.
*
* Output:		contents of I2C2 receive buffer.
*
* Overview:		Read a single byte from Bus
*
* Note:			None
********************************************************************/
unsigned int ReadI2C2(void)
{

	unsigned int time = I2C_TIMEOUT;
	
	I2C2CONbits.RCEN = 1;			//Enable Master receive
	
	I2C2STATbits.I2COV = 0;

	while( !I2C2STATbits.RBF )		//Espera ACK del SLAVE sino salir
	{
		if( time == 0 )	return -1;
		else time--;
		
		if( I2C2STATbits.BCL ) return -1;
	};
	
	return(I2C2RCV);

}

/*********************************************************************
* Function:        WriteI2C2()
*
* Input:		Byte to write.
*
* Output:		None.
*
* Overview:		Writes a byte out to the bus
*
* Note:			None
********************************************************************/
unsigned int WriteI2C2(unsigned char byte)
{

	unsigned int time = I2C_TIMEOUT;

	I2C2TRN = byte;					//Load byte to I2C2 Transmit buffer
	while (I2C2STATbits.TBF)		//wait for data transmission
	{
		if( time == 0 )	return -3;
		else time--;
		
		if( I2C2STATbits.BCL ) return -4;
	}
	
	time = I2C_TIMEOUT;
	
    if(I2C2STATbits.IWCOL) return -1;	/* If write collision occurs,return -1 */
    if(I2C2STATbits.BCL) return -2;		/* If bus collision occurs,return -1 */
    
	while( I2C2STATbits.ACKSTAT )		//Espera ACK del SLAVE sino salir
	{
		if( time == 0 )	return -3;
		else time--;
		
		if( I2C2STATbits.BCL ) return -4;
	};
	
	return 0;

}


/*********************************************************************
* Function:        IdleI2C2()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Waits for bus to become Idle
*
* Note:			None
********************************************************************/
unsigned int IdleI2C2(void)
{

	unsigned int time = I2C_TIMEOUT;

	I2C2STATbits.I2COV = 0;

    /* Wait until I2C Bus is Inactive */
    while( I2C2CONbits.SEN || I2C2CONbits.PEN || I2C2CONbits.RCEN || 
           I2C2CONbits.ACKEN || I2C2STATbits.TRSTAT )
	{
		if( time == 0 )	return -1;
		else time--;
		
		if( I2C2STATbits.BCL ) return -1;
	};
	
	return 0;
}




/*********************************************************************
* Function:        ACKStatus()
*
* Input:		None.
*
* Output:		Acknowledge Status.
*
* Overview:		Return the Acknowledge status on the bus
*
* Note:			None
********************************************************************/
/*
unsigned int ACKStatusI2C2(void)
{
	return (!I2C2STATbits.ACKSTAT);		//Return Ack Status
}
*/

/*********************************************************************
* Function:        NotAckI2C2()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates a NO Acknowledge on the Bus
*
* Note:			None
********************************************************************/
unsigned int NotAckI2C2(void)
{
	
	unsigned int time = I2C_TIMEOUT;

	I2C2CONbits.ACKDT = 1;			//Set for NotACk
	I2C2CONbits.ACKEN = 1;

	while( I2C2CONbits.ACKEN )		//wait for ACK to complete
	{
		if( time == 0 )	return -1;
		else time--;
		
		if( I2C2STATbits.BCL ) return -1;
	};
	
	return 0;
}



/*********************************************************************
* Function:     AckI2C2()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates an Acknowledge.
*
* Note:			None
********************************************************************/
unsigned int AckI2C2(void)
{

	unsigned int time = I2C_TIMEOUT;

	I2C2CONbits.ACKDT = 0;			//Set for ACk
	I2C2CONbits.ACKEN = 1;

	while( I2C2CONbits.ACKEN )		//wait for ACK to complete
	{
		if( time == 0 )	return -1;
		else time--;
		
		if( I2C2STATbits.BCL ) return -1;
	};
	
	return 0;
}


/*********************************************************************
* Function:       getsI2C2()
*
* Input:		array pointer, Length.
*
* Output:		the number of bytes recived
*
* Overview:		read Length number of Bytes into array
*
* Note:			None
********************************************************************/
unsigned int getsI2C2(unsigned char *rdptr, unsigned char length)
{
	
	unsigned char i;

	I2C2CONbits.RCEN = 1;			//Enable Master receive

	while ( length -- )
	{
		*rdptr++ = ReadI2C2();		//get a single byte
		
		if( I2C2STATbits.BCL )		//Test for Bus collision
		{
			return -1;
		}

		if( length )
		{
			i++;
			AckI2C2( );				//Acknowledge until all read
		}
	}

	return i;
}



/*********************************************************************
* Function:        putsI2C()
*
* Input:		pointer to array.
*
* Output:		None.
*
* Overview:		writes a string of data upto PAGESIZE from array
*
* Note:			None
********************************************************************/
unsigned int putsI2C2( unsigned char *wrptr, unsigned char length )
{
	int temp;

	while ( length -- )		//Transmit Data 
	{	
		temp = WriteI2C2( *wrptr );
 
		if( temp )		//Write 1 byte
		{
			return temp;					//Error
		}

		if( IdleI2C2( ) )				//Wait for idle
		{
			return -1;					//Error
		}

		wrptr++;
	}

	return 0;						// todo salio bien

}


/*********************************************************************
* Function:     IO_I2C2formatEEPROM()
*
* Input:		Memory I2C address.
*
* Output:		None.
*
* Overview:		Format a specific EEPROM
*
* Note:			None
********************************************************************/

void IO_I2C1formatEEPROM( unsigned char add, unsigned int pages )
{
	
	unsigned int i, j;
	unsigned char hi_add;
	unsigned char lo_add;

	INT8U err;
	OSSemPend( I2C1_Sem, 0, &err );
	
	for( i = 0; i < pages; i++)
	{
		IdleI2C1();												//wait for bus Idle
		StartI2C1();											//Generate Start condition
		
		if( WriteI2C1( add & 0xFE ) != 0 ) i--;			//send device address for a write
	
		IdleI2C1();												//wait for bus Idle
	
		if( WriteI2C1( hi_add ) != 0 ) i--;				//send device address for a write
	
		IdleI2C1();												//wait for bus Idle
	
		if( WriteI2C1( lo_add ) != 0 ) i--;	//send device address for a write
	
		IdleI2C1();	

	
		for( j = 0; j < 128; j++)			//Transmit Data 
		{	
			if( WriteI2C1( 0x00 ) )			//Write 1 byte
			{
				j--;						//Error, retry!!
			}
	
			IdleI2C1( );					//Wait for Idle bus
		}
	
		IdleI2C1();							//wait for bus Idle
		StopI2C1();							//Generate a stop

		hi_add++;
		lo_add += 0x10;

		//DelayNmSec( 10 );				
		OSTimeDlyHMSM(0, 0, 0, 10); 		// if OS is enable									
	}

	err = OSSemPost( I2C1_Sem );
	
}




/*********************************************************************
* Function:     I2CM_Config()
*
* Input:		Memory I2C address.
*
* Output:		None.
*
* Overview:		Format a specific EEPROM
*
* Note:			None
********************************************************************/

void I2CM_Config( I2C_DEV * I2C_DEV_struct,  INT8U * ptr_datas )
{
  
	I2C_DEV_struct->address = *(ptr_datas);

	I2C_DEV_struct->t_sample = *(ptr_datas+1);
	I2C_DEV_struct->t_sample += *(ptr_datas+2)*256;

	I2C_DEV_struct->tr_sample_cont = *(ptr_datas+3);
	I2C_DEV_struct->tr_sample_cont += *(ptr_datas+4)*256;
	
	I2C_DEV_struct->tw_sample_cont = *(ptr_datas+5);
	I2C_DEV_struct->tw_sample_cont += *(ptr_datas+6)*256;
	
	I2C_DEV_struct->m = *(ptr_datas+7);
	I2C_DEV_struct->m += *(ptr_datas+8)*256;

	I2C_DEV_struct->b = *(ptr_datas+9);
	I2C_DEV_struct->b += *(ptr_datas+10)*256;


	I2C_DEV_struct->r_bytes_length = *(ptr_datas+11);
		
	I2C_DEV_struct->r_length = *(ptr_datas+12);
	if( I2C_DEV_struct->r_length > 2 ) I2C_DEV_struct->r_length = 2;

	I2C_DEV_struct->r_bytes[0] = *(ptr_datas+13);
	I2C_DEV_struct->r_bytes[1] = *(ptr_datas+14);


	I2C_DEV_struct->w_bytes_length = *(ptr_datas+15);
	
	I2C_DEV_struct->w_length = *(ptr_datas+16);
	if( I2C_DEV_struct->w_length > 2 ) I2C_DEV_struct->w_length = 2;

	I2C_DEV_struct->w_bytes[0] = *(ptr_datas+17);
	I2C_DEV_struct->w_bytes[1] = *(ptr_datas+18);

}

void I2CM_write( I2C_DEV * I2C_DEV_struct, INT8U * wrptr )
{
	
	INT16U dir;
	
	switch( I2C_DEV_struct->w_length )
	{
		case 0:
			IO_I2C2write( I2C_DEV_struct->address, wrptr, I2C_DEV_struct->w_bytes_length );
		break;
		
		case 1:
			IO_I2C2pageLDwrite( I2C_DEV_struct->address, *(I2C_DEV_struct->w_bytes), wrptr, I2C_DEV_struct->w_bytes_length );
		break;

		case 2:

			dir = I2C_DEV_struct->w_bytes[1];
			dir += (I2C_DEV_struct->w_bytes[0])*256;
			
			IO_I2C2pageHDwrite( I2C_DEV_struct->address, dir, wrptr, I2C_DEV_struct->w_bytes_length );

		break;
	}
	
}


void I2CM_read( I2C_DEV * I2C_DEV_struct, INT8U * rdptr )
{
	
	INT16U dir;
	
	switch( I2C_DEV_struct->r_length )
	{
		case 0:
			IO_I2C2read( I2C_DEV_struct->address, rdptr, I2C_DEV_struct->r_bytes_length );
		break;
		
		case 1:
			IO_I2C2pageLDread( I2C_DEV_struct->address, *(I2C_DEV_struct->r_bytes), rdptr, I2C_DEV_struct->r_bytes_length );
		break;

		case 2:

			dir = I2C_DEV_struct->r_bytes[1];
			dir += I2C_DEV_struct->r_bytes[0]*256;
			
			IO_I2C2pageHDread( I2C_DEV_struct->address, dir, rdptr, I2C_DEV_struct->r_bytes_length );

		break;
	}
}


void I2CDEVnew( VM * Machine )
{

	I2C_DEV * nuevo;
	I2C_DEV * last = Machine->ptr_structs[ I2CDEV_BASE ][1];
	
	nuevo = (I2C_DEV *) malloc ( sizeof( I2C_DEV ) );

	if( nuevo != NULL )
	{
		nuevo->next = NULL;
		
		Machine->I2CDEV_cont++;
		
		if( Machine->ptr_structs[ I2CDEV_BASE  ][0] == NULL )
		{
			Machine->ptr_structs[ I2CDEV_BASE  ][0] = nuevo;			
		}
		else
		{
			last->next = nuevo;
		}
		
		Machine->ptr_structs[ I2CDEV_BASE  ][1] = nuevo;
 	}
 					
}

void I2CDEVdestroy( VM * Machine )
{
	
	I2C_DEV  * last = Machine->ptr_structs[ I2CDEV_BASE ][1];
	
	Machine->ptr_structs[ I2CDEV_BASE ][1] = last->last;
	 
	free( last );
	
	Machine->I2CDEV_cont--;
	 	
}

I2C_DEV * I2CDEVgetptr( VM * Machine, INT8U element )
{
	
	INT8U i;
	I2C_DEV * aux = Machine->ptr_structs[ I2CDEV_BASE ][0];

	for( i = 0; i < element; i++ )
	{
		if( aux->next != NULL ) aux = (I2C_DEV*)aux->next;
		else return NULL;
	}
	
	return aux;
	
}








unsigned int SlaveputsI2C2(unsigned char * wrptr)
{
    
	wrptr--;

    do
	{
		SlaveWriteI2C2( *(wrptr++) );	/* Send a byte */
    	
    	while(I2C2STATbits.TBF);		/* wait till the transmit buffer is clear */ 
        
		while(!IFS3bits.SI2C2IF);		/* Wait till the ACK from master is received */
		IFS3bits.SI2C2IF = 0;			/* Clear Flag */
	    
    }
    while( !I2C2STATbits.ACKSTAT );		/* transmit data until null char */
    
    I2C2CONbits.SCLREL = 1; 

	return 0;  							/* null char was reached */
}


void SlaveWriteI2C2(unsigned char data_out)
{
    
    I2C2TRN = data_out;      	/* data transferred to I2C2TRN reg */
     
	I2C2CONbits.SCLREL = 1;    /* Release the clock */
}


unsigned char SlaveReadI2C2(void)
{
     
	I2C2STATbits.I2COV = 0;
     
	I2C2CONbits.SCLREL = 1; 	// Clock is released
	
	while( !I2C2STATbits.RBF );
     
	return( I2C2RCV );

}

void SlaveWaitForIntrI2C2(void)
{

	I2C2CONbits.SCLREL = 1;			// Release clock	
   	
   	while( !IFS3bits.SI2C2IF );
   	IFS3bits.SI2C2IF = 0;

	
}

unsigned char SlavegetsI2C2(unsigned char * rdptr, unsigned int i2c1_data_wait)
{

    int wait = 0;
    unsigned char temp;						/* flush out old data already on I2CRCV to clear RBF flag */

	temp = I2C2RCV;	

    I2C2STATbits.I2COV = 0;					/* clear OV flag */

    while(!I2C2STATbits.P)					/* check for stop bit */
    {

        while(!DataRdyI2C2())
        {
            if(wait < i2c1_data_wait) wait++ ;  		/* timeout check */              
            else return -1;                				/* return number of bytes received */		
        }

        wait = 0;

        *rdptr++ = I2C2RCV;             /* save byte received */

        if((I2C2CONbits.STREN) && (!I2C2CONbits.SCLREL))
            I2C2CONbits.SCLREL = 1;	/* Clock is released after ACK */

    }

	return 0;
}


char DataRdyI2C2(void)
{
     return I2C2STATbits.RBF;
}





