diff --git a/extra_scripts/zps_observer.py b/extra_scripts/zps_observer.py new file mode 100644 index 0000000000..50018faa54 --- /dev/null +++ b/extra_scripts/zps_observer.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# trunk-ignore-all(ruff/F821) +# trunk-ignore-all(flake8/F821): For SConstruct imports +import re + +Import("env") + +# The ZPS module scans BLE through the NimBLE *host* API ble_gap_disc(), which the +# ESP-IDF only compiles when CONFIG_BT_NIMBLE_ROLE_OBSERVER=y. The base esp32 config +# disables the observer role to save flash (see variants/esp32/esp32-common.ini), so +# re-enable it ONLY when the ZPS module is actually built. This keeps a single flag +# (-DMESHTASTIC_EXCLUDE_ZPS) driving both the C++ module and the IDF sdkconfig. +# +# This runs as a pre: script, before the arduino framework builder reads +# custom_sdkconfig (PlatformIO core runs pre-scripts before $BUILD_SCRIPT). Appending +# to custom_sdkconfig changes its hash and triggers the framework's IDF rebuild path, +# but only for ZPS-enabled envs; for every normal build this is a no-op. +flags = env.GetProjectOption("build_flags", "") +if isinstance(flags, (list, tuple)): + flags = " ".join(flags) + +# Mirror the C semantics of `#if !MESHTASTIC_EXCLUDE_ZPS`: +# flag absent -> module enabled +# -DMESHTASTIC_EXCLUDE_ZPS=0 -> module enabled +# -DMESHTASTIC_EXCLUDE_ZPS or =1 (or anything else) -> module excluded +match = re.search(r"\bMESHTASTIC_EXCLUDE_ZPS\b(?:=(\S+))?", flags) +zps_enabled = (match is None) or (match.group(1) == "0") + +section = "env:" + env["PIOENV"] +config = env.GetProjectConfig() +if zps_enabled and config.has_option(section, "custom_sdkconfig"): + sdkconfig = env.GetProjectOption("custom_sdkconfig") + if "CONFIG_BT_NIMBLE_ROLE_OBSERVER" not in sdkconfig: + config.set( + section, + "custom_sdkconfig", + sdkconfig.rstrip("\n") + "\n CONFIG_BT_NIMBLE_ROLE_OBSERVER=y\n", + ) + print("[ZPS] module enabled -> CONFIG_BT_NIMBLE_ROLE_OBSERVER=y (IDF rebuild)") diff --git a/src/modules/esp32/ZPSModule.cpp b/src/modules/esp32/ZPSModule.cpp index 579158e32d..cb51f90acd 100644 --- a/src/modules/esp32/ZPSModule.cpp +++ b/src/modules/esp32/ZPSModule.cpp @@ -6,6 +6,8 @@ * Released under GPL v3 (see LICENSE file for details) */ +#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_ZPS + #include "ZPSModule.h" #include "Default.h" #include "MeshService.h" @@ -18,7 +20,13 @@ #if !defined(MESHTASTIC_EXCLUDE_BLUETOOTH) -#include "NimBLEDevice.h" +// Use the bundled NimBLE host stack directly (matching src/nimble/NimbleBluetooth.cpp). +// The external h2zero NimBLE-Arduino library (NimBLEDevice.h) is in lib_ignore since the +// pioarduino / arduino-esp32 3.x migration, so we talk to the raw host APIs instead. +#include "host/ble_gap.h" +#include "host/ble_hs.h" +#include "host/ble_hs_adv.h" +#include "host/ble_hs_id.h" #define BLE_MAX_REC 15 #define BLE_NO_RESULTS -1 // Indicates a BLE scan is in progress @@ -256,7 +264,7 @@ int32_t ZPSModule::runOnce() return 5000; } -uint64_t encodeBSS(uint8_t *bssid, uint8_t chan, uint8_t absRSSI) +uint64_t encodeBSS(const uint8_t *bssid, uint8_t chan, uint8_t absRSSI) { uint64_t netBytes = absRSSI & 0xff; netBytes <<= 8; @@ -270,7 +278,7 @@ uint64_t encodeBSS(uint8_t *bssid, uint8_t chan, uint8_t absRSSI) return netBytes; } -uint64_t encodeBLE(uint8_t *addr, uint8_t absRSSI) +uint64_t encodeBLE(const uint8_t *addr, uint8_t absRSSI) { uint64_t netBytes = absRSSI & 0xff; netBytes <<= 8; @@ -416,4 +424,6 @@ static int ble_scan(uint32_t duration, bool passive, bool dedup) return rc; } -#endif // MESHTASTIC_EXCLUDE_BLUETOOTH \ No newline at end of file +#endif // MESHTASTIC_EXCLUDE_BLUETOOTH + +#endif // ARCH_ESP32 && !MESHTASTIC_EXCLUDE_ZPS \ No newline at end of file diff --git a/src/modules/esp32/ZPSModule.h b/src/modules/esp32/ZPSModule.h index 10a1d34331..e3045bacc9 100644 --- a/src/modules/esp32/ZPSModule.h +++ b/src/modules/esp32/ZPSModule.h @@ -20,8 +20,8 @@ enum SCANSTATE { SCAN_NONE, SCAN_BSS_RUN, SCAN_BSS_DONE, SCAN_BLE_RUN, SCAN_BLE_ * Ingest a WiFi BSSID, channel and RSSI (or BLE address and RSSI) * and encode them into a packed uint64 */ -uint64_t encodeBSS(uint8_t *bssid, uint8_t chan, uint8_t absRSSI); -uint64_t encodeBLE(uint8_t *addr, uint8_t absRSSI); +uint64_t encodeBSS(const uint8_t *bssid, uint8_t chan, uint8_t absRSSI); +uint64_t encodeBLE(const uint8_t *addr, uint8_t absRSSI); class ZPSModule : public SinglePortModule, private concurrency::OSThread { diff --git a/variants/esp32/esp32-common.ini b/variants/esp32/esp32-common.ini index 4f302694a4..b3df558410 100644 --- a/variants/esp32/esp32-common.ini +++ b/variants/esp32/esp32-common.ini @@ -14,6 +14,7 @@ platform_packages = extra_scripts = ${env.extra_scripts} pre:extra_scripts/esp32_pre.py + pre:extra_scripts/zps_observer.py extra_scripts/esp32_extra.py build_src_filter =