v1.0 Initial release

v1.0 Initial release

error: pathspec 'GPSLCD.ino' did not match any file(s) known to git

--- GPSLCD.ino
+++ GPSLCD.ino
@@ -0,0 +1,628 @@
+/* GPS LCD
+
+    By GK Grotsky
+    8/30/16
+
+  This program communicate with the u-blox NEO-6M GPS module
+  through a software serial interface. It then displays certain GPS
+  parameters on a I2C 16x2 (or 20x4) character LCD display module. The
+  GPS messages are received by the on-board Arduino UART circuit using
+  the SoftwareSerial library. It then uses the TinyGPS++ library to
+  decode the GPS NMEA messages. The parameters are then displayed on a
+  16x4 (or 20x4) LCD using the LiquidCrystal_I2C library.
+
+  Note: Both the 16x2 and 20x4 LCDs are supported as these are the most popular
+        LCDs available.
+*/
+#include "GPSLCD.h"
+#include <TinyGPS++.h>
+#include <SoftwareSerial.h>
+#include <LiquidCrystal_I2C.h>
+
+TinyGPSPlus gps; // This is the GPS object that will pretty much do all the grunt work with the NMEA data
+SoftwareSerial GPSModule(10, 11); // RX, TX
+LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin); // Initializes class variables and defines the I2C address of the LCD
+bool dataValid; // Data is valid from the GPS module
+GPSStruct GPSData; // Holds the GPS data coming from the GPS module
+
+// The setup (runs once at start up)
+void setup()
+{
+  pinMode(BACKLIGHT_SW, INPUT);
+
+#ifdef _16x2
+  // Selects either speed or heading to be displayed
+  pinMode(SPEED_ALTITUDE_SW, INPUT);
+#else
+  // Selects either altitude or the date/time to be displayed
+  pinMode(ALTITUDE_DATE_TIME_SW, INPUT);
+#endif
+
+  GPSModule.begin(9600); // This opens up communications to the software serial tx and rx lines
+  GPSModule.flush();
+
+  lcd.begin (COLUMN, ROW); // Defines LCD type
+  lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE); // Sets the pin to control the backlight
+  lcd.clear(); // Clear the LCD
+  lcd.home (); // Go to the home position on the LCD
+} // setup
+
+// The loop (runs forever and a day :-))
+void loop()
+{
+  static uint32_t pastSatellites = 0;
+  static uint8_t initializingCounter = 0;
+  static unsigned long prevInitializationTime = INITIALIZATION_INTERVAL;
+  static unsigned long prevCreditTime = TOGGLETIME_INTERVAL;
+  static unsigned long prevInvalidSatellitesTime = TOGGLETIME_INTERVAL;
+  static bool leftInitialization = false;
+  static bool creditToggle = true;
+  static bool invalidSatellitesToggle = true;
+#ifndef _16x2
+  static unsigned long prevDateTime = TOGGLETIME_INTERVAL;
+  static unsigned long prevHeadingTime = TOGGLETIME_INTERVAL;
+  static unsigned long prevHdopTime = TOGGLETIME_INTERVAL;
+  static bool dateTimeToggle = true;
+  static bool headingToggle = true;
+  static bool hdopToggle = true;
+#endif
+#ifdef DATA_VALID_OVERRIDE
+  const bool dataValidOverride = true; // Set true to override data valid for debugging
+#else
+  const bool dataValidOverride = false; // Set false not to override data valid
+#endif
+#ifdef BACKLIGHT_OVERRIDE
+  // Override LCD backlight switch
+  // Force LCD backlight on/off
+  lcd.setBacklight(BACKLIGHT_ONOFF);
+#else
+  // Turn LCD backlight on/off
+  lcd.setBacklight(digitalRead(BACKLIGHT_SW));
+#endif
+  unsigned long now = millis();
+
+  while (GPSModule.available()) // While there are characters to come from the GPS
+  {
+    bool b = gps.encode(GPSModule.read()); // This feeds the serial NMEA data into the GPS library one char at a time
+  }
+
+  // Get the GPS data valid flags
+  dataValid =
+    gps.location.isValid()   &&
+    gps.speed.isValid()      &&
+    gps.altitude.isValid()   &&
+    gps.course.isValid()     &&
+    gps.date.isValid()       &&
+    gps.time.isValid()       &&
+    gps.satellites.isValid() &&
+    gps.hdop.isValid();
+
+  // Check if the GPS data is valid or data valid override is set (for debugging)
+  if (dataValid || dataValidOverride) {
+#ifndef DATA_VALID_OVERRIDE
+    // Store the real GPS data
+    GPSData.satellites = gps.satellites.value();
+    GPSData.lat        = gps.location.lat();
+    GPSData.lon        = gps.location.lng();
+    GPSData.speed      = gps.speed.mph();
+    GPSData.altitude   = gps.altitude.feet();
+#ifndef _16x2
+    GPSData.heading    = gps.course.deg();
+    GPSData.hdop       = gps.hdop.value();
+    GPSData.year       = gps.date.year();
+    GPSData.month      = gps.date.month();
+    GPSData.day        = gps.date.day();
+    GPSData.hour       = gps.time.hour();
+    GPSData.minute     = gps.time.minute();
+    GPSData.second     = gps.time.second();
+#endif // #ifndef _16x2
+#else // #ifndef DATA_VALID_OVERRIDE
+    // Store the fake GPS data (for debugging)
+    GPSData.satellites = 0; // Invalid satellites
+    GPSData.lat        = 39.16d; // East coast
+    GPSData.lon        = -77.07d; //   "
+    GPSData.speed      = 55.0d;
+    GPSData.altitude   = 555.0d;
+#ifndef _16x2
+    GPSData.heading    = 60.0d; // ENE or NE (16 cardinal points or 8 cardinal points)
+    GPSData.hdop       = 150;
+    GPSData.year       = 2016;
+    GPSData.month      = 11; // Day before ST starts
+    GPSData.day        = 5;  //      "
+    GPSData.hour       = 23; // 7pm my local time
+    GPSData.minute     = 10;
+    GPSData.second     = 25;
+#endif // #ifndef _16x2
+#endif // #ifndef DATA_VALID_OVERRIDE
+    // Clear the screen once when leaving initialization
+    if (!leftInitialization) {
+      leftInitialization = true;
+      lcd.clear(); // Clear the LCD
+    }
+    // Display the latest info from the gps object which it derived from the data sent by the GPS unit
+    // Send data to the LCD
+#ifdef _16x2 //------------------------------------------------------
+    lcd.home (); // Go to 1st line
+    lcd.print("Lat: ");
+    lcd.print(GPSData.lat);
+    lcd.setCursor (11, 0);
+    lcd.print("SV:");
+    if ((pastSatellites != GPSData.satellites) || (GPSData.satellites == 0)) {
+      pastSatellites = GPSData.satellites;
+      if (GPSData.satellites == 0) {
+        // Toggle invalid satellites indicator every TOGGLETIME_INTERVAL seconds
+        if (now - prevInvalidSatellitesTime > TOGGLETIME_INTERVAL / 4) {
+          prevInvalidSatellitesTime = now;
+          if (invalidSatellitesToggle) {
+            invalidSatellitesToggle = false;
+            lcd.print("XX");
+          }
+          else {
+            invalidSatellitesToggle = true;
+            lcd.print("  ");
+          } // if (invalidSatellitesToggle)
+        } // if (now - prevInvalidSatellitesTime > TOGGLETIME_INTERVAL)
+      } // if (GPSData.satellites == 0)
+      else if (GPSData.satellites <= 9) {
+        lcd.print(" "); // Blank leading char
+        lcd.print(GPSData.satellites);
+      }
+      else {
+        lcd.print(GPSData.satellites);
+      }
+    } // if ((pastSatellites != GPSData.satellites) || (GPSData.satellites == 0))
+    lcd.setCursor (0, 1); // Go to 2nd line
+    lcd.print("Lon: ");
+    lcd.print(GPSData.lon);
+    if ((digitalRead(SPEED_ALTITUDE_SW))) {
+      lcd.setCursor (12, 1);
+      if (GPSData.speed < SPEED_CUTOUT) {
+        lcd.print("0  ");
+      }
+      else {
+        lcd.print((int16_t)GPSData.speed);
+        lcd.print(" "); // Clear the extra char
+      }
+    }
+    else {
+      lcd.print("     "); // Clear the extra chars
+      if (GPSData.altitude <= 99.9) {
+        lcd.setCursor (14, 1);
+      }
+      else {
+        lcd.setCursor (13, 1);
+      }
+      lcd.print((int16_t)GPSData.altitude); // Altitude
+      // Toggle credit every TOGGLETIME_INTERVAL seconds
+      if (now - prevCreditTime > (TOGGLETIME_INTERVAL / 2)) {
+        prevCreditTime = now;
+        if (creditToggle) { // Display credit
+          creditToggle = false;
+          lcd.print("     "); // Clear the extra chars
+          lcd.print(CREDIT); // Yours truly :-)
+        }
+        else {
+          creditToggle = true;
+          lcd.print("        "); // Clear the extra chars
+        }
+      } // if (now - prevCreditTime > TOGGLETIME_INTERVAL)
+    } // if ((digitalRead(SPEED_ALTITUDE_SW)))
+#else // 20x4 ----------------------------------------------------
+    lcd.home (); // Go to 1st line
+    lcd.print("Lat: ");
+    lcd.print(GPSData.lat);
+    lcd.setCursor (15, 0);
+    lcd.print("SV:");
+    if ((pastSatellites != GPSData.satellites) || (GPSData.satellites == 0)) {
+      pastSatellites = GPSData.satellites;
+      if (GPSData.satellites == 0) {
+        // Toggle invalid satellites indicator every TOGGLETIME_INTERVAL seconds
+        if (now - prevInvalidSatellitesTime > TOGGLETIME_INTERVAL / 3) {
+          prevInvalidSatellitesTime = now;
+          if (invalidSatellitesToggle) {
+            invalidSatellitesToggle = false;
+            lcd.print("XX");
+          }
+          else {
+            invalidSatellitesToggle = true;
+            lcd.print("  ");
+          } // if (invalidSatellitesToggle)
+        } // if (now - prevInvalidSatellitesTime > TOGGLETIME_INTERVAL)
+      } // if (GPSData.satellites == 0)
+      else if (GPSData.satellites <= 9) {
+        lcd.print(" "); // Blank leading char
+        lcd.print(GPSData.satellites);
+      }
+      else {
+        lcd.print(GPSData.satellites);
+      }
+    } // if ((pastSatellites != GPSData.satellites) || (GPSData.satellites == 0))
+    lcd.setCursor (0, 1); // Go to 2nd line
+    lcd.print("Lon: ");
+    lcd.print(GPSData.lon);
+#ifndef CONVERT_TO_LOCAL
+    // Only display if time/date is selected
+    if (!(digitalRead(ALTITUDE_DATE_TIME_SW))) {
+      lcd.print("      "); // Clear the extra chars
+      uint8_t DOW = dayOfWeek(GPSData.year, GPSData.month, GPSData.day);
+      if (IsDST(GPSData.day, GPSData.month, DOW)) {
+        lcd.print("DST");
+      }
+      else {
+        lcd.print(" ST");
+      }
+    }
+    else {
+      lcd.print("         "); // Clear the extra chars
+    }
+#else // #ifndef CONVERT_TO_LOCAL
+    // Display Horizontal Dilution of Precision (Hdop) with the format X.X
+    // It comes in from the GPS module as XXX
+    // If you care how Hdop is computed (I don't :-(), see the following:
+    // http://www2.unb.ca/gge/Resources/gpsworld.may99.pdf
+    uint32_t hdopInteger = GPSData.hdop / 100;
+    uint32_t hdopFarction = (GPSData.hdop - (hdopInteger * 100)) / 10;
+    lcd.print(" Hdop:");
+    if (hdopInteger < 10) {
+      lcd.print(hdopInteger); // Integer part
+      lcd.print(".");
+      lcd.print(hdopFarction); // Fraction part
+    }
+    else {
+      // Hdop value too large for my LCD, so cross it out
+      // Toggle Hdop indicator every TOGGLETIME_INTERVAL seconds
+      if (now - prevHdopTime > TOGGLETIME_INTERVAL / 3) {
+        prevHdopTime = now;
+        if (hdopToggle) {
+          hdopToggle = false;
+          lcd.print("XXX");
+        }
+        else {
+          hdopToggle = true;
+          lcd.print("   ");
+        } // if (hdopToggle)
+      } // if (now - prevHdopTime > TOGGLETIME_INTERVAL)
+    } // if (hdopInteger < 10)
+#endif // #ifndef CONVERT_TO_LOCAL
+    lcd.setCursor (0, 2); // Go to 3rd line
+    lcd.print("Spd: ");
+    if (GPSData.speed < SPEED_CUTOUT) {
+      lcd.print("0  ");
+    }
+    else {
+      lcd.print((int16_t)GPSData.speed);
+      lcd.print(" "); // Clear the extra chars
+    }
+    lcd.setCursor (12, 2);
+    lcd.print("Hdg: ");
+    if (GPSData.speed < SPEED_CUTOUT) {
+      lcd.print("0  ");
+    }
+    else {
+      // Toggle heading every TOGGLETIME_INTERVAL seconds
+      if (now - prevHeadingTime > TOGGLETIME_INTERVAL) {
+        prevHeadingTime = now;
+        if (headingToggle) { // Display cardinal heading
+          headingToggle = false;
+          lcd.print(cardinal(GPSData.heading));
+        }
+        else { // Display degrees heading
+          headingToggle = true;
+          lcd.print((int16_t)GPSData.heading);
+          if (GPSData.heading <= 99.9) lcd.print(" "); // Clear the extra char
+        } // if (headingToggle)
+      } // if (now - prevHeadingTime > TOGGLETIME_INTERVAL)
+    } // if (GPSData.speed < SPEED_CUTOUT)
+    lcd.setCursor (0, 3); // Go to 4th line
+    if ((digitalRead(ALTITUDE_DATE_TIME_SW))) {
+      lcd.print("Alt: ");
+      lcd.print((int16_t)GPSData.altitude);
+      // Toggle credit every TOGGLETIME_INTERVAL seconds
+      if (now - prevCreditTime > (TOGGLETIME_INTERVAL / 2)) {
+        prevCreditTime = now;
+        if (creditToggle) { // Display credit
+          creditToggle = false;
+          lcd.print("         "); // Clear the extra chars
+          lcd.print(CREDIT); // Yours truly :-)
+        }
+        else {
+          creditToggle = true;
+          lcd.print("            "); // Clear the extra chars
+        }
+      } // if (now - prevCreditTime > TOGGLETIME_INTERVAL)
+      prevDateTime = TOGGLETIME_INTERVAL;
+      dateTimeToggle = true; // Default first to display date
+    } // if ((digitalRead(ALTITUDE_DATE_TIME_SW)))
+    else {
+      // Toggle date/time every TOGGLETIME_INTERVAL seconds
+      if (now - prevDateTime > TOGGLETIME_INTERVAL) {
+        prevDateTime = now;
+        if (dateTimeToggle) {
+          // Display date
+          dateTimeToggle = false;
+          lcd.print("Date: ");
+          uint8_t hour = GPSData.hour;
+          uint8_t day  = GPSData.day;
+          uint8_t month = GPSData.month;
+          uint16_t year = GPSData.year;
+#ifdef CONVERT_TO_LOCAL
+          // Convert UTC date to local date
+          bool DST = convertToLocal (&hour, &year, &month,
+                                     &day, GPSData.lon, true); // true means date conversion
+#endif // #ifdef CONVERT_TO_LOCAL
+          if (month < 10) lcd.print("0");
+          lcd.print(month);
+          lcd.print("/");
+          if (day < 10) lcd.print("0");
+          lcd.print(day);
+          lcd.print("/");
+          lcd.print(year);
+          printDay (dayOfWeek (year, month, day));
+        } // if (dateTimeToggle)
+        else {
+          // Display time
+          dateTimeToggle = true;
+          lcd.print("Time: ");
+          uint8_t hour = GPSData.hour;
+          uint8_t day  = GPSData.day;
+          uint8_t month = GPSData.month;
+          uint16_t year = GPSData.year;
+#ifdef CONVERT_TO_LOCAL
+          // Convert UTC time to local time (no need to convert the date)
+          bool DST = convertToLocal (&hour, &year, &month,
+                                     &day, GPSData.lon, false); // false means no date conversion
+#else // #ifdef CONVERT_TO_LOCAL
+#ifdef DISPLAY_12_HOUR
+          if (hour == 0) { // 12 hour clocks don't display 0
+            hour = 12;
+          }
+#endif // #ifdef DISPLAY_12_HOUR
+#endif // #ifdef CONVERT_TO_LOCAL
+#ifdef DISPLAY_12_HOUR
+          char AMPM[] = "am";
+          if (hour >= 12) { // Convert to 12 hour format
+            if (hour > 12) hour -= 12;
+            strcpy (AMPM, "pm");
+          }
+#endif
+          if (hour < 10) lcd.print("0");
+          lcd.print(hour);
+          lcd.print(":");
+          if (GPSData.minute < 10) lcd.print("0");
+          lcd.print(GPSData.minute);
+          lcd.print(":");
+          if (GPSData.second < 10) lcd.print("0");
+          lcd.print(GPSData.second);
+#ifdef DISPLAY_12_HOUR
+          lcd.print(AMPM);
+#endif // #ifdef DISPLAY_12_HOUR
+#ifdef CONVERT_TO_LOCAL
+#ifdef DISPLAY_12_HOUR
+          (DST) ? lcd.print(" DST") : lcd.print("  ST");
+#else // #ifdef DISPLAY_12_HOUR
+          (DST) ? lcd.print("   DST") : lcd.print("    ST");
+#endif // #ifdef DISPLAY_12_HOUR
+#endif // #ifndef CONVERT_TO_LOCAL
+#ifndef CONVERT_TO_LOCAL
+#ifdef DISPLAY_12_HOUR
+          lcd.print(" UTC");
+#else // #ifdef DISPLAY_12_HOUR
+          lcd.print("   UTC");
+#endif // #ifdef DISPLAY_12_HOUR
+#endif // #ifndef CONVERT_TO_LOCAL
+        } // if (dateTimeToggle)
+      } // if (now - prevDateTime > TOGGLETIME_INTERVAL)
+    } // if ((digitalRead(ALTITUDE_DATE_TIME_SW)))
+#endif //------------------------------------------------------------
+  } // if (dataValid)
+  else {
+    // GPS data is not valid, so it must be initializing
+#ifdef _16x2 //------------------------------------------------------
+    // Display initialization screen once every INITIALIZATION_INTERVAL
+    if (now - prevInitializationTime > INITIALIZATION_INTERVAL) {
+      prevInitializationTime = now;
+      lcd.setCursor (6, 0); // Go to 1st line
+      lcd.print("GPS");
+      lcd.setCursor (11, 0);
+      lcd.print("v");
+      lcd.print(VERSION);
+      lcd.setCursor (2, 1); // Go to 2nd line
+      lcd.print("Initializing");
+      lcd.setCursor (15, 1);
+      if (++initializingCounter > 9) initializingCounter = 1; // Limit 1 - 9
+      lcd.print(initializingCounter);
+      leftInitialization = false;
+    }
+#else // 20x4 -------------------------------------------------------
+    // Display initialization screen once every INITIALIZATION_INTERVAL
+    if (now - prevInitializationTime > INITIALIZATION_INTERVAL) {
+      prevInitializationTime = now;
+      lcd.setCursor (8, 0); // Go to 1st line
+      lcd.print("GPS");
+      lcd.setCursor (14, 0);
+      lcd.print("v");
+      lcd.print(VERSION);
+      lcd.setCursor (4, 1); // Go to 2nd line
+      lcd.print("Initializing");
+      lcd.setCursor (6, 2); // Go to 3rd line
+      lcd.print("Data Not");
+      lcd.setCursor (7, 3); // Go to 4th line
+      lcd.print("Valid");
+      lcd.setCursor (19, 3);
+      if (++initializingCounter > 9) initializingCounter = 1; // Limit 1 - 9
+      lcd.print(initializingCounter);
+      leftInitialization = false;
+    }
+#endif //------------------------------------------------------------
+  } // GPS data is not valid
+} // loop
+
+#ifndef _16x2
+/* Helper functions start here
+
+  Ripped off from Electrical Engineering Stack Exchange
+  http://electronics.stackexchange.com/questions/66285/how-to-calculate-day-of-the-week-for-rtc
+  ------------------------------------------------------------
+   Returns the number of days to the start of the specified year, taking leap
+   years into account, but not the shift from the Julian calendar to the
+   Gregorian calendar. Instead, it is as though the Gregorian calendar is
+   extrapolated back in time to a hypothetical "year zero".
+*/
+uint16_t leap (uint16_t year)
+{
+  return year * 365 + (year / 4) - (year / 100) + (year / 400);
+}
+/* Returns a number representing the number of days since March 1 in the
+   hypothetical year 0, not counting the change from the Julian calendar
+   to the Gregorian calendar that occurred in the 16th century. This
+   algorithm is loosely based on a function known as "Zeller's Congruence".
+   This number MOD 7 gives the day of week, where 0 = Monday and 6 = Sunday.
+*/
+uint16_t zeller (uint16_t year, uint8_t month, uint8_t day)
+{
+  year += ((month + 9) / 12) - 1;
+  month = (month + 9) % 12;
+  return leap (year) + month * 30 + ((6 * month + 5) / 10) + day + 1;
+}
+
+// Returns the day of week for a given date.
+uint8_t dayOfWeek (uint16_t year, uint8_t month, uint8_t day)
+{
+  return (zeller (year, month, day) % 7) + 1;
+}
+//----------------------------------------------------------
+
+// Print the day of the week on the LCD
+void printDay(uint8_t day)
+{
+  if (day == 7) day = 0;
+  switch (day)
+  {
+    case 0:  lcd.print(" Mon"); break;
+    case 1:  lcd.print(" Tue"); break;
+    case 2:  lcd.print(" Wed"); break;
+    case 3:  lcd.print(" Thu"); break;
+    case 4:  lcd.print(" Fri"); break;
+    case 5:  lcd.print(" Sat"); break;
+    case 6:  lcd.print(" Sun"); break;
+    default: lcd.print(" Err");
+  }
+}
+
+// Compute the cardinal points of the compass
+const char* cardinal(double course)
+{
+#ifdef _16CARDINAL
+  const char* directions[] = {"N  ", "NNE", "NE ", "ENE", "E  ", "ESE", "SE ", "SSE",
+                              "S  ", "SSW", "SW ", "WSW", "W  ", "WNW", "NW ", "NNW"
+                             };
+#else
+  const char* directions[] = {"N  ", "N  ", "NE ", "NE ", "E  ", "E  ", "SE ", "SE ",
+                              "S  ", "S  ", "SW ", "SW ", "W  ", "W  ", "NW ", "NW "
+                             };
+#endif // #ifdef _16CARDINAL
+  uint8_t direction = (uint8_t)((course + 11.25d) / 22.5d);
+  return directions[direction % 16];
+}
+
+/* Ripped off from Stackoverflow
+  http://stackoverflow.com/questions/5590429/calculating-daylight-saving-time-from-only-date
+
+  Check to see if it's Daylight Savings Time (DST)
+*/
+bool IsDST(uint8_t day, uint8_t month , uint8_t DOW)
+{
+  // Make Day of Week (DOW) match with what Stackoverflow suggests
+  // for DOW (Sunday = 0 to Saturday = 6)
+  switch (DOW)
+  {
+    case 6:  DOW = 0; break; // Sun
+    case 7:  DOW = 1; break; // Mon
+    case 1:  DOW = 2; break; // Tue
+    case 2:  DOW = 3; break; // Wed
+    case 3:  DOW = 4; break; // Thu
+    case 4:  DOW = 5; break; // Fri
+    case 5:  DOW = 6; break; // Sat
+    default: break;
+  }
+  // January, February, and December are out
+  if (month < 3 || month > 11) {
+    return false;
+  }
+  // April to October are in
+  if (month > 3 && month < 11) {
+    return true;
+  }
+  int8_t previousSunday = (int8_t)(day - DOW);
+  // In march, we are DST if our previous Sunday was on or after the 8th
+  if (month == 3) {
+    return previousSunday >= 8;
+  }
+  // In November we must be before the first Sunday to be DST
+  // That means the previous Sunday must be before the 1st
+  return previousSunday <= 0;
+}
+
+#ifdef CONVERT_TO_LOCAL
+/* Convert UTC time and date to local time and date
+   Difference between UTC time/date (at Greenwich) and local time/date is 15 minutes
+   per 1 degree of longitude. See the following:
+   http://www.edaboard.com/thread101516.html
+*/
+bool convertToLocal (uint8_t* hour, uint16_t* year, uint8_t* month,
+                     uint8_t* day, const double lon, bool convertDate) {
+
+  uint8_t DaysAMonth [] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+  // Get Day of Week (DOW)
+  uint8_t DOW = dayOfWeek(*year, *month, *day);
+  // Get Daylight Saving Time (DST) or Standard Time (ST)
+  bool DST = IsDST(*day, *month, DOW);
+  // Compute local time (hours)
+  int8_t UTCOffset = (int8_t)(lon / 15.0d); // UTC offset
+  if (UTCOffset < 0) {
+    // West of Greenwich, subtract
+    UTCOffset = abs(UTCOffset); // Make offset positive
+    if (DST) --UTCOffset; // Compensate for DST
+    if (*hour <= UTCOffset) *hour += 24;
+    *hour = *hour - UTCOffset; // Subtract offset
+  }
+  else {
+    // East of Greenwich, add
+    if (DST) ++UTCOffset; // Compensate for DST
+    if (*hour <= UTCOffset) *hour += 24;
+    *hour = *hour + UTCOffset; // Add offset
+  }
+  // Convert date if convertDate flag is set
+  // Portions of the following code (with some modifications) ripped off from Instructables
+  // http://www.instructables.com/id/GPS-time-UTC-to-local-time-conversion-using-Arduin/?ALLSTEPS
+  if (convertDate) {
+    if ((24 - *hour) <= UTCOffset) { // A new UTC day started
+      if (*year % 4 == 0) DaysAMonth[1] = 29; //leap year check (the simple method)
+      if (*hour < 24) {
+        *day -= 1;
+        if (*day < 1) {
+          if (*month == 1) {
+            *month = 12;
+            *year -= 1;
+          } // if (*month == 1)
+          else {
+            *month -= 1;
+          }
+          *day = DaysAMonth[*month - 1];
+        } // if (*day < 1)
+      } // if (*hour < 24)
+      else if (*hour >= 24) {
+        day += 1;
+        if (*day > DaysAMonth[*month - 1]) {
+          *day = 1;
+          *month += 1;
+          if (*month > 12) *year += 1;
+        } // if (*day > DaysAMonth[*month - 1])
+      } // if (*hour >= 24)
+    } // if ((24 - *hour) <= UTCOffset)
+  } // if (convertDate)
+  return (DST);
+}
+#endif // #ifdef CONVERT_TO_LOCAL
+#endif // #ifndef _16x2


