#include <stdint.h>

#include "i2c_simple.h"

void i2c_init()
{
	TWBR = 0;//bit rate
	TWSR = 0;//Prescaler
	
	TWAR = 0x80;//our address 1000 000, don't listen to general call
	TWAMR = 0;
	
	TWCR = TWEA | TWEN;/* TWINT clear -> we must do something; unset TWSTA manually!, TWSTO */
	//TWDR - data
}

uint8_t i2c_read(uint8_t addr, uint8_t len, uint8_t *data)
{
	TWCR &= ~TWSTO;
	TWCR |= TWINT | TWSTA;
	while(~TWCR & TWINT) {;}/* get bus access */
	/* no error possible */
	
	TWDR = addr | 1;
	TWCR &= ~(TWSTA | TWSTO);
	TWCR |= TWINT;
	while(~TWCR & TWINT) {;}/* transmit address */
	/* possible results: ACK, NAK, abitration lost */
	if(TW_STATUS == TW_MR_SLA_NACK)
	{
		TWCR |= TWINT | TWSTO;
		return 0;
	}
	else if(TW_STATUS == TW_MR_ARB_LOST) {return 0;}
	
	uint8_t done = 0;
	while(done + 1 < len)
	{
		TWCR |= TWEA | TWINT;/* send ack after byte */
		while(~TWCR & TWINT) {;}/* read data */
		data[done] = TWDR;
		done++;
		TWCR |= TWINT;
	}
	
	TWCR &= ~TWEA;
	TWCR |= TWINT;/* send nak after byte */
	while(~TWCR & TWINT) {;}/* read data */
	data[done] = TWDR;
	done++;
	TWCR |= TWINT | TWSTO;
	return done;
}

uint8_t i2c_write(uint8_t addr, uint8_t len, uint8_t *data)
{
	TWCR &= ~TWSTO;
	TWCR |= TWINT | TWSTA;
	while(~TWCR & TWINT) {;}/* get bus access */
	/* no error possible */
	
	TWDR = addr;
	TWCR &= ~(TWSTA | TWSTO);
	TWCR |= TWINT;
	while(~TWCR & TWINT) {;}/* transmit address */
	/* possible results: ACK, NAK, abitration lost */
	if(TW_STATUS == TW_MT_SLA_NACK)
	{
		TWCR |= TWINT | TWSTO;
		return 0;
	}
	else if(TW_STATUS == TW_MT_ARB_LOST) {return 0;}
	
	uint8_t done = 0;
	while(done < len)
	{
		TWDR = data[done];
		TWCR |= TWINT;
		while(~TWCR & TWINT) {;}/* write data */
		/* possible results: ACK, NAK, abitration lost */
		if(TW_STATUS == TW_MT_DATA_NACK)
		{
			TWCR |= TWINT | TWSTO;
			return done;
		}
		else if(TW_STATUS == TW_MT_ARB_LOST) {return done;}
		done++;
	}
	
	TWCR |= TWINT | TWSTO;
	return done;
}

uint8_t i2c_write_read(uint8_t addr, uint8_t writelen, uint8_t *writedata, uint8_t readlen, uint8_t *readdata)
{
	return 0; //TODO: implement
}
