/******************************************************************
 ******************************************************************
 *
 * Project: Electronic Launch Controller
 * Description: A single rod model rocket electronic launch 
 *              controller. Controller has a key to lock out power. 
 *              Switch to check continuity once key is turned on. 
 *              Ten second countdown timer. Momentary power switch 
 *              with simultaneous safety switch to fire rocket. 
 *              
 *              Has a temperature, humidty and pressure sensor which 
 *              is displayed on an LCD screen. 
 *              
 *              Also incorporates a RTC to display time on a 4-digit 
 *              7-segment LED.
 *             
 *              May also be able to incorporate a volt 
 *              meter into the LCD screen
 *              
 * Creation date: February 1, 2022 through
 * Author: Robert W. Austin
 * (C) Austin Aerospace Education Network
 * License: GPL-3.0
 * 
 * ================================================================
 * Based on the following coding examples:
 *  DHT 11 Sensor code  
 *  https://create.arduino.cc/projecthub/arcaegecengiz/using-dht11-b0f365
 *   
 *  TM1637 Clock Example  
 *  https://www.makerguides.com/tm1637-arduino-tutorial/
 *  
 *  Voltage Measurement Example
 *  https://www.instructables.com/Voltage-Measurement-Using-Arduino/
 *  
 *  16x2 LCD display  
 *  Elegoo starter kit code 
 *  
 *  Voltage Measurement
 *  https://www.instructables.com/Voltage-Measurement-Using-Arduino/
 *  
 *  Voltage Divider Calculator
 *  https://ohmslawcalculator.com/voltage-divider-calculator
 * ================================================================
 * Pin configuration - for Uno board 
 *   
 * TM1637 4-Digit 7-Segment LCD Display
 *   VIN  5V 
 *   GND  GND
 *   CLK  D4
 *   DIO  D5
 * 
 * DHT-11 Temp & Humidity Sensor
 *   VIN  5V
 *   GND  GND
 *   DATA D6
 *     
 * LCD 2-Line 16-Character Display
 *   VSS  GND
 *   VDD  5V
 *   V0   Potentiometer 
 *   RS   D7
 *   RW   GND
 *   E    D8
 *   DB4  D9  (PWM)
 *   DB5  D10 (PWM/SS)
 *   DB6  D11 (PWM/MOSI)
 *   DB7  D12 (MISO)
 *   A    5V
 *   K    GND
 *   
 * RTC Real Time Clock
 *   VIN  5V
 *   GND  GND
 *   SDA  A4 
 *   SCL  A5
 *   
 * BMP180 Pressure Sensor
 *   VIN  5V
 *   GND  GND
 *   SDA  A4
 *   SCL  A5
 *   
 * Relay  
 *   VIN  5V
 *   GND  GND
 *   SIG  A3 
 *   
 * Fire Switch
 *   Red  D2
 *   GND  GND
 *   
 * Safety Switch
 *   Red  A2
 *   GND  GND
 *  
 * Peizo Buzzer 
 *   SIG  A1
 *   GND  GND
 *   
 * Battery Voltage
 *   SIG  A0
 *   GND  GND
 * 
 ******************************************************************
 *****************************************************************/ 
 

/****************************************************************** 
 ******************************************************************
 *                                                                *
 *                        LIBRARIES                               *
 *                                                                *
 ******************************************************************
 *****************************************************************/

// ================================================================
// libraries required for the DHT-11 Sensor
   #include <dht11.h>

// ================================================================
// libraries required for the BMP180 Sensor
   #include <SFE_BMP180.h>

// ================================================================
// libraries required for the Liquid Crystal Display
   #include <LiquidCrystal.h>

// ================================================================
// libraries required for the RTC DS1307
   #include "RTClib.h"

// ================================================================
// libraries required for the TM1637 display
  #include <TM1637Display.h>

// ================================================================
// libraries required for any button to debounce
   #include <ezButton.h>

/******************************************************************
 ******************************************************************
 *                                                                *
 *                        DECLARATIONS                            *
 *                                                                *
 ******************************************************************
 *****************************************************************/

// ================================================================
// declarations for Program Version
   const uint8_t prgMajor = 0;
   const uint8_t prgMinor = 6;
   const uint8_t prgPatch = 0;

// ================================================================
// declarations required for the DHT-11 sensor
   #define DHT11PIN 6

// You will need to create an DHT-11 object,
// identified here called "dhtHumiditySensor"
   dht11 dhtSensor;
   int checkDHT;
   float dhtHumidity,dhtTemp;

// ================================================================
// declarations required for the BMP-180
// You will need to create an SFE_BMP180 object, identified here 
// as "baroPressure"
   SFE_BMP180 baroPressure;   

// Base altitude of AAEN in Oxford, AL (in meters)
   #define baseElevation 188.976  

