mirror of https://github.com/MLXXXp/Arduboy2.git
1193 lines
36 KiB
C++
1193 lines
36 KiB
C++
// ========================================
|
|
// Manage an Arduboy's system EEPROM area
|
|
// ========================================
|
|
|
|
/*
|
|
------------------------------------------------------------------------------
|
|
This sketch allows manipulation of the following values in system EEPROM:
|
|
|
|
- The Unit Name. This is a 6 character field that can be read by sketches
|
|
using the readUnitName() function. Also, the Arduboy2 class will display
|
|
the Unit Name at the end of the boot logo sequence, if possible, during
|
|
start up.
|
|
|
|
- The Unit ID. This is a 16 bit value that can be read by sketches using the
|
|
readUnitID() function.
|
|
|
|
- The "Show Unit Name" flag. This flag indicates whether or not the Unit Name
|
|
should be displayed at the end of the boot logo sequence in circumstances
|
|
where it's possible to do so.
|
|
|
|
- The "Show RGB LEDs with Boot Logo" flag. This flag indicates whether or not
|
|
to flash the RGB LEDs while the boot logo is scrolling down.
|
|
|
|
- The "Show Boot Logo" flag. This flag indicates whether or not to display
|
|
the boot logo sequence during start up.
|
|
|
|
This sketch also allows:
|
|
|
|
- The entire System EEPROM area to be reset back to default values.
|
|
|
|
- The entire User EEPROM area to be reset. This will clear the high scores
|
|
and any other data saved by ALL sketches that have ever been installed.
|
|
------------------------------------------------------------------------------
|
|
*/
|
|
|
|
// Version 2.2
|
|
|
|
/*
|
|
------------------------------------------------------------------------------
|
|
Copyright (c) 2018-2020, Scott Allen
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
3. Neither the name of the copyright holders nor the names of its contributors
|
|
may be used to endorse or promote products derived from this software
|
|
without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS OR
|
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
------------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include <Arduboy2.h>
|
|
#include <EEPROM.h>
|
|
|
|
// The frame rate determines the button auto-repeat rate for unit name entry
|
|
constexpr uint8_t frameRate = 10;
|
|
|
|
// The unit ID auto-repeat rate is slowed, compared to the unit name rate, by
|
|
// repeating only once per the defined number of frames
|
|
constexpr unsigned int idRepeatFrames = 3;
|
|
|
|
// Delay time before button auto-repeat starts, in milliseconds
|
|
constexpr unsigned int repeatDelay = 700;
|
|
|
|
// All the constant stings
|
|
const char StrName[] PROGMEM = "NAME";
|
|
const char StrID[] PROGMEM = "ID";
|
|
const char StrFlags[] PROGMEM = "FLAGS";
|
|
const char StrYes[] PROGMEM = "YES";
|
|
const char StrNo[] PROGMEM = "NO";
|
|
const char StrSaveQ[] PROGMEM = "SAVE?";
|
|
const char StrSaved[] PROGMEM = "SAVED";
|
|
const char StrBtnChangeName[] PROGMEM = "UP:change Unit Name";
|
|
const char StrBtnChangeID[] PROGMEM = "DOWN:change Unit ID";
|
|
const char StrBtnFlags[] PROGMEM = "LEFT:flags";
|
|
const char StrBtnReset[] PROGMEM = "RIGHT:reset";
|
|
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 StrShowLogoQ[] PROGMEM = "show boot logo?";
|
|
const char StrShowLEDsQ[] PROGMEM = "show boot LEDs?";
|
|
const char StrShowNameQ[] PROGMEM = "show unit name?";
|
|
const char StrBtnTestLogo[] PROGMEM = "UP+DOWN:test logo";
|
|
const char StrNoLogo1[] PROGMEM = "\"SHOW BOOT LOGO\"";
|
|
const char StrNoLogo2[] PROGMEM = "flag is OFF";
|
|
const char StrBtnResetSys[] PROGMEM = "UP:reset system";
|
|
const char StrBtnResetUser[] PROGMEM = "Down:reset user";
|
|
const char StrEEPROM[] PROGMEM = "EEPROM";
|
|
const char StrResetSys1[] PROGMEM = "EEPROM reserved for";
|
|
const char StrResetSys2[] PROGMEM = "system use will be";
|
|
const char StrResetSys3[] PROGMEM = "reset to defaults!";
|
|
const char StrResetUser1[] PROGMEM = "EEPROM containing";
|
|
const char StrResetUser2[] PROGMEM = "ALL saved sketch data";
|
|
const char StrResetUser3[] PROGMEM = "will be erased!";
|
|
const char StrAreYouSureQ[] PROGMEM = "ARE YOU SURE?";
|
|
const char StrBtnResetYes[] PROGMEM = "YES:hold A, press B";
|
|
const char StrBtnResetNo[] PROGMEM = "NO:any D-pad button";
|
|
const char StrWriting[] PROGMEM = "WRITING...";
|
|
const char StrSystem[] PROGMEM = "SYSTEM";
|
|
const char StrUser[] PROGMEM = "USER";
|
|
const char StrReset[] PROGMEM = "RESET";
|
|
const char StrHex[] PROGMEM = "hex";
|
|
const char StrDecimal[] PROGMEM = "decimal";
|
|
|
|
// Defines for text and field locations
|
|
#define MENU_BTN_CHANGE_NAME_X centerStr_P(StrBtnChangeName)
|
|
#define MENU_BTN_CHANGE_NAME_Y 0
|
|
#define MENU_NAME_X centerStrLen(ARDUBOY_UNIT_NAME_LEN)
|
|
#define MENU_NAME_Y (MENU_BTN_CHANGE_NAME_Y + charHeight + 3)
|
|
|
|
#define MENU_BTN_CHANGE_ID_X centerStr_P(StrBtnChangeID)
|
|
#define MENU_BTN_CHANGE_ID_Y 26
|
|
#define MENU_HEADING_HEX_X (centerStr_P(StrHex) - (WIDTH / 4))
|
|
#define MENU_HEADING_DECIMAL_X (centerStr_P(StrDecimal) + (WIDTH / 4))
|
|
#define MENU_HEADINGS_Y (MENU_BTN_CHANGE_ID_Y + charHeight + 1)
|
|
#define MENU_ID_HEX_X (centerStrLen(5) - (WIDTH / 4))
|
|
#define MENU_ID_DECIMAL_X (centerStrLen(5) + (WIDTH / 4))
|
|
#define MENU_ID_Y (MENU_HEADINGS_Y + charHeight + 1)
|
|
|
|
#define MENU_BTN_FLAGS_X 0
|
|
#define MENU_BTN_FLAGS_Y 56
|
|
#define MENU_BTN_RESET_X rightStr_P(StrBtnReset)
|
|
#define MENU_BTN_RESET_Y MENU_BTN_FLAGS_Y
|
|
|
|
|
|
#define NAME_TITLE_X centerStr_P(StrName)
|
|
#define NAME_TITLE_Y 0
|
|
|
|
#define NAME_BTN_MENU_X 0
|
|
#define NAME_BTN_MENU_Y 0
|
|
#define NAME_BTN_SAVE_X rightStr_P(StrBtnSave)
|
|
#define NAME_BTN_SAVE_Y NAME_BTN_MENU_Y
|
|
|
|
#define NAME_LARGE_X centerStrLen(ARDUBOY_UNIT_NAME_LEN * 2)
|
|
#define NAME_LARGE_Y 11
|
|
|
|
#define NAME_HEX_X 0
|
|
#define NAME_HEX_Y 40
|
|
#define NAME_DECIMAL_X 0
|
|
#define NAME_DECIMAL_Y 54
|
|
|
|
#define NAME_BTN_YES_X 0
|
|
#define NAME_BTN_YES_Y 0
|
|
#define NAME_BTN_NO_X rightStr_P(StrBtnNo)
|
|
#define NAME_BTN_NO_Y NAME_BTN_YES_Y
|
|
|
|
#define NAME_SAVE_Q_X (centerStr_P(StrSaveQ) - ((6 * charWidth) + (charWidth / 2)))
|
|
#define NAME_SAVE_Q_Y (NAME_LARGE_Y + (charHeight / 2) + 3)
|
|
#define NAME_SAVE_X (NAME_SAVE_Q_X + ((strlen_P(StrSaveQ) * charWidth) + charWidth))
|
|
#define NAME_SAVE_Y (NAME_LARGE_Y + 3)
|
|
|
|
|
|
#define ID_TITLE_X centerStr_P(StrID)
|
|
#define ID_TITLE_Y 0
|
|
|
|
#define ID_BTN_MENU_X 0
|
|
#define ID_BTN_MENU_Y 0
|
|
#define ID_BTN_SAVE_X rightStr_P(StrBtnSave)
|
|
#define ID_BTN_SAVE_Y ID_BTN_MENU_Y
|
|
|
|
#define ID_LARGE_X centerStrLen(5 * 2)
|
|
#define ID_LARGE_Y 13
|
|
|
|
#define ID_2_DECIMAL_X 12
|
|
#define ID_2_DECIMAL_Y 38
|
|
#define ID_DECIMAL_X (WIDTH - (charWidth * 5 + 12))
|
|
#define ID_DECIMAL_Y ID_2_DECIMAL_Y
|
|
|
|
#define ID_BINARY_X 0
|
|
#define ID_BINARY_Y 54
|
|
|
|
#define ID_BTN_YES_X 0
|
|
#define ID_BTN_YES_Y 0
|
|
#define ID_BTN_NO_X rightStr_P(StrBtnNo)
|
|
#define ID_BTN_NO_Y ID_BTN_YES_Y
|
|
|
|
#define ID_SAVE_Q_X (centerStr_P(StrSaveQ) - ((5 * charWidth) + (charWidth / 2)))
|
|
#define ID_SAVE_Q_Y (ID_LARGE_Y + (charHeight / 2) + 1)
|
|
#define ID_SAVE_X (ID_SAVE_Q_X + ((strlen_P(StrSaveQ) * charWidth) + charWidth))
|
|
#define ID_SAVE_Y (ID_LARGE_Y + 1)
|
|
|
|
#define FLAGS_TITLE_X centerStr_P(StrFlags)
|
|
#define FLAGS_TITLE_Y 0
|
|
|
|
#define FLAGS_BTN_MENU_X 0
|
|
#define FLAGS_BTN_MENU_Y 0
|
|
#define FLAGS_BTN_SAVE_X rightStr_P(StrBtnSave)
|
|
#define FLAGS_BTN_SAVE_Y FLAGS_BTN_MENU_Y
|
|
|
|
#define FLAGS_LOGO_Y 14
|
|
#define FLAGS_LEDS_Y 27
|
|
#define FLAGS_NAME_Y 40
|
|
|
|
#define FLAGS_Q_X (charWidth * 2)
|
|
#define FLAGS_SET_X rightStr_P(StrYes)
|
|
#define FLAGS_CURSOR_X 0
|
|
|
|
#define FLAGS_TEST_X centerStr_P(StrBtnTestLogo)
|
|
#define FLAGS_TEST_Y 56
|
|
|
|
#define FLAGS_SAVED_X centerStr2_P(StrSaved)
|
|
#define FLAGS_SAVED_Y ((HEIGHT / 2) - (char2Height / 2))
|
|
|
|
#define FLAGS_NO_LOGO_1_X centerStr_P(StrNoLogo1)
|
|
#define FLAGS_NO_LOGO_1_Y ((HEIGHT / 2) - charHeight - 1)
|
|
#define FLAGS_NO_LOGO_2_X centerStr_P(StrNoLogo2)
|
|
#define FLAGS_NO_LOGO_2_Y (FLAGS_NO_LOGO_1_Y + charHeight + 2)
|
|
|
|
#define RESET_BTN_MENU_X centerStr_P(StrBtnMenu)
|
|
#define RESET_BTN_MENU_Y 0
|
|
#define RESET_BTN_SYS_X centerStr_P(StrBtnResetSys)
|
|
#define RESET_BTN_SYS_Y 16
|
|
#define RESET_BTN_SYS_EEPROM_X centerStr_P(StrEEPROM)
|
|
#define RESET_BTN_SYS_EEPROM_Y (RESET_BTN_SYS_Y + charHeight)
|
|
#define RESET_BTN_USER_X centerStr_P(StrBtnResetUser)
|
|
#define RESET_BTN_USER_Y 40
|
|
#define RESET_BTN_USER_EEPROM_X centerStr_P(StrEEPROM)
|
|
#define RESET_BTN_USER_EEPROM_Y (RESET_BTN_USER_Y + charHeight)
|
|
|
|
#define RESET_SYS_TEXT_1_X centerStr_P(StrResetSys1)
|
|
#define RESET_SYS_TEXT_1_Y 0
|
|
#define RESET_SYS_TEXT_2_X centerStr_P(StrResetSys2)
|
|
#define RESET_SYS_TEXT_2_Y (RESET_SYS_TEXT_1_Y + charHeight)
|
|
#define RESET_SYS_TEXT_3_X centerStr_P(StrResetSys3)
|
|
#define RESET_SYS_TEXT_3_Y (RESET_SYS_TEXT_2_Y + charHeight)
|
|
#define RESET_SYS_SURE_Q_X centerStr_P(StrAreYouSureQ)
|
|
#define RESET_SYS_SURE_Q_Y 32
|
|
#define RESET_SYS_BTN_YES_X centerStr_P(StrBtnResetYes)
|
|
#define RESET_SYS_BTN_YES_Y 48
|
|
#define RESET_SYS_BTN_NO_X centerStr_P(StrBtnResetYes)
|
|
#define RESET_SYS_BTN_NO_Y (RESET_SYS_BTN_YES_Y + charHeight)
|
|
|
|
#define RESET_SYS_CONFIRMED_1_X centerStr2_P(StrSystem)
|
|
#define RESET_SYS_CONFIRMED_1_Y 7
|
|
#define RESET_SYS_CONFIRMED_2_X centerStr2_P(StrEEPROM)
|
|
#define RESET_SYS_CONFIRMED_2_Y (RESET_SYS_CONFIRMED_1_Y + char2Height + 2)
|
|
#define RESET_SYS_CONFIRMED_3_X centerStr2_P(StrReset)
|
|
#define RESET_SYS_CONFIRMED_3_Y (RESET_SYS_CONFIRMED_2_Y + char2Height + 2)
|
|
|
|
#define RESET_USER_TEXT_1_X centerStr_P(StrResetUser1)
|
|
#define RESET_USER_TEXT_1_Y 0
|
|
#define RESET_USER_TEXT_2_X centerStr_P(StrResetUser2)
|
|
#define RESET_USER_TEXT_2_Y (RESET_USER_TEXT_1_Y + charHeight)
|
|
#define RESET_USER_TEXT_3_X centerStr_P(StrResetUser3)
|
|
#define RESET_USER_TEXT_3_Y (RESET_USER_TEXT_2_Y + charHeight)
|
|
#define RESET_USER_SURE_Q_X centerStr_P(StrAreYouSureQ)
|
|
#define RESET_USER_SURE_Q_Y 32
|
|
#define RESET_USER_BTN_YES_X centerStr_P(StrBtnResetYes)
|
|
#define RESET_USER_BTN_YES_Y 48
|
|
#define RESET_USER_BTN_NO_X centerStr_P(StrBtnResetYes)
|
|
#define RESET_USER_BTN_NO_Y (RESET_USER_BTN_YES_Y + charHeight)
|
|
|
|
#define RESET_USER_CONFIRMED_1_X centerStr2_P(StrUser)
|
|
#define RESET_USER_CONFIRMED_1_Y 7
|
|
#define RESET_USER_CONFIRMED_2_X centerStr2_P(StrEEPROM)
|
|
#define RESET_USER_CONFIRMED_2_Y (RESET_USER_CONFIRMED_1_Y + char2Height + 2)
|
|
#define RESET_USER_CONFIRMED_3_X centerStr2_P(StrReset)
|
|
#define RESET_USER_CONFIRMED_3_Y (RESET_USER_CONFIRMED_2_Y + char2Height + 2)
|
|
|
|
#define RESET_USER_WRITING_X centerStr2_P(StrWriting)
|
|
#define RESET_USER_WRITING_Y ((HEIGHT / 2) - (char2Height / 2 - 1))
|
|
|
|
// EEPROM addresses
|
|
constexpr unsigned int EEPROMstart = 0x0000;
|
|
constexpr unsigned int EEPROMsize = 1024;
|
|
constexpr unsigned int EEPROMend = EEPROMstart + EEPROMsize - 1;
|
|
|
|
// Calculation of the number of frames to wait before button auto-repeat starts
|
|
constexpr unsigned int delayFrames = repeatDelay / (1000 / frameRate);
|
|
|
|
// The Arduino "magic" has trouble creating prototypes for functions called
|
|
// by pointers, so they're declared here manually
|
|
void stateMain(), stateName(), stateID(), stateFlags(), stateReset();
|
|
void stateSaveName(), stateSaveID(), stateResetSys(), stateResetUser();
|
|
void screenMain(), screenName(), screenID(), screenFlags(), screenReset();
|
|
void screenSaveName(), screenSaveID(), screenResetSys(), screenResetUser();
|
|
|
|
Arduboy2 arduboy;
|
|
|
|
constexpr uint8_t charSpacing = arduboy.getCharacterSpacing(1);
|
|
constexpr uint8_t char2Spacing = arduboy.getCharacterSpacing(2);
|
|
constexpr uint8_t charWidth = arduboy.getCharacterWidth(1) + charSpacing;
|
|
constexpr uint8_t char2Width = arduboy.getCharacterWidth(2) + char2Spacing;
|
|
constexpr uint8_t charHeight = arduboy.getCharacterHeight(1) +
|
|
arduboy.getLineSpacing(1);
|
|
constexpr uint8_t char2Height = arduboy.getCharacterHeight(2) +
|
|
arduboy.getLineSpacing(2);
|
|
|
|
// The number of pixels for a small space between groups
|
|
constexpr uint8_t smallSpace = 4;
|
|
|
|
char unitName[ARDUBOY_UNIT_NAME_BUFFER_SIZE];
|
|
uint8_t nameIndex;
|
|
|
|
uint16_t unitID;
|
|
uint8_t idIndex;
|
|
|
|
bool showLogoFlag;
|
|
bool showLEDsFlag;
|
|
bool showNameFlag;
|
|
|
|
// Selected flag
|
|
enum class SelectedFlag : uint8_t {
|
|
selFlagLogo,
|
|
selFlagLEDs,
|
|
selFlagName
|
|
};
|
|
|
|
SelectedFlag currentFlag;
|
|
|
|
// Assign numbers for each state/screen
|
|
enum class State : uint8_t {
|
|
sMain,
|
|
sName,
|
|
sID,
|
|
sFlags,
|
|
sReset,
|
|
sSaveName,
|
|
sSaveID,
|
|
sResetSys,
|
|
sResetUser,
|
|
sMAX = sResetUser
|
|
};
|
|
|
|
State currentState;
|
|
|
|
// Function pointer array for button handling
|
|
void (*stateFunc[static_cast<uint8_t>(State::sMAX) + 1])() = {
|
|
stateMain,
|
|
stateName,
|
|
stateID,
|
|
stateFlags,
|
|
stateReset,
|
|
stateSaveName,
|
|
stateSaveID,
|
|
stateResetSys,
|
|
stateResetUser
|
|
};
|
|
|
|
// Function pointer array for screen drawing
|
|
void (*screenFunc[static_cast<uint8_t>(State::sMAX) + 1])() = {
|
|
screenMain,
|
|
screenName,
|
|
screenID,
|
|
screenFlags,
|
|
screenReset,
|
|
screenSaveName,
|
|
screenSaveID,
|
|
screenResetSys,
|
|
screenResetUser
|
|
};
|
|
|
|
unsigned int delayCount = 0;
|
|
bool repeating = false;
|
|
|
|
|
|
// ============================= SETUP ===================================
|
|
void setup() {
|
|
arduboy.begin();
|
|
arduboy.setFrameRate(frameRate);
|
|
setState(State::sMain);
|
|
}
|
|
// =======================================================================
|
|
|
|
|
|
// =========================== MAIN LOOP =================================
|
|
void loop() {
|
|
if (!arduboy.nextFrame()) {
|
|
return;
|
|
}
|
|
|
|
arduboy.pollButtons();
|
|
|
|
(*stateFunc[static_cast<uint8_t>(currentState)])();
|
|
|
|
if ((delayCount != 0) && (--delayCount == 0)) {
|
|
repeating = true;
|
|
}
|
|
}
|
|
// =======================================================================
|
|
|
|
|
|
// ------------------------- Program States ------------------------------
|
|
|
|
// Set to the given state and display the screen for that state
|
|
// Can be called with the current state to update the current screen
|
|
void setState(State newState) {
|
|
currentState = newState;
|
|
stopButtonRepeat();
|
|
drawScreen();
|
|
}
|
|
|
|
// STATE: Main selection screen
|
|
void stateMain() {
|
|
if (arduboy.justPressed(UP_BUTTON)) {
|
|
setState(State::sName);
|
|
}
|
|
else if (arduboy.justPressed(DOWN_BUTTON)) {
|
|
setState(State::sID);
|
|
}
|
|
else if (arduboy.justPressed(LEFT_BUTTON)) {
|
|
setState(State::sFlags);
|
|
}
|
|
else if (arduboy.justPressed(RIGHT_BUTTON)) {
|
|
setState(State::sReset);
|
|
}
|
|
}
|
|
|
|
// STATE: Change unit name
|
|
void stateName() {
|
|
if (arduboy.justPressed(UP_BUTTON)) {
|
|
nameCharInc();
|
|
startButtonDelay();
|
|
}
|
|
else if (arduboy.justPressed(DOWN_BUTTON)) {
|
|
nameCharDec();
|
|
startButtonDelay();
|
|
}
|
|
else if (repeating && arduboy.pressed(UP_BUTTON)) {
|
|
nameCharInc();
|
|
}
|
|
else if (repeating && arduboy.pressed(DOWN_BUTTON)) {
|
|
nameCharDec();
|
|
}
|
|
else if (arduboy.justPressed(RIGHT_BUTTON)) {
|
|
nameCursorRight();
|
|
}
|
|
else if (arduboy.justPressed(LEFT_BUTTON)) {
|
|
nameCursorLeft();
|
|
}
|
|
else if (arduboy.justPressed(A_BUTTON)) {
|
|
setState(State::sMain);
|
|
}
|
|
else if (arduboy.justPressed(B_BUTTON)) {
|
|
setState(State::sSaveName);
|
|
}
|
|
else if (repeating) {
|
|
stopButtonRepeat();
|
|
}
|
|
}
|
|
|
|
// STATE: Change unit ID
|
|
void stateID() {
|
|
if (arduboy.justPressed(UP_BUTTON)) {
|
|
idDigitInc();
|
|
startButtonDelay();
|
|
}
|
|
else if (arduboy.justPressed(DOWN_BUTTON)) {
|
|
idDigitDec();
|
|
startButtonDelay();
|
|
}
|
|
else if (repeating && arduboy.pressed(UP_BUTTON)) {
|
|
if (arduboy.everyXFrames(idRepeatFrames)) {
|
|
idDigitInc();
|
|
}
|
|
}
|
|
else if (repeating && arduboy.pressed(DOWN_BUTTON)) {
|
|
if (arduboy.everyXFrames(idRepeatFrames)) {
|
|
idDigitDec();
|
|
}
|
|
}
|
|
else if (arduboy.justPressed(RIGHT_BUTTON)) {
|
|
idCursorRight();
|
|
}
|
|
else if (arduboy.justPressed(LEFT_BUTTON)) {
|
|
idCursorLeft();
|
|
}
|
|
else if (arduboy.justPressed(A_BUTTON)) {
|
|
setState(State::sMain);
|
|
}
|
|
else if (arduboy.justPressed(B_BUTTON)) {
|
|
setState(State::sSaveID);
|
|
}
|
|
else if (repeating) {
|
|
stopButtonRepeat();
|
|
}
|
|
}
|
|
|
|
// STATE: Set system flags
|
|
void stateFlags() {
|
|
if (arduboy.pressed(UP_BUTTON + DOWN_BUTTON)) {
|
|
showNameFlag = arduboy.readShowUnitNameFlag();
|
|
showLEDsFlag = arduboy.readShowBootLogoLEDsFlag();
|
|
if ((showLogoFlag = arduboy.readShowBootLogoFlag()) == true) {
|
|
arduboy.bootLogo();
|
|
}
|
|
else {
|
|
displayNoLogo();
|
|
}
|
|
currentFlag = SelectedFlag::selFlagLogo;
|
|
setState(State::sFlags);
|
|
}
|
|
else if (arduboy.justPressed(UP_BUTTON)) {
|
|
flagsCursorUp();
|
|
}
|
|
else if (arduboy.justPressed(DOWN_BUTTON)) {
|
|
flagsCursorDown();
|
|
}
|
|
else if (arduboy.justPressed(RIGHT_BUTTON) ||
|
|
arduboy.justPressed(LEFT_BUTTON)) {
|
|
flagToggle();
|
|
}
|
|
else if (arduboy.justPressed(A_BUTTON)) {
|
|
setState(State::sMain);
|
|
}
|
|
else if (arduboy.justPressed(B_BUTTON)) {
|
|
saveFlags();
|
|
setState(State::sFlags);
|
|
}
|
|
}
|
|
|
|
// STATE: Reset EEPROM areas
|
|
void stateReset() {
|
|
if (arduboy.justPressed(UP_BUTTON)) {
|
|
setState(State::sResetSys);
|
|
}
|
|
else if (arduboy.justPressed(DOWN_BUTTON)) {
|
|
setState(State::sResetUser);
|
|
}
|
|
else if (arduboy.justPressed(A_BUTTON)) {
|
|
setState(State::sMain);
|
|
}
|
|
}
|
|
|
|
// STATE: Prompt to save the unit name
|
|
void stateSaveName() {
|
|
if (arduboy.justPressed(A_BUTTON)) {
|
|
arduboy.writeUnitName(unitName);
|
|
setState(State::sMain);
|
|
}
|
|
else if (arduboy.justPressed(B_BUTTON)) {
|
|
setState(State::sName);
|
|
}
|
|
}
|
|
|
|
// STATE: Prompt to save the unit ID
|
|
void stateSaveID() {
|
|
if (arduboy.justPressed(A_BUTTON)) {
|
|
arduboy.writeUnitID(unitID);
|
|
setState(State::sMain);
|
|
}
|
|
else if (arduboy.justPressed(B_BUTTON)) {
|
|
setState(State::sID);
|
|
}
|
|
}
|
|
|
|
// STATE: Prompt to reset system EEPROM
|
|
void stateResetSys() {
|
|
if (arduboy.justPressed(B_BUTTON) && arduboy.pressed(A_BUTTON)) {
|
|
resetSysEEPROM();
|
|
setState(State::sReset);
|
|
}
|
|
else if (arduboy.justPressed(UP_BUTTON) ||
|
|
arduboy.justPressed(DOWN_BUTTON) ||
|
|
arduboy.justPressed(RIGHT_BUTTON) ||
|
|
arduboy.justPressed(LEFT_BUTTON)) {
|
|
setState(State::sReset);
|
|
}
|
|
}
|
|
|
|
// STATE: Prompt to reset user EEPROM
|
|
void stateResetUser() {
|
|
if (arduboy.justPressed(B_BUTTON) && arduboy.pressed(A_BUTTON)) {
|
|
resetUserEEPROM();
|
|
setState(State::sReset);
|
|
}
|
|
else if (arduboy.justPressed(UP_BUTTON) ||
|
|
arduboy.justPressed(DOWN_BUTTON) ||
|
|
arduboy.justPressed(RIGHT_BUTTON) ||
|
|
arduboy.justPressed(LEFT_BUTTON)) {
|
|
setState(State::sReset);
|
|
}
|
|
}
|
|
|
|
// ------------------------- Screen Display ------------------------------
|
|
|
|
// Display the screen for the current state
|
|
void drawScreen() {
|
|
arduboy.clear();
|
|
(*screenFunc[static_cast<uint8_t>(currentState)])();
|
|
arduboy.display();
|
|
}
|
|
|
|
// DISPLAY: Main screen
|
|
void screenMain() {
|
|
readEEPROM();
|
|
nameIndex = idIndex = 0;
|
|
currentFlag = SelectedFlag::selFlagLogo;
|
|
|
|
printStr_P(MENU_BTN_CHANGE_NAME_X, MENU_BTN_CHANGE_NAME_Y, StrBtnChangeName);
|
|
printName(MENU_NAME_X, MENU_NAME_Y);
|
|
|
|
printStr_P(MENU_BTN_CHANGE_ID_X, MENU_BTN_CHANGE_ID_Y, StrBtnChangeID);
|
|
printStr_P(MENU_HEADING_HEX_X, MENU_HEADINGS_Y, StrHex);
|
|
printStr_P(MENU_HEADING_DECIMAL_X, MENU_HEADINGS_Y, StrDecimal);
|
|
printIDHex(MENU_ID_HEX_X, MENU_ID_Y);
|
|
printIDDecimal(MENU_ID_DECIMAL_X, MENU_ID_Y);
|
|
|
|
printStr_P(MENU_BTN_FLAGS_X, MENU_BTN_FLAGS_Y, StrBtnFlags);
|
|
printStr_P(MENU_BTN_RESET_X, MENU_BTN_RESET_Y, StrBtnReset);
|
|
}
|
|
|
|
// DISPLAY: Change unit name
|
|
void screenName() {
|
|
printNameScreenCommon();
|
|
printStr_P(NAME_BTN_MENU_X, NAME_BTN_MENU_Y, StrBtnMenu);
|
|
printStr_P(NAME_BTN_SAVE_X, NAME_BTN_SAVE_Y, StrBtnSave);
|
|
printNameLarge(NAME_LARGE_X, NAME_LARGE_Y);
|
|
printNameUnderline(NAME_LARGE_X, NAME_LARGE_Y);
|
|
printNameCursors();
|
|
}
|
|
|
|
// DISPLAY: Change unit ID
|
|
void screenID() {
|
|
printIDScreenCommon();
|
|
printStr_P(ID_BTN_MENU_X, ID_BTN_MENU_Y, StrBtnMenu);
|
|
printStr_P(ID_BTN_SAVE_X, ID_BTN_SAVE_Y, StrBtnSave);
|
|
printIDLarge(ID_LARGE_X, ID_LARGE_Y);
|
|
printIDCursors();
|
|
}
|
|
|
|
// DISPLAY: Set system flags
|
|
void screenFlags() {
|
|
printStr_P(FLAGS_BTN_MENU_X, FLAGS_BTN_MENU_Y, StrBtnMenu);
|
|
printStr_P(FLAGS_BTN_SAVE_X, FLAGS_BTN_SAVE_Y, StrBtnSave);
|
|
printStr_P(FLAGS_TITLE_X, FLAGS_TITLE_Y, StrFlags);
|
|
printStr_P(FLAGS_Q_X, FLAGS_LOGO_Y, StrShowLogoQ);
|
|
printStr_P(FLAGS_Q_X, FLAGS_LEDS_Y, StrShowLEDsQ);
|
|
printStr_P(FLAGS_Q_X, FLAGS_NAME_Y, StrShowNameQ);
|
|
printFlagSettings();
|
|
printStr_P(FLAGS_TEST_X, FLAGS_TEST_Y, StrBtnTestLogo);
|
|
}
|
|
|
|
// DISPLAY: Reset EEPROM areas
|
|
void screenReset() {
|
|
printStr_P(RESET_BTN_MENU_X, RESET_BTN_MENU_Y, StrBtnMenu);
|
|
printStr_P(RESET_BTN_SYS_X, RESET_BTN_SYS_Y, StrBtnResetSys);
|
|
printStr_P(RESET_BTN_SYS_EEPROM_X, RESET_BTN_SYS_EEPROM_Y, StrEEPROM);
|
|
printStr_P(RESET_BTN_USER_X, RESET_BTN_USER_Y, StrBtnResetUser);
|
|
printStr_P(RESET_BTN_USER_EEPROM_X, RESET_BTN_USER_EEPROM_Y, StrEEPROM);
|
|
}
|
|
|
|
// DISPLAY: Prompt to save the unit name
|
|
void screenSaveName() {
|
|
printNameScreenCommon();
|
|
printStr_P(NAME_BTN_YES_X, NAME_BTN_YES_Y, StrBtnYes);
|
|
printStr_P(NAME_BTN_NO_X, NAME_BTN_NO_Y, StrBtnNo);
|
|
printSavePrompt(NAME_SAVE_Q_X, NAME_SAVE_Q_Y);
|
|
printNameLarge(NAME_SAVE_X, NAME_SAVE_Y);
|
|
}
|
|
|
|
// DISPLAY: Prompt to save the unit ID
|
|
void screenSaveID() {
|
|
printIDScreenCommon();
|
|
printStr_P(ID_BTN_YES_X, ID_BTN_YES_Y, StrBtnYes);
|
|
printStr_P(ID_BTN_NO_X, ID_BTN_NO_Y, StrBtnNo);
|
|
printSavePrompt(ID_SAVE_Q_X, ID_SAVE_Q_Y);
|
|
printIDLarge(ID_SAVE_X, ID_SAVE_Y);
|
|
}
|
|
|
|
// DISPLAY: Prompt to reset the system EEPROM area
|
|
void screenResetSys() {
|
|
printStr_P(RESET_SYS_TEXT_1_X, RESET_SYS_TEXT_1_Y, StrResetSys1);
|
|
printStr_P(RESET_SYS_TEXT_2_X, RESET_SYS_TEXT_2_Y, StrResetSys2);
|
|
printStr_P(RESET_SYS_TEXT_3_X, RESET_SYS_TEXT_3_Y, StrResetSys3);
|
|
printStr_P(RESET_SYS_SURE_Q_X, RESET_SYS_SURE_Q_Y, StrAreYouSureQ);
|
|
printStr_P(RESET_SYS_BTN_YES_X, RESET_SYS_BTN_YES_Y, StrBtnResetYes);
|
|
printStr_P(RESET_SYS_BTN_NO_X, RESET_SYS_BTN_NO_Y, StrBtnResetNo);
|
|
}
|
|
|
|
// DISPLAY: Prompt to reset the user EEPROM area
|
|
void screenResetUser() {
|
|
printStr_P(RESET_USER_TEXT_1_X, RESET_USER_TEXT_1_Y, StrResetUser1);
|
|
printStr_P(RESET_USER_TEXT_2_X, RESET_USER_TEXT_2_Y, StrResetUser2);
|
|
printStr_P(RESET_USER_TEXT_3_X, RESET_USER_TEXT_3_Y, StrResetUser3);
|
|
printStr_P(RESET_USER_SURE_Q_X, RESET_USER_SURE_Q_Y, StrAreYouSureQ);
|
|
printStr_P(RESET_USER_BTN_YES_X, RESET_USER_BTN_YES_Y, StrBtnResetYes);
|
|
printStr_P(RESET_USER_BTN_NO_X, RESET_USER_BTN_NO_Y, StrBtnResetNo);
|
|
}
|
|
|
|
// Display a message indicating "Show boot logo" flag is off
|
|
void displayNoLogo() {
|
|
arduboy.clear();
|
|
printStr_P(FLAGS_NO_LOGO_1_X, FLAGS_NO_LOGO_1_Y, StrNoLogo1);
|
|
printStr_P(FLAGS_NO_LOGO_2_X, FLAGS_NO_LOGO_2_Y, StrNoLogo2);
|
|
arduboy.display();
|
|
arduboy.delayShort(2000);
|
|
}
|
|
|
|
// Save the system flags and overlay the "SAVED" message on the screen
|
|
void saveFlags() {
|
|
arduboy.writeShowUnitNameFlag(showNameFlag);
|
|
arduboy.writeShowBootLogoFlag(showLogoFlag);
|
|
arduboy.writeShowBootLogoLEDsFlag(showLEDsFlag);
|
|
printStrLargeRev_P(FLAGS_SAVED_X, FLAGS_SAVED_Y, StrSaved);
|
|
arduboy.display();
|
|
arduboy.delayShort(1500);
|
|
}
|
|
|
|
// Reset the system EEPROM area and display the confirmation message
|
|
void resetSysEEPROM() {
|
|
for (unsigned int i = EEPROMstart; i < EEPROM_STORAGE_SPACE_START; i++) {
|
|
EEPROM.update(i, 0xFF);
|
|
}
|
|
arduboy.clear();
|
|
printStrLargeRev_P(RESET_SYS_CONFIRMED_1_X, RESET_SYS_CONFIRMED_1_Y, StrSystem);
|
|
printStrLargeRev_P(RESET_SYS_CONFIRMED_2_X, RESET_SYS_CONFIRMED_2_Y, StrEEPROM);
|
|
printStrLargeRev_P(RESET_SYS_CONFIRMED_3_X, RESET_SYS_CONFIRMED_3_Y, StrReset);
|
|
arduboy.display();
|
|
arduboy.delayShort(2000);
|
|
}
|
|
|
|
// Reset the user EEPROM area and display the confirmation message
|
|
void resetUserEEPROM() {
|
|
arduboy.clear();
|
|
arduboy.setTextSize(2);
|
|
printStr_P(RESET_USER_WRITING_X, RESET_USER_WRITING_Y, StrWriting);
|
|
arduboy.setTextSize(1);
|
|
arduboy.display(CLEAR_BUFFER);
|
|
for (unsigned int i = EEPROM_STORAGE_SPACE_START; i <= EEPROMend; i++) {
|
|
EEPROM.update(i, 0xFF);
|
|
}
|
|
printStrLargeRev_P(RESET_USER_CONFIRMED_1_X, RESET_USER_CONFIRMED_1_Y, StrUser);
|
|
printStrLargeRev_P(RESET_USER_CONFIRMED_2_X, RESET_USER_CONFIRMED_2_Y, StrEEPROM);
|
|
printStrLargeRev_P(RESET_USER_CONFIRMED_3_X, RESET_USER_CONFIRMED_3_Y, StrReset);
|
|
arduboy.display();
|
|
arduboy.delayShort(2000);
|
|
}
|
|
|
|
// --------------------- Printing Functions ------------------------------
|
|
|
|
// Print the name entry screen common information
|
|
void printNameScreenCommon() {
|
|
printStr_P(NAME_TITLE_X, NAME_TITLE_Y, StrName);
|
|
printNameHex(NAME_HEX_X, NAME_HEX_Y);
|
|
printNameDecimal(NAME_DECIMAL_X, NAME_DECIMAL_Y);
|
|
}
|
|
|
|
// Print the ID entry screen common information
|
|
void printIDScreenCommon() {
|
|
printStr_P(ID_TITLE_X, ID_TITLE_Y, StrID);
|
|
printIDDecimalBytes(ID_2_DECIMAL_X, ID_2_DECIMAL_Y);
|
|
printIDDecimal(ID_DECIMAL_X, ID_DECIMAL_Y);
|
|
printIDBinary(ID_BINARY_X, ID_BINARY_Y);
|
|
}
|
|
|
|
// Print the name screen cursors
|
|
void printNameCursors() {
|
|
arduboy.fillRect(NAME_LARGE_X + (nameIndex * char2Width),
|
|
NAME_LARGE_Y + char2Height + 2,
|
|
char2Width - char2Spacing, 2);
|
|
|
|
arduboy.drawFastHLine(NAME_HEX_X +
|
|
(nameIndex * (charWidth * 3 + smallSpace)),
|
|
NAME_HEX_Y + charHeight + 1,
|
|
charWidth * 3 - charSpacing);
|
|
|
|
arduboy.drawFastHLine(NAME_DECIMAL_X +
|
|
(nameIndex * (charWidth * 3 + smallSpace)),
|
|
NAME_DECIMAL_Y + charHeight + 1,
|
|
charWidth * 3 - charSpacing);
|
|
}
|
|
|
|
// Print the ID screen cursors
|
|
void printIDCursors() {
|
|
arduboy.fillRect(ID_LARGE_X + ((idIndex + 1) * char2Width),
|
|
ID_LARGE_Y + char2Height,
|
|
char2Width - char2Spacing, 2);
|
|
|
|
arduboy.drawFastHLine(ID_2_DECIMAL_X +
|
|
((idIndex / 2) * (charWidth * 3 + smallSpace)),
|
|
ID_2_DECIMAL_Y + charHeight + 1,
|
|
charWidth * 3 - charSpacing);
|
|
|
|
arduboy.drawFastHLine(ID_DECIMAL_X, ID_DECIMAL_Y + charHeight + 1,
|
|
charWidth * 5 - 1);
|
|
|
|
arduboy.drawFastHLine((ID_BINARY_X + charWidth + smallSpace) +
|
|
(idIndex * (charWidth * 4 + smallSpace)),
|
|
ID_BINARY_Y + charHeight + 1,
|
|
charWidth * 4 - charSpacing);
|
|
}
|
|
|
|
// Print the values and cursor for the flags
|
|
void printFlagSettings() {
|
|
int cursorY;
|
|
uint8_t cursorLen = strlen_P(StrYes) * charWidth - charSpacing;
|
|
|
|
if (showLogoFlag) {
|
|
printStr_P(FLAGS_SET_X, FLAGS_LOGO_Y, StrYes);
|
|
}
|
|
else {
|
|
printStr_P(FLAGS_SET_X, FLAGS_LOGO_Y, StrNo);
|
|
}
|
|
|
|
if (showLEDsFlag) {
|
|
printStr_P(FLAGS_SET_X, FLAGS_LEDS_Y, StrYes);
|
|
}
|
|
else {
|
|
printStr_P(FLAGS_SET_X, FLAGS_LEDS_Y, StrNo);
|
|
}
|
|
|
|
if (showNameFlag) {
|
|
printStr_P(FLAGS_SET_X, FLAGS_NAME_Y, StrYes);
|
|
}
|
|
else {
|
|
printStr_P(FLAGS_SET_X, FLAGS_NAME_Y, StrNo);
|
|
}
|
|
|
|
switch (currentFlag) {
|
|
case SelectedFlag::selFlagLEDs:
|
|
cursorY = FLAGS_LEDS_Y;
|
|
if (!showLEDsFlag) {
|
|
cursorLen = strlen_P(StrNo) * charWidth - charSpacing;
|
|
}
|
|
break;
|
|
case SelectedFlag::selFlagName:
|
|
cursorY = FLAGS_NAME_Y;
|
|
if (!showNameFlag) {
|
|
cursorLen = strlen_P(StrNo) * charWidth - charSpacing;
|
|
}
|
|
break;
|
|
default: // selFlagLogo
|
|
cursorY = FLAGS_LOGO_Y;
|
|
if (!showLogoFlag) {
|
|
cursorLen = strlen_P(StrNo) * charWidth - charSpacing;
|
|
}
|
|
break;
|
|
}
|
|
|
|
arduboy.setCursor(FLAGS_CURSOR_X, cursorY);
|
|
arduboy.print('\x10');
|
|
|
|
arduboy.drawFastHLine(FLAGS_SET_X, cursorY + charHeight, cursorLen);
|
|
}
|
|
|
|
// Print the unit name in normal size including an extent underline
|
|
// at the given location
|
|
void printName(int x, int y) {
|
|
printStr(x, y, unitName);
|
|
|
|
y += (charHeight + 1);
|
|
for (uint8_t i = 0; i < ARDUBOY_UNIT_NAME_LEN; i++, x += charWidth) {
|
|
arduboy.drawFastHLine(x, y, charWidth - charSpacing);
|
|
}
|
|
}
|
|
|
|
// Print the unit name in large size at the given location
|
|
void printNameLarge(int x, int y) {
|
|
arduboy.setTextSize(2);
|
|
printStr(x, y, unitName);
|
|
arduboy.setTextSize(1);
|
|
}
|
|
|
|
// Add a line below the large name showing the current length
|
|
// Coordinates are for the name itself
|
|
void printNameUnderline(int x, int y) {
|
|
int lWidth;
|
|
|
|
if (unitName[0] != 0) {
|
|
x -= 1;
|
|
y += (char2Height + 6);
|
|
lWidth = (strlen(unitName) * char2Width);
|
|
arduboy.drawPixel(x, y);
|
|
arduboy.drawPixel(x + lWidth - 1, y);
|
|
arduboy.drawFastHLine(x, y + 1, lWidth);
|
|
}
|
|
}
|
|
|
|
// Print the unit name in hex at the given location
|
|
void printNameHex(int x, int y) {
|
|
for (uint8_t i = 0; i < ARDUBOY_UNIT_NAME_LEN; i++) {
|
|
printHex8(x, y, unitName[i]);
|
|
x += charWidth * 3 + smallSpace;
|
|
}
|
|
}
|
|
|
|
// Print the unit name in decimal at the given location
|
|
void printNameDecimal(int x, int y) {
|
|
for (uint8_t i = 0; i < ARDUBOY_UNIT_NAME_LEN; i++) {
|
|
printDecimal8(x, y, unitName[i]);
|
|
x += charWidth * 3 + smallSpace;
|
|
}
|
|
}
|
|
|
|
// Print the unit ID in large size at the given location
|
|
void printIDLarge(int x, int y) {
|
|
arduboy.setTextSize(2);
|
|
printIDHex(x, y);
|
|
arduboy.setTextSize(1);
|
|
}
|
|
|
|
// Print the unit ID in normal size at the given location
|
|
void printIDHex(int x, int y) {
|
|
printHex16(x, y, unitID);
|
|
}
|
|
|
|
// Print the unit ID as 2 decimal bytes at the given location
|
|
void printIDDecimalBytes(int x, int y) {
|
|
printDecimal8(x, y, unitID >> 8);
|
|
printDecimal8(x + charWidth * 3 + smallSpace, y, unitID & 0x00FF);
|
|
}
|
|
|
|
// Print the unit ID in decimal at the given location
|
|
void printIDDecimal(int x, int y) {
|
|
printDecimal16(x, y, unitID);
|
|
}
|
|
|
|
// print the unit ID in binary at the given location as 4 nybbles
|
|
// with a leading 'b'
|
|
void printIDBinary(int x, int y) {
|
|
arduboy.setCursor(x, y);
|
|
arduboy.print('b');
|
|
x += charWidth + smallSpace;
|
|
for (char i = 3 * 4; i >= 0; i -= 4) {
|
|
printBinaryNybble(x, y, static_cast<uint8_t>(unitID >> i));
|
|
x += charWidth * 4 + smallSpace;
|
|
}
|
|
}
|
|
|
|
// Print the save prompt in reverse at the given location
|
|
void printSavePrompt(int x, int y) {
|
|
arduboy.fillRect(x - 2, y - 2,
|
|
strlen_P(StrSaveQ) * charWidth + 3, charHeight + 3);
|
|
arduboy.setTextColor(BLACK);
|
|
arduboy.setTextBackground(WHITE);
|
|
printStr_P(x, y, StrSaveQ);
|
|
arduboy.setTextColor(WHITE);
|
|
arduboy.setTextBackground(BLACK);
|
|
}
|
|
|
|
// Print a string at the given location
|
|
void printStr(int x, int y, char* str) {
|
|
arduboy.setCursor(x, y);
|
|
arduboy.print(str);
|
|
}
|
|
|
|
// Print a string in program memory at the given location
|
|
void printStr_P(int x, int y, const char* str) {
|
|
arduboy.setCursor(x, y);
|
|
arduboy.print((__FlashStringHelper*)(str));
|
|
}
|
|
|
|
// Print an 8 bit number in decimal, right justified with leading spaces
|
|
void printDecimal8(int x, int y, uint8_t val) {
|
|
printDecimalHelper(x, y, 2, 100, val);
|
|
}
|
|
|
|
// Print a 16 bit number in decimal, right justified with leading spaces
|
|
void printDecimal16(int x, int y, uint16_t val) {
|
|
printDecimalHelper(x, y, 4, 10000, val);
|
|
}
|
|
|
|
// Print a right justified decimal number, given width-1 and (width-1)^10
|
|
void printDecimalHelper(int x, int y, uint8_t width, uint16_t pwr10,
|
|
uint16_t val) {
|
|
arduboy.setCursor(x, y);
|
|
while (width > 0) {
|
|
if (val >= pwr10) {
|
|
break;
|
|
}
|
|
arduboy.print(' ');
|
|
pwr10 /= 10;
|
|
width--;
|
|
}
|
|
arduboy.print(val);
|
|
}
|
|
|
|
// Print an 8 bit hex number with leading x and zeros
|
|
void printHex8(int x, int y, uint8_t val) {
|
|
arduboy.setCursor(x, y);
|
|
arduboy.print('x');
|
|
if (val < 16) {
|
|
arduboy.print('0');
|
|
}
|
|
arduboy.print(val, HEX);
|
|
}
|
|
|
|
// Print a 16 bit hex number with leading x and zeros
|
|
void printHex16(int x, int y, uint16_t val) {
|
|
arduboy.setCursor(x, y);
|
|
arduboy.print('x');
|
|
for (char i = 3 * 4; i >= 0; i -= 4) {
|
|
arduboy.print((val >> i) & 0x000F, HEX);
|
|
}
|
|
}
|
|
|
|
// Print a nybble in binary from the lowest 4 bits of the provided byte
|
|
void printBinaryNybble(int x, int y, uint8_t val) {
|
|
arduboy.setCursor(x, y);
|
|
|
|
for (char i = 3; i >= 0; i--) {
|
|
arduboy.print((val >> i) & 0x01);
|
|
}
|
|
}
|
|
|
|
// Print a constant string in large size and reversed
|
|
void printStrLargeRev_P(int x, int y, const char* string) {
|
|
arduboy.fillRect(x - 4, y - 4,
|
|
strlen_P(string) * char2Width + 6, char2Height + 6);
|
|
arduboy.setTextColor(BLACK);
|
|
arduboy.setTextBackground(WHITE);
|
|
arduboy.setTextSize(2);
|
|
printStr_P(x, y, string);
|
|
arduboy.setTextSize(1);
|
|
arduboy.setTextColor(WHITE);
|
|
arduboy.setTextBackground(BLACK);
|
|
}
|
|
|
|
// ---------------- Control and Utility Functions ------------------------
|
|
|
|
// Get the current unit name and ID, and the system flags, from EEPROM
|
|
void readEEPROM() {
|
|
memset(unitName, 0, sizeof(unitName));
|
|
arduboy.readUnitName(unitName);
|
|
unitID = arduboy.readUnitID();
|
|
showLogoFlag = arduboy.readShowBootLogoFlag();
|
|
showLEDsFlag = arduboy.readShowBootLogoLEDsFlag();
|
|
showNameFlag = arduboy.readShowUnitNameFlag();
|
|
}
|
|
|
|
// Increment the name character at the cursor position
|
|
void nameCharInc() {
|
|
while (invalidChar(++unitName[nameIndex])) { }
|
|
drawScreen();
|
|
}
|
|
|
|
// Decrement the name character at the cursor position
|
|
void nameCharDec() {
|
|
while (invalidChar(--unitName[nameIndex])) { }
|
|
drawScreen();
|
|
}
|
|
|
|
// Return true if the given character is not allowed
|
|
bool invalidChar(char c) {
|
|
return (c == '\n') || (c == '\r') || (static_cast<uint8_t>(c) == 0xFF);
|
|
}
|
|
|
|
// Move the name cursor right
|
|
void nameCursorRight() {
|
|
if (++nameIndex == ARDUBOY_UNIT_NAME_LEN) {
|
|
nameIndex = 0;
|
|
}
|
|
drawScreen();
|
|
}
|
|
|
|
// Move the name cursor left
|
|
void nameCursorLeft() {
|
|
if (nameIndex == 0) {
|
|
nameIndex = ARDUBOY_UNIT_NAME_LEN - 1;
|
|
}
|
|
else {
|
|
nameIndex--;
|
|
}
|
|
drawScreen();
|
|
}
|
|
|
|
// Increment the ID digit at the cursor position
|
|
void idDigitInc() {
|
|
uint16_t mask = 0xF000 >> (idIndex * 4);
|
|
uint16_t val = 0x1000 >> (idIndex * 4);
|
|
|
|
unitID = (unitID & ~mask) | ((unitID + val) & mask);
|
|
drawScreen();
|
|
}
|
|
|
|
// Decrement the ID digit at the cursor position
|
|
void idDigitDec() {
|
|
uint16_t mask = 0xF000 >> (idIndex * 4);
|
|
uint16_t val = 0x1000 >> (idIndex * 4);
|
|
|
|
unitID = (unitID & ~mask) | ((unitID - val) & mask);
|
|
drawScreen();
|
|
}
|
|
|
|
// Move the ID cursor right
|
|
void idCursorRight() {
|
|
if (++idIndex == sizeof(unitID) * 2) {
|
|
idIndex = 0;
|
|
}
|
|
drawScreen();
|
|
}
|
|
|
|
// Move the ID cursor left
|
|
void idCursorLeft() {
|
|
if (idIndex == 0) {
|
|
idIndex = sizeof(unitID) * 2 - 1;
|
|
}
|
|
else {
|
|
idIndex--;
|
|
}
|
|
drawScreen();
|
|
}
|
|
|
|
// Move the Flags cursor down
|
|
void flagsCursorDown() {
|
|
switch (currentFlag) {
|
|
case SelectedFlag::selFlagLogo:
|
|
currentFlag = SelectedFlag::selFlagLEDs;
|
|
break;
|
|
case SelectedFlag::selFlagLEDs:
|
|
currentFlag = SelectedFlag::selFlagName;
|
|
break;
|
|
case SelectedFlag::selFlagName:
|
|
currentFlag = SelectedFlag::selFlagLogo;
|
|
break;
|
|
}
|
|
drawScreen();
|
|
}
|
|
|
|
// Move the Flags cursor up
|
|
void flagsCursorUp() {
|
|
switch (currentFlag) {
|
|
case SelectedFlag::selFlagName:
|
|
currentFlag = SelectedFlag::selFlagLEDs;
|
|
break;
|
|
case SelectedFlag::selFlagLEDs:
|
|
currentFlag = SelectedFlag::selFlagLogo;
|
|
break;
|
|
case SelectedFlag::selFlagLogo:
|
|
currentFlag = SelectedFlag::selFlagName;
|
|
break;
|
|
}
|
|
drawScreen();
|
|
}
|
|
|
|
// Toggle the currently selected flag
|
|
void flagToggle() {
|
|
switch (currentFlag) {
|
|
case SelectedFlag::selFlagLogo:
|
|
showLogoFlag = !showLogoFlag;
|
|
break;
|
|
case SelectedFlag::selFlagLEDs:
|
|
showLEDsFlag = !showLEDsFlag;
|
|
break;
|
|
case SelectedFlag::selFlagName:
|
|
showNameFlag = !showNameFlag;
|
|
break;
|
|
}
|
|
drawScreen();
|
|
}
|
|
|
|
// Start the button auto-repeat delay
|
|
void startButtonDelay() {
|
|
delayCount = delayFrames;
|
|
repeating = false;
|
|
}
|
|
|
|
// Stop the button auto-repeat or delay
|
|
void stopButtonRepeat() {
|
|
delayCount = 0;
|
|
repeating = false;
|
|
}
|
|
|
|
// Calculate the X coordinate to center a string of the given length
|
|
int centerStrLen(unsigned int len) {
|
|
return (WIDTH / 2) - (len * charWidth / 2);
|
|
}
|
|
|
|
// Calculate the X coordinate to center a string located in program memory
|
|
int centerStr_P(const char* str) {
|
|
return (WIDTH / 2) - (strlen_P(str) * charWidth / 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) * char2Width / 2);
|
|
}
|
|
|
|
// Calculate the X coordinate to right justify a string in program memory
|
|
int rightStr_P(const char* str) {
|
|
return WIDTH - (strlen_P(str) * charWidth) + charSpacing;
|
|
}
|
|
|