more sleep option

more sleep option

1) remove WiFi.disconnect()
2) add system_deep_sleep_set_option(2)
3) add wifi_set_phy_mode(PHY_MODE_11N)
4) remove DEBUG_PRINT

--- _15-esp8266-dash-deepsleep-reset/_15-esp8266-dash-deepsleep-reset.ino
+++ _15-esp8266-dash-deepsleep-reset/_15-esp8266-dash-deepsleep-reset.ino
@@ -8,8 +8,8 @@

 ADC_MODE(ADC_VCC);

-#define DEBUG_PRINT 1
-#define EVENT_PRINT 1
+#define DEBUG_PRINT 0
+#define EVENT_PRINT 0

 #define resetupPin  16
 #define blueLED     5
@@ -40,6 +40,8 @@

 void callback(char* intopic, byte* inpayload, unsigned int length)
 {
+  digitalWrite(greenLED, HIGH);
+
   String receivedtopic = intopic;
   String receivedpayload ;

@@ -68,6 +70,8 @@
   }

   subMsgReceived = HIGH;
+  digitalWrite(greenLED, LOW);
+

 }

@@ -162,6 +166,10 @@
     Serial.begin(115200);
   }

+  system_deep_sleep_set_option(2);
+  wifi_set_phy_mode(PHY_MODE_11N);
+
+  digitalWrite(redLED, LOW);
   wifi_connect();

   clientName += "esp8266-";
@@ -182,12 +190,11 @@
     Serial.print("ResetInfo : ");
     Serial.println(getResetInfo);
   }
