#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

#define IODIR	0x00
#define IPOL	0x01
#define GPINTEN	0x02
#define DEFVAL	0x03
#define INTCON	0x04
#define IOCON	0x05
#define GPPU	0x06
#define INTF	0x07
#define INTCAP	0x08
#define GPIO	0x09
#define OLAT	0x0A


//I2C eszközök:
#define MCP23009_addr	0x40
#define PCF8574_addr	0x40
#define MCP3221_addr	0x9A


//I2C állandók:
#define ACK			1
#define NACK		0
#define I2C_READ	1
#define I2C_WRITE	0
#define I2C_TIMEOUT	200

//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 MCP23009_write_register(byte reg, byte data)
{
	i2c_start();
	i2c_write(MCP23009_addr+I2C_WRITE);
	i2c_write(reg);
	i2c_write(data);
	i2c_stop();
}

byte MCP23009_read_register(byte reg)
{
	i2c_start();
	i2c_write(MCP23009_addr+I2C_WRITE);
	i2c_write(reg);
	i2c_start();
	i2c_write(MCP23009_addr+I2C_READ);
	i2c_read(NACK);
	byte out = TWDR;
	i2c_stop();
	return out;
}



#endif
