/* Rev:$Revision: 1.15 $ */
/*******************************************************************************
* Copyright 2006 NetBurner, Inc.  ALL RIGHTS RESERVED
*   Permission is hereby granted to purchasers of NetBurner hardware to use or
*   modify this computer program for any use as long as the resultant program
*   is only executed on NetBurner provided hardware.
*
*   No other rights to use this program or its derivatives in part or in whole
*   are granted.
*
*   It may be possible to license this or other NetBurner software for use on
*   non-NetBurner hardware. Please contact licensing@netburner.com for more
*   information.
*
*   NetBurner makes no representation or warranties with respect to the
*   performance of this computer program, and specifically disclaims any
*   responsibility for any damages, special or consequential, connected with
*   the use of this program.
*
*------------------------------------------------------------------------------
*
*   NetBurner, Inc.
*   5405 Morehouse Drive
*   San Diego, CA  92121
*   http://www.netburner.com
*
*   Information available at:  http://www.netburner.com
*   Support available at:      http://support.netburner.com
******************************************************************************/


#include "predef.h"
#include <basictypes.h>
#include "constants.h"
#include <system.h>
#include <ucos.h>
#include <ucosmcfc.h>
#include <cfinter.h>
#include "multichanneli2c.h"
#include <stdio.h>
#include <intcdefs.h>
#if ( defined MOD5270 ||  defined MOD5213 || defined MOD5282 || defined MOD5234 || defined PK70 || defined MCF52234 || defined MOD5441X | defined NANO54415 )
#include "pins.h"
#endif

#include "sim.h"

extern "C" 
{
#if ( defined MCF5270 || defined MCF5213 )
	void SetIntc( long func, int vector, int level, int prio );
#elif ( defined MCF5234 || defined MCF5282 )
	void SetIntc( int intc, long func, int vector, int level, int prio );
#elif  ( defined MCF5208 )
	void MCF5208SetIntc( long func, int vector, int level);
#elif  ( defined MCF52234 )
	void SetIntc0( long func, int vector, int level, int prio );
#elif  ( defined MCF5441X )
   void SetIntc(int intc, long func, int vector, int level);
#else
#error PROCESSOR_NOT_DEFINED   
#endif
}

// Call back functions that can be used when in slave mode.  Look at multichanneli2c.h for more info  
BYTE ( *I2C_SlaveTX_Callback )( );
void ( *I2C_SlaveTX_NAK_Callback )( );
void ( *I2C_SlaveRX_Callback )( BYTE RX_Data);   


volatile BYTE I2CSlaveRXBuf[I2C_MAX_BUF_SIZE+1];   // buffer used for receiving slave mode i2c data
volatile BYTE I2CSlaveTXBuf[I2C_MAX_BUF_SIZE+1];   // buffer used for sending slave mode i2c data
I2C_Slave_Record I2CSlaveRec;
I2C_Slave_Record * pI2CRec;

OS_SEM I2C_TX_Semaphore;          //semaphore used to determine when a master TX interrupt occurs
OS_SEM I2C_RX_Semaphore;          //semaphore used to determine when a master RX interrupt occurs

volatile BYTE INT_STATUS;           //status of last interrupt (10 will never happen)
extern volatile DWORD TimeTick;     //system ticks
volatile BYTE dummy;                //used for dummy reads
volatile bool bLastTX;              //boolean to tell when we have completed a master-TX
volatile BYTE RnW;                  //2 = Last TX was not address, 1 = RX request, 0 = TX request 
volatile bool bRestarted;           // Used in buf RX, TX functions to identify if we restarted
volatile bool bRestartSlaveTX = true;    // Tells Slave tx ISR what to do after TX finished

void I2CMultiChannelResetPeripheral(int);	//Defined at end


/*-----------------------------------------------------------------------
I2C structure selector
Called by all functions to point at existing sim structures
------------------------------------------------------------------------*/
volatile i2cstruct* i2cModuleSwitch(int moduleNum)
{
	switch(moduleNum)
	{
	case(0): return &sim2.i2c0;
	case(1): return &sim2.i2c1;
	case(2): return &sim1.i2c25[0];
	case(3): return &sim1.i2c25[1];
	case(4): return &sim1.i2c25[2];
	case(5): return &sim1.i2c25[3];
	default: return &sim2.i2c0;
	}
}  

