Refactor Arduino data model - Use objects instead of actions for JSON data model - Add ServoData struct to store all info for a given servo - Add ability to assign certain servos as 'receiver only' servos - Add emergency input stop via double switch of the cutover - Change sendJson methods to be more descriptive - Improve error messages (refactoring freed up additional memory) - Rename variables to use more intuitive names

--- arduino/arduino_sketch/arduino_sketch.ino
+++ arduino/arduino_sketch/arduino_sketch.ino
@@ -7,14 +7,17 @@
 #include <PinChangeInt.h>
 #include <Servo.h>

+//Max value for variable type byte
+const byte BYTE_MAX = 255;
+
 //Sets the max char array size for JSON serial input and output
-const byte CHAR_ARRAY_SIZE = 235;
-
-//Pulse threshold values for receiver input for cutover between auto and manual control
-const byte CUTOVER_BUFFER = 125;
+const byte CHAR_ARRAY_SIZE = BYTE_MAX;
+
+//The allowed margin from the cutover min/max input
+const byte CUTOVER_MARGIN = 125;

 //Number of cutover samples to use for cutoverInAverage
-const byte CUTOVER_SAMPLES = 10;
+const byte CUTOVER_SAMPLE_SIZE = 10;

 //Byte flags used to store whether there is an update from a given input
 const byte FLAG_AILERON = 1;
@@ -27,6 +30,9 @@
 const byte SERVO_MIN = 0;
 const byte SERVO_MAX = 180;

+//Cutover threshold in milliseconds
+const int CUTOVER_THRESHOLD = 1500;
+
 //Default servo input value
 //TODO use better calibration default
 const int RECEIVER_INPUT_DEFAULT = 1500;
@@ -40,7 +46,7 @@

 //Used to store the byte flag values above
 //Note this byte MUST be volatile since it is used in the main code and in the Interrupt Service Routine (ISR) methods
-volatile byte servoInputFlags;
+volatile byte receiverInputFlags;

 //Unsigned ints used to store microsecond values
 //Note: these ints MUST be volatile since they are used in the main code and in the ISR methods
@@ -50,23 +56,6 @@
 volatile uint16_t rudderInValue;
 volatile uint16_t throttleInValue;

-//Stores the pin number for each receiver input
-byte aileronInPin = 255;
-byte cutoverInPin = 255;
-byte elevatorInPin = 255;
-byte rudderInPin = 255;
-byte throttleInPin = 255;
-
-//Stores the servo range of the throttle
-byte aileronMax = SERVO_MAX;
-byte aileronMin = SERVO_MIN;
-byte elevatorMax = SERVO_MAX;
-byte elevatorMin = SERVO_MIN;
-byte rudderMax = SERVO_MAX;
-byte rudderMin = SERVO_MIN;
-byte throttleMax = SERVO_MAX;
-byte throttleMin = SERVO_MIN;
-
 //Determines if the servos are in the process of calibration
 boolean calibrationMode = false;

@@ -76,8 +65,11 @@
 //Determines if new Json data has been collected from serial input for processing
 boolean newData = false;

-//Determines if the plane is controlled manually (remote control) or via autopilot (phone)
-boolean manualControl = false;
+//Determines if the plane is controlled only by the receiver
+boolean receiverControl = false;
+
+//Determines if the plane control is shared between the phone and the receiver
+boolean sharedControl = false;

 //All valid input/output must start/end with the corresponding chars below
 char endMarker = '#';
@@ -86,38 +78,33 @@
 //This array stores Json characters read from serial input
 char receivedJson[CHAR_ARRAY_SIZE];

-//Calibrated min and max for all receiver input (in microseconds)
-uint16_t aileronInMax = RECEIVER_INPUT_DEFAULT;
-uint16_t aileronInMin = RECEIVER_INPUT_DEFAULT;
-uint16_t cutoverInMax = RECEIVER_INPUT_DEFAULT;
-uint16_t cutoverInMin = RECEIVER_INPUT_DEFAULT;
-uint16_t elevatorInMax = RECEIVER_INPUT_DEFAULT;
-uint16_t elevatorInMin = RECEIVER_INPUT_DEFAULT;
-uint16_t rudderInMax = RECEIVER_INPUT_DEFAULT;
-uint16_t rudderInMin = RECEIVER_INPUT_DEFAULT;
-uint16_t throttleInMax = RECEIVER_INPUT_DEFAULT;
-uint16_t throttleInMin = RECEIVER_INPUT_DEFAULT;
-
 //The running average for cutover receiver input
-uint16_t cutoverInAverage = RECEIVER_INPUT_DEFAULT;
-
-//Servos
-Servo aileron;
-Servo elevator;
-Servo rudder;
-Servo throttle;
+uint16_t cutoverInputAverage = RECEIVER_INPUT_DEFAULT;
+
+//The start time for determining the cutover double switch flip for emergency input shutoff
+uint32_t receiverControlStartTime = millis();
+
+struct ServoData {
+  byte outputMax = SERVO_MAX;
+  byte outputMin = SERVO_MIN;
+  byte inputPin = BYTE_MAX;  //Receiver input pin for servo
+  boolean receiverInputOnly = false; //Determines whether this servo only takes receiver input
+  uint16_t inputMax = RECEIVER_INPUT_MIN;  //Calibrated receiver input max for servo
+  uint16_t inputMin = RECEIVER_INPUT_MAX;  //Calibrated receiver input min for servo
+  Servo servo;
+} aileron, cutover, elevator, rudder, throttle;

 void setup() {
   Serial.begin(BAUD_RATE);  //Set the baud rate
   while (!Serial) {}  //Wait for serial port to connect
-  sendJson("status", "ready");  //Inform serial interface that the Arduino is ready
+  sendJsonString("status", "ready");  //Inform serial interface that the Arduino is ready
 }

 void loop() {
   readSerialJsonInput();
   processReceivedJson();
   processReceiverInput();
-}
+}

 //Reads json serial input and stores input in a char array
 //Most of this method code is taken from: https://forum.arduino.cc/index.php?topic=288234.0
@@ -136,7 +123,7 @@
         index++;
         if (index >= CHAR_ARRAY_SIZE) {
           index = CHAR_ARRAY_SIZE - 1;
-          sendJson("error", "Serial buffer overflow");
+          sendJsonString("error", "Serial buffer overflow");
         }
       }
       else {
@@ -152,11 +139,28 @@
   }
 }

