Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions ZAPAROO_FORK.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ non-blocking spawn) are intentionally omitted.
| 11 | **In-core "Frontend" OSD entry** | Adds row 31 (`ALT_LAUNCHER_MENUSUB`) to MENU_COMMON1 marked with `reboot_req` when activated | `menu.cpp:2831,2845-2849,3088-3091` |
| 12 | **OSD/F12 overlay over running frontend** | F12 / `KEY_MENU` reaches the OSD even with frontend running; on menu core opens System Settings directly (skip file picker); F1/F9 disabled when frontend active; `vga_nag` suppressed; auto-open suppressed in CRT mode | `menu.cpp:843-852,1289,1304-1311,1334,1583,1604-1611,6727,6739,6816,6901`, `user_io.cpp:4162-4171` |
| 13 | **Trimmed System Settings render** | `alt_launcher_render_system_menu()` overrides MENU_SYSTEM1 body for the alt-launcher path; `alt_launcher_translate_system_select()` maps trimmed menusub indices (Remap, Define joy, Scripts, Zaparoo, Reboot, Exit) to upstream dispatch slots; `-2` enters the Zaparoo page. All three helpers gate on `installed()` and **must agree**, or the render and the dispatch map desync and rows fire the wrong action | `support/zaparoo/alt_launcher_menu.cpp`, `menu.cpp` `MENU_SYSTEM1/2` hooks |
| 14 | **Zaparoo OSD pages** | System Settings → Zaparoo enters `MENU_ZAPAROO_FRONTEND1/2`: rows 0 Frontend on/off, 1 Kiosk mode, 2 Auto-save, blank, 3 CRT mode, 4 Video standard, 5 Screen position, 6 exit (`menumask = crt ? 0x7F : 0x4F`). `menu.cpp` asks `frontend_page_row_has_submenu()` which row Right enters, rather than carrying a row index that moves whenever this page changes. Row 0 reads `alt_launcher_enabled()`, not `configured()`, so it doesn't show Off merely because the user quit the frontend. Row 1 never toggles directly, it enters `MENU_ZAPAROO_KIOSK1/2`, a No/Yes confirmation modelled on `MENU_SCRIPTS_PRE`; confirming closes the OSD itself. Screen position enters `MENU_ZAPAROO_POSITION1/2` (H/V offsets, live adjust). The CRT rows duplicate the frontend's own settings so a user whose frontend cannot display on the CRT can still fix them | `support/zaparoo/launcher_pages.cpp/.h`, `support/zaparoo/crt_settings.cpp/.h`, `menu.cpp` `MENU_ZAPAROO_*` cases (enum members appended at the tail) |
| 14 | **Zaparoo OSD pages** | System Settings → Zaparoo enters `MENU_ZAPAROO_FRONTEND1/2`: rows 0 Frontend on/off, 1 Kiosk mode, 2 Auto-save, 3 Auto-run CDs, blank, 4 CRT mode, 5 Video standard, 6 Screen position, 7 exit (`menumask = crt ? 0xFF : 0x9F`). `menu.cpp` asks `frontend_page_row_has_submenu()` which row Right enters, rather than carrying that row index in its input dispatch. Row 0 reads `alt_launcher_enabled()`, not `configured()`, so it doesn't show Off merely because the user quit the frontend. Row 1 never toggles directly, it enters `MENU_ZAPAROO_KIOSK1/2`, a No/Yes confirmation modelled on `MENU_SCRIPTS_PRE`; confirming closes the OSD itself. Screen position enters `MENU_ZAPAROO_POSITION1/2` (H/V offsets, live adjust). The CRT rows duplicate the frontend's own settings so a user whose frontend cannot display on the CRT can still fix them | `support/zaparoo/launcher_pages.cpp/.h`, `support/zaparoo/crt_settings.cpp/.h`, `menu.cpp` `MENU_ZAPAROO_*` cases (enum members appended at the tail) |
| 15 | **CRT standard / offsets shared with the frontend** | Standard: state-file byte 1 plus `crt_video_standard` in `zaparoo/frontend.toml` `[settings]`; offsets: `crt_h_offset` / `crt_v_offset` in the same section (the frontend treats the file as authoritative). Live adjust rewrites DDR word1 at `0x3A000004`; with no frontend running Main publishes an alignment pattern into DDR slot 0 so centering can be done blind. The toml is edited one line at a time in place (tmp + rename), never rewritten | `support/zaparoo/crt_settings.cpp` (`toml_set`, `crt_offsets_apply_live`, `crt_test_pattern_publish`) |
| 16 | **OSD auto-dismiss on frontend spawn** | `spawn()` calls `MenuHide()` after fork so an OSD still up from CRT toggle / Reboot doesn't trap input once the frontend grabs the input device | `support/zaparoo/alt_launcher.cpp` (end of `spawn`) |
| 17 | **Framebuffer watchdog** | While an HDMI frontend child is alive, `alt_launcher_poll` re-asserts the HPS framebuffer whenever it is found off (throttled to 250 ms). An HDMI hot-plug re-init (`video_reinit` → `video_menu_bg(-1)` → `video_fb_enable(0)`) otherwise leaves the frontend invisible and makes its startup `vmode` probes time out (frontend then renders at native output size) | `support/zaparoo/alt_launcher.cpp` `alt_launcher_poll()` |
Expand All @@ -48,7 +48,7 @@ non-blocking spawn) are intentionally omitted.
| 24 | **Input loop no longer spins on SD activity** | `input_test` drains events until `poll()` idles for 25 ms; the HPS LED's `brightness_hw_changed` attribute (mmc trigger) wakes it at kHz rates during sustained SD-card activity (a media scrape, for example), so the loop never idled and the UI cothread stalled 200–500 ms per pass — dropped OSD keys, laggy menus, delayed launcher polls. An LED-only wakeup now ends the drain | `input.cpp` (`input_test`, 1-line fork edit) |
| 19 | **CI / build infrastructure** | Docker container build; binary named `MiSTer_Zaparoo`; "Z"-suffixed version; release / unstable CI; sync-upstream workflow; deploy script | `docker-build.sh`, `stable-build.sh`, `unstable-build.sh`, `deploy-zaparoo.sh`, `.github/build_*.sh`, `.github/workflows/*.yml` |
| 20 | **`RECENTS` / `LOG_FILE_ENTRY` forced on** | Both are forced in `alt_launcher_cfg_apply()`, not via `cfg.cpp` defaults. `d0357b9` originally used a `min=1` clamp in `ini_vars[]`, which only ever clamped values actually present in the ini, so an absent key still left the flag at 0; `0ebf4b1` then dropped the `LOG_FILE_ENTRY` half entirely while keeping `recents`. Restored as a plain assignment (see row 4) | `support/zaparoo/alt_launcher.cpp` (`alt_launcher_cfg_apply`) |
| 25 | **Fork settings store** | `config/zaparoo_settings.bin`, 16-byte blob read into a zeroed buffer so an absent or short file means today's behavior. Byte 0 = frontend **disabled**, byte 1 = kiosk **enabled**, byte 2 = save on core exit, rest reserved and preserved by the read-modify-write setters. Cached (the predicates run per scheduler tick, per gamepad event and inside the OSD render loop) and keyed on the storage root. Deliberately not `MiSTer.ini`: an unknown key breaks non-fork Mains, upstream appends to `ini_vars[]` most releases, and the stable build excludes `MiSTer.ini` | `support/zaparoo/settings.cpp/.h` |
| 25 | **Fork settings store** | `config/zaparoo_settings.bin`, 16-byte blob read into a zeroed buffer so an absent or short file means today's behavior. Byte 0 = frontend **disabled**, byte 1 = kiosk **enabled**, byte 2 = save on core exit, byte 3 = CD autorun, rest reserved and preserved by the read-modify-write setters. Cached (the predicates run per scheduler tick, per gamepad event and inside the OSD render loop) and keyed on the storage root. Deliberately not `MiSTer.ini`: an unknown key breaks non-fork Mains, upstream appends to `ini_vars[]` most releases, and the stable build excludes `MiSTer.ini` | `support/zaparoo/settings.cpp/.h` |
| 26 | **Kiosk mode** | Total OSD lockout for card-only setups. Gates: `menu.cpp` key decode (covers F1/F7/F9/F10/F11/F12/ESC/Backspace, the front-panel tap and the keyrah Fn combo), the front-panel button block (its 3s hold sets `menustate` directly), the menu-core auto-open, and `SelectINI()` at boot. **The MGL clause in the auto-open condition is deliberately not gated**: it is how a card launches core + ROM, and gating it would load the core but never mount the game. Deliberately does **not** touch the menu background: whatever the user chose via `status[3:1]` (default 0 = the core's own snow, or a wallpaper / test pattern) is what shows. The idle screensaver keeps working to whatever `OSD_TIMEOUT` / `VIDEO_OFF` say: its countdown only runs while `menustate` is the file browser, which kiosk never reaches, so kiosk substitutes `MENU_NONE2` as the idle state, and skips the `OsdMenuCtl(1)` on wake because that would turn the overlay on over stale OSD buffer contents. Recovery is deleting the settings file | `support/zaparoo/kiosk.cpp/.h`, `menu.cpp:626,1341,1640`, `user_io.cpp:1472` |
| 27 | **`zaparoo_` command surface** | `zaparoo_command()` dispatches every `zaparoo_`-prefixed `/dev/MiSTer_cmd` line: `zaparoo_console ...` delegates to `alt_launcher_command()`, plus `zaparoo_kiosk on\|off\|toggle` and `zaparoo_frontend on\|off\|toggle` (both persisted), `zaparoo_osd open\|close\|toggle`, `zaparoo_save [hold_ms]` and `zaparoo_mount <pos> [path]`. The upstream hook stays one line: the existing `zaparoo_console ` prefix test was widened to `zaparoo_`. `zaparoo_osd` is the everyday admin route under kiosk: a **session-only** bypass that lifts the gates without changing the setting, raising the same `menu_key_set(KEY_F12 \| UPSTROKE)` user_io raises for a real F12 so it works on a game core too. It is deliberately not persisted and dies on the next core load, since that re-execs Main. Cards must be set up before kiosk is switched on | `support/zaparoo/command.cpp/.h`, `support/zaparoo/kiosk.cpp`, `input.cpp` (cmd FIFO dispatch) |
| 29 | **How a core is made to save** | **Read this before touching save or the OSD enable path.** Main never initiates a save; the *core's own Verilog* dumps battery RAM over the SD interface, which `user_io_poll` then writes `O_SYNC`. Two triggers exist, and every core that has a save reads them as `bk_save = <explicit bit> | <autosave path>`. **(a) The explicit bit.** Cores expose a menu row labelled "Save Backup RAM", or "Save Memory Cards" on PSX and "Save Memory Card" on NeoGeo. `menu.cpp:2658-2660` fires it with nothing but `user_io_status_set(opt, 1, ex)` then `user_io_status_set(opt, 0, ex)`, so **no OSD is involved and the save can be completely invisible**. Confirmed present in NES, SNES, Game Boy, GBA, MegaDrive, Genesis, MegaCD, N64, PSX, NeoGeo, Saturn, SMS, TurboGrafx16 and WonderSwan. **(b) The `OSD_STATUS` edge**, which is why the F12 trick works. `OsdEnable()` sends one SPI byte the FPGA turns into `OSD_STATUS`; from `sys/osd.v`, `if(!io_din[0]) {osd_status,highres} <= 0; else {osd_status,info} <= {~io_din[2] & ~io_din[3], io_din[2]};` so it rises **only** with bit 0 set and bits 2 and 3 clear. Bit 2 is `OSD_INFO` and bit 3 is `OSD_MSG`, so **`Info()` (0x45) and `InfoMessage()` (0x49) drive it low** and cannot trigger a save. Status and overlay-enable are the same bit, so this path always shows the full panel. `user_io_osd_is_visible()` mirrors it faithfully at every call site except `OsdMenuCtl(1)` | `sys/osd.v` and each core's top-level `.sv`, not here; consumers in `support/zaparoo/save.cpp`, `support/zaparoo/confstr.cpp` |
Expand All @@ -67,6 +67,7 @@ non-blocking spawn) are intentionally omitted.
| 39 | **`app_restart()` copies `exe` before the launcher teardown** | `user_io_init` honours a per-core `main=` (`[RA_*] main=MiSTer_RA`) with `app_restart(path, xml, getFullPath(cfg.main))`, and that pointer aliases file_io's single static `full_path`. `app_restart()` calls `alt_launcher_shutdown()` first, and `kill_stale_frontends()` (`getFullPath(s_launcher_path)`) plus a cold `alt_launcher_installed()` (`FileExists`) rewrite the buffer to `/media/fat/zaparoo/frontend`, so the `execl` re-launched Main **as the frontend binary**: no Main, black screen, `/tmp/CORENAME` stuck at `MENU`. `exe` is now copied to a private buffer before the teardown. Any pointer handed across `alt_launcher_shutdown()` must not alias `full_path` | `fpga_io.cpp` (`app_restart`, 3 lines beside the existing hook) |
| 40 | **Persistent Main log (`main.log`)** | Main's stdout goes to the console after a reboot, so the first-exit-after-boot slowness could not be captured with the `/tmp/mz.log` recipe (row 23). If `/media/fat/zaparoo/main.log` exists, a constructor dup2's it over stdout and stderr before `main()`, writes a start marker (pid, uptime, wall clock) per exec, rotates to `.old` above 8 MB, and starts a detached heartbeat thread that writes `[zt <uptime ms>]` every 250 ms so upstream's untimed lines can be placed against zlog's `t=`. Marker and heartbeat use `dprintf`, not `printf`: the `setvbuf` in `service_boot.cpp` may not have run yet and is only valid before the stream's first use. Touch the file to enable, delete it to disable; absent file, nothing runs | `support/zaparoo/main_log.cpp` (zero upstream hooks) |
| 41 | **Late-appearing display keeps the frontend on the fallback video mode** | `read_edid()` bails silently when the ADV7513 does not sense HPD + monitor sense, so a TV powering up alongside the DE10 leaves `video_init()` on the built-in default (1280x720) and the frontend probes its render size against that: full-res instead of half. The MENU core exposes no HDMI interrupt pin, so upstream's `video_poll()` hot-plug re-init never runs and the wrong mode sticks until the next core load (observed: 34 minutes). The single 500 ms pre-spawn retry now polls out a 3 s hold window, and if the spawn still happens on the fallback mode the launcher watches the transmitter's sense bits for 30 s behind the running child and restarts it once the display answers. `video_reinit()` is spent only on a link down->up edge and at most 3 times per init, so a display that genuinely has no EDID is not flickered. Sense bits are read through a private `i2c_open(0x39)` handle, as `hdmi_cec.cpp` already does for the same chip | `support/zaparoo/alt_launcher.cpp` (zero upstream hooks) |
| 42 | **Physical CD autorun** | Opt-in OSD setting (settings byte 3, off by default). While the menu core is active, a detached worker probes `/dev/sr0` through `/dev/sr7`, reads the TOC and only the sectors needed to identify the disc, then returns a type and TOC fingerprint to the scheduler. Launch resolution has no extra config file: it probes known physical-CD provider binaries and uses each provider's MGL in its original directory (`MiSTer_Physical-CD` + `_Physical Disc Cores`, or `MiSTer-disc` + `_Disc_Cores`), preserving `same_dir="1"` behavior. Audio and unknown discs are ignored. Detection stops outside the menu core, and the handled fingerprint prevents the same inserted disc relaunching after a return to menu until removal is observed. No physical-disc playback or per-core support is included | `support/zaparoo/physical_cd_autorun.cpp/.h`, `support/zaparoo/settings.cpp/.h`, `support/zaparoo/launcher_pages.cpp/.h`, `scheduler.cpp` |
| 28 | **Early service start** | A `__attribute__((constructor))` runs `/media/fat/Scripts/zaparoo.sh -service start` before `main()`, so ahead of the core-1 affinity pin (a child would inherit it) and ahead of `FindStorage()`'s 30s USB wait. Double fork + `setsid()` and **no** `PR_SET_PDEATHSIG`, the inverse of `exec_launcher_child`: the service must survive the `app_restart()` re-exec every core load performs. No marker file, the script is an ensure | `support/zaparoo/service_boot.cpp` (zero upstream hooks) |

