Cours:DevoirPOO2 classes : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
m
Ligne 213 : Ligne 213 :
 
|}
 
|}
  
{|style="vertical-align:middle; width:100%; text-align:left; "
 
|-
 
| {{boîte déroulante/début|titre=[[Media:pwm.h|pwm.h]]}}
 
<source lang=cpp>
 
#ifndef PWM_H
 
#define PWM_H
 
#include "rpiperipherique.h"
 
 
class Pwm : public RpiPeripherique
 
{
 
private:
 
    unsigned int mRange=0;
 
    unsigned int regPWM_RNG; // Clock controller
 
    unsigned int regPWM_DAT; // Clock controller
 
 
public:
 
    Pwm(unsigned int pwmNumber);
 
    void setRange(unsigned int rng);
 
    void setRapportCyclique(unsigned int rapport);
 
};
 
 
#endif // PWM_H
 
</source>
 
{{boîte déroulante/fin}}
 
||{{boîte déroulante/début|titre=[[Media:pwm.cpp|pwm.cpp]]}}
 
<source lang=cpp>
 
#include "pwm.h"
 
#include <iostream>
 
#include <unistd.h>
 
using namespace std;
 
 
#define PWM_CTL_PWM0 0
 
#define PWM_CTL_PWM1 8
 
#define GPIO_FSEL12 6
 
#define GPIO_FSEL13 9
 
 
#define PWM_MODE_NORMAL 0x1
 
 
 
const unsigned int regGPIO_FSEL = 0x200004; // Clock controller
 
const unsigned int regPWM_CTL  = 0x20C000; // Clock controller
 
const unsigned int regPWM_RNG0  = 0x20C010; // Clock controller
 
const unsigned int regPWM_DAT0  = 0x20C014; // Clock controller
 
const unsigned int regPWM_RNG1  = 0x20C020; // Clock controller
 
const unsigned int regPWM_DAT1  = 0x20C024; // Clock controller
 
 
 
Pwm::Pwm(unsigned int pwmNumber):RpiPeripherique()
 
{
 
 
    int offset,offsetGPIO;
 
    if (pwmNumber>1)
 
    {
 
        cout << "le numéro de PWM doit être 0 ou 1 !"<<endl;
 
        exit(-1);
 
    }
 
    if (pwmNumber==0)
 
    {
 
        cout <<"pwm0"<<endl;
 
        regPWM_RNG = regPWM_RNG0;
 
        regPWM_DAT = regPWM_DAT0;
 
        offset = PWM_CTL_PWM0;
 
        offsetGPIO = GPIO_FSEL12;
 
    }
 
    else
 
    {
 
        cout <<"pwm1"<<endl;
 
        regPWM_RNG = regPWM_RNG1;
 
        regPWM_DAT = regPWM_DAT1;
 
        offset = PWM_CTL_PWM1;
 
        offsetGPIO = GPIO_FSEL13;
 
    }
 
    regClearBits(regPWM_CTL,0xff,offset);
 
    regClearBits(regGPIO_FSEL,0x7,offsetGPIO);
 
    regSetBits(regGPIO_FSEL,0x4,offsetGPIO);
 
    usleep(110);
 
    regSetBits(regPWM_CTL,PWM_MODE_NORMAL,offset);
 
 
}
 
 
void Pwm::setRange(unsigned int rng)
 
{
 
    mRange = rng;
 
    regWrite(regPWM_RNG,rng);
 
    setRapportCyclique(0);
 
}
 
 
void Pwm::setRapportCyclique(unsigned int rapport)
 
{
 
    if (rapport >= mRange)
 
    {
 
        cout << "rapport cyclique non adapté !"<<mRange<<" "<<rapport<<endl;
 
        exit(-1);
 
    }
 
    regWrite(regPWM_DAT,rapport);
 
}
 
</source>
 
{{boîte déroulante/fin}}
 
|}
 
 
{|style="vertical-align:middle; width:100%; text-align:left; "
 
|-
 
| {{boîte déroulante/début|titre=[[Media:pwmclk.h|pwmclk.h]]}}
 
<source lang=cpp>
 
#ifndef PWMCLK_H
 
#define PWMCLK_H
 
 
#include "rpiperipherique.h"
 
/*
 
0    0 Hz    Ground
 
1    19.2 MHz oscillator
 
2    0 Hz    testdebug0
 
3    0 Hz    testdebug1
 
4    0 Hz    PLLA
 
5    1000 MHz PLLC (changes with overclock settings)
 
6    500 MHz  PLLD
 
7    216 MHz  HDMI auxiliary
 
8-15  0 Hz    Ground
 
*/
 
 
class PwmClk : public RpiPeripherique
 
{
 
private:
 
    void regSetBitsWithPassword(unsigned int reg, unsigned int val,unsigned int offset);
 
    void regClearBitsWithPassword(unsigned int reg, unsigned int val,unsigned int offset);
 
public:
 
    PwmClk();
 
    void setPwmClkDiv(unsigned int prediv);
 
};
 
 
#endif // PWMCLK_H
 
</source>
 
{{boîte déroulante/fin}}
 
||{{boîte déroulante/début|titre=[[Media:pwmclk.cpp|pwmclk.cpp]]}}
 
<source lang=cpp>
 
#include "pwmclk.h"
 
#include <unistd.h>
 
#include <stdio.h>
 
#include <stdlib.h>
 
#include <limits.h>
 
#include <iostream>
 
using namespace std;
 
 
#define CM_PWMCTL_SRV 0
 
#define CM_PWMCTL_ENAB 4
 
#define CM_PWMCTL_KILL 5
 
#define CM_PWMCTL_BUSY 7
 
#define CM_PWMCTL_FLIP 8
 
#define CM_PWMCTL_MASH 9
 
#define CM_PWMCTL_PASSWORD 24
 
 
#define CM_PWMDIV_DIVF 0
 
#define CM_PWMDIV_DIVI 12
 
 
#define PWMCLK_PASSWORD 0x5a
 
 
const unsigned int regCM_PWMCTL  = 0x1010a0; // Clock controller
 
const unsigned int regCM_PWMDIV  = 0x1010a4; // Clock controller
 
 
 
PwmClk::PwmClk():RpiPeripherique()
 
{
 
    cout << "Horloge par défaut : clk1 19.2M"<<endl;
 
    cout << "MASH = 0 : % entiere"<<endl;
 
 
    cout << "Arret de l'horloge PWM ..."<<endl;
 
    regClearBitsWithPassword(regCM_PWMCTL,1,CM_PWMCTL_ENAB);
 
    while (regRead(regCM_PWMCTL)&(1<<CM_PWMCTL_BUSY));
 
    cout <<"ok"<<endl;
 
 
 
    regSetBitsWithPassword(regCM_PWMCTL,1,CM_PWMCTL_SRV);
 
    regClearBitsWithPassword(regCM_PWMCTL,3,CM_PWMCTL_MASH);
 
}
 
 
void PwmClk::regSetBitsWithPassword(unsigned int reg, unsigned int val, unsigned int offset)
 
{
 
    unsigned int regVal = regRead(reg);
 
    regVal |= (val<<offset)|(PWMCLK_PASSWORD<<CM_PWMCTL_PASSWORD);
 
    regWrite(reg,regVal);
 
}
 
 
void PwmClk::regClearBitsWithPassword(unsigned int reg, unsigned int val, unsigned int offset)
 
{
 
    unsigned int regVal = regRead(reg);
 
    regVal &=~(val<<offset);
 
    regVal |= PWMCLK_PASSWORD<<CM_PWMCTL_PASSWORD;
 
    regWrite(reg,regVal);
 
}
 
 
 
void PwmClk::setPwmClkDiv(unsigned int prediv)
 
{
 
    if (prediv > 0xfff)
 
    {
 
        cout <<"prediviseur trop grand !!"<<endl;
 
        exit(-1);
 
    }
 
 
    cout << "Arret de l'horloge PWM ..."<<endl;
 
    regClearBitsWithPassword(regCM_PWMCTL,1,CM_PWMCTL_ENAB);
 
    while (regRead(regCM_PWMCTL)&(1<<CM_PWMCTL_BUSY));
 
    cout <<"ok"<<endl;
 
 
 
    regClearBitsWithPassword(regCM_PWMDIV,0xfff,CM_PWMDIV_DIVI);
 
    regSetBitsWithPassword(regCM_PWMDIV,prediv,CM_PWMDIV_DIVI);
 
    cout <<"Démarrage de l'horloge PWM ..."<<endl;
 
    regSetBitsWithPassword(regCM_PWMCTL,1,CM_PWMCTL_ENAB);
 
    while ( (regRead(regCM_PWMCTL)&(1<<CM_PWMCTL_BUSY)) == 0);
 
    cout << "ok !"<<endl;
 
}
 
</source>
 
{{boîte déroulante/fin}}
 
|}
 
 
{|style="vertical-align:middle; width:100%; text-align:left; "
 
|-
 
| {{boîte déroulante/début|titre=[[Media:rpiperipherique.h|rpiperipherique.h]]}}
 
<source lang=cpp>
 
#ifndef RPIPERIPHERIQUE_H
 
#define RPIPERIPHERIQUE_H
 
 
#include <cstdint>
 
 
class RpiPeripherique
 
{
 
private:
 
    int mBaseAdress = 0;
 
    unsigned int *memMap;
 
 
 
public:
 
    RpiPeripherique();
 
protected :
 
    void regWrite(unsigned int reg, unsigned int val);
 
    void regSetBits(unsigned int reg, unsigned int val,unsigned int offset);
 
    void regClearBits(unsigned int reg, unsigned int val,unsigned int offset);
 
    unsigned int regRead(unsigned int reg);
 
};
 
 
#endif // RPIPERIPHERIQUE_H
 
</source>
 
{{boîte déroulante/fin}}
 
||{{boîte déroulante/début|titre=[[Media:rpiperipherique.cpp|rpiperipherique.cpp]]}}
 
<source lang=cpp>
 
#include "rpiperipherique.h"
 
#include <stdio.h>
 
#include <stdlib.h>
 
#include <limits.h>
 
#include <unistd.h>
 
#include <sys/mman.h>
 
#include <sys/types.h>
 
#include <sys/stat.h>
 
#include <fcntl.h>
 
#include <iostream>
 
using namespace std;
 
 
RpiPeripherique::RpiPeripherique()
 
{
 
    uint8_t buf[4];
 
    int memSize = 0;
 
    int fd = open("/sys/firmware/devicetree/base/soc/ranges", O_RDONLY);
 
    if (fd<=0)
 
    {
 
        cout << "Pb de configuration de sysfs !!"<<endl;
 
        exit(-1);
 
    }
 
    lseek(fd, 4, SEEK_SET);
 
    if (read(fd, buf, sizeof(buf)) == sizeof(buf)) {
 
        mBaseAdress = (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] );
 
        cout << "Adresse de base des périphs : 0x"<< hex << mBaseAdress <<endl;
 
    }
 
    lseek(fd, 8, SEEK_SET);
 
    if (read(fd, buf, sizeof(buf)) == sizeof(buf)) {
 
        memSize = (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] );
 
        cout << "Taille de la mémoire : 0x"<< hex << memSize <<endl;
 
    }
 
    close(fd);
 
    if ( (memSize==0) || (mBaseAdress==0) )
 
    {
 
        cout << "Pb de lecture des paramètres mémoire !!"<<endl;
 
        exit(-1);
 
    }
 
    fd = open("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC);
 
    if (fd<=0)
 
    {
 
        cout << "Pb d'accès à /dev/mem !!"<<endl;
 
        exit(-1);
 
    }
 
    memMap = (unsigned int *)mmap(NULL, memSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, mBaseAdress);
 
    if (memMap == MAP_FAILED)
 
    {
 
        cout << "Pb de mappage mémoire !!"<<endl;
 
        exit(-1);
 
    }
 
    close(fd);
 
}
 
 
void RpiPeripherique::regWrite(unsigned int reg, unsigned int val)
 
