/*
 * twi_master.c
 *
 *  Created on: Oct, 2010
 *      Author: fouedjio
 */
#include <stdint.h>
#include <stdio.h>
#include <string.h> 
#include <stddef.h>
#include <math.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/iocan128.h>
#include <avr/iocanxx.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <avr/wdt.h>
#include "api_define.h"
#include "api_global.h"
#include "twi_master.h"
#include "delay.h"
#include "api.h"

/****************************************************************************
 TWI State codes
 ****************************************************************************/
// General TWI Master staus codes                      
#define TWI_START				    0x08  // START has been transmitted
#define TWI_REP_START				0x10  // Repeated START has been transmitted
#define TWI_ARB_LOST				0x38  // Arbitration lost
// TWI Master Transmitter staus codes                      
#define TWI_MTX_ADR_ACK				0x18  // SLA+W has been tramsmitted and ACK received
#define TWI_MTX_ADR_NACK			0x20  // SLA+W has been tramsmitted and NACK received 
#define TWI_MTX_DATA_ACK			0x28  // Data byte has been tramsmitted and ACK received
#define TWI_MTX_DATA_NACK			0x30  // Data byte has been tramsmitted and NACK received 
// TWI Master Receiver staus codes  
#define TWI_MRX_ADR_ACK				0x40  // SLA+R has been tramsmitted and ACK received
#define TWI_MRX_ADR_NACK			0x48  // SLA+R has been tramsmitted and NACK received
#define TWI_MRX_DATA_ACK			0x50  // Data byte has been received and ACK tramsmitted
#define TWI_MRX_DATA_NACK			0x58  // Data byte has been received and NACK tramsmitted
// TWI Slave Transmitter staus codes
#define TWI_STX_ADR_ACK				0xA8  // Own SLA+R has been received; ACK has been returned
#define TWI_STX_ADR_ACK_M_ARB_LOST	0xB0  // Arbitration lost in SLA+R/W as Master; own SLA+R has been received; ACK has been returned
#define TWI_STX_DATA_ACK			0xB8  // Data byte in TWDR has been transmitted; ACK has been received
#define TWI_STX_DATA_NACK			0xC0  // Data byte in TWDR has been transmitted; NOT ACK has been received
#define TWI_STX_DATA_ACK_LAST_BYTE	0xC8  // Last data byte in TWDR has been transmitted (TWEA = �0�); ACK has been received
// TWI Slave Receiver staus codes
#define TWI_SRX_ADR_ACK				0x60  // Own SLA+W has been received ACK has been returned
#define TWI_SRX_ADR_ACK_M_ARB_LOST	0x68  // Arbitration lost in SLA+R/W as Master; own SLA+W has been received; ACK has been returned
#define TWI_SRX_GEN_ACK				0x70  // General call address has been received; ACK has been returned
#define TWI_SRX_GEN_ACK_M_ARB_LOST	0x78  // Arbitration lost in SLA+R/W as Master; General call address has been received; ACK has been returned
#define TWI_SRX_ADR_DATA_ACK		0x80  // Previously addressed with own SLA+W; data has been received; ACK has been returned
#define TWI_SRX_ADR_DATA_NACK		0x88  // Previously addressed with own SLA+W; data has been received; NOT ACK has been returned
#define TWI_SRX_GEN_DATA_ACK		0x90  // Previously addressed with general call; data has been received; ACK has been returned
#define TWI_SRX_GEN_DATA_NACK		0x98  // Previously addressed with general call; data has been received; NOT ACK has been returned
#define TWI_SRX_STOP_RESTART		0xA0  // A STOP condition or repeated START condition has been received while still addressed as Slave
// TWI Miscellaneous status codes
#define TWI_NO_STATE		        0xF8  // No relevant state information available; TWINT = �0�
#define TWI_BUS_ERROR			    0x00  // Bus error due to an illegal START or STOP condition

/*

 * Public Function: Write_to_slave
 * Purpose: Write byte(s) to the slave.
 * It is implicitly assumed, that the slave will
 * accepts 8 bytes
 * Input Parameter: structure
 * Return Value: None

 */

void Write_to_slave(struct uartStruct *ptr_uartStruct)
{
	{
		snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("DEBUG (%4i, %s) address is:0x%x"), __LINE__, __FILE__, ptr_uartStruct->Adresse);
		UART0_Send_Message_String(NULL,0);
	}

	if (!Twim_Start(ptr_uartStruct->Adresse, TWIM_WRITE))
	{
		Twim_Stop();

		twi_errorCode = CommunicationError(ERRT, TWI_ERROR_Could_not_start_TWI_Bus_for_WRITE, 0, NULL, 0);
	}
	else
	{
	    /*if 1 // (eventDebugVerbose <= debug && ( ( debugMask >> debugTWI ) & 0x1 ) )*/
		{
			snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("DEBUG (%4i, %s) writing data"), __LINE__, __FILE__);
			UART0_Send_Message_String(NULL,0);
		}


		for (uint8_t i = 0; i < ptr_uartStruct->Uart_Length; i++)
		{
			Twim_Write(ptr_uartStruct->Uart_Data[i]);
		}
		Twim_Stop();
#warning ist das notwendig?
		//		Delay_ms(1000);
	   if ( verboseDebug <= debug && (debugMask >> debugMain) & 0x1 )
	   {
#warning replace by createRecvHeader also in can.c
		   snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("RECV %s"), READY);
		   UART0_Send_Message_String(NULL, 0);
	   }
	}
}

/*
 * Public Function: read_to_slave
 * Purpose: Read byte(s) from the slave
 * It is implicitly assumed, that the slave will send
 * 8 bytes
 * Input Parameter: structure
 * Return Value: None
 */

