Então PARA...

Dependencies:   MenuLCD mbed

Files at this revision

API Documentation at this revision

Comitter:
ViniR
Date:
Fri May 19 13:07:52 2017 +0000
Commit message:
Ent?o PARA...

Changed in this revision

TextLCD_HelloWorld2.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
menbed/displays/include/menbedDisplayHD44780.h Show annotated file Show diff for this revision Revisions of this file
menbed/displays/menbedDisplayHD44780.cpp Show annotated file Show diff for this revision Revisions of this file
menbed/include/menbed.h Show annotated file Show diff for this revision Revisions of this file
menbed/include/menbedButtonEvent.h Show annotated file Show diff for this revision Revisions of this file
menbed/include/menbedButtonHandler.h Show annotated file Show diff for this revision Revisions of this file
menbed/include/menbedButtonHandlerTimespec.h Show annotated file Show diff for this revision Revisions of this file
menbed/include/menbedDisplay.h Show annotated file Show diff for this revision Revisions of this file
menbed/include/menbedDisplayer.h Show annotated file Show diff for this revision Revisions of this file
menbed/include/menbedMenu.h Show annotated file Show diff for this revision Revisions of this file
menbed/include/menbedMenuItem.h Show annotated file Show diff for this revision Revisions of this file
menbed/include/menbedMenuMessage.h Show annotated file Show diff for this revision Revisions of this file
menbed/include/menbedMenuParam.h Show annotated file Show diff for this revision Revisions of this file
menbed/include/menbedNavigator.h Show annotated file Show diff for this revision Revisions of this file
menbed/include/menbedRefresher.h Show annotated file Show diff for this revision Revisions of this file
menbed/include/menbedStructure.h Show annotated file Show diff for this revision Revisions of this file
menbed/menbed.cpp Show annotated file Show diff for this revision Revisions of this file
menbed/menbedButtonHandler.cpp Show annotated file Show diff for this revision Revisions of this file
menbed/menbedButtonHandlerTimespec.cpp Show annotated file Show diff for this revision Revisions of this file
menbed/menbedDisplayer.cpp Show annotated file Show diff for this revision Revisions of this file
menbed/menbedMenu.cpp Show annotated file Show diff for this revision Revisions of this file
menbed/menbedMenuItem.cpp Show annotated file Show diff for this revision Revisions of this file
menbed/menbedMenuMessage.cpp Show annotated file Show diff for this revision Revisions of this file
menbed/menbedMenuParam.cpp Show annotated file Show diff for this revision Revisions of this file
menbed/menbedNavigator.cpp Show annotated file Show diff for this revision Revisions of this file
menbed/menbedRefresher.cpp Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 92357d1220f3 TextLCD_HelloWorld2.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TextLCD_HelloWorld2.lib	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/users/ViniR/code/MenuLCD/#8ed644ed983b
diff -r 000000000000 -r 92357d1220f3 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,311 @@
+#include "mbed.h"
+#include "menbed.h"
+#include "TextLCD.h"
+#include "Adafruit_ST7735.h"
+
+Serial pc(USBTX, USBRX);
+DigitalIn enable(D2);
+//float photocellVoltage(void) {return 0;}
+
+Adafruit_ST7735 tft(D11, D12, D13, D10, D8, D9); // MOSI, MISO, SCLK, SSEL, TFT_DC, TFT_RST
+
+void testlines(uint16_t color);
+void testfastlines(uint16_t color1, uint16_t color2);
+void IniciandoMaquina(void);
+void Alerta(void);
+void MenuPrincipal(void);
+void Aguarde(void);
+void Executando(void);
+
+//Serial pc(USBTX, USBRX); // tx, rx
+//I2C i2c_lcd(D14,D15); // SDA, SCL
+//TextLCD_I2C lcd(&i2c_lcd, 0x7E, TextLCD::LCD20x4);                  // I2C exp: I2C bus, PCF8574 Slaveaddress, LCD Type
+
+int main() {
+    
+    // Use this initializer if you're using a 1.8" TFT
+    tft.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab
+
+    //iniciando máquina
+    IniciandoMaquina();
+    wait_ms(5000);
+    Alerta();
+    wait_ms(5000);
+    MenuPrincipal();
+    wait_ms(5000);
+    Aguarde();
+    wait_ms(5000);
+    Executando();
+    wait_ms(5000);
+    //InicioProcessoReferenciamento();
+    //wait_ms(5000);
+    
+
+//lcd.setBacklight(TextLCD::LightOn);
+
+    // Declare all the submenus so that they can be referenced in the
+    // definitions of other menus
+    MenbedMenu *rootMenu;
+    MenbedMenu *measurementMenu;
+    MenbedMenu *controlMenu;
+    MenbedMenu *aboutMenu;
+
+    // Root menu--to create a menu, we first create an array of pointers to 
+    // all the menu items that will populate the menu.  The MenbedMenuItem
+    // constructor take five arguments: the function to be executed when the
+    // item is selected; the child menu to open when the item is selected;
+    // a boolean indicating whether the child menu is actually this menu's
+    // ancestor, (useful when creating "go to root menu" items); a parameter
+    // object that holds a value to be viewed or modified; and a text string
+    // indicating what the menu item should say.  The text string may contain
+    // a printf-style specifier for a float that is bracketed by \t characters
+    // to offset it from the surrounding text.  If the float specified is
+    // found, it will be replaced by the value of the parameter.
+    MenbedMenuItem *rootMenuItems[5] = {
+        new MenbedMenuItem (NULL, &measurementMenu, false, NULL, "Controle Manual"), // function,child,bollean,data,text
+        new MenbedMenuItem (NULL, &controlMenu, false, NULL, "Arquivos"),
+        new MenbedMenuItem (NULL, &aboutMenu, false, NULL, "Configuracoes"),
+        new MenbedMenuItem (NULL, &rootMenu, false, NULL, "Referenciamento"),
+        new MenbedMenuItem (NULL, &rootMenu, false, NULL, "Capacitivo"),
+    };
+    // After we have the array of pointers to menu items, we pass the number of
+    // elements in the arry and the array itself to the MenbedMenu constructor.
+    rootMenu = new MenbedMenu (5, rootMenuItems);
+
+    // Measurements menu--the first item of the measurement menu displays the
+    // voltage and the resistor divider junction formed between a photocell and
+    // a fixed resistor.  To print this voltage as part of a menu item, we
+    // create a MenbedMenuParam object that takes as arguments to its
+    // constructor: a pointer to a function that returns a float containing the
+    // value of the parameter; a pointer to a function that we would call to 
+    // change the value of the parameter; a boolean (irrevelant here)
+    // indicating whether the parameter, if it were modifiable by the user, 
+    // should be updated as the user is changing its value or whether its
+    // should only be updated after the user has confirmed the new value; a 
+    // minimum value for the parameter; a maximum value; and a step size.
+       //MenbedMenuParam photocellParam (photocellVoltage, NULL, false, 0.0, 0.0, 0.0);
+       
+    // Having created the parameter, we pass it as the 4th argument of the 
+    // MenbedMenuItem constructor.  Note the \t-offset %.2f format specified
+    // in the menu item text.  The menu system will call the photocellVoltage
+    // function specified in the parameter constructor above and then print the
+    // float that it returns in place of the %.2f in the menu text.
+
+    MenbedMenuItem *measurementMenuItems[2] = {
+        //new MenbedMenuItem (NULL, NULL, false, &photocellParam, "Photocell: \t%.2f\tV"),
+        new MenbedMenuItem (NULL, &rootMenu, true, NULL, "lee") };
+    measurementMenu = new MenbedMenu (2, measurementMenuItems);
+
+    // Controls menu--We have modifiable parameters in the first and second
+    // meu items of the controls menu.  Walking through the first parameter
+    // constructor, the getLed1Pwm function pointer points to a function that
+    // returns the current value of the PWM duty cycle.  The setLed1Pwm 
+    // function pointer points to a function which sets the PWM duty cycle.
+    // The boolean set to true indicates that as soon as the user makes a 
+    // change to the parameter, the setLed1Pwm function will be called.  The
+    // menu system will not wait for the user to confirm his change before
+    // making the call.  The 0.0 and 100.0 represent the minimum and 
+    // maximum PWM values.  The final 1.0 paramter is the step size when
+    // changing the PWM duty cycle.
+ //   MenbedMenuParam pwmParam1 (getLed1Pwm, setLed1Pwm, true, 0.0, 100.0, 1.0);
+    // The only different in this parameter from the one above is that the PWM
+    // duty cycle is not updated (setLed2Pwm is not called) until the user
+    // confirms the new duty cycle.  If the user cancels his modifications
+    // (either by pushing the cancel button or pushing and holding the select
+    // button) setLed2PWM is never called.
+   // MenbedMenuParam pwmParam2 (getLed2Pwm, setLed2Pwm, false, 0.0, 100.0, 1.0);
+    // The third, fourth, and fifth items of the control menu demonstrate
+    // functions when a menu item is selected.  The ability to call a function
+    // can be combined with either displaying a submenu or editing a parameter.
+    MenbedMenuItem *controlMenuItems[6] = {
+      //  new MenbedMenuItem (NULL, NULL, false, &pwmParam1, "LED1 PWM: \t%.0f\t%"),
+      //  new MenbedMenuItem (NULL, NULL, false, &pwmParam2, "LED2 PWM: \t%.0f\t%"),
+      //  new MenbedMenuItem (toggleLed3, NULL, false, NULL, "Toggle LED3"),
+       // new MenbedMenuItem (lightLed4, NULL, false, NULL, "Light LED4"),
+       // new MenbedMenuItem (extinguishLed4, NULL, false, NULL, "Extinguish LED4"),
+        new MenbedMenuItem (NULL, &rootMenu, true, NULL, "Home") };
+    controlMenu = new MenbedMenu (6, controlMenuItems);       
+
+    // About menu--there's nothing fancy here, but the lack of a "Home" item
+    // forces the user to employ the cancel button, either directly or by
+    // pushing and hold the select button, to return to the root menu.
+    MenbedMenuItem *aboutMenuItems[3] = {
+        new MenbedMenuItem (NULL, NULL, false, NULL, "     NXP3915"),
+        new MenbedMenuItem (NULL, NULL, false, NULL, "  Copyright 2011"),
+        new MenbedMenuItem (NULL, NULL, false, NULL, " xxxxxxxx@xxx.xxx") };
+    aboutMenu = new MenbedMenu (3, aboutMenuItems);
+            
+    // Having created the menus, menu items, and item parameters, we are ready
+    // to instantiate the display.  MenbedDisplayHD44780 extends MenbedDisplay
+    // and implements the all-important writeLine function allong with some
+    // other less important functions.  The pins we pass to the constructor
+    // specify the physical interface connection to the LCD.
+    MenbedDisplayHD44780 *hd44780Lcd = new MenbedDisplayHD44780 
+        (D8, D9, D4, D5, D6, D7, MenbedDisplayHD44780::LCD20x4);
+
+    // Now, we have the menu objects and the display object.  All we have to do
+    // is create the menbed menu system.  The number of buttons used by the
+    // menu system is specified by the number of pins passed to the Menbed 
+    // constructor.  The pin order is select, down, up, cancel.  With 
+    // constructor overloading, we can opt out of using the cancel and up
+    // buttons.
+
+    /* Four buttons (select, down, up, cancel ) */    
+    Menbed menbed(D10, D11, D12, D13,
+        rootMenu,
+        hd44780Lcd);
+}
+
+void testlines(uint16_t color)
+{
+    tft.fillScreen(ST7735_BLACK);
+    for (int16_t x=0; x < tft.width(); x+=6) {
+        tft.drawLine(0, 0, x, tft.height()-1, color);
+    }
+    for (int16_t y=0; y < tft.height(); y+=6) {
+        tft.drawLine(0, 0, tft.width()-1, y, color);
+    }
+
+    tft.fillScreen(ST7735_BLACK);
+    for (int16_t x=0; x < tft.width(); x+=6) {
+        tft.drawLine(tft.width()-1, 0, x, tft.height()-1, color);
+    }
+    for (int16_t y=0; y < tft.height(); y+=6) {
+        tft.drawLine(tft.width()-1, 0, 0, y, color);
+    }
+
+    tft.fillScreen(ST7735_BLACK);
+    for (int16_t x=0; x < tft.width(); x+=6) {
+        tft.drawLine(0, tft.height()-1, x, 0, color);
+    }
+    for (int16_t y=0; y < tft.height(); y+=6) {
+        tft.drawLine(0, tft.height()-1, tft.width()-1, y, color);
+    }
+
+    tft.fillScreen(ST7735_BLACK);
+    for (int16_t x=0; x < tft.width(); x+=6) {
+        tft.drawLine(tft.width()-1, tft.height()-1, x, 0, color);
+    }
+    for (int16_t y=0; y < tft.height(); y+=6) {
+        tft.drawLine(tft.width()-1, tft.height()-1, 0, y, color);
+    }
+}
+
+void testfastlines(uint16_t color1, uint16_t color2)
+{
+    tft.fillScreen(ST7735_BLACK);
+    for (int16_t y=0; y < tft.height(); y+=5) {
+        tft.drawFastHLine(0, y, tft.width(), color1);
+    }
+    for (int16_t x=0; x < tft.width(); x+=5) {
+        tft.drawFastVLine(x, 0, tft.height(), color2);
+    }
+}
+
+
+
+void IniciandoMaquina()
+{
+    tft.setTextWrap(true);
+    tft.fillScreen(ST7735_BLACK);
+    int x = 0;
+    while(x < 5) {
+        tft.fillScreen(ST7735_BLACK);
+        tft.setCursor(0,50);
+        tft.setTextColor(ST7735_WHITE);
+        tft.setTextSize(2);
+        tft.printf("Iniciando Pet-Finder");
+        tft.setCursor(0,100);
+        tft.printf("Aguarde");
+        wait_ms(100);
+        tft.fillScreen(ST7735_BLACK);
+        tft.setCursor(0,50);
+        tft.setTextColor(ST7735_WHITE);
+        tft.setTextSize(2);
+        tft.printf("Iniciando Pet-Finder");
+        tft.setCursor(0,100);
+        tft.printf("Aguarde...");
+        wait_ms(100);
+        x += 1;
+    }
+}
+
+
+
+void Alerta() {
+    tft.setTextWrap(true);
+    int x = 0;
+    while(x < 10) {
+        tft.fillScreen(ST7735_BLACK);
+        tft.setCursor(0,50);
+        tft.setTextColor(ST7735_WHITE);
+        tft.setTextSize(2);
+        tft.printf("!!ALERTA!!");
+        wait_ms(200);
+        tft.fillScreen(ST7735_RED);
+        tft.setTextSize(2);
+        tft.printf("!!ALERTA!!");
+        wait_ms(300);
+        x += 1;
+    }
+    
+}
+
+void MenuPrincipal() {
+    tft.fillScreen(ST7735_BLACK);  
+    tft.setCursor(0,0);
+    tft.setTextColor(ST7735_WHITE);
+    tft.setTextSize(2);
+    tft.printf("Pet-Finder");
+    tft.setCursor(0,40);
+    tft.printf("Data:");
+    tft.setCursor(0,55);
+    tft.printf("15/05/2017");
+    tft.setCursor(0,80);
+    tft.printf("Horario:");
+    tft.setCursor(0,95);
+    tft.printf("17h27");
+    wait_ms(200);
+    
+    }
+
+void Aguarde() {
+    int x = 0;
+    while(x < 5) {
+        tft.fillScreen(ST7735_BLACK);  
+        tft.setCursor(0,70);
+        tft.setTextSize(2);
+        tft.printf("Aguarde...");
+        wait_ms(800);
+        x += 1;
+    }
+}
+    
+void Executando() {
+    int x = 0;
+    tft.fillScreen(ST7735_WHITE);  
+    tft.setTextColor(ST7735_BLACK);
+    while(x < 3) {
+        tft.fillScreen(ST7735_GREEN);  
+        tft.setCursor(0,70);
+        tft.setTextSize(2);
+        tft.printf("Executando");
+        wait_ms(800);
+        tft.fillScreen(ST7735_WHITE);  
+        tft.setTextColor(ST7735_BLACK);
+        tft.setCursor(0,70);
+        tft.printf("Executando");
+        wait_ms(400);
+        x += 1;
+    
+        }
+    tft.fillScreen(ST7735_GREEN);  
+    tft.setCursor(0,70);
+    tft.printf("Executando");
+}
+
+
+// ----------------------------------------------------------------------------------------------------------------
+
+
+
diff -r 000000000000 -r 92357d1220f3 mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,1 @@
+https://mbed.org/users/mbed_official/code/mbed/builds/4eea097334d6
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/displays/include/menbedDisplayHD44780.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/displays/include/menbedDisplayHD44780.h	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,79 @@
+/* This code based on mbed TextLCD Library, for a 4-bit LCD based on HD44780,
+ * Copyright (c) 2007-2010, sford, http://mbed.org
+ *
+ * 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.
+ */
+
+#ifndef _MENBEDDISPLAYHD44780_H_
+#define _MENBEDDISPLAYHD44780_H_
+
+#include "mbed.h"
+#include "menbedDisplay.h"
+
+class MenbedDisplayHD44780 : public MenbedDisplay {
+public:
+
+    /** LCD panel format */
+    enum LCDSize {
+        LCD16x2,   /**< 16x2 LCD panel */
+        LCD16x2B,  /**< 16x2 LCD panel alternate addressing */
+        LCD20x2,   /**< 20x2 LCD panel */
+        LCD20x4,   /**< 20x4 LCD panel (default) */
+    };
+
+    MenbedDisplayHD44780 (PinName rs, PinName e, PinName d4, PinName d5, PinName d6, PinName d7, LCDSize size = LCD20x4);
+    
+    virtual bool writeLine (const char *line, uint8_t row);
+    virtual void showUpArrow (bool show);
+    virtual void showDownArrow (bool show);
+    virtual uint8_t getLines (void);
+    virtual uint8_t getLineLength (void);
+    
+protected:
+    enum ArrowSelectorChar {
+        CharUP,
+        CharUP_SELECT,
+        CharSELECT,
+        CharDOWN_SELECT,
+        CharDOWN
+    };
+
+    DigitalOut rs, e;
+    BusOut d;
+    LCDSize size;
+    
+    bool upArrowVisible, downArrowVisible;
+    bool topLineSelected, bottomLineSelected;
+    int cursorCol, cursorRow;
+
+    bool gotoPosition(int row, int column);
+    void clear();
+    void cursorOn();
+    void cursorOff();
+
+    int address(int column, int row);
+    void writeByte(int value);
+    void writeCommand(int command);
+    void writeData(int data);
+    void loadCustomChars(void);
+    int rows();
+    int columns();
+};
+
+#endif /* _MENBEDDISPLAYHD44780_H_ */
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/displays/menbedDisplayHD44780.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/displays/menbedDisplayHD44780.cpp	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,369 @@
+/* This code based on mbed TextLCD Library, for a 4-bit LCD based on HD44780,
+ * Copyright (c) 2007-2010, sford, http://mbed.org
+ *
+ * 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.
+ */
+
+#include "mbed.h"
+#include "include/menbedDisplayHD44780.h"
+#include "menbedDisplay.h"
+
+MenbedDisplayHD44780::MenbedDisplayHD44780 (PinName rs, PinName e, 
+    PinName d4, PinName d5, PinName d6, PinName d7, LCDSize size) : 
+    rs(rs), e(e), d(d4, d5, d6, d7), size(size) 
+{
+    this->e  = 1;
+    this->rs = 0;
+    
+    upArrowVisible = false;
+    downArrowVisible = false;
+    topLineSelected = false;
+    bottomLineSelected = false;
+    cursorCol = -1;
+    cursorRow = -1;
+
+    wait(0.015);        // Wait 15ms to ensure powered up
+
+    // send "Display Settings" 3 times (Only top nibble of 0x30 as we've got 4-bit bus)
+    for (int i=0; i<3; i++) {
+        writeByte(0x3);
+        wait(0.00164);  // this command takes 1.64ms, so wait for it
+    }
+    
+    writeByte(0x2);     // 4-bit mode
+    wait(0.000040f);    // most instructions take 40us
+
+    writeCommand(0x28); // Function set 001 BW N F - -
+    writeCommand(0x0C); // Display on but keep cursor and blinking off
+    writeCommand(0x6);  // Cursor Direction and Display Shift : 0000 01 CD S (CD 0-left, 1-right S(hift) 0-no, 1-yes
+    
+    loadCustomChars();
+    
+    clear();
+}
+
+
+bool MenbedDisplayHD44780::writeLine (const char *line, uint8_t row)
+{
+    int i = 0;
+    int cursorPos = -1;
+
+    if (row >= rows())
+        return false;
+
+    // Skip writing to the left-most column to leave space for the selector
+    // and up/down arrows that will be filled in later.
+    gotoPosition (row, 1);
+
+    while ((line[i] != '\0') && (line[i] != '\n') && (i+1 < columns()))
+    {
+        // Place the cursor at the end of the active parameter, when it exists.
+        // A parameter is active when it is highlighted as indicated by the 
+        // MSB of the character code being set.
+        if ((i > 0) && (line[i-1] & 0x80) && !(line[i] & 0x80))
+            cursorPos = i-1;
+
+        // Print each character to the display after clearing its MSB so that
+        // it prints as a standard ASCII character.
+        writeData (line[i] & ~0x80);
+        i++;
+    }
+    
+    // If the first character of the line is not highlighted but the last is,
+    // a parameter must be selected for editing, and we place the cursor at
+    // the end of the parameter which, in this special case, corresponds to
+    // the end of the line.
+    if (!(line[0] & 0x80) && (line[i-1] & 0x80))
+        cursorPos = i-1;
+
+    // Fill the remainder of the row with spaces to overwrite any old data
+    while (i++ < columns() - 1)
+        writeData(' ');
+
+    // Now go back and fill in the selector and up/down arrows
+    gotoPosition(row, 0);
+    if ((line[0] & 0x80) && (cursorPos == -1))
+    {
+        if (row == 0)
+            topLineSelected = true;
+        else if (row == rows() - 1)
+            bottomLineSelected = true;
+    
+        if ((row == 0) && upArrowVisible)
+            writeData (CharUP_SELECT);
+        else if ((row == rows() - 1) && downArrowVisible)
+            writeData (CharDOWN_SELECT);
+        else
+            writeData (CharSELECT);
+    }
+    else
+    {
+        if (row == 0)
+            topLineSelected = false;
+        else if (row == rows() - 1)
+            bottomLineSelected = false;
+    
+        if ((row == 0) && upArrowVisible)
+            writeData (CharUP);
+        else if ((row == rows() - 1) && downArrowVisible)
+            writeData (CharDOWN);
+        else
+            writeData (' ');
+    }
+
+    // If a parameter is being edited, we turn on the blinking cursor.
+    if (cursorPos != -1)
+    {
+        cursorRow = row;
+        cursorCol = cursorPos + 1;
+        gotoPosition (cursorRow, cursorCol); // Add 1 to account for selector col.
+        cursorOn();
+    }
+    // If this line used to contain the cursor but should not any more reset
+    // the cursor row and column position and turn it off.
+    else if (row == cursorRow)
+    {
+        cursorRow = -1;
+        cursorCol = -1;
+        cursorOff();
+    }
+
+    return true;
+}
+
+
+void MenbedDisplayHD44780::showUpArrow (bool show)
+{
+    upArrowVisible = show;
+    
+    gotoPosition (0, 0);
+    
+    if (show && topLineSelected)
+        writeData (CharUP_SELECT);
+    else if (!show && topLineSelected)
+        writeData (CharSELECT);
+    else if (show && !topLineSelected)
+        writeData (CharUP);
+    else
+        writeData(' ');
+        
+    // Return cursor to its original location
+    if ((cursorRow >= 0) && (cursorCol >= 0))
+        gotoPosition (cursorRow, cursorCol);
+}
+
+
+void MenbedDisplayHD44780::showDownArrow (bool show)
+{
+    downArrowVisible = show;
+    
+    gotoPosition (rows() - 1, 0);
+    
+    if (show && bottomLineSelected)
+        writeData (CharDOWN_SELECT);
+    else if (!show && bottomLineSelected)
+        writeData (CharSELECT);
+    else if (show && !bottomLineSelected)
+        writeData (CharDOWN);
+    else
+        writeData(' ');
+        
+    // Return cursor to its original location
+    if ((cursorRow >= 0) && (cursorCol >= 0))
+        gotoPosition (cursorRow, cursorCol);
+}
+
+
+uint8_t MenbedDisplayHD44780::getLines (void)
+{
+    return rows();
+}
+
+
+uint8_t MenbedDisplayHD44780::getLineLength (void)
+{
+    return columns();
+}
+
+
+void MenbedDisplayHD44780::clear()
+{
+    writeCommand (0x01); // Clear, and set cursor to 0
+    wait (0.050f);
+    gotoPosition (0, 0);
+}
+
+
+bool MenbedDisplayHD44780::gotoPosition(int row, int column)
+{
+    if ((column < 0) || (column >= columns()) || (row < 0) || (row >= rows()))
+        return false;
+
+    writeCommand (address (row, column));
+    return true;
+}
+
+
+void MenbedDisplayHD44780::cursorOn()
+{
+    writeCommand(0x0D); // Display and blinking on, cursor off
+}
+
+
+void MenbedDisplayHD44780::cursorOff()
+{
+    writeCommand(0x0C); // Display on, cursor and blinking off
+}
+
+
+void MenbedDisplayHD44780::writeCommand(int command) {
+    rs = 0;
+    writeByte(command);
+}
+
+
+void MenbedDisplayHD44780::writeData(int data) {
+    rs = 1;
+    writeByte(data);
+}
+
+
+void MenbedDisplayHD44780::writeByte(int value) {
+    d = value >> 4;
+    wait(0.000040f); // most instructions take 40us
+    e = 0;
+    wait(0.000040f);
+    e = 1;
+    d = value >> 0;
+    wait(0.000040f);
+    e = 0;
+    wait(0.000040f);  // most instructions take 40us
+    e = 1;
+}
+
+
+int MenbedDisplayHD44780::address(int row, int column) {
+    switch (size) {
+        case LCD20x4:
+            switch (row) {
+                case 0:
+                    return 0x80 + column;
+                case 1:
+                    return 0xc0 + column;
+                case 2:
+                    return 0x94 + column;
+                case 3:
+                    return 0xd4 + column;
+            }
+        case LCD16x2B:
+            return 0x80 + (row * 40) + column;
+        case LCD16x2:
+        case LCD20x2:
+        default:
+            return 0x80 + (row * 0x40) + column;
+    }
+}
+
+
+int MenbedDisplayHD44780::columns() 
+{
+    switch (size) {
+        case LCD20x4:
+        case LCD20x2:
+            return 20;
+        case LCD16x2:
+        case LCD16x2B:
+        default:
+            return 16;
+    }
+}
+
+
+int MenbedDisplayHD44780::rows() 
+{
+    switch (size) {
+        case LCD20x4:
+            return 4;
+        case LCD16x2:
+        case LCD16x2B:
+        case LCD20x2:
+        default:
+            return 2;
+    }
+}
+
+
+void MenbedDisplayHD44780::loadCustomChars (void)
+{
+
+    // Up arrow
+    writeCommand(0x40 + (8 * CharUP));
+    writeData(0x04);
+    writeData(0x0E);
+    writeData(0x1F);
+    writeData(0x00);
+    writeData(0x00);
+    writeData(0x00);
+    writeData(0x00);
+    writeData(0x00);
+    
+    // Up arrow with selector
+    writeCommand(0x40 + (8 * CharUP_SELECT));
+    writeData(0x04);
+    writeData(0x0E);
+    writeData(0x1F);
+    writeData(0x00);
+    writeData(0x1F);
+    writeData(0x1F);
+    writeData(0x00);
+    writeData(0x00);
+    
+    // Selector alone
+    writeCommand(0x40 + (8 * CharSELECT));
+    writeData(0x00);
+    writeData(0x00);
+    writeData(0x00);
+    writeData(0x1F);
+    writeData(0x1F);
+    writeData(0x00);
+    writeData(0x00);
+    writeData(0x00);    
+    
+    // Down arrow with selector
+    writeCommand(0x40 + (8 * CharDOWN_SELECT));
+    writeData(0x00);
+    writeData(0x00);
+    writeData(0x1F);
+    writeData(0x1F);
+    writeData(0x00);
+    writeData(0x1F);
+    writeData(0x0E);
+    writeData(0x04);
+    
+    // Down arrow
+    writeCommand(0x40 + (8 * CharDOWN));
+    writeData(0x00);
+    writeData(0x00);
+    writeData(0x00);
+    writeData(0x00);
+    writeData(0x00);
+    writeData(0x1F);
+    writeData(0x0E);
+    writeData(0x04);        
+}
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/include/menbed.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbed.h	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,42 @@
+#ifndef _MENBED_H_
+#define _MENBED_H_
+
+#include "menbedButtonEvent.h"
+#include "menbedButtonHandler.h"
+#include "menbedButtonHandlerTimespec.h"
+#include "menbedNavigator.h"
+#include "menbedMenu.h"
+#include "menbedMenuItem.h"
+#include "menbedRefresher.h"
+
+#include "../displays/include/menbedDisplayHD44780.h"
+
+
+class Menbed {
+public:
+    Menbed (PinName select, PinName down, PinName up, PinName cancel,
+        MenbedMenu *rootMenu,
+        MenbedDisplay *display);
+        
+    Menbed (PinName select, PinName down, PinName up,
+        MenbedMenu *rootMenu,
+        MenbedDisplay *display);
+        
+    Menbed (PinName select, PinName down,
+        MenbedMenu *rootMenu,
+        MenbedDisplay *display);                
+
+    Menbed (PinName select, PinName down, PinName up, PinName cancel, 
+        MenbedButtonHandlerTimespec *timespec,
+        MenbedMenu *rootMenu,
+        MenbedDisplay *display);
+
+    ~Menbed ();
+protected:
+    MenbedButtonHandler *buttonHandler;
+    MenbedNavigator *navigator;
+    MenbedDisplayer *displayer;
+    MenbedRefresher *refresher;
+};
+
+#endif /* _MENBED_H_ */
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/include/menbedButtonEvent.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedButtonEvent.h	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,25 @@
+#ifndef _MENBEDBUTTONEVENT_H_
+#define _MENBEDBUTTONEVENT_H_
+
+#include "mbed.h"
+
+class MenbedButtonEvent {
+public:
+    enum ButtonName {
+        ButtonSelect,
+        ButtonDown,
+        ButtonUp,
+        ButtonCancel };
+        
+    enum ButtonAction {
+        BUTTON_ACTION_PUSHED,
+        BUTTON_ACTION_RELEASED_SHORT,
+        BUTTON_ACTION_RELEASED_LONG,
+        BUTTON_ACTION_HELD_LONG };
+        
+    ButtonName name;
+    ButtonAction action;
+    uint8_t numButtons;
+};
+
+#endif /* _MENBEDBUTTONEVENT_H_ */
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/include/menbedButtonHandler.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedButtonHandler.h	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,38 @@
+#ifndef _MENBEDBUTTONHANDLER_H_
+#define _MENBEDBUTTONHANDLER_H_
+
+#include "mbed.h"
+#include "menbedNavigator.h"
+#include "menbedButtonHandlerTimespec.h"
+
+class MenbedButtonHandler {
+public:
+    MenbedButtonHandler(PinName selectPin, PinName downPin, PinName upPin, PinName cancelPin,
+        MenbedButtonHandlerTimespec *timespec, MenbedNavigator *navigator);
+    MenbedButtonHandler(PinName selectPin, PinName downPin, PinName upPin,
+        MenbedButtonHandlerTimespec *timespec, MenbedNavigator *navigator);
+    MenbedButtonHandler(PinName selectPin, PinName downPin,
+        MenbedButtonHandlerTimespec *timespec, MenbedNavigator *navigator);
+                  
+protected:
+    DigitalIn *select, *down, *up, *cancel;
+    MenbedButtonHandlerTimespec *timespec;
+    MenbedNavigator *navigator;
+    
+    Ticker ticker;
+    uint32_t tickerPeriod_us;
+    uint32_t currentTime_us;
+    
+    int numButtons;
+    
+    uint32_t buttonPushedTime_us[4]; // Absolute time button first depressed
+    bool buttonDebounced[4]; // Keep track of which buttons are debounced
+    uint32_t buttonLastTypematicTime_us[4]; // Abs. time of last virtual push
+    bool buttonAlreadyDepressed[4]; // Keep track of state b/t calls to tick()
+    
+    void init (void);
+    void tick (void);
+    bool isButtonDepressed (MenbedButtonEvent::ButtonName);
+};
+
+#endif /* _MENBEDBUTTONHANDLER_H_ */
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/include/menbedButtonHandlerTimespec.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedButtonHandlerTimespec.h	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,24 @@
+#ifndef _MENBEDBUTTONHANDLERTIMESPEC_H_
+#define _MENBEDBUTTONHANDLERTIMESPEC_H_
+
+#include "mbed.h"
+
+class MenbedButtonHandlerTimespec {
+public:
+    uint32_t scanPeriod_us;
+    uint32_t debounceDelay_us;
+    uint32_t longReleaseDelay_us;
+    uint32_t typematicPeriod_us;
+    uint32_t typematicX10Delay_us;
+    uint32_t typematicX10Period_us;
+    
+    MenbedButtonHandlerTimespec ();
+    MenbedButtonHandlerTimespec (uint32_t scanPeriod_us, 
+        uint32_t debounceDelay_us,
+        uint32_t longReleaseDelay_us, uint32_t typematicPeriod_us,
+        uint32_t typematicX10Delay_us, uint32_t typematicX10Period_us);
+        
+    bool dummy() {return false;}
+};
+
+#endif /* _MENBEDBUTTONHANDLERTIMESPEC_H_ */
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/include/menbedDisplay.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedDisplay.h	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,15 @@
+#ifndef _MENBEDDISPLAY_H_
+#define _MENBEDDISPLAY_H_
+
+#include "mbed.h"
+
+class MenbedDisplay {
+public:
+    virtual bool writeLine (const char *line, uint8_t row) = 0;
+    virtual void showUpArrow (bool show) = 0;
+    virtual void showDownArrow (bool show) = 0;
+    virtual uint8_t getLines (void) = 0;
+    virtual uint8_t getLineLength (void) = 0;
+};
+
+#endif /* _MENBEDDISPLAY_H_ */
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/include/menbedDisplayer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedDisplayer.h	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,18 @@
+#ifndef _MENBEDDISPLAYER_H_
+#define _MENBEDDISPLAYER_H_
+
+#include "menbedMenuMessage.h"
+#include "menbedDisplay.h"
+
+class MenbedDisplayer {
+public:
+    MenbedDisplayer (MenbedDisplay *display);
+    void update (MenbedMenuMessage *menuMessage);
+    MenbedDisplay *getDisplay (void) {return display;}
+protected:
+    MenbedDisplay *display;
+    
+    void extractLine (char *catenatedText, uint8_t lineNum, char *extractedText);
+};
+
+#endif /* _MENBEDDISPLAYER_H_ */
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/include/menbedMenu.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedMenu.h	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,21 @@
+#ifndef _MENBEDMENU_H_
+#define _MENBEDMENU_H_
+
+#include <vector>
+
+#include "mbed.h"
+#include "menbedMenuItem.h"
+
+class MenbedMenuItem;
+
+class MenbedMenu {
+public:
+    MenbedMenu *parentMenu;
+    int8_t parentSelectedItemIndex;
+    uint8_t parentTopOfScreenItemIndex;
+    vector<MenbedMenuItem*> menuItems;
+
+    MenbedMenu (uint8_t nItems, MenbedMenuItem *items[]);
+};
+
+#endif /* _MENBEDMENU_H_ */
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/include/menbedMenuItem.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedMenuItem.h	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,47 @@
+#ifndef _MENBEDMENUITEM_H_
+#define _MENBEDMENUITEM_H_
+
+#include <vector>
+#include "mbed.h"
+#include "menbedMenu.h"
+#include "menbedMenuParam.h"
+
+class MenbedMenu;
+
+class MenbedMenuItem {
+public:
+    // Pointer to function that will be called when menu item selected.  This
+    // may be a null pointer if no function should be called.
+    void (*selFcn)();
+    // New menu to display when item selected.  This can be set to null if a
+    // new menu item should not be called when the menu item is selected.
+    MenbedMenu **childMenu;
+    // If true, childMenuIsAncestor indicates that the child menu's parent menu
+    // should be set to null.  This will prevent the user from moving to the
+    // from the child menu back to the current menu.  This is useful when the
+    // menu item is something like "Goto root menu".   Once the user is in the
+    // root menu, we don't want the user to press and hold the select key or
+    // press the cancel key in order to return to the current menu.
+    bool childMenuIsAncestor;
+    // Pointer a structure which itself points to a float that will be displayed
+    // in place of the %f in the text of the menu item.  If the param struct
+    // has an inc memeber that is non-zero, the parameter can be modified by the
+    // user.  In particular, when the user selects this menu item, the parameter
+    // is highlighted and the user can then use the up and down buttons to
+    // modify its value.
+    MenbedMenuParam *param;
+    // Array of char pointers to the strings that will be catenated to form
+    // the text of the menu item.  To insert either a menu parameter or state
+    // variable into the menu item text, make one of the strings a printf-style
+    // conversion specifier for a float.  (Note: only floats are allowed,
+    // integer are not.)  The last string must be an empty string ("") to
+    // indicate it is the last string in the array.  If the empty string is
+    // omitted, unpredictable behavior will result.
+    char *text;
+    
+    MenbedMenuItem (void (*selFcn)(), MenbedMenu **childMenu, 
+        bool childMenuIsAncestor, MenbedMenuParam *param, 
+        char *text);
+};
+
+#endif /* _MENBEDMENUITEM_H_ */
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/include/menbedMenuMessage.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedMenuMessage.h	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,16 @@
+#ifndef _MENBEDMENUMESSAGE_H_
+#define _MENBEDMENUMESSAGE_H_
+
+#include "mbed.h"
+
+class MenbedMenuMessage {
+public:
+    char *text;
+    bool showUpArrow;
+    bool showDownArrow;
+    
+    MenbedMenuMessage (uint8_t numLines, uint8_t lineLength);
+    ~MenbedMenuMessage ();
+};
+
+#endif /* _MENBEDMENUMESSAGE_H_ */
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/include/menbedMenuParam.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedMenuParam.h	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,51 @@
+#ifndef _MENBEDMENUPARAM_H_
+#define _MENBEDMENUPARAM_H_
+#include  <string>
+class MenbedMenuParam {
+public:
+    // Copy of the initial value;
+    float initVal;
+    string initValString;
+    // Temporary copy of the parameter used to the hold the modified value
+    // before it is committed.
+    float tempVal;
+    
+    MenbedMenuParam (float (*initValFcn)(void), void (*finalValFcn)(float),
+        bool liveUpdate, float min, float max,
+        float inc);
+        
+    float getVal (void);
+    void setVal (float v);
+    bool liveUpdate (void) {return _liveUpdate;}
+    float min (void) {return _min;}
+    float max (void) {return _max;}
+    float inc (void) {return _inc;}
+            
+protected:
+    // Pointer to a function returning a float containing the current value of
+    // the parameter.
+    float (*initValFcn)(void);
+    // Pointer to a function taking a float that is called when the parameter
+    // value is modified.
+    string (*initValStringFcn)(void);
+    // Pointer to a function taking a float that is called when the parameter
+    // value is modified.
+    void (*finalValFcn)(float);
+    // Boolean indicating whether the finalValFcn should be called each time
+    // the user makes a change to the variable or whether it should only be
+    // called once the user confirms the change.
+    void (*finalValStringFcn)(string);
+    // Boolean indicating whether the finalValFcn should be called each time
+    // the user makes a change to the variable or whether it should only be
+    // called once the user confirms the change.
+    bool _liveUpdate;
+    // Minimum allowable value.
+    float _min;
+    // Maximum allowable value.
+    float _max;
+    // Amount by which to increment/decrement the parameter with each presses of
+    // the up/down button.
+    float _inc;
+};
+
+#endif /* _MENBEDMENUPARAM_H_ */
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/include/menbedNavigator.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedNavigator.h	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,38 @@
+#ifndef _MENBEDNAVIGATOR_H_
+#define _MENBEDNAVIGATOR_H_
+
+#include "menbedButtonEvent.h"
+#include "menbedStructure.h"
+#include "menbedDisplayer.h"
+#include "menbedMenu.h"
+
+class MenbedNavigator {
+public:
+    MenbedNavigator (MenbedMenu *rootMenu, MenbedDisplayer *displayer);
+    void updateDisplay (void);
+    void handleButtonEvent (MenbedButtonEvent buttonEvent);
+protected:
+    MenbedMenu *activeMenu;
+    uint8_t numButtons;
+    uint8_t numLines;
+    uint8_t lineLength;
+    MenbedDisplayer *displayer;
+    
+    int8_t selectedItemIndex;
+    uint8_t topOfScreenItemIndex;
+    bool paramEditMode;
+
+    void selectItem (void);
+    void gotoParent (void);
+    void moveUp (void);
+    void moveDown (void);
+    void incParam (void);
+    void decParam (void);
+    void saveParam (void);
+    void restoreParam (void);
+    void printMenu (char *menuStr);
+    void printItem (MenbedMenuItem *item, char *line, bool itemSel, bool paramSel);
+    bool checkConvSpec (const char *s);
+};
+
+#endif /* _MENBEDNAVIGATOR_H_ */
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/include/menbedRefresher.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedRefresher.h	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,21 @@
+#ifndef _MENBEDREFRESHER_H_
+#define _MENBEDREFRESHER_H_
+
+#include "mbed.h"
+#include "menbedNavigator.h"
+
+class MenbedRefresher
+{
+public:
+    MenbedRefresher (MenbedNavigator *navigator);
+    MenbedRefresher (MenbedNavigator *navigator, uint32_t refreshPeriod_us);
+    void refreshed (void);
+    
+protected:
+    Ticker ticker;
+    MenbedNavigator *navigator;
+    uint32_t refreshPeriod_us;
+};
+    
+
+#endif /* _MENBEDREFRESHER_H_ */
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/include/menbedStructure.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedStructure.h	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,71 @@
+#ifndef _MENBEDSTRUCTURE_H_
+#define _MENBEDSTRUCTURE_H_
+
+#include "mbed.h"
+
+struct menuParam;
+struct menuItem;
+struct menu;
+
+typedef struct menuParam menuParam_t;
+typedef struct menuItem menuItem_t;
+typedef struct menu menu_t;
+
+struct menuParam{
+    // Pointer to a function returning a float containing the current value of
+    // the parameter.
+    float (*initValFcn)(void);
+    // Pointer to a function taking a float that is called when the parameter
+    // value is modified.
+    void (*finalValFcn)(float);
+    // Copy of the initial value;
+    float initVal;
+    // Temporary copy of the parameter used to the hold the modified value
+    // before it is committed.
+    float tempVal;
+    // Boolean indicating whether the finalValFcn should be called each time
+    // the user makes a change to the variable or whether it should only be
+    // called once the user confirms the change.
+    bool liveUpdate;
+    // Minimum allowable value.
+    float min;
+    // Maximum allowable value.
+    float max;
+    // Amount by which to increment/decrement the parameter with each presses of
+    // the up/down button.
+    float inc;
+};
+
+struct menuItem{
+    // Pointer to function that will be called when menu item selected.  This
+    // may be a null pointer if no function should be called.
+    void (*selFcn)();
+    // New menu to display when item selected.  This can be set to null if a
+    // new menu item should not be called when the menu item is selected.
+    menu_t *childMenu;
+    // If true, childMenuIsAncestor indicates that the child menu's parent menu
+    // should be set to null.  This will prevent the user from moving to the
+    // from the child menu back to the current menu.  This is useful when the
+    // menu item is something like "Goto root menu".   Once the user is in the
+    // root menu, we don't want the user to press and hold the select key or
+    // press the cancel key in order to return to the current menu.
+    bool childMenuIsAncestor;
+    // Pointer a structure which itself points to a float that will be displayed
+    // in place of the %f in the text of the menu item.  If the param struct
+    // has an inc memeber that is non-zero, the parameter can be modified by the
+    // user.  In particular, when the user selects this menu item, the parameter
+    // is highlighted and the user can then use the up and down buttons to
+    // modify its value.
+    menuParam_t *param;
+    // Array of char pointers to the strings that will be catenated to form
+    // the text of the menu item.  To insert either a menu parameter or state
+    // variable into the menu item text, make one of the strings a printf-style
+    // conversion specifier for a float.  (Note: only floats are allowed,
+    // integer are not.)  The last string must be an empty string ("") to
+    // indicate it is the last string in the array.  If the empty string is
+    // omitted, unpredictable behavior will result.
+    char *text[];
+};
+
+
+#endif /* _MENBEDSTRUCTURE_H_ */
diff -r 000000000000 -r 92357d1220f3 menbed/menbed.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbed.cpp	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,57 @@
+#include "mbed.h"
+#include "include/menbed.h"
+
+Menbed::Menbed (PinName select, PinName down, PinName up, PinName cancel,
+    MenbedMenu *rootMenu,
+    MenbedDisplay *display)
+{
+    MenbedButtonHandlerTimespec *timespec = new MenbedButtonHandlerTimespec();
+    
+    displayer = new MenbedDisplayer (display);
+    navigator = new MenbedNavigator (rootMenu, displayer);
+    buttonHandler = new MenbedButtonHandler (select, down, up, cancel, timespec, navigator);
+    refresher = new MenbedRefresher (navigator);
+}
+
+Menbed::Menbed (PinName select, PinName down, PinName up,
+    MenbedMenu *rootMenu,
+    MenbedDisplay *display)
+{
+    MenbedButtonHandlerTimespec *timespec = new MenbedButtonHandlerTimespec();
+    
+    displayer = new MenbedDisplayer (display);
+    navigator = new MenbedNavigator (rootMenu, displayer);
+    buttonHandler = new MenbedButtonHandler (select, down, up, timespec, navigator);
+    refresher = new MenbedRefresher (navigator);
+}
+
+Menbed::Menbed (PinName select, PinName down,
+    MenbedMenu *rootMenu,
+    MenbedDisplay *display)
+{
+    MenbedButtonHandlerTimespec *timespec = new MenbedButtonHandlerTimespec();
+    
+    displayer = new MenbedDisplayer (display);
+    navigator = new MenbedNavigator (rootMenu, displayer);
+    buttonHandler = new MenbedButtonHandler (select, down, timespec, navigator);
+    refresher = new MenbedRefresher (navigator);
+}
+
+Menbed::Menbed(PinName select, PinName down, PinName up, PinName cancel, 
+    MenbedButtonHandlerTimespec *timespec,
+    MenbedMenu *rootMenu,
+    MenbedDisplay *display)
+{
+    displayer = new MenbedDisplayer (display);
+    navigator = new MenbedNavigator (rootMenu, displayer);
+    buttonHandler = new MenbedButtonHandler (select, down, up, cancel, timespec, navigator);
+    refresher = new MenbedRefresher (navigator);
+}
+
+Menbed::~Menbed()
+{
+    delete refresher;
+    delete buttonHandler;
+    delete navigator;
+    delete displayer;
+}
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/menbedButtonHandler.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedButtonHandler.cpp	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,201 @@
+#include "mbed.h"
+#include "include/menbedNavigator.h"
+#include "include/menbedButtonHandlerTimespec.h"
+#include "include/menbedButtonHandler.h"
+
+MenbedButtonHandler::MenbedButtonHandler (PinName selectPin, PinName downPin, 
+    PinName upPin, PinName cancelPin, MenbedButtonHandlerTimespec *timespec,
+    MenbedNavigator *navigator) : 
+    //select(select), down(down), up(up), cancel(cancel),
+    timespec(timespec), navigator(navigator)
+{
+    select = new DigitalIn(selectPin);
+    down = new DigitalIn(downPin);
+    up = new DigitalIn(upPin);
+    cancel = new DigitalIn(cancelPin);
+
+    numButtons = 4;
+    
+    select->mode (PullDown);
+    down->mode (PullDown);
+    up->mode (PullDown);
+    cancel->mode (PullDown);
+    
+    init();
+}
+
+
+MenbedButtonHandler::MenbedButtonHandler (PinName selectPin, PinName downPin, 
+    PinName upPin, MenbedButtonHandlerTimespec *timespec,
+    MenbedNavigator *navigator) :
+    timespec(timespec), navigator(navigator)
+{
+    select = new DigitalIn(selectPin);
+    down = new DigitalIn(downPin);
+    up = new DigitalIn(upPin);
+
+    numButtons = 3;
+    
+    select->mode (PullDown);
+    down->mode (PullDown);
+    up->mode (PullDown);
+    
+    init();
+}
+
+
+MenbedButtonHandler::MenbedButtonHandler (PinName selectPin, PinName downPin, 
+    MenbedButtonHandlerTimespec *timespec,
+    MenbedNavigator *navigator) : 
+    timespec(timespec), navigator(navigator)
+{
+    select = new DigitalIn(selectPin);
+    down = new DigitalIn(downPin);
+
+    numButtons = 2;
+    
+    select->mode (PullDown);
+    down->mode (PullDown);
+    
+    init();
+}
+
+
+void MenbedButtonHandler::init()
+{
+    for (int i=0; i<4; i++)
+    {
+        buttonDebounced[i] = false;
+        buttonAlreadyDepressed[i] = false;
+    }
+    
+    currentTime_us = 0;
+    ticker.attach_us (this, &MenbedButtonHandler::tick, 
+        timespec->scanPeriod_us);
+}
+
+
+void MenbedButtonHandler::tick (void)
+{
+    // Accumulated amount of time that buttons have been continuously depressed
+    uint32_t buttonDepressedTime_us;
+    bool buttonCurrentlyDepressed;
+    
+    MenbedButtonEvent buttonEvent;
+    buttonEvent.numButtons = numButtons;
+    
+    currentTime_us += timespec->scanPeriod_us;
+
+    // Cycle through each of the buttons
+    for (int i=MenbedButtonEvent::ButtonSelect; 
+        (i<=MenbedButtonEvent::ButtonCancel) && (i<numButtons);
+        i++)
+    {
+        buttonEvent.name = (MenbedButtonEvent::ButtonName)i;
+        buttonCurrentlyDepressed = 
+            isButtonDepressed((MenbedButtonEvent::ButtonName)i);
+
+        // The amount of time the current button has been depressed is
+        // the current time minus the time which the button was first
+        // depressed.
+        buttonDepressedTime_us = currentTime_us - buttonPushedTime_us[i];
+
+        if (buttonCurrentlyDepressed && buttonAlreadyDepressed[i])
+        {
+            if ((buttonDepressedTime_us >= timespec->typematicX10Delay_us) &&
+                    (currentTime_us - buttonLastTypematicTime_us[i] >=
+                        timespec->typematicX10Period_us ))
+            {
+                buttonLastTypematicTime_us[i] = currentTime_us;
+                buttonEvent.action = MenbedButtonEvent::BUTTON_ACTION_PUSHED;
+                navigator->handleButtonEvent (buttonEvent);
+            }
+            else if ((buttonDepressedTime_us >=
+                    timespec->typematicPeriod_us)
+                    && (currentTime_us - buttonLastTypematicTime_us[i] >=
+                            timespec->typematicPeriod_us))
+            {
+                buttonLastTypematicTime_us[i] = currentTime_us;
+                buttonEvent.action = MenbedButtonEvent::BUTTON_ACTION_PUSHED;
+                navigator->handleButtonEvent (buttonEvent);
+            }
+            else if ((buttonDepressedTime_us >= timespec->debounceDelay_us)
+                    && (!buttonDebounced[i]))
+            {
+                buttonLastTypematicTime_us[i] = currentTime_us;
+                buttonDebounced[i] = true;
+                buttonEvent.action = MenbedButtonEvent::BUTTON_ACTION_PUSHED;
+                navigator->handleButtonEvent (buttonEvent);
+            }
+
+            if (buttonDebounced[i] &&
+                    (buttonDepressedTime_us >= 
+                        timespec->longReleaseDelay_us))
+            {
+                buttonEvent.action = MenbedButtonEvent::BUTTON_ACTION_HELD_LONG;
+                navigator->handleButtonEvent (buttonEvent);
+            }
+
+            buttonAlreadyDepressed[i] = true;
+        }
+        // Otherwise, if the button was just depressed, we indicate that it
+        // has not yet debounced and record the time so that we know when it
+        // was first pressed.
+        else if (buttonCurrentlyDepressed && !buttonAlreadyDepressed[i])
+        {
+            buttonDebounced[i] = false;
+            buttonPushedTime_us[i] = currentTime_us;
+
+            buttonAlreadyDepressed[i] = true;
+        }
+        // Otherwise, if the button is not depressed but it was previously
+        // depressed and the amount of time it was depressed exceeds the
+        // debounce time, then we say the button has been released.
+        else if (!buttonCurrentlyDepressed && buttonAlreadyDepressed[i])
+        {
+            if (buttonDebounced[i])
+            {
+                if (buttonDepressedTime_us >=
+                        timespec->longReleaseDelay_us)
+                {
+                    buttonEvent.action = MenbedButtonEvent::BUTTON_ACTION_RELEASED_LONG;
+                    navigator->handleButtonEvent (buttonEvent);
+                }
+                else
+                {
+                    buttonEvent.action = MenbedButtonEvent::BUTTON_ACTION_RELEASED_SHORT;
+                       navigator->handleButtonEvent (buttonEvent);
+                }
+            }
+
+            buttonAlreadyDepressed[i] = false;
+        }
+    }
+}
+
+
+bool MenbedButtonHandler::isButtonDepressed (MenbedButtonEvent::ButtonName name)
+{
+    switch (name)
+    {
+    case MenbedButtonEvent::ButtonSelect:
+        return *select;
+    case MenbedButtonEvent::ButtonDown:
+        if (numButtons >= 2)
+            return *down;
+        else
+            return false;
+    case MenbedButtonEvent::ButtonUp:
+        if (numButtons >= 3)
+            return *up;
+        else
+            return false;
+    case MenbedButtonEvent::ButtonCancel:
+        if (numButtons == 4)
+            return *cancel;
+        else
+            return false;
+    }
+    
+    return false;
+}
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/menbedButtonHandlerTimespec.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedButtonHandlerTimespec.cpp	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,20 @@
+#include "mbed.h"
+#include "include/menbedButtonHandlerTimespec.h"
+
+MenbedButtonHandlerTimespec::MenbedButtonHandlerTimespec () :
+    scanPeriod_us(10000), debounceDelay_us(45000), 
+    longReleaseDelay_us(2500000), typematicPeriod_us(333000),
+    typematicX10Delay_us(2997000), typematicX10Period_us(33000)
+{}
+
+MenbedButtonHandlerTimespec::MenbedButtonHandlerTimespec (
+    uint32_t scanPeriod_us, 
+    uint32_t debounceDelay_us,
+    uint32_t longReleaseDelay_us, uint32_t typematicPeriod_us,
+    uint32_t typematicX10Delay_us, uint32_t typematicX10Period_us) :
+    scanPeriod_us(scanPeriod_us), debounceDelay_us(debounceDelay_us),
+    longReleaseDelay_us(longReleaseDelay_us), 
+    typematicPeriod_us(typematicPeriod_us), 
+    typematicX10Delay_us(typematicX10Delay_us),
+    typematicX10Period_us(typematicX10Period_us)
+{}
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/menbedDisplayer.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedDisplayer.cpp	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,81 @@
+#include "mbed.h"
+#include "include/menbedMenuMessage.h"
+#include "include/menbedDisplayer.h"
+
+MenbedDisplayer::MenbedDisplayer (MenbedDisplay *display) :
+    display(display)
+{
+}
+
+
+void MenbedDisplayer::update (MenbedMenuMessage *menuMessage)
+{
+    char *text = new char[display->getLineLength()+1];
+
+    for (int i=0; i<display->getLines(); i++)
+    {
+        extractLine (menuMessage->text, i, text);
+        display->writeLine (text, i);
+    }
+    
+    // Print the up and down arrows if requested
+    display->showUpArrow (menuMessage->showUpArrow);
+    display->showDownArrow (menuMessage->showDownArrow);
+    
+    delete[] text;
+}
+
+
+void MenbedDisplayer::extractLine (char *catenatedText, uint8_t lineNum,
+        char *extractedText)
+{
+    char *subText, *endText;
+    size_t bytesToCopy;
+
+    extractedText[0] = '\0';
+
+    // Return with just a blank line if the line number to be extracted exceeds
+    // the number of lines in the menu
+    if (lineNum > display->getLines() - 1)
+        return;
+
+    // We loop through the catenatedString finding each \n.  These \n
+    // characters separate the substrings that we are trying to extract.
+    subText = catenatedText;
+    while (lineNum > 0)
+    {
+        subText = strchr (subText, '\n');
+
+        // If the \n character was not found, the catenatedText string does not
+        // contain enough \n-separated substrings.
+        if (subText == (char *)NULL)
+        {
+            extractedText[0] = '\0';
+            return;
+        }
+
+        // Increment the subText pointer because the strchr() command returned
+        // a pointer to the \n character found, but next time through the loop
+        // we want to find the next \n, not the same \n again.
+        subText++;
+        lineNum--;
+    }
+
+    // If there are strings following the one we are trying to extract, we
+    // change the \n terminating the string to be extracted into a \0 so that
+    // we can use the strlen function to determine the length of the string
+    // we are trying to extract.  If there are no additional \n-separated
+    // strings following the one we are attempting to extract, strlen should
+    // work on subText without modification.
+    if ((endText = strchr (subText, '\n')) != (char *)NULL)
+        bytesToCopy = endText - subText + 1;
+    else
+        bytesToCopy = strlen(subText);
+
+    // Copy the string found in the \n-separated substring number specified by
+    // the lineNum parameter to the extracted string.
+    strncpy (extractedText, subText, bytesToCopy);
+
+    // Replace the \n at the end of extractedText string with a \0
+    extractedText[bytesToCopy-1] = '\0';
+}
diff -r 000000000000 -r 92357d1220f3 menbed/menbedMenu.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedMenu.cpp	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,13 @@
+#include "mbed.h"
+#include "include/menbedMenuItem.h"
+#include "include/menbedMenu.h"
+
+MenbedMenu::MenbedMenu (uint8_t nItems, MenbedMenuItem *items[])
+{
+    parentMenu = NULL;
+    parentSelectedItemIndex = -1;
+    parentTopOfScreenItemIndex = 0;
+
+    for (int i = 0; i<nItems; i++)
+        menuItems.push_back (items[i]);
+}
diff -r 000000000000 -r 92357d1220f3 menbed/menbedMenuItem.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedMenuItem.cpp	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,9 @@
+#include "mbed.h"
+#include "include/menbedMenuItem.h"
+
+MenbedMenuItem::MenbedMenuItem (void (*selFcn)(), MenbedMenu **childMenu, 
+        bool childMenuIsAncestor, MenbedMenuParam *param, char *text) :
+        selFcn(selFcn), childMenu(childMenu), 
+        childMenuIsAncestor(childMenuIsAncestor), param(param), 
+        text(text)
+{}
diff -r 000000000000 -r 92357d1220f3 menbed/menbedMenuMessage.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedMenuMessage.cpp	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,12 @@
+#include "mbed.h"
+#include "include/menbedMenuMessage.h"
+
+MenbedMenuMessage::MenbedMenuMessage (uint8_t numLines, uint8_t lineLength)
+{
+    text = new char[numLines * lineLength + 1];    
+}
+
+MenbedMenuMessage::~MenbedMenuMessage()
+{
+    delete[] text;
+}
diff -r 000000000000 -r 92357d1220f3 menbed/menbedMenuParam.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedMenuParam.cpp	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,29 @@
+#include "mbed.h"
+#include "include/menbedMenuParam.h"
+#include  <string>
+
+MenbedMenuParam::MenbedMenuParam (
+    float (*initValFcn)(void), void (*finalValFcn)(float),
+    bool liveUpdate, float min, float max,
+    float inc) : 
+    initValFcn(initValFcn), finalValFcn(finalValFcn), _liveUpdate(liveUpdate),
+    _min(min), _max(max), _inc(inc)    
+{
+}
+
+
+float MenbedMenuParam::getVal (void)
+{
+    if (initValFcn == NULL)
+        return 0.0;
+        
+    return initValFcn();
+}
+
+void MenbedMenuParam::setVal (float v)
+{
+    if (finalValFcn == NULL)
+        return;
+        
+    finalValFcn(v);
+}
\ No newline at end of file
diff -r 000000000000 -r 92357d1220f3 menbed/menbedNavigator.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedNavigator.cpp	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,477 @@
+#include "mbed.h"
+#include "include/menbedNavigator.h"
+#include "include/menbedButtonEvent.h"
+#include "include/menbedMenuMessage.h"
+#include "include/menbedMenu.h"
+#include <cstdio>
+
+extern void toggleLed3();
+
+MenbedNavigator::MenbedNavigator(MenbedMenu *rootMenu,  
+        MenbedDisplayer *displayer) :
+    activeMenu(rootMenu), displayer(displayer)
+{
+    selectedItemIndex = -1;
+    topOfScreenItemIndex = 0;
+    paramEditMode = false;
+    
+    numLines = displayer->getDisplay()->getLines();
+    lineLength = displayer->getDisplay()->getLineLength();
+}
+
+void MenbedNavigator::updateDisplay()
+{
+    MenbedMenuMessage menuMsg (numLines, lineLength);
+
+    printMenu (menuMsg.text);
+    menuMsg.showUpArrow = (topOfScreenItemIndex >= 1);
+    menuMsg.showDownArrow = (topOfScreenItemIndex + numLines < (int)(activeMenu->menuItems.size()));
+    
+    displayer->update (&menuMsg);
+}
+
+
+void MenbedNavigator::handleButtonEvent (MenbedButtonEvent buttonEvent)
+{
+    numButtons = buttonEvent.numButtons;
+
+    switch (buttonEvent.name)
+    {
+    case MenbedButtonEvent::ButtonSelect: // Select
+        if (!paramEditMode && (buttonEvent.action == 
+                MenbedButtonEvent::BUTTON_ACTION_RELEASED_SHORT))
+            selectItem();
+        else if (paramEditMode && (buttonEvent.action ==
+                MenbedButtonEvent::BUTTON_ACTION_RELEASED_SHORT))
+            saveParam();
+        else if ((numButtons < 4) && 
+            paramEditMode && (buttonEvent.action == 
+                MenbedButtonEvent::BUTTON_ACTION_HELD_LONG))
+            restoreParam();
+        else if ((numButtons < 4) && !paramEditMode && 
+            (buttonEvent.action ==
+                MenbedButtonEvent::BUTTON_ACTION_HELD_LONG))
+            gotoParent();
+        break;
+        
+    case MenbedButtonEvent::ButtonDown:
+        if (paramEditMode && 
+                (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED))
+            decParam();
+        else if (!paramEditMode && 
+                (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED))
+            moveDown();
+        break;
+        
+    case MenbedButtonEvent::ButtonUp:
+        if (numButtons > 2)
+        {
+            if (paramEditMode && 
+                    (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED))
+                incParam();
+            else if (!paramEditMode &&
+                    (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED))
+                moveUp();
+        }
+        break;
+        
+    case MenbedButtonEvent::ButtonCancel:
+        if (numButtons > 3)
+        {
+            if (paramEditMode && 
+                    (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED))
+                restoreParam();
+            else if (!paramEditMode && 
+                    (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED))
+                gotoParent();
+        }
+        break;
+    }
+
+    updateDisplay();
+    //menuRefresh_refreshed();
+}
+
+
+void MenbedNavigator::selectItem()
+{
+    MenbedMenu **childMenuPtr;
+    MenbedMenu *childMenu;
+
+    if ((selectedItemIndex < 0) || 
+            (selectedItemIndex >= (int)(activeMenu->menuItems.size())))
+         return;
+
+    // If it exists, execute the function associated with the menu item
+    if (activeMenu->menuItems[selectedItemIndex]->selFcn != NULL)
+        activeMenu->menuItems[selectedItemIndex]->selFcn();
+
+    // Show the child menu associated with the menu item.  Initially, the first
+    // item in the child menu is placed at the top of the screen, but is it
+    // left unselected.
+    childMenuPtr = activeMenu->menuItems[selectedItemIndex]->childMenu;
+    if (childMenuPtr != NULL)
+    {
+        childMenu = *(activeMenu->menuItems[selectedItemIndex]->childMenu);
+    
+        if (!activeMenu->menuItems[selectedItemIndex]->childMenuIsAncestor)
+        {
+            childMenu->parentMenu = activeMenu;
+            childMenu->parentSelectedItemIndex = selectedItemIndex;
+            childMenu->parentTopOfScreenItemIndex = topOfScreenItemIndex;
+        }
+        else
+            childMenu->parentMenu = NULL;
+
+        activeMenu = childMenu;
+        topOfScreenItemIndex = 0;
+        selectedItemIndex = -1;       
+    }
+    // Otherwise, if the current menu item has a parameter that can be modified,
+    // we switch to the parameter editing mode.
+    else if ((activeMenu->menuItems[selectedItemIndex]->param != NULL) &&
+            (activeMenu->menuItems[selectedItemIndex]->param->inc() != 0))
+    {
+        // All incrementing and decrementing of the parameter actually happens
+        // to a shadow variable in the param structure named tempValue.  The
+        // parameter value used by the other parts of the system is not updated
+        // until the user is done editing the parameter.
+        activeMenu->menuItems[selectedItemIndex]->param->initVal =
+                activeMenu->menuItems[selectedItemIndex]->param->getVal();
+        activeMenu->menuItems[selectedItemIndex]->param->tempVal =
+                activeMenu->menuItems[selectedItemIndex]->param->initVal;
+        paramEditMode = true;
+    }
+}
+
+
+void MenbedNavigator::gotoParent()
+{
+    if (activeMenu->parentMenu == NULL)
+        return;
+
+    selectedItemIndex = activeMenu->parentSelectedItemIndex;
+    topOfScreenItemIndex = activeMenu->parentTopOfScreenItemIndex;
+    activeMenu = activeMenu->parentMenu;
+}
+
+
+void MenbedNavigator::moveUp()
+{
+    // If we're already at the top of the menu, do nothing
+    if (selectedItemIndex <= -1)
+        return;
+    // If the top item of the menu is already selected, we send a NOP message
+    // which deselects the top line and displays the down arrow if the menu
+    // contains more items than can fit on the screen.  In effect, this allows
+    // the user to deselect all menu items which adds a nice look to the system.
+    else if (selectedItemIndex == 0)
+        selectedItemIndex = -1;
+    // If the currently selected menu item is the also the one at the top of the
+    // screen, we need to scroll the screen down and add the item above the
+    // currently selected one to the top of the screen.
+    else if (selectedItemIndex == topOfScreenItemIndex)
+    {
+        selectedItemIndex--;
+        topOfScreenItemIndex--;
+    }
+    // The selected item is not the top item on the screen.  All we need to do
+    // is select the item above the currently selected item.
+    else
+        selectedItemIndex--;
+}
+
+
+
+void MenbedNavigator::moveDown()
+{
+    // If the last item of the menu is already selected, our behavior depends
+    // on how many buttons are present.  If there is no up button, we cycle
+    // back to the top of the menu.  Otherwise, if an up button is present,
+    // we do nothing.
+    if (selectedItemIndex >= ((int)(activeMenu->menuItems.size()) - 1))
+    {
+        if (numButtons < 3)
+        {
+            selectedItemIndex = -1;
+            topOfScreenItemIndex = 0;
+        }
+        else
+            ;
+    }
+    // If the menu item displayed at the bottom of the screen is already
+    // selected, we will need to scroll the screen up to make room for a new
+    // line at the bottom of the screen.
+    else if (selectedItemIndex ==
+            (topOfScreenItemIndex + numLines - 1))
+    {
+        selectedItemIndex++;
+        topOfScreenItemIndex++;
+    }
+    // Otherwise, if the currently selected menu item is now the one displayed
+    // at the bottom of the screen, we simply change which of the visible items
+    // is highlighted.
+    else
+        selectedItemIndex++;
+        
+}
+
+
+void MenbedNavigator::incParam()
+{
+    float inc;
+    float tempVal;
+
+    if (paramEditMode != true)
+        return;
+
+    inc = activeMenu->menuItems[selectedItemIndex]->param->inc();
+
+    // Initialize our own local copy of the parameter's temporary value.  We do
+    // this so that we can more easily check for violations of the allowed min
+    // and max values.
+    tempVal = activeMenu->menuItems[selectedItemIndex]->param->tempVal;
+    tempVal += inc;
+
+    // Check the bounds on the parameter.
+    if (tempVal > activeMenu->menuItems[selectedItemIndex]->param->max())
+        tempVal = activeMenu->menuItems[selectedItemIndex]->param->max();
+    else if (tempVal < activeMenu->menuItems[selectedItemIndex]->param->min())
+        tempVal = activeMenu->menuItems[selectedItemIndex]->param->min();
+
+    // Assign the local temp. value back to the temporary value in the active
+    // parameter structue.
+    activeMenu->menuItems[selectedItemIndex]->param->tempVal = tempVal;
+
+    // If the parameter is configured to produce live updates, call the
+    // finalValFcn.
+    if (activeMenu->menuItems[selectedItemIndex]->param->liveUpdate())
+        activeMenu->menuItems[selectedItemIndex]->param->setVal(tempVal);
+}
+
+
+void MenbedNavigator::decParam()
+{
+    float inc;
+    float tempVal;
+
+    if (paramEditMode != true)
+        return;
+
+    inc = activeMenu->menuItems[selectedItemIndex]->param->inc();
+
+    // Initialize our own local copy of the parameter's temporary value.  We do
+    // this so that we can more easily check for violations of the allowed min
+    // and max values.
+    tempVal = activeMenu->menuItems[selectedItemIndex]->param->tempVal;
+    tempVal -= inc;
+
+    // Check the bounds on the parameter.
+    if (tempVal > activeMenu->menuItems[selectedItemIndex]->param->max())
+        tempVal = activeMenu->menuItems[selectedItemIndex]->param->max();
+    // If we reach the minimum parameter value when we only have a down button
+    // and not an up button connected to the system, we wrap the parameter
+    // value back around to its maximum.  Otherwise, if there is an up button
+    // present, we peg the parameter at its minimum value.
+    else if (tempVal < activeMenu->menuItems[selectedItemIndex]->param->min())
+    {
+        if (numButtons >= 3)
+            tempVal = activeMenu->menuItems[selectedItemIndex]->param->min();
+        else
+            tempVal = activeMenu->menuItems[selectedItemIndex]->param->max();
+    }
+
+    // Assign the local temp. value back to the temporary value in the active
+    // parameter structue.
+    activeMenu->menuItems[selectedItemIndex]->param->tempVal = tempVal;
+
+    // If the parameter is configured to produce live updates, call the
+    // finalValFcn.
+    if (activeMenu->menuItems[selectedItemIndex]->param->liveUpdate())
+        activeMenu->menuItems[selectedItemIndex]->param->setVal(tempVal);
+}
+
+
+void MenbedNavigator::saveParam()
+{
+    // Save the changes made the shadow variable tempValue to the real parameter
+    // value that is used by the rest of the application.
+    activeMenu->menuItems[selectedItemIndex]->param->setVal (
+            activeMenu->menuItems[selectedItemIndex]->param->tempVal
+            );
+    paramEditMode = false;
+}
+
+
+void MenbedNavigator::restoreParam()
+{
+    // Revert any changes made the parameter by calling the finalValFcn with
+    // the initVal that was stored when we first began editing this parameter.
+    activeMenu->menuItems[selectedItemIndex]->param->setVal(
+            activeMenu->menuItems[selectedItemIndex]->param->initVal
+            );
+    paramEditMode = false;
+}
+
+
+void MenbedNavigator::printMenu (char *menuStr)
+{
+    uint8_t i;
+    char *lineStr = new char[lineLength];
+    bool itemSel;
+
+    menuStr[0] = '\0';
+
+    for (i=topOfScreenItemIndex; i<topOfScreenItemIndex + numLines; i++)
+    {
+        // Make sure we don't try to print more menu items than exist in the
+        // active menu.
+        if (i > ((int)activeMenu->menuItems.size() - 1))
+        {
+            strcat (menuStr, "\n");
+            continue;
+        }
+
+        itemSel = (i == selectedItemIndex);
+
+        printItem (activeMenu->menuItems[i], lineStr, itemSel,
+                paramEditMode && itemSel);
+
+        strncat (menuStr, lineStr, lineLength);
+        strcat (menuStr, "\n");
+    }
+    
+    delete[] lineStr;
+}
+
+
+void MenbedNavigator::printItem (MenbedMenuItem *item, char *line, bool itemSel,
+        bool paramSel)
+{
+    uint8_t i = 0;
+    int8_t j;
+    char *tempStr = new char[lineLength];
+    char *frontTab, *backTab;
+    char *subStr = new char[lineLength];
+    uint8_t copySize;
+
+    // Clear the line of text
+    line[0] = '\0';
+
+    // Iterate over the element in the array of text strings in the provided
+    // menu item until an empty string is found indicating the end of the text
+    // that should be printed for the current line.  For safety, we assume there
+    // are a maximum of three element in the array: 1) text before the
+    // parameter, 2) the parameter, and 3) text after the parameter.
+    
+    frontTab = item->text;
+    while ((strlen (frontTab) > 0) && (i < 3))
+    {
+        backTab = strchr (frontTab, '\t');
+        if (backTab == NULL)
+        {
+            backTab = frontTab + strlen(frontTab);
+            i = 3; // force our way out of the while loop
+        }
+         
+        copySize = backTab - frontTab;
+        if (copySize >= lineLength)
+            copySize = lineLength - 1;
+            
+        strncpy (subStr, frontTab, copySize);
+        subStr[copySize] = '\0';
+        
+        // If the current string in the array is a printf-style conversion
+        // specifier for a float, we replace it with the parameter value.
+        if (checkConvSpec (subStr))
+        {
+            // If the user is currently editing the parameter, print the value
+            // of the shadow variable tempValue instead of the parameters actual
+            // value.  The tempValue is not copied over to the value field of
+            // the structure until the user is done editing the parameter.  To
+            // show that the parameter is being edited, we highlight the value
+            // by inverting the text.
+            if (paramSel)
+            {
+                snprintf (tempStr, lineLength, subStr, item->param->tempVal);
+
+                // We highlight the parameter by inverting the characters on the
+                // screen.  The menu system only allows the standard (0-127)
+                // ASCII character, so we use the MSB/7th bit of each character
+                // to indicate that it should be inverted when printed on the
+                // screen.
+                for (j=strlen(tempStr) - 1; j>=0; j--)
+                    tempStr[j] |= 0x80;
+
+            }
+            // If the user is not currently editing the parameter, we display
+            // the value pointed to by the value field of the param structure.
+            else
+                snprintf (tempStr, lineLength,
+                        subStr, item->param->getVal());                       
+
+            // Attach the parameter string to the growing line.
+            strncat (line, tempStr, lineLength);
+        }
+        // If the string is not a printf-style conversion specifier for a float,
+        // simply catenate the string with the growing line of text.
+        else
+        {
+            strncat (line, subStr, lineLength);
+        }
+           
+        frontTab = backTab + 1;
+        i++;
+    }
+
+    // Append a space to the very end of the line.  The LCD driver looks to the
+    // last character in the line to determine whether to highlight any
+    // remaining whitespace after the text ends.  This approach causes problems
+    // when the parameter is the last text on the line and we are in parameter
+    // modification mode.  Without the extra space at the end of the line, the
+    // LCD controller will highlight the rest of the line even though it is only
+    // the parameter itself that should be highlighted.
+    strncat (line, " ", lineLength);
+
+    // If the parameter has not been selected for modification but the menu item
+    // is currently selected, we highlight the entire line.  In the menu system,
+    // the only allowable character are the standard ASCII codes (0-127).  We
+    // use the (MSB) 7th bit of every character to indicate whether it should be
+    // highlighted/inverted.
+    if (!paramSel && itemSel)
+    {
+        // Set the MSB of each character to invert it when displayed.
+        for (j = strlen(line) - 1; j>= 0; j--)
+            line[j] |= 0x80;
+    }
+    
+    delete[] tempStr;
+    delete[] subStr;
+}
+
+
+// Returns true if the provided string is a printf-style conversion specifier
+// for a float (conversion character is f, e, E, g, or G).  Otherwise, returns
+// false.
+bool MenbedNavigator::checkConvSpec (const char *s)
+{
+    char lastChar;
+
+    // Conversion specifications must begin with a '%'.
+    if (s[0] != '%')
+        return false;
+
+    // Identify the last last character in the conversion specification
+    lastChar = s[strlen(s) - 1];
+
+    // Check that the last character in the conversion specification is either a
+    // 'f', 'e', 'E', 'g', or 'G'--the conversion specifiers for floats.  If it
+    // is, the conversion specification is probably a valid conversion
+    // specification.
+    if ((lastChar == 'f') || (lastChar == 'e') || (lastChar == 'E') ||
+            (lastChar == 'g') || (lastChar == 'G'))
+        return true;
+
+    // Otherwise, it is not.
+    return false;
+}
diff -r 000000000000 -r 92357d1220f3 menbed/menbedRefresher.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedRefresher.cpp	Fri May 19 13:07:52 2017 +0000
@@ -0,0 +1,22 @@
+#include "mbed.h"
+#include "include/menbedRefresher.h"
+#include "include/menbedNavigator.h"
+
+MenbedRefresher::MenbedRefresher (MenbedNavigator *navigator) :
+    navigator(navigator), refreshPeriod_us(50000)
+{
+    ticker.attach_us (navigator, &MenbedNavigator::updateDisplay, refreshPeriod_us);
+}
+
+MenbedRefresher::MenbedRefresher (MenbedNavigator *navigator, uint32_t refreshPeriod_us) :
+    navigator(navigator), refreshPeriod_us(refreshPeriod_us)
+{
+    ticker.attach_us (navigator, &MenbedNavigator::updateDisplay, refreshPeriod_us);
+}
+
+void MenbedRefresher::refreshed (void)
+{
+    // Detatch and then re-attached the ticker to reset it
+    ticker.detach();
+    ticker.attach_us (navigator, &MenbedNavigator::updateDisplay, refreshPeriod_us);
+}
\ No newline at end of file