Update LED codebase

Update LED codebase

--- arduino/Client/Client.ino
+++ arduino/Client/Client.ino
@@ -13,6 +13,7 @@
  * LPD8806 pin assignments
  * DATA    2
  * CLOCK   3
+ * MODE    6
  */

 #include <SPI.h>
@@ -24,15 +25,29 @@
 const int BAUD = 9600;

 const int nLEDs = 32; // Number of LEDs in strand
-const int dataPin  = 2;
-const int clockPin = 3;
+const int dataPin  = 2; // Output pins to the LPD8806
+const int clockPin = 3; // Output pins to the LPD8806
+const int buttonPin = 6;// the number of the input pin
+
 const int frameDuration = 25; // ms to display each frame of animation
+const int counterLimit = 10240; // we don't need to track the number of loop executions up to infinity, once it hits this number it starts back at zero.
 int counter = 0; // keeps track of the number of times we've executed loop
-const int counterLimit = 10240; // we don't need to track the number of loop executions up to infinity, once it hits this number it starts back at zero.
 int maxParticles = 5;
 int maxLeadingCorona = (nLEDs/2)-1;
 int maxTrailingCorona = (nLEDs/2)-1;
-LPD8806 strip = LPD8806(32, dataPin, clockPin);
+
+LPD8806 strip = LPD8806(32, dataPin, clockPin); // Init the strip
+
+int particleParamSetCount = 5;		// number of sets of particle parameters
+int currentParticleParamSet = 1;	// which of those particle parameter sets are currently active
+int ringParamSetCount = 5;			// number of sets of ring parameters
+int currentRingParamSet = 1;		// which of those ring parameter sets are currently active
+
+int PARTICLE = 1;
+int RING = 2;
+
+int mode = RING;
+// int mode = PARTICLE;

 /*
  * array stores 16 parameters per particle. In order these represent:
@@ -49,17 +64,73 @@
  * 6 empty slots, for future expansion
 */

-int particleParams[] = {
-    1, 0, 0, 2, 66, 66, 66, 127, 0, 1, 0, 0, 0, 0, 0, 0,
-    1, 0, 1, 2, 66, 66, 66, 127, 0, 1, 0, 0, 0, 0, 0, 0,
-    1, 0, 0, 4, 127, 0, 0, 127, 0, 1, 0, 0, 0, 0, 0, 0,
-    1, 0, 1, 4, 0, 0, 127, 127, 0, 1, 0, 0, 0, 0, 0, 0,
+int particleParams1[] = {
+    1, 0, 0, 2, 66, 66, 66, 127, 1, 1, 0, 0, 0, 0, 0, 0,
+    1, 0, 1, 2, 66, 66, 66, 127, 1, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 4, 127, 0, 0, 127, 0, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 1, 4, 0, 0, 127, 127, 0, 1, 0, 0, 0, 0, 0, 0,
     0, 0, 1, 2, 127, 127, 127, 127, 0, 1, 0, 0, 0, 0, 0, 0
 };
+
+int particleParams2[] = {
+    1, 0, 0, 4, 43, 43, 43, 127, 1, 1, 0, 0, 0, 0, 0, 0,
+    1, 0, 1, 4, 0, 0, 127, 127, 1, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 2, 66, 66, 66, 127, 0, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 1, 2, 66, 66, 66, 127, 0, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 1, 2, 127, 127, 127, 127, 0, 1, 0, 0, 0, 0, 0, 0
+};
+
+int particleParams3[] = {
+    1, 0, 0, 2, 0, 0, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 1, 2, 66, 66, 66, 127, 0, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 4, 127, 0, 0, 127, 0, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 1, 4, 0, 0, 127, 127, 0, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 1, 2, 127, 127, 127, 127, 0, 1, 0, 0, 0, 0, 0, 0
+};
+
+int particleParams4[] = {
+    1, 0, 0, 2, 43, 43, 43, 127, 0, 1, 0, 0, 0, 0, 0, 0,
+    1, 11, 0, 2, 0, 66, 66, 127, 1, 1, 0, 0, 0, 0, 0, 0,
+    1, 22, 0, 2, 0, 0, 127, 127, 0, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 1, 4, 0, 0, 127, 127, 1, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 1, 2, 127, 127, 127, 127, 0, 1, 0, 0, 0, 0, 0, 0
+};
+
+int particleParams5[] = {
+    1, 0, 0, 2, 66, 66, 66, 127, 1, 1, 0, 0, 0, 0, 0, 0,
+    1, 16, 0, 2, 66, 66, 66, 127, 0, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 4, 127, 0, 0, 127, 1, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 1, 4, 0, 0, 127, 127, 0, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 1, 2, 127, 127, 127, 127, 0, 1, 0, 0, 0, 0, 0, 0
+};
+
+int activeParticleParams[80];
+
+/* arrays store xx parameters defining a ring pattern. Params are:
+ * style - 0: pulse
+ * rate
+ * red val (127 max)
+ * green val
+ * blue val
+ * brightness
+ * 6 empty slots, for future expansion
+*/
+int ringParams1[] = {1, 32, 43, 43, 43, 127, 0, 0, 0, 0, 0, 0};
+int ringParams2[] = {1, 32, 0, 66, 66, 127, 0, 0, 0, 0, 0, 0};
+int ringParams3[] = {0, 64, 0, 66, 66, 127, 0, 0, 0, 0, 0, 0};
+int ringParams4[] = {1, 32, 0, 0, 127, 127, 0, 0, 0, 0, 0, 0};
+int ringParams5[] = {1, 64, 0, 0, 127, 127, 0, 0, 0, 0, 0, 0};
+
+int activeRingParams[12];
+
+int buttonReading; // the current reading from the input pin
+int previousReading = LOW; // the previous reading from the input pin
+
+// the follow variables are longs because the time, measured in miliseconds, will quickly become a bigger number than can be stored in an int.
+long time = 0; // the last time the output pin was toggled
+long debounce = 100; // the debounce time, increase if the output flickers

 String inputString = "";
-String mode = "";
-
 boolean stringComplete = false;

 void setup() {
@@ -71,9 +142,14 @@
     Mirf.config();
     Serial.println("CLIENT READY");

+    pinMode(buttonPin,INPUT_PULLUP);
+
     strip.begin();
     strip.show();
     initPattern();
+    // fill the active params arrays with their default values
+    memcpy(activeParticleParams, particleParams1, 128);
+    memcpy(activeRingParams, ringParams1, 128);
 }

 void loop() {
@@ -94,25 +170,76 @@

     counter++;
     if (counter > counterLimit) counter = 0;
-    renderParticles();
+
+    int switchstate;
+    buttonReading = digitalRead(buttonPin);
+    // If the switch changed, due to bounce or pressing...
+    if (buttonReading != previousReading) time = millis(); // reset the debouncing timer
+
+    if ((millis() - time) > debounce) {
+        switchstate = buttonReading; // whatever the switch is at, its been there for a while so lets act on it!
+        if (switchstate == LOW) nextParamSet(); // Now invert the output on the pin13 LED
+    }
+
+    previousReading = buttonReading; // Save the last reading so we keep a running tally
+
+    (mode == PARTICLE) ? renderParticles() : renderRings();
+
     strip.show();
     clearPixels();
     delay(frameDuration);
 }

+void nextParamSet() {
+    counter = 0;
+    if (mode == PARTICLE) {
+        if (currentParticleParamSet+1 <= particleParamSetCount) {
+            currentParticleParamSet++;
+        } else {
+            currentParticleParamSet = 1;
+            mode = RING;
+            return;
+        }
+
+        switch (currentParticleParamSet) {
+            case 1: memcpy(activeParticleParams, particleParams1, 128); break;
+            case 2: memcpy(activeParticleParams, particleParams2, 128); break;
+            case 3: memcpy(activeParticleParams, particleParams3, 128); break;
+            case 4: memcpy(activeParticleParams, particleParams4, 128); break;
+            case 5: memcpy(activeParticleParams, particleParams5, 128); break;
+        }
+    } else if ( mode == RING ) {
+        if ( currentRingParamSet+1 <= ringParamSetCount ) {
+            currentRingParamSet++;
+        } else {
+            currentRingParamSet = 1;
+            mode = PARTICLE;
+            return;
+        }
+
+        switch (currentRingParamSet) {
+            case 1: memcpy(activeRingParams, ringParams1, 128); break;
+            case 2: memcpy(activeRingParams, ringParams2, 128); break;
+            case 3: memcpy(activeRingParams, ringParams3, 128); break;
+            case 4: memcpy(activeRingParams, ringParams4, 128); break;
+            case 5: memcpy(activeRingParams, ringParams5, 128); break;
+        }
+    }
+}
+
 void initPattern() {
     counter = 0;
-    for (int i=0; i<maxParticles; i++) {
-        int pActive = particleParams[i*16];
+    for (int i = 0; i < maxParticles; i++) {
+        int pActive = activeParticleParams[i * 16];
         if (pActive == 1) {
             // limit the corona sizes
-            int pCoronaLeading = particleParams[i*16+8];
+            int pCoronaLeading = activeParticleParams[i * 16 + 8];
             pCoronaLeading = min(pCoronaLeading, maxLeadingCorona);
-            particleParams[i*16+8] = pCoronaLeading;
-
-            int pCoronaTrailing = particleParams[i*16+9];
+            activeParticleParams[i * 16 + 8] = pCoronaLeading;
+
+            int pCoronaTrailing = activeParticleParams[i * 16 + 9];
             pCoronaTrailing = min(pCoronaTrailing, maxTrailingCorona);
-            particleParams[i*16+9] = pCoronaTrailing;
+            activeParticleParams[i * 16 + 9] = pCoronaTrailing;
         }
     }
 }
@@ -124,55 +251,164 @@
 }

 void renderParticles() {
-    for (int i=0; i<maxParticles; i++) {
-        int pActive = particleParams[i*16];
+    for (int i = 0; i < maxParticles; i++) {
+        int pActive = activeParticleParams[i*16];
         if (pActive == 1) {
-            int pPos = particleParams[i*16+1];
-            int pDirection = particleParams[i*16+2];
-            int pSpeed = particleParams[i*16+3];
-            int pRVal = particleParams[i*16+4];
-            int pGVal = particleParams[i*16+5];
-            int pBVal = particleParams[i*16+6];
-            int pBrightness = particleParams[i*16+7];
-            int pCoronaLeading = particleParams[i*16+8];
-            int pCoronaTrailing = particleParams[i*16+9];
-
-            // if based on the particle's speed it should move on this frame
-            if (counter % pSpeed == 0) { // if this particle rotates clockwise...
-                if (pDirection == 1) { // if this particle has reached the end of the strip...
-                    if ((pPos + 1) == (nLEDs)) {
-                        pPos = 0;
-                    } else {
-                        pPos = pPos+1;
+		int pActive = activeParticleParams[i * 16];
+		if ( pActive == 1 ) {
+                    int pPos = activeParticleParams[i * 16 + 1];
+                    int pDirection = activeParticleParams[i * 16 + 2];
+                    int pSpeed = activeParticleParams[i * 16 + 3];
+                    int pRVal = activeParticleParams[i * 16 + 4];
+                    int pGVal = activeParticleParams[i * 16 + 5];
+                    int pBVal = activeParticleParams[i * 16 + 6];
+                    int pBrightness = activeParticleParams[i * 16 + 7];
+                    int pCoronaLeading = activeParticleParams[i * 16 + 8];
+                    int pCoronaTrailing = activeParticleParams[i * 16 + 9];
+
+                    // if based on the particle's speed it should move on this frame
+                    if (counter % pSpeed == 0) { // if this particle rotates clockwise...
+                        if (pDirection == 1) { // if this particle has reached the end of the strip...
+                            if ((pPos + 1) == nLEDs) {
+                                pPos = 0;
+                            } else {
+                                pPos = pPos + 1;
+                            }
+                        } else { // else, if this particle rotates counter clockwise
+                            if ((pPos - 1) < 0) {
+                                pPos = nLEDs - 1;
+                            } else {
+                                pPos--;
+                            }
+                        }
+
+                        activeParticleParams[i*16+1] = pPos;
                     }
-                } else { // else, if this particle rotates counter clockwise
-                    if (pPos-1 < 0) {
-                        pPos = nLEDs-1;
-                    } else {
-                        pPos--;
+
+                    // note the Color | Color argument blends the existing color (if any) of the pixel with the newly calculated color - so particle overlaps look right
+                    strip.setPixelColor(pPos, strip.Color(pRVal, pGVal, pBVal) | strip.getPixelColor(pPos));
+
+                    /* PLACEHOLDER CODE - replace with proper corona code */
+                    if ( pCoronaLeading > 0 ) {
+                        // clockwise rotation
+                        if (pDirection == 1) {
+                            if (pPos-1 < 0) {
+                                pPos = nLEDs - 1;
+                            } else {
+                                pPos = pPos - 1;
+                            }
+
+                            strip.setPixelColor(pPos, strip.Color(calculateBrightness(pRVal, 10), calculateBrightness(pGVal, 10), calculateBrightness(pBVal, 10)) | strip.getPixelColor(pPos));
+
+                            if (pPos - 1 < 0) {
+                                pPos = nLEDs - 1;
+                            } else {
+                                pPos = pPos - 1;
+                            }
+
+                            strip.setPixelColor(pPos, strip.Color(calculateBrightness(pRVal, 3), calculateBrightness(pGVal, 3), calculateBrightness(pBVal, 3)) | strip.getPixelColor(pPos));
+                        } else {
+                            if (pPos + 1 == nLEDs) {
+                                pPos = 0;
+                            } else {
+                                pPos = pPos + 1;
+                            }
+
+                            strip.setPixelColor(pPos, strip.Color(calculateBrightness(pRVal, 10), calculateBrightness(pGVal, 10), calculateBrightness(pBVal, 10)) | strip.getPixelColor(pPos));
+
+                        if (pPos + 1 == nLEDs) {
+                            pPos = 0;
+                        } else {
+                            pPos = pPos+1;
+                        }
+
+                        strip.setPixelColor(pPos, strip.Color(calculateBrightness(pRVal, 3), calculateBrightness(pGVal, 3), calculateBrightness(pBVal, 3)) | strip.getPixelColor(pPos));
                     }
                 }
-                particleParams[i*16+1] = pPos;
-            }
-            // note the Color | Color argument blends the existing color (if any) of the pixel with the newly calculated color - so particle overlaps look right
-            strip.setPixelColor(pPos, strip.Color(pRVal, pGVal, pBVal) | strip.getPixelColor(pPos));
-
-            /* PLACEHOLDER CODE - replace with proper corona code */
-            if (pPos-1 < 0) {
-                pPos = nLEDs-1;
-            } else {
-                pPos = pPos-1;
-            }
-            strip.setPixelColor(pPos, strip.Color(calculateBrightness(pRVal, 15), calculateBrightness(pGVal, 15), calculateBrightness(pBVal, 15)) | strip.getPixelColor(pPos));
-
-            if (pPos-1 < 0) {
-                pPos = nLEDs-1;
-            } else {
-                pPos = pPos-1;
-            }
-            strip.setPixelColor(pPos, strip.Color(calculateBrightness(pRVal, 5), calculateBrightness(pGVal, 5), calculateBrightness(pBVal, 5)) | strip.getPixelColor(pPos));
-        }
-    }
+            }
+        }
+    }
+}
+
+void renderRings() {
+    int rStyle = activeRingParams[0];
+    int rRate = activeRingParams[1];
+    int rRVal = activeRingParams[2];
+    int rGVal = activeRingParams[3];
+    int rBVal = activeRingParams[4];
+    // TODO do something with the brightness
+    // int rBrightness = activeRingParams[5];
+
+    // this is a sharp pulse style ring
+    if (rStyle == 0) {
+        if (counter % rRate == 0) {
+            for ( int i=0; i<nLEDs; i++ ) {
+                strip.setPixelColor(i, strip.Color(rRVal, rGVal, rBVal));
+            }
+        }
+    }
+
+    // temp variables used for the ring fade
+    int rRFadeVal = 0;
+    int rGFadeVal = 0;
+    int rBFadeVal = 0;
+    // this is a style of ring with a fade into and out of the brightest pulse
+    if (rStyle == 1) {
+        if (counter % rRate == 0) {
+            // colour all the LEDs in the strip
+            for (int i = 0; i < nLEDs; i++) {
+                strip.setPixelColor(i, strip.Color(rRVal, rGVal, rBVal));
+            }
+        } else if ( (counter+1) % rRate == 0 || (counter-1) % rRate == 0 ) {
+            if (rRVal > 0) {
+                rRFadeVal = calculateBrightness(rRVal, 10);
+            }
+
+            if (rGVal > 0) {
+                rGFadeVal = calculateBrightness(rGVal, 10);
+            }
+
+            if (rBVal > 0) {
+                rBFadeVal = calculateBrightness(rBVal, 10);
+            }
+
+            for (int i = 0; i < nLEDs; i++) {
+                strip.setPixelColor(i, strip.Color(rRFadeVal, rGFadeVal, rBFadeVal));
+            }
+        } else if ((counter+2) % rRate == 0 || (counter-2) % rRate == 0) {
+            if (rRVal > 0) {
+                rRFadeVal = calculateBrightness(rRVal, 5);
+            }
+
+            if (rGVal > 0) {
+                rGFadeVal = calculateBrightness(rGVal, 5);
+            }
+
+            if (rBVal > 0) {
+                rBFadeVal = calculateBrightness(rBVal, 5);
+            }
+
+            for ( int i=0; i<nLEDs; i++ ) {
+                strip.setPixelColor(i, strip.Color(rRFadeVal, rGFadeVal, rBFadeVal));
+            }
+        } else if ( (counter+3) % rRate == 0 || (counter-3) % rRate == 0 ) {
+            if (rRVal > 0) {
+                rRFadeVal = calculateBrightness(rRVal, 3);
+            }
+
+            if (rGVal > 0) {
+                rGFadeVal = calculateBrightness(rGVal, 3);
+            }
+
+            if (rBVal > 0) {
+                rBFadeVal = calculateBrightness(rBVal, 3);
+            }
+
+            for (int i = 0; i < nLEDs; i++) {
+                strip.setPixelColor(i, strip.Color(rRFadeVal, rGFadeVal, rBFadeVal));
+            }
+        }
+    }
 }

 // turn all pixels off


Check first char for empty message

Check first char for empty message

--- arduino/stair_sensor/stair_sensor.ino
+++ arduino/stair_sensor/stair_sensor.ino
@@ -205,7 +205,7 @@
     // Time to send another transmition if one is waiting.
     byte oldestIndex = getOldestMsqQueueIndex();
     // Check for a message.
-    if (strlen(msgQueue[oldestIndex]) == 0) {
+    if (msgQueue[oldestIndex][0] == 0) { // First character is zero.
       // nothing to do.
       return;
     }


Fixed bug in high precision mode where seconds are not padded properly.

--- arduino-code/Stellarduino/Stellarduino.ino
+++ arduino-code/Stellarduino/Stellarduino.ino
@@ -141,7 +141,7 @@
   clearScreen();

   state = WAITING_FOR_START;
-  highPrecision = false;
+  highPrecision = true;
 }

 void loop()
@@ -436,7 +436,7 @@

   if (highPrecision)
   {
-    return padding((String)int(floor(hours)), 2) + ":" + padding((String)int(floor(minutes)), 2) + ":" + (String)int(floor((minutes - floor(minutes)) * 60.0));
+    return padding((String)int(floor(hours)), 2) + ":" + padding((String)int(floor(minutes)), 2) + ":" + padding((String)int(floor((minutes - floor(minutes)) * 60.0)), 2);
   } else {
     return padding((String)int(floor(hours)), 2) + ":" + padding((String)int(floor(minutes)), 2) + "." + (String)int(floor((minutes - floor(minutes)) * 10.0));
   }
@@ -450,7 +450,7 @@

   if (highPrecision)
   {
-    return sign + padding((String)int(floor(degs)), 2) + "*" + padding((String)int(floor(minutes)), 2) + ":" + (String)int(floor((minutes - floor(minutes)) * 60.0));
+    return sign + padding((String)int(floor(degs)), 2) + "*" + padding((String)int(floor(minutes)), 2) + ":" + padding((String)int(floor((minutes - floor(minutes)) * 60.0)), 2);
   }
   {
     return sign + padding((String)int(floor(degs)), 2) + "*" + padding((String)int(floor(minutes)), 2);


fix floating input pin

fix floating input pin

--- arduinoHouse/arduinoHouse/arduinoHouse.ino
+++ arduinoHouse/arduinoHouse/arduinoHouse.ino
@@ -219,8 +219,7 @@
   debouncerDeur.interval(50);

   //input
-  pinMode(WC_DETECT, INPUT);
-  digitalWrite(WC_DETECT, LOW);
+  pinMode(WC_DETECT, INPUT_PULLUP);
   // After setting up the button, setup the Bounce instance :
   debouncerWC.attach(WC_DETECT);
   debouncerWC.interval(10);
@@ -228,6 +227,7 @@

   //Install listeners and initialize Wiegand reader
   wiegand.onReceive(receivedData, "Card readed: ");
+
   wiegand.onStateChange(stateChanged, "State changed: ");
   wiegand.begin(WIEGAND_LENGTH_AUTO);


Adding screen messages on wifi and mqtt connect

--- basement_monitor/basement_monitor.ino
+++ basement_monitor/basement_monitor.ino
@@ -45,6 +45,9 @@
         // Attempt to connect
         if (mqttClient.connect(MQTT_CLIENT_NAME, MQTT_USERNAME, MQTT_PASSWORD))
         {
+            Heltec.display->clear();
+            Heltec.display->drawString(0, 0, "Connected to MQTT");
+            Heltec.display->display();
             Serial.println("MQTT connected");
             mqttClient.publish(TOPIC_CONNECTED, "1");
             boolean success = mqttClient.subscribe(TOPIC_LED);
@@ -245,6 +248,11 @@
     setupDHTTask();
     setupLDRTask();
     setupMQTTPollTask();
+
+    Heltec.display->clear();
+    Heltec.display->drawString(0, 0, "Setup complete!");
+    Heltec.display->display();
+
 }

 void loop()


connected sensor to led strips

connected sensor to led strips

--- project.ino
+++ project.ino
@@ -11,35 +11,63 @@
  	* GND connection of the PING))) attached to ground
  	* SIG connection of the PING))) attached to digital pin 7
  */
