The atomics path only takes the lock during rollover (every ~49.7 days)
for a ~5 instruction critical section. A std::atomic_flag spinlock
(1 byte) replaces the full FreeRTOS Mutex (~80-100 bytes RAM) since
contention is near-zero. The full Mutex is kept only for the
MULTI_NO_ATOMICS path (BK72xx) which needs it for broader locking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On ESPHOME_THREAD_SINGLE (ESP8266), the lock is never used.
Guarding it avoids the static local guard variable overhead
(8 bytes RAM + init check on every call).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
millis_64_impl_() handles 32-bit millis() rollover tracking for
platforms without native 64-bit time (ESP8266, LibreTiny). It was a
Scheduler method using Scheduler fields (last_millis_, millis_major_,
lock_), but has nothing to do with scheduling.
Move it to esphome/core/time_64.cpp as Millis64Impl::compute() with
static local state. Access is restricted via friend to millis_64()
(HAL) and Scheduler only.
Also introduces USE_NATIVE_64BIT_TIME define emitted by ESP32, Host,
Zephyr, and RP2040 platforms, replacing the verbose multi-platform
#if guards throughout scheduler.h/cpp.
time_64.cpp is only compiled on platforms that need it (ESP8266,
LibreTiny) via the build filter in config.py.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
RP2040's Pico SDK provides time_us_64() which reads the hardware
timer registers directly, returning native uint64_t microseconds.
This eliminates the need for 32-bit rollover tracking on this
platform.
millis() is now derived from millis_64() (like Zephyr) instead of
the other way around, unifying the time source.
Also removes IRAM_ATTR from all RP2040 HAL functions. On RP2040,
IRAM_ATTR is a no-op: the functions it decorated (millis, micros,
delayMicroseconds, arch_get_cpu_cycle_count) all call into Pico SDK
functions that reside in flash (XIP), so the attribute had no effect.
Remove virtual from Component::call_dump_config() since only
MQTTComponent overrode it. The MQTT override skipped dump_config
for internal entities, which unnecessarily hid useful debug info
from startup logs. The is_internal flag means "don't expose to
Home Assistant", not "don't log config".
This also removes one vtable entry from every Component subclass
and eliminates the indirect call overhead.
Replace floating-point arithmetic with integer weighted average.
This eliminates soft-float library calls on platforms without FPU
(e.g., ESP8266), reducing the function from 352 bytes.
The integer version uses uint16_t weighted average which matches
the float version's output in 99.96% of cases (off-by-one in
the remaining 0.04% due to float precision differences).
Zephyr's k_uptime_get() returns int64_t milliseconds directly,
eliminating the need for 32-bit rollover tracking on this platform.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Zephyr's k_uptime_get() returns int64_t milliseconds directly,
eliminating the need for 32-bit rollover tracking on this platform.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All listener notifications (connect_state, disconnect, got_ip,
scan_complete) are now deferred to wifi_loop_() via pending_ flags.
The TODO was completed but the comment was never removed.