-//Example JSON strings below:
-//@{"config":{"throttle":10, "elevator":9, "rudder":8, "aileron":7, "aileronIn":6, "throttleIn":5, "elevatorIn":4, "rudderIn":3, "cutoverIn":2}, "servos":{"throttle":32, "elevator":90, "rudder":90, "aileron":90}}#
-//@{"calibration":{"aileronInMin":1084,"aileronInMax":1688,"elevatorInMin":964,"elevatorInMax":1752,"rudderInMin":1044,"rudderInMax":1800,"throttleInMin":1020,"throttleInMax":1704,"cutoverInMin":776,"cutoverInMax":1844}}#
-//@{"ranges":{"aileronMin":45, "aileronMax":135, "elevatorMin":0, "elevatorMax":180, "rudderMin":0, "rudderMax":180, "throttleMin":32, "throttleMax":124}}#
-//@{"servos":{"throttle":0, "elevator":100, "aileron":120, "rudder":75}}#
+//Example JSON input below
+//Complete configuration
+//@{"aileron":{"inputConfig":{"max":1688,"min":1084,"pin":6,"receiverOnly":false},"outputConfig":{"max":180,"min":0,"pin":7},"value":90}}#
+//@{"elevator":{"inputConfig":{"max":1752,"min":964,"pin":4,"receiverOnly":true},"outputConfig":{"max":180,"min":0,"pin":9},"value":90}}#
+//@{"rudder":{"inputConfig":{"max":1800,"min":1044,"pin":3,"receiverOnly":true},"outputConfig":{"max":180,"min":0,"pin":8},"value":90}}#
+//@{"throttle":{"inputConfig":{"max":1688,"min":1084,"pin":5,"receiverOnly":true},"outputConfig":{"max":180,"min":0,"pin":10},"value":90}}#
+//@{"cutover":{"inputConfig":{"max":1844,"min":776,"pin":2}}}#
+
+//Configuration without calibration or receiverOnly configuration
+//@{"aileron":{"inputConfig":{"pin":6},"outputConfig":{"max":135,"min":45,"pin":7},"value":90}}#
+//@{"elevator":{"inputConfig":{"pin":4},"outputConfig":{"max":180,"min":0,"pin":9},"value":90}}#
+//@{"rudder":{"inputConfig":{"pin":3},"outputConfig":{"max":180,"min":0,"pin":8},"value":90}}#
+//@{"throttle":{"inputConfig":{"pin":5},"outputConfig":{"max":124,"min":32,"pin":10},"value":32}}#
+//@{"cutover":{"inputConfig":{"pin":2}}}#
+
+//Receiver calibration data (sent or received)
+//@{"aileron":{"inputConfig":{"max":1832,"min":780}},"cutover":{"inputConfig":{"max":1836,"min":756}},"elevator":{"inputConfig":{"max":1644,"min":1248}},"rudder":{"inputConfig":{"max":1612,"min":980}},"throttle":{"inputConfig":{"max":1708,"min":1016}}}#
+
+//Neutral servo command
+//@{"aileron":{"value":90},"elevator":{"value":90},"rudder":{"value":90},"throttle":{"value":32}}#
+
+//Processes JSON received in the readSerialJsonInput() method
 void processReceivedJson() {
   if (newData) {
     StaticJsonBuffer<CHAR_ARRAY_SIZE> jsonBuffer;
@@ -164,7 +168,7 @@

     //If the JSON object failed to parse, inform the serial interface and return
     if (!root.success()) {
-      sendJson("error", "Parsing JSON failed");
+      sendJsonString("error", "Parsing JSON failed");
       newData = false;
       return;
     }
@@ -172,179 +176,121 @@
     //If status is requested, send status check response
     if (root.containsKey("request")) {
       const char* request = root["request"];
-      if (strcmp(request, "status") == 0) sendJson("status", "ready");
-    }
-
-    //Enable or disable manual control
-    if (root.containsKey("manualControl")) {
+      if (strcmp(request, "status") == 0) sendJsonString("status", "ready");
+    }
+
+    //Enable or disable receiver control
+    if (root.containsKey("receiverControl")) {
       if (isCalibrated) {
-        manualControl = (boolean) root["manualControl"];
-        sendJson("manualControl", manualControl);
+        receiverControl = (boolean) root["receiverControl"];
+        sendJsonBoolean("receiverControl", receiverControl);
       } else {
-        sendJson("error", "Calibration required");
+        sendJsonString("error", "Calibration required");
       }
     }

     //Enable or disable calibration mode
     if (root.containsKey("calibrationMode")) {
-      if (!manualControl) {
+      if (!receiverControl) {
         calibrationMode = (boolean) root["calibrationMode"];
-        sendJson("calibrationMode", calibrationMode);
+        sendJsonBoolean("calibrationMode", calibrationMode);
         if (calibrationMode) {
           resetCalibration();
         } else {
-          if (calibrationComplete()) isCalibrated = true;
-          sendCalibrationJsonData();
-        }
-      } else {
-        sendJson("error", "Disable manual control");
-      }
-    }
-
-    //Assigns pin numbers to the motor, servos, and receiver inputs based on the received JSON
-    if (root.containsKey("config")) {
-      if (!manualControl) {
-        JsonObject& config = root["config"];
-        if (config.containsKey("aileron")) {
-          if (aileron.attached()) aileron.detach();
-          byte aileronOutPin = (byte) config["aileron"];
-          aileron.attach(aileronOutPin);
-        }
-        if (config.containsKey("elevator")) {
-          if (elevator.attached()) elevator.detach();
-          byte elevatorOutPin = (byte) config["elevator"];
-          elevator.attach(elevatorOutPin);
-        }
-        if (config.containsKey("rudder")) {
-          if (rudder.attached()) rudder.detach();
-          byte rudderOutPin = (byte) config["rudder"];
-          rudder.attach(rudderOutPin);
-        }
-        if (config.containsKey("throttle")) {
-          if (throttle.attached()) throttle.detach();
-          byte throttleOutPin = (byte) config["throttle"];
-          throttle.attach(throttleOutPin);
-        }
-        if (config.containsKey("aileronIn")) {
-          if (aileronInPin != 255) PCintPort::detachInterrupt(aileronInPin);
-          aileronInPin = (byte) config["aileronIn"];
-          PCintPort::attachInterrupt(aileronInPin, listenForAileron, CHANGE);
-        }
-        if (config.containsKey("cutoverIn")) {
-          if (cutoverInPin != 255) PCintPort::detachInterrupt(cutoverInPin);
-          cutoverInPin = (byte) config["cutoverIn"];
-          PCintPort::attachInterrupt(cutoverInPin, listenForCutover, CHANGE);
-        }
-        if (config.containsKey("elevatorIn")) {
-          if (elevatorInPin != 255) PCintPort::detachInterrupt(elevatorInPin);
-          elevatorInPin = (byte) config["elevatorIn"];
-          PCintPort::attachInterrupt(elevatorInPin, listenForElevator, CHANGE);
-        }
-        if (config.containsKey("rudderIn")) {
-          if (rudderInPin != 255) PCintPort::detachInterrupt(rudderInPin);
-          rudderInPin = (byte) config["rudderIn"];
-          PCintPort::attachInterrupt(rudderInPin, listenForRudder, CHANGE);
-        }
-        if (config.containsKey("throttleIn")) {
-          if (throttleInPin != 255) PCintPort::detachInterrupt(throttleInPin);
-          throttleInPin = (byte) config["throttleIn"];
-          PCintPort::attachInterrupt(throttleInPin, listenForThrottle, CHANGE);
-        }
-      } else {
-        sendJson("error", "Disable manual control");
-      }
-    }
-
-    if (root.containsKey("ranges")) {
-      if (!manualControl) {
-        JsonObject &ranges = root["ranges"];
-        if (ranges.containsKey("aileronMax")) aileronMax = (byte) ranges["aileronMax"];
-        if (ranges.containsKey("aileronMin")) aileronMin = (byte) ranges["aileronMin"];
-        if (ranges.containsKey("elevatorMax")) elevatorMax = (byte) ranges["elevatorMax"];
-        if (ranges.containsKey("elevatorMin")) elevatorMin = (byte) ranges["elevatorMin"];
-        if (ranges.containsKey("rudderMax")) rudderMax = (byte) ranges["rudderMax"];
-        if (ranges.containsKey("rudderMin")) rudderMin = (byte) ranges["rudderMin"];
-        if (ranges.containsKey("throttleMax")) throttleMax = (byte) ranges["throttleMax"];
-        if (ranges.containsKey("throttleMin")) throttleMin = (byte) ranges["throttleMin"];
-      } else {
-        sendJson("error", "Disable manual control");
-      }
-    }
-
-    if (root.containsKey("calibration")) {
-      if (!manualControl) {
-        resetCalibration();
-        JsonObject &calibration = root["calibration"];
-        if (calibration.containsKey("aileronInMax")) aileronInMax = (uint16_t) calibration["aileronInMax"];
-        if (calibration.containsKey("aileronInMin")) aileronInMin = (uint16_t) calibration["aileronInMin"];
-        if (calibration.containsKey("elevatorInMax")) elevatorInMax = (uint16_t) calibration["elevatorInMax"];
-        if (calibration.containsKey("elevatorInMin")) elevatorInMin = (uint16_t) calibration["elevatorInMin"];
-        if (calibration.containsKey("rudderInMax")) rudderInMax = (uint16_t) calibration["rudderInMax"];
-        if (calibration.containsKey("rudderInMin")) rudderInMin = (uint16_t) calibration["rudderInMin"];
-        if (calibration.containsKey("throttleInMax")) throttleInMax = (uint16_t) calibration["throttleInMax"];
-        if (calibration.containsKey("throttleInMin")) throttleInMin = (uint16_t) calibration["throttleInMin"];
-        if (calibration.containsKey("cutoverInMax")) cutoverInMax = (uint16_t) calibration["cutoverInMax"];
-        if (calibration.containsKey("cutoverInMin")) cutoverInMin = (uint16_t) calibration["cutoverInMin"];
-        if (calibrationComplete()) isCalibrated = true;
-        sendJson("isCalibrated", isCalibrated);
-      } else {
-        sendJson("error", "Disable manual control");
-      }
-    }
-
-    //Set the servo values according to the received JSON
-    if (root.containsKey("servos")) {
-      if (!manualControl) {
-        JsonObject &servos = root["servos"];
-        if (servos.containsKey("aileron")) {
-          if (aileron.attached()) {
-            byte aileronValue = servos["aileron"];
-            aileron.write(aileronValue);
-            sendJson("aileron", aileronValue);
+          if (calibrationComplete()){
+            isCalibrated = true;
+            sendCalibrationJsonData();
           } else {
-            sendJson("error", "Aileron not set");
-          }
-        }
-        if (servos.containsKey("elevator")) {
-          if (elevator.attached()) {
-            byte elevatorValue = servos["elevator"];
-            elevator.write(elevatorValue);
-            sendJson("elevator", elevatorValue);
-          } else {
-            sendJson("error", "Elevator not set");
-          }
-        }
-        if (servos.containsKey("rudder")) {
-          if (rudder.attached()) {
-            byte rudderValue = servos["rudder"];
-            rudder.write(rudderValue);
-            sendJson("rudder", rudderValue);
-          } else {
-            sendJson("error", "Rudder not set");
-          }
-        }
-        if (servos.containsKey("throttle")) {
-          if (throttle.attached()) {
-            byte throttleValue = servos["throttle"];
-            throttle.write(throttleValue);
-            sendJson("throttle", throttleValue);
-          } else {
-            sendJson("error", "Throttle not set");
+            sendJsonString("error", "Calibration not complete");
           }
         }
       } else {
-        sendJson("error", "Disable manual control");
-      }
-    }
+        sendJsonString("error", "Disable receiver control to change calibration mode");
+      }
+    }
+
+    //Assigns pin numbers to the motor, servos, and receiver inputs based on the received JSON
+    if (root.containsKey("aileron")) {
+      processServoJson(root["aileron"], aileron, "aileron", listenForAileron, "Unassigned aileron pin");
+    }
+    if (root.containsKey("cutover")) {
+      //Cutover is input only, so output only function parameters can be null
+      processServoJson(root["cutover"], cutover, "", listenForCutover, "");
+    }
+    if (root.containsKey("elevator")) {
+      processServoJson(root["elevator"], elevator, "elevator", listenForElevator, "Unassigned elevator pin");
+    }
+    if (root.containsKey("rudder")) {
+      processServoJson(root["rudder"], rudder, "rudder", listenForRudder, "Unassigned rudder pin");
+    }
+    if (root.containsKey("throttle")) {
+      processServoJson(root["throttle"], throttle, "throttle", listenForThrottle, "Unassigned throttle pin");
+    }
+
     //Reset newData to false so we can read new serial input
     newData = false;
+  }
+}
+
+//Processes received JSON for a given servo (e.g. ServoData struct)
+//The inputISR is the interrupt service routine function for triggering action upon receiver input
+void processServoJson(JsonObject& servoJson, ServoData& servoData, const char servoType[], void inputISR(), const char servoError[]) {
+  if (!receiverControl) {
+    //Check for any output configuration parameters for this servo
+    if (servoJson.containsKey("outputConfig")) {
+      JsonObject& outputConfig = servoJson["outputConfig"];
+      if (outputConfig.containsKey("max")) {
+        servoData.outputMax = (byte) outputConfig["max"];
+      }
+      if (outputConfig.containsKey("min")) {
+        servoData.outputMin = (byte) outputConfig["min"];
+      }
+      if (outputConfig.containsKey("pin")) {
+        if (servoData.servo.attached()) servoData.servo.detach();
+        byte servoOutPin = (byte) outputConfig["pin"];
+        servoData.servo.attach(servoOutPin);
+      }
+    }
+    //Check for any input configuration parameters for this servo
+    if (servoJson.containsKey("inputConfig")) {
+      JsonObject& inputConfig = servoJson["inputConfig"];
+      if (inputConfig.containsKey("max")) {
+        servoData.inputMax = (uint16_t) inputConfig["max"];
+      }
+      if (inputConfig.containsKey("min")) {
+        servoData.inputMin = (uint16_t) inputConfig["min"];
+      }
+      if (inputConfig.containsKey("pin")) {
+        if (servoData.inputPin != BYTE_MAX) PCintPort::detachInterrupt(servoData.inputPin);
+        servoData.inputPin = (byte) inputConfig["pin"];
+        PCintPort::attachInterrupt(servoData.inputPin, inputISR, CHANGE);
+      }
+      if (inputConfig.containsKey("receiverOnly")) {
+        servoData.receiverInputOnly = (boolean) inputConfig["receiverOnly"];
+      }
+    }
+    //Only write to servo if the phone input for this servo has permission to do so
+    if (!servoData.receiverInputOnly) {
+      //Check for any servo output values to write to the servo
+      if (servoJson.containsKey("value")) {
+        if (servoData.servo.attached()) {
+          byte value = (byte) servoJson["value"];
+          servoData.servo.write(value);
+          sendJsonServoOutput(servoType, value);
+        } else {
+          sendJsonString("error", servoError);
+        }
+      }
+    }
+  } else {
+    sendJsonString("error", "Disable receiver control to configure servos");
   }
 }

 //Processes input from the receiver
 void processReceiverInput() {
   //Static variables are used because they maintain their value over multiple function calls
-  static byte servoInputFlagsLocal;
+  static byte receiverInputFlagsLocal;
   static uint16_t aileronInValueLocal;
   static uint16_t cutoverInValueLocal;
   static uint16_t elevatorInValueLocal;
@@ -352,103 +298,71 @@
   static uint16_t throttleInValueLocal;

   //If any servo input byte flags were set in any of the ISR methods, process them here
-  if (servoInputFlags != 0) {
+  if (receiverInputFlags != 0) {
     noInterrupts();
     //While interrupts are paused, copy new servo input values to the corresponding local static variables
-    servoInputFlagsLocal = servoInputFlags;
-    if (servoInputFlagsLocal & FLAG_CUTOVER) cutoverInValueLocal = cutoverInValue;
-      if (manualControl || calibrationMode) {
-        if (servoInputFlagsLocal & FLAG_AILERON) aileronInValueLocal = aileronInValue;
-        if (servoInputFlagsLocal & FLAG_ELEVATOR) elevatorInValueLocal = elevatorInValue;
-        if (servoInputFlagsLocal & FLAG_RUDDER) rudderInValueLocal = rudderInValue;
-        if (servoInputFlagsLocal & FLAG_THROTTLE) throttleInValueLocal = throttleInValue;
-      }
-    servoInputFlags = 0;
+    receiverInputFlagsLocal = receiverInputFlags;
+    if (receiverInputFlagsLocal & FLAG_CUTOVER) cutoverInValueLocal = cutoverInValue;
+      if (receiverControl || calibrationMode) {
+        if (receiverInputFlagsLocal & FLAG_AILERON) aileronInValueLocal = aileronInValue;
+        if (receiverInputFlagsLocal & FLAG_ELEVATOR) elevatorInValueLocal = elevatorInValue;
+        if (receiverInputFlagsLocal & FLAG_RUDDER) rudderInValueLocal = rudderInValue;
+        if (receiverInputFlagsLocal & FLAG_THROTTLE) throttleInValueLocal = throttleInValue;
+      }
+    receiverInputFlags = 0;
     interrupts();
   }
-  //If the cutover switch is flipped, set manualControl accordingly
-  if (servoInputFlagsLocal & FLAG_CUTOVER) {
+  //If the cutover switch is flipped, set receiverControl accordingly
+  if (receiverInputFlagsLocal & FLAG_CUTOVER) {
     //Only use cutover values within the set range for receiver input
     if (calibrationMode && isValidReceiverInput(cutoverInValueLocal)) {
-      if (cutoverInValueLocal > cutoverInMax) cutoverInMax = cutoverInValueLocal;
-      if (cutoverInValueLocal < cutoverInMin) cutoverInMin = cutoverInValueLocal;
+      if (cutoverInValueLocal > cutover.inputMax) cutover.inputMax = cutoverInValueLocal;
+      if (cutoverInValueLocal < cutover.inputMin) cutover.inputMin = cutoverInValueLocal;
     } else if (isCalibrated) {
       //Calculate weighted average for cutover
-      cutoverInAverage = (cutoverInValueLocal + (CUTOVER_SAMPLES - 1)*cutoverInAverage)/CUTOVER_SAMPLES;
-      if (isValidReceiverInput(cutoverInAverage)) {
-        if (manualControl && cutoverInAverage > (cutoverInMax - CUTOVER_BUFFER)) {
-          manualControl = false;
-          sendJson("manualControl", manualControl);
-        } else if (!manualControl && cutoverInAverage < (cutoverInMin + CUTOVER_BUFFER)) {
-          manualControl = true;
-          sendJson("manualControl", manualControl);
+      cutoverInputAverage = (cutoverInValueLocal + (CUTOVER_SAMPLE_SIZE - 1)*cutoverInputAverage)/CUTOVER_SAMPLE_SIZE;
+      if (isValidReceiverInput(cutoverInputAverage)) {
+        if (receiverControl && cutoverInputAverage > (cutover.inputMax - CUTOVER_MARGIN)) {
+          receiverControl = false;
+          //Checks if the cutover switched back and forth slower than the threshold (e.g. not emergency input stop)
+          if ((millis() - receiverControlStartTime) > CUTOVER_THRESHOLD) {
+            sharedControl = true;
+            sendJsonBoolean("sharedControl", true);
+          }
+          sendJsonBoolean("receiverControl", receiverControl);
+        } else if (!receiverControl && cutoverInputAverage < (cutover.inputMin + CUTOVER_MARGIN)) {
+          sharedControl = false;
+          receiverControl = true;
+          sendJsonBoolean("receiverControl", receiverControl);
+          sendJsonBoolean("sharedControl", false);
+          receiverControlStartTime = millis();
         }
-      } else if (manualControl) {
-        sendJson("error", "Invalid cutover input");
-      }
-    }
-  }
-
-  //Only process servo input if manualControl or calibrationMode are enabled
-  if (manualControl || calibrationMode) {
+      } else if (receiverControl) {
+        sendJsonString("error", "Cutover input out of range");
+      }
+    }
+  }
+
+  //Only process servo input if receiverControl or calibrationMode are enabled
+  if (receiverControl || calibrationMode) {
     //Process input for each servo that received new input from the receiver
-    if (servoInputFlagsLocal & FLAG_AILERON) {
-      //Only use aileron values within the set range for receiver input
-      if (isValidReceiverInput(aileronInValueLocal)) {
-        if (calibrationMode) {
-          if (aileronInValueLocal > aileronInMax) aileronInMax = aileronInValueLocal;
-          if (aileronInValueLocal < aileronInMin) aileronInMin = aileronInValueLocal;
-        } else if (manualControl) {
-          processServoInput(aileron, aileronInValueLocal, "aileron", "Aileron not set");
-        }
-      } else {
-        sendJson("error", "Invalid aileron input");
-      }
-    }
-    if (servoInputFlagsLocal & FLAG_ELEVATOR) {
-      //Only use elevator values within the set range for receiver input
-      if (isValidReceiverInput(elevatorInValueLocal)) {
-        if (calibrationMode) {
-          if (elevatorInValueLocal > elevatorInMax) elevatorInMax = elevatorInValueLocal;
-          if (elevatorInValueLocal < elevatorInMin) elevatorInMin = elevatorInValueLocal;
-        } else if (manualControl) {
-          processServoInput(elevator, elevatorInValueLocal, "elevator", "Elevator not set");
-        }
-      } else {
-        sendJson("error", "Invalid elevator input");
-      }
-    }
-    if (servoInputFlagsLocal & FLAG_RUDDER) {
-      //Only use rudder values within the set range for receiver input
-      if (isValidReceiverInput(rudderInValueLocal)) {
-        if (calibrationMode) {
-          if (rudderInValueLocal > rudderInMax) rudderInMax = rudderInValueLocal;
-          if (rudderInValueLocal < rudderInMin) rudderInMin = rudderInValueLocal;
-        } else if (manualControl) {
-          processServoInput(rudder, rudderInValueLocal, "rudder", "Rudder not set");
-        }
-      } else {
-        sendJson("error", "Invalid rudder input");
-      }
-    }
-    if (servoInputFlagsLocal & FLAG_THROTTLE) {
-      //Only use throttle values within the set range for receiver input
-      if (isValidReceiverInput(throttleInValueLocal)) {
-        if (calibrationMode) {
-          if (throttleInValueLocal > throttleInMax) throttleInMax = throttleInValueLocal;
-          if (throttleInValueLocal < throttleInMin) throttleInMin = throttleInValueLocal;
-        } else if (manualControl) {
-          processServoInput(throttle, throttleInValueLocal, "throttle", "Throttle not set");
-        }
-      } else {
-        sendJson("error", "Invalid throttle input");
-      }
+    if (receiverInputFlagsLocal & FLAG_AILERON) {
+      processServoInput(aileron, aileronInValueLocal, "aileron", "Unassigned aileron pin", "Aileron input out of range");
+    }
+    if (receiverInputFlagsLocal & FLAG_ELEVATOR) {
+      processServoInput(elevator, elevatorInValueLocal, "elevator", "Unassigned elevator pin", "Elevator input out of range");
+    }
+    if (receiverInputFlagsLocal & FLAG_RUDDER) {
+      processServoInput(rudder, rudderInValueLocal, "rudder", "Unassigned rudder pin", "Rudder input out of range");
+    }
+    if (receiverInputFlagsLocal & FLAG_THROTTLE) {
+      processServoInput(throttle, throttleInValueLocal, "throttle", "Unassigned throttle pin", "Throttle input out of range");
     }
   }
 }

 //Takes a key (text) value (boolean) pair and sends them as JSON over the serial interface
-void sendJson(const char key[], boolean value) {
+void sendJsonBoolean(const char key[], boolean value) {
   StaticJsonBuffer<CHAR_ARRAY_SIZE> jsonBuffer;
   JsonObject& root = jsonBuffer.createObject();
   root[key] = value;
@@ -458,7 +372,7 @@
 }

 //Takes a key value (char array) pair and sends them as JSON over the serial interface
-void sendJson(const char key[], const char value[]) {
+void sendJsonString(const char key[], const char value[]) {
   StaticJsonBuffer<CHAR_ARRAY_SIZE> jsonBuffer;
   JsonObject& root = jsonBuffer.createObject();
   root[key] = value;
@@ -468,10 +382,12 @@
 }

 //Takes a key (text) value (int) pair and sends them as JSON over the serial interface
-void sendJson(const char key[], byte value) {
+void sendJsonServoOutput(const char key[], byte value) {
   StaticJsonBuffer<CHAR_ARRAY_SIZE> jsonBuffer;
   JsonObject& root = jsonBuffer.createObject();
-  root[key] = value;
+  JsonObject& servoJson = jsonBuffer.createObject();
+  servoJson["value"] = value;
+  root[key] = servoJson;
   Serial.print(startMarker);
   root.printTo(Serial);
   Serial.println(endMarker);
@@ -480,53 +396,77 @@
 //Sends all calibrated receiver input max and min values as JSON over the serial interface
 void sendCalibrationJsonData() {
   StaticJsonBuffer<CHAR_ARRAY_SIZE> jsonBuffer;
-  JsonObject &root = jsonBuffer.createObject();
-  JsonObject &calibration = jsonBuffer.createObject();;
-  calibration["aileronInMin"] = aileronInMin;
-  calibration["aileronInMax"] = aileronInMax;
-  calibration["elevatorInMin"] = elevatorInMin;
-  calibration["elevatorInMax"] = elevatorInMax;
-  calibration["rudderInMin"] = rudderInMin;
-  calibration["rudderInMax"] = rudderInMax;
-  calibration["throttleInMin"] = throttleInMin;
-  calibration["throttleInMax"] = throttleInMax;
-  calibration["cutoverInMin"] = cutoverInMin;
-  calibration["cutoverInMax"] = cutoverInMax;
-  root["calibration"] = calibration;
+  JsonObject& root = jsonBuffer.createObject();
+
+  JsonObject& aileronJson = jsonBuffer.createObject();
+  JsonObject& cutoverJson = jsonBuffer.createObject();
+  JsonObject& elevatorJson = jsonBuffer.createObject();
+  JsonObject& rudderJson = jsonBuffer.createObject();
+  JsonObject& throttleJson = jsonBuffer.createObject();
+
+  JsonObject& aileronInputJson = jsonBuffer.createObject();
+  JsonObject& cutoverInputJson = jsonBuffer.createObject();
+  JsonObject& elevatorInputJson = jsonBuffer.createObject();
+  JsonObject& rudderInputJson = jsonBuffer.createObject();
+  JsonObject& throttleInputJson = jsonBuffer.createObject();
+
+  aileronInputJson["max"] = aileron.inputMax;
+  cutoverInputJson["max"] = cutover.inputMax;
+  elevatorInputJson["max"] = elevator.inputMax;
+  rudderInputJson["max"] = rudder.inputMax;
+  throttleInputJson["max"] = throttle.inputMax;
+
+  aileronInputJson["min"] = aileron.inputMin;
+  cutoverInputJson["min"] = cutover.inputMin;
+  elevatorInputJson["min"] = elevator.inputMin;
+  rudderInputJson["min"] = rudder.inputMin;
+  throttleInputJson["min"] = throttle.inputMin;
+
+  aileronJson["inputConfig"] = aileronInputJson;
+  cutoverJson["inputConfig"] = cutoverInputJson;
+  elevatorJson["inputConfig"] = elevatorInputJson;
+  rudderJson["inputConfig"] = rudderInputJson;
+  throttleJson["inputConfig"] = throttleInputJson;
+
+  root["aileron"] = aileronJson;
+  root["cutover"] = cutoverJson;
+  root["elevator"] = elevatorJson;
+  root["rudder"] = rudderJson;
+  root["throttle"] = throttleJson;
+
   Serial.print(startMarker);
   root.printTo(Serial);
   Serial.println(endMarker);
 }

 //Checks if the receiver inputs have been calibrated
-//TODO use better verification method
 boolean calibrationComplete() {
-  if (aileronInMax == RECEIVER_INPUT_DEFAULT) return false;
-  if (aileronInMin == RECEIVER_INPUT_DEFAULT) return false;
-  if (elevatorInMax == RECEIVER_INPUT_DEFAULT) return false;
-  if (elevatorInMin == RECEIVER_INPUT_DEFAULT) return false;
-  if (rudderInMax == RECEIVER_INPUT_DEFAULT) return false;
-  if (rudderInMin == RECEIVER_INPUT_DEFAULT) return false;
-  if (throttleInMax == RECEIVER_INPUT_DEFAULT) return false;
-  if (throttleInMin == RECEIVER_INPUT_DEFAULT) return false;
-  if (cutoverInMax == RECEIVER_INPUT_DEFAULT) return false;
-  if (cutoverInMin == RECEIVER_INPUT_DEFAULT) return false;
+  if (aileron.inputMax == RECEIVER_INPUT_MIN) return false;
+  if (aileron.inputMin == RECEIVER_INPUT_MAX) return false;
+  if (elevator.inputMax == RECEIVER_INPUT_MIN) return false;
+  if (elevator.inputMin == RECEIVER_INPUT_MAX) return false;
+  if (rudder.inputMax == RECEIVER_INPUT_MIN) return false;
+  if (rudder.inputMin == RECEIVER_INPUT_MAX) return false;
+  if (throttle.inputMax == RECEIVER_INPUT_MIN) return false;
+  if (throttle.inputMin == RECEIVER_INPUT_MAX) return false;
+  if (cutover.inputMax == RECEIVER_INPUT_MIN) return false;
+  if (cutover.inputMin == RECEIVER_INPUT_MAX) return false;
   return true;
 }

 //Reset all calibrated receiver input values to the default
 void resetCalibration() {
   isCalibrated = false;
-  aileronInMax = RECEIVER_INPUT_DEFAULT;
-  aileronInMin = RECEIVER_INPUT_DEFAULT;
-  elevatorInMax = RECEIVER_INPUT_DEFAULT;
-  elevatorInMin = RECEIVER_INPUT_DEFAULT;
-  rudderInMax = RECEIVER_INPUT_DEFAULT;
-  rudderInMin = RECEIVER_INPUT_DEFAULT;
-  throttleInMax = RECEIVER_INPUT_DEFAULT;
-  throttleInMin = RECEIVER_INPUT_DEFAULT;
-  cutoverInMax = RECEIVER_INPUT_DEFAULT;
-  cutoverInMin = RECEIVER_INPUT_DEFAULT;
+  aileron.inputMax = RECEIVER_INPUT_MIN;
+  aileron.inputMin = RECEIVER_INPUT_MAX;
+  elevator.inputMax = RECEIVER_INPUT_MIN;
+  elevator.inputMin = RECEIVER_INPUT_MAX;
+  rudder.inputMax = RECEIVER_INPUT_MIN;
+  rudder.inputMin = RECEIVER_INPUT_MAX;
+  throttle.inputMax = RECEIVER_INPUT_MIN;
+  throttle.inputMin = RECEIVER_INPUT_MAX;
+  cutover.inputMax = RECEIVER_INPUT_MIN;
+  cutover.inputMin= RECEIVER_INPUT_MAX;
 }

 //Interrupt Service Routine (ISR) for aileron receiver input
@@ -536,7 +476,7 @@
     aileronInStart = micros();
   } else {
     aileronInValue = (uint16_t) (micros() - aileronInStart);
-    servoInputFlags |= FLAG_AILERON;
+    receiverInputFlags |= FLAG_AILERON;
   }
 }

@@ -547,7 +487,7 @@
     cutoverInStart = micros();
   } else {
     cutoverInValue = (uint16_t) (micros() - cutoverInStart);
-    servoInputFlags |= FLAG_CUTOVER;
+    receiverInputFlags |= FLAG_CUTOVER;
   }
 }

@@ -558,7 +498,7 @@
     elevatorInStart = micros();
   } else {
     elevatorInValue = (uint16_t) (micros() - elevatorInStart);
-    servoInputFlags |= FLAG_ELEVATOR;
+    receiverInputFlags |= FLAG_ELEVATOR;
   }
 }

@@ -569,7 +509,7 @@
     rudderInStart = micros();
   } else {
     rudderInValue = (uint16_t) (micros() - rudderInStart);
-    servoInputFlags |= FLAG_RUDDER;
+    receiverInputFlags |= FLAG_RUDDER;
   }
 }

