mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 10:12:52 +00:00
End the autorepeat table with a never-run step so the filter stores no count
This commit is contained in:
@@ -264,12 +264,18 @@ async def autorepeat_filter_to_code(config: list[ConfigType], filter_id: ID) ->
|
||||
)
|
||||
for conf in config
|
||||
]
|
||||
# A never-run delay ends the table, so the filter stores no count.
|
||||
timings.append(
|
||||
cg.StructInitializer(
|
||||
AutorepeatFilterTiming, ("delay", cg.RawExpression("SCHEDULER_DONT_RUN"))
|
||||
)
|
||||
)
|
||||
table = cg.shared_progmem_array(
|
||||
"binary_sensor_autorepeat_timings",
|
||||
AutorepeatFilterTiming,
|
||||
cg.ArrayInitializer(*timings),
|
||||
)
|
||||
return cg.new_Pvariable(filter_id, table, len(timings))
|
||||
return cg.new_Pvariable(filter_id, table)
|
||||
|
||||
|
||||
@register_filter("lambda", LambdaFilter, cv.returning_lambda)
|
||||
|
||||
@@ -83,12 +83,12 @@ optional<bool> AutorepeatFilter::new_value(bool value) {
|
||||
}
|
||||
|
||||
void AutorepeatFilter::next_timing_() {
|
||||
if (this->active_timing_ < this->timings_count_) {
|
||||
App.scheduler.set_timeout(this, this->timings_[this->active_timing_].delay, [this]() { this->next_timing_(); });
|
||||
}
|
||||
if (this->active_timing_ <= this->timings_count_) {
|
||||
this->active_timing_++;
|
||||
const uint32_t delay = this->timings_[this->active_timing_].delay;
|
||||
if (delay != SCHEDULER_DONT_RUN) {
|
||||
App.scheduler.set_timeout(this, delay, [this]() { this->next_timing_(); });
|
||||
}
|
||||
// Only reached with active_timing_ at most the end-marker index, so this never passes it.
|
||||
this->active_timing_++;
|
||||
if (this->active_timing_ == 2)
|
||||
this->next_value_(false);
|
||||
}
|
||||
|
||||
@@ -93,14 +93,13 @@ static_assert(std::is_same_v<decltype(AutorepeatFilterTiming::delay), uint32_t>
|
||||
std::is_same_v<decltype(AutorepeatFilterTiming::time_on), uint32_t>,
|
||||
"AutorepeatFilterTiming fields must stay uint32_t");
|
||||
|
||||
/// Timings live in a PROGMEM table emitted by codegen. Every field is uint32_t, so aligned
|
||||
/// loads straight from flash are safe on ESP8266.
|
||||
/// Timings live in a PROGMEM table emitted by codegen, ended by an entry whose delay is
|
||||
/// SCHEDULER_DONT_RUN (a step that could never advance anyway). Aligned loads are ESP8266 safe.
|
||||
/// The two scheduled timers are keyed off `this` and `&active_timing_`; since the address
|
||||
/// of `active_timing_` is taken as a scheduler key, the class must not be copied or moved.
|
||||
class AutorepeatFilter : public Filter {
|
||||
public:
|
||||
AutorepeatFilter(const AutorepeatFilterTiming *timings, uint8_t timings_count)
|
||||
: timings_(timings), timings_count_(timings_count) {}
|
||||
explicit AutorepeatFilter(const AutorepeatFilterTiming *timings) : timings_(timings) {}
|
||||
AutorepeatFilter(const AutorepeatFilter &) = delete;
|
||||
AutorepeatFilter &operator=(const AutorepeatFilter &) = delete;
|
||||
|
||||
@@ -110,9 +109,8 @@ class AutorepeatFilter : public Filter {
|
||||
void next_timing_();
|
||||
void next_value_(bool val);
|
||||
|
||||
uint8_t active_timing_{0}; // before timings_ so it fills the padding after the Filter base
|
||||
const AutorepeatFilterTiming *timings_;
|
||||
uint8_t timings_count_;
|
||||
uint8_t active_timing_{0};
|
||||
};
|
||||
|
||||
class LambdaFilter : public Filter {
|
||||
|
||||
@@ -16,9 +16,11 @@ def test_autorepeat_timings_shared_progmem_table(
|
||||
)
|
||||
assert len(tables) == 2
|
||||
shared, default = tables
|
||||
assert main_cpp.count(f"AutorepeatFilter({shared}, 2);") == 2
|
||||
assert f"AutorepeatFilter({default}, 1);" in main_cpp
|
||||
assert main_cpp.count(f"AutorepeatFilter({shared});") == 2
|
||||
assert f"AutorepeatFilter({default});" in main_cpp
|
||||
assert "binary_sensor_autorepeat_timings" not in tables
|
||||
default_table = main_cpp.split(f"{default}[] PROGMEM = ", 1)[1].split(";", 1)[0]
|
||||
for field in (".delay = 1000", ".time_off = 100", ".time_on = 900"):
|
||||
assert field in default_table
|
||||
# Each table ends with a never-run delay instead of the filter storing a count.
|
||||
assert main_cpp.count(".delay = SCHEDULER_DONT_RUN") == len(tables)
|
||||
|
||||
Reference in New Issue
Block a user