/*************************************************************
  Energie Sensor (Spannung / Strom / Leistung)
  - Empfängerspannung über Ext Eingang

  Um Messfehler zu klein zu halten ist die genaue Referenzspannung sehr wichtig. AVcc ist mit der Versorgungsspannung belegt.
  R1 an Vcc, R2 an GND
                     R1+R2    4K4+2K2
  Teilerverhältnis = -----    ------- = 3
                      R2        2K2
                   
                   Referenzspannung   5060mV
  Bereichsbreite = ----------------   ------ = 4,946mV je Tick
                     Maximalwert      1023

  Messwert vom ADC umwandeln in Spannung:
  Spannung = ADCwert * Bereichsbreite * Teilerverhältnis



  Empfängerspannung am Ext Anschluss.
  Spannungsteiler, halbe Spg. am Analog Pin, max. 10V
  
          8V4 (max. 10V)
           |
          1K
           |
  PinA6 ---|  (max 5V)
           |
          1K
           |
          GND

  Testergebnis:
  RX = 7.07V, Mitte = 3.53V > ADC 716
  5000mV / 1023 = ADC 4,8875855 mV / Tick
  Anzeige 6.99 - 7.00V
  ------------------------------------------------------------
  
  Copyright (C) 2017 Thomas Lehmann
  
  Version history:
  1.00   23.12.2017  created

***************************************************************/

#define SENS_POWER_CPP

#include "SensPower.h"




#if _SENS_VOLT_ == 1

// Klasse indizierbar, Aufruf je Sensor
// ====================================
bool SensorPwrVolt::Init( uint8_t Id, uint8_t VIdx )
{
  // uV je Tick, AVcc / 1023 Schritte, nK:nK = Teiler 1:x
  VoltScale = GData.ADCuV * ((GData.EEprom.Data.CfgVoltRVcc[VIdx] + GData.EEprom.Data.CfgVoltRGnd[VIdx]) / GData.EEprom.Data.CfgVoltRGnd[VIdx]);
  PinVolt = PIN_VOLT(VIdx);

  TmoRefresh = PWR_VOLT_TMO_REFRESH + Id;     // Zeit bis zur 1. Messung
  return( true );
}


// ==========
// 10mS Timer
// ==========
void SensorPwrVolt::Tim10mS()
{
  // Refresh Spannungsmessung ?
  if( --TmoRefresh == 0 )
    {
    TmoRefresh = PWR_VOLT_TMO_REFRESH;          // Zeit bis zur nächsten Messung

    // A/D Wandler lesen 0-1023 = 0-5V
    // Ergebnis in uV, Telewert 2 dez Stellen 1234mV = 12.34V / 10 >> 1.23V
    TVal.VoltageDez2 = (analogRead(PinVolt) * VoltScale) / 1000.0 / 10.0;
    }
}

#endif





#if _SENS_MUI_  == 1
// Klasse indizierbar, Aufruf je Sensor
// ====================================
#define CFG_MUI GData.EEprom.Data.CfgMuiCapaRes[SensIdx]
bool SensorPwrMui::Init( uint8_t Id, uint8_t SensIdx )
{
  MuiIdx = SensIdx;

  // kein SensorTyp obwohl analog Port für Stromsensor konfiguriert (nur dann ist MUI aktiv)?
  if( GData.EEprom.Data.CfgMuiSensTyp[MuiIdx] == STYP_MUI_ACS_NONE )
    return( false );
  CapaResSw = MainEnableSw(CFG_MUI);              // ggf. Tasten Abfrage aktivieren, Rückgabe ist SW Idx
  if( CFG_MUI >= RESFCT_AUTO )                    // Kapazität auto Rücksetzen bei Überschreiten der letzten Akkuspg. um n%
    {
    uint16_t mV = GetVoltage();                   // Spg. holen
    uint8_t Proz = CFG_MUI - RESFCT_AUTO + 100;   // 0% = auto > immer
    if( mV >= (GData.EEprom.NV.MuiVolt[MuiIdx] * (Proz/100.0)) )
      CapaReset();
/*
TermPutTxt(" AkkuSpg: ");
TermPut(mV);
TermPutTxt(" Saved: ");
TermPut(GData.EEprom.NV.MuiVolt[MuiIdx]);
TermPutTxt(" Diff: ");
TermPut(GData.EEprom.NV.MuiVolt[MuiIdx] * (Proz/100.0));
TermPutTxt(" Capa: ");
TermPutln(GData.EEprom.NV.MuiCapaConsumed[MuiIdx]);
*/
    }
                                                  // im NV sichern solbald 10mAh entnommen wurden
  CapaStart = GData.EEprom.NV.MuiCapaConsumed[MuiIdx] + 10;

  TmoRefresh = PWR_MUI_TMO_REFRESH + Id;          // Zeit bis zur 1. Messung
  return( true );
}
#undef CFG_MUI



