/*
  KY-040 Rotary Encoder Counter using Franzininho, 74HC595, 7 Segment Display (4 digits) and KY-040
  Code by: Uri Shaked
  Modified by: Anderson Costa
  Visit https://wokwi.com to learn about the Wokwi Simulator
  Visit https://franzininho.com.br to learn about the Franzininho
*/

#define ENCODER_CLK 0    // Pin connected to CLK of KY-040
#define ENCODER_DT  1    // Pin connected to DT of KY-040
#define ENCODER_SW  2    // Pin connected to SW of KY-040

#define DATA_PIN    5    // Pin connected to DS of 74HC595
#define LATCH_PIN   3    // Pin connected to STCP of 74HC595
#define CLOCK_PIN   4    // Pin connected to SHCP of 74HC595

uint16_t registers = 0;

uint8_t counter_array[4] = {0, 0, 0, 0};
uint16_t counter = 0;

uint8_t digitPins[] = {4, 7, 10, 13}; // 1-Q4, 1-Q7, 2-Q2, 2-Q5

uint16_t digits[] = {
  0b0100000000000000, // 0
  0b0100000001101100, // 1
  0b1000000001000000, // 2
  0b0000000001001000, // 3
  0b0000000000101100, // 4
  0b0000100000001000, // 5
  0b0000100000000000, // 6
  0b0100000001001100, // 7
  0b0000000000000000, // 8
  0b0000000000001100, // 9
};

uint8_t lastClk = HIGH;

void setup() {
  // Initialize shift register pins
  pinMode(DATA_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);
  pinMode(LATCH_PIN, OUTPUT);

  // Initialize encoder pins
  pinMode(ENCODER_CLK, INPUT);
  pinMode(ENCODER_DT, INPUT);
  pinMode(ENCODER_SW, INPUT_PULLUP);
}

void loop() {
  readEncoder();
  checkReset();
  scanDigit(1);
  scanDigit(2);
  scanDigit(3);
  scanDigit(4);
  updateCounter();
}

void readEncoder() {
  uint8_t newClk = digitalRead(ENCODER_CLK);
  if (newClk != lastClk) {
    // There was a change on the CLK pin
    lastClk = newClk;
    uint8_t dtValue = digitalRead(ENCODER_DT);
    if (newClk == LOW && dtValue == HIGH) {
      counter++; // Clockwise
    }
    if (newClk == LOW && dtValue == LOW) {
      counter--; // Counterclockwise
    }
  }
}

void checkReset() {
  if (digitalRead(ENCODER_SW) == LOW) {
    counter = 0;
  }
}

void updateCounter()
{
  counter_array[0] = extractDigit(4);
  counter_array[1] = extractDigit(3);
  counter_array[2] = extractDigit(2);
  counter_array[3] = extractDigit(1);
}

void scanDigit(int index)
{
  registers = digits[counter_array[index - 1]] | bit(digitPins[index - 1]);
  writeRegisters();
}

int extractDigit(uint8_t pos)
{
  unsigned long Pow = 1;

  for (uint8_t i = 0; i < (pos - 1); i++)
    Pow *= 10;

  // Check values ​​greater than the number of digits
  if (counter > 9999)
    counter = 0;

  return (counter / Pow) % 10;
}

void writeRegisters()
{
  // Set and display registers
  digitalWrite(LATCH_PIN, LOW);
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, highByte(registers));
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, lowByte(registers));
  digitalWrite(LATCH_PIN, HIGH);
}
74HC595
74HC595