better calculation

better calculation

--- testing/arduino/omniwheel4_EncoderD.ino
+++ testing/arduino/omniwheel4_EncoderD.ino
@@ -96,12 +96,12 @@

 void Calibration()
 {
-    if (initState >= 2)
+    if (initState >= 3)
     {
         return;
     }

-    int time = millis();
+    uint16_t time = millis();

     if(initState == 0)
     {
@@ -116,20 +116,46 @@
         initState = 1;
     }

-
-    int delta = 150;
-    if (initState == 1 && initTimestamp + delta <= time && initSpeed == 255)
+    uint8_t delta = 150;
+    if (initState == 1 && initTimestamp + delta*2 <= time)
+    {
+        motor1_RPMCount = 0;
+        motor2_RPMCount = 0;
+        motor3_RPMCount = 0;
+
+        initTimestamp = time;
+       initState = 2;
+    }
+
+
+    if (initState == 2 && initTimestamp + delta <= time && initSpeed == 255)
     {
         motor1_MaxRPM = motor1_RPMCount;
         motor2_MaxRPM = motor2_RPMCount;
         motor3_MaxRPM = motor3_RPMCount;
     }

-    if (initState == 1 && initTimestamp + delta <= time && initSpeed > 0)
-    {
-        SpeedMapping_Motor1[initSpeed] = 255 / motor1_MaxRPM * motor1_RPMCount;
-        SpeedMapping_Motor2[initSpeed] = 255 / motor2_MaxRPM * motor2_RPMCount;
-        SpeedMapping_Motor3[initSpeed] = 255 / motor3_MaxRPM * motor3_RPMCount;
+    if (initState == 2 && initTimestamp + delta <= time && initSpeed > 0)
+    {
+        //SpeedMapping_Motor1[initSpeed] = 255 * motor1_RPMCount / motor1_MaxRPM;
+        //SpeedMapping_Motor2[initSpeed] = 255 * motor2_RPMCount / motor2_MaxRPM;
+        //SpeedMapping_Motor3[initSpeed] = 255 * motor3_RPMCount / motor3_MaxRPM;
+
+       if(SpeedMapping_Motor1[255 * motor1_RPMCount / motor1_MaxRPM] == 0)
+       {
+             SpeedMapping_Motor1[255 * motor1_RPMCount / motor1_MaxRPM] = initSpeed;
+       }
+
+       if(SpeedMapping_Motor2[255 * motor2_RPMCount / motor2_MaxRPM] == 0)
+       {
+             SpeedMapping_Motor2[255 * motor2_RPMCount / motor2_MaxRPM] = initSpeed;
+       }
+
+       if(SpeedMapping_Motor3[255 * motor3_RPMCount / motor3_MaxRPM] == 0)
+       {
+             SpeedMapping_Motor3[255 * motor3_RPMCount / motor3_MaxRPM] = initSpeed;
+       }
+

         // 12:  255 - 245 - 235 - 225 - 215 - 205 - 195 - 185 - 175 - 165 - 155 - 145
         if (initSpeed > 150)
@@ -158,9 +184,9 @@
     }

-    if (initState == 1 && initSpeed == 0)
-    {
-        initState = 2;
+    if (initState == 2 && initSpeed == 0)
+    {
+        initState = 3;
         for(int i = 0; i < SpeedMappingSize; i++)
         {
             Serial.print(i);


swap libs, show afr/tgt

swap libs, show afr/tgt

--- main/main.ino
+++ main/main.ino
@@ -1,8 +1,8 @@
-#include <Canbus.h>
-#include <defaults.h>
+#include <mcp_can.h>
+#include <mcp_can_dfs.h>
+
+
 #include <global.h>
-#include <mcp2515.h>
-#include <mcp2515_defs.h>
 #include <LiquidCrystal.h>
 #include <math.h>

@@ -72,13 +72,14 @@
 unsigned long lastMillis = 0;
 unsigned long currentMillis = 0;

-tCAN message;
 int messageReceived;
-
-tCAN emtpyMessage;

 unsigned long goodDataCount = 0;
 unsigned long badDataCount = 0;
+
+const int SPI_CS_PIN = 10;
+
+MCP_CAN CAN(SPI_CS_PIN);

 void setup() {

@@ -94,14 +95,66 @@
   lcd.print("TGT");

   Serial.begin(115200);
-  int can_init = mcp2515_init(1); //CANSPEED_500 = 1
+  while (CAN_OK != CAN.begin(CAN_500KBPS))              // init can bus : baudrate = 500k
+      {
+          Serial.println("CAN BUS Shield init fail");
+          Serial.println(" Init CAN BUS Shield again");
+          delay(100);
+      }
+  Serial.println("CAN BUS Shield init ok!");
 }

 void loop() {

-  ecu_req(&message);
+  //message->id = 0x5ea; //group 1514 //0x5e8;
+  //message->header.rtr = 0;
+  //message->header.length = 8;

   currentMillis = millis();
+  if(currentMillis - lastMillis >= interval) {
+    lastMillis = currentMillis;
+    lcd.setCursor(4, 2);
+    lcd.print(tgt);
+    draw_bar(tgt, 3, 10.0, 20.0);
+
+    lcd.setCursor(4, 0);
+    lcd.print(afr);
+    draw_bar(afr, 1, 10.0, 20.0);
+
+    //Serial.println(tgt);
+    //Serial.println((double)badDataCount / (double)goodDataCount);
+
+  }
+
+  unsigned char len = 0;
+  unsigned char buf[8];
+
+
+  if(CAN_MSGAVAIL == CAN.checkReceive())            // check if data coming
+  {
+        CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf
+
+        unsigned int canId = CAN.getCanId();
+
+
+
+        if(canId == 1514) {
+          Serial.println("-----------------------------");
+          Serial.print("Get data from ID: ");
+          Serial.println(canId, HEX);
+          tgt = (double)buf[0] / 10.0;
+          afr = (double)buf[1] / 10.0;
+          for(int i = 0; i<2; i++)    // print the data
+          {
+              Serial.print(buf[i]);
+              Serial.print("\t");
+          }
+          Serial.println();
+        }
+
+
+  }
+

   if(messageReceived == 1) {
     if(currentMillis - lastMillis >= interval) {
@@ -123,6 +176,8 @@

 void draw_bar(double value, int row, double minimum, double maximum) {
   lcd.setCursor(0, row);
+  lcd.write("                    ");
+  lcd.setCursor(0, row);
   int bars = ((value - minimum) * 100) / (maximum - minimum);
   int fullBars = bars/5;
   int partialBars = bars % 5;
@@ -135,36 +190,3 @@
   }
 }

-void ecu_req(tCAN *message)
-{
-  message->id = 0x5ea; //group 1514 //0x5e8;
-  message->header.rtr = 0;
-  message->header.length = 8;
-
-  mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), 0);
-  //Serial.println("trying to get data");
-  if(mcp2515_check_message()) {
-
-    //Serial.print("there is a message ");
-    mcp2515_get_message(message);
-
-    if(message->data[0] >= 100) {
-        tgt = (double)message->data[0] / 10.0;
-        //Serial.print("good data ");
-        //Serial.println(tgt);
-        goodDataCount++;
-    }
-    else {
-      ///Serial.println("bad data ");
-      badDataCount++;
-    }
-
-    messageReceived = 1;
-  }
-  else {
-    messageReceived = 0;
-    //Serial.println("no data");
-  }
-
-}
-


Delete Arduino.ino

Delete Arduino.ino

--- Arduino.ino
+++ Arduino.ino
@@ -1,186 +0,0 @@
-#include <Wire.h>
-#include <Stepper.h>
-
-Stepper motor(200,4,5,6,7);
-
-double PSARJdiff = 0.00;
-double oldPSARJstep = 0.00;
-boolean startup = true;
-double oldangle = 0.00;
-double oldPSARJ = 0.00;
-double PSARJcheck = 0.00;
-double PSARJstep = 0.00;
-double Beta1B = 0.0;
-double Beta2B = 0.0;
-double Beta3B = 0.0;
-double Beta4B = 0.0;
-double Beta1A = 0.0;
-double Beta2A = 0.0;
-double Beta3A = 0.0;
-double Beta4A = 0.0;
-double PSARJ = 0.0;
-double SSARJ = 0.0;
-double PTRRJ = 0.0;
-double STRRJ = 0.0;
-boolean AOS = false;
-
-void setup()
-{
-  Wire.begin(4);                // join i2c bus with address #4
-  Wire.onReceive(receiveEvent); // register event
-  Serial.begin(9600);           // start serial for output
-  motor.setSpeed(10);  // 10 rpm
-  startup = true;
-}
-
-void loop()
-{
-  delay(200);
-  /*
-  //delay(1000);
-  //Serial.print("PSARJ ");
-  //Serial.println(PSARJ);  //print the I2C received value
-  Serial.print("SSARJ ");
-  Serial.println(SSARJ);
-  Serial.print("PTRRJ ");
-  Serial.println(PTRRJ);
-  Serial.print("STRRJ ");
-  Serial.println(STRRJ);
-  Serial.print("Beta1B ");
-  Serial.println(Beta1B);
-  Serial.print("Beta2B ");
-  Serial.println(Beta2B);
-  Serial.print("Beta3B ");
-  Serial.println(Beta3B);
-  Serial.print("Beta4B ");
-  Serial.println(Beta4B);
-  Serial.print("Beta1A ");
-  Serial.println(Beta1A);
-  Serial.print("Beta2A ");
-  Serial.println(Beta2A);
-  Serial.print("Beta3A ");
-  Serial.println(Beta3A);
-  Serial.print("Beta4A ");
-  Serial.println(Beta4A);
-  Serial.print("AOS ");
-  Serial.println(AOS);
-
- */
-
-  PSARJdiff = abs(PSARJ - oldPSARJ);
-  Serial.print("PSARJdiff: ");
-  Serial.println(PSARJdiff);
-  if(startup)
-  {
-    oldPSARJ = PSARJ;
-    PSARJstep = ((200.00/360.00)*PSARJ);
-    startup = false;
-    motor.step(PSARJstep);
-    Serial.print("startup & step");
-    Serial.println(PSARJstep);
-  }
-
-  if(!startup && (PSARJdiff > 1)) //check if the angle is different
-  {
-    PSARJstep = ((200.00/360.00)*PSARJ);
-    oldPSARJstep = ((200.00/360.00)*oldPSARJ);
-    double newstep = PSARJstep - oldPSARJstep;
-    motor.step(newstep);
-
-    Serial.print("new step");
-    Serial.println(newstep);
-    oldPSARJ = PSARJ;
-  }
-
-}
-
-void receiveEvent(int howMany)
-{
-  String test = "";
-  while(1 < Wire.available()) // loop through all but the last
-  {
-    char c = Wire.read(); // receive byte as a character
-    test += c;
-
-  }
-  Serial.println(test);
-
-  PSARJ = test.toFloat();
-
-  //int spaceindex = test.indexOf(' ');
-  //String test2 = "";
-  //test2 = test.substring(spaceindex+1);
-
-  //int decimalindex = test2.indexOf('.');
-
-  /*
-  if(test.substring(0,5)=="PSARJ")
-  {
-    PSARJ = test2.substring(0,decimalindex+2).toFloat();
-  }
-  if(test.substring(0,5)=="SSARJ")
-  {
-    SSARJ = test2.substring(0,decimalindex+2).toFloat();
-  }
-  if(test.substring(0,5)=="PTRRJ")
-  {
-    PTRRJ = test2.substring(0,decimalindex+2).toFloat();
-  }
-  if(test.substring(0,5)=="STRRJ")
-  {
-    STRRJ = test2.substring(0,decimalindex+2).toFloat();
-  }
-  if(test.substring(0,6)=="Beta1B")
-  {
-    Beta1B = test2.substring(0,decimalindex+2).toFloat();
-  }
-  if(test.substring(0,6)=="Beta2B")
-  {
-    Beta2B = test2.substring(0,decimalindex+2).toFloat();
-  }
-  if(test.substring(0,6)=="Beta3B")
-  {
-    Beta3B = test2.substring(0,decimalindex+2).toFloat();
-  }
-  if(test.substring(0,6)=="Beta4B")
-  {
-    Beta4B = test2.substring(0,decimalindex+2).toFloat();
-  }
-  if(test.substring(0,6)=="Beta1A")
-  {
-    Beta1A = test2.substring(0,decimalindex+2).toFloat();
-  }
-  if(test.substring(0,6)=="Beta2A")
-  {
-    Beta2A = test2.substring(0,decimalindex+2).toFloat();
-  }
-  if(test.substring(0,6)=="Beta3A")
-  {
-    Beta3A = test2.substring(0,decimalindex+2).toFloat();
-  }
-  if(test.substring(0,6)=="Beta4A")
-  {
-    Beta4A = test2.substring(0,decimalindex+2).toFloat();
-  }
-  if(test.substring(0,3)=="AOS")
-  {
-    Serial.println(test);
-    if(test.substring(4)=="Siqnal Acquire")
-    {
-      AOS = true;
-      //Serial.println("AOS true!");
-    }
-    else
-    {
-      AOS = false;
-      //Serial.println("AOS false!");
-      //Serial.println(test);
-    }
-  }
-  */
-
-  int x = Wire.read();    // receive byte as an integer
-  //Serial.println(x);         // print the integer
-  //Serial.println();
-  Serial.flush();
-}


added get time

added get time

--- SprayCan/SprayCanProject/SprayCanProject.ino
+++ SprayCan/SprayCanProject/SprayCanProject.ino
@@ -33,11 +33,23 @@
   // #include "cont.h"
 }

+
+// Time related Valriables
+unsigned int localPort = 2390;      // local port to listen for UDP packets
+IPAddress timeServerIP; // time.nist.gov NTP server address
+const char* ntpServerName = "time.nist.gov";
+const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
+byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
+WiFiUDP udp;
+unsigned int hh = 0;
+unsigned int mm = 0;
+unsigned int ss = 0;
+
 void setup() {

   WiFi.forceSleepBegin();
-  yield();
-
+  yield();
+
 #ifdef SERIAL_DEBUG
   Serial.begin(74880);
   delay(10);
@@ -51,11 +63,16 @@
   delay(100);

   if (connectToInternet()) {
+    getTime();
     delay(1000);
     disconnectInternet();
   }

 }
+
+//
+//  INTERNET RELATED CODE
+//

 bool connectToInternet() {
   uint32_t time1 = millis();
@@ -73,10 +90,9 @@
     count += 1;
     if (count > 100) {
       return false;
-      Serial.println("");
     }
   }
-
+
   uint32_t time2 = millis();

   Serial.println("");
@@ -84,6 +100,7 @@
   Serial.println(time2 - time1);
   Serial.println("IP address: ");
   Serial.println(WiFi.localIP());
+
   return true;

 }
@@ -95,3 +112,86 @@
   yield();
 }

+//
+//  TIME RELATED CODE
+//
+
+unsigned long getTime() {
+
+  Serial.println("Starting UDP");
+
+  int hh = 0;
+  int mm = 0;
+  int ss = 0;
+
+  udp.begin(localPort);
+
+  //get a random server from the pool
+  WiFi.hostByName(ntpServerName, timeServerIP);
+
+  sendNTPpacket(timeServerIP); // send an NTP packet to a time server
+  // wait to see if a reply is available
+
+  int cb = udp.parsePacket();
+
+  for (int i = 0; i <= 100; i++) {
+    if (!cb) {
+      cb = udp.parsePacket();
+      delay(10);
+    } else {
+      break;
+    }
+  }
+
+
+  if (!cb) {
+    Serial.println("no packet yet");
+    // ESP.deepSleep(10e6, WAKE_RFCAL);
+  }
+  else {
+    udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
+
+    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
+    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
+    unsigned long secsSince1900 = highWord << 16 | lowWord;
+
+    const unsigned long seventyYears = 2208988800UL;
+    unsigned long epoch = secsSince1900 - seventyYears;
+
+    hh = ((((epoch  % 86400L) / 3600) + 11) % 24);
+    mm = (epoch  % 3600) / 60;
+    ss = epoch % 60;
+    Serial.print("time:");
+    Serial.print(hh);
+    Serial.print(':');
+    Serial.print(mm);
+    Serial.print(':');
+    Serial.print(ss);
+    Serial.println("");
+  }
+
+}
+// send an NTP request to the time server at the given address
+unsigned long sendNTPpacket(IPAddress& address)
+{
+  Serial.println("sending NTP packet...");
+  // set all bytes in the buffer to 0
+  memset(packetBuffer, 0, NTP_PACKET_SIZE);
+  // Initialize values needed to form NTP request
+  // (see URL above for details on the packets)
+  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
+  packetBuffer[1] = 0;     // Stratum, or type of clock
+  packetBuffer[2] = 6;     // Polling Interval
+  packetBuffer[3] = 0xEC;  // Peer Clock Precision
+  // 8 bytes of zero for Root Delay & Root Dispersion
+  packetBuffer[12]  = 49;
+  packetBuffer[13]  = 0x4E;
+  packetBuffer[14]  = 49;
+  packetBuffer[15]  = 52;
+
+  // all NTP fields have been given values, now
+  // you can send a packet requesting a timestamp:
+  udp.beginPacket(address, 123); //NTP requests are to port 123
+  udp.write(packetBuffer, NTP_PACKET_SIZE);
+  udp.endPacket();
+}


esp8266_160602_udpTxToLogger > increase connection retry from 6 to 10

--- esp8266_160602_udpTxToLogger.ino
+++ esp8266_160602_udpTxToLogger.ino
@@ -3,6 +3,7 @@

 /*
  * v0.2 2016 Jun. 26
+ *   - increase connection retry from 6 to 10
  *   - increase connection retry from 3 to 6
  *   - disconnect WiFi when WiFi connection failed
  *   - modify WiFi_setup() to avoid endless while loop
@@ -29,7 +30,7 @@
 {
   WiFi.begin(kWifiSsid, kWifiPass);

-  for(int loop = 0; loop < 6; loop++) {
+  for(int loop = 0; loop < 10; loop++) {
     if (WiFi.status() == WL_CONNECTED) {
       s_isWiFiConnected = true;
       break;


Fixed errors.

Fixed errors.

--- mech/mech.ino
+++ mech/mech.ino
@@ -56,6 +56,7 @@
   pinMode(ledPin, OUTPUT);              // Defines LED
   pinMode(optInpin1, INPUT);            //  Defines Optical command PIN "L"
   pinMode(optInpin2, INPUT);            //  Defines Optical command PIN "C"
+  pinMode(optInpin3, INPUT);            //  Defines Optical command PIN "C2"

   stepper1.setMaxSpeed(2000);           //  Set maximum roration speed for "L" Motor 1
   stepper1.setSpeed(500);               //  Set maximum calibration speed for "L" Motor 1
@@ -152,5 +153,6 @@
   busLoop();
   stepper1.run();
   stepper2.run();
+  stepper3.run();
   digitalWrite(ledPin, digitalRead(optInpin1));
 }


fix anto.mqtt.connect() arguments

fix anto.mqtt.connect() arguments

--- examples/BasicMQTT/BasicMQTT.ino
+++ examples/BasicMQTT/BasicMQTT.ino
@@ -41,7 +41,7 @@
   //
   // Secured connection will be
   // slower than secured one.
-  while (!anto.mqtt.connect(user, token, true));
+  while (!anto.mqtt.connect(true));
   Serial.println("\nConnected");

   anto.mqtt.onData(messageReceived);


expand RouterReset_Yun to include reset of the router

--- RouterReset_Yun/RouterReset_Yun.ino
+++ RouterReset_Yun/RouterReset_Yun.ino
@@ -3,20 +3,31 @@
  * red LED (internet down): pin 3
  * green LED (internet up): pin 5
  * yellow LED (testing):    pin 6
+ *
  *
  * needs checkInternet.py installed in /usr/bin in Yun Linino
  */

 #include <Process.h>

-const int redLED = 3;
-const int greenLED = 5;
-const int yellowLED = 6;
+const int redLED     = 3;
+const int greenLED   = 5;
+const int yellowLED  = 6;
+const int routerPin1 = 8;
+const int routerPin2 = 9;
+const int resetRouterTime = 30000;
+const int timeBetweenPings = 5000;
+
+String internetStatus;

 void setup() {
     pinMode(redLED, OUTPUT);
     pinMode(greenLED, OUTPUT);
     pinMode(yellowLED, OUTPUT);
+    pinMode(routerPin1, OUTPUT);
+    pinMode(routerPin2, OUTPUT);
+    digitalWrite(routerPin1, HIGH);
+    digitalWrite(routerPin2, HIGH);

     Bridge.begin();  // make contact with the linux processor

@@ -35,28 +46,35 @@
     digitalWrite(yellowLED, HIGH);
     internetCheck.runShellCommand("/usr/bin/checkInternet.py");

-    while(internetCheck.available() > 0)
+    internetStatus = "";
+    while(internetCheck.available() > 0) {
+      char c = internetCheck.read();
+      if(c != '\n') internetStatus += c;
+    }
+
+    if(internetStatus[0] == '1')
     {
-        char c = internetCheck.read();
-
-        if(c == '1')
-        {
-            digitalWrite(redLED, LOW);
-            digitalWrite(greenLED, HIGH);
-            break;
-        }
-        else if(c == '0')
-        {
-            digitalWrite(redLED, HIGH);
-            digitalWrite(greenLED, LOW);
-            break;
-        }
+        digitalWrite(redLED, LOW);
+        digitalWrite(greenLED, HIGH);
+    }
+    else if(internetStatus[0] == '0')
+    {
+        digitalWrite(redLED, HIGH);
+        digitalWrite(greenLED, LOW);
     }

-    while(internetCheck.available() > 0) // read everything else
-        internetCheck.read();
-
     digitalWrite(yellowLED, LOW);

-    delay(5000);
+    if(internetStatus[0] == '0')
+        resetRouter();
+    else
+        delay(timeBetweenPings);
 }
+
+void resetRouter(void) {
+  digitalWrite(routerPin1, LOW);
+  digitalWrite(routerPin2, LOW);
+  delay(resetRouterTime);
+  digitalWrite(routerPin1, HIGH);
+  digitalWrite(routerPin2, HIGH);
+}


Removing Infinite Loop from Exp.5

Removing Infinite Loop from Exp.5

Infinite While loop was causing errors on Exp. 5. Moved single play-through of song to the setup loop.

--- 05-MusicTime/Code/05-MusicTime/MusicTime.ino
+++ 05-MusicTime/Code/05-MusicTime/MusicTime.ino
@@ -40,11 +40,8 @@
 void setup()
 {
   pinMode(speakerPin, OUTPUT);
-}
-
-
-void loop()
-{
+
+  // We only want to play the song once, so we'll put it in the setup loop
   int i, duration;

   for (i = 0; i < songLength; i++) // step through the song arrays
@@ -62,11 +59,14 @@
     }
     delay(tempo/10);              // brief pause between notes
   }
+
+  //If you want your song to loop forever, place that code in the lopp() below.
+}

