#include <stdio.h>
#include "sysdata.h"
#include "self_discharge.h"

#define HOLD_TIME (10800 ) //10800 = 3 stunde
#define SD_FILTER 64

int16_t SELF_DISCHARGE_Exec(void)
{

  const double batt_float_voltage_tol = 0.03;
  const int32_t batt_voltage_holding_tol = 10;
  int32_t max_u = sys_data.s.parameter.uBatFull * ( 1 + batt_float_voltage_tol);
  int32_t min_u = sys_data.s.parameter.uBatFull * ( 1 - batt_float_voltage_tol);
  static uint32_t holding_counter = 0;
  static int32_t  u_hold = 0;


  sys_data.s.values.selfDischargeTime = holding_counter;

  int32_t u = sys_data.s.values.batteryVoltage;

  if (u > max_u) 
  {
    u_hold = 0;
    holding_counter = 0;
    return -1;
  }

  if (u < min_u) 
  {
    u_hold = 0;
    holding_counter = 0;
    return -1;
  }

  //Bin im richtigen Spannungsbereich, zu haltende Spannung speichern
  if (u_hold == 0)
  {
    u_hold = u;
  }

  int32_t u_hold_max = u_hold + batt_voltage_holding_tol;
  int32_t u_hold_min = u_hold - batt_voltage_holding_tol;

  if (u > u_hold_max)
  {
    u_hold = 0;
    holding_counter = 0;
	//printf("self_discharge: fail voltage too  high!\n");
    return -2;
  }


  if (u < u_hold_min)
  {
    u_hold = 0;
    holding_counter = 0;
	//printf("self_discharge: fail voltage too  low!\n");
    return -2;
  }


  if (sys_data.s.values.batteryCurrent < sys_data.s.parameter.extraDischargeStrom_mA)
  {
	//Abbruch Ladegerät wurde entfernt, wir müssen mindesten den Lipro Strom messen
    u_hold = 0;
    holding_counter = 0;
	//printf("self_discharge: fail current too small!\n");
    return -3;
  }

  holding_counter++;
  if (holding_counter > HOLD_TIME)
  {
    sys_data.s.values.selfDischarge = sys_data.s.values.batteryCurrent -  sys_data.s.parameter.extraDischargeStrom_mA;
  }


  //Wenn ein gültiger Wert gemessen wurde, dann zu Mittelwert hinzufügen
  if (sys_data.s.values.selfDischarge > 0)
  {

    // --- Mittelwert --- 
    static uint32_t last_days;
    static unsigned long avgsum = 0;

    // Converting seconds into days
    uint32_t days = sys_data.s.values.onTime / (24U * 3600U);

    // Alle 24 Stunden ein Wert zur Mittelwertberechnung hinzufügen
    if (days != last_days)
    {
      last_days = days;
    
      uint32_t avgval;
      // Filterlängen in 2er-Potenzen --> Compiler optimiert 
      avgsum -= avgsum/SD_FILTER;
      avgsum += sys_data.s.values.selfDischarge;
      avgval = avgsum / SD_FILTER;

      sys_data.s.values.selfDischargeAvg = avgval;
    }

  }

  
 
  return 0;


}