/*==============================================================================
 * battery_saadc.c - Battery voltage ADC measurement
 *
 * Measures battery voltage via nRF52840 SAADC on AIN2:
 *   - 12-bit resolution, 4x oversampling
 *   - Periodic safety check via battery_loop timer (60 s interval)
 *   - Sequential: battery -> temperature measurement
 *   - Auto power-off after 5 consecutive readings below 3500 mV or above 40 C
 *   - In info4 mode (bulk sensor collection): stores to info_batt
 *
 * Voltage conversion:
 *   mV = ADC_VALUE * (600 / 4095) * 6 * 1.42  (resistor divider correction)
 *============================================================================*/

#include "sdk_common.h"

#include <stdint.h>
#include <string.h>
#include "nrf.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_timer.h"
#include "ble_nus.h"
#include "nrf_log.h"
#include "main.h"
#include "app_timer.h"
#include "battery_saadc.h"
#include "main_timer.h"
#include "tmp235_q1.h"
#include "dr_piezo.h"
#include "debug_print.h"

/* SAADC internal reference voltage (mV, float) */
#define BATTERY_REF_VOLTAGE_IN_MILLIVOLTS   600.0f

/* 1/3 prescaling compensation (input divided by 3, then x2 = total x6) */
#define BATTERY_PRE_SCALING_COMPENSATION    6.0f

/* 12-bit ADC maximum digital value */
#define BATTERY_ADC_RES_12BITS              4095.0f

/* Convert raw ADC value to millivolts */
#define BATTERY_RESULT_IN_MILLI_VOLTS(ADC_VALUE)\
        ((((ADC_VALUE) * BATTERY_REF_VOLTAGE_IN_MILLIVOLTS) / BATTERY_ADC_RES_12BITS) * BATTERY_PRE_SCALING_COMPENSATION)

/* Single ADC buffer (uninit after each measurement, no double-buffer needed) */
static nrf_saadc_value_t adc_buf;

/* Battery monitoring repeat timer */
APP_TIMER_DEF(m_battery_loop_timer_id);

/* Battery monitoring interval (ms) */
#define BATTERY_LOOP_INTERVAL              60000

/* Safety check consecutive count threshold */
#define SAFETY_CHECK_COUNT                 5

/* Low-battery check flag — set by battery_loop, consumed by handler */
bool low_battery_check = false;

/* Safety check mode flag — set by battery handler, consumed by tmp235 handler */
bool safety_check_mode = false;

/* SAADC callback completion flag — used by all_sensors() to wait */
volatile bool battery_saadc_done = false;

/* Safety check: cached battery voltage for use in safety_check_complete() */
static float safety_batt_mv = 0;

/* Safety check: consecutive counters */
static uint8_t low_battery_cnt = 0;
static uint8_t over_temp_cnt = 0;

/* info4: bulk sensor collection mode flag */
extern bool info4;

extern char	ble_tx_buffer[BLE_NUS_MAX_DATA_LEN];
extern bool go_device_power_off;
extern which_cmd_t cmd_type_t;
extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN];

/* info4 mode: cached battery voltage (mV) */
volatile uint16_t info_batt;

/* info4 sequential measurement control flags */
extern bool go_temp;
extern bool go_batt;

extern bool motion_raw_data_enabled;
extern bool ble_got_new_data;
extern bool motion_data_once;

/*==============================================================================
 * safety_check_complete - Called by tmp235 handler after temperature measurement
 *
 * Checks both battery voltage and temperature against thresholds.
 * 5 consecutive readings exceeding either threshold triggers power OFF.
 *============================================================================*/
void safety_check_complete(float temp_c)
{
    //DBG_PRINTF("[SAFETY] Batt=%d mV, Temp=%d.%d C\r\n",
    //           (int)safety_batt_mv, (int)temp_c, ((int)(temp_c * 10)) % 10);

    /* Battery check */
    if (safety_batt_mv <= LOW_BATTERY_VOLTAGE)
    {
        low_battery_cnt++;
        DBG_PRINTF("[SAFETY] Low batt cnt=%d\r\n", low_battery_cnt);
    }
    else
    {
        low_battery_cnt = 0;
    }

    /* Temperature check */
    if (temp_c >= OVER_TEMPERATURE_THRESHOLD)
    {
        over_temp_cnt++;
        DBG_PRINTF("[SAFETY] Over temp cnt=%d\r\n", over_temp_cnt);
    }
    else
    {
        over_temp_cnt = 0;
    }
    
    /* Power OFF if either threshold exceeded 5 consecutive times */
    if (low_battery_cnt >= SAFETY_CHECK_COUNT)
    {
        low_battery_cnt = 0;
        DBG_PRINTF("[SAFETY] Low battery -> Power OFF\r\n");
        go_device_power_off = true;
        main_timer_start();
    }
    else if (over_temp_cnt >= SAFETY_CHECK_COUNT)
    {
        over_temp_cnt = 0;
        DBG_PRINTF("[SAFETY] Over temperature -> Power OFF\r\n");
        go_device_power_off = true;
        main_timer_start();
    }

    dr_piezo_power_off();
}

