SD: add file browsing and TFT display

SD: add file browsing and TFT display

--- sd-n64/sd-n64.ino
+++ sd-n64/sd-n64.ino
@@ -21,14 +21,20 @@
  */

 #include "pins_arduino.h"
-#include "../crc_table.h"
+#include "crc_table.h"
 #include <SPI.h>
 #include <SD.h>
-
-#define INPUT_FILENAME "1key.m64"
+#include <TFT.h>
+#include <Bounce2.h>

 #define SD_SS_PIN 4
 #define STATUS_PIN 13
+#define CS 10
+#define DC 9
+#define RESET 7 // Moved from 8, which is in use by the N64
+
+#define NEXT 2
+#define SELECT 3

 #define SERIAL_BAUD_RATE 9600

@@ -40,29 +46,29 @@
 #define LED_HIGH DDRB &= ~0x20
 #define LED_LOW DDRB |= 0x20

-#define INPUT_BUFFER_SIZE 64 // This is ideal since it allows us to read 256*4/2 = 512 bytes
+#define INPUT_BUFFER_SIZE 16 // This is ideal since it allows us to read 256*4/2 = 512 bytes
 // at once. 512 bytes is an optimization for reading the sd card and skips using another buffer.

 #define INPUT_BUFFER_UPDATE_TIMEOUT 10 // 10 ms

-static char n64_raw_dump[38]; // maximum recv is 1+2+32 bytes + 1 bit
+static char n64_raw_dump[14]; // maximum recv is 1+2+32 bytes + 1 bit
 // n64_raw_dump does /not/ include the command byte. That gets pushed into
 // n64_command:
 static unsigned char n64_command;
 // bytes to send to the 64
 // maximum we'll need to send is 33, 32 for a read request and 1 CRC byte
-static unsigned char n64_buffer[33];
+static unsigned char n64_buffer[5];
 static void get_n64_command();
 static void n64_send();

 // Simple switch buffer. (If buffer A fails to load while buffer B is in use,
 // we still okay, and will try again next loop)
-static unsigned long inputBuffer[INPUT_BUFFER_SIZE];
+static unsigned long *inputBuffer;
 static bool bufferALoaded, bufferBLoaded;
 static bool bufferAInUse, bufferBInUse;
 static int bufferEndPos;
 static bool bufferOneMore;
-static long  bufferPos;
+static long bufferPos;
 static void updateInputBuffer();

 static File m64File;
@@ -71,11 +77,82 @@

 static bool finished = false;

+//static unsigned int progressPos = 0;
+static unsigned long numFrames = 0, curFrame = 0;
+
+#define dirPos curFrame
+#define numFiles numFrames
+//static unsigned long &dirPos = curFrame, &numFiles = numFrames;
+
+TFT screen = TFT(CS, DC, RESET);
+
+Bounce next;
+Bounce select;
+
+static void drawLogo(void)
+{
+  PImage logo = screen.loadImage("mario.bmp");
+  if (!logo.isValid()) {
+    screen.println(F("error while loading mario.bmp"));
+  }
+  screen.image(logo, screen.width() - logo.width(), 0);
+  logo.close();
+}
+
+static void clear(void)
+{
+  screen.setCursor(0,0);
+  screen.background(0,0,0);
+  drawLogo();
+}
+
+static bool extMatches(const char *name)
+{
+  int len = strlen(name);
+  if (len < 5)
+    return false;
+
+  return !strcmp_P(name + len - 4, PSTR(".M64"));
+}
+
+static void drawList()
+{
+  screen.setCursor(0,0);
+  File dir = SD.open(F("/"));
+  if (!dir) {
+    screen.println(F("Failed to open root"));
+    return;
+  }
+  dir.rewindDirectory();
+  int pos = 0;
+  for (m64File = dir.openNextFile(); m64File; m64File = dir.openNextFile()) {
+    const char *name = m64File.name();
+    if (!m64File.isDirectory() && extMatches(name)) {
+      if (pos == dirPos) {
+        screen.stroke(0,255,0);
+        strcpy(n64_raw_dump, name);
+      } else {
+        screen.stroke(255,255,255);
+      }
+
+      screen.println(name);
+      pos++;
+    }
+    m64File.close();
+  }
+  dir.close();
+  numFiles = pos;
+  screen.stroke(255,255,255);
+}
+
 void setup()
 {
+  screen.begin();
+  screen.background(0,0,0);
+
   Serial.begin(SERIAL_BAUD_RATE);
   while (!Serial) { ; } // wait for serial port to connect. Needed for native USB port only
-  Serial.println("Starting up");
+  screen.println(F("Starting up"));

   // Status LED
   digitalWrite(STATUS_PIN, LOW);
@@ -85,20 +162,18 @@
   digitalWrite(N64_PIN, LOW);
   pinMode(N64_PIN, INPUT);

+  pinMode(NEXT, INPUT_PULLUP);
+  pinMode(SELECT, INPUT_PULLUP);
+  next.attach(NEXT);
+  select.attach(SELECT);
+
   // Initialize SD card
   if (!SD.begin(SD_SS_PIN)) {
     m64OpenSuccess = false;
-    Serial.println(F("SD initialization failed!"));
+    screen.println(F("SD initialization failed!"));
     return;
   }
-  Serial.println(F("SD initialization done."));
-
-  // Open m64 file
-  if (!openM64()) {
-    m64OpenSuccess = false;
-    return;
-  }
-  m64OpenSuccess = true;
+  screen.println(F("SD initialization done."));

   // Setup buffer
   bufferALoaded = false;
@@ -108,19 +183,42 @@
   bufferEndPos = -1;
   bufferOneMore = true;
   bufferPos = -1;
-  updateInputBuffer();
-
-  Serial.println(F("Initialization done."));
-}
-
-void loop()
+
+  screen.println(F("Initialization done."));
+
+  clear();
+
+  drawList();
+}
+
+static bool selected = false;
+
+static void selectLoop()
 {
+  next.update();
+  select.update();
+  if (next.fell()) {
+    dirPos++;
+    if (dirPos == numFiles)
+      dirPos = 0;
+    drawList();
+  } else if (select.fell()) {
+    selected = true;
+    openM64();
+    updateInputBuffer();
+  }
+}
+
+ void mainLoop()
+ {
     unsigned char data, addr;
     unsigned long updateTime;
+    unsigned int curPos;

     // Loop forever if file open failed
     if (!m64OpenSuccess) {
-        Serial.print(F("Stopping program due to failed file open..."));
+        screen.stroke(255,0,0);
+        screen.print(F("Stopping program due to failed file open..."));
         while (true) { ; }
     }

@@ -161,7 +259,7 @@

             n64_send(n64_buffer, 3, 0);
             interrupts();
-            Serial.println(F("Controller identified"));
+            screen.println(F("Controller identified"));
             break;
         case 0x01:
             // If the TAS is finished, there's nothing left to do.
@@ -185,10 +283,19 @@
             // Record if it took longer than expected
             updateTime = micros() - updateTime;
             if (updateTime > INPUT_BUFFER_UPDATE_TIMEOUT * 1000) {
-                Serial.print(F("Input buffer update took to long ("));
-                Serial.print(updateTime / 1000);
-                Serial.println(F(" ms)"));
+                screen.print(F("Input buffer update took to long ("));
+                screen.print(updateTime / 1000);
+                screen.println(F(" ms)"));
             }
+
+            curFrame++;
+            curPos = (curFrame * screen.width()) / numFrames;
+            screen.fill(255,0,0);
+/*            while (progressPos < curPos) {
+              screen.point(progressPos++, screen.height() - 1);
+            }*/
+            screen.fill(255,255,255);
+
             break;
         case 0x02:
             // A read. If the address is 0x8000, return 32 bytes of 0x80 bytes,
@@ -202,7 +309,7 @@

             n64_send(n64_buffer, 33, 1);
             interrupts();
-            Serial.println(F("Got a read, what?"));
+            screen.println(F("Got a read, what?"));

             //Serial.println("It was 0x02: the read command");
             break;
@@ -231,7 +338,7 @@
             // send it
             n64_send(n64_buffer, 1, 1);
             interrupts();
-            Serial.println(F("Got a write, what?"));
+            screen.println(F("Got a write, what?"));

             // end of time critical code
             // was the address the rumble latch at 0xC000?
@@ -256,42 +363,61 @@

         default:
             interrupts();
-            Serial.print(F("Unknown command: 0x"));
-            Serial.println(n64_command, HEX);
+            screen.print(F("Unknown command: 0x"));
+            screen.println(n64_command, HEX);
             break;
     }
+}
+
+
+void loop()
+{
+    if (!selected)
+      return selectLoop();
+    mainLoop();
 }

 static bool openM64() {
     char signature[4];
     int version;
+
+    clear();

     // Open the file for reading:
-    Serial.println(F("Opening file '" INPUT_FILENAME "'..."));
-    m64File = SD.open(F(INPUT_FILENAME));
+    screen.print(F("Opening file '"));
+    screen.print(n64_raw_dump);
+    screen.println(F("'..."));
+    m64File = SD.open(n64_raw_dump);
+
+    screen.stroke(255,0,0);

     // Error check
     if (!m64File) {
-        Serial.println(F("Error in opening file"));
+        screen.println(F("Error in opening file"));
         return false;
     }

     // Open header
     if (m64File.read(signature, 4) != 4 || m64File.read(&version, 4) != 4) {
         m64File.close();
+        screen.println(F("Failed to read signature"));
         return false;
     }

     // Validate file signature
     if (memcmp(signature, "M64\x1A", 4) != 0) {
-        Serial.println(F("File is not an m64 file or an error occured while reading."));
+        screen.println(F("m64 signature invalid"));
         m64File.close();
         return false;
     }
+
+    screen.stroke(0,0,255);

     // Print version
-    Serial.print(F("M64 Version: "));
-    Serial.println(version);
+    screen.print(F("M64 Version: "));
+    screen.println(version);
+
+    screen.stroke(255,0,0);

     // Get header size
     switch(version) {
@@ -304,19 +430,32 @@
             break;
         default:
           // Unknown version
-            Serial.println(F("Error: uknown M64 version"));
+            screen.println(F("Error: unknown M64 version"));
             m64File.close();
             return false;
     }

     // Final check
     if (!m64File.available()) {
-        Serial.println(F("No input data found in file"));
+        screen.println(F("No input data found in file"));
         m64File.close();
         return false;
     }

-    Serial.println(F("File opened succesfully"));
+    inputBuffer = malloc(INPUT_BUFFER_SIZE * 4);
+    if (!inputBuffer) {
+      screen.println(F("Failed to allocate input buffer"));
+      m64File.close();
+      return false;
+    }
+
+    screen.stroke(255,255,255);
+
+    screen.println(F("File opened successfully"));
+
+    m64OpenSuccess = true;
+
+    numFrames = (m64File.size() - m64File.position()) / 4;

     return true;
 }
