From 4d5e512952fc83981e3111bac5016307cf7d230f Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Mon, 25 May 2020 08:45:09 +0200 Subject: [PATCH 1/7] esp32 uart and wemos d1-mini32 --- platformio.ini | 7 + src/device_library.h | 6 +- src/sensors.h | 5 + src/settings.h | 2 +- src/system.h | 6 +- src/uart/emsuart_esp32.cpp | 154 +++++++++----------- src/uart/emsuart_esp32.h | 27 ++-- src/uart/emsuart_esp8266.cpp | 262 +++++------------------------------ src/uart/emsuart_esp8266.h | 17 +-- 9 files changed, 133 insertions(+), 353 deletions(-) diff --git a/platformio.ini b/platformio.ini index 41c00a9b5..3f23f0893 100644 --- a/platformio.ini +++ b/platformio.ini @@ -4,6 +4,7 @@ [platformio] default_envs = esp8266 ;default_envs = esp32 +;default_envs = esp32_d1 # override any settings with your own local ones in pio_local.ini extra_configs = pio_local.ini @@ -89,3 +90,9 @@ board = esp32dev lib_deps = ${common.libs_core} ${common.libs_esp32} build_flags = ${common.build_flags} ${common.debug_flags} -D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH +[env:esp32_d1] +build_type = release +platform = espressif32 +board = wemos_d1_mini32 +lib_deps = ${common.libs_core} ${common.libs_esp32} +build_flags = ${common.build_flags} ${common.debug_flags} -D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH diff --git a/src/device_library.h b/src/device_library.h index 62126d0f3..cc89d8699 100644 --- a/src/device_library.h +++ b/src/device_library.h @@ -24,10 +24,10 @@ */ // Boilers - 0x08 +{ 72, DeviceType::BOILER, F("GB125/MC10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {115, DeviceType::BOILER, F("Topline/GB162"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {123, DeviceType::BOILER, F("GBx72/Trendline/Cerapur/Greenstar Si/27i"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {133, DeviceType::BOILER, F("GB125/Logamatic MC110"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, -{115, DeviceType::BOILER, F("Topline/GB162"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {203, DeviceType::BOILER, F("Logamax U122/Cerapur"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {208, DeviceType::BOILER, F("Logamax plus/GB192/Condens GC9000"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, { 64, DeviceType::BOILER, F("BK13,BK15/Smartline/GB1x2"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, @@ -78,7 +78,7 @@ // Gateways - 0x48 / 0x18 {189, DeviceType::GATEWAY, F("KM200"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x48 -{ 94, DeviceType::GATEWAY, F("RC"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x18 +{ 94, DeviceType::GATEWAY, F("RFM"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x18 // Thermostat - not currently supporting write operations, like the Easy/100 types - 0x18 {202, DeviceType::THERMOSTAT, F("Logamatic TC100/Moduline Easy"), DeviceFlags::EMS_DEVICE_FLAG_EASY | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write @@ -98,7 +98,7 @@ // Thermostat - Sieger - 0x10 / 0x17 { 76, DeviceType::THERMOSTAT, F("ES73"), DeviceFlags::EMS_DEVICE_FLAG_RC35}, // 0x10 -{113, DeviceType::THERMOSTAT, F("ES72"), DeviceFlags::EMS_DEVICE_FLAG_RC20_2}, // 0x17 +{113, DeviceType::THERMOSTAT, F("ES72/RC20"), DeviceFlags::EMS_DEVICE_FLAG_RC20_2}, // 0x17 // Thermostat - Junkers - 0x10 {105, DeviceType::THERMOSTAT, F("FW100"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS}, diff --git a/src/sensors.h b/src/sensors.h index a3b530037..98b94bf34 100644 --- a/src/sensors.h +++ b/src/sensors.h @@ -63,7 +63,12 @@ class Sensors { const std::vector devices() const; private: +#if defined(ESP8266) static constexpr uint8_t SENSOR_GPIO = 14; // D5 +#elif defined(ESP32) +// static constexpr uint8_t SENSOR_GPIO = 14; // same position + static constexpr uint8_t SENSOR_GPIO = 18; // for Wemos D1 32 +#endif enum class State { IDLE, READING, SCANNING }; diff --git a/src/settings.h b/src/settings.h index 64fc36619..213478851 100644 --- a/src/settings.h +++ b/src/settings.h @@ -48,7 +48,7 @@ #define EMSESP_DEFAULT_TX_MODE 1 #define EMSESP_DEFAULT_MQTT_ENABLED true #define EMSESP_DEFAULT_MQTT_BASE "home" -#define EMSESP_DEFAULT_MQTT_PORT 1883 +#define EMSESP_DEFAULT_MQTT_PORT 1884 #define EMSESP_DEFAULT_MQTT_QOS 0 #define EMSESP_DEFAULT_MQTT_RETAIN false #define EMSESP_DEFAULT_MQTT_FORMAT 2 // nested diff --git a/src/system.h b/src/system.h index 77dc2dee4..afd08693b 100644 --- a/src/system.h +++ b/src/system.h @@ -81,8 +81,10 @@ class System { static constexpr uint8_t LED_GPIO = 2; static constexpr uint8_t LED_ON = LOW; #elif defined(ESP32) - static constexpr uint8_t LED_GPIO = 5; // on Wemos D32 - static constexpr uint8_t LED_ON = LOW; +// static constexpr uint8_t LED_GPIO = 5; // on Wemos D32 +// static constexpr uint8_t LED_ON = LOW; + static constexpr uint8_t LED_GPIO = 2; // on Wemos D1-32 + static constexpr uint8_t LED_ON = HIGH; #else static constexpr uint8_t LED_GPIO = 0; static constexpr uint8_t LED_ON = 0; diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index 260bdb7ae..7da42a94e 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -26,134 +26,108 @@ namespace emsesp { +static intr_handle_t uart_handle; static RingbufHandle_t buf_handle = NULL; -static QueueHandle_t uart_queue = NULL; -static volatile uint8_t sending = 0; // If a telegram is send we ++, in receiving we ignore if != 0 and -- -uint8_t tx_mode_ = EMS_TXMODE_DEFAULT; +static uint8_t rxbuf[UART_FIFO_LEN]; +static uint8_t rxlen; -// Main interrupt handler -void EMSuart::emsuart_parseTask(void * param) { - for (;;) { + +/* +* Task to handle the incoming data. +*/ +void EMSuart::emsuart_recvTask(void * param) { + while(1) { size_t item_size; - uint8_t * telegram = (uint8_t *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(1000)); - uint8_t telegramSize = item_size; // can't be more than EMS_MAXBUFFERSIZE size (checked in sending task) + uint8_t * telegram = (uint8_t *)xRingbufferReceive(buf_handle, &item_size, portMAX_DELAY); + uint8_t telegramSize = item_size; - // Did we had a timeout? if (telegram) { EMSESP::incoming_telegram(telegram, telegramSize); vRingbufferReturnItem(buf_handle, (void *)telegram); } - } + } } - /* - * system task triggered on BRK interrupt - * incoming received messages are always asynchronous - * The full buffer is sent to the ems_parseTelegram() function in ems.cpp. + * UART interrupt, on break read the fifo and put the whole telegram to ringbuffer */ -void EMSuart::emsuart_recvTask(void * param) { - uart_event_t event; - for (;;) { - if (xQueueReceive(uart_queue, (void *)&event, (portTickType)portMAX_DELAY)) { - // We are only interested in UART_BREAK event and ignore all others - if (event.type == UART_BREAK) { - // If we didn't send it previously it is a newly received telegram - if (sending == 0) { - // Read all bytes which are already in the buffer - uint8_t data[EMSUART_RXBUFSIZE]; - int length = 0; - ESP_ERROR_CHECK(uart_get_buffered_data_len(EMSUART_UART, (size_t *)&length)); - if (length > EMSUART_RXBUFSIZE) // pedantic check - should never be the case because the receive buffer is of size EMSUART_RXBUFSIZE - { - length = EMSUART_RXBUFSIZE; - } - length = uart_read_bytes(EMSUART_UART, data, length, 0); // 0 --> we don't want to wait - // we will have runtime performance penalty with impact because of parseTelegram - // --> send the data to a 2nd task --> use a ringbuffer to exchange data between both tasks --> no need for pEMSRxBuf or alike - // this 2nd tasks processes the message with parseTelegram --> our receiving task is still responsiveness - // already do some validty checking here before informing the 2nd task - if ((length == 2) || ((length > 4) && (length <= EMS_MAXBUFFERSIZE + 1))) { - xRingbufferSend(buf_handle, data, length - 1, 0); // we are not waiting if ringbuffer is full --> just loose telegrams pdMS_TO_TICKS(1000) - } - } else { - --sending; - } - } +static void IRAM_ATTR uart_intr_handle(void *arg) +{ + if (EMS_UART.int_st.brk_det) { + uint8_t rx_fifo_len = EMS_UART.status.rxfifo_cnt; + for (rxlen = 0; rxlen < rx_fifo_len; rxlen++) { + rxbuf[rxlen] = EMS_UART.fifo.rw_byte; // read all bytes into buffer } + if ((rxlen == 2) || ((rxlen > 4) && (rxlen <= EMS_MAXBUFFERSIZE))) { + int baseType = 0; + xRingbufferSendFromISR(buf_handle, rxbuf, rxlen - 1, &baseType); + } + EMS_UART.int_clr.brk_det = 1; // clear flag + EMS_UART.conf0.txd_brk = 0; // if it was break from sending, clear bit } } - /* - * init UART0 driver + * init UART driver */ void EMSuart::start(uint8_t tx_mode) { - - tx_mode_ = tx_mode; - - // Configure UART parameters - // clang-format off uart_config_t uart_config = { .baud_rate = EMSUART_BAUD, .data_bits = UART_DATA_8_BITS, - .parity = UART_PARITY_DISABLE, + .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, - //.rx_flow_ctrl_thresh = 0, // UART HW RTS threshold should not be important }; - // clang-format on - ESP_ERROR_CHECK(uart_param_config(EMSUART_UART, &uart_config)); - - // Set UART pins(TX: IO16 (UART2 default), RX: IO17 (UART2 default), RTS: IO18, CTS: IO19) ESP_ERROR_CHECK(uart_set_pin(EMSUART_UART, EMSUART_TXPIN, EMSUART_RXPIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); - - // Setup UART buffered IO with event queue - // const int uart_buffer_size = (1024 * 2); - // QueueHandle_t uart_queue; - // Install UART driver using an event queue here - // ESP_ERROR_CHECK(uart_driver_install(UART2, uart_buffer_size, - // uart_buffer_size, 10, &uart_queue, 0)); - // do not use user defined interrupt handlers --> we are waiting for break event - // Decision was against written buffered I/O (seems to be fit better to ESP8266 approach), Queue is needed for receiving the break event, queue size wasn't clear - // 1 should be enough - also 10 should be fine - ESP_ERROR_CHECK(uart_driver_install(EMSUART_UART, EMSUART_RXBUFSIZE, 0, 10, &uart_queue, 0)); - - // Create a ringbuffer for communication between recvTask and parseTask (as max message size is ~32 bytes) 512 bytes has capacity to hold more than 16 telegrams + //EMS_UART.conf1.rxfifo_full_thrhd = 127; // enough to hold the incomming telegram, should never reached + //EMS_UART.idle_conf.tx_brk_num = 12; // breaklenght 12 bit + EMS_UART.int_ena.val = 0; // diable all intr. + EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags + EMS_UART.int_ena.brk_det = 1; // activate only break buf_handle = xRingbufferCreate(512, RINGBUF_TYPE_NOSPLIT); - - // start recvTaskQueue stacksize choosen any value 4069 bytes, Priority choosen 2 above normal to be able to fastly react on received signals - // xTaskCreate parameters taken from https://github.com/espressif/esp-idf/blob/ce2a99dc23533f40369e4ab0d17ffd40f4b0dd72/examples/peripherals/uart/uart_events/main/uart_events_example_main.c - xTaskCreate(emsuart_recvTask, "EMS_recv", 2048, NULL, 12, NULL); - - // create 2 tasks because assumption is that parseTelegram needs some time (even on ESP32) which would block receiving task - xTaskCreate(emsuart_parseTask, "EMS_parse", 8000, NULL, 2, NULL); + ESP_ERROR_CHECK(uart_isr_register(EMSUART_UART,uart_intr_handle, NULL, ESP_INTR_FLAG_IRAM, &uart_handle)); + xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, 12, NULL); } -/* + /* + * Stop, disables interrupt + */ +vvoid EMSuart::stop(){ + EMS_UART.int_ena.val = 0; //diable all intr. + }; + + /* + * Restart Interrupt + */ +vvoid EMSuart::restart(){ + EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags + EMS_UART.int_ena.brk_det = 1; // activate only break + }; + + /* * Sends a 1-byte poll, ending with a - * It's a bit dirty. there is no special wait logic per tx_mode type, fifo flushes or error checking */ void EMSuart::send_poll(uint8_t data) { - char buf[1]; - buf[0] = data; - uart_write_bytes_with_break(EMSUART_UART, (const char *)buf, 1, EMSUART_BREAKBITS); + EMS_UART.conf0.txd_brk = 0; // just to make sure the bit is cleared + EMS_UART.fifo.rw_byte = data; + EMS_UART.idle_conf.tx_brk_num = 12; // breaklenght 12 bit + EMS_UART.conf0.txd_brk = 1; // sending ends in a break } /* * Send data to Tx line, ending with a * buf contains the CRC and len is #bytes including the CRC - * returns code, 0=success, 1=brk error, 2=watchdog timeout + * returns code, 1=success */ EMSUART_STATUS EMSuart::transmit(uint8_t * buf, uint8_t len) { - if (len == 0) { - return EMS_TX_STATUS_OK; // nothing to send - } - - if (len && buf) { - ++sending; - uart_write_bytes_with_break(EMSUART_UART, (const char *)buf, len, EMSUART_BREAKBITS); - } - + if (len > 0) { + EMS_UART.conf0.txd_brk = 0; // just to make sure the bit is cleared + for (uint8_t i = 0; i < len; i++) { + EMS_UART.fifo.rw_byte = buf[i]; + } + //uart_tx_chars(EMSUART_UART, (const char *)buf, len); + EMS_UART.idle_conf.tx_brk_num = 12; // breaklenght 12 bit + EMS_UART.conf0.txd_brk = 1; // sending ends in a break + } return EMS_TX_STATUS_OK; } diff --git a/src/uart/emsuart_esp32.h b/src/uart/emsuart_esp32.h index 974e0283a..f800ff5e4 100644 --- a/src/uart/emsuart_esp32.h +++ b/src/uart/emsuart_esp32.h @@ -27,19 +27,14 @@ #include "freertos/queue.h" #include -#define EMS_MAXBUFFERSIZE 34 // max size of the buffer. EMS packets are max 32 bytes, plus extra 2 for BRKs - -#define EMSUART_UART UART_NUM_2 // UART 0 --> Changed to 2 for ESP32 // To do: Adapt -#define EMSUART_RXPIN 17 // To do: Adapt seems to be IO17 for ESP32 UART2 RX pin -#define EMSUART_TXPIN 16 // To do: Adapt seems to be IO16 for ESP32 UART2 TX pin -//#define EMSUART_CONFIG 0x1C // 8N1 (8 bits, no parity, 1 stopbit) -#define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit -#define EMSUART_RXBUFSIZE (2 * UART_FIFO_LEN) -#define EMSUART_BREAKBITS 11 // 11 bits break signal - -#define EMS_TXMODE_DEFAULT 1 -#define EMS_TXMODE_EMSPLUS 2 -#define EMS_TXMODE_HT3 3 +#define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus BRK +#define EMSUART_UART UART_NUM_2 // UART 0 --> Changed to 2 for ESP32 // To do: Adapt +#define EMS_UART UART2 // for intr setting +//#define EMSUART_RXPIN 17 // To do: Adapt seems to be IO17 for ESP32 UART2 RX pin +//#define EMSUART_TXPIN 16 // To do: Adapt seems to be IO16 for ESP32 UART2 TX pin +#define EMSUART_RXPIN 23 // Wemos D1 ESP32 UART2 RX pin for compatibility +#define EMSUART_TXPIN 5 // Wemos D1 ESP32 UART2 TX pin for compatibility +#define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit namespace emsesp { @@ -56,14 +51,12 @@ class EMSuart { static void start(uint8_t tx_mode); static void send_poll(uint8_t data); + static void stop(); + static void restart(); static EMSUART_STATUS transmit(uint8_t * buf, uint8_t len); - static void stop(){}; // not used with ESP32 - static void restart(){}; // not used with ESP32 - private: static void emsuart_recvTask(void * param); - static void emsuart_parseTask(void * param); }; } // namespace emsesp diff --git a/src/uart/emsuart_esp8266.cpp b/src/uart/emsuart_esp8266.cpp index 597b82fad..dc230fae7 100644 --- a/src/uart/emsuart_esp8266.cpp +++ b/src/uart/emsuart_esp8266.cpp @@ -28,48 +28,31 @@ os_event_t recvTaskQueue[EMSUART_recvTaskQueueLen]; // our Rx queue EMSuart::EMSRxBuf_t * pEMSRxBuf; EMSuart::EMSRxBuf_t * paEMSRxBuf[EMS_MAXBUFFERS]; -uint8_t emsRxBufIdx = 0; -uint8_t phantomBreak = 0; -uint8_t tx_mode_ = EMS_TXMODE_DEFAULT; +uint8_t emsRxBufIdx = 0; // // Main interrupt handler // Important: must not use ICACHE_FLASH_ATTR // void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { - static uint8_t length = 0; - static bool rx_idle_ = true; - static uint8_t uart_buffer[EMS_MAXBUFFERSIZE + 2]; - - // is a new buffer? if so init the thing for a new telegram - if (rx_idle_) { - rx_idle_ = false; // status set to busy - length = 0; - } - - // fill IRQ buffer, by emptying Rx FIFO - if (USIS(EMSUART_UART) & ((1 << UIFF) | (1 << UITO) | (1 << UIBD))) { - while ((USS(EMSUART_UART) >> USRXC) & 0xFF) { - uint8_t rx = USF(EMSUART_UART); - if (length < EMS_MAXBUFFERSIZE) - uart_buffer[length++] = rx; - } - - // clear Rx FIFO full and Rx FIFO timeout interrupts - USIC(EMSUART_UART) = (1 << UIFF) | (1 << UITO); - } + static uint8_t length = 0; + static uint8_t uart_buffer[128]; // BREAK detection = End of EMS data block if (USIS(EMSUART_UART) & ((1 << UIBD))) { - ETS_UART_INTR_DISABLE(); // disable all interrupts and clear them - USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt - - pEMSRxBuf->length = (length > EMS_MAXBUFFERSIZE) ? EMS_MAXBUFFERSIZE : length; - os_memcpy((void *)pEMSRxBuf->buffer, (void *)&uart_buffer, pEMSRxBuf->length); // copy data into transfer buffer, including the BRK 0x00 at the end - rx_idle_ = true; // check set the status flag stating BRK has been received and we can start a new package - ETS_UART_INTR_ENABLE(); // re-enable UART interrupts - - system_os_post(EMSUART_recvTaskPrio, 0, 0); // call emsuart_recvTask() at next opportunity + uint8_t rxlen = (USS(EMSUART_UART) & 0xFF); // length of buffer + for (length = 0; length < rxlen; length++) { + uart_buffer[length] = USF(EMSUART_UART); + } + USIE(EMSUART_UART) = 0; // disable all interrupts and clear them + USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset from sending + if (length < EMS_MAXBUFFERSIZE) { // only a valid telegram + pEMSRxBuf->length = length; + os_memcpy((void *)pEMSRxBuf->buffer, (void *)&uart_buffer, pEMSRxBuf->length); // copy data into transfer buffer, including the BRK 0x00 at the end + system_os_post(EMSUART_recvTaskPrio, 0, 0); // call emsuart_recvTask() at next opportunity + } + USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt + USIE(EMSUART_UART) = (1 << UIBD); // enable only rx break } } @@ -84,39 +67,23 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_recvTask(os_event_t * events) { uint8_t length = pCurrent->length; // number of bytes including the BRK at the end pCurrent->length = 0; - if (phantomBreak) { - phantomBreak = 0; - length--; // remove phantom break from Rx buffer - } - // it's a poll or status code, single byte and ok to send on, then quit if (length == 2) { EMSESP::incoming_telegram((uint8_t *)pCurrent->buffer, 1); return; } - // ignore double BRK at the end, possibly from the Tx loopback // also telegrams with no data value - // then transmit EMS buffer, excluding the BRK - if ((length > 4) && (length <= EMS_MAXBUFFERSIZE + 1)) { + // then transmit EMS buffer, excluding the BRK, lenght is checked by irq + if (length > 4) { EMSESP::incoming_telegram((uint8_t *)pCurrent->buffer, length - 1); } } -/* - * flush everything left over in buffer, this clears both rx and tx FIFOs - */ -void ICACHE_FLASH_ATTR EMSuart::emsuart_flush_fifos() { - uint32_t tmp = ((1 << UCRXRST) | (1 << UCTXRST)); // bit mask - USC0(EMSUART_UART) |= (tmp); // set bits - USC0(EMSUART_UART) &= ~(tmp); // clear bits -} - /* * init UART0 driver */ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { - tx_mode_ = tx_mode; // allocate and preset EMS Receive buffers for (int i = 0; i < EMS_MAXBUFFERS; i++) { @@ -125,8 +92,8 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { } pEMSRxBuf = paEMSRxBuf[0]; // reset EMS Rx Buffer - ETS_UART_INTR_DISABLE(); - ETS_UART_INTR_ATTACH(nullptr, nullptr); + //ETS_UART_INTR_DISABLE(); + //ETS_UART_INTR_ATTACH(nullptr, nullptr); // pin settings PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); @@ -138,41 +105,22 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { USD(EMSUART_UART) = (UART_CLK_FREQ / EMSUART_BAUD); USC0(EMSUART_UART) = EMSUART_CONFIG; // 8N1 - emsuart_flush_fifos(); - - // conf1 params - // UCTOE = RX TimeOut enable (default is 1) - // UCTOT = RX TimeOut Threshold (7 bit) = want this when no more data after 1 characters (default is 2) - // UCFFT = RX FIFO Full Threshold (7 bit) = want this to be 31 for 32 bytes of buffer (default was 127) - // see https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf - // - // change: we set UCFFT to 1 to get an immediate indicator about incoming traffic. - // Otherwise, we're only noticed by UCTOT or RxBRK! - USC1(EMSUART_UART) = 0; // reset config first - USC1(EMSUART_UART) = (0x01 << UCFFT) | (0x01 << UCTOT) | (0 << UCTOE); // enable interupts - - // set interrupts for triggers - USIC(EMSUART_UART) = 0xFFFF; // clear all interupts - USIE(EMSUART_UART) = 0; // disable all interrupts - - // enable rx break, fifo full and timeout. - // but not frame error UIFR (because they are too frequent) or overflow UIOF because our buffer is only max 32 bytes - // change: we don't care about Rx Timeout - it may lead to wrong readouts - USIE(EMSUART_UART) = (1 << UIBD) | (1 << UIFF) | (0 << UITO); + USC0(EMSUART_UART) |= ((1 << UCRXRST) | (1 << UCTXRST)); // set bits + USC0(EMSUART_UART) &= ~((1 << UCRXRST) | (1 << UCTXRST)); // clear bits + // UCFFT = RX FIFO Full Threshold (7 bit) = want this to be more than 32) + USC1(EMSUART_UART) = (0x7F << UCFFT); // rx buffer full + USIE(EMSUART_UART) = 0; // disable all interrupts + USIC(EMSUART_UART) = 0xFFFF; // clear all interupts // set up interrupt callbacks for Rx system_os_task(emsuart_recvTask, EMSUART_recvTaskPrio, recvTaskQueue, EMSUART_recvTaskQueueLen); - // disable esp debug which will go to Tx and mess up the line - see https://github.com/espruino/Espruino/issues/655 system_set_os_print(0); - // swap Rx and Tx pins to use GPIO13 (D7) and GPIO15 (D8) respectively system_uart_swap(); - ETS_UART_INTR_ATTACH(emsuart_rx_intr_handler, nullptr); - ETS_UART_INTR_ENABLE(); - - // logger_.info(F("UART service for Rx/Tx started")); + USIE(EMSUART_UART) = (1 << UIBD); // enable only rx break interrupt + //ETS_UART_INTR_ENABLE(); } /* @@ -180,170 +128,36 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { * This is called prior to an OTA upload and also before a save to the filesystem to prevent conflicts */ void ICACHE_FLASH_ATTR EMSuart::stop() { - ETS_UART_INTR_DISABLE(); + USIE(EMSUART_UART) = 0; // disable interrup } /* * re-start UART0 driver */ void ICACHE_FLASH_ATTR EMSuart::restart() { - ETS_UART_INTR_ENABLE(); + USIE(EMSUART_UART) = (1 << UIBD); // enable only rx break } -/* - * Send a BRK signal - * Which is a 11-bit set of zero's (11 cycles) - */ -void ICACHE_FLASH_ATTR EMSuart::tx_brk() { - uint32_t tmp; - - // must make sure Tx FIFO is empty - while (((USS(EMSUART_UART) >> USTXC) & 0xFF)) - ; - - tmp = ((1 << UCRXRST) | (1 << UCTXRST)); // bit mask - USC0(EMSUART_UART) |= (tmp); // set bits - USC0(EMSUART_UART) &= ~(tmp); // clear bits - - // To create a 11-bit we set TXD_BRK bit so the break signal will - // automatically be sent when the tx fifo is empty - tmp = (1 << UCBRK); - USC0(EMSUART_UART) |= (tmp); // set bit - - if (tx_mode_ == EMS_TX_WTD_TIMEOUT) { // EMS+ mode - delayMicroseconds(EMSUART_TX_BRK_WAIT); - } else if (tx_mode_ == EMS_TXMODE_HT3) { // junkers mode - delayMicroseconds(EMSUART_TX_WAIT_BRK - EMSUART_TX_LAG); // 1144 (11 Bits) - } - - USC0(EMSUART_UART) &= ~(tmp); // clear bit -} - -/* - * Sends a 1-byte poll, ending with a - * It's a bit dirty. there is no special wait logic per tx_mode type, fifo flushes or error checking - */ void EMSuart::send_poll(uint8_t data) { + USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear bit USF(EMSUART_UART) = data; - delayMicroseconds(EMSUART_TX_BRK_WAIT); - tx_brk(); // send + USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end } /* * Send data to Tx line, ending with a * buf contains the CRC and len is #bytes including the CRC - * returns code, 0=success, 1=brk error, 2=watchdog timeout */ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { - if (len == 0) { - return EMS_TX_STATUS_OK; // nothing to send - } - - // EMS+ https://github.com/proddy/EMS-ESP/issues/23# - if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // With extra tx delay for EMS+ - for (uint8_t i = 0; i < len; i++) { + if (len) { + USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear bit + for (uint8_t i = 0; i < len ; i++) { USF(EMSUART_UART) = buf[i]; - delayMicroseconds(EMSUART_TX_BRK_WAIT); // 2070 } - tx_brk(); // send - return EMS_TX_STATUS_OK; + USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end } - - // Junkers logic by @philrich - if (tx_mode_ == EMS_TXMODE_HT3) { - for (uint8_t i = 0; i < len; i++) { - USF(EMSUART_UART) = buf[i]; - - // just to be safe wait for tx fifo empty (still needed?) - while (((USS(EMSUART_UART) >> USTXC) & 0xff)) - ; - - // wait until bits are sent on wire - delayMicroseconds(EMSUART_TX_WAIT_BYTE - EMSUART_TX_LAG + EMSUART_TX_WAIT_GAP); // 1760 - } - tx_brk(); // send - return EMS_TX_STATUS_OK; - } - - /* - * Logic for tx_mode of 0 (EMS_TXMODE_DEFAULT) - * based on code from https://github.com/proddy/EMS-ESP/issues/103 by @susisstrolch - * - * Logic: - * we emit the whole telegram, with Rx interrupt disabled, collecting busmaster response in FIFO. - * after sending the last char we poll the Rx status until either - * - size(Rx FIFO) == size(Tx-Telegram) - * - is detected - * At end of receive we re-enable Rx-INT and send a Tx-BRK in loopback mode. - * - * EMS-Bus error handling - * 1. Busmaster stops echoing on Tx w/o permission - * 2. Busmaster cancel telegram by sending a BRK - * - * Case 1. is handled by a watchdog counter which is reset on each - * Tx attempt. The timeout should be 20x EMSUART_BIT_TIME plus - * some smart guess for processing time on targeted EMS device. - * We set Status to EMS_TX_WTD_TIMEOUT and return - * - * Case 2. is handled via a BRK chk during transmission. - * We set Status to EMS_TX_BRK_DETECT and return - * - */ - - EMSUART_STATUS result = EMS_TX_STATUS_OK; - - // disable rx interrupt - // clear Rx status register, resetting the Rx FIFO and flush it - ETS_UART_INTR_DISABLE(); - USC0(EMSUART_UART) |= (1 << UCRXRST); - emsuart_flush_fifos(); - - // send the bytes along the serial line - for (uint8_t i = 0; i < len; i++) { - uint16_t wdc = EMS_TX_TO_COUNT; // 1760 - volatile uint8_t _usrxc = (USS(EMSUART_UART) >> USRXC) & 0xFF; - USF(EMSUART_UART) = buf[i]; // send each Tx byte - // wait for echo from the busmaster - while (((USS(EMSUART_UART) >> USRXC) & 0xFF) == _usrxc) { - delayMicroseconds(EMSUART_BUSY_WAIT); // burn CPU cycles... - if (--wdc == 0) { - ETS_UART_INTR_ENABLE(); - return EMS_TX_WTD_TIMEOUT; - } - if (USIR(EMSUART_UART) & (1 << UIBD)) { - USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ - ETS_UART_INTR_ENABLE(); - return EMS_TX_BRK_DETECT; - } - } - } - - // we got the whole telegram in the Rx buffer - // on Rx-BRK (bus collision), we simply enable Rx and leave it - // otherwise we send the final Tx-BRK in the loopback and re=enable Rx-INT. - // worst case, we'll see an additional Rx-BRK... - if (result == EMS_TX_STATUS_OK) { - // neither bus collision nor timeout - send terminating BRK signal - if (!(USIS(EMSUART_UART) & (1 << UIBD))) { - // no bus collision - send terminating BRK signal - USC0(EMSUART_UART) |= (1 << UCLBE) | (1 << UCBRK); // enable loopback & set - - // wait until BRK detected... - while (!(USIR(EMSUART_UART) & (1 << UIBD))) { - delayMicroseconds(EMSUART_BIT_TIME); - } - - USC0(EMSUART_UART) &= ~((1 << UCBRK) | (1 << UCLBE)); // disable loopback & clear - USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ - phantomBreak = 1; - } - } - - ETS_UART_INTR_ENABLE(); // open up the FIFO again to start receiving - - return result; // send the Tx status back -} - + return EMS_TX_STATUS_OK; +} } // namespace emsesp #endif diff --git a/src/uart/emsuart_esp8266.h b/src/uart/emsuart_esp8266.h index 082300e4a..4227efa1b 100644 --- a/src/uart/emsuart_esp8266.h +++ b/src/uart/emsuart_esp8266.h @@ -28,19 +28,7 @@ #define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit #define EMS_MAXBUFFERS 3 // buffers for circular filling to avoid collisions -#define EMS_MAXBUFFERSIZE 34 // max size of the buffer. EMS packets are max 32 bytes, plus extra 2 for BRKs - -#define EMSUART_BIT_TIME 104 // bit time @9600 baud - -#define EMSUART_TX_BRK_WAIT 2070 // the BRK from Boiler master is roughly 1.039ms, so accounting for hardware lag using around 2078 (for half-duplex) - 8 (lag) -#define EMSUART_TX_WAIT_BYTE (EMSUART_BIT_TIME * 10) // Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) -#define EMSUART_TX_WAIT_BRK (EMSUART_BIT_TIME * 11) // Time to send a BRK Signal (11 Bit) -#define EMSUART_TX_WAIT_GAP (EMSUART_BIT_TIME * 7) // Gap between to Bytes -#define EMSUART_TX_LAG 8 - -#define EMSUART_BUSY_WAIT (EMSUART_BIT_TIME / 8) -#define EMS_TX_TO_CHARS (2 + 20) -#define EMS_TX_TO_COUNT ((EMS_TX_TO_CHARS)*10 * 8) +#define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra 2 for BRK #define EMSUART_recvTaskPrio 1 // 0, 1 or 2. 0 being the lowest #define EMSUART_recvTaskQueueLen 10 // number of queued'd Rx triggers @@ -75,10 +63,7 @@ class EMSuart { private: static void ICACHE_RAM_ATTR emsuart_rx_intr_handler(void * para); - static void ICACHE_FLASH_ATTR emsuart_recvTask(os_event_t * events); - static void ICACHE_FLASH_ATTR emsuart_flush_fifos(); - static void ICACHE_FLASH_ATTR tx_brk(); }; } // namespace emsesp From 55c60365f6096d84c273b2162d978e835739d3fb Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Tue, 26 May 2020 11:42:28 +0200 Subject: [PATCH 2/7] small change --- src/emsesp.cpp | 1 + src/mixing.cpp | 2 +- src/telegram.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 70289c5d4..6a0b0c727 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -569,6 +569,7 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { // check first for echo uint8_t first_value = data[0]; if (((first_value & 0x7F) == txservice_.ems_bus_id()) && (length > 1)) { + DEBUG_LOG(F("Tx echo")); return; // it's an echo } diff --git a/src/mixing.cpp b/src/mixing.cpp index 488406976..3ee78c099 100644 --- a/src/mixing.cpp +++ b/src/mixing.cpp @@ -153,7 +153,7 @@ void Mixing::process_MMStatusMessage(std::shared_ptr telegram) { // the heating circuit is determine by which device_id it is, 0x20 - 0x23 // 0x21 is position 2. 0x20 is typically reserved for the WM10 switch module // see https://github.com/proddy/EMS-ESP/issues/270 and https://github.com/proddy/EMS-ESP/issues/386#issuecomment-629610918 - hc_ = 0x22 - device_id(); + hc_ = device_id() - 0x20 + 1; telegram->read_value(flowTemp_, 1); // is * 10 telegram->read_value(pumpMod_, 3); telegram->read_value(flowSetTemp_, 0); diff --git a/src/telegram.cpp b/src/telegram.cpp index ea7443bcb..b3613ecb9 100644 --- a/src/telegram.cpp +++ b/src/telegram.cpp @@ -268,7 +268,7 @@ void RxService::add(uint8_t * data, uint8_t length) { uint8_t message_length; // work out depending on the type where the data message block starts - if (data[2] < 0xF0) { + if (data[2] < 0xF0 || length < 6) { // EMS 1.0 type_id = data[2]; message_data = data + 4; // message block starts at 5th byte From 348df3e96f9cd83ecc133ae976c7479629b5f25a Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 29 May 2020 12:20:26 +0200 Subject: [PATCH 3/7] uart and some small fixes --- .gitignore | 1 + src/boiler.cpp | 17 +-- src/device_library.h | 2 +- src/emsesp.cpp | 20 +++- src/mixing.cpp | 12 +- src/sensors.cpp | 15 +-- src/sensors.h | 1 - src/telegram.cpp | 5 +- src/telegram.h | 2 +- src/thermostat.cpp | 157 +++++++++++++------------ src/uart/emsuart_esp32.cpp | 20 ++-- src/uart/emsuart_esp32.h | 3 +- src/uart/emsuart_esp8266.cpp | 219 ++++++++++++++++++++++------------- src/uart/emsuart_esp8266.h | 2 +- 14 files changed, 268 insertions(+), 208 deletions(-) diff --git a/.gitignore b/.gitignore index 303d778b1..887d4c52b 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ emsesp doc/github.txt doc/test_data.txt +/src/uart/uart_proddy.txt diff --git a/src/boiler.cpp b/src/boiler.cpp index 283c3fc01..55e6a2fcb 100644 --- a/src/boiler.cpp +++ b/src/boiler.cpp @@ -49,7 +49,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const LOG_DEBUG(F("Registering new Boiler with device ID 0x%02X"), device_id); // the telegram handlers... - register_telegram_type(0x18, F("UBAMonitorFast"), true, std::bind(&Boiler::process_UBAMonitorFast, this, _1)); + register_telegram_type(0x18, F("UBAMonitorFast"), false, std::bind(&Boiler::process_UBAMonitorFast, this, _1)); register_telegram_type(0x19, F("UBAMonitorSlow"), true, std::bind(&Boiler::process_UBAMonitorSlow, this, _1)); register_telegram_type(0x34, F("UBAMonitorWW"), false, std::bind(&Boiler::process_UBAMonitorWW, this, _1)); register_telegram_type(0x1C, F("UBAMaintenanceStatus"), false, std::bind(&Boiler::process_UBAMaintenanceStatus, this, _1)); @@ -61,12 +61,12 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_telegram_type(0x16, F("UBAParameters"), true, std::bind(&Boiler::process_UBAParameters, this, _1)); register_telegram_type(0x1A, F("UBASetPoints"), false, std::bind(&Boiler::process_UBASetPoints, this, _1)); register_telegram_type(0xD1, F("UBAOutdoorTemp"), false, std::bind(&Boiler::process_UBAOutdoorTemp, this, _1)); - register_telegram_type(0xE4, F("UBAMonitorFastPlus"), true, std::bind(&Boiler::process_UBAMonitorFastPlus, this, _1)); - register_telegram_type(0xE5, F("UBAMonitorSlowPlus"), true, std::bind(&Boiler::process_UBAMonitorSlowPlus, this, _1)); + register_telegram_type(0xE4, F("UBAMonitorFastPlus"), false, std::bind(&Boiler::process_UBAMonitorFastPlus, this, _1)); + register_telegram_type(0xE5, F("UBAMonitorSlowPlus"), false, std::bind(&Boiler::process_UBAMonitorSlowPlus, this, _1)); register_telegram_type(0xE9, F("UBADHWStatus"), false, std::bind(&Boiler::process_UBADHWStatus, this, _1)); - register_telegram_type(0xE3, F("HeatPumpMonitor1"), true, std::bind(&Boiler::process_HPMonitor1, this, _1)); - register_telegram_type(0xE5, F("HeatPumpMonitor2"), true, std::bind(&Boiler::process_HPMonitor2, this, _1)); + register_telegram_type(0xE3, F("HeatPumpMonitor1"), false, std::bind(&Boiler::process_HPMonitor1, this, _1)); + register_telegram_type(0xE5, F("HeatPumpMonitor2"), false, std::bind(&Boiler::process_HPMonitor2, this, _1)); // MQTT callbacks register_mqtt_topic("boiler_cmd", std::bind(&Boiler::boiler_cmd, this, _1)); @@ -190,14 +190,17 @@ void Boiler::publish_values() { doc["pumpMod"] = pumpMod_; } if (wWCircPump_ != EMS_VALUE_BOOL_NOTSET) { - doc["wWCircPump"] = wWCircPump_; + doc["wWCircPump"] = Helpers::render_value(s, wWCircPump_, EMS_VALUE_BOOL); } if (wWCircPumpType_ != EMS_VALUE_BOOL_NOTSET) { - doc["wWCiPuType"] = wWCircPumpType_; + doc["wWCiPuType"] = wWCircPumpType_ ? "valve" : "pump"; } if (wWCircPumpMode_ != EMS_VALUE_UINT_NOTSET) { doc["wWCiPuMode"] = wWCircPumpMode_; } + if (wWCirc_ != EMS_VALUE_BOOL_NOTSET) { + doc["wWCirc"] = Helpers::render_value(s, wWCirc_, EMS_VALUE_BOOL); + } if (extTemp_ != EMS_VALUE_SHORT_NOTSET) { doc["outdoorTemp"] = (float)extTemp_ / 10; } diff --git a/src/device_library.h b/src/device_library.h index 4b32361db..4ddcd93e4 100644 --- a/src/device_library.h +++ b/src/device_library.h @@ -24,7 +24,6 @@ */ // Boilers - 0x08 -{ 72, DeviceType::BOILER, F("GB125/MC10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {115, DeviceType::BOILER, F("Topline/GB162"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {123, DeviceType::BOILER, F("GBx72/Trendline/Cerapur/Greenstar Si/27i"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {133, DeviceType::BOILER, F("GB125/Logamatic MC110"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, @@ -37,6 +36,7 @@ {122, DeviceType::BOILER, F("Proline"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {170, DeviceType::BOILER, F("Logano GB212"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {172, DeviceType::BOILER, F("Enviline/Compress 6000AW"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, +{ 72, DeviceType::BOILER, F("GB125/MC10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // Solar Modules - 0x30 { 73, DeviceType::SOLAR, F("SM10"), DeviceFlags::EMS_DEVICE_FLAG_SM10}, diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 825b8780b..519e63755 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -194,7 +194,7 @@ void EMSESP::show_values(uuid::console::Shell & shell) { if (!sensor_devices().empty()) { shell.printfln(F("External temperature sensors:")); for (const auto & device : sensor_devices()) { - shell.printfln(F(" Sensor ID %s: %s°C"), device.to_string().c_str(), Helpers::render_value(valuestr, device.temperature_c_, 2)); + shell.printfln(F(" Sensor ID %s: %s°C"), device.to_string().c_str(), Helpers::render_value(valuestr, device.temperature_c_, 2)); } shell.println(); } @@ -367,13 +367,14 @@ void EMSESP::process_version(std::shared_ptr telegram) { uint8_t product_id = telegram->message_data[offset]; // product ID // get version as XX.XX - char buf[6] = {0}; + char buf[6] = {0}, + buf1[6] = {0}; std::string version(5, '\0'); snprintf_P(&version[0], version.capacity() + 1, PSTR("%s.%s"), Helpers::smallitoa(buf, telegram->message_data[offset + 1]), - Helpers::smallitoa(buf, telegram->message_data[offset + 2])); + Helpers::smallitoa(buf1, telegram->message_data[offset + 2])); // some devices store the protocol type (HT3, Buderus) in the last byte uint8_t brand; @@ -570,6 +571,7 @@ void EMSESP::send_write_request(const uint16_t type_id, // we check if its a complete telegram or just a single byte (which could be a poll or a return status) void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { // check first for echo + //LOG_TRACE(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str()); uint8_t first_value = data[0]; if (((first_value & 0x7F) == txservice_.ems_bus_id()) && (length > 1)) { return; // it's an echo @@ -752,7 +754,7 @@ void EMSESP::console_commands(Shell & shell, unsigned int context) { shell.printfln(F("Performing a deep scan by pinging our device library...")); std::vector Device_Ids; - Device_Ids.push_back(0x09); // Controllers - 0x09 + Device_Ids.push_back(0x08); // Boilers - 0x08 Device_Ids.push_back(0x38); // HeatPump - 0x38 Device_Ids.push_back(0x30); // Solar Module - 0x30 Device_Ids.push_back(0x09); // Controllers - 0x09 @@ -760,10 +762,16 @@ void EMSESP::console_commands(Shell & shell, unsigned int context) { Device_Ids.push_back(0x48); // Gateway - 0x48 Device_Ids.push_back(0x20); // Mixing Devices - 0x20 Device_Ids.push_back(0x21); // Mixing Devices - 0x21 + Device_Ids.push_back(0x22); // Mixing Devices - 0x22 + Device_Ids.push_back(0x23); // Mixing Devices - 0x23 + Device_Ids.push_back(0x28); // Mixing Devices WW- 0x28 + Device_Ids.push_back(0x29); // Mixing Devices WW- 0x29 Device_Ids.push_back(0x10); // Thermostats - 0x10 Device_Ids.push_back(0x17); // Thermostats - 0x17 - Device_Ids.push_back(0x18); // Thermostats - 0x18 - Device_Ids.push_back(0x19); // Thermostats - 0x19 + Device_Ids.push_back(0x18); // Thermostat remote - 0x18 + Device_Ids.push_back(0x19); // Thermostat remote - 0x19 + Device_Ids.push_back(0x1A); // Thermostat remote - 0x1A + Device_Ids.push_back(0x1B); // Thermostat remote - 0x1B Device_Ids.push_back(0x11); // Switches - 0x11 // send the read command with Version command diff --git a/src/mixing.cpp b/src/mixing.cpp index 4a843b44b..198869adf 100644 --- a/src/mixing.cpp +++ b/src/mixing.cpp @@ -66,20 +66,20 @@ void Mixing::show_values(uuid::console::Shell & shell) { if (type_ == Type::WWC) { shell.printfln(F(" Warm Water Circuit #: %d"), hc_); - } else { shell.printfln(F(" Heating Circuit #: %d"), hc_); } - print_value(shell, 2, F("Current flow temperature"), F_(degrees), Helpers::render_value(buffer, flowTemp_, 10)); - print_value(shell, 2, F("Setpoint flow temperature"), F_(degrees), Helpers::render_value(buffer, flowSetTemp_, 1)); - print_value(shell, 2, F("Current pump modulation"), Helpers::render_value(buffer, pumpMod_, 1)); - print_value(shell, 2, F("Current valve status"), Helpers::render_value(buffer, status_, 1)); + print_value(shell, 4, F("Current flow temperature"), F_(degrees), Helpers::render_value(buffer, flowTemp_, 10)); + print_value(shell, 4, F("Setpoint flow temperature"), F_(degrees), Helpers::render_value(buffer, flowSetTemp_, 1)); + print_value(shell, 4, F("Current pump modulation"), Helpers::render_value(buffer, pumpMod_, 1)); + print_value(shell, 4, F("Current valve status"), Helpers::render_value(buffer, status_, 1)); } // publish values via MQTT // ideally we should group up all the mixing units together into a nested JSON but for now we'll send them individually void Mixing::publish_values() { - DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_SMALL); + static DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_MEDIUM); +// StaticJsonDocument doc; JsonObject rootMixing = doc.to(); JsonObject dataMixing; diff --git a/src/sensors.cpp b/src/sensors.cpp index f6dfe2423..94b098406 100644 --- a/src/sensors.cpp +++ b/src/sensors.cpp @@ -232,18 +232,7 @@ std::string Sensors::Device::to_string() const { (unsigned int)(id_)&0xFF); return str; } -std::string Sensors::Device::to_stringc() const { - std::string str(20, '\0'); - snprintf_P(&str[0], - str.capacity() + 1, - PSTR("%02X%04X%04X%04X%02X"), - (unsigned int)(id_ >> 56) & 0xFF, - (unsigned int)(id_ >> 40) & 0xFFFF, - (unsigned int)(id_ >> 24) & 0xFFFF, - (unsigned int)(id_ >> 8) & 0xFFFF, - (unsigned int)(id_)&0xFF); - return str; -} + // send all dallas sensor values as a JSON package to MQTT // assumes there are devices @@ -287,7 +276,7 @@ void Sensors::publish_values() { for (const auto & device : devices_) { if (mqtt_format_ == Settings::MQTT_format::MY) { char s[5]; - doc[device.to_stringc()] = Helpers::render_value(s, device.temperature_c_, 2); + doc[device.to_string()] = Helpers::render_value(s, device.temperature_c_, 2); } else { char sensorID[10]; // sensor{1-n} strlcpy(sensorID, "sensor", 10); diff --git a/src/sensors.h b/src/sensors.h index 8242f3e37..9c66eedd7 100644 --- a/src/sensors.h +++ b/src/sensors.h @@ -46,7 +46,6 @@ class Sensors { uint64_t id() const; std::string to_string() const; - std::string to_stringc() const; float temperature_c_ = NAN; diff --git a/src/telegram.cpp b/src/telegram.cpp index 0b8f7d687..73a90ee15 100644 --- a/src/telegram.cpp +++ b/src/telegram.cpp @@ -364,6 +364,7 @@ void TxService::loop() { // sends a 1 byte poll which is our own device ID void TxService::send_poll() { + //OG_TRACE(F("Ack %02X"),ems_bus_id() ^ ems_mask()); EMSuart::send_poll(ems_bus_id() ^ ems_mask()); } @@ -472,7 +473,7 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) { // send the telegram to the UART Tx EMSUART_STATUS status = EMSuart::transmit(telegram_raw, length); - LOG_TRACE(F("Tx: %s"), Helpers::data_to_hex(telegram_raw, length).c_str()); + //LOG_TRACE(F("Tx: %s"), Helpers::data_to_hex(telegram_raw, length).c_str()); if (status != EMS_TX_STATUS_OK) { LOG_ERROR(F("Failed to transmit Tx via UART. Error: %s"), status == EMS_TX_WTD_TIMEOUT ? F("Timeout") : F("BRK")); } @@ -495,7 +496,7 @@ void TxService::send_telegram(const uint8_t * data, const uint8_t length) { // send the telegram to the UART Tx EMSUART_STATUS status = EMSuart::transmit(telegram_raw, length); - LOG_TRACE(F("Tx: %s"), Helpers::data_to_hex(telegram_raw, length).c_str()); + //LOG_TRACE(F("Tx: %s"), Helpers::data_to_hex(telegram_raw, length).c_str()); if (status != EMS_TX_STATUS_OK) { LOG_ERROR(F("Failed to transmit Tx via UART. Error: %s"), status == EMS_TX_WTD_TIMEOUT ? F("Timeout") : F("BRK")); } diff --git a/src/telegram.h b/src/telegram.h index 3e9e59ebc..19c325fc9 100644 --- a/src/telegram.h +++ b/src/telegram.h @@ -213,7 +213,7 @@ class RxService : public EMSbus { class TxService : public EMSbus { public: - static constexpr size_t MAX_TX_TELEGRAMS = 50; + static constexpr size_t MAX_TX_TELEGRAMS = 30; static constexpr uint8_t TX_WRITE_FAIL = 4; static constexpr uint8_t TX_WRITE_SUCCESS = 1; diff --git a/src/thermostat.cpp b/src/thermostat.cpp index a9e8bff7b..1f4492675 100644 --- a/src/thermostat.cpp +++ b/src/thermostat.cpp @@ -327,7 +327,8 @@ bool Thermostat::updated_values() { static uint16_t current_value_ = 0; for (const auto & hc : heating_circuits_) { // don't publish if we haven't yet received some data - if ((hc->setpoint_roomTemp == EMS_VALUE_SHORT_NOTSET) || (hc->curr_roomTemp == EMS_VALUE_SHORT_NOTSET)) { +// if ((hc->setpoint_roomTemp == EMS_VALUE_SHORT_NOTSET) || (hc->curr_roomTemp == EMS_VALUE_SHORT_NOTSET)) { + if (hc->setpoint_roomTemp == EMS_VALUE_SHORT_NOTSET) { return false; } new_value += hc->setpoint_roomTemp + hc->curr_roomTemp + hc->mode; @@ -359,14 +360,17 @@ void Thermostat::publish_values() { // optional, add external temp. I don't think anyone actually is interested in this if ((flags == EMS_DEVICE_FLAG_RC35) && ((mqtt_format_ == Settings::MQTT_format::SINGLE) || (mqtt_format_ == Settings::MQTT_format::MY))) { + if (datetime_.size()) { + rootThermostat["time"] = datetime_.c_str(); + } if (dampedoutdoortemp != EMS_VALUE_INT_NOTSET) { rootThermostat["dampedtemp"] = dampedoutdoortemp; } if (tempsensor1 != EMS_VALUE_USHORT_NOTSET) { - rootThermostat["tempsens1"] = (float)tempsensor1 / 10; + rootThermostat["tempsensor1"] = (float)tempsensor1 / 10; } if (tempsensor2 != EMS_VALUE_USHORT_NOTSET) { - rootThermostat["tempsens2"] = (float)tempsensor2 / 10; + rootThermostat["tempsensor2"] = (float)tempsensor2 / 10; } } @@ -666,22 +670,78 @@ void Thermostat::show_values(uuid::console::Shell & shell) { char buffer[10]; // for formatting only if (datetime_.size()) { - shell.printfln(F(" Clock: %s"), datetime_.c_str()); + shell.printfln(F(" Clock: %s"), datetime_.c_str()); if (ibaClockOffset != EMS_VALUE_UINT_NOTSET) { - print_value(shell, 1, F("Offset clock"), Helpers::render_value(buffer, ibaClockOffset, 1)); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s + print_value(shell, 2, F("Offset clock"), Helpers::render_value(buffer, ibaClockOffset, 1)); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s } } uint8_t flags = (this->flags() & 0x0F); // specific thermostat characteristics, strip the option bits if (flags == EMS_DEVICE_FLAG_RC35) { - print_value(shell, 1, F("Damped Outdoor temperature"), F_(degrees), Helpers::render_value(buffer, dampedoutdoortemp, 1)); - print_value(shell, 1, F("Tempsensor 1"), F_(degrees), Helpers::render_value(buffer, tempsensor1, 10)); - print_value(shell, 1, F("Tempsensor 2"), F_(degrees), Helpers::render_value(buffer, tempsensor2, 10)); + print_value(shell, 2, F("Damped Outdoor temperature"), F_(degrees), Helpers::render_value(buffer, dampedoutdoortemp, 1)); + print_value(shell, 2, F("Tempsensor 1"), F_(degrees), Helpers::render_value(buffer, tempsensor1, 10)); + print_value(shell, 2, F("Tempsensor 2"), F_(degrees), Helpers::render_value(buffer, tempsensor2, 10)); + } + if (flags == EMS_DEVICE_FLAG_RC30_1) { + // settings parameters + if (ibaMainDisplay != EMS_VALUE_UINT_NOTSET) { + if (ibaMainDisplay == 0) { + shell.printfln(F(" Display: internal temperature")); + } else if (ibaMainDisplay == 1) { + shell.printfln(F(" Display: internal setpoint")); + } else if (ibaMainDisplay == 2) { + shell.printfln(F(" Display: external temperature")); + } else if (ibaMainDisplay == 3) { + shell.printfln(F(" Display: burner temperature")); + } else if (ibaMainDisplay == 4) { + shell.printfln(F(" Display: WW temperature")); + } else if (ibaMainDisplay == 5) { + shell.printfln(F(" Display: functioning mode")); + } else if (ibaMainDisplay == 6) { + shell.printfln(F(" Display: time")); + } else if (ibaMainDisplay == 7) { + shell.printfln(F(" Display: date")); + } else if (ibaMainDisplay == 9) { + shell.printfln(F(" Display: smoke temperature")); + } + } + + if (ibaLanguage != EMS_VALUE_UINT_NOTSET) { + if (ibaLanguage == 0) { + shell.printfln(F(" Language: German")); + } else if (ibaLanguage == 1) { + shell.printfln(F(" Language: Dutch")); + } else if (ibaLanguage == 2) { + shell.printfln(F(" Language: French")); + } else if (ibaLanguage == 3) { + shell.printfln(F(" Language: Italian")); + } + } + } + if (flags == EMS_DEVICE_FLAG_RC35 ||flags == EMS_DEVICE_FLAG_RC30_1) { + + if (ibaCalIntTemperature != EMS_VALUE_INT_NOTSET) { + print_value(shell, 2, F("Offset int. temperature"), F_(degrees), Helpers::render_value(buffer, ibaCalIntTemperature, 2)); + } + + if (ibaMinExtTemperature != EMS_VALUE_INT_NOTSET) { + print_value(shell, 2, F("Min ext. temperature"), F_(degrees), Helpers::render_value(buffer, ibaMinExtTemperature, 0)); // min ext temp for heating curve, in deg. + } + + if (ibaBuildingType != EMS_VALUE_UINT_NOTSET) { + if (ibaBuildingType == 0) { + shell.printfln(F(" Building: light")); + } else if (ibaBuildingType == 1) { + shell.printfln(F(" Building: medium")); + } else if (ibaBuildingType == 2) { + shell.printfln(F(" Building: heavy")); + } + } } for (const auto & hc : heating_circuits_) { - shell.printfln(F(" Heating Circuit %d:"), hc->hc_num()); + shell.printfln(F(" Heating Circuit %d:"), hc->hc_num()); // different thermostat types store their temperature values differently uint8_t format_setpoint, format_curr; @@ -700,13 +760,13 @@ void Thermostat::show_values(uuid::console::Shell & shell) { break; } - print_value(shell, 2, F("Current room temperature"), F_(degrees), Helpers::render_value(buffer, hc->curr_roomTemp, format_curr)); - print_value(shell, 2, F("Setpoint room temperature"), F_(degrees), Helpers::render_value(buffer, hc->setpoint_roomTemp, format_setpoint)); + print_value(shell, 4, F("Current room temperature"), F_(degrees), Helpers::render_value(buffer, hc->curr_roomTemp, format_curr)); + print_value(shell, 4, F("Setpoint room temperature"), F_(degrees), Helpers::render_value(buffer, hc->setpoint_roomTemp, format_setpoint)); if (hc->mode != EMS_VALUE_UINT_NOTSET) { - print_value(shell, 2, F("Mode"), mode_tostring(hc->get_mode(flags)).c_str()); + print_value(shell, 4, F("Mode"), mode_tostring(hc->get_mode(flags)).c_str()); } if (hc->mode_type != EMS_VALUE_UINT_NOTSET) { - print_value(shell, 2, F("Mode Type"), mode_tostring(hc->get_mode_type(flags)).c_str()); + print_value(shell, 4, F("Mode Type"), mode_tostring(hc->get_mode_type(flags)).c_str()); } if ((flags == EMS_DEVICE_FLAG_RC35) || (flags == EMS_DEVICE_FLAG_RC30_1)) { @@ -716,72 +776,19 @@ void Thermostat::show_values(uuid::console::Shell & shell) { shell.printfln(F(" Program is set to Holiday mode")); } - print_value(shell, 2, F("Day temperature"), F_(degrees), Helpers::render_value(buffer, hc->daytemp, 2)); - print_value(shell, 2, F("Night temperature"), F_(degrees), Helpers::render_value(buffer, hc->nighttemp, 2)); - print_value(shell, 2, F("Vacation temperature"), F_(degrees), Helpers::render_value(buffer, hc->holidaytemp, 2)); + print_value(shell, 4, F("Day temperature"), F_(degrees), Helpers::render_value(buffer, hc->daytemp, 2)); + print_value(shell, 4, F("Night temperature"), F_(degrees), Helpers::render_value(buffer, hc->nighttemp, 2)); + print_value(shell, 4, F("Holiday temperature"), F_(degrees), Helpers::render_value(buffer, hc->holidaytemp, 2)); if (hc->offsettemp < 100) { - print_value(shell, 2, F("Offset temperature"), F_(degrees), Helpers::render_value(buffer, hc->offsettemp, 2)); + print_value(shell, 4, F("Offset temperature"), F_(degrees), Helpers::render_value(buffer, hc->offsettemp, 2)); } - print_value(shell, 2, F("Design temperature"), F_(degrees), Helpers::render_value(buffer, hc->designtemp, 2)); + print_value(shell, 4, F("Design temperature"), F_(degrees), Helpers::render_value(buffer, hc->designtemp, 0)); } // show flow temp if we have it if (hc->circuitcalctemp != EMS_VALUE_UINT_NOTSET) { - print_value(shell, 2, F("Calculated flow temperature"), F_(degrees), Helpers::render_value(buffer, hc->circuitcalctemp, 1)); - } - - // settings parameters - if (ibaMainDisplay != EMS_VALUE_UINT_NOTSET) { - if (ibaMainDisplay == 0) { - shell.printfln(F(" Display: internal temperature")); - } else if (ibaMainDisplay == 1) { - shell.printfln(F(" Display: internal setpoint")); - } else if (ibaMainDisplay == 2) { - shell.printfln(F(" Display: external temperature")); - } else if (ibaMainDisplay == 3) { - shell.printfln(F(" Display: burner temperature")); - } else if (ibaMainDisplay == 4) { - shell.printfln(F(" Display: WW temperature")); - } else if (ibaMainDisplay == 5) { - shell.printfln(F(" Display: functioning mode")); - } else if (ibaMainDisplay == 6) { - shell.printfln(F(" Display: time")); - } else if (ibaMainDisplay == 7) { - shell.printfln(F(" Display: date")); - } else if (ibaMainDisplay == 9) { - shell.printfln(F(" Display: smoke temperature")); - } - } - - if (ibaLanguage != EMS_VALUE_UINT_NOTSET) { - if (ibaLanguage == 0) { - shell.printfln(F(" Language: German")); - } else if (ibaLanguage == 1) { - shell.printfln(F(" Language: Dutch")); - } else if (ibaLanguage == 2) { - shell.printfln(F(" Language: French")); - } else if (ibaLanguage == 3) { - shell.printfln(F(" Language: Italian")); - } - } - - if (ibaCalIntTemperature != EMS_VALUE_INT_NOTSET) { - print_value(shell, 2, F("Offset int. temperature"), F_(degrees), Helpers::render_value(buffer, ibaCalIntTemperature, 2)); - } - - if (ibaMinExtTemperature != EMS_VALUE_INT_NOTSET) { - print_value(shell, 2, F("Min ext. temperature"), F_(degrees), Helpers::render_value(buffer, ibaMinExtTemperature, 10)); // min ext temp for heating curve, in deg. - } - - if (ibaBuildingType != EMS_VALUE_UINT_NOTSET) { - if (ibaBuildingType == 0) { - shell.printfln(F(" Building: light")); - } else if (ibaBuildingType == 1) { - shell.printfln(F(" Building: medium")); - } else if (ibaBuildingType == 2) { - shell.printfln(F(" Building: heavy")); - } + print_value(shell, 4, F("Calculated flow temperature"), F_(degrees), Helpers::render_value(buffer, hc->circuitcalctemp, 1)); } } } @@ -859,12 +866,12 @@ void Thermostat::process_EasyMonitor(std::shared_ptr telegram) { // Settings Parameters - 0xA5 - RC30_1 void Thermostat::process_IBASettings(std::shared_ptr telegram) { uint8_t extTemp = 100; // Min. ext temperature is coded as int8, 0xF6=-10, 0x0 = 0, 0xFF=-1. 100 is out of permissible range - + // 22 - display line on RC35 telegram->read_value(ibaMainDisplay, 0); // display on Thermostat: 0 int. temp, 1 int. setpoint, 2 ext. temp., 3 burner temp., 4 ww temp, 5 functioning mode, 6 time, 7 data, 9 smoke temp - telegram->read_value(ibaLanguage, 6); // language on Thermostat: 0 german, 1 dutch, 2 french, 3 italian - telegram->read_value(ibaBuildingType, 2); // building type: 0 = light, 1 = medium, 2 = heavy + telegram->read_value(ibaLanguage, 1); // language on Thermostat: 0 german, 1 dutch, 2 french, 3 italian telegram->read_value(ibaCalIntTemperature, 2); // offset int. temperature sensor, by * 0.1 Kelvin + telegram->read_value(ibaBuildingType, 6); // building type: 0 = light, 1 = medium, 2 = heavy telegram->read_value(extTemp, 5); // min ext temp for heating curve, in deg., 0xF6=-10, 0x0 = 0, 0xFF=-1 if (extTemp != 100) { // code as signed short, to benefit from negative value rendering diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index 25ff8f01a..a8c4142a5 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -52,10 +52,9 @@ void EMSuart::emsuart_recvTask(void * param) { /* * UART interrupt, on break read the fifo and put the whole telegram to ringbuffer */ -static void IRAM_ATTR uart_intr_handle(void * arg) { +void IRAM_ATTR EMSuart::uart_intr_handle(void * arg) { if (EMS_UART.int_st.brk_det) { - uint8_t rx_fifo_len = EMS_UART.status.rxfifo_cnt; - for (rxlen = 0; rxlen < rx_fifo_len; rxlen++) { + for (uint8_t rxlen = 0; EMS_UART.status.rxfifo_cnt > 0; rxlen++) { rxbuf[rxlen] = EMS_UART.fifo.rw_byte; // read all bytes into buffer } if (!drop_first_rx && (rxlen == 2) || ((rxlen > 4) && (rxlen <= EMS_MAXBUFFERSIZE))) { @@ -81,11 +80,9 @@ void EMSuart::start(uint8_t tx_mode) { ESP_ERROR_CHECK(uart_param_config(EMSUART_UART, &uart_config)); ESP_ERROR_CHECK(uart_set_pin(EMSUART_UART, EMSUART_TXPIN, EMSUART_RXPIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); - //EMS_UART.conf1.rxfifo_full_thrhd = 127; // enough to hold the incoming telegram, should never reached - //EMS_UART.idle_conf.tx_brk_num = 12; // breaklength 12 bit - EMS_UART.int_ena.val = 0; // disable all intr. - EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags - buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT); + EMS_UART.int_ena.val = 0; // disable all intr. + EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags + buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT); ESP_ERROR_CHECK(uart_isr_register(EMSUART_UART, uart_intr_handle, NULL, ESP_INTR_FLAG_IRAM, &uart_handle)); xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, 12, NULL); drop_first_rx = true; @@ -116,7 +113,7 @@ void EMSuart::restart() { void EMSuart::send_poll(uint8_t data) { EMS_UART.conf0.txd_brk = 0; // just to make sure the bit is cleared EMS_UART.fifo.rw_byte = data; - EMS_UART.idle_conf.tx_brk_num = 12; // breaklength 12 bit + EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit EMS_UART.conf0.txd_brk = 1; // sending ends in a break } @@ -127,15 +124,12 @@ void EMSuart::send_poll(uint8_t data) { */ EMSUART_STATUS EMSuart::transmit(uint8_t * buf, uint8_t len) { if (len > 0) { - if (EMS_UART.status.txfifo_cnt > 0) { // fifo not empty - return EMS_TX_WTD_TIMEOUT; - } EMS_UART.conf0.txd_brk = 0; // just to make sure the bit is cleared for (uint8_t i = 0; i < len; i++) { EMS_UART.fifo.rw_byte = buf[i]; } //uart_tx_chars(EMSUART_UART, (const char *)buf, len); - EMS_UART.idle_conf.tx_brk_num = 12; // breaklength 12 bit + EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit EMS_UART.conf0.txd_brk = 1; // sending ends in a break } return EMS_TX_STATUS_OK; diff --git a/src/uart/emsuart_esp32.h b/src/uart/emsuart_esp32.h index 59d108c60..dea169d3c 100644 --- a/src/uart/emsuart_esp32.h +++ b/src/uart/emsuart_esp32.h @@ -57,7 +57,8 @@ class EMSuart { static EMSUART_STATUS transmit(uint8_t * buf, uint8_t len); private: - static void emsuart_recvTask(void * param); + static void emsuart_recvTask(void * param); + static void IRAM_ATTR emsuart_rx_intr_handler(void * para); }; } // namespace emsesp diff --git a/src/uart/emsuart_esp8266.cpp b/src/uart/emsuart_esp8266.cpp index 8153aeadc..48ccf716e 100644 --- a/src/uart/emsuart_esp8266.cpp +++ b/src/uart/emsuart_esp8266.cpp @@ -25,35 +25,62 @@ namespace emsesp { os_event_t recvTaskQueue[EMSUART_recvTaskQueueLen]; // our Rx queue + EMSuart::EMSRxBuf_t * pEMSRxBuf; EMSuart::EMSRxBuf_t * paEMSRxBuf[EMS_MAXBUFFERS]; uint8_t emsRxBufIdx = 0; -bool drop_first_rx = true; uint8_t phantomBreak = 0; -uint8_t tx_mode_ = EMS_TXMODE_NEW; +uint8_t tx_mode_ = EMS_TXMODE_DEFAULT; +bool drop_first_rx = true; +// // Main interrupt handler // Important: must not use ICACHE_FLASH_ATTR +// void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { - static uint8_t length = 0; - static uint8_t uart_buffer[128]; + static uint8_t length = 0; +// static bool rx_idle_ = true; + static uint8_t uart_buffer[EMS_MAXBUFFERSIZE + 2]; +/* + // is a new buffer? if so init the thing for a new telegram + if (rx_idle_) { + rx_idle_ = false; // status set to busy + length = 0; + } + // fill IRQ buffer, by emptying Rx FIFO + if (USIS(EMSUART_UART) & ((1 << UIFF) | (1 << UITO) | (1 << UIBD))) { + while ((USS(EMSUART_UART) >> USRXC) & 0xFF) { + uint8_t rx = USF(EMSUART_UART); + if (length < EMS_MAXBUFFERSIZE) + uart_buffer[length++] = rx; + } + + // clear Rx FIFO full and Rx FIFO timeout interrupts + USIC(EMSUART_UART) = (1 << UIFF) | (1 << UITO); + } +*/ // BREAK detection = End of EMS data block if (USIS(EMSUART_UART) & ((1 << UIBD))) { - uint8_t rxlen = (USS(EMSUART_UART) & 0xFF); // length of buffer - for (length = 0; length < rxlen; length++) { - uart_buffer[length] = USF(EMSUART_UART); + length = 0; + while ((USS(EMSUART_UART) >> USRXC) & 0xFF) { + uint8_t rx = USF(EMSUART_UART); + if (length < EMS_MAXBUFFERSIZE) { + uart_buffer[length++] = rx; + } } - USIE(EMSUART_UART) = 0; // disable all interrupts and clear them - USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset from sending - if (!drop_first_rx && (length < EMS_MAXBUFFERSIZE)) { // only a valid telegram + USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear bit + ETS_UART_INTR_DISABLE(); // disable all interrupts and clear them + USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt + if (!drop_first_rx) { pEMSRxBuf->length = length; os_memcpy((void *)pEMSRxBuf->buffer, (void *)&uart_buffer, pEMSRxBuf->length); // copy data into transfer buffer, including the BRK 0x00 at the end - system_os_post(EMSUART_recvTaskPrio, 0, 0); // call emsuart_recvTask() at next opportunity + // rx_idle_ = true; // check set the status flag stating BRK has been received and we can start a new package } drop_first_rx = false; - USIC(EMSUART_UART) |= (1 << UIBD); // INT clear the BREAK detect interrupt - USIE(EMSUART_UART) = (1 << UIBD); // enable only rx break + ETS_UART_INTR_ENABLE(); // re-enable UART interrupts + + system_os_post(EMSUART_recvTaskPrio, 0, 0); // call emsuart_recvTask() at next opportunity } } @@ -79,18 +106,29 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_recvTask(os_event_t * events) { return; } + // ignore double BRK at the end, possibly from the Tx loopback // also telegrams with no data value - // then transmit EMS buffer, excluding the BRK, length is checked by irq - if (length > 4) { + // then transmit EMS buffer, excluding the BRK + if ((length > 4) && (length <= EMS_MAXBUFFERSIZE + 1)) { EMSESP::incoming_telegram((uint8_t *)pCurrent->buffer, length - 1); } } +/* + * flush everything left over in buffer, this clears both rx and tx FIFOs + */ +void ICACHE_FLASH_ATTR EMSuart::emsuart_flush_fifos() { + uint32_t tmp = ((1 << UCRXRST) | (1 << UCTXRST)); // bit mask + USC0(EMSUART_UART) |= (tmp); // set bits + USC0(EMSUART_UART) &= ~(tmp); // clear bits +} + /* * init UART0 driver */ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { tx_mode_ = tx_mode; + // allocate and preset EMS Receive buffers for (int i = 0; i < EMS_MAXBUFFERS; i++) { EMSRxBuf_t * p = (EMSRxBuf_t *)malloc(sizeof(EMSRxBuf_t)); @@ -98,6 +136,9 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { } pEMSRxBuf = paEMSRxBuf[0]; // reset EMS Rx Buffer + ETS_UART_INTR_DISABLE(); + ETS_UART_INTR_ATTACH(nullptr, nullptr); + // pin settings PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); @@ -106,22 +147,45 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { // set 9600, 8 bits, no parity check, 1 stop bit USD(EMSUART_UART) = (UART_CLK_FREQ / EMSUART_BAUD); - USC0(EMSUART_UART) = EMSUART_CONFIG; - // flash fifo buffers, not required since we drop the first telegram - // USC0(EMSUART_UART) |= ((1 << UCRXRST) | (1 << UCTXRST)); // set bits - // USC0(EMSUART_UART) &= ~((1 << UCRXRST) | (1 << UCTXRST)); // clear bits + USC0(EMSUART_UART) = EMSUART_CONFIG; // 8N1 - // we dont use fifo-full interrupt anymore, no need to set this - //USC1(EMSUART_UART) = (0x7F << UCFFT); // rx buffer full - USIE(EMSUART_UART) = 0; // disable all interrupts - USIC(EMSUART_UART) = 0xFFFF; // clear all interupt flags + emsuart_flush_fifos(); + + // conf1 params + // UCTOE = RX TimeOut enable (default is 1) + // UCTOT = RX TimeOut Threshold (7 bit) = want this when no more data after 1 characters (default is 2) + // UCFFT = RX FIFO Full Threshold (7 bit) = want this to be 31 for 32 bytes of buffer (default was 127) + // see https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf + // + // change: we set UCFFT to 1 to get an immediate indicator about incoming traffic. + // Otherwise, we're only noticed by UCTOT or RxBRK! + // change: don't care, we do not use these interrupts + //USC1(EMSUART_UART) = 0; // reset config first + //USC1(EMSUART_UART) = (0x01 << UCFFT) | (0x01 << UCTOT) | (0 << UCTOE); // enable interupts + + // set interrupts for triggers + USIC(EMSUART_UART) = 0xFFFF; // clear all interupts + USIE(EMSUART_UART) = 0; // disable all interrupts + + // enable rx break, fifo full and timeout. + // but not frame error UIFR (because they are too frequent) or overflow UIOF because our buffer is only max 32 bytes + // change: we don't care about Rx Timeout - it may lead to wrong readouts + // change:we don't care about Fifo full and read only on break-detect + USIE(EMSUART_UART) = (1 << UIBD) | (0 << UIFF) | (0 << UITO); + + // set up interrupt callbacks for Rx + system_os_task(emsuart_recvTask, EMSUART_recvTaskPrio, recvTaskQueue, EMSUART_recvTaskQueueLen); + + // disable esp debug which will go to Tx and mess up the line - see https://github.com/espruino/Espruino/issues/655 + system_set_os_print(0); + + // swap Rx and Tx pins to use GPIO13 (D7) and GPIO15 (D8) respectively + system_uart_swap(); - system_set_os_print(0); // disable esp debug which will go to Tx and mess up the line - see https://github.com/espruino/Espruino/issues/655 - system_uart_swap(); // swap Rx and Tx pins to use GPIO13 (D7) and GPIO15 (D8) respectively - system_os_task(emsuart_recvTask, EMSUART_recvTaskPrio, recvTaskQueue, EMSUART_recvTaskQueueLen); // set up interrupt callbacks for Rx ETS_UART_INTR_ATTACH(emsuart_rx_intr_handler, nullptr); - drop_first_rx = true; // drop first telegram since it is incomplete - USIE(EMSUART_UART) = (1 << UIBD); // enable only rx break interrupt + ETS_UART_INTR_ENABLE(); + drop_first_rx = true; + // LOG_INFO(F("UART service for Rx/Tx started")); } /* @@ -129,35 +193,69 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { * This is called prior to an OTA upload and also before a save to the filesystem to prevent conflicts */ void ICACHE_FLASH_ATTR EMSuart::stop() { - USIE(EMSUART_UART) = 0; // disable uart interrupt + ETS_UART_INTR_DISABLE(); } /* * re-start UART0 driver */ void ICACHE_FLASH_ATTR EMSuart::restart() { - if (USIS(EMSUART_UART) & ((1 << UIBD))) { // if we had a break - USIC(EMSUART_UART) |= (1 << UIBD); // clear the BREAK detect flag - drop_first_rx = true; // and drop first frame - } // otherwise there is the beginning of a valid telegram in the fifo - USIE(EMSUART_UART) = (1 << UIBD); // enable rx break interrupt + if (USIS(EMSUART_UART) & ((1 << UIBD))) { + USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt + drop_first_rx = true; + } + ETS_UART_INTR_ENABLE(); } +/* + * Send a BRK signal + * Which is a 11-bit set of zero's (11 cycles) + */ +void ICACHE_FLASH_ATTR EMSuart::tx_brk() { + uint32_t tmp; + + // must make sure Tx FIFO is empty + while (((USS(EMSUART_UART) >> USTXC) & 0xFF)) + ; + + tmp = ((1 << UCRXRST) | (1 << UCTXRST)); // bit mask + USC0(EMSUART_UART) |= (tmp); // set bits + USC0(EMSUART_UART) &= ~(tmp); // clear bits + + // To create a 11-bit we set TXD_BRK bit so the break signal will + // automatically be sent when the tx fifo is empty + tmp = (1 << UCBRK); + USC0(EMSUART_UART) |= (tmp); // set bit + + if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ mode + delayMicroseconds(EMSUART_TX_BRK_WAIT); + } else if (tx_mode_ == EMS_TXMODE_HT3) { // junkers mode + delayMicroseconds(EMSUART_TX_WAIT_BRK - EMSUART_TX_LAG); // 1144 (11 Bits) + } + + USC0(EMSUART_UART) &= ~(tmp); // clear bit +} + +/* + * Sends a 1-byte poll, ending with a + * It's a bit dirty. there is no special wait logic per tx_mode type, fifo flushes or error checking + */ void EMSuart::send_poll(uint8_t data) { if (tx_mode_ == EMS_TXMODE_NEW) { - USC0(EMSUART_UART) &= ~(1 << UCBRK); // in doubt clear bit + USC0(EMSUART_UART) &= ~(1 << UCBRK); // make sure bit is cleared USF(EMSUART_UART) = data; USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end } else { USF(EMSUART_UART) = data; - delayMicroseconds(EMSUART_TX_BRK_WAIT); + delayMicroseconds(EMSUART_TX_BRK_WAIT); tx_brk(); // send - } + } } /* * Send data to Tx line, ending with a * buf contains the CRC and len is #bytes including the CRC + * returns code, 0=success, 1=brk error, 2=watchdog timeout */ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { if (len == 0) { @@ -166,12 +264,9 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { // new code from Michael. See https://github.com/proddy/EMS-ESP/issues/380 if (tx_mode_ == EMS_TXMODE_NEW) { - if ((USS(EMSUART_UART) >> USTXC) & 0xFF) { // buffer not empty - return EMS_TX_WTD_TIMEOUT; - } - USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear bit + USC0(EMSUART_UART) &= ~(1 << UCBRK); // make sure bit is cleared for (uint8_t i = 0; i < len; i++) { - USF(EMSUART_UART) = buf[i]; // fill fifo buffer + USF(EMSUART_UART) = buf[i]; } USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end return EMS_TX_STATUS_OK; @@ -181,7 +276,7 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // With extra tx delay for EMS+ for (uint8_t i = 0; i < len; i++) { USF(EMSUART_UART) = buf[i]; - delayMicroseconds(EMSUART_TX_BRK_WAIT); + delayMicroseconds(EMSUART_TX_BRK_WAIT); // 2070 } tx_brk(); // send return EMS_TX_STATUS_OK; @@ -282,44 +377,6 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { return result; // send the Tx status back } -/* - * flush everything left over in buffer, this clears both rx and tx FIFOs - */ -void ICACHE_FLASH_ATTR EMSuart::emsuart_flush_fifos() { - uint32_t tmp = ((1 << UCRXRST) | (1 << UCTXRST)); // bit mask - USC0(EMSUART_UART) |= (tmp); // set bits - USC0(EMSUART_UART) &= ~(tmp); // clear bits -} - -/* - * Send a BRK signal - * Which is a 11-bit set of zero's (11 cycles) - */ -void ICACHE_FLASH_ATTR EMSuart::tx_brk() { - uint32_t tmp; - - // must make sure Tx FIFO is empty - while (((USS(EMSUART_UART) >> USTXC) & 0xFF)) - ; - - tmp = ((1 << UCRXRST) | (1 << UCTXRST)); // bit mask - USC0(EMSUART_UART) |= (tmp); // set bits - USC0(EMSUART_UART) &= ~(tmp); // clear bits - - // To create a 11-bit we set TXD_BRK bit so the break signal will - // automatically be sent when the tx fifo is empty - tmp = (1 << UCBRK); - USC0(EMSUART_UART) |= (tmp); // set bit - - if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ mode - delayMicroseconds(EMSUART_TX_BRK_WAIT); - } else if (tx_mode_ == EMS_TXMODE_HT3) { // junkers mode - delayMicroseconds(EMSUART_TX_WAIT_BRK - EMSUART_TX_LAG); // 1144 (11 Bits) - } - - USC0(EMSUART_UART) &= ~(tmp); // clear bit -} - } // namespace emsesp #endif diff --git a/src/uart/emsuart_esp8266.h b/src/uart/emsuart_esp8266.h index ae58f3693..810d1bcb1 100644 --- a/src/uart/emsuart_esp8266.h +++ b/src/uart/emsuart_esp8266.h @@ -47,7 +47,7 @@ #define EMSUART_TX_LAG 8 #define EMSUART_BUSY_WAIT (EMSUART_BIT_TIME / 8) #define EMS_TX_TO_CHARS (2 + 20) -#define EMS_TX_TO_COUNT (EMS_TX_TO_CHARS * 8) +#define EMS_TX_TO_COUNT ((EMS_TX_TO_CHARS) * 8) namespace emsesp { From f6854b8ad46d953e8de27381b2418cacf85971ef Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 29 May 2020 18:17:04 +0200 Subject: [PATCH 4/7] esp32 uart timing, RC35 thermostat mqtt enhancement, fix type_id display --- platformio.ini | 6 +- src/emsdevice.cpp | 3 +- src/mixing.cpp | 9 +-- src/thermostat.cpp | 153 ++++++++++++++++++++++++++++++----- src/thermostat.h | 13 ++- src/uart/emsuart_esp32.cpp | 43 +++++----- src/uart/emsuart_esp8266.cpp | 30 +++---- 7 files changed, 185 insertions(+), 72 deletions(-) diff --git a/platformio.ini b/platformio.ini index cc2e10d73..82fdd587e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -2,9 +2,9 @@ ; For EMS-ESP [platformio] -; default_envs = esp8266 +default_envs = esp8266 ; default_envs = esp32 -default_envs = esp32_d1 +; default_envs = esp32_d1 # override any settings with your own local ones in pio_local.ini extra_configs = pio_local.ini @@ -74,7 +74,7 @@ upload_protocol = espota upload_flags = --port=8266 --auth=neo -upload_port = 192.168.0.23 +upload_port = 192.168.0.20 [env:esp8266] build_type = release diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 1a5a27942..1519cc4d8 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -228,7 +228,8 @@ std::string EMSdevice::telegram_type_name(std::shared_ptr telegr } for (const auto & tf : telegram_functions_) { - if ((tf.telegram_type_id_ & 0x7F) == (telegram->type_id & 0x7F)) { +// if ((tf.telegram_type_id_ & 0x7F) == (telegram->type_id & 0x7F)) { + if (tf.telegram_type_id_ == telegram->type_id && (telegram->type_id < 0xF0)) { return uuid::read_flash_string(tf.telegram_type_name_); } } diff --git a/src/mixing.cpp b/src/mixing.cpp index 223ffe330..4589af2fa 100644 --- a/src/mixing.cpp +++ b/src/mixing.cpp @@ -87,8 +87,7 @@ void Mixing::show_values(uuid::console::Shell & shell) { // publish values via MQTT // ideally we should group up all the mixing units together into a nested JSON but for now we'll send them individually void Mixing::publish_values() { - static DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_MEDIUM); -// StaticJsonDocument doc; + DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_SMALL); JsonObject rootMixing = doc.to(); JsonObject dataMixing; @@ -141,13 +140,11 @@ void Mixing::publish_values() { char topic[30]; char s[3]; // for formatting strings strlcpy(topic, "mixing_data", 30); - strlcat(topic, Helpers::itoa(s, hc_), 30); // append hc to topic + strlcat(topic, Helpers::itoa(s, device_id() - 0x20 + 1), 30); // append hc to topic Mqtt::publish(topic, doc); return; } - char topic[30]; - strlcpy(topic, "mixing_data", 30); - Mqtt::publish(topic, doc); + Mqtt::publish("mixing_data", doc); } // heating circuits 0x02D7, 0x02D8 etc... diff --git a/src/thermostat.cpp b/src/thermostat.cpp index 19faf83ae..e69ac5e82 100644 --- a/src/thermostat.cpp +++ b/src/thermostat.cpp @@ -221,6 +221,47 @@ void Thermostat::thermostat_cmd(const char * message) { LOG_DEBUG(F("MQTT error: payload %s, error %s"), message, error.c_str()); return; } + for (const auto & hc : heating_circuits_) { + char hc_name[6], s[3]; // hc{1-4} + strlcpy(hc_name, "hc", 6); + uint8_t hc_num = hc->hc_num(); + strlcat(hc_name, Helpers::itoa(s, hc_num), 6); + if (nullptr != doc[hc_name]["mode"]) { + std::string mode = doc[hc_name]["mode"]; // first check mode + set_mode(mode, hc_num); + } + if (float f = doc[hc_name]["temp"]) { + set_temperature(f, HeatingCircuit::Mode::AUTO, hc_num); + } + if (float f = doc[hc_name]["nighttemp"]) { + set_temperature(f, HeatingCircuit::Mode::NIGHT, hc_num); + } + if (float f = doc[hc_name]["daytemp"]) { + set_temperature(f, HeatingCircuit::Mode::DAY, hc_num); + } + if (float f = doc[hc_name]["nofrosttemp"]) { + set_temperature(f, HeatingCircuit::Mode::NOFROST, hc_num); + } + if (float f = doc[hc_name]["summertemp"]) { + set_temperature(f, HeatingCircuit::Mode::SUMMER, hc_num); + } + if (float f = doc[hc_name]["designtemp"]) { + set_temperature(f, HeatingCircuit::Mode::DESIGN, hc_num); + } + if (float f = doc[hc_name]["offsettemp"]) { + set_temperature(f, HeatingCircuit::Mode::OFFSET, hc_num); + } + if (float f = doc[hc_name]["holidaytemp"]) { // + set_temperature(f, HeatingCircuit::Mode::HOLIDAY, hc_num); + } + if (float f = doc[hc_name]["remotetemp"]) { + if(f > 100 || f < 0) { + hc->remotetemp = EMS_VALUE_SHORT_NOTSET; + } else { + hc->remotetemp = (uint16_t) (f * 10); + } + } + } const char * command = doc["cmd"]; if (command == nullptr) { @@ -301,6 +342,27 @@ void Thermostat::thermostat_cmd(const char * message) { } return; } + if (strcmp(command, "summertemp") == 0) { + float f = doc["data"]; + if (f) { + set_temperature(f, HeatingCircuit::Mode::SUMMER, hc_num); + } + return; + } + if (strcmp(command, "designtemp") == 0) { + float f = doc["data"]; + if (f) { + set_temperature(f, HeatingCircuit::Mode::DESIGN, hc_num); + } + return; + } + if (strcmp(command, "offettemp") == 0) { + float f = doc["data"]; + if (f) { + set_temperature(f, HeatingCircuit::Mode::OFFSET, hc_num); + } + return; + } } void Thermostat::thermostat_cmd_temp(const char * message) { @@ -358,8 +420,8 @@ void Thermostat::publish_values() { JsonObject rootThermostat = doc.to(); JsonObject dataThermostat; - // optional, add external temp. I don't think anyone actually is interested in this - if ((flags == EMS_DEVICE_FLAG_RC35) && ((mqtt_format_ == Settings::MQTT_format::SINGLE) || (mqtt_format_ == Settings::MQTT_format::MY))) { + // optional, add external temp. I don't think anyone (except MichaelDvP) actually is interested in this + if ((flags == EMS_DEVICE_FLAG_RC35 || flags == EMS_DEVICE_FLAG_RC30_1) && (mqtt_format_ == Settings::MQTT_format::SINGLE || mqtt_format_ == Settings::MQTT_format::MY)) { if (datetime_.size()) { rootThermostat["time"] = datetime_.c_str(); } @@ -367,10 +429,32 @@ void Thermostat::publish_values() { rootThermostat["dampedtemp"] = dampedoutdoortemp; } if (tempsensor1 != EMS_VALUE_USHORT_NOTSET) { - rootThermostat["tempsensor1"] = (float)tempsensor1 / 10; + rootThermostat["inttemp1"] = (float)tempsensor1 / 10; } if (tempsensor2 != EMS_VALUE_USHORT_NOTSET) { - rootThermostat["tempsensor2"] = (float)tempsensor2 / 10; + rootThermostat["inttemp2"] = (float)tempsensor2 / 10; + } + + if (ibaCalIntTemperature != EMS_VALUE_INT_NOTSET) { + rootThermostat["intoffset"] = (float)ibaCalIntTemperature / 2; + } + + if (ibaMinExtTemperature != EMS_VALUE_INT_NOTSET) { + rootThermostat["minexttemp"] = (float)ibaMinExtTemperature; // min ext temp for heating curve, in deg. + } + + if (ibaBuildingType != EMS_VALUE_UINT_NOTSET) { + if (ibaBuildingType == 0) { + rootThermostat["building"] = "light"; + } else if (ibaBuildingType == 1) { + rootThermostat["building"] = "medium"; + } else if (ibaBuildingType == 2) { + rootThermostat["building"] = "heavy"; + } + } + if (mqtt_format_ == Settings::MQTT_format::SINGLE) { + Mqtt::publish("thermostat_data", doc); + rootThermostat = doc.to(); // clear object } } @@ -470,14 +554,14 @@ void Thermostat::publish_values() { dataThermostat["modetype"] = mode_tostring(hc->get_mode_type(flags)); } - // if format is single, send immediately and quit + // if format is single, send immediately and clear object for next hc if (mqtt_format_ == Settings::MQTT_format::SINGLE) { char topic[30]; char s[3]; // for formatting strings strlcpy(topic, "thermostat_data", 30); strlcat(topic, Helpers::itoa(s, hc->hc_num()), 30); // append hc to topic Mqtt::publish(topic, doc); - return; + rootThermostat = doc.to(); // clear object } } @@ -652,15 +736,24 @@ std::string Thermostat::mode_tostring(uint8_t mode) const { case HeatingCircuit::Mode::HEAT: return read_flash_string(F("heat")); break; -// case HeatingCircuit::Mode::HOLIDAY: -// return read_flash_string(F("holiday")); -// break; + case HeatingCircuit::Mode::HOLIDAY: + return read_flash_string(F("holiday")); + break; case HeatingCircuit::Mode::NOFROST: return read_flash_string(F("nofrost")); break; case HeatingCircuit::Mode::AUTO: return read_flash_string(F("auto")); break; + case HeatingCircuit::Mode::SUMMER: + return read_flash_string(F("summer")); + break; + case HeatingCircuit::Mode::OFFSET: + return read_flash_string(F("offset")); + break; + case HeatingCircuit::Mode::DESIGN: + return read_flash_string(F("design")); + break; default: case HeatingCircuit::Mode::UNKNOWN: return read_flash_string(F("unknown")); @@ -869,19 +962,14 @@ void Thermostat::process_EasyMonitor(std::shared_ptr telegram) { // Settings Parameters - 0xA5 - RC30_1 void Thermostat::process_IBASettings(std::shared_ptr telegram) { - uint8_t extTemp = 100; // Min. ext temperature is coded as int8, 0xF6=-10, 0x0 = 0, 0xFF=-1. 100 is out of permissible range // 22 - display line on RC35 telegram->read_value(ibaMainDisplay, 0); // display on Thermostat: 0 int. temp, 1 int. setpoint, 2 ext. temp., 3 burner temp., 4 ww temp, 5 functioning mode, 6 time, 7 data, 9 smoke temp telegram->read_value(ibaLanguage, 1); // language on Thermostat: 0 german, 1 dutch, 2 french, 3 italian telegram->read_value(ibaCalIntTemperature, 2); // offset int. temperature sensor, by * 0.1 Kelvin telegram->read_value(ibaBuildingType, 6); // building type: 0 = light, 1 = medium, 2 = heavy - telegram->read_value(extTemp, 5); // min ext temp for heating curve, in deg., 0xF6=-10, 0x0 = 0, 0xFF=-1 - if (extTemp != 100) { - // code as signed short, to benefit from negative value rendering - ibaMinExtTemperature = (int16_t)(extTemp > 127) ? (extTemp - 256) : extTemp; - } - telegram->read_value(ibaClockOffset, 12); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s + telegram->read_value(ibaMinExtTemperature, 5); // min ext temp for heating curve, in deg., 0xF6=-10, 0x0 = 0, 0xFF=-1 + telegram->read_value(ibaClockOffset, 12); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s } // type 0x6F - FR10/FR50/FR100 Junkers @@ -945,7 +1033,7 @@ void Thermostat::process_RC30Set(std::shared_ptr telegram) { // type 0x3E (HC1), 0x48 (HC2), 0x52 (HC3), 0x5C (HC4) - data from the RC35 thermostat (0x10) - 16 bytes void Thermostat::process_RC35Monitor(std::shared_ptr telegram) { // exit if the 15th byte (second from last) is 0x00, which I think is calculated flow setpoint temperature - // with weather controlled RC35s this value can be zero and our setpoint temps will be incorrect + // with weather controlled RC35s this value is >=5, otherwise can be zero and our setpoint temps will be incorrect // see https://github.com/proddy/EMS-ESP/issues/373#issuecomment-627907301 if (telegram->message_data[14] == 0x00) { return; @@ -953,7 +1041,7 @@ void Thermostat::process_RC35Monitor(std::shared_ptr telegram) { std::shared_ptr hc = heating_circuit(telegram); - telegram->read_value8(hc->setpoint_roomTemp, 2); // is * 2, force to single byte + telegram->read_value8(hc->setpoint_roomTemp, 2); // is * 2, force to single byte, is 0 in summermode telegram->read_value(hc->curr_roomTemp, 3); // is * 10 - or 0x7D00 if thermostat is mounted on boiler telegram->read_value(hc->mode_type, 1, 1); telegram->read_value(hc->summer_mode, 1, 0); @@ -975,10 +1063,12 @@ void Thermostat::process_RC35Set(std::shared_ptr telegram) { telegram->read_value(hc->daytemp, 2); // is * 2 telegram->read_value(hc->nighttemp, 1); // is * 2 telegram->read_value(hc->holidaytemp, 3); // is * 2 - telegram->read_value(hc->heatingtype, 0); // byte 0 bit floor heating = 3 + telegram->read_value(hc->heatingtype, 0); // 0- off, 1-radiator, 2-convector, 3-floor - telegram->read_value(hc->designtemp, 17); - telegram->read_value(hc->offsettemp, 6); + telegram->read_value(hc->summertemp, 22); // is * 1 + telegram->read_value(hc->nofrosttemp, 23); // is * 1 + telegram->read_value(hc->designtemp, 17); // is * 1 + telegram->read_value(hc->offsettemp, 6); // is * 2 } // process_RCTime - type 0x06 - date and time from a thermostat - 14 bytes long @@ -1206,10 +1296,29 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co case HeatingCircuit::Mode::HOLIDAY: // change the holiday temp offset = EMS_OFFSET_RC35Set_temp_holiday; break; + case HeatingCircuit::Mode::OFFSET: // change the offset temp + offset = EMS_OFFSET_RC35Set_temp_offset; + break; + case HeatingCircuit::Mode::DESIGN: + offset = EMS_OFFSET_RC35Set_temp_design; + break; + case HeatingCircuit::Mode::SUMMER: + offset = EMS_OFFSET_RC35Set_temp_summer; + break; + case HeatingCircuit::Mode::NOFROST: + offset = EMS_OFFSET_RC35Set_temp_nofrost; + break; default: case HeatingCircuit::Mode::AUTO: // automatic selection, if no type is defined, we use the standard code if (model == EMS_DEVICE_FLAG_RC35) { - offset = EMS_OFFSET_RC35Set_seltemp; // https://github.com/proddy/EMS-ESP/issues/310 + uint8_t mode_ = hc->get_mode(flags()); + if (mode_ == HeatingCircuit::Mode::NIGHT) { + offset = EMS_OFFSET_RC35Set_temp_night; + } else if (mode_ == HeatingCircuit::Mode::DAY) { + offset = EMS_OFFSET_RC35Set_temp_day; + } else { + offset = EMS_OFFSET_RC35Set_seltemp; // https://github.com/proddy/EMS-ESP/issues/310 + } } else { uint8_t mode_type = hc->get_mode_type(flags()); offset = (mode_type == HeatingCircuit::Mode::NIGHT) ? EMS_OFFSET_RC35Set_temp_night : EMS_OFFSET_RC35Set_temp_day; diff --git a/src/thermostat.h b/src/thermostat.h index 9ad8c17ab..c22c2cd0f 100644 --- a/src/thermostat.h +++ b/src/thermostat.h @@ -57,9 +57,12 @@ class Thermostat : public EMSdevice { uint8_t holidaytemp = EMS_VALUE_UINT_NOTSET; uint8_t heatingtype = EMS_VALUE_UINT_NOTSET; // type of heating: 1 radiator, 2 convectors, 3 floors, 4 room supply uint8_t circuitcalctemp = EMS_VALUE_UINT_NOTSET; + uint8_t summertemp = EMS_VALUE_UINT_NOTSET; + uint8_t nofrosttemp = EMS_VALUE_UINT_NOTSET; + uint8_t designtemp = EMS_VALUE_UINT_NOTSET; // heatingcurve design temp at MinExtTemp + uint8_t offsettemp = 100; // heatingcurve offest temp at roomtemp signed! + uint16_t remotetemp = EMS_VALUE_SHORT_NOTSET; // for simulating a RC20 remote - uint8_t designtemp = EMS_VALUE_UINT_NOTSET; // heatingcurve design temp at MinExtTemp - uint8_t offsettemp = 100; // heatingcurve offest temp at roomtemp signed! uint8_t hc_num() const { return hc_num_; @@ -76,7 +79,7 @@ class Thermostat : public EMSdevice { return set_typeid_; } - enum Mode : uint8_t { UNKNOWN, OFF, MANUAL, AUTO, DAY, NIGHT, HEAT, NOFROST, ECO, HOLIDAY, COMFORT, OFFSET, DESIGN }; + enum Mode : uint8_t { UNKNOWN, OFF, MANUAL, AUTO, DAY, NIGHT, HEAT, NOFROST, ECO, HOLIDAY, COMFORT, OFFSET, DESIGN, SUMMER }; private: uint8_t hc_num_; @@ -159,6 +162,10 @@ class Thermostat : public EMSdevice { static constexpr uint8_t EMS_OFFSET_RC35Set_heatingtype = 0; // e.g. floor heating = 3 static constexpr uint8_t EMS_OFFSET_RC35Set_circuitcalctemp = 14; // calculated circuit temperature static constexpr uint8_t EMS_OFFSET_RC35Set_seltemp = 37; // selected temp + static constexpr uint8_t EMS_OFFSET_RC35Set_temp_offset = 6; + static constexpr uint8_t EMS_OFFSET_RC35Set_temp_design = 17; + static constexpr uint8_t EMS_OFFSET_RC35Set_temp_summer = 22; + static constexpr uint8_t EMS_OFFSET_RC35Set_temp_nofrost = 23; static constexpr uint8_t EMS_OFFSET_EasyStatusMessage_setpoint = 10; // setpoint temp static constexpr uint8_t EMS_OFFSET_EasyStatusMessage_curr = 8; // current temp diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index 06d502113..3d993eb26 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -29,9 +29,9 @@ namespace emsesp { static intr_handle_t uart_handle; -static RingbufHandle_t buf_handle = NULL; -static bool drop_first_rx = true; -static uint8_t tx_mode_ = 0xFF; +static RingbufHandle_t buf_handle = NULL; +static bool drop_next_rx = true; +static uint8_t tx_mode_ = 0xFF; /* * Task to handle the incoming data @@ -57,19 +57,20 @@ void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { if (EMS_UART.int_st.brk_det) { EMS_UART.int_clr.brk_det = 1; // clear flag - EMS_UART.conf0.txd_brk = 0; // if it was break from sending, clear bit length = 0; while (EMS_UART.status.rxfifo_cnt) { - uint8_t rx = EMS_UART.fifo.rw_byte; // read all bytes into buffer + uint8_t rx = EMS_UART.fifo.rw_byte; // read all bytes from fifo if (length < EMS_MAXBUFFERSIZE) { rxbuf[length++] = rx; + } else { + drop_next_rx = true; // we have a overflow } } - if ((!drop_first_rx) && ((length == 2) || ((length > 4)))) { + if ((!drop_next_rx) && ((length == 2) || (length > 4))) { int baseType = 0; xRingbufferSendFromISR(buf_handle, rxbuf, length - 1, &baseType); } - drop_first_rx = false; + drop_next_rx = false; } } /* @@ -91,14 +92,15 @@ void EMSuart::start(uint8_t tx_mode) { ESP_ERROR_CHECK(uart_param_config(EMSUART_UART, &uart_config)); ESP_ERROR_CHECK(uart_set_pin(EMSUART_UART, EMSUART_TXPIN, EMSUART_RXPIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); - EMS_UART.int_ena.val = 0; // disable all intr. - EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags - EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit - drop_first_rx = true; - buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT); + EMS_UART.int_ena.val = 0; // disable all intr. + EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags + EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit + EMS_UART.idle_conf.rx_idle_thrhd = 256; + drop_next_rx = true; + buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT); ESP_ERROR_CHECK(uart_isr_register(EMSUART_UART, emsuart_rx_intr_handler, NULL, ESP_INTR_FLAG_IRAM, &uart_handle)); xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, 12, NULL); - EMS_UART.int_ena.brk_det = 1; // activate only break + EMS_UART.int_ena.brk_det = 1; // activate only break } /* @@ -114,19 +116,17 @@ void EMSuart::stop() { void EMSuart::restart() { if (EMS_UART.int_raw.brk_det) { EMS_UART.int_clr.brk_det = 1; // clear flag - drop_first_rx = true; // and drop first frame + drop_next_rx = true; // and drop first frame } - EMS_UART.int_ena.brk_det = 1; // activate only break + EMS_UART.int_ena.brk_det = 1; // activate only break }; /* * Sends a 1-byte poll, ending with a */ void EMSuart::send_poll(uint8_t data) { - EMS_UART.conf0.txd_brk = 0; // just to make sure the bit is cleared - EMS_UART.fifo.rw_byte = data; - //EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit - EMS_UART.conf0.txd_brk = 1; // sending ends in a break + EMS_UART.fifo.rw_byte = data; + EMS_UART.conf0.txd_brk = 1; // after send } /* @@ -136,13 +136,10 @@ void EMSuart::send_poll(uint8_t data) { */ EMSUART_STATUS EMSuart::transmit(uint8_t * buf, uint8_t len) { if (len > 0) { - EMS_UART.conf0.txd_brk = 0; // just to make sure the bit is cleared for (uint8_t i = 0; i < len; i++) { EMS_UART.fifo.rw_byte = buf[i]; } - //uart_tx_chars(EMSUART_UART, (const char *)buf, len); - //EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit - EMS_UART.conf0.txd_brk = 1; // sending ends in a break + EMS_UART.conf0.txd_brk = 1; // after send } return EMS_TX_STATUS_OK; } diff --git a/src/uart/emsuart_esp8266.cpp b/src/uart/emsuart_esp8266.cpp index 5299d354d..f1fc623c7 100644 --- a/src/uart/emsuart_esp8266.cpp +++ b/src/uart/emsuart_esp8266.cpp @@ -28,10 +28,10 @@ os_event_t recvTaskQueue[EMSUART_recvTaskQueueLen]; // our Rx queue EMSuart::EMSRxBuf_t * pEMSRxBuf; EMSuart::EMSRxBuf_t * paEMSRxBuf[EMS_MAXBUFFERS]; -uint8_t emsRxBufIdx = 0; -uint8_t phantomBreak = 0; -uint8_t tx_mode_ = 0xFF; -bool drop_first_rx = true; +uint8_t emsRxBufIdx = 0; +uint8_t phantomBreak = 0; +uint8_t tx_mode_ = 0xFF; +bool drop_next_rx = true; // // Main interrupt handler @@ -67,17 +67,19 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { uint8_t rx = USF(EMSUART_UART); if (length < EMS_MAXBUFFERSIZE) { uart_buffer[length++] = rx; + } else { + drop_next_rx = true; } } - USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear bit - ETS_UART_INTR_DISABLE(); // disable all interrupts and clear them + ETS_UART_INTR_DISABLE(); // disable all interrupts and clear them USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt - if (!drop_first_rx) { + USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk + if (!drop_next_rx) { pEMSRxBuf->length = length; os_memcpy((void *)pEMSRxBuf->buffer, (void *)&uart_buffer, pEMSRxBuf->length); // copy data into transfer buffer, including the BRK 0x00 at the end // rx_idle_ = true; // check set the status flag stating BRK has been received and we can start a new package } - drop_first_rx = false; + drop_next_rx = false; ETS_UART_INTR_ENABLE(); // re-enable UART interrupts system_os_post(EMSUART_recvTaskPrio, 0, 0); // call emsuart_recvTask() at next opportunity @@ -109,7 +111,7 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_recvTask(os_event_t * events) { // ignore double BRK at the end, possibly from the Tx loopback // also telegrams with no data value // then transmit EMS buffer, excluding the BRK - if ((length > 4) && (length <= EMS_MAXBUFFERSIZE + 1)) { + if (length > 4) { EMSESP::incoming_telegram((uint8_t *)pCurrent->buffer, length - 1); } } @@ -188,7 +190,7 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { ETS_UART_INTR_ATTACH(emsuart_rx_intr_handler, nullptr); ETS_UART_INTR_ENABLE(); - drop_first_rx = true; + drop_next_rx = true; // LOG_INFO(F("UART service for Rx/Tx started")); } @@ -204,9 +206,9 @@ void ICACHE_FLASH_ATTR EMSuart::stop() { * re-start UART0 driver */ void ICACHE_FLASH_ATTR EMSuart::restart() { - if (USIS(EMSUART_UART) & ((1 << UIBD))) { + if (USIR(EMSUART_UART) & ((1 << UIBD))) { USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt - drop_first_rx = true; + drop_next_rx = true; } ETS_UART_INTR_ENABLE(); // emsuart_flush_fifos(); @@ -247,7 +249,7 @@ void ICACHE_FLASH_ATTR EMSuart::tx_brk() { */ void EMSuart::send_poll(uint8_t data) { if (tx_mode_ == EMS_TXMODE_NEW) { - USC0(EMSUART_UART) &= ~(1 << UCBRK); // make sure bit is cleared + USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk USF(EMSUART_UART) = data; USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end } else { @@ -269,7 +271,7 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { // new code from Michael. See https://github.com/proddy/EMS-ESP/issues/380 if (tx_mode_ == EMS_TXMODE_NEW) { - USC0(EMSUART_UART) &= ~(1 << UCBRK); // make sure bit is cleared + USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk for (uint8_t i = 0; i < len; i++) { USF(EMSUART_UART) = buf[i]; } From ba08fb65ef218ea44fa22c7638422d4f84acc66d Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Mon, 1 Jun 2020 14:12:29 +0200 Subject: [PATCH 5/7] Typos, version string --- src/console.cpp | 4 +++- src/emsdevice.cpp | 2 +- src/emsesp.cpp | 10 +++++----- src/helpers.cpp | 2 ++ src/mqtt.cpp | 2 +- src/sensors.cpp | 2 +- src/thermostat.cpp | 4 ++-- src/uart/emsuart_esp32.cpp | 2 +- 8 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/console.cpp b/src/console.cpp index 5d6c68b59..c0c61053f 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -235,7 +235,7 @@ void Console::load_standard_commands(unsigned int context) { } // trace logic - if (level == uuid::log::Level::TRACE) { + if (level == uuid::log::Level::TRACE || level == uuid::log::Level::DEBUG) { watch_id = LOG_TRACE_WATCH_NONE; // no watch ID set if (arguments.size() > 1) { // next argument is raw or full @@ -243,6 +243,8 @@ void Console::load_standard_commands(unsigned int context) { emsesp::EMSESP::trace_raw(true); } else if (arguments[1] == read_flash_string(F_(full))) { emsesp::EMSESP::trace_raw(false); + } else { + emsesp::EMSESP::trace_watch_id(Helpers::hextoint(arguments[1].c_str())); } // get the watch_id if its set diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 567b12c4f..1db79d3d2 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -228,7 +228,7 @@ std::string EMSdevice::telegram_type_name(std::shared_ptr telegr } for (const auto & tf : telegram_functions_) { - if (tf.telegram_type_id_ == (telegram->type_id && ((telegram->type_id & 0xF0) != 0xF0))) { + if ((tf.telegram_type_id_ == telegram->type_id) && ((telegram->type_id & 0x0F0) != 0xF0)) { return uuid::read_flash_string(tf.telegram_type_name_); } } diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 851b3626c..ce89b6c45 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -247,6 +247,7 @@ std::string EMSESP::pretty_telegram(std::shared_ptr telegram) { // get the type name, any match will do if (type_name.empty()) { type_name = emsdevice->telegram_type_name(telegram); + } } } @@ -362,14 +363,12 @@ void EMSESP::process_version(std::shared_ptr telegram) { uint8_t product_id = telegram->message_data[offset]; // product ID // get version as XX.XX - char buf[6] = {0}, - buf1[6] = {0}; std::string version(5, '\0'); snprintf_P(&version[0], version.capacity() + 1, - PSTR("%s.%s"), - Helpers::smallitoa(buf, telegram->message_data[offset + 1]), - Helpers::smallitoa(buf1, telegram->message_data[offset + 2])); + PSTR("%02d.%02d"), + telegram->message_data[offset + 1], + telegram->message_data[offset + 2]); // some devices store the protocol type (HT3, Buderus) in the last byte uint8_t brand; @@ -569,6 +568,7 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { //LOG_TRACE(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str()); uint8_t first_value = data[0]; if (((first_value & 0x7F) == txservice_.ems_bus_id()) && (length > 1)) { + rxservice_.add(data, length); // just for logging return; // it's an echo } diff --git a/src/helpers.cpp b/src/helpers.cpp index 4a0380358..2350f53e1 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -279,6 +279,8 @@ uint32_t Helpers::hextoint(const char * hex) { byte = byte - 'a' + 10; else if (byte >= 'A' && byte <= 'F') byte = byte - 'A' + 10; + else + return 0; // error // shift 4 to make space for new digit, and add the 4 bits of the new digit val = (val << 4) | (byte & 0xF); } diff --git a/src/mqtt.cpp b/src/mqtt.cpp index a082903de..e14acc1b8 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -726,7 +726,7 @@ void Mqtt::console_commands(Shell & shell, unsigned int context) { } reconnect(); }); - + EMSESPShell::commands->add_command(ShellContext::MQTT, CommandFlags::ADMIN, flash_string_vector{F_(set), F_(port)}, diff --git a/src/sensors.cpp b/src/sensors.cpp index 7c502e482..554c005d5 100644 --- a/src/sensors.cpp +++ b/src/sensors.cpp @@ -277,7 +277,7 @@ void Sensors::publish_values() { if (mqtt_format_ == Settings::MQTT_format::CUSTOM) { char s[5]; doc[device.to_string()] = Helpers::render_value(s, device.temperature_c_, 2); - } else { + } else { char sensorID[10]; // sensor{1-n} strlcpy(sensorID, "sensor", 10); char s[5]; diff --git a/src/thermostat.cpp b/src/thermostat.cpp index bb57ff86d..faa76608c 100644 --- a/src/thermostat.cpp +++ b/src/thermostat.cpp @@ -470,8 +470,8 @@ void Thermostat::publish_values() { // go through all the heating circuits for (const auto & hc : heating_circuits_) { // if ((hc->setpoint_roomTemp == EMS_VALUE_SHORT_NOTSET) || (hc->curr_roomTemp == EMS_VALUE_SHORT_NOTSET)) { - if (hc->heatingtype == 0) { - break; // skip this HC + if (hc->setpoint_roomTemp == EMS_VALUE_SHORT_NOTSET) { + break; // skip this HC } has_data = true; diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index 9d939c0f2..c45d79362 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -63,7 +63,7 @@ void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { if (length < EMS_MAXBUFFERSIZE) { rxbuf[length++] = rx; } else { - drop_next_rx = true; // we have a overflow + drop_next_rx = true; // we have a overflow } } if ((!drop_next_rx) && ((length == 2) || (length > 4))) { From 3300f1e757a657655bbc5dc9a632719cfd2d15fc Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Tue, 2 Jun 2020 14:01:35 +0200 Subject: [PATCH 6/7] esp8266 uart with irq disabled --- platformio.ini | 2 +- src/sensors.h | 4 +++ src/system.h | 7 +++-- src/uart/emsuart_esp32.cpp | 4 +-- src/uart/emsuart_esp32.h | 5 ++++ src/uart/emsuart_esp8266.cpp | 57 ++++++++++++++++-------------------- 6 files changed, 42 insertions(+), 37 deletions(-) diff --git a/platformio.ini b/platformio.ini index 82fdd587e..204efcd28 100644 --- a/platformio.ini +++ b/platformio.ini @@ -100,4 +100,4 @@ build_type = release platform = espressif32 board = wemos_d1_mini32 lib_deps = ${common.libs_core} ${common.libs_esp32} -build_flags = ${common.build_flags} ${common.debug_flags} -D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH +build_flags = ${common.build_flags} ${common.debug_flags} -D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH -D WEMOS_D1_32 diff --git a/src/sensors.h b/src/sensors.h index 9c66eedd7..f4bf76d91 100644 --- a/src/sensors.h +++ b/src/sensors.h @@ -66,7 +66,11 @@ class Sensors { #if defined(ESP8266) static constexpr uint8_t SENSOR_GPIO = 14; // D5 #elif defined(ESP32) +#ifdef WEMOS_D1_32 static constexpr uint8_t SENSOR_GPIO = 18; // Wemos D1-32 for compatibility D5 +#else + static constexpr uint8_t SENSOR_GPIO = 14; +#endif #endif enum class State { IDLE, READING, SCANNING }; diff --git a/src/system.h b/src/system.h index 01ac50afe..06fd5c32f 100644 --- a/src/system.h +++ b/src/system.h @@ -83,10 +83,13 @@ class System { static constexpr uint8_t LED_GPIO = 2; static constexpr uint8_t LED_ON = LOW; #elif defined(ESP32) -// static constexpr uint8_t LED_GPIO = 5; // on Wemos D32 -// static constexpr uint8_t LED_ON = LOW; +#ifdef WEMOS_D1_32 static constexpr uint8_t LED_GPIO = 2; // on Wemos D1-32 static constexpr uint8_t LED_ON = HIGH; +#else + static constexpr uint8_t LED_GPIO = 5; + static constexpr uint8_t LED_ON = LOW; +#endif #else static constexpr uint8_t LED_GPIO = 0; static constexpr uint8_t LED_ON = 0; diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index c45d79362..13461ca0b 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -126,7 +126,7 @@ void EMSuart::restart() { */ void EMSuart::send_poll(uint8_t data) { EMS_UART.fifo.rw_byte = data; - EMS_UART.conf0.txd_brk = 1; // after send + EMS_UART.conf0.txd_brk = 1; // after send } /* @@ -139,7 +139,7 @@ EMSUART_STATUS EMSuart::transmit(uint8_t * buf, uint8_t len) { for (uint8_t i = 0; i < len; i++) { EMS_UART.fifo.rw_byte = buf[i]; } - EMS_UART.conf0.txd_brk = 1; // after send + EMS_UART.conf0.txd_brk = 1; // after send } return EMS_TX_STATUS_OK; } diff --git a/src/uart/emsuart_esp32.h b/src/uart/emsuart_esp32.h index f627a6d33..5a3a18189 100644 --- a/src/uart/emsuart_esp32.h +++ b/src/uart/emsuart_esp32.h @@ -39,8 +39,13 @@ #define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit // customize the GPIO pins for RX and TX here +#ifdef WEMOS_D1_32 #define EMSUART_RXPIN 23 // 17 is UART2 RX. Use 23 for D7 on a Wemos D1-32 mini for backwards compatabilty #define EMSUART_TXPIN 5 // 16 is UART2 TX. Use 5 for D8 on a Wemos D1-32 mini for backwards compatabilty +#else +#define EMSUART_RXPIN 17 // 17 is UART2 RX. Use 23 for D7 on a Wemos D1-32 mini for backwards compatabilty +#define EMSUART_TXPIN 16 // 16 is UART2 TX. Use 5 for D8 on a Wemos D1-32 mini for backwards compatabilty +#endif namespace emsesp { diff --git a/src/uart/emsuart_esp8266.cpp b/src/uart/emsuart_esp8266.cpp index f9de8613e..eb27cef33 100644 --- a/src/uart/emsuart_esp8266.cpp +++ b/src/uart/emsuart_esp8266.cpp @@ -32,38 +32,21 @@ uint8_t emsRxBufIdx = 0; uint8_t phantomBreak = 0; uint8_t tx_mode_ = 0xFF; bool drop_next_rx = true; +uint32_t emsRxTime; + +#define EMS_RX_TO_TX_TIMEOUT 20 // // Main interrupt handler // Important: must not use ICACHE_FLASH_ATTR // void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { -// static bool rx_idle_ = true; static uint8_t length = 0; static uint8_t uart_buffer[EMS_MAXBUFFERSIZE + 2]; -/* - // is a new buffer? if so init the thing for a new telegram - if (rx_idle_) { - rx_idle_ = false; // status set to busy - length = 0; - } - // fill IRQ buffer, by emptying Rx FIFO - if (USIS(EMSUART_UART) & ((1 << UIFF) | (1 << UITO) | (1 << UIBD))) { - while ((USS(EMSUART_UART) >> USRXC) & 0xFF) { - uint8_t rx = USF(EMSUART_UART); - if (length < EMS_MAXBUFFERSIZE) - uart_buffer[length++] = rx; - } - - // clear Rx FIFO full and Rx FIFO timeout interrupts - USIC(EMSUART_UART) = (1 << UIFF) | (1 << UITO); - } -*/ - // BREAK detection = End of EMS data block - if (USIS(EMSUART_UART) & ((1 << UIBD))) { + if (USIS(EMSUART_UART) & ((1 << UIBD))) { // BREAK detection = End of EMS data block length = 0; - while ((USS(EMSUART_UART) >> USRXC) & 0xFF) { + while ((USS(EMSUART_UART) >> USRXC) & 0xFF) { // read fifo into buffer uint8_t rx = USF(EMSUART_UART); if (length < EMS_MAXBUFFERSIZE) { uart_buffer[length++] = rx; @@ -71,17 +54,14 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { drop_next_rx = true; } } - ETS_UART_INTR_DISABLE(); // disable all interrupts and clear them USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk if (!drop_next_rx) { pEMSRxBuf->length = length; os_memcpy((void *)pEMSRxBuf->buffer, (void *)&uart_buffer, pEMSRxBuf->length); // copy data into transfer buffer, including the BRK 0x00 at the end - // rx_idle_ = true; // check set the status flag stating BRK has been received and we can start a new package + emsRxTime = millis(); } drop_next_rx = false; - ETS_UART_INTR_ENABLE(); // re-enable UART interrupts - system_os_post(EMSUART_recvTaskPrio, 0, 0); // call emsuart_recvTask() at next opportunity } } @@ -211,7 +191,6 @@ void ICACHE_FLASH_ATTR EMSuart::restart() { drop_next_rx = true; } ETS_UART_INTR_ENABLE(); - // emsuart_flush_fifos(); } /* @@ -248,6 +227,7 @@ void ICACHE_FLASH_ATTR EMSuart::tx_brk() { * It's a bit dirty. there is no special wait logic per tx_mode type, fifo flushes or error checking */ void EMSuart::send_poll(uint8_t data) { + noInterrupts(); if (tx_mode_ == EMS_TXMODE_NEW) { USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk USF(EMSUART_UART) = data; @@ -257,6 +237,7 @@ void EMSuart::send_poll(uint8_t data) { delayMicroseconds(EMSUART_TX_BRK_WAIT); tx_brk(); // send } + interrupts(); } /* @@ -268,29 +249,37 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { if (len == 0) { return EMS_TX_STATUS_OK; // nothing to send } + if(millis() > (emsRxTime + EMS_RX_TO_TX_TIMEOUT)) { // send allowed within 20 ms + return EMS_TX_WTD_TIMEOUT; + } // new code from Michael. See https://github.com/proddy/EMS-ESP/issues/380 if (tx_mode_ == EMS_TXMODE_NEW) { USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk + noInterrupts(); for (uint8_t i = 0; i < len; i++) { USF(EMSUART_UART) = buf[i]; } USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end + interrupts(); return EMS_TX_STATUS_OK; } // EMS+ https://github.com/proddy/EMS-ESP/issues/23# if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // With extra tx delay for EMS+ + noInterrupts(); for (uint8_t i = 0; i < len; i++) { USF(EMSUART_UART) = buf[i]; delayMicroseconds(EMSUART_TX_BRK_WAIT); // 2070 } tx_brk(); // send + interrupts(); return EMS_TX_STATUS_OK; } // Junkers logic by @philrich if (tx_mode_ == EMS_TXMODE_HT3) { + noInterrupts(); for (uint8_t i = 0; i < len; i++) { USF(EMSUART_UART) = buf[i]; @@ -302,6 +291,7 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { delayMicroseconds(EMSUART_TX_WAIT_BYTE - EMSUART_TX_LAG + EMSUART_TX_WAIT_GAP); // 1760 } tx_brk(); // send + interrupts(); return EMS_TX_STATUS_OK; } @@ -334,8 +324,8 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { // disable rx interrupt // clear Rx status register, resetting the Rx FIFO and flush it - ETS_UART_INTR_DISABLE(); - USC0(EMSUART_UART) |= (1 << UCRXRST); + noInterrupts(); + //ETS_UART_INTR_DISABLE(); emsuart_flush_fifos(); // send the bytes along the serial line @@ -347,12 +337,14 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { while (((USS(EMSUART_UART) >> USRXC) & 0xFF) == _usrxc) { delayMicroseconds(EMSUART_BUSY_WAIT); // burn CPU cycles... if (--wdc == 0) { - ETS_UART_INTR_ENABLE(); + interrupts(); + //ETS_UART_INTR_ENABLE(); return EMS_TX_WTD_TIMEOUT; } if (USIR(EMSUART_UART) & (1 << UIBD)) { USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ - ETS_UART_INTR_ENABLE(); + interrupts(); + //ETS_UART_INTR_ENABLE(); return EMS_TX_BRK_DETECT; } } @@ -379,7 +371,8 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { } } - ETS_UART_INTR_ENABLE(); // open up the FIFO again to start receiving + interrupts(); + //ETS_UART_INTR_ENABLE(); // open up the FIFO again to start receiving return result; // send the Tx status back } From 4247633850e6d7b493b07c8c8f0a1c01ce9e9660 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Tue, 2 Jun 2020 15:14:51 +0200 Subject: [PATCH 7/7] don't wait in rx loop --- platformio.ini | 4 +++- src/telegram.cpp | 8 ++++---- src/uart/emsuart_esp32.cpp | 7 +++++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/platformio.ini b/platformio.ini index 204efcd28..f94869833 100644 --- a/platformio.ini +++ b/platformio.ini @@ -74,7 +74,7 @@ upload_protocol = espota upload_flags = --port=8266 --auth=neo -upload_port = 192.168.0.20 +;upload_port = 192.168.0.20 [env:esp8266] build_type = release @@ -87,6 +87,7 @@ board_build.f_cpu = 160000000L ; 160MHz board_build.ldscript = eagle.flash.4m1m.ld ; 1019 KB sketch, 1000 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 2052 KB OTA & buffer ; board_build.ldscript = eagle.flash.4m2m.ld ; 1019 KB sketch, 2024 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 1028 KB OTA & buffer build_flags = ${common.build_flags} ${common.debug_flags} -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY +upload_port = 192.168.0.20 [env:esp32] build_type = release @@ -101,3 +102,4 @@ platform = espressif32 board = wemos_d1_mini32 lib_deps = ${common.libs_core} ${common.libs_esp32} build_flags = ${common.build_flags} ${common.debug_flags} -D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH -D WEMOS_D1_32 +upload_port = 192.168.0.23 diff --git a/src/telegram.cpp b/src/telegram.cpp index 8fd6bf852..07026b4b8 100644 --- a/src/telegram.cpp +++ b/src/telegram.cpp @@ -222,10 +222,10 @@ void RxService::start() { void RxService::loop() { #ifndef EMSESP_STANDALONE // give rx some breathing space - if ((uuid::get_uptime() - last_rx_check_) < RX_LOOP_WAIT) { - return; - } - last_rx_check_ = uuid::get_uptime(); + //if ((uuid::get_uptime() - last_rx_check_) < RX_LOOP_WAIT) { + // return; + //} + //last_rx_check_ = uuid::get_uptime(); #endif while (!rx_telegrams_.empty()) { diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index 13461ca0b..b56b97e30 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -32,6 +32,9 @@ static intr_handle_t uart_handle; static RingbufHandle_t buf_handle = NULL; static bool drop_next_rx = true; static uint8_t tx_mode_ = 0xFF; +static uint32_t emsRxTime; + +#define EMS_RX_TO_TX_TIMEOUT 20 /* * Task to handle the incoming data @@ -69,6 +72,7 @@ void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { if ((!drop_next_rx) && ((length == 2) || (length > 4))) { int baseType = 0; xRingbufferSendFromISR(buf_handle, rxbuf, length - 1, &baseType); + emsRxTime = millis(); } drop_next_rx = false; } @@ -135,6 +139,9 @@ void EMSuart::send_poll(uint8_t data) { * returns code, 1=success */ EMSUART_STATUS EMSuart::transmit(uint8_t * buf, uint8_t len) { + if (millis() -emsRxTime > EMS_RX_TO_TX_TIMEOUT) { + return EMS_TX_WTD_TIMEOUT; + } if (len > 0) { for (uint8_t i = 0; i < len; i++) { EMS_UART.fifo.rw_byte = buf[i];