---
Expand Down
2 changes: 1 addition & 1 deletion menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7437,7 +7437,7 @@ void HandleUI(void)
{
position_page_leave();
menustate = MENU_ZAPAROO_FRONTEND1;
menusub = 5;
menusub = 6;
break;
}
if (left || right || plus || minus)
Expand Down
2 changes: 2 additions & 0 deletions scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "profiling.h"
#include "video.h"
#include "support/zaparoo/alt_launcher.h"
#include "support/zaparoo/physical_cd_autorun.h"

static cothread_t co_scheduler = nullptr;
static cothread_t co_poll = nullptr;
Expand Down Expand Up @@ -38,6 +39,7 @@ static void scheduler_co_poll(void)
input_poll(0);
alt_launcher_poll();
zaparoo_poll();
physical_cd_autorun_poll();
video_poll();
}

Expand Down
21 changes: 13 additions & 8 deletions support/zaparoo/launcher_pages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ void frontend_page_render(int menusub, uint64_t *menumask)
OsdSetSize(16);
OsdSetTitle("Zaparoo", OSD_ARROW_LEFT);
bool crt = alt_launcher_native_crt_persisted();
*menumask = crt ? 0x7F : 0x4F;
*menumask = crt ? 0xFF : 0x9F;

char s[64];
int m = 0;
Expand All @@ -30,22 +30,24 @@ void frontend_page_render(int menusub, uint64_t *menumask)
OsdWrite(m++, s, menusub == 1);
sprintf(s, " Auto-save: %s", zaparoo_settings_save_on_exit() ? " On" : "Off");
OsdWrite(m++, s, menusub == 2);
sprintf(s, " Auto-run CDs: %s", zaparoo_settings_cd_autorun() ? " On" : "Off");
OsdWrite(m++, s, menusub == 3);
OsdWrite(m++, "");
sprintf(s, " CRT mode: %s", crt ? " On" : "Off");
OsdWrite(m++, s, menusub == 3);
OsdWrite(m++, s, menusub == 4);
if (crt)
{
sprintf(s, " Video standard: %4s", crt_standard_name(alt_launcher_native_crt_mode()));
OsdWrite(m++, s, menusub == 4);
OsdWrite(m++, " Screen position \x16", menusub == 5);
OsdWrite(m++, s, menusub == 5);
OsdWrite(m++, " Screen position \x16", menusub == 6);
}
while (m < OsdGetSize() - 1) OsdWrite(m++, "");
OsdWrite(15, PAGE_STD_EXIT, menusub == 6);
OsdWrite(15, PAGE_STD_EXIT, menusub == 7);
}