@@ -580,7 +520,7 @@
     throttleInStart = micros();
   } else {
     throttleInValue = (uint16_t) (micros() - throttleInStart);
-    servoInputFlags |= FLAG_THROTTLE;
+    receiverInputFlags |= FLAG_THROTTLE;
   }
 }

@@ -590,46 +530,25 @@
   return false;
 }

-//Processes receiver input and writes the converted value out to the servo
-void processServoInput(Servo servo, int receiverInput, const char servoType[], const char servoError[]) {
-  if (servo.attached()) {
-    //The servoInValue (in microseconds) is mapped to the min and max of the Servo.write() function
-    byte convertedServoValue = map(receiverInput, getReceiverInputMin(servoType), getReceiverInputMax(servoType), getServoMin(servoType), getServoMax(servoType));
-    servo.write(convertedServoValue);
-    sendJson(servoType, convertedServoValue);
-  } else {
-    sendJson("error", servoError);
-  }
-}
-
-//Takes a servoType and returns the corresponding calibrated receiver input min value
-int getReceiverInputMin(const char servoType[]) {
-  if (strcmp(servoType, "aileron") == 0) return aileronInMin;
-  if (strcmp(servoType, "elevator") == 0) return elevatorInMin;
-  if (strcmp(servoType, "rudder") == 0) return rudderInMin;
-  if (strcmp(servoType, "throttle") == 0) return throttleInMin;
-}
-
-//Takes a servoType and returns the corresponding calibrated receiver input max value
-int getReceiverInputMax(const char servoType[]) {
-  if (strcmp(servoType, "aileron") == 0) return aileronInMax;
-  if (strcmp(servoType, "elevator") == 0) return elevatorInMax;
-  if (strcmp(servoType, "rudder") == 0) return rudderInMax;
-  if (strcmp(servoType, "throttle") == 0) return throttleInMax;
-}
-
-//Takes a servoType and returns the corresponding servo min value
-byte getServoMin(const char servoType[]) {
-  if (strcmp(servoType, "aileron") == 0) return aileronMin;
-  if (strcmp(servoType, "elevator") == 0) return elevatorMin;
-  if (strcmp(servoType, "rudder") == 0) return rudderMin;
-  if (strcmp(servoType, "throttle") == 0) return throttleMin;
-}
-
-//Takes a servoType and returns the corresponding servo max value
-byte getServoMax(const char servoType[]) {
-  if (strcmp(servoType, "aileron") == 0) return aileronMax;
-  if (strcmp(servoType, "elevator") == 0) return elevatorMax;
-  if (strcmp(servoType, "rudder") == 0) return rudderMax;
-  if (strcmp(servoType, "throttle") == 0) return throttleMax;
-}
+//Processes receiver input for a given servo and writes the converted output to the servo
+void processServoInput(ServoData& servoData, uint16_t servoInputValue, const char servoType[], const char servoError[], const char servoInputError[]) {
+  //Only use receiver values within the set range for receiver input
+  if (isValidReceiverInput(servoInputValue)) {
+    if (calibrationMode) {
+      if (servoInputValue > servoData.inputMax) servoData.inputMax = servoInputValue;
+      if (servoInputValue < servoData.inputMin) servoData.inputMin = servoInputValue;
+    //Only write to servo if the receiver input for this servo has permission to do so
+    } else if (receiverControl || (sharedControl && servoData.receiverInputOnly)) {
+      if (servoData.servo.attached()) {
+        //The receiverInput (in microseconds) is mapped to the min and max for the Servo.write function (degrees)
+        byte convertedServoValue = map(servoInputValue, servoData.inputMin, servoData.inputMax, servoData.outputMin, servoData.outputMax);
+        servoData.servo.write(convertedServoValue);
+        sendJsonServoOutput(servoType, convertedServoValue);
+      } else {
+        sendJsonString("error", servoError);
+      }
+    }
+  } else {
+    sendJsonString("error", servoInputError);
+  }
+}


