// STATIE DE EPURARE CU BAZINE IBC
/*                                                              ^
.                _______________________________________________|__________________
.               |                            ___________________|_______________   |      
.               |                            |                  |               |  |
|               |    __|_____|__             |    __|_____|__   |               |  | |
|               |   |  |     |  |            |   |  |     |  |  |               |  | |
|      BAZIN 0         |     |       BAZIN 1     |  |     |     | BAZIN 2       |  | |
|                      |     |                   |  |     |     |               |  | |
|   NU ARE POMPE       |     |        POMPE      |  |     |     |  POMPE        |  | |
|                      |     |                   |  |     |   EVACUARE EXT.     |  | |
|                      |     | AERARE  EVACUARE B2  |     | AERARE RECIRCULARE B1/B0 |
|______________________|     |______________________|     |__________________________|

*/

/********* ATENTIE !!! **********/
// Ca Debouncer se utilizeza CI MAX6818
// Pinul A0 este senzorul de nivel din BAZIN 1
// Pinul A1 este senzorul de nivel din BAZIN 2
// Pinul A2 este senzorul de prea plin BAZIN 2
// Pinul A3 comanda electrovana cu trei căi
// Pinul D12 este pompa de evacuare in exrterior
// Pinul D11 este pompa de evacuare in BAZIN 2 dupa ce s-a evacuat in exterior BAZIN 2 si se utilizeaza si la recirculare
// Pinul D10 este pompa de evacuare in BAZIN 0 si se utilizeaza doar la recirculare
// Pinul D9 este pompa de aerare Bazin 2
// Pinul D8 este pompa de aerare BAZIN 1
// Pinul D7 citeste senzorii de temperatura DS18B20 din fiecare bazin si din incinta
// Transmisia wireles este programata direct in IDE pt asigurare comunicatie Master - Slave

// BAZIN 0 - separator grasimi si fermentare anaeroba
// BAZIN 1 si BAZIN 2 fermentare aeroba si au nevoie de casa bacteriilor (un grilaj de plastic + resturi teava PPR)
// BAZIN 0 descarca gravitational in BAZIN 1 
// prea plinul in BAZIN 1 se realizeaza hidraulic
// legatura intre bazine este facuta pe principiul vaselor comunicante
// daca nu functioneaza pompele de evacuare, evacuarea exterioara se face natural cu
// conditia ca iesirea in exterior sa fie mai jos decat intrarea canalizarii in BAZIN 0
// rezultand o fosa septica clasica 
// pompele pentru setarile de mai jos au aproximativ 100 litri / minut la 1m inaltime adica 6 mc/h, valoarea reala se determina experimental 
// daca pompele au debite diferite timpii de pornire evacuare si recirculare sunt diferiti
// trebuind modificate variabilele pentru pompele de EVACUARE si RECIRCULARE 
// pompa standard la care se raporteaza timpii de functionare este de 6 mc/h la  5m inaltime
// cantitatea maxima evacuata este stabilita prin plutitorii de nivel minim care intrerup pompele fara comanda din partea controlerului
// daca se opreste curentul sau apare o resetare fizica controlerul revine la valorile stocate in EEPROM sau la valorile de initializare

#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include <SerialTransfer.h>
#include <util/atomic.h>

LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C address 0x27, 20 column and 4 rows
                                    // adresa este pt a functiona in wokwi,
                                    // alfel trebuie setata pe afisaj

//Stabilire pini butoane
const byte butonPinSETUP = 6;     // Pin digital 6
const byte butonPinTimpPLUS = 5;  // Pin digital 5
const byte butonPinTimpMINUS = 4; // Pin digital 4

// Pin Buzzer
const byte buzzerPin = 13; // Pin digital 13 

// Variabile Meniu
int Meniu = -1; // valoarea -1 indica faptul ca nu ne aflam in meniu
int  subMeniuAERARE = -1;
int  subMeniuEVACUARE = -1;
int  subMeniuRECIRCULARE = -1;
int  subMeniuBazin_1_AERARE = -1;
int  subMeniuBazin_2_AERARE = -1;

// Variabile pentru intreruperea ISR() Timp 

bool volatile flag_Timer1 = false;//variabila care arata ca a aparut intreruperea Timer1

unsigned long durata = 0;//masoara timpul fara precizie de cand a fost pornit conroler-ul 
                         //aproximativ 136 de ani dupa care trebuie resetata

unsigned long timp_Vacanta = 0;// variabila care masoara timpul pentru a verifica daca a avut loc
                      // evacuarea in exterior in 48 de ore timp care reprezinta minim doua  
                      // cicluri complete de epurare prin care se determina faptul ca 
                      // statia nu este folosita, nu are aport de apa noua pt epurare.
                      // aceasta variabila stabileste cand se recircula din Bazin 2 
                      // in Bazin 0 pentru improspatare apa

long alarma_Evacuare = -1;// calculeaza timpul de la apariatia alarmei provocata
                          // de blocarea senzorului de nivel din Bazin 1 astfel 
                          // încat sa fie evitata evacuarea in exterior repetitiv
                          // la fiecare 15 secunde care reprezinta intarzierea
                          // de pornire a evacuarii  
                          // acesta variabila este resetata la inceputul evacuarii
const unsigned long interval_Vacanta = 120; //implicit 48 ore si reprezinta perioada la care se declanseaza vacanta 

byte vacanta = 1; // reduce timpul de aerare si creste timpul de linistire aerare pt economie de energie 
                     // recircula o data la 24 de ore 100 litri din bazin 2 in bazin 0 pentru eliminarea  
                     // mirosurilor, denitrificare si defosforizare
                     // este resetata in etapa de evacuare

// Variabile care stocheaza pinul care  a generat intreruperea ISR()
// pentru pinii IMPUT_PULLUP setati pe GND care genereaza inreruperea
// pinul A0 plutitor Bazin 1 - adica bazinul 1 sa umplut si incepe etapa de evacuare in exterior apa epurata din bazin 2
// pinul A1 plutitor Bazin 2 - adica opreste evacuarea din bazin 1 in bazinul 2 
// pinul A2 plutitor prea plin - cota de avarie bazin 2 si porneste evacuarea 50 litri si
// poate emite o avarie pe afisaj pompa evacuare bazin 2 stricata
bool nivel_B1_Pin_A0 = false;     //plutitor nivel BAZIN 1 declanseaza evacuarea
bool nivel_B2_Pin_A1 = false;     //plutitor nivel BAZIN 2 opreste umplerea bazinului 2
bool prea_plin_B2_Pin_A2 = false; //plutitor prea plin BAZIN 2 evacueaza 100 litri in exterior

const byte intarziere_Plutitor = 15;// implicit 15 secunde generata pentru a adauga un surplus  
                                   // de apa de 25 litri astfel incat plutitorul sa stea inundat
bool surplus_Evacuare = false; // stabileste daca a fost eliminata apa in surplus la evacuare
                               // fata de limit de nivel - acest surplus exita intodeauna minim 25 litri
                               // pentru stabilitatea contactului plutitorului sau daca in timpul linistirii 
                               // functioneaza prea plinul hidraulic si creste nivelul
byte intarziere_Pin_A0 = 0; // aceaste intarzieri sunt necesare pentru ca sa fie preluata  
byte intarziere_Pin_A1 = 0; // distanta de contact a plutitorilor, eliminarea semnalelor 
byte intarziere_Pin_A2 = 0; // false si a semnalelor accidentale datorita efectului de val
                            // intarzierea este de aproximativ 15 sec. sau 25 litri,
                            // evenimentele declansate de plutitori apar dupa expirarea
                            // acestei perioade cu conditia ca plutitorul sa fie in contact

// Variabile pompe
// ATENTIE ! - sa nu se schimbe pozitia variabilelor in "struct POMPE"
struct __attribute__((packed)) POMPE  // Aceasta structura contine variabilele pentru pompe si va fi transmisa
{                                     // wireles catre controlerul MASTER prin HC-12 433 MHz de catre SLAVE
  unsigned int Bazin_1_Aerare = 60;      // implicit 90 de secunde  
  unsigned int Bazin_1_Linistire = 60;   // implicit 900 de secunde 
  unsigned int Bazin_2_Aerare = 60;      // implicit 90 de secunde 
  unsigned int Bazin_2_Linistire = 60;   // implicit 900 de secunde
  unsigned int PornireEvacuare = 20;     // implicit 180 de secunde maxim 240 secunde / max 400 litri - pompa trebuie sa aiba un debit = 6 mc/h
  unsigned int LinistireEvacuare = 9;    // implicit 900 de secunde - este folosita pentru Evacuare si Recirculare
  unsigned int PornireRecirculare = 30;  // implicit 60 de secunde - recircula 100 litri la debitul pompelor de 6 mc/h
  unsigned int AsteptareRecirculare = 1; // implicit 3 ore - max 18 ore in secunde min 21600 - max 64800
} POMPA;

unsigned int PornireEvacuareInBazin2 = POMPA.PornireEvacuare + intarziere_Plutitor; //maxim 240 secunde / max 400 litri - pompa trebuie sa aiba un debit = 6 mc/h
unsigned int LinistireREC = POMPA.LinistireEvacuare; //timpul de linistire inainte de Recirculare
const byte EvacuarePreaPlin = 10;// implicit 30 sec - 50 de litri pt. pompa 6 mc/h si reprezinta timpul necesar 
                                 // evacuarii unei parti din prea plin pana cand se finalizeaza etapa de evacure
                                 // volum de prea plin Bazin 2 = 100 litri
unsigned int ORA_Recirculare = 0; // este utilizata pentru recirculare, masoara o ora pentru a decrementa Recirculare.CL
const unsigned int ora = 36; //constanta care contine nr de secunde dintr-o ora

// aceasta structura este operata in interiorul functiei call_ISR_Timer()
struct Timer_Releu // aceasta structura este un constructor pentru a putea fi initializata ca mai jos
  {
    Timer_Releu ( unsigned int op, unsigned int cl, bool ss) :
                  OP {op}, CL {cl}, SS {ss} {}
    unsigned int  OP = 0; //" OPEN "timpul in secunde pt. care RELEUL este normal deschis NO
    unsigned int  CL = 0; //" CLOSE "timpul in in secunde pt. care RELEUL este normal inchis NC
    bool SS = false;      //" START - STOP " - 0 opreste , 1 porneste un eveniment (actioneaza un releu)
                                   //dupa actiunea STOP/START trebuie reinitializati timpii OP, CL, LP
  };

