#include "tinysnore.h"
#include <Arduino.h>

// Define to enable serial debug
// messages on pin 1
#define debug

// Pin connected to the ESP-01's CH_PD pin (Pin 3)
#define esp_enable_pin 4
// Pin connected to the ESP-01's feedback pin (UTXD / Pin 1)
#define esp_status_pin 3

// Wake up the ESP-01 every 5 minutes
const long update_interval = 1000L * 60L * 5L;
// Cut power to the ESP-01 if the update takes longer than 30 seconds
const long update_timeout = 1000L * 30L;

#ifdef debug
#include <SoftwareSerial.h>
SoftwareSerial Debug(PB0, PB1);
#endif

void setup() {
#ifdef debug
  Debug.begin(9600);
  Debug.println("-> Reset");
#endif
  pinMode(esp_enable_pin, OUTPUT);
  pinMode(esp_status_pin, INPUT_PULLUP);
}

unsigned long runESP() {
  // Reset the ESP
  digitalWrite(esp_enable_pin, LOW);
  snore(100);
  digitalWrite(esp_enable_pin, HIGH);
  // Wait 0.2s for the ESP to boot up
  snore(200);
  // Wait until either the status pin gets pulled HIGH
  // by the ESP or `update_timeout` milliseconds have passed
  unsigned long elapsed_time_ms = 0;
  while (digitalRead(esp_status_pin) == LOW &&
         elapsed_time_ms < update_timeout) {
    snore(100);
    elapsed_time_ms += 100;
  }
  // Turn off the ESP
  digitalWrite(esp_enable_pin, LOW);

  // Return time the mcu was asleep
  return 100L + 200L + elapsed_time_ms;
}

void loop() {
  // Store the current time
  unsigned long start_time = millis();
#ifdef debug
  Debug.print("Start time: ");
  Debug.println(start_time);
  Debug.println("-> Running ESP");
#endif
  // Run the ESP and store the sleep time
  long elapsed_asleep = runESP();
  // Calculate elapsed time the mcu was awake
  long elapsed_awake = millis() - start_time;
  // Calculate the total elapsed time
  long delta_time = elapsed_awake + elapsed_asleep;
  // Sleep until next interval
  long sleep_time = max(0, update_interval - delta_time);
#ifdef debug
  Debug.println("-> ESP Done");
  Debug.print("Took: ");
  Debug.println(delta_time);
  Debug.print("-> Sleeping for ");
  Debug.println(sleep_time);
#endif
  snore(sleep_time);
}