Clean up, implemented HoldClick time in Settings

--- DigitalVFO.ino
+++ DigitalVFO.ino
@@ -18,8 +18,8 @@
 // macro to get number of elements in an array
 #define ARRAY_LEN(a)    (sizeof(a)/sizeof(a[0]))

-//#define RESET   // define if resetting all EEPROM data
-#define DEBUG   // define if debugging
+//#define VFO_RESET   // define if resetting all EEPROM data
+//#define VFO_DEBUG   // define if debugging

 // Digital VFO program name & version
@@ -113,6 +113,9 @@
 #define vfo_Click     5
 #define vfo_HoldClick 6

+// the "in use" display character
+#define IN_USE_CHAR   0x7e
+
 // default LCD contrast & brightness
 const int DefaultLcdContrast = 70;
 const int DefaultLcdBrightness = 150;
@@ -171,19 +174,19 @@
   {
     lcd.clear();
     lcd.setCursor(0, 0);
-    lcd.write(buf);
+    lcd.print(buf);
     lcd.setCursor(0, 1);
-    lcd.write(buf + NUM_COLS);
+    lcd.print(buf + NUM_COLS);
     delay(2000);

     lcd.clear();
     lcd.setCursor(0, 0);
-    lcd.write(" ");   // padding to centre name+version
-    lcd.write(ProgramName);
-    lcd.write(" ");
-    lcd.write(Version);
+    lcd.print(" ");   // padding to centre name+version
+    lcd.print(ProgramName);
+    lcd.print(" ");
+    lcd.print(Version);
     lcd.setCursor(0, 1);
-    lcd.write("   is paused");
+    lcd.print("   is paused");
     delay(2000);
   }
 }
@@ -211,29 +214,29 @@
 // display a simple banner on the LCD
 //----------------------------------------

-#ifndef DEBUG
+#ifndef VFO_DEBUG
 void banner(void)
 {
   Serial.print(ProgramName); Serial.print(" "); Serial.print(Version);
   Serial.print(" ("); Serial.print(Callsign); Serial.println(")");
   lcd.clear();
   lcd.setCursor(0, 0);
-  lcd.write(ProgramName);
-  lcd.write(" ");
-  lcd.write(Version);
+  lcd.print(ProgramName);
+  lcd.print(" ");
+  lcd.print(Version);
   lcd.setCursor(0, 1);
-  lcd.write(Callsign);
+  lcd.print(Callsign);
   delay(2000);    // wait a bit

   for (int i = 0; i <= NUM_COLS; ++i)
   {
     lcd.clear();
     lcd.setCursor(i, 0);
-    lcd.write(ProgramName);
-    lcd.write(" ");
-    lcd.write(Version);
+    lcd.print(ProgramName);
+    lcd.print(" ");
+    lcd.print(Version);
     lcd.setCursor(0, 1);
-    lcd.write(Callsign16 + i);
+    lcd.print(Callsign16 + i);
     delay(200);
   }

@@ -323,7 +326,7 @@
   struct MenuItem **items;    // array of pointers to MenuItem data
 };

-#ifdef DEBUG
+#ifdef VFO_DEBUG
 // dump a MenuItem to the console
 // only called from dump_menu()
 void dump_menuitem(struct MenuItem *menuitem)
@@ -359,7 +362,7 @@
   // clear screen and write menu title on upper row
   lcd.clear();
   lcd.setCursor(0, 0);
-  lcd.write(menu->title);
+  lcd.print(menu->title);
 }

 //----------------------------------------
@@ -383,9 +386,9 @@

   // write indexed item on lower row, right-justified
   lcd.setCursor(0, 1);
-  lcd.write(BlankRow);
+  lcd.print(BlankRow);
   lcd.setCursor(NUM_COLS - max_len, 1);
-  lcd.write(menu->items[item_num]->title);
+  lcd.print(menu->items[item_num]->title);
 }

 //----------------------------------------
@@ -400,24 +403,24 @@
 {
   int item_num = 0;     // index of the menuitem to show

-#ifdef DEBUG
+#ifdef VFO_DEBUG
   dump_menu("menu_show, menu:", menu);
 #endif
-
-  // get rid of any stray events to this point
-  flush_events();

   // draw the menu page
   menu_draw(menu);
   menuitem_draw(menu, item_num);

+  // get rid of any stray events to this point
+  event_flush();
+
   while (true)
   {
     // handle any pending event
-    if (events_pending() > 0)
+    if (event_pending() > 0)
     {
       // get next event and handle it
-      byte event = pop_event();
+      byte event = event_pop();
       Serial.print("menu_show loop: event="); Serial.println(event2display(event));

       switch (event)
@@ -439,6 +442,7 @@
           Serial.println("menu_show: vfo_DnRRight (ignored)");
           break;
         case vfo_Click:
+          Serial.println("menu_show: vfo_Click");
           if (menu->items[item_num]->action != NULL)
           {
             // if there's a handler, call it
@@ -455,7 +459,7 @@
           break;
         case vfo_HoldClick:
           Serial.println("menu_show: vfo_HoldClick, exit menu");
-          flush_events();
+          event_flush();
           return;
         default:
           Serial.print("menu_show: unrecognized event "); Serial.println(event);
@@ -496,7 +500,7 @@
 int queue_fore = 0;   // fore pointer into circular buffer
 int queue_aft = 0;    // aft pointer into circular buffer

-void push_event(VFOEvent event)
+void event_push(VFOEvent event)
 {
   // put new event into next empty slot
   event_queue[queue_fore] = event;
@@ -509,12 +513,12 @@
   // if queue full, abort
   if (queue_aft == queue_fore)
   {
-      dump_queue("ERROR: event queue full:");
+      event_dump_queue("ERROR: event queue full:");
       abort("Event queue full");
   }
 }

-VFOEvent pop_event(void)
+VFOEvent event_pop(void)
 {
   // Must protect from RE code fiddling with queue
   noInterrupts();
@@ -536,7 +540,7 @@
   return event;
 }

-int events_pending(void)
+int event_pending(void)
 {
   // Must protect from RE code fiddling with queue
   noInterrupts();
@@ -553,13 +557,13 @@
   return result;
 }

-void flush_events(void)
+void event_flush(void)
 {
   queue_fore = 0;
   queue_aft = 0;
 }

-void dump_queue(const char *msg)
+void event_dump_queue(const char *msg)
 {
   // Must protect from RE code fiddling with queue
   noInterrupts();
@@ -575,7 +579,7 @@
     Serial.print(" -> ");
     Serial.println(event2display(event));
   }
-  Serial.print("Queue length="); Serial.println(events_pending());
+  Serial.print("Queue length="); Serial.println(event_pending());
   Serial.print("queue_aft="); Serial.print(queue_aft);
   Serial.print(", queue_fore="); Serial.println(queue_fore);
   Serial.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
@@ -631,7 +635,7 @@
     }
   }

-  lcd.write("Hz");
+  lcd.print("Hz");
 }

@@ -641,7 +645,12 @@
 ////////////////////////////////////////////////////////////////////////////////

 // time when click becomes a "hold click" (milliseconds)
-#define HoldClickTime 500
+// the delay is configurable in the UI
+#define MinHoldClickTime        100
+#define MaxHoldClickTime        1000
+#define DefaultHoldClickTime    500
+
+int ReHoldClickTime = DefaultHoldClickTime;

 // internal variables
 bool re_rotation = false;       // true if rotation occurred while knob down
@@ -685,15 +694,15 @@
     // button released, check if rotation, UP event if not
     if (! re_rotation)
     {
-      unsigned long push_time = millis() - re_down_time;
-
-      if (push_time < HoldClickTime)
+      int push_time = millis() - re_down_time;
+
+      if (push_time < ReHoldClickTime)
       {
-        push_event(vfo_Click);
+        event_push(vfo_Click);
       }
       else
       {
-        push_event(vfo_HoldClick);
+        event_push(vfo_HoldClick);
       }
     }
   }
@@ -708,12 +717,12 @@
     // this pin's rising edge
     if (re_down)
     {
-      push_event(vfo_DnRLeft);
+      event_push(vfo_DnRLeft);
       re_rotation = true;
     }
     else
     {
-      push_event(vfo_RLeft);
+      event_push(vfo_RLeft);
     }
     bFlag = 0; //reset flags for the next turn
     aFlag = 0; //reset flags for the next turn
@@ -734,12 +743,12 @@
     // this pin's rising edge
     if (re_down)
     {
-      push_event(vfo_DnRRight);
+      event_push(vfo_DnRRight);
       re_rotation = true;
     }
     else
     {
-      push_event(vfo_RRight);
+      event_push(vfo_RRight);
     }
     bFlag = 0; //reset flags for the next turn
     aFlag = 0; //reset flags for the next turn
@@ -775,11 +784,15 @@
 const int AddressBrightness = AddressContrast + AddressContrastSize;
 const int AddressBrightnessSize = sizeof(LcdBrightness);

+// address for int 'hold click time'
+const int AddressHoldClickTime = AddressBrightness + AddressBrightnessSize;
+const int AddressHoldClickTimeSize = sizeof(ReHoldClickTime);
+
 // number of frequency save slots in EEPROM
 const int NumSaveSlots = 10;

 const int SaveFreqSize = sizeof(long);
-const int SaveFreqBase = AddressBrightness + AddressBrightnessSize;
+const int SaveFreqBase = AddressHoldClickTime + AddressHoldClickTimeSize;
 const int SaveFreqBaseSize = NumSaveSlots * SaveFreqSize;

 //also save the offset for each frequency
@@ -800,6 +813,7 @@
   EEPROM.put(AddressSelDigit, VfoSelectDigit);
   EEPROM.put(AddressBrightness, LcdBrightness);
   EEPROM.put(AddressContrast, LcdContrast);
+  EEPROM.put(AddressHoldClickTime, ReHoldClickTime);
 }

 //----------------------------------------
@@ -812,6 +826,7 @@
   EEPROM.get(AddressSelDigit, VfoSelectDigit);
   EEPROM.get(AddressBrightness, LcdBrightness);
   EEPROM.get(AddressContrast, LcdContrast);
+  EEPROM.get(AddressHoldClickTime, ReHoldClickTime);
 }

 //----------------------------------------
@@ -844,23 +859,26 @@
 // print all EEPROM saved data to console
 //----------------------------------------

