vaguely workable line follower

vaguely workable line follower

--- software/firmware/LogoBotLineFollower/LogoBotLineFollower.ino
+++ software/firmware/LogoBotLineFollower/LogoBotLineFollower.ino
@@ -1,47 +1,48 @@
 #include "Configuration.h"
 #include <DifferentialStepper.h>
-#include <Bot.h>
-#include <Servo.h>

-Bot bot(MOTOR_L_PIN_1, MOTOR_L_PIN_2, MOTOR_L_PIN_3, MOTOR_L_PIN_4, MOTOR_R_PIN_1, MOTOR_R_PIN_2, MOTOR_R_PIN_3, MOTOR_R_PIN_4);
+// differntial stepper drive
+DifferentialStepper diffDrive(
+    DifferentialStepper::HALF4WIRE,
+    MOTOR_L_PIN_1, MOTOR_L_PIN_2, MOTOR_L_PIN_3, MOTOR_L_PIN_4,
+    MOTOR_R_PIN_1, MOTOR_R_PIN_2, MOTOR_R_PIN_3, MOTOR_R_PIN_4
+);
+
+int nextLeft, nextRight;

 void setup()
 {
   Serial.begin(9600);
-  Serial.println("Logobot");
-  bot.begin();
-  bot.initBumpers(SWITCH_FL_PIN, SWITCH_FR_PIN, SWITCH_BL_PIN, SWITCH_BR_PIN, handleCollision);
-  bot.initBuzzer(BUZZER_PIN);
-  //bot.lookAheadEnable(true);
-  bot.playStartupJingle();
+  Serial.println("Logobot Line Follower");
+
+  diffDrive.setMaxStepRate(1000);
+  diffDrive.setAcceleration(2000);
+  diffDrive.setBacklash(STEPS_OF_BACKLASH);
+  diffDrive.setInvertDirectionFor(0,true);
+
+  nextLeft = 5;
+  nextRight = 5;
 }

 void loop()
 {

-  // keep the bot moving (this triggers the stepper motors to move, so needs to be called frequently, i.e. >1KHz)
-  //bot.run();
+  diffDrive.run();

-  // check sensor value, report on Serial
-  delay(500);
-  Serial.println(digitalRead(IR_LEFT_PIN));
+  // check sensors
+  if (!digitalRead(IR_LEFT_PIN)) {
+      nextLeft = 1;
+  }
+  if (!digitalRead(IR_RIGHT_PIN)) {
+      nextRight = 1;
+  }
+
+  if (diffDrive.isQEmpty()) {
+      // decide what to do next
+      diffDrive.queueMove(nextLeft, nextRight);
+
+      // reset next
+      nextLeft = 5;
+      nextRight = 5;
+  }
 }
-
-static void handleCollision(byte collisionData)
-{
-	if (collisionData != 0) {
-		// Just hit something, so stop and buzz
-		bot.emergencyStop();  // this will be called by parseLogoCommand
-		bot.buzz(500);
-	}
-
-	// Insert some recovery based on which bumper was hit
-	bot.drive(-20);
-	if (collisionData == 1) {
-        bot.turn(-30);
-	} else if (collisionData == 2) {
-        bot.turn(60);
-	} else {
-        bot.turn(-90);
-	}
-}


Fixed bug when writing to first byte

Fixed bug when writing to first byte

--- src/arduino_atmega328_burner.ino
+++ src/arduino_atmega328_burner.ino
@@ -49,7 +49,6 @@
 enum State state = REST;
 int blink_timer  = 0;
 ushort addr      = 0x0000;
-byte data        = 0xFF;
 bool wait        = true;
 byte page_buffer[64];
 byte ascii_buffer[128];
@@ -177,10 +176,17 @@

 // Places the byte on the data bus.
 void setDataBus(byte val) {
-   digitalWrite(8, (val >> 6) & 0x01);
-   digitalWrite(9, (val >> 7) & 0x01);
+   digitalWrite(2, val & 1);
+   digitalWrite(3, (val >> 1) & 1);
+   digitalWrite(4, (val >> 2) & 1);
+   digitalWrite(5, (val >> 3) & 1);
+   digitalWrite(6, (val >> 4) & 1);
+   digitalWrite(7, (val >> 5) & 1);
+   digitalWrite(8, (val >> 6) & 1);
+   digitalWrite(9, (val >> 7) & 1);
+
    // MEEPROMMER doesn't mask PIND, this fixes some bad writes
-   PORTD = (PIND & 3) | (val << 2);
+//   PORTD = (PIND & 3) | (val << 2);
 }

 byte readDataBus() {
@@ -290,9 +296,10 @@
    pinMode(CHIP_PIN,   OUTPUT);
    pinMode(WRITE_LED,  OUTPUT);
    pinMode(READ_LED,   OUTPUT);
-   digitalWrite(READ_PIN,   HIGH);
-   digitalWrite(CHIP_PIN,   HIGH);
-   digitalWrite(WRITE_PIN,  HIGH);
+   digitalWrite(READ_PIN,  HIGH);
+   digitalWrite(CHIP_PIN,  HIGH);
+   digitalWrite(WRITE_PIN, HIGH);
+   digitalWrite(SHIFT_PIN, HIGH);

    Serial.begin(9600);
 }
@@ -369,8 +376,8 @@
                fillBinBuffer(ascii_buffer, page_buffer, ascii_bytes);
                int bytes_to_write = ascii_bytes / 2;
                digitalWrite(WRITE_LED, HIGH);
+               setWriteMode();
                for (int i = 0; i < bytes_to_write; ++i) {
-                  setWriteMode();
                   writeToAddr(addr, page_buffer[i]);
                   addr++;
                }
@@ -415,7 +422,6 @@
       case 'R': // Read EEPROM contents
          state = READ;
          addr  = 0x0000;
-         data  = 0x00;
          wait  = false;
          setReadMode();
          digitalWrite(WRITE_LED, LOW);
@@ -434,9 +440,12 @@
          wait = true;
          return;
       case 'W': // Write data to EEPROM
+         // Don't accidentally write anything sent so far to the chip
+         while (Serial.available() > 0) {
+            Serial.read();
+         }
          state = WRITE;
          addr  = 0x0000;
-         data  = 0x00;
          wait  = false;
          digitalWrite(WRITE_LED, HIGH);
          digitalWrite(READ_LED, LOW);


Fleshing Out New Components

Fleshing Out New Components

Got the rotary dial and the i/o expander in the mail, starting to move the code towards that direction, will need to redo more components.

--- KSPboard.ino
+++ KSPboard.ino
@@ -4,23 +4,21 @@
 // controller.  See LICENSE and README
 // for more information.

+#include <Wire.h>
+

 /// pin configurations and constants
 //

-#define ENABLE 1
-#define DISABLE 0
-
-#define FULL 0xFF
-#define HALF 0x7F
-#define ZERO 0x00
+#define ENABLE true
+#define DISABLE false

 // serial
 #define SERIAL_SPEED 115200

 // state pins
 #define PIN_LED 13 // status
-#define PIN_ENABLE 2 // this should be high to run
+#define PIN_ENABLE A1 // this should be high to run

 // helm pins
 #define PIN_PITCH_U 12
@@ -31,11 +29,16 @@
 #define PIN_YAW_R 7
 #define PIN_THROTTLE A0 // analog read

+// rotary pins
+#define PIN_ROT_CLK 2
+#define PIN_ROT_DATA A2
+#define PIN_ROT_SW // no pin yet
+
 // ops pins
-#define PIN_OP_LAUNCH 6
-#define PIN_OP_STAGE 5
-#define PIN_OP_ACG3 4
-#define PIN_OP_ACG5 3
+#define PIN_OP_LAUNCH 0
+#define PIN_OP_STAGE 0
+#define PIN_OP_ACG3 0
+#define PIN_OP_ACG5 0

 // delays
 #define DELAY_LOOP 15
@@ -43,20 +46,29 @@
 #define DELAY_OP 100

 // misc
-#define OPS (sizeof(opPin) / sizeof(byte))
+#define OPS (sizeof(opPin) / sizeof(uint8_t))

 #define ANALOG_MAX (float)1023 // these two are for converting 0-1023 to 0-100
-#define THOTTLE_MAX (float)255
+#define THOTTLE_MAX (float)INT8_MAX
+#define RAMP_MAX 125
+#define RAMP_MIN -125
+#define DIR_MAX 1023
+#define DIR_MIN -1023
+
+enum dir { full, half, zero };

 // helm control variables
-byte pitch, yaw, roll, throttle;
+int16_t pitch, yaw, roll;
+uint8_t throttle;
+int8_t pitch_adj, yaw_adj, roll_adj; // for ramping the directional input
+boolean pitch_stick = true, yaw_stick = false, roll_stick = false;

 // op control variables
 // state == 0 to DELAY_OP-1 -> off / debounce, state == DELAY_OP -> on
