mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Add IDF support to dallas (#2578)
This commit is contained in:
		| @@ -6,26 +6,20 @@ from esphome.const import CONF_ID, CONF_PIN | |||||||
| MULTI_CONF = True | MULTI_CONF = True | ||||||
| AUTO_LOAD = ["sensor"] | AUTO_LOAD = ["sensor"] | ||||||
|  |  | ||||||
| CONF_ONE_WIRE_ID = "one_wire_id" |  | ||||||
| dallas_ns = cg.esphome_ns.namespace("dallas") | dallas_ns = cg.esphome_ns.namespace("dallas") | ||||||
| DallasComponent = dallas_ns.class_("DallasComponent", cg.PollingComponent) | DallasComponent = dallas_ns.class_("DallasComponent", cg.PollingComponent) | ||||||
| ESPOneWire = dallas_ns.class_("ESPOneWire") |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.All( | CONFIG_SCHEMA = cv.Schema( | ||||||
|     cv.Schema( |     { | ||||||
|         { |         cv.GenerateID(): cv.declare_id(DallasComponent), | ||||||
|             cv.GenerateID(): cv.declare_id(DallasComponent), |         cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema, | ||||||
|             cv.GenerateID(CONF_ONE_WIRE_ID): cv.declare_id(ESPOneWire), |     } | ||||||
|             cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema, | ).extend(cv.polling_component_schema("60s")) | ||||||
|         } |  | ||||||
|     ).extend(cv.polling_component_schema("60s")), |  | ||||||
|     # pin_mode call logs in esp-idf, but InterruptLock is active -> crash |  | ||||||
|     cv.only_with_arduino, |  | ||||||
| ) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def to_code(config): | async def to_code(config): | ||||||
|     pin = await cg.gpio_pin_expression(config[CONF_PIN]) |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|     one_wire = cg.new_Pvariable(config[CONF_ONE_WIRE_ID], pin) |  | ||||||
|     var = cg.new_Pvariable(config[CONF_ID], one_wire) |  | ||||||
|     await cg.register_component(var, config) |     await cg.register_component(var, config) | ||||||
|  |  | ||||||
|  |     pin = await cg.gpio_pin_expression(config[CONF_PIN]) | ||||||
|  |     cg.add(var.set_pin(pin)) | ||||||
|   | |||||||
| @@ -31,12 +31,11 @@ uint16_t DallasTemperatureSensor::millis_to_wait_for_conversion() const { | |||||||
| void DallasComponent::setup() { | void DallasComponent::setup() { | ||||||
|   ESP_LOGCONFIG(TAG, "Setting up DallasComponent..."); |   ESP_LOGCONFIG(TAG, "Setting up DallasComponent..."); | ||||||
|  |  | ||||||
|   yield(); |   pin_->setup(); | ||||||
|  |   one_wire_ = new ESPOneWire(pin_);  // NOLINT(cppcoreguidelines-owning-memory) | ||||||
|  |  | ||||||
|   std::vector<uint64_t> raw_sensors; |   std::vector<uint64_t> raw_sensors; | ||||||
|   { |   raw_sensors = this->one_wire_->search_vec(); | ||||||
|     InterruptLock lock; |  | ||||||
|     raw_sensors = this->one_wire_->search_vec(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   for (auto &address : raw_sensors) { |   for (auto &address : raw_sensors) { | ||||||
|     std::string s = uint64_to_string(address); |     std::string s = uint64_to_string(address); | ||||||
| @@ -70,7 +69,7 @@ void DallasComponent::setup() { | |||||||
| } | } | ||||||
| void DallasComponent::dump_config() { | void DallasComponent::dump_config() { | ||||||
|   ESP_LOGCONFIG(TAG, "DallasComponent:"); |   ESP_LOGCONFIG(TAG, "DallasComponent:"); | ||||||
|   LOG_PIN("  Pin: ", this->one_wire_->get_pin()); |   LOG_PIN("  Pin: ", this->pin_); | ||||||
|   LOG_UPDATE_INTERVAL(this); |   LOG_UPDATE_INTERVAL(this); | ||||||
|  |  | ||||||
|   if (this->found_sensors_.empty()) { |   if (this->found_sensors_.empty()) { | ||||||
| @@ -102,15 +101,12 @@ void DallasComponent::update() { | |||||||
|   this->status_clear_warning(); |   this->status_clear_warning(); | ||||||
|  |  | ||||||
|   bool result; |   bool result; | ||||||
|   { |   if (!this->one_wire_->reset()) { | ||||||
|     InterruptLock lock; |     result = false; | ||||||
|     if (!this->one_wire_->reset()) { |   } else { | ||||||
|       result = false; |     result = true; | ||||||
|     } else { |     this->one_wire_->skip(); | ||||||
|       result = true; |     this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION); | ||||||
|       this->one_wire_->skip(); |  | ||||||
|       this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION); |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (!result) { |   if (!result) { | ||||||
| @@ -121,11 +117,7 @@ void DallasComponent::update() { | |||||||
|  |  | ||||||
|   for (auto *sensor : this->sensors_) { |   for (auto *sensor : this->sensors_) { | ||||||
|     this->set_timeout(sensor->get_address_name(), sensor->millis_to_wait_for_conversion(), [this, sensor] { |     this->set_timeout(sensor->get_address_name(), sensor->millis_to_wait_for_conversion(), [this, sensor] { | ||||||
|       bool res; |       bool res = sensor->read_scratch_pad(); | ||||||
|       { |  | ||||||
|         InterruptLock lock; |  | ||||||
|         res = sensor->read_scratch_pad(); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       if (!res) { |       if (!res) { | ||||||
|         ESP_LOGW(TAG, "'%s' - Resetting bus for read failed!", sensor->get_name().c_str()); |         ESP_LOGW(TAG, "'%s' - Resetting bus for read failed!", sensor->get_name().c_str()); | ||||||
| @@ -146,7 +138,6 @@ void DallasComponent::update() { | |||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| DallasComponent::DallasComponent(ESPOneWire *one_wire) : one_wire_(one_wire) {} |  | ||||||
|  |  | ||||||
| void DallasTemperatureSensor::set_address(uint64_t address) { this->address_ = address; } | void DallasTemperatureSensor::set_address(uint64_t address) { this->address_ = address; } | ||||||
| uint8_t DallasTemperatureSensor::get_resolution() const { return this->resolution_; } | uint8_t DallasTemperatureSensor::get_resolution() const { return this->resolution_; } | ||||||
| @@ -162,7 +153,7 @@ const std::string &DallasTemperatureSensor::get_address_name() { | |||||||
|   return this->address_name_; |   return this->address_name_; | ||||||
| } | } | ||||||
| bool IRAM_ATTR DallasTemperatureSensor::read_scratch_pad() { | bool IRAM_ATTR DallasTemperatureSensor::read_scratch_pad() { | ||||||
|   ESPOneWire *wire = this->parent_->one_wire_; |   auto *wire = this->parent_->one_wire_; | ||||||
|   if (!wire->reset()) { |   if (!wire->reset()) { | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
| @@ -176,11 +167,7 @@ bool IRAM_ATTR DallasTemperatureSensor::read_scratch_pad() { | |||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
| bool DallasTemperatureSensor::setup_sensor() { | bool DallasTemperatureSensor::setup_sensor() { | ||||||
|   bool r; |   bool r = this->read_scratch_pad(); | ||||||
|   { |  | ||||||
|     InterruptLock lock; |  | ||||||
|     r = this->read_scratch_pad(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (!r) { |   if (!r) { | ||||||
|     ESP_LOGE(TAG, "Reading scratchpad failed: reset"); |     ESP_LOGE(TAG, "Reading scratchpad failed: reset"); | ||||||
| @@ -214,21 +201,18 @@ bool DallasTemperatureSensor::setup_sensor() { | |||||||
|       break; |       break; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   ESPOneWire *wire = this->parent_->one_wire_; |   auto *wire = this->parent_->one_wire_; | ||||||
|   { |   if (wire->reset()) { | ||||||
|     InterruptLock lock; |     wire->select(this->address_); | ||||||
|     if (wire->reset()) { |     wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD); | ||||||
|       wire->select(this->address_); |     wire->write8(this->scratch_pad_[2]);  // high alarm temp | ||||||
|       wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD); |     wire->write8(this->scratch_pad_[3]);  // low alarm temp | ||||||
|       wire->write8(this->scratch_pad_[2]);  // high alarm temp |     wire->write8(this->scratch_pad_[4]);  // resolution | ||||||
|       wire->write8(this->scratch_pad_[3]);  // low alarm temp |     wire->reset(); | ||||||
|       wire->write8(this->scratch_pad_[4]);  // resolution |  | ||||||
|       wire->reset(); |  | ||||||
|  |  | ||||||
|       // write value to EEPROM |     // write value to EEPROM | ||||||
|       wire->select(this->address_); |     wire->select(this->address_); | ||||||
|       wire->write8(0x48); |     wire->write8(0x48); | ||||||
|     } |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   delay(20);  // allow it to finish operation |   delay(20);  // allow it to finish operation | ||||||
|   | |||||||
| @@ -11,8 +11,7 @@ class DallasTemperatureSensor; | |||||||
|  |  | ||||||
| class DallasComponent : public PollingComponent { | class DallasComponent : public PollingComponent { | ||||||
|  public: |  public: | ||||||
|   explicit DallasComponent(ESPOneWire *one_wire); |   void set_pin(InternalGPIOPin *pin) { pin_ = pin; } | ||||||
|  |  | ||||||
|   void register_sensor(DallasTemperatureSensor *sensor); |   void register_sensor(DallasTemperatureSensor *sensor); | ||||||
|  |  | ||||||
|   void setup() override; |   void setup() override; | ||||||
| @@ -24,6 +23,7 @@ class DallasComponent : public PollingComponent { | |||||||
|  protected: |  protected: | ||||||
|   friend DallasTemperatureSensor; |   friend DallasTemperatureSensor; | ||||||
|  |  | ||||||
|  |   InternalGPIOPin *pin_; | ||||||
|   ESPOneWire *one_wire_; |   ESPOneWire *one_wire_; | ||||||
|   std::vector<DallasTemperatureSensor *> sensors_; |   std::vector<DallasTemperatureSensor *> sensors_; | ||||||
|   std::vector<uint64_t> found_sensors_; |   std::vector<uint64_t> found_sensors_; | ||||||
|   | |||||||
| @@ -10,115 +10,123 @@ static const char *const TAG = "dallas.one_wire"; | |||||||
| const uint8_t ONE_WIRE_ROM_SELECT = 0x55; | const uint8_t ONE_WIRE_ROM_SELECT = 0x55; | ||||||
| const int ONE_WIRE_ROM_SEARCH = 0xF0; | const int ONE_WIRE_ROM_SEARCH = 0xF0; | ||||||
|  |  | ||||||
| ESPOneWire::ESPOneWire(GPIOPin *pin) : pin_(pin) {} | ESPOneWire::ESPOneWire(InternalGPIOPin *pin) { pin_ = pin->to_isr(); } | ||||||
|  |  | ||||||
| bool HOT IRAM_ATTR ESPOneWire::reset() { | bool HOT IRAM_ATTR ESPOneWire::reset() { | ||||||
|   uint8_t retries = 125; |   // See reset here: | ||||||
|  |   // https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html | ||||||
|  |   InterruptLock lock; | ||||||
|  |  | ||||||
|   // Wait for communication to clear |   // Wait for communication to clear (delay G) | ||||||
|   this->pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); |   pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); | ||||||
|  |   uint8_t retries = 125; | ||||||
|   do { |   do { | ||||||
|     if (--retries == 0) |     if (--retries == 0) | ||||||
|       return false; |       return false; | ||||||
|     delayMicroseconds(2); |     delayMicroseconds(2); | ||||||
|   } while (!this->pin_->digital_read()); |   } while (!pin_.digital_read()); | ||||||
|  |  | ||||||
|   // Send 480µs LOW TX reset pulse |   // Send 480µs LOW TX reset pulse (drive bus low, delay H) | ||||||
|   this->pin_->pin_mode(gpio::FLAG_OUTPUT); |   pin_.pin_mode(gpio::FLAG_OUTPUT); | ||||||
|   this->pin_->digital_write(false); |   pin_.digital_write(false); | ||||||
|   delayMicroseconds(480); |   delayMicroseconds(480); | ||||||
|  |  | ||||||
|   // Switch into RX mode, letting the pin float |   // Release the bus, delay I | ||||||
|   this->pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); |   pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); | ||||||
|   // after 15µs-60µs wait time, responder pulls low for 60µs-240µs |  | ||||||
|   // let's have 70µs just in case |  | ||||||
|   delayMicroseconds(70); |   delayMicroseconds(70); | ||||||
|  |  | ||||||
|   bool r = !this->pin_->digital_read(); |   // sample bus, 0=device(s) present, 1=no device present | ||||||
|  |   bool r = !pin_.digital_read(); | ||||||
|  |   // delay J | ||||||
|   delayMicroseconds(410); |   delayMicroseconds(410); | ||||||
|   return r; |   return r; | ||||||
| } | } | ||||||
|  |  | ||||||
| void HOT IRAM_ATTR ESPOneWire::write_bit(bool bit) { | void HOT IRAM_ATTR ESPOneWire::write_bit(bool bit) { | ||||||
|   // Initiate write/read by pulling low. |   // See write 1/0 bit here: | ||||||
|   this->pin_->pin_mode(gpio::FLAG_OUTPUT); |   // https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html | ||||||
|   this->pin_->digital_write(false); |   InterruptLock lock; | ||||||
|  |  | ||||||
|   // bus sampled within 15µs and 60µs after pulling LOW. |   // drive bus low | ||||||
|   if (bit) { |   pin_.pin_mode(gpio::FLAG_OUTPUT); | ||||||
|     // pull high/release within 15µs |   pin_.digital_write(false); | ||||||
|     delayMicroseconds(10); |  | ||||||
|     this->pin_->digital_write(true); |   uint32_t delay0 = bit ? 10 : 65; | ||||||
|     // in total minimum of 60µs long |   uint32_t delay1 = bit ? 55 : 5; | ||||||
|     delayMicroseconds(55); |  | ||||||
|   } else { |   // delay A/C | ||||||
|     // continue pulling LOW for at least 60µs |   delayMicroseconds(delay0); | ||||||
|     delayMicroseconds(65); |   // release bus | ||||||
|     this->pin_->digital_write(true); |   pin_.digital_write(true); | ||||||
|     // grace period, 1µs recovery time |   // delay B/D | ||||||
|     delayMicroseconds(5); |   delayMicroseconds(delay1); | ||||||
|   } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| bool HOT IRAM_ATTR ESPOneWire::read_bit() { | bool HOT IRAM_ATTR ESPOneWire::read_bit() { | ||||||
|   // Initiate read slot by pulling LOW for at least 1µs |   // See read bit here: | ||||||
|   this->pin_->pin_mode(gpio::FLAG_OUTPUT); |   // https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html | ||||||
|   this->pin_->digital_write(false); |   InterruptLock lock; | ||||||
|  |  | ||||||
|  |   // drive bus low, delay A | ||||||
|  |   pin_.pin_mode(gpio::FLAG_OUTPUT); | ||||||
|  |   pin_.digital_write(false); | ||||||
|   delayMicroseconds(3); |   delayMicroseconds(3); | ||||||
|  |  | ||||||
|   // release bus, we have to sample within 15µs of pulling low |   // release bus, delay E | ||||||
|   this->pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); |   pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); | ||||||
|   delayMicroseconds(10); |   delayMicroseconds(10); | ||||||
|  |  | ||||||
|   bool r = this->pin_->digital_read(); |   // sample bus to read bit from peer | ||||||
|   // read time slot at least 60µs long + 1µs recovery time between slots |   bool r = pin_.digital_read(); | ||||||
|  |  | ||||||
|  |   // delay F | ||||||
|   delayMicroseconds(53); |   delayMicroseconds(53); | ||||||
|   return r; |   return r; | ||||||
| } | } | ||||||
|  |  | ||||||
| void IRAM_ATTR ESPOneWire::write8(uint8_t val) { | void ESPOneWire::write8(uint8_t val) { | ||||||
|   for (uint8_t i = 0; i < 8; i++) { |   for (uint8_t i = 0; i < 8; i++) { | ||||||
|     this->write_bit(bool((1u << i) & val)); |     this->write_bit(bool((1u << i) & val)); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| void IRAM_ATTR ESPOneWire::write64(uint64_t val) { | void ESPOneWire::write64(uint64_t val) { | ||||||
|   for (uint8_t i = 0; i < 64; i++) { |   for (uint8_t i = 0; i < 64; i++) { | ||||||
|     this->write_bit(bool((1ULL << i) & val)); |     this->write_bit(bool((1ULL << i) & val)); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| uint8_t IRAM_ATTR ESPOneWire::read8() { | uint8_t ESPOneWire::read8() { | ||||||
|   uint8_t ret = 0; |   uint8_t ret = 0; | ||||||
|   for (uint8_t i = 0; i < 8; i++) { |   for (uint8_t i = 0; i < 8; i++) { | ||||||
|     ret |= (uint8_t(this->read_bit()) << i); |     ret |= (uint8_t(this->read_bit()) << i); | ||||||
|   } |   } | ||||||
|   return ret; |   return ret; | ||||||
| } | } | ||||||
| uint64_t IRAM_ATTR ESPOneWire::read64() { | uint64_t ESPOneWire::read64() { | ||||||
|   uint64_t ret = 0; |   uint64_t ret = 0; | ||||||
|   for (uint8_t i = 0; i < 8; i++) { |   for (uint8_t i = 0; i < 8; i++) { | ||||||
|     ret |= (uint64_t(this->read_bit()) << i); |     ret |= (uint64_t(this->read_bit()) << i); | ||||||
|   } |   } | ||||||
|   return ret; |   return ret; | ||||||
| } | } | ||||||
| void IRAM_ATTR ESPOneWire::select(uint64_t address) { | void ESPOneWire::select(uint64_t address) { | ||||||
|   this->write8(ONE_WIRE_ROM_SELECT); |   this->write8(ONE_WIRE_ROM_SELECT); | ||||||
|   this->write64(address); |   this->write64(address); | ||||||
| } | } | ||||||
| void IRAM_ATTR ESPOneWire::reset_search() { | void ESPOneWire::reset_search() { | ||||||
|   this->last_discrepancy_ = 0; |   this->last_discrepancy_ = 0; | ||||||
|   this->last_device_flag_ = false; |   this->last_device_flag_ = false; | ||||||
|   this->last_family_discrepancy_ = 0; |   this->last_family_discrepancy_ = 0; | ||||||
|   this->rom_number_ = 0; |   this->rom_number_ = 0; | ||||||
| } | } | ||||||
| uint64_t HOT IRAM_ATTR ESPOneWire::search() { | uint64_t ESPOneWire::search() { | ||||||
|   if (this->last_device_flag_) { |   if (this->last_device_flag_) { | ||||||
|     return 0u; |     return 0u; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (!this->reset()) { |   if (!this->reset()) { | ||||||
|     // Reset failed |     // Reset failed or no devices present | ||||||
|     this->reset_search(); |     this->reset_search(); | ||||||
|     return 0u; |     return 0u; | ||||||
|   } |   } | ||||||
| @@ -196,7 +204,7 @@ uint64_t HOT IRAM_ATTR ESPOneWire::search() { | |||||||
|  |  | ||||||
|   return this->rom_number_; |   return this->rom_number_; | ||||||
| } | } | ||||||
| std::vector<uint64_t> IRAM_ATTR ESPOneWire::search_vec() { | std::vector<uint64_t> ESPOneWire::search_vec() { | ||||||
|   std::vector<uint64_t> res; |   std::vector<uint64_t> res; | ||||||
|  |  | ||||||
|   this->reset_search(); |   this->reset_search(); | ||||||
| @@ -206,10 +214,9 @@ std::vector<uint64_t> IRAM_ATTR ESPOneWire::search_vec() { | |||||||
|  |  | ||||||
|   return res; |   return res; | ||||||
| } | } | ||||||
| void IRAM_ATTR ESPOneWire::skip() { | void ESPOneWire::skip() { | ||||||
|   this->write8(0xCC);  // skip ROM |   this->write8(0xCC);  // skip ROM | ||||||
| } | } | ||||||
| GPIOPin *ESPOneWire::get_pin() { return this->pin_; } |  | ||||||
|  |  | ||||||
| uint8_t IRAM_ATTR *ESPOneWire::rom_number8_() { return reinterpret_cast<uint8_t *>(&this->rom_number_); } | uint8_t IRAM_ATTR *ESPOneWire::rom_number8_() { return reinterpret_cast<uint8_t *>(&this->rom_number_); } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "esphome/core/component.h" |  | ||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
| #include <vector> | #include <vector> | ||||||
|  |  | ||||||
| @@ -12,7 +11,7 @@ extern const int ONE_WIRE_ROM_SEARCH; | |||||||
|  |  | ||||||
| class ESPOneWire { | class ESPOneWire { | ||||||
|  public: |  public: | ||||||
|   explicit ESPOneWire(GPIOPin *pin); |   explicit ESPOneWire(InternalGPIOPin *pin); | ||||||
|  |  | ||||||
|   /** Reset the bus, should be done before all write operations. |   /** Reset the bus, should be done before all write operations. | ||||||
|    * |    * | ||||||
| @@ -55,13 +54,11 @@ class ESPOneWire { | |||||||
|   /// Helper that wraps search in a std::vector. |   /// Helper that wraps search in a std::vector. | ||||||
|   std::vector<uint64_t> search_vec(); |   std::vector<uint64_t> search_vec(); | ||||||
|  |  | ||||||
|   GPIOPin *get_pin(); |  | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   /// Helper to get the internal 64-bit unsigned rom number as a 8-bit integer pointer. |   /// Helper to get the internal 64-bit unsigned rom number as a 8-bit integer pointer. | ||||||
|   inline uint8_t *rom_number8_(); |   inline uint8_t *rom_number8_(); | ||||||
|  |  | ||||||
|   GPIOPin *pin_; |   ISRInternalGPIOPin pin_; | ||||||
|   uint8_t last_discrepancy_{0}; |   uint8_t last_discrepancy_{0}; | ||||||
|   uint8_t last_family_discrepancy_{0}; |   uint8_t last_family_discrepancy_{0}; | ||||||
|   bool last_device_flag_{false}; |   bool last_device_flag_{false}; | ||||||
|   | |||||||
| @@ -9,6 +9,22 @@ namespace esp32 { | |||||||
|  |  | ||||||
| static const char *const TAG = "esp32"; | static const char *const TAG = "esp32"; | ||||||
|  |  | ||||||
|  | static int IRAM_ATTR flags_to_mode(gpio::Flags flags) { | ||||||
|  |   if (flags == gpio::FLAG_INPUT) { | ||||||
|  |     return INPUT; | ||||||
|  |   } else if (flags == gpio::FLAG_OUTPUT) { | ||||||
|  |     return OUTPUT; | ||||||
|  |   } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) { | ||||||
|  |     return INPUT_PULLUP; | ||||||
|  |   } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLDOWN)) { | ||||||
|  |     return INPUT_PULLDOWN; | ||||||
|  |   } else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) { | ||||||
|  |     return OUTPUT_OPEN_DRAIN; | ||||||
|  |   } else { | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| struct ISRPinArg { | struct ISRPinArg { | ||||||
|   uint8_t pin; |   uint8_t pin; | ||||||
|   bool inverted; |   bool inverted; | ||||||
| @@ -43,22 +59,9 @@ void ArduinoInternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, g | |||||||
|  |  | ||||||
|   attachInterruptArg(pin_, func, arg, arduino_mode); |   attachInterruptArg(pin_, func, arg, arduino_mode); | ||||||
| } | } | ||||||
|  |  | ||||||
| void ArduinoInternalGPIOPin::pin_mode(gpio::Flags flags) { | void ArduinoInternalGPIOPin::pin_mode(gpio::Flags flags) { | ||||||
|   uint8_t mode; |   pinMode(pin_, flags_to_mode(flags));  // NOLINT | ||||||
|   if (flags == gpio::FLAG_INPUT) { |  | ||||||
|     mode = INPUT; |  | ||||||
|   } else if (flags == gpio::FLAG_OUTPUT) { |  | ||||||
|     mode = OUTPUT; |  | ||||||
|   } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) { |  | ||||||
|     mode = INPUT_PULLUP; |  | ||||||
|   } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLDOWN)) { |  | ||||||
|     mode = INPUT_PULLDOWN; |  | ||||||
|   } else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) { |  | ||||||
|     mode = OUTPUT_OPEN_DRAIN; |  | ||||||
|   } else { |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   pinMode(pin_, mode);  // NOLINT |  | ||||||
| } | } | ||||||
|  |  | ||||||
| std::string ArduinoInternalGPIOPin::dump_summary() const { | std::string ArduinoInternalGPIOPin::dump_summary() const { | ||||||
| @@ -101,6 +104,10 @@ void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() { | |||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  | void IRAM_ATTR ISRInternalGPIOPin::pin_mode(gpio::Flags flags) { | ||||||
|  |   auto *arg = reinterpret_cast<ISRPinArg *>(arg_); | ||||||
|  |   pinMode(arg->pin, flags_to_mode(flags));  // NOLINT | ||||||
|  | } | ||||||
|  |  | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,38 +10,7 @@ static const char *const TAG = "esp32"; | |||||||
|  |  | ||||||
| bool IDFInternalGPIOPin::isr_service_installed = false;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | bool IDFInternalGPIOPin::isr_service_installed = false;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||||
|  |  | ||||||
| struct ISRPinArg { | static gpio_mode_t IRAM_ATTR flags_to_mode(gpio::Flags flags) { | ||||||
|   gpio_num_t pin; |  | ||||||
|   bool inverted; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| ISRInternalGPIOPin IDFInternalGPIOPin::to_isr() const { |  | ||||||
|   auto *arg = new ISRPinArg{};  // NOLINT(cppcoreguidelines-owning-memory) |  | ||||||
|   arg->pin = pin_; |  | ||||||
|   arg->inverted = inverted_; |  | ||||||
|   return ISRInternalGPIOPin((void *) arg); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void IDFInternalGPIOPin::setup() { |  | ||||||
|   pin_mode(flags_); |  | ||||||
|   gpio_set_drive_capability(pin_, drive_strength_); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void IDFInternalGPIOPin::pin_mode(gpio::Flags flags) { |  | ||||||
|   gpio_config_t conf{}; |  | ||||||
|   conf.pin_bit_mask = 1ULL << static_cast<uint32_t>(pin_); |  | ||||||
|   conf.mode = flags_to_mode(flags); |  | ||||||
|   conf.pull_up_en = flags & gpio::FLAG_PULLUP ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE; |  | ||||||
|   conf.pull_down_en = flags & gpio::FLAG_PULLDOWN ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE; |  | ||||||
|   conf.intr_type = GPIO_INTR_DISABLE; |  | ||||||
|   gpio_config(&conf); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool IDFInternalGPIOPin::digital_read() { return bool(gpio_get_level(pin_)) != inverted_; } |  | ||||||
|  |  | ||||||
| void IDFInternalGPIOPin::digital_write(bool value) { gpio_set_level(pin_, value != inverted_ ? 1 : 0); } |  | ||||||
|  |  | ||||||
| gpio_mode_t IDFInternalGPIOPin::flags_to_mode(gpio::Flags flags) { |  | ||||||
|   flags = (gpio::Flags)(flags & ~(gpio::FLAG_PULLUP | gpio::FLAG_PULLDOWN)); |   flags = (gpio::Flags)(flags & ~(gpio::FLAG_PULLUP | gpio::FLAG_PULLDOWN)); | ||||||
|   if (flags == gpio::FLAG_NONE) { |   if (flags == gpio::FLAG_NONE) { | ||||||
|     return GPIO_MODE_DISABLE; |     return GPIO_MODE_DISABLE; | ||||||
| @@ -61,6 +30,18 @@ gpio_mode_t IDFInternalGPIOPin::flags_to_mode(gpio::Flags flags) { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | struct ISRPinArg { | ||||||
|  |   gpio_num_t pin; | ||||||
|  |   bool inverted; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | ISRInternalGPIOPin IDFInternalGPIOPin::to_isr() const { | ||||||
|  |   auto *arg = new ISRPinArg{};  // NOLINT(cppcoreguidelines-owning-memory) | ||||||
|  |   arg->pin = pin_; | ||||||
|  |   arg->inverted = inverted_; | ||||||
|  |   return ISRInternalGPIOPin((void *) arg); | ||||||
|  | } | ||||||
|  |  | ||||||
| void IDFInternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const { | void IDFInternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const { | ||||||
|   gpio_int_type_t idf_type = GPIO_INTR_ANYEDGE; |   gpio_int_type_t idf_type = GPIO_INTR_ANYEDGE; | ||||||
|   switch (type) { |   switch (type) { | ||||||
| @@ -99,6 +80,35 @@ std::string IDFInternalGPIOPin::dump_summary() const { | |||||||
|   return buffer; |   return buffer; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void IDFInternalGPIOPin::setup() { | ||||||
|  |   gpio_config_t conf{}; | ||||||
|  |   conf.pin_bit_mask = 1ULL << static_cast<uint32_t>(pin_); | ||||||
|  |   conf.mode = flags_to_mode(flags_); | ||||||
|  |   conf.pull_up_en = flags_ & gpio::FLAG_PULLUP ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE; | ||||||
|  |   conf.pull_down_en = flags_ & gpio::FLAG_PULLDOWN ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE; | ||||||
|  |   conf.intr_type = GPIO_INTR_DISABLE; | ||||||
|  |   gpio_config(&conf); | ||||||
|  |   gpio_set_drive_capability(pin_, drive_strength_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void IDFInternalGPIOPin::pin_mode(gpio::Flags flags) { | ||||||
|  |   // can't call gpio_config here because that logs in esp-idf which may cause issues | ||||||
|  |   gpio_set_direction(pin_, flags_to_mode(flags)); | ||||||
|  |   gpio_pull_mode_t pull_mode = GPIO_FLOATING; | ||||||
|  |   if (flags & (gpio::FLAG_PULLUP | gpio::FLAG_PULLDOWN)) { | ||||||
|  |     pull_mode = GPIO_PULLUP_PULLDOWN; | ||||||
|  |   } else if (flags & gpio::FLAG_PULLUP) { | ||||||
|  |     pull_mode = GPIO_PULLUP_ONLY; | ||||||
|  |   } else if (flags & gpio::FLAG_PULLDOWN) { | ||||||
|  |     pull_mode = GPIO_PULLDOWN_ONLY; | ||||||
|  |   } | ||||||
|  |   gpio_set_pull_mode(pin_, pull_mode); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool IDFInternalGPIOPin::digital_read() { return bool(gpio_get_level(pin_)) != inverted_; } | ||||||
|  | void IDFInternalGPIOPin::digital_write(bool value) { gpio_set_level(pin_, value != inverted_ ? 1 : 0); } | ||||||
|  | void IDFInternalGPIOPin::detach_interrupt() const { gpio_intr_disable(pin_); } | ||||||
|  |  | ||||||
| }  // namespace esp32 | }  // namespace esp32 | ||||||
|  |  | ||||||
| using namespace esp32; | using namespace esp32; | ||||||
| @@ -114,6 +124,19 @@ void IRAM_ATTR ISRInternalGPIOPin::digital_write(bool value) { | |||||||
| void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() { | void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() { | ||||||
|   // not supported |   // not supported | ||||||
| } | } | ||||||
|  | void IRAM_ATTR ISRInternalGPIOPin::pin_mode(gpio::Flags flags) { | ||||||
|  |   auto *arg = reinterpret_cast<ISRPinArg *>(arg_); | ||||||
|  |   gpio_set_direction(arg->pin, flags_to_mode(flags)); | ||||||
|  |   gpio_pull_mode_t pull_mode = GPIO_FLOATING; | ||||||
|  |   if (flags & (gpio::FLAG_PULLUP | gpio::FLAG_PULLDOWN)) { | ||||||
|  |     pull_mode = GPIO_PULLUP_PULLDOWN; | ||||||
|  |   } else if (flags & gpio::FLAG_PULLUP) { | ||||||
|  |     pull_mode = GPIO_PULLUP_ONLY; | ||||||
|  |   } else if (flags & gpio::FLAG_PULLDOWN) { | ||||||
|  |     pull_mode = GPIO_PULLDOWN_ONLY; | ||||||
|  |   } | ||||||
|  |   gpio_set_pull_mode(arg->pin, pull_mode); | ||||||
|  | } | ||||||
|  |  | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,13 +18,12 @@ class IDFInternalGPIOPin : public InternalGPIOPin { | |||||||
|   bool digital_read() override; |   bool digital_read() override; | ||||||
|   void digital_write(bool value) override; |   void digital_write(bool value) override; | ||||||
|   std::string dump_summary() const override; |   std::string dump_summary() const override; | ||||||
|   void detach_interrupt() const override { gpio_intr_disable(pin_); } |   void detach_interrupt() const override; | ||||||
|   ISRInternalGPIOPin to_isr() const override; |   ISRInternalGPIOPin to_isr() const override; | ||||||
|   uint8_t get_pin() const override { return (uint8_t) pin_; } |   uint8_t get_pin() const override { return (uint8_t) pin_; } | ||||||
|   bool is_inverted() const override { return inverted_; } |   bool is_inverted() const override { return inverted_; } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   static gpio_mode_t flags_to_mode(gpio::Flags flags); |  | ||||||
|   void attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const override; |   void attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const override; | ||||||
|  |  | ||||||
|   gpio_num_t pin_; |   gpio_num_t pin_; | ||||||
|   | |||||||
| @@ -8,6 +8,29 @@ namespace esp8266 { | |||||||
|  |  | ||||||
| static const char *const TAG = "esp8266"; | static const char *const TAG = "esp8266"; | ||||||
|  |  | ||||||
|  | static int IRAM_ATTR flags_to_mode(gpio::Flags flags, uint8_t pin) { | ||||||
|  |   if (flags == gpio::FLAG_INPUT) { | ||||||
|  |     return INPUT; | ||||||
|  |   } else if (flags == gpio::FLAG_OUTPUT) { | ||||||
|  |     return OUTPUT; | ||||||
|  |   } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) { | ||||||
|  |     if (pin == 16) { | ||||||
|  |       // GPIO16 doesn't have a pullup, so pinMode would fail. | ||||||
|  |       // However, sometimes this method is called with pullup mode anyway | ||||||
|  |       // for example from dallas one_wire. For those cases convert this | ||||||
|  |       // to a INPUT mode. | ||||||
|  |       return INPUT; | ||||||
|  |     } | ||||||
|  |     return INPUT_PULLUP; | ||||||
|  |   } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLDOWN)) { | ||||||
|  |     return INPUT_PULLDOWN_16; | ||||||
|  |   } else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) { | ||||||
|  |     return OUTPUT_OPEN_DRAIN; | ||||||
|  |   } else { | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| struct ISRPinArg { | struct ISRPinArg { | ||||||
|   uint8_t pin; |   uint8_t pin; | ||||||
|   bool inverted; |   bool inverted; | ||||||
| @@ -43,28 +66,7 @@ void ESP8266GPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::Int | |||||||
|   attachInterruptArg(pin_, func, arg, arduino_mode); |   attachInterruptArg(pin_, func, arg, arduino_mode); | ||||||
| } | } | ||||||
| void ESP8266GPIOPin::pin_mode(gpio::Flags flags) { | void ESP8266GPIOPin::pin_mode(gpio::Flags flags) { | ||||||
|   uint8_t mode; |   pinMode(pin_, flags_to_mode(flags, pin_));  // NOLINT | ||||||
|   if (flags == gpio::FLAG_INPUT) { |  | ||||||
|     mode = INPUT; |  | ||||||
|   } else if (flags == gpio::FLAG_OUTPUT) { |  | ||||||
|     mode = OUTPUT; |  | ||||||
|   } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) { |  | ||||||
|     mode = INPUT_PULLUP; |  | ||||||
|     if (pin_ == 16) { |  | ||||||
|       // GPIO16 doesn't have a pullup, so pinMode would fail. |  | ||||||
|       // However, sometimes this method is called with pullup mode anyway |  | ||||||
|       // for example from dallas one_wire. For those cases convert this |  | ||||||
|       // to a INPUT mode. |  | ||||||
|       mode = INPUT; |  | ||||||
|     } |  | ||||||
|   } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLDOWN)) { |  | ||||||
|     mode = INPUT_PULLDOWN_16; |  | ||||||
|   } else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) { |  | ||||||
|     mode = OUTPUT_OPEN_DRAIN; |  | ||||||
|   } else { |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   pinMode(pin_, mode);  // NOLINT |  | ||||||
| } | } | ||||||
|  |  | ||||||
| std::string ESP8266GPIOPin::dump_summary() const { | std::string ESP8266GPIOPin::dump_summary() const { | ||||||
| @@ -97,6 +99,10 @@ void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() { | |||||||
|   auto *arg = reinterpret_cast<ISRPinArg *>(arg_); |   auto *arg = reinterpret_cast<ISRPinArg *>(arg_); | ||||||
|   GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1UL << arg->pin); |   GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1UL << arg->pin); | ||||||
| } | } | ||||||
|  | void IRAM_ATTR ISRInternalGPIOPin::pin_mode(gpio::Flags flags) { | ||||||
|  |   auto *arg = reinterpret_cast<ISRPinArg *>(arg_); | ||||||
|  |   pinMode(arg->pin, flags_to_mode(flags, arg->pin));  // NOLINT | ||||||
|  | } | ||||||
|  |  | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|  |  | ||||||
|   | |||||||
| @@ -70,6 +70,7 @@ class ISRInternalGPIOPin { | |||||||
|   bool digital_read(); |   bool digital_read(); | ||||||
|   void digital_write(bool value); |   void digital_write(bool value); | ||||||
|   void clear_interrupt(); |   void clear_interrupt(); | ||||||
|  |   void pin_mode(gpio::Flags flags); | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   void *arg_ = nullptr; |   void *arg_ = nullptr; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user