emdashes begone (#10847)

This commit is contained in:
Tom
2026-07-01 19:01:27 -05:00
committed by GitHub
parent dee94e0758
commit 3becaf2d95
276 files changed
+1795 -1793

No files matched your search

+3 -3
View File
@@ -174,7 +174,7 @@ void getMacAddr(uint8_t *dmac)
// the same kind of stable, host-derived identifier that the BlueZ
// path provides on Linux. If en0 isn't found or has no MAC, dmac is
// left untouched and the caller's "Blank MAC Address not allowed!"
// check will still fire preserving existing behavior for users
// check will still fire - preserving existing behavior for users
// who deliberately rely on --hwid or YAML override.
struct ifaddrs *ifap = nullptr;
if (getifaddrs(&ifap) == 0) {
@@ -548,7 +548,7 @@ void portduinoSetup()
// Pass the full buffer size (9 = 8 chars + null) to getSerialString,
// not 8. The function treats `len` as buffer size and reserves one
// slot for the null terminator, so passing 8 produced a 7-char serial
// and broke the `strlen(serial) == 8` check below masked on Linux
// and broke the `strlen(serial) == 8` check below - masked on Linux
// by the BlueZ HCI MAC fallback in getMacAddr(), but on macOS (where
// the BlueZ path is __linux__-guarded) it left mac_address empty and
// meshtasticd refused to start.
@@ -1170,7 +1170,7 @@ bool MAC_from_string(std::string mac_str, uint8_t *dmac)
std::string exec(const char *cmd)
{ // https://stackoverflow.com/a/478960
#ifdef ARCH_PORTDUINO_WASM
(void)cmd; // no shell/popen in the browser shell-outs degrade to empty
(void)cmd; // no shell/popen in the browser - shell-outs degrade to empty
return "";
#endif
std::array<char, 128> buffer;
+6 -6
View File
@@ -1,8 +1,8 @@
# ARCH_PORTDUINO_WASM meshtasticd in WebAssembly (LoRa over WebUSB)
# ARCH_PORTDUINO_WASM - meshtasticd in WebAssembly (LoRa over WebUSB)
Builds the full portduino firmware (`setup()`/`loop()`) to WebAssembly with
Emscripten, so a real Meshtastic node runs in a browser tab (or headless Node)
and drives a LoRa radio over **WebUSB** through a CH341 USB-to-SPI bridge the
and drives a LoRa radio over **WebUSB** through a CH341 USB-to-SPI bridge - the
same `Ch341Hal` path the desktop `meshtasticd` uses, with the libusb backend
swapped for a WebUSB one. The desktop/native portduino build is untouched.
@@ -11,7 +11,7 @@ swapped for a WebUSB one. The desktop/native portduino build is untouched.
| file | role |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `portduino_glue_wasm.cpp` | LoRa config (MeshToad default + `wasm_set_lora_*` setters, no YAML), VFS mount, region/MAC helpers, and the `wasm_api_*` PhoneAPI bridge |
| `portduino_main_wasm.cpp` | `wasm_setup()` / `wasm_loop_once()` JS drives the cooperative loop |
| `portduino_main_wasm.cpp` | `wasm_setup()` / `wasm_loop_once()` - JS drives the cooperative loop |
| `libpinedio_webusb.c` | WebUSB libpinedio backend (sync C ↔ async WebUSB via Asyncify `EM_ASYNC_JS`) |
| `include/libpinedio-usb.h` | the 12-fn libpinedio API the backend implements |
| `stubs/` | `argp.h` shim + jsoncpp serializer stub (MQTT-only, excluded) |
@@ -28,7 +28,7 @@ This is a normal PlatformIO env (`[env:native-wasm]`) built with the
[meshtastic/platform-wasm](https://github.com/meshtastic/platform-wasm) platform
(emcc/em++), exactly like any other board target.
Prereq: an **Emscripten SDK** on `PATH` `source <emsdk>/emsdk_env.sh` (or
Prereq: an **Emscripten SDK** on `PATH` - `source <emsdk>/emsdk_env.sh` (or
`export EMSDK=<path>`) so the platform builder can locate `emcc`.
```sh
@@ -63,7 +63,7 @@ pump();
```
**API control:** feed a `ToRadio` protobuf with `wasm_api_to_radio(ptr,len)` and
drain `FromRadio` with `wasm_api_from_radio(out,max)` the firmware's own
drain `FromRadio` with `wasm_api_from_radio(out,max)` - the firmware's own
`PhoneAPI`, unframed. The official `@meshtastic/core` SDK drives it through a
~40-line in-process transport (see the `meshtasticd-wasm-node` repo, which hosts
the dev server, the SDK-UI page, the headless node-usb runner, and the TCP :4403
@@ -71,7 +71,7 @@ bridge for the Python CLI). WebUSB is Chromium-only.
**Reboot:** the firmware can't restart itself in wasm, so a reboot (admin/phone
command, factory reset, or the 60 s stuck-TX watchdog) hands off to the host. In
a browser it calls `location.reload()` NodeDB state survives via IDBFS, so the
a browser it calls `location.reload()` - NodeDB state survives via IDBFS, so the
node comes back with the same identity. Headless, provide a `Module.onReboot`
callback to handle it (re-instantiate the module, `process.exit()` for a
supervisor to restart, etc.); without one it just logs and keeps running.
@@ -2,7 +2,7 @@
//
// Same API surface as the upstream libpinedio-usb.h that the firmware's
// Ch341Hal (src/platform/portduino/USBHal.h) compiles against, but WITHOUT the
// libusb / pthread dependencies the implementation (libpinedio_webusb.c)
// libusb / pthread dependencies - the implementation (libpinedio_webusb.c)
// forwards to a JS WebUSB bridge via Emscripten. The struct keeps only the
// fields Ch341Hal actually touches (serial_number, product_string, in_error,
// options[]); GPIO/CS state now lives on the JS side.
@@ -33,9 +33,9 @@
extern "C" EMSCRIPTEN_KEEPALIVE void wasm_fs_sync()
{
// Coalesce: IDBFS syncfs is async, and overlapping syncs warn "2 FS.syncfs
// operations in flight". Never run two at once if one is in flight, mark a
// operations in flight". Never run two at once - if one is in flight, mark a
// pending re-sync and let the running one chain it when it finishes.
// NOTE: loose != / == and string ops only clang-format mangles !== and
// NOTE: loose != / == and string ops only - clang-format mangles !== and
// /regex/ literals inside EM_ASM JS (splitting them into invalid tokens).
EM_ASM({
try {
@@ -78,10 +78,10 @@ void wasm_fs_mount()
portduinoVFS->mountpoint("/meshdata");
}
// Resolve a per-instance MAC address (12 uppercase hex chars, no colons the
// Resolve a per-instance MAC address (12 uppercase hex chars, no colons - the
// MAC_from_string format getMacAddr() expects). The lower 4 bytes become the
// 32-bit NodeNum (pickNewNodeNum: mac[2..5]), so this is the node's identity on
// the mesh every browser node MUST get a distinct one or they collide on the
// the mesh - every browser node MUST get a distinct one or they collide on the
// same NodeNum. Priority:
// 1. MESH_MAC env (headless determinism / parity tests, e.g. DEAD00C0FFEE),
// 2. a value persisted in the /meshdata tree (survives reload/restart),
@@ -235,16 +235,16 @@ void wasm_config_apply()
// (lora) region path exactly (AdminModule.cpp:904-937): validate -> first-region
// keygen + enable tx -> initRegion() -> reloadConfig (resetRadioConfig +
// reconfigure observer recomputes the carrier freq + saveToDisk). A region change
// is reconfigure-only no reboot. Returns 0 on success, -1 if validation fails.
// is reconfigure-only - no reboot. Returns 0 on success, -1 if validation fails.
// `region` is a meshtastic_Config_LoRaConfig_RegionCode enum value.
// Re-entrancy guard. The node is single-threaded + Asyncify: while setup()/loop()
// is suspended inside a WebUSB transfer, the JS event loop is free, so a stray DOM
// or timer callback could re-enter a wasm_* entry point starting a second
// or timer callback could re-enter a wasm_* entry point - starting a second
// Asyncify unwind ("async operation already in flight" abort) or clobbering shared
// PhoneAPI state. The host MUST call these only BETWEEN wasm_loop_once() ticks; the
// flag (set around setup()/loop() in portduino_main_wasm.cpp) lets the entry points
// reject a mid-tick call rather than corrupt/abort. The JS-side queue is the real
// fix this is just the safety net the design otherwise lacked.
// fix - this is just the safety net the design otherwise lacked.
extern "C" volatile bool g_wasm_in_firmware = false;
extern "C" EMSCRIPTEN_KEEPALIVE int wasm_set_region(int region)
@@ -285,11 +285,11 @@ extern "C" EMSCRIPTEN_KEEPALIVE int wasm_set_region(int region)
// those servers are excluded here, so we expose PhoneAPI directly to JS instead.
// A JS-side transport (browser in-process, or a headless HTTP/TCP bridge) feeds
// ToRadio protobufs in via wasm_api_to_radio() and drains FromRadio protobufs
// out via wasm_api_from_radio() exactly the unframed contract the device HTTP
// out via wasm_api_from_radio() - exactly the unframed contract the device HTTP
// API uses. PhoneAPI is abstract on checkIsConnected(); in-process we're always
// connected. We poll available() rather than push from onNowHasData(), to keep
// all API calls OUT of the loop's Asyncify suspend (the JS pump drains only
// between wasm_loop_once() ticks never re-entering wasm mid-SPI).
// between wasm_loop_once() ticks - never re-entering wasm mid-SPI).
class WasmPhoneAPI : public PhoneAPI
{
public:
@@ -300,7 +300,7 @@ static WasmPhoneAPI *g_wasmPhone = nullptr;
// Lazily construct after MeshService exists (PhoneAPI's ctor observes
// service->fromNumChanged). The first API call happens post-setup(), so service
// is live by then no wasm_setup() ordering change needed.
// is live by then - no wasm_setup() ordering change needed.
static WasmPhoneAPI *phone()
{
if (!g_wasmPhone && service)
@@ -310,7 +310,7 @@ static WasmPhoneAPI *phone()
// JS -> device: hand one serialized ToRadio protobuf (UNFRAMED) to the node.
// The SDK's want_config_id, text messages, admin, etc. all arrive here. Returns
// 1 if accepted, 0 if rejected (e.g. per-portnum throttle not a transport error).
// 1 if accepted, 0 if rejected (e.g. per-portnum throttle - not a transport error).
extern "C" EMSCRIPTEN_KEEPALIVE int wasm_api_to_radio(const uint8_t *buf, size_t len)
{
if (g_wasm_in_firmware)
@@ -350,7 +350,7 @@ extern "C" EMSCRIPTEN_KEEPALIVE int wasm_api_is_connected()
// delay()/yield() normally come from framework linux/LinuxCommon.cpp (excluded:
// it's POSIX/threads). We provide them via Asyncify's emscripten_sleep so
// init-time blocking yields to the browser event loop instead of freezing the
// tab exactly the behavior we want at runtime. C++ linkage to match Arduino.h.
// tab - exactly the behavior we want at runtime. C++ linkage to match Arduino.h.
void delay(unsigned long ms)
{
emscripten_sleep(ms);
@@ -378,9 +378,9 @@ void randomSeed(unsigned long seed)
// Restart the node. There is no in-process restart in wasm, so we hand off to
// the JS host: a browser reloads the tab (NodeDB state survives via IDBFS, so it
// comes back as the same node); a headless host calls Module.onReboot() if it
// provided one (re-instantiate or exit as it sees fit), otherwise we just log
// provided one (re-instantiate or exit as it sees fit), otherwise we just log -
// the caller (Power::reboot) already let modules persist via the reboot
// observers. NOTE: loose !=/== and double-quoted strings only clang-format
// observers. NOTE: loose !=/== and double-quoted strings only - clang-format
// mangles !== and /regex/ literals inside EM_ASM JS into invalid runtime tokens.
void reboot()
{
@@ -403,7 +403,7 @@ void reboot()
});
}
// tone()/noTone() no buzzer in the browser (from linux/LinuxCommon.cpp, excluded).
// tone()/noTone() - no buzzer in the browser (from linux/LinuxCommon.cpp, excluded).
void tone(unsigned char, unsigned int, unsigned long) {}
void noTone(unsigned char) {}
void delayMicroseconds(unsigned int us)
@@ -421,6 +421,6 @@ bool shouldWakeOnReceivedMessage()
return false;
}
// TCP phone/API server is excluded in the wasm build no-op stubs so main.cpp links.
// TCP phone/API server is excluded in the wasm build - no-op stubs so main.cpp links.
void initApiServer(int) {}
void deInitApiServer() {}
@@ -1,6 +1,6 @@
// WASM replacement for framework-portduino's cores/portduino/main.cpp.
// The original uses argp (CLI parse), ftw/nftw (FS walk) and an internal
// while(1){ loop(); usleep(loopDelay); } pump none of which fit the browser.
// while(1){ loop(); usleep(loopDelay); } pump - none of which fit the browser.
//
// Here: run the firmware setup() once from main(), then RETURN. JavaScript
// drives the cooperative scheduler by calling wasm_loop_once() on a timer,
@@ -26,8 +26,8 @@ extern void portduinoSetup();
extern void wasm_fs_mount(); // points portduinoVFS at /meshdata (portduino_glue_wasm.cpp)
// Re-entrancy guard (defined in portduino_glue_wasm.cpp). True while the firmware
// is executing setup()/loop() including while it is Asyncify-suspended inside a
// WebUSB transfer so the wasm_* API/region entry points reject a mid-tick
// is executing setup()/loop() - including while it is Asyncify-suspended inside a
// WebUSB transfer - so the wasm_* API/region entry points reject a mid-tick
// re-entry from JS instead of corrupting state or aborting Asyncify. The host is
// expected to call them only between ticks; this is the safety net.
extern "C" volatile bool g_wasm_in_firmware;
@@ -48,7 +48,7 @@ extern "C" EMSCRIPTEN_KEEPALIVE void wasm_setup()
//
// If you want the exact next-delay, expose it: have a small in-tree change make
// loop() stash mainController.runOrDelay() in a global, or just poll fast (e.g.
// JS setTimeout(_, 5)) RX latency is bounded by pollMissedIrqs() each tick.
// JS setTimeout(_, 5)) - RX latency is bounded by pollMissedIrqs() each tick.
extern "C" EMSCRIPTEN_KEEPALIVE int wasm_loop_once()
{
g_wasm_in_firmware = true;
@@ -62,6 +62,6 @@ extern "C" EMSCRIPTEN_KEEPALIVE int wasm_loop_once()
int main()
{
// INVOKE_RUN=0: the page calls wasm_setup() after wiring up Module.ch341.
printf("[meshnode] wasm loaded set Module.ch341, then call wasm_setup()\n");
printf("[meshnode] wasm loaded - set Module.ch341, then call wasm_setup()\n");
return 0;
}
+1 -1
View File
@@ -1,7 +1,7 @@
// Minimal stub of glibc <argp.h> for the wasm build.
//
// framework-portduino's Arduino.h includes <argp.h> unconditionally, and
// PortduinoGlue.cpp DEFINES argp option tables / a parse_opt callback but
// PortduinoGlue.cpp DEFINES argp option tables / a parse_opt callback - but
// nothing in the wasm build CALLS argp_parse (that lived in the framework
// main.cpp we replaced with portduino_main_wasm.cpp). So only the types and
// macros are needed to compile; no argp functions are linked.