getting id

getting id


Print less decimal points for higher voltages. Keeps text on one line

--- VoltMeter.ino
+++ VoltMeter.ino
@@ -53,7 +53,10 @@
   // Print the current voltage followed by the "V" symbol ("/" in this font)
   uView.clear(PAGE);
   uView.setCursor(0,0);
-  uView.print(volts,2);
+  if (volts < 10)
+    uView.print(volts,3);
+  else if (volts < 100)
+    uView.print(volts,2);
   uView.print("/");
 }


use fdsString for passing the string

use fdsString for passing the string

--- chessclock/chessclock.ino
+++ chessclock/chessclock.ino
@@ -4,7 +4,7 @@
 Toont karakters op line 0.
 */
 #include <SPI.h>                                       // Om snelheid te winnen maken we gebruik van SPI.
-#include <fds132text.h>                                                      // Daarom halen we de SPI library erbij.
+#include "fds132text.h"                                                      // Daarom halen we de SPI library erbij.
                                                        // Pinnen voor het aansturen van het FDS132 bord.
 const int strobePin = 10;                              // pin voor strobe signaal, ook wel latch genaamd.
 const int clockPin = 13;                               // pin met clock signaal.
@@ -17,6 +17,8 @@

 fdsChar letterA;
+fdsChar fdsColon;
+fdsString maintext;

 void initialiseLetters(){
     letterA.character_map[0]=B00011000;
@@ -25,8 +27,37 @@
     letterA.character_map[3]=B00111100;
     letterA.character_map[4]=B00100100;
     letterA.character_map[5]=B01000010;
-    letterA.character_map[6]=B01000010;
+    letterA.character_map[6]=B01000010;
+    letterA.width=8;
+
+    fdsColon.character_map[0]=B00000000;
+    fdsColon.character_map[1]=B00000000;
+    fdsColon.character_map[2]=B10000000;
+    fdsColon.character_map[3]=B00000000;
+    fdsColon.character_map[4]=B10000000;
+    fdsColon.character_map[5]=B00000000;
+    fdsColon.character_map[6]=B00000000;
+    fdsColon.width=2;
+
+    maintext.value = &letterA;
+    maintext.rest = 0;
+
+    addToString(&maintext, &fdsColon);
+    addToString(&maintext, &fdsColon);
+    addToString(&maintext, &letterA);
+    addToString(&maintext, &fdsColon);
+}

+void addToString(fdsString *string, fdsChar *addition){
+    //find end of string
+    while(string -> rest != 0) {
+        string = string -> rest;
+    }
+    //add the new character
+    string -> rest = (fdsString *) malloc(sizeof(struct fdsString));
+    string = string -> rest;
+    string -> value = addition;
+    string -> rest = 0;
 }

 void setup() {
@@ -51,7 +82,7 @@
         digitalWrite (resredPin, LOW);                     // en we doven de display om ghosting te voorkomen.
         setRow(row);                                       // we sturen alle zeven rijen aan.
         zeroDisplay();                                     // alle uitgangen van de shiftregisters op nul.
-        setDisplay(row);                                   // haal de te tonen data op.
+        setDisplay(row, maintext);                                   // haal de te tonen data op.
         digitalWrite(strobePin, HIGH);                     // update de shiftregisters.
         digitalWrite (resredPin, HIGH);                    // en zet display terug aan.
         delayMicroseconds(2500);                           // pauseren want de update gaat te vlug.
@@ -71,9 +102,30 @@
        SPI.transfer(0);                                     // door 34 keer een byte met waarde nul te sturen.
    }
 }
-void setDisplay(int row)                               // haal de tekstdata uit de eerder gedefinieerde map met karakters.
-{
-    SPI.transfer(letterA.character_map[row]);
-
+void setDisplay(int row, fdsString outputText)                               // haal de tekstdata uit de eerder gedefinieerde map met karakters.
+{
+    int i = 0;
+    int currentbit = 0;
+    byte outputbytes[34];
+    for(i=0; i<34; i++)
+    {
+       outputbytes[i] = 0;
+    }
+
+    // unpack the fdsString
+    fdsString *current = &outputText;
+    while (i<2000) {
+        i++;
+        if (current == 0) {break;}
+        outputbytes[currentbit/8] = (*(*current).value).character_map[row];
+        currentbit += 8;
+        current = current -> rest;
+    }
+
+    for(i=34; i>=0; i--){
+        SPI.transfer(outputbytes[i]);
+    };
+
 }

+


Fixed intendation, removed "INIT" message

--- arduino/arduino.ino
+++ arduino/arduino.ino
@@ -60,22 +60,21 @@
   //If the initialise flag is exactly 42, this application was used before and is initialised
   //If not, we must set some settings
   if(EEPROM.read(EEPROM_INITIALISED_FLAG) != 42) {
-    Serial.println("INIT");
-     //Set the current profile id to zero
-     uint64_t v = 0;
-     EEPROMwrite64(EEPROM_CURRENT_PROFILE_ID, &v);
+    //Set the current profile id to zero
+    uint64_t v = 0;
+    EEPROMwrite64(EEPROM_CURRENT_PROFILE_ID, &v);

-     //Set the led Count to 60
-     EEPROM.writeInt(EEPROM_LED_COUNT, 60);
+    //Set the led Count to 60
+    EEPROM.writeInt(EEPROM_LED_COUNT, 60);

-     //Set the current system brightness to max
-     EEPROM.write(EEPROM_CURRENT_BRIGHTNESS, 255);
+    //Set the current system brightness to max
+    EEPROM.write(EEPROM_CURRENT_BRIGHTNESS, 255);

-     //Set the neopixels' pin to 6
-     EEPROM.write(EEPROM_NEOPIXLES_PIN, 6);
+    //Set the neopixels' pin to 6
+    EEPROM.write(EEPROM_NEOPIXLES_PIN, 6);

-     //Set the flag so we wont initialise again
-     EEPROM.write(EEPROM_INITIALISED_FLAG, 42);
+    //Set the flag so we wont initialise again
+    EEPROM.write(EEPROM_INITIALISED_FLAG, 42);

   }


Finish storeVolts()

Finish storeVolts()

--- VoltMeter.ino
+++ VoltMeter.ino
@@ -55,10 +55,20 @@

 void storeVolts(float volts) {
-  // Stores the latest voltage measurement
-
-
-  // then store the latest reading in the seconds array
+  // Store the latest reading in the seconds array
   timearr[secs] = volts;
+
+  // Calculate the minute average and store it in the minute array
+  if (++secs == 60) {
+    volts = 0;
+    for (int i=0; i<60; i++) {
+      volts += timearr[i];
+    }
+    timearr[60 + mins] = volts / 60.0;
+    if (++mins == 60) {
+      mins = 0;
+    }
+    secs = 0;
+  }
 }
-
+


send 200 before restarting

send 200 before restarting

--- WifiWeatherGuy.ino
+++ WifiWeatherGuy.ino
@@ -131,6 +131,7 @@
 			File f = SPIFFS.open(config_file, "w");
 			f.print(body);
 			f.close();
+			server.send(200);
 			ESP.restart();
 		} else
 			server.send(400, "text/plain", "No body!");


refactoring

refactoring

--- WifiWeatherGuy.ino
+++ WifiWeatherGuy.ino
@@ -414,6 +414,52 @@
   return false;
 }

+static unsigned cbytes = JSON_OBJECT_SIZE(0) + 9 * JSON_OBJECT_SIZE(2) + 2 * JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(4) +
+                          JSON_OBJECT_SIZE(8) + JSON_OBJECT_SIZE(9) + JSON_OBJECT_SIZE(12) + JSON_OBJECT_SIZE(56) + 2530;
+
+const unsigned snooze_delay = 300000;
+
+static unsigned fbytes = JSON_ARRAY_SIZE(4) + JSON_ARRAY_SIZE(8) + 2*JSON_OBJECT_SIZE(1) + 35*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) +
+                            8*JSON_OBJECT_SIZE(4) + 8*JSON_OBJECT_SIZE(7) + 4*JSON_OBJECT_SIZE(17) + 4*JSON_OBJECT_SIZE(20) + 6150;
+
+void fetch(unsigned now, const __FlashStringHelper *path, unsigned &bytes, unsigned &last_fetch, unsigned interval, void (*f)(JsonObject &)) {
+  if (now - last_fetch > interval) {
+    unsigned heap = ESP.getFreeHeap();
+    if (heap > bytes) {
+      DBG(print(F("Updating ")));
+      DBG(print(path));
+      DBG(print(' '));
+      DBG(print(bytes));
+      DBG(print(' '));
+      DBG(println(heap));
+      WiFiClient client;
+      if (connect_and_get(client, path)) {
+        DynamicJsonBuffer buffer(bytes);
+        JsonObject &root = buffer.parseObject(client);
+        if (root.success()) {
+          f(root);
+          unsigned n = buffer.size();
+          DBG(print(F("Done ")));
+          DBG(println(n));
+          if (n > bytes)
+            bytes = n;
+          last_fetch = now;
+        } else {
+          ERR(println(F("Failed to parse!")));
+          last_fetch += snooze_delay;
+        }
+      } else {
+        ERR(println(F("Failed to fetch!")));
+        last_fetch += snooze_delay;
+      }
+      client.stop();
+    } else {
+      DBG(println(F("Insufficient memory to update!")));
+      last_fetch += snooze_delay;
+    }
+  }
+}
+
 void loop() {
   mdns.update();

@@ -445,77 +491,12 @@
     update_display(screen);
   }

