Skip to content

Commit 5bc1704

Browse files
authored
feat(zaparoo): OSD menu entry to toggle CRT/HDMI launcher mode
2 parents 240095c + 3eeb116 commit 5bc1704

17 files changed

Lines changed: 849 additions & 43 deletions

ZAPAROO_FORK.md

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# Zaparoo Fork — Change Map and Cleanup Backlog
2+
3+
This document maps the Zaparoo-specific changes layered on top of MiSTer-devel
4+
`Main_MiSTer`. It is meant to evolve as the fork iterates, so future
5+
contributors don't have to re-derive the architecture from `git log`.
6+
7+
**Scope:** commits authored by `wizzomafizzo` (Callan Barrett) and `asturur`
8+
(Andrea Bogazzi) between commit `a2eb35e` and the tip of
9+
`feat/zaparoo-fb-toggle`. Upstream merges, upstream-author changes, and
10+
fully-reverted experiments (F2 toggle, picker/notice commands, perf tweak,
11+
non-blocking spawn) are intentionally omitted.
12+
13+
> **Living doc:** when you add a Zaparoo-specific behavior, append a row to
14+
> the table below or revise the inconsistencies section. Stale entries are
15+
> worse than no entries — please prune as you cleanup.
16+
17+
---
18+
19+
## 1. Change map
20+
21+
| # | Cluster | Purpose | Where it lives |
22+
|---|---------|---------|----------------|
23+
| 1 | **External launcher process management** | Spawn `zaparoo/launcher` via `agetty` on tty2; SIGTERM/SIGKILL on shutdown; bounded `waitpid`; respawn timer; 3-strike crash give-up | `support/zaparoo/alt_launcher.cpp` (`spawn`, `kill_launcher`, `alt_launcher_poll`, `return_to_normal_mode`) |
24+
| 2 | **Process discovery & gating** | `alt_launcher_configured()` = file exists at `zaparoo/launcher` (cached, with sticky escape bit); `alt_launcher_active()` = process running | `support/zaparoo/alt_launcher.cpp:34-43,329-332` |
25+
| 3 | **Custom menu RBF discovery** | `menu_rbf_name()` / `is_menu_rbf()` so a Zaparoo build can ship its own renamed menu RBF and the file_io / fpga_io / user_io paths still recognize it | `support/zaparoo/menu_rbf.cpp/.h`; consumers in `file_io.cpp`, `fpga_io.cpp`, `user_io.cpp` |
26+
| 4 | **Forced cfg overrides** | `alt_launcher_cfg_apply()` forces `cfg.fb_terminal = 1; cfg.recents = 1` after INI parse. Original `ALT_LAUNCHER` / `MENU_RBF` INI knobs were dropped in favor of file-existence detection | `cfg.cpp:614`, `support/zaparoo/alt_launcher.cpp:24-30` |
27+
| 5 | **Polling integration** | `alt_launcher_poll()` driven by main scheduler tick | `scheduler.cpp:36`, `support/zaparoo/alt_launcher.cpp:365` |
28+
| 6 | **TTY / framebuffer hygiene** | Clear/reset tty2 around launcher lifecycle; toggle `video_fb_enable` and `video_chvt` only on respawn paths; don't touch them on plain shutdown | `support/zaparoo/alt_launcher.cpp` (`clear_launcher_tty`, `reset_launcher_tty`) |
29+
| 7 | **Joypad routing into launcher** | `alt_launcher_fb_terminal_key()` translates `JOY_L2/R2/OSD` to `KEY_F1/BACKSPACE/MENU`; `joy_digital()` short-circuits to `uinp_send_key` when launcher active | `input.cpp:2475-2484`, `support/zaparoo/alt_launcher.cpp:45-62` |
30+
| 8 | **Native CRT rendering path** | Launcher running in CRT mode: kernel framebuffer at 320×240 RGBA8888, FPGA scans separate region at `0x3A000000`, `status[9]=1` gates it; pre-spawn blank wipes the prior frame | `support/zaparoo/alt_launcher.cpp` (`enable_native_crt_path`, `disable_native_crt_path`, `blank_native_crt_fb`); paired with `Menu_MiSTer/rtl/native_video_*.sv` |
31+
| 9 | **CRT mode persistence** | 1-byte `zaparoo_launcher_crt.bin` via `FileSaveConfig` / `FileLoadConfig`; loaded at menu init, applied on spawn | `support/zaparoo/alt_launcher.cpp:76-89,344,499` |
32+
| 10 | **Native-core auto-init** | `zaparoo_is_native_core()` matches core name `"Zaparoo Launcher"`; `zaparoo_alt_launcher_init_for_core()` auto-spawns when the FPGA loads that core | `support/zaparoo/alt_launcher.cpp:480-495`, `user_io.cpp:1543` |
33+
| 11 | **In-core "Launcher" OSD entry** | Adds row 31 (`ALT_LAUNCHER_MENUSUB`) to MENU_COMMON1 marked with `reboot_req` when activated | `menu.cpp:2831,2845-2849,3088-3091` |
34+
| 12 | **OSD/F12 overlay over running launcher** | F12 / `KEY_MENU` reaches the OSD even with launcher running; on menu core opens System Settings directly (skip file picker); F1/F9 disabled when launcher 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` |
35+
| 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 to upstream dispatch slots | `support/zaparoo/alt_launcher_menu.cpp`, `menu.cpp:6739-6745,6816-6821` |
36+
| 14 | **Right-side Display Centering page** | New menu state hosting H/V offset adjustment + relocated CRT toggle; persisted via 2-byte `zaparoo_video_offsets.bin`; pushed via `user_io_status_set("[13:10]" / "[17:14]")` | `support/zaparoo/display_menu.cpp/.h` *(local rename in progress: `launcher_pages.cpp/.h`)*, `support/zaparoo/alt_launcher.cpp` (offset state + setters), `menu.cpp` `MENU_ZAPAROO_DISPLAY*` cases |
37+
| 15 | **Escape-to-stock semantics** | Sticky `s_escaped` flag makes `alt_launcher_configured()` return `false` after a clean exit, so the rest of the session reverts to stock OSD; reboot resets it | `support/zaparoo/alt_launcher.cpp:32,38-43,229-241` |
38+
| 16 | **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` |
39+
| 17 | **Build-time defaults flipped** | `cfg.recents` and `LOG_FILE_ENTRY` default to enabled in Zaparoo builds | `cfg.cpp` (defaults) |
40+
41+
---
42+
43+
## 2. Inconsistencies and cleanup backlog
44+
45+
These are intentional starting points for follow-up work, ordered roughly from
46+
"30-minute cleanup" to "needs a design pass."
47+
48+
### 2.1 Mixed namespace prefix in one module
49+
`support/zaparoo/alt_launcher.h` uses two prefixes for the same conceptual thing:
50+
51+
```c
52+
alt_launcher_init / _shutdown / _toggle_crt / _native_crt / _active / _configured ...
53+
zaparoo_is_native_core
54+
zaparoo_alt_launcher_init_for_core / _for_menu
55+
```
56+
57+
The `zaparoo_*` wrappers are the only ones called from `user_io.cpp`. Pick one
58+
prefix (`zap_` is shortest) or split into two headers along that boundary.
59+
60+
### 2.2 Three overlapping predicates
61+
Gating across the codebase uses `_configured()` / `_active()` / `_native_crt()`
62+
interchangeably without a documented rule. Current de-facto convention:
63+
64+
| Predicate | Meaning | Used to gate |
65+
|-----------|---------|--------------|
66+
| `_configured` | binary file exists, sticky off after escape | **render paths** (System Settings body, MENU_SYSTEM1 entry, vga_nag, file-picker entry, "Launcher" row visibility, right-arrow gate) |
67+
| `_active` | PID alive | **input handling** (F1/F9 disable, joypad-to-launcher routing, OSD overlay, menu auto-open suppression) |
68+
| `_native_crt` | PID alive AND CRT mode on | **internal video state machine** (`disable_native_crt_path`, status timer) |
69+
70+
The split is mostly principled but leaks at `MENU_SYSTEM1`, which uses
71+
`_configured` for both the gate AND the body delegation while `MENU_NONE2`
72+
auto-open uses `_active`. A user with the launcher binary present but not yet
73+
running sees different OSD behavior than a user without the binary at all —
74+
worth either a comment or a unified helper.
75+
76+
### 2.3 Two persistence files, no shared format
77+
Current state:
78+
79+
```
80+
zaparoo_launcher_crt.bin 1 byte (CRT mode flag)
81+
zaparoo_video_offsets.bin 2 bytes (h_offset, v_offset)
82+
```
83+
84+
Same dir, same `FileSaveConfig` API, but no unified struct. If a third setting
85+
arrives this becomes a per-feature file pattern. A single `zaparoo_state.bin`
86+
with a versioned struct would scale better:
87+
88+
```c
89+
struct zaparoo_state_v1 {
90+
uint8_t magic; // 'Z'
91+
uint8_t version; // 1
92+
uint8_t crt; // 0 / 1
93+
int8_t h_offset; // -8..+7
94+
int8_t v_offset; // -8..+7
95+
uint8_t reserved[3];
96+
};
97+
```
98+
99+
Cost: a one-shot migration on existing installs (read legacy `crt.bin` if
100+
new file is missing; never write the legacy file again).
101+
102+
### 2.4 Hardcoded paths scattered across modules
103+
- Launcher path: `zaparoo/launcher` in `alt_launcher.cpp:22`
104+
- Menu RBF name(s): hardcoded in `support/zaparoo/menu_rbf.cpp`
105+
- Persistence files: hardcoded in `alt_launcher.cpp`
106+
107+
INI knobs were intentionally dropped (commit `72037bc`) in favor of
108+
file-existence detection, but the resulting literals are now in three places.
109+
A small `support/zaparoo/paths.h` (or a `paths.cpp` that resolves them at
110+
startup) would centralize them without bringing INI knobs back.
111+
112+
### 2.5 Status-bit map exists only in code
113+
`status[9]` (CRT gate), `status[13:10]` (h_offset), `status[17:14]` (v_offset)
114+
are agreed upon between this fork and `Menu_MiSTer/feat/dual-mode-native-fb`,
115+
but the agreement is enforced only by lining up `user_io_status_set("[13:10]", …)`
116+
against the SystemVerilog `status[13:10]`. Neither side has a comment
117+
referencing the other.
118+
119+
A short `STATUS.md` (or a header in `support/zaparoo/`) documenting the shared
120+
register layout would prevent accidental conflicts when a future feature
121+
allocates new bits.
122+
123+
### 2.6 F-key handling comment is archaeology
124+
F2 toggle was added (`0cea191`), moved to `user_io_kbd` (`6d2690b`), and both
125+
were reverted (`390c141`, `4220a82`). What remains is a multi-line comment
126+
block in `user_io.cpp:4162-4171` that reads like commit-history narration.
127+
128+
It can shrink to one line:
129+
130+
```c
131+
// F12/KEY_MENU bypasses alt_launcher_active() so the user can open
132+
// the OSD on top of a running launcher.
133+
```
134+
135+
### 2.7 Trimmed-menu dispatcher has a dead branch
136+
`alt_launcher_translate_system_select()` returns `-1` to signal "consumed
137+
inline." That existed for the CRT row, which has now moved to the right page.
138+
139+
The `if (dispatch < 0) { menustate = MENU_SYSTEM1; break; }` branch in
140+
`MENU_SYSTEM2`'s switch is currently unreachable. Either drop it or note that
141+
it's reserved for future inline-handled rows.
142+
143+
### 2.8 `alt_launcher.cpp` is doing too many jobs
144+
~600 lines covering: process lifecycle + video state machine + tty handling
145+
+ status-bit pushers + offset persistence + cfg overrides. Splitting into
146+
`alt_launcher_proc.cpp`, `alt_launcher_video.cpp`, `alt_launcher_state.cpp`
147+
would make each concern testable and easier to audit. Not urgent — the file
148+
is still readable — but the next feature will tip it over.
149+
150+
### 2.9 Hard-override of user INI config is silent
151+
`alt_launcher_cfg_apply()` quietly forces `fb_terminal=1` and `recents=1`
152+
after `cfg_parse`. A user who set `fb_terminal=0` in `MiSTer.ini` gets no
153+
warning that we're overriding them.
154+
155+
At minimum, log it once at startup:
156+
157+
```c
158+
printf("alt_launcher: forcing fb_terminal=1, recents=1 (Zaparoo build)\n");
159+
```
160+
161+
### 2.10 Naming drift in the new menu page
162+
The right-side page was committed as `MENU_ZAPAROO_DISPLAY1/2` with files
163+
`display_menu.{cpp,h}`. Local in-progress refactor renames the menu states
164+
to `MENU_ZAPAROO_VIDEO*` / `MENU_ZAPAROO_LAUNCHER*` and the file to
165+
`launcher_pages.{cpp,h}`. After the rename settles, double-check that the
166+
file name and the symbols inside agree on what the page is called.
167+
168+
---
169+
170+
## 3. Boundary commit
171+
172+
The "fork divergence" reference point used for this analysis is:
173+
174+
```
175+
a2eb35eacdd7789abe3411e4d03381e7bf55309f
176+
```
177+
178+
Use that as the base in `git log a2eb35e..HEAD` if you want to refresh this
179+
document programmatically.

