mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Add ESP8266 core v2.6.2 (#905)
* Add ESP8266 core v2.6.2 * Upstream ESP8266 Wifi fixes * Replace disable_interrupt with InterruptLock C++ class * Update code to use InterruptLock * Lint * Update dht.cpp * Improve InterruptLock docs, mark as ICACHE_RAM_ATTR * Fixes
This commit is contained in:
		| @@ -32,9 +32,11 @@ void DallasComponent::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up DallasComponent..."); | ||||
|  | ||||
|   yield(); | ||||
|   disable_interrupts(); | ||||
|   std::vector<uint64_t> raw_sensors = this->one_wire_->search_vec(); | ||||
|   enable_interrupts(); | ||||
|   std::vector<uint64_t> raw_sensors; | ||||
|   { | ||||
|     InterruptLock lock; | ||||
|     raw_sensors = this->one_wire_->search_vec(); | ||||
|   } | ||||
|  | ||||
|   for (auto &address : raw_sensors) { | ||||
|     std::string s = uint64_to_string(address); | ||||
| @@ -108,16 +110,17 @@ DallasTemperatureSensor *DallasComponent::get_sensor_by_index(uint8_t index, uin | ||||
| void DallasComponent::update() { | ||||
|   this->status_clear_warning(); | ||||
|  | ||||
|   disable_interrupts(); | ||||
|   bool result; | ||||
|   if (!this->one_wire_->reset()) { | ||||
|     result = false; | ||||
|   } else { | ||||
|     result = true; | ||||
|     this->one_wire_->skip(); | ||||
|     this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION); | ||||
|   { | ||||
|     InterruptLock lock; | ||||
|     if (!this->one_wire_->reset()) { | ||||
|       result = false; | ||||
|     } else { | ||||
|       result = true; | ||||
|       this->one_wire_->skip(); | ||||
|       this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION); | ||||
|     } | ||||
|   } | ||||
|   enable_interrupts(); | ||||
|  | ||||
|   if (!result) { | ||||
|     ESP_LOGE(TAG, "Requesting conversion failed"); | ||||
| @@ -127,9 +130,11 @@ void DallasComponent::update() { | ||||
|  | ||||
|   for (auto *sensor : this->sensors_) { | ||||
|     this->set_timeout(sensor->get_address_name(), sensor->millis_to_wait_for_conversion(), [this, sensor] { | ||||
|       disable_interrupts(); | ||||
|       bool res = sensor->read_scratch_pad(); | ||||
|       enable_interrupts(); | ||||
|       bool res; | ||||
|       { | ||||
|         InterruptLock lock; | ||||
|         res = sensor->read_scratch_pad(); | ||||
|       } | ||||
|  | ||||
|       if (!res) { | ||||
|         ESP_LOGW(TAG, "'%s' - Reseting bus for read failed!", sensor->get_name().c_str()); | ||||
| @@ -170,7 +175,7 @@ const std::string &DallasTemperatureSensor::get_address_name() { | ||||
|  | ||||
|   return this->address_name_; | ||||
| } | ||||
| bool DallasTemperatureSensor::read_scratch_pad() { | ||||
| bool ICACHE_RAM_ATTR DallasTemperatureSensor::read_scratch_pad() { | ||||
|   ESPOneWire *wire = this->parent_->one_wire_; | ||||
|   if (!wire->reset()) { | ||||
|     return false; | ||||
| @@ -185,9 +190,11 @@ bool DallasTemperatureSensor::read_scratch_pad() { | ||||
|   return true; | ||||
| } | ||||
| bool DallasTemperatureSensor::setup_sensor() { | ||||
|   disable_interrupts(); | ||||
|   bool r = this->read_scratch_pad(); | ||||
|   enable_interrupts(); | ||||
|   bool r; | ||||
|   { | ||||
|     InterruptLock lock; | ||||
|     r = this->read_scratch_pad(); | ||||
|   } | ||||
|  | ||||
|   if (!r) { | ||||
|     ESP_LOGE(TAG, "Reading scratchpad failed: reset"); | ||||
| @@ -222,20 +229,21 @@ bool DallasTemperatureSensor::setup_sensor() { | ||||
|   } | ||||
|  | ||||
|   ESPOneWire *wire = this->parent_->one_wire_; | ||||
|   disable_interrupts(); | ||||
|   if (wire->reset()) { | ||||
|     wire->select(this->address_); | ||||
|     wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD); | ||||
|     wire->write8(this->scratch_pad_[2]);  // high alarm temp | ||||
|     wire->write8(this->scratch_pad_[3]);  // low alarm temp | ||||
|     wire->write8(this->scratch_pad_[4]);  // resolution | ||||
|     wire->reset(); | ||||
|   { | ||||
|     InterruptLock lock; | ||||
|     if (wire->reset()) { | ||||
|       wire->select(this->address_); | ||||
|       wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD); | ||||
|       wire->write8(this->scratch_pad_[2]);  // high alarm temp | ||||
|       wire->write8(this->scratch_pad_[3]);  // low alarm temp | ||||
|       wire->write8(this->scratch_pad_[4]);  // resolution | ||||
|       wire->reset(); | ||||
|  | ||||
|     // write value to EEPROM | ||||
|     wire->select(this->address_); | ||||
|     wire->write8(0x48); | ||||
|       // write value to EEPROM | ||||
|       wire->select(this->address_); | ||||
|       wire->write8(0x48); | ||||
|     } | ||||
|   } | ||||
|   enable_interrupts(); | ||||
|  | ||||
|   delay(20);  // allow it to finish operation | ||||
|   wire->reset(); | ||||
|   | ||||
| @@ -12,7 +12,7 @@ const int ONE_WIRE_ROM_SEARCH = 0xF0; | ||||
|  | ||||
| ESPOneWire::ESPOneWire(GPIOPin *pin) : pin_(pin) {} | ||||
|  | ||||
| bool HOT ESPOneWire::reset() { | ||||
| bool HOT ICACHE_RAM_ATTR ESPOneWire::reset() { | ||||
|   uint8_t retries = 125; | ||||
|  | ||||
|   // Wait for communication to clear | ||||
| @@ -39,7 +39,7 @@ bool HOT ESPOneWire::reset() { | ||||
|   return r; | ||||
| } | ||||
|  | ||||
| void HOT ESPOneWire::write_bit(bool bit) { | ||||
| void HOT ICACHE_RAM_ATTR ESPOneWire::write_bit(bool bit) { | ||||
|   // Initiate write/read by pulling low. | ||||
|   this->pin_->pin_mode(OUTPUT); | ||||
|   this->pin_->digital_write(false); | ||||
| @@ -60,7 +60,7 @@ void HOT ESPOneWire::write_bit(bool bit) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| bool HOT ESPOneWire::read_bit() { | ||||
| bool HOT ICACHE_RAM_ATTR ESPOneWire::read_bit() { | ||||
|   // Initiate read slot by pulling LOW for at least 1µs | ||||
|   this->pin_->pin_mode(OUTPUT); | ||||
|   this->pin_->digital_write(false); | ||||
| @@ -76,43 +76,43 @@ bool HOT ESPOneWire::read_bit() { | ||||
|   return r; | ||||
| } | ||||
|  | ||||
| void ESPOneWire::write8(uint8_t val) { | ||||
| void ICACHE_RAM_ATTR ESPOneWire::write8(uint8_t val) { | ||||
|   for (uint8_t i = 0; i < 8; i++) { | ||||
|     this->write_bit(bool((1u << i) & val)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ESPOneWire::write64(uint64_t val) { | ||||
| void ICACHE_RAM_ATTR ESPOneWire::write64(uint64_t val) { | ||||
|   for (uint8_t i = 0; i < 64; i++) { | ||||
|     this->write_bit(bool((1ULL << i) & val)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| uint8_t ESPOneWire::read8() { | ||||
| uint8_t ICACHE_RAM_ATTR ESPOneWire::read8() { | ||||
|   uint8_t ret = 0; | ||||
|   for (uint8_t i = 0; i < 8; i++) { | ||||
|     ret |= (uint8_t(this->read_bit()) << i); | ||||
|   } | ||||
|   return ret; | ||||
| } | ||||
| uint64_t ESPOneWire::read64() { | ||||
| uint64_t ICACHE_RAM_ATTR ESPOneWire::read64() { | ||||
|   uint64_t ret = 0; | ||||
|   for (uint8_t i = 0; i < 8; i++) { | ||||
|     ret |= (uint64_t(this->read_bit()) << i); | ||||
|   } | ||||
|   return ret; | ||||
| } | ||||
| void ESPOneWire::select(uint64_t address) { | ||||
| void ICACHE_RAM_ATTR ESPOneWire::select(uint64_t address) { | ||||
|   this->write8(ONE_WIRE_ROM_SELECT); | ||||
|   this->write64(address); | ||||
| } | ||||
| void ESPOneWire::reset_search() { | ||||
| void ICACHE_RAM_ATTR ESPOneWire::reset_search() { | ||||
|   this->last_discrepancy_ = 0; | ||||
|   this->last_device_flag_ = false; | ||||
|   this->last_family_discrepancy_ = 0; | ||||
|   this->rom_number_ = 0; | ||||
| } | ||||
| uint64_t HOT ESPOneWire::search() { | ||||
| uint64_t HOT ICACHE_RAM_ATTR ESPOneWire::search() { | ||||
|   if (this->last_device_flag_) { | ||||
|     return 0u; | ||||
|   } | ||||
| @@ -196,7 +196,7 @@ uint64_t HOT ESPOneWire::search() { | ||||
|  | ||||
|   return this->rom_number_; | ||||
| } | ||||
| std::vector<uint64_t> ESPOneWire::search_vec() { | ||||
| std::vector<uint64_t> ICACHE_RAM_ATTR ESPOneWire::search_vec() { | ||||
|   std::vector<uint64_t> res; | ||||
|  | ||||
|   this->reset_search(); | ||||
| @@ -206,12 +206,12 @@ std::vector<uint64_t> ESPOneWire::search_vec() { | ||||
|  | ||||
|   return res; | ||||
| } | ||||
| void ESPOneWire::skip() { | ||||
| void ICACHE_RAM_ATTR ESPOneWire::skip() { | ||||
|   this->write8(0xCC);  // skip ROM | ||||
| } | ||||
| GPIOPin *ESPOneWire::get_pin() { return this->pin_; } | ||||
|  | ||||
| uint8_t *ESPOneWire::rom_number8_() { return reinterpret_cast<uint8_t *>(&this->rom_number_); } | ||||
| uint8_t ICACHE_RAM_ATTR *ESPOneWire::rom_number8_() { return reinterpret_cast<uint8_t *>(&this->rom_number_); } | ||||
|  | ||||
| }  // namespace dallas | ||||
| }  // namespace esphome | ||||
|   | ||||
| @@ -71,80 +71,101 @@ void DHT::set_dht_model(DHTModel model) { | ||||
|   this->model_ = model; | ||||
|   this->is_auto_detect_ = model == DHT_MODEL_AUTO_DETECT; | ||||
| } | ||||
| bool HOT DHT::read_sensor_(float *temperature, float *humidity, bool report_errors) { | ||||
| bool HOT ICACHE_RAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, bool report_errors) { | ||||
|   *humidity = NAN; | ||||
|   *temperature = NAN; | ||||
|  | ||||
|   disable_interrupts(); | ||||
|   this->pin_->digital_write(false); | ||||
|   this->pin_->pin_mode(OUTPUT); | ||||
|   this->pin_->digital_write(false); | ||||
|  | ||||
|   if (this->model_ == DHT_MODEL_DHT11) { | ||||
|     delayMicroseconds(18000); | ||||
|   } else if (this->model_ == DHT_MODEL_SI7021) { | ||||
|     delayMicroseconds(500); | ||||
|     this->pin_->digital_write(true); | ||||
|     delayMicroseconds(40); | ||||
|   } else { | ||||
|     delayMicroseconds(800); | ||||
|   } | ||||
|   this->pin_->pin_mode(INPUT_PULLUP); | ||||
|   delayMicroseconds(40); | ||||
|  | ||||
|   int error_code = 0; | ||||
|   int8_t i = 0; | ||||
|   uint8_t data[5] = {0, 0, 0, 0, 0}; | ||||
|   uint8_t bit = 7; | ||||
|   uint8_t byte = 0; | ||||
|  | ||||
|   for (int8_t i = -1; i < 40; i++) { | ||||
|     uint32_t start_time = micros(); | ||||
|   { | ||||
|     InterruptLock lock; | ||||
|  | ||||
|     // Wait for rising edge | ||||
|     while (!this->pin_->digital_read()) { | ||||
|       if (micros() - start_time > 90) { | ||||
|         enable_interrupts(); | ||||
|         if (report_errors) { | ||||
|           if (i < 0) { | ||||
|             ESP_LOGW(TAG, "Waiting for DHT communication to clear failed!"); | ||||
|           } else { | ||||
|             ESP_LOGW(TAG, "Rising edge for bit %d failed!", i); | ||||
|           } | ||||
|     this->pin_->digital_write(false); | ||||
|     this->pin_->pin_mode(OUTPUT); | ||||
|     this->pin_->digital_write(false); | ||||
|  | ||||
|     if (this->model_ == DHT_MODEL_DHT11) { | ||||
|       delayMicroseconds(18000); | ||||
|     } else if (this->model_ == DHT_MODEL_SI7021) { | ||||
|       delayMicroseconds(500); | ||||
|       this->pin_->digital_write(true); | ||||
|       delayMicroseconds(40); | ||||
|     } else { | ||||
|       delayMicroseconds(800); | ||||
|     } | ||||
|     this->pin_->pin_mode(INPUT_PULLUP); | ||||
|     delayMicroseconds(40); | ||||
|  | ||||
|     uint8_t bit = 7; | ||||
|     uint8_t byte = 0; | ||||
|  | ||||
|     for (i = -1; i < 40; i++) { | ||||
|       uint32_t start_time = micros(); | ||||
|  | ||||
|       // Wait for rising edge | ||||
|       while (!this->pin_->digital_read()) { | ||||
|         if (micros() - start_time > 90) { | ||||
|           if (i < 0) | ||||
|             error_code = 1; | ||||
|           else | ||||
|             error_code = 2; | ||||
|           break; | ||||
|         } | ||||
|         return false; | ||||
|       } | ||||
|     } | ||||
|       if (error_code != 0) | ||||
|         break; | ||||
|  | ||||
|     start_time = micros(); | ||||
|     uint32_t end_time = start_time; | ||||
|       start_time = micros(); | ||||
|       uint32_t end_time = start_time; | ||||
|  | ||||
|     // Wait for falling edge | ||||
|     while (this->pin_->digital_read()) { | ||||
|       if ((end_time = micros()) - start_time > 90) { | ||||
|         enable_interrupts(); | ||||
|         if (report_errors) { | ||||
|           if (i < 0) { | ||||
|             ESP_LOGW(TAG, "Requesting data from DHT failed!"); | ||||
|           } else { | ||||
|             ESP_LOGW(TAG, "Falling edge for bit %d failed!", i); | ||||
|           } | ||||
|       // Wait for falling edge | ||||
|       while (this->pin_->digital_read()) { | ||||
|         if ((end_time = micros()) - start_time > 90) { | ||||
|           if (i < 0) | ||||
|             error_code = 3; | ||||
|           else | ||||
|             error_code = 4; | ||||
|           break; | ||||
|         } | ||||
|         return false; | ||||
|       } | ||||
|     } | ||||
|       if (error_code != 0) | ||||
|         break; | ||||
|  | ||||
|     if (i < 0) | ||||
|       continue; | ||||
|       if (i < 0) | ||||
|         continue; | ||||
|  | ||||
|     if (end_time - start_time >= 40) { | ||||
|       data[byte] |= 1 << bit; | ||||
|       if (end_time - start_time >= 40) { | ||||
|         data[byte] |= 1 << bit; | ||||
|       } | ||||
|       if (bit == 0) { | ||||
|         bit = 7; | ||||
|         byte++; | ||||
|       } else | ||||
|         bit--; | ||||
|     } | ||||
|     if (bit == 0) { | ||||
|       bit = 7; | ||||
|       byte++; | ||||
|     } else | ||||
|       bit--; | ||||
|   } | ||||
|   enable_interrupts(); | ||||
|   if (!report_errors && error_code != 0) | ||||
|     return false; | ||||
|  | ||||
|   switch (error_code) { | ||||
|     case 1: | ||||
|       ESP_LOGW(TAG, "Waiting for DHT communication to clear failed!"); | ||||
|       return false; | ||||
|     case 2: | ||||
|       ESP_LOGW(TAG, "Rising edge for bit %d failed!", i); | ||||
|       return false; | ||||
|     case 3: | ||||
|       ESP_LOGW(TAG, "Requesting data from DHT failed!"); | ||||
|       return false; | ||||
|     case 4: | ||||
|       ESP_LOGW(TAG, "Falling edge for bit %d failed!", i); | ||||
|       return false; | ||||
|     case 0: | ||||
|     default: | ||||
|       break; | ||||
|   } | ||||
|  | ||||
|   ESP_LOGVV(TAG, | ||||
|             "Data: Hum=0b" BYTE_TO_BINARY_PATTERN BYTE_TO_BINARY_PATTERN | ||||
|   | ||||
| @@ -42,23 +42,24 @@ bool HX711Sensor::read_sensor_(uint32_t *result) { | ||||
|   this->status_clear_warning(); | ||||
|   uint32_t data = 0; | ||||
|  | ||||
|   disable_interrupts(); | ||||
|   for (uint8_t i = 0; i < 24; i++) { | ||||
|     this->sck_pin_->digital_write(true); | ||||
|     delayMicroseconds(1); | ||||
|     data |= uint32_t(this->dout_pin_->digital_read()) << (23 - i); | ||||
|     this->sck_pin_->digital_write(false); | ||||
|     delayMicroseconds(1); | ||||
|   } | ||||
|   { | ||||
|     InterruptLock lock; | ||||
|     for (uint8_t i = 0; i < 24; i++) { | ||||
|       this->sck_pin_->digital_write(true); | ||||
|       delayMicroseconds(1); | ||||
|       data |= uint32_t(this->dout_pin_->digital_read()) << (23 - i); | ||||
|       this->sck_pin_->digital_write(false); | ||||
|       delayMicroseconds(1); | ||||
|     } | ||||
|  | ||||
|   // Cycle clock pin for gain setting | ||||
|   for (uint8_t i = 0; i < this->gain_; i++) { | ||||
|     this->sck_pin_->digital_write(true); | ||||
|     delayMicroseconds(1); | ||||
|     this->sck_pin_->digital_write(false); | ||||
|     delayMicroseconds(1); | ||||
|     // Cycle clock pin for gain setting | ||||
|     for (uint8_t i = 0; i < this->gain_; i++) { | ||||
|       this->sck_pin_->digital_write(true); | ||||
|       delayMicroseconds(1); | ||||
|       this->sck_pin_->digital_write(false); | ||||
|       delayMicroseconds(1); | ||||
|     } | ||||
|   } | ||||
|   enable_interrupts(); | ||||
|  | ||||
|   if (data & 0x800000ULL) { | ||||
|     data |= 0xFF000000ULL; | ||||
|   | ||||
| @@ -67,22 +67,22 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen | ||||
|   uint32_t on_time, off_time; | ||||
|   this->calculate_on_off_time_(this->temp_.get_carrier_frequency(), &on_time, &off_time); | ||||
|   for (uint32_t i = 0; i < send_times; i++) { | ||||
|     disable_interrupts(); | ||||
|     for (int32_t item : this->temp_.get_data()) { | ||||
|       if (item > 0) { | ||||
|         const auto length = uint32_t(item); | ||||
|         this->mark_(on_time, off_time, length); | ||||
|       } else { | ||||
|         const auto length = uint32_t(-item); | ||||
|         this->space_(length); | ||||
|     { | ||||
|       InterruptLock lock; | ||||
|       for (int32_t item : this->temp_.get_data()) { | ||||
|         if (item > 0) { | ||||
|           const auto length = uint32_t(item); | ||||
|           this->mark_(on_time, off_time, length); | ||||
|         } else { | ||||
|           const auto length = uint32_t(-item); | ||||
|           this->space_(length); | ||||
|         } | ||||
|         App.feed_wdt(); | ||||
|       } | ||||
|       App.feed_wdt(); | ||||
|     } | ||||
|     enable_interrupts(); | ||||
|  | ||||
|     if (i + 1 < send_times) { | ||||
|       delay(send_wait / 1000UL); | ||||
|       delayMicroseconds(send_wait % 1000UL); | ||||
|       delay_microseconds_accurate(send_wait); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -295,24 +295,25 @@ void ICACHE_RAM_ATTR HOT ESP8266SoftwareSerial::write_byte(uint8_t data) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   disable_interrupts(); | ||||
|   uint32_t wait = this->bit_time_; | ||||
|   const uint32_t start = ESP.getCycleCount(); | ||||
|   // Start bit | ||||
|   this->write_bit_(false, &wait, start); | ||||
|   this->write_bit_(data & (1 << 0), &wait, start); | ||||
|   this->write_bit_(data & (1 << 1), &wait, start); | ||||
|   this->write_bit_(data & (1 << 2), &wait, start); | ||||
|   this->write_bit_(data & (1 << 3), &wait, start); | ||||
|   this->write_bit_(data & (1 << 4), &wait, start); | ||||
|   this->write_bit_(data & (1 << 5), &wait, start); | ||||
|   this->write_bit_(data & (1 << 6), &wait, start); | ||||
|   this->write_bit_(data & (1 << 7), &wait, start); | ||||
|   // Stop bit | ||||
|   this->write_bit_(true, &wait, start); | ||||
|   if (this->stop_bits_ == 2) | ||||
|     this->wait_(&wait, start); | ||||
|   enable_interrupts(); | ||||
|   { | ||||
|     InterruptLock lock; | ||||
|     uint32_t wait = this->bit_time_; | ||||
|     const uint32_t start = ESP.getCycleCount(); | ||||
|     // Start bit | ||||
|     this->write_bit_(false, &wait, start); | ||||
|     this->write_bit_(data & (1 << 0), &wait, start); | ||||
|     this->write_bit_(data & (1 << 1), &wait, start); | ||||
|     this->write_bit_(data & (1 << 2), &wait, start); | ||||
|     this->write_bit_(data & (1 << 3), &wait, start); | ||||
|     this->write_bit_(data & (1 << 4), &wait, start); | ||||
|     this->write_bit_(data & (1 << 5), &wait, start); | ||||
|     this->write_bit_(data & (1 << 6), &wait, start); | ||||
|     this->write_bit_(data & (1 << 7), &wait, start); | ||||
|     // Stop bit | ||||
|     this->write_bit_(true, &wait, start); | ||||
|     if (this->stop_bits_ == 2) | ||||
|       this->wait_(&wait, start); | ||||
|   } | ||||
| } | ||||
| void ICACHE_RAM_ATTR ESP8266SoftwareSerial::wait_(uint32_t *wait, const uint32_t &start) { | ||||
|   while (ESP.getCycleCount() - start < *wait) | ||||
| @@ -323,7 +324,7 @@ bool ICACHE_RAM_ATTR ESP8266SoftwareSerial::read_bit_(uint32_t *wait, const uint | ||||
|   this->wait_(wait, start); | ||||
|   return this->rx_pin_->digital_read(); | ||||
| } | ||||
| void ESP8266SoftwareSerial::write_bit_(bool bit, uint32_t *wait, const uint32_t &start) { | ||||
| void ICACHE_RAM_ATTR ESP8266SoftwareSerial::write_bit_(bool bit, uint32_t *wait, const uint32_t &start) { | ||||
|   this->tx_pin_->digital_write(bit); | ||||
|   this->wait_(wait, start); | ||||
| } | ||||
|   | ||||
| @@ -6,8 +6,16 @@ | ||||
|  | ||||
| #include <utility> | ||||
| #include <algorithm> | ||||
|  | ||||
| extern "C" { | ||||
| #include "lwip/err.h" | ||||
| #include "lwip/dns.h" | ||||
| #include "lwip/dhcp.h" | ||||
| #include "lwip/init.h"  // LWIP_VERSION_ | ||||
| #if LWIP_IPV6 | ||||
| #include "lwip/netif.h"  // struct netif | ||||
| #endif | ||||
| } | ||||
|  | ||||
| #include "esphome/core/helpers.h" | ||||
| #include "esphome/core/log.h" | ||||
| @@ -74,6 +82,19 @@ bool WiFiComponent::wifi_apply_power_save_() { | ||||
|   } | ||||
|   return wifi_set_sleep_type(power_save); | ||||
| } | ||||
|  | ||||
| #if LWIP_VERSION_MAJOR != 1 | ||||
| /* | ||||
|   lwip v2 needs to be notified of IP changes, see also | ||||
|   https://github.com/d-a-v/Arduino/blob/0e7d21e17144cfc5f53c016191daca8723e89ee8/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp#L251 | ||||
|  */ | ||||
| #undef netif_set_addr  // need to call lwIP-v1.4 netif_set_addr() | ||||
| extern "C" { | ||||
| struct netif *eagle_lwip_getif(int netif_index); | ||||
| void netif_set_addr(struct netif *netif, const ip4_addr_t *ip, const ip4_addr_t *netmask, const ip4_addr_t *gw); | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) { | ||||
|   // enable STA | ||||
|   if (!this->wifi_mode_(true, {})) | ||||
| @@ -94,6 +115,13 @@ bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) { | ||||
|  | ||||
|   bool ret = true; | ||||
|  | ||||
| #if LWIP_VERSION_MAJOR != 1 | ||||
|   // get current->previous IP address | ||||
|   // (check below) | ||||
|   ip_info previp{}; | ||||
|   wifi_get_ip_info(STATION_IF, &previp); | ||||
| #endif | ||||
|  | ||||
|   struct ip_info info {}; | ||||
|   info.ip.addr = static_cast<uint32_t>(manual_ip->static_ip); | ||||
|   info.gw.addr = static_cast<uint32_t>(manual_ip->gateway); | ||||
| @@ -122,6 +150,14 @@ bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) { | ||||
|     dns_setserver(1, &dns); | ||||
|   } | ||||
|  | ||||
| #if LWIP_VERSION_MAJOR != 1 | ||||
|   // trigger address change by calling lwIP-v1.4 api | ||||
|   // only when ip is already set by other mean (generally dhcp) | ||||
|   if (previp.ip.addr != 0 && previp.ip.addr != info.ip.addr) { | ||||
|     netif_set_addr(eagle_lwip_getif(STATION_IF), reinterpret_cast<const ip4_addr_t *>(&info.ip), | ||||
|                    reinterpret_cast<const ip4_addr_t *>(&info.netmask), reinterpret_cast<const ip4_addr_t *>(&info.gw)); | ||||
|   } | ||||
| #endif | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| @@ -133,10 +169,31 @@ IPAddress WiFiComponent::wifi_sta_ip_() { | ||||
|   return {ip.ip.addr}; | ||||
| } | ||||
| bool WiFiComponent::wifi_apply_hostname_() { | ||||
|   bool ret = wifi_station_set_hostname(const_cast<char *>(App.get_name().c_str())); | ||||
|   const std::string &hostname = App.get_name(); | ||||
|   bool ret = wifi_station_set_hostname(const_cast<char *>(hostname.c_str())); | ||||
|   if (!ret) { | ||||
|     ESP_LOGV(TAG, "Setting WiFi Hostname failed!"); | ||||
|   } | ||||
|  | ||||
|   // inform dhcp server of hostname change using dhcp_renew() | ||||
|   for (netif *intf = netif_list; intf; intf = intf->next) { | ||||
|     // unconditionally update all known interfaces | ||||
| #if LWIP_VERSION_MAJOR == 1 | ||||
|     intf->hostname = (char *) wifi_station_get_hostname(); | ||||
| #else | ||||
|     intf->hostname = wifi_station_get_hostname(); | ||||
| #endif | ||||
|     if (netif_dhcp_data(intf) != nullptr) { | ||||
|       // renew already started DHCP leases | ||||
|       err_t lwipret = dhcp_renew(intf); | ||||
|       if (lwipret != ERR_OK) { | ||||
|         ESP_LOGW(TAG, "wifi_apply_hostname_(%s): lwIP error %d on interface %c%c (index %d)", intf->hostname, | ||||
|                  (int) lwipret, intf->name[0], intf->name[1], intf->num); | ||||
|         ret = false; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -156,21 +156,6 @@ ParseOnOffState parse_on_off(const char *str, const char *on, const char *off) { | ||||
|  | ||||
| const char *HOSTNAME_CHARACTER_WHITELIST = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; | ||||
|  | ||||
| void disable_interrupts() { | ||||
| #ifdef ARDUINO_ARCH_ESP32 | ||||
|   portDISABLE_INTERRUPTS(); | ||||
| #else | ||||
|   noInterrupts(); | ||||
| #endif | ||||
| } | ||||
| void enable_interrupts() { | ||||
| #ifdef ARDUINO_ARCH_ESP32 | ||||
|   portENABLE_INTERRUPTS(); | ||||
| #else | ||||
|   interrupts(); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| uint8_t crc8(uint8_t *data, uint8_t len) { | ||||
|   uint8_t crc = 0; | ||||
|  | ||||
| @@ -193,8 +178,8 @@ void delay_microseconds_accurate(uint32_t usec) { | ||||
|   if (usec <= 16383UL) { | ||||
|     delayMicroseconds(usec); | ||||
|   } else { | ||||
|     delay(usec / 1000UL); | ||||
|     delayMicroseconds(usec % 1000UL); | ||||
|     delay(usec / 16383UL); | ||||
|     delayMicroseconds(usec % 16383UL); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -330,4 +315,13 @@ std::string hexencode(const uint8_t *data, uint32_t len) { | ||||
|   return res; | ||||
| } | ||||
|  | ||||
| #ifdef ARDUINO_ARCH_ESP8266 | ||||
| ICACHE_RAM_ATTR InterruptLock::InterruptLock() { xt_state_ = xt_rsil(15); } | ||||
| ICACHE_RAM_ATTR InterruptLock::~InterruptLock() { xt_wsr_ps(xt_state_); } | ||||
| #endif | ||||
| #ifdef ARDUINO_ARCH_ESP32 | ||||
| ICACHE_RAM_ATTR InterruptLock::InterruptLock() { portENABLE_INTERRUPTS(); } | ||||
| ICACHE_RAM_ATTR InterruptLock::~InterruptLock() { portDISABLE_INTERRUPTS(); } | ||||
| #endif | ||||
|  | ||||
| }  // namespace esphome | ||||
|   | ||||
| @@ -133,16 +133,38 @@ uint16_t encode_uint16(uint8_t msb, uint8_t lsb); | ||||
| /// Decode a 16-bit unsigned integer into an array of two values: most significant byte, least significant byte. | ||||
| std::array<uint8_t, 2> decode_uint16(uint16_t value); | ||||
|  | ||||
| /** Cross-platform method to disable interrupts. | ||||
| /*** | ||||
|  * An interrupt helper class. | ||||
|  * | ||||
|  * Useful when you need to do some timing-dependent communication. | ||||
|  * This behaves like std::lock_guard. As long as the value is visible in the current stack, all interrupts | ||||
|  * (including flash reads) will be disabled. | ||||
|  * | ||||
|  * @see Do not forget to call `enable_interrupts()` again or otherwise things will go very wrong. | ||||
|  * Please note all functions called when the interrupt lock must be marked ICACHE_RAM_ATTR (loading code into | ||||
|  * instruction cache is done via interrupts; disabling interrupts prevents data not already in cache from being | ||||
|  * pulled from flash). | ||||
|  * | ||||
|  * Example: | ||||
|  * | ||||
|  * ```cpp | ||||
|  * // interrupts are enabled | ||||
|  * { | ||||
|  *   InterruptLock lock; | ||||
|  *   // do something | ||||
|  *   // interrupts are disabled | ||||
|  * } | ||||
|  * // interrupts are enabled | ||||
|  * ``` | ||||
|  */ | ||||
| void disable_interrupts(); | ||||
| class InterruptLock { | ||||
|  public: | ||||
|   InterruptLock(); | ||||
|   ~InterruptLock(); | ||||
|  | ||||
| /// Cross-platform method to enable interrupts after they have been disabled. | ||||
| void enable_interrupts(); | ||||
|  protected: | ||||
| #ifdef ARDUINO_ARCH_ESP8266 | ||||
|   uint32_t xt_state_; | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| /// Calculate a crc8 of data with the provided data length. | ||||
| uint8_t crc8(uint8_t *data, uint8_t len); | ||||
|   | ||||
| @@ -105,16 +105,18 @@ void ESPPreferences::save_esp8266_flash_() { | ||||
|     return; | ||||
|  | ||||
|   ESP_LOGVV(TAG, "Saving preferences to flash..."); | ||||
|   disable_interrupts(); | ||||
|   auto erase_res = spi_flash_erase_sector(get_esp8266_flash_sector()); | ||||
|   SpiFlashOpResult erase_res, write_res = SPI_FLASH_RESULT_OK; | ||||
|   { | ||||
|     InterruptLock lock; | ||||
|     erase_res = spi_flash_erase_sector(get_esp8266_flash_sector()); | ||||
|     if (erase_res == SPI_FLASH_RESULT_OK) { | ||||
|       write_res = spi_flash_write(get_esp8266_flash_address(), this->flash_storage_, ESP8266_FLASH_STORAGE_SIZE * 4); | ||||
|     } | ||||
|   } | ||||
|   if (erase_res != SPI_FLASH_RESULT_OK) { | ||||
|     enable_interrupts(); | ||||
|     ESP_LOGV(TAG, "Erase ESP8266 flash failed!"); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   auto write_res = spi_flash_write(get_esp8266_flash_address(), this->flash_storage_, ESP8266_FLASH_STORAGE_SIZE * 4); | ||||
|   enable_interrupts(); | ||||
|   if (write_res != SPI_FLASH_RESULT_OK) { | ||||
|     ESP_LOGV(TAG, "Write ESP8266 flash failed!"); | ||||
|     return; | ||||
| @@ -173,9 +175,11 @@ ESPPreferences::ESPPreferences() | ||||
| void ESPPreferences::begin() { | ||||
|   this->flash_storage_ = new uint32_t[ESP8266_FLASH_STORAGE_SIZE]; | ||||
|   ESP_LOGVV(TAG, "Loading preferences from flash..."); | ||||
|   disable_interrupts(); | ||||
|   spi_flash_read(get_esp8266_flash_address(), this->flash_storage_, ESP8266_FLASH_STORAGE_SIZE * 4); | ||||
|   enable_interrupts(); | ||||
|  | ||||
|   { | ||||
|     InterruptLock lock; | ||||
|     spi_flash_read(get_esp8266_flash_address(), this->flash_storage_, ESP8266_FLASH_STORAGE_SIZE * 4); | ||||
|   } | ||||
| } | ||||
|  | ||||
| ESPPreferenceObject ESPPreferences::make_preference(size_t length, uint32_t type, bool in_flash) { | ||||
|   | ||||
| @@ -45,6 +45,8 @@ def validate_board(value): | ||||
| validate_platform = cv.one_of('ESP32', 'ESP8266', upper=True) | ||||
|  | ||||
| PLATFORMIO_ESP8266_LUT = { | ||||
|     '2.6.2': 'espressif8266@2.3.1', | ||||
|     '2.6.1': 'espressif8266@2.3.0', | ||||
|     '2.5.2': 'espressif8266@2.2.3', | ||||
|     '2.5.1': 'espressif8266@2.1.0', | ||||
|     '2.5.0': 'espressif8266@2.0.1', | ||||
|   | ||||
| @@ -60,6 +60,7 @@ FILTER_PLATFORMIO_LINES = [ | ||||
|     r"Using cache: .*", | ||||
|     r'Installing dependencies', | ||||
|     r'.* @ .* is already installed', | ||||
|     r'Building in .* mode', | ||||
| ] | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user