[bugfix] lua ipod mini gen 2 can't quit scripts while under load

I rewrote some of the problematic scripts to use an event loop which
fixed most of the issues but it turns out the underlying issue is
that when the device is under load the timeout that detects a repeat press
makes the key a repeat press and we miss the initial press completely
due to being under load and under the gun

Adds entries for PLA_EXIT and PLA_CANCEL with a Repeat press

Change-Id: I8247b0ebd37fc58608f6be126c49e56f8375e9cf
This commit is contained in:
William Wilgus 2026-07-05 14:32:30 -04:00
parent ebf42dae68
commit 40b9d09022
4 changed files with 172 additions and 89 deletions

View file

@ -323,7 +323,9 @@ const struct button_mapping pla_main_ctx[] =
|| (CONFIG_KEYPAD == IPOD_3G_PAD) \ || (CONFIG_KEYPAD == IPOD_3G_PAD) \
|| (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD)
{PLA_CANCEL, BUTTON_MENU|BUTTON_SELECT, BUTTON_NONE }, {PLA_CANCEL, BUTTON_MENU|BUTTON_SELECT, BUTTON_NONE },
{PLA_CANCEL, BUTTON_MENU|BUTTON_SELECT|BUTTON_REPEAT, BUTTON_NONE },
{PLA_EXIT, BUTTON_PLAY|BUTTON_SELECT, BUTTON_NONE }, {PLA_EXIT, BUTTON_PLAY|BUTTON_SELECT, BUTTON_NONE },
{PLA_EXIT, BUTTON_PLAY|BUTTON_SELECT|BUTTON_REPEAT, BUTTON_NONE },
{PLA_SELECT, BUTTON_SELECT, BUTTON_NONE }, {PLA_SELECT, BUTTON_SELECT, BUTTON_NONE },
{PLA_SELECT_REL, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT }, {PLA_SELECT_REL, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT },
{PLA_SELECT_REPEAT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_NONE }, {PLA_SELECT_REPEAT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_NONE },

View file

@ -16,28 +16,58 @@
]]-- ]]--
local a = {} local a = {}
local b = {}
loops = 1 --global loops = 1 --global
local last_btn = 1
local ret = ""
local status = true
local depth = rb.LCD_DEPTH
if depth < 8 then depth = 8 end
local used, allocd, free = rb.mem_stats()
local alloc_sz = (free / (depth / 8)) / 1024
local function alloc_tables(loops) local function alloc_tables(loops)
for i=1,loops do a[i] = {{}}; local b = {} end for i=1,loops do a[i] = {{tostring(loops * i) .. " mem test"}}; b[i] = {} end
return true b[1] = rb.new_image(loops, alloc_sz);
end
local function alloc_tables_sm(loops)
for i=1,loops do b[i] = {{}}; end
local btn = rb.button_get(false)
if (btn ~= 0) then
if last_btn ~= btn then
last_btn = btn
return false;
end
while rb.button_get(false) ~= 0
do
end
ret = "User Abort"
status = false
return true
end
return false
end end
local ret
local status = true
rb.lcd_putsxy(0, 0, "memchk loops : ") rb.lcd_putsxy(0, 0, "memchk loops : ")
while (status and loops < 1000) while (status and loops < 1000)
do do
rb.lcd_putsxy(0, 20, loops) rb.lcd_putsxy(0, 20, loops)
rb.lcd_update() rb.lcd_update()
alloc_tables(loops)
if alloc_tables_sm(loops) then break end
-- do call protected to catch OOM condition -- do call protected to catch OOM condition
status, ret = pcall(alloc_tables, loops * 1000) status, ret = pcall(alloc_tables, loops * 1000)
loops = loops + 1 loops = loops + 1
_G.loops = loops _G.loops = loops
rb.yield()
end end
local used, allocd, free = rb.mem_stats() used, allocd, free = rb.mem_stats()
local lu = collectgarbage("count") local lu = collectgarbage("count")
local fmt = function(t, v) return string.format("%s: %d Kb\n", t, v /1024) end local fmt = function(t, v) return string.format("%s: %d Kb\n", t, v /1024) end
@ -47,10 +77,18 @@ s_t[1] = "rockbox:\n"
s_t[2] = "Loops : " s_t[2] = "Loops : "
s_t[3] = loops - 1 s_t[3] = loops - 1
s_t[4] = "\n" s_t[4] = "\n"
s_t[5] = fmt("Used ", used) if not status == true then
s_t[6] = fmt("Allocd ", allocd) s_t[5] = ret
s_t[7] = fmt("Free ", free)
s_t[8] = "\nlua:\n" else
s_t[9] = fmt("Used", lu * 1024) s_t[4] = ""
s_t[10] = "\n\nNote that the rockbox used count is a high watermark\n" s_t[5] = ""
end
s_t[6] = "\n"
s_t[7] = fmt("Used ", used)
s_t[8] = fmt("Allocd ", allocd)
s_t[9] = fmt("Free ", free)
s_t[10] = "\nlua:\n"
s_t[11] = fmt("Used", lu * 1024)
s_t[12] = "\n\nNote that the rockbox used count is a high watermark\n"
rb.splash_scroller(10 * rb.HZ, table.concat(s_t)) rb.splash_scroller(10 * rb.HZ, table.concat(s_t))

