Updated arduino

Updated arduino

--- apps/Arduino/ss_basic/ss_basic.ino
+++ apps/Arduino/ss_basic/ss_basic.ino
@@ -56,8 +56,12 @@
 int raceLengthSecs = 60;
 int previousFakeTickMillis = 0;

-int updateInterval = 50;
+int updateInterval = 10;
 unsigned long lastUpdateMillis = 0;
+
+//float mockSpeedsKph[4] = {10.0, 20.0, 30.0, 40.0};
+float mockSpeedsKph[4] = {40.0, 56.0, 48.0, 32.0};
+
 bool bRaceTypeDistance = true;

 void setup()
@@ -88,12 +92,7 @@
     }
 }

-void raceStart()
-{
-    raceStartMillis = millis();
-}
-
-boolean isAlphaNum(char c)
+boolean isAlphaNum(char c)
 {
     if(c >= '0' && c <= '9'){
         return true;
@@ -182,21 +181,6 @@
     }
 }

-void printStatusUpdate()
-{
-    if(currentTimeMillis - lastUpdateMillis > updateInterval) {
-        lastUpdateMillis = currentTimeMillis;
-
-        Serial.print("R:");
-
-        for(int i=0; i<MAX_RACERS; i++){
-            Serial.print(racerTicks[i], DEC);
-            Serial.print(",");
-        }
-        Serial.println(currentTimeMillis, DEC);
-    }
-}
-
 void loop()
 {
     blinkLED();
@@ -226,61 +210,96 @@
         }
         if(lastCountDown == 0) {
             raceStart();
-            raceStarting = false;
-            raceStarted = true;
-
-            for(int i=0; i<MAX_RACERS; i++) {
-                racerTicks[i] = 0;
-                racerFinishTimeMillis[i] = 0;
-            }
-
-            digitalWrite(racer0GoLedPin,HIGH);
-            digitalWrite(racer1GoLedPin,HIGH);
-            digitalWrite(racer2GoLedPin,HIGH);
-            digitalWrite(racer3GoLedPin,HIGH);
         }
     }
     if (raceStarted) {
         currentTimeMillis = millis() - raceStartMillis;

+        updateRacerTicks();
+
         if(bRaceTypeDistance == true){
-            reportDistanceBased();
+            checkDistanceBased();
         }else{
-            reportTimeBased();
-        }
-
-        printStatusUpdate();
+            checkTimeBased();
+        }
+
+        printRacerUpdate();
     }
 }

-void reportDistanceBased()
+void updateRacerTicks()
+{
+    for(int i=0; i<MAX_RACERS; i++) {
+        previoussensorValues[i] = values[i];
+        values[i] = digitalRead(sensorPins[i]);
+
+        if(mockMode){
+            // 1 km/hr = 0.2778 mm/ms
+            // 114.3mm == fake roller diameter
+            float mmSec = mockSpeedsKph[i] * 277.77778;
+            float curTimeSecs = currentTimeMillis / 1000;
+            //racerTicks[i] = floor( curTimeSecs * mmSec / (114.3 * PI));
+            racerTicks[i] = floor( currentTimeMillis * mockSpeedsKph[i] * 0.2778 / (114.3 * PI));
+        }
+
+        if(values[i] == HIGH && previoussensorValues[i] == LOW){
+            racerTicks[i]++;
+        }
+    }
+}
+
+void printRacerUpdate()
+{
+    if(currentTimeMillis - lastUpdateMillis > updateInterval) {
+        lastUpdateMillis = currentTimeMillis;
+
+        Serial.print("R:");
+
+        for(int i=0; i<MAX_RACERS; i++){
+            Serial.print(racerTicks[i], DEC);
+            Serial.print(",");
+        }
+        Serial.println(currentTimeMillis, DEC);
+    }
+}
+
+void raceStart()
+{
+    raceStartMillis = millis();
+    lastUpdateMillis = raceStartMillis;
+
+    raceStarting = false;
+    raceStarted = true;
+
+    // reset all racers
+    for(int i=0; i<MAX_RACERS; i++) {
+        racerTicks[i] = 0;
+        racerFinishTimeMillis[i] = 0;
+    }
+
+    digitalWrite(racer0GoLedPin,HIGH);
+    digitalWrite(racer1GoLedPin,HIGH);
+    digitalWrite(racer2GoLedPin,HIGH);
+    digitalWrite(racer3GoLedPin,HIGH);
+}
+
+void checkDistanceBased()
 {
     bool bFinished = true;
     for(int i=0; i<MAX_RACERS; i++) {
-        values[i] = digitalRead(sensorPins[i]);
-
-        if(mockMode){
-            values[i] = LOW;
-            if(currentTimeMillis - lastUpdateMillis > updateInterval) {
-                racerTicks[i] += i;
-                values[i] = HIGH;
-            }
-        }
-
-        if(values[i] == HIGH && previoussensorValues[i] == LOW){
-            racerTicks[i]++;
-            if(racerFinishTimeMillis[i] == 0 && racerTicks[i] >= raceLengthTicks) {
-                racerFinishTimeMillis[i] = currentTimeMillis;
-                Serial.print(i);
-                Serial.print("F:");
-                Serial.println(racerFinishTimeMillis[i], DEC);
-                digitalWrite(racer0GoLedPin+i,LOW);
-            }
-        }
+        // check to see if they have finished
+        if(racerFinishTimeMillis[i] == 0 && racerTicks[i] >= raceLengthTicks) {
+            racerFinishTimeMillis[i] = currentTimeMillis;
+
+            Serial.print(i);
+            Serial.print("F:");
+            Serial.println(racerFinishTimeMillis[i], DEC);
+            digitalWrite(racer0GoLedPin+i,LOW);
+        }
+
         if(racerFinishTimeMillis[i] == 0){
             bFinished = false;
         }
-        previoussensorValues[i] = values[i];
     }

     if(bFinished == true){
@@ -289,25 +308,8 @@
     }
 }

-void reportTimeBased()
-{
-    for(int i=0; i<MAX_RACERS; i++) {
-        values[i] = digitalRead(sensorPins[i]);
-
-        if(mockMode){
-            values[i] = LOW;
-            if(currentTimeMillis - lastUpdateMillis > updateInterval) {
-                racerTicks[i] += i;
-                values[i] = HIGH;
-            }
-        }
-
-        if(values[i] == HIGH && previoussensorValues[i] == LOW){
-            racerTicks[i]++;
-        }
-        previoussensorValues[i] = values[i];
-    }
-
+void checkTimeBased()
+{
     if(currentTimeMillis > raceLengthSecs * 1000){
         raceStarted = false;
         // print all racers


Sync with 'moonPhase'.

Sync with 'moonPhase'.

--- moonSimtask.ino
+++ moonSimtask.ino
@@ -4,7 +4,7 @@

   while (1)
   {
-    moonData = moonPhase.getInfo();
+    moonData = moonPhase.getPhase();

     ESP_LOGI( TAG, "Moon phase updated: %i degrees %.6f%% lit", moonData.angle, moonData.percentLit * 100 );


testmote_v0_1.ino: - Moved LED light to pin 7

--- testmote_v0_1/testmote_v0_1.ino
+++ testmote_v0_1/testmote_v0_1.ino
@@ -6,7 +6,9 @@
    Circuit:
    * Moteino R4 w/ RFM69HW RF module
    * Battery voltage monitor attached to analog pin 0
-   * Temperature sensor attached to digital pin 3
+   * Temperature sensor attached to analog pin 1
+   * Light LED attached to digital pin 7
+   * Light Switch attached to digital pin 8
    * RF Status LED attached to digital pin 9

    Created 20-JAN-2015 by Jon Brule
@@ -26,8 +28,8 @@

 #define APIN_BATTERY      0
 #define APIN_TEMPERATURE  1
-#define DPIN_LIGHT        9
-#define DPIN_MOTE_LED     12  // moteinos have LEDs on D9
+#define DPIN_LIGHT        7
+#define DPIN_MOTE_LED     9  // moteinos have LEDs on D9

 #define VOLTAGE           3.3


RFduino - NFC and serial fixes

RFduino - NFC and serial fixes

 serial.begin() wait now for port online (delay code by @bertrooode)
error fixed in decodeSN (@bertrooode)
reworked program config section (#define section)
no serial output in BLE interrupt routine (@chaosbiber)
Serial.flush after heavy serial output (@bertrooode)
additional reset of CR95HF after ULP wakeup and Serial.start (@bertrooode)
own printf() code to avoid fragmented Serial.print() calls / reduce system load? to be verified
set different minimum voltage level for Simblee (@FPV-UAV)

--- LBridge_RFduino_V09/LBridge_RFduino_V09.ino
+++ LBridge_RFduino_V09/LBridge_RFduino_V09.ino
@@ -45,46 +45,54 @@
  *  V0.9.06
  *  - queue length adjusted to 8h
  *  - added debug output for decodeSN
+ *  V0.9.07
+ *  - serial.begin wait now for port online (delay code by @bertrooode)
+ *  - error fixed in decodeSN (@bertrooode)
+ *  - reworked program config section (#define section)
+ *  - no serial output in BLE interrupt routine (@chaosbiber)
+ * V0.9.08
+ *  - Serial.flush after heavy serial output (@bertrooode)
+ *  - additional reset of CR95HF after ULP wakeup and Serial.start (@bertrooode)
+ *  - own printf() code to avoid fragmented Serial.print() calls / reduce system load? to be verified
+ *  - set different minimum voltage level for Simblee (@FPV-UAV)
  */

 /* ********************* program configuration options **********************/

-#define RFD                     // enable for RFduino platform?
-//#define N_RFD                   // enable for Simblee platform
-#define N_USE_DEAD_SENSOR       // enable to work with live sensors
-//#define USE_DEAD_SENSOR         // enable to test with a dead sensor
-#define USE_SPIKE_FILTER        // enable to use a spike filter on raw data
-// #define N_USE_SPIKE_FILTER     // enable to not use a spike filter on raw data
-#define USE_XBRIDGE2            // enable to use two way xbridge2 protocol with backfilling
-//#define N_USE_XBRIDGE2            // enable to use plain LimiTTer text transmission without backchannel
-#define USE_SHADOWFRAM          // work with a shadow FRAM copy of the Libre sensor FRAM
-//#define NSHADOWFRAM            // read a full Libre sensor FRAM content each cycle
-
-//#define SHORTSTARTCYCLE         // first 10 cycles with 1 min period
-#define N_SHORTSTARTCYCLE         // normal system start
+#define RFD                     // uncomment for RFduino platform, otherwise Simblee platform will be used
+//#define USE_DEAD_SENSOR         // uncomment to work with live sensors
+#define USE_SPIKE_FILTER        // uncomment to use a spike filter on raw data
+#define USE_XBRIDGE2            // uncomment to use two way xbridge2 protocol with backfilling instead of LimiTTER
+                                // ASCII protocol (ine way)
+#define USE_SHADOWFRAM          // uncomment to work with a shadow FRAM copy of the Libre sensor FRAM
+//#define SHORTSTARTCYCLE         // uncomment to have 10 inital 1 min cycles to have faster sensor start (@FPV_UAV)

 /*
  * debug and other less important options
  * add an "N_" prefix to disbale the option
  */
-#define N_DEBUG
-#define N_SIM_MINUTES_UPCOUNT     // for testing backfilling with dead sensor
-
-/*
- * BLE and central seetings
- */
+//#define DEBUG                 // uncomment to have verbose debug output
+//#define SIM_MINUTES_UPCOUNT     // for testing backfilling with dead sensor
+//#define ULP_WITH_SERIAL         // uncomment to have serial output during Ultrra Low Power sleep
+
+/* ******************** BLE and central seetings ***************************** */
 #define DXQUEUESIZE (8*12)     // 12 h of queue (remember and send the last x hours when reconnected via BLE)

 #define LB_NAME   "xbridge1"    // dont change "xbridge", space for 1 char left to indicate different versions
 #define LB_ADVERT "rfduino"     // dont change "rfduino"
                                 // length of device name and advertisement <=15!!!
 #define LB_VERSION "V0.9"       // program version
-#define LB_MINOR_VERSION ".06"  // indicates minor version
-#define LB_DATETIME "180213_1332" // date_time
+#define LB_MINOR_VERSION ".08"  // indicates minor version
+#define LB_DATETIME "180219_2147" // date_time
 #define SPIKE_HEIGHT 40         // minimum delta to be a spike

+#ifdef RFD
 #define MAX_VOLTAGE 3600        // adjust voltage measurement to have a wider rrange
 #define MIN_VOLTAGE 2300        // minimum voltage where BLE will work properly (@bertrooode)
+#else
+#define MAX_VOLTAGE 3600        // adjust voltage measurement to have a wider rrange
+#define MIN_VOLTAGE 2550        // minimum voltage where BLE will work properly (@FPV-UAV)
+#endif /* RFD */

 /* ****************************** includes ********************************** */

@@ -98,6 +106,7 @@
 #include <SPI.h>
 #include <Stream.h>
 #include <Memory.h>
+#include <itoa.h>             // support functions for sprintf(...)

 // by @clvsjr9 to Arduino 1.6.5 compile
 //#include <data_types.h>
@@ -184,7 +193,6 @@
 byte runPeriod = 1;                 // czas w minutach - 0 = tylko na żądanie

 unsigned long time_loop_started = 0;
-unsigned long time_elapsed = 0;

 bool BatteryOK = false;

@@ -358,29 +366,35 @@
   p = (dataConfig*)ADDRESS_OF_PAGE(MY_FLASH_PAGE);
   // init and open serial line
   Serial.begin(9600);
-  // time sto settle, avoid serial ghost characters
+  // time to settle, avoid serial ghost characters
   delay(2000);
-
-  Serial.print("\r\n=== loop #"); Serial.print(loop_cnt);
-  Serial.print(" =====================================================================================================");
+  // time to settle, method introduced by @bertrooode
+  // wait for serial interface up and running or if 5 secs are elapsed
+  unsigned long ct = mymillis();
+  do {
+    delay(100);
+  } while ( !Serial && ((mymillis()-ct) < 5000) );
+//  print_statef("serial interface ready after %d ms", mymillis()-ct);
+
+  myprintf("\r\n=== starting =====================================================================================================");

   print_statef("LBridge starting");
-  Serial.printf("\r\n\tBLE name: %s, %s%s from %s", LB_NAME, LB_VERSION, LB_MINOR_VERSION, LB_DATETIME);
-  Serial.printf("\r\n\tRAM used: %d, , Flash used: %d", ramUsed(), flashUsed());
-  Serial.printf("\r\n\tQueue size: %d (%d h)", DXQUEUESIZE, DXQUEUESIZE/12);
-  Serial.printf("\r\n\tCompiled Options:");
+  myprintf("\r\n\tBLE name: %s, %s%s from %s", LB_NAME, LB_VERSION, LB_MINOR_VERSION, LB_DATETIME);
+  myprintf("\r\n\tRAM used: %d, , Flash used: %d", ramUsed(), flashUsed());
+  myprintf("\r\n\tQueue size: %d (%d h)", DXQUEUESIZE, DXQUEUESIZE/12);
+  myprintf("\r\n\tCompiled Options:");
 #ifdef SIM_MINUTES_UPCOUNT
-  Serial.printf("\r\n\t\tsimulate sensor minutes upcount");
+  myprintf("\r\n\t\tsimulate sensor minutes upcount");
 #endif
 #ifdef USE_DEAD_SENSOR
-  Serial.printf("\r\n\t\tusage of dead sensors allowed");
+  myprintf("\r\n\t\tusage of dead sensors allowed");
 #else
-  Serial.printf("\r\n\t\tdetect dead sensor - quit sending readings after 14,5d");
+  myprintf("\r\n\t\tdetect dead sensor - quit sending readings after 14,5d");
 #endif
 #ifdef USE_SPIKE_FILTER
-  Serial.printf("\r\n\t\tremove spikes > +-%d (%f mmol/l)", SPIKE_HEIGHT, (float)(SPIKE_HEIGHT/18.02));
+  myprintf("\r\n\t\tremove spikes > +-%d (%f mmol/l)", SPIKE_HEIGHT, (float)(SPIKE_HEIGHT/18.02));
 #else
-  Serial.printf("\r\n\t\tdont detect and remove spikes");
+  myprintf("\r\n\t\tdont detect and remove spikes");
 #endif

   print_state("setup - start - ");
@@ -398,6 +412,9 @@
   runPeriod = p->runPeriod;
 #endif

+  // test
+//  runPeriod = 1;
+
   loop_cnt = 0;

   nfcInit();
@@ -428,10 +445,8 @@

   // display current data from RFduino
   getSoCData();
-  Serial.printf("\r\n\r\n=== loop #%d === BT %s", loop_cnt, BTconnected ? "ON" : "OFF");
-  Serial.printf(" / RSSI: %f === %d mV (/%d", SoCData.rssi, SoCData.voltage, SoCData.voltagePercent);
-  Serial.print("%)");
-  Serial.printf(" === Soc Temp[C]: %f ===", SoCData.temperatureC);
+  myprintf("\r\n\r\n=== loop #%d === BT %s / RSSI: %f ", loop_cnt, BTconnected ? "ON" : "OFF", SoCData.rssi);
+  myprintf("=== %d mV (%d%%)  === Soc Temp[C]: %f ===", SoCData.voltage, SoCData.voltagePercent, SoCData.temperatureC);

   loop_cnt++;

@@ -443,12 +458,16 @@
   }
 #endif

+  // @bertroode: wait for serial output in process
+  Serial.flush();
+  delay(100);
+
   // display system config for remote debugging
   print_statef("BLE: %s, %s%s from %s, HW: ", LB_NAME, LB_VERSION, LB_MINOR_VERSION, LB_DATETIME, LB_VERSION);
 #ifdef RFD
-  Serial.print("RFduino");
+  myprintf("RFduino");
 #else
-  Serial.print("Simblee");
+  myprintf("Simblee");
 #endif

   if ( BatteryOK ) {
@@ -462,25 +481,47 @@
     }
   }
   else {
-    print_state("low Battery - go sleep");
-  }
-
-  time_elapsed = mymillis() - time_loop_started;
+    print_statef("low Battery - go sleep");
+  }
+
+  // @bertroode: wait for serial output in process
+  Serial.flush();
+  delay(100);
+
+  // calculate sleep time ajusted to runPeriod cycle
+  unsigned long sleep_time = (60000 * runPeriod) - (mymillis() - time_loop_started)%60000;
+//  print_statef("sleep_time = %l (0x%x)", sleep_time, sleep_time);
+
   // sanity check
-  if ( time_elapsed > (60000*10) ) {
-    // in case of terror set to 5 mins fix
-    print_statef(" *** error in sleep time calculationm (%d ms) set to 5 min fix", time_elapsed);
-    time_elapsed = 5*60000L;
-  }
-  print_statef("loop %d - end - NFCReady = %d, sleep for %d s", loop_cnt, NFCReady, (60 * runPeriod)-(time_elapsed/1000));
+  if ( sleep_time > 60000*10 ) {
+    // in case of error set to 5 mins fix
+    print_statef(" *** error in sleep time calculationm (sleep %l ms) set to 5 min fix", sleep_time);
+    sleep_time = 5*60000L;
+  }
+  print_statef("loop #%d - end - NFCReady = %d, sleep for %l s", loop_cnt-1, NFCReady, sleep_time/1000);

   Serial.end();         // reduce power consumption
 #ifdef RFD
-  RFduino_ULPDelay((60000 * runPeriod) - time_elapsed) ;
+  RFduino_ULPDelay(sleep_time);
 #else
-  Simblee_ULPDelay((60000 * runPeriod) - time_elapsed) ;
+  Simblee_ULPDelay(sleep_time);
 #endif
+
   Serial.begin(9600);
+  // time to settle, method in troduced by @bertrooode
+  // wait for serial interface up and running or if 5 secs are elapsed
+  unsigned long ct = mymillis();
+  do {
+    delay(100);
+  } while ( !Serial && ((mymillis()-ct) < 5000) );
+//  print_statef("serial interface ready after %d ms", mymillis()-ct);
+
+  // @bertroode: reset CR95HF to be sure processing is stable /
+  digitalWrite(PIN_SPI_SS, LOW);
+  SPI.transfer(0x01);
+  digitalWrite(PIN_SPI_SS, HIGH);
+  delay(1);
+
 }

 /*
@@ -542,7 +583,7 @@
       }
     }
   }
-  print_statef("missed backfilling values detected: %d", nulls);
+  print_statef("backfilling values: %d", nulls);
 }

 /* ********************************** dump stuff ************************ */
@@ -878,6 +919,7 @@
   idnData.romCRC[1] = resultBuffer[14 + 2];
   return idnData;
 }
+
 void printIDNData(IDNDataType idnData)
 {
   String nfc = "";
@@ -1599,13 +1641,11 @@
     print_state("Sensor data error");
   else
   {
-    print_state("BG raw reading: "); Serial.print(sensorData.trend[0]);
-    print_state("BG temperature: "); Serial.print(sensorData.trendTemperature[0]);
-    print_state("next trend position: "); Serial.print(sensorData.nextTrend);
-    Serial.printf(", next history position: %d", sensorData.nextHistory);
-    print_state("minutes since sensor start: "); Serial.print(sensorData.minutesSinceStart);
-    Serial.printf(", minutes to most recent history: -%d min", sensorData.minutesHistoryOffset);
-    print_state("current raw BG reading: "); Serial.print(scale_bg(sensorData.trend[0]));
+    print_statef("BG raw reading: %d, temperature: %f", sensorData.trend[0], sensorData.trendTemperature[0]);
+    print_statef("next trend position: %d, next history position: %d", sensorData.nextTrend, sensorData.nextHistory);
+//    print_state("minutes since sensor start: "); Serial.print(sensorData.minutesSinceStart);
+//    Serial.printf(", minutes to most recent history: -%d min", sensorData.minutesHistoryOffset);
+//    print_state("current raw BG reading: "); Serial.print(sensorData.trend[0]);
   }
 }

@@ -1650,12 +1690,16 @@
     binS = String(uuidShort[i], BIN);
     int l = binS.length();
     if (l == 1) binS = "0000000" + binS;
+
+    // @bertroode: to fix an error in the reference implementation from @UPetersen
+    else if (l == 5) binS = "000" + binS;
+
     else if (l == 6) binS = "00" + binS;
     else if (l == 7) binS = "0" + binS;
     binary += binS;
   }

