//  programme ensacheuse V0.3 - 26/04/2019 - romain barret
 

// CONFIG PROGRAMME A ETATS
enum { INITIALISATION, REMPLISSAGE_RAPIDE, REMPLISSAGE_LENT, PAUSE};
// 3 états de la peseuse
byte etatpeseuse = INITIALISATION ;

enum { POIDSOBJECTIF, LIMITEREMPLISSAGELENT } ;
byte menu = POIDSOBJECTIF ;

int poidsObjectif=1000 ;
int limiteRemplissageLent = 150 ;
int positionTrappeRemplissageLent = 80 ;

//config balance
#include "HX711.h" // lib version BODGE !!    https://github.com/bogde/HX711
#define calibration_factor 2065 //This value is obtained using the SparkFun_HX711_Calibration sketch // 2076


#define DT  A1
#define SCK  A2

HX711 scale;

// configuration lcdkeypad shield :

#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);           // select the pins used on the LCD panel D4=> D9

// define some values used by the panel and buttons
int etat_bouton = 5; // lecture immédiate de l'état du bouton lu
int etat_bouton_memoire = 5; // état du bouton avant.

int adc_key_in  = 0;

#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

int read_LCD_buttons(){               // read the buttons
    adc_key_in = analogRead(0);       // read the value from the sensor 

    // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
    // we add approx 50 to those values and check to see if we are close
    // We make this the 1st option for speed reasons since it will be the most likely result

    if (adc_key_in > 1000) return btnNONE; 

    // For V1.1 us this threshold
    if (adc_key_in < 50)   return btnRIGHT;  
    if (adc_key_in < 250)  return btnUP; 
    if (adc_key_in < 450)  return btnDOWN; 
    if (adc_key_in < 650)  return btnLEFT; 
    if (adc_key_in < 850)  return btnSELECT;  
    return btnNONE;                // when all others fail, return this.
}



//commandes des moteurs

#include <Servo.h> //on importe la bibliothèque Servo

int pinServo=2; // variable pour stocker le pin pour la commande

int pinMoteur=3; 

Servo Trappe; // on définit un objet Servo nommé Trappe

// variables globales utiles au code :

int positionTrappe=159 ;
unsigned long dateDernierChangementTrappe = 0;
byte mouvementTrappe = 0 ;

// paramétrage du tableau des poids.
  #define NOMBREENREGISTREMENTPOIDS 4 // 6 enregistrements.
  int poidsTableau[NOMBREENREGISTREMENTPOIDS] ; // tableau comportant 10 poids
  unsigned long poidsTableauTemps[NOMBREENREGISTREMENTPOIDS] ;
  float poidsTableauDerivee[NOMBREENREGISTREMENTPOIDS] ;

void setup() {

  Serial.begin(9600);

  //écran LCD
 // lcd.init();                      // initialize the lcd 
  lcd.begin(16, 2);
//  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("initialisation");
  
  // voir pour ajouter une option pour refaire la calibration et l'enregistrer dans la mémoire interne arduino pour une utilisation ultérieur.
  scale.begin(DT, SCK);  // ajout V0.0
  scale.set_scale(calibration_factor); //This value is obtained by using the SparkFun_HX711_Calibration sketch
  scale.tare(10); //tarage avec 10 lectures.
  //commandes des moteurs
 
 Trappe.attach(pinServo); // on relie l'objet au pin de commande
 Trappe.write(positionTrappe);


  pinMode(pinMoteur,OUTPUT); //pin 13 en mode OUTPUT
  analogWrite(pinMoteur, 0) ; // est-ce vraiment utile ?
}