void Read_to_slave(struct uartStruct *ptr_uartStruct)
{
	uint8_t i;
	static uint32_t maxTwiData = (sizeof(twiData)/sizeof(uint8_t));

	if (!Twim_Start(ptr_uartStruct->Adresse, TWIM_READ))
	{
		Twim_Stop();
		twi_errorCode = CommunicationError(ERRT, TWI_ERROR_Could_not_start_TWI_Bus_for_READ, 0, NULL, 0);
	}
	else
	{
	    //if 1 // (eventDebugVerbose <= debug && ( ( debugMask >> debugTWI ) & 0x1 ) )
		{
			snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("DEBUG (%4i, %s) reading data"), __LINE__, __FILE__);			UART0_Send_Message_String(NULL,0);
		}

		for (i = 0; i < ptr_uartStruct->Uart_Length -1 && i < maxTwiData -1 ; i++)
		{
			twiData[i] = Twim_ReadAck();
		}
		twiData[i] = Twim_ReadNack();
		Twim_Stop();

#warning ist das notwendig?
//		Delay_ms(1000);

		clearString(twiString, MAX_LENGTH_TWI_DATA); /*clear the variable temp_twiString*/

		for (i = 0; i < ptr_uartStruct->Uart_Length -1 && i < maxTwiData -1 ; i++)
		{
			snprintf_P(twiString, BUFFER_SIZE - 1, PSTR("%s%x "), twiString, twiData[i]);
		}
		snprintf_P(twiString, BUFFER_SIZE - 1, PSTR("%s%x"), twiString, twiData[i]);

#warning replace by createRecvHeader also in can.c
		snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("RECV %s"), twiString);
		UART0_Send_Message_String(NULL, 0);
	}
}

/*
 * Public Function: Twim_Init
 * Purpose: Initialise the TWI Master Interface
 * Input Parameter:
 * uint16_t	TWI_Bitrate (Hz)
 * Return Value: uint8_t
 *	- FALSE:	Bitrate too high
 *	- TRUE:		Bitrate OK
 */

uint8_t Twim_Init(uint32_t TWI_Bitrate)
{
	/* Set TWI bitrate, if bitrate is too high, then error return*/
	TWBR = ((F_CPU / TWI_Bitrate) - 16) / 2;
	if (TWBR < 11)
	{
		return FALSE;
	}
	return TRUE;
}

/*
 * Public Function: Twim_Stop
 * Purpose: Stop the Twi Master
 * Input Parameter: None
 * Return Value: None
 */

void Twim_Stop(void)
{
	/*Send stop condition*/

	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);

	/* Wait until stop condition is executed and bus released*/
	while (TWCR & (1 << TWINT)) {;}
}

/*
 * Public Function: TWIM_Start
 * Purpose: Start the TWI Master Interface
 * Input Parameter:
 - uint8_t	Device address
 - uint8_t	Type of required Operation:
            Twim_READ : Read  data from the slave
            Twim_WRITE: Write data to the slave
 * Return Value: uint8_t
 - TRUE:	OK, TWI Master accessible
 - FALSE:	Error in starting TWI Master
 */

uint8_t Twim_Start(uint8_t Address, uint8_t TWIM_Type)
{
	uint8_t twst;
	/*Send START condition*/
	TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWIE);

	/*Wait until transmission completed*/
	while (!(TWCR & (1 << TWINT)));

	/* Check value of TWI Status Register. Mask prescaler bits.*/
	twst = TWSR & 0xF8;
	if ((twst != TWI_START) && (twst != TWI_REP_START))
		return FALSE;

	/* Send device address*/
	TWDR = ((ptr_uartStruct->Adresse) << 1) + TWIM_Type;
	TWCR = (1 << TWINT) | (1 << TWEN);

	/*Wait until transmission completed and ACK/NACK has been received*/
	while (!(TWCR & (1 << TWINT))) ;

	/*Check value of TWI Status Register. Mask prescaler bits.*/
	twst = TWSR & 0xF8;
	if ((twst != TWI_MTX_ADR_ACK) && (twst != TWI_MRX_ADR_ACK))
		return FALSE;

	return TRUE;
}

/*
 * Public Function: Twim_Write
 * Purpose: Write a byte to the slave
 * Input Parameter:
 - uint8_t	Byte to be sent
 * Return Value: uint8_t
 - TRUE:		OK, Byte sent
 - FALSE:	Error in byte transmission

 */

uint8_t Twim_Write(uint8_t byte)
{
	uint8_t twst;

	/* Send data to the previously addressed device*/
	TWDR = byte;
	TWCR = (1 << TWINT) | (1 << TWEN);

	/*Wait until transmission completed*/
	while (!(TWCR & (1 << TWINT)));

	/* Check value of TWI Status Register. Mask prescaler bits*/
	twst = TWSR & 0xF8;
	if (twst != TWI_MTX_DATA_ACK) return 1;

	return 0;
}

/*
 * Public Function: Twim_ReadAck
 * Purpose: Read a byte from the slave and request next byte
 * Input Parameter: None
 * Return Value: uint8_t
 - uint8_t	Read byte
 */

uint8_t Twim_ReadAck(void)
{
	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
	while (!(TWCR & (1 << TWINT))) {};

	return TWDR;
}

/*
 * Public Function: Twim_ReadAck
 * Purpose: Read the last byte from the slave
 * Input Parameter: None
 * Return Value: uint8_t
 - uint8_t	Read byte
 */
uint8_t Twim_ReadNack(void)
{
	TWCR = (1 << TWINT) | (1 << TWEN);
	while (!(TWCR & (1 << TWINT)))
		;

	return TWDR;
}

