/*attiny84 cde 2 aiguillages KATO
   11/12/2023
   Dominique Hudry
   liens:  https://electroniqueamateur.blogspot.com/2019/06/controler-plusieurs-leds-avec-arduino.html
           https://wokwi.com/projects/383829237167637505
   Commande de deux aigillages KATO par l'appui de BP
   Une impulsion unique et de durée fixe est envoyé à un étage de puissance (L293D double pont en H)
   qui alimente la bobine de chaque aiguillage en modifiant la polarité . 
   La position de chaque aiguillage est indiquée par des leds, le nombre limité des pins imposant le charlieplexing.        

                Brochage ATtiny84

                VCC=|1  U 14|= GND
    BrocheC <-->10 =|2    13|= 0<-- BPdroit1--GND
     BrocheB <-->9 =|3    12|= 1<-- BPdevie1--GND
             Reset =|4    11|= 2<-- BPdroit2--GND
     BrocheA <-->8 =|5    10|= 3<-- BPdevie2--GND
    CdeInput4 <--7 =|6     9|= 4--> CdeInput1
    CdeInput3 <--6 =|7     8|= 5--> CdeInput2

                  Brochage L293D

       +5V--Enable1 =|1  U 16|= +5V
  CdeInput1--Input1 =|2    15|= Input4--CdeInput4
            Output1 =|3    14|= Output4
                GND =|4    13|= GND
                GND =|5    12|= GND
            Output2 =|6    11|= Output3
  CdeInput2--Input2 =|7    10|= Input3--CdeInput3
           +12V--VS =|8     9|= Enable2--+5V

  E1  Input1 Input2 Output1 Output2    E2  Input3 Input4 Output3 Output4
  1     0      0       pas de ddp       1    0      0       pas de ddp
        1      0       +      -              1      0       +       -
        0      1       -      +              0      1       -       +
        1      1       pas de ddp            1      1       pas de ddp

  la bobine de l'aiguiilage1 se branche entre Output1 (fil rouge) et Output2 (fil noir)
    si impulsion positive sur Input1 alors Output1 est au + et Output2 est au -
    si impulsion positive sur Input2 alors Output1 est au - et Output2 est au +

  la bobine de l'aiguiilage2 se branche entre Output3 (fil rouge) et Output4 (fil noir)
    si impulsion positive sur Input3 alors Output3 est au + et Output4 est au -
    si impulsion positive sur Input4 alors Output3 est au - et Output4 est au +
*/

const byte BPdroit1 = 12; // branchement du BP pour commander la position Droit1
const byte BPdevie1 = 11; // branchement du BP pour commander la position Dévié1
const byte BPdroit2 = 2; // branchement du BP pour commander la position Droit2
const byte BPdevie2 = 3; // branchement du BP pour commander la position Dévié2
const byte CdeInput1 = 4; // liaison avec Input1 du L293D
const byte CdeInput2 = 5; // liaison avec Input2 du L293D
const byte CdeInput3 = 6; // liaison avec Input3 du L293D
const byte CdeInput4 = 7; // liaison avec Input4 du L293D
const byte BrocheA = 8; // cde des leds en charlieplexing
const byte BrocheB = 9; // cde des leds en charlieplexing
const byte BrocheC = 10; // cde des leds en charlieplexing
const byte DureeImpulsion = 20; // durée en ms des impulsions envoyées par les CdeInput
bool etatLeds[] = {0, 0, 0, 0}; // état des 4 leds de position, au démarrage tout est éteint
bool etatBPdroit1; // BP relaché: HIGH,  BP appuyé: LOW
bool etatBPdevie1; // BP relaché: HIGH,  BP appuyé: LOW
bool etatBPdroit2; // BP relaché: HIGH,  BP appuyé: LOW
bool etatBPdevie2; // BP relaché: HIGH,  BP appuyé: LOW
bool validationBPdroit1; // permet la prise en compte ou non d'un appui sur BPdroit1
bool validationBPdevie1; // permet la prise en compte ou non d'un appui sur BPdevie1
bool validationBPdroit2; // permet la prise en compte ou non d'un appui sur BPdroit2
bool validationBPdevie2; // permet la prise en compte ou non d'un appui sur BPdevie2

void setup() {
  pinMode(BPdroit1, INPUT_PULLUP); // configuration des pins en entrée
  pinMode(BPdevie1, INPUT_PULLUP);
  pinMode(BPdroit2, INPUT_PULLUP);
  pinMode(BPdevie2, INPUT_PULLUP);
  pinMode(CdeInput1, OUTPUT); // configuration des pins en sortie
  pinMode(CdeInput2, OUTPUT);
  pinMode(CdeInput3, OUTPUT);
  pinMode(CdeInput4, OUTPUT);
  digitalWrite(CdeInput1, LOW); // à la mise sous tension toutes les commandes sont au niveau LOW
  digitalWrite(CdeInput2, LOW);
  digitalWrite(CdeInput3, LOW);
  digitalWrite(CdeInput4, LOW);
  validationBPdroit1 = true; // permet la prise en compte de n'importe lequel des BP
  validationBPdevie1 = true;
  validationBPdroit2 = true;
  validationBPdevie2 = true;
  efface_tout(); // les leds de position sont toutes éteintes
} // fin setup