/*-----------------------------------------------------------------------
I2C interrupt service routine.
Called by hardware when event occurs on I2C bus
------------------------------------------------------------------------*/
void I2C_MultiChannel_Isr(int moduleNum)
{
	register volatile i2cstruct* i2cModule = i2cModuleSwitch(moduleNum);
	I2C_SR &= 0xFD;  // clear interrupt flag

	//-------------------------------------------------------------------------------------------
	//         SLAVE MODE interrupts 
	//--------------------------------------------------------------------------------------------
	
	// Is I2C set to be in slave mode
	//-------------------------------
	if (I2C_CR_SLAVE)
	{
		// Did we lose a starting arbitration 
		//-----------------------------------
		if ( I2C_SR_ARB_LOST )  
		{
			I2C_CLR_ARB_LOST;
			I2C_SR &= 0xEF; //clear arbitration lost flag
			if (!I2C_SR_ADRES_AS_SLAVE)  //if we are not being addressed as a slave return
			{   
				INT_STATUS = I2C_LOST_ARB;
				OSSemPost( & I2C_TX_Semaphore ); // Post to pending semaphore
				return;
			}
			else  //We tried to get the bus but instead we were addressed
			{     //return and trigger another interrupt to complete slave transmission 
				INT_STATUS = I2C_LOST_ARB_ADD;
				OSSemPost( & I2C_TX_Semaphore ); // Post to pending semaphore
				return;
			}
		}// end Did we lose a starting arbitration 

		//-------------------------------------------------------------------------------------------

		// Did we get addressed as a slave 
		//-----------------------------------
		else if ( I2C_SR_ADRES_AS_SLAVE )  
		{
			// Are we being requested for a slave transmit
			//-------------------------------------------
			if ( I2C_SR_SLAVE_TX ) 
			{
				I2C_SET_TX;  //set to be in TX mode 
				if( I2C_SlaveTX_Callback )
				{
					I2C_DR = I2C_SlaveTX_Callback(); 
					return;
				}
				
				//if buffer is empty
				if( pI2CRec->I2Ctx_put == pI2CRec->I2Ctx_get )
				{
					I2C_DR = I2C_SLAVE_TX_TERM_CHAR;
					return;
				}  

				// write next byte to Master and increment pointer
				I2C_DR = pI2CRec->pI2CTxbuf[pI2CRec->I2Ctx_put++];     
				
				if(  (pI2CRec->I2Ctx_put == I2C_MAX_BUF_SIZE) &&
						(pI2CRec->I2Ctx_get != I2C_MAX_BUF_SIZE) )
				pI2CRec->I2Ctx_put = 0; 
				return;
			}
			
			// We are being requested for a slave recieve
			//-------------------------------------------
			else 
			{   
				for(volatile int x = 0; x<100; x++); // hardware bug fix
				I2C_SET_RX;          //set to be in RX mode 
				dummy = I2C_DR;  //Dummy Read to start Read
				return;
			}
		} // end Did we get addressed as a slave 

		//--------------------------------------------------------------------------------------------      

		// We are in the middle of a slave transmission 
		//---------------------------------------------
		else
		{
			// Are we Transmitting
			//--------------------
			if( I2C_CR_TX )
			{
				// If we recieved no Ack
				if( !I2C_SR_RX_ACK )                     
				{
					I2C_SET_RX;          //set to be in RX mode 
					dummy = I2C_DR;  //Dummy Read to release bus
					if( bRestartSlaveTX )
					{
						pI2CRec->I2Ctx_put = 0;                // Restart pointer
					}
					if( I2C_SlaveTX_NAK_Callback )
					I2C_SlaveTX_NAK_Callback();
					return;   
				}
				// Normal Slave TX data Transmission            
				else 
				{
					if( I2C_SlaveTX_Callback )
					{
						I2C_DR = I2C_SlaveTX_Callback();
						return;
					}
					
					//if buffer is empty
					if( pI2CRec->I2Ctx_put == pI2CRec->I2Ctx_get )
					{
						I2C_DR = I2C_SLAVE_TX_TERM_CHAR;
						return;
					}  

					// write next byte to Master and increment pointer
					I2C_DR = pI2CRec->pI2CTxbuf[pI2CRec->I2Ctx_put++];     
					
					if(  (pI2CRec->I2Ctx_put == I2C_MAX_BUF_SIZE) &&
							(pI2CRec->I2Ctx_get != I2C_MAX_BUF_SIZE) )
					pI2CRec->I2Ctx_put = 0;
					return;  
				}
			}
			
			// We Recieving
			//--------------------
			else
			{
				if( I2C_SlaveRX_Callback )
				{
					BYTE TempRead = I2C_DR;
					I2C_SlaveRX_Callback( TempRead );
					return;
				}
				
				// read next byte to buffer and increment pointer
				pI2CRec->pI2CRxbuf[pI2CRec->I2Crx_put++] = I2C_DR;     

				if ( pI2CRec->I2Crx_put == (I2C_MAX_BUF_SIZE+1) )
				{
					pI2CRec->I2Crx_put = 0;
				}
				if ( pI2CRec->I2Crx_put == pI2CRec->I2Crx_get )
				{
					pI2CRec->I2Crx_get++;
					if ( pI2CRec->I2Crx_get == (I2C_MAX_BUF_SIZE+1) )
					{
						pI2CRec->I2Crx_get = 0;
					}
				}
				else
				{
					OSSemPost( &pI2CRec->I2C_Slave_RX_Semaphore );
				}
				return;
			}
		} // end we are in the middle of a slave transmission
	} // end Are we are in slave mode

	//-------------------------------------------------------------------------------------------
	//         MASTER MODE interruptS 
	//--------------------------------------------------------------------------------------------

	// I2C set to be in master mode
	//-------------------------------
	else
	{
		// Are we Transmitting
		//--------------------
		if( I2C_CR_TX )
		{
			//Was the last TX a slave addressing
			if ( RnW != 2 )                 
			{
				if (!I2C_SR_RX_ACK)
				{
					INT_STATUS = I2C_NO_LINK_RX_ACK;
					OSSemPost( & I2C_TX_Semaphore ); // Post to pending tx semaphore
					return;
				}
				if( RnW )                        //addressed for a read event
				{   
					I2C_SET_RX;                   //set to be in RX mode 
					INT_STATUS = I2C_NEXT_READ_OK;
				}
				else                             //addressed for a write event
				INT_STATUS = I2C_NEXT_WRITE_OK;
				
				RnW = 2;
				OSSemPost( & I2C_TX_Semaphore ); // Post to pending tx semaphore
				return;
			}
			
			// Did we recieve a RX not ack or was last value sent
			else if ( bLastTX )  
			{
				bLastTX = false;
				INT_STATUS = I2C_MASTER_OK;
				OSSemPost( & I2C_TX_Semaphore ); // Post to pending tx semaphore
				return;
			}
			
			// Did we recieved no ack from the slave reciever
			else if (!I2C_SR_RX_ACK)
			{
				INT_STATUS = I2C_NO_LINK_RX_ACK;
				OSSemPost( & I2C_TX_Semaphore ); // Post to pending tx semaphore
				return;
			}

			//We are doing a standard master-TX
			else
			{
				INT_STATUS = I2C_NEXT_WRITE_OK;
				OSSemPost( & I2C_TX_Semaphore ); // Post to pending tx semaphore
				return;
			}
		}//end Are we transmitting master 

		//--------------------------------------------------------------------------------------------
		
		// We are Recieving
		//--------------------
		else
		{
			//We Just Recieved the last master RX byte since there was no RX ACK set
			if( !I2C_CR_RX_ACK )
			{
				I2C_SET_ACK;               // turn RX acks back on
				INT_STATUS = I2C_MASTER_OK;
			}
			else
			{
				INT_STATUS = I2C_NEXT_READ_OK;
			}
			OSSemPost( & I2C_RX_Semaphore ); // Post to pending RX semaphore
			return;
		}//end of master-RX
	}// end of master mode interrupts
}//end of i2c_int_routine