// initializez variabilele pentru relee pompe
struct Timer_Releu AerareB1 = {POMPA.Bazin_1_Aerare, POMPA.Bazin_1_Linistire, true };
struct Timer_Releu AerareB2 = {POMPA.Bazin_2_Aerare, POMPA.Bazin_2_Linistire, true }; 
struct Timer_Releu Recirculare = {POMPA.PornireRecirculare, POMPA.AsteptareRecirculare , true };
struct Timer_Releu Evacuare = {POMPA.PornireEvacuare, POMPA.LinistireEvacuare, false };


// Structura pentru afisarea ETAPEI / STARII pe LCD si transmitere date wireles prin HC-12
struct __attribute__((packed)) LCD20x4  // Aceasta structura contine textul afisat pe 
{                                       // fiecare linie a afisajului LCD20x4
  char Line0[21];                       // Aceasta structura va fi transmisa wireles
  char Line1[21];                       // catre controlerul SLAVE prin HC-12 433 MHz
  char Line2[21];                       // pt afisare pe SLAVE in inmp real
  char Line3[21];
  unsigned int Alarma[5] = {0, 0, 0, 0, 0};// stocheaza nr. de aparitii a alarmelor si numara pana la max. 65535 de aparatii
} LCD;

byte alarma = 0; // stabileste tipul de alarma si ia valori  
                 // 1 si 2 pt prea plin BAZIN 2
                 // 3 cand plutitorul de nivel maxim din BAZIN 2 este blocat sau pompa 
                 //   de evacuare in exterior este arsa
                 // 4 senzor nivel defect sau murdar si nu cupleaza in Bazin 1 sau pompa de
                 //   evacuare in Bazin 2 este arsa
                 // 5 cind pompa de evacuare este arsa sau senzor de prea plin defect sau murdar/lipit

                 // se elimina prin resetare alarma chiar daca senzorii de nivel revin la normal
                 // si practic pompele nu sunt arse
                 // resetarea alarmei se realizeaza prin resetare fizica a microcontroleru-lui
                 // momentan microcontrolerul nu poate determina daca o anumita pompa este arsa fizic
                 // alarmele se bazeaza doar pe starea senzorilor de nivel

byte timpAfisareAlarma = 0; // afisaza alarma timp de 10 sec la aparitia acesteia dupa care o reseteza
                            // pentru a nu bloca afisajul afisindu-se in continuare STAREA in care se afla statia 

/*********************** FUNCTII MEMORIE EEPROM **********************************************/

/************************ STOCARE SETARI IN MEMORIA EEPROM ************************/

// Acesta functie citeste sau scrie valorile variabilelor globale necesare stabilirii
// timpilor utilizati intr-un ciclu de epurare
// Aceasta functie este folosita in meniul Setup pentru stocarea modificarii variabilelor,
// in functia Initializare_Ciclu () si in functia setup()
// o scriere  dureaza aproximativ 3.3 ms/octet la care se aduna si durata codului functiei
// din cate am citit EEPROM este sters odata cu instalarea unui program si toti bitii sunt 0xFF adica 1111 1111 sau 255 dec
// acest fapt este de verificat fizic

unsigned int Scrie_Citeste_EEPROM (byte flag, byte addr = 1, unsigned int *save_Var = 1)
  {
    // flag = 0 functia este folosita in functia setup()
    //        1 functia este folosita in functia Initializare_Ciclu () 
    //        2 functia este folosita in meniul Setup si salveaza varibila
    //          pentru a nu se afecta ciclul in care se afla statia
    //        3 intoarce valoarea de la adresa "addr" 

    // addr - este optionala si contine adresa la care se salveaza save_Var
    // save_Var - este optionala si reprezinta variabila din corpul " struct POMPE " ce urmeaza a fi salvata
    // aceste variabile sunt transmise prin referinta doar in meniul Setup si au urmatoarele adrese:
    
    // addr HEX   adr DEC      save_Var
    //---------   --------  -------------------
    //   0x01       01      Bazin_1_Aerare  
    //   0x03       03      Bazin_1_Linistire  
    //   0x05       05      Bazin_2_Aerare 
    //   0x07       07      Bazin_2_Linistire 
    //   0x09       09      PornireEvacuare 
    //   0x0B       11      LinistireEvacuare 
    //   0x0D       13      PornireRecirculare 
    //   0x0F       15      AsteptareRecirculare 

    // octetul de la adresa 0 are    = 0xFF adica 1111 1111 sau 255 dec, daca programul este incarcat in Mcu prima oara
    // indicativul, adica valoarea   = 0x80 adica 1000 0000 sau 128 dec, daca memoria contine stocate valori nemodificate
    // stocata                       = 0x40 adica 0100 0000 sau  64 dec, daca daca memoria a fost modificata in meniul Setup
    // acest octet este necesar mai ales la resetarea Mcu pt initializarea variabilelor prin pastrarea setarilor

    // cu acesta functie se stocheaza primul octet si " struct POMPE " adica variabila POMPA
    // initializarea de tip bloc se realizeaza in functia setup() si in functia Initializare_Ciclu ()
    // pentru AERARE si RECIRCULARE  initializarea se face individual la fiecare final de ciclu 
    // astfel incat sa nu se afecteze buna functionare a statiei in timpul setarii in meniul Setup

    // daca parametrii introdusi sunt gresiti aceasta functie genereaza erori necontrolabile

    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
      {
        unsigned int EE_Address = 0;
        byte indicativ = 0;// adresa primului octet
        unsigned int val = 0;// valoarea unei variabile citite la adresa "addr"

        EEPROM.get(0, indicativ);
        EE_Address += sizeof (indicativ); // calculez adresa de stocare pt. tmp_POMPA

        switch (flag) 
          {
            case 0: // functia setup()
              if      (indicativ == 0xFF) {EEPROM.put(0, 0x80); EEPROM.put(EE_Address, POMPA);}// prima rulare a programului
              else EEPROM.get(EE_Address, POMPA);// se initializeaza la fiecare resetare
              break;
            case 1: // functia Initializare_Ciclu ()
              if (indicativ == 0x40) EEPROM.get(EE_Address, POMPA);// se initializeaza la fiecare resetare
              break;
            case 2: // meniul Setup - se va stoca la fiecare SAVE & EXIT din submeniuri
              EEPROM.put(0, 0x40);
              EEPROM.put(addr, *save_Var);
              break;
            case 3: // se va citi valoarea de la adresa "addr" si va returna valoarea citita "val" folosit in AERARE daca au fost modificate variabilele in meniul Setup
              EEPROM.get(addr, val); return val;
              break;
          }
      }
  }

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



/*********************** FUNCTII PENTRU INTRERUPERILE ISR() *********************************/


/************ FUNCTIE CARE AFISEAZA ALTERNANT STARE/ALARM IN CAZUL APARITIEI ALARMEI *************/

inline String STARE_ALARMA ()
{
// in cazul aparitiei unei alarme se va afisa alternant STARE/ALARM
// si activez led si buzzer pe pin D13 (PB5) care sa atentioneze ca 
// a aparut cel putin o alarma

  unsigned long tmp = 0;
  static bool stare_Alarma = false;

  for (uint8_t i = 0; i <= 4; i++) { tmp += LCD.Alarma[i]; }
  if (tmp == 0 ) {PORTB &= ~_BV(PB5); return(vacanta == 1 ? "STARE" : "VEGHE");}
  else if (tmp != 0 && stare_Alarma == false) {stare_Alarma = true; PORTB &= ~_BV(PB5); return (vacanta == 1 ? "STARE" : "VEGHE");}
  else if (tmp != 0 && stare_Alarma == true) {stare_Alarma = false; PORTB |= _BV(PB5); return ("ALARM");}

} //End STARE_ALARMA


/************************* FUNCTIE AFISARE STARE CICLU **************************************/
// Acesta functie afiseaza etapa in care se afla statia de epurare

