// HackerBox ESP ECG demo code (for HackerBox 0122)
//
// https://hackerboxes.com/products/hackerbox-0122-ouroboros
//

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#define TFT_DC     26
#define TFT_CS      5
#define TFT_MOSI   23
#define TFT_CLK    18
#define TFT_RST    22 
#define TFT_MISO   19
#define TFT_BL     25

#define BUTTON      4

#define ECG_SENSE  36
#define ECG_LOP    17
#define ECG_LON    16

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);

void setup() {
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);  // Backlight ON

  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(0);

  pinMode(BUTTON, INPUT_PULLDOWN);
  pinMode(ECG_SENSE, INPUT);
  pinMode(ECG_LOP, INPUT);
  pinMode(ECG_LON, INPUT);
}

void loop(void) {
  // display a simulated trace until button is pressed
  while((digitalRead(BUTTON) == LOW))
    simTrace();
  // after button, clear screen and display measured ECG
  tft.fillScreen(0);
  ECGtrace();
}

void simTrace(){
  int dx;
  dx = random(10);
  tft.drawFastHLine(0, (240-87), 20+dx, 0xFFFF);
  tft.fillRect(20+dx, 40, 54, 170, 0);
  simPRT(20+dx,175+random(25));
  tft.drawFastHLine(73+dx, (240-87), 90, 0xFFFF);
  delay(100);
  dx = random(10);
  tft.drawFastHLine(90, (240-87), 110+dx, 0xFFFF);
  tft.fillRect(200+dx, 40, 54, 170, 0);
  simPRT(200+dx,175+random(25));
  tft.drawFastHLine(253+dx, (240-87), 66+dx, 0xFFFF); 
  delay(100);
}

void simPRT(int t0, int peak) {
  int x;
  int waveP[] = {87,87,87,87,87,88,90,91,92,91,90,88,87,86,79};
  for (x=0; x<15; x++)
    tft.drawPixel(x+t0, (240-waveP[x]), 0xFFFF);
  //draw rising R spike
  tft.drawLine(15+t0, (240-79), 19+t0, (240-peak), 0xFFFF);
  //draw falling R spike
  tft.drawLine(19+t0, (240-peak), 22+t0, (240-69), 0xFFFF);
  int waveT[]={82,83,83,83,84,85,88,91,95,97,98,96,94,91,88,
               87,86,84,85,86,88,89,90,88,86,87,87,87,87,87}; 
  for (x=0; x<30; x++)
    tft.drawPixel((23+x+t0), (240-waveT[x]), 0xFFFF);

}

void ECGtrace() {
  int t, last, current;
  last=120;
  while(1) {
    for (t=0; t<320; t++){
      current = readECG();
      tft.drawFastVLine(t, 0, 240, 0x0000); //clear next column
      if (t>0) {
        tft.drawLine(t-1, last, t, current, 0xFFFF);
      }
      last = current;
    } 
  }
}

int readECG() {
  int y;
  double e;
  if ((digitalRead(ECG_LOP) == 1) || (digitalRead(ECG_LON) == 1)) {
    y = 120; //ECG leads are off, return midpoint value of 120
  } else {
    e = analogRead(ECG_SENSE);
    e = ((e / 4096) * 230); //scale from 0..4096 to 0..230
    y = round(e);
  }
  y = 240-y; //invert, since display has y=0 as top row
  return y; 
}