#include <EEPROM.h>
#include <Adafruit_Sensor.h>
#include <RTClib.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SENSOR_PIN A0
#define SPEAKER_PIN 10
#define SOUND_CTRL_BUTTON_PIN 9
#define RECORD_CTRL_BUTTON_PIN 8
#define MENU_CTRL_BUTTON_PIN 7
#define POT1_PIN A1
#define POT2_PIN A2
#define RED_LED 13
#define YELLOW_LED 12
#define GREEN_LED 11

#define SENSOR_READINGS 10
#define READINGS_DELAY 100
#define GRAPH_HEIGHT 32
#define GRAPH_WIDTH 128

enum Language { ENGLISH, FRENCH };
Language currentLanguage = ENGLISH;

// English and French text
const String englishText[] = {"Time: ", "BPM: ", "Menu Option: ", "Menu Value: "};
const String frenchText[] = {"Temps: ", "BPM: ", "Option de menu: ", "Valeur de menu: "};

RTC_DS3231 rtc;
Adafruit_SSD1306 display1(128, 32, &Wire, -1);
Adafruit_SSD1306 display2(128, 32, &Wire, -1);

bool speakerOn = true;
int graphTimeScale = 1;
int heartRate = 0;
DateTime now;

int heartRateBuffer[10];
int bufferIndex = 0;
int eepromAddress = 0;

struct Record {
  time_t timestamp;
  int heartRate;
};

