Delete So_Simple_Decoder.ino

Delete So_Simple_Decoder.ino

Удален за ненадобностью.

--- temp/So_Simple_Decoder.ino
+++ temp/So_Simple_Decoder.ino
@@ -1,255 +0,0 @@
-#include <AltSoftSerial.h>
-
-AltSoftSerial mySerial;
-int c = 0;
-uint8_t message[60];
-uint8_t CK_A = 0, CK_B = 0;
-uint8_t CK_AU = 0, CK_BU = 0;
-int gpsStep = 0;
-uint8_t UBX_id = 0;
-uint8_t UBX_class = 0;
-uint8_t meslenL = 0;
-uint8_t meslenH = 0;
-int16_t meslen = 0;
-int count = 0;
-boolean gotUBX = false;
-boolean POSLLH = 0;
-boolean SVINFO = 0;
-boolean SOL = 0;
-boolean VELNED = 0;
-char GPSdata[40];
-long int longitude;
-float longitudef;
-long int latitude;
-float latitudef;
-long int height;
-float heightf;
-long int speed3;
-float speed3f;
-short int FixType;
-short int NumSV;
-
-void ubx_checksum(byte ubx_data) //рассчет контрольной суммы
-{
-  CK_A += ubx_data;
-  CK_B += CK_A;
-}
-
-void getUBX(void) //Получаем пакет и делаем с ним штуки
-{
-  if (Serial.available())
-  {
-    uint8_t c = Serial.read();
-    switch (gpsStep)
-    {
-      case 0:
-        {
-          if (c == 0xB5){
-            gpsStep++;
-   //         mySerial.print("0");
-          }
-          break;
-        }
-      case 1:
-        {
-          if (c == 0x62){
-            gpsStep++;
-  //          mySerial.print("1");
-          }
-          else{
-            gpsStep = 0;
-    //        mySerial.println("not62");
-          }
-          break;
-        }
-      case 2:
-        {
-          UBX_class = c;
-          ubx_checksum(c);
-          gpsStep++;
-    //        mySerial.print("2");
-          break;
-        }
-      case 3:
-        {
-          UBX_id = c;
-          ubx_checksum(c);
-          gpsStep++;
-   //         mySerial.print("3");
-          break;
-        }
-      case 4:
-        {
-          meslenL = c;
-          ubx_checksum(c);
-          gpsStep++;
- //           mySerial.print("ml");
-          break;
-        }
-      case 5:
-        {
-          meslenH = c;
-          ubx_checksum(c);
-          gpsStep++;
-          meslen = 0xFF & meslenL;
-          meslen |= meslenH << 8;
-          count = 0;
-  //          mySerial.print("mh");
-          break;
-        }
-      case 6:
-        {
-          message[count] = c;
-          ubx_checksum(c);
-          count++;
-          if (count == meslen)
-          {
-            gpsStep++;
-            count = 0;
-          }
-          break;
-        }
-      case 7:
-        {
-          CK_AU = c;
-          gpsStep++;
-          break;
-        }
-      case 8:
-        {
-          CK_BU = c;
-          if (CK_A == CK_AU && CK_B == CK_BU) //сравнение контрольной суммы
-          {
-            gotUBX = true;
-          }
-      //    clearVars();
-          break;
-        }
-    }
-  }
-}
-
-void decodeUBX(void)
-{
-  if (UBX_class == 0x01)
-  {
-    switch (UBX_id)
-    {
-      case 0x02:  //NAV-POSLLH
-        {
-          longitude = 0xFF & message[7];       //долгота
-          longitude = longitude << 8;
-          longitude |= message[6];
-          longitude = longitude << 8;
-          longitude |= message[5];
-          longitude = longitude << 8;
-          longitude |= message[4];
-          longitudef = longitude / 10000000.0;
-
-          latitude = 0xFF & message[11];       //широта
-          latitude = latitude << 8;
-          latitude |= message[10];
-          latitude = latitude << 8;
-          latitude |= message[9];
-          latitude = latitude << 8;
-          latitude |= message[8];
-          latitudef = latitude / 10000000.0;
-
-          height = 0xFF & message[19];         //высота
-          height = height << 8;
-          height |= message[18];
-          height = height << 8;
-          height |= message[17];
-          height = height << 8;
-          height |= message[16];
-          heightf = height / 1000.0;
-
-          POSLLH = true;
-          break;
-        }
-      case 0x12:  //NAV-VELNED
-        {
-          speed3 = 0xFF & message[19];        //скорость
-          speed3 = speed3 << 8;
-          speed3 |= message[18];
-          speed3 = speed3 << 8;
-          speed3 |= message[17];
-          speed3 = speed3 << 8;
-          speed3 |= message[16];
-          speed3f = speed3 / 100.0;
-
-          VELNED = true;
-          break;
-        }
-      case 0x06:  // NAV-SOL
-        {
-          NumSV = message[47];          //кол-во спутников в решении
-          FixType |= message[10];        //тип фикса
-   //     mySerial.print(message[47]);
-
-          SOL = true;
-          break;
-        }
-    }
-  }
-}
-
-void sendGPS(void)
-{
-  mySerial.print("A");
-  mySerial.print(longitudef, 5);
-  mySerial.print("  B");
-  mySerial.print(latitudef, 5);
-  mySerial.print("  C");
-  mySerial.print(heightf, 3);
-  mySerial.print("  D");
-  mySerial.print(speed3f, 3);
-  mySerial.print("  E");
-  mySerial.print(NumSV);
-  mySerial.print("  F");
-  mySerial.println(FixType);
-  longitude = 0;
-  latitude = 0;
-  height = 0;
-  speed3 = 0;
-  NumSV = 0;
-  FixType = 0;
-}
-
-void clearVars(void)
-{
-  gpsStep = 0;
-  UBX_id = 0;
-  UBX_class = 0;
-  meslen = 0;
-  count = 0;
-  CK_AU = 0;
-  CK_BU = 0;
-  CK_A = 0;
-  CK_B = 0;
-  memset(message, 0, 60);
-}
-
-void setup() {
-  Serial.begin(57600);
-  mySerial.begin(9600);
-}
-
-void loop()
-{
-  getUBX();
-  if (gotUBX == true)
-  {
-    mySerial.print("");
-    decodeUBX();
-    if (POSLLH == 1 && VELNED == 1)
-    {
-      sendGPS();
-      POSLLH = 0;
-      VELNED = 0;
-      SOL = 0;
-    }
-    clearVars();
-    gotUBX = false;
-  }
-}


ARDIN-2-HW-assert-handling ble_modify_setup_data

--- libraries/BLE/examples/ble_modify_setup_data/ble_modify_setup_data.ino
+++ libraries/BLE/examples/ble_modify_setup_data/ble_modify_setup_data.ino
@@ -273,8 +273,15 @@
               Serial.println(F("Evt Device Started: Standby"));
               //Looking for an iPhone by sending radio advertisements
               //When an iPhone connects to us we will get an ACI_EVT_CONNECTED event from the nRF8001
+              if (aci_evt->params.device_started.hw_error)
+              {
+                delay(20); //Magic number used to make sure the HW error event is handled correctly.
+              }
+              else
+              {
               lib_aci_connect(180/* in seconds */, 0x0050 /* advertising interval 50ms*/);
               Serial.println(F("Advertising started"));
+              }
               break;
           }
         }
@@ -388,6 +395,18 @@
         {
           aci_state.data_credit_available++;
         }
+        break;
+      case ACI_EVT_HW_ERROR:
+        Serial.println(F("HW error: "));
+        Serial.println(aci_evt->params.hw_error.line_num, DEC);
+
+        for(uint8_t counter = 0; counter <= (aci_evt->len - 3); counter++)
+        {
+          Serial.write(aci_evt->params.hw_error.file_name[counter]); //uint8_t file_name[20];
+        }
+        Serial.println();
+        lib_aci_connect(30/* in seconds */, 0x0100 /* advertising interval 100ms*/);
+        Serial.println(F("Advertising started"));
         break;

     }


Cleanup debugging and reimplement middle button

--- mouse_rat.ino
+++ mouse_rat.ino
@@ -23,16 +23,20 @@
       accelMin = -20,
       // Map inputs to this range (pixels)
       outMin   =  50,
-      outMax   = -50;
+      outMax   = -50,
+      // How many milliseconds between polling the accelerometer
+      delayRate = 7;
+
+const boolean DEBUG = true;

 int calibrationCounter = 0;

 float xRange[] = {0,0};
 float yRange[] = {0,0};

-const int MOUSE_LEFT_PIN = 8,
-          MOUSE_RIGHT_PIN = 6;
-//          MOUSE_MID_PIN   = 6;
+const int MOUSE_LEFT_PIN = 10,
+          MOUSE_RIGHT_PIN = 6,
+          MOUSE_MID_PIN   = 8;

 uint16_t lasttouched = 0,
          currtouched = 0;
@@ -61,7 +65,7 @@

 void setup(void) {
-  Serial.begin(9600);
+  if (DEBUG) Serial.begin(9600);

   dof_setup();
   mpr_setup();
@@ -77,12 +81,12 @@
 void mpr_setup() {
   // needed to keep leonardo/micro from starting too fast!
   while (!Serial);
-  Serial.begin(9600);    Serial.println("Adafruit MPR121 Capacitive Touch sensor test");
+  if (DEBUG) Serial.begin(9600); Serial.println("Adafruit MPR121 Capacitive Touch sensor test");

   // Default address is 0x5A, if tied to 3.3V its 0x5B
   // If tied to SDA its 0x5C and if SCL then 0x5D
-  if (!cap.begin(0x5A))  Serial.println("MPR121 not found");
-  else                   Serial.println("MPR121 found!");
+  if (!cap.begin(0x5A))  if (DEBUG) Serial.println("MPR121 not found");
+  else                   if (DEBUG) Serial.println("MPR121 found!");
 }

@@ -125,7 +129,7 @@
     calibrationCounter++;
     calibrate(accel.acceleration.x, accel.acceleration.y);
   }
-  delay(7);
+  delay(delayRate);
 }

@@ -158,9 +162,11 @@

   xNormal = (xRange[0] + xRange[1])/2;
   yNormal = (yRange[0] + yRange[1])/2;
