/*
 * i2c_pcal64xx.c
 *
 *  Created on: May 3, 2024
 *      Author: tm
 *
 *  PCAL6416 and PCAL6408A
 *
 */


#include <stdint.h>
#include <stdbool.h>
#include "system.h"
#include "sleep.h"
#include "user_io.h"
#include "uartstdio.h"  // User local version with larger RX buffer
#include "inc/hw_types.h"
#include "inc/hw_i2c.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"

#include "board_util.h"
#include "i2c0.h"
#include "i2c_pcal64xx.h"

#if BOARD_MSC == 3
#include "apf.h"

extern struct apfBootInitGlobals apf;
#endif // BOARD_MSC == 3


//https://infocenter.nordicsemi.com/index.jsp?topic=%2Fsdk_nrf5_v17.0.2%2Fgroup__pcal6408a__driver.html

uint8_t pcal6408_shadow_port0;

uint8_t pcal6416_shadow_port0;
uint8_t pcal6416_shadow_port1;

int pcal6408_probe(void)
{
    return i2c0_busScan();
}
int pcal6408_test(void)
{
    return pcal6408_probe();
}
int pcal6408_init(void)
{
    return 0;
}
int pcal6408_reset(void)
{
    return 0;
}
int pcal6408_write_default(void)
{
    return 0;
}
int pcal6408_start(void)
{
    return 0;
}
int pcal6408_stop(void)
{
    return 0;
}
int pcal6408_read8_port(uint32_t portNum, uint8_t *data)
{
    return 0;
}

int pcal6408_write8_port(uint32_t portNum, uint8_t data)
{
    return 0;
}
int pcal6408_write1_port(uint32_t portNum, uint8_t bitNum, uint32_t state)
{
    return 0;
}

// --------------- pcal6416 -------------------------
// pcal6416 present on the i2c bus?
int pcal6416_probe(uint8_t i2cAddr)
{
    int retVal;
    uint8_t regVal;

    retVal = pcal6416_read_byte(PCAL6416A_CONFIG0, &regVal);
    if(retVal <= 0)
    {
        return 0;
    }

    return 1;
}

// reads 8 bits from register 'reg_addr'
int pcal6416_read_byte(uint8_t reg_addr, uint8_t *data)
{
    if(i2c0_read_reg8(PCAL6416_I2C_ADDR, reg_addr, data) <= 0)
    {
        return 0;
    }

    return 1;
}

int pcal6416_read(uint8_t reg_addr, uint8_t *data, uint8_t byteCnt)
{
    if(i2c0_write_then_read(PCAL6416_I2C_ADDR, &reg_addr, 1, data, byteCnt) <= 0)
    {
        return 0;
    }

    return 1;
}

// writes 1 byte '_data' to register 'reg_addr'
int pcal6416_write_byte(uint8_t reg_addr, uint8_t device_data)
{
    if(i2c0_write_reg8(PCAL6416_I2C_ADDR, reg_addr, device_data) <= 0)
    {
        return 0;
    }

    return 1;
}

int pcal6416_write(uint8_t reg_addr, uint8_t *data, uint8_t length)
{
    if(i2c0_write_then_write(PCAL6416_I2C_ADDR, &reg_addr, 1, data, length) <= 0)
    {
        return 0;
    }

    return 1;
}

int pcal6416_spec_pwr(int state)
{
    int retVal;
#if BOARD_MSC == 3
    if(state)
    {
        apf.isus_spec_pwr = TRUE;
        pcal6416_shadow_port0 |= SPEC_PWR_ON;
        retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
    }
    else
    {
        apf.isus_spec_pwr = FALSE;
        pcal6416_shadow_port0 &= ~SPEC_PWR_ON;
        retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
    }
#else
    retVal = -1;
#endif // BOARD_MSC == 3

    return(retVal);
}