cfg.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ static const ini_var_t ini_vars[] =
139139
{ "SCREENSHOT_IMAGE_FORMAT", (void *)(&(cfg.screenshot_image_format)), STRING, 0, sizeof(cfg.screenshot_image_format) - 1 },
140140
{ "XBE2_SHIFT", (void*)(&(cfg.xbe2_shift)), UINT16, 0, 0x22F },
141141
{ "SPD_QUIRK", (void*)(&(cfg.spd_quirk)), UINT8, 0, 3 },
142-
{ "ALT_LAUNCHER", (void*)(&(cfg.alt_launcher)), STRING, 0, sizeof(cfg.alt_launcher) - 1 },
143142
};
144143

145144
static const int nvars = (int)(sizeof(ini_vars) / sizeof(ini_var_t));
@@ -580,7 +579,6 @@ const char* cfg_get_label(uint8_t alt)
580579
void cfg_parse()
581580
{
582581
memset(&cfg, 0, sizeof(cfg));
583-
alt_launcher_cfg_defaults();
584582
cfg.csync = 1;
585583
cfg.bootscreen = 1;
586584
cfg.fb_terminal = 1;
@@ -613,6 +611,8 @@ void cfg_parse()
613611
ini_parse(altcfg(), video_get_core_mode_name(0));
614612
}
615613