void StareCiclu ( uint8_t etapa = 0)
{
  
  String tmp = "";

  tmp = STARE_ALARMA();
 
  if (Meniu != -1) return;
  //-----------------------------------------------------------------
  
  if (timpAfisareAlarma == 10 && alarma > 2 ) // afisez alarma tip  3, 4 si 5 timp de 10 sec. de la apariția acesteia dupa care se reseteaza
    {                                         // evenimentele privind nr aparitiei alarmelor sun stocate in variabila Alarma[0-3]
      alarma = 0; timpAfisareAlarma = 0;       
    }                                          
  else if (alarma > 2) {timpAfisareAlarma++; }
  
  //------------------------------------------------------------------
  if ( alarma ) etapa = 4;

  switch (etapa)
  {
    case 1: //EVACUARE
      //if ( alarma ) break;
      tmp += " << EVACUARE >>";
      strcpy(LCD.Line0 , tmp.c_str());
      tmp = String(Evacuare.CL) +"    ";
      if(Evacuare.CL > 0) tmp = ("> Linistire " + tmp.substring(0,5) + "sec"); else tmp = ("  Linistire " + tmp.substring(0,5) + "sec"); 
      strcpy(LCD.Line1, tmp.c_str());

      tmp = String(Evacuare.OP) +"    ";
      if(Evacuare.OP > 0 && Evacuare.CL == 0) tmp = ("> Evacuare  " + tmp.substring(0,5) + "sec"); else tmp = ("  Evacuare  " + tmp.substring(0,5) + "sec");
      strcpy(LCD.Line2, tmp.c_str());

      tmp = String(PornireEvacuareInBazin2) +"    ";
      if(PornireEvacuareInBazin2 > 0 && Evacuare.OP == 0) tmp = ("> Umplere   " + tmp.substring(0,5) + "sec"); else tmp = ("  Umplere   " + tmp.substring(0,5) + "sec");
      strcpy(LCD.Line3, tmp.c_str());
    break;
    case 2: //RECIRCULARE
      //if ( alarma ) break;
      tmp += " << RECIRCUL >>";
      strcpy(LCD.Line0 , tmp.c_str());
      tmp = String(LinistireREC) + "    " ;
      if(LinistireREC > 0) tmp = ("> Linistire " + tmp.substring(0,5) + "sec"); else tmp = ("  Linistire " + tmp.substring(0,5) + "sec");
      strcpy(LCD.Line1, tmp.c_str());

      tmp = String(Recirculare.OP) +"    ";
      if(Recirculare.OP > 0 && LinistireREC == 0) tmp = ("> Amestec   " + tmp.substring(0,5) + "sec"); else tmp = ("  Amestec   " + tmp.substring(0,5) + "sec");
      strcpy(LCD.Line2, tmp.c_str());
      strcpy(LCD.Line3, "  --------- ---- ---");
    break;
    case 3: //AERARE
      //if ( alarma ) break;
      tmp += "  <<  PASIV  >>";
      strcpy(LCD.Line0 , tmp.c_str());
      strcpy(LCD.Line1 , "    Bazin 1  Bazin 2");

      tmp = String(AerareB1.OP) + "    ";
      tmp = ("AER " + tmp.substring(0,4) + "sec  " );
      strcpy(LCD.Line2 , tmp.c_str());
      tmp = String(AerareB2.OP) + "    ";
      tmp = tmp.substring(0,4) + "sec";
      strcat(LCD.Line2 , tmp.c_str());

      tmp = String(AerareB1.CL) + "    ";
      tmp = ("LIN " + tmp.substring(0,4) + "sec  ");
      strcpy(LCD.Line3 , tmp.c_str());
      tmp = String(AerareB2.CL) + "    ";
      tmp = (tmp.substring(0,4) + "sec");
      strcat(LCD.Line3 , tmp.c_str());

    break;
    case 4: // ALARME
      switch (alarma)
        {
          case 1: //PREA PLIN BAZIN 2
            strcpy(LCD.Line0 , "** ALARM PREAPLIN **");
            strcpy(LCD.Line1 , " Verifica evacuarea.");
            strcpy(LCD.Line2 , " Debit mare, peste  ");
            strcpy(LCD.Line3 , "  20 litri / min.   ");
          break;
          case 2: //PREA PLIN BAZIN 2
            strcpy(LCD.Line0 , "** ALARM PREAPLIN **");
            strcpy(LCD.Line1 , "Pompa Evac.P2.2 arsa");
            strcpy(LCD.Line2 , "sau plutitor prea - ");
            strcpy(LCD.Line3 , "plin BAZIN 2 blocat.");
          break;
          case 3: //EVACUARE
            strcpy(LCD.Line0 , "** ALARM EVACUARE **");
            strcpy(LCD.Line1 , "Pompa de evacuare in");
            strcpy(LCD.Line2 , "exterior P2.2 arsa. ");
            strcpy(LCD.Line3 , "Senzor nivel blocat.");         
          break;
          case 4: //EVACUARE
            strcpy(LCD.Line0 , "* ALARM UMPLERE B2 *");
            strcpy(LCD.Line1 , "Senzorii de nivel   ");
            strcpy(LCD.Line2 , "defecti sau murdari/");
            strcpy(LCD.Line3 , "P1.2 umplere B2 arsa");
          break;
          case 5: //EVACUARE
            strcpy(LCD.Line0 , "** ALARM EVACUARE **");
            strcpy(LCD.Line1 , "      ATENTIE !     ");
            strcpy(LCD.Line2 , "Pompa de evacuare in");
            strcpy(LCD.Line3 , "exterior P2.2 arsa. ");         
          break;
        }
    break;

  }
  lcd.setCursor (0,0); lcd.print((char*)LCD.Line0);
  lcd.setCursor (0,1); lcd.print((char*)LCD.Line1);
  lcd.setCursor (0,2); lcd.print((char*)LCD.Line2);
  lcd.setCursor (0,3); lcd.print((char*)LCD.Line3);
  
}// end StareCiclu



/******************** FUNCTIE INITIALIZARE CICLU ***********************/

void Initializare_Ciclu ()
{
  //oprim toate pompele
  PORTB &= ~_BV(PB4); // opreste releul de pe pinul D12 care activeaza pompa de evacuare in exterior
  PORTB &= ~_BV(PB3); // opreste releul de pe pinul D11 care activeaza pompa de evacuare in bazin 2
  PORTB &= ~_BV(PB2); // opreste releul de pe pinul D10 care activeaza pompa de evacuare in bazin 0
  PORTB &= ~_BV(PB1); // opreste releul de pe pinul D8 care activeaza pompa de aerare bazin 1
  PORTB &= ~_BV(PB0); // opreste releul de pe pinul D9 care activeaza pompa de aerare bazin 2
  // reseteaza intarzierea
  intarziere_Pin_A0 = 0;
  intarziere_Pin_A1 = 0;
  //reinitializez toate variabilele pentru o etapa de epurare noua
  Scrie_Citeste_EEPROM (0);
  AerareB1 = {POMPA.Bazin_1_Aerare, POMPA.Bazin_1_Linistire, true };
  AerareB2 = {POMPA.Bazin_2_Aerare, POMPA.Bazin_2_Linistire, true }; 
  Recirculare = {POMPA.PornireRecirculare, POMPA.AsteptareRecirculare , true };
  Evacuare = {POMPA.PornireEvacuare, POMPA.LinistireEvacuare, false};
  PornireEvacuareInBazin2 = POMPA.PornireEvacuare + intarziere_Plutitor;
  ORA_Recirculare = 0; //daca apare evenimentul evacuare si recircularea nu s-a efectuat
  LinistireREC = POMPA.LinistireEvacuare;

  // schimb pozitia electrovanei cu trei cai penru recirculare normala
  if (timp_Vacanta < interval_Vacanta) PORTC &= ~_BV(PC3); 
}