int pcal6416_lamp_pwr(int state)
{
    int retVal = -1;
#if BOARD_MSC == 3
    if(state)
    {
        apf.isus_lamp_pwr = TRUE;
        pcal6416_shadow_port0 |= LAMP_PWR_ON;
        retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
    }
    else
    {
        apf.isus_lamp_pwr = FALSE;
        pcal6416_shadow_port0 &= ~LAMP_PWR_ON;
        retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
    }
#endif // BOARD_MSC == 3

    return(retVal);
}

int pcal6416_deuterium(int state)
{
    int retVal;
#if BOARD_MSC == 3
    if(state)
    {
        apf.isus_lamp_deuterium = TRUE;
        pcal6416_shadow_port0 |= LAMP_DU_ENABLE;
        retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
    }
    else
    {
        apf.isus_lamp_deuterium = FALSE;
        pcal6416_shadow_port0 &= ~LAMP_DU_ENABLE;
        retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
    }
#else
    retVal = -1;
#endif // BOARD_MSC == 3

    return(retVal);
}

int pcal6416_tungsten(int state)
{
    int retVal;

    #if BOARD_MSC == 3
    if(state)
    {
        apf.isus_lamp_tungsten = TRUE;
        pcal6416_shadow_port0 |= LAMP_W_ENABLE;
        retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
    }
    else
    {
        apf.isus_lamp_tungsten = FALSE;
        pcal6416_shadow_port0 &= ~LAMP_W_ENABLE;
        retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
    }
#else
    retVal = -1;
#endif // BOARD_MSC == 3

    return(retVal);
}


#ifdef NOCODE
case 'A':
    pcal6416_shadow_port0 |= SPEC_PWR_ON;
    retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
    break;
case 'a':
    pcal6416_shadow_port0 &= ~SPEC_PWR_ON;
    retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
    break;


    //uprintf("C/c -- Lamp Pwr\r\n");
    case 'C':
        pcal6416_shadow_port0 |= LAMP_PWR_ON;
        retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
        break;
    case 'c':
        pcal6416_shadow_port0 &= ~LAMP_PWR_ON;
        retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
        break;


        //uprintf("D/d -- Lamp D\r\n");
        case 'D':
            pcal6416_shadow_port0 |= LAMP_DU_ENABLE;
            retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
            break;
        case 'd':
            pcal6416_shadow_port0 &= ~LAMP_DU_ENABLE;
            retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
            break;

        //uprintf("E/e -- Lamp W\r\n");
        case 'E':
            pcal6416_shadow_port0 |= LAMP_W_ENABLE;
            retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
            break;
        case 'e':
            pcal6416_shadow_port0 &= ~LAMP_W_ENABLE;
            retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
            break;

#endif

