#include <LiquidCrystal.h>
#include "temperature.h"
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

//AdcSamples temperatureS0(A0, AdcSamples::BitRes::OS11);
AdcSamples temperatureS0(A0, AdcSamples::BitRes::OS16);
OverSampling overSamp(10, 16, 2);

#define P_OUTRANGE      900
#define N_OUTRANGE      120

const byte g_relayPin = 13;

int16_t g_temperature;
int16_t g_setpoint;
int16_t g_isteresi = 3 * 100; 


bool checkThermostate(bool state) {
  switch (state) {
    case LOW:
    if (g_temperature <= g_setpoint - g_isteresi) {
        state = HIGH;
    }
    break;
    case HIGH:
    if (g_temperature >= g_setpoint) {
        state = LOW;
    }
    break;
     
  } // end switch (thermostateState)
  return state;
} // end checkThermostate()


/** analog16Samples() colleziona 16 samples, 1 ogni 62ms 
    Somma tutti i 16 samples e divide questa per 16.
    Durante il collezionamento restituisce 0, mentre
    dopo avere tutti i 16 samples, calcola la media e la restituisce.
*/
uint16_t analog16Samples() {
    static uint16_t somma;
    static uint32_t timer62ms;
    static byte nSamples;

    if (millis() - timer62ms >= 62) {
        
        timer62ms = millis();
        somma += analogRead(A0);    // accumula i campioni
        nSamples++;
        if (nSamples == 16) {
            nSamples = 0;
            
            uint16_t media = somma / 16;  // calcola la media
            somma = 0;
            //Serial.println(media);
            if ((media < N_OUTRANGE) || (media > P_OUTRANGE)) {
                return 1024;
            }
            
            return media; // restituisce la media
        }
          
    }
    return 0;
}

// 14-bit 16384
// 16-bit 65535
float calcTemperature(uint16_t a0) {
    float average = a0;
    average = 65535.001 / average - 1;
    average = 10000.0 / average;
    //float steinhart;
    average = average / 10000.0;      // (R/Ro)
    average = log(average);           // ln(R/Ro)
    average /= 3950;                  // 1/B * ln(R/Ro)
    average += 1.0 / (25 + 273.15);   // + (1/To)
    average = 1.0 / average;          // Invert
    average -= 273.15;  
    return average;           
}


void setup()
{
    Serial.begin(115200);
    lcd.begin(16, 2);
    pinMode(2, INPUT_PULLUP);
        
    pinMode(g_relayPin, OUTPUT);
    uint32_t TotalADC = 0;
    Serial.println(micros());  // 13904
    for (uint16_t i=0; i<4096; i++) {
        TotalADC = TotalADC + analogRead(A0);
    }
    Serial.println(micros()); // 450412
    // 450412 - 13904 = 436508 us (436 ms)
    // 436508 / 4096 = 106,569us per campione alla freq di 125KHz
    // una conversione ADC impiega 13 cicli ADC un ciclo 
    // ADC dura (1/125000) * 13 = 0,000104s (0.104ms o 104us)
    // quindi la analogRead() non è poi così lenta.
    Serial.println(TotalADC);
    //overSamp.begin();
    temperatureS0.begin();
    
    

       
   
       
} // end void setup()


constexpr char *onoff[] = { "OFF", "ON " };
char temperatureBuffer[7];
// struttura di supporto
struct Setpoint {
  uint16_t _old;
  uint16_t _new = 1024;   // new != old
};

Setpoint mySetpoint;

float calcDelta(float newTemp) {
    static float oldTemp = -500;
    if (oldTemp == -500) {
        oldTemp = newTemp;
    } else {
        float deltat = fabs(newTemp - oldTemp);
        oldTemp = newTemp;
        return deltat;
    }
    return oldTemp;
}

byte counterAbnormal;
uint32_t t;
bool q = true;
bool x;
void loop() {
    temperatureS0.run();
    if (temperatureS0.available()) {
        uint32_t t = temperatureS0.read();
        Serial.println(t);
        Serial.println(calcTemperature(t), 4);
        delay(250);
        //Serial.println(calcTemperature(temperatureS0.lastMedia()));
    }
     
     #if(0)
  // a0 contiene una lettura aggiornata ogni 62ms x 16 = 992ms
  uint16_t a0 = analog16Samples();
  // entra nella if (a0 != 0) ogni 992ms
  if ((a0 > 0) && (a0 != 1024)) {
      //Serial.println(millis());
      //Serial.println(temperatureS0.lastMedia());
     
      // converte a0 in tf.
      float tf = calcTemperature(a0);
      // converte tf nella C string temperatureBuffer
      
      dtostrf(tf, 6, 1, temperatureBuffer);
      if ((uint16_t)calcDelta(tf) > 5) {
          counterAbnormal++;
      }
      if (counterAbnormal > 5) {
          Serial.println("Check sensor!");
          counterAbnormal = 0;
      }
        



      // tronca e converte tf in int16_t
      g_temperature = tf * 100;
      // visualizza la C string temperatureBuffer sul display
      lcd.setCursor(0, 1);
      lcd.print(temperatureBuffer);
      // chiama la funzione termostato
      bool thState = checkThermostate(digitalRead(g_relayPin));
      digitalWrite(g_relayPin, thState);
      // visualizza ON/OFF sul display
      lcd.setCursor(10, 0);
      lcd.print(onoff[thState]);
  } else if (a0 == 1024) {
      // c'è un problema con la sonda
      lcd.setCursor(0, 1);
      lcd.print("ER:S00");
      bool thState = LOW;
      digitalWrite(g_relayPin, thState);
      lcd.setCursor(10, 0);
      lcd.print(onoff[thState]);

  }

  // usa struttura di supporto 
  mySetpoint._old = analogRead(A1);
  if (mySetpoint._old != mySetpoint._new) {
      mySetpoint._new = mySetpoint._old;
     
      float stpf = mySetpoint._new / 13.3;
      g_setpoint = stpf * 100;    // da float a uint16_t
      dtostrf(stpf, 6, 1, temperatureBuffer);
     
      lcd.setCursor(0, 0);
      lcd.print(temperatureBuffer);
  }
  #endif 
    
} // end void loop()
nano:12
nano:11
nano:10
nano:9
nano:8
nano:7
nano:6
nano:5
nano:4
nano:3
nano:2
nano:GND.2
nano:RESET.2
nano:0
nano:1
nano:13
nano:3.3V
nano:AREF
nano:A0
nano:A1
nano:A2
nano:A3
nano:A4
nano:A5
nano:A6
nano:A7
nano:5V
nano:RESET
nano:GND.1
nano:VIN
nano:12.2
nano:5V.2
nano:13.2
nano:11.2
nano:RESET.3
nano:GND.3
lcd:VSS
lcd:VDD
lcd:V0
lcd:RS
lcd:RW
lcd:E
lcd:D0
lcd:D1
lcd:D2
lcd:D3
lcd:D4
lcd:D5
lcd:D6
lcd:D7
lcd:A
lcd:K
r1:1
r1:2
pot2:GND
pot2:SIG
pot2:VCC
ntc1:GND
ntc1:VCC
ntc1:OUT
led1:A
led1:C
NOCOMNCVCCGNDINLED1PWRRelay Module
relay2:VCC
relay2:GND
relay2:IN
relay2:NC
relay2:COM
relay2:NO
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r