/*  TRY 5 - HEX VERSION WORKS!!!!!
  Purpose - to repeat Prof Spoelstra's 7 seg timing counter algorithm
  without use of switch and case statements and sevseg library
  extend to the hex alphabet
  Understand the approach to simplify the code

  Approach
  - include pattern for bit maps of 7 seg digits and letters
  - assign digit and segment pins to variables
  - funct add - timing algorithm one timing increment per call to update segments
  - funct clearleds - turn off leds by high-ing digit pins and low-ering segment pins (no current flow)
  - funct picknumber - passes pattern to digital writes for parsing to turn on/off segment pins for the digit
  - funct pickdigit - determines which digit line to turn low to light the digit

*/

#include <TimerOne.h>
// globals

// pin assignments
const byte a = 6;     // connect to a
const byte b = 7;     // b
const byte c = 8;     // etc
const byte d = 9;
const byte e = 10;
const byte f = 11;
const byte g = 12;
const byte dp = 13;
const byte d4 = 5;
const byte d3 = 4;
const byte d2 = 3;
const byte d1 = 2;
// segment pin array
const byte SEG_ARRAY[] = { a, b, c, d, e, f, g, dp };
//digit pin array
const byte DIGIT_ARRAY[ ] = {d1, d2, d3, d4};

//7-seg pattern array for bit illumination of segments to make characters

const byte PATTERN  [] = {
  //            .gfe dcba order
  0x3F, // 0    0011 1111                         AAAAA
  0x06, // 1    0000 0110                        F     B
  0x5B, // 2    0101 1011                        F     B
  0x4F, // 3    0100 1111                        F     B
  0x66, // 4    0110 0110                         GGGGG
  0x6D, // 5    0110 1101                        E     c
  0x7D, // 6    0111 1101                        E     C
  0x07, // 7    0000 0111                        E     C
  0x7F, // 8    0111 1111                         DDDDD
  0x6F, // 9    0110 1111                                DP

  0x77,  // A  01110111       see seven segment pattern map
  0x7C,  // B  01111100
  0x39,  // C  00111001
  0x5E,  // D  01011110
  0x79,  // E  01111001
  0x71   // F  01110001
};

byte timeDelay = 5; // multiplexing time between digits
int count = 0;      // count will be displayed on the 7-seg digits  *volatile?
byte num0 = 0;      // value of 1000 digit
byte num1 = 0;      // value of 100 digit
byte num2 = 0;     // value of 10 digit
byte num3 = 0;      // value of 1 digit
bool prntFlag = false;  // set true for serial output of running variables
                        // note: must comment out timer calls and interrupts
                        // and addback the for loop to check variables

void setup() {
  // set digit pins as outpuy
  for (byte j = 0; j < sizeof(SEG_ARRAY); j++) {
    pinMode (SEG_ARRAY[j], OUTPUT);   // default state is LOW
  }
  // set segment pins as input_pullups (with internal current limit resistors)
  for (byte j = 0; j < sizeof(DIGIT_ARRAY); j++) {
    pinMode (DIGIT_ARRAY[j], OUTPUT);       // was INPUT_PULLUP
    // default stateu is HIGH
  }
  //timing routines - comment out for stub testing
  Timer1.initialize(1000000);  // set timer for 1e6 microsecons or 1 second
  Timer1.attachInterrupt(add);  // attach the timer ISR
  //Serial.begin(9600);
}

void loop() {

  //for (count = 0; count < 20; count++) {  // test stub loop just to see if picking digits and segments correctly
    if (prntFlag) {
      Serial.println("----------------");
      Serial.print("count = ");
      Serial.println(count);
    }
    clearLEDs();                          // clear display
    num0 = (count / (16*16*16));                // get value of 16*16*16 digit
    pickDigit(0);                         // High-ing digit d1
    pickNumber( num0 );
    delay(timeDelay);                     // short delay to avoid flicker

    clearLEDs();                          // clear display
    num1 =  (count % 16) / (16*16);       // get value of 16*16 digit
    pickDigit(1);                         // High-ing digit d2
    pickNumber( num1 );
    delay(timeDelay);                     // short delay to avoid flicker

    clearLEDs();                          // clear display
    num2 =  (count % (16*16)) / 16;       // get value of 16 digit
    pickDigit(2);                         // High-ing digit d3
    pickNumber( num2 );
    delay(timeDelay);                     // short delay to avoid flicker

    clearLEDs();                          // clear display
    num3 = (count % 16 );                 // get value of unit digit
    pickDigit(3);                         // High-ing digit d4
    pickNumber( num3 ) ;
    delay(timeDelay);                     // short delay to avoid flicker

    // repeat sequence on same count until ISR increments count

    //delay(1000); // delay to read the output
  //}  end of for loop
}

