////////////////////////////////////////////////////////////////////
    class CStateMachineRotary //déclaration de la classe
    {
    public:            //membres accessibles depuis l'extérieur de la classe, il s'agit de l'interface d'interaction de la classe
      CStateMachineRotary(int brocheAinit, int brocheBinit); //Constructeur avec paramètres pour régler les 2 broches Arduino utilisées
      void clock();    //méthode pour cadencer la machine à état (faire 1 coup d'horloge)
      int getPosition()//méthode accesseur pour accéder à l'attribut privé position
    	{ return position;} //on parle de méthode inlinée car l'implémentation est faite dans la déclaration de la classe
     
    private:        //membres privés pour réaliser l'encapsulation: ces attributs sont inacessibles directement depuis l'extérieur de la classe
      byte etat;    //numéro de l'état actif
      byte entreeA; //valeur lue sur l'entrée A
      byte entreeB; //valeur lue sur l'entrée B
      int brocheA;  //numéro de broche Arduino utilisée pour l'entrée A
      int brocheB;  //numéro de broche Arduino utilisée pour l'entrée B
      virtual void frontDetecte(){}; //methode abstraite, sera implémentée dans la classe fille
      virtual void actionSurTousLesEtats(){}; //methode abstraite, sera implémentée dans la classe fille
    protected:      //ces membres peuvent être accédés dans les classes filles
      int position; //position angulaire mesurée    
    };  //ne pas oublier le ;
    ////////////////////////////////////////////////////////////////////
    //Implémentation de la méthode constructeur
    CStateMachineRotary::CStateMachineRotary(int brocheAinit, int brocheBinit){
    // à compléter
		//configurer et initialiser ce qui doit l'être
 etat=0;
 brocheA=brocheAinit;
 brocheB=brocheBinit;
 pinMode(brocheA, INPUT_PULLUP);
 pinMode(brocheB, INPUT_PULLUP); 
 entreeA=digitalRead(brocheA);
 entreeB=digitalRead(brocheB); 
 position=0;
    }
    //Implémentation de la méthode clock
    void CStateMachineRotary::clock(){
    // à compléter
		//lecture et mémorisation des entrées
  entreeA=digitalRead(brocheA);
  entreeB=digitalRead(brocheB);
//actions sur transition
if ((etat==0) && (entreeA==1)){
  position++;
	frontDetecte();
  }
  if ((etat==1) && (entreeA==0)){	
  position--;
	frontDetecte();
  }
//évolution de l'état
 switch (etat){
	case 0: if  (entreeA==1) 
			etat=1;
		else if  (entreeB==1) 
			etat=3;
		break;
	case 1: if  (entreeB==1) 
			etat=2;
		else if  (entreeA==0) 
			etat=0;
		break;
	case 2: if  (entreeA==0) 
			etat=3;
		else if  (entreeB==0) 
			etat=1;
		break;
	default:
	case 3: if  (entreeB==0) 
			etat=0;
    else if  (entreeA==1) 
			etat=2;		
		break;
}
//actions sur état
actionSurTousLesEtats();
//Serial.println(etat);
    }



    ////////////////////////////////////////////////////////////////////
    class CStateMachineRotaryWithSpeed: public CStateMachineRotary
    {
    public:
      CStateMachineRotaryWithSpeed(int brocheAinit, int brocheBinit);
      float getSpeed(); //méthode accesseur pour accéder à l'attribut privé speed
     
    private:
		  void actionSurTousLesEtats(){};
      float speed;  //vitesse mesurée
      unsigned long lastPulseTime; //horodatage du dernier front
      void frontDetecte(); //implémentation pour effectuer des traitements lorsqu'un front est detecté
    };
    ////////////////////////////////////////////////////////////////////
    //Implémentation du constructeur de la classe fille, exécutée après avoir exécuté le constructeur de la classe mère
    CStateMachineRotaryWithSpeed::CStateMachineRotaryWithSpeed(int brocheAinit, int brocheBinit): CStateMachineRotary(brocheAinit, brocheBinit){
     lastPulseTime=micros(); //initialisation de la date initiale pour l'horodatage des fronts
     speed=0; //initialise vitesse nulle au démarrage. Attention, en simu, l'encodeur génère des fronts parasites
    }  
    ////////////////////////////////////////////////////////////////////
    //implémentation de la méthode frontDetecte() qui n'était pas implémentée dans la classe mère
    void CStateMachineRotaryWithSpeed::frontDetecte()
    {
      // à compléter
     unsigned long newPulseTime=micros();
		 speed=1000000/(newPulseTime-lastPulseTime);
		 lastPulseTime=newPulseTime;
     }







    //implémentation de la mesure de vitesse
    float CStateMachineRotaryWithSpeed::getSpeed(){
      //à faire: calculer la vitesse et l'affecter à l'attribut speed
     unsigned long newPulseTime=micros();
		 if ((newPulseTime-lastPulseTime)>=2000000)
		 speed=0;

			return speed;
    }


////////////////////////////////////////////////////////////////////
class CStateMachineRotaryWithSpeedWithReset: public CStateMachineRotaryWithSpeed
{
public:
  CStateMachineRotaryWithSpeedWithReset(int brocheAinit, int brocheBinit,int brocheCinit);
  
private:
  void actionSurTousLesEtats();
  int brocheC;
};
////////////////////////////////////////////////////////////////////
CStateMachineRotaryWithSpeedWithReset::CStateMachineRotaryWithSpeedWithReset(int brocheAinit, int brocheBinit,int brocheCinit) : CStateMachineRotaryWithSpeed( brocheAinit,  brocheBinit) 
{
brocheC=brocheCinit;
pinMode(brocheC, INPUT);
}
void CStateMachineRotaryWithSpeedWithReset::actionSurTousLesEtats(){
if (digitalRead(brocheC)==1)
   position=0;
	 }



CStateMachineRotary encoder1(A4,A5);

CStateMachineRotaryWithSpeedWithReset encoder2(A0,A1,A2); 

void setup() {
Serial.begin(115200);

}

void loop() {
	encoder1.clock();
	encoder2.clock();

//affichage de la valeur mesurée 10 fois par seconde
unsigned int periodiciteTache1=100;
static unsigned long timerTache1 = millis();
if (millis() - timerTache1 >= periodiciteTache1) {
    timerTache1 += periodiciteTache1;

    Serial.print(encoder1.getPosition());
		Serial.print("  ");
		Serial.print(encoder2.getPosition());
		Serial.print("  ");
		Serial.println(encoder2.getSpeed());

}

}
D0D1D2D3D4D5D6D7GNDLOGIC