Delete C_DISCOR-Industruino.ino

Delete C_DISCOR-Industruino.ino

--- Examples/C_DISCOR-Industruino/C_DISCOR-Industruino.ino
+++ Examples/C_DISCOR-Industruino/C_DISCOR-Industruino.ino
@@ -1,209 +0,0 @@
-/*-------------------------------------------------------------------------------------------------------------------------------------------*
- * SE2R : C_DISCOR - Fonction de détection temporisée de discordance entre deux valeurs ToR ou analogiques                        29/06/2015 *
- *-------------------------------------------------------------------------------------------------------------------------------------------*
- *        C_DISCOR(float IN1, float IN2, float DIF, float CPT[], boolean RES[], int CFG)                                          29/06/2015 *
- *                IN1 : Première valeur à comparer                                                                                *
- *                IN2 : Deuxième valeur à comparer                                                                                *
- *                DIF : Différence maximum tolérée entre IN1 et IN2                                                                          *
- *                TPO : [0] Compteur de temporisation                                                                                *
- *                      [1] Tempo de confirmation de la discordance                                                                          *
- *                      [2] Temps de cycle automate calculé par la fonction                                                                  *
- *                      [3] Mémorisation de la variable système Millis pour le calcul du temps de cycle                                      *
- *                RES : [0] Discordance de l'équipement - forcément un tableau de taille au moins 1                                          *
- *                CFG : Commande de forçage.                                                                                *
- *                      <0 : RES maintenu à false donc en discordance                                                                        *
- *                      0  : RES figée dans son dernier état connu                                                                           *
- *                      1  : RES est true sauf si IN1 et IN2 diffèrent de plus de DIF pendant plus de CPT[1] sans discontinuer               *
- *                      2  : RES maintenu à true en permanence                                                                               *
- *                      3  : RES maintenu à true en permanence                                                                               *
- *                      >3 : RES maintenu à false                                                                                *
- *-------------------------------------------------------------------------------------------------------------------------------------------*
- * Copyright SE2R under the APACHE Licence                                                                                *
- *-------------------------------------------------------------------------------------------------------------------------------------------*
- * Plate-formes testées : Industruino 32U8 et 1286                                                                                *
- *-------------------------------------------------------------------------------------------------------------------------------------------*
- * 29/06/2015 : DD, SE2R : Testée et validée sur banc                                                                                *
- *-------------------------------------------------------------------------------------------------------------------------------------------*/
-
-// Déclaration des bibliothèques nécessaires à l'exécution du programme ---------------------------------------------------------------------*
-#include <DIS.h>                        // Biblio   - SE2R - Fonctions de dialogue et d'affichage sur l'écran UC1701 Industruino
-static DIS DIS;                         // Biblio   - Activation du constructeur de la bibliothèque de fonctions d'affichage
-static UC1701 lcd;
-#include <BMS.h>                        // Biblio   - SE2R - Fonctions de contrôle et régulation
-static BMS BMS;                         // Biblio   - Activation du constructeur de la bibliothèque de fonctions d'affichage
-
-// Déclaration des variables nécessaires à l'exécution de la fonction -----------------------------------------------------------------------*
-boolean FCO_REAR[1];                    // C_DISCOR - [00] Commande de réarmement depuis l'extérieur
-boolean EDx_TEL_XXXX[9];                // Système  - [00] Inutilisée
-                                        //            [01] Etat de la lecture de la voie digitale 1 si elle est une entrée
-                                        //            [02] Etat de la lecture de la voie digitale 2 si elle est une entrée
-                                        //            [03] Etat de la lecture de la voie digitale 3 si elle est une entrée
-                                        //            [04] Etat de la lecture de la voie digitale 4 si elle est une entrée
-                                        //            [05] Etat de la lecture de la voie digitale 5 si elle est une entrée
-                                        //            [06] Etat de la lecture de la voie digitale 6 si elle est une entrée
-                                        //            [07] Etat de la lecture de la voie digitale 7 si elle est une entrée
-                                        //            [08] Etat de la lecture de la voie digitale 8 si elle est une entrée
-boolean SDx_TSL_XXXX[9];                // Système  - [00] Mémoire temporaire utilisée pour les calculs
-                                        //            [01] Etat de la commande de la voie digitale 1 si elle est une sortie
-                                        //            [02] Etat de la commande de la voie digitale 1 si elle est une sortie
-                                        //            [04] Etat de la commande de la voie digitale 1 si elle est une sortie
-                                        //            [05] Etat de la commande de la voie digitale 1 si elle est une sortie
-                                        //            [07] Etat de la commande de la voie digitale 1 si elle est une sortie
-                                        //            [08] Etat de la commande de la voie digitale 1 si elle est une sortie
-boolean FDM_XXXX[1];                    // C_DISCOR - [00] Etat de la commande à transmettre à la sortie
-float VTT_XXXX[5];                      // C_DISCOR - [00] Compteur des temporisations
-                                        //            [01] Tempo de confirmation de la discordance
-                                        //            [02] Temps de cycle automate calculé par la fonction
-                                        //            [03] Mémorisation de la variable système Millis pour le calcul du temps de cycle
-int VCO_XXXX[1];                        // C_DISCOR - [00] Commande de forçage par l'extérieur
-
-// Déclaration des variables nécessaires au fonctionnement de l'écran -----------------------------------------------------------------------*
-String TCM_PRES[21] = {                 // EcranLCD - Table de chaînes de caractères de présentation
-  "                     ",  // 00
-  "-  Menu  Principal  -",
-  "Retour Accueil      ",
-  "Rearmer             ",
-  "Chrono              ",
-  "Entree 1            ",
-  "Entree 2            ",
-  "Discorde            ",
-  "- Selection + Enter -",
-  "-    Rearmement     -",
-  "- Tempo discordance -",  // 10
-  " ",
-  " ",
-  " ",
-  " ",
-  " ",
-  " ",
-  " ",
-  " ",
-  " ",
-  " "};                      // 20
-
-
-String TCM_UNIT[21] = {                 // EcranLCD - Table de chaînes de caractères d'unités standard
-  "        ",  // 00
-  "oC      ",
-  "%       ",
-  "s       ",
-  "V       ",
-  "mV      ",  // 05
-  "",
-  "",
-  "",
-  "",
-  "",          // 10
-  "   Arret ",
-  "  Marche ",
-  "Discorde ",
-  "  Normal ",
-  "  Active ", // 15
-  " Rearmer ",
-  " ",
-  " ",
-  " ",
-  "  " };      // 20
-
-boolean FCO_PRUP[5];                    // EcranLCD - Information de touche "Up" appuyée
-boolean FCO_PREN[5];                    // EcranLCD - Information de touche "Enter" appuyée
-boolean FCO_PRDN[5];                    // EcranLCD - Information de touche "Down" appuyée
-int VNT_MENU[2];                        // EcranLCD - Table d'adressage des menus
-int VNC_MENU[10];                       // EcranLCD - Table des numéros de menus
-int VNC_PRUP[11];                       // EcranLCD - Table des numéros de menus de destination par la touche "Up"
-int VNC_PREN[10];                       // EcranLCD - Table des numéros de menus de destination par la touche "Enter"
-int VNC_PRDN[10];                       // EcranLCD - Table des numéros de menus de destination par la touche "Down"
-float VTT_SCRN[10];                     // EcranLCD - Table des temporisations
-int VNX_MN02[12];                       // EcranLCD - Table des menus de destimation et des index du menu 02 - Principal
-boolean FCM_REAR[1];                    // G_MODV1B - Mémoire de la demande de réarmement
-float VTM_TPAM[11];                     // G_MODV1F - Mémoire de calcul de la commande de la fonction pour VTT_XXXX[1] - Tempo à la marche
-float VTM_TPMA[11];                     // G_MODV1F - Mémoire de calcul de la commande de la fonction pour VTT_XXXX[2] - Tempo à l'arrêt
-
-void setup() {                          // Initialisation -----------------------------------------------------------------------------------*
-Indio.digitalMode(1,INPUT);             // Système  - Affectation de la voie Dx1 en tant qu'entrée digitale
-Indio.digitalMode(2,INPUT);             // Système  - Affectation de la voie Dx2 en tant qu'entrée digitale
-VCO_XXXX[0] = 1;                        // C_CDELEM - Passage du forçage en position auto
-
-VTT_SCRN[1] = 180;                      // G_TOUCHx - Temporisation d'inactivité sur le rétroéclairage
-VTT_SCRN[2] = 240;                      // G_TOUCHx - Temporisation d'inactivité de retour à l'écran principal
-VTT_SCRN[3] = 20;                       // G_TOUCHx - Temporisation d'antirebond de la touche "Enter"
-VTT_SCRN[4] = 15;                       // G_TOUCHx - Temporisation d'antiredond des touches "Up" et "Down"
-VNT_MENU[0] = 4;                        // G_NAVIGM - Taille des tables d'index et de destinations
-VNT_MENU[1] = 1;                        // G_NAVIGM - Initialisation du pointeur de destinations
-
-//                                      // G_NAVIGM - Tables d'adressage de l'écran LCD
-VNC_MENU[0] = 1;
-VNC_MENU[1] = 1;
-VNC_MENU[2] = 2;
-VNC_MENU[3] = 3;
-VNC_MENU[4] = 4;
-VNC_PRUP[1] =   1; VNC_PREN[1] =   2; VNC_PRDN[1] =   2;
-VNC_PRUP[2] =   2; VNC_PREN[2] =   2; VNC_PRDN[2] =   2;
-VNC_PRUP[3] =   3; VNC_PREN[3] =   2; VNC_PRDN[3] =   3;
-VNC_PRUP[4] =   4; VNC_PREN[4] =   2; VNC_PRDN[4] =   4;
-VNC_PRUP[5] =   2;
-
-VNX_MN02[0] = 0;						// G_CHOIX8 - Table des menus de destination et des index du menu 11 - Initialisation index
-VNX_MN02[1] = 1;
-VNX_MN02[2] = 3;
-VNX_MN02[3] = 4;
-VNX_MN02[4] = 0;
-VNX_MN02[5] = 0;
-VNX_MN02[6] = 0;
-VNX_MN02[7] = 0;
-VNX_MN02[8] = 1;
-VNX_MN02[9] = 3;
-VNX_MN02[10] = 1;
-
-VTM_XXXX[1] = 0; VTM_XXXX[2] = 600; VTM_XXXX[3] = 1;  VTM_XXXX[4] = VTT_XXXX[1];  VTM_XXXX[8] = 100;
-
-//                                      // EcranLCD - Paramétrage spécifique Industruino 1286
-pinMode(23, INPUT);                     // EcranLCD - Spécifique 1286 - Touche flèche basse
-pinMode(24, INPUT);                     // EcranLCD - Spécifique 1286 - Touche entrée
-pinMode(25, INPUT);                     // EcranLCD - Spécifique 1286 - Touche flèche haute
-pinMode(26, OUTPUT);                    // EcranLCD - Spécifique 1286 - Sortie de commande du rétroéclairage
-
-/*                                      // EcranLCD - Paramétrage spécifique Industruino 32U8
-pinMode(13, OUTPUT);                    // EcranLCD - Spécifique 32U8 - Sortie de commande du rétroéclairage
-*/
-lcd.begin();                            // EcranLCD - Initialisation de l'écran LCD
-lcd.clear();                            // EcranLCD - Effacement de l'écran LCD
-}
-
-void loop() {                            // Exécution ---------------------------------------------------------------------------------------*
-if (Indio.digitalRead(1) == HIGH) { EDx_TEL_XXXX[1] = false; } else { EDx_TEL_XXXX[1] = true; }
-if (Indio.digitalRead(2) == HIGH) { EDx_TEL_XXXX[2] = false; } else { EDx_TEL_XXXX[2] = true; }
-if (FCO_REAR[0]) { FDM_XXXX[0] = true; }
-BMS.C_DISCOR(EDx_TEL_XXXX[1], EDx_TEL_XXXX[2], 0.5, VTT_XXXX, FDM_XXXX, 1 - (2 * (FDM_XXXX[0] == false)));
-
-//                                      // EcranLCD - Gestion des touches spécifique Industruino 1286
-DIS.G_TOUCH2(VNC_MENU, VTT_SCRN, FCO_PRUP, FCO_PREN, FCO_PRDN);
-/*                                      // EcranLCD - Gestion des touches spécifique Industruino 32U8
-DIS.G_TOUCH1(VNC_MENU, VTT_SCRN, FCO_PRUP, FCO_PREN, FCO_PRDN);
-*/
-
-if (VNC_MENU[0] ==  1) { lcd.setCursor(0, 0); lcd.clearLine(); }
-DIS.G_MESS1L(VNC_MENU, 1, 1, 0, "   www.eControls.eu  ");
-DIS.G_MESS1L(VNC_MENU, 1, 2, 0, "    SE2R Softwares   ");
-DIS.G_MESS1L(VNC_MENU, 1, 3, 0, "  Industruino  1286  ");
-// DIS.G_MESS1L(VNC_MENU, 1, 3, 0, "  Industruino  32U8  ");
-if (VNC_MENU[0] ==  1) { lcd.setCursor(0, 4); lcd.clearLine(); }
-DIS.G_MESS1L(VNC_MENU, 1, 5, 0, "Fonction BMS.C_DISCOR");
-DIS.G_MESS1L(VNC_MENU, 1, 6, 0, "A# TESTS     C# 00001");
-DIS.G_MESS1L(VNC_MENU, 1, 7, 0, "V.1.01     29/06/2015");
-
-DIS.G_CHOIX8(VNC_MENU, 2, FCO_PRUP, FCO_PREN, FCO_PRDN, VNX_MN02);
-DIS.G_MESS1L(VNC_MENU, 2, 0, 0, TCM_PRES[1]);
-DIS.G_MESS1L(VNC_MENU, 2, 1, 6, TCM_PRES[2]);
-DIS.G_VISV1B(VNC_MENU, 2, 2, 6, FCO_REAR[0], TCM_PRES[3], TCM_UNIT[15], TCM_UNIT[16]);
-DIS.G_VISV1F(VNC_MENU, 2, 3, 6, VTT_XXXX[0], TCM_PRES[4], TCM_UNIT[3]);
-DIS.G_VISV1B(VNC_MENU, 2, 4, 0, EDx_TEL_XXXX[1], TCM_PRES[6], TCM_UNIT[11], TCM_UNIT[12]);
-DIS.G_VISV1B(VNC_MENU, 2, 5, 0, EDx_TEL_XXXX[2], TCM_PRES[6], TCM_UNIT[11], TCM_UNIT[12]);
-DIS.G_VISV1B(VNC_MENU, 2, 6, 0, FDM_XXXX[0], TCM_PRES[7], TCM_UNIT[13], TCM_UNIT[14]);
-DIS.G_MESS1L(VNC_MENU, 2, 7, 0, TCM_PRES[8]);
-
-DIS.G_MODV1B(VNC_MENU, 3, FCO_PRUP, FCO_PREN, FCO_PRDN, FCO_REAR, 0, FCM_REAR, TCM_PRES[9] , "Rearme discorde a On", TCM_UNIT[13], TCM_UNIT[14], true);
-DIS.G_MODV1F(VNC_MENU, 5, FCO_PRUP, FCO_PREN, FCO_PRDN, VTT_XXXX, 1, VTM_TPAM, TCM_PRES[10], "Avant  passage a Off", TCM_UNIT[3], true, 0);
-
-DIS.G_NAVIGM(VNC_MENU, VNT_MENU, FCO_PRUP, FCO_PREN, FCO_PRDN , VNC_PRUP, VNC_PREN, VNC_PRDN);
-}


