//*****************************************************************************
// File Name	: i2ctest.c
// 
// Title		: example usage of I2C library functions
// Revision		: 1.0
// Notes		:	
// Target MCU	: Atmel AVR series
// Editor Tabs	: 4
// 
// Revision History:
// When			Who			Description of change
// -----------	-----------	-----------------------
// 03-Feb-2003	pstang		Created the program
//*****************************************************************************

 
//----- Include Files ---------------------------------------------------------
#include <avr/io.h>		// include I/O definitions (port names, pin names, etc)
#include <avr/interrupt.h>	// include interrupt support

#include "global.h"		// include our global settings
#include "uart.h"		// include uart function library
#include "rprintf.h"	// include printf function library
#include "a2d.h"		// include A/D converter function library
#include "timer.h"		// include timer function library (timing, PWM, etc)
#include "vt100.h"		// include VT100 terminal support
#include "i2c.h"		// include i2c support
#include "debug.h"		// include debug functions


#define LOCAL_ADDR	0xA0
#define TARGET_ADDR	0xA0

// local data buffer
unsigned char localBuffer[] = "Pascal is cool!!Pascal is Cool!!";
unsigned char localBufferLength = 0x20;

void i2cTest(void);
void i2cSlaveReceiveService(u08 receiveDataLength, u08* receiveData);
u08 i2cSlaveTransmitService(u08 transmitDataLengthMax, u08* transmitData);
void i2cMasterSendDiag(u08 deviceAddr, u08 length, u08* data);
void testI2cMemory(void);
void showByte(u08 byte);

//----- Begin Code ------------------------------------------------------------
int main(void)
{
	// initialize our libraries
	// initialize the UART (serial port)
	uartInit();
	// make all rprintf statements use uart for output
	rprintfInit(uartSendByte);
	// initialize the timer system
	timerInit();
	// clear terminal screen
	vt100ClearScreen();
	vt100SetCursorPos(1,1);
	// print a little intro message so we know things are working
	rprintf("\r\nWelcome to i2c test!\r\n");
	
	// run tests
	
	i2cTest();

	return 0;
}


void i2cTest(void)
{
	u08 c=0;
	showByte(0x55);

	// initialize i2c function library
	i2cInit();
	// set local device address and allow response to general call
	i2cSetLocalDeviceAddr(LOCAL_ADDR, TRUE);
	// set the Slave Receive Handler function
	// (this function will run whenever a master somewhere else on the bus
	//  writes data to us as a slave)
	i2cSetSlaveReceiveHandler( i2cSlaveReceiveService );
	// set the Slave Transmit Handler function
	// (this function will run whenever a master somewhere else on the bus
	//  attempts to read data from us as a slave)
	i2cSetSlaveTransmitHandler( i2cSlaveTransmitService );

	timerPause(500);
	showByte(0xAA);

	while(1)
	{
		rprintf("Command>");
		while(!c) uartReceiveByte(&c);
		
		switch(c)
		{
		case 's':
			rprintf("Send: ");
			// get string from terminal
			localBufferLength = 0;
			c = 0;
			while((c != 0x0D) && (localBufferLength < 0x20))
			{
				while(!uartReceiveByte(&c));
				localBuffer[localBufferLength++] = c;
				uartSendByte(c);
			}
			// switch CR to NULL to terminate string
			localBuffer[localBufferLength-1] = 0;
			// send string over I2C
			i2cMasterSend(TARGET_ADDR, localBufferLength, localBuffer);
			//i2cMasterSendNI(TARGET_ADDR, localBufferLength, localBuffer);
			rprintfCRLF();
			break;
		case 'r':
			rprintf("Receive: ");
			// receive string over I2C
			i2cMasterReceive(TARGET_ADDR, 0x10, localBuffer);
			//i2cMasterReceiveNI(TARGET_ADDR, 0x10, localBuffer);
			// format buffer
			localBuffer[0x10] = 0;
			rprintfStr(localBuffer);
			rprintfCRLF();
			break;
		case 'm':
			testI2cMemory();
			break;
		default:
			rprintf("Unknown Command!");
			break;
		}
		c = 0;
		rprintfCRLF();
	}

}