-  const unsigned snooze_delay = 300000;
-  if (now - last_fetch_conditions > cfg.conditions_interval) {
-    unsigned heap = ESP.getFreeHeap();
-    static unsigned cbytes = JSON_OBJECT_SIZE(0) + 9 * JSON_OBJECT_SIZE(2) + 2 * JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(4) +
-                              JSON_OBJECT_SIZE(8) + JSON_OBJECT_SIZE(9) + JSON_OBJECT_SIZE(12) + JSON_OBJECT_SIZE(56) + 2530;
-    if (heap > cbytes) {
-      DBG(print(F("Updating conditions ")));
-      DBG(print(cbytes));
-      DBG(print(' '));
-      DBG(println(heap));
-      WiFiClient client;
-      if (connect_and_get(client, F("astronomy/conditions"))) {
-        DynamicJsonBuffer buffer(cbytes);
-        JsonObject &root = buffer.parseObject(client);
-        if (root.success()) {
-          if (update_conditions(root, conditions))
-            update_display(screen);
-          unsigned n = buffer.size();
-          DBG(print(F("Done ")));
-          DBG(println(n));
-          if (n > cbytes)
-            cbytes = n;
-          last_fetch_conditions = now;
-        } else {
-          ERR(println(F("Failed to parse conditions!")));
-          last_fetch_conditions += snooze_delay;
-        }
-      } else {
-        ERR(println(F("Failed to fetch conditions!")));
-        last_fetch_conditions += snooze_delay;
-      }
-      client.stop();
-    } else {
-      DBG(println(F("Insufficient memory to update conditions!")));
-      last_fetch_conditions += snooze_delay;
-    }
-  }
-
-  if (now - last_fetch_forecasts > cfg.forecasts_interval) {
-    unsigned heap = ESP.getFreeHeap();
-    static unsigned fbytes = JSON_ARRAY_SIZE(4) + JSON_ARRAY_SIZE(8) + 2*JSON_OBJECT_SIZE(1) + 35*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) +
-                              8*JSON_OBJECT_SIZE(4) + 8*JSON_OBJECT_SIZE(7) + 4*JSON_OBJECT_SIZE(17) + 4*JSON_OBJECT_SIZE(20) + 6150;
-    if (heap > fbytes) {
-      DBG(print(F("Updating forecasts ")));
-      DBG(print(fbytes));
-      DBG(print(' '));
-      DBG(println(heap));
-      WiFiClient client;
-      if (connect_and_get(client, F("forecast"))) {
-        DynamicJsonBuffer buffer(fbytes);
-        JsonObject &root = buffer.parseObject(client);
-        if (root.success()) {
-          update_forecasts(root);
-          unsigned n = buffer.size();
-          DBG(print(F("Done ")));
-          DBG(println(n));
-          if (n > fbytes)
-            fbytes = n;
-          last_fetch_forecasts = now;
-        } else {
-          ERR(println(F("Failed to parse forecasts!")));
-          last_fetch_forecasts += snooze_delay;
-        }
-      } else {
-        ERR(println(F("Failed to fetch forecast!")));
-        last_fetch_forecasts += snooze_delay;
-      }
-      client.stop();
-    } else {
-      DBG(println(F("Insufficient memory to update forecasts!")));
-      last_fetch_forecasts += snooze_delay;
-    }
-  }
-}
+  fetch(now, F("astronomy/conditions"), cbytes, last_fetch_conditions, cfg.conditions_interval, [] (JsonObject &root) {
+    if (update_conditions(root, conditions))
+      update_display(screen);
+  });
+
+  fetch(now, F("forecast"), fbytes, last_fetch_forecasts, cfg.forecasts_interval, [] (JsonObject &root) {
+    update_forecasts(root);
+  });
+}


Update LIMIT.ino

Update LIMIT.ino

--- examples/Unit/LIMIT/LIMIT.ino
+++ examples/Unit/LIMIT/LIMIT.ino
@@ -3,8 +3,8 @@
 * Copyright (c) 2022 by M5Stack
 *                  Equipped with M5Core sample source code
 *                          配套  M5Core 示例源代码
-* Visit the website for more information:
-* 获取更多资料请访问:
+* Visit the website for more information: https://docs.m5stack.com/zh_CN/products
+* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/products
 *
 * describe: Limit.
 * date: 2022/6/1


Made the read from the ultrasonic sensor more asynchronous and less blocking

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

 //------------------------------------------------------------------------------
 const uint8_t VERSION_MAJOR = 0;
-const uint8_t VERSION_MINOR = 32;
+const uint8_t VERSION_MINOR = 36;
 const uint16_t FIRMWARE_ID = 0xACED;

 const uint16_t MAX_MSG_SIZE = 32;
@@ -152,6 +152,8 @@
 volatile uint8_t gCurMotorWaveTick = 0;

 int gLastUltrasonicReading = -1;
+unsigned long gUltrasonicPulseStartTimeUS = 0;
+bool gbTakingUltrasonicSensorReading = false;

 // This byte determines which pins are used as digital inputs
 // A bit set to 1 indicates that the pin is used as a digital input
@@ -265,6 +267,53 @@
     gPanServo.writeMicroseconds( gPanServoLimits.convertAngleToPWM( gPanServoAngle ) );
     gTiltServo.writeMicroseconds( gTiltServoLimits.convertAngleToPWM( gTiltServoAngle ) );

+    // Periodically kick off an ultrasonic sensor read
+    if ( curTime - gLastUltrasonicReadTimeMS >= SENSOR_READ_INTERVAL_MS
+       && !gbTakingUltrasonicSensorReading )
+    {
+        // Start to measure the range
+        pinMode( ULTRASONIC_PIN, OUTPUT );
+        digitalWrite( ULTRASONIC_PIN, LOW );
+        delayMicroseconds( 2 );
+        digitalWrite( ULTRASONIC_PIN, HIGH );
+        delayMicroseconds( 5 );
+        digitalWrite( ULTRASONIC_PIN, LOW );
+
+        unsigned long startWaitTimeUS = micros();
+
+        // Wait for the response pulse to start
+        pinMode( ULTRASONIC_PIN, INPUT );
+        bool bPulseStarted = false;
+        while ( !bPulseStarted
+           && micros() - startWaitTimeUS < 500 )
+        {
+            bPulseStarted = digitalRead( ULTRASONIC_PIN ) == HIGH;
+        }
+
+        if ( bPulseStarted )
+        {
+            gUltrasonicPulseStartTimeUS = micros();
+            gbTakingUltrasonicSensorReading = true;
+        }
+        else
+        {
+            // Looks like no sensor is attached. Wait a bit before trying again
+            gLastUltrasonicReadTimeMS = curTime;
+        }
+    }
+
+    // Check the status of an ongoing ultrasonic read
+    if ( gbTakingUltrasonicSensorReading
+        && digitalRead( ULTRASONIC_PIN ) == LOW )
+    {
+        // Pulse has ended
+        unsigned long durationUS = micros() - gUltrasonicPulseStartTimeUS;
+
+        gLastUltrasonicReading = durationUS/ULTRASONIC_US_PER_CM;;
+        gLastUltrasonicReadTimeMS = curTime;
+        gbTakingUltrasonicSensorReading = false;
+    }
+
     // Periodically read from the sensors and send the readings back
     if ( curTime - gLastSensorReadTimeMS >= SENSOR_READ_INTERVAL_MS )
     {
@@ -282,11 +331,7 @@
         }
         else
         {
-            if ( curTime - gLastUltrasonicReadTimeMS >= SENSOR_READ_INTERVAL_MS )
-            {
-                gLastUltrasonicReading = measureDistanceUltrasonic( ULTRASONIC_PIN );
-                gLastUltrasonicReadTimeMS = curTime;
-            }
+            // Ultrasonic reads are being carried out on this pin
         }

         if ( gSensorConfiguration & (1 << 1) )
@@ -315,23 +360,6 @@

         gLastSensorReadTimeMS = curTime;
     }
-}
-
-//------------------------------------------------------------------------------
-int measureDistanceUltrasonic( int pin )
-{
-    // Send control pulse
-    pinMode( pin, OUTPUT );
-    digitalWrite( pin, LOW );
-    delayMicroseconds( 2 );
-    digitalWrite( pin, HIGH );
-    delayMicroseconds( 5 );
-    digitalWrite( pin, LOW );
-    pinMode( pin, INPUT );
-
-    long durationUS = pulseIn( ULTRASONIC_PIN, HIGH, MAX_ULTRASONIC_TIMEOUT_US );
-
-    return durationUS/ULTRASONIC_US_PER_CM;
 }

 //------------------------------------------------------------------------------


alter the rfduino code to make it more predictable when serial data will be transmitted

--- src/rfduino/serial_reporter/serial_reporter.ino
+++ src/rfduino/serial_reporter/serial_reporter.ino
@@ -1,74 +1,7 @@
 #include <RFduinoBLE.h>
-/*
-  CircularBuffer.h - circular buffer library for Arduino.
-
-  Copyright (c) 2009 Hiroki Yagita.
-
-  Permission is hereby granted, free of charge, to any person obtaining
-  a copy of this software and associated documentation files (the
-  'Software'), to deal in the Software without restriction, including
-  without limitation the rights to use, copy, modify, merge, publish,
-  distribute, sublicense, and/or sell copies of the Software, and to
-  permit persons to whom the Software is furnished to do so, subject to
-  the following conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-  CLAIM, DAMAGES OR OTHER LIABILITY, 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.
- */
-#ifndef CIRCULARBUFFER_h
-#define CIRCULARBUFFER_h
-#include <inttypes.h>
-
-template <typename T, uint16_t Size>
-class CircularBuffer {
-public:
-  enum {
-    Empty = 0,
-    Half = Size / 2,
-    Full = Size,
-  };
-
-  CircularBuffer() :
-    wp_(buf_), rp_(buf_), tail_(buf_+Size),  remain_(0) {}
-  ~CircularBuffer() {}
-  void push(T value) {
-    *wp_++ = value;
-    remain_++;
-    if (wp_ == tail_) wp_ = buf_;
-  }
-  T pop() {
-    T result = *rp_++;
-    remain_--;
-    if (rp_ == tail_) rp_ = buf_;
-    return result;
-  }
-  int remain() const {
-    return remain_;
-  }
-
-private:
-  T buf_[Size];
-  T *wp_;
-  T *rp_;
-  T *tail_;
-  uint16_t remain_;
-};
-
-#endif

-#define MAX_MILLIS_TO_WAIT 1000
-
-CircularBuffer<char, 1000> buffer;
+char data[100];
 int connected = false;
-int loops = 0;

 void setup() {
   /* RX is Pin 0, TX is Pin 1 */
@@ -81,25 +14,29 @@
 }

 void loop() {
-  unsigned long starttime = millis();
+
+  /* Wait while the Radio is active */
+  while (RFduinoBLE.radioActive)
+  ;

-  while((Serial.available() > 0) && ((millis() - starttime) < MAX_MILLIS_TO_WAIT) ) {
-    buffer.push(Serial.read());
+  /* Quick! Give me the data! */
+  Serial.write(1);
+  char bytesRead = 0;
+
+  /* Read in 100 bytes of data */
+  while(bytesRead < 100) {
+    if (Serial.available()) {
+      data[bytesRead++] = Serial.read();
+    }
+
+    /* best not to thrash */
+    delay(5);
   }

   if (connected) {
-    int charactersToSend = min(20, buffer.remain());
-
-    char buf[charactersToSend];
-    for (int i = 0; i < charactersToSend; i++) {
-      buf[i] = buffer.pop();
-    }
-
-    if (charactersToSend > 0) {
-      // send is queued (the ble stack delays send to the start of the next tx window)
-      while (! RFduinoBLE.send(buf, charactersToSend))
-        ;  // all tx buffers in use (can't send - try again later)
-    }
+    /* send is queued (the ble stack delays send to the start of the next tx window) */
+    while (! RFduinoBLE.send(data, charactersToSend))
+      ;  /* all tx buffers in use (can't send - try again later) */
   }
 }


correcting auth header

correcting auth header

--- nest-rest.ino
+++ nest-rest.ino
@@ -47,7 +47,7 @@
                        };

-      client.setHeader("Auth:xk2e2k245h5lsa");
+      client.setHeader("Authorization: Token xk2e2k245h5lsa");
       client.post("/data", message, &response);

       //if (!manager.sendtoWait(buf, 2, from)) {


Retirada de debug.

Retirada de debug.

--- quad/quad.ino
+++ quad/quad.ino
@@ -372,7 +372,6 @@

   /* Inicializa a MPU e seu respectivo DMP */
   mpu.initialize();
-  D(Serial.println("A"));
   dmpStatus = mpu.dmpInitialize();

   /* Define os offsets do MPU. Utilizado o programa MPU6050_calibration para chegar a esses números. */
