diff --git a/src/telegram.cpp b/src/telegram.cpp index a393093bc..d5da2ad11 100644 --- a/src/telegram.cpp +++ b/src/telegram.cpp @@ -461,25 +461,19 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) { length++; // add one since we want to now include the CRC - LOG_DEBUG(F("Sending %s Tx [#%d], telegram: %s"), - (telegram->operation == Telegram::Operation::TX_WRITE) ? F("write") : F("read"), - tx_telegram.id_, - telegram->to_string(telegram_raw, length).c_str()); - // send the telegram to the UART Tx uint16_t status = EMSuart::transmit(telegram_raw, length); -#ifdef EMSESP_DEBUG - // if watching in 'raw' mode - if (EMSESP::watch() == 2) { - LOG_INFO(F("[DEBUG] Tx: %s"), Helpers::data_to_hex(telegram_raw, length).c_str()); - } -#endif if (status == EMS_TX_STATUS_ERR) { LOG_ERROR(F("Failed to transmit Tx via UART.")); increment_telegram_fail_count(); // another Tx fail tx_waiting(false); // nothing send, tx not in wait state return; +// } else { +// LOG_DEBUG(F("Send %s Tx [#%d], telegram: %s"), +// (telegram->operation == Telegram::Operation::TX_WRITE) ? F("write") : F("read"), +// tx_telegram.id_, +// telegram->to_string(telegram_raw, length).c_str()); } tx_waiting(true); // tx now in a wait state @@ -496,17 +490,17 @@ void TxService::send_telegram(const uint8_t * data, const uint8_t length) { } telegram_raw[length] = calculate_crc(telegram_raw, length); // apppend CRC - LOG_DEBUG(F("Sending Raw telegram: %s (length=%d)"), Helpers::data_to_hex(telegram_raw, length).c_str(), length); - tx_waiting(false); // no post validation // send the telegram to the UART Tx uint16_t status = EMSuart::transmit(telegram_raw, length); - //LOG_DEBUG(F("Tx: %s"), Helpers::data_to_hex(telegram_raw, length).c_str()); + if (status == EMS_TX_STATUS_ERR) { LOG_ERROR(F("Failed to transmit Tx via UART.")); increment_telegram_fail_count(); // another Tx fail +// } else { +// LOG_DEBUG(F("Send Raw telegram: %s (length=%d)"), Helpers::data_to_hex(telegram_raw, length).c_str(), length); } } diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index d4dc5d2b5..6d0040874 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -33,7 +33,6 @@ static RingbufHandle_t buf_handle = NULL; static hw_timer_t * timer = NULL; bool drop_next_rx = true; uint8_t tx_mode_ = 0xFF; -//portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; uint8_t emsTxBuf[EMS_MAXBUFFERSIZE]; uint8_t emsTxBufIdx; uint8_t emsTxBufLen; @@ -99,13 +98,7 @@ void IRAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { * init UART driver */ void EMSuart::start(uint8_t tx_mode) { - if (tx_mode == EMS_TXMODE_DEFAULT) { - emsTxWait = EMSUART_BIT_TIME * 11; - } else if (tx_mode == EMS_TXMODE_EMSPLUS) { - emsTxWait = EMSUART_BIT_TIME * 20; - } else if (tx_mode == EMS_TXMODE_HT3) { - emsTxWait = EMSUART_BIT_TIME * 17; - } else if(tx_mode > 10 ) { + if(tx_mode > 10 ) { emsTxWait = EMSUART_BIT_TIME * tx_mode; } else if(tx_mode > 5 ) { emsTxWait = EMSUART_BIT_TIME * tx_mode * 2; @@ -123,13 +116,10 @@ void EMSuart::start(uint8_t tx_mode) { .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, } + ESP_ERROR_CHECK(uart_param_config(EMSUART_UART, &uart_config)); if (tx_mode_ == 5) { EMS_UART.conf0.stop_bit_num = UART_STOP_BITS_1_5; - } else { - EMS_UART.conf0.stop_bit_num = UART_STOP_BITS_1; } - - 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 @@ -195,15 +185,10 @@ void EMSuart::send_poll(uint8_t data) { * returns code, 1=success */ uint16_t EMSuart::transmit(uint8_t * buf, uint8_t len) { - if (len == 0 || len > 32) { + if (len == 0 || len >= EMS_MAXBUFFERSIZE) { return EMS_TX_STATUS_ERR; } - if (tx_mode_ == EMS_TXMODE_NEW || tx_mode_ == 5) { - for (uint8_t i = 0; i < len; i++) { - EMS_UART.fifo.rw_byte = buf[i]; - } - EMS_UART.conf0.txd_brk = 1; // after send - } else { + if (tx_mode_ > 5) { // timer controlled modes for (uint8_t i = 0; i < len; i++) { emsTxBuf[i] = buf[i]; } @@ -212,7 +197,44 @@ uint16_t EMSuart::transmit(uint8_t * buf, uint8_t len) { emsTxBufLen = len; timerAlarmWrite(timer, emsTxWait, false); timerAlarmEnable(timer); + return EMS_TX_STATUS_OK; } + if (tx_mode_ >= EMS_TXMODE_NEW) { // hardware controlled modes + for (uint8_t i = 0; i < len; i++) { + EMS_UART.fifo.rw_byte = buf[i]; + } + EMS_UART.conf0.txd_brk = 1; // after send + return EMS_TX_STATUS_OK; + } + if (tx_mode_ >= EMS_TXMODE_EMSPLUS) { // EMS+ with long delay + for (uint8_t i = 0; i < len; i++) { + EMS_UART.fifo.rw_byte = buf[i]; + delaymicroseconds(EMSUART_TX_WAIT_PLUS); + } + EMS_UART.conf0.txd_brk = 1; // after send, cleard by hardware after send + return EMS_TX_STATUS_OK; + } + if (tx_mode_ >= EMS_TXMODE_HT3) { // HT3 with 7 bittimes delay + for (uint8_t i = 0; i < len; i++) { + EMS_UART.fifo.rw_byte = buf[i]; + delayMicroseconds(EMSUART_TX_WAIT_HT3); + } + EMS_UART.conf0.txd_brk = 1; // after send, cleard by hardware after send + return EMS_TX_STATUS_OK; + } + // mode 1 + // flush fifos -- not supported in ESP32 uart #2! + // EMS_UART.conf0.rxfifo_rst = 1; + // EMS_UART.conf0.txfifo_rst = 1; + for (uint8_t i = 0; i < len; i++) { + volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt; + EMS_UART.fifo.rw_byte = buf[i]; // send each Tx byte + // wait for echo + while (EMS_UART.status.rxfifo_cnt == _usrxc) { + delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... + } + } + EMS_UART.conf0.txd_brk = 1; // after send, cleard by hardware after send return EMS_TX_STATUS_OK; } diff --git a/src/uart/emsuart_esp32.h b/src/uart/emsuart_esp32.h index 000a20c00..763bc491b 100644 --- a/src/uart/emsuart_esp32.h +++ b/src/uart/emsuart_esp32.h @@ -45,6 +45,19 @@ #define EMS_TXMODE_HT3 3 #define EMS_TXMODE_NEW 4 // for michael's testing +// LEGACY +#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud +#define EMSUART_TX_WAIT_BRK (EMSUART_TX_BIT_TIME * 11) // 1144 + +// EMS 1.0 +#define EMSUART_TX_BUSY_WAIT (EMSUART_TX_BIT_TIME / 8) // 13 + +// HT3/Junkers - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) plus 7 bit delay. The -8 is for lag compensation. +#define EMSUART_TX_WAIT_HT3 (EMSUART_TX_BIT_TIME * 17) - 8 // 1760 + +// EMS+ - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) and delay of another Bytetime. +#define EMSUART_TX_WAIT_PLUS 2070 + // customize the GPIO pins for RX and TX here #ifdef WEMOS_D1_32 diff --git a/src/uart/emsuart_esp8266.cpp b/src/uart/emsuart_esp8266.cpp index 1b1468f89..c071585f7 100644 --- a/src/uart/emsuart_esp8266.cpp +++ b/src/uart/emsuart_esp8266.cpp @@ -24,18 +24,12 @@ namespace emsesp { -MAKE_PSTR(logger_name, "emsuart") - -uuid::log::Logger EMSuart::logger_{F_(logger_name), uuid::log::Facility::CONSOLE}; 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_next_rx = true; -uint32_t emsRxTime; -// uint32_t emsTxTime = 0; uint8_t emsTxBuf[EMS_MAXBUFFERSIZE]; uint8_t emsTxBufIdx; uint8_t emsTxBufLen; @@ -67,7 +61,6 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { 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 - emsRxTime = uuid::get_uptime(); } drop_next_rx = false; system_os_post(EMSUART_recvTaskPrio, 0, 0); // call emsuart_recvTask() at next opportunity @@ -85,24 +78,8 @@ 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 - } - // if (emsTxTime > 0) { - // LOG_INFO(F("tx duration: %d ms"), uuid::get_uptime() - emsTxTime); - // emsTxTime = 0; - // } - // 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) { + // Ignore telegrams with no data value, then transmit EMS buffer, excluding the BRK + if (length > 4 || length == 2) { EMSESP::incoming_telegram((uint8_t *)pCurrent->buffer, length - 1); } } @@ -111,9 +88,8 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_recvTask(os_event_t * events) { * 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 + USC0(EMSUART_UART) |= ((1 << UCRXRST) | (1 << UCTXRST)); // set bits + USC0(EMSUART_UART) &= ~((1 << UCRXRST) | (1 << UCTXRST)); // clear bits } // ISR to Fire when Timer is triggered @@ -128,7 +104,7 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { } else if (emsTxBufIdx == emsTxBufLen) { USC0(EMSUART_UART) |= (1 << UCBRK); // set if (tx_mode_ > 5 || tx_mode_ < 11) { - timer1_write(5 * EMSUART_TX_BIT_TIME * 12); + timer1_write(5 * EMSUART_TX_BIT_TIME * 11); USIE(EMSUART_UART) &= ~(1 << UIBD); // disable break interrupt } } else if (USC0(EMSUART_UART) & (1 << UCBRK)) { @@ -141,9 +117,9 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { */ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { if (tx_mode > 10) { - emsTxWait = 5 * EMSUART_TX_BIT_TIME * tx_mode; // bittimes for tx_mode + emsTxWait = 5 * EMSUART_TX_BIT_TIME * tx_mode; // bittimes for tx_mode } else if (tx_mode > 5) { - emsTxWait = 10 * EMSUART_TX_BIT_TIME * tx_mode; // bittimes for tx_mode + emsTxWait = 10 * EMSUART_TX_BIT_TIME * tx_mode; // bittimes for tx_mode } if (tx_mode == 5) { USC0(EMSUART_UART) = 0x2C; // 8N1,5 @@ -249,13 +225,9 @@ void ICACHE_FLASH_ATTR EMSuart::restart() { */ void ICACHE_FLASH_ATTR EMSuart::tx_brk() { - // must make sure Tx FIFO is empty - while (((USS(EMSUART_UART) >> USTXC) & 0xFF)) - ; - // do not clear buffers to get a echo back - // tmp = ((1 << UCRXRST) | (1 << UCTXRST)); // bit mask - // USC0(EMSUART_UART) |= (tmp); // set bits - // USC0(EMSUART_UART) &= ~(tmp); // clear bits + // make sure Tx FIFO is empty + while (((USS(EMSUART_UART) >> USTXC) & 0xFF)) { + } // To create a 11-bit we set TXD_BRK bit so the break signal will // automatically be sent when the tx fifo is empty @@ -264,8 +236,11 @@ void ICACHE_FLASH_ATTR EMSuart::tx_brk() { if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ mode delayMicroseconds(EMSUART_TX_WAIT_PLUS); // 2070 - } else { // junkers and EMS1.0 + } else if (tx_mode_ == EMS_TXMODE_HT3) { // junkers delayMicroseconds(EMSUART_TX_WAIT_BRK); // 1144 + } else { // EMS1.0 + while (!(USIR(EMSUART_UART) & (1 << UIBD))) { + } } USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear BRK bit @@ -279,14 +254,15 @@ void ICACHE_FLASH_ATTR EMSuart::tx_brk() { void EMSuart::send_poll(uint8_t data) { // reset tx-brk, just in case it is accidently set USC0(EMSUART_UART) &= ~(1 << UCBRK); + if (tx_mode_ > 5) { // timer controlled modes USF(EMSUART_UART) = data; - emsTxBufIdx = 0; - emsTxBufLen = 1; + emsTxBufIdx = 0; + emsTxBufLen = 1; timer1_write(emsTxWait); } else if (tx_mode_ >= EMS_TXMODE_NEW) { // hardware controlled modes USF(EMSUART_UART) = data; - USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end + USC0(EMSUART_UART) |= (1 << UCBRK); // brk after sendout } else if (tx_mode_ == EMS_TXMODE_HT3) { USF(EMSUART_UART) = data; delayMicroseconds(EMSUART_TX_WAIT_HT3); @@ -308,16 +284,10 @@ void EMSuart::send_poll(uint8_t data) { * returns code, 0=success, 1=brk error, 2=watchdog timeout */ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { - if (len == 0 || len > 32) { + if (len == 0 || len >= EMS_MAXBUFFERSIZE) { return EMS_TX_STATUS_ERR; // nothing or to much to send } -#ifdef EMSESP_DEBUG - // LOG_INFO(F("[DEBUG] UART Response time: %d ms"), uuid::get_uptime() - emsRxTime); -#endif - // emsTxTime = uuid::get_uptime(); - // if ((uuid::get_uptime() - emsRxTime) > EMS_RX_TO_TX_TIMEOUT)) { // send allowed within 20 ms - // return EMS_TX_STATUS_ERR; - // } + // reset tx-brk, just in case it is accidently set USC0(EMSUART_UART) &= ~(1 << UCBRK); @@ -326,16 +296,14 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { for (uint8_t i = 0; i < len; i++) { emsTxBuf[i] = buf[i]; } - emsTxBufIdx = 0; - emsTxBufLen = len; + emsTxBufIdx = 0; + emsTxBufLen = len; USF(EMSUART_UART) = buf[0]; - // timer1_attachInterrupt(emsuart_tx_timer_intr_handler); // Add ISR Function - // timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); // 5 MHz timer timer1_write(emsTxWait); return EMS_TX_STATUS_OK; } - // new code from Michael. See https://github.com/proddy/EMS-ESP/issues/380 + // hardware controlled modes with 1 and 1,5 stopbits if (tx_mode_ >= EMS_TXMODE_NEW) { for (uint8_t i = 0; i < len; i++) { USF(EMSUART_UART) = buf[i]; @@ -358,11 +326,9 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { 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)) - ; - + while (((USS(EMSUART_UART) >> USTXC) & 0xff)) { + } // wait until bits are sent on wire delayMicroseconds(EMSUART_TX_WAIT_HT3); } @@ -397,16 +363,14 @@ uint16_t 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 - // noInterrupts(); ETS_UART_INTR_DISABLE(); - // USC0(EMSUART_UART) |= (1 << UCRXRST); // reset uart rx fifo emsuart_flush_fifos(); // send the bytes along the serial line for (uint8_t i = 0; i < len; i++) { volatile uint8_t _usrxc = (USS(EMSUART_UART) >> USRXC) & 0xFF; USF(EMSUART_UART) = buf[i]; // send each Tx byte - // wait for echo from the busmaster + // wait for echo while (((USS(EMSUART_UART) >> USRXC) & 0xFF) == _usrxc) { delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... } @@ -419,21 +383,16 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { // 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 USC0(EMSUART_UART) |= (1 << UCBRK); // set // wait until BRK detected... while (!(USIR(EMSUART_UART) & (1 << UIBD))) { - delayMicroseconds(EMSUART_TX_BIT_TIME); + // delayMicroseconds(EMSUART_TX_BIT_TIME); } USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear - // USC0(EMSUART_UART) &= ~((1 << UCBRK) | (1 << UCLBE)); // disable loopback & clear - // USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ - // phantomBreak = 1; } - // interrupts(); ETS_UART_INTR_ENABLE(); // open up the FIFO again to start receiving return EMS_TX_STATUS_OK; // send the Tx ok status back diff --git a/src/uart/emsuart_esp8266.h b/src/uart/emsuart_esp8266.h index 1923b2f2e..e3ba11e30 100644 --- a/src/uart/emsuart_esp8266.h +++ b/src/uart/emsuart_esp8266.h @@ -75,8 +75,6 @@ class EMSuart { } EMSRxBuf_t; private: - // static constexpr uint32_t EMS_RX_TO_TX_TIMEOUT = 20; - static uuid::log::Logger logger_; 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();