mirror of
https://github.com/esphome/esphome.git
synced 2026-02-04 01:39:38 -07:00
Compare commits
3 Commits
json_web_s
...
scheduler_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d91cad1636 | ||
|
|
54d0328002 | ||
|
|
865312ff60 |
@@ -91,8 +91,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 timestamp BEFORE taking lock - millis_48_ may need to acquire lock itself
|
||||||
const uint64_t now = this->millis_64_(millis());
|
const Time48 now = this->millis_48_(millis());
|
||||||
|
|
||||||
// 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_};
|
||||||
@@ -291,12 +291,12 @@ 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
|
// Convert the fresh timestamp from caller (usually Application::loop()) to 48-bit
|
||||||
const auto now_64 = this->millis_64_(now); // 'now' from parameter - fresh from caller
|
const auto now_48 = this->millis_48_(now); // 'now' from parameter - fresh from caller
|
||||||
const uint64_t next_exec = item->get_next_execution();
|
const Time48 next_exec = item->get_next_execution();
|
||||||
if (next_exec < now_64)
|
if (next_exec < now_48)
|
||||||
return 0;
|
return 0;
|
||||||
return next_exec - now_64;
|
return next_exec - now_48;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::full_cleanup_removed_items_() {
|
void Scheduler::full_cleanup_removed_items_() {
|
||||||
@@ -331,28 +331,21 @@ 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
|
// Convert the fresh timestamp from main loop to 48-bit for scheduler operations
|
||||||
const auto now_64 = this->millis_64_(now); // 'now' from parameter - fresh from Application::loop()
|
const auto now_48 = this->millis_48_(now); // 'now' from parameter - fresh from Application::loop()
|
||||||
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)
|
||||||
bool has_added_items = false;
|
bool has_added_items = false;
|
||||||
|
|
||||||
#ifdef ESPHOME_DEBUG_SCHEDULER
|
#ifdef ESPHOME_DEBUG_SCHEDULER
|
||||||
static uint64_t last_print = 0;
|
static Time48 last_print{};
|
||||||
|
|
||||||
if (now_64 - last_print > 2000) {
|
if ((now_48 - last_print) > 2000) {
|
||||||
last_print = now_64;
|
last_print = now_48;
|
||||||
std::vector<std::unique_ptr<SchedulerItem>> old_items;
|
std::vector<std::unique_ptr<SchedulerItem>> old_items;
|
||||||
#ifdef ESPHOME_THREAD_MULTI_ATOMICS
|
ESP_LOGD(TAG, "Items: count=%zu, pool=%zu, now=(%" PRIu16 ", %" PRIu32 ")", this->items_.size(),
|
||||||
const auto last_dbg = this->last_millis_.load(std::memory_order_relaxed);
|
this->scheduler_item_pool_.size(), now_48.major, now_48.millis);
|
||||||
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(),
|
|
||||||
this->scheduler_item_pool_.size(), now_64, major_dbg, last_dbg);
|
|
||||||
#else /* not ESPHOME_THREAD_MULTI_ATOMICS */
|
|
||||||
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_);
|
|
||||||
#endif /* else ESPHOME_THREAD_MULTI_ATOMICS */
|
|
||||||
// Cleanup before debug output
|
// Cleanup before debug output
|
||||||
this->cleanup_();
|
this->cleanup_();
|
||||||
while (!this->items_.empty()) {
|
while (!this->items_.empty()) {
|
||||||
@@ -364,9 +357,10 @@ void HOT Scheduler::call(uint32_t now) {
|
|||||||
|
|
||||||
const char *name = item->get_name();
|
const char *name = item->get_name();
|
||||||
bool is_cancelled = is_item_removed_(item.get());
|
bool is_cancelled = is_item_removed_(item.get());
|
||||||
ESP_LOGD(TAG, " %s '%s/%s' interval=%" PRIu32 " next_execution in %" PRIu64 "ms at %" PRIu64 "%s",
|
const Time48 next_exec = item->get_next_execution();
|
||||||
|
ESP_LOGD(TAG, " %s '%s/%s' interval=%" PRIu32 " next_execution in %" PRIu32 "ms at (%" PRIu16 ", %" PRIu32 ")%s",
|
||||||
item->get_type_str(), LOG_STR_ARG(item->get_source()), name ? name : "(null)", item->interval,
|
item->get_type_str(), LOG_STR_ARG(item->get_source()), name ? name : "(null)", item->interval,
|
||||||
item->get_next_execution() - now_64, item->get_next_execution(), is_cancelled ? " [CANCELLED]" : "");
|
next_exec - now_48, next_exec.major, next_exec.millis, is_cancelled ? " [CANCELLED]" : "");
|
||||||
|
|
||||||
old_items.push_back(std::move(item));
|
old_items.push_back(std::move(item));
|
||||||
}
|
}
|
||||||
@@ -393,7 +387,7 @@ void HOT Scheduler::call(uint32_t now) {
|
|||||||
while (!this->items_.empty()) {
|
while (!this->items_.empty()) {
|
||||||
// Don't copy-by value yet
|
// Don't copy-by value yet
|
||||||
auto &item = this->items_[0];
|
auto &item = this->items_[0];
|
||||||
if (item->get_next_execution() > now_64) {
|
if (item->get_next_execution() > now_48) {
|
||||||
// Not reached timeout yet, done for this call
|
// Not reached timeout yet, done for this call
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -430,9 +424,12 @@ void HOT Scheduler::call(uint32_t now) {
|
|||||||
|
|
||||||
#ifdef ESPHOME_DEBUG_SCHEDULER
|
#ifdef ESPHOME_DEBUG_SCHEDULER
|
||||||
const char *item_name = item->get_name();
|
const char *item_name = item->get_name();
|
||||||
ESP_LOGV(TAG, "Running %s '%s/%s' with interval=%" PRIu32 " next_execution=%" PRIu64 " (now=%" PRIu64 ")",
|
const Time48 next_exec_dbg = item->get_next_execution();
|
||||||
|
ESP_LOGV(TAG,
|
||||||
|
"Running %s '%s/%s' with interval=%" PRIu32 " next_execution=(%" PRIu16 ", %" PRIu32 ") now=(%" PRIu16
|
||||||
|
", %" PRIu32 ")",
|
||||||
item->get_type_str(), LOG_STR_ARG(item->get_source()), item_name ? item_name : "(null)", item->interval,
|
item->get_type_str(), LOG_STR_ARG(item->get_source()), item_name ? item_name : "(null)", item->interval,
|
||||||
item->get_next_execution(), now_64);
|
next_exec_dbg.major, next_exec_dbg.millis, now_48.major, now_48.millis);
|
||||||
#endif /* ESPHOME_DEBUG_SCHEDULER */
|
#endif /* ESPHOME_DEBUG_SCHEDULER */
|
||||||
|
|
||||||
// Warning: During callback(), a lot of stuff can happen, including:
|
// Warning: During callback(), a lot of stuff can happen, including:
|
||||||
@@ -454,7 +451,7 @@ void HOT Scheduler::call(uint32_t now) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (executed_item->type == SchedulerItem::INTERVAL) {
|
if (executed_item->type == SchedulerItem::INTERVAL) {
|
||||||
executed_item->set_next_execution(now_64 + executed_item->interval);
|
executed_item->set_next_execution(now_48 + executed_item->interval);
|
||||||
// Add new item directly to to_add_
|
// Add new item directly to to_add_
|
||||||
// since we have the lock held
|
// since we have the lock held
|
||||||
this->to_add_.push_back(std::move(executed_item));
|
this->to_add_.push_back(std::move(executed_item));
|
||||||
@@ -579,7 +576,7 @@ bool HOT Scheduler::cancel_item_locked_(Component *component, const char *name_c
|
|||||||
return total_cancelled > 0;
|
return total_cancelled > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Scheduler::millis_64_(uint32_t now) {
|
Time48 Scheduler::millis_48_(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.)
|
||||||
@@ -615,8 +612,7 @@ uint64_t Scheduler::millis_64_(uint32_t now) {
|
|||||||
this->last_millis_ = now;
|
this->last_millis_ = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combine major (high 32 bits) and now (low 32 bits) into 64-bit time
|
return {now, major};
|
||||||
return now + (static_cast<uint64_t>(major) << 32);
|
|
||||||
|
|
||||||
#elif defined(ESPHOME_THREAD_MULTI_NO_ATOMICS)
|
#elif defined(ESPHOME_THREAD_MULTI_NO_ATOMICS)
|
||||||
// This is the multi core no atomics implementation.
|
// This is the multi core no atomics implementation.
|
||||||
@@ -664,8 +660,7 @@ uint64_t Scheduler::millis_64_(uint32_t now) {
|
|||||||
// If now <= last and we're not near rollover, don't update
|
// If now <= last and we're not near rollover, don't update
|
||||||
// This minimizes backwards time movement
|
// This minimizes backwards time movement
|
||||||
|
|
||||||
// Combine major (high 32 bits) and now (low 32 bits) into 64-bit time
|
return {now, major};
|
||||||
return now + (static_cast<uint64_t>(major) << 32);
|
|
||||||
|
|
||||||
#elif defined(ESPHOME_THREAD_MULTI_ATOMICS)
|
#elif defined(ESPHOME_THREAD_MULTI_ATOMICS)
|
||||||
// This is the multi core with atomics implementation.
|
// This is the multi core with atomics implementation.
|
||||||
@@ -725,7 +720,7 @@ uint64_t Scheduler::millis_64_(uint32_t now) {
|
|||||||
}
|
}
|
||||||
uint16_t major_end = this->millis_major_.load(std::memory_order_relaxed);
|
uint16_t major_end = this->millis_major_.load(std::memory_order_relaxed);
|
||||||
if (major_end == major)
|
if (major_end == major)
|
||||||
return now + (static_cast<uint64_t>(major) << 32);
|
return {now, major};
|
||||||
}
|
}
|
||||||
// Unreachable - the loop always returns when major_end == major
|
// Unreachable - the loop always returns when major_end == major
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
@@ -738,10 +733,7 @@ uint64_t Scheduler::millis_64_(uint32_t now) {
|
|||||||
|
|
||||||
bool HOT Scheduler::SchedulerItem::cmp(const std::unique_ptr<SchedulerItem> &a,
|
bool HOT Scheduler::SchedulerItem::cmp(const std::unique_ptr<SchedulerItem> &a,
|
||||||
const std::unique_ptr<SchedulerItem> &b) {
|
const std::unique_ptr<SchedulerItem> &b) {
|
||||||
// High bits are almost always equal (change only on 32-bit rollover ~49 days)
|
return a->get_next_execution() > b->get_next_execution();
|
||||||
// Optimize for common case: check low bits first when high bits are equal
|
|
||||||
return (a->next_execution_high_ == b->next_execution_high_) ? (a->next_execution_low_ > b->next_execution_low_)
|
|
||||||
: (a->next_execution_high_ > b->next_execution_high_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::recycle_item_main_loop_(std::unique_ptr<SchedulerItem> item) {
|
void Scheduler::recycle_item_main_loop_(std::unique_ptr<SchedulerItem> item) {
|
||||||
@@ -767,7 +759,7 @@ void Scheduler::recycle_item_main_loop_(std::unique_ptr<SchedulerItem> item) {
|
|||||||
|
|
||||||
#ifdef ESPHOME_DEBUG_SCHEDULER
|
#ifdef ESPHOME_DEBUG_SCHEDULER
|
||||||
void Scheduler::debug_log_timer_(const SchedulerItem *item, bool is_static_string, const char *name_cstr,
|
void Scheduler::debug_log_timer_(const SchedulerItem *item, bool is_static_string, const char *name_cstr,
|
||||||
SchedulerItem::Type type, uint32_t delay, uint64_t now) {
|
SchedulerItem::Type type, uint32_t delay, Time48 now) {
|
||||||
// Validate static strings in debug mode
|
// Validate static strings in debug mode
|
||||||
if (is_static_string && name_cstr != nullptr) {
|
if (is_static_string && name_cstr != nullptr) {
|
||||||
validate_static_string(name_cstr);
|
validate_static_string(name_cstr);
|
||||||
@@ -780,8 +772,7 @@ void Scheduler::debug_log_timer_(const SchedulerItem *item, bool is_static_strin
|
|||||||
name_cstr ? name_cstr : "(null)", type_str, delay);
|
name_cstr ? name_cstr : "(null)", type_str, delay);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGD(TAG, "set_%s(name='%s/%s', %s=%" PRIu32 ", offset=%" PRIu32 ")", type_str, LOG_STR_ARG(item->get_source()),
|
ESP_LOGD(TAG, "set_%s(name='%s/%s', %s=%" PRIu32 ", offset=%" PRIu32 ")", type_str, LOG_STR_ARG(item->get_source()),
|
||||||
name_cstr ? name_cstr : "(null)", type_str, delay,
|
name_cstr ? name_cstr : "(null)", type_str, delay, item->get_next_execution() - now);
|
||||||
static_cast<uint32_t>(item->get_next_execution() - now));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* ESPHOME_DEBUG_SCHEDULER */
|
#endif /* ESPHOME_DEBUG_SCHEDULER */
|
||||||
|
|||||||
@@ -13,6 +13,49 @@
|
|||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
|
|
||||||
|
// 48-bit timestamp for scheduler operations.
|
||||||
|
// Uses 32-bit math with manual carry detection to avoid expensive 64-bit
|
||||||
|
// emulation on ESP8266 and other 32-bit platforms without native 64-bit support.
|
||||||
|
struct Time48 {
|
||||||
|
uint32_t millis{0}; // Low 32 bits - milliseconds within current epoch
|
||||||
|
uint16_t major{0}; // High 16 bits - rollover counter (~49.7 days each)
|
||||||
|
|
||||||
|
constexpr Time48() = default;
|
||||||
|
constexpr Time48(uint32_t millis, uint16_t major) : millis(millis), major(major) {}
|
||||||
|
|
||||||
|
// Add a 32-bit offset (delay/interval)
|
||||||
|
constexpr Time48 operator+(uint32_t offset) const {
|
||||||
|
uint32_t new_millis = millis + offset;
|
||||||
|
uint16_t new_major = major;
|
||||||
|
if (new_millis < millis)
|
||||||
|
new_major++; // Overflow occurred
|
||||||
|
return {new_millis, new_major};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare operators - optimized for 32-bit platforms
|
||||||
|
// Written to generate same control flow as GCC's native 64-bit comparison:
|
||||||
|
// Uses cascading < comparisons instead of != to produce tighter branch sequences
|
||||||
|
constexpr bool operator<(const Time48 &other) const {
|
||||||
|
if (major < other.major)
|
||||||
|
return true;
|
||||||
|
if (other.major < major)
|
||||||
|
return false;
|
||||||
|
return millis < other.millis;
|
||||||
|
}
|
||||||
|
constexpr bool operator>(const Time48 &other) const { return other < *this; }
|
||||||
|
constexpr bool operator<=(const Time48 &other) const { return !(other < *this); }
|
||||||
|
constexpr bool operator>=(const Time48 &other) const { return !(*this < other); }
|
||||||
|
|
||||||
|
// Subtract two Time48 values, returning 32-bit result
|
||||||
|
// PRECONDITION: *this >= other AND difference fits in 32 bits
|
||||||
|
// This is always true for scheduler since max delay is ~49 days
|
||||||
|
constexpr uint32_t operator-(const Time48 &other) const {
|
||||||
|
// Two's complement subtraction works even across major boundary
|
||||||
|
// when the result is known to fit in 32 bits
|
||||||
|
return millis - other.millis;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class Component;
|
class Component;
|
||||||
struct RetryArgs;
|
struct RetryArgs;
|
||||||
|
|
||||||
@@ -94,15 +137,13 @@ class Scheduler {
|
|||||||
} name_;
|
} name_;
|
||||||
uint32_t interval;
|
uint32_t interval;
|
||||||
// Split time to handle millis() rollover. The scheduler combines the 32-bit millis()
|
// Split time to handle millis() rollover. The scheduler combines the 32-bit millis()
|
||||||
// with a 16-bit rollover counter to create a 48-bit time space (using 32+16 bits).
|
// with a 16-bit rollover counter to create a 48-bit time space. With 49.7 days per
|
||||||
// This is intentionally limited to 48 bits, not stored as a full 64-bit value.
|
// 32-bit rollover, the 16-bit counter supports 49.7 days × 65536 = ~8900 years.
|
||||||
// With 49.7 days per 32-bit rollover, the 16-bit counter supports
|
// This ensures correct scheduling even when devices run for months.
|
||||||
// 49.7 days × 65536 = ~8900 years. This ensures correct scheduling
|
// Split into two fields for better memory alignment on 32-bit systems.
|
||||||
// even when devices run for months. Split into two fields for better memory
|
uint32_t next_execution_millis_; // Lower 32 bits of execution time (millis value)
|
||||||
// alignment on 32-bit systems.
|
|
||||||
uint32_t next_execution_low_; // Lower 32 bits of execution time (millis value)
|
|
||||||
std::function<void()> callback;
|
std::function<void()> callback;
|
||||||
uint16_t next_execution_high_; // Upper 16 bits (millis_major counter)
|
uint16_t next_execution_major_; // Upper 16 bits (millis_major counter)
|
||||||
|
|
||||||
#ifdef ESPHOME_THREAD_MULTI_ATOMICS
|
#ifdef ESPHOME_THREAD_MULTI_ATOMICS
|
||||||
// Multi-threaded with atomics: use atomic for lock-free access
|
// Multi-threaded with atomics: use atomic for lock-free access
|
||||||
@@ -128,8 +169,8 @@ class Scheduler {
|
|||||||
SchedulerItem()
|
SchedulerItem()
|
||||||
: component(nullptr),
|
: component(nullptr),
|
||||||
interval(0),
|
interval(0),
|
||||||
next_execution_low_(0),
|
next_execution_millis_(0),
|
||||||
next_execution_high_(0),
|
next_execution_major_(0),
|
||||||
#ifdef ESPHOME_THREAD_MULTI_ATOMICS
|
#ifdef ESPHOME_THREAD_MULTI_ATOMICS
|
||||||
// remove is initialized in the member declaration as std::atomic<bool>{false}
|
// remove is initialized in the member declaration as std::atomic<bool>{false}
|
||||||
type(TIMEOUT),
|
type(TIMEOUT),
|
||||||
@@ -189,18 +230,11 @@ class Scheduler {
|
|||||||
|
|
||||||
static bool cmp(const std::unique_ptr<SchedulerItem> &a, const std::unique_ptr<SchedulerItem> &b);
|
static bool cmp(const std::unique_ptr<SchedulerItem> &a, const std::unique_ptr<SchedulerItem> &b);
|
||||||
|
|
||||||
// Note: We use 48 bits total (32 + 16), stored in a 64-bit value for API compatibility.
|
constexpr Time48 get_next_execution() const { return {next_execution_millis_, next_execution_major_}; }
|
||||||
// The upper 16 bits of the 64-bit value are always zero, which is fine since
|
|
||||||
// millis_major_ is also 16 bits and they must match.
|
|
||||||
constexpr uint64_t get_next_execution() const {
|
|
||||||
return (static_cast<uint64_t>(next_execution_high_) << 32) | next_execution_low_;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void set_next_execution(uint64_t value) {
|
constexpr void set_next_execution(Time48 value) {
|
||||||
next_execution_low_ = static_cast<uint32_t>(value);
|
next_execution_millis_ = value.millis;
|
||||||
// Cast to uint16_t intentionally truncates to lower 16 bits of the upper 32 bits.
|
next_execution_major_ = value.major;
|
||||||
// This is correct because millis_major_ that creates these values is also 16 bits.
|
|
||||||
next_execution_high_ = static_cast<uint16_t>(value >> 32);
|
|
||||||
}
|
}
|
||||||
constexpr const char *get_type_str() const { return (type == TIMEOUT) ? "timeout" : "interval"; }
|
constexpr const char *get_type_str() const { return (type == TIMEOUT) ? "timeout" : "interval"; }
|
||||||
const LogString *get_source() const { return component ? component->get_component_log_str() : LOG_STR("unknown"); }
|
const LogString *get_source() const { return component ? component->get_component_log_str() : LOG_STR("unknown"); }
|
||||||
@@ -214,7 +248,7 @@ class Scheduler {
|
|||||||
void set_retry_common_(Component *component, bool is_static_string, const void *name_ptr, uint32_t initial_wait_time,
|
void set_retry_common_(Component *component, bool is_static_string, const void *name_ptr, uint32_t initial_wait_time,
|
||||||
uint8_t max_attempts, std::function<RetryResult(uint8_t)> func, float backoff_increase_factor);
|
uint8_t max_attempts, std::function<RetryResult(uint8_t)> func, float backoff_increase_factor);
|
||||||
|
|
||||||
uint64_t millis_64_(uint32_t now);
|
Time48 millis_48_(uint32_t now);
|
||||||
// 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).
|
||||||
@@ -283,7 +317,7 @@ class Scheduler {
|
|||||||
#ifdef ESPHOME_DEBUG_SCHEDULER
|
#ifdef ESPHOME_DEBUG_SCHEDULER
|
||||||
// Helper for debug logging in set_timer_common_ - extracted to reduce code size
|
// Helper for debug logging in set_timer_common_ - extracted to reduce code size
|
||||||
void debug_log_timer_(const SchedulerItem *item, bool is_static_string, const char *name_cstr,
|
void debug_log_timer_(const SchedulerItem *item, bool is_static_string, const char *name_cstr,
|
||||||
SchedulerItem::Type type, uint32_t delay, uint64_t now);
|
SchedulerItem::Type type, uint32_t delay, Time48 now);
|
||||||
#endif /* ESPHOME_DEBUG_SCHEDULER */
|
#endif /* ESPHOME_DEBUG_SCHEDULER */
|
||||||
|
|
||||||
#ifndef ESPHOME_THREAD_SINGLE
|
#ifndef ESPHOME_THREAD_SINGLE
|
||||||
|
|||||||
Reference in New Issue
Block a user