@@ -385,7 +384,6 @@

   /* Só prossegue somente se o houve a inicialização correta do DMP */
   if (dmpStatus == 0) {
-    D(Serial.println("B"));
     /* Liga o DMP. Agora o MPU está pronto! */
     mpu.setDMPEnabled(true);

@@ -393,13 +391,11 @@
     attachInterrupt(0, dmpDataReady, RISING);
     mpuIntStatus = mpu.getIntStatus();

-D(Serial.println("C"));
     /* Inicializa a flag de controle do DMP para o loop() saber que está tudo certo */
     dmpReady = true;

     /* Obtem o tamanho do pacote do DMP */
     packetSize = mpu.dmpGetFIFOPacketSize();
-    D(Serial.println("D"));
   }
   else {
     // ERRO!
@@ -450,7 +446,6 @@
   if (rcOnOff > 10) {
     setPIDParameters('P');
   } else if (pidChanged) {
-    D(Serial.println("PIDs gravados na EEPROM"));
     writePIDParameters();
     pidChanged = false;
   }


Fixed variable typo that resulted in longitude not being set.

--- arduino-code/Stellarduino/Stellarduino.ino
+++ arduino-code/Stellarduino/Stellarduino.ino
@@ -149,7 +149,7 @@
       // Determine date and time.
       lcdDatePrompt(lcd, initialDate);
       lcdCoordPrompt(lcd, "Enter latitude", &latitude);
-      lcdCoordPrompt(lcd, "Enter longitude", &latitude);
+      lcdCoordPrompt(lcd, "Enter longitude", &longitude);

       // Once data is collected, star selection can be performed.
       autoSelectAlignmentStars();


add support for standby mode

add support for standby mode

--- onboard_controller/onboard_controller.ino
+++ onboard_controller/onboard_controller.ino
@@ -6,8 +6,11 @@
 /*--debug macros--*/
 //#define readDebug //print Serial1 reads to console
 //#define writeDebug //print Serial1 writes to console
-#define fakeGPS //fake the presence of a gps
+//#define fakeGPS //fake the presence of a gps
 //#define rawGPSDebug //print raw gps data to console
+
+#define LAUNCH_TX_PD 250;
+#define STANDBY_TX_PD 3000;

 #define PIN_TEST 13
 #define PIN_PAYLOAD_ABORT 12
@@ -22,15 +25,10 @@
 Payload payload_start;
 Payload* ptr_payload = &payload;

-enum States {
-  STOPPED, PRE_LAUNCH, POST_LAUNCH, ERROR
-};
-
-States state = STOPPED;
+int tx_pd = STANDBY_TX_PD; //time between message transmission, in ms

 // XBee's DOUT (TX) is connected to pin 0 (Arduino's Hardware RX)
 // XBee's DIN (RX) is connected to pin 1 (Arduino's Hardware TX)
-
 SoftwareSerial gpsSerial(8, 7);
 Adafruit_GPS GPS(&gpsSerial);

@@ -103,7 +101,8 @@
         payload.flags.payload_abort = 0;
         break;
       case DIR_BEGIN_LAUNCH:
-
+        payload.flags.main_launch = 1;
+        tx_pd = LAUNCH_TX_PD;
         break;
       default:
         digitalWrite(PIN_TEST,LOW);
@@ -118,7 +117,7 @@

   // if millis() or timer wraps around, reset
   if (timer > millis())  timer = millis();
-  if (millis() - timer > 250) {
+  if (millis() - timer > tx_pd) {
     timer = millis(); // reset the timer

     #ifdef fakeGPS //fake gps data


Updated IDLE example with Teensy results

--- examples/Scheduler_example06_IDLE/Scheduler_example06_IDLE.ino
+++ examples/Scheduler_example06_IDLE/Scheduler_example06_IDLE.ino
@@ -11,18 +11,29 @@
 The result are:

 1): With #define _TASK_SLEEP_ON_IDLE_RUN enabled
-Start
-c1=10771 - v2.5.0 (v1.9.0: same)
-c2=1001
+On Arduino Uno:
+  Start
+  c1=10771 - v2.5.0 (v1.9.0: same)
+  c2=1001

+On Teensy 3.5 (120MHz ARM):
+  Start
+  c1=21065
+  c2=1001

 and

 2): With #define _TASK_SLEEP_ON_IDLE_RUN disabled (commented out)
-Start
-c1=635735 - v2.5.0  (v1.9.0: 551947)
-c2=1001
+Arduino Uno:
+  Start
+  c1=635735 - v2.5.0  (v1.9.0: 551947)
+  c2=1001

+On Teensy 3.5 (120MHz ARM):
+  Start
+  c1=2690322
+  c2=1001
+
 C1 is scenario 2) is much higher than in scenario 1) because processor is put to sleep for 1), but not for 2)

  */


Change formatting for enums. Remove lcd_print_P macro.

--- dremelfuge.ino
+++ dremelfuge.ino
@@ -52,9 +52,6 @@
   // Functors customizing methods on lcdPrinter
   NormalPrint raw;               // Default constructors
   FSecsPrint fsecs;
-
-  // Macro to prettify long line for reading and then printing to LCD from Flash
-  #define lcd_print_P(string)  lcd.print( (PGM_P) pgm_read_word( &(string) ))

   /* `pgm_read_word` implementation:
     Implements a Load Program Memory instruction on an 8-bit RAM
@@ -135,13 +132,12 @@
     */

   // Enumeration of row indices as UI elements
-  enum line : char {
-
+  enum line : char
+  {
     Title = 0,
     Time,
     Speed,
     Instructions
-
   };

 } // namespace
@@ -247,13 +243,12 @@
     */

   // Define a custom type, whose enumerated values are the size of `char`s
-  enum class Mode : char {
-
+  enum class Mode : char
+  {
     SETTING_TIME,
     SETTING_SPEED,
     SPINNING
-
-  }; // enum class Mode
+  };

   static Mode currentMode = Mode::SETTING_TIME;         // initialization over assignment; set SETTING_TIME as the first mode!


wip (#148)

wip (#148)

--- Photon/Controllers/FrontPanel/src/FrontPanel.ino
+++ Photon/Controllers/FrontPanel/src/FrontPanel.ino
@@ -40,7 +40,7 @@
 #include <PatriotLight.h>
 #include <PatriotNCD8Light.h>

-#define CONTROLLER_NAME "FrontPanel2"
+#define CONTROLLER_NAME "FrontPanel"
 #define MQTT_BROKER "192.168.50.33"
 #define ADDRESS 1      // PWM board lowest switch on


SpaceX Edits.  Succint fade, remove broken features

--- final_revised/final_revised.ino
+++ final_revised/final_revised.ino
@@ -1,6 +1,6 @@
 // Jean-Luc Chamaa - PreFab LED Strip Control via Ardunio
 #include <LiquidCrystal.h>
-#include <ffft.h>
+//#include <ffft.h>
 #include <stdio.h>
 #define ADC_CHANNEL 0

@@ -9,11 +9,13 @@
 // global Variables for testThree & consolidate
 int globaLast=0;
 int lastDir=0;
+/*
 // global variables for the fft implementation
 int16_t       capture[FFT_N];    // Audio capture buffer
 complex_t     bfly_buff[FFT_N];  // FFT "butterfly" buffer
 uint16_t      spectrum[FFT_N/2]; // Spectrum output buffer
 volatile byte samplePos = 0;     // Buffer position counter
+*/
 int party =0;

@@ -58,7 +60,6 @@
 int currentMenu	=	0; // Which menu is the user currently in?

 char* menu0[]	={	" Custom Color    ",
-					" Party Mode      ",
 					" Fade Mode       ",
 					" Strobe Mode     ",
 					" Settings        "};
@@ -115,7 +116,7 @@
         delay(300);
     }
 }
-
+/*
 void sampleAndTransform(){
     while(ADCSRA & _BV(ADIE)); // CALLS ISR UNTIL ADIE IS 0
     fft_input(capture, bfly_buff);   // Samples -> complex #s
@@ -124,12 +125,13 @@
     fft_output(bfly_buff, spectrum); // Complex -> spectrum
     //ADCSRA |= _BV(ADIE);             // SETS ADIE TO 1 AND RESUMES ISR
 }
-
+*/
 void startTheParty(){

 }

 int partyMode() {
+  /*
     switch (ADMUX)
     {
         case 0x00:
@@ -146,6 +148,7 @@
         	return(0);
         	break;
     }
+    */
 }

 int testThree() {
@@ -201,42 +204,42 @@

 void fullfade(){   // fade from red to green
 	while(1){
-
+    int wait=0;
 		int r=255;int g=0;int b=0;
-		for(int del=0;del<256;del++)
+		for(int del=0;del<256;)
 		{

-			int wait= analogRead(A3)/20;
+			int wait= 1+analogRead(A3)/50;
 			apply(r-del,g+del,b);
-			delay(wait);
 			if(consolidate()==LEFT) return;
 			lcd.setCursor(14,0);
-			lcd.print(wait);
-			lcd.print("  ");
+      lcd.print(wait);
+      lcd.print(" ");
+      del=del+wait;
 		}
 		// fade from green to blue
 		r=0;g=255;b=0;
-		for(int del=0;del<256;del++)
+		for(int del=0;del<256;)
 		{
-			int wait= analogRead(A3)/20;
+			int wait= 1+analogRead(A3)/50;
 			apply(r,g-del,b+del);
-			delay(wait);
+			if(consolidate()==LEFT) return;
+      lcd.setCursor(14,0);
+      lcd.print(wait);
+      lcd.print(" ");
+      del=del+wait;
+		}
+		// fade from blue to red
+		r=0;g=0;b=255;
+		for(int del=0;del<256;)
+		{
+			int wait= 1+analogRead(A3)/50;
+			apply(r+del,g,b-del);
 			if(consolidate()==LEFT) return;
 			lcd.setCursor(14,0);
-			lcd.print(wait);
-			lcd.print("  ");
-		}
-		// fade from blue to red
-		r=0;g=0;b=255;
-		for(int del=0;del<256;del++)
-		{
-			int wait= analogRead(A3)/20;
-			apply(r+del,g,b-del);
-			delay(wait);
-			if(consolidate()==LEFT) return;
-			lcd.setCursor(14,0);
-			lcd.print(wait);
-			lcd.print("  ");
+      lcd.print(wait);
+      lcd.print(" ");
+      del=del+wait;
 		}
 	}
 }
@@ -278,9 +281,15 @@
 			long detectionSpan = 0;
 			pinMode(A1, INPUT);
 			pinMode(relay, OUTPUT);
+      lcd.setCursor(0,0);
+      lcd.print("    CLAPPER     ");
+      lcd.setCursor(0,1);
+      lcd.print("BLUE = 0 -> EXIT");
 			while(analogRead(A5)!=0){ //exit clap mode by turning red to 0
+
 				int sensorState = digitalRead(A1);
 				if (sensorState == 1){
+          Serial.println("detected");
 					if (claps == 0){
 						detectionSpanInitial = detectionSpan = millis();
 						claps++;
@@ -307,7 +316,25 @@
 					claps = 0;
 				}
 			}
+      lcd.setCursor(0,0);
+      lcd.print(" RED GREEN BLUE ");
+      lcd.setCursor(0,1);
+      lcd.print("                ");
 			clapper=false;
+      rpot=analogRead(A3);
+      lcd.setCursor(1,1);
+      lcd.print(rpot*10/102);
+      lcd.print(" ");
+
+      gpot=analogRead(A4);
+      lcd.setCursor(6,1);
+      lcd.print(gpot*10/102);
+      lcd.print(" ");
+      bpot=analogRead(A5);
+      lcd.setCursor(12,1);
+      lcd.print(bpot*10/102);
+      lcd.print(" ");
+
 		}
 	}
 }
@@ -415,17 +442,16 @@
 		    				lcd.print("               ");
 		    				customCol();
 		    				break;
-		    			case 1:
-		    				startTheParty();
-			    		case 2:  // Fade
+
+			    		case 1:  // Fade
 		    				delay(500);
 		    				lcd.setCursor(0,0);
-		    				lcd.print("Speed (0-51):             ");
+		    				lcd.print("Speed (1-20):             ");
 		    				lcd.setCursor(0,1);
 		    				lcd.print("Turn Top Knob");
 		    				fullfade();
 		    				break;
-			    		case 3: // strobe
+			    		case 2: // strobe
 			    			delay(500);
 		    				lcd.setCursor(0,0);
 		    				lcd.print("BPM:             ");
@@ -433,7 +459,7 @@
 		    				lcd.print("Turn Top Knob");
 		    				strobeMode();
 		    				break;
-			    		case 4: // Settings option: push forward
+			    		case 3: // Settings option: push forward
 			    			currentMenu=1;
 			    			break;

@@ -466,7 +492,7 @@

-
+/*
 ISR(ADC_vect) { // Audio-sampling interrupt
     if(party==1){
     static const int16_t noiseThreshold = 4;
@@ -475,3 +501,4 @@
   if(++samplePos >= FFT_N) ADCSRA &= ~_BV(ADIE); // Buffer full, interrupt off
 }
 }
+*/