// ==========
// 10mS Timer
// ==========
void SensorPwrMui::Tim10mS()
{
  if( TmoRefresh == 0 )                           // nicht aktiv
    return;

  // Kapazitäts Reset per Taster ?
  if( BIT_TST(GData.Switch.Activ, CapaResSw) )    // Rücksetztaster betätigt ?
    CapaReset();

  // Refresh Messwerte ?
  if( --TmoRefresh == 0 )
    {
    TmoRefresh = PWR_MUI_TMO_REFRESH;             // Zeit bis zur nächsten Messung
    uint16_t mA = GetCurrent();                   // Strom berechnen
    uint16_t mV = GetVoltage();                   // Spg. holen

    TVal.CurrentDez2 = mA / 10.0;                 // Übergabe in Ampere mit 2 dez Stellen
    TVal.VoltageDez2 = mV / 10.0;                 // Telewert 2 dez Stellen 1234mV = 12.34V / 10 >> 1.23V

TermPutTxt("mA: ");
TermPut(TVal.CurrentDez2);

    GData.EEprom.NV.MuiVolt[MuiIdx] = mV;         // letzte Spg. Lage für Auto Rücksetzen merken, gespeichert wird bei Stromfluss
    }
}

uint16_t SensorPwrMui::GetVoltage( void )
{
  if( PIN_MUI_V(MuiIdx) == 0 )                    // haben wir auch einen passenden Spg. Pin ?
    return( 0 );
  // uV je Tick, AVcc / 1023 Schritte, nK:nK = Teiler 1:x
  float VoltScale = GData.ADCuV * ((GData.EEprom.Data.CfgMuiRVcc[MuiIdx] + GData.EEprom.Data.CfgMuiRGnd[MuiIdx]) / GData.EEprom.Data.CfgMuiRGnd[MuiIdx]);

  // A/D Wandler lesen 0-1023 = 0-5V
  float mV = ((analogRead(PIN_MUI_V(MuiIdx)) * VoltScale)) / 1000.0;

  return( (uint16_t)mV );
}


// Strom ... berechnen
// ===================
// Rückgabe ist akt. Stromfluss in mA
// nur 16 BIT da Funktion nur zur Kalibrierung per JB benötigt wird
uint16_t SensorPwrMui::GetCurrent( void )
{
  uint8_t STyp = GData.EEprom.Data.CfgMuiSensTyp[MuiIdx];   // eingestellter SensorTyp
  float uVOffs = GData.EEprom.Data.CfgMuiCalib[MuiIdx]*1000;  // Kalibrierung auf 0
  if( STyp >= STYP_MUI_ACS758_50B )
    uVOffs += ACS_B_OFFS(GData.EEprom.Data.AVcc) * 1000.0;  // bi-direktionale Typen, Offs halbe Refspannung
  else
    uVOffs += ACS_U_OFFS(GData.EEprom.Data.AVcc) * 1000.0;  // uni-direktionale Typen

  float uV = analogRead(PIN_MUI_A(MuiIdx)) * GData.ADCuV;
  float mA = (uV - uVOffs) / pgm_read_byte(&Acs[STyp].mVperAmp);
  if( mA < 0 )                                  // es ist ja kein Generator ;)
    mA = 0;

  MesureTime = millis() - MesureTime;           // Entnahme anteilig auf 1h gerechnet
  GData.EEprom.NV.MuiCapaConsumed[MuiIdx] += mA * MesureTime / (60*60*1000.0);
  MesureTime = millis();
  // ausreichend entnommen zum Sichern ?
  if( GData.EEprom.NV.MuiCapaConsumed[MuiIdx] > CapaStart )
    {                                           // triggern solange Strom fliesst
    CapaStart = GData.EEprom.NV.MuiCapaConsumed[MuiIdx];
    CapaStart++;
    GData.Signal |= SIG_SAVE2NV;
    }
  // verbrauchte
  TVal.CapaConsumed = GData.EEprom.NV.MuiCapaConsumed[MuiIdx];


/*
TermPutTxt(" mV: ");
TermPut(uV/1000);
TermPutTxt(" mA: ");
TermPut(mA);
TermPutTxt(" / ");
TermPut(TVal.CurrentDez2);
TermPutTxt(" Capa: ");
TermPut(GData.EEprom.NV.MuiCapaConsumed[MuiIdx]);
TermPutTxt(" Start: ");
TermPutln(CapaStart);
*/

/*
TermPutTxt("consumed: ");
TermPut(TVal.CapaConsumed);
TermPutTxt(" remain: ");
TermPut(TVal.CapaRemain);
TermPutTxt(" A: ");
TermPut(TVal.CurrentDez2);
TermPutTxt(" V: ");
TermPut(TVal.VoltageDez2);
TermPutTxt(" W: ");
TermPutln(TVal.Watt);
*/
  return( (uint16_t)mA );
}




#endif