void clearLEDs() {        // clear the 7-segment display
  // set digital pins LOW
  for (byte j = 0; j < sizeof(SEG_ARRAY); j++) {
    digitalWrite (SEG_ARRAY[j], LOW);  // to 0 v  (no voltage to anode (+) of led diodes)
  }
  // set segment pins HIGH
  for (byte j = 0; j < sizeof(DIGIT_ARRAY); j++) {
    digitalWrite (DIGIT_ARRAY[j], HIGH); // to 5 v (high voltage to cathode (-) of led diode)
  }
}

void pickDigit( byte digitIndex) {   // picks the digit to drop LOW for current flow
  digitalWrite( DIGIT_ARRAY [digitIndex], LOW);
  // this is for diagnostics
  if (prntFlag) {
    Serial.print("Digit= ");
    Serial.print(digitIndex);
    Serial.print("  ");

    if (digitIndex == 0) {
      Serial.print(num0);
      Serial.println("---");  // 1000
    }
    else if (digitIndex == 1) { // 100
      Serial.print("-");
      Serial.print(num1);
      Serial.println("--");
    }
    else if (digitIndex == 2) { // 10
      Serial.print("--");
      Serial.print(num2);
      Serial.println("-");
    }
    else if (digitIndex == 3) {  // 1
      Serial.print(" ---");
      Serial.println(num3);
    }
    else {
      Serial.println(" error in pickDigit");
    }
  }
}

void pickNumber(byte patternIndex) {   // picks the number pattern to display (1=HIGH, 0 = LOW)
  // use this order - most to least signif digit = .gfedcba

  if (prntFlag) {
    Serial.print("    Pattern = ");
    Serial.println(PATTERN[patternIndex], BIN);
    prntBits(PATTERN[patternIndex]);    // prints bit pattern bit by bit
  }

  digitalWrite( a, bitRead( PATTERN[patternIndex], 0))  ;  // picks the 0th bit of PATTERN[picked]
  digitalWrite( b, bitRead( PATTERN[patternIndex], 1))  ;  // picks the 1st bit of PATTERN[picked]
  digitalWrite( c, bitRead( PATTERN[patternIndex], 2))  ;  // picks the 2nd bit of PATTERN[picked]
  digitalWrite( d, bitRead( PATTERN[patternIndex], 3))  ;  // picks the 3rd bit of PATTERN[picked]
  digitalWrite( e, bitRead( PATTERN[patternIndex], 4))  ;  // picks the 4th bit of PATTERN[picked]
  digitalWrite( f, bitRead( PATTERN[patternIndex], 5))  ;  // picks the 5th bit of PATTERN[picked]
  digitalWrite( g, bitRead( PATTERN[patternIndex], 6))  ;  // picks the 6th bit of PATTERN[picked]
  digitalWrite( dp, bitRead( PATTERN[patternIndex], 7))  ; // picks the 7th bit of PATTERN[picked]

}

// ISR for 1 second timer
void add () {
  // increment counter
  count++;
  // check if out of range
  if (count >= 10000) {
    count = 0;
  }
}


// this function prints the bit pattern bit by bit
void prntBits(byte b)
{
  Serial.println("     .gfe dcba");
  Serial.print("     ");
  for (int i = 7; i >= 0; i--)  // descending increments
  {
    Serial.print(bitRead(b, i));
    if (i % 4 == 0) Serial.print(" "); // put a blank between bytes for readability
  }
  Serial.println();
}