/*******************************************************************************
 * @file	app_raw_main.c
 * @author	CandyPops Co.
 * @version V1.0.0
 * @date	2022-09-05
 * @brief
 ******************************************************************************/

/*******************************************************************************
 * 2026.03.26 jhChun
 * This file is currently not executed at runtime.
 * Instead of interrupt-driven reads, imu_read_direct() in app_raw.c
 * reads registers directly. May be cleaned up later as needed.
 ******************************************************************************/

/*******************************************************************************
 * [Module overview] ICM42670P main initialization and polling loop
 *
 * Handles the full initialization sequence and main loop for the ICM42670P
 * IMU sensor.
 *
 * Init flow (icm42670_init):
 *   1) setup_mcu()             - Configure I2C serial interface struct and TWI init
 *   2) setup_imu_device()      - IMU driver init + WHOAMI verification
 *   3) configure_imu_device()  - Sensor parameter config (FSR, ODR, power mode)
 *   4) inv_gpio_sensor_irq_init() - INT1 (P1.13) GPIO interrupt setup
 *
 * Main loop (icm42670_main):
 *   - irq_from_device flag is set when INT1 interrupt fires
 *   - Main loop checks the flag and reads sensor data when set
 *   - Interrupt triggers on falling edge (HITOLO) with INT1 pin pulled up
 *
 * Helper functions:
 *   - inv_imu_sleep_us()     - nrf_delay_us wrapper (used by IMU driver)
 *   - inv_imu_get_time_us()  - Provides timestamp via RTC1 counter
 ******************************************************************************/
#include "sdk_config.h"
#include "app_raw.h"
#include "app_raw_main.h"
#include "RingBuffer.h"
#include "inv_imu_driver.h"

#include "system_interface.h"

/* std */
#include <stdio.h>
#include "nrf.h"
#include "app_error.h"
#include "boards.h"
#include "nrfx_gpiote.h"
#include "nrf_delay.h"

#include "app_util_platform.h"
#include "main.h"  /* 2026-03-17: removed cmd_parse.h, using main.h */
#include "i2c_manager.h"
/* --------------------------------------------------------------------------------------
 *  Global variables
 * -------------------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------------------
 *  Static variables
 * -------------------------------------------------------------------------------------- */

/*
 * IMU interrupt flag
 * Set to 1 on falling-edge interrupt of INT1 pin.
 * Main loop checks this flag, reads data, and clears it to 0.
 * volatile: modified by ISR, prevents compiler optimization.
 */
static volatile int irq_from_device;


/* --------------------------------------------------------------------------------------
 *  Forward declaration
 * -------------------------------------------------------------------------------------- */
static int setup_mcu(struct inv_imu_serif *icm_serif);

/*!
* @brief	Sensor general interrupt handler, calls specific handlers.
*
* This function is called when an external interrupt is triggered by the sensor,
* checks interrupt registers of InvenSense Sensor to determine the source and type of interrupt
* and calls the specific interrupt handler accordingly.
*
* @param[in]	NULL
*
* @param[out]	NULL
*
* @return		NULL
*
*/
/*
 * inv_gpio_sensor_interrupt_handler()
 * INT1 pin interrupt handler (ISR).
 * Called when the sensor has new data ready; sets a flag and returns immediately.
 * Actual data processing is done in the main loop (icm42670_main).
 */
static void inv_gpio_sensor_interrupt_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
	irq_from_device = 1;
}


/*
 * inv_gpio_sensor_irq_init()
 * Initializes INT1 (P1.13) GPIO interrupt.
 *
 * Configuration:
 *   - Trigger: falling edge (HITOLO) — when the sensor pulls INT low
 *   - Pull-up: internal pull-up enabled
 *   - Handler: inv_gpio_sensor_interrupt_handler
 *   - Initializes GPIOTE module first if not already initialized
 */
void inv_gpio_sensor_irq_init(void)
{
    ret_code_t err_code;

	/* Initialize GPIOTE module (skip if already initialized) */
	if (!nrfx_gpiote_is_init())
	{
	  err_code = nrfx_gpiote_init();
	  APP_ERROR_CHECK(err_code);
	}

    /* Falling-edge interrupt: trigger on High->Low transition, internal pull-up */
    nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
    in_config.pull = NRF_GPIO_PIN_PULLUP;

    /* Register interrupt handler for INT1 pin */
    err_code = nrfx_gpiote_in_init(ICM42670_INT1_PIN, &in_config, inv_gpio_sensor_interrupt_handler);
    APP_ERROR_CHECK(err_code);

    /* Enable interrupt event */
    nrfx_gpiote_in_event_enable(ICM42670_INT1_PIN, true);
}


/*
 * inv_gpio_sensor_irq_uninit()
 * Disables and releases the INT1 GPIO interrupt.
 * Called when deactivating the sensor or before re-initialization.
 */
