/*
  Project:       ShiftRegister_7Seg_Demo
  Description:   In a real circuit add transistors on each digit!
                 The gray wires are digits, colored are the segments.
                 Written for common cathode displays.
                 TO DO:
                  Add digit shift register
                  Support negative numbers
  Creation date: 11/10/24
  Author:        AnonEngineering

  License:       https://en.wikipedia.org/wiki/Beerware
*/

const uint8_t MAX_DIGITS = 4;///////////////////////////////////////////

// pin definitions
const uint8_t CLOCK_PIN = 8;
const uint8_t LATCH_PIN = 7;
const uint8_t DATA_PIN  = 6;
const uint8_t POT_PIN   = A0;
const uint8_t DIGIT_PINS[MAX_DIGITS] = {2, 3, 4, 5}; //, A1, A2, A3, A4};
// lookup table, which segments are on for each value
const uint8_t SEG_BYTES[] = {
  0xFC, /* 0 */
  0x60, /* 1 */
  0xDA, /* 2 */
  0xF2, /* 3 */
  0x66, /* 4 */
  0xB6, /* 5 */
  0xBE, /* 6 */
  0xE0, /* 7 */
  0xFE, /* 8 */
  0xF6, /* 9 */
  0x00  /* blank */
};

uint8_t DP_POSITION = 0;  // for test

// for hardware test only
void testDisplay()  {
  writeShiftDigit(0, 1, false);
  writeShiftDigit(1, 2, false);
  writeShiftDigit(2, 3, false);
  writeShiftDigit(3, 4, false);
  writeShiftDigit(4, 5, false);
  writeShiftDigit(5, 6, true);
  writeShiftDigit(6, 7, false);
  writeShiftDigit(7, 8, false);
}

void updateDisplay(uint32_t value, uint8_t dpPos)  {
  uint8_t digitVal;
  uint8_t powOfTen = MAX_DIGITS - 1;
  uint32_t op1 = 1, op2 = 1;

  for (uint8_t digit = 0; digit < powOfTen; digit++) {
    for (uint8_t p = powOfTen - digit; p >= 1; p--) {
      op1 = op1 * 10;
    }
    op2 = op1 * 10;
    // with leading zero blanking (10 is a blank char)
    digitVal = value < op1 ? 10 : (value % op2) / op1;
    writeShiftDigit(digit, digitVal, ((dpPos - 1) == digit) ? true : false);
    op1 = 1; op2 = 1;
  }
  // last digit is never blanked
  writeShiftDigit(powOfTen, value % 10, ((dpPos - 1) == powOfTen) ? true : false);
}

void writeShiftDigit(uint8_t digit, uint8_t number, bool dp)  {
  uint8_t value = SEG_BYTES[number];
  digitalWrite(LATCH_PIN, LOW);
  shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, dp ? (value | 0x01) : value);
  digitalWrite(LATCH_PIN, HIGH);
  digitalWrite(DIGIT_PINS[digit], LOW);
  digitalWrite(DIGIT_PINS[digit], HIGH);
}

void setup() {
  Serial.begin(115200);
  pinMode(DATA_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);
  pinMode(LATCH_PIN, OUTPUT);
  for (uint8_t i = 0; i < MAX_DIGITS; i++) {
    pinMode(DIGIT_PINS[i], OUTPUT);
  }
}

void loop() {
  // multiply pot value by 1000 for 8 digits
  uint32_t potVal = analogRead(POT_PIN); // * 1000ul;
  // update display often
  updateDisplay(potVal, DP_POSITION);
  //testDisplay();
}
$abcdeabcde151015202530fghijfghij
74HC595