bool frontend_page_row_has_submenu(int menusub)
{
return menusub == 5;
return menusub == 6;
}

int frontend_page_select(int menusub)
Expand Down Expand Up @@ -74,12 +76,15 @@ int frontend_page_select(int menusub)
}
return 4;
case 3:
alt_launcher_toggle_native_crt();
zaparoo_settings_set_cd_autorun(!zaparoo_settings_cd_autorun());
return 0;
case 4:
alt_launcher_set_native_crt_mode(crt_standard_next(alt_launcher_native_crt_mode()));
alt_launcher_toggle_native_crt();
return 0;
case 5:
alt_launcher_set_native_crt_mode(crt_standard_next(alt_launcher_native_crt_mode()));
return 0;
case 6:
return 1;
default:
return 2;
Expand Down
5 changes: 3 additions & 2 deletions support/zaparoo/launcher_pages.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
// the kiosk confirmation. Renderers write the OSD directly (the pages fit in
// 16 rows); menu.cpp owns the state machine.

// Rows: 0 Frontend, 1 Kiosk mode, 2 Auto-save, 3 CRT mode,
// 4 Video standard (CRT on), 5 Screen position (CRT on), 6 exit.
// Rows: 0 Frontend, 1 Kiosk mode, 2 Auto-save, 3 Auto-run CDs,
// 4 CRT mode, 5 Video standard (CRT on), 6 Screen position (CRT on),
// 7 exit.
void frontend_page_render(int menusub, uint64_t *menumask);
// Select on the highlighted row: 0 redraw, 1 enter Position, 2 leave the page,
// 3 enter the kiosk confirmation, 4 enter the auto-save confirmation.
Expand Down
Loading