INTERRUPT( i2c0_multichannel_int_routine, 0x2600 )
{
	I2C_MultiChannel_Isr(0);
}

INTERRUPT( i2c1_multichannel_int_routine, 0x2600 )
{
	I2C_MultiChannel_Isr(1);
}

INTERRUPT( i2c2_multichannel_int_routine, 0x2600 )
{
	I2C_MultiChannel_Isr(2);
}

INTERRUPT( i2c3_multichannel_int_routine, 0x2600 )
{
	I2C_MultiChannel_Isr(3);
}

INTERRUPT( i2c4_multichannel_int_routine, 0x2600 )
{
	I2C_MultiChannel_Isr(4);
}

INTERRUPT( i2c5_multichannel_int_routine, 0x2600 )
{
	I2C_MultiChannel_Isr(5);
}


/*------------------------------------------------------------------------------------------
			END OF I2C interrupt ROUTINE
------------------------------------------------------------------------------------------*/


/*------------------------------------------------------------------------------------------
void I2CStop()

Will issue a stop signal if the module has master control of the I2C bus
And will release the bus if we are a slave device

returns nothing
*///////////////////////////////////////////////////////////////////////////////////
BYTE MultiChannel_I2CStop(int moduleNum, DWORD ticks_to_wait)
{
	register volatile i2cstruct* i2cModule = i2cModuleSwitch(moduleNum);
	ticks_to_wait = (ticks_to_wait + TimeTick); //timout tick is the current tick + offset 

	I2C_CR &= 0xDF;  // generate stop command

	while ( I2C_SR_BUSY )  //Keep checking for bus to go idle
	{
		if ( ticks_to_wait <= TimeTick )
		{
			INT_STATUS = I2C_BUS_NOT_AVAIL;
			return INT_STATUS;
		}
	}
	// else we freed the bus
	I2C_SET_ACK;            // make sure RX acks are still enable
	INT_STATUS = I2C_OK;
	return I2C_OK;
}


/*----------------------------------------------------------------------------
int I2CSend( BYTE val, DWORD ticks_to_wait = 5 );

Sends BYTE 'val' on the I2C bus
With a timeout of 'ticks_to_wait' 
Timeout will be value defined in header file if not included when function called

Returns the current state of the I2C bus
*///////////////////////////////////////////////////////////////////////////////////
BYTE MultiChannel_I2CSend( int moduleNum, BYTE val, DWORD ticks_to_wait)
{
	register volatile i2cstruct* i2cModule = i2cModuleSwitch(moduleNum);
	// Are we in a state capable of sending on the bus
	if(INT_STATUS != I2C_NEXT_WRITE_OK )         
	{
		BYTE I2CState = INT_STATUS;
		I2CMultiChannelResetPeripheral(moduleNum);
		I2CStop();                             // If not send stop or release bus
		return I2CState;                     // and return error
	}
	// We send the data and wait for the interrupt to post the semaphore
	I2C_DR = val;                
	if (OSSemPend(& I2C_TX_Semaphore, ticks_to_wait)==OS_TIMEOUT)
	{
		I2CStop();                 // Send stop or release bus
		I2CMultiChannelResetPeripheral(moduleNum);
		return I2C_TIMEOUT;        // and return error
	}
	return INT_STATUS;  // Successfully sent data
}

