From cfa278a4b10e58c7543781893bcbf3fc828000ac Mon Sep 17 00:00:00 2001 From: CommanderRedYT Date: Thu, 27 Jan 2022 18:02:25 +0100 Subject: [PATCH 1/3] Basic Menu for managing profiles --- main/CMakeLists.txt | 2 ++ main/displays/menus/mainmenu.cpp | 3 +++ main/displays/menus/manageprofilesmenu.cpp | 31 ++++++++++++++++++++++ main/displays/menus/manageprofilesmenu.h | 14 ++++++++++ 4 files changed, 50 insertions(+) create mode 100644 main/displays/menus/manageprofilesmenu.cpp create mode 100644 main/displays/menus/manageprofilesmenu.h diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index dd14754..f3bd8f6 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -111,6 +111,7 @@ set(headers displays/menus/limitssettingsmenu.h displays/menus/lockscreensettingsmenu.h displays/menus/mainmenu.h + displays/menus/manageprofilesmenu.h displays/menus/modessettingsmenu.h displays/menus/mosfetsmenu.h displays/menus/motorfeedbackdebugmenu.h @@ -341,6 +342,7 @@ set(sources displays/menus/limitssettingsmenu.cpp displays/menus/lockscreensettingsmenu.cpp displays/menus/mainmenu.cpp + displays/menus/manageprofilesmenu.cpp displays/menus/modessettingsmenu.cpp displays/menus/mosfetsmenu.cpp displays/menus/motorfeedbackdebugmenu.cpp diff --git a/main/displays/menus/mainmenu.cpp b/main/displays/menus/mainmenu.cpp index a14d028..d5cd736 100644 --- a/main/displays/menus/mainmenu.cpp +++ b/main/displays/menus/mainmenu.cpp @@ -16,6 +16,7 @@ #include "displays/powersupplydisplay.h" #include "displays/menus/bmsmenu.h" #include "displays/menus/settingsmenu.h" +#include "displays/menus/manageprofilesmenu.h" #include "displays/menus/mosfetsmenu.h" #include "displays/menus/demosmenu.h" #include "displays/menus/greenpassmenu.h" @@ -78,6 +79,7 @@ constexpr char TEXT_DEBUG[] = "Debug"; constexpr char TEXT_BATTERY[] = "Battery"; constexpr char TEXT_BATTERYDEBUG[] = "Bat Debug Menu"; constexpr char TEXT_TOGGLECLOUDDEBUG[] = "Cloud Debug"; +constexpr char TEXT_MANAGEPROFILESMENU[] = "Manage Profile Settings"; } // namespace @@ -115,6 +117,7 @@ MainMenu::MainMenu() #endif constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&bobbyicons::demos>>>(); if (SHOWITEM) { constructMenuItem, SwitchScreenAction>>(); } + if (SHOWITEM) { constructMenuItem,SwitchScreenAction>>(); } if (SHOWITEM) { constructMenuItem, SwitchScreenAction>>(); } constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&bobbyicons::poweroff>>>(); constructMenuItem, RebootAction, StaticMenuItemIcon<&bobbyicons::reboot>>>(); diff --git a/main/displays/menus/manageprofilesmenu.cpp b/main/displays/menus/manageprofilesmenu.cpp new file mode 100644 index 0000000..2b87c85 --- /dev/null +++ b/main/displays/menus/manageprofilesmenu.cpp @@ -0,0 +1,31 @@ +#include "manageprofilesmenu.h" + +// 3rdparty lib includes +#include + +// local includes +#include "actions/switchscreenaction.h" +#include "mainmenu.h" + +namespace { +constexpr char TEXT_MANAGEPROFILESMENU[] = "Manage Profiles Menu"; +constexpr char TEXT_BACK[] = "Back"; +} + +using namespace espgui; + +ManageProfilesMenu::ManageProfilesMenu() +{ + constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&espgui::icons::back>>>(); +} + +void ManageProfilesMenu::back() +{ + switchScreen(); +} + +std::string ManageProfilesMenu::text() const +{ + return TEXT_MANAGEPROFILESMENU; +} +// functions: clear profile, copy profile, move profile diff --git a/main/displays/menus/manageprofilesmenu.h b/main/displays/menus/manageprofilesmenu.h new file mode 100644 index 0000000..fa77fd2 --- /dev/null +++ b/main/displays/menus/manageprofilesmenu.h @@ -0,0 +1,14 @@ +#pragma once + +// local includes +#include + +class ManageProfilesMenu : public BobbyMenuDisplay +{ +public: + ManageProfilesMenu(); + + std::string text() const override; + + void back() override; +}; From 98ef64d82e22077d6e3f93e085827a022e0cbcf3 Mon Sep 17 00:00:00 2001 From: CommanderRedYT Date: Fri, 28 Jan 2022 19:24:56 +0100 Subject: [PATCH 2/3] Added profile reset functionallity --- main/displays/menus/mainmenu.cpp | 6 +- main/displays/menus/manageprofilesmenu.cpp | 164 ++++++++++++++++++++- main/displays/menus/manageprofilesmenu.h | 28 +++- 3 files changed, 188 insertions(+), 10 deletions(-) diff --git a/main/displays/menus/mainmenu.cpp b/main/displays/menus/mainmenu.cpp index d5cd736..dc99b3e 100644 --- a/main/displays/menus/mainmenu.cpp +++ b/main/displays/menus/mainmenu.cpp @@ -79,7 +79,7 @@ constexpr char TEXT_DEBUG[] = "Debug"; constexpr char TEXT_BATTERY[] = "Battery"; constexpr char TEXT_BATTERYDEBUG[] = "Bat Debug Menu"; constexpr char TEXT_TOGGLECLOUDDEBUG[] = "Cloud Debug"; -constexpr char TEXT_MANAGEPROFILESMENU[] = "Manage Profile Settings"; +constexpr char TEXT_MANAGEPROFILESMENU[] = "Manage Profiles"; } // namespace @@ -116,8 +116,8 @@ MainMenu::MainMenu() if (SHOWITEM) { constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&bobbyicons::bms>>>(); } #endif constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&bobbyicons::demos>>>(); - if (SHOWITEM) { constructMenuItem, SwitchScreenAction>>(); } - if (SHOWITEM) { constructMenuItem,SwitchScreenAction>>(); } + if (SHOWITEM) { constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&bobbyicons::presets>>>(); } + if (SHOWITEM) { constructMenuItem,SwitchScreenAction, StaticMenuItemIcon<&bobbyicons::presets>>>(); } if (SHOWITEM) { constructMenuItem, SwitchScreenAction>>(); } constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&bobbyicons::poweroff>>>(); constructMenuItem, RebootAction, StaticMenuItemIcon<&bobbyicons::reboot>>>(); diff --git a/main/displays/menus/manageprofilesmenu.cpp b/main/displays/menus/manageprofilesmenu.cpp index 2b87c85..7dbce98 100644 --- a/main/displays/menus/manageprofilesmenu.cpp +++ b/main/displays/menus/manageprofilesmenu.cpp @@ -2,30 +2,184 @@ // 3rdparty lib includes #include +#include // local includes #include "actions/switchscreenaction.h" +#include "bobbyerrorhandler.h" +#include "globals.h" #include "mainmenu.h" +#include "presets.h" +#include "utils.h" -namespace { -constexpr char TEXT_MANAGEPROFILESMENU[] = "Manage Profiles Menu"; -constexpr char TEXT_BACK[] = "Back"; -} +constexpr const char * const TAG = "ProfileManager"; using namespace espgui; +namespace { +constexpr char TEXT_MANAGEPROFILESMENU[] = "Manage Profiles Menu"; +constexpr char TEXT_BACK[] = "Back"; +} // namespace + +class ManageProfileMenuItem : public MenuItem +{ + using Base = MenuItem; +public: + ManageProfileMenuItem(ManageProfilesMenu &menu, const uint8_t profileIndex) : m_menu{menu}, m_profileIndex{profileIndex} {} + void copy() + { + + } + + void swap() + { + + } + + void clear() + { + if (m_mode == CONFIRMCLEAR) + { + m_menu.unlock(); + ESP_LOGI(TAG, "Reseting profile %i...", m_profileIndex); + profileSettings = presets::defaultProfileSettings; + m_mode = _DEFAULT; + } + else + { + m_menu.lock(); + m_mode = CONFIRMCLEAR; + BobbyErrorHandler{}.errorOccured("Press CONFIRM to reset Profile or BACK to cancel."); + } + } + + std::string text() const override + { + switch (m_mode) + { + case _DEFAULT: + return fmt::format("Profile {}", m_profileIndex); + case CONFIRMCLEAR: + return fmt::format("&1Profile {}", m_profileIndex); + } + return fmt::format("Profile {}", m_profileIndex); + } + + int color() const override + { + if (m_mode == CONFIRMCLEAR) + return TFT_RED; + else if (m_menu.m_locked) + return TFT_DARKGREY; + return TFT_WHITE; + }; + + void triggered() override + { + switch (m_menu.m_action) + { + case Actions::Clear: + clear(); + break; + case Actions::Copy: + copy(); + break; + case Actions::Swap: + swap(); + break; + default: + break; + } + } + + void update() override + { + Base::update(); + if (m_mode != _DEFAULT && !m_menu.m_locked) + m_mode = _DEFAULT; + } +private: + enum Mode : uint8_t { + _DEFAULT, + CONFIRMCLEAR + } m_mode; + ManageProfilesMenu &m_menu; + const uint8_t m_profileIndex; +}; + +class ManageProfileModeMenuItem : public MenuItem +{ +public: + ManageProfileModeMenuItem(ManageProfilesMenu &menu) : m_menu{menu} {} + std::string text() const override { + return fmt::format("&7{}", m_menu.action_text()); + } + + void triggered() override { + m_menu.m_action = Actions((uint8_t)m_menu.m_action+1); + + if(m_menu.m_action == Actions::__END__) + { + m_menu.m_action = Actions(0); + } + } +private: + ManageProfilesMenu &m_menu; +}; + ManageProfilesMenu::ManageProfilesMenu() { + for (uint8_t i = 0; i < 4; i++) + { + constructMenuItem(*this, i); + } + constructMenuItem(*this); constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&espgui::icons::back>>>(); } +void ManageProfilesMenu::start() +{ + Base::start(); + m_oldMode = currentMode; + currentMode = &m_mode; +} + +void ManageProfilesMenu::stop() +{ + Base::stop(); + + if (currentMode == &m_mode) + { + m_mode.stop(); + lastMode = nullptr; + currentMode = m_oldMode; + } +} + void ManageProfilesMenu::back() { - switchScreen(); + if (!m_locked) + switchScreen(); + else + m_locked = false; } std::string ManageProfilesMenu::text() const { return TEXT_MANAGEPROFILESMENU; } + +std::string ManageProfilesMenu::action_text() const { + return toString(m_action); +} + +void ManageProfilesMenu::lock() { + m_locked = true; +} + +void ManageProfilesMenu::unlock() { + m_locked = false; +} // functions: clear profile, copy profile, move profile +// TODO: If m_locked == true, only confirm and back (espgui::Button::Right and espgui::Button::Left) should be allowed to pass to the menuitems. +// diff --git a/main/displays/menus/manageprofilesmenu.h b/main/displays/menus/manageprofilesmenu.h index fa77fd2..3b3c448 100644 --- a/main/displays/menus/manageprofilesmenu.h +++ b/main/displays/menus/manageprofilesmenu.h @@ -1,14 +1,38 @@ #pragma once +// 3rdparty lib includes +#include + // local includes -#include +#include "displays/bobbymenudisplay.h" +#include "modes/ignoreinputmode.h" + +#define ActionValues(x) \ + x(Clear) \ + x(Copy) \ + x(Swap) \ + x(__END__) +DECLARE_TYPESAFE_ENUM(Actions, : uint8_t, ActionValues) class ManageProfilesMenu : public BobbyMenuDisplay { + friend class ManageProfileMenuItem; + friend class ManageProfileModeMenuItem; + using Base = BobbyMenuDisplay; public: ManageProfilesMenu(); + void start() override; + void stop() override; std::string text() const override; - + std::string action_text() const; void back() override; + void lock(); + void unlock(); +private: + ModeInterface *m_oldMode; + IgnoreInputMode m_mode{0, bobbycar::protocol::ControlType::FieldOrientedControl, bobbycar::protocol::ControlMode::Torque}; +protected: + bool m_locked{false}; + Actions m_action{Actions::Clear}; }; From 8a1051d91bdd8e8673eba5d7bd5f50d2bfd30bf4 Mon Sep 17 00:00:00 2001 From: CommanderRedYT Date: Sat, 29 Jan 2022 03:28:40 +0100 Subject: [PATCH 3/3] Finished menu to clear, swap and copy profiles --- main/displays/menus/manageprofilesmenu.cpp | 112 +++++++++++++++++++-- main/displays/menus/manageprofilesmenu.h | 1 + main/webserver.cpp | 2 +- main/webserver_displaycontrol.cpp | 7 ++ main/webserver_ota.cpp | 6 +- 5 files changed, 115 insertions(+), 13 deletions(-) diff --git a/main/displays/menus/manageprofilesmenu.cpp b/main/displays/menus/manageprofilesmenu.cpp index 7dbce98..7fa56ef 100644 --- a/main/displays/menus/manageprofilesmenu.cpp +++ b/main/displays/menus/manageprofilesmenu.cpp @@ -10,6 +10,7 @@ #include "globals.h" #include "mainmenu.h" #include "presets.h" +#include "settingsutils.h" #include "utils.h" constexpr const char * const TAG = "ProfileManager"; @@ -28,27 +29,101 @@ public: ManageProfileMenuItem(ManageProfilesMenu &menu, const uint8_t profileIndex) : m_menu{menu}, m_profileIndex{profileIndex} {} void copy() { + if (m_mode == CONFIRM_COPY) + { + const auto currProfile = settingsPersister.currentlyOpenProfileIndex(); + if (!currProfile) + return; + settingsutils::switchProfile(m_menu.m_firstIndex); + + if (!settingsPersister.openProfile(m_profileIndex)) // just switch nvs namespace + { + BobbyErrorHandler{}.errorOccured(fmt::format("openProfile({}) failed", m_profileIndex)); + return; + } + saveProfileSettings(); + settingsutils::switchProfile(*currProfile); + m_mode = _DEFAULT; + m_menu.m_firstIndex = -1; + } + else if (m_menu.m_firstIndex == m_profileIndex && m_mode == SELECT_OTHER) + { + m_mode = _DEFAULT; + m_menu.m_firstIndex = -1; + } + else if (m_menu.m_firstIndex == -1 && m_mode == _DEFAULT) + { + m_mode = SELECT_OTHER; + m_menu.m_firstIndex = m_profileIndex; + } + else if (m_menu.m_firstIndex != -1 && m_menu.m_firstIndex != m_profileIndex) + { + BobbyErrorHandler{}.errorOccured(fmt::format("Press CONFIRM to COPY from Profile {} to Profile {}", m_menu.m_firstIndex, m_profileIndex)); + m_mode = CONFIRM_COPY; + } } void swap() { + if (m_mode == CONFIRM_SWAP) + { + const auto currProfile = settingsPersister.currentlyOpenProfileIndex(); + if (!currProfile) + return; + settingsutils::switchProfile(m_menu.m_firstIndex); + const ProfileSettings tmp = profileSettings; + settingsutils::switchProfile(m_profileIndex); + const ProfileSettings tmp2 = profileSettings; + + profileSettings = tmp; + saveProfileSettings(); + settingsutils::switchProfile(m_menu.m_firstIndex); + profileSettings = tmp2; + saveProfileSettings(); + + m_mode = _DEFAULT; + m_menu.m_firstIndex = -1; + settingsutils::switchProfile(*currProfile); + } + else if (m_menu.m_firstIndex == m_profileIndex && m_mode == SELECT_OTHER) + { + m_mode = _DEFAULT; + m_menu.m_firstIndex = -1; + } + else if (m_menu.m_firstIndex == -1 && m_mode == _DEFAULT) + { + m_mode = SELECT_OTHER; + m_menu.m_firstIndex = m_profileIndex; + } + else if (m_menu.m_firstIndex != -1 && m_menu.m_firstIndex != m_profileIndex) + { + BobbyErrorHandler{}.errorOccured(fmt::format("Press CONFIRM to SWAP Profile {} with Profile {}", m_menu.m_firstIndex, m_profileIndex)); + m_mode = CONFIRM_SWAP; + } } void clear() { - if (m_mode == CONFIRMCLEAR) + if (m_mode == CONFIRM_CLEAR) { + const auto currProfile = settingsPersister.currentlyOpenProfileIndex(); + if (!currProfile) + return; + m_menu.unlock(); ESP_LOGI(TAG, "Reseting profile %i...", m_profileIndex); + settingsutils::switchProfile(m_profileIndex); profileSettings = presets::defaultProfileSettings; + saveProfileSettings(); m_mode = _DEFAULT; + settingsutils::switchProfile(*currProfile); } - else + else if(m_mode == _DEFAULT) { m_menu.lock(); - m_mode = CONFIRMCLEAR; + m_mode = CONFIRM_CLEAR; BobbyErrorHandler{}.errorOccured("Press CONFIRM to reset Profile or BACK to cancel."); } } @@ -59,16 +134,22 @@ public: { case _DEFAULT: return fmt::format("Profile {}", m_profileIndex); - case CONFIRMCLEAR: + case CONFIRM_CLEAR: return fmt::format("&1Profile {}", m_profileIndex); + default: + break; } return fmt::format("Profile {}", m_profileIndex); } int color() const override { - if (m_mode == CONFIRMCLEAR) + if (m_mode == CONFIRM_CLEAR || m_mode == CONFIRM_COPY || m_mode == CONFIRM_SWAP) return TFT_RED; + else if (m_menu.m_firstIndex == m_profileIndex) + return TFT_GREEN; + else if (m_menu.m_firstIndex != -1) + return TFT_GREY; else if (m_menu.m_locked) return TFT_DARKGREY; return TFT_WHITE; @@ -95,13 +176,16 @@ public: void update() override { Base::update(); - if (m_mode != _DEFAULT && !m_menu.m_locked) + if (m_mode != _DEFAULT && !m_menu.m_locked && m_menu.m_firstIndex == -1) m_mode = _DEFAULT; } private: enum Mode : uint8_t { _DEFAULT, - CONFIRMCLEAR + CONFIRM_CLEAR, + SELECT_OTHER, + CONFIRM_COPY, + CONFIRM_SWAP } m_mode; ManageProfilesMenu &m_menu; const uint8_t m_profileIndex; @@ -122,6 +206,8 @@ public: { m_menu.m_action = Actions(0); } + m_menu.m_firstIndex = -1; + m_menu.unlock(); } private: ManageProfilesMenu &m_menu; @@ -158,10 +244,18 @@ void ManageProfilesMenu::stop() void ManageProfilesMenu::back() { - if (!m_locked) + if (!m_locked && m_firstIndex == -1) + { switchScreen(); - else + return; + } + + if (m_locked) m_locked = false; + + if (m_firstIndex != -1) + m_firstIndex = -1; + } std::string ManageProfilesMenu::text() const diff --git a/main/displays/menus/manageprofilesmenu.h b/main/displays/menus/manageprofilesmenu.h index 3b3c448..500645d 100644 --- a/main/displays/menus/manageprofilesmenu.h +++ b/main/displays/menus/manageprofilesmenu.h @@ -35,4 +35,5 @@ private: protected: bool m_locked{false}; Actions m_action{Actions::Clear}; + int8_t m_firstIndex{-1}; }; diff --git a/main/webserver.cpp b/main/webserver.cpp index 8798732..9812683 100644 --- a/main/webserver.cpp +++ b/main/webserver.cpp @@ -174,7 +174,7 @@ esp_err_t webserver_status_handler(httpd_req_t *req) CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); } #endif - + CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Access-Control-Allow-Origin", "http://web.bobbycar.cloud"); std::string wants_json_query; if (auto result = esphttpdutils::webserver_get_query(req)) wants_json_query = *result; diff --git a/main/webserver_displaycontrol.cpp b/main/webserver_displaycontrol.cpp index 32227c7..7e9ef9d 100644 --- a/main/webserver_displaycontrol.cpp +++ b/main/webserver_displaycontrol.cpp @@ -281,6 +281,8 @@ esp_err_t webserver_root_handler(httpd_req_t *req) } } + CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Access-Control-Allow-Origin", "http://web.bobbycar.cloud"); + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::Ok, (key_result == ESP_OK) ? "application/json":"text/html", body) } @@ -354,6 +356,7 @@ esp_err_t webserver_triggerRawButton_handler(httpd_req_t *req) espgui::currentDisplay->rawButtonReleased(button); CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Location", "/") + CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Access-Control-Allow-Origin", "http://web.bobbycar.cloud"); CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::TemporaryRedirect, "text/html", "Ok, continue at /") } @@ -427,6 +430,7 @@ esp_err_t webserver_triggerButton_handler(httpd_req_t *req) espgui::currentDisplay->buttonReleased(button); CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Location", "/") + CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Access-Control-Allow-Origin", "http://web.bobbycar.cloud"); CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::TemporaryRedirect, "text/html", "Ok, continue at /") } @@ -441,6 +445,7 @@ esp_err_t webserver_triggerItem_handler(httpd_req_t *req) CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); } #endif + CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Access-Control-Allow-Origin", "http://web.bobbycar.cloud"); std::string query; if (auto result = esphttpdutils::webserver_get_query(req)) @@ -530,6 +535,8 @@ esp_err_t webserver_setValue_handler(httpd_req_t *req) } #endif + CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Access-Control-Allow-Origin", "http://web.bobbycar.cloud"); + std::string query; if (auto result = esphttpdutils::webserver_get_query(req)) query = *result; diff --git a/main/webserver_ota.cpp b/main/webserver_ota.cpp index 2d614f6..f2546ce 100644 --- a/main/webserver_ota.cpp +++ b/main/webserver_ota.cpp @@ -43,7 +43,7 @@ esp_err_t webserver_ota_percentage_handler(httpd_req_t *req) CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); } #endif - + CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Access-Control-Allow-Origin", "http://web.bobbycar.cloud"); std::string body; std::string wants_json_query; @@ -102,7 +102,7 @@ esp_err_t webserver_ota_handler(httpd_req_t *req) CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); } #endif - + CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Access-Control-Allow-Origin", "http://web.bobbycar.cloud"); std::string body; std::string wants_json_query; @@ -370,7 +370,7 @@ esp_err_t webserver_trigger_ota_handler(httpd_req_t *req) CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); } #endif - + CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Access-Control-Allow-Origin", "http://web.bobbycar.cloud"); std::string query; if (auto result = esphttpdutils::webserver_get_query(req)) query = *result;