Skip to content
Snippets Groups Projects
Button.h 3.27 KiB
Newer Older
#ifndef BUTTON_h
#define BUTTON_h

class Button {

  private:
    int _pin;
    int _id;

    bool _state;

    volatile bool _inputFlag = false;
    bool _changeFlag = false;

    bool _pressedFlag = false;
    bool _holdFlag = false;

    unsigned long _previousTimer;

    int _clickInterval = 1000;
    int _holdInterval = 1000;
    int _repeatInterval = 1000;

    void (*_cb)(Button*, uint8_t, bool); // Callback function

    bool _read() {
      return digitalRead(_pin);
    }

    void _setClickInterval(int x) {
      _clickInterval = x;
    }

    void _setHoldInterval(int x) {
      _holdInterval = x;
    }

    void _setRepeatInterval(int x) {
      _repeatInterval = x;
    }

  public:

    // Public members:

    static const uint8_t kEventPressed = 0;        // Button was pressed
    static const uint8_t kEventReleased = 1;       // Button was released
    static const uint8_t kEventClicked = 2;        // Button was clicked (pressed and released within _clickInterval)
    static const uint8_t kEventHeld = 3;    // Button was held down for longer than _holdInterval
    static const uint8_t kEventTick = 4;  // Event released every _repeatInterval when button held

    // Public functions:

    Button(int pin, int id = 99) : _pin(pin), _id(id) {
      pinMode(_pin, INPUT_PULLUP);

      _state = _read();

      _previousTimer = millis();
    }

    void initInterrupts(void(*function)()) {
      attachInterrupt(_pin, function, CHANGE);
    }

    void setEventHandler(void(*function)(Button*, uint8_t, bool)) {
      _cb = function;
    }

    bool getState() {
      return _state;
    }

    int getId() {
      return _id;
    }

    int getClickInterval() {
      return _clickInterval;
    }

    int getHoldInterval() {
      return _holdInterval;
    }

    int getRepeatInterval() {
      return _repeatInterval;
    }

    void check() {
      unsigned long timer = millis();
      unsigned long deltaTime = timer - _previousTimer;
      _state = _read();

      if (_inputFlag == true) {
        _inputFlag = false;

        // Button pressed
        if (_state == LOW
            && _pressedFlag == false) {
          _pressedFlag = true;
          _previousTimer = timer;
          _cb(this, kEventPressed, _state);
          return;

        // Button clicked
        } else if (_state == HIGH
                  && deltaTime < _clickInterval
                  && _holdFlag == false) {
          _pressedFlag = false;
          _previousTimer = timer;
          _cb(this, kEventClicked, _state);
          return;

        // Button released
        } else if (_state == HIGH) {
          _pressedFlag = false;
          _holdFlag = false;
          _previousTimer = timer;
          _cb(this, kEventReleased, _state);
          return;
        }
      }

      // Button held
      if (_state == LOW
          && deltaTime > _holdInterval
          && _holdFlag == false) {
        _holdFlag = true;
        _previousTimer = timer;
        _cb(this, kEventHeld, _state);
        return;

      // Button tick
      } else if (_state == LOW
                && deltaTime > _repeatInterval
                && _holdFlag == true) {
        _previousTimer = timer;
        _cb(this, kEventTick, _state);
        return;
      }
    }

    void ICACHE_RAM_ATTR tick() {
      _inputFlag = true;
    }

};

#endif