Cours:DevoirPOO2 classes

De troyesGEII
Aller à : navigation, rechercher


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"

enum numeroPWM{ PWM0, PWM1 };

class ledDimmable : public EclairageDimmable
{
public:
    ledDimmable(numeroPWM _numero);

protected:
    int numeroGPIO;
    int rapportCyclique;

    void appliquerConsigne() override;
};

#endif // LEDDIMMABLE_H

leddimmable.cpp

#include "leddimmable.h"
#include <pigpio.h>

ledDimmable::ledDimmable(numeroPWM _numero)
    : EclairageDimmable()
{
    gpioInitialise();
    if (_numero==PWM0) numeroGPIO=12;
    else               numeroGPIO=13;
    appliquerConsigne();
}

void ledDimmable::appliquerConsigne()
{
    EclairageDimmable::appliquerConsigne();
    if (isOn==false)
    {
       gpioHardwarePWM(numeroGPIO,500,0);
    }
    else
    {
        gpioHardwarePWM(numeroGPIO,500,puissance*10000);
    }
}

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();
}