* Fix heap blowout on TBeams
* Update src/graphics/draw/MessageRenderer.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Set MESSAGE_HISTORY_LIMIT to 10 for original ESP32 to optimize RAM usage
* Optimize message frame allocation to prevent excessive memory usage
* Refine message history limits for resource-constrained builds and cap cached lines to prevent heap overflow
* Update src/graphics/draw/MessageRenderer.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix(native): implement BinarySemaphorePosix with proper pthread synchronization
The BinarySemaphorePosix class (used on all Linux/portduino/native builds)
had stub implementations: give() was a no-op and take() just called
delay(msec) and returned false. This broke the cooperative thread scheduler
on native platforms — threads could not wake the main loop, radio RX
interrupts were missed, and telemetry never transmitted over the mesh.
Replace the stubs with a proper binary semaphore using pthread_mutex_t +
pthread_cond_t + bool signaled:
- take(msec): pthread_cond_timedwait with CLOCK_REALTIME timeout, consumes
signal atomically (binary semaphore semantics)
- give(): sets signaled=true, signals condition variable
- giveFromISR(): delegates to give(), sets pxHigherPriorityTaskWoken
Tested on Raspberry Pi 3 Model B (ARM64, Debian Bookworm) with Adafruit
LoRa Radio Bonnet (SX1276). Before fix: no radio TX/RX, no telemetry on
mesh. After fix: bidirectional LoRa, MQTT gateway, telemetry all working.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ARCH_PORTDUINO
* Refactor BinarySemaphorePosix header for ARCH_PORTDUINO
* Change preprocessor directive from ifndef to ifdef
* Gate new Semaphore code to Portduino and fix STM compilation
* Binary Semaphore Posix better error handling
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
* fix(native): implement BinarySemaphorePosix with proper pthread synchronization
The BinarySemaphorePosix class (used on all Linux/portduino/native builds)
had stub implementations: give() was a no-op and take() just called
delay(msec) and returned false. This broke the cooperative thread scheduler
on native platforms — threads could not wake the main loop, radio RX
interrupts were missed, and telemetry never transmitted over the mesh.
Replace the stubs with a proper binary semaphore using pthread_mutex_t +
pthread_cond_t + bool signaled:
- take(msec): pthread_cond_timedwait with CLOCK_REALTIME timeout, consumes
signal atomically (binary semaphore semantics)
- give(): sets signaled=true, signals condition variable
- giveFromISR(): delegates to give(), sets pxHigherPriorityTaskWoken
Tested on Raspberry Pi 3 Model B (ARM64, Debian Bookworm) with Adafruit
LoRa Radio Bonnet (SX1276). Before fix: no radio TX/RX, no telemetry on
mesh. After fix: bidirectional LoRa, MQTT gateway, telemetry all working.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ARCH_PORTDUINO
* Refactor BinarySemaphorePosix header for ARCH_PORTDUINO
* Change preprocessor directive from ifndef to ifdef
* Gate new Semaphore code to Portduino and fix STM compilation
* Binary Semaphore Posix better error handling
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
* Add powerlimits to reconfigured radio settings as well as init settings.
* Refactor preamble length handling for wide LoRa configurations
* Moved the preamble setting to the main class and made the references static
MQTT password was logged in cleartext via LOG_INFO when connecting to
the broker, exposing credentials to anyone with log access. Replace
the password format specifier with a static mask.
Co-authored-by: Patrickschell609 <patrickschell609@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Consolidate SHTs into one class
* Remove separate SHT imports
* Create one single SHTXX sensor type
* Let the SHTXXSensor class handle variant detection
* Minor logging improvements
* Add functions to set accuracy on SHT3X and SHT4X
* Fix variable init in constructor
* Add bus to SHT sensor init
* Update src/modules/Telemetry/Sensor/SHTXXSensor.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/modules/Telemetry/Sensor/SHTXXSensor.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Fix accuracy conditions on SHTXX
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Merge upstream
* Add SHT2X detection on 0x40
* Read second part of SHT2X serial number
---------
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
SerialModule's weather station parser divides by velCount and dirCount
to compute wind speed/direction averages. Both counters are only
incremented when their respective sensor readings arrive, but the
division runs whenever gotwind is true (set by EITHER reading) and
the averaging interval has elapsed.
If only WindDir arrives without WindSpeed (or vice versa), or if the
timer fires before any readings accumulate, the division produces
undefined behavior (floating-point divide by zero on embedded = NaN
or hardware fault depending on platform).
Fix: add velCount > 0 && dirCount > 0 guard to the averaging block.
Co-authored-by: Patrickschell609 <patrickschell609@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
* fix MESHTASTIC_EXCLUDE_SCREEN
* mesh-tab map constraints (2 MB PSRAM)
* point MUI commit to the related PR
---------
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
* Fix TAG low‑voltage reboot hang after App configuration
* nRF52: Move low-VDD System OFF logic to variant hook
* Addressed review
* serialize SAADC access with shared mutex for VDD and battery reads
* raise LPCOMP wake threshold to ensure rising-edge wake
* Trunk fmt
---------
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
* fix(routing): prevent licensed users from rebroadcasting packets from unlicensed or unknown users
* fix(routing): prevent licensed users from rebroadcasting packets to or from unlicensed users
---------
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
The W5100S Ethernet chip has only 4 hardware sockets. On RAK4631
Ethernet gateways with syslog and NTP enabled, all 4 sockets were
permanently consumed (NTP UDP + Syslog UDP + TCP API listener + TCP
API client), leaving none for MQTT, DHCP lease renewal, or additional
TCP connections.
- NTP: Remove permanent timeClient.begin() at startup; NTPClient::update()
auto-initializes when needed. Add timeClient.end() after each query to
release the UDP socket immediately.
- Syslog: Remove socket allocation from Syslog::enable(). Open and close
the UDP socket on-demand in _sendLog() around each message send.
- MQTT: Fix socket leak in isValidConfig() where a successful test
connection was never closed (PubSubClient destructor does not call
disconnect). Add explicit pubSub->disconnect() before returning.
Made-with: Cursor
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
The W5100S Ethernet chip has only 4 hardware sockets. On RAK4631
Ethernet gateways with syslog and NTP enabled, all 4 sockets were
permanently consumed (NTP UDP + Syslog UDP + TCP API listener + TCP
API client), leaving none for MQTT, DHCP lease renewal, or additional
TCP connections.
- NTP: Remove permanent timeClient.begin() at startup; NTPClient::update()
auto-initializes when needed. Add timeClient.end() after each query to
release the UDP socket immediately.
- Syslog: Remove socket allocation from Syslog::enable(). Open and close
the UDP socket on-demand in _sendLog() around each message send.
- MQTT: Fix socket leak in isValidConfig() where a successful test
connection was never closed (PubSubClient destructor does not call
disconnect). Add explicit pubSub->disconnect() before returning.
Made-with: Cursor
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
* Fix TransmitHistory to improve epoch handling
* Enable epoch handling in unit tests
* Improve comments and test handling for epoch persistence in TransmitHistory
* Add boot-relative timestamp handling and unit tests for TransmitHistory
* loadFromDisk should handle legacy entries and clean up old v1 files after migration
* Revert "loadFromDisk should handle legacy entries and clean up old v1 files after migration"
This reverts commit eb7e5c7acfa4ac077fe50980be752e4b42a739b8.
* Add NodeInfoModule integration for RTC quality changes and trigger immediate checks
* Update test conditions for RTC quality checks
* Fix TAG low‑voltage reboot hang after App configuration
* nRF52: Move low-VDD System OFF logic to variant hook
* Addressed review
* serialize SAADC access with shared mutex for VDD and battery reads
* raise LPCOMP wake threshold to ensure rising-edge wake
* Trunk fmt
---------
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
* fix(routing): prevent licensed users from rebroadcasting packets from unlicensed or unknown users
* fix(routing): prevent licensed users from rebroadcasting packets to or from unlicensed users
---------
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
* fix: apply all LoRa config changes live without rebooting
All LoRa radio settings (SF, BW, CR, frequency, power, preset,
sx126x_rx_boosted_gain) now apply immediately via reconfigure()
without requiring a node reboot.
- AdminModule: requiresReboot = false for all LoRa config changes;
LoRa changes were already handled by the configChanged observer
calling reconfigure() but the reboot flag was set unnecessarily
- AdminModule: validate LORA_24 region against radio hardware at
config time; reject with BAD_REQUEST if hardware lacks 2.4 GHz
capability (wideLora() returns false or no radio instance)
- SX126xInterface/LR11x0Interface: apply sx126x_rx_boosted_gain in
reconfigure(); register 0x08AC is writable in STDBY mode (SX1261/2
datasheet §9.6); retention registers written so setting survives
warm-sleep cycles; log warning on setter failure
- DebugRenderer: show BW/SF/CR on debug screen when custom modem is
active instead of the preset name
- DisplayFormatters: clarify comment on getModemPresetDisplayName
* fix: remove redundant reboot after LoRa config changes in on-device menus
Region, frequency slot, and radio preset pickers in MenuHandler all
called reloadConfig() then immediately set rebootAtMsec. reloadConfig()
already fires the configChanged observer which calls reconfigure(), so
the forced reboot was unnecessary — same rationale as the parent commit.
* fix: guard LORA_24 region selection against hardware capability in on-device menu
Without a reboot, reconfigure() now applies region changes directly.
Previously getRadio() caught the LORA_24-on-sub-GHz mismatch post-reboot
and reverted to UNSET — that safety net is gone. Add an explicit wideLora()
check in LoraRegionPicker so sub-GHz-only hardware silently ignores LORA_24
selection instead of attempting a live reconfigure with an invalid frequency.
---------
Co-authored-by: elwimen <elwimen@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
The touch-to-backlight feature was gated behind TTGO_T_ECHO_PLUS, but
the regular T-Echo has the same backlight pin (PIN_EINK_EN, P1.11).
This changes the guard to use PIN_EINK_EN only, so any device with an
e-ink backlight pin gets the feature.
Fixes#7630
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>