+
+#include <Adafruit_NeoPixel.h>
+#include <avr/power.h>

-// Pin number of the sensor's output
-const int pingPin = 7;
+#define PIN_STRIP 6
+#define PIN_SENSOR 7
+
+Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, PIN_STRIP, NEO_GRB + NEO_KHZ800);

 void setup() {
-  // initialize serial communication:
   Serial.begin(9600);
+
+  strip.begin();
+  strip.show();
 }

 void loop(){
   triggerSensor();
-  long distance = readSensor();
+  int distance = readSensor();
+  changeColor(distance);
   printDistance(distance);

   delay(50);
+}
+
+long changeColor(int distance){
+  int maxDistance = 200;
+  int minDistance = 50;
+
+  distance = max(minDistance, distance);
+  distance = min(maxDistance, distance);
+
+  int value = 255.00 / (maxDistance - minDistance) * (distance - minDistance);
+  int green = value;
+  int red = 255 - value;
+
+  uint32_t c = strip.Color(red, green, 0);
+
+  for(uint16_t i=0; i<strip.numPixels(); i++) {
+    strip.setPixelColor(i, c);
+  }
+
+  strip.show();
 }

 long readSensor(){
   // The same pin is used to read the signal from the PING))): a HIGH
   // pulse whose duration is the time (in microseconds) from the sending
   // of the ping to the reception of its echo off of an object.
-  pinMode(pingPin, INPUT);
-  long duration = pulseIn(pingPin, HIGH);
+  pinMode(PIN_SENSOR, INPUT);
+  long duration = pulseIn(PIN_SENSOR, HIGH);

   // convert the time into a distance
   return microsecondsToCentimeters(duration);
 }