-
-  Serial.print(xRange[0]); Serial.print(", "); Serial.println(xRange[1]);
-  Serial.print(yRange[0]); Serial.print(", "); Serial.println(yRange[1]);
+
+  if (DEBUG) {
+    Serial.print("X Min: "); Serial.print(xRange[0]); Serial.print(", Max: "); Serial.println(xRange[1]);
+    Serial.print("Y Min: "); Serial.print(yRange[0]); Serial.print(", Max: "); Serial.println(yRange[1]);
+  }
 }

@@ -168,27 +174,34 @@

   switch(id) {
     case MOUSE_LEFT_PIN:
-      Serial.println("Left button touched"); Serial.println("");
+      if (DEBUG) Serial.println("Left button touched"); Serial.println("");
       Mouse.press(MOUSE_LEFT);
       break;
-//    case MOUSE_MID_PIN:
-//      Mouse.press(MOUSE_MIDDLE);
-//      break;
+    case MOUSE_MID_PIN:
+      if (DEBUG) Serial.println("Middle button touched"); Serial.println("");
+      Mouse.press(MOUSE_MIDDLE);
+      break;
     case MOUSE_RIGHT_PIN:
+      if (DEBUG) Serial.println("Right button touched"); Serial.println("");
+      Mouse.press(MOUSE_RIGHT);
+      break;
+  }
+}
+

 void releaseHandler(int id) {
-  //Serial.print(id); Serial.println(" released");

   switch(id) {
     case MOUSE_LEFT_PIN:
+      if (DEBUG) Serial.println("Left button released"); Serial.println("");
       Mouse.release(MOUSE_LEFT);
-      Serial.println("Left button released"); Serial.println("");
-      break;
-//    case MOUSE_MID_PIN:
-//      Mouse.release(MOUSE_MIDDLE);
-//      break;
+      break;
+    case MOUSE_MID_PIN:
+      if (DEBUG) Serial.println("Middle button released"); Serial.println("");
+      Mouse.release(MOUSE_MIDDLE);
+      break;
     case MOUSE_RIGHT_PIN:
-      Serial.println("Right button released"); Serial.println("");
+      if (DEBUG) Serial.println("Right button released"); Serial.println("");
       Mouse.release(MOUSE_RIGHT);
       break;
   }
@@ -200,19 +213,20 @@
 }

-void displaySensorDetails(void) {
+void displaySensorDetails(int delayAmt) {
   sensor_t accel, mag, gyro, temp;
   lsm.getSensor(&accel, &mag, &gyro, &temp);

-  Serial.println(F("------------------------------------"));
-  Serial.print  (F("Sensor:       ")); Serial.println(accel.name);
-  Serial.print  (F("Driver Ver:   ")); Serial.println(accel.version);
-  Serial.print  (F("Unique ID:    ")); Serial.println(accel.sensor_id);
-  Serial.print  (F("Max Value:    ")); Serial.print(accel.max_value); Serial.println(F(" m/s^2"));
-  Serial.print  (F("Min Value:    ")); Serial.print(accel.min_value); Serial.println(F(" m/s^2"));
-  Serial.print  (F("Resolution:   ")); Serial.print(accel.resolution); Serial.println(F(" m/s^2"));
-  Serial.println(F("------------------------------------"));
-  Serial.println(F(""));
-
-  delay(500);
-}
+  if (DEBUG) {
+    Serial.println(F("------------------------------------"));
+    Serial.print  (F("Sensor:       ")); Serial.println(accel.name);
+    Serial.print  (F("Driver Ver:   ")); Serial.println(accel.version);
+    Serial.print  (F("Unique ID:    ")); Serial.println(accel.sensor_id);
+    Serial.print  (F("Max Value:    ")); Serial.print(accel.max_value); Serial.println(F(" m/s^2"));
+    Serial.print  (F("Min Value:    ")); Serial.print(accel.min_value); Serial.println(F(" m/s^2"));
+    Serial.print  (F("Resolution:   ")); Serial.print(accel.resolution); Serial.println(F(" m/s^2"));
+    Serial.println(F("------------------------------------"));
+    Serial.println(F(""));
+  }
+  delay(delayAmt);
+}


Update motor.ino

Update motor.ino

--- code/motor.ino
+++ code/motor.ino
@@ -9,29 +9,25 @@
 #define ESQUERDO 1
 #define DIREITO 2

-int In1 = 4;
-int In2 = 5;
-int In3 = 6;
-int In4 = 7;
-
-int EnA = 10;
-int EnB = 11;
-
-int VelEsq = 0;
-int VelDir = 0;
-int VelMin = 120;
-int VelMax = 245;
-
+Int
+  In1 = 4,
+  In2 = 5,
+  In3 = 6,
+  In4 = 7,
+  EnA = 10,
+  EnB = 11,
+  VelEsq = 0,
+  VelDir = 0,
+  VelMin = 120,
+  VelMax = 245;

 void Mover(int direcao, int velocidade) {
   velocidade = abs(velocidade);
   if (direcao == 1) {
-
     digitalWrite(In1, HIGH);
     digitalWrite(In2, LOW);       // Anda pra
     digitalWrite(In3, LOW);       // Frente
     digitalWrite(In4, HIGH);
-
   } else if (direcao == 2) {
     digitalWrite(In1, LOW);
     digitalWrite(In2, HIGH);      // Anda pra
@@ -47,15 +43,10 @@
     }
     analogWrite(EnA, velocidade);
     analogWrite(EnB, velocidade);
-    //Serial.print("Vmotor: ");
-    //Serial.print(velocidade);
 }
-
 void morreu() {
-
     digitalWrite(In1, HIGH);
     digitalWrite(In2, HIGH);       // FREIA TUDO
     digitalWrite(In3, HIGH);
     digitalWrite(In4, HIGH);
-
 }


Testing..

Testing..

--- module/module.ino
+++ module/module.ino
@@ -149,7 +149,7 @@
 */
 unsigned long accumulator(void) {
 	unsigned char A[bufferSize];
-	unsigned long startTime, endTime = 0;
+	unsigned long startTime = 0;
 	unsigned int periodX, periodY;
 	unsigned int lastPeriodX, lastPeriodY;
 	unsigned long periodCount, sendCount = 0;
@@ -174,11 +174,11 @@
 			if (pollCounter == pollTimeout) {
 				soundFeedback(reject);
 				Serial.print(messages.cancel);
-				endTime = (millis() - startTime)/1000;
+				sendCount = (millis() - startTime)/1000;
 				while(1) {
-					Serial.println(endTime);
+					Serial.println(sendCount);
 				}
-				return endTime;
+				return sendCount;
 			}
 		}
 		else {


TW-27: initial doc

TW-27: initial doc

--- tinywatch.ino
+++ tinywatch.ino
@@ -3,21 +3,29 @@
 #include "lib_RenderBuffer.h"
 #include "lib_StringBuffer.h"

+//Determines which version of TinyScreen we are using.
 TinyScreen display = TinyScreen(TinyScreenPlus);
+//Buffer used for drawing.
 RenderBuffer<uint8_t,20> buffer;

+//Pinouts for TinyShield BLE.
 #define BLE_REQ 10
 #define BLE_RDY 2
 #define BLE_RST 9

+//Instantiate BLE peripheral.
 BLEPeripheral blePeripheral = BLEPeripheral(BLE_REQ, BLE_RDY, BLE_RST);

+//Uniquely identifies BLE peripheral, used for advertising.
 BLEService service = BLEService("CCC0");
+//Defines behavior of BLE peripheral.
 BLECharCharacteristic characteristic = BLECharCharacteristic("CCC1", BLERead | BLENotify);
+//Description of content sent via BLE peripheral.
 BLEDescriptor desc = BLEDescriptor("2901", "value");

 void setup() {
   BLESetup();
+  //TinyScreen display setup.
   display.begin();
   display.setFlip(true);
   display.setBrightness(8);
@@ -29,22 +37,27 @@
 }

 void BLESetup(){
+  //Name of BLE peripheral when connecting to master.
   blePeripheral.setLocalName("tinywatch");

+  //Setting advertising id from service.
   blePeripheral.setAdvertisedServiceUuid(service.uuid());
+  //Adding attributes for BLE peripheral.
   blePeripheral.addAttribute(service);
   blePeripheral.addAttribute(characteristic);
   blePeripheral.addAttribute(desc);
-
+
+  //Bind events for connects and disconnects.
   blePeripheral.setEventHandler(BLEConnected, blePeripheralConnectHandler);
   blePeripheral.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);
-
+
+  //Start BLE service.
   blePeripheral.begin();
 }

 void blePeripheralConnectHandler(BLECentral& central) {
   if (central){
-    buffer.drawText(stringBuffer.start().put("connected...").get(),15,8,buffer.rgb(255,0,0), &virtualDJ_5ptFontInfo);
+    buffer.drawText(stringBuffer.start().put("connected...").get(),15,8,buffer.rgb(255,0,0), &virtualDJ_5ptFontInfo);
     buffer.flush(display);
     stringBuffer.reset();
   }


Correção da impressão do intervalo.

Correção da impressão do intervalo.

--- quad/quad.ino
+++ quad/quad.ino
@@ -33,8 +33,8 @@
 #endif

 #ifdef DEBUG
-  long tmCheckpoint;   // Marca o tempo no checkpoint
-  long tmInterval;     // Intervalo entre última medição e o checkpoint
+  unsigned long tmCheckpoint; // Marca o tempo no checkpoint
+  unsigned long tmInterval;   // Intervalo entre última medição e o checkpoint
   int countToSend = 0; // Controla o intervalo de envio das informações
 #endif

@@ -612,26 +612,26 @@
   tmCheckpoint = micros();

   String tmValues;
-  tmValues += padding("RCT=" + String(int(rcThrottle)), 8) + ";";
+  tmValues += padding("RCT=" + String(int(rcThrottle)), 9) + ";";
   tmValues += padding("RCY=" + String(int(rcYaw)), 8) + ";";
   tmValues += padding("RCP=" + String(int(rcPitch)), 8) + ";";
   tmValues += padding("RCR=" + String(int(rcRoll)), 8) + ";";
   tmValues += padding("RCO=" + String(int(rcOnOff)), 8) + ";";
   tmValues += padding("RCD=" + String(int(rcDimmer)), 8) + ";";
-  tmValues += padding("ZRP=" + String(int(rcPitchZero)), 9) + ";";
-  tmValues += padding("ZRR=" + String(int(rcRollZero)), 9) + ";";
-  tmValues += padding("ZRY=" + String(int(rcYawZero)), 9) + ";";
-  tmValues += padding("DMP=" + String(int(ypr_degree[DMP_PITCH])), 10) + ";";
-  tmValues += padding("DMR=" + String(int(ypr_degree[DMP_ROLL])), 10) + ";";
-  tmValues += padding("DMY=" + String(int(ypr_degree[DMP_YAW])), 10) + ";";
+  // tmValues += padding("ZRP=" + String(int(rcPitchZero)), 9) + ";";
+  // tmValues += padding("ZRR=" + String(int(rcRollZero)), 9) + ";";
+  // tmValues += padding("ZRY=" + String(int(rcYawZero)), 9) + ";";
+  tmValues += padding("DMP=" + String(int(ypr_degree[DMP_PITCH])), 9) + ";";
+  tmValues += padding("DMR=" + String(int(ypr_degree[DMP_ROLL])), 9) + ";";
+  tmValues += padding("DMY=" + String(int(ypr_degree[DMP_YAW])), 9) + ";";
   tmValues += padding("PIP=" + String(int(pitch_stab_output)), 8) + ";";
   tmValues += padding("PIR=" + String(int(roll_stab_output)), 8) + ";";
   tmValues += padding("PIY=" + String(int(yaw_stab_output)), 8) + ";";
-  tmValues += padding("MFL=" + String(int(motors[MOTOR_FL])), 8) + ";";
-  tmValues += padding("MFR=" + String(int(motors[MOTOR_FR])), 8) + ";";
-  tmValues += padding("MBL=" + String(int(motors[MOTOR_BL])), 8) + ";";
-  tmValues += padding("MBR=" + String(int(motors[MOTOR_BR])), 8) + ";";
-  tmValues += padding("INT=" + String(int(tmInterval)), 10) + ";";
+  tmValues += padding("MFL=" + String(int(motors[MOTOR_FL])), 9) + ";";
+  tmValues += padding("MFR=" + String(int(motors[MOTOR_FR])), 9) + ";";
+  tmValues += padding("MBL=" + String(int(motors[MOTOR_BL])), 9) + ";";
+  tmValues += padding("MBR=" + String(int(motors[MOTOR_BR])), 9) + ";";
+  tmValues += padding("INT=" + String(tmInterval), 11) + ";";
   // for (int i=0; i < 6; i++) {
   //  tmValues += padding(String(channels[i]), 8) + ";";
   // }


Fixed a few display bugs.

Fixed a few display bugs.

--- shutter-timer/src/shutter-timer.ino
+++ shutter-timer/src/shutter-timer.ino
@@ -101,7 +101,7 @@
   Serial.print("Shutter detected: 1/");
   Serial.print(shutter);
   Serial.print("s (");
-  Serial.print(duration / 1000);
+  Serial.print(duration / 1000.0);
   Serial.print("ms)");

   Serial.print("    Avg (");
@@ -109,9 +109,10 @@
   Serial.print(") 1/");
   Serial.print(avgShutter);
   Serial.print("s (");
-  Serial.print(mean / 1000 );
+  Serial.print(mean / 1000.0 );
   Serial.print("ms) σ:");
-  Serial.println(stdDevSample / 1000);
+  Serial.print( count == 1 ? 0.0 : stdDevSample / 1000 );
+  Serial.println("ms");
 }

 void debugRawValues()