/************************* FUNCTIE TRATARE EVENIMENTE ISR() PINI IN ISR() TIMER **************************/
inline void call_ISR_Timer (void)
{
  // se pastreaza ordinea if-urilor pt functionare corecta:
  //  1. prea plin
  //  2. evacuare 
  //  3. recirculare
  //  4. aerare


  static byte TIMP_Evacuare_PreaPlin = 0;//este utilizata pentru evacuare prea plin BAZIN 2
  static byte tmp_ALARMA = 0; // stocheaza temporar alarma aparuta inainte de alarma preaplin si  
                              // este folosita strict pentru afisare
  static bool stare_nivel_B2_Pin_A1 = 0; // stocheaza starea senzorului de nivel Bazin 2 cand apare alarma 4
                                        // adica starea pinului A1 si este folosit pentru evitare evacuare 
                                        // dupa cum urmeaza - daca este false produce un nou ciclu daca senzorul
                                        // de nivel Bazin 2 s-a cuplat si 
   
  timp_Vacanta ++;// reprezinta timpul de la aparitia ultimului eveniment EVACUARE
  if (alarma_Evacuare >= 0) alarma_Evacuare ++;//reprezinta timpul de la aparitia ultimei alarme provocata de blocarea senzorului de nivel din Bazin 1

  if (timp_Vacanta == interval_Vacanta) // activez starea de vacanta daca timp
    {                                   // de 48 de ore nu s-a produs evacuarea
      vacanta = 2;                      // aceste variabile sunt resetate cand
    }                                   // apare evenimentul evacuare
    
  /**** PREA PLIN BAZIN 2 ****/

  /* 1) acest eveniment apare atunci cand plutitorul de nivel din BAZIN 1 nu este cuplat si 
     plutitorul de prea plin cupleaza, adica BAZIN 1 sa umplut si nu porneste evacuarea,
     transferul de apa in BAZIN 2 facanduse hidraulic pana cand se ajunge la nivelul de prea plin 
     din BAZIN 2 fiind necesara evacuarea 
     2) cand plutitorului de nivel BAZIN 1 declanseaza procesul de evacuare dar pompa de evacuare
     in exterior nu porneste sau este arsa si comunicarea intre bazine se realizeaza hidraulic 
     pana cand se atinge nivelul de prea plin din BAZIN 2

  */
  if (((PINC & (1 << PC2)) == 0) && (TIMP_Evacuare_PreaPlin == 0))
    {
      prea_plin_B2_Pin_A2 = true; // pin A2 este pentru prea plin din Bazin 2 
                                  // se evacueaza in exterior 50 litri
      tmp_ALARMA = alarma;
      PORTB |= _BV(PB4);  // porneste releul de pe pinul D12 care activeaza pompa de evacuare in exterior
      PORTB &= ~_BV(PB3); // opreste releul de pe pinul D11 care activeaza pompa de evacuare in bazin 2
      PORTB &= ~_BV(PB2); // opreste releul de pe pinul D10 care activeaza pompa de evacuare in bazin 0
      PORTB &= ~_BV(PB1); // opreste releul de pe pinul D8 care activeaza pompa de aerare bazin 1
      PORTB &= ~_BV(PB0); // opreste releul de pe pinul D9 care activeaza pompa de aerare bazin 2
      TIMP_Evacuare_PreaPlin++; alarma = 1; 
      LCD.Alarma[0]<65535 ? LCD.Alarma[0] ++ : LCD.Alarma[0] = 65535;// stochez aparitia alarmei
      StareCiclu (4);// afisez starea prea plin BAZIN 2
      return;
    }
  else if (prea_plin_B2_Pin_A2 && (TIMP_Evacuare_PreaPlin < EvacuarePreaPlin)) // evacueaza in exterior parte din prea plin 
    {
      TIMP_Evacuare_PreaPlin++;
      StareCiclu (4);// afisez starea prea plin BAZIN 2 cat timp dureaza " EvacuarePreaPlin "
      if (TIMP_Evacuare_PreaPlin != EvacuarePreaPlin) return;
    }
  else if (prea_plin_B2_Pin_A2 && (TIMP_Evacuare_PreaPlin >= EvacuarePreaPlin)) // a evacuat in exterior parte din plin
    {                                                                           // dar senzorul de nivel pt prea plin
                                                                                // nu s-a decuplat
      if ((TIMP_Evacuare_PreaPlin < POMPA.PornireEvacuare)) // preventiv continua evacuarea pana se atinge timpul " PornireEvacuare "
        {                                             // daca contactul este activ debitul este asa de mare incat pompa de
                                                      // nu face fata (complicat sa se intample deoarece pompa din put are 3 mc/h)
                                                      // sau senzorul a ramas lipit din cauza mizeriei 
                                                      
          alarma = 2; // declansez alarma 2, adica pompa de evacuare este arsa sau          
                      // plutitorul prea-plin blocat, va functiona hidraulic         
                      // pompa de evacuare se opreste in cazul plutitorului blocat cand 
                      // este depasit timpul de evacuare intr-un ciclu normal si 
                      // revine la ciclul normal cand se deblocheaza
          if (TIMP_Evacuare_PreaPlin == EvacuarePreaPlin) LCD.Alarma[1]<65535 ? LCD.Alarma[1] ++ : LCD.Alarma[1] = 65535;// stochez aparitia alarmei
          TIMP_Evacuare_PreaPlin++;
          StareCiclu (4);// afisez starea prea-plin BAZIN 2 pana cand se termina timpul " PornireEvacuare "
          return;
        }
      else if ((TIMP_Evacuare_PreaPlin == POMPA.PornireEvacuare ))// s-a atins timpul maxim de evacuare 
        {
          PORTB &= ~_BV(PB4);   //opreste releul de pe pinul D12 care activeaza pompa de evacuare in exterior
          TIMP_Evacuare_PreaPlin++;// mai adun o unitate pt ca sa se depaseasca " PornireEvacuare "
          
          // restabilesc starea dinainte de prea plin deoarece plutitorul plutitorul nu revine la normal
          // si a fost consumat timpul de pornire evacuare insemna ca pompa de evacuare s-a ars sau plutitorul a ramas cuplat

          (tmp_ALARMA > 2) ? alarma = tmp_ALARMA : alarma = 0;
          
          // pornim pompele corespunzatoare etapei intrerupte de prea plin
          if((Evacuare.SS == true ) && (Evacuare.CL == 0)) PORTB |= _BV(PB4); else PORTB &= ~_BV(PB4);  //opreste / porneste releul de pe pinul D12 care activeaza pompa de evacuare in exterior
          if ((Recirculare.SS == true ) && (LinistireREC == 0))
            {
              PORTB |= _BV(PB3); // porneste releul de pe pinul D11 care activeaza pompa de evacuare in bazin 2
              PORTB |= _BV(PB2); // porneste releul de pe pinul D10 care activeaza pompa de evacuare in bazin 0
            }
          if ((AerareB1.SS == true)  && (AerareB1.OP != 0) && (AerareB1.CL == POMPA.Bazin_1_Linistire)) PORTB |= _BV(PB1); // porneste releul de pe pinul D8 care activeaza pompa de aerare bazin 1
          if ((AerareB2.SS == true)  && (AerareB2.OP != 0) && (AerareB2.CL == POMPA.Bazin_2_Linistire)) PORTB |= _BV(PB0); // porneste releul de pe pinul D9 care activeaza pompa de aerare bazin 2
        }
    } 

  if (((PINC & (1 << PC2)) != 0) && (TIMP_Evacuare_PreaPlin >= EvacuarePreaPlin ))//plutitorul a revenit la normal dupa evacuare preaplin 
    {
      if (TIMP_Evacuare_PreaPlin <= POMPA.PornireEvacuare )// restabilesc starea dinainte de prea plin 
        {                                            // deoarece plutitorul a revenit la normal
                                                     // in timpul evacuarii prea plin
        
          PORTB &= ~_BV(PB4);   //opreste releul de pe pinul D12 care activeaza pompa de evacuare in exterior

          (tmp_ALARMA > 2) ? alarma = tmp_ALARMA : alarma = 0;

          // pornim pompele corespunzatoare etapei intrerupte de prea plin
          if((Evacuare.SS == true ) && (Evacuare.CL == 0)) PORTB |= _BV(PB4); else PORTB &= ~_BV(PB4);  //opreste / porneste releul de pe pinul D12 care activeaza pompa de evacuare in exterior
          if ((Recirculare.SS == true ) && (LinistireREC == 0))
            {
              PORTB |= _BV(PB3); // porneste releul de pe pinul D11 care activeaza pompa de evacuare in bazin 2
              PORTB |= _BV(PB2); // porneste releul de pe pinul D10 care activeaza pompa de evacuare in bazin 1
            }
          if ((AerareB1.SS == true)  && (AerareB1.OP != 0) && (AerareB1.CL == POMPA.Bazin_1_Linistire)) PORTB |= _BV(PB1); // porneste releul de pe pinul D8 care activeaza pompa de aerare bazin 1
          if ((AerareB2.SS == true)  && (AerareB2.OP != 0) && (AerareB2.CL == POMPA.Bazin_2_Linistire)) PORTB |= _BV(PB0); // porneste releul de pe pinul D9 care activeaza pompa de aerare bazin 2
        }
      prea_plin_B2_Pin_A2 = false;
      TIMP_Evacuare_PreaPlin = 0;
    }
// end Prea Plin

  /**** EVACUARE ****/


  if (LCD.Alarma[4] && prea_plin_B2_Pin_A2) // pt. alarma 5 se evita evacuare continu
    {                                       // deoarece pompa de evacuare este sigur arsa
      goto Evita_Evacuarea;                 // senzorul de prea plin a ramas lipit in contact
    }  
  else if (alarma_Evacuare >= 0 && alarma_Evacuare < interval_Vacanta / 2) // evita Evacuarea daca senzorul de nivel Bazin 1 a ramas cuplat
    {                                                                      // si umplerea Bazin 2 s-a terminat - adica a aparut alarma 4
                                                                           // pentru a se evita evacuarea repetitiva
                                                                           // alarma_Evacuare este setata 0 cand apare alarma 4
      if ((PINC & (1 << PC0)) != 0) alarma_Evacuare = -1;// evacuarea revine la normal daca senzorul de nivel Bazin 1 se decupleaza
      
      else if (!stare_nivel_B2_Pin_A1 && (PINC & (1 << PC1)) == 0) alarma_Evacuare = -1;// se executa evacuarea daca senzorul de nivel 
                                                                                        // Bazin 2 s-a cuplat prin echilibrare hidraulica 
                                                                                        // si senzorul de nivel Bazin este cuplat in continuare
      else goto Evita_Evacuarea;                                                  
    }                                                    
  else if ((alarma_Evacuare == interval_Vacanta / 2))// forteaza evacuarea odata la 24 ore daca a aparut alarma 4 
    {                                               // cu conditia ca prea plinul din Bazin 2 sa nu fie cuplat functioneaza hidraulic
      prea_plin_B2_Pin_A2 ? alarma_Evacuare = 0 : alarma_Evacuare = -1;
    }


  /******* Eliminare semnale false generate de plutitorul de nivel Bazin 1 - Pin A0 *********/
  
  //produce intarzierea pt. eliminarea semnalelor false pe senzorul de nivel bazin 1
  if (((PINC & (1 << PC0)) == 0)  && (intarziere_Pin_A0 >= 0) && (intarziere_Pin_A0 < intarziere_Plutitor))// daca plutitorul din Bazin 1 este cuplat "intarziere_Plutitor secunde" 
    {                                                                                                      // se executa evacuarea
      nivel_B1_Pin_A0 = true;
      Evacuare.SS = true;    
      intarziere_Pin_A0++;// se produce o intarziere de "intarziere_Plutitor secunde" necesara pentru ca plutitorul sa fie inundat
      goto Evita_Evacuarea;// evita codul de evacuare
    }
  else if (((PINC & (1 << PC0)) != 0)  && (intarziere_Pin_A0 < intarziere_Plutitor))//daca plutitorul din Bazin 1 nu este cuplat "intarziere_Plutitor secunde" 
    {                                                                               // nu se executa evacuarea   
      nivel_B1_Pin_A0 = false;
      Evacuare.SS = false;    
      intarziere_Pin_A0 = 0;
      goto Evita_Evacuarea;// evita codul de evacuare
    }
  /****************************************************************************/

/* -------aici incepe procesul de linistire, evacuare in exterior si umplere Bazin 2--------------------------------------*/

  if (nivel_B1_Pin_A0 && Evacuare.SS )//eveniment pin A0 - Bazinul 1 sa umplut, opreste aerarea si  
    {                                 //recircularea pornind evacuarea,  
                                      //daca pompa de evacuare in BAZIN 1 sau BAZIN 2 s-a ars,
                                      //functioneza ca vase comunicante 
        // Verifica pozitia plutitorului de nivel din Bazin 2 l
      if ((PINC & (1 << PC1)) == 0)
        {nivel_B2_Pin_A1 = true;}
      else
        {nivel_B2_Pin_A1 = false; }
      StareCiclu (1);// afisez starea pentru evacuare cand nu avem alarme in evacuare

      // stabilesc durata de linistire in functie de ciclul in care se afla statia
      // adica daca se afla in perioada de linistire aerare sau recirculare
      // timpul de linisti evacuare este doar diferenta de timp
      if (Evacuare.SS == true && Evacuare.CL == POMPA.LinistireEvacuare)// verifica daca evacuarea a aparut in timpul 
        {                                                         //linistirii aerare sau recirculare
          
          // stabileste timpul de linistire in functie de starea in care se afla statia
          AerareB1.SS = false; AerareB2.SS = false; Recirculare.SS = false; Evacuare.CL--;
          if ( (AerareB2.OP == 0) && (Recirculare.CL != 0) )// cilul de evacuare a aparut in perioada linistirii aerarii
            {
              if (POMPA.LinistireEvacuare >= (POMPA.Bazin_2_Linistire - AerareB2.CL))//recupereaza timpul de linistire trecut
                {                                                        // in timpul aerarii
                  Evacuare.CL = POMPA.LinistireEvacuare - (POMPA.Bazin_2_Linistire - AerareB2.CL);// continua linistirea pentru diferenta de timp trecut
                }
              else Evacuare.CL = 0;// timpul de linistire s-a epuizat si se poate realiza evacuarea
            }
          else if ((Recirculare.CL == 0) && (LinistireREC != 0)) Evacuare.CL = LinistireREC;// ciclul de evacuare a aparut in perioada linistirii
                                                                                            // pentru recirculare  si continua pentru diferenta de timp
                                                                                            // timpul de linistire pentru recirculare este identic cu
                                                                                            // timpul de linistire pentru evacuare
          //oprim toate pompele
          PORTB &= ~_BV(PB4); // opreste releul de pe pinul D12 care activeaza pompa de evacuare in exterior
          PORTB &= ~_BV(PB3); // opreste releul de pe pinul D11 care activeaza pompa de evacuare in bazin 2
          PORTB &= ~_BV(PB2); // opreste releul de pe pinul D10 care activeaza pompa de evacuare in bazin 0
          PORTB &= ~_BV(PB1); // opreste releul de pe pinul D8 care activeaza pompa de aerare bazin 1
          PORTB &= ~_BV(PB0); // opreste releul de pe pinul D9 care activeaza pompa de aerare bazin 2
          
          timp_Vacanta = 0; vacanta = 1; // resetez starea de vacanta
          PORTC &= ~_BV(PC3); // schimb pozitia electrovanei cu trei cai penru recirculare normala
          return;
        }
      else if ((Evacuare.SS == true) && (Evacuare.CL <= POMPA.LinistireEvacuare))// incepe perioada de linistire
        {
  /*---------------- linistire ----------------------------------------------------------------------------------*/

          // aici continua procesul de linistire
          if ( Evacuare.CL != 0 ) // releul pe pinul D12 este Normal Close pt. perioada CL
            {
              Evacuare.CL--;
              if ((Evacuare.CL == 0) && (Evacuare.OP == POMPA.PornireEvacuare) && nivel_B1_Pin_A0 && !nivel_B2_Pin_A1)
                {
                  Evacuare.OP = 0;// sare peste etapa de evacuare in exterior daca plutitorul din Bazin 2 nu este la nivel
                  return;         // prin aceasta se realizeaza echilibrarea volumetrica a statiei de epurare
                }
              return;
            } 
  //------------------ evacuare -----------------------------------------------------------------------------------*/
          
          //aici incepe evauarea in exterior
          if((Evacuare.CL == 0) && (Evacuare.OP == POMPA.PornireEvacuare) && nivel_B2_Pin_A1)// sa terminat linistirea si incepe evacuarea
            {              
              PORTB |= _BV(PB4);// porneste releul de pe pinul D12 care activeaza pompa de evacuare in exterior
              Evacuare.OP--;
              return;
            }
          else if ((Evacuare.OP != 0) && nivel_B2_Pin_A1 )// daca apa de evacuat este mai sus de plutiorul de nivel din BAZIN 2, adica in timpul
            {                                             // linistirii pt. evacuare sa depasit prea plinul hidraulic din BAZIN 1, elimina 
              Evacuare.OP--;                              // surplusul si revine la PornireEvacuare in cadrul ISR pin A1 cand se modifica starea plutiorului                          
              surplus_Evacuare = true;
              if (Evacuare.OP == 0) // pompa evacuare in exterior defecta sau senzor de nivel BAZIN 2 blocat ON(cuplat)
                { 
                  alarma = 3; // declansez ALARMA - nu s-a decuplat senzorul de nivel in Bazin 2
                  LCD.Alarma[2]<65535 ? LCD.Alarma[2] += 1 : LCD.Alarma[2] = 65535;
                  //StareCiclu (4); // afisez starea cand s-a declansat alarma
                  //Initializare_Ciclu();
                  return; 
                }
            }
          else if ((Evacuare.OP != 0) && !nivel_B2_Pin_A1)// a fost eliminat surplusul de apa si evacueaza cantitatea de apa epurata
            {
              Evacuare.OP--;
              if (surplus_Evacuare)              // daca exista surplus de apa aparut in timpul linistirii
                {                                // reinitializeaza timpul de evacuare dupa  eliminarea 
                  Evacuare.OP = POMPA.PornireEvacuare; // surplusului pentru a se pastra timpii de epurare
                  surplus_Evacuare = false;                       
                }
              return;
            }
  //-------------- umplere bazin 2 ---------------------------------------------------------------------------------------*/

          //aici incepe umplerea bazinului 2  
          if (Evacuare.CL == 0 && Evacuare.OP == 0 )// s-a epuizat linistirea si evacuarea
            {
              //Serial.println(PornireEvacuareInBazin2);
              if (PornireEvacuareInBazin2 == POMPA.PornireEvacuare + intarziere_Plutitor)// se umple Bazinul 2  dupa ce a fost evacuat in exterior
                {                                                                  // daca senzorul de nivel din Bazinul 2-pin A1 nu este decuplat
                  PORTB &= ~_BV(PB4); // opreste releul de pe pinul D12 care activeaza pompa de evacuare in exterior
                  if (!prea_plin_B2_Pin_A2 ) // porneste pompa de umplere daca preaplinul nu este cuplat, 
                    {                        // altfel transferul se realizeaza hidraulic 
                      PORTB |= _BV(PB3); // porneste releul de pe pinul D11 care activeaza pompa de evacuare in bazin 2
                      //PornireEvacuareInBazin2--;
                    }
                    PornireEvacuareInBazin2--;
                  return;
                }
              else if (PornireEvacuareInBazin2 >= 0 && PornireEvacuareInBazin2 <= POMPA.PornireEvacuare + intarziere_Plutitor) //umple bazinul 2 dupa evacuare
                {                                                                                                      // pompa are 100 litri/min si are      
                                                                                                                      // nevoie de 180 secunde de a evacua
                                                                                                                      // 300 litri in bazinul 2
                  if (!nivel_B2_Pin_A1 && PornireEvacuareInBazin2 != 0 && !prea_plin_B2_Pin_A2) 
                    {
                      PornireEvacuareInBazin2-- ; // continua umplerea
                      return;
                    }
                  else if (PornireEvacuareInBazin2 == 0 && !prea_plin_B2_Pin_A2)
                    {
                      if (((PINC & (1 << PC0)) == 0))// senzorul de nivel bazin 1 a ramas 
                        {                            // cuplat-senzor nivel defect sau murdar
                                                    // sau pompa de umplere defecta  
                          alarma = 4; // declansez ALARMA - nu s-a decuplat senzorul de nivel in bazin 1
                          stare_nivel_B2_Pin_A1 = nivel_B2_Pin_A1;
                          alarma_Evacuare++ ;
                          LCD.Alarma[3]<65535 ? LCD.Alarma[3] += 1 : LCD.Alarma[3] = 65535;
                          StareCiclu (4); // afisez starea cand s-a declansat alarma
                          Initializare_Ciclu();
                          return;            
                        } 
                      else if ((PINC & (1 << PC0)) != 0)// umplerea sa facut cu succes
                        {
                          Initializare_Ciclu();
                          return;
                        }
                    }
                  else if (((PINC & (1 << PC0)) == 0 && nivel_B2_Pin_A1) && !prea_plin_B2_Pin_A2)// forteaza umplerea daca senzorul de nivel din 
                    {                                                                            // Bazin 2 nu a fost decuplat in urma evacuarii
                      PornireEvacuareInBazin2-- ; 
                      return;
                    }
                  else if (nivel_B2_Pin_A1 && (PornireEvacuareInBazin2 != 0) && !prea_plin_B2_Pin_A2)// senzorul de nivel Bazin 2 s-a cuplat  
                    {                                                                           // si nu s-a epuizat timpul de umplere
                                                                                                // continua umplerea 15 secunde
                      if (intarziere_Pin_A1 >= 0 && intarziere_Pin_A1 < intarziere_Plutitor) // pompa de evacuare in Bazin 2 mai functioneaza 15 secunde
                        {                                                                    // aceasta situatie apare in general cand bazinul 2 nu a
                                                                                            // functionat plin si se produce o echilibrare de nivel
                          intarziere_Pin_A1++; // numara intarzierea de 15 secunde
                          PornireEvacuareInBazin2 = intarziere_Plutitor - intarziere_Pin_A1;
                          return;
                        }
                    }
                  else if ((PINC & (1 << PC0)) == 0 && PornireEvacuareInBazin2 == 0 ) // s-a terminat umplerea BAZIN 2 si senzorul de nivel nu este cuplat
                    {                                                         // senzor nivel defect sau murdar si nu cupleaza sau pompa de umplere defecta
                      alarma = 4; // declansez ALARMA - nu s-a decuplat senzorul de nivel in bazin 1
                      stare_nivel_B2_Pin_A1 = nivel_B2_Pin_A1;
                      alarma_Evacuare++ ;
                      LCD.Alarma[3]<65535 ? LCD.Alarma[3] += 1 : LCD.Alarma[3] = 65535;
                      //StareCiclu (4); // afisez starea cand s-a declansat alarma
                      Initializare_Ciclu();
                      return;            
                    } 
                  else if (((PINC & (1 << PC0)) == 0 || nivel_B2_Pin_A1) && prea_plin_B2_Pin_A2)// apare cand senzorul de nivel nu s-a decuplat dupa evacuare
                    {                                                                           // deoarece verificarea senzorului se face o singura data
                                                                                                // la inceputul umplerii, fapt care arata ca umplerea se realizeaza
                                                                                                // intre nivel bazin 2 si prea plin, adica bazinul 2 a ramas plin
                                                                                                // si prin umplere sa atins nivelul de preaplin si 
                                                                                                // " PornireEvacuareInBazin2 " nu a ajuns la 0
                      alarma = 5; // declansez ALARMA - pompa de evacuare in exterior sigur este arsa
                      LCD.Alarma[4]<65535 ? LCD.Alarma[4] += 1 : LCD.Alarma[4] = 65535;
                      //StareCiclu (4); // afisez starea cand s-a declansat alarma
                      Initializare_Ciclu();
                      return;
                    }
                }
            }
        }
    return;
  }// end Evacuare

Evita_Evacuarea: // saltul la aceasta eticheta pastreaza procesele 
                 // in functiune pana se realizeaza intarzierea pe
                 // pinul A0 pentru eliminarea semnalelor false

  /**** RECIRCULARE ****/


  if (Recirculare.SS == true )//&& !nivel_B1_Pin_A0)
    {
    //-------------------------------------------------------------------------------  
      // stabilesc setari pt recirculare vacanta - are loc odata la 48 ore
      if (timp_Vacanta >= interval_Vacanta && timp_Vacanta <= interval_Vacanta + 10) 
      { 
        
        if (timp_Vacanta == interval_Vacanta)
        {
          if (LinistireREC == 0)
            {
              //Recirculare = {PornireRecirculare, AsteptareRecirculare , true };
              LinistireREC = POMPA.LinistireEvacuare;
              Recirculare.OP = POMPA.PornireRecirculare;
            }
              PORTB &= ~_BV(PB3); // opreste releul de pe pinul D11 care activeaza pompa de evacuare in bazin 2
              PORTB &= ~_BV(PB2); // opreste releul de pe pinul D10 care activeaza pompa de evacuare in bazin 0
              PORTC |= _BV(PC3);  // schimb pozitia electrovanei cu trei căi penru improspatare apa Bazin 0
        }  
                                                                 
        if (timp_Vacanta == interval_Vacanta +10) // astept 10 secunde sa se comute vana cu trei căi
        {
          timp_Vacanta = 0;
          Recirculare.CL = 0; ORA_Recirculare = 0; // fortez recircularea pentru improspatare apa Bazin 0
        }
      }
    //--------------------------------------------------------------------------------
      //recirculare normala
      ORA_Recirculare++;
      if ((ORA_Recirculare == ora) && (Recirculare.CL != 0)) {Recirculare.CL--; ORA_Recirculare = 0;}
      if (Recirculare.CL == 0)
        {
          StareCiclu (2);// afisez starea pentru Recirculare
          if (LinistireREC == POMPA.LinistireEvacuare) 
            {
              AerareB1.SS = false; AerareB2.SS = false; LinistireREC--;
              if ( (AerareB1.OP == 0) && (AerareB2.OP == 0) )// cilul de recirculare a aparut in perioada linistirii aerarii
                {
                  if (POMPA.LinistireEvacuare >= (POMPA.Bazin_2_Linistire - AerareB2.CL))//recupereaza timpul de linistire trecut
                    {                                                        // in timpul aerarii
                      LinistireREC = POMPA.LinistireEvacuare - (POMPA.Bazin_2_Linistire - AerareB2.CL);// continua linistirea pentru diferenta de timp trecut
                    }
                  else LinistireREC = 0;// timpul de linistire s-a epuizat si se poate realiza recircularea
                }

              //oprim toate pompele
              PORTB &= ~_BV(PB4); // opreste releul de pe pinul D12 care activeaza pompa de evacuare in exterior
              PORTB &= ~_BV(PB3); // opreste releul de pe pinul D11 care activeaza pompa de evacuare in bazin 2
              PORTB &= ~_BV(PB2); // opreste releul de pe pinul D10 care activeaza pompa de evacuare in bazin 0
              PORTB &= ~_BV(PB1); // opreste releul de pe pinul D8 care activeaza pompa de aerare bazin 1
              PORTB &= ~_BV(PB0); // opreste releul de pe pinul D9 care activeaza pompa de aerare bazin 2
            }
          if (LinistireREC != 0) 
            {
              LinistireREC--;
              //StareCiclu (2);// afisez starea pentru Recirculare
              return;
            }
          if (LinistireREC == 0 && Recirculare.OP == POMPA.PornireRecirculare)
            {
              PORTB |= _BV(PB3); // porneste releul de pe pinul D11 care activeaza pompa de evacuare in bazin 2
              PORTB |= _BV(PB2); // porneste releul de pe pinul D10 care activeaza pompa de evacuare in bazin 0
              Recirculare.OP--; 
              //StareCiclu (2);// afisez starea pentru Recirculare
              return;
            }
          else if ((LinistireREC == 0) && (Recirculare.OP != 0)) 
            {
              Recirculare.OP--;
              //StareCiclu (2);// afisez starea pentru Recirculare
              return;
            }
          else if ((LinistireREC == 0) && (Recirculare.OP == 0)) {Initializare_Ciclu();} // s-a terminat recircularea 
        }
    }// end Recirculare

  /**** AERARE ****/

  if (AerareB1.SS == true && AerareB2.SS == true)//aerarea se face in pararel la timpi diferiti pt fiecare bazin
    {
        StareCiclu (3);// afisez starea pentru Aerare 
        //aerare Bazin 1      
        if (AerareB1.OP == POMPA.Bazin_1_Aerare) 
          {
            //oprim pompele de recirculare si evacuare
            PORTB &= ~_BV(PB4); // opreste releul de pe pinul D12 care activeaza pompa de evacuare in exterior
            PORTB &= ~_BV(PB3); // opreste releul de pe pinul D11 care activeaza pompa de evacuare in bazin 2
            PORTB &= ~_BV(PB2); // opreste releul de pe pinul D10 care activeaza pompa de evacuare in bazin 0
            AerareB1.OP--;
            PORTB |= _BV(PB1); // porneste releul de pe pinul D8 care activeaza pompa de aerare bazin 1
          }
        else if (AerareB1.OP != 0) AerareB1.OP--;
        else if ((AerareB1.OP == 0) && (AerareB1.CL == POMPA.Bazin_1_Linistire)) 
          {
            PORTB &= ~_BV(PB1); // opresc releul de pe pinul D8 care activeaza pompa de aerare bazin 1
            AerareB1.CL--;
          }
        else if ((AerareB1.OP == 0) && (AerareB1.CL != 0)) AerareB1.CL--;
        else if ((AerareB1.OP == 0) && (AerareB1.CL == 0)) 
          {
            AerareB1.CL = POMPA.Bazin_1_Linistire; AerareB1.OP = POMPA.Bazin_1_Aerare;
          }
        // aerare Bazin 2
        if (AerareB2.OP == POMPA.Bazin_2_Aerare) 
          {
            //oprim pompele de recirculare si evacuare
            PORTB &= ~_BV(PB4); // opreste releul de pe pinul D12 care activeaza pompa de evacuare in exterior
            PORTB &= ~_BV(PB3); // opreste releul de pe pinul D11 care activeaza pompa de evacuare in bazin 2
            PORTB &= ~_BV(PB2); // opreste releul de pe pinul D10 care activeaza pompa de evacuare in bazin 0
            AerareB2.OP--;
            PORTB |= _BV(PB0); // porneste releul de pe pinul D8 care activeaza pompa de aerare bazin 1
          }
        else if (AerareB2.OP != 0) AerareB2.OP--;
        else if ((AerareB2.OP == 0) && (AerareB2.CL == POMPA.Bazin_2_Linistire)) 
          {
            PORTB &= ~_BV(PB0); // opresc releul de pe pinul D8 care activeaza pompa de aerare bazin 2
            AerareB2.CL--;
          }
        else if ((AerareB2.OP == 0) && (AerareB2.CL != 0)) AerareB2.CL--;
        else if ((AerareB2.OP == 0) && (AerareB2.CL == 0)) 
          {
            AerareB2.CL = POMPA.Bazin_2_Linistire; AerareB2.OP = POMPA.Bazin_2_Aerare;
          }
    }// end Aerare

}// end call_ISR_Timer