-  print_state("decodeSN #1: "); Serial.print(binary);
+//  print_state("decodeSN #1: "); Serial.print(binary);

   String v = "0";
   char pozS[5];
@@ -1666,7 +1710,7 @@
     v += lookupTable[value];
   }

-  print_state("decodeSN #2: "); Serial.print(v);
+//  print_state("decodeSN #2: "); Serial.print(v);

   return v;
 }
@@ -1692,7 +1736,7 @@
 #endif

   if ( debug )
-    print_statef("got glucose(%d) at %d min, stored at %d, inc. write to ", glucose, current_time_ms/60000, Pkts.write);
+    print_statef("got glucose(%d) at %d min, stored at %d, inc. write to ", scale_bg(glucose), current_time_ms/60000, Pkts.write);
   // so increment write position for next round...
   if ( ++Pkts.write >= DXQUEUESIZE )
     Pkts.write = 0;
@@ -1784,7 +1828,7 @@

   print_state("index/pointer/minutes:");
   Serial.printf("\r\n\tnext trend block #%d, next history block #%d", sensorData.nextTrend, sensorData.nextHistory);
-  Serial.printf("\r\n\tminutes elapsed: %d, minutes distance to most recent history value: %d", sensorData.minutesSinceStart, sensorData.minutesHistoryOffset);
+  Serial.printf("\r\n\tminutes elapsed: %d, minutes distance to most recent history value: -%d", sensorData.minutesSinceStart, sensorData.minutesHistoryOffset);

   // copy 16 trend data
   int index = 0;
@@ -1825,7 +1869,7 @@
     for (int k = index; k < index + 6; k++) pomiar[k - index] = sensorDataBody[k];
     sensorData.history[i] = ((pomiar[1] << 8) & 0x0F00) + pomiar[0];
   }
-  Serial.print("done");
+  Serial.print(" - done");
 }

 void decodeSensorFooter()
@@ -2141,13 +2185,17 @@
 void RFduinoBLE_onDisconnect()
 {
   BTconnected = false;
+#ifdef ULP_WITH_SERIAL
   print_state("+++++++++++++ BLE lost");
+#endif
 }

 void RFduinoBLE_onConnect()
 {
   BTconnected = true;
+#ifdef ULP_WITH_SERIAL
   print_state("+++++++++++++ BLE conn");
+#endif
 }

 void RFduinoBLE_onRSSI(int rssi)
@@ -2172,13 +2220,17 @@
 void SimbleeBLE_onDisconnect()
 {
   BTconnected = false;
+#ifdef ULP_WITH_SERIAL
   print_state("+++++++++++++ BLE lost");
+#endif
 }

 void SimbleeBLE_onConnect()
 {
   BTconnected = true;
+#ifdef ULP_WITH_SERIAL
   print_state("+++++++++++++ BLE conn");
+#endif
 }

 void SimbleeBLE_onRSSI(int rssi)
@@ -2612,34 +2664,173 @@
   return free_memory;
 }

-/*
- * print timestamp and current status/action
- */
+/*
+ * print current timestamp
+ */
+char * current_timestamp(char *outbuffer)
+{
+  unsigned long ms = mymillis();
+
+  sprintf(outbuffer, "\r\n[%03d][%03d][%03d] ", ms/60000, (ms/1000)%60, ms%1000);
+  return(outbuffer);
+}
+
 void print_state(String str)
 {
-  unsigned long ms = mymillis();
-  unsigned long val;
-  int i;
-
-  Serial.println("");
-  Serial.print("[");
-  Serial.print(ms / 60000);
-  Serial.print("][");
-  if ( (val = ((ms / 1000) % 60)) < 10 )
-    Serial.print("0");
-  Serial.print(val);
-  Serial.print("][");
-  if ( (val = (ms % 1000)) < 10 )
-    Serial.print("00");
-  else if ( val < 100 )
-    Serial.print("0");
-  Serial.print(val);
-  Serial.print("] ");
-
-  Serial.print(str);
+  char ob[80];
+
+  Serial.printf("%s%s", current_timestamp(ob), str.cstr());
+//  Serial.print(str);
 }

 int print_statef(const char *format, ...)
