/*! \file cesi1.ino
        \brief Premier TD pour le CESI.
        \author Bertrand Vandeportaele IUT GEII
        \date  28/10/2021
    */ 
    #include "lib_io_tp.h"
    /** Variable globale indiquant la broche Arduino connectée à la LED */
    const unsigned int LEDPIN=3;
    /** Variable globale indiquant la broche Arduino connectée au bouton poussoir */
    const unsigned int BUTTONPIN=2;
    /** Variable globale permettant de stocker la dernière valeur écrite sur le 
        port de sortie, pour pouvoir en modifier uniquement certains bits */
    unsigned char imageSortie=0;   
    //-------------------------------------------------------------------
    //prototypes de toutes les fonctions de ce fichier
    void exo1();
    void exo2();
    void exo3();
    void exo4();
    void exo5();
    void exo6();
    void exo7();
    void exo8();
    void exo9();
    void exo10();
    void exo11();
    void exo12();
    void exo13();
    void tache1();
    void tache2();
    //-------------------------------------------------------------------
    /*! \fn void setup()
        \brief Initialisation des périphériques et des variables globales
    */
    void setup() {
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
    SetupES();
    Serial.begin(115200);
    pinMode(BUTTONPIN, INPUT_PULLUP);
    pinMode(LEDPIN, OUTPUT);
    digitalWrite(LEDPIN, LOW);
    //A0 configurée en analogique par défaut
    }
//-------------------------------------------------------------------    
//-------------------------------------------------------------------
/*!
 * \fn void loop()
 * \brief La fonction loop doit appeler une seule fonction exo... à la 
 * fois, vous devez conserver le code de tous les exercices mais n'en 
 * utiliser qu'un à la fois
*/
    void loop() {
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
    exo12();
    }
    //-------------------------------------------------------------------