Update shield_sdlog.ino

Update shield_sdlog.ino

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/tonesandtones/Adafruit-GPS-Library.git/'


bug in relay status

bug in relay status

--- _02-mqtt-sw-temperature/_02-mqtt-sw-temperature.ino
+++ _02-mqtt-sw-temperature/_02-mqtt-sw-temperature.ino
@@ -34,6 +34,8 @@

 // OTHER
 #define REPORT_INTERVAL 9500 // in msec
+
+#define BETWEEN_RELAY_ACTIVE 5000

 // DS18B20
 #define ONE_WIRE_BUS 12
@@ -176,12 +178,12 @@

   unsigned long now = millis();

-  if ((now - lastRelayActionmillis) >= 30000) {
+  if ((now - lastRelayActionmillis) >= BETWEEN_RELAY_ACTIVE ) {
     if ( receivedpayload == "{\"LIGHT\":1}") {
-      relaystatus = 1 ;
-    }
-    else if ( receivedpayload == "{\"LIGHT\":0}") {
-      relaystatus = 0 ;
+      relaystatus = HIGH ;
+    }
+    if ( receivedpayload == "{\"LIGHT\":0}") {
+      relaystatus = LOW ;
     }
   }

@@ -206,7 +208,7 @@
   delay(20);

   startMills = timemillis = lastRelayActionmillis = millis();
-  lastRelayActionmillis += 30000;
+  lastRelayActionmillis += BETWEEN_RELAY_ACTIVE;

   pinMode(pir, INPUT);
   pinMode(RELAYPIN, OUTPUT);
@@ -292,7 +294,7 @@
       }

       long now = millis();