// variables for sensor readings
// currentTemp = temperature (old T) 
// absolutePress = pressure (old P)
// relativePress = sea level pressure (old p0)
   double currentTemp,absolutePress,relativePress;                   

// variable to report on status of sensor                
   char bmp180Status;

// ================================================================
// declarations required for the LCD
//                BS E  D4 D5  D6  D7
   LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

   const int lcdButtonPin = 3;
   volatile int lcdScreenDisplay;
   
// ================================================================
// TEMP for debouncing
   unsigned long button_time = 0;
   unsigned long last_button_time = 0;

// ================================================================
// declarations required for the RTC DS1307
   RTC_DS3231 rtc;
   int displayTime;
   int displayYear;
   int displayMonth;
   int displayDay;

// ================================================================
// declarations required for Fire and Safety Switch
   const int fireButtonPin = 2;
   const int safetyButtonPin = A2;
   const int fireRelayPin = A3;
   volatile int fireCountdown;

// ================================================================
// declarations for peizo buzzer
   int buzzer = A1;

// ================================================================
// declarations for variables for millis instead of using delay
   int waitPeriod = 2000;
   unsigned long timeNow = 0;

// ================================================================
// declarations required for the voltage meter 
// set up for 6 volt battery
   int valuePin0 = 0;
   float voltage;
 
   // these resistor values are for a 6-volt battery
   // adjust the value if using a different voltage battery
   float R1 = 10000.0;
   float R2 = 51000.0;
   
  
// ================================================================
// declarations required for the TM1637 4-digit display
   #define CLK 4
   #define DIO 5
   TM1637Display clockDisplay = TM1637Display(CLK, DIO);
   
// ================================================================
// Constants for 4-Digit 7-segment display
   const uint8_t SEG_BOOT[] = 
   {
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,  // B
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,          // O
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,          // O
   SEG_D | SEG_E | SEG_F | SEG_G                           // t
   };

// Constants for PASS
   const uint8_t SEG_PASS[] = 
   {
   SEG_A | SEG_B | SEG_E | SEG_F | SEG_G,          // P
   SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,  // A
   SEG_A | SEG_C | SEG_D | SEG_F | SEG_G,          // S
   SEG_A | SEG_C | SEG_D | SEG_F | SEG_G           // S
   };

// Constants for FAIL
   const uint8_t SEG_FAIL[] = 
   {
   SEG_A | SEG_E | SEG_F | SEG_G,                  // F
   SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,  // A
   SEG_E | SEG_F,                                  // I
   SEG_D | SEG_E | SEG_F                           // L
   };

// Constants for FIRE
   const uint8_t SEG_FIRE[] = 
   {
   SEG_A | SEG_E | SEG_F | SEG_G,                  // F
   SEG_E | SEG_F,                                  // I
   SEG_E | SEG_G,                                  // R
   SEG_A | SEG_D | SEG_E | SEG_F | SEG_G           // E  
   };

// Constants for SAFE
   const uint8_t SEG_SAFE[] = 
   {
   SEG_A | SEG_C | SEG_D | SEG_F | SEG_G,          // S
   SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,  // A
   SEG_A | SEG_E | SEG_F | SEG_G,                  // F
   SEG_A | SEG_D | SEG_E | SEG_F | SEG_G           // E
   };

// Constants for STAY
   const uint8_t SEG_STAY[] = 
   {
   SEG_A | SEG_C | SEG_D | SEG_F | SEG_G,          // S
   SEG_D | SEG_E | SEG_F | SEG_G,                  // t
   SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,  // A
   SEG_B | SEG_C | SEG_D | SEG_F | SEG_G           // Y
   };

// Constants for AWAY
   const uint8_t SEG_AWAY[] = 
   {
   SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,  // A
   SEG_C | SEG_D | SEG_E,                          // W
   SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,  // A
   SEG_B | SEG_C | SEG_D | SEG_F | SEG_G           // Y
   };

const uint8_t SEG_10[] = 
   {
   SEG_D | SEG_E | SEG_F | SEG_G,                 // t
   SEG_G,                                         // -
   SEG_B | SEG_C ,                                // 1
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F  // O
   };

const uint8_t SEG_09[] = 
   {
   SEG_D | SEG_E | SEG_F | SEG_G,                   // t
   SEG_G,                                           // -
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,   // O
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G    // 9
   };

const uint8_t SEG_08[] = 
   {
   SEG_D | SEG_E | SEG_F | SEG_G,                           // t
   SEG_G,                                                   // -
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,           // O
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G    // 8
   };

const uint8_t SEG_07[] = 
   {
   SEG_D | SEG_E | SEG_F | SEG_G,                           // t
   SEG_G,                                                   // -
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,           // O
   SEG_A | SEG_B | SEG_C                                    // 7
   };