change in examples

change in examples

--- examples/semaphore/semaphore.ino
+++ examples/semaphore/semaphore.ino
@@ -15,31 +15,37 @@

 #include <Arduino.h>
 #include <SPI.h>
-#include <TimerOne.h>
 #include <MergCBUS.h>
 #include <Message.h>
 #include <EEPROM.h>

-#define GREEN_LED 5       //merg green led port
-#define YELLOW_LED 4      //merg yellow led port
-#define PUSH_BUTTON 3     //std merg push button
-#define PUSH_BUTTON1 9    //debug push button
+#define GREEN_LED      5    //merg green led port
+#define YELLOW_LED     4    //merg yellow led port
+#define PUSH_BUTTON    3    //std merg push button
+#define NUM_NODE_VARS  1    //the transition interval
+#define NUM_EVENTS     20   //supported events
+#define NUM_EVENT_VARS 0    //no need for supported event variables
+#define NUM_DEVICES    1    //one device number
+#define MODULE_ID      55   //module id
+#define MANUFACTURER_ID 165 //manufacturer id
+#define MIN_CODE       0    //min code version
+#define MAX_CODE       1    //max code version
+
+#define CANPORT        53   //attached mcp2551 pin
+
 //semaphore leds
-#define GREEN 10        //green led
-#define YELLOW 11        //green led
-#define RED 12        //green led
-#define TRANSITION_TIME  2000 //time in milli to keep the yellow light on
+#define GREEN 10              //green led pin
+#define YELLOW 11             //yellow led pin
+#define RED 12                //red led pin
+#define TRANSITION_TIME  50   //time in milli to keep the yellow light on
+#define NNVar1           40   //the yellow light will stay on for 2 seconds

-MergCBUS cbus=MergCBUS(5,20,1,0);
+MergCBUS cbus=MergCBUS(NUM_NODE_VARS,NUM_EVENTS,NUM_EVENT_VARS,NUM_DEVICES);
+
 byte lighton;//control the state
 byte nextlighton;//control the state
 unsigned long starttime;

-//timer function to read the can messages
-void readCanMessages(){
-  //read the can message and put then in a circular buffer
-  cbus.cbusRead();
-}

 void setup(){

@@ -49,40 +55,36 @@

   //Configuration data for the node
-  cbus.getNodeId()->setNodeName("MODTESTE",8);  //node name
-  cbus.getNodeId()->setModuleId(55);            //module number
-  cbus.getNodeId()->setManufacturerId(0xA5);    //merg code
-  cbus.getNodeId()->setMinCodeVersion(1);       //Version 1
-  cbus.getNodeId()->setMaxCodeVersion(0);
+  cbus.getNodeId()->setNodeName("SEMAPHOR",8);         //node name
+  cbus.getNodeId()->setModuleId(MODULE_ID);            //module number
+  cbus.getNodeId()->setManufacturerId(MANUFACTURER_ID);//merg code
+  cbus.getNodeId()->setMinCodeVersion(MIN_CODE);       //Version 1
+  cbus.getNodeId()->setMaxCodeVersion(MAX_CODE);
   cbus.getNodeId()->setProducerNode(false);
   cbus.getNodeId()->setConsumerNode(true);
-  cbus.setStdNN(999); //standard node number
+  cbus.setPushButton(PUSH_BUTTON);//set the push button ports

-  if (digitalRead(PUSH_BUTTON1)==LOW){
+  //used to manually reset the node. while turning on keep the button pressed
+  //this forces the node for slim mode with an empty memory for learned events and devices
+  if (digitalRead(PUSH_BUTTON)==LOW){
     Serial.println("Setup new memory");
     cbus.setUpNewMemory();
     cbus.saveNodeFlags();
+    //set the default value
+    cbus.setNodeVariable(1,NNVar1);
   }

   cbus.setLeds(GREEN_LED,YELLOW_LED);//set the led ports
-  cbus.setPushButton(PUSH_BUTTON);//set the push button ports
-  cbus.setDebug(false);//print some messages on the serial port
+
   cbus.setUserHandlerFunction(&myUserFunc);//function that implements the node logic
-  cbus.initCanBus(53,CAN_125KBPS,10,200);  //initiate the transport layer
-
-  Timer1.initialize(10000);//microseconds
-  Timer1.attachInterrupt(readCanMessages);
+  cbus.initCanBus(CANPORT);  //initiate the transport layer

   Serial.println("Setup finished");
 }

 void loop (){
-
+  cbus.cbusRead();
   cbus.run();//do all logic
-  //debug memory
-  if (digitalRead(PUSH_BUTTON1)==LOW){
-    cbus.dumpMemory();
-  }
 }

 void myUserFunc(Message *msg,MergCBUS *mcbus){
@@ -101,7 +103,11 @@
       }
   }
   if (lighton==YELLOW){
-    if ((millis()-starttime)>TRANSITION_TIME){
+    byte interval=cbus.getNodeVar(1);
+    if (interval<=0){
+        interval=1;
+    }
+    if ((millis()-starttime)>(TRANSITION_TIME*interval)){
       lighton=nextlighton;
     }
   }


Update Treadmill.ino

Update Treadmill.ino

--- Treadmill/Treadmill.ino
+++ Treadmill/Treadmill.ino
@@ -24,6 +24,8 @@
     digitalWrite(UD, LOW);
     digitalWrite(CLK, LOW);
     digitalWrite(CLK, HIGH);
+
+    set_speed_old = set_speed;
   }

   else if(set_speed < set_speed_old){
@@ -31,6 +33,8 @@
     digitalWrite(UD, HIGH);
     digitalWrite(CLK, LOW);
     digitalWrite(CLK, HIGH);
+
+    set_speed_old = set_speed;
   }

   else {


getFreeRAM() re-implemented, now also for ARM

--- YaesuTest/YaesuTest.ino
+++ YaesuTest/YaesuTest.ino
@@ -45,9 +45,7 @@
 #endif // (__AVR__)

 // local prototypes
-#if defined (__AVR__)
-static int availableMemory();
-#endif // (__AVR__)
+static int getFreeRAM();

 void setup() {

@@ -59,9 +57,7 @@
   Serial.begin(UART_BAUD_RATE);
   Serial << F("YaesuTest: starting ...") << endl;

- #if defined (__AVR__)
-  Serial << F("Free SRAM: ") << availableMemory() << endl;
- #endif // (__AVR__)
+  Serial << F("Free SRAM: ") << getFreeRAM() << endl;
 #endif // DEBUG

   // set the data rate for the SoftwareSerial port(s)
@@ -86,7 +82,7 @@
 /** Set the desired frequency and mode of the TX (one quantity at a time). */
 static void txSetFrequencyAndMode(YaesuCAT& ft817,
                                   uint32_t& desired_frequency,
-                                  byte& desired_mode,
+                                  byte desired_mode,
                                   unsigned long interval=500) {

   static unsigned long s_time = millis();
@@ -183,24 +179,33 @@
 /**
  *  Try to inquire max. available memory by allocating until heap is exhausted.
  */
-#if defined (__AVR__)
-static int availableMemory() {
-
-#if 0
-  // from: https://devel-ik.fzk.de/wsvn/fd-online/Diverse/Oktokopter/Arduino2Flasher/trunk/Arduino2Flasher.ino
-  int size = 10000;
-  byte *buf;
-  while ((buf = (byte *) malloc(--size)) == NULL);
-  free(buf);
-  return size;
-#else
+static int getFreeRAM() {
+
+  char top;
+
+#ifndef __arm__
+  extern char *__brkval;
+  extern char __bss_end;
+#endif  // __arm__
+
   // see also:
-  // https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory
-  extern int __heap_start, *__brkval;
-  int v;
-
-  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
-#endif
-}
-#endif // (__AVR__)
-
+  // https://forum.pjrc.com/threads/23256-Get-Free-Memory-for-Teensy-3-0
+#ifdef __arm__
+   uint32_t stackTop;
+    uint32_t heapTop;
+
+    // current position of the stack.
+    stackTop = (uint32_t) &stackTop;
+
+    // current position of heap.
+    void* hTop = malloc(1);
+    heapTop = (uint32_t) hTop;
+    free(hTop);
+
+    // The difference is the free, available ram.
+    return stackTop - heapTop;
+#else  // __arm__
+  return __brkval ? &top - __brkval : &top - &__bss_end;
+#endif  // __arm__
+}
+


Continue to update basic mqtt point code. Code now activtes AP if it can't connect to wifi as well as allows AP activation via button press at boot. AP page now has better styling.

--- mqttHA_Point/mqttHA_Point.ino
+++ mqttHA_Point/mqttHA_Point.ino
@@ -1,7 +1,8 @@
-#include <dummy.h>
+//#include <dummy.h>
 #include <ESP8266WiFi.h>
+#include <WiFiClient.h>
+#include <ESP8266WebServer.h>
 #include <PubSubClient.h>
-#include <ESP8266WebServer.h>
 #include <EEPROM.h>

 // Update these with values suitable for your network.
@@ -31,7 +32,7 @@
 unsigned long startTime;
 long timeHeld;
 /////////////////////////////////////////////////////////////////////////////////////////////////////////
-void setup_wifi() {
+void connect2Wifi() {

   delay(10);
   WiFi.begin();
@@ -39,28 +40,30 @@
   Serial.println("Reading EEPROM ssid");

   for (int i = 32; i < 64; ++i)
-    {
-      esid += char(EEPROM.read(i));
-    }
+  {
+    esid += char(EEPROM.read(i));
+  }
   Serial.print("SSID: ");
   Serial.println(esid);
-  Serial.println("Reading EEPROM pass");

+  Serial.println("Reading EEPROM pass");
   for (int i = 64; i < 128; ++i)
-    {
-      epass += char(EEPROM.read(i));
-    }
+  {
+    epass += char(EEPROM.read(i));
+  }
   Serial.print("PASS: ");
   Serial.println(epass);
-         if (testWifi()) {
-          Serial.println("");
-          Serial.println("Connected to wifi network :/ ");
-          return;
-        }

-}
-/////////////////////////////////////////////////////////////////////////////////////////////////////////
-bool testWifi(void) {
+   if (wifiConnected())
+   {
+    Serial.println("");
+    Serial.println("Connected to wifi network :/ ");
+    return;
+    }
+
+}
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool wifiConnected(void) {
   WiFi.mode(WIFI_STA);
   int c = 0;
   if ( esid.length() > 1 ) {
@@ -103,7 +106,9 @@
   int n = WiFi.scanNetworks();
   Serial.println("scan done");
   if (n == 0)
+  {
     Serial.println("no networks found");
+  }
   else
   {
     Serial.print(n);
@@ -122,19 +127,21 @@
      }
   }
   Serial.println("");
-  st = "
";
+  st = "<select name='ssid' size='5'>";
   for (int i = 0; i < n; ++i)
     {
       // Print SSID and RSSI for each network found
-      st += "
";
+      st += "<option value='";
+      st += WiFi.SSID(i);
+      st += "'>";
       st += WiFi.SSID(i);
       st += " (";
       st += WiFi.RSSI(i);
       st += ")";
       st += (WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":"*";
-      st += "
";
+      st += "</option>";
     }
-  st += "
";
+  st += "</select>";
   delay(100);
   WiFi.softAP(ssid, passphrase, 6);
   Serial.println("softap");
@@ -152,11 +159,24 @@
         Serial.println("server received /");
         IPAddress ip = WiFi.softAPIP();
         String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);
-        content = "<!DOCTYPE HTML>\r\nHello from ESP8266 at ";
+        content = "<!DOCTYPE HTML>";
+        content += "";
+        content += " <meta charset='utf-8'> <meta http-equiv='X-UA-Compatible' content='IE=edge'> <title></title> <meta name='description' content=''> <meta name='viewport' content='width=device-width, initial-scale=1'> <link rel='stylesheet' href=''> ";
+        content += "";
+        content += "";
+        content += "
Welcome to redDevice WiFi Setup at IP Address:";
         content += ipStr;
-        content += "
";
+        content += "
";
+        content += "
Please select your WiFi network and enter the pass key
";
+        content += "<form method='get' action='setting'>";
         content += st;
-        content += "
<form method='get' action='setting'>SSID: <input name='ssid' length=32><input name='pass' length=64><input type='submit'></form>";
+        content += "
Key: <input type='password' name='pass' length=64>
";
+        content += "<input type='submit' value='Enter'>";
+        content += "</form>";
+        content += "";
         content += "";
         server.send(200, "text/html", content);
     });
@@ -327,51 +347,96 @@
   EEPROM.begin(512);
   //pinMode(0, INPUT);
   pinMode(4, INPUT);
+  pinMode(LED_BUILTIN, OUTPUT);
+  digitalWrite(LED_BUILTIN, HIGH); //Turn off
   WiFi.begin();
   delay(1000);
   Serial.println("");
   Serial.println("delay done");
   Serial.println(digitalRead(4));
-   if (digitalRead(4)==false)
+
+  //If button is pressed on power up then start access point for config
+  if (digitalRead(4)==false)
   {
     Serial.println("button pressed at beginning");
     delay(250);
-     if (digitalRead(4)==false)setupAP();
-     while(1){server.handleClient();delay(10);}
-
-  }
-  else{
-  Serial.println("");
-  redEEPromRead();
-  Serial.println("");
-  Serial.print("point ID is: ");
-  Serial.println(pointID);
-  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
-  setup_wifi();
-  client.setServer(mqtt_server, 1883);
-  client.setCallback(callback);
-  pinMode(0, INPUT);
-  delay(1000);
-  reconnect();}
+    if (digitalRead(4)==false)
+      {
+        setupAP();
+      }
+    while(1)
+      {
+        server.handleClient();
+        delay(10);
+      }
+  }
+
+  //Try to connect to WiFi
+  connect2Wifi();
+
+  //If wifi is not connected start access point for config
+  if(!wifiConnected())
+  {
+    digitalWrite(LED_BUILTIN, LOW); //Turn on
+    setupAP();
+    while(1)
+      {
+        server.handleClient();
+        delay(10);
+      }
+  }

+//  if (digitalRead(4)==false)
+//  {
+//    Serial.println("button pressed at beginning");
+//    delay(250);
+//    if (digitalRead(4)==false)
+//      {
+//        setupAP();
+//      }
+//    while(1)
+//      {
+//        server.handleClient();
+//        delay(10);
+//      }
+//
+//  }
+//  else
+//  {
+//    Serial.println("");
+//    redEEPromRead();
+//    Serial.println("");
+//    Serial.print("point ID is: ");
+//    Serial.println(pointID);
+//    pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
+//    connect2Wifi();
+//    client.setServer(mqtt_server, 1883);
+//    client.setCallback(callback);
+//    pinMode(0, INPUT);
+//    delay(1000);
+//    reconnect();
+//   }
+
 }
 /////////////////////////////////////////////////////////////////////////////////////////////////////////
 void loop() {
-
-  if (!client.connected() && (WiFi.status() == WL_CONNECTED)) {
-    Serial.println("rwwwiaiau");
-    reconnect();
-  }
-
-  client.loop();
-
-   if (digitalRead(0)==false)
-  {
-    Serial.println("button pressed");
-    delay(250);
-     if (digitalRead(0)==false)joinControlNet();
-
-  }
-
-
-}
+//  setupAP();
+
+//  if (!client.connected() && (WiFi.status() == WL_CONNECTED)) {
+//    Serial.println("rwwwiaiau");
+//    reconnect();
+//  }
+//
+//  client.loop();
+//
+//   if (digitalRead(0)==false)
+//  {
+//    Serial.println("button pressed");
+//    delay(250);
+//     if (digitalRead(0)==false)joinControlNet();
+//
+//  }
+
+    Serial.println("looping");
+    delay(1000);
+}


