#ifndef __I2C_H__
#define __I2C_H__

#include<util/twi.h>

#define MY_TWBR ((F_CPU/F_I2C)-16)/2
#if (MY_TWBR<0) || (MY_TWBR>255)
	#error "TWBR value out of range!"
#endif




//I2C eszközök:
#define MCP23009_addr	0x40
#define PCF8574_addr	0x40
#define PCF8574A_addr	0x70
#define MCP3221_addr	0x9A


//I2C állandók:
#define ACK			1
#define NACK		0
#define I2C_READ	1
#define I2C_WRITE	0
#define I2C_TIMEOUT	255

//hibajelző és hibakódok:
#define I2C_TRANSFER_OK		0
#define I2C_START_ERROR		1
#define I2C_DEVICE_MISSING	2
#define I2C_WRITE_ERROR		3
byte i2c_error  = 0;


void i2c_init()
{
	TWCR = 1<<TWEN;
	TWSR = 0b00000000;
	TWBR = MY_TWBR;

}

byte i2c_start()
{
	//megvárja az előző "STOP condition" végrehajtását!
	for(byte i=0; (TWCR & (1<<TWSTO))&& (i<I2C_TIMEOUT); i++) _delay_us(1);
	//adatátvitel indul!
	TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
	for(byte i=0; (!(TWCR & (1<<TWINT)))&& (i<I2C_TIMEOUT); i++) _delay_us(1);
	return TWSR & 0xF8;		//'TW_START'
}

//cím és adat átadása is itt történik!
byte i2c_write(byte data)
{
	TWDR = data;
	TWCR = (1<<TWINT) | (1<<TWEN);
	for(byte i=0; (!(TWCR & (1<<TWINT)))&& (i<I2C_TIMEOUT); i++) _delay_us(1);
	return TWSR & 0xF8;		//'TW_MT_SLA_ACK' vagy 'TW_MT_DATA_ACK' vagy 'TW_MR_SLA_ACK'
}

//csak olvasásra. "ack": több-bájtos kiolvasásra!
byte i2c_read(byte ack)
{
	if(ack)	TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
	else	TWCR = (1<<TWINT) | (1<<TWEN);
	for(byte i=0; (!(TWCR & (1<<TWINT)))&& (i<I2C_TIMEOUT); i++) _delay_us(1);
	return TWSR & 0xF8;		//???
}

void i2c_stop()
{
	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
}


void i2c_expander(byte data)
{
	if(i2c_start() != TW_START)								{ i2c_stop(); i2c_error=1; return; }
	if(i2c_write(PCF8574_addr+I2C_WRITE) != TW_MT_SLA_ACK)	{ i2c_stop(); i2c_error=2; return; }
	if(i2c_write(data) != TW_MT_DATA_ACK)					{ i2c_stop(); i2c_error=3; return; }
	i2c_stop();
	i2c_error = 0;
	//PCF8574_state = data;
}


void expander_write(byte addr, byte data)
{
	addr = ((addr&0b00001111)<<1) + I2C_WRITE;
	if(addr<16) addr+=PCF8574_addr; else addr+=PCF8574A_addr-16;
	if(i2c_start() != TW_START)				{ i2c_stop(); i2c_error=1; return; }
	if(i2c_write(addr) != TW_MT_SLA_ACK)	{ i2c_stop(); i2c_error=2; return; }
	if(i2c_write(data) != TW_MT_DATA_ACK)	{ i2c_stop(); i2c_error=3; return; }
	i2c_stop();
	i2c_error = 0;
}


byte expander_read(byte addr)
{
	addr = ((addr&0b00001111)<<1) + I2C_READ;
	if(addr<16) addr+=PCF8574_addr; else addr+=PCF8574A_addr-16;
	if(i2c_start() != TW_START)				{ i2c_stop(); i2c_error=1; return 255; }
	if(i2c_write(addr) != TW_MR_SLA_ACK)	{ i2c_stop(); i2c_error=2; return 255; }
	if(i2c_read(NACK) != TW_MR_DATA_NACK)	{ i2c_stop(); i2c_error=3; return 255; }
	//i2c_read(NACK);
	i2c_stop();
	i2c_error = 0;
	return TWDR;
}




#endif