-  // We only want to play the song once, so we'll pause forever:
-  while(true){}
-  // If you'd like your song to play over and over,
-  // remove the above statement
+
+void loop()
+{
+//do nothing
 }


try to fix bluetooth throttle calc

try to fix bluetooth throttle calc

--- longboard-ctl.ino
+++ longboard-ctl.ino
@@ -156,7 +156,7 @@
                 errorStop();
                 break;
             case 'G':
-                throttleBluetoothOut = 126 + constrain(Bluetooth.parseInt()*1.26, 0, 126);
+                throttleBluetoothOut = (int)(126.0 + constrain((float)Bluetooth.parseInt()*1.26, 0.0, 126.0));
                 break;
             default:
                 break;


calculation tweak, trick avoids divide by zero

--- examples/RF12/radioBlip2/radioBlip2.ino
+++ examples/RF12/radioBlip2/radioBlip2.ino
@@ -34,7 +34,7 @@
   bitClear(ADCSRA, ADIE);
   // convert ADC readings to fit in one byte, i.e. 20 mV steps:
   //  1.0V = 0, 1.8V = 40, 3.3V = 115, 5.0V = 200, 6.0V = 250
-  return (55U * 1023U) / (ADC + 1) - 50;
+  return (55U * 1024U) / (ADC + 1) - 50;
 }

 void setup() {


Update Esp32-mqtt.ino (#29)

Update Esp32-mqtt.ino (#29)

Fix array out of bounds

--- examples/Esp32-mqtt/Esp32-mqtt.ino
+++ examples/Esp32-mqtt/Esp32-mqtt.ino
@@ -23,7 +23,7 @@
 #define MQTT_MAX_PACKET_SIZE 512
 #include <PubSubClient.h>

-NN_DIGIT priv_key[8];
+NN_DIGIT priv_key[9];
 const char *host = "mqtt.googleapis.com";
 const int httpsPort = 8883;
 // const int httpsPort = 443;


otra pequeña modificacion que no cambia el funcionamiento

--- Arduino/src/sketch.ino
+++ Arduino/src/sketch.ino
@@ -168,6 +168,7 @@
   String estado = hashTable.getString("estado");
   String sensor = hashTable.getString("sensor");
   int grados = hashTable.getLong("grados");
+  //No hago nada aun.
 }
 void accionesIluminacion(JsonHashTable hashTable){
   int pin = hashTable.getLong("id");


Have quadcopter loiter wherever it was when altitude mode was activated

--- examples/quadcopter/quadcopter.ino
+++ examples/quadcopter/quadcopter.ino
@@ -134,6 +134,7 @@
             comms.sendString("Alt Hold");
             altitudeHold.setup(outputThrottle);
             altitudeSetpoint = altitude.getAltitude();
+            positionHold.setTarget(gps.getLocation());
             altHoldEnabled = true;
         }

@@ -192,8 +193,8 @@
     [](){ return power.getAmperage(); },           //AMPERAGE
     [](){ return altitude.getAltitude(); },        //ALTITUDE

-    /*[](){ return 1E6f/averageInterval; },
-
+    /*
+    [](){ return 1E6f/averageInterval; },
     [](){ return gps.getCourse(); },
     [](){ return gps.getGroundSpeed(); },
     [](){ return positionHold.distance; },
@@ -203,7 +204,8 @@
     [](){ return proutput.pitch; },
     [](){ return proutput.roll; },
     [](){ return radioPitch; },
-    [](){ return radioRoll; },*/
+    [](){ return radioRoll; },
+    */
 };

 const uint8_t telemetryTotal =


update controller program

update controller program

--- tank/src/sketch.ino
+++ tank/src/sketch.ino
@@ -1,9 +1,49 @@
+/*--------------------------------------
+Description:
+	Arduino Tank Program
+Arduino Board:
+	all
+Use Pin:
+	OUTPUT:
+		1~15
+	INPUT:
+		0
+  -------------------------------------*/
+
 #include <Servo.h>

 #define MAX 250
 #define NOM 50

 #define BaudRate (115200)
+
+#define debug false
+
+//発射状況
+bool launchMode = false;
+
+bool launchButtonReleased = true;
+//発射開始時刻
+unsigned long launchStart = 0;
+//発射完了時刻
+unsigned long launchEnd = 0;
+//一時保存用
+unsigned long launchTempTime;
+
+
+//発射開始～発射終了までの時間
+const unsigned long start2endT = 1000000ul;
+//発射終了～次の発射までの時間
+const unsigned long end2startT = 2000000ul;
+//LEDオンの幅
+const unsigned long ledOnT = 12;
+//LEDオフの幅
+const unsigned long ledOffT = 12;
+//LEDのオンオフにかかる時間の合計
+const unsigned long ledSumT = ledOnT + ledOffT;
+
+
+

 //2砲台右回転
 const int Turn_A = 2;
@@ -25,15 +65,17 @@

 //9 サーボモータ(砲身上下)
 const int Up_Down = 9;
-//10 NC
-
+
+//10 左モータ制御
+const int Left_B = 12;
 //11(PWM) : 左モーター
 const int Left_PWM = 11;
-//12, 13 左モータ制御
-const int Left_A = 12;
-//12, 13 左モータ制御
-const int Left_B = 10;
-
+//12 左モータ制御
+const int Left_A = 13;
+
+//14(アナログ0番)
+const int launch_LED = 14;
+const int launch_LED2 = 15;

 //https://bitbucket.org/sh4869/micomtanks

@@ -47,6 +89,7 @@
 	pinMode(0, INPUT);
 	pinMode(1, OUTPUT);
 	pinMode(2, OUTPUT);
+	//	delay(1000);
 	pinMode(3, OUTPUT);
 	pinMode(4, OUTPUT);
 	pinMode(5, OUTPUT);
@@ -54,13 +97,53 @@
 	pinMode(7, OUTPUT);
 	pinMode(8, OUTPUT);
 	//pinMode(9, OUTPUT);
-	pinMode(10, OUTPUT);
+	//pinMode(10, OUTPUT);
 	pinMode(11, OUTPUT);
 	pinMode(12, OUTPUT);
 	pinMode(13, OUTPUT);

+	pinMode(launch_LED, OUTPUT);
+	pinMode(launch_LED2, OUTPUT);
+
 	Serial.begin(BaudRate);
 	myservo.attach(Up_Down);
+
+	//while (true)
+	//{
+	//	RightMotor(63);
+	//	delay(1000);
+	//	RightMotor(32);
+	//	delay(1000);
+	//	RightMotor(0);
+	//	delay(1000);
+	//	RightMotor(32);
+	//	delay(1000);
+	//	LeftMotor(63);
+	//	delay(1000);
+	//	LeftMotor(32);
+	//	delay(1000);
+	//	LeftMotor(0);
+	//	delay(1000);
+	//	LeftMotor(32);
+	//	delay(1000);
+	//}
+	//Serial.print("Start\r\n");
+	//while (true)
+	//{
+	//	myservo.write(180);
+	//	delay(1000);
+	//	myservo.write(0);
+	//	delay(1000);
+	//}
+#if 0
+	while (true)
+	{
+		digitalWrite(launch_LED, HIGH);
+		delayMicroseconds(13);
+		digitalWrite(launch_LED, LOW);
+		delayMicroseconds(13);
+	}
+#endif
 }

 //砲台の回転に関する関数