/******************** FUNCTIE RESETARE SOFTWARE PLACA  *******************/
// resetare arduino.
// Trebuie scrisa inainte functiei loop().
// resetFunc() este chemata cand este nevoie.
inline void(* resetFunc) (void) = 0;

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




/************************ INTRERUPERE ISR PENTRU TIMP ***************************/


ISR(TIMER1_OVF_vect) //Intrerupere TIMER1 
{
/************ INTRERUPERE/EVENIMENT CARE MASOARA TIMPUL IN SECUDE **********************************/
// Acesta intrerupere este folosita pentru functii de timp prin intreruperea functiei " loop () "
// Se poate utiliza pentru ceas, semnale pe pini, etc. care nu au nevoie de timp de precizie la microsecunda
//ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { UNSIGNED Long temp = Durata} din lib. #include <util/atomic.h>
// pentru a nu se transmite un rezultat eronat in timpul intreruperii

  flag_Timer1 = true;

}// end ISR

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


void setup() 
{
    Serial.begin(9600);
    lcd.init(); //initialize the lcd
    lcd.backlight(); //open the backlight

  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
  {
  
  // initializare pini butoane
    pinMode(butonPinSETUP, INPUT_PULLUP);
    pinMode(butonPinTimpMINUS, INPUT_PULLUP);
    pinMode(butonPinTimpPLUS, INPUT_PULLUP);

  // initializare pin buzzer
    pinMode(buzzerPin, OUTPUT);

  // initializare pini senzori de nivel (plutitori cu contacte REED montati in bazine)
    pinMode(A0, INPUT_PULLUP);
    pinMode(A1, INPUT_PULLUP);
    pinMode(A2, INPUT_PULLUP);

  // initializare pini pompe
    pinMode(8, OUTPUT);
    //pinMode(9, OUTPUT); // acesti pini nu trebuie setati OUTPUT, deoarece cred ca
    //pinMode(10, OUTPUT);// bilioteca LCD îi foloseste deja ca PWM si se pare ca 
    pinMode(11, OUTPUT);  // functioneaza in WOKWI asa, dar trebuie verificat real pe MC
    pinMode(12, OUTPUT);

  // initializare pin robinet 3 căi
    pinMode(A3, OUTPUT);

    Initializare_Ciclu();

  // initializez TIMER 1 sa cheme ISR la o secunda
    TCCR1B = 0x10; // 0001 0000, Disable Timer 
    TCCR1A = 0xA2; // 1010 0010

    ICR1 = 31250; // valuare TOP
    TCNT1 = 0x0;  // porneste de la 0
    TCCR1B |= 4; // Prescale=256, Enable Timer in binar 0000 0100
                 // sau (1<<CS10)|(0 << CS11)|(0 << CS12) prin scriere registrii

    // Set Overflow Interrupt Mask Bit 
    TIMSK1 |= 1; // ISR Prototype --> ISR(TIMER1_OVF_vect){}


  /*************************************************************************************************/
  } //end ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
}// end setup()


