diff --git a/src/tangara/app_console/app_console.cpp b/src/tangara/app_console/app_console.cpp index af9061fe..11862143 100644 --- a/src/tangara/app_console/app_console.cpp +++ b/src/tangara/app_console/app_console.cpp @@ -683,6 +683,26 @@ void RegisterLua() { esp_console_cmd_register(&cmd_luarun); } +int CmdSnapshot(int argc, char** argv) { + if (argc != 2) { + std::cout << "snapshot expects 1 argument" << std::endl; + return 1; + } + + events::Ui().Dispatch(ui::Screenshot{.filename = argv[1]}); + return 0; +} + +void RegisterSnapshot() { + esp_console_cmd_t cmd_snapshot{ + .command = "snapshot", + .help = "Saves a screenshot of the display to a file", + .hint = "filename", + .func = &CmdSnapshot, + .argtable = NULL}; + esp_console_cmd_register(&cmd_snapshot); +} + auto AppConsole::PrerunCallback() -> void { Console::PrerunCallback(); esp_log_level_set("*", ESP_LOG_NONE); @@ -713,6 +733,7 @@ auto AppConsole::RegisterExtraComponents() -> void { RegisterHapticEffect(); RegisterLua(); + RegisterSnapshot(); } } // namespace console diff --git a/src/tangara/ui/ui_events.hpp b/src/tangara/ui/ui_events.hpp index 05fd4483..0f371769 100644 --- a/src/tangara/ui/ui_events.hpp +++ b/src/tangara/ui/ui_events.hpp @@ -30,6 +30,10 @@ struct OnLuaError : tinyfsm::Event { struct DumpLuaStack : tinyfsm::Event {}; +struct Screenshot : tinyfsm::Event { + std::string filename; +}; + namespace internal { struct InitDisplay : tinyfsm::Event { diff --git a/src/tangara/ui/ui_fsm.cpp b/src/tangara/ui/ui_fsm.cpp index 476732db..4f93fe61 100644 --- a/src/tangara/ui/ui_fsm.cpp +++ b/src/tangara/ui/ui_fsm.cpp @@ -13,6 +13,7 @@ #include #include "FreeRTOSConfig.h" +#include "draw/lv_draw_buf.h" #include "drivers/bluetooth.hpp" #include "lvgl.h" @@ -26,6 +27,9 @@ #include "freertos/projdefs.h" #include "lua.hpp" #include "luavgl.h" +#include "misc/lv_color.h" +#include "misc/lv_utils.h" +#include "others/snapshot/lv_snapshot.h" #include "tick/lv_tick.h" #include "tinyfsm.hpp" @@ -363,6 +367,28 @@ int UiState::PopScreen() { return sScreens.size(); } +void UiState::react(const Screenshot& ev) { + if (!sCurrentScreen) { + return; + } + ESP_LOGI(kTag, "taking snapshot"); + lv_draw_buf_t* buf = + lv_snapshot_take(sCurrentScreen->root(), LV_COLOR_FORMAT_RGB888); + if (!buf) { + ESP_LOGW(kTag, "snapshot failed"); + return; + } + ESP_LOGI(kTag, "writing to file"); + std::string fullpath = "//sdcard/" + ev.filename; + auto res = lv_draw_buf_save_to_file(buf, fullpath.c_str()); + lv_draw_buf_destroy(buf); + if (res == LV_RESULT_OK) { + ESP_LOGI(kTag, "write okay!"); + } else { + ESP_LOGE(kTag, "write failed!"); + } +} + void UiState::react(const system_fsm::KeyLockChanged& ev) { sDisplay->SetDisplayOn(!ev.locking); sInput->lock(ev.locking); diff --git a/src/tangara/ui/ui_fsm.hpp b/src/tangara/ui/ui_fsm.hpp index 72688fa0..cef9a13a 100644 --- a/src/tangara/ui/ui_fsm.hpp +++ b/src/tangara/ui/ui_fsm.hpp @@ -53,6 +53,7 @@ class UiState : public tinyfsm::Fsm { /* Fallback event handler. Does nothing. */ void react(const tinyfsm::Event& ev) {} + void react(const Screenshot&); virtual void react(const OnLuaError&) {} virtual void react(const DumpLuaStack&) {} virtual void react(const internal::BackPressed&) {}