From 2fcf17fedafbca252462bd7badba3969312e703a Mon Sep 17 00:00:00 2001 From: jonny_jr9 Date: Sun, 18 Feb 2024 10:00:34 +0100 Subject: [PATCH] Major Rework all files - Pass pointers to tasks, Remove gloabl variables - All files: Modify almost all files to adjust functions and classes to work with pointers to objects passed at task creation instead of global variables from config.hpp - Remove/clear config.hpp to get rid of all global variables - main.cpp - Create pointer to all shared (used in multiple tasks) objects in main - remove evaluatedSwitch button object, since joystick library is used to get switch events - changes HTTP-mode - always init http-server (do not enable/disable at mode change) - pass url-handle function to init-htpp function - add lambda function to pass method of instance for thatMajor Rework all files - Remove global variables, pass pointers to tasks - All files: Modify almost all files to adjust functions and classes to work with pointers to objects passed at task creation instead of global variables from config.hpp - Remove/clear config.hpp to get rid of all global variables - main.cpp - Create pointer to all shared (used in multiple tasks) objects in main - remove evaluatedSwitch button object, since joystick library is used to get switch events - changes HTTP-mode - always init http-server (do not enable/disable at mode change) - pass url-handle function to init-htpp function - add lambda function to pass method of instance for that NOTES: - tested on breakoutboard only - known issue that slow encoder events are not recognized (especially in menu) - slowing down motorctl helps --- board_single/main/auto.cpp | 25 +-- board_single/main/auto.hpp | 10 +- board_single/main/button.cpp | 43 ++++-- board_single/main/button.hpp | 39 +++-- board_single/main/config.cpp | 254 ++++++++++++++----------------- board_single/main/config.hpp | 83 +++++----- board_single/main/control.cpp | 81 ++++------ board_single/main/control.hpp | 19 ++- board_single/main/display.cpp | 29 ++-- board_single/main/display.hpp | 17 ++- board_single/main/encoder.cpp | 16 +- board_single/main/encoder.hpp | 10 +- board_single/main/main.cpp | 277 +++++++++++++++++++++------------- board_single/main/menu.cpp | 60 ++++---- board_single/main/menu.hpp | 10 +- board_single/sdkconfig | 15 +- common/http.cpp | 28 ++-- common/http.hpp | 26 ++-- common/motorctl.cpp | 27 +++- common/motorctl.hpp | 18 +++ 20 files changed, 618 insertions(+), 469 deletions(-) diff --git a/board_single/main/auto.cpp b/board_single/main/auto.cpp index 4cf4a71..8882c74 100644 --- a/board_single/main/auto.cpp +++ b/board_single/main/auto.cpp @@ -8,9 +8,12 @@ static const char * TAG = "automatedArmchair"; //============================= //======== constructor ======== //============================= -automatedArmchair::automatedArmchair(void) { - //create command queue - commandQueue = xQueueCreate( 32, sizeof( commandSimple_t ) ); //TODO add max size to config? +automatedArmchair_c::automatedArmchair_c(controlledMotor *motorLeft_f, controlledMotor *motorRight_f) +{ + motorLeft = motorLeft_f; + motorRight = motorRight_f; + // create command queue + commandQueue = xQueueCreate(32, sizeof(commandSimple_t)); // TODO add max size to config? } @@ -18,7 +21,7 @@ automatedArmchair::automatedArmchair(void) { //============================== //====== generateCommands ====== //============================== -motorCommands_t automatedArmchair::generateCommands(auto_instruction_t * instruction) { +motorCommands_t automatedArmchair_c::generateCommands(auto_instruction_t * instruction) { //reset instruction *instruction = auto_instruction_t::NONE; //check if previous command is finished @@ -29,10 +32,10 @@ motorCommands_t automatedArmchair::generateCommands(auto_instruction_t * instruc //copy instruction to be provided to control task *instruction = cmdCurrent.instruction; //set acceleration / fading parameters according to command - motorLeft.setFade(fadeType_t::DECEL, cmdCurrent.fadeDecel); - motorRight.setFade(fadeType_t::DECEL, cmdCurrent.fadeDecel); - motorLeft.setFade(fadeType_t::ACCEL, cmdCurrent.fadeAccel); - motorRight.setFade(fadeType_t::ACCEL, cmdCurrent.fadeAccel); + motorLeft->setFade(fadeType_t::DECEL, cmdCurrent.fadeDecel); + motorRight->setFade(fadeType_t::DECEL, cmdCurrent.fadeDecel); + motorLeft->setFade(fadeType_t::ACCEL, cmdCurrent.fadeAccel); + motorRight->setFade(fadeType_t::ACCEL, cmdCurrent.fadeAccel); //calculate timestamp the command is finished timestampCmdFinished = esp_log_timestamp() + cmdCurrent.msDuration; //copy the new commands @@ -55,7 +58,7 @@ motorCommands_t automatedArmchair::generateCommands(auto_instruction_t * instruc //======== addCommand ======== //============================ //function that adds a basic command to the queue -void automatedArmchair::addCommand(commandSimple_t command) { +void automatedArmchair_c::addCommand(commandSimple_t command) { //add command to queue if ( xQueueSend( commandQueue, ( void * )&command, ( TickType_t ) 0 ) ){ ESP_LOGI(TAG, "Successfully inserted command to queue"); @@ -64,7 +67,7 @@ void automatedArmchair::addCommand(commandSimple_t command) { } } -void automatedArmchair::addCommands(commandSimple_t commands[], size_t count) { +void automatedArmchair_c::addCommands(commandSimple_t commands[], size_t count) { for (int i = 0; i < count; i++) { ESP_LOGI(TAG, "Reading command no. %d from provided array", i); addCommand(commands[i]); @@ -77,7 +80,7 @@ void automatedArmchair::addCommands(commandSimple_t commands[], size_t count) { //=============================== //function that deletes all pending/queued commands //e.g. when switching modes -motorCommands_t automatedArmchair::clearCommands() { +motorCommands_t automatedArmchair_c::clearCommands() { //clear command queue xQueueReset( commandQueue ); ESP_LOGW(TAG, "command queue was successfully emptied"); diff --git a/board_single/main/auto.hpp b/board_single/main/auto.hpp index 3f37646..4cf66d8 100644 --- a/board_single/main/auto.hpp +++ b/board_single/main/auto.hpp @@ -33,13 +33,13 @@ typedef struct commandSimple_t{ //------------------------------------ -//----- automatedArmchair class ----- +//----- automatedArmchair_c class ----- //------------------------------------ -class automatedArmchair { +class automatedArmchair_c { public: //--- methods --- //constructor - automatedArmchair(void); + automatedArmchair_c(controlledMotor * motorLeft, controlledMotor * motorRight); //function to generate motor commands //can be also seen as handle function //TODO: go with other approach: separate task for handling auto mode @@ -62,6 +62,8 @@ class automatedArmchair { private: //--- methods --- //--- objects --- + controlledMotor * motorLeft; + controlledMotor * motorRight; //TODO: add buzzer here //--- variables --- //queue for storing pending commands @@ -124,7 +126,7 @@ if (trigger){ .instruction = auto_instruction_t::SWITCH_JOYSTICK_MODE }; - //send commands to automatedArmchair command queue + //send commands to automatedArmchair_c command queue armchair.addCommands(cmds, 3); //change mode to AUTO diff --git a/board_single/main/button.cpp b/board_single/main/button.cpp index 06f4c9e..40962ac 100644 --- a/board_single/main/button.cpp +++ b/board_single/main/button.cpp @@ -10,29 +10,44 @@ extern "C" #include "button.hpp" #include "encoder.hpp" +// tag for logging +static const char *TAG = "button"; - -//tag for logging -static const char * TAG = "button"; - - +//====================================== +//============ button task ============= +//====================================== +// task that handles the button interface/commands +void task_button(void *task_button_parameters) +{ + task_button_parameters_t *objects = (task_button_parameters_t *)task_button_parameters; + ESP_LOGI(TAG, "Initializing command-button and starting handle loop"); + // create button instance + buttonCommands commandButton(objects->control, objects->joystick, objects->encoderQueue, objects->motorLeft, objects->motorRight, objects->buzzer); + // start handle loop + commandButton.startHandleLoop(); +} //----------------------------- //-------- constructor -------- //----------------------------- -buttonCommands::buttonCommands(gpio_evaluatedSwitch * button_f, evaluatedJoystick * joystick_f, controlledArmchair * control_f, buzzer_t * buzzer_f, controlledMotor * motorLeft_f, controlledMotor * motorRight_f){ - //copy object pointers - button = button_f; - joystick = joystick_f; +buttonCommands::buttonCommands( + controlledArmchair *control_f, + evaluatedJoystick *joystick_f, + QueueHandle_t encoderQueue_f, + controlledMotor *motorLeft_f, + controlledMotor *motorRight_f, + buzzer_t *buzzer_f) +{ + // copy object pointers control = control_f; - buzzer = buzzer_f; + joystick = joystick_f; + encoderQueue = encoderQueue_f; motorLeft = motorLeft_f; motorRight = motorRight_f; - //TODO declare / configure evaluatedSwitch here instead of config (unnecessary that button object is globally available - only used here)? + buzzer = buzzer_f; + // TODO declare / configure evaluatedSwitch here instead of config (unnecessary that button object is globally available - only used here)? } - - //---------------------------- //--------- action ----------- //---------------------------- @@ -40,7 +55,7 @@ buttonCommands::buttonCommands(gpio_evaluatedSwitch * button_f, evaluatedJoystic void buttonCommands::action (uint8_t count, bool lastPressLong){ //--- variables --- bool decelEnabled; //for different beeping when toggling - commandSimple_t cmds[8]; //array for commands for automatedArmchair + commandSimple_t cmds[8]; //array for commands for automatedArmchair_c //--- get joystick position --- //in case joystick is used for additional cases: diff --git a/board_single/main/button.hpp b/board_single/main/button.hpp index 09de729..30b52b0 100644 --- a/board_single/main/button.hpp +++ b/board_single/main/button.hpp @@ -17,14 +17,13 @@ class buttonCommands { public: //--- constructor --- - buttonCommands ( - gpio_evaluatedSwitch * button_f, - evaluatedJoystick * joystick_f, - controlledArmchair * control_f, - buzzer_t * buzzer_f, - controlledMotor * motorLeft_f, - controlledMotor * motorRight_f - ); + buttonCommands( + controlledArmchair *control_f, + evaluatedJoystick *joystick_f, + QueueHandle_t encoderQueue_f, + controlledMotor * motorLeft_f, + controlledMotor *motorRight_f, + buzzer_t *buzzer_f); //--- functions --- //the following function has to be started once in a separate task. @@ -36,12 +35,12 @@ class buttonCommands { void action(uint8_t count, bool lastPressLong); //--- objects --- - gpio_evaluatedSwitch* button; - evaluatedJoystick* joystick; controlledArmchair * control; - buzzer_t* buzzer; + evaluatedJoystick* joystick; controlledMotor * motorLeft; controlledMotor * motorRight; + buzzer_t* buzzer; + QueueHandle_t encoderQueue; //--- variables --- uint8_t count = 0; @@ -51,3 +50,21 @@ class buttonCommands { }; + + +//====================================== +//============ button task ============= +//====================================== +// struct with variables passed to task from main +typedef struct task_button_parameters_t +{ + controlledArmchair *control; + evaluatedJoystick *joystick; + QueueHandle_t encoderQueue; + controlledMotor *motorLeft; + controlledMotor *motorRight; + buzzer_t *buzzer; +} task_button_parameters_t; + +//task that handles the button interface/commands +void task_button( void * task_button_parameters ); \ No newline at end of file diff --git a/board_single/main/config.cpp b/board_single/main/config.cpp index 60a0d3d..9a64e60 100644 --- a/board_single/main/config.cpp +++ b/board_single/main/config.cpp @@ -1,8 +1,54 @@ -#include "config.hpp" +// NOTE: this file is included in main.cpp only. +// outsourced all configuration related functions and structures to this file: -//=================================== -//======= motor configuration ======= -//=================================== +#include "motordrivers.hpp" +#include "motorctl.hpp" +#include "joystick.hpp" +#include "http.hpp" +#include "speedsensor.hpp" + +#include "buzzer.hpp" +#include "control.hpp" +#include "fan.hpp" +#include "auto.hpp" +#include "chairAdjust.hpp" + +//================================== +//======== define loglevels ======== +//================================== +void setLoglevels(void) +{ + // set loglevel for all tags: + esp_log_level_set("*", ESP_LOG_WARN); + + //--- set loglevel for individual tags --- + esp_log_level_set("main", ESP_LOG_INFO); + esp_log_level_set("buzzer", ESP_LOG_ERROR); + // esp_log_level_set("motordriver", ESP_LOG_DEBUG); + esp_log_level_set("motor-control", ESP_LOG_WARN); + // esp_log_level_set("evaluatedJoystick", ESP_LOG_DEBUG); + // esp_log_level_set("joystickCommands", ESP_LOG_DEBUG); + esp_log_level_set("button", ESP_LOG_INFO); + esp_log_level_set("control", ESP_LOG_INFO); + // esp_log_level_set("fan-control", ESP_LOG_INFO); + esp_log_level_set("wifi", ESP_LOG_INFO); + esp_log_level_set("http", ESP_LOG_INFO); + // esp_log_level_set("automatedArmchair", ESP_LOG_DEBUG); + esp_log_level_set("display", ESP_LOG_INFO); + // esp_log_level_set("current-sensors", ESP_LOG_INFO); + // esp_log_level_set("speedSensor", ESP_LOG_INFO); + esp_log_level_set("chair-adjustment", ESP_LOG_INFO); + esp_log_level_set("menu", ESP_LOG_INFO); + esp_log_level_set("encoder", ESP_LOG_INFO); +} + +//================================== +//======== configuration =========== +//================================== + +//----------------------------------- +//------- motor configuration ------- +//----------------------------------- /* ==> currently using other driver //--- configure left motor (hardware) --- single100a_config_t configDriverLeft = { @@ -11,8 +57,8 @@ single100a_config_t configDriverLeft = { .gpio_b = GPIO_NUM_4, .ledc_timer = LEDC_TIMER_0, .ledc_channel = LEDC_CHANNEL_0, - .aEnabledPinState = false, //-> pins inverted (mosfets) - .bEnabledPinState = false, + .aEnabledPinState = false, //-> pins inverted (mosfets) + .bEnabledPinState = false, .resolution = LEDC_TIMER_11_BIT, .pwmFreq = 10000 }; @@ -24,180 +70,114 @@ single100a_config_t configDriverRight = { .gpio_b = GPIO_NUM_14, .ledc_timer = LEDC_TIMER_1, .ledc_channel = LEDC_CHANNEL_1, - .aEnabledPinState = false, //-> pin inverted (mosfet) - .bEnabledPinState = true, //-> not inverted (direct) + .aEnabledPinState = false, //-> pin inverted (mosfet) + .bEnabledPinState = true, //-> not inverted (direct) .resolution = LEDC_TIMER_11_BIT, .pwmFreq = 10000 - }; - */ + }; + */ //--- configure sabertooth driver --- (controls both motors in one instance) sabertooth2x60_config_t sabertoothConfig = { - .gpio_TX = GPIO_NUM_25, - .uart_num = UART_NUM_2 -}; + .gpio_TX = GPIO_NUM_25, + .uart_num = UART_NUM_2}; - -//TODO add motor name string -> then use as log tag? +// TODO add motor name string -> then use as log tag? //--- configure left motor (contol) --- motorctl_config_t configMotorControlLeft = { - .msFadeAccel = 1500, //acceleration of the motor (ms it takes from 0% to 100%) - .msFadeDecel = 1000, //deceleration of the motor (ms it takes from 100% to 0%) - .currentLimitEnabled = false, - .currentSensor_adc = ADC1_CHANNEL_4, //GPIO32 - .currentSensor_ratedCurrent = 50, + .msFadeAccel = 1500, // acceleration of the motor (ms it takes from 0% to 100%) + .msFadeDecel = 1000, // deceleration of the motor (ms it takes from 100% to 0%) + .currentLimitEnabled = false, + .currentSensor_adc = ADC1_CHANNEL_4, // GPIO32 + .currentSensor_ratedCurrent = 50, .currentMax = 30, - .deadTimeMs = 0 //minimum time motor is off between direction change + .deadTimeMs = 0 // minimum time motor is off between direction change }; //--- configure right motor (contol) --- motorctl_config_t configMotorControlRight = { - .msFadeAccel = 1500, //acceleration of the motor (ms it takes from 0% to 100%) - .msFadeDecel = 1000, //deceleration of the motor (ms it takes from 100% to 0%) - .currentLimitEnabled = false, - .currentSensor_adc = ADC1_CHANNEL_5, //GPIO33 - .currentSensor_ratedCurrent = 50, + .msFadeAccel = 1500, // acceleration of the motor (ms it takes from 0% to 100%) + .msFadeDecel = 1000, // deceleration of the motor (ms it takes from 100% to 0%) + .currentLimitEnabled = false, + .currentSensor_adc = ADC1_CHANNEL_5, // GPIO33 + .currentSensor_ratedCurrent = 50, .currentMax = 30, - .deadTimeMs = 0 //minimum time motor is off between direction change + .deadTimeMs = 0 // minimum time motor is off between direction change }; - - -//============================== -//======= control config ======= -//============================== +//------------------------------ +//------- control config ------- +//------------------------------ control_config_t configControl = { - .defaultMode = controlMode_t::JOYSTICK, //default mode after startup and toggling IDLE - //--- timeout --- - .timeoutMs = 3*60*1000, //time of inactivity after which the mode gets switched to IDLE - .timeoutTolerancePer = 5, //percentage the duty can vary between timeout checks considered still inactive + .defaultMode = controlMode_t::JOYSTICK, // default mode after startup and toggling IDLE + //--- timeout --- + .timeoutMs = 3 * 60 * 1000, // time of inactivity after which the mode gets switched to IDLE + .timeoutTolerancePer = 5, // percentage the duty can vary between timeout checks considered still inactive //--- http mode --- }; - - -//=============================== -//===== httpJoystick config ===== -//=============================== +//------------------------------- +//----- httpJoystick config ----- +//------------------------------- httpJoystick_config_t configHttpJoystickMain{ - .toleranceZeroX_Per = 1, //percentage around joystick axis the coordinate snaps to 0 + .toleranceZeroX_Per = 1, // percentage around joystick axis the coordinate snaps to 0 .toleranceZeroY_Per = 6, - .toleranceEndPer = 2, //percentage before joystick end the coordinate snaps to 1/-1 - .timeoutMs = 2500 //time no new data was received before the motors get turned off + .toleranceEndPer = 2, // percentage before joystick end the coordinate snaps to 1/-1 + .timeoutMs = 2500 // time no new data was received before the motors get turned off }; - - -//====================================== -//======= joystick configuration ======= -//====================================== +//-------------------------------------- +//------- joystick configuration ------- +//-------------------------------------- joystick_config_t configJoystick = { - .adc_x = ADC1_CHANNEL_0, //GPIO36 - .adc_y = ADC1_CHANNEL_3, //GPIO39 - //percentage of joystick range the coordinate of the axis snaps to 0 (0-100) - .tolerance_zeroX_per = 7, //6 - .tolerance_zeroY_per = 10, //7 - //percentage of joystick range the coordinate snaps to -1 or 1 before configured "_max" or "_min" threshold (mechanical end) is reached (0-100) - .tolerance_end_per = 4, - //threshold the radius jumps to 1 before the stick is at max radius (range 0-1) + .adc_x = ADC1_CHANNEL_0, // GPIO36 + .adc_y = ADC1_CHANNEL_3, // GPIO39 + // percentage of joystick range the coordinate of the axis snaps to 0 (0-100) + .tolerance_zeroX_per = 7, // 6 + .tolerance_zeroY_per = 10, // 7 + // percentage of joystick range the coordinate snaps to -1 or 1 before configured "_max" or "_min" threshold (mechanical end) is reached (0-100) + .tolerance_end_per = 4, + // threshold the radius jumps to 1 before the stick is at max radius (range 0-1) .tolerance_radius = 0.09, - //min and max adc values of each axis, !!!AFTER INVERSION!!! is applied: + // min and max adc values of each axis, !!!AFTER INVERSION!!! is applied: .x_min = 1710, //=> x=-1 .x_max = 2980, //=> x=1 .y_min = 1700, //=> y=-1 .y_max = 2940, //=> y=1 - //invert adc measurement + // invert adc measurement .x_inverted = true, - .y_inverted = true -}; + .y_inverted = true}; - - -//============================ -//=== configure fan contol === -//============================ +//---------------------------- +//--- configure fan contol --- +//---------------------------- fan_config_t configCooling = { .gpio_fan = GPIO_NUM_13, .dutyThreshold = 40, - .minOnMs = 1500, - .minOffMs = 3000, - .turnOffDelayMs = 5000, + .minOnMs = 1500, + .minOffMs = 3000, + .turnOffDelayMs = 5000, }; - - -//============================================ -//======== speed sensor configuration ======== -//============================================ +//-------------------------------------------- +//-------- speed sensor configuration -------- +//-------------------------------------------- speedSensor_config_t speedLeft_config{ - .gpioPin = GPIO_NUM_5, - .degreePerGroup = 360/5, - .tireCircumferenceMeter = 210.0*3.141/1000.0, - .directionInverted = false, - .logName = "speedLeft", + .gpioPin = GPIO_NUM_5, + .degreePerGroup = 360 / 5, + .tireCircumferenceMeter = 210.0 * 3.141 / 1000.0, + .directionInverted = false, + .logName = "speedLeft", }; speedSensor_config_t speedRight_config{ - .gpioPin = GPIO_NUM_14, - .degreePerGroup = 360/12, - .tireCircumferenceMeter = 210.0*3.141/1000.0, - .directionInverted = true, - .logName = "speedRight", + .gpioPin = GPIO_NUM_14, + .degreePerGroup = 360 / 12, + .tireCircumferenceMeter = 210.0 * 3.141 / 1000.0, + .directionInverted = true, + .logName = "speedRight", }; - - - -//================================= -//===== create global objects ===== -//================================= -//TODO outsource global variables to e.g. global.cpp and only config options here? -//create sabertooth motor driver instance -sabertooth2x60a sabertoothDriver(sabertoothConfig); - - -//--- controlledMotor --- -//functions for updating the duty via certain/current driver that can then be passed to controlledMotor -//-> makes it possible to easily use different motor drivers -//note: ignoring warning "capture of variable 'sabertoothDriver' with non-automatic storage duration", since sabertoothDriver object does not get destroyed anywhere - no lifetime issue -motorSetCommandFunc_t setLeftFunc = [&sabertoothDriver](motorCommand_t cmd) { - sabertoothDriver.setLeft(cmd); -}; -motorSetCommandFunc_t setRightFunc = [&sabertoothDriver](motorCommand_t cmd) { - sabertoothDriver.setRight(cmd); -}; -//create controlled motor instances (motorctl.hpp) -controlledMotor motorLeft(setLeftFunc, configMotorControlLeft); -controlledMotor motorRight(setRightFunc, configMotorControlRight); - -//create speedsensor instances -speedSensor speedLeft (speedLeft_config); -speedSensor speedRight (speedRight_config); - -//create global joystic instance (joystick.hpp) -evaluatedJoystick joystick(configJoystick); - -//create global evaluated switch instance for button next to joystick -gpio_evaluatedSwitch buttonJoystick(GPIO_NUM_21, true, false); //pullup true, not inverted (switch to GND use pullup of controller) - -//create buzzer object on pin 12 with gap between queued events of 100ms -buzzer_t buzzer(GPIO_NUM_12, 100); - -//create global httpJoystick object (http.hpp) -httpJoystick httpJoystickMain(configHttpJoystickMain); - -//create global control object (control.hpp) -controlledArmchair control(configControl, &buzzer, &motorLeft, &motorRight, &joystick, &httpJoystickMain); - -//create global automatedArmchair object (for auto-mode) (auto.hpp) -automatedArmchair armchair; - -//create global objects for controlling the chair position -// gpio_up, gpio_down, name -cControlledRest legRest(GPIO_NUM_4, GPIO_NUM_16, "legRest"); -cControlledRest backRest(GPIO_NUM_2, GPIO_NUM_15, "backRest"); - - diff --git a/board_single/main/config.hpp b/board_single/main/config.hpp index 6549f89..697d4f4 100644 --- a/board_single/main/config.hpp +++ b/board_single/main/config.hpp @@ -13,44 +13,45 @@ #include "speedsensor.hpp" #include "chairAdjust.hpp" - -//in IDLE mode: set loglevel for evaluatedJoystick to DEBUG -//and repeatedly read joystick e.g. for manually calibrating / testing joystick -//#define JOYSTICK_LOG_IN_IDLE - - -//TODO outsource global variables to e.g. global.cpp and only config options here? - -//create global controlledMotor instances for both motors -extern controlledMotor motorLeft; -extern controlledMotor motorRight; - -//create global joystic instance -extern evaluatedJoystick joystick; - -//create global evaluated switch instance for button next to joystick -extern gpio_evaluatedSwitch buttonJoystick; - -//create global buzzer object -extern buzzer_t buzzer; - -//create global control object -extern controlledArmchair control; - -//create global automatedArmchair object (for auto-mode) -extern automatedArmchair armchair; - -//create global httpJoystick object -//extern httpJoystick httpJoystickMain; - -//configuration for fans / cooling -extern fan_config_t configCooling; - -//create global objects for measuring speed -extern speedSensor speedLeft; -extern speedSensor speedRight; - -//create global objects for controlling the chair position -extern cControlledRest legRest; -extern cControlledRest backRest; - +// +////in IDLE mode: set loglevel for evaluatedJoystick to DEBUG +////and repeatedly read joystick e.g. for manually calibrating / testing joystick +////#define JOYSTICK_LOG_IN_IDLE +// +// +////TODO outsource global variables to e.g. global.cpp and only config options here? +// +////create global controlledMotor instances for both motors +//extern controlledMotor motorLeft; +//extern controlledMotor motorRight; +// +////create global joystic instance +//extern evaluatedJoystick joystick; +// +////create global evaluated switch instance for button next to joystick +//extern gpio_evaluatedSwitch buttonJoystick; +// +////create global buzzer object +//extern buzzer_t buzzer; +// +////create global control object +//extern controlledArmchair control; +// +////create global automatedArmchair object (for auto-mode) +//extern automatedArmchair_c armchair; +// +////create global httpJoystick object +////extern httpJoystick httpJoystickMain; +// +////configuration for fans / cooling +//extern fan_config_t configCooling; +// +////create global objects for measuring speed +//extern speedSensor speedLeft; +//extern speedSensor speedRight; +// +////create global objects for controlling the chair position +//extern cControlledRest legRest; +//extern cControlledRest backRest; +// +// \ No newline at end of file diff --git a/board_single/main/control.cpp b/board_single/main/control.cpp index 44646bd..e32c448 100644 --- a/board_single/main/control.cpp +++ b/board_single/main/control.cpp @@ -26,14 +26,17 @@ const char* controlModeStr[9] = {"IDLE", "JOYSTICK", "MASSAGE", "HTTP", "MQTT", //----------------------------- //-------- constructor -------- //----------------------------- -controlledArmchair::controlledArmchair ( - control_config_t config_f, - buzzer_t * buzzer_f, - controlledMotor* motorLeft_f, - controlledMotor* motorRight_f, - evaluatedJoystick* joystick_f, - httpJoystick* httpJoystick_f - ){ +controlledArmchair::controlledArmchair( + control_config_t config_f, + buzzer_t *buzzer_f, + controlledMotor *motorLeft_f, + controlledMotor *motorRight_f, + evaluatedJoystick *joystick_f, + httpJoystick *httpJoystick_f, + automatedArmchair_c *automatedArmchair_f, + cControlledRest *legRest_f, + cControlledRest *backRest_f) +{ //copy configuration config = config_f; @@ -43,13 +46,28 @@ controlledArmchair::controlledArmchair ( motorRight = motorRight_f; joystick_l = joystick_f, httpJoystickMain_l = httpJoystick_f; + automatedArmchair = automatedArmchair_f; + legRest = legRest_f; + backRest = backRest_f; //set default mode from config modePrevious = config.defaultMode; //TODO declare / configure controlled motors here instead of config (unnecessary that button object is globally available - only used here)? } - +//======================================= +//============ control task ============= +//======================================= +//task that controls the armchair modes and initiates commands generation and applies them to driver +//parameter: pointer to controlledArmchair object +void task_control( void * pvParameters ){ + //control_task_parameters_t * objects = (control_task_parameters_t *)pvParameters; + controlledArmchair * control = (controlledArmchair *)pvParameters; + ESP_LOGI(TAG, "Initializing controlledArmchair and starting handle loop"); + //start handle loop (control object declared in config.hpp) + //objects->control->startHandleLoop(); + control->startHandleLoop(); +} //---------------------------------- //---------- Handle loop ----------- @@ -70,7 +88,7 @@ void controlledArmchair::startHandleLoop() { commands = cmds_bothMotorsIdle; motorRight->setTarget(commands.right.state, commands.right.duty); motorLeft->setTarget(commands.left.state, commands.left.duty); - vTaskDelay(200 / portTICK_PERIOD_MS); + vTaskDelay(300 / portTICK_PERIOD_MS); #ifdef JOYSTICK_LOG_IN_IDLE //get joystick data here (without using it) //since loglevel is DEBUG, calculateion details is output @@ -132,7 +150,7 @@ void controlledArmchair::startHandleLoop() { case controlMode_t::AUTO: vTaskDelay(20 / portTICK_PERIOD_MS); //generate commands - commands = armchair.generateCommands(&instruction); + commands = automatedArmchair->generateCommands(&instruction); //--- apply commands to motors --- //TODO make motorctl.setTarget also accept motorcommand struct directly motorRight->setTarget(commands.right.state, commands.right.duty); @@ -179,7 +197,7 @@ void controlledArmchair::startHandleLoop() { motorRight->setTarget(commands.right.state, commands.right.duty); motorLeft->setTarget(commands.left.state, commands.left.duty); //--- control armchair position with joystick input --- - controlChairAdjustment(joystick_l->getData(), &legRest, &backRest); + controlChairAdjustment(joystick_l->getData(), legRest, backRest); break; @@ -359,21 +377,6 @@ void controlledArmchair::changeMode(controlMode_t modeNew) { buzzer->beep(1,200,100); break; - case controlMode_t::HTTP: - ESP_LOGW(TAG, "switching from http mode -> disabling http and wifi"); - //stop http server - ESP_LOGI(TAG, "disabling http server..."); - http_stop_server(); - - //FIXME: make wifi function work here - currently starting wifi at startup (see notes main.cpp) - //stop wifi - //TODO: decide whether ap or client is currently used - which has to be disabled? - //ESP_LOGI(TAG, "deinit wifi..."); - //wifi_deinit_client(); - //wifi_deinit_ap(); - ESP_LOGI(TAG, "done stopping http mode"); - break; - case controlMode_t::MASSAGE: ESP_LOGW(TAG, "switching from MASSAGE mode -> restoring fading, reset frozen input"); //TODO: fix issue when downfading was disabled before switching to massage mode - currently it gets enabled again here... @@ -401,8 +404,8 @@ void controlledArmchair::changeMode(controlMode_t modeNew) { case controlMode_t::ADJUST_CHAIR: ESP_LOGW(TAG, "switching from ADJUST_CHAIR mode => turning off adjustment motors..."); //prevent motors from being always on in case of mode switch while joystick is not in center thus motors currently moving - legRest.setState(REST_OFF); - backRest.setState(REST_OFF); + legRest->setState(REST_OFF); + backRest->setState(REST_OFF); break; } @@ -427,26 +430,6 @@ void controlledArmchair::changeMode(controlMode_t modeNew) { buzzer->beep(4,200,100); break; - case controlMode_t::HTTP: - ESP_LOGW(TAG, "switching to http mode -> enabling http and wifi"); - //start wifi - //TODO: decide wether ap or client should be started - ESP_LOGI(TAG, "init wifi..."); - - //FIXME: make wifi function work here - currently starting wifi at startup (see notes main.cpp) - //wifi_init_client(); - //wifi_init_ap(); - - //wait for wifi - //ESP_LOGI(TAG, "waiting for wifi..."); - //vTaskDelay(1000 / portTICK_PERIOD_MS); - - //start http server - ESP_LOGI(TAG, "init http server..."); - http_init_server(); - ESP_LOGI(TAG, "done initializing http mode"); - break; - case controlMode_t::MASSAGE: ESP_LOGW(TAG, "switching to MASSAGE mode -> reducing fading"); uint32_t shake_msFadeAccel = 500; //TODO: move this to config diff --git a/board_single/main/control.hpp b/board_single/main/control.hpp index 003f299..1ae8e3f 100644 --- a/board_single/main/control.hpp +++ b/board_single/main/control.hpp @@ -5,6 +5,8 @@ #include "buzzer.hpp" #include "http.hpp" #include "auto.hpp" +#include "speedsensor.hpp" +#include "chairAdjust.hpp" //-------------------------------------------- @@ -25,6 +27,13 @@ typedef struct control_config_t { } control_config_t; +//======================================= +//============ control task ============= +//======================================= +//task that controls the armchair modes and initiates commands generation and applies them to driver +//parameter: pointer to controlledArmchair object +void task_control( void * pvParameters ); + //================================== @@ -41,7 +50,10 @@ class controlledArmchair { controlledMotor* motorLeft_f, controlledMotor* motorRight_f, evaluatedJoystick* joystick_f, - httpJoystick* httpJoystick_f + httpJoystick* httpJoystick_f, + automatedArmchair_c* automatedArmchair, + cControlledRest * legRest, + cControlledRest * backRest ); //--- functions --- @@ -85,6 +97,9 @@ class controlledArmchair { controlledMotor* motorRight; httpJoystick* httpJoystickMain_l; evaluatedJoystick* joystick_l; + automatedArmchair_c *automatedArmchair; + cControlledRest * legRest; + cControlledRest * backRest; //---variables --- //struct for motor commands returned by generate functions of each mode @@ -103,7 +118,7 @@ class controlledArmchair { bool freezeInput = false; //variables for AUTO mode - auto_instruction_t instruction = auto_instruction_t::NONE; //variable to receive instructions from automatedArmchair + auto_instruction_t instruction = auto_instruction_t::NONE; //variable to receive instructions from automatedArmchair_c //variable to store button event uint8_t buttonCount = 0; diff --git a/board_single/main/display.cpp b/board_single/main/display.cpp index 5665168..79450ec 100644 --- a/board_single/main/display.cpp +++ b/board_single/main/display.cpp @@ -204,7 +204,7 @@ float getBatteryPercent(){ //----------------------- //shows overview on entire display: //percentage, voltage, current, mode, rpm, speed -void showScreen1() +void showScreen1(display_task_parameters_t * objects) { //-- battery percentage -- // TODO update when no load (currentsensors = ~0A) only @@ -214,24 +214,24 @@ void showScreen1() //-- voltage and current -- displayTextLine(&dev, 3, false, false, "%04.1fV %04.1f:%04.1fA", getBatteryVoltage(), - fabs(motorLeft.getCurrentA()), - fabs(motorRight.getCurrentA())); + fabs(objects->motorLeft->getCurrentA()), + fabs(objects->motorRight->getCurrentA())); //-- control state -- //print large line - displayTextLine(&dev, 4, true, false, "%s ", control.getCurrentModeStr()); + displayTextLine(&dev, 4, true, false, "%s ", objects->control->getCurrentModeStr()); //-- speed and RPM -- displayTextLine(&dev, 7, false, false, "%3.1fkm/h %03.0f:%03.0fR", - fabs((speedLeft.getKmph() + speedRight.getKmph()) / 2), - speedLeft.getRpm(), - speedRight.getRpm()); + fabs((objects->speedLeft->getKmph() + objects->speedRight->getKmph()) / 2), + objects->speedLeft->getRpm(), + objects->speedRight->getRpm()); // debug speed sensors ESP_LOGD(TAG, "%3.1fkm/h %03.0f:%03.0fR", - fabs((speedLeft.getKmph() + speedRight.getKmph()) / 2), - speedLeft.getRpm(), - speedRight.getRpm()); + fabs((objects->speedLeft->getKmph() + objects->speedRight->getKmph()) / 2), + objects->speedLeft->getRpm(), + objects->speedRight->getRpm()); } @@ -264,6 +264,9 @@ void showStartupMsg(){ void display_task(void *pvParameters) { + //get struct with pointers to all needed global objects from task parameter + display_task_parameters_t *objects = (display_task_parameters_t *)pvParameters; + // initialize display display_init(); // TODO check if successfully initialized @@ -276,14 +279,14 @@ void display_task(void *pvParameters) // repeatedly update display with content while (1) { - if (control.getCurrentMode() == controlMode_t::MENU) + if (objects->control->getCurrentMode() == controlMode_t::MENU) { //uses encoder events to control menu and updates display - handleMenu(&dev); + handleMenu(objects, &dev); } else //show status screen in any other mode { - showScreen1(); + showScreen1(objects); vTaskDelay(STATUS_SCREEN_UPDATE_INTERVAL / portTICK_PERIOD_MS); } // TODO add pages and menus diff --git a/board_single/main/display.hpp b/board_single/main/display.hpp index 869435c..9c16983 100644 --- a/board_single/main/display.hpp +++ b/board_single/main/display.hpp @@ -13,7 +13,22 @@ extern "C" { #include "font8x8_basic.h" } -#include "config.hpp" + +#include "joystick.hpp" +#include "control.hpp" +#include "speedsensor.hpp" + +// struct with variables passed to task from main() +typedef struct display_task_parameters_t { + controlledArmchair * control; + evaluatedJoystick * joystick; + QueueHandle_t encoderQueue; + controlledMotor * motorLeft; + controlledMotor * motorRight; + speedSensor * speedLeft; + speedSensor * speedRight; + buzzer_t *buzzer; +} display_task_parameters_t; //task that inititialized the display, displays welcome message diff --git a/board_single/main/encoder.cpp b/board_single/main/encoder.cpp index d2684e1..8f073ae 100644 --- a/board_single/main/encoder.cpp +++ b/board_single/main/encoder.cpp @@ -39,11 +39,17 @@ rotary_encoder_t encoderConfig = { //================================== //========== encoder_init ========== //================================== -//initialize encoder -void encoder_init(){ - encoderQueue = xQueueCreate(QUEUE_SIZE, sizeof(rotary_encoder_event_t)); +//initialize encoder //TODO pass config to this function +QueueHandle_t encoder_init() +{ + QueueHandle_t encoderQueue = xQueueCreate(QUEUE_SIZE, sizeof(rotary_encoder_event_t)); rotary_encoder_init(encoderQueue); rotary_encoder_add(&encoderConfig); + if (encoderQueue == NULL) + ESP_LOGE(TAG, "Error initializing encoder or queue"); + else + ESP_LOGW(TAG, "Initialized encoder and encoderQueue"); + return encoderQueue; } @@ -52,7 +58,9 @@ void encoder_init(){ //====== task_encoderExample ======= //================================== //receive and handle all available encoder events -void task_encoderExample(void *arg) { +void task_encoderExample(void * arg) { + //get queue with encoder events from task parameter: + QueueHandle_t encoderQueue = (QueueHandle_t)arg; static rotary_encoder_event_t ev; //store event data while (1) { if (xQueueReceive(encoderQueue, &ev, portMAX_DELAY)) { diff --git a/board_single/main/encoder.hpp b/board_single/main/encoder.hpp index 0808d13..21a60e9 100644 --- a/board_single/main/encoder.hpp +++ b/board_single/main/encoder.hpp @@ -10,11 +10,11 @@ extern "C" { #define PIN_B GPIO_NUM_26 #define PIN_BUTTON GPIO_NUM_27 -//global encoder queue -extern QueueHandle_t encoderQueue; - //init encoder with config in encoder.cpp -void encoder_init(); +QueueHandle_t encoder_init(); //TODO pass config to function + //task that handles encoder events -void task_encoderExample(void *arg); +//note: queue obtained from encoder_init() has to be passed to that task +void task_encoderExample(void *encoderQueue); +//example: xTaskCreate(&task_encoderExample, "task_buzzer", 2048, encoderQueue, 2, NULL); \ No newline at end of file diff --git a/board_single/main/main.cpp b/board_single/main/main.cpp index 88cf1f9..64e9011 100644 --- a/board_single/main/main.cpp +++ b/board_single/main/main.cpp @@ -1,6 +1,3 @@ -#include "hal/uart_types.h" -#include "motordrivers.hpp" -#include "types.hpp" extern "C" { #include @@ -14,44 +11,88 @@ extern "C" #include "sdkconfig.h" #include "esp_spiffs.h" -#include "driver/ledc.h" - //custom C files #include "wifi.h" } //custom C++ files +//folder common +#include "uart_common.hpp" +#include "motordrivers.hpp" +#include "http.hpp" +#include "types.hpp" +#include "speedsensor.hpp" +#include "motorctl.hpp" + +//folder single_board #include "config.hpp" #include "control.hpp" #include "button.hpp" -#include "http.hpp" - -#include "uart_common.hpp" - #include "display.hpp" #include "encoder.hpp" + +//only extends this file (no library): +//outsourced all configuration related structures +#include "config.cpp" + + + +//================================ +//======== declarations ========== +//================================ +//--- declare all pointers to shared objects --- +controlledMotor *motorLeft; +controlledMotor *motorRight; + +sabertooth2x60a *sabertoothDriver; + +evaluatedJoystick *joystick; + +buzzer_t *buzzer; + +controlledArmchair *control; + +automatedArmchair_c *automatedArmchair; + +httpJoystick *httpJoystickMain; + +speedSensor *speedLeft; +speedSensor *speedRight; + +cControlledRest *legRest; +cControlledRest *backRest; + + +//--- lambda functions motor-driver --- +// functions for updating the duty via currently used motor driver (hardware) that can then be passed to controlledMotor +//-> makes it possible to easily use different motor drivers +motorSetCommandFunc_t setLeftFunc = [&sabertoothDriver](motorCommand_t cmd) +{ + sabertoothDriver->setLeft(cmd); +}; +motorSetCommandFunc_t setRightFunc = [&sabertoothDriver](motorCommand_t cmd) +{ + sabertoothDriver->setRight(cmd); +}; + +//--- lambda function http-joystick --- +// function that initializes the http server requires a function pointer to function that handels each url +// the httpd_uri config struct does not accept a pointer to a method of a class instance, directly +// thus this lambda function is necessary: +// declare pointer to receiveHttpData method of httpJoystick class +esp_err_t (httpJoystick::*pointerToReceiveFunc)(httpd_req_t *req) = &httpJoystick::receiveHttpData; +esp_err_t on_joystick_url(httpd_req_t *req) +{ + // run pointer to receiveHttpData function of httpJoystickMain instance + return (httpJoystickMain->*pointerToReceiveFunc)(req); +} + //tag for logging static const char * TAG = "main"; -//==================================== -//========== motorctl task =========== -//==================================== -//task for handling the motors (ramp, current limit, driver) -void task_motorctl( void * pvParameters ){ - ESP_LOGI(TAG, "starting handle loop..."); - while(1){ - motorRight.handle(); - motorLeft.handle(); - //10khz -> T=100us - vTaskDelay(10 / portTICK_PERIOD_MS); - } -} - - - //====================================== //============ buzzer task ============= //====================================== @@ -61,33 +102,7 @@ void task_buzzer( void * pvParameters ){ ESP_LOGI("task_buzzer", "Start of buzzer task..."); //run function that waits for a beep events to arrive in the queue //and processes them - buzzer.processQueue(); -} - - - -//======================================= -//============ control task ============= -//======================================= -//task that controls the armchair modes and initiates commands generation and applies them to driver -void task_control( void * pvParameters ){ - ESP_LOGI(TAG, "Initializing controlledArmchair and starting handle loop"); - //start handle loop (control object declared in config.hpp) - control.startHandleLoop(); -} - - - -//====================================== -//============ button task ============= -//====================================== -//task that handles the button interface/commands -void task_button( void * pvParameters ){ - ESP_LOGI(TAG, "Initializing command-button and starting handle loop"); - //create button instance - buttonCommands commandButton(&buttonJoystick, &joystick, &control, &buzzer, &motorLeft, &motorRight); - //start handle loop - commandButton.startHandleLoop(); + buzzer->processQueue(); } @@ -95,11 +110,12 @@ void task_button( void * pvParameters ){ //======================================= //============== fan task =============== //======================================= +//TODO: move this definition to fan.cpp //task that controlls fans for cooling the drivers void task_fans( void * pvParameters ){ ESP_LOGI(TAG, "Initializing fans and starting fan handle loop"); //create fan instances with config defined in config.cpp - controlledFan fan(configCooling, &motorLeft, &motorRight); + controlledFan fan(configCooling, motorLeft, motorRight); //repeatedly run fan handle function in a slow loop while(1){ fan.handle(); @@ -132,31 +148,54 @@ void init_spiffs(){ -//================================== -//======== define loglevels ======== -//================================== -void setLoglevels(void){ - //set loglevel for all tags: - esp_log_level_set("*", ESP_LOG_WARN); - //--- set loglevel for individual tags --- - esp_log_level_set("main", ESP_LOG_INFO); - esp_log_level_set("buzzer", ESP_LOG_ERROR); - //esp_log_level_set("motordriver", ESP_LOG_DEBUG); - //esp_log_level_set("motor-control", ESP_LOG_INFO); - //esp_log_level_set("evaluatedJoystick", ESP_LOG_DEBUG); - //esp_log_level_set("joystickCommands", ESP_LOG_DEBUG); - esp_log_level_set("button", ESP_LOG_INFO); - esp_log_level_set("control", ESP_LOG_INFO); - //esp_log_level_set("fan-control", ESP_LOG_INFO); - esp_log_level_set("wifi", ESP_LOG_INFO); - esp_log_level_set("http", ESP_LOG_INFO); - //esp_log_level_set("automatedArmchair", ESP_LOG_DEBUG); - esp_log_level_set("display", ESP_LOG_INFO); - //esp_log_level_set("current-sensors", ESP_LOG_INFO); - //esp_log_level_set("speedSensor", ESP_LOG_INFO); - esp_log_level_set("chair-adjustment", ESP_LOG_INFO); - esp_log_level_set("menu", ESP_LOG_INFO); + +//================================= +//========= createObjects ========= +//================================= +//create all shared objects +//their references can be passed to the tasks that need access in main + +//Note: the configuration structures (e.g. configMotorControlLeft) are outsourced to file 'config.cpp' + +void createObjects() +{ + // create sabertooth motor driver instance + // sabertooth2x60a sabertoothDriver(sabertoothConfig); + // with configuration above + sabertoothDriver = new sabertooth2x60a(sabertoothConfig); + + // create controlled motor instances (motorctl.hpp) + // with configurations above + motorLeft = new controlledMotor(setLeftFunc, configMotorControlLeft); + motorRight = new controlledMotor(setRightFunc, configMotorControlRight); + + // create speedsensor instances + // with configurations above + speedLeft = new speedSensor(speedLeft_config); + speedRight = new speedSensor(speedRight_config); + + // create joystic instance (joystick.hpp) + joystick = new evaluatedJoystick(configJoystick); + + // create httpJoystick object (http.hpp) + httpJoystickMain = new httpJoystick(configHttpJoystickMain); + http_init_server(on_joystick_url); + + // create buzzer object on pin 12 with gap between queued events of 100ms + buzzer = new buzzer_t(GPIO_NUM_12, 100); + + // create control object (control.hpp) + // with configuration above + control = new controlledArmchair(configControl, buzzer, motorLeft, motorRight, joystick, httpJoystickMain, automatedArmchair, legRest, backRest); + + // create automatedArmchair_c object (for auto-mode) (auto.hpp) + automatedArmchair = new automatedArmchair_c(motorLeft, motorRight); + + // create objects for controlling the chair position + // gpio_up, gpio_down, name + legRest = new cControlledRest(GPIO_NUM_4, GPIO_NUM_16, "legRest"); + backRest = new cControlledRest(GPIO_NUM_2, GPIO_NUM_15, "backRest"); } @@ -166,25 +205,53 @@ void setLoglevels(void){ //=========== app_main ============ //================================= extern "C" void app_main(void) { - //enable 5V volate regulator + + ESP_LOGW(TAG, "===== INITIALIZING COMPONENTS ====="); + //--- define log levels --- + setLoglevels(); + + //--- enable 5V volate regulator --- ESP_LOGW(TAG, "enabling 5V regulator..."); gpio_pad_select_gpio(GPIO_NUM_17); gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT); gpio_set_level(GPIO_NUM_17, 1); - //---- define log levels ---- - setLoglevels(); + //--- initialize nvs-flash and netif (needed for wifi) --- + wifi_initNvs_initNetif(); + + //--- initialize spiffs --- + init_spiffs(); + + //--- initialize and start wifi --- + ESP_LOGD(TAG,"starting wifi..."); + //wifi_init_client(); //connect to existing wifi + wifi_init_ap(); //start access point + ESP_LOGD(TAG,"done starting wifi"); - // init encoder //--- initialize encoder --- - encoder_init(); - // now global encoderQueue providing all encoder events is available + const QueueHandle_t encoderQueue = encoder_init(); + + + + //--- create all objects --- + ESP_LOGW(TAG, "===== CREATING SHARED OBJECTS ====="); + + //create all class instances used below + //see 'createObjects.hpp' + createObjects(); + + + +#ifndef ENCODER_TEST + //--- create tasks --- + ESP_LOGW(TAG, "===== CREATING TASKS ====="); //---------------------------------------------- //--- create task for controlling the motors --- //---------------------------------------------- //task that receives commands, handles ramp and current limit and executes commands using the motordriver function - xTaskCreate(&task_motorctl, "task_motor-control", 2*4096, NULL, 6, NULL); + task_motorctl_parameters_t motorctl_param = {motorLeft, motorRight}; + xTaskCreate(&task_motorctl, "task_motor-control", 2*4096, &motorctl_param, 6, NULL); //------------------------------ //--- create task for buzzer --- @@ -195,46 +262,38 @@ extern "C" void app_main(void) { //--- create task for control --- //------------------------------- //task that generates motor commands depending on the current mode and sends those to motorctl task - xTaskCreate(&task_control, "task_control", 4096, NULL, 5, NULL); + //note: pointer to shared object 'control' is passed as task parameter: + xTaskCreate(&task_control, "task_control", 4096, control, 5, NULL); //------------------------------ //--- create task for button --- //------------------------------ - //task that evaluates and processes the button input and runs the configured commands - xTaskCreate(&task_button, "task_button", 4096, NULL, 4, NULL); + //task that handles button/encoder events in any mode except 'MENU' (e.g. switch modes by pressing certain count) + task_button_parameters_t button_param = {control, joystick, encoderQueue, motorLeft, motorRight, buzzer}; + xTaskCreate(&task_button, "task_button", 4096, &button_param, 4, NULL); //----------------------------------- //--- create task for fan control --- //----------------------------------- - //task that evaluates and processes the button input and runs the configured commands + //task that controls cooling fans of the motor driver xTaskCreate(&task_fans, "task_fans", 2048, NULL, 1, NULL); - //----------------------------------- //----- create task for display ----- //----------------------------------- - //task that handles the display - xTaskCreate(&display_task, "display_task", 3*2048, NULL, 1, NULL); + ////task that handles the display (show stats, handle menu in 'MENU' mode) + display_task_parameters_t display_param = {control, joystick, encoderQueue, motorLeft, motorRight, speedLeft, speedRight, buzzer}; + xTaskCreate(&display_task, "display_task", 3*2048, &display_param, 1, NULL); - //beep at startup - buzzer.beep(3, 70, 50); +#endif - //--- initialize nvs-flash and netif (needed for wifi) --- - wifi_initNvs_initNetif(); - - //--- initialize spiffs --- - init_spiffs(); - - //--- initialize and start wifi --- - //FIXME: run wifi_init_client or wifi_init_ap as intended from control.cpp when switching state - //currently commented out because of error "assert failed: xQueueSemaphoreTake queue.c:1549 (pxQueue->uxItemSize == 0)" when calling control->changeMode from button.cpp - //when calling control.changeMode(http) from main.cpp it worked without error for some reason? - ESP_LOGI(TAG,"starting wifi..."); - //wifi_init_client(); //connect to existing wifi - wifi_init_ap(); //start access point - ESP_LOGI(TAG,"done starting wifi"); + //--- startup finished --- + ESP_LOGW(TAG, "===== STARTUP FINISHED ====="); + buzzer->beep(3, 70, 50); + //--- testing encoder --- + //xTaskCreate(&task_encoderExample, "task_buzzer", 2048, encoderQueue, 2, NULL); //--- testing http server --- // wifi_init_client(); //connect to existing wifi @@ -243,8 +302,8 @@ extern "C" void app_main(void) { // http_init_server(); - //--- testing force http mode after startup --- - //control.changeMode(controlMode_t::HTTP); + //--- testing force specific mode after startup --- + //control->changeMode(controlMode_t::MENU); diff --git a/board_single/main/menu.cpp b/board_single/main/menu.cpp index 2b99684..622b675 100644 --- a/board_single/main/menu.cpp +++ b/board_single/main/menu.cpp @@ -30,12 +30,14 @@ static int value = 0; //######################### //#### center Joystick #### //######################### -void item_centerJoystick_action(int value, SSD1306_t * display){ +void item_centerJoystick_action(display_task_parameters_t * objects, SSD1306_t * display, int value){ if (!value) return; ESP_LOGW(TAG, "defining joystick center"); - joystick.defineCenter(); + (*objects).joystick->defineCenter(); + //objects->joystick->defineCenter(); + //joystick->defineCenter(); } -int item_centerJoystick_value(){ +int item_centerJoystick_value(display_task_parameters_t * objects){ return 1; } @@ -59,7 +61,7 @@ menuItem_t item_centerJoystick = { //#### debug Joystick #### //######################## //continously show/update joystick data on display -void item_debugJoystick_action(int value, SSD1306_t * display) +void item_debugJoystick_action(display_task_parameters_t * objects, SSD1306_t * display, int value) { //--- variables --- bool running = true; @@ -77,10 +79,10 @@ void item_debugJoystick_action(int value, SSD1306_t * display) //-- show/update values -- // stop when button pressed or control state changes (timeouts to IDLE) - while (running && control.getCurrentMode() == controlMode_t::MENU) + while (running && objects->control->getCurrentMode() == controlMode_t::MENU) { // repeatedly print all joystick data - joystickData_t data = joystick.getData(); + joystickData_t data = objects->joystick->getData(); displayTextLine(display, 1, false, false, "x = %.3f ", data.x); displayTextLine(display, 2, false, false, "y = %.3f ", data.y); displayTextLine(display, 3, false, false, "radius = %.3f", data.radius); @@ -88,7 +90,7 @@ void item_debugJoystick_action(int value, SSD1306_t * display) displayTextLine(display, 5, false, false, "pos=%-12s ", joystickPosStr[(int)data.position]); // exit when button pressed - if (xQueueReceive(encoderQueue, &event, 20 / portTICK_PERIOD_MS)) + if (xQueueReceive(objects->encoderQueue, &event, 20 / portTICK_PERIOD_MS)) { switch (event.type) { @@ -105,7 +107,7 @@ void item_debugJoystick_action(int value, SSD1306_t * display) } } -int item_debugJoystick_value(){ +int item_debugJoystick_value(display_task_parameters_t * objects){ return 1; } @@ -128,12 +130,12 @@ menuItem_t item_debugJoystick = { //######################## //##### set max duty ##### //######################## -void maxDuty_action(int value, SSD1306_t * display) +void maxDuty_action(display_task_parameters_t * objects, SSD1306_t * display, int value) { //TODO actually store the value ESP_LOGW(TAG, "set max duty to %d", value); } -int maxDuty_currentValue() +int maxDuty_currentValue(display_task_parameters_t * objects) { //TODO get real current value return 84; @@ -156,14 +158,14 @@ menuItem_t item_maxDuty = { //###################### //##### accelLimit ##### //###################### -void item_accelLimit_action(int value, SSD1306_t * display) +void item_accelLimit_action(display_task_parameters_t * objects, SSD1306_t * display, int value) { - motorLeft.setFade(fadeType_t::ACCEL, (uint32_t)value); - motorRight.setFade(fadeType_t::ACCEL, (uint32_t)value); + objects->motorLeft->setFade(fadeType_t::ACCEL, (uint32_t)value); + objects->motorRight->setFade(fadeType_t::ACCEL, (uint32_t)value); } -int item_accelLimit_value() +int item_accelLimit_value(display_task_parameters_t * objects) { - return motorLeft.getFade(fadeType_t::ACCEL); + return objects->motorLeft->getFade(fadeType_t::ACCEL); } menuItem_t item_accelLimit = { item_accelLimit_action, // function action @@ -183,14 +185,14 @@ menuItem_t item_accelLimit = { // ###################### // ##### decelLimit ##### // ###################### -void item_decelLimit_action(int value, SSD1306_t * display) +void item_decelLimit_action(display_task_parameters_t * objects, SSD1306_t * display, int value) { - motorLeft.setFade(fadeType_t::DECEL, (uint32_t)value); - motorRight.setFade(fadeType_t::DECEL, (uint32_t)value); + objects->motorLeft->setFade(fadeType_t::DECEL, (uint32_t)value); + objects->motorRight->setFade(fadeType_t::DECEL, (uint32_t)value); } -int item_decelLimit_value() +int item_decelLimit_value(display_task_parameters_t * objects) { - return motorLeft.getFade(fadeType_t::DECEL); + return objects->motorLeft->getFade(fadeType_t::DECEL); } menuItem_t item_decelLimit = { item_decelLimit_action, // function action @@ -210,11 +212,11 @@ menuItem_t item_decelLimit = { //##################### //###### example ###### //##################### -void item_example_action(int value, SSD1306_t * display) +void item_example_action(display_task_parameters_t * objects, SSD1306_t * display, int value) { return; } -int item_example_value(){ +int item_example_value(display_task_parameters_t * objects){ return 53; } menuItem_t item_example = { @@ -342,7 +344,7 @@ void showValueSelect(SSD1306_t *display, int selectedItem) //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) -void handleMenu(SSD1306_t *display) +void handleMenu(display_task_parameters_t * objects, SSD1306_t *display) { static uint32_t lastActivity = 0; static int selectedItem = 0; @@ -358,7 +360,7 @@ void handleMenu(SSD1306_t *display) // update display showItemList(display, selectedItem); // shows list of items with currently selected one on display // wait for encoder event - if (xQueueReceive(encoderQueue, &event, QUEUE_TIMEOUT / portTICK_PERIOD_MS)) + if (xQueueReceive(objects->encoderQueue, &event, QUEUE_TIMEOUT / portTICK_PERIOD_MS)) { lastActivity = esp_log_timestamp(); switch (event.type) @@ -387,7 +389,7 @@ void handleMenu(SSD1306_t *display) // change state (menu to set value) menuState = SET_VALUE; // get currently configured value - value = menuItems[selectedItem].currentValue(); + value = menuItems[selectedItem].currentValue(objects); // clear display ssd1306_clear_screen(display, false); break; @@ -395,7 +397,7 @@ void handleMenu(SSD1306_t *display) //exit menu mode case RE_ET_BTN_LONG_PRESSED: //change to previous mode (e.g. JOYSTICK) - 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 ssd1306_clear_screen(display, false); break; @@ -413,7 +415,7 @@ void handleMenu(SSD1306_t *display) // wait for encoder event showValueSelect(display, selectedItem); - if (xQueueReceive(encoderQueue, &event, QUEUE_TIMEOUT / portTICK_PERIOD_MS)) + if (xQueueReceive(objects->encoderQueue, &event, QUEUE_TIMEOUT / portTICK_PERIOD_MS)) { lastActivity = esp_log_timestamp(); switch (event.type) @@ -434,7 +436,7 @@ void handleMenu(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); - menuItems[selectedItem].action(value, display); + menuItems[selectedItem].action(objects, display, value); menuState = MAIN_MENU; break; case RE_ET_BTN_PRESSED: @@ -459,7 +461,7 @@ void handleMenu(SSD1306_t *display) menuState = MAIN_MENU; ssd1306_clear_screen(display, false); // change control mode - control.changeMode(controlMode_t::IDLE); + objects->control->changeMode(controlMode_t::IDLE); return; } } \ No newline at end of file diff --git a/board_single/main/menu.hpp b/board_single/main/menu.hpp index 6b86e47..96534ea 100644 --- a/board_single/main/menu.hpp +++ b/board_single/main/menu.hpp @@ -13,9 +13,10 @@ typedef enum { //--- menuItem_t --- // struct describes one menu element (all defined in menu.cpp) -typedef struct { - void (*action)(int value, SSD1306_t * display); // pointer to function run when confirmed - int (*currentValue)(); // pointer to function to get currently configured value +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 valueMin; // min allowed value int valueMax; // max allowed value int valueIncrement; // amount changed at one encoder tick (+/-) @@ -28,5 +29,4 @@ typedef struct { const char line7[17]; // below value } menuItem_t; - -void handleMenu(SSD1306_t * display); \ No newline at end of file +void handleMenu(display_task_parameters_t * objects, SSD1306_t *display); \ No newline at end of file diff --git a/board_single/sdkconfig b/board_single/sdkconfig index 6e3dc02..b5179e1 100644 --- a/board_single/sdkconfig +++ b/board_single/sdkconfig @@ -140,10 +140,10 @@ CONFIG_I2C_INTERFACE=y # CONFIG_SPI_INTERFACE is not set # CONFIG_SSD1306_128x32 is not set CONFIG_SSD1306_128x64=y -CONFIG_OFFSETX=0 +CONFIG_OFFSETX=2 # CONFIG_FLIP is not set CONFIG_SCL_GPIO=22 -CONFIG_SDA_GPIO=21 +CONFIG_SDA_GPIO=23 CONFIG_RESET_GPIO=15 CONFIG_I2C_PORT_0=y # CONFIG_I2C_PORT_1 is not set @@ -1246,6 +1246,17 @@ CONFIG_WPA_MBEDTLS_CRYPTO=y # CONFIG_WPA_MBO_SUPPORT is not set # CONFIG_WPA_DPP_SUPPORT is not set # end of Supplicant + +# +# Rotary encoders +# +CONFIG_RE_MAX=1 +CONFIG_RE_INTERVAL_US=1000 +CONFIG_RE_BTN_DEAD_TIME_US=10000 +CONFIG_RE_BTN_PRESSED_LEVEL_0=y +# CONFIG_RE_BTN_PRESSED_LEVEL_1 is not set +CONFIG_RE_BTN_LONG_PRESS_TIME_US=500000 +# end of Rotary encoders # end of Component config # diff --git a/common/http.cpp b/common/http.cpp index 8b784a4..4bdb2be 100644 --- a/common/http.cpp +++ b/common/http.cpp @@ -201,27 +201,17 @@ joystickData_t httpJoystick::getData(){ } -//-------------------------------------------- -//--- receiveHttpData for httpJoystickMain --- -//-------------------------------------------- -//function that wraps pointer to member function of httpJoystickMain instance in a "normal" function which the webserver can run on joystick URL - -//declare pointer to receiveHttpData method of httpJoystick class -esp_err_t (httpJoystick::*pointerToReceiveFunc)(httpd_req_t *req) = &httpJoystick::receiveHttpData; - -esp_err_t on_joystick_url(httpd_req_t *req){ - //run pointer to receiveHttpData function of httpJoystickMain instance - return (httpJoystickMain.*pointerToReceiveFunc)(req); -} - - //============================ //===== init http server ===== //============================ -//function that initializes http server and configures available urls -void http_init_server() +//function that initializes http server and configures available url's + +//parameter: provide pointer to function that handle incomming joystick data (for configuring the url) +//TODO add handle functions to future additional endpoints/urls here too +void http_init_server(http_handler_t onJoystickUrl) { + ESP_LOGI(TAG, "initializing HTTP-Server..."); //---- configure webserver ---- httpd_config_t config = HTTPD_DEFAULT_CONFIG(); @@ -236,7 +226,7 @@ void http_init_server() httpd_uri_t joystick_url = { .uri = "/api/joystick", .method = HTTP_POST, - .handler = on_joystick_url, + .handler = onJoystickUrl, }; httpd_register_uri_handler(server, &joystick_url); @@ -265,8 +255,8 @@ void http_init_server() //function that destroys the http server void http_stop_server() { - printf("stopping http\n"); - httpd_stop(server); + ESP_LOGW(TAG, "stopping HTTP-Server"); + httpd_stop(server); } diff --git a/common/http.hpp b/common/http.hpp index 0005c84..d007919 100644 --- a/common/http.hpp +++ b/common/http.hpp @@ -13,7 +13,18 @@ extern "C" //===== init http server ===== //============================ //function that initializes http server and configures available urls -void http_init_server(); +//parameter: provide pointer to function that handles incomming joystick data (for configuring the url) +//TODO add handle functions to future additional endpoints/urls here too +typedef esp_err_t (*http_handler_t)(httpd_req_t *req); +void http_init_server(http_handler_t onJoystickUrl); + +//example with lambda function to pass method of a class instance: +//esp_err_t (httpJoystick::*pointerToReceiveFunc)(httpd_req_t *req) = &httpJoystick::receiveHttpData; +//esp_err_t on_joystick_url(httpd_req_t *req){ +// //run pointer to receiveHttpData function of httpJoystickMain instance +// return (httpJoystickMain->*pointerToReceiveFunc)(req); +//} +//http_init_server(on_joystick_url); //============================== @@ -27,7 +38,7 @@ void start_mdns_service(); //===== stop http server ===== //============================ //function that destroys the http server -void http_stop_server(); +void http_stop_server(httpd_handle_t * httpServer); //============================== @@ -47,7 +58,7 @@ typedef struct httpJoystick_config_t { class httpJoystick{ public: //--- constructor --- - httpJoystick( httpJoystick_config_t config_f ); + httpJoystick(httpJoystick_config_t config_f); //--- functions --- joystickData_t getData(); //wait for and return joystick data from queue, if timeout return CENTER @@ -67,11 +78,4 @@ class httpJoystick{ .radius = 0, .angle = 0 }; -}; - - - -//===== global object ===== -//create global instance of httpJoystick -//note: is constructed/configured in config.cpp -extern httpJoystick httpJoystickMain; +}; \ No newline at end of file diff --git a/common/motorctl.cpp b/common/motorctl.cpp index 67ee009..d3c4f1a 100644 --- a/common/motorctl.cpp +++ b/common/motorctl.cpp @@ -7,6 +7,24 @@ static const char * TAG = "motor-control"; #define TIMEOUT_IDLE_WHEN_NO_COMMAND 8000 + + +//==================================== +//========== motorctl task =========== +//==================================== +//task for handling the motors (ramp, current limit, driver) +void task_motorctl( void * task_motorctl_parameters ){ + task_motorctl_parameters_t *objects = (task_motorctl_parameters_t *)task_motorctl_parameters; + ESP_LOGW(TAG, "Task-motorctl: starting handle loop..."); + while(1){ + objects->motorRight->handle(); + objects->motorLeft->handle(); + vTaskDelay(20 / portTICK_PERIOD_MS); + } +} + + + //============================= //======== constructor ======== //============================= @@ -33,6 +51,11 @@ controlledMotor::controlledMotor(motorSetCommandFunc_t setCommandFunc, motorctl //============================ void controlledMotor::init(){ commandQueue = xQueueCreate( 1, sizeof( struct motorCommand_t ) ); + if (commandQueue == NULL) + ESP_LOGE(TAG, "Failed to create command-queue"); + else + ESP_LOGW(TAG, "Initialized command-queue"); + //cSensor.calibrateZeroAmpere(); //currently done in currentsensor constructor TODO do this regularly e.g. in idle? } @@ -252,11 +275,11 @@ void controlledMotor::setTarget(motorstate_t state_f, float duty_f){ .state = state_f, .duty = duty_f }; - - ESP_LOGD(TAG, "Inserted command to queue: state=%s, duty=%.2f", motorstateStr[(int)commandSend.state], commandSend.duty); + ESP_LOGI(TAG, "setTarget: Inserting command to queue: state='%s'(%d), duty=%.2f", motorstateStr[(int)commandSend.state], (int)commandSend.state, commandSend.duty); //send command to queue (overwrite if an old command is still in the queue and not processed) xQueueOverwrite( commandQueue, ( void * )&commandSend); //xQueueSend( commandQueue, ( void * )&commandSend, ( TickType_t ) 0 ); + ESP_LOGD(TAG, "finished inserting new command"); } diff --git a/common/motorctl.hpp b/common/motorctl.hpp index adeb840..5792d55 100644 --- a/common/motorctl.hpp +++ b/common/motorctl.hpp @@ -86,3 +86,21 @@ class controlledMotor { uint32_t timestamp_commandReceived = 0; bool receiveTimeout = false; }; + + + +// struct with variables passed to task from main +typedef struct task_motorctl_parameters_t { + controlledMotor * motorLeft; + controlledMotor * motorRight; +} task_motorctl_parameters_t; + + +//==================================== +//========== motorctl task =========== +//==================================== +//task that inititialized the display, displays welcome message +//and releatedly updates the display with certain content +//note: pointer to required objects have to be provided as task-parameter +void task_motorctl( void * task_motorctl_parameters ); +