diff --git a/Homework 3/.gitkeep b/Homework 3/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/Homework 3/Question 1 Proof/.gitkeep b/Homework 3/Question 1 Proof/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/Homework 3/Question 1 Proof/DAQ_initial.ino b/Homework 3/Question 1 Proof/DAQ_initial.ino
new file mode 100644
index 0000000000000000000000000000000000000000..d7b5fb20434310676036e7a37f11012ad0122baa
--- /dev/null
+++ b/Homework 3/Question 1 Proof/DAQ_initial.ino	
@@ -0,0 +1,1012 @@
+/*
+Group 1: Jeremy, Pavan, Ayush, Sam
+Homework 3: DAQ
+9th of Feburary, 2023
+
+File Name: DAQ initial
+
+Goal/Purpose: To have a program that is able to collect and use all of the sensors and devices intended
+for our project. In this code, it will read the GPS and RTC for time, then read the BME for temperature
+and write it and the name of a picture taken to an SD Card), all while the LCD is displaying updates on
+what task is currently being underwent and how many pictures/iterations of the loop have successfully executed.
+
+We spent around 12 hours total on this project, and referenced previous homeworks, online adafruit/arduino fourms,
+and the provided test code on the 371 website. The data graph/mean/standard deviation is found in the excel file.
+*/
+#include <Wire.h>
+#include <SPI.h>
+#include <Adafruit_Sensor.h>
+#include "Adafruit_BME680.h"
+#include <LiquidCrystal.h>
+#include <TimeLib.h>
+#include <DS1307RTC.h>
+#include <Keypad.h>
+#include "SdFat.h"
+#include <Adafruit_VC0706.h>
+//#include <SD.h>
+#include <Adafruit_GPS.h>
+#include "RTClib.h"
+RTC_DS3231 rtc;
+//GPS
+#define GPSSerial Serial1
+#define GPSECHO1 false
+#define GPSECHO2 false
+#define GPSECHO3 false
+#define PMTK_SET_NMEA_UPDATE_10SEC "$PMTK220,10000*2F"
+#define PMTK_SET_NMEA_UPDATE_5SEC "$PMTK220,5000*2F"
+#define PMTK_SET_NMEA_UPDATE_1HZ  "$PMTK220,1000*1F"
+#define PMTK_SET_NMEA_UPDATE_2HZ  "$PMTK220,500*2B"
+#define PMTK_SET_NMEA_UPDATE_5HZ  "$PMTK220,200*2C"
+
+//SNAPSHOT
+#if defined(__AVR__) || defined(ESP8266)
+#include <SoftwareSerial.h>         
+SoftwareSerial cameraconnection(69, 3);
+#else
+#define cameraconnection Serial1
+
+#endif
+#define chipSelect 53
+
+//BME SD
+#define BME_SCK 13
+#define BME_MISO 12
+#define BME_MOSI 11
+#define BME_CS 10
+#define SD_CS_PIN SS
+#define SEALEVELPRESSURE_HPA (1013.25)
+Adafruit_VC0706 cam = Adafruit_VC0706(&cameraconnection);
+#define GPSMINLENGTH 55
+#define GPSMAXLENGTH 120
+Adafruit_GPS GPS(&GPSSerial);
+char* GPS_sentence;
+String GPS_sentence_string;
+const int GPRMC_hour_index1 = 8;
+const int GPRMC_hour_index2 = GPRMC_hour_index1 + 2;
+
+const int GPRMC_minutes_index1 = GPRMC_hour_index2;
+const int GPRMC_minutes_index2 = GPRMC_minutes_index1 + 2;
+      
+const int GPRMC_seconds_index1 = GPRMC_minutes_index2;
+const int GPRMC_seconds_index2 = GPRMC_seconds_index1 + 2;
+      
+const int GPRMC_milliseconds_index1 = GPRMC_seconds_index2 + 1;   // skip the decimal point
+const int GPRMC_milliseconds_index2 = GPRMC_milliseconds_index1 + 3;
+      
+const int GPRMC_AV_code_index1 = 19;
+const int GPRMC_AV_code_index2 = GPRMC_AV_code_index1 + 1;
+      
+const int GPRMC_latitude_1_index1 = 21;
+const int GPRMC_latitude_1_index2 = GPRMC_latitude_1_index1 + 4;
+      
+const int GPRMC_latitude_2_index1 = GPRMC_latitude_1_index2 + 1;   // skip the decimal point
+const int GPRMC_latitude_2_index2 = GPRMC_latitude_2_index1 + 4;
+
+const int GPRMC_latitude_NS_index1 = 31;
+const int GPRMC_latitude_NS_index2 = GPRMC_latitude_NS_index1 + 1;
+
+const int GPRMC_longitude_1_index1 = 33;
+const int GPRMC_longitude_1_index2 = GPRMC_longitude_1_index1 + 5;    // 0 - 180 so we need an extra digit
+      
+const int GPRMC_longitude_2_index1 = GPRMC_longitude_1_index2 + 1;   // skip the decimal point
+const int GPRMC_longitude_2_index2 = GPRMC_longitude_2_index1 + 4;
+      
+const int GPRMC_longitude_EW_index1 = 44;
+const int GPRMC_longitude_EW_index2 = GPRMC_longitude_EW_index1 + 1;
+
+// pointers into a GPGGA GPS data sentence:
+
+const int GPGGA_hour_index1 = 8;
+const int GPGGA_hour_index2 = GPGGA_hour_index1 + 2;
+
+const int GPGGA_minutes_index1 = GPGGA_hour_index2;
+const int GPGGA_minutes_index2 = GPGGA_minutes_index1 + 2;
+      
+const int GPGGA_seconds_index1 = GPGGA_minutes_index2;
+const int GPGGA_seconds_index2 = GPGGA_seconds_index1 + 2;
+      
+const int GPGGA_milliseconds_index1 = GPGGA_seconds_index2 + 1;   // skip the decimal point
+const int GPGGA_milliseconds_index2 = GPGGA_milliseconds_index1 + 3;
+      
+const int GPGGA_latitude_1_index1 = 19;
+const int GPGGA_latitude_1_index2 = GPGGA_latitude_1_index1 + 4;
+      
+const int GPGGA_latitude_2_index1 = GPGGA_latitude_1_index2 + 1;   // skip the decimal point
+const int GPGGA_latitude_2_index2 = GPGGA_latitude_2_index1 + 4;
+
+const int GPGGA_latitude_NS_index1 = 29;
+const int GPGGA_latitude_NS_index2 = GPGGA_latitude_NS_index1 + 1;
+
+const int GPGGA_longitude_1_index1 = 31;
+const int GPGGA_longitude_1_index2 = GPGGA_longitude_1_index1 + 5;    // 0 - 180 so we need an extra digit
+      
+const int GPGGA_longitude_2_index1 = GPGGA_longitude_1_index2 + 1;   // skip the decimal point
+const int GPGGA_longitude_2_index2 = GPGGA_longitude_2_index1 + 4;
+      
+const int GPGGA_longitude_EW_index1 = 42;
+const int GPGGA_longitude_EW_index2 = GPGGA_longitude_EW_index1 + 1;
+
+const int GPGGA_fix_quality_index1 = 44;
+const int GPGGA_fix_quality_index2 = GPGGA_fix_quality_index1 + 1;
+
+const int GPGGA_satellites_index1 = 46;
+const int GPGGA_satellites_index2 = GPGGA_satellites_index1 + 2;
+
+// keep track of how many times we've read a character from the GPS device. 
+long GPS_char_reads = 0;
+
+// bail out if we exceed the following number of attempts. when set to 1,000,000 this corresponds
+// to about 6 seconds. we need to do this to keep an unresponsive GPS device from hanging the program.
+const long GPS_char_reads_maximum = 1000000;
+
+// define some of the (self-explanatory) GPS data variables. Times/dates are UTC.
+String GPS_hour_string;
+String GPS_minutes_string;
+String GPS_seconds_string;
+String GPS_milliseconds_string;
+int GPS_hour;
+int GPS_minutes;
+int GPS_seconds;
+int GPS_milliseconds;
+
+// this one tells us about data validity: A is good, V is invalid.
+String GPS_AV_code_string;
+
+// latitude data
+String GPS_latitude_1_string;
+String GPS_latitude_2_string;
+String GPS_latitude_NS_string;
+int GPS_latitude_1;
+int GPS_latitude_2;
+
+// longitude data
+String GPS_longitude_1_string;
+String GPS_longitude_2_string;
+String GPS_longitude_EW_string;
+int GPS_longitude_1;
+int GPS_longitude_2;
+
+// velocity information; speed is in knots! 
+String GPS_speed_knots_string;
+String GPS_direction_string;
+float GPS_speed_knots;
+float GPS_direction;
+
+String GPS_date_string;
+
+String GPS_fix_quality_string;
+String GPS_satellites_string;
+int GPS_fix_quality;
+int GPS_satellites;
+
+String GPS_altitude_string;
+float GPS_altitude;
+String GPS_command;
+char daysOfTheWeek[7][4] = 
+  {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+int RTC_hour, RTC_minute, RTC_second;
+int RTC_year, RTC_month, RTC_day_of_month;
+bool already_set_RTC_from_GPS;
+
+
+SdFat SD_thingy;
+File myFiley;
+
+char filename[ ] = "data.csv";
+
+const char *monthName[12] = {
+  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+tmElements_t tm;
+Adafruit_BME680 bme; // I2C
+const byte ROWS = 4; 
+const byte COLS = 3;
+
+char keys[ROWS][COLS] = {
+{'1','2','3'},
+{'4','5','6'},
+{'7','8','9'},
+{'*','0','#'}
+};
+bool getTime(const char *str)
+{
+  int Hour, Min, Sec;
+
+  if (sscanf(str, "%d:%d:%d", &Hour, &Min, &Sec) != 3) return false;
+  tm.Hour = Hour;
+  tm.Minute = Min;
+  tm.Second = Sec;
+  return true;
+}
+
+bool getDate(const char *str)
+{
+  char Month[12];
+  int Day, Year;
+  uint8_t monthIndex;
+
+  if (sscanf(str, "%s %d %d", Month, &Day, &Year) != 3) return false;
+  for (monthIndex = 0; monthIndex < 12; monthIndex++) {
+    if (strcmp(Month, monthName[monthIndex]) == 0) break;
+  }
+  if (monthIndex >= 12) return false;
+  tm.Day = Day;
+  tm.Month = monthIndex + 1;
+  tm.Year = CalendarYrToTm(Year);
+  return true;
+}
+byte Arduino_colPins[COLS] = {2, 3, 18}; 
+byte Arduino_rowPins[ROWS] = {31, 33, 35, 37};
+Keypad kpd = Keypad( makeKeymap(keys), Arduino_rowPins, Arduino_colPins, ROWS, COLS );
+
+const int rs = 12, en = 11, data4 = 36, data5 = 34, data6 = 32, data7 = 30;
+LiquidCrystal lcd(rs, en, data4, data5, data6, data7);
+
+
+void setup() {
+    if (!bme.begin()) {
+    Serial.println("Could not find a valid BME680 sensor, check wiring!");
+    while (1);
+  bme.setTemperatureOversampling(BME680_OS_8X);
+  bme.setHumidityOversampling(BME680_OS_2X);
+  bme.setPressureOversampling(BME680_OS_4X);
+  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
+  bme.setGasHeater(320, 150); // 320*C for 150 ms
+
+  }
+  //HW 2
+  bool parse=false;
+  bool config=false;
+
+  // get the date and time the compiler was run
+  if (getDate(__DATE__) && getTime(__TIME__)) {
+    parse = true;
+    // and configure the RTC with this info
+    if (RTC.write(tm)) {
+      config = true;
+    }
+  }
+  Serial.begin(115200);
+  while (!Serial);
+  Serial.println(F("BME680 test"));
+
+  if (!bme.begin()) {
+    Serial.println("Could not find a valid BME680 sensor, check wiring!");
+    while (1);
+  }
+
+  // Set up oversampling and filter initialization
+  bme.setTemperatureOversampling(BME680_OS_8X);
+  bme.setHumidityOversampling(BME680_OS_2X);
+  bme.setPressureOversampling(BME680_OS_4X);
+  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
+  bme.setGasHeater(320, 150); // 320*C for 150 ms
+
+    lcd.begin(16, 2);
+    Serial.println("About to write to LCD.");
+      Serial.println("LCD lines are 16 characters long.");
+       while (!Serial) ; // wait for Arduino Serial Monitor
+  delay(200);
+  if (parse && config) {
+    Serial.print("DS1307 configured Time=");
+    Serial.print(__TIME__);
+    Serial.print(", Date=");
+    Serial.println(__DATE__);
+  } else if (parse) {
+    Serial.println("DS1307 Communication Error :-{");
+    Serial.println("Please check your circuitry");
+  } else {
+    Serial.print("Could not parse info from the compiler, Time=\"");
+    Serial.print(__TIME__);
+    Serial.print("\", Date=\"");
+    Serial.print(__DATE__);
+    Serial.println("\"");
+  }
+  //HW 2 DONE
+
+  //camera begin
+  #if !defined(SOFTWARE_SPI)
+#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+  if(chipSelect != 53) pinMode(53, OUTPUT); // SS on Mega
+#else
+  if(chipSelect != 10) pinMode(10, OUTPUT); // SS on Uno, etc.
+#endif
+#endif
+
+
+  Serial.println("VC0706 Camera snapshot test");
+  
+  // see if the card is present and can be initialized:
+  if (!SD_thingy.begin(chipSelect)) {
+    Serial.println("Card failed, or not present");
+    // don't do anything more:
+    return;
+  }  
+  
+  // Try to locate the camera
+  if (cam.begin()) {
+    Serial.println("Camera Found:");
+  } else {
+    Serial.println("No camera found?");
+    return;
+  }
+  // Print out the camera version information (optional)
+  char *reply = cam.getVersion();
+  if (reply == 0) {
+    Serial.print("Failed to get version");
+  } else {
+    Serial.println("-----------------");
+    Serial.print(reply);
+    Serial.println("-----------------");
+  }
+  //CAMERA END
+
+  //GPS BEGIN
+  GPS.begin(9600);
+  
+  // turn on RMC (recommended minimum) and GGA (fix data, including altitude)
+  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
+    GPS.sendCommand(PMTK_SET_NMEA_UPDATE_5HZ); 
+}
+void updateTime() {
+   Serial.println("Setting the RTC Date");
+       bool parse=false;
+  bool config=false;
+  if (getDate(__DATE__) && getTime(__TIME__)) {
+    parse = true;
+    if (RTC.write(tm)) {
+      config = true;
+    }
+     while (!Serial);
+  delay(200);
+  if (parse && config) {
+    Serial.print("DS1307 configured Time=");
+    Serial.print(__TIME__);
+    Serial.print(", Date=");
+    Serial.println(__DATE__);
+  } else if (parse) {
+    Serial.println("DS1307 Communication Error :-{");
+    Serial.println("Please check your circuitry");
+  } else {
+    Serial.print("Could not parse info from the compiler, Time=\"");
+    Serial.print(__TIME__);
+    Serial.print("\", Date=\"");
+    Serial.print(__DATE__);
+    Serial.println("\"");
+  }
+  }
+}
+void writeCSV(String picname, String speed_knots, String direction) {
+    Serial.println("opening the csv file");
+        while (!Serial) { }
+  Serial.print("Initializing SD card reading software... ");
+  if (!SD_thingy.begin(SD_CS_PIN)) {
+    Serial.println("SD initialization failed!");
+    delay(100);
+    exit(0);
+  }
+  /*
+  Serial.println("initialization done.");
+  if(SD_thingy.exists(filename)) { 
+    SD_thingy.remove(filename); 
+    delay(100);   
+    }
+    */
+  myFiley = SD_thingy.open(filename, FILE_WRITE);
+  if (myFiley) {
+    Serial.print("Writing to "); Serial.print(filename); Serial.println("...");    
+    } else {   
+    Serial.print("error opening "); Serial.println(filename); 
+    delay(100);
+    exit(0);
+    }
+    myFiley.print(__TIME__);myFiley.print(",");myFiley.print(__DATE__);myFiley.print(",");myFiley.print(picname);myFiley.print(",");myFiley.print(speed_knots);myFiley.print(",");myFiley.println(direction);
+  Serial.println("Finished writing to file. Now close it, open it, read it.");
+  lcd.setCursor(0,1);
+  lcd.print("Closing");
+  myFiley.close();
+}
+String picturename = "IMAGE00.JPG";
+void getphoto() {
+  cam.setImageSize(VC0706_640x480);        // biggest
+  //cam.setImageSize(VC0706_320x240);        // medium
+  //cam.setImageSize(VC0706_160x120);          // small
+
+  // You can read the size back from the camera (optional, but maybe useful?)
+  uint8_t imgsize = cam.getImageSize();
+  Serial.print("Image size: ");
+  if (imgsize == VC0706_640x480) Serial.println("640x480");
+  if (imgsize == VC0706_320x240) Serial.println("320x240");
+  if (imgsize == VC0706_160x120) Serial.println("160x120");
+
+  Serial.println("Snap in 3 secs...");
+    lcd.setCursor(0,1);
+  lcd.print("Taking pic");
+  delay(3000);
+
+  if (! cam.takePicture()) 
+    Serial.println("Failed to snap!");
+  else 
+    Serial.println("Picture taken!");
+      lcd.setCursor(0,1);
+    lcd.print("Pic taken!");
+  
+  // Create an image with the name IMAGExx.JPG
+  char picname[13];
+  strcpy(picname, "IMAGE00.JPG");
+  for (int i = 0; i < 100; i++) {
+    picname[5] = '0' + i/10;
+    picname[6] = '0' + i%10;
+    picturename[5] = '0' + i/10;
+    picturename[6] = '0' + i%10;
+
+    // create if does not exist, do not open existing, write, sync after write
+    if (! SD_thingy.exists(picname)) {
+      break;
+    }
+  }
+  
+  // Open the file for writing
+  File imgFile = SD_thingy.open(picname, FILE_WRITE);
+
+  // Get the size of the image (frame) taken  
+  uint32_t jpglen = cam.frameLength();
+  Serial.print("Storing ");
+    lcd.setCursor(0,1);
+  lcd.print("Storing");
+  Serial.print(jpglen, DEC);
+  Serial.print(" byte image.");
+
+  int32_t time = millis();
+  pinMode(8, OUTPUT);
+  // Read all the data up to # bytes!
+  byte wCount = 0; // For counting # of writes
+  while (jpglen > 0) {
+    // read 32 bytes at a time;
+    uint8_t *buffer;
+    uint8_t bytesToRead = min((uint32_t)32, jpglen); // change 32 to 64 for a speedup but may not work with all setups!
+    buffer = cam.readPicture(bytesToRead);
+    imgFile.write(buffer, bytesToRead);
+    if(++wCount >= 64) { // Every 2K, give a little feedback so it doesn't appear locked up
+      Serial.print('.');
+      wCount = 0;
+    }
+    //Serial.print("Read ");  Serial.print(bytesToRead, DEC); Serial.println(" bytes");
+    jpglen -= bytesToRead;
+  }
+  imgFile.close();
+
+  time = millis() - time;
+  Serial.println("done!");
+  lcd.setCursor(0,1);
+  lcd.print("Done!");
+  Serial.print(time); Serial.println(" ms elapsed");
+}
+
+int count = 0;
+void loop() {
+  updateTime();
+if (! bme.performReading()) {
+    Serial.println("Failed to perform reading :(");
+    return;
+  }
+
+
+
+GPS_query();
+Serial.println(GPS_minutes * 60 + GPS_seconds);
+Serial.print("TIME: ");Serial.println(__TIME__);
+
+
+lcd.setCursor(0,0);
+lcd.print("Entries: ");lcd.print(count);
+getphoto();
+Serial.println(picturename);
+float BME_temp = bme.temperature;
+Serial.println(BME_temp);
+float GPS_second = GPS_minutes * 60 + GPS_seconds; 
+writeCSV(picturename,(String)GPS_second,(String)BME_temp);
+  delay(1000);
+
+Serial.println("pic taken");
+count++;
+delay(1000);
+
+}
+int GPS_query()
+{
+
+  // return 0 if we found good GPS navigational data and -1 if not.
+  
+  // The GPS device has its own microprocessor and, once we have loaded its parameters,
+  // free-runs at a 1 Hz sampling rate. We do not trigger its registration of
+  // latitude and longitude, rather we just read from it the last data record
+  // it has stored. And we do it one character at a time!
+
+  // I will keep reading from the GPS until I have a complete sentence carrying valid
+  // navigational data, with a maximum number of reads to prevent the program from hanging. Once
+  // the GPS reports its updates latitude/longitude information, we'll push this to the 
+  // LCD display, then return to the main loop. 
+   
+  // zero out (or set to defaults) values returned by the GPS device in case we can't 
+  // get it to respond.
+  GPS_hour = GPS_minutes = GPS_seconds = GPS_milliseconds = 0;
+
+  GPS_AV_code_string = "V";
+
+  GPS_latitude_1 = GPS_latitude_2 = 0;
+  GPS_latitude_NS_string = "x";
+  
+  GPS_longitude_1 = GPS_longitude_2 = 0;
+  GPS_longitude_EW_string = "y";
+    
+  GPS_speed_knots = 0.;
+  GPS_direction = 0.;
+    
+  GPS_date_string = "000000";
+  
+  GPS_fix_quality = GPS_satellites = 0;
+  
+  GPS_altitude = 0.;
+
+  // initialize the number-of-reads counter since we might find ourselves
+  // with an unparseable data record, or an unresponsive GPS, and want to keep trying.
+  // This will let me protect against the data logger's program hanging. 
+  GPS_char_reads = 0;
+
+  // set a flag saying we want to keep trying; we'll use this to keep looking for
+  // useful navigation when the GPS is working fine, but still looking for satellites.
+  bool keep_trying = true;
+  
+  // Stay inside the following loop until we've read a complete GPS sentence with
+  // good navigational data, or else the loop times out. With GPS_char_reads_maximum 
+  // set to a million this'll take about 6 seconds to time out. 
+  
+  while (true) {
+  
+    // if we get back to this point but the keep_trying flag is false, we'll want
+    // to declare failure and quit.
+
+    if(!keep_trying) return -1;
+    
+    // this gets the last sentence read from GPS and clears a newline flag in the Adafruit 
+    // library code.
+    GPS_sentence = GPS.lastNMEA();
+    Serial.println("printing raw");
+
+  
+    while(GPS_char_reads <= GPS_char_reads_maximum) 
+      {
+  
+      // try to read a single character from the GPS device.
+      char single_GPS_char = GPS.read();
+  
+      // bump the number of times we've tried to read from the GPS.
+      GPS_char_reads++;
+  
+      // now ask if we've received a complete data sentence. If yes, break
+      // out of this loop.
+  
+      if(GPS.newNMEAreceived()) break;
+  
+      }
+  
+          
+    // if we hit the limit on the number of character reads we'e tried, print a message and bail out.
+    if (GPS_char_reads >= GPS_char_reads_maximum) 
+      {
+Serial.println(GPS_sentence);
+      keep_trying = false;
+      
+      Serial.println("GPS navigation data not yet available. Try again later.");
+    
+        
+      return -1;
+        
+      }
+
+    // get the last complete sentence read from GP; this automatically clears a newline flag inside 
+    // the Adafruit library code.
+    GPS_sentence = GPS.lastNMEA();
+    
+    // convert GPS data sentence from a character array to a string.
+    GPS_sentence_string = String(GPS_sentence);
+  
+    // now do a cursory check that the sentence we've just read is OK. Check that there is only
+    // one $, as the first character in the sentence, and that there's an asterisk (which commes 
+    // immediately before the checksum).
+     
+    // sentence starts with a $? 
+    bool data_OK = GPS_sentence_string.charAt(0) == '$';    
+  
+    // sentence contains no other $? The indexOf call will return -1 if $ is not found.
+    data_OK = data_OK && (GPS_sentence_string.indexOf('$', 2) <  0);
+    
+    // now find that asterisk...
+    data_OK = data_OK && (GPS_sentence_string.indexOf('*', 0) >  0);
+  
+    if (GPSECHO1) 
+      {
+      Serial.println("\n******************\njust received a complete sentence, so parse stuff. Sentence is");
+      Serial.println(GPS_sentence_string);
+      }
+  
+    // now parse the GPS sentence. I am only interested in sentences that begin with
+    // $GPGGA ("GPS fix data") or $GPRMC ("recommended minimum specific GPS/Transit data").
+  
+    if(GPSECHO1)
+      {
+      Serial.print("length of GPS_sentence_string just received...");
+      Serial.println(GPS_sentence_string.length());
+      }
+  
+    // now get substring holding the GPS command. Only proceed if it is $GPRMC or $GPGGA.
+    GPS_command = GPS_sentence_string.substring(0, 6);
+  
+    // also trim it to make sure we don't have hidden stuff or white space sneaking in.
+    GPS_command.trim();
+  
+    if(GPSECHO1) 
+      {
+      Serial.print("GPS command is "); Serial.println(GPS_command);
+      }   
+  
+    // if data_OK is true then we have a good sentence. but we also need the sentence
+    // to hold navigational data we can use, otherwise we'll want to keep listening.
+    // we can only work with GPRMC and GPGGA sentences. 
+  
+    bool command_OK = GPS_command.equals("$GPRMC") || GPS_command.equals("$GPGGA"); 
+    
+    // if we have a sentence that, upon cursory inspection, is well formatted AND might
+    // hold navigational data, continue to parse the sentence. If the GPS device
+    // hasn't found any satellites yet, we'll want to go back to the top of the loop
+    // to keep trying, rather than declaring defeat and returning.
+  
+    //////////////////////////////////////////////////////////////////////
+    /////////////////////////// GPRMC sentence ///////////////////////////
+    //////////////////////////////////////////////////////////////////////
+    
+     if (data_OK && GPS_command.equals("$GPRMC"))
+        {
+            
+        if(GPSECHO2) 
+          {
+          Serial.print("\nnew GPS sentence: "); Serial.println(GPS_sentence_string);
+          }
+    
+        // parse the time. these are global variables, already declared.
+
+        GPS_hour_string = GPS_sentence_string.substring(GPRMC_hour_index1, GPRMC_hour_index2);
+        GPS_minutes_string = GPS_sentence_string.substring(GPRMC_minutes_index1, GPRMC_minutes_index2);
+        GPS_seconds_string = GPS_sentence_string.substring(GPRMC_seconds_index1, GPRMC_seconds_index2);
+        GPS_milliseconds_string = GPS_sentence_string.substring(GPRMC_milliseconds_index1, 
+          GPRMC_milliseconds_index2);
+        GPS_AV_code_string = GPS_sentence_string.substring(GPRMC_AV_code_index1, GPRMC_AV_code_index2);
+    
+        GPS_hour = GPS_hour_string.toInt();
+        GPS_minutes = GPS_minutes_string.toInt();
+        GPS_seconds = GPS_seconds_string.toInt();
+        GPS_milliseconds = GPS_milliseconds_string.toInt();
+    
+        if(GPSECHO2)
+          {
+          Serial.print("Time (UTC) = "); Serial.print(GPS_hour); Serial.print(":");
+          Serial.print(GPS_minutes); Serial.print(":");
+          Serial.print(GPS_seconds); Serial.print(".");
+          Serial.println(GPS_milliseconds);
+          Serial.print("A/V code is "); Serial.println(GPS_AV_code_string);
+          }
+    
+        // now see if the data are valid: we'll expect an "A" as the AV code string.
+        // We also expect an asterisk two characters from the end. Also check that the sentence 
+        // is at least as long as the minimum length expected.
+    
+        data_OK = GPS_AV_code_string == "A";
+    
+        // now look for the asterisk after trimming any trailing whitespace in the GPS sentence.
+        // the asterisk preceeds the sentence's checksum information, which I won't bother to check.
+        int asterisk_should_be_here = GPS_sentence_string.length() - 4; 
+    
+        data_OK = data_OK && (GPS_sentence_string.charAt(asterisk_should_be_here) == '*');
+
+        if(GPSECHO2)
+          {
+          Serial.print("expected asterisk position "); Serial.print(asterisk_should_be_here); 
+          Serial.print(" at that position: "); Serial.println(GPS_sentence_string.charAt(asterisk_should_be_here));
+          }
+    
+        // now check that the sentence is not too short.      
+        data_OK = data_OK && (GPS_sentence_string.length() >= GPSMINLENGTH);
+    
+        if (!data_OK) 
+          {
+
+          keep_trying = true;
+           
+          if (GPSECHO1)
+            {
+            Serial.print("GPS sentence not good for navigation: "); Serial.println(GPS_sentence_string);
+            Serial.println("I will keep trying...");
+            }
+            
+ 
+          }
+    
+        // if data are not good, go back to the top of the loop by breaking out of this if block.
+        // we've already set keep_trying to be true.
+        
+        if (!data_OK) break;
+            
+        // so far so good, so keep going...
+        
+        // now parse latitude 
+        
+        GPS_latitude_1_string = GPS_sentence_string.substring(GPRMC_latitude_1_index1, 
+          GPRMC_latitude_1_index2);
+        GPS_latitude_2_string = GPS_sentence_string.substring(GPRMC_latitude_2_index1, 
+          GPRMC_latitude_2_index2);
+        GPS_latitude_NS_string = GPS_sentence_string.substring(GPRMC_latitude_NS_index1, 
+          GPRMC_latitude_NS_index2);
+    
+        GPS_latitude_1 = GPS_latitude_1_string.toInt();      
+        GPS_latitude_2 = GPS_latitude_2_string.toInt();      
+    
+        if(GPSECHO2)
+          {
+          Serial.print("Latitude x 100 = "); Serial.print(GPS_latitude_1); Serial.print(".");
+          Serial.print(GPS_latitude_2); Serial.println(GPS_latitude_NS_string);
+          }
+          
+        // now parse longitude 
+        
+        GPS_longitude_1_string = GPS_sentence_string.substring(GPRMC_longitude_1_index1, 
+          GPRMC_longitude_1_index2);
+        GPS_longitude_2_string = GPS_sentence_string.substring(GPRMC_longitude_2_index1, 
+          GPRMC_longitude_2_index2);
+        GPS_longitude_EW_string = GPS_sentence_string.substring(GPRMC_longitude_EW_index1, 
+          GPRMC_longitude_EW_index2);
+    
+        GPS_longitude_1 = GPS_longitude_1_string.toInt();      
+        GPS_longitude_2 = GPS_longitude_2_string.toInt();      
+          
+        if(GPSECHO2)
+          {
+          Serial.print("Longitude x 100 = "); Serial.print(GPS_longitude_1); Serial.print(".");
+          Serial.print(GPS_longitude_2); Serial.println(GPS_longitude_EW_string); 
+          }
+    
+        // now parse speed and direction. we'll need to locate the 7th and 8th commas in the
+        // data sentence to do this. so use the indexOf function to find them.
+        // it returns -1 if string wasn't found. the number of digits is not uniquely defined 
+        // so we need to find the fields based on the commas separating them from others.
+        
+        int comma_A_index = GPRMC_longitude_EW_index2;
+        int comma_B_index = GPS_sentence_string.indexOf(",", comma_A_index + 1);
+        int comma_C_index = GPS_sentence_string.indexOf(",", comma_B_index + 1);
+    
+        GPS_speed_knots_string = GPS_sentence_string.substring(comma_A_index + 1, comma_B_index); 
+        GPS_direction_string = GPS_sentence_string.substring(comma_B_index + 1, comma_C_index); 
+        
+        GPS_speed_knots = GPS_speed_knots_string.toFloat();
+        GPS_direction = GPS_direction_string.toFloat();
+    
+        if(GPSECHO2)
+          {
+          Serial.print("Speed (knots) = "); Serial.println(GPS_speed_knots);
+          Serial.print("Direction (degrees) = "); Serial.println(GPS_direction);
+          }
+          
+        // now get the (UTC) date, in format DDMMYY, e.g. 080618 for 8 June 2018.
+        GPS_date_string = GPS_sentence_string.substring(comma_C_index+ + 1, comma_C_index + 7);
+        
+        if(GPSECHO2)
+          {
+          Serial.print("date, in format ddmmyy = "); Serial.println(GPS_date_string);    
+          }
+    
+        // Write message to LCD now. It will look like this (no satellite data in this record):
+        //     Sats: 4006.9539N
+        //     N/A  08815.4431W
+
+
+        // print a summary of the data and parsed results:
+        if(GPSECHO3)
+          {
+          Serial.print("GPS sentence: "); Serial.println(GPS_sentence_string);
+
+          Serial.print("Time (UTC) = "); Serial.print(GPS_hour); Serial.print(":");
+          Serial.print(GPS_minutes); Serial.print(":");
+          Serial.print(GPS_seconds); Serial.print(".");
+          Serial.println(GPS_milliseconds);
+        
+          Serial.print("Latitude x 100 = "); Serial.print(GPS_latitude_1); Serial.print(".");
+          Serial.print(GPS_latitude_2); Serial.print(" "); Serial.print(GPS_latitude_NS_string);
+
+          Serial.print("    Longitude x 100 = "); Serial.print(GPS_longitude_1); Serial.print(".");
+          Serial.print(GPS_longitude_2); Serial.print(" "); Serial.println(GPS_longitude_EW_string); 
+
+          Serial.print("Speed (knots) = "); Serial.print(GPS_speed_knots);
+          Serial.print("     Direction (degrees) = "); Serial.println(GPS_direction);
+
+          Serial.println("There is no satellite or altitude information in a GPRMC data sentence.");
+              
+          }
+      
+        // all done with this sentence, so return.
+        return 0;
+          
+        }  // end of "if (data_OK && GPS_command.equals("$GPRMC"))" block
+
+    //////////////////////////////////////////////////////////////////////
+    /////////////////////////// GPGGA sentence ///////////////////////////
+    //////////////////////////////////////////////////////////////////////
+    
+      if (data_OK && GPS_command.equals("$GPGGA"))
+        {
+
+        if(GPSECHO2) 
+          {
+          Serial.print("\nnew GPS sentence: "); Serial.println(GPS_sentence_string);
+          }
+    
+        // parse the time
+    
+        GPS_hour_string = GPS_sentence_string.substring(GPGGA_hour_index1, GPGGA_hour_index2);
+        GPS_minutes_string = GPS_sentence_string.substring(GPGGA_minutes_index1, GPGGA_minutes_index2);
+        GPS_seconds_string = GPS_sentence_string.substring(GPGGA_seconds_index1, GPGGA_seconds_index2);
+        GPS_milliseconds_string = GPS_sentence_string.substring(GPGGA_milliseconds_index1, 
+          GPGGA_milliseconds_index2);
+    
+        GPS_hour = GPS_hour_string.toInt();
+        GPS_minutes = GPS_minutes_string.toInt();
+        GPS_seconds = GPS_seconds_string.toInt();
+        GPS_milliseconds = GPS_milliseconds_string.toInt();
+    
+        if(GPSECHO2)
+          {
+          Serial.print("Time (UTC) = "); Serial.print(GPS_hour); Serial.print(":");
+          Serial.print(GPS_minutes); Serial.print(":");
+          Serial.print(GPS_seconds); Serial.print(".");
+          Serial.println(GPS_milliseconds);
+          }
+    
+        // now get the fix quality and number of satellites.
+    
+        GPS_fix_quality_string = GPS_sentence_string.substring(GPGGA_fix_quality_index1, 
+          GPGGA_fix_quality_index2);
+        GPS_satellites_string = GPS_sentence_string.substring(GPGGA_satellites_index1, 
+          GPGGA_satellites_index2);
+    
+        int GPS_fix_quality = GPS_fix_quality_string.toInt();      
+        int GPS_satellites = GPS_satellites_string.toInt();      
+    
+        if(GPSECHO2)
+          {
+          Serial.print("fix quality (1 for GPS, 2 for DGPS) = "); Serial.println(GPS_fix_quality);
+          Serial.print("number of satellites = "); Serial.println(GPS_satellites);
+          }
+    
+        // now see if the data are valid: we'll expect a fix, and at least three satellites.
+    
+        bool data_OK = (GPS_fix_quality > 0) && (GPS_satellites >= 3); 
+    
+        // now look for the asterisk.
+        int asterisk_should_be_here = GPS_sentence_string.length() - 4; 
+    
+        data_OK = data_OK && (GPS_sentence_string.charAt(asterisk_should_be_here) == '*');
+    
+        // now check that the sentence is not too short.      
+        data_OK = data_OK && (GPS_sentence_string.length() >= GPSMINLENGTH);
+
+        if (!data_OK) 
+          {
+
+          keep_trying = true;
+           
+          if (GPSECHO1)
+            {
+            Serial.print("GPS sentence not good for navigation: "); Serial.println(GPS_sentence_string);
+            Serial.println("I will keep trying...");
+            }
+
+          }
+    
+        // if data are not good, go back to the top of the loop by breaking out of this if block.
+        
+        if (!data_OK) break;
+            
+        // so far so good, so keep going...
+        
+        // now parse latitude 
+        
+        String GPS_latitude_1_string = GPS_sentence_string.substring(GPGGA_latitude_1_index1, 
+        GPGGA_latitude_1_index2);
+        String GPS_latitude_2_string = GPS_sentence_string.substring(GPGGA_latitude_2_index1, 
+        GPGGA_latitude_2_index2);
+        String GPS_latitude_NS_string = GPS_sentence_string.substring(GPGGA_latitude_NS_index1, 
+        GPGGA_latitude_NS_index2);
+    
+        int GPS_latitude_1 = GPS_latitude_1_string.toInt();      
+        int GPS_latitude_2 = GPS_latitude_2_string.toInt();      
+    
+        if(GPSECHO2)
+          {
+          Serial.print("Latitude x 100 = "); Serial.print(GPS_latitude_1); Serial.print(".");
+          Serial.print(GPS_latitude_2); Serial.println(GPS_latitude_NS_string);
+          }
+          
+        // now parse longitude 
+        
+        String GPS_longitude_1_string = GPS_sentence_string.substring(GPGGA_longitude_1_index1, 
+        GPGGA_longitude_1_index2);
+        String GPS_longitude_2_string = GPS_sentence_string.substring(GPGGA_longitude_2_index1, 
+        GPGGA_longitude_2_index2);
+        String GPS_longitude_EW_string = GPS_sentence_string.substring(GPGGA_longitude_EW_index1, 
+        GPGGA_longitude_EW_index2);
+    
+        int GPS_longitude_1 = GPS_longitude_1_string.toInt();      
+        int GPS_longitude_2 = GPS_longitude_2_string.toInt();      
+    
+        if(GPSECHO2)
+          {         
+          Serial.print("Longitude x 100 = "); Serial.print(GPS_longitude_1); Serial.print(".");
+          Serial.print(GPS_longitude_2); Serial.println(GPS_longitude_EW_string); 
+          }
+          
+        // let's skip the "horizontal dilution" figure and go straight for the altitude now.
+        // this begins two fields to the right of the num,ber of satellites so find this
+        // by counting commas. use the indexOf function to find them.
+        int comma_A_index = GPS_sentence_string.indexOf(",", GPGGA_satellites_index2 + 1);
+        int comma_B_index = GPS_sentence_string.indexOf(",", comma_A_index + 1);
+    
+        String GPS_altitude_string = GPS_sentence_string.substring(comma_A_index + 1, comma_B_index); 
+        
+        float GPS_altitude = GPS_altitude_string.toFloat();
+    
+        if(GPSECHO2)
+          {
+          Serial.print("Altitude (meters) = "); Serial.println(GPS_altitude);
+          }
+    
+        // Write message to LCD now. It will look like this:
+        //     Sats: 4006.9539N
+        //       10 08815.4431W
+             
+
+        // print a summary of the data and parsed results:
+        if(GPSECHO3)
+          {
+          Serial.print("GPS sentence: "); Serial.println(GPS_sentence_string);
+
+          Serial.print("Time (UTC) = "); Serial.print(GPS_hour); Serial.print(":");
+          Serial.print(GPS_minutes); Serial.print(":");
+          Serial.print(GPS_seconds); Serial.print(".");
+          Serial.println(GPS_milliseconds);
+        
+          Serial.print("Latitude x 100 = "); Serial.print(GPS_latitude_1); Serial.print(".");
+          Serial.print(GPS_latitude_2); Serial.print(" "); Serial.print(GPS_latitude_NS_string);
+
+          Serial.print("    Longitude x 100 = "); Serial.print(GPS_longitude_1); Serial.print(".");
+          Serial.print(GPS_longitude_2); Serial.print(" "); Serial.println(GPS_longitude_EW_string); 
+
+          Serial.print("Speed (knots) = "); Serial.print(GPS_speed_knots);
+          Serial.print("     Direction (degrees) = "); Serial.println(GPS_direction);
+
+          Serial.print("Number of satellites: "); Serial.print(GPS_satellites);
+          Serial.print("       Altitude (meters): "); Serial.println(GPS_altitude);
+              
+          }
+       
+        // all done with this sentence, so return.
+        return 0;
+       
+      }   // end of "if (data_OK && GPS_command.equals("$GPGGA"))" block
+  
+    // we'll fall through to here (instead of returning) when we've read a complete 
+    // sentence, but it doesn't have navigational information (for example, an antenna 
+    // status record).
+    
+    } 
+
+  }
diff --git a/Homework 3/Question 1 Proof/GPS_test_code.ino b/Homework 3/Question 1 Proof/GPS_test_code.ino
new file mode 100644
index 0000000000000000000000000000000000000000..02fbb7cb1fa9e593ea3a5e63c12698c95977fee9
--- /dev/null
+++ b/Homework 3/Question 1 Proof/GPS_test_code.ino	
@@ -0,0 +1,1189 @@
+#include <Adafruit_GPS.h>
+
+ /*************************************************** 
+  This file is GPS_p398dlp.ino
+
+  Read from the Adaruit GPS breakout board.
+
+  To use this: see the functions setup and loop, and replace things 
+  there with your own code.
+  
+
+  You'll want to do Tools -> Serial Monitor, then set the baud rate to 115,200
+  if you want to stream GPS data to the serial monitor window. If you only set
+  the baud rate to 9600 it'll be too slow, and interfere with data transmission
+  from the GPS device to the Arduino processor.
+
+  Also make sure that Tools -> Port is set to the Arduino's port.
+
+  We are interested in two kinds of "sentences" holding GPS navigational data: one
+  begins with $GPRMC, which holds "Recommended minimum specific GPS/Transit data."
+  The other begins with $GPGGA, which holds "Global Positioning System Fix Data."
+  Both include latitude and longitude. See a description of the formats, below. 
+
+  Here is the $GPRMC format:
+  0 - 5     $GPRMC
+  7 - 8     hour, UTC      
+  9 - 10    minutes, UTC      
+  11 - 12   seconds, UTC
+  14 - 16   milliseconds
+  18        A for navigation data OK, V for navigation data not present.
+  20 - 28   latitude x 100, in degrees; F9.4 format      
+  30        N or S
+  32 - 41   longitude x 100, in degrees; F10.4 format      
+  43        E or W
+  next      speed over the ground, in knots; floating point, 5 characters
+            (data between 7th and 8th commas) 
+  next      course direction, degrees, floating point
+           (data between 8th and 9th commas) 
+  other stuff too. Two examples, the first with navigation information, the second without:
+  $GPRMC,135228.000,A,4006.9605,N,08815.4528,W,0.44,336.27,090618,,,A*71
+  $GPRMC,135217.000,V,,,,,0.74,222.59,090618,,,N*45
+           1         2         3         4         5         6         7         8
+  012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+  Here is the $GPGGA format:
+  0 - 5     $GPGGA
+  7 - 8     hour, UTC      
+  9 - 10    minutes, UTC      
+  11 - 16   seconds, UTC, F6.3 format      
+  18 - 26   latitude x 100, in degrees; F9.4 format      
+  28        N or S
+  30 - 39   longitude x 100, in degrees; F10.4 format      
+  41        E or W
+  43        fix quality: 0 for no fix, 1 for GPS, 2 for DGPS.
+  45 - 46   number of satellites
+  48 - 51   horizontal dilution of precision
+  53 - 57   altitude above sea level
+  59        M for altitude in meters
+  other stuff too. Two examples, the first with navigation information, the second without:
+  $GPGGA,135224.000,4006.9611,N,08815.4523,W,1,07,1.11,211.7,M,-33.9,M,,*53
+  $GPGGA,135217.000,,,,,0,07,,,M,,M,,*7C
+            1         2         3         4         5         6         7         8
+  012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+  Set GPSECHO1 and GPSECHO2 to 'false' to turn off echoing the GPS data to the Serial console
+  that are useful for debugging. Set GPSECHO3 to 'false' to prevent final navigation result 
+  from being printed to monitor. Set one or more to 'true' if you want to debug and listen 
+  to the raw GPS sentences. GPSECHO1 yields more verbose echoing than GPSECHO2.
+    
+  George Gollin
+  University of Illinois
+  September 2018
+
+***************************************************/ 
+
+//////////////////////////////////////////////////////////////////////
+/////////////////////// global parameters ////////////////////////////
+//////////////////////////////////////////////////////////////////////
+
+/////////////////////////// LCD parameters ///////////////////////////
+
+#include <LiquidCrystal.h>
+
+// The LCD is a GlobalFontz 16 x 2 device.
+
+// initialize the LCD library by associating LCD interface pins
+// with the arduino pins to which they are connected. first define
+// the pin numbers: reset (rs), enable (en), etc.
+const int rs = 12, en = 11, d4 = 36, d5 = 34, d6 = 32, d7 = 30;
+
+// instantiate an LCD object named "lcd" now. We can use its class
+// functions to do good stuff, e.g. lcd.print("the text").
+LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
+
+// total number of characters in one line of the LCD display
+#define LCDWIDTH 16
+
+//////////////////////////// keypad parameters ////////////////////////////
+
+#include <Keypad.h>
+
+// keypad has four rows and three columns. pushing one key connects together
+// the corresponding row and column pins.
+
+const byte ROWS = 4;
+const byte COLS = 3;
+
+// what they keys actually stand for:
+char keys[ROWS][COLS] = {
+{'1','2','3'},
+{'4','5','6'},
+{'7','8','9'},
+{'*','0','#'}
+};
+
+// I am using an Arduino Mega 2560 with a number of breakout boards. 
+// I have the following  pin assignments in order to allow the column
+// pins to generate interrupts, if I should decide to take awareness of
+// the keypad this way. Note that there might be complicated interactions
+// between interrupts used to read the microphone's ADC channel and keypad 
+// interrupts. 
+ 
+// Arduino pins looking at the three column pins:
+byte colPins[COLS] = {2, 3, 18}; 
+// Arduino pins looking at the four row pins:
+byte rowPins[ROWS] = {31, 33, 35, 37}; 
+
+// instantiate a keypad object.
+Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
+
+// character returned when I query the keypad (might be empty)
+char query_keypad_char = NO_KEY;
+
+// last non-null character read from keypad
+char last_key_char = NO_KEY;
+
+////////////////////////// DS3231 real time clock parameters ////////////////////////
+
+// this is an I2C device on an Adafruit breakout board. It is a cute little thing 
+// with a backup battery.
+
+#include "RTClib.h"
+
+// instantiate a real time clock object named "rtc":
+RTC_DS3231 rtc;
+
+// names of the days of the week:
+char daysOfTheWeek[7][4] = 
+  {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+
+// declare type for a few RTC-related global variables
+int RTC_hour, RTC_minute, RTC_second;
+int RTC_year, RTC_month, RTC_day_of_month;
+
+
+// have we already set the RTC clock from the GPS?
+bool already_set_RTC_from_GPS;
+   
+/////////////////////////////// GPS parameters /////////////////////////////
+
+// Set GPSECHO1 and GPSECHO2 to 'false' to turn off echoing the GPS data to the Serial console
+// that are useful for debugging. Set GPSECHO3 to 'false' to prevent final navigation result 
+// from being printed to monitor. Set one or more to 'true' if you want to debug and listen 
+//to the raw GPS sentences. GPSECHO1 yields more verbose echoing than GPSECHO2.
+#define GPSECHO1 false
+#define GPSECHO2 false
+#define GPSECHO3 false
+
+// get the header file in which lots of things are defined:
+#include <Adafruit_GPS.h>
+
+// also define some more stuff relating to update rates. See 
+// https://blogs.fsfe.org/t.kandler/2013/11/17/set-gps-update-
+// rate-on-arduino-uno-adafruit-ultimate-gps-logger-shield/
+#define PMTK_SET_NMEA_UPDATE_10SEC "$PMTK220,10000*2F"
+#define PMTK_SET_NMEA_UPDATE_5SEC "$PMTK220,5000*2F"
+#define PMTK_SET_NMEA_UPDATE_1HZ  "$PMTK220,1000*1F"
+#define PMTK_SET_NMEA_UPDATE_2HZ  "$PMTK220,500*2B"
+#define PMTK_SET_NMEA_UPDATE_5HZ  "$PMTK220,200*2C"
+
+// let's use the Arduino's second serial port to communicate with the GPS device.
+#define GPSSerial Serial2
+
+// Connect to the GPS via the Arduino's hardware port
+Adafruit_GPS GPS(&GPSSerial);
+     
+// we don't expect a valid GPS "sentence" to be longer than this...
+#define GPSMAXLENGTH 120
+// or shorter than this:
+#define GPSMINLENGTH 55
+
+// last sentence read from the GPS:
+char* GPS_sentence;
+
+// we'll also want to convert the character array to a string for convenience
+String GPS_sentence_string;
+
+String GPS_command;
+
+// pointers into parts of a GPRMC GPS data sentence:
+
+const int GPRMC_hour_index1 = 8;
+const int GPRMC_hour_index2 = GPRMC_hour_index1 + 2;
+
+const int GPRMC_minutes_index1 = GPRMC_hour_index2;
+const int GPRMC_minutes_index2 = GPRMC_minutes_index1 + 2;
+      
+const int GPRMC_seconds_index1 = GPRMC_minutes_index2;
+const int GPRMC_seconds_index2 = GPRMC_seconds_index1 + 2;
+      
+const int GPRMC_milliseconds_index1 = GPRMC_seconds_index2 + 1;   // skip the decimal point
+const int GPRMC_milliseconds_index2 = GPRMC_milliseconds_index1 + 3;
+      
+const int GPRMC_AV_code_index1 = 19;
+const int GPRMC_AV_code_index2 = GPRMC_AV_code_index1 + 1;
+      
+const int GPRMC_latitude_1_index1 = 21;
+const int GPRMC_latitude_1_index2 = GPRMC_latitude_1_index1 + 4;
+      
+const int GPRMC_latitude_2_index1 = GPRMC_latitude_1_index2 + 1;   // skip the decimal point
+const int GPRMC_latitude_2_index2 = GPRMC_latitude_2_index1 + 4;
+
+const int GPRMC_latitude_NS_index1 = 31;
+const int GPRMC_latitude_NS_index2 = GPRMC_latitude_NS_index1 + 1;
+
+const int GPRMC_longitude_1_index1 = 33;
+const int GPRMC_longitude_1_index2 = GPRMC_longitude_1_index1 + 5;    // 0 - 180 so we need an extra digit
+      
+const int GPRMC_longitude_2_index1 = GPRMC_longitude_1_index2 + 1;   // skip the decimal point
+const int GPRMC_longitude_2_index2 = GPRMC_longitude_2_index1 + 4;
+      
+const int GPRMC_longitude_EW_index1 = 44;
+const int GPRMC_longitude_EW_index2 = GPRMC_longitude_EW_index1 + 1;
+
+// pointers into a GPGGA GPS data sentence:
+
+const int GPGGA_hour_index1 = 8;
+const int GPGGA_hour_index2 = GPGGA_hour_index1 + 2;
+
+const int GPGGA_minutes_index1 = GPGGA_hour_index2;
+const int GPGGA_minutes_index2 = GPGGA_minutes_index1 + 2;
+      
+const int GPGGA_seconds_index1 = GPGGA_minutes_index2;
+const int GPGGA_seconds_index2 = GPGGA_seconds_index1 + 2;
+      
+const int GPGGA_milliseconds_index1 = GPGGA_seconds_index2 + 1;   // skip the decimal point
+const int GPGGA_milliseconds_index2 = GPGGA_milliseconds_index1 + 3;
+      
+const int GPGGA_latitude_1_index1 = 19;
+const int GPGGA_latitude_1_index2 = GPGGA_latitude_1_index1 + 4;
+      
+const int GPGGA_latitude_2_index1 = GPGGA_latitude_1_index2 + 1;   // skip the decimal point
+const int GPGGA_latitude_2_index2 = GPGGA_latitude_2_index1 + 4;
+
+const int GPGGA_latitude_NS_index1 = 29;
+const int GPGGA_latitude_NS_index2 = GPGGA_latitude_NS_index1 + 1;
+
+const int GPGGA_longitude_1_index1 = 31;
+const int GPGGA_longitude_1_index2 = GPGGA_longitude_1_index1 + 5;    // 0 - 180 so we need an extra digit
+      
+const int GPGGA_longitude_2_index1 = GPGGA_longitude_1_index2 + 1;   // skip the decimal point
+const int GPGGA_longitude_2_index2 = GPGGA_longitude_2_index1 + 4;
+      
+const int GPGGA_longitude_EW_index1 = 42;
+const int GPGGA_longitude_EW_index2 = GPGGA_longitude_EW_index1 + 1;
+
+const int GPGGA_fix_quality_index1 = 44;
+const int GPGGA_fix_quality_index2 = GPGGA_fix_quality_index1 + 1;
+
+const int GPGGA_satellites_index1 = 46;
+const int GPGGA_satellites_index2 = GPGGA_satellites_index1 + 2;
+
+// keep track of how many times we've read a character from the GPS device. 
+long GPS_char_reads = 0;
+
+// bail out if we exceed the following number of attempts. when set to 1,000,000 this corresponds
+// to about 6 seconds. we need to do this to keep an unresponsive GPS device from hanging the program.
+const long GPS_char_reads_maximum = 1000000;
+
+// define some of the (self-explanatory) GPS data variables. Times/dates are UTC.
+String GPS_hour_string;
+String GPS_minutes_string;
+String GPS_seconds_string;
+String GPS_milliseconds_string;
+int GPS_hour;
+int GPS_minutes;
+int GPS_seconds;
+int GPS_milliseconds;
+
+// this one tells us about data validity: A is good, V is invalid.
+String GPS_AV_code_string;
+
+// latitude data
+String GPS_latitude_1_string;
+String GPS_latitude_2_string;
+String GPS_latitude_NS_string;
+int GPS_latitude_1;
+int GPS_latitude_2;
+
+// longitude data
+String GPS_longitude_1_string;
+String GPS_longitude_2_string;
+String GPS_longitude_EW_string;
+int GPS_longitude_1;
+int GPS_longitude_2;
+
+// velocity information; speed is in knots! 
+String GPS_speed_knots_string;
+String GPS_direction_string;
+float GPS_speed_knots;
+float GPS_direction;
+
+String GPS_date_string;
+
+String GPS_fix_quality_string;
+String GPS_satellites_string;
+int GPS_fix_quality;
+int GPS_satellites;
+
+String GPS_altitude_string;
+float GPS_altitude;
+
+//////////////////////////////////////////////////////////////////////
+//////////////////// end of global parameters ////////////////////////
+//////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////
+///////////////////////// setup function /////////////////////////////
+//////////////////////////////////////////////////////////////////////
+
+void setup() 
+{
+
+  // setup is run once, immediately after the program is downloaded into
+  // the Arduino. 
+
+  /////////////////// serial port for serial monitor window ///////////////////
+
+  // set to 115,200 baud so that we don't cause problems associated with reading
+  // and reporting GPS data.
+  Serial.begin(115200);
+
+ /////////////////////////// LCD setup ////////////////////////////
+
+  // set up the LCD's number of columns and rows, then print a message:
+  lcd.begin(16, 2);
+  LCD_message("P398DLP GPS data", "reader/parser   ");
+
+  // delay a bit so I have time to see the display.
+  delay(1000);
+  
+/////////////////////////// DS3231 real time clock  setup /////////////////////////
+
+  // turn on the RTC and check that it is talking to us.
+
+  if (! rtc.begin()) {
+
+    // uh oh, it's not talking to us.
+    LCD_message("DS3231 RTC", "unresponsive");
+    // delay 5 seconds so that user can read the display
+    delay(5000);  
+
+    } else {
+
+  if (rtc.lostPower()) {
+  
+    LCD_message("DS3231 RTC lost", "power. Set to...");
+
+    // Set the RTC with an explicit date & time: September 1, 1988, 7:37:00 am
+    rtc.adjust(DateTime(1988, 9, 1, 7, 37, 0));
+    
+    }
+  }
+  
+  // set flag that we haven't already set the RTC clock from the GPS
+  already_set_RTC_from_GPS = false;
+
+  // ask user for year, month, day of the month. see 
+  // https://www.arduino.cc/en/Tutorial.StringToIntExample
+
+  Serial.println("Please enter the year (e.g. 2018) now.");
+
+  String inString = "";    // string to hold input
+  int inChar = 12345;
+
+  // did we NOT just get a new line character?
+  while (inChar != '\n' and inChar != '\r') {
+
+    // see if there's any new input.
+    while (Serial.available() > 0) {
+
+      // read the input character
+      inChar = Serial.read();
+
+      if (isDigit(inChar)) {
+        // convert the incoming byte to a char and add it to the string:
+        inString += (char)inChar;
+      }
+
+      // if you get a newline, print the string, then the string's value:
+      if (inChar == '\n' or inChar == '\r') {
+        RTC_year = inString.toInt();
+        // clear the string for new input:
+        inString = "";
+      }      
+    }
+  }
+
+  Serial.println("Please enter the month (e.g. 1 for January) now.");
+
+  inString = "";    // string to hold input
+  inChar = 12345;
+
+  // did we NOT just get a new line character?
+  while (inChar != '\n' and inChar != '\r') {
+
+    // see if there's any new input.
+    while (Serial.available() > 0) {
+
+      // read the input character
+      inChar = Serial.read();
+
+      if (isDigit(inChar)) {
+        // convert the incoming byte to a char and add it to the string:
+        inString += (char)inChar;
+      }
+
+      // if you get a newline, print the string, then the string's value:
+      if (inChar == '\n' or inChar == '\r') {
+        RTC_month = inString.toInt();
+        // clear the string for new input:
+        inString = "";
+      }      
+    }
+  }
+
+  Serial.println("Please enter the day of the month (e.g. 1 for January 1st) now.");
+
+  inString = "";    // string to hold input
+  inChar = 12345;
+
+  // did we NOT just get a new line character?
+  while (inChar != '\n' and inChar != '\r') {
+
+    // see if there's any new input.
+    while (Serial.available() > 0) {
+
+      // read the input character
+      inChar = Serial.read();
+
+      if (isDigit(inChar)) {
+        // convert the incoming byte to a char and add it to the string:
+        inString += (char)inChar;
+      }
+
+      // if you get a newline, print the string, then the string's value:
+      if (inChar == '\n' or inChar == '\r') {
+        RTC_day_of_month = inString.toInt();
+        // clear the string for new input:
+        inString = "";
+      }      
+    }
+  }
+  
+  Serial.print("you've entered the year, month, day as "); Serial.print(RTC_year); Serial.print("/");
+  Serial.print(RTC_month); Serial.print("/");
+  Serial.println(RTC_day_of_month); 
+  
+////////////////////////////////// GPS setup //////////////////////////////
+
+  // If you want to see a detailed report of the GPS information, open a serial 
+  // monitor window by going to the Tools -> Serial Monitor menu, then checking
+  // the Autoscroll box at the bottom left of the window, and setting the baud rate
+  // to 115200 baud.
+
+  // once we've set up the GPS it will free-run: it has its own built-in microprocessor.
+     
+  // 9600 NMEA is the default communication and baud rate for Adafruit MTK GPS units. 
+  // NMEA is "National Marine Electronics Association." 
+  // Note that this serial communication path is different from the one driving the serial 
+  // monitor window on your laptop, which should be running at 115,200 baud.
+  GPS.begin(9600);
+  
+  // turn on RMC (recommended minimum) and GGA (fix data, including altitude)
+  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
+  
+  // uncomment this line to turn on only the "minimum recommended" data:
+  // GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
+  
+  // Set the update rate to once per second. Faster than this might make it hard for
+  // the serial communication line to keep up. You'll want to check that the 
+  // faster read rates work reliably for you before using them. 
+
+  // what the heck... let's try 5 Hz.
+  //GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); 
+  // GPS.sendCommand(PMTK_SET_NMEA_UPDATE_2HZ); 
+  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_5HZ); 
+  // GPS.sendCommand(PMTK_SET_NMEA_UPDATE_10HZ); 
+  
+  // Request updates on antenna status, comment out to keep quiet.
+  // GPS.sendCommand(PGCMD_ANTENNA);
+
+  // Ask for firmware version, write this to the serial monitor. Comment out to keep quiet.
+  // GPSSerial.println(PMTK_Q_RELEASE);
+
+/////////////////////////////////////////////////////////////////////////
+
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//////////////////////////// loop function ///////////////////////////
+//////////////////////////////////////////////////////////////////////
+
+void loop() 
+{
+
+  // loop function is executed repeatedly after the setup function finishes.
+    
+  // request GPS position information
+  GPS_query();
+
+  // now print some of it: the data are stored in global variables and can
+  // be accessed here. variable names are self explanatory.
+  Serial.print("\nGPS_hour (UTC) = "); Serial.print(GPS_hour); 
+  Serial.print("   GPS_minutes = "); Serial.print(GPS_minutes); 
+  Serial.print("   GPS_seconds = "); Serial.print(GPS_seconds); 
+  Serial.print("   GPS_milliseconds = "); Serial.println(GPS_milliseconds); 
+  
+  Serial.print("100 x lattitude and longitude (degrees): ");
+  Serial.print(GPS_latitude_1_string); Serial.print("."); Serial.print(GPS_latitude_2_string); 
+  Serial.print(GPS_latitude_NS_string); Serial.print("    ");
+  Serial.print(GPS_longitude_1_string); Serial.print("."); Serial.print(GPS_longitude_2_string); 
+  Serial.println(GPS_longitude_EW_string);
+
+  Serial.print("GPS_speed_knots = "); Serial.print(GPS_speed_knots); 
+  Serial.print("   GPS speed, mph = "); Serial.print(GPS_speed_knots * 1.15078); 
+  Serial.print("   direction (degrees) = "); Serial.println(GPS_direction);
+
+  // Serial.print("try GPS.now... "); Serial.println(GPS.now);
+    
+  delay(500);
+
+  // if we have GPS data and haven't yet set the RTC, set the clock now.
+  if( (GPS_hour != 0 or GPS_minutes != 0 or GPS_seconds != 0 or GPS_milliseconds != 0)
+      and !already_set_RTC_from_GPS) {
+
+    // we have something coming in from the GPS, and haven't yet set the real time 
+    // clock, so set the RTC now using the last data sentence from the GPS. This isn't
+    // the most accurate way to do it, but it ought to get us within a second of the
+    // correct time.
+
+    // To set the RTC with an explicit date & time: September 1, 1988, 7:37:00 am do this:
+    // rtc.adjust(DateTime(1988, 9, 1, 7, 37, 0));
+    
+    rtc.adjust(DateTime(RTC_year, RTC_month, RTC_day_of_month, GPS_hour, GPS_minutes, GPS_seconds));
+    already_set_RTC_from_GPS = true;
+
+  }
+  
+  // talk to the realtime clock and print its information. note that unless you've 
+  // synchronized the RTC and GPS, they won't necessarily agree.
+  DS3231_query();
+
+  Serial.print("RTC_hour = "); Serial.print(RTC_hour);
+  Serial.print("   RTC_minute = "); Serial.print(RTC_minute);
+  Serial.print("   RTC_second = "); Serial.println(RTC_second);
+
+  delay(500);
+  
+}
+
+
+//////////////////////////////////////////////////////////////////////
+////////////////////////// LCD_message function //////////////////////
+//////////////////////////////////////////////////////////////////////
+
+void LCD_message(String line1, String line2)
+{
+  // write two lines (of 16 characters each, maximum) to the LCD display.
+  // I assume an object named "lcd" has been created already, has been 
+  // initialized in setup, and is global.
+
+  // set the cursor to the beginning of the first line, clear the line, then write.
+  lcd.setCursor(0, 0);
+  lcd.print("                ");
+  lcd.setCursor(0, 0);
+  lcd.print(line1);
+
+  // now do the next line.
+  lcd.setCursor(0, 1);
+  lcd.print("                ");
+  lcd.setCursor(0, 1);
+  lcd.print(line2);
+
+  return;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+////////////////////// DS3231_query function /////////////////////////
+//////////////////////////////////////////////////////////////////////
+
+void DS3231_query()
+{
+  // read from the DS3231 real time clock.
+
+  // these were already declared as global variables.
+  // int RTC_minute, RTC_second;
+  
+  // we have already instantiated the device as an object named "now" so we can
+  // call its class functions.
+  DateTime now = rtc.now();
+
+  lcd.setCursor(0, 0);
+  lcd.print("Realtime clock  ");
+  
+  // write time information to LCD. Year, etc. first, after setting LCD to second line.
+  lcd.setCursor(0, 1);
+  lcd.print("                ");
+  lcd.setCursor(0, 1);
+  lcd.print(now.year(), DEC);
+  lcd.print('/');
+  lcd.print(now.month(), DEC);
+  lcd.print('/');
+  lcd.print(now.day(), DEC);
+
+  // delay a second
+  delay(1000);
+
+  // now display the day of the week and time.
+  RTC_hour = now.hour();
+  RTC_minute = now.minute();
+  RTC_second = now.second();  
+  
+  lcd.setCursor(0, 1);
+  lcd.print("                ");
+  lcd.setCursor(0, 1);
+  lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
+  lcd.print(". ");
+  
+  lcd.print(RTC_hour, DEC);
+  lcd.print(':');
+  if (RTC_minute < 10) {lcd.print('0');}
+  lcd.print(RTC_minute, DEC);
+  lcd.print(':');
+  if (RTC_second < 10) {lcd.print('0');}
+  lcd.print(RTC_second, DEC);
+
+  // there are other functions available, such as 
+  //    now.unixtime();
+  //    DateTime future (now + TimeSpan(7,12,30,6));
+  //    future.year(); etc. etc.
+
+}
+
+
+
+//////////////////////////////////////////////////////////////////////
+////////////////////// GPS_query function /////////////////////////
+//////////////////////////////////////////////////////////////////////
+
+int GPS_query()
+{
+
+  // return 0 if we found good GPS navigational data and -1 if not.
+  
+  // The GPS device has its own microprocessor and, once we have loaded its parameters,
+  // free-runs at a 1 Hz sampling rate. We do not trigger its registration of
+  // latitude and longitude, rather we just read from it the last data record
+  // it has stored. And we do it one character at a time!
+
+  // I will keep reading from the GPS until I have a complete sentence carrying valid
+  // navigational data, with a maximum number of reads to prevent the program from hanging. Once
+  // the GPS reports its updates latitude/longitude information, we'll push this to the 
+  // LCD display, then return to the main loop. 
+   
+  // zero out (or set to defaults) values returned by the GPS device in case we can't 
+  // get it to respond.
+  GPS_hour = GPS_minutes = GPS_seconds = GPS_milliseconds = 0;
+
+  GPS_AV_code_string = "V";
+
+  GPS_latitude_1 = GPS_latitude_2 = 0;
+  GPS_latitude_NS_string = "x";
+  
+  GPS_longitude_1 = GPS_longitude_2 = 0;
+  GPS_longitude_EW_string = "y";
+    
+  GPS_speed_knots = 0.;
+  GPS_direction = 0.;
+    
+  GPS_date_string = "000000";
+  
+  GPS_fix_quality = GPS_satellites = 0;
+  
+  GPS_altitude = 0.;
+
+  // initialize the number-of-reads counter since we might find ourselves
+  // with an unparseable data record, or an unresponsive GPS, and want to keep trying.
+  // This will let me protect against the data logger's program hanging. 
+  GPS_char_reads = 0;
+
+  // set a flag saying we want to keep trying; we'll use this to keep looking for
+  // useful navigation when the GPS is working fine, but still looking for satellites.
+  bool keep_trying = true;
+  
+  // Stay inside the following loop until we've read a complete GPS sentence with
+  // good navigational data, or else the loop times out. With GPS_char_reads_maximum 
+  // set to a million this'll take about 6 seconds to time out. 
+  
+  while (true) {
+  
+    // if we get back to this point but the keep_trying flag is false, we'll want
+    // to declare failure and quit.
+
+    if(!keep_trying) return -1;
+    
+    // this gets the last sentence read from GPS and clears a newline flag in the Adafruit 
+    // library code.
+    GPS_sentence = GPS.lastNMEA();
+  
+    while(GPS_char_reads <= GPS_char_reads_maximum) 
+      {
+  
+      // try to read a single character from the GPS device.
+      char single_GPS_char = GPS.read();
+  
+      // bump the number of times we've tried to read from the GPS.
+      GPS_char_reads++;
+  
+      // now ask if we've received a complete data sentence. If yes, break
+      // out of this loop.
+  
+      if(GPS.newNMEAreceived()) break;
+  
+      }
+  
+      
+    // if we hit the limit on the number of character reads we'e tried, print a message and bail out.
+    if (GPS_char_reads >= GPS_char_reads_maximum) 
+      {
+
+      keep_trying = false;
+      
+      Serial.println("GPS navigation data not yet available. Try again later.");
+      LCD_message("GPS navigation  ", "data unavailable");
+        
+      return -1;
+        
+      }
+
+    // get the last complete sentence read from GP; this automatically clears a newline flag inside 
+    // the Adafruit library code.
+    GPS_sentence = GPS.lastNMEA();
+    
+    // convert GPS data sentence from a character array to a string.
+    GPS_sentence_string = String(GPS_sentence);
+  
+    // now do a cursory check that the sentence we've just read is OK. Check that there is only
+    // one $, as the first character in the sentence, and that there's an asterisk (which commes 
+    // immediately before the checksum).
+     
+    // sentence starts with a $? 
+    bool data_OK = GPS_sentence_string.charAt(0) == '$';    
+  
+    // sentence contains no other $? The indexOf call will return -1 if $ is not found.
+    data_OK = data_OK && (GPS_sentence_string.indexOf('$', 2) <  0);
+    
+    // now find that asterisk...
+    data_OK = data_OK && (GPS_sentence_string.indexOf('*', 0) >  0);
+  
+    if (GPSECHO1) 
+      {
+      Serial.println("\n******************\njust received a complete sentence, so parse stuff. Sentence is");
+      Serial.println(GPS_sentence_string);
+      }
+  
+    // now parse the GPS sentence. I am only interested in sentences that begin with
+    // $GPGGA ("GPS fix data") or $GPRMC ("recommended minimum specific GPS/Transit data").
+  
+    if(GPSECHO1)
+      {
+      Serial.print("length of GPS_sentence_string just received...");
+      Serial.println(GPS_sentence_string.length());
+      }
+  
+    // now get substring holding the GPS command. Only proceed if it is $GPRMC or $GPGGA.
+    GPS_command = GPS_sentence_string.substring(0, 6);
+  
+    // also trim it to make sure we don't have hidden stuff or white space sneaking in.
+    GPS_command.trim();
+  
+    if(GPSECHO1) 
+      {
+      Serial.print("GPS command is "); Serial.println(GPS_command);
+      }   
+  
+    // if data_OK is true then we have a good sentence. but we also need the sentence
+    // to hold navigational data we can use, otherwise we'll want to keep listening.
+    // we can only work with GPRMC and GPGGA sentences. 
+  
+    bool command_OK = GPS_command.equals("$GPRMC") || GPS_command.equals("$GPGGA"); 
+    
+    // if we have a sentence that, upon cursory inspection, is well formatted AND might
+    // hold navigational data, continue to parse the sentence. If the GPS device
+    // hasn't found any satellites yet, we'll want to go back to the top of the loop
+    // to keep trying, rather than declaring defeat and returning.
+  
+    //////////////////////////////////////////////////////////////////////
+    /////////////////////////// GPRMC sentence ///////////////////////////
+    //////////////////////////////////////////////////////////////////////
+    
+     if (data_OK && GPS_command.equals("$GPRMC"))
+        {
+            
+        if(GPSECHO2) 
+          {
+          Serial.print("\nnew GPS sentence: "); Serial.println(GPS_sentence_string);
+          }
+    
+        // parse the time. these are global variables, already declared.
+
+        GPS_hour_string = GPS_sentence_string.substring(GPRMC_hour_index1, GPRMC_hour_index2);
+        GPS_minutes_string = GPS_sentence_string.substring(GPRMC_minutes_index1, GPRMC_minutes_index2);
+        GPS_seconds_string = GPS_sentence_string.substring(GPRMC_seconds_index1, GPRMC_seconds_index2);
+        GPS_milliseconds_string = GPS_sentence_string.substring(GPRMC_milliseconds_index1, 
+          GPRMC_milliseconds_index2);
+        GPS_AV_code_string = GPS_sentence_string.substring(GPRMC_AV_code_index1, GPRMC_AV_code_index2);
+    
+        GPS_hour = GPS_hour_string.toInt();
+        GPS_minutes = GPS_minutes_string.toInt();
+        GPS_seconds = GPS_seconds_string.toInt();
+        GPS_milliseconds = GPS_milliseconds_string.toInt();
+    
+        if(GPSECHO2)
+          {
+          Serial.print("Time (UTC) = "); Serial.print(GPS_hour); Serial.print(":");
+          Serial.print(GPS_minutes); Serial.print(":");
+          Serial.print(GPS_seconds); Serial.print(".");
+          Serial.println(GPS_milliseconds);
+          Serial.print("A/V code is "); Serial.println(GPS_AV_code_string);
+          }
+    
+        // now see if the data are valid: we'll expect an "A" as the AV code string.
+        // We also expect an asterisk two characters from the end. Also check that the sentence 
+        // is at least as long as the minimum length expected.
+    
+        data_OK = GPS_AV_code_string == "A";
+    
+        // now look for the asterisk after trimming any trailing whitespace in the GPS sentence.
+        // the asterisk preceeds the sentence's checksum information, which I won't bother to check.
+        int asterisk_should_be_here = GPS_sentence_string.length() - 4; 
+    
+        data_OK = data_OK && (GPS_sentence_string.charAt(asterisk_should_be_here) == '*');
+
+        if(GPSECHO2)
+          {
+          Serial.print("expected asterisk position "); Serial.print(asterisk_should_be_here); 
+          Serial.print(" at that position: "); Serial.println(GPS_sentence_string.charAt(asterisk_should_be_here));
+          }
+    
+        // now check that the sentence is not too short.      
+        data_OK = data_OK && (GPS_sentence_string.length() >= GPSMINLENGTH);
+    
+        if (!data_OK) 
+          {
+
+          keep_trying = true;
+           
+          if (GPSECHO1)
+            {
+            Serial.print("GPS sentence not good for navigation: "); Serial.println(GPS_sentence_string);
+            Serial.println("I will keep trying...");
+            }
+            
+          lcd.setCursor(0, 0);
+          lcd.print("GPS navigation  ");
+          lcd.setCursor(0, 1);
+          lcd.print("data not present");
+          
+          }
+    
+        // if data are not good, go back to the top of the loop by breaking out of this if block.
+        // we've already set keep_trying to be true.
+        
+        if (!data_OK) break;
+            
+        // so far so good, so keep going...
+        
+        // now parse latitude 
+        
+        GPS_latitude_1_string = GPS_sentence_string.substring(GPRMC_latitude_1_index1, 
+          GPRMC_latitude_1_index2);
+        GPS_latitude_2_string = GPS_sentence_string.substring(GPRMC_latitude_2_index1, 
+          GPRMC_latitude_2_index2);
+        GPS_latitude_NS_string = GPS_sentence_string.substring(GPRMC_latitude_NS_index1, 
+          GPRMC_latitude_NS_index2);
+    
+        GPS_latitude_1 = GPS_latitude_1_string.toInt();      
+        GPS_latitude_2 = GPS_latitude_2_string.toInt();      
+    
+        if(GPSECHO2)
+          {
+          Serial.print("Latitude x 100 = "); Serial.print(GPS_latitude_1); Serial.print(".");
+          Serial.print(GPS_latitude_2); Serial.println(GPS_latitude_NS_string);
+          }
+          
+        // now parse longitude 
+        
+        GPS_longitude_1_string = GPS_sentence_string.substring(GPRMC_longitude_1_index1, 
+          GPRMC_longitude_1_index2);
+        GPS_longitude_2_string = GPS_sentence_string.substring(GPRMC_longitude_2_index1, 
+          GPRMC_longitude_2_index2);
+        GPS_longitude_EW_string = GPS_sentence_string.substring(GPRMC_longitude_EW_index1, 
+          GPRMC_longitude_EW_index2);
+    
+        GPS_longitude_1 = GPS_longitude_1_string.toInt();      
+        GPS_longitude_2 = GPS_longitude_2_string.toInt();      
+          
+        if(GPSECHO2)
+          {
+          Serial.print("Longitude x 100 = "); Serial.print(GPS_longitude_1); Serial.print(".");
+          Serial.print(GPS_longitude_2); Serial.println(GPS_longitude_EW_string); 
+          }
+    
+        // now parse speed and direction. we'll need to locate the 7th and 8th commas in the
+        // data sentence to do this. so use the indexOf function to find them.
+        // it returns -1 if string wasn't found. the number of digits is not uniquely defined 
+        // so we need to find the fields based on the commas separating them from others.
+        
+        int comma_A_index = GPRMC_longitude_EW_index2;
+        int comma_B_index = GPS_sentence_string.indexOf(",", comma_A_index + 1);
+        int comma_C_index = GPS_sentence_string.indexOf(",", comma_B_index + 1);
+    
+        GPS_speed_knots_string = GPS_sentence_string.substring(comma_A_index + 1, comma_B_index); 
+        GPS_direction_string = GPS_sentence_string.substring(comma_B_index + 1, comma_C_index); 
+        
+        GPS_speed_knots = GPS_speed_knots_string.toFloat();
+        GPS_direction = GPS_direction_string.toFloat();
+    
+        if(GPSECHO2)
+          {
+          Serial.print("Speed (knots) = "); Serial.println(GPS_speed_knots);
+          Serial.print("Direction (degrees) = "); Serial.println(GPS_direction);
+          }
+          
+        // now get the (UTC) date, in format DDMMYY, e.g. 080618 for 8 June 2018.
+        GPS_date_string = GPS_sentence_string.substring(comma_C_index+ + 1, comma_C_index + 7);
+        
+        if(GPSECHO2)
+          {
+          Serial.print("date, in format ddmmyy = "); Serial.println(GPS_date_string);    
+          }
+    
+        // Write message to LCD now. It will look like this (no satellite data in this record):
+        //     Sats: 4006.9539N
+        //     N/A  08815.4431W
+        
+        lcd.setCursor(0, 0);
+        lcd.print("Sats: ");
+        lcd.setCursor(6, 0);
+        lcd.print(GPS_latitude_1_string); lcd.print("."); lcd.print(GPS_latitude_2_string); 
+        lcd.print(GPS_latitude_NS_string); 
+    
+        lcd.setCursor(0, 1);
+        lcd.print("N/A ");
+        lcd.setCursor(5, 1);
+        lcd.print(GPS_longitude_1_string); lcd.print("."); lcd.print(GPS_longitude_2_string); 
+        lcd.print(GPS_longitude_EW_string);
+
+        // print a summary of the data and parsed results:
+        if(GPSECHO3)
+          {
+          Serial.print("GPS sentence: "); Serial.println(GPS_sentence_string);
+
+          Serial.print("Time (UTC) = "); Serial.print(GPS_hour); Serial.print(":");
+          Serial.print(GPS_minutes); Serial.print(":");
+          Serial.print(GPS_seconds); Serial.print(".");
+          Serial.println(GPS_milliseconds);
+        
+          Serial.print("Latitude x 100 = "); Serial.print(GPS_latitude_1); Serial.print(".");
+          Serial.print(GPS_latitude_2); Serial.print(" "); Serial.print(GPS_latitude_NS_string);
+
+          Serial.print("    Longitude x 100 = "); Serial.print(GPS_longitude_1); Serial.print(".");
+          Serial.print(GPS_longitude_2); Serial.print(" "); Serial.println(GPS_longitude_EW_string); 
+
+          Serial.print("Speed (knots) = "); Serial.print(GPS_speed_knots);
+          Serial.print("     Direction (degrees) = "); Serial.println(GPS_direction);
+
+          Serial.println("There is no satellite or altitude information in a GPRMC data sentence.");
+              
+          }
+      
+        // all done with this sentence, so return.
+        return 0;
+          
+        }  // end of "if (data_OK && GPS_command.equals("$GPRMC"))" block
+
+    //////////////////////////////////////////////////////////////////////
+    /////////////////////////// GPGGA sentence ///////////////////////////
+    //////////////////////////////////////////////////////////////////////
+    
+      if (data_OK && GPS_command.equals("$GPGGA"))
+        {
+
+        if(GPSECHO2) 
+          {
+          Serial.print("\nnew GPS sentence: "); Serial.println(GPS_sentence_string);
+          }
+    
+        // parse the time
+    
+        GPS_hour_string = GPS_sentence_string.substring(GPGGA_hour_index1, GPGGA_hour_index2);
+        GPS_minutes_string = GPS_sentence_string.substring(GPGGA_minutes_index1, GPGGA_minutes_index2);
+        GPS_seconds_string = GPS_sentence_string.substring(GPGGA_seconds_index1, GPGGA_seconds_index2);
+        GPS_milliseconds_string = GPS_sentence_string.substring(GPGGA_milliseconds_index1, 
+          GPGGA_milliseconds_index2);
+    
+        GPS_hour = GPS_hour_string.toInt();
+        GPS_minutes = GPS_minutes_string.toInt();
+        GPS_seconds = GPS_seconds_string.toInt();
+        GPS_milliseconds = GPS_milliseconds_string.toInt();
+    
+        if(GPSECHO2)
+          {
+          Serial.print("Time (UTC) = "); Serial.print(GPS_hour); Serial.print(":");
+          Serial.print(GPS_minutes); Serial.print(":");
+          Serial.print(GPS_seconds); Serial.print(".");
+          Serial.println(GPS_milliseconds);
+          }
+    
+        // now get the fix quality and number of satellites.
+    
+        GPS_fix_quality_string = GPS_sentence_string.substring(GPGGA_fix_quality_index1, 
+          GPGGA_fix_quality_index2);
+        GPS_satellites_string = GPS_sentence_string.substring(GPGGA_satellites_index1, 
+          GPGGA_satellites_index2);
+    
+        int GPS_fix_quality = GPS_fix_quality_string.toInt();      
+        int GPS_satellites = GPS_satellites_string.toInt();      
+    
+        if(GPSECHO2)
+          {
+          Serial.print("fix quality (1 for GPS, 2 for DGPS) = "); Serial.println(GPS_fix_quality);
+          Serial.print("number of satellites = "); Serial.println(GPS_satellites);
+          }
+    
+        // now see if the data are valid: we'll expect a fix, and at least three satellites.
+    
+        bool data_OK = (GPS_fix_quality > 0) && (GPS_satellites >= 3); 
+    
+        // now look for the asterisk.
+        int asterisk_should_be_here = GPS_sentence_string.length() - 4; 
+    
+        data_OK = data_OK && (GPS_sentence_string.charAt(asterisk_should_be_here) == '*');
+    
+        // now check that the sentence is not too short.      
+        data_OK = data_OK && (GPS_sentence_string.length() >= GPSMINLENGTH);
+
+        if (!data_OK) 
+          {
+
+          keep_trying = true;
+           
+          if (GPSECHO1)
+            {
+            Serial.print("GPS sentence not good for navigation: "); Serial.println(GPS_sentence_string);
+            Serial.println("I will keep trying...");
+            }
+            
+          lcd.setCursor(0, 0);
+          lcd.print("GPS navigation  ");
+          lcd.setCursor(0, 1);
+          lcd.print("data not present");
+          
+          }
+    
+        // if data are not good, go back to the top of the loop by breaking out of this if block.
+        
+        if (!data_OK) break;
+            
+        // so far so good, so keep going...
+        
+        // now parse latitude 
+        
+        String GPS_latitude_1_string = GPS_sentence_string.substring(GPGGA_latitude_1_index1, 
+        GPGGA_latitude_1_index2);
+        String GPS_latitude_2_string = GPS_sentence_string.substring(GPGGA_latitude_2_index1, 
+        GPGGA_latitude_2_index2);
+        String GPS_latitude_NS_string = GPS_sentence_string.substring(GPGGA_latitude_NS_index1, 
+        GPGGA_latitude_NS_index2);
+    
+        int GPS_latitude_1 = GPS_latitude_1_string.toInt();      
+        int GPS_latitude_2 = GPS_latitude_2_string.toInt();      
+    
+        if(GPSECHO2)
+          {
+          Serial.print("Latitude x 100 = "); Serial.print(GPS_latitude_1); Serial.print(".");
+          Serial.print(GPS_latitude_2); Serial.println(GPS_latitude_NS_string);
+          }
+          
+        // now parse longitude 
+        
+        String GPS_longitude_1_string = GPS_sentence_string.substring(GPGGA_longitude_1_index1, 
+        GPGGA_longitude_1_index2);
+        String GPS_longitude_2_string = GPS_sentence_string.substring(GPGGA_longitude_2_index1, 
+        GPGGA_longitude_2_index2);
+        String GPS_longitude_EW_string = GPS_sentence_string.substring(GPGGA_longitude_EW_index1, 
+        GPGGA_longitude_EW_index2);
+    
+        int GPS_longitude_1 = GPS_longitude_1_string.toInt();      
+        int GPS_longitude_2 = GPS_longitude_2_string.toInt();      
+    
+        if(GPSECHO2)
+          {         
+          Serial.print("Longitude x 100 = "); Serial.print(GPS_longitude_1); Serial.print(".");
+          Serial.print(GPS_longitude_2); Serial.println(GPS_longitude_EW_string); 
+          }
+          
+        // let's skip the "horizontal dilution" figure and go straight for the altitude now.
+        // this begins two fields to the right of the num,ber of satellites so find this
+        // by counting commas. use the indexOf function to find them.
+        int comma_A_index = GPS_sentence_string.indexOf(",", GPGGA_satellites_index2 + 1);
+        int comma_B_index = GPS_sentence_string.indexOf(",", comma_A_index + 1);
+    
+        String GPS_altitude_string = GPS_sentence_string.substring(comma_A_index + 1, comma_B_index); 
+        
+        float GPS_altitude = GPS_altitude_string.toFloat();
+    
+        if(GPSECHO2)
+          {
+          Serial.print("Altitude (meters) = "); Serial.println(GPS_altitude);
+          }
+    
+        // Write message to LCD now. It will look like this:
+        //     Sats: 4006.9539N
+        //       10 08815.4431W
+             
+        lcd.setCursor(0, 0);
+        lcd.print("Sats: ");
+        lcd.setCursor(6, 0);
+        lcd.print(GPS_latitude_1_string); lcd.print("."); lcd.print(GPS_latitude_2_string); 
+        lcd.print(GPS_latitude_NS_string); 
+    
+        lcd.setCursor(0, 1);
+        lcd.print("      ");
+        lcd.setCursor(2, 1);
+        lcd.print(GPS_satellites);
+        lcd.setCursor(5, 1);
+        lcd.print(GPS_longitude_1_string); lcd.print("."); lcd.print(GPS_longitude_2_string); 
+        lcd.print(GPS_longitude_EW_string);
+
+        // print a summary of the data and parsed results:
+        if(GPSECHO3)
+          {
+          Serial.print("GPS sentence: "); Serial.println(GPS_sentence_string);
+
+          Serial.print("Time (UTC) = "); Serial.print(GPS_hour); Serial.print(":");
+          Serial.print(GPS_minutes); Serial.print(":");
+          Serial.print(GPS_seconds); Serial.print(".");
+          Serial.println(GPS_milliseconds);
+        
+          Serial.print("Latitude x 100 = "); Serial.print(GPS_latitude_1); Serial.print(".");
+          Serial.print(GPS_latitude_2); Serial.print(" "); Serial.print(GPS_latitude_NS_string);
+
+          Serial.print("    Longitude x 100 = "); Serial.print(GPS_longitude_1); Serial.print(".");
+          Serial.print(GPS_longitude_2); Serial.print(" "); Serial.println(GPS_longitude_EW_string); 
+
+          Serial.print("Speed (knots) = "); Serial.print(GPS_speed_knots);
+          Serial.print("     Direction (degrees) = "); Serial.println(GPS_direction);
+
+          Serial.print("Number of satellites: "); Serial.print(GPS_satellites);
+          Serial.print("       Altitude (meters): "); Serial.println(GPS_altitude);
+              
+          }
+       
+        // all done with this sentence, so return.
+        return 0;
+       
+      }   // end of "if (data_OK && GPS_command.equals("$GPGGA"))" block
+  
+    // we'll fall through to here (instead of returning) when we've read a complete 
+    // sentence, but it doesn't have navigational information (for example, an antenna 
+    // status record).
+    
+    } 
+
+  }
diff --git a/Homework 3/Question 1 Proof/gps_+_rtc_proof.png b/Homework 3/Question 1 Proof/gps_+_rtc_proof.png
new file mode 100644
index 0000000000000000000000000000000000000000..7ae76bc8667e9d409d2ffc8847001293829383da
Binary files /dev/null and b/Homework 3/Question 1 Proof/gps_+_rtc_proof.png differ
diff --git a/Homework 3/Question 1 Proof/pic+sd+bme_proof.png b/Homework 3/Question 1 Proof/pic+sd+bme_proof.png
new file mode 100644
index 0000000000000000000000000000000000000000..faa3ef2d53f694d9ba9c67cc6b28d60650d0e54c
Binary files /dev/null and b/Homework 3/Question 1 Proof/pic+sd+bme_proof.png differ
diff --git a/Homework 3/Question 2/.gitkeep b/Homework 3/Question 2/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/Homework 3/Question 2/IMAGE00.JPG b/Homework 3/Question 2/IMAGE00.JPG
new file mode 100644
index 0000000000000000000000000000000000000000..3bed0c3478f2f9d1a7d23c5f0d117acb6cbc1090
Binary files /dev/null and b/Homework 3/Question 2/IMAGE00.JPG differ
diff --git a/Homework 3/Question 2/data.csv b/Homework 3/Question 2/data.csv
new file mode 100644
index 0000000000000000000000000000000000000000..3e58ee294e4c819663d27b9508c00fdbbc604dda
--- /dev/null
+++ b/Homework 3/Question 2/data.csv	
@@ -0,0 +1,7 @@
+12:06:03,Feb  9 2023,IMAGE00.JPG,1387,25.98,,,,,,,,,,
+12:06:03,Feb  9 2023,IMAGE01.JPG,1809,25.53,,,,,,,,,Mean,Standard Deviation
+12:06:03,Feb  9 2023,IMAGE02.JPG,1809,25.13,,,,,,,,,24.92428571,0.612275782
+12:06:03,Feb  9 2023,IMAGE03.JPG,1809,24.8,,,,,,,,,,
+12:06:03,Feb  9 2023,IMAGE04.JPG,2041,24.54,,,,,,,,,,
+12:06:03,Feb  9 2023,IMAGE05.JPG,2960,24.33,,,,,,,,,,
+12:06:03,Feb  9 2023,IMAGE06.JPG,3066,24.16,,,,,,,,,,
diff --git a/Homework 3/Question 2/tempvstime.png b/Homework 3/Question 2/tempvstime.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce4d2ba0565f9c893a9349671d7639fbddfdaed5
Binary files /dev/null and b/Homework 3/Question 2/tempvstime.png differ