/*==============================================================================
 * i2c_manager.c - HW / SW I2C mutex switching logic
 *
 * Manages mutually-exclusive HW (TWI peripheral) and SW (bit-bang) I2C modes.
 *
 * HW I2C : nRF52840 TWI hardware, 400 kHz Fast Mode (ICM42670P IMU)
 * SW I2C : GPIO bit-bang (legacy, currently unused)
 *
 * Pins:
 *   SCL = P1.14 (ICM42670_I2C_SCL_PIN)
 *   SDA = P1.15 (ICM42670_I2C_SDA_PIN)
 *
 * The two bool flags HW_I2C_FRQ and SW_I2C_FRQ track the current mode.
 * Switching releases the old mode's resources before initialising the new one.
 *============================================================================*/

#include "i2c_manager.h"
#include "debug_print.h"
#include "nrf_delay.h"

#include "nrf_drv_twi.h"
#include "nrfx_twi.h"
#include "boards.h"
#include "system_interface.h"

/* Current I2C mode flags */
bool HW_I2C_FRQ = true;
bool SW_I2C_FRQ = false;

/* TWI instance (nRF52840 supports TWI0 and TWI1) */
#define TWI_INSTANCE 0
const nrfx_twi_t m_twi = NRFX_TWI_INSTANCE(TWI_INSTANCE);

/* Disable and uninitialise the TWI peripheral, releasing GPIO pins. */
static void twi_uninitialize(void)
{
    nrfx_twi_disable(&m_twi);
    nrfx_twi_uninit(&m_twi);
}

/* Initialise the TWI peripheral (SCL/SDA pins, 400 kHz, blocking mode). */
static void twi_initialize(void)
{
    ret_code_t err_code;

    const nrfx_twi_config_t twi_config =
    {
       .scl                = ICM42670_I2C_SCL_PIN,
       .sda                = ICM42670_I2C_SDA_PIN,
       .frequency          = NRF_TWI_FREQ_400K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
    };

    err_code = nrfx_twi_init(&m_twi, &twi_config, NULL, NULL);
    APP_ERROR_CHECK(err_code);

    nrfx_twi_enable(&m_twi);
}

/*==============================================================================
 * hw_i2c_init_once - Switch to or initialise HW TWI mode
 *
 * If SW mode is active, its flag is cleared first.
 * If HW mode is already active, returns immediately (no re-init).
 *============================================================================*/
void hw_i2c_init_once(void)
{
    if (SW_I2C_FRQ)
    {
        SW_I2C_FRQ = false;
        nrf_delay_ms(2);   /* mode-switch settling */
    }

    if (HW_I2C_FRQ)
    {
        return;
    }

    twi_initialize();
    nrf_delay_ms(2);

    HW_I2C_FRQ = true;
    SW_I2C_FRQ = false;
}

/*==============================================================================
 * sw_i2c_init_once - Switch to SW bit-bang mode (legacy, unused)
 *
 * If HW mode is active, TWI is released first.
 * If SW mode is already active, returns immediately.
 *============================================================================*/
void sw_i2c_init_once(void)
{
    if (HW_I2C_FRQ)
    {
        nrfx_twi_disable(&m_twi);
        nrfx_twi_uninit(&m_twi);
        nrf_delay_ms(2);
        HW_I2C_FRQ = false;
    }

    if (SW_I2C_FRQ)
    {
        return;
    }

    twi_uninitialize();
    nrf_delay_ms(1);

    SW_I2C_FRQ = true;
    HW_I2C_FRQ = false;
}

/*==============================================================================
 * i2c_reset_state - Clear all mode flags
 *
 * Forces re-initialisation on the next init call. Used for system reset
 * or error recovery.
 *============================================================================*/
void i2c_reset_state(void)
{
    HW_I2C_FRQ = false;
    SW_I2C_FRQ = false;
    DBG_PRINTF("Flags reset\r\n");
}
