/*
  HiFiLOGIX 0.2.0 (Fix 1)
  
  dewdude@gmail.com - 12-JAN-2019

  !!! IMPORTANT NOTICE !!!
  
  As of 0.2.0 EEPROM support is no longer considered to be beta and has been
  fully integrated in to the main build. You should be aware of the following:
  
  It uses EEPROM addresses 1020 - 1023
  It will erase any data you may have there during the initilization routine.
  
  If your EEPROM is smaller, or you don't want to use 1020 - 1023; then you'll
  need to change their #define to match what you want/need. 
  
  Pin 2 is used for the hardware interrupt trigger that writes the data. It's
  set to run fall. This will be done in hardware by isolating a capacitor for
  the Arduino and tying pin 2 to the part of the power supply that will drop 
  first. The reserve current should last long enough to update the values before
  draining. 
  
 */
#include <Wire.h>
#include <U8g2lib.h>
#include <IRremote.h>
#include <avr/pgmspace.h> 
#include <EEPROM.h>
#define di 1022
#define dx 1021
#define db 1020
#define dt 1023
#include "logo.h" // XBMP data for logo.

U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE); 

const char in0[] PROGMEM = "TAPE-2";
const char in1[] PROGMEM = "TAPE-1";
const char in2[] PROGMEM = "AUX";
const char in3[] PROGMEM = "TUNER";
const char in4[] PROGMEM = "PHONO-1";
const char in5[] PROGMEM = "PHONO-2";

const char * const inputs[] PROGMEM ={in0,in1,in2,in3,in4,in5};
// scl to pin 28
// sdl pin 27
int latchPin = 11; // 328 pin 17 - 595 pin 12
int clockPin = 9; // 15 - pin 11
int dataPin = 12; // 18 - 14
int IRin = 7; //13 
int blanking = 5; // 11
int matrix = A1; // 23
byte eop = 0;
byte ex = 0;
byte ei = 0;
IRrecv remote(IRin);
decode_results ircode;
char txt[8];

void DontCrossTheStreams(byte op, byte x, byte i)           // There's something very important I forgot to tell you.
{															// Don't cross the streams.
    strcpy_P(txt, (char*)pgm_read_word(&(inputs[i])));      // Why?
    digitalWrite(latchPin, LOW);                            // It would be bad.
    shiftOut(dataPin, clockPin, LSBFIRST, op);              // What do you mean, bad?
    digitalWrite(latchPin, HIGH);                           // Imagine all life as you know
    u8g2.clearBuffer();                                     // it stopping instaneously
    u8g2.drawStr(x,30,txt);                                 // and every molecule in
    u8g2.sendBuffer();                                      // your body exploding
    eop = op; ex = x; ei = i;                               // at the speed of light.  
 // Total protonic reversal.                                // That's bad.
 //lastbreath();
}// Important safety tip, thanks Egon.



void eeprominit() {                                         // This checks the EEPROM to see if it's
                                                            // been initialized by the code before.
if (EEPROM.read(dt) == 'F') {                               // Check address 1023 for init flag "T"
    return;
  } else {
    EEPROM.write(db, 16);
    EEPROM.write(dx, 32);
    EEPROM.write(di, 2);
    EEPROM.write(dt, 'F');
  }
}

void lastbreath() {				// The idea here is to throw a large capacitor on to the voltage rail
  EEPROM.write(db, eop);		// powering the Arduino; but keep it from powering anything else. 
  EEPROM.write(dx, ex);		// Monitor the "other" 5V rail with pin 2 and trigger an interrupt
  EEPROM.write(di, ei);		// and rely on the caps charge to keep charge long enough to write. 
}

void annoyingtrick() {
  u8g2.clearBuffer();                                     // it stopping instaneously
    u8g2.drawStr(22,30,"RAVE");                                 // and every molecule in
    u8g2.sendBuffer();
  for (int b = 0; b <=20000; b++){
    byte trick = 0;
    trick = random(1,127);
    digitalWrite(latchPin, LOW);                            // It would be bad.
    shiftOut(dataPin, clockPin, LSBFIRST, trick);              // What do you mean, bad?
    digitalWrite(latchPin, HIGH); 
    delay(25);}
    DontCrossTheStreams(16,32,2);
}
void setup()
{
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
  pinMode(blanking, OUTPUT);
  eeprominit();
  u8g2.begin();
  remote.enableIRIn();
  u8g2.firstPage();                       // Logo is now bitmapped and since I only call it
    do {                                  // once, it doesn't need it's own function.
    u8g2.drawXBMP(14,4,hifilogix_width,hifilogix_height,hifilogix_bits);
    } while ( u8g2.nextPage() );
  delay(2000);                            // It takes the Denon about 4.5 seconds to kick speakers on.
  u8g2.setFont(u8g2_font_logisoso28_tr);  
  DontCrossTheStreams(EEPROM.read(db),EEPROM.read(dx),EEPROM.read(di));  // Read settings stored in EEPROM.
  digitalWrite(blanking,HIGH);            // Now drives a logic inverter.
  attachInterrupt (digitalPinToInterrupt(2), lastbreath, FALLING); // Write the values before your cap discharges!
  attachInterrupt (digitalPinToInterrupt(2), lastbreath, CHANGE); // Write the values before your cap discharges! 
  attachInterrupt (digitalPinToInterrupt(2), lastbreath, LOW);            
}

void loop()
{
int mx = analogRead(matrix);
byte icode = 0;                           // I changed how I handed the inputs.
if (remote.decode(&ircode)) {
    icode = ircode.value;
    remote.resume();    
}
// I don't know if it improves things, but I sure like how much smaller this section is.      
if ((mx > 850 && mx < 860) || (icode == 0x97)) DontCrossTheStreams(64,10,0); // The code I originally used to figure out my
if ((mx > 2 && mx < 5)     || (icode == 0x67)) DontCrossTheStreams(32,10,1); // remote codes returned 3 bytes in hex. I can't 
if ((mx > 45 && mx < 50)   || (icode == 0x4F)) DontCrossTheStreams(16,32,2); // remember what that code was, but I only need 
if ((mx > 950 && mx < 970)  || (icode == 0xCF)) DontCrossTheStreams(8,18,3);  // the last bit with the remote I'm using. 
if ((mx > 22 && mx < 30) || (icode == 0xE7)) DontCrossTheStreams(6,1,4);   // I'm working on making the bare-bones utility I
if ((mx > 990 && mx < 1010) || (icode == 0x85)) DontCrossTheStreams(5,1,5);   // wrote a bit more user-friendly.
if (icode == 0xAD) annoyingtrick();
delay(200);
}
