#include <inttypes.h>
#include "i2c_sw.h"

/* Send data byte out on bang i2c, return false if ack
 * Assumes start has been set up or a next byte
 * so  both lines are assumed low
 * **Lower byte of 'data' is sent**
 */
unsigned char i2c_send( register unsigned int data )
{
	volatile unsigned int i= 0; /* will be register */
	/* output eight bits of 'data' */
	for( ; i < 8; ++i )
	{
		/* send the data bit */
		if( data & 0x80 )
			I2C_DIR&= ~I2C_SDA;
		else
			I2C_DIR|= I2C_SDA;

		/* shift next data bit */
		data<<= 1;

		/* Toggle SCL, first high */
		I2C_DIR&= ~I2C_SCL;

#ifdef I2C_UDLY
		brief_pause( I2C_DDLY );
#endif /* I2C_UDLY */

		/* Set SCL Low */
		I2C_DIR|= I2C_SCL;
	}

	/* make sure SDA inputs */
	I2C_DIR&= ~I2C_SDA;

	/* Set	SCL High */
	I2C_DIR&= ~I2C_SCL;

	/* get the ack bit, true if ack */
	uint16_t ack= !( I2C_IN & I2C_SDA );

	if( ack ) /* leave SDA in last state! */
		I2C_DIR|= I2C_SDA;

	/* Set SCL Low */
	I2C_DIR|= I2C_SCL;

	return ack;
}

/* Assumes the IC2_MASTER_SCL is low */
void i2c_receive( unsigned char* buf, int count )
{
	unsigned char data;
	for( ; count--; )
	{
		data= 0;
		/* Release SDA */
		I2C_DIR&= ~I2C_SDA;

		volatile unsigned int i= 0;
		for( ; i < 8; ++i )
		{
			/* Set Clock High */
			I2C_DIR&= ~I2C_SCL;

			/* shift the bit over */
			data= data << 1;

			if( I2C_IN & I2C_SDA )
				data|= 0x01;

			/* Set Clock Low */
			I2C_DIR|= I2C_SCL;
		}
		/* put the input data byte into the buffer, inc buffer pointer */
		*buf++= data;

		/* No Ack after last byte */
		if( count )
			I2C_DIR|= I2C_SDA;

		/* Toggle SCL, first high */
		I2C_DIR&= ~I2C_SCL;

#ifdef I2C_UDLY
		brief_pause( I2C_DDLY );
#endif /* I2C_UDLY */

		/* Set SCL Low */
		I2C_DIR|= I2C_SCL;
	}
}

void i2c_start( void )
{
	/* Make sure both pins are high */
	I2C_DIR&= ~( I2C_SDA | I2C_SCL );
	/* Set output low here so'I2C Master Init' is not needed */
	I2C_OUT&= ~( I2C_SDA | I2C_SCL );

	/* Set SDALow, pause in case both pins were not high */
	brief_pause( I2C_SDLY );
	I2C_DIR|= I2C_SDA;

	/* Set SCL Low */
	brief_pause( I2C_SDLY );
	I2C_DIR|= I2C_SCL;
}

/* Assumes SCL is low */
void i2c_stop( void )
{
	/* make sure SDA is low */
	I2C_DIR|= I2C_SDA;

	/* SCL to high, pause in case SDA was high */
	brief_pause( I2C_SDLY );
	I2C_DIR&= ~I2C_SCL;
	/* SDA to high */
	brief_pause( I2C_SDLY );
	I2C_DIR&= ~I2C_SDA;
}