/*----------------------------------------------------------------------------
void I2CInit( BYTE slave_Addr = 0x08, BYTE freqdiv = 0x16 );  MCF5270, MCF5234 and MCF5208
void I2CInit( BYTE slave_Addr = 0x08, BYTE freqdiv = 0x15 );  MCF5213, MCF5282 and MCF52234

I2C initialization routine

Will assign 'slave_Addr' to be the address when module addressed by another 
master on the I2C bus.  Default Address if parameter not included is 0x08.
Phillips I2C Standard states that the two groups addresses 0000XXX and 1111XXX
are reserved for advanced purposes.  The addresses 11110XX are also reserved for
the 10-bit addressing I2C protocol.

FOR ALL MCF5270, MCF5234 and MCF5208 products:
System Bus Clock which = 150MHZ/2 divided by 'freqdiv' will give you the max baud rate
of the master mode I2C bus. Values of freqdiv are found in a the I2FDR table found in
the I2C section of the MCF5270 user manual provided by freescale.  0x16=768 which
gives a baud rate close to 100Kbits/s is the value set if parameter excluded

FOR ALL MCF5213, MCF5282 and MCF52234 products:
System Bus Clock which = 66MHZ divided by 'freqdiv' will give you the max baud rate
of the master mode I2C bus. Values of freqdiv are found in a the I2FDR table found in
the I2C section of the MCF5282 user manual provided by freescale.  0x15=640 which
gives a baud rate close to 100Kbits/s is the value set if parameter excluded

returns nothing 
*///////////////////////////////////////////////////////////////////////////////////
void MultiChannel_I2CInit( int moduleNum, BYTE slave_Addr, BYTE freqdiv )
{
	register volatile i2cstruct* i2cModule = i2cModuleSwitch(moduleNum);
	pI2CRec = &I2CSlaveRec;
	pI2CRec->pI2CRxbuf = I2CSlaveRXBuf;
	pI2CRec->pI2CTxbuf = I2CSlaveTXBuf;
	pI2CRec->I2Crx_put = 0;
	pI2CRec->I2Crx_get = 0;
	pI2CRec->I2Ctx_put = 0;
	pI2CRec->I2Ctx_get = 0;

#if ( defined MOD5270 ||  defined MOD5282 || defined MOD5234  )
	J2[39].function( PINJ2_39_SDA );  // Set Pins to I2C
	J2[42].function( PINJ2_42_SCL );
#elif ( defined MOD5213 )
	Pins[4].function( PIN4_SDA );
	Pins[5].function( PIN5_SCL );
#elif ( defined MCF5270 || defined MCF5208 || defined MCF5234 )
	sim.gpio.par_feci2c |= 0xF;
#elif ( defined MCF52234 )
	CPU_Pins[79].function( CPUPIN79_SCL );
	CPU_Pins[80].function( CPUPIN80_SDA );
#elif (defined MOD5441X)
	switch(moduleNum)
	{
		case(0):
		{
			J2[39].function( PINJ2_39_I2C0_SDA);  // Set Pins to I2C
			J2[42].function( PINJ2_42_I2C0_SCL);
			break;
		}
		case(1):
		{
			J2[41].function( PINJ2_41_I2C1_SDA);
			J2[44].function( PINJ2_44_I2C1_SCL);
			break;
		}
		case(2):
		{
			J2[17].function( PINJ2_17_I2C2_SDA);  // Set Pins to I2C
			J2[18].function( PINJ2_18_I2C2_SCL);
			break;
		}
		case(4):
		{
			J2[3].function( PINJ2_3_I2C4_SDA);
			J2[4].function( PINJ2_4_I2C4_SCL);
			break;
		}
		case(5):
		{
			J2[21].function( PINJ2_21_I2C5_SDA);
			J2[22].function( PINJ2_22_I2C5_SCL);
			break;
		}
		default:
		{
			J2[39].function( PINJ2_39_I2C0_SDA);  // Set Pins to I2C
			J2[42].function( PINJ2_42_I2C0_SCL);
			break;
		}
	}

#elif (defined NANO54415)
	switch(moduleNum)
	{
		case(0):
		{
			Pins[29].function( PIN_29_I2C0_SDA);  // Set Pins to I2C
			Pins[27].function( PIN_27_I2C0_SCL);
			break;
		}
		case(1):
		{
			Pins[20].function( PIN_20_I2C1_SDA);  // Set Pins to I2C
			Pins[22].function( PIN_22_I2C1_SCL);
			break;
		}
		case(4):
		{
			Pins[24].function( PIN_24_I2C4_SDA);  // Set Pins to I2C
			Pins[26].function( PIN_26_I2C4_SCL);
			break;
		}
		case(5):
		{
			Pins[32].function( PIN_32_I2C5_SDA);  // Set Pins to I2C
			Pins[34].function( PIN_34_I2C5_SCL);
			break;
		}
		default:
		{
			Pins[29].function( PIN_29_I2C0_SDA);  // Set Pins to I2C
			Pins[27].function( PIN_27_I2C0_SCL);
			break;
		}
	}
#else
#error PLATFORM_NOT_DEFINED_FOR_I2C_PIN_INIT
#endif   

	I2C_SR = 0;  //clears all interupts and previous i2c conditions
	I2C_CR = 0;  //clears all interupts and previous i2c conditions
	OSSemInit(& I2C_TX_Semaphore, 0);  //initialize interrupt semaphores
	OSSemInit(& I2C_RX_Semaphore, 0);  
	OSSemInit(&pI2CRec->I2C_Slave_RX_Semaphore, 0);

#if ( defined MCF5270 || defined MCF5213 )
	SetIntc( ( long ) &i2c_multichannel_int_routine, 17, 3 /* IRQ 3 */, 4 );
#elif ( defined MCF5234 || defined MCF5282 )
	SetIntc( 0, ( long ) &i2c_multichannel_int_routine, 17, 3 /* IRQ 3 */, 4 );
#elif  ( defined MCF5208 )
	MCF5208SetIntc(( long )&i2c_multichannel_int_routine, 30, 3 );
#elif  ( defined MCF52234 )
	SetIntc0( ( long ) &i2c_multichannel_int_routine, 17, 3 /* IRQ 3 */, 4  );
#elif  ( defined MCF5441X )
	switch(moduleNum)
		{
		case(0): SETUP_I2C0_ISR(&i2c0_multichannel_int_routine, 3); break;
		case(1): SETUP_I2C1_ISR(&i2c1_multichannel_int_routine, 3); break;
		case(2): SETUP_I2C2_ISR(&i2c2_multichannel_int_routine, 3); break;
		case(3): SETUP_I2C3_ISR(&i2c3_multichannel_int_routine, 3); break;
		case(4): SETUP_I2C4_ISR(&i2c4_multichannel_int_routine, 3); break;
		case(5): SETUP_I2C5_ISR(&i2c5_multichannel_int_routine, 3); break;
		default: SetIntc(0, ( long ) &i2c0_multichannel_int_routine, 30, 3 /* IRQ 3 */); break;
		}

#else 
#error PROCESSOR_NOT_DEFINED   
#endif
	//Initialization according to 22.6.1 in MCF5213 user manual

	//Step 1
	I2C_FDR = freqdiv;

	//Step 2
	I2C_ADR = (slave_Addr<<1);

	//Step 3
	I2C_CR = 0x80;

	if(I2C_SR_BUSY)
	{
		I2C_CR = 0x0;
		I2C_CR = 0xA0;
		volatile BYTE bv;
		bv = I2C_DR;
		I2C_SR = 0x0;
		I2C_CR = 0x0;
		I2C_CR = 0x80;
	}
	
	//Step 4
	I2C_CR = 0xC0;  //interupts, slave, ack
	return;

}


