add a suitable print function for debugging

--- examples/raw-feather/raw-feather.ino
+++ examples/raw-feather/raw-feather.ino
@@ -52,6 +52,9 @@
 #include <lmic.h>
 #include <hal/hal.h>
 #include <SPI.h>
+
+#include <stdarg.h>
+#include <stdio.h>

 // we formerly would check this configuration; but now there is a flag,
 // in the LMIC, LMIC.noRXIQinversion;
@@ -111,6 +114,26 @@
 // this gets callled by the library but we choose not to display any info;
 // and no action is required.
 void onEvent (ev_t ev) {
+}
+
+extern "C" {
+void lmic_printf(const char *fmt, ...);
+};
+
+void lmic_printf(const char *fmt, ...) {
+	if (! Serial.dtr())
+		return;
+
+	char buf[256];
+	va_list ap;
+
+	va_start(ap, fmt);
+	(void) vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
+	va_end(ap);
+
+	// in case we overflowed:
+	buf[sizeof(buf) - 1] = '\0';
+	if (Serial.dtr()) Serial.print(buf);
 }

 osjob_t txjob;


implements positionSetpoint()

implements positionSetpoint()

funny fact: the function works better inside CANDataRead() than in main
loop

--- arduino_control/arduino_control.ino
+++ arduino_control/arduino_control.ino
@@ -207,18 +207,17 @@
 //*******************
 // POSITION SETPOINT
 //*******************
-void positionSetpoint(double position)
-{
-  uint32_t angulo = (position/4096)*200000;
-
-  setpoint_position[4] = angulo & 0xFF;
-  setpoint_position[5] = (angulo >> 8) & 0xFF;
-  setpoint_position[6] = (angulo >> 16) & 0xFF;
-  setpoint_position[7] = (angulo >> 24) & 0xFF;
+void positionSetpoint(uint32_t angle)
+{
+  angle *= 200000 / 4096; //conversion to quadrature counts
+
+  setpoint_position[4] = angle & 0xFF;
+  setpoint_position[5] = (angle >> 8) & 0xFF;
+  setpoint_position[6] = (angle >> 16) & 0xFF;
+  setpoint_position[7] = (angle >> 24) & 0xFF;

   // clear the string:
   CAN.sendMsgBuf(0x601, 0, 8, setpoint_position);
-  delay(100);
 }

 //******************************
@@ -264,20 +263,20 @@
   }
 }

-//******************************
-// POSITION DATA READ
-//******************************
-float encoderDataRead(unsigned char buf[])
-{
-    unsigned char encoder_data[8];
-
-    encoder_data = buf[4];
-    encoder_data <<= 8;
-    encoder_data = encoder_data | buf[5];
-
-    Serial.print("Encoder: ");
-    Serial.println(encoder_data);
-}
+// //******************************
+// // POSITION DATA READ
+// //******************************
+// float encoderDataRead(unsigned char buf[])
+// {
+//     unsigned char encoder_data[8];
+
+//     encoder_data = buf[4];
+//     encoder_data <<= 8;
+//     encoder_data = encoder_data | buf[5];
+
+//     Serial.print("Encoder: ");
+//     Serial.println(encoder_data);
+// }

 //****************
 // CAN DATA READ
@@ -324,8 +323,12 @@
         break;

       // ID 321 message has information sent by the amplification board
+      // Messages coming from the amp_board has most significative bits coming first
       case 0x321:
-        encoderDataRead(buf);
+        // encoderDataRead();
+        encoder_data = buf[4];
+        encoder_data <<= 8; // bitshift equals times 2^8
+        encoder_data = encoder_data | buf[5]; // sum operation

         // // load cell information is read from buf[1], buf[2] and buf[3] and converted to decimal
         loadcell_data = buf[1];
@@ -334,13 +337,18 @@
         loadcell_data <<= 8;
         loadcell_data = loadcell_data | buf[3];

-//        Serial.print("Loadcell: ");
-//        Serial.println(loadcell_data);
-
-//
+        positionSetpoint(encoder_data);
+
+        //        Serial.print("Loadcell: ");
+        //        Serial.println(loadcell_data);
+
+        Serial.print("Encoder Position: ");
+        Serial.println(encoder_data);
+
         break;
       }
-      // return(encoder_data);
+      return(encoder_data);
+      return(loadcell_data);
   }
 }

@@ -360,7 +368,6 @@

     //    reads CAN BUS
     CANDataRead();
-

     if (sync_flag){
       sync_flag=0;


space out analog reads

space out analog reads

--- scriptor.ino
+++ scriptor.ino
@@ -32,11 +32,11 @@
   // It takes about 100 microseconds (0.0001 s) to read an analog input,
   // so the maximum reading rate is about 10,000 times a second.
   int a0 = analogRead(A0);
-  int a1 = analogRead(A1);
   int a2 = analogRead(A2);
+  int a4 = analogRead(A4);

   // create msg
-  Data msg = {time, a0, a1, a2};
+  Data msg = {time, a0, a2, a4};

   if (counter < N) {
 	  MESSAGES[counter] = msg;


Add files via upload

Add files via upload

fixed issue with blinking with one eye


add '>' command for sending a packet to any band, group, etc

--- examples/RF12/RF12demo/RF12demo.ino
+++ examples/RF12/RF12demo/RF12demo.ino
@@ -51,7 +51,7 @@
 static RF12Config config;

 static char cmd;
-static byte value, stack[RF12_MAXDATA], top, sendLen, dest, quiet;
+static byte value, stack[RF12_MAXDATA+4], top, sendLen, dest, quiet;
 static byte testbuf[RF12_MAXDATA], testCounter, useHex;

 static void showNibble (byte nibble) {
@@ -113,6 +113,10 @@

   if (!rf12_config())
     Serial.println("config save failed");
+}
+
+static byte bandToFreq (byte band) {
+  return band == 8 ? RF12_868MHZ : band == 9 ? RF12_915MHZ : RF12_433MHZ;
 }

 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -548,8 +552,8 @@
   "  <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"
+  "  t          - broadcast max-size test packet, request ack" "\n"
+  "  ...,<nn> a - send data packet to node <nn>, request 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"
@@ -593,7 +597,7 @@
     if (top < sizeof stack)
       stack[top++] = value;
     value = 0;
-  } else if ('a' <= c && c <='z' || 'A' <= c && c <= 'Z') {
+  } else if ('a' <= c && c <='z') {
     Serial.print("> ");
     for (byte i = 0; i < top; ++i) {
       Serial.print((int) stack[i]);
@@ -610,9 +614,8 @@
         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);
+        if (value)
+          config.nodeId = (bandToFreq(value) << 6) + (config.nodeId & 0x3F);
         saveConfig();
         break;
       case 'g': // set network group
@@ -651,14 +654,14 @@
         activityLed(1);
         fs20cmd(256 * stack[0] + stack[1], stack[2], value);
         activityLed(0);
-        rf12_config(); // restore normal packet listening mode
+        rf12_config(0); // 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
+        rf12_config(0); // restore normal packet listening mode
         break;
       case 'd': // dump all log markers
         if (df_present())
@@ -701,7 +704,17 @@
     }
     value = top = 0;
     memset(stack, 0, sizeof stack);
-  } else if (c > ' ')
+  } else if (c == '>') {
+    // special case, send to specific band and group, and don't echo cmd
+    // input: band,group,node,header,data...
+    stack[top++] = value;
+    rf12_initialize(stack[2], bandToFreq(stack[0]), stack[1]);
+    rf12_sendNow(stack[3], stack + 4, top - 4);
+    rf12_sendWait(2);
+    rf12_config(0); // restore original band, etc
+    value = top = 0;
+    memset(stack, 0, sizeof stack);
+  } else if (' ' < c && c < 'A')
     showHelp();
 }


yak shaving

yak shaving

--- examples/RF12/RF12demo/RF12demo.ino
+++ examples/RF12/RF12demo/RF12demo.ino
@@ -322,7 +322,7 @@
             break;
         if (c == '\n')
             printOneChar('\r');
-        Serial.print(c);
+        printOneChar(c);
     }
 }

@@ -595,7 +595,7 @@
     for (byte i = 0; i < count; ++i) {
         printOneChar(' ');
         char c = (char) data[i];
-        Serial.print(c < ' ' || c > '~' ? '.' : c);
+        printOneChar(c < ' ' || c > '~' ? '.' : c);
     }
     Serial.println();
 }
@@ -719,8 +719,8 @@
             if (config.group == 0) {
                 showString(PSTR(" II "));
             }
-            Serial.print(rf12_hdr & RF12_HDR_DST ? '>' : '<');
-            Serial.print((char) ('@' + (rf12_hdr & RF12_HDR_MASK)));
+            printOneChar(rf12_hdr & RF12_HDR_DST ? '>' : '<');
+            printOneChar('@' + (rf12_hdr & RF12_HDR_MASK));
             displayASCII((const uint8_t*) rf12_data, n);
         }


moved inside main file

moved inside main file

--- examples/functions_menu/blink_and_fade.ino
+++ examples/functions_menu/blink_and_fade.ino
@@ -1,78 +0,0 @@
-void fade() {
-	static byte step = 0;
-	static bool goingUp = true;
-	if (step == 0) {
-		if (goingUp) {
-			redLed_level++;
-		} else {
-			redLed_level--;
-		}
-		if (redLed_level >= 10) {
-			goingUp = false;
-		}
-		if (redLed_level <= 0 && goingUp == false) {
-			step++;
-			goingUp = true;
-		}
-		greenLed_level = 0;
-		blueLed_level = 0;
-	}
-	if (step == 1) {
-		if (goingUp) {
-			greenLed_level++;
-		} else {
-			greenLed_level--;
-		}
-		if (greenLed_level >= 10) {
-			goingUp = false;
-		}
-		if (greenLed_level <= 0 && goingUp == false) {
-			step++;
-			goingUp = true;
-		}
-		redLed_level = 0;
-		blueLed_level = 0;
-	}
-	if (step >= 2) {
-		if (goingUp) {
-			blueLed_level++;
-		} else {
-			blueLed_level--;
-		}
-		if (blueLed_level >= 10) {
-			goingUp = false;
-		}
-		if (blueLed_level <= 0 && goingUp == false) {
-			step = 0;
-			goingUp = true;
-		}
-		redLed_level = 0;
-		greenLed_level = 0;
-	}
-	PWM_log(redLed, redLed_level);
-	PWM_log(greenLed, greenLed_level);
-	PWM_log(blueLed, blueLed_level);
-}
-
-void blink() {
-	static byte blinkStep = 0;
-	if (blinkStep == 0) {
-		redLed_level = 10;
-		greenLed_level = 0;
-		blueLed_level = 0;
-		blinkStep++;
-	} else if (blinkStep == 1) {
-		redLed_level = 0;
-		greenLed_level = 10;
-		blueLed_level = 0;
-		blinkStep++;
-	} else if (blinkStep >= 2) {
-		redLed_level = 0;
-		greenLed_level = 0;
-		blueLed_level = 10;
-		blinkStep = 0;
-	}
-	PWM_log(redLed, redLed_level);
-	PWM_log(greenLed, greenLed_level);
-	PWM_log(blueLed, blueLed_level);
-}


Added version publish to set up of node

Added version publish to set up of node


Version that actually switches the relays

--- humidity_simple/humidity_simple.ino
+++ humidity_simple/humidity_simple.ino
@@ -1,18 +1,28 @@
 #include <Time.h>

