From 2ee7d5b531b5f51bb5d4cb2c2d57a0cb7d2c93c1 Mon Sep 17 00:00:00 2001 From: 0xFEEDC0DE64 Date: Fri, 22 May 2020 23:53:30 +0200 Subject: [PATCH] Implement basic web server --- src/changevaluedisplay.h | 3 + src/display.h | 4 + src/displays/menus/wifiscanmenu.h | 7 ++ src/main.cpp | 5 ++ src/menudefinitioninterface.h | 1 + src/menudisplay.h | 3 + src/staticmenudefinition.h | 11 +++ src/webserver.h | 135 ++++++++++++++++++++++++++++++ 8 files changed, 169 insertions(+) create mode 100644 src/webserver.h diff --git a/src/changevaluedisplay.h b/src/changevaluedisplay.h index 484bd6f..fab703f 100644 --- a/src/changevaluedisplay.h +++ b/src/changevaluedisplay.h @@ -14,6 +14,9 @@ class ChangeValueDisplayInterface : public Display, public virtual TextInterface public: void initScreen() override; + TextInterface *asTextInterface() override { return this; } + const TextInterface *asTextInterface() const override { return this; } + ChangeValueDisplayInterface *asChangeValueDisplayInterface() override { return this; } const ChangeValueDisplayInterface *asChangeValueDisplayInterface() const override { return this; } diff --git a/src/display.h b/src/display.h index 4e95c49..a1039d1 100644 --- a/src/display.h +++ b/src/display.h @@ -3,6 +3,7 @@ #include namespace { +class TextInterface; class MenuDisplay; class ChangeValueDisplayInterface; } @@ -21,6 +22,9 @@ public: virtual void rotate(int offset) {} virtual void button() {} + virtual TextInterface *asTextInterface() { return nullptr; } + virtual const TextInterface *asTextInterface() const { return nullptr; } + virtual MenuDisplay *asMenuDisplay() { return nullptr; } virtual const MenuDisplay *asMenuDisplay() const { return nullptr; } diff --git a/src/displays/menus/wifiscanmenu.h b/src/displays/menus/wifiscanmenu.h index 08a1ddc..18d0c5e 100644 --- a/src/displays/menus/wifiscanmenu.h +++ b/src/displays/menus/wifiscanmenu.h @@ -36,6 +36,13 @@ public: callback(m_backItem); } + void runForEveryMenuItem(std::function &&callback) const override + { + for (auto &item : vec) + callback(item); + callback(m_backItem); + } + private: makeComponent, SwitchScreenAction, StaticMenuItemIcon<&icons::back>> m_backItem; diff --git a/src/main.cpp b/src/main.cpp index ba83764..b798bcf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,6 +18,7 @@ #include "statistics.h" #include "actions/bluetoothbeginmasteraction.h" #include "actions/bluetoothconnectbmsaction.h" +#include "webserver.h" namespace { ModeInterface *lastMode{}; @@ -84,6 +85,8 @@ void setup() initOta(); + initWebserver(); + readPotis(); if (gas > 200.f || brems > 200.f) @@ -159,5 +162,7 @@ void loop() handleOta(); + handleWebserver(); + bms::update(); } diff --git a/src/menudefinitioninterface.h b/src/menudefinitioninterface.h index e86a6ab..6e6ebe6 100644 --- a/src/menudefinitioninterface.h +++ b/src/menudefinitioninterface.h @@ -9,5 +9,6 @@ class MenuDefinitionInterface { public: virtual void runForEveryMenuItem(std::function &&callback) = 0; + virtual void runForEveryMenuItem(std::function &&callback) const = 0; }; } diff --git a/src/menudisplay.h b/src/menudisplay.h index 37e61eb..6c89d85 100644 --- a/src/menudisplay.h +++ b/src/menudisplay.h @@ -26,6 +26,9 @@ public: virtual void itemPressed(int index); + TextInterface *asTextInterface() override { return this; } + const TextInterface *asTextInterface() const override { return this; } + MenuDisplay *asMenuDisplay() override { return this; } const MenuDisplay *asMenuDisplay() const override { return this; } diff --git a/src/staticmenudefinition.h b/src/staticmenudefinition.h index 5dc4e90..6f3d189 100644 --- a/src/staticmenudefinition.h +++ b/src/staticmenudefinition.h @@ -15,6 +15,11 @@ public: callback(item); } + void runForEveryMenuItem(std::function &&callback) const override + { + callback(item); + } + private: T item; }; @@ -31,6 +36,12 @@ public: Base::runForEveryMenuItem(std::move(callback)); } + void runForEveryMenuItem(std::function &&callback) const override + { + callback(item); + Base::runForEveryMenuItem(std::move(callback)); + } + private: T item; }; diff --git a/src/webserver.h b/src/webserver.h new file mode 100644 index 0000000..d0e1e23 --- /dev/null +++ b/src/webserver.h @@ -0,0 +1,135 @@ +#pragma once + +#include + +#include "screens.h" + +namespace { +WebServer webServer{80}; + +class HtmlTag { +public: + HtmlTag(const String &tagName, String &content) : + m_tagName{tagName}, + m_content{content} + { + content += "<" + tagName + ">"; + } + + ~HtmlTag() + { + m_content += ""; + } + +private: + const String m_tagName; + String &m_content; +}; + +void initWebserver() +{ + webServer.on("/", HTTP_GET, [](){ + webServer.sendHeader("Connection", "close"); + + String content; + + { + HtmlTag htmlTag{"html", content}; + + { + HtmlTag headTag{"head", content}; + + HtmlTag titleTag{"title", content}; + content += "Bobbycar remote"; + } + + { + HtmlTag bodyTag{"body", content}; + + { + HtmlTag h1Tag{"h1", content}; + content += "Bobbycar remote"; + } + + { + HtmlTag pTag{"p", content}; + + content += "Up Down Confirm"; + } + + if (auto constCurrentDisplay = static_cast(currentDisplay)) + { + if (const auto *textInterface = currentDisplay->asTextInterface()) + { + HtmlTag h2Tag{"h2", content}; + content += textInterface->text(); + } + + if (const auto *menuDisplay = currentDisplay->asMenuDisplay()) + { + HtmlTag ulTag{"ul", content}; + + int i{0}; + menuDisplay->runForEveryMenuItem([&,selectedIndex=menuDisplay->selectedIndex()](const MenuItem &menuItem){ + content += ""; + + i++; + }); + } + else if (const auto *changeValueDisplay = currentDisplay->asChangeValueDisplayInterface()) + { + content += "shownValue()} + "\" />"; + } + else + { + content += "No web control implemented for current display."; + } + } + else + { + content += "Currently no screen instantiated."; + } + } + } + + webServer.send(200, "text/html", content); + }); + + webServer.on("/up", HTTP_GET, [](){ + InputDispatcher::rotate(-1); + + webServer.sendHeader("Connection", "close"); + webServer.sendHeader("Location", "/"); + webServer.send(302, "text/html", "ok"); + }); + + webServer.on("/down", HTTP_GET, [](){ + InputDispatcher::rotate(1); + + webServer.sendHeader("Connection", "close"); + webServer.sendHeader("Location", "/"); + webServer.send(302, "text/html", "ok"); + }); + + webServer.on("/confirm", HTTP_GET, [](){ + InputDispatcher::button(true); + InputDispatcher::button(false); + + webServer.sendHeader("Connection", "close"); + webServer.sendHeader("Location", "/"); + webServer.send(302, "text/html", "ok"); + }); + + webServer.begin(); +} + +void handleWebserver() +{ + webServer.handleClient(); +} +}