Code for autonomous rover for Sparkfun AVC. DataBus won 3rd in 2012 and the same code was used on Troubled Child, a 1986 Jeep Grand Wagoneer to win 1st in 2014.

Dependencies:   mbed Watchdog SDFileSystem DigoleSerialDisp

Files at this revision

API Documentation at this revision

Comitter:
shimniok
Date:
Fri Nov 30 15:41:05 2018 +0000
Parent:
22:dc54ca6e6eec
Child:
24:46318b2bf974
Commit message:
Disabled PinDetect code (for now); fixed attach() calls in various functions to use new callback class.

Changed in this revision

Estimation/Matrix/Matrix.cpp Show annotated file Show diff for this revision Revisions of this file
PinDetect.lib Show diff for this revision Revisions of this file
Schedule/Schedule.cpp Show annotated file Show diff for this revision Revisions of this file
Sensors/Camera/Camera.cpp Show annotated file Show diff for this revision Revisions of this file
Sensors/GPS/Sirf3.cpp Show annotated file Show diff for this revision Revisions of this file
Sensors/GPS/Ublox6.cpp Show annotated file Show diff for this revision Revisions of this file
Sensors/GPS/Venus638flpx.cpp Show annotated file Show diff for this revision Revisions of this file
Sensors/IncrementalEncoder/IncrementalEncoder.cpp Show annotated file Show diff for this revision Revisions of this file
UI/Beep/Beep.cpp Show annotated file Show diff for this revision Revisions of this file
UI/Buttons/Buttons.cpp Show annotated file Show diff for this revision Revisions of this file
UI/Buttons/PinDetect.cpp Show annotated file Show diff for this revision Revisions of this file
UI/Buttons/PinDetect.h Show annotated file Show diff for this revision Revisions of this file
globals.h Show annotated file Show diff for this revision Revisions of this file
logging/logging.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/Estimation/Matrix/Matrix.cpp	Thu Nov 29 19:45:49 2018 +0000
+++ b/Estimation/Matrix/Matrix.cpp	Fri Nov 30 15:41:05 2018 +0000
@@ -1,235 +0,0 @@
-#include <stdio.h>
-#include "Matrix.h"
-
-unsigned int matrix_error = 0;
-
-void Vector_Cross_Product(float C[3], float A[3], float B[3])
-{
-    C[0] = (A[1] * B[2]) - (A[2] * B[1]);
-    C[1] = (A[2] * B[0]) - (A[0] * B[2]);
-    C[2] = (A[0] * B[1]) - (A[1] * B[0]);
-  
-    return;
-}
-
-void Vector_Scale(float C[3], float A[3], float b)
-{
-    for (int m = 0; m < 3; m++)
-        C[m] = A[m] * b;
-        
-    return;
-}
-
-float Vector_Dot_Product(float A[3], float B[3])
-{
-    float result = 0.0;
-
-    for (int i = 0; i < 3; i++) {
-        result += A[i] * B[i];
-    }
-    
-    return result;
-}
-
-void Vector_Add(float C[3], float A[3], float B[3])
-{
-    for (int m = 0; m < 3; m++)
-        C[m] = A[m] + B[m];
-        
-    return;
-}
-
-void Vector_Add(float C[3][3], float A[3][3], float B[3][3])
-{
-    for (int m = 0; m < 3; m++)
-        for (int n = 0; n < 3; n++)
-            C[m][n] = A[m][n] + B[m][n];
-}
-
-void Matrix_Add(float C[3][3], float A[3][3], float B[3][3])
-{
-    for (int i = 0; i < 3; i++) {
-        for (int j = 0; j < 3; j++) {
-           C[i][j] = A[i][j] + B[i][j];
-        }
-    }
-}
-
-void Matrix_Add(int n, int m, float *C, float *A, float *B)
-{
-    for (int i = 0; i < n*m; i++) {
-       C[i] = A[i] + B[i];
-    }
-}
-
-void Matrix_Subtract(int n, int m, float *C, float *A, float *B)
-{
-    for (int i = 0; i < n*m; i++) {
-       C[i] = A[i] - B[i];
-    }
-}
-
-
-
-// grabbed from MatrixMath library for Arduino
-// http://arduino.cc/playground/Code/MatrixMath
-// E.g., the equivalent Octave script:
-//   A=[x; y; z];
-//   B=[xx xy xz; yx yy yz; zx xy zz]; 
-//   C=A*B;
-// Would be called like this:
-//   Matrix_Mulitply(1, 3, 3, C, A, B);
-//
-void Matrix_Multiply(int m, int p, int n, float *C, float *A, float *B)
-{
-    // A = input matrix (m x p)
-    // B = input matrix (p x n)
-    // m = number of rows in A
-    // p = number of columns in A = number of rows in B
-    // n = number of columns in B
-    // C = output matrix = A*B (m x n)
-    for (int i=0; i < m; i++) {
-        for(int j=0; j < n; j++) {
-            C[n*i+j] = 0;
-            for (int k=0; k < p; k++) {
-                C[i*n+j] += A[i*p+k] * B[k*n+j];
-            }
-        }
-    }
-        
-    return;
-}
-
-void Matrix_Multiply(float C[3][3], float A[3][3], float B[3][3])
-{
-    for (int i = 0; i < 3; i++) {
-        for (int j = 0; j < 3; j++) {
-            C[i][j] = 0;
-            for (int k = 0; k < 3; k++) {
-               C[i][j] += A[i][k] * B[k][j];
-            }
-        }
-    }
-}
-
-
-void Matrix_Transpose(int n, int m, float *C, float *A)
-{
-    for (int i=0; i < n; i++) {
-        for (int j=0; j < m; j++) {
-            C[j*n+i] = A[i*m+j];
-        }
-    }
-}
-
-#define fabs(x) (((x) < 0) ? -x : x)
-
-// grabbed from MatrixMath library for Arduino
-// http://arduino.cc/playground/Code/MatrixMath
-//Matrix Inversion Routine
-// * This function inverts a matrix based on the Gauss Jordan method.
-// * Specifically, it uses partial pivoting to improve numeric stability.
-// * The algorithm is drawn from those presented in 
-//     NUMERICAL RECIPES: The Art of Scientific Computing.
-// * NOTE: The argument is ALSO the result matrix, meaning the input matrix is REPLACED
-void Matrix_Inverse(int n, float *A)
-{
-    // A = input matrix AND result matrix
-    // n = number of rows = number of columns in A (n x n)
-    int pivrow=0;   // keeps track of current pivot row
-    int k,i,j;        // k: overall index along diagonal; i: row index; j: col index
-    int pivrows[n]; // keeps track of rows swaps to undo at end
-    float tmp;        // used for finding max value and making column swaps
-    
-    for (k = 0; k < n; k++) {
-        // find pivot row, the row with biggest entry in current column
-        tmp = 0;
-        for (i = k; i < n; i++) {
-            if (fabs(A[i*n+k]) >= tmp) {    // 'Avoid using other functions inside abs()?'
-                tmp = fabs(A[i*n+k]);
-                pivrow = i;
-            }
-        }
-        
-        // check for singular matrix
-        if (A[pivrow*n+k] == 0.0f) {
-            matrix_error |= SINGULAR_MATRIX;
-            //fprintf(stdout, "Inversion failed due to singular matrix");
-            return;
-        }
-        
-        // Execute pivot (row swap) if needed
-        if (pivrow != k) {
-            // swap row k with pivrow
-            for (j = 0; j < n; j++) {
-                tmp = A[k*n+j];
-                A[k*n+j] = A[pivrow*n+j];
-                A[pivrow*n+j] = tmp;
-            }
-        }
-        pivrows[k] = pivrow;    // record row swap (even if no swap happened)
-        
-        tmp = 1.0f/A[k*n+k];    // invert pivot element
-        A[k*n+k] = 1.0f;        // This element of input matrix becomes result matrix
-        
-        // Perform row reduction (divide every element by pivot)
-        for (j = 0; j < n; j++) {
-            A[k*n+j] = A[k*n+j]*tmp;
-        }
-        
-        // Now eliminate all other entries in this column
-        for (i = 0; i < n; i++) {
-            if (i != k) {
-                tmp = A[i*n+k];
-                A[i*n+k] = 0.0f;  // The other place where in matrix becomes result mat
-                for (j = 0; j < n; j++) {
-                    A[i*n+j] = A[i*n+j] - A[k*n+j]*tmp;
-                }
-            }
-        }
-    }
-    
-    // Done, now need to undo pivot row swaps by doing column swaps in reverse order
-    for (k = n-1; k >= 0; k--) {
-        if (pivrows[k] != k) {
-            for (i = 0; i < n; i++) {
-                tmp = A[i*n+k];
-                A[i*n+k] = A[i*n+pivrows[k]];
-                A[i*n+pivrows[k]] = tmp;
-            }
-        }
-    }
-    return;
-}
-
-
-void Matrix_Copy(int n, int m, float *C, float *A)
-{
-    for (int i=0; i < n*m; i++)
-        C[i] = A[i];
-}
-
-void Matrix_print(int n, int m, float *A, const char *name)
-{
-    fprintf(stdout, "%s=[", name);
-    for (int i=0; i < n; i++) {
-        for (int j=0; j < m; j++) {
-            fprintf(stdout, "%5.5f", A[i*m+j]);
-            if (j < m-1) fprintf(stdout, ", ");
-        }
-        if (i < n-1) fprintf(stdout, "; ");
-    }
-    fprintf(stdout, "]\n");
-}  
-
-
-void Vector_Print(float A[3], const char *name)
-{
-    fprintf(stdout, "%s=[ ", name);
-    for (int i=0; i < 3; i++)
-        fprintf(stdout, "%5.5f ", A[i]);
-    fprintf(stdout, "]\n");
-    
-    return;
-}
-
--- a/PinDetect.lib	Thu Nov 29 19:45:49 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-https://os.mbed.com/users/AjK/code/PinDetect/#cb3afc45028b
--- a/Schedule/Schedule.cpp	Thu Nov 29 19:45:49 2018 +0000
+++ b/Schedule/Schedule.cpp	Fri Nov 30 15:41:05 2018 +0000
@@ -38,7 +38,7 @@
         _max = max;
         _mode = m;
         float slope = ((float) stop - (float) start) / (float) max;