void loop() {

peser (); // enregistrement dans poidsTableau[] les dix dernières valeurs mesurées
  
  lcd.setCursor(0,1);
  lcd.print("poids: ");
  lcd.print(poids ());
  lcd.print(" g      "); 
  lcd.println();
  
  switch (etatpeseuse) {
    case INITIALISATION: // instructions à exécuter si expression est égale à INITIALISATION
      moteur (159,0) ; // moteur (int nouvellePositionTrappe, int vibreur)

if ( appuiBouton() == btnRIGHT )
  {
    etatpeseuse = REMPLISSAGE_RAPIDE ;
  }

if ( read_LCD_buttons () == btnSELECT ) {
     scale.tare(10); ;
    }

if ( read_LCD_buttons () == btnLEFT ) {
     if ( menu == POIDSOBJECTIF){ menu = LIMITEREMPLISSAGELENT; }
     else menu = POIDSOBJECTIF ;
    }

  switch (menu) {
    case POIDSOBJECTIF:
      lcd.setCursor(0,0);
      lcd.print("Poids obj : ");
      lcd.print(poidsObjectif);

if ( read_LCD_buttons () == btnUP ) {
     poidsObjectif = poidsObjectif + 1 ;
     }

if ( read_LCD_buttons () == btnDOWN ) {
     poidsObjectif = poidsObjectif - 1 ;
     }
    break ;

    case LIMITEREMPLISSAGELENT:
      lcd.setCursor(0,0);
      lcd.print("limite : ");
      lcd.print(poidsObjectif - limiteRemplissageLent);
      lcd.print("      ");

if ( read_LCD_buttons () == btnUP ) {
     limiteRemplissageLent = limiteRemplissageLent + 1 ;
     }

if ( read_LCD_buttons () == btnDOWN ) {
     limiteRemplissageLent = limiteRemplissageLent - 1 ;
     }
    
    break;
  }


      break;
    case REMPLISSAGE_RAPIDE:
      // instructions à exécuter si expression est égale à REMPLISSAGE_RAPIDE
      lcd.setCursor(0,0);
      lcd.print("REMPLISSAGE_RAPIDE");

      moteur (0,255) ; // moteur (int nouvellePositionTrappe, int vibreur)

      if (poids () >= poidsObjectif - limiteRemplissageLent )
      {
      etatpeseuse = REMPLISSAGE_LENT ;
      }

      if ( appuiBouton () == btnRIGHT ) {
       etatpeseuse = REMPLISSAGE_LENT ;
      }
      
      break;
      
    case REMPLISSAGE_LENT:
      // instructions à exécuter si expression est égale à REMPLISSAGE_LENT
      lcd.setCursor(0,0);
      lcd.print("REMPLISSAGE_LENT");

      moteur (positionTrappeRemplissageLent,125) ; // moteur (int nouvellePositionTrappe, int vibreur)

if ( read_LCD_buttons () == btnUP ) {
     positionTrappeRemplissageLent = positionTrappeRemplissageLent - 1 ;
     }

if ( read_LCD_buttons () == btnDOWN ) {
     positionTrappeRemplissageLent = positionTrappeRemplissageLent + 1 ;
     }



      
      if (poids () >= poidsObjectif)
      {
    //moteur (159,0) ; // fermeture de la trappe, vibreur éteint.
      etatpeseuse = INITIALISATION ;
      }

      if ( appuiBouton () == btnRIGHT ) {
      etatpeseuse = INITIALISATION ;
      }

      break;

    default:
      // instructions à exécuter si expression n'est égale à aucune des valeurs des case
      lcd.setCursor(0,0);
      lcd.print("ERREUR");
      break;
  }




}

// CGMT V0.2


void moteur (int nouvellePositionTrappe, int vibreur)
{
unsigned long dateCourante = millis() ;
unsigned long intervalle = dateCourante - dateDernierChangementTrappe ;
  
  if (nouvellePositionTrappe != positionTrappe  )
    {
      if( mouvementTrappe == 0 ) {
      // on donne une nouvelle instruction de commande du servomoteur.
      analogWrite(pinMoteur, 0) ;
      Trappe.write(nouvellePositionTrappe);
      mouvementTrappe = 1 ;
      dateDernierChangementTrappe = dateCourante ;
      intervalle = 0 ;
      }
      
      // 2* abs(nouvellePositionTrappe - positionTrappe)
      
      if ( mouvementTrappe == 1 && intervalle > 2.5* abs(nouvellePositionTrappe - positionTrappe) ) {
      mouvementTrappe = 0 ; 
      positionTrappe = nouvellePositionTrappe ;
      analogWrite(pinMoteur, vibreur) ;
      }      
    }
    else {
    Trappe.write(nouvellePositionTrappe);
    analogWrite(pinMoteur, vibreur) ;    
    }
}


// affinage possible : faire la même chose pour actualiser uniquement quand le vibreur est modifié pour accélerer le programme.


void peser (){
  for (int i=1; i<NOMBREENREGISTREMENTPOIDS; i++) {
    poidsTableau[NOMBREENREGISTREMENTPOIDS-i] = poidsTableau[NOMBREENREGISTREMENTPOIDS-1-i];
    poidsTableauTemps[NOMBREENREGISTREMENTPOIDS-i] = poidsTableauTemps[NOMBREENREGISTREMENTPOIDS-1-i];
    poidsTableauDerivee[NOMBREENREGISTREMENTPOIDS-i] = poidsTableauDerivee[NOMBREENREGISTREMENTPOIDS-1-i]; 
  }
  poidsTableau[0] = scale.get_units();
  poidsTableauTemps[0] = millis() ;
  poidsTableauDerivee[0] = (poidsTableau[1] - poidsTableau[0]) / (poidsTableauTemps[1] - poidsTableauTemps[0]) ;
}

int poids () {
int PoidsTotal = 0 ;
int PoidsMoy ;
float DeriveeTotale = 0 ;
float DeriveeMoy = 0 ;
  for (int i=0; i<NOMBREENREGISTREMENTPOIDS; i++) {
    PoidsTotal = PoidsTotal + poidsTableau[i];
    DeriveeTotale = DeriveeTotale + poidsTableauDerivee[i];
  }

DeriveeMoy = DeriveeTotale / NOMBREENREGISTREMENTPOIDS ;
PoidsMoy = PoidsTotal/NOMBREENREGISTREMENTPOIDS ;
// PoidsMoy  + (DeriveeMoy *(NOMBREENREGISTREMENTPOIDS+3) / 2)
return PoidsMoy  + (DeriveeMoy *(NOMBREENREGISTREMENTPOIDS+1) / 2) ;
  
}

// CGMT V0.2


int appuiBouton () {
      etat_bouton = read_LCD_buttons();
      if (etat_bouton != btnNONE && etat_bouton != etat_bouton_memoire) { // en appuyant sur le bouton,on change d'état.
        etat_bouton_memoire = etat_bouton ;
        return etat_bouton ;
      }
      else         
        etat_bouton_memoire = etat_bouton ;
        return btnNONE ;
}


