From 288a7d856b355506f2cc8ac7295438cc68367e69 Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Thu, 3 Sep 2026 09:36:23 +0200 Subject: [PATCH] feat(sim): port examples/simple_room_server to variants/sim/ Mirrors the simple_repeater sim port exactly: headless (no DISPLAY_CLASS, UITask.cpp excluded from the build), new sim_simple_room_server native env plus build_wasm_room_server.sh, own SimFS root ./sim_data_room so its identity storage can't collide with the companion or repeater instances on the same page/cwd. Verified beyond "it compiles": ran the native binary and confirmed a real _main.id identity file gets persisted through the actual SimFS/IdentityStore path, same as the other two sim targets. Co-Authored-By: Claude Sonnet 5 --- examples/simple_room_server/MyMesh.cpp | 4 + examples/simple_room_server/main.cpp | 29 +++++ variants/sim/build_wasm_room_server.sh | 149 +++++++++++++++++++++++++ variants/sim/platformio.ini | 53 +++++++++ 4 files changed, 235 insertions(+) create mode 100755 variants/sim/build_wasm_room_server.sh diff --git a/examples/simple_room_server/MyMesh.cpp b/examples/simple_room_server/MyMesh.cpp index 546d094f..f2588ec8 100644 --- a/examples/simple_room_server/MyMesh.cpp +++ b/examples/simple_room_server/MyMesh.cpp @@ -787,6 +787,8 @@ bool MyMesh::formatFileSystem() { return LittleFS.format(); #elif defined(ESP32) return SPIFFS.format(); +#elif defined(SIM_PLATFORM) + return _fs->format(); #else #error "need to implement file system erase" return false; @@ -852,6 +854,8 @@ void MyMesh::saveIdentity(const mesh::LocalIdentity &new_id) { IdentityStore store(*_fs, "/identity"); #elif defined(RP2040_PLATFORM) IdentityStore store(*_fs, "/identity"); +#elif defined(SIM_PLATFORM) + IdentityStore store(*_fs, "/identity"); #else #error "need to define saveIdentity()" #endif diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index d833fff3..f340817c 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -21,6 +21,18 @@ void halt() { while (1) ; } +#if defined(SIM_PLATFORM) && defined(__EMSCRIPTEN__) +#include +// Same "has setup() actually finished" readiness flag as +// examples/companion_radio/main.cpp / examples/simple_repeater/main.cpp -- +// see those files' comments for why this is needed instead of a fixed +// post-ready delay. +static bool g_sim_ready = false; +extern "C" EMSCRIPTEN_KEEPALIVE int sim_is_ready() { + return g_sim_ready ? 1 : 0; +} +#endif + static char command[MAX_POST_TEXT_LEN+1]; #ifdef ETHERNET_ENABLED static char ethernet_command[MAX_POST_TEXT_LEN+1]; @@ -28,7 +40,12 @@ static char ethernet_command[MAX_POST_TEXT_LEN+1]; void setup() { Serial.begin(115200); +#ifndef SIM_PLATFORM + // Skip this one-shot boot pause in the sim: under Emscripten it would + // synchronously block the browser's single JS thread for a full second + // (see examples/simple_repeater/main.cpp's setup() for the same guard). delay(1000); +#endif board.begin(); @@ -63,6 +80,15 @@ void setup() { SPIFFS.begin(true); fs = &SPIFFS; IdentityStore store(SPIFFS, "/identity"); +#elif defined(SIM_PLATFORM) + // Own root, distinct from both examples/companion_radio/main.cpp's + // "./sim_data" and examples/simple_repeater/main.cpp's + // "./sim_data_repeater" -- so a room-server instance's identity can never + // collide with either, even sharing a cwd (native) or a page (wasm). + static SimFS sim_fs("./sim_data_room"); + fs = &sim_fs; + IdentityStore store(sim_fs, "/identity"); + store.begin(); #else #error "need to define filesystem" #endif @@ -101,6 +127,9 @@ void setup() { #endif board.onBootComplete(); +#if defined(SIM_PLATFORM) && defined(__EMSCRIPTEN__) + g_sim_ready = true; +#endif } void loop() { diff --git a/variants/sim/build_wasm_room_server.sh b/variants/sim/build_wasm_room_server.sh new file mode 100755 index 00000000..03481c40 --- /dev/null +++ b/variants/sim/build_wasm_room_server.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +# Emscripten build script for the examples/simple_room_server sim -- sibling +# of build_wasm.sh (companion_radio) and build_wasm_repeater.sh +# (simple_repeater), NOT a modification of either. +# +# Differences from build_wasm_repeater.sh, all deliberate: +# - examples/simple_room_server/{main,MyMesh}.cpp instead of +# examples/simple_repeater/{main,MyMesh}.cpp -- UITask.cpp is likewise +# excluded (not added to SRCS at all) since no -DDISPLAY_CLASS is +# defined here, matching every real headless room-server env. +# - -DSIM_FS_ROOT=\"/sim_data_room\" -- must match the "./sim_data_room" +# SimFS root examples/simple_room_server/main.cpp's own SIM_PLATFORM +# branch constructs (see variants/sim/sim_main.cpp), kept DIFFERENT from +# both companion_radio's "/sim_data" and simple_repeater's +# "/sim_data_repeater" so identities can never collide on one page. +# - -sEXPORT_NAME=MeshCoreSimRoomServer -- its own MODULARIZE factory +# name, distinct from MeshCoreSim/MeshCoreSimRepeater. +# - Output lands under web/build/room_server/. +# +# Usage: +# variants/sim/build_wasm_room_server.sh # release-ish build (-O2) +# variants/sim/build_wasm_room_server.sh debug # -O0 -g +# +# Same emsdk 6.0.9 requirement as build_wasm.sh -- see that script's header +# comment for the install command if variants/sim/tools/emsdk/ is missing. +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +EMSDK_DIR="$SCRIPT_DIR/tools/emsdk" +EMXX="$EMSDK_DIR/upstream/emscripten/em++" +OUT_DIR="$SCRIPT_DIR/web/build/room_server" + +if [ ! -x "$EMXX" ]; then + echo "error: em++ not found at $EMXX" >&2 + echo "Install it first:" >&2 + echo " cd $EMSDK_DIR && python3 ./emsdk.py install 6.0.9 && python3 ./emsdk.py activate 6.0.9" >&2 + exit 1 +fi + +BUILD_MODE="${1:-release}" +if [ "$BUILD_MODE" = "debug" ]; then + OPT_FLAGS=(-O0 -g) +else + OPT_FLAGS=(-O2) +fi + +mkdir -p "$OUT_DIR" +cd "$REPO_ROOT" + +# Same list as variants/sim/platformio.ini's [env:sim_simple_room_server] +# build_src_filter, spelled as real paths. +SRCS=( + src/Dispatcher.cpp + src/Identity.cpp + src/Mesh.cpp + src/Packet.cpp + src/Utils.cpp + src/helpers/AdvertDataHelpers.cpp + src/helpers/BaseChatMesh.cpp + src/helpers/ClientACL.cpp + src/helpers/CommonCLI.cpp + src/helpers/ConfigSerializer.cpp + src/helpers/DeviceDiag.cpp + src/helpers/IdentityStore.cpp + src/helpers/RegionMap.cpp + src/helpers/StaticPoolPacketManager.cpp + src/helpers/TransportKeyStore.cpp + src/helpers/TxtDataHelpers.cpp + lib/ed25519/add_scalar.c + lib/ed25519/fe.c + lib/ed25519/ge.c + lib/ed25519/key_exchange.c + lib/ed25519/keypair.c + lib/ed25519/sc.c + lib/ed25519/seed.c + lib/ed25519/sha512.c + lib/ed25519/sign.c + lib/ed25519/verify.c + variants/sim/sim_main.cpp + variants/sim/target.cpp + variants/sim/thirdparty/crypto/AES128.cpp + variants/sim/thirdparty/crypto/AESCommon.cpp + variants/sim/thirdparty/crypto/BigNumberUtil.cpp + variants/sim/thirdparty/crypto/BlockCipher.cpp + variants/sim/thirdparty/crypto/Crypto.cpp + variants/sim/thirdparty/crypto/Curve25519.cpp + variants/sim/thirdparty/crypto/Ed25519.cpp + variants/sim/thirdparty/crypto/Hash.cpp + variants/sim/thirdparty/crypto/rng_stub.cpp + variants/sim/thirdparty/crypto/SHA256.cpp + variants/sim/thirdparty/crypto/SHA512.cpp + variants/sim/thirdparty/cayennelpp/CayenneLPP.cpp + variants/sim/thirdparty/cayennelpp/CayenneLPPPolyline.cpp + examples/simple_room_server/main.cpp + examples/simple_room_server/MyMesh.cpp +) + +INCLUDES=( + -Ivariants/sim/arduino + -Ivariants/sim + -Ivariants/sim/thirdparty/crypto + -Ivariants/sim/thirdparty/cayennelpp + -Ivariants/sim/thirdparty/arduinojson + -Ilib/ed25519 + -Isrc + -Iexamples/simple_room_server +) + +DEFINES=( + -DSIM_PLATFORM + -DMESH_DEBUG=0 + -DENABLE_ADVERT_ON_BOOT=1 + -DADVERT_NAME="\"Sim Room\"" + -DSIM_FS_ROOT="\"/sim_data_room\"" +) + +# -funsigned-char: same reasoning as build_wasm.sh/build_wasm_repeater.sh -- +# keep it uniform across every sim TU even though this app has no UI either. +COMMON_FLAGS=(-std=c++17 -funsigned-char "${OPT_FLAGS[@]}" "${DEFINES[@]}" "${INCLUDES[@]}") + +# Mirror each source's own directory under obj/ -- same macOS APFS +# case-insensitive sha512.o/SHA512.o collision reason as the other two +# build scripts (same source tree). +OBJ_DIR="$OUT_DIR/obj" +rm -rf "$OBJ_DIR" +OBJS=() +for src in "${SRCS[@]}"; do + obj="$OBJ_DIR/${src%.*}.o" + mkdir -p "$(dirname "$obj")" + "$EMXX" -c "${COMMON_FLAGS[@]}" "$src" -o "$obj" + OBJS+=("$obj") +done + +"$EMXX" \ + "${OBJS[@]}" \ + -lidbfs.js \ + -sALLOW_MEMORY_GROWTH=1 \ + -sFORCE_FILESYSTEM=1 \ + -sMODULARIZE=1 \ + -sEXPORT_NAME=MeshCoreSimRoomServer \ + -sENVIRONMENT=web \ + -sEXIT_RUNTIME=0 \ + -sEXPORTED_RUNTIME_METHODS=FS,ccall,cwrap,HEAPU8 \ + -sEXPORTED_FUNCTIONS=_main,_malloc,_free \ + -o "$OUT_DIR/meshcore_sim_room_server.js" + +echo "" +echo "Built: $OUT_DIR/meshcore_sim_room_server.js (+ .wasm alongside it)" diff --git a/variants/sim/platformio.ini b/variants/sim/platformio.ini index 580b3d7c..95e44966 100644 --- a/variants/sim/platformio.ini +++ b/variants/sim/platformio.ini @@ -138,3 +138,56 @@ build_src_filter = ; rather than porting GPIO stubs into variants/sim/arduino/Arduino.h for ; code that would never run. -<../examples/simple_repeater/UITask.cpp> + +; Headless native build of the real examples/simple_room_server app logic +; against the same variants/sim/ interfaces -- sibling of +; [env:sim_simple_repeater] above, same reasoning throughout (no +; DISPLAY_CLASS, so UITask.cpp is never needed here either -- unlike +; simple_repeater's, this one's UITask.cpp actually WOULD compile fine +; headless (its digitalRead(PIN_USER_BTN) call is itself gated behind +; #ifdef PIN_USER_BTN, which this env never defines), but there's still no +; reason to compile a translation unit that's never linked in, so it's +; excluded the same way). +[env:sim_simple_room_server] +platform = native +build_type = debug +build_flags = + -std=c++17 + -g + -funsigned-char + -D SIM_PLATFORM + -D MESH_DEBUG=0 + -D ENABLE_ADVERT_ON_BOOT=1 + -D ADVERT_NAME='"Sim Room"' + -I variants/sim/arduino + -I variants/sim + -I variants/sim/thirdparty/crypto + -I variants/sim/thirdparty/cayennelpp + -I variants/sim/thirdparty/arduinojson + -I lib/ed25519 + -I src + -I examples/simple_room_server +build_src_filter = + -<*> + +<../src/Dispatcher.cpp> + +<../src/Identity.cpp> + +<../src/Mesh.cpp> + +<../src/Packet.cpp> + +<../src/Utils.cpp> + +<../src/helpers/AdvertDataHelpers.cpp> + +<../src/helpers/BaseChatMesh.cpp> + +<../src/helpers/ClientACL.cpp> + +<../src/helpers/CommonCLI.cpp> + +<../src/helpers/ConfigSerializer.cpp> + +<../src/helpers/DeviceDiag.cpp> + +<../src/helpers/IdentityStore.cpp> + +<../src/helpers/RegionMap.cpp> + +<../src/helpers/StaticPoolPacketManager.cpp> + +<../src/helpers/TransportKeyStore.cpp> + +<../src/helpers/TxtDataHelpers.cpp> + +<../lib/ed25519/*.c> + +<../variants/sim/*.cpp> + +<../variants/sim/thirdparty/crypto/*.cpp> + +<../variants/sim/thirdparty/cayennelpp/*.cpp> + +<../examples/simple_room_server/*.cpp> + -<../examples/simple_room_server/UITask.cpp>