mirror of
https://github.com/meshtastic/firmware.git
synced 2026-10-09 14:41:19 -04:00
* First attempt at sending message notifications on Linux
* Add files via upload
* Notifications: Use libnotify
Use libnotify for meshtasticd desktop notifications.
Add "HAS_LIBNOTIFY" macro to guard for builds where libnotify is expected.
This is not included in buildroot/openwrt builds. (no libnotify except when extra repos are added).
Install desktop icon in the correct location on Debian and Fedora packages.
Update dependencies in packaging and dockerfiles.
* Add libnotify to setup-native (GitHub Actions)
* Address review feedback on the meshtasticd notification path
- platformio.ini: only define HAS_LIBNOTIFY when pkg-config actually finds
libnotify. The probe previously ran unguarded and the macro was defined
unconditionally, so a native build without libnotify-dev both hard-failed at
config time and claimed the feature was available.
- Fix the sender lookup for develop's flattened NodeInfoLite: has_user/user.*
are gone, replaced by nodeInfoLiteHasUser() and direct long_name/short_name.
This is a silent semantic conflict - it merges cleanly but does not compile.
- Move the desktop notification off the packet path. notify_notification_show()
is a synchronous DBus round trip and meshtasticd's packet handling is
single-threaded, so a slow or wedged notification daemon could stall the
radio. handleReceived() now resolves the strings and queues them (bounded at
16); a dedicated worker owns every libnotify call.
- Stop retrying forever: a failed notify_init(), or three consecutive failed
shows, latches desktop notifications off instead of re-logging per message.
- NodeDB: the ARCH_PORTDUINO default-enable block was nested inside
#ifdef HAS_I2S, which Portduino never defines, so it never ran. Hoist it out.
* fix(portduino): close input-broker guard before the libnotify block
The libnotify implementation was inserted ahead of the #endif that closed
#if !MESHTASTIC_EXCLUDE_INPUTBROKER, so the file's trailing #endif closed
#if HAS_LIBNOTIFY instead and the input-broker conditional was never closed.
Every build target failed to preprocess:
src/modules/ExternalNotificationModule.cpp:630: error: unterminated #if
Close the guard immediately after handleInputEvent(), as develop does, so the
two conditionals stay independent and HAS_LIBNOTIFY still resolves when the
input broker is excluded.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013EZstXBJtzRyBmUD1h2FLs
* fix(portduino): back off desktop notifications instead of latching them off
notifyDisabled was doing two jobs: "libnotify looks unusable" and "the
destructor wants the worker to exit". Because the worker's only exit path was
also its only failure path, three failed shows turned notifications off for the
process lifetime with no way back. The packaged daemon is exactly that case:
bin/meshtasticd.service runs as User=meshtasticd and the rpm spec creates that
account with /sbin/nologin, so there is no session bus and every show() fails.
A stock install logged three warnings and then went silent forever, while
NodeDB now enables the module by default on Portduino.
Split the flag. notifyShutdown is destructor-only and remains the worker's one
exit; a retry window replaces the latch. After maxNotifyFailures the worker
arms a backoff (30s, doubling to a 15min cap), drops the queue rather than
holding stale popups, and keeps looping. The producer refuses to queue while
the window is open, so the retry is driven by the next message after it expires
rather than by a timer - no idle wakeups, no probe notifications. Any success
resets the backoff. notify_init() moved inside the loop so a retry can pick up
a session bus that was absent at startup.
The worker also no longer calls the LOG_ macros. RedirectablePrint formats into
a shared static buffer that nothing guards and every other writer to it is on
the main thread, so the worker now records the state change under the mutex it
already holds and reportNotifyStatus() emits it from portduinoNotify() and
runOnce(). Per-message failure spam becomes one line per transition: the reason
and retry interval when it goes down, and a line when it comes back.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013EZstXBJtzRyBmUD1h2FLs
* fix(portduino): sanitize mesh text before it reaches libnotify
The notification body was the raw decoded payload and the summary was a node
name, both attacker-controlled, and neither was checked before being handed to
libnotify. g_variant_new_string() rejects invalid UTF-8: a GLib CRITICAL and an
"[Invalid UTF-8]" body by default, and a hard abort under G_DEBUG=fatal-criticals,
so an unauthenticated mesh packet could terminate meshtasticd on any install
running with that flag. An embedded NUL separately truncated the body at the
first one, hiding the rest of the message.
Route both strings through sanitizedMeshText(), which replaces embedded NULs and
then applies the existing sanitizeUtf8() helper. TypeConversions already
sanitizes names on the way into NodeDB, but an abort is too sharp an edge to
leave resting on an invariant owned by another file.
Escape the body for Pango markup as well. Servers advertising "body-markup"
parse a markup subset there, so a message can inject formatting to dress itself
up as trusted UI, and where the server also advertises body-images or
body-hyperlinks it can inject tags that make the notification daemon fetch a
remote URL. The escaping is unconditional rather than gated on
notify_get_server_caps(): a caps query that fails, or goes stale across a daemon
restart, fails open, while on a server without body-markup the only cost is
entities rendering literally, and mesh text carries no markup worth preserving.
The summary is not escaped - the spec gives it no markup, so escaping it would
only ever show entities.
Also call notify_uninit() in the destructor, after the join: the worker owns
every libnotify call, so tearing down while it is still running would be a
use-after-uninit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013EZstXBJtzRyBmUD1h2FLs
* fix(portduino): gate the notification default-on behind HAS_LIBNOTIFY
The default-enable block was gated on ARCH_PORTDUINO, so a native build where
pkg-config could not find libnotify still shipped external_notification enabled.
portduinoNotify() is not compiled into that build, and native defines
EXT_NOTIFICATION_MODULE_OUTPUT as 0 with setup() guarding the pin writes behind
output > 0, so nothing was driven - it only exposed a config surface that can
do nothing. Gate it on the same macro that governs the code it exists to feed.
HAS_LIBNOTIFY is a build flag for the whole env and is simply absent when the
probe fails, so this reads as 0 on every other target, matching how
ExternalNotificationModule.cpp already tests it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013EZstXBJtzRyBmUD1h2FLs
* fix(portduino): fail closed when markup escaping returns NULL
escapedNotificationBody() returned its input unescaped if g_markup_escape_text()
gave back NULL, which would hand libnotify the exact attacker-controlled string
the function exists to neutralize. The branch is unreachable for the input we
pass - already sanitized to valid UTF-8, and GLib documents no NULL return for
it - but an error path whose fallback is the unsafe action is the wrong shape
for a helper on this boundary. Drop the body instead.
Also note in the doc comment why running this on the caller's thread does not
weaken the rule that the worker owns every libnotify call: it is a pure GLib
string function that touches no libnotify or DBus state.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013EZstXBJtzRyBmUD1h2FLs
* style: format ExternalNotificationModule.h per the pinned clang-format
Trunk Check Runner failed on c0d5ebff with "1 unformatted file" against this
header. The deviation is a brace-spacing fix that clang-format wants on the
rtttl stub's begin(): the formatter emitted it while reformatting this file for
an earlier commit, and I reverted it then as unrelated churn. It was not -
trunk's fmt check reports a modified file as a whole, so touching this header at
all surfaces that line, and dropping the formatter's output is what turned the
check red.
Verified with the version trunk.yaml pins, clang-format 20.1.0, rather than the
older one available locally: it is the only remaining deviation across the three
files this branch touches.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013EZstXBJtzRyBmUD1h2FLs
* fix(portduino): stop the libnotify probe swallowing native-tft's link flags
The docker arm64 builds failed to link native-tft:
libmeshtastic-device-ui.a(CURLService.cpp.o): undefined reference to symbol
'curl_easy_reset@@CURL_GNUTLS_3'
/lib/aarch64-linux-gnu/libcurl-gnutls.so.4: DSO missing from command line
-lcurl was never on the link line. The libnotify probe was the last line of
[native_base].build_flags, and an env extending it writes
build_flags = ${native_base.build_flags} -Os -lcurl -lX11 ...
so the interpolation appended those flags to the probe's own line. The result is
a single shell command ending in `... && echo -D HAS_LIBNOTIFY=1 || : -Os -lcurl
-lX11 -linput -lxkbcommon -ffunction-sections -fdata-sections -Wl,--gc-sections`,
where the trailing flags are arguments to echo when the probe succeeds and to `:`
when it fails. They never reach the compiler, and nothing reports it.
Three envs lost flags this way: native-tft and native-tft-debug (-lcurl -lX11
-linput -lxkbcommon), and native-fb (-lcurl, --gc-sections). env:native appends
nothing on that line, which is why the native test suite stayed green and this
stayed hidden until the module compiled and something actually tried to link.
Move the probe above `-I /usr/include` so a plain flag line ends the value, and
record the constraint so the next flag added here does not re-break it.
Verified with `pio project config --json-output`: before, the three envs carried
the flags inside the probe's command string; after, all three carry them as
build flags and no env still swallows any.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013EZstXBJtzRyBmUD1h2FLs
---------
Co-authored-by: Austin Lane <vidplace7@gmail.com>
Co-authored-by: Tom Fifield <tom@tomfifield.net>
Co-authored-by: Claude <noreply@anthropic.com>
539 lines
25 KiB
INI
539 lines
25 KiB
INI
[native_base]
|
|
extends = portduino_base
|
|
build_flags = ${portduino_base.build_flags} -I variants/native/portduino
|
|
; Optional desktop-notification support (see ExternalNotificationModule::portduinoNotify).
|
|
; Emit libnotify's flags *and* HAS_LIBNOTIFY=1 only when the .pc file is actually present,
|
|
; so a native build on a machine without libnotify-dev still configures and links - it just
|
|
; compiles the feature out. `|| :` keeps a failed probe from returning a non-zero exit code.
|
|
;
|
|
; Keep this off the last line. An env extending native_base writes
|
|
; `build_flags = ${native_base.build_flags} -Os -lcurl ...`, and the interpolation appends those
|
|
; flags to whatever line ends this value. Landing them on a `!` line makes them trailing
|
|
; arguments to echo or to `:` instead of compiler flags, and they vanish with no error.
|
|
!pkg-config --exists --silence-errors libnotify && pkg-config --cflags --libs libnotify && echo -D HAS_LIBNOTIFY=1 || :
|
|
-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(<led-matrix.h>) enables HAS_HUB75_NATIVE (see configuration.h). Absent -> no-op.
|
|
!pkg-config --cflags rgbmatrix --silence-errors || :
|
|
!pkg-config --libs rgbmatrix --silence-errors || :
|
|
; Each test suite runs inside its own scratch $HOME. Every suite that constructs a NodeDB loads and
|
|
; saves ~/.portduino/default/prefs/, and nothing cleared it, so state leaked suite -> suite within a
|
|
; run and then run -> every later run: test_nodedb_blocked's deliberately saturated node database
|
|
; was still resident 22 suites later, where test_admin_radio inherited it and failed four unrelated
|
|
; assertions. Registered here rather than only in bin/run-tests.sh so a bare `pio test` and CI get
|
|
; the same boundary. See bin/pio-test-isolate.sh.
|
|
; https://docs.platformio.org/en/latest/projectconf/sections/env/options/test/test_testing_command.html
|
|
; -s matches [env:coverage]. The sandbox above only covers $HOME, but portduinoSetup() searches
|
|
; ./config.yaml and /etc/meshtasticd/config.yaml - absolute, so no $HOME sandbox can hide it. On a
|
|
; host running meshtasticd that config selects the real LoRa module and the run proceeds into GPIO
|
|
; and SPI setup, so a test run would drive the developer's own radio. -s short-circuits ahead of the
|
|
; config search and returns before hardware init. Suites asserting behaviour that simradio changes
|
|
; (PKC selection) clear the flag themselves in setUp, after the radio choice is already made.
|
|
test_testing_command =
|
|
${platformio.src_dir}/../bin/pio-test-isolate.sh
|
|
${platformio.build_dir}/${this.__env__}/meshtasticd
|
|
-s
|
|
|
|
[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}
|
|
; Same per-suite scratch $HOME as [env:native] - see the note there and bin/pio-test-isolate.sh.
|
|
; https://docs.platformio.org/en/latest/projectconf/sections/env/options/test/test_testing_command.html
|
|
test_testing_command =
|
|
${platformio.src_dir}/../bin/pio-test-isolate.sh
|
|
${platformio.build_dir}/${this.__env__}/meshtasticd
|
|
-s
|
|
|
|
; Channel-table userPrefs: initDefaults() must reach every index, not just 0-2. The fixture header
|
|
; stands in for what bin/platformio-custom.py emits for a vendor who configured five channels.
|
|
[env:coverage-channel-table]
|
|
extends = env:coverage
|
|
build_flags = ${env:coverage.build_flags}
|
|
-include test/test_userprefs_channels/userprefs_fixture.h
|
|
test_filter =
|
|
test_userprefs_channels
|
|
|
|
[env:coverage-event-policy]
|
|
extends = env:coverage
|
|
build_flags = ${env:coverage.build_flags}
|
|
-DUSERPREFS_BLOCK_POSITION_ON_EVENT_CHANNEL=1
|
|
-include test/support/userprefs_event_channel.h
|
|
test_filter =
|
|
test_position_precision
|
|
test_event_channel_router
|
|
test_nexthop_routing
|
|
test_event_channel_phone_api
|
|
test_mqtt
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; 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 <bundleID>`.
|
|
; 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,<file>` 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,<file>`)
|
|
; 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 <openssl/*.h> 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(<ulfius.h>)`. 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 (`<linux/input.h>`) which doesn't exist
|
|
; on macOS. graphics/Panel_sdl.* and graphics/TFTDisplay.cpp pull LovyanGFX
|
|
; (which we lib_ignore on macOS for the <malloc.h> issue). Neither is needed
|
|
; for the headless build.
|
|
build_src_filter = ${native_base.build_src_filter}
|
|
-<input/LinuxInput.cpp>
|
|
-<input/LinuxInputImpl.cpp>
|
|
-<graphics/Panel_sdl.cpp>
|
|
-<graphics/TFTDisplay.cpp>
|
|
; LovyanGFX includes <malloc.h> (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 macOS MUI window. This is the normal meshtasticd application using
|
|
; the X11 driver via XQuartz; it intentionally has no simulator fixtures.
|
|
[env:native-macos-tft]
|
|
extends = env:native-macos
|
|
build_type = release
|
|
build_unflags = ${env:native-macos.build_unflags}
|
|
build_flags = ${env:native-macos.build_flags}
|
|
-I/opt/X11/include
|
|
-L/opt/X11/lib
|
|
!pkg-config --cflags --libs x11 --silence-errors || :
|
|
!pkg-config --cflags --libs libcurl --silence-errors || :
|
|
-DRAM_SIZE=16384
|
|
-DUSE_X11=1
|
|
-DHAS_TFT=1
|
|
-DLV_CACHE_DEF_SIZE=6291456
|
|
-DLV_BUILD_TEST=0
|
|
-DLV_USE_LIBINPUT=0
|
|
-DLV_LIBINPUT_XKB=0
|
|
-DLV_LVGL_H_INCLUDE_SIMPLE
|
|
-DLV_CONF_INCLUDE_SIMPLE
|
|
-DUSE_LOG_DEBUG
|
|
-DLOG_DEBUG_INC=\"DebugConfiguration.h\"
|
|
-DUSE_PACKET_API
|
|
-DVIEW_320x240
|
|
lib_deps =
|
|
${native_base.lib_deps}
|
|
${device-ui_base.lib_deps}
|
|
lib_ignore = ${portduino_base.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 <argp.h> 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
|
|
-ladvapi32 ; Service Control Manager entry points in windows/WindowsService.cpp
|
|
; libch341's libpinedio-usb.h pulls in libusb.h and so <windows.h>, 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}
|
|
-<input/LinuxInput.cpp>
|
|
-<input/LinuxInputImpl.cpp>
|
|
-<graphics/Panel_sdl.cpp>
|
|
-<graphics/TFTDisplay.cpp>
|
|
; LovyanGFX includes <malloc.h> 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
|
|
|
|
; Windows counterpart of [env:coverage-channel-table]; same flags, runnable on this host.
|
|
[env:native-windows-channel-table]
|
|
extends = env:native-windows
|
|
build_flags = ${env:native-windows.build_flags}
|
|
-include test/test_userprefs_channels/userprefs_fixture.h
|
|
test_filter =
|
|
test_userprefs_channels
|
|
|
|
; Windows counterpart of [env:coverage-event-policy]; same flags, runnable on this host.
|
|
[env:native-windows-event-policy]
|
|
extends = env:native-windows
|
|
build_flags = ${env:native-windows.build_flags}
|
|
-DUSERPREFS_BLOCK_POSITION_ON_EVENT_CHANNEL=1
|
|
-include test/support/userprefs_event_channel.h
|
|
test_filter = ${env:coverage-event-policy.test_filter}
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; 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>/emsdk_env.sh` (or
|
|
; export EMSDK=<path>) - 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,<file>` (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 <argp.h> 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 <sys/time.h> 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
|
|
; No PWM/RTTTL ringtone playback support in the browser node.
|
|
-DMESHTASTIC_EXCLUDE_RTTTL=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/1c817c2f27aa4593e07d0f7e13b3dbf8d980bcae.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 =
|
|
-<*>
|
|
+<main.cpp>
|
|
+<PowerFSM.cpp> +<Power.cpp> +<airtime.cpp> +<sleep.cpp>
|
|
+<RedirectablePrint.cpp> +<SerialConsole.cpp> +<Observer.cpp>
|
|
+<FSCommon.cpp> +<SafeFile.cpp> +<MessageStore.cpp> +<meshUtils.cpp> +<UptimeClock.cpp>
|
|
+<memGet.cpp> +<memory/> +<GpioLogic.cpp> +<PowerMon.cpp> +<SPILock.cpp>
|
|
+<xmodem.cpp> +<DisplayFormatters.cpp>
|
|
+<detect/ScanI2C.cpp> +<detect/ScanI2CTwoWire.cpp> +<detect/ScanI2CConsumer.cpp>
|
|
+<power/PowerHAL.cpp>
|
|
+<gps/RTC.cpp>
|
|
+<buzz/buzz.cpp> +<buzz/BuzzerFeedbackThread.cpp>
|
|
+<mesh/*.cpp> +<mesh/*.c>
|
|
; template-only, amalgamated into InterfacesTemplates.cpp
|
|
-<mesh/LR20x0Interface.cpp>
|
|
+<mesh/generated/>
|
|
+<concurrency/>
|
|
+<platform/portduino/PortduinoGlue.cpp> +<platform/portduino/SimRadio.cpp>
|
|
+<platform/portduino/wasm/>
|
|
+<modules/> -<modules/esp32/>
|