void loop() 
{
    //static unsigned long tmp_Timp = 0;
    Defilare_Meniu_Setup(); // intra in meniul SETUP cand buttonSETUP este apasat  

    //if (tmp_Timp == 0) tmp_Timp = millis();
    if ( flag_Timer1 && Meniu == -1)
    
    //if ( (millis() - tmp_Timp) >= 1000 && (millis() - tmp_Timp) <= 1001)
      { 
        //Serial.println(millis() - tmp_Timp);
        //Serial.println("Y");
        flag_Timer1 = false;
        call_ISR_Timer ();
        //delay(100);
        if (durata > 604800)// se reseteaza controlerul la fiecare 7 de zile daca nu ajung sa elimin
        {                   // alarmele cu speranta ca nu sunt arse pompele si sunt doar murdari senzorii
          Initializare_Ciclu();
          resetFunc() ;
        }
        //tmp_Timp = millis();          
      }
    //else {Serial.println("x");}


}//end loop()





//////////////////////// FUNCTII INTRODUSE IN void loop() //////////////////////////////////////////

/******************** FUNCTIE OPRIRE CICLU *****************************/

// Acesta functie opreste ciclul cand se intra in meniul Setup si este necesara
// deoarece LCD I2C afiseaza foarte lent se supra incarca stiva si se bolcheaza Mcu
// daca flag = true opreste ciclul, daca este false porneste ciclul din faza in 
// care s-a oprit
// cu alte cuvinte se opresc toate pompele si nu se executa functia call_ISR_Timer
// cand Meniu este diferit de -1
void Oprie_Pornire_CICLU(bool flag)
  {
    static byte pompe[5];
    return;
    if (flag)
      {
        // stochez starea pinilor
        pompe[0] = PINB & (1 << PB0);
        pompe[1] = PINB & (1 << PB1);
        pompe[2] = PINB & (1 << PB2);
        pompe[3] = PINB & (1 << PB3);
        pompe[4] = PINB & (1 << PB4);
        // oprim toate pompele 
        PORTB &= ~_BV(PB4); // opreste releul de pe pinul D12 care activeaza pompa de evacuare in exterior
        PORTB &= ~_BV(PB3); // opreste releul de pe pinul D11 care activeaza pompa de evacuare in bazin 2
        PORTB &= ~_BV(PB2); // opreste releul de pe pinul D10 care activeaza pompa de evacuare in bazin 1
        PORTB &= ~_BV(PB1); // opreste releul de pe pinul D8 care activeaza pompa de aerare bazin 1
        PORTB &= ~_BV(PB0); // opreste releul de pe pinul D9 care activeaza pompa de aerare bazin 2

      }
    else if (!flag)
      {
        // refac starea pompelor
        if (pompe[0]) PORTB |= _BV(PB4); 
        if (pompe[0]) PORTB |= _BV(PB3); 
        if (pompe[0]) PORTB |= _BV(PB2); 
        if (pompe[0]) PORTB |= _BV(PB1); 
        if (pompe[0]) PORTB |= _BV(PB0); 

      }
  }