Update mech.ino

Update mech.ino

--- mech/mech.ino
+++ mech/mech.ino
@@ -178,9 +178,9 @@
   isAutoTune = 1;
   stepperC1.moveTo(10);
   stepperC2.moveTo(10);
-  optimize(&stepperL, 2000, 0);
-  optimize(&stepperC1, 20, 0);
-  optimize(&stepperC2, 20, 0);
+  optimize(&stepperL, 2000, 32);
+  optimize(&stepperC1, 20, 32);
+  optimize(&stepperC2, 20, 32);
   isAutoTune = 0;
 }


Update inline comments to reflect Dash --> Electron changes

--- mega/mega.ino
+++ mega/mega.ino
@@ -5,7 +5,13 @@
  (begun June 6, 2011)

-  January-March 2018
+  March 2018
+
+  Rewrite of cellular system to use Particle Elctron rather than Hologram
+  Dash (which was suddenly discontinued)
+
+
+  January-February 2018

   Celullar communications via Hologram DASH and AIS relaying to fdr server.


updating sweeper angle movement to compensate for felt fencing


Removed comments so back to user input AND generated messages

--- src/CAN/CAN_send_v2/CAN_send_v2.ino
+++ src/CAN/CAN_send_v2/CAN_send_v2.ino
@@ -61,18 +61,17 @@

       // Send the Authentication messages
       SendAuthMessagesByKey(key, keyLen);
-      PrintMessage();
     }

     // Otherwise, Generate a random CAN message
     GenerateMessage(id, dlc, &stmp[0]);
-    //CAN.sendMsgBuf(id, 0, dlc, stmp);
-    //SendAuthMessages();
+    CAN.sendMsgBuf(id, 0, dlc, stmp);
+    SendAuthMessages();

     // Display message on Serial interface
-    //PrintMessage();
+    PrintMessage();
     Serial.flush();
-    delay(1);
+    delay(1000);
 }


Update hallsensor code to reflect changes in wiring on breadboard using pullup resistor

--- tinkering/hallsensor/hall_test.ino
+++ tinkering/hallsensor/hall_test.ino
@@ -1,26 +1,26 @@
 #define HALLPIN P1_5

 int revs;
-int count;
 unsigned long oldtime;
-unsigned long average;
+unsigned int average;
 int rpm[5];
 int hallRead;
 int switched;
-void magnet_detect();

 void setup()
 {
     Serial.begin(9600);
-    //Pull down to start
-    pinMode(HALLPIN,INPUT_PULLDOWN);
+
+    //Pull up to start
+    pinMode(HALLPIN,INPUT_PULLUP);
+    pinMode(P1_4,OUTPUT);
+    digitalWrite(P1_4,HIGH);

     //initialize variables
     switched = 0;
     revs = 0;
     oldtime = 0;
     average = 0;
-    count = 0;
 }

 void loop()
@@ -49,6 +49,5 @@
        revs++;
        switched = 0;
     }
-
 }


Update vibra_led.ino

Update vibra_led.ino

--- r4ff4ella/visibile_invisibile/colore/vibra_led.ino
+++ r4ff4ella/visibile_invisibile/colore/vibra_led.ino
@@ -1 +1,38 @@

+void setup() {
+    pinMode(9,OUTPUT);
+    pinMode(10,OUTPUT);
+    pinMode(11,OUTPUT);
+    Serial.begin(9600);
+}
+
+ char val;
+
+void loop() {
+  //LEGGE I DATI DA PROCESSING E ACCENDE IL LED CON UN DATO COLORE
+while (Serial.available()) { // If data is available to read,
+ val = Serial.read(); // read it and store it in val
+ }
+ if (val == 'R') { // If H was received
+ digitalWrite(9, HIGH); // turn the LED on
+  digitalWrite(10, LOW);
+   digitalWrite(11, LOW);
+ }
+if (val == 'G') {
+ digitalWrite(8, LOW); // turn the LED on
+  digitalWrite(10, HIGH);
+   digitalWrite(11, LOW);
+ }
+ if (val == 'B') {
+ digitalWrite(8, LOW); // turn the LED on
+  digitalWrite(10, LOW);
+   digitalWrite(11, HIGH);
+ }
+
+
+  // RACCOGLIE I DATI DAL SENSORE E LI SCRIVE
+  int sensorValue = analogRead(A0);
+  if(sensorValue>0)
+  Serial.write(sensorValue);
+  delay(1);        // delay in between reads for stability
+}


Reduce sketch size from to 29210 to 28934.

We can remove the duplication between the `debug` function and the `debug2`
macro too.

--- printer.ino
+++ printer.ino
@@ -38,10 +38,13 @@

 #define DEBUG
 #ifdef DEBUG
+void debugTimeAndSeparator() {
+  Serial.print(millis()); Serial.print(": ");
+}
 void debug(char *a) {
-  Serial.print(millis()); Serial.print(": "); Serial.println(a);
-}
-#define debug2(a, b) Serial.print(millis()); Serial.print(": "); Serial.print(a); Serial.println(b);
+  debugTimeAndSeparator(); Serial.println(a);
+}
+#define debug2(a, b) debugTimeAndSeparator(); Serial.print(a); Serial.println(b);
 #else
 #define debug(a)
 #define debug2(a, b)


Nam I love you

Nam I love you

--- 2018-FirefighterL1/2018-FirefighterL1.ino
+++ 2018-FirefighterL1/2018-FirefighterL1.ino
@@ -45,6 +45,10 @@
 //Motor top speeds
 double rightSpeed = 0.3;
 double leftSpeed = 0.3;
+
+//dog flags
+bool dog1 = false;
+bool dog2 = false;

 Ultrasonic frontRightUltrasonic(F_R_ECHO, F_R_TRIG, true);
 Ultrasonic leftUltrasonic(L_ECHO, L_TRIG, true);
