/**
  ******************************************************************************
  * @file    meas.c
  * @author  ECS, Falko Jahn  
  * @version V1.0.0
  * @date    30-Jan-2021
  * @brief   Measurement Modul
  *          Beschreibung in Header
  ******************************************************************************
  */ 

// --- INCLUDES ----------------------------------------------------------------
#include "meas.h"
#include "main.h"
#include "adc.h"
#include "stdio.h"
#include "sysdata.h"
//--- GGF. EXTERNE VARIABLEN ---------------------------------------------------  

//--- LOKALE DEFINES - bitte hier dokumentieren --------------------------------
#define ADC_CONVERTED_DATA_BUFFER_SIZE  4
#define VREF                            2500 //in mV
#define CELL_VOLTAGE_DIVIDER            2
#define ADC_RESOLUTION                  65536 //16 bit AD Wandler durch Oversampling

#define CELL_VOLTAGE_FILTER             8    // Filterlängen in 2er-Potenzen --> Compiler optimiert 
#define CELL_TEMPERATURE_FILTER         8
#define BALANCER_CURRENT_FILTER         8
//--- LOKALE TYPE DEFS - bitte hier dokumentieren-------------------------------

//--- DEFINATIONEN GLOBALER VARIABLEN - Bitte in Header dokumentieren ----------

//--- LOKALE VARIABLEN - bitte hier dokumentieren ------------------------------
__IO  uint16_t  aADCxConvertedData[ADC_CONVERTED_DATA_BUFFER_SIZE]; /* ADC group regular conversion data (array of data) */
__IO  uint32_t  newADCDataFlag;
uint32_t        currentOffset;
uint32_t        totalMeas;


//--- LOKALE FUNKTIONS PROTOTYPEN ---------------------------------------------- 
uint32_t calcCellVoltageFiltered(void);    
uint32_t calcCellVoltageUnfiltered(void);    
int32_t  calcCellTemperature(void);
uint32_t calcBalancerCurrent(void);
extern uint32_t initRefresh;

//--- LOKALE FUNKTIONEN - bitte hier dokumentieren -----------------------------


//--- GLOBALE FUNKTIONEN - bitte in Header dokumentieren------------------------
void MEAS_Init()
{
  if (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK)
  {
    printf("HAL_ADCEx_Calibration_Start: ERROR\n");
    return;
  }
   printf("HAL_ADCEx_Calibration_Start: OK\n");

  if (HAL_ADC_Start_DMA(&hadc1, (uint32_t *)aADCxConvertedData, ADC_CONVERTED_DATA_BUFFER_SIZE ) != HAL_OK)
  {
    /* ADC conversion start error */
    printf("Error HAL_ADC_Start_DMA\n");
    return;
  }
  printf("HAL_ADC_Start_DMA: OK\n");

  //---- Offset calibrierung ---
  //Warte bis Mittelwert gebildet
  while (totalMeas < 100)
  {
    MEAS_Exec();
    initRefresh = 1;
  }

  currentOffset = calcBalancerCurrent();



}

void MEAS_Exec()
{
  if (newADCDataFlag)
  {
    totalMeas++;
    sysData.s.cellVoltage = calcCellVoltageFiltered();
    sysData.s.cellVoltageUnfiltered = calcCellVoltageUnfiltered();
    sysData.s.cellTemperature = calcCellTemperature();
    sysData.s.balancerCurrent = calcBalancerCurrent() - currentOffset;
    newADCDataFlag=0;
  }

}

/**
  * @brief  Conversion complete callback in non blocking mode 
  * @param  hadc: ADC handle
  * @note   This example shows a simple way to report end of conversion
  *         and get conversion result. You can add your own implementation.
  * @retval None
  */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{  
  newADCDataFlag = 1;
}


uint32_t calcCellVoltageFiltered()
{
  static unsigned long avgsum = 0;

  //ADC Wert gefiltert
  uint32_t adcValue;  
                      
  //Wert umgerechnet in Spannung [mV]
  uint32_t u;

  //Filter
  avgsum -= avgsum / CELL_VOLTAGE_FILTER;
  avgsum += aADCxConvertedData[1];;
  adcValue = avgsum / CELL_VOLTAGE_FILTER;
 
  //Umrechnung in Spannung 
  u = (adcValue * VREF * CELL_VOLTAGE_DIVIDER) / ADC_RESOLUTION;

  return u;
}

uint32_t calcCellVoltageUnfiltered()
{
  static unsigned long avgsum = 0;

  //ADC Wert gefiltert
  uint32_t adcValue;  
                      
  //Wert umgerechnet in Spannung [mV]
  uint32_t u;
  adcValue = aADCxConvertedData[1];;
 
 
  //Umrechnung in Spannung 
  u = (adcValue * VREF * CELL_VOLTAGE_DIVIDER) / ADC_RESOLUTION;

  return u;
}



int32_t calcCellTemperature()
{
  static unsigned long avgsum = 0;

  //ADC Wert gefiltert
  uint32_t adcValue;  
                      
  //Wert umgerechnet in Spannung [mV]
  uint32_t u;

  //Wert umgerechnet in [°C ]
  int32_t temp;

  //Filter
  avgsum -= avgsum / CELL_TEMPERATURE_FILTER;
  avgsum += aADCxConvertedData[2];
  adcValue = avgsum / CELL_TEMPERATURE_FILTER;
 
  //Umrechnung in Spannung 
  u = (adcValue * VREF ) / ADC_RESOLUTION;


  //Umrechnung in Grade C
  temp = u;
  temp = temp - 600;
  temp = temp * 100;
  temp = temp / 100; //Von Milligrad in Grad * 10 
  return temp;
}

uint32_t calcBalancerCurrent()
{
  static unsigned long avgsum = 0;

  //ADC Wert gefiltert
  uint32_t adcValue;  
                      
  //Wert umgerechnet in Spannung [mV]
  uint32_t u;

  //Wert umgerechnet in mA 
  int32_t i;

  //Filter
  avgsum -= avgsum / BALANCER_CURRENT_FILTER;
  avgsum += aADCxConvertedData[0];
  adcValue = avgsum / BALANCER_CURRENT_FILTER;
 
  //Umrechnung in Spannung 
  u = (adcValue * VREF ) / ADC_RESOLUTION;

  //Umrechnung in Strom  
  //u = u / 100; //Verstärkunsfaktor INA180A3
  //i = u / 0.001; Shunt Widerstand  
  //Die beiden letzten Zeilen wurden zusammengefasst in
  i = u * 10;

  return i;

}