-      if (now - lastReconnectAttempt > 1000) {
+      if (now - lastReconnectAttempt > 500) {
         lastReconnectAttempt = now;
         if (reconnect()) {
           lastReconnectAttempt = 0;
@@ -305,7 +307,17 @@

   if ( relaystatus != oldrelaystatus ) {

+    if (DEBUG_PRINT) {
+      Serial.print("call changelight  => relaystatus => ");
+      Serial.println(relaystatus);
+    }
+
     changelight();
+
+    if (DEBUG_PRINT) {
+      Serial.print("after changelight  => relaystatus => ");
+      Serial.println(relaystatus);
+    }

     String lightpayload = "{\"LIGHT\":";
     lightpayload += relaystatus;
@@ -316,8 +328,13 @@

   }

-  if ((( millis() - lastRelayActionmillis) > 30000 ) && ( relayIsReady == LOW ) && ( relaystatus == oldrelaystatus ))
+  if ((( millis() - lastRelayActionmillis) > BETWEEN_RELAY_ACTIVE ) && ( relayIsReady == LOW ) && ( relaystatus == oldrelaystatus ))
   {
+
+    if (DEBUG_PRINT) {
+      Serial.print("after BETWEEN_RELAY_ACTIVE => relaystatus => ");
+      Serial.println(relaystatus);
+    }

     String lightpayload = "{\"LIGHT\":";
     lightpayload += relaystatus;
@@ -326,7 +343,7 @@

     sendmqttMsg(rslttopic, lightpayload);
     relayIsReady = HIGH;
-
+
   }

   runTimerDoLightOff();
@@ -376,14 +393,20 @@
   }

   client.loop();
+  yield();

 }

 void runTimerDoLightOff()
 {
-  if (( relaystatus == 1 ) && ( hour() == 6 ) && ( minute() == 00 ) && ( second() < 5 ))
+  if (( relaystatus == HIGH ) && ( hour() == 6 ) && ( minute() == 00 ) && ( second() < 5 ))
   {
-    relaystatus = 0;
+    if (DEBUG_PRINT) {
+      Serial.print(" => ");
+      Serial.print("checking relay status runTimerDoLightOff --> ");
+      Serial.println(relaystatus);
+    }
+    relaystatus = LOW;
   }
 }

@@ -392,21 +415,22 @@

   if (DEBUG_PRINT) {
     Serial.print(" => ");
-    Serial.println("checking relay status changelight");
+    Serial.print("checking relay status changelight --> ");
+    Serial.println(relaystatus);
   }

   digitalWrite(RELAYPIN, relaystatus);
   delay(50);

+  if (DEBUG_PRINT) {
+    Serial.print(" => ");
+    Serial.print("changing relay status --> ");
+    Serial.println(relaystatus);
+  }
+
+  lastRelayActionmillis = millis();
   oldrelaystatus = relaystatus ;
   relayIsReady = LOW;
-
-  if (DEBUG_PRINT) {
-    Serial.print(" => ");
-    Serial.println("changing relay status");
-  }
-
-  lastRelayActionmillis = millis();
 }

 void getdht22temp()
@@ -503,7 +527,7 @@
     Serial.println("Transmit NTP Request called");
   }
   sendNTPpacket(time_server);
