Merge pull request #372 from bobbycar-graz/setup-screen-361

This commit is contained in:
CommanderRedYT
2022-10-26 19:19:17 +02:00
committed by GitHub
61 changed files with 1602 additions and 465 deletions

View File

@ -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

View File

@ -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
#

View File

@ -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
#

View File

@ -4,6 +4,6 @@ dependencies:
source:
type: idf
version: 5.1.0
manifest_hash: 61ebe3a040bdb7a8bb7b582261db12d83b6028789124b5f6ddacb4104628daa6
manifest_hash: 9a4f2dfb2ab76ca07dad44e92970eea272a02162afa87b1dc511d285966e0252
target: esp32
version: 1.0.0

Submodule esp-idf updated: 756de87ccf...036e4cc64b

View File

@ -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()

View File

@ -32,7 +32,6 @@ private:
std::string m_msg;
};
template<typename TMenu>
class PushQrImportDisplayAction : public virtual espgui::ActionInterface
{
public:
@ -41,7 +40,7 @@ public:
void triggered() override
{
espgui::pushScreen<QrImportDisplay<TMenu>>(std::move(m_nvskey));
espgui::pushScreen<QrImportDisplay>(std::move(m_nvskey));
}
private:
std::string m_nvskey;

View File

@ -1,11 +0,0 @@
#include "resetnvsaction.h"
// system includes
#include <esp_system.h>
#include <nvs_flash.h>
void ResetNVSAction::triggered()
{
nvs_flash_erase();
esp_restart();
}

View File

@ -1,10 +1,40 @@
#pragma once
// system includes
#include <esp_system.h>
// 3rdparty lib includes
#include <actioninterface.h>
#include <tftinstance.h>
// local includes
#include "newsettings.h"
template<bool reboot>
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();
}
}
};

View File

@ -0,0 +1,26 @@
#include "setupactions.h"
// 3rdparty lib includes
#include <screenmanager.h>
// 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<SetupBasicButtonsDisplay>(m_early_return);
}
PushPotiCalibrateDisplayAction::PushPotiCalibrateDisplayAction(const bool early_return) :
m_early_return{early_return}
{}
void PushPotiCalibrateDisplayAction::triggered()
{
// espgui::pushScreen<SetupCalibratePotisDisplay>(m_early_return); // commented out until implemented
}

View File

@ -0,0 +1,24 @@
#pragma once
// 3rdparty lib includes
#include <actioninterface.h>
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;
};

View File

@ -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<espcpputils::ticks>(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());

View File

@ -38,7 +38,7 @@ void BobbyGraphDisplay<COUNT>::rawButtonReleased(uint8_t button)
template<size_t COUNT>
void BobbyGraphDisplay<COUNT>::buttonPressed(espgui::Button button)
{
//Base::buttonPressed(button);
Base::buttonPressed(button);
buttonPressedCommon(button);
}

View File

@ -1,221 +0,0 @@
#include "buttoncalibratedisplay.h"
// esp-idf includes
#include <esp_log.h>
// 3rdparty lib includes
#include <tftinstance.h>
#include <fmt/core.h>
#include <screenmanager.h>
// 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<StatusDisplay>();
}
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);
}

View File

@ -1,53 +0,0 @@
#pragma once
// 3rdparty lib includes
#include <displaywithtitle.h>
#include <widgets/label.h>
// 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<uint8_t> 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;
};

View File

