From 4f58fa710a1d244ae6756fb6f24738873ca51f5e Mon Sep 17 00:00:00 2001 From: Scott Allen Date: Wed, 29 Mar 2017 17:36:13 -0400 Subject: [PATCH] Make showing the unit name with the logo optional - Added a flag in system EEPROM to indicate if the unit name should be displayed at the end of the boot logo sequence. Function bootLogoExtra() displays the unit name only if the flag is set. - Added functions writeShowUnitNameFlag() and readShowUnitNameFlag() to write and read the "Show Unit Name" flag in EEPROM. - Enhanced the SetNameAndID example sketch to allow setting the "Show Unit Name" flag in EEPROM. --- examples/SetNameAndID/SetNameAndID.ino | 127 ++++++++++++++++++++++--- keywords.txt | 2 + src/Arduboy2.cpp | 27 +++++- src/Arduboy2.h | 43 ++++++++- 4 files changed, 183 insertions(+), 16 deletions(-) diff --git a/examples/SetNameAndID/SetNameAndID.ino b/examples/SetNameAndID/SetNameAndID.ino index 8b4d131..53cf81d 100644 --- a/examples/SetNameAndID/SetNameAndID.ino +++ b/examples/SetNameAndID/SetNameAndID.ino @@ -14,7 +14,7 @@ ---------------------------------------------------------------------------- */ -// Version 1.0 +// Version 2.0 /* ------------------------------------------------------------------------------ @@ -61,14 +61,20 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // All the constant stings const char StrName[] PROGMEM = "NAME"; const char StrID[] PROGMEM = "ID"; +const char StrYes[] PROGMEM = "YES"; +const char StrNo[] PROGMEM = "NO"; const char StrSaveQ[] PROGMEM = "SAVE?"; +const char StrSaved[] PROGMEM = "SAVED"; +const char StrShowNameQ1[] PROGMEM = "Show Unit Name"; +const char StrShowNameQ2[] PROGMEM = "on logo screen?"; const char StrBtnChangeName[] PROGMEM = "UP:change Unit Name"; const char StrBtnChangeID[] PROGMEM = "DOWN:change Unit ID"; +const char StrBtnShowName[] PROGMEM = "LEFT:set \"show name\""; const char StrBtnMenu[] PROGMEM = "A:menu"; const char StrBtnSave[] PROGMEM = "B:save"; const char StrBtnYes[] PROGMEM = "A:yes"; const char StrBtnNo[] PROGMEM = "B:no"; -const char StrBtnLogo[] PROGMEM = "LEFT:show boot logo"; +const char StrBtnTestLogo[] PROGMEM = "DOWN:test boot logo"; const char StrHex[] PROGMEM = "hex"; const char StrDecimal[] PROGMEM = "decimal"; @@ -91,8 +97,8 @@ const char StrDecimal[] PROGMEM = "decimal"; #define MENU_ID_DECIMAL_X (centerStrLen(5) + (WIDTH / 4)) #define MENU_ID_Y (MENU_HEADINGS_Y + CHAR_HEIGHT + 1) -#define MENU_BTN_LOGO_X 0 -#define MENU_BTN_LOGO_Y 56 +#define MENU_BTN_SHOW_NAME_X 0 +#define MENU_BTN_SHOW_NAME_Y 56 #define NAME_TITLE_X centerStr_P(StrName) @@ -151,13 +157,32 @@ const char StrDecimal[] PROGMEM = "decimal"; #define ID_SAVE_X (ID_SAVE_Q_X + ((strlen_P(StrSaveQ) * CHAR_WIDTH) + CHAR_WIDTH)) #define ID_SAVE_Y (ID_LARGE_Y + 1) +#define SHOW_NAME_BTN_MENU_X 0 +#define SHOW_NAME_BTN_MENU_Y 0 +#define SHOW_NAME_BTN_SAVE_X rightStr_P(StrBtnSave) +#define SHOW_NAME_BTN_SAVE_Y SHOW_NAME_BTN_MENU_Y +#define SHOW_NAME_Q_1_X centerStr_P(StrShowNameQ1) +#define SHOW_NAME_Q_1_Y 12 +#define SHOW_NAME_Q_2_X centerStr_P(StrShowNameQ2) +#define SHOW_NAME_Q_2_Y (SHOW_NAME_Q_1_Y + 8) +#define SHOW_NAME_YES_X ((WIDTH / 2) - ((strlen_P(StrYes) + 1) * CHAR_WIDTH * 2)) +#define SHOW_NAME_YES_Y 34 +#define SHOW_NAME_NO_X ((WIDTH / 2) + (CHAR_WIDTH * 2)) +#define SHOW_NAME_NO_Y SHOW_NAME_YES_Y +#define SHOW_NAME_TEST_X 0 +#define SHOW_NAME_TEST_Y 56 +#define SHOW_NAME_SAVED_X centerStr2_P(StrSaved) +#define SHOW_NAME_SAVED_Y ((HEIGHT / 2) - CHAR_HEIGHT) + // Calculation of the number of frames to wait before button auto-repeat starts #define DELAY_FRAMES (REPEAT_DELAY / (1000 / FRAME_RATE)) // The Arduino "magic" has trouble creating prototypes for functions called // by pointers, so they're declared here manually -void stateMain(), stateName(), stateID(), stateSaveName(), stateSaveID(); -void screenMain(), screenName(), screenID(), screenSaveName(), screenSaveID(); +void stateMain(), stateName(), stateID(), stateShowName(); +void stateSaveName(), stateSaveID(); +void screenMain(), screenName(), screenID(), screenShowName(); +void screenSaveName(), screenSaveID(); Arduboy2 arduboy; @@ -167,11 +192,14 @@ byte nameIndex; uint16_t unitID; byte idIndex; +boolean showNameFlag; + // Assign numbers for each state/screen enum State : byte { sMain, sName, sID, + sShowName, sSaveName, sSaveID, sMAX = sSaveID @@ -184,6 +212,7 @@ void (*stateFunc[sMAX + 1])() = { stateMain, stateName, stateID, + stateShowName, stateSaveName, stateSaveID }; @@ -193,6 +222,7 @@ void (*screenFunc[sMAX + 1])() = { screenMain, screenName, screenID, + screenShowName, screenSaveName, screenSaveID }; @@ -246,9 +276,7 @@ void stateMain() { setState(sID); } else if (arduboy.justPressed(LEFT_BUTTON)) { - arduboy.bootLogo(); - delay(1000); - setState(sMain); + setState(sShowName); } } @@ -322,6 +350,29 @@ void stateID() { } } +// STATE: Set "Show Unit Name" flag +void stateShowName() { + if (arduboy.justPressed(RIGHT_BUTTON)) { + showNameToggle(); + } + else if (arduboy.justPressed(LEFT_BUTTON)) { + showNameToggle(); + } + else if (arduboy.justPressed(A_BUTTON)) { + setState(sMain); + } + else if (arduboy.justPressed(B_BUTTON)) { + saveShowName(); + setState(sShowName); + } + else if (arduboy.justPressed(DOWN_BUTTON)) { + showNameFlag = arduboy.readShowUnitNameFlag(); + arduboy.bootLogo(); + delay(1000); + setState(sShowName); + } +} + // STATE: Prompt to save the unit name void stateSaveName() { if (arduboy.justPressed(A_BUTTON)) { @@ -367,7 +418,7 @@ void screenMain() { printIDHex(MENU_ID_HEX_X, MENU_ID_Y); printIDDecimal(MENU_ID_DECIMAL_X, MENU_ID_Y); - printStr_P(MENU_BTN_LOGO_X, MENU_BTN_LOGO_Y, StrBtnLogo); + printStr_P(MENU_BTN_SHOW_NAME_X, MENU_BTN_SHOW_NAME_Y, StrBtnShowName); } // DISPLAY: Change unit name @@ -389,6 +440,20 @@ void screenID() { printIDCursors(); } +// DISPLAY: Set "Show Unit Name" flag +void screenShowName() { + printStr_P(SHOW_NAME_BTN_MENU_X, SHOW_NAME_BTN_MENU_Y, StrBtnMenu); + printStr_P(SHOW_NAME_BTN_SAVE_X, SHOW_NAME_BTN_SAVE_Y, StrBtnSave); + printStr_P(SHOW_NAME_Q_1_X, SHOW_NAME_Q_1_Y, StrShowNameQ1); + printStr_P(SHOW_NAME_Q_2_X, SHOW_NAME_Q_2_Y, StrShowNameQ2); + arduboy.setTextSize(2); + printStr_P(SHOW_NAME_YES_X, SHOW_NAME_YES_Y, StrYes); + printStr_P(SHOW_NAME_NO_X, SHOW_NAME_NO_Y, StrNo); + arduboy.setTextSize(1); + printShowNameCursor(); + printStr_P(SHOW_NAME_TEST_X, SHOW_NAME_TEST_Y, StrBtnTestLogo); +} + // DISPLAY: Prompt to save the unit name void screenSaveName() { printNameScreenCommon(); @@ -407,6 +472,21 @@ void screenSaveID() { printIDLarge(ID_SAVE_X, ID_SAVE_Y); } +// Save the "Show Unit Name" flag and overlay the "SAVED" message on the screen +void saveShowName() { + arduboy.writeShowUnitNameFlag(showNameFlag); + arduboy.fillRect(SHOW_NAME_SAVED_X - 4, SHOW_NAME_SAVED_Y - 4, + strlen_P(StrSaved) * CHAR_WIDTH * 2 + 6, CHAR_HEIGHT * 2 + 6); + arduboy.setTextColor(BLACK); + arduboy.setTextBackground(WHITE); + arduboy.setTextSize(2); + printStr_P(SHOW_NAME_SAVED_X, SHOW_NAME_SAVED_Y, StrSaved); + arduboy.setTextSize(1); + arduboy.setTextColor(WHITE); + arduboy.setTextBackground(BLACK); + arduboy.display(); + delay(1000); +} // --------------------- Printing Functions ------------------------------ @@ -458,6 +538,18 @@ void printIDCursors() { ID_BINARY_Y + CHAR_HEIGHT + 1, CHAR_WIDTH * 4 - 1); } +// Print the current "Show Unit Name" cursor +void printShowNameCursor() { + if (showNameFlag) { + arduboy.fillRect(SHOW_NAME_YES_X, SHOW_NAME_YES_Y + (CHAR_HEIGHT * 2), + (strlen_P(StrYes) * CHAR_WIDTH - 1) * 2, 2); + } + else { + arduboy.fillRect(SHOW_NAME_NO_X, SHOW_NAME_NO_Y + (CHAR_HEIGHT * 2), + (strlen_P(StrNo) * CHAR_WIDTH - 1) * 2, 2); + } +} + // Print the unit name in normal size including an extent underline // at the given location void printName(int x, int y) { @@ -621,11 +713,12 @@ void printBinaryNybble(int x, int y, byte val) { // ---------------- Control and Utility Functions ------------------------ -// Get the current unit name and ID from EEPROM +// Get the current unit name and ID, and the "Show Unit Name" flag, from EEPROM void readEEPROM() { memset(unitName, 0, sizeof(unitName)); arduboy.readUnitName(unitName); unitID = arduboy.readUnitID(); + showNameFlag = arduboy.readShowUnitNameFlag(); } // Increment the name character at the cursor position @@ -701,6 +794,12 @@ void idCursorLeft() { drawScreen(); } +// Toggle the "Show Unit Name" selection +void showNameToggle() { + showNameFlag = !showNameFlag; + drawScreen(); +} + // Start the button auto-repeat delay void startButtonDelay() { delayCount = DELAY_FRAMES; @@ -723,6 +822,12 @@ int centerStr_P(const char* str) { return (WIDTH / 2) - (strlen_P(str) * CHAR_WIDTH / 2); } +// Calculate the X coordinate to center a size 2 string located in +// program memory +int centerStr2_P(const char* str) { + return (WIDTH / 2) - (strlen_P(str) * CHAR_WIDTH); +} + // Calculate the X coordinate to right justify a string in program memory int rightStr_P(const char* str) { return WIDTH - (strlen_P(str) * CHAR_WIDTH) + 1; diff --git a/keywords.txt b/keywords.txt index 0f843bd..620b25e 100644 --- a/keywords.txt +++ b/keywords.txt @@ -66,6 +66,7 @@ paint8Pixels KEYWORD2 paintScreen KEYWORD2 pollButtons KEYWORD2 pressed KEYWORD2 +readShowUnitNameFlag KEYWORD2 readUnitID KEYWORD2 readUnitName KEYWORD2 safeMode KEYWORD2 @@ -81,6 +82,7 @@ SPItransfer KEYWORD2 systemButtons KEYWORD2 toggle KEYWORD2 width KEYWORD2 +writeShowUnitNameFlag KEYWORD2 writeUnitID KEYWORD2 writeUnitName KEYWORD2 diff --git a/src/Arduboy2.cpp b/src/Arduboy2.cpp index d5fad59..71e0088 100644 --- a/src/Arduboy2.cpp +++ b/src/Arduboy2.cpp @@ -983,6 +983,19 @@ void Arduboy2Base::writeUnitName(char* name) } } +bool Arduboy2Base::readShowUnitNameFlag() +{ + return (EEPROM.read(EEPROM_SYS_FLAGS) & SYS_FLAG_UNAME_MASK); +} + +void Arduboy2Base::writeShowUnitNameFlag(bool val) +{ + uint8_t flags = EEPROM.read(EEPROM_SYS_FLAGS); + + bitWrite(flags, SYS_FLAG_UNAME, val); + EEPROM.update(EEPROM_SYS_FLAGS, flags); +} + void Arduboy2Base::swap(int16_t& a, int16_t& b) { int16_t temp = a; @@ -1051,7 +1064,14 @@ void Arduboy2::bootLogoText() void Arduboy2::bootLogoExtra() { - uint8_t c = EEPROM.read(EEPROM_UNIT_NAME); + uint8_t c; + + if (!readShowUnitNameFlag()) + { + return; + } + + c = EEPROM.read(EEPROM_UNIT_NAME); if (c != 0xFF && c != 0x00) { @@ -1063,10 +1083,11 @@ void Arduboy2::bootLogoExtra() { write(c); c = EEPROM.read(++i); - } while (i < EEPROM_UNIT_NAME + ARDUBOY_UNIT_NAME_LEN); + } + while (i < EEPROM_UNIT_NAME + ARDUBOY_UNIT_NAME_LEN); display(); - delay(1500); + delay(1000); } } diff --git a/src/Arduboy2.h b/src/Arduboy2.h index c53fb4d..8bf8c79 100644 --- a/src/Arduboy2.h +++ b/src/Arduboy2.h @@ -38,13 +38,17 @@ #define ARDUBOY_UNIT_NAME_LEN 6 /**< The maximum length of the unit name string. */ #define EEPROM_VERSION 0 -#define EEPROM_BRIGHTNESS 1 +#define EEPROM_SYS_FLAGS 1 #define EEPROM_AUDIO_ON_OFF 2 #define EEPROM_UNIT_ID 8 // A uint16_t binary unit ID #define EEPROM_UNIT_NAME 10 // An up to 6 character unit name. Cannot contain // 0x00 or 0xFF. Lengths less than 6 are padded // with 0x00 +// EEPROM_SYS_FLAGS values +#define SYS_FLAG_UNAME 0 // Display the unit name on the logo screen +#define SYS_FLAG_UNAME_MASK _BV(SYS_FLAG_UNAME) + /** \brief * Start of EEPROM storage space for sketches. * @@ -959,6 +963,38 @@ class Arduboy2Base : public Arduboy2Core */ void writeUnitName(char* name); + /** \brief + * Read the "Show Unit Name" flag in system EEPROM. + * + * \return `true` if the flag is set to indicate that the unit name should + * be displayed. `false` if the flag is set to not display the unit name. + * + * \details + * The "Show Unit Name" flag is used to determine whether the system + * unit name is to be displayed at the end of the boot logo sequence. + * This function returns the value of this flag. + * + * \see writeShowUnitNameFlag() writeUnitName() readUnitName() + * Arduboy2::bootLogoExtra() + */ + bool readShowUnitNameFlag(); + + /** \brief + * Write the "Show Unit Name" flag in system EEPROM. + * + * \param val If `true` the flag is set to indicate that the unit name should + * be displayed. If `false` the flag is set to not display the unit name. + * + * \details + * The "Show Unit Name" flag is used to determine whether the system + * unit name is to be displayed at the end of the boot logo sequence. + * This function allows the flag to be saved with the desired value. + * + * \see readShowUnitNameFlag() writeUnitName() readUnitName() + * Arduboy2::bootLogoExtra() + */ + void writeShowUnitNameFlag(bool val); + /** \brief * A counter which is incremented once per frame. * @@ -1113,11 +1149,14 @@ class Arduboy2 : public Print, public Arduboy2Base * the bottom of the screen. This function pauses for a short time to allow * the name to be seen. * + * The name is not displayed if the "Show Unit Name" flag is not set. + * * \note * This function would not normally be called directly from within a sketch * itself. * - * \see readUnitName() writeUnitName() bootLogo() bootLogoText() begin() + * \see readUnitName() writeUnitName() bootLogo() bootLogoText() + * writeShowUnitNameFlag() begin() */ virtual void bootLogoExtra();