/************ FUNCTIE CARE DETERMINA CAT TIMP ESTE APASAT UN BUTON *******************/

// ACEASTA FUNCTIE DETERMINA CÂT TIMP UN BUTON ESTE APASAT SI RETURNEAZA TRUE DACA ESTE DEPASIT timpAPASARE
// SAU DACA timpAPASARE = 0 secunde RETURNEAZA EFECTIV TIMPUL DE APASARE
// TIMPUL MAXIM DE APASARE ESTE 2^32-1 MILISECUNDE APROXIMATIV 50 ZILE APOI SE RESETEAZA
// Variabila " btnPIN " reprezinta numarul pinului la care este atasat butonul activat in functia " setup "
// Pinii digitali sunt de la 0 pana la 13
// Pinii analogici de la A0 pana la A7 pentru Arduino NANO PLUS ( ch340 )
// Pinii analogici trebuie introdusi in cadrul functiei cu constantele implicite A0..A7 si au valori de la 14 .. 21
// Se foloseste functia " digitalRead() " indiferent de tipul pinului
// Variabila " start " reprezinta timpul la care a fost apasat butonul si se determina
// cu functia arduino " millis() "
// Variabila " timpAPASARE " reprezinta timpul necesar de apasare ca butonul sa produca efect si este dat in milisecude,
// In interiorul functiei calculul se realizeaza in milisecunde deoarece valoarea " start " este data de functia " millis() "
// Se poate folosi si ISR-ul de mai sus

  unsigned long Timp_Apasare_BTN (  const uint8_t btnPIN,  const unsigned long timpAPASARE ) 
  {

  unsigned long secundeDOWN = 0;
  unsigned long start = millis();

  if (digitalRead(btnPIN)) {return false;}          
  
  while(!digitalRead(btnPIN)) { secundeDOWN = millis();}

  if ( secundeDOWN >= start ) 
    {
      if (timpAPASARE == 0) {return (secundeDOWN - start);}
      else if ((secundeDOWN - start) >= timpAPASARE) {return true;}
      else {return false;}
    } 
  else if (secundeDOWN < start)
    {
      if (timpAPASARE == 0) {return (( pow(2 , 32) -1 - start) + secundeDOWN  );}
      else if ((( pow(2 , 32) -1 - start) + secundeDOWN  )>= timpAPASARE) {return true;} 
      else {return false;}
    }
}//end Timp_Apasare_BTN

  /*********************** FUNCTIE Blink_Meniu ***********************/

  // Acesata functie afiseaza meniul pentru afisaj 20x4
  // Meniul selectat va clipi
  // Prima linie a afisajului este folosita pentru titlu
  // Sunt afisate doar trei linii de meniu
  // Denumirea meniului nu trebuie sa fie mai mare de 14 caractere daca este
  // necesara introducere de date, altfel sa nu depasasca 18 caractere  
  // sel reprezinta pozitia meniului selectat
  // sel reprezinta linia de afisare cu valori 1, 2 sau 3
  // val_ reprezinta valorile variabilelor care se vor afisa modificate prin introducere de date
  // UM_ reprezinta unitatea de masura
  void Blink_Meniu ( int sel = 1, String meniu_1 = "", String meniu_2 = "", String meniu_3 = "",
                     int val_1 = -1, int val_2 = -1, int val_3 = -1, 
                     String UM_1 = "", String UM_2 = "",String UM_3 = "" )
 {
      unsigned long timpBlink ;// timpul de afisare a textului
      int max_nrChar;// nr. maxim de caracte dintr-un meniu afisat
      //Serial.println(meniu_3);  
      //timpBlink = millis ();
      //timpBlink %= 300;
      max_nrChar =max ( max( meniu_1.length(), meniu_2.length() ), meniu_3.length() ) + 3;// se aduna 3 pentru ca adauga caracterul >> sau 2  spatii inainte + spatiul de delimitare
      switch (sel) { // stabileste meniul selectat
        case 1: meniu_1 = ">> " + meniu_1; meniu_2 = "  " + meniu_2 ; meniu_3 = "  " + meniu_3 ; break;
        case 2: meniu_1 = "  " + meniu_1 ; meniu_2 = ">> " + meniu_2; meniu_3 = "  " + meniu_3 ; break;
        case 3: meniu_1 = "  " + meniu_1 ; meniu_2 = "  " + meniu_2 ; meniu_3 = ">> " + meniu_3; break;
      }
      for ( byte i = 2; i = max_nrChar - meniu_1.length(); i++ ) { meniu_1 = meniu_1 + " "; } // se adauga spatii daca textul este mai mic decat max_nrChar
      for ( byte i = 2; i = max_nrChar - meniu_2.length(); i++ ) { meniu_2 = meniu_2 + " "; } // se adauga spatii daca textul este mai mic decat max_nrChar
      for ( byte i = 2; i = max_nrChar - meniu_3.length(); i++ ) { meniu_3 = meniu_3 + " "; } // se adauga spatii daca textul este mai mic decat max_nrChar
      //while (timpBlink > 100 && timpBlink < 299) {
        lcd.setCursor(0, 1); lcd.print( meniu_1 ); if (val_1 != -1) { lcd.setCursor(max_nrChar, 1); lcd.print(val_1); }; if (UM_1 != "") { lcd.setCursor(17, 1); lcd.print(UM_1); }
        lcd.setCursor(0, 2); lcd.print( meniu_2 ); if (val_2 != -1) { lcd.setCursor(max_nrChar, 2); lcd.print(val_2); }; if (UM_2 != "") { lcd.setCursor(17, 2); lcd.print(UM_2); }
        lcd.setCursor(0, 3); lcd.print( meniu_3 ); if (val_3 != -1) { lcd.setCursor(max_nrChar, 3); lcd.print(val_3); }; if (UM_3 != "") { lcd.setCursor(17, 3); lcd.print(UM_3); }
        //timpBlink = millis (); timpBlink %= 300; 
      //}
      //if      (val_1 != -1 && sel == 1) { lcd.setCursor(max_nrChar, sel); lcd.print("   ");} //afiseaza 3 spatii si creaza efectul de clipire citire date
      //else if (val_2 != -1 && sel == 2) { lcd.setCursor(max_nrChar, sel); lcd.print("   ");} //afiseaza 3 spatii si creaza efectul de clipire citire date
      //else if (val_3 != -1 && sel == 3) { lcd.setCursor(max_nrChar, sel); lcd.print("   ");} //afiseaza 3 spatii si creaza efectul de clipire citire date
      //else { lcd.setCursor(0, sel); lcd.print( ">>                " ); }//afiseaza >> + 18 spatii si creaza efectul de clipire meniu             

  }// end Blink_Meniu

    /***************** FUNCTIE Afisare_Meniu ********************/

  // Aceasta functie afiseaza Meniul si Meniul selectat prin licarire si marcat cu caracterul ">"
  // Functia este utilizata in interiorul functiei Defilare_Meniu ()


  inline void Afisare_Meniu_Setup () 
  {
  //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) // cu LCD_I2C se blocheaza in WOKWI
  {

    if (Meniu >= 1 && Meniu <= 4) { lcd.setCursor(0, 0); lcd.print("------ SETARE ------");}
    switch (Meniu) {
      case 1: // Meniu principal 1 - AERARE
          Blink_Meniu ( 1, "AERARE", "EVACUARE", "RECIRCULARE" ); break;

      case 2: // Meniu principal 2 - EVACUARE
          Blink_Meniu ( 2, "AERARE", "EVACUARE", "RECIRCULARE" ); break;

      case 3: // Meniu principal 3 - RECIRCULARE
          Blink_Meniu ( 3, "AERARE", "EVACUARE", "RECIRCULARE" ); break;

      case 4: // Meniu principal 4 - EXIT
          Blink_Meniu ( 3, "EVACUARE", "RECIRCULARE", "EXIT" ); break;

      case 5: // Meniu AERARE
            if (subMeniuAERARE >= 1 && subMeniuAERARE <= 3) { lcd.setCursor(0, 0); lcd.print("-- SETARE: AERARE --");}

            switch (subMeniuAERARE) { // subMeniuAERARE
              case 1:
                  Blink_Meniu ( 1, "BAZIN 1", "BAZIN 2", "EXIT" ); break;

              case 2:
                  Blink_Meniu ( 2, "BAZIN 1", "BAZIN 2", "EXIT" ); break;

              case 3:
                  Blink_Meniu ( 3, "BAZIN 1", "BAZIN 2", "EXIT" ); break;

              case 4: //Aerare BAZIN 1
                    lcd.setCursor(0, 0); lcd.print("-- AERARE BAZIN 1 --");
                    switch (subMeniuBazin_1_AERARE) {
                      case 1: // PORNIRE
                          Blink_Meniu ( 1, "PORNIRE", "LINISTIRE", "SAVE & EXIT",POMPA.Bazin_1_Aerare, POMPA.Bazin_1_Linistire/60,-1, "sec", "min" ); break;                            

                      case 2: // LINISTIRE                            
                          Blink_Meniu ( 2, "PORNIRE", "LINISTIRE", "SAVE & EXIT",POMPA.Bazin_1_Aerare, POMPA.Bazin_1_Linistire/60, -1, "sec", "min" ); break;                            

                      case 3: //SAVE & EXIT                           
                          Blink_Meniu ( 3, "PORNIRE", "LINISTIRE", "SAVE & EXIT",POMPA.Bazin_1_Aerare, POMPA.Bazin_1_Linistire/60, -1, "sec", "min" ); break;                            
                     }
                     break;
              case 5: // Aerare BAZIN 2
                    lcd.setCursor(0, 0); lcd.print("-- AERARE BAZIN 2 --");
                    switch (subMeniuBazin_2_AERARE) {
                      case 1: // PORNIRE                           
                          Blink_Meniu ( 1, "PORNIRE", "LINISTIRE", "SAVE & EXIT",POMPA.Bazin_2_Aerare, POMPA.Bazin_2_Linistire/60, -1, "sec", "min" ); break;                            

                      case 2: // LINISTIRE                           
                          Blink_Meniu ( 2, "PORNIRE", "LINISTIRE", "SAVE & EXIT",POMPA.Bazin_2_Aerare, POMPA.Bazin_2_Linistire/60, -1, "sec", "min" ); break;                            

                      case 3: // SAVE & EXIT                            
                          Blink_Meniu ( 3, "PORNIRE", "LINISTIRE", "SAVE & EXIT",POMPA.Bazin_1_Aerare, POMPA.Bazin_1_Linistire/60, -1, "sec", "min" ); break;                            
                    }
                    break;

             } 
            break;
      case 6: // Meniu EVACUARE
            if (subMeniuEVACUARE >= 1 && subMeniuEVACUARE <= 2) { lcd.setCursor(0, 0); lcd.print("----- EVACUARE -----");}

            switch (subMeniuEVACUARE) { // subMeniuEVACUARE
              case 1:
                  Blink_Meniu ( 1, "PORNIRE", "LINISTIRE", "SAVE & EXIT", POMPA.PornireEvacuare, POMPA.LinistireEvacuare/60, -1, "sec", "min" ); break;

              case 2:
                  Blink_Meniu ( 2, "PORNIRE", "LINISTIRE", "SAVE & EXIT", POMPA.PornireEvacuare, POMPA.LinistireEvacuare/60, -1, "sec", "min" ); break;

              case 3:
                  Blink_Meniu ( 3, "PORNIRE", "LINISTIRE", "SAVE & EXIT", POMPA.PornireEvacuare, POMPA.LinistireEvacuare/60, -1, "sec", "min" ); break;
            }
          break;
      case 7: // Meniu RECIRCULRE
            if (subMeniuRECIRCULARE >= 1 && subMeniuRECIRCULARE <= 2) { lcd.setCursor(0, 0); lcd.print("---- RECIRCULARE ---");}

            switch (subMeniuRECIRCULARE) { // subMeniuRECIRCULARE
              case 1:
                  Blink_Meniu ( 1, "PORNIRE", "ASTEPTARE" , "SAVE & EXIT", POMPA.PornireRecirculare, POMPA.AsteptareRecirculare, -1, "sec" , "ore" ); break;

              case 2:
                  Blink_Meniu ( 2, "PORNIRE", "ASTEPTARE" , "SAVE & EXIT", POMPA.PornireRecirculare, POMPA.AsteptareRecirculare, -1, "sec" , "ore" ); break;

              case 3:
                  Blink_Meniu ( 3, "PORNIRE", "ASTEPTARE" , "SAVE & EXIT", POMPA.PornireRecirculare, POMPA.AsteptareRecirculare, -1, "sec" , "ore" ); break;
            }
          break;
      }
  }         
  }// end Afisare_Meniu_Setup