@ -106,10 +106,7 @@ void Lockscreen::redraw()
{
if (isValid1stPin(m_numbers))
{
if (!gas || !brems || *gas > 200.f || *brems > 200.f)
espgui::switchScreen<PotisCalibrateDisplay>(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<PotisCalibrateDisplay>(true);
else
espgui::popScreen();
espgui::popScreen();
#ifdef LOCKSCREEN_PLUGIN_FIXES_2
LOCKSCREEN_PLUGIN_FIXES_2
#endif

View File

@ -88,7 +88,6 @@ BatteryMenu::BatteryMenu()
constructMenuItem<makeComponent<MenuItem, TextWithValueHelper<TEXT_BATTERY_WHKM, BatteryWHperKMAccessor>, PushScreenAction<BatteryWHperKMChangeScreen>>>();
constructMenuItem<PushScreenTypeSafeChangeMenuItem<BatteryCellType, TEXT_SELECT_CELL_TYPE>>(&configs.battery.cellType);
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_SHOW_BATTERY_GRAPH>, PushScreenAction<BatteryGraphDisplay>, StaticMenuItemIcon<&bobbyicons::graph>>>();
constructMenuItem<makeComponent<MenuItem, EmptyText, DummyAction>>();
constructMenuItem<makeComponent<MenuItem, WhStatisticsText, DummyAction>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BATTERY_CALIBRATE>, PushScreenAction<CalibrateVoltageDisplay>, StaticMenuItemIcon<&bobbyicons::settings>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, PopScreenAction, StaticMenuItemIcon<&espgui::icons::back>>>();

View File

@ -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<makeComponent<MenuItem, StaticText<TEXT_LOCKSCREENSETTINGS>, PushScreenAction<LockscreenSettingsMenu>, StaticMenuItemIcon<&bobbyicons::lock>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BUTTONCALIBRATE>, PushScreenAction<ButtonCalibrateDisplay>>>();
constructMenuItem<makeComponentArgs<MenuItem, PushButtonCalibrateDisplayAction, StaticText<TEXT_BUTTONCALIBRATE>>>(true);
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_EXTRABUTTONCALIBRATE>, PushScreenAction<ExtraButtonCalibrateMenu>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_QUICKACTIONS>, PushScreenAction<SetupQuickActionsMenu>>>();
constructMenuItem<makeComponent<MenuItem, GasText, DisabledColor, StaticFont<2>, DummyAction>>();
constructMenuItem<makeComponent<MenuItem, BremsText, DisabledColor, StaticFont<2>, DummyAction>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_POTISCALIBRATE>, PushScreenAction<PotisCalibrateDisplay>>>();
constructMenuItem<makeComponentArgs<MenuItem, PushPotiCalibrateDisplayAction, StaticText<TEXT_POTISCALIBRATE>>>(true);
#ifdef FEATURE_JOYSTICK
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_JOYSTICK>, PushScreenAction<JoystickDebugDisplay>>>();
#endif

View File

@ -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<makeComponent<MenuItem, StaticText<TEXT_LOADSETTINGS>, LoadSettingsAction>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_SAVESETTINGS>, SaveSettingsAction>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_ERASENVS>, EraseNvsAction>>();
constructMenuItem<makeComponent<MenuItem, EmptyText, DummyAction>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_RESET_NVS_NEW>, ResetNVSAction<true>, StaticMenuItemIcon<&bobbyicons::info>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_DYNAMICMENU>, PushScreenAction<DynamicDebugMenu>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, PopScreenAction, StaticMenuItemIcon<&espgui::icons::back>>>();
}

View File

@ -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<TEXT_RAW_GAS>,
espgui::SingleGraphAccessor<RawGasStatistics>,
espgui::ConfirmActionInterface<espgui::PopScreenAction>,
espgui::BackActionInterface<espgui::PopScreenAction>
>;
using RawBremsGraphDisplay = espgui::makeComponent<
BobbyGraphDisplay<1>,
espgui::StaticText<TEXT_RAW_BREMS>,
espgui::SingleGraphAccessor<RawBremsStatistics>,
espgui::ConfirmActionInterface<espgui::PopScreenAction>,
espgui::BackActionInterface<espgui::PopScreenAction>
>;
using GasGraphDisplay = espgui::makeComponent<
BobbyGraphDisplay<1>,
espgui::StaticText<TEXT_GAS>,
@ -173,6 +189,8 @@ using RssiGraphDisplay = espgui::makeComponent<
GraphsMenu::GraphsMenu()
{
using namespace espgui;
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_RAW_GAS>, PushScreenAction<RawGasGraphDisplay>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_RAW_BREMS>, PushScreenAction<RawBremsGraphDisplay>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_GAS>, PushScreenAction<GasGraphDisplay>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BREMS>, PushScreenAction<BremsGraphDisplay>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_POTIS>, PushScreenAction<PotisGraphDisplay>>>();

View File

@ -81,7 +81,7 @@ GreenPassMenu::GreenPassMenu()
}
else
{
constructMenuItem<makeComponentArgs<MenuItem, PushQrImportDisplayAction<GreenPassMenu>, StaticText<TEXT_ADDCERT>>>(std::move(nvs_key));
constructMenuItem<makeComponentArgs<MenuItem, PushQrImportDisplayAction, StaticText<TEXT_ADDCERT>>>(std::move(nvs_key));
}
}

View File

@ -50,7 +50,7 @@ RecoveryMenu::RecoveryMenu()
configs.callForEveryFeature([&](ConfiguredFeatureFlag &feature){
constructMenuItem<BasicFeatureFlagMenuItem>(feature);
});
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_RESET_NVS>, ResetNVSAction, StaticMenuItemIcon<&bobbyicons::info>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_RESET_NVS>, ResetNVSAction<false>, StaticMenuItemIcon<&bobbyicons::info>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_REBOOT>, RebootAction, StaticMenuItemIcon<&bobbyicons::reboot>>>();
}