@@ -287,7 +291,7 @@
 }

 void loop() {
-
+
   //startUp();
   //levelOneNav();
   //getRotation();


CANtest updated to force driver buffering

--- examples/CANtest/CANtest.ino
+++ examples/CANtest/CANtest.ino
@@ -2,13 +2,24 @@
 // CANtest for Teensy 3.1
 // by teachop
 //
+// This test is talking to a single other echo-node on the bus.
+// 6 frames are transmitted and rx frames are counted.
+// Tx and rx are done in a way to force some driver buffering.
+// Serial is used to print the ongoing status.
+//

+#include <Metro.h>
 #include <FlexCAN.h>

+Metro sysTimer = Metro(1);// milliseconds
+
 int led = 13;
-FlexCAN CANbus(125000);
+FlexCAN CANbus(500000);
 static CAN_message_t msg,rxmsg;
 static uint8_t hex[17] = "0123456789abcdef";
+
+int txCount,rxCount;
+unsigned int txTimer,rxTimer;

 // -------------------------------------------------------------
@@ -28,28 +39,60 @@
 void setup(void)
 {
   CANbus.begin();
-  pinMode(led, OUTPUT);
+  pinMode(led, OUTPUT);
+  digitalWrite(led, 1);
+
+  delay(1000);
+  Serial.println(F("Hello Teensy 3.1 CAN Test."));

-  Serial.println(F("Hello Teensy 3.1 CAN Test."));
+  sysTimer.reset();
 }

 // -------------------------------------------------------------
 void loop(void)
 {
-  if ( CANbus.read(rxmsg) ) {
+  // service software timers based on Metro tick
+  if ( sysTimer.check() ) {
+    if ( txTimer ) --txTimer;
+    if ( rxTimer ) --rxTimer;
+  }
+
+  // if not time-delayed, read CAN messages and print 1st byte
+  if ( !rxTimer ) {
+    while ( CANbus.read(rxmsg) ) {
+      //hexDump( sizeof(rxmsg), (uint8_t *)&rxmsg );
+      Serial.write(rxmsg.buf[0]);
+      rxCount++;
+    }
+  }
+
+  // insert a time delay between transmissions
+  if ( !txTimer ) {
+    // if frames were received, print the count
+    if ( rxCount ) {
+      Serial.write('=');
+      Serial.print(rxCount);
+      rxCount = 0;
+    }
+    txTimer = 100;//milliseconds
+    msg.len = 8;
+    msg.id = 0x222;
+    for( int idx=0; idx<8; ++idx ) {
+      msg.buf[idx] = '0'+idx;
+    }
+    // send 6 at a time to force tx buffering
+    txCount = 6;
     digitalWrite(led, 1);
-    hexDump( sizeof(rxmsg), (uint8_t *)&rxmsg );
-    msg.len = 8;
-    msg.id = 0x555;
-    for( int loop=0; loop<8; ++loop ) {
-      msg.buf[loop] = tolower(rxmsg.buf[loop]);
+    Serial.println(".");
+    while ( txCount-- ) {
+      CANbus.write(msg);
+      msg.buf[0]++;
     }
-    CANbus.write(msg);
-    //hexDump( sizeof(msg), (uint8_t *)&msg );
-    delay(10);
-  } else {
     digitalWrite(led, 0);
+    // time delay to force some rx data queue use
+    rxTimer = 3;//milliseconds
   }
+
 }


Update ArduCAM_Mini_5MP_Plus_Video_Streaming.ino

--- ArduCAM/examples/mini/ArduCAM_Mini_5MP_Plus_Video_Streaming/ArduCAM_Mini_5MP_Plus_Video_Streaming.ino
+++ ArduCAM/examples/mini/ArduCAM_Mini_5MP_Plus_Video_Streaming/ArduCAM_Mini_5MP_Plus_Video_Streaming.ino
@@ -250,7 +250,7 @@
   }
   if (myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK))
   {
-    Serial.println(F("CAM Capture Done. END"));
+    Serial.println(F("ACK CMD CAM Capture Done. END"));
     read_fifo_burst(myCAM);
     //Clear the capture done flag
     myCAM.clear_fifo_flag();


Add basic calibration

Add basic calibration

--- mouse_rat.ino
+++ mouse_rat.ino
@@ -29,23 +29,8 @@

 /* Assign a unique base ID for this sensor */
 Adafruit_LSM9DS0 lsm = Adafruit_LSM9DS0(1000);  // Use I2C, ID #1000
-
-/* Or, use Hardware SPI:
-  SCK -> SPI CLK
-  SDA -> SPI MOSI
-  G_SDO + XM_SDO -> tied together to SPI MISO
-  then select any two pins for the two CS lines:
-*/
-
 #define LSM9DS0_XM_CS 10
 #define LSM9DS0_GYRO_CS 9
-
-//Adafruit_LSM9DS0 lsm = Adafruit_LSM9DS0(LSM9DS0_XM_CS, LSM9DS0_GYRO_CS, 1000);
-/* Or, use Software SPI:
-  G_SDO + XM_SDO -> tied together to the MISO pin!
-  then select any pins for the SPI lines, and the two CS pins above
-*/
-
 #define LSM9DS0_SCLK 13
 #define LSM9DS0_MISO 12
 #define LSM9DS0_MOSI 11
@@ -142,6 +127,11 @@

   /* Setup the sensor gain and integration time */
   configureSensor();
+
+  sensors_event_t accel, mag, gyro, temp;
+  lsm.getEvent(&accel, &mag, &gyro, &temp);
+
+  calibrate(accel.acceleration.x, accel.acceleration.y);
 }

 void loop(void) {
@@ -151,17 +141,16 @@
   lsm.getEvent(&accel, &mag, &gyro, &temp);

   float mx, my = 0.0;
+  float accel_x = clamp(accel.acceleration.y, -20, 20)

-  if (accel.acceleration.x > xNormal || accel.acceleration.x > -xNormal) {
+  if (accel.acceleration.x > xRange[1] || accel.acceleration.x < xRange[0]) {
     my = map(accel.acceleration.x - xNormal, -20, 20, 200, -200);
     mx = map(accel.acceleration.y - yNormal, -20, 20, 200, -200);
   }
-  else if (accel.acceleration.y > yNormal || accel.acceleration.y > -yNormal) {
+  else if (accel.acceleration.y > yRange[1] || accel.acceleration.y < yRange[0]) {
     my = map(accel.acceleration.x - xNormal, -20, 20, 200, -200);
     mx = map(accel.acceleration.y - yNormal, -20, 20, 200, -200);
   }
-
-  calibrate(accel.acceleration.x, accel.acceleration.y);
   Mouse.move(mx, my, 0);

 //  print out accelleration data
@@ -176,7 +165,7 @@
 //  Serial.print("  \tZ: "); Serial.print(gyro.gyro.z);     Serial.println("  \tdps");
 //  Serial.print("Temp: "); Serial.print(temp.temperature); Serial.println(" *C");

-  delay(16);
+  delay(10);
 }

 void calibrate(float x, float y) {
@@ -186,6 +175,14 @@
    yRange[0] = min(yRange[0], y);
    yRange[1] = max(yRange[1], y);

+   xNormal = (xRange[0] + xRange[1])/2;
+   yNormal = (yRange[0] + yRange[1])/2;
+
    Serial.print(xRange[0]); Serial.print(", "); Serial.println(xRange[1]);
    Serial.print(yRange[0]); Serial.print(", "); Serial.println(yRange[1]);
  }
+
+template<typename T>
+T clamp(T Value, T Min, T Max) {
+  return (Value < Min)? Min : (Value > Max)? Max : Value;
+}


Update Set_up.ino

Update Set_up.ino

--- 2.SD_Externo/cobra/Set_up.ino
+++ 2.SD_Externo/cobra/Set_up.ino
@@ -3,7 +3,7 @@
   GD.begin();
     //GD.cmd_setrotate(0);
    // GD.self_calibrate();
-  SD.begin(SD_CS, SD_SCK_MHZ(36));
+  SD.begin(SD_CS, SD_SCK_MHZ(FreqSPI2));

   CobraSTM32();
 }


A few more comments

A few more comments

--- code/lissajous/lissajous.ino
+++ code/lissajous/lissajous.ino
@@ -32,12 +32,13 @@
   while (digitalRead(2) != 0)
   {
     // Keep generating random values. Only on button press do we lock in the values.
-    facter = random(1001, 1021)/1000.0;
-    starter = random(3141)/1000.0;
+    // The random seed is not random enough, so this provides a more random result.
+    facter = random(1001, 1021)/1000.0; // Increase the second number for variation.
+    starter = random(3141)/1000.0; // offset the starting point by 0-3.141 radians
     delay(10);
   }

-  // Main loop, to 90% decay.
+  // Main loop, to 90% decay in amplitude of the movements.
   for(pos = 0; pos < decay*0.9; pos += 1)
   {
     // Adjx just gives me a nice sine wave


mag changes quickly

mag changes quickly

--- DanceFeather/DanceFeather.ino
+++ DanceFeather/DanceFeather.ino
@@ -258,7 +258,7 @@
     bool ret = 0;
     for (int i = startIndex; i < endIndex; i++) {
         float magnitude = mag[i];
-        magAvg[i] = magAvg[i] * 0.99 + magnitude * 0.01;
+        magAvg[i] = magAvg[i] * 0.9 + magnitude * 0.1;
         if (magAvg[i] > maxMag && i > 1 && i < 7) {
             maxMag = magAvg[i];
             maxIndex = i;


Added collision detection for outer walls. Added game over screen

--- snack/snack.ino
+++ snack/snack.ino
@@ -3,27 +3,28 @@
 // make an instance of arduboy used for many functions
 Arduboy arduboy;

-int maxX = 127;
-int minX = 0;
-int maxY = 63;
-int minY = 10;
+byte maxX = 127;
+byte minX = 0;
+byte maxY = 63;
+byte minY = 10;
+bool gameRunning = true;

 class coords
 {
   public:
-  int X = 0;
-  int Y = 0;
+  byte X = 0;
+  byte Y = 0;
 };

 typedef struct coords Coords;

 struct player
 {
-  int X = 0;
-  int Y = 0;
+  byte X = 0;
+  byte Y = 0;
   char dir = 'R';
-  int Len = 0;
-  static const int MaxLength = 10;
+  int Len = 1;
+  static const int MaxLength = 100;
   Coords *Moves[MaxLength] = {NULL};
 };

@@ -39,8 +40,8 @@
 void GenerateFood()
 {
   arduboy.initRandomSeed();
-  foodLocation.X = random(minX, maxX);
-  foodLocation.Y = random(minY, maxY);
+  foodLocation.X = random(minX + 1, maxX - 1);
+  foodLocation.Y = random(minY + 1, maxY - 1);
 }

 void StartGame()
@@ -60,7 +61,7 @@
       p1.Moves[arrayPosition]->X = p1.X;
       p1.Moves[arrayPosition]->Y = p1.Y;

-  if(arrayPosition < p1.Len)
+  if(arrayPosition < p1.Len -1)
   {
     arrayPosition += 1;

@@ -73,6 +74,7 @@

 void CollisionDetection()
 {
+  // Check if on food
   if(p1.X == foodLocation.X && p1.Y == foodLocation.Y)
   {
     if(p1.Len < p1.MaxLength)
@@ -84,6 +86,15 @@
     LogMove();
     GenerateFood();
   }
+
+  //Check if hit wall
+
+  if(p1.X >= maxX || p1.X <= minX || p1.Y >= maxY || p1.Y <= minY)
+  {
+    gameRunning = false;
+  }
+
+  //Check if hit tail
 }

 void DrawTail()
@@ -123,7 +134,7 @@

   // here we set the framerate to 15, we do not need to run at
   // default 60 and it saves us battery life
-  arduboy.setFrameRate(10);
+  arduboy.setFrameRate(30);

  StartGame();
 }
@@ -139,73 +150,92 @@
   // first we clear our screen to black
   arduboy.clear();

-  DrawFrame();
-
-  CollisionDetection();
-
-  if(arduboy.pressed(RIGHT_BUTTON)) {
-    p1.dir = 'R';
-  }
-
-  if(arduboy.pressed(LEFT_BUTTON)) {
-    p1.dir = 'L';
-  }
-
-  if(arduboy.pressed(UP_BUTTON)) {
-    p1.dir = 'U';
-  }
-
-  if(arduboy.pressed(DOWN_BUTTON)) {
-    p1.dir = 'D';
-  }
-
-  switch(p1.dir)
-  {
-    case 'U':
-      if(p1.Y > minY)
-      {
-        p1.Y -= 1;
-      }
+  if(gameRunning == true)
+  {
+    DrawFrame();
+
+    CollisionDetection();
+
+    if(arduboy.pressed(RIGHT_BUTTON)) {
+      p1.dir = 'R';
+    }
+
+    if(arduboy.pressed(LEFT_BUTTON)) {
+      p1.dir = 'L';
+    }
+
+    if(arduboy.pressed(UP_BUTTON)) {
+      p1.dir = 'U';
+    }
+
+    if(arduboy.pressed(DOWN_BUTTON)) {
+      p1.dir = 'D';
+    }
+
+    switch(p1.dir)
+    {
+      case 'U':
+        if(p1.Y > minY)
+        {
+          p1.Y -= 1;
+        }
+        break;
+      case 'D':
+        if(p1.Y < maxY)
+        {
+          p1.Y += 1;
+        }
+        break;
+      case 'L':
+        if(p1.X > minX)
+        {
+          p1.X-= 1;
+        }
+        break;
+      case 'R':
+        if(p1.X < maxX)
+        {
+          p1.X+= 1;
+        }
+
       break;
-    case 'D':
-      if(p1.Y < maxY)
-      {
-        p1.Y += 1;
-      }
-      break;
-    case 'L':
-      if(p1.X > minX)
-      {
-        p1.X-= 1;
-      }
-      break;
-    case 'R':
-      if(p1.X < maxX)
-      {
-        p1.X+= 1;
-      }
-
-    break;
-  }
-
-  arduboy.drawPixel(p1.X, p1.Y, 1);
-  arduboy.drawPixel(foodLocation.X, foodLocation.Y, 1);
-  DrawTail();
-  if(p1.X != previousPosition.X || p1.Y != previousPosition.Y)
-  {
-    previousPosition.X = p1.X;
-    previousPosition.Y = p1.Y;
-    LogMove();
-  }
-
-
-  arduboy.setCursor(63, 0);
-  arduboy.print("Score ");
-
-  char scoreBuff[5];
-  sprintf(scoreBuff, "%05d", score);
-
-  arduboy.print(scoreBuff);
+    }
+
+    arduboy.drawPixel(p1.X, p1.Y, 1);
+    arduboy.drawPixel(foodLocation.X, foodLocation.Y, 1);
+
+    if(p1.X != previousPosition.X || p1.Y != previousPosition.Y)
+    {
+      previousPosition.X = p1.X;
+      previousPosition.Y = p1.Y;
+      LogMove();
+    }
+    DrawTail();
+
+
+    arduboy.setCursor(63, 0);
+    arduboy.print("Score ");
+
+    char scoreBuff[5];
+    sprintf(scoreBuff, "%05d", score);
+
+    arduboy.print(scoreBuff);
+  }
+  else
+  {
+    arduboy.setCursor(20, 20);
+    arduboy.print("Game Over");
+
+    arduboy.setCursor(20, 40);
+    arduboy.print("Score ");
+
+    char scoreBuff[5];
+    sprintf(scoreBuff, "%05d", score);
+
+    arduboy.print(scoreBuff);
+  }
+
+

   // then we finaly we tell the arduboy to display what we just wrote to the display


Change normal mode and song configuration receiption

--- ableton-midi-foot-controller.ino
+++ ableton-midi-foot-controller.ino
@@ -6,6 +6,7 @@
 //#define DEBUG_BUTTONS true
 //#define SINGLE_LED_TEST true
 //#define LCD_TEST true
+#define SONG_CONFIGURATION_DEBUG true

 byte counter;
 const byte CLOCK = 248;
@@ -68,10 +69,11 @@
 const byte numberOfBanks = 5;

 // Modes
-const byte normalMode = 0;
-const byte initMode = 1;
-const byte modeCount = 2;
-byte mode = normalMode;
+const byte UNCONFIGURED = 0;
+const byte NORMAL_MODE = 1;
+const byte INIT_MODE = 2;
+const byte modeCount = 3;
+byte mode = UNCONFIGURED;

 byte initBank = 0;

@@ -86,11 +88,15 @@
 const byte midiChannel = 1;

 const byte SONG_CONFIGURATION = 0;
+const byte CONFIGURATION_START = 1;
+const byte CONFIGURATION_FINISHED = 2;

 const byte SONG_OFFSET = 10;

-const byte numberOfSongs = 128 - SONG_OFFSET;
+const byte numberOfSongs = 30;
 char* songs[numberOfSongs];
+
+byte selectedSong = -1;

 void OnNoteOn(byte channel, byte note, byte velocity) {
@@ -110,49 +116,94 @@

   base64_decode(decoded, (char*)dataArray, realSize);

-  String messageString = String(decoded);
-
-  boolean isConfigurationMessage = messageString.indexOf('{') != -1 && messageString.indexOf('}') != -1;
-
-  lcd.clear();
-  lcd.print(messageString);
+  boolean isConfigurationMessage = strchr(decoded, '{') != NULL;
+
   if (isConfigurationMessage) {
-    byte configurationType = getConfigurationType(messageString);
+    byte configurationType = getConfigurationType(decoded + 1);
     switch (configurationType) {
       case SONG_CONFIGURATION:
-        handleSongConfiguration(messageString);
+        handleSongConfiguration(decoded + 4);
         break;
-    }
-  }
-
-}
-
-void handleSongConfiguration(String message) {
-  byte indexStart = message.indexOf('}') + 1;
-  byte index = message.substring(message.indexOf('{', indexStart) + 1, message.indexOf('}', indexStart)).toInt();
-  Serial.print(index);
-  Serial.print(" ");
-  byte songStart = message.indexOf('}', indexStart) + 1;
-  String song = message.substring(message.indexOf('{', songStart) + 1, message.indexOf('}', songStart));
-  Serial.println(song);
-  int strLen = song.length() + 1;
-  char charArray[strLen];
-  song.toCharArray(charArray, strLen);
-  songs[index] = charArray;
-
+      case CONFIGURATION_START:
+        handleConfigurationStart();
+        break;
+      case CONFIGURATION_FINISHED:
+        handleConfigurationFinished();
+        break;
+    }
+  }
+}
+
+void handleConfigurationStart() {
+  lcd.clear();
+  lcd.print(F("Configuration"));
+  lcd.setCursor(0, 1);
+  lcd.print(F("start"));
+}
+
+void handleConfigurationFinished() {
+#ifdef SONG_CONFIGURATION_DEBUG
   for (byte i = 0; i < numberOfSongs; i++) {
     if (songs[i]) {
       Serial.print(i);
-      Serial.print(" ");
+      Serial.print(F(" "));
       Serial.println(songs[i]);
     }
   }
-}
-
-byte getConfigurationType(String message) {
-  String configurationString = message.substring(message.indexOf('{') + 1, message.indexOf('}'));
-  if (configurationString.equals("C")) {
+#endif
+  lcd.clear();
+  lcd.print(F("Configuration"));
+  lcd.setCursor(0, 1);
+  lcd.print(F("finished"));
+
+  allLedsTest();
+  lcd.clear();
+
+  mode = NORMAL_MODE;
+  selectedSong = 0;
+  handleNormalMode(true);
+}
+
+void handleSongConfiguration(char* messageOriginal) {
+  char* message = (char*)calloc(strlen(messageOriginal) + 1, sizeof(char));
+  strcpy(message, messageOriginal);
+  char* strings;
+  strings = strtok(message, "|");
+  if (strings == NULL) {
+    return;
+  }
+
+  byte index = atoi(strings);
+
+  strings = strtok(NULL, "|");
+  if (strings == NULL) {
+    return;
+  }
+
+#ifdef SONG_CONFIGURATION_DEBUG
+  Serial.print(F("Received song configuration "));
+  Serial.print(index);
+  Serial.print(F(" "));
+  Serial.println(strings);
+#endif
+
+  songs[index - 1] = strings;
+}
+
+byte getConfigurationType(char* messageOriginal) {
+  char* message = (char*)calloc(strlen(messageOriginal) + 1, sizeof(char));
+  strcpy(message, messageOriginal);
+  char* strings;
+  strings = strtok(message, "|");
+  if (strings == NULL) {
+    return -1;
+  }
+  if (strcmp(strings , "SC") == 0) {
     return SONG_CONFIGURATION;
+  } else if (strcmp(strings , "CS") == 0) {
+    return CONFIGURATION_START;
+  } else if (strcmp(strings , "CF") == 0) {
+    return CONFIGURATION_FINISHED;
   }
   return -1;
 }
@@ -255,13 +306,13 @@

 void debugButton(Button *button) {
 #ifdef DEBUG_BUTTONS
-  Serial.print("Button: ");
+  Serial.print(F("Button: "));
   Serial.print((*button).getPin());
-  Serial.print(" Just pressed: ");
+  Serial.print(F(" Just pressed: "));
   Serial.print((*button).isJustPressed());
-  Serial.print(" Pressed: ");
+  Serial.print(F(" Pressed: "));
   Serial.print((*button).isPressed());
-  Serial.print(" Just released : ");
+  Serial.print(F(" Just released : "));
   Serial.println((*button).isJustReleased());
 #endif
 }
@@ -280,6 +331,8 @@
       usbMIDI.sendNoteOff(i + (initBank * numberOfChannelButtons), 0, midiChannel);
     } else if (channelButtons[i].isJustPressed()) {
       usbMIDI.sendNoteOn(i + (initBank * numberOfChannelButtons), 99, midiChannel);
+      Serial.print(F("Midi-Note "));
+      Serial.println(i + (initBank * numberOfChannelButtons));
     }
   }
 }
@@ -302,10 +355,10 @@
   }

   switch (mode) {
-    case normalMode:
+    case NORMAL_MODE:
       handleNormalMode();
       break;
-    case initMode:
+    case INIT_MODE:
       handleInitMode();
       break;
   }
