Revised steering algorithm that actually solves the competition maze. Bot can work a bit better with attached debugger module.

--- maze_robot.ino
+++ maze_robot.ino
@@ -39,9 +39,11 @@
 #define MOTOR_OUT_L 16
 #define MOTOR_OUT_R 21

+#define DEBUGGER_ATTACHED_PIN 3
+
 Servo wheel_left;
 int speed_left = 0;
-int left_zero = 94;
+int left_zero = 93;
 int left_fwd_max = 130;
 int left_rw_max = 55;
 int left_mapped;
@@ -55,6 +57,11 @@

 int speed = 0;
 int dir = 0;
+int more_space = 0;
+int dir_sign = 0;
+
+bool manual_control = true;
+byte byteRead;

 Metro debug_out = Metro(100);

@@ -64,6 +71,9 @@

   wheel_left.attach(MOTOR_OUT_L);
   wheel_right.attach(MOTOR_OUT_R);
+
+  pinMode(DEBUGGER_ATTACHED_PIN, INPUT_PULLUP);
+  manual_control = digitalRead(DEBUGGER_ATTACHED_PIN) == LOW;

   // pinMode(STOP_BUTTON, INPUT_PULLUP);
   // pinMode(DOWN_BUTTON, INPUT_PULLUP);
@@ -77,25 +87,58 @@
   dist_l = analogRead(DIST_IN_L);
   dist_r = analogRead(DIST_IN_R);
   dir = 0;
-  dir += map(
-    dist_r, 0, 300, 90, -90);

-  dir += map(
-      dist_f, 0, 300, 0, -90);
+  if (Serial.available())
+  {
+    /* read the most recent byte */
+    byteRead = Serial.read();
+    if (byteRead == 'a')
+    {
+      manual_control = !manual_control;
+    }
+  }

+  if (manual_control)
+  {
+    left_mapped = left_zero;
+    right_mapped = right_zero;
+  }
+  else
+  {
+    more_space = dist_l - dist_r;

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

-  left_mapped = map_speed(
-    map(dir, -90, 0, 0, 100),
-    left_rw_max, left_zero, left_fwd_max);
-  right_mapped = map_speed(
-    map(dir, 0, 90, 100, 0),
-    right_rw_max, right_zero, right_fwd_max);
+    if (dir >= 0)
+      dir_sign = 1;
+    else
+      dir_sign = -1;
+
+    dir = map(dist_f, 50, 400, dir, dir_sign * 180);
+
+    left_mapped = map_speed(
+      map(dir, -90, 0, 0, 100),
+      left_rw_max, left_zero, left_fwd_max);
+    right_mapped = map_speed(
+      map(dir, 0, 90, 100, 0),
+      right_rw_max, right_zero, right_fwd_max);
+  }

   if (debug_out.check() == 1)
   {
-    p(F("L %03d, F %03d, R %03d, left_mapped %03d, right_mapped %03d"),
-      dist_l, dist_f, dist_r, left_mapped, right_mapped);
+    if (manual_control)
+    {
+      Serial.write("MANUAL ");
+    }
+    else
+    {
+      Serial.write("BOT ");
+    }
+    p(F("L %03d, F %03d, R %03d, dir %03d, left_mapped %03d, right_mapped %03d"),
+      dist_l, dist_f, dist_r, dir, left_mapped, right_mapped);
   }

   wheel_right.write(right_mapped);


user setup depend on connection to cloud

This fixes the potential bugs in 3rd party modules,
such as in servo library, servo attach will touch timer isr,
which may then cause conflict and crash the system
while connecting wifi.

--- src/neurite.ino
+++ src/neurite.ino
@@ -147,9 +147,6 @@
 	start_ticker_led_breath(nd);
 	start_ticker_mon(nd);
 	start_ticker_but(nd);
-#ifdef NEURITE_ENABLE_USER
-	neurite_user_setup();
-#endif
 }

 static int ota_over_http(char *url)
@@ -874,6 +871,7 @@
 	server->send(200, "text/plain", message);
 	/* TODO reboot on save success */
 	log_dbg("out ok\n\r");
+	reboot(nd);
 	return;
 err_handle_save:
 	message += "Bad request\n";
@@ -1071,9 +1069,6 @@
 	log_dbg("sketch free: %d\n\r", ESP.getFreeSketchSpace());

 	neurite_init();
-#ifdef NEURITE_ENABLE_USER
-	neurite_user_setup();
-#endif
 }

 void loop()
@@ -1083,7 +1078,8 @@
 	else
 		neurite_cfg_worker();
 #ifdef NEURITE_ENABLE_USER
-	neurite_user_loop();
+	if (worker_st == WORKER_ST_4)
+		neurite_user_loop();
 #endif
 }

@@ -1103,22 +1099,26 @@
  */

 #ifdef NEURITE_ENABLE_USER
-
 #define USER_LOOP_INTERVAL 1000
-static bool b_user_loop_run = false;

 Servo myservo;
-
-void neurite_user_loop(void)
-{
-	static uint32_t prev_time = 0;
-	if (b_user_loop_run == false)
-		return;
-	/* do something as in a periodically loop */
-	if ((millis() - prev_time) < USER_LOOP_INTERVAL)
-		return;
-	else
-		prev_time = millis();
+static bool b_user_loop_run = true;
+
+enum {
+	USER_ST_0 = 0,
+	USER_ST_1,
+};
+static int user_st = USER_ST_0;
+
+static inline void update_user_state(int st)
+{
+	log_dbg("-> USER_ST_%d\n\r", st);
+	user_st = st;
+}
+
+void neurite_user_worker(void)
+{
+	/* add user stuff here */
 #if 0
 	struct neurite_data_s *nd = &g_nd;
 	static int adc_prev = 0;
@@ -1132,6 +1132,45 @@
 			mqtt_cli.publish(nd->cfg.topic_to, (const char *)buf);
 	}
 #endif
+}
+
+void neurite_user_loop(void)
+{
+	static uint32_t prev_time = 0;
+	if (b_user_loop_run == false)
+		return;
+	if ((millis() - prev_time) < USER_LOOP_INTERVAL)
+		return;
+	prev_time = millis();
+	switch (user_st) {
+		case USER_ST_0:
+			neurite_user_setup();
+			update_user_state(USER_ST_1);
+			break;
+		case USER_ST_1:
+			neurite_user_worker();
+			break;
+		default:
+			log_err("unknown user state: %d\n\r", user_st);
+			break;
+	}
+}
+
+/* called on critical neurite behavior such as OTA */
+void neurite_user_hold(void)
+{
+	log_dbg("\n\r");
+	myservo.detach();
+	update_user_state(USER_ST_0);
+}
+
+/* will be called after neurite system setup */
+void neurite_user_setup(void)
+{
+	log_dbg("\n\r");
+	pinMode(14, OUTPUT);
+	analogWrite(14, 1023);
+	myservo.attach(13);
 }

 /* called once on mqtt message received */
@@ -1240,19 +1279,4 @@
 	}
 }

-/* called on critical neurite behavior such as OTA */
-void neurite_user_hold(void)
-{
-	log_dbg("\n\r");
-	myservo.detach();
-}
-
-/* will be called after neurite system setup */
-void neurite_user_setup(void)
-{
-	log_dbg("\n\r");
-	myservo.attach(13);
-	pinMode(14, OUTPUT);
-	analogWrite(14, 1023);
-}
-#endif
+#endif


Update ServoArduino.ino

Update ServoArduino.ino

Modificado a forma de pegar o angulo do motor
Trocado o (int) para o (byte)

--- AutoMap/ServoArduino.ino
+++ AutoMap/ServoArduino.ino
@@ -23,7 +23,7 @@
 int AnguloX, AnguloY, AnguloZ;
 void setup()
 {
-  Serial.begin(9600);
+  Serial.begin(115200);
   Serial.flush();

   //Inicializa o servo motor
@@ -42,7 +42,7 @@
   temp = Serial.read();
   Serial.println(temp);
   if (valorSerial == 'A'){
-    angulo = (int) temp;
+    angulo = (byte) temp;
     valorSerial = 'c';
   }else{
     valorSerial = temp;
@@ -53,6 +53,7 @@
 {
   if (angulo >= 0){
       servo.write(angulo);
+      Serial.print((int)angulo);
       angulo = -1;
   }
   /*


Mayen E signal now works well.

Mayen E signal now works well.

--- signals/mayen_e/mayen_e.ino
+++ signals/mayen_e/mayen_e.ino
@@ -3,7 +3,7 @@
 #include <signalmover.h>
 #include <Bounce2.h>

-LinearServoMover upper_arm = LinearServoMover(4, 1201, 1850, 800);
+LinearServoMover upper_arm = LinearServoMover(4, 1451, 1850, 600);
 int HP1_BUTTON_PIN = 2;

 SingleSignalMover signal = SingleSignalMover(&upper_arm, HP1_BUTTON_PIN);


downlink cleanup/fix channel create (#17)

* downlink cleanup/fix channel create

--- examples/Downlink/Downlink.ino
+++ examples/Downlink/Downlink.ino
@@ -10,44 +10,11 @@

 // NOTE: Please ensure you've created a channel called "Helium
 // MQTT" called in the Helium Dashboard.
-#define CHANNEL_NAME "AWS IoT"
+#define CHANNEL_NAME "Helium MQTT"

 Helium  helium(&atom_serial);
 Channel channel(&helium);

-
-void
-connect()
-{
-    while (!helium.connected())
-    {
-        Serial.print("Connecting - ");
-        int status = helium.connect();
-        if (report_status(status) != helium_status_OK)
-        {
-            delay(1000);
-        }
-    }
-}
-
-void
-channel_create(const char * channel_name)
-{
-    int8_t result;
-    int    status;
-    do
-    {
-        // Ensure we're connected
-        connect();
-        Serial.print("Creating Channel - ");
-        status = channel.begin(channel_name, &result);
-        // Print status and result
-        if (report_status(status, result) != helium_status_OK)
-        {
-            delay(1000);
-        }
-    } while (helium_status_OK != status || result != 0);
-}

 void
 channel_poll(void * data, size_t len, size_t * used)
@@ -74,9 +41,9 @@
     helium.begin(HELIUM_BAUD_RATE);

     // Connect the Atom to the Helium Network
-    connect();
+    helium_connect(&helium);
     // and ensure the channel is created
-    channel_create(CHANNEL_NAME);
+    channel_create(&channel, CHANNEL_NAME);
 }


Fixed comment in example

Fixed comment in example

--- examples/FSKModem/FSKModem.ino
+++ examples/FSKModem/FSKModem.ino
@@ -167,7 +167,7 @@
   // NOTE: after calling transmitDirect(), SX127x will start
   // transmitting immediately! This signal can jam other
   // devices at the same frequency, it is up to the user
-  // to disable it with idle() method!
+  // to disable it with standby() method!

   // direct mode transmissions can also be received
   // as bit stream on DIO1 (data) and DIO2 (clock)


pre split up

pre split up

began with nightlight and notifier functions

--- wled00/wled00.ino
+++ wled00/wled00.ino
@@ -20,8 +20,8 @@
 String cmdns = "led";
 String apssid = "WLED-AP";
 String appass = "wled1234";
-int apchannel = 1;
-int aphide = 0;
+uint8_t apchannel = 1;
+uint8_t aphide = 0;
 boolean useap = true;
 IPAddress staticip(0, 0, 0, 0);
 IPAddress staticgateway(0, 0, 0, 0);
@@ -32,25 +32,34 @@
 uint16_t transitionDelay = 1500;
 boolean ota_lock = false;
 boolean only_ap = false;
-int led_amount = 16;
-int buttonPin = 3; //needs pull-up
+uint8_t led_amount = 16;
+uint8_t buttonPin = 3; //needs pull-up
 boolean buttonEnabled = true;
 String notifier_ips[]{"10.10.1.128","10.10.1.129"};
 boolean notifyDirect = true, notifyButton = true, notifyForward = true;
 boolean receiveNotifications = true;
 uint8_t bri_n = 100;
+uint8_t nightlightDelayMins = 60;
+boolean nightlightFade = true;
+
+double transitionResolution = 0.05;

 //Internal vars
 byte col_old[]{0, 0, 0};
 byte col_t[]{0, 0, 0};
 long transitionStartTime;
+long nightlightStartTime;
+float tper_last;
 byte bri = 127;
 byte bri_old = 0;
 byte bri_t = 0;
 byte bri_last = 127;
 boolean transitionActive = false;
 boolean buttonPressedBefore = false;
-int notifier_ips_count = 2;
+int notifier_ips_count = 0;
+String notifier_ips_raw = "";
+boolean nightlightActive = false;
+

 NeoPixelBus<NeoGrbFeature, NeoEsp8266Uart800KbpsMethod> strip(led_amount, 1);

@@ -448,6 +457,19 @@
     int i = server.arg("TDLAY").toInt();
     if (i > 0) transitionDelay = i;
   }
+  receiveNotifications = server.hasArg("NRCVE");
+  if (server.hasArg("NRBRI"))
+  {
+    int i = server.arg("NRBRI").toInt();
+    if (i > 0) bri_n = i;
+  }
+  notifyDirect = server.hasArg("NSDIR");
+  notifyButton = server.hasArg("NSBTN");
+  notifyForward = server.hasArg("NSFWD");
+  if (server.hasArg("NSIPS"))
+  {
+    notifier_ips_raw = server.arg("NSIPS");
+  }
   saveSettingsToEEPROM();
 }

@@ -466,19 +488,29 @@
    if (req.indexOf("N=") > 0) isNotification = true;
    pos = req.indexOf("A=");
    if (pos > 0) {
-        bri = req.substring(pos + 2).toInt();
+      bri = req.substring(pos + 2).toInt();
    }
    pos = req.indexOf("R=");
    if (pos > 0) {
-        col[0] = req.substring(pos + 2).toInt();
+      col[0] = req.substring(pos + 2).toInt();
    }
    pos = req.indexOf("G=");
    if (pos > 0) {
-        col[1] = req.substring(pos + 2).toInt();
+      col[1] = req.substring(pos + 2).toInt();
    }
    pos = req.indexOf("B=");
    if (pos > 0) {
-        col[2] = req.substring(pos + 2).toInt();
+      col[2] = req.substring(pos + 2).toInt();
+   }
+   if (req.indexOf("NL=") > 0)
+   {
+      if (req.indexOf("NL=0") > 0)
+      {
+        nightlightActive = false;
+      } else {
+        nightlightActive = true;
+        nightlightStartTime = millis();
+      }
    }
    if (isNotification)
    {
@@ -592,31 +624,6 @@
   path = String();
 }

-void handleFileList() {
-  if(!server.hasArg("dir")) {server.send(500, "text/plain", "BAD ARGS"); return;}
-
-  String path = server.arg("dir");
-  Serial.println("handleFileList: " + path);
-  Dir dir = SPIFFS.openDir(path);
-  path = String();
-
-  String output = "[";
-  while(dir.next()){
-    File entry = dir.openFile("r");
-    if (output != "[") output += ',';
-    bool isDir = false;
-    output += "{\"type\":\"";
-    output += (isDir)?"dir":"file";
-    output += "\",\"name\":\"";
-    output += String(entry.name()).substring(1);
-    output += "\"}";
-    entry.close();
-  }
-
-  output += "]";
-  server.send(200, "text/json", output);
-}
-
 void notify(int callMode)
 {
   switch (callMode)
@@ -711,6 +718,11 @@
       setLedsStandard();
       return;
     }
+    if (tper - tper_last < transitionResolution)
+    {
+      return;
+    }
+    tper_last = tper;
     if (fadeTransition)
     {
       col_t[0] = col_old[0]+((col[0] - col_old[0])*tper);
@@ -722,6 +734,18 @@
     {

     } else setAllLeds();
+  }
+}
+
+void handleNightlight()
+{
+  if (nightlightActive)
+  {
+    float nper = (millis() - nightlightStartTime)/(float)(((int)nightlightDelayMins)*60000);
+    if (nper >= 1)
+    {
+
+    }
   }
 }

@@ -843,7 +867,6 @@
     server.on("/edit", HTTP_PUT, handleFileCreate);
     server.on("/edit", HTTP_DELETE, handleFileDelete);
     server.on("/edit", HTTP_POST, [](){ server.send(200, "text/plain", ""); }, handleFileUpload);
-    server.on("/list", HTTP_GET, handleFileList);
     server.on("/down", HTTP_GET, down);
     server.on("/cleareeprom", HTTP_GET, clearEEPROM);
     //init ota page
@@ -870,6 +893,7 @@
 void loop() {
     server.handleClient();
     handleTransitions();
+    handleNightlight();
     handleAnimations();
     handleButton();
 }


try to debug a bug but with no luch to slove it

--- ArduinoPhone.ino
+++ ArduinoPhone.ino
@@ -20,7 +20,6 @@
 {
     disableTimer();         // disable timer irq
     while (Serial.available()) {
-
         char inChar = (char)Serial.read();
         serialDta[serialDtaCnt++]= inChar;
         if (inChar == '\n') {
@@ -48,7 +47,6 @@

     return sum;
 }
-

 //const unsigned char __numAbc[10][6] PROGMEM =
 char __numAbc[10][5] =
@@ -82,7 +80,6 @@
         serialGot    = false;
         serialDtaCnt = 0;
         UI.msgReadCodeMax = strdo(serialDta);
-        //UI.msgReadNewMsg = 1; // get new msg
         return true;
     }


Another minor progress... need to go back and look at the old code.

--- src/sketch.ino
+++ src/sketch.ino
@@ -8,7 +8,17 @@
 static char msg_buf[MSG_BUF_SIZE];
 static int next_msg_buf_index;

-static bool speed_control_enabled;
+enum SpeedControlState
+{
+	SPEED_CONTROL_DISABLED,
+	SPEED_CONTROL_STOPPED,
+	SPEED_CONTROL_STOPPING,
+	SPEED_CONTROL_DRIVING, /* can't think of a better word for going forwards */
+	SPEED_CONTROL_REVERSING
+};
+
+static SpeedControlState speed_control_state = SPEED_CONTROL_DISABLED;
+
 static int target_speed;
 static int target_steer;
 static int current_speed;
@@ -23,7 +33,38 @@
 unsigned long last_odometer_update;
 unsigned long last_odometer_tick;

-static const int odometer_update_period = 10; // milliseconds
+static const int odometer_update_period = 100; // milliseconds
+
+static void
+update_throttle(int current_speed, int target_speed)
+{
+	int throttle = 0;
+
+	throttle += throttle_offset + 90 +
+	throttle_servo.write(throttle);
+}
+
+static void
+speed_control_update(unsigned long dt, unsigned long ticks)
+{
+	switch (speed_control_state)
+	{
+	case SPEED_CONTROL_DISABLED:
+		return;
+
+	case SPEED_CONTROL_STOPPED:
+		return;
+
+	case SPEED_CONTROL_STOPPING:
+		return;
+
+	case SPEED_CONTROL_DRIVING:
+		return;
+
+	case SPEED_CONTROL_REVERSING:
+		return;
+	}
+}

 static void
 odometer_interrupt()
@@ -42,6 +83,8 @@

 	unsigned long tick_now = odometer_tick;

+	speed_control_update(dt, tick_now - last_odometer_tick);
+
 	last_odometer_tick = tick_now;
 	last_odometer_update = now;
 }
@@ -71,22 +114,22 @@
 	Serial.println();
 }

