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


#include <stdint.h>
#include <stdbool.h>
#include "system.h"
#include "user_io.h"
#include "uartstdio.h"  // User local version with larger RX buffer
#include "inc/tm4c123gh6pm.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"

//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)
{
    i2c0_busScan();
}
int pcal6408_test(void)
{
    pcal6408_probe();
}
int pcal6408_init(void)
{

}
int pcal6408_reset(void)
{

}
int pcal6408_write_default(void)
{

}
int pcal6408_start(void)
{

}
int pcal6408_stop(void)
{

}
int pcal6408_read8_port(uint32_t portNum, uint8_t *data)
{

}

int pcal6408_write8_port(uint32_t portNum, uint8_t data)
{

}
int pcal6408_write1_port(uint32_t portNum, uint8_t bitNum, uint32_t state)
{

}

// --------------- pcal6416 -------------------------
int pcal6416_probe(void)
{
    i2c0_busScan();
}


// reads 8 bits from register 'reg_addr'
//uint8_t bme280_read_byte(uint8_t device_register)
int pcal6416_read_byte(uint8_t reg_addr, uint8_t *data)
{
  uint8_t retByte;

  retByte = i2c0_read8(PCAL6416_I2C_8BIT_ADDR>>1, reg_addr);

  *data = retByte;

  return 0;
}

#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

int pcal6416_test(void)
{

    //pcal6416_probe(0);



}

void i2c_reset(void)
{
    //PA7 is active low i2c_reset GPIO on MSC3 Tiva Module
}


int pcal6416_init(void)
{

    i2c_reset();

    pcal6416_shadow_port0 = 0;
    pcal6416_shadow_port1 = 0;

#ifdef NOCODE
    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)
{
#ifdef NOCODE
    RegIO_SetBit( SYS_I2C_RST );
    Delay500us();
    RegIO_ClrBit( SYS_I2C_RST );
    Delay500us();
#endif
}

//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

}


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

#endif
}

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

#endif
}


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
}

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
}

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
}

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_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