void setup() {
  Serial.begin(9600);
  
  pinMode(RED_LED, OUTPUT);
  pinMode(YELLOW_LED, OUTPUT);
  pinMode(GREEN_LED, OUTPUT);
  pinMode(SPEAKER_PIN, OUTPUT);
  pinMode(SOUND_CTRL_BUTTON_PIN, INPUT_PULLUP);
  pinMode(RECORD_CTRL_BUTTON_PIN, INPUT_PULLUP);
  pinMode(MENU_CTRL_BUTTON_PIN, INPUT_PULLUP);
  pinMode(POT1_PIN, INPUT);
  pinMode(POT2_PIN, INPUT);
  
  if(!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  if(rtc.lostPower()) {
    Serial.println("RTC lost power, let's set the time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
  
  if(!display1.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { 
    Serial.println(F("SSD1306 allocation failed!"));
    for(;;);
  }
  if(!display2.begin(SSD1306_SWITCHCAPVCC, 0x3D)) { 
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  
  display1.clearDisplay();
  display2.clearDisplay();
}

void loop() {
  // Heart rate capturing
  heartRate = readHeartRate();
  if(bufferIndex < 10) {
    heartRateBuffer[bufferIndex] = heartRate;
    bufferIndex++;
  }
  if(bufferIndex == 10 && digitalRead(RECORD_CTRL_BUTTON_PIN) == LOW) {
    Record record;
    record.timestamp = now.unixtime();
    record.heartRate = average(heartRateBuffer, 10);
    EEPROM.put(eepromAddress, record);
    eepromAddress += sizeof(Record);
    bufferIndex = 0;
    
    // Check if EEPROM is full
    if (eepromAddress >= EEPROM.length()) {
      eepromAddress = 0; // Start overwriting old records
    }
  }
  
  // Time Counting
  now = rtc.now();
  
  // Display patient's status
  displayPatientStatus(heartRate);
  
  // Sound signal
  if(digitalRead(SOUND_CTRL_BUTTON_PIN) == LOW) {
    speakerOn = !speakerOn;
  }
  beepHeartRate(heartRate);
  
  // Display on OLEDs
  displayTimeAndBPM(now, heartRate, &display1);
  displayPPG(&display2);
  
  // Menu system
  if(digitalRead(MENU_CTRL_BUTTON_PIN) == LOW) {
    handleMenu();
  }
  
  delay(1000);
}

int readHeartRate() {
  unsigned long lastPeakTime = 0;
  int beatsPerMinute = 0;
  int sensorValue = analogRead(SENSOR_PIN);
  static int lastSensorValue = 0;
  if (lastSensorValue < sensorValue) {
    lastPeakTime = millis();
  } else if (lastSensorValue > sensorValue) {
    unsigned long peakInterval = millis() - lastPeakTime;
    beatsPerMinute = 60000 / peakInterval;
  }
  lastSensorValue = sensorValue;
  return beatsPerMinute;
}


void displayPatientStatus(int heartRate) {
  digitalWrite(RED_LED, LOW);
  digitalWrite(YELLOW_LED, LOW);
  digitalWrite(GREEN_LED, LOW);
  if (heartRate < 50 || heartRate > 100) {
    digitalWrite(RED_LED, HIGH);
  }
  else if (heartRate < 60) {
    digitalWrite(YELLOW_LED, HIGH);
  }
  else {
    digitalWrite(GREEN_LED, HIGH);
  }
}

void beepHeartRate(int heartRate) {
  int frequency;
  if (heartRate < 60) {
    frequency = 200;
  }
  else if (heartRate > 100) {
    frequency = 800;
  }
  else {
    frequency = 500;
  }
  if (speakerOn) {
    tone(SPEAKER_PIN, frequency, 500);
  }
}

void displayTimeAndBPM(DateTime now, int heartRate, Adafruit_SSD1306 *display) {
  display->clearDisplay();
  display->setTextSize(1);
  display->setTextColor(WHITE);
  display->setCursor(0,0);
  
  String timeText = (currentLanguage == ENGLISH) ? englishText[0] : frenchText[0];
  String bpmText = (currentLanguage == ENGLISH) ? englishText[1] : frenchText[1];
  
  display->println(timeText + String(now.hour()) + ":" + String(now.minute()) + ":" + String(now.second()));
  display->println(bpmText + String(heartRate));
  display->display();
}

void displayMenu(int menuOption, int menuValue) {
  // Clear display
  display1.clearDisplay();
  
  // Set text properties
  display1.setTextSize(1);
  display1.setTextColor(WHITE);
  
  // Display menu options and values
  display1.setCursor(0, 0);
  
  String menuOptionText = (currentLanguage == ENGLISH) ? englishText[2] : frenchText[2];
  String menuValueText = (currentLanguage == ENGLISH) ? englishText[3] : frenchText[3];
  
  display1.print(menuOptionText);
  display1.println(menuOption);
  
  display1.setCursor(0, 10);
  display1.print(menuValueText);
  display1.println(menuValue);
  
  // Update display
  display1.display();
}

void displayPPG(Adafruit_SSD1306 *display) {
  static int x = 0;
  static int old_y = display->height() / 2;
  
  int sensorValue = analogRead(SENSOR_PIN);
  int y = map(sensorValue, 0, 1023, display->height(), 0);
  
  display->clearDisplay();
  display->drawLine(x - 1, old_y, x, y, WHITE);
  
  old_y = y;
  x++;
  if(x >= display->width()) {
    x = 0;
  }
  
  display->display();
}

void handleMenu() {
  // Menu variables
  int menuOption = 0;  // Current selected menu option
  int numMenuOptions = 3;  // Total number of menu options
  int menuValue = 0;  // Current value of the selected menu option
  
  // Menu control variables
  int potValue = 0;  // Potentiometer value
  int lastPotValue = 0;  // Previous potentiometer value
  int menuButtonState = HIGH;  // State of the menu button
  int lastMenuButtonState = HIGH;  // Previous state of the menu button
  int menuButtonPress = 0;  // Flag to detect menu button press
  
  // Menu loop
  while (true) {
    // Read potentiometer value
    potValue = analogRead(POT1_PIN);
  
    // Update menu option based on potentiometer value
    menuOption = map(potValue, 0, 1023, 0, numMenuOptions - 1);
  
    // Check for menu button press
    menuButtonState = digitalRead(MENU_CTRL_BUTTON_PIN);
    if (menuButtonState == LOW && lastMenuButtonState == HIGH) {
      menuButtonPress = 1;
    }
    lastMenuButtonState = menuButtonState;
  
    // Update menu value based on button press
    if (menuButtonPress) {
      menuValue++;
      if (menuValue > 10) {
        menuValue = 0;
      }
      menuButtonPress = 0;
    }
  
    // Display menu options and values
    displayMenu(menuOption, menuValue);
  
    // Delay to debounce inputs
    delay(100);
  }
}

void displayMenu(int menuOption, int menuValue) {
  // Clear display
  display1.clearDisplay();
  
  // Set text properties
  display1.setTextSize(1);
  display1.setTextColor(WHITE);
  
  // Display menu options and values
  display1.setCursor(0, 0);
  display1.print("Menu Option: ");
  display1.println(menuOption);
  
  display1.setCursor(0, 10);
  display1.print("Menu Value: ");
  display1.println(menuValue);
  
  // Update display
  display1.display();
}

int average(int* buffer, int size) {
  int sum = 0;
  for(int i = 0; i < size; i++) {
    sum += buffer[i];
  }
  return sum / size;
}
$abcdeabcde151015202530354045505560fghijfghij