/*
 * i2c_ina260.c
 *
 *  Created on: Jul 31, 2024
 *      Author: tm
 */

#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/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 "i2c0.h"
#include "i2c_ina260.h"

float msc_sys_fVoltage;
float msc_sys_fCurrent;
float msc_sys_fPower;

float msc_lamp_fVoltage;
float msc_lamp_fCurrent;
float msc_lamp_fPower;

int ina260_soak_test(void)
{
    int ret;
    int i;

    ret = ina260_probe(INA260_SYS_I2C_ADDR);
    if(ret <= 0)
    {
        uprintf("ina260_soak_test fail"); prn_nl();
        return 0;
    }
    else
    {
        uprintf("ina260_soak_test probe ok"); prn_nl();
    }

    for(i = 0; i < 100; i++)
    {
        ret = ina260_dev_test(INA260_SYS_I2C_ADDR);
        if(ret <= 0)
        {
            uprintf("ina260_soak_test fail"); prn_nl();
            return 0;
        }

        uprintf("[%04d] msc_sys_fVoltage: %0.2f, msc_sys_fCurrent %0.2f, msc_sys_fPower: %0.2f", i, msc_sys_fVoltage, msc_sys_fCurrent, msc_sys_fPower); prn_nl();
        delay_msec(500);
    }

    uprintf("ina260_soak_test pass"); prn_nl();

    return 1;
}

/*
 * for development and debug
 */
int ina260_dev_test(uint8_t i2cAddr)
{
    int ret;

    uint16_t voltageRaw = 0;
    uint16_t currentRaw = 0;
    uint16_t powerRaw   = 0;

    // Configure INA260
    ret = ina260_write_register(INA260_SYS_I2C_ADDR, INA260_CONFIG, INA260_DEF_CONFIG_VALUE);
    if(ret <= 0)
    {
        return 0;
    }

    // Read values
    ret = ina260_read_register(INA260_SYS_I2C_ADDR, INA260_BUS_VOLTAGE, &voltageRaw);
    if(ret <= 0)
    {
        return 0;
    }

    ret = ina260_read_register(INA260_SYS_I2C_ADDR, INA260_CURRENT, &currentRaw);
    if(ret <= 0)
    {
        return 0;
    }

    ret = ina260_read_register(INA260_SYS_I2C_ADDR, INA260_POWER, &powerRaw);
    if(ret <= 0)
    {
        return 0;
    }

    msc_sys_fVoltage = ina260_calc_voltage(voltageRaw);
    msc_sys_fCurrent = ina260_calc_current(currentRaw);
    msc_sys_fPower   = ina260_calc_power(powerRaw);

    return 1;
}

//app calls ina260_init for both ina260s
//primary interface is ina260_system_voltageCurrent and ina260_lamp_voltageCurrent

//INA219_ReadVoltageCurrent( &volts, &amps );
int ina260_system_voltageCurrent( float *sysVolts, float *sysAmps )
{
    int retVal;

    //*sysVolts = 14.3;   //APFTODO
    //*sysAmps = 0.037;

    uint16_t voltageRaw = 0;
    uint16_t currentRaw = 0;
    uint16_t powerRaw   = 0;

    // Configure INA260
    retVal = ina260_write_register(INA260_SYS_I2C_ADDR, INA260_CONFIG, INA260_DEF_CONFIG_VALUE);
    if(retVal <= 0)
    {
        return 0;
    }

    // Read values
    retVal = ina260_read_register(INA260_SYS_I2C_ADDR, INA260_BUS_VOLTAGE, &voltageRaw);
    if(retVal <= 0)
    {
        return 0;
    }

    retVal = ina260_read_register(INA260_SYS_I2C_ADDR, INA260_CURRENT, &currentRaw);
    if(retVal <= 0)
    {
        return 0;
    }

    retVal = ina260_read_register(INA260_SYS_I2C_ADDR, INA260_POWER, &powerRaw);
    if(retVal <= 0)
    {
        return 0;
    }

    msc_sys_fVoltage = ina260_calc_voltage(voltageRaw);
    msc_sys_fCurrent = ina260_calc_current(currentRaw);
    msc_sys_fPower   = ina260_calc_power(powerRaw);

    //uprintf("DBG: sysV = %7.3f, sysI = %7.3f, sysP = %7.3f", msc_sys_fVoltage, msc_sys_fCurrent, msc_sys_fPower); prn_nl();

    *sysVolts = msc_sys_fVoltage;
    *sysAmps = msc_sys_fCurrent;

    return(1);
}