View File

@ -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(),

View File

@ -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);
}
*/

View File

@ -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<float> m_gas, m_brems;
};
*/

View File

@ -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:;
}
}

View File

@ -1,12 +1,11 @@
#pragma once
constexpr const char * const TAG = "qrimport";
// 3rd party includes
#include <esp_log.h>
#include <widgets/label.h>
#include <fmt/core.h>
#include <tftinstance.h>
#include <tl/expected.hpp>
#include <fmt/core.h>
#include <widgets/label.h>
// local includes
#include "bobbydisplay.h"
@ -14,7 +13,6 @@ constexpr const char * const TAG = "qrimport";
#include "qrimport.h"
#include "screenmanager.h"
template<typename TMenu>
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};

View File

@ -0,0 +1,56 @@
#include "ask_calibrate_other_buttons.h"
// 3rdparty lib includes
#include <screenmanager.h>
// 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<SetupFinalInformationDisplay>();
return;
}
Base::start();
setup::lock();
}
void SetupAskCalibrateOtherButtonsDisplay::buttonPressed(espgui::Button button)
{
switch (button)
{
case espgui::Left:
espgui::switchScreen<SetupFinalInformationDisplay>();
return;
case espgui::Right:
m_next_screen = true;
espgui::pushScreen<ExtraButtonCalibrateMenu>();
return;
default:;
}
Base::buttonPressed(button);
}
std::string SetupAskCalibrateOtherButtonsDisplay::text() const
{
return "Other Buttons";
}

View File

@ -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};
};

View File

@ -0,0 +1,53 @@
#include "ask_setup_clouds.h"
// 3rdparty lib includes
#include <screenmanager.h>
// 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<SetupAskCalibrateOtherButtonsDisplay>();
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<SetupCloudDisplay>();
default:;
}
Base::buttonPressed(button);
}
std::string SetupAskSetupCloudsDisplay::text() const
{
return "Cloud Setup";
}

View File

@ -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;
};

View File

@ -0,0 +1,230 @@
#include "basic_buttons.h"
// system includes
#include <esp_log.h>
// 3rdparty lib includes
#include <screenmanager.h>
#include <tftinstance.h>
// 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<SetupCalibratePotisDisplay>();
}
}
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);
}
}

View File

@ -0,0 +1,51 @@
#pragma once
// system includes
#include <optional>
// 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<uint8_t> 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);
};

View File