-void
+static void
 set_stop()
 {

 }

-void
+static void
 set_speed(int speed)
 {

 }

-void
+static void
 set_throttle(int throttle)
 {
-	speed_control_enabled = false;
+	speed_control_state = SPEED_CONTROL_DISABLED;

 	throttle += throttle_offset;
 	if (throttle < 0 || throttle > 180)
@@ -98,7 +141,7 @@
 	throttle_servo.write(throttle);
 }

-void
+static void
 set_steer(int steer)
 {
 	steer += steer_offset;
@@ -232,3 +275,4 @@
 	msg_poll();
 	odometer_poll();
 }
+


Change START_CAR to match the PHY

Change START_CAR to match the PHY

--- VehicleController/VehicleController.ino
+++ VehicleController/VehicleController.ino
@@ -26,7 +26,7 @@

 void setup(){
     // Set Pin Modes
-    pinMode(PIN_START_CAR, INPUT);
+    pinMode(PIN_START_CAR, INPUT_PULLUP);
     pinMode(PIN_BRAKE_IN, INPUT);
     pinMode(PIN_1PPS, INPUT);
     pinMode(PIN_3D_FIX, INPUT);


Support test RAbstractStringRef, RFlashStringRef, RConstStringRef and RStringRef at the sametime

--- tests/TestStringRefs/TestStringRefs.ino
+++ tests/TestStringRefs/TestStringRefs.ino
@@ -5,6 +5,9 @@
 #include <StandardCplusplus.h>
 #include <RabirdToolkit.h>
 #include <RAbstractStringRef.h>
+#include <RConstStringRef.h>
+#include <RStringRef.h>
+#include <RFlashStringRef.h>
 #include <RTest.h>
 #include <string.h>

@@ -50,125 +53,276 @@
 {
 }

-RTEST(TestAbstractStringRef)
-{
-  const char *normalString0 = "";
-  const char *normalString1 = "a";
-  const char *normalString2 = "ab";
-  const char *normalString3 = "abc";
-  const char *normalString4 = "AbC";
-
-  // length
-  RASSERT_EQUAL(BasicStringRef(normalString0).length(), strlen(normalString0));
-  RASSERT_EQUAL(BasicStringRef(normalString1).length(), strlen(normalString1));
-  RASSERT_EQUAL(BasicStringRef(normalString2).length(), strlen(normalString2));
-  RASSERT_EQUAL(BasicStringRef(normalString3).length(), strlen(normalString3));
-
-  // compareTo
-  RASSERT_EQUAL(BasicStringRef(normalString3).compareTo(BasicStringRef(
-                                                          normalString3)), 0);
-  RASSERT_MORE(BasicStringRef(normalString3).compareTo(BasicStringRef(
-                                                         normalString2)), 0);
-  RASSERT_MORE(BasicStringRef(normalString3).compareTo(BasicStringRef(
-                                                         normalString1)), 0);
-  RASSERT_MORE(BasicStringRef(normalString3).compareTo(BasicStringRef(
-                                                         normalString0)), 0);
-
-  RASSERT_LESS(BasicStringRef(normalString0).compareTo(BasicStringRef(
-                                                         normalString3)), 0);
-  RASSERT_LESS(BasicStringRef(normalString0).compareTo(BasicStringRef(
-                                                         normalString2)), 0);
-  RASSERT_LESS(BasicStringRef(normalString0).compareTo(BasicStringRef(
-                                                         normalString1)), 0);
-  RASSERT_LESS(BasicStringRef(normalString0).compareTo(BasicStringRef(
-                                                         normalString0)), 0);
-
-  RASSERT_EQUAL(BasicStringRef(normalString3).compareTo((normalString3)), 0);
-  RASSERT_MORE(BasicStringRef(normalString3).compareTo((normalString2)), 0);
-  RASSERT_MORE(BasicStringRef(normalString3).compareTo((normalString1)), 0);
-  RASSERT_MORE(BasicStringRef(normalString3).compareTo((normalString0)), 0);
-
-  RASSERT_LESS(BasicStringRef(normalString0).compareTo((normalString3)), 0);
-  RASSERT_LESS(BasicStringRef(normalString0).compareTo((normalString2)), 0);
-  RASSERT_LESS(BasicStringRef(normalString0).compareTo((normalString1)), 0);
-  RASSERT_LESS(BasicStringRef(normalString0).compareTo((normalString0)), 0);
-
-  // equals
-  RASSERT_TRUE(BasicStringRef(normalString3).equals(BasicStringRef(
-                                                      normalString3)));
-  RASSERT_TRUE(BasicStringRef(normalString3).equals((normalString3)));
-
-  // equalsIgnoreCase
-  RASSERT_TRUE(BasicStringRef(normalString3).equalsIgnoreCase(BasicStringRef(
-                                                                normalString4)));
-  RASSERT_TRUE(BasicStringRef(normalString3).equalsIgnoreCase(BasicStringRef(
-                                                                normalString3)));
-  RASSERT_FALSE(BasicStringRef(normalString3).equalsIgnoreCase(BasicStringRef(
-                                                                 normalString2)));
-  RASSERT_FALSE(BasicStringRef(normalString3).equalsIgnoreCase(BasicStringRef(
-                                                                 normalString0)));
-
-  // startsWith
-  RASSERT_TRUE(BasicStringRef(normalString3).startsWith(BasicStringRef(
-                                                          normalString3)));
-  RASSERT_TRUE(BasicStringRef(normalString3).startsWith(BasicStringRef(
-                                                          normalString2)));
-  RASSERT_TRUE(BasicStringRef(normalString3).startsWith(BasicStringRef(
-                                                          normalString1)));
-  RASSERT_FALSE(BasicStringRef(normalString3).startsWith(BasicStringRef(
-                                                           normalString0)));
-
-  // endsWith
-  RASSERT_TRUE(BasicStringRef(normalString3).endsWith(BasicStringRef("c")));
-  RASSERT_TRUE(BasicStringRef(normalString3).endsWith(BasicStringRef("bc")));
-  RASSERT_TRUE(BasicStringRef(normalString3).endsWith(BasicStringRef("abc")));
-  RASSERT_FALSE(BasicStringRef(normalString3).endsWith(BasicStringRef("")));
-
-  // charAt
-  RASSERT_TRUE(BasicStringRef(normalString3).charAt(0) == 'a');
-  RASSERT_TRUE(BasicStringRef(normalString3).charAt(1) == 'b');
-  RASSERT_TRUE(BasicStringRef(normalString3).charAt(2) == 'c');
-  RASSERT_TRUE(BasicStringRef(normalString3).charAt(3) == '\0');
-
-  // indexOf
-  RASSERT_EQUAL(BasicStringRef(normalString3).indexOf('a'), 0);
-  RASSERT_EQUAL(BasicStringRef(normalString3).indexOf('b'), 1);
-  RASSERT_EQUAL(BasicStringRef(normalString3).indexOf('c'), 2);
-  RASSERT_EQUAL(BasicStringRef(normalString3).indexOf('d'), -1);
-
-  // lastIndexOf
-  RASSERT_EQUAL(BasicStringRef(normalString3).lastIndexOf('a'), 0);
-  RASSERT_EQUAL(BasicStringRef(normalString3).lastIndexOf('b'), 1);
-  RASSERT_EQUAL(BasicStringRef(normalString3).lastIndexOf('c'), 2);
-  RASSERT_EQUAL(BasicStringRef(normalString3).lastIndexOf('d'), -1);
-
-  // operator ==
-  RASSERT_TRUE(BasicStringRef(normalString3) == BasicStringRef(normalString3));
-  RASSERT_TRUE(BasicStringRef(normalString3) == normalString3);
-
-  // operator !=
-  RASSERT_TRUE(BasicStringRef(normalString3) != BasicStringRef(normalString3));
-  RASSERT_TRUE(BasicStringRef(normalString3) != BasicStringRef(normalString0));
-
-  // operator >
-  RASSERT_TRUE(BasicStringRef(normalString3) > BasicStringRef(normalString2));
-  RASSERT_TRUE(BasicStringRef(normalString3) > BasicStringRef(normalString0));
-
-  // operator <
-  RASSERT_TRUE(BasicStringRef(normalString1) < BasicStringRef(normalString3));
-  RASSERT_TRUE(BasicStringRef(normalString1) < BasicStringRef(normalString2));
-
-  // operator <=
-  RASSERT_TRUE(BasicStringRef(normalString2) <= BasicStringRef(normalString3));
-  RASSERT_TRUE(BasicStringRef(normalString2) <= BasicStringRef(normalString2));
-  RASSERT_TRUE(BasicStringRef(normalString2) <= BasicStringRef(normalString1));
-  RASSERT_FALSE(BasicStringRef(normalString2) <= BasicStringRef(normalString0));
-
-  // operator >=
-  RASSERT_FALSE(BasicStringRef(normalString2) >= BasicStringRef(normalString3));
-  RASSERT_TRUE(BasicStringRef(normalString2) >= BasicStringRef(normalString2));
-  RASSERT_TRUE(BasicStringRef(normalString2) >= BasicStringRef(normalString1));
-  RASSERT_TRUE(BasicStringRef(normalString2) >= BasicStringRef(normalString0));
+template < class DerivedType, class StringRefType >
+class BasicTestStringRef:
+public RTest
+{
+public:
+  typedef BasicTestStringRef < DerivedType, StringRefType > ThisType;
+
+  BasicTestStringRef(const __FlashStringHelper * str)
+    : RTest(str)
+    , mNormalString0("")
+    , mNormalString1("a")
+    , mNormalString2("ab")
+    , mNormalString3("abc")
+    , mNormalString4("AbC")
+    , mFlashString0(F(""))
+    , mFlashString1(F("a"))
+    , mFlashString2(F("ab"))
+    , mFlashString3(F("abc"))
+    , mFlashString4(F("AbC"))
+    , mString0("")
+    , mString1("a")
+    , mString2("ab")
+    , mString3("abc")
+    , mString4("Abc")
+  {
+  }
+
+  void
+  run()
+  {
+    const StringRefType &
+    stringRef0(getDerived()->mStringRef0);
+    const StringRefType &
+    stringRef1(getDerived()->mStringRef1);
+    const StringRefType &
+    stringRef2(getDerived()->mStringRef2);
+    const StringRefType &
+    stringRef3(getDerived()->mStringRef3);
+    const StringRefType &
+    stringRef4(getDerived()->mStringRef4);
+
+    // length
+    RASSERT_EQUAL(stringRef0.length(), strlen(mNormalString0));
+    RASSERT_EQUAL(stringRef1.length(), strlen(mNormalString1));
+    RASSERT_EQUAL(stringRef2.length(), strlen(mNormalString2));
+    RASSERT_EQUAL(stringRef3.length(), strlen(mNormalString3));
+
+    // compareTo
+    RASSERT_EQUAL(stringRef3.compareTo(stringRef3), 0);
+    RASSERT_MORE(stringRef3.compareTo(stringRef2), 0);
+    RASSERT_MORE(stringRef3.compareTo(stringRef1), 0);
+    RASSERT_MORE(stringRef3.compareTo(stringRef0), 0);
+
+    RASSERT_LESS(stringRef0.compareTo(stringRef3), 0);
+    RASSERT_LESS(stringRef0.compareTo(stringRef2), 0);
+    RASSERT_LESS(stringRef0.compareTo(stringRef1), 0);
+    RASSERT_LESS(stringRef0.compareTo(stringRef0), 0);
+
+    RASSERT_EQUAL(stringRef3.compareTo((mNormalString3)), 0);
+    RASSERT_MORE(stringRef3.compareTo((mNormalString2)), 0);
+    RASSERT_MORE(stringRef3.compareTo((mNormalString1)), 0);
+    RASSERT_MORE(stringRef3.compareTo((mNormalString0)), 0);
+
+    RASSERT_LESS(stringRef0.compareTo((mNormalString3)), 0);
+    RASSERT_LESS(stringRef0.compareTo((mNormalString2)), 0);
+    RASSERT_LESS(stringRef0.compareTo((mNormalString1)), 0);
+    RASSERT_LESS(stringRef0.compareTo((mNormalString0)), 0);
+
+    // equals
+    RASSERT_TRUE(stringRef3.equals(stringRef3));
+    RASSERT_TRUE(stringRef3.equals((mNormalString3)));
+
+    // equalsIgnoreCase
+    RASSERT_TRUE(stringRef3.equalsIgnoreCase(stringRef4));
+    RASSERT_TRUE(stringRef3.equalsIgnoreCase(stringRef3));
+    RASSERT_FALSE(stringRef3.equalsIgnoreCase(stringRef2));
+    RASSERT_FALSE(stringRef3.equalsIgnoreCase(stringRef0));
+
+    // startsWith
+    RASSERT_TRUE(stringRef3.startsWith(stringRef3));
+    RASSERT_TRUE(stringRef3.startsWith(stringRef2));
+    RASSERT_TRUE(stringRef3.startsWith(stringRef1));
+    RASSERT_FALSE(stringRef3.startsWith(stringRef0));
+
+    // endsWith
+    RASSERT_TRUE(stringRef3.endsWith(BasicStringRef("c")));
+    RASSERT_TRUE(stringRef3.endsWith(BasicStringRef("bc")));
+    RASSERT_TRUE(stringRef3.endsWith(BasicStringRef("abc")));
+    RASSERT_FALSE(stringRef3.endsWith(BasicStringRef("")));
+
+    // charAt
+    RASSERT_TRUE(stringRef3.charAt(0) == 'a');
+    RASSERT_TRUE(stringRef3.charAt(1) == 'b');
+    RASSERT_TRUE(stringRef3.charAt(2) == 'c');
+    RASSERT_TRUE(stringRef3.charAt(3) == '\0');
+
+    // indexOf
+    RASSERT_EQUAL(stringRef3.indexOf('a'), 0);
+    RASSERT_EQUAL(stringRef3.indexOf('b'), 1);
+    RASSERT_EQUAL(stringRef3.indexOf('c'), 2);
+    RASSERT_EQUAL(stringRef3.indexOf('d'), -1);
+
+    // lastIndexOf
+    RASSERT_EQUAL(stringRef3.lastIndexOf('a'), 0);
+    RASSERT_EQUAL(stringRef3.lastIndexOf('b'), 1);
+    RASSERT_EQUAL(stringRef3.lastIndexOf('c'), 2);
+    RASSERT_EQUAL(stringRef3.lastIndexOf('d'), -1);
+
+    // operator ==
+    RASSERT_TRUE(stringRef3 == stringRef3);
+    RASSERT_TRUE(stringRef3 == mNormalString3);
+
+    // operator !=
+    RASSERT_TRUE(stringRef3 != stringRef3);
+    RASSERT_TRUE(stringRef3 != stringRef0);
+
+    // operator >
+    RASSERT_TRUE(stringRef3 > stringRef2);
+    RASSERT_TRUE(stringRef3 > stringRef0);
+
+    // operator <
+    RASSERT_TRUE(stringRef1 < stringRef3);
+    RASSERT_TRUE(stringRef1 < stringRef2);
+
+    // operator <=
+    RASSERT_TRUE(stringRef2 <= stringRef3);
+    RASSERT_TRUE(stringRef2 <= stringRef2);
+    RASSERT_TRUE(stringRef2 <= stringRef1);
+    RASSERT_FALSE(stringRef2 <= stringRef0);
+
+    // operator >=
+    RASSERT_FALSE(stringRef2 >= stringRef3);
+    RASSERT_TRUE(stringRef2 >= stringRef2);
+    RASSERT_TRUE(stringRef2 >= stringRef1);
+    RASSERT_TRUE(stringRef2 >= stringRef0);
+  }
+
+protected:
+  inline
+  DerivedType *
+  getDerived()
+  {
+    return static_cast < DerivedType * > (const_cast < ThisType * > (this));
+  }
+
+  inline
+  const DerivedType *
+  getDerived() const
+  {
+    return static_cast < DerivedType * > (const_cast < ThisType * > (this));
+  }
+
+public:
+  const char *mNormalString0;
+  const char *mNormalString1;
+  const char *mNormalString2;
+  const char *mNormalString3;
+  const char *mNormalString4;
+
+  const __FlashStringHelper *mFlashString0;
+  const __FlashStringHelper *mFlashString1;
+  const __FlashStringHelper *mFlashString2;
+  const __FlashStringHelper *mFlashString3;
+  const __FlashStringHelper *mFlashString4;
+
+  String mString0;
+  String mString1;
+  String mString2;
+  String mString3;
+  String mString4;
+};
+class TestBasicStringRef
+: public BasicTestStringRef < TestBasicStringRef, BasicStringRef >
+{
+public:
+  typedef BasicStringRef                                           StringRefType;
+  typedef BasicTestStringRef < TestBasicStringRef, StringRefType > BaseType;
+
+  TestBasicStringRef()
+    : BaseType(F("TestBasicStringRef"))
+    , mStringRef0(mNormalString0)
+    , mStringRef1(mNormalString1)
+    , mStringRef2(mNormalString2)
+    , mStringRef3(mNormalString3)
+    , mStringRef4(mNormalString4)
+  {
+  }
+
+public:
+  StringRefType mStringRef0;
+  StringRefType mStringRef1;
+  StringRefType mStringRef2;
+  StringRefType mStringRef3;
+  StringRefType mStringRef4;
+}
+
+class TestConstStringRef
+: public BasicTestStringRef < TestConstStringRef, RConstStringRef >
+{
+public:
+  typedef RConstStringRef
+                                                                     StringRefType;
+  typedef BasicTestStringRef < TestConstStringRef, RConstStringRef > BaseType;
+
+  TestConstStringRef()
+    : BaseType(F("TestConstStringRef"))
+    , mStringRef0(mNormalString0)
+    , mStringRef1(mNormalString1)
+    , mStringRef2(mNormalString2)
+    , mStringRef3(mNormalString3)
+    , mStringRef4(mNormalString4)
+  {
+  }
+
+public:
+  StringRefType mStringRef0;
+  StringRefType mStringRef1;
+  StringRefType mStringRef2;
+  StringRefType mStringRef3;
+  StringRefType mStringRef4;
+}
+
+class TestFlashStringRef
+: public BasicTestStringRef < TestFlashStringRef, RFlashStringRef >
+{
+public:
+  typedef RFlashStringRef                                          StringRefType;
+  typedef BasicTestStringRef < TestFlashStringRef, StringRefType > BaseType;
+
+  TestFlashStringRef()
+    : BaseType(F("TestFlashStringRef"))
+    , mStringRef0(mFlashString0)
+    , mStringRef1(mFlashString1)
+    , mStringRef2(mFlashString2)
+    , mStringRef3(mFlashString3)
+    , mStringRef4(mFlashString4)
+  {
+  }
+
+public:
+  StringRefType mStringRef0;
+  StringRefType mStringRef1;
+  StringRefType mStringRef2;
+  StringRefType mStringRef3;
+  StringRefType mStringRef4;
+}
+
+class TestStringRef
+: public BasicTestStringRef < TestStringRef, RStringRef >
+{
+public:
+  typedef RStringRef                                          StringRefType;
+  typedef BasicTestStringRef < TestStringRef, StringRefType > BaseType;
+
+  TestStringRef()
+    : BaseType(F("TestStringRef"))
+    , mStringRef0(&mString0)
+    , mStringRef1(&mString1)
+    , mStringRef2(&mString2)
+    , mStringRef3(&mString3)
+    , mStringRef4(&mString4)
+  {
+  }
+
+public:
+  StringRefType mStringRef0;
+  StringRefType mStringRef1;
+  StringRefType mStringRef2;
+  StringRefType mStringRef3;
+  StringRefType mStringRef4;
 }

 void
@@ -180,9 +334,16 @@
   {
   }

-  RTestApplication testApp;
-
-  testApp.addTest(&RTEST_INSTANCE(TestAbstractStringRef));
+  RTestApplication   testApp;
+  TestBasicStringRef testBasicStringRef;
+  TestConstStringRef testConstStringRef;
+  TestFlashStringRef testFlashStringRef;
+  TestStringRef      testStringRef;
+
+  testApp.addTest(&testBasicStringRef);
+  testApp.addTest(&testConstStringRef);
+  testApp.addTest(&testFlashStringRef);
+  testApp.addTest(&testStringRef);
   testApp.run();
 }


Code cleanup

Code cleanup

--- arduino/serialWShield/serialWShield.ino
+++ arduino/serialWShield/serialWShield.ino
@@ -14,42 +14,21 @@
 void setup(){
 	comp.begin(9600);

-  pinMode(13, OUTPUT);
-
-  if (LCD){
-  lcd.begin(DOG_LCD_M163);
-  lcd.print("Recvd: -");
-  lcd.setCursor(0,1);
-  lcd.print("Bytes: 0");
-  lcd.setCursor(0, 2);
-  lcd.print("Alive: ");
-  }
+  	pinMode(13, OUTPUT);
+
+	lcd.begin(DOG_LCD_M163);
+	lcd.print("Recvd: -");
+	lcd.setCursor(0,1);
+	lcd.print("Bytes: 0");
+	lcd.setCursor(0, 2);
+	lcd.print("Alive: ");
 }

 void loop(){
-  if (LCD && KEYS){
-  static int oldkey = -1;
-  int adc_key_in = analogRead(0); // read the value from the
-  //digitalWrite(13, HIGH);
-  int key = get_key(adc_key_in); // convert into key press
-  if (key != oldkey){ // if keypress is detected
-    delay(50); // wait for debounce time
-    adc_key_in = analogRead(0); //read the value from the sensor
-    key = get_key(adc_key_in); // convert into key press
-    if (key != oldkey) {
-      oldkey = key;
-      if (key >=0){
-        lcd.setCursor(8, 0); //line=2, x=0
-        lcd.print(key, DEC);
-      }
-    }
-  }
-  //digitalWrite(13, LOW);
-  }
-  lcd.setCursor(7, 2);
-  lcd.print(millis()/1000);
-  lcd.print("s");
-  delay(100);
+  	lcd.setCursor(7, 2);
+	lcd.print(millis()/1000);
+	lcd.print("s");
+	delay(100);
 }

 void serialEvent(){
@@ -58,20 +37,6 @@

 	comp.serialEvent();

-	if (LCD){
-		lcd.setCursor(7, 1);
-		lcd.print(bytes);
-	}
+	lcd.setCursor(7, 1);
+	lcd.print(bytes);
 }
-
-int get_key(int value){
-  const int adc_key_val[5] ={30, 150, 360, 535, 760 };
-  const int NUM_KEYS = 5;
-
-  for (int i = 0; i < NUM_KEYS; ++i){
-    if (value <= adc_key_val[i]){
-      return i;
-    }
-  }
-  return -1;
-}


MQTT433gateway.ino: move setup() to correct position

--- MQTT433gateway.ino
+++ MQTT433gateway.ino
@@ -64,20 +64,6 @@
 boolean logMode = false;
 boolean rawMode = false;
 String otaURL = "";
-
-void setup() {
-  Serial.begin(115200,SERIAL_8N1,SERIAL_TX_ONLY);
-  setupWifi();
-  mqtt.setServer(mqttBroker, 1883);
-  mqtt.setCallback(mqttCallback);
-  pinMode(RECEIVER_PIN, INPUT_PULLUP); //5V protection with reverse diode needs pullup
-  rf.setCallback(rfCallback);
-  rf.setPulseTrainCallBack(rfRawCallback);
-  rf.initReceiver(RECEIVER_PIN);
-  Serial.println();
-  Serial.print(F("Name: "));
-  Serial.println(mainTopic);
-}

 void setupWifi() {
   delay(10);
@@ -263,6 +249,20 @@
   beatLED.off();
 }

+void setup() {
+  Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
+  setupWifi();
+  mqtt.setServer(mqttBroker, 1883);
+  mqtt.setCallback(mqttCallback);
+  pinMode(RECEIVER_PIN, INPUT_PULLUP); //5V protection with reverse diode needs pullup
+  rf.setCallback(rfCallback);
+  rf.setPulseTrainCallBack(rfRawCallback);
+  rf.initReceiver(RECEIVER_PIN);
+  Serial.println();
+  Serial.print(F("Name: "));
+  Serial.println(mainTopic);
+}
+
 void loop() {
   if (!mqtt.connected()) {
     reconnect();


non-blocking servo

non-blocking servo

--- src/arduino/bear.ino
+++ src/arduino/bear.ino
@@ -15,14 +15,21 @@
 const int LED_2 = 8;

 const int SERVO_MAX_ANGLE = 30;
+const int SERVO_BASE_ANGLE = 60;

 const int BLINK_INTERVAL = 150; // in milliseconds
+const int DEGREE_STEP = 1;
+const int SERVO_INTERVAL = 10; // in milliseconds

 Servo myservo; // create servo object to control a servo

 int current_bpm = 120;
+int current_angle = 0;
+
+bool current_velocity_positive = true;
 unsigned long previous_blink_downbeat = 0;
 unsigned long previous_blink_upbeat = 0;
+unsigned long previous_servo_move = 0;

 IRrecv irrecv(IR_RECEIVER);     // create instance of 'irrecv'
 decode_results results;      // create instance of 'decode_results'
@@ -78,13 +85,29 @@

   if (previous_blink_downbeat && current_millis - previous_blink_downbeat >= BLINK_INTERVAL) stop_blink(true);
   if (previous_blink_upbeat && current_millis - previous_blink_upbeat >= BLINK_INTERVAL) stop_blink(false);
+
+  if (previous_servo_move && current_millis - previous_servo_move >= SERVO_INTERVAL) {
+    // check if it should return
+    if (current_angle >= 60000 / current_bpm * 4 / 5 / (2 * SERVO_INTERVAL / DEGREE_STEP)) {
+      --current_angle;
+      current_velocity_positive = !current_velocity_positive;
+    }
+    // move the servo
+    current_angle += (current_velocity_positive ? 1 : -1) * DEGREE_STEP;
+    myservo.write(SERVO_BASE_ANGLE + current_angle);
+    if (current_angle == 0 && !current_velocity_positive) {
+      previous_servo_move = 0;
+    } else {
+      previous_servo_move += SERVO_INTERVAL;
+    }
+  }
 }

 void flash_beat(bool is_downbeat, unsigned long current_millis) {
   digitalWrite(LED_BUILTIN, HIGH);
   digitalWrite(is_downbeat ? RED : BLUE, HIGH);
   digitalWrite(is_downbeat ? LED_1 : LED_2, HIGH);
-  switch_servo();
+  start_servo(current_millis);
   (is_downbeat ? previous_blink_downbeat : previous_blink_upbeat) = current_millis;
 }

@@ -102,6 +125,13 @@
   digitalWrite(is_downbeat ? RED : BLUE, LOW);
   digitalWrite(is_downbeat ? LED_1 : LED_2, LOW);
   (is_downbeat ? previous_blink_downbeat : previous_blink_upbeat) = 0;
+}
+
+void start_servo(unsigned long current_millis) {
+  myservo.write(SERVO_BASE_ANGLE);
+  current_angle = 0;
+  current_velocity_positive = true;
+  previous_servo_move = current_millis;
 }

 void switch_servo() {


removed confirmation for reading registers

--- MSDOS/MSDOS.ino
+++ MSDOS/MSDOS.ino
@@ -479,10 +479,7 @@
       if(caseReadMCReg && !defaultCase)
       {
         CAN_message_t txMessage = setupMCMessage(REG_READ, regID);
-
-        //send message if the user confirms they want to send it
-        if(confirmPopUp(txMessage))
-          Can0.write(txMessage);
+        Can0.write(txMessage);

         Serial.print(F(readMCRegMenu));
       }
@@ -610,7 +607,7 @@
 //Main menu for the program
 void loop() {

-  //only display the menu system if anything is typed into the serial terminal
+  //Menu system for anything typed into the serial terminal
   if (Serial.available() > 0)
   {
     rx_byte = Serial.read();


Cleaned up a bit

Cleaned up a bit

--- Ascii/Ascii.ino
+++ Ascii/Ascii.ino
@@ -7,9 +7,11 @@
 //
 // Copyright 2005 Jeff Whitlatch - ko7m

+#define count(x) (sizeof(x) / sizeof(x[0]))
+
 void setup()
 {
-	char *label[] = { ", dec: ", ", hex: ", ", oct: ", ", bin: "};
+	char *label[] = { ", dec: ", ", hex: ", ", oct: ", ", bin: " };
 	int conv[] = { DEC, HEX, OCT, BIN };

 	//Initialize serial and wait for port to open:
@@ -19,7 +21,7 @@
 	for (int iChar = '!'; iChar <= '~'; iChar++)
 	{
 		Serial.write(iChar);
-		for (int i = 0; i < 4; i++)
+		for (int i = 0; i < count(conv); i++)
 		{
 			Serial.print(label[i]);
 			Serial.print(iChar, conv[i]);


Make helium sketch more useful

Make helium sketch more useful


Minimized code and stablished hex communication

--- RF_receiver.ino
+++ RF_receiver.ino
@@ -1,171 +1,39 @@
-/*
- Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- version 2 as published by the Free Software Foundation.
- */
-
-/**
- * Example for Getting Started with nRF24L01+ radios.
- *
- * This is an example of how to use the RF24 class.  Write this sketch to two
- * different nodes.  Put one of the nodes into 'transmit' mode by connecting
- * with the serial monitor and sending a 'T'.  The ping node sends the current
- * time to the pong node, which responds by sending the value back.  The ping
- * node can then see how long the whole cycle took.
- */
-
 #include <SPI.h>
 #include "nRF24L01.h"
 #include "RF24.h"
 #include "printf.h"

-//
-// Hardware configuration
-//
-
-// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
+//Defines radio pins (CE and CSN) as 9 and 10 respectively

 RF24 radio(9,10);

-//
-// Topology
-//
-
-// Radio pipe addresses for the 2 nodes to communicate.
+//Create channels for communication
 const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
-
-//
-// Role management
-//
-// Set up role.  This sketch uses the same software for all the nodes
-// in this system.  Doing so greatly simplifies testing.
-//
-
-// The various roles supported by this sketch
-typedef enum { role_ping_out = 1, role_pong_back } role_e;
-
-// The debug-friendly names of those roles
-const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};
-
-// The role of the current running sketch
-role_e role = role_pong_back;

 void setup(void)
 {
-  //
-  // Print preamble
-  //
+  //Start serial communication and print info
+  Serial.begin(57600);
+  Serial.println("-- RF_receiver - Drone Board --");

-  Serial.begin(57600);
-  printf_begin();
-  printf("\n\rRF24/examples/GettingStarted/\n\r");
-  printf("ROLE: %s\n\r",role_friendly_name[role]);
-  printf("*** PRESS 'T' to begin transmitting to the other node\n\r");
-
-  //
-  // Setup and configure rf radio
-  //
-
+  //Start radio communication, open writing and reading pipes
   radio.begin();
-
-  // optionally, increase the delay between retries & # of retries
   radio.setRetries(15,15);

-  // optionally, reduce the payload size.  seems to
-  // improve reliability
-  //radio.setPayloadSize(8);
-
-  //
-  // Open pipes to other nodes for communication
-  //
-
-  // This simple sketch opens two pipes for these two nodes to communicate
-  // back and forth.
-  // Open 'our' pipe for writing
-  // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)
-
-  //if ( role == role_ping_out )
-  {
-    //radio.openWritingPipe(pipes[0]);
-    radio.openReadingPipe(1,pipes[1]);
-  }
-  //else
-  {
-    //radio.openWritingPipe(pipes[1]);
-    //radio.openReadingPipe(1,pipes[0]);
-  }
-
-  //
-  // Start listening
-  //
-
+  //Here it opens channel 1 as writing and 0 as reading.
+  //This is default for receiving.
+  //To change for transmitting, we change to the exact opposite.
+  radio.openWritingPipe(pipes[1]);
+  radio.openReadingPipe(1,pipes[0]);
+
+  //Listen to Radio and print details about it.
   radio.startListening();
-
-  //
-  // Dump the configuration of the rf unit for debugging
-  //
-
   radio.printDetails();
 }

 void loop(void)
 {
-  //
-  // Ping out role.  Repeatedly send the current time
-  //
-
-  if (role == role_ping_out)
-  {
-    // First, stop listening so we can talk.
-    radio.stopListening();
-
-    // Take the time, and send it.  This will block until complete
-    unsigned long time = millis();
-    printf("Now sending %lu...",time);
-    bool ok = radio.write( &time, sizeof(unsigned long) );
-
-    if (ok)
-      printf("ok...");
-    else
-      printf("failed.\n\r");
-
-    // Now, continue listening
-    radio.startListening();
-
-    // Wait here until we get a response, or timeout (250ms)
-    unsigned long started_waiting_at = millis();
-    bool timeout = false;
-    while ( ! radio.available() && ! timeout )
-      if (millis() - started_waiting_at > 200 )
-        timeout = true;
-
-    // Describe the results
-    if ( timeout )
-    {
-      printf("Failed, response timed out.\n\r");
-    }
-    else
-    {
-      // Grab the response, compare, and send to debugging spew
-      unsigned long got_time;
-      radio.read( &got_time, sizeof(unsigned long) );
-
-      // Spew it
-      printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time);
-    }
-
-    // Try again 1s later
-    delay(1000);
-  }
-
-  //
-  // Pong back role.  Receive each packet, dump it out, and send it back
-  //
-
-  if ( role == role_pong_back )
-  {
+
     // if there is data ready
     if ( radio.available() )
     {


Add defines to select different input mappings for hardware variations.

--- TandySticks.ino
+++ TandySticks.ino
@@ -8,6 +8,13 @@
   This file is hereby placed in the public domain.
 */

+// Uncomment one of these:
+
+#define HARDWARE_PUBLIC_DOMAIN_CIRCUIT
+//#define HARDWARE_PRODUCTION_PROTOTYPE
+//#define HARDWARE_PRODUCTION_BURGER
+//#define HARDWARE_PRODUCTION_SUPER
+
 #include "TandyStick.h"

 static const unsigned long UPDATE_PERIOD = 8333;                // 1/120th of a second.
@@ -15,13 +22,25 @@
 static const int           PREVIOUS_UPDATES_TO_AVERAGE_IN = 2;  // 3/120th of a second.
 static const int           UPDATES_FOR_DEBOUNCE = 6;            // 1/20th of a second - max press rate is 10 per second.

-TandyStick stick0(Joystick + 0, A3, A2, A6, 2, 3);
-TandyStick stick1(Joystick + 1, A1, A0, A7, 5, 7);
+#if defined(HARDWARE_PUBLIC_DOMAIN_CIRCUIT)
+  TandyStick stick0(Joystick + 0, A3, A2, A6, 2, 3);
+  TandyStick stick1(Joystick + 1, A1, A0, A7, 5, 7);
+#elif defined(HARDWARE_PRODUCTION_PROTOTYPE)
+  TandyStick stick0(Joystick + 0, A0, A1, A6, 2, 3);
+  TandyStick stick1(Joystick + 1, A2, A3, A7, 5, 7);
+#elif defined(HARDWARE_PRODUCTION_BURGER)
+  #error Not implemented yet!
+#elif defined(HARDWARE_PRODUCTION_SUPER)
+  #error Not implemented yet!
+#else
+  #error One (and only one) of the HARDWARE_ types at the top of this file must be uncommented.
+#endif

 unsigned long sNextUpdateEnd;

 void setup()
 {
+
   // Enable for logging.
   Serial.begin(38400);


Fixed servo issue

Fixed servo issue

--- Firmeware/EnsembleFive/EnsembleFive.ino
+++ Firmeware/EnsembleFive/EnsembleFive.ino
@@ -55,6 +55,7 @@
 // servos
 Servo servo1, servo2, servo3;
 bool servoState[3]; // servo state to control servos out of MIDI loop
+bool _servoState[3]; // servo previous state
 float servoPos[3]; // servo current position
 float servoInc[3]; //servo increment value which relates to movement speed
 float servoMinInc[3]; // servo min increment values
@@ -100,6 +101,11 @@

   servoPos[2] = midi2angle(EEPROM.read(S3MINANG));
   servo3.write(servoPos[2]);
+
+  // set servos previous state
+  _servoState[0] = false;
+  _servoState[1] = false;
+  _servoState[2] = false;

   // set servos' min&max increment values
   // NOTE: min/max inc values are between 0 and 127 (after mapped correspond to 0.1 to 10 degrees per millisecond)
@@ -123,7 +129,6 @@
   servoMinAng[2] = midi2angle( EEPROM.read(S3MINANG) );
   servoMaxAng[2] = midi2angle( EEPROM.read(S3MAXANG) );

-
   // set note2pin array
   note2pin[0] = A1;

@@ -150,6 +155,10 @@
             if(pitch < 27){ // set servos' values only (activation is done in runServos function)
               servoInc[pitch-24] = velocity2inc( servoMinInc[pitch-24], servoMaxInc[pitch-24], vel);
               servoState[pitch-24] = true;
+              _servoState[pitch-24] = true;
+              if(pitch==24) servo1.attach(C1);
+              if(pitch==25) servo2.attach(C2);
+              if(pitch==26) servo3.attach(C3);
             }
             if(pitch > 35){ // activate relay
               digitalWrite(note2pin[pitch], LOW);
@@ -186,7 +195,7 @@
   }

   runServos(); // activate servos
-  delay(1); // (used only to set servo increments in a millisecond basis)
+  //delay(1); // (used only to set servo increments in a millisecond basis)
 }

 /***************** FUNTCIONS *****************/
@@ -209,9 +218,10 @@
     servoPos[0] += servoInc[0];
   }
   // servo1 release
-  else if (servoState[0] == false){
+  else if (servoState[0] == false && _servoState[0] == true){
     servoPos[0] = servoMinAng[0];
-    servo1.write( servoPos[0] );
+    servo1.write( servoPos[0] );
+    _servoState[0] = false;
   }

   // servo2 attack
@@ -220,9 +230,10 @@
     servoPos[1] += servoInc[1];
   }
   // servo2 release
-  else if (servoState[1] == false){
+  else if (servoState[1] == false && _servoState[1] == true){
     servoPos[1] = servoMinAng[1];
-    servo2.write( servoPos[1] );
+    servo2.write( servoPos[1] );
+    _servoState[1] = false;
   }

   // servo3 attack
@@ -231,9 +242,10 @@
     servoPos[2] += servoInc[2];
   }
   // servo3 release
-  else if (servoState[2] == false){
+  else if (servoState[2] == false && _servoState[2] == true){
     servoPos[2] = servoMinAng[2];
-    servo3.write( servoPos[2] );
+    servo3.write( servoPos[2] );
+    _servoState[2] = false;
   }
 }


revise message

revise message

--- sketches/EnerginoBattery/EnerginoBattery.ino
+++ sketches/EnerginoBattery/EnerginoBattery.ino
@@ -1,7 +1,10 @@
 /*
- * Energino
- *
- * Energino is a energy consumption meter for DC loads (win average).
+ * EnerginoBattery
+ *
+ * EnerginoBattery is optimized for the ABSOLUTE PLMU. The script includes an
+ * empirical battery discharge model for the 30Ah battery. Resistor and current
+ * sensor paramenters are set to the values used in the Energino embedded with
+ * the PLMU prototype.
  *
  * Circuit:
  *  Analog inputs attached to pins A0 (Current), A1 (Voltage)


Update pmc-xmas-lights.ino

Update pmc-xmas-lights.ino

Fix #48

--- sketches/pmc-xmas-lights/pmc-xmas-lights.ino
+++ sketches/pmc-xmas-lights/pmc-xmas-lights.ino
@@ -25,7 +25,7 @@
 }

 static int bit_count = 0;
-byte var = 1;
+byte direction = 1;

 void loop() {
 #if 1
@@ -36,14 +36,14 @@
   digital_outputs.setAll(value);
   delay(100);

-  if (var == 1)
-    bit_count++;
-    if (bit_count == 7)
-      var = 0;
-  else
-    bit_count--;
-    if (bit_count == 0)
-      var = 1;
+  if (direction >= 1) {
+    if (++bit_count >= 7)
+      direction = 0;
+  }
+  else {
+    if (--bit_count <= 0)
+      direction = 1;
+  }

 #else
   Serial.println("DIGITAL OUT:");


Make the 'id' command conform to the new standard command/response format

--- arduino/rflink/rflink.ino
+++ arduino/rflink/rflink.ino
@@ -67,13 +67,12 @@
     uint8_t node_id = id_read();
     if (argc >= 2) {
         node_id = atoi(argv[1]);
-        Serial.print("Setting id to ");
-        Serial.print(node_id);
         id_write(node_id);
         radio_init(node_id);
    }
-   Serial.print("id = ");
+   Serial.print("id 00 ");
    Serial.println(node_id);
+   return 0;
 }

 static int do_ping(int argc, char *argv[])


Modified bringup code to work without pixels configured

--- HMTL_Modules/HMTL_Bringup/HMTL_Bringup.ino
+++ HMTL_Modules/HMTL_Bringup/HMTL_Bringup.ino
@@ -32,13 +32,16 @@
 config_value_t value_output;
 config_rs485_t rs485_output;
 boolean has_value = false;
-
+boolean has_pixels = false;

 int configOffset = -1;
+
 PixelUtil pixels;

 void setup() {
   Serial.begin(9600);
+
+  DEBUG_PRINTLN(DEBUG_LOW, "***** HMTL Bringup *****");

   // XXX Update this to hmtl_setup()
   readconfig.address = -1;
@@ -68,7 +71,11 @@
   for (int i = 0; i < config.num_outputs; i++) {
     void *data = NULL;
     switch (((output_hdr_t *)outputs[i])->type) {
-    case HMTL_OUTPUT_PIXELS: data = &pixels; break;
+    case HMTL_OUTPUT_PIXELS: {
+      data = &pixels;
+      has_pixels = true;
+      break;
+    }
     case HMTL_OUTPUT_RGB: {
       memcpy(&rgb_output, outputs[i], sizeof (rgb_output));
       break;
@@ -82,46 +89,56 @@
     hmtl_setup_output((output_hdr_t *)outputs[i], data);
   }

-  for (unsigned int i = 0; i < pixels.numPixels(); i++) {
-    pixels.setPixelRGB(i, 0, 0, 0);
+  if (has_pixels) {
+    for (unsigned int i = 0; i < pixels.numPixels(); i++) {
+      pixels.setPixelRGB(i, 0, 0, 0);
+    }
+    pixels.update();
   }
-  pixels.update();
 }

 void loop() {

   DEBUG_PRINTLN(0, "White");
   if (has_value) digitalWrite(value_output.pin, HIGH);
-  for (unsigned int i=0; i < pixels.numPixels(); i++)
-    pixels.setPixelRGB(i, 255, 255, 255);
-  pixels.update();
+  if (has_pixels) {
+    for (unsigned int i=0; i < pixels.numPixels(); i++)
+      pixels.setPixelRGB(i, 255, 255, 255);
+    pixels.update();
+  }

   delay(1000);

   DEBUG_PRINTLN(0, "Red");
   if (has_value) digitalWrite(value_output.pin, LOW);
   digitalWrite(rgb_output.pins[0], HIGH);
-  for (unsigned int i=0; i < pixels.numPixels(); i++)
-    pixels.setPixelRGB(i, 255, 0, 0);
-  pixels.update();
+  if (has_pixels) {
+    for (unsigned int i=0; i < pixels.numPixels(); i++)
+      pixels.setPixelRGB(i, 255, 0, 0);
+    pixels.update();
+  }

   delay(1000);

   DEBUG_PRINTLN(0, "Green");
   digitalWrite(rgb_output.pins[0], LOW);
   digitalWrite(rgb_output.pins[1], HIGH);
-  for (unsigned int i=0; i < pixels.numPixels(); i++)
-    pixels.setPixelRGB(i, 0, 255, 0);
-  pixels.update();
+  if (has_pixels) {
+    for (unsigned int i=0; i < pixels.numPixels(); i++)
+      pixels.setPixelRGB(i, 0, 255, 0);
+    pixels.update();
+  }

   delay(1000);

   DEBUG_PRINTLN(0, "Blue");
   digitalWrite(rgb_output.pins[1], LOW);
   digitalWrite(rgb_output.pins[2], HIGH);
-  for (unsigned int i=0; i < pixels.numPixels(); i++)
-    pixels.setPixelRGB(i, 0, 0, 255);
-  pixels.update();
+  if (has_pixels) {
+    for (unsigned int i=0; i < pixels.numPixels(); i++)
+      pixels.setPixelRGB(i, 0, 0, 255);
+    pixels.update();
+  }

   delay(1000);


post Shane

post Shane

--- extern/Cloud_LED_RFM/Cloud_LED_RFM.ino
+++ extern/Cloud_LED_RFM/Cloud_LED_RFM.ino
@@ -45,7 +45,7 @@
 #define N_PACKETS 100

 // APA102 led strip.  Note, this is only used on the Rx side.
-#define APA_NLED 66
+#define APA_NLED 200
 #define APA_DATA_PIN 4 // DI. JeeNode DO on Port 1. at the end of JeeNode LN.
 #define APA_CLOCK_PIN 7 // CI.  JeeNode DO on Port 4. mid-span of JeeNode LN.
 Adafruit_DotStar APAleds = Adafruit_DotStar(APA_NLED, APA_DATA_PIN, APA_CLOCK_PIN);
@@ -56,7 +56,7 @@
 const uint32_t aBlack = APAleds.Color(0, 0, 0);

 // WS2812B led strip.  Note, this is only used on the Rx side.
-#define WS_NLED 66
+#define WS_NLED 200
 #define WS_DATA_PIN A0 // AI. JeeNode AO on Port 4. at the end of JeeNode LN.
 Adafruit_NeoPixel WSleds = Adafruit_NeoPixel(WS_NLED, WS_DATA_PIN, NEO_GRB + NEO_KHZ800);
 const uint32_t wRed = WSleds.Color(255, 0, 0);
@@ -106,7 +106,7 @@
       doRx(); // receive radio traffic

       static boolean showAPA=true;
-      static boolean showWS=true;
+      static boolean showWS=false;
       doLeds(showAPA, showWS); // update the leds

       break;
@@ -144,7 +144,7 @@
     radio.SendWait(); // wait for completion

     // wait for next send.
-    delay(sendInterval);
+ //   delay(sendInterval);
   }

   Serial << F("Packet sending complete at ") << millis() / 1000 << F(" sec.") << endl;


Change variable names and remove Serial print


another try at troublesome gps

another try at troublesome gps

--- ESP32/beacon_gps_update/beacon_gps_update.ino
+++ ESP32/beacon_gps_update/beacon_gps_update.ino
@@ -94,40 +94,40 @@
 long lat, lon;

 void gps_setup(){
-  Serial2.begin(9600);
+  Serial2.begin(9600);   //Do not change, must match factory setting.
 }

 void
 gps_read_into( beacon_data_t * beaconData)
 {
-    Serial.print(".");
+    //Serial.print(".");
     if(Serial2.available())
     {
-    Serial.print(":");
-      int c = Serial2.read();
+    //Serial.print(":");
+      int c = Serial2.read();
       if (gps.encode(c)) // do we have a valid gps data that we can encode
       {
-          Serial.print(",");
+          //Serial.print(",");
           gps.get_position(&lat,&lon); // get latitude and longitude
-          Serial.printf("Float Position - lat: %f lon: %f \n", flat, flon);
-
-          gps.get_position( &beaconData->fields.gpsLatitute, &beaconData->fields.gpsLongitude );
+          Serial.printf("Position - lat: %ld lon: %ld \n", lat, lon);
+
+          //gps.get_position( &beaconData->fields.gpsLatitute, &beaconData->fields.gpsLongitude );

           // returns speed in 100ths of a knot
-          speed = gps.speed();
+          //speed = gps.speed();

           // course in 100ths of a degree
-          course = gps.course();
+          //course = gps.course();

-          beaconData->fields.gpsForwardBearing            = beaconData->fields.gpsForwardBearing;
-          beaconData->fields.gpsLatitute                  = beaconData->fields.gpsLatitute;  // times by GPS_SCALE;
-          beaconData->fields.gpsLongitude                 = beaconData->fields.gpsLongitude; // times by GPS_SCALE;
-          beaconData->fields.gpsForwardSpeed              = beaconData->fields.gpsForwardSpeed;
-          beaconData->fields.forwardExclusionZoneDistance = beaconData->fields.forwardExclusionZoneDistance;
-          beaconData->fields.rearExclusionZoneDistance    = beaconData->fields.rearExclusionZoneDistance;
-          beaconData->fields.sideExclusionZoneDistance    = beaconData->fields.sideExclusionZoneDistance;
+          //beaconData->fields.gpsForwardBearing            = beaconData->fields.gpsForwardBearing;
+          //beaconData->fields.gpsLatitute                  = beaconData->fields.gpsLatitute;  // times by GPS_SCALE;
+          //beaconData->fields.gpsLongitude                 = beaconData->fields.gpsLongitude; // times by GPS_SCALE;
+          //beaconData->fields.gpsForwardSpeed              = beaconData->fields.gpsForwardSpeed;
+          //beaconData->fields.forwardExclusionZoneDistance = beaconData->fields.forwardExclusionZoneDistance;
+          //beaconData->fields.rearExclusionZoneDistance    = beaconData->fields.rearExclusionZoneDistance;
+          //beaconData->fields.sideExclusionZoneDistance    = beaconData->fields.sideExclusionZoneDistance;

          // Calculate Bearing
@@ -229,7 +229,7 @@

 void
 setup() {
-    Serial.begin(115200);
+    Serial.begin(9600);
     Serial.setDebugOutput(true);
     pinMode(LED_BUILTIN, OUTPUT);
     Serial.print("ESP32 SDK: ");
@@ -241,18 +241,18 @@

 void
-loop() {
+loop() {
     gps_read_into( &myBeaconData );
-    if(esp_ble_gap_config_adv_data(&advertisement_config))
-    {   log_e("gap_config_adv_data failed");
-        exit(1);
-    }
+    //if(esp_ble_gap_config_adv_data(&advertisement_config))
+    //{   log_e("gap_config_adv_data failed");
+    //    exit(1);
+    //}
     delay(500); digitalWrite(LED_BUILTIN, HIGH);
     delay(500); digitalWrite(LED_BUILTIN, LOW);

           //delay(1000);

-    static long counter = 0;  //example only
-    counter = counter + 1;    //example only
-    myBeaconData.fields.watchdogCounter              = counter;
-}
+    //static long counter = 0;  //example only
+    //counter = counter + 1;    //example only
+    //myBeaconData.fields.watchdogCounter              = counter;
+}


Update Weather_mikroe_SAM3X.ino

Update Weather_mikroe_SAM3X.ino

Use Weather Click in Slot C

--- Weather_mikroe_SAM3X/Weather_mikroe_SAM3X.ino
+++ Weather_mikroe_SAM3X/Weather_mikroe_SAM3X.ino
@@ -1,7 +1,41 @@
+/***************************************************************************
+ *
+ * Copyright (c) 2020 Robert Nelson <robert.nelson@digikey.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Slot: C: Weather Click
+ *
+ ***************************************************************************/
+
 #include <SPI.h>
 #include <Wire.h>
+
+/* Adafruit BME280 Library: 2.0.2 */
+#include <Adafruit_Sensor.h>
+#include <Adafruit_BME280.h>
+
 #include "flip_click_defs.h"
-#include "SparkFun_AS3935.h"
+//#include "SparkFun_AS3935.h"
+
+Adafruit_BME280 bme; // I2C
+
+unsigned long delayTime;

 #define AS3935_INDOOR 0x12
 #define AS3935_OUTDOOR 0xE
@@ -12,7 +46,7 @@
 #define AS3935_CS  B_CS
 #define AS3935_INT B_INT

-SparkFun_AS3935 lightning;
+//SparkFun_AS3935 lightning;

 int AS3935_intVal = 0;
 int AS3935_noise = 2; // Value between 1-7
@@ -22,47 +56,83 @@
 const int TMP116_temp_reg   = 0x00;  // Temperature register
 const int TMP116_config_reg = 0x01;  // Configuration register

+int counter=10;
+
+bool has_bme = true;
+
 void setup()
 {
   Serial.begin(57600);
   Serial.println("MIKROE SAM3X WeatherDemo");

-  SPI.begin();
-  SPI.setDataMode( SPI_MODE1 );
+  bme_init();

-  thunder_init();
+//  SPI.begin();
+//  SPI.setDataMode( SPI_MODE1 );

-  Wire.begin();
+//  thunder_init();

-  tmp116_init();
+//  Wire.begin();
+
+//  tmp116_init();
 }

 void loop()
 {
-  double temp = TMP116_ReadTempSensor();
+//  double temp = TMP116_ReadTempSensor();
+//  Serial.println(temp);
+
+//  if(digitalRead(AS3935_INT) == HIGH){
+//    AS3935_intVal = lightning.readInterruptReg();
+//    if(AS3935_intVal == AS3935_NOISE_INT){
+//      Serial.println("debug: Noise.");
+//    }
+//    else if(AS3935_intVal == AS3935_DISTURBER_INT){
+//      Serial.println("debug: Disturber.");
+//    }
+//    else if(AS3935_intVal == AS3935_LIGHTNING_INT){
+//      Serial.println("debug: Lightning Strike Detected!");
+//      // Lightning! Now how far away is it? Distance estimation takes into
+//      // account any previously seen events in the last 15 seconds.
+//      byte distance = lightning.distanceToStorm();
+//      Serial.print("Approximately: ");
+//      Serial.print(distance);
+//      Serial.println("km away!");
+//    }
+//  }

-  Serial.println(temp);
-
-  if(digitalRead(AS3935_INT) == HIGH){
-    AS3935_intVal = lightning.readInterruptReg();
-    if(AS3935_intVal == AS3935_NOISE_INT){
-      Serial.println("debug: Noise.");
-    }
-    else if(AS3935_intVal == AS3935_DISTURBER_INT){
-      Serial.println("debug: Disturber.");
-    }
-    else if(AS3935_intVal == AS3935_LIGHTNING_INT){
-      Serial.println("debug: Lightning Strike Detected!");
-      // Lightning! Now how far away is it? Distance estimation takes into
-      // account any previously seen events in the last 15 seconds.
-      byte distance = lightning.distanceToStorm();
-      Serial.print("Approximately: ");
-      Serial.print(distance);
-      Serial.println("km away!");
-    }
+  bme_read();
+
+  counter++;
+  if (counter == 100)
+  {
+    counter = 10;
   }

   delay(5000); // wait 5 seconds for the next I2C scan
+}
+
+void bme_init() {
+   if (! bme.begin(0x76, &Wire)) {
+        Serial.println("Could not find a valid BME280 sensor, check wiring!");
+        has_bme=false;
+    }
+}
+
+void bme_read() {
+    bme.takeForcedMeasurement(); // has no effect in normal mode
+
+    Serial.print("MIKROESAM3X_WC:");
+    Serial.print(counter);
+    Serial.print(":Temp:");
+    float bme_temp_c = bme.readTemperature();
+    float bme_temp_f = ((bme_temp_c * 1.8) + 32);
+    Serial.print(bme_temp_f);
+    Serial.print("F:Press:");
+    Serial.print(bme.readPressure() / 100.0F);
+    Serial.print("mB:Humidity:");
+    Serial.print(bme.readHumidity());
+    Serial.println("%:#");
 }

 void thunder_init()
@@ -71,14 +141,14 @@
   digitalWrite(AS3935_CS, HIGH);
   pinMode(AS3935_INT, INPUT);

-  if( !lightning.beginSPI(AS3935_CS, 2000000) ){
-    Serial.println ("debug: Lightning Detector did not start up, freezing!");
-    while(1);
-  }
-  else
-    Serial.println("debug: Lightning Detector Ready!");
+//  if( !lightning.beginSPI(AS3935_CS, 2000000) ){
+//    Serial.println ("debug: Lightning Detector did not start up, freezing!");
+//    while(1);
+//  }
+//  else
+//    Serial.println("debug: Lightning Detector Ready!");

-  lightning.setIndoorOutdoor(AS3935_OUTDOOR);
+  //lightning.setIndoorOutdoor(AS3935_OUTDOOR);
 }

 double TMP116_ReadTempSensor(void){


fixed missing assignment in conversion for German layout - all characters on German keyboard work now, removed Serial debug output


Update crybaby_ver1.0.ino

Update crybaby_ver1.0.ino

Found an error in updateAmmoCounter function where, in the "ammoCount < 10000" case, the four writeDigitAscii() command were targeting LED counter positions 0, 1, 1, and 1, instead of 0, 1, 2, and 3 like in every other case.  Credit to Bill Taylor for helping me discover this issue.  Updated ammoCount < 10000 case to update the correct LED positions.

--- crybaby_ver1.0.ino
+++ crybaby_ver1.0.ino
@@ -131,8 +131,8 @@
           else if (ammoCount < 10000) {
             alpha4.writeDigitAscii(0, ammoDisp[0]);
             alpha4.writeDigitAscii(1, ammoDisp[1]);
-            alpha4.writeDigitAscii(1, ammoDisp[2]);
-            alpha4.writeDigitAscii(1, ammoDisp[3]);
+            alpha4.writeDigitAscii(2, ammoDisp[2]);
+            alpha4.writeDigitAscii(3, ammoDisp[3]);
           }
           alpha4.writeDisplay();
 }


Publish humidity with 0.01% resolution.

Publish humidity with 0.01% resolution.

--- zg01_esp/zg01_esp.ino
+++ zg01_esp/zg01_esp.ino
@@ -44,21 +44,19 @@
     wifiManager.autoConnect("ESP-ZG01");
 }

-static void mqtt_send(const char *topic, int value, const char *unit)
+static void mqtt_send(const char *topic, const char *value)
 {
     if (!mqttClient.connected()) {
         mqttClient.setServer(MQTT_HOST, MQTT_PORT);
         mqttClient.connect(esp_id);
     }
     if (mqttClient.connected()) {
-        char string[64];
-        snprintf(string, sizeof(string), "%d %s", value, unit);
         Serial.print("Publishing ");
-        Serial.print(string);
+        Serial.print(value);
         Serial.print(" to ");
         Serial.print(topic);
         Serial.print("...");
-        int result = mqttClient.publish(topic, string, true);
+        int result = mqttClient.publish(topic, value, true);
         Serial.println(result ? "OK" : "FAIL");
     }
 }
@@ -66,6 +64,7 @@
 void loop(void)
 {
     static bool prev_clk = false;
+    char valstr[16];

     bool clk = (digitalRead(PIN_CLOCK) == HIGH);
     if (prev_clk && !clk) {
@@ -83,11 +82,13 @@
             switch (item) {
             case 'P':
                 // CO2
-                mqtt_send(TOPIC_CO2, value, "PPM");
+                snprintf(valstr, sizeof(valstr), "%d PPM", value);
+                mqtt_send(TOPIC_CO2, valstr);
                 break;
             case 'A':
                 // humidity
-                mqtt_send(TOPIC_HUMIDITY, (value + 50) / 100, "%");
+                snprintf(valstr, sizeof(valstr), "%d.%02d %%", value / 100, value % 100);
+                mqtt_send(TOPIC_HUMIDITY, valstr);
                 break;
             default:
                 // ignore unhandled packet


Update Arduino code to operate a second servo

--- Arduino/fishfeeder.ino
+++ Arduino/fishfeeder.ino
@@ -2,7 +2,8 @@
 #include <EEPROM.h>

 int pinled = 2;
-int pinservo = 3;
+int pinservodump = 3;
+int pinservoopen = 6;
 int pinmotor = 4;
 int pinmotorspeed = 5;
 int pingreen = 10;
@@ -18,8 +19,10 @@
 const int containers = 28;
 const int motorspeed = 255;

-const int servoup = 159;
-const int servodown = 63;
+const int servodumpup = 159;
+const int servodumpdown = 63;
+const int servoopenopen = 1;
+const int servoopenclosed = 180;

 const int address_calibrated = 1;
 const int address_position = 2;
@@ -32,11 +35,13 @@

 boolean errorstate = false;

-SoftwareServo servo;
+SoftwareServo servodump;
+SoftwareServo servoopen;

 void setup() {
 	pinMode(pinled, OUTPUT);
-	pinMode(pinservo, OUTPUT);
+	pinMode(pinservodump, OUTPUT);
+	pinMode(pinservoopen, OUTPUT);
 	pinMode(pinmotor, OUTPUT);
 	pinMode(pinmotorspeed, OUTPUT);
 	pinMode(pinred, OUTPUT);
@@ -49,9 +54,12 @@

 	Serial.begin(9600);

-	servo.attach(pinservo);
-	servo.write(servoup);
-
+	servodump.attach(pinservodump);
+	servodump.write(servodumpup);
+	delayandrefresh(300);
+	servoopen.attach(pinservoopen);
+	servoopen.write(servoopenclosed);
+
 	if (EEPROM.read(address_calibrated) == 1) {
 		calibrated = true;
 		position = (float)EEPROM.read(address_position) * (float)containers / (float)fullrotation;
@@ -63,11 +71,11 @@
 	}

 	for (int i = 0; i < 3; i++) {
-		delay(200);
+		delayandrefresh(200);
 		if (calibrated)
 			setcolor(0,255,0);
 		else setcolor(100,255,0);
-		delay(200);
+		delayandrefresh(200);
 		setcolor(0,0,0);
 	}
 }
@@ -228,17 +236,23 @@

 void flush() {
 	setcolor(128,0,200);
-	servo.write(servodown);
+
+	servoopen.write(servoopenopen);
+	delayandrefresh(500);
+
+	servodump.write(servodumpdown);
 	delayandrefresh(600);
-	servo.write(servoup);
-
-	delayandrefresh(1000);
-	servo.write(servodown);
-	delayandrefresh(2000);
-	servo.write(servoup);
-
+	servodump.write(servodumpup);
+
+	delayandrefresh(800);
+	servodump.write(servodumpdown);
+	delayandrefresh(600);
+	servodump.write(servodumpup);
+
+	delayandrefresh(600);
 	setcolor(0,0,0);
-	delayandrefresh(600);
+	servoopen.write(servoopenclosed);
+	delayandrefresh(500);
 }

 void checkserial() {


Changes Debugged, Ramps Working

Changes Debugged, Ramps Working

Pitched, yaw, and roll all now have a ramping function with optional sticky flags.  A direction marked sticky will stick its last abs(highest) value until the opposite direction is pushed and it will reset.  Un-sticky directions will just reset to zero when you let go of the direction.

--- KSPboard.ino
+++ KSPboard.ino
@@ -12,6 +12,7 @@

 #define ENABLE true
 #define DISABLE false
+#define NEUTRAL 2

 // serial
 #define SERIAL_SPEED 115200
@@ -45,7 +46,7 @@
 #define PIN_OP_ACG5 0

 // delays
-#define DELAY_LOOP 1500
+#define DELAY_LOOP 500
 #define DELAY_START 30
 #define DELAY_OP 100

@@ -53,7 +54,7 @@
 #define OPS (sizeof(opPin) / sizeof(uint8_t))

 #define ANALOG_MAX (float)1023 // these two are for converting 0-1023 to 0-100
-#define THOTTLE_MAX (float)INT8_MAX
+#define THOTTLE_MAX (float)UINT8_MAX
 #define RAMP_MAX 125
 #define RAMP_MIN -125
 #define DIR_MAX 1023
@@ -68,13 +69,10 @@
 #define ROLL_PINS PIN_ROLL_R, PIN_ROLL_L
 #define YAW_PINS PIN_YAW_R, PIN_YAW_L

-enum dir { full, half, zero };
-

 // helm control variables
-int16_t pitch, yaw, roll;
-uint8_t throttle;
-int8_t pitch_adj, yaw_adj, roll_adj; // for ramping the directional input
+int16_t pitch, yaw, roll, throttle;
+int8_t pitch_adj = 0, yaw_adj = 0, roll_adj = 0; // for ramping the direction input

 // op control variables
 // state == 0 to DELAY_OP-1 -> off / debounce, state == DELAY_OP -> on
@@ -109,18 +107,19 @@

 int8_t getAdjustment(uint8_t pinH, uint8_t pinL, int8_t adj) // get control input
 {
-  switch (digitalRead(pinH) ? full : (digitalRead(pinL) ? half : zero))
-  {
-    case full:
+  switch (digitalRead(pinH) ? HIGH : (digitalRead(pinL) ? LOW : NEUTRAL))
+  {
+    case HIGH:
       if (adj++ >= RAMP_MAX)
         adj = RAMP_MAX;
       break;

-    case zero:
+    case LOW:
       if (adj-- <= RAMP_MIN)
         adj = RAMP_MIN;
       break;

+    case NEUTRAL:
     default:
       adj = 0;
   }
@@ -128,12 +127,14 @@
   return (adj);
 }

-int16_t getDirection(int16_t current, boolean stick, int8_t adj)
-{
+int16_t getDirection(int16_t current, int8_t adj, boolean stick)
+{
+  // reset current if no stick flag or if adj and current are opposite signs
+  if (!(adj || stick) || (current > 0 && adj < 0) || (current < 0 && adj > 0))
+    current = 0;
+
   current += adj;
-
-  if (!(adj || stick))
-    current = 0;
+

   if (current > DIR_MAX)
     current = DIR_MAX;
@@ -144,9 +145,9 @@
   return (current);
 }

-uint8_t getThrottle(uint8_t pin) // get throttle input
-{
-  return ((uint8_t) (((float)analogRead(pin) * THOTTLE_MAX) / ANALOG_MAX));
+uint16_t getThrottle(uint8_t pin) // get throttle input
+{
+  return (analogRead(pin));
 }

@@ -203,11 +204,7 @@
   // tells the python client when to close
   state = digitalRead(PIN_ENABLE);
   digitalWrite(PIN_LED, state);
-
-  if (state)
-    Serial.println(ENABLE);
-  else
-    Serial.println(DISABLE);
+  Serial.println(state);
 }

 void updateHelm()
@@ -222,6 +219,7 @@

   yaw_adj = getAdjustment(YAW_PINS, yaw_adj);
   yaw = getDirection(yaw, yaw_adj, YAW_STICK);
+  Serial.println(yaw);

   throttle = getThrottle(PIN_THROTTLE);
   Serial.println(throttle);
@@ -285,7 +283,7 @@
   if (state)
   {
     updateHelm();
-    updateOps();
+    //updateOps();
   }

   delay(DELAY_LOOP);


Delete Salt_Lamp_v2.0.ino.ino

Delete Salt_Lamp_v2.0.ino.ino

--- Salt_Lamp_v2.0.ino.ino
+++ Salt_Lamp_v2.0.ino.ino
@@ -1,327 +0,0 @@
-
-// Neopixel Salt Lamp v2.0
-// By Chris Barrett - Polaris Interplanetary - Special Projects Division
-// Supports two modes; All pixel colour fade, and 8 pixel RGB mixer. All modes are asynchronous, and compartmentalized into functions.
-
-//  Dec  2016     - Changed shimmer to use a different array based system to try and finally end flickering.
-//  June 2016     - Re-implemented rotary encoder functions for brightness control
-//                - New timing function to space out updates
-//                - LIGHTNING FUNCTION
-//                - produces a quicker shimmer effect, may replace shimmer with it later.
-//  January 2016  - Shimmer has been overhauled. Cleaner, faster and more productive. NO MORE MID FADE FLICKER?
-//                - Collision detection has been implemented, not sure if it works, will need to check further.
-
-#include <Adafruit_NeoPixel.h>  //  Neopixel library
-//#include <avr/power.h>        //  Not sure why this is here, lol
-#include <Encoder.h>            //  Rotary encoder library.
-
-
-#define PIN            6        //  Which pin on the Arduino is connected to the NeoPixels
-
-
-#define NUMPIXELS      37      //  Highest pixel location.
-#define LOWPIXELS      0       //  Lowest pixel location This was helpful in prototyping because I could use a long strip of lights and only address the last few and stick them in the salt crystal.
-
-
-
-// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
-// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest
-// example for more information on possible values.
-Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
-
-Encoder myEnc(2, 3);                                //  Encoder function variables
-
-//--------------------------------------------------//  TIMER STUFF
-
-
-/* These are from Blink without Delay
-Shows another way to execute delays. */
-unsigned long previousMillis = 0;
-unsigned long lastbolt = 0;
-unsigned long interval = 60;
-int maxb;
-
-
-int butpin = 5;                                     //  integer to store button pin
-int butval;                                         //  Button digital read variable
-int butsel = 1;                                     //  Button mode selection variable.
-int butbounce;                                      //  button debounce
-int rcount;                                         //  Counter for red
-int gcount;                                         //  Counter for green
-int bcount;                                         //  Counter for blue
-int rval;                                           //  int stores red brightness
-int gval;                                           //  int stores green brightness
-int bval;                                           //  int stores blue brightness
-int rgo;                                            //  red go int, 0 for off, 1 for upwards, 2 for downwards
-int ggo;                                            //  green go int, 0 for off, 1 for upwards, 2 for downwards
-int bgo;                                            //  blue go int, 0 for off, 1 for upwards, 2 for downwards
-int magicnumber;                                    //  magic number determines when to fire colours
-int supbright;
-int interntimer;
-
-//--------------------------------------------------//  The following values are for the "Shimmer" routine
-int PixRay[NUMPIXELS][7];
-long oldPosition  = 255;                            //  integer to store encoder value
-int firstrun = 0;                                   //  array to write first run values to pixels
-int randosparkle =0;                                //  integer to hold the random number value
-
-//--------------------------------------------------// LIGHTNING
-int boltgo[8];
-int boltloc[8];
-int boltbright[8];
-int boltupdn[8];
-int boltready[8];
-
-void setup() {                                      //-----------------------------------------------(Setup)
-    pinMode(butpin, INPUT);                         //  Set buttonpin as input
- //   Serial.begin(9600);                           //  Initialize Serial Debug
-   pixels.begin();                                  //  This initializes the NeoPixel library.
-
-    for (int i=0; i <= (NUMPIXELS-1); i++){             //  set magic number for all pixray locations
-      PixRay[i][5] = {i};
-    }
-
-}
-
-void loop() {                                       //-----------------------------------------------(Main Loop)
-
-  if (firstrun == 0){
-  }
-
-  butcheck();
-
-unsigned int tnow = millis();
-
-   // some other logic here would decide when to change the LED state
-   // For this sample, just toggle every 4 seconds
-  if((tnow - previousMillis) >= interval) {
-
-      if (oldPosition > 1 && oldPosition < 255){
-        supbright = oldPosition;
-      }
-
-      if (oldPosition < 0){
-        supbright = 0;
-      }
-
-      if (oldPosition > 255){
-        supbright = 255;
-      }
-
-
-      if (butsel == 1){
-          clearscreen();
-          shimmer();
-      }
-
-      if (butsel == 2){
-          clearscreen();
-          colourfade();
-      }
-
-      if (butsel == 3){
-          clearscreen();
-      }
-
-      pixels.show();                                  // This sends the updated pixel color to the hardware.
-    previousMillis = tnow;
-}
-
-}
-
-void clearscreen(){                                 //-----------------------------------------------(clears the strip)
-    for(int i=0;i<NUMPIXELS;i++){
-        pixels.setPixelColor(i, pixels.Color(0,0,0));
-    }
-}
-
-void butcheck(){                                    //-----------------------------------------------(Button Check Function)
-
-
-
-    long newPosition = myEnc.read();
-    if (newPosition != oldPosition) {
-
-
-    if (newPosition >= 100){
-      myEnc.write(100);
-    }
-    if (newPosition < 0){
-      myEnc.write(0);
-    }
-        oldPosition = newPosition;
-       // Serial.println(newPosition);
-    }
-
-    interval = map(newPosition, 0, 100, 80, 0);
-    maxb = map(newPosition, 0, 100, 0, 255);
-
-    pinMode(butpin, INPUT);
-    butval = digitalRead(butpin);                   // check button pin for a high
-
-
-
-    if (butval == HIGH){                            // if high signal read add one to the button selection variable
-      butbounce = 1;
-    }
-
-    if (butbounce == 1 && butval == LOW){
-     butsel = butsel + 1;
-     butbounce = 0;
-    }
-
-    if (butsel > 2){                               //  resets the button value variable. I use this method so I can add more modes if I want later.
-    butsel = 1;
-    }
-}
-
-void colourfade(){                                  //-----------------------------------------------(Colour Fade Function)
-
-    magicnumber = random(0,30);                     //creates a magic number
-
-    if (magicnumber == 3 && rgo == 0){              //checks to see if magic number has selected red and red is not currently firing
-      rgo = 1;                                      //sets the red go bit to 1 meaning positive alternation
-    }
-
-    if (magicnumber == 10 && ggo == 0){              //checks to see if magic number has selected green
-      ggo = 1;
-    }
-
-    if (magicnumber == 20 && bgo == 0){             //checks to see if magic number has selected blue
-      bgo = 1;
-    }
-
-
-    // ---------------------------------------------// Write Red
-
-    if (rgo == 1){                                  // checks for ascent stage bit, adds one to red brightness
-      rval = rval + 1;
-    }
-
-    if (rgo == 2){                                  // checks for descent stage bit, subtracts one from brightness
-      rval = rval - 1;
-    }
-
-    if (rval >= maxb){                               // sets red bit to 2 meaning negative alternation
-      rgo = 2;
-    }
-
-    if (rval == 0 && rgo == 2){                     // when counter runs out and go bit is 2, reset everything.
-      rgo = 0;
-      rval = 0;
-    }
-
-    // ---------------------------------------------// Write Blue
-
-    if (bgo == 1){                                  // checks for ascent stage bit, adds one to blue brightness
-      bval = bval + 1;
-    }
-
-    if (bgo == 2){                                  // checks for descent stage bit, subtracts one from brightness
-      bval = bval - 1;
-    }
-
-    if (bval >= maxb){
-      bgo = 2;
-    }
-
-    if (bval == 0 && bgo == 2){
-      bgo = 0;
-      bval = 0;
-    }
-
-    // ---------------------------------------------// Write Green
-
-    if (ggo == 1){                                  // checks for ascent stage bit, adds one to green brightness
-      gval = gval + 1;
-    }
-
-    if (ggo == 2){                                  // checks for descent stage bit, subtracts one from brightness
-      gval = gval - 1;
-    }
-
-    if (gval >= maxb){
-      ggo = 2;
-    }
-
-    if (gval == 0 && ggo == 2){
-      ggo = 0;
-      gval = 0;
-    }
-
-
-
-
-    for(int i=LOWPIXELS;i<NUMPIXELS;i++){
-        pixels.setPixelColor(i, pixels.Color(rval,gval,bval));
-    }
-
-
-}
-
-void shimmer() {                                    //-----------------------------------------------(Shimmer Function)
-
-
-     randosparkle = random(0,(NUMPIXELS*10));                   //picks a random number
-
-
-
-    for (int i=0; i <= (NUMPIXELS-1); i++){                     //For loop to check random number against magic numbers and set the pixel for activation
-      if (PixRay[i][5] == randosparkle && PixRay[i][0] == 0){
-        PixRay[i][0] = 1;
-        PixRay[i][1] = random(0,3);
-      }
-    }
-
-//    unsigned int tnow = millis();
-
- //   if((tnow - previousMillis) >= interval) {
-      for (int i=0; i <= (NUMPIXELS-1); i++){                     //For loop to activate a pixel
-          if (PixRay[i][0] == 1){
-              drawPixel(i);
-          }
-      }
-//      previousMillis = tnow;
-//    }
-}
-
-void drawPixel(int pixelv){              //-----------------------------------------------(Red Pixel Draw Function)
-
-
-
-    if (PixRay[pixelv][4] == 0){                      //check if counter is within envelope
-        PixRay[pixelv][2] = PixRay[pixelv][2] + 1;
-    }
-
-    if (PixRay[pixelv][4] == 1){                      //check if counter is within envelope
-        PixRay[pixelv][2] = PixRay[pixelv][2] - 1;
-    }
-
-    if (PixRay[pixelv][2] >= maxb){                    //check if counter is within second half of fade
-      PixRay[pixelv][4] = 1;
-      PixRay[pixelv][2] = maxb;
-    }
-
-    if (PixRay[pixelv][1] == 0){
-      pixels.setPixelColor(pixelv, pixels.Color(PixRay[pixelv][2],0,0));
-    }
-
-    if (PixRay[pixelv][1] == 1){
-      pixels.setPixelColor(pixelv, pixels.Color(0,PixRay[pixelv][2],0));
-    }
-
-    if (PixRay[pixelv][1] == 2){
-      pixels.setPixelColor(pixelv, pixels.Color(0,0,PixRay[pixelv][2]));
-    }
-
-
-    if (PixRay[pixelv][2] <= 0 && PixRay[pixelv][4] == 1){               //check if counter is done alternation
-       pixels.setPixelColor(pixelv, pixels.Color(0,0,0));                //turn selected pixel off
-       PixRay[pixelv][2] = 0;                                            //set brightness to zero
-       PixRay[pixelv][0] = 0;                                            //deactivate pixel activate bit
-       PixRay[pixelv][4] = 0;                                            //reset counter
-    }
-
-}
-
-


Integrating keypad into GUI

Integrating keypad into GUI

--- PixelVFO.ino
+++ PixelVFO.ino
@@ -52,10 +52,19 @@
 #define TFT_CS      10
 Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

+// constants for main screen layout
+#define NUM_F_CHAR            8     // number digits in frequency display
+#define CHAR_WIDTH            27    // width of each frequency digit
+#define DEPTH_FREQ_DISPLAY    50    // depth of frequency display bar
+#define FREQ_OFFSET_Y         40    // offset from top of frequency digits
+#define FREQ_OFFSET_X         40    // offset from left of frequency digits
+#define MHZ_OFFSET_X          257   // offset from left of the 'Hz' units
+
 // display constants - offsets, colours, etc
-#define FONT_BUTTON         (&FreeSansBold12pt7b)
-#define FONT_FREQ           (&FreeSansBold24pt7b)
-
+#define FONT_FREQ           (&FreeSansBold24pt7b) // font for frequency display
+#define FONT_BUTTON         (&FreeSansBold12pt7b) // font for button labels
+
+// various colours
 #define ILI9341_LIGHTGREY   0xC618      /* 192, 192, 192 */
 #define ILI9341_DARKGREY    0x7BEF      /* 128, 128, 128 */

@@ -67,11 +76,6 @@
 #define FREQ_BG             ILI9341_WHITE
 #define FREQ_SEL_BG         ILI9341_GREEN
 #define BOTTOM_BG           ILI9341_WHITE
-
-// touchscreen stuff
-int ts_rotation = 0;
-int ts_width = SCREEN_WIDTH;
-int ts_height = SCREEN_HEIGHT;

 // ONLINE button definitions
 #define BUTTON_RADIUS       5
@@ -96,6 +100,11 @@
 #define MENU_BG2            ILI9341_BLACK
 #define MENU_FG             ILI9341_BLACK

+// touchscreen stuff
+int ts_rotation = 0;
+int ts_width = SCREEN_WIDTH;
+int ts_height = SCREEN_HEIGHT;
+
 // the VFO states
 enum VFOState
 {
@@ -110,7 +119,7 @@
 uint16_t char_x_offset[NUM_F_CHAR + 1]; // x offset for start/end of each character on display

 // index of selected digit in frequency display
-int sel_digit = -1;
+int freq_digit_select = -1;

 uint32_t msraw = 0x80000000;
 #define MIN_REPEAT_PERIOD   100
@@ -154,117 +163,9 @@
   event_push(event_Down, last_x, last_y);
 }

-//-----------------------------------------------
-// Fills the frequency char buffer from a given frequency.
-//
-//     buff  address of char buffer to fill
-//     freq  the frequency to put into the buffer
-//
-// Fills the buffer from the left with MSB first.
-//-----------------------------------------------
-
-void freq_to_buff(char *buff, unsigned long freq)
-{
-  int rem;
-
-  for (int i = NUM_F_CHAR - 1; i >= 0; --i)
-  {
-    rem = freq % 10;
-    freq = freq / 10;
-    buff[i] = '0' + rem;
-  }
-}
-
-//-----------------------------------------------
-// Draw the 'thousands' markers
-//-----------------------------------------------
-
-void draw_thousands(void)
-{
-  tft.fillRect(FREQ_OFFSET_X+CHAR_WIDTH*2, 44, 2, 6, FREQ_FG);
-  tft.fillRect(FREQ_OFFSET_X+CHAR_WIDTH*5, 44, 2, 6, FREQ_FG);
-}
-
-//-----------------------------------------------
-// Routines to draw GUI components on the screen
-//-----------------------------------------------
-
-void drawOnline(void)
-{
-  if (vfo_state == VFO_Standby)
-  {
-    tft.fillRoundRect(ONLINE_X, ONLINE_Y, ONLINE_WIDTH, ONLINE_HEIGHT, BUTTON_RADIUS, STANDBY_BG2);
-    tft.fillRoundRect(ONLINE_X+1, ONLINE_Y+1, ONLINE_WIDTH-2, ONLINE_HEIGHT-2, BUTTON_RADIUS, STANDBY_BG);
-    tft.setCursor(ONLINE_X + 7, SCREEN_HEIGHT - 10);
-    tft.setFont(FONT_BUTTON);
-    tft.setTextColor(STANDBY_FG);
-    tft.print("Standby");
-  }
-  else
-  {
-    tft.fillRoundRect(ONLINE_X, ONLINE_Y, ONLINE_WIDTH, ONLINE_HEIGHT, BUTTON_RADIUS, ONLINE_BG2);
-    tft.fillRoundRect(ONLINE_X+1, ONLINE_Y+1, ONLINE_WIDTH-2, ONLINE_HEIGHT-2, BUTTON_RADIUS, ONLINE_BG);
-    tft.setCursor(ONLINE_X + 7, SCREEN_HEIGHT - 10);
-    tft.setFont(FONT_BUTTON);
-    tft.setTextColor(ONLINE_FG);
-    tft.print("ONLINE");
-  }
-}
-
-void drawMenu(void)
-{
-  tft.fillRoundRect(MENU_X, MENU_Y, MENU_WIDTH, MENU_HEIGHT, BUTTON_RADIUS, MENU_BG2);
-  tft.fillRoundRect(MENU_X+1, MENU_Y+1, MENU_WIDTH-2, MENU_HEIGHT-2, BUTTON_RADIUS, MENU_BG);
-  tft.setCursor(MENU_X + 22, SCREEN_HEIGHT - 10);
-  tft.setFont(FONT_BUTTON);
-  tft.setTextColor(MENU_FG);
-  tft.print("Menu");
-}
-
-void draw_screen(void)
-{
-  tft.setFont(FONT_FREQ);
-
-  // start drawing things that don't change
-  tft.fillRect(0, DEPTH_FREQ_DISPLAY, tft.width(), SCREEN_HEIGHT-DEPTH_FREQ_DISPLAY, SCREEN_BG2);
-  tft.setTextWrap(false);
-  tft.fillRoundRect(0, 0, tft.width(), DEPTH_FREQ_DISPLAY, 5, FREQ_BG);
-  tft.setCursor(MHZ_OFFSET_X, FREQ_OFFSET_Y);
-  tft.setTextColor(FREQ_FG);
-  tft.print("Hz");
-
-  drawOnline();
-  drawMenu();
-}
-
-//-----------------------------------------------
-// Get touch information, if anyu.
-//     x, y  pointers to cells to receive X and Y position
-// Returns 'true' if touch found - X and Y cells updated.
-// Returns 'false' if no touch - X and Y cells NOT updated.
-//-----------------------------------------------
-bool ts_read(int *x, int *y)
-{
-  // See if there's any touch data for us
-  if (ts.bufferEmpty())
-  {
-    return false;
-  }
-
-  // Retrieve a point
-  TS_Point p = ts.getPoint();
-
-  if (p.z < 100)
-  {
-    return false;
-  }
-
-  // Scale from ~0->4000 to tft.width using the calibration #'s
-  *x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
-  *y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
-
-  return true;
-}
+//////////////////////////////////////////////////////////////////////////////
+// Code to handle the 'frequency' widget at screen top
+//////////////////////////////////////////////////////////////////////////////

 //-----------------------------------------------
 // Draw the frequency byte buffer to the screen.
@@ -272,7 +173,7 @@
 // Updates all digits on the screen.  Skips leading zeros.
 //-----------------------------------------------

-void display_frequency(int select=-1)
+void freq_show(int select=-1)
 {
   bool leading_space = true;

@@ -291,6 +192,172 @@
       leading_space = false;
     }
   }
+}
+
+//-----------------------------------------------
+// Set a digit of the frequency display.
+//     offset     offset into the frequency digits buffer
+//     new_digit  new digit, binary [0-9]
+// Also updates the top of screen display.
+//-----------------------------------------------
+
+void freq_set_digit(int offset, int new_digit)
+{
+  Serial.printf("freq_set_digit: offset=%d, new_digit=%d\n", offset, new_digit);
+  freq_display[offset] = new_digit;
+  tft.setFont(FONT_FREQ);
+  tft.drawChar(char_x_offset[offset], FREQ_OFFSET_Y,
+               freq_display[offset], FREQ_FG, FREQ_BG, 1);
+}
+
+//-----------------------------------------------
+// Draw a selected digit in the frequency display.
+//     select  index of digit to highlight
+//-----------------------------------------------
+
+void freq_select(int select)
+{
+  tft.fillRect(char_x_offset[select]-1, 2,
+               CHAR_WIDTH+1, DEPTH_FREQ_DISPLAY-4, FREQ_SEL_BG);
+  tft.setFont(FONT_FREQ);
+  tft.drawChar(char_x_offset[select], FREQ_OFFSET_Y,
+               freq_display[select], FREQ_FG, FREQ_BG, 1);
+}
+
+//-----------------------------------------------
+// Unselect a digit in the frequency display.
+//     select  index of digit to unselect
+//-----------------------------------------------
+
+void freq_unselect(int select)
+{
+  Serial.printf("freq_unselect: select=%d\n", select);
+  tft.fillRect(char_x_offset[select]-1, 2,
+               CHAR_WIDTH+1, DEPTH_FREQ_DISPLAY-4, FREQ_BG);
+  tft.setFont(FONT_FREQ);
+  tft.drawChar(char_x_offset[select], FREQ_OFFSET_Y,
+               freq_display[select], FREQ_FG, FREQ_BG, 1);
+}
+
+//-----------------------------------------------
+// Fills the frequency char buffer from a given frequency.
+//
+//     buff  address of char buffer to fill
+//     freq  the frequency to put into the buffer
+//
+// Fills the buffer from the left with MSB first.
+//-----------------------------------------------
+
+void freq_to_buff(char *buff, unsigned long freq)
+{
+  int rem;
+
+  for (int i = NUM_F_CHAR - 1; i >= 0; --i)
+  {
+    rem = freq % 10;
+    freq = freq / 10;
+    buff[i] = '0' + rem;
+  }
+}
+
+//-----------------------------------------------
+// Draw the frequency 'thousands' markers
+//-----------------------------------------------
+
+void draw_thousands(void)
+{
+  tft.fillRect(FREQ_OFFSET_X+CHAR_WIDTH*2, 44, 2, 6, FREQ_FG);
+  tft.fillRect(FREQ_OFFSET_X+CHAR_WIDTH*5, 44, 2, 6, FREQ_FG);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Code to handle the 'online' and 'menu' buttons.
+//////////////////////////////////////////////////////////////////////////////
+
+//-----------------------------------------------
+// Draw the ONLINE/standby button.
+// Uses global 'vfo_state' to determine button text.
+//-----------------------------------------------
+
+void drawOnline(void)
+{
+  if (vfo_state == VFO_Standby)
+  {
+    tft.fillRoundRect(ONLINE_X, ONLINE_Y, ONLINE_WIDTH, ONLINE_HEIGHT, BUTTON_RADIUS, STANDBY_BG2);
+    tft.fillRoundRect(ONLINE_X+1, ONLINE_Y+1, ONLINE_WIDTH-2, ONLINE_HEIGHT-2, BUTTON_RADIUS, STANDBY_BG);
+    tft.setCursor(ONLINE_X + 7, SCREEN_HEIGHT - 10);
+    tft.setFont(FONT_BUTTON);
+    tft.setTextColor(STANDBY_FG);
+    tft.print("Standby");
+  }
+  else
+  {
+    tft.fillRoundRect(ONLINE_X, ONLINE_Y, ONLINE_WIDTH, ONLINE_HEIGHT, BUTTON_RADIUS, ONLINE_BG2);
+    tft.fillRoundRect(ONLINE_X+1, ONLINE_Y+1, ONLINE_WIDTH-2, ONLINE_HEIGHT-2, BUTTON_RADIUS, ONLINE_BG);
+    tft.setCursor(ONLINE_X + 7, SCREEN_HEIGHT - 10);
+    tft.setFont(FONT_BUTTON);
+    tft.setTextColor(ONLINE_FG);
+    tft.print("ONLINE");
+  }
+}
+
+//-----------------------------------------------
+// Draw the Menu button.
+//-----------------------------------------------
+
+void drawMenu(void)
+{
+  tft.fillRoundRect(MENU_X, MENU_Y, MENU_WIDTH, MENU_HEIGHT, BUTTON_RADIUS, MENU_BG2);
+  tft.fillRoundRect(MENU_X+1, MENU_Y+1, MENU_WIDTH-2, MENU_HEIGHT-2, BUTTON_RADIUS, MENU_BG);
+  tft.setCursor(MENU_X + 22, SCREEN_HEIGHT - 10);
+  tft.setFont(FONT_BUTTON);
+  tft.setTextColor(MENU_FG);
+  tft.print("Menu");
+}
+
+void draw_screen(void)
+{
+  tft.setFont(FONT_FREQ);
+
+  // start drawing things that don't change
+  tft.fillRect(0, DEPTH_FREQ_DISPLAY, tft.width(), SCREEN_HEIGHT-DEPTH_FREQ_DISPLAY, SCREEN_BG2);
+  tft.setTextWrap(false);
+  tft.fillRoundRect(0, 0, tft.width(), DEPTH_FREQ_DISPLAY, 5, FREQ_BG);
+  tft.setCursor(MHZ_OFFSET_X, FREQ_OFFSET_Y);
+  tft.setTextColor(FREQ_FG);
+  tft.print("Hz");
+
+  drawOnline();
+  drawMenu();
+}
+
+//-----------------------------------------------
+// Get touch information, if anyu.
+//     x, y  pointers to cells to receive X and Y position
+// Returns 'true' if touch found - X and Y cells updated.
+// Returns 'false' if no touch - X and Y cells NOT updated.
+//-----------------------------------------------
+bool ts_read(int *x, int *y)
+{
+  // See if there's any touch data for us
+  if (ts.bufferEmpty())
+  {
+    return false;
+  }
+
+  // Retrieve a point
+  TS_Point p = ts.getPoint();
+
+  if (p.z < 100)
+  {
+    return false;
+  }
+
+  // Scale from ~0->4000 to tft.width using the calibration #'s
+  *x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
+  *y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
+
+  return true;
 }

 // main screen HotSpot definitions
@@ -316,6 +383,7 @@

 bool freq_hs_handler(HotSpot *hs_ptr)
 {
+  freq_digit_select = hs_ptr->arg;
   keypad_show(hs_ptr->arg);
   return true;
 }
@@ -356,9 +424,22 @@

 char keypad_chars[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};

+//-----------------------------------------------
+// User pressed keypad button.
+//     hs  address of hotspot data object
+// Update the frequency display.
+//-----------------------------------------------
+
 bool keypad_handler(HotSpot *hs)
 {
   Serial.printf("keypad_handler: called, arg=%d\n", hs->arg);
+
+  freq_unselect(freq_digit_select);
+  freq_set_digit(freq_digit_select, hs->arg);
+  if (freq_digit_select < NUM_F_CHAR)
+    freq_digit_select += 1;
+  freq_select(freq_digit_select);
+
   return false;
 }

@@ -415,6 +496,7 @@

 void keypad_button_draw(char ch, int x, int y)
 {
+  // draw the keypad button
   tft.drawRoundRect(KEYPAD_X+KEYPAD_MARGIN+(KEYPAD_MARGIN+KEYPAD_BUTTON_W)*x,
                     KEYPAD_Y+KEYPAD_MARGIN+(KEYPAD_MARGIN+KEYPAD_BUTTON_H)*y,
                     KEYPAD_BUTTON_H, KEYPAD_BUTTON_H,
@@ -429,6 +511,7 @@
   tft.setTextColor(STANDBY_FG);
   tft.print(ch);

+  // fill in the X & Y position in the hotspot data
   hs_keypad[y*3 + x].x = KEYPAD_X+KEYPAD_MARGIN+(KEYPAD_MARGIN+KEYPAD_BUTTON_W)*x;
   hs_keypad[y*3 + x].y = KEYPAD_Y+KEYPAD_MARGIN+(KEYPAD_MARGIN+KEYPAD_BUTTON_H)*y;
 }
@@ -441,7 +524,7 @@
 void keypad_show(int offset)
 {
   // highlight the frequency digit we are changing
-  display_frequency(offset);
+  freq_select(offset);

   // draw keypad basic outline
   tft.fillRoundRect(KEYPAD_X, KEYPAD_Y, KEYPAD_W, KEYPAD_H, BUTTON_RADIUS, ILI9341_BLACK);
@@ -524,7 +607,7 @@
 #endif

   // show the frequency
-  display_frequency();
+  freq_show();
 }

 //-----------------------------------------------
@@ -546,7 +629,7 @@
         {
           Serial.printf("hs_handletouch() returned 'true', refreshing display\n");
           draw_screen();
-          display_frequency();
+          freq_show();
           event_flush();
         }
         break;


created a simple program to control the stepper motors via the serial port of the arduino

--- executer/executer.ino
+++ executer/executer.ino
@@ -1,9 +1,97 @@
+short steppers[][5] = {
+  //{STEP, DIR, EN, +5V, STEPS/REV}
+  {30, 32, 34, 36, 200}, //Left
+  {31, 33, 35, 37, 200}, //Back
+  {38, 40, 42, 44, 200}, //Front
+  {39, 41, 43, 45, 200}, //Top
+  {46, 48, 50, 52, 200}, //Bottom
+  {47, 49, 51, 53, 200}  //Right
+};
+
+char commands[32];
+
+int steps_per_quarter_turn = 100;
+
+char get_nybble(char* arr, int i) {
+  if (i%2==0)
+    return arr[i]>>4;
+  else
+    return arr[i]%16;
+}
+
+char get_cmd_stepper_index(char cmd) {
+  return cmd%8;
+}
+
+char get_cmd_direction(char cmd) {
+  return cmd>>3;
+}
+
+void enable_stepper(short* stepper) {
+  pinMode(stepper[0], OUTPUT);
+  pinMode(stepper[1], OUTPUT);
+  pinMode(stepper[2], OUTPUT);
+  pinMode(stepper[3], OUTPUT);
+
+  digitalWrite(stepper[2], HIGH);
+  digitalWrite(stepper[3], HIGH);
+}
+
+void step_stepper(short* stepper, int steps, int d) {
+  digitalWrite(stepper[1], ((steps < 0)?HIGH:LOW));
+  for (int i = 0; i < abs(steps); i++) {
+    digitalWrite(stepper[0],HIGH);
+    delayMicroseconds(d);
+    digitalWrite(stepper[0],LOW);
+    delayMicroseconds(d);
+  }
+}
+
 void setup() {
-  // put your setup code here, to run once:
-
+  for (int i = 0; i < 6; i++) {
+    enable_stepper(steppers[i]);
+  }
+  Serial.begin(9600);
 }

 void loop() {
-  // put your main code here, to run repeatedly:
-
+  int n;
+  if (n=Serial.available()) {
+    char buf[2];
+
+    Serial.readBytes(buf,2);
+    char command = buf[0];
+    char dir = buf[1];
+
+    Serial.print(command);
+    Serial.println(dir);
+
+    int stepper_i = -1;
+    switch (command) {
+      case 'f'://front
+        stepper_i = 2;
+        break;
+      case 't'://top
+        stepper_i = 3;
+        break;
+      case 'l'://left
+        stepper_i = 0;
+        break;
+      case 'r'://right
+        stepper_i = 5;
+        break;
+      case 'b'://back
+        stepper_i = 1;
+        break;
+      case 'B'://bottom
+        stepper_i = 4;
+        break;
+      default:
+        break;
+    }
+
+    if (stepper_i != -1) {
+      step_stepper(steppers[stepper_i], ((dir=='+')?1:-1)*100, 250);
+    }
+  }
 }