void pcal6416_test_menu(void)
{
    int retVal;
    time_t timer;
    char input;

    while(1)
    {
        prn_nl(); prn_nl(); 
		uprintf("PCAL6416 Menu:\r\n");
        uprintf("A/a -- Spec Pwr\r\n");
        uprintf("B/b -- Pump Pwr\r\n");
        uprintf("C/c -- Lamp Pwr\r\n");
        uprintf("D/d -- Lamp D\r\n");
        uprintf("E/e -- Lamp W\r\n");
        uprintf("F/f -- Lamp Shutter\r\n");
        uprintf("G/g -- Spec rs232 Enable\r\n");  //uprintf("G/g -- Spare pin 1");
        uprintf("H/h -- Spare pin 2");
        uprintf("T   -- PCAL6416 dev test\r\n");
        uprintf("9 -- Exit to Main Menu\r\r\n");
        uprintf("\r\r\nEnter Selection [9]: ");

        UARTFlushRx();
        timer = MENU_TIMEOUT_SEC + read_hib_rtcc();

        while(1)
        {
            if( UARTRxBytesAvail() )
            {
                input = get_key();
                break;
            }

            if( timer <= read_hib_rtcc() ) sleep(IDLE, 0);
        }

        switch(input)
        {
            //uprintf("A/a -- Spec Pwr\r\n");
            case 'A':
                pcal6416_shadow_port0 |= SPEC_PWR_ON;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;
            case 'a':
                pcal6416_shadow_port0 &= ~SPEC_PWR_ON;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;

            //uprintf("B/b -- Pump Pwr\r\n");
            case 'B':
                pcal6416_shadow_port0 |= PUMP_PWR_ON;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;
            case 'b':
                pcal6416_shadow_port0 &= ~PUMP_PWR_ON;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;

            //uprintf("C/c -- Lamp Pwr\r\n");
            case 'C':
                pcal6416_shadow_port0 |= LAMP_PWR_ON;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;
            case 'c':
                pcal6416_shadow_port0 &= ~LAMP_PWR_ON;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;

            //uprintf("D/d -- Lamp D\r\n");
            case 'D':
                pcal6416_shadow_port0 |= LAMP_DU_ENABLE;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;
            case 'd':
                pcal6416_shadow_port0 &= ~LAMP_DU_ENABLE;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;

            //uprintf("E/e -- Lamp W\r\n");
            case 'E':
                pcal6416_shadow_port0 |= LAMP_W_ENABLE;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;
            case 'e':
                pcal6416_shadow_port0 &= ~LAMP_W_ENABLE;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;

            //uprintf("F/f -- Lamp Shutter\r\n");
            case 'F':
                pcal6416_shadow_port0 |= LAMP_SHUT_ENABLE;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;
            case 'f':
                pcal6416_shadow_port0 &= ~LAMP_SHUT_ENABLE;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;

            //uprintf("G/g -- Spare pin 1");
            case 'G':
                //pcal6416_shadow_port0 |= PCAL6416_SPARE1;
                pcal6416_shadow_port0 |= SPEC_232_EN;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;
            case 'g':
                //pcal6416_shadow_port0 &= ~PCAL6416_SPARE1;
                pcal6416_shadow_port0 &= ~SPEC_232_EN;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;

            //uprintf("H/h -- Spare pin 2");
            case 'H':
                pcal6416_shadow_port0 |= PCAL6416_SPARE2;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;
            case 'h':
                pcal6416_shadow_port0 &= ~PCAL6416_SPARE2;
                retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);
                break;

            //uprintf("T   -- PCAL6416 dev test\r\n");
            case 'T':
            case 't':
                pcal6416_test(0);  // dev test for periph driver
                break;

            default: //Exit
                uprintf("\r\r\nPress enter to bring up main menu\r\r\n");
                return;
        }

        if(retVal <= 0)
        {
            uprintf("\r\nPCAL6416 operation '%c' failed\r\n", input);
        }
    }
}