const uint8_t SEG_06[] = 
   {
   SEG_D | SEG_E | SEG_F | SEG_G,                           // t
   SEG_G,                                                   // -
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,           // O
   SEG_A | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G            // 6
   };

const uint8_t SEG_05[] = 
   {
   SEG_D | SEG_E | SEG_F | SEG_G,                           // t
   SEG_G,                                                   // -
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,           // O
   SEG_A | SEG_C | SEG_D | SEG_F | SEG_G                    // 5
   };

const uint8_t SEG_04[] = 
   {
   SEG_D | SEG_E | SEG_F | SEG_G,                           // t
   SEG_G,                                                   // -
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,           // O
   SEG_B | SEG_C | SEG_F | SEG_G                            // 4
   };

const uint8_t SEG_03[] = 
   {
   SEG_D | SEG_E | SEG_F | SEG_G,                           // t
   SEG_G,                                                   // -
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,           // O
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_G                    // 3
   };

const uint8_t SEG_02[] = 
   {
   SEG_D | SEG_E | SEG_F | SEG_G,                           // t
   SEG_G,                                                   // -
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,           // O
   SEG_A | SEG_B | SEG_D | SEG_F | SEG_G                    // 2
   };

const uint8_t SEG_01[] = 
   {
   SEG_D | SEG_E | SEG_F | SEG_G,                           // t
   SEG_G,                                                   // -
   SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,           // O
   SEG_B | SEG_C                                            // 1
   }; 


/******************************************************************
 ******************************************************************
 *                                                                *
 *                            SETUP                               *
 *                                                                *
 ******************************************************************
 ******************************************************************/

void setup()
{
  
  // ==============================================================
  // Turn on LED lamp to show Arduino has power
     pinMode(LED_BUILTIN, OUTPUT);
     digitalWrite(LED_BUILTIN, HIGH);
  
  // ==============================================================
  // Initialize LCD cols and rows (cols = 16, rows = 2)
     lcd.begin(16,2);

  // Display splash screen 1 on LCD
     splashScreenLCD1();  
    
  // ==============================================================
  // Setup for 4-Digit LED display
  // Set the display brightness (0-7):
     clockDisplay.setBrightness(5);

  // Clear the display:
     clockDisplay.clear(); 

  // show BOOT on LED
     clockDisplay.setSegments(SEG_BOOT);
 
  // ==============================================================
  // Initialize the serial port.
  // Start Serial monitor - used for debugging
     Serial.begin(9600);  

  // Wait for console opening:
     delay(3000);  

  // Display splash screen 2 on LCD
     splashScreenLCD2(); 
  
  // Display splash screen on serial monitor
     splashScreen();   
     delay(3000);
  
  // ==============================================================
  // Setup for RTC 
    Serial.println(F("Initializing Real Time Clock Module. Standby..."));

  // Check if RTC is connected correctly
     if (! rtc.begin()) 
     {
      // show error in Serial Monitor
         Serial.println(F("Unable to find Real Time Clock"));

      // show error on LCD
         lcd.setCursor(0,0);
         lcd.print(F("Unable to find           "));
         lcd.setCursor(0,1);
         lcd.print(F("Real Time Clock           "));

      // show FAIL on LED
         clockDisplay.setSegments(SEG_FAIL);
      
      //pause program
       while (1);
     }
     else
     {
      //show success in Serial Monitor
        Serial.println(F("Real Time Clock initialized"));
        Serial.println();
     }
  
  // Check if the RTC lost power and if so, set the time
     if (rtc.lostPower()) 
     {
      Serial.println(F("It appears the Real time Clock lost power.")); 
      Serial.println(F("Adjusting date and time to equal sketch compile"));
      Serial.println();
    
      // The following line sets the RTC to the date & time this sketch 
      // was compiled
      rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
     }
     else
     {
      Serial.println(F("No indication of RTC power loss"));
      Serial.println();    
     }

  // ==============================================================
  // Setup for BMP-180
  
     Serial.println(F("Initializing BMP180 pressure sensor. Standby..."));  

  // Initialize the sensor (it is important to get calibration values 
  // stored on the device).
     if (baroPressure.begin())
     {
      // Sensor initiated
      Serial.println(F("BMP180 sensor initialization successful"));
      Serial.println();
     }  
     else
     {
      // Something went wrong, this is usually a connection problem,
      // See the comments at the top of this sketch for the proper connections.
      Serial.println(F("BMP180 sensor initialization failed. Check connections and reset system."));

      //show error on LCD
      lcd.setCursor(0,0);
      lcd.print(F("BMP Sensor Fail "));
      lcd.setCursor(0,1);
      lcd.print(F("to Initialize   "));

      // show FAIL on LED
      clockDisplay.setSegments(SEG_FAIL);
    
      while(1); // Pause forever.
     }

  // ==============================================================
  // Setup for DHT-11
     Serial.println(F("Initializing DHT11 humidity sensor. Standby..."));

     checkDHT = dhtSensor.read(DHT11PIN);
  
     if (checkDHT != -2)
     {
      // Sensor initiated
      Serial.println(F("DHT11 sensor initialization successful"));
      Serial.println();
     }
      else
    {
    // Something went wrong, this is usually a connection problem,
    // See the comments at the top of this sketch for the proper connections.
    Serial.println(F("DHT11 sensor initialization failed. Check connections and reset system."));

    //show error on LCD
    lcd.setCursor(0,0);
    lcd.print(F("DHT Sensor Fail "));
    lcd.setCursor(0,1);
    lcd.print(F("to Initialize   "));

    // show FAIL on LED
    clockDisplay.setSegments(SEG_FAIL);
    
    while(1); // Pause forever.
  }

  // ==============================================================
  // Set LCD pin for interrupt
     pinMode(lcdButtonPin, INPUT_PULLUP);
     attachInterrupt(digitalPinToInterrupt(lcdButtonPin), lcdSwitchScreens, FALLING);

  // ==============================================================  
  // Show all sensors initialized on LCD screen
     lcd.setCursor(0,0);
     lcd.print(F("All Sensors     "));
     lcd.setCursor(0,1);
     lcd.print(F("Initialized     "));

     delay(3000);
    
  // ============================================================== 
  // Initialize Fire Control Button
     Serial.println(F("Initializing Launch System. Standby..."));
  
  // Setup Fire pin for interrupt
     pinMode(fireButtonPin, INPUT_PULLUP);
     attachInterrupt(digitalPinToInterrupt(fireButtonPin), fireButtonRoutine, FALLING);

  // set value to no launch
     fireCountdown=0;

  // Setup Safety pin
     pinMode(safetyButtonPin, INPUT_PULLUP);

  // Setup fire relay pin
     pinMode(fireRelayPin, OUTPUT);
  
  // Initialize peizo buzzer
     pinMode(buzzer,OUTPUT);

     // quick chirp
        digitalWrite(buzzer,HIGH);
        delay(50);
        digitalWrite(buzzer,LOW);
     
  // Display Fire Button Now Active LCD screen
     lcd.setCursor(0,0);
     lcd.print(F("Launch System   "));
     lcd.setCursor(0,1);
     lcd.print(F("Initialized     "));

  // Fire button initiated
     Serial.println(F("Launch System initialization successful"));
     Serial.println();

  // show PASS on LED
     clockDisplay.setSegments(SEG_PASS);

     delay(3000);   
}

   
/******************************************************************
 ******************************************************************
 *                                                                *
 *                      MAIN PROGRAM LOOP                         *
 *                                                                *
 ******************************************************************
 ******************************************************************/

