mirror of
https://github.com/esphome/esphome.git
synced 2026-09-02 02:56:01 +00:00
[gpio] Remove redundant last_state_ and pack GPIOBinarySensor fields
Remove last_state_ from GPIOBinarySensorStore — it was always set to the same value as state_ in the ISR and never written elsewhere, making the comparison `new_state != last_state_` equivalent to `new_state != state_`. Move use_interrupt_ and interrupt_type_ into the store to fill the padding freed by removing last_state_, eliminating all internal padding. Store layout (12B, zero padding): isr_pin_.arg_* 4B component_* 4B state_ 1B (volatile) changed_ 1B (volatile) use_interrupt_ 1B interrupt_type_ 1B Saves 4 bytes per GPIOBinarySensor instance (64B → 60B).
This commit is contained in:
@@ -23,9 +23,8 @@ static const LogString *gpio_mode_to_string(bool use_interrupt) {
|
||||
|
||||
void IRAM_ATTR GPIOBinarySensorStore::gpio_intr(GPIOBinarySensorStore *arg) {
|
||||
bool new_state = arg->isr_pin_.digital_read();
|
||||
if (new_state != arg->last_state_) {
|
||||
if (new_state != arg->state_) {
|
||||
arg->state_ = new_state;
|
||||
arg->last_state_ = new_state;
|
||||
arg->changed_ = true;
|
||||
// Wake up the component from its disabled loop state
|
||||
if (arg->component_ != nullptr) {
|
||||
@@ -40,22 +39,21 @@ void GPIOBinarySensorStore::setup(InternalGPIOPin *pin, gpio::InterruptType type
|
||||
this->component_ = component;
|
||||
|
||||
// Read initial state
|
||||
this->last_state_ = pin->digital_read();
|
||||
this->state_ = this->last_state_;
|
||||
this->state_ = pin->digital_read();
|
||||
|
||||
// Attach interrupt - from this point on, any changes will be caught by the interrupt
|
||||
pin->attach_interrupt(&GPIOBinarySensorStore::gpio_intr, this, type);
|
||||
}
|
||||
|
||||
void GPIOBinarySensor::setup() {
|
||||
if (this->use_interrupt_ && !this->pin_->is_internal()) {
|
||||
if (this->store_.use_interrupt_ && !this->pin_->is_internal()) {
|
||||
ESP_LOGD(TAG, "GPIO is not internal, falling back to polling mode");
|
||||
this->use_interrupt_ = false;
|
||||
this->store_.use_interrupt_ = false;
|
||||
}
|
||||
|
||||
if (this->use_interrupt_) {
|
||||
if (this->store_.use_interrupt_) {
|
||||
auto *internal_pin = static_cast<InternalGPIOPin *>(this->pin_);
|
||||
this->store_.setup(internal_pin, this->interrupt_type_, this);
|
||||
this->store_.setup(internal_pin, this->store_.interrupt_type_, this);
|
||||
this->publish_initial_state(this->store_.get_state());
|
||||
} else {
|
||||
this->pin_->setup();
|
||||
@@ -66,14 +64,14 @@ void GPIOBinarySensor::setup() {
|
||||
void GPIOBinarySensor::dump_config() {
|
||||
LOG_BINARY_SENSOR("", "GPIO Binary Sensor", this);
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
ESP_LOGCONFIG(TAG, " Mode: %s", LOG_STR_ARG(gpio_mode_to_string(this->use_interrupt_)));
|
||||
if (this->use_interrupt_) {
|
||||
ESP_LOGCONFIG(TAG, " Interrupt Type: %s", LOG_STR_ARG(interrupt_type_to_string(this->interrupt_type_)));
|
||||
ESP_LOGCONFIG(TAG, " Mode: %s", LOG_STR_ARG(gpio_mode_to_string(this->store_.use_interrupt_)));
|
||||
if (this->store_.use_interrupt_) {
|
||||
ESP_LOGCONFIG(TAG, " Interrupt Type: %s", LOG_STR_ARG(interrupt_type_to_string(this->store_.interrupt_type_)));
|
||||
}
|
||||
}
|
||||
|
||||
void GPIOBinarySensor::loop() {
|
||||
if (this->use_interrupt_) {
|
||||
if (this->store_.use_interrupt_) {
|
||||
if (this->store_.is_changed()) {
|
||||
// Clear the flag immediately to minimize the window where we might miss changes
|
||||
this->store_.clear_changed();
|
||||
|
||||
@@ -32,11 +32,13 @@ class GPIOBinarySensorStore {
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class GPIOBinarySensor;
|
||||
ISRInternalGPIOPin isr_pin_;
|
||||
volatile bool state_{false};
|
||||
volatile bool last_state_{false};
|
||||
volatile bool changed_{false};
|
||||
Component *component_{nullptr}; // Pointer to the component for enable_loop_soon_any_context()
|
||||
volatile bool state_{false};
|
||||
volatile bool changed_{false};
|
||||
bool use_interrupt_{true};
|
||||
gpio::InterruptType interrupt_type_{gpio::INTERRUPT_ANY_EDGE};
|
||||
};
|
||||
|
||||
class GPIOBinarySensor final : public binary_sensor::BinarySensor, public Component {
|
||||
@@ -44,9 +46,9 @@ class GPIOBinarySensor final : public binary_sensor::BinarySensor, public Compon
|
||||
// No destructor needed: ESPHome components are created at boot and live forever.
|
||||
// Interrupts are only detached on reboot when memory is cleared anyway.
|
||||
|
||||
void set_pin(GPIOPin *pin) { pin_ = pin; }
|
||||
void set_use_interrupt(bool use_interrupt) { use_interrupt_ = use_interrupt; }
|
||||
void set_interrupt_type(gpio::InterruptType type) { interrupt_type_ = type; }
|
||||
void set_pin(GPIOPin *pin) { this->pin_ = pin; }
|
||||
void set_use_interrupt(bool use_interrupt) { this->store_.use_interrupt_ = use_interrupt; }
|
||||
void set_interrupt_type(gpio::InterruptType type) { this->store_.interrupt_type_ = type; }
|
||||
// ========== INTERNAL METHODS ==========
|
||||
// (In most use cases you won't need these)
|
||||
/// Setup pin
|
||||
@@ -59,8 +61,6 @@ class GPIOBinarySensor final : public binary_sensor::BinarySensor, public Compon
|
||||
|
||||
protected:
|
||||
GPIOPin *pin_;
|
||||
bool use_interrupt_{true};
|
||||
gpio::InterruptType interrupt_type_{gpio::INTERRUPT_ANY_EDGE};
|
||||
GPIOBinarySensorStore store_;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user