// slave operations
void i2cSlaveReceiveService(u08 receiveDataLength, u08* receiveData)
{
	u08 i;

	// this function will run when a master somewhere else on the bus
	// addresses us and wishes to write data to us

	showByte(*receiveData);
	cbi(PORTB, PB6);

	// copy the received data to a local buffer
	for(i=0; i<receiveDataLength; i++)
	{
		localBuffer[i] = *receiveData++;
	}
	localBufferLength = receiveDataLength;
}

u08 i2cSlaveTransmitService(u08 transmitDataLengthMax, u08* transmitData)
{
	u08 i;

	// this function will run when a master somewhere else on the bus
	// addresses us and wishes to read data from us

	showByte(*transmitData);
	cbi(PORTB, PB7);

	// copy the local buffer to the transmit buffer
	for(i=0; i<localBufferLength; i++)
	{
		*transmitData++ = localBuffer[i];
	}

	localBuffer[0]++;

	return localBufferLength;
}

void i2cMasterSendDiag(u08 deviceAddr, u08 length, u08* data)
{
	// this function is equivalent to the i2cMasterSendNI() in the I2C library
	// except it will print information about transmission progress to the terminal

	// disable TWI interrupt
	cbi(TWCR, TWIE);

	// send start condition
	i2cSendStart();
	i2cWaitForComplete();
	rprintf("STA-");

	// send device address with write
	i2cSendByte( deviceAddr&0xFE );
	i2cWaitForComplete();
	rprintf("SLA+W-");
	
	// send data
	while(length)
	{
		i2cSendByte( *data++ );
		i2cWaitForComplete();
		rprintf("DATA-");
		length--;
	}
	
	// transmit stop condition
	// leave with TWEA on for slave receiving
	i2cSendStop();
	while( !(inb(TWCR) & BV(TWSTO)) );
	rprintf("STO");

	// enable TWI interrupt
	sbi(TWCR, TWIE);
}

void testI2cMemory(void)
{
	u08 i;
	u08 txdata[66];
	u08 rxdata[66];

	rprintfProgStrM("\r\nRunning I2C memory test (24xxyy devices)\r\n");

	// compose address
	txdata[0] = 0;
	txdata[1] = 0;
	// compose data
	for(i=0; i<16; i++)
		txdata[2+i] = localBuffer[i];
	// send address and data
	i2cMasterSendNI(TARGET_ADDR, 18, txdata);
	
	rprintfProgStrM("Stored data: ");
	// null-terminate data
	txdata[18] = 0;
	rprintfStr(&txdata[2]);
	rprintfCRLF();
	
	timerPause(100);

	// send address
	i2cMasterSendNI(TARGET_ADDR, 2, txdata);
	// get data
	i2cMasterReceiveNI(TARGET_ADDR, 16, rxdata);
	// null-terminate received string
	rxdata[16] = 0;

	rprintfProgStrM("Received data: ");
	rprintfStr(rxdata);
	rprintfCRLF();
/*
	u08 c;
	u16 addr=0;

	while(1)
	{
		while(!uartReceiveByte(&c));

		switch(c)
		{
		case '+':
			addr+=64;
			break;
		case '-':
			addr-=64;
			break;
		}
		c = 0;
		txdata[0] = (addr>>8);
		txdata[1] = (addr&0x00FF);
		i2cMasterSendNI(TARGET_ADDR, 2, txdata);
		i2cMasterReceiveNI(TARGET_ADDR, 64, rxdata);
		rprintfProgStrM("Received data at ");
		rprintfu16(addr);
		rprintfProgStrM(":\r\n");
		debugPrintHexTable(64, rxdata);
	}
*/
}

void showByte(u08 byte)
{
	// set PORTB to output
	outb(DDRB, 0xFF);
	// output byte to LEDs
	outb(PORTB, ~byte);
}