-  delay(1000);
+  delay(2000);
   uint32_t beginWait = millis();
   while (millis() - beginWait < 1500) {
     int size = udp.parsePacket();


Create fade_toward_solid_color.ino

Create fade_toward_solid_color.ino

error: pathspec 'fade_toward_solid_color.ino' did not match any file(s) known to git

--- fade_toward_solid_color.ino
+++ fade_toward_solid_color.ino
@@ -0,0 +1,106 @@
+/****************************************************************
+This example displays a color on all pixels, then blends the
+display to a new color and holds it for a bit.  Then repeats...
+
+The serial monitor will print out the target color when a new
+one is picked.
+
+Marc Miller, Jan 2020
+****************************************************************/
+
+#include "FastLED.h"
+#define LED_TYPE      LPD8806
+#define COLOR_ORDER   GRB
+#define DATA_PIN      11
+#define CLOCK_PIN     13   // ignore for clockless pixel types
+#define NUM_LEDS      32
+uint8_t BRIGHTNESS = 128;  // master brightness [0-255]
+CRGB leds[NUM_LEDS];
+
+CRGB currentColor(130,25,25);  // starting color
+CRGB targetColor(30,40,130);   // starting target color
+const uint8_t fadeRate = 42;   // larger number is a slower fade
+
+boolean fadeToColor = 1;  // turns on/off the fading toward target
+
+
+//===============================================================
+void setup() {
+  Serial.begin(115200);
+  delay(3000);  // (optional) safety start up delay
+  //FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
+  FastLED.addLeds<LED_TYPE, DATA_PIN, CLOCK_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
+  FastLED.setBrightness(BRIGHTNESS);  // set initial master brightness
+
+  fill_solid(leds, NUM_LEDS, currentColor);
+  FastLED.show();   // update the display
+  Serial.println("\nSetup done.\n");
+}
+
+
+//===============================================================
+void loop() {
+
+  EVERY_N_SECONDS(15) {
+    newTargetColor();  // set the new target color
+    fadeToColor = 1;  // start fading toward target
+  }
+
+  EVERY_N_MILLISECONDS(fadeRate) {
+    if (currentColor == targetColor) {
+      fadeToColor = 0;  // stop fading
+    }
+    if (fadeToColor) {
+      nblendU8TowardU8( currentColor.r, targetColor.r);
+      nblendU8TowardU8( currentColor.g, targetColor.g);
+      nblendU8TowardU8( currentColor.b, targetColor.b);
+      currentColor = CRGB(currentColor.r,currentColor.g,currentColor.b);
+    }
+
+    fill_solid(leds, NUM_LEDS, currentColor);
+
+    // For Testing --- always display target on first pixel
+    leds[0] = targetColor;
+
+    FastLED.show();
+  }
+
+} // end_main_loop
+
+
+//===============================================================
+// Modified helper function that blends one uint8_t toward another,
+// based on function from Mark Kriegsman's fadeTowardColor example:
+// https://gist.github.com/kriegsman/d0a5ed3c8f38c64adcb4837dafb6e690
+void nblendU8TowardU8(uint8_t& current, const uint8_t target)
+{
+  if( current == target) {
+    return;
+  }
+
+  if( current < target ) {
+    uint8_t delta = target - current;
+    delta = scale8_video( delta, 1);
+    current += delta;
+  } else {
+    uint8_t delta = current - target;
+    delta = scale8_video( delta, 1);
+    current -= delta;
+  }
+}
+
+
+//---------------------------------------------------------------
+// Pick a new target color to fade toward
+void newTargetColor() {
+  random16_add_entropy( random() );
+  targetColor = CHSV( random8(), 255, 255);
+
+  Serial.print("New targetColor ");
+  Serial.print("\tr: "); Serial.print(targetColor.r);
+  Serial.print("\tg: "); Serial.print(targetColor.g);
+  Serial.print("\tb: "); Serial.println(targetColor.b);
+}
+
+
+//---------------------------------------------------------------


Update pt_remote controlled car.ino

Update pt_remote controlled car.ino

error: pathspec 'pt_remote' did not match any file(s) known to git
error: pathspec 'controlled' did not match any file(s) known to git
error: pathspec 'car/pt_remote' did not match any file(s) known to git
error: pathspec 'controlled' did not match any file(s) known to git
error: pathspec 'car.ino' did not match any file(s) known to git


Update SlaveModule.ino

Update SlaveModule.ino

error: pathspec 'Arduino' did not match any file(s) known to git
error: pathspec 'code/SlaveModule/SlaveModule.ino' did not match any file(s) known to git


Cerveau: Ecran - update pins

Cerveau: Ecran - update pins

error: pathspec 'Module' did not match any file(s) known to git
error: pathspec 'Cerveau/Ecran/BotMenu/BotMenu/BotMenu.ino' did not match any file(s) known to git


Modifying poll time

Modifying poll time

error: pathspec 'unit' did not match any file(s) known to git
error: pathspec 'tests/pwm_detector_test/pwm_detector_test.ino' did not match any file(s) known to git


version 0.1

version 0.1

Example how to use isSMSunread and readSMS (with more information)

error: pathspec 'examples/GPRS_SMSread.ino' did not match any file(s) known to git

--- examples/GPRS_SMSread.ino
+++ examples/GPRS_SMSread.ino
@@ -0,0 +1,59 @@
+/*
+GPRS SMS Read
+
+This sketch is used to test seeeduino GPRS_Shield's reading SMS
+function.To make it work, you should insert SIM card
+to Seeeduino GPRS Shield,enjoy it!
+
+There are two methods to read SMS:
+  1. GPRS_LoopHandle.ino  -> in order to recieve "+CMTI: "SM""
+      may be you need to send this command to your shield: "AT+CNMI=2,2,0,0,0"
+  2. GPRS_SMSread.ino -> you have to check if there are any
+      UNREAD sms, and you don't need to check serial data continuosly
+
+create on 2014/10/16, version: 0.1
+by op2op2op2(op2op2op2@hotmail.com)
+*/
+
+#include <GPRS_Shield_Arduino.h>
+#include <SoftwareSerial.h>
+#include <Wire.h>
+#include <Suli.h>
+
+#define PIN_TX    7
+#define PIN_RX    8
+#define BAUDRATE  9600
+
+#define MESSAGE_LENGTH 160
+char message[MESSAGE_LENGTH];
+int messageIndex = 0;
+
+char phone[16];
+char datetime[24];
+
+GPRS gprsTest(PIN_TX,PIN_RX,BAUDRATE);//RX,TX,PWR,BaudRate
+
+void setup() {
+  Serial.begin(9600);
+  while(0 != gprsTest.init()) {
+      delay(1000);
+      Serial.print("init error\r\n");
+  }
+  delay(3000);
+  Serial.println("Init Success, please send SMS message to me!");
+}
+
+void loop() {
+   messageIndex = gprsTest.isSMSunread();
+   if (messageIndex > 0) { //At least, there is one UNREAD SMS
+      gprsTest.readSMS(messageIndex, message, MESSAGE_LENGTH, phone, datetime);
+      //In order not to full SIM Memory, is better to delete it
+      gprsTest.deleteSMS(messageIndex);
+      Serial.print("From number: ");
+      Serial.println(phone);
+      Serial.print("Datetime: ");
+      Serial.println(datetime);
+      Serial.print("Recv Message: ");
+      Serial.println(message);
+   }
+}


Initial commit with deep sleep and watchdog timer

error: pathspec 'firmware/HotPotato/HotPotato.ino' did not match any file(s) known to git

--- firmware/HotPotato/HotPotato.ino
+++ firmware/HotPotato/HotPotato.ino
@@ -0,0 +1,150 @@
+#include <avr/sleep.h>
+#include <avr/power.h>
+#include <avr/wdt.h>
+
+const unsigned int BUZZER_PIN = PB0;
+const unsigned int MOTOR_PIN = PB1;
+const unsigned int BUTTON_PIN = PB2;
+const unsigned int ACCELEROMETER_IN = PB3;
+const unsigned int ACCELEROMETER_POWER = PB4;
+const unsigned long DEBOUNCE_TIME = 50;
+
+volatile bool watchDogBarked = false;
+bool watchDogEnabled = false;
+
+volatile bool buttonPressed = false;
+
+enum WatchDogTimeout {
+  WDT_16ms,
+  WDT_32ms,
+  WDT_64ms,
+  WDT_128ms,
+  WDT_250ms,
+  WDT_500ms,
+  WDT_1sec,
+  WDT_2sec,
+  WDT_4sec,
+  WDT_8sec
+};
+
+enum PowerState {
+  SLEEP,
+  GAME
+};
+
+PowerState currentState = SLEEP; // Start with sleep as the initial state
+
+void setupWatchDogTimeoutOneshot(WatchDogTimeout wdt) {
+  // Adopted from InsideGadgets (www.insidegadgets.com)
+  byte timeoutVal = wdt & 7;
+  if (wdt > 7) {
+    timeoutVal |= (1 << 5);
+  }
+  timeoutVal |= (1 << WDCE);
+
+  MCUSR &= ~(1 << WDRF);
+  WDTCR |= (1 << WDCE) | (1 << WDE); // Start timed sequence
+  WDTCR = timeoutVal;
+  WDTCR |= _BV(WDIE);
+  wdt_reset();  // pat the dog
+}
+
+/**
+   Disables the accelerometer by setting the pin that powers it up to LOW
+*/
+void turnAccelerometerOff() {
+  digitalWrite(ACCELEROMETER_POWER, LOW);
+}
+
+/**
+   Enables the accelerometer by setting the pin that powers it up to HIGH
+*/
+void turnAccelerometerOn() {
+  digitalWrite(ACCELEROMETER_POWER, HIGH);
+}
+
+/**
+  Watchdog interrupt routine to be triggered when watchdog times out
+*/
+ISR(WDT_vect) {
+  watchDogBarked = true;
+  wdt_disable(); // disable watchdog
+}
+
+/**
+   Change interrupt routine (e.g. when button presses occur)
+*/
+ISR (PCINT0_vect) {
+  // TO-DO: Investigate ways to debounce the button
+  if (digitalRead(BUTTON_PIN) == HIGH) {
+    buttonPressed = true;
+  }
+}
+
+/**
+   Sets up pin change interrupt for PB2
+*/
+void setupChangeInterrupt() {
+  PCMSK |= bit (PCINT2); // want pin D2 (PB2)
+  GIFR |= bit (PCIF); // clear any outstanding interrupts
+  GIMSK |= bit (PCIE); // enable pin change interrupts
+}
+
+/**
+   Sets the MCU into a deep sleep state until a change interrupt is triggered
+*/
+void goToDeepSleep() {
+  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
+  ADCSRA = 0; // turn off ADC
+  power_all_disable (); // power off ADC, Timer 0 and 1, serial interface
+  sleep_enable();
+  sleep_cpu(); // Sleep here and wait for the interrupt
+  sleep_disable();
+  power_all_enable(); // power everything back on
+}
+
+void setup() {
+  pinMode(BUZZER_PIN, OUTPUT);
+  pinMode(MOTOR_PIN, OUTPUT);
+  pinMode(BUTTON_PIN, INPUT);
+  pinMode(ACCELEROMETER_IN, INPUT);
+  pinMode(ACCELEROMETER_POWER, OUTPUT);
+  setupChangeInterrupt();
+}
+
+void loop() {
+  switch (currentState) {
+    case SLEEP:
+      turnAccelerometerOff();
+      // Go to deep sleep until an interrupt occurs
+      goToDeepSleep();
+      // Proceed to the
+      if (buttonPressed) {
+        currentState = GAME;
+        buttonPressed = false;
+      }
+      break;
+    case GAME:
+      // If watchdog is not enabled, then we just arrived from SLEEP state
+      if (!watchDogEnabled) {
+        turnAccelerometerOn();
+        // Set up watchdog to be triggered (once) after the specified time
+        setupWatchDogTimeoutOneshot(WDT_1sec);
+        watchDogEnabled = true;
+        digitalWrite(BUZZER_PIN, HIGH);
+      }
+      // Go to deep sleep until an interrupt occurs
+      goToDeepSleep();
+      // We might have gone out of sleep due to another interrupt (i.e. the switch)
+      // So make sure that we only get out of this state using the watchdog
+      if (watchDogBarked) {
+        digitalWrite(BUZZER_PIN, LOW);
+        currentState = SLEEP;
+        watchDogBarked = false;
+        watchDogEnabled = false;
+      }
+      break;
+    default:
+      break;
+  }
+}


Create motor_driver.ino

Create motor_driver.ino

error: pathspec 'examples/motor_driver/motor_driver.ino' did not match any file(s) known to git

--- examples/motor_driver/motor_driver.ino
+++ examples/motor_driver/motor_driver.ino
@@ -0,0 +1,70 @@
+#include "MDriver.h"
+
+/*
+ * Библиотека MDrive предназначена для управление коллекторными двигателями
+ * посредством драйвера двигателе на микросхеме L293 или L298.
+ *
+ * В данном примере выходы драйвера двигателей подключены к следующим
+ * цифровым пинам Arduino:
+ * 1) для первого двигателя:*/
+#define ENA 3 //(ШИМ)
+#define IN1 2
+#define IN2 4
+  //2) для второго двигателя:
+#define ENB 5 //(ШИМ)
+#define IN3 6
+#define IN4 7
+
+/* Библиотека содержит следующие функции:
+ * speed(uint8_t speed); - принимает значение от 0 до 255, управляет
+ *  скоростью вращения. Если двигатель инициализирован без регулировки
+ *  скорости, то эта функция становится неактивной.
+ * forward(); и backward(); - управляют вращением двигателя в разных
+ *  направлениях
+ * stop(); - остановка двигателя
+ */
+
+//Первый способ инициализации.
+//Подключение двигателей с функцией регулировки скорости.
+//Конструктор принимает следующие аргументы MDrive(EN, IN1, IN2)
+MDriver m1(ENA, IN1, IN2);
+MDriver m2(ENB, IN3, IN4);
+
+//Второй способ инициализации.
+//Подключение моторов без регулировки скорости,
+//подразумевается что пин EN на плате драйвера двигателей подтянут к +5V.
+//Конструктор принимает следующие аргументы MDrive(IN1, IN2)
+//MDriver m1(IN1, IN2);
+//MDriver m2(IN3, IN4);
+
+//С использованием регулировки скорости
+void setup()
+{
+  for (int i = 255; i > 0; i -= 5)  //Плавное уменьшение скорости до полной остановки
+  {
+    m1.speed(i);
+    m1.backward();
+
+    m2.speed(i);
+    m2.backward();
+    delay(500);
+  }
+
+  for (int i = 0; i < 255; i += 5)  //Плавное увеличение скорости до максимальной, вращение в другую сторону
+  {
+    m1.speed(i);
+    m1.forward();
+
+    m2.speed(i);
+    m2.forward();
+    delay(500);
+  }
+
+  //Вращение двигателей в противоположных направлениях
+  m1.speed(MAX);
+  m2.speed(MAX);
+  m1.forward();
+  m2.backward();
+}
+
+void loop(){}


adds fona digital out example

adds fona digital out example

error: pathspec 'arduino-fona/digital-out/digital-out.ino' did not match any file(s) known to git

--- arduino-fona/digital-out/digital-out.ino
+++ arduino-fona/digital-out/digital-out.ino
@@ -0,0 +1,84 @@
+#include <SoftwareSerial.h>
+#include <Adafruit_FONA.h>
+
+#define FONA_RX 2
+#define FONA_TX 3
+#define FONA_RST 4
+#define LIGHT 8
+
+// replace xxxxxxxxx with your Adafruit IO key
+#define AIO_KEY "xxxxxxxxx"
+#define AIO_URL "http://io.adafruit.com/api/feeds/%s/data/last.txt?X-AIO-Key=%s"
+
+SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
+Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
+
+void setup() {
+
+  // set button pin as an input
+  pinMode(BUTTON, INPUT_PULLUP);
+
+  // wait until Serial is available
+  while (!Serial);
+
+  // Serial init
+  Serial.begin(115200);
+  Serial.println(F("Initializing....(May take a few seconds)"));
+
+  // SoftwareSerial init
+  fonaSS.begin(4800);
+
+  // bail if we can't connect to the FONA
+  if (! fona.begin(fonaSS)) {
+    Serial.println(F("Couldn't find FONA"));
+    while(1);
+  }
+
+  // turn on GPRS
+  fona.enableGPRS(true);
+
+}
+
+void loop() {
+
+  char* data = getData("Light");
+  int state = atoi(data);
+
+  digitalWrite(LIGHT, state == 1 ? HIGH : LOW);
+
+  // wait 1 second
+  delay(1000);
+
+}
+
+char* getData(char *feed) {
+
+  uint16_t statuscode;
+  int16_t length;
+  int16_t i = 0;
+
+  char url[200];
+  sprintf(url, AIO_URL, feed, AIO_KEY);
+
+  if(! fona.HTTP_GET_start(url, &statuscode, (uint16_t *)&length))
+    return "";
+
+  char data[length];
+
+  while(length > 0) {
+
+    if(fona.available()) {
+
+      data[i] = fona.read();
+      length--;
+      i++;
+
+    }
+
+  }
+
+  fona.HTTP_GET_end();
+
+  return data;
+
+}


serial library

serial library

error: pathspec 'serial2ethernet.ino' did not match any file(s) known to git

--- serial2ethernet.ino
+++ serial2ethernet.ino
@@ -0,0 +1,170 @@
+#include <SPI.h>
+#include <Ethernet.h>
+
+// Enter a MAC address and IP address for your controller below.
+byte mac[] = {
+  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
+
+// Our IP address
+IPAddress ip(2,2,2,103);
+
+// Initialize the Ethernet server library
+// with the IP address and port you want to use
+// (port 80 is default for HTTP):
+EthernetServer server(80);
+
+void setup()
+  {
+  // Open serial communications and wait for port to open:
+  Serial.begin(9600);
+  while (!Serial) { } // wait for serial port to connect.
+
+  // start the Ethernet connection and the server:
+  Ethernet.begin(mac, ip);
+  server.begin();
+  Serial.print(F("Server is at "));
+  Serial.println(Ethernet.localIP());
+  }  // end of setup
+
+// how much serial data we expect before a newline
+const unsigned int MAX_INPUT = 100;
+// the maximum length of paramters we accept
+const int MAX_PARAM = 10;
+
+// Example GET line: GET /?foo=bar HTTP/1.1
+void processGet (const char * data)
+  {
+  // find where the parameters start
+  const char * paramsPos = strchr (data, '?');
+  if (paramsPos == NULL)
+    return;  // no parameters
+  // find the trailing space
+  const char * spacePos = strchr (paramsPos, ' ');
+  if (spacePos == NULL)
+    return;  // no space found
+  // work out how long the parameters are
+  int paramLength = spacePos - paramsPos - 1;
+  // see if too long
+  if (paramLength >= MAX_PARAM)
+    return;  // too long for us
+  // copy parameters into a buffer
+  char param [MAX_PARAM];
+  memcpy (param, paramsPos + 1, paramLength);  // skip the "?"
+  param [paramLength] = 0;  // null terminator
+
+  // do things depending on argument (GET parameters)
+
+  if (strcmp (param, "foo") == 0){
+  tempx();
+    Serial.println (F("Activating foo"));
+//
+  }
+
+  else if (strcmp (param, "bar") == 0){
+    Serial.println (F("Activating bar"));
+  }
+  }  // end of processGet
+
+// here to process incoming serial data after a terminator received
+void processData (const char * data)
+  {
+  Serial.println (data);
+  if (strlen (data) < 4)
+    return;
+
+  if (memcmp (data, "GET ", 4) == 0)
+    processGet (&data [4]);
+  }  // end of processData
+
+bool processIncomingByte (const byte inByte)
+  {
+  static char input_line [MAX_INPUT];
+  static unsigned int input_pos = 0;
+  switch (inByte)
+    {
+    case '\n':   // end of text
+      input_line [input_pos] = 0;  // terminating null byte
+      if (input_pos == 0)
+        return true;   // got blank line
+      // terminator reached! process input_line here ...
+      processData (input_line);
+      // reset buffer for next time
+      input_pos = 0;
+      break;
+
+    case '\r':   // discard carriage return
+      break;
+
+    default:
+      // keep adding if not full ... allow for terminating null byte
+      if (input_pos < (MAX_INPUT - 1))
+        input_line [input_pos++] = inByte;
+      break;
+    }  // end of switch
+  return false;    // don't have a blank line yet
+  } // end of processIncomingByte
+
+
+void loop()
+  {
+  // listen for incoming clients
+  EthernetClient client = server.available();
+  if (client)
+    {
+    Serial.println(F("Client connected"));
+    // an http request ends with a blank line
+    boolean done = false;
+    while (client.connected() && !done)
+      {
+      while (client.available () > 0 && !done)
+        done = processIncomingByte (client.read ());
+      }  // end of while client connected
+
+    // send a standard http response header
+    client.println(F("HTTP/1.1 200 OK"));
+    client.println(F("Content-Type: text/html"));
+    client.println(F("Connection: close"));  // close after completion of the response
+    client.println();   // end of HTTP header
+    client.println(F("<!DOCTYPE HTML>"));
+    client.println(F(""));
+    client.println(F(""));
+    client.println(F("<title>Test page</title>"));
+    client.println(F(""));
+    client.println(F(""));
+    client.println(F("
My web page
"));
+    client.println(F("
Requested actions performed"));
+    client.println(F(""));
+    client.println(F(""));
+
+    // give the web browser time to receive the data
+    delay(10);
+    // close the connection:
+    client.stop();
+    Serial.println(F("Client disconnected"));
+  }  // end of got a new client
+}
+
+
+
+void tempx(){
+    EthernetClient client = server.available();
+    client.println(F("HTTP/1.1 200 OK"));
+    client.println(F("Content-Type: text/html"));
+    client.println(F("Connection: close"));  // close after completion of the response
+    client.println();   // end of HTTP header
+    client.println(F("<!DOCTYPE HTML>"));
+    client.println(F(""));
+    client.println(F(""));
+    client.println(F("<title>Test page</title>"));
+    client.println(F(""));
+    client.println(F(""));
+    client.println(F("
TEMPERATURE IS:
"));
+    client.println(F(""));
+    client.println(F(""));
+
+    // give the web browser time to receive the data
+    delay(10);
+    // close the connection:
+    client.stop();
+
+}


Add v3.0 conditioning code that does not use interrupts

error: pathspec 'Arduino/v0.3.0_conditioning/v0.3.0_conditioning.ino' did not match any file(s) known to git

--- Arduino/v0.3.0_conditioning/v0.3.0_conditioning.ino
+++ Arduino/v0.3.0_conditioning/v0.3.0_conditioning.ino
@@ -0,0 +1,109 @@
+#include "AES.h"
+#include "CBC.h"
+
+#define CHAIN_SIZE 2
+#define BLOCK_SIZE 16  // this is defined in AES library. We should probably set it dynamically.
+#define SAMPLE_SIZE (BLOCK_SIZE * CHAIN_SIZE)
+
+byte key[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
+
+CBC<AES128> cbc;
+
+byte sourcePool[SAMPLE_SIZE];
+byte moduloReplacement;
+
+bool flip = false;
+
+int currentByte = 0;
+int bitCounter=0;
+
+/******* SETUP *********/
+
+void setup()
+{
+  // Defining PB1 and PB2 as outputs by setting PORTB1 and PORTB2
+  // Setting DDB1 and DDB2
+  DDRB |= bit (DDB1) | bit (DDB2);
+
+  //Set D pins to input
+  DDRD = 0x00;
+
+  Serial.begin(2000000);
+
+  calculateModuloReplacement();
+}
+
+
+//This method is so we don't have to use modulo in collectBytes().
+//(Modulo is very slow on Arduino.)
+void calculateModuloReplacement(){
+  double logValue = log(SAMPLE_SIZE) / log(2);
+  double roundedLogValue = round(logValue);
+
+  //Assert that sample size is a power of 2
+  //Otherwise our fast modulo technique will not work
+  if (fabs(logValue - roundedLogValue) > 0.001) {
+    abort();
+  }
+
+  int variableSizeInBits = sizeof(moduloReplacement) * 8;
+  moduloReplacement = 0xFF >> (variableSizeInBits - (byte)roundedLogValue);
+}
+
+
+void loop() {
+  currentByte = 0;
+  for (bitCounter=0; bitCounter < 8; bitCounter += 2) {
+    runClockSignals();
+    runClockSignals();
+    byte pinVal = (PIND >> 6) & B00000011;
+    currentByte |= pinVal << bitCounter;
+  }
+  boolean poolFull = collectByte(currentByte);
+    if (poolFull){
+      conditionPoolAndWriteToSerial();
+      //Serial.write(sourcePool, SAMPLE_SIZE);
+    }
+}
+
+void runClockSignals(){
+  if (flip) {
+    PORTB = 0b00000010;
+  }
+  else {
+    PORTB = 0b00000100;
+  }
+  flip = !flip;
+}
+
+
+//@return true if sourcePool is full
+boolean collectByte(byte currentByte){
+  static int byteCount = 0;
+  sourcePool[byteCount] = currentByte;
+  byteCount = (++byteCount) & moduloReplacement;
+  //Serial.println(byteCount);
+
+  if (byteCount == 0){
+    return true;
+  }
+  return false;
+}
+
+ //TODO: this should return encrypted pool, and mac should
+ //be sent in the calling function
+void conditionPoolAndWriteToSerial(){
+  //Serial.println("Conditioning");
+  static byte iv[BLOCK_SIZE] = {0};
+  byte output[SAMPLE_SIZE];
+  cbc.clear();
+  cbc.setKey(key, 16);
+  cbc.setIV(iv, 16);
+  cbc.encrypt(output, sourcePool, SAMPLE_SIZE);
+
+  //advance pointer to last block (the MAC)
+  byte *outBuf = &output[SAMPLE_SIZE - BLOCK_SIZE];
+  Serial.write(outBuf, BLOCK_SIZE);
+}
+


Esp8266 started

Esp8266 started

error: pathspec 'src/Esp8266/esp8266/esp8266.ino' did not match any file(s) known to git

--- src/Esp8266/esp8266/esp8266.ino
+++ src/Esp8266/esp8266/esp8266.ino
@@ -0,0 +1,9 @@
+void setup() {
+  // put your setup code here, to run once:
+
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+
+}


Particle photon

Particle photon

error: pathspec 'photon.ino' did not match any file(s) known to git

--- photon.ino
+++ photon.ino
@@ -0,0 +1,41 @@
+Servo a;
+Servo b;
+Servo c;
+Servo d;
+
+int angle;
+int angle2;
+int angle3;
+int angle4;
+
+void setup() {
+    angle = 90;
+    angle2 = 92;
+    angle3 = 180;
+    angle4 = 0;
+    a.attach(D0);
+    b.attach(D1);
+    c.attach(D2);
+    d.attach(D3);
+
+    Particle.variable("angle", angle);
+    Particle.variable("angle2", angle2);
+    Particle.variable("angle3", angle3);
+    Particle.function("set", set);
+}
+
+void loop() {
+    a.write((180 - angle) - 10);
+    b.write(180 - angle2);
+    c.write(180 - angle3);
+    d.write(angle4);
+}
+
+int set(String i){
+    received = i;
+    angle = i.substring(0,3).toInt();
+    angle2 = i.substring(3,6).toInt();
+    angle3 = i.substring(6,9).toInt();
+    angle4 = i.substring(9,12).toInt();
+    return 0;
+}


Change morse_dict's type to byte.

Change morse_dict's type to byte.

Should save 26*4 bytes.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/kdomen/Morse-Code.git/'


- Eddystone URL beacon example

- Eddystone URL beacon example

error: pathspec 'examples/Eddystone/EddystoneURL/EddystoneURL.ino' did not match any file(s) known to git

--- examples/Eddystone/EddystoneURL/EddystoneURL.ino
+++ examples/Eddystone/EddystoneURL/EddystoneURL.ino
@@ -0,0 +1,30 @@
+// Import libraries (EddystoneBeacon depends on SPI)
+#include <SPI.h>
+#include <EddystoneBeacon.h>
+
+// define pins (varies per shield/board)
+//
+//   Adafruit Bluefruit LE   10, 2, 9
+//   Blend                    9, 8, UNUSED
+//   Blend Micro              6, 7, 4
+//   RBL BLE Shield           9, 8, UNUSED
+
+#define EDDYSTONE_BEACON_REQ   6
+#define EDDYSTONE_BEACON_RDY   7
+#define EDDYSTONE_BEACON_RST   4
+
+EddystoneBeacon eddystoneBeacon = EddystoneBeacon(EDDYSTONE_BEACON_REQ, EDDYSTONE_BEACON_RDY, EDDYSTONE_BEACON_RST);
+
+void setup() {
+  Serial.begin(9600);
+
+  delay(1000);
+
+  eddystoneBeacon.begin(0x20, "http://www.example.com"); // power, URI
+
+  Serial.println(F("Eddystone URL Beacon"));
+}
+
+void loop() {
+  eddystoneBeacon.loop();
+}


Modified the range of gyroscope

Modified the range of gyroscope

Changed range of gyroscope from 250 to 2000

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/minhcly/imu3darduino.git/'


Added PWM code

Added PWM code

error: pathspec 'CSC_460_-_Jan_21.ino' did not match any file(s) known to git

--- CSC_460_-_Jan_21.ino
+++ CSC_460_-_Jan_21.ino
@@ -0,0 +1,138 @@
+//#include <Servo.h>
+
+//Servo myservo;  // create servo object to control a servo
+
+int potpin = 0;  // analog pin used to connect the potentiometer
+int val;    // variable to read the value from the analog pin
+volatile byte b = 0; // Byte we're trying to transmit
+volatile int i = 7; // Index of byte b we're comparing against.
+
+void setup()
+{
+  pinMode(3, OUTPUT);
+  pinMode(13, OUTPUT);
+//  myservo.attach(9);  // attaches the servo on pin 9 to ¨the servo object
+  Serial.begin(9600);
+
+  pinMode(10, OUTPUT);
+
+
+  //Clear timer config.
+  TCCR3A = 0;
+  TCCR3B = 0;
+  //Set to CTC (mode 4)
+  TCCR3B |= (1<<WGM32);
+
+  //Set prescaller to 256
+//  TCCR3B |= (1<<CS32);
+  TCCR3B |= (1<<CS30);
+
+  //Set TOP value (0.5 seconds)
+//  OCR3A = 31250;
+   OCR3A = 8000;
+
+//  //Enable interupt A for timer 3.
+//  TIMSK  `3 |= (1<<OCIE3A);
+//
+//  //Set timer to 0 (optional here).
+//  TCNT3 = 0;
+
+
+//  //PWM
+  //Clear timer config
+  TCCR1A = 0;
+  TCCR1B = 0;
+  TIMSK1 &= ~(1<<OCIE1C);
+  //Set to Fast PWM (mode 15)
+  TCCR1A |= (1<<WGM10) | (1<<WGM11);
+  TCCR1B |= (1<<WGM12) | (1<<WGM13);
+
+  //Enable output C.
+  TCCR1A |= (1<<COM1C1);
+  //No prescaler
+  TCCR1B |= (1<<CS10);
+
+  OCR1A = 410;  //38KHz
+  OCR1C = 140;  //Target
+  TCCR1A &= ~(1<<COM1C1);
+}
+
+
+volatile int header = 1;
+ISR(TIMER3_COMPA_vect)
+{
+
+  if(header == 1){
+    // turn on for 500us
+     TCCR1A |= (1<<COM1C1);
+     header = 2;
+     return;
+  }else if (header == 2){
+    // turn off for 500us
+    TCCR1A &= ~(1<<COM1C1);
+    header = 0;
+    return;
+  }
+
+
+  if ((b & (1 << i)) != 0) {
+    TCCR1A |= (1<<COM1C1);
+//    OCR1C = 140;  //Target
+//    digitalWrite(3, HIGH);
+  } else {
+    TCCR1A &= ~(1<<COM1C1);
+//    OCR1C = 0;  //Target
+   // digitalWrite(3, LOW);
+  }
+
+  i -= 1;
+
+  // All of byte was transmitted.
+  if (i < 0) {
+//    digitalWrite(3, LOW);
+//    OCR1C = 0;  //Target
+    // disable the IRT
+    TCCR1A &= ~(1<<COM1C1);
+
+
+    TIMSK3 ^= (1<<OCIE3A);
+    digitalWrite(10, LOW);
+  }
+}
+
+void transmit(byte _b) {
+  digitalWrite(10, HIGH);
+  b = _b;
+  i = 7;
+  header = 1;
+
+  cli();
+
+  //Enable interupt A for timer 3.
+  TIMSK3 |= (1<<OCIE3A);
+  // Clear interrupt;
+  TIFR3 |= (1<<OCF3A);
+  //Set timer to 0 (optional here).
+  TCNT3 = 0;
+
+  sei();
+}
+
+void loop()
+{
+  val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
+  val = map(val, 0, 1023, 0, 180);     // scale it to use it with the servo (value between 0 and 180)
+//  Serial.println(val);
+
+  int button = analogRead(A2);
+  Serial.println(button);
+  if (button < 10) {
+    transmit(0xAA);
+  }
+
+  int receiver = analogRead(A3);
+//  Serial.println(receiver);
+//  myservo.write(val);                  // sets the servo position according to the scaled value
+  delay(15);                           // waits for the servo to get there
+}
+


added forgotten file of last commit

added forgotten file of last commit

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/joschal/X2RP6.git/'


Add example sketch for receiving OTA updates in MQTT messages

error: pathspec 'examples/ESP8266-OTA/ESP8266-OTA.ino' did not match any file(s) known to git

--- examples/ESP8266-OTA/ESP8266-OTA.ino
+++ examples/ESP8266-OTA/ESP8266-OTA.ino
@@ -0,0 +1,96 @@
+/*
+ * Test/demonstration of over-the-air update of an ESP8266 using MQTT.
+ *
+ * This sketch connects to an MQTT broker and subscribes to a specific topic
+ * to receive OTA updates on.
+ * Send the message using the mosquitto tool:
+ $ mosquitto_pub -h 192.168.1.1 -t 'ota/192.168.1.13' -f /tmp/build*.tmp/sensor-node.cpp.bin
+ *
+ */
+
+#include <ESP8266WiFi.h>
+#include <WiFiClient.h>
+#include <PubSubClient.h>
+
+// Replace with your Wifi SSID and passphrase
+const char* ssid = "xxxxxxxx";
+const char* pass = "yyyyyyyy";
+
+// Replace with the IP address of your MQTT server
+IPAddress server_ip(192,168,1,1);
+
+void setup() {
+  Serial.begin(115200);
+  Serial.println("");
+  Serial.println("Arduino MQTT OTA Test");
+
+  Serial.printf("Sketch size: %u\n", ESP.getSketchSize());
+  Serial.printf("Free size: %u\n", ESP.getFreeSketchSpace());
+}
+
+WiFiClient wclient;
+PubSubClient client(wclient, server_ip);
+
+void receive_ota(const MQTT::Publish& pub) {
+  uint32_t startTime = millis();
+  uint32_t size = pub.payload_len();
+  if (size == 0)
+    return;
+
+  Serial.print("Receiving OTA of ");
+  Serial.print(size);
+  Serial.println(" bytes...");
+
+  Serial.setDebugOutput(true);
+  if (!Update.begin(size)) {
+    Serial.println("Update Begin Error");
+    return;
+  }
+
+  uint32_t total = 0;
+  while (!Update.isFinished()) {
+    uint32_t written = Update.write(*pub.payload_stream());
+    if (written > 0) {
+      total += written;
+      Serial.print(total, DEC);
+      Serial.println(" bytes");
+    }
+  }
+
+  if (Update.end()) {
+    Serial.println("Clearing retained message.");
+    client.publish(MQTT::Publish(pub.topic(), "")
+                   .set_retain());
+
+    Serial.printf("Update Success: %u\nRebooting...\n", millis() - startTime);
+    ESP.restart();
+  } else {
+    Update.printError(Serial);
+  }
+  Serial.setDebugOutput(false);
+}
+
+void loop() {
+  if (WiFi.status() != WL_CONNECTED) {
+    Serial.print("Connecting to ");
+    Serial.print(ssid);
+    Serial.println("...");
+    WiFi.begin(ssid, pass);
+    if (WiFi.waitForConnectResult() != WL_CONNECTED)
+      return;
+
+    IPAddress local = WiFi.localIP();
+    String ipaddr = String(local[0]) + "." + String(local[1]) + "." + String(local[2]) + "." + String(local[3]);
+    Serial.print("IP address: ");
+    Serial.println(ipaddr);
+
+    client.connect(WiFi.macAddress());  // Give ourselves a unique client name
+    client.set_callback(receive_ota);   // Register our callback for receiving OTA's
+
+    String topic = "ota/" + ipaddr;
+    Serial.print("Subscribing to topic ");
+    Serial.println(topic);
+    client.subscribe(topic);
+  }
+  client.loop();
+}


Create Button_alt.ino

Create Button_alt.ino

error: pathspec 'Arduino/Basics/Digital/Button_alt.ino' did not match any file(s) known to git

--- Arduino/Basics/Digital/Button_alt.ino
+++ Arduino/Basics/Digital/Button_alt.ino
@@ -0,0 +1,48 @@
+/*
+Button
+Carlos Castellanos | 2014 | ccastellanos.com
+
+Press and relasese to turn an LED on, then press and relasese again to turn off
+
+Note: this example works best witha momentary pushbutton or similary biased switch
+
+
+Schematic, see:
+https://github.com/carloscastellanos/teaching/blob/master/Arduino/Basics/Digital/Button_schem.png
+
+Suggestions:
+- Can you make the LED go off after a certain amount of time has passed? Hint: while
+  using 'delay' will work, you can also look into the 'millis' function...
+- add an additional led and/or button na d increase the complexity of behaviors
+*/
+
+// constants won't change. They're used here to set pin numbers (faster/saves memory):
+const int buttonPin = 2;      // pins for button and LED
+const int ledPin = 13;
+
+// store button's status - initialize to OFF (this variable will change, so it's not a const)
+int buttonState = 0;
+int prevButtonState = 0;
+bool on = false;
+
+void setup() {
+  pinMode(buttonPin, INPUT);    // set button to input
+  pinMode(ledPin, OUTPUT);      // LED to output
+}
+
+void loop() {
+
+  // read the state of the button into our variable
+  buttonState = digitalRead(buttonPin);
+
+  // test that state
+  if (buttonState == HIGH) {      // if button is pressed...
+    if(prevButtonState == LOW) {  // if it was previously not pressed
+      on = !on;
+      digitalWrite(ledPin, on);   // toggle the LED
+    }
+  }
+
+  prevButtonState = buttonState; // save the previous button state
+
+}


Create msnger.ino

Create msnger.ino

error: pathspec 'msnger.ino' did not match any file(s) known to git

--- msnger.ino
+++ msnger.ino
@@ -0,0 +1,327 @@
+#include <Adafruit_CC3000.h>
+#include <ccspi.h>
+#include <SPI.h>
+#include <string.h>
+#include "utility/debug.h"
+#include <LiquidCrystal.h>
+
+LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7);
+
+// These are the interrupt and control pins
+#define ADAFRUIT_CC3000_IRQ   3  // MUST be an interrupt pin!
+
+// These can be any two pins
+#define ADAFRUIT_CC3000_VBAT  19
+#define ADAFRUIT_CC3000_CS    2
+
+// Use hardware SPI for the remaining pins
+// On an UNO, SCK = 13, MISO = 12, and MOSI = 11
+Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,SPI_CLOCK_DIVIDER);
+
+#define WLAN_SSID       "SSID"
+#define WLAN_PASS       "password"
+
+// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
+#define WLAN_SECURITY   WLAN_SEC_WPA2
+
+// Timeout for connection to web server
+#define IDLE_TIMEOUT_MS  10000
+
+// Define the web page to grab
+#define WEBSITE      "www.puffycode.com"
+#define DEF_WEBPAGE  "/messenger/msgrecv.php"
+
+// Define button presses
+#define UP 141
+#define DOWN 326
+#define LEFT1 502
+#define LEFT2 503
+#define RIGHT 0
+#define SELECT 738
+
+// Define the max num of characters allowed on screen
+#define CHAR_LIMIT 39
+
+/* VARIABLE DECLARATIONS */
+boolean connectionState = false;  // Variable for keeping track of the connection to the AP
+boolean lcdIndex = 0;             // Keep track if messages[0] or messages[1] is displayed
+unsigned long timer;              // Timer for refreshing the messages at an interval
+unsigned short msgIndex;          // Index of current message
+unsigned short msgCount;          // Total number of messages
+String messages[2] = {"", ""};    // Array to hold the message ([0] Message, [1] Overflow of LCD)
+String displayCount = "";         // String to hold the index / msgCount
+String author = "";               // String for the author's name
+unsigned short lcdCycle = 0;      // Integer for counting cycles
+
+uint32_t ip;
+
+void setup(void)
+{
+  //Serial.begin(115200);
+  lcd.begin(40,2);
+  pinMode(A0, INPUT);
+
+  //Serial.print("Free RAM: "); Serial.println(getFreeRam(), DEC);
+
+  // Start and setup the CC3000
+  setupCC3000();
+
+  // Pull the web page.
+  getWebpage(DEF_WEBPAGE);
+}
+
+void loop(void)
+{
+  if (connectionState) {
+    if (!timer) {
+      timer = millis();
+    } else if ((millis() - timer) >= 300000UL) {
+      getWebpage(DEF_WEBPAGE);
+      timer = NULL;
+    }
+  }
+  // Read the state of the buttons on the LCD shield
+  switch (analogRead(A0)) {
+    case UP:
+      connectAP();
+      getWebpage(DEF_WEBPAGE);
+      break;
+    case DOWN:
+      disconnectAP();
+      break;
+    case RIGHT:
+      nextMsg();
+      break;
+    case LEFT1:
+    case LEFT2:
+      if (msgIndex == 1) {break;}
+      prevMsg();
+      break;
+    case SELECT:
+      getWebpage(DEF_WEBPAGE);
+      break;
+    default:
+      break;
+  }
+
+  if (lcdCycle++ == CHAR_LIMIT && messages[1].length() > 0) {
+    // Swap the messages on screen
+    if (lcdIndex) {
+      setScreen(messages[0], displayCount, 0);
+      lcdIndex = 0;
+    } else {
+      setScreen(messages[1], "", 0);
+      lcdIndex = 1;
+    }
+    lcdCycle = 0;
+  }
+  lcd.scrollDisplayLeft();
+  delay(250);
+}
+
+void setScreen(String topline, String bottomline, int pos) {
+  lcd.clear();
+  lcd.setCursor(pos,0);
+  lcd.print(topline);
+  lcd.setCursor(pos,1);
+  lcd.print(bottomline);
+}
+
+void setupCC3000() {
+  /* Initialise the module */
+  //Serial.println(F("\nInitializing..."));
+  setScreen("Initializing", "CC3000...", 0);
+  if (!cc3000.begin())
+  {
+    //Serial.println(F("Couldn't begin()! Check your wiring?"));
+    while(1);
+  }
+
+  setScreen("Setting the Mac", "Address", 0);
+
+  /* Optional: Update the Mac Address to a known value */
+  uint8_t macAddress[6] = { 0x08, 0x00, 0x28, 0x01, 0x79, 0xB7 };
+   if (!cc3000.setMacAddress(macAddress))
+   {
+     //Serial.println(F("Failed trying to update the MAC address"));
+     while(1);
+   }
+
+   // Connect to the AP
+   connectAP();
+}
+
+void connectAP() {
+  setScreen("Connecting to ", WLAN_SSID, 0);
+  //Serial.print(F("\nAttempting to connect to ")); Serial.println(WLAN_SSID);
+  if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
+    //Serial.println(F("Failed!"));
+    while(1);
+  }
+
+  // Connection established
+  //Serial.println(F("Connected!"));
+  setScreen("Connected...", "", 0);
+  connectionState = true;
+
+  /* Wait for DHCP to complete */
+  //Serial.println(F("Request DHCP"));
+  setScreen("Requesting IP", "Address...", 0);
+  while (!cc3000.checkDHCP())
+  {
+    delay(100); // ToDo: Insert a DHCP timeout!
+  }
+  ip = 0;
+  // Try looking up the website's IP address
+  //Serial.print(WEBSITE); Serial.print(F(" -> "));
+  setScreen("Resolving", WEBSITE, 0);
+  while (ip == 0) {
+    if (! cc3000.getHostByName(WEBSITE, &ip)) {
+      //Serial.println(F("Couldn't resolve!"));
+      setScreen("Couldn't resolve...", "", 0);
+    }
+    delay(500);
+  }
+  cc3000.printIPdotsRev(ip);
+}
+
+void getWebpage(char *webpage) {
+  setScreen("Retrieving", "messages...", 0);
+  Adafruit_CC3000_Client www = cc3000.connectTCP(ip, 80);
+
+  if (www.connected()) {
+    www.fastrprint(F("GET "));
+    www.fastrprint(webpage);
+    //Serial.print("Requesting webpage -> ");
+    //Serial.println(webpage);
+    www.fastrprint(F(" HTTP/1.1\r\n"));
+    www.fastrprint(F("Host: ")); www.fastrprint(WEBSITE); www.fastrprint(F("\r\n"));
+    www.fastrprint(F("\r\n"));
+    www.println();
+  } else {
+    //Serial.println(F("Connection failed"));
+    setScreen("Connection failed...", "", 0);
+    return;
+  }
+
+  /* Read data until either the connection is closed, or the idle timeout is reached. */
+  unsigned long lastRead = millis();
+  boolean inMsg, inMsgIndex, inMsgCount, inAuthor;
+  inMsg = inMsgIndex = inMsgCount = inAuthor = false;
+  author = "";
+  messages[0] = messages[1] = "";
+  unsigned int i = 0;     // Used to keep track of loops when assigning msgIndex and msgCount
+  int tempIndex[5] = {0,0,0,0,0};
+  //Serial.println("\n");
+  while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS)) {
+    while (www.available()) {
+      char c = www.read();
+      if (c == '%') {
+        inMsg = (inMsg == false) ? true : false;
+        continue;
+      }
+      if (inMsg) {
+        // Check for the first delimiter
+        if (c == '^') {
+          inMsgIndex = (inMsgIndex == false) ? true : false;
+
+          // At this point if we are in the msgCount area this means
+          // we have reached the end of the delimited space and need to
+          // convert the int array to a single integer
+          if (inMsgCount) {
+            msgCount = convertArrayToInt(tempIndex, i);
+
+            // Now set the inAuthor boolean to true because the next
+            // part of the packet is the author's name
+            inAuthor = true;
+            //Serial.print("msgCount = ");
+            //Serial.println(msgCount, DEC);
+          }
+          continue;
+        }
+
+        if (c == ':') {
+          inAuthor = false;
+          continue;
+        }
+
+        // Check for the second delimiter
+        if (c == '/') {
+          // At this point we have collected the index
+          msgIndex = convertArrayToInt(tempIndex, i);
+          //Serial.print("msgIndex = ");
+          //Serial.println(msgIndex, DEC);
+
+          // We are now in msgCount and need to reset the i counter
+          inMsgCount = (inMsgCount == false) ? true : false;
+          i = 0;
+          memset(tempIndex, 5, sizeof(int));
+          continue;
+        }
+
+        if (inMsgIndex) {
+          if (inMsgCount) {
+            tempIndex[i] = c - '0';
+            i++;
+          } else {
+            tempIndex[i] = c - '0';
+            i++;
+          }
+          continue;
+        }
+
+        if (inAuthor) {
+          author += c;
+          continue;
+        }
+
+        // Copy the character to the message
+        if (messages[0].length() < CHAR_LIMIT) {
+          messages[0] += c;
+        } else {
+          messages[1] += c;
+        }
+      }
+      lastRead = millis();
+    }
+  }
+  www.close();
+
+  displayCount = (String)"Msg " + msgIndex + "/" + msgCount + "  By: " + author;
+  lcdIndex = lcdCycle = 0;
+  setScreen(messages[0], displayCount, 0);
+  //Serial.println(message);
+}
+
+void disconnectAP() {
+  // Disconnect from the AP
+  //Serial.println(F("\n\nDisconnecting"));
+  cc3000.disconnect();
+
+  // Set the connection state to false and stop the timer
+  connectionState = false;
+  timer = NULL;
+
+  // Set the LCD display to disconnected
+  setScreen("Disconnected from AP...", "", 0);
+}
+
+void prevMsg() {
+  char temp[64];
+  sprintf(temp, "%s?index=%d", DEF_WEBPAGE, msgIndex - 1);
+  getWebpage(temp);
+}
+
+void nextMsg() {
+  char temp[64];
+  sprintf(temp, "%s?index=%d", DEF_WEBPAGE, msgIndex + 1);
+  getWebpage(temp);
+}
+
+int convertArrayToInt(int *a, int aSize) {
+  int i, b = 0;
+  for (i = 0; i < aSize; i++) {
+    b = (b * 10) + a[i];
+  }
+  return b;
+}


[MCP23017]: Play with TCA9548 to have multiple I2c busses

error: pathspec 'Mcp23017/mcp23017/mcp23017.ino' did not match any file(s) known to git

--- Mcp23017/mcp23017/mcp23017.ino
+++ Mcp23017/mcp23017/mcp23017.ino
@@ -0,0 +1,180 @@
+#include <Wire.h>
+
+#define PCA9548ADDR 0x70
+
+#define I2C_CHANNEL_SDSC0 0x01
+#define I2C_CHANNEL_SDSC1 0x02
+#define I2C_CHANNEL_SDSC2 0x04
+#define I2C_CHANNEL_SDSC3 0x08
+#define I2C_CHANNEL_SDSC4 0x10
+#define I2C_CHANNEL_SDSC5 0x20
+#define I2C_CHANNEL_SDSC6 0x40
+#define I2C_CHANNEL_SDSC7 0x80
+
+int ledState = 0;
+int result = 0;
+
+
+void setup() {
+  // put your setup code here, to run once:
+  delay(2000);
+
+  Wire.begin();
+
+  //select SDA3 / SCL3
+  selectI2cChannels(I2C_CHANNEL_SDSC3);
+  Wire.beginTransmission(0x20);
+  //port A as output
+  Wire.write(0x00);
+  Wire.write(0x00);
+  Wire.endTransmission();
+  Wire.beginTransmission(0x20);
+  //port B as output
+  Wire.write(0x01);
+  Wire.write(0x00);
+  Wire.endTransmission();
+//  Wire.beginTransmission(0x20);
+//  //Write '1' to GPB0-GPB3
+//  Wire.write(0x13);
+//  Wire.write(0x0f);
+//  Wire.endTransmission();
+
+  //select SDA0 / SCL0
+  selectI2cChannels(I2C_CHANNEL_SDSC0);
+  Wire.beginTransmission(0x20);
+  //port A as output
+  Wire.write(0x00);
+  Wire.write(0x00);
+  Wire.endTransmission();
+  Wire.beginTransmission(0x20);
+  //port B, GPB0 as output / GPB1-GPB7 as input
+  Wire.write(0x01);
+  Wire.write(0xFE);
+  Wire.endTransmission();
+  Wire.beginTransmission(0x20);
+  Wire.write(0x13);
+  Wire.write(0x01);
+  Wire.endTransmission();
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  selectI2cChannels(I2C_CHANNEL_SDSC3);
+  Wire.beginTransmission(0x20);
+  Wire.write(0x13);
+  Wire.write(0x00);
+  Wire.endTransmission();
+  delay(100);
+
+  selectI2cChannels(I2C_CHANNEL_SDSC0);
+  Wire.beginTransmission(0x20);
+  Wire.write(0x13);
+  Wire.endTransmission();
+  Wire.requestFrom(0x20, 1);
+  result = Wire.read();
+  if (result & 0x02) {
+    Wire.beginTransmission(0x20);
+    Wire.write(0x13);
+    Wire.write(0x00);
+    Wire.endTransmission();
+  } else {
+    Wire.beginTransmission(0x20);
+    Wire.write(0x13);
+    Wire.write(0x01);
+    Wire.endTransmission();
+    delay(100);
+    Wire.beginTransmission(0x20);
+    Wire.write(0x13);
+    Wire.write(0x00);
+    Wire.endTransmission();
+  }
+
+//  Wire.beginTransmission(0x20);
+//  Wire.write(0x13);
+//  if (ledState == 0x01) {
+//    ledState = 0x00;
+//  } else {
+//    ledState = 0x01;
+//  }
+//  Wire.write(ledState);
+//  Wire.endTransmission();
+//
+  selectI2cChannels(I2C_CHANNEL_SDSC3);
+  Wire.beginTransmission(0x20);
+  Wire.write(0x13);
+  Wire.write(0x01);
+  Wire.endTransmission();
+  delay(100);
+
+//  selectI2cChannels(I2C_CHANNEL_SDSC0);
+//  Wire.beginTransmission(0x20);
+//  Wire.write(0x13);
+//  if (ledState == 0x01) {
+//    ledState = 0x00;
+//  } else {
+//    ledState = 0x01;
+//  }
+//  Wire.write(ledState);
+//  Wire.endTransmission();
+
+  selectI2cChannels(I2C_CHANNEL_SDSC3);
+  Wire.beginTransmission(0x20);
+  Wire.write(0x13);
+  Wire.write(0x02);
+  Wire.endTransmission();
+  delay(100);
+
+//  selectI2cChannels(I2C_CHANNEL_SDSC0);
+//  Wire.beginTransmission(0x20);
+//  Wire.write(0x13);
+//  if (ledState == 0x01) {
+//    ledState = 0x00;
+//  } else {
+//    ledState = 0x01;
+//  }
+//  Wire.write(ledState);
+//  Wire.endTransmission();
+//
+  selectI2cChannels(I2C_CHANNEL_SDSC3);
+  Wire.beginTransmission(0x20);
+  Wire.write(0x13);
+  Wire.write(0x04);
+  Wire.endTransmission();
+  delay(100);
+
+//  selectI2cChannels(I2C_CHANNEL_SDSC0);
+//  Wire.beginTransmission(0x20);
+//  Wire.write(0x13);
+//  if (ledState == 0x01) {
+//    ledState = 0x00;
+//  } else {
+//    ledState = 0x01;
+//  }
+//  Wire.write(ledState);
+//  Wire.endTransmission();
+//
+  selectI2cChannels(I2C_CHANNEL_SDSC3);
+  Wire.beginTransmission(0x20);
+  Wire.write(0x13);
+  Wire.write(0x08);
+  Wire.endTransmission();
+  delay(100);
+
+//  selectI2cChannels(I2C_CHANNEL_SDSC0);
+//  Wire.beginTransmission(0x20);
+//  Wire.write(0x13);
+//  if (ledState == 0x01) {
+//    ledState = 0x00;
+//  } else {
+//    ledState = 0x01;
+//  }
+//  Wire.write(ledState);
+//  Wire.endTransmission();
+}
+
+void selectI2cChannels(int channels)
+{
+  Wire.beginTransmission(PCA9548ADDR);
+  Wire.write(channels);
+  Wire.endTransmission();
+}


AdaFruit base code

AdaFruit base code

error: pathspec 'LazIRTag.ino' did not match any file(s) known to git

--- LazIRTag.ino
+++ LazIRTag.ino
@@ -0,0 +1,103 @@
+/* Raw IR decoder sketch!
+This sketch/program uses the Arduno and a PNA4602 to
+decode IR received. This can be used to make a IR receiver
+(by looking for a particular code)
+or transmitter (by pulsing an IR LED at ~38KHz for the
+durations detected
+Code is public domain, check out www.ladyada.net and adafruit.com
+for more tutorials!
+*/
+
+// We need to use the 'raw' pin reading methods
+// because timing is very important here and the digitalRead()
+// procedure is slower!
+//uint8_t IRpin = 2;
+// Digital pin #2 is the same as Pin D2 see
+// http://arduino.cc/en/Hacking/PinMapping168 for the 'raw' pin mapping
+#define IRpin_PIN PIND
+#define IRpin 2
+// for MEGA use these!
+//#define IRpin_PIN PINE
+//#define IRpin 4
+
+// the maximum pulse we'll listen for - 65 milliseconds is a long time
+#define MAXPULSE 65000
+
+// what our timing resolution should be, larger is better
+// as its more 'precise' - but too large and you wont get
+// accurate timing
+#define RESOLUTION 20
+
+// we will store up to 100 pulse pairs (this is -a lot-)
+uint16_t pulses[100][2]; // pair is high and low pulse
+uint8_t currentpulse = 0; // index for pulses we're storing
+
+void setup(void) {
+  Serial.begin(9600);
+  Serial.println("Ready to decode IR!");
+}
+
+void loop(void) {
+  uint16_t highpulse, lowpulse; // temporary storage timing
+  highpulse = lowpulse = 0; // start out with no pulse length
+
+
+// while (digitalRead(IRpin)) { // this is too slow!
+    while (IRpin_PIN & (1 << IRpin)) {
+     // pin is still HIGH
+
+     // count off another few microseconds
+     highpulse++;
+     delayMicroseconds(RESOLUTION);
+
+     // If the pulse is too long, we 'timed out' - either nothing
+     // was received or the code is finished, so print what
+     // we've grabbed so far, and then reset
+     if ((highpulse >= MAXPULSE) && (currentpulse != 0)) {
+       printpulses();
+       currentpulse=0;
+       return;
+     }
+  }
+  // we didn't time out so lets stash the reading
+  pulses[currentpulse][0] = highpulse;
+
+  // same as above
+  while (! (IRpin_PIN & _BV(IRpin))) {
+     // pin is still LOW
+     lowpulse++;
+     delayMicroseconds(RESOLUTION);
+     if ((lowpulse >= MAXPULSE) && (currentpulse != 0)) {
+       printpulses();
+       currentpulse=0;
+       return;
+     }
+  }
+  pulses[currentpulse][1] = lowpulse;
+
+  // we read one high-low pulse successfully, continue!
+  currentpulse++;
+}
+void printpulses(void) {
+  Serial.println("\n\r\n\rReceived: \n\rOFF \tON");
+  for (uint8_t i = 0; i < currentpulse; i++) {
+    Serial.print(pulses[i][0] * RESOLUTION, DEC);
+    Serial.print(" usec, ");
+    Serial.print(pulses[i][1] * RESOLUTION, DEC);
+    Serial.println(" usec");
+  }
+
+  // print it in a 'array' format
+  Serial.println("int IRsignal[] = {");
+  Serial.println("// ON, OFF (in 10's of microseconds)");
+  for (uint8_t i = 0; i < currentpulse-1; i++) {
+    Serial.print("\t"); // tab
+    Serial.print(pulses[i][1] * RESOLUTION / 10, DEC);
+    Serial.print(", ");
+    Serial.print(pulses[i+1][0] * RESOLUTION / 10, DEC);
+    Serial.println(",");
+  }
+  Serial.print("\t"); // tab
+  Serial.print(pulses[currentpulse-1][1] * RESOLUTION / 10, DEC);
+  Serial.print(", 0};");
+}


Updating LED code for new layout

Updating LED code for new layout

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/rniemand/ArduinoProjects.git/'


Example Arduino Code to turn on/off LED via serial

Send commands to the Arduino via serial

error: pathspec 'ArduinoCode/serial_blink.ino' did not match any file(s) known to git

--- ArduinoCode/serial_blink.ino
+++ ArduinoCode/serial_blink.ino
@@ -0,0 +1,53 @@
+
+/*
+Serial Test
+*/
+String inString = ""; //string to hold input
+String TimeString = "";
+String CommandString = "";
+int timeInt = "";
+
+void setup() // initializes the sketch by defining variables and pin modes
+{
+  pinMode(LED_BUILTIN, OUTPUT); // set the built in LED to turn on and oFF
+  Serial.begin(9600);// sets the data rate for the serial monitor tool
+//  while (! Serial);
+//  Serial.println("Push Button or Type 'onA' or 'onB'");// Prints the phrase on serial monitor
+
+}
+
+void loop() //following information will not return information to the function that it was called
+{
+  //Serial monitor, send a command of the formate "00,000" where the first is a two digit number
+  //corresponding to some action the arduino should take, and the third is some additional information
+  // in the "01" example it is the length of time to keep the LED on for.
+  if(Serial.available()) { //gets the number of bytes available for reading from the serial port
+   inString = Serial.readString();//reads incoming data from the serial port sets it as a string
+   int commaIndex = inString.indexOf(','); //finds the delimiter postion
+   CommandString = inString.substring(0,commaIndex); //splits the string into the command
+   TimeString = inString.substring(commaIndex+1); //splits out the amount of time to stay on, if necessary
+   timeInt = TimeString.toInt(); //converts the time string into an integer
+   //Serial.print("Input:");
+   //Serial.println(inString);
+   //Serial.print("Command:");
+   //Serial.println(CommandString);
+   //Serial.print("Time:");
+   //Serial.println(timeInt);
+   if (CommandString == "00"){ //command "00" is simpily to turn on LED
+     digitalWrite(LED_BUILTIN, LOW);
+   }
+   if (CommandString == "01"){ //commands the LED to turn on for the amount time in seconds given in serial command
+                                //this is a lazy implementation of this though since the entire loop is delayed, it would
+                                //be better to implement it as a counter in the main loop and have it shut off after so many main loops
+     digitalWrite(LED_BUILTIN, HIGH);
+     delay(timeInt*1000); //delay in milliseconds
+     digitalWrite(LED_BUILTIN,LOW);
+   }
+   if (CommandString == "02"){ //turns the LED off
+    digitalWrite(LED_BUILTIN, HIGH);
+   }
+  }
+  //here you should be able to put in your other commands
+}
+
+


Test_code

Test_code

The code is from Bob. We want to figure out the mechanism of the motion
detector.

error: pathspec 'test' did not match any file(s) known to git
error: pathspec 'code' did not match any file(s) known to git
error: pathspec 'from' did not match any file(s) known to git
error: pathspec 'bob/main.ino' did not match any file(s) known to git


Added Arduino Code.

Added Arduino Code.

error: pathspec 'Arduino/IRTest/IRTest.ino' did not match any file(s) known to git

--- Arduino/IRTest/IRTest.ino
+++ Arduino/IRTest/IRTest.ino
@@ -0,0 +1,41 @@
+const int senRead = 0;
+int countC = 0, countB = 0;
+
+void setup()
+{
+    Serial.begin(9600);
+}
+
+void loop()
+{
+    //Serial.println("BLUETOOTH?");
+    if (analogRead(senRead) < 800)
+    {
+        if (countC <= 2)
+        {
+            countC++;
+        }
+        countB = 0;
+        if (countC == 2)
+        {
+            //Serial.print(String(millis())); Serial.print(" ");
+            Serial.println("1"); // Send 1 for IR detected
+        }
+    }
+    else if (analogRead(senRead >= 800))
+    {
+        if (countB <= 2)
+        {
+            countB++;
+        }
+        countC = 0;
+        if (countB == 2)
+        {
+            //Serial.print(String(millis())); Serial.print(" ");
+            Serial.println("0");
+        }
+    }
+
+    delay(1);
+}
+


Counter Sketch for fieldtest

Counter Sketch for fieldtest

error: pathspec 'theftprotection_counter.ino' did not match any file(s) known to git

--- theftprotection_counter.ino
+++ theftprotection_counter.ino
@@ -0,0 +1,116 @@
+/**
+Arduino GPS Client to retrieve the Location data from the GPS shield.
+The information are processed through the TinyGPS library and send via the Akeru
+**/
+
+#include <SoftwareSerial.h>
+#include <Akeru.h>
+#include <TinyGPS.h>
+
+// Counter
+int counter;
+
+TinyGPS gps;
+// Akeru uses RX=5, TX=4
+SoftwareSerial ssAkeru(5,4);
+SoftwareSerial ss(6,7);
+
+void setup()
+{
+  counter = 0;
+  Serial.begin(9600);
+  Serial.print("Finished setup\n");
+}
+
+typedef struct {
+  bool theftprotection;
+  float lat;
+  float lng;
+  int count;
+} Payload;
+
+void loop()
+{
+  bool newData = false;
+  unsigned long chars;
+  unsigned short sentences, failed;
+	Payload p;
+
+ ss.begin(9600);
+
+  // PARSE GPS data for one second and report some key values
+  for (unsigned long start = millis(); millis() - start < 1000;)
+  {
+    while (ss.available())
+    {
+      char c = ss.read();
+      //Serial.print(c); //uncomment to see the full NMEA datasets
+      if (gps.encode(c)) // Did a new valid sentence come in?
+        newData = true;
+    }
+  }
+  // end gps in order to make port listening for akeru available
+  ss.end();
+
+  if (newData)
+  {
+    // IF NEW GPS-DATA
+    float flat, flon;
+    unsigned long age;
+    gps.f_get_position(&flat, &flon, &age);
+    Serial.println("");
+    Serial.print("LAT = ");
+    Serial.println(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
+    Serial.print("LON = ");
+    Serial.println(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
+    newData = false;
+
+
+    p.theftprotection = true;
+    p.lat = flat;
+    p.lng = flon;
+    p.count = counter;
+
+
+    // INIT MODEM
+    Akeru.begin();
+    // Wait 1 second for the modem to warm up
+    delay(1000);
+
+    if(!Akeru.isReady()) {
+      Serial.println("Modem not ready");
+    } else {
+      Serial.println("Modem ready");
+
+      // CHECK IF LNG/LAT != 0
+      if(p.lat == 0 || p.lng == 0) {
+        Serial.println("Unknown position");
+      } else {
+        Serial.println("Message-Size: ");
+        Serial.println(sizeof(p));
+        Akeru.send(&p, sizeof(p));
+        Serial.println("Message sent!");
+        counter++;
+        delay(1000);
+      }
+
+    }
+    // end modem in order to make port listening for gps available
+    ssAkeru.end();
+  } else {
+
+    Serial.print("Theft-Protection: 1\n");
+    Serial.print("No GPS data\n");
+    Serial.print("LAT = 0.00000\n");
+    Serial.print("LON = 0.00000\n");
+    DHT.read11(dht_dpin);
+    Serial.print("Humidity = ");
+    Serial.print(DHT.humidity);
+    Serial.print("%  ");
+    Serial.print("temperature = ");
+    Serial.print(DHT.temperature);
+    Serial.println("C\n");
+
+    delay(1000);
+  }
+}


Added deletion of data.csv in init

Added deletion of data.csv in init

error: pathspec 'Sensors.ino' did not match any file(s) known to git

--- Sensors.ino
+++ Sensors.ino
@@ -0,0 +1,132 @@
+#include "Potentiometer.h"
+#include "HallEffect.h"
+#include "IMU.h"
+#include "SDHelper.h"
+
+/* hallEffect leftHall, rightHall; */
+potentiometer shockLeftPot, shockRightPot;
+LSM9DS1 imu;
+#define brakePressureFront A2
+
+//the hardware CS pin (10 on most Arduino boards,
+// 53 on the Mega) must be left as an output or the SD
+// library functions will not work.
+const int CSpin = 10;
+String dataString = ""; // holds the data to be written to the SD card
+float sensorReading1 = 0.00; // value read from your first sensor
+float sensorReading2 = 0.00; // value read from your second sensor
+float gyroX = 0.00; // value read from your third sensor
+float gyroY = 0.00;
+float gyroZ = 0.00;
+float accelX = 0.00;
+float accelY = 0.00;
+float accelZ = 0.00;
+
+#define PRINT_SPEED 250 // 250 ms between prints
+static unsigned long lastPrint = 0; // Keep track of print time
+
+float shockLeftPos, shockRightPos;
+float brakePressureFrontValue;
+
+void setup() {
+    Serial.begin(115200);
+
+    if (!initSD(CSpin)) {
+        Serial.println("Card error");
+        while(1);
+    }
+
+    /* rightHall.pinNum=3; */
+    /* leftHall.pinNum=4; */
+    /* pinMode(rightHall.pinNum,INPUT); */
+    /* pinMode(leftHall.pinNum,INPUT); */
+
+    shockLeftPot.pin = A0;
+    shockLeftPot.degrees = 360;
+    shockRightPot.pin = A1;
+    shockRightPot.degrees = 360;
+
+    Serial.println("Beginning IMU initialization.");
+    // Before initializing the IMU, there are a few settings
+    // we may need to adjust. Use the settings struct to set
+    // the device's communication mode and addresses:
+    imu.settings.device.commInterface = IMU_MODE_I2C;
+    imu.settings.device.mAddress = LSM9DS1_M;
+    imu.settings.device.agAddress = LSM9DS1_AG;
+    // The above lines will only take effect AFTER calling
+    // imu.begin(), which verifies communication with the IMU
+    // and turns it on.
+    if (!imu.begin())
+    {
+        Serial.println("Failed to communicate with LSM9DS1.");
+        Serial.println("Double-check wiring.");
+        Serial.println("Default settings in this sketch will " \
+                "work for an out of the box LSM9DS1 " \
+                "Breakout, but may need to be modified " \
+                "if the board jumpers are.");
+        while (1)
+            ;
+    }
+}
+
+// the loop routine runs over and over again forever:
+void loop() {
+    shockLeftPos  = refresh_RotaryPotentiometer(shockLeftPot);
+    shockRightPos = refresh_RotaryPotentiometer(shockRightPot);
+    brakePressureFrontValue = (analogRead(brakePressureFront)*5.0/1023.0-.5)/4*5000;
+
+    /* refresh_WheelSpeed(rightHall); */
+    refresh_IMU(imu);
+
+    if ((lastPrint + PRINT_SPEED) < millis())
+    {
+        gyroX = imu.calcGyro(imu.gx);
+        gyroY = imu.calcGyro(imu.gy);
+        gyroZ = imu.calcGyro(imu.gz);
+        //accel readings
+        accelX = imu.calcAccel(imu.ax);
+        accelY = imu.calcAccel(imu.ay);
+        accelZ = imu.calcAccel(imu.az);
+        lastPrint = millis(); // Update lastPrint time
+    }
+    // build the data string
+
+    //dataString = String(sensorReading1) + ",";
+    //dataString += String(sensorReading2) + ",";
+    dataString = String(gyroX) + ",";
+    dataString += String(gyroY) + ",";
+    dataString += String(gyroZ) + ",";
+    dataString += String(accelX) + ",";
+    dataString += String(accelY) + ",";
+    dataString += String(accelZ) + ","; // for IMU
+
+    dataString += String(shockLeftPos)   + ",";
+    dataString += String(shockRightPos)  + ",";
+    dataString += String(brakePressureFrontValue) + ",";
+
+    // Debug print statements
+    /*
+    Serial.print( "Left shock position: " );
+    Serial.println( shockLeftPos );
+    Serial.print( "Right shock position: " );
+    Serial.println( shockRightPos) ;
+    Serial.print( "Brake pressure value: " );
+    Serial.println( analogRead(brakePressureFront) );
+    */
+    Serial.print( "Gyro X: " );
+    Serial.println(gyroX);
+    Serial.print( "Gyro Y: " );
+    Serial.println(gyroY);
+    Serial.print( "Gyro Z: " );
+    Serial.println(gyroZ);
+    Serial.print( "Accel X: " );
+    Serial.println(accelX);
+    Serial.print( "Accel Y: " );
+    Serial.println(accelY);
+    Serial.print( "Accel Z: " );
+    Serial.println(accelZ);
+
+    //Serial.println ( brakePressureFrontValue );
+    // convert to CSV
+    saveData(dataString); // save to SD card
+}


Add constant speed tests as an example sketch #79

error: pathspec 'examples/UnitTest/UnitTest.ino' did not match any file(s) known to git

--- examples/UnitTest/UnitTest.ino
+++ examples/UnitTest/UnitTest.ino
@@ -0,0 +1,146 @@
+/*
+ * This is not an example sketch, it is used to validate code changes
+ * and determine maximum workable RPM/microsteps parameters for a given board.
+ *
+ * Usage: run with serial terminal open
+ *
+ * All driver tests are done with microstep 1. Increasing microstep halves max rpm with each level.
+ * The maximum usable RPM can be determined from the output.
+ * The max RPM at a different microstep can be calculated with formula "max rpm / microstep"
+ *
+ * Copyright (C)2020 Laurentiu Badea
+ *
+ * This file may be redistributed under the terms of the MIT license.
+ * A copy of this license has been included with this distribution in the file LICENSE.
+ */
+#include <Arduino.h>
+
+#include "BasicStepperDriver.h"
+#include "MultiDriver.h"
+#include "SyncDriver.h"
+
+// RPMS contains the list of RPMS to test at, assuming microstep=1
+const float RPMS[] = {60, 0.5, 1, 10, 100, 200, 300, 600, 1200, 2400, 4800, 9600};
+const int RPMS_COUNT = sizeof(RPMS)/sizeof(*RPMS);
+// STEPS is how many steps for each test. More has better accuracy but slower
+#define STEPS 20
+// ALLOWED_DEVIATION is the error tolerance. 0.10 considers 90% - 110% range aceptable
+#define ALLOWED_DEVIATION 0.10
+
+/*
+ * Verify that the expected time calculation is correct at different rpms and two microstep levels
+ */
+bool test_calculations(BasicStepperDriver stepper){
+    bool pass = true;
+    char t[128];
+    for (int i = 0; i < RPMS_COUNT; i++){
+        float rpm = RPMS[i];
+        for (int microstep = 1; microstep <= 16; microstep <<= 4){
+            long expected_micros = long(1000000.0f * 60.0f / rpm);
+            stepper.begin(rpm, microstep);
+            long estimated_micros = stepper.getTimeForMove(200*microstep);
+            sprintf(t, "rpm=%-3d expected=%9uµs estimated %9uµs",
+                    int(rpm), expected_micros, estimated_micros);
+            Serial.println(t);
+            if (estimated_micros != expected_micros) {
+                pass = false;
+            }
+        }
+    }
+    return pass;
+}
+
+/*
+ * Pass/fail the result and print it out in a one-line format
+ */
+bool result(float rpm, int microstep, int steps, long elapsed_micros, long expected_micros){
+    bool pass = true;
+    char t[128];
+    float error = (float(elapsed_micros) - float(expected_micros)) / float(expected_micros);
+    unsigned step_micros = expected_micros / steps;
+    unsigned error_micros = abs(elapsed_micros - expected_micros) / steps;
+    sprintf(t, "microstep=%-3d rpm=%-3d expected=%9uµs elapsed=%9uµs step_err=%4dµs step=%6dµs",
+            microstep, int(rpm), expected_micros, elapsed_micros, error_micros, step_micros);
+    Serial.print(t);
+    if (error >= ALLOWED_DEVIATION || error <= -ALLOWED_DEVIATION) {
+        pass = false;
+        Serial.print(" FAIL");
+    }
+    Serial.println();
+    return pass;
+}
+
+/*
+ * Run the tests for BasicStepperDriver
+ */
+bool test_basic(BasicStepperDriver stepper){
+    bool pass = true;
+    for (int i = 0; i < RPMS_COUNT; i++){
+        float rpm = RPMS[i];
+        stepper.begin(rpm, 1);
+        unsigned long start_time_micros = micros();
+        stepper.move(STEPS);
+        long elapsed_micros = micros() - start_time_micros;
+        pass &= result(rpm, 1, STEPS, elapsed_micros, stepper.getTimeForMove(STEPS));
+    }
+    return pass;
+}
+
+/*
+ * Run the tests for MultiDriver with 3 motors
+ */
+bool test_multi(BasicStepperDriver s1, BasicStepperDriver s2, BasicStepperDriver s3){
+    MultiDriver controller(s1, s2, s3);
+    bool pass = true;
+    for (int i = 0; i < RPMS_COUNT; i++){
+        float rpm = RPMS[i];
+        s1.begin(rpm, 1);
+        s2.begin(rpm, 1);
+        s3.begin(rpm, 1);
+        unsigned long start_time_micros = micros();
+        controller.move(STEPS, 2*STEPS/3, -STEPS/2);
+        long elapsed_micros = micros() - start_time_micros;
+        pass &= result(rpm, 1, STEPS, elapsed_micros, s1.getTimeForMove(STEPS));
+    }
+    return pass;
+}
+
+/*
+ * Run the tests for SyncDriver with 3 motors
+ */
+bool test_sync(BasicStepperDriver s1, BasicStepperDriver s2, BasicStepperDriver s3){
+    SyncDriver controller(s1, s2, s3);
+    bool pass = true;
+    for (int i = 0; i < RPMS_COUNT; i++){
+        float rpm = RPMS[i];
+        s1.begin(rpm, 1);
+        s2.begin(rpm, 1);
+        s3.begin(rpm, 1);
+        unsigned long start_time_micros = micros();
+        controller.move(STEPS, 2*STEPS/3, -STEPS/2);
+        long elapsed_micros = micros() - start_time_micros;
+        pass &= result(rpm, 1, STEPS, elapsed_micros, s1.getTimeForMove(STEPS));
+    }
+    return pass;
+}
+
+#define TEST_RESULT(result, func, ...) #func "(" #__VA_ARGS__ "): " result
+#define RUN_TEST(desc, func, ...) Serial.println(desc); Serial.println(func(__VA_ARGS__) ? TEST_RESULT("OK", func, __VA_ARGS__) : TEST_RESULT("FAIL", func, __VA_ARGS__))
+
+void setup() {
+
+    BasicStepperDriver s1(200, 12, 13);
+    BasicStepperDriver s2(200, 12, 13);
+    BasicStepperDriver s3(200, 12, 13);
+
+    Serial.begin(1000000);
+    delay(2000);
+    RUN_TEST("Timing Calculation test", test_calculations, s1);
+    RUN_TEST("BasicStepperDriver test", test_basic, s1);
+    RUN_TEST("MultiDriver test", test_multi, s1, s2, s3);
+    RUN_TEST("SyncDriver test", test_sync, s1, s2, s3);
+}
+
+void loop() {
+    delay(1);
+}


Added Temperature sensor code

Added Temperature sensor code

error: pathspec 'Prototypes/A7' did not match any file(s) known to git
error: pathspec 'Test/A7_Test/A7_Test.ino' did not match any file(s) known to git


Combined the mapSnake function and the globalSnake function, also deleted some redundant things

error: pathspec 'Arduino' did not match any file(s) known to git
error: pathspec 'code/Snake/Snake.ino' did not match any file(s) known to git