#include "i2c.h"

/************************** DEFINICE PROCEDUR **********************/
/*
void delay_us1(register unsigned char time)
{
 do
 	{
	time--;
	}
 while(time);
}
*/
void delay_us(void) //cca 4us
{
 #pragma ASM
	nop
	nop
 #pragma ENDASM
}

void delay(void)	 //cca 17 us
{
	EA = 0;    // Disable all interrupts for a accurate timing
	
		delay_us();
		delay_us();
		delay_us();
		delay_us(); 

	EA = 1;    // Enable all interrupts
	return;
}


void i2c_delay(void)  // Wait for 5µs
{
	EA = 0;    // Disable all interrupts for a accurate timing
	
	delay_us();
	EA = 1;    // Enable all interrupts
	return;
}


void i2c_start(void)
{
	EA = 0;        // Disable all interrupts for a accurate timing
	// Force defined state of SCL and SDA
	SCL = 1;       // Release SCL
	SDA = 1;       // Release SDA
	i2c_delay();   // Force 5µs-delay
	// Generate START condition
	SDA = 0;
	i2c_delay();   // Force 5µs-delay
	SCL = 0;
	EA = 1;        // Enable all interrupts
	// I2C Busy
	return;
}


void i2c_stop(void)
{
	EA = 0;        // Disable all interrupts for a accurate timing
	// Generate STOP condition
	SDA = 0;
	i2c_delay();   // Force 5µs-delay
	SCL = 1;       // Release SCL
	i2c_delay();   // Force 5µs-delay
	SDA = 1;       // Release SDA
	EA = 1;        // Enable all interrupts
	i2c_delay();   // *********************
	// I2C Idle
	return;
}


void i2c_ack(void)		// Send ACK bit - vse vporadku
{
	EA = 0;				// Disable all interrupts for a accurate timing
	// Generate ACK
	SDA = 0;
	SCL = 1;			// Release SCL
	while(SCL == 0);	// Synchronize clock
	i2c_delay();		// Force 5µs-delay
	SCL = 0;			// Force a clock cycle
	EA = 1;				// Enable all interrupts
	return;
}


void i2c_nack(void)		// Send ACK bit - chyba
{
	EA = 0;             // Disable all interrupts for a accurate timing
	// Generate NACK
	SDA = 1;            // Release SDA
	SCL = 1;            // Release SCL
	while(SCL == 0);    // Synchronize clock
	i2c_delay();        // Force 5µs-delay
	SCL = 0;            // Force a clock cycle
	EA = 1;             // Enable all interrupts
	return;
}


unsigned char i2c_check(void)	// Prijma ACK bit od Slavu SDA = 0 - OK, SDA = 1 - Chyba
{
	EA = 0;            // Disable all interrupts for a accurate timing
	SDA = 1;           // Release SDA
	SCL = 1;           // Release SCL
	while(SCL == 0);   // Synchronize clock
	i2c_delay();       // Force 5µs-delay
	if (SDA)           // SDA is high
	{
		SCL = 0;          // Force a clock cycle
		return(1);        // No acknowledge from Slave
	}
	SCL = 0;           // Force a clock cycle
	EA = 1;            // Enable all interrupts
	return(0);         // Acknowledge from Slave
}


unsigned char i2c_write(unsigned char value)
{
	unsigned char idata counter = 0;  // Bitcounter
	EA = 0;                           // Disable all interrupts for a accurate timing
	for ( counter = 0; counter < 8; counter++ )
	{
		SDA = (bit)((value & 0x80) >> 7); // Set SDA to value of MSB
		SCL = 1;                        // Release SCL
		while(SCL == 0);                // Synchronize clock
		i2c_delay();                    // Force 5µs-delay
		SCL = 0;                        // Force a clock cycle
		value <<= 1;                    // Prepare next bit for transmission
	}
	EA = 1;                           // Enable all interrupts
	// Generate a 9. clock cycle and check ACK from SLAVE
	// Return the result
	return(i2c_check());
}


unsigned char i2c_read(void)
{
	unsigned char data result  = 0;  // Returnvalue with read I2C byte
	unsigned char data counter = 0;  // Bitcounter
	EA = 0;              // Disable all interrupts for a accurate timing
	for ( counter = 0; counter < 8; counter++ )
	{
		SDA = 1;           // Release SDA
		SCL = 1;           // Release SCL
		while(SCL == 0);   // Synchronize clock
		i2c_delay();       // Force 5µs-delay
		result <<= 1;      // Shift left the result
		if (SDA)
			result |= 0x01;  // Set actual SDA state to LSB
		SCL = 0;           // Force a clock cycle
		i2c_delay();       // Force 5µs-delay
	}
	EA = 1;              // Enable all interrupts
	// ACK or NACK from MASTER must be generated outside this routine
	return(result);
}


void MAX_write(unsigned char adress, unsigned char command, unsigned char rdata)
{
	i2c_start();   // Generate START condition
	// Send SLAVE adress with write request
	if (i2c_write(adress | WRITE))
	{
		return;
	}
	// Send command
	if (i2c_write(command) )
	{
		return;
	}
	// Send data
	if (i2c_write(rdata) )
	{
		return;
	}
	// Send content to memory adress
	i2c_stop();    // Generate STOP condition
	return;
}


unsigned char MAX_read(unsigned char adress, unsigned char command)
{
	unsigned char idata rdata = 0;
	i2c_start();   // Generate START condition
	// Send SLAVE adress with write request
	if (i2c_write(adress | WRITE))
	{
		return(0);
	}
	// Send command
	if (i2c_write(command) )
	{
		return(rdata);
	}
	i2c_start();   // Generate START condition
	// Send SLAVE adress with read request
	if (i2c_write(adress | READ))
	{
		return(0);
	}
	// Read data
	rdata = i2c_read();
	i2c_ack();
	// Send content to memory adress
	i2c_stop();    // Generate STOP condition
	return(rdata);
}
