#include "uksi_calc_res.h"


/** 
  * @brief    Конфигуарция коэфициентов АЦП.
  * @param    adc       Указатель на кастомный хендл АЦП
  * @param    levelZero Нулевой уровень (в квантах АЦП)
  * @param    valueMax  Максимальный уровень Единиц Измерения (в Вольтах/Амперах/Градусах)
  * @param    levelMax  Максимальный уровень АЦП (в квантах АЦП)
  * @return   HAL Status.
  */
HAL_StatusTypeDef ADC_ConfigCoef(ADC_t *adc, uint16_t levelZero, float valueMax, uint16_t levelMax, uint16_t lOffset)
{
  HAL_StatusTypeDef res;
  if(check_null_ptr_1(adc))
    return HAL_ERROR;
  if((valueMax == 0) || (levelMax == 0))
    return HAL_ERROR;
   
  adc->Coefs.lMax   = levelMax;
  adc->Coefs.vMax   = valueMax;
  adc->Coefs.lZero  = levelZero;
  adc->Coefs.lOffset  = lOffset;
  
  return HAL_OK;
}

/** 
  * @brief    Конфигуарция фильтров АЦП.
  * @param    adc       Указатель на кастомный хендл АЦП
  * @param    levelZero Нулевой уровень (в квантах АЦП)
  * @param    valueMax  Максимальный уровень Единиц Измерения (в Вольтах/Амперах/Градусах)
  * @param    levelMax  Максимальный уровень АЦП (в квантах АЦП)
  * @return   HAL Status.
  */
HAL_StatusTypeDef ADC_ConfigFilter(ADC_t *adc, uint8_t median_size, uint32_t average_size)
{
  HAL_StatusTypeDef res;
  if(check_null_ptr_1(adc))
    return HAL_ERROR;
   
  FilterMedianInt_Init(&adc->mdn, median_size, 0);
  FilterAverageInt_Init(&adc->avg, average_size, FILTER_MODE_DEFAULT);
  
 
  Filter_Start(&adc->mdn);
  Filter_Start(&adc->avg);
  
  return HAL_OK;
}
/** 
  * @brief    Расчет напряжения на АЦП.
  * @param    adc       Указатель на кастомный хендл АЦП
  * @param    rawval    Сырое значение АЦП
  * @return   Напряжение (float).
  */
float ADC_Calc(ADC_t *adc)
{
  if(check_null_ptr_1(adc))
    return 0;
  ADC_Coefs_t *coefs  = &adc->Coefs;
  
  int16_t rawval = HAL_ADC_GetValue(adc->hadc);
  
  
  rawval = Filter_Process(&adc->mdn, rawval);
  rawval = Filter_Process(&adc->avg, rawval);
  
  rawval -= coefs->lOffset;
  if(rawval < 0)
    rawval = 0;
  if(rawval >4095)
    rawval = 4095;
  adc->Raw = rawval;  
  
  adc->Voltage = ((float)(rawval)-coefs->lZero) * coefs->vMax / (coefs->lMax-coefs->lZero);
  return adc->Voltage;
}

HAL_StatusTypeDef UKSI_Calc_Init(UKSI_Calc_t *calc, ADC_HandleTypeDef *hadc)
{
  if(check_null_ptr_2(calc, hadc))
    return HAL_ERROR;
  
  calc->adc.hadc = hadc;
//  ADC_ConfigCoef(&calc->adc, 0, 1.259, 1639, 14);
  ADC_ConfigCoef(&calc->adc, 0, 0.529, 703, 14);
  ADC_ConfigFilter(&calc->adc, 10, 50000);
  
  calc->RMeasOhm = 35060;
  calc->RLimitOhm = 1.5e6;
  calc->DCVoltage = 31.58;//60;
  
  foster_init(&calc->adc.foster, 3000.0f);
  foster_set_mse(&calc->adc.foster, 0.001f); /* Подберите под ваши значения напряжения */
  
  HAL_ADCEx_Calibration_Start(hadc, ADC_SINGLE_ENDED);
  
  calc->IsoOhm = 100e6;
  calc->IsoMOhm = calc->IsoOhm / 1000000.0f;
  
  return HAL_ADC_Start(hadc);
}


/** 
  * @brief    Расчет изоляции.
  * @param    calc       Указатель на структуру для расчета изоляции
  * @return   Сопротивление изоляции (float).
  */
float UKSI_Calc_Isolation(UKSI_Calc_t *calc)
{
  if(check_null_ptr_1(calc))
    return 0;
  
  float voltage = ADC_Calc(&calc->adc);
  
  if(Filter_isDataReady(&calc->adc.avg))
  {
    /* Расчет тока */
    float current = voltage / calc->RMeasOhm;
    calc->IsoCurrentuA = current * 1000000.0f;
    
    /* Проверка стабильности напряжения */
    foster_add_sample(&calc->adc.foster, voltage);
       
    if(foster_is_ready(&calc->adc.foster)) {
      uint8_t stability = foster_check(&calc->adc.foster);
      calc->adc.is_stable = stability;
      
      /* Если нестабильно, возвращаем 0 или предыдущее значение */
      if(stability == 1) { /* Нестабильно */
        return calc->IsoOhm; /* Или calc->IsoOhm для сохранения последнего значения */
      }
    }
    
    /* Расчет изоляции */    
    float Rtotal = calc->DCVoltage / current;
    float Riso = Rtotal - (calc->RMeasOhm + calc->RLimitOhm);
    
    calc->IsoOhm = Riso;
    calc->IsoMOhm = Riso / 1000000.0f;
    
  }
  return calc->IsoOhm;
}


