Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Bump the pioarduino ESP-IDF framework from v5.5.3 to v5.5.3.1 which
fixes the gatt_main.c compile error when GATTS is disabled. This allows
reverting the workaround that unconditionally enabled CONFIG_BT_GATTS_ENABLE.
Also update _format_framework_espidf_version to support dot-separated
sub-release versions (e.g., 5.5.3.1) in both the tag and asset filename.
Log a warning when a client connects with an API version older than
1.14. This alerts users that their client needs updating before the
backward-compatibility code for pre-1.14 clients is removed in 2026.7.0.
Same pattern as the decode side - the bit manipulation was
duplicated in the main loop and tail path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
base64_find_char() safely handles any input including 0,
returning 0 via strchr fallback - no special contract needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fold the output copy loop into base64_decode_quad_ since both
call sites use the same truncation-checked copy logic, differing
only in count (3 vs i-1).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The base64 character-to-byte conversion and output copy loop were
duplicated in both the main decode loop and the tail/padding path.
Extract into a shared static helper to reduce flash usage (-64 bytes
on ESP32) and eliminate duplicated logic.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The base64 character-to-byte conversion was duplicated in both the
main decode loop and the tail/padding path. Extract into a shared
static helper to reduce flash usage (-64 bytes on ESP32).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the scheduler lock is already held, atomic loads of the remove
flag don't need acquire ordering — the mutex provides all necessary
synchronization guarantees. Add is_item_removed_locked_() helper that
uses memory_order_relaxed and use it in all _locked_ call sites.
This eliminates redundant memw barriers on Xtensa, saving 12 bytes
in matches_item_locked_ (152 → 140 B) and reducing pipeline stalls
in the scheduler hot path.
Replace the std::chrono::steady_clock approach with the scheduler's
existing millis_64() rollover tracking. This avoids pulling in
gettimeofday_r, system_clock, and the ArduinoJson int64_t serializer
template, saving ~270 bytes of flash and 8 bytes of RAM on ESP8266.
Send uptime as uint32_t seconds (good for ~136 years) instead of
int64_t milliseconds.
Reverts the frame header synchronization added in #14135 and #14136
in favor of a simpler fix: increasing MAX_LINE_LENGTH so that the
existing footer-based resynchronization can recover after losing sync.
Both components already check for frame footers at every byte position,
which naturally resyncs the parser. The problem was that the buffers
were sized exactly to fit the largest frame, so a desynced parser's
footer could land at the overflow boundary and get discarded. Increasing
the buffer by 4 bytes (footer size) ensures the footer always lands
inside the buffer.
- ld2450: 41 -> 45 (zone query response = 40 bytes + 1 null + 4 footer)
- ld2410: 46 -> 50 (engineering data frame = 45 bytes + 1 null + 4 footer)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>