@@ -331,13 +384,37 @@
     update = true;
   }
   if (update) {
-    Serial.print("MIDI offset ");
+    Serial.print(F("MIDI offset "));
     Serial.println(initBank);
   }
 }

+void handleNormalMode(boolean forceUpdate) {
+  changeBank();
+  boolean update = false;
+  for (byte i = 0; i < numberOfChannelButtons; i++) {
+    if (channelButtons[i].isJustReleased()) {
+      update = selectedSong != i;
+      selectedSong = i;
+    }
+  }
+
+
+  if (update || forceUpdate) {
+    for (byte i = 0; i < numberOfChannelButtons; i++) {
+      channelButtons[i].turnLedOff();
+    }
+    channelButtons[selectedSong].turnLedOn();
+    char* song = songs[selectedSong + (bank * numberOfChannelButtons)];
+    if (song) {
+      lcd.clear();
+      lcd.print(song);
+    }
+  }
+}
+
 void handleNormalMode() {
-  changeBank();
+  handleNormalMode(false);
 }

 boolean changeMode() {


Add reference to Arduino UNO specs and ATmega328P-PU at top. Remove Timer interrupt implementation but leave a comment. Change "secsLeft" to "timeLeft" and keep the value in milliseconds, so that the centrifuge is as accurately timed as possible--no distortion due to integer division on millis() and spinningStartTime cutting the time short or long.

--- Dremelfuge.ino
+++ Dremelfuge.ino
@@ -3,6 +3,10 @@
 Adapted from Orlov's Instructable on Arduino Powered Centrifuge

 Compiled and Edited by: Albert Ju, Fu Yang Chin
+
+Uploaded to an Arduino UNO, with MCU ATmega328P-PU.
+Arduino UNO specs: https://www.arduino.cc/en/Main/ArduinoBoardUno
+ATmega328P-PU datasheet: http://www.atmel.com/Images/doc8161.pdf
 */

 #include <LiquidCrystal.h>                              // include the library for the display;
@@ -10,7 +14,7 @@
 #include "LEDButton.h"                                  // include custom library which is in the same directory as this file
                                                         // because it's a relative path, use "" LITERAL PATHNAME
 #include "karina_utility.cpp"                           // for void printfSecs(unsigned long seconds, T& t)
-#include <avr/interrupt.h>                              // for interrupts
+
 //============================GLOBAL VARIABLES=================================//
 /* *** These variables MUST be global because they're being used by multiple
   totally separate functions--static local won't do
@@ -23,8 +27,6 @@

 namespace
 {
-    long unsigned int currentSecs = 0;                            // current time in secs, overflows if Dremelfuge on for 18.2 hours
-
     LiquidCrystal lcd
     = LiquidCrystal(12, 11, 5, 4, 3, 6);                // initialize LC object with the numbers of the interface pins

@@ -82,152 +84,9 @@
   lcd.setCursor(0, 3);
   lcd.print(F("   Push to "));

-  /* Explanation of timer interrupts and applications of bit operations:
-    An interrupt is a special type of user-defined event; interrupts occur either
-    when a timer reaches a certain value (timer interrupts), or when a pin
-    changes state (external interrupts). This block will focus on timer
-    interrupts. Note that the terms "interrupt" as an event and
-    "Interrupt Service Routine (ISR)," which is the function that is run when an
-    interrupt occurs, are used almost interchangeably.
-
-    "n" = timer number; Timer0, Timer1, ...
-    "x" = A or B, in the context of named regisers.
-    Registers are a small but very quickly-accessed memory location that reside
-    on the processor itself. Registers store special values that need to be read
-    and/or written very quickly.
-    ----------
-
-    MCUs have built-in timers. Timers are just modules used to measure time,
-    physically via the oscillation of Voltage storage in a capacitor-inductor
-    circuit, like an electric pendulum. To utilize this physical process in a
-    MCU, the timer circuit has many additional components: a counter register
-    whose value increments with each tick, a output comparison register whose
-    value is compared with the counter on every tick to let the programmer time
-    events, prescalers to change the frequency of the timer ticks, and a wave
-    generation module that can use the timer to produce various waveforms through
-    PWM, to name some main ones.
-
-    Timers have 2 primary modes of operation: 1) increment from 0 until a TOP
-    value is reached, and then reset to 0; 2) increment from 0 until a TOP value
-    is reached, and then decrement back down to 0. These are the main attributes
-    of the non-PWM and PWM modes, respectively. Generally, the latter should be
-    used for timing events, while the former should be used for PWM.
-    We shall pay special attention to the non-PWM modes for this project. There
-    are two non-PWM modes: Normal and CTC (Clear Timer on Compare match). In
-    Normal mode, *TCNTn (the register that holds the Timer CouNT) *keeps
-    incrementing until it overflows.** On the same tick (clock cycle) that
-    overflow occurs, the Timer/Counter Overflow flag (TOVn) is raised. In CTC
-    mode, TCNTn increments until a specific, user-set value is reached, at which
-    point TCNTn is cleared (set to 0). This user-set value is stored in OCRnx
-    (Output Compare Register nA or nB). Every single clock cycle, the value of
-    TCNTn is compared with OCRnx. On the clock cycle after the comparison returns
-    true, the corresponding OCFnx (Output Compare Flag) is raised. However, an
-    additional clock cycle must be spent clearing TCNTn, unlike Normal mode--this
-    represents a one-tick delay that must be taken into account in timing
-    calculations.
-    You _could_ use interrupts through Output Comparison on Normal mode just like
-    in CTC mode, but the calculation is comparatively not straightforward, so
-    using CTC mode is easier in most cases.
-
-    What determines the frequency of each tick? The clock cycle does! While AVRs
-    have a builtin system clock, whose processor speed determines its system
-    clock frequency, you can use unitless "prescalers" to change the clock
-    speed/tick frequency of individual timers. Using a timer without prescalers
-    would mean using the system clock speed, which is way too fast for many
-    practical purposes. Prescalers effectively give individual timers slower
-    clocks. These prescaled clocks will be slower than the system clock by
-    factors of 2--that is,
-    [frequency of prescaled clock = system clock frequency/pow(2, n)].
-    Prescalars are "system clock-dividers."
-    You can select between different prescalers in the TCCRnB bit string.
-
-    There are two Timer/Counter Control Registers, TCCRnA and TCCRnB, which
-    are bit strings whose different bit values correspond to the different Timer
-    settings: mode (set by WGMy Waveform Generation Mode bits in TCCRnA and
-    TCCRnB), whether/how to change the outputs of external pins (OCnx) when OCFnx
-    flags are raised (set by COMnxy COMpare match output mode bits in TCCRnA),
-    and what if any prescaler value to use (CSny bits in TCCRnB). All
-    combinations of modes and prescalers and output comparisons are valid.
-    Additionally, you can have up to 2 Output Control Registers, i.e. up to 2
-    values that the Timer is checked against every tick and that can ultimately
-    cause ISRs. These are OCRnA and OCRnB; "x" denotes a bit corresponding to
-    either OCR.
-    See the appropriate Atmel AVR datasheet for details on bit string layout.
-
-    Details of implementation:
-    An interrupt service routine (ISR) is a function that runs when an interrupt
-    flag is raised, i.e. ISRs are run when "interrupts" occur.
-    An interrupt flag is a bit that keeps track of whether a timer event has
-    occurred (1) or not (0). A timer event is either overflow (w/ flag TOVn) or
-    a successful comparison of the timer with the value in the output compare
-    register (when TCNTn == OCRnx, OCFnx is raised).
-    Interrupt flags are stored in interrupt flag registers. One interrupt flag
-    register is used for each timer. The value of/in an interrupt flag register
-    is a bit string whose bits correspond to which flags have been raised.
-
-    A timer mask (TIMSKn) is a string of bits that determines *which timer events
-    to pay attention to*, i.e. *which flags can trigger ISRs*, i.e. "which
-    interrupts are activated/attached." A bit set to 1 in TIMSKn means that that
-    associated flag will not be masked off, so that if that flag is raised, its
-    corresponding ISR will run automatically.
-    The bit masking is done behind the scenes, probably taken care of through
-    the configuration of the Timer circuit itself.
-
-    Bit concepts:
-    Generally, a bit mask is a string of *bits used to extract bit values of
-    interest from other bit strings,* usually by binary AND (&) in a process
-    called "masking off" the other bits outside the mask, or sometimes by binary
-    OR (|) in a process called "masking on" the other bits outside the mask.
-    When we set the bits in TIMSKn, we're "building a bit mask," determining
-    which bit values are of interest.
-
-    A bit value is meaningless without the context of where that bit value lies
-    in a bit string. This is especially true of bits inside registers used for
-    special purposes: "You have a 1? THAT'S GREAT. But where is it? What does
-    that 1 MEAN? How am I supposed to know what this 1 means when I don't know
-    where it is?"
-    When we talk of the "foo bit," we're talking about the bit value AT POSITION
-    FOO--we're talking about the state of foo. For bits, location = meaning
-    = what state the 1 or 0 alludes to.
-    That's why constants like OCIE1A are actually the values of indexes. In the
-    datasheet, the bit _AT_ OCIE1A represents the STATE _OF_ OCIE1A.
-
-    Reference for knowledge but incorrect datasheet:
-    http://www.atmel.com/Images/doc8025.pdf
-    */
-  // ATmega328P-PU datasheet: http://www.atmel.com/Images/doc8161.pdf
-
-  cli();                                                // disable interrupts while setting up timers--CLear Interrupts
-  TIMSK1 = (1 << OCIE1A);                               // set the OCIE1A bit in TIMSK1 to 1, Enabling OC Interrupts w/ OCR1A
-  TCCR1B = (1 << WGM12);                                // enable CTC mode as specified in the datasheet
-  TCCR1A = 0;                                           // MAKE SURE THAT THE SETTINGS IN THIS MODE ARE CORRECTLY SET TO 0 AS WELL
-
-  /* Calculation of settings producing a Timer1 Output Compare Interrupt every 1s
-    ATmega328P-PU clock speed = 16MHz = 16 000 000 Hz = ticks per second
-    Want ISR every 1 second
-    Prescalar is unitless, divides internal clock speed for smaller Timer clock speed
-    highest prescalar = 1024
-    16 000 000 Hz / 1024 = 15 625 Hz = 0.000064 s per tick with prescalar 1024
-    1 tick = 1 increment
-    (x increments + 1 tick for reset) * 0.000064 s per increment ~= 1 second per x increments with prescalar 1024
-    x = 15 624 increments aka ticks with prescalar 1024
-    */
-
-  TCCR1B |= (1 << CS12) | (1 << CS10);                  // use 1024 prescalar for Timer1; OR combines both CS bits, |= appends old!
-  OCR1A = 15624;                                        // Output Compare Register value that raises a flag every 1s w/ this Timer1
-  sei();                                                // enable interrupts now that timers set up--SEt Interrupts
-
-  Serial.begin(9600);
-  TCNT1 = 0;                                            // set Timer/Counter 1 to 0
+  // Timer interrupt implementation + explanation removed; see commit f587[...]
+
 } // void setup()
