diff --git a/components/FastLED-idf b/components/FastLED-idf index 3f4d710..6a64e87 160000 --- a/components/FastLED-idf +++ b/components/FastLED-idf @@ -1 +1 @@ -Subproject commit 3f4d71050e64e15df045e9320a79a7bb77261310 +Subproject commit 6a64e87bc3251741ad161436c63424263dbcd23f diff --git a/components/TFT_eSPI b/components/TFT_eSPI index 4dacb61..39dd567 160000 --- a/components/TFT_eSPI +++ b/components/TFT_eSPI @@ -1 +1 @@ -Subproject commit 4dacb617bec71ef793b14b69629b2214e06bea28 +Subproject commit 39dd567a9ed2de0ef8f655d7b23cbccc15666320 diff --git a/components/arduino-esp32 b/components/arduino-esp32 index 07f43ec..1acd16f 160000 --- a/components/arduino-esp32 +++ b/components/arduino-esp32 @@ -1 +1 @@ -Subproject commit 07f43ec91cf6d6e185850a839db8229557bdc2d0 +Subproject commit 1acd16f991f4e7ced82ee794a1a31899daf99c0b diff --git a/components/bobbycar-protocol b/components/bobbycar-protocol index 701243a..0734d65 160000 --- a/components/bobbycar-protocol +++ b/components/bobbycar-protocol @@ -1 +1 @@ -Subproject commit 701243ad89a3efead1fba2dbd5c9228ea7d407e5 +Subproject commit 0734d65146169297f82c91cb958761680a4ea232 diff --git a/components/esp-gui-lib b/components/esp-gui-lib index ab94620..0f89f6c 160000 --- a/components/esp-gui-lib +++ b/components/esp-gui-lib @@ -1 +1 @@ -Subproject commit ab946208e51df556d237d67e23e845573374b4a7 +Subproject commit 0f89f6c994d8b43d5c7759f4ac109baf80bbec7f diff --git a/components/espconfiglib b/components/espconfiglib index 6129681..64af48a 160000 --- a/components/espconfiglib +++ b/components/espconfiglib @@ -1 +1 @@ -Subproject commit 6129681a6daf3554c17763ca8c86265c01a5854f +Subproject commit 64af48aca0fab7bd3d85cd03bb216c2f68ca3332 diff --git a/components/espwifistack b/components/espwifistack index 2bf332f..980a4ac 160000 --- a/components/espwifistack +++ b/components/espwifistack @@ -1 +1 @@ -Subproject commit 2bf332f3eb6816721f0f9a60c0ca14787cacbc65 +Subproject commit 980a4acd11c2cafeb4f037fb41ae5501008452a3 diff --git a/configs/config_comred_new.cmake b/configs/config_comred_new.cmake index fe9ea98..331f554 100644 --- a/configs/config_comred_new.cmake +++ b/configs/config_comred_new.cmake @@ -1,20 +1,20 @@ set(BOBBY_APP_NAME bobbyquad_comred_new) set(BOBBY_DEFAULT_USERNAME comred_new) -add_definitions( - -DUSER_SETUP_LOADED=1 - -DLOAD_GLCD=1 - -DLOAD_FONT2=1 - -DLOAD_FONT4=1 - -DLOAD_FONT7=1 - -DILI9341_DRIVER=1 - -DTFT_MOSI=13 - -DTFT_SCLK=15 - -DTFT_CS=14 - -DTFT_DC=12 - -DTFT_RST=2 - -DSPI_FREQUENCY=40000000 -) +# add_definitions( +# -DUSER_SETUP_LOADED=1 +# -DLOAD_GLCD=1 +# -DLOAD_FONT2=1 +# -DLOAD_FONT4=1 +# -DLOAD_FONT7=1 +# -DILI9341_DRIVER=1 +# -DTFT_MOSI=13 +# -DTFT_SCLK=15 +# -DTFT_CS=14 +# -DTFT_DC=12 +# -DTFT_RST=2 +# -DSPI_FREQUENCY=40000000 +# ) set(BOBBYCAR_BUILDFLAGS # Pins diff --git a/configs/sdkconfig_comred_new b/configs/sdkconfig_comred_new index bbb6272..c8eb7d1 100644 --- a/configs/sdkconfig_comred_new +++ b/configs/sdkconfig_comred_new @@ -180,6 +180,7 @@ CONFIG_SOC_WIFI_WAPI_SUPPORT=y CONFIG_SOC_WIFI_CSI_SUPPORT=y CONFIG_SOC_WIFI_MESH_SUPPORT=y CONFIG_SOC_BLE_SUPPORTED=y +CONFIG_SOC_BLE_MESH_SUPPORTED=y CONFIG_SOC_BT_CLASSIC_SUPPORTED=y CONFIG_IDF_CMAKE=y CONFIG_IDF_TARGET_ARCH_XTENSA=y @@ -665,6 +666,7 @@ CONFIG_SPI_SLAVE_ISR_IN_IRAM=y # MCPWM Configuration # # CONFIG_MCPWM_ISR_IRAM_SAFE is not set +# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set # CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set # CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set # end of MCPWM Configuration @@ -1733,8 +1735,8 @@ CONFIG_TFT_ILI9341_DRIVER=y # CONFIG_TFT_SSD1963_800ALT_DRIVER is not set # CONFIG_TFT_ILI9225_DRIVER is not set # CONFIG_TFT_GC9A01_DRIVER is not set -CONFIG_TFT_RGB_ORDER=y -# CONFIG_TFT_BGR_ORDER is not set +# CONFIG_TFT_RGB_ORDER is not set +CONFIG_TFT_BGR_ORDER=y # CONFIG_TFT_M5STACK is not set CONFIG_TFT_INVERSION_DISABLE=y # CONFIG_TFT_INVERSION_ON is not set @@ -1766,12 +1768,13 @@ CONFIG_TFT_RST=2 # # CONFIG_TFT_LOAD_GLCD is not set CONFIG_TFT_LOAD_FONT2=y -# CONFIG_TFT_LOAD_FONT4 is not set +CONFIG_TFT_LOAD_FONT4=y CONFIG_TFT_LOAD_FONT6=y CONFIG_TFT_LOAD_FONT7=y CONFIG_TFT_LOAD_FONT8=y CONFIG_TFT_LOAD_GFXFF=y CONFIG_TFT_SMOOTH_FONT=y +# CONFIG_TFT_IS_AUTOBAHN is not set # end of Fonts # diff --git a/configs/sdkconfig_testdevice2 b/configs/sdkconfig_testdevice2 index 24b653a..4d84b15 100644 --- a/configs/sdkconfig_testdevice2 +++ b/configs/sdkconfig_testdevice2 @@ -180,6 +180,7 @@ CONFIG_SOC_WIFI_WAPI_SUPPORT=y CONFIG_SOC_WIFI_CSI_SUPPORT=y CONFIG_SOC_WIFI_MESH_SUPPORT=y CONFIG_SOC_BLE_SUPPORTED=y +CONFIG_SOC_BLE_MESH_SUPPORTED=y CONFIG_SOC_BT_CLASSIC_SUPPORTED=y CONFIG_IDF_CMAKE=y CONFIG_IDF_TARGET_ARCH_XTENSA=y @@ -665,6 +666,7 @@ CONFIG_SPI_SLAVE_ISR_IN_IRAM=y # MCPWM Configuration # # CONFIG_MCPWM_ISR_IRAM_SAFE is not set +# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set # CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set # CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set # end of MCPWM Configuration @@ -1773,6 +1775,7 @@ CONFIG_TFT_LOAD_FONT7=y CONFIG_TFT_LOAD_FONT8=y CONFIG_TFT_LOAD_GFXFF=y CONFIG_TFT_SMOOTH_FONT=y +# CONFIG_TFT_IS_AUTOBAHN is not set # end of Fonts # diff --git a/dependencies.lock b/dependencies.lock index d1b0fd4..4fe39c7 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -4,6 +4,6 @@ dependencies: source: type: idf version: 5.1.0 -manifest_hash: 61ebe3a040bdb7a8bb7b582261db12d83b6028789124b5f6ddacb4104628daa6 +manifest_hash: 9a4f2dfb2ab76ca07dad44e92970eea272a02162afa87b1dc511d285966e0252 target: esp32 version: 1.0.0 diff --git a/esp-idf b/esp-idf index 756de87..036e4cc 160000 --- a/esp-idf +++ b/esp-idf @@ -1 +1 @@ -Subproject commit 756de87ccfe91fd2384c1b776dc6db7ba0f03d46 +Subproject commit 036e4cc64b442660c916542c5ee78971ba27c2e0 diff --git a/esp-protocols b/esp-protocols index 49e1369..d8db56f 160000 --- a/esp-protocols +++ b/esp-protocols @@ -1 +1 @@ -Subproject commit 49e1369ae94752b091903034fc706a62de11761b +Subproject commit d8db56f89ecb710b7b7348871f0418fdb8ce5275 diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 5227b44..ffb26d6 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,4 +1,4 @@ -set(headers +set(BOBBY_HEADERS accessorhelpers.h accessors/globalaccessors.h accessors/settingsaccessors.h @@ -26,6 +26,7 @@ set(headers actions/rebootaction.h actions/resetnvsaction.h actions/savesettingsaction.h + actions/setupactions.h actions/switchprofileaction.h actions/tempomatmodeapplycurrentpeedaction.h actions/updateswapfrontbackaction.h @@ -72,7 +73,6 @@ set(headers displays/bobbymenudisplay.h displays/bobbypopupdisplay.h displays/bobbysplitgraphdisplay.h - displays/buttoncalibratedisplay.h displays/calibratevoltagedisplay.h displays/confiscationdisplay.h displays/gameoflifedisplay.h @@ -159,6 +159,13 @@ set(headers displays/qrcodedebug.h displays/qrdisplay.h displays/qrimportdisplay.h + displays/setup/ask_calibrate_other_buttons.h + displays/setup/ask_setup_clouds.h + displays/setup/basic_buttons.h + displays/setup/calibrate_potis.h + displays/setup/final_information.h + displays/setup/information.h + displays/setup/setup_cloud.h displays/speedinfodisplay.h displays/spirodisplay.h displays/starfielddisplay.h @@ -233,6 +240,7 @@ set(headers serial_bobby.h settingspersister.h settingsutils.h + setup.h softpwmlimiter.h statistics.h statustexthelper.h @@ -259,7 +267,7 @@ set(headers wifiguiutils.h ) -set(sources +set(BOBBY_SOURCES accessors/wifistaconfigaccessors.cpp actions/assertaction.cpp actions/bluetoothbeginaction.cpp @@ -282,6 +290,7 @@ set(sources actions/rebootaction.cpp actions/resetnvsaction.cpp actions/savesettingsaction.cpp + actions/setupactions.cpp actions/switchprofileaction.cpp actions/tempomatmodeapplycurrentpeedaction.cpp actions/updateswapfrontbackaction.cpp @@ -325,7 +334,6 @@ set(sources displays/bobbymenudisplay.cpp displays/bobbypopupdisplay.cpp displays/bobbysplitgraphdisplay.cpp - displays/buttoncalibratedisplay.cpp displays/calibratevoltagedisplay.cpp displays/confiscationdisplay.cpp displays/gameoflifedisplay.cpp @@ -410,6 +418,13 @@ set(sources displays/qrcodedebug.cpp displays/qrdisplay.cpp displays/qrimportdisplay.cpp + displays/setup/ask_calibrate_other_buttons.cpp + displays/setup/ask_setup_clouds.cpp + displays/setup/basic_buttons.cpp + displays/setup/calibrate_potis.cpp + displays/setup/final_information.cpp + displays/setup/information.cpp + displays/setup/setup_cloud.cpp displays/speedinfodisplay.cpp displays/spirodisplay.cpp displays/starfielddisplay.cpp @@ -485,6 +500,7 @@ set(sources serial_bobby.cpp settingspersister.cpp settingsutils.cpp + setup.cpp softpwmlimiter.cpp statistics.cpp statustexthelper.cpp @@ -519,8 +535,8 @@ set(dependencies idf_component_register( SRCS - ${headers} - ${sources} + ${BOBBY_HEADERS} + ${BOBBY_SOURCES} INCLUDE_DIRS . REQUIRES @@ -538,14 +554,31 @@ execute_process( COMMAND git rev-parse --abbrev-ref HEAD OUTPUT_VARIABLE GIT_BRANCH ) +execute_process( + COMMAND git status --short + OUTPUT_VARIABLE GIT_STATUS +) + +if (NOT GIT_STATUS STREQUAL "") + set(GIT_STATUS "dirty") +else() + set(GIT_STATUS "clean") +endif() string(STRIP "${GIT_REV}" GIT_REV) string(SUBSTRING "${GIT_REV}" 1 7 GIT_SHORT_REV) string(STRIP "${GIT_MESSAGE}" GIT_MESSAGE) string(REPLACE "\n" " " GIT_MESSAGE "${GIT_MESSAGE}") +string(REPLACE "\"" "\\\"" GIT_MESSAGE "${GIT_MESSAGE}") string(SUBSTRING "${GIT_MESSAGE}" 0 100 GIT_MESSAGE) string(STRIP "${GIT_BRANCH}" GIT_BRANCH) +message(WARNING "Git revision: ${GIT_REV}") +message(WARNING "Git short revision: ${GIT_SHORT_REV}") +message(WARNING "Git message: ${GIT_MESSAGE}") +message(WARNING "Git branch: ${GIT_BRANCH}") +message(WARNING "Git status: ${GIT_STATUS}") + if(NOT DEFINED BOBBY_DEFAULT_USERNAME) message(FATAL_ERROR "Please define BOBBY_DEFAULT_USERNAME") endif() diff --git a/main/actions/qraction.h b/main/actions/qraction.h index 1cb0702..4ed0f0d 100644 --- a/main/actions/qraction.h +++ b/main/actions/qraction.h @@ -32,7 +32,6 @@ private: std::string m_msg; }; -template class PushQrImportDisplayAction : public virtual espgui::ActionInterface { public: @@ -41,7 +40,7 @@ public: void triggered() override { - espgui::pushScreen>(std::move(m_nvskey)); + espgui::pushScreen(std::move(m_nvskey)); } private: std::string m_nvskey; diff --git a/main/actions/resetnvsaction.cpp b/main/actions/resetnvsaction.cpp index d8b4c90..e69de29 100644 --- a/main/actions/resetnvsaction.cpp +++ b/main/actions/resetnvsaction.cpp @@ -1,11 +0,0 @@ -#include "resetnvsaction.h" - -// system includes -#include -#include - -void ResetNVSAction::triggered() -{ - nvs_flash_erase(); - esp_restart(); -} diff --git a/main/actions/resetnvsaction.h b/main/actions/resetnvsaction.h index 78ddc84..1ac898e 100644 --- a/main/actions/resetnvsaction.h +++ b/main/actions/resetnvsaction.h @@ -1,10 +1,40 @@ #pragma once +// system includes +#include + // 3rdparty lib includes #include +#include +// local includes +#include "newsettings.h" + +template class ResetNVSAction : public virtual espgui::ActionInterface { public: - void triggered() override; + void triggered() override + { + if (reboot) + { + espgui::tft.fillScreen(TFT_BLACK); + espgui::tft.setTextColor(TFT_YELLOW); + + espgui::tft.drawString("Reboot", 5, 5, 4); + + espgui::tft.fillRect(0, 34, espgui::tft.width(), 3, TFT_WHITE); + + espgui::tft.setTextColor(TFT_WHITE); + espgui::tft.drawString("Rebooting now...", 0, 50, 4); + + configs.reset(); + + esp_restart(); + } + else + { + configs.reset(); + } + } }; diff --git a/main/actions/setupactions.cpp b/main/actions/setupactions.cpp new file mode 100644 index 0000000..1bd1488 --- /dev/null +++ b/main/actions/setupactions.cpp @@ -0,0 +1,26 @@ +#include "setupactions.h" + +// 3rdparty lib includes +#include + +// local includes +#include "displays/setup/basic_buttons.h" +#include "displays/setup/calibrate_potis.h" + +PushButtonCalibrateDisplayAction::PushButtonCalibrateDisplayAction(const bool early_return) : + m_early_return{early_return} +{} + +void PushButtonCalibrateDisplayAction::triggered() +{ + espgui::pushScreen(m_early_return); +} + +PushPotiCalibrateDisplayAction::PushPotiCalibrateDisplayAction(const bool early_return) : + m_early_return{early_return} +{} + +void PushPotiCalibrateDisplayAction::triggered() +{ + // espgui::pushScreen(m_early_return); // commented out until implemented +} diff --git a/main/actions/setupactions.h b/main/actions/setupactions.h new file mode 100644 index 0000000..bd3fd43 --- /dev/null +++ b/main/actions/setupactions.h @@ -0,0 +1,24 @@ +#pragma once + +// 3rdparty lib includes +#include + +class PushButtonCalibrateDisplayAction : public virtual espgui::ActionInterface +{ +public: + explicit PushButtonCalibrateDisplayAction(bool early_return); + + void triggered() override; +private: + const bool m_early_return; +}; + +class PushPotiCalibrateDisplayAction : public virtual espgui::ActionInterface +{ +public: + explicit PushPotiCalibrateDisplayAction(bool early_return); + + void triggered() override; +private: + const bool m_early_return; +}; diff --git a/main/cloud.cpp b/main/cloud.cpp index d4238d3..6ff03e9 100644 --- a/main/cloud.cpp +++ b/main/cloud.cpp @@ -590,7 +590,7 @@ void updateCloud() lastCloudSend = now; } - if (!lastHeartbeat || now - *lastHeartbeat >= 1500ms) + if (!lastHeartbeat || now - *lastHeartbeat >= 1500ms && !configs.cloudSettings.cloudKey.value().empty()) { cloudHeartbeat(); lastHeartbeat = now; @@ -743,7 +743,7 @@ void cloudSend() const auto timeout = std::chrono::ceil(espchrono::milliseconds32{configs.cloudSettings.cloudTransmitTimeout.value()}).count(); - if (!hasAnnouncedItself && configs.cloudSettings.cloudEnabled.value()) + if (!hasAnnouncedItself && configs.cloudSettings.cloudEnabled.value() && !configs.cloudSettings.cloudKey.value().empty()) { std::string helloWorld = getLoginMessage(); ESP_LOGW(TAG, "=====> %s", helloWorld.c_str()); diff --git a/main/displays/bobbygraphdisplay.h b/main/displays/bobbygraphdisplay.h index e3dd181..3ca683b 100644 --- a/main/displays/bobbygraphdisplay.h +++ b/main/displays/bobbygraphdisplay.h @@ -38,7 +38,7 @@ void BobbyGraphDisplay::rawButtonReleased(uint8_t button) template void BobbyGraphDisplay::buttonPressed(espgui::Button button) { - //Base::buttonPressed(button); + Base::buttonPressed(button); buttonPressedCommon(button); } diff --git a/main/displays/buttoncalibratedisplay.cpp b/main/displays/buttoncalibratedisplay.cpp deleted file mode 100644 index eb8300d..0000000 --- a/main/displays/buttoncalibratedisplay.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include "buttoncalibratedisplay.h" - -// esp-idf includes -#include - -// 3rdparty lib includes -#include -#include -#include - -// local includes -#include "bobbyerrorhandler.h" -#include "displays/statusdisplay.h" -#include "newsettings.h" - -namespace { -constexpr const char TAG[] = "BUTTON"; -} // namespace - -std::string ButtonCalibrateDisplay::text() const -{ - return "Button calibrate"; -} - -void ButtonCalibrateDisplay::start() -{ - Base::start(); - - m_oldMode = currentMode; - currentMode = &m_mode; - m_lastButton = std::nullopt; - m_status = WaitingLeft; - - m_finished = false; -} - -void ButtonCalibrateDisplay::initScreen() -{ - Base::initScreen(); - - m_labelInstruction.start(); - m_labelLeft.start(); - m_labelRight.start(); - m_labelUp.start(); - m_labelDown.start(); - m_labelEnd.start(); -} - -void ButtonCalibrateDisplay::update() -{ - Base::update(); - - if (m_finished) - { - m_finished = false; - - if (auto result = configs.write_config(configs.dpadMappingLeft, m_leftButton); !result) - { - BobbyErrorHandler{}.errorOccurred(std::move(result).error()); - return; - } - else - { - ESP_LOGI(TAG, "Left button set to %d", m_leftButton); - } - - if (auto result = configs.write_config(configs.dpadMappingRight, m_rightButton); !result) - { - BobbyErrorHandler{}.errorOccurred(std::move(result).error()); - return; - } - else - { - ESP_LOGI(TAG, "Right button set to %d", m_rightButton); - } - if (auto result = configs.write_config(configs.dpadMappingUp, m_upButton); !result) - { - BobbyErrorHandler{}.errorOccurred(std::move(result).error()); - return; - } - else - { - ESP_LOGI(TAG, "Up button set to %d", m_upButton); - } - if (auto result = configs.write_config(configs.dpadMappingDown, m_downButton); !result) - { - BobbyErrorHandler{}.errorOccurred(std::move(result).error()); - return; - } - else - { - ESP_LOGI(TAG, "Down button set to %d", m_downButton); - } - - if (espgui::displayStack.empty()) - { - espgui::switchScreen(); - } - else - espgui::popScreen(); - } -} - -void ButtonCalibrateDisplay::redraw() -{ - Base::redraw(); - - espgui::tft.setTextColor(TFT_WHITE, TFT_BLACK); - - switch (m_status) - { - case WaitingLeft: - if (m_lastButton) - m_labelInstruction.redraw("Press LEFT again"); - else - m_labelInstruction.redraw("Press LEFT"); - break; - case WaitingRight: - if (m_lastButton) - m_labelInstruction.redraw("Press RIGHT again"); - else - m_labelInstruction.redraw("Press RIGHT"); - break; - case WaitingUp: - if (m_lastButton) - m_labelInstruction.redraw("Press UP again"); - else - m_labelInstruction.redraw("Press UP"); - break; - case WaitingDown: - if (m_lastButton) - m_labelInstruction.redraw("Press DOWN again"); - else - m_labelInstruction.redraw("Press DOWN"); - break; - case Finished: - m_labelInstruction.redraw("Finished"); - break; - } - - m_labelLeft.redraw(m_status > WaitingLeft ? fmt::format("Left: {}", m_leftButton) : std::string{}); - m_labelRight.redraw(m_status > WaitingRight ? fmt::format("Right: {}", m_rightButton) : std::string{}); - m_labelUp.redraw(m_status > WaitingUp ? fmt::format("Up: {}", m_upButton) : std::string{}); - m_labelDown.redraw(m_status > WaitingDown ? fmt::format("Down: {}", m_downButton) : std::string{}); - - m_labelEnd.redraw(m_status == Finished ? "Press RIGHT to save" : ""); -} - -void ButtonCalibrateDisplay::stop() -{ - Base::stop(); - - if (currentMode == &m_mode) - { - // to avoid crash after deconstruction - m_mode.stop(); - lastMode = nullptr; - - currentMode = m_oldMode; - } -} - -void ButtonCalibrateDisplay::rawButtonPressed(uint8_t button) -{ - //Base::rawButtonPressed(button); - - if (m_status == Finished) - { - if (button == m_rightButton) - { - ESP_LOGI(TAG, "correct button"); - m_finished = true; - } - else - ESP_LOGI(TAG, "wrong button"); - } - else if (!m_lastButton || *m_lastButton != button) - m_lastButton = button; - else - { - switch (m_status) - { - case WaitingLeft: - m_leftButton = button; - m_lastButton = std::nullopt; - m_status = WaitingRight; - break; - case WaitingRight: - m_rightButton = button; - m_lastButton = std::nullopt; - m_status = WaitingUp; - break; - case WaitingUp: - m_upButton = button; - m_lastButton = std::nullopt; - m_status = WaitingDown; - break; - case WaitingDown: - m_downButton = button; - m_lastButton = std::nullopt; - m_status = Finished; - break; - case Finished:; - } - } -} - -void ButtonCalibrateDisplay::rawButtonReleased(uint8_t button) -{ - //Base::rawButtonReleased(button); -} - -void ButtonCalibrateDisplay::buttonPressed(espgui::Button button) -{ - //Base::buttonPressed(button); -} - -void ButtonCalibrateDisplay::buttonReleased(espgui::Button button) -{ - //Base::buttonReleased(button); -} diff --git a/main/displays/buttoncalibratedisplay.h b/main/displays/buttoncalibratedisplay.h deleted file mode 100644 index 135eac0..0000000 --- a/main/displays/buttoncalibratedisplay.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -// 3rdparty lib includes -#include -#include - -// local includes -#include "globals.h" -#include "modeinterface.h" -#include "modes/ignoreinputmode.h" - -class ButtonCalibrateDisplay : public espgui::DisplayWithTitle -{ - using Base = espgui::DisplayWithTitle; - -public: - ButtonCalibrateDisplay() = default; - explicit ButtonCalibrateDisplay(bool bootup) : m_bootup{bootup} {} - - std::string text() const override; - void start() override; - void initScreen() override; - void update() override; - void redraw() override; - void stop() override; - - void rawButtonPressed(uint8_t button) override; - void rawButtonReleased(uint8_t button) override; - void buttonPressed(espgui::Button button) override; - void buttonReleased(espgui::Button button) override; - -private: - const bool m_bootup{false}; - ModeInterface *m_oldMode; - IgnoreInputMode m_mode{0, bobbycar::protocol::ControlType::FieldOrientedControl, bobbycar::protocol::ControlMode::Torque}; - - std::optional m_lastButton; - - enum { WaitingLeft, WaitingRight, WaitingUp, WaitingDown, Finished } m_status; - - espgui::Label m_labelInstruction{25, 72}; - - espgui::Label m_labelLeft{25, 100}; - espgui::Label m_labelRight{25, 125}; - espgui::Label m_labelUp{25, 150}; - espgui::Label m_labelDown{25, 175}; - - espgui::Label m_labelEnd{25, 225}; - - uint8_t m_leftButton, m_rightButton, m_upButton, m_downButton; - - bool m_finished; -}; diff --git a/main/displays/lockscreen.cpp b/main/displays/lockscreen.cpp index a1d51d5..dbdb7ff 100644 --- a/main/displays/lockscreen.cpp +++ b/main/displays/lockscreen.cpp @@ -106,10 +106,7 @@ void Lockscreen::redraw() { if (isValid1stPin(m_numbers)) { - if (!gas || !brems || *gas > 200.f || *brems > 200.f) - espgui::switchScreen(true); - else - espgui::popScreen(); + espgui::popScreen(); #ifdef LOCKSCREEN_PLUGIN #include LOCKSCREEN_PLUGIN LOCKSCREEN_PLUGIN_FIXES_1 @@ -118,10 +115,7 @@ LOCKSCREEN_PLUGIN_FIXES_1 } else if(isValid2ndPin(m_numbers)) { - if (!gas || !brems || *gas > 200.f || *brems > 200.f) - espgui::switchScreen(true); - else - espgui::popScreen(); + espgui::popScreen(); #ifdef LOCKSCREEN_PLUGIN_FIXES_2 LOCKSCREEN_PLUGIN_FIXES_2 #endif diff --git a/main/displays/menus/batterymenu.cpp b/main/displays/menus/batterymenu.cpp index 40e8f25..809eee9 100644 --- a/main/displays/menus/batterymenu.cpp +++ b/main/displays/menus/batterymenu.cpp @@ -88,7 +88,6 @@ BatteryMenu::BatteryMenu() constructMenuItem, PushScreenAction>>(); constructMenuItem>(&configs.battery.cellType); constructMenuItem, PushScreenAction, StaticMenuItemIcon<&bobbyicons::graph>>>(); - constructMenuItem>(); constructMenuItem>(); constructMenuItem, PushScreenAction, StaticMenuItemIcon<&bobbyicons::settings>>>(); constructMenuItem, PopScreenAction, StaticMenuItemIcon<&espgui::icons::back>>>(); diff --git a/main/displays/menus/boardcomputerhardwaresettingsmenu.cpp b/main/displays/menus/boardcomputerhardwaresettingsmenu.cpp index 5474529..a2c4893 100644 --- a/main/displays/menus/boardcomputerhardwaresettingsmenu.cpp +++ b/main/displays/menus/boardcomputerhardwaresettingsmenu.cpp @@ -11,9 +11,9 @@ // local includes #include "accessors/settingsaccessors.h" +#include "actions/setupactions.h" #include "bobbycheckbox.h" #include "displays/bobbychangevaluedisplay.h" -#include "displays/buttoncalibratedisplay.h" #include "displays/menus/extrabuttoncalibratemenu.h" #include "displays/menus/lockscreensettingsmenu.h" #include "displays/menus/setupquickactionsmenu.h" @@ -192,12 +192,12 @@ using namespace espgui; BoardcomputerHardwareSettingsMenu::BoardcomputerHardwareSettingsMenu() { constructMenuItem, PushScreenAction, StaticMenuItemIcon<&bobbyicons::lock>>>(); - constructMenuItem, PushScreenAction>>(); + constructMenuItem>>(true); constructMenuItem, PushScreenAction>>(); constructMenuItem, PushScreenAction>>(); constructMenuItem, DummyAction>>(); constructMenuItem, DummyAction>>(); - constructMenuItem, PushScreenAction>>(); + constructMenuItem>>(true); #ifdef FEATURE_JOYSTICK constructMenuItem, PushScreenAction>>(); #endif diff --git a/main/displays/menus/debugmenu.cpp b/main/displays/menus/debugmenu.cpp index 55871cd..4eadaf9 100644 --- a/main/displays/menus/debugmenu.cpp +++ b/main/displays/menus/debugmenu.cpp @@ -13,8 +13,10 @@ #include "actions/loadsettingsaction.h" #include "actions/savesettingsaction.h" #include "actions/erasenvsaction.h" +#include "actions/resetnvsaction.h" #include "icons/lock.h" #include "icons/battery.h" +#include "icons/info.h" #include "debugcolorhelpers.h" #include "esptexthelpers.h" #include "accessors/settingsaccessors.h" @@ -57,6 +59,7 @@ constexpr char TEXT_TOGGLECLOUDDEBUG[] = "Cloud Debug"; constexpr char TEXT_LOADSETTINGS[] = "Load settings (old)"; constexpr char TEXT_SAVESETTINGS[] = "Save settings (old)"; constexpr char TEXT_ERASENVS[] = "Erase NVS (old)"; +constexpr char TEXT_RESET_NVS_NEW[] = "Reset NVS (new)"; constexpr char TEXT_DYNAMICMENU[] = "GUI experiments"; constexpr char TEXT_BACK[] = "Back"; } // namespace @@ -99,6 +102,8 @@ DebugMenu::DebugMenu() constructMenuItem, LoadSettingsAction>>(); constructMenuItem, SaveSettingsAction>>(); constructMenuItem, EraseNvsAction>>(); + constructMenuItem>(); + constructMenuItem, ResetNVSAction, StaticMenuItemIcon<&bobbyicons::info>>>(); constructMenuItem, PushScreenAction>>(); constructMenuItem, PopScreenAction, StaticMenuItemIcon<&espgui::icons::back>>>(); } diff --git a/main/displays/menus/graphsmenu.cpp b/main/displays/menus/graphsmenu.cpp index e6c805f..cc2f167 100644 --- a/main/displays/menus/graphsmenu.cpp +++ b/main/displays/menus/graphsmenu.cpp @@ -15,6 +15,8 @@ namespace { constexpr char TEXT_GRAPHS[] = "Graphs"; +constexpr char TEXT_RAW_GAS[] = "Raw Gas"; +constexpr char TEXT_RAW_BREMS[] = "Raw Brems"; constexpr char TEXT_GAS[] = "Gas"; constexpr char TEXT_BREMS[] = "Brems"; constexpr char TEXT_POTIS[] = "Potis"; @@ -32,6 +34,20 @@ constexpr char TEXT_MOTORCURRENTS[] = "Motor currents"; constexpr char TEXT_RSSI[] = "RSSI"; constexpr char TEXT_BACK[] = "Back"; +using RawGasGraphDisplay = espgui::makeComponent< + BobbyGraphDisplay<1>, + espgui::StaticText, + espgui::SingleGraphAccessor, + espgui::ConfirmActionInterface, + espgui::BackActionInterface +>; +using RawBremsGraphDisplay = espgui::makeComponent< + BobbyGraphDisplay<1>, + espgui::StaticText, + espgui::SingleGraphAccessor, + espgui::ConfirmActionInterface, + espgui::BackActionInterface +>; using GasGraphDisplay = espgui::makeComponent< BobbyGraphDisplay<1>, espgui::StaticText, @@ -173,6 +189,8 @@ using RssiGraphDisplay = espgui::makeComponent< GraphsMenu::GraphsMenu() { using namespace espgui; + constructMenuItem, PushScreenAction>>(); + constructMenuItem, PushScreenAction>>(); constructMenuItem, PushScreenAction>>(); constructMenuItem, PushScreenAction>>(); constructMenuItem, PushScreenAction>>(); diff --git a/main/displays/menus/greenpassmenu.cpp b/main/displays/menus/greenpassmenu.cpp index 68a13cd..ede4d38 100644 --- a/main/displays/menus/greenpassmenu.cpp +++ b/main/displays/menus/greenpassmenu.cpp @@ -81,7 +81,7 @@ GreenPassMenu::GreenPassMenu() } else { - constructMenuItem, StaticText>>(std::move(nvs_key)); + constructMenuItem>>(std::move(nvs_key)); } } diff --git a/main/displays/menus/recoverymenu.cpp b/main/displays/menus/recoverymenu.cpp index 1053462..fc621cf 100644 --- a/main/displays/menus/recoverymenu.cpp +++ b/main/displays/menus/recoverymenu.cpp @@ -50,7 +50,7 @@ RecoveryMenu::RecoveryMenu() configs.callForEveryFeature([&](ConfiguredFeatureFlag &feature){ constructMenuItem(feature); }); - constructMenuItem, ResetNVSAction, StaticMenuItemIcon<&bobbyicons::info>>>(); + constructMenuItem, ResetNVSAction, StaticMenuItemIcon<&bobbyicons::info>>>(); constructMenuItem, RebootAction, StaticMenuItemIcon<&bobbyicons::reboot>>>(); } diff --git a/main/displays/menus/statisticsmenu.cpp b/main/displays/menus/statisticsmenu.cpp index af1f445..f7f651d 100644 --- a/main/displays/menus/statisticsmenu.cpp +++ b/main/displays/menus/statisticsmenu.cpp @@ -48,7 +48,7 @@ public: - converted.hours() - converted.minutes() - converted.seconds(); - return fmt::format("Up: {:02d}:{:02d}:{:02d}&s&7.{:03d}", + return fmt::format("Up: {:02d}:{:02d}:{:02d}&s&7.{:01d}", converted.hours().count(), converted.minutes().count(), converted.seconds().count(), @@ -93,7 +93,7 @@ public: - converted.hours() - converted.minutes() - converted.seconds(); - return fmt::format("Drive: {:02d}:{:02d}:{:02d}&s&7.{:03d}", + return fmt::format("Drive: {:02d}:{:02d}:{:02d}&s&7.{:02d}", converted.hours().count(), converted.minutes().count(), converted.seconds().count(), diff --git a/main/displays/potiscalibratedisplay.cpp b/main/displays/potiscalibratedisplay.cpp index 06ff592..0b75e91 100644 --- a/main/displays/potiscalibratedisplay.cpp +++ b/main/displays/potiscalibratedisplay.cpp @@ -16,6 +16,7 @@ namespace { constexpr char TEXT_CALIBRATE[] = "Potis Calibrate"; } // namespace +/* std::string PotisCalibrateDisplay::text() const { return TEXT_CALIBRATE; @@ -320,3 +321,4 @@ void PotisCalibrateDisplay::copyToSettings() configs.write_config(configs.bremsMin, m_bremsMin); configs.write_config(configs.bremsMax, m_bremsMax); } +*/ diff --git a/main/displays/potiscalibratedisplay.h b/main/displays/potiscalibratedisplay.h index 5b4044f..82c6b86 100644 --- a/main/displays/potiscalibratedisplay.h +++ b/main/displays/potiscalibratedisplay.h @@ -16,6 +16,7 @@ #include "modeinterface.h" #include "modes/ignoreinputmode.h" +/* class PotisCalibrateDisplay : public BobbyDisplayWithTitle { using Base = BobbyDisplayWithTitle; @@ -90,3 +91,4 @@ private: ; std::optional m_gas, m_brems; }; +*/ diff --git a/main/displays/qrimportdisplay.cpp b/main/displays/qrimportdisplay.cpp index e69de29..ae6ea26 100644 --- a/main/displays/qrimportdisplay.cpp +++ b/main/displays/qrimportdisplay.cpp @@ -0,0 +1,92 @@ +#include "qrimportdisplay.h" + +namespace { +constexpr const char * const TAG = "qrimport"; +} + +void QrImportDisplay::start() +{ + using namespace espgui; + Base::start(); + + m_statuslabel.start(); + + qrimport::setup_request(); + + if (const auto result = qrimport::start_qr_request(); result) + { + ESP_LOGI(TAG, "started request, waiting for result"); + m_waitingForResult = true; + } + else + { + ESP_LOGE(TAG, "could not start request: %.*s", result.error().size(), result.error().data()); + m_result = tl::make_unexpected(std::move(result).error()); + } +} + +void QrImportDisplay::update() +{ + using namespace espgui; + Base::update(); + + if (!m_waitingForResult) + return; + + if (qrimport::get_request_running()) + return; + + m_waitingForResult = false; + + m_result = qrimport::check_request(); + if (m_result) + { + ESP_LOGI(TAG, "%.*s => %.*s", m_nvs_key.size(), m_nvs_key.data(), m_result->size(), m_result->data()); + if (const auto result = qrimport::set_qr_code(m_nvs_key, *m_result); !result) + m_result = tl::make_unexpected(fmt::format("saving qr failed: {}", esp_err_to_name(result.error()))); + } + else + ESP_LOGW(TAG, "failed %.*s => %.*s", m_nvs_key.size(), m_nvs_key.data(), m_result.error().size(), m_result.error().data()); +} + +void QrImportDisplay::redraw() +{ + using namespace espgui; + Base::redraw(); + + if (m_waitingForResult) + { + tft.setTextColor(TFT_YELLOW, TFT_BLACK); + m_statuslabel.redraw("In progress"); + } + else if (!m_result && !m_result.error().empty()) + { + tft.setTextColor(TFT_RED, TFT_BLACK); + BobbyErrorHandler{}.errorOccurred(fmt::format("Error: {}", m_result.error())); + m_result.error().clear(); + } + else + { + tft.setTextColor(TFT_GREEN, TFT_BLACK); + m_statuslabel.redraw("OK"); + popScreen(); + } +} + +void QrImportDisplay::buttonPressed(espgui::Button button) +{ + using namespace espgui; + Base::buttonPressed(button); + + switch (button) + { + using espgui::Button; + case Button::Left: + if (!m_waitingForResult) + popScreen(); + else + ESP_LOGW(TAG, "tried to leave while waiting for result"); + break; + default:; + } +} diff --git a/main/displays/qrimportdisplay.h b/main/displays/qrimportdisplay.h index dd82e5a..0605397 100644 --- a/main/displays/qrimportdisplay.h +++ b/main/displays/qrimportdisplay.h @@ -1,12 +1,11 @@ #pragma once -constexpr const char * const TAG = "qrimport"; // 3rd party includes #include -#include +#include #include #include -#include +#include // local includes #include "bobbydisplay.h" @@ -14,7 +13,6 @@ constexpr const char * const TAG = "qrimport"; #include "qrimport.h" #include "screenmanager.h" -template class QrImportDisplay : public BobbyDisplay { using Base = BobbyDisplay; @@ -23,92 +21,10 @@ public: explicit QrImportDisplay(const std::string &nvs_key) : m_nvs_key{nvs_key} {} explicit QrImportDisplay(std::string &&nvs_key) : m_nvs_key{std::move(nvs_key)} {} - void start() override - { - using namespace espgui; - Base::start(); - - m_statuslabel.start(); - - qrimport::setup_request(); - - if (const auto result = qrimport::start_qr_request(); result) - { - ESP_LOGI(TAG, "started request, waiting for result"); - m_waitingForResult = true; - } - else - { - ESP_LOGE(TAG, "could not start request: %.*s", result.error().size(), result.error().data()); - m_result = tl::make_unexpected(std::move(result).error()); - } - } - - void update() override - { - using namespace espgui; - Base::update(); - - if (!m_waitingForResult) - return; - - if (qrimport::get_request_running()) - return; - - m_waitingForResult = false; - - m_result = qrimport::check_request(); - if (m_result) - { - ESP_LOGI(TAG, "%.*s => %.*s", m_nvs_key.size(), m_nvs_key.data(), m_result->size(), m_result->data()); - if (const auto result = qrimport::set_qr_code(m_nvs_key, *m_result); !result) - m_result = tl::make_unexpected(fmt::format("saving qr failed: {}", esp_err_to_name(result.error()))); - } - else - ESP_LOGW(TAG, "failed %.*s => %.*s", m_nvs_key.size(), m_nvs_key.data(), m_result.error().size(), m_result.error().data()); - } - - void redraw() override - { - using namespace espgui; - Base::redraw(); - - if (m_waitingForResult) - { - tft.setTextColor(TFT_YELLOW, TFT_BLACK); - m_statuslabel.redraw("In progress"); - } - else if (!m_result && !m_result.error().empty()) - { - tft.setTextColor(TFT_RED, TFT_BLACK); - BobbyErrorHandler{}.errorOccurred(fmt::format("Error: {}", m_result.error())); - m_result.error().clear(); - } - else - { - tft.setTextColor(TFT_GREEN, TFT_BLACK); - m_statuslabel.redraw("OK"); - popScreen(); - } - } - - void buttonPressed(espgui::Button button) override - { - using namespace espgui; - Base::buttonPressed(button); - - switch (button) - { - using espgui::Button; - case Button::Left: - if (!m_waitingForResult) - popScreen(); - else - ESP_LOGW(TAG, "tried to leave while waiting for result"); - break; - default:; - } - } + void start() override; + void update() override; + void redraw() override; + void buttonPressed(espgui::Button button) override; private: bool m_waitingForResult{false}; diff --git a/main/displays/setup/ask_calibrate_other_buttons.cpp b/main/displays/setup/ask_calibrate_other_buttons.cpp new file mode 100644 index 0000000..e641d13 --- /dev/null +++ b/main/displays/setup/ask_calibrate_other_buttons.cpp @@ -0,0 +1,56 @@ +#include "ask_calibrate_other_buttons.h" + +// 3rdparty lib includes +#include + +// local includes +#include "displays/menus/extrabuttoncalibratemenu.h" +#include "displays/setup/final_information.h" +#include "setup.h" +#include "utils.h" + +namespace { +constexpr char const askSetupOtherButtonsText[] = "Do you want to setup other\nbuttons?\n(Blinker, Profile Buttons, etc.)\n\nPress LEFT to skip other buttons.\nPress RIGHT to setup buttons."; +} // namespace + +void SetupAskCalibrateOtherButtonsDisplay::initScreen() +{ + Base::initScreen(); + + drawLargeText(askSetupOtherButtonsText); +} + +void SetupAskCalibrateOtherButtonsDisplay::start() +{ + if (m_next_screen) + { + espgui::switchScreen(); + return; + } + + Base::start(); + + setup::lock(); +} + +void SetupAskCalibrateOtherButtonsDisplay::buttonPressed(espgui::Button button) +{ + switch (button) + { + case espgui::Left: + espgui::switchScreen(); + return; + case espgui::Right: + m_next_screen = true; + espgui::pushScreen(); + return; + default:; + } + + Base::buttonPressed(button); +} + +std::string SetupAskCalibrateOtherButtonsDisplay::text() const +{ + return "Other Buttons"; +} diff --git a/main/displays/setup/ask_calibrate_other_buttons.h b/main/displays/setup/ask_calibrate_other_buttons.h new file mode 100644 index 0000000..e1a0a3c --- /dev/null +++ b/main/displays/setup/ask_calibrate_other_buttons.h @@ -0,0 +1,18 @@ +#pragma once + +// local includes +#include "displays/bobbydisplaywithtitle.h" + +class SetupAskCalibrateOtherButtonsDisplay : public virtual BobbyDisplayWithTitle +{ + using Base = BobbyDisplayWithTitle; +public: + void initScreen() override; + void start() override; + + void buttonPressed(espgui::Button button) override; + + [[nodiscard]] std::string text() const override; +private: + bool m_next_screen{false}; +}; diff --git a/main/displays/setup/ask_setup_clouds.cpp b/main/displays/setup/ask_setup_clouds.cpp new file mode 100644 index 0000000..383c53b --- /dev/null +++ b/main/displays/setup/ask_setup_clouds.cpp @@ -0,0 +1,53 @@ +#include "ask_setup_clouds.h" + +// 3rdparty lib includes +#include + +// local includes +#include "displays/setup/ask_calibrate_other_buttons.h" +#include "displays/setup/setup_cloud.h" +#include "setup.h" +#include "taskmanager.h" +#include "utils.h" + +namespace { +constexpr char const askCloudText[] = "Do you want to setup cloud?\nWith this, you will be able\nto send data to graphana,\nremote control things like Buttons\nand NVS and more!\n\nPress LEFT to skip cloud.\nPress RIGHT to setup cloud."; +} // namespace + +void SetupAskSetupCloudsDisplay::initScreen() +{ + Base::initScreen(); + + drawLargeText(askCloudText); +} + +void SetupAskSetupCloudsDisplay::start() +{ + Base::start(); + + setup::lock(); +} + +void SetupAskSetupCloudsDisplay::buttonPressed(espgui::Button button) +{ + switch (button) + { + case espgui::Left: // skip cloud setup + espgui::switchScreen(); + return; + case espgui::Right: // enter cloud setup + configs.write_config(configs.feature.cloud.isEnabled, true); + configs.write_config(configs.feature.udpcloud.isEnabled, true); + + reload_tasks(); + espgui::switchScreen(); + default:; + } + + Base::buttonPressed(button); +} + +std::string SetupAskSetupCloudsDisplay::text() const +{ + return "Cloud Setup"; +} diff --git a/main/displays/setup/ask_setup_clouds.h b/main/displays/setup/ask_setup_clouds.h new file mode 100644 index 0000000..0a80598 --- /dev/null +++ b/main/displays/setup/ask_setup_clouds.h @@ -0,0 +1,16 @@ +#pragma once + +// local includes +#include "displays/bobbydisplaywithtitle.h" + +class SetupAskSetupCloudsDisplay : public virtual BobbyDisplayWithTitle +{ + using Base = BobbyDisplayWithTitle; +public: + void initScreen() override; + void start() override; + + void buttonPressed(espgui::Button button) override; + + [[nodiscard]] std::string text() const override; +}; diff --git a/main/displays/setup/basic_buttons.cpp b/main/displays/setup/basic_buttons.cpp new file mode 100644 index 0000000..5c47178 --- /dev/null +++ b/main/displays/setup/basic_buttons.cpp @@ -0,0 +1,230 @@ +#include "basic_buttons.h" + +// system includes +#include + +// 3rdparty lib includes +#include +#include + +// local includes +#include "bobbyerrorhandler.h" +#include "displays/setup/calibrate_potis.h" +#include "setup.h" +#include "utils.h" + +namespace { +constexpr char const buttonText[] = "Please press the highlighted\n buttons!"; +constexpr const char * const TAG = "SETUP-BUTTONS"; +} + +void SetupBasicButtonsDisplay::initScreen() +{ + Base::initScreen(); + + drawLargeText(buttonText); + drawButtons(m_button_cal_status); +} + +void SetupBasicButtonsDisplay::start() +{ + Base::start(); + + setup::lock(); + + m_lastButton = std::nullopt; + m_button_cal_status = LEFT; + m_button_cal_finished = false; +} + +void SetupBasicButtonsDisplay::update() +{ + if (m_button_cal_finished) + { + m_button_cal_finished = false; + saveButtons(); + + if (m_early_return) + { + setup::unlock(); + espgui::popScreen(); + } + else + { + espgui::switchScreen(); + } + } + + Base::update(); +} + +void SetupBasicButtonsDisplay::redraw() +{ + Base::redraw(); +} + +void SetupBasicButtonsDisplay::rawButtonPressed(uint8_t button) +{ + if (m_button_cal_status == FINISHED) + { + if (button == m_rightButton) + { + m_button_cal_finished = true; + } + } + else if (!m_lastButton || *m_lastButton != button) + m_lastButton = button; + else + { + switch (m_button_cal_status) + { + case LEFT: + m_leftButton = button; + m_lastButton = std::nullopt; + m_button_cal_status = RIGHT; + break; + case RIGHT: + m_rightButton = button; + m_lastButton = std::nullopt; + m_button_cal_status = UP; + break; + case UP: + m_upButton = button; + m_lastButton = std::nullopt; + m_button_cal_status = DOWN; + break; + case DOWN: + m_downButton = button; + m_lastButton = std::nullopt; + m_button_cal_status = FINISHED; + break; + default:; + } + } + + drawButtons(m_button_cal_status); + + Base::rawButtonPressed(button); +} + +void SetupBasicButtonsDisplay::rawButtonReleased(uint8_t button) +{ + // Base::rawButtonReleased(button); +} + +void SetupBasicButtonsDisplay::buttonPressed(espgui::Button button) +{ + // Base::buttonPressed(button); +} + +void SetupBasicButtonsDisplay::buttonReleased(espgui::Button button) +{ + // Base::buttonReleased(button); +} + +std::string SetupBasicButtonsDisplay::text() const +{ + return "Calibrate Buttons"; +} + +void SetupBasicButtonsDisplay::saveButtons() const +{ + if (auto result = configs.write_config(configs.dpadMappingLeft, m_leftButton); !result) + { + BobbyErrorHandler{}.errorOccurred(std::move(result).error()); + return; + } + else + { + ESP_LOGI(TAG, "Left button set to %d", m_leftButton); + } + + if (auto result = configs.write_config(configs.dpadMappingRight, m_rightButton); !result) + { + BobbyErrorHandler{}.errorOccurred(std::move(result).error()); + return; + } + else + { + ESP_LOGI(TAG, "Right button set to %d", m_rightButton); + } + if (auto result = configs.write_config(configs.dpadMappingUp, m_upButton); !result) + { + BobbyErrorHandler{}.errorOccurred(std::move(result).error()); + return; + } + else + { + ESP_LOGI(TAG, "Up button set to %d", m_upButton); + } + if (auto result = configs.write_config(configs.dpadMappingDown, m_downButton); !result) + { + BobbyErrorHandler{}.errorOccurred(std::move(result).error()); + return; + } + else + { + ESP_LOGI(TAG, "Down button set to %d", m_downButton); + } +} + +void SetupBasicButtonsDisplay::drawButtons(const SetupBasicButtonsDisplay::CurrentButton button) +{ + using namespace espgui; + + const int16_t x_mid = tft.width() / 2; + const int16_t y_mid = tft.height() / 2; + + const auto offset = 40; + const auto radius = 15; + const auto subtract = 2; + + const auto up_x = x_mid; + const auto up_y = y_mid - offset; + + const auto down_x = x_mid; + const auto down_y = y_mid + offset; + + const auto left_x = x_mid - offset; + const auto left_y = y_mid; + + const auto right_x = x_mid + offset; + const auto right_y = y_mid; + + tft.fillCircle(up_x, up_y, radius-subtract, TFT_BLACK); + tft.fillCircle(down_x, down_y, radius-subtract, TFT_BLACK); + tft.fillCircle(left_x, left_y, radius-subtract, TFT_BLACK); + tft.fillCircle(right_x, right_y, radius-subtract, TFT_BLACK); + + tft.drawCircle(up_x, up_y, radius, TFT_WHITE); + tft.drawCircle(down_x, down_y, radius, TFT_WHITE); + tft.drawCircle(left_x, left_y, radius, TFT_WHITE); + tft.drawCircle(right_x, right_y, radius, TFT_WHITE); + + if (m_button_cal_finished) + { + return; + } + + switch(button) + { + case UP: + tft.fillCircle(up_x, up_y, radius-subtract, m_lastButton ? TFT_YELLOW : TFT_WHITE); + break; + case DOWN: + tft.fillCircle(down_x, down_y, radius-subtract, m_lastButton ? TFT_YELLOW : TFT_WHITE); + break; + case LEFT: + tft.fillCircle(left_x, left_y, radius-subtract, m_lastButton ? TFT_YELLOW : TFT_WHITE); + break; + case RIGHT: + tft.fillCircle(right_x, right_y, radius-subtract, m_lastButton ? TFT_YELLOW : TFT_WHITE); + break; + default:; + } + + if (m_button_cal_status == FINISHED) + { + tft.fillCircle(right_x, right_y, radius-subtract, TFT_GREEN); + } +} diff --git a/main/displays/setup/basic_buttons.h b/main/displays/setup/basic_buttons.h new file mode 100644 index 0000000..88853fa --- /dev/null +++ b/main/displays/setup/basic_buttons.h @@ -0,0 +1,51 @@ +#pragma once + +// system includes +#include + +// local includes +#include "displays/bobbydisplaywithtitle.h" + +class SetupBasicButtonsDisplay : public virtual BobbyDisplayWithTitle +{ + using Base = BobbyDisplayWithTitle; + + enum CurrentButton : int8_t + { + UP, + DOWN, + LEFT, + RIGHT, + FINISHED + }; // button calibration +public: + explicit SetupBasicButtonsDisplay(bool early_return = false) : + m_early_return{early_return} + {} + + void initScreen() override; + void start() override; + void update() override; + void redraw() override; + + void rawButtonPressed(uint8_t button) override; + void rawButtonReleased(uint8_t button) override; + void buttonPressed(espgui::Button button) override; + void buttonReleased(espgui::Button button) override; + + [[nodiscard]] std::string text() const override; +private: + const bool m_early_return; + + std::optional m_lastButton; + + CurrentButton m_button_cal_status; + + uint8_t m_leftButton, m_rightButton, m_upButton, m_downButton; + + bool m_button_cal_finished; + + void saveButtons() const; + + void drawButtons(CurrentButton button); +}; diff --git a/main/displays/setup/calibrate_potis.cpp b/main/displays/setup/calibrate_potis.cpp new file mode 100644 index 0000000..435e3ea --- /dev/null +++ b/main/displays/setup/calibrate_potis.cpp @@ -0,0 +1,309 @@ +#include "calibrate_potis.h" + +// 3rdparty lib includes +#include +#include +#include + +// local includes +#include "displays/setup/ask_setup_clouds.h" +#include "globals.h" +#include "setup.h" + +using namespace espgui; + +void SetupCalibratePotisDisplay::initScreen() +{ + Base::initScreen(); + + tft.setTextFont(4); + tft.setTextColor(TFT_WHITE, TFT_BLACK); + + tft.drawString("gas:", 25, 47); + tft.drawString("brems:", 25, 147); + + for (auto &label : m_labels) + label.start(); + + for (auto &progressBar : m_progressBars) + progressBar.start(); + + m_renderedButton = -1; +} + +void SetupCalibratePotisDisplay::start() +{ + Base::start(); + + setup::lock(); + + m_selectedButton = 0; + m_status = Status::Begin; + copyFromSettings(); + m_gas = std::nullopt; + m_brems = std::nullopt; +} +void SetupCalibratePotisDisplay::update() +{ + Base::update(); + + if (raw_gas) + m_gas = cpputils::mapValueClamped(*raw_gas, m_gasMin, m_gasMax, 0.f, 1000.f); + else + m_gas = std::nullopt; + + if (raw_brems) + m_brems = cpputils::mapValueClamped(*raw_brems, m_bremsMin, m_bremsMax, 0.f, 1000.f); + else + m_brems = std::nullopt; +} + +void SetupCalibratePotisDisplay::redraw() +{ + Base::redraw(); + + m_labels[0].redraw(m_gas ? fmt::format("{:.02f}", *m_gas) : "?"); + m_labels[1].redraw(raw_gas ? std::to_string(*raw_gas) : "?"); + if (m_status == Status::GasMin) + espgui::tft.setTextColor(TFT_RED, TFT_BLACK); + m_labels[2].redraw(std::to_string(m_gasMin)); + if (m_status == Status::GasMin) + espgui::tft.setTextColor(TFT_WHITE, TFT_BLACK); + if (m_status == Status::GasMax) + espgui::tft.setTextColor(TFT_RED, TFT_BLACK); + m_labels[3].redraw(std::to_string(m_gasMax)); + if (m_status == Status::GasMax) + espgui::tft.setTextColor(TFT_WHITE, TFT_BLACK); + + m_progressBars[0].redraw(m_gas ? *m_gas : 0); + + m_labels[4].redraw(m_brems ? fmt::format("{:.02f}", *m_brems) : "?"); + m_labels[5].redraw(raw_brems ? std::to_string(*raw_brems) : "?"); + if (m_status == Status::BremsMin) + espgui::tft.setTextColor(TFT_RED, TFT_BLACK); + m_labels[6].redraw(std::to_string(m_bremsMin)); + if (m_status == Status::BremsMin) + espgui::tft.setTextColor(TFT_WHITE, TFT_BLACK); + if (m_status == Status::BremsMax) + espgui::tft.setTextColor(TFT_RED, TFT_BLACK); + m_labels[7].redraw(std::to_string(m_bremsMax)); + if (m_status == Status::BremsMax) + espgui::tft.setTextColor(TFT_WHITE, TFT_BLACK); + + m_progressBars[1].redraw(m_brems ? *m_brems : 0); + + m_labels[8].redraw([&](){ + switch (m_status) + { + case Status::Begin: return "Start calibrating?"; +#ifdef FEATURE_JOYSTICK + case Status::Mitte: return "Release joystick"; +#endif + case Status::GasMin: return "Release gas"; + case Status::GasMax: return "Press gas"; + case Status::BremsMin: return "Release brems"; + case Status::BremsMax: return "Press brems"; + case Status::Confirm: return "Verify"; + } + __builtin_unreachable(); + }()); + + { + const auto failed = !m_gas || !m_brems || (m_status == Status::Confirm && (*m_gas > 100 || *m_brems > 100)); + const auto color = failed ? TFT_DARKGREY : TFT_WHITE; + espgui::tft.setTextColor(color, TFT_BLACK); + m_labels[9].redraw([&](){ + switch (m_status) + { + case Status::Begin: return "Yes"; +#ifdef FEATURE_JOYSTICK + case Status::Mitte: +#endif + case Status::GasMin: + case Status::GasMax: + case Status::BremsMin: + case Status::BremsMax: return "Next"; + case Status::Confirm: return "Save"; + } + __builtin_unreachable(); + }()); + + if (m_selectedButton != m_renderedButton && (m_selectedButton == 0 || m_renderedButton == 0)) + espgui::tft.drawRect(3, 275, 100, 27, m_selectedButton == 0 ? color : TFT_BLACK); + } + + espgui::tft.setTextColor(TFT_WHITE, TFT_BLACK); + m_labels[10].redraw([&](){ + switch (m_status) + { + case Status::Begin: return "No"; +#ifdef FEATURE_JOYSTICK + case Status::Mitte: +#endif + case Status::GasMin: + case Status::GasMax: + case Status::BremsMin: + case Status::BremsMax: + case Status::Confirm: return "Abort"; + } + __builtin_unreachable(); + }()); + + if (m_selectedButton != m_renderedButton && (m_selectedButton == 1 || m_renderedButton == 1)) + espgui::tft.drawRect(123, 275, 100, 27, m_selectedButton == 1 ? TFT_WHITE : TFT_BLACK); + + m_renderedButton = m_selectedButton; +} + +void SetupCalibratePotisDisplay::stop() +{ + if (m_early_return) + { + setup::unlock(); + } + + Base::stop(); +} + +void SetupCalibratePotisDisplay::buttonPressed(espgui::Button button) +{ + Base::buttonPressed(button); + + switch (button) + { + using espgui::Button; + case Button::Up: + m_selectedButton--; + + if (m_selectedButton < 0) + m_selectedButton = 1; + + break; + case Button::Down: + m_selectedButton++; + + if (m_selectedButton > 1) + m_selectedButton = 0; + + break; + case Button::Left: + back: + switch (m_status) + { + case Status::Begin: + if (m_early_return) + espgui::popScreen(); + else + espgui::switchScreen(); + break; +#ifdef FEATURE_JOYSTICK + case Status::Mitte: +#endif + case Status::GasMin: + case Status::GasMax: + case Status::BremsMin: + case Status::BremsMax: + case Status::Confirm: + m_selectedButton = 0; + m_status = Status::Begin; + copyFromSettings(); + } + + break; + case Button::Right: + switch (m_selectedButton) + { + case 0: // left button pressed + if (!raw_gas || !raw_brems || !m_gas || !m_brems) + return; + + switch (m_status) + { +#ifndef FEATURE_JOYSTICK + case Status::Begin: + m_status = Status::GasMin; + break; +#else + case Status::Begin: + m_status = Status::Mitte; + break; + + case Status::Mitte: + m_gasMitte = *raw_gas; + m_bremsMitte = *raw_brems; + m_status = Status::GasMin; + break; +#endif + case Status::GasMin: + m_gasMin = *raw_gas; + m_status = Status::GasMax; + break; + case Status::GasMax: + m_gasMax = *raw_gas; + m_status = Status::BremsMin; + { + const auto dead = (m_gasMax - m_gasMin)/20; + m_gasMin += dead; + m_gasMax -= dead; + } + break; + case Status::BremsMin: + m_bremsMin = *raw_brems; + m_status = Status::BremsMax; + break; + case Status::BremsMax: + m_bremsMax = *raw_brems; + m_status = Status::Confirm; + { + const auto dead = (m_bremsMax - m_bremsMin)/20; + m_bremsMin += dead; + m_bremsMax -= dead; + } + break; + case Status::Confirm: + if (*m_gas > 100 || *m_brems > 100) + return; + + copyToSettings(); + + if (m_early_return) + espgui::popScreen(); + else + espgui::switchScreen(); + } + break; + case 1: // right button pressed + goto back; + } + break; + } +}; + +std::string SetupCalibratePotisDisplay::text() const +{ + return "Calibrate Potis"; +} + +void SetupCalibratePotisDisplay::copyFromSettings() +{ +#ifdef FEATURE_JOYSTICK + m_gasMitte = configs.gasMitte.value(); + m_bremsMitte = configs.bremsMitte.value(); +#endif + m_gasMin = configs.gasMin.value(); + m_gasMax = configs.gasMax.value(); + m_bremsMin = configs.bremsMin.value(); + m_bremsMax = configs.bremsMax.value(); +} + +void SetupCalibratePotisDisplay::copyToSettings() const +{ +#ifdef FEATURE_JOYSTICK + configs.write_config(configs.gasMitte, m_gasMitte); + configs.write_config(configs.bremsMitte, m_bremsMitte); +#endif + configs.write_config(configs.gasMin, m_gasMin); + configs.write_config(configs.gasMax, m_gasMax); + configs.write_config(configs.bremsMin, m_bremsMin); + configs.write_config(configs.bremsMax, m_bremsMax); +} diff --git a/main/displays/setup/calibrate_potis.h b/main/displays/setup/calibrate_potis.h new file mode 100644 index 0000000..059238e --- /dev/null +++ b/main/displays/setup/calibrate_potis.h @@ -0,0 +1,86 @@ +#pragma once + +// system includes +#include +#include + +// 3rdparty lib includes +#include +#include + +// local includes +#include "displays/bobbydisplaywithtitle.h" + +class SetupCalibratePotisDisplay : public virtual BobbyDisplayWithTitle +{ + using Base = BobbyDisplayWithTitle; +public: + explicit SetupCalibratePotisDisplay(bool early_return = false) : + m_early_return{early_return} + {} + + void initScreen() override; + void start() override; + void update() override; + void redraw() override; + void stop() override; + + void buttonPressed(espgui::Button button) override; + + [[nodiscard]] std::string text() const override; + +private: + void copyFromSettings(); + void copyToSettings() const; + + const bool m_early_return; + + std::array m_labels {{ + espgui::Label{25, 72}, // 100, 23 + espgui::Label{145, 72}, // 100, 23 + espgui::Label{25, 97}, // 100, 23 + espgui::Label{145, 97}, // 100, 23 + + espgui::Label{25, 172}, // 100, 23 + espgui::Label{145, 172}, // 100, 23 + espgui::Label{25, 197}, // 100, 23 + espgui::Label{145, 197}, // 100, 23 + + espgui::Label{25, 247}, // 190, 23 + + espgui::Label{25, 277}, // 100, 23 + espgui::Label{145, 277}, // 100, 23 + }}; + + std::array m_progressBars {{ + espgui::ProgressBar{20, 129, 200, 10, 0, 1000}, + espgui::ProgressBar{20, 229, 200, 10, 0, 1000} + }}; + + enum Status { + Begin, +#ifdef FEATURE_JOYSTICK + Mitte, +#endif + GasMin, + GasMax, + BremsMin, + BremsMax, + Confirm + }; + + int8_t m_selectedButton, m_renderedButton; + + Status m_status; + int16_t + m_gasMin, + m_gasMax, + m_bremsMin, + m_bremsMax +#ifdef FEATURE_JOYSTICK + ,m_gasMitte + ,m_bremsMitte +#endif + ; + std::optional m_gas, m_brems; +}; diff --git a/main/displays/setup/final_information.cpp b/main/displays/setup/final_information.cpp new file mode 100644 index 0000000..d934f09 --- /dev/null +++ b/main/displays/setup/final_information.cpp @@ -0,0 +1,58 @@ +#include "final_information.h" + +// 3rdparty lib includes +#include + +// local includes +#include "displays/menus/extrabuttoncalibratemenu.h" +#include "displays/statusdisplay.h" +#include "newsettings.h" +#include "setup.h" +#include "utils.h" + +using namespace std::chrono_literals; + +namespace { +constexpr char const finalInformationText[] = "Setup is done!\nIf cloud is setup, go to\nhttps://service.bobbycar.cloud/\nand register this bobbycar!\nThis is also used\nto setup udp cloud.\nPress any button to exit."; +} // namespace + +void SetupFinalInformationDisplay::initScreen() +{ + Base::initScreen(); + + drawLargeText(finalInformationText); +} + +void SetupFinalInformationDisplay::start() +{ + Base::start(); + + setup::lock(); +} + +void SetupFinalInformationDisplay::stop() +{ + Base::stop(); + + setup::unlock(); +} + +void SetupFinalInformationDisplay::buttonPressed(espgui::Button button) +{ + configs.write_config(configs.boardcomputerHardware.setupFinished, true); + if (espgui::displayStack.empty()) + { + espgui::switchScreen(); + } + else + { + espgui::popScreen(); + } + + Base::buttonPressed(button); +} + +std::string SetupFinalInformationDisplay::text() const +{ + return "All done!"; +} diff --git a/main/displays/setup/final_information.h b/main/displays/setup/final_information.h new file mode 100644 index 0000000..a56303a --- /dev/null +++ b/main/displays/setup/final_information.h @@ -0,0 +1,20 @@ +#pragma once + +// 3rdparty lib includes +#include + +// local includes +#include "displays/bobbydisplaywithtitle.h" + +class SetupFinalInformationDisplay : public virtual BobbyDisplayWithTitle +{ + using Base = BobbyDisplayWithTitle; +public: + void initScreen() override; + void start() override; + void stop() override; + + void buttonPressed(espgui::Button button) override; + + [[nodiscard]] std::string text() const override; +}; diff --git a/main/displays/setup/information.cpp b/main/displays/setup/information.cpp new file mode 100644 index 0000000..53fec57 --- /dev/null +++ b/main/displays/setup/information.cpp @@ -0,0 +1,64 @@ +#include "information.h" + +// 3rdparty lib includes +#include + +// local includes +#include "displays/setup/basic_buttons.h" +#include "setup.h" +#include "utils.h" + +using namespace std::chrono_literals; + +namespace { +constexpr char const informationText[] = "Congratulations on your new\nbobbycar! This guide will help\nyou through initial setup,\ncalibrate everything and\nget you ready!"; +} // namespace + +void SetupInformationDisplay::initScreen() +{ + Base::initScreen(); + + m_init_text_progressbar.start(); + + drawLargeText(informationText); +} + +void SetupInformationDisplay::start() +{ + Base::start(); + + setup::lock(); + + m_menu_opened_timestamp = espchrono::millis_clock::now(); +} + +void SetupInformationDisplay::update() +{ + if (espchrono::ago(m_menu_opened_timestamp) > 5s) + { + espgui::switchScreen(); + } + + Base::update(); +} + +void SetupInformationDisplay::redraw() +{ + m_init_text_progressbar.redraw(espchrono::ago(m_menu_opened_timestamp) / 50ms); + + Base::redraw(); +} + +void SetupInformationDisplay::buttonPressed(espgui::Button button) +{ + if (espchrono::ago(m_menu_opened_timestamp) > 500ms) + { + espgui::switchScreen(); + } +} + +[[nodiscard]] std::string SetupInformationDisplay::text() const +{ + return "First Steps"; +} + diff --git a/main/displays/setup/information.h b/main/displays/setup/information.h new file mode 100644 index 0000000..fe7e09f --- /dev/null +++ b/main/displays/setup/information.h @@ -0,0 +1,26 @@ +#pragma once + +// 3rdparty lib includes +#include +#include +#include + +// local includes +#include "displays/bobbydisplaywithtitle.h" + +class SetupInformationDisplay : public virtual BobbyDisplayWithTitle +{ + using Base = BobbyDisplayWithTitle; +public: + void initScreen() override; + void start() override; + void update() override; + void redraw() override; + + void buttonPressed(espgui::Button button) override; + + [[nodiscard]] std::string text() const override; +private: + espchrono::millis_clock::time_point m_menu_opened_timestamp; + espgui::ProgressBar m_init_text_progressbar{10, espgui::tft.height()/2, espgui::tft.width()-20, 30, 0, 100}; +}; diff --git a/main/displays/setup/setup_cloud.cpp b/main/displays/setup/setup_cloud.cpp new file mode 100644 index 0000000..e7885d3 --- /dev/null +++ b/main/displays/setup/setup_cloud.cpp @@ -0,0 +1,103 @@ +#include "setup_cloud.h" + +// 3rdparty lib includes +#include +#include +#include + +// local includes +#include "accessors/settingsaccessors.h" +#include "bobbycheckbox.h" +#include "displays/bobbychangevaluedisplay.h" +#include "displays/setup/ask_calibrate_other_buttons.h" +#include "setup.h" + +using namespace espgui; + +namespace { +constexpr const char TEXT_ENABLE_CLOUD[] = "Enable Cloud"; +constexpr const char TEXT_CLOUD_USERNAME[] = "Cloud Username"; +constexpr const char TEXT_CLOUD_URL[] = "Cloud URL"; +constexpr const char TEXT_CLOUD_KEY[] = "Cloud Key"; +constexpr const char TEXT_DONE[] = "Done"; + +using CloudUsernameChangeScreen = espgui::makeComponent< + BobbyChangeValueDisplay, + espgui::StaticText, + UsernameAccessor, + espgui::ConfirmActionInterface, + espgui::BackActionInterface +>; + +using CloudURLChangeScreen = espgui::makeComponent< + BobbyChangeValueDisplay, + espgui::StaticText, + CloudURLAccessor, + espgui::ConfirmActionInterface, + espgui::BackActionInterface +>; + +using CloudKeyChangeScreen = espgui::makeComponent< + BobbyChangeValueDisplay, + espgui::StaticText, + CloudKeyAccessor, + espgui::ConfirmActionInterface, + espgui::BackActionInterface +>; // cloud setup + +template +class CloudSetupFinishedAction : public virtual ActionInterface +{ +public: + void triggered() override + { + if (early_return) + { + espgui::popScreen(); + } + else + { + espgui::switchScreen(); + } + } +}; +} // namespace + +SetupCloudDisplay::SetupCloudDisplay(const bool early_return) : m_early_return{early_return} +{ + constructMenuItem, BobbyCheckbox, CloudEnabledAccessor>>(); + constructMenuItem, PushScreenAction>>(); + constructMenuItem, PushScreenAction>>(); + constructMenuItem, PushScreenAction>>(); + + if (early_return) + constructMenuItem, CloudSetupFinishedAction>>(); + else + constructMenuItem, CloudSetupFinishedAction>>(); +} + +void SetupCloudDisplay::start() +{ + Base::start(); + + setup::lock(); +} + +void SetupCloudDisplay::stop() +{ + if (m_early_return) + { + setup::unlock(); + } + + Base::stop(); +} + +void SetupCloudDisplay::back() +{} + +std::string SetupCloudDisplay::text() const +{ + return "WebSocket Cloud"; +} + diff --git a/main/displays/setup/setup_cloud.h b/main/displays/setup/setup_cloud.h new file mode 100644 index 0000000..3db4996 --- /dev/null +++ b/main/displays/setup/setup_cloud.h @@ -0,0 +1,20 @@ +#pragma once + +// local includes +#include "displays/bobbymenudisplay.h" + +class SetupCloudDisplay : public virtual BobbyMenuDisplay +{ + using Base = BobbyMenuDisplay; +public: + explicit SetupCloudDisplay(bool early_return = false); + + void start() override; + void stop() override; + + void back() override; + + [[nodiscard]] std::string text() const override; +private: + const bool m_early_return; +}; diff --git a/main/main.cpp b/main/main.cpp index ed1272a..0d2ab78 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -31,14 +31,20 @@ using namespace std::chrono_literals; #else #include "modes/defaultmode.h" #endif -#include "displays/buttoncalibratedisplay.h" #include "displays/lockscreen.h" #include "displays/menus/recoverymenu.h" #include "displays/potiscalibratedisplay.h" +#include "displays/setup/information.h" +#include "displays/setup/basic_buttons.h" +#include "displays/setup/calibrate_potis.h" #include "displays/statusdisplay.h" #include "newsettings.h" #include "taskmanager.h" +#define BOOT_PROGRESS(s) \ + bootLabel.redraw(s); \ + ESP_LOGI("BOOT", "%s", s); + namespace { espchrono::millis_clock::time_point lastStatsPush; std::optional lastStatsUpdate; @@ -94,7 +100,7 @@ extern "C" void app_main() recovery = true; } - bootLabel.redraw("settings"); + BOOT_PROGRESS("settings"); if (const auto result = configs.init("bobbycar"); result != ESP_OK) ESP_LOGE(TAG, "config_init_settings() failed with %s", esp_err_to_name(result)); @@ -117,7 +123,7 @@ extern "C" void app_main() { if (checkEnabledByName(task.name())) { - bootLabel.redraw(task.name()); + BOOT_PROGRESS(task.name()); task.setup(false); } } @@ -128,33 +134,43 @@ extern "C" void app_main() currentMode = &modes::defaultMode; #endif - bootLabel.redraw("switchScreen"); + BOOT_PROGRESS("switchScreen"); - if (configs.dpadMappingLeft.value() == INPUT_MAPPING_NONE || - configs.dpadMappingRight.value() == INPUT_MAPPING_NONE || - configs.dpadMappingUp.value() == INPUT_MAPPING_NONE || - configs.dpadMappingDown.value() == INPUT_MAPPING_NONE) + if (const auto result = checkIfInCalibration(); result) { - espgui::switchScreen(true); + switch(*result) + { + case SetupStep::INFORMATION: + BOOT_PROGRESS("Calibtration"); + espgui::switchScreen(); + break; + case SetupStep::BASIC_BUTTONS: + BOOT_PROGRESS("Calibtration"); + espgui::switchScreen(true); + break; + case SetupStep::CALIBRATE_POTIS: + espgui::switchScreen(true); + break; + default:; + } } else if (configs.lockscreen.keepLockedAfterReboot.value() && configs.lockscreen.locked.value()) { + BOOT_PROGRESS("Locked"); espgui::switchScreen(); espgui::pushScreen(); } else { - if (!gas || !brems || *gas > 200.f || *brems > 200.f) - espgui::switchScreen(true); - else - { - espgui::switchScreen(); - } + BOOT_PROGRESS("StatusDisplay") + espgui::switchScreen(); } esp_chip_info(&chip_info); esp_pm_get_configuration(&pm_config); + ESP_LOGI(TAG, "Entering main loop..."); + while (true) { const auto now = espchrono::millis_clock::now(); diff --git a/main/newsettings.h b/main/newsettings.h index 7b1186d..cb5f37e 100644 --- a/main/newsettings.h +++ b/main/newsettings.h @@ -364,7 +364,8 @@ public: ConfigWrapperLegacy cloudSendRate {1, DoReset, {}, "cloudSendRate" }; ConfigWrapperLegacy udpSendRateMs {65, DoReset, {}, "udpSendRate" }; } timersSettings; - ConfigWrapperLegacy flipScreen {false, DoReset, {}, "flipScreen" }; + ConfigWrapperLegacy flipScreen {false, NoReset, {}, "flipScreen" }; + ConfigWrapperLegacy setupFinished {false, DoReset, {}, "setupFinished" }; } boardcomputerHardware; struct { @@ -487,6 +488,8 @@ public: ConfigWrapperLegacy bleFenceEnabled {false, DoReset, {}, "bleFenceEnabled" }; } bleSettings; + ConfigWrapperLegacy setupDone {false, DoReset, {}, "setupDone" }; + #define NEW_SETTINGS(x) \ x(baseMacAddressOverride) \ x(hostname) \ @@ -710,9 +713,10 @@ public: x(boardcomputerHardware.timersSettings.statsUpdateRate) \ x(boardcomputerHardware.timersSettings.cloudCollectRate) \ x(boardcomputerHardware.timersSettings.cloudSendRate) \ - x(boardcomputerHardware.timersSettings.udpSendRateMs) \ + x(boardcomputerHardware.timersSettings.udpSendRateMs) \ \ x(boardcomputerHardware.flipScreen) \ + x(boardcomputerHardware.setupFinished) \ \ x(cloudSettings.cloudEnabled) \ x(cloudSettings.cloudTransmitTimeout) \ diff --git a/main/potis.cpp b/main/potis.cpp index 23aed58..e77a1ab 100644 --- a/main/potis.cpp +++ b/main/potis.cpp @@ -73,6 +73,18 @@ void readPotis() // sum += analogRead(pin); // return sum / sampleCount; // }; + constexpr auto sampleMultipleTimes = [](adc_channel_t channel){ + int sum{}; + const auto sampleCount = configs.sampleCount.value(); + for (int i = 0; i < sampleCount; i++) + { + int value; + if (const auto result = adc_oneshot_read(adc1_handle, channel, &value); result != ESP_OK) + ESP_LOGE(TAG, "adc_oneshot_read_channel() failed with %s", esp_err_to_name(result)); + sum += value; + } + return sum / sampleCount; + }; raw_gas = std::nullopt; raw_brems = std::nullopt; @@ -100,19 +112,13 @@ void readPotis() #ifdef FEATURE_ADC_IN if (!raw_gas) { - int raw; - if (const auto result = adc_oneshot_read(adc1_handle, ADC_CHANNEL_GAS, &raw); result == ESP_OK) - raw_gas = raw; - else - ESP_LOGE(TAG, "adc_oneshot_read() failed with %s", esp_err_to_name(result)); + raw_gas = sampleMultipleTimes(ADC_CHANNEL_GAS); + ESP_LOGD(TAG, "raw_gas: %d", *raw_gas); } if (!raw_brems) { - int raw; - if (const auto result = adc_oneshot_read(adc1_handle, ADC_CHANNEL_BREMS, &raw); result == ESP_OK) - raw_brems = raw; - else - ESP_LOGE(TAG, "adc_oneshot_read() failed with %s", esp_err_to_name(result)); + raw_brems = sampleMultipleTimes(ADC_CHANNEL_BREMS); + ESP_LOGD(TAG, "raw_brems: %d", *raw_brems); } #endif diff --git a/main/setup.cpp b/main/setup.cpp new file mode 100644 index 0000000..d00c52e --- /dev/null +++ b/main/setup.cpp @@ -0,0 +1,39 @@ +#include "setup.h" + +// local includes +#include "globals.h" + +namespace setup { +bool currently_locked; +ModeInterface* oldMode; +IgnoreInputMode setup_mode{0, bobbycar::protocol::ControlType::FieldOrientedControl, bobbycar::protocol::ControlMode::Torque}; + +void lock() +{ + if (currently_locked) + return; + + oldMode = currentMode; + currentMode = &setup_mode; +} + +void unlock() +{ + if (!currently_locked) + return; + + if (currentMode == &setup_mode) + { + // to avoid crash after deconstruction + setup_mode.stop(); + lastMode = nullptr; + + currentMode = oldMode; + } +} + +bool isLocked() +{ + return currently_locked; +} +} // namespace setup diff --git a/main/setup.h b/main/setup.h new file mode 100644 index 0000000..0e074ad --- /dev/null +++ b/main/setup.h @@ -0,0 +1,23 @@ +#pragma once + +// local includes +#include "bobbytypesafeenum.h" +#include "modeinterface.h" +#include "modes/ignoreinputmode.h" + +#define SetupStepValues(x) \ + x(INFORMATION) \ + x(BASIC_BUTTONS) \ + x(CALIBRATE_POTIS) + +DECLARE_BOBBYTYPESAFE_ENUM(SetupStep, : uint8_t, SetupStepValues); + +namespace setup { +extern bool currently_locked; +extern ModeInterface* oldMode; +extern IgnoreInputMode setup_mode; + +void lock(); +void unlock(); +bool isLocked(); +} // namespace setup diff --git a/main/statistics.cpp b/main/statistics.cpp index 1f92a20..c0dc322 100644 --- a/main/statistics.cpp +++ b/main/statistics.cpp @@ -1,7 +1,7 @@ #include "statistics.h" namespace statistics { -ContainerType gas, brems, avgSpeed, avgSpeedKmh, sumCurrent, frontVoltage, backVoltage, frontLeftCurrent, frontRightCurrent, backLeftCurrent, backRightCurrent, +ContainerType raw_gas, raw_brems, gas, brems, avgSpeed, avgSpeedKmh, sumCurrent, frontVoltage, backVoltage, frontLeftCurrent, frontRightCurrent, backLeftCurrent, backRightCurrent, #ifdef FEATURE_BMS bmsVoltage, bmsCurrent, bmsPower, #endif @@ -10,6 +10,10 @@ ContainerType gas, brems, avgSpeed, avgSpeedKmh, sumCurrent, frontVoltage, backV void pushStats() { + if (raw_gas) + statistics::raw_gas.push_back(*raw_gas); + if (raw_brems) + statistics::raw_brems.push_back(*raw_brems); if (gas) statistics::gas.push_back(*gas); if (brems) diff --git a/main/statistics.h b/main/statistics.h index 1867d4f..411d776 100644 --- a/main/statistics.h +++ b/main/statistics.h @@ -11,7 +11,7 @@ namespace statistics { using ContainerType = ring_buffer; -extern ContainerType gas, brems, avgSpeed, avgSpeedKmh, sumCurrent, frontVoltage, backVoltage, frontLeftCurrent, frontRightCurrent, backLeftCurrent, backRightCurrent, +extern ContainerType raw_gas, raw_brems, gas, brems, avgSpeed, avgSpeedKmh, sumCurrent, frontVoltage, backVoltage, frontLeftCurrent, frontRightCurrent, backLeftCurrent, backRightCurrent, #ifdef FEATURE_BMS bmsVoltage, bmsCurrent, bmsPower, #endif @@ -33,6 +33,8 @@ public: const statistics::ContainerType &getBuffer() const override { return T; } }; +using RawGasStatistics = BufferAccessorImpl; +using RawBremsStatistics = BufferAccessorImpl; using GasStatistics = BufferAccessorImpl; using BremsStatistics = BufferAccessorImpl; using AvgSpeedStatistics = BufferAccessorImpl; diff --git a/main/taskmanager.cpp b/main/taskmanager.cpp index ee3e8ef..5f32758 100644 --- a/main/taskmanager.cpp +++ b/main/taskmanager.cpp @@ -115,7 +115,7 @@ void sched_pushStats(bool printTasks) ESP_LOGI(TAG, "end listing tasks"); } -tl::expected checkInitializedByName(std::string name) +tl::expected checkInitializedByName(const std::string& name) { for (auto &schedulerTask : schedulerTasks) { @@ -126,7 +126,7 @@ tl::expected checkInitializedByName(std::string name) return tl::make_unexpected("Task not found: " + std::string{name}); } -bool checkEnabledByName(std::string name) { +bool checkEnabledByName(const std::string& name) { bool enabled = true; // iterate over all feature flags (runForEveryFeature()) configs.callForEveryFeature([&](ConfiguredFeatureFlag &feature) { @@ -135,3 +135,14 @@ bool checkEnabledByName(std::string name) { }); return enabled; } + +void reload_tasks() +{ + for (auto &task : schedulerTasks) + { + if (checkEnabledByName(task.name()) && !task.isInitialized()) + { + task.setup(); + } + } +} diff --git a/main/taskmanager.h b/main/taskmanager.h index c3bc2ee..c78848a 100644 --- a/main/taskmanager.h +++ b/main/taskmanager.h @@ -16,6 +16,8 @@ extern const BobbySchedulerTask &drivingModeTask; void sched_pushStats(bool printTasks); -tl::expected checkInitializedByName(std::string name); +tl::expected checkInitializedByName(const std::string& name); -bool checkEnabledByName(std::string name); +bool checkEnabledByName(const std::string& name); + +void reload_tasks(); diff --git a/main/udpcloud.cpp b/main/udpcloud.cpp index 64f1e7e..f31f6d6 100644 --- a/main/udpcloud.cpp +++ b/main/udpcloud.cpp @@ -241,8 +241,6 @@ void sendUdpCloudPacket() ESP_LOGE(TAG, "send to cloud failed: %.*s (ip=%s)", result.error().size(), result.error().data(), wifi_stack::toString(udpCloudIp.u_addr.ip4).c_str()); } - // ESP_LOGI(TAG, "%s", buf.c_str()); - visualSendUdpPacket = !visualSendUdpPacket; } } diff --git a/main/utils.cpp b/main/utils.cpp index 6bd27d7..5ed372f 100644 --- a/main/utils.cpp +++ b/main/utils.cpp @@ -3,6 +3,9 @@ // system includes #include +// 3rdparty lib includes +#include + // local includes #include "globals.h" #include "newsettings.h" @@ -380,3 +383,58 @@ std::string toString(esp_chip_model_t esp_chip_model) return "invalid"; } } + +std::optional checkIfInCalibration() +{ + if (!configs.boardcomputerHardware.setupFinished.value()) + { + return SetupStep::INFORMATION; + } + else if ( + configs.dpadMappingLeft.value() == INPUT_MAPPING_NONE || + configs.dpadMappingRight.value() == INPUT_MAPPING_NONE || + configs.dpadMappingUp.value() == INPUT_MAPPING_NONE || + configs.dpadMappingDown.value() == INPUT_MAPPING_NONE + ) + { + return SetupStep::BASIC_BUTTONS; + } + else if (!gas || !brems || *gas > 200.f || *brems > 200.f) + { + return SetupStep::CALIBRATE_POTIS; + } + return std::nullopt; +} + +void drawLargeText(const std::string&& text) +{ + using namespace espgui; + + const auto topMargin = 50; + const uint8_t leftMargin = 8; + const auto rightMargin = leftMargin; + const auto bottomMargin = leftMargin; + + int x = leftMargin + 5; + int y = topMargin + 5; + + tft.setTextColor(TFT_WHITE); + + for (char c : text) + { + if (c == '\n' || x > tft.width() - rightMargin - 10) + { + x = leftMargin + 5; + y += tft.fontHeight(2); + } + + if (c != '\n') + { + const auto addedWidth = tft.drawChar(tft.decodeUTF8(c), x, y, 2); + x += addedWidth; + } + + if (y >= tft.height() - bottomMargin) + break; + } +} diff --git a/main/utils.h b/main/utils.h index 8139a96..51e5d43 100644 --- a/main/utils.h +++ b/main/utils.h @@ -46,6 +46,7 @@ #ifdef DPAD_BOARDCOMPUTER_V2 #include "dpad_boardcomputer_v2.h" #endif +#include "setup.h" extern bool currentlyReverseBeeping; extern bool reverseBeepToggle; @@ -101,6 +102,8 @@ float float_map(float x, float in_min, float in_max, float out_min, float out_ma bool is_valid_timestamp(espchrono::utc_clock::time_point timestamp); std::string toString(esp_chip_model_t esp_chip_model); +std::optional checkIfInCalibration(); +void drawLargeText(const std::string&& text); namespace bobbydpad { #ifdef FEATURE_DPAD