Added Failed MQTT Serial Message

Added Failed MQTT Serial Message

--- src/WiFiSensor/WiFiSensor.ino
+++ src/WiFiSensor/WiFiSensor.ino
@@ -157,10 +157,14 @@
         snprintf(msg, 25, "%s", String(lastmeasurement.temperature).c_str());
         if(client.publish( (topicname + mqtttemperaturetopic).c_str(), msg)){
 			Serial.println("Successful Published Data: " + topicname + mqtttemperaturetopic + " Value: " + msg );
+		}else{
+			Serial.println("Failed Published Data: " + topicname + mqtttemperaturetopic + " Value: " + msg );
 		}
         snprintf(msg, 75, "%s", String(lastmeasurement.humidity).c_str());
         if(client.publish((topicname + mqtthumiditytopic).c_str(), msg)){
 			Serial.println("Successful Published Data 2: " + topicname + mqtthumiditytopic + " Value: " + msg );
+		}else{
+			Serial.println("Failed Published Data 2: " + topicname + mqtthumiditytopic + " Value: " + msg );
 		}
       }
     }


took out buffers, adjusted output

took out buffers, adjusted output

--- aquaponicMCP/aquaponicMCP.ino
+++ aquaponicMCP/aquaponicMCP.ino
@@ -2,13 +2,14 @@
 #include "OneWire.h"

 //analog pins
-#define plantLight A0
+#define plantLight A1
 #define aquaLight A1
-#define waterTurbSensor A2
+#define waterTurbSensor A0
+#define ovenTemp A0

 //digital pins
 OneWire  ds(2); //water temp sensor
-#define RELAY1  3
+#define RELAY1  5
 #define plantLed 4
 #define aquaLed 5
 #define turbLed 6
@@ -28,16 +29,11 @@
 float plantLightReading = 0.0;
 float waterTempReading = 0.0;
 float waterTurbReading = 0.0;
-
-//buffers to hold sensor data
-uint16_t plantLightBuffer[64];
-uint16_t aquaLightBuffer[64];
-uint16_t tempBuffer[64];
-uint16_t turbBuffer[64];
+float ovenTempReading = 0.0;

 uint8_t bufferCounter = 1;

-bool powerIsOn = false;
+bool powerIsOn = true;

 uint8_t incomingByte;