/*------------------------------------------------------------------------------
int I2CStart( BYTE addr, BOOL Read_Not_Write, DWORD ticks_to_wait = I2C_START_TIMEOUT);

Start of comunication with a slave device
'addr' is the address of the slave device we wish to comunicate with on the bus
'ticks_to_wait' is the amount of time we will wait for a start transmision to complete
this time includes waiting for a busy bus to become active plus the time it takes
to recieve an an ack from the slave device 
The timeout value defined in the header file will be used if function called without
ticks_to_wait parameter
'R/W' will select whether we will be read or write the next BYTE from slave.

returns the state of the communication on the bus
*///////////////////////////////////////////////////////////////////////////////////
//#define I2C_START_READ  ( 1 ) //defines to be used for bRead_Not_Write
//#define I2C_START_WRITE ( 0 )  
BYTE MultiChannel_I2CStart( int moduleNum, BYTE addr, bool bRead_Not_Write, DWORD ticks_to_wait)
{
	register volatile i2cstruct* i2cModule = i2cModuleSwitch(moduleNum);
	ticks_to_wait = (ticks_to_wait + TimeTick);  // tick when timeout will occur

	//setup address data to be written to slave on bus
	addr = (addr<<1);      //align address to fit R/W bit

	if(bRead_Not_Write)
	{
		addr |= 0x01;      //add a 1 in R/W position for read
		RnW = 1;          //tells interrupt what addressing is used
	}
	else
	{
		addr &= 0xFE;      //add a 0 in R/W position for write
		RnW = 0;          //tells interrupt what addressing is used
	}

	while ( I2C_SR_BUSY )  //Keep checking for bus to go idle
	{
		if ( ticks_to_wait <= TimeTick )
		{
			I2CMultiChannelResetPeripheral(moduleNum);
			INT_STATUS = I2C_BUS_NOT_AVAIL;
			return INT_STATUS;
		}
	}
	INT_STATUS = I2C_NEXT_WRITE_OK;  // OK to attempt send of slave address on bus
	I2C_CR = 0xF0;               //I2C set to: interrupt, master, transmit
	while ( !I2C_SR_BUSY )  //Keep checking for bus to go busy
	{
		if ( ticks_to_wait <= TimeTick )
		{
			I2CMultiChannelResetPeripheral(moduleNum);
			INT_STATUS = I2C_BUS_NOT_AVAIL;
			return INT_STATUS;
		}
	}
	BYTE I2CState;                   // Stores return values of NB I2C functions

	bool BadArb = true;              // Did we get good arbitration?

	while( BadArb )
	{
		//send slave address with remaining time
		I2CState = I2CSend(addr, (ticks_to_wait-TimeTick)); 
		
		//Did we lose arbitration and get addressed as a slave
		if ( I2CState == I2C_LOST_ARB_ADD )
		{   
			#if ( defined MCF5270 ||  defined MCF5213 )
			sim.intc.intfrcl |= (1 << 17); // Trigger interrupt to complete transfer as slave  
			#elif ( defined MCF5234 || MCF5282 || MCF52234 )    
			sim.intc[0].intfrcl |= (1 << 17); // Trigger interrupt to complete transfer as slave  
			#elif  ( defined MCF5208 )
			sim.intc.intfrcl |= (1 << 30); // Trigger interrupt to complete transfer as slave  
			#elif ( defined MCF5441X )
			switch(moduleNum)
			{
			case(0): sim2.intc[0].intfrcl |= (1 << 17); break;
			case(1): sim2.intc[1].intfrch |= (1 << 25); break;	//57
			case(2): sim2.intc[1].intfrch |= (1 << 26); break;	//58
			case(3): sim2.intc[1].intfrch |= (1 << 27); break;	//59
			case(4): sim2.intc[1].intfrch |= (1 << 28); break;	//60
			case(5): sim2.intc[1].intfrch |= (1 << 29); break;	//61
			default: sim2.intc[0].intfrcl |= (1 << 17); break;
			}
			#else
			#error intfrcl trigger missing for defined platform
			#endif
			
			return I2C_LOST_ARB_ADD;
		}
		
		// Was arbitration OK
		else if ( I2CState != I2C_LOST_ARB )
		BadArb = false;      // exit while loop since good arbitration           
		
		// we lost arbitration but NOT addressed as slave
		else                         
		{
			while ( I2C_SR_BUSY )  //Keep checking for bus to go idle
			{
				if ( ticks_to_wait <= TimeTick )
				{
					I2CMultiChannelResetPeripheral(moduleNum);
					return I2C_BUS_NOT_AVAIL;
				}     
			}     
			INT_STATUS = I2C_NEXT_WRITE_OK;  // OK to attempt send of slave address on bus
			I2C_CR = 0xF0;               //I2C set to: interrupt, master, transmit
			
		}      
	}
	return INT_STATUS;                     //Return the last interrupt status
}

