/******************************************************************************
** Copyright 2015 MBARI - Monterey Bay Aquarium Research Institute
*******************************************************************************
*******************************************************************************
** Summary  : Routines to control PCAL6416A 16 Bit I/O Expander
** Filename : pcal6416.c
** Author   : Luke Coletti
** Project  :
** Version  : 1.0
** Compiler : MetroWerks Code Warrior v8.3
** Created  : 12/15/14
** Archived :
*******************************************************************************
** Modification History:
** 01/02/15 : CF2 Port, LJC
*******************************************************************************/

#include        <cfxbios.h>             // Persistor BIOS and I/O Definitions
#include	<io_i2c.h>
#include	<io_regs.h>
#include        <pcal6416.h>


int PCAL6416_Init( void )
{
	int ret;

	PCAL6416_Reset();

	I2C_Select( I2C_BUS_SYS );

	I2C_Start();                                            //I2C Start (S)
	ret = I2C_WrByte( PCAL6416_ADDR_WR );      				//Send Slave Addr to Wr
	ret &= I2C_WrByte( PCAL6416_OUTCONFIG_REG ); 			//Send Command Byte (Reg Address)
	ret &= I2C_WrByte( PCAL6416_OUTCONFIG_VAL ); 			//Init Port Configuration (push-pull or open-drain) of GPIO
	I2C_Start();                                            //I2C Restart (Sr)	
	ret &= I2C_WrByte( PCAL6416_ADDR_WR );      			//Send Slave Addr to Wr
	ret &= I2C_WrByte( PCAL6416_OUTPUT_PORT0 ); 			//Send Command Byte (Reg Address)
	ret &= I2C_WrByte( PCAL6416_OUTPUT_VAL0 );  			//Output Port0 Default Pin States
	I2C_Start();                                            //I2C Restart (Sr)
	ret &= I2C_WrByte( PCAL6416_ADDR_WR );          		//Send Slave Addr to Wr
	ret &= I2C_WrByte( PCAL6416_CONFIG_REG0 );  			//Send Command Byte (Reg Address)
	ret &= I2C_WrByte( PCAL6416_CONFIG_VAL0 );  			//Init Data Direction of GPIO
	ret &= I2C_WrByte( PCAL6416_CONFIG_VAL1 );  			//Init Data Direction of GPIO
	I2C_Start();                                    		//I2C Restart (Sr)
	ret &= I2C_WrByte( PCAL6416_ADDR_WR );          		//Send Slave Addr to Wr
	ret &= I2C_WrByte( PCAL6416_PULLENB_REG0 ); 			//Send Command Byte (Reg Address)
	ret &= I2C_WrByte( PCAL6416_PULLENB_VAL0 );     		//Init Port Pull-Up/Down Enable
	ret &= I2C_WrByte( PCAL6416_PULLENB_VAL1 ); 			//Init Port Pull-Up/Down Enable
	I2C_Stop();                                     		//I2C Stop (P)

	I2C_Select( I2C_BUS_DISABLE );

	//ret &= PCAL6416_WritePortDefaults();                    //Init GPIO Outputs to Default State

	if( ret != I2C_ACK )									//If device ACK'd every transmitted byte, then we're in good shape
		ret = ERROR;

	return( ret );											//Return I2C Transfer Status


}


int PCAL6416_WritePortDefaults( void )
{
	int ret;

	I2C_Select( I2C_BUS_SYS );

	I2C_Start();                                    //I2C Start (S)
	ret =  I2C_WrByte( PCAL6416_ADDR_WR );      //Send Slave Addr to Wr
	ret &= I2C_WrByte( PCAL6416_OUTPUT_PORT0 ); //Send Command Byte (Reg Address)
	ret &= I2C_WrByte( PCAL6416_OUTPUT_VAL0 );  //Output Port0 Default Pin States
	I2C_Stop();                                     //I2C Stop (P)

	I2C_Select( I2C_BUS_DISABLE );

	if( ret != I2C_ACK )                                                    //If device ACK'd every transmitted byte, then we're in good shape
		ret = ERROR;

	return( ret );                                                                  //Return I2C Transfer Status

}