614+
alt_launcher_cfg_apply();
615+
616616
if (strlen(cfg.vga_mode))
617617
{
618618
if (!strcasecmp(cfg.vga_mode, "rgb")) cfg.vga_mode_int = 0;

cfg.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ typedef struct {
106106
char screenshot_image_format[16];
107107
uint16_t xbe2_shift;
108108
uint8_t spd_quirk;
109-
char alt_launcher[1024];
110109
} cfg_t;
111110

112111
extern cfg_t cfg;

file_io.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "scheduler.h"
3434
#include "video.h"
3535
#include "support.h"
36+
#include "support/zaparoo/menu_rbf.h"
3637

3738
#define MIN(a,b) (((a)<(b)) ? (a) : (b))
3839

@@ -1127,7 +1128,7 @@ void setStorage(int dev)
11271128
{
11281129
device = 0;
11291130
FileSave(CONFIG_DIR"/device.bin", &dev, sizeof(int));
1130-
fpga_load_rbf("menu.rbf");
1131+
fpga_load_rbf(menu_rbf_name());
11311132
}
11321133

11331134
static int orig_device = 0;
@@ -1693,7 +1694,7 @@ int ScanDirectory(char* path, int mode, const char *extension, int options, cons
16931694
// skip hidden files
16941695
if (!strncasecmp(de->d_name, ".", 1)) continue;
16951696
//skip non-selectable files
1696-
if (!strcasecmp(de->d_name, "menu.rbf")) continue;
1697+
if (is_menu_rbf(de->d_name)) continue;
16971698
if (!strncasecmp(de->d_name, "menu_20", 7)) continue;
16981699
if (!strncasecmp(de->d_name, "boot", 4))
16991700
{

fpga_io.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "shmem.h"
1818
#include "offload.h"
1919
#include "support/zaparoo/alt_launcher.h"
20+
#include "support/zaparoo/menu_rbf.h"
2021

2122
#include "fpga_base_addr_ac5.h"
2223
#include "fpga_manager.h"
@@ -441,7 +442,7 @@ int fpga_load_rbf(const char *name, const char *cfg, const char *xml)
441442
printf("Loading RBF: %s\n", name);
442443

443444
if(name[0] == '/') strcpy(path, name);
444-
else sprintf(path, "%s/%s", !strcasecmp(name, "menu.rbf") ? getStorageDir(0) : getRootDir(), name);
445+
else sprintf(path, "%s/%s", is_menu_rbf(name) ? getStorageDir(0) : getRootDir(), name);
445446

446447
int rbf = open(path, O_RDONLY);
447448
if (rbf < 0)
@@ -504,7 +505,7 @@ int fpga_load_rbf(const char *name, const char *cfg, const char *xml)
504505
}
505506
close(rbf);
506507

507-
app_restart(!strcasecmp(name, "menu.rbf") ? "menu.rbf" : path, xml);
508+
app_restart(is_menu_rbf(name) ? menu_rbf_name() : path, xml);
508509
return ret;
509510
}
510511

input.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3564,7 +3564,7 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int
35643564
if (osd_event == 2) joy_digital(input[dev].num, 0, 0, 0, BTN_OSD);
35653565
}
35663566

3567-
if (user_io_osd_is_visible() || video_fb_state())
3567+
if (user_io_osd_is_visible() || video_fb_state() || alt_launcher_active())
35683568
{
35693569
if (ev->value <= 1)
35703570
{

0 commit comments

Comments
 (0)