minor test update

minor test update

--- tests/Tower/ST3795_test/ST3795_test.ino
+++ tests/Tower/ST3795_test/ST3795_test.ino
@@ -2,7 +2,7 @@
 #include <Streaming.h>
 #include <Metro.h>

-SoftwareSerial IRsend(8, 7);
+SoftwareSerial IRsend(8, 7); // Pin 7 to ST3795 RXD (pin 3)

 uint16_t addressC = 0x00F7;
 byte redC = 0x20;
@@ -22,9 +22,9 @@
 void loop() {
   // put your main code here, to run repeatedly:
   send(redC);
-  delay(5000);
+  delay(1000);
   send(grnC);
-  delay(5000);
+  delay(1000);

 }


Clean includes

Clean includes

--- Valokepakko.ino
+++ Valokepakko.ino
@@ -1,7 +1,7 @@
 #include <avr/pgmspace.h>
+#include <math.h>

 #include "image.h"
-#include "math.h"

 #include <Adafruit_NeoPixel.h>
 #ifdef __AVR__


example updated

example updated

--- examples/arduino/main.ino
+++ examples/arduino/main.ino
@@ -10,7 +10,7 @@
             virtual void begin(void) {

                 Vref = 1.2023f;
-
+
                 pinMode(ADC_CS_PIN, OUTPUT);
                 digitalWrite(ADC_CS_PIN, HIGH);

@@ -61,10 +61,15 @@
     adc.begin();

     {   using namespace MCP3911;
-
-		// set register map ptr
-		adc._c = &c;
-
+
+        // set register map ptr
+        adc._c = &c;
+
+        adc.reg_read(REG_STATUSCOM, REGISTER, 2);
+        adc.status.read_reg_incr  = ALL;
+        adc.status.write_reg_incr = ALL;
+        adc.reg_write(REG_STATUSCOM, REGISTER, 2);
+
         // read default values
         adc.reg_read(REG_CHANNEL_0, ALL);

@@ -81,10 +86,12 @@
         c.config.prescale       = MCLK4;
         c.config.dither         = MAX;

+        adc.status.read_reg_incr = ALL;
+        adc.status.write_reg_incr = TYPE;
+
         // vref adjustment
         c.vrefcal += 0x11;

-
         // write out all regs
         adc.reg_write(REG_MOD, TYPE);
     }


moved ifdef ADC_USE_DMA in example

moved ifdef ADC_USE_DMA in example

--- examples/adc_dma/adc_dma.ino
+++ examples/adc_dma/adc_dma.ino
@@ -10,11 +10,10 @@
     For the RMS it keeps the average from the previous set of data.
 */

-#ifdef ADC_USE_DMA
-
 #include <ADC.h>
 #include <AnalogBufferDMA.h>

+#ifdef ADC_USE_DMA

 // This version uses both ADC1 and ADC2
 #if defined(KINETISL)
@@ -147,4 +146,4 @@
 #else // make sure the example can run for any boards (automated testing)
 void setup() {}
 void loop() {}
-#endif // ADC_USE_DMA+#endif // ADC_USE_DMA


add i(nstrument)_type

add i(nstrument)_type

--- ptw-wheel.ino
+++ ptw-wheel.ino
@@ -17,9 +17,15 @@
 //   NEO_KHZ800  800 KHz bitstream (e.g. High Density LED strip)
 Adafruit_NeoPixel strip = Adafruit_NeoPixel(TOTAL_PIXELS, 6, NEO_GRB + NEO_KHZ800);

+// serial communication
 char input[11];   // 文字列格納用
 String input_str;   // 文字列格納用
 int i = 0;  // 文字数のカウンタ
+
+// instrument types
+#define INSTRUMENT_TYPE_ONESHOT 0
+#define INSTRUMENT_TYPE_LONGSHOT 1
+int i_type = INSTRUMENT_TYPE_ONESHOT;

 // instrument color
 int i_color_r = 255;
@@ -51,10 +57,24 @@
   if (0<Serial.available()) {
     String command = Serial.readStringUntil(':');
     String argument = Serial.readStringUntil(';');
+
+    Serial.print("command:");
+    Serial.println(command);
+
+    // set instrument type
+    // "t:[0|1];"
+    if(command=="t") {
+      if(argument.toInt()==INSTRUMENT_TYPE_ONESHOT || argument.toInt()==INSTRUMENT_TYPE_LONGSHOT) {
+        i_type = argument.toInt();
+      }
+      else {
+        Serial.print("Invalid argument: ");
+        Serial.println(argument);
+      }
+    }
     // set instrument color
     // "i:[000-255].[000-255].[000-255];"
-    if(command=="i") {
-      Serial.println(command);
+    else if(command=="i") {
       if(argument.length()==11) {

         i_color_r = constrainValue(argument.substring(0,3).toInt());
@@ -156,7 +176,6 @@
 }

 void updateLED() {
-  Serial.println("updateLED");
   uint32_t instrument_color = multiplicateBrightness(i_color_r, i_color_g, i_color_b);
   uint32_t effect_color = multiplicateBrightness(e_color_r, e_color_g, e_color_b);


Implement SSE parity checking

Implement SSE parity checking

--- pi_interrupt_mouse/pi_interrupt_mouse.ino
+++ pi_interrupt_mouse/pi_interrupt_mouse.ino
@@ -10,6 +10,7 @@
 // https://github.com/PaulStoffregen/AltSoftSerial

 AltSoftSerial mySerial;
+int missedPackets = 0;

 enum states {
   NO_CLICK,
@@ -34,12 +35,14 @@
   }
 }

+
 void setup() {
-  mySerial.begin(115200);
-  Serial.begin(115200, SERIAL_8E1);    // serial / USB port
+  mySerial.begin(9600);
+  Serial.begin(115200);    // serial / USB port
   while (!Serial);
   AbsoluteMouse.begin();
   attachInterrupt(digitalPinToInterrupt(2), interrupt, RISING); //interrupt pin from Mega
+  //Serial.println("Ready");
 }

 void loop() {
@@ -62,21 +65,38 @@
       break;
   }

-  String cmd = "";
-  //command terminates with '.'
+  // commands from the pi terminate with '.'
+  char cmd[11] = "";
+  char cmd2[11] = ""; // sse parity \o/

   // check if byte available on the software serial port
   //receives zero-padded string of 16 bit coordinates (xy) ending with a '.'
   if (mySerial.available()) {
-    cmd = (mySerial.readStringUntil('.'));
-    mySerial.println(cmd);
-    Serial.println(cmd);
-    String dx = cmd.substring(0,5);
-    String dy = cmd.substring(5,10);
-    Serial.println(dx + " " + dy);
-    int x = dx.toInt();
-    int y = dy.toInt();
-    AbsoluteMouse.moveTo(x,y);
+    mySerial.readBytesUntil('.', cmd, 11);
+    while (!mySerial.available()) {}
+    mySerial.readBytesUntil('.', cmd2, 11);
+
+    String cmdStr = String(cmd);
+    String cmdStr2 = String(cmd2);
+
+    if (cmdStr.equals(cmdStr2)) {
+      //mySerial.println(cmd);
+      //Serial.println("cmd: " + cmdStr);
+      String dx = cmdStr.substring(0,5);
+      String dy = cmdStr.substring(5,10);
+      //Serial.println("goto " + dx + " " + dy);
+      int x = dx.toInt();
+      int y = dy.toInt();
+      AbsoluteMouse.moveTo(x,y);
+    } else {
+      missedPackets++;
+      if (missedPackets >= 15){
+        missedPackets = 0;
+        mySerial.readBytesUntil('.', cmd, 11);
+        loop();
+      }
+      //Serial.println("Packet miss");
+    }
   }

 }


Fixed ADC powerup.

Fixed ADC powerup.

--- examples/Sandbox/CosaEEPROM/CosaEEPROM.ino
+++ examples/Sandbox/CosaEEPROM/CosaEEPROM.ino
@@ -49,7 +49,7 @@
 };

 // Sensor log in EEPROM
-static const int DATA_MAX = 8;
+static const int DATA_MAX = 64;
 uint16_t data[DATA_MAX] EEMEM;

 // Analog input pin
@@ -74,6 +74,8 @@
 	<< PSTR(", speed = ") << init.speed
 	<< PSTR(", name = \"") << init.name
 	<< PSTR("\")\n");
+
+  AnalogPin::powerup();
 }

 void loop()


diagonal test

diagonal test

--- proj/ledvo_lounge_final/ledvo_lounge_final.ino
+++ proj/ledvo_lounge_final/ledvo_lounge_final.ino
@@ -223,26 +223,35 @@
     //      anim_switch = false;
     //    }

+    static uint8_t blah = 0;
+    EVERY_N_SECONDS(10) {
+      blah = (blah+1)%3;
+      reset_all();
+    }
+
+    fill_solid(d_leds[blah], d_LED_num, CHSV(gHue, 255, gBrightness));
+    FastLED.show();
+
     // Select animation to run based on global counter
     if (!dj_control) {
-      if (gAnimCounter == 0) {
-        fill_all();
-      }
-      else if (gAnimCounter == 1) {
-        trap_solid();
-      }
-      else if (gAnimCounter == 2) {
-        saw_chaser_0(chaser_opt);
-      }
-      else if (gAnimCounter == 3) {
-        saw_chaser_1(chaser_opt);
-      }
-      else if (gAnimCounter == 4) {
-        saw_solid_0();
-      }
-      else if (gAnimCounter == 5) {
-        saw_solid_1();
-      }
+//      if (gAnimCounter == 0) {
+//        fill_all();
+//      }
+//      else if (gAnimCounter == 1) {
+//        trap_solid();
+//      }
+//      else if (gAnimCounter == 2) {
+//        saw_chaser_0(chaser_opt);
+//      }
+//      else if (gAnimCounter == 3) {
+//        saw_chaser_1(chaser_opt);
+//      }
+//      else if (gAnimCounter == 4) {
+//        saw_solid_0();
+//      }
+//      else if (gAnimCounter == 5) {
+//        saw_solid_1();
+//      }
       /*if (gAnimCounter == 0) {
         fill_all();
         }
@@ -276,6 +285,8 @@
         else if (gAnimCounter == 10) {
         all_trap_chaser(chaser_opt);
         }*/
+
+
     }

     // The following are all checks for DJ animations that