void loop() {
  // gestion de l'allumage des leds de position des deux aiguillages
  for (byte i = 0; i < 4 ; i++) { // on cherche quelles leds doivent être allumées
    if (etatLeds[i] == 1) {
      reglage_led(i + 1); // on régle les paramètres pour chaque led devant être allumée
    } // fin if
    else { 
      efface_tout(); // sinon on les éteint toutes
    } // fin else
  } // fin for

  // gestion du BP pour positionnement de l'aiguillage1 en position Droit
  etatBPdroit1 = digitalRead (BPdroit1); // lecture de l'état du BPdroit1
  if (etatBPdroit1 == LOW && validationBPdroit1 == true) { // si conditions pour un déclenchement
    digitalWrite(CdeInput1, HIGH); // impulsion envoyée sur input1 du L293D
    delay(DureeImpulsion);
    digitalWrite(CdeInput1, LOW);
    etatLeds[0] = 1; // la led1 Aiguillage1 Droit s'allume
    etatLeds[1] = 0; // la led2 Aiguillage1 Dévié s'éteint
    validationBPdroit1 = false; // les déclenchements par BPdirect sont bloqués
    validationBPdevie1 = true; // seule une action sur BPdevie est autorisée
  } // fin if

  // gestion du BP pour positionnement de l'aiguillage1 en position Dévié
  etatBPdevie1 = digitalRead (BPdevie1); // lecture de l'état du BPdevie
  if (etatBPdevie1 == LOW && validationBPdevie1 == true) { // si conditions pour un déclenchement
    digitalWrite(CdeInput2, HIGH); // impulsion envoyée sur input2 du L293D
    delay(DureeImpulsion);
    digitalWrite(CdeInput2, LOW);
    etatLeds[0] = 0; // la led1 Aiguillage1 Droit s'éteint
    etatLeds[1] = 1; // la led2 Aiguillage1 Dévié s'allume
    validationBPdevie1 = false; // les déclenchements par BPdevie sont bloqués
    validationBPdroit1 = true; // seule une action sur BPdroit est autorisée
  } // fin if

  // gestion du BP pour positionnement de l'aiguillage2 en position Droit
  etatBPdroit2 = digitalRead (BPdroit2); // lecture de l'état du BPdroit2
  if (etatBPdroit2 == LOW && validationBPdroit2 == true) { // si conditions pour un déclenchement
    digitalWrite(CdeInput3, HIGH); // impulsion envoyée sur input3 du L293D
    delay(DureeImpulsion);
    digitalWrite(CdeInput3, LOW);
    etatLeds[2] = 1; // la led3 Aiguillage2 Droit s'allume
    etatLeds[3] = 0; // la led4 Aiguillage2 Dévié s'éteint
    validationBPdroit2 = false; // les déclenchements par BPdroit2 sont bloqués
    validationBPdevie2 = true; // seule une action sur BPdevie2 est autorisée
  } // fin if

  // gestion du BP pour positionnement de l'aiguillage2 en position Dévié
  etatBPdevie2 = digitalRead (BPdevie2); // lecture de l'état du BPdevie2
  if (etatBPdevie2 == LOW && validationBPdevie2 == true) { // si conditions pour un déclenchement
    digitalWrite(CdeInput4, HIGH); // impulsion envoyée sur input4 du L293D
    delay(DureeImpulsion);
    digitalWrite(CdeInput4, LOW);
    etatLeds[3] = 1; // la led4 Aiguillage2 Dévié s'allume
    etatLeds[2] = 0; // la led3 Aiguillage2 Droit s'éteint
    validationBPdevie2 = false; // les déclenchements par BPdevie2 sont bloqués
    validationBPdroit2 = true; // seule une action sur BPdroit2 est autorisée
  } // fin if
} // fin loop


void efface_tout() {
  pinMode(BrocheA, INPUT); // on met les 3 broches de commande en haute impédance
  pinMode(BrocheB, INPUT);
  pinMode(BrocheC, INPUT);
} // fin efface_tout


void reglage_led(byte numeroLed) { // pour chaque led devant s'allumer on précise uniquement les broches impliquées
  switch (numeroLed)  {
    case 1: // led1 Aiguillage1 Droit
      reglage_broches(BrocheA, BrocheB); // A+ B-
      break;

    case 2: // led2 Aiguillage1 Dévié
      reglage_broches(BrocheB, BrocheA); // B+ A-
      break;

    case 3: // led3 Aiguillage2 Droit
      reglage_broches(BrocheB, BrocheC); // B+ C-
      break;

    case 4: // led4 Aiguillage2 Dévié
      reglage_broches(BrocheC, BrocheB); // C+ B-
      break;

    default:
      break;
  } // fin switch case
} // fin reglage_led


void reglage_broches(byte anode, byte cathode) { // on fixe le niveau des broches impliquées
  efface_tout();  // on éteint les leds, donc il restera systématiquement une broche en haute impédance
  pinMode(anode, OUTPUT); // la broche qui envoie du +5V
  digitalWrite(anode, HIGH);
  pinMode(cathode, OUTPUT);// la broche qui est à la masse
  digitalWrite(cathode, LOW);
} // fin reglage_broches