-
-/* While spinning, only update LCD every 1s--don't waste SRAM updating LCD before
-  the time can even change
-  */
-ISR(TIMER1_COMPA_vect)                                  // Interrupt Service Routine that runs when OC unit 1A raises its flag
-{
-  currentSecs++;                                        // incremented every 1s, so its value truly reflects time since prog started
-} // ISR(SIG_OUTPUT_COMPARE1A)

 /////////////////////////////////////////////////////////////////////////////////
 void loop()
@@ -292,6 +151,7 @@
     with different modifiers and scopes and allocations will be stored in
     different areas of RAM and by different means.
     */
+
   enum class Mode
   {
     SETTING_TIME,
@@ -416,14 +276,15 @@
       /* Save SRAM by doing this calculation only once per loop()::SPINNING (by
         saving the result in a variable)
         */
-      unsigned long secondsLeft =
-      (setDuration - (millis() - spinningStartTime))/1000;
+      unsigned long timeLeft =                          // need timeLeft in ms so as to get a precise duration for the centrifuge
+      (setDuration - (millis() - spinningStartTime));

       lcd.setCursor(13, 1);
-      printfSecs(secondsLeft, lcd);
+      printfSecs(timeLeft/1000, lcd);                   // timeLeft in ms, printing secs; inconsistent _display_ results due to int
+                                                        // division, but this case block truly does last as long as timeLeft
       lcd.print(F("  "));

-      if(wpb.pressed() || secondsLeft == 0)
+      if(wpb.pressed() || timeLeft <= 0)                // `<=` because the delay between instructions may cause millis => -timeLeft
       {
         digitalWrite(MOTOR_PIN, LOW);
         changedUIString = false;                        // UI string will be changed back!


Experimental changes to balance stepper motion

--- shipStation/lbcc_ship_stepper/lbcc_ship_stepper.ino
+++ shipStation/lbcc_ship_stepper/lbcc_ship_stepper.ino
@@ -50,14 +50,16 @@
   } else {
     Serial.println(F("BNO055 IMU detected.."));
   }
-//  bno.setExtCrystalUse(true);                     //Use the external clock in the IMU
-//  bno.setMode(bno.OPERATION_MODE_NDOF);
+  bno.setExtCrystalUse(true);                     //Use the external clock in the IMU
+  bno.setMode(bno.OPERATION_MODE_NDOF);

   // Set stepper motor acceleration and top speeds
   xAxis.setMaxSpeed(10000);
   xAxis.setAcceleration(5000);
   yAxis.setMaxSpeed(10000);
   yAxis.setAcceleration(5000);
+  // Temporary
+  balance();
 }