-        for (int i=0; i <= max; i++) {
+        for (tick i=0; i <= max; i++) {
             _schedule[i] = ((int) (slope*(float)i)) + start;
         }
     }
--- a/Sensors/Camera/Camera.cpp	Thu Nov 29 19:45:49 2018 +0000
+++ b/Sensors/Camera/Camera.cpp	Fri Nov 30 15:41:05 2018 +0000
@@ -11,7 +11,7 @@
 
 void Camera::start()
 {
-    serial.attach(this, &Camera::receive, Serial::RxIrq);
+    serial.attach(callback(this, &Camera::receive), Serial::RxIrq);
     
     // ping
     // should now get ACK\r or NACK\r
--- a/Sensors/GPS/Sirf3.cpp	Thu Nov 29 19:45:49 2018 +0000
+++ b/Sensors/GPS/Sirf3.cpp	Fri Nov 30 15:41:05 2018 +0000
@@ -28,7 +28,7 @@
 {
     reset_available();
     setBaud(4800);
-    serial.attach(this, &Sirf3::recv_handler, Serial::RxIrq);
+    serial.attach(callback(this, &Sirf3::recv_handler), Serial::RxIrq);
 }
 
 void Sirf3::disable(void)
--- a/Sensors/GPS/Ublox6.cpp	Thu Nov 29 19:45:49 2018 +0000
+++ b/Sensors/GPS/Ublox6.cpp	Fri Nov 30 15:41:05 2018 +0000
@@ -36,7 +36,8 @@
 void Ublox6::enable(void)
 {
     reset_available();
-    serial.attach(this, &Ublox6::recv_handler, Serial::RxIrq);
+    serial.attach(callback(this, &Ublox6::recv_handler), Serial::RxIrq);
+    //attach (T *object, R(T::*member)(A1))
 }
 
 void Ublox6::disable(void)
--- a/Sensors/GPS/Venus638flpx.cpp	Thu Nov 29 19:45:49 2018 +0000
+++ b/Sensors/GPS/Venus638flpx.cpp	Fri Nov 30 15:41:05 2018 +0000
@@ -30,7 +30,7 @@
 void Venus638flpx::enable(void)
 {
     reset_available();
-    serial.attach(this, &Venus638flpx::recv_handler, Serial::RxIrq);
+    serial.attach(callback(this, &Venus638flpx::recv_handler), Serial::RxIrq);
 }
 
 void Venus638flpx::disable(void)
--- a/Sensors/IncrementalEncoder/IncrementalEncoder.cpp	Thu Nov 29 19:45:49 2018 +0000
+++ b/Sensors/IncrementalEncoder/IncrementalEncoder.cpp	Fri Nov 30 15:41:05 2018 +0000
@@ -2,8 +2,8 @@
 
 IncrementalEncoder::IncrementalEncoder(PinName pin):  _lastTicks(0),  _ticks(0), _new(false), _interrupt(pin) {
     _interrupt.mode(PullNone); // default is pulldown but my encoder board uses a pull-up and that just don't work
-    _interrupt.rise(this, &IncrementalEncoder::_incRise); 
-    _interrupt.fall(this, &IncrementalEncoder::_incFall); 
+    _interrupt.rise(callback(this, &IncrementalEncoder::_incRise)); 
+    _interrupt.fall(callback(this, &IncrementalEncoder::_incFall)); 
     _t.start();
     _t.reset();
     _lastTime = _t.read_us();
--- a/UI/Beep/Beep.cpp	Thu Nov 29 19:45:49 2018 +0000
+++ b/UI/Beep/Beep.cpp	Fri Nov 30 15:41:05 2018 +0000
@@ -25,7 +25,7 @@
 
     _pwm.period(1.0/freq);
     _pwm.write(0.5);            // 50% duty cycle - beep on
-    toff.attach(this,&Beep::nobeep, time);   // time to off
+    toff.attach(callback(this, &Beep::nobeep), time);   // time to off
 }
 
 
--- a/UI/Buttons/Buttons.cpp	Thu Nov 29 19:45:49 2018 +0000
+++ b/UI/Buttons/Buttons.cpp	Fri Nov 30 15:41:05 2018 +0000
@@ -1,18 +1,18 @@
 #include "devices.h"
 #include "Buttons.h"
-#include "PinDetect.h"
 
-PinDetect nextButton(BUTTONNEXT);
-PinDetect selectButton(BUTTONSELECT);            // Input selectButton
-PinDetect prevButton(BUTTONPREV);
+//PinDetect nextButton(BUTTONNEXT);
+//PinDetect selectButton(BUTTONSELECT);            // Input selectButton
+//PinDetect prevButton(BUTTONPREV);
 
-Buttons::Buttons(void): which(0), pressed(false)
+Buttons::Buttons(void): 
+    which(0), pressed(false)
 {
 }
 
 void Buttons::init()
 {
-
+/*
     // Set up button (plugs into two GPIOs, active low
     selectButton.mode(PullUp);
     selectButton.setSamplesTillAssert(50);
@@ -31,6 +31,7 @@
     prevButton.setAssertValue(0); // active low logic
     prevButton.setSampleFrequency(50); // us
     prevButton.attach_asserted( this, &Buttons::prevPressed );
+*/
 }
 
 void Buttons::nextPressed() 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI/Buttons/PinDetect.cpp	Fri Nov 30 15:41:05 2018 +0000
@@ -0,0 +1,154 @@
+/*
+    by Michael Shimniok
+    
+    based on PinDetect Copyright (c) 2010 Andy Kirkham
+
+    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.
+*/
+
+#if 0
+
+#include "PinDetect.h"
+
+/** initialise class */
+void PinDetect::init(PinName p, PinMode m) {
+    _sampleTime              = PINDETECT_SAMPLE_PERIOD;
+    _samplesTillAssert       = PINDETECT_ASSERT_COUNT;
+    _samplesTillHeld         = 0;
+    _samplesTillAssertReload = PINDETECT_ASSERT_COUNT;
+    _samplesTillHeldReload   = PINDETECT_HOLD_COUNT;
+    _assertValue             = PINDETECT_PIN_ASSTERED;
+
+    _in = new DigitalIn( p );
+    _in->mode( m );
+    _prevState = _in->read();
+    _ticker = new Ticker;
+}
+
+
+void PinDetect::isr(void) {
+/*
+    int currentState = _in->read();
+
+    if ( currentState != _prevState ) {
+        if ( _samplesTillAssert == 0 ) {
+            _prevState = currentState;
+            _samplesTillHeld = _samplesTillHeldReload;
+            if ( currentState == _assertValue )
+                _callbackAsserted.call();
+            else
+                _callbackDeasserted.call();
+        }
+        else {
+            _samplesTillAssert--;
+        }
+    }
+    else {
+        _samplesTillAssert = _samplesTillAssertReload;
+    }
+
+    if ( _samplesTillHeld ) {
+        if ( _prevState == currentState ) {
+            _samplesTillHeld--;
+            if ( _samplesTillHeld == 0 ) {
+                if ( currentState == _assertValue )
+                    _callbackAssertedHeld.call();
+                else
+                    _callbackDeassertedHeld.call();
+            }
+        }
+        else {
+            _samplesTillHeld = 0;
+        }
+    }
+    */
+}
+
+
+PinDetect::PinDetect(PinName p) {
+    init( p, PullDown );
+}
+
+PinDetect::PinDetect(PinName p, PinMode m) {
+    init( p, m );
+}
+
+PinDetect::~PinDetect() {
+    if ( _ticker )  delete( _ticker );
+    if ( _in )      delete( _in );
+}
+
+void PinDetect::setSampleFrequency(int i) {
+    _sampleTime = i;
+    _prevState  = _in->read();
+    //_ticker->attach_us( this, &PinDetect::isr, _sampleTime );
+}
+
+void PinDetect::setAssertValue (int i) {
+     _assertValue = i & 1; 
+}
+
+void PinDetect::setSamplesTillAssert(int i) {
+    _samplesTillAssertReload = i; 
+}
+
+void PinDetect::setSamplesTillHeld(int i) { 
+    _samplesTillHeldReload = i; 
+}
+
+void PinDetect::mode(PinMode m) { 
+    _in->mode( m ); 
+}
+
+void PinDetect::attach_asserted(Callback function) {
+  _callbackAsserted = function;
+}
+
+template<typename T>
+void PinDetect::attach_asserted(T *object, void (T::*member)(void)) {
+//    _callbackAsserted.attach( object, member );
+}
+
+void PinDetect::attach_deasserted(void (*function)(void)) {
+//    _callbackDeasserted.attach( function );
+}
+
+template<typename T>
+void PinDetect::attach_deasserted(T *object, void (T::*member)(void)) {
+//    _callbackDeasserted.attach( object, member );
+}
+
+void PinDetect::attach_asserted_held(void (*function)(void)) {
+//    _callbackAssertedHeld.attach( function );
+}
+template<typename T>
+void PinDetect::attach_asserted_held(T *object, void (T::*member)(void)) {
+//    _callbackAssertedHeld.attach( object, member );
+}
+
+void PinDetect::attach_deasserted_held(void (*function)(void)) {
+//    _callbackDeassertedHeld.attach( function );
+}
+
+template<typename T>
+void PinDetect::attach_deasserted_held(T *object, void (T::*member)(void)) {
+//    _callbackDeassertedHeld.attach( object, member );
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI/Buttons/PinDetect.h	Fri Nov 30 15:41:05 2018 +0000
@@ -0,0 +1,412 @@
+/*
+    by Michael Shimniok
+    
+    based on PinDetect Copyright (c) 2010 Andy Kirkham
+
+    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.
+*/
+
+#if 0
+
+#ifndef AJK_PIN_DETECT_H
+#define AJK_PIN_DETECT_H
+
+#include "mbed.h"
+
+#define PINDETECT_PIN_ASSTERED   1
+#define PINDETECT_SAMPLE_PERIOD 20000
+#define PINDETECT_ASSERT_COUNT  1
+#define PINDETECT_HOLD_COUNT    50
+
+/** PinDetect adds mechanical switch debouncing to DigitialIn and interrupt callbacks.
+ *
+ * This is done by sampling the specified pin at regular intervals and detecting any
+ * change of state ( 0 -> 1 or 1 -> 0 ). When a state change is detected the attached
+ * callback handler is called. Additionally, if the pin stays in the same state after
+ * a state change for a defined period of time, an extra callback is made allowing a
+ * program to detect when a "key is pressed and held down" rather than a momentary
+ * key/switch press.
+ *
+ * All parameters are customisable which include:-
+ *  <ul>
+ *  <li> The sampling frequency. </li>
+ *  <li> The number of continuous samples until a state change is detected. </li>
+ *  <li> The number of continuous samples until a key is assumed held after a state change. </li>
+ *  <li> The logic level which is assumed to be asserted (0volts or +volts). </li>
+ *  </ul>
+ *
+ * Only callbacks that have been attached will be called by the library.
+ *
+ * Example:
+ * @code
+ * #include "mbed.h"
+ * #include "PinDetect.h"
+ *
+ * PinDetect  pin( p30 );
+ * DigitialOut led1( LED1 );
+ * DigitialOut led2( LED2 );
+ * DigitialOut led3( LED3 );
+ * DigitialOut led4( LED4 );
+ *
+ * void keyPressed( void ) {
+ *     led2 = 1;
+ *     led3 = 0;
+ *     led4 = 0;
+ * }
+ *
+ * void keyReleased( void ) {
+ *     led2 = 0;
+ *     led3 = 0;
+ *     led4 = 0;
+ * }
+ *
+ * void keyPressedHeld( void ) {
+ *     led3 = 1;
+ * }
+ *
+ * void keyReleasedHeld( void ) {
+ *     led4 = 1;
+ * }
+ *
+ * int main() {
+ *
+ *     pin.mode( PullDown );
+ *     pin.attach_asserted( &keyPressed );
+ *     pin.attach_deasserted( &keyReleased );
+ *     pin.attach_asserted_held( &keyPressedHeld );
+ *     pin.attach_deasserted_held( &keyReleasedHeld );
+ *
+ *     // Sampling does not begin until you set a frequency.
+ *     // The default is 20ms. If you want a different frequency
+ *     // then pass the period in microseconds for example, for 10ms :-
+ *     //     pin.setSampleFrequency( 10000 );
+ *     //
+ *     pin.setSampleFrequency(); // Defaults to 20ms.
+ *
+ *     while( 1 ) {
+ *         led1 = !led1;
+ *         wait( 0.2 );
+ *     }
+ * }
+ * @endcode
+ *
+ * This example will flash led1 in a similar to a standard starting program.
+ *
+ * Applying a "1" (switch on) to pin 30 will switch on led2, removing the "1" to "0"
+ * (switch off) led2 goes out. Holding the "switch" at one for one second will switch
+ * on led3. An unasserted P30 (switched off) will, after one second illuminate led4
+ * when the deasserted calledback is called.
+ *
+ * The above is a very basic introduction. For more details:-
+ * @see example.h
+ */
+class PinDetect {
+
+protected:
+    DigitalIn   *_in;
+    Ticker      *_ticker;
+    int         _prevState;
+    int         _currentStateCounter;
+    int         _sampleTime;
+    int         _assertValue;
+    int         _samplesTillAssertReload;
+    int         _samplesTillAssert;
+    int         _samplesTillHeldReload;
+    int         _samplesTillHeld;
+    //FunctionPointer _callbackAsserted;
+    //FunctionPointer _callbackDeasserted;
+    //FunctionPointer _callbackAssertedHeld;
+    //FunctionPointer _callbackDeassertedHeld;
+
+    /** initialise class
+     *
+     * @param PinName p is a valid pin that supports DigitalIn
+     * @param PinMode m The mode the DigitalIn should use.
+     */
+    void init(PinName p, PinMode m); 
+
+    /** The Ticker periodic callback function
+     */
+    void isr(void);
+
+public:
+
+    friend class Ticker;
+
+    /** PinDetect constructor
+     *
+     * By default the PinMode is set to PullDown.
+     *
+     * @see http://mbed.org/handbook/DigitalIn
+     * @param p PinName is a valid pin that supports DigitalIn
+     */
+    PinDetect(PinName p);
+
+    /** PinDetect constructor
+     *
+     * @see http://mbed.org/handbook/DigitalIn
+     * @param PinName p is a valid pin that supports DigitalIn
+     * @param PinMode m The mode the DigitalIn should use.
+     */
+    PinDetect(PinName p, PinMode m);
+
+    /** PinDetect destructor
+     */
+    ~PinDetect();
+
+    /** Set the sampling time in microseconds.
+     *
+     * @param int The time between pin samples in microseconds.
+     */
+    void setSampleFrequency(int i = PINDETECT_SAMPLE_PERIOD);
+
+    /** Set the value used as assert.
+     *
+     * Defaults to 1 (ie if pin == 1 then pin asserted).
+     *
+     * @param int New assert value (1 or 0)
+     */
+    void setAssertValue(int i = PINDETECT_PIN_ASSTERED);
+
+    /** Set the number of continuous samples until assert assumed.
+     *
+     * Defaults to 1 (1 * sample frequency).
+     *
+     * @param int The number of continuous samples until assert assumed.
+     */
+    void setSamplesTillAssert(int i);
+
+    /** Set the number of continuous samples until held assumed.
+     *
+     * Defaults to 50 * sample frequency.
+     *
+     * @param int The number of continuous samples until held assumed.
+     */
+    void setSamplesTillHeld(int i);
+
+    /** Set the pin mode.
+     *
+     * @see http://mbed.org/projects/libraries/api/mbed/trunk/DigitalInOut#DigitalInOut.mode
+     * @param PinMode m The mode to pass on to the DigitalIn
+     */
+    void mode(PinMode m);
+
+    /** Attach a callback function
+     *
+     * @code
+     *
+     * DigitalOut led1( LED1 );
+     * PinDetect pin( p30 );
+     *
+     * void myCallback( void ) {
+     *   led1 = 1;
+     * };
+     *
+     * main() {
+     *     pin.attach_asserted( &myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is asserted.
+     * @param function A C function pointer
+     */
+    void attach_asserted(Callback function);
+
+    /** Attach a callback object/method
+     *
+     * @code
+     *
+     * class Bar {
+     *   public:
+     *     void myCallback( void ) { led1 = 1; }
+     * };
+     *
+     * DigitalOut led1( LED1 );
+     * PinDetect pin( p30 );
+     * Bar bar;
+     *
+     * main() {
+     *     pin.attach_asserted( &bar, &Bar::myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is asserted.
+     * @param object An object that conatins the callback method.
+     * @param method The method within the object to call.
+     */
+    template<typename T>
+    void attach_asserted(T *object, void (T::*member)(void));
+
+    /** Attach a callback function
+     *
+     * @code
+     *
+     * DigitalOut led1( LED1 );
+     * PinDetect pin( p30 );
+     *
+     * void myCallback( void ) {
+     *   led1 = 0;
+     * };
+     *
+     * main() {
+     *     pin.attach_deasserted( &myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is deasserted.
+     * @param function A C function pointer
+     */
+    void attach_deasserted(void (*function)(void));
+
+    /** Attach a callback object/method
+     *
+     * @code
+     *
+     * class Bar {
+     *   public:
+     *     void myCallback( void ) { led1 = 0; }
+     * };
+     *
+     * DigitalOut led1( LED1 );
+     * PinDetect pin( p30 );
+     * Bar bar;
+     *
+     * main() {
+     *     pin.attach_deasserted( &bar, &Bar::myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is deasserted.
+     * @param object An object that conatins the callback method.
+     * @param method The method within the object to call.
+     */
+    template<typename T>
+    void attach_deasserted(T *object, void (T::*member)(void));
+
+    /** Attach a callback function
+     *
+     * @code
+     *
+     * DigitalOut led2( LED2 );
+     * PinDetect pin( p30 );
+     *
+     * void myCallback( void ) {
+     *   led2 = 1;
+     * };
+     *
+     * main() {
+     *     pin.attach_asserted_held( &myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is asserted and held.
+     * @param function A C function pointer
+     */
+    void attach_asserted_held(void (*function)(void));
+
+    /** Attach a callback object/method
+     *
+     * @code
+     *
+     * class Bar {
+     *   public:
+     *     void myCallback( void ) { led2 = 0; }
+     * };
+     *
+     * DigitalOut led2( LED2 );
+     * PinDetect pin( p30 );
+     * Bar bar;
+     *
+     * main() {
+     *     pin.attach_asserted_held( &bar, &Bar::myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is asserted and held.
+     * @param object An object that conatins the callback method.
+     * @param method The method within the object to call.
+     */
+    template<typename T>
+    void attach_asserted_held(T *object, void (T::*member)(void));
+
+    /** Attach a callback function
+     *
+     * @code
+     *
+     * DigitalOut led3( LED3 );
+     * PinDetect pin( p30 );
+     *
+     * void myCallback( void ) {
+     *   led3 = 1;
+     * };
+     *
+     * main() {
+     *     pin.attach_deasserted_held( &myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is deasserted and held.
+     * @param function A C function pointer
+     */
+    void attach_deasserted_held(void (*function)(void));
+
+    /** Attach a callback object/method
+     *
+     * @code
+     *
+     * class Bar {
+     *   public:
+     *     void myCallback( void ) { led3 = 0; }
+     * };
+     *
+     * DigitalOut led3( LED3 );
+     * PinDetect pin( p30 );
+     * Bar bar;
+     *
+     * main() {
+     *     pin.attach_deasserted_held( &bar, &Bar::myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is deasserted and held.
+     * @param object An object that conatins the callback method.
+     * @param method The method within the object to call.
+     */
+    template<typename T>
+    void attach_deasserted_held(T *object, void (T::*member)(void));
+
+    /** operator int()
+     *
+     * Read the value of the pin being sampled.
+     */
+    operator int() { return _in->read(); }
+
+};
+
+#endif
+
+#endif
--- a/globals.h	Thu Nov 29 19:45:49 2018 +0000
+++ b/globals.h	Fri Nov 30 15:41:05 2018 +0000
@@ -15,7 +15,7 @@
 #include "SerialGraphicLCD.h"
 
 extern Steering steering;
-extern Serial pc;
+//extern Serial pc;
 extern SerialGraphicLCD lcd;
 extern Buttons keypad;
 
--- a/logging/logging.cpp	Thu Nov 29 19:45:49 2018 +0000
+++ b/logging/logging.cpp	Fri Nov 30 15:41:05 2018 +0000
@@ -1,273 +0,0 @@
-#include "SystemState.h"
-#include "globals.h"
-#include "logging.h"
-#include "SDFileSystem.h"
-#include "SerialGraphicLCD.h"
-
-// TODO 2 set up logging out of low priority interrupt handler
-
-//SDFileSystem sd(p5, p6, p7, p8, "log"); // mosi, miso, sclk, cs
-static FILE *logp;
-
-Timer logtimer;
-//extern int bufCount;
-
-/*
-void logData( const SystemState s ) {
-    unsigned char buf[512]; // for now we really only need ~256 bytes but in case I add more to state...
-    unsigned char *state = (unsigned char *) &s;
-    //unsigned int t1, t2, t3;
-    //logtimer.start();
-    //logtimer.reset();
-    if (logp) {
-        //t1 = logtimer.read_us();
-        encode(state, sizeof(s), buf, 0); // infinite line size
-        //t2 = logtimer.read_us();
-        fputs((char *) buf, logp);
-        fputs("\n", logp);
-        bufCount--;
-        fprintf(stdout, "bufCount: %d\n", bufCount);
-        //t3 = logtimer.read_us();
-        //fprintf(stdout, "%d %d\n", t3-t2, t2-t1);
-    }
-}
-*/
-
-// from Arduino source
-size_t printNumber(FILE *f, unsigned long n)
-{
-    char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
-    char *str = &buf[sizeof(buf) - 1];
-
-    *str = '\0';
-
-    do {
-        unsigned long m = n;
-        n /= 10;
-        char c = m - 10 * n;
-        *--str = c + '0';
-    } while(n);
-
-    return fputs(str, f);
-}
-
-// from Arduino source
-size_t printInt(FILE *f, long n)
-{
-    int t = 0;
-    if (n < 0) {
-        t = fputc('-', f);
-        n = -n;
-    }
-    return printNumber(f, n) + t;
-}
-
-// from Arduino source
-size_t printFloat(FILE *f, double number, uint8_t digits)
-{
-    size_t n=0;
-
-    if (isnan(number)) return fputs("nan", f);
-    if (isinf(number)) return fputs("inf", f);
-    if (number > 4294967040.0) return fputs("ovf", f);  // constant determined empirically
-    if (number <-4294967040.0) return fputs("ovf", f);  // constant determined empirically
-
-    // Handle negative numbers
-    if (number < 0.0) {
-        n += fputc('-', f);
-        number = -number;
-    }
-
-    // Round correctly so that print(1.999, 2) prints as "2.00"
-    double rounding = 0.5;
-    for (uint8_t i=0; i < digits; ++i)
-        rounding /= 10.0;
-
-    number += rounding;
-
-    // Extract the integer part of the number and print it
-    unsigned long int_part = (unsigned long)number;
-    double remainder = number - (double)int_part;
-    n += printInt(f, int_part);
-
-    // Print the decimal point, but only if there are digits beyond
-    if (digits > 0) {
-        n += fputc('.', f);
-    }
-
-    // Extract digits from the remainder one at a time
-    while (digits-- > 0) {
-        remainder *= 10.0;
-        int toPrint = int(remainder);
-        n += fputc(toPrint+'0', f);
-        remainder -= toPrint;
-    }
-
-    return n;
-}
-
-
-// If I use arduino style print routines, logging takes ~1000 / ~8000 usec
-// the big sprintf takes ~ 700-750 usec all by itself
-void logData( SystemState *s )
-{
-    //char buf[256];
-    //unsigned int t1, t2;
-    //logtimer.start();
-    //logtimer.reset();
-    //t1 = logtimer.read_us();
-
-    if (s) {
-        printInt(logp, s->millis);
-        fputc(',',logp);
-        printFloat(logp, s->current, 2);
-        fputc(',',logp);
-        printFloat(logp, s->voltage, 2);
-        fputc(',',logp);
-        for (int q=0; q < 3; q++) {
-            printFloat(logp, s->gyro[q], 6);
-            fputc(',',logp);
-        }
-        printInt(logp, s->gTemp);
-        fputc(',',logp);
-        for (int q=0; q < 3; q++) {
-            printInt(logp, s->a[q]);
-            fputc(',',logp);
-        }
-        /*
-        for (int q=0; q < 3; q++) {
-            printInt(logp, s->m[q]);
-            fputc(',',logp);
-        }
-        */
-        printFloat(logp, s->gHeading, 2);
-        fputc(',',logp);
-
-        // GPS 1
-        fprintf(logp, "%.7f,%.7f,", s->gpsLatitude, s->gpsLongitude);
-        //printFloat(logp, s->gpsLatitude, 7);
-        //fputc(',',logp);
-        //printFloat(logp, s->gpsLongitude, 7);
-        //fputc(',',logp);
-        printFloat(logp, s->gpsCourse_deg, 2);
-        fputc(',',logp);
-        printFloat(logp, s->gpsSpeed_mps, 2);
-        fputc(',',logp);
-        printFloat(logp, s->gpsHDOP, 1);
-        fputc(',',logp);
-        printInt(logp, s->gpsSats);
-        fputc(',',logp);
-        // Encoders
-        printFloat(logp, s->lrEncDistance, 7);
-        fputc(',',logp);
-        printFloat(logp, s->rrEncDistance, 7);
-        fputc(',',logp);
-        printFloat(logp, s->lrEncSpeed, 2);
-        fputc(',',logp);
-        printFloat(logp, s->rrEncSpeed, 2);
-        fputc(',',logp);
-        printFloat(logp, s->encHeading, 2);
-        fputc(',',logp);
-        // Estimates
-        printFloat(logp, s->estHeading, 2);
-        fputc(',',logp);
-        printFloat(logp, s->estLagHeading, 2);
-        fputc(',',logp);
-        printFloat(logp, s->estLatitude,  7);
-        fputc(',',logp);
-        printFloat(logp, s->estLongitude, 7);
-        fputc(',',logp);
-        printFloat(logp, s->estX, 4);
-        fputc(',',logp);
-        printFloat(logp, s->estY, 4);
-        fputc(',',logp);
-        // Nav
-        printInt(logp, s->nextWaypoint);
-        fputc(',',logp);
-        printFloat(logp, s->bearing, 2);
-        fputc(',',logp);
-        printFloat(logp, s->distance, 3);
-        fputc(',',logp);
-        printFloat(logp, s->steerAngle, 3);
-        fputc(',',logp);
-        printFloat(logp, s->errHeading, 3);
-        fputc(',',logp);
-        printFloat(logp, s->LABrg, 2);
-        fputc(',',logp);
-        printFloat(logp, s->LAx, 4);
-        fputc(',',logp);
-        printFloat(logp, s->LAy, 4);
-        fputc('\n',logp);
-        fflush(logp);
-
-        //t2 = logtimer.read_us();
-        //fprintf(stdout, "%d\n", t2-t1);
-    }
-
-    return;
-}
-
-
-FILE *openlog(const char *prefix)
-{
-    FILE *fp = 0;
-    char myname[64];
-
-    pc.printf("Opening file...\n");
-
-    while (fp == 0) {
-        sprintf(myname, "%s/test.txt", LOGDIR);
-        if ((fp = fopen(myname, "w")) == 0) {
-            pc.printf("Waiting for filesystem to come online...");
-            wait(0.200);
-            lcd.pos(0,1);
-            lcd.printf("%-16s", "Waiting for fs");
-        }
-    }
-    fclose(fp);
-
-    for (int i = 0; i < 1000; i++) {
-        sprintf(myname, "%s/%s%03d.csv", LOGDIR, prefix, i);
-        if ((fp = fopen(myname, "r")) == 0) {
-            break;
-        } else {
-            fclose(fp);
-        }
-    }
-    fp = fopen(myname, "w");
-    if (fp == 0) {
-        pc.printf("file write failed: %s\n", myname);
-    } else {
-
-        // TODO 3 set error message, get rid of writing to terminal
-
-        //status = true;
-        pc.printf("opened %s for writing\n", myname);
-        lcd.pos(0,1);
-        lcd.printf("%-16s", myname);
-    }
-
-    return fp;
-}
-
-
-// Find the next unused filename of the form logger##.csv where # is 0-9
-//
-bool initLogfile()
-{
-    bool status = false;
-
-    logp = openlog("log");
-
-    if (logp != 0) {
-        status = true;
-        //fprintf(logp, "s.millis, s.current, s.voltage, s.gx, s.gy, s.gz, s.gTemp, s.ax, s.ay, s.az, s.mx, s.my, s.mz, s.gHeading, s.cHeading, s.roll, s.pitch, s.yaw, s.gpsLatitude, s.gpsLongitude, s.gpsCourse, s.gpsSpeed, s.gpsHDOP, s.lrEncDistance, s.rrEncDistance, s.lrEncSpeed, s.rrEncSpeed, s.encHeading, s.estHeading, s.estLatitude, s.estLongitude, s.estNorthing, s.estEasting, s.estX, s.estY, s.nextWaypoint, s.bearing, s.distance, s.gbias, s.errAngle, s.leftRanger, s.rightRanger, s.centerRanger, s.crossTrackErr\n");
-    }
-
-    return status;
-}
-
-void closeLogfile(void)
-{
-    if (logp) fclose(logp);
-}