-  delay(50);
-  digitalWrite(redLED, LOW);
 }

 void loop()
 {
+  digitalWrite(greenLED, HIGH);
   if (WiFi.status() == WL_CONNECTED) {
     if (!client.connected()) {
       long now = millis();
@@ -226,15 +233,16 @@
   buttonpayload += vdd;
   buttonpayload += "}";

-  digitalWrite(greenLED, HIGH);
+  digitalWrite(greenLED, LOW);

   if (sendmqttMsg(buttontopic, buttonpayload)) {
+    digitalWrite(greenLED, HIGH);
     if (sendmqttMsg(topic, lightpayload)) {
       topicMsgSent = HIGH;
       digitalWrite(greenLED, LOW);
     }
   }
-  digitalWrite(greenLED, LOW);
+  digitalWrite(greenLED, HIGH);
 }

 boolean sendmqttMsg(char* topictosend, String payload)
@@ -275,9 +283,7 @@
 void goingToSleep()
 {
   client.disconnect();
-  WiFi.disconnect();
-  digitalWrite(greenLED, HIGH);
-  delay(100);
+  //WiFi.disconnect();
   digitalWrite(greenLED, LOW);
   digitalWrite(blueLED, LOW);
   digitalWrite(redLED, LOW);


Cleaning code.

Cleaning code.

--- scadacar_sketch/scadacar_sketch.ino
+++ scadacar_sketch/scadacar_sketch.ino
@@ -23,7 +23,7 @@
 SoftwareSerial ss(RXPin, TXPin);

 int readCount = 0;
-int delayTime = 10; // delay time (in seconds) between messages.
+int gpsDelayTime = 10; // delay time (in seconds) between messages.

 SoftwareSerial obd(8,7);
 // Mode 1 PIDs
@@ -155,24 +155,25 @@

 void readGPS()
 {
-
-  // This sketch displays information every time a new sentence is correctly encoded.
-  if (ss.available() > 0) {
-    // delay(1000); // wait 1 sec to give time enough for the serial to receive all the stream
-    while (gps.encode(ss.read())) {
-      if(debug == true) {Serial.println("reading GPS...");}
-      displayGPSLog();
-    }
-  } else {
-    if(debug == true) {Serial.println("nothing from GPS.");}
-  }
-  ss.flush();
-
-  if (millis() > 5000 && gps.charsProcessed() < 10)
-  {
-    if(debug == true) {Serial.println("No GPS detected: check wiring.");}
-    //Serial.println(F("No GPS detected: check wiring."));
-    // while(true);
+  // This will execute the reading GPS function when we want suposing that
+  // each second it reads the TinyGPS
+  if(readCount++ % gpsDelayTime == 0) {
+    // This sketch displays information every time a new sentence is correctly encoded.
+    if (ss.available() > 0) {
+      // delay(1000); // wait 1 sec to give time enough for the serial to receive all the stream
+      while (gps.encode(ss.read())) {
+        if(debug == true) {Serial.println("reading GPS...");}
+        displayGPSLog();
+      }
+    } else {
+      if(debug == true) {Serial.println("nothing from GPS.");}
+    }
+    ss.flush();
+
+    if (millis() > 5000 && gps.charsProcessed() < 10)
+    {
+      if(debug == true) {Serial.println("No GPS detected: check wiring.");}
+    }
   }
 }

@@ -181,26 +182,15 @@
   String strValue;
   char charBuf[15];
   if ( gps.location.isValid() ) {
-    // This function is thanks to http://dereenigne.org/arduino/arduino-float-to-string
+    /* This function is thanks to http://dereenigne.org/arduino/arduino-float-to-string */
     dtostrf(gps.location.lat(), 12, 6, charBuf);
     strValue += charBuf;
-    // Serial.print(strValue);
     strValue += ",";
-    // Serial.print(F(","));
     dtostrf(gps.location.lng(), 12, 6, charBuf);
     strValue += charBuf;
-    // Serial.print(charBuf);
   }
   else {
-    // Serial.print(F("INVALID"));
     strValue += "INVALID";
-  }
-
-  // Serial.println();
-  // This will execute the sending message function when we want suposing that
-  // each second it reads the TinyGPS
-  if(readCount++ % delayTime == 0) {
-    sendMaster(strValue);
   }
 }


renamed file to match project

renamed file to match project

--- arduino-singing-in-the-rain.ino
+++ arduino-singing-in-the-rain.ino
@@ -1,50 +0,0 @@
-/*
-  Melody
-
- Plays a melody
-
- circuit:
- * 8-ohm speaker on digital pin 8
-
- http://arduino.cc/en/Tutorial/Tone
-
- */
-#include "pitches.h"
-
-struct note {
-  int pitch;
-  float duration;
-};
-
-struct note melody[] = {
-  {NOTE_D4, 0.5},
-  {NOTE_D4, 0.25},
-  {NOTE_D4, 0.5}
-};
-
-void setup() {
-  Serial.begin(9600);
-  buzzerSound();
-}
-
-void loop() {
-  // no need to repeat the melody.
-}
-
-void buzzerSound() {
-  Serial.println(sizeof(melody));
-  Serial.println(sizeof(melody[0]));
-  for (int thisNote = 0; thisNote < sizeof(melody)/sizeof(melody[0]); thisNote++) {
-    int noteDuration = 1000 * melody[thisNote].duration;
-    Serial.println(melody[thisNote].duration);
-    Serial.println(melody[thisNote].duration);
-    tone(2, melody[thisNote].pitch, noteDuration);
-
-    // to distinguish the notes, set a minimum time between them.
-    // the note's duration + 30% seems to work well:
-    int pauseBetweenNotes = noteDuration * 1.30;
-    delay(pauseBetweenNotes);
-    // stop the tone playing:
-    // noTone(2);
-  }
-}


Suppress barometer to be able to upload

Suppress barometer to be able to upload

--- Arduino/Attitude_Altitude/Attitude_Altitude.ino
+++ Arduino/Attitude_Altitude/Attitude_Altitude.ino
@@ -8,7 +8,7 @@
 #include "I2Cdev.h"
 #include "MPU6050_6Axis_MotionApps20.h"
 #include "HMC5883L.h"
-#include "MS561101BA.h"
+//#include "MS561101BA.h"
 #include "Wire.h"

 #include <MsTimer2.h>
@@ -24,7 +24,7 @@
 // this device only supports one I2C address (0x1E)
 HMC5883L mag;
 MPU6050 mpu(0x69); // <-- use for AD0 high
-MS561101BA baro = MS561101BA();
+//MS561101BA baro = MS561101BA();

 // uncomment "OUTPUT_READABLE_YAWPITCHROLL" if you want to see the yaw/
 // pitch/roll angles (in degrees) calculated from the quaternions coming
@@ -125,12 +125,12 @@
     Serial.println(F("Initializing Barometer..."));
     // Suppose that the CSB pin is connected to GND.
     // You'll have to check this on your breakout schematics
-    baro.init(MS561101BA_ADDR_CSB_LOW);
+//    baro.init(MS561101BA_ADDR_CSB_LOW);
     delay(100);

     // populate movavg_buff before starting loop
     for(int i=0; i<MOVAVG_SIZE; i++) {
-    movavg_buff[i] = baro.getPressure(MS561101BA_OSR_4096);
+    //movavg_buff[i] = baro.getPressure(MS561101BA_OSR_4096);
     }

     // initialize device
@@ -217,7 +217,7 @@
           heading += 2 * M_PI;

         // other program behavior stuff here
-        float temperature = baro.getTemperature(MS561101BA_OSR_4096);
+        /*float temperature = baro.getTemperature(MS561101BA_OSR_4096);
         if(temperature) { temp = temperature;   }
         attitude.t = temp*100;
         //Serial.print(" temp: "); Serial.print(temp);
@@ -231,7 +231,7 @@
         float altitude = getAltitude(press, temp);
         attitude.h = altitude;
         //Serial.print(" mbar altitude: "); Serial.print(altitude); Serial.println(" m");
-
+        */
         if (millis() > last_time +UPDATE_RATE)
          { sendData();
            last_time = millis();


Improved power consumption by supplying temp sensor via output pin; cleaned up some code

--- firmware/src/PoolBuddy.ino
+++ firmware/src/PoolBuddy.ino
@@ -1,7 +1,8 @@
 #include "DS18B20.h"
 #include "SparkFunMAX17043.h"

-#define TEMP_SENSOR D6
+#define POWER D6
+#define TEMP_SENSOR D5
 #define PH_ADDRESS 99
 #define ORP_ADDRESS 98
 #define SAMPLE_INTERVAL 2500
@@ -20,10 +21,12 @@
 int wifi;

 void setup() {
-  Serial.begin(9600);
+  //Serial.begin(9600);
   if (!Wire.isEnabled())
     Wire.begin();
+  pinMode(POWER,OUTPUT);
   pinMode(TEMP_SENSOR, INPUT);
+  digitalWrite(POWER, HIGH);

   lipo.begin();
   lipo.quickStart();
@@ -54,13 +57,14 @@
     Particle.publish("waterdata", water_data(), PRIVATE);
     if(soc <= 10)
       sleepInterval = 60 * 15;
-    else if(soc <= 10)
+    else if(soc <= 20)
       sleepInterval = 60 * 10;
     else
       sleepInterval = 60 * 5;
     nextSleepTime = millis() + (sleepInterval * 1000) + WAKE_INTERVAL;
     executeRequest(PH_ADDRESS,"Sleep");
     executeRequest(ORP_ADDRESS,"Sleep");
+    digitalWrite(POWER, LOW);
     System.sleep(SLEEP_MODE_DEEP,sleepInterval);
   }
 }
@@ -109,8 +113,10 @@
 }

 int check_calibrated(String args) {
-  executeRequest(PH_ADDRESS,"Cal,?");
-  executeRequest(ORP_ADDRESS,"Cal,?");
+  //Serial.println(executeRequest(PH_ADDRESS,"Cal,?"));
+  //Serial.println(executeRequest(PH_ADDRESS,"Status"));
+  //Serial.println(executeRequest(ORP_ADDRESS,"Cal,?"));
+  //Serial.println(executeRequest(ORP_ADDRESS,"Status"));
   return 0;
 }

@@ -153,20 +159,24 @@
   else
     delay(300);
   Wire.requestFrom(address, 20);
-  switch (Wire.read()) {
+  int val=Wire.read();
+  switch (val) {
     case 1:
-      Serial.println("Success");
+      //Serial.println("Success");
       break;
     case 2:
-      Serial.println("Failed");
+      //Serial.println("Failed");
       return String("Failed");
       break;
     case 254:
-      Serial.println("Pending");
+      //Serial.println("Pending");
       break;
     case 255:
-      Serial.println("No Data");
+      //Serial.println("No Data");
       break;
+    default:
+      //Serial.printlnf("Invalid response %d",val);
+      return String("Failed");
   }

   while(Wire.available()) {


Correct sendNEC example.

Correct sendNEC example.

NEC IR codes are not 36 bits long, they are 32 bits.
Make sure its an unsigned long too.

--- examples/IRsendDemo/IRsendDemo.ino
+++ examples/IRsendDemo/IRsendDemo.ino
@@ -17,7 +17,7 @@

 void loop() {
   Serial.println("NEC");
-  irsend.sendNEC(0x00FFE01F, 36);
+  irsend.sendNEC(0x00FFE01FUL, 32);
   delay(2000);
   Serial.println("Sony");
   irsend.sendSony(0xa90, 12);


add 'flicker()' function to emulate candle

add flicker function to emulate candle as alternative to 'gradual()'

--- chuckolantern/chuckolantern.ino
+++ chuckolantern/chuckolantern.ino
@@ -106,6 +106,45 @@
     }

 }
+
+void flicker()
+{
+    // try to flicker like a candle...
+    int baseColor = 6; //between 0 and 63
+    int flickerLength = 10; //length of flicker in MS
+    if(random(100) > 85)
+    {
+      for(x=0;x<8;x++)
+      {
+        for(y=0;y<8;y++)
+        {
+          //Paint random colors
+          //Rb.setPixelZXY(z,x,y,RED[i],GREEN[i],BLUE[i]); //uses R, G and B color bytes
+          Rb.setPixelXY(x,y,0,0,0); //uses R, G and B color bytes
+        }
+      }
+      delay(random(flickerLength));
+    }
+    else
+    {
+      int offset = random(6); //how much to randomize color
+      for(x=0;x<8;x++)
+      {
+        for(y=0;y<8;y++)
+        {
+          //Paint random colors
+          //Rb.setPixelZXY(z,x,y,RED[i],GREEN[i],BLUE[i]); //uses R, G and B color bytes
+          Rb.setPixelXY(x,y,RED[baseColor + offset],GREEN[baseColor + offset],BLUE[baseColor + offset]); //uses R, G and B color bytes
+
+        }
+      }
+      delay(random(400)); //how long to delay before checking for another flicker...
+      motionSense = digitalRead(motionPin);
+      if(motionSense == 1)
+        return;
+    }
+
+}
 void loop()
 {
    if (motionSense == 1)
@@ -113,5 +152,6 @@
     stutter(); //or do -
     // fast();
    }
-   else gradual();
+   else flicker(); // or do -
+   //   gradual();
 }


Remake of the System example.

Remake of the System example.

--- examples/system_menu/system_menu.ino
+++ examples/system_menu/system_menu.ino
@@ -1,15 +1,53 @@
+/*
+ * LiquidMenu library - system_menu.ino
+ *
+ * This example demonstrates the how to build a menu system.
+ *
+ * Menu system is a collection of menus. To build a menu system
+ * you need put the menus into an object of class LiquidSystem.
+ * The methods used on LiquidMenu should now be called directly
+ * on the LiquidSystem object. To switch between menus use the
+ * bool LiquidSystem::change_menu(LiquidMenu &p_liquidMenu) method.
+ * This method can be wrapped inside a callback function and called
+ * on through the menu. This example also uses EEPROM to save the
+ * state of the LED and reading period.
+ *
+ *
+ * The circuit:
+ * https://github.com/VasilKalchev/LiquidMenu/blob/master/examples/system_menu/system_menu.png
+ * - LCD RS pin to Arduino pin 12
+ * - LCD E pin to Arduino pin 11
+ * - LCD D4 pin to Arduino pin 5
+ * - LCD D5 pin to Arduino pin 4
+ * - LCD D6 pin to Arduino pin 3
+ * - LCD D7 pin to Arduino pin 2
+ * - LCD R/W pin to ground
+ * - LCD VSS pin to ground
+ * - LCD VCC pin to 5V
+ * - 10k ohm potentiometer: ends to 5V and ground, wiper to LCD V0
+ * - 150 ohm resistor from 5V to LCD Anode
+ * - LCD Cathode to ground
+ * - ----
+ * - Button (left) to Arduino pin A0 and ground
+ * - Button (right) to Arduino pin 7 and ground
+ * - Button (up) to Arduino pin 8 and ground
+ * - Button (down) to Arduino pin 9 and ground
+ * - Button (enter) to Arduino pin 10 and ground
+ * - A PWM controlled device (LED...) to Arduino pin 6
+ * - some analog input to Arduino pin A4 (unconnected also works)
+ * - some analog input to Arduino pin A5 (unconnected also works)
+ *
+ * Created July 24, 2016
+ * by Vasil Kalchev
+ *
+ * https://github.com/VasilKalchev/LiquidMenu
+ *
+ */
+
 #include <LiquidCrystal.h>
 #include <LiquidMenu.h>
 #include <EEPROM.h>
 #include "Button.h"
-
-// An array holding linearized 8bit PWM values.
-const uint8_t log_8bit[11] PROGMEM = {0, 1, 2, 3, 6, 12, 22, 40, 74, 138, 255};
-
-// PWM function using the above array.
-void PWM_log(uint8_t pin, uint8_t level) {
-	analogWrite(pin, pgm_read_byte_near(log_8bit + level));
-}

 // Pin mapping for the display
 const byte LCD_RS = 12;
@@ -24,78 +62,73 @@

 // Button objects instantiation
 const bool pullup = true;
-Button left(4, pullup);
-Button right(5, pullup);
-Button up(6, pullup);
-Button down(12, pullup);
-Button enter(8, pullup);
+Button left(A0, pullup);
+Button right(7, pullup);
+Button up(8, pullup);
+Button down(9, pullup);
+Button enter(10, pullup);

 // Pin definitions and variables for their state.
-const byte pin9 = 9;
-byte pin9_level = 0;
-
-const byte pin10 = 10;
-byte pin10_level = 0;
-
-const byte pinA1 = A4;
-byte pinA1_value = 0;
-
-const byte pinA2 = A5;
-byte pinA2_value = 0;
+const byte pin6 = 6;
+byte pin6_level = 0;
+
+const byte pinA4 = A4;
+byte pinA4_value = 0;
+
+const byte pinA5 = A5;
+byte pinA5_value = 0;

 // The analog reading sample period in seconds.
 // It is later overwritten by it's EEPROM value.
 unsigned short sample_period = 2;

-// Text used for indication for the save line.
-char* saved_text;
+// Text used for indication for the save lines.
+char* input_saved;
+char* output_saved;

 enum FunctionTypes {
-	increase = 1,
-	decrease = 2,
+  increase = 1,
+  decrease = 2,
 };

 // A LiquidLine object can be used more that once.
-LiquidLine back_line(11, 1, "-BACK");
+LiquidLine back_line(11, 1, "/BACK");

 LiquidLine welcome_line1(1, 0, "LiquidMenu ", VERSION);
 LiquidLine welcome_line2(1, 1, "System example");
 LiquidScreen welcome_screen(welcome_line1, welcome_line2);

-LiquidLine mm_line(3, 0, "Main menu");
-LiquidScreen mm_screen(mm_line);
-
 // These lines direct to other menus.
-LiquidLine outputs_line(0, 0, "-Outputs");
-LiquidLine inputs_line(0, 1, "-Inputs");
+LiquidLine outputs_line(0, 0, "/Outputs");
+LiquidLine inputs_line(0, 1, "/Inputs");
 LiquidScreen io_screen(outputs_line, inputs_line);

 // This is the first menu.
-LiquidMenu main_menu(lcd, welcome_screen, mm_screen, io_screen, 1);
-
-
-LiquidLine pin9_line(0, 0, "Pin 9: ", pin9_level);
-LiquidLine pin10_line(0, 1, "Pin 10: ", pin10_level);
-LiquidScreen pins9_10_screen(pin9_line, pin10_line);
-
-LiquidLine oSave_line(0, 0, "Save values", saved_text);
+LiquidMenu main_menu(lcd, welcome_screen, io_screen, 1);
+
+
+LiquidLine pin6_line(0, 0, "Pin 6: ", pin6_level);
+LiquidScreen pin6_screen(pin6_line);
+
+LiquidLine oSave_line(0, 0, "Save", output_saved);
 LiquidScreen oSecondary_screen(oSave_line, back_line);

-// This is a second menu object.
-LiquidMenu outputs_menu(lcd, pins9_10_screen, oSecondary_screen);
-
-
-LiquidLine pinA1_line(0, 0, "Pin A4: ", pinA1_value);
-LiquidLine pinA2_line(0, 1, "Pin A5: ", pinA2_value);
-LiquidScreen pinsA1_A2_screen(pinA1_line, pinA2_line);
+// This is the second menu.
+LiquidMenu outputs_menu(lcd, pin6_screen, oSecondary_screen);
+
+
+LiquidLine pinA4_line(0, 0, "Pin A4: ", pinA4_value);
+LiquidLine pinA5_line(0, 1, "Pin A5: ", pinA5_value);
+LiquidScreen pinsA4_A5_screen(pinA4_line, pinA5_line);

 LiquidLine iSample_line(0, 0, "Sample: ", sample_period, "s");
-LiquidScreen iSecondary_screen(iSample_line, back_line);
-
-// And this is the final third menu object.
-LiquidMenu inputs_menu(lcd, pinsA1_A2_screen, iSecondary_screen);
+LiquidLine iSave_line(0, 1, "Save", input_saved);
+LiquidScreen iSecondary_screen(iSample_line, iSave_line, back_line);
+
+// And this is the final third menu.
+LiquidMenu inputs_menu(lcd, pinsA4_A5_screen, iSecondary_screen);

 /*
  * LiquidSystem object combines the LiquidMenu objects to form
@@ -107,143 +140,128 @@

 // Checks all the buttons.
 void buttonsCheck() {
-	if (right.check() == LOW) {
-		menu_system.next_screen();
-	}
-	if (left.check() == LOW) {
-		menu_system.previous_screen();
-	}
-	if (up.check() == LOW) {
-		menu_system.call_function(increase);
-	}
-	if (down.check() == LOW) {
-		menu_system.call_function(decrease);
-	}
-	if (enter.check() == LOW) {
-		menu_system.switch_focus();
-	}
+  if (right.check() == LOW) {
+    menu_system.next_screen();
+  }
+  if (left.check() == LOW) {
+    menu_system.previous_screen();
+  }
+  if (up.check() == LOW) {
+    menu_system.call_function(increase);
+  }
+  if (down.check() == LOW) {
+    menu_system.call_function(decrease);
+  }
+  if (enter.check() == LOW) {
+    menu_system.switch_focus();
+  }
 }

 // Callback function that will be attached to back_line.
 void go_back() {
-	// This function takes reference to the wanted menu.
-	menu_system.change_menu(main_menu);
+  // This function takes reference to the wanted menu.
+  menu_system.change_menu(main_menu);
 }

 void goto_outputs_menu() {
-	menu_system.change_menu(outputs_menu);
+  menu_system.change_menu(outputs_menu);
 }

 void goto_inputs_menu() {
-	menu_system.change_menu(inputs_menu);
-}
-
-void increase_pin9() {
-	if (pin9_level < 10) {
-		pin9_level++;
-	} else {
-		pin9_level = 0;
-	}
-	PWM_log(pin9, pin9_level);
-	saved_text = (char*)"  ";
-}
-
-void decrease_pin9() {
-	if (pin9_level > 0) {
-		pin9_level--;
-	} else {
-		pin9_level = 10;
-	}
-	PWM_log(pin9, pin9_level);
-	saved_text = (char*)"  ";
-}
-
-void increase_pin10() {
-	if (pin10_level < 10) {
-		pin10_level++;
-	} else {
-		pin10_level = 0;
-	}
-	PWM_log(pin10, pin10_level);
-	saved_text = (char*)"  ";
-}
-
-void decrease_pin10() {
-	if (pin10_level > 1) {
-		pin10_level--;
-	} else {
-		pin10_level = 10;
-	}
-	PWM_log(pin10, pin10_level);
-	saved_text = (char*)"  ";
-}
-
-void save_state() {
-	EEPROM.put(9, pin9_level);
-	EEPROM.put(10, pin10_level);
-	EEPROM.put(11, sample_period);
-	saved_text = (char*)" *";
+  menu_system.change_menu(inputs_menu);
+}
+
+void increase_pin6() {
+  if (pin6_level < 225) {
+    pin6_level += 25;
+  } else {
+    pin6_level = 250;
+  }
+  analogWrite(pin6, pin6_level);
+  output_saved = (char*)"  ";
+}
+
+void decrease_pin6() {
+  if (pin6_level > 25) {
+    pin6_level -= 25;
+  } else {
+    pin6_level = 0;
+  }
+  analogWrite(pin6, pin6_level);
+  output_saved = (char*)"  ";
+}
+
+void save_input() {
+  EEPROM.put(11, sample_period);
+  input_saved = (char*)" *";
+}
+
+void save_output() {
+  EEPROM.put(9, pin6_level);
+  output_saved = (char*)" *";
 }

 void increase_samplePeriod() {
-	if (sample_period < 10) {
-		sample_period++;
-	saved_text = (char*)"  ";
-	}
+  if (sample_period < 10) {
+    sample_period++;
+    input_saved = (char*)"  ";
+  }
 }

 void decrease_samplePeriod() {
-	if (sample_period > 0) {
-		sample_period--;
-	saved_text = (char*)"  ";
-	}
+  if (sample_period > 0) {
+    sample_period--;
+    input_saved = (char*)"  ";
+  }
 }

 void setup() {
-	Serial.begin(250000);
-
-	pinMode(pin9, OUTPUT);
-	pinMode(pin10, OUTPUT);
-
-    // Reads the values recorded in the EEPROM
-	EEPROM.get(9, pin9_level);
-	EEPROM.get(10, pin10_level);
-	EEPROM.get(11, sample_period);
-	PWM_log(pin9, pin9_level);
-	PWM_log(pin10, pin10_level);
-
-	lcd.begin(16, 2);
-
-	back_line.set_focusPosition(Position::LEFT);
-
-	back_line.attach_function(1, go_back);
-
-	outputs_line.attach_function(1, goto_outputs_menu);
-	outputs_line.attach_function(2, goto_outputs_menu);
-	inputs_line.attach_function(1, goto_inputs_menu);
-	inputs_line.attach_function(2, goto_inputs_menu);
-
-	pin9_line.attach_function(increase, increase_pin9);
-	pin9_line.attach_function(decrease, decrease_pin9);
-	pin10_line.attach_function(increase, increase_pin10);
-	pin10_line.attach_function(decrease, decrease_pin10);
-
-	oSave_line.attach_function(1, save_state);
-	iSample_line.attach_function(increase, increase_samplePeriod);
-	iSample_line.attach_function(decrease, decrease_samplePeriod);
-
-	menu_system.update();
+  Serial.begin(250000);
+
+  pinMode(pin6, OUTPUT);
+
+  // Reads the values recorded in the EEPROM
+  EEPROM.get(9, pin6_level);
+  EEPROM.get(11, sample_period);
+  analogWrite(pin6, pin6_level);
+
+  lcd.begin(16, 2);
+
+  back_line.set_focusPosition(Position::LEFT);
+
+  back_line.attach_function(1, go_back);
+  back_line.attach_function(2, go_back);
+
+  outputs_line.attach_function(1, goto_outputs_menu);
+  outputs_line.attach_function(2, goto_outputs_menu);
+  inputs_line.attach_function(1, goto_inputs_menu);
+  inputs_line.attach_function(2, goto_inputs_menu);
+
+  pin6_line.attach_function(increase, increase_pin6);
+  pin6_line.attach_function(decrease, decrease_pin6);
+
+  oSave_line.attach_function(1, save_output);
+  oSave_line.attach_function(2, save_output);
+  iSave_line.attach_function(1, save_input);
+  iSave_line.attach_function(2, save_input);
+  iSample_line.attach_function(increase, increase_samplePeriod);
+  iSample_line.attach_function(decrease, decrease_samplePeriod);
+
+  input_saved = (char*)" *";
+  output_saved = (char*)" *";
+
+  menu_system.update();
 }

 void loop() {
-	buttonsCheck();
-
-	static unsigned long lastMillis_sample = 0;
-	if (millis() - lastMillis_sample > (sample_period * 1000)) {
-		lastMillis_sample = millis();
-		pinA1_value = analogRead(pinA1);
-		pinA2_value = analogRead(pinA2);
-		menu_system.update();
-	}
-
-}
+  buttonsCheck();
+
+  static unsigned long lastMillis_sample = 0;
+  if (millis() - lastMillis_sample > (sample_period * 1000)) {
+    lastMillis_sample = millis();
+    pinA4_value = analogRead(pinA4);
+    pinA5_value = analogRead(pinA5);
+    menu_system.update();
+  }
+
+}


sketch file using new rbc implementation details

--- firmware/examples/ble-mesh-cloud.ino
+++ firmware/examples/ble-mesh-cloud.ino
@@ -26,6 +26,7 @@
 #include "nrf8001-ble-uart-spark-io/boards.h"

 #include "nrf8001-ble-uart-spark-io/rbc_mesh_interface.h"
+#include "nrf8001-ble-uart-spark-io/serial_evt.h"

 enum state_t{
@@ -102,10 +103,11 @@
 bool newMessage = false;

 void initConnectionSlowly(){
-    uint8_t accAddr[4] = {0x8f, 0xa6, 0x41,0xa5 };
+    uint32_t accAddr = 0xA541A68F;
     switch(initState) {
         case 0:
-            rbc_mesh_init(accAddr, (uint8_t) 38, (uint8_t) 2);
+            rbc_mesh_init(accAddr, (uint8_t) 38, (uint8_t) 2, (uint32_t) 0x64000000); // 100 as little endian, spark is big endian
+
             initState++;
             break;
         case 1:
@@ -133,12 +135,17 @@
         initConnectionSlowly();
     }
     //Process any ACI commands or events
-    hal_aci_data_t evnt;
+    serial_evt_t evnt;
     newMessage = rbc_mesh_evt_get(&evnt);

-    if(state == waitingForEvent && newMessage){
+    if(state == waitingForEvent && newMessage
+        && evnt.opcode == SERIAL_EVT_OPCODE_CMD_RSP){
         state = ready;

-        lastResponse = evnt.buffer[evnt.buffer[0]];
+        lastResponse = evnt.params.cmd_rsp.response.val_get.data[0];
     }
+
+    Serial.print(state);
+    Serial.print("  ");
+    Serial.println(initState);
 }


Contrôle en vitesse des roues et lecture de la direction.

--- controle_par_mannette/controle_par_mannette.ino
+++ controle_par_mannette/controle_par_mannette.ino
@@ -9,18 +9,125 @@
 //
 /////////////////////////////////////////////////////////////

+/////////////////////////////////////////////////////////////
+//
+// Constantes
+//
+/////////////////////////////////////////////////////////////
+
+#define DEBOGGAGE 0
+
+// Numéro de pin des sorties vers les moteurs
+const int moteur_avant   =  9;
+const int moteur_arriere = 10;
+const int moteur_gauche  =  3;  // (à confirmer)
+const int moteur_droite  = 11;  // (à confirmer)
+
+// Numéro de pin de l'entrée de direction
+const int mesure_direction = A6;
+
+// Numéro de pin des entrées de la mannette
+const int mannette_avant   =  4;
+const int mannette_arriere =  7;
+const int mannette_gauche  =  8;
+const int mannette_droite  = 12;
+const int mannette_vitesse = A7;
+
+// Durée minimale de la boucle principale
+const int dt = 10;
+
+/////////////////////////////////////////////////////////////
+//
+// Initialisation
+//
+/////////////////////////////////////////////////////////////
+
 void setup() {
+  // Initialisation de la communication série
+  Serial.begin(115200);
+
+  Serial.println(F("Controle de Norbert par mannette"));
+  Serial.println(F("David Beaudette (2016)"));
+
   // Initialisation des sorties vers les moteurs
+  pinMode(moteur_avant,   OUTPUT);
+  pinMode(moteur_arriere, OUTPUT);
+  pinMode(moteur_gauche,  OUTPUT);
+  pinMode(moteur_droite,  OUTPUT);

   // Initialisation des entrées de la mannette
+  pinMode(mannette_avant,   INPUT_PULLUP);
+  pinMode(mannette_arriere, INPUT_PULLUP);
+  pinMode(mannette_gauche,  INPUT_PULLUP);
+  pinMode(mannette_droite,  INPUT_PULLUP);

-  // Initialisation de l'entrée analogique
+  //  Entrée de vitesse
+  pinMode(mannette_vitesse,  INPUT);
+  analogReference(EXTERNAL);

   // Initialisation du PID de la direction
+  //  Entrée de direction
+  pinMode(mesure_direction,  INPUT);
+

 }

+/////////////////////////////////////////////////////////////
+//
+// Programme principal
+//
+/////////////////////////////////////////////////////////////
+
 void loop() {
-  //

+  // Lire l'état des controles sur la manette
+  int bouton_avant   = digitalRead(mannette_avant);
+  int bouton_arriere = digitalRead(mannette_arriere);
+
+  int vitesse_i = 1023 - analogRead(mannette_vitesse);
+  int vitesse_moteur;
+
+  // Convertir la lecture analogique entière entre 20% et 100% de 255
+  float vitesse_f = (vitesse_i / 1023.0);
+  vitesse_moteur = max(vitesse_f, 0.1) * 255.0;
+
+#if DEBOGGAGE
+  Serial.print(F("Vitesse au potentiometre: "));
+  Serial.print(vitesse_i);
+  Serial.print(F(", une fois convertie entre 0 et 1: "));
+  Serial.print(vitesse_f);
+  Serial.print(F(", entre 0 et 255: "));
+  Serial.print(vitesse_moteur);
+  Serial.println(F("."));
+#endif
+
+  if(bouton_avant == LOW) {
+    // Activer le moteur avant
+    analogWrite(moteur_avant, vitesse_moteur);
+  }
+  else {
+    analogWrite(moteur_avant, 0);
+  }
+  if(bouton_arriere == LOW) {
+      // Activer le moteur arrière
+      analogWrite(moteur_arriere, vitesse_moteur);
+  }
+  else {
+    analogWrite(moteur_arriere, 0);
+  }
+
+  // Lire la direction actuelle
+  int direction_i = analogRead(mesure_direction);
+  // Convertir la lecture analogique entière entre -1 et 1
+  float direction_f = 2.0 * (direction_i - 44.0) / (1023.0 - 44.0) - 1.0;
+
+#if DEBOGGAGE
+  Serial.print(F("Direction au potentiometre: "));
+  Serial.print(direction_i);
+  Serial.print(F(", une fois convertie entre -1 et 1: "));
+  Serial.print(direction_f);
+  Serial.println(F("."));
+#endif
+
+  delay(dt);
 }


forgot to add initialization

forgot to add initialization

--- examples/LCDML_DISPLAYTYPE/LCDML_glcd_adafruit_st7735/LCDML_glcd_adafruit_st7735.ino
+++ examples/LCDML_DISPLAYTYPE/LCDML_glcd_adafruit_st7735/LCDML_glcd_adafruit_st7735.ino
@@ -133,9 +133,10 @@

     // Enable all items with _LCDML_G1
     LCDML_DISP_groupEnable(_LCDML_G1); // enable group 1
-
+
+    SPI.begin();
     // clear lcd
-    display.fillScreen(_LCDML_ADAFRUIT_BACKGROUND_COLOR);
+    display.initR(INITR_BLACKTAB);
     // set text color / Textfarbe setzen
     display.setTextColor(_LCDML_ADAFRUIT_TEXT_COLOR);
     // set text size / Textgroesse setzen


Delete gpslcd.ino

Delete gpslcd.ino

--- gpslcd.ino
+++ gpslcd.ino
@@ -1,623 +0,0 @@
-/* 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 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
-  20x4 LCD using the LiquidCrystal_I2C library.
-
-  https://github.com/Grommet123/GPSLCD
-
-  The MIT License (MIT)
-
-  Permission is hereby granted, free of charge, to any person obtaining a copy
-  of this software and associated documentation files (the "Software"), to deal
-  in the Software without restriction, including without limitation the rights
-  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the Software is
-  furnished to do so, subject to the following conditions:
-
-  The above copyright notice and this permission notice shall be included in all
-  copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-  SOFTWARE.
-
-*/
-
-#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
-// Initializes class variables and defines the I2C address of the LCD
-LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);
-
-// The setup (runs once at start up)
-void setup()
-{
-  pinMode(BACKLIGHT_SW, INPUT);
-  // Selects either altitude or the date/time to be displayed
-  pinMode(ALTITUDE_DATE_TIME_SW, INPUT);
-  // Select switches
-  pinMode(DISPLAY_12_HOUR_SW, INPUT);
-  pinMode(CONVERT_TO_LOCAL_SW, INPUT);
-  pinMode(DISPLAY_HDOP_SW, INPUT);
-  pinMode(CARDINAL_SW, INPUT);
-  pinMode(LOW_SPEED_OVERRIDE, INPUT);
-  pinMode(ON_BOARD_LED, OUTPUT); // Turn off on-board LED
-  digitalWrite(ON_BOARD_LED, LOW); //       "
-
-  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;
-  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;
-  bool display12_24_Hour = !digitalRead(DISPLAY_12_HOUR_SW);
-  bool localUTCTimeDate = !digitalRead(CONVERT_TO_LOCAL_SW);
-  bool displayHdop = !digitalRead(DISPLAY_HDOP_SW);
-  bool cardinal8_16 = !digitalRead(CARDINAL_SW);
-  bool lowSpeedOverride = !digitalRead(LOW_SPEED_OVERRIDE);
-  bool dataValid; // Data valid from the GPS module
-  GPSStruct GPSData; // Holds the GPS data coming from the GPS module
-  unsigned long now = millis(); // The time "now"
-
-#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
-
-  // Get the data from the GPS module
-  while (GPSModule.available()) // While there are characters coming from the GPS module
-  {
-    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();
-    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();
-#else // #ifndef DATA_VALID_OVERRIDE
-    // Store the fake GPS data (for debugging)
-    GPSData.satellites = 5;
-    GPSData.lat        = 40.71d;  // East coast (NYC)
-    GPSData.lon        = -74.00d; //   "
-    GPSData.speed      = 5.0d;
-    GPSData.altitude   = 555.0d;
-    GPSData.heading    = 60.0d; // ENE or NE (16 cardinal points or 8 cardinal points)
-    GPSData.hdop       = 150; // 1.5
-    GPSData.year       = 2017;
-    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 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 is derived from the data sent by the GPS unit
-    // Send data to the LCD
-    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 / 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);
-    // Only display if time/date is selected
-    if ((digitalRead(ALTITUDE_DATE_TIME_SW))) {
-      if (!localUTCTimeDate) {
-        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 { // if (!localUTCTimeDate)
-        // Display Hdop
-        displayHdopOnLCD(GPSData.hdop, displayHdop, now,
-                         &prevHdopTime, &hdopToggle);
-      } // if (!localUTCTimeDate)
-    } // if ((digitalRead(ALTITUDE_DATE_TIME_SW)))
-    else {
-      // Display Hdop
-      displayHdopOnLCD(GPSData.hdop, displayHdop, now,
-                       &prevHdopTime, &hdopToggle);
-    } // if ((digitalRead(ALTITUDE_DATE_TIME_SW)))
-    lcd.setCursor(0, 2); // Go to 3rd line
-    lcd.print("Spd: ");
-    if ((GPSData.speed < SPEED_CUTOUT) && (lowSpeedOverride)) {
-      lcd.print("0  ");
-    }
-    else {
-      lcd.print((int16_t)GPSData.speed);
-      lcd.print(" "); // Clear the extra chars
-    } // if ((GPSData.speed < SPEED_CUTOUT) && (lowSpeedOverride))
-    lcd.setCursor(12, 2);
-    lcd.print("Hdg: ");
-    if ((GPSData.speed < SPEED_CUTOUT) && (lowSpeedOverride)) {
-      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, cardinal8_16));
-        }
-        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) && (lowSpeedOverride))
-    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)
-    } // if ((digitalRead(ALTITUDE_DATE_TIME_SW)))
-    else {
-      // Toggle date/time every TOGGLETIME_INTERVAL seconds
-      if (now - prevDateTime > TOGGLETIME_INTERVAL) {
-        prevDateTime = now;
-        if (dateTimeToggle) {
-          // Display time
-          dateTimeToggle = false;
-          lcd.print("Time: ");
-          uint8_t hour = GPSData.hour;
-          uint8_t day  = GPSData.day;
-          uint8_t month = GPSData.month;
-          uint16_t year = GPSData.year;
-          bool DST = false;
-          if (localUTCTimeDate) {
-            // Convert UTC time to local time (no need to convert the date)
-            DST = convertToLocal(&hour, &year, &month,
-                                 &day, GPSData.lon, false); // false means no date conversion
-          }
-          else { // if (localUTCTimeDate)
-            if (display12_24_Hour) {
-              if (hour == 0) { // 12 hour clocks don't display 0
-                hour = 12;
-              }
-            } // if (display12_24_Hour)
-          } // if (localUTCTimeDate)
-          char AMPM[] = "am";
-          if (display12_24_Hour) {
-            if (hour >= 12) { // Convert to 12 hour format
-              if (hour > 12) hour -= 12;
-              strcpy(AMPM, "pm");
-            }
-          } // if (display12_24_Hour)
-          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);
-          if (display12_24_Hour) {
-            lcd.print(AMPM);
-          }
-          if (localUTCTimeDate) {
-            if (display12_24_Hour) {
-              (DST) ? lcd.print(" DST") : lcd.print("  ST");
-            }
-            else {
-              (DST) ? lcd.print("   DST") : lcd.print("    ST");
-            } // if (display12_24_Hour)
-          } // if (localUTCTimeDate)
-          if (!localUTCTimeDate) {
-            if (display12_24_Hour) {
-              lcd.print(" UTC");
-            }
-            else {
-              lcd.print("   UTC");
-            } // if (display12_24_Hour)
-          } // if (!localUTCTimeDate)
-        } // if (dateTimeToggle)
-        else {
-          // Display date
-          dateTimeToggle = true;
-          lcd.print("Date: ");
-          uint8_t hour = GPSData.hour;
-          uint8_t day  = GPSData.day;
-          uint8_t month = GPSData.month;
-          uint16_t year = GPSData.year;
-          if (localUTCTimeDate) {
-            // Convert UTC date to local date
-            bool DST = convertToLocal(&hour, &year, &month,
-                                      &day, GPSData.lon, true); // true means date conversion
-          } // if (localUTCTimeDate)
-          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);
-          displayDayOnLCD(dayOfWeek(year, month, day));
-        } // if (dateTimeToggle)
-      } // if (now - prevDateTime > TOGGLETIME_INTERVAL)
-    } // if ((digitalRead(ALTITUDE_DATE_TIME_SW)))
-  } // if (dataValid)
-  else {
-    // GPS data is not valid, so it must be initializing
-    // 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(16, 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(0, 3);
-      lcd.print("SV:"); // Desplay the number of satellites
-      lcd.print(gps.satellites.value());
-      lcd.setCursor(19, 3); // Display the initializing counter
-      if (++initializingCounter > 9) initializingCounter = 1; // Limit 1 - 9
-      lcd.print(initializingCounter);
-      leftInitialization = false;
-    }
-  } // GPS data is not valid
-} // loop
-
-/* Helper functions start here
-
-  The following three functions 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;
-}
-
-// Display the day of the week on the LCD
-void displayDayOnLCD(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 (16 or 8 cardinal points)
-const char* cardinal(double course, bool cardinalSelect)
-{
-  if (!cardinalSelect) {
-    const char* directions[] = {"N  ", "NNE", "NE ", "ENE", "E  ", "ESE", "SE ", "SSE",
-                                "S  ", "SSW", "SW ", "WSW", "W  ", "WNW", "NW ", "NNW"
-                               };
-    uint8_t direction = (uint8_t)((course + 11.25d) / 22.5d);
-    return directions[direction % 16];
-  }
-  else {
-    const char* directions[] = {"N  ", "N  ", "NE ", "NE ", "E  ", "E  ", "SE ", "SE ",
-                                "S  ", "S  ", "SW ", "SW ", "W  ", "W  ", "NW ", "NW "
-                               };
-    uint8_t direction = (uint8_t)((course + 11.25d) / 22.5d);
-    return directions[direction % 16];
-  } // if (!cardinalSelect)
-}
-
-/* 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;
-}
-
-/* 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, bool doDST) {
-
-  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)round((lon / 15.0d)); // UTC offset
-  if (UTCOffset < 0) {
-    // West of Greenwich, subtract
-    UTCOffset = abs(UTCOffset); // Make offset positive
-    if (DST && convertDate && doDST) --UTCOffset; // Compensate for DST
-    if (*hour <= UTCOffset) *hour += 24;
-    if (DST) {
-      *hour -= (UTCOffset - 1); // Subtract offset
-    } else {
-      *hour -= (UTCOffset); // Subtract offset
-    }
-  }
-  else {
-    // East of Greenwich, add
-    if (DST && convertDate && doDST) --UTCOffset; // Compensate for DST
-    if (*hour <= UTCOffset) *hour += 24;
-    if (DST) {
-      *hour += (UTCOffset + 1); // add offset
-    } else {
-      *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);
-}
-
-// Dislpays Hdop or horizontal position error on the LCD
-void displayHdopOnLCD(uint32_t Hdop, bool HdopSelect, unsigned long now,
-                      unsigned long* prevHdopTime, bool* hdopToggle) {
-  if (!HdopSelect) {
-    // 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
-    float hdop = (float)Hdop / 100.0f; // Hdop in X.X format
-    lcd.print(" Hdop:");
-    if (hdop < 10.0f) {
-      lcd.print((uint32_t)hdop);
-      lcd.print(".");
-      lcd.print((uint32_t)((hdop - (uint32_t)hdop) * 10.0f));
-    }
-    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 (hdop < 10.0f)
-  }
-  else { // if (!HdopSelect)
-    // Display horizontal position error in feet
-    float hError = (float)Hdop / 100.0f; // Error in X.X format
-    hError *= GPS_RECEIVER_ERROR; // Error in meters
-    hError *= _GPS_FEET_PER_METER; // Error in feet
-    lcd.print(" Err: ");
-    if (hError < 100.0f) {
-      lcd.print((uint8_t)hError);
-      if (hError < 10.0f) {
-        lcd.print("f "); // feet
-      }
-      else {
-        lcd.print("f"); // feet
-      }
-    }
-    else { // if (hError < 100.0f)
-      // horizontal position error 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 (hError < 100.0f)
-  } // if (!HdopSelect)
-}


speedo.ino : added some checking to the best speed, if the wheel parks you can get a high value, the highest possible is 8.83 so reset it when higher than 8.8

--- speedo/speedo.ino
+++ speedo/speedo.ino
@@ -127,6 +127,11 @@
     best = mph;
     displayBest();
   }
+  else if(mph > 8.80)
+  {
+    best = 0;
+    Serial.print("Best reset\n");
+  }
   delay(1000);
 }


código ajustado para aquisição com perído fixo de amostragem

--- src/arduino/thermocoupleReader/thermocoupleReader.ino
+++ src/arduino/thermocoupleReader/thermocoupleReader.ino
@@ -2,20 +2,40 @@
  * Medida de Temperatura usando LM35 e Termopar MTK-01
  *
  * @authors Rafael, Camila, Pamella
- * @version 0.1 'Teste Leitura'
+ * @version 0.12 'Teste Leitura multiplos sensores'
  */