/*------------------------------------------------------------------------------
int I2CRestart( BYTE addr, BOOL Read_Not_Write, DWORD ticks_to_wait = I2C_RX_TX_TIMEOUT);

Restart of comunication with a slave device after finished communincation on the bus
This is used instead of a 'stop' and will allow user to communicate on bus again without
giving up control of the bus first.
'addr' is the address of the slave device we wish to comunicate with on the bus
'ticks_to_wait' is the amount of time we will wait for a start transmision to complete
this time includes the time it takes to recieve an an ack from the addressed slave device 
The timeout value defined in the header file will be used if function called without
ticks_to_wait parameter
'R/W' will select whether we will be read or write the next BYTE from slave

returns the state of the communication on the bus
*///////////////////////////////////////////////////////////////////////////////////
//#define I2C_START_READ  ( 1 ) //defines to be used for bRead_Not_Write
//#define I2C_START_WRITE ( 0 )  
BYTE MultiChannel_I2CRestart( int moduleNum, BYTE addr, bool bRead_Not_Write, DWORD ticks_to_wait )
{
	register volatile i2cstruct* i2cModule = i2cModuleSwitch(moduleNum);
	if ( I2C_CR_SLAVE ) // if we are the master fail
	return I2C_NOT_READY;

	bRestarted = true; // used in buf send functions

	//setup address data to be written to slave on bus
	addr = (addr<<1);      //align address to fit R/W bit

	if(bRead_Not_Write)
	{
		addr |= 0x01;      //add a 1 in R/W position for read
		RnW = 1;          //tells interrupt what addressing is used
	}
	else
	{
		addr &= 0xFE;      //add a 0 in R/W position for write
		RnW = 0;          //tells interrupt what addressing is used
	}

	INT_STATUS = I2C_NEXT_WRITE_OK;  // OK to attempt send of slave address on bus
	I2C_SET_REPEAT_START;
	//send slave address with remaining time
	//INT_STATUS = I2CSend(addr, (ticks_to_wait-TimeTick));   // modified 3/27/2012
	INT_STATUS = I2CSend( addr, ticks_to_wait ); 
	return INT_STATUS;
}

