Refine and implement hardware interface (#37)
This commit is contained in:
parent
7a9ee138db
commit
6a78c4cfa1
47 changed files with 3532 additions and 1627 deletions
|
@ -1029,7 +1029,7 @@
|
|||
(property "ki_keywords" "cap capacitor")
|
||||
(path "/5d818a81-71ff-4f40-8854-04efda688b48")
|
||||
(attr smd)
|
||||
(fp_text reference "C13" (at -3.25 -1.68) (layer "F.SilkS")
|
||||
(fp_text reference "C13" (at -3.238895 0.068182) (layer "F.SilkS")
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
(tstamp 15439bba-04d4-4528-ad0e-855324eb39a5)
|
||||
)
|
||||
|
@ -6445,7 +6445,7 @@
|
|||
(property "ki_keywords" "cap capacitor")
|
||||
(path "/a888a00f-5496-4d09-af9f-455dba2d8767")
|
||||
(attr smd)
|
||||
(fp_text reference "C14" (at 3.5 -1.85) (layer "F.SilkS")
|
||||
(fp_text reference "C14" (at 3.488895 -0.14998) (layer "F.SilkS")
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
(tstamp 5ecdc16d-4df0-4830-8429-f936a2864918)
|
||||
)
|
||||
|
|
Binary file not shown.
30
Platformio/.vscode/settings.json
vendored
30
Platformio/.vscode/settings.json
vendored
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"cmake.configureOnOpen": false,
|
||||
"files.associations": {
|
||||
"*.json": "jsonc",
|
||||
"random": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
|
@ -50,7 +51,34 @@
|
|||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp"
|
||||
"typeinfo": "cpp",
|
||||
"bit": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "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,
|
||||
|
|
BIN
Platformio/HAL/Architecture.png
Normal file
BIN
Platformio/HAL/Architecture.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
40
Platformio/HAL/Architecture.puml
Normal file
40
Platformio/HAL/Architecture.puml
Normal file
|
@ -0,0 +1,40 @@
|
|||
@startuml
|
||||
' KEY
|
||||
' --> : is a
|
||||
' *-- : must have
|
||||
' o-- : should have
|
||||
|
||||
namespace HAL{
|
||||
interface BatteryInterface
|
||||
interface WifiInterface
|
||||
interface OtherHWInterface
|
||||
|
||||
abstract HardwareAbstract
|
||||
|
||||
HardwareAbstract o-- BatteryInterface
|
||||
HardwareAbstract o-- WifiInterface
|
||||
HardwareAbstract o-- OtherHWInterface
|
||||
}
|
||||
|
||||
namespace Simulator{
|
||||
class BatterySimulator
|
||||
class WifiSimulator
|
||||
BatterySimulator --> HAL.BatteryInterface
|
||||
WifiSimulator --> HAL.WifiInterface
|
||||
}
|
||||
|
||||
namespace ESP32{
|
||||
class Battery
|
||||
class WifiHandler
|
||||
Battery --> HAL.BatteryInterface
|
||||
WifiHandler --> HAL.WifiInterface
|
||||
}
|
||||
|
||||
|
||||
namespace UI {
|
||||
class OmoteUI
|
||||
OmoteUI *-- HAL.HardwareAbstract
|
||||
}
|
||||
|
||||
|
||||
@enduml
|
5
Platformio/HAL/HardwareAbstract.cpp
Normal file
5
Platformio/HAL/HardwareAbstract.cpp
Normal file
|
@ -0,0 +1,5 @@
|
|||
#include "HardwareAbstract.hpp"
|
||||
|
||||
HardwareAbstract::HardwareAbstract(){
|
||||
|
||||
}
|
30
Platformio/HAL/HardwareAbstract.hpp
Normal file
30
Platformio/HAL/HardwareAbstract.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
// OMOTE Hardware Abstraction
|
||||
// 2023 Matthew Colvin
|
||||
#pragma once
|
||||
#include "BatteryInterface.h"
|
||||
#include "DisplayAbstract.h"
|
||||
#include "wifiHandlerInterface.h"
|
||||
|
||||
#include "Notification.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class HardwareAbstract {
|
||||
public:
|
||||
HardwareAbstract();
|
||||
|
||||
/// @brief Override in order to do setup of hardware devices post construction
|
||||
virtual void init() = 0;
|
||||
|
||||
|
||||
/// @brief Override to allow printing of a message for debugging
|
||||
/// @param message - Debug message
|
||||
virtual void debugPrint(const char* fmt, ...) = 0;
|
||||
|
||||
virtual std::shared_ptr<BatteryInterface> battery() = 0;
|
||||
virtual std::shared_ptr<DisplayAbstract> display() = 0;
|
||||
virtual std::shared_ptr<wifiHandlerInterface> wifi() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
};
|
9
Platformio/HAL/HardwareModules/BatteryInterface.h
Normal file
9
Platformio/HAL/HardwareModules/BatteryInterface.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
#include "Notification.hpp"
|
||||
|
||||
class BatteryInterface {
|
||||
public:
|
||||
BatteryInterface() = default;
|
||||
virtual int getPercentage() = 0;
|
||||
virtual bool isCharging() = 0;
|
||||
};
|
35
Platformio/HAL/HardwareModules/DisplayAbstract.cpp
Normal file
35
Platformio/HAL/HardwareModules/DisplayAbstract.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include "DisplayAbstract.h"
|
||||
|
||||
std::shared_ptr<DisplayAbstract> DisplayAbstract::mInstance = nullptr;
|
||||
|
||||
DisplayAbstract::DisplayAbstract(){
|
||||
lv_init();
|
||||
|
||||
lv_disp_draw_buf_init(&mdraw_buf, mbufA, mbufB,
|
||||
SCREEN_WIDTH * SCREEN_HEIGHT / 10);
|
||||
|
||||
// Initialize the display driver
|
||||
static lv_disp_drv_t disp_drv;
|
||||
lv_disp_drv_init(&disp_drv);
|
||||
disp_drv.hor_res = SCREEN_WIDTH;
|
||||
disp_drv.ver_res = SCREEN_HEIGHT;
|
||||
disp_drv.flush_cb = &DisplayAbstract::flushDisplayImpl;
|
||||
disp_drv.draw_buf = &mdraw_buf;
|
||||
lv_disp_drv_register(&disp_drv);
|
||||
|
||||
// Initialize the touchscreen driver
|
||||
static lv_indev_drv_t indev_drv;
|
||||
lv_indev_drv_init(&indev_drv);
|
||||
indev_drv.type = LV_INDEV_TYPE_POINTER;
|
||||
indev_drv.read_cb = &DisplayAbstract::screenInputImpl;
|
||||
lv_indev_drv_register(&indev_drv);
|
||||
|
||||
}
|
||||
|
||||
void DisplayAbstract::flushDisplayImpl(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
|
||||
mInstance->flushDisplay(disp, area, color_p);
|
||||
}
|
||||
|
||||
void DisplayAbstract::screenInputImpl(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) {
|
||||
mInstance->screenInput(indev_driver, data);
|
||||
}
|
28
Platformio/HAL/HardwareModules/DisplayAbstract.h
Normal file
28
Platformio/HAL/HardwareModules/DisplayAbstract.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
#include <memory>
|
||||
#include "lvgl.h"
|
||||
class DisplayAbstract
|
||||
{
|
||||
public:
|
||||
DisplayAbstract();
|
||||
virtual void setBrightness(uint8_t brightness) = 0;
|
||||
virtual uint8_t getBrightness() = 0;
|
||||
virtual void turnOff() = 0;
|
||||
|
||||
protected:
|
||||
// Set this with a getInstance method in the Child Class
|
||||
static std::shared_ptr<DisplayAbstract> mInstance;
|
||||
|
||||
virtual void flushDisplay(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) = 0;
|
||||
virtual void screenInput(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) = 0;
|
||||
private:
|
||||
|
||||
// Used to satisfy LVGL APIs
|
||||
static void flushDisplayImpl(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p);
|
||||
static void screenInputImpl(lv_indev_drv_t *indev_driver, lv_indev_data_t *data);
|
||||
|
||||
// LVGL Screen Buffers
|
||||
lv_disp_draw_buf_t mdraw_buf;
|
||||
lv_color_t mbufA[SCREEN_WIDTH * SCREEN_HEIGHT / 10];
|
||||
lv_color_t mbufB[SCREEN_WIDTH * SCREEN_HEIGHT / 10];
|
||||
};
|
17
Platformio/HAL/HardwareModules/UIInterface.h
Normal file
17
Platformio/HAL/HardwareModules/UIInterface.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
class UIInterface
|
||||
{
|
||||
public:
|
||||
virtual void setup() = 0;
|
||||
virtual void setup_ui() = 0;
|
||||
virtual void wifi_scan_complete(unsigned int size) = 0;
|
||||
virtual void clear_wifi_networks() = 0;
|
||||
virtual void update_wifi(bool connected) = 0;
|
||||
virtual void hide_keyboard() = 0;
|
||||
virtual void show_keyboard() = 0;
|
||||
virtual void update() = 0;
|
||||
virtual void reset_settings_menu() = 0;
|
||||
virtual void update_battery(int percentage, bool isCharging, bool isConnected) = 0;
|
||||
virtual void turnOff() = 0;
|
||||
};
|
25
Platformio/HAL/HardwareModules/wifiHandlerInterface.h
Normal file
25
Platformio/HAL/HardwareModules/wifiHandlerInterface.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
typedef struct {
|
||||
std::string ssid;
|
||||
int rssi;
|
||||
} WifiInfo;
|
||||
|
||||
typedef struct {
|
||||
bool isConnected;
|
||||
std::string IP;
|
||||
std::string ssid;
|
||||
}wifiStatus;
|
||||
|
||||
class wifiHandlerInterface{
|
||||
public:
|
||||
virtual bool isAvailable() = 0;
|
||||
virtual void scan() = 0;
|
||||
virtual void connect(std::shared_ptr<std::string> ssid, std::shared_ptr<std::string> password) = 0;
|
||||
virtual void onScanDone(std::function<void (std::shared_ptr<std::vector<WifiInfo>>)> function) = 0;
|
||||
virtual void onStatusUpdate(std::function<void (std::shared_ptr<wifiStatus>)> function) = 0;
|
||||
virtual void begin() = 0;
|
||||
};
|
9
Platformio/HAL/MPMCQueueInterface.hpp
Normal file
9
Platformio/HAL/MPMCQueueInterface.hpp
Normal file
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
#include "SPSCQueueInterface.hpp"
|
||||
|
||||
template <typename T>
|
||||
class MPMCQueueInterface: public SPSCQueueInterface<T>
|
||||
{
|
||||
public:
|
||||
bool push(T obj, bool overwrite = false);
|
||||
};
|
29
Platformio/HAL/Notification.hpp
Normal file
29
Platformio/HAL/Notification.hpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
template <class... notifyData>
|
||||
class Notification{
|
||||
public:
|
||||
typedef std::function<void(notifyData...)> HandlerTy;
|
||||
|
||||
Notification() = default;
|
||||
void onNotify(HandlerTy aHandler);
|
||||
void notify(notifyData... notifySendData);
|
||||
|
||||
private:
|
||||
std::vector<HandlerTy> mFunctionHandlers;
|
||||
};
|
||||
|
||||
|
||||
template <class... handlerData>
|
||||
void Notification<handlerData...>::onNotify(HandlerTy aHandler){
|
||||
mFunctionHandlers.push_back(std::move(aHandler));
|
||||
}
|
||||
|
||||
template <class... outboundData>
|
||||
void Notification<outboundData...>::notify(outboundData... notifySendData){
|
||||
for (auto handler : mFunctionHandlers){
|
||||
handler(notifySendData...);
|
||||
}
|
||||
}
|
12
Platformio/HAL/SPSCQueueInterface.hpp
Normal file
12
Platformio/HAL/SPSCQueueInterface.hpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
#include <optional>
|
||||
|
||||
template <typename T>
|
||||
class SPSCQueueInterface {
|
||||
public:
|
||||
virtual bool push(T obj) = 0;
|
||||
virtual std::optional<T> pop() = 0;
|
||||
virtual std::optional<T> peek() = 0;
|
||||
virtual bool isFull() = 0;
|
||||
virtual bool isEmpty() = 0;
|
||||
};
|
|
@ -1,5 +1,6 @@
|
|||
#include "HardwareRevX.hpp"
|
||||
#include "driver/ledc.h"
|
||||
#include "display.hpp"
|
||||
#include "wifihandler.hpp"
|
||||
|
||||
std::shared_ptr<HardwareRevX> HardwareRevX::mInstance = nullptr;
|
||||
|
||||
|
@ -49,6 +50,10 @@ void HardwareRevX::initIO() {
|
|||
gpio_deep_sleep_hold_dis();
|
||||
}
|
||||
|
||||
HardwareRevX::HardwareRevX():
|
||||
HardwareAbstract(){
|
||||
}
|
||||
|
||||
HardwareRevX::WakeReason getWakeReason() {
|
||||
// Find out wakeup cause
|
||||
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT1) {
|
||||
|
@ -64,110 +69,53 @@ HardwareRevX::WakeReason getWakeReason() {
|
|||
void HardwareRevX::init() {
|
||||
// Make sure ESP32 is running at full speed
|
||||
setCpuFrequencyMhz(240);
|
||||
|
||||
wakeup_reason = getWakeReason();
|
||||
initIO();
|
||||
setupBacklight();
|
||||
Serial.begin(115200);
|
||||
|
||||
mDisplay = Display::getInstance();
|
||||
mBattery = std::make_shared<Battery>(ADC_BAT,CRG_STAT);
|
||||
mWifiHandler = wifiHandler::getInstance();
|
||||
restorePreferences();
|
||||
slowDisplayWakeup();
|
||||
setupTFT();
|
||||
setupTouchScreen();
|
||||
initLVGL();
|
||||
setupWifi();
|
||||
|
||||
mDisplay->onTouch([this]([[maybe_unused]] auto touchPoint){ standbyTimer = SLEEP_TIMEOUT;});
|
||||
|
||||
setupIMU();
|
||||
setupIR();
|
||||
|
||||
debugPrint(std::string("Finished Hardware Setup in %d", millis()));
|
||||
debugPrint("Finished Hardware Setup in %d", millis());
|
||||
}
|
||||
|
||||
void HardwareRevX::debugPrint(std::string aDebugMessage) {
|
||||
Serial.print(aDebugMessage.c_str());
|
||||
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);
|
||||
}
|
||||
|
||||
void HardwareRevX::sendIR() {}
|
||||
|
||||
void HardwareRevX::MQTTPublish(const char *topic, const char *payload) {
|
||||
#ifdef ENABLE_WIFI
|
||||
if (client.connected()) {
|
||||
client.publish(topic, payload);
|
||||
} else {
|
||||
debugPrint("MQTT Client Not Connected When Attempting Publish.");
|
||||
std::shared_ptr<HardwareRevX> HardwareRevX::getInstance(){
|
||||
if (!mInstance) {
|
||||
mInstance = std::shared_ptr<HardwareRevX>(new HardwareRevX());
|
||||
}
|
||||
#else
|
||||
debugPrint("Attempting To Publish MQTT with wifi Disabled!");
|
||||
#endif
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
HardwareInterface::batteryStatus HardwareRevX::getBatteryPercentage() {
|
||||
return battery;
|
||||
std::shared_ptr<wifiHandlerInterface> HardwareRevX::wifi()
|
||||
{
|
||||
return mWifiHandler;
|
||||
}
|
||||
|
||||
void HardwareRevX::initLVGL() {
|
||||
lv_init();
|
||||
|
||||
lv_disp_draw_buf_init(&mdraw_buf, mbufA, mbufB,
|
||||
SCREEN_WIDTH * SCREEN_HEIGHT / 10);
|
||||
|
||||
// Initialize the display driver
|
||||
static lv_disp_drv_t disp_drv;
|
||||
lv_disp_drv_init(&disp_drv);
|
||||
disp_drv.hor_res = SCREEN_WIDTH;
|
||||
disp_drv.ver_res = SCREEN_HEIGHT;
|
||||
disp_drv.flush_cb = &HardwareRevX::displayFlushImpl;
|
||||
disp_drv.draw_buf = &mdraw_buf;
|
||||
lv_disp_drv_register(&disp_drv);
|
||||
|
||||
// Initialize the touchscreen driver
|
||||
static lv_indev_drv_t indev_drv;
|
||||
lv_indev_drv_init(&indev_drv);
|
||||
indev_drv.type = LV_INDEV_TYPE_POINTER;
|
||||
indev_drv.read_cb = &HardwareRevX::touchPadReadImpl;
|
||||
lv_indev_drv_register(&indev_drv);
|
||||
std::shared_ptr<BatteryInterface> HardwareRevX::battery(){
|
||||
return mBattery;
|
||||
}
|
||||
|
||||
void HardwareRevX::handleDisplayFlush(lv_disp_drv_t *disp,
|
||||
const lv_area_t *area,
|
||||
lv_color_t *color_p) {
|
||||
uint32_t w = (area->x2 - area->x1 + 1);
|
||||
uint32_t h = (area->y2 - area->y1 + 1);
|
||||
|
||||
tft.startWrite();
|
||||
tft.setAddrWindow(area->x1, area->y1, w, h);
|
||||
tft.pushPixelsDMA((uint16_t *)&color_p->full, w * h);
|
||||
tft.endWrite();
|
||||
|
||||
lv_disp_flush_ready(disp);
|
||||
}
|
||||
|
||||
void HardwareRevX::handleTouchPadRead(lv_indev_drv_t *indev_driver,
|
||||
lv_indev_data_t *data) {
|
||||
// int16_t touchX, touchY;
|
||||
touchPoint = touch.getPoint();
|
||||
int16_t touchX = touchPoint.x;
|
||||
int16_t touchY = touchPoint.y;
|
||||
bool touched = false;
|
||||
if ((touchX > 0) || (touchY > 0)) {
|
||||
touched = true;
|
||||
standbyTimer = SLEEP_TIMEOUT;
|
||||
}
|
||||
|
||||
if (!touched) {
|
||||
data->state = LV_INDEV_STATE_REL;
|
||||
} else {
|
||||
data->state = LV_INDEV_STATE_PR;
|
||||
|
||||
// Set the coordinates
|
||||
data->point.x = SCREEN_WIDTH - touchX;
|
||||
data->point.y = SCREEN_HEIGHT - touchY;
|
||||
|
||||
// Serial.print( "touchpoint: x" );
|
||||
// Serial.print( touchX );
|
||||
// Serial.print( " y" );
|
||||
// Serial.println( touchY );
|
||||
// tft.drawFastHLine(0, screenHeight - touchY, screenWidth, TFT_RED);
|
||||
// tft.drawFastVLine(screenWidth - touchX, 0, screenHeight, TFT_RED);
|
||||
}
|
||||
std::shared_ptr<DisplayAbstract> HardwareRevX::display(){
|
||||
return mDisplay;
|
||||
}
|
||||
|
||||
void HardwareRevX::activityDetection() {
|
||||
|
@ -197,7 +145,7 @@ void HardwareRevX::activityDetection() {
|
|||
void HardwareRevX::enterSleep() {
|
||||
// Save settings to internal flash memory
|
||||
preferences.putBool("wkpByIMU", wakeupByIMUEnabled);
|
||||
preferences.putUChar("blBrightness", backlight_brightness);
|
||||
preferences.putUChar("blBrightness", mDisplay->getBrightness());
|
||||
preferences.putUChar("currentDevice", currentDevice);
|
||||
if (!preferences.getBool("alreadySetUp"))
|
||||
preferences.putBool("alreadySetUp", true);
|
||||
|
@ -210,12 +158,6 @@ void HardwareRevX::enterSleep() {
|
|||
IMU.readRegister(&intDataRead,
|
||||
LIS3DH_INT1_SRC); // really clear interrupt
|
||||
|
||||
#ifdef ENABLE_WIFI
|
||||
// Power down modem
|
||||
WiFi.disconnect();
|
||||
WiFi.mode(WIFI_OFF);
|
||||
#endif
|
||||
|
||||
// Prepare IO states
|
||||
digitalWrite(LCD_DC, LOW); // LCD control signals off
|
||||
digitalWrite(LCD_CS, LOW);
|
||||
|
@ -309,51 +251,16 @@ void HardwareRevX::configIMUInterrupts() {
|
|||
IMU.writeRegister(LIS3DH_CTRL_REG3, dataToWrite);
|
||||
}
|
||||
|
||||
void HardwareRevX::setupBacklight() {
|
||||
// Configure the backlight PWM
|
||||
// Manual setup because ledcSetup() briefly turns on the backlight
|
||||
ledc_channel_config_t ledc_channel_left;
|
||||
ledc_channel_left.gpio_num = (gpio_num_t)LCD_BL;
|
||||
ledc_channel_left.speed_mode = LEDC_HIGH_SPEED_MODE;
|
||||
ledc_channel_left.channel = LEDC_CHANNEL_5;
|
||||
ledc_channel_left.intr_type = LEDC_INTR_DISABLE;
|
||||
ledc_channel_left.timer_sel = LEDC_TIMER_1;
|
||||
ledc_channel_left.flags.output_invert = 1; // Can't do this with ledcSetup()
|
||||
ledc_channel_left.duty = 0;
|
||||
|
||||
ledc_timer_config_t ledc_timer;
|
||||
ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE;
|
||||
ledc_timer.duty_resolution = LEDC_TIMER_8_BIT;
|
||||
ledc_timer.timer_num = LEDC_TIMER_1;
|
||||
ledc_timer.freq_hz = 640;
|
||||
|
||||
ledc_channel_config(&ledc_channel_left);
|
||||
ledc_timer_config(&ledc_timer);
|
||||
}
|
||||
|
||||
void HardwareRevX::restorePreferences() {
|
||||
// Restore settings from internal flash memory
|
||||
int backlight_brightness = 255;
|
||||
preferences.begin("settings", false);
|
||||
if (preferences.getBool("alreadySetUp")) {
|
||||
wakeupByIMUEnabled = preferences.getBool("wkpByIMU");
|
||||
backlight_brightness = preferences.getUChar("blBrightness");
|
||||
currentDevice = preferences.getUChar("currentDevice");
|
||||
}
|
||||
}
|
||||
|
||||
void HardwareRevX::setupTFT() {
|
||||
// Setup TFT
|
||||
tft.init();
|
||||
tft.initDMA();
|
||||
tft.setRotation(0);
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
tft.setSwapBytes(true);
|
||||
}
|
||||
|
||||
void HardwareRevX::setupTouchScreen() {
|
||||
// Configure i2c pins and set frequency to 400kHz
|
||||
Wire.begin(SDA, SCL, 400000);
|
||||
touch.begin(128); // Initialize touchscreen and set sensitivity threshold
|
||||
mDisplay->setBrightness(backlight_brightness);
|
||||
}
|
||||
|
||||
void HardwareRevX::setupIMU() {
|
||||
|
@ -371,37 +278,6 @@ void HardwareRevX::setupIMU() {
|
|||
IMU.readRegister(&intDataRead, LIS3DH_INT1_SRC); // clear interrupt
|
||||
}
|
||||
|
||||
void HardwareRevX::slowDisplayWakeup() {
|
||||
// Slowly charge the VSW voltage to prevent a brownout
|
||||
// Workaround for hardware rev 1!
|
||||
for (int i = 0; i < 100; i++) {
|
||||
digitalWrite(LCD_EN, HIGH); // LCD Logic off
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(LCD_EN, LOW); // LCD Logic on
|
||||
}
|
||||
|
||||
delay(100); // Wait for the LCD driver to power on
|
||||
}
|
||||
|
||||
void HardwareRevX::handleWifiEvent(WiFiEvent_t event) {
|
||||
#ifdef ENABLE_WIFI
|
||||
// Serial.printf("[WiFi-event] event: %d\n", event);
|
||||
if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP) {
|
||||
client.setServer(MQTT_SERVER, 1883); // MQTT initialization
|
||||
client.connect("OMOTE"); // Connect using a client id
|
||||
}
|
||||
// Set status bar icon based on WiFi status
|
||||
// TODO allow UI to register a Handler for these events
|
||||
|
||||
// if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP ||
|
||||
// event == ARDUINO_EVENT_WIFI_STA_GOT_IP6) {
|
||||
// lv_label_set_text(WifiLabel, LV_SYMBOL_WIFI);
|
||||
// } else {
|
||||
// lv_label_set_text(WifiLabel, "");
|
||||
// }
|
||||
#endif
|
||||
}
|
||||
|
||||
void HardwareRevX::setupIR() {
|
||||
// Setup IR
|
||||
IrSender.begin();
|
||||
|
@ -409,52 +285,11 @@ void HardwareRevX::setupIR() {
|
|||
IrReceiver.enableIRIn(); // Start the receiver
|
||||
}
|
||||
|
||||
void HardwareRevX::setupWifi() {
|
||||
#ifdef ENABLE_WIFI
|
||||
// Setup WiFi
|
||||
WiFi.setHostname("OMOTE"); // define hostname
|
||||
WiFi.onEvent(wiFiEventImpl);
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
||||
WiFi.setSleep(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void HardwareRevX::startTasks() {
|
||||
if (xTaskCreate(&HardwareRevX::updateBatteryTask, "Battery Percent Update",
|
||||
1024, nullptr, 5, &batteryUpdateTskHndl) != pdPASS) {
|
||||
debugPrint("ERROR Could not Create Battery Update Task!");
|
||||
}
|
||||
}
|
||||
|
||||
void HardwareRevX::updateBatteryTask([[maybe_unused]] void *aData) {
|
||||
while (true) {
|
||||
mInstance->battery.voltage =
|
||||
analogRead(ADC_BAT) * 2 * 3300 / 4095 + 350; // 350mV ADC offset
|
||||
mInstance->battery.percentage =
|
||||
constrain(map(mInstance->battery.voltage, 3700, 4200, 0, 100), 0, 100);
|
||||
mInstance->battery.isCharging = !digitalRead(CRG_STAT);
|
||||
// Check if battery is charging, fully charged or disconnected
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
// Update battery at 1Hz
|
||||
}
|
||||
}
|
||||
void HardwareRevX::startTasks() {}
|
||||
|
||||
void HardwareRevX::loopHandler() {
|
||||
|
||||
// TODO Move the backlight handling into task that spawns when the backlight
|
||||
// setting changes and then gets deleted when the setting is achieved.
|
||||
// Update Backlight brightness
|
||||
static int fadeInTimer = millis(); // fadeInTimer = time after setup
|
||||
if (millis() <
|
||||
fadeInTimer + backlight_brightness) { // Fade in the backlight brightness
|
||||
ledcWrite(5, millis() - fadeInTimer);
|
||||
} else { // Dim Backlight before entering standby
|
||||
if (standbyTimer < 2000)
|
||||
ledcWrite(5, 85); // Backlight dim
|
||||
else
|
||||
ledcWrite(5, backlight_brightness); // Backlight on
|
||||
}
|
||||
|
||||
standbyTimer < 2000 ? mDisplay->sleep() : mDisplay->wake();
|
||||
|
||||
// TODO move to debug task
|
||||
// Blink debug LED at 1 Hz
|
||||
digitalWrite(USER_LED, millis() % 1000 > 500);
|
||||
|
@ -470,30 +305,6 @@ void HardwareRevX::loopHandler() {
|
|||
IMUTaskTimer = millis();
|
||||
}
|
||||
|
||||
// TODO Convert to free RTOS task
|
||||
|
||||
// TODO Create batter change notification for UI
|
||||
|
||||
// if (battery_ischarging || (!battery_ischarging && battery_voltage >
|
||||
// 4350)) {
|
||||
// lv_label_set_text(objBattPercentage, "");
|
||||
// lv_label_set_text(objBattIcon, LV_SYMBOL_USB);
|
||||
// } else {
|
||||
// // Update status bar battery indicator
|
||||
// // lv_label_set_text_fmt(objBattPercentage, "%d%%",
|
||||
// battery_percentage); if (battery_percentage > 95)
|
||||
// lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_FULL);
|
||||
// else if (battery_percentage > 75)
|
||||
// lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_3);
|
||||
// else if (battery_percentage > 50)
|
||||
// lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_2);
|
||||
// else if (battery_percentage > 25)
|
||||
// lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_1);
|
||||
// else
|
||||
// lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_EMPTY);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Keypad Handling
|
||||
customKeypad.getKey(); // Populate key list
|
||||
for (int i = 0; i < LIST_MAX;
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
#pragma once
|
||||
#include "SparkFunLIS3DH.h"
|
||||
|
||||
#include "HardwareInterface.h"
|
||||
#include <WiFi.h>
|
||||
#include "Wire.h"
|
||||
#include "HardwareAbstract.hpp"
|
||||
#include "lvgl.h"
|
||||
#include <Adafruit_FT6206.h>
|
||||
#include "battery.hpp"
|
||||
#include <IRrecv.h>
|
||||
#include <IRremoteESP8266.h>
|
||||
#include <IRsend.h>
|
||||
|
@ -13,90 +11,56 @@
|
|||
#include <Keypad.h> // modified for inverted logic
|
||||
#include <Preferences.h>
|
||||
#include <PubSubClient.h>
|
||||
#include <TFT_eSPI.h> // Hardware-specific library
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include "wifihandler.hpp"
|
||||
|
||||
|
||||
|
||||
#include "omoteconfig.h"
|
||||
#include "BatteryInterface.h"
|
||||
#include "wifiHandlerInterface.h"
|
||||
#include "display.hpp"
|
||||
|
||||
class HardwareRevX : public HardwareInterface {
|
||||
class HardwareRevX : public HardwareAbstract {
|
||||
public:
|
||||
enum class WakeReason { RESET, IMU, KEYPAD };
|
||||
|
||||
static std::shared_ptr<HardwareRevX> getInstance() {
|
||||
if (!mInstance) {
|
||||
mInstance = std::make_shared<HardwareRevX>();
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
static std::shared_ptr<HardwareRevX> getInstance();
|
||||
static std::weak_ptr<HardwareRevX> getRefrence() { return getInstance(); }
|
||||
|
||||
HardwareRevX() : HardwareInterface(){};
|
||||
// HardwareInterface
|
||||
// HardwareAbstract
|
||||
virtual void init() override;
|
||||
virtual void sendIR() override;
|
||||
virtual void MQTTPublish(const char *topic, const char *payload) override;
|
||||
virtual batteryStatus getBatteryPercentage() override;
|
||||
virtual void debugPrint(std::string aDebugMessage) override;
|
||||
virtual void debugPrint(const char* fmt, ...) override;
|
||||
|
||||
virtual std::shared_ptr<BatteryInterface> battery() override;
|
||||
virtual std::shared_ptr<DisplayAbstract> display() override;
|
||||
virtual std::shared_ptr<wifiHandlerInterface> wifi() override;
|
||||
|
||||
/// @brief To be ran in loop out in main
|
||||
// TODO move to a freertos task
|
||||
void loopHandler();
|
||||
|
||||
protected:
|
||||
// Init Functions to setup hardware
|
||||
void initIO();
|
||||
void setupBacklight();
|
||||
void restorePreferences();
|
||||
void slowDisplayWakeup();
|
||||
void setupTFT();
|
||||
void setupTouchScreen();
|
||||
void initLVGL();
|
||||
void setupIMU();
|
||||
void setupIR();
|
||||
void setupWifi();
|
||||
|
||||
void activityDetection();
|
||||
void enterSleep();
|
||||
void configIMUInterrupts();
|
||||
|
||||
// UI/UX Handlers
|
||||
void handleDisplayFlush(lv_disp_drv_t *disp, const lv_area_t *area,
|
||||
lv_color_t *color_p);
|
||||
void handleTouchPadRead(lv_indev_drv_t *indev_driver, lv_indev_data_t *data);
|
||||
|
||||
void handleWifiEvent(WiFiEvent_t event);
|
||||
|
||||
// Tasks
|
||||
void startTasks();
|
||||
|
||||
static void updateBatteryTask([[maybe_unused]] void *aData);
|
||||
TaskHandle_t batteryUpdateTskHndl = nullptr;
|
||||
|
||||
private:
|
||||
// Static Wrappers Needed to Satisfy C APIs
|
||||
static void wiFiEventImpl(WiFiEvent_t event) {
|
||||
mInstance->handleWifiEvent(event);
|
||||
}
|
||||
static void displayFlushImpl(lv_disp_drv_t *disp, const lv_area_t *area,
|
||||
lv_color_t *color_p) {
|
||||
mInstance->handleDisplayFlush(disp, area, color_p);
|
||||
}
|
||||
static void touchPadReadImpl(lv_indev_drv_t *indev_driver,
|
||||
lv_indev_data_t *data) {
|
||||
mInstance->handleTouchPadRead(indev_driver, data);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_WIFI
|
||||
WiFiClient espClient;
|
||||
PubSubClient client = PubSubClient(espClient);
|
||||
#endif
|
||||
|
||||
Adafruit_FT6206 touch = Adafruit_FT6206();
|
||||
TS_Point touchPoint;
|
||||
TS_Point oldPoint;
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
HardwareRevX();
|
||||
|
||||
std::shared_ptr<Battery> mBattery;
|
||||
std::shared_ptr<Display> mDisplay;
|
||||
std::shared_ptr<wifiHandler> mWifiHandler;
|
||||
// IMU Motion Detection
|
||||
LIS3DH IMU = LIS3DH(I2C_MODE, 0x19); // Default constructor is I2C, addr 0x19.
|
||||
int standbyTimer = SLEEP_TIMEOUT;
|
||||
|
@ -105,7 +69,6 @@ private:
|
|||
|
||||
Preferences preferences;
|
||||
bool wakeupByIMUEnabled = true;
|
||||
int backlight_brightness = 255;
|
||||
byte currentDevice = 1; // Current Device to control (allows switching
|
||||
// mappings between devices)
|
||||
|
||||
|
@ -113,14 +76,6 @@ private:
|
|||
IRsend IrSender = IRsend(IR_LED, true);
|
||||
IRrecv IrReceiver = IRrecv(IR_RX);
|
||||
|
||||
HardwareInterface::batteryStatus battery;
|
||||
|
||||
// LVGL Screen Buffers
|
||||
lv_disp_draw_buf_t mdraw_buf;
|
||||
lv_color_t mbufA[SCREEN_WIDTH * SCREEN_HEIGHT / 10];
|
||||
lv_color_t mbufB[SCREEN_WIDTH * SCREEN_HEIGHT / 10];
|
||||
|
||||
lv_color_t color_primary = lv_color_hex(0x303030); // gray
|
||||
|
||||
// Keypad declarations
|
||||
static const byte ROWS = 5; // four rows
|
||||
|
|
33
Platformio/HAL/Targets/ESP32/battery/battery.cpp
Normal file
33
Platformio/HAL/Targets/ESP32/battery/battery.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include "battery.hpp"
|
||||
#include <Arduino.h>
|
||||
|
||||
Battery::Battery(int adc_pin, int charging_pin): BatteryInterface(),
|
||||
mAdcPin(adc_pin),
|
||||
mChargingPin(charging_pin)
|
||||
{
|
||||
mAdcPin = adc_pin;
|
||||
mChargingPin = charging_pin;
|
||||
// Power Pin Definition
|
||||
pinMode(mChargingPin, INPUT_PULLUP);
|
||||
pinMode(mAdcPin, INPUT);
|
||||
}
|
||||
|
||||
int Battery::getPercentage()
|
||||
{
|
||||
return constrain(map(this->getVoltage(), 3700, 4200, 0, 100), 0, 100);
|
||||
}
|
||||
|
||||
bool Battery::isCharging()
|
||||
{
|
||||
return !digitalRead(mChargingPin);
|
||||
}
|
||||
|
||||
bool Battery::isConnected()
|
||||
{
|
||||
return ((!isCharging()) && (getVoltage() < 4350));
|
||||
}
|
||||
|
||||
int Battery::getVoltage()
|
||||
{
|
||||
return analogRead(mAdcPin)*2*3300/4095 + 350;
|
||||
}
|
58
Platformio/HAL/Targets/ESP32/battery/battery.hpp
Normal file
58
Platformio/HAL/Targets/ESP32/battery/battery.hpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
#include "BatteryInterface.h"
|
||||
#include "DisplayAbstract.h"
|
||||
|
||||
class Battery: public BatteryInterface {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Get the Percentage of the battery
|
||||
*
|
||||
* @return int Percentage of the battery
|
||||
*/
|
||||
virtual int getPercentage() override;
|
||||
|
||||
/**
|
||||
* @brief Function to determine if the battery is charging or not
|
||||
*
|
||||
* @return true Battery is currently charging
|
||||
* @return false Battery is currently not charging
|
||||
*/
|
||||
virtual bool isCharging() override;
|
||||
|
||||
/**
|
||||
* @brief Function to determine if the battery is connected
|
||||
*
|
||||
* @return true Battery is connected
|
||||
* @return false Battery is not connected
|
||||
*/
|
||||
bool isConnected();
|
||||
|
||||
Battery(int adc_pin, int charging_pin);
|
||||
|
||||
// Not sure why this is needed but shared_ptr seems to really
|
||||
// need it possibly a compiler template handling limitation
|
||||
// none the less we really should not use it.
|
||||
Battery() = default;
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief Function to get the current voltage of the battery
|
||||
*
|
||||
* @return int Voltage of the battery in mV
|
||||
*/
|
||||
int getVoltage();
|
||||
|
||||
/**
|
||||
* @brief Variable to store which pin should be used for ADC
|
||||
*
|
||||
*/
|
||||
int mAdcPin;
|
||||
|
||||
/**
|
||||
* @brief Variable to store which pin is used to indicate if the battery is currently charging or not
|
||||
*
|
||||
*/
|
||||
int mChargingPin;
|
||||
|
||||
};
|
194
Platformio/HAL/Targets/ESP32/display/display.cpp
Normal file
194
Platformio/HAL/Targets/ESP32/display/display.cpp
Normal file
|
@ -0,0 +1,194 @@
|
|||
|
||||
#include "display.hpp"
|
||||
#include "omoteconfig.h"
|
||||
#include "Wire.h"
|
||||
#include "driver/ledc.h"
|
||||
|
||||
std::shared_ptr<Display> Display::getInstance()
|
||||
{
|
||||
if (DisplayAbstract::mInstance == nullptr)
|
||||
{
|
||||
DisplayAbstract::mInstance = std::shared_ptr<Display>(new Display(LCD_BL, LCD_EN));
|
||||
}
|
||||
return std::static_pointer_cast<Display>(mInstance);
|
||||
}
|
||||
|
||||
Display::Display(int backlight_pin, int enable_pin): DisplayAbstract(),
|
||||
mBacklightPin(backlight_pin),
|
||||
mEnablePin(enable_pin),
|
||||
tft(TFT_eSPI()),
|
||||
touch(Adafruit_FT6206())
|
||||
{
|
||||
pinMode(mEnablePin, OUTPUT);
|
||||
digitalWrite(mEnablePin, HIGH);
|
||||
pinMode(mBacklightPin, OUTPUT);
|
||||
digitalWrite(mBacklightPin, HIGH);
|
||||
|
||||
setupBacklight(); // This eliminates the flash of the backlight
|
||||
|
||||
// Slowly charge the VSW voltage to prevent a brownout
|
||||
// Workaround for hardware rev 1!
|
||||
for(int i = 0; i < 100; i++){
|
||||
digitalWrite(this->mEnablePin, HIGH); // LCD Logic off
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(this->mEnablePin, LOW); // LCD Logic on
|
||||
}
|
||||
|
||||
setupTFT();
|
||||
setupTouchScreen();
|
||||
mFadeTaskMutex = xSemaphoreCreateBinary();
|
||||
xSemaphoreGive(mFadeTaskMutex);
|
||||
}
|
||||
|
||||
void Display::setupBacklight() {
|
||||
// Configure the backlight PWM
|
||||
// Manual setup because ledcSetup() briefly turns on the backlight
|
||||
ledc_channel_config_t ledc_channel_left;
|
||||
ledc_channel_left.gpio_num = (gpio_num_t)mBacklightPin;
|
||||
ledc_channel_left.speed_mode = LEDC_HIGH_SPEED_MODE;
|
||||
ledc_channel_left.channel = LEDC_CHANNEL_5;
|
||||
ledc_channel_left.intr_type = LEDC_INTR_DISABLE;
|
||||
ledc_channel_left.timer_sel = LEDC_TIMER_1;
|
||||
ledc_channel_left.flags.output_invert = 1; // Can't do this with ledcSetup()
|
||||
ledc_channel_left.duty = 0;
|
||||
ledc_channel_left.hpoint = 0;
|
||||
ledc_timer_config_t ledc_timer;
|
||||
ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE;
|
||||
ledc_timer.duty_resolution = LEDC_TIMER_8_BIT;
|
||||
ledc_timer.timer_num = LEDC_TIMER_1;
|
||||
ledc_timer.clk_cfg = LEDC_AUTO_CLK;
|
||||
ledc_timer.freq_hz = 640;
|
||||
ledc_channel_config(&ledc_channel_left);
|
||||
ledc_timer_config(&ledc_timer);
|
||||
}
|
||||
|
||||
void Display::onTouch(Notification<TS_Point>::HandlerTy aTouchHandler){
|
||||
mTouchEvent.onNotify(std::move(aTouchHandler));
|
||||
}
|
||||
|
||||
void Display::setupTFT() {
|
||||
delay(100);
|
||||
tft.init();
|
||||
tft.initDMA();
|
||||
tft.setRotation(0);
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
tft.setSwapBytes(true);
|
||||
}
|
||||
|
||||
void Display::setupTouchScreen(){
|
||||
// Configure i2c pins and set frequency to 400kHz
|
||||
Wire.begin(SDA, SCL, 400000);
|
||||
touch.begin(128); // Initialize touchscreen and set sensitivity threshold
|
||||
}
|
||||
|
||||
void Display::setBrightness(uint8_t brightness)
|
||||
{
|
||||
mAwakeBrightness = brightness;
|
||||
Serial.print("Set Brightness:");
|
||||
Serial.println(mAwakeBrightness);
|
||||
startFade();
|
||||
}
|
||||
|
||||
uint8_t Display::getBrightness(){
|
||||
return mAwakeBrightness;
|
||||
}
|
||||
|
||||
void Display::setCurrentBrightness(uint8_t brightness){
|
||||
mBrightness = brightness;
|
||||
auto duty = static_cast<int>(mBrightness);
|
||||
ledcWrite(LCD_BACKLIGHT_LEDC_CHANNEL, duty);
|
||||
// Serial.print("Current Brightness:");
|
||||
// Serial.println(mBrightness);
|
||||
}
|
||||
|
||||
void Display::turnOff()
|
||||
{
|
||||
digitalWrite(this->mBacklightPin, HIGH);
|
||||
digitalWrite(this->mEnablePin, HIGH);
|
||||
pinMode(this->mBacklightPin, INPUT);
|
||||
pinMode(this->mEnablePin, INPUT);
|
||||
gpio_hold_en((gpio_num_t) mBacklightPin);
|
||||
gpio_hold_en((gpio_num_t) mEnablePin);
|
||||
}
|
||||
|
||||
void Display::screenInput(lv_indev_drv_t *indev_driver, lv_indev_data_t *data){
|
||||
// int16_t touchX, touchY;
|
||||
touchPoint = touch.getPoint();
|
||||
int16_t touchX = touchPoint.x;
|
||||
int16_t touchY = touchPoint.y;
|
||||
bool touched = false;
|
||||
if ((touchX > 0) || (touchY > 0)) {
|
||||
touched = true;
|
||||
mTouchEvent.notify(touchPoint);
|
||||
}
|
||||
|
||||
if (!touched) {
|
||||
data->state = LV_INDEV_STATE_REL;
|
||||
} else {
|
||||
data->state = LV_INDEV_STATE_PR;
|
||||
|
||||
// Set the coordinates
|
||||
data->point.x = SCREEN_WIDTH - touchX;
|
||||
data->point.y = SCREEN_HEIGHT - touchY;
|
||||
|
||||
// Serial.print( "touchpoint: x" );
|
||||
// Serial.print( touchX );
|
||||
// Serial.print( " y" );
|
||||
// Serial.println( touchY );
|
||||
// tft.drawFastHLine(0, screenHeight - touchY, screenWidth, TFT_RED);
|
||||
// tft.drawFastVLine(screenWidth - touchX, 0, screenHeight, TFT_RED);
|
||||
}
|
||||
}
|
||||
|
||||
void Display::fadeImpl(void* ){
|
||||
bool fadeDone = false;
|
||||
while(!fadeDone){
|
||||
fadeDone = getInstance()->fade();
|
||||
vTaskDelay(3 / portTICK_PERIOD_MS); // 3 miliseconds between steps
|
||||
// 0 - 255 will take about .75 seconds to fade up.
|
||||
}
|
||||
|
||||
xSemaphoreTake(getInstance()->mFadeTaskMutex,portMAX_DELAY);
|
||||
getInstance()->mDisplayFadeTask = nullptr;
|
||||
xSemaphoreGive(getInstance()->mFadeTaskMutex);
|
||||
|
||||
vTaskDelete(nullptr); // Delete Fade Task
|
||||
}
|
||||
|
||||
bool Display::fade(){
|
||||
//Early return no fade needed.
|
||||
if (mBrightness == mAwakeBrightness ||
|
||||
isAsleep && mBrightness == 0){return true;}
|
||||
|
||||
bool fadeDown = isAsleep || mBrightness > mAwakeBrightness;
|
||||
if (fadeDown){
|
||||
setCurrentBrightness(mBrightness - 1);
|
||||
auto setPoint = isAsleep ? 0 : mAwakeBrightness;
|
||||
return mBrightness == setPoint;
|
||||
}else{
|
||||
setCurrentBrightness(mBrightness + 1);
|
||||
return mBrightness == mAwakeBrightness;
|
||||
}
|
||||
}
|
||||
|
||||
void Display::startFade(){
|
||||
xSemaphoreTake(mFadeTaskMutex,portMAX_DELAY);
|
||||
// Only Create Task if it is needed
|
||||
if(mDisplayFadeTask == nullptr){
|
||||
xTaskCreate(&Display::fadeImpl, "Display Fade Task",
|
||||
1024, nullptr, 5, &mDisplayFadeTask);
|
||||
}
|
||||
xSemaphoreGive(mFadeTaskMutex);
|
||||
}
|
||||
|
||||
void Display::flushDisplay(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
|
||||
uint32_t w = (area->x2 - area->x1 + 1);
|
||||
uint32_t h = (area->y2 - area->y1 + 1);
|
||||
|
||||
tft.startWrite();
|
||||
tft.setAddrWindow(area->x1, area->y1, w, h);
|
||||
tft.pushPixelsDMA((uint16_t *)&color_p->full, w * h);
|
||||
tft.endWrite();
|
||||
|
||||
lv_disp_flush_ready(disp);
|
||||
}
|
73
Platformio/HAL/Targets/ESP32/display/display.hpp
Normal file
73
Platformio/HAL/Targets/ESP32/display/display.hpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
#pragma once
|
||||
#include "DisplayAbstract.h"
|
||||
#include "HardwareAbstract.hpp"
|
||||
#include "Notification.hpp"
|
||||
#include <Adafruit_FT6206.h>
|
||||
#include <memory>
|
||||
#include <TFT_eSPI.h>
|
||||
#include "driver/ledc.h"
|
||||
|
||||
/*LEDC Channel to use for the LCD backlight*/
|
||||
#define LCD_BACKLIGHT_LEDC_CHANNEL LEDC_CHANNEL_5
|
||||
|
||||
#define LCD_BACKLIGHT_LEDC_FREQUENCY 640
|
||||
|
||||
#define LCD_BACKLIGHT_LEDC_BIT_RESOLUTION 8
|
||||
|
||||
#define DEFAULT_BACKLIGHT_BRIGHTNESS 128
|
||||
|
||||
|
||||
class Display: public DisplayAbstract
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<Display> getInstance();
|
||||
|
||||
/// @brief Set brightness setting and fade to it
|
||||
/// @param brightness
|
||||
virtual void setBrightness(uint8_t brightness) override;
|
||||
virtual uint8_t getBrightness() override;
|
||||
virtual void turnOff() override;
|
||||
|
||||
void onTouch(Notification<TS_Point>::HandlerTy aTouchHandler);
|
||||
|
||||
inline void wake() {if(isAsleep) {isAsleep = false; startFade();}}
|
||||
inline void sleep() {if(!isAsleep){isAsleep = true; startFade();}}
|
||||
|
||||
protected:
|
||||
virtual void flushDisplay(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p);
|
||||
virtual void screenInput(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) override;
|
||||
|
||||
/// @brief Fade toward brightness based on isAwake
|
||||
/// @return True - Fade complete
|
||||
/// False - Fade set point not reached
|
||||
bool fade();
|
||||
/// @brief Start the Fade task
|
||||
void startFade();
|
||||
|
||||
/// @brief Set the actual display brightness right now
|
||||
/// @param brightness
|
||||
void setCurrentBrightness(uint8_t brightness);
|
||||
|
||||
private:
|
||||
Display(int backlight_pin, int enable_pin);
|
||||
void setupTFT();
|
||||
void setupTouchScreen();
|
||||
void setupBacklight();
|
||||
|
||||
int mEnablePin;
|
||||
int mBacklightPin;
|
||||
TFT_eSPI tft;
|
||||
|
||||
Adafruit_FT6206 touch;
|
||||
TS_Point touchPoint;
|
||||
TS_Point oldPoint;
|
||||
Notification<TS_Point> mTouchEvent;
|
||||
|
||||
TaskHandle_t mDisplayFadeTask = nullptr;
|
||||
SemaphoreHandle_t mFadeTaskMutex = nullptr;
|
||||
static void fadeImpl(void* aBrightness);
|
||||
|
||||
uint8_t mBrightness = 0; // Current display brightness
|
||||
uint8_t mAwakeBrightness = 100; // Current setting for brightness when awake
|
||||
bool isAsleep = false;
|
||||
};
|
70
Platformio/HAL/Targets/ESP32/freeRTOSMPMCQueue.cpp
Normal file
70
Platformio/HAL/Targets/ESP32/freeRTOSMPMCQueue.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include "freeRTOSMPMCQueue.hpp"
|
||||
|
||||
template <typename T>
|
||||
freeRTOSMPMCQueue<T>::freeRTOSMPMCQueue(uint32_t size)
|
||||
{
|
||||
this->queue = xQueueCreate(size, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
freeRTOSMPMCQueue<T>::~freeRTOSMPMCQueue()
|
||||
{
|
||||
vQueueDelete(this->queue);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool freeRTOSMPMCQueue<T>::push(T obj)
|
||||
{
|
||||
return xQueueSendToBack(this->queue, &obj, 0) == pdTRUE;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool freeRTOSMPMCQueue<T>::push(T obj, bool overwrite)
|
||||
{
|
||||
if (overwrite == true)
|
||||
{
|
||||
xQueueOverwrite(this->queue, obj);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this->push(obj);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::optional<T> freeRTOSMPMCQueue<T>::pop()
|
||||
{
|
||||
T retval;
|
||||
|
||||
if (xQueueReceive(this->queue, &retval, 0) == pdTRUE)
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::optional<T> freeRTOSMPMCQueue<T>::peek()
|
||||
{
|
||||
T retval;
|
||||
|
||||
if (xQueuePeek(this->queue, &retval, 0) == pdTRUE)
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool freeRTOSMPMCQueue<T>::isFull()
|
||||
{
|
||||
return (xQueueIsQueueFullFromISR(this->queue) == pdTRUE);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool freeRTOSMPMCQueue<T>::isEmpty()
|
||||
{
|
||||
return (xQueueIsQueueEmptyFromISR(this->queue) == pdTRUE);
|
||||
}
|
18
Platformio/HAL/Targets/ESP32/freeRTOSMPMCQueue.hpp
Normal file
18
Platformio/HAL/Targets/ESP32/freeRTOSMPMCQueue.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
#include "MPMCQueueInterface.hpp"
|
||||
#include "Arduino.h"
|
||||
template <typename T>
|
||||
class freeRTOSMPMCQueue: public MPMCQueueInterface<T>
|
||||
{
|
||||
public:
|
||||
freeRTOSMPMCQueue(uint32_t size);
|
||||
~freeRTOSMPMCQueue();
|
||||
bool push (T obj);
|
||||
bool push (T obj, bool overwrite);
|
||||
std::optional<T> pop();
|
||||
std::optional<T> peek();
|
||||
bool isFull();
|
||||
bool isEmpty();
|
||||
private:
|
||||
QueueHandle_t queue;
|
||||
};
|
230
Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.cpp
Normal file
230
Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.cpp
Normal file
|
@ -0,0 +1,230 @@
|
|||
#include "wifihandler.hpp"
|
||||
#include <Arduino.h>
|
||||
#include <Preferences.h>
|
||||
#include "HardwareAbstract.hpp"
|
||||
#include "WiFi.h"
|
||||
|
||||
std::shared_ptr<wifiHandler> 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<WifiInfo> *vec = new std::vector<WifiInfo>();
|
||||
std::shared_ptr<std::vector<WifiInfo>> info = std::shared_ptr<std::vector<WifiInfo>>(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");
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO Convert To callbacks
|
||||
//this->display.clear_wifi_networks();
|
||||
Serial.print(no_networks);
|
||||
Serial.print(" found\n");
|
||||
//this->display.wifi_scan_complete( no_networks);
|
||||
}
|
||||
this->scan_notification.notify(info);
|
||||
if (WiFi.isConnected() == false)
|
||||
{
|
||||
WiFi.reconnect();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
||||
this->update_credentials();
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
case ARDUINO_EVENT_WIFI_STA_LOST_IP:
|
||||
case ARDUINO_EVENT_WIFI_STA_STOP:
|
||||
this->update_status();
|
||||
default:
|
||||
Serial.print("Wifi Status: ");
|
||||
Serial.println(WiFi.status());
|
||||
break;
|
||||
}
|
||||
if (WiFi.status() == WL_CONNECT_FAILED)
|
||||
{
|
||||
Serial.println("connection failed.");
|
||||
WiFi.disconnect();
|
||||
}
|
||||
Serial.println(WiFi.status());
|
||||
}
|
||||
|
||||
bool wifiHandler::isAvailable(){
|
||||
return true;
|
||||
}
|
||||
std::shared_ptr<wifiHandler> wifiHandler::getInstance()
|
||||
{
|
||||
if(mInstance)
|
||||
{
|
||||
return mInstance;
|
||||
}
|
||||
mInstance = std::shared_ptr<wifiHandler>(new wifiHandler());
|
||||
return mInstance;
|
||||
};
|
||||
|
||||
wifiHandler::wifiHandler()
|
||||
{
|
||||
this->password = "";
|
||||
this->SSID = "";
|
||||
}
|
||||
|
||||
void wifiHandler::update_status()
|
||||
{
|
||||
Serial.println("update_status");
|
||||
std::shared_ptr<wifiStatus> status = std::make_shared<wifiStatus>(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->status_update.notify(status);
|
||||
}
|
||||
|
||||
void wifiHandler::update_credentials()
|
||||
{
|
||||
// No connection was attempted so don't try to to save the creds
|
||||
if(!this->connect_attempt) return;
|
||||
#if 0
|
||||
if (strcmp(temporary_password, wifiHandler::password) != 0 || strcmp(temporary_ssid, wifiHandler::SSID) != 0)
|
||||
{
|
||||
strcpy(wifiHandler::password, temporary_password);
|
||||
strcpy(wifiHandler::SSID, temporary_ssid);
|
||||
|
||||
Preferences preferences;
|
||||
preferences.begin("wifiSettings", false);
|
||||
String tempString = wifiHandler::password;
|
||||
preferences.putString("password", tempString);
|
||||
tempString = wifiHandler::SSID;
|
||||
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
|
||||
this->connect_attempt = false;
|
||||
}
|
||||
|
||||
void wifiHandler::scan()
|
||||
{
|
||||
Serial.println("scan called");
|
||||
/* If the */
|
||||
WiFi.status();
|
||||
if (WiFi.isConnected() != true)
|
||||
{
|
||||
WiFi.disconnect();
|
||||
}
|
||||
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;
|
||||
preferences.begin("wifiSettings",false);
|
||||
String ssid = preferences.getString("SSID");
|
||||
String password = preferences.getString("password");
|
||||
preferences.end();
|
||||
|
||||
/* If the SSID is not empty, there was a value stored in the preferences and we try to use it.*/
|
||||
if (!ssid.isEmpty())
|
||||
{
|
||||
Serial.print("Connecting to wifi ");
|
||||
Serial.println(ssid);
|
||||
//strcpy(this->SSID, ssid.c_str());
|
||||
//strcpy(this->password, password.c_str());
|
||||
this->SSID = ssid.c_str();
|
||||
this->password = password.c_str();
|
||||
this->connect(std::make_shared<std::string>(std::string(this->SSID)), std::make_shared<std::string>(std::string(this->password)));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("no SSID or password stored");
|
||||
/*Set first character to \0 indicates an empty string*/
|
||||
this->SSID[0] = '\0';
|
||||
this->password[0] = '\0';
|
||||
WiFi.disconnect();
|
||||
}
|
||||
|
||||
WiFi.setSleep(true);
|
||||
}
|
||||
|
||||
void wifiHandler::onScanDone(std::function<void (std::shared_ptr<std::vector<WifiInfo>>)> function){
|
||||
this->scan_notification.onNotify(std::move(function));
|
||||
}
|
||||
|
||||
void wifiHandler::onStatusUpdate(std::function<void (std::shared_ptr<wifiStatus>)> function){
|
||||
this->status_update.onNotify(std::move(function));
|
||||
}
|
||||
|
||||
void wifiHandler::connect(std::shared_ptr<std::string> ssid, std::shared_ptr<std::string> password)
|
||||
{
|
||||
this->connect_attempt = true;
|
||||
this->temporary_password = password;
|
||||
this->temporary_ssid = ssid;
|
||||
WiFi.begin(ssid->c_str(), password->c_str());
|
||||
}
|
||||
|
||||
void wifiHandler::turnOff()
|
||||
{
|
||||
WiFi.disconnect();
|
||||
WiFi.mode(WIFI_OFF);
|
||||
}
|
||||
|
||||
void wifiHandler::disconnect(){
|
||||
WiFi.disconnect();
|
||||
}
|
||||
|
||||
bool wifiHandler::isConnected()
|
||||
{
|
||||
return WiFi.isConnected();
|
||||
}
|
||||
|
||||
std::string wifiHandler::getIP()
|
||||
{
|
||||
return std::string(WiFi.localIP().toString().c_str());
|
||||
}
|
99
Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.hpp
Normal file
99
Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.hpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
#pragma once
|
||||
#include "wifiHandlerInterface.h"
|
||||
#include "Notification.hpp"
|
||||
#include "memory.h"
|
||||
#include <WiFi.h>
|
||||
|
||||
#define STRING_SIZE 50
|
||||
|
||||
class wifiHandler: public wifiHandlerInterface {
|
||||
public:
|
||||
wifiHandler();
|
||||
static std::shared_ptr<wifiHandler> getInstance();
|
||||
/**
|
||||
* @brief Function to initialize the wifi handler
|
||||
*
|
||||
*/
|
||||
void begin();
|
||||
|
||||
/**
|
||||
* @brief Connect to the wifi using the provided credetials
|
||||
*
|
||||
* @param SSID
|
||||
* @param password
|
||||
*/
|
||||
void connect(std::shared_ptr<std::string> ssid, std::shared_ptr<std::string> password);
|
||||
//void connect(const char* SSID, const char* password);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief function to trigger asynchronous scan for wifi networks
|
||||
*
|
||||
*/
|
||||
void scan();
|
||||
bool isAvailable();
|
||||
void onScanDone(std::function<void (std::shared_ptr<std::vector<WifiInfo>>)> function);
|
||||
void onStatusUpdate(std::function<void (std::shared_ptr<wifiStatus>)> function);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
Notification<std::shared_ptr<std::vector<WifiInfo>>> scan_notification;
|
||||
Notification<std::shared_ptr<wifiStatus>> status_update;
|
||||
/**
|
||||
* @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
|
||||
* overwritten.
|
||||
*
|
||||
* @param temporary_ssid
|
||||
* @param temporary_password
|
||||
*/
|
||||
void update_credentials();
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event);
|
||||
|
||||
/**
|
||||
* @brief Function to turn off wifi
|
||||
*
|
||||
*/
|
||||
void turnOff();
|
||||
/**
|
||||
* @brief Function to get the IP address of this device
|
||||
*
|
||||
* @return String IP Address of the device
|
||||
*/
|
||||
std::string getIP();
|
||||
wifiStatus wifi_status;
|
||||
static std::shared_ptr<wifiHandler> mInstance;
|
||||
bool connect_attempt = false;
|
||||
std::shared_ptr<std::string> temporary_password;
|
||||
std::shared_ptr<std::string> temporary_ssid;
|
||||
|
||||
void update_status();
|
||||
/**
|
||||
* @brief Internal variable to store the wifi password
|
||||
*
|
||||
*/
|
||||
std::string password;
|
||||
|
||||
/**
|
||||
* @brief Function to disconnect from the network
|
||||
*
|
||||
*/
|
||||
void disconnect();
|
||||
|
||||
/**
|
||||
* @brief Function to determine wether or not we are connected to a network
|
||||
*
|
||||
* @return true Device is connected to wifi network
|
||||
* @return false Device is not connected to wifi network
|
||||
*/
|
||||
bool isConnected();
|
||||
/**
|
||||
* @brief Internal variable to store the wifi SSID
|
||||
*
|
||||
*/
|
||||
std::string SSID;
|
||||
|
||||
};
|
|
@ -1,70 +1,48 @@
|
|||
#include "HardwareSimulator.hpp"
|
||||
#include <unistd.h>
|
||||
#include "SDL2/SDL.h"
|
||||
#include "display/monitor.h"
|
||||
#include "indev/mouse.h"
|
||||
#include "indev/mousewheel.h"
|
||||
#include "indev/keyboard.h"
|
||||
#include "sdl/sdl.h"
|
||||
|
||||
/**
|
||||
* A task to measure the elapsed time for LittlevGL
|
||||
* @param data unused
|
||||
* @return never return
|
||||
*/
|
||||
static int tick_thread(void * data)
|
||||
#include "SDLDisplay.hpp"
|
||||
#include <sstream>
|
||||
|
||||
HardwareSimulator::HardwareSimulator(): HardwareAbstract(),
|
||||
mTickThread([](){
|
||||
while(true){
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(2));
|
||||
lv_tick_inc(2); /*Tell lvgl that 2 milliseconds were elapsed*/
|
||||
}}),
|
||||
mBattery(std::make_shared<BatterySimulator>()),
|
||||
mDisplay(SDLDisplay::getInstance()),
|
||||
mWifiHandler(std::make_shared<wifiHandlerSim>())
|
||||
{
|
||||
(void)data;
|
||||
|
||||
while(1) {
|
||||
SDL_Delay(5); /*Sleep for 5 millisecond*/
|
||||
lv_tick_inc(5); /*Tell LittelvGL that 5 milliseconds were elapsed*/
|
||||
}
|
||||
|
||||
return 0;
|
||||
mHardwareStatusTitleUpdate = std::thread([this] {
|
||||
int dataToShow = 0;
|
||||
while (true)
|
||||
{
|
||||
std::stringstream title;
|
||||
switch (dataToShow){
|
||||
case 0:
|
||||
title << "Batt:" << mBattery->getPercentage() << "%" << std::endl;
|
||||
break;
|
||||
case 1:
|
||||
title << "BKLght: " << static_cast<int>(mDisplay->getBrightness()) << std::endl;
|
||||
dataToShow = -1;
|
||||
break;
|
||||
default:
|
||||
dataToShow = -1;
|
||||
}
|
||||
dataToShow++;
|
||||
|
||||
mDisplay->setTitle(title.str());
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void HardwareSimulator::init() {
|
||||
lv_init();
|
||||
// Workaround for sdl2 `-m32` crash
|
||||
// https://bugs.launchpad.net/ubuntu/+source/libsdl2/+bug/1775067/comments/7
|
||||
#ifndef WIN32
|
||||
setenv("DBUS_FATAL_WARNINGS", "0", 1);
|
||||
#endif
|
||||
|
||||
/* Add a display
|
||||
* Use the 'monitor' driver which creates window on PC's monitor to simulate a display*/
|
||||
|
||||
static lv_disp_draw_buf_t disp_buf;
|
||||
static lv_color_t buf[SDL_HOR_RES * 10]; /*Declare a buffer for 10 lines*/
|
||||
lv_disp_draw_buf_init(&disp_buf, buf, NULL, SDL_HOR_RES * 10); /*Initialize the display buffer*/
|
||||
|
||||
static lv_disp_drv_t disp_drv;
|
||||
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
|
||||
disp_drv.flush_cb = sdl_display_flush; /*Used when `LV_VDB_SIZE != 0` in lv_conf.h (buffered drawing)*/
|
||||
disp_drv.draw_buf = &disp_buf;
|
||||
disp_drv.hor_res = SDL_HOR_RES;
|
||||
disp_drv.ver_res = SDL_VER_RES;
|
||||
//disp_drv.disp_fill = monitor_fill; /*Used when `LV_VDB_SIZE == 0` in lv_conf.h (unbuffered drawing)*/
|
||||
//disp_drv.disp_map = monitor_map; /*Used when `LV_VDB_SIZE == 0` in lv_conf.h (unbuffered drawing)*/
|
||||
lv_disp_drv_register(&disp_drv);
|
||||
|
||||
/* Add the mouse as input device
|
||||
* Use the 'mouse' driver which reads the PC's mouse*/
|
||||
static lv_indev_drv_t indev_drv;
|
||||
lv_indev_drv_init(&indev_drv); /*Basic initialization*/
|
||||
indev_drv.type = LV_INDEV_TYPE_POINTER;
|
||||
indev_drv.read_cb = sdl_mouse_read; /*This function will be called periodically (by the library) to get the mouse position and state*/
|
||||
lv_indev_drv_register(&indev_drv);
|
||||
|
||||
sdl_init();
|
||||
|
||||
/* Tick init.
|
||||
* You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed
|
||||
* Create an SDL thread to do this*/
|
||||
SDL_CreateThread(tick_thread, "tick", NULL);
|
||||
|
||||
std::shared_ptr<BatteryInterface> HardwareSimulator::battery(){
|
||||
return mBattery;
|
||||
}
|
||||
std::shared_ptr<DisplayAbstract> HardwareSimulator::display(){
|
||||
return mDisplay;
|
||||
}
|
||||
std::shared_ptr<wifiHandlerInterface> HardwareSimulator::wifi(){
|
||||
return mWifiHandler;
|
||||
}
|
|
@ -1,29 +1,34 @@
|
|||
#pragma once
|
||||
#include "HardwareInterface.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "HardwareAbstract.hpp"
|
||||
|
||||
class HardwareSimulator : public HardwareInterface {
|
||||
#include "batterySimulator.hpp"
|
||||
#include "SDLDisplay.hpp"
|
||||
#include "wifiHandlerSim.hpp"
|
||||
|
||||
#include <thread>
|
||||
|
||||
class HardwareSimulator : public HardwareAbstract {
|
||||
public:
|
||||
HardwareSimulator() = default;
|
||||
HardwareSimulator();
|
||||
|
||||
virtual void init() override {};
|
||||
|
||||
virtual void debugPrint(std::string message) override {
|
||||
std::cout << message;
|
||||
virtual void debugPrint(const char* fmt, ...) override {
|
||||
va_list arguments;
|
||||
va_start(arguments, fmt);
|
||||
vprintf(fmt, arguments);
|
||||
va_end(arguments);
|
||||
}
|
||||
|
||||
virtual void sendIR() override {}
|
||||
virtual std::shared_ptr<BatteryInterface> battery() override;
|
||||
virtual std::shared_ptr<DisplayAbstract> display() override;
|
||||
virtual std::shared_ptr<wifiHandlerInterface> wifi() override;
|
||||
|
||||
virtual void MQTTPublish(const char *topic, const char *payload) override{
|
||||
private:
|
||||
std::thread mTickThread;
|
||||
std::thread mHardwareStatusTitleUpdate;
|
||||
|
||||
};
|
||||
|
||||
virtual void init() override;
|
||||
|
||||
virtual batteryStatus getBatteryPercentage() {
|
||||
batteryStatus fakeStatus;
|
||||
fakeStatus.isCharging = false;
|
||||
fakeStatus.percentage = 100;
|
||||
fakeStatus.voltage = 4200;
|
||||
return fakeStatus;
|
||||
}
|
||||
std::shared_ptr<BatterySimulator> mBattery;
|
||||
std::shared_ptr<SDLDisplay> mDisplay;
|
||||
std::shared_ptr<wifiHandlerSim> mWifiHandler;
|
||||
};
|
||||
|
|
39
Platformio/HAL/Targets/Simulator/SDLDisplay.cpp
Normal file
39
Platformio/HAL/Targets/Simulator/SDLDisplay.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include "SDLDisplay.hpp"
|
||||
#include "sdl/sdl.h"
|
||||
#include <string>
|
||||
|
||||
std::shared_ptr<SDLDisplay> SDLDisplay::getInstance(){
|
||||
if (!DisplayAbstract::mInstance){
|
||||
DisplayAbstract::mInstance = std::shared_ptr<SDLDisplay>(new SDLDisplay());
|
||||
}
|
||||
return std::static_pointer_cast<SDLDisplay>(mInstance);
|
||||
}
|
||||
|
||||
void SDLDisplay::setBrightness(uint8_t brightness){
|
||||
mBrightness = brightness;
|
||||
}
|
||||
|
||||
uint8_t SDLDisplay::getBrightness(){
|
||||
return mBrightness;
|
||||
}
|
||||
|
||||
void SDLDisplay::turnOff(){
|
||||
|
||||
}
|
||||
|
||||
void SDLDisplay::flushDisplay(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p){
|
||||
sdl_display_flush(disp,area,color_p);
|
||||
}
|
||||
|
||||
void SDLDisplay::screenInput(lv_indev_drv_t *indev_driver, lv_indev_data_t *data){
|
||||
sdl_mouse_read(indev_driver,data);
|
||||
}
|
||||
|
||||
void SDLDisplay::setTitle(std::string aNewTitle){
|
||||
SDL_SetWindowTitle(mSimWindow,aNewTitle.c_str());
|
||||
}
|
||||
|
||||
SDLDisplay::SDLDisplay(): DisplayAbstract() {
|
||||
sdl_init();
|
||||
mSimWindow = SDL_GetWindowFromID(1); // Get the SDL window via ID hopefully it is always 1...
|
||||
}
|
25
Platformio/HAL/Targets/Simulator/SDLDisplay.hpp
Normal file
25
Platformio/HAL/Targets/Simulator/SDLDisplay.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "SDL2/SDL.h"
|
||||
#include "DisplayAbstract.h"
|
||||
|
||||
class SDLDisplay : public DisplayAbstract{
|
||||
|
||||
public:
|
||||
static std::shared_ptr<SDLDisplay> getInstance();
|
||||
|
||||
virtual void setBrightness(uint8_t brightness) override;
|
||||
virtual uint8_t getBrightness() override;
|
||||
virtual void turnOff() override;
|
||||
|
||||
void setTitle(std::string aNewTitle);
|
||||
|
||||
protected:
|
||||
virtual void flushDisplay(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) override;
|
||||
virtual void screenInput(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) override;
|
||||
|
||||
private:
|
||||
SDLDisplay();
|
||||
uint8_t mBrightness;
|
||||
SDL_Window* mSimWindow;
|
||||
};
|
77
Platformio/HAL/Targets/Simulator/SimulatorMPMCQueue.cpp
Normal file
77
Platformio/HAL/Targets/Simulator/SimulatorMPMCQueue.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include "SimulatorMPMCQueue.hpp"
|
||||
|
||||
template <typename T>
|
||||
bool SimulatorMPMCQueue<T>::push(T obj)
|
||||
{
|
||||
return this->push(obj, false);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool SimulatorMPMCQueue<T>::push(T obj, bool overwrite)
|
||||
{
|
||||
bool retval = false;
|
||||
if (this->mtx.try_lock())
|
||||
{
|
||||
if (this->isFull() && overwrite)
|
||||
{
|
||||
/* If we should overwrite already written data and the buffer is full, we increment the rd_index as well.
|
||||
This has to be done in the mutex so we do not overwrite data which is already being read*/
|
||||
this->rd_index = this->incrementIndex(this->rd_index);
|
||||
}
|
||||
|
||||
/* If the buffer is full, we can not write to the buffer. If overwrite is set to true, this check will never
|
||||
fail as we move the rd_index if the buffer would otherwise be full*/
|
||||
if (!this->isFull())
|
||||
{
|
||||
retval = true;
|
||||
this->data[this->wr_index] = obj;
|
||||
this->wr_index = this->incrementIndex(this->wr_index);
|
||||
}
|
||||
this->mtx.unlock();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::optional<T> SimulatorMPMCQueue<T>::pop()
|
||||
{
|
||||
T retval;
|
||||
if (this->mtx.try_lock()){
|
||||
|
||||
if (this->isEmpty())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
retval = this->data[this->rd_index];
|
||||
this->rd_index = this->incrementIndex(this->rd_index);
|
||||
this->mtx.unlock();
|
||||
return retval;
|
||||
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::optional<T> SimulatorMPMCQueue<T>::peek()
|
||||
{
|
||||
T retval;
|
||||
if (this->mtx.try_lock())
|
||||
{
|
||||
if (this->isEmpty())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
retval = this->data[this->rd_index];
|
||||
this->mtx.unlock();
|
||||
return retval;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint32_t SimulatorMPMCQueue<T>::incrementIndex(uint32_t index)
|
||||
{
|
||||
return (index + 1) % this->size;
|
||||
}
|
24
Platformio/HAL/Targets/Simulator/SimulatorMPMCQueue.hpp
Normal file
24
Platformio/HAL/Targets/Simulator/SimulatorMPMCQueue.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
#include "MPMCQueueInterface.hpp"
|
||||
#include "SimulatorSPSCQueue.hpp"
|
||||
#include <mutex>
|
||||
|
||||
template <typename T>
|
||||
class SimulatorMPMCQueue: public SimulatorSPSCQueue<T>, public MPMCQueueInterface<T>
|
||||
{
|
||||
public:
|
||||
SimulatorMPMCQueue(uint32_t size): SimulatorSPSCQueue<T>(size){};
|
||||
bool push (T obj);
|
||||
bool push (T obj, bool overwrite);
|
||||
std::optional<T> pop();
|
||||
std::optional<T> peek();
|
||||
bool isFull();
|
||||
bool isEmpty();
|
||||
private:
|
||||
T* data;
|
||||
uint32_t size;
|
||||
uint32_t rd_index;
|
||||
uint32_t wr_index;
|
||||
uint32_t incrementIndex(uint32_t index);
|
||||
std::mutex mtx;
|
||||
};
|
68
Platformio/HAL/Targets/Simulator/SimulatorSPSCQueue.cpp
Normal file
68
Platformio/HAL/Targets/Simulator/SimulatorSPSCQueue.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include "SimulatorSPSCQueue.hpp"
|
||||
|
||||
template <typename T>
|
||||
SimulatorSPSCQueue<T>::SimulatorSPSCQueue(uint32_t size)
|
||||
{
|
||||
this->size = size;
|
||||
this->data = new T[](this->size + 1);
|
||||
this->rd_index = 0;
|
||||
this->wr_index = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SimulatorSPSCQueue<T>::~SimulatorSPSCQueue()
|
||||
{
|
||||
free(this->data);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool SimulatorSPSCQueue<T>::isFull()
|
||||
{
|
||||
return ((this->wr_index + 1) % this->size) == this->rd_index;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool SimulatorSPSCQueue<T>::isEmpty()
|
||||
{
|
||||
return this->rd_index == this->wr_index;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool SimulatorSPSCQueue<T>::push(T obj)
|
||||
{
|
||||
bool retval = false;
|
||||
if (!this->isFull())
|
||||
{
|
||||
retval = true;
|
||||
this->data[this->wr_index] = obj;
|
||||
this->wr_index = this->incrementIndex(this->wr_index);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::optional<T> SimulatorSPSCQueue<T>::pop()
|
||||
{
|
||||
std::optional<T> retval;
|
||||
|
||||
retval = this->peek();
|
||||
|
||||
this->rd_index = this->incrementIndex(this->rd_index);
|
||||
return retval;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::optional<T> SimulatorSPSCQueue<T>::peek()
|
||||
{
|
||||
if (this->isEmpty())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
return this->data[this->rd_index];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint32_t SimulatorSPSCQueue<T>::incrementIndex(uint32_t index)
|
||||
{
|
||||
return (index + 1) % this->size;
|
||||
}
|
22
Platformio/HAL/Targets/Simulator/SimulatorSPSCQueue.hpp
Normal file
22
Platformio/HAL/Targets/Simulator/SimulatorSPSCQueue.hpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
#include "SPSCQueueInterface.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
template <typename T>
|
||||
class SimulatorSPSCQueue: public SPSCQueueInterface<T>
|
||||
{
|
||||
public:
|
||||
SimulatorSPSCQueue(uint32_t size);
|
||||
~SimulatorSPSCQueue();
|
||||
bool push (T obj);
|
||||
std::optional<T> pop();
|
||||
std::optional<T> peek();
|
||||
bool isFull();
|
||||
bool isEmpty();
|
||||
private:
|
||||
T* data;
|
||||
uint32_t size;
|
||||
uint32_t rd_index;
|
||||
uint32_t wr_index;
|
||||
uint32_t incrementIndex(uint32_t index);
|
||||
};
|
23
Platformio/HAL/Targets/Simulator/batterySimulator.hpp
Normal file
23
Platformio/HAL/Targets/Simulator/batterySimulator.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "BatteryInterface.h"
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
class BatterySimulator: public BatteryInterface{
|
||||
public:
|
||||
BatterySimulator() :
|
||||
mCreationTime(std::chrono::high_resolution_clock::now())
|
||||
{};
|
||||
~BatterySimulator(){}
|
||||
|
||||
virtual int getPercentage() override {
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
auto batteryRunTime = std::chrono::duration_cast<std::chrono::seconds>(now - mCreationTime);
|
||||
constexpr auto minToBatteryZero = 3;
|
||||
auto fakeBattPercentage = 100 - ((batteryRunTime / std::chrono::duration<float,std::ratio<60LL>>(minToBatteryZero)) * 100);
|
||||
return std::floor(fakeBattPercentage < 100 ? fakeBattPercentage : 0);
|
||||
}
|
||||
|
||||
virtual bool isCharging() override { return false; }
|
||||
|
||||
private:
|
||||
std::chrono::_V2::system_clock::time_point mCreationTime;
|
||||
};
|
|
@ -1,6 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#define IS_SIMULATOR true
|
||||
|
||||
#define SCREEN_WIDTH 240
|
||||
#define SCREEN_HEIGHT 360
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
#include "wifiHandlerSim.hpp"
|
||||
|
||||
std::shared_ptr<wifiHandlerSim> mInstance;
|
||||
|
||||
std::shared_ptr<wifiHandlerSim> wifiHandlerSim::getInstance()
|
||||
{
|
||||
if(mInstance)
|
||||
{
|
||||
return mInstance;
|
||||
}
|
||||
mInstance = std::make_shared<wifiHandlerSim>(wifiHandlerSim());
|
||||
return mInstance;
|
||||
};
|
||||
|
||||
wifiHandlerSim::wifiHandlerSim(){
|
||||
|
||||
}
|
||||
|
||||
void wifiHandlerSim::begin(){
|
||||
|
||||
}
|
||||
|
||||
static wifiStatus status = {
|
||||
.isConnected = true
|
||||
, .IP = "172.0.0.1"
|
||||
};
|
||||
|
||||
void wifiHandlerSim::connect(std::shared_ptr<std::string> ssid, std::shared_ptr<std::string> password){
|
||||
status.ssid = *ssid;
|
||||
std::shared_ptr<wifiStatus> new_status = std::make_shared<wifiStatus> (wifiStatus(std::move(status)));
|
||||
this->status_update.notify(new_status);
|
||||
}
|
||||
|
||||
static const WifiInfo wifis[] = {
|
||||
{
|
||||
.ssid = "High Signal Wifi"
|
||||
, .rssi = -49
|
||||
}
|
||||
, {
|
||||
.ssid = "Mid Signal Wifi"
|
||||
, .rssi = -55
|
||||
}
|
||||
, {
|
||||
.ssid = "Low Signal Wifi"
|
||||
, .rssi = -65
|
||||
}
|
||||
, {
|
||||
.ssid = "No Signal Wifi"
|
||||
, .rssi = -90
|
||||
}
|
||||
};
|
||||
|
||||
void wifiHandlerSim::scan(){
|
||||
std::shared_ptr<std::vector<WifiInfo>> info = std::make_shared<std::vector<WifiInfo>>(std::vector(std::begin(wifis), std::end(wifis)));
|
||||
this->scan_notification.notify(info);
|
||||
}
|
||||
|
||||
bool wifiHandlerSim::isAvailable(){
|
||||
return false;
|
||||
}
|
||||
|
||||
void wifiHandlerSim::onScanDone(std::function<void (std::shared_ptr<std::vector<WifiInfo>>)> function){
|
||||
this->scan_notification.onNotify(std::move(function));
|
||||
}
|
||||
|
||||
void wifiHandlerSim::onStatusUpdate(std::function<void (std::shared_ptr<wifiStatus>)> function){
|
||||
this->status_update.onNotify(std::move(function));
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include "wifiHandlerInterface.h"
|
||||
#include "Notification.hpp"
|
||||
#include <memory>
|
||||
|
||||
class wifiHandlerSim: public wifiHandlerInterface {
|
||||
public:
|
||||
wifiHandlerSim();
|
||||
static std::shared_ptr<wifiHandlerSim> getInstance();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Connect to the wifi using the provided credetials
|
||||
*
|
||||
* @param SSID
|
||||
* @param password
|
||||
*/
|
||||
void connect(std::shared_ptr<std::string> ssid, std::shared_ptr<std::string> password);
|
||||
//void connect(const char* SSID, const char* password);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief function to trigger asynchronous scan for wifi networks
|
||||
*
|
||||
*/
|
||||
void scan();
|
||||
bool isAvailable();
|
||||
void begin();
|
||||
void onScanDone(std::function<void (std::shared_ptr<std::vector<WifiInfo>>)> function);
|
||||
void onStatusUpdate(std::function<void (std::shared_ptr<wifiStatus>)> function);
|
||||
private:
|
||||
Notification<std::shared_ptr<std::vector<WifiInfo>>> scan_notification;
|
||||
Notification<std::shared_ptr<wifiStatus>> status_update;
|
||||
};
|
1154
Platformio/OmoteUI/Images.cpp
Normal file
1154
Platformio/OmoteUI/Images.cpp
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -9,6 +9,8 @@ std::shared_ptr<OmoteUI> OmoteUI::mInstance = nullptr;
|
|||
// #if defined(IS_SIMULATOR) && (IS_SIMULATOR == true)
|
||||
// #endif
|
||||
|
||||
OmoteUI::OmoteUI(std::shared_ptr<HardwareAbstract> aHardware) : mHardware(aHardware){}
|
||||
|
||||
// Set the page indicator scroll position relative to the tabview scroll
|
||||
// position
|
||||
void OmoteUI::store_scroll_value_event_cb(lv_event_t *e) {
|
||||
|
@ -27,13 +29,13 @@ void OmoteUI::tabview_device_event_cb(lv_event_t *e) {
|
|||
// Slider Event handler
|
||||
void OmoteUI::bl_slider_event_cb(lv_event_t *e) {
|
||||
lv_obj_t *slider = lv_event_get_target(e);
|
||||
backlight_brightness = std::clamp(lv_slider_get_value(slider), 60, 255);
|
||||
auto newBrightness = std::clamp(lv_slider_get_value(slider), 60, 255);
|
||||
mHardware->display()->setBrightness(newBrightness);
|
||||
}
|
||||
|
||||
// Apple Key Event handler
|
||||
void OmoteUI::appleKey_event_cb(lv_event_t *e) {
|
||||
// Send IR command based on the event user data
|
||||
mHardware->sendIR();
|
||||
//mHardware->debugPrint(std::to_string(50 + (int)e->user_data));
|
||||
}
|
||||
|
||||
|
@ -91,39 +93,146 @@ void OmoteUI::loopHandler(){
|
|||
lv_timer_handler();
|
||||
}
|
||||
|
||||
void OmoteUI::create_status_bar(){
|
||||
// Create a status bar
|
||||
lv_obj_t* statusbar = lv_btn_create(lv_scr_act());
|
||||
lv_obj_set_size(statusbar, 240, 20);
|
||||
lv_obj_set_style_shadow_width(statusbar, 0, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(statusbar, lv_color_black(), LV_PART_MAIN);
|
||||
lv_obj_set_style_radius(statusbar, 0, LV_PART_MAIN);
|
||||
lv_obj_align(statusbar, LV_ALIGN_TOP_MID, 0, 0);
|
||||
|
||||
this->WifiLabel = lv_label_create(statusbar);
|
||||
lv_label_set_text(this->WifiLabel, "");
|
||||
lv_obj_align(this->WifiLabel, LV_ALIGN_LEFT_MID, -8, 0);
|
||||
lv_obj_set_style_text_font(this->WifiLabel, &lv_font_montserrat_12, LV_PART_MAIN);
|
||||
|
||||
this->objBattPercentage = lv_label_create(statusbar);
|
||||
lv_label_set_text(this->objBattPercentage, "");
|
||||
lv_obj_align(this->objBattPercentage, LV_ALIGN_RIGHT_MID, -16, 0);
|
||||
lv_obj_set_style_text_font(this->objBattPercentage, &lv_font_montserrat_12, LV_PART_MAIN);
|
||||
|
||||
this->objBattIcon = lv_label_create(statusbar);
|
||||
lv_label_set_text(this->objBattIcon, LV_SYMBOL_BATTERY_EMPTY);
|
||||
lv_obj_align(this->objBattIcon, LV_ALIGN_RIGHT_MID, 8, 0);
|
||||
lv_obj_set_style_text_font(this->objBattIcon, &lv_font_montserrat_16, LV_PART_MAIN);
|
||||
|
||||
batteryPoller = std::make_unique<poller>([&batteryIcon = objBattIcon, battery = mHardware->battery()](){
|
||||
auto percent = battery->getPercentage();
|
||||
if(percent > 95) lv_label_set_text(batteryIcon, LV_SYMBOL_BATTERY_FULL);
|
||||
else if(percent > 75) lv_label_set_text(batteryIcon, LV_SYMBOL_BATTERY_3);
|
||||
else if(percent > 50) lv_label_set_text(batteryIcon, LV_SYMBOL_BATTERY_2);
|
||||
else if(percent > 25) lv_label_set_text(batteryIcon, LV_SYMBOL_BATTERY_1);
|
||||
else lv_label_set_text(batteryIcon, LV_SYMBOL_BATTERY_EMPTY);
|
||||
});
|
||||
}
|
||||
|
||||
void OmoteUI::setup_settings(lv_obj_t* parent)
|
||||
{
|
||||
// Add content to the settings tab
|
||||
// With a flex layout, setting groups/boxes will position themselves automatically
|
||||
lv_obj_set_layout(parent, LV_LAYOUT_FLEX);
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_scrollbar_mode(parent, LV_SCROLLBAR_MODE_ACTIVE);
|
||||
// Add a label, then a box for the display settings
|
||||
this->settingsMenu = lv_menu_create(parent);
|
||||
lv_obj_set_width(this->settingsMenu, 210);
|
||||
|
||||
/* Create main page for settings this->settingsMenu*/
|
||||
this->settingsMainPage = lv_menu_page_create(this->settingsMenu, NULL);
|
||||
lv_obj_t* cont = lv_menu_cont_create(this->settingsMainPage);
|
||||
lv_obj_set_layout(cont, LV_LAYOUT_FLEX);
|
||||
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_scrollbar_mode(cont, LV_SCROLLBAR_MODE_ACTIVE);
|
||||
//lv_obj_set_width(cont, lv_obj_get_width(parent));
|
||||
this->display_settings(cont);
|
||||
|
||||
this->create_wifi_settings(this->settingsMenu, cont);
|
||||
|
||||
// Another setting for the battery
|
||||
lv_obj_t* menuLabel = lv_label_create(cont);
|
||||
lv_label_set_text(menuLabel, "Battery");
|
||||
lv_obj_t* menuBox = lv_obj_create(cont);
|
||||
lv_obj_set_size(menuBox, lv_pct(100), 125);
|
||||
lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN);
|
||||
|
||||
lv_menu_set_page(this->settingsMenu, this->settingsMainPage);
|
||||
}
|
||||
|
||||
void OmoteUI::ta_kb_event_cb(lv_event_t* e)
|
||||
{
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
lv_obj_t * ta = lv_event_get_target(e);
|
||||
lv_obj_t * kb = (lv_obj_t*) lv_event_get_user_data(e);
|
||||
switch(code){
|
||||
case LV_EVENT_FOCUSED:
|
||||
lv_keyboard_set_textarea(kb, ta);
|
||||
lv_obj_clear_flag(kb, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_move_foreground(kb);
|
||||
break;
|
||||
case LV_EVENT_DEFOCUSED:
|
||||
lv_keyboard_set_textarea(kb, NULL);
|
||||
lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OmoteUI::create_keyboard()
|
||||
{
|
||||
this->kb = lv_keyboard_create(lv_scr_act());
|
||||
lv_obj_add_flag(this->kb, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_set_y(this->kb, 0);
|
||||
}
|
||||
|
||||
void OmoteUI::hide_keyboard()
|
||||
{
|
||||
lv_obj_add_flag(this->kb, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
void OmoteUI::reset_settings_menu()
|
||||
{
|
||||
lv_menu_set_page(this->settingsMenu, this->settingsMainPage);
|
||||
}
|
||||
|
||||
void OmoteUI::attach_keyboard(lv_obj_t* textarea)
|
||||
{
|
||||
if (this->kb == NULL)
|
||||
{
|
||||
this->create_keyboard();
|
||||
}
|
||||
lv_keyboard_set_textarea(this->kb, textarea);
|
||||
lv_obj_add_event_cb(textarea, [] (lv_event_t* e) {mInstance->ta_kb_event_cb(e);}, LV_EVENT_FOCUSED, this->kb);
|
||||
lv_obj_add_event_cb(textarea, [] (lv_event_t* e) {mInstance->ta_kb_event_cb(e);}, LV_EVENT_DEFOCUSED, this->kb);
|
||||
}
|
||||
|
||||
void OmoteUI::layout_UI() {
|
||||
|
||||
// --- LVGL UI Configuration ---
|
||||
|
||||
// Set the background color
|
||||
// Set the background color
|
||||
lv_obj_set_style_bg_color(lv_scr_act(), lv_color_black(), LV_PART_MAIN);
|
||||
|
||||
this->create_keyboard();
|
||||
// Setup a scrollable tabview for devices and settings
|
||||
lv_obj_t *tabview;
|
||||
tabview =
|
||||
lv_tabview_create(lv_scr_act(), LV_DIR_TOP,
|
||||
0); // Hide tab labels by setting their height to 0
|
||||
lv_obj_t* tabview;
|
||||
tabview = lv_tabview_create(lv_scr_act(), LV_DIR_TOP, 0); // Hide tab labels by setting their height to 0
|
||||
lv_obj_set_style_bg_color(tabview, lv_color_black(), LV_PART_MAIN);
|
||||
lv_obj_set_size(tabview, SCREEN_WIDTH,
|
||||
270); // 270 = screenHeight(320) - panel(30) - statusbar(20)
|
||||
lv_obj_set_size(tabview, SCREEN_WIDTH, 270); // 270 = screenHeight(320) - panel(30) - statusbar(20)
|
||||
lv_obj_align(tabview, LV_ALIGN_TOP_MID, 0, 20);
|
||||
|
||||
// Add 4 tabs (names are irrelevant since the labels are hidden)
|
||||
lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "Settings");
|
||||
lv_obj_t *tab2 = lv_tabview_add_tab(tabview, "Technisat");
|
||||
lv_obj_t *tab3 = lv_tabview_add_tab(tabview, "Apple TV");
|
||||
lv_obj_t *tab4 = lv_tabview_add_tab(tabview, "Smart Home");
|
||||
lv_obj_t* tab1 = lv_tabview_add_tab(tabview, "Settings");
|
||||
lv_obj_t* tab2 = lv_tabview_add_tab(tabview, "Technisat");
|
||||
lv_obj_t* tab3 = lv_tabview_add_tab(tabview, "Apple TV");
|
||||
lv_obj_t* tab4 = lv_tabview_add_tab(tabview, "Smart Home");
|
||||
|
||||
// Configure number button grid
|
||||
static lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1),
|
||||
LV_GRID_TEMPLATE_LAST}; // equal x distribution
|
||||
static lv_coord_t row_dsc[] = {
|
||||
52, 52, 52, 52, LV_GRID_TEMPLATE_LAST}; // manual y distribution to
|
||||
// compress the grid a bit
|
||||
// Configure number button grid
|
||||
static lv_coord_t col_dsc[] = { LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST }; // equal x distribution
|
||||
static lv_coord_t row_dsc[] = { 52, 52, 52, 52, LV_GRID_TEMPLATE_LAST }; // manual y distribution to compress the grid a bit
|
||||
|
||||
// Create a container with grid for tab2
|
||||
lv_obj_set_style_pad_all(tab2, 0, LV_PART_MAIN);
|
||||
lv_obj_t *cont = lv_obj_create(tab2);
|
||||
lv_obj_t* cont = lv_obj_create(tab2);
|
||||
lv_obj_set_style_shadow_width(cont, 0, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(cont, lv_color_black(), LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(cont, 0, LV_PART_MAIN);
|
||||
|
@ -134,61 +243,50 @@ void OmoteUI::layout_UI() {
|
|||
lv_obj_align(cont, LV_ALIGN_TOP_MID, 0, 0);
|
||||
lv_obj_set_style_radius(cont, 0, LV_PART_MAIN);
|
||||
|
||||
lv_obj_t *buttonLabel;
|
||||
lv_obj_t *obj;
|
||||
lv_obj_t* buttonLabel;
|
||||
lv_obj_t* obj;
|
||||
|
||||
// Iterate through grid buttons and configure them
|
||||
// Iterate through grid buttons configure them
|
||||
for (int i = 0; i < 12; i++) {
|
||||
uint8_t col = i % 3;
|
||||
uint8_t row = i / 3;
|
||||
// Create the button object
|
||||
if ((row == 3) && ((col == 0) || (col == 2)))
|
||||
continue; // Do not create a complete fourth row, only a 0 button
|
||||
if ((row == 3) && ((col == 0) || (col == 2))) continue; // Do not create a complete fourth row, only a 0 button
|
||||
obj = lv_btn_create(cont);
|
||||
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1,
|
||||
LV_GRID_ALIGN_STRETCH, row, 1);
|
||||
lv_obj_set_style_bg_color(obj, color_primary, LV_PART_MAIN);
|
||||
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1, LV_GRID_ALIGN_STRETCH, row, 1);
|
||||
lv_obj_set_style_bg_color(obj, this->color_primary, LV_PART_MAIN);
|
||||
lv_obj_set_style_radius(obj, 14, LV_PART_MAIN);
|
||||
lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE); // Clicking a button causes
|
||||
// a event in its container
|
||||
lv_obj_set_style_shadow_color(obj, lv_color_hex(0x404040), LV_PART_MAIN);
|
||||
lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE); // Clicking a button causes a event in its container
|
||||
// Create Labels for each button
|
||||
buttonLabel = lv_label_create(obj);
|
||||
if (i < 9) {
|
||||
lv_label_set_text_fmt(buttonLabel, std::to_string(i + 1).c_str(), col,
|
||||
row);
|
||||
lv_obj_set_user_data(obj,
|
||||
(void *)i); // Add user data so we can identify which
|
||||
// button caused the container event
|
||||
} else {
|
||||
lv_label_set_text_fmt(buttonLabel, "0", col, row);
|
||||
lv_obj_set_user_data(obj, (void *)9);
|
||||
buttonLabel = lv_label_create(obj);
|
||||
if(i < 9){
|
||||
lv_label_set_text_fmt(buttonLabel, std::to_string(i+1).c_str(), col, row);
|
||||
lv_obj_set_user_data(obj, (void*)i); // Add user data so we can identify which button caused the container event
|
||||
}
|
||||
lv_obj_set_style_text_font(buttonLabel, &lv_font_montserrat_24,
|
||||
LV_PART_MAIN);
|
||||
else{
|
||||
lv_label_set_text_fmt(buttonLabel, "0", col, row);
|
||||
lv_obj_set_user_data(obj, (void*)9);
|
||||
}
|
||||
lv_obj_set_style_text_font(buttonLabel, &lv_font_montserrat_24, LV_PART_MAIN);
|
||||
lv_obj_center(buttonLabel);
|
||||
}
|
||||
// Create a shared event for all button inside container
|
||||
lv_obj_add_event_cb(
|
||||
cont, [](lv_event_t *e) { mInstance->virtualKeypad_event_cb(e); },
|
||||
LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_add_event_cb(cont, [] (lv_event_t* e) {mInstance->virtualKeypad_event_cb(e);}, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
|
||||
// Add content to the Apple TV tab (3)
|
||||
// Add a nice apple tv logo
|
||||
|
||||
lv_obj_t* appleImg = imgs.addAppleTVIcon(tab3);
|
||||
lv_obj_align(appleImg, LV_ALIGN_CENTER, 0, -60);
|
||||
|
||||
// create two buttons and add their icons accordingly
|
||||
lv_obj_t *button = lv_btn_create(tab3);
|
||||
lv_obj_t* button = lv_btn_create(tab3);
|
||||
lv_obj_align(button, LV_ALIGN_BOTTOM_LEFT, 10, 0);
|
||||
lv_obj_set_size(button, 60, 60);
|
||||
lv_obj_set_style_radius(button, 30, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(button, color_primary, LV_PART_MAIN);
|
||||
lv_obj_add_event_cb(
|
||||
button, [](lv_event_t *e) { mInstance->appleKey_event_cb(e); },
|
||||
LV_EVENT_CLICKED, (void *)1);
|
||||
lv_obj_add_event_cb(button, [] (lv_event_t* e) {mInstance->appleKey_event_cb(e);}, LV_EVENT_CLICKED, (void*)1);
|
||||
|
||||
appleImg = imgs.addAppleBackIcon(button);
|
||||
appleImg = imgs.addAppleDisplayImage(button);
|
||||
lv_obj_align(appleImg, LV_ALIGN_CENTER, -3, 0);
|
||||
lv_obj_set_style_img_recolor(appleImg, lv_color_white(), LV_PART_MAIN);
|
||||
lv_obj_set_style_img_recolor_opa(appleImg, LV_OPA_COVER, LV_PART_MAIN);
|
||||
|
@ -199,9 +297,7 @@ void OmoteUI::layout_UI() {
|
|||
lv_obj_set_size(button, 60, 60);
|
||||
lv_obj_set_style_radius(button, 30, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(button, color_primary, LV_PART_MAIN);
|
||||
lv_obj_add_event_cb(
|
||||
button, [](lv_event_t *e) { mInstance->appleKey_event_cb(e); },
|
||||
LV_EVENT_CLICKED, (void *)2);
|
||||
lv_obj_add_event_cb(button, [] (lv_event_t* e) {mInstance->appleKey_event_cb(e);}, LV_EVENT_CLICKED, (void*)2);
|
||||
|
||||
appleImg = imgs.addAppleDisplayImage(button);
|
||||
lv_obj_align(appleImg, LV_ALIGN_CENTER, 0, 0);
|
||||
|
@ -209,157 +305,49 @@ void OmoteUI::layout_UI() {
|
|||
lv_obj_set_style_img_recolor_opa(appleImg, LV_OPA_COVER, LV_PART_MAIN);
|
||||
lv_obj_align(appleImg, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
// Add content to the settings tab
|
||||
// With a flex layout, setting groups/boxes will position themselves
|
||||
// automatically
|
||||
lv_obj_set_layout(tab1, LV_LAYOUT_FLEX);
|
||||
lv_obj_set_flex_flow(tab1, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_scrollbar_mode(tab1, LV_SCROLLBAR_MODE_ACTIVE);
|
||||
|
||||
|
||||
// Add a label, then a box for the display settings
|
||||
lv_obj_t *menuLabel = lv_label_create(tab1);
|
||||
lv_label_set_text(menuLabel, "Display");
|
||||
|
||||
lv_obj_t *menuBox = lv_obj_create(tab1);
|
||||
lv_obj_set_size(menuBox, lv_pct(100), 109);
|
||||
lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN);
|
||||
|
||||
lv_obj_t *brightnessIcon = imgs.addLowBrightnessIcon(menuBox);
|
||||
lv_obj_align(brightnessIcon, LV_ALIGN_TOP_LEFT, 0, 0);
|
||||
|
||||
lv_obj_t *slider = lv_slider_create(menuBox);
|
||||
lv_slider_set_range(slider, 60, 255);
|
||||
lv_obj_set_style_bg_color(slider, lv_color_white(), LV_PART_KNOB);
|
||||
lv_obj_set_style_bg_opa(slider, LV_OPA_COVER, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(slider, lv_color_lighten(color_primary, 50),
|
||||
LV_PART_MAIN);
|
||||
lv_slider_set_value(slider, backlight_brightness, LV_ANIM_OFF);
|
||||
lv_obj_set_size(slider, lv_pct(66), 10);
|
||||
lv_obj_align(slider, LV_ALIGN_TOP_MID, 0, 3);
|
||||
|
||||
brightnessIcon = imgs.addHighBrightnessIcon(menuBox);
|
||||
lv_obj_align(brightnessIcon, LV_ALIGN_TOP_RIGHT, 0, -1);
|
||||
|
||||
lv_obj_add_event_cb(
|
||||
slider, [](lv_event_t *e) { mInstance->bl_slider_event_cb(e); },
|
||||
LV_EVENT_VALUE_CHANGED, NULL);
|
||||
|
||||
menuLabel = lv_label_create(menuBox);
|
||||
lv_label_set_text(menuLabel, "Lift to Wake");
|
||||
lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 0, 32);
|
||||
lv_obj_t *wakeToggle = lv_switch_create(menuBox);
|
||||
lv_obj_set_size(wakeToggle, 40, 22);
|
||||
lv_obj_align(wakeToggle, LV_ALIGN_TOP_RIGHT, 0, 29);
|
||||
lv_obj_set_style_bg_color(wakeToggle, lv_color_lighten(color_primary, 50),
|
||||
LV_PART_MAIN);
|
||||
lv_obj_add_event_cb(
|
||||
wakeToggle,
|
||||
[](lv_event_t *e) { mInstance->WakeEnableSetting_event_cb(e); },
|
||||
LV_EVENT_VALUE_CHANGED, NULL);
|
||||
if (wakeupByIMUEnabled)
|
||||
lv_obj_add_state(wakeToggle, LV_STATE_CHECKED); // set default state
|
||||
|
||||
menuLabel = lv_label_create(menuBox);
|
||||
lv_label_set_text(menuLabel, "Timeout");
|
||||
lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 0, 64);
|
||||
lv_obj_t *drop = lv_dropdown_create(menuBox);
|
||||
lv_dropdown_set_options(drop, "10s\n"
|
||||
"30s\n"
|
||||
"1m\n"
|
||||
"3m");
|
||||
lv_obj_align(drop, LV_ALIGN_TOP_RIGHT, 0, 61);
|
||||
lv_obj_set_size(drop, 70, 22);
|
||||
lv_obj_set_style_pad_top(drop, 1, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(drop, color_primary, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(drop, 0, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(lv_dropdown_get_list(drop), color_primary,
|
||||
LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(lv_dropdown_get_list(drop), 1, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_color(lv_dropdown_get_list(drop),
|
||||
lv_color_darken(color_primary, 40),
|
||||
LV_PART_MAIN);
|
||||
|
||||
// Add another label, then a settings box for WiFi
|
||||
menuLabel = lv_label_create(tab1);
|
||||
lv_label_set_text(menuLabel, "Wi-Fi");
|
||||
menuBox = lv_obj_create(tab1);
|
||||
lv_obj_set_size(menuBox, lv_pct(100), 80);
|
||||
lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN);
|
||||
menuLabel = lv_label_create(menuBox);
|
||||
lv_label_set_text(menuLabel, "Network");
|
||||
menuLabel = lv_label_create(menuBox);
|
||||
lv_label_set_text(menuLabel, LV_SYMBOL_RIGHT);
|
||||
lv_obj_align(menuLabel, LV_ALIGN_TOP_RIGHT, 0, 0);
|
||||
menuLabel = lv_label_create(menuBox);
|
||||
lv_label_set_text(menuLabel, "Password");
|
||||
lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 0, 32);
|
||||
menuLabel = lv_label_create(menuBox);
|
||||
lv_label_set_text(menuLabel, LV_SYMBOL_RIGHT);
|
||||
lv_obj_align(menuLabel, LV_ALIGN_TOP_RIGHT, 0, 32);
|
||||
|
||||
// Another setting for the battery
|
||||
menuLabel = lv_label_create(tab1);
|
||||
lv_label_set_text(menuLabel, "Battery");
|
||||
menuBox = lv_obj_create(tab1);
|
||||
lv_obj_set_size(menuBox, lv_pct(100), 125);
|
||||
lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN);
|
||||
this->setup_settings(tab1);
|
||||
|
||||
// Add content to the smart home tab (4)
|
||||
|
||||
lv_obj_set_layout(tab4, LV_LAYOUT_FLEX);
|
||||
lv_obj_set_flex_flow(tab4, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_scrollbar_mode(tab4, LV_SCROLLBAR_MODE_ACTIVE);
|
||||
|
||||
// Add a label, then a box for the light controls
|
||||
menuLabel = lv_label_create(tab4);
|
||||
lv_obj_t* menuLabel = lv_label_create(tab4);
|
||||
lv_label_set_text(menuLabel, "Living Room");
|
||||
|
||||
menuBox = lv_obj_create(tab4);
|
||||
lv_obj_t* menuBox = lv_obj_create(tab4);
|
||||
lv_obj_set_size(menuBox, lv_pct(100), 79);
|
||||
lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN);
|
||||
|
||||
lv_obj_t *bulbIcon = imgs.addLightBulbIcon(menuBox);
|
||||
lv_obj_t* bulbIcon = imgs.addLightBulbIcon(menuBox);
|
||||
lv_obj_align(bulbIcon, LV_ALIGN_TOP_LEFT, 0, 0);
|
||||
|
||||
menuLabel = lv_label_create(menuBox);
|
||||
lv_label_set_text(menuLabel, "Floor Lamp");
|
||||
lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 22, 3);
|
||||
lv_obj_t *lightToggleA = lv_switch_create(menuBox);
|
||||
lv_obj_t* lightToggleA = lv_switch_create(menuBox);
|
||||
lv_obj_set_size(lightToggleA, 40, 22);
|
||||
lv_obj_align(lightToggleA, LV_ALIGN_TOP_RIGHT, 0, 0);
|
||||
lv_obj_set_style_bg_color(lightToggleA, lv_color_lighten(color_primary, 50),
|
||||
LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(lightToggleA, lv_color_lighten(color_primary, 50), LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(lightToggleA, color_primary, LV_PART_INDICATOR);
|
||||
lv_obj_add_event_cb(
|
||||
lightToggleA,
|
||||
[](lv_event_t *e) { mInstance->smartHomeToggle_event_cb(e); },
|
||||
LV_EVENT_VALUE_CHANGED, (void *)1);
|
||||
lv_obj_add_event_cb(lightToggleA, [] (lv_event_t* e) {mInstance->smartHomeToggle_event_cb(e);}, LV_EVENT_VALUE_CHANGED, (void*)1);
|
||||
|
||||
slider = lv_slider_create(menuBox);
|
||||
lv_slider_set_range(slider, 60, 255);
|
||||
lv_obj_set_style_bg_color(slider, lv_color_lighten(lv_color_black(), 30),
|
||||
LV_PART_INDICATOR);
|
||||
lv_obj_set_style_bg_grad_color(
|
||||
slider, lv_color_lighten(lv_palette_main(LV_PALETTE_AMBER), 180),
|
||||
LV_PART_INDICATOR);
|
||||
lv_obj_t *slider = lv_slider_create(menuBox);
|
||||
lv_slider_set_range(slider, 0, 100);
|
||||
lv_obj_set_style_bg_color(slider, lv_color_lighten(lv_color_black(), 30), LV_PART_INDICATOR);
|
||||
lv_obj_set_style_bg_grad_color(slider, lv_color_lighten(lv_palette_main(LV_PALETTE_AMBER), 180), LV_PART_INDICATOR);
|
||||
lv_obj_set_style_bg_grad_dir(slider, LV_GRAD_DIR_HOR, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_bg_color(slider, lv_color_white(), LV_PART_KNOB);
|
||||
lv_obj_set_style_bg_opa(slider, 255, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(slider, lv_color_lighten(color_primary, 50),
|
||||
LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(slider, lv_color_lighten(color_primary, 50), LV_PART_MAIN);
|
||||
lv_slider_set_value(slider, 255, LV_ANIM_OFF);
|
||||
lv_obj_set_size(slider, lv_pct(90), 10);
|
||||
lv_obj_align(slider, LV_ALIGN_TOP_MID, 0, 37);
|
||||
lv_obj_add_event_cb(
|
||||
slider, [](lv_event_t *e) { mInstance->smartHomeSlider_event_cb(e); },
|
||||
LV_EVENT_VALUE_CHANGED, (void *)1);
|
||||
lv_obj_add_event_cb(slider, [] (lv_event_t* e) {mInstance->smartHomeSlider_event_cb(e);}, LV_EVENT_VALUE_CHANGED, (void*)1);
|
||||
|
||||
// Add another menu box for a second appliance
|
||||
// Add another this->settingsMenu box for a second appliance
|
||||
menuBox = lv_obj_create(tab4);
|
||||
lv_obj_set_size(menuBox, lv_pct(100), 79);
|
||||
lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN);
|
||||
|
@ -371,35 +359,26 @@ void OmoteUI::layout_UI() {
|
|||
menuLabel = lv_label_create(menuBox);
|
||||
lv_label_set_text(menuLabel, "Ceiling Light");
|
||||
lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 22, 3);
|
||||
lv_obj_t *lightToggleB = lv_switch_create(menuBox);
|
||||
lv_obj_t* lightToggleB = lv_switch_create(menuBox);
|
||||
lv_obj_set_size(lightToggleB, 40, 22);
|
||||
lv_obj_align(lightToggleB, LV_ALIGN_TOP_RIGHT, 0, 0);
|
||||
lv_obj_set_style_bg_color(lightToggleB, lv_color_lighten(color_primary, 50),
|
||||
LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(lightToggleB, lv_color_lighten(color_primary, 50), LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(lightToggleB, color_primary, LV_PART_INDICATOR);
|
||||
lv_obj_add_event_cb(
|
||||
lightToggleB,
|
||||
[](lv_event_t *e) { mInstance->smartHomeToggle_event_cb(e); },
|
||||
LV_EVENT_VALUE_CHANGED, (void *)2);
|
||||
lv_obj_add_event_cb(lightToggleB, [] (lv_event_t* e) {mInstance->smartHomeToggle_event_cb(e);}, LV_EVENT_VALUE_CHANGED, (void*)2);
|
||||
|
||||
slider = lv_slider_create(menuBox);
|
||||
lv_slider_set_range(slider, 60, 255);
|
||||
lv_obj_set_style_bg_color(slider, lv_color_lighten(lv_color_black(), 30),
|
||||
LV_PART_INDICATOR);
|
||||
lv_obj_set_style_bg_grad_color(
|
||||
slider, lv_color_lighten(lv_palette_main(LV_PALETTE_AMBER), 180),
|
||||
LV_PART_INDICATOR);
|
||||
lv_slider_set_range(slider, 0, 100);
|
||||
lv_obj_set_style_bg_color(slider, lv_color_lighten(lv_color_black(), 30), LV_PART_INDICATOR);
|
||||
lv_obj_set_style_bg_grad_color(slider, lv_color_lighten(lv_palette_main(LV_PALETTE_AMBER), 180), LV_PART_INDICATOR);
|
||||
lv_obj_set_style_bg_grad_dir(slider, LV_GRAD_DIR_HOR, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_bg_color(slider, lv_color_white(), LV_PART_KNOB);
|
||||
lv_obj_set_style_bg_opa(slider, 255, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(slider, lv_color_lighten(color_primary, 50),
|
||||
LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(slider, lv_color_lighten(color_primary, 50), LV_PART_MAIN);
|
||||
lv_slider_set_value(slider, 255, LV_ANIM_OFF);
|
||||
lv_obj_set_size(slider, lv_pct(90), 10);
|
||||
lv_obj_align(slider, LV_ALIGN_TOP_MID, 0, 37);
|
||||
lv_obj_add_event_cb(
|
||||
slider, [](lv_event_t *e) { mInstance->smartHomeSlider_event_cb(e); },
|
||||
LV_EVENT_VALUE_CHANGED, (void *)2);
|
||||
lv_obj_add_event_cb(slider, [] (lv_event_t* e) {mInstance->smartHomeSlider_event_cb(e);}, LV_EVENT_VALUE_CHANGED, (void*)2);
|
||||
|
||||
|
||||
// Add another room (empty for now)
|
||||
menuLabel = lv_label_create(tab4);
|
||||
|
@ -410,19 +389,20 @@ void OmoteUI::layout_UI() {
|
|||
lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN);
|
||||
|
||||
|
||||
// Set current page according to the current Device
|
||||
lv_tabview_set_act(tabview, currentDevice, LV_ANIM_OFF);
|
||||
lv_tabview_set_act(tabview, 0, LV_ANIM_OFF);
|
||||
|
||||
|
||||
// Create a page indicator
|
||||
panel = lv_obj_create(lv_scr_act());
|
||||
lv_obj_clear_flag(
|
||||
panel, LV_OBJ_FLAG_CLICKABLE); // this indicator will not be clickable
|
||||
lv_obj_clear_flag(panel, LV_OBJ_FLAG_CLICKABLE); // This indicator will not be clickable
|
||||
lv_obj_set_size(panel, SCREEN_WIDTH, 30);
|
||||
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_align(panel, LV_ALIGN_BOTTOM_MID, 0, 0);
|
||||
lv_obj_set_scrollbar_mode(panel, LV_SCROLLBAR_MODE_OFF);
|
||||
// This small hidden button enables the page indicator to scroll further
|
||||
lv_obj_t *btn = lv_btn_create(panel);
|
||||
lv_obj_t* btn = lv_btn_create(panel);
|
||||
lv_obj_set_size(btn, 50, lv_pct(100));
|
||||
lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN);
|
||||
lv_obj_set_style_opa(btn, LV_OPA_TRANSP, LV_PART_MAIN);
|
||||
|
@ -430,7 +410,7 @@ void OmoteUI::layout_UI() {
|
|||
btn = lv_btn_create(panel);
|
||||
lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_set_size(btn, 150, lv_pct(100));
|
||||
lv_obj_t *label = lv_label_create(btn);
|
||||
lv_obj_t* label = lv_label_create(btn);
|
||||
lv_label_set_text_fmt(label, "Settings");
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN);
|
||||
|
@ -467,15 +447,10 @@ void OmoteUI::layout_UI() {
|
|||
lv_obj_set_size(btn, 50, lv_pct(100));
|
||||
lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN);
|
||||
lv_obj_set_style_opa(btn, LV_OPA_TRANSP, LV_PART_MAIN);
|
||||
|
||||
|
||||
// Make the indicator scroll together with the tabs by creating a scroll event
|
||||
lv_obj_add_event_cb(
|
||||
lv_tabview_get_content(tabview),
|
||||
[](lv_event_t *e) { mInstance->store_scroll_value_event_cb(e); },
|
||||
LV_EVENT_SCROLL, NULL);
|
||||
lv_obj_add_event_cb(
|
||||
tabview, [](lv_event_t *e) { mInstance->tabview_device_event_cb(e); },
|
||||
LV_EVENT_VALUE_CHANGED, NULL);
|
||||
lv_obj_add_event_cb(lv_tabview_get_content(tabview), [] (lv_event_t* e) {mInstance->store_scroll_value_event_cb(e);}, LV_EVENT_SCROLL, NULL);
|
||||
lv_obj_add_event_cb(tabview, [] (lv_event_t* e) {mInstance->tabview_device_event_cb(e);}, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
// Initialize scroll position for the indicator
|
||||
lv_event_send(lv_tabview_get_content(tabview), LV_EVENT_SCROLL, NULL);
|
||||
|
||||
|
@ -488,35 +463,13 @@ void OmoteUI::layout_UI() {
|
|||
lv_obj_add_style(panel, &style_btn, 0);
|
||||
|
||||
// Make the indicator fade out at the sides using gradient bitmaps
|
||||
lv_obj_t *img1 = imgs.addLeftGradiant(lv_scr_act());
|
||||
lv_obj_t* img1 = imgs.addLeftGradiant(lv_scr_act());
|
||||
lv_obj_align(img1, LV_ALIGN_BOTTOM_LEFT, 0, 0);
|
||||
lv_obj_set_size(img1, 30, 30); // stretch the 1-pixel high image to 30px
|
||||
|
||||
lv_obj_t* img2 = imgs.addRightGradiant(lv_scr_act());
|
||||
lv_obj_align(img2, LV_ALIGN_BOTTOM_RIGHT, 0, 0);
|
||||
lv_obj_set_size(img2, 30, 30);
|
||||
|
||||
// Create a status bar
|
||||
lv_obj_t *statusbar = lv_btn_create(lv_scr_act());
|
||||
lv_obj_set_size(statusbar, 240, 20);
|
||||
lv_obj_set_style_shadow_width(statusbar, 0, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(statusbar, lv_color_black(), LV_PART_MAIN);
|
||||
lv_obj_set_style_radius(statusbar, 0, LV_PART_MAIN);
|
||||
lv_obj_align(statusbar, LV_ALIGN_TOP_MID, 0, 0);
|
||||
|
||||
lv_obj_t *WifiLabel = lv_label_create(statusbar);
|
||||
lv_label_set_text(WifiLabel, LV_SYMBOL_WIFI);
|
||||
lv_obj_align(WifiLabel, LV_ALIGN_LEFT_MID, -8, 0);
|
||||
lv_obj_set_style_text_font(WifiLabel, &lv_font_montserrat_14, LV_PART_MAIN);
|
||||
|
||||
lv_obj_t *objBattPercentage = lv_label_create(statusbar);
|
||||
lv_label_set_text(objBattPercentage, "");
|
||||
lv_obj_align(objBattPercentage, LV_ALIGN_RIGHT_MID, -16, 0);
|
||||
lv_obj_set_style_text_font(objBattPercentage, &lv_font_montserrat_14,
|
||||
LV_PART_MAIN);
|
||||
|
||||
lv_obj_t *objBattIcon = lv_label_create(statusbar);
|
||||
lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_EMPTY);
|
||||
lv_obj_align(objBattIcon, LV_ALIGN_RIGHT_MID, 8, 0);
|
||||
lv_obj_set_style_text_font(objBattIcon, &lv_font_montserrat_14, LV_PART_MAIN);
|
||||
this->create_status_bar();
|
||||
this->mHardware->wifi()->begin();
|
||||
}
|
||||
|
|
|
@ -2,25 +2,24 @@
|
|||
// 2023 Matthew Colvin
|
||||
#pragma once
|
||||
|
||||
#include "HardwareInterface.h"
|
||||
#include "HardwareAbstract.hpp"
|
||||
#include "Images.hpp"
|
||||
#include "lvgl.h"
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include "poller.hpp"
|
||||
|
||||
/// @brief Singleton to allow UI code to live separately from the Initialization
|
||||
/// of resources.
|
||||
class OmoteUI {
|
||||
public:
|
||||
OmoteUI(std::shared_ptr<HardwareInterface> aHardware)
|
||||
: mHardware(aHardware){};
|
||||
OmoteUI(std::shared_ptr<HardwareAbstract> aHardware);
|
||||
|
||||
static std::weak_ptr<OmoteUI> getRefrence() { return getInstance(); };
|
||||
static std::shared_ptr<OmoteUI>
|
||||
getInstance(std::shared_ptr<HardwareInterface> aHardware = nullptr) {
|
||||
getInstance(std::shared_ptr<HardwareAbstract> aHardware = nullptr) {
|
||||
if (mInstance) {
|
||||
return mInstance;
|
||||
} else if (aHardware) {
|
||||
|
@ -46,23 +45,194 @@ public:
|
|||
void smartHomeSlider_event_cb(lv_event_t *e);
|
||||
// Virtual Keypad Event handler
|
||||
void virtualKeypad_event_cb(lv_event_t *e);
|
||||
void wifi_settings_cb(lv_event_t* event);
|
||||
|
||||
void connect_btn_cb(lv_event_t* event);
|
||||
|
||||
void password_field_event_cb(lv_event_t* e);
|
||||
// Use LVGL to layout the ui and register the callbacks
|
||||
void layout_UI();
|
||||
|
||||
void ta_kb_event_cb(lv_event_t* e);
|
||||
|
||||
void wifi_scan_done(std::shared_ptr<std::vector<WifiInfo>> info);
|
||||
void loopHandler();
|
||||
/**
|
||||
* @brief Function to hide the keyboard. If the keyboard is attached to a text area, it will be hidden when the
|
||||
* text area is defocused. This function can be used if the keyboard need to be hidden due to some script event.
|
||||
*
|
||||
*/
|
||||
void hide_keyboard();
|
||||
|
||||
/**
|
||||
* @brief Function to show the keyboard. If a text area needs the keybaord, it should be attached to the text area
|
||||
* using the approbiate function. The keyboard will then show up when the text area is focused. This function is
|
||||
* needed if the keyboard should be shown due to some script or other trigger.
|
||||
*
|
||||
*/
|
||||
void show_keyboard();
|
||||
|
||||
private:
|
||||
static std::shared_ptr<OmoteUI> mInstance;
|
||||
std::shared_ptr<HardwareInterface> mHardware;
|
||||
std::shared_ptr<HardwareAbstract> mHardware;
|
||||
|
||||
std::unique_ptr<poller> batteryPoller;
|
||||
|
||||
void reset_settings_menu();
|
||||
void attach_keyboard(lv_obj_t* textarea);
|
||||
std::shared_ptr<std::vector<WifiInfo>> found_wifi_networks;
|
||||
/**
|
||||
* @brief Keyboard object used whenever a keyboard is needed.
|
||||
*
|
||||
*/
|
||||
lv_obj_t* kb;
|
||||
|
||||
/**
|
||||
* @brief Function to create the keyboard object which can then be attached to different text areas.
|
||||
*
|
||||
*/
|
||||
void create_keyboard();
|
||||
|
||||
/**
|
||||
* @brief Set the up settings object
|
||||
*
|
||||
* @param parent
|
||||
*/
|
||||
void setup_settings(lv_obj_t* parent);
|
||||
|
||||
/**
|
||||
* @brief LVGL Menu for settings pages as needed.
|
||||
*
|
||||
*/
|
||||
lv_obj_t* settingsMenu;
|
||||
|
||||
/**
|
||||
* @brief Main page of the settings menu
|
||||
*
|
||||
*/
|
||||
lv_obj_t* settingsMainPage;
|
||||
|
||||
/**
|
||||
* @brief Battery percentage label
|
||||
*
|
||||
*/
|
||||
lv_obj_t* objBattPercentage;
|
||||
|
||||
/**
|
||||
* @brief Battery icon object in the status bar
|
||||
*
|
||||
*/
|
||||
lv_obj_t* objBattIcon;
|
||||
|
||||
void create_status_bar();
|
||||
|
||||
lv_obj_t *panel = nullptr;
|
||||
Images imgs = Images();
|
||||
uint_fast8_t currentDevice = 4;
|
||||
int backlight_brightness = 255;
|
||||
lv_color_t color_primary = lv_color_hex(0x303030); // gray
|
||||
bool wakeupByIMUEnabled = true;
|
||||
|
||||
inline static const uint_fast8_t virtualKeyMapTechnisat[10] = {
|
||||
0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0};
|
||||
|
||||
/************************************** WIFI Settings Menu *******************************************************/
|
||||
/**
|
||||
* @brief Container within the wifi selection page
|
||||
*/
|
||||
lv_obj_t* wifi_setting_cont;
|
||||
|
||||
/**
|
||||
* @brief Wifi settings entry point on the settings tab
|
||||
*
|
||||
*/
|
||||
lv_obj_t* wifiOverview;
|
||||
|
||||
/**
|
||||
* @brief Label in the wifi password page. This label is updated with the selected SSID when the credentials for
|
||||
* a wifi network is entered.
|
||||
*
|
||||
*/
|
||||
lv_obj_t* wifi_password_label;
|
||||
|
||||
/**
|
||||
* @brief Menu Subpage for the wifi password
|
||||
*/
|
||||
lv_obj_t* wifi_password_page;
|
||||
|
||||
/**
|
||||
* @brief Menu Subpage for wifi selection
|
||||
*/
|
||||
lv_obj_t* wifi_selection_page;
|
||||
|
||||
/**
|
||||
* @brief Wifi Label shown in the top status bar
|
||||
*/
|
||||
lv_obj_t* WifiLabel;
|
||||
|
||||
/**
|
||||
* @brief Number of wifi subpage needed to display the found wifi networks
|
||||
*
|
||||
*/
|
||||
unsigned int no_subpages;
|
||||
|
||||
/**
|
||||
* @brief number of wifi networks found
|
||||
*
|
||||
*/
|
||||
unsigned int no_wifi_networks;
|
||||
|
||||
|
||||
void wifi_status(std::shared_ptr<wifiStatus> status);
|
||||
/**
|
||||
* @brief callback function to get next wifi subpage. This callback can be used to get the next or previous page
|
||||
*
|
||||
* @param e lvgl event object
|
||||
*/
|
||||
void next_wifi_selection_subpage(lv_event_t* e);
|
||||
|
||||
/**
|
||||
* @brief Create a wifi selection sub page object
|
||||
*
|
||||
* @param menu LVGL Menu where the sub page should be added to
|
||||
* @return lv_obj_t* Menu sub page object pointer
|
||||
*/
|
||||
lv_obj_t* create_wifi_selection_page(lv_obj_t* menu);
|
||||
|
||||
/**
|
||||
* @brief Method to create the wifi password sub page
|
||||
*
|
||||
* @param menu Menu where the sub page should be created
|
||||
* @return lv_obj_t* menu sub page object pointer
|
||||
*/
|
||||
lv_obj_t* create_wifi_password_page(lv_obj_t* menu);
|
||||
|
||||
/**
|
||||
* @brief Method to create the wifi settings on the main page
|
||||
*
|
||||
* @param parent lv object parent where the main settings page should be added to
|
||||
*/
|
||||
void create_wifi_main_page(lv_obj_t* parent);
|
||||
|
||||
/**
|
||||
* @brief Method to create wifi settings. This method will call the create_wifi_selection_page,
|
||||
* the create_wifi_password_page, and the create_wifi_main_page
|
||||
*
|
||||
* @param menu Settings menu where the sub pages should be added to
|
||||
* @param parent lv object parent where the main settings page should be added to
|
||||
*/
|
||||
void create_wifi_settings(lv_obj_t* menu, lv_obj_t* parent);
|
||||
|
||||
/**
|
||||
* @brief Function to update the wifi selection sub page
|
||||
*
|
||||
* @param page index of the page to display
|
||||
*/
|
||||
void update_wifi_selection_subpage(int page);
|
||||
|
||||
/**
|
||||
* @brief Function to create the display settings page.
|
||||
*
|
||||
* @param parent LVGL object acting as a parent for the display settings page
|
||||
*/
|
||||
void display_settings(lv_obj_t* parent);
|
||||
};
|
||||
|
|
56
Platformio/OmoteUI/displaySettings.cpp
Normal file
56
Platformio/OmoteUI/displaySettings.cpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
#include "OmoteUI.hpp"
|
||||
|
||||
void OmoteUI::display_settings(lv_obj_t* parent)
|
||||
{
|
||||
|
||||
lv_obj_t* menuLabel = lv_label_create(parent);
|
||||
lv_label_set_text(menuLabel, "Display");
|
||||
|
||||
lv_obj_t* menuBox = lv_obj_create(parent);
|
||||
lv_obj_set_size(menuBox, lv_pct(100), 109);
|
||||
lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN);
|
||||
|
||||
lv_obj_t* brightnessIcon = imgs.addLowBrightnessIcon(menuBox);
|
||||
lv_obj_align(brightnessIcon, LV_ALIGN_TOP_LEFT, 0, 0);
|
||||
lv_obj_t* slider = lv_slider_create(menuBox);
|
||||
lv_slider_set_range(slider, 0, 255);
|
||||
lv_obj_set_style_bg_color(slider, lv_color_white(), LV_PART_KNOB);
|
||||
lv_obj_set_style_bg_opa(slider, LV_OPA_COVER, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(slider, lv_color_lighten(color_primary, 50), LV_PART_MAIN);
|
||||
lv_slider_set_value(slider, mHardware->display()->getBrightness() , LV_ANIM_OFF);
|
||||
lv_obj_set_size(slider, lv_pct(66), 10);
|
||||
lv_obj_align(slider, LV_ALIGN_TOP_MID, 0, 3);
|
||||
brightnessIcon = imgs.addHighBrightnessIcon(menuBox);
|
||||
lv_obj_align(brightnessIcon, LV_ALIGN_TOP_RIGHT, 0, -1);
|
||||
lv_obj_add_event_cb(slider, [] (lv_event_t* e) {mInstance->bl_slider_event_cb(e);}, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
|
||||
menuLabel = lv_label_create(menuBox);
|
||||
lv_label_set_text(menuLabel, "Lift to Wake");
|
||||
lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 0, 32);
|
||||
lv_obj_t* wakeToggle = lv_switch_create(menuBox);
|
||||
lv_obj_set_size(wakeToggle, 40, 22);
|
||||
lv_obj_align(wakeToggle, LV_ALIGN_TOP_RIGHT, 0, 29);
|
||||
lv_obj_set_style_bg_color(wakeToggle, lv_color_hex(0x505050), LV_PART_MAIN);
|
||||
lv_obj_add_event_cb(wakeToggle, [] (lv_event_t* e) {mInstance->WakeEnableSetting_event_cb(e);}, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
if(wakeupByIMUEnabled) lv_obj_add_state(wakeToggle, LV_STATE_CHECKED); // set default state
|
||||
|
||||
menuLabel = lv_label_create(menuBox);
|
||||
lv_label_set_text(menuLabel, "Timeout");
|
||||
lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 0, 64);
|
||||
lv_obj_t* drop = lv_dropdown_create(menuBox);
|
||||
lv_dropdown_set_options(drop, "10s\n"
|
||||
"30s\n"
|
||||
"1m\n"
|
||||
"3m");
|
||||
lv_obj_align(drop, LV_ALIGN_TOP_RIGHT, 0, 61);
|
||||
lv_obj_set_size(drop, 70, 22);
|
||||
//lv_obj_set_style_text_font(drop, &lv_font_montserrat_12, LV_PART_MAIN);
|
||||
//lv_obj_set_style_text_font(lv_dropdown_get_list(drop), &lv_font_montserrat_12, LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_top(drop, 1, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(drop, color_primary, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(lv_dropdown_get_list(drop), color_primary, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(lv_dropdown_get_list(drop), 1, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_color(lv_dropdown_get_list(drop), lv_color_hex(0x505050), LV_PART_MAIN);
|
||||
|
||||
}
|
26
Platformio/OmoteUI/poller.cpp
Normal file
26
Platformio/OmoteUI/poller.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include "poller.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
poller::poller(std::function<void()> aOnPollCb, milliseconds aPollTime):mIntermittentCallback(std::move(aOnPollCb)){
|
||||
mTimer = lv_timer_create(poller::onPoll,aPollTime.count(),this);
|
||||
lv_timer_set_repeat_count(mTimer,-1); // Call forever
|
||||
}
|
||||
|
||||
poller::~poller(){
|
||||
if(mTimer){
|
||||
lv_timer_del(mTimer);
|
||||
mTimer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void poller::onPoll(_lv_timer_t* aTimer){
|
||||
poller* currentPoller = reinterpret_cast<poller*>(aTimer->user_data);
|
||||
|
||||
if(currentPoller->mIntermittentCallback){
|
||||
currentPoller->mIntermittentCallback();
|
||||
}
|
||||
}
|
23
Platformio/OmoteUI/poller.hpp
Normal file
23
Platformio/OmoteUI/poller.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include "lvgl.h"
|
||||
|
||||
class poller{
|
||||
public:
|
||||
poller(std::function<void()> aOnPollCb, std::chrono::milliseconds pollTime = std::chrono::seconds(5));
|
||||
virtual ~poller();
|
||||
|
||||
void setPollPeriod(std::chrono::milliseconds aPollPeriod){ lv_timer_set_period(mTimer, aPollPeriod.count());}
|
||||
inline void pause() { lv_timer_pause(mTimer);}
|
||||
inline void resume() { lv_timer_resume(mTimer);}
|
||||
inline void reset() { lv_timer_reset(mTimer);}
|
||||
inline void runNext() { lv_timer_ready(mTimer);}
|
||||
|
||||
private:
|
||||
lv_timer_t* mTimer = nullptr;
|
||||
std::function<void()> mIntermittentCallback = nullptr;
|
||||
|
||||
// Static function registered to every timers callback to pass this object as context
|
||||
static void onPoll(_lv_timer_t* aTimer);
|
||||
};
|
312
Platformio/OmoteUI/wifiSettings.cpp
Normal file
312
Platformio/OmoteUI/wifiSettings.cpp
Normal file
|
@ -0,0 +1,312 @@
|
|||
#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*/
|
||||
lv_obj_t* subpage = lv_menu_page_create(menu, NULL);
|
||||
this->wifi_setting_cont = lv_menu_cont_create(subpage);
|
||||
lv_obj_set_layout(this->wifi_setting_cont, LV_LAYOUT_FLEX);
|
||||
lv_obj_set_flex_flow(this->wifi_setting_cont, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_scrollbar_mode(this->wifi_setting_cont, LV_SCROLLBAR_MODE_ACTIVE);
|
||||
|
||||
lv_obj_t* menuLabel = lv_label_create(this->wifi_setting_cont);
|
||||
lv_label_set_text(menuLabel, "Searching for wifi networks");
|
||||
|
||||
|
||||
return subpage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback function for the show password checkbox. Checking the box will show the password while unchecked the
|
||||
* password will be shown as dots.
|
||||
*
|
||||
* @param e Pointer to event object for the event where this callback is called
|
||||
*/
|
||||
static void show_password_cb(lv_event_t* e)
|
||||
{
|
||||
lv_obj_t* password_field = (lv_obj_t*) e->user_data;
|
||||
if (lv_obj_has_state(e->target, LV_STATE_CHECKED)){
|
||||
lv_textarea_set_password_mode(password_field, false);
|
||||
}
|
||||
else{
|
||||
lv_textarea_set_password_mode(password_field, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Textarea callback function for the password field. In case the enter key is pressed in the text area, the
|
||||
* function will try to connect to the network with the provided password.
|
||||
*
|
||||
* @param e Pointer to event object for the event where this callback is called
|
||||
*/
|
||||
void OmoteUI::password_field_event_cb(lv_event_t* e)
|
||||
{
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
lv_obj_t * ta = lv_event_get_target(e);
|
||||
lv_obj_t * kb = (lv_obj_t*) lv_event_get_user_data(e);
|
||||
|
||||
const char* password = lv_textarea_get_text(ta);
|
||||
switch(code){
|
||||
case LV_EVENT_READY:
|
||||
this->mHardware->wifi()->connect(std::make_shared<std::string>(std::string(ssid)), std::make_shared<std::string>(std::string(password)));
|
||||
lv_obj_clear_state(ta, LV_STATE_FOCUSED);
|
||||
this->hide_keyboard();
|
||||
this->reset_settings_menu();
|
||||
/* Fall through on purpose. Pressing enter should disable the keyboard as well*/
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback which is triggered when clicking the connect button. It triggers the wifi connection.
|
||||
*
|
||||
* @param event Pointer to event object for the event where this callback is called
|
||||
*/
|
||||
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(std::make_shared<std::string>(std::string(ssid)), std::make_shared<std::string>(std::string(password)));
|
||||
//Trigger wifi connection here
|
||||
//wifihandler.connect(ssid, password);
|
||||
lv_obj_clear_state(ta, LV_STATE_FOCUSED);
|
||||
this->hide_keyboard();
|
||||
this->reset_settings_menu();
|
||||
|
||||
}
|
||||
|
||||
void OmoteUI::create_wifi_main_page(lv_obj_t* parent)
|
||||
{
|
||||
lv_obj_t* menuLabel = lv_label_create(parent);
|
||||
lv_label_set_text(menuLabel, "Wi-Fi");
|
||||
this->wifiOverview = lv_obj_create(parent);
|
||||
lv_obj_set_size(this->wifiOverview, lv_pct(100), 80);
|
||||
lv_obj_set_style_bg_color(this->wifiOverview, color_primary, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(this->wifiOverview, 0, LV_PART_MAIN);
|
||||
menuLabel = lv_label_create(this->wifiOverview);
|
||||
|
||||
lv_obj_t* arrow = lv_label_create(this->wifiOverview);
|
||||
lv_label_set_text(arrow, LV_SYMBOL_RIGHT);
|
||||
lv_obj_align(arrow, LV_ALIGN_TOP_RIGHT, 0, 0);
|
||||
|
||||
lv_obj_t* ip_label = lv_label_create(this->wifiOverview);
|
||||
lv_label_set_text(ip_label, "IP:");
|
||||
lv_obj_align(ip_label, LV_ALIGN_BOTTOM_LEFT, 0, 0);
|
||||
|
||||
lv_obj_t* ip = lv_label_create(this->wifiOverview);
|
||||
lv_obj_align(ip, LV_ALIGN_BOTTOM_RIGHT, 0, 0);
|
||||
|
||||
lv_label_set_text(menuLabel, "Disconnected");
|
||||
lv_label_set_text(ip, "-");
|
||||
|
||||
lv_menu_set_load_page_event(this->settingsMenu, this->wifiOverview, this->wifi_selection_page);
|
||||
lv_obj_add_event_cb(this->wifiOverview, [] (lv_event_t* e) {mInstance->wifi_settings_cb(e);}, LV_EVENT_CLICKED, this->wifi_setting_cont);
|
||||
}
|
||||
|
||||
void OmoteUI::wifi_scan_done(std::shared_ptr<std::vector<WifiInfo>> 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 = (uintptr_t) 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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->wifi()->onScanDone([] (std::shared_ptr<std::vector<WifiInfo>> info) {mInstance->wifi_scan_done(info);});
|
||||
this->mHardware->wifi()->onStatusUpdate([] (std::shared_ptr<wifiStatus> status) {mInstance->wifi_status(status);});
|
||||
}
|
||||
|
||||
void OmoteUI::wifi_status(std::shared_ptr<wifiStatus> 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)
|
||||
{
|
||||
lv_obj_t* ret_val = lv_menu_page_create(menu, NULL);
|
||||
lv_obj_t* cont = lv_menu_cont_create(ret_val);
|
||||
lv_obj_set_layout(cont, LV_LAYOUT_FLEX);
|
||||
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_scrollbar_mode(cont, LV_SCROLLBAR_MODE_ACTIVE);
|
||||
|
||||
this->wifi_password_label = lv_label_create(cont);
|
||||
lv_label_set_text(this->wifi_password_label, "Password");
|
||||
lv_obj_t* password_input = lv_textarea_create(cont);
|
||||
lv_obj_set_width(password_input, lv_pct(100));
|
||||
lv_textarea_set_password_mode(password_input, true);
|
||||
lv_textarea_set_one_line(password_input, true);
|
||||
lv_textarea_set_placeholder_text(password_input, "Password");
|
||||
lv_obj_add_event_cb(password_input, [] (lv_event_t* e) {mInstance->password_field_event_cb(e);} , LV_EVENT_READY, NULL );
|
||||
this->attach_keyboard(password_input);
|
||||
|
||||
lv_obj_t* show_password = lv_checkbox_create(cont);
|
||||
lv_checkbox_set_text(show_password, "Show password");
|
||||
lv_obj_add_event_cb(show_password, show_password_cb, LV_EVENT_VALUE_CHANGED, password_input);
|
||||
|
||||
lv_obj_t* connect_button = lv_btn_create(cont);
|
||||
lv_obj_t* label = lv_label_create(connect_button);
|
||||
lv_label_set_text(label, "Connect");
|
||||
lv_obj_add_event_cb(connect_button,[] (lv_event_t* e) { mInstance->connect_btn_cb(e);}, LV_EVENT_CLICKED, password_input);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback which is triggered when the wifi settings are opened (the wifi settings are pressed in the settings
|
||||
* main page). This function will trigger the asynchronous scan for wifi networks and update the label of the wifi
|
||||
* selection page to indicate that wifi networks are being searched for. The wifi event callback function then has to
|
||||
* call the API function to fill the page with the found networks.
|
||||
*
|
||||
* @param event Pointer to event object for the event where this callback is called
|
||||
*/
|
||||
void OmoteUI::wifi_settings_cb(lv_event_t* event)
|
||||
{
|
||||
lv_obj_t* cont = (lv_obj_t*) lv_event_get_user_data(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();
|
||||
//This will trigger an asynchronouse network scan
|
||||
// We need to trigger wifi search via HAL
|
||||
//wifihandler.scan();
|
||||
}
|
|
@ -40,13 +40,17 @@ build_flags =
|
|||
; ------------- Includes ------------------------------------
|
||||
-I OmoteUI
|
||||
-I HAL
|
||||
-I HAL/Interface
|
||||
-I HAL/HardwareModules
|
||||
|
||||
lib_deps =
|
||||
lvgl/lvgl@^8.3.9
|
||||
;lvgl/lvgl@^8.3.9
|
||||
lvgl=https://github.com/lvgl/lvgl/archive/refs/tags/v8.3.9.zip
|
||||
|
||||
lib_archive = false
|
||||
build_src_filter =
|
||||
+<../OmoteUI/*>
|
||||
+<../HAL/HardwareAbstract.cpp>
|
||||
+<../HAL/HardwareModules/*.cpp>
|
||||
|
||||
|
||||
|
||||
|
@ -62,6 +66,7 @@ lib_deps =
|
|||
${env.lib_deps}
|
||||
sparkfun/SparkFun LIS3DH Arduino Library@^1.0.3
|
||||
crankyoldgit/IRremoteESP8266@^2.8.4
|
||||
adafruit/Adafruit BusIO @ 1.9.6
|
||||
adafruit/Adafruit FT6206 Library@^1.0.6
|
||||
bodmer/TFT_eSPI@^2.5.23
|
||||
knolleary/PubSubClient@^2.8
|
||||
|
@ -95,6 +100,9 @@ build_flags =
|
|||
|
||||
; ------------- Includes --------------------------------------------
|
||||
-I HAL/Targets/ESP32
|
||||
-I HAL/Targets/ESP32/battery
|
||||
-I HAL/Targets/ESP32/display
|
||||
-I HAL/Targets/ESP32/wifiHandler
|
||||
|
||||
build_unflags =
|
||||
-std=gnu++11
|
||||
|
@ -116,6 +124,7 @@ build_flags =
|
|||
-D LV_LVGL_H_INCLUDE_SIMPLE
|
||||
-D LV_DRV_NO_CONF
|
||||
-D USE_SDL
|
||||
-D SDL_MAIN_HANDLED
|
||||
-D SDL_HOR_RES=SCREEN_WIDTH
|
||||
-D SDL_VER_RES=SCREEN_HEIGHT
|
||||
-D SDL_ZOOM=1
|
||||
|
@ -123,6 +132,7 @@ build_flags =
|
|||
|
||||
; -------------- Sim Includes ---------------------------
|
||||
-I HAL/Targets/Simulator
|
||||
-I HAL/Targets/Simulator/wifiHandlerSim
|
||||
|
||||
debug_build_flags =
|
||||
-g ;Allow debugging in vscode
|
||||
|
@ -135,6 +145,6 @@ lib_deps =
|
|||
build_src_filter =
|
||||
+<simMain.cpp>
|
||||
+<../HAL/Targets/Simulator/*>
|
||||
+<../OmoteUI/*>
|
||||
${env.build_src_filter}
|
||||
; Force compile LVGL demo, remove when working on your own project
|
||||
|
||||
|
|
|
@ -89,6 +89,8 @@ Distributed under the GPL v3 License. See [LICENSE](https://github.com/CoretechR
|
|||
|
||||
## Contact
|
||||
|
||||
Maximilian Kern - [kernm.de](kernm.de)
|
||||
Maximilian Kern - [kernm.de](https://kernm.de)
|
||||
|
||||
Project Link: [https://hackaday.io/project/191752-omote-diy-universal-remote](https://hackaday.io/project/191752-omote-diy-universal-remote)
|
||||
Omote Discord: [https://discord.gg/5PnYFAsKsG](https://discord.gg/5PnYFAsKsG)
|
||||
|
||||
Project Page on Hackaday.io: [https://hackaday.io/project/191752-omote-diy-universal-remote](https://hackaday.io/project/191752-omote-diy-universal-remote)
|
||||
|
|
Loading…
Reference in a new issue