diff --git a/board_single/main/menu.cpp b/board_single/main/menu.cpp index 622b675..ba64bf2 100644 --- a/board_single/main/menu.cpp +++ b/board_single/main/menu.cpp @@ -25,7 +25,9 @@ static int value = 0; //================================ //===== CONFIGURE MENU ITEMS ===== //================================ -// note: when line4 * and line5 * are empty the value is printed large +// Instructions / Behavior: +// - when line4 * and line5 * are empty the value is printed large +// - when 3rd element is not NULL (pointer to defaultValue function) that return value is shown in line 2 //######################### //#### center Joystick #### @@ -33,9 +35,8 @@ static int value = 0; void item_centerJoystick_action(display_task_parameters_t * objects, SSD1306_t * display, int value){ if (!value) return; ESP_LOGW(TAG, "defining joystick center"); - (*objects).joystick->defineCenter(); - //objects->joystick->defineCenter(); - //joystick->defineCenter(); + objects->joystick->defineCenter(); + objects->buzzer->beep(3, 60, 40); } int item_centerJoystick_value(display_task_parameters_t * objects){ return 1; @@ -43,17 +44,18 @@ int item_centerJoystick_value(display_task_parameters_t * objects){ menuItem_t item_centerJoystick = { item_centerJoystick_action, // function action - item_centerJoystick_value, - 0, // valueMin - 1, // valueMAx - 1, // valueIncrement - "Center Joystick", // title - "Center Joystick", // line1 (above value) - "click to confirm", // line2 (above value) - "defines current", // line4 * (below value) - "pos as center", // line5 * - "click to confirm", // line6 - "set 0 to cancel", // line7 + item_centerJoystick_value, // function get initial value + NULL, // function get default value or NULL + 0, // valueMin + 1, // valueMAx + 1, // valueIncrement + "Center Joystick", // title + "Center Joystick", // line1 (above value) + "click to confirm", // line2 (above value) + "defines current", // line4 * (below value) + "pos as center", // line5 * + "click to confirm", // line6 + "set 0 to cancel", // line7 }; @@ -61,6 +63,7 @@ menuItem_t item_centerJoystick = { //#### debug Joystick #### //######################## //continously show/update joystick data on display +#define DEBUG_JOYSTICK_UPDATE_INTERVAL 50 void item_debugJoystick_action(display_task_parameters_t * objects, SSD1306_t * display, int value) { //--- variables --- @@ -90,8 +93,9 @@ void item_debugJoystick_action(display_task_parameters_t * objects, SSD1306_t * displayTextLine(display, 5, false, false, "pos=%-12s ", joystickPosStr[(int)data.position]); // exit when button pressed - if (xQueueReceive(objects->encoderQueue, &event, 20 / portTICK_PERIOD_MS)) + if (xQueueReceive(objects->encoderQueue, &event, DEBUG_JOYSTICK_UPDATE_INTERVAL / portTICK_PERIOD_MS)) { + objects->control->resetTimeout(); switch (event.type) { case RE_ET_BTN_CLICKED: @@ -113,17 +117,18 @@ int item_debugJoystick_value(display_task_parameters_t * objects){ menuItem_t item_debugJoystick = { item_debugJoystick_action, // function action - item_debugJoystick_value, - 0, // valueMin - 1, // valueMAx - 1, // valueIncrement - "Debug joystick", // title - "Debug joystick", // line1 (above value) - "", // line2 (above value) - "click to enter", // line4 * (below value) - "debug screen", // line5 * - "prints values", // line6 - "set 0 to cancel", // line7 + item_debugJoystick_value, // function get initial value + NULL, // function get default value or NULL + 0, // valueMin + 1, // valueMAx + 1, // valueIncrement + "Debug joystick", // title + "Debug joystick", // line1 (above value) + "", // line2 (above value) + "click to enter", // line4 * (below value) + "debug screen", // line5 * + "prints values", // line6 + "set 0 to cancel", // line7 }; @@ -141,20 +146,22 @@ int maxDuty_currentValue(display_task_parameters_t * objects) return 84; } menuItem_t item_maxDuty = { - maxDuty_action, // function action - maxDuty_currentValue, - 1, // valueMin - 99, // valueMAx - 1, // valueIncrement - "max duty", // title - "", // line1 (above value) - " set max-duty: ", // line2 (above value) - "", // line4 * (below value) - "", // line5 * - " 1-99 ", // line6 - " percent ", // line7 + maxDuty_action, // function action + maxDuty_currentValue, // function get initial value + NULL, // function get default value or NULL + 1, // valueMin + 99, // valueMAx + 1, // valueIncrement + "max duty", // title + "", // line1 (above value) + " set max-duty: ", // line2 (above value) + "", // line4 * (below value) + "", // line5 * + " 1-99 ", // line6 + " percent ", // line7 }; + //###################### //##### accelLimit ##### //###################### @@ -167,21 +174,27 @@ int item_accelLimit_value(display_task_parameters_t * objects) { return objects->motorLeft->getFade(fadeType_t::ACCEL); } +int item_accelLimit_default(display_task_parameters_t * objects) +{ + return objects->motorLeft->getFadeDefault(fadeType_t::ACCEL); +} menuItem_t item_accelLimit = { - item_accelLimit_action, // function action - item_accelLimit_value, - 0, // valueMin - 10000, // valueMAx - 100, // valueIncrement - "Accel limit", // title - "Accel limit /", // line1 (above value) - "Fade up time", // line2 (above value) - "", // line4 * (below value) - "", // line5 * - "milliseconds", // line6 - "from 0 to 100%", // line7 + item_accelLimit_action, // function action + item_accelLimit_value, // function get initial value + item_accelLimit_default, // function get default value or NULL + 0, // valueMin + 10000, // valueMAx + 100, // valueIncrement + "Accel limit", // title + " Fade up time", // line1 (above value) + "", // line2 <= showing "default = %d" + "", // line4 * (below value) + "", // line5 * + "milliseconds", // line6 + "from 0 to 100%", // line7 }; + // ###################### // ##### decelLimit ##### // ###################### @@ -194,21 +207,27 @@ int item_decelLimit_value(display_task_parameters_t * objects) { return objects->motorLeft->getFade(fadeType_t::DECEL); } +int item_decelLimit_default(display_task_parameters_t * objects) +{ + return objects->motorLeft->getFadeDefault(fadeType_t::DECEL); +} menuItem_t item_decelLimit = { - item_decelLimit_action, // function action - item_decelLimit_value, - 0, // valueMin - 10000, // valueMAx - 100, // valueIncrement - "Decel limit", // title - "Decel limit /", // line1 (above value) - "Fade down time", // line2 (above value) - "", // line4 * (below value) - "", // line5 * - "milliseconds", // line6 - "from 100 to 0%", // line7 + item_decelLimit_action, // function action + item_decelLimit_value, // function get initial value + item_decelLimit_default, // function get default value or NULL + 0, // valueMin + 10000, // valueMAx + 100, // valueIncrement + "Decel limit", // title + " Fade down time", // line1 (above value) + "", // line2 <= showing "default = %d" + "", // line4 * (below value) + "", // line5 * + "milliseconds", // line6 + "from 100 to 0%", // line7 }; + //##################### //###### example ###### //##################### @@ -217,42 +236,47 @@ void item_example_action(display_task_parameters_t * objects, SSD1306_t * displa return; } int item_example_value(display_task_parameters_t * objects){ - return 53; + return 53; //initial value shown / changed from +} +int item_example_valueDefault(display_task_parameters_t * objects){ + return 931; // optionally shown in line 2 as "default = %d" } menuItem_t item_example = { item_example_action, // function action - item_example_value, - -255, // valueMin - 255, // valueMAx - 2, // valueIncrement - "example-item-max", // title - "line 1 - above", // line1 (above value) - "line 2 - above", // line2 (above value) - "line 4 - below", // line4 * (below value) - "line 5 - below", // line5 * - "line 6 - below", // line6 - "line 7 - last", // line7 + item_example_value, // function get initial value + NULL, // function get default value or NULL + -255, // valueMin + 255, // valueMAx + 2, // valueIncrement + "example-item-max", // title + "line 1 - above", // line1 (above value) + "line 2 - above", // line2 (above value) + "line 4 - below", // line4 * (below value) + "line 5 - below", // line5 * + "line 6 - below", // line6 + "line 7 - last", // line7 }; menuItem_t item_last = { item_example_action, // function action - item_example_value, - -500, // valueMin - 4500, // valueMAx - 50, // valueIncrement - "set large number", // title - "line 1 - above", // line1 (above value) - "line 2 - above", // line2 (above value) - "", // line4 * (below value) - "", // line5 * - "line 6 - below", // line6 - "line 7 - last", // line7 + item_example_value, // function get initial value + item_example_valueDefault, // function get default value or NULL + -500, // valueMin + 4500, // valueMAx + 50, // valueIncrement + "set large number", // title + "line 1 - above", // line1 (above value) + "line 2 - above", // line2 (above value) + "", // line4 * (below value) + "", // line5 * + "line 6 - below", // line6 + "line 7 - last", // line7 }; //store all configured menu items in one array -menuItem_t menuItems[] = {item_centerJoystick, item_debugJoystick, item_accelLimit, item_decelLimit, item_example, item_last}; -int itemCount = 6; +const menuItem_t menuItems[] = {item_centerJoystick, item_debugJoystick, item_accelLimit, item_decelLimit, item_example, item_last}; +const int itemCount = 6; @@ -298,21 +322,28 @@ void showItemList(SSD1306_t *display, int selectedItem) } } -//--------------------------- -//----- showValueSelect ----- -//--------------------------- +//----------------------------- +//--- showValueSelectStatic --- +//----------------------------- // function that renders value-select screen to display (one update) // shows configured text of selected item and currently selected value // TODO show previous value in one line? -// TODO update changed line only (value) -void showValueSelect(SSD1306_t *display, int selectedItem) +void showValueSelectStatic(display_task_parameters_t * objects, SSD1306_t *display, int selectedItem) { //-- show title line -- displayTextLine(display, 0, false, true, " -- set value -- "); // inverted //-- show text above value -- displayTextLine(display, 1, false, false, "%-16s", menuItems[selectedItem].line1); + +//-- show line 2 or default value --- + if (menuItems[selectedItem].defaultValue != NULL){ + displayTextLineCentered(display, 2, false, false, "default = %d", menuItems[selectedItem].defaultValue(objects)); + } + else{ + //displayTextLine(display, 2, false, false, "previous=%d", menuItems[selectedItem].currentValue(objects)); // <= show previous value displayTextLine(display, 2, false, false, "%-16s", menuItems[selectedItem].line2); +} //-- show value and other configured lines -- // print value large, if 2 description lines are empty @@ -334,6 +365,24 @@ void showValueSelect(SSD1306_t *display, int selectedItem) } } +//----------------------------- +//----- updateValueSelect ----- +//----------------------------- +// update line with currently set value only (increses performance significantly) +void updateValueSelect(SSD1306_t *display, int selectedItem) +{ + // print value large, if 2 description lines are empty + if (strlen(menuItems[selectedItem].line4) == 0 && strlen(menuItems[selectedItem].line5) == 0) + { + // print large value + line5 and line6 + displayTextLineCentered(display, 3, true, false, "%d", value); //large centered + } + else + { + displayTextLineCentered(display, 3, false, false, "%d", value); //centered + } +} + @@ -343,11 +392,12 @@ void showValueSelect(SSD1306_t *display, int selectedItem) //controls menu with encoder input and displays the text on oled display //function is repeatedly called by display task when in menu state #define QUEUE_TIMEOUT 3000 //timeout no encoder event - to handle timeout and not block the display loop -#define MENU_TIMEOUT 60000 //inactivity timeout (switch to IDLE mode) +#define MENU_TIMEOUT 60000 //inactivity timeout (switch to IDLE mode) note: should be smaller than IDLE timeout in control task void handleMenu(display_task_parameters_t * objects, SSD1306_t *display) { static uint32_t lastActivity = 0; static int selectedItem = 0; + static bool staticContentUpdated = false; rotary_encoder_event_t event; // store event data //--- handle different menu states --- @@ -363,10 +413,12 @@ void handleMenu(display_task_parameters_t * objects, SSD1306_t *display) if (xQueueReceive(objects->encoderQueue, &event, QUEUE_TIMEOUT / portTICK_PERIOD_MS)) { lastActivity = esp_log_timestamp(); + objects->control->resetTimeout(); switch (event.type) { case RE_ET_CHANGED: //--- scroll in list --- + objects->buzzer->beep(1, 10, 5); if (event.diff < 0) { if (selectedItem != itemCount - 1) @@ -385,9 +437,11 @@ void handleMenu(display_task_parameters_t * objects, SSD1306_t *display) case RE_ET_BTN_CLICKED: //--- switch to edit value page --- + objects->buzzer->beep(1, 50, 10); ESP_LOGI(TAG, "Button pressed - switching to state SET_VALUE"); // change state (menu to set value) menuState = SET_VALUE; + staticContentUpdated = false; // get currently configured value value = menuItems[selectedItem].currentValue(objects); // clear display @@ -397,6 +451,7 @@ void handleMenu(display_task_parameters_t * objects, SSD1306_t *display) //exit menu mode case RE_ET_BTN_LONG_PRESSED: //change to previous mode (e.g. JOYSTICK) + objects->buzzer->beep(4, 15, 5); objects->control->toggleMode(controlMode_t::MENU); //currently already in MENU -> changes to previous mode ssd1306_clear_screen(display, false); break; @@ -413,15 +468,25 @@ void handleMenu(display_task_parameters_t * objects, SSD1306_t *display) //------------------------- case SET_VALUE: // wait for encoder event - showValueSelect(display, selectedItem); + if (!staticContentUpdated) + { + showValueSelectStatic(objects, display, selectedItem); + staticContentUpdated = true; + } + else + { + // update line with currently set value only (increses performance significantly) + updateValueSelect(display, selectedItem); + } if (xQueueReceive(objects->encoderQueue, &event, QUEUE_TIMEOUT / portTICK_PERIOD_MS)) { - lastActivity = esp_log_timestamp(); + objects->control->resetTimeout(); switch (event.type) { case RE_ET_CHANGED: //-- change value -- + objects->buzzer->beep(1, 25, 10); // increment value if (event.diff < 0) value += menuItems[selectedItem].valueIncrement; @@ -436,6 +501,7 @@ void handleMenu(display_task_parameters_t * objects, SSD1306_t *display) case RE_ET_BTN_CLICKED: //-- apply value -- ESP_LOGI(TAG, "Button pressed - running action function with value=%d for item '%s'", value, menuItems[selectedItem].title); + objects->buzzer->beep(2, 50, 50); menuItems[selectedItem].action(objects, display, value); menuState = MAIN_MENU; break; @@ -444,6 +510,7 @@ void handleMenu(display_task_parameters_t * objects, SSD1306_t *display) case RE_ET_BTN_LONG_PRESSED: break; } + lastActivity = esp_log_timestamp(); } break; } @@ -455,6 +522,7 @@ void handleMenu(display_task_parameters_t * objects, SSD1306_t *display) //close menu and switch to IDLE mode when no encoder event within MENU_TIMEOUT if (esp_log_timestamp() - lastActivity > MENU_TIMEOUT) { + objects->buzzer->beep(1, 500, 10); ESP_LOGW(TAG, "TIMEOUT - no activity for more than %ds -> closing menu, switching to IDLE", MENU_TIMEOUT/1000); // reset menu selectedItem = 0; diff --git a/board_single/main/menu.hpp b/board_single/main/menu.hpp index 96534ea..b7682ec 100644 --- a/board_single/main/menu.hpp +++ b/board_single/main/menu.hpp @@ -17,6 +17,7 @@ typedef struct { void (*action)(display_task_parameters_t * objects, SSD1306_t * display, int value); // pointer to function run when confirmed int (*currentValue)(display_task_parameters_t * objects); // pointer to function to get currently configured value + int (*defaultValue)(display_task_parameters_t * objects); // pointer to function to get currently configured value int valueMin; // min allowed value int valueMax; // max allowed value int valueIncrement; // amount changed at one encoder tick (+/-) diff --git a/common/motorctl.cpp b/common/motorctl.cpp index 5083bc8..ef2dade 100644 --- a/common/motorctl.cpp +++ b/common/motorctl.cpp @@ -351,7 +351,7 @@ void controlledMotor::setFade(fadeType_t fadeType, uint32_t msFadeNew){ break; case fadeType_t::DECEL: ESP_LOGW(TAG, "[%s] changed fade-down time from %d to %d",config.name, msFadeDecel, msFadeNew); - msFadeDecel = msFadeNew; + // write new value to nvs and update the variable writeDecelDuration(msFadeNew); break; } @@ -474,6 +474,11 @@ void controlledMotor::loadDecelDuration(void) // write provided value to nvs to be persistent and update the local variable msFadeAccel void controlledMotor::writeAccelDuration(uint32_t newValue) { + // check if unchanged + if(msFadeAccel == newValue){ + ESP_LOGW(TAG, "value unchanged at %d, not writing to nvs", newValue); + return; + } // generate nvs storage key char key[15]; snprintf(key, 15, "m-%s-accel", config.name); @@ -498,6 +503,11 @@ void controlledMotor::writeAccelDuration(uint32_t newValue) // TODO: reduce duplicate code void controlledMotor::writeDecelDuration(uint32_t newValue) { + // check if unchanged + if(msFadeDecel == newValue){ + ESP_LOGW(TAG, "value unchanged at %d, not writing to nvs", newValue); + return; + } // generate nvs storage key char key[15]; snprintf(key, 15, "m-%s-decel", config.name);