Cours:DevoirPOO2 classes

De troyesGEII
Aller à : navigation, rechercher

Il s’agit d’une page protégée.


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

}

pwm.h

#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

pwm.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);
}

pwmclk.h

#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

pwmclk.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;
}

rpiperipherique.h

#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

rpiperipherique.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);
}

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