From 64b106c13e18c33be0f2b0de532054e0ed3f731d Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 13 Dec 2023 16:10:08 +1100 Subject: add a cool lua repl --- src/app_console/app_console.cpp | 56 +++++++++++++++++++++++++++++++++++++ src/dev_console/include/console.hpp | 2 +- src/drivers/include/gpios.hpp | 2 +- src/drivers/spiffs.cpp | 35 +++++++++++++++++++++-- src/lua/CMakeLists.txt | 3 +- src/lua/bridge.cpp | 11 ++++++++ src/lua/include/lua_thread.hpp | 1 + src/lua/lua_thread.cpp | 9 ++++++ 8 files changed, 114 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/app_console/app_console.cpp b/src/app_console/app_console.cpp index 63accc21..f99f7536 100644 --- a/src/app_console/app_console.cpp +++ b/src/app_console/app_console.cpp @@ -37,6 +37,7 @@ #include "freertos/projdefs.h" #include "haptics.hpp" #include "index.hpp" +#include "lua_thread.hpp" #include "memory_resource.hpp" #include "service_locator.hpp" #include "system_events.hpp" @@ -557,6 +558,60 @@ void RegisterHapticEffect() { esp_console_cmd_register(&cmd); } +static const char kReplMain[] = + "package.path = '/repl/?.lua;/repl/?/init.lua;' .. package.path\n" + "local repl = require 'repl.console'\n" + "local col = require('term').colors\n" + "function repl:getprompt(level)\n" + "if level == 1 then\n" + "return col.blue .. '>>' .. col.reset\n" + "else\n" + "return '..'\n" + "end\n" + "end\n" + "repl:loadplugin 'linenoise'\n" + "repl:loadplugin 'history'\n" + "repl:loadplugin 'completion'\n" + "repl:loadplugin 'autoreturn'\n" + "repl:loadplugin 'pretty_print'\n" + "print 'Lua 5.4.4 Copyright (C) 1994-2023 Lua.org, PUC-Rio'\n" + "print 'luarepl 0.10 Copyright (C) 2011-2015 Rob Hoelz'\n" + "repl:run()\n"; + +int CmdLua(int argc, char** argv) { + std::unique_ptr context{ + lua::LuaThread::Start(*AppConsole::sServices)}; + if (!context) { + return 1; + } + + if (argc == 1) { + return context->RunString(kReplMain); + } else { + std::ostringstream path; + path << argv[0]; + for (size_t i = 1; i < argc; i++) { + path << " " << argv[i]; + } + FILINFO info; + if (f_stat(path.str().c_str(), &info) != FR_OK) { + std::cout << "file not found: " << path.str() << std::endl; + } + return context->RunScript(path.str()); + } + return 0; +} + +void RegisterLua() { + esp_console_cmd_t cmd{ + .command = "lua", + .help = "Executes a lua script. With no args, begins a lua repl session", + .hint = NULL, + .func = &CmdLua, + .argtable = NULL}; + esp_console_cmd_register(&cmd); +} + auto AppConsole::RegisterExtraComponents() -> void { RegisterListDir(); RegisterPlayFile(); @@ -579,6 +634,7 @@ auto AppConsole::RegisterExtraComponents() -> void { RegisterCoreDump(); RegisterHapticEffect(); + RegisterLua(); } } // namespace console diff --git a/src/dev_console/include/console.hpp b/src/dev_console/include/console.hpp index fedf3632..fd4050c2 100644 --- a/src/dev_console/include/console.hpp +++ b/src/dev_console/include/console.hpp @@ -18,7 +18,7 @@ class Console { auto Launch() -> void; protected: - virtual auto GetStackSizeKiB() -> uint16_t { return 8; } + virtual auto GetStackSizeKiB() -> uint16_t { return 16; } virtual auto RegisterExtraComponents() -> void {} private: diff --git a/src/drivers/include/gpios.hpp b/src/drivers/include/gpios.hpp index fe4b1c4c..a201c173 100644 --- a/src/drivers/include/gpios.hpp +++ b/src/drivers/include/gpios.hpp @@ -78,7 +78,7 @@ class IGpios { */ virtual auto Get(Pin) const -> bool = 0; - virtual auto IsLocked() const -> bool { return Get(Pin::kKeyLock); } + virtual auto IsLocked() const -> bool { return !Get(Pin::kKeyLock); } }; class Gpios : public IGpios { diff --git a/src/drivers/spiffs.cpp b/src/drivers/spiffs.cpp index 9a85c0d3..f03d2f68 100644 --- a/src/drivers/spiffs.cpp +++ b/src/drivers/spiffs.cpp @@ -14,7 +14,7 @@ namespace drivers { [[maybe_unused]] static constexpr char kTag[] = "spiffs"; -esp_err_t spiffs_mount() { +static auto mount_script_dir() -> esp_err_t { esp_vfs_spiffs_conf_t config{ .base_path = "/lua", .partition_label = "lua", @@ -26,10 +26,41 @@ esp_err_t spiffs_mount() { if (res == ESP_OK) { size_t total, used; esp_spiffs_info("lua", &total, &used); - ESP_LOGI(kTag, "spiffs mounted okay. %d / %d ", used / 1024, total / 1024); + ESP_LOGI(kTag, "lua scripts mounted okay. %d / %d ", used / 1024, + total / 1024); } return res; } +static auto mount_repl_dir() -> esp_err_t { + esp_vfs_spiffs_conf_t config{ + .base_path = "/repl", + .partition_label = "repl", + .max_files = 5, + .format_if_mount_failed = false, + }; + + esp_err_t res = esp_vfs_spiffs_register(&config); + if (res == ESP_OK) { + size_t total, used; + esp_spiffs_info("repl", &total, &used); + ESP_LOGI(kTag, "lua repl mounted okay. %d / %d ", used / 1024, + total / 1024); + } + + return res; +} + +esp_err_t spiffs_mount() { + esp_err_t res; + if ((res = mount_script_dir()) != ESP_OK) { + return res; + } + if ((res = mount_repl_dir()) != ESP_OK) { + return res; + } + return ESP_OK; +} + } // namespace drivers diff --git a/src/lua/CMakeLists.txt b/src/lua/CMakeLists.txt index 654e2763..5c67a57e 100644 --- a/src/lua/CMakeLists.txt +++ b/src/lua/CMakeLists.txt @@ -5,5 +5,6 @@ idf_component_register( SRCS "lua_thread.cpp" "bridge.cpp" "property.cpp" "lua_database.cpp" "lua_queue.cpp" INCLUDE_DIRS "include" - REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database" "esp_timer" "battery" "esp-idf-lua" "luavgl") + REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database" + "esp_timer" "battery" "esp-idf-lua" "luavgl" "lua-linenoise" "lua-term") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/lua/bridge.cpp b/src/lua/bridge.cpp index 8d7b4fd0..1063cfbf 100644 --- a/src/lua/bridge.cpp +++ b/src/lua/bridge.cpp @@ -25,6 +25,11 @@ #include "service_locator.hpp" #include "ui_events.hpp" +extern "C" { +int luaopen_linenoise(lua_State* L); +int luaopen_term_core(lua_State* L); +} + namespace lua { [[maybe_unused]] static constexpr char kTag[] = "lua_bridge"; @@ -61,6 +66,12 @@ Bridge::Bridge(system_fsm::ServiceLocator& services, lua_State& s) luaL_requiref(&s, "legacy_ui", lua_legacy_ui, true); lua_pop(&s, 1); + luaL_requiref(&s, "linenoise", luaopen_linenoise, true); + lua_pop(&s, 1); + + luaL_requiref(&s, "term.core", luaopen_term_core, true); + lua_pop(&s, 1); + RegisterDatabaseModule(&s); RegisterQueueModule(&s); } diff --git a/src/lua/include/lua_thread.hpp b/src/lua/include/lua_thread.hpp index b10fdadf..c85ccb91 100644 --- a/src/lua/include/lua_thread.hpp +++ b/src/lua/include/lua_thread.hpp @@ -28,6 +28,7 @@ class LuaThread { ~LuaThread(); auto RunScript(const std::string& path) -> bool; + auto RunString(const std::string& path) -> bool; auto bridge() -> Bridge& { return *bridge_; } auto state() -> lua_State* { return state_; } diff --git a/src/lua/lua_thread.cpp b/src/lua/lua_thread.cpp index 4704c3e8..dc588144 100644 --- a/src/lua/lua_thread.cpp +++ b/src/lua/lua_thread.cpp @@ -114,6 +114,15 @@ auto LuaThread::RunScript(const std::string& path) -> bool { return true; } +auto LuaThread::RunString(const std::string& script) -> bool { + int res = luaL_loadstring(state_, script.c_str()); + if (res != LUA_OK) { + return false; + } + CallProtected(state_, 0, 0); + return true; +} + static int msg_handler(lua_State* L) { if (!lua_isstring(L, 1)) { return 1; -- cgit v1.2.3