#include <OneWire.h>
#include <DallasTemperature.h>
#include <EEPROM.h>

#define MIN_TEMP 10.0
#define MAX_TEMP 24.0
#define ERR_TEMP 88.0

//
// IO Ports
//
// display
//const int displayAPin = 2; // @A : out
//const int displayBPin = 3; // @B : out
//const int displayCPin = 4; // @C : out
//const int displayDPin = 5; // @D : out
const int displayDEnablePin = 6; // !Enable : out
const int displayUEnablePin = 7; // !Enable : out

const int displayAddress [] = { 2, 3, 4, 5}; // Ports connectes aux afficheurs

// Command
const int CmdePin = 8; // Cmd : out;

// Sensor 1-Wire
const int SensorPin = 9; // Sensor : in/out

// Keys
const int KeyUpPin = 14; // Up : in
const int KeyDwPin = 15; // Down : in
const int KeyModePin = 10; // Mode : in

// Trimmer
const int TrimPin = 2; // Trimmer : analog in

//
// Variables
//
byte secondes;
byte minutes;
byte stateConversion;

unsigned long previousMillis = 0; // will store last time
unsigned long intervalTick = 1000; // 1s

boolean validity; // validite du capteur

float temperature;
float hysteresis;

float consigne;
boolean saveconsigne;
const int adr_consigne = 0; 

byte sensorAddress[8];
OneWire oneWire(SensorPin);
DallasTemperature sensors(&oneWire);


boolean tick () {
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > intervalTick) {
    previousMillis = currentMillis;   
    
    secondes++;
    if (secondes >= 60) {
      secondes=0;
      minutes++;
      if (minutes >= 60) {
        minutes=0;
      }
    }

    return true;
  }
  return false;
}

void setup() {
  // start serial port
  //Serial.begin(9600);
  //Serial.println("Init");
  
  // Ports
  byte i;
  for (i=0; i < 4; i++) {
    pinMode(displayAddress[i], OUTPUT);
  }

  pinMode(displayDEnablePin, OUTPUT);
  pinMode(displayUEnablePin, OUTPUT);
  digitalWrite(displayDEnablePin, HIGH); // Latched
  digitalWrite(displayUEnablePin, HIGH); // Latched

  pinMode(CmdePin, OUTPUT);
  digitalWrite(CmdePin, LOW);

  pinMode(KeyUpPin, INPUT);
  digitalWrite(KeyUpPin, HIGH); // turn on pullup 
  pinMode(KeyDwPin, INPUT);
  digitalWrite(KeyDwPin, HIGH); // turn on pullup 
  pinMode(KeyModePin, INPUT);
  digitalWrite(KeyModePin, HIGH); // turn on pullup 
  pinMode(SensorPin, INPUT);
  digitalWrite(SensorPin, HIGH); // turn on pullup 

  // Variables
  previousMillis = millis(); // Temps de reference
  secondes = 59;
  minutes = 59;

  hysteresis = 0.5; // +/- 0.5
  temperature = ERR_TEMP; // Temperature suffisamment haute pour ne pas commencer avec un demarrage
  validity = false; // Pas de capteur
  saveconsigne = false; // Sauvegarde de la consigne en EEPROM

  // consigne = 10.0; // La plus basse pour ne pas commencer un demarrage 
  consigne = (float) EEPROM.read(adr_consigne);
  if (consigne < MIN_TEMP || consigne > MAX_TEMP) {
    consigne = MIN_TEMP;
  }
  
  sensors.begin();
  if (sensors.getDeviceCount()) {
    validity = sensors.getAddress(sensorAddress, 0);
    sensors.setResolution(sensorAddress, 9);
  } 
  
  //Serial.print("Found ");
  //Serial.print(sensors.getDeviceCount(), DEC);
  //Serial.println(" devices.");  
}


boolean keyPressed (int pin) {
  if (digitalRead(pin)) return false; // Not pressed
  delay(20); // 20ms
  if (digitalRead(pin)) return false; // Glitch
  return true;
}

void keyHold (int pin) {
  while (!digitalRead(pin));
}

void bin2BCD (byte val, byte &h, byte &l) {
  h = 0;
  l = 0;
  while (val >= 10) {
    val = val - 10;
    h++;
  }

  l = val; // Le reste
}

void display (float val) {
  byte i, h, l;
  bin2BCD (byte(val), h, l);

  // Affichage dizaines
  for (i = 0; i < 4; i++) {
    digitalWrite (displayAddress[i], (h >> i) & 0x01);
  }

  digitalWrite (displayDEnablePin, LOW);
  digitalWrite (displayDEnablePin, HIGH);

  // Affichage unites
  for (i = 0; i < 4; i++) {
    digitalWrite (displayAddress[i], (l >> i) & 0x01);
  }

  digitalWrite (displayUEnablePin, LOW);
  digitalWrite (displayUEnablePin, HIGH);
}

void loop () {
  // Definition de la consigne
  if (keyPressed (KeyModePin)) {
    boolean fin = false;
    display (consigne); // On visualise la consigne
    
    while (!digitalRead(KeyModePin)) {
      if (keyPressed (KeyUpPin)) {
        if (consigne < MAX_TEMP) {
          consigne++;
          display (consigne); // On actualise la nouvelle consigne
          saveconsigne = true; 
        }       
        keyHold(KeyUpPin); // Attente relachement
      }
      
      if (keyPressed (KeyDwPin)) {
        if (consigne > MIN_TEMP) {
          consigne--;
          display (consigne); // On actualise la nouvelle consigne
          saveconsigne = true;
        }
        keyHold(KeyDwPin); // Attente relachement
      }
    }
    
    // On a quitte le mode consigne
    display (temperature); // On reaffiche l'ancienne temperature mesuree
  }
  
  // Tick 1 seconde
  if (tick()) {
    // Sauvegarde de la consigne ?
    if (saveconsigne) {
      saveconsigne = false; // Ne pas oublier sinon on detruit rapidement l'EEPROM
      EEPROM.write(adr_consigne, (int) (consigne));
    }
    
    // Lancement de la conversion
    if (stateConversion == 0) {
      sensors.requestTemperatures(); // Send the command to get temperatures
      stateConversion = 1;
    } 
    else { // Affichage temperature
      validity = sensors.isConnected(sensorAddress);
      if (validity) { // Seulement si on est sur d'acceder au capteur
        temperature = sensors.getTempC (sensorAddress);
        //Serial.print("Temp C: ");
        //Serial.print(temperature);        
        
      }
      else {
        temperature = ERR_TEMP; // En cas d'abscence de capteur  
      }
      
      display (temperature);
      stateConversion = 0;
    }
    
    // Permet d'avoir une valeur valide
    if (secondes == 5) { // 1 fois par minute, commence a 5 secondes
      if (validity) { // Seulement si la temperatrue est valide
        if (temperature > (consigne + hysteresis)) { // on coupe
          digitalWrite (CmdePin, LOW);
        }
        else if (temperature < (consigne - hysteresis)) { // on allume
          digitalWrite (CmdePin, HIGH);
        }
      }
      else { // En cas de temperature invalide, on coupe tout
        digitalWrite (CmdePin, LOW);         
      }
    }
  }
}


