feat(sim): two-device messaging + repeater relay over a JS ether

Ports examples/simple_repeater to variants/sim/ (new sim_simple_repeater
native env + build_wasm_repeater.sh) and adds a JS "ether"
(variants/sim/web/mesh.html) that bridges two real companion_radio WASM
instances through a real simple_repeater instance in a strict A<->R<->B
topology (no direct A-B link), proving genuine relay routing rather than
a shortcut.

Also fixes multi-instance issues Phase 2's single-instance design never
surfaced: SimDisplayDriver's canvas context/id caching was keyed on a
single global instead of per-instance, and both wasm builds were missing
_malloc/_free/HEAPU8 runtime exports needed for the ether to poke bytes
into an instance's memory.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-09-03 09:14:15 +02:00
co-authored by Claude Sonnet 5
parent 8f4c92a217
commit 9cfb58a60b
18 changed files with 1199 additions and 54 deletions
+16 -6
View File
@@ -48,13 +48,23 @@ extern "C" EMSCRIPTEN_KEEPALIVE void sim_idbfs_ready() {
emscripten_set_main_loop(sim_main_loop_tick, 0, 1);
}
// The app-level SimFS root to mount IDBFS at -- must match whatever
// relative "./sim_data..." path that app's own main.cpp constructs its
// SimFS with (see the long comment on sim_fs_mount_idbfs() in SimFS.h for
// why those are the same filesystem node under Emscripten's default cwd,
// "/"). Defaults to companion_radio's root, unchanged from Phase 2 --
// Phase 3's simple_repeater build (variants/sim/build_wasm_repeater.sh)
// overrides this via -DSIM_FS_ROOT so its identity storage lands under a
// DIFFERENT IDBFS-backed root than a companion instance's, same reasoning
// as examples/simple_repeater/main.cpp's SIM_PLATFORM branch using
// "./sim_data_repeater" instead of "./sim_data" for its SimFS.
#ifndef SIM_FS_ROOT
#define SIM_FS_ROOT "/sim_data"
#endif
int main() {
printf("MeshCore sim (wasm) starting -- mounting IDBFS at /sim_data...\n");
// "/sim_data" must match the relative "./sim_data" DataStore store(sim_fs,
// ...) in examples/companion_radio/main.cpp resolves to -- see the long
// comment on sim_fs_mount_idbfs() in SimFS.h for why those are the same
// filesystem node under Emscripten's default cwd ("/").
sim_fs_mount_idbfs("/sim_data");
printf("MeshCore sim (wasm) starting -- mounting IDBFS at " SIM_FS_ROOT "...\n");
sim_fs_mount_idbfs(SIM_FS_ROOT);
// Keep the runtime alive after main() returns instead of tearing it down
// (the default for a `main()` that returns under Emscripten) -- the real
// boot sequence hasn't happened yet, it's waiting on sim_idbfs_ready()