@ -0,0 +1,309 @@
#include "calibrate_potis.h"
// 3rdparty lib includes
#include <cpputils.h>
#include <screenmanager.h>
#include <tftinstance.h>
// 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<float>(*raw_gas, m_gasMin, m_gasMax, 0.f, 1000.f);
else
m_gas = std::nullopt;
if (raw_brems)
m_brems = cpputils::mapValueClamped<float>(*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<SetupAskSetupCloudsDisplay>();
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<SetupAskSetupCloudsDisplay>();
}
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);
}

View File

@ -0,0 +1,86 @@
#pragma once
// system includes
#include <array>
#include <optional>
// 3rdparty lib includes
#include <widgets/label.h>
#include <widgets/progressbar.h>
// 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<espgui::Label, 11> 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<espgui::ProgressBar, 2> 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<float> m_gas, m_brems;
};

View File

@ -0,0 +1,58 @@
#include "final_information.h"
// 3rdparty lib includes
#include <screenmanager.h>
// 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<StatusDisplay>();
}
else
{
espgui::popScreen();
}
Base::buttonPressed(button);
}
std::string SetupFinalInformationDisplay::text() const
{
return "All done!";
}

View File

@ -0,0 +1,20 @@
#pragma once
// 3rdparty lib includes
#include <espchrono.h>
// 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;
};

View File

@ -0,0 +1,64 @@
#include "information.h"
// 3rdparty lib includes
#include <screenmanager.h>
// 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<SetupBasicButtonsDisplay>();
}
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<SetupBasicButtonsDisplay>();
}
}
[[nodiscard]] std::string SetupInformationDisplay::text() const
{
return "First Steps";
}

View File

@ -0,0 +1,26 @@
#pragma once
// 3rdparty lib includes
#include <espchrono.h>
#include <tftinstance.h>
#include <widgets/progressbar.h>
// 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};
};

View File

@ -0,0 +1,103 @@
#include "setup_cloud.h"
// 3rdparty lib includes
#include <actions/popscreenaction.h>
#include <actions/pushscreenaction.h>
#include <changevaluedisplay_string.h>
// 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<std::string>,
espgui::StaticText<TEXT_CLOUD_USERNAME>,
UsernameAccessor,
espgui::ConfirmActionInterface<espgui::PopScreenAction>,
espgui::BackActionInterface<espgui::PopScreenAction>
>;
using CloudURLChangeScreen = espgui::makeComponent<
BobbyChangeValueDisplay<std::string>,
espgui::StaticText<TEXT_CLOUD_URL>,
CloudURLAccessor,
espgui::ConfirmActionInterface<espgui::PopScreenAction>,
espgui::BackActionInterface<espgui::PopScreenAction>
>;
using CloudKeyChangeScreen = espgui::makeComponent<
BobbyChangeValueDisplay<std::string>,
espgui::StaticText<TEXT_CLOUD_KEY>,
CloudKeyAccessor,
espgui::ConfirmActionInterface<espgui::PopScreenAction>,
espgui::BackActionInterface<espgui::PopScreenAction>
>; // cloud setup
template<bool early_return>
class CloudSetupFinishedAction : public virtual ActionInterface
{
public:
void triggered() override
{
if (early_return)
{
espgui::popScreen();
}
else
{
espgui::switchScreen<SetupAskCalibrateOtherButtonsDisplay>();
}
}
};
} // namespace
SetupCloudDisplay::SetupCloudDisplay(const bool early_return) : m_early_return{early_return}
{
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_ENABLE_CLOUD>, BobbyCheckbox, CloudEnabledAccessor>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_CLOUD_USERNAME>, PushScreenAction<CloudUsernameChangeScreen>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_CLOUD_URL>, PushScreenAction<CloudURLChangeScreen>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_CLOUD_KEY>, PushScreenAction<CloudKeyChangeScreen>>>();
if (early_return)
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_DONE>, CloudSetupFinishedAction<true>>>();
else
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_DONE>, CloudSetupFinishedAction<false>>>();
}
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";
}

View File

@ -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;
};

View File

