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:
Otto Winter 2019-12-04 19:30:10 +01:00
parent 219fe41831
commit 072b2c445c
No known key found for this signature in database
GPG key ID: 48ED2DDB96D7682C
11 changed files with 289 additions and 180 deletions

View file

@ -32,9 +32,11 @@ void DallasComponent::setup() {
ESP_LOGCONFIG(TAG, "Setting up DallasComponent..."); ESP_LOGCONFIG(TAG, "Setting up DallasComponent...");
yield(); yield();
disable_interrupts(); std::vector<uint64_t> raw_sensors;
std::vector<uint64_t> raw_sensors = this->one_wire_->search_vec(); {
enable_interrupts(); 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);
@ -108,8 +110,9 @@ DallasTemperatureSensor *DallasComponent::get_sensor_by_index(uint8_t index, uin
void DallasComponent::update() { void DallasComponent::update() {
this->status_clear_warning(); this->status_clear_warning();
disable_interrupts();
bool result; bool result;
{
InterruptLock lock;
if (!this->one_wire_->reset()) { if (!this->one_wire_->reset()) {
result = false; result = false;
} else { } else {
@ -117,7 +120,7 @@ void DallasComponent::update() {
this->one_wire_->skip(); this->one_wire_->skip();
this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION); this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION);
} }
enable_interrupts(); }
if (!result) { if (!result) {
ESP_LOGE(TAG, "Requesting conversion failed"); ESP_LOGE(TAG, "Requesting conversion failed");
@ -127,9 +130,11 @@ 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] {
disable_interrupts(); bool res;
bool res = sensor->read_scratch_pad(); {
enable_interrupts(); InterruptLock lock;
res = sensor->read_scratch_pad();
}
if (!res) { if (!res) {
ESP_LOGW(TAG, "'%s' - Reseting bus for read failed!", sensor->get_name().c_str()); 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_; return this->address_name_;
} }
bool DallasTemperatureSensor::read_scratch_pad() { bool ICACHE_RAM_ATTR DallasTemperatureSensor::read_scratch_pad() {
ESPOneWire *wire = this->parent_->one_wire_; ESPOneWire *wire = this->parent_->one_wire_;
if (!wire->reset()) { if (!wire->reset()) {
return false; return false;
@ -185,9 +190,11 @@ bool DallasTemperatureSensor::read_scratch_pad() {
return true; return true;
} }
bool DallasTemperatureSensor::setup_sensor() { bool DallasTemperatureSensor::setup_sensor() {
disable_interrupts(); bool r;
bool r = this->read_scratch_pad(); {
enable_interrupts(); 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");
@ -222,7 +229,8 @@ bool DallasTemperatureSensor::setup_sensor() {
} }
ESPOneWire *wire = this->parent_->one_wire_; ESPOneWire *wire = this->parent_->one_wire_;
disable_interrupts(); {
InterruptLock lock;
if (wire->reset()) { if (wire->reset()) {
wire->select(this->address_); wire->select(this->address_);
wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD); wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD);
@ -235,7 +243,7 @@ bool DallasTemperatureSensor::setup_sensor() {
wire->select(this->address_); wire->select(this->address_);
wire->write8(0x48); wire->write8(0x48);
} }
enable_interrupts(); }
delay(20); // allow it to finish operation delay(20); // allow it to finish operation
wire->reset(); wire->reset();

View file

@ -12,7 +12,7 @@ const int ONE_WIRE_ROM_SEARCH = 0xF0;
ESPOneWire::ESPOneWire(GPIOPin *pin) : pin_(pin) {} ESPOneWire::ESPOneWire(GPIOPin *pin) : pin_(pin) {}
bool HOT ESPOneWire::reset() { bool HOT ICACHE_RAM_ATTR ESPOneWire::reset() {
uint8_t retries = 125; uint8_t retries = 125;
// Wait for communication to clear // Wait for communication to clear
@ -39,7 +39,7 @@ bool HOT ESPOneWire::reset() {
return r; 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. // Initiate write/read by pulling low.
this->pin_->pin_mode(OUTPUT); this->pin_->pin_mode(OUTPUT);
this->pin_->digital_write(false); 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 // Initiate read slot by pulling LOW for at least 1µs
this->pin_->pin_mode(OUTPUT); this->pin_->pin_mode(OUTPUT);
this->pin_->digital_write(false); this->pin_->digital_write(false);
@ -76,43 +76,43 @@ bool HOT ESPOneWire::read_bit() {
return r; 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++) { for (uint8_t i = 0; i < 8; i++) {
this->write_bit(bool((1u << i) & val)); 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++) { for (uint8_t i = 0; i < 64; i++) {
this->write_bit(bool((1ULL << i) & val)); this->write_bit(bool((1ULL << i) & val));
} }
} }
uint8_t ESPOneWire::read8() { uint8_t ICACHE_RAM_ATTR 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 ESPOneWire::read64() { uint64_t ICACHE_RAM_ATTR 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 ESPOneWire::select(uint64_t address) { void ICACHE_RAM_ATTR ESPOneWire::select(uint64_t address) {
this->write8(ONE_WIRE_ROM_SELECT); this->write8(ONE_WIRE_ROM_SELECT);
this->write64(address); this->write64(address);
} }
void ESPOneWire::reset_search() { void ICACHE_RAM_ATTR 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 ESPOneWire::search() { uint64_t HOT ICACHE_RAM_ATTR ESPOneWire::search() {
if (this->last_device_flag_) { if (this->last_device_flag_) {
return 0u; return 0u;
} }
@ -196,7 +196,7 @@ uint64_t HOT ESPOneWire::search() {
return this->rom_number_; 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; std::vector<uint64_t> res;
this->reset_search(); this->reset_search();
@ -206,12 +206,12 @@ std::vector<uint64_t> ESPOneWire::search_vec() {
return res; return res;
} }
void ESPOneWire::skip() { void ICACHE_RAM_ATTR ESPOneWire::skip() {
this->write8(0xCC); // skip ROM this->write8(0xCC); // skip ROM
} }
GPIOPin *ESPOneWire::get_pin() { return this->pin_; } 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 dallas
} // namespace esphome } // namespace esphome

View file

@ -71,11 +71,17 @@ void DHT::set_dht_model(DHTModel model) {
this->model_ = model; this->model_ = model;
this->is_auto_detect_ = model == DHT_MODEL_AUTO_DETECT; 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; *humidity = NAN;
*temperature = NAN; *temperature = NAN;
disable_interrupts(); int error_code = 0;
int8_t i = 0;
uint8_t data[5] = {0, 0, 0, 0, 0};
{
InterruptLock lock;
this->pin_->digital_write(false); this->pin_->digital_write(false);
this->pin_->pin_mode(OUTPUT); this->pin_->pin_mode(OUTPUT);
this->pin_->digital_write(false); this->pin_->digital_write(false);
@ -92,27 +98,24 @@ bool HOT DHT::read_sensor_(float *temperature, float *humidity, bool report_erro
this->pin_->pin_mode(INPUT_PULLUP); this->pin_->pin_mode(INPUT_PULLUP);
delayMicroseconds(40); delayMicroseconds(40);
uint8_t data[5] = {0, 0, 0, 0, 0};
uint8_t bit = 7; uint8_t bit = 7;
uint8_t byte = 0; uint8_t byte = 0;
for (int8_t i = -1; i < 40; i++) { for (i = -1; i < 40; i++) {
uint32_t start_time = micros(); uint32_t start_time = micros();
// Wait for rising edge // Wait for rising edge
while (!this->pin_->digital_read()) { while (!this->pin_->digital_read()) {
if (micros() - start_time > 90) { if (micros() - start_time > 90) {
enable_interrupts(); if (i < 0)
if (report_errors) { error_code = 1;
if (i < 0) { else
ESP_LOGW(TAG, "Waiting for DHT communication to clear failed!"); error_code = 2;
} else { break;
ESP_LOGW(TAG, "Rising edge for bit %d failed!", i);
}
}
return false;
} }
} }
if (error_code != 0)
break;
start_time = micros(); start_time = micros();
uint32_t end_time = start_time; uint32_t end_time = start_time;
@ -120,17 +123,15 @@ bool HOT DHT::read_sensor_(float *temperature, float *humidity, bool report_erro
// Wait for falling edge // Wait for falling edge
while (this->pin_->digital_read()) { while (this->pin_->digital_read()) {
if ((end_time = micros()) - start_time > 90) { if ((end_time = micros()) - start_time > 90) {
enable_interrupts(); if (i < 0)
if (report_errors) { error_code = 3;
if (i < 0) { else
ESP_LOGW(TAG, "Requesting data from DHT failed!"); error_code = 4;
} else { break;
ESP_LOGW(TAG, "Falling edge for bit %d failed!", i);
}
}
return false;
} }
} }
if (error_code != 0)
break;
if (i < 0) if (i < 0)
continue; continue;
@ -144,7 +145,27 @@ bool HOT DHT::read_sensor_(float *temperature, float *humidity, bool report_erro
} else } else
bit--; 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, ESP_LOGVV(TAG,
"Data: Hum=0b" BYTE_TO_BINARY_PATTERN BYTE_TO_BINARY_PATTERN "Data: Hum=0b" BYTE_TO_BINARY_PATTERN BYTE_TO_BINARY_PATTERN

View file

@ -42,7 +42,8 @@ bool HX711Sensor::read_sensor_(uint32_t *result) {
this->status_clear_warning(); this->status_clear_warning();
uint32_t data = 0; uint32_t data = 0;
disable_interrupts(); {
InterruptLock lock;
for (uint8_t i = 0; i < 24; i++) { for (uint8_t i = 0; i < 24; i++) {
this->sck_pin_->digital_write(true); this->sck_pin_->digital_write(true);
delayMicroseconds(1); delayMicroseconds(1);
@ -58,7 +59,7 @@ bool HX711Sensor::read_sensor_(uint32_t *result) {
this->sck_pin_->digital_write(false); this->sck_pin_->digital_write(false);
delayMicroseconds(1); delayMicroseconds(1);
} }
enable_interrupts(); }
if (data & 0x800000ULL) { if (data & 0x800000ULL) {
data |= 0xFF000000ULL; data |= 0xFF000000ULL;

View file

@ -67,7 +67,8 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
uint32_t on_time, off_time; uint32_t on_time, off_time;
this->calculate_on_off_time_(this->temp_.get_carrier_frequency(), &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++) { for (uint32_t i = 0; i < send_times; i++) {
disable_interrupts(); {
InterruptLock lock;
for (int32_t item : this->temp_.get_data()) { for (int32_t item : this->temp_.get_data()) {
if (item > 0) { if (item > 0) {
const auto length = uint32_t(item); const auto length = uint32_t(item);
@ -78,11 +79,10 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
} }
App.feed_wdt(); App.feed_wdt();
} }
enable_interrupts(); }
if (i + 1 < send_times) { if (i + 1 < send_times) {
delay(send_wait / 1000UL); delay_microseconds_accurate(send_wait);
delayMicroseconds(send_wait % 1000UL);
} }
} }
} }

View file

@ -295,7 +295,8 @@ void ICACHE_RAM_ATTR HOT ESP8266SoftwareSerial::write_byte(uint8_t data) {
return; return;
} }
disable_interrupts(); {
InterruptLock lock;
uint32_t wait = this->bit_time_; uint32_t wait = this->bit_time_;
const uint32_t start = ESP.getCycleCount(); const uint32_t start = ESP.getCycleCount();
// Start bit // Start bit
@ -312,7 +313,7 @@ void ICACHE_RAM_ATTR HOT ESP8266SoftwareSerial::write_byte(uint8_t data) {
this->write_bit_(true, &wait, start); this->write_bit_(true, &wait, start);
if (this->stop_bits_ == 2) if (this->stop_bits_ == 2)
this->wait_(&wait, start); this->wait_(&wait, start);
enable_interrupts(); }
} }
void ICACHE_RAM_ATTR ESP8266SoftwareSerial::wait_(uint32_t *wait, const uint32_t &start) { void ICACHE_RAM_ATTR ESP8266SoftwareSerial::wait_(uint32_t *wait, const uint32_t &start) {
while (ESP.getCycleCount() - start < *wait) 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); this->wait_(wait, start);
return this->rx_pin_->digital_read(); 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->tx_pin_->digital_write(bit);
this->wait_(wait, start); this->wait_(wait, start);
} }

View file

@ -6,8 +6,16 @@
#include <utility> #include <utility>
#include <algorithm> #include <algorithm>
extern "C" {
#include "lwip/err.h" #include "lwip/err.h"
#include "lwip/dns.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/helpers.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
@ -74,6 +82,19 @@ bool WiFiComponent::wifi_apply_power_save_() {
} }
return wifi_set_sleep_type(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) { bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) {
// enable STA // enable STA
if (!this->wifi_mode_(true, {})) if (!this->wifi_mode_(true, {}))
@ -94,6 +115,13 @@ bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) {
bool ret = true; 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 {}; struct ip_info info {};
info.ip.addr = static_cast<uint32_t>(manual_ip->static_ip); info.ip.addr = static_cast<uint32_t>(manual_ip->static_ip);
info.gw.addr = static_cast<uint32_t>(manual_ip->gateway); 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); 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; return ret;
} }
@ -133,10 +169,31 @@ IPAddress WiFiComponent::wifi_sta_ip_() {
return {ip.ip.addr}; return {ip.ip.addr};
} }
bool WiFiComponent::wifi_apply_hostname_() { 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) { if (!ret) {
ESP_LOGV(TAG, "Setting WiFi Hostname failed!"); 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; return ret;
} }

View file

@ -156,21 +156,6 @@ ParseOnOffState parse_on_off(const char *str, const char *on, const char *off) {
const char *HOSTNAME_CHARACTER_WHITELIST = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; 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 crc8(uint8_t *data, uint8_t len) {
uint8_t crc = 0; uint8_t crc = 0;
@ -193,8 +178,8 @@ void delay_microseconds_accurate(uint32_t usec) {
if (usec <= 16383UL) { if (usec <= 16383UL) {
delayMicroseconds(usec); delayMicroseconds(usec);
} else { } else {
delay(usec / 1000UL); delay(usec / 16383UL);
delayMicroseconds(usec % 1000UL); delayMicroseconds(usec % 16383UL);
} }
} }
@ -330,4 +315,13 @@ std::string hexencode(const uint8_t *data, uint32_t len) {
return res; 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 } // namespace esphome

View file

@ -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. /// 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); 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. protected:
void enable_interrupts(); #ifdef ARDUINO_ARCH_ESP8266
uint32_t xt_state_;
#endif
};
/// Calculate a crc8 of data with the provided data length. /// Calculate a crc8 of data with the provided data length.
uint8_t crc8(uint8_t *data, uint8_t len); uint8_t crc8(uint8_t *data, uint8_t len);

View file

@ -105,16 +105,18 @@ void ESPPreferences::save_esp8266_flash_() {
return; return;
ESP_LOGVV(TAG, "Saving preferences to flash..."); ESP_LOGVV(TAG, "Saving preferences to flash...");
disable_interrupts(); SpiFlashOpResult erase_res, write_res = SPI_FLASH_RESULT_OK;
auto erase_res = spi_flash_erase_sector(get_esp8266_flash_sector()); {
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) { if (erase_res != SPI_FLASH_RESULT_OK) {
enable_interrupts();
ESP_LOGV(TAG, "Erase ESP8266 flash failed!"); ESP_LOGV(TAG, "Erase ESP8266 flash failed!");
return; 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) { if (write_res != SPI_FLASH_RESULT_OK) {
ESP_LOGV(TAG, "Write ESP8266 flash failed!"); ESP_LOGV(TAG, "Write ESP8266 flash failed!");
return; return;
@ -173,9 +175,11 @@ ESPPreferences::ESPPreferences()
void ESPPreferences::begin() { void ESPPreferences::begin() {
this->flash_storage_ = new uint32_t[ESP8266_FLASH_STORAGE_SIZE]; this->flash_storage_ = new uint32_t[ESP8266_FLASH_STORAGE_SIZE];
ESP_LOGVV(TAG, "Loading preferences from flash..."); ESP_LOGVV(TAG, "Loading preferences from flash...");
disable_interrupts();
{
InterruptLock lock;
spi_flash_read(get_esp8266_flash_address(), this->flash_storage_, ESP8266_FLASH_STORAGE_SIZE * 4); spi_flash_read(get_esp8266_flash_address(), this->flash_storage_, ESP8266_FLASH_STORAGE_SIZE * 4);
enable_interrupts(); }
} }
ESPPreferenceObject ESPPreferences::make_preference(size_t length, uint32_t type, bool in_flash) { ESPPreferenceObject ESPPreferences::make_preference(size_t length, uint32_t type, bool in_flash) {

View file

@ -60,6 +60,7 @@ FILTER_PLATFORMIO_LINES = [
r"Using cache: .*", r"Using cache: .*",
r'Installing dependencies', r'Installing dependencies',
r'.* @ .* is already installed', r'.* @ .* is already installed',
r'Building in .* mode',
] ]