void loop() 
{
  // ==============================================================  
  // fire button has been pushed - proceed to countdown  
     if (fireCountdown == 1)
       launchCountdown();
  
  // ==============================================================  
  // Main Loop for RTC and to display time on LED Display
  // Get current date and time
     DateTime now = rtc.now();

  // Create time format to display
     displayTime = (now.hour() * 100) + now.minute();  

  // Display the current time in 24 hour format 
  // with leading zeros enabled and a center colon:
     clockDisplay.showNumberDecEx(displayTime, 0b11100000, true);

  // ============================================================== 
  // display selected LCD screen
     showLCDScreen();
} 


/******************************************************************
 ******************************************************************
 *                                                                *
 *              SPLASH SCREEN ON SERIAL MONITOR                   *
 *                                                                *
 ******************************************************************
 ******************************************************************/

void splashScreen()
{
  // Display on the Serial Monitor
     Serial.println(F("Austin Aerospace Educational Network Project: "));
     Serial.println(F("Electronic Research Launch Controller"));  
     Serial.print(F("Version: "));
     Serial.print(prgMajor); Serial.print(F(".")); Serial.print(prgMinor); Serial.print(F(".")); Serial.println(prgPatch);
     Serial.println(F("https://rocketryjournal.wordpress.com"));
     Serial.println();
     Serial.println(F("=================================================="));
     Serial.println(F("Begin Sensor Initilization Process"));
     Serial.println(F("=================================================="));
     Serial.println();
}


/******************************************************************
 ******************************************************************
 *                                                                *
 *                    SPLASH SCREENS FOR LCD                      *
 *                                                                *
 ******************************************************************
 ******************************************************************/
void splashScreenLCD1()
{
  // Display splash screen 1 on LCD screen
     lcd.setCursor(0,0);
     lcd.print(F("Austin Aerospace"));
     lcd.setCursor(0,1);
     lcd.print(F("Network"));
}