void inv_gpio_sensor_irq_uninit(void)
{
	/* Disable interrupt event */
	nrfx_gpiote_in_event_disable(ICM42670_INT1_PIN);

	/* Release INT1 pin interrupt configuration */
	nrfx_gpiote_in_uninit(ICM42670_INT1_PIN);

	/* Release GPIOTE module (only if initialized) */
	if (nrfx_gpiote_is_init())
	{
	  nrfx_gpiote_uninit();

	}
}

/* --------------------------------------------------------------------------------------
 *  Main
 * -------------------------------------------------------------------------------------- */

/*
 * icm42670_init()
 * Performs the full ICM42670P initialization sequence.
 *
 * Init order:
 *   1) setup_mcu()             - Configure I2C interface struct and TWI hardware init
 *   2) setup_imu_device()      - IMU driver init, WHOAMI (0x67) verification
 *   3) configure_imu_device()  - FSR, ODR, power mode configuration
 *   4) inv_gpio_sensor_irq_init() - Enable INT1 interrupt (data-ready notification)
 *
 * Returns: 0=success, -1=initialization failure
 */
int icm42670_init(void)
{
	int rc = 0;
	struct inv_imu_serif icm_serif;

	rc |= setup_mcu(&icm_serif);
	rc |= setup_imu_device(&icm_serif);
	rc |= configure_imu_device();

	if(rc != 0){
		printf("!!!error during initialization\r\n");
		return -1;
	}

	/* Enable INT1 interrupt after successful init — ISR fires on data ready */
	inv_gpio_sensor_irq_init();

	return rc;
}


/*
 * icm42670_main()
 * ICM42670P main polling loop.
 * Must be called periodically from the main application loop.
 *
 * Operation:
 *   1) Check if I2C hardware is initialized (hw_i2c_init_once)
 *   2) Check irq_from_device flag (set by ISR)
 *   3) If flag is set, read sensor data (get_imu_data)
 *   4) Clear flag after data read completes
 *
 * Note: Interrupt-based polling — ISR only sets the flag; actual I2C
 * communication is done in the main context.
 */
void icm42670_main(void)
{
	int rc = 0;
   hw_i2c_init_once();
	/* Check for interrupt and read data */

	if (irq_from_device) {
		rc = get_imu_data();

		if(rc < 0) {
			printf("error while getting data\r\n");
		}

		/* Clear flag — wait for next interrupt */
		irq_from_device = 0;
	}

}


/* --------------------------------------------------------------------------------------
 *  Functions definitions
 * -------------------------------------------------------------------------------------- */

/*
 * setup_mcu()
 * Configures the MCU-side serial interface.
 *
 * Registers the following in the inv_imu_serif struct:
 *   - read_reg / write_reg : I2C read/write callbacks (implemented in system_interface.c)
 *   - max_read / max_write : Max transfer size (32KB)
 *   - serif_type           : Communication type (UI_I2C)
 *
 * After configuration, calls inv_io_hal_init() to initialize the TWI hardware.
 */
static int setup_mcu(struct inv_imu_serif *icm_serif)
{
	int rc = 0;

	/* Configure serial interface struct for IMU driver */
	icm_serif->context   = 0;        /* Context unused */
	icm_serif->read_reg  = inv_io_hal_read_reg;   /* Register read callback */
	icm_serif->write_reg = inv_io_hal_write_reg;   /* Register write callback */
	icm_serif->max_read  = 1024*32;  /* Max bytes per read */
	icm_serif->max_write = 1024*32;  /* Max bytes per write */
	icm_serif->serif_type = SERIF_TYPE;  /* UI_I2C (defined in app_raw.h) */

	/* Initialize TWI hardware */
	rc |= inv_io_hal_init(icm_serif);

	return rc;
}


/* --------------------------------------------------------------------------------------
 *  Extern functions definition
 * -------------------------------------------------------------------------------------- */

/*
 * inv_imu_sleep_us()
 * Microsecond sleep function used by the IMU driver.
 * Wraps nrf_delay_us() to provide a platform-independent interface.
 * Example: used for gyro startup delay (GYR_STARTUP_TIME_US).
 */
void inv_imu_sleep_us(uint32_t us)
{
	nrf_delay_us(us);
}


/*
 * inv_imu_get_time_us()
 * Timestamp function used by the IMU driver.
 * Returns the nRF52840 RTC1 counter value.
 *
 * Note: RTC1 runs at 32.768kHz, so the returned value is technically
 * in RTC ticks (~30.5us/tick), not microseconds.
 * Used for relative time comparisons within the driver.
 */
uint64_t inv_imu_get_time_us(void)
{
	return NRF_RTC1->COUNTER;
}