-#define PIN_LM35 A0
+#define PIN_LM35      A0
+#define PIN_MTK01     A1
+#define INTERVAL      500  //ms
+
+unsigned long lasttime = millis();

 void setup() {
   // Inicia Porta Serial
   Serial.begin(9600);
+
+  // Define Portas Sensores
+  pinMode(PIN_LM35,INPUT);
+  pinMode(PIN_MTK01,INPUT);
 }

 void loop() {
-  int temp1 = analogRead(PIN_LM35);
-  Serial.println(temp1);
+  // Loop com período fixo de Amostragem
+  if (millis() - lasttime >= INTERVAL) {
+    // Ajusta Timer
+    lasttime = millis();
+
+    // Ler o valor dos sensores
+    int rawTemp1 = analogRead(PIN_LM35);
+    int rawTemp2 = analogRead(PIN_MTK01);

-  delay(100);
-}`
+    // Envia via Serial
+    Serial.print(lasttime);
+    Serial.print(' ');
+    Serial.print(rawTemp1);
+    Serial.print(' ');
+    Serial.println(rawTemp2);
+  }
+}


Version 2.7c - 20th June 2019

Version 2.7c - 20th June 2019

Fixes #25

--- ulisp.ino
+++ ulisp.ino
@@ -1,5 +1,5 @@
-/* uLisp AVR Version 2.7 - www.ulisp.com
-   David Johnson-Davies - www.technoblogy.com - 20th May 2019
+/* uLisp AVR Version 2.7c - www.ulisp.com
+   David Johnson-Davies - www.technoblogy.com - 20th June 2019

    Licensed under the MIT license: https://opensource.org/licenses/MIT
 */
@@ -795,8 +795,11 @@
   function = cdr(function);
   // Dropframe
   if (tc) {
-    while (*env != NULL && car(*env) != NULL) pop(*env);
-  } else push(nil, *env);
+    if (*env != NULL && car(*env) == NULL) {
+      pop(*env);
+      while (*env != NULL && car(*env) != NULL) pop(*env);
+    } else push(nil, *env);
+  }
   // Push state
   while (state != NULL) {
     object *pair = first(state);
@@ -837,6 +840,7 @@
   if (args != NULL) error2(fname, PSTR("has too many arguments"));
   if (trace) { pserial(')'); pln(pserial); }
   // Do an implicit progn
+  if (tc) push(nil, *env);
   return tf_progn(function, *env);
 }


Version 2.9c - 2nd October 2019

Version 2.9c - 2nd October 2019

Support Curiosity Nano

--- ulisp.ino
+++ ulisp.ino
@@ -1,5 +1,5 @@
-/* uLisp AVR Version 2.9b - www.ulisp.com
-   David Johnson-Davies - www.technoblogy.com - 25th September 2019
+/* uLisp AVR Version 2.9c - www.ulisp.com
+   David Johnson-Davies - www.technoblogy.com - 2nd October 2019

    Licensed under the MIT license: https://opensource.org/licenses/MIT
 */
@@ -145,6 +145,16 @@
 #define SYMBOLTABLESIZE 512             /* Bytes */

 #elif defined(ARDUINO_AVR_NANO_EVERY)
+#define WORKSPACESIZE 1068-SDSIZE       /* Objects (4*bytes) */
+#define EEPROMSIZE 256                  /* Bytes */
+#define SYMBOLTABLESIZE BUFFERSIZE      /* Bytes - no long symbols */
+
+#elif defined(ARDUINO_AVR_ATmega4809)   /* Curiosity Nano using MegaCoreX */
+#define Serial Serial3
+#define WORKSPACESIZE 1068-SDSIZE       /* Objects (4*bytes) */
+#define EEPROMSIZE 256                  /* Bytes */
+#define SYMBOLTABLESIZE BUFFERSIZE      /* Bytes - no long symbols */
+
 #define WORKSPACESIZE 1068-SDSIZE       /* Objects (4*bytes) */
 #define EEPROMSIZE 256                  /* Bytes */
 #define SYMBOLTABLESIZE BUFFERSIZE      /* Bytes - no long symbols */
@@ -1194,6 +1204,8 @@
   if (!(pin>=0 && pin<=15)) error(ANALOGREAD, invalidpin, number(pin));
 #elif defined(__AVR_ATmega1284P__)
   if (!(pin>=0 && pin<=7)) error(ANALOGREAD, invalidpin, number(pin));
+#elif defined(ARDUINO_AVR_ATmega4809)  /* MegaCoreX core */
+  if (!((pin>=22 && pin<=33) || (pin>=36 && pin<=39))) error(ANALOGREAD, invalidpin, number(pin));
 #elif defined(__AVR_ATmega4809__)
   if (!(pin>=14 && pin<=21)) error(ANALOGREAD, invalidpin, number(pin));
 #elif defined(__AVR_ATtiny3216__)
@@ -1208,6 +1220,8 @@
   if (!((pin>=2 && pin<=13) || (pin>=44 && pin <=46))) error(ANALOGWRITE, invalidpin, number(pin));
 #elif defined(__AVR_ATmega1284P__)
   if (!(pin==3 || pin==4 || pin==6 || pin==7 || (pin>=12 && pin<=15))) error(ANALOGWRITE, invalidpin, number(pin));
+#elif defined(ARDUINO_AVR_ATmega4809)  /* MegaCoreX core */
+  if (!((pin>=16 && pin<=19) || (pin>=38 && pin<=39))) error(ANALOGWRITE, invalidpin, number(pin));
 #elif defined(__AVR_ATmega4809__)
   if (!(pin==3 || pin==5 || pin==6 || pin==9 || pin==10)) error(ANALOGWRITE, invalidpin, number(pin));
 #elif defined(__AVR_ATtiny3216__)
@@ -3851,7 +3865,7 @@

 void setup () {
   Serial.begin(9600);
-  #if defined(ARDUINO_AVR_NANO_EVERY)
+  #if defined(ARDUINO_AVR_NANO_EVERY) || defined(ARDUINO_AVR_ATmega4809)
   delay(2500);
   #else
   int start = millis();


Version 2.9 - 20th September 2019

Version 2.9 - 20th September 2019

Fixes #28

--- ulisp.ino
+++ ulisp.ino
@@ -1,5 +1,5 @@
-/* uLisp AVR Version 2.8a - www.ulisp.com
-   David Johnson-Davies - www.technoblogy.com - 6th August 2019
+/* uLisp AVR Version 2.9 - www.ulisp.com
+   David Johnson-Davies - www.technoblogy.com - 20th September 2019

    Licensed under the MIT license: https://opensource.org/licenses/MIT
 */
@@ -24,6 +24,7 @@
 #include <setjmp.h>
 #include <SPI.h>
 #include <limits.h>
+#include <EEPROM.h>

 #if defined(sdcardsupport)
 #include <SD.h>
@@ -32,6 +33,11 @@
 #define SDSIZE 0
 #endif

+#if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+#define PROGMEM
+#define PSTR(s) (s)
+#endif
+
 // C Macros

 #define nil                NULL
@@ -70,8 +76,8 @@
 enum stream { SERIALSTREAM, I2CSTREAM, SPISTREAM, SDSTREAM };

 enum function { NIL, TEE, NOTHING, OPTIONAL, AMPREST, LAMBDA, LET, LETSTAR, CLOSURE, SPECIAL_FORMS, QUOTE,
-DEFUN, DEFVAR, SETQ, LOOP, PUSH, POP, INCF, DECF, SETF, DOLIST, DOTIMES, TRACE, UNTRACE, FORMILLIS,
-WITHSERIAL, WITHI2C, WITHSPI, WITHSDCARD, TAIL_FORMS, PROGN, RETURN, IF, COND, WHEN, UNLESS, CASE, AND,
+DEFUN, DEFVAR, SETQ, LOOP, RETURN, PUSH, POP, INCF, DECF, SETF, DOLIST, DOTIMES, TRACE, UNTRACE,
+FORMILLIS, WITHSERIAL, WITHI2C, WITHSPI, WITHSDCARD, TAIL_FORMS, PROGN, IF, COND, WHEN, UNLESS, CASE, AND,
 OR, FUNCTIONS, NOT, NULLFN, CONS, ATOM, LISTP, CONSP, SYMBOLP, STREAMP, EQ, CAR, FIRST, CDR, REST, CAAR,
 CADR, SECOND, CDAR, CDDR, CAAAR, CAADR, CADAR, CADDR, THIRD, CDAAR, CDADR, CDDAR, CDDDR, LENGTH, LIST,
 REVERSE, NTH, ASSOC, MEMBER, APPLY, FUNCALL, APPEND, MAPC, MAPCAR, MAPCAN, ADD, SUBTRACT, MULTIPLY,
@@ -114,31 +120,49 @@

 typedef int (*gfun_t)();
 typedef void (*pfun_t)(char);
+#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284P__)
+typedef int BitOrder;
+typedef int PinMode;
+#endif

 // Workspace - sizes in bytes
 #define WORDALIGNED __attribute__((aligned (2)))
 #define BUFFERSIZE 18

 #if defined(__AVR_ATmega328P__)
-#define WORKSPACESIZE 315-SDSIZE        /* Cells (4*bytes) */
+#define WORKSPACESIZE 315-SDSIZE        /* Objects (4*bytes) */
 #define EEPROMSIZE 1024                 /* Bytes */
 #define SYMBOLTABLESIZE BUFFERSIZE      /* Bytes - no long symbols */

 #elif defined(__AVR_ATmega2560__)
-#define WORKSPACESIZE 1214-SDSIZE       /* Cells (4*bytes) */
+#define WORKSPACESIZE 1214-SDSIZE       /* Objects (4*bytes) */
 #define EEPROMSIZE 4096                 /* Bytes */
 #define SYMBOLTABLESIZE 512             /* Bytes */

 #elif defined(__AVR_ATmega1284P__)
-#define WORKSPACESIZE 2816-SDSIZE       /* Cells (4*bytes) */
+#define WORKSPACESIZE 2816-SDSIZE       /* Objects (4*bytes) */
 #define EEPROMSIZE 4096                 /* Bytes */
 #define SYMBOLTABLESIZE 512             /* Bytes */

+#elif defined(ARDUINO_AVR_NANO_EVERY)
+#define WORKSPACESIZE 1068-SDSIZE       /* Objects (4*bytes) */
+#define EEPROMSIZE 256                  /* Bytes */
+#define SYMBOLTABLESIZE BUFFERSIZE      /* Bytes - no long symbols */
+
+#elif defined(__AVR_ATmega4809__)
+#define WORKSPACESIZE 1068-SDSIZE       /* Objects (4*bytes) */
+#define EEPROMSIZE 256                  /* Bytes */
+#define SYMBOLTABLESIZE BUFFERSIZE      /* Bytes - no long symbols */
+
+#elif defined(__AVR_ATtiny3216__)
+#define WORKSPACESIZE 306-SDSIZE        /* Objects (4*bytes) */
+#define EEPROMSIZE 256                  /* Bytes */
+#define SYMBOLTABLESIZE BUFFERSIZE      /* Bytes - no long symbols */
+
 #endif

 object Workspace[WORKSPACESIZE] WORDALIGNED;
 char SymbolTable[SYMBOLTABLESIZE];
-typedef int BitOrder;
 #define SDCARD_SS_PIN 10

 // Global variables
@@ -158,10 +182,9 @@
 char BreakLevel = 0;
 char LastChar = 0;
 char LastPrint = 0;
-char PrintReadably = 1;

 // Flags
-enum flag { RETURNFLAG, ESCAPE, EXITEDITOR, LIBRARYLOADED };
+enum flag { PRINTREADABLY, RETURNFLAG, ESCAPE, EXITEDITOR, LIBRARYLOADED };
 volatile char Flags;

 // Forward references
@@ -373,19 +396,9 @@
   file.write(data & 0xFF); file.write(data>>8 & 0xFF);
 }
 #else
-typedef struct {
-  unsigned int eval;
-  unsigned int datasize;
-  unsigned int globalenv;
-  unsigned int gcstack;
-  #if SYMBOLTABLESIZE > BUFFERSIZE
-  unsigned int symboltop;
-  char table[SYMBOLTABLESIZE];
-  #endif
-  object data[];
-} struct_image;
-
-struct_image EEMEM image;
+void EEPROMWriteInt (unsigned int *addr, int data) {
+  EEPROM.write((*addr)++, data & 0xFF); EEPROM.write((*addr)++, data>>8 & 0xFF);
+}
 #endif

 unsigned int saveimage (object *arg) {
@@ -418,22 +431,32 @@
   if (!(arg == NULL || listp(arg))) error(SAVEIMAGE, PSTR("illegal argument"), arg);
   int bytesneeded = imagesize*4 + SYMBOLTABLESIZE + 10;
   if (bytesneeded > EEPROMSIZE) error(SAVEIMAGE, PSTR("image size too large"), number(imagesize));
-  eeprom_update_word(&image.datasize, imagesize);
-  eeprom_update_word(&image.eval, (unsigned int)arg);
-  eeprom_update_word(&image.globalenv, (unsigned int)GlobalEnv);
-  eeprom_update_word(&image.gcstack, (unsigned int)GCStack);
+  unsigned int addr = 0;
+  EEPROMWriteInt(&addr, (unsigned int)arg);
+  EEPROMWriteInt(&addr, imagesize);
+  EEPROMWriteInt(&addr, (unsigned int)GlobalEnv);
+  EEPROMWriteInt(&addr, (unsigned int)GCStack);
   #if SYMBOLTABLESIZE > BUFFERSIZE
-  eeprom_update_word(&image.symboltop, (unsigned int)SymbolTop);
-  eeprom_update_block(SymbolTable, image.table, SYMBOLTABLESIZE);
+  EEPROMWriteInt(&addr, (unsigned int)SymbolTop);
+  for (int i=0; i<SYMBOLTABLESIZE; i++) EEPROM.write(addr++, SymbolTable[i]);
   #endif
-  eeprom_update_block(Workspace, image.data, imagesize*4);
+  for (unsigned int i=0; i<imagesize; i++) {
+    object *obj = &Workspace[i];
+    EEPROMWriteInt(&addr, (uintptr_t)car(obj));
+    EEPROMWriteInt(&addr, (uintptr_t)cdr(obj));
+  }
   return imagesize;
 #endif
 }

 #if defined(sdcardsupport)
 int SDReadInt (File file) {
-  uintptr_t b0 = file.read(); uintptr_t b1 = file.read();
+  uint8_t b0 = file.read(); uint8_t b1 = file.read();
+  return b0 | b1<<8;
+}
+#else
+int EEPROMReadInt (unsigned int *addr) {
+  uint8_t b0 = EEPROM.read((*addr)++); uint8_t b1 = EEPROM.read((*addr)++);
   return b0 | b1<<8;
 }
 #endif
@@ -463,15 +486,21 @@
   gc(NULL, NULL);
   return imagesize;
 #else
-  unsigned int imagesize = eeprom_read_word(&image.datasize);
+  unsigned int addr = 0;
+  EEPROMReadInt(&addr); // Skip eval address
+  unsigned int imagesize = EEPROMReadInt(&addr);
   if (imagesize == 0 || imagesize == 0xFFFF) error2(LOADIMAGE, PSTR("no saved image"));
-  GlobalEnv = (object *)eeprom_read_word(&image.globalenv);
-  GCStack = (object *)eeprom_read_word(&image.gcstack);
+  GlobalEnv = (object *)EEPROMReadInt(&addr);
+  GCStack = (object *)EEPROMReadInt(&addr);
   #if SYMBOLTABLESIZE > BUFFERSIZE
-  SymbolTop = (char *)eeprom_read_word(&image.symboltop);
-  eeprom_read_block(SymbolTable, image.table, SYMBOLTABLESIZE);
+  SymbolTop = (char *)EEPROMReadInt(&addr);
+  for (int i=0; i<SYMBOLTABLESIZE; i++) SymbolTable[i] = EEPROM.read(addr++);
   #endif
-  eeprom_read_block(Workspace, image.data, imagesize*4);
+  for (int i=0; i<imagesize; i++) {
+    object *obj = &Workspace[i];
+    car(obj) = (object *)EEPROMReadInt(&addr);
+    cdr(obj) = (object *)EEPROMReadInt(&addr);
+  }
   gc(NULL, NULL);
   return imagesize;
 #endif
@@ -489,7 +518,8 @@
     apply(0, autorun, NULL, NULL);
   }
 #else
-  object *autorun = (object *)eeprom_read_word(&image.eval);
+  unsigned int addr = 0;
+  object *autorun = (object *)EEPROMReadInt(&addr);
   if (autorun != NULL && (unsigned int)autorun != 0xFFFF) {
     loadimage(nil);
     apply(0, autorun, NULL, NULL);
@@ -529,11 +559,11 @@
 const char notastring[] PROGMEM = "argument is not a string";
 const char notalist[] PROGMEM = "argument is not a list";
 const char notproper[] PROGMEM = "argument is not a proper list";
-const char notproper2[] PROGMEM = "second argument is not a proper list";
-const char notproper3[] PROGMEM = "third argument is not a proper list";
 const char noargument[] PROGMEM = "missing argument";
 const char nostream[] PROGMEM = "missing stream argument";
 const char overflow[] PROGMEM = "arithmetic overflow";
+const char invalidpin[] PROGMEM = "invalid pin";
+const char resultproper[] PROGMEM = "result is not a proper list";

 // Tracing

@@ -801,7 +831,7 @@
   if (trace) {
     indent(TraceDepth[trace-1]<<1, pserial);
     pint(TraceDepth[trace-1]++, pserial);
-    pserial(':'); pserial(' '); pserial('('); pstring(lookupbuiltin(name), pserial);
+    pserial(':'); pserial(' '); pserial('('); pstring(symbolname(name), pserial);
   }
   object *params = first(function);
   function = cdr(function);
@@ -942,6 +972,10 @@
 uint8_t const TWI_SCL_PIN = 5;
 #endif

+#if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+uint32_t const FREQUENCY = 400000L;  // Hardware I2C clock in Hz
+uint32_t const T_RISE = 300L;        // Rise time
+#else
 uint32_t const F_TWI = 400000L;  // Hardware I2C clock in Hz
 uint8_t const TWSR_MTX_DATA_ACK = 0x28;
 uint8_t const TWSR_MTX_ADR_ACK = 0x18;
@@ -950,33 +984,68 @@
 uint8_t const TWSR_REP_START = 0x10;
 uint8_t const I2C_READ = 1;
 uint8_t const I2C_WRITE = 0;
+#endif

 void I2Cinit(bool enablePullup) {
+#if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+  if (enablePullup) {
+    pinMode(PIN_WIRE_SDA, INPUT_PULLUP);
+    pinMode(PIN_WIRE_SCL, INPUT_PULLUP);
+  }
+  uint32_t baud = ((F_CPU_CORRECTED/FREQUENCY) - (((F_CPU_CORRECTED*T_RISE)/1000)/1000)/1000 - 10)/2;
+  TWI0.MBAUD = (uint8_t)baud;
+  TWI0.MCTRLA = TWI_ENABLE_bm;                                        // Enable as master, no interrupts
+  TWI0.MSTATUS = TWI_BUSSTATE_IDLE_gc;
+#else
   TWSR = 0;                        // no prescaler
   TWBR = (F_CPU/F_TWI - 16)/2;     // set bit rate factor
   if (enablePullup) {
     digitalWrite(TWI_SDA_PIN, HIGH);
     digitalWrite(TWI_SCL_PIN, HIGH);
   }
-}
-
-uint8_t I2Cread() {
+#endif
+}
+
+int I2Cread() {
+#if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+  if (I2CCount != 0) I2CCount--;
+  while (!(TWI0.MSTATUS & TWI_RIF_bm));                               // Wait for read interrupt flag
+  uint8_t data = TWI0.MDATA;
+  // Check slave sent ACK?
+  if (I2CCount != 0) TWI0.MCTRLB = TWI_MCMD_RECVTRANS_gc;             // ACK = more bytes to read
+  else TWI0.MCTRLB = TWI_ACKACT_bm | TWI_MCMD_RECVTRANS_gc;           // Send NAK
+  return data;
+#else
   if (I2CCount != 0) I2CCount--;
   TWCR = 1<<TWINT | 1<<TWEN | ((I2CCount == 0) ? 0 : (1<<TWEA));
   while (!(TWCR & 1<<TWINT));
   return TWDR;
+#endif
 }

 bool I2Cwrite(uint8_t data) {
+#if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+  while (!(TWI0.MSTATUS & TWI_WIF_bm));                               // Wait for write interrupt flag
+  TWI0.MDATA = data;
+  TWI0.MCTRLB = TWI_MCMD_RECVTRANS_gc;                                // Do nothing
+  return !(TWI0.MSTATUS & TWI_RXACK_bm);                              // Returns true if slave gave an ACK
+#else
   TWDR = data;
   TWCR = 1<<TWINT | 1 << TWEN;
   while (!(TWCR & 1<<TWINT));
   return (TWSR & 0xF8) == TWSR_MTX_DATA_ACK;
+#endif
 }

 bool I2Cstart(uint8_t address, uint8_t read) {
+#if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+  TWI0.MADDR = address<<1 | read;                                     // Send START condition
+  while (!(TWI0.MSTATUS & (TWI_WIF_bm | TWI_RIF_bm)));                // Wait for write or read interrupt flag
+  if ((TWI0.MSTATUS & TWI_ARBLOST_bm)) return false;                  // Return false if arbitration lost or bus error
+  return !(TWI0.MSTATUS & TWI_RXACK_bm);                              // Return true if slave gave an ACK
+#else
   uint8_t addressRW = address<<1 | read;
-  TWCR = 1<<TWINT | 1<<TWSTA | 1<<TWEN;    // send START condition
+  TWCR = 1<<TWINT | 1<<TWSTA | 1<<TWEN;    // Send START condition
   while (!(TWCR & 1<<TWINT));
   if ((TWSR & 0xF8) != TWSR_START && (TWSR & 0xF8) != TWSR_REP_START) return false;
   TWDR = addressRW;  // send device address and direction
@@ -984,16 +1053,22 @@
   while (!(TWCR & 1<<TWINT));
   if (addressRW & I2C_READ) return (TWSR & 0xF8) == TWSR_MRX_ADR_ACK;
   else return (TWSR & 0xF8) == TWSR_MTX_ADR_ACK;
-}
-
-bool I2Crestart(uint8_t address, uint8_t read) {
+#endif
+}
+
+bool I2Crestart (uint8_t address, uint8_t read) {
   return I2Cstart(address, read);
 }

-void I2Cstop(uint8_t read) {
+void I2Cstop (uint8_t read) {
+#if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+  (void) read;
+  TWI0.MCTRLB = TWI_ACKACT_bm | TWI_MCMD_STOP_gc;                     // Send STOP
+#else
   (void) read;
   TWCR = 1<<TWINT | 1<<TWEN | 1<<TWSTO;
   while (TWCR & 1<<TWSTO); // wait until stop and bus released
+#endif
 }

 // Streams
@@ -1114,30 +1189,42 @@

 void checkanalogread (int pin) {
 #if defined(__AVR_ATmega328P__)
-  if (!(pin>=0 && pin<=5)) error(ANALOGREAD, PSTR("invalid pin"), number(pin));
+  if (!(pin>=0 && pin<=5)) error(ANALOGREAD, invalidpin, number(pin));
 #elif defined(__AVR_ATmega2560__)
-  if (!(pin>=0 && pin<=15)) error(ANALOGREAD, PSTR("invalid pin"), number(pin));
+  if (!(pin>=0 && pin<=15)) error(ANALOGREAD, invalidpin, number(pin));
 #elif defined(__AVR_ATmega1284P__)
-  if (!(pin>=0 && pin<=7)) error(ANALOGREAD, PSTR("invalid pin"), number(pin));
+  if (!(pin>=0 && pin<=7)) error(ANALOGREAD, invalidpin, number(pin));
+#elif defined(__AVR_ATmega4809__)
+  if (!(pin>=14 && pin<=21)) error(ANALOGREAD, invalidpin, number(pin));
+#elif defined(__AVR_ATtiny3216__)
+  if (!(pin>=0 && pin<=5) || !(pin>=8 && pin<=9) || !(pin>=14 && pin<=17)) error(ANALOGREAD, invalidpin, number(pin));
 #endif
 }

 void checkanalogwrite (int pin) {
 #if defined(__AVR_ATmega328P__)
-  if (!(pin>=3 && pin<=11 && pin!=4 && pin!=7 && pin!=8)) error(ANALOGWRITE, PSTR("invalid pin"), number(pin));
+  if (!(pin>=3 && pin<=11 && pin!=4 && pin!=7 && pin!=8)) error(ANALOGWRITE, invalidpin, number(pin));
 #elif defined(__AVR_ATmega2560__)
-  if (!((pin>=2 && pin<=13) || (pin>=44 && pin <=46))) error(ANALOGWRITE, PSTR("invalid pin"), number(pin));
+  if (!((pin>=2 && pin<=13) || (pin>=44 && pin <=46))) error(ANALOGWRITE, invalidpin, number(pin));
 #elif defined(__AVR_ATmega1284P__)
-  if (!(pin==3 || pin==4 || pin==6 || pin==7 || (pin>=12 && pin<=15))) error(ANALOGWRITE, PSTR("invalid pin"), number(pin));
+  if (!(pin==3 || pin==4 || pin==6 || pin==7 || (pin>=12 && pin<=15))) error(ANALOGWRITE, invalidpin, number(pin));
+#elif defined(__AVR_ATmega4809__)
+  if (!(pin==3 || pin==5 || pin==6 || pin==9 || pin==10)) error(ANALOGWRITE, invalidpin, number(pin));
+#elif defined(__AVR_ATtiny3216__)
+  if (!(pin==0 || pin==1 || (pin>=7 && pin<=11) || pin==16)) error(ANALOGWRITE, invalidpin, number(pin));
 #endif
 }

 // Note

+#if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+const int scale[] PROGMEM = {4186,4435,4699,4978,5274,5588,5920,6272,6645,7040,7459,7902};
+#else
 const uint8_t scale[] PROGMEM = {239,226,213,201,190,179,169,160,151,142,134,127};
+#endif

 void playnote (int pin, int note, int octave) {
-  #if defined(__AVR_ATmega328P__)
+#if defined(__AVR_ATmega328P__)
   if (pin == 3) {
     DDRD = DDRD | 1<<DDD3; // PD3 (Arduino D3) as output
     TCCR2A = 0<<COM2A0 | 1<<COM2B0 | 2<<WGM20; // Toggle OC2B on match
@@ -1150,7 +1237,7 @@
   OCR2A = pgm_read_byte(&scale[note%12]) - 1;
   TCCR2B = 0<<WGM22 | prescaler<<CS20;

-  #elif defined(__AVR_ATmega2560__)
+#elif defined(__AVR_ATmega2560__)
   if (pin == 9) {
     DDRH = DDRH | 1<<DDH6; // PH6 (Arduino D9) as output
     TCCR2A = 0<<COM2A0 | 1<<COM2B0 | 2<<WGM20; // Toggle OC2B on match
@@ -1163,7 +1250,7 @@
   OCR2A = pgm_read_byte(&scale[note%12]) - 1;
   TCCR2B = 0<<WGM22 | prescaler<<CS20;

-  #elif defined(__AVR_ATmega1284P__)
+#elif defined(__AVR_ATmega1284P__)
   if (pin == 14) {
     DDRD = DDRD | 1<<DDD6; // PD6 (Arduino D14) as output
     TCCR2A = 0<<COM2A0 | 1<<COM2B0 | 2<<WGM20; // Toggle OC2B on match
@@ -1175,26 +1262,38 @@
   if (prescaler<3 || prescaler>6) error(NOTE, PSTR("octave out of range"), number(prescaler));
   OCR2A = pgm_read_byte(&scale[note%12]) - 1;
   TCCR2B = 0<<WGM22 | prescaler<<CS20;
+
+#elif defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+  int prescaler = 8 - octave - note/12;
+  if (prescaler<0 || prescaler>8) error(NOTE, PSTR("octave out of range"), number(prescaler));
+  tone(pin, scale[note%12]>>prescaler);
   #endif
 }

 void nonote (int pin) {
+#if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+  noTone(pin);
+#else
   (void) pin;
   TCCR2B = 0<<WGM22 | 0<<CS20;
+#endif
 }

 // Sleep

-// Interrupt vector for sleep watchdog
-ISR(WDT_vect) {
+#if !defined(__AVR_ATmega4809__) && !defined(__AVR_ATtiny3216__)
+  // Interrupt vector for sleep watchdog
+  ISR(WDT_vect) {
   WDTCSR |= 1<<WDIE;
 }
+#endif

 void initsleep () {
   set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 }

 void sleep (int secs) {
+#if !defined(__AVR_ATmega4809__) && !defined(__AVR_ATtiny3216__)
   // Set up Watchdog timer for 1 Hz interrupt
   WDTCSR = 1<<WDCE | 1<<WDE;
   WDTCSR = 1<<WDIE | 6<<WDP0;     // 1 sec interrupt
@@ -1220,6 +1319,9 @@
 #elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284P__)
   PRR0 = PRR0 & ~(1<<PRTIM0);
 #endif
+#else
+  delay(1000*secs);
+#endif
 }

 // Special forms
@@ -1263,7 +1365,6 @@
 }

 object *sp_loop (object *args, object *env) {
-  clrflag(RETURNFLAG);
   object *start = args;
   for (;;) {
     args = start;
@@ -1276,6 +1377,12 @@
       args = cdr(args);
     }
   }
+}
+
+object *sp_return (object *args, object *env) {
+  object *result = eval(tf_progn(args,env), env);
+  setflag(RETURNFLAG);
+  return result;
 }

 object *sp_push (object *args, object *env) {
@@ -1340,22 +1447,26 @@
   if (args == NULL) error2(DOLIST, noargument);
   object *params = first(args);
   object *var = first(params);
-  object *result;
   object *list = eval(second(params), env);
   push(list, GCStack); // Don't GC the list
   object *pair = cons(var,nil);
   push(pair,env);
   params = cdr(cdr(params));
-  object *forms = cdr(args);
+  args = cdr(args);
   while (list != NULL) {
     if (improperp(list)) error(DOLIST, notproper, list);
     cdr(pair) = first(list);
+    object *forms = args;
+    while (forms != NULL) {
+      object *result = eval(car(forms), env);
+      if (tstflag(RETURNFLAG)) {
+        clrflag(RETURNFLAG);
+        pop(GCStack);
+        return result;
+      }
+      forms = cdr(forms);
+    }
     list = cdr(list);
-    result = eval(tf_progn(forms,env), env);
-    if (tstflag(RETURNFLAG)) {
-      clrflag(RETURNFLAG);
-      return result;
-    }
   }
   cdr(pair) = nil;
   pop(GCStack);
@@ -1367,21 +1478,24 @@
   if (args == NULL) error2(DOTIMES, noargument);
   object *params = first(args);
   object *var = first(params);
-  object *result;
   int count = checkinteger(DOTIMES, eval(second(params), env));
   int index = 0;
   params = cdr(cdr(params));
   object *pair = cons(var,number(0));
   push(pair,env);
-  object *forms = cdr(args);
+  args = cdr(args);
   while (index < count) {
     cdr(pair) = number(index);
+    object *forms = args;
+    while (forms != NULL) {
+      object *result = eval(car(forms), env);
+      if (tstflag(RETURNFLAG)) {
+        clrflag(RETURNFLAG);
+        return result;
+      }
+      forms = cdr(forms);
+    }
     index++;
-    result = eval(tf_progn(forms,env), env);
-    if (tstflag(RETURNFLAG)) {
-      clrflag(RETURNFLAG);
-      return result;
-    }
   }
   cdr(pair) = number(index);
   if (params == NULL) return nil;
@@ -1547,17 +1661,11 @@
   if (args == NULL) return nil;
   object *more = cdr(args);
   while (more != NULL) {
-    object *result = eval(car(args),env);
-    if (tstflag(RETURNFLAG)) return result;
+    eval(car(args), env);
     args = more;
     more = cdr(args);
   }
   return car(args);
-}
-
-object *tf_return (object *args, object *env) {
-  setflag(RETURNFLAG);
-  return tf_progn(args, env);
 }

 object *tf_if (object *args, object *env) {
@@ -1777,7 +1885,7 @@
   int n = checkinteger(NTH, first(args));
   object *list = second(args);
   while (list != NULL) {
-    if (improperp(list)) error(NTH, notproper2, list);
+    if (improperp(list)) error(NTH, notproper, list);
     if (n == 0) return car(list);
     list = cdr(list);
     n--;
@@ -1843,100 +1951,93 @@

 object *fn_mapc (object *args, object *env) {
   object *function = first(args);
-  object *list1 = second(args);
-  object *result = list1;
-  object *list2 = cddr(args);
-  if (list2 != NULL) {
-    list2 = car(list2);
-    object *result2 = list2;
-    while (list1 != NULL && list2 != NULL) {
-      if (improperp(list1)) error(MAPC, notproper2, result);
-      if (improperp(list2)) error(MAPC, notproper3, result2);
-      apply(MAPC, function, cons(car(list1),cons(car(list2),NULL)), env);
-      list1 = cdr(list1); list2 = cdr(list2);
+  args = cdr(args);
+  object *result = first(args);
+  object *params = cons(NULL, NULL);
+  push(params,GCStack);
+  // Make parameters
+  while (true) {
+    object *tailp = params;
+    object *lists = args;
+    while (lists != NULL) {
+      object *list = car(lists);
+      if (list == NULL) {
+         pop(GCStack);
+         return result;
+      }
+      if (improperp(list)) error(MAPC, notproper, list);
+      object *obj = cons(first(list),NULL);
+      car(lists) = cdr(list);
+      cdr(tailp) = obj; tailp = obj;
+      lists = cdr(lists);
     }
-  } else {
-    while (list1 != NULL) {
-      if (improperp(list1)) error(MAPC, notproper2, result);
-      apply(MAPC, function, cons(car(list1),NULL), env);
-      list1 = cdr(list1);
-    }
-  }
-  return result;
+    apply(MAPC, function, cdr(params), env);
+  }
 }

 object *fn_mapcar (object *args, object *env) {
   object *function = first(args);
-  object *list1 = second(args);
-  object *result = list1;
-  object *list2 = cddr(args);
-  object *head = cons(NULL, NULL);
+  args = cdr(args);
+  object *params = cons(NULL, NULL);
+  push(params,GCStack);
+  object *head = cons(NULL, NULL);
   push(head,GCStack);
   object *tail = head;
-  if (list2 != NULL) {
-    list2 = car(list2);
-    object *result2 = list2;
-    while (list1 != NULL && list2 != NULL) {
-      if (improperp(list1)) error(MAPCAR, notproper2, result);
-      if (improperp(list2)) error(MAPCAR, notproper3, result2);
-      object *result = apply(MAPCAR, function, cons(car(list1), cons(car(list2),NULL)), env);
-      object *obj = cons(result,NULL);
-      cdr(tail) = obj;
-      tail = obj;
-      list1 = cdr(list1); list2 = cdr(list2);
+  // Make parameters
+  while (true) {
+    object *tailp = params;
+    object *lists = args;
+    while (lists != NULL) {
+      object *list = car(lists);
+      if (list == NULL) {
+         pop(GCStack);
+         pop(GCStack);
+         return cdr(head);
+      }
+      if (improperp(list)) error(MAPCAR, notproper, list);
+      object *obj = cons(first(list),NULL);
+      car(lists) = cdr(list);
+      cdr(tailp) = obj; tailp = obj;
+      lists = cdr(lists);
     }
-  } else if (list1 != NULL) {
-    while (list1 != NULL) {
-      if (improperp(list1)) error(MAPCAR, notproper2, result);
-      object *result = apply(MAPCAR, function, cons(car(list1),NULL), env);
-      object *obj = cons(result,NULL);
-      cdr(tail) = obj;
-      tail = obj;
-      list1 = cdr(list1);
-    }
-  }
-  pop(GCStack);
-  return cdr(head);
+    object *result = apply(MAPCAR, function, cdr(params), env);
+    object *obj = cons(result,NULL);
+    cdr(tail) = obj; tail = obj;
+  }
 }

 object *fn_mapcan (object *args, object *env) {
   object *function = first(args);
-  object *list1 = second(args);
-  object *result = list1;
-  object *list2 = cddr(args);
-  object *head = cons(NULL, NULL);
+  args = cdr(args);
+  object *params = cons(NULL, NULL);
+  push(params,GCStack);
+  object *head = cons(NULL, NULL);
   push(head,GCStack);
   object *tail = head;
-  if (list2 != NULL) {
-    list2 = car(list2);
-    object *result2 = list2;
-    while (list1 != NULL && list2 != NULL) {
-      if (improperp(list1)) error(MAPCAN, notproper2, result);
-      if (improperp(list2)) error(MAPCAN, notproper3, result2);
-      object *result = apply(MAPCAN, function, cons(car(list1), cons(car(list2),NULL)), env);
-      while ((unsigned int)result >= PAIR) {
-        cdr(tail) = result;
-        tail = result;
-        result = cdr(result);
+  // Make parameters
+  while (true) {
+    object *tailp = params;
+    object *lists = args;
+    while (lists != NULL) {
+      object *list = car(lists);
+      if (list == NULL) {
+         pop(GCStack);
+         pop(GCStack);
+         return cdr(head);
       }
-      if (cdr(list1) != NULL && cdr(list2) != NULL && result != NULL) error2(MAPCAN, PSTR("result is not a proper list"));
-      list1 = cdr(list1); list2 = cdr(list2);
+      if (improperp(list)) error(MAPCAN, notproper, list);
+      object *obj = cons(first(list),NULL);
+      car(lists) = cdr(list);
+      cdr(tailp) = obj; tailp = obj;
+      lists = cdr(lists);
     }
-  } else if (list1 != NULL) {
-    while (list1 != NULL) {
-      if (improperp(list1)) error(MAPCAN, notproper2, result);
-      object *result = apply(MAPCAN, function, cons(car(list1),NULL), env);
-      while ((unsigned int)result >= PAIR) {
-        cdr(tail) = result;
-        tail = result;
-        result = cdr(result);
-      }
-      if (cdr(list1) != NULL && result != NULL) error2(MAPCAN, PSTR("result is not a proper list"));
-      list1 = cdr(list1);
+    object *result = apply(MAPCAN, function, cdr(params), env);
+    while (consp(result)) {
+      cdr(tail) = result; tail = result;
+      result = cdr(result);
     }
-  }
-  pop(GCStack);
-  return cdr(head);
+    if (result != NULL) error(MAPCAN, resultproper, result);
+  }
 }

 // Arithmetic functions
@@ -2402,10 +2503,10 @@
   obj->type = STRING;
   GlobalString = NULL;
   GlobalStringIndex = 0;
-  char temp = PrintReadably;
-  PrintReadably = 0;
+  char temp = Flags;
+  clrflag(PRINTREADABLY);
   printobject(arg, pstr);
-  PrintReadably = temp;
+  Flags = temp;
   obj->cdr = GlobalString;
   return obj;
 }
@@ -2464,10 +2565,8 @@
   (void) env;
   int value = checkinteger(ASH, first(args));
   int count = checkinteger(ASH, second(args));
-  if (count >= 0)
-    return number(value << count);
-  else
-    return number(value >> abs(count));
+  if (count >= 0) return number(value << count);
+  else return number(value >> abs(count));
 }

 object *fn_logbitp (object *args, object *env) {
@@ -2538,10 +2637,10 @@
   (void) env;
   object *obj = first(args);
   pfun_t pfun = pstreamfun(cdr(args));
-  char temp = PrintReadably;
-  PrintReadably = 0;
+  char temp = Flags;
+  clrflag(PRINTREADABLY);
   printobject(obj, pfun);
-  PrintReadably = temp;
+  Flags = temp;
   return obj;
 }

@@ -2577,10 +2676,10 @@
   (void) env;
   object *obj = first(args);
   pfun_t pfun = pstreamfun(cdr(args));
-  char temp = PrintReadably;
-  PrintReadably = 0;
+  char temp = Flags;
+  clrflag(PRINTREADABLY);
   printstring(obj, pfun);
-  PrintReadably = temp;
+  Flags = temp;
   return nil;
 }

@@ -2588,11 +2687,11 @@
   (void) env;
   object *obj = first(args);
   pfun_t pfun = pstreamfun(cdr(args));
-  char temp = PrintReadably;
-  PrintReadably = 0;
+  char temp = Flags;
+  clrflag(PRINTREADABLY);
   printstring(obj, pfun);
   pln(pfun);
-  PrintReadably = temp;
+  Flags = temp;
   return nil;
 }

@@ -2652,7 +2751,7 @@
 object *fn_pinmode (object *args, object *env) {
   (void) env;
   int pin = checkinteger(PINMODE, first(args));
-  int pm = INPUT;
+  PinMode pm = INPUT;
   object *mode = second(args);
   if (integerp(mode)) {
     int nmode = checkinteger(PINMODE, mode);
@@ -2675,8 +2774,8 @@
   (void) env;
   int pin = checkinteger(DIGITALWRITE, first(args));
   object *mode = second(args);
-  if (integerp(mode)) digitalWrite(pin, mode->integer);
-  else digitalWrite(pin, (mode != nil));
+  if (integerp(mode)) digitalWrite(pin, mode->integer ? HIGH : LOW);
+  else digitalWrite(pin, (mode != nil) ? HIGH : LOW);
   return mode;
 }

@@ -2814,7 +2913,11 @@
     int name = arg->name;
     if (name == DEFUN) special = 2;
     else for (int i=0; i<ppspecials; i++) {
-      if (name == pgm_read_byte(&ppspecial[i])) { special = 1; break; }
+      #if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+      if (name == ppspecial[i]) { special = 1; break; }
+      #else
+      if (name == pgm_read_byte(&ppspecial[i])) { special = 1; break; }
+      #endif
     }
   }
   while (form != NULL) {
@@ -2917,23 +3020,23 @@
 const char string12[] PROGMEM = "defvar";
 const char string13[] PROGMEM = "setq";
 const char string14[] PROGMEM = "loop";
-const char string15[] PROGMEM = "push";
-const char string16[] PROGMEM = "pop";
-const char string17[] PROGMEM = "incf";
-const char string18[] PROGMEM = "decf";
-const char string19[] PROGMEM = "setf";
-const char string20[] PROGMEM = "dolist";
-const char string21[] PROGMEM = "dotimes";
-const char string22[] PROGMEM = "trace";
-const char string23[] PROGMEM = "untrace";
-const char string24[] PROGMEM = "for-millis";
-const char string25[] PROGMEM = "with-serial";
-const char string26[] PROGMEM = "with-i2c";
-const char string27[] PROGMEM = "with-spi";
-const char string28[] PROGMEM = "with-sd-card";
-const char string29[] PROGMEM = "tail_forms";
-const char string30[] PROGMEM = "progn";
-const char string31[] PROGMEM = "return";
+const char string15[] PROGMEM = "return";
+const char string16[] PROGMEM = "push";
+const char string17[] PROGMEM = "pop";
+const char string18[] PROGMEM = "incf";
+const char string19[] PROGMEM = "decf";
+const char string20[] PROGMEM = "setf";
+const char string21[] PROGMEM = "dolist";
+const char string22[] PROGMEM = "dotimes";
+const char string23[] PROGMEM = "trace";
+const char string24[] PROGMEM = "untrace";
+const char string25[] PROGMEM = "for-millis";
+const char string26[] PROGMEM = "with-serial";
+const char string27[] PROGMEM = "with-i2c";
+const char string28[] PROGMEM = "with-spi";
+const char string29[] PROGMEM = "with-sd-card";
+const char string30[] PROGMEM = "tail_forms";
+const char string31[] PROGMEM = "progn";
 const char string32[] PROGMEM = "if";
 const char string33[] PROGMEM = "cond";
 const char string34[] PROGMEM = "when";
@@ -3079,23 +3182,23 @@
   { string12, sp_defvar, 2, 2 },
   { string13, sp_setq, 2, 2 },
   { string14, sp_loop, 0, 127 },
-  { string15, sp_push, 2, 2 },
-  { string16, sp_pop, 1, 1 },
-  { string17, sp_incf, 1, 2 },
-  { string18, sp_decf, 1, 2 },
-  { string19, sp_setf, 2, 2 },
-  { string20, sp_dolist, 1, 127 },
-  { string21, sp_dotimes, 1, 127 },
-  { string22, sp_trace, 0, 1 },
-  { string23, sp_untrace, 0, 1 },
-  { string24, sp_formillis, 1, 127 },
-  { string25, sp_withserial, 1, 127 },
-  { string26, sp_withi2c, 1, 127 },
-  { string27, sp_withspi, 1, 127 },
-  { string28, sp_withsdcard, 2, 127 },
-  { string29, NULL, NIL, NIL },
-  { string30, tf_progn, 0, 127 },
-  { string31, tf_return, 0, 127 },
+  { string15, sp_return, 0, 127 },
+  { string16, sp_push, 2, 2 },
+  { string17, sp_pop, 1, 1 },
+  { string18, sp_incf, 1, 2 },
+  { string19, sp_decf, 1, 2 },
+  { string20, sp_setf, 2, 2 },
+  { string21, sp_dolist, 1, 127 },
+  { string22, sp_dotimes, 1, 127 },
+  { string23, sp_trace, 0, 1 },
+  { string24, sp_untrace, 0, 1 },
+  { string25, sp_formillis, 1, 127 },
+  { string26, sp_withserial, 1, 127 },
+  { string27, sp_withi2c, 1, 127 },
+  { string28, sp_withspi, 1, 127 },
+  { string29, sp_withsdcard, 2, 127 },
+  { string30, NULL, NIL, NIL },
+  { string31, tf_progn, 0, 127 },
   { string32, tf_if, 2, 3 },
   { string33, tf_cond, 0, 127 },
   { string34, tf_when, 1, 127 },
@@ -3140,9 +3243,9 @@
   { string73, fn_apply, 2, 127 },
   { string74, fn_funcall, 1, 127 },
   { string75, fn_append, 0, 127 },
-  { string76, fn_mapc, 2, 3 },
-  { string77, fn_mapcar, 2, 3 },
-  { string78, fn_mapcan, 2, 3 },
+  { string76, fn_mapc, 2, 127 },
+  { string77, fn_mapcar, 2, 127 },
+  { string78, fn_mapcan, 2, 127 },
   { string79, fn_add, 0, 127 },
   { string80, fn_subtract, 1, 127 },
   { string81, fn_multiply, 0, 127 },
@@ -3231,7 +3334,11 @@
 int builtin (char* n) {
   int entry = 0;
   while (entry < ENDFUNCTIONS) {
+    #if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+    if (strcasecmp(n, (char*)lookup_table[entry].string) == 0)
+    #else
     if (strcasecmp_P(n, (char*)pgm_read_word(&lookup_table[entry].string)) == 0)
+    #endif
       return entry;
     entry++;
   }
@@ -3253,20 +3360,36 @@
 }

 intptr_t lookupfn (symbol_t name) {
+  #if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+  return (intptr_t)lookup_table[name].fptr;
+  #else
   return pgm_read_word(&lookup_table[name].fptr);
+  #endif
 }

 uint8_t lookupmin (symbol_t name) {
+  #if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+  return lookup_table[name].min;
+  #else
   return pgm_read_byte(&lookup_table[name].min);
+  #endif
 }

 uint8_t lookupmax (symbol_t name) {
+  #if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+  return lookup_table[name].max;
+  #else
   return pgm_read_byte(&lookup_table[name].max);
+  #endif
 }

 char *lookupbuiltin (symbol_t name) {
   char *buffer = SymbolTop;
+  #if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+  strcpy(buffer, (char *)(lookup_table[name].string));
+  #else
   strcpy_P(buffer, (char *)(pgm_read_word(&lookup_table[name].string)));
+  #endif
   return buffer;
 }

@@ -3454,13 +3577,13 @@
 "Page\0Return\0SO\0SI\0DLE\0DC1\0DC2\0DC3\0DC4\0NAK\0SYN\0ETB\0CAN\0EM\0SUB\0Escape\0FS\0GS\0RS\0US\0Space\0";

 void pcharacter (char c, pfun_t pfun) {
-  if (!PrintReadably) pfun(c);
+  if (!tstflag(PRINTREADABLY)) pfun(c);
   else {
     pfun('#'); pfun('\\');
     if (c > 32) pfun(c);
     else {
-      PGM_P p = ControlCodes;
-      while (c > 0) {p = p + strlen_P(p) + 1; c--; }
+      const char *p = ControlCodes;
+      while (c > 0) {p = p + strlen(p) + 1; c--; }
       pfstring(p, pfun);
     }
   }
@@ -3471,24 +3594,28 @@
 }

 void printstring (object *form, pfun_t pfun) {
-  if (PrintReadably) pfun('"');
+  if (tstflag(PRINTREADABLY)) pfun('"');
   form = cdr(form);
   while (form != NULL) {
     int chars = form->integer;
     for (int i=(sizeof(int)-1)*8; i>=0; i=i-8) {
       char ch = chars>>i & 0xFF;
-      if (PrintReadably && (ch == '"' || ch == '\\')) pfun('\\');
+      if (tstflag(PRINTREADABLY) && (ch == '"' || ch == '\\')) pfun('\\');
       if (ch) pfun(ch);
     }
     form = car(form);
   }
-  if (PrintReadably) pfun('"');
+  if (tstflag(PRINTREADABLY)) pfun('"');
 }

 void pfstring (PGM_P s, pfun_t pfun) {
-  intptr_t p = (intptr_t)s;
+  int p = 0;
   while (1) {
-    char c = pgm_read_byte(p++);
+    #if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+    char c = s[p++];
+    #else
+    char c = pgm_read_byte(&s[p++]);
+    #endif
     if (c == 0) return;
     pfun(c);
   }
@@ -3559,7 +3686,11 @@
     LastChar = 0;
     return temp;
   }
+  #if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+  char c = LispLibrary[GlobalStringIndex++];
+  #else
   char c = pgm_read_byte(&LispLibrary[GlobalStringIndex++]);
+  #endif
   return (c != 0) ? c : -1; // -1?
 }

@@ -3646,8 +3777,13 @@
     if (index == 1) return character(buffer[0]);
     PGM_P p = ControlCodes; char c = 0;
     while (c < 33) {
+      #if defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3216__)
+      if (strcasecmp(buffer, p) == 0) return character(c);
+      p = p + strlen(p) + 1; c++;
+      #else
       if (strcasecmp_P(buffer, p) == 0) return character(c);
       p = p + strlen_P(p) + 1; c++;
+      #endif
     }
     error2(0, PSTR("Unknown character"));
   }
@@ -3702,12 +3838,16 @@

 void setup () {
   Serial.begin(9600);
+  #if defined(ARDUINO_AVR_NANO_EVERY) || defined(__AVR_ATtiny3216__)
+  delay(2500);
+  #else
   int start = millis();
-  while (millis() - start < 5000) { if (Serial) break; }
+  while ((millis() - start) < 5000) { if (Serial) break; }
+  #endif
   initworkspace();
   initenv();
   initsleep();
-  pfstring(PSTR("uLisp 2.8 "), pserial); pln(pserial);
+  pfstring(PSTR("uLisp 2.9 "), pserial); pln(pserial);
 }

 // Read/Evaluate/Print loop


allow to set time properly. No error correction on date, it must be set correctly.

--- vibrate_alarm_clock.ino
+++ vibrate_alarm_clock.ino
@@ -26,7 +26,7 @@
 typedef enum {NORMAL, ALARM, SETTING_TIME, SETTING_ALARM} CLOCK_STATE ;
 CLOCK_STATE currentState = NORMAL;

-typedef enum {T_HOUR, T_MINUTE, T_SECOND, T_YEAR, T_MONTH, T_DAY} SETTING_TIME_STATE ;
+typedef enum {T_HOUR, T_MINUTE, T_SECOND, T_DAY, T_MONTH, T_YEAR} SETTING_TIME_STATE ;
 SETTING_TIME_STATE settingTimeProcess;

 typedef enum {A_HOUR, A_MINUTE, A_TYPE} SETTING_ALARM_STATE ;
@@ -161,6 +161,34 @@
   }
   break;
   case SETTING_TIME:
+  {
+    DateTime now = RTC.now();
+    DateTime newTime;
+    switch(settingTimeProcess){
+      case T_HOUR:
+        newTime = DateTime(now.year(), now.month(), now.day(), getNextHourFromCurrentHour(now.hour(), false), now.minute(), now.second());
+        break;
+      case T_MINUTE:
+        newTime = DateTime(now.year(), now.month(), now.day(), now.hour(), getNextMinSecFromCurrentMinSec(now.minute(), false), now.second());
+        break;
+      case T_SECOND:
+        newTime = DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), getNextMinSecFromCurrentMinSec(now.second(), false));
+        break;
+      case T_DAY:
+        newTime = DateTime(now.year(), now.month(), now.day() - 1, now.hour(), now.minute(), now.second());
+        break;
+      case T_MONTH:
+        newTime = DateTime(now.year(), now.month() - 1, now.day(), now.hour(), now.minute(), now.second());
+        break;
+      case T_YEAR:
+        newTime = DateTime(now.year() - 1, now.month(), now.day(), now.hour(), now.minute(), now.second());
+        break;
+      default: break;
+
+    }
+
+    RTC.adjust(newTime);
+  }
   break;
   default: break;
   }
@@ -290,6 +318,36 @@
     }
     break;
     case SETTING_TIME:
+      {
+    DateTime now = RTC.now();
+    DateTime newTime;
+    switch(settingTimeProcess){
+      case T_HOUR:
+        newTime = DateTime(now.year(), now.month(), now.day(), getNextHourFromCurrentHour(now.hour(), true), now.minute(), now.second());
+        break;
+      case T_MINUTE:
+        newTime = DateTime(now.year(), now.month(), now.day(), now.hour(), getNextMinSecFromCurrentMinSec(now.minute(), true), now.second());
+        break;
+      case T_SECOND:
+        newTime = DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), getNextMinSecFromCurrentMinSec(now.second(), true));
+        break;
+      case T_DAY:
+        newTime = DateTime(now.year(), now.month(), now.day() + 1, now.hour(), now.minute(), now.second());
+        break;
+      case T_MONTH:
+        newTime = DateTime(now.year(), now.month() + 1, now.day(), now.hour(), now.minute(), now.second());
+        break;
+      case T_YEAR:
+        newTime = DateTime(now.year() + 1, now.month(), now.day(), now.hour(), now.minute(), now.second());
+        break;
+      default: break;
+
+    }
+
+    RTC.adjust(newTime);
+  }
+
+
     break;
     default: break;
   }
@@ -531,7 +589,9 @@
   if(currentState == SETTING_TIME && settingTimeProcess == T_DAY && !blinkOn){
     dayString = "  ";
   } else {
-    dayString = String(day);
+    char buff[3];
+    sprintf(buff, "%02d", day);
+    dayString = buff;
   }

   if(currentState == SETTING_TIME && settingTimeProcess == T_MONTH && !blinkOn){


Add heartbeat

Add heartbeat

--- hvacMonitor.ino
+++ hvacMonitor.ino
@@ -19,6 +19,8 @@

 SimpleTimer timer;

+WidgetLED led1(V2);
+
 WidgetLCD lcd(V5);

 WidgetRTC rtc;
@@ -46,6 +48,7 @@

   timer.setInterval(2500L, sendTemps); // Temperature sensor polling interval
   timer.setInterval(2500L, sendLCDstatus); // Blower fan status polling interval
+  timer.setInterval(5000L, sendHeartbeat); // Blinks Blynk LED to reflect online status

   while (Blynk.connect() == false) {
     // Wait until connected
@@ -94,6 +97,7 @@
   {
     Blynk.virtualWrite(1, "ERR");
   }
+  led1.off();
 }

 void sendLCDstatus()
@@ -101,10 +105,10 @@
   if (digitalRead(blowerPin) == HIGH) // Runs when blower is OFF.
   {
     //lcd.clear();
-    lcd.print(0, 0, " HVAC OFF since");
+    lcd.print(0, 0, " HVAC OFF since  ");
     if (offHour < 10)
     {
-      lcd.print(1, 1, offHour);
+      lcd.print(0, 1, String(" ") + offHour); // Since lcd.clear() is not used, this space overwrites old data.
     }
     else
     {
@@ -129,23 +133,24 @@
     {
       lcd.print(5, 1, "PM on");
     }
+
     if (offMonth < 10)
     {
       lcd.print(11, 1, offMonth);
       lcd.print(12, 1, "/");
-      lcd.print(13, 1, offDay);
+      lcd.print(13, 1, offDay + String("  ")); // Since lcd.clear() is not used, this space overwrites old data.
     }
     else
     {
       lcd.print(11, 1, offMonth);
       lcd.print(13, 1, "/");
-      lcd.print(14, 1, offDay);
+      lcd.print(14, 1, offDay + String("  ")); // Since lcd.clear() is not used, this space overwrites old data.
     }
   }
   else
   {
     //lcd.clear(); // Runs when blower is ON.
-    lcd.print(0, 0, " HVAC ON since ");
+    lcd.print(0, 0, "  HVAC ON since  ");
     if (onHour < 10)
     {
       lcd.print(1, 1, onHour);
@@ -206,6 +211,11 @@
   }
 }

+void sendHeartbeat()
+{
+  led1.on();
+}
+
 void loop()
 {
   Blynk.run();