Add joystick-calibration wizzard (store in nvs), Optimize Menu
- menu:
    - Add item joystick calibration wizzard
    - Add item RESET (clear nvs and restart)
    - Add configuration option to not show/change value. Instead only show confirm message
      apply this to all items only running action
    - Optimize formatting and comments
- main:
    - pass nvsHandle to display task and joystick class
- joystick:
    - Add methods to write and load calibration values (axis min/max adc value) from nvs
    - Add method to get raw adc value
			
			
This commit is contained in:
		
							parent
							
								
									c9c371a742
								
							
						
					
					
						commit
						cdfa64fbc0
					
				@ -8,6 +8,8 @@ extern "C" {
 | 
				
			|||||||
#include "freertos/FreeRTOS.h"
 | 
					#include "freertos/FreeRTOS.h"
 | 
				
			||||||
#include "freertos/task.h"
 | 
					#include "freertos/task.h"
 | 
				
			||||||
#include "esp_log.h"
 | 
					#include "esp_log.h"
 | 
				
			||||||
 | 
					#include "nvs_flash.h"
 | 
				
			||||||
 | 
					#include "nvs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ssd1306.h"
 | 
					#include "ssd1306.h"
 | 
				
			||||||
#include "font8x8_basic.h"
 | 
					#include "font8x8_basic.h"
 | 
				
			||||||
@ -42,6 +44,7 @@ typedef struct display_task_parameters_t {
 | 
				
			|||||||
    speedSensor * speedLeft;
 | 
					    speedSensor * speedLeft;
 | 
				
			||||||
    speedSensor * speedRight;
 | 
					    speedSensor * speedRight;
 | 
				
			||||||
    buzzer_t *buzzer;
 | 
					    buzzer_t *buzzer;
 | 
				
			||||||
 | 
					    nvs_handle_t * nvsHandle;
 | 
				
			||||||
} display_task_parameters_t;
 | 
					} display_task_parameters_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -152,8 +152,8 @@ void createObjects()
 | 
				
			|||||||
    speedLeft = new speedSensor(speedLeft_config);
 | 
					    speedLeft = new speedSensor(speedLeft_config);
 | 
				
			||||||
    speedRight = new speedSensor(speedRight_config);
 | 
					    speedRight = new speedSensor(speedRight_config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // create joystic instance (joystick.hpp)
 | 
					    // create joystick instance (joystick.hpp)
 | 
				
			||||||
    joystick = new evaluatedJoystick(configJoystick);
 | 
					    joystick = new evaluatedJoystick(configJoystick, &nvsHandle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // create httpJoystick object (http.hpp)
 | 
					    // create httpJoystick object (http.hpp)
 | 
				
			||||||
    httpJoystickMain = new httpJoystick(configHttpJoystickMain);
 | 
					    httpJoystickMain = new httpJoystick(configHttpJoystickMain);
 | 
				
			||||||
@ -286,8 +286,8 @@ extern "C" void app_main(void) {
 | 
				
			|||||||
	//-----------------------------------
 | 
						//-----------------------------------
 | 
				
			||||||
	//----- create task for display -----
 | 
						//----- create task for display -----
 | 
				
			||||||
	//-----------------------------------
 | 
						//-----------------------------------
 | 
				
			||||||
	////task that handles the display (show stats, handle menu in 'MENU' mode)
 | 
						//task that handles the display (show stats, handle menu in 'MENU' mode)
 | 
				
			||||||
	display_task_parameters_t display_param = {display_config, control, joystick, encoderQueue, motorLeft, motorRight, speedLeft, speedRight, buzzer};
 | 
						display_task_parameters_t display_param = {display_config, control, joystick, encoderQueue, motorLeft, motorRight, speedLeft, speedRight, buzzer, &nvsHandle};
 | 
				
			||||||
	xTaskCreate(&display_task, "display_task", 3*2048, &display_param, 3, NULL);
 | 
						xTaskCreate(&display_task, "display_task", 3*2048, &display_param, 3, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vTaskDelay(200 / portTICK_PERIOD_MS); //wait for all tasks to finish initializing
 | 
						vTaskDelay(200 / portTICK_PERIOD_MS); //wait for all tasks to finish initializing
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,8 @@ static int value = 0;
 | 
				
			|||||||
//================================
 | 
					//================================
 | 
				
			||||||
// Instructions / Behavior:
 | 
					// Instructions / Behavior:
 | 
				
			||||||
// - when line4 * and line5 * are empty the value is printed large
 | 
					// - 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
 | 
					// - when 3rd element is not NULL (pointer to defaultValue function) return int value of that function is shown in line 2
 | 
				
			||||||
 | 
					// - when 2nd element is NULL (pointer to currentValue function): instead of current value "click to confirm is shown" in line 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#########################
 | 
					//#########################
 | 
				
			||||||
//#### center Joystick ####
 | 
					//#### center Joystick ####
 | 
				
			||||||
@ -38,24 +39,146 @@ void item_centerJoystick_action(display_task_parameters_t * objects, SSD1306_t *
 | 
				
			|||||||
    objects->joystick->defineCenter();
 | 
					    objects->joystick->defineCenter();
 | 
				
			||||||
    objects->buzzer->beep(3, 60, 40);
 | 
					    objects->buzzer->beep(3, 60, 40);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
int item_centerJoystick_value(display_task_parameters_t * objects){
 | 
					 | 
				
			||||||
    return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
menuItem_t item_centerJoystick = {
 | 
					menuItem_t item_centerJoystick = {
 | 
				
			||||||
    item_centerJoystick_action, // function action
 | 
					    item_centerJoystick_action, // function action
 | 
				
			||||||
    item_centerJoystick_value,  // function get initial value
 | 
					    NULL,                       // function get initial value or NULL(show in line 2)
 | 
				
			||||||
    NULL,                       // function get default value or NULL
 | 
					    NULL,                       // function get default value or NULL(dont set value, show msg)
 | 
				
			||||||
    0,                          // valueMin
 | 
					    0,                          // valueMin
 | 
				
			||||||
    1,                          // valueMAx
 | 
					    0,                          // valueMax
 | 
				
			||||||
    1,                          // valueIncrement
 | 
					    0,                          // valueIncrement
 | 
				
			||||||
    "Center Joystick ",          // title
 | 
					    "Center Joystick ",          // title
 | 
				
			||||||
    "Center Joystick ",          // line1 (above value)
 | 
					    "Center Joystick ",          // line1 (above value)
 | 
				
			||||||
    "click to confirm",         // line2 (above value)
 | 
					    "",                         // line2 (above value)
 | 
				
			||||||
    "defines current ",          // line4 * (below value)
 | 
					    "defines current ",          // line4 * (below value)
 | 
				
			||||||
    "pos as center   ",            // line5 *
 | 
					    "pos as center   ",            // line5 *
 | 
				
			||||||
    "click to confirm",         // line6
 | 
					    "",                         // line6
 | 
				
			||||||
    "set 0 to cancel",          // line7
 | 
					    "=>long to cancel",           // line7
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ############################
 | 
				
			||||||
 | 
					// #### calibrate Joystick ####
 | 
				
			||||||
 | 
					// ############################
 | 
				
			||||||
 | 
					// continously show/update joystick data on display
 | 
				
			||||||
 | 
					#define CALIBRATE_JOYSTICK_UPDATE_INTERVAL 50
 | 
				
			||||||
 | 
					void item_calibrateJoystick_action(display_task_parameters_t *objects, SSD1306_t *display, int value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    //--- variables ---
 | 
				
			||||||
 | 
					    bool running = true;
 | 
				
			||||||
 | 
					    joystickCalibrationMode_t mode = X_MIN;
 | 
				
			||||||
 | 
					    rotary_encoder_event_t event;
 | 
				
			||||||
 | 
					    int valueNow = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //-- pre loop instructions --
 | 
				
			||||||
 | 
					    ESP_LOGW(TAG, "starting joystick calibration sequence");
 | 
				
			||||||
 | 
					    ssd1306_clear_screen(display, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //-- show static lines --
 | 
				
			||||||
 | 
					    // show first line (title)
 | 
				
			||||||
 | 
					    displayTextLine(display, 0, false, true, "calibrate stick");
 | 
				
			||||||
 | 
					    // show last line (info)
 | 
				
			||||||
 | 
					    displayTextLineCentered(display, 7, false, true, " click: confirm ");
 | 
				
			||||||
 | 
					    // show initital state
 | 
				
			||||||
 | 
					    displayTextLineCentered(display, 1, true, false, "%s", "X-min");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //-- loop until all positions are defined --
 | 
				
			||||||
 | 
					    while (running && objects->control->getCurrentMode() == controlMode_t::MENU)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // repeatedly print adc value depending on currently selected axis
 | 
				
			||||||
 | 
					        switch (mode)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        case X_MIN:
 | 
				
			||||||
 | 
					        case X_MAX:
 | 
				
			||||||
 | 
					            displayTextLineCentered(display, 4, true, false, "%d", valueNow = objects->joystick->getRawX()); // large
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case Y_MIN:
 | 
				
			||||||
 | 
					        case Y_MAX:
 | 
				
			||||||
 | 
					            displayTextLineCentered(display, 4, true, false, "%d", valueNow = objects->joystick->getRawY()); // large
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case X_CENTER:
 | 
				
			||||||
 | 
					        case Y_CENTER:
 | 
				
			||||||
 | 
					            displayTextLine(display, 4, false, false, "    x = %d", objects->joystick->getRawX());
 | 
				
			||||||
 | 
					            displayTextLine(display, 5, false, false, "    y = %d", objects->joystick->getRawY());
 | 
				
			||||||
 | 
					            displayTextLine(display, 6, false, false, "release & click!");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // handle encoder event
 | 
				
			||||||
 | 
					        // save and next when button clicked, exit when long pressed
 | 
				
			||||||
 | 
					        if (xQueueReceive(objects->encoderQueue, &event, CALIBRATE_JOYSTICK_UPDATE_INTERVAL / portTICK_PERIOD_MS))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            objects->control->resetTimeout();
 | 
				
			||||||
 | 
					            switch (event.type)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					            case RE_ET_BTN_CLICKED:
 | 
				
			||||||
 | 
					                objects->buzzer->beep(2, 120, 50);
 | 
				
			||||||
 | 
					                switch (mode)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                case X_MIN:
 | 
				
			||||||
 | 
					                    // save x min position
 | 
				
			||||||
 | 
					                    ESP_LOGW(TAG, "calibrate-stick: saving  X_MIN");
 | 
				
			||||||
 | 
					                    objects->joystick->writeCalibration(mode, valueNow);
 | 
				
			||||||
 | 
					                    displayTextLineCentered(display, 1, true, false, "%s", "X-max");
 | 
				
			||||||
 | 
					                    mode = X_MAX;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case X_MAX:
 | 
				
			||||||
 | 
					                    // save x max position
 | 
				
			||||||
 | 
					                    ESP_LOGW(TAG, "calibrate-stick: saving  X_MAX");
 | 
				
			||||||
 | 
					                    objects->joystick->writeCalibration(mode, valueNow);
 | 
				
			||||||
 | 
					                    displayTextLineCentered(display, 1, true, false, "%s", "Y-min");
 | 
				
			||||||
 | 
					                    mode = Y_MIN;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case Y_MIN:
 | 
				
			||||||
 | 
					                    // save y min position
 | 
				
			||||||
 | 
					                    ESP_LOGW(TAG, "calibrate-stick: saving  Y_MIN");
 | 
				
			||||||
 | 
					                    objects->joystick->writeCalibration(mode, valueNow);
 | 
				
			||||||
 | 
					                    displayTextLineCentered(display, 1, true, false, "%s", "Y-max");
 | 
				
			||||||
 | 
					                    mode = Y_MAX;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case Y_MAX:
 | 
				
			||||||
 | 
					                    // save y max position
 | 
				
			||||||
 | 
					                    ESP_LOGW(TAG, "calibrate-stick: saving  Y_MAX");
 | 
				
			||||||
 | 
					                    objects->joystick->writeCalibration(mode, valueNow);
 | 
				
			||||||
 | 
					                    displayTextLineCentered(display, 1, true, false, "%s", "CENTR");
 | 
				
			||||||
 | 
					                    mode = X_CENTER;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case X_CENTER:
 | 
				
			||||||
 | 
					                case Y_CENTER:
 | 
				
			||||||
 | 
					                    // save center position
 | 
				
			||||||
 | 
					                    ESP_LOGW(TAG, "calibrate-stick: saving  CENTER -> finished");
 | 
				
			||||||
 | 
					                    objects->joystick->defineCenter();
 | 
				
			||||||
 | 
					                    // finished
 | 
				
			||||||
 | 
					                    running = false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case RE_ET_BTN_LONG_PRESSED:
 | 
				
			||||||
 | 
					                //exit to main-menu
 | 
				
			||||||
 | 
					                objects->buzzer->beep(1, 1000, 10);
 | 
				
			||||||
 | 
					                ESP_LOGW(TAG, "aborting calibration sqeuence");
 | 
				
			||||||
 | 
					                running = false;
 | 
				
			||||||
 | 
					            case RE_ET_CHANGED:
 | 
				
			||||||
 | 
					            case RE_ET_BTN_PRESSED:
 | 
				
			||||||
 | 
					            case RE_ET_BTN_RELEASED:
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					menuItem_t item_calibrateJoystick = {
 | 
				
			||||||
 | 
					    item_calibrateJoystick_action, // function action
 | 
				
			||||||
 | 
					    NULL,                          // function get initial value or NULL(show in line 2)
 | 
				
			||||||
 | 
					    NULL,                          // function get default value or NULL(dont set value, show msg)
 | 
				
			||||||
 | 
					    0,                             // valueMin
 | 
				
			||||||
 | 
					    0,                             // valueMax
 | 
				
			||||||
 | 
					    0,                             // valueIncrement
 | 
				
			||||||
 | 
					    "Calibrate Stick ",            // title
 | 
				
			||||||
 | 
					    "   Calibrate    ",            // line1 (above value)
 | 
				
			||||||
 | 
					    "   Joystick     ",            // line2 (above value)
 | 
				
			||||||
 | 
					    " click to start ",            // line4 * (below value)
 | 
				
			||||||
 | 
					    "   sequence     ",            // line5 *
 | 
				
			||||||
 | 
					    "                ",            // line6
 | 
				
			||||||
 | 
					    "=>long to cancel",            // line7
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -71,8 +194,6 @@ void item_debugJoystick_action(display_task_parameters_t * objects, SSD1306_t *
 | 
				
			|||||||
    rotary_encoder_event_t event;
 | 
					    rotary_encoder_event_t event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //-- pre loop instructions --
 | 
					    //-- pre loop instructions --
 | 
				
			||||||
    if (!value) // dont open menu when value was set to 0
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    ESP_LOGW(TAG, "showing joystick debug page");
 | 
					    ESP_LOGW(TAG, "showing joystick debug page");
 | 
				
			||||||
    ssd1306_clear_screen(display, false);
 | 
					    ssd1306_clear_screen(display, false);
 | 
				
			||||||
    // show title
 | 
					    // show title
 | 
				
			||||||
@ -99,36 +220,32 @@ void item_debugJoystick_action(display_task_parameters_t * objects, SSD1306_t *
 | 
				
			|||||||
            switch (event.type)
 | 
					            switch (event.type)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
            case RE_ET_BTN_CLICKED:
 | 
					            case RE_ET_BTN_CLICKED:
 | 
				
			||||||
 | 
					            case RE_ET_BTN_LONG_PRESSED:
 | 
				
			||||||
                running = false;
 | 
					                running = false;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case RE_ET_CHANGED:
 | 
					            case RE_ET_CHANGED:
 | 
				
			||||||
            case RE_ET_BTN_PRESSED:
 | 
					            case RE_ET_BTN_PRESSED:
 | 
				
			||||||
            case RE_ET_BTN_RELEASED:
 | 
					            case RE_ET_BTN_RELEASED:
 | 
				
			||||||
            case RE_ET_BTN_LONG_PRESSED:
 | 
					 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int item_debugJoystick_value(display_task_parameters_t * objects){
 | 
					 | 
				
			||||||
    return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
menuItem_t item_debugJoystick = {
 | 
					menuItem_t item_debugJoystick = {
 | 
				
			||||||
    item_debugJoystick_action, // function action
 | 
					    item_debugJoystick_action, // function action
 | 
				
			||||||
    item_debugJoystick_value,  // function get initial value
 | 
					    NULL,                      // function get initial value or NULL(show in line 2)
 | 
				
			||||||
    NULL,                      // function get default value or NULL
 | 
					    NULL,                      // function get default value or NULL(dont set value, show msg)
 | 
				
			||||||
    0,                         // valueMin
 | 
					    0,                         // valueMin
 | 
				
			||||||
    1,                         // valueMAx
 | 
					    0,                         // valueMax
 | 
				
			||||||
    1,                         // valueIncrement
 | 
					    0,                         // valueIncrement
 | 
				
			||||||
    "Debug joystick  ",        // title
 | 
					    "Debug joystick  ",        // title
 | 
				
			||||||
    "Debug joystick  ",        // line1 (above value)
 | 
					    "Debug joystick  ",        // line1 (above value)
 | 
				
			||||||
    "",                        // line2 (above value)
 | 
					    "",                        // line2 (above value)
 | 
				
			||||||
    "click to enter",          // line4 * (below value)
 | 
					    "",                        // line4 * (below value)
 | 
				
			||||||
    "debug screen    ",        // line5 *
 | 
					    "debug screen    ",        // line5 *
 | 
				
			||||||
    "prints values   ",        // line6
 | 
					    "prints values   ",        // line6
 | 
				
			||||||
    "set 0 to cancel",         // line7
 | 
					    "=>long to cancel",        // line7
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -147,10 +264,10 @@ int maxDuty_currentValue(display_task_parameters_t * objects)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
menuItem_t item_maxDuty = {
 | 
					menuItem_t item_maxDuty = {
 | 
				
			||||||
    maxDuty_action,       // function action
 | 
					    maxDuty_action,       // function action
 | 
				
			||||||
    maxDuty_currentValue, // function get initial value
 | 
					    maxDuty_currentValue, // function get initial value or NULL(show in line 2)
 | 
				
			||||||
    NULL,                 // function get default value or NULL
 | 
					    NULL,                 // function get default value or NULL(dont set value, show msg)
 | 
				
			||||||
    1,                    // valueMin
 | 
					    1,                    // valueMin
 | 
				
			||||||
    99,                   // valueMAx
 | 
					    99,                   // valueMax
 | 
				
			||||||
    1,                    // valueIncrement
 | 
					    1,                    // valueIncrement
 | 
				
			||||||
    "max duty        ",   // title
 | 
					    "max duty        ",   // title
 | 
				
			||||||
    "",                   // line1 (above value)
 | 
					    "",                   // line1 (above value)
 | 
				
			||||||
@ -180,10 +297,10 @@ int item_accelLimit_default(display_task_parameters_t * objects)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
menuItem_t item_accelLimit = {
 | 
					menuItem_t item_accelLimit = {
 | 
				
			||||||
    item_accelLimit_action,  // function action
 | 
					    item_accelLimit_action,  // function action
 | 
				
			||||||
    item_accelLimit_value,   // function get initial value
 | 
					    item_accelLimit_value,   // function get initial value or NULL(show in line 2)
 | 
				
			||||||
    item_accelLimit_default, // function get default value or NULL
 | 
					    item_accelLimit_default, // function get default value or NULL(dont set value, show msg)
 | 
				
			||||||
    0,                       // valueMin
 | 
					    0,                       // valueMin
 | 
				
			||||||
    10000,                   // valueMAx
 | 
					    10000,                   // valueMax
 | 
				
			||||||
    100,                     // valueIncrement
 | 
					    100,                     // valueIncrement
 | 
				
			||||||
    "Accel limit     ",      // title
 | 
					    "Accel limit     ",      // title
 | 
				
			||||||
    " Fade up time   ",      // line1 (above value)
 | 
					    " Fade up time   ",      // line1 (above value)
 | 
				
			||||||
@ -213,10 +330,10 @@ int item_decelLimit_default(display_task_parameters_t * objects)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
menuItem_t item_decelLimit = {
 | 
					menuItem_t item_decelLimit = {
 | 
				
			||||||
    item_decelLimit_action,  // function action
 | 
					    item_decelLimit_action,  // function action
 | 
				
			||||||
    item_decelLimit_value,   // function get initial value
 | 
					    item_decelLimit_value,   // function get initial value or NULL(show in line 2)
 | 
				
			||||||
    item_decelLimit_default, // function get default value or NULL
 | 
					    item_decelLimit_default, // function get default value or NULL(dont set value, show msg)
 | 
				
			||||||
    0,                       // valueMin
 | 
					    0,                       // valueMin
 | 
				
			||||||
    10000,                   // valueMAx
 | 
					    10000,                   // valueMax
 | 
				
			||||||
    100,                     // valueIncrement
 | 
					    100,                     // valueIncrement
 | 
				
			||||||
    "Decel limit     ",      // title
 | 
					    "Decel limit     ",      // title
 | 
				
			||||||
    " Fade down time ",      // line1 (above value)
 | 
					    " Fade down time ",      // line1 (above value)
 | 
				
			||||||
@ -228,6 +345,44 @@ menuItem_t item_decelLimit = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//#####################
 | 
				
			||||||
 | 
					//####### RESET #######
 | 
				
			||||||
 | 
					//#####################
 | 
				
			||||||
 | 
					void item_reset_action(display_task_parameters_t *objects, SSD1306_t *display, int value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    objects->buzzer->beep(1, 2000, 0);
 | 
				
			||||||
 | 
					    // close and erase NVS
 | 
				
			||||||
 | 
					    ESP_LOGW(TAG, "closing and ERASING non-volatile-storage...");
 | 
				
			||||||
 | 
					    nvs_close(*(objects->nvsHandle));
 | 
				
			||||||
 | 
					    ESP_ERROR_CHECK(nvs_flash_erase());
 | 
				
			||||||
 | 
					    // show message restarting
 | 
				
			||||||
 | 
					    ssd1306_clear_screen(display, false);
 | 
				
			||||||
 | 
					    displayTextLineCentered(display, 0, false, true, "");
 | 
				
			||||||
 | 
					    displayTextLineCentered(display, 1, true, true, "RE-");
 | 
				
			||||||
 | 
					    displayTextLineCentered(display, 4, true, true, "START");
 | 
				
			||||||
 | 
					    displayTextLineCentered(display, 7, false, true, "");
 | 
				
			||||||
 | 
					    vTaskDelay(1000 / portTICK_PERIOD_MS); // wait for buzzer to beep
 | 
				
			||||||
 | 
					    // restart
 | 
				
			||||||
 | 
					    ESP_LOGW(TAG, "RESTARTING");
 | 
				
			||||||
 | 
					    esp_restart();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					menuItem_t item_reset = {
 | 
				
			||||||
 | 
					    item_reset_action,  // function action
 | 
				
			||||||
 | 
					    NULL,               // function get initial value or NULL(show in line 2)
 | 
				
			||||||
 | 
					    NULL,               // function get default value or NULL(dont set value, show msg)
 | 
				
			||||||
 | 
					    0,                  // valueMin
 | 
				
			||||||
 | 
					    0,                  // valueMax
 | 
				
			||||||
 | 
					    0,                  // valueIncrement
 | 
				
			||||||
 | 
					    "RESET defaults  ", // title
 | 
				
			||||||
 | 
					    "   reset nvs    ", // line1 (above value)
 | 
				
			||||||
 | 
					    "  and restart   ", // line2 <= showing "default = %d"
 | 
				
			||||||
 | 
					    "reset all stored", // line4 * (below value)
 | 
				
			||||||
 | 
					    "   parameters   ", // line5 *
 | 
				
			||||||
 | 
					    "",                 // line6
 | 
				
			||||||
 | 
					    "=>long to cancel", // line7
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#####################
 | 
					//#####################
 | 
				
			||||||
//###### example ######
 | 
					//###### example ######
 | 
				
			||||||
//#####################
 | 
					//#####################
 | 
				
			||||||
@ -243,10 +398,10 @@ int item_example_valueDefault(display_task_parameters_t * objects){
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
menuItem_t item_example = {
 | 
					menuItem_t item_example = {
 | 
				
			||||||
    item_example_action, // function action
 | 
					    item_example_action, // function action
 | 
				
			||||||
    item_example_value,  // function get initial value
 | 
					    item_example_value,  // function get initial value or NULL(show in line 2)
 | 
				
			||||||
    NULL,                // function get default value or NULL
 | 
					    NULL,                // function get default value or NULL(dont set value, show msg)
 | 
				
			||||||
    -255,                // valueMin
 | 
					    -255,                // valueMin
 | 
				
			||||||
    255,                 // valueMAx
 | 
					    255,                 // valueMax
 | 
				
			||||||
    2,                   // valueIncrement
 | 
					    2,                   // valueIncrement
 | 
				
			||||||
    "example-item-max",  // title
 | 
					    "example-item-max",  // title
 | 
				
			||||||
    "line 1 - above  ",  // line1 (above value)
 | 
					    "line 1 - above  ",  // line1 (above value)
 | 
				
			||||||
@ -259,10 +414,10 @@ menuItem_t item_example = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
menuItem_t item_last = {
 | 
					menuItem_t item_last = {
 | 
				
			||||||
    item_example_action, // function action
 | 
					    item_example_action, // function action
 | 
				
			||||||
    item_example_value,  // function get initial value
 | 
					    item_example_value,  // function get initial value or NULL(show in line 2)
 | 
				
			||||||
    item_example_valueDefault, // function get default value or NULL
 | 
					    item_example_valueDefault, // function get default value or NULL(dont set value, show msg)
 | 
				
			||||||
    -500,                // valueMin
 | 
					    -500,                // valueMin
 | 
				
			||||||
    4500,                // valueMAx
 | 
					    4500,                // valueMax
 | 
				
			||||||
    50,                  // valueIncrement
 | 
					    50,                  // valueIncrement
 | 
				
			||||||
    "set large number",  // title
 | 
					    "set large number",  // title
 | 
				
			||||||
    "line 1 - above  ",  // line1 (above value)
 | 
					    "line 1 - above  ",  // line1 (above value)
 | 
				
			||||||
@ -271,12 +426,14 @@ menuItem_t item_last = {
 | 
				
			|||||||
    "",                  // line5 *
 | 
					    "",                  // line5 *
 | 
				
			||||||
    "line 6 - below  ",  // line6
 | 
					    "line 6 - below  ",  // line6
 | 
				
			||||||
    "line 7 - last   ",  // line7
 | 
					    "line 7 - last   ",  // line7
 | 
				
			||||||
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//store all configured menu items in one array
 | 
					
 | 
				
			||||||
const menuItem_t menuItems[] = {item_centerJoystick, item_debugJoystick, item_accelLimit, item_decelLimit, item_example, item_last};
 | 
					//####################################################
 | 
				
			||||||
const int itemCount = 6;
 | 
					//### store all configured menu items in one array ###
 | 
				
			||||||
 | 
					//####################################################
 | 
				
			||||||
 | 
					const menuItem_t menuItems[] = {item_centerJoystick, item_calibrateJoystick, item_debugJoystick, item_accelLimit, item_decelLimit, item_reset, item_example, item_last};
 | 
				
			||||||
 | 
					const int itemCount = 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -322,12 +479,12 @@ void showItemList(SSD1306_t *display, int selectedItem)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//-----------------------------
 | 
					//-----------------------------
 | 
				
			||||||
//--- showValueSelectStatic ---
 | 
					//--- showValueSelectStatic ---
 | 
				
			||||||
//-----------------------------
 | 
					//-----------------------------
 | 
				
			||||||
// function that renders value-select screen to display (one update)
 | 
					// function that renders lines that do not update of value-select screen to display (initial update)
 | 
				
			||||||
// shows configured text of selected item and currently selected value
 | 
					// shows configured text of currently selected item
 | 
				
			||||||
// TODO show previous value in one line?
 | 
					 | 
				
			||||||
void showValueSelectStatic(display_task_parameters_t * objects, SSD1306_t *display, int selectedItem)
 | 
					void showValueSelectStatic(display_task_parameters_t * objects, SSD1306_t *display, int selectedItem)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    //-- show title line --
 | 
					    //-- show title line --
 | 
				
			||||||
@ -340,30 +497,41 @@ void showValueSelectStatic(display_task_parameters_t * objects, SSD1306_t *displ
 | 
				
			|||||||
    if (menuItems[selectedItem].defaultValue != NULL){
 | 
					    if (menuItems[selectedItem].defaultValue != NULL){
 | 
				
			||||||
        displayTextLineCentered(display, 2, false, false, "default = %d", menuItems[selectedItem].defaultValue(objects));
 | 
					        displayTextLineCentered(display, 2, false, false, "default = %d", menuItems[selectedItem].defaultValue(objects));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else{
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        // displayTextLine(display, 2, false, false, "previous=%d", menuItems[selectedItem].currentValue(objects)); // <= show previous value
 | 
					        // displayTextLine(display, 2, false, false, "previous=%d", menuItems[selectedItem].currentValue(objects)); // <= show previous value
 | 
				
			||||||
        displayTextLine(display, 2, false, false, "%-16s", menuItems[selectedItem].line2);
 | 
					        displayTextLine(display, 2, false, false, "%-16s", menuItems[selectedItem].line2);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //-- show value and other configured lines --
 | 
					    //-- show value and other configured lines --
 | 
				
			||||||
    // print value large, if 2 description lines are empty
 | 
					    // print value large, if two description lines are empty
 | 
				
			||||||
    if (strlen(menuItems[selectedItem].line4) == 0 && strlen(menuItems[selectedItem].line5) == 0)
 | 
					    if (strlen(menuItems[selectedItem].line4) == 0 && strlen(menuItems[selectedItem].line5) == 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // print large value + line5 and line6
 | 
					        // print less lines: line5 and line6 only (due to large value)
 | 
				
			||||||
        displayTextLineCentered(display, 3, true, false, "%d", value); //large centered
 | 
					        //displayTextLineCentered(display, 3, true, false, "%d", value); //large centered (value shown in separate function)
 | 
				
			||||||
        displayTextLine(display, 6, false, false, "%-16s", menuItems[selectedItem].line6);
 | 
					        displayTextLine(display, 6, false, false, "%-16s", menuItems[selectedItem].line6);
 | 
				
			||||||
        displayTextLine(display, 7, false, false, "%-16s", menuItems[selectedItem].line7);
 | 
					        displayTextLine(display, 7, false, false, "%-16s", menuItems[selectedItem].line7);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        displayTextLineCentered(display, 3, false, false, "%d", value); //centered
 | 
					        //displayTextLineCentered(display, 3, false, false, "%d", value); //centered (value shown in separate function)
 | 
				
			||||||
        // print description lines 4 to 7
 | 
					        // print description lines 4 to 7
 | 
				
			||||||
        displayTextLine(display, 4, false, false, "%-16s", menuItems[selectedItem].line4);
 | 
					        displayTextLine(display, 4, false, false, "%-16s", menuItems[selectedItem].line4);
 | 
				
			||||||
        displayTextLine(display, 5, false, false, "%-16s", menuItems[selectedItem].line5);
 | 
					        displayTextLine(display, 5, false, false, "%-16s", menuItems[selectedItem].line5);
 | 
				
			||||||
        displayTextLine(display, 6, false, false, "%-16s", menuItems[selectedItem].line6);
 | 
					        displayTextLine(display, 6, false, false, "%-16s", menuItems[selectedItem].line6);
 | 
				
			||||||
        displayTextLine(display, 7, false, false, "%-16s", menuItems[selectedItem].line7);
 | 
					        displayTextLine(display, 7, false, false, "%-16s", menuItems[selectedItem].line7);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //-- show info msg instead of value --
 | 
				
			||||||
 | 
					    //when pointer to default value func not defined (set value not used, action only)
 | 
				
			||||||
 | 
					    if (menuItems[selectedItem].currentValue == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        //show static text
 | 
				
			||||||
 | 
					        displayTextLineCentered(display, 3, false, true, "%s", "click to confirm");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    // otherwise value gets updated in next iteration of menu-handle function
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//-----------------------------
 | 
					//-----------------------------
 | 
				
			||||||
//----- updateValueSelect -----
 | 
					//----- updateValueSelect -----
 | 
				
			||||||
@ -374,30 +542,29 @@ void updateValueSelect(SSD1306_t *display, int selectedItem)
 | 
				
			|||||||
    // print value large, if 2 description lines are empty
 | 
					    // print value large, if 2 description lines are empty
 | 
				
			||||||
    if (strlen(menuItems[selectedItem].line4) == 0 && strlen(menuItems[selectedItem].line5) == 0)
 | 
					    if (strlen(menuItems[selectedItem].line4) == 0 && strlen(menuItems[selectedItem].line5) == 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // print large value + line5 and line6
 | 
					        // print large and centered value in line 3-5
 | 
				
			||||||
        displayTextLineCentered(display, 3, true, false, "%d", value); // large centered
 | 
					        displayTextLineCentered(display, 3, true, false, "%d", value); // large centered
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        //print value centered in line 3
 | 
				
			||||||
        displayTextLineCentered(display, 3, false, false, "%d", value); // centered
 | 
					        displayTextLineCentered(display, 3, false, false, "%d", value); // centered
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
//========================
 | 
					//========================
 | 
				
			||||||
//====== handleMenu ======
 | 
					//====== handleMenu ======
 | 
				
			||||||
//========================
 | 
					//========================
 | 
				
			||||||
//controls menu with encoder input and displays the text on oled display
 | 
					//controls menu with encoder input and displays the text on oled display
 | 
				
			||||||
//function is repeatedly called by display task when in menu state
 | 
					//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 QUEUE_TIMEOUT 3000 //timeout no encoder event - to not block the display loop and actually handle menu-timeout
 | 
				
			||||||
#define MENU_TIMEOUT 60000 //inactivity timeout (switch to IDLE mode) note: should be smaller than IDLE timeout in control task
 | 
					#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)
 | 
					void handleMenu(display_task_parameters_t * objects, SSD1306_t *display)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    static uint32_t lastActivity = 0;
 | 
					    static uint32_t lastActivity = 0;
 | 
				
			||||||
    static int selectedItem = 0;
 | 
					    static int selectedItem = 0;
 | 
				
			||||||
    static bool staticContentUpdated = false;
 | 
					 | 
				
			||||||
    rotary_encoder_event_t event; // store event data
 | 
					    rotary_encoder_event_t event; // store event data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //--- handle different menu states ---
 | 
					    //--- handle different menu states ---
 | 
				
			||||||
@ -412,6 +579,7 @@ void handleMenu(display_task_parameters_t * objects, SSD1306_t *display)
 | 
				
			|||||||
        // wait for encoder event
 | 
					        // wait for encoder event
 | 
				
			||||||
        if (xQueueReceive(objects->encoderQueue, &event, QUEUE_TIMEOUT / portTICK_PERIOD_MS))
 | 
					        if (xQueueReceive(objects->encoderQueue, &event, QUEUE_TIMEOUT / portTICK_PERIOD_MS))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            // reset menu- and control-timeout on any encoder event
 | 
				
			||||||
            lastActivity = esp_log_timestamp();
 | 
					            lastActivity = esp_log_timestamp();
 | 
				
			||||||
            objects->control->resetTimeout();
 | 
					            objects->control->resetTimeout();
 | 
				
			||||||
            switch (event.type)
 | 
					            switch (event.type)
 | 
				
			||||||
@ -441,15 +609,19 @@ void handleMenu(display_task_parameters_t * objects, SSD1306_t *display)
 | 
				
			|||||||
                ESP_LOGI(TAG, "Button pressed - switching to state SET_VALUE");
 | 
					                ESP_LOGI(TAG, "Button pressed - switching to state SET_VALUE");
 | 
				
			||||||
                // change state (menu to set value)
 | 
					                // change state (menu to set value)
 | 
				
			||||||
                menuState = SET_VALUE;
 | 
					                menuState = SET_VALUE;
 | 
				
			||||||
                staticContentUpdated = false;
 | 
					 | 
				
			||||||
                // get currently configured value
 | 
					 | 
				
			||||||
                value = menuItems[selectedItem].currentValue(objects);
 | 
					 | 
				
			||||||
                // clear display
 | 
					                // clear display
 | 
				
			||||||
                ssd1306_clear_screen(display, false);
 | 
					                ssd1306_clear_screen(display, false);
 | 
				
			||||||
 | 
					                //update static content of set-value screen once at change only
 | 
				
			||||||
 | 
					                showValueSelectStatic(objects, display, selectedItem);
 | 
				
			||||||
 | 
					                // get currently configured value, when value-select feature is actually used in this item
 | 
				
			||||||
 | 
					                if (menuItems[selectedItem].currentValue != NULL)
 | 
				
			||||||
 | 
					                    value = menuItems[selectedItem].currentValue(objects);
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    value = 0;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //exit menu mode
 | 
					 | 
				
			||||||
            case RE_ET_BTN_LONG_PRESSED:
 | 
					            case RE_ET_BTN_LONG_PRESSED:
 | 
				
			||||||
 | 
					                //--- exit menu mode ---
 | 
				
			||||||
                // change to previous mode (e.g. JOYSTICK)
 | 
					                // change to previous mode (e.g. JOYSTICK)
 | 
				
			||||||
                objects->buzzer->beep(4, 15, 5);
 | 
					                objects->buzzer->beep(4, 15, 5);
 | 
				
			||||||
                objects->control->toggleMode(controlMode_t::MENU); //currently already in MENU -> changes to previous mode
 | 
					                objects->control->toggleMode(controlMode_t::MENU); //currently already in MENU -> changes to previous mode
 | 
				
			||||||
@ -467,18 +639,12 @@ void handleMenu(display_task_parameters_t * objects, SSD1306_t *display)
 | 
				
			|||||||
        //---- State SET VALUE ----
 | 
					        //---- State SET VALUE ----
 | 
				
			||||||
        //-------------------------
 | 
					        //-------------------------
 | 
				
			||||||
    case SET_VALUE:
 | 
					    case SET_VALUE:
 | 
				
			||||||
        // wait for encoder event
 | 
					        // update currently selected value
 | 
				
			||||||
        if (!staticContentUpdated)
 | 
					        // note: static lines are updated at mode change
 | 
				
			||||||
        {
 | 
					        if (menuItems[selectedItem].currentValue != NULL) // dont update when set-value not used for this item
 | 
				
			||||||
            showValueSelectStatic(objects, display, selectedItem);
 | 
					 | 
				
			||||||
            staticContentUpdated = true;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            // update line with currently set value only (increses performance significantly)
 | 
					 | 
				
			||||||
            updateValueSelect(display, selectedItem);
 | 
					            updateValueSelect(display, selectedItem);
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // wait for encoder event
 | 
				
			||||||
        if (xQueueReceive(objects->encoderQueue, &event, QUEUE_TIMEOUT / portTICK_PERIOD_MS))
 | 
					        if (xQueueReceive(objects->encoderQueue, &event, QUEUE_TIMEOUT / portTICK_PERIOD_MS))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            objects->control->resetTimeout();
 | 
					            objects->control->resetTimeout();
 | 
				
			||||||
@ -486,6 +652,9 @@ void handleMenu(display_task_parameters_t * objects, SSD1306_t *display)
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
            case RE_ET_CHANGED:
 | 
					            case RE_ET_CHANGED:
 | 
				
			||||||
                //-- change value --
 | 
					                //-- change value --
 | 
				
			||||||
 | 
					                // no need to increment value when item configured to not show value
 | 
				
			||||||
 | 
					                if (menuItems[selectedItem].currentValue != NULL)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
                    objects->buzzer->beep(1, 25, 10);
 | 
					                    objects->buzzer->beep(1, 25, 10);
 | 
				
			||||||
                    // increment value
 | 
					                    // increment value
 | 
				
			||||||
                    if (event.diff < 0)
 | 
					                    if (event.diff < 0)
 | 
				
			||||||
@ -497,6 +666,7 @@ void handleMenu(display_task_parameters_t * objects, SSD1306_t *display)
 | 
				
			|||||||
                        value = menuItems[selectedItem].valueMax;
 | 
					                        value = menuItems[selectedItem].valueMax;
 | 
				
			||||||
                    if (value < menuItems[selectedItem].valueMin)
 | 
					                    if (value < menuItems[selectedItem].valueMin)
 | 
				
			||||||
                        value = menuItems[selectedItem].valueMin;
 | 
					                        value = menuItems[selectedItem].valueMin;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case RE_ET_BTN_CLICKED:
 | 
					            case RE_ET_BTN_CLICKED:
 | 
				
			||||||
                //-- apply value --
 | 
					                //-- apply value --
 | 
				
			||||||
@ -505,12 +675,19 @@ void handleMenu(display_task_parameters_t * objects, SSD1306_t *display)
 | 
				
			|||||||
                menuItems[selectedItem].action(objects, display, value);
 | 
					                menuItems[selectedItem].action(objects, display, value);
 | 
				
			||||||
                menuState = MAIN_MENU;
 | 
					                menuState = MAIN_MENU;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					            case RE_ET_BTN_LONG_PRESSED:
 | 
				
			||||||
 | 
					                //-- exit value select to main menu --
 | 
				
			||||||
 | 
					                objects->buzzer->beep(2, 100, 50);
 | 
				
			||||||
 | 
					                ssd1306_clear_screen(display, false);
 | 
				
			||||||
 | 
					                menuState = MAIN_MENU;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
            case RE_ET_BTN_PRESSED:
 | 
					            case RE_ET_BTN_PRESSED:
 | 
				
			||||||
            case RE_ET_BTN_RELEASED:
 | 
					            case RE_ET_BTN_RELEASED:
 | 
				
			||||||
            case RE_ET_BTN_LONG_PRESSED:
 | 
					 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            // reset menu- and control-timeout on any encoder event
 | 
				
			||||||
            lastActivity = esp_log_timestamp();
 | 
					            lastActivity = esp_log_timestamp();
 | 
				
			||||||
 | 
					            objects->control->resetTimeout();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -519,10 +696,9 @@ void handleMenu(display_task_parameters_t * objects, SSD1306_t *display)
 | 
				
			|||||||
    //--------------------
 | 
					    //--------------------
 | 
				
			||||||
    //--- menu timeout ---
 | 
					    //--- menu timeout ---
 | 
				
			||||||
    //--------------------
 | 
					    //--------------------
 | 
				
			||||||
    //close menu and switch to IDLE mode when no encoder event within MENU_TIMEOUT
 | 
					    //close menu and switch to IDLE mode when no encoder event occured within MENU_TIMEOUT
 | 
				
			||||||
    if (esp_log_timestamp() - lastActivity > 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);
 | 
					        ESP_LOGW(TAG, "TIMEOUT - no activity for more than %ds -> closing menu, switching to IDLE", MENU_TIMEOUT/1000);
 | 
				
			||||||
        // reset menu
 | 
					        // reset menu
 | 
				
			||||||
        selectedItem = 0;
 | 
					        selectedItem = 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -19,8 +19,9 @@ static const char * TAG_CMD = "joystickCommands";
 | 
				
			|||||||
//-------- constructor --------
 | 
					//-------- constructor --------
 | 
				
			||||||
//-----------------------------
 | 
					//-----------------------------
 | 
				
			||||||
//copy provided struct with all configuration and run init function
 | 
					//copy provided struct with all configuration and run init function
 | 
				
			||||||
evaluatedJoystick::evaluatedJoystick(joystick_config_t config_f){
 | 
					evaluatedJoystick::evaluatedJoystick(joystick_config_t config_f, nvs_handle_t * nvsHandle_f){
 | 
				
			||||||
    config = config_f;
 | 
					    config = config_f;
 | 
				
			||||||
 | 
					    nvsHandle = nvsHandle_f;
 | 
				
			||||||
    init();
 | 
					    init();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -30,7 +31,7 @@ evaluatedJoystick::evaluatedJoystick(joystick_config_t config_f){
 | 
				
			|||||||
//---------- init ------------
 | 
					//---------- init ------------
 | 
				
			||||||
//----------------------------
 | 
					//----------------------------
 | 
				
			||||||
void evaluatedJoystick::init(){
 | 
					void evaluatedJoystick::init(){
 | 
				
			||||||
    ESP_LOGI(TAG, "initializing joystick");
 | 
					    ESP_LOGW(TAG, "initializing ADC's and loading calibration...");
 | 
				
			||||||
    //initialize adc
 | 
					    //initialize adc
 | 
				
			||||||
    adc1_config_width(ADC_WIDTH_BIT_12); //=> max resolution 4096
 | 
					    adc1_config_width(ADC_WIDTH_BIT_12); //=> max resolution 4096
 | 
				
			||||||
                                         
 | 
					                                         
 | 
				
			||||||
@ -41,6 +42,12 @@ void evaluatedJoystick::init(){
 | 
				
			|||||||
    adc1_config_channel_atten(config.adc_x, ADC_ATTEN_DB_11); //max voltage
 | 
					    adc1_config_channel_atten(config.adc_x, ADC_ATTEN_DB_11); //max voltage
 | 
				
			||||||
    adc1_config_channel_atten(config.adc_y, ADC_ATTEN_DB_11); //max voltage
 | 
					    adc1_config_channel_atten(config.adc_y, ADC_ATTEN_DB_11); //max voltage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //load stored calibration values (if not found loads defaults from config)
 | 
				
			||||||
 | 
					    loadCalibration(X_MIN);
 | 
				
			||||||
 | 
					    loadCalibration(X_MAX);
 | 
				
			||||||
 | 
					    loadCalibration(Y_MIN);
 | 
				
			||||||
 | 
					    loadCalibration(Y_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //define joystick center from current position
 | 
					    //define joystick center from current position
 | 
				
			||||||
    defineCenter(); //define joystick center from current position
 | 
					    defineCenter(); //define joystick center from current position
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -81,17 +88,17 @@ joystickData_t evaluatedJoystick::getData() {
 | 
				
			|||||||
    ESP_LOGV(TAG, "getting X coodrdinate...");
 | 
					    ESP_LOGV(TAG, "getting X coodrdinate...");
 | 
				
			||||||
	uint32_t adcRead;
 | 
						uint32_t adcRead;
 | 
				
			||||||
	adcRead = readAdc(config.adc_x, config.x_inverted);
 | 
						adcRead = readAdc(config.adc_x, config.x_inverted);
 | 
				
			||||||
    float x = scaleCoordinate(readAdc(config.adc_x, config.x_inverted), config.x_min, config.x_max, x_center,  config.tolerance_zeroX_per, config.tolerance_end_per);
 | 
					    float x = scaleCoordinate(readAdc(config.adc_x, config.x_inverted), x_min, x_max, x_center,  config.tolerance_zeroX_per, config.tolerance_end_per);
 | 
				
			||||||
    data.x = x;
 | 
					    data.x = x;
 | 
				
			||||||
	ESP_LOGD(TAG, "X: adc-raw=%d \tadc-conv=%d \tmin=%d \t max=%d \tcenter=%d \tinverted=%d => x=%.3f",
 | 
						ESP_LOGD(TAG, "X: adc-raw=%d \tadc-conv=%d \tmin=%d \t max=%d \tcenter=%d \tinverted=%d => x=%.3f",
 | 
				
			||||||
        adc1_get_raw(config.adc_x), adcRead,  config.x_min, config.x_max, x_center, config.x_inverted, x);
 | 
					        adc1_get_raw(config.adc_x), adcRead,  x_min, x_max, x_center, config.x_inverted, x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ESP_LOGV(TAG, "getting Y coodrinate...");
 | 
					    ESP_LOGV(TAG, "getting Y coodrinate...");
 | 
				
			||||||
	adcRead = readAdc(config.adc_y, config.y_inverted);
 | 
						adcRead = readAdc(config.adc_y, config.y_inverted);
 | 
				
			||||||
    float y = scaleCoordinate(adcRead, config.y_min, config.y_max, y_center,  config.tolerance_zeroY_per, config.tolerance_end_per);
 | 
					    float y = scaleCoordinate(adcRead, y_min, y_max, y_center,  config.tolerance_zeroY_per, config.tolerance_end_per);
 | 
				
			||||||
    data.y = y;
 | 
					    data.y = y;
 | 
				
			||||||
	ESP_LOGD(TAG, "Y: adc-raw=%d \tadc-conv=%d \tmin=%d \t max=%d \tcenter=%d \tinverted=%d => y=%.3lf",
 | 
						ESP_LOGD(TAG, "Y: adc-raw=%d \tadc-conv=%d \tmin=%d \t max=%d \tcenter=%d \tinverted=%d => y=%.3lf",
 | 
				
			||||||
        adc1_get_raw(config.adc_y), adcRead,  config.y_min, config.y_max, y_center, config.y_inverted, y);
 | 
					        adc1_get_raw(config.adc_y), adcRead,  y_min, y_max, y_center, config.y_inverted, y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //calculate radius
 | 
					    //calculate radius
 | 
				
			||||||
    data.radius = sqrt(pow(data.x,2) + pow(data.y,2));
 | 
					    data.radius = sqrt(pow(data.x,2) + pow(data.y,2));
 | 
				
			||||||
@ -570,3 +577,123 @@ motorCommands_t joystick_generateCommandsShaking(joystickData_t data){
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return commands;
 | 
					    return commands;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// corresponding storage key strings to each joystickCalibratenMode variable
 | 
				
			||||||
 | 
					const char *calibrationStorageKeys[] = {"stick_x-min", "stick_x-max", "stick_y-min", "stick_y-max", "", ""};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//-------------------------------
 | 
				
			||||||
 | 
					//------- loadCalibration -------
 | 
				
			||||||
 | 
					//-------------------------------
 | 
				
			||||||
 | 
					// loads selected calibration value from nvs or default values from config if no data stored
 | 
				
			||||||
 | 
					void evaluatedJoystick::loadCalibration(joystickCalibrationMode_t mode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // determine desired variables
 | 
				
			||||||
 | 
					    int *configValue, *usedValue;
 | 
				
			||||||
 | 
					    switch (mode)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    case X_MIN:
 | 
				
			||||||
 | 
					        configValue = &(config.x_min);
 | 
				
			||||||
 | 
					        usedValue = &x_min;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case X_MAX:
 | 
				
			||||||
 | 
					        configValue = &(config.x_max);
 | 
				
			||||||
 | 
					        usedValue = &x_max;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case Y_MIN:
 | 
				
			||||||
 | 
					        configValue = &(config.y_min);
 | 
				
			||||||
 | 
					        usedValue = &y_min;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case Y_MAX:
 | 
				
			||||||
 | 
					        configValue = &(config.y_max);
 | 
				
			||||||
 | 
					        usedValue = &y_max;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case X_CENTER:
 | 
				
			||||||
 | 
					    case Y_CENTER:
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        // center position is not stored in nvs, it gets defined at startup or during calibration
 | 
				
			||||||
 | 
					        ESP_LOGE(TAG, "loadCalibration: 'center_x' and 'center_y' are not stored in nvs -> not assigning anything");
 | 
				
			||||||
 | 
					        // defineCenter();
 | 
				
			||||||
 | 
					        return; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // read from nvs
 | 
				
			||||||
 | 
					    int16_t valueRead;
 | 
				
			||||||
 | 
					    esp_err_t err = nvs_get_i16(*nvsHandle, calibrationStorageKeys[(int)mode], &valueRead);
 | 
				
			||||||
 | 
					    switch (err)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    case ESP_OK:
 | 
				
			||||||
 | 
					        ESP_LOGW(TAG, "Successfully read value '%s' from nvs. Overriding default value %d with %d", calibrationStorageKeys[(int)mode], *configValue, valueRead);
 | 
				
			||||||
 | 
					        *usedValue = (int)valueRead;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case ESP_ERR_NVS_NOT_FOUND:
 | 
				
			||||||
 | 
					        ESP_LOGW(TAG, "nvs: the value '%s' is not initialized yet, loading default value %d", calibrationStorageKeys[(int)mode], *configValue);
 | 
				
			||||||
 | 
					        *usedValue = *configValue;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        ESP_LOGE(TAG, "Error (%s) reading nvs!", esp_err_to_name(err));
 | 
				
			||||||
 | 
					        *usedValue = *configValue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//-------------------------------
 | 
				
			||||||
 | 
					//------- loadCalibration -------
 | 
				
			||||||
 | 
					//-------------------------------
 | 
				
			||||||
 | 
					// loads selected calibration value from nvs or default values from config if no data stored
 | 
				
			||||||
 | 
					void evaluatedJoystick::writeCalibration(joystickCalibrationMode_t mode, int newValue)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // determine desired variables
 | 
				
			||||||
 | 
					    int *configValue, *usedValue;
 | 
				
			||||||
 | 
					    switch (mode)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    case X_MIN:
 | 
				
			||||||
 | 
					        configValue = &(config.x_min);
 | 
				
			||||||
 | 
					        usedValue = &x_min;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case X_MAX:
 | 
				
			||||||
 | 
					        configValue = &(config.x_max);
 | 
				
			||||||
 | 
					        usedValue = &x_max;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case Y_MIN:
 | 
				
			||||||
 | 
					        configValue = &(config.y_min);
 | 
				
			||||||
 | 
					        usedValue = &y_min;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case Y_MAX:
 | 
				
			||||||
 | 
					        configValue = &(config.y_max);
 | 
				
			||||||
 | 
					        usedValue = &y_max;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case X_CENTER:
 | 
				
			||||||
 | 
					        x_center = newValue;
 | 
				
			||||||
 | 
					        ESP_LOGW(TAG, "writeCalibration: 'center_x' or 'center_y' are not stored in nvs -> loading only");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    case Y_CENTER:
 | 
				
			||||||
 | 
					        y_center = newValue;
 | 
				
			||||||
 | 
					        ESP_LOGW(TAG, "writeCalibration: 'center_x' or 'center_y' are not stored in nvs -> loading only");
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // check if unchanged
 | 
				
			||||||
 | 
					    if (*usedValue == newValue)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ESP_LOGW(TAG, "writeCalibration: value '%s' unchanged at %d, not writing to nvs", calibrationStorageKeys[(int)mode], newValue);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // update nvs value
 | 
				
			||||||
 | 
					    ESP_LOGW(TAG, "writeCalibration: updating nvs value '%s' from %d to %d", calibrationStorageKeys[(int)mode], *usedValue, newValue);
 | 
				
			||||||
 | 
					    esp_err_t err = nvs_set_i16(*nvsHandle, calibrationStorageKeys[(int)mode], newValue);
 | 
				
			||||||
 | 
					    if (err != ESP_OK)
 | 
				
			||||||
 | 
					        ESP_LOGE(TAG, "nvs: failed writing");
 | 
				
			||||||
 | 
					    err = nvs_commit(*nvsHandle);
 | 
				
			||||||
 | 
					    if (err != ESP_OK)
 | 
				
			||||||
 | 
					        ESP_LOGE(TAG, "nvs: failed committing updates");
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        ESP_LOGI(TAG, "nvs: successfully committed updates");
 | 
				
			||||||
 | 
					    // update variable
 | 
				
			||||||
 | 
					    *usedValue = newValue;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -8,6 +8,8 @@ extern "C"
 | 
				
			|||||||
#include "driver/adc.h"
 | 
					#include "driver/adc.h"
 | 
				
			||||||
#include "esp_log.h"
 | 
					#include "esp_log.h"
 | 
				
			||||||
#include "esp_err.h"
 | 
					#include "esp_err.h"
 | 
				
			||||||
 | 
					#include "nvs_flash.h"
 | 
				
			||||||
 | 
					#include "nvs.h"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <cmath>
 | 
					#include <cmath>
 | 
				
			||||||
@ -55,6 +57,7 @@ typedef struct joystick_config_t {
 | 
				
			|||||||
enum class joystickPos_t {CENTER, Y_AXIS, X_AXIS, TOP_RIGHT, TOP_LEFT, BOTTOM_LEFT, BOTTOM_RIGHT};
 | 
					enum class joystickPos_t {CENTER, Y_AXIS, X_AXIS, TOP_RIGHT, TOP_LEFT, BOTTOM_LEFT, BOTTOM_RIGHT};
 | 
				
			||||||
extern const char* joystickPosStr[7];
 | 
					extern const char* joystickPosStr[7];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum joystickCalibrationMode_t { X_MIN = 0, X_MAX, Y_MIN, Y_MAX, X_CENTER, Y_CENTER } joystickCalibrationMode_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//struct with current data of the joystick
 | 
					//struct with current data of the joystick
 | 
				
			||||||
typedef struct joystickData_t {
 | 
					typedef struct joystickData_t {
 | 
				
			||||||
@ -70,24 +73,38 @@ typedef struct joystickData_t {
 | 
				
			|||||||
//------------------------------------
 | 
					//------------------------------------
 | 
				
			||||||
//----- evaluatedJoystick class  -----
 | 
					//----- evaluatedJoystick class  -----
 | 
				
			||||||
//------------------------------------
 | 
					//------------------------------------
 | 
				
			||||||
class evaluatedJoystick {
 | 
					class evaluatedJoystick
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    //--- constructor ---
 | 
					    //--- constructor ---
 | 
				
			||||||
        evaluatedJoystick(joystick_config_t config_f);
 | 
					    evaluatedJoystick(joystick_config_t config_f, nvs_handle_t * nvsHandle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //--- functions ---
 | 
					    //--- functions ---
 | 
				
			||||||
    joystickData_t getData(); // read joystick, calculate values and return the data in a struct
 | 
					    joystickData_t getData(); // read joystick, calculate values and return the data in a struct
 | 
				
			||||||
 | 
					    // get raw adc value (inversion applied)
 | 
				
			||||||
 | 
					    int getRawX() { return readAdc(config.adc_x, config.x_inverted); }
 | 
				
			||||||
 | 
					    int getRawY() { return readAdc(config.adc_y, config.y_inverted); }
 | 
				
			||||||
    void defineCenter(); // define joystick center from current position
 | 
					    void defineCenter(); // define joystick center from current position
 | 
				
			||||||
 | 
					    void writeCalibration(joystickCalibrationMode_t mode, int newValue); // load certain new calibration value and store it in nvs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    //--- functions ---
 | 
					    //--- functions ---
 | 
				
			||||||
    // initialize adc inputs, define center
 | 
					    // initialize adc inputs, define center
 | 
				
			||||||
    void init();
 | 
					    void init();
 | 
				
			||||||
 | 
					    // loads selected calibration value from nvs or default values from config if no data stored
 | 
				
			||||||
 | 
					    void loadCalibration(joystickCalibrationMode_t mode);
 | 
				
			||||||
        // read adc while making multiple samples with option to invert the result
 | 
					        // read adc while making multiple samples with option to invert the result
 | 
				
			||||||
        int readAdc(adc1_channel_t adc_channel, bool inverted = false);
 | 
					        int readAdc(adc1_channel_t adc_channel, bool inverted = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //--- variables ---
 | 
					        //--- variables ---
 | 
				
			||||||
 | 
					        // handle for using the nvs flash (persistent config variables)
 | 
				
			||||||
 | 
					        nvs_handle_t *nvsHandle;
 | 
				
			||||||
        joystick_config_t config;
 | 
					        joystick_config_t config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int x_min;
 | 
				
			||||||
 | 
					        int x_max;
 | 
				
			||||||
 | 
					        int y_min;
 | 
				
			||||||
 | 
					        int y_max;
 | 
				
			||||||
        int x_center;
 | 
					        int x_center;
 | 
				
			||||||
        int y_center;
 | 
					        int y_center;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user