diff --git a/application/basic_demo/fatfs_image/lua/coroutine_demo.lua b/application/basic_demo/fatfs_image/lua/coroutine_demo.lua deleted file mode 100644 index ec0464f..0000000 --- a/application/basic_demo/fatfs_image/lua/coroutine_demo.lua +++ /dev/null @@ -1,47 +0,0 @@ -local delay = require("delay") - -print("[coroutine_demo] start") - -local co = coroutine.create(function(name) - print("[coroutine_demo] worker enter: " .. tostring(name)) - - for step = 1, 3 do - print(string.format("[coroutine_demo] worker step=%d before yield", step)) - coroutine.yield("yield@" .. tostring(step)) - print(string.format("[coroutine_demo] worker step=%d after resume", step)) - delay.delay_ms(100) - end - - return "done:" .. tostring(name) -end) - -print("[coroutine_demo] initial status: " .. coroutine.status(co)) - -local ok, value = coroutine.resume(co, "demo-task") -print(string.format("[coroutine_demo] resume #1 ok=%s value=%s status=%s", - tostring(ok), tostring(value), coroutine.status(co))) - -ok, value = coroutine.resume(co) -print(string.format("[coroutine_demo] resume #2 ok=%s value=%s status=%s", - tostring(ok), tostring(value), coroutine.status(co))) - -ok, value = coroutine.resume(co) -print(string.format("[coroutine_demo] resume #3 ok=%s value=%s status=%s", - tostring(ok), tostring(value), coroutine.status(co))) - -ok, value = coroutine.resume(co) -print(string.format("[coroutine_demo] resume #4 ok=%s value=%s status=%s", - tostring(ok), tostring(value), coroutine.status(co))) - -local wrapped = coroutine.wrap(function() - for i = 1, 2 do - coroutine.yield("wrap@" .. tostring(i)) - end - return "wrap-done" -end) - -print("[coroutine_demo] wrap call #1: " .. tostring(wrapped())) -print("[coroutine_demo] wrap call #2: " .. tostring(wrapped())) -print("[coroutine_demo] wrap call #3: " .. tostring(wrapped())) - -print("[coroutine_demo] done") diff --git a/application/basic_demo/fatfs_image/lua/display_demo.lua b/application/basic_demo/fatfs_image/lua/display_demo.lua index 786b8da..066d08a 100644 --- a/application/basic_demo/fatfs_image/lua/display_demo.lua +++ b/application/basic_demo/fatfs_image/lua/display_demo.lua @@ -34,9 +34,9 @@ if not panel_handle then return end -local ok, err = pcall(display.create_screen, panel_handle, io_handle, width, height) +local ok, err = pcall(display.init, panel_handle, io_handle, width, height) if not ok then - print("[display_demo] ERROR: create_screen failed: " .. tostring(err)) + print("[display_demo] ERROR: init failed: " .. tostring(err)) return end @@ -45,7 +45,7 @@ local screen_created = true local function cleanup() if screen_created then pcall(display.end_frame) - pcall(display.destroy_screen) + pcall(display.deinit) screen_created = false end end @@ -54,7 +54,7 @@ width = display.width() height = display.height() if width <= 0 or height <= 0 then - print("[display_demo] ERROR: invalid display size after create_screen") + print("[display_demo] ERROR: invalid display size after init") cleanup() return end diff --git a/application/basic_demo/fatfs_image/lua/gc_demo.lua b/application/basic_demo/fatfs_image/lua/gc_demo.lua deleted file mode 100644 index 4da00aa..0000000 --- a/application/basic_demo/fatfs_image/lua/gc_demo.lua +++ /dev/null @@ -1,33 +0,0 @@ -local function kb() - return collectgarbage("count") -end - -local function print_kb(label) - print(string.format("[gc_demo] %s: %.2f KB", label, kb())) -end - -print("[gc_demo] start") -print_kb("initial") - -local blocks = {} -for i = 1, 400 do - local t = {} - for j = 1, 64 do - t[j] = string.format("block=%d item=%d", i, j) - end - blocks[i] = t -end - -print_kb("after allocation") - -blocks = nil -print_kb("after release refs") - -local step_done = collectgarbage("step", 64) -print(string.format("[gc_demo] step result: %s", tostring(step_done))) -print_kb("after one step") - -collectgarbage("collect") -print_kb("after full collect") - -print("[gc_demo] done") diff --git a/application/basic_demo/fatfs_image/lua/gc_userdata_demo.lua b/application/basic_demo/fatfs_image/lua/gc_userdata_demo.lua deleted file mode 100644 index bf68614..0000000 --- a/application/basic_demo/fatfs_image/lua/gc_userdata_demo.lua +++ /dev/null @@ -1,39 +0,0 @@ -local btn = require("button") - -local gpio_num = (args and args.gpio_num) or 0 -local rounds = (args and args.rounds) or 12 - -print(string.format( - "[gc_userdata_demo] start gpio=%d rounds=%d", - gpio_num, - rounds -)) - -local function make_and_drop_button(index) - local handle, err = btn.new(gpio_num, 0) - if not handle then - error(string.format("button.new failed at round %d: %s", index, tostring(err))) - end - - print(string.format("[gc_userdata_demo] round=%d created handle=%s", index, tostring(handle))) - - -- Drop the only Lua reference on purpose. The userdata __gc should release - -- the native button handle so repeated creation does not exhaust BTN_MAX_HANDLES. - handle = nil - collectgarbage("collect") - collectgarbage("collect") -end - -for i = 1, rounds do - make_and_drop_button(i) -end - -local final_handle, final_err = btn.new(gpio_num, 0) -if not final_handle then - error("[gc_userdata_demo] final create failed after GC cycling: " .. tostring(final_err)) -end - -print("[gc_userdata_demo] final create succeeded after repeated GC") -btn.close(final_handle) -collectgarbage("collect") -print("[gc_userdata_demo] done") diff --git a/application/basic_demo/fatfs_image/lua/lcd_touch_paint.lua b/application/basic_demo/fatfs_image/lua/lcd_touch_paint.lua index a20f04d..b243e91 100644 --- a/application/basic_demo/fatfs_image/lua/lcd_touch_paint.lua +++ b/application/basic_demo/fatfs_image/lua/lcd_touch_paint.lua @@ -9,9 +9,9 @@ if not panel_handle then return end -local ok, err = pcall(display.create_screen, panel_handle, io_handle, width, height) +local ok, err = pcall(display.init, panel_handle, io_handle, width, height) if not ok then - print("[lcd_touch_paint] ERROR: create_screen failed: " .. tostring(err)) + print("[lcd_touch_paint] ERROR: init failed: " .. tostring(err)) return end @@ -20,7 +20,7 @@ local screen_created = true local function cleanup() if screen_created then pcall(display.end_frame) - pcall(display.destroy_screen) + pcall(display.deinit) screen_created = false end end @@ -29,7 +29,7 @@ width = display.width() height = display.height() if width <= 0 or height <= 0 then - print("[lcd_touch_paint] ERROR: invalid display size after create_screen") + print("[lcd_touch_paint] ERROR: invalid display size after init") cleanup() return end diff --git a/application/basic_demo/fatfs_image/lua/random_demo_stress.lua b/application/basic_demo/fatfs_image/lua/random_demo_stress.lua index bcf8ace..c460496 100644 --- a/application/basic_demo/fatfs_image/lua/random_demo_stress.lua +++ b/application/basic_demo/fatfs_image/lua/random_demo_stress.lua @@ -2,7 +2,7 @@ local delay = require("delay") local esp_heap = require("esp_heap") local LUA_ROOT = "/fatfs/data/lua" -local caps = esp_heap.caps() +local caps = esp_heap.caps local iterations = (args and args.iterations) or 20 local pause_ms = (args and args.pause_ms) or 200 diff --git a/application/basic_demo/main/basic_demo_cli.c b/application/basic_demo/main/basic_demo_cli.c index 246d773..9fbcf32 100644 --- a/application/basic_demo/main/basic_demo_cli.c +++ b/application/basic_demo/main/basic_demo_cli.c @@ -668,7 +668,7 @@ esp_err_t basic_demo_cli_start(void) ESP_LOGI(TAG, "Starting console REPL"); repl_config.prompt = "basic_demo> "; - repl_config.task_stack_size = 8192; + repl_config.task_stack_size = 4096; repl_config.max_cmdline_length = 512; #if CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM diff --git a/application/basic_demo/main/main.c b/application/basic_demo/main/main.c index a355e7a..0f761b1 100644 --- a/application/basic_demo/main/main.c +++ b/application/basic_demo/main/main.c @@ -97,7 +97,7 @@ static void memory_monitor_task(void *arg) size_t psram_free = heap_caps_get_free_size(MALLOC_CAP_SPIRAM); ESP_LOGI(TAG, "Memory: internal_free=%u bytes, internal_min_free=%u bytes, psram_free=%u bytes", (unsigned)internal_free, (unsigned)internal_min, (unsigned)psram_free); - // print_task_stack_info(); + print_task_stack_info(); } } @@ -131,6 +131,6 @@ void app_main(void) #if BASIC_DEMO_ENABLE_MEM_LOG /* Start memory monitor: print internal free, min free, PSRAM free every 20s */ - xTaskCreate(memory_monitor_task, "mem_mon", 8192, NULL, 1, NULL); + xTaskCreate(memory_monitor_task, "mem_mon", 4096, NULL, 1, NULL); #endif } diff --git a/components/claw_capabilities/cap_time/src/cap_time.c b/components/claw_capabilities/cap_time/src/cap_time.c index 3c77710..9bd1f0a 100644 --- a/components/claw_capabilities/cap_time/src/cap_time.c +++ b/components/claw_capabilities/cap_time/src/cap_time.c @@ -28,7 +28,7 @@ static const char *TAG = "cap_time"; #define CAP_TIME_MIN_VALID_EPOCH 1704067200 #define CAP_TIME_DEFAULT_DISCONNECTED_RETRY_MS 5000 #define CAP_TIME_DEFAULT_SYNC_RETRY_MS 30000 -#define CAP_TIME_SYNC_TASK_STACK_SIZE 6144 +#define CAP_TIME_SYNC_TASK_STACK_SIZE 4096 #define CAP_TIME_SYNC_TASK_PRIORITY 5 static const char *s_month_names[] = { diff --git a/components/lua_modules/lua_module_display/skills/lua_module_display.md b/components/lua_modules/lua_module_display/skills/lua_module_display.md index 3f67c72..edfa076 100644 --- a/components/lua_modules/lua_module_display/skills/lua_module_display.md +++ b/components/lua_modules/lua_module_display/skills/lua_module_display.md @@ -3,7 +3,7 @@ This skill describes how to correctly use `display` when writing Lua scripts. `display` is a low-level drawing module. It can: -- Create and destroy the LCD drawing context +- Initialize and deinitialize the LCD drawing context - Draw text, lines, rectangles, circles, arcs, ellipses, triangles, and round rectangles - Draw raw RGB565 bitmaps - Draw JPEG and PNG images from memory or files @@ -20,10 +20,10 @@ local display = require("display") local panel_handle, io_handle, width, height = board_manager.get_display_lcd_params("display_lcd") -display.create_screen(panel_handle, io_handle, width, height) +display.init(panel_handle, io_handle, width, height) ``` -After `display.create_screen(...)` succeeds: +After `display.init(...)` succeeds: - `display.width()` returns the current screen width - `display.height()` returns the current screen height - Most drawing APIs can be used @@ -32,7 +32,7 @@ When finished: ```lua pcall(display.end_frame) -pcall(display.destroy_screen) +pcall(display.deinit) ``` ## Important rules @@ -47,9 +47,9 @@ pcall(display.destroy_screen) ## Screen lifecycle -### `display.create_screen(panel_handle, io_handle, lcd_width, lcd_height)` +### `display.init(panel_handle, io_handle, lcd_width, lcd_height)` -Creates the drawing context. +Initializes the drawing context. - `panel_handle`: lightuserdata, usually from `board_manager.get_display_lcd_params(...)` - `io_handle`: lightuserdata @@ -58,9 +58,9 @@ Creates the drawing context. - Returns `true` on success - Raises a Lua error on failure -### `display.destroy_screen()` +### `display.deinit()` -Destroys the drawing context. +Deinitializes the drawing context. - Returns `true` on success - Raises a Lua error on failure @@ -390,12 +390,12 @@ Returns: For normal screen rendering: 1. Use `board_manager.get_display_lcd_params("display_lcd")` -2. Call `display.create_screen(...)` +2. Call `display.init(...)` 3. Call `display.begin_frame(...)` 4. Draw text, shapes, or images 5. Call `display.present()` or `display.present_rect(...)` 6. Call `display.end_frame()` -7. Call `display.destroy_screen()` before exit +7. Call `display.deinit()` before exit ## Example @@ -406,7 +406,7 @@ local display = require("display") local panel_handle, io_handle, width, height = bm.get_display_lcd_params("display_lcd") -display.create_screen(panel_handle, io_handle, width, height) +display.init(panel_handle, io_handle, width, height) display.begin_frame({ clear = true, r = 12, g = 18, b = 28 }) @@ -429,5 +429,5 @@ display.draw_text_aligned(0, display.height() - 24, display.width(), 20, "frame display.present() display.end_frame() -display.destroy_screen() +display.deinit() ``` diff --git a/components/lua_modules/lua_module_display/src/display_hal.c b/components/lua_modules/lua_module_display/src/display_hal.c index e841d01..f6936b5 100644 --- a/components/lua_modules/lua_module_display/src/display_hal.c +++ b/components/lua_modules/lua_module_display/src/display_hal.c @@ -57,6 +57,7 @@ typedef struct { static display_hal_state_t s_state; static void display_hal_clear_clip_locked(void); +static esp_err_t display_hal_clear_io_callbacks_locked(void); static bool display_hal_flush_done_isr(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx); @@ -151,6 +152,8 @@ fail: esp_err_t display_hal_destroy(void) { esp_err_t ret = display_hal_lock(); + SemaphoreHandle_t flush_done_to_delete = NULL; + SemaphoreHandle_t lock_to_delete = NULL; if (ret != ESP_OK) { return ret; @@ -164,6 +167,14 @@ esp_err_t display_hal_destroy(void) } } + if (s_state.display_callbacks_registered) { + ret = display_hal_clear_io_callbacks_locked(); + if (ret != ESP_OK) { + display_hal_unlock(); + return ret; + } + } + for (size_t i = 0; i < DISPLAY_HAL_FRAMEBUFFER_COUNT_MAX; ++i) { heap_caps_free(s_state.framebuffers[i]); s_state.framebuffers[i] = NULL; @@ -173,8 +184,12 @@ esp_err_t display_hal_destroy(void) s_state.painter = NULL; } + flush_done_to_delete = s_state.display_flush_done; + lock_to_delete = s_state.lock; + s_state.panel = NULL; s_state.io = NULL; + s_state.display_callbacks_registered = false; s_state.width = 0; s_state.height = 0; s_state.framebuffer_bytes = 0; @@ -190,8 +205,18 @@ esp_err_t display_hal_destroy(void) s_state.clip_y = 0; s_state.clip_width = 0; s_state.clip_height = 0; + s_state.display_flush_done = NULL; + s_state.lock = NULL; - display_hal_unlock(); + if (lock_to_delete) { + xSemaphoreGive(lock_to_delete); + } + if (flush_done_to_delete) { + vSemaphoreDelete(flush_done_to_delete); + } + if (lock_to_delete) { + vSemaphoreDelete(lock_to_delete); + } return ESP_OK; } @@ -204,6 +229,21 @@ static void display_hal_clear_clip_locked(void) s_state.clip_height = s_state.height; } +static esp_err_t display_hal_clear_io_callbacks_locked(void) +{ + const esp_lcd_panel_io_callbacks_t callbacks = {0}; + + if (!s_state.io) { + s_state.display_callbacks_registered = false; + return ESP_OK; + } + + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_register_event_callbacks(s_state.io, &callbacks, NULL), + TAG, "clear flush callback failed"); + s_state.display_callbacks_registered = false; + return ESP_OK; +} + static uint16_t *display_hal_get_draw_framebuffer_locked(void) { if (s_state.framebuffer_count == 0) { diff --git a/components/lua_modules/lua_module_display/src/lua_module_display.c b/components/lua_modules/lua_module_display/src/lua_module_display.c index 58173d1..7236f5b 100644 --- a/components/lua_modules/lua_module_display/src/lua_module_display.c +++ b/components/lua_modules/lua_module_display/src/lua_module_display.c @@ -84,7 +84,7 @@ static void *lua_display_check_lightuserdata_arg(lua_State *L, int index, const * Screen lifecycle * ---------------------------------------------------------------------- */ -static int lua_display_create_screen(lua_State *L) +static int lua_display_init(lua_State *L) { esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)lua_display_check_lightuserdata_arg( @@ -97,19 +97,19 @@ static int lua_display_create_screen(lua_State *L) esp_err_t err = display_hal_create(panel_handle, io_handle, lcd_width, lcd_height); if (err != ESP_OK) { - return luaL_error(L, "display create_screen failed: %s", esp_err_to_name(err)); + return luaL_error(L, "display init failed: %s", esp_err_to_name(err)); } lua_pushboolean(L, 1); return 1; } -static int lua_display_destroy_screen(lua_State *L) +static int lua_display_deinit(lua_State *L) { (void)L; esp_err_t err = display_hal_destroy(); if (err != ESP_OK) { - return luaL_error(L, "display destroy_screen failed: %s", esp_err_to_name(err)); + return luaL_error(L, "display deinit failed: %s", esp_err_to_name(err)); } lua_pushboolean(L, 1); @@ -1184,10 +1184,10 @@ int luaopen_display(lua_State *L) { lua_newtable(L); - lua_pushcfunction(L, lua_display_create_screen); - lua_setfield(L, -2, "create_screen"); - lua_pushcfunction(L, lua_display_destroy_screen); - lua_setfield(L, -2, "destroy_screen"); + lua_pushcfunction(L, lua_display_init); + lua_setfield(L, -2, "init"); + lua_pushcfunction(L, lua_display_deinit); + lua_setfield(L, -2, "deinit"); lua_pushcfunction(L, lua_display_width); lua_setfield(L, -2, "width"); diff --git a/components/lua_modules/lua_module_esp_heap/lua_module_esp_heap.c b/components/lua_modules/lua_module_esp_heap/lua_module_esp_heap.c index af3b39a..434978e 100644 --- a/components/lua_modules/lua_module_esp_heap/lua_module_esp_heap.c +++ b/components/lua_modules/lua_module_esp_heap/lua_module_esp_heap.c @@ -58,13 +58,6 @@ static void lua_module_esp_heap_push_caps_constants(lua_State *L) lua_setfield(L, -2, "RETENTION"); } -static int lua_module_esp_heap_caps(lua_State *L) -{ - lua_newtable(L); - lua_module_esp_heap_push_caps_constants(L); - return 1; -} - static int lua_module_esp_heap_get_info(lua_State *L) { lua_Integer caps_value = luaL_optinteger(L, 1, MALLOC_CAP_DEFAULT); @@ -173,7 +166,6 @@ static int lua_module_esp_heap_get_current_task(lua_State *L) int luaopen_esp_heap(lua_State *L) { static const luaL_Reg funcs[] = { - {"caps", lua_module_esp_heap_caps}, {"get_info", lua_module_esp_heap_get_info}, {"get_task_watermarks", lua_module_esp_heap_get_task_watermarks}, {"get_current_task", lua_module_esp_heap_get_current_task}, @@ -182,6 +174,9 @@ int luaopen_esp_heap(lua_State *L) lua_newtable(L); luaL_setfuncs(L, funcs, 0); + lua_newtable(L); + lua_module_esp_heap_push_caps_constants(L); + lua_setfield(L, -2, "caps"); return 1; } diff --git a/components/lua_modules/lua_module_esp_heap/skills/lua_module_esp_heap.md b/components/lua_modules/lua_module_esp_heap/skills/lua_module_esp_heap.md index 127094a..228f5e8 100644 --- a/components/lua_modules/lua_module_esp_heap/skills/lua_module_esp_heap.md +++ b/components/lua_modules/lua_module_esp_heap/skills/lua_module_esp_heap.md @@ -4,7 +4,7 @@ This skill describes how to correctly use esp_heap when writing Lua scripts. ## How to call - Import it with `local esp_heap = require("esp_heap")` -- Call `local caps = esp_heap.caps()` to get capability flags such as `caps.DEFAULT`, `caps.INTERNAL`, and `caps.SPIRAM` +- Read `local caps = esp_heap.caps` to get capability flags such as `caps.DEFAULT`, `caps.INTERNAL`, and `caps.SPIRAM` - Call `esp_heap.get_info(caps)` to read heap statistics such as `free_size`, `allocated_size`, and `largest_free_block` - Call `esp_heap.get_task_watermarks()` to inspect stack high-water marks for tasks - Call `esp_heap.get_current_task()` to inspect the current task state @@ -12,7 +12,7 @@ This skill describes how to correctly use esp_heap when writing Lua scripts. ## Example ```lua local esp_heap = require("esp_heap") -local caps = esp_heap.caps() +local caps = esp_heap.caps local info = esp_heap.get_info(caps.DEFAULT) print(info.free_size, info.largest_free_block)