@@ -78,39 +161,136 @@
 }

 //発射(開始、停止)
-void burn(bool mode){
+#if 0
+void launch(bool mode){
 	if (mode)
 	{
-
+		if (launchMode)
+		{
+			//発射中(長押し)
+			//開始からの時間で判定
+			launchEnd = micros();
+			launchTempTime = launchEnd - launchStart;
+			if (start2endT > launchTempTime)
+			{
+				//現在OnにするかOffにするか判定(launchTempTime=開始してからの時間)
+				if ((launchTempTime % ledSumT) <= ledOnT)
+				{
+					digitalWrite(launch_LED, HIGH);
+					//digitalWrite(launch_LED2, LOW);
+				}
+				else{
+					digitalWrite(launch_LED, LOW);
+					//digitalWrite(launch_LED2, HIGH);
+				}
+				launchButtonReleased = false;
+			}
+			else
+			{
+				//停止
+				digitalWrite(launch_LED, LOW);
+				//digitalWrite(launch_LED2, HIGH);
+				digitalWrite(launch_LED2, LOW);
+				launchMode = false;
+				launchButtonReleased = false;
+			}
+		}
+		else
+		{
+			//発射終了後長押しもしくは開始
+			//ボタンをオフにしないと次を打てない
+			if (launchButtonReleased)
+			{
+				//発射開始
+				//終了からの時間経過で判定
+				launchStart = micros();
+				launchTempTime = launchStart - launchEnd;
+				if (end2startT < launchTempTime)
+				{
+					digitalWrite(launch_LED, HIGH);
+					digitalWrite(launch_LED2, HIGH);
+					//digitalWrite(launch_LED2, LOW);
+					launchMode = true;
+				}
+				launchButtonReleased = false;
+			}
+		}
 	}
 	else
 	{
-
-	}
-}
-
-////砲台の上下
-//void battery(char val){
-//	if (val != 'x'){
-//		int vali = elect(val);
-//		vali = vali * 10;
-//		myservo.write(vali);
-//	}
-//}
-
-//発射
-void Push(void){
-	digitalWrite(Push_A, LOW);
-	digitalWrite(Push_B, HIGH);
-}
+		launchButtonReleased = true;
+		if (launchMode)
+		{
+			//離していても時間が経ってないなら判定を行う
+			//開始からの時間で判定
+			launchEnd = micros();
+			launchTempTime = launchEnd - launchStart;
+			if (start2endT > launchTempTime)
+			{
+				//現在OnにするかOffにするか判定(launchTempTime=開始してからの時間)
+				if ((launchTempTime % ledSumT) <= ledOnT)
+				{
+					digitalWrite(launch_LED, HIGH);
+					//digitalWrite(launch_LED2, LOW);
+				}
+				else{
+					digitalWrite(launch_LED, LOW);
+					//digitalWrite(launch_LED2, HIGH);
+				}
+			}
+			else
+			{
+				//停止
+				digitalWrite(launch_LED, LOW);
+				digitalWrite(launch_LED2, LOW);
+				//digitalWrite(launch_LED2, HIGH);
+				launchMode = false;
+			}
+		}
+	}
+}
+#else
+void launch(bool mode){
+	if (mode)
+	{
+		//終了からの時間経過で判定
+		launchStart = micros();
+		launchTempTime = launchStart - launchEnd;
+		if (end2startT < launchTempTime)
+		{
+			launchEnd = launchStart + start2endT;
+			digitalWrite(launch_LED2, HIGH);
+			LeftMotor(32);
+			RightMotor(32);
+			Turn_Stop();
+			launchEnd = micros();
+			launchTempTime = launchEnd - launchStart;
+			while (start2endT > launchTempTime)
+			{
+				delayMicroseconds(ledOffT);
+				digitalWrite(launch_LED, HIGH);
+				delayMicroseconds(ledOnT);
+				digitalWrite(launch_LED, LOW);
+				launchEnd = micros();
+				launchTempTime = launchEnd - launchStart;
+			}
+			digitalWrite(launch_LED2, LOW);
+			Serial.flush();
+		}
+	}
+
+}
+#endif
+
 //サーボモーター(0～63を+0～180へ)
 void ServoMotor(unsigned char val){
-	myservo.write(((int) val) * 180 / 32);
+	Serial.write('A' + (val >> 2));
+	myservo.write(((int) val));
 }

 //右モーター(0～63を+-0～255へ)
 void RightMotor(unsigned char val){
-	if (val == 32)
+	if ((val == 32) || (val == 31))
 	{
 		digitalWrite(Right_A, LOW);
 		digitalWrite(Right_B, LOW);
@@ -125,12 +305,12 @@
 	{
 		digitalWrite(Right_A, LOW);
 		digitalWrite(Right_B, HIGH);
-		analogWrite(Right_PWM, (-(val - 32)) << 3);
+		analogWrite(Right_PWM, (-(val - 31)) << 3);
 	}
 }
 //左モーター(0～63を+-0～255へ)
 void LeftMotor(unsigned char val){
-	if (val == 32)
+	if ((val == 32) || (val == 31))
 	{
 		digitalWrite(Left_A, LOW);
 		digitalWrite(Left_B, LOW);
@@ -145,64 +325,12 @@
 	{
 		digitalWrite(Left_A, LOW);
 		digitalWrite(Left_B, HIGH);
-		analogWrite(Left_PWM, (-(val - 32)) << 3);
-	}
-}
-
-////右側モーターに関する関数
-//void Right_go(char val){
-//	int vali = elect(val);
-//	Serial.println(vali);
-//	if (vali == 5){
-//		digitalWrite(Right_A, LOW);
-//		digitalWrite(Right_B, LOW);
-//	}
-//	else if (vali > 5){
-//		digitalWrite(Right_A, HIGH);
-//		digitalWrite(Right_B, LOW);
-//		analogWrite(Right_PWM, NOM + ((vali - 5) * 20));
-//	}
-//	else{
-//		digitalWrite(Right_A, LOW);
-//		digitalWrite(Right_B, HIGH);
-//		vali = vali - 6;
-//		analogWrite(Right_PWM, NOM + (-vali * 20));
-//	}
-//}
-////左側のモーターに関する関数
-//void Left_go(char val){
-//	int vali = elect(val);
-//	Serial.println(vali);
-//	if (vali == 5){
-//		digitalWrite(Left_A, LOW);
-//		digitalWrite(Left_B, LOW);
-//	}
-//	else if (vali > 5){
-//		digitalWrite(Left_A, HIGH);
-//		digitalWrite(Left_B, LOW);
-//		analogWrite(Left_PWM, NOM + ((vali - 5) * 20));
-//	}
-//	else{
-//		digitalWrite(Left_A, LOW);
-//		digitalWrite(Left_B, HIGH);
-//		vali = vali - 6;
-//		analogWrite(Left_PWM, NOM + (-vali * 10));
-//	}
-//}
+		analogWrite(Left_PWM, (-(val - 31)) << 3);
+	}
+}

 inline int elect(char x){
 	return x - '0';
-	//switch (x){
-	//case '1':return 1; break;
-	//case '2':return 2; break;
-	//case '3':return 3; break;
-	//case '4':return 4; break;
-	//case '5':return 5; break;
-	//case '6':return 6; break;
-	//case '7':return 7; break;
-	//case '8':return 8; break;
-	//case '9':return 9; break;
-	//}
 }

@@ -231,7 +359,17 @@
 	{
 		byteNo++;
 		buff = Serial.read();
-
+		for (int i = 7; i > 0; i--)
+		{
+			if (1 & (buff >> i))break;
+#if debug
+			else Serial.write('0');
+#endif
+		}
+#if debug
+		Serial.print((int) buff, BIN);
+		Serial.print('-');
+#endif
 		//パリティ
 		temp2 = 0;
 		for (temp1 = 1; temp1 < 8; temp1++)
@@ -243,11 +381,15 @@
 		}
 		if ((temp2 & 0x01) != (buff & 0x01))
 		{
-			digitalWrite(13, HIGH);
 			dirty = true;
+#if debug
+			Serial.print('_');
+#endif
 		}
 		else{
-			digitalWrite(13, LOW);
+#if debug
+			Serial.print('!');
+#endif
 		}

 		//最終ビット
@@ -257,6 +399,16 @@
 			if ((!dirty) && (byteNo == 4) && ((buff & 0x70) == parity))
 			{
 				//正常
+#if debug
+				Serial.print("R=");
+				Serial.print((int) Rmotor);
+				Serial.print(" L=");
+				Serial.print((int) Lmotor);
+				Serial.print(" D=");
+				Serial.print(((int) servoVal) * 180 / 64);
+
+				Serial.print("         \r");
+#endif
 				RightMotor(Rmotor);
 				LeftMotor(Lmotor);
 				ServoMotor(servoVal);
@@ -289,13 +441,19 @@
 						Turn_Stop();
 					}
 				}
-				burn(0x02 & buff);
-			}
+				launch(0x02 & buff);
+			}
+#if debug
 			if (dirty)
 			{
+				//digitalWrite(13, HIGH);
+				Serial.print('f');
 			}
 			else{
-			}
+				//digitalWrite(13, LOW);
+				Serial.print('t');
+			}
+#endif
 			parity = 0;
 			byteNo = 0;
 			dirty = false;
@@ -305,16 +463,31 @@
 				switch (byteNo)
 				{
 				case 1:
-					Rmotor = 0x3E & (buff >> 1);
+					Rmotor = (0x7E & buff) >> 1;
+#if debug
+					Serial.print('1');
+#endif
+					parity = (buff & 0x01) << 6;
 					break;
 				case 2:
-					Lmotor = 0x3E & (buff >> 1);
+					Lmotor = (0x7E & buff) >> 1;
+#if debug
+					Serial.print('2');
+#endif
+					parity |= (buff & 0x01) << 5;
 					break;
 				case 3:
-					servoVal = 0x3E & (buff >> 1);
+					servoVal = (0x7E & buff) >> 1;
+#if debug
+					Serial.print('3');
+#endif
+					parity |= (buff & 0x01) << 4;
 					break;
 				default:
 					dirty = true;
+#if debug
+					Serial.print('e');
+#endif
 					break;
 				}
 			}
@@ -323,5 +496,6 @@
 	else
 	{
 	}
-}
-
+
+}
+


Removed unused #defines and imports.

Removed unused #defines and imports.

--- freezer_node_v0_1/freezer_node_v0_1.ino
+++ freezer_node_v0_1/freezer_node_v0_1.ino
@@ -16,7 +16,6 @@
 ----------------------------------------------------------------------------- */

 #include <JeeLib.h>
-#include <RF12sio.h>
 #include <OneWire.h>
 #include <DallasTemperature.h>
 #include <TimerOne.h>
@@ -44,7 +43,6 @@

 #define NODEID          2       // node ID used for this unit
 #define NETWORKID       99
-#define GATEWAYID       1
 #define FREQUENCY       RF12_915MHZ

 #define BUFFER_SIZE     128
@@ -211,7 +209,7 @@
         encoder.push(sensorData.tempOut);
     encoder.endDict();

-}
+}

 //------------------------------------------------------------------------------
 // generate periodic report (i.e. send out a packet and optionally report on


corrected backslashes at end-of-line

corrected backslashes at end-of-line

--- src/keyboard_layouts/keyboard_layouts.ino
+++ src/keyboard_layouts/keyboard_layouts.ino
@@ -126,7 +126,7 @@
     else if(firstByte==0x59) { k=KEY_Y; modifier=KEYMODIF_LEFT_SHIFT; return 0; } // Y
     else if(firstByte==0x5A) { k=KEY_Z; modifier=KEYMODIF_LEFT_SHIFT; return 0; } // Z
     else if(firstByte==0x5B) { k=KEY_LEFT_BRACE; return 0; } // [
-    else if(firstByte==0x5C) { k=KEY_BACKSLASH; return 0; } // \
+    else if(firstByte==0x5C) { k=KEY_BACKSLASH; return 0; } // '\'
     else if(firstByte==0x5D) { k=KEY_RIGHT_BRACE; return 0; } // ]
     else if(firstByte==0x5E) { k=KEY_6; modifier=KEYMODIF_LEFT_SHIFT; return 0; } // ^
     else if(firstByte==0x5F) { k=KEY_MINUS; modifier=KEYMODIF_LEFT_SHIFT; return 0; } // _
@@ -136,7 +136,7 @@
     else if(firstByte==0x59) { k=KEY_Z; modifier=KEYMODIF_LEFT_SHIFT; return 0; } // Y
     else if(firstByte==0x5A) { k=KEY_Y; modifier=KEYMODIF_LEFT_SHIFT; return 0; } // Z
     else if(firstByte==0x5B) { k=KEY_8; (KeyboardModifier)(KEYMODIF_LEFT_CTRL|KEYMODIF_LEFT_ALT); return 0; } // [
-    else if(firstByte==0x5C) { k=KEY_MINUS; (KeyboardModifier)(KEYMODIF_LEFT_CTRL|KEYMODIF_LEFT_ALT); return 0; } // \
+    else if(firstByte==0x5C) { k=KEY_MINUS; (KeyboardModifier)(KEYMODIF_LEFT_CTRL|KEYMODIF_LEFT_ALT); return 0; } // '\'
     else if(firstByte==0x5D) { k=KEY_9; (KeyboardModifier)(KEYMODIF_LEFT_CTRL|KEYMODIF_LEFT_ALT); return 0; } // ]
     else if(firstByte==0x5E) { k=KEY_TILDE; return 0; } // ^
     else if(firstByte==0x5F) { k=KEY_SLASH; modifier=KEYMODIF_LEFT_SHIFT; return 0; } // _