-void printDistance(long distance){
+void printDistance(int distance){
   Serial.print(distance);
   Serial.print("cm");
   Serial.println();
@@ -48,15 +76,15 @@
 void triggerSensor(){
   // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
   // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
-  pinMode(pingPin, OUTPUT);
-  digitalWrite(pingPin, LOW);
+  pinMode(PIN_SENSOR, OUTPUT);
+  digitalWrite(PIN_SENSOR, LOW);
   delayMicroseconds(2);
-  digitalWrite(pingPin, HIGH);
+  digitalWrite(PIN_SENSOR, HIGH);
   delayMicroseconds(5);
-  digitalWrite(pingPin, LOW);
+  digitalWrite(PIN_SENSOR, LOW);
 }

-long microsecondsToCentimeters(long microseconds)
+int microsecondsToCentimeters(long microseconds)
 {
   // The speed of sound is 340 m/s or 29 microseconds per centimeter.
   // The ping travels out and back, so to find the distance of the


Update BlynkBlink.ino

Update BlynkBlink.ino

--- examples/GettingStarted/BlynkBlink/BlynkBlink.ino
+++ examples/GettingStarted/BlynkBlink/BlynkBlink.ino
@@ -43,6 +43,9 @@
   4. Add a Button Widget. Select Pin D9 in Widget's Settings
   5. Press Play icon. Enjoy Blynking!

+  You can find a QR code for easy setup of this project here:
+  https://github.com/blynkkk/blynk-library/tree/master/examples/GettingStarted/BlynkBlink
+
 ********************************************************************/

 #define BLYNK_PRINT Serial // Enables Serial Monitor


Fix USB transfer type identification

Fix USB transfer type identification

Bulk endpoints were incorrectly shown as Interrupt.

--- libraries/USBHost/examples/USB_desc/USB_desc.ino
+++ libraries/USBHost/examples/USB_desc/USB_desc.ino
@@ -340,6 +340,8 @@
 /* function to print endpoint descriptor */
 void printepdescr( uint8_t* descr_ptr )
 {
+  uint8_t transfer_type;
+
  USB_ENDPOINT_DESCRIPTOR* ep_ptr = ( USB_ENDPOINT_DESCRIPTOR* )descr_ptr;
   printProgStr(End_Header_str);
   printProgStr(End_Address_str);
@@ -347,9 +349,10 @@
   else printProgStr(PSTR("OUT\t\t"));
   print_hex( (ep_ptr->bEndpointAddress & 0xF), 8 );
   printProgStr(End_Attr_str);
-  if( 0x03 & ep_ptr->bmAttributes ) printProgStr(PSTR("INTERRUPT\t"));
-  else if( 0x02 & ep_ptr->bmAttributes ) printProgStr(PSTR("BULK\t"));
-  else if( 0x01 & ep_ptr->bmAttributes ) printProgStr(PSTR("ISO\t"));
+  transfer_type = ep_ptr->bmAttributes & bmUSB_TRANSFER_TYPE;
+  if( transfer_type == USB_TRANSFER_TYPE_INTERRUPT ) printProgStr(PSTR("INTERRUPT\t"));
+  else if( transfer_type == USB_TRANSFER_TYPE_BULK ) printProgStr(PSTR("BULK\t"));
+  else if( transfer_type == USB_TRANSFER_TYPE_ISOCHRONOUS ) printProgStr(PSTR("ISO\t"));
   print_hex( ep_ptr->bmAttributes, 8 );
   printProgStr(End_Pktsize_str);
   print_hex( ep_ptr->wMaxPacketSize, 16 );


updated library to use new version of FastLED

--- AdalightPIN6GRB/AdalightPIN6GRB.ino
+++ AdalightPIN6GRB/AdalightPIN6GRB.ino
@@ -4,11 +4,11 @@
 // Uses Adalight protocol and is compatible with Boblight, Prismatik etc
 // "Magic Word" for synchronisation is 'Ada' followed by LED High, Low and Checksum
 //
-#include <FastSPI_LED2.h>
+#include "FastLED.h"
 ///// User definitions /////

 // Define the number of LEDs
-#define NUM_LEDS 78
+#define NUM_LEDS 46

 // Define SPI Pin
 #define PIN 6
@@ -31,7 +31,7 @@
 void setup()
 {

-  FastLED.addLeds<WS2812, PIN, RGB>(leds, NUM_LEDS);
+  FastLED.addLeds<WS2812B, PIN, GRB>(leds, NUM_LEDS);

   // initial RGB flash
   LEDS.showColor(CRGB(255, 0, 0));


put MAX_COLORS back to 255

put MAX_COLORS back to 255

--- firmware/spark-neopixel-control.ino
+++ firmware/spark-neopixel-control.ino
@@ -10,7 +10,7 @@
 #define PIXEL_TYPE WS2812B

 //particle params
-#define MAX_COLOR 200
+#define MAX_COLOR 255
 #define NUM_PARTICLES 12
 #define FPS 30
 #define MILLIS_PER_FRAME (1000 / FPS)


switch to 2-space indentation

switch to 2-space indentation

--- examples/RF12/RF12demo/RF12demo.ino
+++ examples/RF12/RF12demo/RF12demo.ino
@@ -17,24 +17,24 @@
 #else
 #define SERIAL_BAUD 57600

-#define DATAFLASH   1   // check for presence of DataFlash memory on JeeLink
+#define DATAFLASH 1 // check for presence of DataFlash memory on JeeLink
 #define FLASH_MBIT  16  // support for various dataflash sizes: 4/8/16 Mbit

-#define LED_PIN     9   // activity LED, comment out to disable
+#define LED_PIN   9 // activity LED, comment out to disable

 #endif

 #define COLLECT 0x20 // collect mode, i.e. pass incoming without sending acks

 static unsigned long now () {
-    // FIXME 49-day overflow
-    return millis() / 1000;
+  // FIXME 49-day overflow
+  return millis() / 1000;
 }

 static void activityLed (byte on) {
 #ifdef LED_PIN
-    pinMode(LED_PIN, OUTPUT);
-    digitalWrite(LED_PIN, !on);
+  pinMode(LED_PIN, OUTPUT);
+  digitalWrite(LED_PIN, !on);
 #endif
 }

@@ -42,10 +42,10 @@
 // RF12 configuration setup code

 typedef struct {
-    byte nodeId;
-    byte group;
-    char msg[RF12_EEPROM_SIZE-4];
-    word crc;
+  byte nodeId;
+  byte group;
+  char msg[RF12_EEPROM_SIZE-4];
+  word crc;
 } RF12Config;

 static RF12Config config;
@@ -55,64 +55,64 @@
 static byte testbuf[RF12_MAXDATA], testCounter, useHex;

 static void showNibble (byte nibble) {
-    char c = '0' + (nibble & 0x0F);
-    if (c > '9')
-        c += 7;
-    Serial.print(c);
+  char c = '0' + (nibble & 0x0F);
+  if (c > '9')
+    c += 7;
+  Serial.print(c);
 }

 static void showByte (byte value) {
-    if (useHex) {
-        showNibble(value >> 4);
-        showNibble(value);
-    } else
-        Serial.print((int) value);
+  if (useHex) {
+    showNibble(value >> 4);
+    showNibble(value);
+  } else
+    Serial.print((int) value);
 }

 static void addCh (char* msg, char c) {
-    byte n = strlen(msg);
-    msg[n] = c;
+  byte n = strlen(msg);
+  msg[n] = c;
 }

 static void addInt (char* msg, word v) {
-    if (v >= 10)
-        addInt(msg, v / 10);
-    addCh(msg, '0' + v % 10);
+  if (v >= 10)
+    addInt(msg, v / 10);
+  addCh(msg, '0' + v % 10);
 }

 static void saveConfig () {
-    // set up a nice config string to be shown on startup
-    memset(config.msg, 0, sizeof config.msg);
-    strcpy(config.msg, " ");
-
-    byte id = config.nodeId & 0x1F;
-    addCh(config.msg, '@' + id);
-    strcat(config.msg, " i");
-    addInt(config.msg, id);
-    if (config.nodeId & COLLECT)
-        addCh(config.msg, '*');
-
-    strcat(config.msg, " g");
-    addInt(config.msg, config.group);
-
-    strcat(config.msg, " @ ");
-    static word bands[4] = { 315, 433, 868, 915 };
-    word band = config.nodeId >> 6;
-    addInt(config.msg, bands[band]);
-    strcat(config.msg, " MHz ");
-
-    config.crc = ~0;
-    for (byte i = 0; i < sizeof config - 2; ++i)
-        config.crc = _crc16_update(config.crc, ((byte*) &config)[i]);
-
-    // save to EEPROM
-    for (byte i = 0; i < sizeof config; ++i) {
-        byte b = ((byte*) &config)[i];
-        eeprom_write_byte(RF12_EEPROM_ADDR + i, b);
-    }
-
-    if (!rf12_config())
-        Serial.println("config save failed");
+  // set up a nice config string to be shown on startup
+  memset(config.msg, 0, sizeof config.msg);
+  strcpy(config.msg, " ");
+
+  byte id = config.nodeId & 0x1F;
+  addCh(config.msg, '@' + id);
+  strcat(config.msg, " i");
+  addInt(config.msg, id);
+  if (config.nodeId & COLLECT)
+    addCh(config.msg, '*');
+
+  strcat(config.msg, " g");
+  addInt(config.msg, config.group);
+
+  strcat(config.msg, " @ ");
+  static word bands[4] = { 315, 433, 868, 915 };
+  word band = config.nodeId >> 6;
+  addInt(config.msg, bands[band]);
+  strcat(config.msg, " MHz ");
+
+  config.crc = ~0;
+  for (byte i = 0; i < sizeof config - 2; ++i)
+    config.crc = _crc16_update(config.crc, ((byte*) &config)[i]);
+
+  // save to EEPROM
+  for (byte i = 0; i < sizeof config; ++i) {
+    byte b = ((byte*) &config)[i];
+    eeprom_write_byte(RF12_EEPROM_ADDR + i, b);
+  }
+
+  if (!rf12_config())
+    Serial.println("config save failed");
 }

 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -122,50 +122,50 @@
 // for 25 us SPI overhead to end up with the proper on-the-air pulse widths.
 // With thanks to JGJ Veken for his help in getting these values right.
 static void ookPulse(int on, int off) {
-    rf12_onOff(1);
-    delayMicroseconds(on + 150);
-    rf12_onOff(0);
-    delayMicroseconds(off - 200);
+  rf12_onOff(1);
+  delayMicroseconds(on + 150);
+  rf12_onOff(0);
+  delayMicroseconds(off - 200);
 }

 static void fs20sendBits(word data, byte bits) {
-    if (bits == 8) {
-        ++bits;
-        data = (data << 1) | parity_even_bit(data);
-    }
-    for (word mask = bit(bits-1); mask != 0; mask >>= 1) {
-        int width = data & mask ? 600 : 400;
-        ookPulse(width, width);
-    }
+  if (bits == 8) {
+    ++bits;
+    data = (data << 1) | parity_even_bit(data);
+  }
+  for (word mask = bit(bits-1); mask != 0; mask >>= 1) {
+    int width = data & mask ? 600 : 400;
+    ookPulse(width, width);
+  }
 }

 static void fs20cmd(word house, byte addr, byte cmd) {
-	byte sum = 6 + (house >> 8) + house + addr + cmd;
-	for (byte i = 0; i < 3; ++i) {
-		fs20sendBits(1, 13);
-		fs20sendBits(house >> 8, 8);
-		fs20sendBits(house, 8);
-		fs20sendBits(addr, 8);
-		fs20sendBits(cmd, 8);
-		fs20sendBits(sum, 8);
-		fs20sendBits(0, 1);
-		delay(10);
-	}
+  byte sum = 6 + (house >> 8) + house + addr + cmd;
+  for (byte i = 0; i < 3; ++i) {
+    fs20sendBits(1, 13);
+    fs20sendBits(house >> 8, 8);
+    fs20sendBits(house, 8);
+    fs20sendBits(addr, 8);
+    fs20sendBits(cmd, 8);
+    fs20sendBits(sum, 8);
+    fs20sendBits(0, 1);
+    delay(10);
+  }
 }

 static void kakuSend(char addr, byte device, byte on) {
-    int cmd = 0x600 | ((device - 1) << 4) | ((addr - 1) & 0xF);
-    if (on)
-        cmd |= 0x800;
-    for (byte i = 0; i < 4; ++i) {
-        for (byte bit = 0; bit < 12; ++bit) {
-            ookPulse(375, 1125);
-            int on = bitRead(cmd, bit) ? 1125 : 375;
-            ookPulse(on, 1500 - on);
-        }
-		ookPulse(375, 375);
-		delay(11); // approximate
-    }
+  int cmd = 0x600 | ((device - 1) << 4) | ((addr - 1) & 0xF);
+  if (on)
+    cmd |= 0x800;
+  for (byte i = 0; i < 4; ++i) {
+    for (byte bit = 0; bit < 12; ++bit) {
+      ookPulse(375, 1125);
+      int on = bitRead(cmd, bit) ? 1125 : 375;
+      ookPulse(on, 1500 - on);
+    }
+    ookPulse(375, 375);
+    delay(11); // approximate
+  }
 }

 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -173,360 +173,360 @@

 #if DATAFLASH

-#define DF_ENABLE_PIN   8           // PB0
+#define DF_ENABLE_PIN 8     // PB0

 #if FLASH_MBIT == 4
 // settings for 0.5 Mbyte flash in JLv2
-#define DF_BLOCK_SIZE   16          // number of pages erased at same time
-#define DF_LOG_BEGIN    32          // first 2 blocks reserved for future use
-#define DF_LOG_LIMIT    0x0700      // last 64k is not used for logging
-#define DF_MEM_TOTAL    0x0800      // 2048 pages, i.e. 0.5 Mbyte
-#define DF_DEVICE_ID    0x1F44      // see AT25DF041A datasheet
-#define DF_PAGE_ERASE   0x20        // erase one block of flash memory
+#define DF_BLOCK_SIZE 16      // number of pages erased at same time
+#define DF_LOG_BEGIN  32      // first 2 blocks reserved for future use
+#define DF_LOG_LIMIT  0x0700    // last 64k is not used for logging
+#define DF_MEM_TOTAL  0x0800    // 2048 pages, i.e. 0.5 Mbyte
+#define DF_DEVICE_ID  0x1F44    // see AT25DF041A datasheet
+#define DF_PAGE_ERASE 0x20    // erase one block of flash memory
 #endif

 #if FLASH_MBIT == 8
 // settings for 1 Mbyte flash in JLv2
-#define DF_BLOCK_SIZE   16          // number of pages erased at same time
-#define DF_LOG_BEGIN    32          // first 2 blocks reserved for future use
-#define DF_LOG_LIMIT    0x0F00      // last 64k is not used for logging
-#define DF_MEM_TOTAL    0x1000      // 4096 pages, i.e. 1 Mbyte
-#define DF_DEVICE_ID    0x1F45      // see AT26DF081A datasheet
-#define DF_PAGE_ERASE   0x20        // erase one block of flash memory
+#define DF_BLOCK_SIZE 16      // number of pages erased at same time
+#define DF_LOG_BEGIN  32      // first 2 blocks reserved for future use
+#define DF_LOG_LIMIT  0x0F00    // last 64k is not used for logging
+#define DF_MEM_TOTAL  0x1000    // 4096 pages, i.e. 1 Mbyte
+#define DF_DEVICE_ID  0x1F45    // see AT26DF081A datasheet
+#define DF_PAGE_ERASE 0x20    // erase one block of flash memory
 #endif

 #if FLASH_MBIT == 16
 // settings for 2 Mbyte flash in JLv3
-#define DF_BLOCK_SIZE   256         // number of pages erased at same time
-#define DF_LOG_BEGIN    512         // first 2 blocks reserved for future use
-#define DF_LOG_LIMIT    0x1F00      // last 64k is not used for logging
-#define DF_MEM_TOTAL    0x2000      // 8192 pages, i.e. 2 Mbyte
-#define DF_DEVICE_ID    0x2020      // see M25P16 datasheet
-#define DF_PAGE_ERASE   0xD8        // erase one block of flash memory
+#define DF_BLOCK_SIZE 256     // number of pages erased at same time
+#define DF_LOG_BEGIN  512     // first 2 blocks reserved for future use
+#define DF_LOG_LIMIT  0x1F00    // last 64k is not used for logging
+#define DF_MEM_TOTAL  0x2000    // 8192 pages, i.e. 2 Mbyte
+#define DF_DEVICE_ID  0x2020    // see M25P16 datasheet
+#define DF_PAGE_ERASE 0xD8    // erase one block of flash memory
 #endif

 // structure of each page in the log buffer, size must be exactly 256 bytes
 typedef struct {
-    byte data [248];
-    word seqnum;
-    long timestamp;
-    word crc;
+  byte data [248];
+  word seqnum;
+  long timestamp;
+  word crc;
 } FlashPage;

 // structure of consecutive entries in the data area of each FlashPage
 typedef struct {
-    byte length;
-    byte offset;
-    byte header;
-    byte data[RF12_MAXDATA];
+  byte length;
+  byte offset;
+  byte header;
+  byte data[RF12_MAXDATA];
 } FlashEntry;

-static FlashPage dfBuf;     // for data not yet written to flash
-static word dfLastPage;     // page number last written
-static byte dfFill;         // next byte available in buffer to store entries
+static FlashPage dfBuf;   // for data not yet written to flash
+static word dfLastPage;   // page number last written
+static byte dfFill;     // next byte available in buffer to store entries

 static byte df_present () {
-    return dfLastPage != 0;
+  return dfLastPage != 0;
 }

 static void df_enable () {
-    // digitalWrite(ENABLE_PIN, 0);
-    bitClear(PORTB, 0);
+  // digitalWrite(ENABLE_PIN, 0);
+  bitClear(PORTB, 0);
 }

 static void df_disable () {
-    // digitalWrite(ENABLE_PIN, 1);
-    bitSet(PORTB, 0);
+  // digitalWrite(ENABLE_PIN, 1);
+  bitSet(PORTB, 0);
 }

 static byte df_xfer (byte cmd) {
-    SPDR = cmd;
-    while (!bitRead(SPSR, SPIF))
-        ;
-    return SPDR;
+  SPDR = cmd;
+  while (!bitRead(SPSR, SPIF))
+    ;
+  return SPDR;
 }

 void df_command (byte cmd) {
-    for (;;) {
-        cli();
-        df_enable();
-        df_xfer(0x05); // Read Status Register
-        byte status = df_xfer(0);
-        df_disable();
-        sei();
-        // don't wait for ready bit if there is clearly no dataflash connected
-        if (status == 0xFF || (status & 1) == 0)
-            break;
-    }
-
+  for (;;) {
     cli();
     df_enable();
-    df_xfer(cmd);
-}
-
-static void df_deselect () {
+    df_xfer(0x05); // Read Status Register
+    byte status = df_xfer(0);
     df_disable();
     sei();
+    // don't wait for ready bit if there is clearly no dataflash connected
+    if (status == 0xFF || (status & 1) == 0)
+      break;
+  }
+
+  cli();
+  df_enable();
+  df_xfer(cmd);
+}
+
+static void df_deselect () {
+  df_disable();
+  sei();
 }

 static void df_writeCmd (byte cmd) {
-    df_command(0x06); // Write Enable
-    df_deselect();
-    df_command(cmd);
+  df_command(0x06); // Write Enable
+  df_deselect();
+  df_command(cmd);
 }

 void df_read (word block, word off, void* buf, word len) {
-    df_command(0x03); // Read Array (Low Frequency)
-    df_xfer(block >> 8);
-    df_xfer(block);
-    df_xfer(off);
-    for (word i = 0; i < len; ++i)
-        ((byte*) buf)[(byte) i] = df_xfer(0);
-    df_deselect();
+  df_command(0x03); // Read Array (Low Frequency)
+  df_xfer(block >> 8);
+  df_xfer(block);
+  df_xfer(off);
+  for (word i = 0; i < len; ++i)
+    ((byte*) buf)[(byte) i] = df_xfer(0);
+  df_deselect();
 }

 void df_write (word block, const void* buf) {
-    df_writeCmd(0x02); // Byte/Page Program
-    df_xfer(block >> 8);
-    df_xfer(block);
-    df_xfer(0);
-    for (word i = 0; i < 256; ++i)
-        df_xfer(((const byte*) buf)[(byte) i]);
-    df_deselect();
+  df_writeCmd(0x02); // Byte/Page Program
+  df_xfer(block >> 8);
+  df_xfer(block);
+  df_xfer(0);
+  for (word i = 0; i < 256; ++i)
+    df_xfer(((const byte*) buf)[(byte) i]);
+  df_deselect();
 }

 // wait for current command to complete
 void df_flush () {
-    df_read(0, 0, 0, 0);
+  df_read(0, 0, 0, 0);
 }

 static void df_wipe () {
-    Serial.println("DF W");
+  Serial.println("DF W");
+
+  df_writeCmd(0xC7); // Chip Erase
+  df_deselect();
+  df_flush();
+}
+
+static void df_erase (word block) {
+  Serial.print("DF E ");
+  Serial.println(block);
+
+  df_writeCmd(DF_PAGE_ERASE); // Block Erase
+  df_xfer(block >> 8);
+  df_xfer(block);
+  df_xfer(0);
+  df_deselect();
+  df_flush();
+}
+
+static word df_wrap (word page) {
+  return page < DF_LOG_LIMIT ? page : DF_LOG_BEGIN;
+}
+
+static void df_saveBuf () {
+  if (dfFill == 0)
+    return;
+
+  dfLastPage = df_wrap(dfLastPage + 1);
+  if (dfLastPage == DF_LOG_BEGIN)
+    ++dfBuf.seqnum; // bump to next seqnum when wrapping
+
+  // set remainder of buffer data to 0xFF and calculate crc over entire buffer
+  dfBuf.crc = ~0;
+  for (byte i = 0; i < sizeof dfBuf - 2; ++i) {
+    if (dfFill <= i && i < sizeof dfBuf.data)
+      dfBuf.data[i] = 0xFF;
+    dfBuf.crc = _crc16_update(dfBuf.crc, dfBuf.data[i]);
+  }
+
+  df_write(dfLastPage, &dfBuf);
+  dfFill = 0;
+
+  // wait for write to finish before reporting page, seqnum, and time stamp
+  df_flush();
+  Serial.print("DF S ");
+  Serial.print(dfLastPage);
+  Serial.print(' ');
+  Serial.print(dfBuf.seqnum);
+  Serial.print(' ');
+  Serial.println(dfBuf.timestamp);
+
+  // erase next block if we just saved data into a fresh block
+  // at this point in time dfBuf is empty, so a lengthy erase cycle is ok
+  if (dfLastPage % DF_BLOCK_SIZE == 0)
+    df_erase(df_wrap(dfLastPage + DF_BLOCK_SIZE));
+}
+
+static void df_append (const void* buf, byte len) {
+  //FIXME the current logic can't append incoming packets during a save!
+
+  // fill in page time stamp when appending to a fresh page
+  if (dfFill == 0)
+    dfBuf.timestamp = now();
+
+  long offset = now() - dfBuf.timestamp;
+  if (offset >= 255 || dfFill + 1 + len > sizeof dfBuf.data) {
+    df_saveBuf();
+
+    dfBuf.timestamp = now();
+    offset = 0;
+  }
+
+  // append new entry to flash buffer
+  dfBuf.data[dfFill++] = offset;
+  memcpy(dfBuf.data + dfFill, buf, len);
+  dfFill += len;
+}
+
+// go through entire log buffer to figure out which page was last saved
+static void scanForLastSave () {
+  dfBuf.seqnum = 0;
+  dfLastPage = DF_LOG_LIMIT - 1;
+  // look for last page before an empty page
+  for (word page = DF_LOG_BEGIN; page < DF_LOG_LIMIT; ++page) {
+    word currseq;
+    df_read(page, sizeof dfBuf.data, &currseq, sizeof currseq);
+    if (currseq != 0xFFFF) {
+      dfLastPage = page;
+      dfBuf.seqnum = currseq + 1;
+    } else if (dfLastPage == page - 1)
+      break; // careful with empty-filled-empty case, i.e. after wrap
+  }
+}
+
+static void df_initialize () {
+  // assumes SPI has already been initialized for the RFM12B
+  df_disable();
+  pinMode(DF_ENABLE_PIN, OUTPUT);
+  df_command(0x9F); // Read Manufacturer and Device ID
+  word info = df_xfer(0) << 8;
+  info |= df_xfer(0);
+  df_deselect();
+
+  if (info == DF_DEVICE_ID) {
+    df_writeCmd(0x01);  // Write Status Register ...
+    df_xfer(0);     // ... Global Unprotect
+    df_deselect();
+
+    scanForLastSave();

-    df_writeCmd(0xC7); // Chip Erase
-    df_deselect();
-    df_flush();
-}
-
-static void df_erase (word block) {
-    Serial.print("DF E ");
-    Serial.println(block);
-
-    df_writeCmd(DF_PAGE_ERASE); // Block Erase
-    df_xfer(block >> 8);
-    df_xfer(block);
-    df_xfer(0);
-    df_deselect();
-    df_flush();
-}
-
-static word df_wrap (word page) {
-    return page < DF_LOG_LIMIT ? page : DF_LOG_BEGIN;
-}
-
-static void df_saveBuf () {
-    if (dfFill == 0)
-        return;
-
-    dfLastPage = df_wrap(dfLastPage + 1);
-    if (dfLastPage == DF_LOG_BEGIN)
-        ++dfBuf.seqnum; // bump to next seqnum when wrapping
-
-    // set remainder of buffer data to 0xFF and calculate crc over entire buffer
-    dfBuf.crc = ~0;
-    for (byte i = 0; i < sizeof dfBuf - 2; ++i) {
-        if (dfFill <= i && i < sizeof dfBuf.data)
-            dfBuf.data[i] = 0xFF;
-        dfBuf.crc = _crc16_update(dfBuf.crc, dfBuf.data[i]);
-    }
-
-    df_write(dfLastPage, &dfBuf);
-    dfFill = 0;
-
-    // wait for write to finish before reporting page, seqnum, and time stamp
-    df_flush();
-    Serial.print("DF S ");
+    Serial.print("DF I ");
     Serial.print(dfLastPage);
+    Serial.print(' ');
+    Serial.println(dfBuf.seqnum);
+
+    // df_wipe();
+    df_saveBuf(); //XXX
+  }
+}
+
+static void discardInput () {
+  while (Serial.read() >= 0)
+    ;
+}
+
+static void df_dump () {
+  struct { word seqnum; long timestamp; word crc; } curr;
+  discardInput();
+  for (word page = DF_LOG_BEGIN; page < DF_LOG_LIMIT; ++page) {
+    if (Serial.read() >= 0)
+      break;
+    // read marker from page in flash
+    df_read(page, sizeof dfBuf.data, &curr, sizeof curr);
+    if (curr.seqnum == 0xFFFF)
+      continue; // page never written to
+    Serial.print(" df# ");
+    Serial.print(page);
+    Serial.print(" : ");
+    Serial.print(curr.seqnum);
+    Serial.print(' ');
+    Serial.print(curr.timestamp);
+    Serial.print(' ');
+    Serial.println(curr.crc);
+  }
+}
+
+static word scanForMarker (word seqnum, long asof) {
+  word lastPage = 0;
+  struct { word seqnum; long timestamp; } last, curr;
+  last.seqnum = 0xFFFF;
+  // go through all the pages in log area of flash
+  for (word page = DF_LOG_BEGIN; page < DF_LOG_LIMIT; ++page) {
+    // read seqnum and timestamp from page in flash
+    df_read(page, sizeof dfBuf.data, &curr, sizeof curr);
+    if (curr.seqnum == 0xFFFF)
+      continue; // page never written to
+    if (curr.seqnum >= seqnum && curr.seqnum < last.seqnum) {
+      last = curr;
+      lastPage = page;
+    }
+    if (curr.seqnum == last.seqnum && curr.timestamp <= asof)
+      lastPage = page;
+  }
+  return lastPage;
+}
+
+static void df_replay (word seqnum, long asof) {
+  word page = scanForMarker(seqnum, asof);
+  Serial.print("r: page ");
+  Serial.print(page);
+  Serial.print(' ');
+  Serial.println(dfLastPage);
+  discardInput();
+  word savedSeqnum = dfBuf.seqnum;
+  while (page != dfLastPage) {
+    if (Serial.read() >= 0)
+      break;
+    page = df_wrap(page + 1);
+    df_read(page, 0, &dfBuf, sizeof dfBuf); // overwrites ram buffer!
+    if (dfBuf.seqnum == 0xFFFF)
+      continue; // page never written to
+    // skip and report bad pages
+    word crc = ~0;
+    for (word i = 0; i < sizeof dfBuf; ++i)
+      crc = _crc16_update(crc, dfBuf.data[i]);
+    if (crc != 0) {
+      Serial.print("DF C? ");
+      Serial.print(page);
+      Serial.print(' ');
+      Serial.println(crc);
+      continue;
+    }
+    // report each entry as "R seqnum time <data...>"
+    byte i = 0;
+    while (i < sizeof dfBuf.data && dfBuf.data[i] < 255) {
+      if (Serial.available())
+        break;
+      Serial.print("R ");
+      Serial.print(dfBuf.seqnum);
+      Serial.print(' ');
+      Serial.print(dfBuf.timestamp + dfBuf.data[i++]);
+      Serial.print(' ');
+      Serial.print((int) dfBuf.data[i++]);
+      byte n = dfBuf.data[i++];
+      while (n-- > 0) {
+        Serial.print(' ');
+        Serial.print((int) dfBuf.data[i++]);
+      }
+      Serial.println();
+    }
+    // at end of each page, report a "DF R" marker, to allow re-starting
+    Serial.print("DF R ");
+    Serial.print(page);
     Serial.print(' ');
     Serial.print(dfBuf.seqnum);
     Serial.print(' ');
     Serial.println(dfBuf.timestamp);
-
-    // erase next block if we just saved data into a fresh block
-    // at this point in time dfBuf is empty, so a lengthy erase cycle is ok
-    if (dfLastPage % DF_BLOCK_SIZE == 0)
-        df_erase(df_wrap(dfLastPage + DF_BLOCK_SIZE));
-}
-
-static void df_append (const void* buf, byte len) {
-    //FIXME the current logic can't append incoming packets during a save!
-
-    // fill in page time stamp when appending to a fresh page
-    if (dfFill == 0)
-        dfBuf.timestamp = now();
-
-    long offset = now() - dfBuf.timestamp;
-    if (offset >= 255 || dfFill + 1 + len > sizeof dfBuf.data) {
-        df_saveBuf();
-
-        dfBuf.timestamp = now();
-        offset = 0;
-    }
-
-    // append new entry to flash buffer
-    dfBuf.data[dfFill++] = offset;
-    memcpy(dfBuf.data + dfFill, buf, len);
-    dfFill += len;
-}
-
-// go through entire log buffer to figure out which page was last saved
-static void scanForLastSave () {
-    dfBuf.seqnum = 0;
-    dfLastPage = DF_LOG_LIMIT - 1;
-    // look for last page before an empty page
-    for (word page = DF_LOG_BEGIN; page < DF_LOG_LIMIT; ++page) {
-        word currseq;
-        df_read(page, sizeof dfBuf.data, &currseq, sizeof currseq);
-        if (currseq != 0xFFFF) {
-            dfLastPage = page;
-            dfBuf.seqnum = currseq + 1;
-        } else if (dfLastPage == page - 1)
-            break; // careful with empty-filled-empty case, i.e. after wrap
-    }
-}
-
-static void df_initialize () {
-    // assumes SPI has already been initialized for the RFM12B
-    df_disable();
-    pinMode(DF_ENABLE_PIN, OUTPUT);
-    df_command(0x9F); // Read Manufacturer and Device ID
-    word info = df_xfer(0) << 8;
-    info |= df_xfer(0);
-    df_deselect();
-
-    if (info == DF_DEVICE_ID) {
-        df_writeCmd(0x01);  // Write Status Register ...
-        df_xfer(0);         // ... Global Unprotect
-        df_deselect();
-
-        scanForLastSave();
-
-        Serial.print("DF I ");
-        Serial.print(dfLastPage);
-        Serial.print(' ');
-        Serial.println(dfBuf.seqnum);
-
-        // df_wipe();
-        df_saveBuf(); //XXX
-    }
-}
-
-static void discardInput () {
-    while (Serial.read() >= 0)
-        ;
-}
-
-static void df_dump () {
-    struct { word seqnum; long timestamp; word crc; } curr;
-    discardInput();
-    for (word page = DF_LOG_BEGIN; page < DF_LOG_LIMIT; ++page) {
-        if (Serial.read() >= 0)
-            break;
-        // read marker from page in flash
-        df_read(page, sizeof dfBuf.data, &curr, sizeof curr);
-        if (curr.seqnum == 0xFFFF)
-            continue; // page never written to
-        Serial.print(" df# ");
-        Serial.print(page);
-        Serial.print(" : ");
-        Serial.print(curr.seqnum);
-        Serial.print(' ');
-        Serial.print(curr.timestamp);
-        Serial.print(' ');
-        Serial.println(curr.crc);
-    }
-}
-
-static word scanForMarker (word seqnum, long asof) {
-    word lastPage = 0;
-    struct { word seqnum; long timestamp; } last, curr;
-    last.seqnum = 0xFFFF;
-    // go through all the pages in log area of flash
-    for (word page = DF_LOG_BEGIN; page < DF_LOG_LIMIT; ++page) {
-        // read seqnum and timestamp from page in flash
-        df_read(page, sizeof dfBuf.data, &curr, sizeof curr);
-        if (curr.seqnum == 0xFFFF)
-            continue; // page never written to
-        if (curr.seqnum >= seqnum && curr.seqnum < last.seqnum) {
-            last = curr;
-            lastPage = page;
-        }
-        if (curr.seqnum == last.seqnum && curr.timestamp <= asof)
-            lastPage = page;
-    }
-    return lastPage;
-}
-
-static void df_replay (word seqnum, long asof) {
-    word page = scanForMarker(seqnum, asof);
-    Serial.print("r: page ");
-    Serial.print(page);
-    Serial.print(' ');
-    Serial.println(dfLastPage);
-    discardInput();
-    word savedSeqnum = dfBuf.seqnum;
-    while (page != dfLastPage) {
-        if (Serial.read() >= 0)
-            break;
-        page = df_wrap(page + 1);
-        df_read(page, 0, &dfBuf, sizeof dfBuf); // overwrites ram buffer!
-        if (dfBuf.seqnum == 0xFFFF)
-            continue; // page never written to
-        // skip and report bad pages
-        word crc = ~0;
-        for (word i = 0; i < sizeof dfBuf; ++i)
-            crc = _crc16_update(crc, dfBuf.data[i]);
-        if (crc != 0) {
-            Serial.print("DF C? ");
-            Serial.print(page);
-            Serial.print(' ');
-            Serial.println(crc);
-            continue;
-        }
-        // report each entry as "R seqnum time <data...>"
-        byte i = 0;
-        while (i < sizeof dfBuf.data && dfBuf.data[i] < 255) {
-            if (Serial.available())
-                break;
-            Serial.print("R ");
-            Serial.print(dfBuf.seqnum);
-            Serial.print(' ');
-            Serial.print(dfBuf.timestamp + dfBuf.data[i++]);
-            Serial.print(' ');
-            Serial.print((int) dfBuf.data[i++]);
-            byte n = dfBuf.data[i++];
-            while (n-- > 0) {
-                Serial.print(' ');
-                Serial.print((int) dfBuf.data[i++]);
-            }
-            Serial.println();
-        }
-        // at end of each page, report a "DF R" marker, to allow re-starting
-        Serial.print("DF R ");
-        Serial.print(page);
-        Serial.print(' ');
-        Serial.print(dfBuf.seqnum);
-        Serial.print(' ');
-        Serial.println(dfBuf.timestamp);
-    }
-    dfFill = 0; // ram buffer is no longer valid
-    dfBuf.seqnum = savedSeqnum + 1; // so next replay will start at a new value
-    Serial.print("DF E ");
-    Serial.print(dfLastPage);
-    Serial.print(' ');
-    Serial.print(dfBuf.seqnum);
-    Serial.print(' ');
-    Serial.println(millis());
+  }
+  dfFill = 0; // ram buffer is no longer valid
+  dfBuf.seqnum = savedSeqnum + 1; // so next replay will start at a new value
+  Serial.print("DF E ");
+  Serial.print(dfLastPage);
+  Serial.print(' ');
+  Serial.print(dfBuf.seqnum);
+  Serial.print(' ');
+  Serial.println(millis());
 }

 #else // DATAFLASH
@@ -542,245 +542,245 @@
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 const char helpText1[] PROGMEM =
-    "\n"
-    "Available commands:" "\n"
-    "  <nn> i     - set node ID (standard node ids are 1..30)" "\n"
-    "  <n> b      - set MHz band (4 = 433, 8 = 868, 9 = 915)" "\n"
-    "  <nnn> g    - set network group (RFM12 only allows 212, 0 = any)" "\n"
-    "  <n> c      - set collect mode (advanced, normally 0)" "\n"
-    "  t          - broadcast max-size test packet, with ack" "\n"
-    "  ...,<nn> a - send data packet to node <nn>, with ack" "\n"
-    "  ...,<nn> s - send data packet to node <nn>, no ack" "\n"
-    "  <n> l      - turn activity LED on PB1 on or off" "\n"
-    "  <n> q      - set quiet mode (1 = don't report bad packets)" "\n"
-    "  <n> x      - set reporting format (0 = decimal, 1 = hex)" "\n"
-    "  123 z      - total power down, needs a reset to start up again" "\n"
-    "Remote control commands:" "\n"
-    "  <hchi>,<hclo>,<addr>,<cmd> f     - FS20 command (868 MHz)" "\n"
-    "  <addr>,<dev>,<on> k              - KAKU command (433 MHz)" "\n"
+  "\n"
+  "Available commands:" "\n"
+  "  <nn> i     - set node ID (standard node ids are 1..30)" "\n"
+  "  <n> b      - set MHz band (4 = 433, 8 = 868, 9 = 915)" "\n"
+  "  <nnn> g    - set network group (RFM12 only allows 212, 0 = any)" "\n"
+  "  <n> c      - set collect mode (advanced, normally 0)" "\n"
+  "  t          - broadcast max-size test packet, with ack" "\n"
+  "  ...,<nn> a - send data packet to node <nn>, with ack" "\n"
+  "  ...,<nn> s - send data packet to node <nn>, no ack" "\n"
+  "  <n> l      - turn activity LED on PB1 on or off" "\n"
+  "  <n> q      - set quiet mode (1 = don't report bad packets)" "\n"
+  "  <n> x      - set reporting format (0 = decimal, 1 = hex)" "\n"
+  "  123 z      - total power down, needs a reset to start up again" "\n"
+  "Remote control commands:" "\n"
+  "  <hchi>,<hclo>,<addr>,<cmd> f     - FS20 command (868 MHz)" "\n"
+  "  <addr>,<dev>,<on> k              - KAKU command (433 MHz)" "\n"
 ;
 const char helpText2[] PROGMEM =
-    "Flash storage (JeeLink only):" "\n"
-    "  d                                - dump all log markers" "\n"
-    "  <sh>,<sl>,<t3>,<t2>,<t1>,<t0> r  - replay from specified marker" "\n"
-    "  123,<bhi>,<blo> e                - erase 4K block" "\n"
-    "  12,34 w                          - wipe entire flash memory" "\n"
+  "Flash storage (JeeLink only):" "\n"
+  "  d                                - dump all log markers" "\n"
+  "  <sh>,<sl>,<t3>,<t2>,<t1>,<t0> r  - replay from specified marker" "\n"
+  "  123,<bhi>,<blo> e                - erase 4K block" "\n"
+  "  12,34 w                          - wipe entire flash memory" "\n"
 ;

 static void showString (PGM_P s) {
-    for (;;) {
-        char c = pgm_read_byte(s++);
-        if (c == 0)
-            break;
-        if (c == '\n')
-            Serial.print('\r');
-        Serial.print(c);
-    }
+  for (;;) {
+    char c = pgm_read_byte(s++);
+    if (c == 0)
+      break;
+    if (c == '\n')
+      Serial.print('\r');
+    Serial.print(c);
+  }
 }

 static void showHelp () {
-    showString(helpText1);
-    if (df_present())
-        showString(helpText2);
-    Serial.println("Current configuration:");
-    rf12_config();
+  showString(helpText1);
+  if (df_present())
+    showString(helpText2);
+  Serial.println("Current configuration:");
+  rf12_config();
 }

 static void handleInput (char c) {
-    if ('0' <= c && c <= '9')
-        value = 10 * value + c - '0';
-    else if (c == ',') {
-        if (top < sizeof stack)
-            stack[top++] = value;
-        value = 0;
-    } else if ('a' <= c && c <='z' || 'A' <= c && c <= 'Z') {
-        Serial.print("> ");
-        for (byte i = 0; i < top; ++i) {
-            Serial.print((int) stack[i]);
-            Serial.print(',');
+  if ('0' <= c && c <= '9')
+    value = 10 * value + c - '0';
+  else if (c == ',') {
+    if (top < sizeof stack)
+      stack[top++] = value;
+    value = 0;
+  } else if ('a' <= c && c <='z' || 'A' <= c && c <= 'Z') {
+    Serial.print("> ");
+    for (byte i = 0; i < top; ++i) {
+      Serial.print((int) stack[i]);
+      Serial.print(',');
+    }
+    Serial.print((int) value);
+    Serial.println(c);
+    switch (c) {
+      default:
+        showHelp();
+        break;
+      case 'i': // set node id
+        config.nodeId = (config.nodeId & 0xE0) + (value & 0x1F);
+        saveConfig();
+        break;
+      case 'b': // set band: 4 = 433, 8 = 868, 9 = 915
+        value = value == 8 ? RF12_868MHZ :
+            value == 9 ? RF12_915MHZ : RF12_433MHZ;
+        config.nodeId = (value << 6) + (config.nodeId & 0x3F);
+        saveConfig();
+        break;
+      case 'g': // set network group
+        config.group = value;
+        saveConfig();
+        break;
+      case 'c': // set collect mode (off = 0, on = 1)
+        if (value)
+          config.nodeId |= COLLECT;
+        else
+          config.nodeId &= ~COLLECT;
+        saveConfig();
+        break;
+      case 't': // broadcast a maximum size test packet, request an ack
+        cmd = 'a';
+        sendLen = RF12_MAXDATA;
+        dest = 0;
+        for (byte i = 0; i < RF12_MAXDATA; ++i)
+          testbuf[i] = i + testCounter;
+        Serial.print("test ");
+        Serial.println((int) testCounter); // first byte in test buffer
+        ++testCounter;
+        break;
+      case 'a': // send packet to node ID N, request an ack
+      case 's': // send packet to node ID N, no ack
+        cmd = c;
+        sendLen = top;
+        dest = value;
+        memcpy(testbuf, stack, top);
+        break;
+      case 'l': // turn activity LED on or off
+        activityLed(value);
+        break;
+      case 'f': // send FS20 command: <hchi>,<hclo>,<addr>,<cmd>f
+        rf12_initialize(0, RF12_868MHZ);
+        activityLed(1);
+        fs20cmd(256 * stack[0] + stack[1], stack[2], value);
+        activityLed(0);
+        rf12_config(); // restore normal packet listening mode
+        break;
+      case 'k': // send KAKU command: <addr>,<dev>,<on>k
+        rf12_initialize(0, RF12_433MHZ);
+        activityLed(1);
+        kakuSend(stack[0], stack[1], value);
+        activityLed(0);
+        rf12_config(); // restore normal packet listening mode
+        break;
+      case 'd': // dump all log markers
+        if (df_present())
+          df_dump();
+        break;
+      case 'r': // replay from specified seqnum/time marker
+        if (df_present()) {
+          word seqnum = (stack[0] << 8) || stack[1];
+          long asof = (stack[2] << 8) || stack[3];
+          asof = (asof << 16) | ((stack[4] << 8) || value);
+          df_replay(seqnum, asof);
         }
-        Serial.print((int) value);
-        Serial.println(c);
-        switch (c) {
-            default:
-                showHelp();
-                break;
-            case 'i': // set node id
-                config.nodeId = (config.nodeId & 0xE0) + (value & 0x1F);
-                saveConfig();
-                break;
-            case 'b': // set band: 4 = 433, 8 = 868, 9 = 915
-                value = value == 8 ? RF12_868MHZ :
-                        value == 9 ? RF12_915MHZ : RF12_433MHZ;
-                config.nodeId = (value << 6) + (config.nodeId & 0x3F);
-                saveConfig();
-                break;
-            case 'g': // set network group
-                config.group = value;
-                saveConfig();
-                break;
-            case 'c': // set collect mode (off = 0, on = 1)
-                if (value)
-                    config.nodeId |= COLLECT;
-                else
-                    config.nodeId &= ~COLLECT;
-                saveConfig();
-                break;
-            case 't': // broadcast a maximum size test packet, request an ack
-                cmd = 'a';
-                sendLen = RF12_MAXDATA;
-                dest = 0;
-                for (byte i = 0; i < RF12_MAXDATA; ++i)
-                    testbuf[i] = i + testCounter;
-                Serial.print("test ");
-                Serial.println((int) testCounter); // first byte in test buffer
-                ++testCounter;
-                break;
-            case 'a': // send packet to node ID N, request an ack
-            case 's': // send packet to node ID N, no ack
-                cmd = c;
-                sendLen = top;
-                dest = value;
-                memcpy(testbuf, stack, top);
-                break;
-            case 'l': // turn activity LED on or off
-                activityLed(value);
-                break;
-            case 'f': // send FS20 command: <hchi>,<hclo>,<addr>,<cmd>f
-                rf12_initialize(0, RF12_868MHZ);
-                activityLed(1);
-                fs20cmd(256 * stack[0] + stack[1], stack[2], value);
-                activityLed(0);
-                rf12_config(); // restore normal packet listening mode
-                break;
-            case 'k': // send KAKU command: <addr>,<dev>,<on>k
-                rf12_initialize(0, RF12_433MHZ);
-                activityLed(1);
-                kakuSend(stack[0], stack[1], value);
-                activityLed(0);
-                rf12_config(); // restore normal packet listening mode
-                break;
-            case 'd': // dump all log markers
-                if (df_present())
-                    df_dump();
-                break;
-            case 'r': // replay from specified seqnum/time marker
-                if (df_present()) {
-                    word seqnum = (stack[0] << 8) || stack[1];
-                    long asof = (stack[2] << 8) || stack[3];
-                    asof = (asof << 16) | ((stack[4] << 8) || value);
-                    df_replay(seqnum, asof);
-                }
-                break;
-            case 'e': // erase specified 4Kb block
-                if (df_present() && stack[0] == 123) {
-                    word block = (stack[1] << 8) | value;
-                    df_erase(block);
-                }
-                break;
-            case 'w': // wipe entire flash memory
-                if (df_present() && stack[0] == 12 && value == 34) {
-                    df_wipe();
-                    Serial.println("erased");
-                }
-                break;
-            case 'q': // turn quiet mode on or off (don't report bad packets)
-                quiet = value;
-                break;
-            case 'z': // put the ATmega in ultra-low power mode (reset needed)
-                if (value == 123) {
-                    delay(10);
-                    rf12_sleep(RF12_SLEEP);
-                    cli();
-                    Sleepy::powerDown();
-                }
-                break;
-            case 'x': // set reporting mode to hex (1) or decimal (0)
-                useHex = value;
-                break;
+        break;
+      case 'e': // erase specified 4Kb block
+        if (df_present() && stack[0] == 123) {
+          word block = (stack[1] << 8) | value;
+          df_erase(block);
         }
-        value = top = 0;
-        memset(stack, 0, sizeof stack);
-    } else if (c > ' ')
-        showHelp();
+        break;
+      case 'w': // wipe entire flash memory
+        if (df_present() && stack[0] == 12 && value == 34) {
+          df_wipe();
+          Serial.println("erased");
+        }
+        break;
+      case 'q': // turn quiet mode on or off (don't report bad packets)
+        quiet = value;
+        break;
+      case 'z': // put the ATmega in ultra-low power mode (reset needed)
+        if (value == 123) {
+          delay(10);
+          rf12_sleep(RF12_SLEEP);
+          cli();
+          Sleepy::powerDown();
+        }
+        break;
+      case 'x': // set reporting mode to hex (1) or decimal (0)
+        useHex = value;
+        break;
+    }
+    value = top = 0;
+    memset(stack, 0, sizeof stack);
+  } else if (c > ' ')
+    showHelp();
 }

 void setup() {
-    Serial.begin(SERIAL_BAUD);
-    Serial.print("\n[RF12demo.10]");
+  Serial.begin(SERIAL_BAUD);
+  Serial.print("\n[RF12demo.10]");
+  activityLed(0);
+
+  if (rf12_config()) {
+    config.nodeId = eeprom_read_byte(RF12_EEPROM_ADDR);
+    config.group = eeprom_read_byte(RF12_EEPROM_ADDR + 1);
+  } else {
+    config.nodeId = 0x41; // 433 MHz, node 1
+    config.group = 0xD4;  // default group 212
+    saveConfig();
+  }
+
+  df_initialize();
+
+  showHelp();
+}
+
+void loop() {
+  if (Serial.available())
+    handleInput(Serial.read());
+
+  if (rf12_recvDone()) {
+    byte n = rf12_len;
+    if (rf12_crc == 0)
+      Serial.print("OK");
+    else {
+      if (quiet)
+        return;
+      Serial.print(" ?");
+      if (n > 20) // print at most 20 bytes if crc is wrong
+        n = 20;
+    }
+    if (useHex)
+      Serial.print('X');
+    if (config.group == 0) {
+      Serial.print(" G");
+      showByte(rf12_grp);
+    }
+    Serial.print(' ');
+    showByte(rf12_hdr);
+    for (byte i = 0; i < n; ++i) {
+      if (!useHex)
+        Serial.print(' ');
+      showByte(rf12_data[i]);
+    }
+    Serial.println();
+
+    if (rf12_crc == 0) {
+      activityLed(1);
+
+      if (df_present())
+        df_append((const char*) rf12_data - 2, rf12_len + 2);
+
+      if (RF12_WANTS_ACK && (config.nodeId & COLLECT) == 0) {
+        Serial.println(" -> ack");
+        rf12_sendStart(RF12_ACK_REPLY, 0, 0);
+      }
+
+      activityLed(0);
+    }
+  }
+
+  if (cmd && rf12_canSend()) {
+    activityLed(1);
+
+    Serial.print(" -> ");
+    Serial.print((int) sendLen);
+    Serial.println(" b");
+    byte header = cmd == 'a' ? RF12_HDR_ACK : 0;
+    if (dest)
+      header |= RF12_HDR_DST | dest;
+    rf12_sendStart(header, testbuf, sendLen);
+    cmd = 0;
+
     activityLed(0);
-
-    if (rf12_config()) {
-        config.nodeId = eeprom_read_byte(RF12_EEPROM_ADDR);
-        config.group = eeprom_read_byte(RF12_EEPROM_ADDR + 1);
-    } else {
-        config.nodeId = 0x41; // 433 MHz, node 1
-        config.group = 0xD4;  // default group 212
-        saveConfig();
-    }
-
-    df_initialize();
-
-    showHelp();
-}
-
-void loop() {
-    if (Serial.available())
-        handleInput(Serial.read());
-
-    if (rf12_recvDone()) {
-        byte n = rf12_len;
-        if (rf12_crc == 0)
-            Serial.print("OK");
-        else {
-            if (quiet)
-                return;
-            Serial.print(" ?");
-            if (n > 20) // print at most 20 bytes if crc is wrong
-                n = 20;
-        }
-        if (useHex)
-            Serial.print('X');
-        if (config.group == 0) {
-            Serial.print(" G");
-            showByte(rf12_grp);
-        }
-        Serial.print(' ');
-        showByte(rf12_hdr);
-        for (byte i = 0; i < n; ++i) {
-            if (!useHex)
-                Serial.print(' ');
-            showByte(rf12_data[i]);
-        }
-        Serial.println();
-
-        if (rf12_crc == 0) {
-            activityLed(1);
-
-            if (df_present())
-                df_append((const char*) rf12_data - 2, rf12_len + 2);
-
-            if (RF12_WANTS_ACK && (config.nodeId & COLLECT) == 0) {
-                Serial.println(" -> ack");
-                rf12_sendStart(RF12_ACK_REPLY, 0, 0);
-            }
-
-            activityLed(0);
-        }
-    }
-
-    if (cmd && rf12_canSend()) {
-        activityLed(1);
-
-        Serial.print(" -> ");
-        Serial.print((int) sendLen);
-        Serial.println(" b");
-        byte header = cmd == 'a' ? RF12_HDR_ACK : 0;
-        if (dest)
-            header |= RF12_HDR_DST | dest;
-        rf12_sendStart(header, testbuf, sendLen);
-        cmd = 0;
-
-        activityLed(0);
-    }
-}
+  }
+}


- fixed Simple player

- fixed Simple player

--- firmware/examples/simple_player.ino
+++ firmware/examples/simple_player.ino
@@ -1,5 +1,5 @@
 #include "application.h"
-#include "Wtv020sd16p.h"
+#include "Wtv020sd16p/Wtv020sd16p.h"

 #define WTV020_RESET_PIN D2  // The pin number of the reset pin.
 #define WTV020_CLOCK_PIN D3  // The pin number of the clock pin.


m tidy up :shipit:

m tidy up :shipit:

--- switchcube.ino
+++ switchcube.ino
@@ -1,155 +0,0 @@
-
-// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
-// for both classes must be in the include path of the project
-#include "I2Cdev.h"
-#include "MPU6050.h"
-
-// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
-// is used in I2Cdev.h
-#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
-#include "Wire.h"
-#endif
-
-// class default I2C address is 0x68
-// specific I2C addresses may be passed as a parameter here
-// AD0 low = 0x68 (default)
-// AD0 high = 0x69
-MPU6050 mpu;
-//MPU6050 mpu(0x69); // <-- use for AD0 high
-
-int16_t ax, ay, az; // accel values
-int16_t gx, gy, gz; // gyro values
-
-// uncomment "OUTPUT_READABLE_mpu" if you want to see a tab-separated
-// list of the accel X/Y/Z and then gyro X/Y/Z values in decimal. Easy to read,
-// not so easy to parse, and slow(er) over UART.
-#define OUTPUT_READABLE_mpu
-
-// uncomment "OUTPUT_BINARY_mpu" to send all 6 axes of data as 16-bit
-// binary, one right after the other. This is very fast (as fast as possible
-// without compression or data loss), and easy to parse, but impossible to read
-// for a human.
-// #define OUTPUT_BINARY_mpu
-
-#define STATUS_LED_PIN 5
-bool blinkState = false;
-
-void setup() {
-  // initialize serial communication
-  // (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
-  // it's really up to you depending on your project)
-  pinMode(3,OUTPUT);
-  digitalWrite(3, HIGH); // Vcc for MPU6050
-  Serial.begin(115200);
-  delay(128);
-  // initialize device
-  Serial.println(F("Initializing devices..."));
-  // join I2C bus (I2Cdev library doesn't do this automatically)
-#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
-  Serial.println(F("I2CSetup"));
-  Wire.begin();
-#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
-  Serial.println(F("FastwireSetup"));
-  Fastwire::setup(400, true);
-#endif
-  Serial.println(F("mpu.initialize"));
-  mpu.initialize();
-  // verify connection
-  Serial.println(F("Testing device connections..."));
-  Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
-  mpu.setDLPFMode(6); // 5Hz low pass
-  mpu.setDHPFMode(4); // 0.625Hz high pass
-  mpu.setFullScaleAccelRange(2);
-  mpu.setFullScaleGyroRange(3);
-  //    Wire.write(0x16);            // register DLPF_CFG - low pass filter configuration & sample rate
-  //    Wire.write(0x1D);            //   10Hz Low Pass Filter Bandwidth - Internal Sample Rate 1kHz
-
-  Serial.println(F("Reading/Updating internal sensor offsets..."));
-  // -76	-2359	1688	0	0	0
-  //-596	-585	664	0	0	0
-  Serial.print(mpu.getXAccelOffset());
-  Serial.print(F("\t")); // -76
-  Serial.print(mpu.getYAccelOffset());
-  Serial.print(F("\t")); // -2359
-  Serial.print(mpu.getZAccelOffset());
-  Serial.print(F("\t")); // 1688
-  Serial.print(mpu.getXGyroOffset());
-  Serial.print(F("\t")); // 0
-  Serial.print(mpu.getYGyroOffset());
-  Serial.print(F("\t")); // 0
-  Serial.print(mpu.getZGyroOffset());
-  Serial.print(F("\t")); // 0
-  Serial.print(F("\n"));
-
-  // change accel/gyro offset values
-  mpu.setXGyroOffset(28);
-  mpu.setYGyroOffset(6);
-  mpu.setZGyroOffset(13);
-
-  Serial.print(mpu.getXAccelOffset());
-  Serial.print(F("\t")); // -76
-  Serial.print(mpu.getYAccelOffset());
-  Serial.print(F("\t")); // -2359
-  Serial.print(mpu.getZAccelOffset());
-  Serial.print(F("\t")); // 1688
-  Serial.print(mpu.getXGyroOffset());
-  Serial.print(F("\t")); // 0
-  Serial.print(mpu.getYGyroOffset());
-  Serial.print(F("\t")); // 0
-  Serial.print(mpu.getZGyroOffset());
-  Serial.print(F("\t")); // 0
-  Serial.print(F("\n"));
-
-  // configure Arduino LED for output
-  pinMode(STATUS_LED_PIN, OUTPUT);
-}
-
-void loop() {
-  // read raw accel/gyro measurements from device
-  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
-  // these methods (and a few others) are also available
-  //mpu.getAcceleration(&ax, &ay, &az);
-  //mpu.getRotation(&gx, &gy, &gz);
-
-#ifdef OUTPUT_READABLE_mpu
-  // display tab-separated accel/gyro x/y/z values
-  Serial.print(F("a/g:\t"));
-  Serial.print(ax);
-  Serial.print(F("\t"));
-  Serial.print(ay);
-  Serial.print(F("\t"));
-  Serial.print(az);
-  Serial.print(F("\t"));
-  Serial.print(gx);
-  Serial.print(F("\t"));
-  Serial.print(gy);
-  Serial.print(F("\t"));
-  Serial.print(gz);
-  Serial.print(F("\t"));
-  double dT = ( (double) mpu.getTemperature() + 12412.0) / 340.0;
-  Serial.print(dT, 3);
-  Serial.print(F("C \t"));
-  Serial.println();
-#endif
-
-#ifdef OUTPUT_BINARY_mpu
-  Serial.write((uint8_t)(ax >> 8));
-  Serial.write((uint8_t)(ax & 0xFF));
-  Serial.write((uint8_t)(ay >> 8));
-  Serial.write((uint8_t)(ay & 0xFF));
-  Serial.write((uint8_t)(az >> 8));
-  Serial.write((uint8_t)(az & 0xFF));
-  Serial.write((uint8_t)(gx >> 8));
-  Serial.write((uint8_t)(gx & 0xFF));
-  Serial.write((uint8_t)(gy >> 8));
-  Serial.write((uint8_t)(gy & 0xFF));
-  Serial.write((uint8_t)(gz >> 8));
-  Serial.write((uint8_t)(gz & 0xFF));
-#endif
-
-  // blink LED to indicate activity
-  blinkState = !blinkState;
-  digitalWrite(STATUS_LED_PIN, blinkState);
-  delay(100);
-}
-


next move will not be made until the previous one has not finished

--- jenny5-firmware/jenny5-firmware.ino
+++ jenny5-firmware/jenny5-firmware.ino
@@ -7,14 +7,18 @@
 int step_pins[num_motors] = {3,6,9,12};
 int enable_pins[4] = {4,7,10,13};

-int default_motor_speed = 3200; //maximum steps per second
+int default_motor_speed = 200; //maximum steps per second
 int default_motor_acceleration = 800; //steps/second/second to accelerate

-char firmware_version[] = "2015.11.09.4";
+char is_command_running;
+
+char firmware_version[] = "2015.11.10.6";

 AccelStepper *steppers[num_motors];

 char current_buffer[65];
+
+#define DEBUG

 //--------------------------------------------------------------------------------------------
 void setup()
@@ -44,19 +48,26 @@
   Serial.println();

   current_buffer[0] = 0;
+  is_command_running = 0;
 }
 //--------------------------------------------------------------------------------------------
 //Main loop
 void loop() {

-  if (Serial.available()) {
+  if (!is_command_running && (Serial.available() || current_buffer[0])) {
     int num_read = 0;
     char arduino_buffer[65];

     num_read = Serial.readBytes(arduino_buffer, 64); //Read up to 64 bytes
     arduino_buffer[num_read] = 0;// terminate the string
-    if (num_read){
+    if (arduino_buffer[0] || current_buffer[0]){
       strcat(current_buffer, arduino_buffer);
+
+      #ifdef DEBUG
+      Serial.write("initial buffer is=");
+      Serial.write(current_buffer);
+      #endif
+
       // parse from the beginning until I find a M, D, S or A
       int buffer_length = strlen(current_buffer);
       for (int i = 0; i < buffer_length; i++)
@@ -68,12 +79,27 @@
               char tmp_str[64];
               strncpy(tmp_str, current_buffer + i + 1, j - i - 1);
               tmp_str[j - i - 1] = 0;
+
+              #ifdef DEBUG
+              Serial.write("current command is=");
+              Serial.write(tmp_str);
+              #endif
+
               int motor_index, num_steps;
               sscanf(tmp_str, "%d%d", &motor_index, &num_steps);
               move_motor(motor_index, num_steps);
+              is_command_running = 1;
+
               // remove the current executed command
               strcpy(current_buffer, current_buffer + j + 1);
-              break;
+
+              #ifdef DEBUG
+              Serial.write("buffer left=");
+              Serial.write(current_buffer);
+              Serial.println(strlen(current_buffer));
+              #endif
+
+              break; //for i
           }
           else{// the string is not completed ... so I must wait more...
             break; // for i
@@ -104,11 +130,17 @@
   }

 // run motors
+  bool is_one_motor_running = false;
   for (int m = 0; m < num_motors; m++)
-    if (steppers[m]->distanceToGo())
+    if (steppers[m]->distanceToGo()){
       steppers[m]->run();
-    else
-      steppers[m]->setCurrentPosition(0);
+      is_one_motor_running = true;
+    }
+    else{
+      steppers[m]->setCurrentPosition(0);
+    }
+  if (!is_one_motor_running)
+    is_command_running = 0;
 }
 //--------------------------------------------------------------------------------------------
 void move_motor(int motor_index, int num_steps)


auto format

auto format

--- _09_ir_tx_rx/_09_ir_tx_rx.ino
+++ _09_ir_tx_rx/_09_ir_tx_rx.ino
@@ -386,10 +386,10 @@
       case 0xFF02FD: // remote on
         if ( o_wrkMode == 0 ) {
           t.stop(tvIsOffEvent);
-          t.stop(tvIsOnEvent);
+          t.stop(tvIsOnEvent);
         } else {
-          tvOnTimer();
-          temp_Mills = millis();
+          tvOnTimer();
+          temp_Mills = millis();
         }
         o_wrkMode = ! o_wrkMode;
         o_startMode = 1;
@@ -398,9 +398,9 @@
       case 0xFF9867: // remote off
         if ( timerStatus == 1 ) {
           t.stop(tvIsOffEvent);
-          t.stop(tvIsOnEvent);
+          t.stop(tvIsOnEvent);
         } else {
-          tvOnTimer();
+          tvOnTimer();
           temp_Mills = millis();
         }
         timerStatus = ! timerStatus;
@@ -411,7 +411,7 @@
           t.stop(tvIsOffEvent);
           t.stop(tvIsOnEvent);
         } else {
-          tvOnTimer();
+          tvOnTimer();
           temp_Mills = millis();
         }
         tvPowerStatus = ! tvPowerStatus;
@@ -432,7 +432,7 @@
     pir_Mills = millis();
   }
 }
-
+
 void tvOnTimer()
 {
   t.stop(tvIsOffEvent);
@@ -462,25 +462,25 @@
     tvOnTimer();
     lcd.setCursor(15, 0);
     lcd.print(" ");
-  }
-}
-
-//
+  }
+}
+
+//
 void doTvControlbyPir(int onoff)
 {
-   if ( o_wrkMode == 1 && o_startMode == 1 ) {
-      switch (onoff) {
-        case 1:
-          lcd.setCursor(15, 0);
-          lcd.print(" ");
-          irSendTvbypir(1);
-          break;
-        case 0:
-          lcd.setCursor(15, 0);
-          lcd.write(6);
-          irSendTvbypir(0);
-          break;
-      }
+  if ( o_wrkMode == 1 && o_startMode == 1 ) {
+    switch (onoff) {
+      case 1:
+        lcd.setCursor(15, 0);
+        lcd.print(" ");
+        irSendTvbypir(1);
+        break;
+      case 0:
+        lcd.setCursor(15, 0);
+        lcd.write(6);
+        irSendTvbypir(0);
+        break;
+    }
   }
   r = !r;
 }
@@ -508,15 +508,15 @@
   }
 }

-void irSendTvbypir()
+void irSendTvbypir()
 {
   if ( tvPowerStatus == 1 ) {
     switch (onoff) {
       case 1:
-          irSendTvOut(1);
+        irSendTvOut(1);
         break;
       case 0:
-          irSendTvOut(0);
+        irSendTvOut(0);
         break;
     }
   }
@@ -539,7 +539,7 @@
           irsend.sendNEC(tv_left, 32);
           delay(300);
         }
-        irsend.sendNEC(tv_enter, 32);
+        irsend.sendNEC(tv_enter, 32);
         break;
       case 1:
         irsend.sendNEC(tv_input, 32);


added excel timestamp to logger

added excel timestamp to logger

--- code/arduino/logger/logger_sketch/logger_sketch.ino
+++ code/arduino/logger/logger_sketch/logger_sketch.ino
@@ -13,7 +13,6 @@
 #include <TimeAlarms.h>
 #include <DS1307RTC.h>
 #include <dht11.h>
-

 #include <SPI.h>
 #include <SD.h>
@@ -61,12 +60,17 @@

 void log_data() {

-    char buffer[17] ;
+    char buffer[26] ;
+    // timestamp
     int hh = hour();
     int mm = minute();
     int ss = second();
-    // time
-    sprintf(buffer,"%02d:%02d:%02d,",hh,mm,ss);
+	int yyyy = year();
+	int mm = month();
+	int dd = day();
+
+	// 18 char excel timestamp
+    sprintf(buffer,"%02d-%02d-%02d %02d:%02d:%02d,",yyyy,mm,dd,hh,mm,ss);

     int dht11_code = DHT11.read(DHT11_PIN);
     micro_delay(200);
@@ -80,13 +84,13 @@

     if(dht11_code != 0 ) {
         // error
-        sprintf(buffer+9,"%7s","error");
+        sprintf(buffer+18,"%7s","error");

     } else {
-        sprintf(buffer+9,"%-03d,%-03d",DHT11.temperature,DHT11.humidity);
+        sprintf(buffer+18,"%-03d,%-03d",DHT11.temperature,DHT11.humidity);
     }

-    buffer[16] = '\0' ;
+    buffer[25] = '\0' ;

     // write to SD card
     dataFile.println(buffer);


can now detect connections between any top shelf sockets

--- arduino/modularsynth/modularsynth.ino
+++ arduino/modularsynth/modularsynth.ino
@@ -4,8 +4,7 @@
 const int READ_SELECT_3 = 5;

 // pins for reading from multiplexers
-const int READ_MUX_1 = 22;
-const int READ_MUX_2 = 23; // actually there's only 1 at the moment
+const int READ_MUX_PINS[] = {22, 23, 24, 25, 26, 27, 28, 29};

 // pins for selecting demux channel for writing
 const int WRITE_SELECT_1 = 10;
@@ -23,8 +22,6 @@
   pinMode(READ_SELECT_1,OUTPUT);
   pinMode(READ_SELECT_2,OUTPUT);
   pinMode(READ_SELECT_3,OUTPUT);
-  pinMode(READ_MUX_1,INPUT);
-  pinMode(READ_MUX_2,INPUT);
   pinMode(WRITE_SELECT_1,OUTPUT);
   pinMode(WRITE_SELECT_2,OUTPUT);
   pinMode(WRITE_SELECT_3,OUTPUT);
@@ -32,9 +29,9 @@
   pinMode(DEMUX_SELECT_2,OUTPUT);
   pinMode(DEMUX_SELECT_3,OUTPUT);
   pinMode(13, OUTPUT);
-  digitalWrite(DEMUX_SELECT_1, bitRead(4,0));
-  digitalWrite(DEMUX_SELECT_2, bitRead(4,1));
-  digitalWrite(DEMUX_SELECT_3, bitRead(4,2));
+  for(int i=0;i<8;i++) {
+    pinMode(READ_MUX_PINS[i], INPUT);
+  }
   Serial.begin(9600);
   Serial1.begin(31250);
 }
@@ -56,26 +53,41 @@
 bool gate = false;

 void loop() {
-  int i,j;
-  for(i=0;i<8;i++) {
-    digitalWrite(WRITE_SELECT_1,bitRead(i,0));
-    digitalWrite(WRITE_SELECT_2,bitRead(i,1));
-    digitalWrite(WRITE_SELECT_3,bitRead(i,2));
+  int i,j,k,m;
+
+  // supply 5V to each "write" demultiplexer in turn
+  for(i=0;i<2;i++) {
+    digitalWrite(DEMUX_SELECT_1,bitRead(i,0));
+    digitalWrite(DEMUX_SELECT_2,bitRead(i,1));
+    digitalWrite(DEMUX_SELECT_3,bitRead(i,2));
+
+    // supply 5V to each pin in turn
     for(j=0;j<8;j++) {
-      checkMidi();
-      if(i<j) {
-        digitalWrite(READ_SELECT_1,bitRead(j,0));
-        digitalWrite(READ_SELECT_2,bitRead(j,1));
-        digitalWrite(READ_SELECT_3,bitRead(j,2));
-        if(digitalRead(READ_MUX_1)==HIGH) {
-          Serial.print(i);
-          Serial.print("-");
-          Serial.print(j);
-          Serial.print("\n");
+      digitalWrite(WRITE_SELECT_1,bitRead(j,0));
+      digitalWrite(WRITE_SELECT_2,bitRead(j,1));
+      digitalWrite(WRITE_SELECT_3,bitRead(j,2));
+
+      // select "read" multiplexer pins in turn (for all multiplexers simultaneously)
+      for(k=0;k<8;k++) {
+        digitalWrite(READ_SELECT_1,bitRead(k,0));
+        digitalWrite(READ_SELECT_2,bitRead(k,1));
+        digitalWrite(READ_SELECT_3,bitRead(k,2));
+
+        // read from each multiplexer in turn
+        for(m=0;m<2;m++) {
+          if(i*8+j<m*8+k) {
+            if(digitalRead(READ_MUX_PINS[m])==HIGH) {
+              Serial.print(i*8 + j);
+              Serial.print("-");
+              Serial.print(m*8 + k);
+              Serial.print("\n");
+            }
+          }
         }
       }
     }
   }
+
   //checkMidi();
   for(byte i = 0; i < 0; i ++) {
     checkMidi();


Update ThingspeakWriteSingleField.ino

Update ThingspeakWriteSingleField.ino

--- Arduino/NetworkCommunication/ThingspeakWriteSingleField/ThingspeakWriteSingleField.ino
+++ Arduino/NetworkCommunication/ThingspeakWriteSingleField/ThingspeakWriteSingleField.ino
@@ -81,5 +81,5 @@

   photocell = analogRead(0);

-  delay(20000); // Wait 5 seconds to update the channel again
+  delay(20000); // Wait 20 seconds to update the channel again
 }


Adjusting some defaults after testing production deployment :)

--- projects/SumpPumpController/Arduino/Arduino.ino
+++ projects/SumpPumpController/Arduino/Arduino.ino
@@ -22,13 +22,13 @@
   30, //int acPumpOnTimeWarning; // number of seconds AC pump can be on at a time before warning
   86400UL, //unsigned long selftestTimeBetween; // Minimum number of seconds between self tests
   20, //byte selfTestTimeLimit; // Length of DC Pump self test, if depth measurement is not met (seconds)
-  30, //int selfTestMinDepth; // Minimum depth needed to initialize self test
-  5, //int selfTestDepthDiff; // How much water lefel should drop for self test to be considered OK
+  24, //int selfTestMinDepth; // Minimum depth needed to initialize self test
+  5, //int selfTestDepthDiff; // How much water level should drop for self test to be considered OK
   1, //byte depthMeasureTime; // Frequency with which water level should be read (seconds)
   false, //boolean buzzerEnabled; // whether buzzer should sound in case of alert or not
   512, //int zeroPressure; // 0-point for pressure sensor
-  6, //int pointsPerCm; // points per CM, can be negative, depending on which side of the differential measuring tube is connected
-     // 5mv per point; 58 points per kPa, 17 Pa per point, 98Pa per CM, 5.7 points per CM
+  5, //int pointsPerCm; // points per CM, can be negative, depending on which side of the differential measuring tube is connected
+     // 5mv per point; 58 points per kPa, 17 Pa per point, 98Pa per CM, 5.7 points per CM (rounding down, just in case)
   60 //int dcPumpOnTimeWarning; // how long DC pump can be on at a time before warning (seconds)
 };


targetBearing based on location

targetBearing based on location

--- master/master.ino
+++ master/master.ino
@@ -1159,11 +1159,30 @@
 		/* end tsops */

 		/* goal detection */
+#ifdef PIXY_ENABLED
 		getGoalData();
 		/* end goal detection */
-
+#endif
 		/* face forwards */
-		targetBearing = goalAngle_r_field; // always face goals
+		if (goalDetected){
+			targetBearing = goalAngle_r_field * 1.3; // always face goals
+		}
+		else if (linelocation == LINELOCATION::SIDE_LEFT){
+			targetBearing = 45;
+		}
+		else if (linelocation == LINELOCATION::SIDE_RIGHT){
+			targetBearing = -45;
+		}
+		else if (linelocation == LINELOCATION::CORNER_TOP_LEFT){
+			targetBearing = 90;
+		}
+		else if (linelocation == LINELOCATION::CORNER_TOP_RIGHT){
+			targetBearing = -90;
+		}
+		else{
+			targetBearing = 0;
+		}
+
 		tsopAngle_r_targetBearing = tsopAngle_r_field - targetBearing; // target bearing is relative to field
 		TOBEARING180(tsopAngle_r_targetBearing);


form tinkering

form tinkering

--- ardesp/waterelf/waterelf.ino
+++ ardesp/waterelf/waterelf.ino
@@ -52,7 +52,7 @@
   "
Configure server location
\n"
   "
\n"
     "<form method='POST' action='actuate'>\n"
-    "Operate actuator: "
+    "External power: "
     "on <input type='radio' name='state' value='on'>\n"
     "off <input type='radio' name='state' value='off' checked>\n"
     "<input type='submit' value='Submit'></form>\n"
@@ -389,9 +389,9 @@
   f += "<form method='POST' action='svrchz'> ";
   f += "
Local server IP address: ";
   f += "<input type='textarea' name='svraddr'>

 ";
-  f += "Sharing on WeGrow.social:
";
+  f += "Sharing on WeGrow.social: ";
   f += "on <input type='radio' name='wegrow' value='on' checked>\n";
-  f += "off <input type='radio' name='wegrow' value='off'>\n";
+  f += "off <input type='radio' name='wegrow' value='off'>

\n";
   f += "<input type='submit' value='Submit'></form>
";

   f += pageFooter;


Makes random game run longer.

Makes random game run longer.

--- arduboy-game/arduboy-game.ino
+++ arduboy-game/arduboy-game.ino
@@ -106,7 +106,7 @@
   score = 0;

   // Random test to set score
-  unsigned int randomScore = random(4000, 99999);
+  unsigned int randomScore = random(65000, 99999);

   // Loop to simulate a game that ends with score being
   // close to value of randomScore


buoy: Fix lat/lon decimal places.

buoy: Fix lat/lon decimal places.


whammy position MIDI function implemented removed LED code

--- whammy_seq.ino
+++ whammy_seq.ino
@@ -12,38 +12,35 @@
 int current_step = 0;

 // sequence will eventually be loaded from EEPROM
-int sequence[] = {0, 127, 0, 127, 0, 127, 0, 127};
+int sequence[] = {0, 127};

 // the setup function runs once when you press reset or power the board
 void setup() {
-  pinMode(13, OUTPUT);
+  //  Set MIDI baud rate:
+  Serial.begin(31250);
 }

 // the loop function runs over and over again forever
 void loop() {
-  blink();
-
   // there will eventually be loops for "stop" and "program" modes
   play_loop();
 }

-void blink() {
-  // blink built-in LED to show program is running
-  digitalWrite(13, HIGH);
-  delay(500);
-  digitalWrite(13, LOW);
-  delay(50);
-}
+void play_loop() {
+  send_whammy_position((byte) sequence[current_step]);

-void play_loop() {
-  send_whammy_position(sequence[current_step]);
+  // TODO get rid of delay and use millis()
+  delay(250);

   // next step
   current_step += 1;
   current_step = current_step % (sizeof(sequence) / sizeof(sequence[0]));
 }

-void send_whammy_position(int value) {
-  // TODO
-}+void send_whammy_position(byte value) {
+  Serial.write((byte) 176); // CC on Channel 1 (10110000)
+  Serial.write((byte) 11); // Controller 11
+  Serial.write(value); // value
+}
+


fixed PWM not working. Some compilers do not 'see' analogWrite if nested too deeply

--- code/firmware/firmware.ino
+++ code/firmware/firmware.ino
@@ -18,10 +18,11 @@
 // time between samples in milliseconds
 const int sampleInterval = 200;
 // digital & analog I/O pin setup
-const int pwmVRefPin = 5;
-const int pwmIRefPin = 6;
+const int pwmVRefPin = 7;
+const int pwmIRefPin = 8;
 const int VsensePin = A0;
 const int IsensePin = A1;
+const int LEDPin = 13;
 // measurement variables
 int sensorBufferLength = 5;
 int analogSensorA0Value = 0;
@@ -90,6 +91,9 @@
   updateVRefPwmValue();
   updateIRefPwmValue();
   sampleSensors();
+  // fix for some compilers: not called if deeply nested
+  analogWrite(pwmIRefPin,IRefPwmValue);
+  analogWrite(pwmVRefPin,VRefPwmValue);
 }

 // function for initializing sample buffers to all zeros
@@ -108,12 +112,20 @@
   analogWrite(pwmVRefPin, 0);
   pinMode(pwmIRefPin, OUTPUT);
   analogWrite(pwmIRefPin, 0);
+
+  pinMode(LEDPin, OUTPUT);
+
+//  for (int pin=1;pin<=12;pin++){
+//    pinMode(pin, OUTPUT);
+//    analogWrite(pin, 50);
+//  }
 }

 // load settings from EEPROM
 void loadSettings() {
   // read from EEPROM
   isFirstRun = int(EEPROM.read(1));
+  digitalWrite(LEDPin,isFirstRun);
   isStreamingSensorData = int(EEPROM.read(2));
   sensorA0ZeroVoltReference = readSensorValueFromEEPROM(3);
   sensorA0OtherReference = readSensorValueFromEEPROM(5);


First version with averages per hour, day and week

--- sketch_relais_humidity/sketch_relais_humidity.ino
+++ sketch_relais_humidity/sketch_relais_humidity.ino
@@ -2,17 +2,59 @@

 const int relaisPin =  11;
 const int sensorPin = A0;    // select the input pin for the potentiometer
+const int MINVALUE = 0;
 const int MAXVALUE = 1023;
 int sensorValue = 0;  // variable to store the value coming from the sensor
 int thresholdLow = 0;
 int thresholdHigh = 0;
-int dayMax = 0;
-int dayMin = 0;
-int firstRun = 1;
-int prevday = 0;
-int diff;
-int avg;
-int curday;
+int hourMax = MINVALUE;
+int hourMin = MAXVALUE;
+int prevweekday = 0, prevhour = 0;
+int curweekday = 0, curhour = 0;
+
+/* Three arrays that keep track of sensor values (one every 5 minutes),
+ * and averages (24 hours a day, then 7 days in a week)
+ */
+struct sensordata {
+  int average;
+  int minimum;
+  int maximum;
+};
+typedef struct sensordata sensordata;
+
+const int hum_hour_max = 12; // 12 * 5 minutes in one hour
+const int hum_day_max = 24; // hours in a day
+const int hum_week_max = 7; // days in a week
+sensordata hum_hour[hum_hour_max];
+sensordata hum_day[hum_day_max];
+sensordata hum_week[hum_week_max];
+int hum_hour_len = 0;
+int hum_day_len = 0;
+int hum_week_len = 0;
+
+sensordata average;
+
+int humidity() {
+  sensorValue = analogRead(sensorPin);
+
+  // sensor value is high when humidity is low, this is
+  // counterintuitive (it's a dryness sensor!), so we
+  // reverse it:
+  return MAXVALUE - sensorValue;
+}
+
+void avg_min_max(const struct sensordata *sdata, int length, struct sensordata *out) {
+  out->average = 0;
+  out->minimum = MAXVALUE;
+  out->maximum = MINVALUE;
+
+  for (int i = 0; i < length; ++i) {
+    out->average =+ sdata[i].average;
+    out->minimum = min(sdata[i].minimum, out->minimum);
+    out->maximum = max(sdata[i].maximum, out->maximum);
+  }
+  out->average /= length;
+}

 void setup() {
   // initialize the 11 pin as an output:
@@ -20,33 +62,63 @@
   pinMode(relaisPin, OUTPUT);
   pinMode(sensorPin, INPUT);
   digitalWrite(relaisPin, HIGH);
+
+  prevweekday = weekday();
+  prevhour = hour();
+  sensorValue = humidity();
+  // first run, initialize threshold to sane values
+  average.average = sensorValue;
+  average.minimum = -10;
+  average.maximum = 10;
+  thresholdLow = constrain(sensorValue + average.minimum, 0, MAXVALUE);
+  thresholdHigh = constrain(sensorValue + average.maximum, 0, MAXVALUE);
 }

-void loop(){
-  sensorValue = analogRead(sensorPin);
-  sensorValue = MAXVALUE - sensorValue;
-  curday = day();
-  if (firstRun == 1) {
-    // first run, initialize threshold to sane values
-    firstRun = 0;
-    prevday = curday;
-    thresholdLow = constrain(sensorValue - 10, 0, MAXVALUE);
-    thresholdHigh = constrain(sensorValue + 10, 0, MAXVALUE);
-    dayMin = thresholdLow;
-    dayMax = thresholdHigh;
+void loop() {
+  sensorValue = humidity();
+  hourMin = constrain(sensorValue, 0, hourMin);
+  hourMax = constrain(sensorValue, hourMax, MAXVALUE);
+  sensordata tmp = {sensorValue, hourMin - sensorValue, hourMax - sensorValue};
+  hum_hour[hum_hour_len] = tmp;
+  if (hum_hour_len < hum_hour_max - 1) {
+    hum_hour_len++;
   }
-  dayMin = constrain(sensorValue, 0, dayMin);
-  dayMax = constrain(sensorValue, dayMax, MAXVALUE);
-  if (prevday != curday) {
-    prevday = curday;
-    diff = dayMax - dayMin;
-    avg = dayMin + diff / 2;
-    thresholdLow = avg - diff / 4;
-    thresholdHigh = avg + diff / 4;
-    dayMin = sensorValue;
-    dayMax = sensorValue;
+
+  curweekday = weekday();
+  if (prevweekday != curweekday) {
+    // every start of the week, calculate the averages of the week before
+    if (curweekday == 0) {
+      avg_min_max(hum_week, hum_week_len, &average);
+      hum_week_len = 0;
+    }
+    // every start of the day, calculate the averages of the day before
+    avg_min_max(hum_day, hum_day_len, &hum_week[hum_week_len]);
+    hum_day_len = 0;
+    if (hum_week_len < hum_week_max - 1) {
+      hum_week_len++;
+    }
+    prevweekday = curweekday;
+  }
+
+  // every start of the hour, calculate the averages of the 5 minute periods
+  curhour = hour();
+  if (prevhour != curhour) {
+    prevhour = curhour;
+    avg_min_max(hum_hour, hum_hour_len, &hum_day[hum_day_len]);
+    hum_hour_len = 0;
+    if (hum_day_len < hum_day_max - 1) {
+      hum_day_len++;
+    }
+
+    average.maximum = max(average.maximum, hourMax - sensorValue);
+    thresholdHigh = average.average + (average.maximum / 4) * 3;
+    thresholdLow = average.average + average.maximum / 4;
+
+    hourMin = MAXVALUE;
+    hourMax = MINVALUE;
   }

+  // print out the values for debugging/plotting
   Serial.print("humidity = ");
   Serial.print(sensorValue);
   Serial.print(", tlow = ");
@@ -54,10 +126,11 @@
   Serial.print(", thi = ");
   Serial.print(thresholdHigh);
   Serial.print(", dmin = ");
-  Serial.print(dayMin);
+  Serial.print(average.average + average.minimum);
   Serial.print(", dmax = ");
-  Serial.println(dayMax);
+  Serial.println(average.average + average.maximum);

+  // switch the relays!
   if (sensorValue < thresholdLow) {
     // HIGH means setting the relay to NC
     digitalWrite(relaisPin, HIGH);


Delete birthdaysong.ino

Delete birthdaysong.ino

--- birthdaysong/birthdaysong.ino
+++ birthdaysong/birthdaysong.ino
@@ -1,62 +0,0 @@
-//ONG LIT YIT 2013-07-20
-//This following code plays happy birthday melody on Arduino
-//Put Piezo Buzzer on GDN and 13 (Positive and negative are reversible)
-//this project requires a Piezo Buzze an Arduino board and jumper wires to connect Buzzer's (+) to ~13 and (-) to GND (any GND)
-//HAVE FUN
-
-int speakerPin = 13;
-int length = 28; // the number of notes
-char notes[] = "GGAGcB GGAGdc GGxecBA yyecdc";
-int beats[] = { 2, 2, 8, 8, 8, 16, 1, 2, 2, 8, 8,8, 16, 1, 2,2,8,8,8,8,16, 1,2,2,8,8,8,16 };
-int tempo = 150;
-
-void playTone(int tone, int duration) {
-
-for (long i = 0; i < duration * 1000L; i += tone * 2) {
-   digitalWrite(speakerPin, HIGH);
-   delayMicroseconds(tone);
-   digitalWrite(speakerPin, LOW);
-   delayMicroseconds(tone);
-}
-}
-
-void playNote(char note, int duration) {
-
-char names[] = {'C', 'D', 'E', 'F', 'G', 'A', 'B',
-
-                 'c', 'd', 'e', 'f', 'g', 'a', 'b',
-
-                 'x', 'y' };
-
-int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014,
-
-                 956,  834,  765,  593,  468,  346,  224,
-
-                 655 , 715 };
-
-int SPEE = 5;
-// play the tone corresponding to the note name
-
-for (int i = 0; i < 17; i++) {
-   if (names[i] == note) {
-    int newduration = duration/SPEE;
-     playTone(tones[i], newduration);
-   }
-}
-}
-
-void setup() {
-pinMode(speakerPin, OUTPUT);
-}
-
-void loop() {
-for (int i = 0; i < length; i++) {
-   if (notes[i] == ' ') {
-     delay(beats[i] * tempo); // rest
-   } else {
-     playNote(notes[i], beats[i] * tempo);
-   }
-   // pause between notes
-   delay(tempo);
-}
-}


[Arduino] Implemented Jetpack Button on Digital 3.

Signed-off-by: Juri Berlanda <5bfdca9e82c53adb0603ce7083f4ba4f2da5cacf@hotmail.com>

--- Arduino/vj-flight-controller/vj-flight-controller.ino
+++ Arduino/vj-flight-controller/vj-flight-controller.ino
@@ -79,6 +79,7 @@

 #define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6)
+#define JETPACK_PIN 3
 bool blinkState = false;

 // MPU control/status vars
@@ -164,6 +165,10 @@
         Serial.print(aaWorld.y);
         Serial.print("\t");
         Serial.println(aaWorld.z);
+        break;
+      case 'j':
+        Serial.print("j\t");
+        Serial.println(!digitalRead(JETPACK_PIN)); // pin low -> pressed
         break;
       default:
         Serial.print("ERROR - Command ");
@@ -223,6 +228,10 @@
     Serial.println(F(")"));
   }

+  // Setup Jetpack button
+  pinMode(JETPACK_PIN, INPUT);
+  digitalWrite(JETPACK_PIN, HIGH); // connect internal pull-up
+
   // configure LED for output
   pinMode(LED_PIN, OUTPUT);


Route locking button now takes 3 seconds to activate

--- signalboxes/kelberg/kelberg.ino
+++ signalboxes/kelberg/kelberg.ino
@@ -344,8 +344,8 @@
   for (int number = 0; number < ARRAY_SIZE; number++) {
     levers[number].interval(200);
   }
-  // Special case: route fixation button should take a second to activate.
-  levers[ROUTE_A_FIXATION].interval(1000);
+  // Special case: route fixation button should take three seconds to activate.
+  levers[ROUTE_A_FIXATION].interval(3000);

   // look up the initial lever positions and update accordingly.
   for (int number = 0; number < ARRAY_SIZE; number++) {