-byte opState[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+uint8_t opState[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 // operation pins set to zero are skipped
-byte opPin[] =
+uint8_t opPin[] =
 {
   0,             // null
   0,             // action group 1
@@ -74,20 +86,55 @@
 };

 // this controls whether the python script closes or not, 1 == run
-byte state = 1;
+boolean state = 1;
+
+// specialized control functions
+

 //// helper functions
 //

-byte readDirection(byte pinH, byte pinL) // get control input
-{
-  return (digitalRead(pinH) ? FULL : (digitalRead(pinL) ? ZERO : HALF));
-}
-
-byte readThrottle(byte pin) // get throttle input
-{
-  return ((byte) (((float)analogRead(pin) * THOTTLE_MAX) / ANALOG_MAX));
+int8_t readDirection(uint8_t pinH, uint8_t pinL, int8_t adj) // get control input
+{
+  switch (digitalRead(pinH) ? full : (digitalRead(pinL) ? half : zero))
+  {
+    case full:
+      if (adj++ >= RAMP_MAX)
+        adj = RAMP_MAX;
+      break;
+
+    case zero:
+      if (adj-- <= RAMP_MIN)
+        adj = RAMP_MIN;
+      break;
+
+    default:
+      adj = 0;
+  }
+
+  return (adj);
+}
+
+int16_t setDirection(int16_t current, boolean stick, int8_t adj)
+{
+  current += adj;
+
+  if (!(adj || stick))
+    current = 0;
+
+  if (current > DIR_MAX)
+    current = DIR_MAX;
+
+  if (current < DIR_MIN)
+    current = DIR_MIN;
+
+  return (current);
+}
+
+uint8_t readThrottle(uint8_t pin) // get throttle input
+{
+  return ((uint8_t) (((float)analogRead(pin) * THOTTLE_MAX) / ANALOG_MAX));
 }

@@ -96,6 +143,8 @@

 void setupSerial()
 {
+  Wire.begin(); // start up I/O expanders
+
   Serial.begin(SERIAL_SPEED);
   Serial.println();
   Serial.flush();
@@ -148,25 +197,26 @@

 void updateHelm()
 {
-  // get new values
-  pitch = readDirection(PIN_PITCH_U, PIN_PITCH_D);
-  roll = readDirection(PIN_ROLL_R, PIN_ROLL_L);
-  yaw = readDirection(PIN_YAW_R, PIN_YAW_L);
-
-  // helm are always sent without enable code
-  Serial.println(pitch);
-  Serial.println(yaw);
-  Serial.println(roll);
-
-  // read throttle
+  pitch_adj = readDirection(PIN_PITCH_U, PIN_PITCH_D, pitch_adj);
+  pitch = setDirection(pitch, pitch_adj, pitch_stick);
+  Serial.println(pitch)
+
+  // roll
+  //
+  //
+
+  // yaw
+  //
+  //
+
   throttle = readThrottle(PIN_THROTTLE);
   Serial.println(throttle);
 }

 void updateOps()
 {
-  byte ops = 0;
-  byte index = 0;
+  uint8_t ops = 0;
+  uint8_t index = 0;

   for (index = 0; index < OPS; index++)
@@ -206,6 +256,7 @@
 void setup()
 {
   setupSerial();
+
   setupState();
   setupHelm();
   setupOps();
@@ -224,6 +275,7 @@
   }

   delay(DELAY_LOOP);
+
   Serial.flush();
 }


operations now track on / off properly

operations now track on / off properly

it was only sending when an operation switch was 'on' not when it was switched 'off' the python script needed this functionality so the arduino script was expended

--- KSPboard.ino
+++ KSPboard.ino
@@ -26,6 +26,10 @@
 #define ENABLE true
 #define DISABLE false
 #define NEUTRAL 2 // the natural extension to HIGH and LOW ;-)
+
+// high byte / low byte macros
+#define HI(Q) ((uint8_t) ((0xFF00 & Q) >> 8))
+#define LO(Q) ((uint8_t) (0x00FF & Q))

 // serial
 #define SERIAL_SPEED 115200
@@ -103,7 +107,8 @@
 // Basically if this is not equal to DELAY_OP then it is in debounce state
 // or off (zero).  When it is equal to DELAY_OP then it fires the op code out
 // over serial. This allows multi switch debounce in a convenient package.
-uint8_t opState[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+uint8_t opDebounce[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+uint16_t opState = 0; // holds current switch state

 // this controls whether the python script closes or not, 1 == run
 boolean state = 1;
@@ -224,15 +229,15 @@

 void setupSerial()
 {
-  Wire.begin(); // start up I/O expanders
-
+  // start up serial interface
   Serial.begin(SERIAL_SPEED);
   Serial.println();
   Serial.flush();

-  Serial.print(1); // enable code, super secure
+  // serial enable code, super secure
   Serial.print(1);
   Serial.print(1);
+  Serial.print(1);
 }

 void setupControl()
@@ -240,7 +245,7 @@
   // when you click the dial
   pinMode(PIN_ROT_CTRL_SW, INPUT_PULLUP);

-  // set the data line as input as well
+  // set the data line as input as well (has internal pull up)
   pinMode(PIN_ROT_CTRL_DATA, INPUT);

   // the rotary encoder uses two wire differential signalling
@@ -260,25 +265,28 @@
 void setupHelm()
 {
   // rows are output, and cols are input
+  uint8_t index = 0;
+
   // here we setup the input_pullup pinMode for the cols
-
-  uint8_t index = 0;
-
   for (index = PIN_HELM_MAT_COL; index < PIN_HELM_MAT_COLS; index++)
   {
     pinMode(index, INPUT_PULLUP); // active low matrix
   }

+  // then pull these up to 5V so current cannot flow
   for (index = PIN_HELM_MAT_ROW; index < PIN_HELM_MAT_ROWS; index++)
   {
     pinMode(index, OUTPUT);
-    digitalWrite(index, HIGH); // pull these up to 5V so current cannot flow
+    digitalWrite(index, HIGH);
   }
 }

 void setupOps()
 {
-  // put check here for i/o expander??
+  // start up I/O expander(s)
+  Wire.begin();
+
+  // ping the expanders to make sure they are operational
 }

@@ -303,6 +311,8 @@
     controlState = newState; // update the hilighted state

     // do hiligting stuff //
+
+    Serial.print(F("new state => ")); Serial.println(newState);
   }

   if (controlDebounce > 0) //
@@ -311,7 +321,7 @@
   }
   else
   {
-    if (digitalRead(PIN_ROT_CTRL_SW)) // if you press dis switch lock the sas control state
+    if (!digitalRead(PIN_ROT_CTRL_SW)) // if you press dis switch lock the sas control state
     {
       controlLocked = controlState; // update locked variable

@@ -371,16 +381,23 @@

       for (index = 0; index < OPS; index++) // scan through ops 1-16 (everything but sas)
       {
-        if (opState[index] > 0) // check for debounce on current pin
+        if (opDebounce[index] > 0) // check for debounce on current pin
         {
-          opState[index]--; // decrement debounce counter for current state
+          opDebounce[index]--; // decrement debounce counter for current state
         }
         else // if not we can check to see if it's triggered
         {
+          uint16_t opMask = 1 << index; // get and save the current mask
+
           // scan through 0b0000000000000001 to 0b1000000000000000 masks
           // if that switch is 1 then set it's state to DELAY_OP to flag
           // it to be sent out over serial, otherwise set it to zero
-          opState[index] =  ((1 << index) & data) ? DELAY_OP : 0;
+          opDebounce[index] =  (opMask & data) ? DELAY_OP : 0; // DELAY_OP signals state change
+
+          if (opState & opMask) // if it's on turn it off
+            opState &= ~opMask;
+          else                  // or vice versa
+            opState |= opMask;

           // increase the operations counter
           ops++;
@@ -396,8 +413,11 @@
     for (index = 0; index < OPS; index++)
     {
       // for each state that's flagged...
-      if (opState[index] == DELAY_OP)
+      if (opDebounce[index] == DELAY_OP)
+      {
         Serial.println(index); // print it
+        Serial.println((boolean)(opState & (1 << index))); // print it's state
+      }
     }
   }


Debugging main screen colour corruption (issue #2)

--- PixelVFO.ino
+++ PixelVFO.ino
@@ -70,7 +70,8 @@
 #define MENUBTN_BG2            0x4000
 #define MENUBTN_FG             ILI9341_BLUE

-#define CREDIT_FG              ILI9341_BLUE
+#define CREDIT_FG              ILI9341_BLACK
+#define CREDIT_BG              ILI9341_BLUE

 // ONLINE button definitions
 #define ONLINE_WIDTH        110
@@ -349,11 +350,11 @@
   Serial.printf(F("credits_action: called\n"));

   // start drawing things that don't change
-  tft.fillRect(0, DEPTH_FREQ_DISPLAY, tft.width(), SCREEN_HEIGHT-DEPTH_FREQ_DISPLAY, SCREEN_BG2);
-  tft.fillRect(0, 0, tft.width(), tft.height(), FREQ_SEL_BG);
+//  tft.fillRect(0, DEPTH_FREQ_DISPLAY, tft.width(), SCREEN_HEIGHT-DEPTH_FREQ_DISPLAY, SCREEN_BG2);
+  tft.fillRect(0, 0, tft.width(), tft.height(), CREDIT_BG);
   tft.fillRoundRect(0, 0, tft.width(), DEPTH_FREQ_DISPLAY, 5, FREQ_BG);
   tft.setCursor(5, FREQ_OFFSET_Y);
-  tft.setTextColor(FREQ_FG);
+  tft.setTextColor(CREDIT_FG);
   tft.setFont(FONT_MENU);
   tft.print("Credits");
   menuBackButton();


Consts gets caps

Consts gets caps

--- computer_box/computer_box.ino
+++ computer_box/computer_box.ino
@@ -5,8 +5,8 @@

 #define DHTTYPE DHT22   // DHT 22  (AM2302)

-const int ac_probe = 2;
-const int dc_probe = 1;
+const int AC_PROBE = 2;
+const int DC_PROBE = 1;

 const int FAN_PIN = 4;
 const int DHT_PIN = 3; // DHT Temp & Humidity Pin
@@ -90,10 +90,10 @@

 /* DC Probe: ~730 = 11.53 */
 void read_voltages() {
-  int ac_reading = analogRead(ac_probe);
+  int ac_reading = analogRead(AC_PROBE);
   float ac_voltage = ac_reading / 1023 * 5;

-  int dc_reading = analogRead(dc_probe);
+  int dc_reading = analogRead(DC_PROBE);
   float dc_voltage = dc_reading * 0.0158;

   Serial.print("\"voltages\":{");


Added static pins for activation switch and ignition coil

--- Flameduino/Flameduino.ino
+++ Flameduino/Flameduino.ino
@@ -15,7 +15,9 @@
 #define ACTIVATION_PIN 2
 #define TACH_PIN 3
 #define IGNITION_PIN 4
-#define EXTERNAL_LED_PIN 4
+#define EXTERNAL_LED_PIN 5
+#define ACTIVATION_STATIC_PIN 7
+#define IGNITION_STATIC_PIN 8
 #define INTERNAL_LED_PIN 13
 #define FREQUENCY_PIN A0

@@ -74,14 +76,20 @@
 void setup()
 {
   pinMode(ACTIVATION_PIN, INPUT);
+  pinMode(ACTIVATION_STATIC_PIN, OUTPUT);
   pinMode(TACH_PIN, INPUT);
   pinMode(IGNITION_PIN, OUTPUT);
+  pinMode(IGNITION_STATIC_PIN, OUTPUT);
   pinMode(FREQUENCY_PIN, INPUT);
   pinMode(INTERNAL_LED_PIN, OUTPUT);
   pinMode(EXTERNAL_LED_PIN, OUTPUT);

   //Use built in pull-up resistor
   digitalWrite(ACTIVATION_PIN, HIGH);
+
+  //Set Static Pins
+  digitalWrite(ACTIVATION_STATIC_PIN, activeState);
+  digitalWrite(IGNITION_STATIC_PIN, LOW);

   active = isActive();
   dischargeCoil();


Add pin control and timeouts

Add pin control and timeouts

--- teensy/teensy.ino
+++ teensy/teensy.ino
@@ -58,7 +58,7 @@
 static char n64_raw_dump[36]; // maximum recv is 1+2+32 bytes + 1 bit
 // n64_raw_dump does not include the command byte. That gets pushed into
 // n64_command:
-static unsigned char n64_command;
+static int n64_command;
 // bytes to send to the 64
 // maximum we'll need to send is 33, 32 for a read request and 1 CRC byte
 static unsigned char n64_buffer[33];
@@ -166,9 +166,51 @@
   Serial.println(dat[3], HEX);
 }

+static bool setPinMode(const String& cmd)
+{
+  if (cmd.length() < 3)
+    return false;
+  if (cmd[1] != ':')
+    return false;
+
+  int pinNumber = cmd.substring(2).toInt();
+
+  if (cmd[0] == 'I')
+    pinMode(pinNumber, INPUT);
+  else if (cmd[0] == 'O')
+    pinMode(pinNumber, OUTPUT);
+  else if (cmd[0] == 'U')
+    pinMode(pinNumber, INPUT_PULLUP);
+  else if (cmd[0] == 'D')
+    pinMode(pinNumber, INPUT_PULLDOWN);
+  else
+    return false;
+
+  return true;
+}
+
+static bool writePin(const String& cmd)
+{
+  if (cmd.length() < 3)
+    return false;
+  if (cmd[1] != ':')
+    return false;
+
+  int pinNumber = cmd.substring(2).toInt();
+
+  if (cmd[0] == '0')
+    digitalWrite(pinNumber, LOW);
+  else if (cmd[0] == '1')
+    digitalWrite(pinNumber, HIGH);
+  else
+    return false;
+
+  return true;
+}
+
 static FatFile writeFile;

-const bool skippingInput = false;
+bool skippingInput = false;
 static String inputString;

 static void handleCommand(const String& cmd)
@@ -195,9 +237,13 @@

   } else if (cmd.startsWith("CL:")) {
     writeFile.close();
+  } else if (cmd.startsWith("PM:")) {
+    setPinMode(cmd.substring(3));
+  } else if (cmd.startsWith("DW:")) {
+    writePin(cmd.substring(3));
   } else {
     Serial.print("Unknown CMD:");
-    Serial.println(cmd);
+    Serial.println(cmd.c_str());
   }
 }

@@ -210,15 +256,28 @@
       if (skippingInput)
         Serial.println("Skipped line longer than 256 chars");
       else
-        handleCommand();
+        handleCommand(inputString);
       inputString = "";
       skippingInput = false;
     } else if (inputString.length() > 256) {
       skippingInput = true;
     } else {
-      inputString += newChar;
+      inputString += (char)newChar;
     }
   }
+}
+
+static void waitForIdle(int us)
+{
+  LED_HIGH;
+  N64_HIGH;
+  startTimer();
+  int lastReset = 0;
+  while (readTimer() - lastReset < us * MICRO_CYCLES && readTimer() < us * MICRO_CYCLES * 4) {
+    if (!N64_QUERY)
+      lastReset = readTimer();
+  }
+  LED_LOW;
 }

 static void mainLoop()
@@ -246,9 +305,6 @@
     // Bail if file open failed
     if (!m64OpenSuccess)
         return;
-
-    // wait to make sure the line is idle before
-    // we begin listening

     noInterrupts();

@@ -314,7 +370,7 @@
             curFrame++;

             pos = bufferPos + 1;
-            if (pos >= INPUT_BUFFER_SIZE)
+            if (pos >= INPUT_BUFFER_SIZE)
                 pos = 0;
             bufferPos = pos;

@@ -389,6 +445,11 @@
             //Serial.print(addr, HEX);
             //Serial.print(" and data was 0x");
             //Serial.println(data, HEX);
+            break;
+
+        case -1:
+            Serial.println(F("Timed out reading N64 command"));
+            waitForIdle(1000);
             break;

         default:
@@ -503,11 +564,12 @@
     Serial.flush();

     // Wait for the line to go idle, then begin listening
+    /*
     for (int idle_wait=32; idle_wait>0; --idle_wait) {
         if (!N64_QUERY) {
             idle_wait = 32;
         }
-    }
+    }*/

     noInterrupts();
     m64OpenSuccess = true;
@@ -522,7 +584,7 @@

 static void updateInputBuffer() {
-    if (finished)
+    if (finished || !m64OpenSuccess)
       return;

     long readBytes = 0;
@@ -655,28 +717,29 @@
  */
 static void n64_send(unsigned char *buffer, char length, bool wide_stop)
 {
-    long target;
-    LED_HIGH;
-    N64_LOW;
+  long target;
+  LED_HIGH;
+  N64_LOW;
+  startTimer();
+
+  for (int i = 0; i < length * 8; i++) {
+    char bit = (buffer[i >> 3] >> (7 - (i & 7))) & 1;
+    target = MICRO_CYCLES * (3 - bit * 2);
+    while (readTimer() < target);
+      N64_HIGH;
+    while (readTimer() < MICRO_CYCLES * 4);
+      N64_LOW;
     startTimer();
-
-    for (int i = 0; i < length * 8; i++) {
-      char bit = (buffer[i >> 3] >> (7 - (i & 7))) & 1;
-      target = MICRO_CYCLES * (3 - bit * 2);
-      while (readTimer() < target);
-      N64_HIGH;
-      while (readTimer() < MICRO_CYCLES * 4);
-      N64_LOW;
-      startTimer();
-    }
-
-    target = MICRO_CYCLES * (1 + wide_stop);
-
-    while (readTimer() < target);
-
-    N64_HIGH;
-    LED_LOW;
-    while (!N64_QUERY);
+  }
+
+  target = MICRO_CYCLES * (1 + wide_stop);
+
+  while (readTimer() < target);
+
+  N64_HIGH;
+  startTimer();
+  while (!N64_QUERY && readTimer() < MICRO_CYCLES * 4);
+  LED_LOW;
 }

 /**
@@ -701,11 +764,20 @@

     LED_HIGH;

+#define FAIL_TIMEOUT {\
+  if (readTimer() >= MICRO_CYCLES * 10) {\
+    n64_command = -1; \
+    goto fail; \
+  } \
+}\
+
     for (int i = 1; i <= bitcount; i++) {
-        while (!N64_QUERY);
+        while (!N64_QUERY)
+          FAIL_TIMEOUT;
         long lowTime = readTimer();
         startTimer();
-        while (N64_QUERY);
+        while (N64_QUERY)
+          FAIL_TIMEOUT;
         long highTime = readTimer();
         startTimer();
         char bit = (lowTime < highTime);
@@ -739,9 +811,12 @@
     }

     // Wait for the stop bit
-    while (!N64_QUERY);
+    while (!N64_QUERY)
+      FAIL_TIMEOUT;
     startTimer();
     while (readTimer() < MICRO_CYCLES * 2);

+fail:
+
     LED_LOW;
 }


Bug fix

Bug fix

--- MagnusCore/MagnusCore.ino
+++ MagnusCore/MagnusCore.ino
@@ -170,7 +170,7 @@
         // we have valid buffer of serial input
         char cmd = command[0];
         Ownership newOwner = owner;
-        uint8_t newSumLevel;
+        uint8_t newSumLevel = sumLevel;
         switch (cmd) {
             case '*':
                 Serial.println("Magnus Core Node");
@@ -191,6 +191,7 @@
                     uint8_t rl = command[res] - '0';
                     newSumLevel += rl;
                 }
+                if (newSumLevel > 64) newSumLevel = 64;
                 char strength;
                 strength = command[PORTAL_STRENGTH_INDEX];
                 percent = decodePercent(strength);


Update Mod-Sketch.ino

Update Mod-Sketch.ino

ew from v0.2.2:
G = get Powerlevel : Returns Powerlevel
v = get Version : Returns Version information

New from v0.2.4:
U ... = Play the User transmitted pattern, for example:
U 3,255 0 0 500, 0 0 255 500, 0 255 0 500
3 Entries
First Motor 255, Second 0, Third 0, for 500ms
First Motor 0, Second 0, Third 255, for 500ms
First Motor 0, Second 255, Third 0, for 500ms

allStop Pattern added

New from v0.2.5:
u = Returns current Userpattern

--------------
Changed Versionstring to "Mod-Sketch v0.2.5"

--- Mod-Sketch/Mod-Sketch.ino
+++ Mod-Sketch/Mod-Sketch.ino
@@ -1,4 +1,5 @@
-/* Mod Sketch v0.2.1 -- written by Craig Durkin / Comingle. */
+/* Mod Sketch v0.2.5 -- written by Craig Durkin / Comingle. */
+/* Additional Commands & Documentation added by Holger 'Lynxx' Hippenstiel */
 /* This software comes pre-loaded on Comingle Mod sex toys */

 // Include necessary libraries: Wire.h and WiiChuck.h for the nunchuck, OSSex.h for the Mod library
@@ -9,7 +10,51 @@
 // Add the pattern library.
 #include "patterns.h"

+/*
+Available commands over Serial:
+- <n>         = Set Value for all Motors : Returns nothing
+0 <n>         = Set Value for Motor 1 : Return current Value
+1 <n>         = Set Value for Motor 2 : Return current Value
+2 <n>         = Set Value for Motor 3 : Return current Value
+c             = Cycle Pattern : Returns running pattern
+g             = Get number of currently running pattern : Returns running pattern
+i             = Read input 0 or 1 : Returns value of input
+l <n>         = Set LED power : Return current Value
+p             = Decrease Power : Returns new Powerlevel
+P             = Increase Power : Returns new Powerlevel
+r <n>         = Run a specific pattern, r,0; r,1; etc. : Returns running pattern
+s             = Stop all Motors, reset Patternnumber, Power & Timescale : Returns nothing
+t             = Decrease pattern time, as in everything goes faster : Returns new Timescale
+T             = Increase pattern time, as in everything goes slower : Returns new Timescale
+{<n>,<n>,<n>} = Set Value for Motor1,2 and 3 in a single line : Returns nothing
+
+New from v0.2.2:
+G = get Powerlevel : Returns Powerlevel
+v = get Version : Returns Version information
+
+New from v0.2.4:
+U ... = Play the User transmitted pattern, for example:
+U 3,255 0 0 500, 0 0 255 500, 0 255 0 500
+3 Entries
+First Motor 255, Second 0, Third 0, for 500ms
+First Motor 0, Second 0, Third 255, for 500ms
+First Motor 0, Second 255, Third 0, for 500ms
+
+allStop Pattern added
+
+New from v0.2.5:
+u = Returns current Userpattern
+*/
+
+const String txtVersion = "Mod-Sketch v0.2.5";
+int* userPattern; // Will dynamicly be allocated/freed
+int userPatternSize = 0;
+int userPatternNumber = 0; // Number of the Userpattern
+int currentPatternNumber = 0; // Currently added Pattern number
+
 void setup() {
+  Toy.setID(); // Set Toy ID using default Value, currently 1 = MOD
+
   // Button will increase/decrease power by 20%
   Toy.setPowerScaleStep(0.2);

@@ -19,17 +64,20 @@
   // Set the patterns that the button will cycle through. Toy will do nothing on startup, and clicking the button once will run the 'first' pattern
   // Clicking again will run 'second', etc.

-  Toy.addPattern(first);
-  Toy.addPattern(second);
-  Toy.addPattern(third);
-  Toy.addPattern(pulse);
-  Toy.addPattern(fadeCos);
-  Toy.addPattern(weird3);
-  Toy.addPattern(sharpRamp);
-  Toy.addPattern(flicker);
-  Toy.addPattern(weird2);
-  Toy.addPattern(fadeOffset);
-  Toy.addPattern(pulse2);
+  AddPattern(first);
+  AddPattern(second);
+  AddPattern(third);
+  AddPattern(pulse);
+  AddPattern(fadeCos);
+  AddPattern(weird3);
+  AddPattern(sharpRamp);
+  AddPattern(flicker);
+  AddPattern(weird2);
+  AddPattern(fadeOffset);
+  AddPattern(pulse2);
+  userPatternNumber = currentPatternNumber; // Remember number of Userpattern
+  AddPattern(userPatternPlayer);
+  AddPattern(allStop);

   // Set up the button click handlers
   Toy.attachClick(click);
@@ -40,87 +88,152 @@
   Serial.begin(9600);
 }

-
-
 void loop() {
   serialProcessor();
 }

-// Serial console. Read a character in to command[1], and a value in to val
+// Serial console. Read a character in to inChar, and a value in to val
 void serialProcessor() {
-  char command[1];
-  byte val;
-
   if (Serial.available() > 0) {
-    Serial.readBytes(command,1);
-    if (command[0] == 'l') { // Set LED power
-      val = Serial.parseInt();
-      Toy.setLED(0,val);
-      Serial.println(val);
-    } else if (command[0] == '0' || command[0] == '1' || command[0] == '2') { // Set power of individual motor
-      val = Serial.parseInt();
-      Toy.setOutput(command[0], val);
-      Serial.println(val);
-    } else if (command[0] == '-') { // Catch '-1', set power of all motors
-      int out = Serial.parseInt();
-      out *= -1;
-      val = Serial.parseInt();
-      Toy.setOutput(out,val);
-    } else if (command[0] == '{') {
-      int motors[3];
-      motors[0] = Serial.parseInt();
-      motors[1] = Serial.parseInt();
-      motors[2] = Serial.parseInt();
-      for (int i = 0; i < 3; i++) {
-        if (motors[i] >= 0) {
-          Toy.setOutput(i, motors[i]);
+    char inChar = Serial.read();
+    byte val;
+    switch (inChar) {
+      case 'l': // Set LED-Power
+        val = SerialParseInt();
+        SetLED(val);
+        PrintLine(val);
+        break;
+
+      case '0': // Set Power for Motor1-3 directly
+      case '1':
+      case '2':
+        val = SerialParseInt();
+        SetOutput(inChar, val);
+        PrintLine(val);
+        break;
+
+      case '-':  // Catch '-1', set power of all motors
+      {
+        int out = SerialParseInt();
+        out *= -1;
+        val = SerialParseInt();
+        SetOutput(out,val);
+        break;
+      }
+
+      case '{': // Set Power for all 3 Motors in a single line
+        for (int i = 0; i < 3; i++) {
+          val = SerialParseInt();
+          if (val >= 0)
+            SetOutput(i, val);
         }
+        break;
+
+      case 'p': // Decrease Toy power, same as longpressing the button
+        PrintLine(Toy.decreasePower());
+        break;
+
+      case 'P': // Increase Toy power, same as doubleclicking the button
+        PrintLine(Toy.increasePower());
+        break;
+
+      case 't': // Decrease pattern time, as in everything goes faster
+        PrintLine(Toy.decreaseTime());
+        break;
+
+      case 'T': // Increase pattern time, as in everything goes slower : Returns new Timescale
+        PrintLine(Toy.increaseTime());
+        break;
+
+      case 'r': // Run a specific pattern, r,0; r,1; r 2 etc.
+        val = SerialParseInt();
+        Toy.runPattern(val);
+        PrintPattern();
+        break;
+
+      case 'g': // Get number of currently running pattern
+        PrintPattern();
+        break;
+
+      case 's': // Stop all Motors, reset Patternnumber, Power & Timescale
+        Toy.stop();
+        break;
+
+      case 'c': // Cycle Pattern, same as single clicking the button
+        Toy.cyclePattern();
+        PrintPattern();
+        break;
+
+      case 'i': // Read input 0 or 1 and print it to serial port
+      {
+        int in = SerialParseInt();
+        in %= Toy.device.inCount;
+        PrintLine(Toy.getInput(in));
+        break;
       }
-    } else if (command[0] == 'p') {
-      Serial.println(Toy.decreasePower());
-    } else if (command[0] == 'P') {
-      Serial.println(Toy.increasePower());
-    } else if (command[0] == 't') { // Decrease pattern time, as in everything goes faster
-      Serial.println(Toy.decreaseTime());
-    } else if (command[0] == 'T') {
-      Serial.println(Toy.increaseTime());
-    } else if (command[0] == 'r') { // Run a specific pattern, r,0; r,1; etc.
-      val = Serial.parseInt();
-      Toy.runPattern(val);
-      Serial.println(Toy.getPattern());
-    } else if (command[0] == 'g') {  // Get number of currently running pattern
-      Serial.println(Toy.getPattern());
-    } else if (command[0] == 's') {
-      Toy.stop();
-    } else if (command[0] == 'c') {
-      Toy.cyclePattern();
-      Serial.println(Toy.getPattern());
-    } else if (command[0] == 'i') { // Read input 0 or 1 and print it to serial port
-      int in = Serial.parseInt();
-      in %= Toy.device.inCount;
-      Serial.println(Toy.getInput(in));
+
+      case 'v': // Print Version information
+        PrintLine(txtVersion);
+        break;
+
+      case 'G': // Get the Powerlevel
+        PrintLine(Toy.getPowerScaleFactor());
+        break;
+
+      case 'U': // Read User-Pattern
+        // UserPattern created before?
+        if (userPattern != 0) {
+          Toy.stop(); // It's maybe currently playing the User-Pattern, therefore stop
+          // Remove the old UserPattern
+          delete [] userPattern;
+        }
+        userPatternSize = SerialParseInt(); // Number of entries
+        userPattern = new int[userPatternSize * 4]; // Each entry consists of 3 motorvalues (-1 also possible) and a time
+        for (int i = 0; i < userPatternSize*4; i++)
+          userPattern[i] = SerialParseInt();
+
+        Toy.runPattern(userPatternNumber);
+        PrintPattern();
+        break;
+
+      case 'u': // Print User-Pattern
+        String strPrint = "";
+        strPrint += userPatternSize;
+        if (userPatternSize != 0) {
+          int k = 0;
+          for (int i = 0; i < userPatternSize; i++) {
+            strPrint += ",";
+            for (int j = 0; j < 4; j++) {
+              strPrint += userPattern[k++];
+              if (j < 3)
+                strPrint += " ";
+            }
+          }
+        }
+        PrintLine(strPrint);
+        break;
     }
   }
 }
-

 // Cycle through all the outputs, turn the LED on and leave it on to show that we're on
 void startupSequence() {
   int outs = Toy.device.outCount;
   int outInterval = 100 / outs;

-  Toy.setLED(0,128);
+  SetLED(128);

   for (int i = 0; i < outs; i++) {
-    Toy.setOutput(i, 100+outInterval*i);
+    SetOutput(i, 100+outInterval*i);
     delay(100);
-    Toy.setOutput(i, 0);
+    SetOutput(i, 0);
     delay(50);
   }
+
   for (int i = 0; i < 3; i++) {
-    Toy.setLED(0,0);
+    SetLED(0);
     delay(100);
-    Toy.setLED(0,128);
+    SetLED(128);
     delay(100);
   }
 }
@@ -140,4 +253,69 @@
   Toy.decreasePower();
 }

-
+// Add a pattern to the toy
+void AddPattern(int (*patternFunc)(int)) {
+  Toy.addPattern(patternFunc);
+  currentPatternNumber++;
+}
+
+// Often used object-functions in own functions = smaller
+int SerialParseInt() {
+  return Serial.parseInt();
+}
+
+void SetOutput(int n, int v) {
+    Toy.setOutput(n, v);
+}
+
+void SetLED(int v) {
+    Toy.setLED(0, v);
+}
+
+// Serial.println-Calls in functions, this way object-reference only needed once
+void PrintLine(float number) {
+  Serial.println(number);
+}
+
+void PrintLine(int number) {
+  Serial.println(number);
+}
+
+void PrintLine(unsigned int number) {
+  Serial.println(number);
+}
+
+void PrintLine(String text) {
+  Serial.println(text);
+}
+
+// Print Pattern number or "User Pattern"
+void PrintPattern() {
+  int val = Toy.getPattern();
+  if (val == userPatternNumber) {
+    String strPrint = "";
+    strPrint += val;
+    strPrint += " (User Pattern)";
+    PrintLine(strPrint);
+  }
+  else
+    PrintLine(val);
+}
+
+// Play the User transmitted pattern, for example:
+// U 3,255 0 0 500, 0 0 255 500, 0 255 0 500
+// 3 Entries
+// First Motor 255, Second 0, Third 0, for 500ms
+// First Motor 0, Second 0, Third 255, for 500ms
+// First Motor 0, Second 255, Third 0, for 500ms
+int userPatternPlayer(int seq) {
+  // If no Userpattern created yet, skip to next pattern
+  if (userPatternSize == 0)
+    Toy.cyclePattern();
+  else {
+    seq %= userPatternSize;
+    SetMotorsAndTime(userPattern[seq*4], userPattern[seq*4+1], userPattern[seq*4+2], userPattern[seq*4+3]);
+  }
+  return 1;
+}
+


Make this compile on latest Arduino and Boards

--- water_heater_monitor/water_heater_monitor.ino
+++ water_heater_monitor/water_heater_monitor.ino
@@ -17,68 +17,6 @@
 uint8_t data_index = 0;

 DHT dht = DHT(0, DHT22);               // Pin 0, DHT 22 (AM2302)
-
-void setup () {
-  initHardware();
-  connectWiFi();
-
-  // debugging...
-  //strcpy(eagle_data, "0:05  120.0  110.0  12.0  159.0  100.0  110.0  ON  OFF  ");
-  //postToPhant();
-  //data_index = 0;
-  //eagle_data[data_index] = '\0';
-}
-
-void loop () {
-  unsigned long now = millis();
-
-  // If we haven't updated in 5 minutes, send along a "PING" to keep showing something.
-  if (now > lastUpdateTime + 300000 || now < lastUpdateTime) {
-    // Reset the data to send a blank "ping"
-    data_index = 0;
-    eagle_data[data_index] = '\0';
-
-    if (postToPhant()) {
-      lastUpdateTime = now;
-    }
-  }
-
-  while (Serial.available()) {
-    char c = Serial.read();
-
-    // Assume a LF is the end of the line
-    if (c == '\n' && strlen(eagle_data) > 0) {
-      // Update once per minute
-      //
-      // Don't send any Eagle header messages we come across.  Also, make sure
-      // there's a : character in the string. It's always the 2nd or 3rd
-      // character so it goes a long way in assuming we have a full set of data.
-
-      unsigned long now = millis();
-
-      if ((now > lastUpdateTime + 60000 || now < lastUpdateTime) && strncmp(eagle_data, "RUNTIME", 7) != 0 && (eagle_data[1] == ':' || eagle_data[2] == ':')) {
-        if (postToPhant()) {
-          lastUpdateTime = now;
-        }
-      }
-
-      // Reset the data.  Hitting an LF should always do this, succesful send or not
-      data_index = 0;
-      eagle_data[data_index] = '\0';
-    } else if (c != '\r') {
-      // Capture everything else (but not a CR)
-      if (data_index < 80) {
-        eagle_data[data_index++] = c;
-      } else {
-        // This case should never happen, but avoid the overrun just the same :)
-        data_index = 0;
-      }
-      eagle_data[data_index] = '\0';
-    }
-
-    yield();    // Yeild to the ESP8266 here, just in case
-  }
-}

 void initHardware() {
   Serial.begin(2400);
@@ -175,3 +113,65 @@
   return 1; // Return success
 }

+void setup () {
+  initHardware();
+  connectWiFi();
+
+  // debugging...
+  //strcpy(eagle_data, "0:05  120.0  110.0  12.0  159.0  100.0  110.0  ON  OFF  ");
+  //postToPhant();
+  //data_index = 0;
+  //eagle_data[data_index] = '\0';
+}
+
+void loop () {
+  unsigned long now = millis();
+
+  // If we haven't updated in 5 minutes, send along a "PING" to keep showing something.
+  if (now > lastUpdateTime + 300000 || now < lastUpdateTime) {
+    // Reset the data to send a blank "ping"
+    data_index = 0;
+    eagle_data[data_index] = '\0';
+
+    if (postToPhant()) {
+      lastUpdateTime = now;
+    }
+  }
+
+  while (Serial.available()) {
+    char c = Serial.read();
+
+    // Assume a LF is the end of the line
+    if (c == '\n' && strlen(eagle_data) > 0) {
+      // Update once per minute
+      //
+      // Don't send any Eagle header messages we come across.  Also, make sure
+      // there's a : character in the string. It's always the 2nd or 3rd
+      // character so it goes a long way in assuming we have a full set of data.
+
+      unsigned long now = millis();
+
+      if ((now > lastUpdateTime + 60000 || now < lastUpdateTime) && strncmp(eagle_data, "RUNTIME", 7) != 0 && (eagle_data[1] == ':' || eagle_data[2] == ':')) {
+        if (postToPhant()) {
+          lastUpdateTime = now;
+        }
+      }
+
+      // Reset the data.  Hitting an LF should always do this, succesful send or not
+      data_index = 0;
+      eagle_data[data_index] = '\0';
+    } else if (c != '\r') {
+      // Capture everything else (but not a CR)
+      if (data_index < 80) {
+        eagle_data[data_index++] = c;
+      } else {
+        // This case should never happen, but avoid the overrun just the same :)
+        data_index = 0;
+      }
+      eagle_data[data_index] = '\0';
+    }
+
+    yield();    // Yeild to the ESP8266 here, just in case
+  }
+}
+


last tweaks

last tweaks

--- examples/attiny84/frankenmeter.ino
+++ examples/attiny84/frankenmeter.ino
@@ -3,10 +3,7 @@
  * (Can program with Arduino as ISP using one of these:
  * http://programmablehardware.blogspot.ie/2011/05/in-system-programming.html )
  */
-#include <stdint.h>
 #include <math.h>
-#include <avr/wdt.h>
-
 #include <Interrupted.h>

 // thermistor parameters
@@ -20,9 +17,9 @@

 typedef enum { cent, fahr, abso } units_t;

-#define IDLE		10000L
-#define DIGIT		500L
-#define DEBOUNCE	250L
+#define IDLE_MS		10000L
+#define DIGIT_MS	500L
+#define DEBOUNCE_MS	500L

 #define THERMISTOR	7
 #define SWITCH		1
@@ -33,7 +30,7 @@
 Analog thermistor(THERMISTOR, vcc);
 PinChangeGroup pins(PB);
 PinChange button(SWITCH, pins);
-Timer1 timer(TIMER, DIGIT);
+Timer1 timer(TIMER, DIGIT_MS);
 Devices devices;

 const uint8_t A = _BV(0);
@@ -144,7 +141,7 @@
 			digitalWrite(DIVIDER_GND, LOW);
 			thermistor.wake();
 			thermistor.enable();
-		} else if (now - last > DEBOUNCE) {
+		} else if (now - last > DEBOUNCE_MS) {
 			last = now;
 			if (units == cent)
 				units = fahr;
@@ -168,7 +165,7 @@
 		p = reformat(units, curr_temp, buf);
 		break;
 	}
-	if (now - last > IDLE) {
+	if (now - last > IDLE_MS) {
 		timer.enable(false);
 		thermistor.enable(false);
 		thermistor.sleep();


Update bme680tphg.ino

Update bme680tphg.ino

in-text title fixed

--- examples/bme680tphg/bme680tphg.ino
+++ examples/bme680tphg/bme680tphg.ino
@@ -1,6 +1,6 @@
 /**************************************************************************************

-This is example for ClosedCube HDC1080 Humidity and Temperature Sensor breakout booard
+This is an example for ClosedCube BME680 Humidity,Temperature,Pressure and Gas Sensor Breakout Board

 Initial Date: 15-Sep-2017


Keypad now working

Keypad now working

--- PixelVFO.ino
+++ PixelVFO.ino
@@ -100,11 +100,6 @@
 #define MENU_BG2            ILI9341_BLACK
 #define MENU_FG             ILI9341_BLACK

-// touchscreen stuff
-int ts_rotation = 0;
-int ts_width = SCREEN_WIDTH;
-int ts_height = SCREEN_HEIGHT;
-
 // the VFO states
 enum VFOState
 {
@@ -112,14 +107,17 @@
   VFO_Online
 };

-// store the VFO frequency here
+// touchscreen stuff
+//int ts_rotation = 0;
+int ts_width = SCREEN_WIDTH;
+int ts_height = SCREEN_HEIGHT;
+
+// state variables for frequency - display, etc
 // the characters in 'freq_display' are stored MSB at left (index 0)
-char freq_display[NUM_F_CHAR];          // digits of frequency, as binary values [0-9]
-unsigned long frequency;                // frequency as a long integer
-uint16_t char_x_offset[NUM_F_CHAR + 1]; // x offset for start/end of each character on display
-
-// index of selected digit in frequency display
-int freq_digit_select = -1;
+char freq_display[NUM_F_CHAR];                  // digits of frequency, as char values ['0'-'9']
+unsigned long frequency;                        // frequency as a long integer
+uint16_t freq_char_x_offset[NUM_F_CHAR + 1];    // x offset for start/end of each character on display
+int freq_digit_select = -1;                     // index of selected digit in frequency display

 uint32_t msraw = 0x80000000;
 #define MIN_REPEAT_PERIOD   100
@@ -170,6 +168,7 @@
 //-----------------------------------------------
 // Draw the frequency byte buffer to the screen.
 //     select  index of digit to highlight
+//
 // Updates all digits on the screen.  Skips leading zeros.
 //-----------------------------------------------

@@ -182,49 +181,19 @@
   for (int i = 0; i < NUM_F_CHAR; ++i)
   {
     if (i == select)
-      tft.fillRect(char_x_offset[i], 2, CHAR_WIDTH+2, DEPTH_FREQ_DISPLAY-4, FREQ_SEL_BG);
+      tft.fillRect(freq_char_x_offset[i], 2, CHAR_WIDTH+2, DEPTH_FREQ_DISPLAY-4, FREQ_SEL_BG);
     else
-      tft.fillRect(char_x_offset[i], 2, CHAR_WIDTH+2, DEPTH_FREQ_DISPLAY-4, FREQ_BG);
+      tft.fillRect(freq_char_x_offset[i], 2, CHAR_WIDTH+2, DEPTH_FREQ_DISPLAY-4, FREQ_BG);

     if ((freq_display[i] != '0') || !leading_space)
     {
-      tft.drawChar(char_x_offset[i], FREQ_OFFSET_Y, freq_display[i], FREQ_FG, FREQ_BG, 1);
+      tft.drawChar(freq_char_x_offset[i], FREQ_OFFSET_Y, freq_display[i], FREQ_FG, FREQ_BG, 1);
       leading_space = false;
     }
   }
 }

 //-----------------------------------------------
-// Set a digit of the frequency display.
-//     offset     offset into the frequency digits buffer
-//     new_digit  new digit, binary [0-9]
-// Also updates the top of screen display.
-//-----------------------------------------------
-
-void freq_set_digit(int offset, int new_digit)
-{
-  Serial.printf("freq_set_digit: offset=%d, new_digit=%d\n", offset, new_digit);
-  freq_display[offset] = new_digit;
-  tft.setFont(FONT_FREQ);
-  tft.drawChar(char_x_offset[offset], FREQ_OFFSET_Y,
-               freq_display[offset], FREQ_FG, FREQ_BG, 1);
-}
-
-//-----------------------------------------------
-// Draw a selected digit in the frequency display.
-//     select  index of digit to highlight
-//-----------------------------------------------
-
-void freq_select(int select)
-{
-  tft.fillRect(char_x_offset[select]-1, 2,
-               CHAR_WIDTH+1, DEPTH_FREQ_DISPLAY-4, FREQ_SEL_BG);
-  tft.setFont(FONT_FREQ);
-  tft.drawChar(char_x_offset[select], FREQ_OFFSET_Y,
-               freq_display[select], FREQ_FG, FREQ_BG, 1);
-}
-
-//-----------------------------------------------
 // Unselect a digit in the frequency display.
 //     select  index of digit to unselect
 //-----------------------------------------------
@@ -232,10 +201,10 @@
 void freq_unselect(int select)
 {
   Serial.printf("freq_unselect: select=%d\n", select);
-  tft.fillRect(char_x_offset[select]-1, 2,
+  tft.fillRect(freq_char_x_offset[select]-1, 2,
                CHAR_WIDTH+1, DEPTH_FREQ_DISPLAY-4, FREQ_BG);
   tft.setFont(FONT_FREQ);
-  tft.drawChar(char_x_offset[select], FREQ_OFFSET_Y,
+  tft.drawChar(freq_char_x_offset[select], FREQ_OFFSET_Y,
                freq_display[select], FREQ_FG, FREQ_BG, 1);
 }

@@ -261,6 +230,26 @@
 }

 //-----------------------------------------------
+// Gets an integer frequency from the frequency char buffer.
+//     buff  address of char buffer to fill
+//
+// Returns the buffer value as an unsigned long value.
+//-----------------------------------------------
+
+unsigned long freq_to_int(char *buff)
+{
+  unsigned long result = 0;
+
+  for (int i = 0; i < NUM_F_CHAR; ++i)
+  {
+    result = result * 10 + freq_display[i] - '0';
+  }
+
+
+  return result;
+}
+
+//-----------------------------------------------
 // Draw the frequency 'thousands' markers
 //-----------------------------------------------

@@ -301,8 +290,13 @@
   }
 }

-//-----------------------------------------------
-// Draw the Menu button.
+void undrawOnline(void)
+{
+  tft.fillRect(ONLINE_X, ONLINE_Y, ONLINE_WIDTH, ONLINE_HEIGHT, SCREEN_BG2);
+}
+
+//-----------------------------------------------
+// Draw and undraw the Menu button.
 //-----------------------------------------------

 void drawMenu(void)
@@ -315,6 +309,15 @@
   tft.print("Menu");
 }

+void undrawMenu(void)
+{
+  tft.fillRect(MENU_X, MENU_Y, MENU_WIDTH, MENU_HEIGHT, SCREEN_BG2);
+}
+
+//-----------------------------------------------
+// Draw the entire screen (the bits that don't change).
+//-----------------------------------------------
+
 void draw_screen(void)
 {
   tft.setFont(FONT_FREQ);
@@ -323,6 +326,7 @@
   tft.fillRect(0, DEPTH_FREQ_DISPLAY, tft.width(), SCREEN_HEIGHT-DEPTH_FREQ_DISPLAY, SCREEN_BG2);
   tft.setTextWrap(false);
   tft.fillRoundRect(0, 0, tft.width(), DEPTH_FREQ_DISPLAY, 5, FREQ_BG);
+  tft.fillRect(0, 0, tft.width(), DEPTH_FREQ_DISPLAY, FREQ_BG);
   tft.setCursor(MHZ_OFFSET_X, FREQ_OFFSET_Y);
   tft.setTextColor(FREQ_FG);
   tft.print("Hz");
@@ -390,11 +394,18 @@

 bool online_hs_handler(HotSpot *hs_ptr)
 {
+  // toggle state and redraw the button
   if (vfo_state == VFO_Standby)
+  {
     vfo_state = VFO_Online;
+    // TODO: set up DDS
+  }
   else
+  {
     vfo_state = VFO_Standby;
-
+    // TODO: turn off DDS
+  }
+
   drawOnline();

   return false;
@@ -416,7 +427,7 @@
 #define KEYPAD_H            (KEYPAD_MARGIN*5 + KEYPAD_BUTTON_H*4)
 #define KEYPAD_X            ((SCREEN_WIDTH - KEYPAD_W) / 2)
 #define KEYPAD_Y            (DEPTH_FREQ_DISPLAY + 1)
-#define KEYPAD_EDGE_COLOR   ILI9341_BLUE
+#define KEYPAD_BG           ILI9341_GREEN
 #define KEYPAD_FILL_COLOR   ILI9341_WHITE
 #define KEYPAD_BUTTON_W     44
 #define KEYPAD_BUTTON_H     44
@@ -432,13 +443,13 @@

 bool keypad_handler(HotSpot *hs)
 {
-  Serial.printf("keypad_handler: called, arg=%d\n", hs->arg);
-
-  freq_unselect(freq_digit_select);
-  freq_set_digit(freq_digit_select, hs->arg);
-  if (freq_digit_select < NUM_F_CHAR)
-    freq_digit_select += 1;
-  freq_select(freq_digit_select);
+  int arg = hs->arg;
+
+  freq_display[freq_digit_select] = '0' + arg;
+  freq_digit_select += 1;
+  if (freq_digit_select >= NUM_F_CHAR)
+    freq_digit_select = NUM_F_CHAR - 1;
+  freq_show(freq_digit_select);

   return false;
 }
@@ -458,6 +469,10 @@
 bool keypad_freq_handler(HotSpot *hs)
 {
   Serial.printf("keypad_freq_handler: called, arg=%d\n", hs->arg);
+
+  freq_digit_select = hs->arg;
+  freq_show(freq_digit_select);
+
   return false;
 }

@@ -505,9 +520,10 @@
                     KEYPAD_Y+KEYPAD_MARGIN+(KEYPAD_MARGIN+KEYPAD_BUTTON_H)*y+1,
                     KEYPAD_BUTTON_H-2, KEYPAD_BUTTON_H-2,
                     BUTTON_RADIUS, KEYPAD_FILL_COLOR);
-  tft.setCursor(KEYPAD_X+KEYPAD_MARGIN+(KEYPAD_MARGIN+KEYPAD_BUTTON_W)*x+1 + 14,
-                KEYPAD_Y+KEYPAD_MARGIN+(KEYPAD_MARGIN+KEYPAD_BUTTON_H)*y + 30);
-  tft.setFont(FONT_BUTTON);
+  tft.setCursor(KEYPAD_X+KEYPAD_MARGIN+(KEYPAD_MARGIN+KEYPAD_BUTTON_W)*x+1 + 8,
+                KEYPAD_Y+KEYPAD_MARGIN+(KEYPAD_MARGIN+KEYPAD_BUTTON_H)*y + 37);
+  //tft.setFont(FONT_BUTTON);
+    tft.setFont(FONT_FREQ);
   tft.setTextColor(STANDBY_FG);
   tft.print(ch);

@@ -517,18 +533,25 @@
 }

 //-----------------------------------------------
-// Draw the keypad.
+// Draw the keypad, handle interactions with it.
 //     offset  the index into the frequency buffer of digit to change.
+//
+// We highlight the digit we are going to change.
+// We have a small event loop here to handle the keypad.
 //-----------------------------------------------

 void keypad_show(int offset)
 {
   // highlight the frequency digit we are changing
-  freq_select(offset);
-
+  freq_show(offset);
+
+  // remove the online/menu buttons
+  undrawOnline();
+  undrawMenu();
+
   // draw keypad basic outline
   tft.fillRoundRect(KEYPAD_X, KEYPAD_Y, KEYPAD_W, KEYPAD_H, BUTTON_RADIUS, ILI9341_BLACK);
-  tft.fillRoundRect(KEYPAD_X+1, KEYPAD_Y+1, KEYPAD_W-2, KEYPAD_H-2, BUTTON_RADIUS, KEYPAD_EDGE_COLOR);
+  tft.fillRoundRect(KEYPAD_X+1, KEYPAD_Y+1, KEYPAD_W-2, KEYPAD_H-2, BUTTON_RADIUS, KEYPAD_BG);

   // draw buttons on the keypad
   for (int y = 0; y < 3; ++y)
@@ -538,8 +561,8 @@
       keypad_button_draw('0' + y*3 + x + 1, x, y);
     }
   }
-  keypad_button_draw('0', 1, 3);
-  keypad_button_draw('#', 2, 3);
+  keypad_button_draw('0', 1, 3);    // '0' is in non-linear place
+  keypad_button_draw('#', 2, 3);    // '#' is in non-linear place

   // event loop
   while (true)
@@ -550,10 +573,10 @@
     switch (event->event)
     {
       case event_Down:
-        Serial.printf("keypad_show: event %s\n", event2display(event));
         if (hs_handletouch(event->x, event->y, hs_keypad, KeypadHSLen))
         {
           Serial.printf("hs_handletouch() returned 'true', end of keypad\n");
+          //freq_show();
           return;
         }
         break;
@@ -578,11 +601,11 @@
   frequency = 1000000L;
   freq_to_buff(freq_display, 1000000L);

-  // initialize 'char_x_offset' array
+  // initialize 'freq_char_x_offset' array
   int x_offset = FREQ_OFFSET_X;
   for (int i = 0; i <= NUM_F_CHAR; ++i)
   {
-    char_x_offset[i] = x_offset;
+    freq_char_x_offset[i] = x_offset;
     x_offset += CHAR_WIDTH;
   }

@@ -603,7 +626,7 @@
 #if 0
   // draw the 'edge of digits' markers
   for (int i = 0; i <= NUM_F_CHAR; ++i)
-    tft.drawFastVLine(char_x_offset[i], 44, 6, ILI9341_RED);
+    tft.drawFastVLine(freq_char_x_offset[i], 44, 6, ILI9341_RED);
 #endif

   // show the frequency
@@ -630,7 +653,7 @@
           Serial.printf("hs_handletouch() returned 'true', refreshing display\n");
           draw_screen();
           freq_show();
-          event_flush();
+          //event_flush();
         }
         break;
       case event_None:


chmod

chmod


fix more whitespace issues

fix more whitespace issues

--- bot_base.ino
+++ bot_base.ino
@@ -131,7 +131,7 @@
   if(speed == 0 && direction) {
     finalSpeedLeft = direction;
     finalSpeedRight = -direction;
-	} else {
+  } else {
     finalSpeedLeft = speed * ((-255 - direction) / -255.0);
     finalSpeedRight = speed * ((255 - direction) / 255.0);

@@ -139,7 +139,7 @@
     if (speed > 0 && finalSpeedRight > speed){finalSpeedRight = speed;}
     if (speed < 0 && finalSpeedLeft < speed){finalSpeedLeft = speed;}
     if (speed < 0 && finalSpeedRight < speed){finalSpeedRight = speed;}
-	}
+  }
   // !! no ramping assumes your motor controllor does it !!
   leftWheel.writeMicroseconds(map(finalSpeedLeft,-255,255,1000,2000));
   rightWheel.writeMicroseconds(map(finalSpeedRight,-255,255,1000,2000));


set timeoff for pending state led blinking

--- client/client.ino
+++ client/client.ino
@@ -44,6 +44,7 @@
 unsigned long end_time;
 unsigned long toggle_time;
 unsigned long signal_time;
+unsigned long pendingThreshold = 10000;

 #define statusOff 0
 #define statusPending 1
@@ -73,6 +74,13 @@
 void loop()
 {
   //led control
+  if(mills() - start_time > pendingThreshold) {
+    //stop blinking after a period of time
+    digitalWrite(ledStatePin, LOW);
+    statePending = false;
+
+  }
+
   if(statePending) {
     end_time = millis();

@@ -122,11 +130,13 @@
           //set led blink fast
           statePending = true;
           ledStateInterval = 100;
+          start_time = millis();

         } else if(strcmp(p.data, "020") == 0) {
           //set led blink slow
           statePending = true;
           ledStateInterval = 600;
+          start_time = millis();

         }
       }


Re-copied test code

Re-copied test code

--- 2018-Firefighter-TestCode/2018-Firefighter-TestCode.ino
+++ 2018-Firefighter-TestCode/2018-Firefighter-TestCode.ino
@@ -14,7 +14,6 @@
 #define BABY_LED 17
 #define CAMERA 15
 #define CAMERA_LED 16
-#define GYRO_INPUT_PIN 18

 //Ultrasonic Trigger and Echo pins (30-39)
 #define F_L_ECHO  30  //Front-left Ultrasonic
@@ -66,12 +65,14 @@
   leftServo.write(135);
   rightServo.write(20); //Half power plus additional 25
   delay(100);
+  stopRobot();
 }

 void moveSlightRight() {
   leftServo.write(160); //Half power plus additional 25
   rightServo.write(45);
   delay(100);
+  stopRobot();
 }

 void stopRobot() {
@@ -93,18 +94,21 @@

 void stopExtinguisher(){
   extinguisher.write(90);
+  while(true){
+    digitalWrite(FLAME_LED, HIGH);
+  }
 }

 //Gyro functions
 //Resets the gyro so that the current positioning is angle "0"
 void resetGyro(){
-  gyroStartAngle = digitalRead(GYRO_PIN);
+  gyroStartAngle = getGyroRoll();
   gyroTargetAngle = 0;
 }

 //Returns the current angle of the robot relative to its starting angle
 float getGyroAngle(){
-  return digitalRead(GYRO_PIN)-gyroStartAngle;
+  return getGyroRoll()-gyroStartAngle;
 }

 //adjusts the target angle based on how much we want to turn and turns the robot until that target is reached
@@ -115,7 +119,7 @@
     gyroTargetAngle = 360 - gyroTargetAngle;
   }
   if(gyroTargetAngle < 0){
-    gyroTargetAngle = 360 + gyroTargetAngle
+    gyroTargetAngle = 360 + gyroTargetAngle;
   }
   if(gyroTargetAngle < getGyroAngle()){
     leftServo.write(180);
@@ -228,6 +232,8 @@
   extinguisher.write(90);

+
+
   pinMode(IR_PIN_LEFT, INPUT);
   pinMode(IR_PIN_RIGHT, INPUT);

@@ -235,17 +241,70 @@
   attachInterrupt(digitalPinToInterrupt(IR_PIN_RIGHT), extinguishFire, RISING);

   pinMode(FLAME_LED, OUTPUT);
+
   pinMode(MIC_LED, OUTPUT);
+
   pinMode(BABY_LED, OUTPUT);
+
   pinMode(CAMERA_LED, OUTPUT);
-  pinMode(GYRO, INPUT);
+
+  setup_gyro();
+
   FreqCount.begin(1000); // Begin measuring sound
 }

 void loop() {
-  rollForward();
-}
-
-void extinguishFire() {
-  rollBackward();
-}
+// put your main code here, to run repeatedly:
+
+  if (checkingMicrophone) {   //Robot doesn't start until it hears the start frequency
+    checkMicrophone();
+  }
+
+  startUp();
+  levelOneNav();
+  delay(100);
+
+  /* if (usingCamera()){    //Only used for CV
+    digitalWrite(CAMERA_LED, HIGH);
+  } else {
+    digitalWrite(CAMERA_LED, LOW);
+  }
+
+  if(detectBaby()){
+    digitalWrite(BABY_LED, HIGH);
+  } else {
+    digitalWrite(BABY_LED, LOW);
+  } */
+
+
+  /* if (robotOn) {     //Not entirely sure what this code is for
+
+    extinguishFire();
+
+    delay(100);
+
+    if (detectFire()){
+      digitalWrite(FLAME_LED, HIGH);
+    } else {
+      digitalWrite(FLAME_LED, LOW);
+    }
+
+    if (usingCamera()){
+      digitalWrite(CAMERA_LED, HIGH);
+    } else {
+      digitalWrite(CAMERA_LED, LOW);
+    }
+
+    if(detectBaby()){
+      digitalWrite(BABY_LED, HIGH);
+    } else {
+      digitalWrite(BABY_LED, LOW);
+    }
+
+    if(hearingStartSound){
+      digitalWrite(MIC_LED, HIGH);
+    } else {
+      digitalWrite(MIC_LED, LOW);
+    }
+  } */
+}


completed initial driveUnit, fix temp scale, misc variable optimizations

--- ardustat.ino
+++ ardustat.ino
@@ -37,16 +37,16 @@
 const int offset = 50; // 5

 // HVAC system parameters
-const int fanDelay = 6000; // ms
+const unsigned long fanDelay = 60000; // ms, 1 minute
+const unsigned long cycleOn = 900000; // ms, 15 minutes
+const unsigned long cycleOff = 2700000; // ms, 45 minutes
+

 // global variables used in the loops
 int centerpoint;
 uint8_t mode;

 void setup(void) {
-    // variable declaration
-    uint8_t check;
-
     // setup digital pins
     pinMode(buttonUp, INPUT); // is default
     pinMode(buttonDwn, INPUT); // is default
@@ -62,8 +62,7 @@
     // if it's there, load the previous settings
     // otherwise use the defaults and write them to EEPROM
     // note that mode only stores either "on" or "off"
-    check = EEPROM.read(eepCheckAddr);
-    if (check == eepCheckVal) {
+    if (eepCheckVal == EEPROM.read(eepCheckAddr)) {
         Serial.println(F("Using mode and temperature from EEPROM"));
         mode = EEPROM.read(eepModeAddr);
         centerpoint = getEEPROMint(eepCenterpointAddr);
@@ -92,7 +91,7 @@

     // if this is first time button is pressed, move the setpoint
     // if both buttons are pressed, toggle system on and off and save to eeprom
-    // TODO: write this as an interrupt?
+    // write this as an interrupt someday?
     if ((stateUp == LOW) && (stateDwn == LOW) && (prevUp != LOW) && (prevDwn != LOW)) {
         if (mode == off) {
             mode = on;
@@ -179,7 +178,7 @@
     Serial.print(F("   deg C: "));
     Serial.print(tempC);

-    return int(tempF * 10);
+    return int(tempF * 10.0);
 }

@@ -193,7 +192,7 @@
     Args:
         unit (uint8_t): which HVAC function to activate, or off for all off
     Returns:
-        none
+        None

     wiring notes:
     red wire - 24V hot
@@ -202,71 +201,103 @@
     yellow wire - cooling
     white wire - heating
     */
-    static unsigned long timeFan = 0;
+    static unsigned long timeFanOn = 0;
     unsigned long timeCurrent = millis();

     switch(unit) {
         case cool:
-            if ((timeCurrent - timeFan) < fanDelay) {
-                driveUnit(fan);
-            } else {
+            // we must always be sure that fan is on before AC
+            driveUnit(fan);
+            // dwell for fanDelay ms if turning it on first time
+            if ((timeCurrent - timeFanOn) > fanDelay) {
+                // only write to pin if not already on
                 if (digitalRead(relayAC) != HIGH) {
                     digitalWrite(relayAC, HIGH);
                 }
             }
             break;
         case heat:
-            if ((timeCurrent - timeFan) < fanDelay) {
-                driveUnit(fan);
-            } else {
+            // heat operates exactly the same way as cool
+            driveUnit(fan);
+            if ((timeCurrent - timeFanOn) > fanDelay) {
                 if (digitalRead(relayHeat) != HIGH) {
                     digitalWrite(relayHeat, HIGH);
                 }
             }
             break;
         case fan:
+             // turn on fan and record time that we do so, only if fan not on
             if (digitalRead(relayFan) != HIGH) {
-                timeFan = timeCurrent;
+                timeFanOn = timeCurrent;
                 digitalWrite(relayFan, HIGH);
             }
             break;
         case shutdown:
-
+            // turn off other units, then purge vents for fanDelay ms
+            // shutdown is only ever the mode set for exactly 1 loop run
+            // it is followed by cycle, abuse the timing state var and let
+            // cycle shut off the fan after fanDelay time
+            timeFanOn = (timeCurrent - cycleOn) + fanDelay;
+            digitalWrite(relayAC, LOW);
+            digitalWrite(relayHeat, LOW);
+            break;
+        case cycle:
+            // run the fan periodically
+            if ((timeCurrent - timeFanOn) > cycleOff) {
+                driveUnit(fan);
+            } else if ((timeCurrent - timeFanOn) > cycleOn) {
+                digitalWrite(relayFan, LOW);
+            }
+            break;
         default:
+            // this is used for "off" and "on" and anything broken
             digitalWrite(relayFan, LOW);
             digitalWrite(relayAC, LOW);
             digitalWrite(relayHeat, LOW);
-            break;
     }
 }

 int getEEPROMint(int address) {
-    uint8_t hiByte, loByte;
-
-    hiByte = EEPROM.read(address);
-    loByte = EEPROM.read(address + 1);
-
-    return word(hiByte, loByte);
+    /*
+    This function retrieves an int stored in EEPROM starting at address provided
+
+    Arguments:
+        address (int):  EEPROM byte to begin reading first byte from
+    Returns:
+        value (int):  integer stored in the EEPROM
+    */
+    return word(EEPROM.read(address), EEPROM.read(address + 1));
 }

 void setEEPROMint(int address, int value) {
-    uint8_t hiByte, loByte;
-
-    hiByte = highByte(value);
-    loByte = lowByte(value);
-
-    if (EEPROM.read(address) != hiByte) {
-        EEPROM.write(address, hiByte);
-    }
-    if (EEPROM.read(address + 1) != loByte) {
-        EEPROM.write(address + 1, loByte);
-    }
+    /*
+    This function stores an int in EEPROM starting at address provided,
+    but only if value is different than presently stored
+
+    Arguments:
+        address (int):  EEPROM byte to begin storage at
+        value (int):  integer value to store
+    Returns:
+        None
+    */
+    setEEPROMbyte(address, highByte(value));
+    setEEPROMbyte(address + 1, lowByte(value));
 }

 void setEEPROMbyte(int address, uint8_t value) {
+    /*
+    This function stores a byte in EEPROM at address provided,
+    but only if value is different than presently stored
+
+    Arguments:
+        address (int):  EEPROM byte to begin storage at
+        value (uint8_t):  byte value to store
+    Returns:
+        None
+    */
     if (EEPROM.read(address) != value) {
         EEPROM.write(address, value);
     }


Support ATTiny84 and ATTiny85 MCUs

Support ATTiny84 and ATTiny85 MCUs

--- ArduinoPrototype/ArduinoPrototype.ino
+++ ArduinoPrototype/ArduinoPrototype.ino
@@ -3,6 +3,9 @@
 const int CLOCKWISE = 1;
 const int COUNTER_CLOCKWISE = 0;

+#if defined(__AVR_ATmega328P__)
+
+// Arduino Pins
 const int speedInPin = A0;
 const int rateOfSpeedChangeInPin = A1;
 const int speedOutPin = 9;
@@ -10,35 +13,85 @@
 const int directionSwitchInPin = 6;
 const int directionOutputPin = 5;

+#elif defined( __AVR_ATtinyX4__ )
+
+// ATMEL ATTINY84 / arduino-tiny mapping
+//
+//                           +-\/-+
+//                     VCC  1|    |14  GND
+//             (D  0)  PB0  2|    |13  AREF (D 10) (A 0)
+//             (D  1)  PB1  3|    |12  PA1  (D  9) (A 1)
+//       RESET         PB3  4|    |11  PA2  (D  8) (A 2)
+//  PWM  INT0  (D  2)  PB2  5|    |10  PA3  (D  7) (A 3)
+//  PWM  (A 7) (D  3)  PA7  6|    |9   PA4  (D  6) (A 4)
+//  PWM  (A 6) (D  4)  PA6  7|    |8   PA5  (D  5) (A 5)   PWM
+//                           +----+
+//
+const int speedInPin = A0;
+const int rateOfSpeedChangeInPin = A1;
+const int speedOutPin = 5;
+const int onOffSwitchInPin = 7;
+const int directionSwitchInPin = 8;
+const int directionOutputPin = 6;
+
+#elif defined( __AVR_ATtinyX5__ )
+
+// ATMEL ATTINY85 / arduino-tiny mapping
+//                           +-\/-+
+//  Ain0       (D  5)  PB5  1|    |8   VCC
+//  Ain3       (D  3)  PB3  2|    |7   PB2  (D  2)  INT0  Ain1
+//  Ain2       (D  4)  PB4  3|    |6   PB1  (D  1)        pwm1
+//                     GND  4|    |5   PB0  (D  0)        pwm0
+//                           +----+
+//
+// NOTE!!!! This requires use of the RESET pin so either RSTDISBL fuse must be set
+// which prevents normal reprogramming or the rateOfChange pot has to be used as a
+// rheostat and as R1 of a voltage divider so that the voltage on A0 never goes
+// below ~1.5V and resets the MCU.
+//
+const int speedInPin = A3;
+const int rateOfSpeedChangeInPin = A0;
+const int speedOutPin = 0;
+const int onOffSwitchInPin = 2;
+const int directionSwitchInPin = 1;
+const int directionOutputPin = 4;
+
+#endif
+
+// Settings and limits
 const int switchDebounceTime = 30;
 const int minimumDelay = 5;
 const int maximumDelay = 40;
 const int minimumSpeed = 10;
 // 10K ohm potentiometers probably won't get all the way to 1024
+// and we want to make sure that max feasible input = max motor speed
 const int potentiometerCeiling = 1000;
+// For prototyping we want to avoid disabling RESET so we need to arrange
+// the circuit to keep a minimum voltage so we don't RESET the MCU.
+// For production we'll change the fuses and set this to 0.
+const int rateOfSpeedChangePotentiometerFloor = 800;

+// Switches using the Bounce library for debouncing
 Bounce onOffSwitch = Bounce(onOffSwitchInPin, switchDebounceTime);
 Bounce directionSwitch = Bounce(directionSwitchInPin, switchDebounceTime);

-int speedTarget = 0;
-int rateOfSpeedChange = 0;
+// State variables
+int targetSpeed = 0;
 int currentSpeed = 0;
 int delayBetweenAdjustments = 15;
 boolean powerEnabled = false;
-int directionTarget = CLOCKWISE;
+int targetDirection = CLOCKWISE;
 int currentDirection = CLOCKWISE;
-
-int debugOutputCounter = 0;

 void setup()
 {
   pinMode(onOffSwitchInPin, INPUT_PULLUP);
   pinMode(directionSwitchInPin, INPUT_PULLUP);
   pinMode(directionOutputPin, OUTPUT);
+  // We don't have to set pin mode for analog inputs

-  digitalWrite(directionOutputPin, directionTarget);
-
-  Serial.begin(9600);
+  // TODO: check startup logic to make sure this is right
+  digitalWrite(directionOutputPin, targetDirection);
 }

 void loop()
@@ -51,69 +104,58 @@

   if (powerEnabled)
   {
-    speedTarget = ReadPotentiometer(speedInPin);
-    speedTarget = map(speedTarget, 0, potentiometerCeiling, minimumSpeed, 255);
+    targetSpeed = ReadPotentiometer(speedInPin);
+    targetSpeed = map(targetSpeed, 0, potentiometerCeiling, minimumSpeed, 255);

     delayBetweenAdjustments = ReadPotentiometer(rateOfSpeedChangeInPin);
-    delayBetweenAdjustments = map(delayBetweenAdjustments, 0, potentiometerCeiling, minimumDelay, maximumDelay);
+    delayBetweenAdjustments = constrain(delayBetweenAdjustments, rateOfSpeedChangePotentiometerFloor, potentiometerCeiling);
+    delayBetweenAdjustments = map(delayBetweenAdjustments, rateOfSpeedChangePotentiometerFloor, potentiometerCeiling, minimumDelay, maximumDelay);
   }
   else
   {
-    speedTarget = 0;
+    targetSpeed = 0;
   }

   directionSwitch.update();
-  directionTarget = directionSwitch.read();
+  targetDirection = directionSwitch.read();

-  if (directionTarget == CLOCKWISE)
+  if (targetDirection == CLOCKWISE)
   {
-    speedTarget = abs(speedTarget);
+    targetSpeed = abs(targetSpeed);
   }
   else
   {
-    speedTarget = -abs(speedTarget);
+    targetSpeed = -abs(targetSpeed);
   }

-  if (currentSpeed == 0 && currentDirection != directionTarget)
+  if (currentSpeed == 0 && currentDirection != targetDirection)
   {
     // We're at zero speed and want to switch directions.
     // The motor spec sheet says we have to wait .5 seconds before
-    // switching.
+    // switching to make sure that the motor has come to a full stop.

-    // TODO: can we just write direction on every loop based on the sign of the speed?
+    // TODO: do we need to hit the run/stop control line in order to
+    // guarentee that the motor is stopped?

     delay(500);
-    digitalWrite(directionOutputPin, directionTarget);
-    currentDirection = directionTarget;
+    digitalWrite(directionOutputPin, targetDirection);
+    currentDirection = targetDirection;
   }

-  currentSpeed += SlewToward(currentSpeed, speedTarget);
+  currentSpeed += SlewToward(currentSpeed, targetSpeed);
   analogWrite(speedOutPin, abs(currentSpeed));
-
-//  if (debugOutputCounter++ == 20)
-//  {
-//    debugOutputCounter = 0;
-//    Serial.print("currentSpeed = " );
-//    Serial.print(currentSpeed);
-//    Serial.print("\t target = ");
-//    Serial.print(speedTarget);
-//    Serial.print("\t delayBetweenAdjustments = ");
-//    Serial.println(delayBetweenAdjustments);
-//  }

+  // Rather than trying to write a fixed-delay loop we're being lazy and using a
+  // variable-deplay loop to control the rate at which we change the motor speed.
+  // This should be fine because we don't have anything urgent that we need to do
+  // in between adjustments anyway and the input response lag even at maximum delay
+  // will never be noticable to the user.
   delay(delayBetweenAdjustments);
-}
-
-boolean ReadSwitch(int pin)
-{
-  return !digitalRead(pin);
 }

 int ReadPotentiometer(int pin)
 {
-  int value;
-
-  value = analogRead(pin);
+  int value = analogRead(pin);
   value = constrain(value, 0, potentiometerCeiling);

   return value;


Added logic to cycle between DR0-5, added additional logging to show on the serial console which helps analyzing issues

    * examples/SodaqOne-TTN-Mapper-binary/SodaqOne-TTN-Mapper-binary.ino:

--- examples/SodaqOne-TTN-Mapper-binary/SodaqOne-TTN-Mapper-binary.ino
+++ examples/SodaqOne-TTN-Mapper-binary/SodaqOne-TTN-Mapper-binary.ino
@@ -1,3 +1,5 @@
+#include <rn2xx3.h>
+
 /*
  * Author: JP Meijers
  * Date: 2016-09-02
@@ -37,6 +39,7 @@
 uint32_t LatitudeBinary, LongitudeBinary;
 uint16_t altitudeGps;
 uint8_t hdopGps;
+int dr = 0;

 void setup()
 {
@@ -60,7 +63,6 @@
     // initialize GPS
     sodaq_gps.init(GPS_ENABLE);

-    // myLora.setDR(0); //set the datarate at which we measure. DR7 is the best.
     pinMode(LED_BLUE, OUTPUT);
     digitalWrite(LED_BLUE, HIGH);
     pinMode(LED_RED, OUTPUT);
@@ -107,6 +109,7 @@
     join_result = myLora.init();
     digitalWrite(LED_BLUE, HIGH);
   }
+
   SerialUSB.println("Successfully joined TTN");

 }
@@ -121,6 +124,8 @@

   while(sodaq_gps.getLat()==0.0)
   {
+    SerialUSB.println("Lattide still 0.0, doing another scan");
+
     digitalWrite(LED_RED, LOW);
     sodaq_gps.scan();
     digitalWrite(LED_RED, HIGH);
@@ -152,9 +157,25 @@
     toLog = toLog + String(buffer);
   }

+  SerialUSB.print("Transmit on DR");
+  SerialUSB.print(dr);
+  SerialUSB.print(" coordinates ");
+  SerialUSB.print(sodaq_gps.getLat(), 13);
+  SerialUSB.print(" ");
+  SerialUSB.print(sodaq_gps.getLon(), 13);
+  SerialUSB.print(" altitude ");
+  SerialUSB.print(sodaq_gps.getAlt(), 1);
+  SerialUSB.print(" and HDOP ");
+  SerialUSB.print(sodaq_gps.getHDOP(), 2);
+  SerialUSB.print(" hex ");
   SerialUSB.println(toLog);
+
   digitalWrite(LED_BLUE, LOW);
   myLora.txBytes(txBuffer, sizeof(txBuffer));
   digitalWrite(LED_BLUE, HIGH);
+
+  // Cycle between datarate 0 and 5
+  dr = (++dr) % 6;
+  myLora.setDR(dr);
   SerialUSB.println("TX done");
 }


changed system LED init

changed system LED init

--- T4/src/AFE-Firmware-T4.ino
+++ T4/src/AFE-Firmware-T4.ino
@@ -63,7 +63,10 @@
   Network.begin(Device.getMode());

   /* Initializing LED, checking if LED exists is made on Class level  */
-  Led.begin(0);
+  uint8_t systeLedID = Data.getSystemLedID();
+  if (systeLedID > 0) {
+    Led.begin(systeLedID - 1);
+  }

   /* If device in configuration mode then start LED blinking */
   if (Device.getMode() != MODE_NORMAL) {


Add modes for making lights appear twinkly

--- Arduino/LightPlayer/LightPlayer.ino
+++ Arduino/LightPlayer/LightPlayer.ino
@@ -58,6 +58,10 @@
   uint8_t cycle_floor_green;
   uint8_t cycle_floor_blue;

+  uint8_t twinkle_red;
+  uint8_t twinkle_green;
+  uint8_t twinkle_blue;
+
   uint8_t reduce_speed;
   uint8_t increase_speed;
   uint8_t toggle_pause;
@@ -126,6 +130,8 @@
 const int SKIP_SECONDS = 60;
 const int FPS = 20;
 const int32_t SKIP_BYTES = int32_t(sizeof(frame)) * FPS * SKIP_SECONDS;
+
+const int TWINKLE_AMOUNT = 2;

 //------------------------------------------------------------------------------
 // File system object.
@@ -219,6 +225,9 @@
   if (ops.cycle_floor_red)     Serial.print(F("\ncycle_floor_red"));
   if (ops.cycle_floor_green)   Serial.print(F("\ncycle_floor_green"));
   if (ops.cycle_floor_blue)    Serial.print(F("\ncycle_floor_blue"));
+  if (ops.twinkle_red)         Serial.print(F("\ntwinkle_red"));
+  if (ops.twinkle_green)       Serial.print(F("\ntwinkle_green"));
+  if (ops.twinkle_blue)        Serial.print(F("\ntwinkle_blue"));
   if (ops.reduce_speed)        Serial.print(F("\nreduce_speed"));
   if (ops.increase_speed)      Serial.print(F("\nincrease_speed"));
   if (ops.toggle_pause)        Serial.print(F("\ntoggle_pause"));
@@ -263,6 +272,18 @@
   frame_len = 0;
 }

+void twinkleMode(ColorIntensity & high)
+{
+  r_intensity.floor = ColorIntensity::MIN;
+  g_intensity.floor = ColorIntensity::MIN;
+  b_intensity.floor = ColorIntensity::MIN;
+  r_intensity.ceil = ColorIntensity::MIN + TWINKLE_AMOUNT;
+  g_intensity.ceil = ColorIntensity::MIN + TWINKLE_AMOUNT;
+  b_intensity.ceil = ColorIntensity::MIN + TWINKLE_AMOUNT;
+  high.floor = high.ceil;
+  high.ceil = ColorIntensity::MAX;
+}
+
 void performPendingOperations(PendingOperations & ops)
 {
 #ifdef DEBUG
@@ -278,6 +299,9 @@
   if (ops.cycle_floor_red)     r_intensity.raiseFloor();
   if (ops.cycle_floor_green)   g_intensity.raiseFloor();
   if (ops.cycle_floor_blue)    b_intensity.raiseFloor();
+  if (ops.twinkle_red)         twinkleMode(r_intensity);
+  if (ops.twinkle_green)       twinkleMode(g_intensity);
+  if (ops.twinkle_blue)        twinkleMode(b_intensity);
   if (ops.reduce_speed)        speed = max(speed-1, MIN_SPEED);
   if (ops.increase_speed)      speed = min(speed+1, MAX_SPEED);
   if (ops.toggle_pause)        speed = (speed == -1 ? 0 : -1);
@@ -296,6 +320,9 @@
        || ops.cycle_floor_red
        || ops.cycle_floor_green
        || ops.cycle_floor_blue
+       || ops.twinkle_red
+       || ops.twinkle_green
+       || ops.twinkle_blue
        || ops.reduce_speed
        || ops.increase_speed
        || ops.toggle_pause
@@ -433,6 +460,18 @@

         case Pressed::b: {
           GlobalPendingOperations.reset_settings = 1;
+        } break;
+
+        case Pressed::ad: {
+          GlobalPendingOperations.twinkle_red = 1;
+        } break;
+
+        case Pressed::bd: {
+          GlobalPendingOperations.twinkle_green = 1;
+        } break;
+
+        case Pressed::cd: {
+          GlobalPendingOperations.twinkle_blue = 1;
         } break;
       }
     } break;


Use interrupts to handle button presses

Use interrupts to handle button presses

Rather than polling the state of RF receiver button pins periodically,
set up a pin change interrupt to detect button presses.

--- Arduino/LightPlayer/LightPlayer.ino
+++ Arduino/LightPlayer/LightPlayer.ino
@@ -15,25 +15,24 @@
 // analog 2 - RF remote button B
 // analog 3 - RF remote button A

-namespace Pressed {
-  const int none = 0;
-  const int a    = 8;
-  const int b    = 4;
-  const int c    = 2;
-  const int d    = 1;
-  const int abcd = a|b|c|d;
-  const int abc  = a|b|c;
-  const int abd  = a|b|d;
-  const int ab   = a|b;
-  const int acd  = a|c|d;
-  const int ac   = a|c;
-  const int ad   = a|d;
-  const int bcd  = b|c|d;
-  const int bc   = b|c;
-  const int bd   = b|d;
-  const int cd   = c|d;
-  const int all  = abcd;
-}
+enum class Pressed : uint8_t {
+  none = 0,
+  a    = 8,
+  b    = 4,
+  c    = 2,
+  d    = 1,
+  abcd = a|b|c|d,
+  abc  = a|b|c,
+  abd  = a|b|d,
+  ab   = a|b,
+  acd  = a|c|d,
+  ac   = a|c,
+  ad   = a|d,
+  bcd  = b|c|d,
+  bc   = b|c,
+  bd   = b|d,
+  cd   = c|d,
+};

 enum {
   NORMAL_MODE,
@@ -43,6 +42,25 @@
   MACRO_MODE,
   MISC_MODE,
 } Mode;
+
+struct PendingOperations
+{
+  uint8_t cycle_brightness;
+  uint8_t skip_video;
+
+  uint8_t cycle_ceiling_red;
+  uint8_t cycle_ceiling_green;
+  uint8_t cycle_ceiling_blue;
+
+  uint8_t cycle_floor_red;
+  uint8_t cycle_floor_green;
+  uint8_t cycle_floor_blue;
+
+  uint8_t toggle_negative;
+  uint8_t reset_settings;
+};
+
+volatile PendingOperations GlobalPendingOperations;

 apa106<D, 6>   LEDstrip;
 rgb frame[200];
@@ -153,10 +171,28 @@
   sd.ls();

   nextFile();
-}
-
-#ifdef DEBUG
-void printSettingsIfDebug()
+  startMillis = millis();
+
+  PCMSK1 = B1111; // Enable interrupts for inputs A0, A1, A2, A3
+  PCIFR  |= bit(PCIF1);   // clear any outstanding interrupts
+  PCICR  |= bit(PCIE1);   // enable pin change interrupts for D8 to D13
+}
+
+void printPendingOperations(PendingOperations & ops)
+{
+  if (ops.cycle_brightness)    Serial.print(F("\ncycle_brightness"));
+  if (ops.skip_video)          Serial.print(F("\nskip_video"));
+  if (ops.cycle_ceiling_red)   Serial.print(F("\ncycle_ceiling_red"));
+  if (ops.cycle_ceiling_green) Serial.print(F("\ncycle_ceiling_green"));
+  if (ops.cycle_ceiling_blue)  Serial.print(F("\ncycle_ceiling_blue"));
+  if (ops.cycle_floor_red)     Serial.print(F("\ncycle_floor_red"));
+  if (ops.cycle_floor_green)   Serial.print(F("\ncycle_floor_green"));
+  if (ops.cycle_floor_blue)    Serial.print(F("\ncycle_floor_blue"));
+  if (ops.toggle_negative)     Serial.print(F("\ntoggle_negative"));
+  if (ops.reset_settings)      Serial.print(F("\nreset_settings"));
+}
+
+void printSettings()
 {
   Serial.print(F("\nMode: "));
   Serial.print(Mode);
@@ -177,11 +213,6 @@
   Serial.print(F(" neg "));
   Serial.print(negative);
 }
-#else
-inline void printSettingsIfDebug()
-{
-}
-#endif

 void resetDefaultSettings()
 {
@@ -192,50 +223,55 @@
   negative = 0;
 }

-void handleRfRemoteButtons()
-{
-  static int old_button_states = Pressed::all;
-  int button_states = PINC & B1111;
-
-  if (button_states == old_button_states) {
-    return;
-  }
-  old_button_states = button_states;
-
+void performPendingOperations(PendingOperations & ops)
+{
 #ifdef DEBUG
-  Serial.print(F("\nPressed buttons: "));
-  switch (button_states) {
-    case Pressed::none: Serial.print(F("NONE")); break;
-    case Pressed::d:    Serial.print(F("   D")); break;
-    case Pressed::c:    Serial.print(F("  C ")); break;
-    case Pressed::cd:   Serial.print(F("  CD")); break;
-    case Pressed::b:    Serial.print(F(" B  ")); break;
-    case Pressed::bd:   Serial.print(F(" B D")); break;
-    case Pressed::bc:   Serial.print(F(" BC ")); break;
-    case Pressed::bcd:  Serial.print(F(" BCD")); break;
-    case Pressed::a:    Serial.print(F("A   ")); break;
-    case Pressed::ad:   Serial.print(F("A  D")); break;
-    case Pressed::ac:   Serial.print(F("A C ")); break;
-    case Pressed::acd:  Serial.print(F("A CD")); break;
-    case Pressed::ab:   Serial.print(F("AB  ")); break;
-    case Pressed::abd:  Serial.print(F("AB D")); break;
-    case Pressed::abc:  Serial.print(F("ABC ")); break;
-    case Pressed::abcd: Serial.print(F("ABCD")); break;
-  }
+  printPendingOperations(ops);
 #endif
+
+  if (ops.cycle_brightness)    brightness -= BRIGHTNESS_STEP;
+  if (ops.skip_video)          infile.close();
+  if (ops.cycle_ceiling_red)   r_intensity.lowerCeil();
+  if (ops.cycle_ceiling_green) g_intensity.lowerCeil();
+  if (ops.cycle_ceiling_blue)  b_intensity.lowerCeil();
+  if (ops.cycle_floor_red)     r_intensity.raiseFloor();
+  if (ops.cycle_floor_green)   g_intensity.raiseFloor();
+  if (ops.cycle_floor_blue)    b_intensity.raiseFloor();
+  if (ops.toggle_negative)     negative = !negative;
+  if (ops.reset_settings)      resetDefaultSettings();
+
+#ifdef DEBUG
+  if (    ops.cycle_brightness
+       || ops.skip_video
+       || ops.cycle_ceiling_red
+       || ops.cycle_ceiling_green
+       || ops.cycle_ceiling_blue
+       || ops.cycle_floor_red
+       || ops.cycle_floor_green
+       || ops.cycle_floor_blue
+       || ops.toggle_negative
+       || ops.reset_settings)
+  {
+    printSettings();
+  }
+#endif
+}
+
+ISR(PCINT1_vect) // handle pin change interrupt for A0 to A5
+{
+  // Atomically read pins A0-A5, mask off A4 and A5, and represent
+  // the states of A0, A1, A2, and A3 as a Pressed enum object
+  auto button_states = static_cast<Pressed>(PINC & B1111);

   switch(Mode) {
     case NORMAL_MODE: {
       switch (button_states) {
-        case Pressed::d:
-        default: return;
-
         case Pressed::a: {
-          brightness -= BRIGHTNESS_STEP; // overflow to 255 at zero
+          GlobalPendingOperations.cycle_brightness = 1;
         } break;

         case Pressed::b: {
-          nextFile();
+          GlobalPendingOperations.skip_video = 1;
         } break;

         case Pressed::ab: {
@@ -254,35 +290,61 @@

     case COLOR_CEILING_MODE: {
       switch (button_states) {
-        case Pressed::d: Mode = NORMAL_MODE;
-        default: return;
-        case Pressed::a: r_intensity.lowerCeil(); break;
-        case Pressed::b: g_intensity.lowerCeil(); break;
-        case Pressed::c: b_intensity.lowerCeil(); break;
+        case Pressed::d: {
+          Mode = NORMAL_MODE;
+        } break;
+
+        case Pressed::a: {
+          GlobalPendingOperations.cycle_ceiling_red = 1;
+        } break;
+
+        case Pressed::b: {
+          GlobalPendingOperations.cycle_ceiling_green = 1;
+        } break;
+
+        case Pressed::c: {
+          GlobalPendingOperations.cycle_ceiling_blue = 1;
+        } break;
+
       }
     } break;

     case COLOR_FLOOR_MODE: {
       switch (button_states) {
-        case Pressed::d: Mode = NORMAL_MODE;
-        default: return;
-        case Pressed::a: r_intensity.raiseFloor(); break;
-        case Pressed::b: g_intensity.raiseFloor(); break;
-        case Pressed::c: b_intensity.raiseFloor(); break;
+        case Pressed::d: {
+          Mode = NORMAL_MODE;
+        } break;
+
+        case Pressed::a: {
+          GlobalPendingOperations.cycle_floor_red = 1;
+        } break;
+
+        case Pressed::b: {
+          GlobalPendingOperations.cycle_floor_green = 1;
+        } break;
+
+        case Pressed::c: {
+          GlobalPendingOperations.cycle_floor_blue = 1;
+        } break;
       }
     } break;

     case MISC_MODE: {
       switch (button_states) {
-        case Pressed::d: Mode = NORMAL_MODE;
-        default: return;
-        case Pressed::a: negative = !negative; break;
-        case Pressed::b: resetDefaultSettings(); break;
+        case Pressed::d: {
+          Mode = NORMAL_MODE;
+        } break;
+
+        case Pressed::a: {
+          GlobalPendingOperations.toggle_negative = 1;
+        } break;
+
+        case Pressed::b: {
+          GlobalPendingOperations.reset_settings = 1;
+        } break;
       }
     } break;
   }
-
-  printSettingsIfDebug();
 }

 void nextFile()
@@ -300,7 +362,6 @@
         infile.getName(buf, sizeof(buf));
         cout << F("\nOpened file: ") << buf;
 #endif
-        startMillis = millis();
         return;
       }
       infile.close();
@@ -334,20 +395,21 @@

 void loop()
 {
-  handleRfRemoteButtons();
-
   if (!readFrame()) {
     nextFile();
+    startMillis = millis();
     return;
   }

-  handleRfRemoteButtons();
+  PendingOperations pending_operations;
+  noInterrupts();
+  memcpy(&pending_operations, &GlobalPendingOperations, sizeof(pending_operations));
+  memset(&GlobalPendingOperations, 0, sizeof(GlobalPendingOperations));
+  interrupts();
+
+  performPendingOperations(pending_operations);

   adjustFrameColors();
-
-  while (millis() - startMillis < 49UL) {
-    handleRfRemoteButtons();
-  }

   while (millis() - startMillis < 50UL) {
     // busy loop until its time to paint the lights


fix to fit documentation

fix to fit documentation

--- ArduinoRF24-LED/ArduinoRF24-LED.ino
+++ ArduinoRF24-LED/ArduinoRF24-LED.ino
@@ -127,14 +127,12 @@
                 led_num = led_num % LED_NUM;
                 digitalWrite(led_pins[led_num], HIGH);
                 write_buffer[0] = 0x00;
-                write_buffer[9] = 0x01;
                 break;
             case 0x03:
                 led_num = read_buffer[9];
                 led_num = led_num % LED_NUM;
                 digitalWrite(led_pins[led_num], LOW);
                 write_buffer[0] = 0x00;
-                write_buffer[9] = 0x01;
                 break;
             case 0x04:
                 write_buffer[9] = digitalRead(led_pins[3]);


Fixed PreallocatedFile::close().

Fixed PreallocatedFile::close().

File was truncated to wrong length.

--- SdFatSDIO_low_latency_logger.ino
+++ SdFatSDIO_low_latency_logger.ino
@@ -210,7 +210,7 @@
                 log("Error writing log file. Current sector: %u\n", next_sector);
             }
         }
-        if(next_sector) file.truncate((next_sector - first_sector - 1) * 512 + partial_sector_len);
+        if(next_sector) file.truncate((next_sector - first_sector) * 512 + partial_sector_len);
         file.close();
         partial_sector_len = 0;
         first_sector = 0;


daniel changes

daniel changes

--- SpaceTeam-Wireless-Teensy/SpaceTeam-Wireless-Teensy.ino
+++ SpaceTeam-Wireless-Teensy/SpaceTeam-Wireless-Teensy.ino
@@ -12,7 +12,7 @@

 byte addresses[][6] = {"1Node","2Node"};

-#define BUFFER_SIZE 128
+#define BUFFER_SIZE 127

 typedef enum color {
   none,
@@ -31,8 +31,8 @@
 // 0 means end of array

 typedef struct RX_Sequence {
+  uint8_t len;
   byte sequence[BUFFER_SIZE];
-  int length;
 };

 RX_Sequence sequence;
@@ -54,14 +54,14 @@
   pinMode(13, OUTPUT);
   // 0 the sequence buffer
   memset(&sequence, 0, sizeof(sequence));
-  sequence.length = 0;
+  sequence.len = 0;

   setColorHigh(ledR);

   Serial.print("before radio begin");

   radio.begin();
-  radio.setPALevel(RF24_PA_LOW);
+//  radio.setPALevel(RF24_PA_LOW);
   radio.setChannel(11);
   radio.printDetails();

@@ -72,19 +72,20 @@
   // Start the radio listening for data
   Serial.print("before radio startlistening");
   radio.startListening();
-  delay(10);
+  delay(7000);
+  radio.printDetails();

 }

-int addColor(RX_Sequence sequence) {
-  if (sequence.length > BUFFER_SIZE) {
+int addColor(RX_Sequence& sequence) {
+  if (sequence.len > BUFFER_SIZE) {
     return 1; // cant hold the entire sequence in memory
   }

-  sequence.sequence[sequence.length] = random(1, 4); // (yellow, green, red)
+  sequence.sequence[sequence.len] = random(1, 4); // (yellow, green, red)

-  sequence.length += 1;
+  sequence.len += 1;
   return 0;
 }
 void setColor(byte color, bool highOrLow) {
@@ -123,7 +124,7 @@
 void displaySequence(RX_Sequence sequence) {
   setAllLow();
   int i;
-  for (i = 0; i < sequence.length; i++) {
+  for (i = 0; i < sequence.len; i++) {
     setColorHigh(sequence.sequence[i]);
     delay(COLOR_DURATION);

@@ -153,26 +154,30 @@

 // the loop routine runs over and over again forever:
 void loop() {
-
   if (addColor(sequence)) {
-    // this is an error, but we dont care
+    Serial.print("addColor error");
+
   }
-  for (int i = 0; i < sequence.length; i++){
+  Serial.print("The sequence is ");
+  for (int i = 0; i < sequence.len; i++){
     Serial.print(sequence.sequence[i]);
   }
   Serial.println("");
+  Serial.print("The length is ");
+  Serial.println(sequence.len);
+  Serial.print("RX_Sequence length is ");
+  Serial.print(sizeof(RX_Sequence));
   displaySequence(sequence);
-
   radio.stopListening();
+  Serial.println(" waiting to write");
   radio.write(&sequence, sizeof(RX_Sequence));

-
   // will be high when waiting for a response
+  radio.startListening();
   digitalWrite(13, HIGH);
-  byte correctSequence = -1;
-  while (sequence.length == 0) {
-  }
-  while (correctSequence == -1) {
+  byte correctSequence = 3;
+  Serial.println("before loop");
+  while (correctSequence == 3) {
     if (radio.available()) {
       radio.read(&correctSequence, sizeof(byte));
     }
@@ -182,8 +187,9 @@

   displayCorrectness(correctSequence);

-  if (correctSequence == 0) {
+  if (correctSequence != 1) {
     memset(&sequence, 0, sizeof(RX_Sequence));
+    sequence.len = 0;
   }

   delay(1);        // delay in between reads for stability


Delete Example_2.ino

Delete Example_2.ino


Minor updates

Minor updates

--- sensor_firmware/sensor_firmware.ino
+++ sensor_firmware/sensor_firmware.ino
@@ -5,7 +5,6 @@

 #include "TimerOne.h"
-

 int counter = 0;
 int average = 0;
@@ -21,14 +20,16 @@
 }

 void loop() {
-    // We don't need to do anything for now
+    // We don't actually need anything in here since all of our
+    // logic is in the Interrupt Service Routine (ISR)
 }

 /* Here is the routine that is run when the timer interrupt goes off */
 void interrupt_loop(){
     int sensorValue = analogRead(A0);

-    // Prints out every 5000 samples
+    // prints out an average value after 5000 samples
+    // TODO: Implement our actual filter here
     if(counter == 5000){
         Serial.println(sensorValue);
         counter = 0;


Black Frame after 20 sec without OpPoll

Black Frame after 20 sec without OpPoll

--- BlackLED.ino
+++ BlackLED.ino
@@ -10,6 +10,8 @@

 //#define _use_FastLED  //for all types of chips but only 3 channel !!only LPD8806 implemented in code
 #define _use_octoWS2811 //for all WS2811 type chips
+
+#define blackOnPollTimeOut true

 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //
@@ -114,6 +116,8 @@
 uint8_t numUniUpdated = 0;
 unsigned long currentMillis = 0;
 unsigned long previousMillis = 0;
+
+unsigned long lastPoll = 0;

 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //
@@ -346,6 +350,10 @@
               //T_ArtPoll* poll = (T_ArtPoll*)udp_buffer;
               //if(poll->TalkToMe & 0x2){

+              #ifdef blackOnPollTimeOut == true
+                lastPoll = millis();
+              #endif
+
               float tempCelsius = 25.0 + 0.17083 * (2454.19 - tempVal);
               sprintf(node.pollReport, "numOuts;%d;numUniPOut;%d;temp;%.1f;fps;%.1f;uUniPF;%.1f;", NUM_OF_OUTPUTS, num_universes_per_output, tempCelsius, fps, avgUniUpdated);
               node.createPollReply(); //create pollReply
@@ -487,4 +495,13 @@

   // read temperature value
   tempVal = analogRead(38) * 0.01 + tempVal * 0.99;
+  #ifdef blackOnPollTimeOut == true
+    currentMillis = millis();
+    if (currentMillis - lastPoll > 20000) {
+      for (int i = 0; i < num_led_per_output * 8; i++) {
+        LEDS.setPixel(i, 0);
+      }
+      LEDS.show();
+    }
+  #endif
 }


Edit to XBee_WiFI

Edit to XBee_WiFI

--- XBee_WiFI/XBee_WiFI.ino
+++ XBee_WiFI/XBee_WiFI.ino
@@ -40,6 +40,7 @@

 void loop() {
   // put your main code here, to run repeatedly:
+
   // if there is data available from the shield
   while (wifly.available()) {
     Serial.write(wifly.read()); // display the data in the serial monitor window


COH-80: WIP

COH-80: WIP

--- COHEAT2015/20160316-COHEAT-M1/COHEAT-M1/COHEAT-M1.ino
+++ COHEAT2015/20160316-COHEAT-M1/COHEAT-M1/COHEAT-M1.ino
@@ -351,7 +351,7 @@
 #else
   uint8_t key[16];
   if(!OTV0P2BASE::getPrimaryBuilding16ByteSecretKey(key))
-    { OTV0P2BASE::serialPrintlnAndFlush("!TX key"); return(false); } // FAIL
+    { OTV0P2BASE::serialPrintlnAndFlush(F("!TX key")); return(false); } // FAIL
   const OTRadioLink::SimpleSecureFrame32or0BodyTXBase::fixed32BTextSize12BNonce16BTagSimpleEnc_ptr_t e = OTAESGCM::fixed32BTextSize12BNonce16BTagSimpleEnc_DEFAULT_STATELESS;
   uint8_t buf[OTRadioLink::SimpleSecureFrame32or0BodyTXBase::generateSecureBeaconMaxBufSize];
   const uint8_t bodylen = secureTXState.generateSecureBeaconRawForTX(buf, sizeof(buf), lenTXID, e, NULL, key); // 2 byte ID.
@@ -361,8 +361,8 @@
   // doing so may reuse IVs and destroy the cipher security.
   const bool success = (0 != bodylen) && PrimaryRadio.sendRaw(buf+1, bodylen-1);
 #if 1 && defined(DEBUG)
-  if(!success) { OTV0P2BASE::serialPrintlnAndFlush("!TX"); }
-  else { OTV0P2BASE::serialPrintlnAndFlush("TX alert"); }
+  if(!success) { OTV0P2BASE::serialPrintlnAndFlush(F("!TX")); }
+  else { OTV0P2BASE::serialPrintlnAndFlush(F("TX alert")); }
 #endif
   if(success) { return(true); } // Done!
 #endif // ENABLE_OTSECUREFRAME_ENCODING_SUPPORT
@@ -490,8 +490,9 @@

   // If still waiting for a poll after a boost request,
   // arrange to send extra alerts about once every two minutes,
+  // no closer together than every about every 8 seconds,
   // randomly so as to minimise collisions with other regular traffic.
-  if(waitingForPollAfterBoostRequest && (sec == (OTV0P2BASE::randRNG8() & 0x3e)))
+  if(waitingForPollAfterBoostRequest && (sec == (OTV0P2BASE::randRNG8() & 0x38)))
     { sendCC1AlertByRFM23B(); }

   return(false); // No human interaction this tick...
@@ -737,12 +738,12 @@
           // Non-secure: send raw frame as-is.
           // Send at default power...  One going missing won't hurt that much.
           if(!PrimaryRadio.sendRaw(txbuf, bodylen))
-            { OTV0P2BASE::serialPrintlnAndFlush("!TX fail"); return; } // FAIL
+            { OTV0P2BASE::serialPrintlnAndFlush(F("!TX fail")); return; } // FAIL
 #else
           // Secure: wrap frame in encrypted layer...
           uint8_t key[16];
           if(!OTV0P2BASE::getPrimaryBuilding16ByteSecretKey(key))
-            { OTV0P2BASE::serialPrintlnAndFlush("!TX key"); return; } // FAIL
+            { OTV0P2BASE::serialPrintlnAndFlush(F("!TX key")); return; } // FAIL
           const OTRadioLink::SimpleSecureFrame32or0BodyTXBase::fixed32BTextSize12BNonce16BTagSimpleEnc_ptr_t e = OTAESGCM::fixed32BTextSize12BNonce16BTagSimpleEnc_DEFAULT_STATELESS;
           uint8_t buf[OTRadioLink::SecurableFrameHeader::maxSmallFrameSize];

@@ -756,7 +757,7 @@

-          OTV0P2BASE::serialPrintlnAndFlush("!TX not impl"); // FAIL
+          OTV0P2BASE::serialPrintlnAndFlush(F("!TX not impl")); // FAIL
 #endif // !defined(ENABLE_OTSECUREFRAME_ENCODING_SUPPORT)
           }
         }
@@ -851,7 +852,7 @@
       oldDropped = dropped;
       }
 #endif
-#if 0 && defined(DEBUG) && !defined(ENABLE_TRIMMED_MEMORY)
+#if 1 && defined(DEBUG) && !defined(ENABLE_TRIMMED_MEMORY)
     // Filtered out messages are not an error.
     const uint8_t filtered = PrimaryRadio.getRXMsgsFilteredRecent();
     static uint8_t oldFiltered;
@@ -1140,7 +1141,7 @@
           // Secure: wrap frame in encrypted layer...
           uint8_t key[16];
           if(!OTV0P2BASE::getPrimaryBuilding16ByteSecretKey(key))
-            { OTV0P2BASE::serialPrintlnAndFlush("!TX key"); return(false); } // FAIL
+            { OTV0P2BASE::serialPrintlnAndFlush(F("!TX key")); return(false); } // FAIL
           const OTRadioLink::SimpleSecureFrame32or0BodyTXBase::fixed32BTextSize12BNonce16BTagSimpleEnc_ptr_t e = OTAESGCM::fixed32BTextSize12BNonce16BTagSimpleEnc_DEFAULT_STATELESS;
           uint8_t buf[OTRadioLink::SecurableFrameHeader::maxSmallFrameSize];

@@ -1155,10 +1156,10 @@

-          OTV0P2BASE::serialPrintlnAndFlush("!TX not impl"); // FAIL
+//          OTV0P2BASE::serialPrintlnAndFlush(F("!TX not impl")); // FAIL
 #endif // !defined(ENABLE_OTSECUREFRAME_ENCODING_SUPPORT)
           // Fall-through is failure...
-          DEBUG_SERIAL_PRINT_FLASHSTRING("!TX fail");
+          OTV0P2BASE::serialPrintlnAndFlush(F("!TX fail"));
           }
         }
       }