/*
 * Computer Switchboard
 * 
 * Because interfacing with computers should be fun
 * and a keyboard is not enough.
 * 
 * Let's turn a computer into an airplane (interface wise).
 * 
 */

 //todo: debounce, see neotimer

//makes serial slower so it can be read
#define DEBUGMODE 0

#include <avr/io.h>
#include <avr/interrupt.h>

 

/*  SevenSegmentLEDdisplay102a.ino
 *   2017-02-20
 *   Mel Lester Jr.
 *  Simple example of using Shift Register with a
 *  Single Digit Seven Segment LED Display
*/
// Globals
const int dataPin = 4;  // blue wire to 74HC595 pin 14
const int latchPin = 7; // green to 74HC595 pin 12
const int clockPin = 8; // yellow to 74HC595 pin 11

/* uncomment one of the following lines that describes your display
 *  and comment out the line that does not describe your display */
const char common = 'a';    // common anode
//const char common = 'c';    // common cathode

bool decPt = true;  // decimal point display flag


//switch

// digital pin 9 has a pushbutton attached to it. Give it a name:
int pushButton = 9;


//rotary

// -----
// SimplePollRotator.ino - Example for the RotaryEncoder library.
// This class is implemented for use with the Arduino environment.
// Copyright (c) by Matthias Hertel, http://www.mathertel.de
// This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
// More information on: http://www.mathertel.de/Arduino
// -----
// 18.01.2014 created by Matthias Hertel
// -----

// This example checks the state of the rotary encoder in the loop() function.
// The current position is printed on output when changed.

// Hardware setup:
// Attach a rotary encoder with output pins to A2 and A3.
// The common contact should be attached to ground.

#include <RotaryEncoder.h>

// Setup a RoraryEncoder for pins A2 and A3:
//RotaryEncoder encoder(A2, A1);
RotaryEncoder encoder(A1, A2);
int difference = 0;



uint8_t segdisp = 0;






//Timer
//http://maxembedded.com/2011/06/avr-timers-timer1/

// global variable to count the number of overflows
volatile uint8_t tot_overflow;

volatile uint8_t ClearTimer = 0;

uint8_t buttonpressed = 0;

// TIMER1 overflow interrupt service routine
// called whenever TCNT1 overflows
ISR(TIMER1_OVF_vect)
{
    // keep a track of number of overflows
    tot_overflow++;
    //Serial.println("Timer works!1");
 
    // check for number of overflows here itself
    // 61 overflows = 2 seconds delay (approx.) //EDIT: NO it's not in atmega328p nano.
                                                
    //if (tot_overflow >= 2) // NOTE: '>=' used instead of '=='
    if (tot_overflow >= 100) // NOTE: '>=' used instead of '=='
    {
        buttonpressed = 0;
        //PORTC ^= (1 << 0);  // toggles the led
        // no timer reset required here as the timer
        // is reset every time it overflows

        if(DEBUGMODE){
          Serial.println("Timer works!2");
        }
        tot_overflow = 0;   // reset overflow counter
        
        ClearTimer = 1; //clear interrupts / timer outside of interrupt
        delay(10);
    }
}
 

 
void setup() {
  // initialize I/O pins
  pinMode(dataPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);

  Serial.begin(9600);

  pinMode(pushButton, INPUT_PULLUP);
  
  timer1_init();

  
}

void loop() {

  if (ClearTimer == 1){
    cli();

    if(DEBUGMODE){
      Serial.println("Ready"); //this doesn't print correctly unless you remove ClearTimer to zero below.
      delay(50);
    }
    else{
    //Serial.println("Ready"); //this doesn't print correctly unless you remove ClearTimer to zero below.
    delay(50);
    ClearTimer = 0; //comment this, and uncomment ready for debugging.
    }
  }
 
  //decPt = !decPt; // display decimal point every other pass through loop

  // generate characters to display for hexidecimal numbers 0 to F
 /* for (int i = 0; i <= 15; i++) {
    byte bits = myfnNumToBits(i) ;
    if (decPt) {
      bits = bits | B00000001;  // add decimal point if needed
    }
    myfnUpdateDisplay(bits);    // display alphanumeric digit
    delay(500);                 // pause for 1/2 second
  }*/

  byte bits = myfnNumToBits(segdisp);
  if (decPt) {
      bits = bits | B00000001;  // add decimal point if switch high
    }
  
  myfnUpdateDisplay(bits);




  //ROTARY

  static uint8_t pos = 0;
  encoder.tick();

  uint8_t newPos = encoder.getPosition();
  if (pos != newPos) {
    difference = pos - newPos;
    
    
    //Serial.print(newPos);
    //Serial.println();
    //Serial.println(difference);
    pos = newPos;

    segdisp = (segdisp + difference);
    segdisp = segdisp & B00000111;//only give me the last three bits
                                  //if there is anything there, so and.
                                  //gives me 0-7  
    
    //Serial.println(segdisp);
   
  } 



//BUTTONS

  int resultb = 0;
  resultb = PINB;
  delay(100);
  if (resultb == 0 && buttonpressed == 0){
                       // turn on ~3 second delay, for debounce
                       
    decPt = 1;
    buttonpressed = 1;
    Serial.print("User Pressed button: ");
    Serial.println(segdisp);
    delay(50);     // delay to cheat interrupts stopping me.
    sei();
    delay(100);
  }
  else{
    decPt = 0;
  }
  // too fast, print serial when checking switch only
  // Serial.println(resultb,BIN); // noisy, but reads 0 when low.
} 



void myfnUpdateDisplay(byte eightBits) {
  if (common == 'a') {                  // using a common anonde display?
    eightBits = eightBits ^ B11111111;  // then flip all bits using XOR 
  }
  digitalWrite(latchPin, LOW);  // prepare shift register for data
  shiftOut(dataPin, clockPin, LSBFIRST, eightBits); // send data
  digitalWrite(latchPin, HIGH); // update display
}

byte myfnNumToBits(int someNumber) {
  switch (someNumber) {
    case 0:
      return B11111100;
      break;
    case 1:
      return B01100000;
      break;
    case 2:
      return B11011010;
      break;
    case 3:
      return B11110010;
      break;
    case 4:
      return B01100110;
      break;
    case 5:
      return B10110110;
      break;
    case 6:
      return B10111110;
      break;
    case 7:
      return B11100000;
      break;
    case 8:
      return B11111110;
      break;
    case 9:
      return B11110110;
      break;
    case 10:
      return B11101110; // Hexidecimal A
      break;
    case 11:
      return B00111110; // Hexidecimal B
      break;
    case 12:
      return B10011100; // Hexidecimal C or use for Centigrade
      break;
    case 13:
      return B01111010; // Hexidecimal D
      break;
    case 14:
      return B10011110; // Hexidecimal E
      break;
    case 15:
      return B10001110; // Hexidecimal F or use for Fahrenheit
      break;  
    default:
      return B10010010; // Error condition, displays three vertical bars
      break;   
  }




}



 
// initialize timer, interrupt and variable
void timer1_init()
{
    // set up timer with prescaler 
    TCCR1B |= (1 << CS10);
    TCCR1B |= (1 << CS11);
 
    // initialize counter
    TCNT1 = 0;
 
    // enable overflow interrupt
    // TIMSK |= (1 << TOIE1); //doesn't work, not in atmega328p
    // but data sheet has...
    // in section 12 (why the f, isn't there a table of contents in my data sheet?)
    TIMSK1 |= (1 << TOIE1);
    
    // enable global interrupts
    // I'll do this when a button pressed
    // sei();
 
    // initialize overflow counter variable
    tot_overflow = 0;
}


