//Travis Edrington
//For measuring and tracking BPM
//Green button, pin 8, is press sensor
//Blue displays average
//Red resets average

#define DEBUG 1 // Will we use serial output?  0 for no, 1 for yes
#define SIM 0 //For when at https://wokwi.com/projects/376282746342508545

#if DEBUG
#define PRINTS(s)   { Serial.print(F(s)); Serial.println(); }
#define PRINT(s,v)  { Serial.print(F(s)); Serial.print(": "); Serial.print(v); Serial.println(); }
#define PRINTX(s,v) { Serial.print(F(s)); Serial.print(": "); Serial.print(F("0x")); Serial.print(v, HEX); Serial.println();}
#else
#define PRINTS(s)
#define PRINT(s,v)
#define PRINTX(s,v)
#endif

const byte button_reset = 10; //For longterm logging, reset
const byte tap_input = 9; //for button
const byte data_input = 11; //for data from another device

const byte toofast = 6;
const byte fast = 5;
const byte perfect = 4;
const byte slow = 3;
const byte tooslow = 2;

float BPM = 120.0;
float BPMtarget = 110.0;
const byte BPMtolerance = 5;
const byte BPMlimit = 10;


unsigned long nowmicro;
unsigned long nowmilli;
unsigned long lastmicro;
unsigned long lastmilli;
byte lastbuttonstatus = 0;

void setup() {
  // put your setup code here, to run once:
  nowmicro = micros();
  nowmilli = millis();
  lastmicro = nowmicro;
  lastmilli = nowmilli;
  pinMode(button_reset, INPUT_PULLUP);
  pinMode(tap_input, INPUT);
  pinMode(data_input, INPUT);

  analogWrite(toofast, HIGH);
  analogWrite(fast, HIGH);
  analogWrite(perfect, HIGH);
  analogWrite(slow, HIGH);
  analogWrite(tooslow, HIGH);

  #if DEBUG
  Serial.begin(9600);
  while (!Serial) {
    ;  // wait for serial port to connect. Needed for native USB port only
  }
  #endif
}

void loop() {
  Serial.println(digitalRead(data_input));

  // put your main code here, to run repeatedly:
  if ((digitalRead(tap_input) == HIGH) and (lastbuttonstatus == 0)) {  //Button down
    nowmicro = micros();
    nowmilli = millis();
    BPM = (float)60000000 / (nowmicro - lastmicro);

#if DEBUG
    PRINTS("");
    PRINT("∆micros", nowmicro - lastmicro);
    PRINT("∆millis", nowmilli - lastmilli);
    
    PRINT("BPM micros", BPM);
    PRINT("BPM millis", (float)60000 / (nowmilli - lastmilli));
#endif


    analogWrite(toofast, 0);
    analogWrite(fast, 0);
    analogWrite(perfect, 0);
    analogWrite(slow, 0);
    analogWrite(tooslow, 0);

    float BPMDelta = BPM - BPMtarget;

    if (abs(BPMDelta) < BPMtolerance) {
      analogWrite(perfect, 255);
    } else if (abs(BPMDelta) < BPMlimit) {
      if (BPMDelta < 0) {
        //within acceptable limits but BPM is slower than target
        analogWrite(slow, 255);
      } else {
        analogWrite(fast, 255);
      }
    } else {
      if (BPMDelta < 0) {
        //not within acceptable limits and BPM is slower than target
        analogWrite(tooslow, 255);
      } else {
        analogWrite(toofast, 255);
      }
    }

    lastmicro = nowmicro;
    lastmilli = nowmilli;
    lastbuttonstatus = 30;
  } else if ((digitalRead(tap_input) == LOW) && (lastbuttonstatus > 0)) {
    lastbuttonstatus = lastbuttonstatus - 1;
  }
}