#include <Adafruit_SSD1306.h>
#include <SoftwareSerial.h>
#include <TinyGPS++.h>

#define OLED_Address 0x3C // I2C address for OLED
#define SIM900_RX 7       // SIM900A RX pin
#define SIM900_TX 8       // SIM900A TX pin
#define GPS_RX 4          // NEO-6M GPS RX pin
#define GPS_TX 5          // NEO-6M GPS TX pin
#define BUTTON1_PIN 2     // Push Button 1 pin
#define BUTTON2_PIN 3     // Push Button 2 pin

Adafruit_SSD1306 oled(128, 64);
SoftwareSerial sim900(SIM900_RX, SIM900_TX); // Create software serial for GSM
SoftwareSerial gpsSerial(GPS_RX, GPS_TX);     // Create software serial for GPS
TinyGPSPlus gps;

int a = 0;
int lasta = 0;
int lastb = 0;
unsigned long LastTime = 0;
unsigned long ThisTime;
bool BPMTiming = false;
bool BeatComplete = false;
int BPM = 0;
#define UpperThreshold 560
#define LowerThreshold 530
unsigned long beatInterval = 0;  // Time between beats

String simStatus = "SIM: Init";
String gsmStatus = "GSM: Init";
String gpsStatus = "GPS: Init";

void setup() {
  oled.begin(SSD1306_SWITCHCAPVCC, OLED_Address);
  oled.clearDisplay();
  oled.setTextSize(2);
  oled.setTextColor(WHITE);

  Serial.begin(9600); 
  sim900.begin(9600);   // Initialize SIM900A serial communication
  gpsSerial.begin(9600); // Initialize GPS serial communication

  pinMode(BUTTON1_PIN, INPUT_PULLUP); // Configure button pin
  pinMode(BUTTON2_PIN, INPUT_PULLUP); // Configure button pin

  delay(1000);
  checkGSM();
  checkGPS();
}

void loop() {
  if (a > 127) {
    oled.clearDisplay();
    a = 0;
    lasta = a;
  }

  ThisTime = millis();
  
  int value = analogRead(A0);
  
  int b = 60 - (value / 16);
  oled.drawLine(lasta, lastb, a, b, WHITE);
  lastb = b;
  lasta = a;

  if (value > UpperThreshold) {
    if (BPMTiming == false) {
      LastTime = millis();
      BPMTiming = true;
    }
  }

  if (value < LowerThreshold && BPMTiming) {
    beatInterval = ThisTime - LastTime;
    if (beatInterval > 0) {
      BPM = int(60 / (float(beatInterval) / 1000));
      LastTime = ThisTime;
    }
    
    BPMTiming = false;
    BeatComplete = true;
  }

  // Display SIM, GSM, and GPS statuses in the corners
  oled.setTextSize(1);
  oled.setCursor(0, 0);
  oled.print(simStatus);

  oled.setCursor(80, 0);
  oled.print(gsmStatus);

  oled.setCursor(0, 10);
  oled.print(gpsStatus);

  oled.fillRect(0, 50, 128, 16, BLACK);
  oled.setTextSize(2);
  oled.setCursor(0, 50);
  oled.print("BPM:");
  
  Serial.print("BPM: ");
  Serial.println(BPM); 

  oled.print(BPM);
  oled.display();

  a++;

  // Check GPS and GSM status periodically
  checkGSM();
  checkGPS();

  // Check button state for Button 1
  if (digitalRead(BUTTON1_PIN) == LOW) { // Button 1 pressed
    sendSOSAndCoordinates();
    delay(1000); // Debounce delay
  }
}

void checkGSM() {
  simStatus = "SIM: Init"; // Reset status
  sim900.println("AT"); // Send AT command to check connection
  delay(100);
  if (sim900.available()) {
    String response = sim900.readString();
    if (response.indexOf("OK") != -1) {
      simStatus = "SIM: OK";
      gsmStatus = "GSM: Conn"; // Update GSM status as connected
    } else {
      gsmStatus = "GSM: Fail"; // Update GSM status as failed
    }
  } else {
    gsmStatus = "GSM: Fail"; // Update GSM status as failed
  }
}

void checkGPS() {
  gpsStatus = "GPS: Init"; // Reset status
  while (gpsSerial.available() > 0) {
    gps.encode(gpsSerial.read());
    if (gps.location.isUpdated()) {
      gpsStatus = "GPS: OK"; // Update GPS status as OK when updated
      return;
    }
  }
  gpsStatus = "GPS: Fail"; // Update GPS status if no update
}

void sendSOSAndCoordinates() {
  String phoneNumber = "+1234567890"; // Replace with the desired phone number
  String sosMessage = "SOS! Emergency! Please help.";
  
  // Send SOS Message
  sim900.print("AT+CMGF=1\r"); // Set SMS mode
  delay(100);
  sim900.print("AT+CMGS=\"" + phoneNumber + "\"\r"); // Send message to specified number
  delay(100);
  sim900.print(sosMessage); // Send the SOS message
  delay(100);
  sim900.write(26); // Send CTRL+Z to send the message
  delay(1000);

  // Send Coordinates
  if (gps.location.isValid()) {
    String coordinateMessage = "Current Coordinates: Latitude: " + String(gps.location.lat(), 6) + ", Longitude: " + String(gps.location.lng(), 6);
    
    sim900.print("AT+CMGF=1\r"); // Set SMS mode
    delay(100);
    sim900.print("AT+CMGS=\"" + phoneNumber + "\"\r"); // Send message to specified number
    delay(100);
    sim900.print(coordinateMessage); // Send the coordinate message
    delay(100);
    sim900.write(26); // Send CTRL+Z to send the message
    delay(1000);
  } else {
    Serial.println("No valid GPS data.");
  }
}