/*
 * i2c_isl28022.c
 *
 * Communicates with ISL28022 via I2C.
 *
 *  Created on: 2023/06/09
 *      Author: BestTechnology
 */

#pragma GCC push_options
#pragma GCC optimize ("O0")

#include "hal_data.h"

#include <stdint.h>

#include "trace.h"

#include "power_monitor.h"

#define RESET_VALUE             (0x00)

//static volatile i2c_master_event_t i2c_master_event = (i2c_master_event_t)RESET_VALUE;

typedef enum { iicps_none, iicps_w_ex, iicps_w_comp, iicps_r_waddrex, iicps_r_rdatex, iicps_r_comp } tiic_prog_stat;

//uint16_t isl28022_reg[10] = {0};
//static uint8_t req_reg_addr = 0;
static uint16_t *isl28022_destreaddata = NULL;
static volatile tiic_prog_stat iic_pstat = iicps_none;
static volatile Tisl_comstat i2c_stat = tisl_none;

void sci_i2c_master_callback (i2c_master_callback_args_t * p_args) {
    static uint8_t rreg[4];
    if (NULL != p_args) {
//        i2c_master_event = p_args->event;
        switch (iic_pstat) {
            case iicps_none:
                break;
            case iicps_w_ex:
                if (p_args->event == I2C_MASTER_EVENT_TX_COMPLETE) {
                    iic_pstat = iicps_w_comp;
                    i2c_stat = tisl_term;
                } else iic_pstat = iicps_none;
                break;
            case iicps_w_comp:
                iic_pstat = iicps_none;
                break;

            case iicps_r_waddrex:
                if (R_SCI_I2C_Read (&g_i2c3_ctrl, &rreg[0], 2, false) == FSP_SUCCESS) {
                    iic_pstat = iicps_r_rdatex;
                } else {
                    i2c_stat = tisl_none;
                    iic_pstat = iicps_none;
                }
                break;
            case iicps_r_rdatex:
                if (p_args->event == I2C_MASTER_EVENT_RX_COMPLETE) {
                    if (isl28022_destreaddata != NULL) *isl28022_destreaddata = __builtin_bswap16 (*(uint16_t *)&rreg);
                    isl28022_destreaddata = NULL;
                    iic_pstat = iicps_r_comp;
                    i2c_stat = tisl_term;
                } else iic_pstat = iicps_none;
                break;
            case iicps_r_comp:
                iic_pstat = iicps_none;
                break;
        }
    }
}

bool isl28022_write (uint8_t addr, uint16_t val) {
    bool result = false;
    uint32_t timeout_us;
    iic_pstat = iicps_none;

    if (addr <= ISLREG_ADDR_AUXCTRLREG && i2c_stat != tisl_busy) {
        R_SCI_I2C_SlaveAddressSet (&g_i2c3_ctrl, ISL28022_I2C_SLAVEADDRESS, I2C_MASTER_ADDR_MODE_7BIT);
        timeout_us = 1000000;
        static uint8_t dat[3];
        dat[0] = addr;
        dat[1] = (uint8_t)(val >> 8);
        dat[2] = (uint8_t)(val & 0xff);
        if (R_SCI_I2C_Write (&g_i2c3_ctrl, &dat[0], sizeof(dat), false) == FSP_SUCCESS) {
            iic_pstat = iicps_w_ex;
            i2c_stat = tisl_busy;
            while (iic_pstat == iicps_w_ex && timeout_us) {
                R_BSP_SoftwareDelay (1U, BSP_DELAY_UNITS_MICROSECONDS);
                timeout_us--;
            }
            result = (iic_pstat == iicps_w_comp);
            iic_pstat = iicps_none;
            i2c_stat = tisl_term;
        }
    }
    return result;
}

bool isl28022_read (uint8_t addr, uint16_t *dest) {
    if (isl28022_read_ex (addr, dest)) {
        for (int i = 0; i < 100000; i++) {
            if (iic_pstat == iicps_r_comp) return true;
            R_BSP_SoftwareDelay (1, BSP_DELAY_UNITS_MICROSECONDS);
        }
    }
    return false;
}

// Only make requests to avoid waiting lists to be seen.
bool isl28022_read_ex (uint8_t addr, uint16_t *dest) {
    bool result = false;

    if (addr <= ISLREG_ADDR_AUXCTRLREG && i2c_stat != tisl_busy && dest != NULL) {
        if (R_SCI_I2C_SlaveAddressSet (&g_i2c3_ctrl, ISL28022_I2C_SLAVEADDRESS, I2C_MASTER_ADDR_MODE_7BIT) == FSP_SUCCESS) {
            uint8_t rregcmd[1] = { addr };
            isl28022_destreaddata = dest;
            if (R_SCI_I2C_Write (&g_i2c3_ctrl, &rregcmd[0], 1, false) == FSP_SUCCESS) {
                iic_pstat = iicps_r_waddrex;
                i2c_stat = tisl_busy;
                result = true;
            }
        }
    }
    return result;
}

Tisl_comstat isl28022_comp_stat (void) {
    return i2c_stat;
}

void isl28022_force_reset_stat (void) {
    iic_pstat = iicps_none;
    i2c_stat = tisl_none;
}

bool isl28022_init (uint8_t brng, uint8_t pga, uint8_t badc, uint8_t sadc, uint8_t mode, uint16_t cal) {
    if (R_SCI_I2C_Open (&g_i2c3_ctrl, &g_i2c3_cfg) == FSP_SUCCESS) {
        i2c_stat = tisl_none;
        // 15    :RST
        // 14..13:BRNG  00:16V 01:32V 10:60V 11:60V
        // 12..11:PG    00:40mV 01:80mV 10:160mV 11:320mV
        // 10..7 :BADC
        // 6..3  :SADC
        // 2..0  :MODE
        uint16_t reg = (uint16_t)(((brng & 0x3) << 13) | ((pga & 0x3) << 11) | ((badc & 0xf) << 7) | ((sadc & 0xf) << 11) | ((mode & 0x7) << 0));
        uint16_t d = 0;;

        isl28022_write (0, 0x8000);
        R_BSP_SoftwareDelay (100U, BSP_DELAY_UNITS_MILLISECONDS);
        if (!isl28022_read (ISLREG_ADDR_CONFIG, &d)) return false;

        //default 0x799f
        isl28022_write (ISLREG_ADDR_CONFIG, reg);
        if (!isl28022_read (ISLREG_ADDR_CONFIG, &d)) return false;

        isl28022_write (ISLREG_ADDR_CALIBRATIONREG, cal);
        if (!isl28022_read (ISLREG_ADDR_CALIBRATIONREG, &d)) return false;

        return true;
    }
    return false;
}

#pragma GCC pop_options