-const int relayPin =  11;
+// consts for controlling relays
+const int K1 = 11;
+const int K2 = 12;
+const int milliseconds_switch_delay = 100;
+const int NormallyConnected = HIGH;
+const int NormallyOpen = LOW;
+
+
+// consts/variables for humidity sensor and averages etc.
 const int sensorPin = A0;    // select the input pin for the potentiometer
 const int MINHUMIDITY = 0;
 const int MAXHUMIDITY = 1023;
 const int milliseconds_sleep = 5000;
 const float avg_decay = 0.00001;
 const float deviation_decay = 0.01;
+
 int thresholdLow = 0;
 int thresholdHigh = 0;
 float avg = 0;
-float deviation = 20;
+float deviation = 40;
 int humidity = 0;
 int startup_seconds = 900; // sensor needs to settle for 15 minutes
+int on_off = 0;

 int get_humidity() {
   int sensorValue = analogRead(sensorPin);
@@ -24,11 +34,16 @@
 }

 void setup() {
-  // initialize the 11 pin as an output:
   Serial.begin(9600);
-  pinMode(relayPin, OUTPUT);
+
+  // set relays to normally connected
+  pinMode(K1, OUTPUT);
+  pinMode(K2, OUTPUT);
+  digitalWrite(K1, NormallyConnected);
+  digitalWrite(K2, NormallyConnected);
+
+  // initialize sensor
   pinMode(sensorPin, INPUT);
-  digitalWrite(relayPin, HIGH);
   avg = get_humidity();
 }

@@ -50,25 +65,40 @@
   thresholdLow = avg + deviation / 3.0f;
   thresholdHigh = avg + 2.0f * deviation / 3.0f;

-  // print out the values for debugging/plotting
+  on_off = avg;
+  // switch the relays!
+  if (humidity < thresholdLow) {
+    // because we don't know the status of the 3-way switch, we switch both
+    // relays at the same time and hope there is no short circuit. This should
+    // not be an issue, but anyway...
+    digitalWrite(K1, NormallyConnected);
+    digitalWrite(K2, NormallyConnected);
+    on_off -= 20;
+  } else if (humidity > thresholdHigh) {
+    digitalWrite(K2, NormallyOpen);
+    // since we don't know how the switch is switched, we first switch K2 to
+    // non-connected, then wait a while for it to settle, before we switch
+    // K1 to connected L. This should prevent any shorts (don't know if that
+    // is actually an issue, but better safe than sorry).
+    delay(milliseconds_switch_delay);
+    digitalWrite(K1, NormallyOpen);
+    on_off -= 10;
+  } else {
+    on_off -= 15;
+  }
+   // print out the values for debugging/plotting
   Serial.print("humidity = ");
   Serial.print(humidity);
   Serial.print(", tlow = ");
   Serial.print(thresholdLow);
   Serial.print(", thi = ");
   Serial.print(thresholdHigh);
-  Serial.print(", dmin = ");
+  Serial.print(", avg = ");
   Serial.print((int)(avg));
-  Serial.print(", dmax = ");
-  Serial.println((int)(avg + deviation));
-
-  // switch the relays!
-  if (humidity < thresholdLow) {
-    // HIGH means setting the relay to NC
-    digitalWrite(relayPin, HIGH);
-  } else if (humidity > thresholdHigh) {
-    // LOW means setting the relay to NO
-    digitalWrite(relayPin, LOW);
-  }
+  Serial.print(", deviation = ");
+  Serial.print((int)(avg + deviation));
+  Serial.print(", on_off = ");
+  Serial.println((int)(on_off));
+
   delay(milliseconds_sleep);
 }


implemented minimum time for each state to protect on-off on the fan and the heating element

version is now 0.9

--- minimalistthermostat.ino
+++ minimalistthermostat.ino
@@ -1,6 +1,3 @@
-//TODO:
-// have a minimun time for each state to protect on-off on the fan and the heating element
-
 //The MIT License (MIT)
 //Copyright (c) 2016 Gustavo Gonnet
 //
@@ -20,24 +17,24 @@
 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
+
 #include "application.h"
 #include "elapsedMillis.h"
 #include "PietteTech_DHT.h"
 #include "FiniteStateMachine.h"
-
 #define APP_NAME "Thermostat"
-// IO mapping
-// D0 : relay: fan
-// D1 : relay: heat
-// D2 : relay: cold
-// D3 : relay:
-// D4 : DHT22
-// D5 : unused
-// D6 : unused
-// D7 : unused
-// A0~A7 : unused
-
-//initialize states with proper enter, update and exit functions
+
+String VERSION = "Version 0.09";
+/*******************************************************************************
+ * changes in version 0.09:
+       * reorganized code to group functions
+       * added minimum time to protect on-off on the fan and the heating element
+          in function heatingUpdateFunction()
+*******************************************************************************/
+
+/*******************************************************************************
+ initialize FSM states with proper enter, update and exit functions
+*******************************************************************************/
 State initState = State( initEnterFunction, initUpdateFunction, initExitFunction );
 State idleState = State( idleEnterFunction, idleUpdateFunction, idleExitFunction );
 State heatingState = State( heatingEnterFunction, heatingUpdateFunction, heatingExitFunction );
@@ -46,15 +43,41 @@
 //initialize state machine, start in state: Idle
 FSM thermostatStateMachine = FSM(initState);

-String VERSION = "Version 0.07";
+//milliseconds for the init cycle, so temperature samples get stabilized
+//this should be in the order of the 5 minutes: 5*60*1000==300000
+#define INIT_TIMEOUT 30000
+elapsedMillis initTimer;
+
+//milliseconds to leave the fan on when the target temp has been reached
+//this evacuates the heat or the cold air from vents
+#define END_OF_CYCLE_TIMEOUT 15000
+elapsedMillis endOfCycleTimer;
+
+//minimum number of milliseconds to leave the heating element on
+// to protect on-off on the fan and the heating element
+#define MINIMUM_ON_TIMEOUT 5000
+elapsedMillis minimumOnTimer;
+
+/*******************************************************************************
+ IO mapping
+*******************************************************************************/
+// D0 : relay: fan
+// D1 : relay: heat
+// D2 : relay: cold
+// D4 : DHT22
+// D3, D5~D7 : unused
+// A0~A7 : unused
 int fan = D0;
 int heat = D1;
 int cold = D2;
+//TESTING_HACK
 int fanTesting;
 int heatTesting;
 int coldTesting;

-// system defines
+/*******************************************************************************
+ DHT sensor
+*******************************************************************************/
 #define DHTTYPE  DHT22                // Sensor type DHT11/21/22/AM2301/AM2302
 #define DHTPIN   4                    // Digital pin for communications
 #define DHT_SAMPLE_INTERVAL   30000   // Sample room temperature every 30 seconds
@@ -63,16 +86,9 @@
 bool bDHTstarted;       // flag to indicate we started acquisition
 elapsedMillis dhtSampleInterval;

-//milliseconds for the init cycle, so temperature samples get stabilized
-//this should be in the order of the 5 minutes: 5*60*1000==300000
-#define INIT_TIMEOUT 30000
-elapsedMillis initTimer;
-
-//milliseconds to leave the fan on when the target temp has been reached
-//this evacuates the heat or the cold air from vents
-#define END_OF_CYCLE_TIMEOUT 15000
-elapsedMillis endOfCycleTimer;
-
+/*******************************************************************************
+ thermostat related declarations
+*******************************************************************************/
 //temperature related variables - internal
 float targetTemp = 19.0;
 float currentTemp = 20.0;
@@ -83,54 +99,62 @@
 String currentTempString = String(currentTemp); //String to store the sensor's temp so it can be exposed
 String currentHumidityString = String(currentHumidity); //String to store the sensor's humidity so it can be exposed

-//testing variables
+//TESTING_HACK
+// this allows me to system test the project
 bool testing = false;

+
+/*******************************************************************************
+ * Function Name  : setup
+ * Description    : this function runs once at system boot
+ *******************************************************************************/
 void setup() {

- //publish startup message with firmware version
- Particle.publish(APP_NAME, VERSION, 60, PRIVATE);
-
- //declare and init pins
- pinMode(fan, OUTPUT);
- pinMode(heat, OUTPUT);
- pinMode(cold, OUTPUT);
- myDigitalWrite(fan, LOW);
- myDigitalWrite(heat, LOW);
- myDigitalWrite(cold, LOW);
-
- //declare cloud variables
- //https://docs.particle.io/reference/firmware/photon/#particle-variable-
- //Currently, up to 10 cloud variables may be defined and each variable name is limited to a maximum of 12 characters
- if (Particle.variable("targetTemp", targetTempString)==false) {
-   Particle.publish(APP_NAME, "ERROR: Failed to register variable targetTemp", 60, PRIVATE);
- }
- if (Particle.variable("currentTemp", currentTempString)==false) {
-   Particle.publish(APP_NAME, "ERROR: Failed to register variable currentTemp", 60, PRIVATE);
- }
- if (Particle.variable("humidity", currentHumidityString)==false) {
-   Particle.publish(APP_NAME, "ERROR: Failed to register variable humidity", 60, PRIVATE);
- }
-
- //declare cloud functions
- //https://docs.particle.io/reference/firmware/photon/#particle-function-
- //Currently the application supports the creation of up to 4 different cloud functions.
- //The length of the funcKey is limited to a max of 12 characters.
- // If you declare a function name longer than 12 characters the function will not be registered.
- //user functions
- if (Particle.function("setTargetTmp", setTargetTemp)==false) {
-    Particle.publish(APP_NAME, "ERROR: Failed to register function setTargetTemp", 60, PRIVATE);
- }
- //testing functions
- if (Particle.function("setTesting", setTesting)==false) {
-    Particle.publish(APP_NAME, "ERROR: Failed to register function setTesting", 60, PRIVATE);
- }
- if (Particle.function("setCurrTmp", setCurrentTemp)==false) {
-    Particle.publish(APP_NAME, "ERROR: Failed to register function setCurrentTemp", 60, PRIVATE);
- }
- if (Particle.function("getOutputs", getOutputs)==false) {
-    Particle.publish(APP_NAME, "ERROR: Failed to register function getOutputs", 60, PRIVATE);
- }
+  //pulish startup message with firmware version
+  Particle.publish(APP_NAME, VERSION, 60, PRIVATE);
+
+  //declare and init pins
+  pinMode(fan, OUTPUT);
+  pinMode(heat, OUTPUT);
+  pinMode(cold, OUTPUT);
+  myDigitalWrite(fan, LOW);
+  myDigitalWrite(heat, LOW);
+  myDigitalWrite(cold, LOW);
+
+  //declare cloud variables
+  //https://docs.particle.io/reference/firmware/photon/#particle-variable-
+  //Currently, up to 10 cloud variables may be defined and each variable name is limited to a maximum of 12 characters
+  if (Particle.variable("targetTemp", targetTempString)==false) {
+    Particle.publish(APP_NAME, "ERROR: Failed to register variable targetTemp", 60, PRIVATE);
+  }
+  if (Particle.variable("currentTemp", currentTempString)==false) {
+    Particle.publish(APP_NAME, "ERROR: Failed to register variable currentTemp", 60, PRIVATE);
+  }
+  if (Particle.variable("humidity", currentHumidityString)==false) {
+    Particle.publish(APP_NAME, "ERROR: Failed to register variable humidity", 60, PRIVATE);
+  }
+
+  //declare cloud functions
+  //https://docs.particle.io/reference/firmware/photon/#particle-function-
+  //Currently the application supports the creation of up to 4 different cloud functions.
+  //The length of the funcKey is limited to a max of 12 characters.
+  // If you declare a function name longer than 12 characters the function will not be registered.
+  //user functions
+  if (Particle.function("setTargetTmp", setTargetTemp)==false) {
+     Particle.publish(APP_NAME, "ERROR: Failed to register function setTargetTemp", 60, PRIVATE);
+  }
+  //TESTING_HACK
+  if (Particle.function("setTesting", setTesting)==false) {
+     Particle.publish(APP_NAME, "ERROR: Failed to register function setTesting", 60, PRIVATE);
+  }
+  //TESTING_HACK
+  if (Particle.function("setCurrTmp", setCurrentTemp)==false) {
+     Particle.publish(APP_NAME, "ERROR: Failed to register function setCurrentTemp", 60, PRIVATE);
+  }
+  //TESTING_HACK
+  if (Particle.function("getOutputs", getOutputs)==false) {
+     Particle.publish(APP_NAME, "ERROR: Failed to register function getOutputs", 60, PRIVATE);
+  }

 }

