#include <p24HJ128GP204.h>
#include "i2c.h"

void i2c_init (void)
{
    WRITE_sda();
	WRITE_scl();
	SDA = 1;
	SCL = 1;
}


void i2c_ack_polling(unsigned char device_address)
{
    while(1)
    {
        i2c_start();
        if (i2c_send_byte(device_address) == ACK) break;
    }
    i2c_stop();
}


void i2c_start(void)
{
    WRITE_sda();
    SDA = 1;
    i2c_delay(I2C_DELAY);

    SCL = 1;
    i2c_delay(I2C_DELAY);

    SDA = 0;
    i2c_delay(I2C_DELAY);
}

//The I2C Clock has a minimum of 2us high time and 2us low time
void i2c_stop(void)
{
    SCL = 0;
    i2c_delay(I2C_DELAY);

    WRITE_sda();

    SDA = 0;
    i2c_delay(I2C_DELAY);

    SCL = 1;
    i2c_delay(I2C_DELAY);

    SDA = 1;
    i2c_delay(I2C_DELAY);
}

//The I2C Clock has a minimum of 2us high time and 2us low time
//8MHz = 0.5us per instruction
unsigned char i2c_read_byte(void)
{
    int j, in_byte;

    SCL = 0;

    READ_sda();

    for(j = 0 ; j < 8 ; j++)
    {
        SCL = 0;
        i2c_delay(I2C_DELAY);

        SCL = 1;
        i2c_delay(I2C_DELAY);

        in_byte = in_byte << 1;
        in_byte |= SDARD;
    }

    return(in_byte);
}

unsigned char i2c_read_multibyte(void)
{
    int j, in_byte;

    SCL = 0;

    READ_sda();

    for(j = 0 ; j < 8 ; j++)
    {
        SCL = 0;
        i2c_delay(I2C_DELAY);

        SCL = 1;
        i2c_delay(I2C_DELAY);

        in_byte = in_byte << 1;
        in_byte |= SDARD;
    }

	SCL = 0;
	i2c_delay(I2C_DELAY);
	WRITE_sda ();
	SDA = 0;
	i2c_delay(5);
	SCL = 1;
	i2c_delay(I2C_DELAY);

    return(in_byte);
}

//The I2C Clock has a minimum of 2us high time and 2us low time
//8MHz = 500ns per instruction
unsigned char i2c_send_byte(unsigned char out_byte)
{
    unsigned char i;

    WRITE_sda();

    for(i = 0 ; i < 8 ; i++)
    {
        SCL = 0;
        i2c_delay(I2C_DELAY);

		if (out_byte & 0x80) {
			SDA = 1;
		} else {
			SDA = 0;
		}
        out_byte = out_byte << 1;
        i2c_delay(5);

        SCL = 1;
        i2c_delay(I2C_DELAY);
    }

    //Read ack
    SCL = 0;
    READ_sda(); // XXX
    i2c_delay(I2C_DELAY);

    READ_sda();

    SCL = 1;
    i2c_delay(I2C_DELAY);

    //Wait for IC to acknowledge
    for(i = 0 ; i < 255 ; i++)
        if(SDARD == 0) break;

    SCL = 0;
    i2c_delay(I2C_DELAY);

    if (i == 255) return(NO_ACK);
    
    return(ACK);
}

void i2c_delay (unsigned char x)
{
	while (x--) {
		Nop ();
		Nop ();
		Nop ();
		Nop ();
		Nop ();
		Nop ();
		Nop ();
		Nop ();
		Nop ();
		Nop ();
		Nop ();
		Nop ();
		Nop ();
		Nop ();
		Nop ();
		Nop ();
	}
}





/*
// SCL line is connected to pin RA4
#define SCL_TRISA_REG				TRISAbits.TRISA4 
#define SCL_LATCH_REG				LATAbits.LATA4
#define SCL_PORT_REG				PORTAbits.RA4

// SDA line is connected to pin RA4
#define SDA_TRISA_REG				TRISAbits.TRISA9 
#define SDA_LATCH_REG				LATAbits.LATA9
#define SDA_PORT_REG				PORTAbits.RA9

// drive clock line directly
#define SCL_LO()					LATAbits.LATA4 = 0
#define SCL_HI()					LATAbits.LATA4 = 1
#define SCL_RD()					PORTAbits.RA4

// unfloat / float data line to drive a zero / float a one
#define SDA_LO()					TRISAbits.TRISA9 = 0
#define SDA_HI()					TRISAbits.TRISA9 = 1
#define SDA_RD()					PORTAbits.RA9

void i2c_init (void)
{
	// make SCL pin an output and set it high
	SCL_TRISA_REG = 0;
	SCL_LATCH_REG = 1;
	
	// place SDA pin in high-impedance state and let it float high
	// set SDA latch value to zero so when pin is driven it will be driven low
	SDA_TRISA_REG = 1;
	SDA_LATCH_REG = 0;
}

void i2c_start (void)
{
	// assumes SCL and SDA are high on entry
	// set sda low while scl is high
	SDA_LO ();
	i2c_delay ();
	SCL_LO ();
	i2c_delay ();
}

void i2c_stop (void)
{
	// assumes SCL low on entry
	// set sda high while scl is high
	SDA_LO ();
	i2c_delay ();
	SCL_HI ();
	i2c_delay ();
	SDA_HI ();
	i2c_delay ();
}

void i2c_restart (void)
{
	// assumes SCL low on entry
	SDA_LO ();
	i2c_delay ();
	SCL_HI ();
	i2c_delay ();
	SDA_HI ();
	i2c_delay ();
	SCL_LO ();
	i2c_delay ();
	SCL_HI ();
	i2c_delay ();
	SDA_LO ();
	i2c_delay ();
	SCL_LO ();
	i2c_delay ();
}

void i2c_send_byte (unsigned char data)
{
	// assumes SCL low on entry
	unsigned char i;

	for (i = 0; i < 8; i++) {
		// set sda high or low depending on bit 
		if (data & 0x80) SDA_HI (); else SDA_LO ();
		i2c_delay ();
		// set scl high
		SCL_HI ();
		i2c_delay ();
		// set scl low
		SCL_LO ();
		i2c_delay ();

		data = data << 1;
	}

	SDA_HI ();
	SCL_HI ();
	i2c_delay ();

	for (i = 0; i < 255; i++) {
		if (SDA_RD () == 0) break;
	}

	SCL_LO ();
	i2c_delay ();
}
*/