+{
+  va_list vl;
+  char op[256];
+  char *opp;
+
+  memset(op, 0, sizeof(op));      // for 0 termination
+
+  current_timestamp(op);          // set current timestamp
+
+  opp = &op[strlen(op)];
+  va_start(vl, format);
+
+  while (*format)
+  {
+    if (*format == '%')
+    {
+      format++;
+      char ch = *format;
+      if (! ch)
+        break;
+      else if (ch == '%')
+        *opp++ = *format;
+      else if (ch == 'b') {
+        unsigned u = va_arg(vl, unsigned);
+        utoa(u, opp, 2);
+        opp = &op[strlen(op)];
+      }
+      else if (ch == 'c') {
+        int ch = va_arg(vl, int);
+        *opp++ = (char)ch;
+      }
+      else if (ch == 'd') {
+        int i = va_arg(vl, int);
+        itoa(i, opp, 10);
+        opp = &op[strlen(op)];
+      }
+      else if (ch == 'l') {
+        unsigned long i = va_arg(vl, unsigned long);
+        ultoa(i, opp, 10);
+        opp = &op[strlen(op)];
+      }
+      else if (ch == 'u') {
+        unsigned u = va_arg(vl, unsigned);
+        utoa(u, opp, 10);
+        opp = &op[strlen(op)];
+      }
+      else if (ch == 'x') {
+        unsigned x = va_arg(vl, unsigned);
+        itoa(x, opp, 16);
+        opp = &op[strlen(op)];
+      }
+      else if (ch == 's') {
+        char *s = va_arg(vl, char *);
+        strcat(op, s);
+        opp = &op[strlen(op)];
+      }
+      else if (ch == 'f') {
+        char format[20];
+        double d = va_arg(vl, double);
+        sprintf(opp, "%d.%02d", (int)d, ((int)(d*100))%100);
+        opp = &op[strlen(op)];
+      }
+    }
+    else
+     *opp++ = *format;
+    format++;
+  }
+
+  va_end(vl);
+
+  Serial.print(op);
+
+  return 1;
+}
+
+int myprintf(const char *format, ...)
+{
+  va_list vl;
+  char op[256];
+  char *opp;
+
+  memset(op, 0, sizeof(op));  // for 0 termination
+  opp = &op[0];               // set pointer to array start
+  va_start(vl, format);
+
+  while (*format) {
+    if (*format == '%') {     // format descriptor found?
+      format++;
+      char ch = *format;
+      if (! ch)
+        break;
+      else if (ch == '%')
+        *opp++ = *format;
+      else if (ch == 'b') {
+        unsigned u = va_arg(vl, unsigned);
+        utoa(u, opp, 2);
+        opp = &op[strlen(op)];
+      }
+      else if (ch == 'c') {
+        int ch = va_arg(vl, int);
+        *opp++ = (char)ch;
+      }
+      else if (ch == 'd') {
+        int i = va_arg(vl, int);
+        itoa(i, opp, 10);
+        opp = &op[strlen(op)];
+      }
+      else if (ch == 'l') {
+        unsigned long i = va_arg(vl, unsigned long);
+        ultoa(i, opp, 10);
+        opp = &op[strlen(op)];
+      }
+      else if (ch == 'u') {
+        unsigned u = va_arg(vl, unsigned);
+        utoa(u, opp, 10);
+        opp = &op[strlen(op)];
+      }
+      else if (ch == 'x') {
+        unsigned x = va_arg(vl, unsigned);
+        itoa(x, opp, 16);
+        opp = &op[strlen(op)];
+      }
+      else if (ch == 's') {
+        char *s = va_arg(vl, char *);
+        strcat(op, s);
+        opp = &op[strlen(op)];
+      }
+      else if (ch == 'f') {
+        char format[20];
+        double d = va_arg(vl, double);
+        sprintf(opp, "%d.%02d", (int)d, ((int)(d*100))%100);
+        opp = &op[strlen(op)];
+      }
+    }
+    else
+     *opp++ = *format;
+    format++;
+  }
+
+  va_end(vl);
+
+  Serial.print(op);
+
+  return 1;
+}
+
+int old_print_statef(const char *format, ...)
 {
   va_list vl;
   size_t n = 0;


Added gravity

Added gravity

--- src/src.ino
+++ src/src.ino
@@ -182,6 +182,7 @@
 void MoveBird()
 {
 	static float y = 0.5;
+	game.BirdVel = game.BirdVel + grav;
 	float initY = game.BirdCrd;

   	game.BirdCrd = game.BirdCrd + game.BirdVel;


Update dudrack.ino

Update dudrack.ino

--- arduino/dudrack/dudrack.ino
+++ arduino/dudrack/dudrack.ino
@@ -5,11 +5,17 @@
 #include <usbhub.h>
 #include <Keyboard.h>
 #include <Mouse.h>
-
-#define LEN 8
-
-#define MODIFIER_CTRL_LEFT 0x1
-#define MODIFIER_SHIFT_LEFT 0x2
+#include <Joystick.h>
+
+#define OUTPUT_TO_SERIAL 0
+
+#define NUM_REPORT_KEYS 6
+
+#define MODIFIER_LEFT_CTRL 0x1
+#define MODIFIER_LEFT_SHIFT 0x2
+#define MODIFIER_LEFT_ALT 0x4
+#define MODIFIER_RIGHT_SHIFT 0x20
+#define MODIFIER_RIGHT_ALT 0x40

 #define KEY_CAPS_LOCK 0x39
 #define KEY_HENKAN 0x8A
@@ -60,6 +66,7 @@
 #define KEY_B 0x5
 #define KEY_N 0x11
 #define KEY_M 0x10
+#define KEY_SPACE 0x2C
 #define KEY_COMMA 0x36
 #define KEY_PERIOD 0x37
 #define KEY_SLASH 0x38
@@ -79,189 +86,556 @@
 #define KEY_HOME 0x4A
 #define KEY_END 0x4D

-#define KEY_COUNT 0x100
-
-#define OUTPUT_TO_SERIAL 1
-
-uint8_t neutralTable[KEY_COUNT];
-void initNeutralTable(){
-    for (int i = 0; i < KEY_COUNT; ++i){
-        neutralTable[i] = i;
-    }
-
-    neutralTable[KEY_Q        ] = KEY_COLON;
-    neutralTable[KEY_W        ] = KEY_COMMA;
-    neutralTable[KEY_E        ] = KEY_PERIOD;
-    neutralTable[KEY_R        ] = KEY_P;
-    neutralTable[KEY_T        ] = KEY_Y;
-    neutralTable[KEY_Y        ] = KEY_F;
-    neutralTable[KEY_U        ] = KEY_G;
-    neutralTable[KEY_I        ] = KEY_C;
-    neutralTable[KEY_O        ] = KEY_R;
-    neutralTable[KEY_P        ] = KEY_L;
-    neutralTable[KEY_AT       ] = KEY_SLASH;
-    neutralTable[KEY_S        ] = KEY_O;
-    neutralTable[KEY_D        ] = KEY_E;
-    neutralTable[KEY_F        ] = KEY_U;
-    neutralTable[KEY_G        ] = KEY_I;
-    neutralTable[KEY_H        ] = KEY_D;
-    neutralTable[KEY_J        ] = KEY_H;
-    neutralTable[KEY_K        ] = KEY_T;
-    neutralTable[KEY_L        ] = KEY_N;
-    neutralTable[KEY_SEMICOLON] = KEY_S;
-    neutralTable[KEY_COLON    ] = KEY_MINUS;
-    neutralTable[KEY_Z        ] = KEY_SEMICOLON;
-    neutralTable[KEY_X        ] = KEY_Q;
-    neutralTable[KEY_C        ] = KEY_J;
-    neutralTable[KEY_V        ] = KEY_K;
-    neutralTable[KEY_B        ] = KEY_X;
-    neutralTable[KEY_N        ] = KEY_B;
-    neutralTable[KEY_M        ] = KEY_M;
-    neutralTable[KEY_COMMA    ] = KEY_W;
-    neutralTable[KEY_PERIOD   ] = KEY_V;
-    neutralTable[KEY_SLASH    ] = KEY_Z;
-}
-
-uint8_t henkanTable[KEY_COUNT];
-void initHenkanTable(){
-    for (int i = 0; i < KEY_COUNT; ++i){
-        henkanTable[i] = i;
-    }
-
-    henkanTable[KEY_Q        ] = KEY_1;
-    henkanTable[KEY_W        ] = KEY_2;
-    henkanTable[KEY_E        ] = KEY_3;
-    henkanTable[KEY_R        ] = KEY_4;
-    henkanTable[KEY_T        ] = KEY_5;
-    henkanTable[KEY_Y        ] = KEY_6;
-    henkanTable[KEY_U        ] = KEY_7;
-    henkanTable[KEY_I        ] = KEY_8;
-    henkanTable[KEY_O        ] = KEY_9;
-    henkanTable[KEY_P        ] = KEY_0;
-    henkanTable[KEY_AT       ] = KEY_SLASH;
-    henkanTable[KEY_A        ] = KEY_TAB;
-    henkanTable[KEY_S        ] = KEY_ESCAPE;
-    henkanTable[KEY_D        ] = KEY_ENTER;
-    henkanTable[KEY_F        ] = KEY_BACKSPACE;
-    henkanTable[KEY_G        ] = KEY_DELETE;
-    henkanTable[KEY_H        ] = KEY_HOME;
-    henkanTable[KEY_J        ] = KEY_LEFT;
-    henkanTable[KEY_K        ] = KEY_UP;
-    henkanTable[KEY_L        ] = KEY_RIGHT;
-    henkanTable[KEY_SEMICOLON] = KEY_END;
-    henkanTable[KEY_COLON    ] = KEY_MINUS;
-    henkanTable[KEY_Z        ] = KEY_AT;
-    henkanTable[KEY_X        ] = KEY_BRACKET_OPEN;
-    henkanTable[KEY_C        ] = KEY_BRACKET_CLOSE;
-    henkanTable[KEY_V        ] = KEY_HAT;
-    henkanTable[KEY_B        ] = KEY_X;
-    henkanTable[KEY_N        ] = KEY_B;
-    henkanTable[KEY_M        ] = KEY_BACKSLASH;
-    henkanTable[KEY_COMMA    ] = KEY_DOWN;
-    henkanTable[KEY_PERIOD   ] = KEY_YEN;
-    henkanTable[KEY_SLASH    ] = KEY_HAN_ZEN;
-}
-
-bool remove(uint8_t *buf, uint8_t key){
-    uint8_t index;
-
-    for (index = 2; index < LEN; ++index) {
-        if (buf[index] == key) break;
-    }
-
-    if (index == LEN) return false;
-
-    for (; index < LEN - 1; ++index) {
-        buf[index] = buf[index + 1];
-    }
-
-    buf[LEN - 1] = 0;
+#define KEY_PAGE_UP 0x4B
+#define KEY_PAGE_DOWN 0x4E
+
+#define KEY_COUNT 0xE8
+
+#define MOUSE_MOVE_COEFFICIENT 3.0
+#define MOUSE_SCROLL_COEFFICIENT 1.0
+
+#define MODE_NEUTRAL 0
+#define MODE_DUDRACK 1
+#define MODE_STG 2
+#define MODE_COUNT 3
+
+#define MAPPING_NEUTRAL 0
+#define MAPPING_HENKAN 1
+#define MAPPING_COUNT 2
+
+#define STICK_NEUTRAL 0
+#define STICK_DOWN 1
+#define STICK_UP -1
+#define STICK_LEFT -1
+#define STICK_RIGHT 1
+
+#define STICK_DOWN_KEY KEY_A
+#define STICK_UP_KEY KEY_S
+#define STICK_LEFT_KEY KEY_AT
+#define STICK_RIGHT_KEY KEY_BRACKET_OPEN
+#define BUTTON_0_MODIFIER bmRightAlt
+#define BUTTON_1_KEY KEY_ENTER
+#define BUTTON_2_MODIFIER bmLeftAlt
+#define BUTTON_3_KEY KEY_TAB
+#define BUTTON_4_MODIFIER bmLeftCtrl
+#define BUTTON_5_KEY KEY_SPACE
+
+USB    Usb;
+USBHub Hub(&Usb);
+
+HIDBoot<USB_HID_PROTOCOL_KEYBOARD | USB_HID_PROTOCOL_MOUSE> HidComposite(&Usb);
+HIDBoot<USB_HID_PROTOCOL_KEYBOARD>                          HidKeyboard(&Usb);
+HIDBoot<USB_HID_PROTOCOL_MOUSE>                             HidMouse(&Usb);
+
+Joystick_ Joystick;
+
+uint8_t keyMappings[MAPPING_COUNT][KEY_COUNT];
+void initKeyMappings() {
+    for (int mapping = 0; mapping < MAPPING_COUNT; ++mapping) {
+        for (int key = 0; key < KEY_COUNT; ++key) {
+            keyMappings[mapping][key] = key;
+        }
+    }
+
+    keyMappings[MAPPING_NEUTRAL][KEY_Q        ] = KEY_COLON;
+    keyMappings[MAPPING_NEUTRAL][KEY_W        ] = KEY_COMMA;
+    keyMappings[MAPPING_NEUTRAL][KEY_E        ] = KEY_PERIOD;
+    keyMappings[MAPPING_NEUTRAL][KEY_R        ] = KEY_P;
+    keyMappings[MAPPING_NEUTRAL][KEY_T        ] = KEY_Y;
+    keyMappings[MAPPING_NEUTRAL][KEY_Y        ] = KEY_F;
+    keyMappings[MAPPING_NEUTRAL][KEY_U        ] = KEY_G;
+    keyMappings[MAPPING_NEUTRAL][KEY_I        ] = KEY_C;
+    keyMappings[MAPPING_NEUTRAL][KEY_O        ] = KEY_R;
+    keyMappings[MAPPING_NEUTRAL][KEY_P        ] = KEY_L;
+    keyMappings[MAPPING_NEUTRAL][KEY_AT       ] = KEY_SLASH;
+    keyMappings[MAPPING_NEUTRAL][KEY_S        ] = KEY_O;
+    keyMappings[MAPPING_NEUTRAL][KEY_D        ] = KEY_E;
+    keyMappings[MAPPING_NEUTRAL][KEY_F        ] = KEY_U;
+    keyMappings[MAPPING_NEUTRAL][KEY_G        ] = KEY_I;
+    keyMappings[MAPPING_NEUTRAL][KEY_H        ] = KEY_D;
+    keyMappings[MAPPING_NEUTRAL][KEY_J        ] = KEY_H;
+    keyMappings[MAPPING_NEUTRAL][KEY_K        ] = KEY_T;
+    keyMappings[MAPPING_NEUTRAL][KEY_L        ] = KEY_N;
+    keyMappings[MAPPING_NEUTRAL][KEY_SEMICOLON] = KEY_S;
+    keyMappings[MAPPING_NEUTRAL][KEY_COLON    ] = KEY_MINUS;
+    keyMappings[MAPPING_NEUTRAL][KEY_Z        ] = KEY_SEMICOLON;
+    keyMappings[MAPPING_NEUTRAL][KEY_X        ] = KEY_Q;
+    keyMappings[MAPPING_NEUTRAL][KEY_C        ] = KEY_J;
+    keyMappings[MAPPING_NEUTRAL][KEY_V        ] = KEY_K;
+    keyMappings[MAPPING_NEUTRAL][KEY_B        ] = KEY_X;
+    keyMappings[MAPPING_NEUTRAL][KEY_N        ] = KEY_B;
+    keyMappings[MAPPING_NEUTRAL][KEY_M        ] = KEY_M;
+    keyMappings[MAPPING_NEUTRAL][KEY_COMMA    ] = KEY_W;
+    keyMappings[MAPPING_NEUTRAL][KEY_PERIOD   ] = KEY_V;
+    keyMappings[MAPPING_NEUTRAL][KEY_SLASH    ] = KEY_Z;
+
+    keyMappings[MAPPING_HENKAN][KEY_Q        ] = KEY_1;
+    keyMappings[MAPPING_HENKAN][KEY_W        ] = KEY_2;
+    keyMappings[MAPPING_HENKAN][KEY_E        ] = KEY_3;
+    keyMappings[MAPPING_HENKAN][KEY_R        ] = KEY_4;
+    keyMappings[MAPPING_HENKAN][KEY_T        ] = KEY_5;
+    keyMappings[MAPPING_HENKAN][KEY_Y        ] = KEY_6;
+    keyMappings[MAPPING_HENKAN][KEY_U        ] = KEY_7;
+    keyMappings[MAPPING_HENKAN][KEY_I        ] = KEY_8;
+    keyMappings[MAPPING_HENKAN][KEY_O        ] = KEY_9;
+    keyMappings[MAPPING_HENKAN][KEY_P        ] = KEY_0;
+    keyMappings[MAPPING_HENKAN][KEY_AT       ] = KEY_SLASH;
+    keyMappings[MAPPING_HENKAN][KEY_A        ] = KEY_TAB;
+    keyMappings[MAPPING_HENKAN][KEY_S        ] = KEY_ESCAPE;
+    keyMappings[MAPPING_HENKAN][KEY_D        ] = KEY_ENTER;
+    keyMappings[MAPPING_HENKAN][KEY_F        ] = KEY_BACKSPACE;
+    keyMappings[MAPPING_HENKAN][KEY_G        ] = KEY_DELETE;
+    keyMappings[MAPPING_HENKAN][KEY_H        ] = KEY_AT;
+    keyMappings[MAPPING_HENKAN][KEY_J        ] = KEY_BACKSLASH;
+    keyMappings[MAPPING_HENKAN][KEY_K        ] = KEY_BRACKET_OPEN;
+    keyMappings[MAPPING_HENKAN][KEY_L        ] = KEY_BRACKET_CLOSE;
+    keyMappings[MAPPING_HENKAN][KEY_SEMICOLON] = KEY_YEN;
+    keyMappings[MAPPING_HENKAN][KEY_COLON    ] = KEY_MINUS;
+    keyMappings[MAPPING_HENKAN][KEY_Z        ] = KEY_LEFT;
+    keyMappings[MAPPING_HENKAN][KEY_X        ] = KEY_DOWN;
+    keyMappings[MAPPING_HENKAN][KEY_C        ] = KEY_UP;
+    keyMappings[MAPPING_HENKAN][KEY_V        ] = KEY_RIGHT;
+    keyMappings[MAPPING_HENKAN][KEY_B        ] = KEY_X;
+    keyMappings[MAPPING_HENKAN][KEY_N        ] = KEY_HAN_ZEN;
+    keyMappings[MAPPING_HENKAN][KEY_M        ] = KEY_MUHENKAN;
+    keyMappings[MAPPING_HENKAN][KEY_COMMA    ] = KEY_HOME;
+    keyMappings[MAPPING_HENKAN][KEY_PERIOD   ] = KEY_END;
+    keyMappings[MAPPING_HENKAN][KEY_SLASH    ] = KEY_HAT;
+}
+
+int currentMode = MODE_DUDRACK;
+
+KeyReport keyReport = {};
+bool henkanPressed = false;
+bool muhenkanPressed = false;
+bool spacePressed = false;
+bool noEventBetweenSpaceEvents = false;
+
+bool downPressed = false;
+bool upPressed = false;
+bool leftPressed = false;
+bool rightPressed = false;
+
+bool removeFromKeyReport(KeyReport *report, uint8_t key){
+    int i;
+
+    for (i = 0; i < NUM_REPORT_KEYS; ++i) {
+        if (report->keys[i] == key) {
+            break;
+        }
+    }
+
+    if (i == NUM_REPORT_KEYS) {
+        return false;
+    }
+
+    for (; i < NUM_REPORT_KEYS - 1; ++i) {
+        report->keys[i] = report->keys[i + 1];
+    }
+
+    report->keys[NUM_REPORT_KEYS - 1] = 0;

     return true;
 }

-void changeCapsLockToControl(uint8_t *buf){
-    if (remove(buf, KEY_CAPS_LOCK)) buf[0] |= MODIFIER_CTRL_LEFT;
-}
-
-void changeMuhenkanToShift(uint8_t *buf) {
-    if (remove(buf, KEY_MUHENKAN)) buf[0] |= MODIFIER_SHIFT_LEFT;
-}
-
-bool henkanPrev = false;
-
-void handleCustomModifier(uint8_t *buf) {
-    bool henkan = remove(buf, KEY_HENKAN);
-
-    // modifierが変化した時にはキーを出力しない
-    if (!henkanPrev && henkan || henkanPrev && !henkan) {
-        for (int i = 2; i < LEN; i++) {
-            buf[i] = 0;
-        }
-    } else if (henkan){
-        for (int i = 2; i < LEN; i++){
-            buf[i] = henkanTable[buf[i]];
-        }
+void pressKey(uint8_t key) {
+    for (int i = 0; i < NUM_REPORT_KEYS; ++i) {
+        if (keyReport.keys[i] == 0) {
+            keyReport.keys[i] = key;
+
+            Keyboard.sendReport(&keyReport);
+
+            return;
+        }
+
+        if (keyReport.keys[i] == key) {
+            return;
+        }
+    }
+}
+
+void releaseKey(uint8_t key) {
+    if (removeFromKeyReport(&keyReport, key)) {
+        Keyboard.sendReport(&keyReport);
+    }
+}
+
+void releaseAllKeys() {
+    henkanPressed = false;
+    muhenkanPressed = false;
+    spacePressed = false;
+
+    downPressed = false;
+    upPressed = false;
+    leftPressed = false;
+    rightPressed = false;
+
+    keyReport.modifiers = 0;
+
+    for (int i = 0; i < NUM_REPORT_KEYS; i++) {
+        keyReport.keys[i] = 0;
+    }
+
+    Keyboard.sendReport(&keyReport);
+}
+
+void pressModifier(uint8_t modifier) {
+    keyReport.modifiers |= modifier;
+    Keyboard.sendReport(&keyReport);
+}
+
+void releaseModifier(uint8_t modifier) {
+    keyReport.modifiers &= ~modifier;
+    Keyboard.sendReport(&keyReport);
+}
+
+void changeModifiers(uint8_t modifiers) {
+    keyReport.modifiers = modifiers | (spacePressed ? MODIFIER_LEFT_SHIFT : 0);
+    Keyboard.sendReport(&keyReport);
+}
+
+bool handleModeSwitch(uint8_t modifiers, uint8_t key) {
+    if (modifiers & MODIFIER_RIGHT_SHIFT) {
+        switch (key) {
+            case KEY_1:
+                currentMode = MODE_NEUTRAL;
+
+                return true;
+
+            case KEY_2:
+                currentMode = MODE_DUDRACK;
+
+                return true;
+
+            case KEY_3:
+                currentMode = MODE_STG;
+
+                return true;
+        }
+    }
+
+    return false;
+}
+
+void dudrackKeyDown(uint8_t key) {
+    switch (key) {
+        case KEY_HENKAN:
+            henkanPressed = true;
+
+            return;
+
+        case KEY_MUHENKAN:
+            muhenkanPressed = true;
+
+            return;
+
+        case KEY_SPACE:
+            pressModifier(MODIFIER_LEFT_SHIFT);
+            spacePressed = true;
+            noEventBetweenSpaceEvents = true;
+
+            return;
+
+        default:
+            noEventBetweenSpaceEvents = false;
+
+            if (muhenkanPressed) {
+                pressModifier(MODIFIER_LEFT_SHIFT);
+            }
+
+            if (henkanPressed || muhenkanPressed) {
+                pressKey(keyMappings[MAPPING_HENKAN][key]);
+            } else {
+                pressKey(keyMappings[MAPPING_NEUTRAL][key]);
+            }
+    }
+}
+
+void dudrackKeyUp(uint8_t key) {
+    switch (key) {
+        case KEY_HENKAN:
+            henkanPressed = false;
+
+            return;
+
+        case KEY_MUHENKAN:
+            muhenkanPressed = false;
+            releaseModifier(MODIFIER_LEFT_SHIFT);
+
+            return;
+
+        case KEY_SPACE:
+            spacePressed = false;
+            releaseModifier(MODIFIER_LEFT_SHIFT);
+            if (noEventBetweenSpaceEvents) {
+                pressKey(KEY_SPACE);
+                releaseKey(KEY_SPACE);
+            }
+
+            return;
+
+        default:
+            releaseKey(keyMappings[MAPPING_HENKAN][key]);
+            releaseKey(keyMappings[MAPPING_NEUTRAL][key]);
+
+            if (muhenkanPressed) {
+                releaseModifier(MODIFIER_LEFT_SHIFT);
+            }
+    }
+}
+
+void dudrackModifiersChange(uint8_t modifiers) {
+    changeModifiers(modifiers);
+}
+
+void stgKeyDown(uint8_t key) {
+    switch (key) {
+        case STICK_DOWN_KEY:
+            downPressed = true;
+            Joystick.setYAxis(STICK_DOWN);
+
+            return;
+
+        case STICK_UP_KEY:
+            upPressed = true;
+            Joystick.setYAxis(STICK_UP);
+
+            return;
+
+        case STICK_LEFT_KEY:
+            leftPressed = true;
+            Joystick.setXAxis(STICK_LEFT);
+
+            return;
+
+        case STICK_RIGHT_KEY:
+            rightPressed = true;
+            Joystick.setXAxis(STICK_RIGHT);
+
+            return;
+
+        case BUTTON_1_KEY:
+            Joystick.pressButton(1);
+
+            return;
+
+        case BUTTON_3_KEY:
+            Joystick.pressButton(3);
+
+            return;
+
+        case BUTTON_5_KEY:
+            Joystick.pressButton(5);
+
+            return;
+    }
+}
+
+void stgKeyUp(uint8_t key) {
+    switch (key) {
+        case STICK_DOWN_KEY:
+            downPressed = false;
+            Joystick.setYAxis(upPressed ? STICK_UP : STICK_NEUTRAL);
+
+            return;
+
+        case STICK_UP_KEY:
+            upPressed = false;
+            Joystick.setYAxis(downPressed ? STICK_DOWN : STICK_NEUTRAL);
+
+            return;
+
+        case STICK_LEFT_KEY:
+            leftPressed = false;
+            Joystick.setXAxis(rightPressed ? STICK_RIGHT : STICK_NEUTRAL);
+
+            return;
+
+        case STICK_RIGHT_KEY:
+            rightPressed = false;
+            Joystick.setXAxis(leftPressed ? STICK_LEFT : STICK_NEUTRAL);
+
+            return;
+
+        case BUTTON_1_KEY:
+            Joystick.releaseButton(1);
+
+            return;
+
+        case BUTTON_3_KEY:
+            Joystick.releaseButton(3);
+
+            return;
+
+        case BUTTON_5_KEY:
+            Joystick.releaseButton(5);
+
+            return;
+    }
+}
+
+void stgModifiersChange(uint8_t modifiers) {
+    MODIFIERKEYS mod = *((MODIFIERKEYS*)&modifiers);
+
+    if (mod.BUTTON_0_MODIFIER) {
+        Joystick.pressButton(0);
     } else {
-        for (int i = 2; i < LEN; i++){
-            buf[i] = neutralTable[buf[i]];
-        }
-    }
-
-    henkanPrev = henkan;
-}
-
-
-class HIDKeyboardReportParser : public HIDReportParser {
+        Joystick.releaseButton(0);
+    }
+
+    if (mod.BUTTON_2_MODIFIER) {
+        Joystick.pressButton(2);
+    } else {
+        Joystick.releaseButton(2);
+    }
+
+    if (mod.BUTTON_4_MODIFIER) {
+        Joystick.pressButton(4);
+    } else {
+        Joystick.releaseButton(4);
+    }
+}
+
+class : public KeyboardReportParser {
 public:
     virtual void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
-#if OUTPUT_TO_SERIAL
-        Serial.print("SRC:  ");
-        for (int i = 0; i < LEN; i++) {
-            Serial.print(buf[i], HEX);
+        KeyReport *report = (KeyReport*)(buf);
+
+#if OUTPUT_TO_SERIAL
+        Serial.print("src modifiers:  ");
+        Serial.println(report->modifiers, HEX);
+        Serial.print("src keys:  ");
+        for (int i = 0; i < NUM_REPORT_KEYS; i++) {
+            Serial.print(report->keys[i], HEX);
             Serial.print(" ");
         }
         Serial.println("");
 #endif

-        changeCapsLockToControl(buf);
-        changeMuhenkanToShift(buf);
-        handleCustomModifier(buf);
-
-#if OUTPUT_TO_SERIAL
-        Serial.print("DEST: ");
-        for (int i = 0; i < len; i++) {
-            Serial.print(buf[i], HEX);
+        if (removeFromKeyReport(report, KEY_CAPS_LOCK)) {
+            report->modifiers |= MODIFIER_LEFT_CTRL;
+        }
+
+#if OUTPUT_TO_SERIAL
+        Serial.print("dest modifiers:  ");
+        Serial.println(report->modifiers, HEX);
+        Serial.print("dest keys:  ");
+        for (int i = 0; i < NUM_REPORT_KEYS; i++) {
+            Serial.print(report->keys[i], HEX);
             Serial.print(" ");
         }
         Serial.println("");
 #endif

-        Keyboard.sendReport((KeyReport *)buf);
-    }
-};
-
-
-class HIDMouseReportParser : public MouseReportParser {
+        KeyboardReportParser::Parse(hid, is_rpt_id, len, (uint8_t*)report);
+
+#if OUTPUT_TO_SERIAL
+        Serial.println("");
+#endif
+    }
+
+    virtual void OnKeyDown(uint8_t modifiers, uint8_t key) {
+#if OUTPUT_TO_SERIAL
+        Serial.print("key down:  ");
+        Serial.println(key, HEX);
+#endif
+
+        if (handleModeSwitch(modifiers, key)) {
+            releaseAllKeys();
+
+            return;
+        }
+
+        switch (currentMode) {
+            case MODE_NEUTRAL:
+                pressKey(key);
+                return;
+
+            case MODE_DUDRACK:
+                dudrackKeyDown(key);
+                return;
+
+            case MODE_STG:
+                stgKeyDown(key);
+                return;
+        }
+    }
+
+    virtual void OnKeyUp(uint8_t modifiers, uint8_t key) {
+#if OUTPUT_TO_SERIAL
+        Serial.print("key up:  ");
+        Serial.println(key, HEX);
+#endif
+
+        switch (currentMode) {
+            case MODE_NEUTRAL:
+                releaseKey(key);
+                return;
+
+            case MODE_DUDRACK:
+                dudrackKeyUp(key);
+                return;
+
+            case MODE_STG:
+                stgKeyUp(key);
+                return;
+        }
+    }
+
+    virtual void OnControlKeysChanged(uint8_t before, uint8_t after) {
+#if OUTPUT_TO_SERIAL
+        Serial.print("modifiers change: ");
+        Serial.print(before, HEX);
+        Serial.print(" -> ");
+        Serial.println(after, HEX);
+#endif
+
+        switch (currentMode) {
+            case MODE_NEUTRAL:
+                changeModifiers(after);
+                return;
+
+            case MODE_DUDRACK:
+                dudrackModifiersChange(after);
+                return;
+
+            case MODE_STG:
+                stgModifiersChange(after);
+                return;
+        }
+    }
+} keyboardReportParser;
+
+class : public MouseReportParser {
 protected:
-    virtual void OnMouseMove(MOUSEINFO *mouseInfo)        { Mouse.move((signed char)(mouseInfo->dX * 1.5), (signed char)(mouseInfo->dY * 1.5), 0); }
+    virtual void OnMouseMove(MOUSEINFO *mouseInfo)        {
+        if (muhenkanPressed || henkanPressed) {
+#if OUTPUT_TO_SERIAL
+            Serial.print("mouse scroll: ");
+            Serial.println(min(1, max(-1, (int8_t)(-mouseInfo->dY * MOUSE_SCROLL_COEFFICIENT))));
+#endif
+            Mouse.move(0, 0, min(1, max(-1, (int8_t)(-mouseInfo->dY * MOUSE_SCROLL_COEFFICIENT))));
+        } else {
+#if OUTPUT_TO_SERIAL
+            Serial.print("mouse move: ");
+            Serial.print((int8_t)(mouseInfo->dX * MOUSE_MOVE_COEFFICIENT));
+            Serial.print(" ");
+            Serial.println((int8_t)(mouseInfo->dY * MOUSE_MOVE_COEFFICIENT));
+#endif
+            Mouse.move(
+                (int8_t)(mouseInfo->dX * MOUSE_MOVE_COEFFICIENT),
+                (int8_t)(mouseInfo->dY * MOUSE_MOVE_COEFFICIENT),
+                0
+            );
+        }
+    }
+
     virtual void OnLeftButtonDown(MOUSEINFO *mouseInfo)   { Mouse.press(MOUSE_LEFT); }
     virtual void OnLeftButtonUp(MOUSEINFO *mouseInfo)     { Mouse.release(MOUSE_LEFT); }
     virtual void OnRightButtonDown(MOUSEINFO *mouseInfo)  { Mouse.press(MOUSE_RIGHT); }
     virtual void OnRightButtonUp(MOUSEINFO *mouseInfo)    { Mouse.release(MOUSE_RIGHT); }
-    virtual void OnMiddleButtonDown(MOUSEINFO *mouseInfo) { Mouse.press(MOUSE_MIDDLE); }
-    virtual void OnMiddleButtonUp(MOUSEINFO *mouseInfo)   { Mouse.release(MOUSE_MIDDLE); }
-};
-
-USB    Usb;
-USBHub Hub(&Usb);
-
-HIDBoot<USB_HID_PROTOCOL_KEYBOARD | USB_HID_PROTOCOL_MOUSE> HidComposite(&Usb);
-HIDBoot<USB_HID_PROTOCOL_KEYBOARD>                          HidKeyboard(&Usb);
-HIDBoot<USB_HID_PROTOCOL_MOUSE>                             HidMouse(&Usb);
-
-HIDKeyboardReportParser keyboardReportParser;
-HIDMouseReportParser mouseReportParser;
+} mouseReportParser;
+

 void setup() {
     int usbStatus = Usb.Init();
@@ -272,17 +646,22 @@
     if (usbStatus == -1) {
         Serial.println("OSC did not start.");
     }
-#endif
-
-    initNeutralTable();
-    initHenkanTable();
+    Serial.println("Started");
+#endif
+
+    initKeyMappings();

     HidComposite.SetReportParser(0, &keyboardReportParser);
     HidComposite.SetReportParser(1, &mouseReportParser);
     HidKeyboard.SetReportParser(0, &keyboardReportParser);
     HidMouse.SetReportParser(0, &mouseReportParser);
+
+    Joystick.setXAxisRange(STICK_UP, STICK_DOWN);
+    Joystick.setYAxisRange(STICK_LEFT, STICK_RIGHT);
+
     Mouse.begin();
     Keyboard.begin();
+    Joystick.begin();
 }

 void loop() {


Added analog proximity type reset switch code.

--- starsynctrackers.ino
+++ starsynctrackers.ino
@@ -25,18 +25,42 @@
 static const float D_F = 0.410; // Distiance along rod from plate to starting position // Russ: 0.432
 static const float RECALC_INTERVAL_S = 15; // Time in seconds between recalculating

+// STOP_TYPE
+// 0 for switch button type
+// 1 for analog proximity type
+#define STOP_TYPE 0
+static const int STOP_ANALOG_POWER_PINS[3] = {5, 6, 7}; //Pins stop switch gets power from, Digital pins only.
+static const int STOP_ANALOG_POWER_STOP_VALUE = 300; // 0 - 1023 (0 closer, 1023 farther)
 static const int STOP_BUTTON_PIN = A4;      // The pin the stop push switch is on
 static const int STOP_BUTTON_TYPE = 1;     // The type of switch 0 - Normally Closed; 1 - Normally Open
 static const float DIRECTION = -1.0; // 1 forward is forward; -1 + is forward is backward

 #include "stepper_drivers.h"

+#if STOP_TYPE == 1
+void stop_analog_power(boolean powered) {
+  // Switch all pins at same time so one pin doesn't give all the current for some time.
+  uint8_t d = (1 << STOP_ANALOG_POWER_PINS[0]) + (1 << STOP_ANALOG_POWER_PINS[1]) + (1 << STOP_ANALOG_POWER_PINS[2]);
+  if (powered) {
+    PORTD |= d;
+    // digitalWrite(STOP_ANALOG_POWER_PINS[0], HIGH); digitalWrite(STOP_ANALOG_POWER_PINS[1], HIGH); digitalWrite(STOP_ANALOG_POWER_PINS[2], HIGH);
+  } else {
+    PORTD &= 0xFF ^ d;
+    // digitalWrite(STOP_ANALOG_POWER_PINS[0], LOW); digitalWrite(STOP_ANALOG_POWER_PINS[1], LOW); digitalWrite(STOP_ANALOG_POWER_PINS[2], LOW);
+  }
+}
+#endif
+
+
 void setup()
 {
   Serial.begin(9600);           // set up Serial library at 9600 bps
   Serial.println("Star Tracker v0.01");
-
+
+#if STOP_TYPE == 0
   pinMode(STOP_BUTTON_PIN, INPUT_PULLUP);
+#endif
+
 #if STEPPER_DRIVER == 0
   AFMS.begin();  // create with the default frequency 1.6KHz
 #endif
@@ -50,18 +74,31 @@
 {
   Serial.println("goInitialPosition");
   delay(250);
+
+#if STOP_TYPE == 0
   int buttonV = digitalRead(STOP_BUTTON_PIN);
-  Serial.println(buttonV);
-  Serial.println(buttonV == STOP_BUTTON_TYPE);
   while (buttonV == STOP_BUTTON_TYPE)
+#else
+  stop_button_analog_power(true);
+  delay(100);
+  int buttonV = analogRead(STOP_BUTTON_PIN);
+  while (buttonV > STOP_ANALOG_POWER_STOP_VALUE)
+#endif
   {
     reset_lp();
+
+#if STOP_TYPE == 0
     buttonV = digitalRead(STOP_BUTTON_PIN);
+#else
+    buttonV = analogRead(STOP_BUTTON_PIN); //TODO: Does analog read greatly slow down reset
+#endif
   }
-  Serial.println(buttonV);
   reset_done();
   Astepper1.setSpeed(0);
   Astepper1.runSpeed();
+#if STOP_TYPE == 1
+  stop_button_analog_power(false);
+#endif
   Serial.println("At initial position");
   delay(250);
   Serial.println("goInitialPosition end");


loop logic changed

loop logic changed

--- client/RGB_control/RGB_control.ino
+++ client/RGB_control/RGB_control.ino
@@ -18,9 +18,8 @@
 #include "gammaTable.h"
 #include "config.h" //set your SSID and pass here

-
 #define DEBUG false //debug output
-String Version = "v0.0.2";
+String Version = "v0.1.0";

 const uint8_t r1Pin = D1,
               g1Pin = D2,
@@ -35,6 +34,7 @@
 int value = 0;
 String thisMAC = WiFi.macAddress();
 String clientID = "RGB_controller_" + thisMAC;
+bool otaInProgress = false;

 String domain = "RGB-LED-control";

@@ -46,12 +46,13 @@
 };
 const unsigned char subscriptions_length = sizeof(subscriptions)/sizeof(subscriptions[0]);

-int r1, g1, b1;
+
 unsigned long fadeRcvTime, lastFadePWMMillis=0;
 int curRGB[] = {0, 0, 0},
      wasRGB[3],
      toRGB[3];
 int fadeTime = 0;
+bool fadeActive = false;

 void registration()
 {
@@ -68,15 +69,15 @@
   //Serial.println(number);

   // Split them up into r, g, b values
-  r1 = number >> 16;
-  g1 = number >> 8 & 0xFF;
-  b1 = number & 0xFF;
+  int r1 = number >> 16;
+  int g1 = number >> 8 & 0xFF;
+  int b1 = number & 0xFF;
   curRGB[0] = r1;
   curRGB[1] = g1;
   curRGB[2] = b1;
 }

-int tmpLast = 0;
+
 void setParsedRGB()
 {
   //analogWrite(r1Pin, gamma8[curRGB[0]] * 4);
@@ -115,6 +116,13 @@
       }
       setParsedRGB();
     }
+  } else {
+    // finish fade by setting final toRGB
+    if (fadeActive) {
+      memcpy(curRGB, toRGB, sizeof(toRGB));
+      setParsedRGB();
+    }
+    fadeActive = false;
   }
 }

@@ -146,6 +154,7 @@
   else if (String(topic) == subscriptions[2])
   {
     parseFade(data);
+    fadeActive = true;
   }

   mqttClient.loop();
@@ -179,9 +188,7 @@
   Serial.println("Version " + Version);
 }

-
-
-void mqttTryReconnect() {
+bool mqttTryReconnect() {
   Serial.print("Attempting MQTT connection...");
   // Attempt to connect
   if (mqttClient.connect(clientID.c_str())) {
@@ -194,14 +201,16 @@
         Serial.println(subscriptions[i]);
       #endif
     }
+    return true;
   } else {
-    Serial.print("failed, rc=");
-    Serial.print(mqttClient.state());
-    Serial.println(" try again in 5 seconds");
-    // Wait 5 seconds before retrying
-    delay(5000);
-
-  }
+    return false;
+  }
+}
+
+void disableLights() {
+  analogWrite(r1Pin, gamma10[0]);
+  analogWrite(g1Pin, gamma10[0]);
+  analogWrite(b1Pin, gamma10[0]);
 }

 void setupOTA()
