mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-16 16:41:33 +10:00
emdashes begone (#10847)
This commit is contained in:
@@ -349,7 +349,7 @@ void cpuDeepSleep(uint32_t msecToWake)
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
#endif
|
||||
|
||||
// User shutdown (DELAY_FOREVER / portMAX_DELAY): no RTC timer — align with nRF52 system_off semantics.
|
||||
// User shutdown (DELAY_FOREVER / portMAX_DELAY): no RTC timer - align with nRF52 system_off semantics.
|
||||
if (msecToWake != portMAX_DELAY)
|
||||
esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs
|
||||
esp_deep_sleep_start();
|
||||
|
||||
@@ -413,7 +413,7 @@ bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passke
|
||||
"Bluetooth\nPIN\n[M]" + configuredPasskeyText.substr(0, 3) + " " + configuredPasskeyText.substr(3, 6);
|
||||
// Use the pairing_pin notification type so the lockdown UI short-
|
||||
// circuit (Screen.cpp updateUiFrame) allows the overlay through
|
||||
// even on a locked device — see H13 audit fix. The banner content
|
||||
// even on a locked device - see H13 audit fix. The banner content
|
||||
// is the per-attempt ephemeral pair PIN, not operator content.
|
||||
graphics::BannerOverlayOptions opts;
|
||||
opts.message = ble_message.c_str();
|
||||
|
||||
@@ -125,7 +125,7 @@ bool readRegister(uint8_t address, uint8_t reg, uint8_t &value)
|
||||
twim->TXD.PTR = (uint32_t)®
|
||||
twim->TXD.MAXCNT = 1;
|
||||
// LASTTX_SUSPEND shortcut: peripheral suspends automatically after the TX
|
||||
// byte, so EVENTS_SUSPENDED is set before we even poll — no clearing race.
|
||||
// byte, so EVENTS_SUSPENDED is set before we even poll - no clearing race.
|
||||
twim->SHORTS = TWIM_SHORTS_LASTTX_SUSPEND_Msk;
|
||||
twim->TASKS_RESUME = 1;
|
||||
twim->TASKS_STARTTX = 1;
|
||||
|
||||
@@ -58,7 +58,7 @@ extern "C" void HardFault_Impl(uint32_t stack[])
|
||||
// RAM contents, zero the DEK / KEK / ephemeralKEK so they aren't sitting
|
||||
// in BSS for a fault dump to pick up. This is called from the asm naked
|
||||
// HardFault_Handler entry above, so we're effectively in the chip's
|
||||
// exception context — keep this strictly to in-RAM scrubbing, no flash
|
||||
// exception context - keep this strictly to in-RAM scrubbing, no flash
|
||||
// I/O, no logging.
|
||||
#ifdef MESHTASTIC_ENCRYPTED_STORAGE
|
||||
EncryptedStorage::secureWipeKeys();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Arduino.h — Zephyr compatibility shim for nRF54L15
|
||||
* Arduino.h - Zephyr compatibility shim for nRF54L15
|
||||
*
|
||||
* Provides the Arduino API surface expected by Meshtastic, backed by
|
||||
* Zephyr primitives. Only the subset actually used by Meshtastic is
|
||||
@@ -69,7 +69,7 @@ typedef uint16_t word;
|
||||
#define bit(b) (1UL << (b))
|
||||
#define lowByte(w) ((uint8_t)((w)&0xff))
|
||||
#define highByte(w) ((uint8_t)((w) >> 8))
|
||||
// word(h,l) — only define if not already defined (conflicts with typedef above)
|
||||
// word(h,l) - only define if not already defined (conflicts with typedef above)
|
||||
#undef word
|
||||
#define word(h, l) ((uint16_t)(((h) << 8) | (l)))
|
||||
|
||||
@@ -121,11 +121,11 @@ static inline void interrupts() {}
|
||||
static inline void noInterrupts() {}
|
||||
#define digitalPinToInterrupt(p) (p)
|
||||
|
||||
// ── portMAX_DELAY — freertosinc.h also defines this; let it win ──────────────
|
||||
// ── portMAX_DELAY - freertosinc.h also defines this; let it win ──────────────
|
||||
// We intentionally do NOT define portMAX_DELAY here. freertosinc.h defines
|
||||
// it for the FreeRTOS / Meshtastic threading layer and must not be overridden.
|
||||
|
||||
// ── Timing & system functions — declared with C linkage ──────────────────────
|
||||
// ── Timing & system functions - declared with C linkage ──────────────────────
|
||||
// buzz.cpp and others forward-declare delay() as extern "C"; keep linkage
|
||||
// consistent by wrapping in extern "C" here.
|
||||
#ifdef __cplusplus
|
||||
@@ -146,7 +146,7 @@ void yield(void);
|
||||
#include <cctype>
|
||||
#include <cstdarg>
|
||||
|
||||
// ── C++ STL — include BEFORE defining any min/max helpers ───────────────────
|
||||
// ── C++ STL - include BEFORE defining any min/max helpers ───────────────────
|
||||
// Include algorithm first so its min/max templates are in scope.
|
||||
// We must NOT define min/max as function-like macros: the C++ STL uses
|
||||
// 3-argument versions (min(a,b,comp)) that the preprocessor would treat as
|
||||
@@ -188,7 +188,7 @@ static inline long random(long lo, long hi)
|
||||
return hi > lo ? lo + rand() % (hi - lo) : lo;
|
||||
}
|
||||
|
||||
// ── GPIO — real Zephyr implementation (Phase 3) ──────────────────────────────
|
||||
// ── GPIO - real Zephyr implementation (Phase 3) ──────────────────────────────
|
||||
// Implemented in nrf54l15_arduino.cpp using Zephyr GPIO/SPI APIs.
|
||||
// Pin numbering: P0.n = n, P1.n = 16+n, P2.n = 32+n
|
||||
void pinMode(uint32_t pin, uint32_t mode);
|
||||
@@ -206,12 +206,12 @@ static inline void analogWrite(uint32_t, uint32_t) {}
|
||||
static inline void analogReadResolution(int) {}
|
||||
static inline void analogWriteResolution(int) {}
|
||||
|
||||
// ── __WFI — provided by CMSIS core_cm33.h; do NOT redefine here ─────────────
|
||||
// ── __WFI - provided by CMSIS core_cm33.h; do NOT redefine here ─────────────
|
||||
|
||||
// ── __FlashStringHelper — Arduino PROGMEM string class (no-op on Cortex-M) ──
|
||||
// ── __FlashStringHelper - Arduino PROGMEM string class (no-op on Cortex-M) ──
|
||||
class __FlashStringHelper;
|
||||
|
||||
// ── attachInterrupt / detachInterrupt — real Zephyr GPIO interrupt impl ──────
|
||||
// ── attachInterrupt / detachInterrupt - real Zephyr GPIO interrupt impl ──────
|
||||
typedef void (*voidFuncPtr)(void);
|
||||
void attachInterrupt(uint32_t pin, voidFuncPtr cb, int mode);
|
||||
void detachInterrupt(uint32_t pin);
|
||||
@@ -685,7 +685,7 @@ class HardwareSerial : public Stream
|
||||
String readStringUntil(char) { return String(); }
|
||||
};
|
||||
|
||||
// Uart — nRF52 BSP alias for HardwareSerial (used by GPS.h when ARCH_NRF52)
|
||||
// Uart - nRF52 BSP alias for HardwareSerial (used by GPS.h when ARCH_NRF52)
|
||||
typedef HardwareSerial Uart;
|
||||
|
||||
extern HardwareSerial Serial;
|
||||
@@ -715,7 +715,7 @@ static inline unsigned long pulseIn(uint8_t, uint8_t, unsigned long = 1000000UL)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ── strdup / stpcpy — POSIX extensions not in Zephyr newlib ─────────────────
|
||||
// ── strdup / stpcpy - POSIX extensions not in Zephyr newlib ─────────────────
|
||||
#ifndef strdup
|
||||
static inline char *strdup(const char *s)
|
||||
{
|
||||
@@ -735,14 +735,14 @@ static inline char *stpcpy(char *dst, const char *src)
|
||||
}
|
||||
#endif
|
||||
|
||||
// ── strnstr — BSD extension not in Zephyr libc; defined in meshUtils.cpp ─────
|
||||
// ── strnstr - BSD extension not in Zephyr libc; defined in meshUtils.cpp ─────
|
||||
// Declare here so callers (GPS.cpp etc.) don't need ARCH_PORTDUINO.
|
||||
#ifndef STRNSTR
|
||||
#define STRNSTR
|
||||
char *strnstr(const char *s, const char *find, size_t slen);
|
||||
#endif
|
||||
|
||||
// ── strlcpy — BSD extension; implementation in nrf54l15_arduino.cpp ──────────
|
||||
// ── strlcpy - BSD extension; implementation in nrf54l15_arduino.cpp ──────────
|
||||
#ifndef HAVE_STRLCPY
|
||||
#define HAVE_STRLCPY
|
||||
#ifdef __cplusplus
|
||||
@@ -754,7 +754,7 @@ size_t strlcpy(char *dst, const char *src, size_t size);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ── setenv / getenv / tzset — Zephyr stubs for timezone support ──────────────
|
||||
// ── setenv / getenv / tzset - Zephyr stubs for timezone support ──────────────
|
||||
#include <stdlib.h>
|
||||
static inline int setenv(const char *, const char *, int)
|
||||
{
|
||||
@@ -762,7 +762,7 @@ static inline int setenv(const char *, const char *, int)
|
||||
}
|
||||
static inline void tzset(void) {}
|
||||
|
||||
// ── dbgHeapFree / dbgHeapTotal — nRF52 BSP heap diagnostics ─────────────────
|
||||
// ── dbgHeapFree / dbgHeapTotal - nRF52 BSP heap diagnostics ─────────────────
|
||||
// Used by memGet.cpp when ARCH_NRF52 is defined. Return 0 for Phase 2.
|
||||
static inline uint32_t dbgHeapFree(void)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// IPAddress.h — stub for nRF54L15/Zephyr
|
||||
// IPAddress.h - stub for nRF54L15/Zephyr
|
||||
// MQTT.cpp includes this for IPv4 address representation.
|
||||
// Phase 2: compile-only stub.
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// InternalFileSystem.cpp — Zephyr LittleFS backend for nRF54L15
|
||||
// InternalFileSystem.cpp - Zephyr LittleFS backend for nRF54L15
|
||||
//
|
||||
// Implements Adafruit_LittleFS_Namespace used by FSCommon.h/cpp.
|
||||
// Storage: 36 KB storage_partition in nRF54L15 internal RRAM (defined in
|
||||
@@ -124,7 +124,7 @@ File InternalFileSystem::open(const char *path, const char *mode)
|
||||
// Open as a regular file
|
||||
fs_mode_t flags;
|
||||
if (strcmp(mode, FILE_O_WRITE) == 0) {
|
||||
// Truncate on write — unlink first to ensure a clean start
|
||||
// Truncate on write - unlink first to ensure a clean start
|
||||
fs_unlink(abs);
|
||||
flags = FS_O_WRITE | FS_O_CREATE;
|
||||
} else {
|
||||
@@ -198,7 +198,7 @@ bool InternalFileSystem::rmdir_r(const char *path)
|
||||
struct fs_dir_t dir;
|
||||
fs_dir_t_init(&dir);
|
||||
if (fs_opendir(&dir, abs) != 0) {
|
||||
// Not a directory — try to delete as file
|
||||
// Not a directory - try to delete as file
|
||||
return fs_unlink(abs) == 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// InternalFileSystem.h — Zephyr LittleFS backend for nRF54L15
|
||||
// InternalFileSystem.h - Zephyr LittleFS backend for nRF54L15
|
||||
//
|
||||
// Implements the Adafruit InternalFileSystem API subset used by Meshtastic,
|
||||
// backed by Zephyr's fs/littlefs on the storage_partition of the nRF54L15's
|
||||
// internal RRAM. Partition size is taken from the DTS at compile time via
|
||||
// FIXED_PARTITION_SIZE(storage_partition) — the DK overlay currently maps
|
||||
// FIXED_PARTITION_SIZE(storage_partition) - the DK overlay currently maps
|
||||
// ~700 KB into slot1 (see zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.overlay).
|
||||
//
|
||||
// Mount point: /lfs
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// NRF52Bluetooth.h — stub for nRF54L15/Zephyr
|
||||
// NRF52Bluetooth.h - stub for nRF54L15/Zephyr
|
||||
// main.h includes this when ARCH_NRF52 is defined.
|
||||
// Bluetooth is excluded (MESHTASTIC_EXCLUDE_BLUETOOTH=1); this satisfies the
|
||||
// include chain without pulling in the nRF52 Bluefruit SDK.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// NRF54L15Bluetooth.cpp — Zephyr BLE GATT peripheral for Meshtastic nRF54L15
|
||||
// NRF54L15Bluetooth.cpp - Zephyr BLE GATT peripheral for Meshtastic nRF54L15
|
||||
//
|
||||
// GATT profile (identical UUIDs to the nRF52 / NimBLE implementations):
|
||||
// Service: 6ba1b218-15a8-461f-9fa8-5dcae273eafd
|
||||
@@ -37,7 +37,7 @@
|
||||
#include <zephyr/sys/reboot.h>
|
||||
|
||||
// ── UUID definitions (little-endian per Bluetooth spec)
|
||||
// ─────────────────────── Syntax: replace hyphens with commas, prefix 0x —
|
||||
// ─────────────────────── Syntax: replace hyphens with commas, prefix 0x -
|
||||
// matches BT_UUID_128_ENCODE doc.
|
||||
|
||||
#define MESH_SVC_UUID_VAL BT_UUID_128_ENCODE(0x6ba1b218, 0x15a8, 0x461f, 0x9fa8, 0x5dcae273eafd)
|
||||
@@ -61,7 +61,7 @@ static K_MUTEX_DEFINE(ble_mutex);
|
||||
// no active connection. Caller MUST bt_conn_unref() when done.
|
||||
//
|
||||
// Reading `active_conn` outside this lock races with disconnected_cb which can
|
||||
// unref + null it on the BT RX thread — touching the freed pointer (even just
|
||||
// unref + null it on the BT RX thread - touching the freed pointer (even just
|
||||
// to bt_conn_ref it) is a use-after-free.
|
||||
static struct bt_conn *acquire_active_conn()
|
||||
{
|
||||
@@ -77,7 +77,7 @@ static struct bt_conn *acquire_active_conn()
|
||||
static bool bt_initialized = false; // bt_enable() called at most once
|
||||
static bool ble_enabled = false; // set by setup(), cleared by shutdown()
|
||||
|
||||
// Forward declarations — BT_GATT_SERVICE_DEFINE(mesh_svc, ...) is below, but
|
||||
// Forward declarations - BT_GATT_SERVICE_DEFINE(mesh_svc, ...) is below, but
|
||||
// read_fromradio() (defined earlier) needs to reference the service to notify
|
||||
// on fromNum after each non-empty read.
|
||||
#define FROMNUM_ATTR_IDX 2
|
||||
@@ -111,7 +111,7 @@ static void adv_restart_work_fn(struct k_work *work)
|
||||
static uint16_t fromnum_ccc_val = 0;
|
||||
static uint16_t logradio_ccc_val = 0;
|
||||
|
||||
// Scratch buffers — only one BLE operation at a time
|
||||
// Scratch buffers - only one BLE operation at a time
|
||||
static uint8_t fromRadioBytes[meshtastic_FromRadio_size];
|
||||
static size_t fromRadioLen = 0;
|
||||
static uint8_t toRadioBytes[meshtastic_ToRadio_size];
|
||||
@@ -127,7 +127,7 @@ static uint32_t fromNumValue = 0;
|
||||
// buffer under a mutex and let BleDeferredThread (running on the Meshtastic
|
||||
// OSThread scheduler, 24 KB stack) do the actual call outside the lock.
|
||||
//
|
||||
// The mutex makes the producer/consumer handoff race-free — producer may
|
||||
// The mutex makes the producer/consumer handoff race-free - producer may
|
||||
// overwrite a pending buffer the consumer hasn't read yet (dropped packet),
|
||||
// but partial reads / torn writes are impossible.
|
||||
K_MUTEX_DEFINE(pendingToRadioMutex);
|
||||
@@ -141,7 +141,7 @@ static bool pendingToRadio = false;
|
||||
// LE Disconnection Complete event to the host: when iOS tears down the link
|
||||
// (either explicitly by the user or via supervision timeout), the LL layer
|
||||
// drops the connection but disconnected_cb never fires, active_conn stays
|
||||
// non-null and advertising never restarts — the device vanishes from scans
|
||||
// non-null and advertising never restarts - the device vanishes from scans
|
||||
// until power cycle. Track the connected timestamp and the last time we
|
||||
// observed ATT traffic; a long ATT idle on an "active" connection means we
|
||||
// are zombied. A cold reboot is the only path that reliably recovers (any
|
||||
@@ -228,7 +228,7 @@ static ssize_t write_toradio(struct bt_conn *conn, const struct bt_gatt_attr *at
|
||||
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
|
||||
}
|
||||
|
||||
// Deduplicate — drop packet if identical to the last one we processed
|
||||
// Deduplicate - drop packet if identical to the last one we processed
|
||||
if (memcmp(lastToRadio, buf, len) != 0) {
|
||||
memcpy(lastToRadio, buf, len);
|
||||
if (len < MAX_TO_FROM_RADIO_SIZE) {
|
||||
@@ -236,7 +236,7 @@ static ssize_t write_toradio(struct bt_conn *conn, const struct bt_gatt_attr *at
|
||||
}
|
||||
// Defer handleToRadio() to BleDeferredThread (24 KB stack).
|
||||
// Running it here on bt_workq (6 KB) overflows during handleStartConfig.
|
||||
// Always overwrite pending — we already dedup'd above via lastToRadio,
|
||||
// Always overwrite pending - we already dedup'd above via lastToRadio,
|
||||
// so any new write here is genuinely new data that must be delivered.
|
||||
k_mutex_lock(&pendingToRadioMutex, K_FOREVER);
|
||||
memcpy(pendingToRadioBuf, buf, len);
|
||||
@@ -274,19 +274,19 @@ static ssize_t write_toradio(struct bt_conn *conn, const struct bt_gatt_attr *at
|
||||
|
||||
BT_GATT_SERVICE_DEFINE(mesh_svc, BT_GATT_PRIMARY_SERVICE(&mesh_svc_uuid.uuid),
|
||||
|
||||
// fromNum: READ | NOTIFY — packet-counter triggers phone to read fromRadio
|
||||
// fromNum: READ | NOTIFY - packet-counter triggers phone to read fromRadio
|
||||
BT_GATT_CHARACTERISTIC(&fromnum_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, MESH_PERM_READ,
|
||||
read_fromnum, NULL, &fromNumValue),
|
||||
BT_GATT_CCC(fromnum_ccc_changed, MESH_PERM_READ | MESH_PERM_WRITE),
|
||||
|
||||
// fromRadio: READ — phone polls this after receiving a fromNum notification
|
||||
// fromRadio: READ - phone polls this after receiving a fromNum notification
|
||||
BT_GATT_CHARACTERISTIC(&fromradio_uuid.uuid, BT_GATT_CHRC_READ, MESH_PERM_READ, read_fromradio, NULL,
|
||||
NULL),
|
||||
|
||||
// toRadio: WRITE — phone sends protobuf packets to the device
|
||||
// toRadio: WRITE - phone sends protobuf packets to the device
|
||||
BT_GATT_CHARACTERISTIC(&toradio_uuid.uuid, BT_GATT_CHRC_WRITE, MESH_PERM_WRITE, NULL, write_toradio, NULL),
|
||||
|
||||
// logRadio: READ | NOTIFY | INDICATE — log stream to phone when connected
|
||||
// logRadio: READ | NOTIFY | INDICATE - log stream to phone when connected
|
||||
BT_GATT_CHARACTERISTIC(&logradio_uuid.uuid,
|
||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_INDICATE, MESH_PERM_READ,
|
||||
read_logradio, NULL, NULL),
|
||||
@@ -308,7 +308,7 @@ BT_GATT_SERVICE_DEFINE(mesh_svc, BT_GATT_PRIMARY_SERVICE(&mesh_svc_uuid.uuid),
|
||||
// the subsequent bt_le_ext_adv_delete() sends LE Remove Advertising Set
|
||||
// (0x203c) which times out → kernel oops at hci_core.c:506.
|
||||
//
|
||||
// With CONFIG_BT_EXT_ADV=n the host uses pure legacy HCI commands — the same
|
||||
// With CONFIG_BT_EXT_ADV=n the host uses pure legacy HCI commands - the same
|
||||
// path Nordic NCS uses in all nRF54L15 examples (peripheral_uart,
|
||||
// peripheral_lbs) and which is universally iOS-compatible. The legacy data
|
||||
// payload is 31 bytes:
|
||||
@@ -328,7 +328,7 @@ static void start_advertising()
|
||||
|
||||
// Legacy scan-response payload is 31 bytes total. Each AD entry costs 2
|
||||
// bytes (length + type), leaving 29 bytes for the name. With
|
||||
// CONFIG_BT_DEVICE_NAME_MAX=32 the name can exceed that — truncate and
|
||||
// CONFIG_BT_DEVICE_NAME_MAX=32 the name can exceed that - truncate and
|
||||
// mark as SHORTENED so bt_le_adv_start() doesn't reject the payload.
|
||||
constexpr size_t LEGACY_SCAN_RSP_NAME_MAX = 31 - 2;
|
||||
bool name_shortened = full_name_len > LEGACY_SCAN_RSP_NAME_MAX;
|
||||
@@ -397,7 +397,7 @@ static void connected_cb(struct bt_conn *conn, uint8_t err)
|
||||
meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::CONNECTED);
|
||||
bluetoothStatus->updateStatus(&newStatus);
|
||||
|
||||
// nRF54L15-DK has no screen — cannot display a PIN to the user.
|
||||
// nRF54L15-DK has no screen - cannot display a PIN to the user.
|
||||
// Requesting BT_SECURITY_L2 causes the OS to show a pairing dialog that
|
||||
// the user dismisses, triggering disconnect + advertising restart failure.
|
||||
// Skip security negotiation; the Meshtastic app works over plain GATT.
|
||||
@@ -428,7 +428,7 @@ static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
|
||||
meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED);
|
||||
bluetoothStatus->updateStatus(&newStatus);
|
||||
|
||||
// Schedule advertising restart via work queue — NOT from this callback
|
||||
// Schedule advertising restart via work queue - NOT from this callback
|
||||
// directly. disconnected_cb runs on the BT RX thread; calling
|
||||
// bt_le_adv_start() here would deadlock (see adv_restart_work comment above).
|
||||
if (ble_enabled) {
|
||||
@@ -442,7 +442,7 @@ static void security_changed_cb(struct bt_conn *conn, bt_security_t level, enum
|
||||
if (err == BT_SECURITY_ERR_PIN_OR_KEY_MISSING) {
|
||||
// Phone has a stale bond (device was wiped/reflashed). Unpair the stale
|
||||
// entry so the phone re-pairs cleanly on the next connection attempt.
|
||||
LOG_WARN("BLE stale bond detected (key missing) — unpairing");
|
||||
LOG_WARN("BLE stale bond detected (key missing) - unpairing");
|
||||
bt_unpair(BT_ID_DEFAULT, bt_conn_get_dst(conn));
|
||||
bt_conn_disconnect(conn, BT_HCI_ERR_AUTH_FAIL);
|
||||
} else if (err) {
|
||||
@@ -523,7 +523,7 @@ void BluetoothPhoneAPI::onNowHasData(uint32_t fromRadioNum)
|
||||
return;
|
||||
|
||||
// active_conn may be torn down on another thread while we're dispatching
|
||||
// this notify — acquire under ble_mutex so disconnected_cb can't free the
|
||||
// this notify - acquire under ble_mutex so disconnected_cb can't free the
|
||||
// conn between the null check and bt_conn_ref.
|
||||
struct bt_conn *conn = acquire_active_conn();
|
||||
if (!conn)
|
||||
@@ -606,7 +606,7 @@ class BleDeferredThread : public concurrency::OSThread
|
||||
uint32_t now = k_uptime_get_32();
|
||||
uint32_t att_idle = now - last_att_time_ms;
|
||||
|
||||
// Liveness probe — only when ATT has been quiet for a while.
|
||||
// Liveness probe - only when ATT has been quiet for a while.
|
||||
if (att_idle > IDLE_BEFORE_PROBE_MS && (now - last_probe_ms) >= PROBE_INTERVAL_MS &&
|
||||
(fromnum_ccc_val & BT_GATT_CCC_NOTIFY)) {
|
||||
last_probe_ms = now;
|
||||
@@ -620,7 +620,7 @@ class BleDeferredThread : public concurrency::OSThread
|
||||
}
|
||||
bt_conn_unref(conn);
|
||||
|
||||
// Hard ceiling — last-resort reboot if probes miss the zombie.
|
||||
// Hard ceiling - last-resort reboot if probes miss the zombie.
|
||||
if (att_idle > HARD_WATCHDOG_MS && (now - connect_time_ms) > HARD_WATCHDOG_MS) {
|
||||
LOG_WARN("BLE zombie (hard watchdog %us); rebooting", HARD_WATCHDOG_MS / 1000);
|
||||
k_sleep(K_MSEC(50));
|
||||
@@ -635,7 +635,7 @@ static BleDeferredThread *bleDeferredThread = nullptr;
|
||||
// ── BT stack pre-initializer (call from main thread before OSThreads start) ──
|
||||
//
|
||||
// bt_enable() requires substantially more stack than a Meshtastic OSThread
|
||||
// (PowerFSMThread) provides — calling it there causes a stack overflow.
|
||||
// (PowerFSMThread) provides - calling it there causes a stack overflow.
|
||||
// Call this from nrf54l15Setup() (main Zephyr thread, CONFIG_MAIN_STACK_SIZE)
|
||||
// so that by the time NRF54L15Bluetooth::setup() runs from PowerFSMThread,
|
||||
// bt_initialized is already true and bt_enable() is skipped.
|
||||
@@ -653,7 +653,7 @@ void nrf54l15_bt_preinit()
|
||||
|
||||
// Phase 7: load bonding keys from LittleFS (/lfs/bt_settings).
|
||||
// LittleFS is already mounted by fsInit() before nrf54l15Setup() runs.
|
||||
// On first boot the file doesn't exist — settings_load() returns 0 (OK).
|
||||
// On first boot the file doesn't exist - settings_load() returns 0 (OK).
|
||||
// On subsequent boots, previously bonded peers are restored so the
|
||||
// phone can reconnect without re-pairing.
|
||||
err = settings_load();
|
||||
@@ -697,7 +697,7 @@ static bool nrf54l15_bt_init_common()
|
||||
bt_conn_auth_cb_register(&auth_cb);
|
||||
bt_conn_auth_info_cb_register(&auth_info_cb);
|
||||
|
||||
// FIXED_PIN — register the configured passkey so the mobile app prompts
|
||||
// FIXED_PIN - register the configured passkey so the mobile app prompts
|
||||
// the user for that specific number instead of a random display-only PIN.
|
||||
// RANDOM_PIN (and clamped NO_PIN) keeps the default behavior: Zephyr
|
||||
// generates a fresh passkey on each pairing attempt and fires
|
||||
@@ -797,7 +797,7 @@ void NRF54L15Bluetooth::sendLog(const uint8_t *logMessage, size_t length)
|
||||
return;
|
||||
}
|
||||
// Send as notify regardless of whether client subscribed to NOTIFY or
|
||||
// INDICATE — bt_gatt_indicate() requires a params struct with a callback;
|
||||
// INDICATE - bt_gatt_indicate() requires a params struct with a callback;
|
||||
// notify is simpler and the app accepts both. Change to indicate if
|
||||
// compatibility issues arise.
|
||||
bt_gatt_notify(conn, &mesh_svc.attrs[LOGRADIO_ATTR_IDX], logMessage, (uint16_t)length);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// NRF54L15Bluetooth.h — Zephyr BLE backend for nRF54L15
|
||||
// NRF54L15Bluetooth.h - Zephyr BLE backend for nRF54L15
|
||||
//
|
||||
// Implements the same interface as NRF52Bluetooth (same method names and
|
||||
// signatures) so main.cpp and AdminModule can use nrf52Bluetooth pointer
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Nrf52SaadcLock.h — stub for nRF54L15/Zephyr
|
||||
// Nrf52SaadcLock.h - stub for nRF54L15/Zephyr
|
||||
// Power.cpp includes this when ARCH_NRF52 is defined.
|
||||
// Phase 2: compile-only stub.
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Print.h — shim for nRF54L15/Zephyr
|
||||
// Print.h - shim for nRF54L15/Zephyr
|
||||
// Meshtastic includes <Print.h> separately; redirect to our Arduino.h shim.
|
||||
#pragma once
|
||||
#include "Arduino.h"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* SPI.h — Arduino SPI shim for Zephyr/nRF54L15
|
||||
* SPI.h - Arduino SPI shim for Zephyr/nRF54L15
|
||||
*
|
||||
* Provides the Arduino SPIClass interface backed by Zephyr's SPI API. The
|
||||
* backing controller is SPIM00 (HP domain, 3.0 V); the implementation in
|
||||
@@ -7,7 +7,7 @@
|
||||
* bus is configured in zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.overlay.
|
||||
* RadioLib uses ArduinoHal which calls transfer() byte-by-byte.
|
||||
*
|
||||
* CS pin is handled by RadioLib via digitalWrite() — hardware CS is not used.
|
||||
* CS pin is handled by RadioLib via digitalWrite() - hardware CS is not used.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@@ -25,7 +25,7 @@ struct SPISettings {
|
||||
uint8_t bitOrder;
|
||||
uint8_t dataMode;
|
||||
|
||||
// Arduino API allows `SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0))` — implicit form is intentional.
|
||||
// Arduino API allows `SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0))` - implicit form is intentional.
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
SPISettings(uint32_t clock = 4000000, uint8_t bitOrder = MSBFIRST, uint8_t dataMode = SPI_MODE0)
|
||||
: clock(clock), bitOrder(bitOrder), dataMode(dataMode)
|
||||
@@ -46,7 +46,7 @@ class SPIClass
|
||||
void setClockDivider(uint8_t div) {}
|
||||
void setFrequency(uint32_t freq) {}
|
||||
|
||||
// Real Zephyr SPI implementation — defined in nrf54l15_arduino.cpp
|
||||
// Real Zephyr SPI implementation - defined in nrf54l15_arduino.cpp
|
||||
uint8_t transfer(uint8_t data);
|
||||
uint16_t transfer16(uint16_t data);
|
||||
void transfer(void *buf, size_t count);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Stream.h — shim for nRF54L15/Zephyr
|
||||
// Stream.h - shim for nRF54L15/Zephyr
|
||||
// StreamAPI.h and other Meshtastic headers include <Stream.h>.
|
||||
// Redirect to our Arduino.h shim which defines the Stream base class.
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Tone.h — shim for nRF54L15/Zephyr
|
||||
// Tone.h - shim for nRF54L15/Zephyr
|
||||
// Tone functions are stubbed in Arduino.h; this header satisfies direct includes.
|
||||
#pragma once
|
||||
#include "Arduino.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// WProgram.h — shim for nRF54L15/Zephyr
|
||||
// WProgram.h - shim for nRF54L15/Zephyr
|
||||
// ArduinoThread (and other legacy Arduino libs) include <WProgram.h>.
|
||||
// Redirect to our Arduino.h shim.
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Wire.cpp — Arduino TwoWire backed by Zephyr i2c30 (TWIM30 hardware).
|
||||
// Wire.cpp - Arduino TwoWire backed by Zephyr i2c30 (TWIM30 hardware).
|
||||
//
|
||||
// The pinctrl + clock-frequency are configured in
|
||||
// zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.overlay. Runtime begin()/setClock()
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
// Resolve the i2c30 node at compile time. If the overlay has not enabled
|
||||
// i2c30, this evaluates to a NULL device pointer and every call short-circuits
|
||||
// to a NACK return code — matching the prior compile-only stub behavior.
|
||||
// to a NACK return code - matching the prior compile-only stub behavior.
|
||||
#define I2C_NODE DT_NODELABEL(i2c30)
|
||||
|
||||
static const struct device *getI2CDevice()
|
||||
@@ -49,7 +49,7 @@ void TwoWire::begin()
|
||||
|
||||
void TwoWire::begin(uint8_t /*sda*/, uint8_t /*scl*/)
|
||||
{
|
||||
// SDA/SCL fixed by overlay pinctrl — pin args ignored.
|
||||
// SDA/SCL fixed by overlay pinctrl - pin args ignored.
|
||||
begin();
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ void TwoWire::beginTransmission(uint8_t addr)
|
||||
size_t TwoWire::write(uint8_t data)
|
||||
{
|
||||
if (txLen >= WIRE_BUFFER_LENGTH) {
|
||||
return 0; // overflow — endTransmission() will return 1
|
||||
return 0; // overflow - endTransmission() will return 1
|
||||
}
|
||||
txBuf[txLen++] = data;
|
||||
return 1;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/**
|
||||
* Wire.h — Arduino TwoWire (I2C) shim for Zephyr / nRF54L15.
|
||||
* Wire.h - Arduino TwoWire (I2C) shim for Zephyr / nRF54L15.
|
||||
*
|
||||
* Bus binding: the Zephyr device tree alias `i2c30` (TWIM30 hardware
|
||||
* peripheral, HP domain, 3.0 V) is resolved at compile time via
|
||||
* DEVICE_DT_GET in Wire.cpp. SDA/SCL pins are configured in the board
|
||||
* overlay via pinctrl — `begin(sda, scl)` overloads are accepted for
|
||||
* overlay via pinctrl - `begin(sda, scl)` overloads are accepted for
|
||||
* Arduino API compatibility but the pin arguments are ignored.
|
||||
*
|
||||
* Buffer sizes are sized for the worst-case I2C consumer we plan to use
|
||||
@@ -28,7 +28,7 @@ class TwoWire
|
||||
TwoWire();
|
||||
|
||||
// ── Bus lifecycle ─────────────────────────────────────────────────
|
||||
// begin() variants — pin arguments are accepted for API compatibility
|
||||
// begin() variants - pin arguments are accepted for API compatibility
|
||||
// but ignored: SDA/SCL are fixed by the Zephyr overlay pinctrl. freq
|
||||
// is also fixed by overlay clock-frequency (use setClock() at runtime).
|
||||
void begin();
|
||||
@@ -63,7 +63,7 @@ class TwoWire
|
||||
size_t readBytes(char *buf, size_t len) { return readBytes((uint8_t *)buf, len); }
|
||||
void flush() {}
|
||||
|
||||
// Slave callbacks unsupported — peripheral-only stub.
|
||||
// Slave callbacks unsupported - peripheral-only stub.
|
||||
void onReceive(void (*)(int)) {}
|
||||
void onRequest(void (*)(void)) {}
|
||||
|
||||
@@ -80,4 +80,4 @@ class TwoWire
|
||||
};
|
||||
|
||||
extern TwoWire Wire;
|
||||
extern TwoWire Wire1; // alias to Wire — only one I2C bus on this board
|
||||
extern TwoWire Wire1; // alias to Wire - only one I2C bus on this board
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
// optional subsystem (BLE, screen, I2C, GPS, buttons, telemetry, sensors,
|
||||
// radio, CPU shutdown, ...) is wrapped in `#if HAS_FOO` so a given board
|
||||
// only pays for the features it actually ships. On memory-tight MCUs this
|
||||
// is not cosmetic — it's the difference between a binary that fits in
|
||||
// is not cosmetic - it's the difference between a binary that fits in
|
||||
// flash and one that doesn't, and between a build that links and one that
|
||||
// drags in drivers for hardware the board doesn't have. Defaulting to 0
|
||||
// here (rather than inheriting nRF52 defaults) is deliberate: the
|
||||
// nRF54L15-DK is a bare dev kit with no screen, no I2C sensors, no GPS,
|
||||
// no user buttons — so every HAS_* flag starts off and gets flipped on
|
||||
// no user buttons - so every HAS_* flag starts off and gets flipped on
|
||||
// explicitly by variants that add that hardware.
|
||||
//
|
||||
// Feature flags are also the cleanest way to absorb platform divergence
|
||||
@@ -24,8 +24,8 @@
|
||||
// to bring up the next board (flip the flags, don't patch call sites),
|
||||
// and keeps the "does this platform support X?" question answerable by
|
||||
// reading one file instead of grepping the tree. BLE in particular is
|
||||
// deferred to Phase 2 on this port — the nRF54L15 uses MPSL/Zephyr BLE
|
||||
// APIs rather than the Adafruit SoftDevice stack used by nRF52840 — so
|
||||
// deferred to Phase 2 on this port - the nRF54L15 uses MPSL/Zephyr BLE
|
||||
// APIs rather than the Adafruit SoftDevice stack used by nRF52840 - so
|
||||
// while HAS_BLUETOOTH defaults to 1, the actual implementation lives in
|
||||
// NRF54L15Bluetooth.cpp behind its own Zephyr Kconfig gates.
|
||||
//
|
||||
@@ -58,7 +58,7 @@
|
||||
#define HAS_CPU_SHUTDOWN 0
|
||||
#endif
|
||||
|
||||
// ADC reference — nRF54L15 SAADC uses VDD/4 internal ref by default
|
||||
// ADC reference - nRF54L15 SAADC uses VDD/4 internal ref by default
|
||||
#ifndef AREF_VOLTAGE
|
||||
#define AREF_VOLTAGE 3.6
|
||||
#endif
|
||||
@@ -67,7 +67,7 @@
|
||||
#endif
|
||||
|
||||
//
|
||||
// HW_VENDOR — maps build-time define to HardwareModel enum.
|
||||
// HW_VENDOR - maps build-time define to HardwareModel enum.
|
||||
// PRIVATE_HW (255): the protobuf HardwareModel enum reserves DK / DIY boards
|
||||
// without an SKU under this value; the nRF54L15-DK doesn't get a dedicated
|
||||
// enum number. Variant manifest matches via custom_meshtastic_hw_model = 255.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// bluefruit.h — stub for nRF54L15/Zephyr
|
||||
// bluefruit.h - stub for nRF54L15/Zephyr
|
||||
// NodeDB.cpp includes this when ARCH_NRF52 is defined.
|
||||
// Bluetooth is excluded (MESHTASTIC_EXCLUDE_BLUETOOTH=1); this satisfies
|
||||
// the include chain without pulling in the Adafruit Bluefruit SDK.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* main-nrf54l15.cpp — Platform entry points for Nordic nRF54L15
|
||||
* main-nrf54l15.cpp - Platform entry points for Nordic nRF54L15
|
||||
*
|
||||
* Adapted from src/platform/nrf52/main-nrf52.cpp.
|
||||
* SoftDevice, Adafruit BLE, and nRFCrypto are NOT available on nRF54L15.
|
||||
@@ -42,7 +42,7 @@ void variant_nrf54l15LoopHook(void) {}
|
||||
// ── PowerHAL ─────────────────────────────────────────────────────────────
|
||||
bool powerHAL_isVBUSConnected()
|
||||
{
|
||||
// TODO(nrf54l15): nRF54L15 has a USB POWER peripheral — read USBREGSTATUS
|
||||
// TODO(nrf54l15): nRF54L15 has a USB POWER peripheral - read USBREGSTATUS
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ void cpuDeepSleep(uint32_t msecToWake)
|
||||
delay(msecToWake);
|
||||
NVIC_SystemReset();
|
||||
} else {
|
||||
// System off equivalent — halt
|
||||
// System off equivalent - halt
|
||||
while (1) {
|
||||
__WFI();
|
||||
}
|
||||
@@ -173,7 +173,7 @@ void cpuDeepSleep(uint32_t msecToWake)
|
||||
}
|
||||
|
||||
// ── Setup / Loop ──────────────────────────────────────────────────────────
|
||||
// Forward declaration — defined in NRF54L15Bluetooth.cpp
|
||||
// Forward declaration - defined in NRF54L15Bluetooth.cpp
|
||||
void nrf54l15_bt_preinit();
|
||||
|
||||
void nrf54l15Setup()
|
||||
@@ -198,7 +198,7 @@ void nrf54l15Setup()
|
||||
|
||||
void nrf54l15Loop()
|
||||
{
|
||||
// First-call gate for the future WDT init — body will hold real init code, not just the bookkeeping flag.
|
||||
// First-call gate for the future WDT init - body will hold real init code, not just the bookkeeping flag.
|
||||
// cppcheck-suppress duplicateConditionalAssign
|
||||
if (!watchdog_running) {
|
||||
// TODO(nrf54l15): enable WDT here
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* nrf54l15_arduino.cpp — Arduino shim implementations for Zephyr/nRF54L15
|
||||
* nrf54l15_arduino.cpp - Arduino shim implementations for Zephyr/nRF54L15
|
||||
*
|
||||
* Provides concrete implementations for Print, HardwareSerial, GPIO, SPI,
|
||||
* and String methods declared in Arduino.h / SPI.h.
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "bluefruit.h"
|
||||
BlueFruitClass Bluefruit;
|
||||
|
||||
// ── _fini stub — ARM newlib's __libc_fini_array references _fini, but ────────
|
||||
// ── _fini stub - ARM newlib's __libc_fini_array references _fini, but ────────
|
||||
// Zephyr startup doesn't provide it. Provide a weak no-op so the linker
|
||||
// is satisfied when C++ global dtors or atexit() pull in __libc_fini_array.
|
||||
extern "C" void __attribute__((weak)) _fini(void) {}
|
||||
@@ -38,7 +38,7 @@ HardwareSerial Serial;
|
||||
HardwareSerial Serial1;
|
||||
HardwareSerial Serial2;
|
||||
|
||||
// ── Timing functions — C linkage to match extern "C" declarations ────────────
|
||||
// ── Timing functions - C linkage to match extern "C" declarations ────────────
|
||||
extern "C" uint32_t millis(void)
|
||||
{
|
||||
return (uint32_t)k_uptime_get_32();
|
||||
@@ -60,7 +60,7 @@ extern "C" void yield(void)
|
||||
k_yield();
|
||||
}
|
||||
|
||||
// ── NVIC_SystemReset — wraps __NVIC_SystemReset from CMSIS core_cm33.h ───────
|
||||
// ── NVIC_SystemReset - wraps __NVIC_SystemReset from CMSIS core_cm33.h ───────
|
||||
// core_cm33.h has #define NVIC_SystemReset __NVIC_SystemReset, so undef it
|
||||
// before defining our own implementation to prevent macro expansion collision.
|
||||
#pragma push_macro("NVIC_SystemReset")
|
||||
@@ -100,7 +100,7 @@ int Print::printf(const char *fmt, ...)
|
||||
return n;
|
||||
}
|
||||
|
||||
// ── strlcpy — BSD extension not in Zephyr newlib ────────────────────────────
|
||||
// ── strlcpy - BSD extension not in Zephyr newlib ────────────────────────────
|
||||
extern "C" size_t strlcpy(char *dst, const char *src, size_t size)
|
||||
{
|
||||
size_t len = strlen(src);
|
||||
@@ -211,7 +211,7 @@ void String::replace(const String &from, const String &to)
|
||||
{
|
||||
if (from.isEmpty() || !_buf)
|
||||
return;
|
||||
// Simple O(n²) replace — fine for typical Meshtastic string lengths
|
||||
// Simple O(n²) replace - fine for typical Meshtastic string lengths
|
||||
String result;
|
||||
const char *p = _buf;
|
||||
while (*p) {
|
||||
@@ -226,7 +226,7 @@ void String::replace(const String &from, const String &to)
|
||||
}
|
||||
|
||||
// ═════════════════════════════════════════════════════════════════════════════
|
||||
// GPIO — Real Zephyr implementation (Phase 3)
|
||||
// GPIO - Real Zephyr implementation (Phase 3)
|
||||
// Pin mapping: P0.n = n (0-15), P1.n = 16+n (16-31), P2.n = 32+n (32-47)
|
||||
// ═════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
@@ -269,7 +269,7 @@ void pinMode(uint32_t pin, uint32_t mode)
|
||||
gpio_pin_configure(dev, zpin, flags);
|
||||
}
|
||||
|
||||
// Bring-up diagnostics for the SX1262 wiring path. Off by default — enable by
|
||||
// Bring-up diagnostics for the SX1262 wiring path. Off by default - enable by
|
||||
// adding `-DNRF54L15_GPIO_DEBUG` to platformio.ini build_flags. Useful when
|
||||
// validating CS/NRESET toggles after a wiring change, diagnosing a "stuck HIGH"
|
||||
// BUSY before the first NRESET pulse, or tracing BUSY transitions during early
|
||||
@@ -303,7 +303,7 @@ void digitalWrite(uint32_t pin, uint32_t value)
|
||||
gpio_pin_t zpin;
|
||||
const struct device *dev = _gpio_dev_for_pin(pin, &zpin);
|
||||
if (!device_is_ready(dev)) {
|
||||
// Genuine hardware/DTS misconfiguration — keep this regardless of the
|
||||
// Genuine hardware/DTS misconfiguration - keep this regardless of the
|
||||
// GPIO_DEBUG gate so it surfaces in production builds too.
|
||||
printk("[GPIO] pin%u dev NOT READY\n", (unsigned)pin);
|
||||
return;
|
||||
@@ -351,7 +351,7 @@ int digitalRead(uint32_t pin)
|
||||
return v;
|
||||
}
|
||||
|
||||
// ─── attachInterrupt — supports up to NRF54L15_MAX_IRQS pins ────────────────
|
||||
// ─── attachInterrupt - supports up to NRF54L15_MAX_IRQS pins ────────────────
|
||||
#define NRF54L15_MAX_IRQS 8
|
||||
|
||||
struct _PinIrq {
|
||||
@@ -432,12 +432,12 @@ void detachInterrupt(uint32_t pin)
|
||||
}
|
||||
|
||||
// ═════════════════════════════════════════════════════════════════════════════
|
||||
// SPI — Real Zephyr implementation using SPIM00 (HP domain, 3.0V)
|
||||
// CS is handled by RadioLib via digitalWrite() — hardware CS not used.
|
||||
// SPI - Real Zephyr implementation using SPIM00 (HP domain, 3.0V)
|
||||
// CS is handled by RadioLib via digitalWrite() - hardware CS not used.
|
||||
// Mode 0 (CPOL=0, CPHA=0), MSB first.
|
||||
// ═════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
// Use SPIM00 (HP domain, 3.0V) — SPIM20 is 1.8V LP domain, incompatible with SX1262.
|
||||
// Use SPIM00 (HP domain, 3.0V) - SPIM20 is 1.8V LP domain, incompatible with SX1262.
|
||||
// Lazy-init: DEVICE_DT_GET in global scope fails when the extern symbol is
|
||||
// not visible in this translation unit. Use a function-local static instead.
|
||||
static const struct device *_spi00(void)
|
||||
@@ -463,13 +463,13 @@ static const struct device *_spi00(void)
|
||||
// 1 MHz → prescaler = 128 > 126 → NRFX_ERROR_INVALID_PARAM → -EIO on every
|
||||
// transfer. Minimum valid frequency is 2 MHz (prescaler = 64).
|
||||
static const struct spi_config _spi00_cfg = {
|
||||
.frequency = 2000000U, // 2 MHz — minimum valid for SPIM00 at 128 MHz base
|
||||
.frequency = 2000000U, // 2 MHz - minimum valid for SPIM00 at 128 MHz base
|
||||
.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB,
|
||||
.slave = 0,
|
||||
.cs = {}, // CS = NULL → RadioLib handles CS via GPIO
|
||||
};
|
||||
|
||||
// Static DMA buffers — stack-allocated bufs on nRF54L15 may not be reachable
|
||||
// Static DMA buffers - stack-allocated bufs on nRF54L15 may not be reachable
|
||||
// by SPIM20 EasyDMA. Static placement in .bss/.data is always in Global SRAM.
|
||||
// rx_byte is pre-filled with 0xAA before every transfer so we can distinguish:
|
||||
// 0xAA → DMA never wrote (EasyDMA can't reach the buffer)
|
||||
@@ -510,7 +510,7 @@ uint8_t SPIClass::transfer(uint8_t data)
|
||||
return _spi_rx_byte;
|
||||
}
|
||||
|
||||
// Static DMA-safe buffers for transfer16 — same EasyDMA reachability concern
|
||||
// Static DMA-safe buffers for transfer16 - same EasyDMA reachability concern
|
||||
// applies as for the byte path: stack buffers from a caller thread may sit in
|
||||
// per-thread RAM regions that EasyDMA cannot reach.
|
||||
static uint8_t _spi_tx16[2] __attribute__((aligned(4)));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* nrf54l15_main.cpp — Zephyr entry point for Meshtastic nRF54L15 port
|
||||
* nrf54l15_main.cpp - Zephyr entry point for Meshtastic nRF54L15 port
|
||||
*
|
||||
* Zephyr calls main() instead of Arduino's setup()/loop().
|
||||
* This file provides the main() that bootstraps the Arduino-style
|
||||
@@ -34,7 +34,7 @@ static struct crash_info saved_crash __attribute__((section(".noinit")));
|
||||
// Override Zephyr's weak fatal handler to save crash info, then cold-reboot so
|
||||
// main() can report the saved record on the next boot. We don't rely on
|
||||
// CONFIG_RESET_ON_FATAL_ERROR (default off → k_fatal_halt would spin forever)
|
||||
// — we issue sys_reboot() ourselves after flushing logs.
|
||||
// - we issue sys_reboot() ourselves after flushing logs.
|
||||
extern "C" void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *esf)
|
||||
{
|
||||
saved_crash.magic = CRASH_MAGIC;
|
||||
@@ -55,7 +55,7 @@ extern "C" void k_sys_fatal_error_handler(unsigned int reason, const struct arch
|
||||
saved_crash.cfsr);
|
||||
|
||||
// Walk the failing thread's stack and print any word that looks like a
|
||||
// Thumb code address (0x1000 — flash end, with the Thumb-mode low bit set).
|
||||
// Thumb code address (0x1000 - flash end, with the Thumb-mode low bit set).
|
||||
// The Cortex-M exception frame at PSP holds r0,r1,r2,r3,r12,lr,pc,xpsr
|
||||
// (8 words); deeper words are the caller's saved frame, which gives a
|
||||
// crude but useful poor-man's backtrace when CONFIG_DEBUG_COREDUMP is off.
|
||||
@@ -64,7 +64,7 @@ extern "C" void k_sys_fatal_error_handler(unsigned int reason, const struct arch
|
||||
// abort itself. Cheap (~150 B of code) and silent until a fault.
|
||||
uint32_t psp;
|
||||
__asm__ volatile("mrs %0, psp" : "=r"(psp));
|
||||
printk("[nrf54l15] PSP=0x%08x — stack walk:\n", psp);
|
||||
printk("[nrf54l15] PSP=0x%08x - stack walk:\n", psp);
|
||||
// Validate PSP before dereferencing. Real faults frequently leave PSP
|
||||
// pointing at corrupted/unmapped memory, and walking it blindly triggers a
|
||||
// second fault inside this handler. Restrict to nRF54L15 SRAM (256 KB at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// utility/bonding.h — stub for nRF54L15/Zephyr
|
||||
// utility/bonding.h - stub for nRF54L15/Zephyr
|
||||
// NodeDB.cpp includes this when ARCH_NRF52 is defined.
|
||||
// Bluetooth is excluded; this stub satisfies the include chain.
|
||||
#pragma once
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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.
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#define STM32WL_FLASH_BASE (FLASH_BASE)
|
||||
|
||||
/*
|
||||
* LFS tunables — all of these are stored in the LFS superblock.
|
||||
* LFS tunables - all of these are stored in the LFS superblock.
|
||||
* Changing ANY of them is incompatible with the existing on-disk format;
|
||||
* the filesystem will be detected as corrupted and reformatted on first boot.
|
||||
*
|
||||
@@ -43,7 +43,7 @@
|
||||
* FLASH_END_ADDR is computed from FLASH_SIZE (read from the chip at link time).
|
||||
*/
|
||||
#define LFS_FLASH_TOTAL_SIZE \
|
||||
(7 * STM32WL_PAGE_SIZE) /* 14 KiB — last 7 physical pages (FORMAT BREAK: reduced from 10 pages / 20 KiB) */
|
||||
(7 * STM32WL_PAGE_SIZE) /* 14 KiB - last 7 physical pages (FORMAT BREAK: reduced from 10 pages / 20 KiB) */
|
||||
#define LFS_BLOCK_SIZE (256) /* virtual block size (FORMAT BREAK if changed) */
|
||||
|
||||
#define LFS_FLASH_ADDR_END (FLASH_END_ADDR)
|
||||
|
||||
@@ -393,7 +393,7 @@ void File::rewindDirectory(void)
|
||||
_fs->_unlockFS();
|
||||
}
|
||||
|
||||
// Default constructor — binds to the global InternalFS instance.
|
||||
// Default constructor - binds to the global InternalFS instance.
|
||||
// Allows File to be declared without an explicit filesystem argument,
|
||||
// matching the API of ESP32/RP2040/Portduino File objects.
|
||||
File::File() : File(InternalFS) {}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#define BOOTLOADER_MAGIC 0xD00DB007UL
|
||||
#define SYS_MEM_BASE 0x1FFF0000UL
|
||||
|
||||
// Placed in .noinit — not zeroed at startup, survives NVIC_SystemReset().
|
||||
// Placed in .noinit - not zeroed at startup, survives NVIC_SystemReset().
|
||||
__attribute__((section(".noinit"), used)) volatile uint32_t g_bootloaderMagic;
|
||||
|
||||
// Fires before main() / HAL_Init(). Must use only core Cortex-M registers.
|
||||
|
||||
Reference in New Issue
Block a user