4 errors

Dependencies:   KS0108_PCF8574 mbed

Files at this revision

API Documentation at this revision

Comitter:
GuiTwo
Date:
Tue Sep 11 10:21:10 2012 +0000
Parent:
2:66e4ebaba5df
Commit message:
4 errors on vector .cc

Changed in this revision

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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/displays/include/menbedDisplayHD44780.h	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/displays/menbedDisplayHD44780.cpp	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbed.h	Tue Sep 11 10:21:10 2012 +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 "../KS0108_PCF8574/KS0108.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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedButtonEvent.h	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedButtonHandler.h	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedButtonHandlerTimespec.h	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedDisplay.h	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedDisplayer.h	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedMenu.h	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedMenuItem.h	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedMenuMessage.h	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedMenuParam.h	Tue Sep 11 10:21:10 2012 +0000
@@ -0,0 +1,43 @@
+#ifndef _MENBEDMENUPARAM_H_
+#define _MENBEDMENUPARAM_H_
+
+class MenbedMenuParam {
+public:
+    // 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;
+    
+    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.
+    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.
+    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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedNavigator.h	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedRefresher.h	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/include/menbedStructure.h	Tue Sep 11 10:21:10 2012 +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_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbed.cpp	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedButtonHandler.cpp	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedButtonHandlerTimespec.cpp	Tue Sep 11 10:21:10 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedDisplayer.cpp	Tue Sep 11 10:21:10 2012 +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';
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedMenu.cpp	Tue Sep 11 10:21:10 2012 +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]);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedMenuItem.cpp	Tue Sep 11 10:21:10 2012 +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)
+{}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedMenuMessage.cpp	Tue Sep 11 10:21:10 2012 +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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedMenuParam.cpp	Tue Sep 11 10:21:10 2012 +0000
@@ -0,0 +1,27 @@
+#include "mbed.h"
+#include "include/menbedMenuParam.h"
+
+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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedNavigator.cpp	Tue Sep 11 10:21:10 2012 +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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menbed/menbedRefresher.cpp	Tue Sep 11 10:21:10 2012 +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