void pcal6416_test(int testNum)
{
    uint8_t i2cData[8];
    int retVal;

    uprintf("\r\npcal6416_test start\r\n");


    retVal = pcal6416_probe(PCAL6416_I2C_ADDR);
    if(retVal == 0)
        uprintf("PCAL6416 not found at 0x%02x\r\n", PCAL6416_I2C_ADDR);
    else
        uprintf("PCAL6416 found at 0x%02x\r\n", PCAL6416_I2C_ADDR);

//The Configuration registers (registers 6 and 7) configure the direction of the I/O pins.
//    If a bit in these registers is set to 1, the corresponding port pin is enabled as a highimpedance input. If a bit in these registers is cleared to 0, the corresponding port pin
//    is enabled as an output.

    //write config register as output for p0 and inputs for p1
    //pcal6416_write_byte(PCAL6416A_CONFIG0, 0x00);   // outputs

    //pcal6416_write_byte(PCAL6416A_CONFIG1, 0xFF);   // inputs

    i2cData[0] = 0x00;      // outputs
    i2cData[1] = 0xFF;      // inputs
    pcal6416_write(PCAL6416A_CONFIG0, &i2cData[0], 2);

    //pcal6416_read(PCAL6416A_CONFIG0, &i2cData[0], 2);

    pcal6416_read_byte(PCAL6416A_CONFIG0, &i2cData[0]);
    uprintf("\r\n wrote 0x00, read 0x%02x\r\n", i2cData[0]);

    pcal6416_read_byte(PCAL6416A_CONFIG1, &i2cData[1]);
    uprintf("\r\n wrote 0xFF, read 0x%02x\r\n", i2cData[1]);
    wait_consoleTx();

    //THOM TODO: Saleae has I2C NAK on last read
    // it does this both for i2c_read and i2c_read_byte


    while(1)
    {

        pcal6416_write_byte(PCAL6416A_OUT_PORT0, 0x00);  // 140usec
        delay_usec(100);

        pcal6416_write_byte(PCAL6416A_OUT_PORT0, 0xFF);
        delay_usec(100);

        if( UARTRxBytesAvail() )
        {
            UARTFlushRx();
            break;    // break from while(1)
        }

    }

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

#ifdef GEMINIAI

#define PCAL6416_ADDR 0x20  // Replace with your device address
#define PORT0_REG 0x00

//void TogglePCAL6416Port0() {
    // Assuming I2C0 is configured and enabled

    uint8_t data[2];
    uint8_t portState;

    // Read initial port state
    data[0] = PORT0_REG;
    I2CMasterSlaveAddrSet(I2C0_BASE, PCAL6416_ADDR, false);
    I2CMasterDataPut(I2C0_BASE, data[0]);
    I2CMasterControl(I2C0_BASE, MASTER_CMD_SINGLE_SEND);  //I2C_MASTER_CMD_SINGLE_SEND
    while(I2CMasterBusy(I2C0_BASE));

    I2CMasterSlaveAddrSet(I2C0_BASE, PCAL6416_ADDR, true);
    I2CMasterControl(I2C0_BASE, MASTER_CMD_SINGLE_RECEIVE);
    while(I2CMasterBusy(I2C0_BASE));
    portState = I2CMasterDataGet(I2C0_BASE);

    while (1) {
        // Invert port state
        portState = ~portState;

        // Write new state to port 0
        data[0] = PORT0_REG;
        data[1] = portState;
        I2CMasterSlaveAddrSet(I2C0_BASE, PCAL6416_ADDR, false);
        I2CMasterDataPut(I2C0_BASE, data[0]);
        I2CMasterDataPut(I2C0_BASE, data[1]);
        I2CMasterControl(I2C0_BASE, MASTER_CMD_BURST_SEND_START);
        while(I2CMasterBusy(I2C0_BASE));

        // Introduce delay as needed
        SysCtlDelay(SysCtlClockGet() / (3 * 80)); // 1ms delay
    }
#endif

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


#ifdef NOCODE
    for(indx=0; indx<100; indx++)
    {
        pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, 0xff, 1);
        delay_msec(1);
        pcal6416_write_port_bit(PCAL6416A_OUT_PORT0, 0xff, 0);
        delay_msec(1);
    }
#endif

    uprintf("\r\npcal6416_test end\r\n");
}












#ifdef NOCODE
uint8_t pcal6416_readChipID(int prnFlg)
{
    uint8_t  chipId;

    pcal6416_read_byte(PCAL6416_CHIPID, &chipId);

    if(prnFlg) uprintf("\r\nPCAL6416 Chip ID = 0x%02x, reading reg returns: 0x%02x\r\n", PCAL6416_CHIPID_VAL, chipId );

    return(chipId);
}
#endif



void i2c_reset(void)
{
    //PA7 is active hi, i2c_reset is via FET on MSC3 baseboard
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_7); // PA7 is I2C_RST is active hi, goes to the gate of a FET
    MAP_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_7, 0xFF);

    delay_msec(1);

    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_7); // PA7 is I2C_RST is active hi, goes to the gate of a FET
    MAP_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_7, 0x00);        // reset inactive


}


