/*
 * adc_temp.c
 *
 * Measure output of temperature sensor with ADC.
 *
 *  Created on: 2023/06/09
 *      Author: BestTechnology
 */

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

#include "hal_data.h"

#include <stdint.h>

#include "adc_temp.h"

#include "interpolation.h"

// Apparently, the calculation results are not in accordance with the theoretical values, so an offset value is added to the analog measured values.
#define _MTORTEMP_OFFSET    (2000)
#define _AMPTEMP_OFFSET     (-6000)

// ADC values
// 0:NTC near motor, 1:HVPAK temp out, 2:MPU temp out
static double adc_value[3] = {0};

// SMA
static double movingmean (double *ave, double dat, int32_t num) {
  *ave = (*ave * (num - 1.0) + dat) / (double)num;
  return *ave;
}

////////////////////////////////////////////////////////////
// For temperature sensors
////////////////////////////////////////////////////////////
// INTERP 1D data for NTC to degC
// murata NCP15WB473E03RC (R0=47000,B=4050,R=8200,VP=3.3,T0=25)
static const int32_t interp_ntc_1d[] = {
  11141,13721,16734,20113,23713,27318,30687,33613,35972,37743,38988,  // x (adc value * 10)
   1000,  900,  800,  700,  600,  500,  400,  300,  200,  100,    0,  // y (degC * 10)
};
static const int32_t interp_ntc_ar_w = (sizeof (interp_ntc_1d) / sizeof (interp_ntc_1d[0])) / 2;

// INTERP 1D data for SLG47115's temp to degC
static const int32_t interp_hvamp_1d[] = {
   9705, 10072, 10436, 10617, 10801, 11159, 11519, 11874, 12225, 12574, 12748, 12925, 13270, 13615, 13957, 14297, 14634, 14964, // x (adc value * 10)
   1100,  1000,   900,   850,   800,   700,   600,   500,   400,   300,   250,   200,   100,    00,  -100,  -200,  -300,  -400  // y (degC * 10)
};
static const int32_t interp_hvamp_ar_w = (sizeof (interp_hvamp_1d) / sizeof (interp_hvamp_1d[0])) / 2;

int get_motor_temp (void) {
    return interp1dim (((int)adc_value[0] * 10 + _MTORTEMP_OFFSET), interp_ntc_1d, interp_ntc_ar_w);
}

int get_hvamp_temp (void) {
    return interp1dim (((int)adc_value[1] * 10 + _AMPTEMP_OFFSET), interp_hvamp_1d, interp_hvamp_ar_w);
//    return adc_value[1];
}

// TODO:Calibration value returns only 0, so operations are handled only with fixed values.
int get_cpu_temp (void) {
#if 1
    return (int)((((double)adc_value[2] * 0.196551f) - 277.439f) * 10.0);
#else
#define ADC_EXAMPLE_VCC_MICROVOLT                       (3300000)
#define ADC_EXAMPLE_TEMPERATURE_RESOLUTION              (12U)
#define ADC_EXAMPLE_REFERENCE_CALIBRATION_TEMPERATURE   (127)
#define TSN_ADC_COVERSION_SLOPE_COUNTS_PER_DEG_C        (5.08896f)
#define TSN_CAL_OFFEST_COUNTS_AT_127DEG_TO_0DEG_C       (646)

    adc_info_t adc_info;
    (void) R_ADC_InfoGet(&g_adc0_ctrl, &adc_info);
    double mcutemp = (double) (((double)adv[2] - (((double) adc_info.calibration_data) - TSN_CAL_OFFEST_COUNTS_AT_127DEG_TO_0DEG_C)) / TSN_ADC_COVERSION_SLOPE_COUNTS_PER_DEG_C);
    return (int)mcutemp;
#endif
}

void update_adcvalue (void) {
    uint16_t adcv;
    R_ADC_Read (&g_adc0_ctrl, ADC_CHANNEL_2, &adcv);
    movingmean (&adc_value[0], adcv, 100);
    R_ADC_Read (&g_adc0_ctrl, ADC_CHANNEL_13, &adcv);
    movingmean (&adc_value[1], adcv, 300);
    R_ADC_Read (&g_adc0_ctrl, ADC_CHANNEL_TEMPERATURE, &adcv);
    movingmean (&adc_value[2], adcv, 1);
}

#pragma GCC pop_options