/*!
 * \fn void exo1()
 * \brief Exercice 1:
 * Vous devez piloter le port de sortie en recopiant l'état du port 
 * entrée et afficher sur la console série en héxadécimal la valeur lue 
 * sur le port d'entrée
 * Utilisez les fonctions void SetupES(void); unsigned char readPort(void); 
 * et void writePort(unsigned char value); de lib_io_tp.h
 * Configurez et utiliser l'interface de communication Série/USB
 * https://www.arduino.cc/reference/en/language/functions/communication/serial
 * https://www.arduino.cc/reference/en/language/functions/communication/serial/print/
 * https://www.arduino.cc/reference/en/language/functions/communication/serial/println/
*/
    void exo1(){
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
    unsigned char memo;
    memo=readPort();
    writePort(memo);
    
    Serial.println(memo,HEX);
    }
    //-------------------------------------------------------------------
    /*!
     * \fn void exo2()
     * \brief Exercice 2:
     * Vous devez piloter le port de sortie en recopiant l'entrée 7 sur la 
     * sortie dont le numéro est défini par entree(2..0)
    */
    void exo2(){
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
      unsigned char entree;
      entree=readPort();
      unsigned char e7=(entree>>7)&1;
      unsigned char e20=entree&7;
      unsigned char sortie= e7<<e20;
    
    writePort(sortie);
    }
    //-------------------------------------------------------------------
    /*!
     * \fn void exo3()
     * \brief Exercice 3:
     * Vous devez piloter le port de sortie pour réaliser le transcodage de la 
     * valeur 4 bits lues sur entrée(3..0) vers les 7 bits du port de sortie 
     * (6..0) en utilisant le     tableau tab fourni,
     * puis ajouter le pilotage de la sortie 7 avec l'entrée 7
    */
    void exo3(){
      byte tab[]={0x3f,0x06,0x5b,0x4F,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
     unsigned char entree;
    entree=readPort();
      unsigned char e7=(entree>>7)&1;
      unsigned char e30=entree&0B1111;
      unsigned char sortie= tab[e30] | (e7 <<7);
    
    writePort(sortie);
    }
    //-------------------------------------------------------------------
    /*!
     * \fn void exo4()
     * \brief Exercice 4:
     * Vous devez configurer les entrées sorties numériques de l'arduino numéro 
     * BUTTONPIN et LEDPIN, puis effectuer la recopie de l'entrée BUTTONPIN sur la 
     * sortie LEDPIN en boucle.  
     * https://www.arduino.cc/reference/en/language/functions/digital-io/pinMode/
     * https://www.arduino.cc/reference/en/language/functions/digital-io/digitalread/
     * https://www.arduino.cc/reference/en/language/functions/digital-io/digitalwrite/
    */
    void exo4(){
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
    unsigned char val=digitalRead(BUTTONPIN);
    //delay(100);
    digitalWrite(LEDPIN,val );
    }
    //-------------------------------------------------------------------
    /*!
     * \fn void exo5()
     * \brief Exercice 5:
     * Vous devez configurer l'entrée analogique A0  puis effectuer la commande du 
     * port de sortie pour qu'une seule LED s'allume à la position approximative du 
     * potentiomètre.
     * https://www.arduino.cc/reference/en/language/functions/analog-io/analogRead/
    */
    void exo5(){
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
    uint16_t pos=analogRead(A0);
    uint16_t numeroled=pos>>7;
    numeroled=7-numeroled;
    uint8_t valsortie=1<<numeroled;
    writePort(valsortie);
    }
    //-------------------------------------------------------------------
    /*!
     * \fn void exo6()
     * \brief Exercice 6:
     * Vous devez configurer l'entrée analogique A0  puis effectuer la commande de 
     * la LED connecté à la sortie LEDPIN afin qu'elle clignote à une fréquence 
     * pilotée par le potentiomètre. La commande de la durée des états hauts et bas 
     * de la sortie LEDPIN sera gérée à l'aide d'une fonction d'attente bloquante delay: 
     * https://www.arduino.cc/reference/en/language/functions/time/delay/
    */
    void exo6(){
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
/*      uint16_t pos=analogRead(A0);
     digitalWrite(LEDPIN,1);
     delay(pos);
     digitalWrite(LEDPIN,0);
     delay(pos);
  */ 
    static   unsigned char etat=0;
       uint16_t pos=analogRead(A0);
     digitalWrite(LEDPIN,etat);
     delay(pos);
     //etat=(etat+1)%2;
     etat=etat^1;
  
     /*if (etat==0)
     etat=1;
     else 
     etat=0;
*/
    }
    //-------------------------------------------------------------------
    /*!
     * \fn void exo7()
     * \brief Exercice 7:
     * Vous devez configurer l'entrée analogique A0  puis effectuer la commande de 
     * la LED connecté à la sortie LEDPIN afin qu'elle clignote avec un rapport cyclique 
     * piloté par le potentiomètre. La commande de la durée des états hauts et bas de 
     * la sortie LEDPIN sera cette fois ci gérée à l'aide d'une sortie PWM (la broche 
     * LEDPIN est compatible PWM) à l'aide de la fonction analogWrite() : 
     * https://www.arduino.cc/reference/en/language/functions/analog-io/analogWrite/
    */
    void exo7(){
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
    analogWrite(LEDPIN, analogRead(A0)>>2);
    }
    //-------------------------------------------------------------------
    /*!
     * \fn void exo8()
     * \brief Exercice 8:
     * Vous devez combiner les exercices 1 et 6 en utilisant une durée de 2 secondes 
     * pour les états hauts et bas du signal pilotant la sortie LEDPIN. Faire en sorte 
     * que la fonction génère une demi période du signal carré. Constatez si 
     * le port de sortie est mis à jour instantanément lorsque le port d'entrée est 
     * modifié.
    */
    void exo8(){
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
    exo1();
    exo6();
    }
    //-------------------------------------------------------------------
    /*!
     * \fn void exo9()
     * \brief Exercice 9:
     * Vous devez modifier l'exercice 8 pour faire en sorte que la recopie du port 
     * d'entrée se fasse sur le port de sortie en permanence. Pour cela utiliser une 
     * fonction non bloquante pour gérer la temporisation à l'aide d'un timer par 
     * scrutation: 
     * https://www.arduino.cc/reference/en/language/functions/time/millis/
    */
    void exo9(){
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
    if (true){
      unsigned char memo;
      memo=readPort();
      writePort(memo);
      }
    
      uint16_t   periodicite=2000;
    static uint32_t   timer=millis();
    
    if (millis()-timer>=periodicite){
     timer=timer+periodicite; //attention bug au bout de 50 jours
     static   unsigned char etat=0;
     digitalWrite(LEDPIN,etat);
     etat=etat^1;
    }
    }
    //-------------------------------------------------------------------
    /*!
     * \fn void exo10()
     * \brief Exercice 10:
     * Découverte du pseudo parallélisme: Dans un premier temps exo10 appelle juste 
     * la fonction tache1() puis réalise une attente bloquante de 500ms.
    */
    void exo10(){
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
    
    tache1();
    delay(500);
    }
    //-------------------------------------------------------------------
    /*!
     * \fn void tache1()
     * \brief tache1:
     * Découverte du pseudo parallélisme: la tache 1 consiste à réaliser un compteur 
     * sur 4 bits sur les bits (3..0) du port de sortie. La valeur maximale prise par 
     * ce compteur est réglé par les bits (3..0) du port d'entrée. "t1" doit être 
     * affiché dans la console série.
    */
    void tache1(){
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
    
    uint8_t max=readPort()&0xF;
    static uint8_t compteur=0;
    compteur=(compteur+1)%(max+1);
    imageSortie= (imageSortie& 0xF0) | (compteur & 0x0F);
    writePort(imageSortie);
    Serial.println("t1");
    }
    //-------------------------------------------------------------------
    /*!
     * \fn void exo11()
     * \brief Exercice 11:
     * Découverte du pseudo parallélisme: Dans un second temps exo11 appelle les 
     * fonctions tache1() et  tache2() puis réalise une attente bloquante de 500ms.
    */
    void exo11(){
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
    
    tache1();
    tache2();
    delay(500);
    }
    //-------------------------------------------------------------------
    /*!
     * \fn void tache2()
     * \brief tache2:
     * Découverte du pseudo parallélisme: la tache 2 consiste à réaliser un 
     * chenillard sur 4 bits sur les bits (7..4) du port de sortie. 4 séquences 
     * différentes sont définies dans les tableaux tab1 à 4 fournis. Le choix de 
     * la séquence utilisée est réalisé à l'aide des bits d'entrées (6..5). Si le 
     * bit d'entrée 4 est à 0 alors la séquence est mise en pause. "t2" doit être 
     * affiché dans la console série.
    */
    void tache2(){
    byte tab1[]={0x1,0x2,0x4,0x8,0x4,0x2};
    byte tab2[]={0x1,0x3,0x7,0xf,0x7,0x3};
    byte tab3[]={0x8,0xC,0xE,0xf,0xC,0x8};
    byte tab4[]={0x8,0x1,0x4,0x2,0x1,0x4};
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
    uint8_t max=5;
    static uint8_t compteur=0;
     
    uint8_t entree=readPort();
    uint8_t en= (entree>>4) &1;
    uint8_t choixseq= (entree>>5) &3;
    compteur=(compteur+en)%(max+1);
    
    byte * tabtab[4]={tab1,tab2,tab3,tab4};
    imageSortie= (imageSortie& 0x0F) | (tabtab[choixseq][compteur]<<4);
        
    /*
    switch(choixseq){
      case 0:
        imageSortie= (imageSortie& 0x0F) | (tab1[compteur]<<4);
        break;
      case 1:
        imageSortie= (imageSortie& 0x0F) | (tab2[compteur]<<4);
        break;
      ....
      
          }
          */
    //imageSortie= (imageSortie& 0x0F) | (tab[compteur]<<4);
    writePort(imageSortie);
    Serial.println("t2");
    }
    //-------------------------------------------------------------------
    /*!
     * \fn void exo12()
     * \brief Exercice 12:
     * Découverte du pseudo parallélisme: la tache1 doit être réalisée toutes les 
     * 500ms et la tache2 doit être réalisée toutes les Nms, N étant la valeur sur 
     * 10bits lue sur l'entrée analogique 0.
    */
    void exo12(){
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------
    
    uint16_t   periodiciteTache1=500;
    static uint32_t   timerTache1=millis();
    if (millis()-timerTache1>=periodiciteTache1){
     timerTache1=timerTache1+periodiciteTache1; 
      tache1();
    }
    uint16_t   periodiciteTache2=analogRead(A0);
    static uint32_t   timerTache2=millis();
    if (millis()-timerTache2>=periodiciteTache2){
     timerTache2=timerTache2+periodiciteTache2; 
      tache2();
    }
 
    }
    //-------------------------------------------------------------------
    /*!
     * \fn void exo13()
     * \brief Exercice 13:
     * Gestion d'une interruption matérielle: ajouter à l'exo12 la commande de la 
     * commutation de la LED connectée à LEDPIN par l'appui sur le bouton poussoir 
     * connecté à BUTTONPIN. Pour cela vous utiliserez une interruption sur front sur un broche. 
     * La liste des vecteurs d'interruption est visible en page 49 de  
     * https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf 
     * vous utiliserez external interrupt en page 53, BUTTONPIN doit être égal à 2 
     * car c'est uniquement cette broche qui peut déclencher cette interruption.
    */
    void exo13(){
    exo12();
    }
    //-------------------------------------------------------------------
    //            CODE A COMPLETER PAR LES ETUDIANTS
    //-------------------------------------------------------------------