@@ -341,7 +480,7 @@
         if (bufferPos < INPUT_BUFFER_SIZE / 2) {
             // Verify the buffer in use is loaded
             if (!bufferALoaded) {
-                Serial.println(F("Error: New input was not loaded in buffer."));
+                screen.println(F("Error: New input was not loaded in buffer."));
             }

             // Clear old buffer when loading
@@ -353,7 +492,7 @@
             bufferBInUse = false;
         } else {
             if (!bufferBLoaded) {
-                Serial.println(F("Error: New input was not loaded in buffer."));
+                screen.println(F("Error: New input was not loaded in buffer."));
             }

             // Clear old buffer when loading
@@ -370,7 +509,7 @@
     if (bufferEndPos != -1) {
         // Perform one more input then end once the last input data has been queued.
         if (!bufferOneMore) {
-            Serial.println(F("TAS finished playing"));
+            screen.println(F("TAS finished playing"));
             finished = true;
         }
         else if (bufferPos == bufferEndPos)
@@ -381,7 +520,7 @@

     // Check for file end
     if (!m64File.available()) {
-        Serial.println(F("End of M64 loaded into buffer"));
+//        screen.println(F("End of M64 loaded into buffer"));

         // Set end
         if (!bufferAInUse) {
@@ -393,7 +532,7 @@
             bufferEndPos = INPUT_BUFFER_SIZE/2 - 1;
         } else {
             // Da fuq? (This should never happen)
-            Serial.println(F("Unexpected ending of input file"));
+            screen.println(F("Unexpected ending of input file"));

             // End immediatley
             bufferEndPos = 0;
@@ -411,12 +550,12 @@
         // Read bytes
         readBytes = m64File.read(inputBuffer, INPUT_BUFFER_SIZE*2);
         if (readBytes == 0) {
-            Serial.println(F("Failed to read next inputs from file. (This is recoverable)"));
+            screen.println(F("Failed to read next inputs from file. (This is recoverable)"));
         }
         else {
             bufferALoaded = true;
             if (readBytes != INPUT_BUFFER_SIZE*2) {
-                Serial.println(F("End of M64 file found. Loading remaining bytes."));
+//                screen.println(F("End of M64 file found. Loading remaining bytes."));
                 bufferEndPos = readBytes / 4 - 1;
                 // Close file
                 m64File.close();
@@ -429,12 +568,12 @@
         // Read bytes
         readBytes = m64File.read(inputBuffer + (INPUT_BUFFER_SIZE / 2), INPUT_BUFFER_SIZE*2);
         if (readBytes == 0) {
-            Serial.println(F("Failed to read next inputs from file. (This is recoverable)"));
+            screen.println(F("Failed to read next inputs from file. (This is recoverable)"));
         }
         else {
             bufferBLoaded = true;
             if (readBytes != INPUT_BUFFER_SIZE*2) {
-                Serial.println(F("End of M64 file found. Loading remaining bytes."));
+//                screen.println(F("End of M64 file found. Loading remaining bytes."));
                 // buffer end is offset from middle
                 bufferEndPos = INPUT_BUFFER_SIZE / 2 + readBytes / 4 - 1;
                 // Close file


Dedicated wifiClient class for MQTT, restore mDNS port 80 advertisement

--- Arduino_Sketch/HASwitchPlate/HASwitchPlate.ino
+++ Arduino_Sketch/HASwitchPlate/HASwitchPlate.ino
@@ -99,7 +99,7 @@
 const uint16_t mqttMaxPacketSize = 4096;            // Size of buffer for incoming MQTT message
 String mqttClientId;                                // Auto-generated MQTT ClientID
 String mqttGetSubtopic;                             // MQTT subtopic for incoming commands requesting .val
-String mqttGetSubtopicJSON;                         // MQTT object buffer for JSON status when reqeusting .val
+String mqttGetSubtopicJSON;                         // MQTT object buffer for JSON status when requesting .val
 String mqttStateTopic;                              // MQTT topic for outgoing panel interactions
 String mqttStateJSONTopic;                          // MQTT topic for outgoing panel interactions in JSON format
 String mqttCommandTopic;                            // MQTT topic for incoming panel commands
@@ -117,6 +117,7 @@
 uint8_t nextionResetPin = D6;                       // Pin for Nextion power rail switch (GPIO12/D6)

 WiFiClient wifiClient;
+WiFiClient wifiMQTTClient;
 MQTTClient mqttClient(mqttMaxPacketSize);
 ESP8266WebServer webServer(80);
 ESP8266HTTPUpdateServer httpOTAUpdate;
@@ -166,7 +167,7 @@
   if (mdnsEnabled)
   {
     MDNS.begin(haspNode); // Add mDNS hostname
-    // MDNS.addService("http", "tcp", 80); this breaks Wemo devices when Home Assistant discovery is enabled.  No idea why.
+    MDNS.addService("http", "tcp", 80);
     if (debugTelnetEnabled)
     {
       MDNS.addService("telnet", "tcp", 23);
@@ -201,7 +202,7 @@
   espSetupOta();

   // Create server and assign callbacks for MQTT
-  mqttClient.begin(mqttServer, atoi(mqttPort), wifiClient);
+  mqttClient.begin(mqttServer, atoi(mqttPort), wifiMQTTClient);
   mqttClient.onMessage(mqttCallback);
   mqttConnect();

@@ -215,7 +216,6 @@
     telnetServer.begin();
     debugPrintln(String(F("TELNET: debug server enabled at telnet:")) + WiFi.localIP().toString());
   }
-
   debugPrintln(F("SYSTEM: System init complete."));
 }

@@ -597,9 +597,9 @@
   mqttStatusPayload += String(F("\"espUptime\":")) + String(long(millis() / 1000)) + String(F(","));
   mqttStatusPayload += String(F("\"signalStrength\":")) + String(WiFi.RSSI()) + String(F(","));
   mqttStatusPayload += String(F("\"haspIP\":\"")) + WiFi.localIP().toString() + String(F("\","));
-  mqttStatusPayload += String(F("\"heapFree\":")) + String(ESP.getFreeHeap());
-  mqttStatusPayload += String(F("\"heapFragmentation\":")) + String(ESP.getHeapFragmentation());
-  mqttStatusPayload += String(F("\"espCore\":")) + String(ESP.getCoreVersion());
+  mqttStatusPayload += String(F("\"heapFree\":")) + String(ESP.getFreeHeap()) + String(F(","));
+  mqttStatusPayload += String(F("\"heapFragmentation\":")) + String(ESP.getHeapFragmentation()) + String(F(","));
+  mqttStatusPayload += String(F("\"espCore\":\"")) + String(ESP.getCoreVersion()) + String(F("\""));
   mqttStatusPayload += "}";

   mqttClient.publish(mqttSensorTopic, mqttStatusPayload);


Display bars of current part

Display bars of current part

--- ableton-midi-foot-controller.ino
+++ ableton-midi-foot-controller.ino
@@ -167,6 +167,10 @@
   if (mode != SONG_MODE) {
     return;
   }
+
+  nextPartScheduled = false;
+  bars = 0;
+
   lcd.clear();
   lcd.setCursor(0, 0);
   lcd.print(message);
@@ -207,6 +211,8 @@
   if (mode != SONG_MODE) {
     return;
   }
+
+  nextPartScheduled = true;

   clearLine(1);
   lcd.setCursor(0, 1);
@@ -238,8 +244,8 @@
   allLedsTest();
   lcd.clear();

+  selectedSong = 0;
   changeMode(NORMAL_MODE);
-  selectedSong = 0;
 }

 void handleSongConfiguration(char* messageOriginal) {
@@ -479,7 +485,7 @@
   if (stopButton.isJustReleased()) {
     midiNoteSendStart = 0;
     midiNoteToSend = STOP_MIDI_NOTE;
-    stopButton.turnLedOff();
+    bars = 0;
     changeMode(NORMAL_MODE);
   }

@@ -547,8 +553,6 @@
   if (playButton.isJustPressed()) {
     playButton.turnLedOn();
   }
-
-

   if (playButton.isJustReleased()) {
     midiNoteSendStart = 0;
@@ -613,9 +617,31 @@
   }
 }

+void handleBarChange() {
+  if (mode != SONG_MODE || nextPartScheduled) {
+    return;
+  }
+  clearLine(1);
+  lcd.setCursor(0, 1);
+  lcd.print(bars);
+  lcd.print(" bars");
+}
+
 void RealTimeSystem(byte realtimebyte) {
   if (realtimebyte == CLOCK) {
     counter++;
+
+    if (denominator > 0) {
+      double increase = (1 / 24.0) * (denominator / 4.0);
+      fullDenominator = fullDenominator + increase;
+
+      if (fullDenominator >= numerator && numerator > 0) {
+        fullDenominator = 0;
+        bars++;
+        handleBarChange();
+      }
+    }
+
     if (counter == 24) {
       counter = 0;
       digitalWrite(bpmLed, HIGH);
@@ -638,6 +664,7 @@
   if (realtimebyte == STOP) {
     digitalWrite(bpmLed, LOW);
     playing = false;
+    bars = 0;
     changeMode(NORMAL_MODE);
   }
 }


Divided rotator positions into 18 steps

Divided rotator positions into 18 steps

--- Modules/Action/Rotator/ArduinoCodes/RotatorATmega/RotatorATmega.ino
+++ Modules/Action/Rotator/ArduinoCodes/RotatorATmega/RotatorATmega.ino
@@ -46,6 +46,8 @@
   myservo.attach(servo_pin);
 }

+int prev_pos = 0;
+
 void loop()
 {
     int input_val = cutAndMap(input.filteredAnalogRead(AVERAGE), 50, 975, 0, 1023);
@@ -55,7 +57,9 @@
       input_val = 1023;*/

     int pos = cutAndMap(input_val, 0, 1023, 0, 180);
-
-    myservo.write(pos);              // tell servo to go to position in variable 'pos'
-    delay(15);                       // waits 15ms for the servo to reach the position
+    if (abs(pos - prev_pos) > 10) {    // only move if change is more than 10
+      prev_pos = pos;
+      myservo.write(pos);              // tell servo to go to position in variable 'pos'
+      delay(15);                       // waits 15ms for the servo to reach the position
+    }
 }


Implemented output sequencing, compiles, not yet tested

--- src/Full_decoder/Full_decoder.ino
+++ src/Full_decoder/Full_decoder.ino
@@ -1,8 +1,9 @@
 #include <OneWire.h>
-
+#define CIRCULAR_BUFFER_XS
+#include <CircularBuffer.h>

 #include "config.h"
-#define VERSION 10400
+#define VERSION 10499

 #if PINSERVO == 1
 #warning "USING SERVO"
@@ -54,6 +55,7 @@

 bool pins_busy = false;

+CircularBuffer<uint8_t, MAX> pins_to_update;
 /*
 The LocoNet CV related stuff
 */
@@ -206,6 +208,7 @@
     DEBUG("Pin #");
     DEBUGLN(slot);
     confpins[slot]->print();
+    pins_to_update.push(slot);
 }
 void setup() {
 #ifdef USE_SERIAL
@@ -263,9 +266,15 @@

 void loop() {
 	pins_busy = false;
-  for (uint8_t i =0 ; i < pins_conf ; i++) {
-	 confpins[i]->update();
-  };
+  if (~pins_to_update.isEmpty()) {
+    if (~confpins[pins_to_update.first()]->update()) { // Update the first item, as long as update() returns true, otherwise...
+      DEBUG("Done updating ");
+      DEBUGLN(pins_to_update.first());
+      pins_to_update.shift(); // ..drop the first item
+      DEBUG(pins_to_update.size());
+      DEBUGLN(" active pins left in the queue");
+    }
+  }

   /*** LOCONET ***/
   LnPacket = LocoNet.receive();
@@ -292,6 +301,7 @@
   for (uint8_t i =0 ; i < MAX ; i++) {
     if (confpins[i]->_address == Address){
       confpins[i]->set(Direction, Output);
+      pins_to_update.push(i);
       eeprom_write_word((uint16_t*)&(_CV.conf[i].servo.state), confpins[i]->get_state());
       DEBUG("Thrown switch: ");
       DEBUG(i);


Update example to work with latest version of the library

--- Arduino/libraries/BackEmfMotor/examples/BackEmfMotorExample/BackEmfMotorExample.ino
+++ Arduino/libraries/BackEmfMotor/examples/BackEmfMotorExample/BackEmfMotorExample.ino
@@ -18,32 +18,17 @@

 BackEmfMotor gMotor;

-static void StartTargetSpeed(int speed, int dir) {
+static void StartTargetSpeed(int speed) {
   gMotor.SetTargetSpeed(speed);
   gMotor.SetCommand(BackEmfMotor::kStart);
-  gMotor.SetDirection(dir);
 }

-static void StartPWMSpeed(int pwm, int dir) {
-  gMotor.SetPwm(pwm);
+static void StartPwmMicros(int pwmMicros) {
+  gMotor.SetPwmMicros(pwmMicros);
   gMotor.SetCommand(BackEmfMotor::kStart);
-  gMotor.SetDirection(dir);
-}
-
-static void SetupPrescaler() {
-  //clear timer 1 bits
-  TCCR1B &= ~(0x7);
-  //set timer 1 prescaler to 1
-  TCCR1B |= 0x1;
-
-  //clear timer 2 bits
-  TCCR2B &= ~(0x7);
-  //set timer 2 prescaler to 1
-  TCCR2B |= 0x1;
 }

 void setup() {
-  SetupPrescaler();
 #ifdef __Use_CombinedL298HBridge__
   gMotor.Initialize(2, 3, 4, 11, 1);
 #else
@@ -64,22 +49,22 @@
       gMotor.SetCommand(BackEmfMotor::kStop);
       break;
     case '8':
-      StartTargetSpeed(256, 0);
+      StartTargetSpeed(256);
       break;
     case '2':
-      StartTargetSpeed(256, 1);
+      StartTargetSpeed(-256);
       break;
     case '7':
-      StartPWMSpeed(255, 0);
+      StartPwmMicros(9000);
       break;
     case '1':
-      StartPWMSpeed(255, 1);
+      StartPwmMicros(-9000);
       break;
     case '9':
-      StartPWMSpeed(128, 0);
+      StartPwmMicros(6000);
       break;
     case '3':
-      StartPWMSpeed(128, 1);
+      StartPwmMicros(-6000);
       break;
     }


Update calibration.ino

Update calibration.ino

--- arduino/AP_Utils/examples/calibration/calibration.ino
+++ arduino/AP_Utils/examples/calibration/calibration.ino
@@ -25,7 +25,6 @@
   int offsets[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
   //start ArduPod with the offsets
   ardupod.begin(offsets);
-  while(true);
 }

 void loop() {}


Minor bugfixes to the Tetris game as well as clear comments

--- arduino/libraries/ledtable/examples/Tetris/Tetris.ino
+++ arduino/libraries/ledtable/examples/Tetris/Tetris.ino
@@ -2,37 +2,81 @@
 #include <Adafruit_NeoPixel.h>
 #include <ledtable.h>

+/*
+ * SNES Controls for Tetris
+ *
+ * A:         put the block down at this column
+ * START:     start a new round, whole game resets all stats except the sessionHighscore, also shows the highscore and your final score
+ * SELECT:    pauses the game
+ * UP:        turn the block used at the moment
+ * RIGHT:     put the block one pixel to the right
+ * LEFT:      put the block one pixel to the left
+ * DOWN:      put the pixel one block down
+ *
+ */
+
+
+
+// Ports for SNES Controller
 #define clock 2
 #define strobe 3
 #define data 4
+
+// Size and pin for the LEDTable
 #define sizeX 20
 #define sizeY 10
 #define LEDTABLE_PIN 6

+// Global data storage for the block used at the moment and the next block
 byte mThisBlock;
 byte mNextBlock;
+
+// Rotation used at the moment (initializes at 0 every game)
 short mRotation = 0;
+
+// Start position of blocks (initializes at 0 | 5 every game)
 short mPosX = 0;
 short mPosY = 5;

+// Level management (cycles are the number of blocks fallen, counter is the variable of how many frames are gone since last reset to limit)
 byte cycles = 0;
+int counter = 0;
+
+// Level management. These can be changed in order to make levels easier or harder:
+  // limit - the base number of frames until a block falls used at level 1 (Default 30)
+  // maxCycles - the number of blocks that have to fall until the level gets up (Default 10)
+  // difficulty - the number of frames until a block falls used at maximum level (Default 10)
+  // difficultyHardening - the reduction in number of frames until a block falls when cycles reaches maxCycles (Default 5)
 byte limit = 30;
+byte baseLimit = limit;
+byte maxCycles = 10;
+byte difficulty = 10;
+byte difficultyHardening = 5;
+
+// ID of the block used at the moment, never resets, only if it overflows, is just for comparison with the previous block
 short blockCounter = 0;

+// Point counter (resets at Reset, if points are added when a block manifests it will be sent to Serial Write). Higher levels as well as deleting multiple rows at once will result in getting more points.
 short pointCounter = 0;
 int pointsThisRound = 0;
 int linesThisRound = 0;

+int sessionHighscore = 0;
+
+// Game states, when gameOver is activated it will reset at restart, pause whill reset at pressing SELECT (is a bit buggy atm)
 boolean gameOver = false;
 boolean pause = false;

+// The LEDTable to show the game
 LEDTable ledtable = LEDTable(LEDTABLE_PIN, 20, 10, PIXELORDER<snake>);

+// Initialization of the Controller
 Snes controller(clock, strobe, data);
-int counter = 0;
-
+
+// The array containing the color of the pixel placed in it.
 short fieldmap[sizeX][sizeY];

+// Array of Colors (RGB mapped to the block type).
 static const short colors[7][3] =
 {
   {
@@ -58,6 +102,7 @@
   }
 };

+// Array of blocks and rotations (7 Blocks with 4 Rotations, each one being created by 4 pixels that have a pair of coordinates related to the relation pixel (mPosX | mPosY)).
 static const short blocks[7][4][4][2] =
 {  {
   { {-1, 0},{ 0, 0},{ 1, 0},{ 2, 0} },   /* cyan    */
@@ -99,76 +144,95 @@
 void setup()
 {
   Serial.begin(9600);
-  Serial.println("SNES");
-
+
+  // Checking if Controller is avaible, if not tetris won't continue but stop.
+  if (controller.read() != false) {
+    Serial.println("SNES Controller avaible");
+    gameOver = true;
+  } else {
+    Serial.println("SNED Controller unavaible");
+  }
+
+  // Initialization of the Fieldmap to -1 (no pixel unavaible).
   initFieldmap();

+  // Generate a random Seed from a fluctuating port
   randomSeed(analogRead(0));
-
+
+  // Activate the LEDTable and set its brightness as well as coloring the game board.
   ledtable.begin();
-  ledtable.brightness(20);
+  ledtable.brightness(40);
   for (int i = 0; i < sizeY; i++) {
     for (int j = 0; j < sizeX; j++) {
       ledtable.fill(j,i,RGB(0,0,64));
     }
   }
   ledtable.show();
+
+  // Get the first random number since it is always 0, forget it and then set the Block and the next block.
   random(7);
   mThisBlock = random(7);
   mNextBlock = random(7);
+
+  // Show the block used at the moment
   showBlock();
 }

 // Main Loop for the Arduino
 void loop()
 {
+  // Get the controller state
   word state = controller.read();

-  if (!gameOver && !pause) {
-    if (bitRead(state, 4) == false)
-    {
-      rotate();
-      delay(125);
-    }
-    if (bitRead(state, 5) == false)
-    {
-      fall();
-      delay(20);
-    }
-    if (bitRead(state, 6) == false)
-    {
-      left();
+  // Check again if Controller is connected, otherwise do nothing, then check if the game isn't paused or over
+  if (state != false) {
+    if (!gameOver && !pause) {
+      if (bitRead(state, 4) == false)
+      {
+        rotate();
+        delay(125);
+      }
+      if (bitRead(state, 5) == false)
+      {
+        fall();
+        delay(20);
+      }
+      if (bitRead(state, 6) == false)
+      {
+        left();
+        delay(75);
+      }
+      if (bitRead(state, 7) == false)
+      {
+        right();
+        delay(75);
+      }
+      if (bitRead(state, 8) == false) {
+        down();
+        delay(75);
+      }
+    }
+    if (bitRead(state, 2) == false && !gameOver) {
+      pause = !pause;
+      delay(100);
+    }
+    if (bitRead(state, 3) == false) {
+      reset();
       delay(75);
     }
-    if (bitRead(state, 7) == false)
-    {
-      right();
-      delay(75);
-    }
-    if (bitRead(state, 8) == false) {
-      down();
-      delay(75);
-    }
-  }
-
-  if (bitRead(state, 2) == false && !gameOver) {
-    pause = !pause;
-    delay(100);
-  }
-  if (bitRead(state, 3) == false) {
-    reset();
-    delay(75);
   }
   counter++;

+  // Initiate fall sequence if the limit of frames is reached.
   if (counter >= limit && !gameOver && !pause) {
     fall();
     counter = 0;
   }

-  if (cycles > 10) {
-    if (limit > 5) {
-      limit -= 5;
+  // After a number of blocks manifested (cycles) reduce the limit.
+  if (cycles > maxCycles) {
+    if (limit > difficulty) {
+      limit -= difficultyHardening;
     }
     cycles = 0;
   }
@@ -191,14 +255,20 @@
 // Reset the whole Map
 void reset() {
   initFieldmap();
+  startNextBlock();
+  startNextBlock();
   ledtable.fill(RGB(0,0,64));
   ledtable.show();
   counter = 0;
+  Serial.println("Highscore: " + sessionHighscore);
+  Serial.println("Your score: " + pointCounter);
+  if (pointCounter > sessionHighscore) {
+    Serial.println("New Highscore!!! Congratulations!");
+    sessionHighscore = pointCounter;
+  }
   pointCounter = 0;
-  startNextBlock();
-  startNextBlock();
-  showBlock();
-  limit = 30;
+  showBlock();
+  limit = baseLimit;
   gameOver = false;
 }

@@ -220,10 +290,26 @@
   mNextBlock = random(7);
   showBlock();
   blockCounter++;
+//  showNextBlock();
   if (fieldmap[mPosX][mPosY] != -1) {
     gameOver = true;
   }
 }
+
+// Get the X value of the current block with pixel number pPixel
+int getX(int pPixel) {
+  return mPosX + blocks[mThisBlock][mRotation][pPixel][0];
+}
+
+// Get the Y value of the current block with pixel number pPixel
+int getY(int pPixel) {
+  return mPosY + blocks[mThisBlock][mRotation][pPixel][1];
+}
+
+Color getColor() {
+  return RGB(colors[mThisBlock][0],colors[mThisBlock][1],colors[mThisBlock][2]);
+}
+
 /*
  * ===========================================
  *  SNES-Controller Commands
@@ -307,7 +393,19 @@
 // Show a not manifested block
 void showBlock() {
   for (int i = 0; i < 4; i++) {
-    ledtable.fill(mPosX + blocks[mThisBlock][mRotation][i][0],mPosY + blocks[mThisBlock][mRotation][i][1],RGB(colors[mThisBlock][0],colors[mThisBlock][1],colors[mThisBlock][2]));
+    ledtable.fill(getX(i),getY(i),getColor());
+  }
+  ledtable.show();
+}
+
+// Show upcoming block
+void showNextBlock() {
+  for (int i = 0; i < 4; i++) {
+    ledtable.fill(13 + blocks[mThisBlock][mRotation][i][0],3 + blocks[mThisBlock][mRotation][i][1],RGB(colors[mThisBlock][0],colors[mThisBlock][1],colors[mThisBlock][2]));
+  }
+
+  for (int i = 0; i < 4; i++) {
+    ledtable.fill(blocks[13 + mNextBlock][0][i][0],3 + blocks[mNextBlock][0][i][1],RGB(colors[mNextBlock][0],colors[mNextBlock][1],colors[mNextBlock][2]));
   }
   ledtable.show();
 }
@@ -315,7 +413,7 @@
 // clear out the Position of the block, now there will be background color again and the block has to be showed again
 boolean clearBlock() {
   for (int i = 0; i < 4; i++) {
-    ledtable.fill(mPosX + blocks[mThisBlock][mRotation][i][0],mPosY + blocks[mThisBlock][mRotation][i][1],RGB(0,0,64));
+    ledtable.fill(getX(i),getY(i),RGB(0,0,64));
   }
 }

@@ -323,7 +421,7 @@
 void manifest() {

   for (int i = 0; i < 4; i++) {
-    fieldmap[mPosX + blocks[mThisBlock][mRotation][i][0]][mPosY + blocks[mThisBlock][mRotation][i][1]] = mThisBlock;
+    fieldmap[getX(i)][getY(i)] = mThisBlock;
   }
   clearLines();
   cycles++;
@@ -336,6 +434,7 @@
  * ===========================
  */

+// Check if there are lines that are to clear, if there are: clear them and show the new score
  void clearLines() {

   boolean lLineClear = true;
@@ -356,14 +455,16 @@
   }

   pointCounter += linesThisRound * pointsThisRound;
-  //Serial.print("New score: ");
-  Serial.print(pointCounter);
-  Serial.println();
+  if (linesThisRound * pointsThisRound == 0) {
+    Serial.print("New score: ");
+    Serial.print(pointCounter);
+    Serial.println();
+  }
   linesThisRound = 0;
   pointsThisRound = 0;
 }

-// Remove a single line
+// Remove the line pLine from the LEDTable and the fieldMap
 void removeLine(int pLine) {

   // Clear the line out of the Field Map
@@ -389,5 +490,5 @@
     }
   }
   ledtable.show();
-  pointsThisRound += 7 - (limit / 5);
-}
+  pointsThisRound += (maxCycles / difficultyHardening) + 1 - (limit / difficultyHardening);
+}


Mode missed

Mode missed

--- hardware/esp8266com/esp8266/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino
+++ hardware/esp8266com/esp8266/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino
@@ -16,6 +16,7 @@
     EEPROM.write(i, 0);

   // turn the LED on when we're done
+  pinMode(13, OUTPUT);
   digitalWrite(13, HIGH);
   EEPROM.end();
 }


Improving Ethernet/WebServer; SD file read performance.

--- examples/Ethernet/CosaSDWebServer/CosaSDWebServer.ino
+++ examples/Ethernet/CosaSDWebServer/CosaSDWebServer.ino
@@ -67,6 +67,7 @@
   // Attempt to open the file. Report back if not found
   FAT16::File file;
   if (!file.open(path, O_READ)) {
+    // Strip possible extra extension character and try again
     path[strlen(path) - 1] = 0;
     if (!file.open(path, O_READ)) {
       trace << PSTR(" Not Found") << endl;
@@ -80,9 +81,13 @@
   page << PSTR("HTTP/1.1 200 OK" CRLF
 	       "Content-Type: text/html" CRLF
 	       "Connection: close" CRLF CRLF);
-  int c;
-  while ((c = file.getchar()) != IOStream::EOF) {
-    page << (char) c;
+
+  // Use block read/write to improve performance
+  static const size_t BUF_MAX = 128;
+  uint8_t buf[BUF_MAX];
+  int count;
+  while ((count = file.read(buf, sizeof(buf))) > 0) {
+    page.get_device()->write(buf, count);
   }
   file.close();
 }


setting wifimode fixing little bug

setting wifimode
fixing little bug

--- esp8266-anemometer.ino
+++ esp8266-anemometer.ino
@@ -29,6 +29,8 @@
     Serial.print("Connecting to ");
     Serial.println(ssid);
   }
+  WiFi.persistent(false);
+  WiFi.mode(WIFI_STA);
   WiFi.begin(ssid, password);
   int maxWait = 500;
   while (WiFi.status() != WL_CONNECTED) {
@@ -72,7 +74,7 @@
       wind = 0.0;
     else
       wind = 1.761 / (1 + rps) + 3.013 * rps;// found here: https://www.amazon.de/gp/customer-reviews/R3C68WVOLJ7ZTO/ref=cm_cr_getr_d_rvw_ttl?ie=UTF8&ASIN=B0018LBFG8 (in German)
-    if(last_wind - wind > 1 || wind - last_wind < -1 || count >= 10){
+    if(last_wind - wind > 0.8 || last_wind - wind < -0.8 || count >= 10){
       if(debugOutput){
         Serial.print("Wind: ");
         Serial.print(wind);
@@ -97,6 +99,7 @@
     next_timestamp  = millis()+1000; //intervall is 1s
     attachInterrupt(input_pin,Interrupt,RISING);
   }
+  yield();
 }

 void reconnect() {


--- esp8266_160220_BYOP.ino
+++ esp8266_160220_BYOP.ino
@@ -6,6 +6,8 @@

 /*
+ * v0.8 2016 Feb 20
+ *  - add proc_check(), proc_get(), proc_post(), proc_bye()
  * v0.7 2016 Feb 20
  *  - add [s_owner]
  *  - add [Pizero_owner_t]
@@ -104,9 +106,29 @@
   debug_outputDebugString("proc_hello", "line105 > [S/N]" + serno);
   debug_outputDebugString("proc_hello", "line106 > [name]" + nickname);

-  // TODO: 0m > display "Hello,[nickName]" to LCD
+  // TODO: 0m > display "Hello,<CR><LF>[nickName]" to LCD

   return true;
+}
+
+bool proc_check(String csvline)
+{
+  debug_outputDebugString("proc_check", "line116 > start");
+}
+
+bool proc_get(String csvline)
+{
+  debug_outputDebugString("proc_get", "line121 > start");
+}
+
+bool proc_post(String csvline)
+{
+  debug_outputDebugString("proc_post", "line126 > start");
+}
+
+bool proc_bye(String csvline)
+{
+    Serial.println("bye,7of9");
 }

 void Serial_replyToCommand(String cmdline)
@@ -125,8 +147,17 @@
   case CMD_HELLO:
     proc_hello(cmdline);
     break;
+  case CMD_CHECK:
+    proc_check(cmdline);
+    break;
+  case CMD_GET:
+    proc_get(cmdline);
+    break;
+  case CMD_POST:
+    proc_post(cmdline);
+    break;
   case CMD_BYE:
-    Serial.println("bye,7of9");
+    proc_bye(cmdline);
     break;
   default:
     // do nothing


Working towards getting only the text in the payload out

--- firmware/examples/readTag/readtag.ino
+++ firmware/examples/readTag/readtag.ino
@@ -22,6 +22,8 @@
                 for (i = 0; i < tagMessage.getRecordCount()   ; i++)  {
                          //
                          NdefRecord tagRecord = tagMessage.getRecord(i);
+                         int payloadLength = tagRecord.getPayloadLength();
+                         char *tagMessage[payloadLength];
                          tagRecord.print();

                 }


GNU General Public License v2.0

GNU General Public License v2.0

--- examples/Test_InputDebounce/Test_InputDebounce.ino
+++ examples/Test_InputDebounce/Test_InputDebounce.ino
@@ -3,6 +3,8 @@

   Mario Ban, 05.2015

+  GNU General Public License v2.0
+  Copyright (C) 2015 Mario Ban
 */

 #include "InputDebounce.h"


[feat] correctly implement set mode

[feat] correctly implement set mode

--- src/du.ino
+++ src/du.ino
@@ -45,7 +45,9 @@
  * Set pin mode
  */
 void sm(char *pin, char *val) {
-  Serial.println('0');
+  int p = atoi(pin);
+  if (strcmp(val, "00") == 0) pinMode(p, OUTPUT);
+  else pinMode(p, INPUT);
 }

 /*


Minor corrections

Minor corrections

--- hispatracker/hispatracker.ino
+++ hispatracker/hispatracker.ino
@@ -73,8 +73,8 @@
 unsigned long next_aprs = 0;

 void setup() {
-//    pinMode(LED_PIN, OUTPUT);
-//    pin_write(LED_PIN, HIGH);
+    pinMode(LED_PIN, OUTPUT);
+    pin_write(LED_PIN, HIGH);
     pinMode(4, OUTPUT); //SD Card pin

     bmp.begin();
@@ -138,14 +138,12 @@

     if (!ds.search(addr)) {
         ds.reset_search();
-        // delay(250);
         return lastExtTemp;
     }

     if (OneWire::crc8(addr, 7) != addr[7]) {
         return -100.0;
     }
-    type_s = 0;

     ds.reset();
     ds.select(addr);
@@ -163,20 +161,13 @@

     // Convert the data to actual temperature
     int16_t raw = (data[1] << 8) | data[0];
-    if (type_s) {
-        raw = raw << 3; // 9 bit resolution default
-        if (data[7] == 0x10) {
-            // "count remain" gives full 12 bit resolution
-            raw = (raw & 0xFFF0) + 12 - data[6];
-        }
-    } else {
-        byte cfg = (data[4] & 0x60);
-        // at lower res, the low bits are undefined, so let's zero them
-        if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
-        else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
-        else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
-        //// default is 12 bit resolution, 750 ms conversion time
-    }
+    byte cfg = (data[4] & 0x60);
+    // at lower res, the low bits are undefined, so let's zero them
+    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
+    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
+    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
+    //// default is 12 bit resolution, 750 ms conversion time
+
     lastExtTemp = (float) raw / 16.0;

     return lastExtTemp;


better handle the left button press

better handle the left button press

avoid flickering when it's kept pressed

--- status.ino
+++ status.ino
@@ -53,8 +53,7 @@
     if (strip.buttonOn(4)) { // left
         processButton(RESPONSE_OK);
     }
-
-    if (drainResponse == RESPONSE_OK) {
+    else if (drainResponse == RESPONSE_OK) {
         for(int i=0; i<12; i++) {
             updateColor(i);
         }


Comments, Serial support, user accessible sketch size tuning

I have started commenting all lines of code for easier readability.
Also, i am making the interpreter size tunable by the user. Want a huge
text game and don't need graphics? Save memory by turning off serial
support? You can now turn modules ON and OFF during defines at top.

I also have some basic serial support. anykey() is supported with
serial input, but i haven't written anything for branches (press a or b)

--- Players/ArduBoyGTI/ArduBoyGTI.ino
+++ Players/ArduBoyGTI/ArduBoyGTI.ino
@@ -3,6 +3,11 @@
 // arduboy.h: uint8_t getCursorX(); uint8_t getCursorY();
 // arduboy.cpp: uint8_t Arduboy::getCursorX() { return cursor_x; } uint8_t Arduboy::getCursorY() { return cursor_y; }
 // replace char gti[]  with your compiled game bytecode by using compiler.py and bin2array.py -- it is currently silence.bin now
+
+#define ON 1
+#define OFF 0
+
+// Standard includes for Arduboy

 #include <SPI.h>
 #include <EEPROM.h>
@@ -10,6 +15,19 @@
 #include <avr/pgmspace.h>
 Arduboy display;

+// Game options
+// Interpreter size tuning (turning off some interpreter support can save PROGMEM memory, but code must not contain related bytecodes (unless stated!)
+
+#define SOUND ON             // 574 bytes (If support is disabled, bytecode is skipped properly)
+#define SERIAL OFF           // 182 bytes (no impact on bytecode interpreting)
+
+#define VARIABLES ON
+#define MUSIC ON
+#define SFXLIB ON            // 496 bytes (If support is disabled, bytecode is skipped properly)
+#define VECTOR ON
+
+// Button definition
+
 #define FIRE_BUTTON 1
 #define JUMP_BUTTON 2
 #define RIGHT 4
@@ -17,12 +35,13 @@
 #define UP 16
 #define LEFT 32

+// Init system variables
+
 uint8_t state = 0;
 uint16_t room = 0;
 uint8_t inst = 0;
 uint8_t col = 0;
 uint8_t row = 0;
-uint8_t sound = 1;
 uint8_t effect = 0;

 extern const unsigned char arduino[];
@@ -50,160 +69,175 @@
   showIntro();
   display.clearDisplay();
   display.display();
+  #if SERIAL == ON
+  Serial.begin(9600);
+  #endif
 }

 void loop() {
 startVM(0);
 }

-void showIntro()
+void showIntro()    // Show Arduino retro intro
 {
    for(int i=-8; i<28; i=i+2) {
     display.clearDisplay();
     display.drawSlowXYBitmap(46,i, arduino, 32,8,1);
     display.display();
     delay(1000/30);
-  }  if(sound == 1) {
+  }
+  #if SOUND == ON
    display.tunes.tone(987, 160);
     delay(160);
    display.tunes.tone(1318, 400);
    delay(2000);
+  #endif
+}
+
+void startVM(uint16_t pc) {
+ while(1) {
+  uint16_t type = pgm_read_byte_near(&(gti[pc])) << 8 | pgm_read_byte_near(&(gti[pc+1])) & 0xFF;  // Read in type of frame
+  pc++;                                                                                // bump program counter
+  col = 0;                                                                                // reset columns in text display
+  if(type == 65535) {                                                                             // SPECIAL Frame Detected
+     pc++;                                                                                // bump program counter
+     uint8_t mode = pgm_read_byte_near(&(gti[pc]));                                               // get the special packet mode
+
+     switch (mode) {                                                                              // switch based on what mode the frame is
+
+       // 0x00 - Game Over
+
+       case 0:                                                                                // Game Over handler
+           while(1) {                                                                             // loop over text until we hit a null
+             pc++;                                                                                // bump program counter
+             uint8_t buff = pgm_read_byte_near(&(gti[pc]));                                       // read a chracter
+             if(buff == 0) { break; }                                                             // is it a null? then we are done printing text
+             printer(pgm_read_byte_near(&(gti[pc])));                                             // print out the text using our text output handler
+           }
+           display.print("*GAME OVER*");                                                          // print generic Game Over message
+           #if SERIAL == ON
+           Serial.print("*GAME OVER*");                                                           // if the serial port is turned on, print message over serial
+           #endif
+           anykey();                                                                              // wait for anykey
+           col = 0;                                                                               // reset the columns (probably not needed)
+           return;                                                                                // quit out of the VM
+           break;                                                                                // break that will not be executed
+
+       // 0x05 - Jump
+
+       case 5:                                                                                // Jump handler
+           pc++;                                                                                // bump the program counter
+           pc = pgm_read_byte_near(&(gti[pc])) << 8 | pgm_read_byte_near(&(gti[pc+1])) & 0xFF;    // Set the program counter to the address in 16 bit field
+           break;                                                                                // switch break
+
+       // 0x0D - Effects Library
+
+       case 13:                                                                                // Effects Handler
+       #if SFXLIB == ON                                                                           // If our effects library is switched on
+            pc++;                                                                                // Bump program counter
+            effect = pgm_read_byte_near(&(gti[pc]));                                              // Get effect type
+
+            switch(effect) {                                                                      // Effect switcher
+
+               // 0x00 - Low pitched rumbling sound
+
+               case 0:                                                                            // rumble handler
+                   #if SOUND == ON                                                                // Is sound turned on?
+                   for(int x = 60; x < 150; x++) {                                                // Low frequency sweep
+                   display.tunes.tone(x, 10);  delay(10); }                                       // Play our low frequency sweep
+                   #endif                                                                         // end sound check
+                   break;                                                                         // switch break
+
+               // 0x01 - Random lightning flash
+
+               case 1:                                                                            // Random lightning flash
+                   for(int x = 0; x < 100; x++) {                                                 // Small loop for our flashes
+                     if(random(0,10) == 1) {                                                      // 1 in 10 chance of a flash
+                            display.fillScreen(WHITE);                                            // Fill screen with white
+                            display.display();                                                    // push it out
+                     }
+                     else {                                                                       // Not a 1 in 10 chance?
+                            display.fillScreen(BLACK);                                            // Make screen black
+                            display.display();                                                    // Push it out
+                     }
+                   }
+                   break;                                                                         // switch break
+            }
+            pc++;                                                                                // Bump program counter
+       #else                                                                                // Otherwise, is the SFX mode disabled?
+         pc++; pc++;                                                                              // Increment program counter so we dont lose position
+       #endif
+            break;                                                                                // switch break
+
+       // 0x10 - Display page of text and wait for any key
+
+       case 16:                                                                                // text handler
+           while(1) {                                                                             // print some text until we find a null
+             pc++;                                                                                // Bump program counter
+             uint8_t buff = pgm_read_byte_near(&(gti[pc]));                                       // Read a character
+             if(buff == 0) { break; }                                                             // Is it null? then break out of loop
+             printer(pgm_read_byte_near(&(gti[pc])));                                             // Send text off to our printer
+           }
+           anykey();                                                                              // Wait for any key
+           pc++;                                                                                // Bump program counter
+           break;                                                                                // Switch case break
+    }
   }
-}
-
-/*
-void showMenu(uint8_t selector) {
-  display.clearDisplay();
-    display.setCursor(0,0);
-  display.println("GTI VM\n\n");
-  if(selector == 0) { display.println("> Start\n  Settings"); }
-  if(selector == 1) { display.println("  Start\n> Settings"); }
-  display.display();
-  delay(1000/30);
-  if(display.pressed(UP) || display.pressed(DOWN)) {
-      display.tunes.tone(300, 50);
-      if(state == 0) { state = 1; } else { state = 0; }
-      while(display.pressed(UP) || display.pressed(DOWN)) { }
-    }
-  if(display.pressed(FIRE_BUTTON) || display.pressed(JUMP_BUTTON)) { if(selector == 0) { state = 2; } if(selector == 1) { state = 3; } }
-}
-*/
-
-void startVM(uint16_t pc) {
-  while(1) {
-  uint16_t type = pgm_read_byte_near(&(gti[pc])) << 8 | pgm_read_byte_near(&(gti[pc+1])) & 0xFF;
-  pc++;
-  col = 0;
-  if(type == 65535) {
-     pc++;
-     uint8_t mode = pgm_read_byte_near(&(gti[pc]));
-
-     switch (mode) {
-       case 0:   // game over
-           while(1) {
-             pc++;
-             uint8_t buff = pgm_read_byte_near(&(gti[pc]));
-             if(buff == 0) { break; }
-             printer(pgm_read_byte_near(&(gti[pc])));
-           }
-           display.print("*GAME OVER*");
-           anykey(); col = 0;
-           return;
-           break;
-       case 5:   // jump
-           pc++;
-           pc = pgm_read_byte_near(&(gti[pc])) << 8 | pgm_read_byte_near(&(gti[pc+1])) & 0xFF;
-
-           break;
-       case 13:  // sfx library
-            pc++;
-            effect = pgm_read_byte_near(&(gti[pc]));
-            switch(effect) {
-               case 0:   // rumble
-                   for(int x = 60; x < 150; x++) {
-                   display.tunes.tone(x, 10);  delay(10); }
-                   break;
-               case 1:
-                   for(int x = 0; x < 100; x++) {
-                     if(random(0,10) == 1) { display.fillScreen(WHITE); display.display();  } else { display.fillScreen(BLACK); display.display(); }
-                   }
-                   break;
-            }  pc++;
-            break;
-       case 16:  // text page
-           while(1) {
-             pc++;
-             uint8_t buff = pgm_read_byte_near(&(gti[pc]));
-             /*
-                         if(buff == 32) {      // seek ahead for wrapping -- extremely redundant, but we have to do it
-                uint8_t z = 1;
-                while(1) {
-                   if(pgm_read_byte_near(&(gti[pc+z])) == 32) {
-                       if((z + col) > 19) { display.fillRect(display.getCursorX(),display.getCursorY(),8,8,BLACK);  display.print("\n"); col = 0; display.display(); break; }
-                       else { break; }
-                   }
-                   if(pgm_read_byte_near(&(gti[pc+z])) == 0) {
-                       if((z + col) > 19) { display.fillRect(display.getCursorX(),display.getCursorY(),8,8,BLACK);  display.print("\n"); col = 0; display.display(); break; }
-                   }  else { break; }
-                  z++;
-                }
-              } */
-
-
-             if(buff == 0) { break; }
-             printer(pgm_read_byte_near(&(gti[pc])));
-           }
-           anykey(); pc++;
-           break;
-  }
-  }
-  else {
-      pc++;
-      uint16_t alterexit = pgm_read_byte_near(&(gti[pc])) << 8 | pgm_read_byte_near(&(gti[pc+1])) & 0xFF;
-      pc++; pc++;
-      int i = 0;
-      while(1 == 1) {
-        uint8_t buff = pgm_read_byte_near(&(gti[pc]));
-        if(buff == 0) { exita[i] = 0; break; }
-        exita[i] = buff; Serial.print((char)exita[i]);
-        i++; pc++;
+
+  // We did not find a SPECIAL frame, so we assume it is a NORMAL frame (and per framing format, it must be)
+  // We reuse the 'type' uint16_t variable as jump a's address
+
+  else {
+
+     // Jump A description buffer
+
+      pc++;                                                                                // bump program counter
+      uint16_t alterexit = pgm_read_byte_near(&(gti[pc])) << 8 | pgm_read_byte_near(&(gti[pc+1])) & 0xFF;     // get jump b address
+      pc++; pc++;                                                                                // bump program counter
+      int i = 0;                                                                                // initalize i (to keep track of array position)
+      while(1 == 1) {                                                                                // fill jump a description buffer
+        uint8_t buff = pgm_read_byte_near(&(gti[pc]));                                                        // get a chracter
+        if(buff == 0) { exita[i] = 0; break; }                                                                // Is it null? append the null to array then stop
+        exita[i] = buff;                                                                                // fill array with newest character
+        i++; pc++;                                                                                // bump array position and program counter
       }
-      pc++;
-      i = 0;
-      while(1 == 1) {
-        uint8_t buff = pgm_read_byte_near(&(gti[pc]));
-        if(buff == 0) { exitb[i] = 0; break; }
-        exitb[i] = buff; Serial.print((char)exitb[i]);
-        i++; pc++;
-      } int x = 0;
+
+     // Jump B description buffer
+
+      pc++;                                                                                // bump program counter
+      i = 0;                                                                                // reset array position
+      while(1 == 1) {                                                                                // fill jump b description buffer
+        uint8_t buff = pgm_read_byte_near(&(gti[pc]));                                                        // get a character
+        if(buff == 0) { exitb[i] = 0; break; }                                                                // Is it null? append the null to array then stop
+        exitb[i] = buff;                                                                                // fill array with newest character
+        i++; pc++;                                                                                // bump array position and program counter
+      }
+
+      int x = 0;                                                                                // define x (we could probably still reuse i?)

+      // Main description printing (since the description goes before the jump selections)

-      while(1) {
-             pc++;
-             uint8_t buff = pgm_read_byte_near(&(gti[pc]));
-             if(buff == 0) { break; }  /*
-             if(buff == 32) {      // seek ahead for wrapping -- extremely redundant, but we have to do it
-                uint8_t z = 1;
-                while(1) {
-                   if(pgm_read_byte_near(&(gti[pc+z])) == 32) {
-                       if((z + col) > 21) { display.fillRect(display.getCursorX(),display.getCursorY(),8,8,BLACK);  display.print("\n"); col = 0; display.display(); break; }
-                       else { break; }
-                   }
-                   if(pgm_read_byte_near(&(gti[pc+z])) == 0) {
-                       if((z + col) > 21) { display.fillRect(display.getCursorX(),display.getCursorY(),8,8,BLACK);  display.print("\n"); col = 0; display.display(); break; }
-                   }  else { break; }
-                  z++;
-                }
-              } */
-
-             printer(pgm_read_byte_near(&(gti[pc])));
+      while(1) {                                                                                // print the main description text, null terminated
+             pc++;                                                                                // bump program counter
+             uint8_t buff = pgm_read_byte_near(&(gti[pc]));                                                   // get character from main description
+             if(buff == 0) { break; }                                                                         // did we find a null? stop printing description
+             printer(pgm_read_byte_near(&(gti[pc])));                                                         // Print out our newest character
       }
       pc++;
-      if(sound == 1) { display.tunes.tone(1318, 50); }
+      #if SOUND == ON
+      display.tunes.tone(1318, 50);
+      #endif
       display.fillRect(display.getCursorX(),display.getCursorY(),8,8,BLACK); display.display();
-      if(display.getCursorY() < 40) { display.print("\n"); }
+      if(display.getCursorY() < 40) { display.print("\n");
+      #if SERIAL == ON
+      Serial.println();
+      #endif
+      }

       display.print("\nA] ");  display.display();  col=3;
+      #if SERIAL == ON
+      Serial.print("\nA] ");
+      #endif
        x = 0;
        while(1) {
              if(exita[x] == 0) { break; }
@@ -211,9 +245,14 @@
              x++;
       }
       x = 0;
-      if(sound == 1) { display.tunes.tone(1318, 50); }
+      #if SOUND == ON
+      display.tunes.tone(1318, 50);
+      #endif
       display.fillRect(display.getCursorX(),display.getCursorY(),8,8,BLACK); display.display();
       display.print("\nB] ");  display.display(); col=3;
+      #if SERIAL == ON
+      Serial.print("\nB] ");
+      #endif
        while(1) {
              if(exitb[x] == 0) { break; }
              printer(exitb[x]);
@@ -236,20 +275,31 @@

 void printer(uint8_t character) {
  col++;
- if(col > 20) {  display.fillRect(display.getCursorX(),display.getCursorY(),8,8,BLACK); display.println(); col = 0; }
+ if(col > 20) {  display.fillRect(display.getCursorX(),display.getCursorY(),8,8,BLACK); display.println(); col = 0;
+ #if SERIAL == ON
+ Serial.print("\n");
+ #endif
+ }
  if(character == 10) { display.fillRect(display.getCursorX(),display.getCursorY(),8,8,BLACK); col = 0; }
  display.print((char)character);
- if(sound == 1) { display.tunes.tone(1318, 2); }
+ #if SOUND == ON
+ display.tunes.tone(1318, 2);
+ #endif
  display.fillRect(display.getCursorX(),display.getCursorY(),8,8,WHITE);
- display.display();
+ display.display();
+ #if SERIAL == ON
+ Serial.print((char)character);
+ #endif
  delay(50);
 }

 uint8_t select() {
-  uint8_t c = 0; uint8_t blink = 0; if(sound == 1) {
+  uint8_t c = 0; uint8_t blink = 0;
+  #if SOUND == ON
      display.tunes.tone(1318, 50);  delay(50);
     display.tunes.tone(400, 50); delay(50);
-    display.tunes.tone(600, 50); delay(50); }
+    display.tunes.tone(600, 50); delay(50);
+  #endif
   while(1) {
    if(display.pressed(FIRE_BUTTON)) { return 1; }
    if(display.pressed(JUMP_BUTTON)) { return 0; }
@@ -273,13 +323,18 @@

 void anykey() {
   display.fillRect(display.getCursorX(),display.getCursorY(),8,8,BLACK); display.display();
-   if(sound == 1) { display.tunes.tone(600, 50);  delay(50);
+  #if SOUND == ON
+    display.tunes.tone(600, 50);  delay(50);
     display.tunes.tone(1318, 50); delay(50);
-    display.tunes.tone(900, 50); delay(50); }
+    display.tunes.tone(900, 50); delay(50);
+  #endif
     int c = 0;
     int blink = 0;
   while(1) {
    if(display.pressed(FIRE_BUTTON) || display.pressed(JUMP_BUTTON)) { break; }
+   #if SERIAL == ON
+   if(Serial.available()) { Serial.read(); Serial.read(); Serial.read(); break; }
+   #endif
     c++;
     if(c > 10000) {
        if(blink == 1) {
@@ -295,5 +350,8 @@
    }
    }
   display.setCursor(0,0); display.clearDisplay(); display.display();
-}
-
+  #if SERIAL == ON
+  Serial.println("\n");
+  #endif
+}
+


Adding new web content

Adding new web content

--- bsd/bsd.ino
+++ bsd/bsd.ino
@@ -31,7 +31,7 @@

 // TONES
 #define SPEAKER_PIN  9 // must be a PWM pin (digital 9, 10 or 11)
-uint8_t tones[] = {261, 277, 294, 311, 330, 349, 370, 392, 415, 840}; // freq x * Hz
+uint16_t tones[] = {261, 277, 294, 311, 330, 349, 370, 900, 1480, 2960}; // freq x * Hz

 // NEOPIXELS
 #define NEOPIXEL_PIN   6
@@ -55,12 +55,13 @@
   flashLed(BOOT_PIN, 3, 300);
   server.listenOnLocalhost();
   server.begin();
-  delay(5000); // wait for all processes to start
+  delay(2000); // wait for all processes to start
   yunAddr = getIPaddr();
   bsURL = "http://" + yunAddr + "/arduino/";
   flashLed(BOOT_PIN, 2, 100);
-  makeNoise(2, tones[1], 100);
+  makeNoise(2, tones[9], 100);
   sendIP();
+  buildStartPage();
   ledOFF();
 }

@@ -76,7 +77,6 @@
 void process(BridgeClient client) {
   // read the command
   String command = client.readStringUntil('/');
-  printHtmlPage(client);
   if (command == "bs") {
     int value = 0;
     value = client.parseInt();
@@ -104,7 +104,7 @@
 // reps: how many times we send call tone()
 // freq: value of the frequecy
 // d: pause between tones in millis
-void makeNoise(uint8_t reps, uint8_t freq, uint16_t d) {
+void makeNoise(uint8_t reps, uint16_t freq, uint16_t d) {
   for (uint16_t i = 0; i < reps; i++) {
     tone(SPEAKER_PIN, freq);
     delay(d);
@@ -114,18 +114,6 @@
   noTone(SPEAKER_PIN);
 }

-// remindes me the old days when we had to write our own c||perl CGI libs :)
-void printHtmlPage(BridgeClient client) {
-  client.println("Status: 200");
-  client.println("Content-type: text/html");
-  client.println();
-  client.println("
");
-  client.println("");
-  client.println("
");
-  client.println("OFF [admin only]
");
-  client.println("");
-}
-
 void printJSonHealth(BridgeClient client) {
   // print health stats in json format
   client.print("bshits:");
@@ -133,10 +121,9 @@
 }

 void bsAlarm() {
-  makeNoise(30, tones[9], 5);
-  for (uint16_t i = 0; i < 10 ; i++) {
+  makeNoise(400, tones[8], 20);
+  for (uint16_t i = 0; i < 70 ; i++) {
     lightUp(255, 0, 0, 50);
-    makeNoise(10, tones[9], 5);
     ledOFF();
     delay(50);
   }
@@ -173,12 +160,19 @@
   }
   return ipaddr;
 }
-
+
 void sendIP() {
   Process p;
-  String link= "http://"+yunAddr+"\/arduino\/bs";
+  String link = "http://" + yunAddr + "/sd/bsdetector/";
   p.runShellCommand("cat /mnt/sd/mail_header.txt > /mnt/sd/mail.txt");
-  p.runShellCommand("echo \""+link+"\" >>  /mnt/sd/mail.txt");
-  p.runShellCommand("cat /mnt/sd/mail.txt | ssmtp bruno.georges@gmail.com "); //
+  p.runShellCommand("echo \"" + link + "\" >>  /mnt/sd/mail.txt");
+  p.runShellCommand("cat /mnt/sd/mail.txt | ssmtp bruno.georges@gmail.com ffeldman@redhat.com "); //
 }

+void buildStartPage() {
+  Process p;
+  p.runShellCommand("cat /mnt/sda1/arduino/www/bsdetector/index.html.tmpl > /mnt/sda1/arduino/www/bsdetector/index.html");
+  p.runShellCommand("sed -i \'s/ip_addr/"+yunAddr+"/g\' /mnt/sda1/arduino/www/bsdetector/index.html");
+}
+
+


Updated AutoConnectWithFSParameters to toggle between ArduinoJson5 and ArduinoJson6

--- examples/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino
+++ examples/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino
@@ -1,13 +1,14 @@
 #include <FS.h>                   //this needs to be first, or it all crashes and burns...
-
 #include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino
-
 //needed for library
 #include <DNSServer.h>
 #include <ESP8266WebServer.h>
 #include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager

 #include <ArduinoJson.h>          //https://github.com/bblanchon/ArduinoJson
+
+//Comment out this line if you are still using ArduinoJsonV5
+#define UseJsonV6

 //define your default values here, if there are different values in config.json, they are overwritten.
 char mqtt_server[40];
@@ -22,7 +23,6 @@
   Serial.println("Should save config");
   shouldSaveConfig = true;
 }
-

 void setup() {
   // put your setup code here, to run once:
@@ -48,16 +48,22 @@
         std::unique_ptr<char[]> buf(new char[size]);

         configFile.readBytes(buf.get(), size);
+
+#ifdef UseJsonV6
+        DynamicJsonDocument json(1024);
+        auto deserializeError = deserializeJson(json, buf.get());
+        serializeJson(json, Serial);
+        if ( ! deserializeError ) {
+#else
         DynamicJsonBuffer jsonBuffer;
         JsonObject& json = jsonBuffer.parseObject(buf.get());
         json.printTo(Serial);
         if (json.success()) {
+#endif
           Serial.println("\nparsed json");
-
           strcpy(mqtt_server, json["mqtt_server"]);
           strcpy(mqtt_port, json["mqtt_port"]);
           strcpy(blynk_token, json["blynk_token"]);
-
         } else {
           Serial.println("failed to load json config");
         }
@@ -68,8 +74,6 @@
     Serial.println("failed to mount FS");
   }
   //end read
-
-

   // The extra parameters to be configured (can be either global or just in the setup)
   // After connecting, parameter.getValue() will get you the configured value
@@ -86,8 +90,8 @@
   wifiManager.setSaveConfigCallback(saveConfigCallback);

   //set static ip
-  wifiManager.setSTAStaticIPConfig(IPAddress(10,0,1,99), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
-
+  wifiManager.setSTAStaticIPConfig(IPAddress(10, 0, 1, 99), IPAddress(10, 0, 1, 1), IPAddress(255, 255, 255, 0));
+
   //add all your parameters here
   wifiManager.addParameter(&custom_mqtt_server);
   wifiManager.addParameter(&custom_mqtt_port);
@@ -99,7 +103,7 @@
   //set minimu quality of signal so it ignores AP's under that quality
   //defaults to 8%
   //wifiManager.setMinimumSignalQuality();
-
+
   //sets timeout until configuration portal gets turned off
   //useful to make it all retry or go to sleep
   //in seconds
@@ -124,12 +128,20 @@
   strcpy(mqtt_server, custom_mqtt_server.getValue());
   strcpy(mqtt_port, custom_mqtt_port.getValue());
   strcpy(blynk_token, custom_blynk_token.getValue());
+  Serial.println("The values in the file are: ");
+  Serial.println("\tmqtt_server : " + String(mqtt_server));
+  Serial.println("\tmqtt_port : " + String(mqtt_port));
+  Serial.println("\tblynk_token : " + String(blynk_token));

   //save the custom parameters to FS
   if (shouldSaveConfig) {
     Serial.println("saving config");
+#ifdef UseJsonV6
+    DynamicJsonDocument json(1024);
+#else
     DynamicJsonBuffer jsonBuffer;
     JsonObject& json = jsonBuffer.createObject();
+#endif
     json["mqtt_server"] = mqtt_server;
     json["mqtt_port"] = mqtt_port;
     json["blynk_token"] = blynk_token;
@@ -139,19 +151,22 @@
       Serial.println("failed to open config file for writing");
     }

+#ifdef UseJsonV6
+    serializeJson(json, Serial);
+    serializeJson(json, configFile);
+#else
     json.printTo(Serial);
     json.printTo(configFile);
+#endif
     configFile.close();
     //end save
   }

   Serial.println("local ip");
   Serial.println(WiFi.localIP());
-
 }

 void loop() {
   // put your main code here, to run repeatedly:

-
 }


Update LogoBotWifiScribbler.ino

Update LogoBotWifiScribbler.ino

Start of code to write letters in world space...  starting with the letter L

--- software/firmware/LogoBotWifiScribbler/LogoBotWifiScribbler.ino
+++ software/firmware/LogoBotWifiScribbler/LogoBotWifiScribbler.ino
@@ -1,5 +1,6 @@
 #include <AccelStepper.h>
 #include <Servo.h>
+#include<stdlib.h>

 // Pin definitions

@@ -33,8 +34,6 @@
 // Servo for Pen Lift (Note same as LED for now)
 #define SERVO       11

-#define dlcs doLogoCommandSync
-
 // Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48
 AccelStepper stepperL(AccelStepper::HALF4WIRE, motorLPin1, motorLPin3, motorLPin2, motorLPin4);
 AccelStepper stepperR(AccelStepper::HALF4WIRE, motorRPin1, motorRPin3, motorRPin2, motorRPin4);
@@ -47,9 +46,9 @@

 // position state info
 struct POSITION {
-  long x;
-  long y;
-  long ang;
+  float x;
+  float y;
+  float ang;
 };
 POSITION position;

@@ -59,6 +58,9 @@

 // buffered text to "write" using the pen
 String text = "";
+float fontSize = 20;  // =em, equal to line spacing (between baselines), text sizes derived from this
+float capHeight = fontSize * 0.7;
+float letterSpacing = fontSize * 0.1;

 // cmd received over serial - builds up char at a time
 String cmd;
@@ -221,8 +223,6 @@

 void doLogoCommand(String c)
 {
-
-  Serial.println(c);
   /* Official Logo Commands
        Implemented
          -FD, BK, LT, RT
@@ -235,25 +235,26 @@
       BZ n - sound buzzer for n milliseconds
       ST - stop
       SIG - sign Logobots name
+      TO x y
     */

   if (c.startsWith("TO")) {
     // split out x and y co-ordinates
     int sp = c.indexOf(" ",3);
-    int x = c.substring(3,sp).toInt();
-    int y = c.substring(sp+1).toInt();
+    float x = c.substring(3,sp).toFloat();
+    float y = c.substring(sp+1).toFloat();
     driveTo(x,y);
   } else if (c.startsWith("FD")) {
-    int dist = c.substring(3).toInt();
+    float dist = c.substring(3).toFloat();
     drive(dist);
   } else if (c.startsWith("BK")) {
-    int dist = c.substring(3).toInt();
+    float dist = c.substring(3).toFloat();
     drive(-dist);
   } else if (c.startsWith("RT")) {
-    int angle = c.substring(3).toInt();
+    float angle = c.substring(3).toFloat();
     turn(-angle);
   } else if (c.startsWith("LT")) {
-    int angle = c.substring(3).toInt();
+    float angle = c.substring(3).toFloat();
     turn(angle);
   } else if (c.startsWith("ST")) {
     stepperL.stop();
@@ -265,48 +266,38 @@
   } else if (c.startsWith("PD")) {
     penDown();
   } else if (c.startsWith("SIG")) {
-    writeLogobot();
+    writeText("LOGOBOT");
   } else if (c.startsWith("WT")) {
     writeText(c.substring(3));
   }
 }

-void doLogoCommandSync(String cmd)
-{
-  doLogoCommand(cmd);
-
-  // Nasty, really needs to run the main loop.
-  while (stepperL.distanceToGo() != 0 || stepperR.distanceToGo() != 0) {
-    stepperL.run();
-    stepperR.run();
-  }
-}
-
-void driveTo(long x, long y) {
+
+void driveTo(float x, float y) {
   // calc angle
-  long ang = atan2(y-position.y, x-position.x) * 180 / PI;
+  float ang = atan2(y-position.y, x-position.x) * 180 / PI;
   // now angle delta
   ang = ang - position.ang;
   turn(ang);

   // and distance
-  long dist = sqrt(sqr(y-position.y) + sqr(x-position.x));
+  float dist = sqrt(sqr(y-position.y) + sqr(x-position.x));
   drive(dist);
 }

-void drive(long distance)
+void drive(float distance)
 {
   // update state
   position.x += distance * cos(position.ang * PI / 180);
   position.y += distance * sin(position.ang * PI / 180);

   // prime the move
-  distance *= STEPS_PER_MM;
-  stepperL.move(distance);
-  stepperR.move(distance);
-}
-
-void turn(long ang)
+  int steps = distance * STEPS_PER_MM;
+  stepperL.move(steps);
+  stepperR.move(steps);
+}
+
+void turn(float ang)
 {
   // update state
   position.ang += ang;
@@ -316,9 +307,9 @@
   if (position.ang < -360) position.ang += 360;

   // prime the move
-  ang *= STEPS_PER_DEG;
-  stepperR.move(ang);
-  stepperL.move(-ang);
+  int steps = ang * STEPS_PER_DEG;
+  stepperR.move(steps);
+  stepperL.move(-steps);
 }

 void buzz(int len)
@@ -337,16 +328,10 @@
 }

 void writeChar(char c) {
+
     switch(c) {
         case 'L':
-          pushCmd("FD 100");
-          pushCmd("PD");
-          pushCmd("BK 100");
-          pushCmd("RT 90");
-          pushCmd("FD 80");
-          pushCmd("PU");
-
-          pushCmd("FD 50");
+          writeL();
           break;

         default:
@@ -357,121 +342,40 @@

 void writeText(String s) {
   // overwrite write text
-  text = s;
+  text = s;
+  text.toUpperCase();

   // reset current state
   resetPosition();
 }

-void writeLogobot()
-{
-  // L
-  dlcs("FD 100");
-  dlcs("PD");
-  dlcs("BK 100");
-  dlcs("RT 90");
-  dlcs("FD 80");
-  dlcs("PU");
-
-  dlcs("FD 50");
-
-  // O
-  dlcs("PD");
-  dlcs("FD 80");
-  dlcs("LT 90");
-  dlcs("FD 100");
-  dlcs("LT 90");
-  dlcs("FD 80");
-  dlcs("LT 90");
-  dlcs("FD 100");
-  dlcs("PU");
-
-  dlcs("LT 90");
-  dlcs("FD 130");
-
-  // G
-  dlcs("FD 80");
-  dlcs("LT 90");
-  dlcs("FD 100");
-  dlcs("LT 90");
-  dlcs("PD");
-  dlcs("FD 80");
-  dlcs("LT 90");
-  dlcs("FD 100");
-  dlcs("LT 90");
-  dlcs("FD 80");
-  dlcs("LT 90");
-  dlcs("FD 60");
-  dlcs("PU");
-
-  dlcs("BK 60");
-  dlcs("RT 90");
-  dlcs("FD 50");
-
-  // O
-  dlcs("PD");
-  dlcs("FD 80");
-  dlcs("LT 90");
-  dlcs("FD 100");
-  dlcs("LT 90");
-  dlcs("FD 80");
-  dlcs("LT 90");
-  dlcs("FD 100");
-  dlcs("PU");
-
-  dlcs("LT 90");
-  dlcs("FD 130");
-
-  // B
-  dlcs("PD");
-  dlcs("FD 80");
-  dlcs("LT 90");
-  dlcs("FD 40");
-  dlcs("LT 50");
-  dlcs("FD 40");
-  dlcs("RT 100");
-  dlcs("FD 40");
-  dlcs("LT 50");
-  dlcs("FD 40");
-  dlcs("LT 90");
-  dlcs("FD 80");
-  dlcs("LT 90");
-  dlcs("FD 100");
-  dlcs("PU");
-
-  dlcs("LT 90");
-  dlcs("FD 130");
-
-  // O
-  dlcs("PD");
-  dlcs("FD 80");
-  dlcs("LT 90");
-  dlcs("FD 100");
-  dlcs("LT 90");
-  dlcs("FD 80");
-  dlcs("LT 90");
-  dlcs("FD 100");
-  dlcs("PU");
-
-  dlcs("LT 90");
-  dlcs("FD 170");
-
-  // T
-  dlcs("LT 90");
-  dlcs("PD");
-  dlcs("FD 150");
-  dlcs("LT 90");
-  dlcs("PU");
-  dlcs("BK 40");
-  dlcs("PD");
-  dlcs("FD 400");
-  dlcs("PU");
-
-  // Get out of the way
-  dlcs("RT 45");
-  dlcs("FD 2000");
-
-}
+
+// Alphabet
+
+static char outstr[15];
+void pushTo(float x, float y) {
+  dtostrf(x,5,1,outstr);
+  String s = "TO ";
+  s.concat(outstr);
+  dtostrf(y,5,1,outstr);
+  s.concat(" ");
+  s.concat(outstr);
+  pushCmd(s);
+}
+
+void writeL() {
+  float x = position.x;
+  float y = position.y;
+  float w = fontSize * 0.5;
+  pushCmd("PD");
+  pushTo(x, y + capHeight);
+  pushTo(x,y);
+  pushTo(x + w, y);
+  pushCmd("PU");
+  pushTo(x + w + letterSpacing, y);
+}
+
+

 long sqr(long v) {
   return v*v;


Abort reading on error

Abort reading on error

It is possible for error to happen when disabling infopage bit. Bail out
in this case since we will be reading the code and not info page.

--- Read_Mainpage/Read_Mainpage.ino
+++ Read_Mainpage/Read_Mainpage.ino
@@ -55,7 +55,8 @@
   progStart();

   // Set InfoPage bit so InfoPage flash is read
-  disableInfoPage();
+  if (!disableInfoPage())
+    goto done;

   // Read from MainPage
   Serial.println("READING...");


more flash strings

more flash strings

--- WifiWeatherGuy.ino
+++ WifiWeatherGuy.ino
@@ -20,13 +20,11 @@
 #define TFT_LED D2
 #define SWITCH D3

+bool debug;
 TFT_ILI9163C tft = TFT_ILI9163C(CS, DC);
-
 MDNSResponder mdns;
 ESP8266WebServer server(80);
 ESP8266HTTPUpdateServer httpUpdater;
-
-bool debug;

 uint32_t last_fetch_conditions = 0, last_fetch_forecasts = 0;
 uint32_t display_on = 0;
@@ -48,19 +46,12 @@
   void configure(JsonObject &o);
 } cfg;

-static void strncpy_null(char *dest, const char *src, int n) {
-  if (src)
-    strncpy(dest, src, n);
-  else
-    *dest = 0;
-}
-
 void config::configure(JsonObject &o) {
-  strncpy_null(ssid, o[F("ssid")], sizeof(ssid));
-  strncpy_null(password, o[F("password")], sizeof(password));
-  strncpy_null(key, o[F("key")], sizeof(key));
-  strncpy_null(station, o[F("station")], sizeof(station));
-  strncpy_null(hostname, o[F("hostname")], sizeof(hostname));
+  strncpy(ssid, o[F("ssid")] | "", sizeof(ssid));
+  strncpy(password, o[F("password")] | "", sizeof(password));
+  strncpy(key, o[F("key")] | "", sizeof(key));
+  strncpy(station, o[F("station")] | "", sizeof(station));
+  strncpy(hostname, o[F("hostname")] | "", sizeof(hostname));
   conditions_interval = 1000 * (int)o[F("conditions_interval")];
   forecasts_interval = 1000 * (int)o[F("forecasts_interval")];
   metric = (bool)o[F("metric")];
@@ -121,7 +112,7 @@
   tft.print(F("dim: "));
   tft.println(cfg.dim);
   if (debug)
-    tft.println("DEBUG");
+    tft.println(F("DEBUG"));

   WiFi.mode(WIFI_STA);
   WiFi.hostname(cfg.hostname);
@@ -140,7 +131,6 @@
     tft.println(cfg.hostname);
     tft.println(F("to configure WiFi"));
   } else {
-
     DBG(println());
     DBG(print(F("Connected to ")));
     DBG(println(cfg.ssid));
@@ -201,15 +191,14 @@
   time_t epoch;
   char city[48];
   int wind_degrees;
-
 } conditions;

 bool update_conditions(JsonObject &root, struct Conditions &c) {
-
-  JsonObject& current_observation = root[F("current_observation")];
+  JsonObject &current_observation = root[F("current_observation")];
   time_t epoch = (time_t)atoi(current_observation[F("observation_epoch")]);
   if (epoch == c.epoch)
     return false;
+
   c.epoch = epoch;
   strncpy(c.icon, current_observation[F("icon")], sizeof(c.icon));
   strncpy(c.weather, current_observation[F("weather")], sizeof(c.weather));
@@ -254,11 +243,9 @@
   int ave_humidity;
   char conditions[32];
   char icon[16];
-
 } forecasts[4];

 void update_forecasts(JsonObject &root) {
-
   JsonArray &days = root[F("forecast")][F("simpleforecast")][F("forecastday")];
   for (int i = 0; i < 4; i++) {
     JsonObject &day = days[i];
@@ -285,7 +272,6 @@
 }

 void display_weather(struct Conditions &c) {
-
   tft.fillScreen(WHITE);
   tft.setTextColor(BLACK);

@@ -317,15 +303,14 @@
 }

 void display_astronomy(struct Conditions &c) {
-
   tft.fillScreen(BLACK);
   tft.setTextColor(WHITE);

   tft.setTextSize(2);
   tft.setCursor(1, 1);
-  tft.print("sun");
+  tft.print(F("sun"));
   tft.setCursor(right(4, tft.width(), 2), 1);
-  tft.print("moon");
+  tft.print(F("moon"));
   tft.setTextSize(1);
   tft.setCursor(strlen(c.sunrise_hour) == 1? 7: 1, 17);
   tft.print(c.sunrise_hour);
@@ -364,7 +349,6 @@
 }

 void display_forecast(struct Forecast &f) {
-
   tft.fillScreen(WHITE);
   tft.setTextColor(BLACK);

@@ -417,18 +401,16 @@
 }

 void loop() {
-
-  static int screen = 0;
+  mdns.update();

   server.handleClient();
   if (!connected)
     return;

-  mdns.update();
-
   uint32_t now = millis();
   bool swtch = !digitalRead(SWITCH);

+  static int screen = 0;
   if (fade == cfg.dim) {
     if (swtch) {
       display_on = now;


Remove uneeded header

Remove uneeded header

--- iDONT.ino
+++ iDONT.ino
@@ -4,8 +4,6 @@
 #include <DNSServer.h>            //Local DNS Server used for redirecting all requests to the configuration portal
 #include <ESP8266WebServer.h>     //Local WebServer used to serve the configuration portal
 #include <WiFiManager.h>          //https://github.com/kentaylor/WiFiManager WiFi
-#include <ESP8266WebServer.h>
-

 WiFiServer* pWifiServer;
 unsigned char btnState;


v3.6 Bug fixes

v3.6 Bug fixes

--- WeatherDisplay.ino
+++ WeatherDisplay.ino
@@ -17,7 +17,7 @@
 #include <Adafruit_GFX.h>

 WiFiClient client;
-char servername[] = "api.openweathermap.org"; // remote server we will connect to
+String serverName = "api.openweathermap.org"; // Remote server we will connect to
 String result;
 boolean night = false;
 bool toggleDisplay = digitalRead(TOGGLEDISPLAY_SW);
@@ -123,16 +123,16 @@

   String APIKEY(APIKey);
   String CityID(cityID);
-  if (client.connect(servername, 80)) {  //starts client connection, checks for connection
+  if (client.connect(serverName.c_str(), 80)) { // Starts client connection, checks for connection
     client.println("GET /data/2.5/forecast?id=" + CityID + "&units=imperial&cnt=1&APPID=" + APIKEY);
-    client.println("Host: api.openweathermap.org");
+    client.println("Host: " + serverName);
     client.println("User-Agent: ArduinoWiFi/1.1");
     client.println("Connection: close");
     client.println();
   }
   else {
 #ifdef DEBUG
-    Serial.println("connection failed"); //error message if no client connect
+    Serial.println("connection failed"); // Error message if no client connect
     Serial.println();
 #endif
     return;
@@ -222,12 +222,7 @@
   Serial.print(setI);
   Serial.println("pm");
   Serial.print("Time last updated ");
-#ifdef CONVERTTIMETOLOCAL
   Serial.println(timeS);
-#else
-  Serial.print(timeS);
-  Serial.println(" UTC");
-#endif
   Serial.print("UTC ");
   Serial.println(timeUTC);
 #endif // #ifdef DEBUG
@@ -375,7 +370,7 @@
     case 800: drawClearWeather(); break;
     case 801: drawFewClouds(); break;
     case 802: drawFewClouds(); break;
-    case 803: drawCloud(); break;
+    case 803: drawFewClouds(); break;
     case 804: drawCloud(); break;

     case 200: drawThunderstorm(); break;
@@ -400,7 +395,6 @@
     case 321: drawLightRain(); break;

     case 500: drawLightRainWithSunOrMoon(); break;
-    //    case 501: drawLightRainWithSunOrMoon(); break;
     case 501: drawModerateRain(); break;
     case 502: drawLightRainWithSunOrMoon(); break;
     case 503: drawLightRainWithSunOrMoon(); break;
@@ -453,7 +447,7 @@
   timeS = timeS.substring(length - 8, length - 6); // Strip out the hours
   int time = timeS.toInt();

-#ifdef CONVERTTIMETOLOCAL
+#ifdef ERROROFFSET
   // For some reason, openweathermap.org time is off by some (???)
   // hours from UTC. Need to compensate
   int TimeErrorOffset = -3;
@@ -461,11 +455,7 @@
       (time == 12)) {
     time += (TimeErrorOffset + 2);
   }
-  else if (time == 15) {
-    time += (TimeErrorOffset + 0);
-  }
   else if (time == 0) {
-    time += (TimeErrorOffset + 0);
     convertDate(time, &year, &month, &day);
   }
   else {
@@ -488,9 +478,7 @@
   Serial.print(day);
   Serial.print("/");
   Serial.println(year);
-#ifdef CONVERTTIMETOLOCAL
   Serial.println((DST) ? "It's DST" : "It's ST");
-#endif
 #endif

   // Get sunrise and sunset time in UTC