[native_base] extends = portduino_base build_flags = ${portduino_base.build_flags} -I variants/native/portduino -I /usr/include board = cross_platform board_level = extra lib_deps = ${portduino_base.lib_deps} # renovate: datasource=custom.pio depName=Melopero RV3028 packageName=melopero/library/Melopero RV3028 melopero/Melopero RV3028@1.2.0 build_src_filter = ${portduino_base.build_src_filter} [env:native] extends = native_base ; The pkg-config commands below optionally add link flags. ; the || : is just a "or run the null command" to avoid returning an error code build_flags = ${native_base.build_flags} !pkg-config --libs libulfius --silence-errors || : !pkg-config --libs openssl --silence-errors || : !pkg-config --cflags --libs sdl2 --silence-errors || : !pkg-config --cflags --libs libbsd-overlay --silence-errors || : ; Optional HUB75 RGB-matrix support on Raspberry Pi via hzeller/rpi-rgb-led-matrix. ; When the lib is installed (provides rgbmatrix.pc), these add its include/link flags and ; __has_include() enables HAS_HUB75_NATIVE (see configuration.h). Absent -> no-op. !pkg-config --cflags rgbmatrix --silence-errors || : !pkg-config --libs rgbmatrix --silence-errors || : [env:native-tft] extends = native_base build_type = release lib_deps = ${native_base.lib_deps} ${device-ui_base.lib_deps} build_flags = ${native_base.build_flags} -Os -lcurl -lX11 -linput -lxkbcommon -ffunction-sections -fdata-sections -Wl,--gc-sections -D RAM_SIZE=16384 -D USE_X11=1 -D HAS_TFT=1 -D HAS_SCREEN=1 -D LV_CACHE_DEF_SIZE=6291456 -D LV_BUILD_TEST=0 -D LV_USE_LIBINPUT=1 -D LV_LVGL_H_INCLUDE_SIMPLE -D LV_CONF_INCLUDE_SIMPLE -D LV_COMP_CONF_INCLUDE_SIMPLE -D USE_LOG_DEBUG -D LOG_DEBUG_INC=\"DebugConfiguration.h\" -D USE_PACKET_API -D VIEW_320x240 !pkg-config --libs libulfius --silence-errors || : !pkg-config --libs openssl --silence-errors || : !pkg-config --cflags --libs sdl2 --silence-errors || : !pkg-config --cflags --libs libbsd-overlay --silence-errors || : build_src_filter = ${native_base.build_src_filter} [env:native-fb] extends = native_base build_type = release lib_deps = ${native_base.lib_deps} ${device-ui_base.lib_deps} build_flags = ${native_base.build_flags} -Os -ffunction-sections -fdata-sections -lcurl -Wl,--gc-sections -D RAM_SIZE=8192 -D USE_FRAMEBUFFER=1 -D LV_COLOR_DEPTH=32 -D HAS_TFT=1 -D HAS_SCREEN=1 -D LV_BUILD_TEST=0 -D LV_USE_LOG=0 -D LV_USE_EVDEV=1 -D LV_LVGL_H_INCLUDE_SIMPLE -D LV_CONF_INCLUDE_SIMPLE -D LV_COMP_CONF_INCLUDE_SIMPLE -D USE_LOG_DEBUG -D LOG_DEBUG_INC=\"DebugConfiguration.h\" -D USE_PACKET_API -D VIEW_320x240 -D MAP_FULL_REDRAW !pkg-config --libs libulfius --silence-errors || : !pkg-config --libs openssl --silence-errors || : !pkg-config --cflags --libs sdl2 --silence-errors || : !pkg-config --cflags --libs libbsd-overlay --silence-errors || : build_src_filter = ${native_base.build_src_filter} [env:native-tft-debug] extends = native_base build_type = debug lib_deps = ${native_base.lib_deps} ${device-ui_base.lib_deps} build_flags = ${native_base.build_flags} -g -O0 -fsanitize=address -lcurl -lX11 -linput -lxkbcommon -D DEBUG_HEAP -D RAM_SIZE=16384 -D USE_X11=1 -D HAS_TFT=1 -D HAS_SCREEN=1 -D LV_CACHE_DEF_SIZE=6291456 -D LV_BUILD_TEST=0 -D LV_USE_LOG=1 -D LV_USE_SYSMON=1 -D LV_USE_PERF_MONITOR=1 -D LV_USE_MEM_MONITOR=0 -D LV_USE_PROFILER=0 -D LV_USE_LIBINPUT=1 -D LV_LVGL_H_INCLUDE_SIMPLE -D LV_CONF_INCLUDE_SIMPLE -D LV_COMP_CONF_INCLUDE_SIMPLE -D USE_LOG_DEBUG -D LOG_DEBUG_INC=\"DebugConfiguration.h\" -D USE_PACKET_API -D VIEW_320x240 !pkg-config --libs libulfius --silence-errors || : !pkg-config --libs openssl --silence-errors || : !pkg-config --cflags --libs sdl2 --silence-errors || : !pkg-config --cflags --libs libbsd-overlay --silence-errors || : build_src_filter = ${env:native-tft.build_src_filter} [env:coverage] extends = env:native build_flags = -lgcov --coverage -fprofile-abs-path -fsanitize=address ${env:native.build_flags} ; https://docs.platformio.org/en/latest/projectconf/sections/env/options/test/test_testing_command.html test_testing_command = ${platformio.build_dir}/${this.__env__}/meshtasticd -s ; --------------------------------------------------------------------------- ; Native build for macOS (Darwin / arm64 + x86_64). Headless meshtasticd that ; runs in SimRadio mode (`-s`) or against real LoRa hardware via a CH341 ; USB-SPI bridge. No BlueZ, libgpiod, or Linux I2C - those require Linux. ; ; Prerequisites (Homebrew): ; brew install platformio yaml-cpp libuv openssl@3 libusb argp-standalone pkg-config jsoncpp ; # Optional: enable the HTTP API (PiWebServer) on macOS: ; brew install ulfius ; ; The macOS-side patches now live upstream: ; * meshtastic/platform-native - `String.h`-shadow shim, `-Wno-enum-constexpr-conversion`, ; empty-variant-dir guard. Pulled via `portduino_base.platform` zip pin. ; * meshtastic/framework-portduino - LinuxHardwareI2C macOS stubs, AsyncUDP ; SOCK_NONBLOCK fallback, Common.h __APPLE__ guard, WiFiServer.cpp extern-C ; fix, package.json URL refresh. Pulled by platform-native at its pinned commit. ; This env therefore only carries the firmware-side build flags and src filter. ; ; Real LoRa hardware on macOS: ; The same lib_dep `pine64/libch341-spi-userspace` used on Linux works on ; macOS as-is - its `libusb_detach_kernel_driver()` call is `__linux__`- ; guarded, but on macOS the kernel doesn't bind a driver to a CH341A SPI ; bridge (PID 0x5512; bDeviceClass=0xff vendor-specific) by default, so ; no detach is needed. Apple's bundled CH34x driver targets the CH340 ; *UART* variant (PID 0x7523) - different product. libusb opens the device ; and claims interface 0 directly via IOUSBHostInterface. ; ; To use, point `meshtasticd` at any of the existing `bin/config.d/lora-*.yaml` ; files that specify `spidev: ch341` - they're platform-agnostic. Example: ; pio run -e native-macos ; mkdir -p ~/.meshtasticd && cp bin/config-dist.yaml ~/.meshtasticd/config.yaml ; # Edit ~/.meshtasticd/config.yaml: ConfigDirectory: ./config.d/ ; mkdir ~/.meshtasticd/config.d && cp bin/config.d/lora-meshstick-1262.yaml ~/.meshtasticd/config.d/ ; cd ~/.meshtasticd && /path/to/firmware/.pio/build/native-macos/meshtasticd ; ; The MAC address auto-derives from the CH341's USB serial + product string ; (PortduinoGlue.cpp ~497-518); on Linux a BlueZ HCI socket is the fallback ; when that path isn't taken, but BlueZ is `__linux__`-guarded so the ; serial-derivation path is mandatory on macOS. Override with ; `MACAddress: AA:BB:CC:DD:EE:FF` in config.yaml's `General:` section if ; the device's serial isn't 8 hex chars. ; ; Diagnosing CH341 issues on macOS: ; ioreg -p IOUSB -l -w 0 | grep -B2 -A30 0x5512 ; Children should be `IOUSBHostInterface`. If a vendor driver class ; (e.g. `com.wch.CH34xVCPDriver` from a third-party WCH installer) ; claims interface 0, libusb will fail with LIBUSB_ERROR_BUSY. ; Workaround: `sudo kmutil unload -b `. ; LIBUSB_DEBUG=4 .pio/build/native-macos/meshtasticd ; Verbose libusb trace - useful when claim_interface fails. ; --------------------------------------------------------------------------- [env:native-macos] extends = native_base ; Apple's ld doesn't accept GNU ld's `-Wl,-Map,` syntax (inherited from ; the top-level platformio.ini). Strip it; the linker map isn't useful for ; the macOS dev loop anyway, and Apple ld's equivalent (`-Wl,-map,`) ; uses different argument shape. build_unflags = -Wl,-Map,"${platformio.build_dir}"/output.map ; libi2c is Linux-only but build_flags_common carries -li2c (also duplicated in the Linux-only ; build_flags); macOS has no libi2c, so strip it here to let the link succeed. -li2c build_flags = ${portduino_base.build_flags_common} -I variants/native/portduino -I/opt/homebrew/include -I/opt/homebrew/opt/argp-standalone/include -I/opt/homebrew/opt/yaml-cpp/include -L/opt/homebrew/lib -L/opt/homebrew/opt/argp-standalone/lib -L/opt/homebrew/opt/yaml-cpp/lib -largp -DPORTDUINO_DARWIN ; Headless build - variants/native/portduino/variant.h would otherwise ; default HAS_SCREEN to 1 and pull in screen-renderer source that uses ; VLA-with-initializer (a GNU/GCC extension Apple Clang rejects). ; MESHTASTIC_EXCLUDE_SCREEN gates the optional `screen->setHeading(...)`- ; style screen-driver hooks scattered through sensor sources. -DHAS_SCREEN=0 -DMESHTASTIC_EXCLUDE_SCREEN=1 ; openssl@3 is the keg-only Homebrew formula; --cflags is required so the ; compiler finds in the Homebrew prefix (not just the linker). !pkg-config --cflags --libs openssl --silence-errors || : ; PiWebServer (src/mesh/raspihttp/PiWebServer.cpp) auto-engages when ulfius ; headers are reachable via `#if __has_include()`. The `|| :` ; tail keeps the build green when the user hasn't run `brew install ulfius` ; - they just don't get the HTTP API in that case. !pkg-config --cflags --libs liborcania --silence-errors || : !pkg-config --cflags --libs libyder --silence-errors || : !pkg-config --cflags --libs libulfius --silence-errors || : ; src/input/Linux*.{cpp,h} drive evdev (``) which doesn't exist ; on macOS. graphics/Panel_sdl.* and graphics/TFTDisplay.cpp pull LovyanGFX ; (which we lib_ignore on macOS for the issue). Neither is needed ; for the headless build. build_src_filter = ${native_base.build_src_filter} - - - - ; LovyanGFX includes (Linux-only) and is only needed by TFT ; variants - not relevant for the headless macOS build. lib_ignore = ${portduino_base.lib_ignore} LovyanGFX ; --------------------------------------------------------------------------- ; Same as [env:native-macos] but built with AddressSanitizer for catching ; use-after-free, leaks, and OOB access during local development. Headless ; (no SDL/X11/libinput) so it stays cheap to build. Mirrors the shape of ; [env:native-tft-debug] but without the TFT/X11 dependencies. ; ; pio run -e native-macos-debug ; .pio/build/native-macos-debug/meshtasticd -s ; ; ASan runtime tuning (set in the shell before launching): ; ASAN_OPTIONS=detect_leaks=1:halt_on_error=0:abort_on_error=1 ; MallocStackLogging=1 # macOS: nicer stack traces in malloc reports ; --------------------------------------------------------------------------- [env:native-macos-debug] extends = native_base build_type = debug build_unflags = ${env:native-macos.build_unflags} build_flags = ${env:native-macos.build_flags} -O0 -g -fsanitize=address -fno-omit-frame-pointer build_src_filter = ${env:native-macos.build_src_filter} lib_ignore = ${env:native-macos.lib_ignore} ; --------------------------------------------------------------------------- ; Native build for Windows (x86_64) via the MSYS2 UCRT64 MinGW-w64 toolchain. ; Headless meshtasticd.exe running in SimRadio mode (`-s`). No BlueZ, libgpiod or ; Linux I2C, and no UDP multicast: the framework's AsyncUDP.cpp is BSD sockets, ; so HAS_UDP_MULTICAST stays unset here as it does on macOS. ; ; MSVC is not an option: platform-native's builder calls env.Tool("gcc") and the ; firmware builds as gnu17/gnu++17 with GNU extensions throughout. ; ; Prerequisites (MSYS2, https://www.msys2.org/): ; pacman -S --needed mingw-w64-ucrt-x86_64-{gcc,pkgconf,yaml-cpp,libuv,jsoncpp,openssl,libusb} ; ; argp is not packaged for MSYS2's mingw environments (msys/libargp links the ; msys-2.0.dll emulation layer and can't be used for a native binary), yet ; Arduino.h includes and main.cpp calls argp_parse(). Build it once from ; source, the same dependency macOS meets with `brew install argp-standalone`: ; git clone https://github.com/tom42/argp-standalone ; cd argp-standalone && cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=Release . ; cmake --build build ; cp include/argp-standalone/argp.h /ucrt64/include/argp.h ; ships no install() rules ; cp build/src/libargp-standalone.a /ucrt64/lib/libargp.a ; ; Build from any shell with /ucrt64/bin on PATH: ; pio run -e native-windows ; .pio/build/native-windows/meshtasticd.exe -s ; --------------------------------------------------------------------------- [env:native-windows] extends = native_base build_flags = ${portduino_base.build_flags_common} -I variants/native/portduino ; Our drop-in libpinedio-usb.h, replacing the libusb one: libusb can only reach ; a device bound to WinUSB, which means Zadig on every machine. See ; src/platform/portduino/windows/libpinedio_ch341dll.c. -I src/platform/portduino/windows/include -largp -lws2_32 ; GpsdSerial.cpp's TCP client -lbcrypt ; BCryptGenRandom() in HardwareRNG.cpp -liphlpapi ; GetAdaptersAddresses() host-MAC fallback in PortduinoGlue.cpp ; libch341's libpinedio-usb.h pulls in libusb.h and so , which ; collides with the Arduino API: winuser.h's `typedef struct tagINPUT INPUT` vs ; the PinMode enumerator, and rpcndr.h's `typedef unsigned char boolean` vs ; Arduino's `typedef bool boolean`. NOUSER and WIN32_LEAN_AND_MEAN keep those ; headers out, NOMINMAX stops min/max being macroed over std::min/std::max. -DWIN32_LEAN_AND_MEAN -DNOMINMAX -DNOUSER -DNOGDI ; yaml-cpp declares its API __declspec(dllimport) unless told the link is ; static, leaving every YAML symbol undefined as __imp_*. -DYAML_CPP_STATIC_DEFINE ; Headless: variant.h would otherwise default HAS_SCREEN to 1 and pull in the ; screen renderer; EXCLUDE_SCREEN gates the `screen->...` hooks in the sensors. -DHAS_SCREEN=0 -DMESHTASTIC_EXCLUDE_SCREEN=1 !pkg-config --cflags --libs openssl --silence-errors || : build_unflags = -fPIC ; ignored on Windows, where all code is position-independent ; Static link, so meshtasticd.exe stands alone and can't be hijacked by a stray ; System32 DLL. PlatformIO only feeds build_flags to the compile step, hence the script. extra_scripts = ${env.extra_scripts} post:extra_scripts/windows_link_flags.py ; LinuxInput drives evdev; Panel_sdl/TFTDisplay pull LovyanGFX. Neither is needed ; for the headless build. build_src_filter = ${native_base.build_src_filter} - - - - ; LovyanGFX includes and is only needed by the TFT variants. The pine64 ; libch341 is the libusb backend that libpinedio_ch341dll.c replaces; keeping both ; would duplicate every pinedio_* symbol. lib_ignore = ${portduino_base.lib_ignore} LovyanGFX Pine libch341-spi Userspace library ; --------------------------------------------------------------------------- ; WASM (Emscripten) - the portduino node compiled to WebAssembly, driving a real ; LoRa radio over WebUSB through a CH341 (src/platform/portduino/wasm/). The same ; setup()/loop() firmware that runs native, but the radio HAL talks WebUSB and ; the cooperative loop suspends via Asyncify. Software/CI build target; the radio ; path itself is hardware (CH341/WebUSB, Chromium). See the README in that dir. ; ; Toolchain comes from the meshtastic/platform-wasm PlatformIO platform (emcc/ ; em++). Prereq: an Emscripten SDK on PATH - `source /emsdk_env.sh` (or ; export EMSDK=) - so the platform builder can locate emcc. ; ; Build: pio run -e native-wasm -> .pio/build/native-wasm/meshnode.{mjs,wasm} ; --------------------------------------------------------------------------- [env:native-wasm] platform = # renovate: datasource=git-refs depName=platform-wasm packageName=https://github.com/meshtastic/platform-wasm gitBranch=master https://github.com/meshtastic/platform-wasm/archive/7834113c8ee05bedc6af9c9cce7f515a1560e2c6.zip framework = arduino board = wasm board_level = extra ; wasm-ld doesn't accept GNU ld's `-Wl,-Map,` (inherited from [env]); strip ; it. The linker map isn't meaningful for the emcc/Asyncify output anyway. build_unflags = -Wl,-Map,"${platformio.build_dir}"/output.map build_flags = ${arduino_base.build_flags} -I variants/native/portduino -I src/platform/portduino ; FIRST: our stub shadows the missing glibc header -I src/platform/portduino/wasm/stubs -I src/platform/portduino/wasm/include -I src/platform/portduino/wasm -D ARCH_PORTDUINO ; ARCH_PORTDUINO_WASM gates every wasm guard in the firmware (the glue/main ; entry points, the single-threaded cooperative paths, region/RNG, etc.). The ; platform's board.json also injects it, but define it here too so the build's ; correctness never hinges on an out-of-repo board file. -D ARCH_PORTDUINO_WASM -DRADIOLIB_EEPROM_UNSUPPORTED -fexceptions ; firmware uses gettimeofday(); the native toolchain pulls in ; transitively but emscripten doesn't, so force it. -include sys/time.h ; Headless browser node - no screen / GPS / I2C / sensors / host services. ; Same exclusions the standalone emcc build used; gate out hardware/host code ; the tab can't run (the EXCLUDE_* defines also keep LDF from pulling the libs). -DHAS_SCREEN=0 -DMESHTASTIC_EXCLUDE_SCREEN=1 -DMESHTASTIC_EXCLUDE_GPS=1 -DNO_GPS=1 -DNO_EXT_GPIO=1 -DMESHTASTIC_EXCLUDE_I2C=1 -DMESHTASTIC_EXCLUDE_ACCELEROMETER=1 -DMESHTASTIC_EXCLUDE_MAGNETOMETER=1 -DMESHTASTIC_EXCLUDE_AUDIO=1 -DMESHTASTIC_EXCLUDE_INPUTBROKER=1 -DMESHTASTIC_EXCLUDE_MQTT=1 -DMESHTASTIC_EXCLUDE_TZ=1 -DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR=1 -DMESHTASTIC_EXCLUDE_DETECTIONSENSOR=1 -DMESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION=1 -DMESHTASTIC_EXCLUDE_CANNEDMESSAGES=1 -DMESHTASTIC_EXCLUDE_STOREFORWARD=1 -DMESHTASTIC_EXCLUDE_SERIAL=1 -DMESHTASTIC_EXCLUDE_PAXCOUNTER=1 -DMESHTASTIC_EXCLUDE_WAYPOINT=1 ; The firmware-specific emcc *link* settings (exported fns, runtime methods, the ; WebUSB Asyncify import seam, the ES-module factory name) can't ride in ; build_flags - PlatformIO only feeds those to the compile step - so they're ; appended to LINKFLAGS by this post script. (The generic Asyncify/MODULARIZE/ ; memory flags and emsdk auto-location both come from the platform-wasm builder.) extra_scripts = ${env.extra_scripts} post:extra_scripts/wasm_link_flags.py ; chain+ so the EXCLUDE_* / HAS_SCREEN defines gate sensor/screen #includes out ; of LDF (otherwise it would try to build host/incompatible sensor libs). lib_ldf_mode = chain+ lib_deps = ${env.lib_deps} ${radiolib_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic/Crypto packageName=https://github.com/meshtastic/Crypto gitBranch=main https://github.com/meshtastic/Crypto/archive/591ff9a690e8168ccb7a36abde8d7783e448d395.zip # renovate: datasource=custom.pio depName=Melopero RV3028 packageName=melopero/library/Melopero RV3028 melopero/Melopero RV3028@1.2.0 lib_ignore = LovyanGFX SD ; Curated source set - the proven standalone emcc build's file list expressed as ; a PlatformIO filter. Deny everything, then add exactly what the browser node ; links: the wasm cooperative-loop entry, the mesh stack (top-level + generated), ; concurrency, the portduino glue, and the non-esp32 modules (the EXCLUDE_* ; defines gate the unwanted module bodies). serialization/ stays excluded - the ; wasm stub replaces MeshPacketSerializer (jsoncpp is MQTT-only). build_src_filter = -<*> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + -