From 53fa7b7c873b47b43f0bb06f7986bb2d00ab7e06 Mon Sep 17 00:00:00 2001 From: Thomas Bittner Date: Sun, 20 Aug 2023 23:24:36 +0200 Subject: [PATCH] Added wifi UI and change debug print function * HardwareAbstract debug print function now uses VA_LIST * Added wifi handling UI * Notification items currently part of hardware abstract --- Platformio/.vscode/settings.json | 25 ++- Platformio/HAL/Architecture.png | Bin 26035 -> 33242 bytes Platformio/HAL/HardwareAbstract.cpp | 35 +--- Platformio/HAL/HardwareAbstract.hpp | 35 ++-- .../HardwareModules/wifiHandlerInterface.h | 4 +- Platformio/HAL/Notification.hpp | 3 +- Platformio/HAL/Targets/ESP32/HardwareRevX.cpp | 27 ++- Platformio/HAL/Targets/ESP32/HardwareRevX.hpp | 10 ++ .../HAL/Targets/ESP32/display/display.cpp | 9 +- .../HAL/Targets/ESP32/display/display.hpp | 7 +- .../Targets/ESP32/wifiHandler/wifihandler.cpp | 110 +++++++++--- .../Targets/ESP32/wifiHandler/wifihandler.hpp | 30 ++-- .../Targets/Simulator/HardwareSimulator.hpp | 10 +- Platformio/OmoteUI/Images.cpp | 156 ++++++++++++++++++ Platformio/OmoteUI/Images.hpp | 11 +- Platformio/OmoteUI/OmoteUI.hpp | 3 +- Platformio/OmoteUI/wifiSettings.cpp | 151 ++++++++++++++++- 17 files changed, 509 insertions(+), 117 deletions(-) diff --git a/Platformio/.vscode/settings.json b/Platformio/.vscode/settings.json index 2d766ef..0745d47 100644 --- a/Platformio/.vscode/settings.json +++ b/Platformio/.vscode/settings.json @@ -55,7 +55,30 @@ "bit": "cpp", "compare": "cpp", "concepts": "cpp", - "numbers": "cpp" + "numbers": "cpp", + "any": "cpp", + "hash_map": "cpp", + "strstream": "cpp", + "bitset": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "complex": "cpp", + "condition_variable": "cpp", + "forward_list": "cpp", + "list": "cpp", + "ratio": "cpp", + "format": "cpp", + "future": "cpp", + "mutex": "cpp", + "semaphore": "cpp", + "shared_mutex": "cpp", + "span": "cpp", + "stop_token": "cpp", + "thread": "cpp", + "cfenv": "cpp", + "typeindex": "cpp", + "valarray": "cpp", + "variant": "cpp" }, "cmake.sourceDirectory": "${workspaceFolder}/.pio/libdeps/esp32/Adafruit BusIO", "editor.formatOnSave": false, diff --git a/Platformio/HAL/Architecture.png b/Platformio/HAL/Architecture.png index ac3de9e0dc4d701ff0000abc0eecb4b592b8dcda..88deb45c3d463233f2d03bcc7bb65192590de55b 100644 GIT binary patch literal 33242 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 diff --git a/Platformio/HAL/HardwareAbstract.cpp b/Platformio/HAL/HardwareAbstract.cpp index 7752d9c..31aa920 100644 --- a/Platformio/HAL/HardwareAbstract.cpp +++ b/Platformio/HAL/HardwareAbstract.cpp @@ -1,48 +1,23 @@ #include "HardwareAbstract.hpp" -HardwareAbstract::HardwareAbstract( - std::shared_ptr aDisplay, - std::shared_ptr aBattery, - std::shared_ptr aWifiHandler -) -: mBattery(std::move(aBattery)), - mWifiHandler(std::move(aWifiHandler)), - mDisplay(std::move(aDisplay)) +HardwareAbstract::HardwareAbstract() {} std::optional HardwareAbstract::getBatteryStatus(){ +#if 0 if(mBattery){ HardwareAbstract::batteryStatus currentStatus; currentStatus.percentage = mBattery->getPercentage(); currentStatus.isCharging = mBattery->isCharging(); return currentStatus; } +#endif return std::nullopt; } +#if 0 void HardwareAbstract::onBatteryChange(std::function onBatteryStatusChangeHandler){ mBatteryNotification.onNotify(std::move(onBatteryStatusChangeHandler)); } - -void HardwareAbstract::onStartWifiScan(std::function cb_func){ - this->wifi_scan_start_cb.push_back(cb_func); -} - -void HardwareAbstract::onWifiScanDone(std::function>)> cb_func){ - this->wifi_scan_done_cb.push_back(cb_func); -} - -void HardwareAbstract::notifyStartWifiScan(){ - for (std::function cb_func:this->wifi_scan_start_cb) - { - cb_func(); - } -} - -void HardwareAbstract::notifyWifiScanDone(std::shared_ptr> info){ - for (std::function>)> cb_func: this->wifi_scan_done_cb) - { - cb_func(info); - } -} +#endif diff --git a/Platformio/HAL/HardwareAbstract.hpp b/Platformio/HAL/HardwareAbstract.hpp index e1ebc84..65b79a9 100644 --- a/Platformio/HAL/HardwareAbstract.hpp +++ b/Platformio/HAL/HardwareAbstract.hpp @@ -1,16 +1,13 @@ // OMOTE Hardware Abstraction // 2023 Matthew Colvin - -#pragma once +#ifndef _HARDWAREABSTRACT_H_ +#define _HARDWAREABSTRACT_H_ #include #include #include #include #include #include -#include "BatteryInterface.h" -#include "DisplayAbstract.h" -#include "wifiHandlerInterface.h" #include "Notification.hpp" typedef struct { @@ -18,12 +15,15 @@ typedef struct { int rssi; } WifiInfo; +typedef struct { + bool isConnected; + std::string IP; + std::string ssid; +}wifiStatus; + class HardwareAbstract { public: HardwareAbstract( - std::shared_ptr aDisplay, - std::shared_ptr aBattery = nullptr, - std::shared_ptr aWifiHandler = nullptr ); struct batteryStatus { @@ -39,27 +39,24 @@ public: /// status has changed. /// @param onBatteryStatusChangeHandler - Callable to be ran when batter status changes void onBatteryChange(std::function onBatteryStatusChangeHandler); - - void onStartWifiScan(std::function cb_func); - void onWifiScanDone(std::function>)> cb_func); - void notifyStartWifiScan(); - void notifyWifiScanDone(std::shared_ptr> info); + /// @brief Override in order to do setup of hardware devices virtual void init() = 0; /// @brief Override to allow printing of a message for debugging /// @param message - Debug message - virtual void debugPrint(std::string message) = 0; + virtual void debugPrint(const char* fmt, ...) = 0; + + Notification>> wifi_scan_done; + Notification<> wifi_scan_start; + Notification, std::shared_ptr> wifi_connect; + Notification> wifi_status_update; protected: Notification mBatteryNotification; private: - std::vector> wifi_scan_start_cb; - std::vector>)>> wifi_scan_done_cb; - std::shared_ptr mBattery; - std::shared_ptr mWifiHandler; - std::shared_ptr mDisplay; }; +#endif \ No newline at end of file diff --git a/Platformio/HAL/HardwareModules/wifiHandlerInterface.h b/Platformio/HAL/HardwareModules/wifiHandlerInterface.h index e8c2a31..38caa54 100644 --- a/Platformio/HAL/HardwareModules/wifiHandlerInterface.h +++ b/Platformio/HAL/HardwareModules/wifiHandlerInterface.h @@ -1,14 +1,14 @@ #pragma once #include +#include "HardwareAbstract.hpp" class wifiHandlerInterface{ public: virtual void begin() = 0; - virtual void connect(const char* SSID, const char* password) = 0; + //virtual void connect(const char* SSID, const char* password) = 0; virtual void disconnect() = 0; virtual bool isConnected() = 0; virtual void turnOff() = 0; virtual void scan() = 0; - virtual char* getSSID() = 0; virtual std::string getIP() = 0; }; \ No newline at end of file diff --git a/Platformio/HAL/Notification.hpp b/Platformio/HAL/Notification.hpp index 876c5aa..6b8920f 100644 --- a/Platformio/HAL/Notification.hpp +++ b/Platformio/HAL/Notification.hpp @@ -15,6 +15,7 @@ class Notification{ std::vector mFunctionHandlers; }; + template void Notification::onNotify(HandlerTy aHandler){ mFunctionHandlers.push_back(std::move(aHandler)); @@ -25,4 +26,4 @@ void Notification::notify(outboundData... notifySendData){ for (auto handler : mFunctionHandlers){ handler(notifySendData...); } -} +} \ No newline at end of file diff --git a/Platformio/HAL/Targets/ESP32/HardwareRevX.cpp b/Platformio/HAL/Targets/ESP32/HardwareRevX.cpp index c2f8e35..e29c29b 100644 --- a/Platformio/HAL/Targets/ESP32/HardwareRevX.cpp +++ b/Platformio/HAL/Targets/ESP32/HardwareRevX.cpp @@ -52,13 +52,7 @@ void HardwareRevX::initIO() { } HardwareRevX::HardwareRevX(): - HardwareAbstract( - Display::getInstance(), - std::make_shared(ADC_BAT,CRG_STAT), - wifiHandler::getInstance() - ){ - // Reset Sleep Timer on Touch Events - Display::getInstance()->onTouch([this]([[maybe_unused]] auto touchPoint){ standbyTimer = SLEEP_TIMEOUT;}); + HardwareAbstract(){ } HardwareRevX::WakeReason getWakeReason() { @@ -77,6 +71,9 @@ void HardwareRevX::init() { // Make sure ESP32 is running at full speed setCpuFrequencyMhz(240); + mDisplay = Display::getInstance(std::shared_ptr(this)); + mBattery = std::make_shared(ADC_BAT,CRG_STAT); + mWifiHandler = wifiHandler::getInstance(std::shared_ptr(this)); wakeup_reason = getWakeReason(); initIO(); setupBacklight(); @@ -86,12 +83,26 @@ void HardwareRevX::init() { setupIMU(); setupIR(); - debugPrint(std::string("Finished Hardware Setup in %d", millis())); + debugPrint("Finished Hardware Setup in %d", millis()); } +#if 0 void HardwareRevX::debugPrint(std::string aDebugMessage) { Serial.print(aDebugMessage.c_str()); } +#else +void HardwareRevX::debugPrint(const char* fmt, ...) +{ + char result[100]; + va_list arguments; + + va_start(arguments, fmt); + vsnprintf(result, 100, fmt, arguments); + va_end (arguments); + + Serial.print(result); +} +#endif std::shared_ptr HardwareRevX::getInstance(){ if (!mInstance) { diff --git a/Platformio/HAL/Targets/ESP32/HardwareRevX.hpp b/Platformio/HAL/Targets/ESP32/HardwareRevX.hpp index 82417b9..ed5fa67 100644 --- a/Platformio/HAL/Targets/ESP32/HardwareRevX.hpp +++ b/Platformio/HAL/Targets/ESP32/HardwareRevX.hpp @@ -16,6 +16,9 @@ #include "omoteconfig.h" +#include "BatteryInterface.h" +#include "wifiHandlerInterface.h" +#include "DisplayAbstract.h" class HardwareRevX : public HardwareAbstract { @@ -27,7 +30,11 @@ public: // HardwareAbstract virtual void init() override; + #if 0 virtual void debugPrint(std::string aDebugMessage) override; + #else + void debugPrint(const char* fmt, ...); + #endif void loopHandler(); @@ -54,6 +61,9 @@ protected: private: HardwareRevX(); + std::shared_ptr mBattery; + std::shared_ptr mWifiHandler; + std::shared_ptr mDisplay; // IMU Motion Detection LIS3DH IMU = LIS3DH(I2C_MODE, 0x19); // Default constructor is I2C, addr 0x19. int standbyTimer = SLEEP_TIMEOUT; diff --git a/Platformio/HAL/Targets/ESP32/display/display.cpp b/Platformio/HAL/Targets/ESP32/display/display.cpp index 422bd2c..f3290a0 100644 --- a/Platformio/HAL/Targets/ESP32/display/display.cpp +++ b/Platformio/HAL/Targets/ESP32/display/display.cpp @@ -3,20 +3,21 @@ #include "omoteconfig.h" #include "Wire.h" -std::shared_ptr Display::getInstance() +std::shared_ptr Display::getInstance(std::shared_ptr aHardware) { if (DisplayAbstract::mInstance == nullptr) { - DisplayAbstract::mInstance = std::shared_ptr(new Display(LCD_EN, LCD_BL)); + DisplayAbstract::mInstance = std::shared_ptr(new Display(LCD_EN, LCD_BL, aHardware)); } return std::static_pointer_cast(mInstance); } -Display::Display(int backlight_pin, int enable_pin): DisplayAbstract(), +Display::Display(int backlight_pin, int enable_pin, std::shared_ptr aHardware): DisplayAbstract(), mBacklightPin(backlight_pin), mEnablePin(enable_pin), tft(TFT_eSPI()), - touch(Adafruit_FT6206()) + touch(Adafruit_FT6206()), + mHardware(aHardware) { pinMode(mEnablePin, OUTPUT); digitalWrite(mEnablePin, HIGH); diff --git a/Platformio/HAL/Targets/ESP32/display/display.hpp b/Platformio/HAL/Targets/ESP32/display/display.hpp index a359ebb..ac3adb9 100644 --- a/Platformio/HAL/Targets/ESP32/display/display.hpp +++ b/Platformio/HAL/Targets/ESP32/display/display.hpp @@ -1,5 +1,6 @@ #pragma once #include "DisplayAbstract.h" +#include "HardwareAbstract.hpp" #include "Notification.hpp" #include #include @@ -19,7 +20,7 @@ class Display: public DisplayAbstract { public: - static std::shared_ptr getInstance(); + static std::shared_ptr getInstance(std::shared_ptr aHardware); virtual void setBrightness(uint8_t brightness) override; virtual void turnOff() override; @@ -31,7 +32,7 @@ class Display: public DisplayAbstract virtual void screenInput(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) override; private: - Display(int backlight_pin, int enable_pin); + Display(int backlight_pin, int enable_pin, std::shared_ptr aHardware); void setupTFT(); void setupTouchScreen(); @@ -42,6 +43,6 @@ class Display: public DisplayAbstract Adafruit_FT6206 touch; TS_Point touchPoint; TS_Point oldPoint; - + std::shared_ptr mHardware; Notification mTouchEvent; }; \ No newline at end of file diff --git a/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.cpp b/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.cpp index 7e32afb..bde29b9 100644 --- a/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.cpp +++ b/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.cpp @@ -1,18 +1,29 @@ #include "wifihandler.hpp" #include #include +#include "HardwareAbstract.hpp" std::shared_ptr wifiHandler::mInstance = nullptr; - // WiFi status event void wifiHandler::WiFiEvent(WiFiEvent_t event){ int no_networks = 0; switch (event) { case ARDUINO_EVENT_WIFI_SCAN_DONE: + { Serial.println("WIFI scan done\n"); no_networks = WiFi.scanComplete(); + std::vector *vec = new std::vector(); + std::shared_ptr> info = std::shared_ptr>(vec); + + for (int i = 0; i < no_networks; i++) + { + info->push_back(WifiInfo { + .ssid = std::string(WiFi.SSID(i).c_str()), + .rssi = WiFi.RSSI(i) + }); + } if (no_networks < 0) { Serial.println("Scan failed"); @@ -25,40 +36,74 @@ void wifiHandler::WiFiEvent(WiFiEvent_t event){ Serial.print(" found\n"); //this->display.wifi_scan_complete( no_networks); } + mHardware->wifi_scan_done.notify(info); break; + } case ARDUINO_EVENT_WIFI_STA_GOT_IP: case ARDUINO_EVENT_WIFI_STA_GOT_IP6: - // TODO convert to callbacks - //display.update_wifi(true); - //update_credentials(temporary_ssid, temporary_password); - break; + this->update_credentials(); case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: case ARDUINO_EVENT_WIFI_STA_LOST_IP: case ARDUINO_EVENT_WIFI_STA_STOP: - // TODO Convert to Callbacks - //display.update_wifi(false); + this->update_status(); default: break; } + if (WiFi.status() == WL_CONNECT_FAILED) + { + Serial.println("connection failed."); + WiFi.disconnect(); + } + Serial.println(WiFi.status()); } -std::shared_ptr wifiHandler::getInstance() +std::shared_ptr wifiHandler::getInstance(std::shared_ptr aHardware) { if(mInstance) { return mInstance; } - return std::shared_ptr(new wifiHandler()); + mInstance = std::shared_ptr(new wifiHandler(aHardware)); + return mInstance; }; -wifiHandler::wifiHandler() +wifiHandler::wifiHandler(std::shared_ptr aHardware) { - this->password[0] = '\0'; - this->SSID[0] = '\0'; + this->mHardware = aHardware; + this->mHardware->wifi_scan_start.onNotify([this](){this->mHardware->debugPrint("scan called\n"); this->scan();}); + this->mHardware->wifi_connect.onNotify([this] (std::shared_ptr ssid, std::shared_ptr password){this->connect(ssid, password);}); + this->password = ""; + this->SSID = ""; + this->begin(); } -void wifiHandler::update_credentials(const char* temporary_ssid, const char* temporary_password) +void wifiHandler::update_status() { + Serial.println("update_status"); + std::shared_ptr status = std::make_shared(wifiStatus()); + //wifiStatus *status = new wifiStatus(); + status->isConnected = WiFi.isConnected(); + //status->IP = WiFi.localIP(); + IPAddress ip = WiFi.localIP(); + String ip_str = ip.toString(); + status->IP = ip.toString().c_str(); + + //ip.copy(status->IP, ip.length()); + String ssid = WiFi.SSID(); + status->ssid = WiFi.SSID().c_str(); + + //this->wifi_status.isConnected = WiFi.isConnected(); + //this->wifi_status.IP = WiFi.localIP(); + //this->wifi_status.isConnected = true; + + + //Serial.println(WiFi.localIP()); + this->mHardware->wifi_status_update.notify(status); +} + +void wifiHandler::update_credentials() +{ +#if 0 if (strcmp(temporary_password, wifiHandler::password) != 0 || strcmp(temporary_ssid, wifiHandler::SSID) != 0) { strcpy(wifiHandler::password, temporary_password); @@ -72,18 +117,36 @@ void wifiHandler::update_credentials(const char* temporary_ssid, const char* tem preferences.putString("SSID", tempString); preferences.end(); } +#else + if (this->temporary_password->compare(this->password) != 0 || this->temporary_ssid->compare(this->SSID)) + { + this->password = *(this->temporary_password); + this->SSID = *(this->temporary_ssid); + + Preferences preferences; + preferences.begin("wifiSettings", false); + String tempString = this->temporary_password->c_str(); + preferences.putString("password", tempString); + tempString = this->temporary_ssid->c_str(); + preferences.putString("SSID", tempString); + preferences.end(); + } +#endif } void wifiHandler::scan() { + Serial.println("scan called"); WiFi.scanNetworks(true); } + void wifiHandler::begin() { //this->display = display; WiFi.setHostname("OMOTE"); WiFi.mode(WIFI_STA); + //WiFi.onEvent([this] (WiFiEvent_t event) {mInstance->WiFiEvent(event);}); WiFi.onEvent([] (WiFiEvent_t event) {mInstance->WiFiEvent(event);}); Preferences preferences; @@ -97,9 +160,11 @@ void wifiHandler::begin() { Serial.print("Connecting to wifi "); Serial.println(ssid); - strcpy(this->SSID, ssid.c_str()); - strcpy(this->password, password.c_str()); - this->connect(this->SSID, this->password); + //strcpy(this->SSID, ssid.c_str()); + //strcpy(this->password, password.c_str()); + this->SSID = ssid.c_str(); + this->password = password.c_str(); + //this->connect(this->SSID, this->password); } else { @@ -113,11 +178,11 @@ void wifiHandler::begin() WiFi.setSleep(true); } -void wifiHandler::connect(const char* SSID, const char* password) +void wifiHandler::connect(std::shared_ptr ssid, std::shared_ptr password) { - strncpy(this->temporary_password, password, STRING_SIZE); - strncpy(this->temporary_ssid, SSID, STRING_SIZE); - WiFi.begin(SSID, password); + this->temporary_password = password; + this->temporary_ssid = ssid; + WiFi.begin(ssid->c_str(), password->c_str()); } void wifiHandler::turnOff() @@ -135,11 +200,6 @@ bool wifiHandler::isConnected() return WiFi.isConnected(); } -char* wifiHandler::getSSID() -{ - return this->SSID; -} - std::string wifiHandler::getIP() { return std::string(WiFi.localIP().toString().c_str()); diff --git a/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.hpp b/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.hpp index 02c6eef..458e245 100644 --- a/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.hpp +++ b/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.hpp @@ -1,12 +1,14 @@ #pragma once #include "wifiHandlerInterface.h" +#include "HardwareAbstract.hpp" #include #define STRING_SIZE 50 class wifiHandler: public wifiHandlerInterface { public: - static std::shared_ptr getInstance(); + wifiHandler(std::shared_ptr aHardware); + static std::shared_ptr getInstance(std::shared_ptr aHardware); /** * @brief Function to initialize the wifi handler * @@ -19,7 +21,7 @@ class wifiHandler: public wifiHandlerInterface { * @param SSID * @param password */ - void connect(const char* SSID, const char* password); + //void connect(const char* SSID, const char* password); /** * @brief Function to disconnect from the network @@ -47,13 +49,6 @@ class wifiHandler: public wifiHandlerInterface { */ void scan(); - /** - * @brief Function to get SSID of the currently connected wifi network - * - * @return char* SSID of the currently connected network - */ - char* getSSID(); - /** * @brief Function to update the wifi credentials. This function is called in the wifi event callback function * after a connection is established. Only then is the new credentials stored and the old stored credentials @@ -62,7 +57,7 @@ class wifiHandler: public wifiHandlerInterface { * @param temporary_ssid * @param temporary_password */ - void update_credentials(const char* temporary_ssid, const char* temporary_password); + void update_credentials(); void WiFiEvent(WiFiEvent_t event); @@ -72,24 +67,27 @@ class wifiHandler: public wifiHandlerInterface { * @return String IP Address of the device */ std::string getIP(); + Notification>> scan_done; private: - wifiHandler(); - + wifiStatus wifi_status; static std::shared_ptr mInstance; - char temporary_password[STRING_SIZE]; - char temporary_ssid[STRING_SIZE]; + std::shared_ptr mHardware; + std::shared_ptr temporary_password; + std::shared_ptr temporary_ssid; + void connect(std::shared_ptr ssid, std::shared_ptr password); + void update_status(); /** * @brief Internal variable to store the wifi password * */ - char password[STRING_SIZE]; + std::string password; /** * @brief Internal variable to store the wifi SSID * */ - char SSID[STRING_SIZE]; + std::string SSID; }; \ No newline at end of file diff --git a/Platformio/HAL/Targets/Simulator/HardwareSimulator.hpp b/Platformio/HAL/Targets/Simulator/HardwareSimulator.hpp index 5837fe3..5d40d5f 100644 --- a/Platformio/HAL/Targets/Simulator/HardwareSimulator.hpp +++ b/Platformio/HAL/Targets/Simulator/HardwareSimulator.hpp @@ -6,10 +6,18 @@ class HardwareSimulator : public HardwareAbstract { public: HardwareSimulator(); - +#if 0 virtual void debugPrint(std::string message) override { std::cout << message; } + #else + virtual void debugPrint(const char* fmt, ...) override { + va_list arguments; + va_start(arguments, fmt); + vprintf(fmt, arguments); + va_end(arguments); + } + #endif virtual void init() override {}; diff --git a/Platformio/OmoteUI/Images.cpp b/Platformio/OmoteUI/Images.cpp index 6fb51a3..0a32e1a 100644 --- a/Platformio/OmoteUI/Images.cpp +++ b/Platformio/OmoteUI/Images.cpp @@ -1,5 +1,10 @@ #include "Images.hpp" +static void update_default_image_color(lv_obj_t* image) +{ + lv_obj_set_style_img_recolor(image, lv_color_white(), LV_PART_MAIN); + lv_obj_set_style_img_recolor_opa(image, LV_OPA_COVER, LV_PART_MAIN); +} Images::Images(){ setupImageDescriptions(); @@ -36,6 +41,27 @@ lv_obj_t* Images::addLightBulbIcon(lv_obj_t* parent){ return bulbIcon; } +lv_obj_t* Images::addWifiNoSignal(lv_obj_t* parent){ + lv_obj_t* noSignal = this->addImg(parent, &this->wifiNoSignal); + update_default_image_color(noSignal); + return noSignal; +} +lv_obj_t* Images::addWifiLowSignal(lv_obj_t* parent){ + lv_obj_t* lowSignal = this->addImg(parent, &this->wifiLowSignal); + update_default_image_color(lowSignal); + return lowSignal; +} +lv_obj_t* Images::addWifiMidSignal(lv_obj_t* parent){ + lv_obj_t* lowSignal = this->addImg(parent, &this->wifiMidSignal); + update_default_image_color(lowSignal); + return lowSignal; +} +lv_obj_t* Images::addWifiHighSignal(lv_obj_t* parent){ + lv_obj_t* lowSignal = this->addImg(parent, &this->wifiHighSignal); + update_default_image_color(lowSignal); + return lowSignal; +} + lv_obj_t* Images::addLeftGradiant(lv_obj_t* parent){ return this->addImg(parent, &this->gradientLeft); } @@ -934,6 +960,103 @@ inline static const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST uint8_t 0xff, 0xff, 0xff, 0xff, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x22, 0x22, 0x21, 0x01, 0x00, 0x00, 0x00, }; + +inline static const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST uint8_t WiFi_No_Signal_map[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +inline static const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST uint8_t WiFi_Mid_Signal_map[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +inline static const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST uint8_t WiFi_Low_Signal_map[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +inline static const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST uint8_t WiFi_High_Signal_map[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + void Images::setupImageDescriptions(){ this->low_brightness.header.cf = LV_IMG_CF_ALPHA_8BIT; this->low_brightness.header.always_zero = 0; @@ -995,4 +1118,37 @@ void Images::setupImageDescriptions(){ this->gradientRight.header.h = 1; this->gradientRight.data_size = 30; this->gradientRight.data = gradientRight_map; + + this->wifiNoSignal.header.cf = LV_IMG_CF_ALPHA_8BIT; + this->wifiNoSignal.header.always_zero = 0; + this->wifiNoSignal.header.reserved = 0; + this->wifiNoSignal.header.w = 25; + this->wifiNoSignal.header.h = 21; + this->wifiNoSignal.data_size = 525; + this->wifiNoSignal.data = WiFi_No_Signal_map; + + this->wifiLowSignal.header.cf = LV_IMG_CF_ALPHA_8BIT; + this->wifiLowSignal.header.always_zero = 0; + this->wifiLowSignal.header.reserved = 0; + this->wifiLowSignal.header.w = 25; + this->wifiLowSignal.header.h = 21; + this->wifiLowSignal.data_size = 525; + this->wifiLowSignal.data = WiFi_Low_Signal_map; + + this->wifiMidSignal.header.cf = LV_IMG_CF_ALPHA_8BIT; + this->wifiMidSignal.header.always_zero = 0; + this->wifiMidSignal.header.reserved = 0; + this->wifiMidSignal.header.w = 25; + this->wifiMidSignal.header.h = 21; + this->wifiMidSignal.data_size = 525; + this->wifiMidSignal.data = WiFi_Mid_Signal_map; + + this->wifiHighSignal.header.cf = LV_IMG_CF_ALPHA_8BIT; + this->wifiHighSignal.header.always_zero = 0; + this->wifiHighSignal.header.reserved = 0; + this->wifiHighSignal.header.w = 25; + this->wifiHighSignal.header.h = 21; + this->wifiHighSignal.data_size = 525; + this->wifiHighSignal.data = WiFi_High_Signal_map; + } \ No newline at end of file diff --git a/Platformio/OmoteUI/Images.hpp b/Platformio/OmoteUI/Images.hpp index 6c00649..be23311 100644 --- a/Platformio/OmoteUI/Images.hpp +++ b/Platformio/OmoteUI/Images.hpp @@ -19,6 +19,12 @@ public: lv_obj_t* addLeftGradiant(lv_obj_t* parent); lv_obj_t* addRightGradiant(lv_obj_t* parent); + lv_obj_t* addWifiNoSignal(lv_obj_t* parent); + lv_obj_t* addWifiLowSignal(lv_obj_t* parent); + lv_obj_t* addWifiMidSignal(lv_obj_t* parent); + lv_obj_t* addWifiHighSignal(lv_obj_t* parent); + + private: // Make Image based on anImageDesc then // add that image to parent. @@ -36,6 +42,9 @@ private: lv_img_dsc_t gradientLeft; lv_img_dsc_t gradientRight; - + lv_img_dsc_t wifiNoSignal; + lv_img_dsc_t wifiLowSignal; + lv_img_dsc_t wifiMidSignal; + lv_img_dsc_t wifiHighSignal; }; \ No newline at end of file diff --git a/Platformio/OmoteUI/OmoteUI.hpp b/Platformio/OmoteUI/OmoteUI.hpp index 912ad9b..a6040a6 100644 --- a/Platformio/OmoteUI/OmoteUI.hpp +++ b/Platformio/OmoteUI/OmoteUI.hpp @@ -78,7 +78,7 @@ private: std::shared_ptr mHardware; void reset_settings_menu(); void attach_keyboard(lv_obj_t* textarea); - + std::shared_ptr> found_wifi_networks; /** * @brief Keyboard object used whenever a keyboard is needed. * @@ -180,6 +180,7 @@ void create_keyboard(); unsigned int no_wifi_networks; + void wifi_status(std::shared_ptr status); /** * @brief callback function to get next wifi subpage. This callback can be used to get the next or previous page * diff --git a/Platformio/OmoteUI/wifiSettings.cpp b/Platformio/OmoteUI/wifiSettings.cpp index 2745668..f975490 100644 --- a/Platformio/OmoteUI/wifiSettings.cpp +++ b/Platformio/OmoteUI/wifiSettings.cpp @@ -1,5 +1,8 @@ #include "OmoteUI.hpp" +#define WIFI_SUBPAGE_SIZE 3 +static char* ssid; + lv_obj_t* OmoteUI::create_wifi_selection_page(lv_obj_t* menu) { /* Create sub page for wifi*/ @@ -49,7 +52,7 @@ void OmoteUI::password_field_event_cb(lv_event_t* e) const char* password = lv_textarea_get_text(ta); switch(code){ case LV_EVENT_READY: - //wifihandler.connect(ssid, password); + this->mHardware->wifi_connect.notify(std::make_shared(std::string(ssid)), std::make_shared(std::string(password))); lv_obj_clear_state(ta, LV_STATE_FOCUSED); this->hide_keyboard(); this->reset_settings_menu(); @@ -70,11 +73,13 @@ void OmoteUI::connect_btn_cb(lv_event_t* event) lv_obj_t* ta = (lv_obj_t*) event->user_data; const char* password = lv_textarea_get_text(ta); + this->mHardware->wifi_connect.notify(std::make_shared(std::string(ssid)), std::make_shared(std::string(password))); //Trigger wifi connection here //wifihandler.connect(ssid, password); lv_obj_clear_state(ta, LV_STATE_FOCUSED); - this->hide_keyboard(); + this->hide_keyboard(); this->reset_settings_menu(); + } void OmoteUI::create_wifi_main_page(lv_obj_t* parent) @@ -107,10 +112,120 @@ void OmoteUI::create_wifi_main_page(lv_obj_t* parent) void OmoteUI::wifi_scan_done(std::shared_ptr> info) { - for (WifiInfo i:*info) + unsigned int size = info->size(); + this->no_subpages = (size + WIFI_SUBPAGE_SIZE - 1)/WIFI_SUBPAGE_SIZE; + this->no_wifi_networks = size; + this->found_wifi_networks = info; + + if (size == 0) + { + lv_obj_t* menuBox = lv_obj_create(this->wifi_setting_cont); + lv_obj_set_size(menuBox, lv_pct(100), 45); + lv_obj_set_scrollbar_mode(menuBox, LV_SCROLLBAR_MODE_OFF); + lv_obj_t* menuLabel = lv_label_create(menuBox); + lv_label_set_text(menuLabel, "no networks found"); + } + else + { + this->update_wifi_selection_subpage(0); + } +} +void OmoteUI::next_wifi_selection_subpage(lv_event_t* e) +{ + int subpage = (int) lv_event_get_user_data(e); + this->update_wifi_selection_subpage(subpage); +} + + +/** + * @brief Callback function in case a wifi is selected. This callback function will change the label of the wifi password + * sub page to the selected wifi network. + * + * @param e Pointer to event object for the event where this callback is called + */ +static void wifi_selected_cb(lv_event_t* e) +{ + lv_obj_t* label = lv_obj_get_child(e->target, 0); + lv_label_set_text((lv_obj_t*) e->user_data, lv_label_get_text(label)); + ssid = lv_label_get_text(label); +} + + +void OmoteUI::update_wifi_selection_subpage(int page) +{ + if (page < this->no_subpages) + { + lv_obj_clean(this->wifi_setting_cont); + + lv_obj_t* pageLabel = lv_label_create(this->wifi_setting_cont); + lv_label_set_text_fmt(pageLabel, "Page %d/%d", page + 1, this->no_subpages); + if (page > 0) { - mHardware->debugPrint(i.ssid); + lv_obj_t* menuBox = lv_obj_create(this->wifi_setting_cont); + lv_obj_set_size(menuBox, lv_pct(100), 45); + lv_obj_set_scrollbar_mode(menuBox, LV_SCROLLBAR_MODE_OFF); + + lv_obj_t* menuLabel = lv_label_create(menuBox); + lv_label_set_text(menuLabel, "Previous"); + lv_obj_align(menuLabel, LV_ALIGN_TOP_RIGHT, 0, 0); + lv_obj_add_event_cb(menuBox, [](lv_event_t* e) {mInstance->next_wifi_selection_subpage(e);},LV_EVENT_CLICKED, (void*)(page - 1)); + lv_obj_t* arrow = lv_label_create(menuBox); + lv_label_set_text(arrow, LV_SYMBOL_LEFT); + lv_obj_align(arrow, LV_ALIGN_TOP_LEFT, 0, 0); } + + for (int i = 0; i < WIFI_SUBPAGE_SIZE && (page*WIFI_SUBPAGE_SIZE + i) < this->no_wifi_networks; i++) + { + lv_obj_t* menuBox = lv_obj_create(this->wifi_setting_cont); + lv_obj_set_size(menuBox, lv_pct(100), 45); + lv_obj_set_scrollbar_mode(menuBox, LV_SCROLLBAR_MODE_OFF); + + lv_obj_add_flag(menuBox, LV_OBJ_FLAG_EVENT_BUBBLE); + + lv_obj_t* menuLabel = lv_label_create(menuBox); + lv_label_set_text(menuLabel, this->found_wifi_networks->at(page*WIFI_SUBPAGE_SIZE + i).ssid.c_str()); + lv_obj_t* wifi_image; + + int RSSI = this->found_wifi_networks->at(page*WIFI_SUBPAGE_SIZE + i).rssi; + + if (RSSI > -50) + { + wifi_image = imgs.addWifiHighSignal(menuBox); + } + else if (RSSI > -60) + { + wifi_image = imgs.addWifiMidSignal(menuBox); + } + else if (RSSI > -70) + { + wifi_image = imgs.addWifiLowSignal(menuBox); + } + else + { + wifi_image = imgs.addWifiLowSignal(menuBox); + } + lv_obj_align(wifi_image, LV_ALIGN_TOP_RIGHT, 0, 0); + lv_menu_set_load_page_event(this->settingsMenu, menuBox, this->wifi_password_page); + lv_obj_add_event_cb(menuBox, wifi_selected_cb, LV_EVENT_CLICKED, this->wifi_password_label); + } + + if ((page + 1) < this->no_subpages) + { + lv_obj_t* menuBox = lv_obj_create(this->wifi_setting_cont); + lv_obj_set_size(menuBox, lv_pct(100), 45); + lv_obj_set_scrollbar_mode(menuBox, LV_SCROLLBAR_MODE_OFF); + + lv_obj_t* menuLabel = lv_label_create(menuBox); + lv_label_set_text(menuLabel, "Next"); + lv_obj_add_event_cb(menuBox, [](lv_event_t* e) {mInstance->next_wifi_selection_subpage(e);}, LV_EVENT_CLICKED, (void*)(page + 1)); + + lv_obj_t* arrow = lv_label_create(menuBox); + lv_label_set_text(arrow, LV_SYMBOL_RIGHT); + lv_obj_align(arrow, LV_ALIGN_TOP_RIGHT, 0, 0); + + } + lv_obj_scroll_to_y(this->wifi_setting_cont, 0, LV_ANIM_OFF); + } } void OmoteUI::create_wifi_settings(lv_obj_t* menu, lv_obj_t* parent) @@ -118,7 +233,31 @@ void OmoteUI::create_wifi_settings(lv_obj_t* menu, lv_obj_t* parent) this->wifi_selection_page = this->create_wifi_selection_page(menu); this->wifi_password_page = this->create_wifi_password_page(this->settingsMenu); this->create_wifi_main_page(parent); - this->mHardware->onWifiScanDone([this] (std::shared_ptr> info) {this->wifi_scan_done(info);}); + this->mHardware->wifi_scan_done.onNotify([this] (std::shared_ptr> info) {this->wifi_scan_done(info);}); + this->mHardware->wifi_status_update.onNotify([this] (std::shared_ptr status) {this->wifi_status(status);}); +} + +void OmoteUI::wifi_status(std::shared_ptr status) +{ + this->mHardware->debugPrint("connected %d\n", status->isConnected); + this->mHardware->debugPrint("IP %s\n", status->IP); + this->mHardware->debugPrint("SSID %s\n", status->ssid); + + lv_obj_t* ip_label = lv_obj_get_child(this->wifiOverview, 3); + lv_obj_t* ssid_label = lv_obj_get_child(this->wifiOverview, 0); + + if (status->isConnected) + { + lv_label_set_text(this->WifiLabel, LV_SYMBOL_WIFI); + lv_label_set_text(ssid_label, status->ssid.c_str()); + lv_label_set_text(ip_label, status->IP.c_str()); + } + else + { + lv_label_set_text(this->WifiLabel, ""); + lv_label_set_text(ssid_label, "Disconnected"); + lv_label_set_text(ip_label, "-"); + } } lv_obj_t* OmoteUI::create_wifi_password_page(lv_obj_t* menu) @@ -165,6 +304,8 @@ void OmoteUI::wifi_settings_cb(lv_event_t* event) lv_obj_clean(cont); lv_obj_t* label = lv_label_create(cont); lv_label_set_text(label, "Searching for wifi networks"); + mHardware->debugPrint("Wifi settings cb called\n"); + mHardware->wifi_scan_start.notify(); //This will trigger an asynchronouse network scan // We need to trigger wifi search via HAL //wifihandler.scan();