@@ -48,21 +44,19 @@
 //run once on start
 void setup() {
   Serial.begin(9600);
-  plantLightBuffer[0] = 1791;
-  aquaLightBuffer[0] = 1792;
-  tempBuffer[0] = 1793;
-  turbBuffer[0] = 1794;
+  Serial.println("hi");
   pinMode(plantLed, OUTPUT);
   pinMode(aquaLed, OUTPUT);
   pinMode(turbLed, OUTPUT);
   pinMode(tempLed, OUTPUT);
   pinMode(lightButton, INPUT);
   digitalWrite(lightButton, HIGH);
+  pinMode(RELAY1, OUTPUT);
+  digitalWrite(RELAY1, HIGH);
 }

 //main program loop.
 void loop() {
-  LogData();
   SendData();
   SendCommands();
   GetManual();
@@ -80,37 +74,32 @@
  * After an hour has passed, auto mode will turn back on.
  */
 void GetManual(){
-  if(digitalRead(lightButton)){
-    digitalWrite(RELAY1, powerIsOn);
-    powerIsOn = !powerIsOn;
-    autoTimer = millis();
-  }
+//  if(digitalRead(lightButton)){
+////    digitalWrite(RELAY1, powerIsOn);
+//    powerIsOn = !powerIsOn;
+//    autoTimer = millis();
+//  }
 }

 /*these will be raw readings, converting from voltage to
  * degrees or light etc should most likly done in a seperate
  * function or even in the data logger.
  */
-void LogData(){
-  if(bufferCounter >= 64) return;
-  plantLightReading = analogRead(aquaLight);
-  aquaLightReading = analogRead(plantLight);
-  waterTempReading = ReadTemp();
-  waterTurbReading = analogRead(waterTurbSensor);
-  plantLightBuffer[bufferCounter] = plantLightReading;
-  aquaLightBuffer[bufferCounter] = aquaLightReading;
-  tempBuffer[bufferCounter] = waterTempReading;
-  turbBuffer[bufferCounter] = waterTurbReading;
-  bufferCounter += 1;
-  Serial.print("aquaLight: ");
-  Serial.print(aquaLightReading);
-  Serial.print(" rightLight: ");
-  Serial.print(plantLightReading);
-  Serial.print(" waterTemp: ");
-  Serial.println(waterTempReading);
-  Serial.print(" waterTurb: ");
-  Serial.print(waterTurbReading);
-}
+void SendData(){
+  String mystr = "['data', {'station': 'aquaponicStation', 'sensors': [{'sensor': 'aquaLight', 'value': ";
+  mystr += analogRead(aquaLight) ;
+  mystr += "},{'sensor':'plantLight','value':";
+  mystr += analogRead(plantLight);
+  mystr += "},{'sensor':'waterTurb','value':";
+  mystr += analogRead(waterTurbSensor);
+//  mystr += "},{'sensor':'waterTemp','value':";
+//  mystr += ReadTemp();
+  mystr += "},{'sensor':'OvenTemp','value':";
+  mystr += analogRead(ovenTemp);
+  mystr += "}]}]";
+  Serial.println(mystr);
+}
+

 //Script I found online and modifed using the OneWire, returns the temperature in fahrenheit.
 float ReadTemp(){
@@ -185,26 +174,6 @@
   return fahrenheit;
 }

-/* Im sure there is a better way, consider a timeout?
- * we'll need to check for missed or overwritten data
- * because this might take to long
- */
-void SendData(){
-  if(bufferCounter >= 64){
-    SendBuffer(plantLightBuffer);
-    SendBuffer(aquaLightBuffer);
-    SendBuffer(tempBuffer);
-    SendBuffer(turbBuffer);
-    bufferCounter = 1;
-  }
-}
-
-void SendBuffer(int buf[]){
-  for(int i = 0; i < 64; i++){
-    Serial.write(buf[i]);
-  }
-}
-
 //read input via serial
 void GetInput(){
   if (Serial.available() > 0) {
@@ -213,12 +182,12 @@
     //light schduling
     //turn lights off
     if(incomingByte == 1){
-       digitalWrite(RELAY1,0);
+//       digitalWrite(RELAY1,0);
        powerIsOn = false;
     }
     //turn lights on
     if(incomingByte == 2){
-       digitalWrite(RELAY1,1);
+//       digitalWrite(RELAY1,1);
        powerIsOn = true;
     }
   }


Demo: Fixed the number of menu items.D

Demo: Fixed the number of menu items.D

--- examples/Demo/Demo.ino
+++ examples/Demo/Demo.ino
@@ -608,7 +608,7 @@
   { "Music", musicDemo },
   { "Power", powerDemo },
 };
-Menu mainMenu(mainMenuItems, 7);
+Menu mainMenu(mainMenuItems, 6);

 // This function watches for button presses.  If a button is
 // pressed, it beeps a corresponding beep and it returns 'A',


temporary fixes for KISS example

temporary fixes for KISS example

--- examples/KISS/KISS.ino
+++ examples/KISS/KISS.ino
@@ -7,6 +7,11 @@
  * into the HamShield RF jack. Connect the Arduino to wall
  * power and then to your computer via USB. Issue commands
  * via the KISS equipment.
+ *
+ * You can also just use the serial terminal to send and receive
+ * APRS packets, but keep in mind that several fields in the packet
+ * are bit-shifted from standard ASCII (so if you're receiving,
+ * you won't get human readable callsigns or paths).
  *
  * To use the KISS example with YAAC:
  * 1. open the configure YAAC wizard
@@ -55,9 +60,9 @@
   radio.setVolume2(0xFF);
   radio.setSQHiThresh(-100);
   radio.setSQLoThresh(-100);
-  radio.setSQOn();
+  //radio.setSQOn();
   radio.frequency(144390);
-  //radio.bypassPreDeEmph();
+  radio.bypassPreDeEmph();

   dds.start();
   afsk.start(&dds);


Fixing types. The RF24 library f's up half the data. WHY?!

--- attiny/attiny.ino
+++ attiny/attiny.ino
@@ -36,8 +36,8 @@
 role_e role;
 const char* role_friendly_name[] = { "invalid", "Remote", "LED Board"};

-bool led_state;
-bool sensor_state;
+uint8_t led_state;
+uint8_t sensor_state;
 volatile int awakems = 0;
 int send_tries = 0;
 bool send_ok = true;
@@ -105,8 +105,7 @@
     if (role == role_remote) {
         // Get the current state of buttons, and
         // Test if the current state is different from the last state we sent
-        delay(5);
-        bool state = !digitalRead(sensor_pin);
+        uint8_t state = !digitalRead(sensor_pin);
         printf("Sensor state: %d\n", state);
         if (state != sensor_state) {
             different = true;
@@ -121,7 +120,7 @@
             digitalWrite(led_pin, led_state);
             radio.powerUp();
             delay(10);
-            send_ok = radio.write( &sensor_state, sizeof(bool), false );
+            send_ok = radio.write( &sensor_state, sizeof(uint8_t), false );
             if (send_ok) {
                 printf("ok\n\r");
             } else {
@@ -147,17 +146,17 @@
     if (role == role_led) {
         if (radio.available()) {
             // Dump the payloads until we've gotten everything
-            bool done = false;
+            uint8_t done;
             awakems = 0;
             while (!done) {
-                done = radio.read( &sensor_state, sizeof(bool) );
+                done = radio.read( &sensor_state, sizeof(uint8_t) );
             }
 //            if (led_state != sensor_state) {
 //                different = true;
                 printf("Got buttons: %d\n\r", sensor_state);
                 led_state = sensor_state;
                 digitalWrite(led_pin, led_state);
-                awakems = -1000;
+                awakems = -10000;
 //            }
         }


Update PrintStates2.ino

Update PrintStates2.ino

--- examples/PrintStates2/PrintStates2.ino
+++ examples/PrintStates2/PrintStates2.ino
@@ -3,20 +3,20 @@
 #include <MobaTools.h>
 // define pin numbers
 const byte buttonPin [] = { A0, A1, A2, A3 };
-const byte anzahlButtons = sizeof(buttonPin);
+const byte buttonCnt = sizeof(buttonPin);
 char txtBuf[50];

 /*button_t getHW( void ) {
   // raw reading of buttons
   button_t buttonTemp = 0;
-  for (byte i = 0; i < anzahlButtons; i++) {
+  for (byte i = 0; i < buttonCnt; i++) {
     bitWrite( buttonTemp,i,!digitalRead(buttonPin[i]) );
   }
   return buttonTemp;
 }*/

 //MoToButtons Buttons( getHW, 30, 500, 500 );
-MoToButtons Buttons( buttonPin, anzahlButtons, 30, 500 );
+MoToButtons Buttons( buttonPin, buttonCnt, 30, 500 );

 void printPressedEvent( uint8_t buttonNbr ) {
   if ( Buttons.pressed(buttonNbr) ) {
@@ -67,7 +67,7 @@
   Serial.begin(115200);
   while(!Serial);       // only for Leonardo/Micro ( mega32u4 based boards

-  for (int i = 0; i < anzahlButtons; i++)  {
+  for (int i = 0; i < buttonCnt; i++)  {
     // buttons must switch to Gnc
     pinMode(buttonPin[i], INPUT_PULLUP);
   }


Avoid unnecessary timeouts

Avoid unnecessary timeouts

Replaced a 500ms delay in the show task with MAX_DELAY. There's really no point in timing out (and crashing the program) just because the application hasn't called show.

--- examples/DemoReelESP32/DemoReelESP32.ino
+++ examples/DemoReelESP32/DemoReelESP32.ino
@@ -39,7 +39,6 @@
 void FastLEDshowESP32()
 {
     if (userTaskHandle == 0) {
-        const TickType_t xMaxBlockTime = pdMS_TO_TICKS( 200 );
         // -- Store the handle of the current task, so that the show task can
         //    notify it when it's done
         userTaskHandle = xTaskGetCurrentTaskHandle();
@@ -48,6 +47,7 @@
         xTaskNotifyGive(FastLEDshowTaskHandle);

         // -- Wait to be notified that it's done
+        const TickType_t xMaxBlockTime = pdMS_TO_TICKS( 200 );
         ulTaskNotifyTake(pdTRUE, xMaxBlockTime);
         userTaskHandle = 0;
     }
@@ -58,11 +58,10 @@
  */
 void FastLEDshowTask(void *pvParameters)
 {
-    const TickType_t xMaxBlockTime = pdMS_TO_TICKS( 500 );
     // -- Run forever...
     for(;;) {
         // -- Wait for the trigger
-        ulTaskNotifyTake(pdTRUE, xMaxBlockTime);
+        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

         // -- Do the show (synchronously)
         FastLED.show();


Fixed altScrollText() function

Fixed altScrollText() function

Arduino doesn't seem to like -sizeof(), -1 * sizeof(), or anything similar, so I had to create a variable first, assign it the value of sizeof(), then make the variable negative.

--- examples/ScrollingText/ScrollingText.ino
+++ examples/ScrollingText/ScrollingText.ino
@@ -23,8 +23,8 @@
 #endif

 // Defines the number of 8x8 display rows and columns
-const byte NUM_ROWS = 6;
-const byte NUM_COLS = 8;
+const byte NUM_ROWS = 2;
+const byte NUM_COLS = 4;

 /*
  * Create an LedMarix object
@@ -36,15 +36,21 @@
 #else
 LedMatrix lm = LedMatrix(NUM_ROWS, NUM_COLS);
 #endif
+
 /*
  * Enter the text you want to scroll. Leave a few blank spaces
- * at the end for an easy way to scroll off the screen.
-*/
-char text[] = "Hello World!          ";
+ * at the end as an easy way to scroll off the screen.
+ * I used 4 different text strings to verify each of the 4
+ * functions used is working properly.
+ */
+char text1[] = "Hello World 1!          ";      // scrollText() 8x8 Font
+char text2[] = "Hello World 2!          ";      // scrollText() 5x7 Font
+char text3[] = "Hello World 3!          ";      // altScrollText() 8x8 Font
+char text4[] = "Hello World 4!          ";      // altScrollText() 5x7 Font

 void setup() {
    // No setup required. Some options you can set are
-   lm.scrollDelay(5);      // Sets the delay for scrolling text. 0 = fastest
+   lm.scrollDelay(20);     // Sets the delay for scrolling text. 0 = fastest
    lm.setIntensity(1);     // Sets the LED intensity. Default is 1.
    lm.setFont(FONT8x8);    // Sets the char font. Either FONT8x8 (default) or FONT5x7.
 }
@@ -63,23 +69,24 @@
  * the screen. The spaces between characters is already accounted for.
  */
 void scrollText() {
+
    lm.setFont(FONT8x8);
+
    // Loop through each character in the text[] array
-   for (int i = 0; i < sizeof(text)-1; i++) {
-
+   for (int i = 0; i < sizeof(text1)-1; i++) {
       /*
        * For each character, call the scrollChar() function.
        * scrollChar(char, row) has 2 arguements:
        *  - character to scroll
        *  - 8x8 dot matrix display row to scroll it on (first row = 0)
        */
-      lm.scrollChar(text[i], 0);
+      lm.scrollChar(text1[i], 0);
    }

-   // Second example using line 2 with 5x7 font
+   // Second example using line 2 with 5x7 font (if you have a 2nd row of 8x8 displays)
    lm.setFont(FONT5x7);
-   for (int i = 0; i < sizeof(text)-1; i++) {
-      lm.scrollChar(text[i], 1);
+   for (int i = 0; i < sizeof(text2)-1; i++) {
+      lm.scrollChar(text2[i], 1);
    }
 }

@@ -87,39 +94,39 @@
  * An alternate method of scrolling text using the dispChar() function.
  * Essentially this method works by writing the full string of text to
  * the display starting with it just off the right side of the screen.
- * It then redraws each character one column to the left until the entire
- * string has been displayed.
+ * It then redraws each character shifted one column to the left until
+ * the entire string has been displayed.
  *
  * This method is much slower, but allows you to scroll text at any Y position.
 */
-void altScrollText(){
-
+void altScrollText() {
    /*
-    Start drawing at the first x position off the display.
-    Stop drawing at the size of text string multiplied by the font width,
-    but in the negative.
+    Start drawing at the first x position off the right side of the display.
+    Stop drawing once the entire string has scrolled off the screen.
+    (-1 x string length x font width)
    */
+
+   // For some reason Arduino doesn't like -sizeof(), so we have to create a variable instead.
+   int strLength = sizeof(text3);
+
    lm.setFont(FONT8x8);
-   for (int x = NUM_COLS * 8; x >= -sizeof(text)*8; x--) {
-
-      lm.clear();       // Clear the led array of any previous data
-
-      for (int i = 0; i < sizeof(text)-1; i++) {   // Now draw each character in the string
-
+
+   for (int x = NUM_COLS * 8; x >= -strLength * 8; x--) {   // This loop determines where to start drawing chars
+      lm.clear();                                           // Clear the led array of any previous data
+      for (int i = 0; i < strLength-1; i++) {               // Next draw each character in the string
          /*
-          printChar() takes 3 parameters:
-           - Character to print
-           - X position (left)
-           - Y position (top)
+          printChar(c, x, y) takes 3 parameters:
+           - c = Character to print
+           - x = Left-most X position
+           - y = Top-most Y position
           The y position will always stay the same (unless you want to try something funky)
-          The x position of each character is determined by the starting x
-          position from the outer for loop plus the font width multiplied
-          by its location in the text array.
+          The x position of each character is determined by the starting x position
+          from the outer for() loop + the font width * its index in the text array.
          */
-         lm.printChar(text[i], x + (FONT8x8 * i), 0);
+         lm.printChar(text3[i], x + (FONT8x8 * i), 0);
       }
       lm.update();      // update() must be called to redraw the display
-      delay(2);         // This sets the scroll speed
+      delay(20);        // This sets the scroll speed
    }

    /*
@@ -128,15 +135,14 @@
     however, the 5x7 does not. If using the 5x7 font, you need to add
     one to the font width.
    */
+   strLength = sizeof(text4);
    lm.setFont(FONT5x7);
-   for (int x = NUM_COLS * 8; x >= -sizeof(text)*(FONT5x7 + 1); x--) {
+   for (int x = NUM_COLS * 8; x >= -strLength * (FONT5x7 + 1); x--) {
       lm.clear();
-      for (int i = 0; i < sizeof(text)-1; i++) {
-         lm.printChar(text[i], x + ((FONT5x7 + 1) * i), 8);
+      for (int i = 0; i < strLength-1; i++) {
+         lm.printChar(text4[i], x + ((FONT5x7 + 1) * i), 8);
       }
       lm.update();
-      delay(2);
+      delay(20);
    }
 }
-
-


Fixed issue that fan control did no longer work in case of sensor2 failure

--- cellar-climate-controller.ino
+++ cellar-climate-controller.ino
@@ -261,7 +261,7 @@
     lcd.setCursor(0, 0);
     lcd.print("***FanControl***");
     lcd.setCursor(0, 1);
-    lcd.print("***   2.04   ***");
+    lcd.print("***   2.05   ***");
     time = millis() - time;
     Serial.print("Took "); Serial.print(time); Serial.println(" ms");
     lcd.setBacklight(WHITE);
@@ -493,7 +493,7 @@
 void controlFan() {
     float absHumidityOutside;
     float tempOutside;
-    if (absHumidityOutside1 != ABS_HUMIDITY_ERROR && absHumidityOutside1 != ABS_HUMIDITY_ERROR) {
+    if (absHumidityOutside1 != ABS_HUMIDITY_ERROR && absHumidityOutside2 != ABS_HUMIDITY_ERROR) {
         if (absHumidityOutside1 > absHumidityOutside2) {
             absHumidityOutside = absHumidityOutside1;
             tempOutside = tempOutside1;


fix bogus commit

fix bogus commit

--- examples/multiple-read/multiple-read.ino
+++ examples/multiple-read/multiple-read.ino
@@ -87,6 +87,7 @@
         Index++;
         sendNewDP = true;
     }
+    if(Index > numberOfDPs){
       //reset when array has completely been handled
       doLoop = false;
     }


Fixed reset reason showing wrong reason.

--- loggertask.ino
+++ loggertask.ino
@@ -135,8 +135,9 @@

 const char * resetStr[] =
 {
-  "NO_MEAN",
+  "",
   "POWERON_RESET",
+  "",
   "SW_RESET",
   "OWDT_RESET",
   "DEEPSLEEP_RESET",


Alles werkt

Alles werkt

--- LightTrain.ino
+++ LightTrain.ino
@@ -3,25 +3,25 @@

 #include <Adafruit_NeoPixel.h>
 #ifdef __AVR__
-  #include <avr/power.h>
+#include <avr/power.h>
 #endif

-#define PIN            6
+#define PIN            4
 #define NUMPIXELS      10
 #define SENSOR_THRESHOLD 400

-#define IDLE_TIME 300*1000
+#define IDLE_TIME 15*1000
 #define WIT pixels.Color(255,255,255)
 #define UIT pixels.Color(0,0,0)

 #if (delayval >= 200)
-  #define KLEUR pixels.Color(0, 150, 0)
+#define KLEUR pixels.Color(0, 150, 0)
 #elif (delayval < 200)
-  #define KLEUR pixels.Color(200,144,0)
+#define KLEUR pixels.Color(200,144,0)
 #elif (delayval < 150)
-  #define KLEUR pixels.Color(200, 100, 0)
+#define KLEUR pixels.Color(200, 100, 0)
 #else
-  #define KLEUR pixels.Color(200, 0, 0)
+#define KLEUR pixels.Color(200, 0, 0)
 #endif

 // When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
@@ -35,6 +35,7 @@
 int laatste_trein;   // Aantal milliseconden sinds de laatste keer dat de trein langskwam.
 int aantal_leds;
 boolean trein_langs;
+

 void setup() {
   pixels.begin(); // This initializes the NeoPixel library.
@@ -55,20 +56,22 @@
   }
   aantal_leds = ms/delayval;
   if(trein_langs) {
-    laatste_trein = millis();
-    for(int i=0;i<NUMPIXELS;i++){
+    for(int i=0;i<NUMPIXELS+aantal_leds;i++){
       int achterste_led = i - aantal_leds;
       if(achterste_led >= 0) {
         pixels.setPixelColor(achterste_led, WIT);
       }
-      pixels.setPixelColor(i, KLEUR);
+      if (i < NUMPIXELS) {
+        pixels.setPixelColor(i, KLEUR);
+      }
       pixels.show();
       delay(delayval);
     }
     trein_langs = false;
     ms = 0;
+    laatste_trein = millis();
   }
-  if(millis() - laatste_trein > IDLE_TIME) {
+  if((millis() - laatste_trein) > IDLE_TIME) {
     // De trein is al lang niet langsgeweest, zet de lampjes uit
     for(int i=0;i<NUMPIXELS;i++){
       // Zet de lampjes uit


ATLEDGE-643: Add chip ID to SerialFlash example sketch

RawHardwareTest reports the 101's on-board SPI flash chip as an unknown
device. Fix this by adding the device's JEDEC ID to the example sketch.

--- libraries/SerialFlash/examples/RawHardwareTest/RawHardwareTest.ino
+++ libraries/SerialFlash/examples/RawHardwareTest/RawHardwareTest.ino
@@ -391,6 +391,7 @@
 		// Winbond
 		if (id[1] == 0x40) {
 			if (id[2] == 0x14) return "W25Q80BV";
+			if (id[2] == 0x15) return "W25Q16DV";
 			if (id[2] == 0x17) return "W25Q64FV";
 			if (id[2] == 0x18) return "W25Q128FV";
 			if (id[2] == 0x19) return "W25Q256FV";


Slightly opimized algorithm for another race. Stay bit more to the right and turn more aggressively. Lap time dropped from about 22s to about 18s.

--- maze_robot.ino
+++ maze_robot.ino
@@ -102,9 +102,9 @@
   debug_light_on = 1 - debug_light_on;
   digitalWrite(13, debug_light_on);

-  dist_f_reader.update();
-  dist_l_reader.update();
-  dist_r_reader.update();
+  // dist_f_reader.update();
+  // dist_l_reader.update();
+  // dist_r_reader.update();
   dist_f = analogRead(DIST_IN_F);
   dist_l = analogRead(DIST_IN_L);
   dist_r = analogRead(DIST_IN_R);
@@ -160,12 +160,12 @@
   {
     dir = 0;

-    more_space = dist_l - dist_r;
+    more_space = dist_l - dist_r * 0.8f;

     if (more_space > 0)
-      dir += map(more_space, 0, 300, 5, 120);
+      dir += map(more_space, 0, 300, 5, 180);
     else
-      dir += map(abs(more_space), 0, 300, 5, -120);
+      dir += map(abs(more_space), 0, 300, 5, -180);

     if (dir >= 0)
       dir_sign = 1;


Hold first button reset data to defaults


dx-dave: Fix to "out of scope" error

dx-dave: Fix to "out of scope" error

ERROR encountered validating nunchuck_basic_click:

Arduino: 1.6.7 (Mac OS X), Board: "LilyPad Arduino USB"

nunchuck_basic_click:14: error: 'c_update' was not declared in this scope
 WiiChuck nunchuck = WiiChuck(c_update, z_update);
                              ^
nunchuck_basic_click:14: error: 'z_update' was not declared in this scope
 WiiChuck nunchuck = WiiChuck(c_update, z_update);
                                        ^
exit status 1
'c_update' was not declared in this scope

  This report would have more information with
  "Show verbose output during compilation"
  enabled in File > Preferences.

--- examples/nunchuck_basic_click/nunchuck_basic_click.ino
+++ examples/nunchuck_basic_click/nunchuck_basic_click.ino
@@ -6,6 +6,9 @@
 #include <OSSex.h>
 #include <Wire.h>
 #include <WiiChuck.h>
+
+bool c_update();
+bool z_update();

 // Create the nunchuck object
 // c_update and z_update are the button update functions. OSSex/OneButton normally works


Configuration of connected lamps.

Configuration of connected lamps.

--- TestServer.ino
+++ TestServer.ino
@@ -17,6 +17,9 @@
 // Maximum number of devices connected to IO pins.
 #define MAX_DEVICES 8

+// Length of name strings. (hostname, room names, lamp names, etc.)
+#define NAME_LEN 32
+

 enum Io_Type {
   test,
@@ -26,14 +29,14 @@
 };

 typedef struct Connected_device {
-  char unique_id[32];
-  char room[32];
+  char name[NAME_LEN];
+  char room[NAME_LEN];
   Io_Type io_type;
   int io_pins[4];
 } Connected_device;

 struct Config {
-  char hostname[32];
+  char hostname[NAME_LEN];
   Connected_device devices[MAX_DEVICES];
   char config_version[4];
   // TODO: add WFI ssid and password.
@@ -48,11 +51,24 @@

+// Configuration
+void SetHostname(const char* new_hostname) {
+  strncpy(config.hostname, new_hostname, NAME_LEN);
+}
+
+void SetDevice(const unsigned int index, struct Connected_device device) {
+  if (index < MAX_DEVICES) {
+    memcpy(&(config.devices[index]), &device, sizeof(device));
+  }
+}
+
+
 // mDNS
-//extern String brokers[MAX_BROKERS][4];  // Array containing information about brokers received over mDNS.
 Brokers brokers(QUESTION_SERVICE);

-void answerCallback(const mdns::Answer* answer){ brokers.ParseMDnsAnswer(answer); }
+void answerCallback(const mdns::Answer* answer) {
+  brokers.ParseMDnsAnswer(answer);
+}
 mdns::MDns my_mdns(NULL, NULL, answerCallback);

@@ -126,6 +142,21 @@
   message += config.config_version;
   message += "\n";

+  for(int i = 0; i < MAX_DEVICES; ++i){
+    message += i;
+    message += "  ";
+    message += config.devices[i].name;
+    message += "  ";
+    message += config.devices[i].room;
+    message += "  ";
+    message += config.devices[i].io_type + "  ";
+    message += config.devices[i].io_pins[0] + ",";
+    message += config.devices[i].io_pins[1] + ",";
+    message += config.devices[i].io_pins[2] + ",";
+    message += config.devices[i].io_pins[3];
+    message += "\n";
+  }
+
   message += brokers.Summary();

   http_server.send(200, "text/plain", message);
@@ -133,9 +164,46 @@
 }

 void handleConfig() {
+  const unsigned int now = millis() / 1000;
+
   String message = "";
+
   if (http_server.hasArg("test_arg")) {
     message += "test_arg: " + http_server.arg("test_arg") + "\n";
+  }
+  if (http_server.hasArg("hostname")) {
+    char tmp_buffer[NAME_LEN];
+    http_server.arg("hostname").toCharArray(tmp_buffer, NAME_LEN);
+    SetHostname(tmp_buffer);
+    message += "hostname: " + http_server.arg("hostname") + "\n";
+  }
+  if (http_server.hasArg("device") and http_server.hasArg("name") and http_server.hasArg("room") and http_server.hasArg("io_type") and http_server.hasArg("io_pins")) {
+    unsigned int index = http_server.arg("device").toInt();
+    Connected_device device;
+    http_server.arg("name").toCharArray(device.name, NAME_LEN);
+    http_server.arg("room").toCharArray(device.room, NAME_LEN);
+    if (http_server.arg("io_type") == "test") {
+      device.io_type = Io_Type::test;
+    } else if (http_server.arg("io_type") == "rgb") {
+      device.io_type = Io_Type::rgb;
+    } else if (http_server.arg("io_type") == "pwm") {
+      device.io_type = Io_Type::pwm;
+    } else if (http_server.arg("io_type") == "onoff") {
+      device.io_type = Io_Type::onoff;
+    }
+    char tmp_buffer[NAME_LEN];
+    http_server.arg("io_pins").toCharArray(tmp_buffer, NAME_LEN);
+    char* pch = strtok (tmp_buffer, ",");
+    int i = 0;
+    while (pch != NULL and i < 4)
+    {
+      device.io_pins[i] = atoi(pch);
+      pch = strtok(NULL, ",");
+    }
+
+    SetDevice(index, device);
+
+    message += "device: " + http_server.arg("device") + "\n";
   }

   http_server.send(200, "text/plain", message);
@@ -215,5 +283,5 @@
   if (!mqtt_client.connected()) {
     Serial.println("MQTT disconnected.");
     mqtt_connect();
-  }
-}
+  }
+}


v5.2 Fix connection logic

v5.2 Fix connection logic

--- WeatherDisplay.ino
+++ WeatherDisplay.ino
@@ -139,14 +139,13 @@
     return;
   }

-  // Not sure why this is needed.  It works fine without it
-  // while (client.connected() && !client.available()) delay(1); //waits for data
+  while (client.connected() && !client.available()) delay(1); //waits for data

 #ifdef DEBUG
   Serial.println("Waiting for data");
 #endif

-  while (client.connected() && client.available()) { // While connected
+  while (client.connected() || client.available()) { //connected or data available
     char c = client.read(); // Gets byte from WIFI buffer
     result = result + c;
   }


COH-80: WIP

COH-80: WIP

--- Arduino/COHEAT2015/20160316-COHEAT-M1/COHEAT-M1/COHEAT-M1.ino
+++ Arduino/COHEAT2015/20160316-COHEAT-M1/COHEAT-M1/COHEAT-M1.ino
@@ -1157,8 +1157,8 @@
           if(!OTV0P2BASE::getPrimaryBuilding16ByteSecretKey(key))
             { OTV0P2BASE::serialPrintlnAndFlush(F("!TX key")); return(false); } // FAIL
           const OTRadioLink::SimpleSecureFrame32or0BodyTXBase::fixed32BTextSize12BNonce16BTagSimpleEnc_ptr_t e = OTAESGCM::fixed32BTextSize12BNonce16BTagSimpleEnc_DEFAULT_STATELESS;
-          // Note: hub must indicate which relay it is sendinf (reverse traffic) to.
-          setTXID(FHT8V.nvGetHC1(), FHT8V.nvGetHC2());
+          // Hub must indicate which relay it is sending (reverse traffic) to.
+          setTXID(q.getHC1(), q.getHC2());
           uint8_t sbuf[OTRadioLink::SecurableFrameHeader::maxSmallFrameSize];
           const uint8_t sbodylen = secureTXState.generateSecureOStyleFrameForTX(sbuf, sizeof(sbuf), OTRadioLink::FTS_RESERVED_Q, lenTXID, txbuf, bodylen, e, NULL, key);
           const bool success = (0 != sbodylen) && PrimaryRadio.sendRaw(sbuf+1, sbodylen-1);


HP and Speed control switches stick based on isLeftStickMode

--- padawan360_body/padawan360_body_mega_i2c_ino/padawan360_body_mega_i2c/padawan360_body_mega_i2c.ino
+++ padawan360_body/padawan360_body_mega_i2c_ino/padawan360_body_mega_i2c/padawan360_body_mega_i2c.ino
@@ -16,6 +16,9 @@
 so I wanted to be able to have something with parts that other builder's could easily track
 down and buy parts even at your local big box store.

+v2.0 Changes:
+- Makes left analog stick default drive control stick. Configurable between left or right stick via isLeftStickDrive
+
 Hardware:
 ***Arduino Mega 2560***
 USB Host Shield from circuits@home
@@ -51,14 +54,14 @@
 // Default drive speed at startup
 byte drivespeed = DRIVESPEED1;

-// Set isLeftStickDrive to true for driving  with the left stick
-// Set isLeftStickDrive to false for driving with the right stick (legacy and original configuration)
-boolean isLeftStickDrive = true;
-
 // the higher this number the faster the droid will spin in place, lower - easier to control.
 // Recommend beginner: 40 to 50, experienced: 50 $ up, I like 70
 // This may vary based on your drive system and power system
 const byte TURNSPEED = 70;
+
+// Set isLeftStickDrive to true for driving  with the left stick
+// Set isLeftStickDrive to false for driving with the right stick (legacy and original configuration)
+boolean isLeftStickDrive = true;

 // If using a speed controller for the dome, sets the top speed. You'll want to vary it potenitally
 // depending on your motor. My Pittman is really fast so I dial this down a ways from top speed.
@@ -142,6 +145,8 @@
 AnalogHatEnum throttleAxis;
 AnalogHatEnum turnAxis;
 AnalogHatEnum domeAxis;
+ButtonEnum speedSelectButton;
+ButtonEnum hpLightToggleButton;

 // this is legacy right now. The rest of the sketch isn't set to send any of this
@@ -203,10 +208,15 @@
     throttleAxis = LeftHatY;
     turnAxis = LeftHatX;
     domeAxis = RightHatX;
+    speedSelectButton = L3;
+    hpLightToggleButton = R3;
+
   } else {
     throttleAxis = RightHatY;
     turnAxis = RightHatX;
     domeAxis = LeftHatX;
+    speedSelectButton = R3;
+    hpLightToggleButton = L3;
   }

@@ -470,8 +480,9 @@
     }
   }

-  // turn hp light on & off with Left Analog Stick Press (L3)
-  if (Xbox.getButtonClick(L3, 0))  {
+  // turn hp light on & off with Right Analog Stick Press (R3) for left stick drive mode
+  // turn hp light on & off with Left Analog Stick Press (L3) for right stick drive mode
+  if (Xbox.getButtonClick(hpLightToggleButton, 0))  {
     // if hp light is on, turn it off
     if (isHPOn) {
       isHPOn = false;
@@ -487,10 +498,11 @@
   }

-  // Change drivespeed if drive is eabled
-  // Press Right Analog Stick (R3)
+  // Change drivespeed if drive is enabled
+  // Press Left Analog Stick (L3) for left stick drive mode
+  // Press Right Analog Stick (R3) for right stick drive mode
   // Set LEDs for speed - 1 LED, Low. 2 LED - Med. 3 LED High
-  if (Xbox.getButtonClick(R3, 0) && isDriveEnabled) {
+  if (Xbox.getButtonClick(speedSelectButton, 0) && isDriveEnabled) {
     //if in lowest speed
     if (drivespeed == DRIVESPEED1) {
       //change to medium speed and play sound 3-tone


working on dim mode

working on dim mode

--- 03_Illuminar.ino
+++ 03_Illuminar.ino
@@ -4,21 +4,27 @@
 float irSensorVal=0;

 int irDelta=100;
-int irBase=20;
-int irMax=230;
+int irBase=25;
+int irMax=200;

 int t1=0;
 int t2=0;

 int state=0; // 0= off, 1 = on
+int handposition=0; // 0 = off, 1 = on
+
+int dimMode=0;
+int minDim=5;
+int maxDim=255;
+int dimVal=200;
 int readyForChange=1;

 int pwmOut=9;

 unsigned long lastTime;
-int timeDelta=50;
+int timeDelta=500;

 void switchState(){
@@ -45,6 +51,10 @@
     irSensorVal = irSensorVal*10;

     irSensorVal = map(irSensorVal, irBase, irMax, 0, 1000);
+
+    if(irSensorVal > 1000){
+      irSensorVal = 1000;
+    }

 }

@@ -69,29 +79,58 @@

   unsigned long thisTime= millis();

-  if( thisTime >= lastTime + timeDelta){
-    Serial.print(thisTime);
-    Serial.println("BINGO");
-
-    lastTime=thisTime;
-
-  }
+  //if( thisTime >= lastTime + timeDelta){
+   // Serial.print(thisTime);
+   // Serial.println("BINGO");
+   // lastTime=thisTime;
+  //}

   readIR();

   if( irSensorVal >= (t1 + irDelta) ){
-    switchState();
-  }
-
-  if(irSensorVal <  (t1 + irDelta) ){
-     readyForChange=1;
+    //switchState();
+    if(handposition == 0){
+      lastTime=thisTime;
+      handposition=1;
+    }else if(handposition == 1){
+      if(thisTime >= lastTime + timeDelta){
+        if(dimMode == 0){
+          dimMode=1;
+        }
+      }
+    }
+  }else if(irSensorVal <  (t1 + irDelta) ){
+    if(thisTime < lastTime + timeDelta){
+      if(handposition == 1){
+        if(state == 0 ){
+          state = 1;
+        }else{
+          state = 0;
+        }
+      }
+    }
+      handposition=0;
+      dimMode=0;
   }

+
+if(dimMode==1){
+  dimVal= map(irSensorVal, 0, 1000, 0, 255);
+  if(dimVal < minDim){
+    dimVal = minDim;
+  }
+
+  if(dimVal > maxDim){
+    dimVal = maxDim;
+  }
+
+}
+

   if(state == 1){
-    analogWrite(pwmOut,200);  // analogRead values go from 0 to 1023, analogWrite values from 0 to 255
+    analogWrite(pwmOut,dimVal);  // analogRead values go from 0 to 1023, analogWrite values from 0 to 255
   }else if(state == 0){
     analogWrite(pwmOut,0);  // analogRead values go from 0 to 1023, analogWrite values from 0 to 255

@@ -100,7 +139,9 @@

    Serial.print("STATE: ");
    Serial.print(state);
-
+
+   Serial.print("   HAND: ");
+   Serial.print(handposition);

   Serial.print("   IR Val:");


remove trailing spaces

remove trailing spaces

--- ArduBreakout.ino
+++ ArduBreakout.ino
@@ -2,7 +2,7 @@
   Breakout
  Copyright (C) 2011 Sebastian Goscik
  All rights reserved.
-
+
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
@@ -111,10 +111,10 @@
   if(xPaddle > 0)
   {
     if( !digitalRead(9))
-    {
+    {
       xPaddle--;
     }
-  }
+  }
 }

 void moveBall()
@@ -144,7 +144,7 @@
     {
       display.drawRect(xPaddle, 63, 11, 1, 0);
       xPaddle = 54;
-      yb=60;
+      yb=60;
       released = false;
       lives--;
       drawLives();
@@ -152,7 +152,7 @@
       if (random(0, 2) == 0)
       {
         dx = 1;
-      }
+      }
       else
       {
         dx = -1;
@@ -215,7 +215,7 @@
                 yb += dy;
                 bounced = true;
                 tone(A2, 261, 250);
-              }
+              }
             }

             //Hoizontal collision
@@ -228,7 +228,7 @@
                 xb += dx;
                 bounced = true;
                 tone(A2, 261, 250);
-              }
+              }
             }
           }
         }
@@ -245,22 +245,22 @@
     //Release ball if FIRE pressed
     pad3 = !digitalRead(A0);
     if (pad3 == 1 && oldpad3 == 0)
-    {
+    {
       released=true;

       //Apply random direction to ball on release
       if (random(0, 2) == 0)
       {
         dx = 1;
-      }
+      }
       else
       {
         dx = -1;
       }
-      //Makes sure the ball heads upwards
+      //Makes sure the ball heads upwards
       dy = -1;
     }
-    oldpad3 = pad3;
+    oldpad3 = pad3;
   }
 }

@@ -331,7 +331,7 @@

         paused=false;
     }
-    oldpad2=pad2;
+    oldpad2=pad2;
   }
 }

@@ -340,7 +340,7 @@
   score += (level*10);
   sprintf(text, "SCORE:%u", score);
   display.setCursor(80, 90);
-  display.print(text);
+  display.print(text);
 }

 void newLevel(){
@@ -367,14 +367,14 @@
       display.drawRect(10*column, 2+6*row, 8, 4, 1);
     }
   }
-
+
   //Draws the initial lives
   drawLives();
-
+
   //Draws the initial score
   sprintf(text, "SCORE:%u", score);
   display.setCursor(80, 90);
-  display.print(text);
+  display.print(text);
 }

 //Used to delay images while reading button input
@@ -438,7 +438,7 @@
       display.display();
     }
   }
-  if (pollFireButton(300))
+  if (pollFireButton(300))
   {
     return true;
   }
@@ -502,7 +502,7 @@
   initials[1] = ' ';
   initials[2] = ' ';

-  while (true)
+  while (true)
   {
     display.display();
     display.clearDisplay();
@@ -621,7 +621,7 @@
     lo = EEPROM.read(address + (5*i) + 1);
     if ((hi == 0xFF) && (lo == 0xFF))
     {
-      // The values are uninitialized, so treat this entry
+      // The values are uninitialized, so treat this entry
       // as a score of 0.
       tmpScore = 0;
     } else
@@ -639,7 +639,7 @@
         if ((hi == 0xFF) && (lo == 0xFF))
         {
         tmpScore = 0;
-        }
+        }
         else
         {
           tmpScore = (hi << 8) | lo;
@@ -676,7 +676,7 @@

-void loop()
+void loop()
 {
   display.display();

@@ -694,7 +694,7 @@
   //Initial level draw
   if (!initialDraw)
   {
-    //Clears the screen
+    //Clears the screen
     display.display();
     display.clearDisplay();
     //Selects Font
@@ -722,13 +722,13 @@
     if(brickCount==60)
     {
       level++;
-      newLevel();
+      newLevel();
     }
   }
   else
   {
     drawGameOver();
-    if (score > 0)
+    if (score > 0)
     {
       enterHighScore(2);
     }


working simple demo

working simple demo

--- simple_bt_demo/simple_bt_demo.ino
+++ simple_bt_demo/simple_bt_demo.ino
@@ -12,6 +12,8 @@
 // Must include both SoftwareSerial and Bluetooth.h
 #include <SoftwareSerial.h>
 #include "Bluetooth.h"
+
+#define BAUD_RATE 9600

 /*
  * BLUETOOTH
@@ -43,8 +45,6 @@
         {
             r = bt.spp.read();

-            bt.spp.print(r);
-
             if (r == 'i')
             {
                 count++;
@@ -57,6 +57,8 @@
             bt.spp.print("count : ");
             bt.spp.print(count);
             bt.spp.print("\r\n");
+
+            bt.spp.flush();
         }
     }
 }


new inner loop

new inner loop

--- leonardo/leo595/leo595.ino
+++ leonardo/leo595/leo595.ino
@@ -20,6 +20,10 @@
 #define MYDELAY 500

 void clockout(uint8_t);
+void update_values();
+
+uint8_t leds[8];
+unsigned long mil;

 /* pin11 goes to 595 pin 11 */
 #define SHIFTCLOCK 11
@@ -29,15 +33,75 @@
 #define STROBEPIN 12

 void setup(void) {
+  uint8_t i;
   pinMode(SERDATAIN, OUTPUT);
   pinMode(SHIFTCLOCK, OUTPUT);
   pinMode(STROBEPIN, OUTPUT);
   pinMode(13, OUTPUT);
+
+  for(i=0;i<8;i++) {
+     leds[i] = i;
+  }
+
   return;
 }

 void loop(void) {
+  uint8_t current_byte;
+  // loop 256 times with wrap
+  for (uint8_t outer=1;outer!=0;outer++) {
+    current_byte=0;
+    for (uint8_t inner=0;inner < 8;inner++) {
+      if (leds[inner] >= outer) {
+        current_byte |= _BV(inner);
+      } else {
+        current_byte &= ~_BV(inner);
+      } /* if leds are to show */
+    }   /* inner 8 values to compare */
+    clockout(current_byte);
+  }     /* outer loop for 256 values */
+  mil=millis();
+  update_values();
+}
+
+void update_led1() {
+  // leds[0]
+}
+void update_led2() {
+  // leds[1]
+}
+void update_led3() {
+  // leds[2]
+}
+void update_led4() {
+  leds[3]++;
+}
+void update_led5() {
+  // leds[4];
+}
+void update_led6() {
+}
+void update_led7() {
+   if ((mil % 20) == 0) leds[5]--;
+}
+void update_led8() {
+   if ((mil % 20) == 0) leds[4]++;
+}
+
+void
+update_values() {
+  update_led1();
+  update_led2();
+  update_led3();
+  update_led4();
+  update_led5();
+  update_led6();
+  update_led7();
+  update_led8();
+}
+
+void unused(void) {
   uint8_t value = 0, overall = 0;
   unsigned long now;

@@ -81,11 +145,6 @@

   return;
 }
-/* SAMPLE
-clockout(255);
-digitalWrite(13,HIGH);
-delay(1000);
-*/

 void clockout(uint8_t data) {
   uint8_t loop, pin = 1;


Use only the configured pins

Use only the configured pins

--- src/Full_decoder/Full_decoder.ino
+++ src/Full_decoder/Full_decoder.ino
@@ -31,6 +31,7 @@

 #define MAX 24
 ConfiguredPin* confpins[MAX];
+uint8_t pins_conf = 0;

 #include "Adafruit_TLC5947.h"

@@ -151,8 +152,8 @@
   uint8_t i = 0;
   DEBUG("Max # of pins:");
   DEBUGLN(MAX);
-
-  for (i = 0; i < MAX; i++) {
+  pins_conf = eeprom_read_byte((uint8_t*)&(_CV.pins_conf));
+  for (i = 0; i < pins_conf; i++) {
     configureSlot(i);
   }
   programmingMode = false;
@@ -160,7 +161,7 @@

 void loop() {
 	pins_busy = false;
-  for (uint8_t i =0 ; i < MAX ; i++) {
+  for (uint8_t i =0 ; i < pins_conf ; i++) {
 	 confpins[i]->update();
   };


minor changes

minor changes

--- crossbow.ino
+++ crossbow.ino
@@ -9,7 +9,7 @@
 #include <PPMReader.h>

 #define PPM_INPUT_PIN       2
-#define PPM_INPUT_INTERRUPT 0
+#define PPM_INPUT_INTERRUPT 1 //For Pro Micro 1, For Pro Mini 0

 PPMReader ppmReader(PPM_INPUT_PIN, PPM_INPUT_INTERRUPT);

@@ -173,6 +173,12 @@
     return 8 - get10bitHighShift(channel);
 }

+void clearQspPayload() {
+    for (uint8_t i = 0; i < QSP_PAYLOAD_LENGTH; i++) {
+        qspPayload[i] = 0;
+    }
+}
+
 #endif

 void loop(void) {
@@ -187,9 +193,7 @@
         uint8_t payloadBit = 0;
         uint8_t bitsToMove = 0;

-        for (uint8_t i = 0; i < QSP_PAYLOAD_LENGTH; i++) {
-            qspPayload[i] = 0;
-        }
+        clearQspPayload();

         for (uint8_t i = 0; i < PPM_CHANNEL_COUNT; i++) {
             uint16_t channelValue10 = map(ppmReader.get(i), 1000, 2000, 0, 1000) & 0x03ff;


Example: Quad to SD: improve comments

Example: Quad to SD: improve comments

--- examples/AIC_Shield/SerialControlledSDWriter_Quad/SerialControlledSDWriter_Quad.ino
+++ examples/AIC_Shield/SerialControlledSDWriter_Quad/SerialControlledSDWriter_Quad.ino
@@ -3,7 +3,9 @@

    Created: Chip Audette, OpenAudio, May 2019
    Purpose: Write 4 channels of audio to SD based on serial commands
-      via USB serial or via BT serial
+      via USB serial or via BT serial.
+
+	  Writes to a single 4-channel WAV file.  Can be opened in Audacity.

    MIT License.  use at your own risk.
 */


SerialControlledSDWriter_Quad: use AICShield class

--- examples/AIC_Shield/SerialControlledSDWriter_Quad/SerialControlledSDWriter_Quad.ino
+++ examples/AIC_Shield/SerialControlledSDWriter_Quad/SerialControlledSDWriter_Quad.ino
@@ -38,12 +38,9 @@

 // /////////// Define audio objects...they are configured later

-#define AIC_RESET_PIN 20   //for I2C connection to AIC shield (eventually move into Tympan library)
-#define AIC_I2C_BUS 2     //for I2C connection to AIC shield (eventually move into Tympan library)
-
 // define classes to control the Tympan and the AIC_Shield
 Tympan                        myTympan(TympanRev::D);    //note: Rev C is not compatible with the AIC shield
-AudioControlAIC3206           aicShield(AIC_RESET_PIN,AIC_I2C_BUS);  //for AIC_Shield
+AICShield                     aicShield(TympanRev::D, AICShieldRev::A);  //for AIC_Shield
 AudioInputI2SQuad_F32         i2s_in(audio_settings);   //Digital audio input from the ADC
 AudioSDWriter_F32             audioSDWriter(audio_settings); //this is stereo by default
 AudioOutputI2SQuad_F32        i2s_out(audio_settings);  //Digital audio output to the DAC.  Should always be last.


Tidied up actuator presentation

Tidied up actuator presentation

--- ardesp/waterelfactuator/waterelfactuator.ino
+++ ardesp/waterelfactuator/waterelfactuator.ino
@@ -47,9 +47,9 @@
   "
Wifi status
\n"
   "
\n"
     "<form method='POST' action='actuate'>\n"
-    "Actuator: "
-    "on <input type='radio' name='state' value='on' checked>\n"
-    "off <input type='radio' name='state' value='off'>\n"
+    "Operate actuator: "
+    "on <input type='radio' name='state' value='on'>\n"
+    "off <input type='radio' name='state' value='off' checked>\n"
     "<input type='submit' value='Submit'></form>
\n"
   "
\n"
   "

\n"
@@ -374,7 +374,7 @@
     }
   }

-  // TODO trigger the 433 transmitter
+  // now we trigger the 433 transmitter
   if(newState == true){
     mySwitch.switchOn(4, 2);
   } else {


Overhaul Arduino sketch - Add ability to use receiver input - Add ability to calibrate receiver input - Add ability to use cutover to switch between phone and receiver

--- arduino/arduino_sketch/arduino_sketch.ino
+++ arduino/arduino_sketch/arduino_sketch.ino
@@ -1,32 +1,64 @@
 //Created by Ryan Staatz
+//For RC receiver background, see: http://rcarduino.blogspot.com/2013/04/problem-reading-rc-channels-rcarduino.html

 //Arduino JSON library: https://github.com/bblanchon/ArduinoJson
 #include <ArduinoJson.h>
+//PinChangeInt library: http://playground.arduino.cc/Main/PinChangeInt
+#include <PinChangeInt.h>
 #include <Servo.h>
+
+//Pulse threshold values for receiver input for cutover between auto and manual control
+const byte CUTOVER_BUFFER = 150;
+
+//Byte flags used to store whether there is an update from a given input
+const byte FLAG_AILERON = 1;
+const byte FLAG_ELEVATOR = 2;
+const byte FLAG_RUDDER = 4;
+const byte FLAG_THROTTLE = 8;
+const byte FLAG_CUTOVER = 16;
+
+//Min and max values for the Servo.write() function
+const byte SERVO_MIN = 0;
+const byte SERVO_MAX = 180;
+
+//Sets the max char array size for JSON serial input and output
+const int CHAR_ARRAY_SIZE = 300;
+
+//Default servo input value
+//TODO use better calibration default
+const int RECEIVER_INPUT_DEFAULT = 1500;
+
+//Min and max possible values to filter for receiver servo input
+const int RECEIVER_INPUT_MAX = 2300;
+const int RECEIVER_INPUT_MIN = 700;

 //Sets the baud rate of the Arduino
 const long BAUD_RATE = 115200;

-//Receiver input timeout in microseconds
-const int PULSE_TIMEOUT = 44100;
-
-//Pulse threshold values for receiver input for cutover between auto and manual control
-const int CUTOVER_MIN = 900;
-const int CUTOVER_MAX = 1500;
-
-//Pulse threshold values for receiver input for servos and motor
-const int RECEIVER_MIN = 750;
-const int RECEIVER_MAX = 1800;
-
-//Sets the character array (max) length for serial input
-const int numChars = 300;
-
-//This array stores Json characters read from serial input
-char receivedJson[numChars];
-
-//All valid input/output must start/end with the corresponding char
-char startMarker = '@';
-char endMarker = '#';
+//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;
+
+//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
+volatile uint16_t aileronInValue;
+volatile uint16_t cutoverInValue;
+volatile uint16_t elevatorInValue;
+volatile uint16_t rudderInValue;
+volatile uint16_t throttleInValue;
+
+//Stores the pin number for each receiver input
+int aileronInPin = -1;
+int cutoverInPin = -1;
+int elevatorInPin = -1;
+int rudderInPin = -1;
+int throttleInPin = -1;
+
+//Determines if the servos are in the process of calibration
+boolean calibrationMode = false;
+
+//Determines if the calibration procedure has been performed
+boolean isCalibrated = false;

 //Determines if new Json data has been collected from serial input for processing
 boolean newData = false;
@@ -34,17 +66,26 @@
 //Determines if the plane is controlled manually (remote control) or via autopilot (phone)
 boolean manualControl = false;

-//Determines if the cutover pin can use interrupts
-boolean cutoverInterrupt = false;
-
-//Stores the pin value for each receiver input
-int aileronIn = -1;
-int elevatorIn = -1;
-int rudderIn = -1;
-int throttleIn = -1;
-int cutoverIn = -1;
-
-//Servos (including the motor)
+//All valid input/output must start/end with the corresponding chars below
+char endMarker = '#';
+char startMarker = '@';
+
+//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 aileronMax = RECEIVER_INPUT_DEFAULT;
+uint16_t aileronMin = RECEIVER_INPUT_DEFAULT;
+uint16_t cutoverMax = RECEIVER_INPUT_DEFAULT;
+uint16_t cutoverMin = RECEIVER_INPUT_DEFAULT;
+uint16_t elevatorMax = RECEIVER_INPUT_DEFAULT;
+uint16_t elevatorMin = RECEIVER_INPUT_DEFAULT;
+uint16_t rudderMax = RECEIVER_INPUT_DEFAULT;
+uint16_t rudderMin = RECEIVER_INPUT_DEFAULT;
+uint16_t throttleMax = RECEIVER_INPUT_DEFAULT;
+uint16_t throttleMin = RECEIVER_INPUT_DEFAULT;
+
+//Servos
 Servo aileron;
 Servo elevator;
 Servo rudder;
@@ -53,18 +94,18 @@
 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 Arduino is ready
+  sendJson("status", "ready");  //Inform serial interface that the Arduino is ready
 }

 void loop() {
-  readSerialJsonText();
-  processJsonText();
-  readReceiverInput();
+  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
-void readSerialJsonText() {
+void readSerialJsonInput() {
   static boolean receiveInProgress = false;  //Determines if a char received via serial input belongs to the current json input char array
   static int index = 0;  //Index for storing the most recently received serial input in the correct place in the input char array
   char charIn;  //Char being currently read from serial input
@@ -77,8 +118,8 @@
       if (charIn != endMarker) {
         receivedJson[index] = charIn;
         index++;
-        if (index >= numChars) {
-          index = numChars - 1;
+        if (index >= CHAR_ARRAY_SIZE) {
+          index = CHAR_ARRAY_SIZE - 1;
           sendJson("error", "Serial buffer overflow");
         }
       }
@@ -96,11 +137,11 @@
 }

 //Example JSON strings below:
-//@{"manualControl":false, "config":{"throttle":10, "elevator":9, "aileron":8, "rudder":7, "aileronIn":6, "elevatorIn":5, "rudderIn":4, "throttleIn":3, "cutoverIn":2, "cutoverInterrupt":true}, "throttle":120, "elevator":100, "aileron":90, "rudder":75}#
-//@{"aileron": 90}#
-void processJsonText() {
-  if (newData == true) {
-    StaticJsonBuffer<numChars> jsonBuffer;
+//@{"config":{"throttle":10, "elevator":9, "rudder":8, "aileron":7, "aileronIn":6, "throttleIn":5, "elevatorIn":4, "rudderIn":3, "cutoverIn":2}, "throttle": 32, "elevator": 90, "rudder": 90, "aileron": 90}#
+//@{"throttle":0, "elevator":100, "aileron":120, "rudder":75}#
+void processReceivedJson() {
+  if (newData) {
+    StaticJsonBuffer<CHAR_ARRAY_SIZE> jsonBuffer;
     JsonObject& root = jsonBuffer.parseObject(receivedJson);

     //If the JSON object failed to parse, inform the serial interface and return
@@ -118,186 +159,233 @@

     //Enable or disable manual control
     if (root.containsKey("manualControl")) {
-      manualControl = (boolean) root["manualControl"];
-      if (manualControl) {
-        sendJson("manualControl", true);
+      if (isCalibrated) {
+        manualControl = (boolean) root["manualControl"];
+        sendJson("manualControl", manualControl);
       } else {
-        sendJson("manualControl", false);
+        sendJson("error", "Receiver inputs require calibration");
+      }
+    }
+
+    //Enable or disable calibration mode
+    if (root.containsKey("calibrationMode")) {
+      calibrationMode = (boolean) root["calibrationMode"];
+      sendJson("calibrationMode", calibrationMode);
+      if (calibrationMode) {
+        resetCalibration();
+        isCalibrated = false;
+      } else {
+        if (calibrationComplete()) isCalibrated = true;
+        sendCalibrationJsonData();
       }
     }

     //Assigns pin numbers to the motor, servos, and receiver inputs based on the received JSON
     if (root.containsKey("config")) {
-      JsonObject& config = root["config"];
-      if (config.containsKey("aileron")) {
-        int aileronPin = (int) config["aileron"];
-        aileron.attach(aileronPin);
-      }
-      if (config.containsKey("elevator")) {
-        int elevatorPin = (int) config["elevator"];
-        elevator.attach(elevatorPin);
-      }
-      if (config.containsKey("rudder")) {
-        int rudderPin = (int) config["rudder"];
-        rudder.attach(rudderPin);
-      }
-      if (config.containsKey("throttle")) {
-        int throttlePin = (int) config["throttle"];
-        throttle.attach(throttlePin);
-      }
-      if (config.containsKey("aileronIn")) {
-        aileronIn = (int) config["aileronIn"];
-        pinMode(aileronIn, INPUT);
-      }
-      if (config.containsKey("elevatorIn")) {
-        elevatorIn = (int) config["elevatorIn"];
-        pinMode(elevatorIn, INPUT);
-      }
-      if (config.containsKey("rudderIn")) {
-        rudderIn = (int) config["rudderIn"];
-        pinMode(rudderIn, INPUT);
-      }
-      if (config.containsKey("throttleIn")) {
-        throttleIn = (int) config["throttleIn"];
-        pinMode(throttleIn, INPUT);
-      }
-      if (config.containsKey("cutoverIn")) {
-        cutoverIn = (int) config["cutoverIn"];
-        pinMode(cutoverIn, INPUT);
-      }
-      //Configures an interrupt service routine for listening for the cutover signal from the receiver
-      if (config.containsKey("cutoverInterrupt")) {
-        if (cutoverIn != -1) {
-          cutoverInterrupt = (boolean) config["cutoverInterrupt"];
-          attachInterrupt(digitalPinToInterrupt(cutoverIn), listenForCutover, CHANGE);
-        } else {
-          sendJson("error", "Unassigned cutover pin");
-        }
-      }
-    }
-
-    //If autopilot is enabled, set the servo values according to the received JSON
-    if (!manualControl) {
-      if (root.containsKey("aileron")) {
-        if (aileron.attached()) {
-          int aileronValue = root["aileron"];
-          aileron.write(aileronValue);
-          sendJson("aileron", aileronValue);
-        } else {
-          sendJson("error", "Unassigned aileron pin");
-        }
-      }
-
-      if (root.containsKey("elevator")) {
-        if (elevator.attached()) {
-          int elevatorValue = root["elevator"];
-          elevator.write(elevatorValue);
-          sendJson("elevator", elevatorValue);
-        } else {
-          sendJson("error", "Unassigned elevator pin");
-        }
-      }
-
-      if (root.containsKey("rudder")) {
-        if (rudder.attached()) {
-          int rudderValue = root["rudder"];
-          rudder.write(rudderValue);
-          sendJson("rudder", rudderValue);
-        } else {
-          sendJson("error", "Unassigned rudder pin");
-        }
-      }
-
-      if (root.containsKey("throttle")) {
-        if (throttle.attached()) {
-          int throttleValue = root["throttle"];
-          throttle.write(throttleValue);
-          sendJson("throttle", throttleValue);
-        } else {
-          sendJson("error", "Unassigned throttle pin");
-        }
-      }
-    }
+      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 != -1) PCintPort::detachInterrupt(aileronInPin);
+          aileronInPin = (int) config["aileronIn"];
+          PCintPort::attachInterrupt(aileronInPin, listenForAileron, CHANGE);
+        }
+        if (config.containsKey("cutoverIn")) {
+          if (cutoverInPin != -1) PCintPort::detachInterrupt(cutoverInPin);
+          cutoverInPin = (int) config["cutoverIn"];
+          PCintPort::attachInterrupt(cutoverInPin, listenForCutover, CHANGE);
+        }
+        if (config.containsKey("elevatorIn")) {
+          if (elevatorInPin != -1) PCintPort::detachInterrupt(elevatorInPin);
+          elevatorInPin = (int) config["elevatorIn"];
+          PCintPort::attachInterrupt(elevatorInPin, listenForElevator, CHANGE);
+        }
+        if (config.containsKey("rudderIn")) {
+          if (rudderInPin != -1) PCintPort::detachInterrupt(rudderInPin);
+          rudderInPin = (int) config["rudderIn"];
+          PCintPort::attachInterrupt(rudderInPin, listenForRudder, CHANGE);
+        }
+        if (config.containsKey("throttleIn")) {
+          if (throttleInPin != -1) PCintPort::detachInterrupt(throttleInPin);
+          throttleInPin = (int) config["throttleIn"];
+          PCintPort::attachInterrupt(throttleInPin, listenForThrottle, CHANGE);
+        }
+      } else {
+        sendJson("error", "Manual control must be disabled to configure servos");
+      }
+    }
+
+    //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 = root["aileron"];
+            aileron.write(aileronValue);
+            sendJson("aileron", aileronValue);
+          } else {
+            sendJson("error", "Unassigned aileron pin");
+          }
+        }
+        if (servos.containsKey("elevator")) {
+          if (elevator.attached()) {
+            byte elevatorValue = root["elevator"];
+            elevator.write(elevatorValue);
+            sendJson("elevator", elevatorValue);
+          } else {
+            sendJson("error", "Unassigned elevator pin");
+          }
+        }
+        if (servos.containsKey("rudder")) {
+          if (rudder.attached()) {
+            byte rudderValue = root["rudder"];
+            rudder.write(rudderValue);
+            sendJson("rudder", rudderValue);
+          } else {
+            sendJson("error", "Unassigned rudder pin");
+          }
+        }
+        if (servos.containsKey("throttle")) {
+          if (throttle.attached()) {
+            byte throttleValue = root["throttle"];
+            throttle.write(throttleValue);
+            sendJson("throttle", throttleValue);
+          } else {
+            sendJson("error", "Unassigned throttle pin");
+          }
+        }
+      } else {
+        sendJson("error", "Manual control must be disabled to use servos");
+      }
+    }
+    //Reset newData to false so we can read new serial input
     newData = false;
   }
 }

-//TODO prevent process from hanging if receiver is out of range and no interrupt is in place
-//Listens for cutover input to switch between manual (receiver) and autopilot (phone) mode
-void listenForCutover() {
-  if (cutoverIn != -1) {
-    long pulse = pulseIn(cutoverIn, HIGH, PULSE_TIMEOUT);
-    if (pulse != 0) {
-      if (pulse < CUTOVER_MIN) {
-        manualControl = false;
-        sendJson("manualControl", false);
-      } else if (pulse > CUTOVER_MAX) {
-        manualControl = true;
-        sendJson("manualControl", true);
-      }
-    }
-  }
-}
-
-//Reads receiver input and writes translated values to servos
-void readReceiverInput() {
-  if (!cutoverInterrupt) listenForCutover();  //If there is no cutover interrupt already running, listen for cutover without an interrupt
-  //Only read servo inputs if manual control is enabled
-  if (manualControl) {
-    if (throttle.attached()) {
-      if (throttleIn != -1) {
-        long pulse = pulseIn(throttleIn, HIGH, PULSE_TIMEOUT);
-        if (pulse != 0) {
-          int servoPosition = constrain(map(pulse, RECEIVER_MIN, RECEIVER_MAX, 0, 180), 0, 180);
-          throttle.write(servoPosition);
-          sendJson("rudder", servoPosition);         }
+//Processes input from the receiver
+void processReceiverInput() {
+  //Static variables are used because they maintain their value over multiple function calls
+  static byte servoInputFlagsLocal;
+  static uint16_t aileronInValueLocal;
+  static uint16_t elevatorInValueLocal;
+  static uint16_t rudderInValueLocal;
+  static uint16_t throttleInValueLocal;
+  static uint16_t cutoverInValueLocal;
+
+  //If any servo input byte flags were set in any of the ISR methods, process them here
+  if (servoInputFlags != 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;
+    interrupts();
+  }
+  //If the cutover switch is flipped, set manualControl accordingly
+  if (servoInputFlagsLocal & FLAG_CUTOVER) {
+    //Only use cutover values within the set range for receiver input
+    if (isValidReceiverInput(cutoverInValueLocal)) {
+      if (calibrationMode) {
+        if (cutoverInValueLocal > cutoverMax) cutoverMax = cutoverInValueLocal;
+        if (cutoverInValueLocal < cutoverMin) cutoverMin = cutoverInValueLocal;
+      } else if (isCalibrated) {
+        if (manualControl && cutoverInValueLocal > (cutoverMax - CUTOVER_BUFFER)) {
+          manualControl = false;
+          sendJson("manualControl", manualControl);
+        } else if (!manualControl && cutoverInValueLocal < (cutoverMin + CUTOVER_BUFFER)) {
+          manualControl = true;
+          sendJson("manualControl", manualControl);
+        }
       }
     } else {
-      sendJson("error", "Unassigned throttle pin");
-    }
-
-    if (elevator.attached()) {
-      if (elevatorIn != -1) {
-        long pulse = pulseIn(elevatorIn, HIGH, PULSE_TIMEOUT);
-        if (pulse != 0) {
-          int servoPosition = constrain(map(pulse, RECEIVER_MIN, RECEIVER_MAX, 0, 180), 0, 180);
-          elevator.write(servoPosition);
-          sendJson("rudder", servoPosition);         }
+      sendJson("error", "Cutover input value out of range");
+    }
+  }
+  //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 > aileronMax) aileronMax = aileronInValueLocal;
+        if (aileronInValueLocal < aileronMin) aileronMin = aileronInValueLocal;
+      } else if (manualControl) {
+        processServoInput(aileron, aileronInValueLocal, "aileron", "Unassigned aileron pin");
       }
     } else {
-      sendJson("error", "Unassigned elevator pin");
-    }
-
-    if (aileron.attached()) {
-      if (aileronIn != -1) {
-        long pulse = pulseIn(aileronIn, HIGH, PULSE_TIMEOUT);
-        if (pulse != 0) {
-          int servoPosition = constrain(map(pulse, RECEIVER_MIN, RECEIVER_MAX, 0, 180), 0, 180);
-          aileron.write(servoPosition);
-          sendJson("rudder", servoPosition);         }
+      sendJson("error", "Aileron input value out of range");
+    }
+  }
+  if (servoInputFlagsLocal & FLAG_ELEVATOR) {
+    //Only use elevator values within the set range for receiver input
+    if (isValidReceiverInput(elevatorInValueLocal)) {
+      if (calibrationMode) {
+        if (elevatorInValueLocal > elevatorMax) elevatorMax = elevatorInValueLocal;
+        if (elevatorInValueLocal < elevatorMin) elevatorMin = elevatorInValueLocal;
+      } else if (manualControl) {
+        processServoInput(elevator, elevatorInValueLocal, "elevator", "Unassigned elevator pin");
       }
     } else {
-      sendJson("error", "Unassigned aileron pin");
-    }
-
-    if (rudder.attached()) {
-      if (rudderIn != -1) {
-        long pulse = pulseIn(rudderIn, HIGH, PULSE_TIMEOUT);
-        if (pulse != 0) {
-          int servoPosition = constrain(map(pulse, RECEIVER_MIN, RECEIVER_MAX, 0, 180), 0, 180);
-          rudder.write(servoPosition);
-          sendJson("rudder", servoPosition);
-        }
+      sendJson("error", "Elevator input value out of range");
+    }
+  }
+  if (servoInputFlagsLocal & FLAG_RUDDER) {
+  //Only use rudder values within the set range for receiver input
+    if (isValidReceiverInput(rudderInValueLocal)) {
+      if (calibrationMode) {
+        if (rudderInValueLocal > rudderMax) rudderMax = rudderInValueLocal;
+        if (rudderInValueLocal < rudderMin) rudderMin = rudderInValueLocal;
+      } else if (manualControl) {
+        processServoInput(rudder, rudderInValueLocal, "rudder", "Unassigned rudder pin");
       }
     } else {
-      sendJson("error", "Unassigned rudder pin");
+      sendJson("error", "Rudder input value out of range");
+    }
+  }
+  if (servoInputFlagsLocal & FLAG_THROTTLE) {
+    //Only use throttle values within the set range for receiver input
+    if (isValidReceiverInput(throttleInValueLocal)) {
+      if (calibrationMode) {
+        if (throttleInValueLocal > throttleMax) throttleMax = throttleInValueLocal;
+        if (throttleInValueLocal < throttleMin) throttleMin = throttleInValueLocal;
+      } else if (manualControl) {
+        processServoInput(throttle, throttleInValueLocal, "throttle", "Unassigned throttle pin");
+      }
+    } else {
+      sendJson("error", "Throttle input value 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) {
-  StaticJsonBuffer<numChars> jsonBuffer;
+  StaticJsonBuffer<CHAR_ARRAY_SIZE> jsonBuffer;
   JsonObject& root = jsonBuffer.createObject();
   root[key] = value;
   Serial.print(startMarker);
@@ -307,7 +395,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[]) {
-  StaticJsonBuffer<numChars> jsonBuffer;
+  StaticJsonBuffer<CHAR_ARRAY_SIZE> jsonBuffer;
   JsonObject& root = jsonBuffer.createObject();
   root[key] = value;
   Serial.print(startMarker);
@@ -316,11 +404,151 @@
 }

 //Takes a key (text) value (int) pair and sends them as JSON over the serial interface
-void sendJson(const char key[], int value) {
-  StaticJsonBuffer<numChars> jsonBuffer;
+void sendJson(const char key[], byte value) {
+  StaticJsonBuffer<CHAR_ARRAY_SIZE> jsonBuffer;
   JsonObject& root = jsonBuffer.createObject();
   root[key] = value;
   Serial.print(startMarker);
   root.printTo(Serial);
   Serial.println(endMarker);
 }
+
+//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 &calibrationData = jsonBuffer.createObject();;
+  calibrationData["aileronMin"] = aileronMin;
+  calibrationData["aileronMax"] = aileronMax;
+  calibrationData["elevatorMin"] = elevatorMin;
+  calibrationData["elevatorMax"] = elevatorMax;
+  calibrationData["rudderMin"] = rudderMin;
+  calibrationData["rudderMax"] = rudderMax;
+  calibrationData["throttleMin"] = throttleMin;
+  calibrationData["throttleMax"] = throttleMax;
+  calibrationData["cutoverMin"] = cutoverMin;
+  calibrationData["cutoverMax"] = cutoverMax;
+  root["calibrationData"] = calibrationData;
+  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 (aileronMax == RECEIVER_INPUT_DEFAULT) return false;
+  if (aileronMin == RECEIVER_INPUT_DEFAULT) return false;
+  if (elevatorMax == RECEIVER_INPUT_DEFAULT) return false;
+  if (elevatorMin == RECEIVER_INPUT_DEFAULT) return false;
+  if (rudderMax == RECEIVER_INPUT_DEFAULT) return false;
+  if (rudderMin == RECEIVER_INPUT_DEFAULT) return false;
+  if (throttleMax == RECEIVER_INPUT_DEFAULT) return false;
+  if (throttleMin == RECEIVER_INPUT_DEFAULT) return false;
+  if (cutoverMax == RECEIVER_INPUT_DEFAULT) return false;
+  if (cutoverMin == RECEIVER_INPUT_DEFAULT) return false;
+  return true;
+}
+
+//Reset all calibrated receiver input values to the default
+void resetCalibration() {
+  aileronMax = RECEIVER_INPUT_DEFAULT;
+  aileronMin = RECEIVER_INPUT_DEFAULT;
+  elevatorMax = RECEIVER_INPUT_DEFAULT;
+  elevatorMin = RECEIVER_INPUT_DEFAULT;
+  rudderMax = RECEIVER_INPUT_DEFAULT;
+  rudderMin = RECEIVER_INPUT_DEFAULT;
+  throttleMax = RECEIVER_INPUT_DEFAULT;
+  throttleMin = RECEIVER_INPUT_DEFAULT;
+  cutoverMax = RECEIVER_INPUT_DEFAULT;
+  cutoverMin = RECEIVER_INPUT_DEFAULT;
+}
+
+//Interrupt Service Routine (ISR) for aileron receiver input
+void listenForAileron() {
+  static uint32_t aileronInStart;
+  if (PCintPort::pinState) {
+    aileronInStart = micros();
+  } else {
+    aileronInValue = (uint16_t) (micros() - aileronInStart);
+    servoInputFlags |= FLAG_AILERON;
+  }
+}
+
+//Interrupt Service Routine (ISR) for cutover input
+void listenForCutover() {
+  static uint32_t cutoverInStart;
+  if (PCintPort::pinState) {
+    cutoverInStart = micros();
+  } else {
+    cutoverInValue = (uint16_t) (micros() - cutoverInStart);
+    servoInputFlags |= FLAG_CUTOVER;
+  }
+}
+
+//Interrupt Service Routine (ISR) for elevator receiver input
+void listenForElevator() {
+  static uint32_t elevatorInStart;
+  if (PCintPort::pinState) {
+    elevatorInStart = micros();
+  } else {
+    elevatorInValue = (uint16_t) (micros() - elevatorInStart);
+    servoInputFlags |= FLAG_ELEVATOR;
+  }
+}
+
+//Interrupt Service Routine (ISR) for rudder receiver input
+void listenForRudder() {
+  static uint32_t rudderInStart;
+  if (PCintPort::pinState) {
+    rudderInStart = micros();
+  } else {
+    rudderInValue = (uint16_t) (micros() - rudderInStart);
+    servoInputFlags |= FLAG_RUDDER;
+  }
+}
+
+//Interrupt Service Routine (ISR) for throttle receiver input
+void listenForThrottle() {
+  static uint32_t throttleInStart;
+  if (PCintPort::pinState) {
+    throttleInStart = micros();
+  } else {
+    throttleInValue = (uint16_t) (micros() - throttleInStart);
+    servoInputFlags |= FLAG_THROTTLE;
+  }
+}
+
+//Determines whether a given value is valid receiver input
+boolean isValidReceiverInput(uint16_t receiverInput) {
+  if (receiverInput < RECEIVER_INPUT_MAX && receiverInput > RECEIVER_INPUT_MIN) return true;
+  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), SERVO_MIN, SERVO_MAX);
+    servo.write(convertedServoValue);
+    sendJson(servoType, convertedServoValue);
+  } else {
+    sendJson("error", servoError);
+  }
+}
+
+//Takes a servoType and returns the corresponding calibrated receiver input max value
+int getReceiverInputMax(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;
+}
+
+//Takes a servoType and returns the corresponding calibrated receiver input min value
+int getReceiverInputMin(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;
+}


[minor] comments on client lib

[minor] comments on client lib

--- src/du.ino
+++ src/du.ino
@@ -41,13 +41,23 @@
   }
 }

-
+/*
+ * Set pin mode
+ */
 void sm(char *pin, char *val) {
   Serial.println('0');
 }
+
+/*
+ * Digital write
+ */
 void dw(char *pin, char *val) {
   Serial.println('1');
 }
+
+/*
+ * Digital read
+ */
 void dr(char *pin, char *val) {
   Serial.println('2');
 }


Fix rfduino firmware syntax error

Fix rfduino firmware syntax error

--- examples/evothings.bluetooth_discovery/firmware/RFduino.ino
+++ examples/evothings.bluetooth_discovery/firmware/RFduino.ino
@@ -12,7 +12,7 @@
 int i;
 bool connected;
 int len;
-char sendData[20];
+uint8_t sendData[20];
 uint8_t getData[20];
 uint8_t last_sector_ID = 0;
 uint8_t current_sector_ID = 0;
@@ -222,7 +222,7 @@
             send_string(GET_VERSION, VERSION);
             break;
         case GET_UUID:
-            send_string(GET_UUID, GET_UUID);
+            send_string(GET_UUID, UUID);
             break;
         case LED_ON:
             ledOn(getData[0], getData[1], getData[2]);


Remove code stop if the audio board is not working.

--- Arduino/Neutrino_Wand/Neutrino_Wand.ino
+++ Arduino/Neutrino_Wand/Neutrino_Wand.ino
@@ -105,12 +105,6 @@
 void setup() {
   // softwareserial at 9600 baud for the audio board
   ss.begin(9600);
-
-  // see if we have the soundboard
-  // If we fail to communicate, loop forever for now but it would be nice to warn the user somehow
-  if (!sfx.reset()) {
-    while (1);
-  }

   // set act modes for the fx board
   pinMode(ACT, INPUT);


implemented half stepping 	modified:   mcu_main/mcu_main.ino

--- mcu_main/mcu_main.ino
+++ mcu_main/mcu_main.ino
@@ -13,8 +13,9 @@
   boolean  cw;
 };

-void wave_step(const State* state);
-void full_step(const State* state);
+void wave(const State* state);
+void full(const State* state);
+void half(const State* state);

 void setup()
 {
@@ -28,18 +29,18 @@
 {

   State state;
-  state.spd = 10;
-  state.steps = 150;
+  state.spd = 500;
+  state.steps = 250;
   state.running = true;
-  state.cw = false;
+  state.cw = true;

-  full_step(&state);
+  half(&state);

   while(true);
 }

 //!  speed range: [10,500]
-void wave_step(const State* state)
+void wave(const State* state)
 {
   //!  specify the starting index according to the direction
   unsigned a,b,c,d;
@@ -67,8 +68,9 @@
     delay(10000/(state->spd));
   }
 }
+
 //!  speed range: [10,500]
-void full_step(const State* state)
+void full(const State* state)
 {
   //!  specify the starting index according to the direction
   unsigned a,b,c,d;
@@ -97,3 +99,45 @@
   }
 }

+//!  speed range: [10,500]
+void half(const State* state)
+{
+  //!  specify the starting index according to the direction
+  int a = 0, c = 2, b = 4, d = 6;
+
+    //!  move steps as specified if running == true.
+  boolean arr[8] = {1,1,1,0, 0,0,0,0};
+  unsigned count = state->steps;
+  while(count-- > 0 && state->running)
+  {
+      if(!state->cw)
+      {
+            digitalWrite(A, arr[a++]);
+            digitalWrite(B, arr[b++]);
+            digitalWrite(C, arr[c++]);
+            digitalWrite(D, arr[d++]);
+
+            a %= 8;
+            b %= 8;
+            c %= 8;
+            d %= 8;
+      }
+      else
+      {
+            digitalWrite(A, arr[a--]);
+            digitalWrite(B, arr[b--]);
+            digitalWrite(C, arr[c--]);
+            digitalWrite(D, arr[d--]);
+
+            if(a < 0)  a = 7;
+            if(b < 0)  b = 7;
+            if(c < 0)  c = 7;
+            if(d < 0)  d = 7;
+      }
+
+    //!  speed control
+    delay(10000/(state->spd));
+  }
+
+
+}


Function changes

Function changes

Added emergency state in case temp gets too high. Changed so displayed
temp is in real time. Change to use temp offset rather then temp
reading delay.

--- ArduinoExhaust/MainLoop.ino
+++ ArduinoExhaust/MainLoop.ino
@@ -26,7 +26,7 @@

   case S_Emergency:
     F_Emergency();
-    break;
+  break;
   }
 }


Several small changes: Add comments, LCD info during setup process, LED control, etc.

--- Arduino/coopController/coopController.ino
+++ Arduino/coopController/coopController.ino
@@ -33,9 +33,9 @@
 const int rtcSCL        = 21;  // Real Time Clock SCL (i2c arduino mega)

 // LCD Pins
-const int lcd_4  = 24;  // LCD RS
-const int lcd_5  = 25;  // LCD R/W
-const int lcd_6  = 26;  // LCD Enable
+const int lcd_4  = 24; // LCD RS
+const int lcd_5  = 25; // LCD R/W
+const int lcd_6  = 26; // LCD Enable
 const int lcd_11 = 27; // LCD Data 4
 const int lcd_12 = 28; // LCD Data 5
 const int lcd_13 = 29; // LCD Data 6
@@ -67,6 +67,7 @@
 // Misc Settings
 const unsigned long millisPerDay    = 86400000; // Milliseconds per day
 const unsigned long debounceWait    =      100; // Debounce timer (100ms)
+const unsigned long ledBlinkRate    =      500; // Delay between LED blinks
 const unsigned long remoteOverride  =   600000; // Length of time to lockout readings. (10min)
 const unsigned long readingInterval =   300000; // How often to take sensor readings. (5min)
 const int           fanThreshold    =       78; // When temperature exceeds this threshold, turn on fan
@@ -77,6 +78,7 @@
 unsigned long lastReading  = 0;
 unsigned long lastDebounce = 0;
 unsigned long lastRTCSync  = 0;
+unsigned long lastLEDBlink = 0;
 String        doorState    = "closed"; // Values will be one of: closed, closing, open, opening
 boolean       heaterState  = false;
 boolean       lampState    = false;
@@ -93,6 +95,9 @@
 MQTT mqtt(&esp);
 boolean wifiConnected = false;

+/**
+ * Manage WIFI connection
+ */
 void wifiCb(void* response) {
   uint32_t status;
   RESPONSE res(response);
@@ -113,22 +118,55 @@
   }
 }

+/**
+ * MQTT Connection event handler.
+ *
+ * Subscribes to desired channels
+ */
 void mqttConnected(void* response) {
   if (Debugging) {
     debugger.println("MQTT Connected");
   }
+
+  // Subscribe to time beacon channel to keep RTC up to date.
   mqtt.subscribe(sTime);
+
+  // Subscribe to remote trigger channel to allow remote control of chicken coop
   mqtt.subscribe(sRemote);
 }

+/**
+ * MQTT Disconnect event handler.
+ */
 void mqttDisconnected(void* response) {
   if (Debugging) {
     debugger.println("MQTT Disconnected");
   }
 }

-void mqttPublished(void* response) {}
-
+/**
+ * MQTT Publish even handler.
+ *
+ * We don't really need this, but it allows logging of any sent
+ * messages for debugging purposes.
+ */
+void mqttPublished(void* response) {
+  RESPONSE res(response);
+  String topic = res.popString();
+  String data  = res.popString();
+  if (Debugging) {
+    debugger.print("MQTT Data published to channel '");
+    debugger.print(topic);
+    debugger.print("': ");
+    debugger.println(data);
+  }
+}
+
+/**
+ * Handle incoming MQTT messages.
+ *
+ * This allows us to remotely trigger events via WIFI!
+ */
 void mqttData(void* response) {
   RESPONSE res(response);
   String topic = res.popString();
@@ -161,7 +199,7 @@

   // Sync RTC to time beacon once/day
   if (topic == "time/beacon") {
-    if ((millis() - millisPerDay) > lastRTCSync) {
+    if ((unsigned long)(millis() - millisPerDay) >= lastRTCSync) {
       rtc.adjust(atoi(data.c_str()));
       lastRTCSync = millis();
     }
@@ -265,11 +303,14 @@
   return TemperatureSum;
 }

+/**
+ * Write current temp, brightness level, and door status to LCD screen.
+ */
 void updateLCD() {
-  char tempStr[5];
+  char tempStr[4];
   lcd.clear();
   lcd.setCursor(0,0);
-  lcd.print(dtostrf(tempF, 5, 1, tempStr));
+  lcd.print(dtostrf(tempF, 4, 1, tempStr));
   lcd.print("F | L ");
   lcd.print(brightness);
   lcd.print("%");
@@ -278,6 +319,41 @@
   lcd.print(doorState);
 }

+/**
+ * Allow writing misc messages to the LCD screen.
+ */
+void lcdWrite(char *firstLine = "", char *secondLine = "") {
+  lcd.clear();
+  lcd.setCursor(0,0);
+  lcd.print(firstLine);
+  lcd.setCursor(0,1);
+  lcd.print(secondLine);
+}
+
+/**
+ * Handle door LEDs
+ */
+void doorLEDs() {
+  // When door is closed, closed LED should be lit
+  if (doorState == "closed") {
+    digitalWrite(doorClosedLED, HIGH);
+    digitalWrite(doorOpenLED, LOW);
+  }
+  // When door is open, open LED should be lit
+  else if (doorState == "open") {
+    digitalWrite(doorClosedLED, LOW);
+    digitalWrite(doorOpenLED, HIGH);
+  }
+  // If door is opening/closing (or stuck?) blink LEDs back and forth
+  else {
+    if ((unsigned long)(millis() - lastLEDBlink) >= ledBlinkRate) {
+      lastLEDBlink = millis();
+      digitalWrite(doorClosedLED, !digitalRead(doorClosedLED));
+      digitalWrite(doorOpenLED, !digitalRead(doorOpenLED));
+    }
+  }
+}
+
 /****************************/

 void readSensors() {
@@ -304,7 +380,14 @@
     debugger.begin(115200);
     debugger.println("Initialising...");
   }
+  // Init LCD
+  pinMode(lcd_bl, OUTPUT);
+  digitalWrite(lcd_bl, HIGH);
+  lcd.begin(16,2);
+  lcdWrite("Initializing...");
+
   espPort.begin(115200);
+  lcdWrite("Initializing...", "WIFI Connecting");
   esp.enable();
   delay(500);
   esp.reset();
@@ -314,10 +397,12 @@
   if (Debugging) {
     debugger.println("ARDUINO: Setup MQTT client");
   }
+  lcdWrite("Initializing...", "MQTT Connecting");
   if (!mqtt.begin("coop_duino", "", "", 120, 1)) { // client_id, username, password, keepalive time, cleansession boolean
     if (Debugging) {
       debugger.println("ARDUINO: Failed to setup MQTT");
     }
+    lcdWrite("MQTT Connect", "Failure");
     while(1);
   }

@@ -332,6 +417,7 @@
   esp.wifiCb.attach(&wifiCb);
   esp.wifiConnect(wHost, wPass);

+  lcdWrite("System Ready");

   /**
    * Setup pin modes
@@ -347,7 +433,6 @@
   pinMode(doorBottom, INPUT);
   pinMode(fan, OUTPUT);
   pinMode(fanSpeed, OUTPUT);
-  pinMode(lcd_bl, OUTPUT);

   // Pin defaults
   digitalWrite(lampRelay, LOW);
@@ -361,9 +446,7 @@
   digitalWrite(doorBottom, HIGH); // Enable resistor
   digitalWrite(fan, LOW);
   digitalWrite(fanSpeed, LOW);
-  digitalWrite(lcd_bl, HIGH);
-
-  lcd.begin(16,2);
+
 }

@@ -371,7 +454,7 @@
 void loop() {
   esp.process();

-  if ((millis() - readingInterval) > lastReading) {
+  if ((unsigned long)(millis() - readingInterval) >= lastReading) {
     // Do stuff!
     readSensors();
     updateLCD();