/*==============================================================================
 * tmp235_q1.c - TMP235-Q1 analogue temperature sensor driver
 *
 * Reads the TMP235-Q1 analogue output via SAADC AIN3 and converts to deg C.
 *
 * Temperature conversion (piecewise linear, per datasheet):
 *   Vout <= 1500 mV  (0..100 C)  : Ta = (Vout - 500)    / 10.0
 *   Vout <= 1750 mV  (100..125 C): Ta = (Vout - 1500)    / 10.1 + 100
 *   Vout <= 2000 mV  (125..150 C): Ta = (Vout - 1752.5)  / 10.6 + 125
 *   Vout > 2000 mV               : out of sensor range
 *============================================================================*/

#include "sdk_common.h"

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_drv_saadc.h"
#include "ble_nus.h"
#include "tmp235_q1.h"
#include "main.h"
#include "main_timer.h"
#include "battery_saadc.h"
#include "debug_print.h"

/* SAADC internal reference (mV) */
#define TMP235_REF_VOLTAGE_IN_MILLIVOLTS        600.0f
/* 1/3 prescaling compensation (x6) */
#define TMP235_PRE_SCALING_COMPENSATION         6.0f
/* 12-bit ADC full scale */
#define TMP235_ADC_RES_12BITS                   4096.0f

/* Convert raw ADC value to TMP235 output voltage (mV) */
#define TMP235_VOUT_IN_MILLI_VOLTS(ADC_VALUE)\
        ((((ADC_VALUE) * TMP235_REF_VOLTAGE_IN_MILLIVOLTS) / TMP235_ADC_RES_12BITS) * TMP235_PRE_SCALING_COMPENSATION)

static nrf_saadc_value_t adc_buf;
extern char     ble_tx_buffer[BLE_NUS_MAX_DATA_LEN];
extern uint8_t  ble_bin_buffer[BLE_NUS_MAX_DATA_LEN];

extern which_cmd_t cmd_type_t;
extern bool info4;
extern bool go_temp;

/* info4 mode: cached temperature (deg C x 100, integer) */
volatile uint16_t info_temp;
extern bool motion_raw_data_enabled;

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


/*==============================================================================
 * tmp235_voltage_handler - SAADC conversion complete callback
 *
 * ADC value -> Vout (mV) -> temperature (deg C), then:
 *   - info4 mode: store to info_temp (C x 100 integer)
 *   - Normal mode: send rso: response over BLE or UART
 *============================================================================*/
void tmp235_voltage_handler(nrf_drv_saadc_evt_t const * p_event)
{
    float led_temp;
    float led_temp_16;

    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        nrf_saadc_value_t adc_result;
        float tmp235_voltage_in_milli_volts = 0;

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

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

        /* ADC -> TMP235 output voltage (mV) */
        tmp235_voltage_in_milli_volts = TMP235_VOUT_IN_MILLI_VOLTS(adc_result);

        /* Vout -> temperature (piecewise linear per datasheet) */
        if(tmp235_voltage_in_milli_volts <= 1500)
        {
            /* 0..100 C: slope 10.0 mV/C, offset 500 mV */
            led_temp = (tmp235_voltage_in_milli_volts - 500.0f) / 10.0f + 0.0f;
        }
        else if(tmp235_voltage_in_milli_volts <= 1750)
        {
            /* 100..125 C: slope 10.1 mV/C */
            led_temp = (tmp235_voltage_in_milli_volts - 1500.0f) / 10.1f + 100.0f;
        }
        else if(tmp235_voltage_in_milli_volts <= 2000)
        {
            /* 125..150 C: slope 10.6 mV/C */
            led_temp = (tmp235_voltage_in_milli_volts - 1752.5f) / 10.6f + 125.0f;
        }
        else
        {
            /* Out of sensor range (>150 C) */
            DBG_PRINTF("ERR!!! Temperature is over 150c\r\n");
        }

        /* --- Safety check mode: pass temperature to battery module for judgment --- */
        if (safety_check_mode == true)
        {
            safety_check_mode = false;
            safety_check_complete(led_temp);
        }

        /* --- info4 mode: store value for mbb? bulk response --- */
        else if (info4 == true)
        {
            info_temp = (uint16_t)(led_temp * 100);
        }
        else if (cmd_type_t == CMD_UART)
        {
            DBG_PRINTF("To%.2f\r\n\r\n", led_temp);
        }
        else if (cmd_type_t == CMD_BLE)
        {
            led_temp_16 = led_temp * 100;
            single_format_data(ble_bin_buffer, "rso:", (uint16_t)led_temp_16);
            dr_binary_tx_safe(ble_bin_buffer, 3);
        }

        tmp235_saadc_done = true;
    }
}


/*==============================================================================
 * tmp235_init - Initialise SAADC for TMP235 and start measurement
 *
 * AIN3, single-ended, 12-bit, 4x oversampling, burst enabled.
 * Triggers sampling immediately; result arrives via tmp235_voltage_handler.
 *============================================================================*/
void tmp235_init(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, tmp235_voltage_handler);
    APP_ERROR_CHECK(err_code);

    nrf_saadc_channel_config_t config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3);
    config.burst = NRF_SAADC_BURST_ENABLED;
    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);

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


/*==============================================================================
 * tmp235_voltage_level_meas - External entry point for one-shot reading
 *
 * Calls tmp235_init() which both initialises and triggers sampling.
 *============================================================================*/
void tmp235_voltage_level_meas(void)
{
    tmp235_init();
}
