mirror of
https://github.com/esphome/esphome.git
synced 2026-05-28 21:59:59 +08:00
[core] Add millis_64() HAL function with native ESP32 implementation (#14339)
This commit is contained in:
@@ -23,6 +23,7 @@ namespace esphome {
|
|||||||
|
|
||||||
void HOT yield() { vPortYield(); }
|
void HOT yield() { vPortYield(); }
|
||||||
uint32_t IRAM_ATTR HOT millis() { return (uint32_t) (esp_timer_get_time() / 1000ULL); }
|
uint32_t IRAM_ATTR HOT millis() { return (uint32_t) (esp_timer_get_time() / 1000ULL); }
|
||||||
|
uint64_t HOT millis_64() { return static_cast<uint64_t>(esp_timer_get_time()) / 1000ULL; }
|
||||||
void HOT delay(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); }
|
void HOT delay(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); }
|
||||||
uint32_t IRAM_ATTR HOT micros() { return (uint32_t) esp_timer_get_time(); }
|
uint32_t IRAM_ATTR HOT micros() { return (uint32_t) esp_timer_get_time(); }
|
||||||
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); }
|
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); }
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/application.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
@@ -16,6 +17,7 @@ namespace esphome {
|
|||||||
|
|
||||||
void HOT yield() { ::yield(); }
|
void HOT yield() { ::yield(); }
|
||||||
uint32_t IRAM_ATTR HOT millis() { return ::millis(); }
|
uint32_t IRAM_ATTR HOT millis() { return ::millis(); }
|
||||||
|
uint64_t millis_64() { return App.scheduler.millis_64_impl_(::millis()); }
|
||||||
void HOT delay(uint32_t ms) { ::delay(ms); }
|
void HOT delay(uint32_t ms) { ::delay(ms); }
|
||||||
uint32_t IRAM_ATTR HOT micros() { return ::micros(); }
|
uint32_t IRAM_ATTR HOT micros() { return ::micros(); }
|
||||||
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); }
|
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); }
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#ifdef USE_HOST
|
#ifdef USE_HOST
|
||||||
|
|
||||||
|
#include "esphome/core/application.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
@@ -19,6 +20,7 @@ uint32_t IRAM_ATTR HOT millis() {
|
|||||||
uint32_t ms = round(spec.tv_nsec / 1e6);
|
uint32_t ms = round(spec.tv_nsec / 1e6);
|
||||||
return ((uint32_t) seconds) * 1000U + ms;
|
return ((uint32_t) seconds) * 1000U + ms;
|
||||||
}
|
}
|
||||||
|
uint64_t millis_64() { return App.scheduler.millis_64_impl_(millis()); }
|
||||||
void HOT delay(uint32_t ms) {
|
void HOT delay(uint32_t ms) {
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
ts.tv_sec = ms / 1000;
|
ts.tv_sec = ms / 1000;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/application.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@ namespace esphome {
|
|||||||
|
|
||||||
void HOT yield() { ::yield(); }
|
void HOT yield() { ::yield(); }
|
||||||
uint32_t IRAM_ATTR HOT millis() { return ::millis(); }
|
uint32_t IRAM_ATTR HOT millis() { return ::millis(); }
|
||||||
|
uint64_t millis_64() { return App.scheduler.millis_64_impl_(::millis()); }
|
||||||
uint32_t IRAM_ATTR HOT micros() { return ::micros(); }
|
uint32_t IRAM_ATTR HOT micros() { return ::micros(); }
|
||||||
void HOT delay(uint32_t ms) { ::delay(ms); }
|
void HOT delay(uint32_t ms) { ::delay(ms); }
|
||||||
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { ::delayMicroseconds(us); }
|
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { ::delayMicroseconds(us); }
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/application.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
|
|
||||||
#include "hardware/watchdog.h"
|
#include "hardware/watchdog.h"
|
||||||
@@ -11,6 +12,7 @@ namespace esphome {
|
|||||||
|
|
||||||
void HOT yield() { ::yield(); }
|
void HOT yield() { ::yield(); }
|
||||||
uint32_t IRAM_ATTR HOT millis() { return ::millis(); }
|
uint32_t IRAM_ATTR HOT millis() { return ::millis(); }
|
||||||
|
uint64_t millis_64() { return App.scheduler.millis_64_impl_(::millis()); }
|
||||||
void HOT delay(uint32_t ms) { ::delay(ms); }
|
void HOT delay(uint32_t ms) { ::delay(ms); }
|
||||||
uint32_t IRAM_ATTR HOT micros() { return ::micros(); }
|
uint32_t IRAM_ATTR HOT micros() { return ::micros(); }
|
||||||
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); }
|
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "uptime_seconds_sensor.h"
|
#include "uptime_seconds_sensor.h"
|
||||||
|
|
||||||
#include "esphome/core/application.h"
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
namespace esphome::uptime {
|
namespace esphome::uptime {
|
||||||
@@ -8,7 +8,7 @@ namespace esphome::uptime {
|
|||||||
static const char *const TAG = "uptime.sensor";
|
static const char *const TAG = "uptime.sensor";
|
||||||
|
|
||||||
void UptimeSecondsSensor::update() {
|
void UptimeSecondsSensor::update() {
|
||||||
const uint64_t uptime = App.scheduler.millis_64();
|
const uint64_t uptime = millis_64();
|
||||||
const uint64_t seconds_int = uptime / 1000ULL;
|
const uint64_t seconds_int = uptime / 1000ULL;
|
||||||
const float seconds = float(seconds_int) + (uptime % 1000ULL) / 1000.0f;
|
const float seconds = float(seconds_int) + (uptime % 1000ULL) / 1000.0f;
|
||||||
this->publish_state(seconds);
|
this->publish_state(seconds);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "uptime_text_sensor.h"
|
#include "uptime_text_sensor.h"
|
||||||
|
|
||||||
#include "esphome/core/application.h"
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ static void append_unit(char *buf, size_t buf_size, size_t &pos, const char *sep
|
|||||||
void UptimeTextSensor::setup() { this->update(); }
|
void UptimeTextSensor::setup() { this->update(); }
|
||||||
|
|
||||||
void UptimeTextSensor::update() {
|
void UptimeTextSensor::update() {
|
||||||
uint32_t uptime = static_cast<uint32_t>(App.scheduler.millis_64() / 1000);
|
uint32_t uptime = static_cast<uint32_t>(millis_64() / 1000);
|
||||||
unsigned interval = this->get_update_interval() / 1000;
|
unsigned interval = this->get_update_interval() / 1000;
|
||||||
|
|
||||||
// Calculate all time units
|
// Calculate all time units
|
||||||
|
|||||||
@@ -385,7 +385,7 @@ json::SerializationBuffer<> WebServer::get_config_json() {
|
|||||||
#endif
|
#endif
|
||||||
root[ESPHOME_F("log")] = this->expose_log_;
|
root[ESPHOME_F("log")] = this->expose_log_;
|
||||||
root[ESPHOME_F("lang")] = "en";
|
root[ESPHOME_F("lang")] = "en";
|
||||||
root[ESPHOME_F("uptime")] = static_cast<uint32_t>(App.scheduler.millis_64() / 1000);
|
root[ESPHOME_F("uptime")] = static_cast<uint32_t>(millis_64() / 1000);
|
||||||
|
|
||||||
return builder.serialize();
|
return builder.serialize();
|
||||||
}
|
}
|
||||||
@@ -414,7 +414,7 @@ void WebServer::setup() {
|
|||||||
// getting a lot of events
|
// getting a lot of events
|
||||||
this->set_interval(10000, [this]() {
|
this->set_interval(10000, [this]() {
|
||||||
char buf[32];
|
char buf[32];
|
||||||
auto uptime = static_cast<uint32_t>(App.scheduler.millis_64() / 1000);
|
auto uptime = static_cast<uint32_t>(millis_64() / 1000);
|
||||||
buf_append_printf(buf, sizeof(buf), 0, "{\"uptime\":%u}", uptime);
|
buf_append_printf(buf, sizeof(buf), 0, "{\"uptime\":%u}", uptime);
|
||||||
this->events_.try_send_nodefer(buf, "ping", millis(), 30000);
|
this->events_.try_send_nodefer(buf, "ping", millis(), 30000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <zephyr/drivers/watchdog.h>
|
#include <zephyr/drivers/watchdog.h>
|
||||||
#include <zephyr/sys/reboot.h>
|
#include <zephyr/sys/reboot.h>
|
||||||
#include <zephyr/random/random.h>
|
#include <zephyr/random/random.h>
|
||||||
|
#include "esphome/core/application.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
@@ -17,6 +18,7 @@ static const device *const WDT = DEVICE_DT_GET(DT_ALIAS(watchdog0));
|
|||||||
|
|
||||||
void yield() { ::k_yield(); }
|
void yield() { ::k_yield(); }
|
||||||
uint32_t millis() { return k_ticks_to_ms_floor32(k_uptime_ticks()); }
|
uint32_t millis() { return k_ticks_to_ms_floor32(k_uptime_ticks()); }
|
||||||
|
uint64_t millis_64() { return App.scheduler.millis_64_impl_(millis()); }
|
||||||
uint32_t micros() { return k_ticks_to_us_floor32(k_uptime_ticks()); }
|
uint32_t micros() { return k_ticks_to_us_floor32(k_uptime_ticks()); }
|
||||||
void delayMicroseconds(uint32_t us) { ::k_usleep(us); }
|
void delayMicroseconds(uint32_t us) { ::k_usleep(us); }
|
||||||
void delay(uint32_t ms) { ::k_msleep(ms); }
|
void delay(uint32_t ms) { ::k_msleep(ms); }
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ namespace esphome {
|
|||||||
|
|
||||||
void yield();
|
void yield();
|
||||||
uint32_t millis();
|
uint32_t millis();
|
||||||
|
uint64_t millis_64();
|
||||||
uint32_t micros();
|
uint32_t micros();
|
||||||
void delay(uint32_t ms);
|
void delay(uint32_t ms);
|
||||||
void delayMicroseconds(uint32_t us); // NOLINT(readability-identifier-naming)
|
void delayMicroseconds(uint32_t us); // NOLINT(readability-identifier-naming)
|
||||||
|
|||||||
+19
-15
@@ -28,8 +28,10 @@ static constexpr size_t MAX_POOL_SIZE = 5;
|
|||||||
// Set to 5 to match the pool size - when we have as many cancelled items as our
|
// Set to 5 to match the pool size - when we have as many cancelled items as our
|
||||||
// pool can hold, it's time to clean up and recycle them.
|
// pool can hold, it's time to clean up and recycle them.
|
||||||
static constexpr uint32_t MAX_LOGICALLY_DELETED_ITEMS = 5;
|
static constexpr uint32_t MAX_LOGICALLY_DELETED_ITEMS = 5;
|
||||||
|
#ifndef USE_ESP32
|
||||||
// Half the 32-bit range - used to detect rollovers vs normal time progression
|
// Half the 32-bit range - used to detect rollovers vs normal time progression
|
||||||
static constexpr uint32_t HALF_MAX_UINT32 = std::numeric_limits<uint32_t>::max() / 2;
|
static constexpr uint32_t HALF_MAX_UINT32 = std::numeric_limits<uint32_t>::max() / 2;
|
||||||
|
#endif
|
||||||
// max delay to start an interval sequence
|
// max delay to start an interval sequence
|
||||||
static constexpr uint32_t MAX_INTERVAL_DELAY = 5000;
|
static constexpr uint32_t MAX_INTERVAL_DELAY = 5000;
|
||||||
|
|
||||||
@@ -150,8 +152,8 @@ void HOT Scheduler::set_timer_common_(Component *component, SchedulerItem::Type
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get fresh timestamp BEFORE taking lock - millis_64_ may need to acquire lock itself
|
// Get fresh 64-bit timestamp BEFORE taking lock
|
||||||
const uint64_t now = this->millis_64_(millis());
|
const uint64_t now_64 = millis_64();
|
||||||
|
|
||||||
// Take lock early to protect scheduler_item_pool_ access
|
// Take lock early to protect scheduler_item_pool_ access
|
||||||
LockGuard guard{this->lock_};
|
LockGuard guard{this->lock_};
|
||||||
@@ -184,7 +186,7 @@ void HOT Scheduler::set_timer_common_(Component *component, SchedulerItem::Type
|
|||||||
item->interval = delay;
|
item->interval = delay;
|
||||||
// first execution happens immediately after a random smallish offset
|
// first execution happens immediately after a random smallish offset
|
||||||
uint32_t offset = this->calculate_interval_offset_(delay);
|
uint32_t offset = this->calculate_interval_offset_(delay);
|
||||||
item->set_next_execution(now + offset);
|
item->set_next_execution(now_64 + offset);
|
||||||
#ifdef ESPHOME_LOG_HAS_VERBOSE
|
#ifdef ESPHOME_LOG_HAS_VERBOSE
|
||||||
SchedulerNameLog name_log;
|
SchedulerNameLog name_log;
|
||||||
ESP_LOGV(TAG, "Scheduler interval for %s is %" PRIu32 "ms, offset %" PRIu32 "ms",
|
ESP_LOGV(TAG, "Scheduler interval for %s is %" PRIu32 "ms, offset %" PRIu32 "ms",
|
||||||
@@ -192,11 +194,11 @@ void HOT Scheduler::set_timer_common_(Component *component, SchedulerItem::Type
|
|||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
item->interval = 0;
|
item->interval = 0;
|
||||||
item->set_next_execution(now + delay);
|
item->set_next_execution(now_64 + delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESPHOME_DEBUG_SCHEDULER
|
#ifdef ESPHOME_DEBUG_SCHEDULER
|
||||||
this->debug_log_timer_(item.get(), name_type, static_name, hash_or_id, type, delay, now);
|
this->debug_log_timer_(item.get(), name_type, static_name, hash_or_id, type, delay, now_64);
|
||||||
#endif /* ESPHOME_DEBUG_SCHEDULER */
|
#endif /* ESPHOME_DEBUG_SCHEDULER */
|
||||||
|
|
||||||
// For retries, check if there's a cancelled timeout first
|
// For retries, check if there's a cancelled timeout first
|
||||||
@@ -399,8 +401,7 @@ optional<uint32_t> HOT Scheduler::next_schedule_in(uint32_t now) {
|
|||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto &item = this->items_[0];
|
auto &item = this->items_[0];
|
||||||
// Convert the fresh timestamp from caller (usually Application::loop()) to 64-bit
|
const auto now_64 = this->millis_64_from_(now);
|
||||||
const auto now_64 = this->millis_64_(now); // 'now' from parameter - fresh from caller
|
|
||||||
const uint64_t next_exec = item->get_next_execution();
|
const uint64_t next_exec = item->get_next_execution();
|
||||||
if (next_exec < now_64)
|
if (next_exec < now_64)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -461,8 +462,8 @@ void HOT Scheduler::call(uint32_t now) {
|
|||||||
this->process_defer_queue_(now);
|
this->process_defer_queue_(now);
|
||||||
#endif /* not ESPHOME_THREAD_SINGLE */
|
#endif /* not ESPHOME_THREAD_SINGLE */
|
||||||
|
|
||||||
// Convert the fresh timestamp from main loop to 64-bit for scheduler operations
|
// Extend the caller's 32-bit timestamp to 64-bit for scheduler operations
|
||||||
const auto now_64 = this->millis_64_(now); // 'now' from parameter - fresh from Application::loop()
|
const auto now_64 = this->millis_64_from_(now);
|
||||||
this->process_to_add();
|
this->process_to_add();
|
||||||
|
|
||||||
// Track if any items were added to to_add_ during this call (intervals or from callbacks)
|
// Track if any items were added to to_add_ during this call (intervals or from callbacks)
|
||||||
@@ -474,15 +475,18 @@ void HOT Scheduler::call(uint32_t now) {
|
|||||||
if (now_64 - last_print > 2000) {
|
if (now_64 - last_print > 2000) {
|
||||||
last_print = now_64;
|
last_print = now_64;
|
||||||
std::vector<SchedulerItemPtr> old_items;
|
std::vector<SchedulerItemPtr> old_items;
|
||||||
#ifdef ESPHOME_THREAD_MULTI_ATOMICS
|
#if !defined(USE_ESP32) && defined(ESPHOME_THREAD_MULTI_ATOMICS)
|
||||||
const auto last_dbg = this->last_millis_.load(std::memory_order_relaxed);
|
const auto last_dbg = this->last_millis_.load(std::memory_order_relaxed);
|
||||||
const auto major_dbg = this->millis_major_.load(std::memory_order_relaxed);
|
const auto major_dbg = this->millis_major_.load(std::memory_order_relaxed);
|
||||||
ESP_LOGD(TAG, "Items: count=%zu, pool=%zu, now=%" PRIu64 " (%" PRIu16 ", %" PRIu32 ")", this->items_.size(),
|
ESP_LOGD(TAG, "Items: count=%zu, pool=%zu, now=%" PRIu64 " (%" PRIu16 ", %" PRIu32 ")", this->items_.size(),
|
||||||
this->scheduler_item_pool_.size(), now_64, major_dbg, last_dbg);
|
this->scheduler_item_pool_.size(), now_64, major_dbg, last_dbg);
|
||||||
#else /* not ESPHOME_THREAD_MULTI_ATOMICS */
|
#elif !defined(USE_ESP32)
|
||||||
ESP_LOGD(TAG, "Items: count=%zu, pool=%zu, now=%" PRIu64 " (%" PRIu16 ", %" PRIu32 ")", this->items_.size(),
|
ESP_LOGD(TAG, "Items: count=%zu, pool=%zu, now=%" PRIu64 " (%" PRIu16 ", %" PRIu32 ")", this->items_.size(),
|
||||||
this->scheduler_item_pool_.size(), now_64, this->millis_major_, this->last_millis_);
|
this->scheduler_item_pool_.size(), now_64, this->millis_major_, this->last_millis_);
|
||||||
#endif /* else ESPHOME_THREAD_MULTI_ATOMICS */
|
#else
|
||||||
|
ESP_LOGD(TAG, "Items: count=%zu, pool=%zu, now=%" PRIu64, this->items_.size(), this->scheduler_item_pool_.size(),
|
||||||
|
now_64);
|
||||||
|
#endif
|
||||||
// Cleanup before debug output
|
// Cleanup before debug output
|
||||||
this->cleanup_();
|
this->cleanup_();
|
||||||
while (!this->items_.empty()) {
|
while (!this->items_.empty()) {
|
||||||
@@ -710,9 +714,8 @@ bool HOT Scheduler::cancel_item_locked_(Component *component, NameType name_type
|
|||||||
return total_cancelled > 0;
|
return total_cancelled > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Scheduler::millis_64() { return this->millis_64_(millis()); }
|
#ifndef USE_ESP32
|
||||||
|
uint64_t Scheduler::millis_64_impl_(uint32_t now) {
|
||||||
uint64_t Scheduler::millis_64_(uint32_t now) {
|
|
||||||
// THREAD SAFETY NOTE:
|
// THREAD SAFETY NOTE:
|
||||||
// This function has three implementations, based on the precompiler flags
|
// This function has three implementations, based on the precompiler flags
|
||||||
// - ESPHOME_THREAD_SINGLE - Runs on single-threaded platforms (ESP8266, RP2040, etc.)
|
// - ESPHOME_THREAD_SINGLE - Runs on single-threaded platforms (ESP8266, RP2040, etc.)
|
||||||
@@ -869,6 +872,7 @@ uint64_t Scheduler::millis_64_(uint32_t now) {
|
|||||||
"No platform threading model defined. One of ESPHOME_THREAD_SINGLE, ESPHOME_THREAD_MULTI_NO_ATOMICS, or ESPHOME_THREAD_MULTI_ATOMICS must be defined."
|
"No platform threading model defined. One of ESPHOME_THREAD_SINGLE, ESPHOME_THREAD_MULTI_NO_ATOMICS, or ESPHOME_THREAD_MULTI_ATOMICS must be defined."
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif // not USE_ESP32
|
||||||
|
|
||||||
bool HOT Scheduler::SchedulerItem::cmp(const SchedulerItemPtr &a, const SchedulerItemPtr &b) {
|
bool HOT Scheduler::SchedulerItem::cmp(const SchedulerItemPtr &a, const SchedulerItemPtr &b) {
|
||||||
// High bits are almost always equal (change only on 32-bit rollover ~49 days)
|
// High bits are almost always equal (change only on 32-bit rollover ~49 days)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
@@ -117,12 +118,12 @@ class Scheduler {
|
|||||||
bool cancel_retry(Component *component, uint32_t id);
|
bool cancel_retry(Component *component, uint32_t id);
|
||||||
|
|
||||||
/// Get 64-bit millisecond timestamp (handles 32-bit millis() rollover)
|
/// Get 64-bit millisecond timestamp (handles 32-bit millis() rollover)
|
||||||
uint64_t millis_64();
|
uint64_t millis_64() { return esphome::millis_64(); }
|
||||||
|
|
||||||
// Calculate when the next scheduled item should run
|
// Calculate when the next scheduled item should run.
|
||||||
// @param now Fresh timestamp from millis() - must not be stale/cached
|
// @param now On ESP32, unused for 64-bit extension (native); on other platforms, extended to 64-bit via rollover.
|
||||||
// Returns the time in milliseconds until the next scheduled item, or nullopt if no items
|
// Returns the time in milliseconds until the next scheduled item, or nullopt if no items.
|
||||||
// This method performs cleanup of removed items before checking the schedule
|
// This method performs cleanup of removed items before checking the schedule.
|
||||||
// IMPORTANT: This method should only be called from the main thread (loop task).
|
// IMPORTANT: This method should only be called from the main thread (loop task).
|
||||||
optional<uint32_t> next_schedule_in(uint32_t now);
|
optional<uint32_t> next_schedule_in(uint32_t now);
|
||||||
|
|
||||||
@@ -282,7 +283,25 @@ class Scheduler {
|
|||||||
// Common implementation for cancel_retry
|
// Common implementation for cancel_retry
|
||||||
bool cancel_retry_(Component *component, NameType name_type, const char *static_name, uint32_t hash_or_id);
|
bool cancel_retry_(Component *component, NameType name_type, const char *static_name, uint32_t hash_or_id);
|
||||||
|
|
||||||
uint64_t millis_64_(uint32_t now);
|
// Extend a 32-bit millis() value to 64-bit. Use when the caller already has a fresh now.
|
||||||
|
// On ESP32, ignores now and uses esp_timer_get_time() directly (native 64-bit).
|
||||||
|
// On non-ESP32, extends now to 64-bit using rollover tracking.
|
||||||
|
uint64_t millis_64_from_(uint32_t now) {
|
||||||
|
#ifdef USE_ESP32
|
||||||
|
(void) now;
|
||||||
|
return millis_64();
|
||||||
|
#else
|
||||||
|
return this->millis_64_impl_(now);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef USE_ESP32
|
||||||
|
// On non-ESP32 platforms, millis_64() HAL function delegates to this method
|
||||||
|
// which tracks 32-bit millis() rollover using millis_major_ and last_millis_.
|
||||||
|
// On ESP32, millis_64() uses esp_timer_get_time() directly.
|
||||||
|
friend uint64_t millis_64();
|
||||||
|
uint64_t millis_64_impl_(uint32_t now);
|
||||||
|
#endif
|
||||||
// Cleanup logically deleted items from the scheduler
|
// Cleanup logically deleted items from the scheduler
|
||||||
// Returns the number of items remaining after cleanup
|
// Returns the number of items remaining after cleanup
|
||||||
// IMPORTANT: This method should only be called from the main thread (loop task).
|
// IMPORTANT: This method should only be called from the main thread (loop task).
|
||||||
@@ -549,6 +568,9 @@ class Scheduler {
|
|||||||
// to synchronize between tasks (see https://github.com/esphome/backlog/issues/52)
|
// to synchronize between tasks (see https://github.com/esphome/backlog/issues/52)
|
||||||
std::vector<SchedulerItemPtr> scheduler_item_pool_;
|
std::vector<SchedulerItemPtr> scheduler_item_pool_;
|
||||||
|
|
||||||
|
#ifndef USE_ESP32
|
||||||
|
// On ESP32, millis_64() uses esp_timer_get_time() directly; no rollover tracking needed.
|
||||||
|
// On other platforms, these fields track 32-bit millis() rollover for millis_64_impl_().
|
||||||
#ifdef ESPHOME_THREAD_MULTI_ATOMICS
|
#ifdef ESPHOME_THREAD_MULTI_ATOMICS
|
||||||
/*
|
/*
|
||||||
* Multi-threaded platforms with atomic support: last_millis_ needs atomic for lock-free updates
|
* Multi-threaded platforms with atomic support: last_millis_ needs atomic for lock-free updates
|
||||||
@@ -577,6 +599,7 @@ class Scheduler {
|
|||||||
#else /* not ESPHOME_THREAD_MULTI_ATOMICS */
|
#else /* not ESPHOME_THREAD_MULTI_ATOMICS */
|
||||||
uint16_t millis_major_{0};
|
uint16_t millis_major_{0};
|
||||||
#endif /* else ESPHOME_THREAD_MULTI_ATOMICS */
|
#endif /* else ESPHOME_THREAD_MULTI_ATOMICS */
|
||||||
|
#endif /* not USE_ESP32 */
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|||||||
Reference in New Issue
Block a user