Convert quantizer function to use widgets module.

--- examples/qntzr/qntzr.ino
+++ examples/qntzr/qntzr.ino
@@ -21,6 +21,7 @@
  */

 #include <du-ino_function.h>
+#include <du-ino_widgets.h>
 #include <du-ino_scales.h>
 #include <avr/pgmspace.h>

@@ -33,21 +34,56 @@

 void trig_isr();

+void trigger_mode_scroll_callback(int delta);
+void key_scroll_callback(int delta);
+void scale_scroll_callback(int delta);
+void notes_click_callback(uint8_t selected);
+
 class DU_Quantizer_Function : public DUINO_Function {
  public:
   DU_Quantizer_Function() : DUINO_Function(0b00001100) { }

   virtual void setup()
   {
+    // build widget hierarchy
+    container_outer_ = new DUINO_WidgetContainer<2>(DUINO_Widget::DoubleClick);
+    container_top_ = new DUINO_WidgetContainer<3>(DUINO_Widget::Click, 2);
+    container_outer_->attach_child(container_top_, 0);
+    widget_trigger_mode_ = new DUINO_DisplayWidget(76, 0, 9, 9, DUINO_Widget::Full);
+    widget_trigger_mode_->attach_scroll_callback(trigger_mode_scroll_callback);
+    container_top_->attach_child(widget_trigger_mode_, 0);
+    widget_key_ = new DUINO_DisplayWidget(90, 0, 13, 9, DUINO_Widget::Full);
+    widget_key_->attach_scroll_callback(key_scroll_callback);
+    container_top_->attach_child(widget_key_, 1);
+    widget_scale_ = new DUINO_DisplayWidget(108, 0, 19, 9, DUINO_Widget::Full);
+    widget_scale_->attach_scroll_callback(scale_scroll_callback);
+    container_top_->attach_child(widget_scale_, 2);
+    container_notes_ = new DUINO_WidgetContainer<12>(DUINO_Widget::Scroll);
+    container_outer_->attach_child(container_notes_, 1);
+    widgets_notes_[0] = new DUINO_DisplayWidget(6, 54, 7, 7, DUINO_Widget::DottedBox);
+    widgets_notes_[1] = new DUINO_DisplayWidget(15, 29, 7, 7, DUINO_Widget::DottedBox);
+    widgets_notes_[2] = new DUINO_DisplayWidget(24, 54, 7, 7, DUINO_Widget::DottedBox);
+    widgets_notes_[3] = new DUINO_DisplayWidget(33, 29, 7, 7, DUINO_Widget::DottedBox);
+    widgets_notes_[4] = new DUINO_DisplayWidget(42, 54, 7, 7, DUINO_Widget::DottedBox);
+    widgets_notes_[5] = new DUINO_DisplayWidget(60, 54, 7, 7, DUINO_Widget::DottedBox);
+    widgets_notes_[6] = new DUINO_DisplayWidget(69, 29, 7, 7, DUINO_Widget::DottedBox);
+    widgets_notes_[7] = new DUINO_DisplayWidget(78, 54, 7, 7, DUINO_Widget::DottedBox);
+    widgets_notes_[8] = new DUINO_DisplayWidget(87, 29, 7, 7, DUINO_Widget::DottedBox);
+    widgets_notes_[9] = new DUINO_DisplayWidget(96, 54, 7, 7, DUINO_Widget::DottedBox);
+    widgets_notes_[10] = new DUINO_DisplayWidget(105, 29, 7, 7, DUINO_Widget::DottedBox);
+    widgets_notes_[11] = new DUINO_DisplayWidget(114, 54, 7, 7, DUINO_Widget::DottedBox);
+    for(uint8_t i = 0; i < 12; ++i)
+    {
+      container_notes_->attach_child(widgets_notes_[i], i);
+    }
+    container_notes_->attach_click_callback_array(notes_click_callback);
+
     trigger_mode = false;
     key = 0;
     scale_id = 0;
     scale = get_scale_by_id(scale_id);
     output_octave = 0;
     output_note = 0;
-    main_selected = false;
-    top_selected = 2;
-    note_selected = 0;
     current_displayed_note = 0;

     gt_attach_interrupt(GT3, trig_isr, FALLING);
@@ -56,100 +92,22 @@
     Display.draw_du_logo_sm(0, 0, DUINO_SH1106::White);
     Display.draw_text(16, 0, "QNTZR", DUINO_SH1106::White);

-    // draw C key
-    Display.draw_vline(1, 11, 52, DUINO_SH1106::White);
-    Display.draw_hline(2, 11, 9, DUINO_SH1106::White);
-    Display.draw_hline(2, 62, 15, DUINO_SH1106::White);
-    Display.draw_vline(11, 11, 29, DUINO_SH1106::White);
-    Display.draw_hline(12, 39, 5, DUINO_SH1106::White);
-    Display.draw_vline(17, 39, 24, DUINO_SH1106::White);
-
-    // draw Db key
-    Display.draw_vline(13, 11, 27, DUINO_SH1106::White);
-    Display.draw_hline(14, 11, 9, DUINO_SH1106::White);
-    Display.draw_hline(14, 37, 9, DUINO_SH1106::White);
-    Display.draw_vline(23, 11, 27, DUINO_SH1106::White);
-
-    // draw D key
-    Display.draw_vline(19, 39, 24, DUINO_SH1106::White);
-    Display.draw_hline(20, 39, 5, DUINO_SH1106::White);
-    Display.draw_hline(20, 62, 15, DUINO_SH1106::White);
-    Display.draw_vline(25, 11, 29, DUINO_SH1106::White);
-    Display.draw_hline(26, 11, 3, DUINO_SH1106::White);
-    Display.draw_vline(29, 11, 29, DUINO_SH1106::White);
-    Display.draw_hline(30, 39, 5, DUINO_SH1106::White);
-    Display.draw_vline(35, 39, 24, DUINO_SH1106::White);
-
-    // draw Eb key
-    Display.draw_vline(31, 11, 27, DUINO_SH1106::White);
-    Display.draw_hline(32, 11, 9, DUINO_SH1106::White);
-    Display.draw_hline(32, 37, 9, DUINO_SH1106::White);
-    Display.draw_vline(41, 11, 27, DUINO_SH1106::White);
-
-    // draw E key
-    Display.draw_vline(37, 39, 24, DUINO_SH1106::White);
-    Display.draw_hline(38, 39, 5, DUINO_SH1106::White);
-    Display.draw_hline(38, 62, 15, DUINO_SH1106::White);
-    Display.draw_vline(43, 11, 29, DUINO_SH1106::White);
-    Display.draw_hline(44, 11, 9, DUINO_SH1106::White);
-    Display.draw_vline(53, 11, 52, DUINO_SH1106::White);
-
-    // draw F key
-    Display.draw_vline(55, 11, 52, DUINO_SH1106::White);
-    Display.draw_hline(56, 11, 9, DUINO_SH1106::White);
-    Display.draw_hline(56, 62, 15, DUINO_SH1106::White);
-    Display.draw_vline(65, 11, 29, DUINO_SH1106::White);
-    Display.draw_hline(66, 39, 5, DUINO_SH1106::White);
-    Display.draw_vline(71, 39, 24, DUINO_SH1106::White);
-
-    // draw Gb key
-    Display.draw_vline(67, 11, 27, DUINO_SH1106::White);
-    Display.draw_hline(68, 11, 9, DUINO_SH1106::White);
-    Display.draw_hline(68, 37, 9, DUINO_SH1106::White);
-    Display.draw_vline(77, 11, 27, DUINO_SH1106::White);
-
-    // draw G key
-    Display.draw_vline(73, 39, 24, DUINO_SH1106::White);
-    Display.draw_hline(74, 39, 5, DUINO_SH1106::White);
-    Display.draw_hline(74, 62, 15, DUINO_SH1106::White);
-    Display.draw_vline(79, 11, 29, DUINO_SH1106::White);
-    Display.draw_hline(80, 11, 3, DUINO_SH1106::White);
-    Display.draw_vline(83, 11, 29, DUINO_SH1106::White);
-    Display.draw_hline(84, 39, 5, DUINO_SH1106::White);
-    Display.draw_vline(89, 39, 24, DUINO_SH1106::White);
-
-    // draw Ab key
-    Display.draw_vline(85, 11, 27, DUINO_SH1106::White);
-    Display.draw_hline(86, 11, 9, DUINO_SH1106::White);
-    Display.draw_hline(86, 37, 9, DUINO_SH1106::White);
-    Display.draw_vline(95, 11, 27, DUINO_SH1106::White);
-
-    // draw A key
-    Display.draw_vline(91, 39, 24, DUINO_SH1106::White);
-    Display.draw_hline(92, 39, 5, DUINO_SH1106::White);
-    Display.draw_hline(92, 62, 15, DUINO_SH1106::White);
-    Display.draw_vline(97, 11, 29, DUINO_SH1106::White);
-    Display.draw_hline(98, 11, 3, DUINO_SH1106::White);
-    Display.draw_vline(101, 11, 29, DUINO_SH1106::White);
-    Display.draw_hline(102, 39, 5, DUINO_SH1106::White);
-    Display.draw_vline(107, 39, 24, DUINO_SH1106::White);
-
-    // draw Bb key
-    Display.draw_vline(103, 11, 27, DUINO_SH1106::White);
-    Display.draw_hline(104, 11, 9, DUINO_SH1106::White);
-    Display.draw_hline(104, 37, 9, DUINO_SH1106::White);
-    Display.draw_vline(113, 11, 27, DUINO_SH1106::White);
-
-    // draw B key
-    Display.draw_vline(109, 39, 24, DUINO_SH1106::White);
-    Display.draw_hline(110, 39, 5, DUINO_SH1106::White);
-    Display.draw_hline(110, 62, 15, DUINO_SH1106::White);
-    Display.draw_vline(115, 11, 29, DUINO_SH1106::White);
-    Display.draw_hline(116, 11, 9, DUINO_SH1106::White);
-    Display.draw_vline(125, 11, 52, DUINO_SH1106::White);
+    // draw kays
+    draw_left_key(1, 11);     // C
+    draw_black_key(13, 11);   // Db
+    draw_center_key(19, 11);  // D
+    draw_black_key(31, 11);   // Eb
+    draw_right_key(37, 11);   // E
+    draw_left_key(55, 11);    // F
+    draw_black_key(67, 11);   // Gb
+    draw_center_key(73, 11);  // G
+    draw_black_key(85, 11);   // Ab
+    draw_center_key(91, 11);  // A
+    draw_black_key(103, 11);  // Bb
+    draw_right_key(109, 11);  // B

     invert_note(current_displayed_note);
-    invert_current_selection();
+    widget_setup(container_outer_);
     Display.display_all();

     display_trigger_mode();
@@ -161,151 +119,76 @@
   {
     if(!trigger_mode || triggered)
     {
-      if(!scale)
+      if(scale == 0)
       {
         cv_out(CO1, 0.0);
         output_octave = 0;
         output_note = 0;
-        triggered = false;
-        return;
-      }
-
-      // read input
-      float input = cv_read(CI1);
-
-      // find a lower bound
-      int below_octave = (int)input - 1;
-      uint8_t below_note = 0;
-      while(!(scale & (1 << below_note)))
-      {
-        below_note++;
-      }
-
-      // find closest lower and upper values
-      int above_octave = below_octave, octave = below_octave;
-      uint8_t above_note = below_note, note = below_note;
-      while(note_cv(above_octave, key, above_note) < input)
-      {
-        note++;
-        if(note > 11)
-        {
-          note = 0;
-          octave++;
-        }
-
-        if(scale & (1 << note))
-        {
-          below_octave = above_octave;
-          below_note = above_note;
-          above_octave = octave;
-          above_note = note;
-        }
-      }
-
-      // output the nearer of the two values
-      float below = note_cv(below_octave, key, below_note);
-      float above = note_cv(above_octave, key, above_note);
-      if(input - below < above - input)
-      {
-        cv_out(CO1, below);
-        octave = below_octave;
-        note = below_note;
       }
       else
       {
-        cv_out(CO1, above);
-        octave = above_octave;
-        note = above_note;
+        // read input
+        float input = cv_read(CI1);
+
+        // find a lower bound
+        int below_octave = (int)input - 1;
+        uint8_t below_note = 0;
+        while(!(scale & (1 << below_note)))
+        {
+          below_note++;
+        }
+
+        // find closest lower and upper values
+        int above_octave = below_octave, octave = below_octave;
+        uint8_t above_note = below_note, note = below_note;
+        while(note_cv(above_octave, key, above_note) < input)
+        {
+          note++;
+          if(note > 11)
+          {
+            note = 0;
+            octave++;
+          }
+
+          if(scale & (1 << note))
+          {
+            below_octave = above_octave;
+            below_note = above_note;
+            above_octave = octave;
+            above_note = note;
+          }
+        }
+
+        // output the nearer of the two values
+        float below = note_cv(below_octave, key, below_note);
+        float above = note_cv(above_octave, key, above_note);
+        if(input - below < above - input)
+        {
+          cv_out(CO1, below);
+          octave = below_octave;
+          note = below_note;
+        }
+        else
+        {
+          cv_out(CO1, above);
+          octave = above_octave;
+          note = above_note;
+        }
+
+        // send trigger and update display note if note has changed
+        if(octave != output_octave || note != output_note)
+        {
+          gt_out(GT1, true, true);
+          output_octave = octave;
+          output_note = note;
+        }
       }
-
-      // send trigger and update display note if note has changed
-      if(octave != output_octave || note != output_note)
-      {
-        gt_out(GT1, true, true);
-        output_octave = octave;
-        output_note = note;
-      }
-
+
       // reset trigger
       triggered = false;
     }

-    // handle encoder button press
-    DUINO_Encoder::Button b = Encoder.get_button();
-    if(b == DUINO_Encoder::DoubleClicked)
-    {
-      invert_current_selection();
-      main_selected = !main_selected;
-      invert_current_selection();
-    }
-    else if(b == DUINO_Encoder::Clicked)
-    {
-      if(main_selected)
-      {
-        scale ^= (1 << note_selected);
-        scale_id = get_id_from_scale(scale);
-        display_scale();
-        triggered = true;
-      }
-      else
-      {
-        invert_current_selection();
-        top_selected++;
-        top_selected %= 3;
-        invert_current_selection();
-      }
-    }
-
-    // handle encoder spin
-    int16_t v = Encoder.get_value();
-    if(v)
-    {
-      if(main_selected)
-      {
-        invert_current_selection();
-        note_selected += v;
-        note_selected %= 12;
-        if(note_selected < 0)
-        {
-          note_selected += 12;
-        }
-        invert_current_selection();
-      }
-      else
-      {
-        switch(top_selected)
-        {
-          case 0: // trigger mode
-            trigger_mode = v > 0;
-            display_trigger_mode();
-            break;
-          case 1: // key
-            key += v;
-            key %= 12;
-            if(key < 0)
-            {
-              key += 12;
-            }
-            display_key();
-            triggered = true;
-            break;
-          case 2: // scale
-            scale_id += v;
-            if(scale_id < -1)
-            {
-              scale_id = -1;
-            }
-            else if(scale_id >= N_SCALES)
-            {
-              scale_id = N_SCALES - 1;
-            }
-            scale = get_scale_by_id(scale_id);
-            display_scale();
-            triggered = true;
-            break;
-        }
-      }
-    }
+    widget_loop();

     // display current note
     if(output_note != current_displayed_note)
@@ -316,128 +199,107 @@
     }
   }

+  void widget_trigger_mode_scroll_callback(int delta)
+  {
+    trigger_mode = delta > 0;
+    display_trigger_mode();
+  }
+
+  void widget_key_scroll_callback(int delta)
+  {
+    key += delta;
+    key %= 12;
+    if(key < 0)
+    {
+      key += 12;
+    }
+    display_key();
+    triggered = true;
+  }
+
+  void widget_scale_scroll_callback(int delta)
+  {
+    scale_id += delta;
+    if(scale_id < -1)
+    {
+      scale_id = -1;
+    }
+    else if(scale_id >= N_SCALES)
+    {
+      scale_id = N_SCALES - 1;
+    }
+    scale = get_scale_by_id(scale_id);
+    display_scale();
+    triggered = true;
+  }
+
+  void widgets_notes_click_callback(uint8_t selected)
+  {
+    scale ^= (1 << selected);
+    scale_id = get_id_from_scale(scale);
+    display_scale();
+    triggered = true;
+  }
+
  private:
   float note_cv(int octave, uint8_t key, uint8_t note)
   {
     return (float)octave + (float)key / 12.0 + (float)note / 12.0;
   }

-  void get_note_indicator_coordinates(uint8_t note, uint16_t * x, uint16_t * y)
-  {
-    switch(note)
-    {
-      case 0: // C
-        *x = 6;
-        *y = 54;
-        break;
-      case 1: // Db
-        *x = 15;
-        *y = 29;
-        break;
-      case 2: // D
-        *x = 24;
-        *y = 54;
-        break;
-      case 3: // Eb
-        *x = 33;
-        *y = 29;
-        break;
-      case 4: // E
-        *x = 42;
-        *y = 54;
-        break;
-      case 5: // F
-        *x = 60;
-        *y = 54;
-        break;
-      case 6: // Gb
-        *x = 69;
-        *y = 29;
-        break;
-      case 7: // G
-        *x = 78;
-        *y = 54;
-        break;
-      case 8: // Ab
-        *x = 87;
-        *y = 29;
-        break;
-      case 9: // A
-        *x = 96;
-        *y = 54;
-        break;
-      case 10: // Bb
-        *x = 105;
-        *y = 29;
-        break;
-      case 11: // B
-        *x = 114;
-        *y = 54;
-        break;
-    }
-  }
-
-  void invert_current_selection()
-  {
-    if(main_selected)
-    {
-      int16_t x, y;
-      get_note_indicator_coordinates(note_selected, &x, &y);
-      Display.draw_pixel(x, y, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 2, y, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 4, y, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 6, y, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x, y + 2, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x, y + 4, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x, y + 6, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 2, y + 6, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 4, y + 6, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 6, y + 6, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 6, y + 2, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 6, y + 4, DUINO_SH1106::Inverse);
-      if(y == 29)
-      {
-        Display.display(x, x + 6, 3, 4);
-      }
-      else
-      {
-        Display.display(x, x + 6, 6, 7);
-      }
-    }
-    else
-    {
-      switch(top_selected)
-      {
-        case 0: // trigger mode
-          Display.fill_rect(76, 0, 9, 9, DUINO_SH1106::Inverse);
-          Display.display(76, 84, 0, 1);
-          break;
-        case 1: // key
-          Display.fill_rect(90, 0, 13, 9, DUINO_SH1106::Inverse);
-          Display.display(90, 102, 0, 1);
-          break;
-        case 2: // scale
-          Display.fill_rect(108, 0, 19, 9, DUINO_SH1106::Inverse);
-          Display.display(108, 126, 0, 1);
-          break;
-      }
-    }
+  void draw_left_key(int16_t x, int16_t y)
+  {
+    Display.draw_vline(x, y, 52, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y, 9, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y + 51, 15, DUINO_SH1106::White);
+    Display.draw_vline(x + 10, y, 29, DUINO_SH1106::White);
+    Display.draw_hline(x + 11, y + 28, 5, DUINO_SH1106::White);
+    Display.draw_vline(x + 16, y + 28, 24, DUINO_SH1106::White);
+  }
+
+  void draw_center_key(int16_t x, int16_t y)
+  {
+    Display.draw_vline(x, y + 28, 24, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y + 28, 5, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y + 51, 15, DUINO_SH1106::White);
+    Display.draw_vline(x + 6, y, 29, DUINO_SH1106::White);
+    Display.draw_hline(x + 7, y, 3, DUINO_SH1106::White);
+    Display.draw_vline(x + 10, y, 29, DUINO_SH1106::White);
+    Display.draw_hline(x + 11, y + 28, 5, DUINO_SH1106::White);
+    Display.draw_vline(x + 16, y + 28, 24, DUINO_SH1106::White);
+  }
+
+  void draw_right_key(int16_t x, int16_t y)
+  {
+    Display.draw_vline(x, y + 28, 24, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y + 28, 5, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y + 51, 15, DUINO_SH1106::White);
+    Display.draw_vline(x + 6, y, 29, DUINO_SH1106::White);
+    Display.draw_hline(x + 7, y, 9, DUINO_SH1106::White);
+    Display.draw_vline(x + 16, y, 52, DUINO_SH1106::White);
+  }
+
+  void draw_black_key(int16_t x, int16_t y)
+  {
+    Display.draw_vline(x, y, 27, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y, 9, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y + 26, 9, DUINO_SH1106::White);
+    Display.draw_vline(x + 10, y, 27, DUINO_SH1106::White);
   }

   void display_trigger_mode()
   {
-    bool selected = !main_selected && top_selected == 0;
-    Display.fill_rect(77, 1, 7, 7, selected ? DUINO_SH1106::White : DUINO_SH1106::Black);
-
-    Display.draw_bitmap_7(77, 1, icons, trigger_mode, selected ? DUINO_SH1106::Black : DUINO_SH1106::White);
-
-    Display.display(77, 83, 0, 0);
+    Display.fill_rect(widget_trigger_mode_->x() + 1, widget_trigger_mode_->y() + 1, 7, 7,
+        widget_trigger_mode_->inverted() ? DUINO_SH1106::White : DUINO_SH1106::Black);
+    Display.draw_bitmap_7(widget_trigger_mode_->x() + 1, widget_trigger_mode_->y() + 1, icons, trigger_mode,
+        widget_trigger_mode_->inverted() ? DUINO_SH1106::Black : DUINO_SH1106::White);
+    widget_trigger_mode_->display();
   }

   void display_key()
   {
-    bool selected = !main_selected && top_selected == 1;
-    Display.fill_rect(91, 1, 11, 7, selected ? DUINO_SH1106::White : DUINO_SH1106::Black);
+    Display.fill_rect(widget_key_->x() + 1, widget_key_->y() + 1, 11, 7,
+        widget_key_->inverted() ? DUINO_SH1106::White : DUINO_SH1106::Black);

     bool sharp = false;
     unsigned char letter;
@@ -476,38 +338,40 @@
         break;
     }

-    Display.draw_char(91, 1, letter, selected ? DUINO_SH1106::Black : DUINO_SH1106::White);
+    Display.draw_char(widget_key_->x() + 1, widget_key_->y() + 1, letter,
+        widget_key_->inverted() ? DUINO_SH1106::Black : DUINO_SH1106::White);
     if(sharp)
     {
-      Display.draw_char(97, 1, '#', selected ? DUINO_SH1106::Black : DUINO_SH1106::White);
-    }
-
-    Display.display(91, 101, 0, 0);
+      Display.draw_char(widget_key_->x() + 7, widget_key_->y() + 1, '#',
+          widget_key_->inverted() ? DUINO_SH1106::Black : DUINO_SH1106::White);
+    }
+
+    widget_key_->display();
   }

   void display_scale()
   {
-    bool selected = !main_selected && top_selected == 2;
-    Display.fill_rect(108, 0, 19, 9, selected ? DUINO_SH1106::White : DUINO_SH1106::Black);
+    Display.fill_rect(widget_scale_->x() + 1, widget_scale_->y() + 1, 17, 7,
+        widget_scale_->inverted() ? DUINO_SH1106::White : DUINO_SH1106::Black);
     if(scale_id > -1)
     {
       for(uint8_t i = 0; i < 3; ++i)
       {
-        Display.draw_char(109 + i * 6, 1, pgm_read_byte(&scales[scale_id * 5 + 2 + i]),
-            selected ? DUINO_SH1106::Black : DUINO_SH1106::White);
+        Display.draw_char(widget_scale_->x() + 1 + i * 6, widget_scale_->y() + 1,
+            pgm_read_byte(&scales[scale_id * 5 + 2 + i]),
+            widget_scale_->inverted() ? DUINO_SH1106::Black : DUINO_SH1106::White);
       }
     }

-    int16_t x, y;
     for(uint8_t note = 0; note < 12; ++note)
     {
-      get_note_indicator_coordinates(note, &x, &y);
       bool white = scale & (1 << note);
       if(note == current_displayed_note)
       {
         white = !white;
       }
-      Display.fill_rect(x + 1, y + 1, 5, 5, white ? DUINO_SH1106::White : DUINO_SH1106::Black);
+      Display.fill_rect(widgets_notes_[note]->x() + 1, widgets_notes_[note]->y() + 1, 5, 5,
+          white ? DUINO_SH1106::White : DUINO_SH1106::Black);
     }

     Display.display_all();
@@ -572,6 +436,14 @@

     Display.display(2, 124, 1, refresh_lower ? 7 : 4);
   }
