Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: KS0108_PCF8574 mbed
Revision 3:ec80bb6ff5da, committed 2012-09-11
- 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
--- /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