@@ -105,18 +107,64 @@
 }

 void updateMotors(double aziDegs, double eleDegs){
-  azimuth_steps = radsToSteps(aziDegs);
-  elevation_steps = radsToSteps(eleDegs);
+  azimuth_steps = degreesToSteps(aziDegs);
+  elevation_steps = degreesToSteps(eleDegs);
+  Serial.print(F("yaw="));
+  Serial.print(aziDegs);
+  Serial.print(F(", pitch="));
+  Serial.print(eleDegs);
+  Serial.print(F(", "));
+  Serial.print(sys);
+  Serial.print(F(", "));
+  Serial.print(gyro);
+  Serial.print(F(", "));
+  Serial.print(accel);
+  Serial.print(F(", "));
+  Serial.println(mag);
   xAxis.moveTo(azimuth_steps);
   yAxis.moveTo(elevation_steps);
 }

-float radsToSteps(float rad)
-{
-  // Takes radians, returns steps (assuming 16*3060 = 48960 total steps)
-  // rad/(2*pi) = steps / (microsteps * motor steps)
-  return rad * 24480 / M_PI;
+void balance(){
+  while(1){
+    // Read IMU 10 times per second
+    if(millis() - imuTimer > 100){
+      imuTimer = millis(); // reset the timer
+      //Read the current calibration values from the IMU
+      bno.getCalibration(&sys, &gyro, &accel, &mag);
+      //Read the current positional values
+      bno.getEvent(&event);
+
+      // Using quaternions
+      imu::Quaternion q = bno.getQuat();
+      q.normalize();
+      float temp = q.x();  q.x() = -q.y();  q.y() = temp;
+      q.z() = -q.z();
+      // Converted back to eulers
+      imu::Vector<3> euler = q.toEuler();
+
+      updateMotors(
+        radsToDegrees(euler.x()),
+        radsToDegrees(euler.z())
+      );
+    }
+
+    xAxis.run();
+    yAxis.run();
+  }
+}
+
+
+double degreesToSteps(double deg){
+  // Takes degrees, returns steps (assuming 16*3060 = 48960 total steps)
+  // deg / 360 = steps / (microsteps * motor steps)
+  return deg * 136;
+}
+
+double radsToDegrees(double rad){
+  // Takes radians, returns degrees
+  return rad * 180 / M_PI;
 }


Fixed BUG in battery reporting code

Fixed BUG in battery reporting code

--- DigitalVFO.ino
+++ DigitalVFO.ino
@@ -1892,7 +1892,7 @@
   Serial.printf(F("%s %s%s (%s)\n"), ProgramName, Version, MinorVersion, Callsign);
 #endif

-#if (DEBUG > 0)
+#if (DEBUG != 0)
   Serial.printf(F("DEBUG is defined as %06X:\n"), DEBUG);
   decode_debug_levels(DEBUG);
 #else
@@ -2759,8 +2759,10 @@
     BatterySymbol = battnone;
 #if (DEBUG & DEBUG_BATT)
     if (batt_report_count > 0)
+    {
       Serial.printf(F("no battery\n"));
       batt_report_count = -ReportVoltageDelay;
+    }
 #endif
   }
   else if (MeasuredVoltage < MinVoltage)
@@ -2768,8 +2770,10 @@
     BatterySymbol = battunder;
 #if (DEBUG & DEBUG_BATT)
     if (batt_report_count > 0)
+    {
       Serial.printf(F("battery under voltage\n"));
       batt_report_count = -ReportVoltageDelay;
+    }
 #endif
   }
   else if (MeasuredVoltage > OverVoltage)
@@ -2777,8 +2781,10 @@
     BatterySymbol = battover;
 #if (DEBUG & DEBUG_BATT)
     if (batt_report_count > 0)
+    {
       Serial.printf(F("OVER VOLTAGE\n"));
       batt_report_count = -ReportVoltageDelay;
+    }
 #endif
   }
   else


Working on save/restore/delete slot menus

--- DigitalVFO.ino
+++ DigitalVFO.ino
@@ -304,7 +304,7 @@
 typedef void (*ItemSelection)(Menu *, int);

 // handler for inc/dec of custom item (vfo_RRight, vfo_RLeft events)
-typedef void (*ItemIncDec)(int delta);
+typedef int (*ItemIncDec)(int item_num, int delta);

 // structure defining a menu item
 struct MenuItem
@@ -399,7 +399,7 @@
 void menuitem_draw(struct Menu *menu, int item_num)
 {
   if (menu->num_items == 1)
-    (menu->items[item_num]->incdec)(0);  // draw without modifying
+    (menu->items[item_num]->incdec)(item_num, 0);  // draw without modifying
   else
     menuitem_draw_std(menu, item_num);
 }
@@ -416,18 +416,16 @@
   //Serial.print("menu_show: menu="); Serial.print((unsigned long) menu, HEX);
   dump_menu("menu_show, menu:", menu);
   Serial.print("item_num="); Serial.println(item_num);
-
+
   // get rid of any stray events to this point
   flush_events();

   // draw the menu page
   menu_draw(menu);

-  dump_menuitem("menu_show, menuitem:", menu->items[item_num]);
-
   // decide if drawing menuitem or a dynamic display
   if (menu->num_items == 1)
-    (menu->items[item_num]->incdec)(0);  // draw without modifying
+    (menu->items[item_num]->incdec)(item_num, 0);  // draw without modifying
   else
     menuitem_draw(menu, item_num);

@@ -449,7 +447,8 @@
           if (menu->num_items == 1)
           {
             // special dynamic menuitem
-            menu->items[item_num]->incdec(-1);
+            item_num = menu->items[0]->incdec(item_num, -1);
+            Serial.print("After vfo_RLeft, item_num="); Serial.println(item_num);
           }
           else
           {
@@ -463,7 +462,11 @@
           if (menu->num_items == 1)
           {
             // special dynamic menuitem
-            menu->items[item_num]->incdec(+1);
+            Serial.print("calling incdec(");
+            Serial.print(item_num);
+            Serial.println(", +1)");
+            item_num = menu->items[0]->incdec(item_num, +1);
+            Serial.print("after vfo_RRight, item_num="); Serial.println(item_num);
           }
           else
           {
@@ -471,6 +474,7 @@
             if (++item_num >= menu->num_items)
               item_num = menu->num_items - 1;
           }
+          Serial.println("point 1");
           break;
         case vfo_DnRLeft:
           Serial.println("Menu: vfo_DnRLeft");
@@ -487,10 +491,13 @@

           // if there's a handler, call it
           // this will probably destroy the curent menu page
-          if (menu->items[item_num]->action != NULL)
+          if (menu->items[0]->action != NULL)
           {
             Serial.println("Calling vfo_Click handler");
-            (*menu->items[item_num]->action)(menu->items[item_num]->menu, 0);
+            Serial.print("menu->items[0]->action=");
+            Serial.print((unsigned long) menu->items[0]->action, HEX);
+            Serial.print(", item_num="); Serial.println(item_num);
+            (*menu->items[0]->action)(menu->items[0]->menu, item_num);
           }

           menu_draw(menu);    // redraw the menu header
@@ -504,14 +511,24 @@
           Serial.print("Menu: unrecognized event "); Serial.println(event);
           break;
       }