+
+  DUINO_WidgetContainer<2> * container_outer_;
+  DUINO_WidgetContainer<3> * container_top_;
+  DUINO_WidgetContainer<12> * container_notes_;
+  DUINO_DisplayWidget * widget_trigger_mode_;
+  DUINO_DisplayWidget * widget_key_;
+  DUINO_DisplayWidget * widget_scale_;
+  DUINO_DisplayWidget * widgets_notes_[12];

   bool trigger_mode;
   int8_t key;
@@ -579,9 +451,6 @@
   uint16_t scale;
   uint8_t output_note;
   int output_octave;
-  bool main_selected;
-  uint8_t top_selected;  // 0 - trigger mode, 1 - key, 2 - scale
-  int8_t note_selected;
   uint8_t current_displayed_note;
 };

@@ -592,6 +461,11 @@
   triggered = true;
 }

+void trigger_mode_scroll_callback(int delta) { function->widget_trigger_mode_scroll_callback(delta); }
+void key_scroll_callback(int delta) { function->widget_key_scroll_callback(delta); }
+void scale_scroll_callback(int delta) { function->widget_scale_scroll_callback(delta); }
+void notes_click_callback(uint8_t selected) { function->widgets_notes_click_callback(selected); }
+
 void setup()
 {
   function = new DU_Quantizer_Function();


Commit after tests

Commit after tests

--- MID/MID.ino
+++ MID/MID.ino
@@ -149,7 +149,7 @@
     shutDown.cursor();
     //
     // Listen state pins
-    carStat.listener();D
+    carStat.listener();
     //
     // Listen LPG fuel system from serial com
 #ifdef ADT_FUEL_SYSTEM_SERIAL


Make use of the return value of the scan operation

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

--- examples/SodaqOne-TTN-Mapper-binary/SodaqOne-TTN-Mapper-binary.ino
+++ examples/SodaqOne-TTN-Mapper-binary/SodaqOne-TTN-Mapper-binary.ino
@@ -55,12 +55,11 @@
 }
  *
  */
-#include <Arduino.h>
 #include "Sodaq_UBlox_GPS.h"
 #include <rn2xx3.h>

-//create an instance of the rn2xx3 library,
-//giving Serial1 as stream to use for communication with the radio
+// Create an instance of the rn2xx3 library,
+// Giving Serial1 as stream to use for communication with the radio
 rn2xx3 myLora(Serial1);

 String toLog;
@@ -77,7 +76,7 @@
     SerialUSB.begin(57600);
     Serial1.begin(57600);

-    // make sure usb serial connection is available,
+    // Make sure usb serial connection is available,
     // or after 10s go on anyway for 'headless' use of the node.
     while ((!SerialUSB) && (millis() < 10000));

@@ -85,13 +84,13 @@

     initialize_radio();

-    //transmit a startup message
+    // Transmit a startup message
     myLora.tx("TTN Mapper on Sodaq One");

     // Enable next line to enable debug information of the sodaq_gps
     //sodaq_gps.setDiag(SerialUSB);

-    // initialize GPS
+    // Initialize GPS
     sodaq_gps.init(GPS_ENABLE);

     // Set the datarate/spreading factor at which we communicate.
@@ -114,7 +113,7 @@
     Serial1.read();
   }