void splashScreenLCD2() 
{
  // Display splash screen 2 on LCD screen
     lcd.setCursor(0,0);
     lcd.print(F("Launch Controler"));
     lcd.setCursor(0,1);
     lcd.print(F("Version:  . .   "));
     lcd.setCursor(9,1); lcd.print(prgMajor); 
     lcd.setCursor(11,1); lcd.print(prgMinor); 
     lcd.setCursor(13,1); lcd.print(prgPatch);    
}

/******************************************************************
 ******************************************************************
 *                                                                *
 *              REAL TIME CLOCK DATE CALCULATIONS                 *
 *                                                                *
 ******************************************************************
 ******************************************************************/
void rtcDate()
{
  // Get date from RTC
     DateTime now = rtc.now();
     
  // Assign to variables
     displayYear = now.year();
     displayMonth = now.month();
     displayDay = now.day();
}


/******************************************************************
 ******************************************************************
 *                                                                *
 *                  BMP180 PRESSURE CALCULATIONS                  *
 *                                                                *
 ******************************************************************
 ******************************************************************/

void bmp180Measurements()
{
  // Start a pressure measurement:
  // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait).
  // If request is successful, the number of ms to wait is returned.
  // If request is unsuccessful, 0 is returned.

     bmp180Status = baroPressure.startPressure(3);
     if (bmp180Status != 0)
      {
        // Retrieve the completed pressure measurement:
        // Note that the measurement is stored in the variable absolutePress.
        // Note also that the function requires the previous temperature measurement (currentTemp).
        // (If temperature is stable, you can do one temperature measurement for a number of 
        // pressure measurements.)
        // Function returns 1 if successful, 0 if failure.

        bmp180Status = baroPressure.getPressure(absolutePress,currentTemp);

        if (bmp180Status != 0)
        {
          relativePress = baroPressure.sealevel(absolutePress,baseElevation);
        } 
        else Serial.println(F("Error retrieving pressure measurement\n"));   
      }    
} 


/******************************************************************
 ******************************************************************
 *                                                                *
 *                      DHT CALCULATIONS                          *
 *                                                                *
 ******************************************************************
 ******************************************************************/
void dht11Measurements()
{
  // Get temp and humidity readings
     dhtSensor.read(DHT11PIN);
     dhtHumidity = dhtSensor.humidity;
     dhtTemp = dhtSensor.temperature;
}


/******************************************************************
 ******************************************************************
 *                                                                *
 *                      VOLTMETER CALCULATIONS                    *
 *                                                                *
 ******************************************************************
 ******************************************************************/
void voltageMeasurements()
{
  valuePin0 = analogRead(A0);
  voltage = valuePin0 * (5.0/1024)*((R1 + R2)/R2);
}


/******************************************************************
 ******************************************************************
 *                                                                *
 *            DATE AND TIME DISPLAYED ON SERIAL MONITOR           *
 *                                                                *
 ******************************************************************
 ******************************************************************/

void DateAndTimeSerialMonitor()
{
  timeNow = millis();  

  // Print date and time on serial monitor
     Serial.println(F("=================================================="));
     Serial.print(F("Date & Time: "));
     Serial.print(displayTime);
     Serial.print(" hrs - ");
     Serial.print(displayMonth);  Serial.print(F("/"));
     Serial.print(displayDay);    Serial.print(F("/"));
     Serial.println(displayYear);  
     Serial.println(F("=================================================="));

  while (millis() < timeNow + waitPeriod)
  {}
}

/******************************************************************
 ******************************************************************
 *                                                                *
 *        BMP180 RESULTS DISPLAYED ON SERIAL MONITOR              *
 *                                                                *
 ******************************************************************
 ******************************************************************/

void bmp180SerialMonitor()
{
  timeNow = millis();  
  
  // Display pressure readings on the Serial Monitor
     Serial.print(F("Pressure Readings from BMP180 Sensor"));  
     Serial.println();
    
  // Base elevation
     Serial.print(F("  Base Elevation: "));
     Serial.print(baseElevation,2);
     Serial.println(F(" m "));  
  
  // Absolute pressure
     Serial.print(F("  Absolute pressure: "));
     Serial.print(absolutePress,2);
     Serial.println(F(" mb "));
      
  // Relative pressure
     Serial.print(F("  Relative (sea-level) pressure: "));
     Serial.print(relativePress,2);
     Serial.println(F(" mb "));
     Serial.println(); 

  while (millis() < timeNow + waitPeriod)
  {}
}

/******************************************************************
 ******************************************************************
 *                                                                *
 *         DHT11 RESULTS DISPLAYED ON SERIAL MONITOR              *
 *                                                                *
 ******************************************************************
 ******************************************************************/