check the return value before printing new data

--- arduino/motors_ahrs/motors_ahrs.ino
+++ arduino/motors_ahrs/motors_ahrs.ino
@@ -30,7 +30,9 @@

 void loop()
 {
-    MinIMU9AHRS_loop();
-    MinIMU9AHRS_printdata();
-    delay(20);
+    if (MinIMU9AHRS_loop())
+    {
+        MinIMU9AHRS_printdata();
+    }
+    delay(10);
 }


new blah 2

new blah 2

--- proj/hypercube/HCS/HCS.ino
+++ proj/hypercube/HCS/HCS.ino
@@ -273,7 +273,7 @@
       chase_spiral(OUTER, oOffset, true);
       break;
     case 3:
-      chase_mod(OUTER, true);
+      chase_mod(OUTER);
       break;
     //case 4:
     //  snow_anim(OUTER, 50, 0.3);


Version 1.7 27th March 2017

Version 1.7 27th March 2017

* Adds the pretty printer function pprint, which allows you to print functions in a nicely formatted way, and a trace feature using trace and untrace, allowing you to trace the calls to and returns from up to three functions at a time.

* Fixes a long-standing bug which could give incorrect results when two functions using the same symbols called each other.

--- ulisp.ino
+++ ulisp.ino
@@ -1,5 +1,5 @@
-/* uLisp Version 1.6 - www.ulisp.com
-   David Johnson-Davies - www.technoblogy.com - 4th March 2017
+/* uLisp Version 1.7 - www.ulisp.com
+   David Johnson-Davies - www.technoblogy.com - 27th March 2017

    Licensed under the MIT license: https://opensource.org/licenses/MIT
 */
@@ -30,10 +30,12 @@
 #define pop(y)             ((y) = cdr(y))

 #define numberp(x)         ((x)->type == NUMBER)
+#define symbolp(x)         ((x)->type == SYMBOL)
 #define stringp(x)         ((x)->type == STRING)
 #define streamp(x)         ((x)->type == STREAM)
 #define listp(x)           ((x) == NULL || (x)->type >= PAIR || (x)->type == ZERO)
 #define consp(x)           (((x)->type >= PAIR || (x)->type == ZERO) && (x) != NULL)
+#define atom(x)            (((x)->type < PAIR && (x)->type != ZERO) || (x) == NULL)

 #define mark(x)            (car(x) = (object *)(((unsigned int)(car(x))) | 0x8000))
 #define unmark(x)          (car(x) = (object *)(((unsigned int)(car(x))) & 0x7FFF))
@@ -47,26 +49,30 @@
 // RAMSTART, RAMEND, and E2END are defined by the processor's ioxxx.h file

 const int RAMsize = RAMEND - RAMSTART + 1;
-const int workspacesize = (RAMsize - RAMsize/4 - 268)/4;
+const int workspacesize = (RAMsize - RAMsize/4 - 266)/4;
 const int EEPROMsize = E2END;

-const int buflen = 17;  // Length of longest symbol + 1
+const int buflen = 17;  // Length of longest symbol
+const int tracemax = 3; // Number of traced functions
 enum type {ZERO, SYMBOL, NUMBER, STREAM, STRING, PAIR };  // STRING and PAIR must be last
 enum token { UNUSED, BRA, KET, QUO, DOT };
 enum stream { SERIALSTREAM, I2CSTREAM, SPISTREAM };

-enum function { SYMBOLS, NIL, TEE, STRINGSYM, AMPREST, LAMBDA, LET, LETSTAR, CLOSURE, SPECIAL_FORMS,
-QUOTE, DEFUN, DEFVAR, SETQ, LOOP, PUSH, POP, INCF, DECF, SETF, DOLIST, DOTIMES, FORMILLIS, WITHI2C,
-WITHSPI, TAIL_FORMS, PROGN, RETURN, IF, COND, WHEN, UNLESS, AND, OR, FUNCTIONS, NOT, NULLFN, CONS, ATOM,
-LISTP, CONSP, NUMBERP, 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, ADD, SUBTRACT, MULTIPLY, DIVIDE, MOD, ONEPLUS, ONEMINUS, ABS, RANDOM, MAX,
-MIN, NUMEQ, LESS, LESSEQ, GREATER, GREATEREQ, NOTEQ, PLUSP, MINUSP, ZEROP, ODDP, EVENP, STRINGP, STRINGEQ,
-CONCATENATE, SUBSEQ, LOGAND, LOGIOR, LOGXOR, LOGNOT, ASH, LOGBITP, EVAL, GLOBALS, LOCALS, MAKUNBOUND,
-BREAK, READ, PRIN1, PRINT, PRINC, TERPRI, READLINE, READBYTE, WRITEBYTE, RESTARTI2C, GC, ROOM, SAVEIMAGE,
-LOADIMAGE, CLS, PINMODE, DIGITALREAD, DIGITALWRITE, ANALOGREAD, ANALOGWRITE, DELAY, MILLIS, NOTE, EDIT, ENDFUNCTIONS };
+enum function { SYMBOLS, NIL, TEE, NOTHING, STRINGFN, AMPREST, LAMBDA, LET, LETSTAR, CLOSURE,
+SPECIAL_FORMS, QUOTE, DEFUN, DEFVAR, SETQ, LOOP, PUSH, POP, INCF, DECF, SETF, DOLIST, DOTIMES, TRACE,
+UNTRACE, FORMILLIS, WITHI2C, WITHSPI, TAIL_FORMS, PROGN, RETURN, IF, COND, WHEN, UNLESS, AND, OR,
+FUNCTIONS, NOT, NULLFN, CONS, ATOM, LISTP, CONSP, NUMBERP, 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, ADD, SUBTRACT, MULTIPLY, DIVIDE,
+MOD, ONEPLUS, ONEMINUS, ABS, RANDOM, MAX, MIN, NUMEQ, LESS, LESSEQ, GREATER, GREATEREQ, NOTEQ, PLUSP,
+MINUSP, ZEROP, ODDP, EVENP, STRINGP, STRINGEQ, CONCATENATE, SUBSEQ, LOGAND, LOGIOR, LOGXOR, LOGNOT, ASH,
+LOGBITP, EVAL, GLOBALS, LOCALS, MAKUNBOUND, BREAK, READ, PRIN1, PRINT, PRINC, TERPRI, READLINE, READBYTE,
+WRITEBYTE, RESTARTI2C, GC, ROOM, SAVEIMAGE, LOADIMAGE, CLS, PINMODE, DIGITALREAD, DIGITALWRITE,
+ANALOGREAD, ANALOGWRITE, DELAY, MILLIS, NOTE, EDIT, PPRINT, ENDFUNCTIONS };

 // Typedefs
+
+typedef unsigned int symbol_t;

 typedef struct sobject {
   union {
@@ -77,7 +83,7 @@
     struct {
       enum type type;
       union {
-        unsigned int name;
+        symbol_t name;
         int integer;
       };
     };
@@ -102,6 +108,8 @@
 object *freelist;
 extern uint8_t _end;
 int i2cCount;
+unsigned int TraceFn[tracemax];
+unsigned int TraceDepth[tracemax];

 object *GlobalEnv;
 object *GCStack = NULL;
@@ -120,8 +128,8 @@
 object *read ();
 void repl(object *env);
 void printobject (object *form);
-char *lookupstring (unsigned int name);
-int lookupfn (unsigned int name);
+char *lookupstring (symbol_t name);
+int lookupfn (symbol_t name);
 int builtin (char* n);
 void Display (char c);

@@ -139,7 +147,7 @@
 }

 object *myalloc () {
-  if (freespace == 0) error(F("No room"));
+  if (freespace == 0) error(F("\rNo room"));
   object *temp = freelist;
   freelist = cdr(freelist);
   freespace--;
@@ -169,7 +177,7 @@
   return ptr;
 }

-object *symbol (unsigned int name) {
+object *symbol (symbol_t name) {
   object *ptr = myalloc();
   ptr->type = SYMBOL;
   ptr->name = name;
@@ -230,9 +238,7 @@
   markobject(env);
   sweep();
   #if defined(debug1)
-  pchar('{');
-  pint(freespace - start);
-  pchar('}');
+  pchar('{'); pint(freespace - start); pchar('}');
   #endif
 }

@@ -340,6 +346,36 @@
   longjmp(exception, 1);
 }

+// Tracing
+
+boolean tracing (symbol_t name) {
+  int i = 0;
+  while (i < tracemax) {
+    if (TraceFn[i] == name) return i+1;
+    i++;
+  }
+  return 0;
+}
+
+void trace (symbol_t name) {
+  if (tracing(name)) error(F("Already being traced"));
+  int i = 0;
+  while (i < tracemax) {
+    if (TraceFn[i] == 0) { TraceFn[i] = name; TraceDepth[i] = 0; return; }
+    i++;
+  }
+  error(F("Already tracing 3 functions"));
+}
+
+void untrace (symbol_t name) {
+  int i = 0;
+  while (i < tracemax) {
+    if (TraceFn[i] == name) { TraceFn[i] = 0; return; }
+    i++;
+  }
+  error(F("It wasn't being traced"));
+}
+
 // Helper functions

 int toradix40 (int ch) {
@@ -347,7 +383,7 @@
   if (ch >= '0' && ch <= '9') return ch-'0'+30;
   ch = ch | 0x20;
   if (ch >= 'a' && ch <= 'z') return ch-'a'+1;
-  error(F("Illegal character in symbol"));
+  error(F("\rIllegal character in symbol"));
   return 0;
 }

@@ -369,10 +405,10 @@
   return 16;
 }

