/*********
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/ttgo-lora32-sx1276-arduino-ide/
*********/
#define OLED
#define BAT

//Libraries for LoRa
#include <SPI.h>
#include <LoRa.h>

//Libraries for OLED Display
#ifdef OLED
  #include <Wire.h>
  #include <Adafruit_GFX.h>
  #include <Adafruit_SSD1306.h>
#endif

//#include "SSD1306.h" // alias for `#include "SSD1306Wire.h"

//define the pins used by the LoRa transceiver module
#define SCK 5
#define MISO 19
#define MOSI 27
#define SS 18
#define RST 14
#define DIO0 26

//433E6 for Asia
//866E6 for Europe
//915E6 for North America
#define BAND 866E6

#ifdef OLED
//OLED pins
  #define OLED_SDA 4
  #define OLED_SCL 15 
  #define OLED_RST 16
  #define SCREEN_WIDTH 128 // OLED display width, in pixels
  #define SCREEN_HEIGHT 64 // OLED display height, in pixels
  Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RST);
#endif

#ifdef SLEEP
// deep sleep 
#define uS_TO_S_FACTOR 1000000  // conversion factor for micro seconds to seconds 
#define TIME_TO_SLEEP  360       // time ESP32 will go to sleep (in seconds)   - 99 for (about) 1% duty cycle  
uint64_t  sleepfor = uS_TO_S_FACTOR * TIME_TO_SLEEP;
#endif

// stores the data on the RTC memory so that it will not be deleted during the deep sleep
RTC_DATA_ATTR int bootCount = 0; 
RTC_DATA_ATTR int pckCounter = 0;   // sending packet number...


#define BUTTON_PIN_BITMASK 0x1000000000 // 2^36 in hex

#ifdef BAT
const uint8_t vbatPin = 37;
double VBAT;  // battery voltage from ESP32 ADC read
#endif


String reason = "Dont know            ";

void setup() {
  Serial.begin(115200);
  pinMode(2,OUTPUT);
  Serial.println("LoRa low power Sender Test");
  //SPI LoRa pins
  SPI.begin(SCK, MISO, MOSI, SS);
  //setup LoRa transceiver module
  LoRa.setPins(SS, RST, DIO0);
  if (!LoRa.begin(BAND)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
  Serial.println("LoRa init completed"); 
       
  print_wakeup_reason();
 
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_36,1); //1 = High, 0 = Low
  
#ifdef OLED
  //reset OLED display via software
  pinMode(OLED_RST, OUTPUT);
  digitalWrite(OLED_RST, LOW);
  delay(20);
  digitalWrite(OLED_RST, HIGH);
  //initialize OLED
  Wire.begin(OLED_SDA, OLED_SCL);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }  
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.setCursor(0,0);
  display.print("LORA low power sender ");
  display.setCursor(0,10);
  display.print(reason);
  display.display();
  delay(1000);
#endif 
  
  //Increments boot number and prints it every reboot
  bootCount++;
  Serial.println("Boot number: " + String(bootCount));
#ifdef SLEEP
  esp_sleep_enable_timer_wakeup(sleepfor);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds");
#endif
  Serial.println("Going to sleep now");
  Serial.flush();   // waits for the transmission of outgoing serial data to complete 
  digitalWrite(2, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(2, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);        
  esp_deep_sleep_start();  
 
}

void loop() {  }

void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); 
        // send packet
      reason = "Found someone "+String(bootCount);
      LoRa.beginPacket();
      LoRa.print("! Found someone ");
      LoRa.print(bootCount);
      LoRa.endPacket();
    break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); 
    // send packet
      reason = "Timer ";
#ifdef BAT
      VBAT = ReadVoltage(vbatPin);
      Serial.print("Vbat = "); Serial.print(VBAT); Serial.println(" Volts");
      LoRa.beginPacket();
      LoRa.print(String(VBAT));
      LoRa.print(bootCount);
      LoRa.endPacket();
#endif
    break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

#ifdef BAT
double ReadVoltage(byte pin){
  double reading = analogRead(pin); // Reference voltage is 3v3 so maximum reading is 3v3 = 4095 in range 0 to 4095
  if(reading < 1 || reading > 4095) return 0;
  // return -0.000000000009824 * pow(reading,3) + 0.000000016557283 * pow(reading,2) + 0.000854596860691 * reading + 0.065440348345433;
  return -0.000000000000016 * pow(reading,4) + 0.000000000118171 * pow(reading,3)- 0.000000301211691 * pow(reading,2)+ 0.001109019271794 * reading + 0.034143524634089;
} // Added an improved polynomial, use either, comment out as required
#endif