@@ -138,200 +162,19 @@
 void dht_wrapper() { DHT.isrCallback(); }

+/*******************************************************************************
+ * Function Name  : loop
+ * Description    : this function runs continuously while the project is running
+ *******************************************************************************/
 void loop() {
+
+  //this function reads the temperature of the DHT sensor
   readTemperature();
+
+  //this function updates the FSM
+  // the FSM is the heart of the thermostat - all actions are defined by its states
   thermostatStateMachine.update();
-}
-
-/*******************************************************************************
- * Function Name  : readTemperature
- * Description    : reads the temperature of the DHT22 sensor at every DHT_SAMPLE_INTERVAL
-                    if testing the app, it returns right away
- * Return         : 0
- *******************************************************************************/
-int readTemperature() {
-
-  //are we testing the app? then no need to acquire from the sensor
-  if (testing) {
-   return 0;
-  }
-
-  //time is up? no, then come back later
-  if (dhtSampleInterval < DHT_SAMPLE_INTERVAL) {
-   return 0;
-  }
-
-  //time is up, reset timer
-  dhtSampleInterval = 0;
-
-  // start the sample
-  if (!bDHTstarted) {
-    DHT.acquire();
-    bDHTstarted = true;
-  }
-
-  //still acquiring sample? go away
-  if (DHT.acquiring()) {
-    return 0;
-  }
-
-  //sample acquired - go ahead and store temperature and humidity in internal variables
-  publishTemperature( (float)DHT.getCelsius(), (float)DHT.getHumidity() );
-
-  //reset the sample flag so we can take another
-  bDHTstarted = false;
-
-  return 0;
-}
-
-/*******************************************************************************
- * Function Name  : publishTemperature
- * Description    : the temperature/humidity passed as parameters get stored in internal variables
-                    and then published
- * Return         : 0
- *******************************************************************************/
-int publishTemperature( float temperature, float humidity ) {
-
- char currentTempChar[32];
- currentTemp = temperature;
- int currentTempDecimals = (currentTemp - (int)currentTemp) * 100;
- sprintf(currentTempChar,"%0d.%d", (int)currentTemp, currentTempDecimals);
-
- char currentHumidityChar[32];
- currentHumidity = humidity;
- int currentHumidityDecimals = (currentHumidity - (int)currentHumidity) * 100;
- sprintf(currentHumidityChar,"%0d.%d", (int)currentHumidity, currentHumidityDecimals);
-
- //publish readings into exposed variables
- currentTempString = String(currentTempChar);
- currentHumidityString = String(currentHumidityChar);
-
- //publish readings
- Particle.publish(APP_NAME, "Current temperature: " + currentTempString, 60, PRIVATE);
- Particle.publish(APP_NAME, "Current humidity: " + currentHumidityString, 60, PRIVATE);
-
- return 0;
-
-}
-
-//utility functions
-void initEnterFunction(){
- Particle.publish(APP_NAME, "initEnterFunction", 60, PRIVATE);
- //start the timer of this cycle
- initTimer = 0;
-
-}
-void initUpdateFunction(){
- //time is up?
- if (initTimer > INIT_TIMEOUT) {
-  thermostatStateMachine.transitionTo(idleState);
- }
-}
-void initExitFunction(){
- Particle.publish(APP_NAME, "initExitFunction", 60, PRIVATE);
-}
-
-void idleEnterFunction(){
- Particle.publish(APP_NAME, "idleEnterFunction", 60, PRIVATE);
- myDigitalWrite(fan, LOW);
- myDigitalWrite(heat, LOW);
- myDigitalWrite(cold, LOW);
-}
-void idleUpdateFunction(){
- if ( currentTemp <= (targetTemp - margin) ) {
-  Particle.publish(APP_NAME, "Starting to heat", 60, PRIVATE);
-  thermostatStateMachine.transitionTo(heatingState);
- }
-}
-void idleExitFunction(){
- Particle.publish(APP_NAME, "idleExitFunction", 60, PRIVATE);
-}
-
-void heatingEnterFunction(){
- Particle.publish(APP_NAME, "heatingEnterFunction", 60, PRIVATE);
- myDigitalWrite(fan, HIGH);
- myDigitalWrite(heat, HIGH);
- myDigitalWrite(cold, LOW);
-}
-void heatingUpdateFunction(){
- if ( currentTemp >= (targetTemp + margin) ) {
-  Particle.publish(APP_NAME, "Desired temperature reached", 60, PRIVATE);
-  thermostatStateMachine.transitionTo(endOfCycleState);
- }
-}
-void heatingExitFunction(){
- Particle.publish(APP_NAME, "heatingExitFunction", 60, PRIVATE);
- myDigitalWrite(fan, HIGH);
- myDigitalWrite(heat, LOW);
- myDigitalWrite(cold, LOW);
-}
-
-void endOfCycleEnterFunction(){
- Particle.publish(APP_NAME, "endOfCycleEnterFunction", 60, PRIVATE);
- myDigitalWrite(fan, HIGH);
- myDigitalWrite(heat, LOW);
- myDigitalWrite(cold, LOW);
-
- //start the timer of this cycle
- endOfCycleTimer = 0;
-
-}
-void endOfCycleUpdateFunction(){
- //time is up?
- if (endOfCycleTimer > END_OF_CYCLE_TIMEOUT) {
-  thermostatStateMachine.transitionTo(idleState);
- }
-}
-void endOfCycleExitFunction(){
- Particle.publish(APP_NAME, "endOfCycleExitFunction", 60, PRIVATE);
-}
-
-/*******************************************************************************
- * Function Name  : setTesting
- * Description    : sets the testing variable to true
- * Return         : 0
- *******************************************************************************/
-int setTesting(String dummy)
-{
-  testing = true;
-  return 0;
-}
-
-/*******************************************************************************
- * Function Name  : getOutputs
- * Description    : returns the outputs so we can test the program
- * Return         : returns the outputs
- *******************************************************************************/
-int getOutputs(String dummy)
-{
-  // int fan = D0;
-  // int heat = D1;
-  // int cold = D2;
-  return coldTesting*4 + heatTesting*2 + fanTesting*1;
-}
-
-/*******************************************************************************
- * Function Name  : setCurrentTemp
- * Description    : sets the current temperature of the thermostat
-                    newCurrentTemp has to be a valid float value, or no new current temp will be set
- * Return         : 0, or -1 if it fails to convert the temp to float
- *******************************************************************************/
-int setCurrentTemp(String newCurrentTemp)
-{
-  float tmpFloat = newCurrentTemp.toFloat();
-
-  //update the current temp only in the case the conversion to float works
-  // (toFloat returns 0 if there is a problem in the conversion)
-  // sorry, if you wanted to set 0 as the current temp, you can't :)
-  if ( tmpFloat > 0 ) {
-    currentTemp = tmpFloat;
-    currentTempString = String(currentTemp);
-    Particle.publish(APP_NAME, "New current temp: " + currentTempString, 60, PRIVATE);
-    return 0;
-  } else {
-    Particle.publish(APP_NAME, "ERROR: Failed to set new current temp to " + newCurrentTemp, 60, PRIVATE);
-    return -1;
-  }
+
 }

 /*******************************************************************************
@@ -357,6 +200,233 @@
   }
 }

+/*******************************************************************************
+ * Function Name  : readTemperature
+ * Description    : reads the temperature of the DHT22 sensor at every DHT_SAMPLE_INTERVAL
+                    if testing the app, it returns right away
+ * Return         : 0
+ *******************************************************************************/
+int readTemperature() {
+
+  //TESTING_HACK
+  //are we testing the app? then no need to acquire from the sensor
+  if (testing) {
+   return 0;
+  }
+
+  //time is up? no, then come back later
+  if (dhtSampleInterval < DHT_SAMPLE_INTERVAL) {
+   return 0;
+  }
+
+  //time is up, reset timer
+  dhtSampleInterval = 0;
+
+  // start the sample
+  if (!bDHTstarted) {
+    DHT.acquireAndWait(5);
+    bDHTstarted = true;
+  }
+
+  //still acquiring sample? go away
+  if (DHT.acquiring()) {
+    return 0;
+  }
+
+  //sample acquired - go ahead and store temperature and humidity in internal variables
+  publishTemperature( (float)DHT.getCelsius(), (float)DHT.getHumidity() );
+
+  //reset the sample flag so we can take another
+  bDHTstarted = false;
+
+  return 0;
+}
+
+/*******************************************************************************
+ * Function Name  : publishTemperature
+ * Description    : the temperature/humidity passed as parameters get stored in internal variables
+                    and then published
+ * Return         : 0
+ *******************************************************************************/
+int publishTemperature( float temperature, float humidity ) {
+
+ char currentTempChar[32];
+ currentTemp = temperature;
+ int currentTempDecimals = (currentTemp - (int)currentTemp) * 100;
+ sprintf(currentTempChar,"%0d.%d", (int)currentTemp, currentTempDecimals);
+
+ char currentHumidityChar[32];
+ currentHumidity = humidity;
+ int currentHumidityDecimals = (currentHumidity - (int)currentHumidity) * 100;
+ sprintf(currentHumidityChar,"%0d.%d", (int)currentHumidity, currentHumidityDecimals);
+
+ //publish readings into exposed variables
+ currentTempString = String(currentTempChar);
+ currentHumidityString = String(currentHumidityChar);
+
+ //publish readings
+ Particle.publish(APP_NAME, "Current temperature: " + currentTempString, 60, PRIVATE);
+ Particle.publish(APP_NAME, "Current humidity: " + currentHumidityString, 60, PRIVATE);
+
+ return 0;
+
+}
+
+
+/*******************************************************************************
+********************************************************************************
+********************************************************************************
+ FINITE STATE MACHINE FUNCTIONS
+********************************************************************************
+********************************************************************************
+*******************************************************************************/
+void initEnterFunction(){
+ Particle.publish(APP_NAME, "initEnterFunction", 60, PRIVATE);
+ //start the timer of this cycle
+ initTimer = 0;
+
+}
+void initUpdateFunction(){
+ //time is up?
+ if (initTimer > INIT_TIMEOUT) {
+  thermostatStateMachine.transitionTo(idleState);
+ }
+}
+void initExitFunction(){
+ Particle.publish(APP_NAME, "initExitFunction", 60, PRIVATE);
+}
+
+void idleEnterFunction(){
+ Particle.publish(APP_NAME, "idleEnterFunction", 60, PRIVATE);
+ myDigitalWrite(fan, LOW);
+ myDigitalWrite(heat, LOW);
+ myDigitalWrite(cold, LOW);
+}
+void idleUpdateFunction(){
+ if ( currentTemp <= (targetTemp - margin) ) {
+  Particle.publish(APP_NAME, "Starting to heat", 60, PRIVATE);
+  thermostatStateMachine.transitionTo(heatingState);
+ }
+}
+void idleExitFunction(){
+ Particle.publish(APP_NAME, "idleExitFunction", 60, PRIVATE);
+}
+
+void heatingEnterFunction(){
+ Particle.publish(APP_NAME, "heatingEnterFunction", 60, PRIVATE);
+ myDigitalWrite(fan, HIGH);
+ myDigitalWrite(heat, HIGH);
+ myDigitalWrite(cold, LOW);
+
+ //start the minimum timer of this cycle
+ minimumOnTimer = 0;
+}
+void heatingUpdateFunction(){
+  //is minimum time up?
+  if (minimumOnTimer < MINIMUM_ON_TIMEOUT) {
+    //not yet, so get out of here
+    return;
+  }
+
+  if ( currentTemp >= (targetTemp + margin) ) {
+    Particle.publish(APP_NAME, "Desired temperature reached", 60, PRIVATE);
+    thermostatStateMachine.transitionTo(endOfCycleState);
+  }
+}
+void heatingExitFunction(){
+ Particle.publish(APP_NAME, "heatingExitFunction", 60, PRIVATE);
+ myDigitalWrite(fan, HIGH);
+ myDigitalWrite(heat, LOW);
+ myDigitalWrite(cold, LOW);
+}
+
+void endOfCycleEnterFunction(){
+ Particle.publish(APP_NAME, "endOfCycleEnterFunction", 60, PRIVATE);
+ myDigitalWrite(fan, HIGH);
+ myDigitalWrite(heat, LOW);
+ myDigitalWrite(cold, LOW);
+
+ //start the timer of this cycle
+ endOfCycleTimer = 0;
+
+}
+void endOfCycleUpdateFunction(){
+ //time is up?
+ if (endOfCycleTimer > END_OF_CYCLE_TIMEOUT) {
+  thermostatStateMachine.transitionTo(idleState);
+ }
+}
+void endOfCycleExitFunction(){
+ Particle.publish(APP_NAME, "endOfCycleExitFunction", 60, PRIVATE);
+}
+
+
+/*******************************************************************************
+********************************************************************************
+********************************************************************************
+ TESTING HACKS
+********************************************************************************
+********************************************************************************
+*******************************************************************************/
+
+/*******************************************************************************
+ * Function Name  : setTesting
+ * Description    : sets the testing variable to true - this enables me to override
+                     the temperature read by the DHT sensor.
+                    this is a hack that allows me to system test the project
+ * Return         : 0
+ *******************************************************************************/
+int setTesting(String dummy)
+{
+  testing = true;
+  return 0;
+}
+
+/*******************************************************************************
+ * Function Name  : getOutputs
+ * Description    : returns the outputs so we can test the program
+                    this is a hack that allows me to system test the project
+ * Return         : returns the outputs
+ *******************************************************************************/
+int getOutputs(String dummy)
+{
+  // int fan = D0;
+  // int heat = D1;
+  // int cold = D2;
+  return coldTesting*4 + heatTesting*2 + fanTesting*1;
+}
+
+/*******************************************************************************
+ * Function Name  : setCurrentTemp
+ * Description    : sets the current temperature of the thermostat
+                    newCurrentTemp has to be a valid float value, or no new current temp will be set
+                    this is a hack that allows me to system test the project
+* Return         : 0, or -1 if it fails to convert the temp to float
+ *******************************************************************************/
+int setCurrentTemp(String newCurrentTemp)
+{
+  float tmpFloat = newCurrentTemp.toFloat();
+
+  //update the current temp only in the case the conversion to float works
+  // (toFloat returns 0 if there is a problem in the conversion)
+  // sorry, if you wanted to set 0 as the current temp, you can't :)
+  if ( tmpFloat > 0 ) {
+    currentTemp = tmpFloat;
+    currentTempString = String(currentTemp);
+    Particle.publish(APP_NAME, "New current temp: " + currentTempString, 60, PRIVATE);
+    return 0;
+  } else {
+    Particle.publish(APP_NAME, "ERROR: Failed to set new current temp to " + newCurrentTemp, 60, PRIVATE);
+    return -1;
+  }
+}
+
+/*******************************************************************************
+ * Function Name  : getOutputs
+ * Description    : returns the outputs so we can test the program
+                    this is a hack that allows me to system test the project
+ * Return         : returns the outputs
+ *******************************************************************************/
 void myDigitalWrite( int input, int status){
   digitalWrite(input, status);
   if (input == fan){


Steering calibration at setup

Steering calibration at setup

--- potential_motor_control_IR.ino
+++ potential_motor_control_IR.ino
@@ -5,6 +5,9 @@
 #include <EVShield.h>
 #include <EVShieldAGS.h>
 #include <EVs_EV3Infrared.h>
+
+const int FULL_POWER = 100;
+const int STEERING_FULL_POWER = 60;

 /* Init Shield */
 EVShield evshield(0x34, 0x36);
@@ -23,6 +26,8 @@
 int32_t maxSteerLeft;               // max value for steering left
 int32_t maxSteerRight;              // max value for steering right
 int32_t centerSteer;                // center value of steering
+
+int32_t static power = 0;                      // power settings for rear wheels, single for now

 void setup()
 {
@@ -61,18 +66,20 @@
   Serial.println ("Press GO button to calibrate steering");
   evshield.waitForButtonPress(BTN_GO);

+  maxSteerRight = setMaxRight();
+  Serial.println("Max Right Steering Value: ");
+  Serial.println(maxSteerRight);
+  delay(1000);
+
   maxSteerLeft = setMaxLeft();
   Serial.println("Max Left Steering Value: ");
   Serial.println(maxSteerLeft);
   delay(1000);

-  maxSteerRight = setMaxRight();
-  Serial.println("Max Right Steering Value: ");
-  Serial.println(maxSteerRight);
-  delay(1000);
-
-  centerSteer = centerSteering(maxSteerLeft, maxSteerRight);
-
+  centerSteer = centerSteering(maxSteerLeft, maxSteerRight) - maxSteerRight;
+  Serial.println("Center value: ");
+  Serial.println(centerSteer);
+  delay(500);
   Serial.println ("Press GO button to Start Car");
   evshield.waitForButtonPress(BTN_GO);

@@ -86,32 +93,49 @@
   int channel = 1;
   button = sensorIR.readChannelButton(channel);

-  driveForward(button);
-  driveBackward(button);
+  steeringDegrees = getSteeringPosition();
+  power = powerTurning(steeringDegrees);
+  Serial.print("Power rating: ");
+  Serial.println(power);
+  driveForward(button, power);
+  driveBackward(button, power);
   turnLeft(button);
   turnRight(button);
-
-  steeringDegrees = getSteeringPosition();
-
+
   Serial.print("Degrees: ");
   Serial.println(steeringDegrees);
 }

-void driveForward(int button)
+void driveForward(int button, int32_t power)
 {
   if(button == 1)
   {
-    evshield.bank_b.motorRunUnlimited(SH_Motor_1, SH_Direction_Forward, 100);
-    evshield.bank_a.motorRunUnlimited(SH_Motor_1, SH_Direction_Forward, 100);
+    evshield.bank_b.motorRunUnlimited(SH_Motor_1, SH_Direction_Forward, power);
+    evshield.bank_a.motorRunUnlimited(SH_Motor_1, SH_Direction_Forward, power);
   }
 }

-void driveBackward(int button)
+void driveBackward(int button, int power)
 {
   if(button == 2)
   {
-    evshield.bank_b.motorRunUnlimited(SH_Motor_1, SH_Direction_Reverse, 100);
-    evshield.bank_a.motorRunUnlimited(SH_Motor_1, SH_Direction_Reverse, 100);
+    evshield.bank_b.motorRunUnlimited(SH_Motor_1, SH_Direction_Reverse, power);
+    evshield.bank_a.motorRunUnlimited(SH_Motor_1, SH_Direction_Reverse, power);
+  }
+}
+
+//use getSteering() as method to calculate current position
+int32_t powerTurning(int steeringValue)
+{
+  Serial.println("calculating power");
+  if(steeringValue < (centerSteer + 10))
+  {
+    Serial.println("Turned Righ");
+    return 100;
+  }
+  else
+  {
+    return 1;
   }
 }

@@ -136,14 +160,14 @@
   return evshield.bank_b.motorGetEncoderPosition(SH_Motor_2);
 }

-int32_t setMaxLeft()
+int32_t setMaxRight()
 {
   evshield.bank_b.motorRunSeconds(SH_Motor_2, SH_Direction_Forward, 100, 5, SH_Completion_Wait_For, SH_Next_Action_Float);
   delay(5000);
   return evshield.bank_b.motorGetEncoderPosition(SH_Motor_2);
 }

-int32_t setMaxRight()
+int32_t setMaxLeft()
 {
   evshield.bank_b.motorRunSeconds(SH_Motor_2, SH_Direction_Reverse, 100, 5, SH_Completion_Wait_For, SH_Next_Action_Float);
   delay(5000);
@@ -152,7 +176,7 @@

 int32_t centerSteering(int32_t maxLeft, int32_t maxRight)
 {
-  int center = (maxLeft - maxRight) / 2;
+  int32_t center = (maxRight - maxLeft) / 2;
   evshield.bank_b.motorRunDegrees(SH_Motor_2, SH_Direction_Forward, 100, center, SH_Completion_Wait_For, SH_Next_Action_Float);
   delay(5000);
   return center;


Forward Movement

Forward Movement

Rudimentary attempt at flying forward for a specified time.

--- drone_control/drone_control.ino
+++ drone_control/drone_control.ino
@@ -51,6 +51,35 @@

 double MicrosToSecond(ulong micro){
   return micro / 1000000.f;
+}
+
+void FlyForTime(int motorValue, int timePeriod)
+{
+  static int flightStartTime = millis();
+  static bool isFlying = false;
+
+  if(TimeDelta - flightStartTime < timePeriod && !isFlying)
+  {
+    SetMotor(FRONT_LEFT, SERVO_HOVER);
+    SetMotor(FRONT_RIGHT, SERVO_HOVER);
+
+    SetMotor(BACK_LEFT, SERVO_HOVER + 250);
+    SetMotor(BACK_RIGHT, SERVO_HOVER + 250);
+
+    isFlying = true;
+  }
+  else if(TimeDelta - flightStartTime >= timePeriod && isFlying)
+  {
+    SetMotor(BACK_LEFT, SERVO_HOVER);
+    SetMotor(BACK_RIGHT, SERVO_HOVER);
+    flightStartTime = 0;
+    isFlying = false;
+  }
+}
+
+void FlyForDistance(int motorValue, float distance)
+{
+
 }

 void LiftOff(float feet){


Changes to IMU handling, clean up, no idle screen saver, but has motion indication.

--- sketch/CurieDice/CurieDice.ino
+++ sketch/CurieDice/CurieDice.ino
@@ -232,12 +232,13 @@
 int noMotionCount=0;
 int loMotionCount=0;
 int hiMotionCount=0;
-#define TSLOTS 10           // storage for chunks
+#define TSLOTS 20           // storage for chunks
 int loCounts[TSLOTS]={};
 int hiCounts[TSLOTS]={};
 int tIndex=0;
 int noMoSlots=0;    // number of consecutive noMotion slots
 int dispPause=0;
+#define ORIENTATION_TOL   9

 void resultShow(int ori) {
   pix.disp(orientDisp[ori], (ori)?0x0f0:0xf00, 0);
@@ -255,7 +256,7 @@
   SERIAL_PRINTLN(z);
   for (int i=0; i<6; i++) {
     signed char *t = orientable[i];
-    if (abs(x-t[0])<3 && abs(y-t[1])<3 && abs(z-t[2])<3) return t[3];
+    if (abs(x-t[0])<ORIENTATION_TOL && abs(y-t[1])<ORIENTATION_TOL && abs(z-t[2])<ORIENTATION_TOL) return t[3];
   }
   return 0;
 }
@@ -277,8 +278,8 @@
     int f = face[i];
     pix.disp(orientDisp[f], 0xf00, 3000);
     pix.disp(orientDisp[f], 0xf60, 2000);
+    CurieIMU.readAccelerometer(vcurr[0], vcurr[1], vcurr[2]);
     pix.disp(orientDisp[f], 0x0f0, 1000);
-    CurieIMU.readAccelerometer(vcurr[0], vcurr[1], vcurr[2]);
     signed char *t = orientable[i];
     t[0] = (signed char)(vcurr[0]>>8);
     t[1] = (signed char)(vcurr[1]>>8);
@@ -288,7 +289,7 @@
 }

 int16_t imuRead() {
-static unsigned long currTimeQuant = 0;
+  static unsigned long currTimeQuant = 0;
   for (int i=0; i<6; i++) vprev[i] = vcurr[i];
   //CurieIMU.readMotionSensor(vcurr[0], vcurr[1], vcurr[2], vcurr[3], vcurr[4], vcurr[5]);
   CurieIMU.readAccelerometer(vcurr[0], vcurr[1], vcurr[2]);
@@ -302,8 +303,8 @@

   unsigned long tq = millis()>>TSLOT_SHIFT;
   if (tq == currTimeQuant) {
-    if (movement >= 16) hiMotionCount++;
-    else if (movement >= 4) loMotionCount++;
+    if (movement >= 32) hiMotionCount++;
+    else if (movement >= 8) loMotionCount++;
     else
       noMotionCount++;
   }
@@ -311,14 +312,24 @@
     // end of a time slot
     loCounts[tIndex]=loMotionCount;
     hiCounts[tIndex]=hiMotionCount;
+    if (dispPause) {
+      dispPause--;
+    }
+    else {
+      int pxi = tIndex;
+      for (int pxc=7; pxc>=0; pxc--) {
+        int color = 0x0;
+        if (hiCounts[pxi]) color=0x00f;
+        else if (loCounts[pxi]) color=0x0f0;
+        pix.set(pxc, color, 0);
+        if (pxi > 0)  pxi--;
+        else          pxi = TSLOTS-1;
+      }
+    }
     tIndex = (tIndex==(TSLOTS-1))?0:tIndex+1;
     if ((loMotionCount+hiMotionCount)==0) {
       // this slot had no motion
       noMoSlots++;
-      if (dispPause)
-        dispPause--;
-      else
-        idleShow();
       if (noMoSlots == 5) {
         // eval for possible throw
         int i = tIndex - (5+1);
@@ -326,7 +337,7 @@
         int his=0;
         int lows=0;
         pix.disp(0xff, 0x000, 0);
-        for (int n=0; n<5; n++) {
+        for (int n=0; n<15; n++) {  // eval last n slots
           SERIAL_PRINT(i);
           SERIAL_PRINT("hist: ");

@@ -343,8 +354,7 @@
           }
           i = (i==0)? TSLOTS-1:i-1;
         }
-        if ((his+lows)>3 && his>0) {
-        //if ((his+lows)>1 && his>=0) {
+        if ((his+lows)>6 && his>0) {
           int roll = calcOrientation();
           SERIAL_PRINTLN(roll);
           resultShow(roll);
@@ -366,8 +376,6 @@
 }

-
-
 // **********************************************************************
 // ************* setup **************************************************
 // **********************************************************************
@@ -375,6 +383,7 @@
   setupOnboardLED();
   setupDiceId();

+
   pix.setup();
   setupVibe();

@@ -391,6 +400,8 @@
   pix.set(1, 0x0f0, 500);      // 0 - green BLE setup done

+  readDiceId();
+
   // *************** IMU Setup ***************************************
   // initialize device
   SERIAL_PRINTLN("Initializing IMU device...");
@@ -407,33 +418,12 @@
     pix.set(7,0xf00,0);      // 8 - red - err connecting to IMU
   }

-  CurieIMU.setAccelerometerRange(8);
-  CurieIMU.setGyroRange(2000);
-  /*
-  // use the code below to calibrate accel/gyro offset values
-  SERIAL_PRINTLN("Internal sensor offsets BEFORE calibration...");
-  SERIAL_PRINT(CurieIMU.getXAccelOffset());
-  SERIAL_PRINT("\t"); // -76
-  SERIAL_PRINT(CurieIMU.getYAccelOffset());
-  SERIAL_PRINT("\t"); // -235
-  SERIAL_PRINT(CurieIMU.getZAccelOffset());
-  SERIAL_PRINT("\t"); // 168
-  SERIAL_PRINT(CurieIMU.getXGyroOffset());
-  SERIAL_PRINT("\t"); // 0
-  SERIAL_PRINT(CurieIMU.getYGyroOffset());
-  SERIAL_PRINT("\t"); // 0
-  SERIAL_PRINT(CurieIMU.getZGyroOffset());
-
-  pix.set(3, 0x00f, 200);      // 1 - blue IMU - orient dice for calibration
-
-  CurieIMU.setGyroOffsetEnabled(true);
-  CurieIMU.setAccelOffsetEnabled(true);
-*/
+  CurieIMU.setDetectionThreshold(CURIE_IMU_SHOCK, 1500);
+  CurieIMU.setDetectionDuration(CURIE_IMU_SHOCK, 50);
+
+  diceCal();
+
   pix.set(4, 0x0f0, 0);      // 1 - green IMU setup done
-  readDiceId();
-
-  diceCal();
-

 }


Fix a problem with a compilation on Microsoft Windows

Signed-off-by: Roman3349 <6b7cbc66756660b4790b3af1ec1507653acaa035@centrum.cz>

--- src/Hello-world.ino
+++ src/Hello-world.ino
@@ -1,3 +1,19 @@
+/**
+ * Copyright 2015-2016 MICRORISC s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #if defined(__PIC32MX__)
 #include <WProgram.h>
 #else


update

update

--- src/Firmware.ino
+++ src/Firmware.ino
@@ -2,14 +2,15 @@
 #include <MeStepper.h>
 #define STATES_COUNT 128
 #define COMMANDS_COUNT 3
-#define PULSES_PER_MM 200
-#define DEBUG true
+#define PULSES_PER_MM 50
+#define CURVE_SECTION 0.5
+#define NUM_STEPS 100
+// #define DEBUG true
 struct MotionState
 {
     bool dirX;
     bool dirY;
-    double e2;
-    double err;
+    long err;
     double dx;
     double dy;
     long tx;
@@ -57,10 +58,8 @@
     Serial.begin(115200);
     delay(1000);
     Serial.println("opened");
-    stepperX.setMicroStep(32);
-    stepperY.setMicroStep(32);
-    stepperX.enableOutputs();
-    stepperY.enableOutputs();
+    stepperX.setMicroStep(16);
+    stepperY.setMicroStep(16);
 }

 void loop()
@@ -100,7 +99,7 @@
     if (_statesIndex > 0)
     {
         _state = _states[0];
-        _targetDelays = 5000 / (1 + _commState.speed * 49);
+        _targetDelays = 50000 / (1 + _commState.speed * 4);
         _currentAccel = _commState.accel;
         for (int i = 0; i < _statesIndex - 1; i++)
         {
@@ -243,6 +242,20 @@
         firePower(v[0]);
         break;
     }
+    case 'o':
+    {
+        if (v[0] > 0)
+        {
+            stepperX.enableOutputs();
+            stepperY.enableOutputs();
+        }
+        else
+        {
+            stepperX.disableOutputs();
+            stepperY.disableOutputs();
+        }
+    }
+    break;
     }
 }

@@ -284,8 +297,6 @@
 /**
  * motion control
  */
-#define CURVE_SECTION 0.5
-#define NUM_STEPS 20
 bool positionToGo()
 {
     long distX = xPositionToGo(_state.tx);
@@ -297,23 +308,22 @@
 {
     long distX = xPositionToGo(_state.tx);
     long distY = yPositionToGo(_state.ty);
-
 #ifdef DEBUG
-    String str = "position:";
+    String str = "p:";
     str += _positionX;
     str += ",";
     str += _positionY;
-// Serial.println(str);
+    Serial.println(str);
 #endif
     if (distX == 0 && distY == 0)
         return;
-    _state.e2 = _state.err;
-    if (_state.e2 > -_state.dx)
+    long e2 = _state.err;
+    if (e2 > -_state.dx)
     {
         _state.err -= _state.dy;
         stepX(_state.dirX);
     }
-    if (_state.e2 < _state.dy)
+    if (e2 < _state.dy)
     {
         _state.err += _state.dx;
         stepY(_state.dirY);
@@ -376,7 +386,7 @@
     }
     if (_currentDelays > 2000)
     {
-        delay(floorf(_currentDelays / 1000));
+        delay((int)(_currentDelays / 1000));
         delayMicroseconds(_currentDelays % 1000);
     }
     else
@@ -470,9 +480,9 @@
         dfy += ddfy;
         ddfx += dddfx;
         ddfy += dddfy;
-        lineTo(fx, fy);
-    }
-    lineTo(x3, y3);
+        lineTo(floorf(fx * 100) / 100, floorf(fy * 100) / 100);
+    }
+    lineTo(floorf(x3 * 100) / 100, floorf(y3 * 100) / 100);
 }
 void quadTo(long x1, long y1, long x2, long y2)
 {


Updated meshquitto_node.ino

Updated meshquitto_node.ino

--- meshquitto_node/meshquitto_node.ino
+++ meshquitto_node/meshquitto_node.ino
@@ -1,62 +1,52 @@
+/*=================================================================================== */
+/* meshquitto_node/meshquitto_node.ino                                                */
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* Example implementation of a meshquitto node.                                       */
+/*                                                                                */
+/* This example assumes that a DS18B20 temp sensor is plugged in on port D4 and a LED */
+/* on port D1. For exact wiring refer to mesquitto_node.png                           */
+/*                                                                                */
+/* Created by Lyudmil Vladimirov, Feb 2017                                            */
+/* More info: https://github.com/sglvladi/meshquitto                                  */
+/* ================================================================================== */
+
 #include <DallasTemperature.h>
 #include<ESP8266WiFi.h>
-
-//************************************************************
-// this is a simple example that uses the easyMesh library
-//
-// 1. blinks led once for every node on the mesh
-// 2. blink cycle repeats every BLINK_PERIOD
-// 3. sends a silly message to every node on the mesh at a random time betweew 1 and 5 seconds
-// 4. prints anything it recieves to Serial.print
-//
-//
-//************************************************************
 #include <painlessMesh.h>
 #include <AES.h>
 #include "HashMap.h"
-#include "SimpleList.h"
-
-// some gpio pin that is connected to an LED...
-// on my rig, this is 5, change to the right number of your LED.
-#define   LED             D1      // GPIO number of connected LED
-
-#define   BLINK_PERIOD    1000000 // microseconds until cycle repeat
-#define   BLINK_DURATION  100000  // microseconds LED is on for
-
+#include "./libraries/CustomList/CustomList.h"
+
+// Define GPIO pins
+#define   LED_PIN             D1      // GPIO pin of connected LED
+#define   LED_TOPIC           "/LED1"
+#define   TEMP_PIN            D4      // GPIO pin of connected DS18B20 temp sensor
+#define   TEMP_TOPIC          "/TEMP1"
+
+// Mesh network details
 #define   MESH_SSID       "whateverYouLike"
 #define   MESH_PASSWORD   "somethingSneaky"
 #define   MESH_ENCRYPT    "sampleEncryptKey"
 #define   MESH_PORT       5555
 #define   GW_ID           2143537872

-#define NC_ID 0x00
-#define WIND_ID 0x01
-#define VOLT_ID 0x02
-#define CURR_ID 0x03
-#define HUM_ID 0x04
-#define TEMP_ID 0x05
-#define DOOR_ID 0x06
-#define RELAY_ID 0x07
-#define LIGHT_ID 0x08
-
+// How often the node should publish the temperature
 #define SEND_INTERVAL 1000

+// Mesh intantiation
 painlessMesh  mesh;
+
+// Storage containers and buffers
 bool calc_delay = false;
-SimpleList<uint32_t> nodes;
+CustomList<uint32_t> nodes;
 uint32_t sendMessageTime = 0;

-String key = "0123456789010123";
-int bits = 256;
-unsigned long long int my_iv = 36753562;
-
-long lastMsg[17] = {millis(), millis(), millis(), millis(),
-                    millis(), millis(), millis(), millis(),
-                    millis(), millis(), millis(), millis(),
-                    millis(), millis(), millis(), millis(), millis()};
-
-// {Identifier => Sensor type} Map
-CreateHashMap(sensTypeMap, String, int, 8);
+// AES Encryption parameters
+const String                  AES_KEY   = "0123456789010123";
+const unsigned long long int  AES_IV    = 36753562;
+const int                     AES_BITS  = 256;
+
+long lastMsg = millis();

 /************************************************************************/
 /* Turns returned mac address into a readable string                    */
@@ -86,7 +76,7 @@

 /************************************************************************/
-/* Reads from DS18B20 sensor interfase given one-wire                   */
+/* Reads and returns the device MAC adress as a String                  */
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 String getMac()
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
@@ -97,14 +87,16 @@
 }
 /************************************************************************/

-/************************************************************************/
-/* Reads from DS18B20 sensor interfase given one-wire                   */
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-int readTemp(int port, int sensor_id)
+
+/************************************************************************/
+/* Checks if SEND_INTERVAL has passed and if true, reads from DS18B20   */
+/* sensor and publishes temperature                                     */
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+int readTemp(int port)
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 {
-  if((millis()-lastMsg[sensor_id]>=SEND_INTERVAL)){
-    lastMsg[sensor_id] = millis();
+  if((millis()-lastMsg>=SEND_INTERVAL)){
+    lastMsg = millis();
     // Setup a oneWire instance to communicate with any OneWire devices
     // (not just Maxim/Dallas temperature ICs)
     OneWire oneWire(port);
@@ -114,22 +106,20 @@
     sensors.begin();
     Serial.print(" Requesting temperatures...");
     sensors.requestTemperaturesByIndex(0);
-    Serial.print("Temperature for sensor T");
-    Serial.print(sensor_id);
-    Serial.print(" is: ");
+    Serial.print("Temperature: ");
     double temperature = sensors.getTempCByIndex(0);
     Serial.print(temperature); Serial.println(" *C");
     char temp[] = "";
     dtostrf(temperature,1, 2, temp);
     DynamicJsonBuffer jsonBufferFS;
     JsonObject& rootFS2 = jsonBufferFS.createObject();
-    rootFS2["topic"] = String(getMac()+"/sensors/T"+sensor_id+"/output/value");
+    rootFS2["topic"] = TEMP_TOPIC;
     rootFS2["payload"] = String(temperature);
     String json_msg;
     rootFS2.printTo(json_msg);
     Serial.println("Sending.....");
     uint32_t dest = GW_ID;
-    String encrypted_msg = AES_encrypt(json_msg, key);
+    String encrypted_msg = AES_encrypt(json_msg, AES_KEY);
     mesh.sendSingle( dest, encrypted_msg );

     return sensors.getDeviceCount();
@@ -138,20 +128,32 @@
 }
 /************************************************************************/

-void printHeap(){
+
+/************************************************************************/
+/* Prints available heap memory to Serial                               */
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+void printHeap(){
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   Serial.print("Free Heap: "); Serial.println(ESP.getFreeHeap());
 }
-
-String AES_encrypt(String plain, String key) {
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+/*************************************************************************/
+/* Performs AES encryption on a given text. Key *must* be 16 bytes.      */
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+String AES_encrypt(String plain, String key)
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+{
   /* Local AES instance (uncomment to recreate problem) */
   AES aes ;
-  aes.set_IV(my_iv);
+  aes.set_IV(AES_IV);
   byte * plain_buf = (unsigned char*)plain.c_str();
   byte * key_buf = (unsigned char*)key.c_str();
   // add padding where appropriate
   int cipher_length = (plain.length()+1 < 16) ? 16 : (plain.length()+1) + (16 - (plain.length()+1) % 16);
   byte cipher_buf[cipher_length];
-  aes.do_aes_encrypt(plain_buf, plain.length() + 1, cipher_buf, key_buf, bits);
+  aes.do_aes_encrypt(plain_buf, plain.length() + 1, cipher_buf, key_buf, AES_BITS);
   String cipher = aes.printToHEXString(cipher_buf, cipher_length);
   //aes.printArray(cipher_buf, false);
   uint16_t plain_size = plain.length();
@@ -170,13 +172,20 @@
   //Serial.println(cipher);
   return cipher;
 }
-
-String AES_decrypt(String cipher, String key) {
-  printHeap();
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+/*************************************************************************/
+/* Performs AES decryption on a given cipher. Key *must* be 16 bytes.    */
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+String AES_decrypt(String cipher, String key)
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+{
+  //printHeap();
   /* Local AES instance (uncomment to recreate problem) */
   AES aes ;
   //Serial.println(cipher);
-  aes.set_IV(my_iv);
+  aes.set_IV(AES_IV);
   byte cipher_buf[cipher.length()/2-2];
   int j = 0;
   for(int i=0;i<=cipher.length()-6;i+=2){
@@ -185,7 +194,7 @@
     //Serial.print(char(cipher_buf[j]));
     j++;
   }
-  printHeap();
+  //printHeap();
   //aes.printArray(cipher_buf, false);
   int plain_size = cipher.substring(cipher.length()-4).toInt();
   //Serial.println(plain_size);
@@ -193,18 +202,23 @@
   byte * key_buf = (unsigned char*)key.c_str();
   int plain_length = cipher.length();
   byte plain_buf[plain_length];
-  aes.do_aes_decrypt(cipher_buf, cipher.length()/2-2, plain_buf, key_buf, bits);
+  aes.do_aes_decrypt(cipher_buf, cipher.length()/2-2, plain_buf, key_buf, AES_BITS);
   String plain = aes.printToString(plain_buf, plain_size);
   //Serial.println(sizeof(plain_buf)/sizeof(plain_buf[0]));
   //Serial.println(plain.length());
-  printHeap();
+  //printHeap();
   return plain;
 }
-
-
-
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+/************************************************************************/
+/* Mesh received callback: Receives a message and if the topic of the   */
+/* received message matches LED_TOPIC, then sets the LED ON, if payload */
+/* is equal to 1, and OFF, if payload is equal to 0                     */
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 void receivedCallback( uint32_t from, String &msg ) {
-  String decrypted_msg = AES_decrypt(msg, key);
+  String decrypted_msg = AES_decrypt(msg, AES_KEY);
   Serial.printf("startHere: Received from %d msg=",from); Serial.println(decrypted_msg);
   String response = "Message received! ID: ";
   char contentBuffer[500];
@@ -213,94 +227,29 @@
   JsonObject& rootFS2 = jsonBuffer.parseObject(contentBuffer);
   String topic = rootFS2["topic"];
   String payload = rootFS2["payload"];
-  Serial.print("Message arrived [");
-  Serial.print(topic);
-  Serial.print("] ");
-  int topic_length = topic.length();
-  int subtopicNo = 0;
-  for (int i=0; i<topic_length; i++){
-    if (String(topic.charAt(i)) == "/"){
-      subtopicNo++;
-    }
-  }
-  //Serial.print("subotpicNo: "); Serial.println(subtopicNo);
-  String subtopics[subtopicNo];
-  bool topicParsed = false;
-  int parserPos = 0;
-  int i = 0;
-  while(!topicParsed){
-    //yield();
-    int startPos = parserPos+1;
-    //Serial.print("indexOf: "); Serial.println(topic_str.indexOf("/", startPos));
-    int endPos = topic.indexOf("/", startPos);
-    if (endPos==-1){
-      endPos = topic.length();
-      topicParsed = true;
-    }
-    subtopics[i] = topic.substring(startPos, endPos);
-    parserPos = endPos;
-    i++;
-  }
-  // 0:device_id, 1:"sensors", 2:sensor_id, 3: "input"/"output", 4: "value"/"min"/"max" etc.
-  String sensor_id = String(subtopics[2]);
-  //String(topic).substring(String(topic).lastIndexOf("/")+1);
-  int sensor_type = sensTypeMap[sensor_id.substring(0,1)];
-  int channel_id = (sensor_id.substring(1)).toInt();
-  Serial.print("Channel_id: "); Serial.println(channel_id);
-  Serial.println();
-  if (sensor_type == RELAY_ID){
+  Serial.println("Message arrived...");
+  Serial.println("Topic: "+topic);
+  Serial.println("Payload: "+payload);
+
+  // If topic matches LED_TOPIC
+  if(topic == LED_TOPIC){
     // Switch on the LED if an 1 was received as first character
-    Serial.print("Channel id: ");
-    Serial.println(channel_id);
-    Serial.println("==================>");
-    Serial.println("Relay message detected");
-    int requested_state = int((char)payload[0]=='0'? 0:1);
-    Serial.println("Requested state: "+String(((requested_state==1) ? "OFF":"ON")));
-    //if(int(requested_state)==readRelay(channel_id)){
-    Serial.print("..."); Serial.print(requested_state); Serial.println("...");
-    switch(requested_state){
-      case(0):{
-        Serial.println("Turning relay ON");
-        pinMode(D1,OUTPUT);
-        digitalWrite(LED, LOW);
-        //delay(500);
-        break;
-
-      }
-      case(1):{
-        Serial.println("Turning relay OFF");
-        pinMode(D1,OUTPUT);
-        digitalWrite(LED, HIGH);
-        break;
-      }
-      default:{
-        Serial.println("No matching action");
-        break;
-      }
-    }
-    String topic_back = "/" + getMac()+ "/sensors/"+sensor_id+"/output/value";
-    Serial.println("Sending.....");
-    JsonObject& rootFS2 = jsonBuffer.createObject();
-    rootFS2["topic"] = topic_back;
-    rootFS2["payload"] = digitalRead(LED);
-    String json_msg;
-    rootFS2.printTo(json_msg);
-    Serial.println("Sending.....");
-    uint32_t dest = GW_ID;
-    String encrypted_msg = AES_encrypt(json_msg, key);
-    mesh.sendSingle( dest, encrypted_msg );
-  }
-}
-
-void newConnectionCallback(uint32_t nodeId) {
-    Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
-}
-
-SimpleList<uint32_t> getDifference(SimpleList<uint32_t> arr1, SimpleList<uint32_t> arr2){
+    int requested_state = int((char)payload[0]=='1'? 1:0);
+    Serial.println("Turning LED "+String(((requested_state==1) ? "ON":"OFF")));
+    digitalWrite(LED_PIN, requested_state);
+  }
+}
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+/*****************************************************************************/
+/* Computes and returns the set difference between two CustomList<uint32_t>  */
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+CustomList<uint32_t> getDifference(CustomList<uint32_t> arr1, CustomList<uint32_t> arr2){

   int m = arr1.size();
   int n = arr2.size();
-  SimpleList<uint32_t> diff;
+  CustomList<uint32_t> diff;
   int i = 0, j = 0;
   while (i < m && j < n)
   {
@@ -316,12 +265,17 @@
   }
   return diff;
 }
-
-SimpleList<uint32_t> getIntersection(SimpleList<uint32_t> arr1, SimpleList<uint32_t> arr2){
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+/*******************************************************************************/
+/* Computes and returns the set intersection between two CustomList<uint32_t>  */
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+CustomList<uint32_t> getIntersection(CustomList<uint32_t> arr1, CustomList<uint32_t> arr2){

   int m = arr1.size();
   int n = arr2.size();
-  SimpleList<uint32_t> intersect;
+  CustomList<uint32_t> intersect;
   int i = 0, j = 0;
   while (i < m && j < n)
   {
@@ -337,34 +291,47 @@
   }
   return intersect;
 }
-
-SimpleList<uint32_t> getLostConnections(SimpleList<uint32_t> nodes, SimpleList<uint32_t> old_nodes){
-
-  SimpleList<uint32_t> diff = getDifference(old_nodes, nodes);
-  SimpleList<uint32_t> lostCons = getIntersection(diff, old_nodes);
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+/**************************************************************************/
+/* Given two lists, before and after a new scan, computes and returns all */
+/* nodes that have disconnected since the last scan.                      */
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+CustomList<uint32_t> getLostConnections(CustomList<uint32_t> nodes, CustomList<uint32_t> old_nodes){
+
+  CustomList<uint32_t> diff = getDifference(old_nodes, nodes);
+  CustomList<uint32_t> lostCons = getIntersection(diff, old_nodes);
   return lostCons;

 }
-
-SimpleList<uint32_t> getNewConnections(SimpleList<uint32_t> nodes, SimpleList<uint32_t> old_nodes){
-
-  SimpleList<uint32_t> diff = getDifference(old_nodes, nodes);
-  SimpleList<uint32_t> newCons = getIntersection(diff, nodes);
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+/**************************************************************************/
+/* Given two lists, before and after a new scan, computes and returns all */
+/* newly connected nodes.                                                 */
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+CustomList<uint32_t> getNewConnections(CustomList<uint32_t> nodes, CustomList<uint32_t> old_nodes){
+
+  CustomList<uint32_t> diff = getDifference(old_nodes, nodes);
+  CustomList<uint32_t> newCons = getIntersection(diff, nodes);
   return newCons;

 }
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

 void changedConnectionCallback() {

     Serial.printf("Changed connections %s\n", mesh.subConnectionJson().c_str());
-    SimpleList<uint32_t> old_nodes = nodes;
+    CustomList<uint32_t> old_nodes = nodes;
     nodes = mesh.getNodeList();
     nodes.sort();
     Serial.printf("Num nodes: %d\n", nodes.size());

     // Print all available connections to nodes
     Serial.printf("Connection list:");
-    SimpleList<uint32_t>::iterator node = nodes.begin();
+    CustomList<uint32_t>::iterator node = nodes.begin();
     while (node != nodes.end()) {
         Serial.printf(" %u", *node);
         node++;
@@ -372,7 +339,7 @@
     Serial.println();

     // Get and print lost connections to nodes
-    SimpleList<uint32_t> lostCons = getLostConnections(nodes, old_nodes);
+    CustomList<uint32_t> lostCons = getLostConnections(nodes, old_nodes);
     if(lostCons.size()>0){
       Serial.printf("Lost Connections: ");
       node = lostCons.begin();
@@ -386,27 +353,32 @@
     //    DO STUFF .....
     // ========================>
     // Free up the memory
-    lostCons.~SimpleList<uint32_t>();
+    lostCons.~CustomList<uint32_t>();

     calc_delay = true;
     old_nodes = nodes;
 }
-
+
+
+/************************************************************************/
+/* Currently unused painlessMesh callbacks                              */
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+void newConnectionCallback(uint32_t nodeId) {
+    Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
+}
 void nodeTimeAdjustedCallback(int32_t offset) {
     Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(), offset);
 }
-
 void delayReceivedCallback(uint32_t from, int32_t delay) {
     Serial.printf("Delay to node %u is %d us\n", from, delay);
 }
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+

 void setup() {
   Serial.begin(115200);
-  // Set up sensor type hashMap
-  sensTypeMap["W"] = 1; sensTypeMap["V"] = 2; sensTypeMap["C"] = 3; sensTypeMap["H"] = 4;
-  sensTypeMap["T"] = 5; sensTypeMap["D"] = 6; sensTypeMap["R"] = 7; sensTypeMap["L"] = 8;
   Serial.print("Chip ID: "); Serial.println(ESP.getChipId());
-  pinMode( LED, OUTPUT );
+  pinMode( LED_PIN, OUTPUT );
   //mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on
   mesh.setDebugMsgTypes( ERROR | STARTUP );  // set before init() so that you can see startup messages

@@ -422,35 +394,7 @@

 void loop() {
   mesh.update();
-  readTemp(D4, 4);
-  //Serial.println("\n Intersection:");
-  //printIntersection(arr1, arr2, m, n);
-  //Serial.println("\n Difference:");
-  //printDifference(arr1, arr2, m, n);
-  //Serial.print("Free heap: "); Serial.println(ESP.getFreeHeap());
-  // run the blinky
-//  bool  onFlag = false;
-//  uint32_t cycleTime = mesh.getNodeTime() % BLINK_PERIOD;
-//  for ( uint8_t i = 0; i < ( mesh.connectionCount() + 1); i++ ) {
-//    uint32_t onTime = BLINK_DURATION * i * 2;
-//
-//    if ( cycleTime > onTime && cycleTime < onTime + BLINK_DURATION )
-//      onFlag = true;
-//  }
-//  digitalWrite( LED, onFlag );
-//
-//  // get next random time for send message
-//  if ( sendMessageTime == 0 ) {
-//    sendMessageTime = mesh.getNodeTime() + random( 1000000, 5000000 );
-//  }
-//
-//  // if the time is ripe, send everyone a message!
-//  if ( sendMessageTime != 0 && sendMessageTime < mesh.getNodeTime() ){
-//    String msg = "Hello from node ";
-//    msg += mesh.getNodeId();
-//    //mesh.sendBroadcast( msg );
-//    sendMessageTime = 0;
-//  }
-}
-
-
+  readTemp(D4);
+}
+
+


read out vcc twice, before and after sending

--- examples/RF12/radioBlip2/radioBlip2.ino
+++ examples/RF12/radioBlip2/radioBlip2.ino
@@ -9,7 +9,8 @@
 struct {
   long ping;  // 32-bit counter
   byte id;    // identity, should be different for each node
-  byte vcc;   // measured BCC, 1.0V = 0 .. 6.0V = 250
+  byte vcc1;  // VCC before transmit, 1.0V = 0 .. 6.0V = 250
+  byte vcc2;  // VCC after transmit, will be sent in next cycle
 } payload;

 volatile bool adcDone;
@@ -36,33 +37,36 @@
 }

 void setup() {
-    cli();
-    CLKPR = bit(CLKPCE);
+  cli();
+  CLKPR = bit(CLKPCE);
 #if defined(__AVR_ATtiny84__)
-    CLKPR = 0; // div 1, i.e. speed up to 8 MHz
+  CLKPR = 0; // div 1, i.e. speed up to 8 MHz
 #else
-    CLKPR = 1; // div 2, i.e. slow down to 8 MHz
+  CLKPR = 1; // div 2, i.e. slow down to 8 MHz
 #endif
-    sei();
-    rf12_initialize(17, RF12_868MHZ, 5);
-    // see http://tools.jeelabs.org/rfm12b
-    rf12_control(0xC040); // set low-battery level to 2.2V i.s.o. 3.1V
-    payload.id = BLIP_ID;
+  sei();
+  rf12_initialize(17, RF12_868MHZ, 5);
+  // see http://tools.jeelabs.org/rfm12b
+  rf12_control(0xC040); // set low-battery level to 2.2V i.s.o. 3.1V
+  payload.id = BLIP_ID;
 }

 void loop() {
-    ++payload.ping;
-    payload.vcc = vccRead();
-
-    while (!rf12_canSend())
-        rf12_recvDone();
-
-    rf12_sendStart(0, &payload, sizeof payload);
-    // set the sync mode to 2 if the fuses are still the Arduino default
-    // mode 3 (full powerdown) can only be used with 258 CK startup fuses
-    rf12_sendWait(2);
-
-    rf12_sleep(RF12_SLEEP);
-    Sleepy::loseSomeTime(60000);
-    rf12_sleep(RF12_WAKEUP);
+  payload.vcc1 = vccRead();
+
+  ++payload.ping;
+
+  while (!rf12_canSend())
+    rf12_recvDone();
+
+  rf12_sendStart(0, &payload, sizeof payload);
+  // set the sync mode to 2 if the fuses are still the Arduino default
+  // mode 3 (full powerdown) can only be used with 258 CK startup fuses
+  rf12_sendWait(2);
+
+  payload.vcc2 = vccRead();
+
+  rf12_sleep(RF12_SLEEP);
+  Sleepy::loseSomeTime(60000);
+  rf12_sleep(RF12_WAKEUP);
 }


add drawer 2 sensing

add drawer 2 sensing

--- examples/Habitat_Temps/Habitat_Temps.ino
+++ examples/Habitat_Temps/Habitat_Temps.ino
@@ -333,7 +333,6 @@
   SensorPtr = &Mux0Temp1;   // EC Top
   stat = sensor_read (SensorPtr);

-
   SensorPtr = &Mux0Temp2;   // EC Bot
   stat = sensor_read (SensorPtr);

@@ -353,8 +352,6 @@

   // ------------------------------
-
-  // Init Mux1Temp1 Sensors
   SensorPtr = &Mux1Temp1;
   stat = sensor_read (SensorPtr);

@@ -364,6 +361,29 @@
   SensorPtr = &Mux1Temp3;
   stat = sensor_read (SensorPtr);

+    // Enable Mux Channel 2
+  stat = PCA9548A_70.control_write(PCA9548A_PORT_2_ENABLE);
+  if (SUCCESS != stat)
+  {
+    text_ptr = (PCA9548A_70.status_text[PCA9548A_70.error.error_val]);
+    Serial.printf("mux2 control write failed with return of 0x%.2X: %s\r\n", PCA9548A_70.error.error_val, text_ptr);
+    delay(dtime/2); // don't blast repeat failures too quickly
+  }
+  else
+  {
+    stat = PCA9548A_70.control_read(&control_read_val);
+    if (verbose) Serial.printf("OK control=0x%.2X\r\n", control_read_val);
+  }
+
+  // ------------------------------
+  SensorPtr = &Mux2Temp1;
+  stat = sensor_read (SensorPtr);
+
+  SensorPtr = &Mux2Temp2;
+  stat = sensor_read (SensorPtr);
+
+  SensorPtr = &Mux2Temp3;
+  stat = sensor_read (SensorPtr);

   Serial.println();


Removing program memory calculation. Increases program size with +300 bytes!

--- examples/TWI/CosaAT24CXX/CosaAT24CXX.ino
+++ examples/TWI/CosaAT24CXX/CosaAT24CXX.ino
@@ -93,9 +93,8 @@
   TRACE(&z);
   TRACE(&last);

-  // Check free memory and size of program
+  // Check free memory
   TRACE(free_memory());
-  TRACE((void*) &exit);

   // Initiate EEPROM variables
   init_eeprom();


Uppercase incoming characters

Uppercase incoming characters

--- software/firmware/LogoBotPolarGraph/LogoBotPolarGraph.ino
+++ software/firmware/LogoBotPolarGraph/LogoBotPolarGraph.ino
@@ -25,9 +25,6 @@
   LogobotText::begin(textQ);

   // bot will initialise at 260,-300
-
-  // Move to top left of writing window (100, -200)
-  //cmdQ.enqueue("", LOGO_CMD_CS);
   lineY = bot.state.y;
 }

@@ -35,7 +32,7 @@
 {
   // Parse Logo commands from Serial
   if (Serial.available()) {
-    char c = Serial.read();
+    char c = toupper(Serial.read());

     if (c == '\r' || c == '\n') {  // if found a line end
       if (cmd != "") {  // check the command isn't blank


Examples: removing commented-out include of Audio.h

--- examples/01-Basic/BasicGain/BasicGain.ino
+++ examples/01-Basic/BasicGain/BasicGain.ino
@@ -13,7 +13,6 @@
 */

 //here are the libraries that we need
-//include <Audio.h>           //include the Teensy Audio Library
 #include <Tympan_Library.h>  //include the Tympan Library

 //create audio library objects for handling the audio


the inner workings are almost done. I decided to go for a simpler approach instead of using a state machine to make debugging simpler initially

--- audible-altimeter/audible-altimeter.ino
+++ audible-altimeter/audible-altimeter.ino
@@ -5,13 +5,12 @@

 #define LED_PIN (13)

-#define ON_GROUND 0
-#define IN_AIR    1
-#define SKYDIVING 2
-
 SFE_BMP180 pressure;

-double baseline; // baseline pressure
+
+enum period_t sleepPeriod; // how long the processor should sleep for
+double basePressure, previousPressure, previousAltitude; // pressure (mb): 0 AGL
+
 //3.33 fpm elevator

 void BMPSetup() {
@@ -30,38 +29,9 @@

   // Get the baseline pressure:

-  baseline = getPressure();
+  basePressure = getPressure();
+  previousPressure = basePressure;
 }
-
-
-
-struct state;
-typedef void state_fn(struct state *);
-
-struct state
-{
-    state_fn * next;
-//    int i; // data
-    enum period_t sleepPeriod; // how long the processor should sleep for the state
-    float baseAltitude; // altitude, in m, above MSL == 0 AGL
-};
-
-state_fn foo, bar;
-
-void foo(struct state * state)
-{
-    Serial.println(__func__);
-    state->next = bar;
-}
-
-void bar(struct state * state)
-{
-    Serial.println( __func__);
-    state->next = foo;
-}
-
-struct state state = { foo, SLEEP_8S };
-

 /***************************************************
  *  Name:        setup
@@ -85,6 +55,8 @@

   BMPSetup();

+  sleepPeriod = SLEEP_8S;
+
   Serial.println("Initialisation complete.");
   delay(100); //Allow for serial print to complete.
 }
@@ -102,87 +74,41 @@
  ***************************************************/
 void loop()
 {
-  if (!state.next) state = { foo, SLEEP_8S};
-
+  double currentPressure, currentAltitude;
+
   /* Toggle the LED */
   digitalWrite(LED_PIN, HIGH);

-  // execute the next step
-  state.next(&state);
+  currentPressure = getPressure();
+  currentAltitude = pressure.altitude(currentPressure, basePressure);
+
+  if (currentAltitude < 2 && currentAltitude > -2) {
+    sleepPeriod = SLEEP_8S;
+    // consider this noise, set as base
+    basePressure = currentPressure;
+  } else {
+    // we're in the air
+    sleepPeriod = SLEEP_1S;
+
+    // human falls at 53 m/s
+    // open canopy, full flight 5 m/s
+    // refresh rate is 1 s on arduino
+    while (previousAltitude - currentAltitude > 35 && // m/s
+           currentAltitude < 1370) { // 4500 ft
+      // beep and wait for slowing down
+      tone(2, 2048);
+      LowPower.powerSave(SLEEP_1S, ADC_OFF, BOD_ON, TIMER2_ON);
+      noTone(2);
+    }
+  }
+
+  previousPressure = currentPressure;
+  previousAltitude = currentAltitude;

   digitalWrite(LED_PIN, LOW);

-  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
-
+  LowPower.powerDown(sleepPeriod, ADC_OFF, BOD_ON);
 }
-
-
-
-
-void getAltitude() {
-
-  double newAlt,P;
-
-  // Get a new pressure reading:
-
-  P = getPressure();
-
-  // Show the relative altitude difference between
-  // the new reading and the baseline reading:
-
-  newAlt = pressure.altitude(P,baseline);
-
-  baseline = P;
-}
-
-//void inPlane() {
-//  if (speed > 80) {
-//    WDT1Sec();
-//    state = SKYDIVING;
-//  }
-//}
-//
-//void skydiving() {
-//  if (oldAlt - newAlt > 8.0) {
-//    // We are descending quickly!
-//    if (absAlt < ALERT_THRESHOLD) {
-//      state = ALERTING;
-//    } else {
-//      state = SKYDIVING;
-//    }
-//  }
-//}
-//
-//void alert() {
-//  while (still descending > 80 mph) {
-//    // alert
-//  }
-//  else {
-//    // go ON_GROUND
-//  }
-//}
-//
-//void onGround() {
-//
-//  delay(100);
-//  Serial.print("relative altitude: ");
-//  if (newAlt >= 0.0) Serial.print(" "); // add a space for positive numbers
-//  Serial.println(newAlt,1);
-//  Serial.print(oldAlt);
-//  Serial.print(" ");
-//  Serial.print(newAlt);
-//  Serial.print(" ");
-//  Serial.println(oldAlt - newAlt);
-//  delay(100);
-//
-//
-//}
-
-void inAir() {
-
-}
-
-


flap updated

flap updated


Receive song configurations

Receive song configurations

--- ableton-midi-foot-controller.ino
+++ ableton-midi-foot-controller.ino
@@ -79,6 +79,14 @@

 const byte midiChannel = 1;

+const byte SONG_CONFIGURATION = 0;
+
+const byte SONG_OFFSET = 10;
+
+const byte numberOfSongs = 128 - SONG_OFFSET;
+char* songs[numberOfSongs];
+
+
 void OnNoteOn(byte channel, byte note, byte velocity) {
   digitalWrite(ledPin, HIGH);
 }
@@ -96,9 +104,51 @@

   base64_decode(decoded, (char*)dataArray, realSize);

+  String messageString = String(decoded);
+
+  boolean isConfigurationMessage = messageString.indexOf('{') != -1 && messageString.indexOf('}') != -1;
+
   lcd.clear();
-  lcd.print(decoded);
-
+  lcd.print(messageString);
+  if (isConfigurationMessage) {
+    byte configurationType = getConfigurationType(messageString);
+    switch (configurationType) {
+      case SONG_CONFIGURATION:
+        handleSongConfiguration(messageString);
+        break;
+    }
+  }
+
+}
+
+void handleSongConfiguration(String message) {
+  byte indexStart = message.indexOf('}') + 1;
+  byte index = message.substring(message.indexOf('{', indexStart) + 1, message.indexOf('}', indexStart)).toInt();
+  Serial.print(index);
+  Serial.print(" ");
+  byte songStart = message.indexOf('}', indexStart) + 1;
+  String song = message.substring(message.indexOf('{', songStart) + 1, message.indexOf('}', songStart));
+  Serial.println(song);
+  int strLen = song.length() + 1;
+  char charArray[strLen];
+  song.toCharArray(charArray, strLen);
+  songs[index] = charArray;
+
+  for (byte i = 0; i < numberOfSongs; i++) {
+    if (songs[i]) {
+      Serial.print(i);
+      Serial.print(" ");
+      Serial.println(songs[i]);
+    }
+  }
+}
+
+byte getConfigurationType(String message) {
+  String configurationString = message.substring(message.indexOf('{') + 1, message.indexOf('}'));
+  if (configurationString.equals("C")) {
+    return SONG_CONFIGURATION;
+  }
+  return -1;
 }

 void setupButtons() {


inline simple method in class definition

--- ksp-gegi-microusb/ksp-gegi-microusb.ino
+++ ksp-gegi-microusb/ksp-gegi-microusb.ino
@@ -74,7 +74,7 @@
   public:
     analogInPin(const uint8_t id, const uint8_t pin, const int threshold);
     void update(const bool force);
-    uint8_t getAValue() const;
+    uint8_t getAValue() const { return (m_lastAValue); };
   private:
     void updateJoystick() const;
     const uint8_t m_id, m_pin;
@@ -120,10 +120,6 @@
 	}
 }

-uint8_t analogInPin::getAValue(void) const {
-	return (m_lastAValue);
-}
-
 void analogInPin::updateJoystick() const {
 	switch (m_id) {
 		case 0: // throttle pot


Update OnewireKeypad_EventKey.ino

Update OnewireKeypad_EventKey.ino

Removed Precision

--- Examples/OnewireKeypad_EventKey/OnewireKeypad_EventKey.ino
+++ Examples/OnewireKeypad_EventKey/OnewireKeypad_EventKey.ino
@@ -7,28 +7,24 @@
   '*','0','#',
 };

-OnewireKeypad <Print, 12 > Keypad(Serial, KEYS, 4, 3, A0, 4700, 1000, ExtremePrec );
+OnewireKeypad <Print, 12 > Keypad(Serial, KEYS, 4, 3, A0, 4700, 1000 );

-void setup ()
-{
+void setup () {
   Serial.begin(115200);
   pinMode(13,OUTPUT);
   Keypad.addEventKey(test, '#'); // Add Function to list | Key to look for
   Keypad.addEventKey(togglePin13, '*');
 }

-void loop()
-{
+void loop() {
   Keypad.ListenforEventKey(); // check if an EventKey is found
 }

-void test()
-{
+void test() {
   Serial.println("This is a test");
   Keypad.deleteEventKey('#'); // remove function from list
 }

-void togglePin13()
-{
+void togglePin13() {
   digitalWrite(13,!digitalRead(13));
 }