void dht11SerialMonitor()
{
  timeNow = millis();
  
  // Display temp and humidity readings on the Serial Monitor
     Serial.print(F("Temperature and Humidity Readings from DHT11 Sensor"));  
     Serial.println();

  // Display temperature
     Serial.print(F("  Temperature: "));
     Serial.print(dhtTemp,0);
     Serial.println(F(" C ")); 
  
  // Display humidity
     Serial.print(F("  Humidity: "));
     Serial.print(dhtHumidity,0);
     Serial.println(F("% "));
     Serial.println();
     
  while (millis() < timeNow + waitPeriod)
  {}
}


/******************************************************************
 ******************************************************************
 *                                                                *
 *    VOLTAGE MEASUREMENTS RESULTS DISPLAYED ON SERIAL MONITOR    *
 *                                                                *
 ******************************************************************
 ******************************************************************/
void voltageSerialMonitor()
{
  // get current time  
     timeNow = millis();  
  
     Serial.print(F("Launch Pad Power: "));
     Serial.print(voltage);
     Serial.println(F(" volts"));
     
   while (millis() < timeNow + waitPeriod)
   {}
}


/******************************************************************
 ******************************************************************
 *                                                                *
 *            DATE AND TIME RESULTS DISPLAYED ON LCD              *
 *                                                                *
 ******************************************************************
 ******************************************************************/

void DateAndTimeLCD()
{
  // Display Date
     lcd.setCursor(0,0);
     lcd.print(F("Date:           "));
     lcd.setCursor(6,0);
     lcd.print(displayMonth);lcd.print("/");lcd.print(displayDay);lcd.print("/");lcd.print(displayYear);
     lcd.setCursor(0,1);
     lcd.print(F("Time:           "));
     lcd.setCursor(6,1);
     lcd.print(displayTime);
     lcd.setCursor(10,1);
     lcd.print(" hrs ");
}


/******************************************************************
 ******************************************************************
 *                                                                *
 *              BMP180 RESULTS DISPLAYED ON LCD                   *
 *                                                                *
 *    Three subroutines are present - one for each LCD screen     *                                                            
 *                                                                *
 ******************************************************************
 ******************************************************************/


// ================================================================
// Subroutine 1: Base Elevation  
void bmp180LCD1()
{
  // get current time  
     timeNow = millis(); 
  
  // Display pressure readings on the Serial Monitor
  // Base Elevation
     lcd.setCursor(0,0);
     lcd.print(F("Base Elevation  "));
     lcd.setCursor(0,1);
     lcd.print(F("          meters"));
     lcd.setCursor(0,1);
     lcd.print(baseElevation,2);

  while (millis() < timeNow + waitPeriod)
  {}
}

// ================================================================
// Subroutine 2: Absolute Pressure  
void bmp180LCD2()
{  
  timeNow = millis(); 
    
  // Absolute pressure
     lcd.setCursor(0,0);
     lcd.print(F("Absolute Press  "));
     lcd.setCursor(0,1);
     lcd.print(F("        mb      "));
     lcd.setCursor(0,1);  
     lcd.print(absolutePress,2);
  
  while (millis() < timeNow + waitPeriod)
  {}
}

// ================================================================
// Subroutine 3: Relative Pressure 
void bmp180LCD3()
{
  timeNow = millis();    
  
  // Relative pressure
     lcd.setCursor(0,0);
     lcd.print(F("Relative Press  "));
     lcd.setCursor(0,1);
     lcd.print(F("        mb      "));
     lcd.setCursor(0,1);  
     lcd.print(relativePress,2);   
  
  while (millis() < timeNow + waitPeriod)
  {}
}

/******************************************************************
 ******************************************************************
 *                                                                *
 *              DHT11 RESULTS DISPLAYED ON LCD                    *
 *                                                                *
 ******************************************************************
 ******************************************************************/

void dht11LCD()
{
  // get current time  
     timeNow = millis();
     
  // Main Loop for displaying temp and humidity on LCD
     lcd.setCursor(0,0);
     lcd.print(F("Temp           C"));
     lcd.setCursor(9,0);
     lcd.print(dhtTemp);
     lcd.setCursor(0,1);
     lcd.print(F("Humidity       %"));
     lcd.setCursor(9,1);
     lcd.print(dhtHumidity);

  while (millis() < timeNow + waitPeriod)
  {}
}


/******************************************************************
 ******************************************************************
 *                                                                *
 *            VOLTAGE MEASUREMENTS DISPLAYED ON LCD               *
 *                                                                *
 ******************************************************************
 ******************************************************************/
void voltageLCD()
{
  // get current time  
     timeNow = millis();
     
     lcd.setCursor(0,0);
     lcd.print(F("Launch Pad Power"));
     lcd.setCursor(0,1);
     lcd.print(F("        Volts   "));
     lcd.setCursor(3,1);
     lcd.print(voltage);

  while (millis() < timeNow + waitPeriod)
  {}
}