View file

@ -273,7 +273,7 @@ local function Rot(t_pts, rot)
local nw = max_x local nw = max_x
local nh = max_y local nh = max_y
rot = rot % 7 --rot = rot % 7
if rot == 0 then if rot == 0 then
return t_pts return t_pts
end end
@ -326,96 +326,118 @@ local function Rot(t_pts, rot)
return rot_memoized[rot][pts] return rot_memoized[rot][pts]
end end
local count = -1
local function rb_logo_rot(x, y, sx, sy, rot) local function rb_logo_rot(x, y, sx, sy, rot)
local polygon local rot_m = rot % 7
local rot_next = rot + 1
if count >= 0 then local polygon = _poly.polygon
polygon = _poly.polygon _lcd:clear(BLACK)
_lcd:clear(BLACK) _poly.polyline(_LCD, x, y, Rot(cross_left_pts, rot_m), WHITE, false, true, sx, sy)
_poly.polyline(_LCD, x, y, Rot(cross_left_pts, rot), WHITE, false, true, sx, sy) _poly.polyline(_LCD, x, y, Rot(R_shadow_pts, rot_m), WHITE, false, true, sx, sy)
_poly.polyline(_LCD, x, y, Rot(R_shadow_pts, rot), WHITE, false, true, sx, sy)
else
polygon = function() end
end
repeat repeat
polygon(_LCD, x, y, Rot(R_outline_pts, rot), BLACK, YELLOW, true, sx, sy) polygon(_LCD, x, y, Rot(R_outline_pts, rot_m), BLACK, YELLOW, true, sx, sy)
polygon(_LCD, x, y, Rot(R_center_pts, rot), BLACK, BLACK, true, sx, sy) polygon(_LCD, x, y, Rot(R_center_pts, rot_m), BLACK, BLACK, true, sx, sy)
polygon(_LCD, x, y, Rot(b_outline_pts, rot), BLACK, GREY, true, sx, sy) polygon(_LCD, x, y, Rot(b_outline_pts, rot_m), BLACK, GREY, true, sx, sy)
polygon(_LCD, x, y, Rot(b_center_pts, rot), BLACK, BLACK, true, sx, sy) polygon(_LCD, x, y, Rot(b_center_pts, rot_m), BLACK, BLACK, true, sx, sy)
polygon(_LCD, x, y, Rot(clef_pts, rot), WHITE, WHITE, true, sx, sy) polygon(_LCD, x, y, Rot(clef_pts, rot_m), WHITE, WHITE, true, sx, sy)
polygon(_LCD, x, y, Rot(clef_void_1_pts, rot), WHITE, BLACK, true, sx, sy) polygon(_LCD, x, y, Rot(clef_void_1_pts, rot_m), WHITE, BLACK, true, sx, sy)
polygon(_LCD, x, y, Rot(clef_void_2_pts, rot), WHITE, YELLOW, true, sx, sy) polygon(_LCD, x, y, Rot(clef_void_2_pts, rot_m), WHITE, YELLOW, true, sx, sy)
polygon(_LCD, x, y, Rot(clef_void_3_pts, rot), WHITE, YELLOW, true, sx, sy) polygon(_LCD, x, y, Rot(clef_void_3_pts, rot_m), WHITE, YELLOW, true, sx, sy)
polygon = function() end -- don't draw but memoize the next point
rot = rot + 1 rot = rot + 1
until count >= 0 or rot >= 6; rot_m = rot % 7
until rot > rot_next;
end end
-- we want the size of everything @ 1:1 scale so we can use that to flip/rotate the figure
rb_logo_sz(0, 0)
local action local action
local redraw = true; local redraw = true;
local rot = 0 local rot = 0
local sx = -2 local sx = -2
local sy = -2 local sy = -2
local max_sx = (rb.LCD_WIDTH / max_x) * 3
local max_sy = (rb.LCD_HEIGHT / max_y) * 3
-- we want the size of everything @ 1:1 scale so we can use that to flip/rotate the figure
rb_logo_sz(0, 0)
while true do do
local act = rb.actions
local quit = false
if redraw then function action_event(action)
rb_logo_rot(0,0, sx, sy, rot) local event
_lcd:update()
if count > 0 then if action == actions.CANCEL or action == actions.EXIT then
redraw = false quit = true
end
if action == 0 then --timer timeout
rot = rot + 1
redraw = true
local prot = (rot) % 7 local prot = (rot) % 7
if prot > 0 then if prot > 0 then -- erase the previous rot
prot = prot - 1 prot = prot - 1
if prot == 0 then prot = 6 end if prot == 0 then prot = 6 end
rot_memoized[tostring(prot)] = nil rot_memoized[tostring(prot)] = nil
end end
end end
end
action = rb.get_plugin_action(rb.HZ/2, 1) if redraw then
if action == actions.CANCEL or action == actions.EXIT then --do nothing till redrawn
break elseif action == actions.LEFT then
end sx = sx - 1
elseif action == actions.LEFTR then
redraw = redraw or (action ~= actions.NONE) sx = sx - 1
sy = sy - 1
if action == actions.LEFT then elseif action == actions.RIGHT then
sx = sx - 1 sx = sx + 1
elseif action == actions.LEFTR then elseif action == actions.RIGHTR then
sx = sx - 1 sx = sx + 1
sy = sy - 1 sy = sy + 1
elseif action == actions.RIGHT then elseif action == actions.UP then
sx = sx + 1 sy = sy - 1
elseif action == actions.RIGHTR then elseif action == actions.UPR then
sx = sx + 1 sy = sy - 1
sy = sy + 1 sx = sy
elseif action == actions.UP then elseif action == actions.DOWN then
sy = sy - 1 sy = sy + 1
elseif action == actions.UPR then elseif action == actions.DOWNR then
sy = sy - 1 sy = sy + 1
sx = sy sx = sy
elseif action == actions.DOWN then elseif action == actions.SELR then
sy = sy + 1 rot = rot + 1
elseif action == actions.DOWNR then count = 0;
sy = sy + 1 redraw = true
sx = sy else
elseif action == actions.SELR then return
rot = rot + 1 end
count = 0; if sx > max_sx then sx = max_sx end
if sy > max_sy then sy = max_sy end
redraw = true redraw = true
elseif count > 5 then
count = 0;
rot = rot + 1
redraw = true
else
count = count + 1
end end
function action_set_quit(bQuit)
quit = bQuit
end
function action_quit()
return quit
end
end
local eva = rockev.register("action", action_event)
local evt = rockev.register("timer", action_event, rb.HZ * 5)
--[[ Main loop ]]
while not action_quit() do
if redraw then
rb_logo_rot(0,0, sx, sy, rot)
_lcd:update()
redraw = false
end
rb.yield()
end --wend end --wend
local used, allocd, free = rb.mem_stats() local used, allocd, free = rb.mem_stats()