@@ -217,9 +226,12 @@

   ArduinoOTA.onStart([]() {
     Serial.println("[OTA] Start");
+    disableLights();
+    otaInProgress = true;
   });
   ArduinoOTA.onEnd([]() {
     Serial.println("\n[OTA] End");
+    otaInProgress = false;
   });
   ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
     Serial.printf("[OTA] Progress: %u%%\r", (progress / (total / 100)));
@@ -231,6 +243,7 @@
     else if (error == OTA_CONNECT_ERROR) Serial.println("[OTA] Connect Failed");
     else if (error == OTA_RECEIVE_ERROR) Serial.println("[OTA] Receive Failed");
     else if (error == OTA_END_ERROR) Serial.println("[OTA] End Failed");
+    otaInProgress = false;
   });
   ArduinoOTA.begin();
   Serial.println("[OTA] ready");
@@ -254,13 +267,20 @@
   registration();
 }

+unsigned int loopCounter = 1;

 void loop() {
   ArduinoOTA.handle();
-  while(!mqttClient.connected()) {
-    mqttTryReconnect();
-    ArduinoOTA.handle();
-  }
-  mqttClient.loop();
-  fadeLoop();
-}
+  if (!otaInProgress) {
+    if (mqttClient.connected()) {
+      mqttClient.loop();
+      fadeLoop();
+    } else {
+      delay(100);
+      loopCounter++;
+      if (loopCounter % 50 == 0) {
+        mqttTryReconnect();
+      }
+    }
+  }
+}


