Final push to unify all menu states

All states are now handled by the new menu system, although some are flagged to have a custom handler that does everything by itself.

I replaced most reference parameters to pointers to be able to typecast in a nicer way.

Key input is not passed as a parameter to the menu functions instead of having global variables they all access. I think I broke one thing by doing this, since there is no way to propagate key input changes to the next frame.
This commit is contained in:
Mikael Degerfält 2019-06-23 16:55:25 +02:00
parent 9a595c0ffc
commit 5b59b4cd0f
4 changed files with 364 additions and 314 deletions

View file

@ -274,12 +274,14 @@ static bool updateAdjustCursor(uint32_t timeNow) {
return false; return false;
} }
int updateAdjustMenu(uint32_t timeNow, uint8_t buttons, bool firstRun, bool drawSensor) { int updateAdjustMenu(uint32_t timeNow, KeyState &input, bool firstRun, bool drawSensor) {
bool redraw = false; bool redraw = false;
int result = 0; int result = 0;
const AdjustMenuEntry *currentMenu = adjustMenuEntries[adjustOption]; const AdjustMenuEntry *currentMenu = adjustMenuEntries[adjustOption];
uint8_t buttons = input.changed ? input.current : 0;
if(firstRun || refreshScreen) { if(firstRun || refreshScreen) {
adjustCurrent = 0; adjustCurrent = 0;
refreshScreen = false; refreshScreen = false;
@ -294,7 +296,6 @@ int updateAdjustMenu(uint32_t timeNow, uint8_t buttons, bool firstRun, bool draw
redraw |= updateAdjustCursor(timeNow); redraw |= updateAdjustCursor(timeNow);
bool save = false; bool save = false;
if( buttons == BTN_DOWN ) { if( buttons == BTN_DOWN ) {
adjustOption += 1; adjustOption += 1;
refreshScreen = 1; refreshScreen = 1;
@ -357,3 +358,4 @@ int updateAdjustMenu(uint32_t timeNow, uint8_t buttons, bool firstRun, bool draw
return result; return result;
} }

View file

@ -11,11 +11,6 @@
#include "settings.h" #include "settings.h"
#include "numenu.h" #include "numenu.h"
static uint8_t lastDeumButtons = 0;
static uint8_t deumButtonState = 0;
static byte buttonPressedAndNotUsed = 0;
enum CursorIdx { enum CursorIdx {
EMain, EMain,
EBreath, EBreath,
@ -44,15 +39,13 @@ const unsigned long cursorBlinkInterval = 300; // the cursor blink toggle int
const unsigned long patchViewTimeUp = 2000; // ms until patch view shuts off const unsigned long patchViewTimeUp = 2000; // ms until patch view shuts off
const unsigned long menuTimeUp = 60000; // menu shuts off after one minute of button inactivity const unsigned long menuTimeUp = 60000; // menu shuts off after one minute of button inactivity
static unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
static unsigned long buttonRepeatTime = 0;
static unsigned long buttonPressedTime = 0;
static unsigned long menuTime = 0; static unsigned long menuTime = 0;
static unsigned long patchViewTime = 0; static unsigned long patchViewTime = 0;
unsigned long cursorBlinkTime = 0; // the last time the cursor was toggled unsigned long cursorBlinkTime = 0; // the last time the cursor was toggled
//Display state //Display state
static byte state = DISPLAYOFF_IDL; static byte menuState= DISPLAYOFF_IDL;
static byte stateFirstRun = 1; static byte stateFirstRun = 1;
// The external function of subSquelch has been broken, // The external function of subSquelch has been broken,
@ -205,10 +198,10 @@ static void plotSubOption(const char* label, int color) {
display.println(label); display.println(label);
} }
static bool drawSubMenu(const MenuPage &page, int color) { static bool drawSubMenu(const MenuPage *page, int color) {
int index = cursors[page.cursor]; int index = cursors[page->cursor];
// TODO: Null check subMenuFunc // TODO: Null check subMenuFunc
const MenuEntry* subEntry = page.entries[index]; const MenuEntry* subEntry = page->entries[index];
switch(subEntry->type) { switch(subEntry->type) {
case MenuType::ESub: case MenuType::ESub:
{ {
@ -245,7 +238,7 @@ static void clearSubValue() {
display.fillRect(65, 24, 60, 37, BLACK); display.fillRect(65, 24, 60, 37, BLACK);
} }
static bool updateSubMenuCursor(const MenuPage &page, uint32_t timeNow) static bool updateSubMenuCursor(const MenuPage *page, uint32_t timeNow)
{ {
if ((timeNow - cursorBlinkTime) > cursorBlinkInterval) { if ((timeNow - cursorBlinkTime) > cursorBlinkInterval) {
cursorBlinkTime = timeNow; cursorBlinkTime = timeNow;
@ -260,35 +253,42 @@ static bool updateSubMenuCursor(const MenuPage &page, uint32_t timeNow)
return false; return false;
} }
static void plotMenuEntries(const MenuPage &page, bool clear = false) { static void plotMenuEntries(const MenuPage *page, bool clear = false) {
int row = 0; int row = 0;
if(clear) { if(clear) {
display.fillRect( 0, MENU_HEADER_OFFSET, 56, 64-MENU_HEADER_OFFSET, BLACK ); display.fillRect( 0, MENU_HEADER_OFFSET, 56, 64-MENU_HEADER_OFFSET, BLACK );
} }
for(int item = offsets[page.cursor]; (item < page.numEntries) && (row < MENU_NUM_ROWS); item++, row++) { for(int item = offsets[page->cursor]; (item < page->numEntries) && (row < MENU_NUM_ROWS); item++, row++) {
int rowPixel = (row)*MENU_ROW_HEIGHT + MENU_HEADER_OFFSET; int rowPixel = (row)*MENU_ROW_HEIGHT + MENU_HEADER_OFFSET;
const char* lineText = page.entries[item]->title; const char* lineText = page->entries[item]->title;
display.setCursor(0,rowPixel); display.setCursor(0,rowPixel);
display.println(lineText); display.println(lineText);
} }
} }
static void drawMenu(const MenuPage &page, const char* customTitle = nullptr) { typedef void (*MenuTitleGetFunc)(char*out);
static void drawMenu(const MenuPage *page) {
//Initialize display and draw menu header + line //Initialize display and draw menu header + line
display.clearDisplay(); display.clearDisplay();
display.setTextSize(1); display.setTextSize(1);
display.setTextColor(WHITE); display.setTextColor(WHITE);
display.setCursor(0,0); display.setCursor(0,0);
if(customTitle)
display.println(customTitle); if(page->flags & EMenuCustomTitle) {
else // This is a bit hacky, but we are reusing the title pointer as a function pointer
display.println(page.title); MenuTitleGetFunc func = (MenuTitleGetFunc)page->title;
char buffer[23];
func(buffer);
display.println(buffer);
} else
display.println(page->title);
display.drawLine(0, MENU_ROW_HEIGHT, 127, MENU_ROW_HEIGHT, WHITE); display.drawLine(0, MENU_ROW_HEIGHT, 127, MENU_ROW_HEIGHT, WHITE);
plotMenuEntries(page); plotMenuEntries(page);
} }
static void drawMenuScreen() { static void mainTitleGetStr(char* out) {
//Construct the title including voltage reading. //Construct the title including voltage reading.
//Involves intricate splicing of the title string with battery voltage //Involves intricate splicing of the title string with battery voltage
char menuTitle[] = "MENU XXX Y.YV"; //Allocate string buffer of appropriate size with some placeholders char menuTitle[] = "MENU XXX Y.YV"; //Allocate string buffer of appropriate size with some placeholders
@ -304,7 +304,7 @@ static void drawMenuScreen() {
splice2[0] = (voltage/10)+'0'; splice2[0] = (voltage/10)+'0';
splice2[2] = (voltage%10)+'0'; splice2[2] = (voltage%10)+'0';
} }
drawMenu(mainMenuPage, menuTitle); strncpy(out, menuTitle, 22);
} }
static void drawTrills(){ static void drawTrills(){
@ -471,8 +471,8 @@ const MenuEntry* mainMenuEntries[] = {
}; };
const MenuPage mainMenuPage = { const MenuPage mainMenuPage = {
nullptr, (const char*)mainTitleGetStr,
EMenuPageRoot, EMenuPageRoot | EMenuCustomTitle,
CursorIdx::EMain, CursorIdx::EMain,
DISPLAYOFF_IDL, DISPLAYOFF_IDL,
ARR_LEN(mainMenuEntries), mainMenuEntries ARR_LEN(mainMenuEntries), mainMenuEntries
@ -806,24 +806,41 @@ const MenuPage vibratoMenuPage = {
ARR_LEN(vibratorMenuEntries), vibratorMenuEntries ARR_LEN(vibratorMenuEntries), vibratorMenuEntries
}; };
//***********************************************************
static bool patchPageUpdate(KeyState& __unused input, uint32_t __unused timeNow);
static bool idlePageUpdate(KeyState& __unused input, uint32_t __unused timeNow);
const MenuPageCustom adjustMenuPage = {
nullptr, EMenuPageCustom, adjustPageUpdate,
};
const MenuPageCustom patchMenuPage = {
nullptr, EMenuPageCustom, patchPageUpdate,
};
const MenuPageCustom idleMenuPage = {
nullptr, EMenuPageCustom, idlePageUpdate,
};
//*********************************************************** //***********************************************************
static bool selectMenuOption(const MenuPage &page) { static bool selectMenuOption(const MenuPage *page) {
int cursorPosition = cursors[page.cursor]; int cursorPosition = cursors[page->cursor];
const MenuEntry* menuEntry = page.entries[cursorPosition]; const MenuEntry* menuEntry = page->entries[cursorPosition];
cursorBlinkTime = millis(); cursorBlinkTime = millis();
switch(menuEntry->type) { switch(menuEntry->type) {
case MenuType::ESub: case MenuType::ESub:
activeSub[page.cursor] = cursorPosition+1; activeSub[page->cursor] = cursorPosition+1;
drawMenuCursor(cursorPosition, WHITE); drawMenuCursor(cursorPosition, WHITE);
drawSubBox( ((const MenuEntrySub*)menuEntry)->subTitle); drawSubBox( ((const MenuEntrySub*)menuEntry)->subTitle);
drawSubMenu(page, WHITE); drawSubMenu(page, WHITE);
return true; return true;
case MenuType::EStateChange: case MenuType::EStateChange:
state = ((const MenuEntryStateCh*)menuEntry)->state; menuState= ((const MenuEntryStateCh*)menuEntry)->state;
stateFirstRun = 1; stateFirstRun = 1;
break; break;
} }
@ -831,25 +848,22 @@ static bool selectMenuOption(const MenuPage &page) {
return false; return false;
} }
//*********************************************************** //***********************************************************
static bool updateSubMenu(const MenuPage &page, uint32_t timeNow) { static bool updateSubMenu(const MenuPage *page, KeyState &input, uint32_t timeNow) {
bool redraw = false; bool redraw = false;
bool redrawSubValue = false; bool redrawSubValue = false;
if (buttonPressedAndNotUsed) { if (input.changed) {
buttonPressedAndNotUsed = 0; int current_sub = activeSub[page->cursor] -1;
int current_sub = activeSub[page.cursor] -1;
if( current_sub < 0) if( current_sub < 0)
return false; return false;
auto sub = (const MenuEntrySub*)page.entries[current_sub]; auto sub = (const MenuEntrySub*)page->entries[current_sub];
uint16_t currentVal = *sub->valuePtr; uint16_t currentVal = *sub->valuePtr;
switch (deumButtonState){ switch (input.current){
case BTN_DOWN: case BTN_DOWN:
if(currentVal > sub->min) { if(currentVal > sub->min) {
currentVal -= 1; currentVal -= 1;
@ -870,16 +884,16 @@ static bool updateSubMenu(const MenuPage &page, uint32_t timeNow) {
if(sub->flags & EMenuEntryEnterHandler) { if(sub->flags & EMenuEntryEnterHandler) {
bool result = sub->onEnterFunc(); bool result = sub->onEnterFunc();
if(result) { if(result) {
activeSub[page.cursor] = 0; activeSub[page->cursor] = 0;
} }
} else { } else {
activeSub[page.cursor] = 0; activeSub[page->cursor] = 0;
sub->applyFunc(*sub); sub->applyFunc(*sub);
} }
break; break;
case BTN_MENU: case BTN_MENU:
activeSub[page.cursor] = 0; activeSub[page->cursor] = 0;
sub->applyFunc(*sub); sub->applyFunc(*sub);
break; break;
} }
@ -899,16 +913,14 @@ static bool updateSubMenu(const MenuPage &page, uint32_t timeNow) {
return redraw; return redraw;
} }
static bool updateMenuPage( const MenuPage &page, uint32_t timeNow ) { static bool updateMenuPage(const MenuPage *page, KeyState &input, uint32_t timeNow) {
byte cursorPos = cursors[page.cursor]; byte cursorPos = cursors[page->cursor];
byte newPos = cursorPos; byte newPos = cursorPos;
bool redraw = false; bool redraw = false;
if (buttonPressedAndNotUsed) { if (input.changed) {
int lastEntry = page.numEntries-1; int lastEntry = page->numEntries-1;
switch (input.current) {
buttonPressedAndNotUsed = 0;
switch (deumButtonState) {
case BTN_DOWN: case BTN_DOWN:
if (cursorPos < lastEntry) if (cursorPos < lastEntry)
newPos = cursorPos+1; newPos = cursorPos+1;
@ -924,7 +936,8 @@ static bool updateMenuPage( const MenuPage &page, uint32_t timeNow ) {
break; break;
case BTN_MENU: case BTN_MENU:
state = page.parentPage; Serial.print("back to parent...");
menuState= page->parentPage;
stateFirstRun = 1; stateFirstRun = 1;
break; break;
} }
@ -935,7 +948,7 @@ static bool updateMenuPage( const MenuPage &page, uint32_t timeNow ) {
cursorNow = BLACK; cursorNow = BLACK;
clearSub(); clearSub();
redraw = true; redraw = true;
cursors[page.cursor] = newPos; cursors[page->cursor] = newPos;
} }
} else if ((timeNow - cursorBlinkTime) > cursorBlinkInterval) { } else if ((timeNow - cursorBlinkTime) > cursorBlinkInterval) {
// Only need to update cursor blink if no buttons were pressed // Only need to update cursor blink if no buttons were pressed
@ -948,60 +961,44 @@ static bool updateMenuPage( const MenuPage &page, uint32_t timeNow ) {
return redraw; return redraw;
} }
static bool updatePage(const MenuPage &page, uint32_t timeNow) { static void checkForPatchView(int buttons);
static bool updatePage(const MenuPage *page, KeyState &input, uint32_t timeNow) {
if(page->flags & EMenuPageCustom) {
auto custom = (const MenuPageCustom*)page;
return custom->menuUpdateFunc(input, timeNow);
}
bool redraw = false;
if (stateFirstRun) { if (stateFirstRun) {
drawMenu(page); drawMenu(page);
stateFirstRun = 0; stateFirstRun = 0;
} }
if (activeSub[page.cursor]) { if (activeSub[page->cursor]) {
return updateSubMenu(page, timeNow); redraw = updateSubMenu(page, input, timeNow);
} else { } else {
return updateMenuPage(page, timeNow); redraw = updateMenuPage(page, input, timeNow);
}
}
if((page->flags & EMenuPageRoot) && input.changed)
checkForPatchView(input.current);
static bool updateSensorPixelsFlag = false;
void drawSensorPixels() {
updateSensorPixelsFlag = true;
}
bool adjustPageUpdate(uint16_t buttonChanges, uint32_t timeNow) {
// This is a hack to update touch_Thr is it was changed..
int old_thr = ctouchThrVal;
int result = updateAdjustMenu(timeNow, buttonChanges, stateFirstRun, updateSensorPixelsFlag);
bool redraw = false;
updateSensorPixelsFlag = false;
stateFirstRun = 0;
buttonPressedAndNotUsed = 0;
if(result < 0) {
// Go back to main menu
state = MAIN_MENU;
stateFirstRun = true;
} else {
redraw = result;
} }
if( old_thr != ctouchThrVal) {
touch_Thr = map(ctouchThrVal,ctouchHiLimit,ctouchLoLimit,ttouchLoLimit,ttouchHiLimit);
}
return redraw; return redraw;
} }
//*********************************************************** //***********************************************************
static void checkForPatchView(int buttons) { static void checkForPatchView(int buttons) {
int trills = readTrills(); int trills = readTrills();
switch (buttons){ switch (buttons) {
case BTN_MENU+BTN_DOWN:
break;
case BTN_MENU+BTN_ENTER: case BTN_MENU+BTN_ENTER:
if (trills) { if (trills) {
state = PATCH_VIEW; menuState= PATCH_VIEW;
stateFirstRun = 1; stateFirstRun = 1;
setFPS(trills, patch); setFPS(trills, patch);
} }
@ -1009,14 +1006,16 @@ static void checkForPatchView(int buttons) {
case BTN_MENU+BTN_UP: case BTN_MENU+BTN_UP:
if (trills) { if (trills) {
state = PATCH_VIEW; menuState= PATCH_VIEW;
stateFirstRun = 1; stateFirstRun = 1;
clearFPS(trills); clearFPS(trills);
} }
break; break;
default: break;
} }
} }
//***********************************************************
// This should be moved to a separate file/process that handles only led // This should be moved to a separate file/process that handles only led
static void statusBlink() { static void statusBlink() {
digitalWrite(statusLedPin,LOW); digitalWrite(statusLedPin,LOW);
@ -1030,12 +1029,219 @@ static void statusBlink() {
//*********************************************************** //***********************************************************
void menu() {
unsigned long timeNow = millis();
const MenuPage *currentPage = nullptr;
bool redraw = stateFirstRun; static bool updateSensorPixelsFlag = false;
// read the state of the switches void drawSensorPixels() {
updateSensorPixelsFlag = true;
}
//***********************************************************
bool adjustPageUpdate(KeyState &input, uint32_t timeNow) {
// This is a hack to update touch_Thr is it was changed..
int old_thr = ctouchThrVal;
int result = updateAdjustMenu(timeNow, input, stateFirstRun, updateSensorPixelsFlag);
bool redraw = false;
updateSensorPixelsFlag = false;
stateFirstRun = 0;
if(result < 0) {
// Go back to main menu
menuState= MAIN_MENU;
stateFirstRun = true;
} else {
redraw = result;
}
if( old_thr != ctouchThrVal) {
touch_Thr = map(ctouchThrVal,ctouchHiLimit,ctouchLoLimit,ttouchLoLimit,ttouchHiLimit);
}
return redraw;
}
static bool patchPageUpdate(KeyState& input, uint32_t timeNow) {
bool redraw = false;
if (stateFirstRun) {
display.ssd1306_command(SSD1306_DISPLAYON);
drawPatchView();
patchViewTime = timeNow;
stateFirstRun = 0;
}
if ((timeNow - patchViewTime) > patchViewTimeUp) {
menuState= DISPLAYOFF_IDL;
stateFirstRun = 1;
doPatchUpdate = 1;
FPD = 0;
writeSetting(PATCH_ADDR,patch);
}
if (input.changed) {
patchViewTime = timeNow;
int trills = readTrills();
switch (input.current){
case BTN_DOWN:
// down
if (trills && (fastPatch[trills-1] > 0)){
patch = fastPatch[trills-1];
activePatch = 0;
doPatchUpdate = 1;
FPD = 1;
writeSetting(PATCH_ADDR,patch);
} else if (!trills){
if (patch > 1){
patch--;
} else patch = 128;
activePatch = 0;
doPatchUpdate = 1;
FPD = 0;
}
drawPatchView();
redraw = true;
break;
case BTN_ENTER:
// enter
if (trills && (fastPatch[trills-1] > 0)){
patch = fastPatch[trills-1];
activePatch = 0;
doPatchUpdate = 1;
FPD = 1;
drawPatchView();
redraw = true;
}
break;
case BTN_UP:
// up
if (trills && (fastPatch[trills-1] > 0)){
patch = fastPatch[trills-1];
activePatch = 0;
doPatchUpdate = 1;
FPD = 1;
writeSetting(PATCH_ADDR,patch);
} else if (!trills){
if (patch < 128){
patch++;
} else patch = 1;
activePatch = 0;
doPatchUpdate = 1;
FPD = 0;
}
drawPatchView();
redraw = true;
break;
case BTN_MENU:
if (FPD < 2){
menuState= DISPLAYOFF_IDL;
stateFirstRun = 1;
doPatchUpdate = 1;
}
writeSetting(PATCH_ADDR,patch);
FPD = 0;
break;
case BTN_MENU+BTN_ENTER:
midiPanic();
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(35,15);
display.println("DON'T");
display.setCursor(35,30);
display.println("PANIC");
redraw = true;
break;
case BTN_MENU+BTN_ENTER+BTN_UP+BTN_DOWN:
//all keys depressed, reboot to programming mode
_reboot_Teensyduino_();
}
}
return redraw;
}
static bool idlePageUpdate(KeyState& __unused input, uint32_t __unused timeNow) {
bool redraw = false;
if (stateFirstRun) {
display.ssd1306_command(SSD1306_DISPLAYOFF);
display.clearDisplay();
redraw = true;
stateFirstRun = 0;
}
if (input.changed) {
int trills = readTrills();
switch (input.current){
case BTN_UP: // fallthrough
case BTN_DOWN:
if (trills && (fastPatch[trills-1] > 0)){
patch = fastPatch[trills-1];
activePatch = 0;
doPatchUpdate = 1;
FPD = 1;
} // else if (!trills) buttonPressedAndNotUsed = 1; // <- TODO: this is now broken, all input is consumed... solve in another way.
menuState= PATCH_VIEW;
stateFirstRun = 1;
break;
case BTN_ENTER:
if (trills && (fastPatch[trills-1] > 0)){
patch = fastPatch[trills-1];
activePatch = 0;
doPatchUpdate = 1;
FPD = 1;
}
menuState= PATCH_VIEW;
stateFirstRun = 1;
break;
case BTN_MENU:
if (pinkyKey && (exSensor >= ((extracThrVal+extracMaxVal)/2))) { // switch breath activated legacy settings on/off
legacyBrAct = !legacyBrAct;
dipSwBits = dipSwBits ^ (1<<2);
writeSetting(DIPSW_BITS_ADDR,dipSwBits);
statusBlink();
} else if ((exSensor >= ((extracThrVal+extracMaxVal)/2))) { // switch pb pad activated legacy settings control on/off
legacy = !legacy;
dipSwBits = dipSwBits ^ (1<<1);
writeSetting(DIPSW_BITS_ADDR,dipSwBits);
statusBlink();
} else if (pinkyKey && !specialKey){ //hold pinky key for rotator menu, and if too high touch sensing blocks regular menu, touching special key helps
display.ssd1306_command(SSD1306_DISPLAYON);
menuState= ROTATOR_MENU;
stateFirstRun = 1;
} else {
display.ssd1306_command(SSD1306_DISPLAYON);
menuState= MAIN_MENU;
stateFirstRun = 1;
}
break;
case BTN_UP | BTN_DOWN | BTN_ENTER | BTN_MENU:
//all keys depressed, reboot to programming mode
_reboot_Teensyduino_();
}
}
return redraw;
}
//***********************************************************
static KeyState readInput(uint32_t timeNow) {
static uint32_t lastDebounceTime = 0; // the last time the output pin was toggled
static uint32_t buttonRepeatTime = 0;
static uint32_t buttonPressedTime = 0;
static uint8_t lastDeumButtons = 0;
static uint8_t deumButtonState = 0;
KeyState keys = { deumButtonState, 0 };
uint8_t deumButtons = 0x0f ^(digitalRead(dPin) | (digitalRead(ePin) << 1) | (digitalRead(uPin) << 2) | (digitalRead(mPin)<<3)); uint8_t deumButtons = 0x0f ^(digitalRead(dPin) | (digitalRead(ePin) << 1) | (digitalRead(uPin) << 2) | (digitalRead(mPin)<<3));
// check to see if you just pressed the button // check to see if you just pressed the button
@ -1048,230 +1254,65 @@ void menu() {
lastDebounceTime = timeNow; lastDebounceTime = timeNow;
} }
if ((timeNow - lastDebounceTime) > debounceDelay) { if ((timeNow - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer than the debounce // whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state: // delay, so take it as the actual current state:
// if the button state has changed: // if the button state has changed:
if (deumButtons != deumButtonState) { if (deumButtons != deumButtonState) {
keys.current = deumButtons;
keys.changed = deumButtonState ^ deumButtons;
deumButtonState = deumButtons; deumButtonState = deumButtons;
menuTime = timeNow; menuTime = timeNow;
buttonPressedAndNotUsed = 1;
buttonPressedTime = timeNow; buttonPressedTime = timeNow;
} }
if (((deumButtons == 1) || (deumButtons == 4)) && (timeNow - buttonPressedTime > buttonRepeatDelay) && (timeNow - buttonRepeatTime > buttonRepeatInterval)){ if (((deumButtons == BTN_DOWN) || (deumButtons == BTN_UP)) && (timeNow - buttonPressedTime > buttonRepeatDelay) && (timeNow - buttonRepeatTime > buttonRepeatInterval)){
buttonPressedAndNotUsed = 1;
buttonRepeatTime = timeNow; buttonRepeatTime = timeNow;
keys.changed = deumButtons; // Key repeat
} }
} }
// save the reading. Next time through the loop, it'll be the lastButtonState: // save the reading. Next time through the loop, it'll be the lastButtonState:
lastDeumButtons = deumButtons; lastDeumButtons = deumButtons;
// shut off menu system if not used for a while (changes not stored by exiting a setting manually will not be stored in EEPROM) return keys;
if (state && ((timeNow - menuTime) > menuTimeUp)) { }
state = DISPLAYOFF_IDL;
stateFirstRun = 1;
void menu() {
unsigned long timeNow = millis();
bool redraw = stateFirstRun;
KeyState input = readInput(timeNow);
// read the state of the switches
// shut off menu system if not used for a while (changes not stored by exiting a setting manually will not be stored in EEPROM)
if (menuState&& ((timeNow - menuTime) > menuTimeUp)) {
menuState= DISPLAYOFF_IDL;
stateFirstRun = 1;
subVibSquelch = 0; subVibSquelch = 0;
memset(activeSub, 0, sizeof(activeSub)); memset(activeSub, 0, sizeof(activeSub));
} }
if (state == DISPLAYOFF_IDL) { if (menuState== DISPLAYOFF_IDL) {
if (stateFirstRun) { redraw |= updatePage((const MenuPage*)&idleMenuPage, input, timeNow);
display.ssd1306_command(SSD1306_DISPLAYOFF); } else if (menuState== PATCH_VIEW) {
stateFirstRun = 0; redraw |= updatePage((const MenuPage*)&patchMenuPage, input, timeNow);
} } else if (menuState== MAIN_MENU) {
if (buttonPressedAndNotUsed) { redraw |= updatePage(&mainMenuPage, input, timeNow);
buttonPressedAndNotUsed = 0; } else if (menuState== ROTATOR_MENU) {
int trills = readTrills(); redraw |= updatePage(&rotatorMenuPage, input, timeNow);
switch (deumButtonState){ } else if (menuState== ADJUST_MENU) {
case BTN_UP: // fallthrough redraw |= updatePage((const MenuPage*)&adjustMenuPage, input, timeNow);
case BTN_DOWN: } else if (menuState== SETUP_BR_MENU) {
if (trills && (fastPatch[trills-1] > 0)){ redraw |= updatePage(&breathMenuPage, input, timeNow);
patch = fastPatch[trills-1]; } else if (menuState== SETUP_CT_MENU) {
activePatch = 0; redraw |= updatePage(&controlMenuPage, input, timeNow);
doPatchUpdate = 1; } else if (menuState== VIBRATO_MENU) {
FPD = 1; redraw |= updatePage(&vibratoMenuPage, input, timeNow);
} else if (!trills) buttonPressedAndNotUsed = 1;
state = PATCH_VIEW;
stateFirstRun = 1;
break;
case BTN_ENTER:
if (trills && (fastPatch[trills-1] > 0)){
patch = fastPatch[trills-1];
activePatch = 0;
doPatchUpdate = 1;
FPD = 1;
}
state = PATCH_VIEW;
stateFirstRun = 1;
break;
case BTN_MENU:
if (pinkyKey && (exSensor >= ((extracThrVal+extracMaxVal)/2))) { // switch breath activated legacy settings on/off
legacyBrAct = !legacyBrAct;
dipSwBits = dipSwBits ^ (1<<2);
writeSetting(DIPSW_BITS_ADDR,dipSwBits);
statusBlink();
} else if ((exSensor >= ((extracThrVal+extracMaxVal)/2))) { // switch pb pad activated legacy settings control on/off
legacy = !legacy;
dipSwBits = dipSwBits ^ (1<<1);
writeSetting(DIPSW_BITS_ADDR,dipSwBits);
statusBlink();
} else if (pinkyKey && !specialKey){ //hold pinky key for rotator menu, and if too high touch sensing blocks regular menu, touching special key helps
display.ssd1306_command(SSD1306_DISPLAYON);
state = ROTATOR_MENU;
stateFirstRun = 1;
} else {
display.ssd1306_command(SSD1306_DISPLAYON);
state = MAIN_MENU;
stateFirstRun = 1;
}
break;
case 15:
//all keys depressed, reboot to programming mode
_reboot_Teensyduino_();
}
}
} else if (state == PATCH_VIEW) {
if (stateFirstRun) {
display.ssd1306_command(SSD1306_DISPLAYON);
drawPatchView();
patchViewTime = timeNow;
stateFirstRun = 0;
}
if ((timeNow - patchViewTime) > patchViewTimeUp) {
state = DISPLAYOFF_IDL;
stateFirstRun = 1;
doPatchUpdate = 1;
FPD = 0;
writeSetting(PATCH_ADDR,patch);
}
if (buttonPressedAndNotUsed){
buttonPressedAndNotUsed = 0;
patchViewTime = timeNow;
int trills = readTrills();
switch (deumButtonState){
case BTN_DOWN:
// down
if (trills && (fastPatch[trills-1] > 0)){
patch = fastPatch[trills-1];
activePatch = 0;
doPatchUpdate = 1;
FPD = 1;
writeSetting(PATCH_ADDR,patch);
} else if (!trills){
if (patch > 1){
patch--;
} else patch = 128;
activePatch = 0;
doPatchUpdate = 1;
FPD = 0;
}
drawPatchView();
redraw = true;
break;
case BTN_ENTER:
// enter
if (trills && (fastPatch[trills-1] > 0)){
patch = fastPatch[trills-1];
activePatch = 0;
doPatchUpdate = 1;
FPD = 1;
drawPatchView();
redraw = true;
}
break;
case BTN_UP:
// up
if (trills && (fastPatch[trills-1] > 0)){
patch = fastPatch[trills-1];
activePatch = 0;
doPatchUpdate = 1;
FPD = 1;
writeSetting(PATCH_ADDR,patch);
} else if (!trills){
if (patch < 128){
patch++;
} else patch = 1;
activePatch = 0;
doPatchUpdate = 1;
FPD = 0;
}
drawPatchView();
redraw = true;
break;
case BTN_MENU:
if (FPD < 2){
state = DISPLAYOFF_IDL;
stateFirstRun = 1;
doPatchUpdate = 1;
}
writeSetting(PATCH_ADDR,patch);
FPD = 0;
break;
case BTN_MENU+BTN_ENTER:
midiPanic();
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(35,15);
display.println("DON'T");
display.setCursor(35,30);
display.println("PANIC");
redraw = true;
break;
case BTN_MENU+BTN_ENTER+BTN_UP+BTN_DOWN:
//all keys depressed, reboot to programming mode
_reboot_Teensyduino_();
}
}
} else if (state == MAIN_MENU) { // MAIN MENU HERE <<<<<<<<<<<<<<<
currentPage = &mainMenuPage;
if (stateFirstRun) {
drawMenuScreen();
stateFirstRun = 0;
}
if(activeSub[currentPage->cursor]) {
redraw |= updateSubMenu(*currentPage, timeNow);
} else {
bool hadButtons = buttonPressedAndNotUsed;
redraw |= updateMenuPage(*currentPage, timeNow);
if (hadButtons)
checkForPatchView(deumButtonState);
}
} else if (state == ROTATOR_MENU) { // ROTATOR MENU HERE <<<<<<<<<<<<<<<
currentPage = &rotatorMenuPage;
if (stateFirstRun) {
drawMenu(*currentPage);
stateFirstRun = 0;
}
if(activeSub[currentPage->cursor]) {
redraw |= updateSubMenu(*currentPage, timeNow);
} else {
bool hadButtons = buttonPressedAndNotUsed;
redraw |= updateMenuPage(*currentPage, timeNow);
if (hadButtons)
checkForPatchView(deumButtonState);
}
// end rotator menu
} else if (state == ADJUST_MENU) {
adjustPageUpdate(buttonPressedAndNotUsed ? deumButtonState : 0, timeNow);
} else if (state == SETUP_BR_MENU) { // SETUP BREATH MENU HERE <<<<<<<<<<<<<<
redraw |= updatePage(breathMenuPage, timeNow);
} else if (state == SETUP_CT_MENU) { // SETUP CONTROLLERS MENU HERE <<<<<<<<<<<<<
redraw |= updatePage(controlMenuPage, timeNow);
} else if (state == VIBRATO_MENU) { // VIBRATO MENU HERE <<<<<<<<<<<<<
redraw |= updatePage(vibratoMenuPage, timeNow);
} }
if(redraw) { if(redraw) {

View file

@ -2,6 +2,7 @@
#define __MENU_H #define __MENU_H
#include "Wiring.h" #include "Wiring.h"
#include "numenu.h"
#define MENU_ROW_HEIGHT 9 #define MENU_ROW_HEIGHT 9
#define MENU_HEADER_OFFSET 12 #define MENU_HEADER_OFFSET 12
@ -11,11 +12,11 @@
#define DISPLAYOFF_IDL 0 #define DISPLAYOFF_IDL 0
#define MAIN_MENU 1 #define MAIN_MENU 1
#define PATCH_VIEW 2 #define PATCH_VIEW 2
#define ADJUST_MENU 70 #define ADJUST_MENU 3
#define SETUP_BR_MENU 80 #define SETUP_BR_MENU 4
#define SETUP_CT_MENU 90 #define SETUP_CT_MENU 5
#define ROTATOR_MENU 100 #define ROTATOR_MENU 6
#define VIBRATO_MENU 110 #define VIBRATO_MENU 7
#define ARR_LEN(a) (sizeof (a) / sizeof (a[0])) #define ARR_LEN(a) (sizeof (a) / sizeof (a[0]))
@ -25,7 +26,6 @@
#define BTN_MENU 8 #define BTN_MENU 8
extern const unsigned long debounceDelay; // the debounce time; increase if the output flickers extern const unsigned long debounceDelay; // the debounce time; increase if the output flickers
extern const unsigned long buttonRepeatInterval; extern const unsigned long buttonRepeatInterval;
extern const unsigned long buttonRepeatDelay; extern const unsigned long buttonRepeatDelay;
@ -33,9 +33,7 @@ extern const unsigned long cursorBlinkInterval; // the cursor blink toggle in
extern const unsigned long patchViewTimeUp; // ms until patch view shuts off extern const unsigned long patchViewTimeUp; // ms until patch view shuts off
extern const unsigned long menuTimeUp; // menu shuts off after one minute of button inactivity extern const unsigned long menuTimeUp; // menu shuts off after one minute of button inactivity
extern byte subVibSquelch; // TODO: This is broken <- subVibSquelch is never set, we need another way to expose what menu is open.
extern byte subVibSquelch;
void initDisplay(); void initDisplay();
void showVersion(); void showVersion();
@ -44,7 +42,7 @@ void drawSensorPixels();
unsigned short readSetting(byte address); unsigned short readSetting(byte address);
void writeSetting(byte address, unsigned short value); void writeSetting(byte address, unsigned short value);
int updateAdjustMenu(uint32_t timeNow, uint8_t buttons, bool firstRun, bool updateSensor); int updateAdjustMenu(uint32_t timeNow, KeyState &input, bool firstRun, bool drawSensor);
bool adjustPageUpdate(uint16_t buttonChanges, uint32_t timeNow); bool adjustPageUpdate(KeyState &input, uint32_t timeNow);
#endif #endif

View file

@ -1,6 +1,15 @@
#ifndef __NUMENU_H #ifndef __NUMENU_H
#define __NUMENU_H #define __NUMENU_H
#include <stdint.h>
//***********************************************************
struct KeyState {
uint8_t current;
uint8_t changed;
};
//*********************************************************** //***********************************************************
enum MenuType { enum MenuType {
@ -18,6 +27,7 @@ enum MenuEntryFlags {
enum MenuPageFlags { enum MenuPageFlags {
EMenuPageCustom = (1u<<0), EMenuPageCustom = (1u<<0),
EMenuPageRoot = (1u<<1), EMenuPageRoot = (1u<<1),
EMenuCustomTitle = (1u << 2),
}; };
@ -45,22 +55,22 @@ struct MenuEntrySub {
struct MenuEntryStateCh { struct MenuEntryStateCh {
enum MenuType type; enum MenuType type;
const char* title; const char* title;
byte state; uint8_t state;
}; };
struct MenuPage { struct MenuPage {
const char* title; const char* title;
uint16_t flags; uint16_t flags;
byte cursor; uint8_t cursor;
byte parentPage; uint8_t parentPage;
byte numEntries; uint8_t numEntries;
const MenuEntry** entries; const MenuEntry** entries;
}; };
struct MenuPageCustom { struct MenuPageCustom {
const char* title; const char* title;
uint16_t flags; uint16_t flags;
bool (*menuUpdateFunc)(void); bool (*menuUpdateFunc)(KeyState &input, uint32_t timeNow);
}; };
//*********************************************************** //***********************************************************
@ -77,5 +87,4 @@ struct AdjustMenuEntry {
void (*saveFunc)(const AdjustMenuEntry&); void (*saveFunc)(const AdjustMenuEntry&);
}; };
#endif #endif