diff --git a/docs/RUNTIME_DISC_MENU.md b/docs/RUNTIME_DISC_MENU.md index e3f720af..aff2c83b 100644 --- a/docs/RUNTIME_DISC_MENU.md +++ b/docs/RUNTIME_DISC_MENU.md @@ -61,3 +61,7 @@ not trigger a change. Providers clear when the mod session resets or activates. `disc_tray_log` reads the always-on ring, including `origin: auto` events. Tracked by `beads-eio.3.342`. + +Automatic request suppression is session-local. The host calls +`psx_disc_tray_reset_session()` before each boot, including a soft restart; the +process-lifetime tray event ring remains available for diagnosis. diff --git a/runtime/include/psx_disc_tray.h b/runtime/include/psx_disc_tray.h index 1522bc12..08a33324 100644 --- a/runtime/include/psx_disc_tray.h +++ b/runtime/include/psx_disc_tray.h @@ -61,6 +61,9 @@ int psx_disc_tray_cycle(int disc_1based, int origin); * may change without rearming it. Returns -1 when no attempt was made, else * PsxDiscTrayResult. Same mounted disc never cycles automatically. */ int psx_disc_tray_auto_poll(int requested, int ready); +/* Begin a new emulation session. Clear request suppression, preserving the + * process-lifetime diagnostic ring. Call with emulation stopped. */ +void psx_disc_tray_reset_session(void); /* Host notification after a successful DISC CHANGE (not after a same-media * reinsert). path is the roster entry now mounted. Called on the emu thread, diff --git a/runtime/src/main.cpp b/runtime/src/main.cpp index fc47ad49..919e75dd 100644 --- a/runtime/src/main.cpp +++ b/runtime/src/main.cpp @@ -19154,6 +19154,7 @@ session_reboot: } disc_menu_session = { &selected_disc_index, &disc_path_str, &resolved_disc, exe_dir_from_argv(argv[0]) / "settings.toml" }; + psx_disc_tray_reset_session(); psx_disc_tray_set_host_hook([](void *ctx, int disc, const char *path) { auto &session = *static_cast(ctx); *session.selected = disc; diff --git a/runtime/src/psx_disc_tray.c b/runtime/src/psx_disc_tray.c index 6f06f393..b155004f 100644 --- a/runtime/src/psx_disc_tray.c +++ b/runtime/src/psx_disc_tray.c @@ -17,6 +17,12 @@ static PsxDiscTrayHostHook s_hook; static void *s_hook_ctx; +static int s_episode_disc, s_attempted; + +void psx_disc_tray_reset_session(void) +{ + s_episode_disc = s_attempted = 0; +} static PsxDiscTrayEvent s_log[PSX_DISC_TRAY_LOG_CAP]; static uint64_t s_log_total; @@ -108,14 +114,13 @@ int psx_disc_tray_cycle(int disc_1based, int origin) int psx_disc_tray_auto_poll(int requested, int ready) { - static int episode_disc, attempted; - if (requested != episode_disc) { - episode_disc = requested; - attempted = 0; + if (requested != s_episode_disc) { + s_episode_disc = requested; + s_attempted = 0; } - if (requested <= 0 || !ready || attempted) return -1; + if (requested <= 0 || !ready || s_attempted) return -1; if (requested == psx_disc_tray_mounted_disc()) return -1; - attempted = 1; + s_attempted = 1; return psx_disc_tray_cycle(requested, PSX_DISC_TRAY_ORIGIN_AUTO); } diff --git a/runtime/tests/test_runtime_disc_menu.c b/runtime/tests/test_runtime_disc_menu.c index 6d405beb..4b042368 100644 --- a/runtime/tests/test_runtime_disc_menu.c +++ b/runtime/tests/test_runtime_disc_menu.c @@ -76,6 +76,17 @@ int main(void) { online = 0; psx_disc_tray_auto_poll(0, 0); assert(psx_disc_tray_auto_poll(1, 1) == PSX_DISC_TRAY_OK && mounted == 1); + /* A failed request stays suppressed within a session, but the same + * request must be attempted after a soft session restart. */ + psx_disc_tray_auto_poll(0, 0); + missing = 1; + assert(psx_disc_tray_auto_poll(2, 1) == PSX_DISC_TRAY_ERR_OPEN_FAILED); + before = opens; + missing = 0; + assert(psx_disc_tray_auto_poll(2, 1) == -1 && opens == before); + psx_disc_tray_reset_session(); + assert(psx_disc_tray_auto_poll(2, 1) == PSX_DISC_TRAY_OK); + assert(opens == before + 1 && mounted == 2); /* Always-on ring wraps and retains the latest result in sequence order. */ for (int i = 0; i < 40; ++i) psx_disc_tray_cycle(5, PSX_DISC_TRAY_ORIGIN_DEBUG_SELECT); const PsxDiscTrayEvent *events;