/******************************************************************
 ******************************************************************
 *                                                                *
 *                LAUNCH COUNTDOWN SEQUENCE                       *
 *                                                                *
 ******************************************************************
 ******************************************************************/
void launchCountdown()
{
  // ================================================================
  // Launch Sequence


  
  // if safety button is HIGH assume rogue button push
     if (digitalRead(safetyButtonPin) == HIGH)
      {
        fireCountdown = 0;
        return;
      }       

  // turn off interrupts during firing sequence
     detachInterrupt(digitalPinToInterrupt(fireButtonPin));
       
  // show Fire button pressed on screen  
     Serial.println(F("=================================================="));
     Serial.println(F("Fire and Launch Safety Buttons Pressed"));
     Serial.println(F("Launch Sequence Initiated"));
     Serial.println(F("=================================================="));  
  
  // Display launch sequence on LCD screen   
     lcd.setCursor(0,0);
     lcd.print(F("Launch Sequence "));
     lcd.setCursor(0,1);
     lcd.print(F("Initiated       ")); 

  // Start loop LED countdown clock from t-10
     for (int countdown = 10; countdown > 0; countdown --)
     {
      // determine which clock to display
      if (countdown == 10)
        {
        clockDisplay.setSegments(SEG_10);
        }
      else if (countdown == 9)
        {
        clockDisplay.setSegments(SEG_09);
        }
      else if (countdown == 8)
        {
        clockDisplay.setSegments(SEG_08);
        }
      else if (countdown == 7)
        {
        clockDisplay.setSegments(SEG_07);
        }
      else if (countdown == 6)
        {
        clockDisplay.setSegments(SEG_06);
        }
      else if (countdown == 5)
        {
        clockDisplay.setSegments(SEG_05);
        } 
      else if (countdown == 4)
        {
        clockDisplay.setSegments(SEG_04);
        }
      else if (countdown == 3)
        {
        clockDisplay.setSegments(SEG_03);
        }
      else if (countdown == 2)
        {
        clockDisplay.setSegments(SEG_02);
        }
      else if (countdown == 1)
        {
        clockDisplay.setSegments(SEG_01); 
        }
      
      // sound tone
      digitalWrite(buzzer,HIGH);
      delay(500);
      digitalWrite(buzzer,LOW);
      delay(500); 
      
      // Check for ABORT
      if ((digitalRead(safetyButtonPin) == HIGH) || (digitalRead(fireButtonPin) == HIGH))
      {
        // jump to Launch Abort sequence
          abortLaunch();

        // return to loop()
         return;        
      }      
     }      


  // show FIRE on LED
     clockDisplay.setSegments(SEG_FIRE);

     // Check for ABORT
     if ((digitalRead(safetyButtonPin) == HIGH) || (digitalRead(fireButtonPin) == HIGH))
     {
      // jump to Launch Abort sequence
         abortLaunch();

      // return to loop()
         return;        
     }  

  // ================================================================
  // Supply power to launch pad

  // Last Opportunity for ABORT
     if ((digitalRead(safetyButtonPin) == HIGH) || (digitalRead(fireButtonPin) == HIGH))
     {
      // jump to Launch Abort sequence
         abortLaunch();

      // return to loop()
         return;        
     }   
  
  // open relay to send power to ingiter
     digitalWrite(fireRelayPin, HIGH);
     // sound tone
     digitalWrite(buzzer,HIGH);
     
  // Display power flowing to launch pad on LCD screen   
     lcd.setCursor(0,0);
     lcd.print(F("Power Flowing to"));
     lcd.setCursor(0,1);
     lcd.print(F("Launch Pad      "));

  // show power is flowing to pad on screen  
     Serial.println(F("=================================================="));
     Serial.println(F("Power is flowing to the Launch Pad"));
     Serial.println(F("Stay Clear of Launch Pad"));
     Serial.println(F("=================================================="));

  // keep relay open and current flowing for
  // 5-seconds to provide power to igniter  
     delay (2000);

  // ================================================================
  // Turn off power to pad
  
  // reset relay to off
     digitalWrite(fireRelayPin, LOW);
     
  // turn off tone   
     digitalWrite(buzzer,LOW);

     
  // reset variable to 0 to be ready for next fire  
     fireCountdown = 0;  
        
  // ================================================================
  // Start 60-second wait period before approaching pad   
     
  // show power has stopped flowing on screen  
     Serial.println(F("=================================================="));
     Serial.println(F("Power has stopped flowing to the Launch Pad"));
     Serial.println(F("Stay Clear of Launch Pad for 60-seconds"));
     Serial.println(F("=================================================="));
  
  // stop all power and functions for 60 seconds
  // Start loop for pad safety countdown 
     for (int safety = 60; safety > 0; safety -=10)
     {      
      clockDisplay.setSegments(SEG_STAY); 
      lcd.setCursor(0,0);
      lcd.print(F(" Keep Pad Clear "));
      lcd.setCursor(0,1);
      lcd.print(F(" for ")); 
      lcd.print(safety); 
      lcd.print(F("-seconds ")); 
      delay (5000);

      clockDisplay.setSegments(SEG_AWAY);
      lcd.setCursor(0,1);
      lcd.print(F(" for ")); 
      lcd.print(safety-5); 
      lcd.print(F("-seconds ")); 
      delay (5000); 
     }
  
  // return to normal operations  
     Serial.println(F("=================================================="));
     Serial.println(F("It is now safe to approach the launch pad"));
     Serial.println(F("=================================================="));
     
  // turn interrupts back on
  //   interrupts();

  // Display "SAFE" LED countdown clock
     clockDisplay.setSegments(SEG_SAFE);

  // Indicate safe on LCD  
     lcd.setCursor(0,0);
     lcd.print(F("It is now safe  "));
     lcd.setCursor(0,1);
     lcd.print(F("to approach pad "));
    
   // quick chirp
        digitalWrite(buzzer,HIGH);
        delay(100);
        digitalWrite(buzzer,LOW);        
        delay (3000);

  // turn interrupts back on
     attachInterrupt(digitalPinToInterrupt(fireButtonPin), fireButtonRoutine, FALLING);
}


