diff --git a/components/bobbycar-protocol b/components/bobbycar-protocol index a331746..9e256ac 160000 --- a/components/bobbycar-protocol +++ b/components/bobbycar-protocol @@ -1 +1 @@ -Subproject commit a331746edecef1cd14bd8ab6a109b3859c45cce8 +Subproject commit 9e256acdaad453ead91d3c49496bedc731b81b36 diff --git a/main/bobbybuttons.cpp b/main/bobbybuttons.cpp index 4ff256c..8a4b5cd 100644 --- a/main/bobbybuttons.cpp +++ b/main/bobbybuttons.cpp @@ -1,23 +1,39 @@ #include "bobbybuttons.h" +// local includes +#include "newsettings.h" + [[nodiscard]] std::optional translateRawButton(uint8_t button) { - switch (button) - { + // Invalid + if (button == INPUT_MAPPING_NONE) + return std::nullopt; + using espgui::Button; - case 0: return Button::Left; - case 1: return Button::Right; - case 2: return Button::Up; - case 3: return Button::Down; - case 4: return Button(BobbyButton::Profile0); - case 5: return Button(BobbyButton::Profile1); - case 6: return Button(BobbyButton::Profile2); - case 7: return Button(BobbyButton::Profile3); - case 8: return Button(BobbyButton::Left2); - case 9: return Button(BobbyButton::Right2); - case 10: return Button(BobbyButton::Up2); - case 11: return Button(BobbyButton::Down2); - } + if (configs.dpadMappingLeft.value == button) + return Button::Left; + if (configs.dpadMappingRight.value == button) + return Button::Right; + if (configs.dpadMappingUp.value == button) + return Button::Up; + if (configs.dpadMappingDown.value == button) + return Button::Down; + if (configs.dpadMappingProfile0.value == button) + return Button(BobbyButton::Profile0); + if (configs.dpadMappingProfile1.value == button) + return Button(BobbyButton::Profile1); + if (configs.dpadMappingProfile2.value == button) + return Button(BobbyButton::Profile2); + if (configs.dpadMappingProfile3.value == button) + return Button(BobbyButton::Profile3); + if (configs.dpadMappingLeft2.value == button) + return Button(BobbyButton::Left2); + if (configs.dpadMappingRight2.value == button) + return Button(BobbyButton::Right2); + if (configs.dpadMappingUp2.value == button) + return Button(BobbyButton::Up2); + if (configs.dpadMappingDown2.value == button) + return Button(BobbyButton::Down2); return std::nullopt; } diff --git a/main/can.cpp b/main/can.cpp index 8a152b6..075b302 100644 --- a/main/can.cpp +++ b/main/can.cpp @@ -13,12 +13,13 @@ // 3rdparty lib includes #include #include +#include // local includes #include "bobbycar-can.h" #include "globals.h" -#include "buttons.h" #include "newsettings.h" +#include "bobbybuttons.h" using namespace std::chrono_literals; @@ -29,7 +30,6 @@ constexpr const char * const TAG = "BOBBYCAN"; std::optional can_gas, can_brems; espchrono::millis_clock::time_point last_can_gas{}, last_can_brems{}; -CanButtonsState lastButtonsState; void initCan() { @@ -160,47 +160,22 @@ bool parseBoardcomputerCanMessage(const twai_message_t &message) switch (message.identifier) { using namespace bobbycar::protocol::can; - case Boardcomputer::Command::ButtonPress: - { - const auto canButtonBits = *((uint16_t*)message.data); - CanButtonsState newState { - .up = bool(canButtonBits & Boardcomputer::ButtonUp), - .down = bool(canButtonBits & Boardcomputer::ButtonDown), - .confirm = bool(canButtonBits & Boardcomputer::ButtonConfirm), - .back = bool(canButtonBits & Boardcomputer::ButtonBack), - .profile0 = bool(canButtonBits & Boardcomputer::ButtonProfile0), - .profile1 = bool(canButtonBits & Boardcomputer::ButtonProfile1), - .profile2 = bool(canButtonBits & Boardcomputer::ButtonProfile2), - .profile3 = bool(canButtonBits & Boardcomputer::ButtonProfile3), - }; - - if (lastButtonsState.up != newState.up) - InputDispatcher::upButton(newState.up); - - if (lastButtonsState.down != newState.down) - InputDispatcher::downButton(newState.down); - - if (lastButtonsState.confirm != newState.confirm) - InputDispatcher::confirmButton(newState.confirm); - - if (lastButtonsState.back != newState.back) - InputDispatcher::backButton(newState.back); - - if (lastButtonsState.profile0 != newState.profile0) - InputDispatcher::profileButton(0, newState.profile0); - - if (lastButtonsState.profile1 != newState.profile1) - InputDispatcher::profileButton(1, newState.profile1); - - if (lastButtonsState.profile2 != newState.profile2) - InputDispatcher::profileButton(2, newState.profile2); - - if (lastButtonsState.profile3 != newState.profile3) - InputDispatcher::profileButton(3, newState.profile3); - - lastButtonsState = newState; + case Boardcomputer::Command::RawButtonPressed: + if (espgui::currentDisplay) + espgui::currentDisplay->rawButtonPressed(*((const uint8_t*)message.data)); + break; + case Boardcomputer::Command::RawButtonReleased: + if (espgui::currentDisplay) + espgui::currentDisplay->rawButtonReleased(*((const uint8_t*)message.data)); + break; + case Boardcomputer::Command::ButtonPressed: + if (espgui::currentDisplay) + espgui::currentDisplay->rawButtonPressed(espgui::Button(*((const uint8_t*)message.data))); + break; + case Boardcomputer::Command::ButtonReleased: + if (espgui::currentDisplay) + espgui::currentDisplay->rawButtonPressed(espgui::Button(*((const uint8_t*)message.data))); break; - } case Boardcomputer::Command::RawGas: can_gas = *((int16_t*)message.data); last_can_gas = espchrono::millis_clock::now(); diff --git a/main/debuginputhandler.cpp b/main/debuginputhandler.cpp index 02c38c7..89bbeb9 100644 --- a/main/debuginputhandler.cpp +++ b/main/debuginputhandler.cpp @@ -10,12 +10,12 @@ // 3rdparty lib includes #include #include +#include // local includes #include "globals.h" #include "utils.h" -#include "screens.h" -#include "buttons.h" +#include "bobbybuttons.h" namespace { constexpr const char * const TAG = "DEBUG"; @@ -54,83 +54,127 @@ void handleDebugInput() for (char c : std::string_view{data, length}) { - switch (c) + if (consoleControlCharsReceived < 2) { - case 'i': - case 'I': - espgui::tft.init(); - break; - case 'p': - case 'P': - { - const auto firstPower = controllers.front.command.poweroff; - for (Controller &controller : controllers) - controller.command.poweroff = !firstPower; - break; + switch (c) + { + case '\x1b': + if (consoleControlCharsReceived == 0) + consoleControlCharsReceived = 1; + else + consoleControlCharsReceived = 0; + break; + case '\x5b': + if (consoleControlCharsReceived == 1) + consoleControlCharsReceived = 2; + else + consoleControlCharsReceived = 0; + break; + case 'i': + case 'I': + consoleControlCharsReceived = 0; + espgui::tft.init(); + break; + case 'p': + case 'P': + { + consoleControlCharsReceived = 0; + const auto firstPower = controllers.front.command.poweroff; + for (Controller &controller : controllers) + controller.command.poweroff = !firstPower; + break; + } + case 'l': + case 'L': + { + consoleControlCharsReceived = 0; + const auto firstLed = controllers.front.command.led; + for (Controller &controller : controllers) + controller.command.led = !firstLed; + break; + } + case 'r': + case 'R': + consoleControlCharsReceived = 0; + loadSettings(); + break; + case 's': + case 'S': + consoleControlCharsReceived = 0; + saveSettings(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + consoleControlCharsReceived = 0; + for (Controller &controller : controllers) + controller.command.buzzer.freq = c-'0'; + break; + case 'z': + case 'Z': + consoleControlCharsReceived = 0; + if (espgui::currentDisplay) + { + espgui::currentDisplay->buttonPressed(espgui::Button(BobbyButton::Left2)); + espgui::currentDisplay->buttonReleased(espgui::Button(BobbyButton::Left2)); + } + break; + case 'u': + case 'U': + consoleControlCharsReceived = 0; + if (espgui::currentDisplay) + { + espgui::currentDisplay->buttonPressed(espgui::Button(BobbyButton::Right2)); + espgui::currentDisplay->buttonReleased(espgui::Button(BobbyButton::Right2)); + } + break; + default: + consoleControlCharsReceived = 0; + } } - case 'l': - case 'L': + else { - const auto firstLed = controllers.front.command.led; - for (Controller &controller : controllers) - controller.command.led = !firstLed; - break; - } - case 'r': - case 'R': - loadSettings(); - break; - case 's': - case 'S': - saveSettings(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - for (Controller &controller : controllers) - controller.command.buzzer.freq = c-'0'; - break; - case 'A': - InputDispatcher::rotate(-1); - break; - case 'B': - InputDispatcher::rotate(1); - break; - case 'C': - InputDispatcher::confirmButton(true); - InputDispatcher::confirmButton(false); - break; - case 'D': - InputDispatcher::backButton(true); - InputDispatcher::backButton(false); - break; - case 'z': - case 'Z': -#ifndef LEDSTRIP_WRONG_DIRECTION - InputDispatcher::blinkLeftButton(true); - InputDispatcher::blinkLeftButton(false); -#else - InputDispatcher::blinkRightButton(true); - InputDispatcher::blinkRightButton(false); -#endif - break; - case 'u': - case 'U': -#ifndef LEDSTRIP_WRONG_DIRECTION - InputDispatcher::blinkRightButton(true); - InputDispatcher::blinkRightButton(false); -#else - InputDispatcher::blinkLeftButton(true); - InputDispatcher::blinkLeftButton(false); -#endif - break; + consoleControlCharsReceived = 0; + switch (c) + { + case 'A': // Up arrow pressed + if (espgui::currentDisplay) + { + espgui::currentDisplay->buttonPressed(espgui::Button::Up); + espgui::currentDisplay->buttonReleased(espgui::Button::Up); + } + break; + case 'B': // Down arrow pressed + if (espgui::currentDisplay) + { + espgui::currentDisplay->buttonPressed(espgui::Button::Down); + espgui::currentDisplay->buttonReleased(espgui::Button::Down); + } + break; + case 'C': // Right arrow pressed + if (espgui::currentDisplay) + { + espgui::currentDisplay->buttonPressed(espgui::Button::Right); + espgui::currentDisplay->buttonReleased(espgui::Button::Right); + } + break; + case 'D': // Left arrow pressed + if (espgui::currentDisplay) + { + espgui::currentDisplay->buttonPressed(espgui::Button::Left); + espgui::currentDisplay->buttonReleased(espgui::Button::Left); + } + break; + default: + ESP_LOGI(TAG, "unknown control char received: %hhx", c); + } } } } diff --git a/main/displays/lockscreen.cpp b/main/displays/lockscreen.cpp index b0d5c9a..4c1d843 100644 --- a/main/displays/lockscreen.cpp +++ b/main/displays/lockscreen.cpp @@ -8,9 +8,9 @@ #include "globals.h" #include "utils.h" #include "texts.h" -#include "buttons.h" #include "displays/menus/mainmenu.h" #include "displays/calibratedisplay.h" +#include "bobbybuttons.h" void Lockscreen::start() { @@ -24,7 +24,6 @@ void Lockscreen::start() m_oldMode = currentMode; currentMode = &m_mode; - profileButtonDisabled = !settings.lockscreen.allowPresetSwitch; isLocked = true; if (settings.lockscreen.keepLockedAfterReboot && !settings.lockscreen.locked) { @@ -71,9 +70,6 @@ void Lockscreen::initScreen() void Lockscreen::update() { Base::update(); - - // just in case someone changes that settings somehow - profileButtonDisabled = !settings.lockscreen.allowPresetSwitch; } void Lockscreen::redraw() @@ -147,7 +143,6 @@ void Lockscreen::stop() currentMode = m_oldMode; } - profileButtonDisabled = false; isLocked = false; if (!(!gas || !brems || *gas > 200.f || *brems > 200.f)) { @@ -161,6 +156,8 @@ void Lockscreen::stop() void Lockscreen::buttonPressed(espgui::Button button) { + if (settings.lockscreen.allowPresetSwitch || + !cpputils::is_in(button, BobbyButton::Profile0, BobbyButton::Profile1, BobbyButton::Profile2, BobbyButton::Profile3)) Base::buttonPressed(button); switch (button) diff --git a/main/newsettings.h b/main/newsettings.h index 4b417c1..ccc0b3c 100644 --- a/main/newsettings.h +++ b/main/newsettings.h @@ -24,6 +24,8 @@ using namespace espconfig; std::string defaultHostname(); +constexpr const auto INPUT_MAPPING_NONE = std::numeric_limits::max(); + class WiFiConfig { public: @@ -126,6 +128,19 @@ public: ConfigWrapper dpadDebounce {25, DoReset, {}, "dpadDebounce" }; + ConfigWrapper dpadMappingLeft {INPUT_MAPPING_NONE, DoReset, {}, "dpadMapLeft" }; + ConfigWrapper dpadMappingRight {INPUT_MAPPING_NONE, DoReset, {}, "dpadMapRight" }; + ConfigWrapper dpadMappingUp {INPUT_MAPPING_NONE, DoReset, {}, "dpadMapUp" }; + ConfigWrapper dpadMappingDown {INPUT_MAPPING_NONE, DoReset, {}, "dpadMapDown" }; + ConfigWrapper dpadMappingProfile0{INPUT_MAPPING_NONE, DoReset, {}, "dpadMapProfile0" }; + ConfigWrapper dpadMappingProfile1{INPUT_MAPPING_NONE, DoReset, {}, "dpadMapProfile1" }; + ConfigWrapper dpadMappingProfile2{INPUT_MAPPING_NONE, DoReset, {}, "dpadMapProfile2" }; + ConfigWrapper dpadMappingProfile3{INPUT_MAPPING_NONE, DoReset, {}, "dpadMapProfile3" }; + ConfigWrapper dpadMappingLeft2 {INPUT_MAPPING_NONE, DoReset, {}, "dpadMapLeft2" }; + ConfigWrapper dpadMappingRight2 {INPUT_MAPPING_NONE, DoReset, {}, "dpadMapRight2" }; + ConfigWrapper dpadMappingUp2 {INPUT_MAPPING_NONE, DoReset, {}, "dpadMapUp2" }; + ConfigWrapper dpadMappingDown2 {INPUT_MAPPING_NONE, DoReset, {}, "dpadMapDown2" }; + std::array wireless_door_configs { WirelessDoorsConfig { "door_id0", "door_token0" }, WirelessDoorsConfig { "door_id1", "door_token1" }, @@ -294,6 +309,19 @@ public: \ x(dpadDebounce) \ \ + x(dpadMappingLeft) \ + x(dpadMappingRight) \ + x(dpadMappingUp) \ + x(dpadMappingDown) \ + x(dpadMappingProfile0) \ + x(dpadMappingProfile1) \ + x(dpadMappingProfile2) \ + x(dpadMappingProfile3) \ + x(dpadMappingLeft2) \ + x(dpadMappingRight2) \ + x(dpadMappingUp2) \ + x(dpadMappingDown2) \ + \ x(wireless_door_configs[0].doorId) \ x(wireless_door_configs[0].doorToken) \ x(wireless_door_configs[1].doorId) \ diff --git a/main/serialhandler.cpp b/main/serialhandler.cpp deleted file mode 100644 index 7b499d1..0000000 --- a/main/serialhandler.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "serialhandler.h" - -// Arduino includes -#include - -// 3rdparty lib includes -#include - -// local includes -#include "globals.h" -#include "utils.h" -#include "screens.h" -#include "buttons.h" - -using namespace espgui; - -//wl_status_t last_status; -//IPAddress last_ip; - -void handleSerial() -{ - //const auto status = WiFi.status(); - //if (last_status != status) - //{ - //Serial.print("Status changed to: "); - //Serial.println(to_string(status).c_str()); - //last_status = status; - //} - - //const auto ip = WiFi.localIP(); - //if (last_ip != ip) - //{ - //Serial.print("IP changed to: "); - //Serial.println(to_string(ip).c_str()); - //last_ip = ip; - //} - - while(Serial.available()) - { - const auto c = Serial.read(); - - switch (c) - { - case 'i': - case 'I': - tft.init(); - break; - case 'p': - case 'P': - { - const auto firstPower = controllers.front.command.poweroff; - for (Controller &controller : controllers) - controller.command.poweroff = !firstPower; - break; - } - case 'l': - case 'L': - { - const auto firstLed = controllers.front.command.led; - for (Controller &controller : controllers) - controller.command.led = !firstLed; - break; - } - case 'r': - case 'R': - loadSettings(); - break; - case 's': - case 'S': - saveSettings(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - for (Controller &controller : controllers) - controller.command.buzzer.freq = c-'0'; - break; - case 'A': - InputDispatcher::rotate(-1); - break; - case 'B': - InputDispatcher::rotate(1); - break; - case 'C': - InputDispatcher::confirmButton(true); - InputDispatcher::confirmButton(false); - break; - case 'D': - InputDispatcher::backButton(true); - InputDispatcher::backButton(false); - break; - case 'z': - case 'Z': -#ifndef LEDSTRIP_WRONG_DIRECTION - InputDispatcher::blinkLeftButton(true); - InputDispatcher::blinkLeftButton(false); -#else - InputDispatcher::blinkRightButton(true); - InputDispatcher::blinkRightButton(false); -#endif - break; - case 'u': - case 'U': -#ifndef LEDSTRIP_WRONG_DIRECTION - InputDispatcher::blinkRightButton(true); - InputDispatcher::blinkRightButton(false); -#else - InputDispatcher::blinkLeftButton(true); - InputDispatcher::blinkLeftButton(false); -#endif - break; - } - } -} diff --git a/main/webserver.cpp b/main/webserver.cpp index 899722c..8798732 100644 --- a/main/webserver.cpp +++ b/main/webserver.cpp @@ -59,7 +59,7 @@ void initWebserver() { httpd_config_t httpConfig HTTPD_DEFAULT_CONFIG(); httpConfig.core_id = 1; - httpConfig.max_uri_handlers = 15; + httpConfig.max_uri_handlers = 16; httpConfig.stack_size = 8192; const auto result = httpd_start(&httpdHandle, &httpConfig); @@ -70,6 +70,7 @@ void initWebserver() for (const httpd_uri_t &uri : { httpd_uri_t { .uri = "/", .method = HTTP_GET, .handler = webserver_root_handler, .user_ctx = NULL }, + httpd_uri_t { .uri = "/triggerRawButton", .method = HTTP_GET, .handler = webserver_triggerRawButton_handler, .user_ctx = NULL }, httpd_uri_t { .uri = "/triggerButton", .method = HTTP_GET, .handler = webserver_triggerButton_handler, .user_ctx = NULL }, httpd_uri_t { .uri = "/triggerItem", .method = HTTP_GET, .handler = webserver_triggerItem_handler, .user_ctx = NULL }, httpd_uri_t { .uri = "/setValue", .method = HTTP_GET, .handler = webserver_setValue_handler, .user_ctx = NULL }, diff --git a/main/webserver_displaycontrol.cpp b/main/webserver_displaycontrol.cpp index f3ffc99..32227c7 100644 --- a/main/webserver_displaycontrol.cpp +++ b/main/webserver_displaycontrol.cpp @@ -15,13 +15,14 @@ #include #include #include +#include #include #include #include +#include // local includes -#include "buttons.h" -#include "globals.h" +#include "bobbybuttons.h" #include "webserver_lock.h" #include "newsettings.h" @@ -190,14 +191,48 @@ esp_err_t webserver_root_handler(httpd_req_t *req) { HtmlTag pTag{"p", body}; - body += "Up " - "Down " - "Confirm " - "Back " - "Profile0 " - "Profile1 " - "Profile2 " - "Profile3 "; + body += "Trigger raw button: " + "Button0 " + "Button1 " + "Button2 " + "Button3 " + "Button4 " + "Button5 " + "Button6 " + "Button7 " + "Button8 " + "Button9 " + "Button10 " + "Button11"; + } + + { + HtmlTag pTag{"p", body}; + body += fmt::format("Trigger button: " + "Left " + "Right " + "Up " + "Down " + "Profile0 " + "Profile1 " + "Profile2 " + "Profile3 " + "Left2 " + "Right2 " + "Up2 " + "Down2", + std::to_underlying(espgui::Button::Left), + std::to_underlying(espgui::Button::Right), + std::to_underlying(espgui::Button::Up), + std::to_underlying(espgui::Button::Down), + std::to_underlying(BobbyButton::Profile0), + std::to_underlying(BobbyButton::Profile1), + std::to_underlying(BobbyButton::Profile2), + std::to_underlying(BobbyButton::Profile3), + std::to_underlying(BobbyButton::Left2), + std::to_underlying(BobbyButton::Right2), + std::to_underlying(BobbyButton::Up2), + std::to_underlying(BobbyButton::Down2)); } if (auto currentDisplay = static_cast(espgui::currentDisplay.get())) @@ -228,6 +263,12 @@ esp_err_t webserver_root_handler(httpd_req_t *req) body += fmt::format("", changeValueDisplay->shownValue()); body += ""; } + else if (const auto *changeValueDisplay = currentDisplay->asChangeValueDisplayString()) + { + HtmlTag formTag{"form", "action=\"/setValue\" method=\"GET\"", body}; + body += fmt::format("", changeValueDisplay->shownValue()); + body += ""; + } else { body += "No web control implemented for current display."; @@ -243,9 +284,8 @@ esp_err_t webserver_root_handler(httpd_req_t *req) CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::Ok, (key_result == ESP_OK) ? "application/json":"text/html", body) } -esp_err_t webserver_triggerButton_handler(httpd_req_t *req) +esp_err_t webserver_triggerRawButton_handler(httpd_req_t *req) { - #ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; if (!helper.locked()) @@ -265,7 +305,7 @@ esp_err_t webserver_triggerButton_handler(httpd_req_t *req) CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", result.error()); } - std::string button; + uint8_t button; constexpr const std::string_view buttonParamName{"button"}; { @@ -289,77 +329,105 @@ esp_err_t webserver_triggerButton_handler(httpd_req_t *req) char valueBuf[257]; esphttpdutils::urldecode(valueBuf, valueBufEncoded); - button = valueBuf; + std::string_view value{valueBuf}; + + if (auto parsed = cpputils::fromString(value)) + { + button = *parsed; + } + else + { + const auto msg = fmt::format("could not parse {} {}", buttonParamName, value); + ESP_LOGW(TAG, "%.*s", msg.size(), msg.data()); + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); + } } - if (button == "up") + if (!espgui::currentDisplay) { - InputDispatcher::rotate(-1); - - CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Location", "/") - CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::TemporaryRedirect, "text/html", "Ok, continue at /") - } - else if (button == "down") - { - InputDispatcher::rotate(1); - - CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Location", "/") - CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::TemporaryRedirect, "text/html", "Ok, continue at /") - } - else if (button == "confirm") - { - InputDispatcher::confirmButton(true); - InputDispatcher::confirmButton(false); - - CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Location", "/") - CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::TemporaryRedirect, "text/html", "Ok, continue at /") - } - else if (button == "back") - { - InputDispatcher::backButton(true); - InputDispatcher::backButton(false); - - CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Location", "/") - CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::TemporaryRedirect, "text/html", "Ok, continue at /") - } - else if (button == "profile0") - { - InputDispatcher::profileButton(0, true); - InputDispatcher::profileButton(0, false); - - CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Location", "/") - CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::TemporaryRedirect, "text/html", "Ok, continue at /") - } - else if (button == "profile1") - { - InputDispatcher::profileButton(1, true); - InputDispatcher::profileButton(1, false); - - CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Location", "/") - CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::TemporaryRedirect, "text/html", "Ok, continue at /") - } - else if (button == "profile2") - { - InputDispatcher::profileButton(2, true); - InputDispatcher::profileButton(2, false); - - CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Location", "/") - CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::TemporaryRedirect, "text/html", "Ok, continue at /") - } - else if (button == "profile3") - { - InputDispatcher::profileButton(3, true); - InputDispatcher::profileButton(3, false); - - CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Location", "/") - CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::TemporaryRedirect, "text/html", "Ok, continue at /") - } - else - { - const auto msg = fmt::format("invalid {} {}", buttonParamName, button); + constexpr const std::string_view msg = "espgui::currentDisplay is null"; ESP_LOGW(TAG, "%.*s", msg.size(), msg.data()); CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); } + + espgui::currentDisplay->rawButtonPressed(button); + espgui::currentDisplay->rawButtonReleased(button); + + CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Location", "/") + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::TemporaryRedirect, "text/html", "Ok, continue at /") +} + +esp_err_t webserver_triggerButton_handler(httpd_req_t *req) +{ +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET + espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; + if (!helper.locked()) + { + constexpr const std::string_view msg = "could not lock webserver_lock"; + ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); + } +#endif + + std::string query; + if (auto result = esphttpdutils::webserver_get_query(req)) + query = *result; + else + { + ESP_LOGE(TAG, "%.*s", result.error().size(), result.error().data()); + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", result.error()); + } + + espgui::Button button; + constexpr const std::string_view buttonParamName{"button"}; + + { + char valueBufEncoded[256]; + if (const auto result = httpd_query_key_value(query.data(), buttonParamName.data(), valueBufEncoded, 256); result != ESP_OK) + { + if (result == ESP_ERR_NOT_FOUND) + { + const auto msg = fmt::format("{} not set", buttonParamName); + ESP_LOGW(TAG, "%.*s", msg.size(), msg.data()); + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); + } + else + { + const auto msg = fmt::format("httpd_query_key_value() {} failed with {}", buttonParamName, esp_err_to_name(result)); + ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); + } + } + + char valueBuf[257]; + esphttpdutils::urldecode(valueBuf, valueBufEncoded); + + std::string_view value{valueBuf}; + + if (auto parsed = cpputils::fromString>(value)) + { + button = espgui::Button(*parsed); + } + else + { + const auto msg = fmt::format("could not parse {} {}", buttonParamName, value); + ESP_LOGW(TAG, "%.*s", msg.size(), msg.data()); + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); + } + } + + if (!espgui::currentDisplay) + { + constexpr const std::string_view msg = "espgui::currentDisplay is null"; + ESP_LOGW(TAG, "%.*s", msg.size(), msg.data()); + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); + } + + espgui::currentDisplay->buttonPressed(button); + espgui::currentDisplay->buttonReleased(button); + + CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Location", "/") + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::TemporaryRedirect, "text/html", "Ok, continue at /") } esp_err_t webserver_triggerItem_handler(httpd_req_t *req) @@ -471,8 +539,7 @@ esp_err_t webserver_setValue_handler(httpd_req_t *req) CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", result.error()); } - int newValue; - + char valueBuf[257]; constexpr const std::string_view valueParamName{"value"}; { @@ -493,11 +560,21 @@ esp_err_t webserver_setValue_handler(httpd_req_t *req) } } - char valueBuf[257]; esphttpdutils::urldecode(valueBuf, valueBufEncoded); + } - std::string_view value{valueBuf}; + std::string_view value{valueBuf}; + if (!espgui::currentDisplay) + { + constexpr const std::string_view msg = "espgui::currentDisplay is null"; + ESP_LOGW(TAG, "%.*s", msg.size(), msg.data()); + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); + } + + if (auto *changeValueDisplay = espgui::currentDisplay->asChangeValueDisplayInterface()) + { + int newValue; if (auto parsed = cpputils::fromString(value)) { newValue = *parsed; @@ -508,24 +585,20 @@ esp_err_t webserver_setValue_handler(httpd_req_t *req) ESP_LOGW(TAG, "%.*s", msg.size(), msg.data()); CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); } - } - if (!espgui::currentDisplay) + changeValueDisplay->setShownValue(newValue); + } + else if (auto *changeValueDisplay = espgui::currentDisplay->asChangeValueDisplayString()) { - constexpr const std::string_view msg = "espgui::currentDisplay is null"; - ESP_LOGW(TAG, "%.*s", msg.size(), msg.data()); - CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); + changeValueDisplay->setShownValue(std::string{value}); } - - auto *changeValueDisplay = espgui::currentDisplay->asChangeValueDisplayInterface(); - if (!changeValueDisplay) + else { constexpr const std::string_view msg = "espgui::currentDisplay is not a change value display"; ESP_LOGW(TAG, "%.*s", msg.size(), msg.data()); CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); } - changeValueDisplay->setShownValue(newValue); CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Location", "/") CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::TemporaryRedirect, "text/html", "Ok, continue at /") diff --git a/main/webserver_displaycontrol.h b/main/webserver_displaycontrol.h index 7a7736e..90a6fbf 100644 --- a/main/webserver_displaycontrol.h +++ b/main/webserver_displaycontrol.h @@ -8,6 +8,7 @@ #ifdef FEATURE_WEBSERVER esp_err_t webserver_root_handler(httpd_req_t *req); +esp_err_t webserver_triggerRawButton_handler(httpd_req_t *req); esp_err_t webserver_triggerButton_handler(httpd_req_t *req); esp_err_t webserver_triggerItem_handler(httpd_req_t *req); esp_err_t webserver_setValue_handler(httpd_req_t *req);