#define ENCODER_CLK 34
#define ENCODER_DT 35
#define ENCODER_BTN 4

typedef enum {
  UP, DOWN
} Direction;

struct Encoder {
  int value = 0;
  bool updated;
  Direction direction;
  bool buttonPressed;
  int min = 0;
  int max = 100;
  int stepsize = 1;
};
Encoder encoder;


void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);

  initEncoder();
}

void loop() {
  if (encoder.updated) {
    Serial.println("Encoder: " + String(encoder.value) + "  Direction: " + String(encoder.direction));
    encoder.updated = false;
  }
  if (encoder.buttonPressed) {
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  }
  delay(100);
}

void initEncoder() {
  pinMode(ENCODER_BTN, INPUT_PULLUP);
  pinMode(ENCODER_CLK, INPUT);
  pinMode(ENCODER_DT, INPUT);

  attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), doEncoderRotate, FALLING);
  attachInterrupt(digitalPinToInterrupt(ENCODER_BTN), doEncoderButton, CHANGE);
}

void doEncoderRotate() {
  int dtValue = digitalRead(ENCODER_DT);
  if (dtValue == HIGH && encoder.value < encoder.max) {
    encoder.value += encoder.stepsize;
    encoder.direction = UP;
    encoder.updated = true;
  }
  if (dtValue == LOW && encoder.value > encoder.min) {
    encoder.value -= encoder.stepsize;
    encoder.direction = DOWN;
    encoder.updated = true;
  }
}

void doEncoderButton() {
  encoder.buttonPressed = !encoder.buttonPressed;
}