Button fix

Button fix

--- resilient-network.ino
+++ resilient-network.ino
@@ -127,7 +127,7 @@

 void loop() {
   if (isSource) {
-    if (!digitalRead(button1pin)) {
+    if (!digitalRead(button2pin)) {
       if(SERIAL_DEBUG) Serial.println("alert");
       char c = ALERT;
       for (int i=0; i<3; i++) bus[i]->write(c);


fix readsms

fix readsms

--- examples/GPRS_ReadSMS/GPRS_ReadSMS.ino
+++ examples/GPRS_ReadSMS/GPRS_ReadSMS.ino
@@ -1,17 +1,25 @@
 // библиотека для работы с GPRS устройством
 #include <GPRS_Shield_Arduino.h>

-// библиотека для эмуляции Serial порта
+// библиотека для эмуляции Serial-порта
 // она нужна для работы библиотеки GPRS_Shield_Arduino
 #include <SoftwareSerial.h>

-// номер на который будем отправлять сообщение
-#define PHONE_NUMBER  "+79263995140"
-// текст сообщения, которое будем отправлять
-#define MESSAGE  "Hello from GPRS Shield"
+// длина сообщения
+#define MESSAGE_LENGTH 160
+
+// номер сообщения в памяти сим-карты
+int messageIndex = 0;
+
+// текст сообщения
+char message[MESSAGE_LENGTH];
+// номер, с которого пришло сообщение
+char phone[16];
+// дата отправки сообщения
+char datetime[24];

 // создаём объект класса GPRS и передаём ему скорость 9600 бод
-// с помощью него будем давать команды GPRS шилду
+// с помощью него будем давать команды GPRS-шилду
 GPRS gprs(9600);

 void setup()
@@ -33,14 +41,34 @@
     delay(1000);
     Serial.print("Init error\r\n");
   }
-  // вывод об удачной инициализации GPRS Shield
+  // выводим сообщение об удачной инициализации GPRS Shield
   Serial.println("GPRS init success");
-  // сообщаем о написании и отправке СМС по указанному номеру
-  Serial.println("Start to send message ...");
-  // отправляем сообщение по указанному номеру с заданным текстом
-  gprs.sendSMS(PHONE_NUMBER, MESSAGE);
+  Serial.println("Please send SMS message to me!");
 }

 void loop()
 {
+  // проверяем наличие непрочитанных сообщений
+  // и находим их номер в памяти сим-карты
+  messageIndex = gprs.isSMSunread();
+  if (messageIndex > 0) {
+    // если есть хотя бы одно непрочитанное сообщение,
+    // читаем его
+    gprs.readSMS(messageIndex, message, MESSAGE_LENGTH, phone, datetime);
+
+    // Удаляем прочитанное сообщение из памяти Сим-карты
+    gprs.deleteSMS(messageIndex);
+
+    // выводим номер, с которого пришло смс
+    Serial.print("From number: ");
+    Serial.println(phone);
+
+    // выводим дату, когда пришло смс
+    Serial.print("Datetime: ");
+    Serial.println(datetime);
+
+    // выводим текст сообщения
+    Serial.print("Recieved Message: ");
+    Serial.println(message);
+  }
 }


Moved "int ReadingNumber=0" out loop to avoid constantly resetting to zero

--- VernierAnalogSensor/VernierAnalogSensor.ino
+++ VernierAnalogSensor/VernierAnalogSensor.ino
@@ -15,6 +15,7 @@
 float Intercept = -19.295;
 float Slope = 175.416;
 int TimeBetweenReadings = 500; // in ms
+int ReadingNumber=0;
 /////////////////////////////////////////
 void setup()
 {
@@ -39,7 +40,6 @@
   float Count;
 float Voltage;
 float SensorReading;
-int ReadingNumber=0;
 float Time;
 //the print below does the division first to avoid overflows
   Serial.print(ReadingNumber/1000.0*TimeBetweenReadings);


turn off DETAIL_TIMING

turn off DETAIL_TIMING

--- TICC/TICC.ino
+++ TICC/TICC.ino
@@ -9,7 +9,7 @@

 extern const char SW_VERSION[17] = "20170308.1";    // 8 March 2017 - version 1

-#define DETAIL_TIMING     // if enabled, prints execution time
+//#define DETAIL_TIMING     // if enabled, prints execution time

 #include <stdint.h>           // define unint16_t, uint32_t
 #include <SPI.h>              // SPI support


Add a couple of Leslie demo presets

Add a couple of Leslie demo presets

--- roto.ino
+++ roto.ino
@@ -146,6 +146,8 @@
     ALL_DRAWBARS,
     PERCUSSION,
     VIBRATO,
+    LESLIE,
+    LESLIE_FAST_GROWL,
 };

 void preset(int conf) {
@@ -175,14 +177,23 @@
         midiControl[CC_DRAWBAR_0 + 9] = 127;
         break;
     case PERCUSSION:
-	midiControl[CC_PERCUSSION] = 127;
-	midiControl[CC_PERCUSSION_THIRD] = 127;
-	break;
+        midiControl[CC_PERCUSSION] = 127;
+        midiControl[CC_PERCUSSION_THIRD] = 127;
+        break;
     case VIBRATO:
-	midiControl[CC_VIBRATO] = 127;
-	midiControl[CC_VIBRATO_MODE] = 127;
-	midiControl[CC_ROTARY_STOP] = 127;
-	break;
+        midiControl[CC_VIBRATO] = 127;
+        midiControl[CC_VIBRATO_MODE] = 127;
+        midiControl[CC_ROTARY_STOP] = 127;
+        break;
+    case LESLIE:
+        midiControl[CC_ROTARY_STOP] = 0;
+        midiControl[CC_ROTARY_SPEED] = 0;
+        break;
+    case LESLIE_FAST_GROWL:
+        midiControl[CC_ROTARY_STOP] = 0;
+        midiControl[CC_ROTARY_SPEED] = 127;
+        midiControl[CC_SPEAKER_DRIVE] = 127;
+        break;
     }

     updateLeslieAmplifier();
@@ -207,7 +218,7 @@
     vibrato.init();

     reset();
-    preset(VIBRATO);
+    preset(LESLIE_FAST_GROWL);

     swell.gain(1.0);

@@ -316,23 +327,23 @@
 }

 void updateVibrato() {
-    if (!midiControl[CC_VIBRATO]) {
-	vibrato.setMode(Off);
-    }
-
     uint8_t mode = midiControl[CC_VIBRATO_MODE];
     if (mode == 0) {
-	vibrato.setMode(V1);
+        vibrato.setMode(V1);
     } else if (mode <= 26) {
-	vibrato.setMode(C1);
+        vibrato.setMode(C1);
     } else if (mode <= 51) {
-	vibrato.setMode(V2);
+        vibrato.setMode(V2);
     } else if (mode <= 84) {
-	vibrato.setMode(C2);
+        vibrato.setMode(C2);
     } else if (mode <= 102) {
-	vibrato.setMode(V3);
+        vibrato.setMode(V3);
     } else if (mode <= 127) {
-	vibrato.setMode(C3);
+        vibrato.setMode(C3);
+    }
+
+    if (!midiControl[CC_VIBRATO]) {
+        vibrato.setMode(Off);
     }
 }


Added Delay

Added Delay

--- AudrinoCode/PressureSensorRead/PressureSensorRead.ino
+++ AudrinoCode/PressureSensorRead/PressureSensorRead.ino
@@ -24,13 +24,14 @@
     String row = "";
     for(int i = 0; i < 5; i++)
     {
-      row = row + sensorValues[i] + ",";
+      row = row + sensorValues[i] + ","; //creating a comma separated file
     }
     row = row + sensorValues[5] + "\n";
     char writeData[row.length()];
-    row.toCharArray(writeData, row.length());
+    row.toCharArray(writeData, row.length()); //conversion to char array
     data.write(writeData);
     data.close();
   }