/*==============================================================================
 * battery_event_handler - SAADC conversion complete callback
 *
 * Converts the raw ADC value to battery voltage (mV) and then:
 *   - Low-battery check mode: store voltage, chain temperature measurement
 *   - info4 mode: store to info_batt (no BLE send)
 *   - Normal mode: send rsn: response over BLE or UART
 *============================================================================*/
void battery_event_handler(nrf_drv_saadc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        nrf_saadc_value_t register_val = 0;
        float batt_lvl_in_milli_volt_0 = 0;
        float batt_lvl_in_milli_volt_1 = 0;

        register_val = p_event->data.done.p_buffer[0];

        /* Release SAADC — shared with temperature / pressure ADC */
        nrf_drv_saadc_channel_uninit(0);
        nrf_drv_saadc_uninit();

        battery_saadc_done = true;

        /* ADC -> mV conversion */
        batt_lvl_in_milli_volt_0 = BATTERY_RESULT_IN_MILLI_VOLTS(register_val);

        /* Resistor divider correction factor 1.42 */
        batt_lvl_in_milli_volt_1 = batt_lvl_in_milli_volt_0 * 1.42f;

        /* --- Safety check mode: store voltage, chain temperature measurement --- */
        if (low_battery_check == true)
        {
            low_battery_check = false;
            safety_batt_mv = batt_lvl_in_milli_volt_1;
            safety_check_mode = true;

            /* TMP235 shares piezo TX/RX power rail */
            if (!dr_piezo_is_power_on())
            {
                dr_piezo_power_on();
            }
            tmp235_voltage_level_meas();
        }

        /* --- info4 mode: store value for mbb? bulk response --- */
        else if (info4 == true)
        {
            info_batt = batt_lvl_in_milli_volt_1;
        }

        /* --- Normal mode: send rsn: BLE response --- */
        else
        {
            if (cmd_type_t == CMD_UART)
            {
                DBG_PRINTF("Tn%d\r\n\r\n", (int)batt_lvl_in_milli_volt_1);
            }
            else if (cmd_type_t == CMD_BLE)
            {
                single_format_data(ble_bin_buffer, "rsn:", batt_lvl_in_milli_volt_1);
                dr_binary_tx_safe(ble_bin_buffer, 3);
            }
        }
    }
}


/*==============================================================================
 * battery_configure - Set up SAADC for battery voltage measurement
 *
 * AIN2, single-ended, 1/6 gain, 12-bit, 4x oversampling, burst enabled.
 * Registers a single buffer (uninit after one conversion).
 *============================================================================*/
static void battery_configure(void)
{
    nrf_drv_saadc_config_t saadc_config = NRF_DRV_SAADC_DEFAULT_CONFIG;
    saadc_config.resolution = NRF_SAADC_RESOLUTION_12BIT;
    saadc_config.oversample = NRF_SAADC_OVERSAMPLE_4X;
    ret_code_t err_code = nrf_drv_saadc_init(&saadc_config, battery_event_handler);
    if (err_code != NRF_SUCCESS)
    {
        return;  /* SAADC busy — skip this cycle, retry next */
    }

    nrf_saadc_channel_config_t config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
    config.burst = NRF_SAADC_BURST_ENABLED;
    config.acq_time = NRF_SAADC_ACQTIME_10US;
    err_code = nrf_drv_saadc_channel_init(0, &config);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
    APP_ERROR_CHECK(err_code);
}

/*==============================================================================
 * battery_level_meas - Start a single battery voltage measurement
 *
 * Configures SAADC and triggers sampling. Result arrives asynchronously
 * via battery_event_handler.
 *============================================================================*/
void battery_level_meas(void)
{
    ret_code_t err_code;

    battery_configure();
    err_code = nrf_drv_saadc_sample();
    APP_ERROR_CHECK(err_code);
}


/*==============================================================================
 * battery_loop - Periodic battery monitoring timer callback
 *
 * Sets the low-battery check flag and starts a measurement.
 * Skips if info4 mode is active (SAADC conflict).
 *============================================================================*/
void battery_loop(void * p_context)
{
    UNUSED_PARAMETER(p_context);

    if (info4 == true)
    {
        return;
    }

    low_battery_check = true;
    battery_level_meas();
}

/* Start the periodic battery monitoring timer. */
void battery_timer_start(void)
{
    APP_ERROR_CHECK(app_timer_start(m_battery_loop_timer_id, APP_TIMER_TICKS(BATTERY_LOOP_INTERVAL), NULL));
}

/* Stop the battery monitoring timer. */
void battery_timer_stop(void)
{
    APP_ERROR_CHECK(app_timer_stop(m_battery_loop_timer_id));
}

/* Initialise the battery monitoring timer (repeated mode). */
void battery_timer_init(void)
{
    APP_ERROR_CHECK(app_timer_create(&m_battery_loop_timer_id, APP_TIMER_MODE_REPEATED, battery_loop));
}