+Serial.println("point 2");

       // update the menu display
       if (menu->num_items == 1)
-        (menu->items[item_num]->incdec)(0);  // draw without modifying
+      {
+        Serial.println("point 3");
+        Serial.print("????: item_num="); Serial.print(item_num);
+        Serial.print(", menu->items[0]->incdec=");
+        Serial.println((unsigned long) menu->items[0]->incdec, HEX);
+        (menu->items[0]->incdec)(item_num, 0);  // draw without modifying
+        Serial.println("point 4");
+      }
       else
+      {
+        Serial.println("point 5");
         menuitem_draw(menu, item_num);
-
-      dump_menuitem("menu_show: new menuitem=", menu->items[item_num]);
+        Serial.println("point 6");
+      }
     }
   }
 }
@@ -658,7 +675,7 @@
   ltobbuff(buf, MAX_FREQ_CHARS, freq);

   lcd.createChar(SELECT_CHAR, sel_digits[int(buf[index])]);
-  lcd.setCursor(NUM_COLS - MAX_FREQ_CHARS - 2, 0);
+  lcd.setCursor(NUM_COLS - MAX_FREQ_CHARS - 2, row);
   for (int i = 0; i < MAX_FREQ_CHARS; ++i)
   {
     int char_val = buf[i];
@@ -1149,23 +1166,65 @@

 void saveslot_action(Menu *menu, int item_num)
 {
-  Serial.println("saveslot_action() entered");
+  Serial.print("saveslot_action() entered, item_num=");
+  Serial.println(item_num);

   // display an 'action' flash
   menu_flash();

   put_slot(item_num, VfoFrequency, VfoSelectDigit);

-  savresdel_show(menu, item_num);
+//  savresdel_show(menu, item_num);
 }

 //----------------------------------------
 // cycle through the save slots
 //----------------------------------------

-void saveslot_incdec(int delta)
-{
-
+int saveslot_incdec(int item_num, int delta)
+{
+  Frequency freq;
+  SelOffset offset;
+
+  Serial.print("saveslot_incdec: item_num="); Serial.print(item_num);
+  Serial.print(", delta="); Serial.println(delta);
+
+  if (delta != 0)
+  {
+    Serial.print("Old item_num="); Serial.println(item_num);
+
+    // bump the slot number, limit to [0, 9]
+    item_num += delta;
+    if (item_num < 0)
+      item_num = 0;
+    else
+      if (item_num > 9)
+        item_num = 9;
+
+    Serial.print("New item_num="); Serial.println(item_num);
+  }
+
+  // draw the row 1 representation of the value
+  Serial.println("Xpoint 1");
+  get_slot(item_num, freq, offset);
+  Serial.println("Xpoint 2");
+  lcd.setCursor(0, 1);
+  lcd.write(BlankRow);
+  if (VfoFrequency == freq)
+  {
+    lcd.setCursor(0, 1);
+    lcd.write("*");
+  }
+  Serial.println("Xpoint 3");
+  lcd.setCursor(4, 1);
+  lcd.write(item_num + '0');
+  lcd.write(":");
+  Serial.println("Xpoint 4");
+  print_freq(freq, -1, 1);
+  Serial.println("Xpoint 5");
+
+  Serial.print("saveslot_incdec: returning item_num="); Serial.println(item_num);
+  return item_num;
 }

 //----------------------------------------
@@ -1188,9 +1247,9 @@
 // cycle through the slots
 //----------------------------------------

-void restoreslot_incdec(int delta)
-{
-
+int restoreslot_incdec(int item_num, int delta)
+{
+  return item_num;
 }

 //----------------------------------------
@@ -1213,9 +1272,50 @@
 // cycle through the slots
 //----------------------------------------

-void deleteslot_incdec(int delta)
-{
-
+int deleteslot_incdec(int item_num, int delta)
+{
+  Frequency freq;
+  SelOffset offset;
+
+  Serial.print("deleteslot_incdec: item_num="); Serial.print(item_num);
+  Serial.print(", delta="); Serial.println(delta);
+
+  if (delta != 0)
+  {
+    Serial.print("Old item_num="); Serial.println(item_num);
+
+    // bump the slot number, limit to [0, 9]
+    item_num += delta;
+    if (item_num < 0)
+      item_num = 0;
+    else
+      if (item_num > 9)
+        item_num = 9;
+
+    Serial.print("New item_num="); Serial.println(item_num);
+  }
+
+  // draw the row 1 representation of the value
+  Serial.println("Xpoint 1");
+  get_slot(item_num, freq, offset);
+  Serial.println("Xpoint 2");
+  lcd.setCursor(0, 1);
+  lcd.write(BlankRow);
+  if (VfoFrequency == freq)
+  {
+    lcd.setCursor(0, 1);
+    lcd.write("*");
+  }
+  Serial.println("Xpoint 3");
+  lcd.setCursor(4, 1);
+  lcd.write(item_num + '0');
+  lcd.write(":");
+  Serial.println("Xpoint 4");
+  print_freq(freq, -1, 1);
+  Serial.println("Xpoint 5");
+
+  Serial.print("saveslot_incdec: returning item_num="); Serial.println(item_num);
+  return item_num;
 }

 //----------------------------------------
@@ -1235,7 +1335,7 @@
 // adjust the LCD brightness up or down and update menu display
 //----------------------------------------

-void brightness_incdec(int delta)
+int brightness_incdec(int item_num, int delta)
 {
   Serial.print("brightness_incdec: delta="); Serial.println(delta);

@@ -1271,6 +1371,8 @@
   {
     lcd.write(ALLSET_CHAR);
   }
+
+  return item_num;
 }

 //----------------------------------------
@@ -1290,7 +1392,7 @@
 // adjust the LCD contrast up or down and update menu display
 //----------------------------------------

-void contrast_incdec(int delta)
+int contrast_incdec(int item_num, int delta)
 {
   Serial.print("contrast_incdec: delta="); Serial.println(delta);

@@ -1326,6 +1428,8 @@
   {
     lcd.write(ALLSET_CHAR);
   }
+
+  return item_num;
 }

 //----------------------------------------
@@ -1467,56 +1571,6 @@
   put_slot(slot_num, 0L, 0);

 //  savresdel_show(menu, slot_num);  NOT NEEDED?
-}
-
-//----------------------------------------
-//----------------------------------------
-
-void contrast_select(struct Menu *menu, int slot_num)
-{
-  Serial.print("contrast_select(): slot_num="); Serial.println(slot_num);
-
-  // adjust contrast
-  // +/- opposite to that for brightness because increasing
-  // voltage has the opposite effect with contrast
-  if (slot_num == 0)        // "increase" item selected
-    LcdContrast -= 10;
-  else if (slot_num == 1)   // "decrease" item selected
-    LcdContrast += 10;
-  else
-    abort("Bad slot number");
-
-  if (LcdContrast < 0)
-    LcdContrast = 0;
-  if (LcdContrast > 125)
-    LcdContrast = 125;
-  analogWrite(mc_Contrast, LcdContrast);
-  Serial.print("Set contrast to "); Serial.println(LcdContrast);
-  menu_flash();
-}
-
-//----------------------------------------
-//----------------------------------------
-
-void brightness_select(struct Menu *menu, int slot_num)
-{
-  Serial.print("brightness_select(): slot_num="); Serial.println(slot_num);
-
-  if (slot_num == 0)        // "increase" item selected
-    LcdBrightness += 10;
-  else if (slot_num == 1)   // "increase" item selected
-    LcdBrightness -= 10;
-  else
-    abort("Bad slot numvber");
-
-  if (LcdBrightness < 0)
-    LcdBrightness = 0;
-  if (LcdBrightness > 255)
-    LcdBrightness = 255;
-
-  analogWrite(mc_Brightness, LcdBrightness);
-  Serial.print("Set brightness to "); Serial.println(LcdBrightness);
-  menu_flash();
 }

 //----------------------------------------


TW-9: refactored render loop and added flag to check when time is set.

--- tinywatch.ino
+++ tinywatch.ino
@@ -8,6 +8,7 @@
 TinyScreen display = TinyScreen(TinyScreenPlus);
 //Buffer used for drawing.
 RenderBuffer<uint8_t,20> buffer;
+char isTimeSet = 0;

 //Pinouts for TinyShield BLE.
 #define BLE_REQ 10
@@ -34,7 +35,7 @@

 void bleSetup(){
   //Name of BLE peripheral when connecting to master.
-  blePeripheral.setDeviceName("tinywatch");
+  blePeripheral.setLocalName("tinywatch");
   blePeripheral.setAppearance(0xC0);

   //Setting advertising id from service.
@@ -51,12 +52,19 @@

   //Start BLE service.
   blePeripheral.begin();
-  messageWithSecondDelay("searching...");
 }

 void loop() {
   blePeripheral.poll();
-  renderTime();
+  BLECentral central = blePeripheral.central();
+  if(central){
+    while(central.connected()){
+      blePeripheral.poll();
+      renderTime();
+      refreshScreen();
+    }
+  }
+  buffer.drawText("searching...",15,8,buffer.rgb(255,0,0), &virtualDJ_5ptFontInfo);
   refreshScreen();
 }

@@ -66,13 +74,11 @@

 void blePeripheralDisconnectHandler(BLECentral& central) {
   messageWithSecondDelay("disconnected...");
-  messageWithSecondDelay("searching...");
 }

 void setTimeHandler(BLECentral& central, BLECharacteristic& characteristic){
-  messageWithSecondDelay("written...");
   setTime(timeCharacteristic.valueBE());
-  messageWithSecondDelay("time written...");
+  isTimeSet = 1;
 }

 void messageWithSecondDelay(String msg){
@@ -86,9 +92,10 @@
   stringBuffer.reset();
 }

-//TODO: Method to render date.
 void renderTime(){
-  buffer.drawText(((String)hour() + ":" + (String)minute() + ":" + (String)second()).c_str(),15,8,buffer.rgb(255,0,0), &virtualDJ_5ptFontInfo);
+  if(isTimeSet){
+    buffer.drawText(((String)hour() + ":" + (String)minute() + ":" + (String)second()).c_str(),15,8,buffer.rgb(255,0,0), &virtualDJ_5ptFontInfo);
+  }
 }

 //TODO: Method to render date.