From dc3d84b266137673f79e57839a383c17ab5c66c1 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 27 Sep 2020 18:26:30 +0200 Subject: [PATCH] Fix ESP32 OneWire driver Fix ESP32 OneWire driver (#9302) --- .../OneWire.cpp | 170 +++++++----- .../OneWire.h | 34 +-- .../README.md | 11 + .../DS18x20_Temperature.pde | 0 .../examples/DS2408_Switch/DS2408_Switch.pde | 0 .../examples/DS250x_PROM/DS250x_PROM.pde | 0 .../keywords.txt | 0 .../library.json | 0 .../library.properties | 4 +- tasmota/xsns_05_ds18x20.ino | 2 + tasmota/xsns_05_ds18x20_esp32.ino | 254 ++++++++++++++++++ 11 files changed, 385 insertions(+), 90 deletions(-) rename lib/{OneWire-2.3.3.06 => OneWire-Stickbreaker-20190506-1.1}/OneWire.cpp (86%) rename lib/{OneWire-2.3.3.06 => OneWire-Stickbreaker-20190506-1.1}/OneWire.h (95%) create mode 100644 lib/OneWire-Stickbreaker-20190506-1.1/README.md rename lib/{OneWire-2.3.3.06 => OneWire-Stickbreaker-20190506-1.1}/examples/DS18x20_Temperature/DS18x20_Temperature.pde (100%) rename lib/{OneWire-2.3.3.06 => OneWire-Stickbreaker-20190506-1.1}/examples/DS2408_Switch/DS2408_Switch.pde (100%) rename lib/{OneWire-2.3.3.06 => OneWire-Stickbreaker-20190506-1.1}/examples/DS250x_PROM/DS250x_PROM.pde (100%) rename lib/{OneWire-2.3.3.06 => OneWire-Stickbreaker-20190506-1.1}/keywords.txt (100%) rename lib/{OneWire-2.3.3.06 => OneWire-Stickbreaker-20190506-1.1}/library.json (100%) rename lib/{OneWire-2.3.3.06 => OneWire-Stickbreaker-20190506-1.1}/library.properties (83%) create mode 100644 tasmota/xsns_05_ds18x20_esp32.ino diff --git a/lib/OneWire-2.3.3.06/OneWire.cpp b/lib/OneWire-Stickbreaker-20190506-1.1/OneWire.cpp similarity index 86% rename from lib/OneWire-2.3.3.06/OneWire.cpp rename to lib/OneWire-Stickbreaker-20190506-1.1/OneWire.cpp index 5c9945d51..4476ff53a 100644 --- a/lib/OneWire-2.3.3.06/OneWire.cpp +++ b/lib/OneWire-Stickbreaker-20190506-1.1/OneWire.cpp @@ -32,6 +32,17 @@ private email about OneWire). OneWire is now very mature code. No changes other than adding definitions for newer hardware support are anticipated. +======= +Version 2.3.3 ESP32 Stickbreaker 06MAY2019 + Add a #ifdef to isolate ESP32 mods +Version 2.3.1 ESP32 everslick 30APR2018 + add IRAM_ATTR attribute to write_bit/read_bit to fix icache miss delay + https://github.com/espressif/arduino-esp32/issues/1335 + +Version 2.3 ESP32 stickbreaker 28DEC2017 + adjust to use portENTER_CRITICAL(&mux) instead of noInterrupts(); + adjust to use portEXIT_CRITICAL(&mux) instead of Interrupts(); + Version 2.3: Unknown chip fallback mode, Roger Clark Teensy-LC compatibility, Paul Stoffregen @@ -141,14 +152,18 @@ sample code bearing this copyright. #include "OneWire.h" +#ifdef ARDUINO_ARCH_ESP32 +#define noInterrupts() {portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;portENTER_CRITICAL(&mux) +#define interrupts() portEXIT_CRITICAL(&mux);} +#endif OneWire::OneWire(uint8_t pin) { - pinMode(pin, INPUT); - bitmask = PIN_TO_BITMASK(pin); - baseReg = PIN_TO_BASEREG(pin); + pinMode(pin, INPUT); + bitmask = PIN_TO_BITMASK(pin); + baseReg = PIN_TO_BASEREG(pin); #if ONEWIRE_SEARCH - reset_search(); + reset_search(); #endif } @@ -159,60 +174,65 @@ OneWire::OneWire(uint8_t pin) // // Returns 1 if a device asserted a presence pulse, 0 otherwise. // +#ifdef ARDUINO_ARCH_ESP32 +uint8_t IRAM_ATTR OneWire::reset(void) +#else uint8_t OneWire::reset(void) +#endif { - IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask; - volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg; - uint8_t r; - uint8_t retries = 125; - - noInterrupts(); - DIRECT_MODE_INPUT(reg, mask); - interrupts(); - // wait until the wire is high... just in case - do { - if (--retries == 0) return 0; - delayMicroseconds(2); - } while ( !DIRECT_READ(reg, mask)); - - noInterrupts(); - DIRECT_WRITE_LOW(reg, mask); - DIRECT_MODE_OUTPUT(reg, mask); // drive output low - interrupts(); - delayMicroseconds(480); - noInterrupts(); - DIRECT_MODE_INPUT(reg, mask); // allow it to float - delayMicroseconds(70); - r = !DIRECT_READ(reg, mask); - interrupts(); - delayMicroseconds(410); - return r; + IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask; + volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg; + uint8_t r; + uint8_t retries = 125; + noInterrupts(); + DIRECT_MODE_INPUT(reg, mask); + interrupts(); + // wait until the wire is high... just in case + do { + if (--retries == 0) return 0; + delayMicroseconds(2); + } while ( !DIRECT_READ(reg, mask)); + + noInterrupts(); + DIRECT_WRITE_LOW(reg, mask); + DIRECT_MODE_OUTPUT(reg, mask); // drive output low + delayMicroseconds(480); + DIRECT_MODE_INPUT(reg, mask); // allow it to float + delayMicroseconds(70); + r = !DIRECT_READ(reg, mask); + interrupts(); + delayMicroseconds(410); + return r; } // // Write a bit. Port and bit is used to cut lookup time and provide // more certain timing. // +#ifdef ARDUINO_ARCH_ESP32 +void IRAM_ATTR OneWire::write_bit(uint8_t v) +#else void OneWire::write_bit(uint8_t v) +#endif { IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask; volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg; if (v & 1) { - noInterrupts(); + noInterrupts(); DIRECT_WRITE_LOW(reg, mask); DIRECT_MODE_OUTPUT(reg, mask); // drive output low delayMicroseconds(10); DIRECT_WRITE_HIGH(reg, mask); // drive output high - interrupts(); + interrupts(); delayMicroseconds(55); } else { - noInterrupts(); + noInterrupts(); DIRECT_WRITE_LOW(reg, mask); DIRECT_MODE_OUTPUT(reg, mask); // drive output low delayMicroseconds(65); DIRECT_WRITE_HIGH(reg, mask); // drive output high - interrupts(); + interrupts(); delayMicroseconds(5); } } @@ -221,20 +241,24 @@ void OneWire::write_bit(uint8_t v) // Read a bit. Port and bit is used to cut lookup time and provide // more certain timing. // +#ifdef ARDUINO_ARCH_ESP32 +uint8_t IRAM_ATTR OneWire::read_bit(void) +#else uint8_t OneWire::read_bit(void) +#endif { IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask; volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg; uint8_t r; - noInterrupts(); + noInterrupts(); DIRECT_MODE_OUTPUT(reg, mask); DIRECT_WRITE_LOW(reg, mask); delayMicroseconds(3); DIRECT_MODE_INPUT(reg, mask); // let pin float, pull up will raise delayMicroseconds(10); r = DIRECT_READ(reg, mask); - interrupts(); + interrupts(); delayMicroseconds(53); return r; } @@ -247,17 +271,17 @@ uint8_t OneWire::read_bit(void) // other mishap. // void OneWire::write(uint8_t v, uint8_t power /* = 0 */) { - uint8_t bitMask; + uint8_t bitMask; - for (bitMask = 0x01; bitMask; bitMask <<= 1) { - OneWire::write_bit( (bitMask & v)?1:0); - } - if ( !power) { - noInterrupts(); - DIRECT_MODE_INPUT(baseReg, bitmask); - DIRECT_WRITE_LOW(baseReg, bitmask); - interrupts(); - } + for (bitMask = 0x01; bitMask; bitMask <<= 1) { + OneWire::write_bit( (bitMask & v)?1:0); + } + if ( !power) { + noInterrupts(); + DIRECT_MODE_INPUT(baseReg, bitmask); + DIRECT_WRITE_LOW(baseReg, bitmask); + interrupts(); + } } void OneWire::write_bytes(const uint8_t *buf, uint16_t count, bool power /* = 0 */) { @@ -279,7 +303,7 @@ uint8_t OneWire::read() { uint8_t r = 0; for (bitMask = 0x01; bitMask; bitMask <<= 1) { - if ( OneWire::read_bit()) r |= bitMask; + if ( OneWire::read_bit()) r |= bitMask; } return r; } @@ -311,9 +335,9 @@ void OneWire::skip() void OneWire::depower() { - noInterrupts(); - DIRECT_MODE_INPUT(baseReg, bitmask); - interrupts(); + noInterrupts(); + DIRECT_MODE_INPUT(baseReg, bitmask); + interrupts(); } #if ONEWIRE_SEARCH @@ -391,13 +415,12 @@ uint8_t OneWire::search(uint8_t *newAddr, bool search_mode /* = true */) LastFamilyDiscrepancy = 0; return FALSE; } - // issue the search command if (search_mode == true) { write(0xF0); // NORMAL SEARCH } else { write(0xEC); // CONDITIONAL SEARCH - } + } // loop to do the search do @@ -405,7 +428,7 @@ uint8_t OneWire::search(uint8_t *newAddr, bool search_mode /* = true */) // read a bit and its complement id_bit = read_bit(); cmp_id_bit = read_bit(); - + // check for no devices on 1-wire if ((id_bit == 1) && (cmp_id_bit == 1)) break; @@ -459,7 +482,6 @@ uint8_t OneWire::search(uint8_t *newAddr, bool search_mode /* = true */) } } while(rom_byte_number < 8); // loop until through all ROM bytes 0-7 - // if the search was successful then if (!(id_bit_number < 65)) { @@ -524,12 +546,12 @@ static const uint8_t PROGMEM dscrc_table[] = { // uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len) { - uint8_t crc = 0; + uint8_t crc = 0; - while (len--) { - crc = pgm_read_byte(dscrc_table + (crc ^ *addr++)); - } - return crc; + while (len--) { + crc = pgm_read_byte(dscrc_table + (crc ^ *addr++)); + } + return crc; } #else // @@ -538,22 +560,22 @@ uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len) // uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len) { - uint8_t crc = 0; + uint8_t crc = 0; - while (len--) { + while (len--) { #if defined(__AVR__) - crc = _crc_ibutton_update(crc, *addr++); + crc = _crc_ibutton_update(crc, *addr++); #else - uint8_t inbyte = *addr++; - for (uint8_t i = 8; i; i--) { - uint8_t mix = (crc ^ inbyte) & 0x01; - crc >>= 1; - if (mix) crc ^= 0x8C; - inbyte >>= 1; - } + uint8_t inbyte = *addr++; + for (uint8_t i = 8; i; i--) { + uint8_t mix = (crc ^ inbyte) & 0x01; + crc >>= 1; + if (mix) crc ^= 0x8C; + inbyte >>= 1; + } #endif - } - return crc; + } + return crc; } #endif @@ -594,4 +616,10 @@ uint16_t OneWire::crc16(const uint8_t* input, uint16_t len, uint16_t crc) } #endif + +#ifdef ARDUINO_ARCH_ESP32 +#undef noInterrupts() +#undef interrupts() +#endif + #endif diff --git a/lib/OneWire-2.3.3.06/OneWire.h b/lib/OneWire-Stickbreaker-20190506-1.1/OneWire.h similarity index 95% rename from lib/OneWire-2.3.3.06/OneWire.h rename to lib/OneWire-Stickbreaker-20190506-1.1/OneWire.h index 47bf7c1cb..119ac5413 100644 --- a/lib/OneWire-2.3.3.06/OneWire.h +++ b/lib/OneWire-Stickbreaker-20190506-1.1/OneWire.h @@ -275,18 +275,18 @@ void directModeOutput(IO_REG_TYPE pin) #include "portable.h" #include "avr/pgmspace.h" -#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId) -#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType) -#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase) -#define DIR_OFFSET_SS 0x01 -#define DIR_OFFSET_SOC 0x04 -#define EXT_PORT_OFFSET_SS 0x0A -#define EXT_PORT_OFFSET_SOC 0x50 +#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId) +#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType) +#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase) +#define DIR_OFFSET_SS 0x01 +#define DIR_OFFSET_SOC 0x04 +#define EXT_PORT_OFFSET_SS 0x0A +#define EXT_PORT_OFFSET_SOC 0x50 /* GPIO registers base address */ -#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase) -#define PIN_TO_BITMASK(pin) pin -#define IO_REG_TYPE uint32_t +#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase) +#define PIN_TO_BITMASK(pin) pin +#define IO_REG_TYPE uint32_t #define IO_REG_BASE_ATTR #define IO_REG_MASK_ATTR @@ -307,7 +307,7 @@ void directModeInput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) { if (SS_GPIO == GPIO_TYPE(pin)) { WRITE_ARC_REG(READ_ARC_REG((((IO_REG_TYPE)base) + DIR_OFFSET_SS)) & ~(0x01 << GPIO_ID(pin)), - ((IO_REG_TYPE)(base) + DIR_OFFSET_SS)); + ((IO_REG_TYPE)(base) + DIR_OFFSET_SS)); } else { MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) &= ~(0x01 << GPIO_ID(pin)); } @@ -318,7 +318,7 @@ void directModeOutput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) { if (SS_GPIO == GPIO_TYPE(pin)) { WRITE_ARC_REG(READ_ARC_REG(((IO_REG_TYPE)(base) + DIR_OFFSET_SS)) | (0x01 << GPIO_ID(pin)), - ((IO_REG_TYPE)(base) + DIR_OFFSET_SS)); + ((IO_REG_TYPE)(base) + DIR_OFFSET_SS)); } else { MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) |= (0x01 << GPIO_ID(pin)); } @@ -344,11 +344,11 @@ void directWriteHigh(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) } } -#define DIRECT_READ(base, pin) directRead(base, pin) -#define DIRECT_MODE_INPUT(base, pin) directModeInput(base, pin) -#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(base, pin) -#define DIRECT_WRITE_LOW(base, pin) directWriteLow(base, pin) -#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(base, pin) +#define DIRECT_READ(base, pin) directRead(base, pin) +#define DIRECT_MODE_INPUT(base, pin) directModeInput(base, pin) +#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(base, pin) +#define DIRECT_WRITE_LOW(base, pin) directWriteLow(base, pin) +#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(base, pin) #elif defined(__riscv) diff --git a/lib/OneWire-Stickbreaker-20190506-1.1/README.md b/lib/OneWire-Stickbreaker-20190506-1.1/README.md new file mode 100644 index 000000000..fcc566fbf --- /dev/null +++ b/lib/OneWire-Stickbreaker-20190506-1.1/README.md @@ -0,0 +1,11 @@ +# OneWire library + A modification of the Arduino OneWire library maintained by @PaulStoffregen. This modifications supports the ESP32 under the Arduino-esp32 Environment. + + No changes are required for compatibility with Arduino coding. + +Original Source is Paul's 2.3 version. Forked 28DEC2017 + +@stickbreaker +V2.3.1 30APR2018 add IRAM_ATTR to read_bit() write_bit() to solve ICache miss timing failure. + thanks @everslick re: https://github.com/espressif/arduino-esp32/issues/1335 +V2.3 28DEC2017 original mods to support ESP32 diff --git a/lib/OneWire-2.3.3.06/examples/DS18x20_Temperature/DS18x20_Temperature.pde b/lib/OneWire-Stickbreaker-20190506-1.1/examples/DS18x20_Temperature/DS18x20_Temperature.pde similarity index 100% rename from lib/OneWire-2.3.3.06/examples/DS18x20_Temperature/DS18x20_Temperature.pde rename to lib/OneWire-Stickbreaker-20190506-1.1/examples/DS18x20_Temperature/DS18x20_Temperature.pde diff --git a/lib/OneWire-2.3.3.06/examples/DS2408_Switch/DS2408_Switch.pde b/lib/OneWire-Stickbreaker-20190506-1.1/examples/DS2408_Switch/DS2408_Switch.pde similarity index 100% rename from lib/OneWire-2.3.3.06/examples/DS2408_Switch/DS2408_Switch.pde rename to lib/OneWire-Stickbreaker-20190506-1.1/examples/DS2408_Switch/DS2408_Switch.pde diff --git a/lib/OneWire-2.3.3.06/examples/DS250x_PROM/DS250x_PROM.pde b/lib/OneWire-Stickbreaker-20190506-1.1/examples/DS250x_PROM/DS250x_PROM.pde similarity index 100% rename from lib/OneWire-2.3.3.06/examples/DS250x_PROM/DS250x_PROM.pde rename to lib/OneWire-Stickbreaker-20190506-1.1/examples/DS250x_PROM/DS250x_PROM.pde diff --git a/lib/OneWire-2.3.3.06/keywords.txt b/lib/OneWire-Stickbreaker-20190506-1.1/keywords.txt similarity index 100% rename from lib/OneWire-2.3.3.06/keywords.txt rename to lib/OneWire-Stickbreaker-20190506-1.1/keywords.txt diff --git a/lib/OneWire-2.3.3.06/library.json b/lib/OneWire-Stickbreaker-20190506-1.1/library.json similarity index 100% rename from lib/OneWire-2.3.3.06/library.json rename to lib/OneWire-Stickbreaker-20190506-1.1/library.json diff --git a/lib/OneWire-2.3.3.06/library.properties b/lib/OneWire-Stickbreaker-20190506-1.1/library.properties similarity index 83% rename from lib/OneWire-2.3.3.06/library.properties rename to lib/OneWire-Stickbreaker-20190506-1.1/library.properties index cd8fc05f7..2a8b08e53 100644 --- a/lib/OneWire-2.3.3.06/library.properties +++ b/lib/OneWire-Stickbreaker-20190506-1.1/library.properties @@ -3,8 +3,8 @@ version=2.3.3 author=Jim Studt, Tom Pollard, Robin James, Glenn Trewitt, Jason Dangel, Guillermo Lovato, Paul Stoffregen, Scott Roberts, Bertrik Sikken, Mark Tillotson, Ken Butcher, Roger Clark, Love Nystrom maintainer=Paul Stoffregen sentence=Access 1-wire temperature sensors, memory and other chips. -paragraph= +paragraph= Mod of Paul Stoffregen code to support ESP32 category=Communication url=http://www.pjrc.com/teensy/td_libs_OneWire.html -architectures=* +architectures=esp32 diff --git a/tasmota/xsns_05_ds18x20.ino b/tasmota/xsns_05_ds18x20.ino index 361847932..e828c55d6 100644 --- a/tasmota/xsns_05_ds18x20.ino +++ b/tasmota/xsns_05_ds18x20.ino @@ -17,6 +17,7 @@ along with this program. If not, see . */ +#ifdef ESP8266 #ifdef USE_DS18x20 /*********************************************************************************************\ * DS18B20 - Temperature - Multiple sensors @@ -547,3 +548,4 @@ bool Xsns05(uint8_t function) } #endif // USE_DS18x20 +#endif // ESP8266 diff --git a/tasmota/xsns_05_ds18x20_esp32.ino b/tasmota/xsns_05_ds18x20_esp32.ino new file mode 100644 index 000000000..b12e2ceb0 --- /dev/null +++ b/tasmota/xsns_05_ds18x20_esp32.ino @@ -0,0 +1,254 @@ +/* + xsns_05_ds18x20_esp32.ino - DS18x20 temperature sensor support for Tasmota + + Copyright (C) 2019 Heiko Krupp and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef ESP32 +#ifdef USE_DS18x20 +/*********************************************************************************************\ + * DS18B20 - Temperature - Multiple sensors +\*********************************************************************************************/ + +#define XSNS_05 5 + +#define DS18S20_CHIPID 0x10 // +/-0.5C 9-bit +#define DS1822_CHIPID 0x22 // +/-2C 12-bit +#define DS18B20_CHIPID 0x28 // +/-0.5C 12-bit +#define MAX31850_CHIPID 0x3B // +/-0.25C 14-bit + +#define W1_SKIP_ROM 0xCC +#define W1_CONVERT_TEMP 0x44 +#define W1_READ_SCRATCHPAD 0xBE + +#define DS18X20_MAX_SENSORS 8 + +const char kDs18x20Types[] PROGMEM = "DS18x20|DS18S20|DS1822|DS18B20|MAX31850"; + +uint8_t ds18x20_chipids[] = { 0, DS18S20_CHIPID, DS1822_CHIPID, DS18B20_CHIPID, MAX31850_CHIPID }; + +uint8_t ds18x20_address[DS18X20_MAX_SENSORS][8]; +uint8_t ds18x20_index[DS18X20_MAX_SENSORS]; +uint8_t ds18x20_valid[DS18X20_MAX_SENSORS]; +uint8_t ds18x20_sensors = 0; +char ds18x20_types[12]; + +/********************************************************************************************/ + +#include + +OneWire *ds = nullptr; + +void Ds18x20Init(void) { + ds = new OneWire(Pin(GPIO_DSB)); + + Ds18x20Search(); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSORS_FOUND " %d"), ds18x20_sensors); +} + +void Ds18x20Search(void) { + uint8_t num_sensors=0; + uint8_t sensor = 0; + + ds->reset_search(); + for (num_sensors = 0; num_sensors < DS18X20_MAX_SENSORS; num_sensors) { + if (!ds->search(ds18x20_address[num_sensors])) { + ds->reset_search(); + break; + } + // If CRC Ok and Type DS18S20, DS1822, DS18B20 or MAX31850 + if ((OneWire::crc8(ds18x20_address[num_sensors], 7) == ds18x20_address[num_sensors][7]) && + ((ds18x20_address[num_sensors][0]==DS18S20_CHIPID) || + (ds18x20_address[num_sensors][0]==DS1822_CHIPID) || + (ds18x20_address[num_sensors][0]==DS18B20_CHIPID) || + (ds18x20_address[num_sensors][0]==MAX31850_CHIPID))) { + num_sensors++; + } + } + for (uint32_t i = 0; i < num_sensors; i++) { + ds18x20_index[i] = i; + } + for (uint32_t i = 0; i < num_sensors; i++) { + for (uint32_t j = i + 1; j < num_sensors; j++) { + if (uint32_t(ds18x20_address[ds18x20_index[i]]) > uint32_t(ds18x20_address[ds18x20_index[j]])) { + std::swap(ds18x20_index[i], ds18x20_index[j]); + } + } + } + ds18x20_sensors = num_sensors; +} + +void Ds18x20Convert(void) { + ds->reset(); + ds->write(W1_SKIP_ROM); // Address all Sensors on Bus + ds->write(W1_CONVERT_TEMP); // start conversion, no parasite power on at the end +// delay(750); // 750ms should be enough for 12bit conv +} + +bool Ds18x20Read(uint8_t sensor, float &t) +{ + uint8_t data[12]; + int8_t sign = 1; + + t = NAN; + + uint8_t index = ds18x20_index[sensor]; + if (ds18x20_valid[index]) { ds18x20_valid[index]--; } + + ds->reset(); + ds->select(ds18x20_address[index]); + ds->write(W1_READ_SCRATCHPAD); // Read Scratchpad + + for (uint32_t i = 0; i < 9; i++) { + data[i] = ds->read(); + } + if (OneWire::crc8(data, 8) == data[8]) { + switch(ds18x20_address[index][0]) { + case DS18S20_CHIPID: { + int16_t tempS = (((data[1] << 8) | (data[0] & 0xFE)) << 3) | ((0x10 - data[6]) & 0x0F); + t = ConvertTemp(tempS * 0.0625 - 0.250); + ds18x20_valid[index] = SENSOR_MAX_MISS; + return true; + } + case DS1822_CHIPID: + case DS18B20_CHIPID: { + uint16_t temp12 = (data[1] << 8) + data[0]; + if (temp12 > 2047) { + temp12 = (~temp12) +1; + sign = -1; + } + t = ConvertTemp(sign * temp12 * 0.0625); // Divide by 16 + ds18x20_valid[index] = SENSOR_MAX_MISS; + return true; + } + case MAX31850_CHIPID: { + int16_t temp14 = (data[1] << 8) + (data[0] & 0xFC); + t = ConvertTemp(temp14 * 0.0625); // Divide by 16 + ds18x20_valid[index] = SENSOR_MAX_MISS; + return true; + } + } + } + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSOR_CRC_ERROR)); + return false; +} + +void Ds18x20Name(uint8_t sensor) +{ + uint8_t index = sizeof(ds18x20_chipids); + while (index) { + if (ds18x20_address[ds18x20_index[sensor]][0] == ds18x20_chipids[index]) { + break; + } + index--; + } + GetTextIndexed(ds18x20_types, sizeof(ds18x20_types), index, kDs18x20Types); + if (ds18x20_sensors > 1) { + snprintf_P(ds18x20_types, sizeof(ds18x20_types), PSTR("%s%c%d"), ds18x20_types, IndexSeparator(), sensor +1); + } +} + +/********************************************************************************************/ + +void Ds18x20EverySecond(void) +{ + if (!ds18x20_sensors) { return; } + + if (uptime & 1) { + // 2mS +// Ds18x20Search(); // Check for changes in sensors number + Ds18x20Convert(); // Start Conversion, takes up to one second + } else { + float t; + for (uint32_t i = 0; i < ds18x20_sensors; i++) { + // 12mS per device + if (!Ds18x20Read(i, t)) { // Read temperature + Ds18x20Name(i); + AddLogMissed(ds18x20_types, ds18x20_valid[ds18x20_index[i]]); + } + } + } +} + +void Ds18x20Show(bool json) +{ + float t; + + uint8_t dsxflg = 0; + for (uint32_t i = 0; i < ds18x20_sensors; i++) { + if (Ds18x20Read(i, t)) { // Check if read failed + char temperature[33]; + dtostrfd(t, Settings.flag2.temperature_resolution, temperature); + + Ds18x20Name(i); + + if (json) { + char address[17]; + for (uint32_t j = 0; j < 6; j++) { + sprintf(address+2*j, "%02X", ds18x20_address[ds18x20_index[i]][6-j]); // Skip sensor type and crc + } + ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_ID "\":\"%s\",\"" D_JSON_TEMPERATURE "\":%s}"), ds18x20_types, address, temperature); + dsxflg++; +#ifdef USE_DOMOTICZ + if ((0 == tele_period) && (1 == dsxflg)) { + DomoticzSensor(DZ_TEMP, temperature); + } +#endif // USE_DOMOTICZ +#ifdef USE_KNX + if ((0 == tele_period) && (1 == dsxflg)) { + KnxSensor(KNX_TEMPERATURE, t); + } +#endif // USE_KNX +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_SNS_TEMP, ds18x20_types, temperature, TempUnit()); +#endif // USE_WEBSERVER + } + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns05(uint8_t function) +{ + bool result = false; + + if (PinUsed(GPIO_DSB)) { + switch (function) { + case FUNC_INIT: + Ds18x20Init(); + break; + case FUNC_EVERY_SECOND: + Ds18x20EverySecond(); + break; + case FUNC_JSON_APPEND: + Ds18x20Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + Ds18x20Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_DS18x20 +#endif // ESP32