int pcal6416_init(void)
{
    int retVal;
    uint8_t i2cData[4];

    //i2c_reset();      // DONT call i2c_reset as it will also reset the PCAL6408

    retVal = pcal6416_probe(PCAL6416_I2C_ADDR);
    if(retVal <= 0)
    {
        uprintf("PCAL6416 not found at 0x%02x\r\n", PCAL6416_I2C_ADDR);
        return 0;
    }
//    else
//    {
//        uprintf("PCAL6416 found at 0x%02x\r\n", PCAL6416_I2C_ADDR);
//    }


    i2cData[0] = 0x00;      // outputs
    i2cData[1] = 0xFF;      // inputs
    retVal = pcal6416_write(PCAL6416A_CONFIG0, &i2cData[0], 2);
    if(retVal <= 0)
    {
        return 0;
    }

    //pcal6416_read_byte(PCAL6416A_CONFIG0, &i2cData[0]);
    //uprintf("\r\n wrote 0x00, read 0x%02x\r\n", i2cData[0]);

    //pcal6416_read_byte(PCAL6416A_CONFIG1, &i2cData[1]);
    //uprintf("\r\n wrote 0xFF, read 0x%02x\r\n", i2cData[1]);
    //wait_consoleTx();

    pcal6416_shadow_port0 = 0x00;   // output port
    pcal6416_shadow_port1 = 0x00;   // input port

    retVal = pcal6416_write_byte(PCAL6416A_OUT_PORT0, pcal6416_shadow_port0);  // 140usec
    if(retVal <= 0)
    {
        return 0;
    }

    return 1;

#ifdef CF2CODE
    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 );
#endif
}

int pcal6416_reset(void)
{

    //PA7 is active hi, i2c_reset is via FET on MSC3 baseboard
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_7); // PA7 is I2C_RST is active hi, goes to the gate of a FET
    MAP_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_7, 0xFF);

    delay_msec(1);

    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_7); // PA7 is I2C_RST is active hi, goes to the gate of a FET
    MAP_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_7, 0x00);        // reset inactive
#ifdef NOCODE
    RegIO_SetBit( SYS_I2C_RST );
    Delay500us();
    RegIO_ClrBit( SYS_I2C_RST );
    Delay500us();
#endif

    return 1;
}

//int PCAL6416_WritePortDefaults( void )
int pcal6416_write_default(void)
{

#ifdef NOCODE
    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 );
#endif    //Return I2C Transfer Status

    return 0;
}


int pcal6416_start(void)
{
    //wakeup an initialized part
#ifdef NOCODE

#endif
    return 0;
}

int pcal6416_stop(void)
{
    //idle/sleep an initialized part
#ifdef NOCODE

#endif
    return 0;
}


int pcal6416_read_port_byte(uint32_t portNum, uint8_t *data)
{
#ifdef NOCODE
    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

#endif
    return 0;
}

int pcal6416_read_port_16bit(uint32_t portNum, uint8_t *data0, uint8_t *data1)
{
#ifdef NOCODE
    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 );
#endif
    return 0;
}

int pcal6416_write_port_byte(uint32_t portNum, uint8_t data)
{
#ifdef NOCODE
    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 );
#endif
    return 0;
}

int pcal6416_write_port_bit(uint8_t regNum, uint8_t bitMask, uint32_t state)
{
    unsigned char data;
    int retVal;

#define APF_ERROR   (-2)  // APFTODO

    if( (regNum != PCAL6416A_OUT_PORT0) && (regNum != PCAL6416A_OUT_PORT1) )
        return(APF_ERROR);

    if( (state != 1) && (state != 0) )
        return( APF_ERROR );

    data = 0;
    if(regNum == PCAL6416A_OUT_PORT0)
        data = pcal6416_shadow_port0;
    if(regNum == PCAL6416A_OUT_PORT1)
        data = pcal6416_shadow_port1;

    if( state == 1 )
        data |= bitMask;
    else
        data &= ~bitMask;

    //int i2c0_write_reg_byte(uint8_t i2c_addr, uint8_t reg_addr, uint8_t data)
    //i2c0_write_reg_byte(PCAL6416_I2C_8BIT_ADDR>>1, regNum, state);
	//i2c0_write_reg_byte(PCAL6416_I2C_ADDR, regNum, state);
    retVal = i2c0_write_reg8(PCAL6416_I2C_ADDR, regNum, data);
    if(retVal <= 0)
    {
        return 0;
    }

    return 1;

    //i2c0_disable();

#ifdef NOCODE
    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 );
#endif
}


#ifdef NOCODE
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();

}
#endif