-#ifdef DEBUG
+#ifdef VFO_DEBUG
 void dump_eeprom(void)
 {
   Frequency ulong;
   SelOffset offset;
   int brightness;
   int contrast;
+  int hold;

   EEPROM.get(AddressFreq, ulong);
   EEPROM.get(AddressSelDigit, offset);
   EEPROM.get(AddressBrightness, brightness);
   EEPROM.get(AddressContrast, contrast);
+  EEPROM.get(AddressHoldClickTime, hold);
   Serial.println("=================================================");
   Serial.print("dump_eeprom: VfoFrequency="); Serial.println(ulong);
   Serial.print("             AddressSelDigit="); Serial.println(offset);
   Serial.print("             LcdBrightness="); Serial.println(brightness);
   Serial.print("             LcdContrast="); Serial.println(contrast);
+  Serial.print("             ReHoldClickTime="); Serial.println(hold);

   for (int i = 0; i < NumSaveSlots; ++i)
   {
@@ -952,20 +970,22 @@
 // The standard Arduino setup() function.
 //----------------------------------------

-#ifdef RESET
-void zero_slots(void)
+#ifdef VFO_RESET
+void zero_eeprom(void)
 {
   Frequency zero_freq = 0L;
   SelOffset zero_offset = 0;
-
+
   // zero the frequency+selected values
   VfoFrequency = MIN_FREQ;
   VfoSelectDigit = 0;
   LcdBrightness = DefaultLcdBrightness;
   LcdContrast = DefaultLcdContrast;
+  ReHoldClickTime = DefaultHoldClickTime;

   save_to_eeprom();

+  // zero the save slots
   for (int i = 0; i < NumSaveSlots; ++i)
   {
     put_slot(i, zero_freq, zero_offset);
@@ -977,8 +997,8 @@
 {
   Serial.begin(115200);

-#ifdef RESET
-  zero_slots();
+#ifdef VFO_RESET
+  zero_eeprom();
   Serial.println("All EEPROM data reset");
 #endif

@@ -1003,31 +1023,44 @@
   re_setup(VfoSelectDigit);

   // show program name and version number
-#ifndef DEBUG
+#ifndef VFO_DEBUG
   banner();
-  if (pop_event() == vfo_HoldClick)
-  {
-    // if holdClick during banner, reset brightness/contrast
+
+  // we might have got a 'reset' HoldClick during banner presentation
+  if (event_pop() == vfo_HoldClick)
+  {
+    // if holdClick during banner, reset all "Settings" values
     LcdBrightness = DefaultLcdBrightness;
     analogWrite(mc_Brightness, LcdBrightness);
     LcdContrast = DefaultLcdContrast;
     analogWrite(mc_Contrast, LcdContrast);
-
+    ReHoldClickTime = DefaultHoldClickTime;
+
+    // tell what happened on LCD
+    lcd.clear();
+    lcd.print("Reset all values");
+    lcd.setCursor(0, 1);
+    lcd.print("in Settings menu");
+
+    // and Serial console
     Serial.print("Reset brightness to "); Serial.print(LcdBrightness);
-    Serial.print(" and contrast to "); Serial.println(LcdContrast);
-
-    lcd.clear();
-    lcd.write("Reset Contrast");
-    lcd.setCursor(0, 1);
-    lcd.write("and Brightness");
-    delay(3000);
+    Serial.print(", contrast to "); Serial.print(LcdContrast);
+    Serial.print(" and hold time to "); Serial.println(ReHoldClickTime);
+    Serial.println("Select or rotate the rotary encoder to continue");
+
+    // wait here until there is some input action
+    event_flush();
+    while (! event_pending())
+      delay(100);
+    event_flush();
+    delay(500);
   }
 #endif

   // we sometimes see random events on powerup, flush them here
-  flush_events();
-
-#ifdef DEBUG
+  event_flush();
+
+#ifdef VFO_DEBUG
   // dump EEPROM values
   dump_eeprom();
 #endif
@@ -1036,7 +1069,7 @@
   show_main_screen();

   // we sometimes see random events on powerup, flush them here
-  flush_events();
+  event_flush();
 }

 //----------------------------------------
@@ -1046,7 +1079,7 @@
 {
   lcd.clear();
   lcd.setCursor(0, 0);
-  lcd.write("Freq:");
+  lcd.print("Freq:");
   print_freq(VfoFrequency, VfoSelectDigit, 0);
 }

@@ -1061,15 +1094,15 @@

   get_slot(slot_num, freq, offset);
   lcd.setCursor(0, 1);
-  lcd.write(BlankRow);
+  lcd.print(BlankRow);
   if (VfoFrequency == freq)
   {
     lcd.setCursor(0, 1);
-    lcd.write("*");
+    lcd.write(IN_USE_CHAR);
   }
   lcd.setCursor(4, 1);
   lcd.write(slot_num + '0');
-  lcd.write(":");
+  lcd.print(":");
   print_freq(freq, -1, 1);
 }

@@ -1084,11 +1117,11 @@
   int slot_num = 0;       // the slot we are viewing/saving

   // get rid of any stray events to this point
-  flush_events();
+  event_flush();

   // draw row 0 of menu
   lcd.clear();
-  lcd.write(menu->items[item_num]->title);
+  lcd.print(menu->items[item_num]->title);

   // show row slot info on row 1
   show_slot_frequency(slot_num);
@@ -1097,9 +1130,9 @@
   while (true)
   {
     // handle any pending event
-    if (events_pending() > 0)
+    if (event_pending() > 0)
     {
-      byte event = pop_event(); // get next event and handle it
+      byte event = event_pop(); // get next event and handle it

       switch (event)
       {
@@ -1117,7 +1150,7 @@
           menu_flash();
           break;
         case vfo_HoldClick:
-          flush_events();
+          event_flush();
           return;
         default:
           // ignore any events we don't handle
@@ -1141,11 +1174,11 @@
   int slot_num = 0;       // the slot we are viewing/restoring

   // get rid of any stray events to this point
-  flush_events();
+  event_flush();

   // draw row 0 of menu
   lcd.clear();
-  lcd.write(menu->items[item_num]->title);
+  lcd.print(menu->items[item_num]->title);

   // show row slot info on row 1
   show_slot_frequency(slot_num);
@@ -1154,9 +1187,9 @@
   while (true)
   {
     // handle any pending event
-    if (events_pending() > 0)
+    if (event_pending() > 0)
     {
-      byte event = pop_event(); // get next event and handle it
+      byte event = event_pop(); // get next event and handle it

       switch (event)
       {
@@ -1173,7 +1206,7 @@
           menu_flash();
           break;
         case vfo_HoldClick:
-          flush_events();
+          event_flush();
           return;
         default:
           // ignore any events we don't handle
@@ -1199,11 +1232,11 @@
   int slot_num = 0;               // the slot we are viewing/restoring

   // get rid of any stray events to this point
-  flush_events();
+  event_flush();

   // draw row 0 of menu
   lcd.clear();
-  lcd.write(menu->items[item_num]->title);
+  lcd.print(menu->items[item_num]->title);

   // show row slot info on row 1
   show_slot_frequency(slot_num);
@@ -1212,9 +1245,9 @@
   while (true)
   {
     // handle any pending event
-    if (events_pending() > 0)
+    if (event_pending() > 0)
     {
-      byte event = pop_event(); // get next event and handle it
+      byte event = event_pop(); // get next event and handle it

       switch (event)
       {
@@ -1231,7 +1264,7 @@
           menu_flash();
           break;
         case vfo_HoldClick:
-          flush_events();
+          event_flush();
           return;
         default:
           // ignored events we don't handle
@@ -1252,14 +1285,14 @@
 void draw_row1_bar(int length)
 {
   lcd.setCursor(0, 1);
-  lcd.write(BlankRow);
+  lcd.print(BlankRow);
   lcd.setCursor(0, 1);
   for (int i = 0; i < length; ++i)
     lcd.write(ALLSET_CHAR);
 }

 //----------------------------------------
-// save the current brightness to EEPROM
+// Set the current contrast and save to EEPROM if 'actioned'.
 //   menu      address of 'calling' menu
 //   item_num  index of MenuItem we were actioned from
 //----------------------------------------
@@ -1270,11 +1303,11 @@
   int index = (LcdBrightness + 1) / 16;

   // get rid of any stray events to this point
-  flush_events();
+  event_flush();

   // draw row 0 of menu, get heading from MenuItem
   lcd.clear();
-  lcd.write(menu->items[item_num]->title);
+  lcd.print(menu->items[item_num]->title);

   // show row slot info on row 1
   draw_row1_bar(index);
@@ -1283,9 +1316,9 @@
   while (true)
   {
     // handle any pending event
-    if (events_pending() > 0)
+    if (event_pending() > 0)
     {
-      byte event = pop_event(); // get next event and handle it
+      byte event = event_pop(); // get next event and handle it

       switch (event)
       {
@@ -1302,7 +1335,7 @@
           menu_flash();
           break;
         case vfo_HoldClick:
-          flush_events();
+          event_flush();
           return;
         default:
           // ignored events we don't handle
@@ -1320,7 +1353,7 @@
 }

 //----------------------------------------
-// save the current contrast to EEPROM
+// Set the current contrast and save to EEPROM if 'actioned'.
 //   menu      address of 'calling' menu
 //   item_num  index of MenuItem we were actioned from
 //----------------------------------------
@@ -1331,11 +1364,11 @@
   int index = 16 - LcdContrast / 8;

   // get rid of any stray events to this point
-  flush_events();
+  event_flush();

   // draw row 0 of menu, get heading from MenuItem
   lcd.clear();
-  lcd.write(menu->items[item_num]->title);
+  lcd.print(menu->items[item_num]->title);

   // show row slot info on row 1
   draw_row1_bar(index);
@@ -1344,9 +1377,9 @@
   while (true)
   {
     // handle any pending event
-    if (events_pending() > 0)
+    if (event_pending() > 0)
     {
-      byte event = pop_event(); // get next event and handle it
+      byte event = event_pop(); // get next event and handle it

       switch (event)
       {
@@ -1363,7 +1396,7 @@
           menu_flash();
           break;
         case vfo_HoldClick:
-          flush_events();
+          event_flush();
           return;
         default:
           // ignored events we don't handle
@@ -1381,12 +1414,110 @@
 }

 //----------------------------------------
+// Draw a click hold time in milliseconds on row 1 of LCD.
+//----------------------------------------
+
+void draw_row1_time(int msec)
+{
+  Serial.print("draw_row1_time: msec="); Serial.print(msec);
+  Serial.print(", ReHoldClickTime="); Serial.println(ReHoldClickTime);
+
+  lcd.setCursor(0, 1);
+  lcd.print(BlankRow);
+
+  if (msec == ReHoldClickTime)
+  {
+    Serial.println("draw_row1_time: drawing *");
+    lcd.setCursor(0, 1);
+    lcd.write(IN_USE_CHAR);
+  }
+
+  lcd.setCursor(8, 1);
+  if (msec < 1000)
+    lcd.setCursor(9, 1);
+  lcd.print(msec);
+  lcd.print("msec");
+}
+
+//----------------------------------------
+// Set the current 'hold click' time and save to EEPROM if 'actioned'.
+//   menu      address of 'calling' menu
+//   item_num  index of MenuItem we were actioned from
+// This works differently from brightness/contrast.  We show menuitems
+// of the time to use.
+//----------------------------------------
+
+void holdclick_action(struct Menu *menu, int item_num)
+{
+  Serial.println("holdclick_action: entered");
+
+  int holdtime = ReHoldClickTime;
+
+// the step time for hold click
+#define HOLD_STEP   100
+
+  // get rid of any stray events to this point
+  event_flush();
+
+  // draw row 0 of menu, get heading from MenuItem
+  lcd.clear();
+  lcd.print(menu->items[item_num]->title);
+
+  // show row slot info on row 1
+  draw_row1_time(holdtime);
+
+  // handle events in our own little event loop
+  while (true)
+  {
+    // handle any pending event
+    if (event_pending() > 0)
+    {
+      byte event = event_pop(); // get next event and handle it
+
+      switch (event)
+      {
+        case vfo_RLeft:
+          holdtime -= HOLD_STEP;
+          if (holdtime < MinHoldClickTime)
+            holdtime = MinHoldClickTime;
+          Serial.print("holdclick_action: vfo_RLeft, after holdtime=");
+          Serial.println(holdtime);
+          break;
+        case vfo_RRight:
+          holdtime += HOLD_STEP;
+          if (holdtime > MaxHoldClickTime)
+            holdtime = MaxHoldClickTime;
+          Serial.print("holdclick_action: vfo_RRight, after holdtime=");
+          Serial.println(holdtime);
+          break;
+        case vfo_Click:
+          ReHoldClickTime = holdtime;
+          save_to_eeprom();
+          menu_flash();
+          break;
+        case vfo_HoldClick:
+          event_flush();
+          return;
+        default:
+          // ignored events we don't handle
+          break;
+      }
+
+      // show hold time value in row 1
+      draw_row1_time(holdtime);
+    }
+  }
+}
+
+
+//----------------------------------------
 // Settings menu
 //----------------------------------------

 struct MenuItem mi_brightness = {"Brightness", NULL, &brightness_action};
 struct MenuItem mi_contrast = {"Contrast", NULL, &contrast_action};
-struct MenuItem *mia_settings[] = {&mi_brightness, &mi_contrast};
+struct MenuItem mi_holdclick = {"Hold click", NULL, &holdclick_action};
+struct MenuItem *mia_settings[] = {&mi_brightness, &mi_contrast, &mi_holdclick};
 struct Menu settings_menu = {"Settings", ARRAY_LEN(mia_settings), mia_settings};

 //----------------------------------------
@@ -1412,10 +1543,10 @@
   int old_position = VfoSelectDigit;

   // handle all events in the queue
-  while (events_pending() > 0)
+  while (event_pending() > 0)
   {
     // get next event and handle it
-    VFOEvent event = pop_event();
+    VFOEvent event = event_pop();

     switch (event)
     {


fix time format. fix bug in lifo mode if buffer empty.

--- autobaud_bitlash.ino
+++ autobaud_bitlash.ino
@@ -96,9 +96,9 @@
   if (getarg(0) > 1)
     lifo_mode = (getarg(2) != 0);
   // banner
-  printf_P(PSTR("Index | Time (ms) | Hex  | Dec | ASCII\r\n"));
+  printf_P(PSTR("Index |  Time (ms)  | Hex  | Dec | ASCII\r\n"));
   // datas
-  word i = (lifo_mode) ? rx_byte_index - 1: rx_byte_index;
+  word i = (lifo_mode and rx_byte_index) ? rx_byte_index - 1: rx_byte_index;
   word index = 0;
   word line = 0;
   unsigned long t_origin = 0;
@@ -112,7 +112,7 @@
         t_origin = rx_bytes[i].time;
       // no printable ascii -> set to 0x00
       char ascii = ((rx_bytes[i].value >= 0x20) and (rx_bytes[i].value <= 0x7e)) ? rx_bytes[i].value : 0x00;
-      printf_P(PSTR("  %3d | %9ld | 0x%02x | %3d | %c\r\n"), line++, rx_bytes[i].time - t_origin, rx_bytes[i].value, rx_bytes[i].value, ascii);
+      printf_P(PSTR("  %3d | %11ld | 0x%02x | %3d | %c\r\n"), line++, rx_bytes[i].time - t_origin, rx_bytes[i].value, rx_bytes[i].value, ascii);
     }
     index++;
     // next byte


Added timestamp test for loop

Added timestamp test for loop

--- Sensorizer.ino
+++ Sensorizer.ino
@@ -81,7 +81,14 @@
   #include "TestInterface.h"
 #endif

-
+#define ENABLE_TIMESTAMP_TEST 0
+#if ENABLE_TIMESTAMP_TEST
+
+#define TEST_TIMESTAMPS_LENGTH 512
+int testTimestampsIdx = 0;
+unsigned long testTimestamps[TEST_TIMESTAMPS_LENGTH];
+
+#endif

 void setupServer() {
     // must wait a bit for the MIDI device to boot up before it accepts our messages
@@ -120,7 +127,7 @@
 /* timer variables */
 unsigned long currentMillis;        // store the current value from millis()
 unsigned long previousMillis;       // for comparison with currentMillis
-int samplingInterval = 1;//19;          // how often to run the main loop (in ms)
+int samplingInterval = 1;//19;          // how often to run the main loop (in ms). set to 0 to disable samplingThrottle.

 // -----------------------------------------------------------------------------
@@ -236,12 +243,18 @@
   midiIn->check();
 #endif

+
+#if ENABLE_TIMESTAMP_TEST
+  unsigned long microTimestamp = micros();
+
+#endif
+
   /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over
    * 60 bytes. use a timer to sending an event character every 4 ms to
    * trigger the buffer to dump. */

   currentMillis = millis();
-  if (currentMillis - previousMillis > samplingInterval) {
+  if (samplingInterval == 0 || currentMillis - previousMillis > samplingInterval) {
     previousMillis += samplingInterval;

     /* ANALOGREAD - do all analogReads() at the configured sampling interval */
@@ -288,6 +301,29 @@
   }

+#if ENABLE_TIMESTAMP_TEST
+  unsigned long microTimestampDelta = micros() - microTimestamp;
+
+
+  if (SerialUSB.getWriteError() > 0) {
+      SerialUSB.println("ERROR WRITING TO USB");
+      SerialUSB.clearWriteError();
+  }
+
+
+  testTimestamps[testTimestampsIdx] = microTimestampDelta;
+
+  if (++testTimestampsIdx >= TEST_TIMESTAMPS_LENGTH) {
+    testTimestampsIdx = 0;
+
+    SerialUSB.println("Timestamps:");
+    unsigned long firstTimestamp = testTimestamps[0];
+    for (int i = 0; i < TEST_TIMESTAMPS_LENGTH; i++) {
+      SerialUSB.println(testTimestamps[i]);
+    }
+  }
+#endif
+
   // relay all debug messages from BLE
 #if ENABLE_DEBUG_PRINTING && ENABLE_DEBUG_PRINTING_RELAY_FROM_BLE && defined(BLE_RESET_PIN)


Made some untouched vars constants

Made some untouched vars constants


Increase serial message length

Increase serial message length

Signed-off-by: Mark Knoop <f1b5a91d4d6ad523f2610114591c007e75d15084@markknoop.com>

--- src/sketch.ino
+++ src/sketch.ino
@@ -35,7 +35,7 @@
 #define rSetDuration   12
 #define rReset         13
 #define rDurlength      5
-#define rLength        12
+#define rLength        14
 /*
  * ranges:
     21-39  set halfturns


add serial reading functionality

add serial reading functionality

--- Attic_Controller/Attic_Controller.ino
+++ Attic_Controller/Attic_Controller.ino
@@ -21,18 +21,22 @@
 #define PASS ""        // your network password            //
 //---------------------------------------------------------//

-#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2320, AM2321
+#define DHTTYPE DHT22     // DHT 22  (AM2302), AM2320, AM2321
 const int DHTPin = 4;
+bool fahrenheit = true;
 DHT dht(DHTPin, DHTTYPE);
-bool fahrenheit = true;
+
+#define MAXCHARS  32        // Max chars before a line break
+#define ENDMARKER '\n'      // Character that defines the end of a line
+char serialChars[MAXCHARS]; // Array to store received data
+static byte next_loc = 0;   // Array location for next char

 unsigned long lastTempHumidSend = millis();
 #define TEMP_HUMID_UPDATE_FREQUENCY 60000

 // Initial set up routines
 void setup() {
-  Serial.begin(115200);
-  Serial.println();
+  Serial.begin(9600);
   dht.begin();
   connectWifi();        //Connect to wifi
   MQTT_Helper.setup();
@@ -41,23 +45,20 @@
 // Main program loop
 void loop() {
   MQTT_Helper.mqttLoop();
-
   checkTempHumid();
-  delay(1000); //saves power; we don't need to check often anyways...
   yield();
+  checkSerial();
+  delay(50); //saves considerable power
 }

 // Initial connection to WiFi
 // We wait for 5 seconds to connect, but do not block on the connection.
 void connectWifi() {
-  Serial.print("Connecting to ");
-  Serial.println(SSID);
   WiFi.begin(SSID, PASS);
   delay(5000);
-  Serial.println(getTemperature() );
 }

-//Send temp / humidity update if need be
+// Send temp / humidity update if need be
 void checkTempHumid() {
   if (millis() > lastTempHumidSend + TEMP_HUMID_UPDATE_FREQUENCY) {

@@ -70,6 +71,49 @@
     MQTT_Helper.publishMQTT("home/attic/controller/temp",  temp,  false);
     MQTT_Helper.publishMQTT("home/attic/controller/humid", humid, false);
     lastTempHumidSend = millis();
+  }
+}
+
+// Check for (and handle) any serial data sent to us from the roof sensor
+// Adapted from:  http://forum.arduino.cc/index.php?topic=288234.0
+void checkSerial() {
+  boolean newData = false;    // If we have a finished data packet
+
+  //Get all the serial bytes we can until there is no more, or there is a newline.
+  while (Serial.available() > 0 && newData == false) {
+    char rc = Serial.read();
+
+    //If a regular character, append to the list
+    if (rc != ENDMARKER) {
+      serialChars[next_loc] = rc;
+      next_loc++;
+      //If it's more than the max length, just overight the last char
+      if (next_loc >= MAXCHARS) {
+        next_loc = MAXCHARS - 1;
+      }
+    }
+    //If a finishing character, then mark as complete
+    else {
+      serialChars[next_loc] = '\0'; // terminate the string
+      next_loc = 0;
+      newData = true;
+    }
+  }
+
+  //Once a full line has been found, send to processing.
+  if (newData == true) {
+    handleSerial();
+    newData = false;
+  }
+}
+
+// Process a complete serial line
+void handleSerial() {
+  Serial.print("This just in ... ");
+  Serial.println(serialChars);
+  char cleanChars[MAXCHARS];
+  if (serialChars[0] == 'T') {
+
   }
 }

@@ -86,4 +130,3 @@
 float getHumidity() {
   return dht.readHumidity();
 }
-


Slower baudrate

Slower baudrate

--- resilient_network/resilient_network.ino
+++ resilient_network/resilient_network.ino
@@ -208,7 +208,7 @@
   // set up pins
   for (int i=0; i<NUM_CONN; i++) {
     bus[i] = new SoftwareSerial(RX[i], TX[i]);
-    bus[i]->begin(115200); //(9600); //1200
+    bus[i]->begin(9600); //115200); //(9600); //1200
     pinMode(coil[i], OUTPUT);

     uint8_t port = digitalPinToPort(RX[i]);


Initial defaults

Initial defaults

--- resilient_network/resilient_network.ino
+++ resilient_network/resilient_network.ino
@@ -26,9 +26,9 @@

 int coil[NUM_CONN] = {6, 5, 10}; // magnets
 int distanceToSource[NUM_CONN] = {99, 99, 99};
-int shortestDistanceToSource;
+int shortestDistanceToSource = 99;
 int lampState;
-int alertState;
+int alertState = false;
 int alertTimer;
 boolean isSource = false;


Turn on ACKs

Turn on ACKs

--- glowworm/glowworm.ino
+++ glowworm/glowworm.ino
@@ -158,7 +158,7 @@
   radio->stopListening();

   radio->begin();
-  radio->setAutoAck(false);
+  radio->setAutoAck(true);
   radio->setChannel(CHANNEL);

   //radio->enableAckPayload(); // So we can send a response back


Tested with CAN_receive_v1 successfully

Tested with CAN_receive_v1 successfully

--- src/md5_test/md5_test.ino
+++ src/md5_test/md5_test.ino
@@ -1,15 +1,27 @@
 #include <MD5.h>
+#include <mcp_can.h>
+
+const int SPI_CS_PIN = 9;
+
+MCP_CAN CAN(SPI_CS_PIN);

 char *correct_key = "sharedkey";

 void setup()
 {
     Serial.begin(115200);
+
+    while (CAN_OK != CAN.begin(CAN_500KBPS))
+    {
+        Serial.println("CAN BUS Shield init fail");
+        Serial.println(" Init CAN BUS Shield again");
+    }
+    Serial.println("CAN BUS Shield init ok!");
 }

 void loop()
 {
-    if (Serial.available() >= 3)
+    while (Serial.available() >= 4)
     {
         // Get user message
         uint32_t id = (uint32_t)Serial.parseInt();
@@ -18,14 +30,16 @@
         for(int i = 0; i < dlc; i++)
             msg[i] = (uint8_t)Serial.parseInt();
         char *key = (char *)(Serial.readString().c_str());
-        uint8_t msgLen, keyLen;
-        SendAuthMessages(correct_key, keyLen, msg, msgLen);
+        uint8_t msgLen, keyLen, fullMsgLen;
+        uint8_t *fullMessage = GetFullMessage(correct_key, keyLen, msg, msgLen, fullMsgLen);
         Serial.flush();
+
+        CAN.sendMsgBuf(id, 0, dlc, msg);
     }
 }

-void SendAuthMessages(char *key, uint8_t &keyLen, uint8_t *data, uint8_t &dataLen)
+uint8_t *GetFullMessage(char *key, uint8_t &keyLen, uint8_t *data, uint8_t &dataLen, uint8_t &lenVar)
 {
     // Convert to uint8_t
     uint8_t *theKey = CStringToUInt8(key, keyLen);
@@ -38,15 +52,7 @@
     for(int i = 0; i < keyLen; i++)
         fullMessage[i + dataLen] = theKey[i];

-    // Print the whole, unhashsed message
-    for(int i = 0; i < (keyLen + dataLen); i++)
-    {
-        if (fullMessage[i] < 0x10)
-            Serial.print('0');
-        Serial.print(fullMessage[i], HEX);
-        Serial.print(' ');
-    }
-    Serial.println();
+    lenVar = keyLen + dataLen;
 }


Impoved logic to look for rising, then falling edge.

--- FumeHoodWatchDog/FumeHoodWatchDog.ino
+++ FumeHoodWatchDog/FumeHoodWatchDog.ino
@@ -1,16 +1,18 @@
 // This is a watchdog program to be run on an Adafruit Trinket

-#define watchDogPin 1
+#define watchDogPin 13
 #define resetPin 2

-unsigned long watchDogInterval = 7000;
+unsigned long watchDogInterval = 30000; // Needs to see a pulse at lease every 30 seconds
 unsigned long resetDuration = 5000;
 unsigned long fumeHoodMonitorBootTime = 15000;
 unsigned long watchDogTimer;

+bool watchDogIsBeingPet = false;
 bool watchDogHasBeenPet = false;

 void setup() {
+  Serial.begin(9600);
   pinMode(watchDogPin, INPUT);
   pinMode(resetPin, OUTPUT);
   digitalWrite(resetPin, HIGH);
@@ -19,9 +21,15 @@
 }

 void loop(){
-  watchDogHasBeenPet = digitalRead(watchDogPin) == 1;
-  if (watchDogHasBeenPet) watchDogTimer = millis();
+  watchDogIsBeingPet = digitalRead(watchDogPin) == 1;
+  if (watchDogIsBeingPet) {
+    watchDogHasBeenPet = true;
+  } else if (!watchDogIsBeingPet && watchDogHasBeenPet) {
+    watchDogTimer = millis();
+    watchDogHasBeenPet = false;
+  }
   unsigned long now = millis();
+  Serial.println(now - watchDogTimer);
   if(now - watchDogTimer >= watchDogInterval){
     digitalWrite(resetPin, LOW);
     delay(resetDuration);


removed unsued ModbusTest Arduino sketch

--- platform_src/ModbusTest/ModbusTest.ino
+++ platform_src/ModbusTest/ModbusTest.ino
@@ -1,29 +0,0 @@
-#include <SimpleModbusSlave.h>
-#include <ArduinoRobot.h>
-#include <Wire.h>
-#include <SPI.h>
-
-enum
-{
-  // just add or remove registers and your good to go...
-  // The first register starts at address 0
-  ADC0,
-  CTRLRD,
-  CTRL,
-  TOTAL_ERRORS,
-  // leave this one
-  TOTAL_REGS_SIZE
-  // total number of registers for function 3 and 16 share the same register array
-};
-
-unsigned int holdingRegs[TOTAL_REGS_SIZE];
-void setup() {
-  Robot.begin();
-  modbus_configure(115200, 1, 0, TOTAL_REGS_SIZE, 0);
-}
-
-void loop() {
-  holdingRegs[TOTAL_ERRORS] = modbus_update(holdingRegs);
-  holdingRegs[ADC0] = Robot.knobRead();
-  holdingRegs[CTRLRD]=holdingRegs[CTRL];
-}


added delay after start button press

added delay after start button press

--- SlotCar.ino
+++ SlotCar.ino
@@ -22,11 +22,13 @@
 void loop() {

   displayUpdate();
+
   waitForStartButton();
+  delay(3000);
+
   startSequence();

   while (1) {
-
     if (startPressed()) break;

     if (getEvent(EVENT_LAP)) {


moved delay to after the go message

moved delay to after the go message

--- SlotCar.ino
+++ SlotCar.ino
@@ -12,7 +12,7 @@
 uint8_t lap[LANES];

 void setup() {
-  delay(3000);
+  delay(2000);
   displayInit();
   timerInit();
   startInit();
@@ -23,9 +23,9 @@

   displayStart();
   waitForStartButton();
+  displayGo();
   delay(3000);

-  displayGo();
   startSequence();
   detectEnable();


incorporate "pedal" management

incorporate "pedal" management

--- chaise2.ino
+++ chaise2.ino
@@ -15,6 +15,9 @@
 //#include "SerialDebugger.h"
 #include "DxLEDTimers.h"
 #include "NoteManager.h"	//	manages/coordinates the notes
+#include "PedalManager.h"
+#include "KeySignatureManager.h"
+#include "ChordManager.h"

 #define NOP __asm__ __volatile__ ("nop\n\t")

@@ -73,6 +76,9 @@
 	memset8( leds, 0, NUM_LEDS * sizeof(CRGB));

 	Conductor.begin();
+	PedalBoard.begin();
+	Transposer.begin();
+	Chord.begin();
 }

 void loop() {
@@ -82,8 +88,16 @@
 		std::bitset<10> b_n (n);
 		for(uint16_t i = 0; i <= MAX_TOUCH_IDX; i++) {
 			if( b_n.test(i) ) {
-				//Serial.print("will play "); Serial.println(i);
-				Conductor.play(i);
+				//	route the message to either the Conductor
+				//	or the PedalBoard
+				if( i < NUM_NOTES )
+					Conductor.play(i);
+				else if( i == 7 ) {
+					Chord.play();
+				}
+				else {
+					PedalBoard.depress(i);
+				}
 			}
 		}
 	}
@@ -93,7 +107,14 @@
 		std::bitset<10> b_r (r);
 		for(uint16_t i = 0; i <= MAX_TOUCH_IDX; i++) {
 			if( b_r.test(i) ) {
-				Conductor.release(i);
+				if( i < NUM_NOTES )
+					Conductor.release(i);
+				else if( i == 7 ) {
+					Chord.release();
+				}
+				else {
+					PedalBoard.release(i);
+				}
 			}
 		}
 	}
@@ -174,6 +195,8 @@

 	//	clear the buffer
 	memset8( leds, 0, NUM_LEDS * sizeof(CRGB));
+	//	update the chord manger before showing leds
+	Chord.update(leds);
 	//	update the note manager *before* showing leds
 	Conductor.update(leds);

@@ -193,6 +216,26 @@
 	// ColorCoordinator.update();	//	update the color coordinator
 	heartbeat.update();
 	Klavier.update();		//	update touch manager
+	PedalFunction pedal = PedalBoard.update();
+	if( pedal == PedalChangePalette ) {
+		Transposer.toggle();
+	}
+	else if( pedal == PedalToggleEcho ) {
+		Conductor.toggleEcho();
+	}
+	else if( pedal == PedalToggleFade) {
+		Conductor.toggleSlowMode();
+	}
+	if( Transposer.update() ) {
+		CRGB palette[7];
+		Serial.println("Transposer updated");
+		Transposer.palette(palette);
+		for(uint8_t i = 0; i < 7; i++ ) {
+			//Serial.print(palette[i].hue); Serial.print(" ");
+			Conductor.setColor(i, palette[i]);
+		}
+		DEBUG_PRINTLN("");
+	}
 	//delay(250);
 	// SerialDebugger.update();
 }


tweaked integration time setting

tweaked integration time setting

--- ardesp/waterelf/waterelf.ino
+++ ardesp/waterelf/waterelf.ino
@@ -425,8 +425,8 @@
   // Changing the integration time gives you a longer time over which to sense light
   // longer timelines are slower, but are good in very low light situtations!
   //tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS);  // shortest integration time (bright light)
-  //tsl.setTiming(TSL2591_INTEGRATIONTIME_200MS);
-  tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS);
+  tsl.setTiming(TSL2591_INTEGRATIONTIME_200MS);
+  //tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS);
   //tsl.setTiming(TSL2591_INTEGRATIONTIME_400MS);
   //tsl.setTiming(TSL2591_INTEGRATIONTIME_500MS);
   //tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS);  // longest integration time (dim light)


Debug to Joystick

Debug to Joystick

--- Joystick/Joystick.ino
+++ Joystick/Joystick.ino
@@ -24,5 +24,14 @@
   intPacket[0] = analogRead(joyXPin);
   intPacket[1] = analogRead(joyYPin);
   intPacket[2] = digitalRead(joySelPin);
+  Serial.print("X: ");
+  Serial.print(analogRead(joyXPin));
+  Serial.print("; ");
+  Serial.print("Y: ");
+  Serial.print(analogRead(joyYPin));
+  Serial.print("; ");
+  Serial.print("Sel: ");
+  Serial.print(digitalRead(joySelPin));
+  Serial.print("; ");
   radio.write((void*)packet, PACKETSIZE, false);
 }


Separate the color changes from the timing.

--- led_pixels/led_pixels.ino
+++ led_pixels/led_pixels.ino
@@ -17,14 +17,15 @@
 uint8_t dataPin  = 2;    // Yellow wire on Adafruit Pixels
 uint8_t clockPin = 3;    // Green wire on Adafruit Pixels

-#define GRIDSIZE 5
+#define GRIDSIZE 5 // We have a 5x5 LED array
+

 unsigned long previousMillis = 0;
 unsigned long frameDelayMillis = 5; // time between frames

 // Set the first variable to the NUMBER of pixels.
-Adafruit_WS2801 strip = Adafruit_WS2801(25, dataPin, clockPin);
-LEDFader Fader(strip, 5, 5);
+Adafruit_WS2801 strip = Adafruit_WS2801(GRIDSIZE*GRIDSIZE, dataPin, clockPin);
+LEDFader Fader(strip, GRIDSIZE, GRIDSIZE);

 typedef void (*AnimationEndedCallback)();
 typedef void (*CurrentAnimationFP)(unsigned long);
@@ -35,22 +36,13 @@
 AnimationEndedCallback transitionCompleteCallback;
 double transitionElapsed; // millis taken by transition so far

-void renderColors(unsigned long delta)
-{
-  if (transitionElapsed < transitionDuration) {
-    transitionElapsed += delta;
-  }
-  else {
-    transitionCompleteCallback();
-  }
-}
+
 /**
  Transition to a frame of colors.
  @param duration in seconds
  */
-void transitionToFrame(byte* frame, double duration, void (*completionCallback)(), uint32_t color)
-{
-
+void transitionToFrame(byte* frame, uint32_t color)
+{
   for (int y = 0; y < GRIDSIZE; y++) {
     byte b = frame[y];
     for (int x = 0; x < GRIDSIZE; x++) {
@@ -58,26 +50,16 @@
       Fader.setPixelColor(x, y, bit ? color : Color(0, 0, 0), 0.2);
     }
   }
-
-  CurrentAnimation = &renderColors;
-  transitionElapsed = 0;
-  transitionDuration = duration * 1000; // convert to millis
-  transitionCompleteCallback = completionCallback;
-}
-
-void transitionToRedFrame(byte* frame, double duration, void (*completionCallback)())
-{
-  transitionToFrame(frame, duration, completionCallback, Color(128, 0, 0));
-}
-
-void transitionToColorFrame(byte* frame, double duration, void (*completionCallback)(), uint32_t color)
-{
-  transitionToFrame(frame, duration, completionCallback, color);
-}
-
-void transitionToBlueFrame(byte* frame, double duration, void (*completionCallback)())
-{
-  transitionToFrame(frame, duration, completionCallback, Color(0, 0, 128));
+}
+
+void transitionToRedFrame(byte* frame)
+{
+  transitionToFrame(frame, Color(128, 0, 0));
+}
+
+void transitionToColorFrame(byte* frame, uint32_t color)
+{
+  transitionToFrame(frame, color);
 }

@@ -89,9 +71,9 @@
   if (transitionElapsed < transitionDuration) {
     transitionElapsed += delta;

-    // clamp
-    if (transitionElapsed > transitionDuration)
-      transitionElapsed = transitionDuration;
+//    // clamp  - no need in this simple pause.
+//    if (transitionElapsed > transitionDuration)
+//      transitionElapsed = transitionDuration;
   }
   else {
     transitionCompleteCallback();
@@ -195,25 +177,9 @@

         uint32_t c = ColorWheel(wheelPos);

-//        // Fade in
-//        if (rainbowStyle & RAINBOW_FADE_IN) {
-//          double fadeInTime = 300;
-//          if (transitionElapsed < fadeInTime) {
-//            byte r = (c >> 16) & 0xff;
-//            byte g = (c >> 8) & 0xff;
-//            byte b = c & 0xff;
-//            double factor = transitionElapsed / fadeInTime;
-//
-//            c = Color(r * factor, g * factor, b * factor);
-//          }
-//        }
-
         Fader.setPixelColor(x, y, c, 0.1);
-        //strip.setPixelColor(y * GRIDSIZE + x, c);
       }
     }
-
-    //strip.show();
   }
   else {
     transitionCompleteCallback();
@@ -233,9 +199,9 @@

 ///////

-void allOff(double duration, void (*completionCallback)())
-{
-  transitionToFrame(AllDark, duration, completionCallback, Color(0, 0, 128));
+void allOff()
+{
+  transitionToFrame(AllDark, Color(0, 0, 128));

   //    for (int y=0;y<GRIDSIZE;y++) {
   //      for (int x=0;x<GRIDSIZE;x++) {
@@ -261,6 +227,7 @@
 };

 Animation animations[] = {
+  // Beating heart
   { animateToBigHeart, 0.2 },
   { pause, 3 },
   { animateToSmallHeart, 0.4 },
@@ -270,6 +237,7 @@
   { animateToSmallHeart, 0.4 },
   { animateToBigHeart, 0.5},

+  // "I <heart> U"
   { animateToLetterI, 0.2 },
   { pause, 1.5 },
   { animateToBigHeart, 0.2},
@@ -277,6 +245,7 @@
   { animateToLetterU, 0.2 },
   { pause, 1.5 },

+  // Beating heart
   { animateToBigHeart, 0.5},
   { animateToSmallHeart, 0.4 },
   { animateToBigHeart, 0.5},
@@ -290,6 +259,7 @@
 //  { allOff, 0.5 },
   { pause, 0.5 },

+  // Color swirls
   { rainbowAnimation, 10, 1 },
   { rainbowAnimation, 15, 0 },

@@ -333,21 +303,26 @@

 void animateToSmallHeart(double duration, uint32_t param)
 {
-  transitionToFrame(SmallHeart, duration, &nextAnimation, Color(200, 0, 0));
+  transitionToFrame(SmallHeart, Color(200, 0, 0));
+  pause(duration, &nextAnimation);
 }

 void animateToBigHeart(double duration, uint32_t param)
 {
-  transitionToRedFrame(BigHeart, duration, &nextAnimation);
+  transitionToRedFrame(BigHeart);
+  pause(duration, &nextAnimation);
 }

 void animateToLetterI(double duration, uint32_t param)
 {
-  transitionToFrame(FontI, duration, &nextAnimation, Color(0, 0, 150));
-}
+  transitionToFrame(FontI, Color(0, 0, 150));
+  pause(duration, &nextAnimation);
+}
+
 void animateToLetterU(double duration, uint32_t param)
 {
-  transitionToFrame(FontU, duration, &nextAnimation, Color(0, 0, 150));
+  transitionToFrame(FontU, Color(0, 0, 150));
+  pause(duration, &nextAnimation);
 }

 void pause(double duration, uint32_t param)
@@ -363,7 +338,8 @@

 void allOff(double duration, uint32_t param)
 {
-  allOff(duration, &nextAnimation);
+  allOff();
+  pause(duration, &nextAnimation);
 }

 //////////////


now setting ap mode name added reset to webpage

--- src/babysteps/BasicOTA/app.ino
+++ src/babysteps/BasicOTA/app.ino
@@ -28,9 +28,15 @@
 void handleRoot() {
   String html("<meta http-equiv='refresh' content='5'>You are connected</>
");
   html.concat(millis());
-  html.concat("");
+  html.concat("<form action='reset'><input type='submit' value='Reset'></form>");
   server.send(200, "text/html", html.c_str());
 }
+
+void handleReset() {
+  server.send(200, "text/html", "Reseting");
+  ESP.reset();
+}
+

 void broadcastStatus() {
   String message("{\"nodeid\":");
@@ -74,6 +80,7 @@
   String hostname(HOSTNAME);
   hostname += String(ESP.getChipId(), HEX);
   ArduinoOTA.setHostname((const char *)hostname.c_str());
+  WiFi.softAP((const char *)hostname.c_str());

   // No authentication by default
   // ArduinoOTA.setPassword((const char *)"123");
@@ -115,8 +122,11 @@
   udp.begin(WiFi.localIP());

   server.on("/", handleRoot);
+  server.on("/reset", handleReset);
+
   server.begin();
   Serial.println("HTTP server started");
+

 }


Fill in the skeleton of the toplevel logic

--- crypt-gears/gear_arduino/gear_arduino.ino
+++ crypt-gears/gear_arduino/gear_arduino.ino
@@ -56,17 +56,45 @@
   Serial.print("  ");
   Serial.println(getConnection(gear_connections[0][0], gear_connections[0][1]));

-  // TODO(benkraft)
-  // this should probably be a state machine since the loop function loops
-  // every cycle -- check if gears are removed, if so, reset (check by making sure gear orientations/types are the same)
-  // first state -- gear insertion
-  // some kind of check that all gears are good
-  // second state -- move through selector gear connections
-  // verify which ones should be connections
-  // if connection is good, turn on specific light/solenoid for feedback
-  // if all 7 connections were good, send message for success
-  // if you need to send any other messages back to the castle, lemme know
-
+  // First, get the state of the world.
+  int gear_types[3];
+  int gear_orientations[3];
+  boolean should_reset = false;
+  for (int i=0; i<3; i++)
+  {
+    getOrientationAndTypeForGear(i, &gear_types[i], &gear_orientations[i]);
+    showLodged(i, should_reset);
+    if (gear_types[i] = -1)
+    {
+      should_reset = true;
+    }
+  }
+
+  // If not all gears are lodged, reset -- which may be a no-op -- and exit.
+  if (should_reset)
+  {
+    reset();
+    return;
+  }
+
+  // TODO(benkraft): figure out whether there is a connection on current
+  // selector position
+
+  // check if we won
+  int winning = true;
+  for (int i=0; i<7; i++)
+  {
+    if (!correct_positions[i])
+    {
+      winning = false;
+    }
+  }
+
+  if (winning)
+  {
+    sendCastleSuccessMessage();
+    // TODO(benkraft): Should we reset here or something?
+  }
 }

 void sendCastleSuccessMessage()
@@ -83,7 +111,9 @@

 // TODO(benkraft): change return signature to however you want to represent gears
 // returns which gear type is inserted + the orientation of the gear
-void getOrientationAndTypeForGear(int gear_num)
+// Return the type and orientation of the gear in the nth position, or -1 for
+// both if no gear is lodged.
+void getOrientationAndTypeForGear(int gear_num, int* type, int* orientation)
 {
   // so the basic idea here is that each gear is attached in 12 places
   // a pair of them will be connected
@@ -150,6 +180,12 @@
   // TODO(bhomberg): open solenoid??
 }

+// turn on light for gear #n lodged, or not
+void showLodged(int n, boolean isLodged)
+{
+  digitalWrite(gear_lodged[n], isLodged ? HIGH : LOW);
+}
+
 // gears have been taken out / selector gear goes back to beginning, reset everything
 void reset()
 {


Delete LH_firmware.ino

Delete LH_firmware.ino

--- LH_firmware.ino
+++ LH_firmware.ino
@@ -1,315 +0,0 @@
-
-boolean laserField[26] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false};
-boolean laserReaderAction = false;
-
-int sensor1 = 1;
-
-//First oktava
-int sensor2 = 2;
-int sensor3 = 3;
-int sensor4 = 4;
-int sensor5 = 5;
-int sensor6 = 6;
-int sensor7 = 7;
-int sensor8 = 8;
-int sensor9 = 9;
-
-//Second oktava
-int sensor10 = 10;
-int sensor11 = 11;
-int sensor12 = 12;
-int sensor13 = 13;
-int sensor14 = 14;
-int sensor15 = 15;
-int sensor16 = 16;
-int sensor17 = 17;
-
-//thirst oktava
-
-int sensor18 = 18;
-int sensor19 = 19;
-int sensor20 = 20;
-int sensor21 = 21;
-int sensor22 = 22;
-int sensor23 = 23;
-int sensor24 = 24;
-int sensor25 = 25;
-
-int sensor26 = 26;
-
-//--------------------------------------------------------------
-
-int laser1 = 27;
-
-int laser2 = 28;
-int laser3 = 29;
-int laser4 = 30;
-int laser5 = 31;
-int laser6 = 32;
-int laser7 = 33;
-int laser8 = 34;
-int laser9 = 35;
-
-int laser10 = 36;
-int laser11 = 37;
-int laser12 = 38;
-int laser13 = 39;
-int laser14 = 40;
-int laser15 = 41;
-int laser16 = 42;
-int laser17 = 43;
-
-int laser18 = 44;
-int laser19 = 45;
-int laser20 = 46;
-int laser21 = 47;
-int laser22 = 48;
-int laser23 = 49;
-int laser24 = 50;
-int laser25 = 51;
-
-int laser26 = 52;
-
-
-void setup() {
-	Serial.begin(115200);
-
-       pinMode(sensor1, INPUT);
-
-       pinMode(sensor2, INPUT);
-       pinMode(sensor3, INPUT);
-       pinMode(sensor4, INPUT);
-       pinMode(sensor5, INPUT);
-       pinMode(sensor6, INPUT);
-       pinMode(sensor7, INPUT);
-       pinMode(sensor8, INPUT);
-       pinMode(sensor9, INPUT);
-
-       pinMode(sensor10, INPUT);
-       pinMode(sensor11, INPUT);
-       pinMode(sensor12, INPUT);
-       pinMode(sensor13, INPUT);
-       pinMode(sensor14, INPUT);
-       pinMode(sensor15, INPUT);
-       pinMode(sensor16, INPUT);
-       pinMode(sensor17, INPUT);
-       pinMode(sensor18, INPUT);
-
-       pinMode(sensor19, INPUT);
-       pinMode(sensor20, INPUT);
-       pinMode(sensor21, INPUT);
-       pinMode(sensor22, INPUT);
-       pinMode(sensor23, INPUT);
-       pinMode(sensor24, INPUT);
-       pinMode(sensor25, INPUT);
-
-       pinMode(sensor26, INPUT);
-
-  //------------------------------------------------------
-
-       pinMode(laser1, INPUT);
-
-       pinMode(laser2, INPUT);
-       pinMode(laser3, INPUT);
-       pinMode(laser4, INPUT);
-       pinMode(laser5, INPUT);
-       pinMode(laser6, INPUT);
-       pinMode(laser7, INPUT);
-       pinMode(laser8, INPUT);
-       pinMode(laser9, INPUT);
-
-       pinMode(laser10, INPUT);
-       pinMode(laser11, INPUT);
-       pinMode(laser12, INPUT);
-       pinMode(laser13, INPUT);
-       pinMode(laser14, INPUT);
-       pinMode(laser15, INPUT);
-       pinMode(laser16, INPUT);
-       pinMode(laser17, INPUT);
-       pinMode(laser18, INPUT);
-
-       pinMode(laser19, INPUT);
-       pinMode(laser20, INPUT);
-       pinMode(laser21, INPUT);
-       pinMode(laser22, INPUT);
-       pinMode(laser23, INPUT);
-       pinMode(laser24, INPUT);
-       pinMode(laser25, INPUT);
-
-       pinMode(laser26, INPUT);
-
-
-}
-void loop() {
-
-
-
-  if(laserReaderAction){
-     LaserReader();
-  }
-}
-
-
-static void LaserReader(){
-
-  if(sensor1 == HIGH){
-      laserField[0] = false;
-  }else{
-    laserField[0] = true;
-  }
-
-
-   if(sensor2 == HIGH){
-      laserField[1] = false;
-  }else{
-    laserField[1] = true;
-  }
-
-
-   if(sensor3 == HIGH){
-      laserField[2] = false;
-  }else{
-    laserField[2] = true;
-  }
-
-
-   if(sensor4== HIGH){
-      laserField[3] = false;
-  }else{
-    laserField[3] = true;
-  }
-
-
-   if(sensor5 == HIGH){
-      laserField[4] = false;
-  }else{
-    laserField[4] = true;
-  }
-
-   if(sensor6 == HIGH){
-      laserField[5] = false;
-  }else{
-    laserField[5] = true;
-  }
-
-   if(sensor7 == HIGH){
-      laserField[6] = false;
-  }else{
-    laserField[6] = true;
-  }
-
-   if(sensor8 == HIGH){
-      laserField[7] = false;
-  }else{
-    laserField[7] = true;
-  }
-
-   if(sensor9 == HIGH){
-      laserField[8] = false;
-  }else{
-    laserField[8] = true;
-  }
-
-   if(sensor10 == HIGH){
-      laserField[9] = false;
-  }else{
-    laserField[9] = true;
-  }
-
-   if(sensor11 == HIGH){
-      laserField[10] = false;
-  }else{
-    laserField[10] = true;
-  }
-
-   if(sensor12 == HIGH){
-      laserField[11] = false;
-  }else{
-    laserField[11] = true;
-  }
-
-   if(sensor13 == HIGH){
-      laserField[12] = false;
-  }else{
-    laserField[12] = true;
-  }
-
-   if(sensor14 == HIGH){
-      laserField[13] = false;
-  }else{
-    laserField[13] = true;
-  }
-
-   if(sensor15 == HIGH){
-      laserField[14] = false;
-  }else{
-    laserField[14] = true;
-  }
-
-   if(sensor16 == HIGH){
-      laserField[15] = false;
-  }else{
-    laserField[15] = true;
-  }
-
-   if(sensor17 == HIGH){
-      laserField[16] = false;
-  }else{
-    laserField[16] = true;
-  }
-
-   if(sensor18 == HIGH){
-      laserField[17] = false;
-  }else{
-    laserField[17] = true;
-  }
-
-   if(sensor19 == HIGH){
-      laserField[18] = false;
-  }else{
-    laserField[18] = true;
-  }
-
-   if(sensor20 == HIGH){
-      laserField[19] = false;
-  }else{
-    laserField[19] = true;
-  }
-
-   if(sensor21 == HIGH){
-      laserField[20] = false;
-  }else{
-    laserField[20] = true;
-  }
-
-   if(sensor22== HIGH){
-      laserField[21] = false;
-  }else{
-    laserField[21] = true;
-  }
-
-   if(sensor23 == HIGH){
-      laserField[22] = false;
-  }else{
-    laserField[22] = true;
-  }
-
-   if(sensor24 == HIGH){
-      laserField[23] = false;
-  }else{
-    laserField[23] = true;
-  }
-
-   if(sensor25 == HIGH){
-      laserField[24] = false;
-  }else{
-    laserField[24] = true;
-  }
-
-   if(sensor26 == HIGH){
-      laserField[25] = false;
-  }else{
-    laserField[25] = true;
-  }
-
-}


Tracked down appropriate (I hope) copyright for the Color-making code from Adafruit.

--- xy.ino
+++ xy.ino
@@ -575,6 +575,31 @@
       strip.setPixelColor( i, 0);
 }

+// ---------------------------------------------------------------------------------------------------------------------
+//  Adafruit WS2801 library code
+// ---------------------------------------------------------------------------------------------------------------------
+
+// The following copyright applies to all code in this section.
+
+// Example library for driving Adafruit WS2801 pixels!
+
+
+//   Designed specifically to work with the Adafruit RGB Pixels!
+//   12mm Bullet shape ----> https://www.adafruit.com/products/322
+//   12mm Flat shape   ----> https://www.adafruit.com/products/738
+//   36mm Square shape ----> https://www.adafruit.com/products/683
+
+//   These pixels use SPI to transmit the color data, and have built in
+//   high speed PWM drivers for 24 bit color per pixel
+//   2 pins are required to interface
+
+//   Adafruit invests time and resources providing this open source code,
+//   please support Adafruit and open-source hardware by purchasing
+//   products from Adafruit!
+
+//   Written by Limor Fried/Ladyada for Adafruit Industries.
+//   BSD license, all text above must be included in any redistribution
+
 // Create a 24 bit color value from R,G,B
 // (Code snitched from Adafruit.  Please don't sue me, y'all, for stealing your bit-shifting code.)
 uint32_t Color(byte r, byte g, byte b)
@@ -588,3 +613,6 @@
   return c;
 }

+// ---------------------------------------------------------------------------------------------------------------------
+//  Adafruit WS2801 library code ENDS
+// ---------------------------------------------------------------------------------------------------------------------


left button pin to wake up from deep sleep

--- vibrate_alarm_clock_2.ino
+++ vibrate_alarm_clock_2.ino
@@ -5,19 +5,21 @@

 #include "LowPower.h"

-#define LEFT_BUTTON_PIN A3
+#define LEFT_BUTTON_INT_PIN INT1
+#define LEFT_BUTTON_NORM_PIN 3
+
 #define MIDDLE_BUTTON_PIN A2
 #define RIGHT_BUTTON_PIN A1
+
+//These two refer to the same pin
+#define ALARM_INT_PIN INT0//Driven LOW by Chronodot on alarm triggered
+#define ALARM_NORM_PIN 2//Driven LOW by Chronodot on alarm triggered

 #define VOLTAGE_MEASURE_PIN A0

 #define MOTOR_PIN1 1
 #define MOTOR_PIN2 0
 #define MOTOR_SLEEP_PIN 6
-
-//These two rofero to the same pin
-#define ALARM_INT_PIN INT0//Driven LOW by Chronodot on alarm triggered
-#define ALARM_NORM_PIN 2//Driven LOW by Chronodot on alarm triggered

 #define ADC_PRECISION 1024

@@ -70,7 +72,7 @@
 boolean previousSecondsBlinkState;
 unsigned long previousSecondsBlinkTime;

-boolean showLCD = true;
+volatile boolean showLCD = true;
 unsigned long lastVibration;
 boolean lastMotorState = false;

@@ -105,7 +107,7 @@
   uView.clear(ALL);   // erase hardware memory inside the OLED controller
   uView.contrast(0); //Lowest constrast so not so glaring

-  pinMode(LEFT_BUTTON_PIN, INPUT_PULLUP);
+  pinMode(LEFT_BUTTON_NORM_PIN, INPUT_PULLUP);
   pinMode(MIDDLE_BUTTON_PIN, INPUT_PULLUP);
   pinMode(RIGHT_BUTTON_PIN, INPUT_PULLUP);

@@ -131,18 +133,14 @@

   delay(INITIAL_TEXT_DELAY);
-
   attachInterrupt(ALARM_INT_PIN, alarmTriggered, FALLING);
-
-
-
-
+  attachInterrupt(LEFT_BUTTON_INT_PIN, leftButtonIntPressed, FALLING); //Left Button is used to wake up from deep sleep
 }

 void loop (){

-  int leftButtonState = digitalRead(LEFT_BUTTON_PIN);
+  int leftButtonState = digitalRead(LEFT_BUTTON_NORM_PIN);
   int middleButtonState = digitalRead(MIDDLE_BUTTON_PIN);
   int rightPinState = digitalRead(RIGHT_BUTTON_PIN);

@@ -197,9 +195,12 @@
   }

-  if(currentState == NORMAL){
-    //Only sleep if not doing anything else
-    LowPower.powerDown(SLEEP_15Ms, ADC_OFF, BOD_OFF);
+  if(currentState == NORMAL){
+    if(showLCD){
+      LowPower.powerDown(SLEEP_15Ms, ADC_OFF, BOD_OFF);
+    }else {
+      LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
+    }

   }

@@ -215,6 +216,13 @@
   if(!showLCD){
     uView.clear(PAGE);
     uView.display();
+  }
+}
+
+void leftButtonIntPressed(){
+  if(!showLCD && currentState == NORMAL){
+    showLCD = true;
+    timeLastPressedLeftButton = millis();
   }
 }


Updates: Sending four values to four pins

Two are digital (motor0 and motor1), and two are analog (wavelength and wave speed)

--- botwurst_a.ino
+++ botwurst_a.ino
@@ -10,9 +10,11 @@
 //The analog pins on the Mega are A0-A5
 #define OUTPIN0 A0
 #define OUTPIN1 A1
+#define OUTPIN2 13
+#define OUTPIN3 12
 //In general, if we ever want to read voltages in from the arduino to get feedback from
 //the robot, it can be done using the input pins
-#define INPIN 12
+#define INPIN 7

 # IN FACT THESE ARE EACH 8 BITS
 byte wave_speed;
@@ -71,6 +73,8 @@
     Serial.println("Ready");  // we might want to read this
     pinMode(OUTPIN0, OUTPUT); //designates OUTPIN0 pin to be an output
     pinMode(OUTPIN1, OUTPUT); //designates OUTPIN1 pin to be an input
+    pinMode(OUTPIN2, OUTPUT);
+    pinMode(OUTPIN3, OUTPUT);
     pinMode(INPIN, INPUT);    //designates INPIN pin to be an input
 }

@@ -87,12 +91,16 @@
     if((lengthValid==1) && (speedValid==1)){
         analogWrite(OUTPIN0, wave_speed); //sends "wave_speed" to pin OUTPIN0
         analogWrite(OUTPIN1, wavelength); //sends "wavelength" to pin OUTPIN1
+        digitalWrite(OUTPIN2, motor_0);   //sends on or off (0 or 1) to pin OUTPIN2
+        digitalWrite(OUTPIN3, motor_1);   //sends on or off (0 or 1) to pin OUTPIN3
         //Serial.print("Reading in voltage: ");
         //Serial.println(digitalRead(INPIN)); //should we ever decide to read in voltages
         return true;
     }
     analogWrite(OUTPIN0, 0); //sends zero voltage, turns off the LED
     analogWrite(OUTPIN1, 0);
+    digitalWrite(OUTPIN2, 0);
+    digitalWrite(OUTPIN3, 0);
     return false;
 }


fix notes left on while scrolling and startup

--- examples/UNTZtrument_Step_Seq/UNTZtrument_Step_Seq.ino
+++ examples/UNTZtrument_Step_Seq/UNTZtrument_Step_Seq.ino
@@ -8,8 +8,6 @@
 // allow transpositions between scales
 // add measure marks as vertical lines when scrolling left and right
 // allow selection of measure size and number of measures by making a box
-// allow making notes stay on when multiples are in a row instead of re keying them
-// add performance layer to be able to play along, each key is a different note so you have access to the entire keyboard and can map keys to multiple instruments
 // accept midi input to set the lights on the performance layer or just set and clear the lights ourself if no one is send us anything
 // add other modes for games like lights out and tetris and break out and match two cards
 // add built in simple synth for audio output, best we can do with space available, add speaker and holes and headphone jack
@@ -20,14 +18,10 @@
 // add blutooth audio output
 // support less than 8 wide grid when scrolling and disable keys on right side
 // add a playlist to play complete song based on layer sets, requires measures to have the same width
-// need to properly restore volumes, instruments, tempo, etc. when switching sets and layers
-// need to send out current volumes and instrumnets at startup, maybe at the start of each measure
-// still have trouble with notes all off when switch layers and grid sets
 // need to check if long notes still work when changing button grid marks or layer and other switches
 // need a scale with just the mt32 drumkit notes
 // flash notes on other layers as they are played so we can see where the notes are being played on other layers
 // add load/save state by midi note export and recording on an external device
-// need to switch to new instrument on grid switch
 // maybe hide play bar when scrolling to avoid confusion
 // add an SD card reader to load and save multiple sets and larger sets and remove some of the restrictions that we have for the EEPROM saving
 // switch grids on measure bars so you you can change earlier than at the end of a grid, less waiting.
@@ -122,106 +116,106 @@
 static const uint8_t PROGMEM
 scales[MAX_SCALES][MAX_MIDI_NOTES] = {
   {
-    107, 105, 103, 101, 100, 98, 96, 95, 93, 91, 89, 88, 86, 84, 83, 81, 79, 77, 76, 74, 72, 71, 69, 67, 65, 64, 62, 60, 59, 57, 55, 53, 52, 50, 48, 47, 45, 43, 41, 40, 38, 36, 35, 33, 31, 29, 28, 26, 24, 23, 21, 19, 17, 16, 14, 12        }
-  ,
-  {
-    106, 104, 103, 101, 99, 98, 96, 94, 92, 91, 89, 87, 86, 84, 82, 80, 79, 77, 75, 74, 72, 70, 68, 67, 65, 63, 62, 60, 58, 56, 55, 53, 51, 50, 48, 46, 44, 43, 41, 39, 38, 36, 34, 32, 31, 29, 27, 26, 24, 22, 20, 19, 17, 15, 14, 12        }
-  ,
-  {
-    87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32        }
-  ,
-  {
-    114, 113, 111, 108, 106, 103, 102, 101, 99, 96, 94, 91, 90, 89, 87, 84, 82, 79, 78, 77, 75, 72, 70, 67, 66, 65, 63, 60, 58, 55, 54, 53, 51, 48, 46, 43, 42, 41, 39, 36, 34, 31, 30, 29, 27, 24, 22, 19, 18, 17, 15, 12, 10, 7, 6, 5        }
-  ,
-  {
-    100, 99, 97, 96, 94, 93, 91, 90, 88, 87, 85, 84, 82, 81, 79, 78, 76, 75, 73, 72, 70, 69, 67, 66, 64, 63, 61, 60, 58, 57, 55, 54, 52, 51, 49, 48, 46, 45, 43, 42, 40, 39, 37, 36, 34, 33, 31, 30, 28, 27, 25, 24, 22, 21, 19, 18        }
-  ,
-  {
-    96, 95, 94, 93, 92, 91, 89, 87, 86, 84, 83, 82, 81, 80, 79, 77, 75, 74, 72, 71, 70, 69, 68, 67, 65, 63, 62, 60, 59, 58, 57, 56, 55, 53, 51, 50, 48, 47, 46, 45, 44, 43, 41, 39, 38, 36, 35, 34, 33, 32, 31, 29, 27, 26, 24, 23        }
-  ,
-  {
-    107, 104, 103, 101, 100, 98, 96, 95, 92, 91, 89, 88, 86, 84, 83, 80, 79, 77, 76, 74, 72, 71, 68, 67, 65, 64, 62, 60, 59, 56, 55, 53, 52, 50, 48, 47, 44, 43, 41, 40, 38, 36, 35, 32, 31, 29, 28, 26, 24, 23, 20, 19, 17, 16, 14, 12        }
-  ,
-  {
-    107, 104, 103, 101, 99, 98, 96, 95, 92, 91, 89, 87, 86, 84, 83, 80, 79, 77, 75, 74, 72, 71, 68, 67, 65, 63, 62, 60, 59, 56, 55, 53, 51, 50, 48, 47, 44, 43, 41, 39, 38, 36, 35, 32, 31, 29, 27, 26, 24, 23, 20, 19, 17, 15, 14, 12        }
-  ,
-  {
-    107, 105, 103, 101, 99, 98, 96, 95, 93, 91, 89, 87, 86, 84, 83, 81, 79, 77, 75, 74, 72, 71, 69, 67, 65, 63, 62, 60, 59, 57, 55, 53, 51, 50, 48, 47, 45, 43, 41, 39, 38, 36, 35, 33, 31, 29, 27, 26, 24, 23, 21, 19, 17, 15, 14, 12        }
-  ,
-  {
-    115, 111, 110, 108, 107, 105, 103, 99, 98, 96, 95, 93, 91, 87, 86, 84, 83, 81, 79, 75, 74, 72, 71, 69, 67, 63, 62, 60, 59, 57, 55, 51, 50, 48, 47, 45, 43, 39, 38, 36, 35, 33, 31, 27, 26, 24, 23, 21, 19, 15, 14, 12, 11, 9, 7, 3        }
-  ,
-  {
-    106, 105, 102, 101, 100, 97, 96, 94, 93, 90, 89, 88, 85, 84, 82, 81, 78, 77, 76, 73, 72, 70, 69, 66, 65, 64, 61, 60, 58, 57, 54, 53, 52, 49, 48, 46, 45, 42, 41, 40, 37, 36, 34, 33, 30, 29, 28, 25, 24, 22, 21, 18, 17, 16, 13, 12        }
-  ,
-  {
-    106, 103, 102, 101, 100, 98, 96, 94, 91, 90, 89, 88, 86, 84, 82, 79, 78, 77, 76, 74, 72, 70, 67, 66, 65, 64, 62, 60, 58, 55, 54, 53, 52, 50, 48, 46, 43, 42, 41, 40, 38, 36, 34, 31, 30, 29, 28, 26, 24, 22, 19, 18, 17, 16, 14, 12        }
-  ,
-  {
-    96, 95, 93, 92, 91, 89, 88, 87, 85, 84, 83, 81, 80, 79, 77, 76, 75, 73, 72, 71, 69, 68, 67, 65, 64, 63, 61, 60, 59, 57, 56, 55, 53, 52, 51, 49, 48, 47, 45, 44, 43, 41, 40, 39, 37, 36, 35, 33, 32, 31, 29, 28, 27, 25, 24, 23        }
-  ,
-  {
-    106, 105, 103, 101, 99, 98, 96, 94, 93, 91, 89, 87, 86, 84, 82, 81, 79, 77, 75, 74, 72, 70, 69, 67, 65, 63, 62, 60, 58, 57, 55, 53, 51, 50, 48, 46, 45, 43, 41, 39, 38, 36, 34, 33, 31, 29, 27, 26, 24, 22, 21, 19, 17, 15, 14, 12        }
-  ,
-  {
-    106, 104, 101, 100, 97, 97, 96, 94, 92, 89, 88, 85, 85, 84, 82, 80, 77, 76, 73, 73, 72, 70, 68, 65, 64, 61, 61, 60, 58, 56, 53, 52, 49, 49, 48, 46, 44, 41, 40, 37, 37, 36, 34, 32, 29, 28, 25, 25, 24, 22, 20, 17, 16, 13, 13, 12        }
-  ,
-  {
-    106, 104, 102, 101, 99, 97, 96, 94, 92, 90, 89, 87, 85, 84, 82, 80, 78, 77, 75, 73, 72, 70, 68, 66, 65, 63, 61, 60, 58, 56, 54, 53, 51, 49, 48, 46, 44, 42, 41, 39, 37, 36, 34, 32, 30, 29, 27, 25, 24, 22, 20, 18, 17, 15, 13, 12        }
-  ,
-  {
-    106, 105, 103, 102, 100, 98, 96, 94, 93, 91, 90, 88, 86, 84, 82, 81, 79, 78, 76, 74, 72, 70, 69, 67, 66, 64, 62, 60, 58, 57, 55, 54, 52, 50, 48, 46, 45, 43, 42, 40, 38, 36, 34, 33, 31, 30, 28, 26, 24, 22, 21, 19, 18, 16, 14, 12        }
-  ,
-  {
-    96, 95, 94, 93, 92, 91, 89, 87, 86, 84, 83, 82, 81, 80, 79, 77, 75, 74, 72, 71, 70, 69, 68, 67, 65, 63, 62, 60, 59, 58, 57, 56, 55, 53, 51, 50, 48, 47, 46, 45, 44, 43, 41, 39, 38, 36, 35, 34, 33, 32, 31, 29, 27, 26, 24, 23        }
-  ,
-  {
-    106, 105, 103, 101, 100, 98, 96, 94, 93, 91, 89, 88, 86, 84, 82, 81, 79, 77, 76, 74, 72, 70, 69, 67, 65, 64, 62, 60, 58, 57, 55, 53, 52, 50, 48, 46, 45, 43, 41, 40, 38, 36, 34, 33, 31, 29, 28, 26, 24, 22, 21, 19, 17, 16, 14, 12        }
-  ,
-  {
-    124, 122, 120, 117, 115, 112, 110, 108, 105, 103, 100, 98, 96, 93, 91, 88, 86, 84, 81, 79, 76, 74, 72, 69, 67, 64, 62, 60, 57, 55, 52, 50, 48, 45, 43, 40, 38, 36, 33, 31, 28, 26, 24, 21, 19, 16, 14, 12, 9, 7, 4, 2, 0, 253, 251, 248        }
-  ,
-  {
-    106, 104, 103, 101, 99, 97, 96, 94, 92, 91, 89, 87, 85, 84, 82, 80, 79, 77, 75, 73, 72, 70, 68, 67, 65, 63, 61, 60, 58, 56, 55, 53, 51, 49, 48, 46, 44, 43, 41, 39, 37, 36, 34, 32, 31, 29, 27, 25, 24, 22, 20, 19, 17, 15, 13, 12        }
-  ,
-  {
-    107, 106, 103, 101, 99, 97, 96, 95, 94, 91, 89, 87, 85, 84, 83, 82, 79, 77, 75, 73, 72, 71, 70, 67, 65, 63, 61, 60, 59, 58, 55, 53, 51, 49, 48, 47, 46, 43, 41, 39, 37, 36, 35, 34, 31, 29, 27, 25, 24, 23, 22, 19, 17, 15, 13, 12        }
-  ,
-  {
-    96, 95, 94, 93, 91, 89, 88, 87, 86, 84, 83, 82, 81, 79, 77, 76, 75, 74, 72, 71, 70, 69, 67, 65, 64, 63, 62, 60, 59, 58, 57, 55, 53, 52, 51, 50, 48, 47, 46, 45, 43, 41, 40, 39, 38, 36, 35, 34, 33, 31, 29, 28, 27, 26, 24, 23        }
-  ,
-  {
-    114, 112, 110, 108, 106, 104, 102, 100, 98, 96, 94, 92, 90, 88, 86, 84, 82, 80, 78, 76, 74, 72, 70, 68, 66, 64, 62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4        }
-  ,
-  {
-    100, 99, 97, 96, 94, 92, 90, 89, 88, 87, 85, 84, 82, 80, 78, 77, 76, 75, 73, 72, 70, 68, 66, 65, 64, 63, 61, 60, 58, 56, 54, 53, 52, 51, 49, 48, 46, 44, 42, 41, 40, 39, 37, 36, 34, 32, 30, 29, 28, 27, 25, 24, 22, 20, 18, 17        }
-  ,
-  {
-    112, 111, 109, 108, 104, 103, 100, 99, 97, 96, 92, 91, 88, 87, 85, 84, 80, 79, 76, 75, 73, 72, 68, 67, 64, 63, 61, 60, 56, 55, 52, 51, 49, 48, 44, 43, 40, 39, 37, 36, 32, 31, 28, 27, 25, 24, 20, 19, 16, 15, 13, 12, 8, 7, 4, 3        }
-  ,
-  {
-    123, 122, 120, 117, 115, 111, 110, 108, 105, 103, 99, 98, 96, 93, 91, 87, 86, 84, 81, 79, 75, 74, 72, 69, 67, 63, 62, 60, 57, 55, 51, 50, 48, 45, 43, 39, 38, 36, 33, 31, 27, 26, 24, 21, 19, 15, 14, 12, 9, 7, 3, 2, 0, 253, 251, 247        }
-  ,
-  {
-    125, 121, 120, 118, 114, 113, 109, 108, 106, 102, 101, 97, 96, 94, 90, 89, 85, 84, 82, 78, 77, 73, 72, 70, 66, 65, 61, 60, 58, 54, 53, 49, 48, 46, 42, 41, 37, 36, 34, 30, 29, 25, 24, 22, 18, 17, 13, 12, 10, 6, 5, 1, 0, 254, 250, 249        }
-  ,
-  {
-    125, 121, 120, 118, 115, 113, 109, 108, 106, 103, 101, 97, 96, 94, 91, 89, 85, 84, 82, 79, 77, 73, 72, 70, 67, 65, 61, 60, 58, 55, 53, 49, 48, 46, 43, 41, 37, 36, 34, 31, 29, 25, 24, 22, 19, 17, 13, 12, 10, 7, 5, 1, 0, 254, 251, 249        }
-  ,
-  {
-    123, 122, 120, 116, 115, 111, 110, 108, 104, 103, 99, 98, 96, 92, 91, 87, 86, 84, 80, 79, 75, 74, 72, 68, 67, 63, 62, 60, 56, 55, 51, 50, 48, 44, 43, 39, 38, 36, 32, 31, 27, 26, 24, 20, 19, 15, 14, 12, 8, 7, 3, 2, 0, 252, 251, 247        }
-  ,
-  {
-    107, 104, 103, 102, 99, 98, 96, 95, 92, 91, 90, 87, 86, 84, 83, 80, 79, 78, 75, 74, 72, 71, 68, 67, 66, 63, 62, 60, 59, 56, 55, 54, 51, 50, 48, 47, 44, 43, 42, 39, 38, 36, 35, 32, 31, 30, 27, 26, 24, 23, 20, 19, 18, 15, 14, 12        }
-  ,
-  {
-    107, 104, 103, 101, 100, 97, 96, 95, 92, 91, 89, 88, 85, 84, 83, 80, 79, 77, 76, 73, 72, 71, 68, 67, 65, 64, 61, 60, 59, 56, 55, 53, 52, 49, 48, 47, 44, 43, 41, 40, 37, 36, 35, 32, 31, 29, 28, 25, 24, 23, 20, 19, 17, 16, 13, 12        }
-  ,
-  {
-    106, 104, 102, 100, 99, 97, 96, 94, 92, 90, 88, 87, 85, 84, 82, 80, 78, 76, 75, 73, 72, 70, 68, 66, 64, 63, 61, 60, 58, 56, 54, 52, 51, 49, 48, 46, 44, 42, 40, 39, 37, 36, 34, 32, 30, 28, 27, 25, 24, 22, 20, 18, 16, 15, 13, 12        }
-  ,
-  {
-    125, 123, 120, 118, 115, 113, 111, 108, 106, 103, 101, 99, 96, 94, 91, 89, 87, 84, 82, 79, 77, 75, 72, 70, 67, 65, 63, 60, 58, 55, 53, 51, 48, 46, 43, 41, 39, 36, 34, 31, 29, 27, 24, 22, 19, 17, 15, 12, 10, 7, 5, 3, 0, 254, 251, 249        }
+    107, 105, 103, 101, 100, 98, 96, 95, 93, 91, 89, 88, 86, 84, 83, 81, 79, 77, 76, 74, 72, 71, 69, 67, 65, 64, 62, 60, 59, 57, 55, 53, 52, 50, 48, 47, 45, 43, 41, 40, 38, 36, 35, 33, 31, 29, 28, 26, 24, 23, 21, 19, 17, 16, 14, 12              }
+  ,
+  {
+    106, 104, 103, 101, 99, 98, 96, 94, 92, 91, 89, 87, 86, 84, 82, 80, 79, 77, 75, 74, 72, 70, 68, 67, 65, 63, 62, 60, 58, 56, 55, 53, 51, 50, 48, 46, 44, 43, 41, 39, 38, 36, 34, 32, 31, 29, 27, 26, 24, 22, 20, 19, 17, 15, 14, 12              }
+  ,
+  {
+    87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32              }
+  ,
+  {
+    114, 113, 111, 108, 106, 103, 102, 101, 99, 96, 94, 91, 90, 89, 87, 84, 82, 79, 78, 77, 75, 72, 70, 67, 66, 65, 63, 60, 58, 55, 54, 53, 51, 48, 46, 43, 42, 41, 39, 36, 34, 31, 30, 29, 27, 24, 22, 19, 18, 17, 15, 12, 10, 7, 6, 5              }
+  ,
+  {
+    100, 99, 97, 96, 94, 93, 91, 90, 88, 87, 85, 84, 82, 81, 79, 78, 76, 75, 73, 72, 70, 69, 67, 66, 64, 63, 61, 60, 58, 57, 55, 54, 52, 51, 49, 48, 46, 45, 43, 42, 40, 39, 37, 36, 34, 33, 31, 30, 28, 27, 25, 24, 22, 21, 19, 18              }
+  ,
+  {
+    96, 95, 94, 93, 92, 91, 89, 87, 86, 84, 83, 82, 81, 80, 79, 77, 75, 74, 72, 71, 70, 69, 68, 67, 65, 63, 62, 60, 59, 58, 57, 56, 55, 53, 51, 50, 48, 47, 46, 45, 44, 43, 41, 39, 38, 36, 35, 34, 33, 32, 31, 29, 27, 26, 24, 23              }
+  ,
+  {
+    107, 104, 103, 101, 100, 98, 96, 95, 92, 91, 89, 88, 86, 84, 83, 80, 79, 77, 76, 74, 72, 71, 68, 67, 65, 64, 62, 60, 59, 56, 55, 53, 52, 50, 48, 47, 44, 43, 41, 40, 38, 36, 35, 32, 31, 29, 28, 26, 24, 23, 20, 19, 17, 16, 14, 12              }
+  ,
+  {
+    107, 104, 103, 101, 99, 98, 96, 95, 92, 91, 89, 87, 86, 84, 83, 80, 79, 77, 75, 74, 72, 71, 68, 67, 65, 63, 62, 60, 59, 56, 55, 53, 51, 50, 48, 47, 44, 43, 41, 39, 38, 36, 35, 32, 31, 29, 27, 26, 24, 23, 20, 19, 17, 15, 14, 12              }
+  ,
+  {
+    107, 105, 103, 101, 99, 98, 96, 95, 93, 91, 89, 87, 86, 84, 83, 81, 79, 77, 75, 74, 72, 71, 69, 67, 65, 63, 62, 60, 59, 57, 55, 53, 51, 50, 48, 47, 45, 43, 41, 39, 38, 36, 35, 33, 31, 29, 27, 26, 24, 23, 21, 19, 17, 15, 14, 12              }
+  ,
+  {
+    115, 111, 110, 108, 107, 105, 103, 99, 98, 96, 95, 93, 91, 87, 86, 84, 83, 81, 79, 75, 74, 72, 71, 69, 67, 63, 62, 60, 59, 57, 55, 51, 50, 48, 47, 45, 43, 39, 38, 36, 35, 33, 31, 27, 26, 24, 23, 21, 19, 15, 14, 12, 11, 9, 7, 3              }
+  ,
+  {
+    106, 105, 102, 101, 100, 97, 96, 94, 93, 90, 89, 88, 85, 84, 82, 81, 78, 77, 76, 73, 72, 70, 69, 66, 65, 64, 61, 60, 58, 57, 54, 53, 52, 49, 48, 46, 45, 42, 41, 40, 37, 36, 34, 33, 30, 29, 28, 25, 24, 22, 21, 18, 17, 16, 13, 12              }
+  ,
+  {
+    106, 103, 102, 101, 100, 98, 96, 94, 91, 90, 89, 88, 86, 84, 82, 79, 78, 77, 76, 74, 72, 70, 67, 66, 65, 64, 62, 60, 58, 55, 54, 53, 52, 50, 48, 46, 43, 42, 41, 40, 38, 36, 34, 31, 30, 29, 28, 26, 24, 22, 19, 18, 17, 16, 14, 12              }
+  ,
+  {
+    96, 95, 93, 92, 91, 89, 88, 87, 85, 84, 83, 81, 80, 79, 77, 76, 75, 73, 72, 71, 69, 68, 67, 65, 64, 63, 61, 60, 59, 57, 56, 55, 53, 52, 51, 49, 48, 47, 45, 44, 43, 41, 40, 39, 37, 36, 35, 33, 32, 31, 29, 28, 27, 25, 24, 23              }
+  ,
+  {
+    106, 105, 103, 101, 99, 98, 96, 94, 93, 91, 89, 87, 86, 84, 82, 81, 79, 77, 75, 74, 72, 70, 69, 67, 65, 63, 62, 60, 58, 57, 55, 53, 51, 50, 48, 46, 45, 43, 41, 39, 38, 36, 34, 33, 31, 29, 27, 26, 24, 22, 21, 19, 17, 15, 14, 12              }
+  ,
+  {
+    106, 104, 101, 100, 97, 97, 96, 94, 92, 89, 88, 85, 85, 84, 82, 80, 77, 76, 73, 73, 72, 70, 68, 65, 64, 61, 61, 60, 58, 56, 53, 52, 49, 49, 48, 46, 44, 41, 40, 37, 37, 36, 34, 32, 29, 28, 25, 25, 24, 22, 20, 17, 16, 13, 13, 12              }
+  ,
+  {
+    106, 104, 102, 101, 99, 97, 96, 94, 92, 90, 89, 87, 85, 84, 82, 80, 78, 77, 75, 73, 72, 70, 68, 66, 65, 63, 61, 60, 58, 56, 54, 53, 51, 49, 48, 46, 44, 42, 41, 39, 37, 36, 34, 32, 30, 29, 27, 25, 24, 22, 20, 18, 17, 15, 13, 12              }
+  ,
+  {
+    106, 105, 103, 102, 100, 98, 96, 94, 93, 91, 90, 88, 86, 84, 82, 81, 79, 78, 76, 74, 72, 70, 69, 67, 66, 64, 62, 60, 58, 57, 55, 54, 52, 50, 48, 46, 45, 43, 42, 40, 38, 36, 34, 33, 31, 30, 28, 26, 24, 22, 21, 19, 18, 16, 14, 12              }
+  ,
+  {
+    96, 95, 94, 93, 92, 91, 89, 87, 86, 84, 83, 82, 81, 80, 79, 77, 75, 74, 72, 71, 70, 69, 68, 67, 65, 63, 62, 60, 59, 58, 57, 56, 55, 53, 51, 50, 48, 47, 46, 45, 44, 43, 41, 39, 38, 36, 35, 34, 33, 32, 31, 29, 27, 26, 24, 23              }
+  ,
+  {
+    106, 105, 103, 101, 100, 98, 96, 94, 93, 91, 89, 88, 86, 84, 82, 81, 79, 77, 76, 74, 72, 70, 69, 67, 65, 64, 62, 60, 58, 57, 55, 53, 52, 50, 48, 46, 45, 43, 41, 40, 38, 36, 34, 33, 31, 29, 28, 26, 24, 22, 21, 19, 17, 16, 14, 12              }
+  ,
+  {
+    124, 122, 120, 117, 115, 112, 110, 108, 105, 103, 100, 98, 96, 93, 91, 88, 86, 84, 81, 79, 76, 74, 72, 69, 67, 64, 62, 60, 57, 55, 52, 50, 48, 45, 43, 40, 38, 36, 33, 31, 28, 26, 24, 21, 19, 16, 14, 12, 9, 7, 4, 2, 0, 253, 251, 248              }
+  ,
+  {
+    106, 104, 103, 101, 99, 97, 96, 94, 92, 91, 89, 87, 85, 84, 82, 80, 79, 77, 75, 73, 72, 70, 68, 67, 65, 63, 61, 60, 58, 56, 55, 53, 51, 49, 48, 46, 44, 43, 41, 39, 37, 36, 34, 32, 31, 29, 27, 25, 24, 22, 20, 19, 17, 15, 13, 12              }
+  ,
+  {
+    107, 106, 103, 101, 99, 97, 96, 95, 94, 91, 89, 87, 85, 84, 83, 82, 79, 77, 75, 73, 72, 71, 70, 67, 65, 63, 61, 60, 59, 58, 55, 53, 51, 49, 48, 47, 46, 43, 41, 39, 37, 36, 35, 34, 31, 29, 27, 25, 24, 23, 22, 19, 17, 15, 13, 12              }
+  ,
+  {
+    96, 95, 94, 93, 91, 89, 88, 87, 86, 84, 83, 82, 81, 79, 77, 76, 75, 74, 72, 71, 70, 69, 67, 65, 64, 63, 62, 60, 59, 58, 57, 55, 53, 52, 51, 50, 48, 47, 46, 45, 43, 41, 40, 39, 38, 36, 35, 34, 33, 31, 29, 28, 27, 26, 24, 23              }
+  ,
+  {
+    114, 112, 110, 108, 106, 104, 102, 100, 98, 96, 94, 92, 90, 88, 86, 84, 82, 80, 78, 76, 74, 72, 70, 68, 66, 64, 62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4              }
+  ,
+  {
+    100, 99, 97, 96, 94, 92, 90, 89, 88, 87, 85, 84, 82, 80, 78, 77, 76, 75, 73, 72, 70, 68, 66, 65, 64, 63, 61, 60, 58, 56, 54, 53, 52, 51, 49, 48, 46, 44, 42, 41, 40, 39, 37, 36, 34, 32, 30, 29, 28, 27, 25, 24, 22, 20, 18, 17              }
+  ,
+  {
+    112, 111, 109, 108, 104, 103, 100, 99, 97, 96, 92, 91, 88, 87, 85, 84, 80, 79, 76, 75, 73, 72, 68, 67, 64, 63, 61, 60, 56, 55, 52, 51, 49, 48, 44, 43, 40, 39, 37, 36, 32, 31, 28, 27, 25, 24, 20, 19, 16, 15, 13, 12, 8, 7, 4, 3              }
+  ,
+  {
+    123, 122, 120, 117, 115, 111, 110, 108, 105, 103, 99, 98, 96, 93, 91, 87, 86, 84, 81, 79, 75, 74, 72, 69, 67, 63, 62, 60, 57, 55, 51, 50, 48, 45, 43, 39, 38, 36, 33, 31, 27, 26, 24, 21, 19, 15, 14, 12, 9, 7, 3, 2, 0, 253, 251, 247              }
+  ,
+  {
+    125, 121, 120, 118, 114, 113, 109, 108, 106, 102, 101, 97, 96, 94, 90, 89, 85, 84, 82, 78, 77, 73, 72, 70, 66, 65, 61, 60, 58, 54, 53, 49, 48, 46, 42, 41, 37, 36, 34, 30, 29, 25, 24, 22, 18, 17, 13, 12, 10, 6, 5, 1, 0, 254, 250, 249              }
+  ,
+  {
+    125, 121, 120, 118, 115, 113, 109, 108, 106, 103, 101, 97, 96, 94, 91, 89, 85, 84, 82, 79, 77, 73, 72, 70, 67, 65, 61, 60, 58, 55, 53, 49, 48, 46, 43, 41, 37, 36, 34, 31, 29, 25, 24, 22, 19, 17, 13, 12, 10, 7, 5, 1, 0, 254, 251, 249              }
+  ,
+  {
+    123, 122, 120, 116, 115, 111, 110, 108, 104, 103, 99, 98, 96, 92, 91, 87, 86, 84, 80, 79, 75, 74, 72, 68, 67, 63, 62, 60, 56, 55, 51, 50, 48, 44, 43, 39, 38, 36, 32, 31, 27, 26, 24, 20, 19, 15, 14, 12, 8, 7, 3, 2, 0, 252, 251, 247              }
+  ,
+  {
+    107, 104, 103, 102, 99, 98, 96, 95, 92, 91, 90, 87, 86, 84, 83, 80, 79, 78, 75, 74, 72, 71, 68, 67, 66, 63, 62, 60, 59, 56, 55, 54, 51, 50, 48, 47, 44, 43, 42, 39, 38, 36, 35, 32, 31, 30, 27, 26, 24, 23, 20, 19, 18, 15, 14, 12              }
+  ,
+  {
+    107, 104, 103, 101, 100, 97, 96, 95, 92, 91, 89, 88, 85, 84, 83, 80, 79, 77, 76, 73, 72, 71, 68, 67, 65, 64, 61, 60, 59, 56, 55, 53, 52, 49, 48, 47, 44, 43, 41, 40, 37, 36, 35, 32, 31, 29, 28, 25, 24, 23, 20, 19, 17, 16, 13, 12              }
+  ,
+  {
+    106, 104, 102, 100, 99, 97, 96, 94, 92, 90, 88, 87, 85, 84, 82, 80, 78, 76, 75, 73, 72, 70, 68, 66, 64, 63, 61, 60, 58, 56, 54, 52, 51, 49, 48, 46, 44, 42, 40, 39, 37, 36, 34, 32, 30, 28, 27, 25, 24, 22, 20, 18, 16, 15, 13, 12              }
+  ,
+  {
+    125, 123, 120, 118, 115, 113, 111, 108, 106, 103, 101, 99, 96, 94, 91, 89, 87, 84, 82, 79, 77, 75, 72, 70, 67, 65, 63, 60, 58, 55, 53, 51, 48, 46, 43, 41, 39, 36, 34, 31, 29, 27, 24, 22, 19, 17, 15, 12, 10, 7, 5, 3, 0, 254, 251, 249              }
 };

 /*
@@ -289,7 +283,7 @@
   EEPROM.write(address + 0, 0xd5); // magic number d6aa96
   EEPROM.write(address + 1, 0xaa);
   EEPROM.write(address + 2, 0x96);
-  EEPROM.write(address + 3, 0x03); // version 2
+  EEPROM.write(address + 3, 0x03); // version 3
   address += 4;
   saveToEEPROM(address, (uint8_t *)&grid[0], sizeof(grid));
   address += sizeof(grid);
@@ -327,7 +321,7 @@
   if ((EEPROM.read(address + 0) == 0xd5) && // magic number d6aa96
   (EEPROM.read(address + 1) == 0xaa) &&
     (EEPROM.read(address + 2) == 0x96) &&
-    (EEPROM.read(address + 3) == 0x03)) // version 2
+    (EEPROM.read(address + 3) == 0x03)) // version 3
   {
     address += 4;
     loadFromEEPROM(address, (uint8_t *)&grid[0], sizeof(grid));
@@ -390,7 +384,7 @@
   memset(channels, 2, sizeof(channels)); // default all channels to 2
   memset(long_notes, 0, sizeof(long_notes));  // default all layers to short notes
   memset(tempo, 240/4, sizeof(long_notes));  // default all grids to 240 bpm
-// todo make sure all channels are always different for all layers
+  // todo make sure all channels are always different for all layers
   channels[0] = 3;
   channels[1] = 4;
   channels[2] = 5;
@@ -434,8 +428,10 @@
     synth.programChange(0, this_channel, this_instrument);
     usbMIDI.sendControlChange(7, this_volume, this_channel);
     synth.setChannelVolume(this_channel, this_volume);
-  }
-
+    usbMIDI.sendControlChange(0x7b, 0, this_channel);
+    synth.allNotesOff(this_channel);
+  }
+
   for (uint8_t grid_index = 0; grid_index < GRID_SETS; grid_index++)
   {
     beatInterval[grid_index] = 15000L / tempo[grid_index];
@@ -732,7 +728,7 @@

               visible_grid_set = x;
               eTempo.setValue(tempo[visible_grid_set] * 16);  // *4's for encoder detents and *4 for byte storage
-
+
               mode = PLAYING_ERASE_GRID_1;

               // redraw whole screen because grid change
@@ -811,7 +807,7 @@
                 temp = MAX_SCALES - 1;
               }
               scale_notes[layer] = temp;
-
+
               // flip the long note setting
               if (long_notes[layer] == 0)
               {
@@ -821,9 +817,10 @@
               {
                 long_notes[layer] = 0;
               }
-
+
               // Send midi control change all notes off for that channel because new scale might not contain any of the old notes that are currently playing
               usbMIDI.sendControlChange(0x7b, 0, channels[layer]);
+              synth.allNotesOff(channels[layer]);

               force_first_note = true;

@@ -885,7 +882,6 @@
       {
         if (diff > 0)
         {
-          // todo need to stop the notes that will be scrolled off
           grid[column_index][layer][visible_grid_set] <<= diff;
         }
         else
@@ -894,17 +890,21 @@
         }
       }

+      // Send midi control change all notes off because we might have scrolled off playing notes
+      usbMIDI.sendControlChange(0x7b, 0, channels[layer]);
+synth.allNotesOff(channels[layer]);
+
       // shift all notes and redraw columns
       for(uint8_t row_index=0; row_index < grid_width[visible_grid_set]; row_index++)
       {
-        #if 0 //decided I don't like this
+#if 0 //decided I don't like this
         if (((temp + row_index) % 7) == 0) //todo this needs to actually point to the C's in a scale (%7 for the moment), scales can have different sizes but Middle C is always placed in the center of the note scale.
         {
           line_horz(row_index, true);
           //todo need to adjust encoder value back a notch when at limit so that we can detect when it moves further at the end of travel by looking at the undivided by 4 value
         }
         else
-        #endif
+#endif
         {
           line_horz(row_index, false);
         }
@@ -928,14 +928,14 @@
       // redraw all columns
       for(uint8_t column_index=0; column_index < BUTTON_GRID_WIDTH; column_index++)
       {
-        #if 0 // decided I don't like this
+#if 0 // decided I don't like this
         if (((temp + column_index) % 4) == 0) //todo hard coded 4 beats a measure for indicator, need to make configured by grid width setting
         {
           line_vert(column_index, true);
           //todo need to adjust encoder value back a notch when at limit so that we can detect when it moves further at the end of travel by looking at the undivided by 4 value
         }
         else
-        #endif
+#endif
         {
           line_vert(column_index, false);
         }
@@ -1039,8 +1039,9 @@
     refresh      = true;

     // todo add display of currnet tempo with a horizontal bar, possibley show other layer tempos
-    tempo[visible_grid_set] = eTempo.getValue() / 16 ; // Div4 for encoder detents and Div4 byte storage
-    beatInterval[visible_grid_set] = 15000L / tempo[visible_grid_set];
+    int temp2 = eTempo.getValue() / 4; // Div4 for encoder detents
+    tempo[visible_grid_set] = temp2 / 4 ; // Div4 byte storage
+    beatInterval[visible_grid_set] = 60000L / temp2;
   }

   // replace lines that may have been erased by play column movement
@@ -1238,6 +1239,7 @@

     // Send midi control change all notes off
     usbMIDI.sendControlChange(0x7b, 0, channels[layer]);
+    synth.allNotesOff(channels[layer]);
   }
 #endif

@@ -1510,3 +1512,6 @@

+
+
+


add description

add description

--- IAQ/IAQ.ino
+++ IAQ/IAQ.ino
@@ -81,7 +81,7 @@
 void setup() {
   Serial.begin(115200);
   Wire.begin();
-  delay(5000);
+  delay(10000);
   attachInterrupt(1, rising, RISING);
 }

@@ -96,14 +96,17 @@
   }
   pwm_co2 = 40*pwm_value1-1800;
   pwm_voc = 25*pwm_value2-125;
-
-  //Serial.print(pwm_value1);
-  //Serial.print(" ");
-  //Serial.println(pwm_value2);
+
+  Serial.print("SGX in PWM (%): CO2 ");
+  Serial.print(pwm_value1);
+  Serial.print(" VOC ");
+  Serial.println(pwm_value2);
   Serial.print("CO2: ");
-  Serial.println(pwm_co2);
-  Serial.print("VOC: ");
-  Serial.println(pwm_voc);
+  Serial.print(pwm_co2);
+  Serial.print(" ppm ");
+  Serial.print(" VOC: ");
+  Serial.print(pwm_voc);
+  Serial.println(" ppa");
 }

 // the loop function runs over and over again forever
@@ -113,8 +116,9 @@
   {
     ppm = readPPM();

-    Serial.print("6713 ppm: ");
-    Serial.println(ppm);
+    Serial.print("6713: ");
+    Serial.print(ppm);
+    Serial.println(" ppm");
      readVOC();
 	// 6713 sample CO2 every 5 seconds
     delay(5000);


Ex: fiWDRC_8BandFreqWarpFIR fix missing audioTestMeasurement

In response to Issue #20

--- examples/05-FullSystems/WDRC_8BandFreqWarpFIR/WDRC_8BandFreqWarpFIR.ino
+++ examples/05-FullSystems/WDRC_8BandFreqWarpFIR/WDRC_8BandFreqWarpFIR.ino
@@ -41,6 +41,7 @@
 AudioOutputI2S_F32              i2s_out(audio_settings);       //Digital audio *to* the Teensy Audio Board DAC.

 //complete the creation of the tester objects
+AudioTestSignalMeasurement_F32  audioTestMeasurement(audio_settings);
 AudioTestSignalMeasurementMulti_F32  audioTestMeasurement_FIR(audio_settings);
 AudioControlTestAmpSweep_F32    ampSweepTester(audio_settings,audioTestGenerator,audioTestMeasurement);
 AudioControlTestFreqSweep_F32   freqSweepTester(audio_settings,audioTestGenerator,audioTestMeasurement);


Repeat STARTED message x3

Repeat STARTED message x3

--- OxFloodNet_Sensor/OxFloodNet_Sensor.ino
+++ OxFloodNet_Sensor/OxFloodNet_Sensor.ino
@@ -389,8 +389,33 @@
     LLAP.sendInt("ERR",val); // Diagnostic
     delay(5000);	// try again in 5 seconds
   }
-
-  LLAP.sendMessage("STARTED");
+  for(int i=0;i<3;i++) {
+    LLAP.sendMessage("STARTED");
+  }
+
+
+
+    // Initial Distance reading
+    uint16_t cm = getRange();
+    // Send temperature reading
+    if( tempSensorFound ) {
+      int latestTemp = (int)(latestTemperature * 100);
+      LLAP.sendIntWithDP( "T", latestTemp, 2);
+    }
+    // Uncompensated distance
+    LLAP.sendInt( "D", lastUncompDistance);
+    // Send reading 3 times to make sure it gets through
+    for(int n = 0; n<1; n++ ) {
+      if( cm > 17 ) {
+        LLAP.sendInt( "U", cm );
+      }
+      else if( cm == 0 ) {
+        LLAP.sendMessage( "UMax" );
+      }
+      else {
+        LLAP.sendMessage( "UErr" );
+      }
+    }

 }


beautifying

beautifying

--- mwsLRWHFv2/mwsLRWHFv2.ino
+++ mwsLRWHFv2/mwsLRWHFv2.ino
@@ -151,7 +151,6 @@
 //Rain time stamp
 int Rainindi=0;
 //Variables used for GPS
-//float flat, flon; // 39.015024 -102.283608686
 //unsigned long age;
 //int year;
 //byte month, day, hour, minute, second, hundredths;
@@ -601,7 +600,6 @@
   lcd.print(F(" C"));
   delay(5000);

-  //Not enough dynamic memory in UNO
   lcd.clear();
   lcd.print("R:");
   lcd.print(dailyrainin);
@@ -612,7 +610,6 @@
   lcd.print(F(" hPa"));
   delay(5000);

-  //Not enough dynamic memory in UNO
   lcd.clear();
   lcd.print(F("Battery Level"));
   lcd.print(get_battery_level());


add debug flag

add debug flag

--- Arduino/firmware/firmware.ino
+++ Arduino/firmware/firmware.ino
@@ -29,6 +29,7 @@
 const int SERVO_PIN= 11;

 // Globals
+bool debug = false;
 volatile uint8_t updateFlagsShared;
 uint8_t updateFlags;
 const int THROTTLE_FLAG = 1;
@@ -191,7 +192,7 @@
   initActuators();

   armActuators();
-  Serial.begin(115200);
+  Serial.begin(38400); //115200);
 }

 void loop() {
@@ -237,10 +238,11 @@
     char ch = (char)Serial.read();
     if (ch == '\n') {
       if (cmdParse(&rc_outputs_steering, &rc_outputs_throttle)) {
-        Serial.print("****");
-        Serial.print(rc_outputs_steering);
-        Serial.println(rc_outputs_throttle);
-
+        if (debug) {
+          Serial.print("****");
+          Serial.print(rc_outputs_steering);
+          Serial.println(rc_outputs_throttle);
+        }
         // output values have changed
         motor.write(rc_outputs_throttle);
         steering.write(rc_outputs_steering);


Just can't get the staff these days.  B^>

--- Arduino/V0p2_Main/V0p2_Main.ino
+++ Arduino/V0p2_Main/V0p2_Main.ino
@@ -760,7 +760,7 @@
   serialStatusReport();
 #endif

-  Report current stack usage.
+  // Report current stack usage.
   OTV0P2BASE::MemoryChecks::resetMinSP();
   OTV0P2BASE::MemoryChecks::recordIfMinSP();
   stackCheck();


Fixed typo on serial output

Fixed typo on serial output

--- remote-control-by-phone/RemoteControl.ino
+++ remote-control-by-phone/RemoteControl.ino
@@ -76,7 +76,7 @@

   // when the light level dips by 30%
   if (LDRReading < (BASELINE * .7)) {
-    Serial.println("\nUh-oh! It's getting dark - better make a call. Dialling now...\n");
+    Serial.println("\nUh-oh! It's getting dark - better make a call. Dialing now...\n");
     digitalWrite(led, LOW); // turn off the light in case it's on from a previous event

     // if the user chooses option 1 when they receive the phone call


Added RF24Network send capability to RF24Node

--- Prototype/RF24Node/RF24Node.ino
+++ Prototype/RF24Node/RF24Node.ino
@@ -10,7 +10,7 @@

 /* *** Globals and sketch configuration *** */
-#define DEBUG           0 /* Enable trace statements */
+#define DEBUG           1 /* Enable trace statements */
 #define SERIAL          1 /* Enable serial */

 #define _MEM            1   // Report free memory
@@ -19,7 +19,7 @@

 #define REPORT_EVERY    2   // report every N measurement cycles
 #define SMOOTH          5   // smoothing factor used for running averages
-#define MEASURE_PERIOD  10  // how often to measure, in tenths of seconds
+#define MEASURE_PERIOD  3  // how often to measure, in tenths of seconds
 #define SCHEDULER_DELAY 100 //ms
 #define UI_DELAY        10000
 #define UI_IDLE         4000  // tenths of seconds idle time, ...
@@ -229,15 +229,6 @@
 // Address of the other node
 const uint16_t other_node = 0;

-// How often to send 'hello world to the other unit
-const unsigned long interval = 2000; //ms
-
-// When did we last send?
-unsigned long last_sent;
-
-// How many have we sent already
-unsigned long packets_sent;
-
 #endif // NRF24

 #if _LCD
@@ -462,13 +453,12 @@
 #endif//SERIAL

 #if _NRF24
-	//payload_t payload = { millis(), packets_sent++ };
 	RF24NetworkHeader header(/*to node*/ other_node);
 	bool ok = network.write(header, &payload, sizeof(payload));
 	if (ok)
-		Serial.println("ok.");
+		debugline("ACK");
 	else
-		Serial.println("failed.");
+		debugline("NACK");
 #endif // NRF24
 }

@@ -584,7 +574,7 @@

 void loop(void)
 {
-	network.update();
+	//network.update();
 	if (ui_irq) {
 		debugline("Irq");
 		ui_irq = false;


fix build error

fix build error

--- Examples/SPIDaisyChain/SPIDaisyChain.ino
+++ Examples/SPIDaisyChain/SPIDaisyChain.ino
@@ -6,7 +6,7 @@
 SPIDaisyChain spi(PIN_CS, NUM_DEVICE);	// CS pin, chained number

 byte send_data[NUM_DEVICE] = {1, 2, 3};
-byte recv_data[NUM_DEVICE] = {0, 0, 0};
+byte* recv_data;

 void setup()
 {
@@ -15,7 +15,7 @@
 void loop()
 {
     // send data[0] to far device, data[1] to near device
-    recv_data = spi.transferDaisyChain(data);
+    recv_data = spi.transferDaisyChain(send_data);

     for (uint8_t i = 0; i < NUM_DEVICE; ++i)
     {


Refactor to support different interfaces in same source

--- Valokepakko.ino
+++ Valokepakko.ino
@@ -7,6 +7,19 @@
 #ifdef __AVR__
   #include <avr/power.h>
 #endif
+
+/****************************************************/
+/* Here you choose which kind of interface is used. */
+/*                                                  */
+/* TIMER Timer based                                */
+/* TILT Orientation based                           */
+/* WHEEL Wheel rotation based                       */
+/*                                                  */
+/* Uncomment only ONE line at a time.               */
+/****************************************************/
+// #define TIMER;
+#define TILT;
+// #define WHEEL;

 const int LED_PIN = 6;

@@ -69,20 +82,7 @@
   uint32_t c = strip.Color(rgb.r, rgb.g, rgb.b);
 }

-void loop() {
-  /**********************/
-  /* Accelerometer code */
-  /**********************/
-
-  // variables to read the pulse widths:
-  int pulseX, pulseY;
-  float angle;
-
-  pulseX = pulseIn(ACCEL_X_PIN, HIGH);
-  pulseY = pulseIn(ACCEL_Y_PIN, HIGH);
-  angle = atan2(pulseX-NO_TILT, pulseY-NO_TILT);
-
-  for (int led = 0; led < LEDS; led++) {
+uint32_t tiltColorLookup(int led, float angle) {
     const float originX = IMAGE_WIDTH / 2;
     const float originY = IMAGE_HEIGHT - 1;

@@ -102,9 +102,32 @@
     int pixelIndex = x + y * IMAGE_WIDTH;
     // If we are out of bounds set color to black
     if (x < 0 || x > IMAGE_WIDTH - 1 || y < 0 || y > IMAGE_HEIGHT - 1) {
-      pixelindex = -1;
+      pixelIndex = -1;
     }
     uint32_t c = lookupColor(pixelIndex);
+}
+
+void loop() {
+  /**********************/
+  /* Accelerometer code */
+  /**********************/
+
+  // variables to read the pulse widths:
+  int pulseX, pulseY;
+  float angle;
+
+  pulseX = pulseIn(ACCEL_X_PIN, HIGH);
+  pulseY = pulseIn(ACCEL_Y_PIN, HIGH);
+  angle = atan2(pulseX-NO_TILT, pulseY-NO_TILT);
+
+  /******************/
+  /* LED strip code */
+  /******************/
+
+  for (int led = 0; led < LEDS; led++) {
+#ifdef TILT
+    uint32_t c = tiltColorLookup(led, angle);
+#endif /* TILT */

     strip.setPixelColor(led, c);
   }