{
 
    *(memMap+reg/4) = val;
 
}
 
 
void RpiPeripherique::regSetBits(unsigned int reg, unsigned int val, unsigned int offset)
 
{
 
    unsigned int regVal = *(memMap+reg/4);
 
    regVal |= val<<offset;
 
    *(memMap+reg/4) = regVal;
 
}
 
 
void RpiPeripherique::regClearBits(unsigned int reg, unsigned int val, unsigned int offset)
 
{
 
    unsigned int regVal = *(memMap+reg/4);
 
    regVal &=~ (val<<offset);
 
    *(memMap+reg/4) = regVal;
 
}
 
 
unsigned int RpiPeripherique::regRead(unsigned int reg)
 
{
 
    return *(memMap+reg/4);
 
}
 
</source>
 
{{boîte déroulante/fin}}
 
|}
 
  
 
{|style="vertical-align:middle; width:100%; text-align:left; "
 
{|style="vertical-align:middle; width:100%; text-align:left; "

Version du 6 octobre 2023 à 15:29


eclairagedimmable.h

#ifndef ECLAIRAGEDIMMABLE_H
#define ECLAIRAGEDIMMABLE_H

#include <QObject>

class EclairageDimmable : public QObject
{
    Q_OBJECT
public:
    explicit EclairageDimmable(QObject *parent = nullptr);

    bool isOn;
    unsigned int puissance; // entre 1 et 4

public slots:
    void allumer();
    void eteindre();
    void augmenterPuissance();
    void diminuerPuissance();
protected:
    virtual void appliquerConsigne();
signals:

};

#endif // ECLAIRAGEDIMMABLE_H

eclairagedimmable.cpp

#include "eclairagedimmable.h"
#include <QDebug>

EclairageDimmable::EclairageDimmable(QObject *parent) : QObject(parent)
{
    isOn=false;
    puissance=1;
}

void EclairageDimmable::allumer()
{
    isOn=true;
    appliquerConsigne();
}

void EclairageDimmable::eteindre()
{
    isOn=false;
    appliquerConsigne();
}

void EclairageDimmable::augmenterPuissance()
{
    if (puissance<4) puissance++;
    appliquerConsigne();
}

void EclairageDimmable::diminuerPuissance()
{
    if (puissance>1) puissance--;
    appliquerConsigne();
}

void EclairageDimmable::appliquerConsigne()
{
    qDebug() << "je suis "<< (isOn==true?"allumée":"éteinte")<< " à la puissance "<<puissance;
}

barregraphe.h

#ifndef BARREGRAPHE_H
#define BARREGRAPHE_H
#include "eclairagedimmable.h"
#include "gpio.h"
using namespace exploringRPi;

class Barregraphe : public EclairageDimmable
{
public:
    Barregraphe(int pinLed1, int pinLed2, int pinLed3, int pinLed4);
protected:
    GPIO led1;
    GPIO led2;
    GPIO led3;
    GPIO led4;

    void appliquerConsigne() override;
};

#endif // BARREGRAPHE_H

barregraphe.cpp

#include "barregraphe.h"

Barregraphe::Barregraphe(int pinLed1, int pinLed2, int pinLed3, int pinLed4)
            :led1(pinLed1),led2(pinLed2),led3(pinLed3),led4(pinLed4)
{
    led1.setDirection(OUTPUT);
    led2.setDirection(OUTPUT);
    led3.setDirection(OUTPUT);
    led4.setDirection(OUTPUT);
}

void Barregraphe::appliquerConsigne()
{
    EclairageDimmable::appliquerConsigne();
v    if (isOn==false)
    {
        led1.setValue(LOW);
        led2.setValue(LOW);
        led3.setValue(LOW);
        led4.setValue(LOW);
    }
    else
    {
        if (puissance==1)
        {
            led1.setValue(HIGH);
            led2.setValue(LOW);
            led3.setValue(LOW);
            led4.setValue(LOW);
        }
        else if (puissance==2)
        {
            led1.setValue(HIGH);
            led2.setValue(HIGH);
            led3.setValue(LOW);
            led4.setValue(LOW);
        }
        else if (puissance==3)
        {
            led1.setValue(HIGH);
            led2.setValue(HIGH);
            led3.setValue(HIGH);
            led4.setValue(LOW);
        }
        else
        {
            led1.setValue(HIGH);
            led2.setValue(HIGH);
            led3.setValue(HIGH);
            led4.setValue(HIGH);
        }
    }
}

leddimmable.h

#ifndef LEDDIMMABLE_H
#define LEDDIMMABLE_H
#include "eclairagedimmable.h"
#include "pwm.h"

class LedDimmable : public EclairageDimmable
{
public:
    LedDimmable(unsigned int numPwm);

protected:
    Pwm mli;

    void appliquerConsigne() override;
};

#endif // LEDDIMMABLE_H

leddimmable.cpp

#include "leddimmable.h"

LedDimmable::LedDimmable(unsigned int numPwm)
            : mli(numPwm)
{
        mli.setRange(23);
        mli.setRapportCyclique(0);
}

void LedDimmable::appliquerConsigne()
{
    EclairageDimmable::appliquerConsigne();
    if (isOn==false)
    {
        mli.setRapportCyclique(0);
    }
    else
    {
        mli.setRapportCyclique(puissance*3+10);
    }

}


gpio.h

#ifndef GPIO_H
#define GPIO_H


#include<string>
#include<fstream>
using std::string;
using std::ofstream;

#define GPIO_PATH "/sys/class/gpio/"

namespace exploringRPi {

typedef int (*CallbackType)(int);
enum GPIO_DIRECTION{ INPUT, OUTPUT };
enum GPIO_VALUE{ LOW=0, HIGH=1 };
enum GPIO_EDGE{ NONE, RISING, FALLING, BOTH };

class GPIO {
private:
    int number, debounceTime;
    string name, path;
public:
    GPIO(int number);                     // constructor exports pin
    virtual int getNumber() { return number; }

    // General Input and Output Settings
    virtual int  setDirection(GPIO_DIRECTION);
    virtual GPIO_DIRECTION getDirection();
    virtual int  setValue(GPIO_VALUE);
    virtual int  toggleOutput();
    virtual GPIO_VALUE getValue();
    virtual int  setActiveLow(bool isLow=true);  // low=1, high=0
    virtual int  setActiveHigh();                // default state
    virtual void setDebounceTime(int time) { this->debounceTime = time; }

    // Advanced output: faster by keeping the stream open (~20x)
    virtual int  streamOpen();
    virtual int  streamWrite(GPIO_VALUE);
    virtual int  streamClose();
    virtual int  toggleOutput(int time); // thread invert output every X ms
    virtual int  toggleOutput(int numberOfTimes, int time);
    virtual void changeToggleTime(int time) { this->togglePeriod = time; }
    virtual void toggleCancel() { this->threadRunning = false; }

    // Advanced input: detect input edges -- threaded and non-threaded
    virtual int  setEdgeType(GPIO_EDGE);
    virtual GPIO_EDGE getEdgeType();
    virtual int  waitForEdge();        // waits until button is pressed
    virtual int  waitForEdge(CallbackType callback); // threaded callback
    virtual void waitForEdgeCancel() { this->threadRunning = false; }

    virtual ~GPIO();  // destructor unexports the pin
private:
    int write(string path, string filename, string value);
    int write(string path, string filename, int value);
    string read(string path, string filename);
    int exportGPIO();
    int unexportGPIO();
    ofstream stream;
    pthread_t thread;
    CallbackType callbackFunction;
    bool threadRunning;
    int togglePeriod;  // default 100ms
    int toggleNumber;  // default -1 (infinite)
    friend void* threadedPoll(void *value);
    friend void* threadedToggle(void *value);
};

void* threadedPoll(void *value);      // callback functions for threads
void* threadedToggle(void *value);    // callback functions for threads

} /* namespace exploringRPi */

#endif // GPIO_H

gpio.cpp

#include "gpio.h"

#include<iostream>
#include<fstream>
#include<string>
#include<sstream>
#include<cstdlib>
#include<cstdio>
#include<fcntl.h>
#include<unistd.h>
#include<sys/epoll.h>
#include<pthread.h>
using namespace std;

namespace exploringRPi {

/**
 *
 * @param number The GPIO number for the RPi
 */
GPIO::GPIO(int number) {
    this->number = number;
    this->debounceTime = 0;
    this->togglePeriod=100;
    this->toggleNumber=-1; //infinite number
    this->callbackFunction = NULL;
    this->threadRunning = false;

    ostringstream s;
    s << "gpio" << number;
    this->name = string(s.str());
    this->path = GPIO_PATH + this->name + "/";
    this->exportGPIO();
    // need to give Linux time to set up the sysfs structure
    usleep(250000); // 250ms delay
}

int GPIO::write(string path, string filename, string value){
   ofstream fs;
   fs.open((path + filename).c_str());
   if (!fs.is_open()){
       perror("GPIO: write failed to open file ");
       return -1;
   }
   fs << value;
   fs.close();
   return 0;
}

string GPIO::read(string path, string filename){
   ifstream fs;
   fs.open((path + filename).c_str());
   if (!fs.is_open()){
       perror("GPIO: read failed to open file ");
    }
   string input;
   getline(fs,input);
   fs.close();
   return input;
}

int GPIO::write(string path, string filename, int value){
   stringstream s;
   s << value;
   return this->write(path,filename,s.str());
}

int GPIO::exportGPIO(){
   return this->write(GPIO_PATH, "export", this->number);
}

int GPIO::unexportGPIO(){
   return this->write(GPIO_PATH, "unexport", this->number);
}

int GPIO::setDirection(GPIO_DIRECTION dir){
   switch(dir){
   case INPUT: return this->write(this->path, "direction", "in");
      break;
   case OUTPUT:return this->write(this->path, "direction", "out");
      break;
   }
   return -1;
}

int GPIO::setValue(GPIO_VALUE value){
   switch(value){
   case HIGH: return this->write(this->path, "value", "1");
      break;
   case LOW: return this->write(this->path, "value", "0");
      break;
   }
   return -1;
}

int GPIO::setEdgeType(GPIO_EDGE value){
   switch(value){
   case NONE: return this->write(this->path, "edge", "none");
      break;
   case RISING: return this->write(this->path, "edge", "rising");
      break;
   case FALLING: return this->write(this->path, "edge", "falling");
      break;
   case BOTH: return this->write(this->path, "edge", "both");
      break;
   }
   return -1;
}

int GPIO::setActiveLow(bool isLow){
   if(isLow) return this->write(this->path, "active_low", "1");
   else return this->write(this->path, "active_low", "0");
}

int GPIO::setActiveHigh(){
   return this->setActiveLow(false);
}

GPIO_VALUE GPIO::getValue(){
    string input = this->read(this->path, "value");
    if (input == "0") return LOW;
    else return HIGH;
}

GPIO_DIRECTION GPIO::getDirection(){
    string input = this->read(this->path, "direction");
    if (input == "in") return INPUT;
    else return OUTPUT;
}

GPIO_EDGE GPIO::getEdgeType(){
    string input = this->read(this->path, "edge");
    if (input == "rising") return RISING;
    else if (input == "falling") return FALLING;
    else if (input == "both") return BOTH;
    else return NONE;
}

int GPIO::streamOpen(){
    stream.open((path + "value").c_str());
    return 0;
}
int GPIO::streamWrite(GPIO_VALUE value){
    stream << value << std::flush;
    return 0;
}
int GPIO::streamClose(){
    stream.close();
    return 0;
}

int GPIO::toggleOutput(){
    this->setDirection(OUTPUT);
    if ((bool) this->getValue()) this->setValue(LOW);
    else this->setValue(HIGH);
    return 0;
}

int GPIO::toggleOutput(int time){ return this->toggleOutput(-1, time); }
int GPIO::toggleOutput(int numberOfTimes, int time){
    this->setDirection(OUTPUT);
    this->toggleNumber = numberOfTimes;
    this->togglePeriod = time;
    this->threadRunning = true;
    if(pthread_create(&this->thread, NULL, &threadedToggle, static_cast<void*>(this))){
        perror("GPIO: Failed to create the toggle thread");
        this->threadRunning = false;
        return -1;
    }
    return 0;
}

// This thread function is a friend function of the class
void* threadedToggle(void *value){
    GPIO *gpio = static_cast<GPIO*>(value);
    bool isHigh = (bool) gpio->getValue(); //find current value
    while(gpio->threadRunning){
        if (isHigh)	gpio->setValue(HIGH);
        else gpio->setValue(LOW);
        usleep(gpio->togglePeriod * 500);
        isHigh=!isHigh;
        if(gpio->toggleNumber>0) gpio->toggleNumber--;
        if(gpio->toggleNumber==0) gpio->threadRunning=false;
    }
    return 0;
}

// Blocking Poll - based on the epoll socket code in the epoll man page
int GPIO::waitForEdge(){
    this->setDirection(INPUT); // must be an input pin to poll its value
    int fd, i, epollfd, count=0;
    struct epoll_event ev;
    epollfd = epoll_create(1);
    if (epollfd == -1) {
       perror("GPIO: Failed to create epollfd");
       return -1;
    }
    if ((fd = open((this->path + "value").c_str(), O_RDONLY | O_NONBLOCK)) == -1) {
       perror("GPIO: Failed to open file");
       return -1;
    }

    //ev.events = read operation | edge triggered | urgent data
    ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
    ev.data.fd = fd;  // attach the file file descriptor

    //Register the file descriptor on the epoll instance, see: man epoll_ctl
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
       perror("GPIO: Failed to add control interface");
       return -1;
    }
    while(count<=1){  // ignore the first trigger
        i = epoll_wait(epollfd, &ev, 1, -1);
        if (i==-1){
            perror("GPIO: Poll Wait fail");
            count=5; // terminate loop
        }
        else {
            count++; // count the triggers up
        }
    }
    close(fd);
    if (count==5) return -1;
    return 0;
}

// This thread function is a friend function of the class
void* threadedPoll(void *value){
    GPIO *gpio = static_cast<GPIO*>(value);
    while(gpio->threadRunning){
        gpio->callbackFunction(gpio->waitForEdge());
        usleep(gpio->debounceTime * 1000);
    }
    return 0;
}

int GPIO::waitForEdge(CallbackType callback){
    this->threadRunning = true;
    this->callbackFunction = callback;
    // create the thread, pass the reference, address of the function and data
    if(pthread_create(&this->thread, NULL, &threadedPoll, static_cast<void*>(this))){
        perror("GPIO: Failed to create the poll thread");
        this->threadRunning = false;
        return -1;
    }
    return 0;
}

GPIO::~GPIO() {
    this->unexportGPIO();
}

} /* namespace exploringRPi */

bouton.h

 #ifndef BOUTON_H
#define BOUTON_H

#include <QObject>
#include <QFileSystemWatcher>
#include "gpio.h"
using namespace exploringRPi;

class Bouton : public QObject
{
    Q_OBJECT
public:
    explicit Bouton(int nbBroche,GPIO_EDGE typeFront);
    bool getValue();
private:
    GPIO broche;
    QFileSystemWatcher fileScanner;
signals:
    void change();
public slots:
    void evenementBroche();
};

#endif // BOUTON_H

bouton.cpp

#include "bouton.h"

Bouton::Bouton(int nbBroche, GPIO_EDGE typeFront) : QObject(), broche(nbBroche)
{
    broche.setDirection(INPUT);
    broche.setEdgeType(typeFront);
    fileScanner.addPath(QString("/sys/class/gpio/gpio%1/value").arg(nbBroche));
    connect(&fileScanner,SIGNAL(fileChanged(QString)),this,SLOT(evenementBroche()));
}

bool Bouton::getValue()
{
    return broche.getValue();
}

void Bouton::evenementBroche()
{
    emit change();
}