int ina260_lamp_voltageCurrent( float *lampVolts, float *lampAmps )
{
    int retVal;

    uint16_t voltageRaw = 0;
    uint16_t currentRaw = 0;
    uint16_t powerRaw   = 0;

    // Configure INA260
    retVal = ina260_write_register(INA260_LAMP_I2C_ADDR, INA260_CONFIG, INA260_DEF_CONFIG_VALUE);
    if(retVal <= 0)
    {
        return 0;
    }

    // Read values
    retVal = ina260_read_register(INA260_LAMP_I2C_ADDR, INA260_BUS_VOLTAGE, &voltageRaw);
    if(retVal <= 0)
    {
        return 0;
    }

    retVal = ina260_read_register(INA260_LAMP_I2C_ADDR, INA260_CURRENT, &currentRaw);
    if(retVal <= 0)
    {
        return 0;
    }

    retVal = ina260_read_register(INA260_LAMP_I2C_ADDR, INA260_POWER, &powerRaw);
    if(retVal <= 0)
    {
        return 0;
    }

    msc_lamp_fVoltage = ina260_calc_voltage(voltageRaw);
    msc_lamp_fCurrent = ina260_calc_current(currentRaw);
    msc_lamp_fPower   = ina260_calc_power(powerRaw);

    //uprintf("DBG: lampV = %7.3f, lampI = %7.3f, lampP = %7.3f", msc_lamp_fVoltage, msc_lamp_fCurrent, msc_lamp_fPower); prn_nl();

    *lampVolts = msc_lamp_fVoltage;
    *lampAmps = msc_lamp_fCurrent;

    return(1);

}

// Calculate voltage
float ina260_calc_voltage(uint16_t rawData)
{
    return (float)rawData * CALIBRATION_VOLTAGE;
}

// Calculate current
float ina260_calc_current(uint16_t rawData)
{
    // current data is signed, so cast to int16_t first
    return (float)((int16_t)rawData) * CALIBRATION_CURRENT;
}

// Calculate power
float ina260_calc_power(uint16_t rawData)
{
    return (float)rawData * CALIBRATION_POWER;
}

/*
 * unit tests
 */
void ina260_test(uint8_t i2cAddr)
{

}

/*
 * is the ina260 present and responding on the i2c bus?
 */
int ina260_probe(uint8_t i2cAddr)
{
    uint16_t mfid_reg;
    uint16_t did_reg;

    if( ina260_read_register(i2cAddr, INA260_MF_ID, &mfid_reg) <= 0 )
    {
        return 0;
    }

    if(mfid_reg != 0x5449U)
    {
        return 0;
    }

    if( ina260_read_register(i2cAddr, INA260_DIE_ID, &did_reg) <= 0)
    {
        return 0;
    }

    // Low 4 bits are die revision, top 12 are device id
    if((did_reg & 0xFFF0U) != 0x2270U)
    {
        return 0;
    }

    return 1;
}

/*
 * initialize ina260
 *
 * return 0 if OK
 */
//
int ina260_init(uint8_t i2cAddr)
{
    if( ina260_probe(i2cAddr) <= 0)
    {
        return 0;
    }

    // Configure INA260
    if( ina260_write_register(i2cAddr, INA260_CONFIG, INA260_DEF_CONFIG_VALUE) <= 0)
    {
        return 0;
    }

    return 1;
}

int ina260_shutdown(uint8_t i2cAddr)
{
    uint16_t config_reg;

    if( ina260_read_register(i2cAddr, INA260_CONFIG, &config_reg) <= 0)
    {
        return 0;
    }

    // Set the mode bits to 0 for shutdown mode
    config_reg = config_reg & 0xFFF8U;

    if( ina260_write_register(i2cAddr, INA260_CONFIG, config_reg) <= 0)
    {
        return 0;
    }

    return 1;
}

int ina260_continuous(uint8_t i2cAddr)
{
    uint16_t config_reg;

    if( ina260_read_register(i2cAddr, INA260_CONFIG, &config_reg) <= 0)
    {
        return 0;
    }

    // Set the mode bits to b111 for continuous mode
    config_reg = config_reg | 0x0007U;

    if( ina260_write_register(i2cAddr, INA260_CONFIG, config_reg) <= 0)
    {
        return 0;
    }

    return 1;
}

/*
 * read voltage and current to global vars
 *
 * return 0 if OK
 */
int ina260_system_read_data(void)
{
    return 0;
}


/*
 * read voltage and current to global vars
 *
 * return 0 if OK
 */
int ina260_lamp_read_data(void)
{
    return 0;
}


// Write to INA260 register
int ina260_write_register(uint8_t i2cAddr, uint8_t reg, uint16_t data)
{
    uint16_t temp = __revsh(data);
    if( i2c0_write_then_read(i2cAddr, &reg, 1, (uint8_t*)&temp, 2) <= 0 )
    {
        return 0;
    }

    return 1;
}


int ina260_read_register(uint8_t i2cAddr, uint8_t regAddr, uint16_t* out_data)
{
    uint16_t temp;
    if( i2c0_read_reg16(i2cAddr, regAddr, &temp) <= 0 )
    {
        return 0;
    }
    temp = __revsh(temp);

    *out_data = temp;

    return 1;
}