@ -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<espchrono::millis_clock::time_point> 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<ButtonCalibrateDisplay>(true);
switch(*result)
{
case SetupStep::INFORMATION:
BOOT_PROGRESS("Calibtration");
espgui::switchScreen<SetupInformationDisplay>();
break;
case SetupStep::BASIC_BUTTONS:
BOOT_PROGRESS("Calibtration");
espgui::switchScreen<SetupBasicButtonsDisplay>(true);
break;
case SetupStep::CALIBRATE_POTIS:
espgui::switchScreen<SetupCalibratePotisDisplay>(true);
break;
default:;
}
}
else if (configs.lockscreen.keepLockedAfterReboot.value() && configs.lockscreen.locked.value())
{
BOOT_PROGRESS("Locked");
espgui::switchScreen<StatusDisplay>();
espgui::pushScreen<Lockscreen>();
}
else
{
if (!gas || !brems || *gas > 200.f || *brems > 200.f)
espgui::switchScreen<PotisCalibrateDisplay>(true);
else
{
espgui::switchScreen<StatusDisplay>();
}
BOOT_PROGRESS("StatusDisplay")
espgui::switchScreen<StatusDisplay>();
}
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();

View File

@ -364,7 +364,8 @@ public:
ConfigWrapperLegacy<int16_t> cloudSendRate {1, DoReset, {}, "cloudSendRate" };
ConfigWrapperLegacy<int16_t> udpSendRateMs {65, DoReset, {}, "udpSendRate" };
} timersSettings;
ConfigWrapperLegacy<bool> flipScreen {false, DoReset, {}, "flipScreen" };
ConfigWrapperLegacy<bool> flipScreen {false, NoReset, {}, "flipScreen" };
ConfigWrapperLegacy<bool> setupFinished {false, DoReset, {}, "setupFinished" };
} boardcomputerHardware;
struct {
@ -487,6 +488,8 @@ public:
ConfigWrapperLegacy<bool> bleFenceEnabled {false, DoReset, {}, "bleFenceEnabled" };
} bleSettings;
ConfigWrapperLegacy<bool> 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) \

View File

@ -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

39
main/setup.cpp Normal file
View File

@ -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

23
main/setup.h Normal file
View File

@ -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

View File

@ -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)

View File

@ -11,7 +11,7 @@
namespace statistics {
using ContainerType = ring_buffer<float, 200>;
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<statistics::raw_gas>;
using RawBremsStatistics = BufferAccessorImpl<statistics::raw_brems>;
using GasStatistics = BufferAccessorImpl<statistics::gas>;
using BremsStatistics = BufferAccessorImpl<statistics::brems>;
using AvgSpeedStatistics = BufferAccessorImpl<statistics::avgSpeed>;

View File

@ -115,7 +115,7 @@ void sched_pushStats(bool printTasks)
ESP_LOGI(TAG, "end listing tasks");
}
tl::expected<bool, std::string> checkInitializedByName(std::string name)
tl::expected<bool, std::string> checkInitializedByName(const std::string& name)
{
for (auto &schedulerTask : schedulerTasks)
{
@ -126,7 +126,7 @@ tl::expected<bool, std::string> 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();
}
}
}

View File

@ -16,6 +16,8 @@ extern const BobbySchedulerTask &drivingModeTask;
void sched_pushStats(bool printTasks);
tl::expected<bool, std::string> checkInitializedByName(std::string name);
tl::expected<bool, std::string> checkInitializedByName(const std::string& name);
bool checkEnabledByName(std::string name);
bool checkEnabledByName(const std::string& name);
void reload_tasks();

View File

@ -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;
}
}

View File

@ -3,6 +3,9 @@
// system includes
#include <utility>
// 3rdparty lib includes
#include <tftinstance.h>
// 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<SetupStep> 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;
}
}

View File

@ -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<SetupStep> checkIfInCalibration();
void drawLargeText(const std::string&& text);
namespace bobbydpad {
#ifdef FEATURE_DPAD