1
0
mirror of https://github.com/esphome/esphome.git synced 2025-02-24 13:58:14 +00:00
esphome/esphome/components/dallas/esp_one_wire.cpp
Otto Winter ac0d921413
ESP-IDF support and generic target platforms (#2303)
* Socket refactor and SSL

* esp-idf temp

* Fixes

* Echo component and noise

* Add noise API transport support

* Updates

* ESP-IDF

* Complete

* Fixes

* Fixes

* Versions update

* New i2c APIs

* Complete i2c refactor

* SPI migration

* Revert ESP Preferences migration, too complex for now

* OTA support

* Remove echo again

* Remove ssl again

* GPIOFlags updates

* Rename esphal and ICACHE_RAM_ATTR

* Make ESP32 arduino compilable again

* Fix GPIO flags

* Complete pin registry refactor and fixes

* Fixes to make test1 compile

* Remove sdkconfig file

* Ignore sdkconfig file

* Fixes in reviewing

* Make test2 compile

* Make test4 compile

* Make test5 compile

* Run clang-format

* Fix lint errors

* Use esp-idf APIs instead of btStart

* Another round of fixes

* Start implementing ESP8266

* Make test3 compile

* Guard esp8266 code

* Lint

* Reformat

* Fixes

* Fixes v2

* more fixes

* ESP-IDF tidy target

* Convert ARDUINO_ARCH_ESPxx

* Update WiFiSignalSensor

* Update time ifdefs

* OTA needs millis from hal

* RestartSwitch needs delay from hal

* ESP-IDF Uart

* Fix OTA blank password

* Allow setting sdkconfig

* Fix idf partitions and allow setting sdkconfig from yaml

* Re-add read/write compat APIs and fix esp8266 uart

* Fix esp8266 store log strings in flash

* Fix ESP32 arduino preferences not initialized

* Update ifdefs

* Change how sdkconfig change is detected

* Add checks to ci-custom and fix them

* Run clang-format

* Add esp-idf clang-tidy target and fix errors

* Fixes from clang-tidy idf round 2

* Fixes from compiling tests with esp-idf

* Run clang-format

* Switch test5.yaml to esp-idf

* Implement ESP8266 Preferences

* Lint

* Re-do PIO package version selection a bit

* Fix arduinoespressif32 package version

* Fix unit tests

* Lint

* Lint fixes

* Fix readv/writev not defined

* Fix graphing component

* Re-add all old options from core/config.py

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2021-09-20 11:47:51 +02:00

218 lines
5.5 KiB
C++

#include "esp_one_wire.h"
#include "esphome/core/log.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace dallas {
static const char *const TAG = "dallas.one_wire";
const uint8_t ONE_WIRE_ROM_SELECT = 0x55;
const int ONE_WIRE_ROM_SEARCH = 0xF0;
ESPOneWire::ESPOneWire(GPIOPin *pin) : pin_(pin) {}
bool HOT IRAM_ATTR ESPOneWire::reset() {
uint8_t retries = 125;
// Wait for communication to clear
this->pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
do {
if (--retries == 0)
return false;
delayMicroseconds(2);
} while (!this->pin_->digital_read());
// Send 480µs LOW TX reset pulse
this->pin_->pin_mode(gpio::FLAG_OUTPUT);
this->pin_->digital_write(false);
delayMicroseconds(480);
// Switch into RX mode, letting the pin float
this->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);
bool r = !this->pin_->digital_read();
delayMicroseconds(410);
return r;
}
void HOT IRAM_ATTR ESPOneWire::write_bit(bool bit) {
// Initiate write/read by pulling low.
this->pin_->pin_mode(gpio::FLAG_OUTPUT);
this->pin_->digital_write(false);
// bus sampled within 15µs and 60µs after pulling LOW.
if (bit) {
// pull high/release within 15µs
delayMicroseconds(10);
this->pin_->digital_write(true);
// in total minimum of 60µs long
delayMicroseconds(55);
} else {
// continue pulling LOW for at least 60µs
delayMicroseconds(65);
this->pin_->digital_write(true);
// grace period, 1µs recovery time
delayMicroseconds(5);
}
}
bool HOT IRAM_ATTR ESPOneWire::read_bit() {
// Initiate read slot by pulling LOW for at least 1µs
this->pin_->pin_mode(gpio::FLAG_OUTPUT);
this->pin_->digital_write(false);
delayMicroseconds(3);
// release bus, we have to sample within 15µs of pulling low
this->pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
delayMicroseconds(10);
bool r = this->pin_->digital_read();
// read time slot at least 60µs long + 1µs recovery time between slots
delayMicroseconds(53);
return r;
}
void IRAM_ATTR ESPOneWire::write8(uint8_t val) {
for (uint8_t i = 0; i < 8; i++) {
this->write_bit(bool((1u << i) & val));
}
}
void IRAM_ATTR ESPOneWire::write64(uint64_t val) {
for (uint8_t i = 0; i < 64; i++) {
this->write_bit(bool((1ULL << i) & val));
}
}
uint8_t IRAM_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 IRAM_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 IRAM_ATTR ESPOneWire::select(uint64_t address) {
this->write8(ONE_WIRE_ROM_SELECT);
this->write64(address);
}
void IRAM_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 IRAM_ATTR ESPOneWire::search() {
if (this->last_device_flag_) {
return 0u;
}
if (!this->reset()) {
// Reset failed
this->reset_search();
return 0u;
}
uint8_t id_bit_number = 1;
uint8_t last_zero = 0;
uint8_t rom_byte_number = 0;
bool search_result = false;
uint8_t rom_byte_mask = 1;
// Initiate search
this->write8(ONE_WIRE_ROM_SEARCH);
do {
// read bit
bool id_bit = this->read_bit();
// read its complement
bool cmp_id_bit = this->read_bit();
if (id_bit && cmp_id_bit)
// No devices participating in search
break;
bool branch;
if (id_bit != cmp_id_bit) {
// only chose one branch, the other one doesn't have any devices.
branch = id_bit;
} else {
// there are devices with both 0s and 1s at this bit
if (id_bit_number < this->last_discrepancy_) {
branch = (this->rom_number8_()[rom_byte_number] & rom_byte_mask) > 0;
} else {
branch = id_bit_number == this->last_discrepancy_;
}
if (!branch) {
last_zero = id_bit_number;
if (last_zero < 9) {
this->last_discrepancy_ = last_zero;
}
}
}
if (branch)
// set bit
this->rom_number8_()[rom_byte_number] |= rom_byte_mask;
else
// clear bit
this->rom_number8_()[rom_byte_number] &= ~rom_byte_mask;
// choose/announce branch
this->write_bit(branch);
id_bit_number++;
rom_byte_mask <<= 1;
if (rom_byte_mask == 0u) {
// go to next byte
rom_byte_number++;
rom_byte_mask = 1;
}
} while (rom_byte_number < 8); // loop through all bytes
if (id_bit_number >= 65) {
this->last_discrepancy_ = last_zero;
if (this->last_discrepancy_ == 0)
// we're at root and have no choices left, so this was the last one.
this->last_device_flag_ = true;
search_result = true;
}
search_result = search_result && (this->rom_number8_()[0] != 0);
if (!search_result) {
this->reset_search();
return 0u;
}
return this->rom_number_;
}
std::vector<uint64_t> IRAM_ATTR ESPOneWire::search_vec() {
std::vector<uint64_t> res;
this->reset_search();
uint64_t address;
while ((address = this->search()) != 0u)
res.push_back(address);
return res;
}
void IRAM_ATTR ESPOneWire::skip() {
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_); }
} // namespace dallas
} // namespace esphome