From 5f88ed733d9c9c3e477f0e1d9d1fcdd9aac7f7db Mon Sep 17 00:00:00 2001 From: Jeremy Poulter Date: Fri, 13 Oct 2023 22:06:59 +0100 Subject: [PATCH] Initial code to render a boot screen and charging screen (with some random text) --- scripts/extra_script.py | 3 -- src/embedded_files.cpp | 23 ++++++++++ src/embedded_files.h | 22 +++++++++ src/lcd_tft.cpp | 94 ++++++++++++++++++++++++++++++--------- src/lcd_tft.h | 16 ++++++- src/time_man.cpp | 4 +- src/time_man.h | 2 +- src/web_server_static.cpp | 33 +------------- 8 files changed, 137 insertions(+), 60 deletions(-) create mode 100644 src/embedded_files.cpp create mode 100644 src/embedded_files.h diff --git a/scripts/extra_script.py b/scripts/extra_script.py index 4cc871a0..1c52c157 100644 --- a/scripts/extra_script.py +++ b/scripts/extra_script.py @@ -163,15 +163,12 @@ def make_static(env, target, source, prefix, files_dir): output_file.write(output) def process_html_app(source, dest, env, prefix, static_func): - print("Processing HTML app in {}".format(source)) - web_server_static_files = join(dest, prefix+"_static_files.h") web_server_static = join(env.subst("$BUILD_DIR"), "src/"+prefix+"_static.cpp.o") files = filtered_listdir(source) for file in files: - print(" {}".format(file)) data_file = join(source, file) header_file = join(dest, prefix+"."+make_safe(file)+".h") env.Command(header_file, data_file, data_to_header) diff --git a/src/embedded_files.cpp b/src/embedded_files.cpp new file mode 100644 index 00000000..97f75b88 --- /dev/null +++ b/src/embedded_files.cpp @@ -0,0 +1,23 @@ + +#include "embedded_files.h" +#include "emonesp.h" + +bool embedded_get_file(String filename, StaticFile *index, size_t length, StaticFile **file) +{ + DBUGF("Looking for %s", filename.c_str()); + + for(int i = 0; i < length; i++) + { + if(filename == index[i].filename) + { + DBUGF("Found %s %d@%p", index[i].filename, index[i].length, index[i].data); + + if(file) { + *file = &index[i]; + } + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/src/embedded_files.h b/src/embedded_files.h new file mode 100644 index 00000000..e77d2a35 --- /dev/null +++ b/src/embedded_files.h @@ -0,0 +1,22 @@ +#ifndef EMBEDDED_FILES_H +#define EMBEDDED_FILES_H + +#include + +#define ARRAY_LENGTH(x) (sizeof(x)/sizeof((x)[0])) + +#define IS_ALIGNED(x) (0 == ((uint32_t)(x) & 0x3)) + +struct StaticFile +{ + const char *filename; + const char *data; + size_t length; + const char *type; + const char *etag; + bool compressed; +}; + +bool embedded_get_file(String filename, StaticFile *index, size_t length, StaticFile **file); + +#endif // EMBEDDED_FILES_H diff --git a/src/lcd_tft.cpp b/src/lcd_tft.cpp index 1a87726f..145429d9 100644 --- a/src/lcd_tft.cpp +++ b/src/lcd_tft.cpp @@ -15,22 +15,22 @@ #include "input.h" #include "app_config.h" #include +#include "embedded_files.h" #include "web_server.h" -// Static files -struct StaticFile -{ - const char *filename; - const char *data; - size_t length; - const char *type; - const char *etag; - bool compressed; -}; +PNG png; #include "lcd_static/lcd_gui_static_files.h" +#define MAX_IMAGE_WIDTH TFT_HEIGHT // Adjust for your images + +struct image_render_state { + TFT_eSPI *tft; + int16_t xpos; + int16_t ypos; +}; + LcdTask::LcdTask() : MicroTasks::Task(), _lcd() @@ -56,16 +56,6 @@ void LcdTask::begin(EvseManager &evse, Scheduler &scheduler, ManualOverride &man void LcdTask::setup() { - DBUGLN("LCD UI setup"); - - _lcd.begin(); - _lcd.setRotation(1); - _lcd.fillScreen(TFT_BLACK); - - delay(100); - - pinMode(LCD_BACKLIGHT_PIN, OUTPUT); - digitalWrite(LCD_BACKLIGHT_PIN, HIGH); } unsigned long LcdTask::loop(MicroTasks::WakeReason reason) @@ -79,12 +69,72 @@ unsigned long LcdTask::loop(MicroTasks::WakeReason reason) unsigned long nextUpdate = MicroTask.Infinate; - //lv_timer_handler(); + switch(_state) + { + case State::Boot: + DBUGLN("LCD UI setup"); + + _lcd.begin(); + _lcd.setRotation(1); + + render_image("/BootScreen.png", 0, 0); + + pinMode(LCD_BACKLIGHT_PIN, OUTPUT); + digitalWrite(LCD_BACKLIGHT_PIN, HIGH); + nextUpdate = 5000; + _state = State::Charge; + break; + + case State::Charge: + render_image("/ChargeScreen.png", 0, 0); + + _lcd.setCursor(0, 0, 2); + _lcd.setTextColor(TFT_WHITE, TFT_BLACK); + _lcd.setTextSize(2); + _lcd.print("OpenEVSE"); + _lcd.setCursor(0, 16); + _lcd.print("WiFi Connected"); + + break; + + default: + break; + } DBUGVAR(nextUpdate); return nextUpdate; } +void LcdTask::render_image(const char *filename, int16_t x, int16_t y) +{ + StaticFile *file = NULL; + if(embedded_get_file(filename, lcd_gui_static_files, ARRAY_LENGTH(lcd_gui_static_files), &file)) + { + DBUGF("Found %s (%d bytes)", filename, file->length); + int16_t rc = png.openFLASH((uint8_t *)file->data, file->length, png_draw); + if (rc == PNG_SUCCESS) + { + DBUGLN("Successfully opened png file"); + DBUGF("image specs: (%d x %d), %d bpp, pixel type: %d\n", png.getWidth(), png.getHeight(), png.getBpp(), png.getPixelType()); + _lcd.startWrite(); + uint32_t dt = millis(); + image_render_state state = {&_lcd, x, y}; + rc = png.decode(&state, 0); + DBUG(millis() - dt); DBUGLN("ms"); + _lcd.endWrite(); + // png.close(); // not needed for memory->memory decode + } + } +} + +void LcdTask::png_draw(PNGDRAW *pDraw) +{ + image_render_state *state = (image_render_state *)pDraw->pUser; + uint16_t lineBuffer[MAX_IMAGE_WIDTH]; + png.getLineAsRGB565(pDraw, lineBuffer, PNG_RGB565_BIG_ENDIAN, 0xffffffff); + state->tft->pushImage(state->xpos, state->ypos + pDraw->y, pDraw->iWidth, 1, lineBuffer); +} + LcdTask lcd; -#endif // ENABLE_SCREEN_LCD_TFT +#endif // ENABLE_SCREEN_LCD_lcd diff --git a/src/lcd_tft.h b/src/lcd_tft.h index 702e7a26..31b738af 100644 --- a/src/lcd_tft.h +++ b/src/lcd_tft.h @@ -13,7 +13,7 @@ //#include #include - +#include class LcdTask : public MicroTasks::Task { @@ -24,10 +24,20 @@ class LcdTask : public MicroTasks::Task const uint16_t _screenWidth = TFT_HEIGHT; const uint16_t _screenHeight = TFT_WIDTH; + enum class State { + Boot, + Charge + }; + + State _state = State::Boot; + + static void png_draw(PNGDRAW *pDraw); protected: void setup(); unsigned long loop(MicroTasks::WakeReason reason); + void render_image(const char *filename, int16_t x, int16_t y); + public: LcdTask(); @@ -36,6 +46,10 @@ class LcdTask : public MicroTasks::Task void display(const __FlashStringHelper *msg, int x, int y, int time, uint32_t flags); void display(String &msg, int x, int y, int time, uint32_t flags); void display(const char *msg, int x, int y, int time, uint32_t flags); + + void fill_screen(uint16_t color) { + _lcd.fillScreen(color); + } }; extern LcdTask lcd; diff --git a/src/time_man.cpp b/src/time_man.cpp index 7e3fc3e2..812b067d 100644 --- a/src/time_man.cpp +++ b/src/time_man.cpp @@ -239,10 +239,10 @@ void time_set_time(struct timeval setTime, const char *source) { timeManager.setTime(setTime, source); } -String time_format_time(time_t time, bool local) +String time_format_time(time_t time, bool local_time) { struct tm timeinfo; - if(local) { + if(local_time) { localtime_r(&time, &timeinfo); } else { gmtime_r(&time, &timeinfo); diff --git a/src/time_man.h b/src/time_man.h index 6be7492f..06a385d6 100644 --- a/src/time_man.h +++ b/src/time_man.h @@ -61,7 +61,7 @@ extern TimeManager timeManager; extern void time_set_time(struct timeval set_time, const char *source); -extern String time_format_time(time_t time, bool local = true); +extern String time_format_time(time_t time, bool local_time = true); extern String time_format_time(tm &time); #endif // _OPENEVSE_TIME_H diff --git a/src/web_server_static.cpp b/src/web_server_static.cpp index 8d3e019e..f0f30b86 100644 --- a/src/web_server_static.cpp +++ b/src/web_server_static.cpp @@ -9,26 +9,12 @@ #include "web_server_static.h" #include "app_config.h" #include "net_manager.h" +#include "embedded_files.h" extern bool enableCors; // defined in web_server.cpp -// Static files -struct StaticFile -{ - const char *filename; - const char *data; - size_t length; - const char *type; - const char *etag; - bool compressed; -}; - #include "web_static/web_server_static_files.h" -#define ARRAY_LENGTH(x) (sizeof(x)/sizeof((x)[0])) - -#define IS_ALIGNED(x) (0 == ((uint32_t)(x) & 0x3)) - #define WEB_SERVER_INDEX_PAGE "index.html" // Pages @@ -51,24 +37,9 @@ static bool web_static_get_file(MongooseHttpServerRequest *request, StaticFile * if(path == "/") { path = String( HOME_PAGE); - } - DBUGF("Looking for %s", path.c_str()); - - for(int i = 0; i < ARRAY_LENGTH(web_server_static_files); i++) { - if(path == web_server_static_files[i].filename) - { - DBUGF("Found %s %d@%p", web_server_static_files[i].filename, web_server_static_files[i].length, web_server_static_files[i].data); - - if(file) { - *file = &web_server_static_files[i]; - } - return true; - } - } - - return false; + return embedded_get_file(path, web_server_static_files, ARRAY_LENGTH(web_server_static_files), file); } bool web_static_handle(MongooseHttpServerRequest *request)