/*----------------------------------------------------------------------------
int I2CRead( PBYTE val, DWORD ticks_to_wait = I2C_RX_TX_TIMEOUT);

Reads BYTE to address 'val' from the I2C bus
With a timeout of 'ticks_to_wait'
Timeout will be value defined in header file if not included when function called
Does not handle no Ack of last byte which
needs to have a I2C_SET_NO_ACK called before second to last read
The ISR will automatically re-enable the ACK
The I2C on this processor also requires that a stop or I2C_SET_TX
be called before the last read or an extra byte will be read
The last read should then be directly pulled from the i2c dr register
since it will not generate an interrupt.

Returns the current state of the I2C bus
*///////////////////////////////////////////////////////////////////////////////////
BYTE MultiChannel_I2CRead( int moduleNum, PBYTE val, DWORD ticks_to_wait )
{
	register volatile i2cstruct* i2cModule = i2cModuleSwitch(moduleNum);
	// Are we in a state capable of reading from the bus
	if(INT_STATUS != I2C_NEXT_READ_OK )         
	{
		I2CMultiChannelResetPeripheral(moduleNum);
		I2CStop();                             // If not send stop or release bus
		return I2C_NOT_READY;                  // and return error
	}

	// We read the data and wait for the interrupt to post the semaphore
	*val = I2C_DR;                
	if (OSSemPend( &I2C_RX_Semaphore, ticks_to_wait)==OS_TIMEOUT)
	{
		I2CMultiChannelResetPeripheral(moduleNum);
		I2CStop();                 // Send stop or release bus
		return I2C_TIMEOUT;        // and return error
	}
	return INT_STATUS;  // Successfully sent data
}

/*----------------------------------------------------------------------------
int I2CSendBuf(BYTE addr, PBYTE buf, int count, bool stop = true);

Sends 'num' BYTES of buffer 'buf' on the I2C bus to address 'addr' 
The transmission is then terminated with a stop signal if user either calls
the function with no 'stop' parameter or a stop = true.  If user wishes to terminate
differently such as a restart then 'stop' can be set false and a NetBurner advanced
I2Cfunction can be used for termination.

returns the result state of the I2C bus
*///////////////////////////////////////////////////////////////////////////////////
BYTE MultiChannel_I2CSendBuf( int moduleNum, BYTE addr, PBYTE buf, int num, bool stop)
{
	register volatile i2cstruct* i2cModule = i2cModuleSwitch(moduleNum);
	BYTE I2CState;                                  // Stores return values of NB I2C functions
	if(!bRestarted)                    // Dont start again if we just restarted
	I2CStart( addr, I2C_START_WRITE );   // Attempt to master I2C bus for write
	else
	bRestarted=false;
	I2CState = INT_STATUS;
	if (I2CState != I2C_NEXT_WRITE_OK)              // If we dont control the bus return
	{   
		I2CMultiChannelResetPeripheral(moduleNum);
		I2CStop();
		return I2CState;
	}
	while (num > 1)                               // write up to 2nd to last byte
	{
		num--;
		I2CState = I2CSend( *buf++);
		if (I2CState != I2C_NEXT_WRITE_OK)           // If send failed give up bus and return
		{
			I2CMultiChannelResetPeripheral(moduleNum);
			I2CStop();
			return I2CState;
		}
	}
	bLastTX = true;                                 //Send last byte
	I2CState = I2CSend( *buf);
	if (I2CState != I2C_MASTER_OK)                  // If send failed give up bus and return
	{
		I2CMultiChannelResetPeripheral(moduleNum);
		I2CStop();
		return I2CState;
	}
	if( stop )
	{                                      // terminate with stop?
		I2CState = I2CStop();
	}
	return I2CState;
}

/*----------------------------------------------------------------------------
int I2CReadBuf(BYTE addr, PBYTE buf, int count, bool stop = true);

Reads 'num' BYTES of buffer 'buf' on the I2C bus to address 'addr' 
The transmission is then terminated with a stop signal if user either calls
the function with no 'stop' parameter or a stop = true.  If user wishes to terminate
differently such as a restart then 'stop' can be set false and a NetBurner advanced
I2Cfunction can be used for termination.

returns the result state of the I2C bus
*///////////////////////////////////////////////////////////////////////////////////
BYTE MultiChannel_I2CReadBuf( int moduleNum, BYTE addr, PBYTE buf, int num, bool stop)
{
	register volatile i2cstruct* i2cModule = i2cModuleSwitch(moduleNum);
	BYTE I2CState;                               // Stores return values of NB I2C functions
	if(!bRestarted)                              // Dont start again if we just restarted
	I2CStart( addr, I2C_START_READ ); // Attempt to master I2C bus for read
	else
	bRestarted=false;
	I2CState = INT_STATUS;
	if (I2CState != I2C_NEXT_READ_OK)            // If we dont control the bus return
	{
		I2CMultiChannelResetPeripheral(moduleNum);
		I2CStop();
		return I2CState;
	}       
	
	if( num == 1 )
	I2C_SET_NO_ACK;                              //no ack for last byte read
	I2CRead(buf);
	while (num > 1)                            // Read up to 2nd to last byte
	{
		if( num == 2 )
		I2C_SET_NO_ACK;                              //no ack for last byte read
		num--;
		I2CState = I2CRead(buf++);
		if ( (I2CState != I2C_NEXT_READ_OK) && (I2CState != I2C_MASTER_OK))         // If read failed give up bus and return
		{
			I2CMultiChannelResetPeripheral(moduleNum);
			I2CStop();
			return I2CState;
		}
	}
	I2C_SET_TX;
	*buf = I2C_DR;   // Last read
	if (I2CState != I2C_MASTER_OK)               // If read failed give up bus and return
	{
		I2CMultiChannelResetPeripheral(moduleNum);
		I2CStop();
		return I2CState;
	}
	if( stop ) 
	{                                  // terminate with stop?
		I2CStop();
		I2CState = I2C_OK;
	}
	return I2CState;
}