-char *name(object *obj){
+char *name (object *obj){
   buffer[3] = '\0';
   if(obj->type != SYMBOL) error(F("Error in name"));
-  unsigned int x = obj->name;
+  symbol_t x = obj->name;
   if (x < ENDFUNCTIONS) return lookupstring(x);
   for (int n=2; n>=0; n--) {
     buffer[n] = fromradix40(x % 40);
@@ -381,17 +417,17 @@
   return buffer;
 }

-int integer(object *obj){
+int integer (object *obj){
   if(obj->type != NUMBER) error(F("not a number"));
   return obj->integer;
 }

-int istream(object *obj){
+int istream (object *obj){
   if(obj->type != STREAM) error(F("not a stream"));
   return obj->integer;
 }

-int issymbol(object *obj, unsigned int n) {
+int issymbol (object *obj, symbol_t n) {
   return obj->type == SYMBOL && obj->name == n;
 }

@@ -402,35 +438,7 @@
   return (same_object || same_symbol || same_number);
 }

-// Lookup variable in environment
-
-object *value(unsigned int n, object *env) {
-  while (env != NULL) {
-    object *item = car(env);
-    if(car(item)->name == n) return item;
-    env = cdr(env);
-  }
-  return nil;
-}
-
-object *findvalue (object *var, object *env) {
-  unsigned int varname = var->name;
-  object *pair = value(varname, env);
-  if (pair == NULL) pair = value(varname, GlobalEnv);
-  if (pair == NULL) error2(var,F("unknown variable"));
-  return pair;
-}
-
-object *findtwin (object *var, object *env) {
-  while (env != NULL) {
-    object *pair = car(env);
-    if (car(pair) == var) return pair;
-    env = cdr(env);
-  }
-  return NULL;
-}
-
-inline int listlength (object *list) {
+int listlength (object *list) {
   int length = 0;
   while (list != NULL) {
     list = cdr(list);
@@ -441,34 +449,42 @@

 // String utilities

+void indent (int spaces) {
+  for (int i=0; i<spaces; i++) pchar(' ');
+}
+
+void buildstring (char ch, int *chars, object **head, object **tail) {
+  if (*chars == 0) {
+    *chars = ch<<8;
+    object *cell = myalloc();
+    if (*head == NULL) *head = cell; else (*tail)->car = cell;
+    cell->car = NULL;
+    cell->integer = *chars;
+    *tail = cell;
+  } else {
+    *chars = *chars | ch;
+    (*tail)->integer = *chars;
+    *chars = 0;
+  }
+}
+
 object *readstring (char delim) {
-    object *obj = myalloc();
-    obj->type = STRING;
-    char ch = gchar();
-    object *head = NULL;
-    object *tail = NULL;
-    int chars = 0;
-    while (ch != delim) {
-      if (ch == '\\') ch = gchar();
-      if (chars == 0) {
-        chars = ch<<8;
-        object *cell = myalloc();
-        if (head == NULL) head = cell; else tail->car = cell;
-        cell->car = NULL;
-        cell->integer = chars;
-        tail = cell;
-      } else {
-        chars = chars | ch;
-        tail->integer = chars;
-        chars = 0;
-      }
-      ch = gchar();
-    }
-    obj->cdr = head;
-    return obj;
-}
-
-inline int stringlength (object *form) {
+  object *obj = myalloc();
+  obj->type = STRING;
+  char ch = gchar();
+  object *head = NULL;
+  object *tail = NULL;
+  int chars = 0;
+  while (ch != delim) {
+    if (ch == '\\') ch = gchar();
+    buildstring(ch, &chars, &head, &tail);
+    ch = gchar();
+  }
+  obj->cdr = head;
+  return obj;
+}
+
+int stringlength (object *form) {
   int length = 0;
   form = cdr(form);
   while (form != NULL) {
@@ -493,15 +509,59 @@
   return ch;
 }

+// Lookup variable in environment
+
+object *value (symbol_t n, object *env) {
+  while (env != NULL) {
+    object *pair = car(env);
+    if (pair != NULL && car(pair)->name == n) return pair;
+    env = cdr(env);
+  }
+  return nil;
+}
+
+object *findvalue (object *var, object *env) {
+  symbol_t varname = var->name;
+  object *pair = value(varname, env);
+  if (pair == NULL) pair = value(varname, GlobalEnv);
+  if (pair == NULL) error2(var,F("unknown variable"));
+  return pair;
+}
+
+object *findtwin (object *var, object *env) {
+  while (env != NULL) {
+    object *pair = car(env);
+    if (pair != NULL && car(pair) == var) return pair;
+    env = cdr(env);
+  }
+  return NULL;
+}
+
+void dropframe (int tc, object **env) {
+  if (tc) {
+    while (*env != NULL && car(*env) != NULL) {
+      pop(*env);
+    }
+    if (*env == NULL) error(F("no frame to drop"));
+  } else {
+    push(nil, *env);
+  }
+}
+
 // Handling closures

-object *closure (int tail, object *fname, object *state, object *function, object *args, object **env) {
+object *closure (object *fname, object *state, object *function, object *args, object **env) {
+  int trace = tracing(fname->name);
+  if (trace) {
+    indent(TraceDepth[trace-1]<<1);
+    pint(TraceDepth[trace-1]++); pchar(':'); pchar(' '); pchar('('); printobject(fname);
+  }
   object *params = first(function);
   function = cdr(function);
   // Push state if not already in env
   while (state != NULL) {
     object *pair = first(state);
-    if (findtwin(car(pair), *env) == NULL) push(first(state), *env);
+    if (findtwin(car(pair), *env) == NULL) push(pair, *env);
     state = cdr(state);
   }
   // Add arguments to environment
@@ -517,22 +577,20 @@
       value = first(args);
       args = cdr(args);
     }
-    if (tail) {
-      object *pair = findtwin(var, *env);
-      if (pair != NULL) cdr(pair) = value;
-      else push(cons(var,value), *env);
-    } else push(cons(var,value), *env);
-    params = cdr(params);
+    push(cons(var,value), *env);
+    params = cdr(params);
+    if (trace) { pchar(' '); printobject(value); }
   }
   if (params != NULL) error2(fname, F("has too few parameters"));
   if (args != NULL) error2(fname, F("has too many parameters"));
+  if (trace) { pchar(')'); pln(); }
   // Do an implicit progn
-  return tf_progn(function, *env);
+  return tf_progn(function, *env);
 }

 object *apply (object *function, object *args, object **env) {
   if (function->type == SYMBOL) {
-    unsigned int name = function->name;
+    symbol_t name = function->name;
     int nargs = listlength(args);
     if (name >= ENDFUNCTIONS) error2(function, F("is not a function"));
     if (nargs<lookupmin(name)) error2(function, F("has too few arguments"));
@@ -541,12 +599,12 @@
   }
   if (listp(function) && issymbol(car(function), LAMBDA)) {
     function = cdr(function);
-    object *result = closure(1, NULL, NULL, function, args, env);
+    object *result = closure(NULL, NULL, function, args, env);
     return eval(result, *env);
   }
   if (listp(function) && issymbol(car(function), CLOSURE)) {
     function = cdr(function);
-    object *result = closure(1, NULL, car(function), cdr(function), args, env);
+    object *result = closure(NULL, car(function), cdr(function), args, env);
     return eval(result, *env);
   }
   error2(function, F("illegal function"));
@@ -556,7 +614,7 @@
 // In-place operations

 object **place (object *args, object *env) {
-  if (!consp(args)) return &cdr(findvalue(args, env));
+  if (atom(args)) return &cdr(findvalue(args, env));
   object* function = first(args);
   if (issymbol(function, CAR) || issymbol(function, FIRST)) {
     object *value = eval(second(args), env);
@@ -571,7 +629,7 @@
   if (issymbol(function, NTH)) {
     int index = integer(eval(second(args), env));
     object *list = eval(third(args), env);
-    if (!consp(list)) error(F("'nth' second argument is not a list"));
+    if (atom(list)) error(F("'nth' second argument is not a list"));
     while (index > 0) {
       list = cdr(list);
       if (list == NULL) error(F("'nth' index out of range"));
@@ -807,6 +865,38 @@
   }
   cdr(pair) = number(index);
   return eval(result, env);
+}
+
+object *sp_trace (object *args, object *env) {
+  (void) env;
+  while (args != NULL) {
+      trace(first(args)->name);
+      args = cdr(args);
+    }
+  int i = 0;
+  while (i < tracemax) {
+    if (TraceFn[i] != 0) args = cons(symbol(TraceFn[i]), args);
+    i++;
+  }
+  return args;
+}
+
+object *sp_untrace (object *args, object *env) {
+  (void) env;
+  if (args == NULL) {
+    int i = 0;
+    while (i < tracemax) {
+      if (TraceFn[i] != 0) args = cons(symbol(TraceFn[i]), args);
+      TraceFn[i] = 0;
+      i++;
+    }
+  } else {
+    while (args != NULL) {
+      untrace(first(args)->name);
+      args = cdr(args);
+    }
+  }
+  return args;
 }

 object *sp_formillis (object *args, object *env) {
@@ -957,39 +1047,37 @@

 object *fn_atom (object *args, object *env) {
   (void) env;
-  object *arg1 = first(args);
-  return consp(arg1) ? nil : tee;
+  return atom(first(args)) ? tee : nil;
 }

 object *fn_listp (object *args, object *env) {
   (void) env;
-  object *arg1 = first(args);
-  return listp(arg1) ? tee : nil;
+  return listp(first(args)) ? tee : nil;
 }

 object *fn_consp (object *args, object *env) {
   (void) env;
-  object *arg1 = first(args);
-  return consp(arg1) ? tee : nil;
+  return consp(first(args)) ? tee : nil;
 }

 object *fn_numberp (object *args, object *env) {
   (void) env;
-  object *arg1 = first(args);
-  return numberp(arg1) ? tee : nil;
+  return numberp(first(args)) ? tee : nil;
+}
+
+object *fn_symbolp (object *args, object *env) {
+  (void) env;
+  return symbolp(first(args)) ? tee : nil;
 }

 object *fn_streamp (object *args, object *env) {
   (void) env;
-  object *arg1 = first(args);
-  return streamp(arg1) ? tee : nil;
+  return streamp(first(args)) ? tee : nil;
 }

 object *fn_eq (object *args, object *env) {
   (void) env;
-  object *arg1 = first(args);
-  object *arg2 = second(args);
-  return eq(arg1, arg2) ? tee : nil;
+  return eq(first(args), second(args)) ? tee : nil;
 }

 // List functions
@@ -1517,8 +1605,8 @@
 object *fn_concatenate (object *args, object *env) {
   (void) env;
   object *arg = first(args);
-  unsigned int name = arg->name;
-  if (name != STRINGSYM) error(F("Only string result supported"));
+  symbol_t name = arg->name;
+  if (name != STRINGFN) error(F("Only string result supported"));
   args = cdr(args);
   object *result = myalloc();
   result->type = STRING;
@@ -1533,18 +1621,7 @@
       int pair = obj->integer;
        while (pair != 0) {
          char ch = pair>>8 & 0xFF;
-         if (chars == 0) {
-           chars = ch<<8;
-           object *cell = myalloc();
-           if (head == NULL) head = cell; else tail->car = cell;
-           cell->car = NULL;
-           cell->integer = chars;
-           tail = cell;
-         } else {
-           chars = chars | ch;
-           tail->integer = chars;
-           chars = 0;
-         }
+         buildstring(ch, &chars, &head, &tail);
          pair = pair<<8;
       }
       obj = car(obj);
@@ -1570,18 +1647,7 @@
   int chars = 0;
   for (int i=start; i<end; i++) {
     char ch = character(arg, i);
-    if (chars == 0) {
-      chars = ch<<8;
-      object *cell = myalloc();
-      if (head == NULL) head = cell; else tail->car = cell;
-      cell->car = NULL;
-      cell->integer = chars;
-      tail = cell;
-    } else {
-      chars = chars | ch;
-      tail->integer = chars;
-      chars = 0;
-    }
+    buildstring(ch, &chars, &head, &tail);
   }
   result->cdr = head;
   return result;
@@ -1649,14 +1715,8 @@
 }

 object *fn_globals (object *args, object *env) {
-  (void) args, (void) env;
-  object *list = GlobalEnv;
-  while (list != NULL) {
-    printobject(car(car(list)));
-    pln();
-    list = cdr(list);
-  }
-  return nil;
+  (void) args;
+  return fn_mapcar(cons(symbol(CAR),cons(GlobalEnv,nil)), env);
 }

 object *fn_locals (object *args, object *env) {
@@ -1686,8 +1746,7 @@

 object *fn_break (object *args, object *env) {
   (void) args;
-  pln();
-  pfstring(F("Break!")); pln();
+  pfstring(F("\rBreak!\r"));
   BreakLevel++;
   repl(env);
   BreakLevel--;
@@ -1794,13 +1853,12 @@
   pint(freespace - initial);
   pfstring(F(" bytes, Time: "));
   pint(micros() - start);
-  pfstring(F(" uS")); pln();
+  pfstring(F(" uS\r"));
   return nil;
 }

 object *fn_room (object *args, object *env) {
-  (void) args;
-  (void) env;
+  (void) args, (void) env;
   return number(freespace);
 }

@@ -1810,14 +1868,12 @@
 }

 object *fn_loadimage (object *args, object *env) {
-  (void) args;
-  (void) env;
+  (void) args, (void) env;
   return number(loadimage());
 }

 object *fn_cls(object *args, object *env) {
-  (void) env;
-  (void) args;
+  (void) args, (void) env;
   pchar(12);
   return nil;
 }
@@ -1879,13 +1935,8 @@
 }

 object *fn_millis (object *args, object *env) {
-  (void) env;
-  (void) args;
-  unsigned long temp = millis();
-  #if defined(checkoverflow)
-  if (temp > 32767) error(F("'millis' arithmetic overflow"));
-  #endif
-  return number(temp);
+  (void) args, (void) env;
+  return number(millis());
 }

 const uint8_t scale[] PROGMEM = {239,226,213,201,190,179,169,160,151,142,134,127};
@@ -1972,7 +2023,7 @@
     else if (c == 'r') fun = read();
     else if (c == '\r') { pfl(); printobject(fun); pln(); }
     else if (c == 'c') fun = cons(read(), fun);
-    else if (!consp(fun)) pchar('!');
+    else if (atom(fun)) pchar('!');
     else if (c == 'd') fun = cons(car(fun), edit(cdr(fun)));
     else if (c == 'a') fun = cons(edit(car(fun)), cdr(fun));
     else if (c == 'x') fun = cdr(fun);
@@ -1980,144 +2031,228 @@
   }
 }

+// Prettyprinter
+
+const int ppindent = 2;
+const int defaultppwidth = 80;
+int ppwidth;
+
+int atomwidth (object *obj) {
+  if (obj == NULL) return 3;
+  if (obj->type == NUMBER) {
+    int w = 1;
+    int n = obj->integer;
+    if (n < 0) { n = -n; w++; }
+    while (n >= 10) { n = n/10; w++; }
+    return w;
+  }
+  if (obj->type == STRING) return stringlength(obj);
+  int w = 0;
+  char *s = name(obj);
+  while (*s++) w++;
+  return w;
+}
+
+boolean quoted (object *obj) {
+  return (consp(obj) && (car(obj)->name == QUOTE) && consp(cdr(obj)) && (cddr(obj) == NULL));
+}
+
+int subwidth (object *obj, int w) {
+  if (atom(obj)) return w - atomwidth(obj);
+  if (quoted(obj)) return subwidthlist(car(cdr(obj)), w - 1);
+  return subwidthlist(obj, w - 1);
+}
+
+int subwidthlist (object *form, int w) {
+  while (form != NULL && w >= 0) {
+    if (atom(form)) return w - (2 + atomwidth(form));
+    w = subwidth(car(form), w - 1);
+    form = cdr(form);
+  }
+  return w;
+}
+
+void superprint (object *form, int lm) {
+  if (atom(form)) printobject(form);
+  else if (quoted(form)) { pchar('\''); superprint(car(cdr(form)), lm + 1); }
+  else if (subwidth(form, ppwidth - lm) >= 0) supersub(form, lm + ppindent, 0);
+  else supersub(form, lm + ppindent, 1);
+}
+
+const int ppspecials = 8;
+const char ppspecial[ppspecials] PROGMEM = { IF, SETQ, TEE, LET, LETSTAR, LAMBDA, WHEN, UNLESS };
+
+void supersub (object *form, int lm, int super) {
+  int special = 0, separate = 1;
+  object *arg = car(form);
+  if (symbolp(arg)) {
+    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; }
+    }
+  }
+  while (form != NULL) {
+    if (atom(form)) { pfstring(F(" . ")); printobject(form); pchar(')'); return; }
+    else if (separate) { pchar('('); separate = 0; }
+    else if (special) { pchar(' '); special--; }
+    else if (!super) pchar(' ');
+    else { pln(); indent(lm); }
+    superprint(car(form), lm);
+    form = cdr(form);
+  }
+  pchar(')'); return;
+}
+
+object *fn_pprint (object *args, object *env) {
+  (void) env;
+  pln();
+  superprint(first(args), 0);
+  return symbol(NOTHING);
+}
+
 // Insert your own function definitions here
-

 // Built-in procedure names - stored in PROGMEM

 const char string0[] PROGMEM = "symbols";
 const char string1[] PROGMEM = "nil";
 const char string2[] PROGMEM = "t";
-const char string3[] PROGMEM = "string";
-const char string4[] PROGMEM = "&rest";
-const char string5[] PROGMEM = "lambda";
-const char string6[] PROGMEM = "let";
-const char string7[] PROGMEM = "let*";
-const char string8[] PROGMEM = "closure";
-const char string9[] PROGMEM = "special_forms";
-const char string10[] PROGMEM = "quote";
-const char string11[] PROGMEM = "defun";
-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 = "for-millis";
-const char string23[] PROGMEM = "with-i2c";
-const char string24[] PROGMEM = "with-spi";
-const char string25[] PROGMEM = "tail_forms";
-const char string26[] PROGMEM = "progn";
-const char string27[] PROGMEM = "return";
-const char string28[] PROGMEM = "if";
-const char string29[] PROGMEM = "cond";
-const char string30[] PROGMEM = "when";
-const char string31[] PROGMEM = "unless";
-const char string32[] PROGMEM = "and";
-const char string33[] PROGMEM = "or";
-const char string34[] PROGMEM = "functions";
-const char string35[] PROGMEM = "not";
-const char string36[] PROGMEM = "null";
-const char string37[] PROGMEM = "cons";
-const char string38[] PROGMEM = "atom";
-const char string39[] PROGMEM = "listp";
-const char string40[] PROGMEM = "consp";
-const char string41[] PROGMEM = "numberp";
-const char string42[] PROGMEM = "streamp";
-const char string43[] PROGMEM = "eq";
-const char string44[] PROGMEM = "car";
-const char string45[] PROGMEM = "first";
-const char string46[] PROGMEM = "cdr";
-const char string47[] PROGMEM = "rest";
-const char string48[] PROGMEM = "caar";
-const char string49[] PROGMEM = "cadr";
-const char string50[] PROGMEM = "second";
-const char string51[] PROGMEM = "cdar";
-const char string52[] PROGMEM = "cddr";
-const char string53[] PROGMEM = "caaar";
-const char string54[] PROGMEM = "caadr";
-const char string55[] PROGMEM = "cadar";
-const char string56[] PROGMEM = "caddr";
-const char string57[] PROGMEM = "third";
-const char string58[] PROGMEM = "cdaar";
-const char string59[] PROGMEM = "cdadr";
-const char string60[] PROGMEM = "cddar";
-const char string61[] PROGMEM = "cdddr";
-const char string62[] PROGMEM = "length";
-const char string63[] PROGMEM = "list";
-const char string64[] PROGMEM = "reverse";
-const char string65[] PROGMEM = "nth";
-const char string66[] PROGMEM = "assoc";
-const char string67[] PROGMEM = "member";
-const char string68[] PROGMEM = "apply";
-const char string69[] PROGMEM = "funcall";
-const char string70[] PROGMEM = "append";
-const char string71[] PROGMEM = "mapc";
-const char string72[] PROGMEM = "mapcar";
-const char string73[] PROGMEM = "+";
-const char string74[] PROGMEM = "-";
-const char string75[] PROGMEM = "*";
-const char string76[] PROGMEM = "/";
-const char string77[] PROGMEM = "mod";
-const char string78[] PROGMEM = "1+";
-const char string79[] PROGMEM = "1-";
-const char string80[] PROGMEM = "abs";
-const char string81[] PROGMEM = "random";
-const char string82[] PROGMEM = "max";
-const char string83[] PROGMEM = "min";
-const char string84[] PROGMEM = "=";
-const char string85[] PROGMEM = "<";
-const char string86[] PROGMEM = "<=";
-const char string87[] PROGMEM = ">";
-const char string88[] PROGMEM = ">=";
-const char string89[] PROGMEM = "/=";
-const char string90[] PROGMEM = "plusp";
-const char string91[] PROGMEM = "minusp";
-const char string92[] PROGMEM = "zerop";
-const char string93[] PROGMEM = "oddp";
-const char string94[] PROGMEM = "evenp";
-const char string95[] PROGMEM = "stringp";
-const char string96[] PROGMEM = "string=";
-const char string97[] PROGMEM = "concatenate";
-const char string98[] PROGMEM = "subseq";
-const char string99[] PROGMEM = "logand";
-const char string100[] PROGMEM = "logior";
-const char string101[] PROGMEM = "logxor";
-const char string102[] PROGMEM = "lognot";
-const char string103[] PROGMEM = "ash";
-const char string104[] PROGMEM = "logbitp";
-const char string105[] PROGMEM = "eval";
-const char string106[] PROGMEM = "globals";
-const char string107[] PROGMEM = "locals";
-const char string108[] PROGMEM = "makunbound";
-const char string109[] PROGMEM = "break";
-const char string110[] PROGMEM = "read";
-const char string111[] PROGMEM = "prin1";
-const char string112[] PROGMEM = "print";
-const char string113[] PROGMEM = "princ";
-const char string114[] PROGMEM = "terpri";
-const char string115[] PROGMEM = "read-line";
-const char string116[] PROGMEM = "read-byte";
-const char string117[] PROGMEM = "write-byte";
-const char string118[] PROGMEM = "restart-i2c";
-const char string119[] PROGMEM = "gc";
-const char string120[] PROGMEM = "room";
-const char string121[] PROGMEM = "save-image";
-const char string122[] PROGMEM = "load-image";
-const char string123[] PROGMEM = "cls";
-const char string124[] PROGMEM = "pinmode";
-const char string125[] PROGMEM = "digitalread";
-const char string126[] PROGMEM = "digitalwrite";
-const char string127[] PROGMEM = "analogread";
-const char string128[] PROGMEM = "analogwrite";
-const char string129[] PROGMEM = "delay";
-const char string130[] PROGMEM = "millis";
-const char string131[] PROGMEM = "note";
-const char string132[] PROGMEM = "edit";
+const char string3[] PROGMEM = "nothing";
+const char string4[] PROGMEM = "string";
+const char string5[] PROGMEM = "&rest";
+const char string6[] PROGMEM = "lambda";
+const char string7[] PROGMEM = "let";
+const char string8[] PROGMEM = "let*";
+const char string9[] PROGMEM = "closure";
+const char string10[] PROGMEM = "special_forms";
+const char string11[] PROGMEM = "quote";
+const char string12[] PROGMEM = "defun";
+const char string13[] PROGMEM = "defvar";
+const char string14[] PROGMEM = "setq";
+const char string15[] PROGMEM = "loop";
+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-i2c";
+const char string27[] PROGMEM = "with-spi";
+const char string28[] PROGMEM = "tail_forms";
+const char string29[] PROGMEM = "progn";
+const char string30[] PROGMEM = "return";
+const char string31[] PROGMEM = "if";
+const char string32[] PROGMEM = "cond";
+const char string33[] PROGMEM = "when";
+const char string34[] PROGMEM = "unless";
+const char string35[] PROGMEM = "and";
+const char string36[] PROGMEM = "or";
+const char string37[] PROGMEM = "functions";
+const char string38[] PROGMEM = "not";
+const char string39[] PROGMEM = "null";
+const char string40[] PROGMEM = "cons";
+const char string41[] PROGMEM = "atom";
+const char string42[] PROGMEM = "listp";
+const char string43[] PROGMEM = "consp";
+const char string44[] PROGMEM = "numberp";
+const char string45[] PROGMEM = "symbolp";
+const char string46[] PROGMEM = "streamp";
+const char string47[] PROGMEM = "eq";
+const char string48[] PROGMEM = "car";
+const char string49[] PROGMEM = "first";
+const char string50[] PROGMEM = "cdr";
+const char string51[] PROGMEM = "rest";
+const char string52[] PROGMEM = "caar";
+const char string53[] PROGMEM = "cadr";
+const char string54[] PROGMEM = "second";
+const char string55[] PROGMEM = "cdar";
+const char string56[] PROGMEM = "cddr";
+const char string57[] PROGMEM = "caaar";
+const char string58[] PROGMEM = "caadr";
+const char string59[] PROGMEM = "cadar";
+const char string60[] PROGMEM = "caddr";
+const char string61[] PROGMEM = "third";
+const char string62[] PROGMEM = "cdaar";
+const char string63[] PROGMEM = "cdadr";
+const char string64[] PROGMEM = "cddar";
+const char string65[] PROGMEM = "cdddr";
+const char string66[] PROGMEM = "length";
+const char string67[] PROGMEM = "list";
+const char string68[] PROGMEM = "reverse";
+const char string69[] PROGMEM = "nth";
+const char string70[] PROGMEM = "assoc";
+const char string71[] PROGMEM = "member";
+const char string72[] PROGMEM = "apply";
+const char string73[] PROGMEM = "funcall";
+const char string74[] PROGMEM = "append";
+const char string75[] PROGMEM = "mapc";
+const char string76[] PROGMEM = "mapcar";
+const char string77[] PROGMEM = "+";
+const char string78[] PROGMEM = "-";
+const char string79[] PROGMEM = "*";
+const char string80[] PROGMEM = "/";
+const char string81[] PROGMEM = "mod";
+const char string82[] PROGMEM = "1+";
+const char string83[] PROGMEM = "1-";
+const char string84[] PROGMEM = "abs";
+const char string85[] PROGMEM = "random";
+const char string86[] PROGMEM = "max";
+const char string87[] PROGMEM = "min";
+const char string88[] PROGMEM = "=";
+const char string89[] PROGMEM = "<";
+const char string90[] PROGMEM = "<=";
+const char string91[] PROGMEM = ">";
+const char string92[] PROGMEM = ">=";
+const char string93[] PROGMEM = "/=";
+const char string94[] PROGMEM = "plusp";
+const char string95[] PROGMEM = "minusp";
+const char string96[] PROGMEM = "zerop";
+const char string97[] PROGMEM = "oddp";
+const char string98[] PROGMEM = "evenp";
+const char string99[] PROGMEM = "stringp";
+const char string100[] PROGMEM = "string=";
+const char string101[] PROGMEM = "concatenate";
+const char string102[] PROGMEM = "subseq";
+const char string103[] PROGMEM = "logand";
+const char string104[] PROGMEM = "logior";
+const char string105[] PROGMEM = "logxor";
+const char string106[] PROGMEM = "lognot";
+const char string107[] PROGMEM = "ash";
+const char string108[] PROGMEM = "logbitp";
+const char string109[] PROGMEM = "eval";
+const char string110[] PROGMEM = "globals";
+const char string111[] PROGMEM = "locals";
+const char string112[] PROGMEM = "makunbound";
+const char string113[] PROGMEM = "break";
+const char string114[] PROGMEM = "read";
+const char string115[] PROGMEM = "prin1";
+const char string116[] PROGMEM = "print";
+const char string117[] PROGMEM = "princ";
+const char string118[] PROGMEM = "terpri";
+const char string119[] PROGMEM = "read-line";
+const char string120[] PROGMEM = "read-byte";
+const char string121[] PROGMEM = "write-byte";
+const char string122[] PROGMEM = "restart-i2c";
+const char string123[] PROGMEM = "gc";
+const char string124[] PROGMEM = "room";
+const char string125[] PROGMEM = "save-image";
+const char string126[] PROGMEM = "load-image";
+const char string127[] PROGMEM = "cls";
+const char string128[] PROGMEM = "pinmode";
+const char string129[] PROGMEM = "digitalread";
+const char string130[] PROGMEM = "digitalwrite";
+const char string131[] PROGMEM = "analogread";
+const char string132[] PROGMEM = "analogwrite";
+const char string133[] PROGMEM = "delay";
+const char string134[] PROGMEM = "millis";
+const char string135[] PROGMEM = "note";
+const char string136[] PROGMEM = "edit";
+const char string137[] PROGMEM = "pprint";

 const tbl_entry_t lookup_table[] PROGMEM = {
   { string0, NULL, NIL, NIL },
@@ -2125,134 +2260,139 @@
   { string2, NULL, 1, 0 },
   { string3, NULL, 1, 0 },
   { string4, NULL, 1, 0 },
-  { string5, NULL, 0, 127 },
+  { string5, NULL, 1, 0 },
   { string6, NULL, 0, 127 },
   { string7, NULL, 0, 127 },
   { string8, NULL, 0, 127 },
-  { string9, NULL, NIL, NIL },
-  { string10, sp_quote, 1, 1 },
-  { string11, sp_defun, 0, 127 },
-  { 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_formillis, 1, 127 },
-  { string23, sp_withi2c, 1, 127 },
-  { string24, sp_withspi, 1, 127 },
-  { string25, NULL, NIL, NIL },
-  { string26, tf_progn, 0, 127 },
-  { string27, tf_return, 0, 127 },
-  { string28, tf_if, 2, 3 },
-  { string29, tf_cond, 0, 127 },
-  { string30, tf_when, 1, 127 },
-  { string31, tf_unless, 1, 127 },
-  { string32, tf_and, 0, 127 },
-  { string33, tf_or, 0, 127 },
-  { string34, NULL, NIL, NIL },
-  { string35, fn_not, 1, 1 },
-  { string36, fn_not, 1, 1 },
-  { string37, fn_cons, 2, 2 },
-  { string38, fn_atom, 1, 1 },
-  { string39, fn_listp, 1, 1 },
-  { string40, fn_consp, 1, 1 },
-  { string41, fn_numberp, 1, 1 },
-  { string42, fn_streamp, 1, 1 },
-  { string43, fn_eq, 2, 2 },
-  { string44, fn_car, 1, 1 },
-  { string45, fn_car, 1, 1 },
-  { string46, fn_cdr, 1, 1 },
-  { string47, fn_cdr, 1, 1 },
-  { string48, fn_caar, 1, 1 },
-  { string49, fn_cadr, 1, 1 },
-  { string50, fn_cadr, 1, 1 },
-  { string51, fn_cdar, 1, 1 },
-  { string52, fn_cddr, 1, 1 },
-  { string53, fn_caaar, 1, 1 },
-  { string54, fn_caadr, 1, 1 },
-  { string55, fn_cadar, 1, 1 },
-  { string56, fn_caddr, 1, 1 },
-  { string57, fn_caddr, 1, 1 },
-  { string58, fn_cdaar, 1, 1 },
-  { string59, fn_cdadr, 1, 1 },
-  { string60, fn_cddar, 1, 1 },
-  { string61, fn_cdddr, 1, 1 },
-  { string62, fn_length, 1, 1 },
-  { string63, fn_list, 0, 127 },
-  { string64, fn_reverse, 1, 1 },
-  { string65, fn_nth, 2, 2 },
-  { string66, fn_assoc, 2, 2 },
-  { string67, fn_member, 2, 2 },
-  { string68, fn_apply, 2, 127 },
-  { string69, fn_funcall, 1, 127 },
-  { string70, fn_append, 0, 127 },
-  { string71, fn_mapc, 2, 3 },
-  { string72, fn_mapcar, 2, 3 },
-  { string73, fn_add, 0, 127 },
-  { string74, fn_subtract, 1, 127 },
-  { string75, fn_multiply, 0, 127 },
-  { string76, fn_divide, 2, 127 },
-  { string77, fn_mod, 2, 2 },
-  { string78, fn_oneplus, 1, 1 },
-  { string79, fn_oneminus, 1, 1 },
-  { string80, fn_abs, 1, 1 },
-  { string81, fn_random, 1, 1 },
-  { string82, fn_max, 1, 127 },
-  { string83, fn_min, 1, 127 },
-  { string84, fn_numeq, 1, 127 },
-  { string85, fn_less, 1, 127 },
-  { string86, fn_lesseq, 1, 127 },
-  { string87, fn_greater, 1, 127 },
-  { string88, fn_greatereq, 1, 127 },
-  { string89, fn_noteq, 1, 127 },
-  { string90, fn_plusp, 1, 1 },
-  { string91, fn_minusp, 1, 1 },
-  { string92, fn_zerop, 1, 1 },
-  { string93, fn_oddp, 1, 1 },
-  { string94, fn_evenp, 1, 1 },
-  { string95, fn_stringp, 1, 1 },
-  { string96, fn_stringeq, 2, 2 },
-  { string97, fn_concatenate, 1, 127 },
-  { string98, fn_subseq, 2, 3 },
-  { string99, fn_logand, 0, 127 },
-  { string100, fn_logior, 0, 127 },
-  { string101, fn_logxor, 0, 127 },
-  { string102, fn_lognot, 1, 1 },
-  { string103, fn_ash, 2, 2 },
-  { string104, fn_logbitp, 2, 2 },
-  { string105, fn_eval, 1, 1 },
-  { string106, fn_globals, 0, 0 },
-  { string107, fn_locals, 0, 0 },
-  { string108, fn_makunbound, 1, 1 },
-  { string109, fn_break, 0, 0 },
-  { string110, fn_read, 0, 0 },
-  { string111, fn_prin1, 1, 1 },
-  { string112, fn_print, 1, 1 },
-  { string113, fn_princ, 1, 1 },
-  { string114, fn_terpri, 0, 0 },
-  { string115, fn_readline, 0, 0 },
-  { string116, fn_readbyte, 0, 2 },
-  { string117, fn_writebyte, 1, 2 },
-  { string118, fn_restarti2c, 1, 2 },
-  { string119, fn_gc, 0, 0 },
-  { string120, fn_room, 0, 0 },
-  { string121, fn_saveimage, 0, 1 },
-  { string122, fn_loadimage, 0, 0 },
-  { string123, fn_cls, 0, 0 },
-  { string124, fn_pinmode, 2, 2 },
-  { string125, fn_digitalread, 1, 1 },
-  { string126, fn_digitalwrite, 2, 2 },
-  { string127, fn_analogread, 1, 1 },
-  { string128, fn_analogwrite, 2, 2 },
-  { string129, fn_delay, 1, 1 },
-  { string130, fn_millis, 0, 0 },
-  { string131, fn_note, 0, 3 },
-  { string132, fn_edit, 1, 1 },
+  { string9, NULL, 0, 127 },
+  { string10, NULL, NIL, NIL },
+  { string11, sp_quote, 1, 1 },
+  { string12, sp_defun, 0, 127 },
+  { string13, sp_defvar, 2, 2 },
+  { string14, sp_setq, 2, 2 },
+  { string15, sp_loop, 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_withi2c, 1, 127 },
+  { string27, sp_withspi, 1, 127 },
+  { string28, NULL, NIL, NIL },
+  { string29, tf_progn, 0, 127 },
+  { string30, tf_return, 0, 127 },
+  { string31, tf_if, 2, 3 },
+  { string32, tf_cond, 0, 127 },
+  { string33, tf_when, 1, 127 },
+  { string34, tf_unless, 1, 127 },
+  { string35, tf_and, 0, 127 },
+  { string36, tf_or, 0, 127 },
+  { string37, NULL, NIL, NIL },
+  { string38, fn_not, 1, 1 },
+  { string39, fn_not, 1, 1 },
+  { string40, fn_cons, 2, 2 },
+  { string41, fn_atom, 1, 1 },
+  { string42, fn_listp, 1, 1 },
+  { string43, fn_consp, 1, 1 },
+  { string44, fn_numberp, 1, 1 },
+  { string45, fn_symbolp, 1, 1 },
+  { string46, fn_streamp, 1, 1 },
+  { string47, fn_eq, 2, 2 },
+  { string48, fn_car, 1, 1 },
+  { string49, fn_car, 1, 1 },
+  { string50, fn_cdr, 1, 1 },
+  { string51, fn_cdr, 1, 1 },
+  { string52, fn_caar, 1, 1 },
+  { string53, fn_cadr, 1, 1 },
+  { string54, fn_cadr, 1, 1 },
+  { string55, fn_cdar, 1, 1 },
+  { string56, fn_cddr, 1, 1 },
+  { string57, fn_caaar, 1, 1 },
+  { string58, fn_caadr, 1, 1 },
+  { string59, fn_cadar, 1, 1 },
+  { string60, fn_caddr, 1, 1 },
+  { string61, fn_caddr, 1, 1 },
+  { string62, fn_cdaar, 1, 1 },
+  { string63, fn_cdadr, 1, 1 },
+  { string64, fn_cddar, 1, 1 },
+  { string65, fn_cdddr, 1, 1 },
+  { string66, fn_length, 1, 1 },
+  { string67, fn_list, 0, 127 },
+  { string68, fn_reverse, 1, 1 },
+  { string69, fn_nth, 2, 2 },
+  { string70, fn_assoc, 2, 2 },
+  { string71, fn_member, 2, 2 },
+  { string72, fn_apply, 2, 127 },
+  { string73, fn_funcall, 1, 127 },
+  { string74, fn_append, 0, 127 },
+  { string75, fn_mapc, 2, 3 },
+  { string76, fn_mapcar, 2, 3 },
+  { string77, fn_add, 0, 127 },
+  { string78, fn_subtract, 1, 127 },
+  { string79, fn_multiply, 0, 127 },
+  { string80, fn_divide, 2, 127 },
+  { string81, fn_mod, 2, 2 },
+  { string82, fn_oneplus, 1, 1 },
+  { string83, fn_oneminus, 1, 1 },
+  { string84, fn_abs, 1, 1 },
+  { string85, fn_random, 1, 1 },
+  { string86, fn_max, 1, 127 },
+  { string87, fn_min, 1, 127 },
+  { string88, fn_numeq, 1, 127 },
+  { string89, fn_less, 1, 127 },
+  { string90, fn_lesseq, 1, 127 },
+  { string91, fn_greater, 1, 127 },
+  { string92, fn_greatereq, 1, 127 },
+  { string93, fn_noteq, 1, 127 },
+  { string94, fn_plusp, 1, 1 },
+  { string95, fn_minusp, 1, 1 },
+  { string96, fn_zerop, 1, 1 },
+  { string97, fn_oddp, 1, 1 },
+  { string98, fn_evenp, 1, 1 },
+  { string99, fn_stringp, 1, 1 },
+  { string100, fn_stringeq, 2, 2 },
+  { string101, fn_concatenate, 1, 127 },
+  { string102, fn_subseq, 2, 3 },
+  { string103, fn_logand, 0, 127 },
+  { string104, fn_logior, 0, 127 },
+  { string105, fn_logxor, 0, 127 },
+  { string106, fn_lognot, 1, 1 },
+  { string107, fn_ash, 2, 2 },
+  { string108, fn_logbitp, 2, 2 },
+  { string109, fn_eval, 1, 1 },
+  { string110, fn_globals, 0, 0 },
+  { string111, fn_locals, 0, 0 },
+  { string112, fn_makunbound, 1, 1 },
+  { string113, fn_break, 0, 0 },
+  { string114, fn_read, 0, 0 },
+  { string115, fn_prin1, 1, 1 },
+  { string116, fn_print, 1, 1 },
+  { string117, fn_princ, 1, 1 },
+  { string118, fn_terpri, 0, 0 },
+  { string119, fn_readline, 0, 0 },
+  { string120, fn_readbyte, 0, 2 },
+  { string121, fn_writebyte, 1, 2 },
+  { string122, fn_restarti2c, 1, 2 },
+  { string123, fn_gc, 0, 0 },
+  { string124, fn_room, 0, 0 },
+  { string125, fn_saveimage, 0, 1 },
+  { string126, fn_loadimage, 0, 0 },
+  { string127, fn_cls, 0, 0 },
+  { string128, fn_pinmode, 2, 2 },
+  { string129, fn_digitalread, 1, 1 },
+  { string130, fn_digitalwrite, 2, 2 },
+  { string131, fn_analogread, 1, 1 },
+  { string132, fn_analogwrite, 2, 2 },
+  { string133, fn_delay, 1, 1 },
+  { string134, fn_millis, 0, 0 },
+  { string135, fn_note, 0, 3 },
+  { string136, fn_edit, 1, 1 },
+  { string137, fn_pprint, 1, 1 },
 };

 // Table lookup functions
@@ -2267,19 +2407,19 @@
   return ENDFUNCTIONS;
 }

-int lookupfn(unsigned int name) {
+int lookupfn(symbol_t name) {
   return pgm_read_word(&lookup_table[name].fptr);
 }

-int lookupmin(unsigned int name) {
+int lookupmin(symbol_t name) {
   return pgm_read_word(&lookup_table[name].min);
 }

-int lookupmax(unsigned int name) {
+int lookupmax(symbol_t name) {
   return pgm_read_word(&lookup_table[name].max);
 }

-char *lookupstring (unsigned int name) {
+char *lookupstring (symbol_t name) {
   strcpy_P(buffer, (char *)(pgm_read_word(&lookup_table[name].string)));
   return buffer;
 }
@@ -2303,7 +2443,7 @@
   if ((form->type == NUMBER) || (form->type == STRING)) return form;

   if (form->type == SYMBOL) {
-    unsigned int name = form->name;
+    symbol_t name = form->name;
     if (name == NIL) return nil;
     object *pair = value(name, env);
     if (pair != NULL) return cdr(pair);
@@ -2319,9 +2459,10 @@

   // List starts with a symbol?
   if (function->type == SYMBOL) {
-    unsigned int name = function->name;
+    symbol_t name = function->name;

     if ((name == LET) || (name == LETSTAR)) {
+      int TCstart = TC;
       object *assigns = first(args);
       object *forms = cdr(args);
       object *newenv = env;
@@ -2334,7 +2475,7 @@
       }
       env = newenv;
       form = tf_progn(forms,env);
-      TC = 1;
+      TC = TCstart;
       goto EVAL;
     }

@@ -2343,9 +2484,11 @@
       object *envcopy = NULL;
       while (env != NULL) {
         object *pair = first(env);
-        object *val = cdr(pair);
-        if (val->type == NUMBER) val = number(val->integer);
-        push(cons(car(pair), val), envcopy);
+        if (pair != NULL) {
+          object *val = cdr(pair);
+          if (val->type == NUMBER) val = number(val->integer);
+          push(cons(car(pair), val), envcopy);
+        }
         env = cdr(env);
       }
       return cons(symbol(CLOSURE), cons(envcopy,args));
@@ -2383,7 +2526,7 @@
   args = cdr(head);

   if (function->type == SYMBOL) {
-    unsigned int name = function->name;
+    symbol_t name = function->name;
     if (name >= ENDFUNCTIONS) error2(fname, F("is not a function"));
     if (nargs<lookupmin(name)) error2(fname, F("has too few arguments"));
     if (nargs>lookupmax(name)) error2(fname, F("has too many arguments"));
@@ -2393,19 +2536,30 @@
   }

   if (listp(function) && issymbol(car(function), LAMBDA)) {
-    form = closure(TCstart, fname, NULL, cdr(function), args, &env);
+    dropframe(TCstart, &env);
+    form = closure(fname, NULL, cdr(function), args, &env);
+    pop(GCStack);
+    int trace = tracing(fname->name);
+    if (trace) {
+      object *result = eval(form, env);
+      indent((--(TraceDepth[trace-1]))<<1);
+      pint(TraceDepth[trace-1]); pchar(':'); pchar(' '); printobject(fname); pfstring(F(" returned "));
+      printobject(result); pln();
+      return result;
+    } else {
+      TC = 1;
+      goto EVAL;
+    }
+  }
+
+  if (listp(function) && issymbol(car(function), CLOSURE)) {
+    function = cdr(function);
+    dropframe(TCstart, &env);
+    form = closure(fname, car(function), cdr(function), args, &env);
     pop(GCStack);
     TC = 1;
     goto EVAL;
-  }
-
-  if (listp(function) && issymbol(car(function), CLOSURE)) {
-    function = cdr(function);
-    form = closure(TCstart, fname, car(function), cdr(function), args, &env);
-    pop(GCStack);
-    TC = 1;
-    goto EVAL;
-  }
+  }

   error2(fname, F("is an illegal function")); return nil;
 }
@@ -2490,7 +2644,7 @@
   } else if (form->type == NUMBER) {
     pint(integer(form));
   } else if (form->type == SYMBOL) {
-    pstring(name(form));
+    if (form->name != NOTHING) pstring(name(form));
   } else if (form->type == STRING) {
     printstring(form);
   } else if (form->type == STREAM) {
@@ -2624,7 +2778,7 @@
   initworkspace();
   initenv();
   _end = 0xA5;      // Canary to check stack
-  pfstring(F("uLisp 1.6")); pln();
+  pfstring(F("uLisp 1.7")); pln();
 }

 // Read/Evaluate/Print loop
@@ -2650,7 +2804,7 @@
     pfl();
     printobject(line);
     pop(GCStack);
-    pln();
+    pfl();
     pln();
   }
 }


Fixed address reading in UtilSlave

Fixed address reading in UtilSlave

--- RS485/UtilClient/UtilSlave/UtilSlave.ino
+++ RS485/UtilClient/UtilSlave/UtilSlave.ino
@@ -17,7 +17,6 @@
 #define PIN_DEBUG_LED 13

 config_hdr_t config;
-int my_address = 0;

 #define NUM_OUTPUTS 3
 byte output_to_pin[NUM_OUTPUTS] = {
@@ -48,7 +47,7 @@

   rs485.setup();

-  DEBUG_VALUELN(DEBUG_HIGH, "address=", my_address);
+  DEBUG_VALUELN(DEBUG_HIGH, "address=", config.address);
 }

@@ -77,7 +76,7 @@
     }
   }

-  blink_value(PIN_DEBUG_LED, my_address, 500, 4);
+  blink_value(PIN_DEBUG_LED, config.address, 500, 4);

   //delay(100);
 }
@@ -86,7 +85,7 @@
 {
   unsigned int msglen;

-  const byte *data = rs485.getMsg(my_address, &msglen);
+  const byte *data = rs485.getMsg(config.address, &msglen);

   if (data != NULL) {
     if (msglen < sizeof (msg_output_value_t)) {


Moved debug message before making WiFi connection starts.

--- src/_wifi.ino
+++ src/_wifi.ino
@@ -37,11 +37,10 @@

   // Connecting
   WiFi.disconnect();
+  DEBUGLOG("[WIFI] Connecting to %s\n", cfg.wifi_ssid);
   WiFi.begin(cfg.wifi_ssid, cfg.wifi_psk);
   MDNS.begin(cfg.hostname);
   MDNS.addService("http", "tcp", 80);
-
-  DEBUGLOG("[WIFI] Connecting to %s\n", cfg.wifi_ssid);

   // Check connection and switch to AP mode if no connection
   if (WiFi.waitForConnectResult() != WL_CONNECTED) {


fix bug

fix bug

--- DanceFeather/DanceFeather.ino
+++ DanceFeather/DanceFeather.ino
@@ -10,6 +10,7 @@
 #include <Adafruit_Sensor.h>
 #include <PDM.h>
 #include <KickFFT.h>
+#include <float.h>

 #define ACC_SIZE 64
 #define FFT_SIZE 512
@@ -217,7 +218,8 @@
 uint16_t _old_max_index = 0;
 float _phase_avg = 0;
 float _phaseRateAverage = 1;
-void updatePhase(float mag[], float phase[], uint16_t startIndex, uint16_t endIndex) {
+
+float updatePhase(float mag[], float phases[], uint16_t startIndex, uint16_t endIndex) {
     float maxValue = -FLT_MAX;
     int maxIndex = startIndex;
     for (int i = startIndex; i < endIndex; i++) {
@@ -227,13 +229,14 @@
             maxIndex = i;
         }
     }
-
-    float phase = phase[maxIndex];
+    Serial.print("INDEX: "); Serial.println(maxIndex);
+
+    float phase = phases[maxIndex];

     // Add the rate to our phase even in the case where we don't update the rate.
     _phase_avg += _phaseRateAverage;

-    if (maxIndex == _old_max_index && maxIndex > 1) {
+    if (maxIndex == _old_max_index && maxIndex > 0) {
         float phaseDiff = normalize_rads(phase - _old_phase);
         //Serial.print("PhaseDiff: "); Serial.println(phaseDiff);

@@ -249,7 +252,7 @@
         _phase_avg = (_phase_avg * 9 + phase) / 10;
         _phase_avg = normalize_rads(_phase_avg);
         //Serial.print("Phase    : "); Serial.println(phase);
-        //Serial.print("Phase Avg: "); Serial.println(_phase_avg);
+        Serial.print("Phase Avg: "); Serial.println(_phase_avg);
     }
     _old_phase = phase;
     _old_max_index = maxIndex;
@@ -263,26 +266,34 @@
     fftBuffer[i] = fftBuffer[i-1];
   }
   fftBuffer[0] = val;
-  float fs = 16000/ACC_SIZE; // 250 Hz
+  float fs = 16000/ACC_SIZE;
   float mag[20];
   float phase[20];
   uint16_t startIndex, endIndex;
   // KickFFT<int32_t>::fft(fs, 0, 4, FFT_SIZE, fftBuffer, mag, startIndex, endIndex);
-  fft_phase(fs, .5, 4, FFT_SIZE, fftBuffer, mag, phase, startIndex, endIndex);
-  Serial.print("startIndex: ");
-  Serial.print(startIndex);
-  Serial.print("  Mag: ");
-  for (int i = startIndex; i < endIndex; i++) {
-    Serial.print(mag[i]);
-    Serial.print(" ");
-  }
-  Serial.println("");
-  Serial.print("Phase: ");
-  for (int i = startIndex; i < endIndex; i++) {
-    Serial.print(phase[i]);
-    Serial.print(" ");
-  }
-  Serial.println("");
+  fft_phase(fs, 0, 4, FFT_SIZE, fftBuffer, mag, phase, startIndex, endIndex);
+  updatePhase(mag, phase, startIndex, endIndex);
+  float hz = fs * 2 * PI/ _phaseRateAverage;
+  Serial.print("BPM: "); Serial.println(hz * 60);
+
+
+  // each sample changes the phase _phaseRateAverage rads
+
+
+  // Serial.print("startIndex: ");
+  // Serial.print(startIndex);
+  // Serial.print("  Mag: ");
+  // for (int i = startIndex; i < endIndex; i++) {
+  //   Serial.print(mag[i]);
+  //   Serial.print(" ");
+  // }
+  // Serial.println("");
+  // Serial.print("Phase: ");
+  // for (int i = startIndex; i < endIndex; i++) {
+  //   Serial.print(phase[i]);
+  //   Serial.print(" ");
+  // }
+  // Serial.println("");
 }

 /*****************************************************************/


added call of the DC update_motors

added call of the DC update_motors

--- jenny5-firmware/jenny5-firmware.ino
+++ jenny5-firmware/jenny5-firmware.ino
@@ -33,7 +33,7 @@
 void setup()
 {
   first_start = 0;
-  strcpy(firmware_version, "2016.02.20.0");
+  strcpy(firmware_version, "2016.02.20.3s");

   current_buffer[0] = 0;

@@ -484,6 +484,10 @@
   if (serial_out[0])
     Serial.write(serial_out);

+  dc_motors_controller_TB6612FNG.update_motors(&buttons_controller, serial_out);
+  if (serial_out[0])
+    Serial.write(serial_out);
+
  //   Serial.print("freeMemory()=");
  // Serial.println(freeMemory());


Remove toplevel.ino file, it moved to firmware/examples

--- maxdetect_rht03_humidity_sensor.ino
+++ maxdetect_rht03_humidity_sensor.ino
@@ -1,113 +0,0 @@
-
-// Code to read out the humidity and temperature values from a
-// Maxdetect RHT03 humidity/temperature sensor.
-// See https://www.sparkfun.com/products/10167 and http://www.humiditycn.com/fl1_1.html
-//
-// Maintained at https://github.com/liyanage/maxdetect-rht03-humidity-sensor
-//
-
-#define PAYLOAD_BITS 40
-#define PAYLOAD_BYTES (PAYLOAD_BITS/8)
-#define PULSE_WIDTH_TRUE_THRESHOLD_MICROSECONDS 35
-#define USE_SPARK_CORE 1
-
-void sensorInterruptHandler();
-
-int sensorPin = D0;
-
-unsigned long listeningStartTime = 0;
-volatile unsigned long lastInterruptTime = 0;
-volatile int interruptCount = 0;
-volatile unsigned char payload[PAYLOAD_BYTES];
-
-double humidity = 0;
-double temperature = 0;
-
-enum {
-    StateUnknown,
-    StateIdle,
-    StateListening
-};
-int state = StateIdle;
-
-void setup() {
-#if USE_SPARK_CORE
-    Spark.variable("humidity", &humidity, DOUBLE);
-    Spark.variable("temperature", &temperature, DOUBLE);
-#endif
-}
-
-void loop() {
-    if (state == StateIdle) {
-        delay(1000);
-
-        // Pull the pin low for 10ms to request a measurement from the sensor
-        pinMode(sensorPin, OUTPUT);
-        digitalWrite(sensorPin, HIGH);
-        delay(10);
-        digitalWrite(sensorPin, LOW);
-        delay(10);
-        digitalWrite(sensorPin, HIGH);
-
-        // Configure the pin for input and set up the change interrupt handler
-        pinMode(sensorPin, INPUT_PULLUP);
-        listeningStartTime = micros();
-        attachInterrupt(sensorPin, sensorInterruptHandler, CHANGE);
-
-        state = StateListening;
-    } else if (state == StateListening) {
-        unsigned long listeningInterval = micros() - listeningStartTime;
-        // We assume that the measurement is done after this interval
-        if (listeningInterval > 4000000) {
-            // Collect the data
-            unsigned int rh = payload[0] << 8 | payload[1];
-            unsigned int t = payload[2] << 8 | payload[3];
-            humidity = (double)rh/10;
-            temperature = (double)t/10;
-
-            // Detach interrupt handler and reset all state for the next measurement
-            detachInterrupt(sensorPin);
-            lastInterruptTime = 0;
-            listeningStartTime = 0;
-            interruptCount = 0;
-            for (int i = 0; i < PAYLOAD_BYTES; i++) {
-                payload[i] = 0;
-            }
-
-            state = StateIdle;
-        }
-        delay(1000);
-    }
-}
-
-void sensorInterruptHandler() {
-    interruptCount++;
-
-    unsigned long now = micros();
-    unsigned long intervalSinceLastChange = 0;
-    if (lastInterruptTime) {
-        intervalSinceLastChange = now - lastInterruptTime;
-    }
-    lastInterruptTime = now;
-
-    if (interruptCount < 4) {
-        // The first three transitions are for the two leading 80us pulses, ignore those
-        return;
-    } else if (interruptCount % 2) {
-        // Every even transition starting with the fourth is for the rising
-        // edge that ends the 50us low period that comes before every bit.
-        // We note the time of that even transition (see above) but ignore
-        // it otherwise.
-        // Every odd transition marks the end of a bit and the length
-        // of the pulse will tell us if it was a 0 or 1 bit.
-        int bitIndex = (interruptCount - 5) / 2;
-        unsigned char value = intervalSinceLastChange > PULSE_WIDTH_TRUE_THRESHOLD_MICROSECONDS ? 1 : 0;
-        // Store the bit into the appropriate bit position of the appropriate
-        // payload byte.
-        payload[bitIndex/8] |= (value << (7 - (bitIndex % 8)));
-    }
-}
-
-
-
-


SerialCsvLogger.ino: use Print class for csv

Streaming of strings is the Arduino way and saves dynamic memory, here
60 bytes.

--- examples/SerialCsvLogger/SerialCsvLogger.ino
+++ examples/SerialCsvLogger/SerialCsvLogger.ino
@@ -7,10 +7,39 @@
 */

 RadiationWatch radiationWatch;
+unsigned long csvStartTime;
+
+void csvKeys(Print &print=Serial)
+{
+  // inizialise start time
+  csvStartTime = millis();
+  // Write CSV keys to a print class (default print class is Serial).
+  print.println("time(ms),count,cpm,uSv/h,uSv/hError");
+}
+
+void csvStatus(RadiationWatch radiationWatch, Print &print=Serial)
+{
+  // Write CSV to a print class (default print class is Serial).
+  // time(ms)
+  print.print(millis() - csvStartTime);
+  print.print(',');
+  // count
+  print.print(radiationWatch.radiationCount());
+  print.print(',');
+  // cpm
+  print.print(radiationWatch.cpm(), 3);
+  print.print(',');
+  // uSv/h
+  print.print(radiationWatch.uSvh(), 3);
+  print.print(',');
+  // uSv/hError
+  print.print(radiationWatch.uSvhError(), 3);
+  print.println("");
+}

 void onRadiationPulse() {
   // For each radiation update the values sent to serial in CSV.
-  Serial.println(radiationWatch.csvStatus());
+  csvStatus(radiationWatch);
 }

 void setup()
@@ -20,8 +49,8 @@
   // Register the callback.
   radiationWatch.registerRadiationCallback(&onRadiationPulse);
   // Print the CSV keys and the initial values.
-  Serial.println(radiationWatch.csvKeys());
-  Serial.println(radiationWatch.csvStatus());
+  csvKeys();
+  csvStatus(radiationWatch);
 }

 void loop()


Flash onboard LED to indicate Wifi connect status

--- OTABootstrap/OTABootstrap.ino
+++ OTABootstrap/OTABootstrap.ino
@@ -1,7 +1,7 @@
 /*
  *  Bootstrap OTA for ESP8266
  *
- *  Starts up using WPS to auto configure Wifi network, if WPS unsuccesful then try WifiManager.
+ *  Starts up using WPS to auto configure Wifi network, if WPS unsuccessful then try WifiManager.
  *  Once connected to Wifi it runs Over-The-Air (OTA) to enable remote program uploads to add further function.
  *
  *  For WPS, press the WPS button on the WiFi Access Point and then within 2 minutes power on the ESP8266 running
@@ -23,16 +23,28 @@
 #include <WiFiUdp.h>
 #include <ArduinoOTA.h>

+#include <Ticker.h>
+
+#define LED_PIN 2 // gpio2 for ESP-12, gpio1 for ESP-01, gpio12 for Sonoff
+
 const String THIS_NAME = String("ESP-") + ESP.getChipId();

 int heartBeatInterval = 15000; // 15 seconds
+Ticker ledBlinker;
+

 void setup(void) {
     Serial.begin(115200); Serial.println();
     Serial.print(THIS_NAME); Serial.print(__DATE__);Serial.println(__TIME__);

+    pinMode(LED_PIN, OUTPUT);
+    ledBlinker.attach(0.2, ledBlink); // start with fast blink to show Wifi connecting
+
     initWifi();
     Serial.print("WiFi connected to "); Serial.print(WiFi.SSID()); Serial.print(", IP address: "); Serial.println(WiFi.localIP());
+
+    ledBlinker.detach();
+    digitalWrite(LED_PIN, LOW);

     initOTA();
 }
@@ -44,6 +56,9 @@

     if (millis() - lastHeartBeat > heartBeatInterval) {
       Serial.println("loop running");
+      digitalWrite(LED_PIN, LOW);
+      delay(50);
+      digitalWrite(LED_PIN, HIGH);
       lastHeartBeat = millis();
     }
 }
@@ -76,6 +91,7 @@
   }

   // still no connection so try WifiManager
+  ledBlinker.attach(0.8, ledBlink); // slow blink led to show in Wifi AP mode
   WiFiManager wifiManager;
   wifiManager.setTimeout(240);
   if(!wifiManager.autoConnect(THIS_NAME.c_str())) {
@@ -108,3 +124,7 @@
   ArduinoOTA.begin();
 }

+void ledBlink() {
+  digitalWrite(LED_PIN, ! digitalRead(LED_PIN));
+}
+


arduino parseBuffer() comparison fixed

arduino parseBuffer() comparison fixed

--- src/arduino/main.ino
+++ src/arduino/main.ino
@@ -35,7 +35,7 @@
 }

 void parseBuffer(uint bufferSize) {
-  if ( bufferSize % 2 == 0) {
+  if ( bufferSize % 2 != 0) {
       // buffer has bad size so return
       return;
   }


LED-color now depends on server state

LED-color now depends on server state


'Prod' menus: bright/contrast working

'Prod' menus: bright/contrast working


Only send battery info if voltage has changed since last read

--- moisture.ino
+++ moisture.ino
@@ -15,13 +15,14 @@
 MySensor gw;
 MyMessage msg(CHILD_ID_MOISTURE, V_HUM);
 MyMessage voltage_msg(CHILD_ID_BATTERY, V_VOLTAGE);
+long oldvoltage = 0;

 void setup()
 {
   pinMode(SENSOR_POWER_PIN, OUTPUT);
   gw.begin();

-  gw.sendSketchInfo("Plant moisture w bat", "1.1");
+  gw.sendSketchInfo("Plant moisture w bat", "1.2");

   gw.present(CHILD_ID_MOISTURE, S_HUM);
   delay(250);
@@ -32,12 +33,16 @@
 {
   digitalWrite(SENSOR_POWER_PIN, HIGH); // Power on the sensor
   gw.sleep(STABILIZATION_TIME);
-  int moistureLevel = (1023 - analogRead(SENSOR_ANALOG_PIN)) / 10.23;
+  int moistureLevel = (1023 - analogRead(SENSOR_ANALOG_PIN));
   digitalWrite(SENSOR_POWER_PIN, LOW);
-  gw.send(msg.set(moistureLevel));
+  // Always send moisture information so the controller sees that the node is alive
+  gw.send(msg.set(moistureLevel / 10.23, 2));
   long voltage = readVcc();
-  gw.send(voltage_msg.set(voltage / 1000.0, 3)); // redVcc returns millivolts and set wants volts and how many decimals (3 in our case)
-  gw.sendBatteryLevel(round((voltage - BATTERY_ZERO) * 100.0 / (BATTERY_FULL - BATTERY_ZERO)));
+  if (oldvoltage != voltage) { // Only send battery information if voltage has changed, to conserve battery.
+    gw.send(voltage_msg.set(voltage / 1000.0, 3)); // redVcc returns millivolts and set wants volts and how many decimals (3 in our case)
+    gw.sendBatteryLevel(round((voltage - BATTERY_ZERO) * 100.0 / (BATTERY_FULL - BATTERY_ZERO)));
+    oldvoltage = voltage;
+  }
   gw.sleep(SLEEP_TIME);
 }