View file

@ -75,6 +75,7 @@ local BLUE = _clr.set(WHITE, 0, 0, 255)
------------------------------------------- -------------------------------------------
local clrs local clrs
local CANCEL_BUTTON = rb.actions.PLA_CANCEL local CANCEL_BUTTON = rb.actions.PLA_CANCEL
local EXIT_BUTTON = rb.actions.PLA_EXIT
local LCD_DEPTH = rb.LCD_DEPTH local LCD_DEPTH = rb.LCD_DEPTH
-- EXAMPLES ---------------------------------------------------------------------- EXAMPLES--------------------------------------------------------------------- -- EXAMPLES ---------------------------------------------------------------------- EXAMPLES---------------------------------------------------------------------
function my_blit(dst_val, dx, dy, src_val, sx, sy) function my_blit(dst_val, dx, dy, src_val, sx, sy)
@ -235,8 +236,9 @@ function bounce_image(img)
_img.resize(img_sqy, img) _img.resize(img_sqy, img)
_img.resize(img_sqx, img) _img.resize(img_sqx, img)
-- moves definition of CANCEL_BUTTON from global to local -- moves definition of CANCEL_BUTTON / EXIT_BUTTON from global to local
local CANCEL_BUTTON = CANCEL_BUTTON local CANCEL_BUTTON = CANCEL_BUTTON
local EXIT_BUTTON = EXIT_BUTTON
-------------------------------------------------------- --------------------------------------------------------
local imgn = img local imgn = img
local hold = 0 local hold = 0
@ -347,7 +349,8 @@ function bounce_image(img)
end end
-- 0 = timeout immediately -- 0 = timeout immediately
-- ( -1 would be never timeout, and >0 is amount of 'ticks' before timeout) -- ( -1 would be never timeout, and >0 is amount of 'ticks' before timeout)
if rb.get_plugin_action(wait) == CANCEL_BUTTON then local btn = rb.get_plugin_action(wait)
if btn == CANCEL_BUTTON or btn == EXIT_BUTTON then
break; break;
end end
end end
@ -444,6 +447,10 @@ function twist(img)
-- calculated position of each point in the sine wave(s) -- calculated position of each point in the sine wave(s)
local xs, xe local xs, xe
-- moves definition of CANCEL_BUTTON / EXIT_BUTTON from global to local
local CANCEL_BUTTON = CANCEL_BUTTON
local EXIT_BUTTON = EXIT_BUTTON
--[[--Profiling code --[[--Profiling code
local timer = _timer.start()]] local timer = _timer.start()]]
@ -527,8 +534,8 @@ function twist(img)
_lcd:update() _lcd:update()
z = z + zi z = z + zi
local btn = rb.get_plugin_action(0)
if rb.get_plugin_action(0) == CANCEL_BUTTON then if btn == CANCEL_BUTTON or btn == EXIT_BUTTON then
break break
end end
collectgarbage("step") collectgarbage("step")
@ -556,7 +563,8 @@ function draw_target(img)
end end
_lcd:update() _lcd:update()
if rb.get_plugin_action( 20) == CANCEL_BUTTON then local btn = rb.get_plugin_action(rb.HZ / 5)
if btn == CANCEL_BUTTON or btn == EXIT_BUTTON then
z = 16; z = 16;
break; break;
end end
@ -596,7 +604,8 @@ function draw_sweep(img, cx, cy, radius, color)
elseif wait < 50 then elseif wait < 50 then
wait = 50 - wait wait = 50 - wait
end end
if rb.get_plugin_action( wait) == CANCEL_BUTTON then local btn = rb.get_plugin_action(wait)
if btn == CANCEL_BUTTON or btn == EXIT_BUTTON then
break break
end end
end end
@ -622,6 +631,10 @@ function rotate_image(img)
screen_img :copy(_LCD, 1, 1, xr, yr, w, h) screen_img :copy(_LCD, 1, 1, xr, yr, w, h)
--_print.f("CW") --_print.f("CW")
-- moves definition of CANCEL_BUTTON / EXIT_BUTTON from global to local
local CANCEL_BUTTON = CANCEL_BUTTON
local EXIT_BUTTON = EXIT_BUTTON
--[[--Profiling code --[[--Profiling code
local timer = _timer.start()]] local timer = _timer.start()]]
@ -660,7 +673,8 @@ function rotate_image(img)
end end
d = d + i d = d + i
if rb.get_plugin_action(0) == CANCEL_BUTTON then local btn = rb.get_plugin_action(0)
if btn == CANCEL_BUTTON or btn == EXIT_BUTTON then
break; break;
end end
end end
@ -686,6 +700,10 @@ function flip_image(img)
screen_img =_img.new(w, h) screen_img =_img.new(w, h)
screen_img :copy(_LCD, 1, 1, x, y, w, h) screen_img :copy(_LCD, 1, 1, x, y, w, h)
-- moves definition of CANCEL_BUTTON / EXIT_BUTTON from global to local
local CANCEL_BUTTON = CANCEL_BUTTON
local EXIT_BUTTON = EXIT_BUTTON
--[[--Profiling code --[[--Profiling code
local timer = _timer.start()]] local timer = _timer.start()]]
@ -707,7 +725,8 @@ function flip_image(img)
d = d + i d = d + i
if rb.get_plugin_action(rb.HZ) == CANCEL_BUTTON then local btn = rb.get_plugin_action(rb.HZ)
if btn == CANCEL_BUTTON or btn == EXIT_BUTTON then
break; break;
end end
end end
@ -733,7 +752,8 @@ function blit_mask(dst)
dst:copy(bmask, 1, 1, 1, 1, nil, nil, false, _blit.BSAND, color) dst:copy(bmask, 1, 1, 1, 1, nil, nil, false, _blit.BSAND, color)
_lcd:update() _lcd:update()
if rb.get_plugin_action(0) == CANCEL_BUTTON then local btn = rb.get_plugin_action(0)
if btn == CANCEL_BUTTON or btn == EXIT_BUTTON then
break break
end end
end end
@ -823,7 +843,8 @@ function long_text()
_lcd:copy(img, 1, _lcd.H - h, w - p, 1) _lcd:copy(img, 1, _lcd.H - h, w - p, 1)
_lcd:update() _lcd:update()
if p == 0 or w - p == 1 then wait = 100; rb.sleep(50) end if p == 0 or w - p == 1 then wait = 100; rb.sleep(50) end
if rb.get_plugin_action(wait) == CANCEL_BUTTON then local btn = rb.get_plugin_action(wait)
if btn == CANCEL_BUTTON or btn == EXIT_BUTTON then
break break
end end
end end