Skip to content
Snippets Groups Projects
RotaryEncoder.h 3.98 KiB
Newer Older
#ifndef ROTARYENCODER_h
#define ROTARYENCODER_h

class RotaryEncoder {

    // Private members:

    int _pinA;
    int _pinB;
    volatile int _state[2];
    volatile int _position;
    volatile bool _inputFlag = false;
    bool _changeFlag = false;

    unsigned long _previousTimer;
    int _interval = 200;

    void (*_cb)(RotaryEncoder*, uint8_t, int); // Callback function

    // {newPin2, newPin1, oldPin2, oldPin1}
    int movements[5][4][4] = {
      { // No movement
        {0, 0, 0, 0},
        {0, 1, 0, 1},
        {1, 0, 1, 0},
        {1, 1, 1, 1}
      },
      { // +1
        {0, 0, 0, 1},
        {0, 1, 1, 1},
        {1, 0, 0, 0},
        {1, 1, 1, 0}
      },
      { // -1
        {0, 0, 1, 0},
        {0, 1, 0, 0},
        {1, 0, 1, 1},
        {1, 1, 0, 1}
      },
      { // +2
        {0, 0, 1, 1},
        {1, 1, 0, 0}
      },
      { // -2
        {0, 1, 1, 0},
        {1, 0, 0, 1}
      },
    };

    // Private Functions:

    void _setState(int a, int b) {
      _state[0] = a;
      _state[1] = b;
    }

    void _incrementPosition(int delta) {
      _position = _position + delta;
    }

    int _findChange(int state1[2], volatile int state2[2]) {
      int stateAppend[] = {state1[1], state1[0], state2[1], state2[0]};

      for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
          if (_compareArrays(stateAppend, movements[i][j])) {
            if (i == 0) {
              return 0;
            }
            else if (i == 1) {
              return 1;
            }
            else if (i == 2) {
              return -1;
            }
            else if (i == 3) {
              return 2;
            }
            else if (i == 4) {
              return -2;
            }
          }
        }
      }

      for (int i = 3; i < 5; i++) {
        for (int j = 0; j < 2; j++) {
          if (_compareArrays(stateAppend, movements[i][j])) {
            if (i == 3) {
              return 2;
            }
            else if (i == 4) {
              return -2;
            }
          }
        }
      }
      Serial.println("INVALID DATA");
      return 0;
    }

    boolean _compareArrays(int a[4], int b[4]) {
      if (a[0] != b[0]) {
        return false;
      }
      if (a[1] != b[1]) {
        return false;
      }
      if (a[2] != b[2]) {
        return false;
      }
      if (a[3] != b[3]) {
        return false;
      }
      return true;
    }

  public:

    // Public members:

    static const uint8_t kEventStableUpdate = 0;
    static const uint8_t kEventUnstableUpdate = 1;

    //Public Functions:

    RotaryEncoder(int pinA, int pinB, int id = 99) : _pinA(pinA), _pinB(pinB), _id(id) {
      pinMode(_pinA, INPUT_PULLUP);
      pinMode(_pinB, INPUT_PULLUP);

      _previousTimer = millis();
      _setState(digitalRead(_pinA), digitalRead(_pinB));
      setPosition(0);
    }

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

    void setEventHandler(void(*function)(RotaryEncoder*, uint8_t, int)) {
      _cb = function;
    }

    int getPostition() {
      return _position;
    }

    int getId() {
      return _id;
    }

    void setPosition(int value) {
      _position = value;
    }

    void check() {
      unsigned long timer = millis();
      unsigned long deltaTime = timer - _previousTimer;
      if (_inputFlag == true) {
        _inputFlag = false;

        _changeFlag = true;
        _previousTimer = timer;

        _cb(this, kEventUnstableUpdate, getPostition());
      }

      if (_changeFlag == true && deltaTime > _interval) {
        _changeFlag = false;

        _cb(this, kEventStableUpdate, getPostition());
      }
    }

    void ICACHE_RAM_ATTR tick() {
      int tempState[] = {digitalRead(_pinA), digitalRead(_pinB)};
      int delta = _findChange(tempState, _state);
      if (delta != 0) {
        _incrementPosition(delta);
        _inputFlag = true;
      }
      _setState(tempState[0], tempState[1]);
    }

};

#endif