/*! \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;   
//-------------------------------------------------------------------
/*! \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(LEDPIN, OUTPUT);
pinMode(BUTTONPIN, INPUT_PULLUP);
setupINT0();
}
//-------------------------------------------------------------------
/*!
 * \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
//-------------------------------------------------------------------
exo13();
}
//-------------------------------------------------------------------
/*!
 * \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 val;
val=readPort();
writePort(val);
if (val<0x10)
  Serial.print(0);
Serial.println(val,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 val;
val=readPort();
unsigned char e20=val& 0B00000111;
unsigned char e7=(val>>7) & 0x1;
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 val;
val=readPort();

unsigned char e30=val& 0B00001111;
writePort(tab[e30]);
}
//-------------------------------------------------------------------
/*!
 * \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
//-------------------------------------------------------------------
    digitalWrite(LEDPIN,digitalRead(BUTTONPIN));
}
//-------------------------------------------------------------------
/*!
 * \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
//-------------------------------------------------------------------
    unsigned char val=(analogRead(A0)>>7)&0x7;
    Serial.println(val);
    //writePort(1<<(7-val));
    unsigned char tab[]={0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1};
    writePort(tab[val]);
}
//-------------------------------------------------------------------
/*!
 * \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
//-------------------------------------------------------------------
    unsigned int val=analogRead(A0);
    /*digitalWrite(LEDPIN,0);
    delay(val);
    digitalWrite(LEDPIN,1);
    delay(val);
    */
    static char etat=0;
    digitalWrite(LEDPIN,etat);
    //etat=(etat+1)%2;
    etat=etat^1;
    delay(val);

}
//-------------------------------------------------------------------
/*!
 * \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
//-------------------------------------------------------------------
 int val = analogRead(A0);  // read the input pin
// analogWrite(LEDPIN, val / 4); // analogRead values go from 0 to 1023, analogWrite values from 0 to 255
 analogWrite(LEDPIN, val >>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
//-------------------------------------------------------------------
unsigned char val;
val=readPort();
writePort(val);
if (val<0x10)
  Serial.print(0);
Serial.println(val,HEX);

static char etat=0;
    digitalWrite(LEDPIN,etat);
    //etat=(etat+1)%2;
    etat=etat^1;
    delay(2000);
}
//-------------------------------------------------------------------
/*!
 * \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
//-------------------------------------------------------------------
unsigned char val;
val=readPort();
writePort(val);
if (val<0x10)
  Serial.print(0);
Serial.println(val,HEX);

static char etat=0;
 
 static unsigned long int timer=millis();
 unsigned int periodicite=2000;

 if (millis()-timer>=periodicite) 
    {
    //timer=millis(); //cumule les retards
    timer=timer+periodicite; //ne cumule pas les retards
    
    digitalWrite(LEDPIN,etat);
    //etat=(etat+1)%2;
    etat=etat^1;
   // delay(2000);
    }
}

//-------------------------------------------------------------------
/*!
 * \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
//-------------------------------------------------------------------
static unsigned char compteur=0;

unsigned char entree= readPort()&0B1111;
compteur=(compteur+1);
if (compteur>=entree+1)
  compteur=0;
  
imageSortie=imageSortie&0B11110000; //faire la place
imageSortie=imageSortie | (compteur&0B1111); //injecter la donnée
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
//-------------------------------------------------------------------
static unsigned char compteur=0;

unsigned char entree= readPort();
unsigned char e4=(entree>>4)&0B00000001;
unsigned char e65=(entree>>5)&0B00000011;

if (e4==1)
  compteur=(compteur+1)%6;


  
imageSortie=imageSortie&0B00001111; //faire la place
/*
if (e65==0)
  imageSortie=imageSortie | (tab1[compteur]<<4); //injecter la donnée
else if (e65==1)
  imageSortie=imageSortie | (tab2[compteur]<<4); //injecter la donnée
else if (e65==2)
  imageSortie=imageSortie | (tab3[compteur]<<4); //injecter la donnée
else //if (e65==3)
  imageSortie=imageSortie | (tab4[compteur]<<4); //injecter la donnée

switch(e65){
  case 0:   imageSortie=imageSortie | (tab1[compteur]<<4); //injecter la donnée
            break;
  case 1:   imageSortie=imageSortie | (tab2[compteur]<<4); //injecter la donnée
            break;
  case 2:   imageSortie=imageSortie | (tab3[compteur]<<4); //injecter la donnée
            break;
  default:  imageSortie=imageSortie | (tab4[compteur]<<4); //injecter la donnée
            break;
}*/
byte *tabtab[4]={tab1,tab2,tab3,tab4};
 imageSortie=imageSortie | (tabtab[e65][compteur]<<4); //injecter la donnée
           

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
//-------------------------------------------------------------------

 static unsigned long int timerTache1=millis();
 unsigned int periodiciteTache1=500;
 if (millis()-timerTache1>=periodiciteTache1) 
    { 
    timerTache1=timerTache1+periodiciteTache1; //ne cumule pas les retards
    tache1();
    }
 static unsigned long int timerTache2=millis();
 unsigned int periodiciteTache2=analogRead(A0);
 if (millis()-timerTache2>=periodiciteTache2) 
    { 
    timerTache2=timerTache2+periodiciteTache2; //ne cumule pas les retards
    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
//-------------------------------------------------------------------
    //-------------------------------------------------------------------
    /*!
     * \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.
    */
    
    //Début solution
    void setupINT0(){
      pinMode(LEDPIN, OUTPUT);
      digitalWrite(LEDPIN,HIGH);
      pinMode(BUTTONPIN, INPUT_PULLUP);
      cli();           // disable all interrupts
      EICRA= (EICRA&0xFC) |2; //ICS0 = 10 pour front descendant
      EIMSK= EIMSK|1; //enable INT0
      sei();             // enable all interrupts
    }
    //-------------------------------------------------------------------
    /* PROBLEME IL Y A LES REBONDS SUR LE POUSSOIR.... anti rebond par logiciel  
     * en inhibant les interruptions après la première pendant un certain temps
      */
    ISR(INT0_vect) {
      unsigned int minTempsEntreIT0=300;
      static unsigned long timerIT0 = millis();
      static unsigned char counter=0;
      unsigned long timeActuel=millis();
      if ( timeActuel - timerIT0 >= minTempsEntreIT0) {
        timerIT0=timeActuel;
        if (counter==0)  
          digitalWrite(LEDPIN,LOW); //allume
        else
          digitalWrite(LEDPIN,HIGH); //eteind
        counter = (counter+1)%2;
        Serial.println("it");
        } 
    }
    ////autre exo à envisager: désactivation dans l'it puis réactivation dans loop via timer partagé
    //-------------------------------------------------------------------
    //temporisation avec interruption timer -> sera vu au tp suivant sur afficheur 7 segments
    //-------------------------------------------------------------------
    //Fin solution

uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
74HC165
sr1:PL
sr1:CP
sr1:D4
sr1:D5
sr1:D6
sr1:D7
sr1:Q7_N
sr1:GND
sr1:Q7
sr1:DS
sr1:D0
sr1:D1
sr1:D2
sr1:D3
sr1:CE
sr1:VCC
sw8:1
sw8:2
sw8:3
sw7:1
sw7:2
sw7:3
sw6:1
sw6:2
sw6:3
sw5:1
sw5:2
sw5:3
sw4:1
sw4:2
sw4:3
sw3:1
sw3:2
sw3:3
sw2:1
sw2:2
sw2:3
sw1:1
sw1:2
sw1:3
74HC595
sr2:Q1
sr2:Q2
sr2:Q3
sr2:Q4
sr2:Q5
sr2:Q6
sr2:Q7
sr2:GND
sr2:Q7S
sr2:MR
sr2:SHCP
sr2:STCP
sr2:OE
sr2:DS
sr2:Q0
sr2:VCC
led1:A
led1:C
led2:A
led2:C
led3:A
led3:C
led4:A
led4:C
led5:A
led5:C
led6:A
led6:C
led7:A
led7:C
led8:A
led8:C
led9:A
led9:C
pot1:VCC
pot1:SIG
pot1:GND
r1:1
r1:2
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
sevseg1:COM.1
sevseg1:COM.2
sevseg1:A
sevseg1:B
sevseg1:C
sevseg1:D
sevseg1:E
sevseg1:F
sevseg1:G
sevseg1:DP
D0D1D2D3D4D5D6D7GNDLOGIC
logic1:D0
logic1:D1
logic1:D2
logic1:D3
logic1:D4
logic1:D5
logic1:D6
logic1:D7
logic1:GND