Переглянути джерело

DK-42 implement DisplayManager basics

Bence Balint 2 роки тому
батько
коміт
71fbc05ecf

+ 1 - 0
components/dk/CMakeLists.txt

@@ -15,6 +15,7 @@ idf_component_register(
         "src/pairing_service/verify_controller.cpp"
 
         "src/tasks/boot.cpp"
+        "src/tasks/display_manager.cpp"
         "src/tasks/main.cpp"
 
         INCLUDE_DIRS

+ 3 - 0
components/dk/include/api/ping_controller.h

@@ -3,12 +3,15 @@
 
 #include <kbf/web_service.h>
 
+#include "tasks/display_manager.h"
+
 class PingController : public kbf::WebService::Controller {
 public:
     PingController() : Controller("/ping") {}
 
 protected:
     kbf::http::Response get(const kbf::http::Request &request) override {
+        DisplayManager::setMessage("ping received", DisplayManager::defaultTimeout);
         return kbf::http::Response(nlohmann::json({{"success", true}}));
     }
 };

+ 0 - 4
components/dk/include/dk.h

@@ -41,10 +41,6 @@ namespace dk {
 
     // old stuff starts here
 
-    extern kbf::driver::LCD lcd; // TODO move to DisplayManager
-
-    void showMessage(const string &message); // TODO move to DisplayManager
-
     void testNotification(); // TODO move to EventManager (?)
 }
 

+ 85 - 0
components/dk/include/tasks/display_manager.h

@@ -0,0 +1,85 @@
+#ifndef DOORKEEPER_DEV_DISPLAY_MANAGER_H
+#define DOORKEEPER_DEV_DISPLAY_MANAGER_H
+
+#include <atomic>
+#include <memory>
+#include <string>
+
+#include <kbf.h>
+#include <kbf/driver/lcd.h>
+#include <kbf/rtos.h>
+#include <kbf/task.h>
+
+class DisplayManager : public kbf::task::Task {
+public:
+    static constexpr const char *const TAG = "DisplayManager";
+
+    static const int defaultTimeout;
+
+    DisplayManager(const std::string &name, void *arg, uint32_t stackSize, uint32_t priority);
+
+    static void start();
+
+    enum class WifiState {
+        AP,
+        ONLINE,
+        OFFLINE,
+        CONNECTING,
+    };
+
+    static void setWifiState(WifiState state);
+
+    enum class DoorState {
+        NOT_CALIBRATED,
+        OPEN,
+        CLOSED,
+    };
+
+    static void setDoorState(DoorState state);
+
+    static void setStatus(std::string text);
+
+    static void setMessage(std::string text, int timeoutMs = 0);
+
+protected:
+    [[noreturn]] void run(void *arg) override;
+
+private:
+    // TODO use Kconfig
+    static std::shared_ptr<kbf::driver::LCD> lcd;
+
+    static std::atomic<WifiState> wifiState;
+    static std::atomic<DoorState> doorState;
+    static std::string            status;
+    static std::string            message;
+
+    static std::shared_ptr<kbf::rtos::EventGroup> eventGroup;
+    struct Events {
+        static const constexpr unsigned int WIFI    = 0;
+        static const constexpr unsigned int DOOR    = 1;
+        static const constexpr unsigned int STATUS  = 2;
+        static const constexpr unsigned int MESSAGE = 3;
+    };
+
+    const std::vector<int> ALL_EVENTS = {
+            Events::WIFI,
+            Events::DOOR,
+            Events::STATUS,
+            Events::MESSAGE,
+    };
+
+    class MessageTimeout : public kbf::task::Task {
+    public:
+        MessageTimeout(const std::string &name, void *arg, uint32_t stackSize, uint32_t priority) :
+                Task(name, arg, stackSize, priority) {}
+
+    protected:
+        void run(void *arg) override;
+    };
+
+    static std::shared_ptr<kbf::task::Task> messageTimeout;
+
+    static std::atomic<int> timeoutMs_;
+};
+
+#endif //DOORKEEPER_DEV_DISPLAY_MANAGER_H

+ 11 - 1
components/dk/src/api/calibrate_controller.cpp

@@ -5,6 +5,7 @@
 #include <kbf.h>
 
 #include "settings_manager.h"
+#include "tasks/display_manager.h"
 
 using namespace kbf;
 using http::Request;
@@ -21,6 +22,8 @@ Response CalibrateController::get(const Request &request) {
 Response CalibrateController::post(const Request &request) {
     ESP_LOGD(TAG, "%s()", __func__);
 
+    DisplayManager::setMessage("calibrating...");
+
     auto sensor = driver::Ultrasonic(5, 18); // TODO use Kconfig
 
     int  min   = 99999;
@@ -50,7 +53,14 @@ Response CalibrateController::post(const Request &request) {
     ESP_LOGI(TAG, "%s: min = %d, max = %d", __func__, min, max);
 
     SettingsManager::CalibrationConfig config = {.high = max, .low = min};
-    if (error) config = {.high = 0, .low = 0};
+    if (error) {
+        DisplayManager::setMessage("cal. error", DisplayManager::defaultTimeout);
+        DisplayManager::setDoorState(DisplayManager::DoorState::NOT_CALIBRATED);
+        config = {.high = 0, .low = 0};
+    } else {
+        DisplayManager::setMessage("cal: " + std::to_string(config.low) + " - " + std::to_string(config.high),
+                                   DisplayManager::defaultTimeout);
+    }
     SettingsManager::instance()->setCalibration(config);
 
     return Response({{"high", config.high},

+ 3 - 10
components/dk/src/dk.cpp

@@ -8,6 +8,7 @@
 #include <kbf/http/client.h>
 
 #include "settings_manager.h"
+#include "tasks/display_manager.h"
 
 
 #define MESSAGE_TIMEOUT 1000 // TODO use Kconfig
@@ -45,20 +46,12 @@ namespace dk {
 
     // old stuff starts here
 
-    driver::LCD lcd = driver::LCD(32, 33, 25, 26, 27, 13); // TODO use Kconfig
-
-    void showMessage(const string &message) {
-        lcd.println(message, 1);
-        kbf::sleep(MESSAGE_TIMEOUT);
-        lcd.println("", 1);
-    }
-
     void testNotification() {
         ESP_LOGI(TAG, "testNotification()");
 
         if (!paired()) {
             ESP_LOGI(TAG, "  not paired");
-            showMessage("not paired");
+            DisplayManager::setMessage("not paired", DisplayManager::defaultTimeout);
             return;
         }
 
@@ -69,6 +62,6 @@ namespace dk {
                                     {{{"X-Pairing-ID", pairingId}}});
         ESP_LOGI(TAG, "test_notification response: %d", response->status);
 
-        showMessage("message sent");
+        DisplayManager::setMessage("message sent", DisplayManager::defaultTimeout);
     }
 }

+ 6 - 6
components/dk/src/pairing_service/pair_controller.cpp

@@ -5,6 +5,7 @@
 #include <kbf/http/client.h>
 
 #include "dk.h"
+#include "tasks/display_manager.h"
 
 using namespace kbf;
 using namespace dk;
@@ -29,10 +30,7 @@ http::Response PairController::post(const http::Request &request) {
     if (!validate(json)) return http::Response("", 500);
     auto firebaseToken = json.find("firebaseToken")->get<string>();
 
-    lcd.clear();
-    kbf::sleep(50);
-    lcd.print("pairing");
-    lcd.move(0, 1);
+    DisplayManager::setMessage("sending request");
 
     auto client = http::Client();
     nlohmann::json data = { // TODO get ID from efuse or nvs
@@ -43,12 +41,14 @@ http::Response PairController::post(const http::Request &request) {
 
     if (response->status != 200) {
         ESP_LOGW(TAG, "failed: %d", response->status);
-        lcd.print("failed");
+        DisplayManager::setMessage("failed", DisplayManager::defaultTimeout);
+        // TODO set pairing mode
+//        mainEventGroup->setBit(MainEvents::SET_PAIRING_MODE);
         return http::Response(nlohmann::json({{"success", false}}));
     }
 
     ESP_LOGI(TAG, "pairing request sent");
-    lcd.print("request sent");
+    DisplayManager::setMessage("request sent");
     return http::Response(nlohmann::json({{"success", true}}));
 }
 

+ 7 - 10
components/dk/src/pairing_service/settings_controller.cpp

@@ -1,13 +1,12 @@
 #include "pairing_service/settings_controller.h"
 
-#include <atomic>
-
 #include <esp_log.h>
 #include <kbf.h>
 #include <kbf/rtos.h>
 #include <kbf/wifi.h>
 
 #include "dk.h"
+#include "tasks/display_manager.h"
 
 using namespace kbf;
 
@@ -40,6 +39,7 @@ static bool connect(const string &ssid, const string &password) {
     ESP_LOGD(TAG, "credentials: %s; %s", ssid.c_str(), password.c_str());
 
     eventGroup.clear();
+    wifi::sta::start();
     wifi::sta::onDisconnect = {[]() { eventGroup.setBit(DISCONNECTED); }};
     wifi::sta::onIp         = {[]() { eventGroup.setBit(GOT_IP); }};
     wifi::sta::connect(ssid, password, true, 2);
@@ -75,15 +75,13 @@ http::Response SettingsController::post(const kbf::http::Request &request) {
     auto ssid     = json.find("ssid")->get<string>();
     auto password = json.find("password")->get<string>();
 
-    dk::lcd.clear();
-    dk::lcd.print("SSID: " + ssid);
-    dk::lcd.move(0, 1);
-    dk::lcd.print("connecting...");
+    DisplayManager::setMessage("SSID " + ssid);
 
     if (!connect(ssid, password)) {
         ESP_LOGW(TAG, "unable to connect to SSID: %s", ssid.c_str());
-        dk::lcd.move(0, 1);
-        dk::lcd.print("failed          ");
+        DisplayManager::setMessage("connect failed", 1000);
+        // TODO set pairing mode
+//        dk::mainEventGroup->setBit(dk::MainEvents::SET_PAIRING_MODE); // TODO is this OK?
         return http::Response(nlohmann::json({{"success", false}}));
     }
 
@@ -93,7 +91,6 @@ http::Response SettingsController::post(const kbf::http::Request &request) {
     };
     SettingsManager::instance()->setWifiConfig(wifiConfig);
 
-    dk::lcd.move(0, 1);
-    dk::lcd.print("connected       ");
+    DisplayManager::setMessage("connected");
     return http::Response(nlohmann::json({{"success", true}}));
 }

+ 5 - 7
components/dk/src/pairing_service/verify_controller.cpp

@@ -5,7 +5,7 @@
 #include <kbf/http/client.h>
 
 #include "dk.h"
-#include "settings_manager.h"
+#include "tasks/display_manager.h"
 
 using namespace kbf;
 using namespace dk;
@@ -30,10 +30,7 @@ http::Response VerifyController::post(const http::Request &request) {
     if (!validate(json)) return http::Response("", 500);
     auto pairingId = json.find("pairingId")->get<string>();
 
-    lcd.clear();
-    kbf::sleep(50);
-    lcd.print("verifying");
-    lcd.move(0, 1);
+    DisplayManager::setMessage("verifying");
 
     auto client = http::Client();
     nlohmann::json data = { // TODO get ID from efuse or nvs
@@ -44,12 +41,13 @@ http::Response VerifyController::post(const http::Request &request) {
 
     if (response->status != 200) {
         ESP_LOGW(TAG, "failed: %d", response->status);
-        lcd.print("failed");
+        DisplayManager::setMessage("failed", DisplayManager::defaultTimeout);
+        // TODO set pairing mode
         return http::Response(nlohmann::json({{"success", false}}));
     }
 
     ESP_LOGI(TAG, "verification successful");
-    lcd.print("successful");
+    DisplayManager::setMessage("success", DisplayManager::defaultTimeout);
     dk::setPairing(pairingId);
 
     return http::Response(nlohmann::json({{"success", true}}));

+ 8 - 9
components/dk/src/tasks/boot.cpp

@@ -14,6 +14,7 @@
 #include "pairing_service/pair_controller.h"
 #include "pairing_service/settings_controller.h"
 #include "pairing_service/verify_controller.h"
+#include "tasks/display_manager.h"
 #include "tasks/main.h"
 
 using namespace kbf;
@@ -26,10 +27,10 @@ Boot::Boot(const std::string &name, void *arg, uint32_t stackSize, uint32_t prio
 void Boot::run(void *arg) {
     ESP_LOGI(TAG, "%s", __func__);
 
-    // TODO start DisplayManager
-    lcd.print("DoorKeeper v0.1");
-    lcd.move(0, 1);
-    lcd.print("loading...");
+    ESP_LOGI(TAG, "starting DisplayManager");
+    DisplayManager::start();
+    DisplayManager::setStatus("DoorKeeper");
+    DisplayManager::setMessage("loading...");
 
     ESP_LOGI(TAG, "setting up mainEventGroup");
     mainEventGroup = make_shared<rtos::EventGroup>();
@@ -48,10 +49,7 @@ void Boot::run(void *arg) {
     ESP_LOGI(TAG, "starting networking");
     auto wifiConfig = SettingsManager::instance()->wifiConfig();
     wifi::sta::onIp         = ([]() { mainEventGroup->setBit(MainEvents::SET_ONLINE_MODE); });
-    wifi::sta::onDisconnect = ([]() {
-        lcd.println("disconnected", 1);
-        mainEventGroup->setBit(MainEvents::SET_OFFLINE_MODE);
-    });
+    wifi::sta::onDisconnect = ([]() { mainEventGroup->setBit(MainEvents::SET_OFFLINE_MODE); });
     wifi::sta::start();
 
     ESP_LOGI(TAG, "setting up pairingService");
@@ -72,7 +70,8 @@ void Boot::run(void *arg) {
 
     ESP_LOGI(TAG, "setting mode");
     if (paired()) {
-        lcd.println("connecting...", 1);
+        DisplayManager::setWifiState(DisplayManager::WifiState::CONNECTING);
+        DisplayManager::setMessage("connecting...");
         wifi::sta::connect(wifiConfig.ssid, wifiConfig.password);
     } else {
         mainEventGroup->setBit(MainEvents::SET_PAIRING_MODE);

+ 189 - 0
components/dk/src/tasks/display_manager.cpp

@@ -0,0 +1,189 @@
+#include <utility>
+
+#include <esp_log.h>
+
+#include "tasks/display_manager.h"
+
+using namespace kbf;
+
+using std::atomic;
+using std::string;
+using std::shared_ptr;
+using std::make_shared;
+
+static const int MAX_STATUS_LEN  = 14;
+static const int MAX_MESSAGE_LEN = 16;
+
+std::shared_ptr<kbf::driver::LCD> DisplayManager::lcd;
+
+atomic<DisplayManager::WifiState> DisplayManager::wifiState;
+atomic<DisplayManager::DoorState> DisplayManager::doorState;
+string                            DisplayManager::status;
+string                            DisplayManager::message;
+
+const int         DisplayManager::defaultTimeout = 2000;
+atomic<int>       DisplayManager::timeoutMs_     = 0;
+
+shared_ptr<rtos::EventGroup> DisplayManager::eventGroup;
+shared_ptr<task::Task>       DisplayManager::messageTimeout;
+
+DisplayManager::DisplayManager(const std::string &name, void *arg, uint32_t stackSize, uint32_t priority) :
+        Task(name, arg, stackSize, priority) {
+    ESP_LOGI(TAG, "%s()", __func__);
+
+    lcd = make_shared<driver::LCD>(32, 33, 25, 26, 27, 13); // TODO use Kconfig
+
+    wifiState = WifiState::OFFLINE;
+    doorState = DoorState::NOT_CALIBRATED;
+
+    eventGroup     = make_shared<rtos::EventGroup>();
+    messageTimeout = nullptr;
+}
+
+void DisplayManager::start() {
+    ESP_LOGI(TAG, "%s()", __func__);
+
+    static auto task = task::start<DisplayManager>("dm", nullptr);
+}
+
+[[noreturn]] void DisplayManager::run(void *arg) {
+    ESP_LOGI(TAG, "%s()", __func__);
+
+    while (true) {
+        eventGroup->waitForAny(ALL_EVENTS);
+
+        if (eventGroup->getBit(Events::WIFI)) {
+            auto state = wifiState.load();
+            ESP_LOGI(TAG, "event: WIFI: %s",
+                     state == WifiState::AP ? "AP" :
+                     state == WifiState::CONNECTING ? "CONNECTING" :
+                     state == WifiState::ONLINE ? "ONLINE" :
+                     state == WifiState::OFFLINE ? "OFFLINE" :
+                     "unknown");
+
+            lcd->move(15, 0);
+            // TODO use custom characters
+            switch (wifiState) {
+                case WifiState::AP:
+                    lcd->print("A");
+                    break;
+                case WifiState::CONNECTING:
+                    lcd->print("C");
+                    break;
+                case WifiState::ONLINE:
+                    lcd->print("O");
+                    break;
+                case WifiState::OFFLINE:
+                    lcd->print("F");
+                    break;
+            }
+            eventGroup->clearBit(Events::WIFI);
+        }
+
+        if (eventGroup->getBit(Events::DOOR)) {
+            auto state = doorState.load();
+            ESP_LOGI(TAG, "event: DOOR: %s",
+                     state == DoorState::NOT_CALIBRATED ? "NOT_CALIBRATED" :
+                     state == DoorState::OPEN ? "OPEN" :
+                     state == DoorState::CLOSED ? "CLOSED" :
+                     "unknown");
+
+            lcd->move(14, 0);
+            // TODO use custom characters
+            switch (doorState) {
+                case DoorState::NOT_CALIBRATED:
+                    lcd->print("X");
+                    break;
+                case DoorState::OPEN:
+                    lcd->print("O");
+                    break;
+                case DoorState::CLOSED:
+                    lcd->print("C");
+                    break;
+            }
+            eventGroup->clearBit(Events::DOOR);
+        }
+
+        if (eventGroup->getBit(Events::STATUS)) {
+            ESP_LOGI(TAG, "event: STATUS: \"%s\"", status.c_str());
+            lcd->move(0, 0);
+
+            string tmp = status.substr(0, MAX_STATUS_LEN);
+            if (status.length() < MAX_STATUS_LEN) {
+                tmp.insert(status.length(), MAX_STATUS_LEN - status.length(), ' ');
+                ESP_LOGD(TAG, "  padded: \"%s\"", tmp.c_str());
+            } else if (status.length() != tmp.length()) {
+                ESP_LOGW(TAG, "  truncated: \"%s\"", tmp.c_str());
+            }
+
+            lcd->print(tmp);
+            eventGroup->clearBit(Events::STATUS);
+        }
+
+        if (eventGroup->getBit(Events::MESSAGE)) {
+            ESP_LOGI(TAG, "event: MESSAGE: \"%s\"", message.c_str());
+            lcd->move(0, 1);
+
+            string tmp = message.substr(0, MAX_MESSAGE_LEN);
+            if (message.length() < MAX_MESSAGE_LEN) {
+                tmp.insert(message.length(), MAX_MESSAGE_LEN - message.length(), ' ');
+                ESP_LOGD(TAG, "  padded: \"%s\"", tmp.c_str());
+            } else if (message.length() != tmp.length()) {
+                ESP_LOGW(TAG, "  truncated: \"%s\"", tmp.c_str());
+            }
+
+            lcd->print(tmp);
+            eventGroup->clearBit(Events::MESSAGE);
+        }
+    }
+}
+
+void DisplayManager::setWifiState(DisplayManager::WifiState state) {
+    ESP_LOGD(TAG, "%s()", __func__);
+
+    wifiState = state;
+    eventGroup->setBit(Events::WIFI);
+}
+
+void DisplayManager::setDoorState(DisplayManager::DoorState state) {
+    ESP_LOGD(TAG, "%s()", __func__);
+
+    doorState = state;
+    eventGroup->setBit(Events::DOOR);
+}
+
+void DisplayManager::setStatus(std::string text) {
+    ESP_LOGD(TAG, "%s(\"%s\")", __func__, text.c_str());
+
+    // TODO use semaphore?
+    status = std::move(text);
+    eventGroup->setBit(Events::STATUS);
+}
+
+void DisplayManager::setMessage(std::string text, int timeoutMs) {
+    ESP_LOGD(TAG, "%s(\"%s\")", __func__, text.c_str());
+
+    if (messageTimeout && messageTimeout->running()) messageTimeout->stop();
+
+    // TODO use semaphore?
+    message = std::move(text);
+    eventGroup->setBit(Events::MESSAGE);
+
+    if (timeoutMs) {
+        timeoutMs_ = timeoutMs;
+        messageTimeout = task::start<MessageTimeout>("msg_timeout", nullptr);
+    }
+}
+
+void DisplayManager::MessageTimeout::run(void *arg) {
+    ESP_LOGI("MessageTimeout", "%s(%d)", __func__, DisplayManager::timeoutMs_.load());
+
+    kbf::sleep(timeoutMs_);
+
+    string tmp;
+    tmp.insert(0, MAX_MESSAGE_LEN, ' ');
+    lcd->move(0, 1);
+    lcd->print(tmp);
+
+    ESP_LOGI("MessageTimeout", "%s() finished", __func__);
+}

+ 12 - 5
components/dk/src/tasks/main.cpp

@@ -5,6 +5,8 @@
 #include <kbf/wifi.h>
 using namespace kbf;
 
+#include "tasks/display_manager.h"
+
 #include "dk.h"
 using namespace dk;
 
@@ -15,18 +17,20 @@ Main::Main(const std::string &name, void *arg, uint32_t stackSize, uint32_t prio
 
 void setupPairingMode() {
     ESP_LOGI(Main::TAG, "%s()", __func__);
-    lcd.println("pairing", 0);
+    DisplayManager::setStatus("pairing");
 
     string pin;
     for (int i = 0; i < 8; i++) pin += std::to_string(esp_random() % 10);
     ESP_LOGI(Main::TAG, "pairing PIN: \"%s\"", pin.c_str());
-    lcd.println("PIN: " + pin, 1);
+    DisplayManager::setMessage("PIN: " + pin);
 
     apiService->stop();
     pairingService->stop();
+    wifi::stop();
 
-    wifi::ap::onConnect = {[](wifi::STA &){ lcd.println("connected", 1); }};
+    wifi::ap::onConnect = {[](wifi::STA &){ DisplayManager::setMessage("connected"); }};
     wifi::ap::start("doorkeeper", pin);
+    DisplayManager::setWifiState(DisplayManager::WifiState::AP);
     pairingService->start();
 }
 
@@ -39,8 +43,9 @@ void startMdns() {
 
 void setupOnlineMode() {
     ESP_LOGI(TAG, "%s()", __func__);
-    lcd.println("DoorKeeper armed", 0);
-    lcd.println("", 1);
+    DisplayManager::setStatus("online");
+    DisplayManager::setMessage("");
+    DisplayManager::setWifiState(DisplayManager::WifiState::ONLINE);
 
     pairingService->stop();
     apiService->start();
@@ -52,6 +57,8 @@ void stopAP() {
 
     pairingService->stop();
     wifi::ap::stop();
+    DisplayManager::setWifiState(DisplayManager::WifiState::ONLINE);
+
     pairingService->start();
     startMdns();
 }

+ 57 - 0
components/dk/test/test_display_manager.cpp

@@ -0,0 +1,57 @@
+#include "tasks/display_manager.h"
+
+#include <kbf.h>
+
+#include <unity.h>
+
+#define DELAY 3000
+
+using namespace kbf;
+
+TEST_CASE("DisplayManager", "[dm]") {
+    DisplayManager::start();
+
+    kbf::sleep(DELAY / 5);
+    DisplayManager::setStatus("DM test");
+    DisplayManager::setMessage("Starting in 5...");
+
+    kbf::sleep(DELAY);
+
+    DisplayManager::setMessage("default timeout", DisplayManager::defaultTimeout);
+
+    kbf::sleep(DELAY);
+    DisplayManager::setStatus("wifi state");
+
+    DisplayManager::setWifiState(DisplayManager::WifiState::AP);
+    DisplayManager::setMessage("AP");
+
+    kbf::sleep(DELAY);
+    DisplayManager::setWifiState(DisplayManager::WifiState::CONNECTING);
+    DisplayManager::setMessage("connecting");
+
+    kbf::sleep(DELAY);
+    DisplayManager::setWifiState(DisplayManager::WifiState::ONLINE);
+    DisplayManager::setMessage("online");
+
+    kbf::sleep(DELAY);
+    DisplayManager::setWifiState(DisplayManager::WifiState::OFFLINE);
+    DisplayManager::setMessage("offline");
+
+    kbf::sleep(DELAY);
+    DisplayManager::setStatus("door state");
+
+    DisplayManager::setDoorState(DisplayManager::DoorState::CLOSED);
+    DisplayManager::setMessage("closed");
+
+    kbf::sleep(DELAY);
+    DisplayManager::setDoorState(DisplayManager::DoorState::OPEN);
+    DisplayManager::setMessage("open");
+
+    kbf::sleep(DELAY);
+    DisplayManager::setDoorState(DisplayManager::DoorState::NOT_CALIBRATED);
+    DisplayManager::setMessage("not calibrated");
+
+    kbf::sleep(DELAY);
+    DisplayManager::setStatus("DM test");
+    DisplayManager::setMessage("finished");
+}