+  delay(100); //wait 100ms

 }


Fix a compile error when HTML_PASSWORD_ENABLE is enabled. (#856)

Fixes #855

--- examples/IRMQTTServer/IRMQTTServer.ino
+++ examples/IRMQTTServer/IRMQTTServer.ino
@@ -1265,7 +1265,8 @@
 void handleReset(void) {
 #if HTML_PASSWORD_ENABLE
   if (!server.authenticate(HttpUsername, HttpPassword)) {
-    debug("Basic HTTP authentication failure for " + kUrlWipe);
+    debug(("Basic HTTP authentication failure for " +
+           String(kUrlWipe)).c_str());
     return server.requestAuthentication();
   }
 #endif
@@ -1294,7 +1295,8 @@
 void handleReboot() {
 #if HTML_PASSWORD_ENABLE
   if (!server.authenticate(HttpUsername, HttpPassword)) {
-    debug("Basic HTTP authentication failure for " + kUrlReboot);
+    debug(("Basic HTTP authentication failure for " +
+           String(kUrlReboot)).c_str());
     return server.requestAuthentication();
   }
 #endif


Allow SQW output frequency to be selected. Support MCP7941x calibration.

--- examples/RTCx_example/RTCx_example.ino
+++ examples/RTCx_example/RTCx_example.ino
@@ -1,5 +1,32 @@
 /*
-
+ * Demonstrate the RTCx library.
+ *
+ * This sketch demonstrates the basic functionality of the RTCx
+ * library. It can also be used to adjust and check the frequency
+ * calibration settings on MCP7941x devices.
+ *
+ * On start-up the autoprobe feature is used to search the I2C bus to
+ * find the first available real-time clock. The sketch indicates
+ * which clock type (if any) has been found. If the clock is an
+ * MCP7941x device the current calibration setting is printed.
+ *
+ * The clock can be set by writing the current unixtime (i.e., seconds
+ * since 1970-01-01 00:00:00Z) prefixed by the character 'T' to
+ * Serial. The string must be terminated by a NULL character, line
+ * feed, or carriage return. E.g., "T1343779200" sets the clock to
+ * 2012-08-01 00:00:00Z".
+ *
+ * The clock error, measured in seconds, can be found in a similar way
+ * by sending the current unix time, prefixed by the character 'C',
+ * e.g., "C1343779200".
+ *
+ * It is possible to set the SQW output frequency by sending "M0" (1Hz
+ * output), "M1" (4096Hz output), "M2" (8192Hz output) or "M3"
+ * (32768Hz output). If the clock is a MCP7941x device then sending
+ * "M4" will enable the calibration mode and output a 64Hz signal
+ * which is continously compensated with the frequency calibration
+ * setting, thereby enabling the correct calibration value to be
+ * found.
  */

 #include <Wire.h>
@@ -91,40 +118,12 @@
     printTm(Serial, &tm);
     Serial.print("unixtime = ");
     Serial.println(t);
-    /*
-    Serial.println("...............");
-    struct RTCx::tm tm2;
-    RTCx::time_t t2 = 1347750631;
-    Serial.print("unixtime = ");
-    Serial.println(t2);
-    RTCx::gmtime_r(&t2, &tm2);
-    printTm(Serial, &tm2);
-    RTCx::time_t t2a = RTCx::mktime(&tm2);
-    printTm(Serial, &tm2);
-    Serial.print("unixtime = ");
-    Serial.println(t2a);
-    Serial.println("...............");
-    */
-    /*
-    rtc.readClock(tm, RTCx::ALARM0);
-    printTm(Serial, &tm);
-    rtc.readClock(tm, RTCx::ALARM1);
-    printTm(Serial, &tm);
-    */
-
-    /*
-      rtc.readClock(tm, RTCx::TIME_POWER_FAILED);
-      printTm(Serial, &tm);
-      rtc.readClock(tm, RTCx::TIME_POWER_RESTORED);
-      printTm(Serial, &tm);
-    */
-
     Serial.println("-----");
   }

   while (Serial.available()) {
     char c = Serial.read();
-    if ((c == '\r' || c == '\n')) {
+    if ((c == '\r' || c == '\n' || c == '\0')) {
       if (bufPos <= bufLen && buffer[0] == 'C') {
 	// Check time error
 	buffer[bufPos] = '\0';
@@ -147,7 +146,44 @@
 	printTm(Serial, &tm);
 	Serial.println("~~~~~");
       }
-
+      if (bufPos <= bufLen && buffer[0] == 'X') {
+	// Set calibration value
+	buffer[bufPos] = '\0';
+	if (rtc.getDevice() == RTCx::MCP7941x) {
+	  int8_t oldCal = rtc.getCalibration();
+	  char *endptr;
+	  long cal = strtol(&(buffer[1]), &endptr, 0);
+	  if (cal >= -127 && cal <= 127 && endptr == &buffer[bufPos]) {
+	    Serial.print("Previous calibration: ");
+	    Serial.println(oldCal, DEC);
+	    Serial.print("Calibration: ");
+	    Serial.println(cal, DEC);
+	      rtc.setCalibration(cal);
+	  }
+	  else
+	    Serial.println("Bad value for calibration");
+	}
+	else {
+	  Serial.println("Cannot set calibration: not a MCP7941x");
+	}
+      }
+      if (bufPos <= bufLen && buffer[0] == 'M') {
+	// Set SQW mode
+	buffer[bufPos] = '\0';
+	  char *endptr;
+	  long mode = strtol(&(buffer[1]), &endptr, 0);
+	  if (mode >= RTCx::freq1Hz && mode <= RTCx::freqCalibration
+	      && endptr == &buffer[bufPos]) {
+	    if (rtc.setSQW((RTCx::freq_t)mode)) {
+	      Serial.print("SQW: ");
+	      Serial.println(mode, DEC);
+	    }
+	    else
+	      Serial.println("Could not set SQW");
+	  }
+	  else
+	    Serial.println("Bad value for SQW");
+      }
       bufPos = 0;
     }
     else if (bufPos < bufLen)


Simplifing the example code to illustrate scan() and gets().

--- examples/Sandbox/CosaUART/CosaUART.ino
+++ examples/Sandbox/CosaUART/CosaUART.ino
@@ -26,18 +26,24 @@
 #include "Cosa/Trace.hh"
 #include "Cosa/IOStream/Driver/UART.hh"

+void echo(uint16_t n, char* s)
+{
+  trace << Watchdog::millis() << ':' << n << ':';
+  trace << PSTR("echo('") << s << PSTR("')") << endl;
+}
+
 void setup()
 {
   // Start the UART and Watchdog
   uart.begin(9600);
-  trace.begin(&uart, PSTR("CosaUART: started"));
+  trace.begin(&uart, PSTR("CosaUART: started (LINE MODE)"));
   Watchdog::begin();
 }

 void loop()
 {
   // Count the number of wake-ups
-  static uint32_t n = 0;
+  static uint16_t n = 0;
   static bool is_scan_mode = false;

   // Sleep and wait for something to happen
@@ -51,29 +57,25 @@
   if (is_scan_mode) {
     // Scan tokens until new-line
     if (trace.scan(s, sizeof(s)) && *s == '\n') return;
-    trace << Watchdog::millis() << ':' << n << ':';
-    trace << PSTR("echo('") << s << PSTR("')") << endl;
+    echo(n, s);
     // Check for mode change command
     if (strcmp_P(s, PSTR("LINE")) == 0) {
       if (trace.scan(s, sizeof(s)) && *s == '\n') {
+	trace << PSTR("LINE MODE") << endl;
 	is_scan_mode = false;
 	return;
       }
-      trace << Watchdog::millis() << ':' << n << ':';
-      trace << PSTR("echo('") << s << PSTR("')") << endl;
+      echo(n, s);
     }
-    while (trace.scan(s, sizeof(s)) && *s != '\n') {
-      trace << Watchdog::millis() << ':' << n << ':';
-      trace << PSTR("echo('") << s << PSTR("')") << endl;
-    }
+    while (trace.scan(s, sizeof(s)) && *s != '\n') echo(n, s);
   }
   else {
     // Scan the line. Skip empty lines
     if (uart.gets(s, sizeof(s)) == NULL) return;
-    trace << Watchdog::millis() << ':' << n << ':';
-    trace << PSTR("echo('") << s << PSTR("')") << endl;
+    echo(n, s);

     // Check for mode change command
     is_scan_mode = strcmp_P(s, PSTR("SCAN")) == 0;
+    if (is_scan_mode) trace << PSTR("SCAN MODE") << endl;
   }
 }


Added 1/32 scan support

Added 1/32 scan support

--- game/game.ino
+++ game/game.ino
@@ -31,6 +31,8 @@
 #define B   A1
 #define C   A2
 #define D   A3
+// 5-bit address bus support
+//#define E   A5

 // Button input
 #define CLOCK 11
@@ -39,6 +41,18 @@
 #define DATA A4
 #define BUTTONS 16 // total buttons

+#ifdef E
+#define ADDR_LOW    0x1f
+#define ADDR_HIGH   0xe0
+#define ADDR_SHIFT  1
+#define BUF_LINES   2
+#else
+#define ADDR_LOW    0xf
+#define ADDR_HIGH   0xf0
+#define ADDR_SHIFT  2
+#define BUF_LINES   4
+#endif
+
 static uint16_t buttons; // buttons currently pressed

 #define DATAPORT PORTD
@@ -63,9 +77,15 @@

 static volatile uint8_t
     *latport, *oeport, *addraport, *addrbport, *addrcport, *addrdport,
+#ifdef E
+    *addreport,
+#endif
     *clockport, *latchbport, *latchjport, *dataport;
 static uint8_t
     sclkpin, latpin, oepin, addrapin, addrbpin, addrcpin, addrdpin,
+#ifdef E
+    addrepin,
+#endif
     clockpin, latchbpin, latchjpin, datapin;

 void game_set_ups(int ups)
@@ -92,6 +112,10 @@
     addrcpin  = digitalPinToBitMask(C);
     addrdport = portOutputRegister(digitalPinToPort(D));
     addrdpin  = digitalPinToBitMask(D);
+#ifdef E
+    addreport = portOutputRegister(digitalPinToPort(E));
+    addrepin  = digitalPinToBitMask(E);
+#endif

     clockport = portOutputRegister(digitalPinToPort(CLOCK));
     clockpin  = digitalPinToBitMask(CLOCK);
@@ -109,6 +133,9 @@
     pinMode(B, OUTPUT);
     pinMode(C, OUTPUT);
     pinMode(D, OUTPUT);
+#ifdef E
+    pinMode(E, OUTPUT);
+#endif

     pinMode(IR1, OUTPUT);
     pinMode(IG1, OUTPUT);
@@ -129,6 +156,9 @@
     *addrbport &= ~addrbpin;
     *addrcport &= ~addrcpin;
     *addrdport &= ~addrdpin;
+#ifdef E
+    *addreport &= ~addrepin;
+#endif

     digitalWrite(IR1, HIGH);
     digitalWrite(IG1, HIGH);
@@ -196,7 +226,7 @@
         {
             if (spr & mask)
             {
-                game_render_buf[xx + ((ry & 0xf0) << 2)] = color;
+                game_render_buf[xx + ((ry & ADDR_HIGH) << ADDR_SHIFT)] = color;
             }
         }
         mask >>= 1;
@@ -212,8 +242,8 @@
 void game_draw_sprite(const struct game_sprite *s, int x, int y, uint8_t color)
 {
     uint8_t height = game_sprite_height(s);
-    uint8_t ry = game_render_y + (y & 0xf0);
-    if (ry < y) ry += 0x10;
+    uint8_t ry = game_render_y + (y & ADDR_HIGH);
+    if (ry < y) ry += ADDR_LOW + 1;
     if (ry >= HEIGHT) return;
     if (ry < (y + height))
     {
@@ -225,15 +255,15 @@
 {
     if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT)
         return;
-    if (game_render_y == (y & 0xf))
-    {
-        game_render_buf[x + ((y & 0xf0) << 2)] = game_make_color(color);
+    if (game_render_y == (y & ADDR_LOW))
+    {
+        game_render_buf[x + ((y & ADDR_HIGH) << ADDR_SHIFT)] = game_make_color(color);
     }
 }

 void game_draw_text(const uint8_t *s, int x, int y, uint8_t color)
 {
-    if (game_render_y < (y & 0xf) || game_render_y >= (y & 0xf) + FONT_HEIGHT)
+    if (game_render_y < (y & ADDR_LOW) || game_render_y >= (y & ADDR_LOW) + FONT_HEIGHT)
         return;
     for (const uint8_t *c = s; *c; ++c)
     {
@@ -244,15 +274,15 @@

 void game_draw_char(uint8_t c, int x, int y, uint8_t color)
 {
-    if (game_render_y < (y & 0xf) || game_render_y >= (y & 0xf) + FONT_HEIGHT)
+    if (game_render_y < (y & ADDR_LOW) || game_render_y >= (y & ADDR_LOW) + FONT_HEIGHT)
         return;
-    int pos = (int)c * FONT_HEIGHT + (game_render_y - (y & 0xf));
+    int pos = (int)c * FONT_HEIGHT + (game_render_y - (y & ADDR_LOW));
     uint8_t d = pgm_read_byte_near(font_data + pos);
     for (int i = 0; i < FONT_WIDTH; ++i)
     {
         if ((d >> (FONT_WIDTH - 1 - i)) & 1)
         {
-            game_render_buf[x + i + ((y & 0xf0) << 2)] = game_make_color(color);
+            game_render_buf[x + i + ((y & ADDR_HIGH) << ADDR_SHIFT)] = game_make_color(color);
         }
     }
 }
@@ -269,7 +299,7 @@

 void game_render_line(uint8_t *buf, int y)
 {
-    for (int i = 0; i < WIDTH * 4; ++i)
+    for (int i = 0; i < WIDTH * BUF_LINES; ++i)
         buf[i] = 0;

     game_render_buf = buf;
@@ -277,9 +307,10 @@

     // call user render()
     render();
-
+#ifndef E
     if (y == WIDTH / 4 - 1) // fix broken led
         buf[WIDTH * 4 - 1] = 0;
+#endif
 }

 void setup()
@@ -294,11 +325,11 @@
     tock = SCLKPORT;
     tick = tock & ~sclkpin;

-    uint8_t lines[4 * WIDTH];
+    uint8_t lines[BUF_LINES * WIDTH];
     game_render_line((uint8_t*)lines, step);

-    uint8_t *line1 = &lines[3 * WIDTH];
-    uint8_t *line2 = &lines[2 * WIDTH];
+    uint8_t *line1 = &lines[(BUF_LINES - 1) * WIDTH];
+    uint8_t *line2 = &lines[(BUF_LINES - 2) * WIDTH];
     uint8_t const8 = 8;
     uint8_t const4 = 4;
     uint8_t tmp;
@@ -329,7 +360,7 @@
     pew pew pew pew pew pew pew pew
     pew pew pew pew pew pew pew pew
     pew pew pew pew pew pew pew pew
-
+#ifdef E
     line1 = &lines[1 * WIDTH];
     line2 = &lines[0 * WIDTH];

@@ -341,7 +372,7 @@
     pew pew pew pew pew pew pew pew
     pew pew pew pew pew pew pew pew
     pew pew pew pew pew pew pew pew
-
+#endif
     *oeport |= oepin;

     if (step & 1)
@@ -360,6 +391,12 @@
         *addrdport |= addrdpin;
     else
         *addrdport &= ~addrdpin;
+#ifdef E
+    if (step & 16)
+        *addreport |= addrepin;
+    else
+        *addreport &= ~addrepin;
+#endif

     *latport |= latpin;
     *latport &= ~latpin;
@@ -391,7 +428,7 @@
         last_update = cur_time;
     }

-    step = (step + 1) & 0xf;
+    step = (step + 1) & ADDR_LOW;
     #if defined(COLOR_6BIT) && COLOR_6BIT
     if (step == 0)
         color_channel = (color_channel + 1) % 3;


Reverse initial states

Reverse initial states

--- teensy/teensy.ino
+++ teensy/teensy.ino
@@ -45,14 +45,14 @@

 int arglen[256] = {};

-#define TRAY_OPEN 0
-#define TRAY_CLOSED 1
-
-#define LOADER_REST 0
-#define LOADER_ACTIVE 1
-
-#define EJECTOR_OFF 0
-#define EJECTOR_ON 1
+#define TRAY_OPEN 1
+#define TRAY_CLOSED 0
+
+#define LOADER_REST 1
+#define LOADER_ACTIVE 0
+
+#define EJECTOR_OFF 1
+#define EJECTOR_ON 0

 int mug_index = 0;
 int tray_state = 2;
@@ -239,6 +239,12 @@
   pinMode(PIN_KCUP_LOADER, OUTPUT);
   pinMode(PIN_KCUP_EJECTOR, OUTPUT);
   pinMode(PIN_TRAY_PISTON, OUTPUT);
+  pinMode(PIN_BREW_BUTTON, OUTPUT);
+
+  digitalWriteFast(PIN_KCUP_LOADER, LOADER_REST);
+  digitalWriteFast(PIN_KCUP_EJECTOR, EJECTOR_OFF);
+  digitalWriteFast(PIN_TRAY_PISTON, TRAY_CLOSED);
+  digitalWriteFast(PIN_BREW_BUTTON, 1);

   Serial.begin(9600);


Migrated code from dev device to display case.

Signed-off-by: Braden Licastro <79d6010d7e15bbb3aa5be04af4e1cdfb0e9c5bfd@live.com>

--- sketches/LRDisplayCase/LRDisplayCase.ino
+++ sketches/LRDisplayCase/LRDisplayCase.ino
@@ -1,114 +1,127 @@
 /*
-  Configuration for Home Assistant:
-    mqtt:
-      broker: <REDACTED>
-      port: 1883
-      client_id: 'ha'
-      username: 'ha'
-      password: '<REDACTED>'
-
-    light:
-    # Interior: Living Room Display Case
-    - platform: mqtt
-      name: 'Living Room Display Case'
-      state_topic: 'firstfloor/lrdisplaycase1/status'
-      command_topic: 'firstfloor/lrdisplaycase1/switch'
-      optimistic: false
-
-  Sources:
-    - MQTT: File > Examples > PubSubClient > mqtt_esp8266
-    - TLS:  https://io.adafruit.com/blog/security/2016/07/05/adafruit-io-security-esp8266/
-    - OTA:  File > Examples > ArduinoOTA > BasicOTA
-*/
+ * Software Revision: 2.1
+ *
+ * Configuration for Home Assistant:
+ *   light:
+ *   # Interior: Living Room Display Case
+ *   - platform: mqtt
+ *     name: 'Living Room Display Case'
+ *     state_topic: 'firstfloor/lrdisplaycase1/status'
+ *     command_topic: 'firstfloor/lrdisplaycase1/switch'
+ *     optimistic: false
+ */

 #include <ESP8266WiFi.h>    // https://github.com/esp8266/Arduino (GNUv2.1 licence)
 #include <PubSubClient.h>   // https://github.com/knolleary/pubsubclient (no licence)
+#include <ESP8266HTTPClient.h>
+#include <ESP8266httpUpdate.h>

 #define DEBUG
 #define MQTT_VERSION MQTT_VERSION_3_1_1

-// Wi-Fi: Access Point SSID and password
+// ESP8266: SSID and password of desired network
 const char*       AP_SSID           = "<REDACTED>";
 const char*       AP_PASSWORD       = "<REDACTED>";

-// MQTT: client ID, broker IP address, port, username & password
-const char*       MQTT_CLIENT_ID    = "<REDACTED>";
-const char*       MQTT_SERVER_IP    = "<REDACTED>";
-const uint16_t    MQTT_SERVER_PORT  = 1883;
-const char*       MQTT_USERNAME     = "<REDACTED>";
-const char*       MQTT_PASSWORD     = "<REDACTED>";
-
-// MQTT: topics
-
-// Living Room Side Lamp
-const char*       TOPIC_RELAY_STATUS             = "firstfloor/lrdisplaycase1/status";
-const char*       TOPIC_RELAY_COMMAND            = "firstfloor/lrdisplaycase1/switch";
-
-// MQTT: payloads
-// Lamps : "ON"/"OFF"
-const char*       PAYLOAD_ON            = "ON";
-const char*       PAYLOAD_OFF           = "OFF";
-
-boolean           g_relay_status       = false;
-
-// buffer used to send/receive data with MQTT
-const uint8_t     MSG_BUFFER_SIZE       = 20;
-char              g_msg_buffer[MSG_BUFFER_SIZE];
-
-const uint8_t     RELAY_PIN       = D1;
-
-// Fixed IP address: IP address, IP gateway, subnet, dns
+// Device network details: IP address, IP gateway, subnet, dns.
+// NOTE: WiFi does not support configurable MAC
 const IPAddress   IP                (<REDACTED>);
 const IPAddress   IP_GATEWAY        (<REDACTED>);
 const IPAddress   IP_SUBNET         (<REDACTED>);
 const IPAddress   IP_DNS            (<REDACTED>);

-// WiFi and MQTT client setup
-WiFiClient  g_wifiClient;
+// MQTT: client ID, broker IP, port, username & password
+const char*       MQTT_CLIENT_ID    = "<REDACTED>";
+const char*       MQTT_SERVER_IP    = "<REDACTED>";
+const uint8_t     MQTT_SERVER_PORT  = 1883;
+const char*       MQTT_USERNAME     = "<REDACTED>";
+const char*       MQTT_PASSWORD     = "<REDACTED>";
+
+// OTA Information
+const char*       OTA_SERVER_IP      = "<REDACTED>";
+const uint8_t     OTA_PORT           = 80;
+
+// MQTT: topics
+// Interior: Living Room Display Case
+const char*       TOPIC_RELAY_STATUS             = "firstfloor/lrdisplaycase1/status";
+const char*       TOPIC_RELAY_COMMAND            = "firstfloor/lrdisplaycase1/switch";
+
+// MQTT: Expected Payloads
+// Lamps : "ON"/"OFF"
+const char*       PAYLOAD_ON        = "ON";
+const char*       PAYLOAD_OFF       = "OFF";
+
+// Track current status of the devices
+boolean           g_relay_status                 = false;
+uint8_t           g_bypass_activated             = 0;
+boolean           g_bypass_hold                  = false;
+boolean           g_bypass_type                  = true; // True = switch; False = button
+
+// Buffer configuration used to send/receive data with MQTT
+const uint8_t     MSG_BUFFER_SIZE   = 20;
+char              g_msg_buffer[MSG_BUFFER_SIZE];
+
+// Pin configuration
+const uint8_t     RELAY_PIN         = D1;
+const uint8_t     BYPASS_PIN        = D2;
+
+// WiFi and MQTT client object initialization
+WiFiClient        g_wifiClient;
 PubSubClient      g_mqttClient(g_wifiClient);

-///////////////////////////////////////////////////////////////////////////
-//
-// RELAY
-//
-///////////////////////////////////////////////////////////////////////////
-
-/*
-  Function called to publish the status of the relay
-*/
+// Other event handling
+const uint8_t       DEBOUNCE_DELAY    = 200; // Delay in MS is .2 sec
+unsigned long       DEBOUNCE_TIME     = 0;
+const unsigned long UPDATE_DELAY      = 300000; // Delay in MS is 5 mins
+unsigned long       UPDATE_TIME       = 0;
+
+
+//############################################################################
+//
+//                          CONTROL AND STATUS
+//
+//############################################################################
+
+/*
+ * Publishes the status of the relay
+ *   INPUT:  NA
+ *   RETURN: NA
+ */
 void publishRelayStatus() {
   if (g_relay_status) {
     if (g_mqttClient.publish(TOPIC_RELAY_STATUS, PAYLOAD_ON, true)) {
-#ifdef DEBUG
-      Serial.print(F("INFO: MQTT message publish succeeded. Topic: "));
-      Serial.print(TOPIC_RELAY_STATUS);
-      Serial.print(F(". Payload: "));
-      Serial.println(PAYLOAD_ON);
-#endif
+      #ifdef DEBUG
+        Serial.print(F("INFO:  MQTT message publish succeeded.\n       Topic: "));
+        Serial.println(TOPIC_RELAY_STATUS);
+        Serial.print(F("       Payload: "));
+        Serial.println(PAYLOAD_ON);
+      #endif
     } else {
-#ifdef DEBUG
-      Serial.println(F("ERROR: MQTT message publish failed, either connection lost, or message too large"));
-#endif
+      #ifdef DEBUG
+            Serial.println(F("ERROR: MQTT message publish failed, either connection lost, or message too large"));
+      #endif
     }
   } else {
     if (g_mqttClient.publish(TOPIC_RELAY_STATUS, PAYLOAD_OFF, true)) {
-#ifdef DEBUG
-      Serial.print(F("INFO: MQTT message publish succeeded. Topic: "));
-      Serial.print(TOPIC_RELAY_STATUS);
-      Serial.print(F(". Payload: "));
-      Serial.println(PAYLOAD_OFF);
-#endif
+      #ifdef DEBUG
+        Serial.print(F("INFO:  MQTT message publish succeeded.\n       Topic: "));
+        Serial.println(TOPIC_RELAY_STATUS);
+        Serial.print(F("       Payload: "));
+        Serial.println(PAYLOAD_OFF);
+      #endif
     } else {
-#ifdef DEBUG
-      Serial.println(F("ERROR: MQTT message publish failed, either connection lost, or message too large"));
-#endif
-    }
-  }
-}
-
-/*
-  Function called to switch the status of the relay
-*/
+      #ifdef DEBUG
+        Serial.println(F("ERROR: MQTT message publish failed, either connection lost, or message too large"));
+      #endif
+    }
+  }
+}
+
+/*
+ * Switches the state of the relay
+ *   INPUT:  NA
+ *   RETURN: NA
+ */
 void setRelayStatus() {
   if (g_relay_status) {
     digitalWrite(RELAY_PIN, HIGH);
@@ -117,68 +130,75 @@
   }
 }

-///////////////////////////////////////////////////////////////////////////
-//
-// WIFI
-//
-///////////////////////////////////////////////////////////////////////////
-
-/*
-   Function called to setup the connection to the Wi-Fi Access Point
+
+//############################################################################
+//
+//                          WIFI CONFIGURATION
+//
+//############################################################################
+
+/*
+ * Set up the connection to the Access Point
+ *   INPUT:  NA
+ *   RETURN: NA
 */
 void setupWifi() {
   delay(10);
-  // attempt to connect to the Wi-Fi AP
-  WiFi.mode(WIFI_STA);
+  WiFi.mode(WIFI_STA); // Station mode. This is a client.
   WiFi.begin(AP_SSID, AP_PASSWORD);
-  // define the fixed IP address
-  WiFi.config(IP, IP_GATEWAY, IP_SUBNET, IP_DNS);
-
+  WiFi.config(IP, IP_GATEWAY, IP_SUBNET, IP_DNS); // MAC address configuration only supported for ethernet devices.
+
+  // Hold until wireless connection is up and running.
   while (WiFi.status() != WL_CONNECTED) {
     delay(500);
   }

-#ifdef DEBUG
-  Serial.println(F("INFO: Client is now connected to the Wi-Fi AP"));
-  Serial.print(F("INFO: IP address: "));
-  Serial.println(WiFi.localIP());
-  Serial.print("INFO:MAC Address:");
-  Serial.println(WiFi.macAddress());
-#endif
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// MQTT
-//
-///////////////////////////////////////////////////////////////////////////
-
-/*
-   Function called when a MQTT message arrived
-   @param p_topic   The topic of the MQTT message
-   @param p_payload The payload of the MQTT message
-   @param p_length  The length of the payload
-*/
+  #ifdef DEBUG
+    Serial.println(F("INFO:  Client is now connected to the wireless network!"));
+    Serial.print(F("       IP address:  "));
+    Serial.println(WiFi.localIP());
+    Serial.print(F("       MAC Address: "));
+    Serial.println(WiFi.macAddress());
+  #endif
+}
+
+
+//############################################################################
+//
+//                                MQTT
+//
+//############################################################################
+
+/*
+ * Function called when a MQTT message arrives
+ *   INPUT:  Charanter array 'p_topic' is the topic of the MQTT message
+ *           Byte array 'p_payload' is the payload of the MQTT message
+ *           Integer 'p_length' is the expectedlength of the payload
+ *   RETURN: NA
+ */
 void callback(char* p_topic, byte* p_payload, unsigned int p_length) {
-#ifdef DEBUG
-  Serial.println(F("INFO: A new MQTT message arrived"));
-  Serial.print(F("INFO: Topic: "));
-  Serial.println(p_topic);
-  Serial.print(F("INFO: Payload: "));
-  for (int i = 0; i < p_length; i++) {
-    Serial.print((char)p_payload[i]);
-  }
-  Serial.println();
-  Serial.print(F("INFO: Length: "));
-  Serial.println(p_length);
-#endif
-  // handle the MQTT topic of the received message
-  if (String(TOPIC_RELAY_COMMAND).equals(p_topic)) {
-    // concat the payload into a string
+  #ifdef DEBUG
+    Serial.println(F("INFO:  A new MQTT message has arrived"));
+    Serial.print(F("       Topic:   "));
+    Serial.println(p_topic);
+    Serial.print(F("       Payload: "));
+    for (int i = 0; i < p_length; i++) {
+      Serial.print((char)p_payload[i]);
+    }
+    Serial.println();
+    Serial.print(F("       Length:  "));
+    Serial.println(p_length);
+  #endif
+
+  // Act on the contents of the payload IF manual bypass isn't triggered for the given event.
+  if (String(TOPIC_RELAY_COMMAND).equals(p_topic) && !g_bypass_hold) {
+    // Type juggle the payload from char array to string.
     String payload;
     for (uint8_t i = 0; i < p_length; i++) {
       payload.concat((char)p_payload[i]);
     }
+
+    // Perform payload action.
     if (payload.equals(String(PAYLOAD_ON))) {
       g_relay_status = true;
       setRelayStatus();
@@ -188,96 +208,190 @@
       setRelayStatus();
       publishRelayStatus();
     } else {
-#ifdef DEBUG
-      Serial.println(F("ERROR: The payload of the MQTT message is not valid"));
-#endif
-    }
+      #ifdef DEBUG
+        Serial.println(F("ERROR: The payload of the MQTT message is not valid"));
+      #endif
+    }
+  } else if (g_bypass_hold) {
+    publishRelayStatus();
+    #ifdef DEBUG
+      Serial.println(F("INFO:  Bypass set, aborting requested action."));
+    #endif
   } else {
-    // do nothing.....
-#ifdef DEBUG
-    Serial.println(F("INFO: The received MQTT message was not used"));
-#endif
-  }
-}
-
-/*
-   Function called to reconnect the client to the MQTT broker and publish/subscribe to/from some MQTT topics
-*/
+    #ifdef DEBUG
+      Serial.println(F("INFO:  The received MQTT message was for a topic we did not subscribe to and was not used."));
+    #endif
+  }
+}
+
+/*
+ * Function called to reconnect the client to the MQTT broker and publish/subscribe to/from some MQTT topics
+ *   INPUT:  NA
+ *   Return: NA
+ */
 void reconnect() {
   while (!g_mqttClient.connected()) {
     if (g_mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {
-#ifdef DEBUG
-      Serial.println(F("INFO: The client is successfully connected to the MQTT broker"));
-#endif
-
-      // subscribe to the relay command topic
+      #ifdef DEBUG
+        Serial.println(F("INFO:  The client is successfully connected to the MQTT broker"));
+      #endif
+
+      // Subscribe to the command topic.
       if (g_mqttClient.subscribe(TOPIC_RELAY_COMMAND)) {
-#ifdef DEBUG
-        Serial.print(F("INFO: Sending the MQTT subscribe succeeded. Topic: "));
-        Serial.println(TOPIC_RELAY_COMMAND);
-#endif
+        #ifdef DEBUG
+          Serial.print(F("INFO:  Sending the MQTT subscribe succeeded.\n       Topic: "));
+          Serial.println(TOPIC_RELAY_COMMAND);
+        #endif
       } else {
-#ifdef DEBUG
-        Serial.print(F("ERROR: Sending the MQTT subscribe failed. Topic: "));
-        Serial.println(TOPIC_RELAY_COMMAND);
-#endif
+        #ifdef DEBUG
+          Serial.print(F("ERROR: Sending the MQTT subscribe failed.\n       Topic: "));
+          Serial.println(TOPIC_RELAY_COMMAND);
+        #endif
       }

-      // set the initial status of the relay
+      // Set the relay to match the value that we have stored.
       setRelayStatus();

-      // publish the initial status of the relay
+      // Publish the status of the relay to bring everything back into sync.
       publishRelayStatus();
     } else {
-#ifdef DEBUG
-      Serial.println(F("ERROR: The connection failed with the MQTT broker"));
-      Serial.print("ERROR: rc: ");
-      Serial.println(g_mqttClient.state());
-      // wait 5 seconds before retrying
-      delay(5000);
-#endif
-    }
-  }
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// SETUP and LOOP
-//
-///////////////////////////////////////////////////////////////////////////
-
-/*
-   Function called once to initialize the board
-*/
+      #ifdef DEBUG
+        Serial.print(F("ERROR: The connection failed with the MQTT broker.\n       Status: "));
+        Serial.println(g_mqttClient.state());
+      #endif
+
+      // Wait before retrying instead of clobbering the server.
+      delay(1000);
+    }
+  }
+}
+
+
+//############################################################################
+//
+//                              OTA Updates
+//
+//############################################################################
+
+/*
+ * Function called to check for updates from the binary server
+ *   INPUT:  NA
+ *   Return: NA
+ */
+void checkForUpdates() {
+  #ifdef DEBUG
+    Serial.println(F("INFO:  OTA update check beginning..."));
+  #endif
+
+  // Make the server side call and hold onto the HTTP return status
+  t_httpUpdate_return state = ESPhttpUpdate.update(OTA_SERVER_IP, OTA_PORT, "/updater.php");
+
+  // Do something based on the response from the server
+  #ifdef DEBUG
+    switch (state) {
+      case HTTP_UPDATE_FAILED:
+        Serial.println(F("ERROR: OTA update failed."));
+        break;
+      case HTTP_UPDATE_NO_UPDATES:
+        Serial.println(F("INFO:  OTA update not available. Already running latest version."));
+        break;
+      case HTTP_UPDATE_OK:
+        Serial.println(F("INFO:  OTA update succeeded."));
+        break;
+    }
+  #endif
+}
+
+
+//############################################################################
+//
+//                            SETUP and LOOP
+//
+//############################################################################
+
+/*
+ * System initialization
+ */
 void setup() {
-#ifdef DEBUG
-  Serial.begin(115200);
-  Serial.println(F("\nINFO: The Wi-Fi module is starting..."));
-#endif
-
-  // init the relay pin as output
-  pinMode(RELAY_PIN,         OUTPUT);
-
+  #ifdef DEBUG
+    Serial.begin(115200);
+    Serial.println(F("\nINFO:  Wireless network initializing..."));
+  #endif
+
+  // Connect to network.
   setupWifi();
-
-  // set the MQTT broker IP address and port
+
+  // Set IO pins for use.
+  pinMode(RELAY_PIN, OUTPUT);
+  pinMode(BYPASS_PIN, INPUT);
+
+  // Configure and connect to MQTT broker.
   g_mqttClient.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);
-  // set the MQTT callback function
   g_mqttClient.setCallback(callback);
 }

 /*
-   Function called infinitely after the setup function
-*/
+ * System run
+ */
 void loop() {
-  // keep the MQTT client connected to the broker
-  if (!g_mqttClient.connected()) {
+  // Ensure connection to MQTT broker is active, if not fix it.
+  if (WiFi.status() != WL_CONNECTED) {
+    setupWifi();
+  }else if (!g_mqttClient.connected()) {
     reconnect();
   }
+
+  // Listen for messages from the broker.
   g_mqttClient.loop();
-
-  // a delay is necessary if the debug is disabled
-  // without a delay, there is some latency to switch on/off a relay
-  yield();
-  //delay(100);
+
+
+  // Prevent bouncing when performing actions following a read.
+  if (millis() - DEBOUNCE_TIME >= DEBOUNCE_DELAY) {
+    if(g_bypass_activated != digitalRead(BYPASS_PIN)) {
+      //Read in the new state change.
+      g_bypass_activated = digitalRead(BYPASS_PIN);
+
+      // Perform the requested action
+      if (g_relay_status == false && g_bypass_activated == HIGH) {
+        #ifdef DEBUG
+          Serial.println("INFO:  Bypass state switched from OFF to ON.");
+        #endif
+        g_relay_status = true;
+        // Hold state if switch; prevents MQTT from overriding physical user.
+        if(g_bypass_type) {
+          g_bypass_hold = true;
+        }
+        setRelayStatus();
+        publishRelayStatus();
+      } else if (g_relay_status == true && g_bypass_activated == LOW) {
+        #ifdef DEBUG
+          Serial.println("INFO:  Bypass state switched from ON to OFF");
+        #endif
+        g_relay_status = false;
+        // Release state if switch; prevents MQTT from overriding physical user.
+        if(g_bypass_type) {
+          g_bypass_hold = false;
+        }
+        setRelayStatus();
+        publishRelayStatus();
+      } else {
+        #ifdef DEBUG
+          Serial.println("INFO:  Requested bypass state matches current state.");
+        #endif
+        // Publish status anyway to prevent client hangs.
+        publishRelayStatus();
+      }
+    }
+    // Set the last time of button press.
+    DEBOUNCE_TIME = millis();
+  }
+
+  // Check for code updates at a throttled pace.
+  if (millis() - UPDATE_TIME >= UPDATE_DELAY) {
+    //Check for update.
+    checkForUpdates();
+
+    // Set the last time of update check.
+    UPDATE_TIME = millis();
+  }
 }


changed the fucking ints to floats that were making the car drive like a fucking drunk fuck tard

--- arduino/car_control/src/main_control_nano/main_control_nano.ino
+++ arduino/car_control/src/main_control_nano/main_control_nano.ino
@@ -320,11 +320,11 @@

 //commander callbacks
 void on_cmd_steer(void){
-    if(!manual_mode) set_steer_angle(commander.readBinArg<int>());
+    if(!manual_mode) set_steer_angle(commander.readBinArg<float>());
 }

 void on_cmd_throttle(void){
-    if(!manual_mode) set_throttle_position(commander.readBinArg<int>());
+    if(!manual_mode) set_throttle_position(commander.readBinArg<float>());
 }

 void on_cmd_toggle_ebrake(void){


Missed a corner case -_- resin height gets set now

--- peachyLifter/peachyLifter.ino
+++ peachyLifter/peachyLifter.ino
@@ -174,6 +174,7 @@
   analog_result = analogRead(HEIGHT_ANALOG_PIN);
 	g_resin_height = (0-(int32_t)analog_result*ANALOG_SCALER);
 	g_layer_float = g_resin_height;
+	g_PrintState.setResinHeight(g_resin_height);
   g_Stepper.moveTo(g_resin_height); //0 minus so that we travel DOWN to absolute positions, relative to 0
 	g_PrintState.start(0); //Start over
 }


Line function changed to .run

Line function changed to .run

--- arrowprint_firmware/arrowprint_firmware.ino
+++ arrowprint_firmware/arrowprint_firmware.ino
@@ -25,7 +25,7 @@
 //physical movement scale (bigger == more);
 double tablexsteps    = 13000;
 double tableysteps    = 13000;
-double tablezsteps    = 210000;    //257142 (100mm) from top (STEPS FROM TABLE SURFACE TO TOP) 0,0,0 is FAR LEFT BOTTOM
+double tablezsteps    = 100000;    //257142 (100mm) from top (STEPS FROM TABLE SURFACE TO TOP) 0,0,0 is FAR LEFT BOTTOM
 double tableesteps  = -3600;

 //measured (1000 = 1mm)
@@ -35,8 +35,8 @@
 double tableedistance = 1000;    //in microns (96mm)

 double maxmotorSpeed = 12600;
-double motorSpeed = 9600;                                           //default 9600
-double motorAccel = 80000; //steps/second/second to accelerate      //default 80000
+double motorSpeed = 12600;                                           //default 9600
+double motorAccel = 160000; //steps/second/second to accelerate      //default 80000

 // Motor pins
 int motorpinXstep = 7;
@@ -88,6 +88,15 @@
   stepper2.setMaxSpeed(maxmotorSpeed);
   stepper4.setMaxSpeed(maxmotorSpeed);
   stepper5.setMaxSpeed(maxmotorSpeed);
+
+  stepper1.setSpeed(motorSpeed);
+  stepper2.setSpeed(motorSpeed);
+  stepper4.setSpeed(motorSpeed);
+  stepper5.setSpeed(motorSpeed);
+  stepper1.setAcceleration(motorAccel);
+  stepper2.setAcceleration(motorAccel);
+  stepper4.setAcceleration(motorAccel);
+  stepper5.setAcceleration(motorAccel);

   zeroaxis();                                //ZERO AXIS

@@ -144,8 +153,8 @@

 ///////////////////////////////////////////////////////ZERO X OVERHANG SIDE TO SIDE

-    stepper5.setSpeed(6400);
-    stepper5.setAcceleration(999999);
+    //stepper5.setSpeed(6400);
+    //stepper5.setAcceleration(999999);

     while (digitalRead(xZeropin) != xZeroNC) {
       stepper5.moveTo(stepper5.currentPosition()-10);      //change to +4 for zero on opposite side
@@ -182,7 +191,7 @@

     while (digitalRead(zZeropin) != zZeroNC) {
       stepper1.moveTo(stepper1.currentPosition()+320);
-      stepper1.runToPosition();
+      stepper1.run();
     }
     stepper1.stop();
     stepper1.setCurrentPosition(tablezsteps);