-  //print out the HWEUI so that we can register it via ttnctl
+  // Print out the HWEUI so that we can register it via ttnctl
   String hweui = myLora.hweui();
   while(hweui.length() != 16)
   {
@@ -127,7 +126,7 @@
   SerialUSB.println("RN2xx3 firmware version:");
   SerialUSB.println(myLora.sysver());

-  //configure your keys and join the network
+  // Configure your keys and join the network
   SerialUSB.println("Trying to join TTN");
   bool join_result = false;

@@ -140,7 +139,7 @@
   while(!join_result)
   {
     SerialUSB.println("Unable to join. Are your keys correct, and do you have TTN coverage?");
-    delay(60000); //delay a minute before retry
+    delay(60000); // Delay a minute before retry
     digitalWrite(LED_BLUE, LOW);
     join_result = myLora.init();
     digitalWrite(LED_BLUE, HIGH);
@@ -154,21 +153,17 @@
 {
   SerialUSB.println("Waiting for GPS fix");

-  digitalWrite(LED_GREEN, LOW);
-  // Keep the GPS enabled after we do a scan, increases accuracy
-  sodaq_gps.scan(true);
+  // Turn off GREEN and turn on RED led to indicate GPS usage
   digitalWrite(LED_GREEN, HIGH);
-
-  // if the latitude is 0, we likely do not have a GPS fix yet, so wait longer
-  while(sodaq_gps.getLat()==0.0)
-  {
-    SerialUSB.println("Latitude still 0.0, doing another scan");
-
-    digitalWrite(LED_RED, LOW);
-    // Keep the GPS enabled after we do a scan, increases accuracy
-    sodaq_gps.scan(true);
-    digitalWrite(LED_RED, HIGH);
-  }
+  digitalWrite(LED_RED, LOW);
+
+  // Scan until we have a succesful GPS fix
+  while(!sodaq_gps.scan(true))
+  {
+    SerialUSB.println("No GPS fix, doing another scan");
+  }
+
+  digitalWrite(LED_RED, HIGH);

   LatitudeBinary = ((sodaq_gps.getLat() + 90) / 180) * 16777215;
   LongitudeBinary = ((sodaq_gps.getLon() + 180) / 360) * 16777215;
@@ -209,6 +204,7 @@
   SerialUSB.print(" hex ");
   SerialUSB.println(toLog);

+  // Turn on blue to indicate Lora usage
   digitalWrite(LED_BLUE, LOW);
   myLora.txBytes(txBuffer, sizeof(txBuffer));
   digitalWrite(LED_BLUE, HIGH);


Interrupts are now used for solenoid timings

checkSolenoids is no longer needed.  Timer 4 interrupts are used to
deactivate the solenoids, which ensures that they are deactivated at the
right time, regardless of what else the program is doing.

--- embedded/Crossfire_Program/Crossfire_Program.ino
+++ embedded/Crossfire_Program/Crossfire_Program.ino
@@ -53,6 +53,7 @@

 //Interface Panel
 #define pinPot A0
+
 #define pinLEDY1 26
 #define pinLEDY2 24
 #define pinLEDY3 22
@@ -73,11 +74,12 @@
 /*******************************************************************************************/
 #define DEBUG 0 //Defining DEBUG turns ON debugging messages

-#define killMsgSend 1 //Prevents the arduino from sending the functional messages to the laptop
+#define killMsgSend 0 //Prevents the arduino from sending the functional messages to the laptop

 #define commsTimeout 200 //The maximum time that a received serial command can take, in mS

 #define ballReleaseTime 35 //The time that the solenoid needs to be activated for to release a ball, in mS
+#define ballReleaseInt floor((ballReleaseTime*125)/8) //The number of 64uS needed to get to ballReleaseTime

 #define angleLowest 30 //The minimum allowable angle
 #define angleHighest 150 //The maximum allowable angle
@@ -114,6 +116,13 @@
 const byte buttonPins[] = {
   0,pinButton1,pinButton2,pinButton3}; //A map for the three momentary buttons

+const byte OCIE4[] = {
+  0, OCIE4A, OCIE4B, OCIE4C}; //A map for the locations of the output compare interrupt enable bit locations
+volatile byte *ptrOCR4H[] = {
+  0, &OCR4AH, &OCR4BH, &OCR4CH}; //Maps for the locations of the high and low output compare value byte locations
+volatile byte *ptrOCR4L[] = {
+  0, &OCR4AL, &OCR4BL, &OCR4CL};
+
 const byte motorLevel[] = {
   0,motorLevel1,motorLevel2,motorLevel3}; //Individual PWM signal levels for each motor
 char offset[] = {
@@ -139,6 +148,7 @@
  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  */
 void setup(){
+
   // Constants
   /*******************************************************************************************/
   commandLength[1]=2;
@@ -149,7 +159,16 @@
   commandLength[0xE0]=1;
   commandLength[0xE1]=1;
   commandLength[0xE2]=2;
-
+
+  // Timer Setup
+  /*******************************************************************************************/
+  //Set timer 4 to Normal mode, clock prescaler of 1024, other parameters
+  TCCR4A = B00000000;
+  TCCR4B = B00000101;
+  interrupts(); //Enable interrupts
+  //NOTE: This must be run BEFORE using delaying commangs.  If this is run after a certain
+  //amount of time, the interrupts don't function correctly.
+
   // Pin Modes and Setup
   /*******************************************************************************************/
   for (byte i=1;i<4;i++){
@@ -183,24 +202,30 @@
   servo2.attach(pinServo2,429,2571);
   servo3.attach(pinServo3,429,2571);

+
   //Run a test pattern on the LEDs
+
+
   float num = 200; //mS
-  for (byte i=0;i<7;i++){
-    for (byte j=1;j<4;j++){
-      digitalWrite(ledPinsY[j],HIGH);
-      delay(round(num));
+  for (byte i=0;i<6;i++){
+    for (byte z=1;z<4;z++){
+      digitalWrite(ledPinsY[z],HIGH);
+      delay(num);
       num=num*0.93;
-      digitalWrite(ledPinsY[j],LOW);
+      digitalWrite(ledPinsY[z],LOW);
     }
-    for (byte j=3;j>0;j--){
-      digitalWrite(ledPins[j],HIGH);
-      delay(round(num));
+    for (byte z=3;z>0;z--){
+      digitalWrite(ledPins[z],HIGH);
+      delay(num);
       num=num*0.93;
-      digitalWrite(ledPins[j],LOW);
+      digitalWrite(ledPins[z],LOW);
     }
   }

-  //Set all servos to 90 degrees
+
+
+
+    //Set all servos to 90 degrees
   servo1.write(90+offset[1]);
   servo2.write(90+offset[2]);
   servo3.write(90+offset[3]);
@@ -210,21 +235,6 @@
   //Send 'Game Start' message to laptop
   sendMessage(0x80);

-
-  //Prototyping stuff DELETE ME!  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  //analogWrite(pinMotor1,0);
-
-  //    releaseBall(1);
-
-  //  while (true) { //Cycle endlessly
-  //    setShooterAngle(1,90);
-  //    delay(1000);
-  //    setShooterAngle(1,45);
-  //    delay(1000);
-  //    setShooterAngle(1,135);
-  //    delay(1000);
-  //  }
-
 }

@@ -237,9 +247,6 @@
  */
 void loop(){
   checkSerial(); //Check for incoming commands, and execute them
-
-  checkSolenoids(); //Deactivates any solenoids when needed
-
 }

@@ -255,7 +262,6 @@
         if (millis()>timer) { //Exit the loop if we don't receive another character
           break;
         }
-        checkSolenoids(); //In case one needs to be turned off while this fn is running
       }
       if (Serial.peek()=='O'){
         Serial.read(); //Remove the 'O' from the serial buffer.
@@ -270,7 +276,6 @@
           if (millis()>timer) { //Exit the loop if we don't receive another character
             break;
           }
-          checkSolenoids(); //In case one needs to be turned off while this fn is running
         }
         commandID=Serial.read(); //This byte is the command ID

@@ -384,31 +389,14 @@
     digitalWrite(solenoidPins[shooterNum],HIGH); //Activate the solenoid: open the passage
     digitalWrite(ledPins[shooterNum],HIGH); //Turn on the respective LED

-    ballReleaseTimer[shooterNum]=millis()+ballReleaseTime; //Set the timer for deactivating the solenoid
-    ballReleasing[shooterNum]=1; //Indicate that we are releasing a ball
-  }
-}
-
-/*▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
-/*checkSolenoids
-/*******************************************************************************************/
-//Check whether there are any solenoids that need to be deactivated
-void checkSolenoids(){
-  for (byte i=1;i<4;i++){ //Check all 3 solenoids
-    if (ballReleasing[i]==1){ //If a ball is currently being released
-      if (millis()>ballReleaseTimer[i]){ //If enough time has passed
-        digitalWrite(solenoidPins[i],LOW); //Deactivate the solenoid: close the passage
-        digitalWrite(ledPins[i],LOW); //Turn off the respective LED
-        ballReleasing[i]=0; //Indicate that the ball is no longer being released
-#if DEBUG==1
-        Serial.print("Deactivating solenoid: ");
-        Serial.println(i);
-#endif
-      }
-    }
-  }
-}
-
+    //With interrupts, set the timed interrupt
+    timedInterrupt(shooterNum, ballReleaseInt); //Should be 547 for 35mS
+
+    //Below is the code before interrupts
+    //ballReleaseTimer[shooterNum]=millis()+ballReleaseTime; //Set the timer for deactivating the solenoid
+    //ballReleasing[shooterNum]=1; //Indicate that we are releasing a ball
+  }
+}

 /*▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
 /*sendMessage
@@ -430,9 +418,59 @@
 #endif
 }

-
-
-
-
-
-
+/*▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
+/*timedInterrupt
+/*******************************************************************************************/
+//timerNum tells whether to use Output Compare A, B or C (for shooters 1, 2 or 3)
+//time tells the amount of time to set it for, in multiples of 62 uS. 547 gives 35mS.
+void timedInterrupt(byte timerNum, unsigned int time){
+
+  //Grab the current count from the timer
+  unsigned int count = TCNT4L; //Read the low byte first;
+  count += TCNT4H*256;
+  //Add the time we wish to find
+  count += time; //Set the the value entered
+
+  //Set the value of count into the output compare registers
+  *ptrOCR4H[timerNum] = count>>8; //High byte first
+  *ptrOCR4L[timerNum] = count; //The low byte
+
+  //Turn on interrupts for output compare on the required timer
+  TIMSK4 |= _BV(OCIE4[timerNum]);
+}
+
+/*▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
+/*Timer Interrupt Service Routines
+/*******************************************************************************************/
+ISR(TIMER4_COMPA_vect){
+  //Turn off the interrupts
+  TIMSK4 &= 255 - _BV(OCIE4A);
+
+  digitalWrite(solenoidPins[1],LOW); //Deactivate the solenoid: close the BB passage
+  digitalWrite(ledPins[1],LOW); //Turn off the respective LED
+#if DEBUG==1
+  Serial.println("Deactivating solenoid: 1");
+#endif
+}
+
+ISR(TIMER4_COMPB_vect){
+  //Turn off the interrupts
+  TIMSK4 &= 255 - _BV(OCIE4B);
+
+  digitalWrite(solenoidPins[2],LOW); //Deactivate the solenoid: close the BB passage
+  digitalWrite(ledPins[2],LOW); //Turn off the respective LED
+#if DEBUG==1
+  Serial.println("Deactivating solenoid: 2");
+#endif
+}
+
+ISR(TIMER4_COMPC_vect){
+  //Turn off the interrupts
+  TIMSK4 &= 255 - _BV(OCIE4C);
+
+  digitalWrite(solenoidPins[3],LOW); //Deactivate the solenoid: close the BB passage
+  digitalWrite(ledPins[3],LOW); //Turn off the respective LED
+#if DEBUG==1
+  Serial.println("Deactivating solenoid: 3");
+#endif
+}


Use interrupt on switch pin

Use interrupt on switch pin

Fix #1

--- wcci/wcci.ino
+++ wcci/wcci.ino
@@ -1,10 +1,12 @@
+#include "Arduino.h"

 #define ESP_RESET 9
-#define GREEN 12
+
 #define RED 10
 #define YELLOW 11
+#define GREEN 12
 #define LED 13
-#define SWITCH 4
+#define SWITCH 3

 #define BLINK_COUNT 1
 #define BLINK_DURATION 500
@@ -13,10 +15,16 @@
 String commandUnlock = "GET /log_visit_state/1 HTTP/1.0\r\n\r\n";

 int count;
-int switchState;
+int lastState;
+int courtesyDelay = 6;
+long lastStateTimestamp;

-void setup()
-{
+
+// sometimes you want to run with leds only
+boolean espActive = false;
+
+void setup() {
+
   pinMode(ESP_RESET, INPUT);
   //pinMode(ESP_RESET, OUTPUT);
   //digitalWrite(ESP_RESET, HIGH);
@@ -24,7 +32,18 @@
   pinMode(GREEN, OUTPUT);
   pinMode(RED, OUTPUT);
   pinMode(YELLOW, OUTPUT);
+
+  // setup the switch
   pinMode(SWITCH, INPUT_PULLUP);
+  lastState = digitalRead(SWITCH);
+  lastStateTimestamp = millis();
+  delay(100);
+  attachInterrupt(digitalPinToInterrupt(SWITCH), onLockStateChange, CHANGE);
+
+  digitalWrite(GREEN, HIGH);
+
+  if (!espActive)
+    return; // bail to loop

   // setup serial with esp-01
   digitalWrite(LED, HIGH);
@@ -52,38 +71,23 @@
   blink(BLINK_COUNT, BLINK_DURATION, 1, 1, 1);
 }

+
+
 void loop() {
-  int state = digitalRead(SWITCH);
-
-  if (switchState != state) {
-    // send state to server
-    if (state == LOW) {
-      sendLock();
-    } else {
-      sendUnlock();
-    }
-  }
-
-  switchState = state;
-
-  if (switchState == LOW) {
+  if (lastState == LOW) {
     count++;
-    digitalWrite(RED, HIGH);
-    digitalWrite(YELLOW, LOW);
-    digitalWrite(GREEN, LOW);
-  } else {
-    if (count > 0) {
-      count -= 6;
+  } else if (count > 0) {
+      count -= courtesyDelay;
       digitalWrite(RED, LOW);
       digitalWrite(YELLOW, HIGH);
       digitalWrite(GREEN, LOW);
-
-    } else {
+  } else {
+      count = 0;
       digitalWrite(RED, LOW);
       digitalWrite(YELLOW, LOW);
       digitalWrite(GREEN, HIGH);
-    }
   }
+
   delay(500);
 }

@@ -101,20 +105,47 @@
   }
 }

+void onLockStateChange() {
+  long now = millis();
+  int state = digitalRead(SWITCH);
+  if (state != lastState && now - lastStateTimestamp > 50) {
+    lastStateTimestamp = millis();
+    lastState = state;
+    if (lastState == LOW) {
+      sendLock();
+    } else {
+      sendUnlock();
+    }
+  }
+}

 bool sendLock() {
-  if (!sendATConnectServer()) return false;
-  if (!sendATPrepareLockDoor()) return false;
-  if (!sendATLockDoor()) return false;
-  if (!sendATCipClose()) return false;
+
+  digitalWrite(RED, HIGH);
+  digitalWrite(YELLOW, LOW);
+  digitalWrite(GREEN, LOW);
+
+  if (espActive) {
+    if (!sendATConnectServer()) return false;
+    if (!sendATPrepareLockDoor()) return false;
+    if (!sendATLockDoor()) return false;
+    if (!sendATCipClose()) return false;
+  }
   return true;
 }

 bool sendUnlock() {
-  if (!sendATConnectServer()) return false;
-  if (!sendATPrepareUnlockDoor()) return false;
-  if (!sendATUnlockDoor()) return false;
-  if (!sendATCipClose()) return false;
+
+  digitalWrite(RED, LOW);
+  digitalWrite(YELLOW, HIGH);
+  digitalWrite(GREEN, LOW);
+
+  if (espActive) {
+    if (!sendATConnectServer()) return false;
+    if (!sendATPrepareUnlockDoor()) return false;
+    if (!sendATUnlockDoor()) return false;
+    if (!sendATCipClose()) return false;
+  }
   return true;
 }


Update normal.ino

Update normal.ino

--- examples/normal/normal.ino
+++ examples/normal/normal.ino
@@ -14,8 +14,8 @@
     - Grove kit shield
     - Potentiometer to A0
     - Led light to D8
-  2. Add 'iot_att' library to your Arduino Environment. [Try this guide](http://arduino.cc/en/Guide/Libraries)
-  3. fill in the missing strings (deviceId, clientId, clientKey, mac) and optionally change/add the sensor & actuator names, ids, descriptions, types
+  2. Add 'allthingstalk_arduino_standard_lib' library to your Arduino Environment. [Try this guide](http://arduino.cc/en/Guide/Libraries)
+  3. Fill in the missing strings (deviceId, clientId, clientKey, mac) and optionally change/add the sensor & actuator names, ids, descriptions, types
      For extra actuators, make certain to extend the callback code at the end of the sketch.
   4. Upload the sketch

@@ -34,7 +34,7 @@
 char httpServer[] = "api.smartliving.io";                  // HTTP API Server host
 char* mqttServer = "broker.smartliving.io";

-byte mac[] = {  0x90, 0xA2, 0xDA, 0x0D, 0xE1, 0x3E }; 	    // Adapt to your Arduino MAC Address
+byte mac[] = {0x90, 0xA2, 0xDA, 0x0D, 0xE1, 0x3E}; 	    // Adapt to your Arduino MAC Address

 char sensorId = '1';										// uniquely identify this asset. Don't use spaces in the id.
 char actuatorId = '2';									// uniquely identify this asset. Don't use spaces in the id.


Fixed Dallas temperature reading bug.

Fixed Dallas temperature reading bug.

Raised the task's priority.

--- aquacontrol32.ino
+++ aquacontrol32.ino
@@ -321,7 +321,7 @@
       "tftTask ",                     /* Name of the task */
       10000,                          /* Stack size in words */
       NULL,                           /* Task input parameter */
-      3,                              /* Priority of the task */
+      5,                              /* Priority of the task */
       NULL,                           /* Task handle. */
       1);                             /* Core where the task should run */
   }


Factor more of button

Factor more of button

--- moros/moros.ino
+++ moros/moros.ino
@@ -33,19 +33,19 @@

   Button(int interrupt_number, void (*interrupt_handler)()) {
     attachInterrupt(interrupt_number, interrupt_handler, RISING);
-  }
+  };
+
+  static inline void handle_button_interrupt(int button) {
+    button_pressed = button;
+  };
 };
 volatile int Button::button_pressed = NONE;

-inline void handle_button_interrupt(int button) {
-  Button::button_pressed = button;
-}
-
 void handle_button_interrupt_0() {
-  handle_button_interrupt(0);
+  Button::handle_button_interrupt(0);
 }
 void handle_button_interrupt_1() {
-  handle_button_interrupt(1);
+  Button::handle_button_interrupt(1);
 }

 class Screen {
@@ -92,6 +92,10 @@
     last_update_ms = 0;
   };

+  void start() {
+    last_update_ms = millis();
+  };
+
   void update() {
     unsigned long time_since_last_update_ms = millis() - last_update_ms;
     if (time_remaining_ms < time_since_last_update_ms) {
@@ -123,6 +127,11 @@
     static char timea[12];
     ltoa(clock->time_remaining_ms/100, timea, 10);
     screen->display_text(timea);
+  };
+
+  void tick() {
+    clock->update();
+    update_display();
   };

@@ -157,6 +166,7 @@

   for(unsigned int i = 0; i < sizeof(players) / sizeof(players[0]); i++) {
     players[i]->init();
+    players[i]->clock->start();
     players[i]->update_display();
   }

@@ -173,8 +183,7 @@
       return;
     }

-    players[active_player]->clock->update();
-    players[active_player]->update_display();
+    players[active_player]->tick();
   }

   if ((active_player == NONE || Button::button_pressed == active_player) && Button::button_pressed != NONE)   {


mornigni 2

mornigni 2

--- Mul_masters/Mul_masters.ino
+++ Mul_masters/Mul_masters.ino
@@ -38,7 +38,7 @@
 void loop() {
  int LEDblock = int(Serial.read());
  if(LEDblock == 0){
-    for(int i =0,i<3;i++){
+    for(int i =0;i<3;i++){
        digitalWrite(gLED,HIGH);
        delay(250);
        digitalWrite(gLED,LOW);
@@ -51,7 +51,7 @@
     }
  }
  else if(LEDblock == -1){
-    for(int i =0,i<3;i++){
+    for(int i =0;i<3;i++){
        digitalWrite(rLED,HIGH);
        delay(250);
        digitalWrite(rLED,LOW);
@@ -65,7 +65,7 @@
     digitalWrite(rLED,LOW);
     digitalWrite(bLED,LOW);
     delay(250);
-    char LED_ADDR = data[LED_block-1][25];
+    char LED_ADDR = data[LEDblock-1][25];
     Wire.beginTransmission(LED_ADDR);
     Wire.write("run");
     Wire.endTransmission();
@@ -102,7 +102,7 @@
  digitalWrite(inLED, LOW);
 }

-void checkFinished(){
+/*void checkFinished(){
  bool allTrue = false;
  if(digitalRead(INPin)==HIGH)
    allTrue = true;
@@ -126,6 +126,6 @@
   /*if(blockCount==0)
       Serial.println("Error end with 0 block");
   else
-      Serial.println("Finished");*/
+      Serial.println("Finished");
  }
-}
+}*/


#9 Attached interrupt and added ISR for setting desired course

--- src/iris/iris.ino
+++ src/iris/iris.ino
@@ -8,45 +8,46 @@
  * It's desired to fire the different tasks with specific intervals.
  * Ex. Fire GPS task with 2000ms intervals and so on...
  */
-#define GPS_TASK_INTERVAL 2000
+#define GPS_TASK_INTERVAL   2000
 #define SERVO_TASK_INTERVAL 50
-#define TFT_TASK_INTERVAL 1000
+#define TFT_TASK_INTERVAL   1000

 // Servo positions (approx analog values)
-#define MAX_POSITION 4040    // Maximum position
+#define MAX_POSITION    4040 // Maximum position
 #define CENTER_POSITION 2020 // Center position
-#define MIN_POSITION 0	     // Minimum position
+#define MIN_POSITION    0    // Minimum position

 // Different A/D resolutions
-#define RESOLUTION_READ 12  // Number of bits we want to use as resolution reading analog input
+#define RESOLUTION_READ  12 // Number of bits we want to use as resolution reading analog input
 #define RESOLUTION_WRITE 12 // Number of bits we want to use as resolution writing analog output

 // Different pins
-#define JOYSTICK_PIN A0
-#define SERVO_PIN DAC0
+#define JOYSTICK_PIN       A0
+#define SERVO_PIN          DAC0
 #define SERVO_FEEDBACK_PIN A1
-#define MODE_SWITCH_PIN 2
-#define TFT_CS 10
-#define TFT_RESET 9
-#define SD_CS 4
-#define SHOW_SPLASH_PIN 5
-#define USE_GPS_PIN 8
-#define ENCODER_PIN_A 11
-#define ENCODER_PIN_B 12
+#define MODE_SWITCH_PIN    2
+#define TFT_CS             10
+#define TFT_RESET          9
+#define SD_CS              4
+#define SHOW_SPLASH_PIN    5
+#define USE_GPS_PIN        8
+#define ENCODER_PIN_A      11
+#define ENCODER_PIN_B      12
+#define SET_COURSE_PIN     3

 // Navigation defines
 #define DEGREE_LIMIT_MAX 360
 #define DEGREE_LIMIT_MIN 1
-#define DEGREE_STEP 0.5
+#define DEGREE_STEP      0.5

 // Different baud rates and serial stuff
-#define BAUD_RATE 115200   // Desired baud rate for serial debug communication
-#define GPS_BAUD_RATE 9600 // Seems to be the standard for Adafruits MTK GPS's, could use 4800 also
-#define GPS_SERIAL Serial1 // DUE has 3 hardware USART so we can use one hardware serial for the GPS
-
-// Colors (RGB565)
+#define BAUD_RATE     115200  // Desired baud rate for serial debug communication
+#define GPS_BAUD_RATE 9600    // Seems to be the standard for Adafruits MTK GPS's, could use 4800 also
+#define GPS_SERIAL    Serial1 // DUE has 3 hardware USART so we can use one hardware serial for the GPS
+
+// Colors in RGB565 format
 #define ARDUINO_BLUE 0x04B3
-#define IRIS_GRAY 0xC618
+#define IRIS_GRAY    0xC618

 // Text stuff
 #define NORMAL_LINE_SPACE 16
@@ -71,6 +72,7 @@
 double Kp = 0.1;
 double Ki = 0.01;
 double Kd = 0.005;
+double sp = 0.0;

 // It's nice to know if SD card has been initialized correctly
 boolean sdInitialized = false;
@@ -105,9 +107,10 @@
   pinMode(SHOW_SPLASH_PIN, INPUT);
   pinMode(USE_GPS_PIN, INPUT);
   Serial.println(F("Pins and directions successfully set..."));
-
+
   Serial.println(F("Attaching interrupts..."));
   // Attaching interrupts
+  attachInterrupt(SET_COURSE_PIN, setDesiredCourse, RISING);
   attachInterrupt(ENCODER_PIN_A, encoderRiseA, RISING);
   attachInterrupt(ENCODER_PIN_B, encoderRiseB, RISING);
   Serial.println(F("Interrupts successfully attached..."));
@@ -210,9 +213,19 @@
 /*************************************************
  *           Interrupt Service Routines          *
  *************************************************/
-
-/*
- * Handles the rise of rotary encoders A signal.
+
+/*
+ * To set the desired course, or more correctly set point(sp),
+ * to current value of encoder.
+ */
+void setDesiredCourse()
+{
+  Serial.print(F("Setting sp to: ")); Serial.println(degreesEncoder);
+  sp = degreesEncoder;
+}
+
+/*
+ * Handles the rise of rotary encoders A signal.
  * Adds or subtract to/from degrees variable in order
  * to keep track of current degree. If neccessary the
  * number of degrees will be adjusted to either 360 or 1.
@@ -234,9 +247,9 @@
   {
     degreesEncoder = degreesEncoder - DEGREE_STEP;
   }
-
+
   // Correct the number of degrees if it's beyond limits
-  if (degreesEncoder > DEGREE_LIMIT_MAX)
+  if (degreesEncoder > DEGREE_LIMIT_MAX)
   {
     degreesEncoder = DEGREE_LIMIT_MIN;
   }
@@ -244,14 +257,14 @@
   {
     degreesEncoder = DEGREE_LIMIT_MAX;
   }
-
+
   Serial.println(degreesEncoder);
   // Remember to attach interrupt with a new ISR
   attachInterrupt(ENCODER_PIN_A, encoderFallA, FALLING);
 }

 /*
- * Handles the fall of rotary encoders A signal.
+ * Handles the fall of rotary encoders A signal.
  * Adds or subtract to/from degrees variable in order
  * to keep track of current degree. If neccessary the
  * number of degrees will be adjusted to either 360 or 1.
@@ -269,8 +282,8 @@
   {
     degreesEncoder = degreesEncoder - DEGREE_STEP;
   }
-
-  if (degreesEncoder > DEGREE_LIMIT_MAX)
+
+  if (degreesEncoder > DEGREE_LIMIT_MAX)
   {
     degreesEncoder = DEGREE_LIMIT_MIN;
   }
@@ -278,13 +291,13 @@
   {
     degreesEncoder = DEGREE_LIMIT_MAX;
   }
-
+
   Serial.println(degreesEncoder);
   attachInterrupt(ENCODER_PIN_A, encoderRiseA, RISING);
 }

 /*
- * Handles the rise of rotary encoders B signal.
+ * Handles the rise of rotary encoders B signal.
  * Adds or subtract to/from degrees variable in order
  * to keep track of current degree. If neccessary the
  * number of degrees will be adjusted to either 360 or 1.
@@ -297,13 +310,13 @@
   if (encoderSignalA == HIGH)
   {
     degreesEncoder = degreesEncoder + DEGREE_STEP;
-  }
+  }
   else if (encoderSignalA == LOW)
   {
     degreesEncoder = degreesEncoder - DEGREE_STEP;
   }
-
-  if (degreesEncoder > DEGREE_LIMIT_MAX)
+
+  if (degreesEncoder > DEGREE_LIMIT_MAX)
   {
     degreesEncoder = DEGREE_LIMIT_MIN;
   }
@@ -311,13 +324,13 @@
   {
     degreesEncoder = DEGREE_LIMIT_MAX;
   }
-
+
   Serial.println(degreesEncoder);
   attachInterrupt(ENCODER_PIN_B, encoderFallB, FALLING);
 }

 /*
- * Handles the fall of rotary encoders B signal.
+ * Handles the fall of rotary encoders B signal.
  * Adds or subtract to/from degrees variable in order
  * to keep track of current degree. If neccessary the
  * number of degrees will be adjusted to either 360 or 1.
@@ -331,13 +344,13 @@
   if (encoderSignalA == LOW)
   {
     degreesEncoder = degreesEncoder + DEGREE_STEP;
-  }
+  }
   else if (encoderSignalA == HIGH)
   {
     degreesEncoder = degreesEncoder - DEGREE_STEP;
   }
-
-  if (degreesEncoder > DEGREE_LIMIT_MAX)
+
+  if (degreesEncoder > DEGREE_LIMIT_MAX)
   {
     degreesEncoder = DEGREE_LIMIT_MIN;
   }
@@ -345,7 +358,7 @@
   {
     degreesEncoder = DEGREE_LIMIT_MAX;
   }
-
+
   Serial.println(degreesEncoder);
   attachInterrupt(ENCODER_PIN_B, encoderRiseB, RISING);
 }
@@ -539,10 +552,10 @@

 /*
  * To figure out if the GPS got enough satellites
- * in order to establish a good position, a
+ * in order to establish a good position, a
  * minimum of 3 satellites are needed for this.
  * True will be returned if GPS got 3 or more satellites
- * else false is returned.
+ * else false is returned.
  * The state of USE_GPS_PIN will also be checked, if it's
  * LOW than false is returned else true is returned, this state
  * can be changed with a DIP switch.
@@ -714,12 +727,12 @@
     // And now we fade it down
     fadeOutTFT(1, 10);
   }
-
+
   Serial.println(F("Disable SPI for SD card reader..."));
   // Ensure that we disable SPI for the SD card reader
   SPI.end(SD_CS);
   SPI.begin();
-
+
   Serial.println(F("Preparing for data rendering, setting background color to black..."));

   // This point the tft should be "black" and empty, in other words prepared for the next step
@@ -743,7 +756,7 @@
   tft.textEnlarge(1);
   tft.textSetCursor(206, 0);
   tft.textWrite("Navigation");
-
+
   tft.textSetCursor(5, tft.height() - NORMAL_LINE_SPACE - 3);
   tft.textEnlarge(0);
   tft.textWrite("Iris - v0.8beta");


[nibeheatpump] arduino nibegw: added STM32 nucleo-F429ZI support (#9933)

Signed-off-by: Tobi <7462e4fb261a80b2397591e4c121147bba8befcd@web.de>

--- bundles/org.openhab.binding.nibeheatpump/contrib/NibeGW/Arduino/NibeGW/NibeGW.ino
+++ bundles/org.openhab.binding.nibeheatpump/contrib/NibeGW/Arduino/NibeGW/NibeGW.ino
@@ -30,6 +30,9 @@
 //#define PRODINO_BOARD
 // Enable if ENC28J60 LAN module is used
 //#define TRANSPORT_ETH_ENC28J60
+// Enable if you use STM32 NUCLEO-F429ZI
+//#define STM32_F429ZI_BOARD
+

 // Enable debug printouts, listen printouts e.g. via netcat (nc -l -u 50000)
 //#define ENABLE_DEBUG
@@ -54,6 +57,11 @@
 #ifdef PRODINO_BOARD
 #define RS485_PORT              Serial1
 #define RS485_DIRECTION_PIN     3
+#elif defined STM32_F429ZI_BOARD
+#include <HardwareSerial.h>
+HardwareSerial Serial1(PG9,PG14);
+#define RS485_PORT              Serial1
+#define RS485_DIRECTION_PIN     PF15
 #else
 #define RS485_PORT              Serial
 #define RS485_DIRECTION_PIN     2
@@ -70,6 +78,10 @@

 #ifdef TRANSPORT_ETH_ENC28J60
 #include <UIPEthernet.h>
+#elif defined STM32_F429ZI_BOARD
+#include <LwIP.h>
+#include <STM32Ethernet.h>
+#include <EthernetUdp.h>
 #else
 #include <SPI.h>
 #include <Ethernet.h>
@@ -81,7 +93,11 @@
 #include "KMPCommon.h"
 #endif

+#ifdef STM32_F429ZI_BOARD
+#include <IWatchdog.h>
+#else
 #include <avr/wdt.h>
+#endif

 #include "NibeGw.h"

@@ -142,12 +158,24 @@
 }
 #endif

+// ######### FUNCTION DEFINITION ######################
+
+void nibeCallbackMsgReceived(const byte* const data, int len);
+int nibeCallbackTokenReceived(eTokenType token, byte* data);
+void sendUdpPacket(const byte * const data, int len);
+void initializeEthernet();
+
+
 // ######### SETUP #######################

 void setup()
 {
   // Start watchdog
+#ifdef STM32_F429ZI_BOARD
+  IWatchdog.begin(2000000); // 2 sec
+#else
   wdt_enable (WDTO_2S);
+#endif

   nibegw.setCallback(nibeCallbackMsgReceived, nibeCallbackTokenReceived);
   nibegw.setAckModbus40Address(ACK_MODBUS40);
@@ -174,7 +202,11 @@

 void loop()
 {
+#ifdef STM32_F429ZI_BOARD
+  IWatchdog.reload();
+#else
   wdt_reset();
+#endif

   long now = millis() / 1000;

@@ -227,6 +259,7 @@
 {
   Ethernet.begin(mac, ip, gw, mask);
   ethernetInitialized = true;
+  udp.begin(TARGET_PORT);
   udp4readCmnds.begin(INCOMING_PORT_READCMDS);
   udp4writeCmnds.begin(INCOMING_PORT_WRITECMDS);
 }


Removed using delay.

Removed using delay.

--- src/main/main.ino
+++ src/main/main.ino
@@ -15,23 +15,40 @@
 const int vehicleNS = 13;

 // Light delay
-int delayTime = 1000; //1sec
+unsigned long delayTime = 1000; //1sec

 // Light delays
-int amberLightDelay = 2000; //2sec
-int greenLightDelay = 5000; //20sec for now 5 sec
-int redLightDelay = 3000; //3 sec
-
-//boolean to control state
-boolean isNSTrafficGreen = false;
-
-int vehicleNSCounter = 0;   // counter for the number of button presses
-int vehicleNSState = 0;        // current state of the button
-int lastVehicleNSState = 0;    // previous state of the button
-
-int vehicleEWCounter = 0;   // counter for the number of button presses
-int vehicleEWState = 0;        // current state of the button
-int lastVehicleEWState = 0;    // previous state of the button
+unsigned long amberLightDelay = 2000; //2sec
+unsigned long minimumGreenLight = 20000; //20 sec
+unsigned long vehicleTime = 5000; //5s
+unsigned long redLightDelay = 3000; //3 sec
+
+int vehicleNSCounter = 0;   // counter for the number of vehicles in NS
+int vehicleNSState = 0;        // current state of the vehicleNS button
+int lastVehicleNSState = 0;    // previous state of the vehicleNS button
+
+int vehicleEWCounter = 0;   // counter for the number of vehicleNS in EW
+int vehicleEWState = 0;        // current state of the vehicleNS button
+int lastVehicleEWState = 0;    // previous state of the vehicleNS button
+
+// time since processing started
+unsigned long timeSinceStart;
+unsigned long previousTimeSinceStart;
+// time to track the greenSignal
+unsigned long timeWhenGreenSignal = 0;
+
+unsigned long previousVehicleTime = 0;
+
+enum trafficStates {
+  NS_GREEN, // North South green
+  NS_AMBER, // North South amber
+  NS_RED, // North South red
+  EW_GREEN, // East West green
+  EW_AMBER, // East West amber
+  EW_RED // East West red
+};
+
+enum trafficStates traffic = NS_GREEN;

 //FUNCTIONS

@@ -59,24 +76,39 @@
   lastVehicleEWState = vehicleEWState;
 }

-//our second task, fires every few seconds and rotates signals
-void changeSignal() {
-  //check current state. check if theres any vehicle in other side if so rotate signal
-  if (isNSTrafficGreen && vehicleEWCounter > 0) {
-    changeEWTrafficToGreen();
-  } else if (!isNSTrafficGreen && vehicleNSCounter > 0) {
-    changeNSTrafficToGreen();
-  } else {
-    //do nothing
-  }
-}
-
-//create a couple timers that will fire repeatedly every x ms
-TimedAction vehiclesNSThread = TimedAction(300, countNSVehicles);
-TimedAction vehiclesEWThread = TimedAction(300, countEWVehicles);
-TimedAction signalThread = TimedAction(5000, changeSignal); //minimum cycle green is 20s we use 5 for now
-TimedAction vehicleRemovalThread = TimedAction(1000, passVehicles); //minimum 1 second for a vehicle to pass
-
+/**
+   Passes vehicles
+*/
+void passVehicles() {
+  //pass vehicles only after minimum vehicle time
+  if (timeSinceStart - previousVehicleTime > vehicleTime) {
+    //Pass any blocked vehicles in NS traffic
+    if (traffic == NS_GREEN) {
+      //when NS traffic cycle change traffic to north south
+      if (vehicleNSCounter > 0 && (timeSinceStart - timeWhenGreenSignal > vehicleTime)) {
+        vehicleNSCounter = vehicleNSCounter - 1;
+        Serial.print("Vehicle NORTH-SOUTH passing. Total vehicles remainning: ");
+        Serial.println(vehicleNSCounter);
+        previousVehicleTime = timeSinceStart;
+      }
+    }
+
+    if (traffic == EW_GREEN) {
+      //when NS traffic cycle change traffic to north south
+      if (vehicleEWCounter > 0 && (timeSinceStart - timeWhenGreenSignal > vehicleTime)) {
+        vehicleEWCounter = vehicleEWCounter - 1;
+        Serial.print("Vehicle EAST-WEST passing. Total vehicles remainning: ");
+        Serial.println(vehicleEWCounter);
+        previousVehicleTime = timeSinceStart;
+      }
+    }
+  }
+}
+
+//creates a couple timers that will fire repeatedly every x ms
+TimedAction vehiclesNSThread = TimedAction(50, countNSVehicles); // checks for NS vehicle every 50 sec and count the total vehicle
+TimedAction vehiclesEWThread = TimedAction(50, countEWVehicles); // checks for ES vehicle every 50 sec and count the total vehicle
+TimedAction vehicleRemovalThread = TimedAction(1000, passVehicles); //a vehicle take minimum 5 to pass

 // where's our third task? well, it's the loop itself :) the task
@@ -102,12 +134,39 @@

 void loop() {
   // put your main code here, to run repeatedly:
+  timeSinceStart = millis();
+
+  switch (traffic) {
+    case NS_GREEN:
+      if (vehicleEWCounter > 0) {
+        changeEWGreenToAmber();
+      }
+      break;
+    case EW_GREEN:
+      if (vehicleNSCounter > 0) {
+        changeNSGreenToAmber();
+      }
+      break;
+    case NS_AMBER:
+      changeNSAmberToRed();
+      break;
+    case NS_RED:
+      changeNSRedToEWGreen();
+      break;
+    case EW_AMBER:
+      changeEWAmberToRed();
+      break;
+    case EW_RED:
+      changeEWRedToNSGreen();
+      break;
+    default:
+      break;
+  }

   //check on our threads. based on how long the system has been
   //running, do they need to fire and do work? if so, do it!
   vehiclesNSThread.check();
   vehiclesEWThread.check();
-  signalThread.check();
   vehicleRemovalThread.check();

   vehicleEWState = digitalRead(vehicleEW);
@@ -117,62 +176,84 @@
 void setInitialTrafficCondition() {
   //initial stage
   //NS green on, red and amber off
-  if (!isNSTrafficGreen) {
-    digitalWrite(trafficNSLights[0], HIGH);
-    digitalWrite(trafficEWLights[2], HIGH);
-    delay(greenLightDelay);
-    isNSTrafficGreen = true;
-  }
-}
-
-/**
-   Passes vehicles
-*/
-void passVehicles() {
-  //Pass any blocked vehicles in NS traffic
-  if (isNSTrafficGreen) {
-    //when NS traffic cycle change traffic to north south
-    if (vehicleNSCounter > 0) {
-      Serial.print("Total NORTH-SOUTH vehicles. ");
-      Serial.println(vehicleNSCounter);
-      vehicleNSCounter = vehicleNSCounter - 1;
-      Serial.print("Vehicle NORTH-SOUTH passing. Total Number remainning");
-      Serial.println(vehicleNSCounter);
-    }
+  if (traffic == NS_GREEN) {
+    setEWTrafficLights(LOW, LOW, HIGH);
+    setNSTrafficLights(HIGH, LOW, LOW);
+  }
+}
+
+void changeEWGreenToAmber() {
+  if (timeSinceStart - previousTimeSinceStart > minimumGreenLight) {
+    Serial.println("Vehicle EAST-WEST direction. Changing signal EAST-WEST to green");
+
+    //change NS to amber
+    setNSTrafficLights(LOW, HIGH, LOW);
+
+    traffic = NS_AMBER;
+    previousTimeSinceStart = timeSinceStart;
+  }
+  else {
+    //if waiting for green light
+    Serial.print("Time left for changing EAST WEST to green in : ");
+    Serial.print((long(minimumGreenLight) - (timeSinceStart - previousTimeSinceStart)) / long(1000));
+    Serial.println("s");
+  }
+}
+
+void changeNSGreenToAmber() {
+  if (timeSinceStart - previousTimeSinceStart > minimumGreenLight) {
+    Serial.println("Vehicle NORTH-SOUTH direction. Changing signal NORTH-SOUTH to green");
+
+    //change EW to amber
+    setEWTrafficLights(LOW, HIGH, LOW);
+    traffic = EW_AMBER;
+    previousTimeSinceStart = timeSinceStart;
   } else {
-    //when NS traffic cycle change traffic to north south
-    if (vehicleEWCounter > 0) {
-      Serial.print("Total EAST-WEST vehicles. ");
-      Serial.println(vehicleEWCounter);
-      vehicleEWCounter = vehicleEWCounter - 1;
-      Serial.print("Vehicle EAST-WEST passing. Total Number remainning");
-      Serial.println(vehicleEWCounter);
-    }
-  }
-}
-
-void changeEWTrafficToGreen() {
-  Serial.println("Vechile EAST-WEST direction. Changing signal EAST-WEST to green");
-  //Change NS to red
-  setNSTrafficLights(LOW, HIGH, LOW);
-  delay(amberLightDelay);
-  setNSTrafficLights(LOW, LOW, HIGH);
-  //Change EW to green
-  delay(redLightDelay);
-  setEWTrafficLights(HIGH, LOW, LOW);
-  isNSTrafficGreen = false;
-}
-
-void changeNSTrafficToGreen() {
-  Serial.println("Vechile NORTH-SOUTH direction. Changing signal NORTH-SOUTH to green");
-  //Change EW to red
-  setEWTrafficLights(LOW, HIGH, LOW);
-  delay(amberLightDelay);
-  setEWTrafficLights(LOW, LOW, HIGH);
-  //Change NS to green
-  delay(redLightDelay);
-  setNSTrafficLights(HIGH, LOW, LOW);
-  isNSTrafficGreen = true;
+    //if waiting for green light
+    Serial.print("Time left for changing NORTH SOUTH to green in : ");
+    Serial.print((long(minimumGreenLight) - (timeSinceStart - previousTimeSinceStart)) / long(1000));
+    Serial.println("s");
+  }
+}
+
+void changeNSAmberToRed() {
+  if (timeSinceStart - previousTimeSinceStart > amberLightDelay) {
+    //Set NS to red
+    setNSTrafficLights(LOW, LOW, HIGH);
+    traffic = NS_RED;
+    previousTimeSinceStart = timeSinceStart;
+  }
+}
+
+void changeNSRedToEWGreen() {
+  if (timeSinceStart - previousTimeSinceStart > redLightDelay) {
+    //Set EW to green
+    setEWTrafficLights(HIGH, LOW, LOW);
+    timeWhenGreenSignal = timeSinceStart;
+    Serial.println("EAST-WEST direction signal green");
+    traffic = EW_GREEN;
+    previousTimeSinceStart = timeSinceStart;
+  }
+}
+
+void changeEWAmberToRed() {
+  if (timeSinceStart - previousTimeSinceStart > amberLightDelay) {
+    //Set EW to red
+    setEWTrafficLights(LOW, LOW, HIGH);
+    traffic = EW_RED;
+    previousTimeSinceStart = timeSinceStart;
+  }
+}
+
+void changeEWRedToNSGreen() {
+  if (timeSinceStart - previousTimeSinceStart > redLightDelay) {
+    //Set NS to green
+    setNSTrafficLights(HIGH, LOW, LOW);
+    timeWhenGreenSignal = timeSinceStart;
+    Serial.println("NORTH-SOUTH direction signal green");
+    traffic = NS_GREEN;
+    previousTimeSinceStart = timeSinceStart;
+  }
 }

 void setNSTrafficLights(uint8_t  greenValue, uint8_t amberValue, uint8_t redValue) {


Finished message segmentation (not tested yet until merged into arduino) (+1 squashed commit) Squashed commits: [80f3fef] partial work on segmentation

--- Alarm_Tone/Alarm_Tone.ino
+++ Alarm_Tone/Alarm_Tone.ino
@@ -28,6 +28,7 @@
 #include <EEPROM.h>

 //General-use global variables
+enum iface {USB, BT};
 enum mode {sensor, alarm};
 unsigned long time = millis();
 const unsigned int eepromModeAddress = 0;
@@ -135,39 +136,46 @@
   }

   if (Serial.available()) { //DO NOT allow mode reconfiguration via bluetooth. Security hazard.
-
-    if (opMode == alarm) { //What if the Serial command was triggered to reconfigure? (CHECK WITH EUGEN THAT POWER AND USB COMBINED WON'T FRY THE BOARD!)
-      char input = Serial.read();
-
-      if (input == '5') {
-        reconfiguration(); //Start reconfiguration code
-      }
-
-      else if (input == '2') { //a heartbeat came in, respond
-        int heartResult = heartbeat(true);
-        if (heartResult == 4 || heartResult / 10 == 4) {
-          speaker(heartDeath, sizeof(heartDeath));
-        }
-      }
-      else if (input == '1') { //alarm has been rung
-        speaker(alarmTone, sizeof(alarmTone));
-      }
-
-    }
-    else if (opMode == sensor) {
-      char input = Serial.read();
-
-      if (input == '5') { //order of these conditions is important so compiler checks available first!
-        reconfiguration(); //Start reconfiguration code
-      }
-      else if (input == '2') { //a heartbeat came in, respond
-        heartbeat(true);
-      }
-
-    }
-    else {
-      //OPMODE BROKE! WARN!
-      blinkRate = 0;
+    char cleanout = ' ';
+
+    //Cleans out any garbage left in the Serial port
+    while (cleanout != '|' && Serial.available()) {
+      cleanout = Serial.read();
+    }
+
+    //if the beginning of a command is found (takes care of "|\0" and "||" possible cases)
+    if (cleanout == '|' && Serial.available() && Serial.peek() != '|') {
+      if (opMode == alarm) { //What if the Serial command was triggered to reconfigure? (CHECK WITH EUGEN THAT POWER AND USB COMBINED WON'T FRY THE BOARD!)
+        char input = Serial.read();
+
+        if (input == '2') { //a heartbeat came in, respond
+          int heartResult = heartbeat(true);
+          if (heartResult == 4 || heartResult / 10 == 4) {
+            speaker(heartDeath, sizeof(heartDeath));
+          }
+        }
+        else if (input == '5') {
+          reconfiguration(); //Start reconfiguration code
+        }
+        else if (input == '1') { //alarm has been rung
+          speaker(alarmTone, sizeof(alarmTone));
+        }
+      }
+      else if (opMode == sensor) {
+        char input = Serial.read();
+
+        if (input == '5') { //order of these conditions is important so compiler checks available first!
+          reconfiguration(); //Start reconfiguration code
+        }
+        else if (input == '2') { //a heartbeat came in, respond
+          heartbeat(true);
+        }
+
+      }
+      else {
+        //OPMODE BROKE! WARN!
+        blinkRate = 0;
+      }
     }
   }

@@ -195,14 +203,14 @@

       //and it's been around for a while without getting turned off, activate
       if (millis() - timeNoticed >= delayTillAlarm && activated == false) {
-        bluetooth.write('1');
+        bluetooth.print("|1|");
         activated = true;
         lastSignal = millis();
       }

       //if the alarm has already been activated, wait for the first alarm to play so you don't flood the alarm beacon
       if (activated && millis() - lastSignal >= 1200) {
-        bluetooth.write('1');
+        bluetooth.print("|1|");
         lastSignal = millis();
       }

@@ -226,7 +234,7 @@

 //Return codes: 0=response ok, 1=waiting for a response, 2=heartbeat sent, 3=incorrect response, 4=lost communications
 //42=lost communications, sent a new one, 41=lost comms, waiting for a response to new heartbeat, 43=lost communications, incorrect response
-//The sensor only returns 2
+//The sensor only returns 2 and 3
 int heartbeat(bool sent) {
   static unsigned long timeSent = millis();
   static unsigned int checkValue = 0;
@@ -237,7 +245,7 @@
   if (!signalSent && opMode == alarm && millis() - timeSent >= heartbeatTimeout) {
     checkValue = random(0, 53);
     timeSent = millis();
-    Serial.print(200 + checkValue);
+    Serial.print("|" + String(200 + checkValue) + "|");
     signalSent = true;
     if (lostComms) {
       return 42;
@@ -255,6 +263,16 @@
     int checkReturned = atoi((const char *) &num) * 10;
     num = Serial.read();
     checkReturned += atoi((const char *) &num);
+
+    if (Serial.read() != '|') {
+      Serial.println ("!Checksum malformed.");
+      if (lostComms) {
+        return 43;
+      }
+      else {
+        return 3;
+      }
+    }

     if (opMode == alarm) {

@@ -262,12 +280,12 @@
       if (checkValue + 1 == checkReturned) {
         signalSent = false;
         lostComms = false;
-        Serial.println("Validated successfully");
+        Serial.println("!Validated successfully.");
         return 0;
       }
       else {
         //signalSent = false; //don't kill the signalSent, the real one may be on the way
-        Serial.println ("No validation");
+        Serial.println ("!No validation.");

         if (lostComms) {
           return 43;
@@ -281,7 +299,7 @@
     }
     else if (opMode == sensor) {
       //increment the return value by one, and send back
-      bluetooth.print(200 + checkReturned + 1);
+      bluetooth.print("|" + String(200 + checkReturned + 1) + "|");
       return 2;
     }

@@ -291,14 +309,14 @@
   if (millis() - timeSent >= heartbeatTimeout && opMode == alarm) {
     signalSent = false;
     lostComms = true;
-    Serial.println ("Lost communications");
+    Serial.println ("!Lost communications");
     return 4;
   }

 }

 bool reconfiguration() {
-  Serial.println ("Starting reconfiguration...");
+  Serial.println ("!Starting reconfiguration...");
   bool retVal = false;
   unsigned int counter = 0;

@@ -317,7 +335,7 @@
         EEPROM.write(eepromModeAddress, 0);
       }
       retVal = true;
-      Serial.println("Now a sensor. Reconfiguration successful.");
+      Serial.println("!Now a sensor. Reconfiguration successful.");
     }
     else if (input == '1' && counter == 1) {
       opMode = alarm;
@@ -326,16 +344,16 @@
         EEPROM.write(eepromModeAddress, 1);
       }
       retVal = true;
-      Serial.println("Now an alarm. Reconfiguration successful.");
+      Serial.println("!Now an alarm. Reconfiguration successful.");
     }
     else if (input == '2' && counter == 1) {

       if (opMode == sensor) {
-        Serial.println("I'm a sensor.");
+        Serial.println("!I'm a sensor.");
         retVal = true;
       }
       else if (opMode == alarm) {
-        Serial.println ("I'm an alarm.");
+        Serial.println ("!I'm an alarm.");
         retVal = true;
       }

@@ -349,8 +367,15 @@
   }

   if (retVal == false) {
-    Serial.println("Reconfiguration failure.");
-  }
+    Serial.println("!Reconfiguration failure.");
+  }
+
+  //Strip out any remaining stuff in the message
+  char clean = ' ';
+  while (clean != '|' && Serial.available()) {
+    clean = Serial.read();
+  }
+
   return retVal;
 }


publish data every 5 sec

publish data every 5 sec

--- house-plant.ino
+++ house-plant.ino
@@ -48,5 +48,5 @@
  	Serial.println(response.status); //For debug only
  	Serial.println(response.body);
  }
- delay(100);
-}+ delay(5000);
+}


Update mpxv6115v.ino

Update mpxv6115v.ino

--- example/mpxv6115v.ino
+++ example/mpxv6115v.ino
@@ -3,27 +3,23 @@
 #include "Arduino.h"
 #include "EEPROM.h"
 #include "MAX7219.h"
-
+//************************************************NESNE ATAMALARI***********************************************************
 LedControl lc=LedControl(12,11,10,4);				//MAX7219 segment pin ve nesne atamaları
 DRV8833 driver=DRV8833();					//DRV8833 sınıfı bir nesne olarak tanımlandırıldı
 MPXV6115V mpxv6115v(A0);					//MPXV6115V nesne ataması yapıldı

-
+//************************************************PİN ATAMALARI*************************************************************

 const int vacuum=A0;						//vakum analog pin
 const int temp=A1;						//temperature analog pin
 const int batt=A2;						//battery analog pin
 const int up=2;							//setting değerini yukarı arttırmak için
 const int down=3;						//setting değerini aşağı azaltmak için
-
+//*************************************************DEĞİŞKENLER**************************************************************
 float vakum;
 int setting=250;
 int tolerance=25;
-
-
 float temp_voltage,degreeC,degreeF;				//Isı değişkenlerinin tanımlanması
-
-
 const unsigned long delaytime=250;


Fixed delay value

Fixed delay value

--- BuzzSimple/BuzzSimple.ino
+++ BuzzSimple/BuzzSimple.ino
@@ -1,14 +1,14 @@
 #define BUZZER 6
-#define PAUSE 2
+#define PAUSE 1000

 void setup() {
   pinMode(BUZZER, OUTPUT);
 }

 void loop() {
-  digitalWrite(BUZZER, HIGH);   // turn the LED on (HIGH is the voltage level)
+  digitalWrite(BUZZER, HIGH);   // turn the BUZZER on (HIGH is the voltage level)
   delay(PAUSE);              // wait for a second
-  digitalWrite(BUZZER, LOW);    // turn the LED off by making the voltage LOW
+  digitalWrite(BUZZER, LOW);    // turn the BUZZER off by making the voltage LOW
   delay(PAUSE);              // wait for a second
 }


Added state machine to handle starting up and shutting down more gracefully/safely.

--- firmware/firmware.ino
+++ firmware/firmware.ino
@@ -32,6 +32,22 @@

 const size_t OUTPUT_BUFFER_SIZE = 576;
 char output_buffer[OUTPUT_BUFFER_SIZE+3];
+
+// System state enumeration
+enum SystemState
+{
+  /** There is no ADK USB device currently plugged in. */
+  DISCONNECTED,
+  /** There is an ADK USB device detected, but it is unresponsive. */
+  CONNECTED,
+  /** There is a Platypus Server currently communicating. */
+  RUNNING
+};
+SystemState system_state = DISCONNECTED;
+
+// Number of empty reads before we consider the Android
+// server to be unresponsive.
+const size_t RESPONSE_TIMEOUT = 255;

 // Define the systems on this board
 // TODO: move this board.h?
@@ -268,6 +284,9 @@
   // Initialize debugging serial console.
   Serial.begin(115200);

+  // Start the system in the disconnected state
+  system_state = DISCONNECTED;
+
   // Make the ADK buffers into null terminated string.
   debug_buffer[INPUT_BUFFER_SIZE] = '\0';
   input_buffer[INPUT_BUFFER_SIZE] = '\0';
@@ -295,48 +314,57 @@

 void loop()
 {
+  // Keep track of how many reads we haven't made so far.
+  size_t response_counter;
+
   // Number of bytes received from USB.
   uint32_t bytes_read = 0;

   // Do USB bookkeeping.
   Usb.Task();

-  // Shutdown system if not connected to USB.
+  // Report system as shutdown if not connected to USB.
   if (!adk.isReady())
   {
-    // Set LED to red when USB is not connected.
-    rgb_led.R(1);
-    rgb_led.G(0);
-
-    // Turn off motors.
-    for (size_t motor_idx = 0; motor_idx < NUM_MOTORS; ++motor_idx) {
-      motor[motor_idx]->disable();
-    }
+    // If not connected to USB, we are 'DISCONNECTED'.
+    system_state = DISCONNECTED;

     // Wait for USB connection again.
     yield();
     return;
-  }
-
-  // Rearm motors if necessary
-  for (size_t motor_idx = 0; motor_idx < NUM_MOTORS; ++motor_idx) {
-    if (!motor[motor_idx]->enabled()) {
-      Serial.print("Arming motor ");
-      Serial.println(motor_idx);
-      motor[motor_idx]->arm();
-    }
-  }
-
-  // Set LED to green when USB is connected.
-  rgb_led.R(0);
-  rgb_led.G(1);
-
-  // Read next command from USB.
+  }
+  else
+  {
+    // If connected to USB, we are now 'CONNECTED'!
+    if (system_state == DISCONNECTED)
+    {
+      system_state = CONNECTED;
+    }
+  }
+
+  // Attempt to read command from USB.
   adk.read(&bytes_read, INPUT_BUFFER_SIZE, (uint8_t*)input_buffer);
   if (bytes_read <= 0)
   {
+    // If we haven't received a response in a long time, maybe
+    // we are 'CONNECTED' but the server is not running.
+    ++response_counter;
+    if (response_counter > RESPONSE_TIMEOUT)
+    {
+      system_state = CONNECTED;
+    }
+
+    // Wait for more USB data again.
     yield();
     return;
+  }
+  else
+  {
+    // If we received a command, the server must be 'RUNNING'.
+    if (system_state == CONNECTED)
+    {
+      system_state = RUNNING;
+    }
   }

   // Properly null-terminate the buffer.
@@ -355,51 +383,82 @@
  */
 void motorUpdateLoop()
 {
-  // Only run while connected via USB.
-  if (!adk.isReady()) {
-    yield();
-    return;
-  }
-
   // Wait for a fixed time period.
   delay(100);

-  // Decay all motors exponentially towards zero speed.
-  //for (size_t motor_idx = 0; motor_idx < NUM_MOTORS; ++motor_idx) {
-  //  motor[motor_idx]->velocity(motor[motor_idx]->velocity() * 0.8);
-  //}
-
-  // TODO: move this to another location (e.g. Motor)
-  // Send motor status update over USB
-  snprintf(output_buffer, OUTPUT_BUFFER_SIZE,
-    "{"
-      "\"m0\":{"
-        "\"v\":%f,"
-        "\"c\":%f"
-      "},"
-      "\"m1\":{"
-        "\"v\":%f,"
-        "\"c\":%f"
-      "}"
-    "}",
-    motor[0]->velocity(), motor[0]->current(),
-    motor[1]->velocity(), motor[1]->current()
-  );
-  send(output_buffer);
-
-  // TODO: Remove this hack
-  // Send encoder status update over USB
-  long pos = ((platypus::Winch*)sensor[2])->position();
-  snprintf(output_buffer, OUTPUT_BUFFER_SIZE,
-    "{"
-      "\"s2\":{"
-        "\"type\":\"winch\","
-        "\"depth\":%ld"
-      "}"
-    "}",
-    pos
-  );
-  send(output_buffer);
+  // Handle the motors appropriately for each system state.
+  switch (system_state)
+  {
+    case DISCONNECTED:
+      // Turn off motors.
+      for (size_t motor_idx = 0; motor_idx < NUM_MOTORS; ++motor_idx)
+      {
+        if (motor[motor_idx]->enabled())
+        {
+          Serial.print("Disabling motor [");
+          Serial.print(motor_idx);
+          Serial.println("]");
+          motor[motor_idx]->disable();
+        }
+      }
+      break;
+    case CONNECTED:
+      // Decay all motors exponentially towards zero speed.
+      for (size_t motor_idx = 0; motor_idx < NUM_MOTORS; ++motor_idx)
+      {
+        motor[motor_idx]->velocity(motor[motor_idx]->velocity() * 0.8);
+      }
+      // NOTE: WE DO NOT BREAK OUT OF SWITCH HERE!
+    case RUNNING:
+      // Rearm motors if necessary.
+      for (size_t motor_idx = 0; motor_idx < NUM_MOTORS; ++motor_idx)
+      {
+        if (!motor[motor_idx]->enabled())
+        {
+          Serial.print("Arming motor [");
+          Serial.print(motor_idx);
+          Serial.println("]");
+          motor[motor_idx]->arm();
+        }
+      }
+      break;
+  }
+
+  // Send system status updates while connected to server.
+  if (system_state == RUNNING)
+  {
+    // TODO: move this to another location (e.g. Motor)
+    // Send motor status update over USB
+    snprintf(output_buffer, OUTPUT_BUFFER_SIZE,
+      "{"
+        "\"m0\":{"
+          "\"v\":%f,"
+          "\"c\":%f"
+        "},"
+        "\"m1\":{"
+          "\"v\":%f,"
+          "\"c\":%f"
+        "}"
+      "}",
+      motor[0]->velocity(), motor[0]->current(),
+      motor[1]->velocity(), motor[1]->current()
+    );
+    send(output_buffer);
+
+    // TODO: Remove this hack
+    // Send encoder status update over USB
+    long pos = ((platypus::Winch*)sensor[2])->position();
+    snprintf(output_buffer, OUTPUT_BUFFER_SIZE,
+      "{"
+        "\"s2\":{"
+          "\"type\":\"winch\","
+          "\"depth\":%ld"
+        "}"
+      "}",
+      pos
+    );
+    send(output_buffer);
+  }
 }

 /**


buttons 9 to 16 soldered

buttons 9 to 16 soldered


preprocessor stuff in settings file.

preprocessor stuff in settings file.

--- OpenStage/c_userSettings.ino
+++ OpenStage/c_userSettings.ino
@@ -1,12 +1,6 @@

 //------------------------------------------------------------------------------------------------
 // Some global definitions that need to be modified by the user for the stage to work
-
-
-
-
-// Define pins for LCD display (http://learn.adafruit.com/character-lcds/wiring-a-character-lcd)
-LiquidCrystal lcd(7, 6, 5, 4, 3, 2 );

 //------------------------------------------------------------------------------------------------
@@ -150,6 +144,11 @@
 // PC3: 34 (a good idea to reserve this for a 4th axis, such as a PIFOC)
 byte stageLEDs[4]={37,36,35,35};

+
+// Define pins for LCD display (http://learn.adafruit.com/character-lcds/wiring-a-character-lcd)
+#if doLCD
+   LiquidCrystal lcd(7, 6, 5, 4, 3, 2 );
+#endif


Lets test on a shared server

Lets test on a shared server

--- Firmware/doornfc-wifi.ino
+++ Firmware/doornfc-wifi.ino
@@ -18,7 +18,7 @@
 #define DEBUG_MODE

-const char* AuthServer = "192.168.1.101";
+const char* AuthServer = "http://manchmakerspace.herokuapp.com";
 IPAddress dns(8, 8, 8, 8);
 const bool ImmaDoor = 1;
 const bool ImmaMachine = 0;


Bug fixes/MASSIVE PROBLEM

Bug fixes/MASSIVE PROBLEM

Fixed a few things (see changelog), but the CODE IS TOO BIG ALREADY!
We’ll need to discuss this at the meeting tonight…

--- FlightCode/FlightCode.ino
+++ FlightCode/FlightCode.ino
@@ -1,12 +1,10 @@
 /*
- * Notre Dame Rocket Team Roll Control Payload Master Code V. 0.8.2
+ * Notre Dame Rocket Team Roll Control Payload Master Code V. 0.8.3
  * Aidan McDonald, 2/1/17
  *
  * Most recent changes:
- * Moved GPS enabling to post-burnout
- * Reconfigured transmitter code to send different sensor data at different points in the flight
- * Configured packet transmission to create a standard data set and interpretive flags for the receiver code to use
- * Modified the gpsDataFlag to be a generic flag set if data is saved, until the GPS is enabled, in which case it reverts to its old role.
+ * Fixed some errors with variable names
+ * Reconfigured the Adafruit sensor variable types
  *
  * To-dones:
   * Basic switch-case structure
@@ -19,11 +17,14 @@
   * Github Sync system working
  *
  * To-dos:
+ *  THE CODE IS ALREADY TOO BIG!!!!!
+      *  This is a pretty serious problem, considering there is still a significant amount of code that needs to be written. Part of the problem is that the
+      *  Adafruit flight controller uses four different libraries, each of which eats up memory space. Maybe replace our flight sensor package? Otherwise,
+      *  we're going to need to severely ramp down the scale of our operations...
   * Figure out what the ground station will be transmitting and configure the receiver accordingly
   * Figure out what data the payload transmits pre-burnout
   * Revise and enhance the staging/thresholds, particularly burnout/apogee accel values
   * Reconfigure the SD datalogging section to allow for easy spreadsheet conversion
-  * Figure out what data format/size the Adafruit sensors use, and fix the code accordingly
   * TEST EVERYTHING
   * NO REALLY, EVERYTHING
    *  Ada Sensors
@@ -66,14 +67,14 @@
 //Constants for SD Card communication
 const int cardSelectPin = 53; //Standard for ATMega; other SPI comms pins are 50-52
 File dataLog; //File to log flight data
-byte accelData[3];
-byte gyroData[3];
-byte baroData[3]; //Char buffers for storing sensor data
+int accelData[3];
+int gyroData[3];
+float baroData[3]; //Char buffers for storing sensor data
 unsigned long timeData[2];

-byte accelZBuffer[5] = {0,0,0,0,0};
-byte baroAltBuffer[5] = {0,0,0,0,0};
-byte gyroZBuffer[7] = {0,0,0,0,0,0,0}; //The other values are arbitrary; this one is used in Simpsons Rule, so it MUST BE ODD!
+int accelZBuffer[5] = {0,0,0,0,0};
+float baroAltBuffer[5] = {0,0,0,0,0};
+int gyroZBuffer[7] = {0,0,0,0,0,0,0}; //The other values are arbitrary; this one is used in Simpsons Rule, so it MUST BE ODD!
 unsigned long timeBuffer[7] = {0,0,0,0,0,0,0}; //Must equal the size of gyroZBuffer; used for the same calculations.

 byte accelAverage;
@@ -249,7 +250,7 @@

   if(!startRollFlag) { //For roll initialization, cant fins in the direction of current roll
     digitalWrite(homePin, LOW);
-    servoHomePin = false;
+    servoHomeFlag = false;
     startRollFlag = true;
     if(event.gyro.z > 0) {
       digitalWrite(statePin, HIGH);
@@ -272,19 +273,19 @@
     if(abs(event.gyro.z) < MIN_ROLL_THRESHOLD)
     {
       digitalWrite(homePin, HIGH);
-      servoHomePin = true;
+      servoHomeFlag = true;
     }
     else if(event.gyro.z > 0)
       {
       digitalWrite(homePin, LOW);
-      servoHomePin = false;
+      servoHomeFlag = false;
       digitalWrite(statePin, LOW);
       finState = false;
       }
     else if(event.gyro.z < 0)
       {
       digitalWrite(homePin, LOW);
-      servoHomePin = false;
+      servoHomeFlag = false;
       digitalWrite(statePin, HIGH);
       finState = true;
       }
@@ -386,8 +387,8 @@
       int packetSize = 19; //Depending on the flight state, the actual packet size may change

       radioPacket[0] = flightState; //Start every packet with the current flight staging (lets the receiver know what data is going to come at the end of the packet)
-      radioPacket[1] = servoOnPin;
-      radioPacket[2] = servoHomePin; //The next three items in each packet report the outputs to the servo.
+      radioPacket[1] = servoOnFlag;
+      radioPacket[2] = servoHomeFlag; //The next three items in each packet report the outputs to the servo.
       radioPacket[3] = finState;

 union{ //Float-to-byte-string converter, needed for GPS data
@@ -425,8 +426,8 @@
 } uInt;

 uInt.tempInt = gyroData[2]; //Remember: THIS ASSUMES Z-AXIS IS VERTICAL!!!
-radioPacket[5] = tempArray[0];
-radioPacket[6] = tempArray[1];
+radioPacket[5] = uInt.tempArray[0];
+radioPacket[6] = uInt.tempArray[1];
 packetSize = 6;
 }


Added Luca's code.

Added Luca's code.

--- src/MonsterSketch/MonsterSketch.ino
+++ src/MonsterSketch/MonsterSketch.ino
@@ -1,5 +1,6 @@
 //#include "Servo.cpp"g_oDataMonster
 #include "DataMonster.cpp"
+#include "SensorModule.cpp"

 // Function Signatures
 void getSerialCommand();
@@ -8,6 +9,7 @@
 // Globals
 //Servo* g_poServo;
 DataMonster* g_poDataMonster;
+SensorModule* g_poMySensorModule;

 int g_iPwmValue = 128;
 bool g_bSettingLowLimit = true;
@@ -38,13 +40,15 @@
   pinMode(g_iLed13, OUTPUT);

   // Generate rand numbers
-//  oRandNumGen = new Random();
+  //  oRandNumGen = new Random();

   // Setup Servos
   //  g_poServo = new Servo(3);
   //  g_poServo->setPwmLimits(0, 255);

   g_poDataMonster = new DataMonster();
+
+  g_poMySensorModule = new SensorModule();

   //Initialize serial and wait for port to open:
   Serial.begin(9600);
@@ -79,16 +83,21 @@
   //    g_poDataMonster->setPosture();

   // IF g_oSensorModule.foundPerson()
-
-  getPersonsLocation(g_fX,g_fY,g_fZ);
+  g_poMySensorModule->update(); // getPersonsLocation(g_fX,g_fY,g_fZ);
   // g_poDataMonster->setMood(FOCUSED)
   // ELSE
   // [X,Y,Z] = g_oSensorModule.getNextDataPosture()
   // g_poDataMonster->setMood(CHILLING)
-  g_poDataMonster->setPosture(g_fX,g_fY,g_fZ);
-    Serial.print("X: ");Serial.print(g_fX);
-    Serial.print("Y: ");Serial.print(g_fY);
-    Serial.print("Z: ");Serial.print(g_fZ);
+  g_fX = g_poMySensorModule->location[0];
+  g_fY = g_poMySensorModule->location[1];
+  g_fZ = g_poMySensorModule->location[2];
+  g_poDataMonster->setPosture(g_fX,  g_fY,  g_fZ);
+  Serial.print("X: ");
+  Serial.print(g_fX);
+  Serial.print(" Y: ");
+  Serial.print(g_fY);
+  Serial.print(" Z: ");
+  Serial.println(g_fZ);

   //////////////
@@ -102,7 +111,7 @@
   // else
   //  {
   // Control Robot
-//  controlRobot();
+  //  controlRobot();
   //  }

 }
@@ -305,3 +314,4 @@

+


Revert "add batt readings"

Revert "add batt readings"

This reverts commit 22afdbb811d28f8e1709133fda770044d0fd18db.

--- Micro_Temp/Micro_Temp.ino
+++ Micro_Temp/Micro_Temp.ino
@@ -26,10 +26,8 @@

 #define UPDATE_FREQUENCY 300 // Time to sleep (in seconds)
 #define DHTTYPE DHT11        // DHT 11
-#define BATT_CAL 0.34        // Offset for internal vcc readings
 const int DHTPin = 2;        // Should be D4 on the Wemos D1 Mini
 bool fahrenheit = true;      // Yes, report fahrenheit
-ADC_MODE(ADC_VCC);           // Allows for reading VCC via internal vreg
 DHT dht(DHTPin, DHTTYPE);

 //Wifi settings
@@ -42,7 +40,7 @@
   Serial.begin(9600);
   while(!Serial) { }         // Wait for serial to initialize.
   Serial.println("I AM WOKE.");
-
+
   dht.begin();
   connectWifi();
   yield();
@@ -110,12 +108,8 @@
   char humid[8];
   dtostrf(getHumidity(), -6, 2, humid);

-  char batt[8];
-  dtostrf((((float)ESP.getVcc()/1024.0)+BATT_CAL), -6, 2, batt);
-
   Serial.println(temp);
   Serial.println(humid);
   MQTT_Helper.publishMQTT("home/living/micro/temp",  temp,  false);
   MQTT_Helper.publishMQTT("home/living/micro/humid", humid, false);
-  MQTT_Helper.publishMQTT("home/living/micro/batt",  batt, false);
 }


cleaning project, further progress on circle visualization

--- project.ino
+++ project.ino
@@ -30,12 +30,12 @@
 int servoMinAngle = 0;
 int servoMaxAngle = 90;
 int servoStepAngle = (servoMaxAngle-servoMinAngle)/(servoSteps-1);
-int servoMSPerDegree = 5;
+int servoMSPerDegree = 200;

-int distanceValues[servoSteps];
+int distanceValues[6];

 void setup() {
-  for(int i=0; i<servoSteps; i++){
+  for(int i=0; i<servoSteps; i+=1){
     distanceValues[i] = 0;
   }

@@ -51,114 +51,95 @@
 }

 void loop(){
-  var i = 0;
+  int i = 0;
   for(servoPos = servoMinAngle; servoPos < servoMaxAngle; servoPos += servoStepAngle){
-    execute(servoPos, i);
+    readSensorWriteLEDs(servoPos, i);
     i+=1;
   }

   for(servoPos = servoMaxAngle; servoPos>servoMinAngle; servoPos-=servoStepAngle)
   {
-    execute(servoPos, i);
+    readSensorWriteLEDs(servoPos, i);
     i-=1;
   }
 }

-void execute(servoPos){
-  servo.write(servoPos, i);
+void readSensorWriteLEDs(int servoPos, int i){
+  servo.write(servoPos);

   triggerSensor();
-  int distance = readSensor();
+  int distance = readSensor();;
   printDistance(distance);

-  distanceValues[i] = distance;
+  distanceValues[i] = distance;
   visualizeCircle();

   delay(servoMSPerDegree*servoStepAngle);
 }

+/**
+ * VISUALIZATION TYPE 1
+ *
+ *    LED-STRIPS:    OBJECT: comming from right
+ *                           near at the right
+ *    [ ][ ][ ]              nearer at the center
+ *    [ ][X][ ]
+ *    [X][X][ ]  =   [o][o][O][O][ ][ ]
+ *    [ ][X][ ]
+ *    [ ][ ][ ]
+ *
+ **/
+
 void visualizeCircle() {
   float maxDistance = 50;
   float minDistance = 10;

-  distance = (distanceValues[0] + distanceValues[1]) / 2;
+  //Calculate the color and the amount of leds for every strip
+  for(int i=0; i<NUMBER_STRIPS; i++){

-  distance = max(minDistance, distance);
-  distance = min(maxDistance, distance);
+    //to get the with 1,2,3 the needed indices we use i*2 and i*2+1
+    //0 = 0,1 / 1 = 2,3 / 2 = 4,5
+    int distance = (distanceValues[i*2] + distanceValues[i*2+1]) / 2;
+    distance = max(minDistance, distance);
+    distance = min(maxDistance, distance);

-  int height = NUMBER_LEDS/NUMBER_STRIPS - (NUMBER_LEDS/NUMBER_STRIPS * ( (distance - minDistance) / (maxDistance - minDistance) ) );
+    int heightStrip = NUMBER_LEDS/NUMBER_STRIPS;
+
+    //how many of the leds of one strip should be switched on
+    int heightToLight = heightStrip * ( (distance - minDistance) / (maxDistance - minDistance) );
+
+    //Calculate the color and the amount of leds for the single strip i
+    for(int j=0; j<heightStrip; j++) {
+      int centerOfStrip = heightStrip/2;
+      int farestLEDFromCenter = heightToLight/2
+
+      /**
+       *   [ ]  When the j is not over or under the heightStrip half plus/minus
+       *   [X]  the height calculated with the distance than it should be switched on
+       *   [X]  <- Center
+       *   [X]
+       *   [ ]  OVerwise it should be off (hear the most top and bottom one)
+       **/
+
+      if(j <= centerOfStrip+farestLEDFromCenter && j >= centerOfStrip+farestLEDFromCenter){
+        strip.setPixelColor(j+(i*heightStrip), strip.Color(255, 0, 0));
+        strip.setPixelColor(j+(i*heightStrip), strip.Color(255, 0, 0));
+      }
+      else{
+        strip.setPixelColor(j+(i*heightStrip), strip.Color(0, 0, 0));
+        strip.setPixelColor(j+(i*heightStrip), strip.Color(0, 0, 0));
+      }
+    }
+  }

-  int single_strip = NUMBER_PINS / 3;
-
-  strip.setBrightness(height * 5);
-
-  for(uint16_t i=0; i<single_strip/2; i++) {
-    if(i <= height/3 && height/3 != 0){
-      for(uint16_t j=0; j < 3; j++) {
-          strip.setPixelColor(single_strip/2 + single_strip*j + i, strip.Color(255, 0, 0));
-          strip.setPixelColor(single_strip/2 + single_strip*j - i -1, strip.Color(255, 0, 0));
-        }
-     }
-    else{
-      for(uint16_t j=0; j < 3; j++) {
-          strip.setPixelColor(single_strip/2 + single_strip*j + i, strip.Color(0, 0, 0));
-          strip.setPixelColor(single_strip/2 + single_strip*j - i -1, strip.Color(0, 0, 0));
-        }
-    }
-  }
   strip.show();
 }

-void changeColorLinear(int distance){
-  float maxDistance = 100;
-  float minDistance = 10;
-
-  uint32_t leds[strip.numPixels()];
-
-
-  for(int i=0; i<strip.numPixels(); i++){
-    int value = min(i*20,255);
-    int green = 255-value;
-    int red = value;
-    leds[i] = strip.Color(red, green, 0);
-  }
-
-  distance = max(minDistance, distance);
-  distance = min(maxDistance, distance);
-
-  int height = NUMBER_PINS - (NUMBER_PINS * ( (distance - minDistance) / (maxDistance - minDistance) ) );
-
-  for(uint16_t i=0; i<strip.numPixels(); i++) {
-    if(i <= height){
-      strip.setPixelColor(i, leds[i]);
-    }
-    else{
-      strip.setPixelColor(i, strip.Color(0,0,0));
-    }
-  }
-
-  strip.show();
-}
-
-long changeColorAll(int distance){
-  int maxDistance = 200;
-  int minDistance = 50;
-
-  distance = max(minDistance, distance);
-  distance = min(maxDistance, distance);
-
-  int value = 255.00 / (maxDistance - minDistance) * (distance - minDistance);
-  int green = value;
-  int red = 255 - value;
-
-  uint32_t c = strip.Color(red, green, 0);
-
-  for(uint16_t i=0; i<strip.numPixels(); i++) {
-    strip.setPixelColor(i, c);
-  }
-
-  strip.show();
-}
+/**
+ *
+ * DISTANCE SENSOR
+ *
+ **/

 long readSensor(){
   // The same pin is used to read the signal from the PING))): a HIGH
@@ -169,12 +150,6 @@

   // convert the time into a distance
   return microsecondsToCentimeters(duration);
-}
-
-void printDistance(int distance){
-  Serial.print(distance);
-  Serial.print(" cm");
-  Serial.println();
 }

 void triggerSensor(){
@@ -188,6 +163,18 @@
   digitalWrite(PIN_SENSOR, LOW);
 }

+/**
+ *
+ * HELPER FUNCTIONS
+ *
+ **/
+
+void printDistance(int distance){
+  Serial.print(distance);
+  Serial.print(" cm");
+  Serial.println();
+}
+
 int microsecondsToCentimeters(long microseconds)
 {
   // The speed of sound is 340 m/s or 29 microseconds per centimeter.


Move flag logic into controller

Move flag logic into controller

--- moros/moros.ino
+++ moros/moros.ino
@@ -170,9 +170,10 @@
     //static char timea[12];
     //ltoa(clock->time_remaining_ms/100, timea, 10);
     screen->display_text(clock->human_time_remaining());
-    if (clock->flag()) {
-      screen->display_flag();
-    }
+  };
+
+  void flag() {
+    screen->display_flag();
   };

   void display_test_pattern() {
@@ -264,6 +265,7 @@
     // Check for flag
     if (players[active_player]->out_of_time()) {
       serprintf("Flag fell for player %d\r\n", active_player);
+      players[active_player]->flag();
       active_player = NONE;
       return;
     }


started autosensing sensor presence

started autosensing sensor presence

--- ardesp/waterelf/waterelf.ino
+++ ardesp/waterelf/waterelf.ino
@@ -64,6 +64,7 @@

 /////////////////////////////////////////////////////////////////////////////
 // data monitoring stuff ////////////////////////////////////////////////////
+const boolean SEND_DATA = false;  // turn of posting of data if required here
 const int MONITOR_POINTS = 60; // number of data points to store
 struct monitor_t {
   unsigned long timestamp;
@@ -86,19 +87,19 @@
 OneWire ds(2); // DS1820 on pin 2 (a 4.7K resistor is necessary)
 DallasTemperature tempSensor(&ds);  // pass through reference to library
 //void getTemperature(float* waterCelsius);
-const boolean GOT_TEMP_SENSOR = true;
+boolean GOT_TEMP_SENSOR = false;
 // array to hold device address
 DeviceAddress tempAddr;

 /////////////////////////////////////////////////////////////////////////////
 // humidity sensor stuff ////////////////////////////////////////////////////
 DHT dht(12, DHT22); // what digital pin we're connected to, plus type DHT22 aka AM2302
-const boolean GOT_HUMID_SENSOR = false;
+boolean GOT_HUMID_SENSOR = false;

 /////////////////////////////////////////////////////////////////////////////
 // Light sensor stuff ///////////////////////////////////////////////////////
 Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); // pass in a number for the sensor identifier (for your use later)
-const boolean GOT_LIGHT_SENSOR = false;
+boolean GOT_LIGHT_SENSOR = false;

 /////////////////////////////////////////////////////////////////////////////
 // RC switch stuff //////////////////////////////////////////////////////////
@@ -151,7 +152,7 @@
     updateSensorData(monitorData);
     delay(100);
     // ledOff();
-    postSensorData(monitorData);
+    if(SEND_DATA) postSensorData(monitorData);
   }
   if(loopCounter == TICK_WIFI_DEBUG) {
     Serial.print("SSID: "); Serial.print(apSSID);
@@ -418,7 +419,6 @@
   if(GOT_HUMID_SENSOR)
   dht.begin();    // Start the humidity and air temperature sensor

-  if(GOT_LIGHT_SENSOR){
   // You can change the gain of the light sensor on the fly, to adapt to brighter/dimmer light situations
   //tsl.setGain(TSL2591_GAIN_LOW);    // 1x gain (bright light)
   tsl.setGain(TSL2591_GAIN_MED);      // 25x gain
@@ -433,7 +433,10 @@
   //tsl.setTiming(TSL2591_INTEGRATIONTIME_500MS);
   //tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS);  // longest integration time (dim light)

-  tsl.begin();    // Start the light sensor
+  if (tsl.begin())
+  {
+    Serial.println("Found a Light sensor");
+    GOT_LIGHT_SENSOR = true;
   }
 }
 void updateSensorData(monitor_t *monitorData) {


hack for denny with faulty sensors

hack for denny with faulty sensors

--- ardesp/waterelf/waterelf.ino
+++ ardesp/waterelf/waterelf.ino
@@ -250,15 +250,34 @@
       off();
     } // TODO if cycleMins - dryMins ...?
   }
+int averageLevel1 = 22; // TODO
+int averageLevel2 = 22;
+int averageLevel3 = 22;
   bool full(monitor_t *now) {
     int l = -1;
+    int al = -1; // TODO
     switch(number) {
       case 1: l = now->waterLevel1; break;
       case 2: l = now->waterLevel2; break;
       case 3: l = now->waterLevel3; break;
     }
     dbg(valveDBG, "now->waterLevel = "); dln(valveDBG, l);
-    return ( l <= fillLevel );
+    dbg(valveDBG, "waterLevel1 = "); dbg(valveDBG, now->waterLevel1);
+    dbg(valveDBG, "; waterLevel2 = "); dbg(valveDBG, now->waterLevel2);
+    dbg(valveDBG, "; waterLevel3 = "); dln(valveDBG, now->waterLevel3);
+
+if(l < 9) return false; // TODO
+switch(number) {
+  case 1: al = (averageLevel1 + l) / 2; averageLevel1 = al;
+  break;
+  case 2: al = (averageLevel2 + l) / 2; averageLevel2 = al;
+  break;
+  case 3: al = (averageLevel3 + l) / 2; averageLevel3 = al;
+  break;
+}
+dbg(valveDBG, "average level = "); dln(valveDBG, al);
+
+    return ( al <= fillLevel );
   }
 };
 int Valve::counter = 1;         // definition (the above only declares)
@@ -266,7 +285,7 @@
 class FlowController { // the set of valves and their config ////////////////
   public:
   int numValves = 3;         // WARNING! call init if resetting!
-  int cycleMins = 21;        // how long is a flood/drain cycle?
+  int cycleMins = 12;        // how long is a flood/drain cycle?
   int maxSimultDrainers = 1; // how many beds can drain simultaneously?
   int minBedsWet = 1;        // min beds that are full or filling
   int maxBedsWet = 2;        // max beds that are full or filling