/******************************************************************
 ******************************************************************
 *                                                                *
 *                  LAUNCH ABORT SEQUENCE                         *
 *                                                                *
 ******************************************************************
 ******************************************************************/
 
void abortLaunch()
{
  // ================================================================
  // Abort Sequence 
  // Once both the Fire button and Safety button are pushed to initiate a launch
  // if either button reports pin as HIGH (button was released) assume abort 

  // Print abort on monitor
     Serial.println(F("==================================================="));   
     Serial.println(F("   ABORT  *  ABORT  *  ABORT  *  ABORT  *  ABORT   "));
     Serial.println(F("==================================================="));

  // Print abort on LCD
     lcd.setCursor(0,0);
     lcd.print(F(" *   LAUNCH   * "));
     lcd.setCursor(0,1);
     lcd.print(F(" *  ABORTED!  * "));

  // show FAIL on LED
     clockDisplay.setSegments(SEG_FAIL);

  // sound buzzer
     int i;
     
     { 
     for (i=0; i<50; i++)
      {
        digitalWrite(buzzer,HIGH);
        delay(50);
        digitalWrite(buzzer,LOW);
        delay(50); 
      }
     }
  
     delay(3000);
  
  // turn interrupts back on
     attachInterrupt(digitalPinToInterrupt(fireButtonPin), fireButtonRoutine, FALLING);        
     
  // reset fire value back to 0
     fireCountdown = 0;

  // Return to launch routine
     return;   

}

/******************************************************************
 ******************************************************************
 *                                                                *
 *                    LCD SCREEN DISPLAY                          *
 *                                                                *
 ******************************************************************
 ******************************************************************/

void showLCDScreen()
{
  if (lcdScreenDisplay == 1)    
  {
    rtcDate();
    DateAndTimeSerialMonitor();
    DateAndTimeLCD();
  }

  else if (lcdScreenDisplay == 2)
  {        
    bmp180Measurements();
    bmp180SerialMonitor();
    bmp180LCD1();   
    bmp180LCD2();
    bmp180LCD3();
  }
      
  else if (lcdScreenDisplay == 3)
  {       
    dht11Measurements();
    dht11SerialMonitor();
    dht11LCD();
  }
      
  else if (lcdScreenDisplay == 4)
  {
    voltageMeasurements();
    voltageSerialMonitor();
    voltageLCD();
  }
  
  else
  {        
    rtcDate();
    DateAndTimeSerialMonitor();
    DateAndTimeLCD();
  }
}


/******************************************************************
 ##################################################################
 #                                                                #
 #                  ISR FIRE BUTTON ROUTINE                       #
 #                                                                #
 ##################################################################
 ******************************************************************/

void fireButtonRoutine()
{
// TEMP for temporary debounce
   button_time = millis();
// check to see if increment() was called in the last 250 milliseconds
   if (button_time - last_button_time > 150)  

// Change value to show fire button pressed  
   fireCountdown = 1;

}


/******************************************************************
 ##################################################################
 #                                                                #
 #          ISR BUTTON PRESS TO CHANGE LCD DISPLAY                #
 #                                                                #
 ##################################################################
 ******************************************************************/

void lcdSwitchScreens()
{
// TEMP for temporary debounce
   button_time = millis();
// check to see if increment() was called in the last 150 milliseconds
   if (button_time - last_button_time > 150)

   lcdScreenDisplay ++;

   if (lcdScreenDisplay > 5)
      lcdScreenDisplay=1;

   delay(10);
   
}