int PCAL6416_ReadPort(uchar Port, uchar *Data)
{
	int ret;

	I2C_Select( I2C_BUS_SYS );

	I2C_Start();                                    //I2C Start (S)
	ret =  I2C_WrByte( PCAL6416_ADDR_WR );          //Send Slave Addr to Wr
	ret &= I2C_WrByte( Port );                      //Send Command Byte
	I2C_Start();                                    //I2C Restart (Sr)
	ret &= I2C_WrByte( PCAL6416_ADDR_RD );          //Send Slave Addr to Rd
	I2C_RdByte( Data );
	I2C_WrNak();
	I2C_Stop();                                                                     //I2C Stop (P)

	I2C_Select( I2C_BUS_DISABLE );

	if( ret != I2C_ACK )                                                    //If device ACK'd every transmitted byte, then we're in good shape
		ret = ERROR;

	return( ret );                                                                  //Return I2C Transfer Status

}


int PCAL6416_ReadPorts(uchar Port0, uchar *Data0, uchar *Data1)
{
	int ret;

	I2C_Select( I2C_BUS_SYS );

	I2C_Start();                                    //I2C Start (S)
	ret =  I2C_WrByte( PCAL6416_ADDR_WR );      //Send Slave Addr to Wr
	ret &= I2C_WrByte( Port0 );                 //Send Command Byte (Reg0 address associates with Data0 data)
	I2C_Start();                                    //I2C Restart (Sr)
	ret &= I2C_WrByte( PCAL6416_ADDR_RD );      //Send Slave Addr to Rd
	I2C_RdByte( Data0 );
	I2C_WrAck();
	I2C_RdByte( Data1 );
	I2C_WrNak();
	I2C_Stop();                                                                     //I2C Stop (P)

	I2C_Select( I2C_BUS_DISABLE );

	if( ret != I2C_ACK )                                                    //If device ACK'd every transmitted byte, then we're in good shape
		ret = ERROR;

	return( ret );                                                                  //Return I2C Transfer Status

}


int PCAL6416_WritePort(uchar Port, uchar Data)
{
	int ret;

	if( (Port != PCAL6416_OUTPUT_PORT0) && (Port != PCAL6416_OUTPUT_PORT1) )
		return( ERROR );

	I2C_Select( I2C_BUS_SYS );

	I2C_Start();                                    //I2C Start (S)
	ret =  I2C_WrByte( PCAL6416_ADDR_WR );      //Send Slave Addr to Wr
	ret &= I2C_WrByte( Port );                  //Send Command Byte (GPIO Address)
	ret &= I2C_WrByte( Data );                      //Send Data (GPIO Data)
	I2C_Stop();                                     //I2C Stop (P)

	I2C_Select( I2C_BUS_DISABLE );

	if( ret != I2C_ACK )                                                    //If device ACK'd every transmitted byte, then we're in good shape
		ret = ERROR;

	return( ret );                                                                  //Return I2C Transfer Status

}


int PCAL6416_WritePortBit(uchar Port, uchar Bitval, uchar State)
{
	uchar Data;
	int ret;

	if( (Port != PCAL6416_OUTPUT_PORT0) && (Port != PCAL6416_OUTPUT_PORT1) )
		return( ERROR );

	if( (State != HIGH) && (State != LOW) )
		return( ERROR );


	I2C_Select( I2C_BUS_SYS );

	I2C_Start();                                    //I2C Start (S)
	ret =  I2C_WrByte( PCAL6416_ADDR_WR );      //Send Slave Addr to Wr
	ret &= I2C_WrByte( Port-PCAL6416_RD_OFFSET ); //Send Command Byte (Offset Passed Output Port/Reg Addr to Matching Input Port/Reg Addr)
	I2C_Start();                                    //I2C Restart (Sr)
	ret &= I2C_WrByte( PCAL6416_ADDR_RD );      //Send Slave Addr to Rd
	I2C_RdByte( &Data );
	I2C_WrNak();
	I2C_Stop();                                     //I2C Stop (P)

	if( State == HIGH )
		Data |= Bitval;
	else
		Data &= ~Bitval;

	I2C_Start();                                    //I2C Start (S)
	ret &= I2C_WrByte( PCAL6416_ADDR_WR );          //Send Slave Addr to Wr
	ret &= I2C_WrByte( Port );                      //Send Command Byte (GPIO Address)
	ret &= I2C_WrByte( Data );                      //Send Data (GPIO Data)
	I2C_Stop();                                     //I2C Stop (P)

	I2C_Select( I2C_BUS_DISABLE );

	if( ret != I2C_ACK )                                                    //If device ACK'd every transmitted byte, then we're in good shape
		ret = ERROR;

	return( ret );                                                                  //Return I2C Transfer Status

}

void PCAL6416_Reset( void )
{

	RegIO_SetBit( SYS_I2C_RST );
	Delay500us();
	RegIO_ClrBit( SYS_I2C_RST );
	Delay500us();

}