/***************** FUNCTIE CARE DEFILEZA MeniuL SETARE CU UN SINGUR BUTON ********************/

// Cand este chemata modifica valoare variabilei " Meniu ".
// Functia este executata numai cand valorea variabilei " Meniu " este >= 1
// Cand variabila " Meniu = -1 " microcontroler-ul executa alte operatii
// Daca butonul SETARE este apasat 1 secunda programul intra in modul setare
// Daca butonul SETARE este apasat 1 secunda pe subMeniu se intra in subMeniuri

inline void Defilare_Meniu_Setup ()  
{
  if (Meniu == -1 && digitalRead(butonPinSETUP)) return;
  
 // unsigned long timpAPASARE = 1000;// timpul de apasare al butonului in milisecunde - adica 1 secunda

  Afisare_Meniu_Setup ();

  if (digitalRead(butonPinSETUP)) return; 

  bool timp = Timp_Apasare_BTN ( butonPinSETUP, 1000 );// returneaza intotdeauna TRUE sau FALSE
                                                       // deoarece timpAPASARE este diferit de zero

  switch (Meniu) { // Meniul principal are 4 submeniuri

    case -1: // intra in modul SETARE
          if (timp) { Meniu = 1; lcd.clear (); Oprie_Pornire_CICLU (true);}
          break;
    case 1: // Meniu principal 1 - AERARE
          if (!timp) { Meniu ++; }
          else { Meniu = 1 + 4; subMeniuAERARE = 1; lcd.clear(); }
          break;
    case 2: // Meniu principal 2 - EVACUARE
          if (!timp) { Meniu ++; }
          else { Meniu = 2 + 4; subMeniuEVACUARE = 1; lcd.clear(); }
          break;
    case 3: // Meniu principal 3 - RECIRCULARE
          if (!timp) { Meniu ++; }
          else { Meniu = 3 + 4; subMeniuRECIRCULARE = 1; lcd.clear(); }
          break;
    case 4: // Meniu principal 4 - EXIT
          if (!timp) { Meniu = 1; }
          else { Meniu = -1 ; subMeniuAERARE = -1; subMeniuEVACUARE = -1; subMeniuRECIRCULARE = -1; lcd.clear(); Oprie_Pornire_CICLU (false);}
          break;
    case 5: // Meniu secundar 1 - AERARE
          switch (subMeniuAERARE) { // subMeniuAERARE are 3 subMeniuri bazin 1 bazin 2 exit

            case 1: // sub Meniu BAZN 1
                  if (!timp) { subMeniuAERARE ++; }
                  else { subMeniuAERARE = 1 + 3; subMeniuBazin_1_AERARE = 1;}
                  break;
            case 2: // sub Meniu BAZN 2
                  if (!timp) { subMeniuAERARE ++; }
                  else { subMeniuAERARE = 2 + 3; subMeniuBazin_2_AERARE = 1;}
                  break;
            case 3: // sub Meniu EXIT
                  if (!timp ) { subMeniuAERARE = 1; }
                  else { Meniu = 1; subMeniuAERARE = -1; lcd.clear ();}
                  break;
            case 4: //sub Meniu Bazin 1 AERARE // are 3 submeniuri PORNIRE , LINISTIRE si SAVE & EXIT
                  switch (subMeniuBazin_1_AERARE) {
                    case 1: //PORNIRE
                          if (!timp ) { subMeniuBazin_1_AERARE++; }
                          break;
                    case 2: //LINISTIRE
                          if (!timp ) { subMeniuBazin_1_AERARE++; }
                          break;
                    case 3: //SAVE & EXIT
                          if (!timp ) { subMeniuBazin_1_AERARE = 1; }
                          else { subMeniuAERARE = 1; subMeniuBazin_1_AERARE = -1; subMeniuBazin_2_AERARE = -1; lcd.clear (); }
                          break;
                  }// end switch (subMeniuBazin_1_AERARE)
                  break;
            case 5: //sub Meniu Bazin 2 AERARE // are 3 submeniuri PORNIRE , LINISTIRE si SAVE & EXIT
                  switch (subMeniuBazin_2_AERARE) {
                    case 1: //PORNIRE
                          if (!timp ) { subMeniuBazin_2_AERARE++; } 
                          break;
                    case 2: //LINISTIRE
                          if (!timp ) { subMeniuBazin_2_AERARE++; } 
                          break;
                    case 3: //SAVE & EXIT
                          if (!timp ) { subMeniuBazin_2_AERARE = 1; }
                          else { subMeniuAERARE = 2; subMeniuBazin_1_AERARE = -1; subMeniuBazin_2_AERARE = -1; lcd.clear (); }
                          break;
                  }// end switch (subMeniuBazin_2_AERARE)
                  break;
          }// end switch (subMeniuAERARE)
          break;
    case 6: // sub Meniu EVACUARE // are 3 sub Meniuri PORNIRE, LINISTIRE si SAVE & EXIT 
          switch (subMeniuEVACUARE) {
            case 1: //PORNIRE
                  if (!timp ) { subMeniuEVACUARE++; }
                  break;
            case 2: //LINISTIRE
                  if (!timp ) { subMeniuEVACUARE++; }
                  break;
            case 3: //SAVE & EXIT
                  if (!timp ) { subMeniuEVACUARE = 1; }
                  else { Meniu = 2; subMeniuEVACUARE = -1; lcd.clear (); }
                  break;
          }// end switch (subMeniuEVACUARE)
          break;
    case 7: // RECIRCULARE // are un2 sub Meniuri PORNIRE si SAVE & EXIT
          switch (subMeniuRECIRCULARE) {
            case 1: //PORNIRE
                  if (!timp ) { subMeniuRECIRCULARE++; }
                  break;
            case 2: //ASTEPTARE
                  if (!timp ) { subMeniuRECIRCULARE++; }
                  break;
            case 3: //SAVE & EXIT
                  if (!timp ) { subMeniuRECIRCULARE = 1; }
                  else { Meniu = 3; subMeniuRECIRCULARE = -1; lcd.clear (); }
                  break;
          }// end switch (subMeniuRECIRCULARE)
          break;
  }// end switch (Meniu)


}//end Defilare_Meniu_Setup