/*----------------------------------------------------------------------------
bool I2CFillSlaveTXBuf(PBYTE buf, DWORD num, bool restart = true);

This will put the first 'num' BYTES from the buffer 'buf' into the 
I2C Slave TX buffer and clear the previously-read contents of the buffer.
The 'restart' parameter tells the slave transmitter how to terminate 
if 'restart' = true then restart next tx from begining TX buffer (A new slave fill replaces buffer);
if 'false' continue next tx from last slave tx,(A new slave fill adds to buffer at last read byte);
In I2C multi.h there is a I2C_SLAVE_TX_TERM_CHAR defined that will decide the terminating char (if any) to send 
when the slave tx buffer is empty

returns false if failed to copy data
*///////////////////////////////////////////////////////////////////////////////////
#define TX_FILL_OK       (0)
#define NOT_ENOUGH_SPACE (1)
BYTE I2CFillSlaveTXBuf(PBYTE buf, DWORD num, bool restart)
{
	if(restart)
	{
		if( num > I2C_MAX_BUF_SIZE)
		return NOT_ENOUGH_SPACE;
		
		USER_ENTER_CRITICAL();           // Enter a critical section to copy TX data
		bRestartSlaveTX = restart;
		for(DWORD i=0; i<num; i++)
		pI2CRec->pI2CTxbuf[i] = buf[i];    // fill buffer with data
		pI2CRec->I2Ctx_put = 0;             // reset the pointer
		pI2CRec->I2Ctx_get = num;  
		USER_EXIT_CRITICAL();            
	}
	else
	{
		if( I2CTXAvail() < num)
		return NOT_ENOUGH_SPACE;
		USER_ENTER_CRITICAL();           // Enter a critical section to copy TX data
		bRestartSlaveTX = restart;
		for(DWORD i=0; i<num; i++)
		{
			pI2CRec->pI2CTxbuf[pI2CRec->I2Ctx_get++] = buf[i];    // fill buffer with data
			if(pI2CRec->I2Ctx_get == I2C_MAX_BUF_SIZE)
			pI2CRec->I2Ctx_get = 0;
		}  
		USER_EXIT_CRITICAL();
	}   
	return TX_FILL_OK;
}


/*----------------------------------------------------------------------------
BYTE I2CGetByte();

This function will pend on a slave recieve I2C semaphore

returns last unread BYTE recieved as a I2C Slave
*///////////////////////////////////////////////////////////////////////////////////
BYTE I2CGetByte()
{
	OSSemPend( &pI2CRec->I2C_Slave_RX_Semaphore, 0 );
	BYTE ret = pI2CRec->pI2CRxbuf[pI2CRec->I2Crx_get++];
	if ( pI2CRec->I2Crx_get == (I2C_MAX_BUF_SIZE+1) )
	pI2CRec->I2Crx_get = 0;
	return ret;
}

/*----------------------------------------------------------------------------
bool I2CRXAvail();

This function returns true if data is available in the Slave RX buffer
*///////////////////////////////////////////////////////////////////////////////////
bool I2CRXAvail()
{
	if( pI2CRec->I2Crx_get != pI2CRec->I2Crx_put )
	return true;
	return false;
}

/*----------------------------------------------------------------------------
DWORD I2CTXAvail();

returns amount of free space available in Slave TX buffer
*///////////////////////////////////////////////////////////////////////////////////
DWORD I2CTXAvail()
{
	if (pI2CRec->I2Ctx_get > pI2CRec->I2Ctx_put)
	return (pI2CRec->I2Ctx_get - pI2CRec->I2Ctx_put );
	return ((I2C_MAX_BUF_SIZE -  pI2CRec->I2Ctx_put) + pI2CRec->I2Ctx_get );
}

void I2CMultiChannelResetPeripheral(int moduleNum)
{
	register volatile i2cstruct* i2cModule = i2cModuleSwitch(moduleNum);
	I2C_CR = 0;  //clears all interupts and previous i2c conditions
	I2C_SR = 0;  //clears all interupts and previous i2c conditions
	I2C_CR = 0x80;

	if(I2C_SR_BUSY)
	{
		I2C_CR = 0x0;
		I2C_CR = 0xA0;
		volatile BYTE bv;
		bv = I2C_DR;
		I2C_SR = 0x0;
		I2C_CR = 0x0;
		I2C_CR = 0x80;
	}

	I2C_CR = 0xC0;  //interupts, slave, ack
	return;
}




