update uart

This commit is contained in:
MichaelDvP
2020-07-21 14:02:35 +02:00
parent 915f961828
commit 01ce088791
3 changed files with 103 additions and 161 deletions

View File

@@ -28,8 +28,8 @@
namespace emsesp { namespace emsesp {
static intr_handle_t uart_handle;
static RingbufHandle_t buf_handle = NULL; static RingbufHandle_t buf_handle = NULL;
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
static hw_timer_t * timer = NULL; static hw_timer_t * timer = NULL;
bool drop_next_rx = true; bool drop_next_rx = true;
uint8_t tx_mode_ = 0xFF; uint8_t tx_mode_ = 0xFF;
@@ -46,7 +46,6 @@ void EMSuart::emsuart_recvTask(void * para) {
size_t item_size; size_t item_size;
uint8_t * telegram = (uint8_t *)xRingbufferReceive(buf_handle, &item_size, portMAX_DELAY); uint8_t * telegram = (uint8_t *)xRingbufferReceive(buf_handle, &item_size, portMAX_DELAY);
uint8_t telegramSize = item_size; uint8_t telegramSize = item_size;
if (telegram) { if (telegram) {
EMSESP::incoming_telegram(telegram, telegramSize); EMSESP::incoming_telegram(telegram, telegramSize);
vRingbufferReturnItem(buf_handle, (void *)telegram); vRingbufferReturnItem(buf_handle, (void *)telegram);
@@ -60,15 +59,10 @@ void EMSuart::emsuart_recvTask(void * para) {
void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
static uint8_t rxbuf[EMS_MAXBUFFERSIZE]; static uint8_t rxbuf[EMS_MAXBUFFERSIZE];
static uint8_t length; static uint8_t length;
portENTER_CRITICAL(&mux);
if (EMS_UART.int_st.brk_det) { if (EMS_UART.int_st.brk_det) {
EMS_UART.int_clr.brk_det = 1; // clear flag EMS_UART.int_clr.brk_det = 1; // clear flag
EMS_UART.conf0.txd_brk = 0; // disable <brk> length = 0;
if (emsTxBufIdx < emsTxBufLen) { // timer tx_mode is interrupted by <brk>
emsTxBufIdx = emsTxBufLen; // stop timer mode
drop_next_rx = true; // we have trash in buffer
}
length = 0;
while (EMS_UART.status.rxfifo_cnt) { while (EMS_UART.status.rxfifo_cnt) {
uint8_t rx = EMS_UART.fifo.rw_byte; // read all bytes from fifo uint8_t rx = EMS_UART.fifo.rw_byte; // read all bytes from fifo
if (length < EMS_MAXBUFFERSIZE) { if (length < EMS_MAXBUFFERSIZE) {
@@ -83,6 +77,7 @@ void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
} }
drop_next_rx = false; drop_next_rx = false;
} }
portEXIT_CRITICAL(&mux);
} }
@@ -90,22 +85,19 @@ void IRAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() {
if (emsTxBufLen == 0) { if (emsTxBufLen == 0) {
return; return;
} }
if (tx_mode_ > 50) { portENTER_CRITICAL(&mux);
for (uint8_t i = 0; i < emsTxBufLen; i++) { if (emsTxBufIdx < emsTxBufLen) {
EMS_UART.fifo.rw_byte = emsTxBuf[i]; EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx];
} } else if (emsTxBufIdx == emsTxBufLen) {
EMS_UART.conf0.txd_brk = 1; // <brk> after send EMS_UART.conf0.txd_inv = 1;
} else { timerAlarmWrite(timer, EMSUART_TX_WAIT_BRK, true);
if (emsTxBufIdx + 1 < emsTxBufLen) { } else if (emsTxBufIdx == emsTxBufLen + 1) {
EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx]; // delayMicroseconds(EMSUART_TX_WAIT_BRK);
timerAlarmWrite(timer, emsTxWait, false); EMS_UART.conf0.txd_inv = 0;
timerAlarmEnable(timer); timerAlarmDisable(timer);
} else if (emsTxBufIdx + 1 == emsTxBufLen) {
EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx];
EMS_UART.conf0.txd_brk = 1; // <brk> after send
}
emsTxBufIdx++;
} }
emsTxBufIdx++;
portEXIT_CRITICAL(&mux);
} }
/* /*
@@ -134,7 +126,7 @@ void EMSuart::start(const uint8_t tx_mode) {
EMS_UART.idle_conf.rx_idle_thrhd = 256; EMS_UART.idle_conf.rx_idle_thrhd = 256;
drop_next_rx = true; drop_next_rx = true;
buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT); buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT);
uart_isr_register(EMSUART_UART, emsuart_rx_intr_handler, NULL, ESP_INTR_FLAG_IRAM, &uart_handle); uart_isr_register(EMSUART_UART, emsuart_rx_intr_handler, NULL, ESP_INTR_FLAG_IRAM, NULL);
xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, configMAX_PRIORITIES - 1, NULL); xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, configMAX_PRIORITIES - 1, NULL);
timer = timerBegin(1, 80, true); // timer prescale to 1 µs, countup timer = timerBegin(1, 80, true); // timer prescale to 1 µs, countup
@@ -154,39 +146,59 @@ void EMSuart::stop() {
* Restart Interrupt * Restart Interrupt
*/ */
void EMSuart::restart() { void EMSuart::restart() {
if (EMS_UART.int_raw.brk_det) { if (EMS_UART.int_raw.brk_det) { // we received a break in the meantime
EMS_UART.int_clr.brk_det = 1; // clear flag EMS_UART.int_clr.brk_det = 1; // clear flag
drop_next_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
emsTxBufIdx = 0; emsTxBufIdx = 0;
emsTxBufLen = 0; emsTxBufLen = 0;
if (tx_mode_ == 1) { emsTxWait = EMSUART_TX_BIT_TIME * (tx_mode_ + 10);
EMS_UART.idle_conf.tx_idle_num = 5; if(tx_mode_ == EMS_TXMODE_NEW) {
} else if (tx_mode_ == 2) { EMS_UART.conf0.txd_brk = 1;
EMS_UART.idle_conf.tx_idle_num = 10;
} else if (tx_mode_ == 3) {
EMS_UART.idle_conf.tx_idle_num = 7;
} else if (tx_mode_ == 4) {
EMS_UART.idle_conf.tx_idle_num = 2;
} else if (tx_mode_ == 5) {
EMS_UART.idle_conf.tx_idle_num = 2;
} else if (tx_mode_ <= 50) {
EMS_UART.idle_conf.tx_idle_num = tx_mode_;
emsTxWait = EMSUART_TX_BIT_TIME * (tx_mode_ + 10);
} else { } else {
EMS_UART.idle_conf.tx_idle_num = 2; EMS_UART.conf0.txd_brk = 0;
emsTxWait = EMSUART_TX_BIT_TIME * (tx_mode_ - 50);
} }
} }
/*
* Sends a 11-bit break by inverting the tx-port
*/
void EMSuart::tx_brk() {
EMS_UART.conf0.txd_inv = 1;
delayMicroseconds(EMSUART_TX_WAIT_BRK);
EMS_UART.conf0.txd_inv = 0;
}
/* /*
* Sends a 1-byte poll, ending with a <BRK> * Sends a 1-byte poll, ending with a <BRK>
*/ */
void EMSuart::send_poll(const uint8_t data) { void EMSuart::send_poll(const uint8_t data) {
EMS_UART.fifo.rw_byte = data; if (tx_mode_ > 5) { // timer controlled modes
EMS_UART.conf0.txd_brk = 1; // <brk> after send emsTxBuf[0] = data;
return; emsTxBufIdx = 0;
emsTxBufLen = 1;
timerAlarmWrite(timer, emsTxWait, true); // start timer with autoreload
timerAlarmEnable(timer); // first interrupt comes immediately
} else if (tx_mode_ == EMS_TXMODE_DEFAULT) {
volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt;
uint16_t timeoutcnt = EMSUART_TX_TIMEOUT;
EMS_UART.fifo.rw_byte = data;
while ((EMS_UART.status.rxfifo_cnt == _usrxc) && (--timeoutcnt > 0)) {
delayMicroseconds(EMSUART_TX_BUSY_WAIT);
}
tx_brk();
} else if (tx_mode_ == EMS_TXMODE_EMSPLUS) {
EMS_UART.fifo.rw_byte = data;
delayMicroseconds(EMSUART_TX_WAIT_PLUS);
tx_brk();
} else if (tx_mode_ == EMS_TXMODE_HT3) {
EMS_UART.fifo.rw_byte = data;
delayMicroseconds(EMSUART_TX_WAIT_HT3);
tx_brk();
} else {
EMS_UART.fifo.rw_byte = data;
}
} }
/* /*
@@ -198,8 +210,6 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
if (len == 0 || len >= EMS_MAXBUFFERSIZE) { if (len == 0 || len >= EMS_MAXBUFFERSIZE) {
return EMS_TX_STATUS_ERR; return EMS_TX_STATUS_ERR;
} }
// needs to be disabled for the delayed modes otherwise the uart makes a <brk> after every byte
EMS_UART.conf0.txd_brk = 0;
if (tx_mode_ > 5) { // timer controlled modes if (tx_mode_ > 5) { // timer controlled modes
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
@@ -207,45 +217,33 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
} }
emsTxBufIdx = 0; emsTxBufIdx = 0;
emsTxBufLen = len; emsTxBufLen = len;
timerAlarmWrite(timer, emsTxWait, false); timerAlarmWrite(timer, emsTxWait, true); // start with autoreload
timerAlarmEnable(timer); timerAlarmEnable(timer);
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }
if (tx_mode_ == 5) { // wait before sending
//vTaskDelay(4 / portTICK_PERIOD_MS);
delayMicroseconds(4000);
for (uint8_t i = 0; i < len; i++) {
EMS_UART.fifo.rw_byte = buf[i];
}
EMS_UART.conf0.txd_brk = 1; // <brk> after send
return EMS_TX_STATUS_OK;
}
if (tx_mode_ == EMS_TXMODE_NEW) { // hardware controlled modes if (tx_mode_ == EMS_TXMODE_NEW) { // hardware controlled modes
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
EMS_UART.fifo.rw_byte = buf[i]; EMS_UART.fifo.rw_byte = buf[i];
} }
EMS_UART.conf0.txd_brk = 1; // <brk> after send
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }
if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ with long delay if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ with long delay
for (uint8_t i = 0; i < len - 1; i++) { for (uint8_t i = 0; i < len; i++) {
EMS_UART.fifo.rw_byte = buf[i]; EMS_UART.fifo.rw_byte = buf[i];
delayMicroseconds(EMSUART_TX_WAIT_PLUS); delayMicroseconds(EMSUART_TX_WAIT_PLUS);
} }
EMS_UART.fifo.rw_byte = buf[len - 1]; tx_brk();
EMS_UART.conf0.txd_brk = 1; // <brk> after send, cleard by hardware after send
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }
if (tx_mode_ == EMS_TXMODE_HT3) { // HT3 with 7 bittimes delay if (tx_mode_ == EMS_TXMODE_HT3) { // HT3 with 7 bittimes delay
for (uint8_t i = 0; i < len - 1; i++) { for (uint8_t i = 0; i < len; i++) {
EMS_UART.fifo.rw_byte = buf[i]; EMS_UART.fifo.rw_byte = buf[i];
delayMicroseconds(EMSUART_TX_WAIT_HT3); delayMicroseconds(EMSUART_TX_WAIT_HT3);
} }
EMS_UART.fifo.rw_byte = buf[len - 1]; tx_brk();
EMS_UART.conf0.txd_brk = 1; // <brk> after send, cleard by hardware after send
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }
@@ -253,7 +251,7 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
// flush fifos -- not supported in ESP32 uart #2! // flush fifos -- not supported in ESP32 uart #2!
// EMS_UART.conf0.rxfifo_rst = 1; // EMS_UART.conf0.rxfifo_rst = 1;
// EMS_UART.conf0.txfifo_rst = 1; // EMS_UART.conf0.txfifo_rst = 1;
for (uint8_t i = 0; i < len - 1; i++) { for (uint8_t i = 0; i < len; i++) {
volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt; volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt;
EMS_UART.fifo.rw_byte = buf[i]; // send each Tx byte EMS_UART.fifo.rw_byte = buf[i]; // send each Tx byte
uint16_t timeoutcnt = EMSUART_TX_TIMEOUT; uint16_t timeoutcnt = EMSUART_TX_TIMEOUT;
@@ -261,8 +259,7 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles...
} }
} }
EMS_UART.fifo.rw_byte = buf[len - 1]; // send each Tx byte tx_brk();
EMS_UART.conf0.txd_brk = 1; // <brk> after send, cleard by hardware after send
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }

View File

@@ -90,6 +90,7 @@ class EMSuart {
static void emsuart_recvTask(void * para); static void emsuart_recvTask(void * para);
static void IRAM_ATTR emsuart_rx_intr_handler(void * para); static void IRAM_ATTR emsuart_rx_intr_handler(void * para);
static void IRAM_ATTR emsuart_tx_timer_intr_handler(); static void IRAM_ATTR emsuart_tx_timer_intr_handler();
static void tx_brk();
}; };
} // namespace emsesp } // namespace emsesp

View File

@@ -47,11 +47,10 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
if (USIS(EMSUART_UART) & ((1 << UIBD))) { // BREAK detection = End of EMS data block if (USIS(EMSUART_UART) & ((1 << UIBD))) { // BREAK detection = End of EMS data block
USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk
if (emsTxBufIdx < emsTxBufLen) { // irq tx_mode is interrupted by <brk> if (emsTxBufIdx < emsTxBufLen) { // irq tx_mode is interrupted by <brk>
emsTxBufIdx = emsTxBufLen; // stop tx emsTxBufIdx = emsTxBufLen + 1; // stop tx
drop_next_rx = true; // we have trash in buffer // drop_next_rx = true; // we have trash in buffer
} }
USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt
USIE(EMSUART_UART) &= ~(1 << UIFF); // disable fifo-full irq
length = 0; length = 0;
while ((USS(EMSUART_UART) >> USRXC) & 0x0FF) { // read fifo into buffer while ((USS(EMSUART_UART) >> USRXC) & 0x0FF) { // read fifo into buffer
uint8_t rx = USF(EMSUART_UART); uint8_t rx = USF(EMSUART_UART);
@@ -88,6 +87,21 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_recvTask(os_event_t * events) {
} }
} }
// ISR to Fire when Timer is triggered
void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() {
emsTxBufIdx++;
if (emsTxBufIdx < emsTxBufLen) {
USF(EMSUART_UART) = emsTxBuf[emsTxBufIdx];
timer1_write(emsTxWait);
} else if (emsTxBufIdx == emsTxBufLen) {
USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK>
timer1_write(EMSUART_TX_WAIT_BRK * 5);
} else {
USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset <BRK>
sending_ = false;
}
}
/* /*
* flush everything left over in buffer, this clears both rx and tx FIFOs * flush everything left over in buffer, this clears both rx and tx FIFOs
*/ */
@@ -96,36 +110,11 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_flush_fifos() {
USC0(EMSUART_UART) &= ~((1 << UCRXRST) | (1 << UCTXRST)); // clear bits USC0(EMSUART_UART) &= ~((1 << UCRXRST) | (1 << UCTXRST)); // clear bits
} }
// ISR to Fire when Timer is triggered
void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() {
if (tx_mode_ > 50) {
for (uint8_t i = 0; i < emsTxBufLen; i++) {
USF(EMSUART_UART) = emsTxBuf[i];
}
USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK>
} else {
if (emsTxBufIdx > emsTxBufLen) {
return;
}
if (emsTxBufIdx < emsTxBufLen) {
USF(EMSUART_UART) = emsTxBuf[emsTxBufIdx];
timer1_write(emsTxWait);
} else if (emsTxBufIdx == emsTxBufLen) {
USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK>
}
emsTxBufIdx++;
}
}
/* /*
* init UART0 driver * init UART0 driver
*/ */
void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
if (tx_mode > 50) { emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode + 10); // bittimes wait between bytes
emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode - 50); // bittimes wait before sending
} else if (tx_mode > 5) {
emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode + 10); // bittimes wait between bytes
}
if (tx_mode_ != 0xFF) { // it's a restart no need to configure uart if (tx_mode_ != 0xFF) { // it's a restart no need to configure uart
tx_mode_ = tx_mode; tx_mode_ = tx_mode;
restart(); restart();
@@ -151,11 +140,7 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
// set 9600, 8 bits, no parity check, 1 stop bit // set 9600, 8 bits, no parity check, 1 stop bit
USD(EMSUART_UART) = (UART_CLK_FREQ / EMSUART_BAUD); USD(EMSUART_UART) = (UART_CLK_FREQ / EMSUART_BAUD);
if (tx_mode_ == 5) { USC0(EMSUART_UART) = EMSUART_CONFIG; // 8N1
USC0(EMSUART_UART) = 0x2C; // 8N1.5
} else {
USC0(EMSUART_UART) = EMSUART_CONFIG; // 8N1
}
emsuart_flush_fifos(); emsuart_flush_fifos();
// conf1 params // conf1 params
@@ -190,12 +175,13 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
system_uart_swap(); system_uart_swap();
ETS_UART_INTR_ATTACH(emsuart_rx_intr_handler, nullptr); ETS_UART_INTR_ATTACH(emsuart_rx_intr_handler, nullptr);
ETS_UART_INTR_ENABLE(); // ETS_UART_INTR_ENABLE();
drop_next_rx = true; drop_next_rx = true;
// for sending with large delay in EMS+ mode we use a timer interrupt // for sending with large delay in EMS+ mode we use a timer interrupt
timer1_attachInterrupt(emsuart_tx_timer_intr_handler); // Add ISR Function timer1_attachInterrupt(emsuart_tx_timer_intr_handler); // Add ISR Function
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); // 5 MHz timer timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); // 5 MHz timer
USIE(EMSUART_UART) = (1 << UIBD);
} }
/* /*
@@ -203,8 +189,8 @@ 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 * 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() { void ICACHE_FLASH_ATTR EMSuart::stop() {
ETS_UART_INTR_DISABLE(); USIE(EMSUART_UART) = 0;
timer1_disable(); // timer1_disable();
} }
/* /*
@@ -215,10 +201,10 @@ void ICACHE_FLASH_ATTR EMSuart::restart() {
USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt
drop_next_rx = true; drop_next_rx = true;
} }
ETS_UART_INTR_ENABLE();
emsTxBufIdx = 0; emsTxBufIdx = 0;
emsTxBufLen = 0; emsTxBufLen = 0;
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); // timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);
USIE(EMSUART_UART) = (1 << UIBD);
} }
/* /*
@@ -229,17 +215,10 @@ void ICACHE_FLASH_ATTR EMSuart::tx_brk() {
// make sure Tx FIFO is empty // make sure Tx FIFO is empty
while (((USS(EMSUART_UART) >> USTXC) & 0xFF)) { while (((USS(EMSUART_UART) >> USTXC) & 0xFF)) {
} }
// To create a 11-bit <BRK> we set TXD_BRK bit so the break signal will
// automatically be sent when the tx fifo is empty
ETS_UART_INTR_DISABLE();
USC0(EMSUART_UART) |= (1 << UCBRK); // set bit USC0(EMSUART_UART) |= (1 << UCBRK); // set bit
// also for EMS+ there is no need to wait longer, we are finished and can free the bus. // also for EMS+ there is no need to wait longer, we are finished and can free the bus.
delayMicroseconds(EMSUART_TX_WAIT_BRK); // 1144 delayMicroseconds(EMSUART_TX_WAIT_BRK); // 1144
USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear BRK bit USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear BRK bit
ETS_UART_INTR_ENABLE();
} }
/* /*
@@ -251,19 +230,11 @@ void EMSuart::send_poll(uint8_t data) {
USC0(EMSUART_UART) &= ~(1 << UCBRK); USC0(EMSUART_UART) &= ~(1 << UCBRK);
sending_ = true; sending_ = true;
if (tx_mode_ > 50) { // timer controlled modes if (tx_mode_ >= 5) { // timer controlled modes
emsTxBuf[0] = data;
emsTxBufLen = 1;
timer1_write(emsTxWait);
} else if (tx_mode_ > 5) { // timer controlled modes
emsTxBuf[0] = data; emsTxBuf[0] = data;
emsTxBufIdx = 0; emsTxBufIdx = 0;
emsTxBufLen = 1; emsTxBufLen = 1;
timer1_write(emsTxWait); timer1_write(emsTxWait);
} else if (tx_mode_ == 5) {
delayMicroseconds(3000);
USF(EMSUART_UART) = data;
USC0(EMSUART_UART) |= (1 << UCBRK);
} else if (tx_mode_ == EMS_TXMODE_NEW) { // hardware controlled modes } else if (tx_mode_ == EMS_TXMODE_NEW) { // hardware controlled modes
USF(EMSUART_UART) = data; USF(EMSUART_UART) = data;
USC0(EMSUART_UART) |= (1 << UCBRK); USC0(EMSUART_UART) |= (1 << UCBRK);
@@ -271,27 +242,22 @@ void EMSuart::send_poll(uint8_t data) {
USF(EMSUART_UART) = data; USF(EMSUART_UART) = data;
delayMicroseconds(EMSUART_TX_WAIT_HT3); delayMicroseconds(EMSUART_TX_WAIT_HT3);
tx_brk(); // send <BRK> tx_brk(); // send <BRK>
sending_ = false;
} else if (tx_mode_ == EMS_TXMODE_EMSPLUS) { } else if (tx_mode_ == EMS_TXMODE_EMSPLUS) {
USF(EMSUART_UART) = data; USF(EMSUART_UART) = data;
delayMicroseconds(EMSUART_TX_WAIT_PLUS); delayMicroseconds(EMSUART_TX_WAIT_PLUS);
tx_brk(); // send <BRK> tx_brk(); // send <BRK>
sending_ = false;
} else { } else {
// tx_mode 1 // tx_mode 1
// EMS1.0, same logic as in transmit
ETS_UART_INTR_DISABLE();
volatile uint8_t _usrxc = (USS(EMSUART_UART) >> USRXC) & 0xFF; volatile uint8_t _usrxc = (USS(EMSUART_UART) >> USRXC) & 0xFF;
USF(EMSUART_UART) = data; USF(EMSUART_UART) = data;
uint16_t timeoutcnt = EMSUART_TX_TIMEOUT; uint16_t timeoutcnt = EMSUART_TX_TIMEOUT;
while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) == _usrxc) && (--timeoutcnt > 0)) { while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) == _usrxc) && (--timeoutcnt > 0)) {
delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles...
} }
USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK> tx_brk(); // send <BRK>
timeoutcnt = EMSUART_TX_TIMEOUT; sending_ = false;
while (!(USIR(EMSUART_UART) & (1 << UIBD)) && (--timeoutcnt > 0)) {
delayMicroseconds(EMSUART_TX_BUSY_WAIT);
}
USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear <BRK>
ETS_UART_INTR_ENABLE();
} }
} }
@@ -308,34 +274,17 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
USC0(EMSUART_UART) &= ~(1 << UCBRK); USC0(EMSUART_UART) &= ~(1 << UCBRK);
sending_ = true; sending_ = true;
// all at once after a initial timer delay
if (tx_mode_ > 50) {
for (uint8_t i = 0; i < len; i++) {
emsTxBuf[i] = buf[i];
}
emsTxBufLen = len;
timer1_write(emsTxWait);
return EMS_TX_STATUS_OK;
}
// timer controlled modes with extra delay // timer controlled modes with extra delay
if (tx_mode_ > 5) { if (tx_mode_ >= 5) {
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
emsTxBuf[i] = buf[i]; emsTxBuf[i] = buf[i];
} }
USF(EMSUART_UART) = buf[0]; // send first byte
emsTxBufIdx = 0; emsTxBufIdx = 0;
emsTxBufLen = len; emsTxBufLen = len;
timer1_write(emsTxWait); timer1_write(emsTxWait);
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }
// fixed delay before sending
if (tx_mode_ == 5) {
delayMicroseconds(3000);
for (uint8_t i = 0; i < len; i++) {
USF(EMSUART_UART) = buf[i];
}
USC0(EMSUART_UART) |= (1 << UCBRK); // send <BRK> at the end
return EMS_TX_STATUS_OK;
}
// new code from Michael. See https://github.com/proddy/EMS-ESP/issues/380 // new code from Michael. See https://github.com/proddy/EMS-ESP/issues/380
if (tx_mode_ == EMS_TXMODE_NEW) { // tx_mode 4 if (tx_mode_ == EMS_TXMODE_NEW) { // tx_mode 4
@@ -353,6 +302,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
delayMicroseconds(EMSUART_TX_WAIT_PLUS); // 2070 delayMicroseconds(EMSUART_TX_WAIT_PLUS); // 2070
} }
tx_brk(); // send <BRK> tx_brk(); // send <BRK>
sending_ = false;
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }
@@ -367,6 +317,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
delayMicroseconds(EMSUART_TX_WAIT_HT3); delayMicroseconds(EMSUART_TX_WAIT_HT3);
} }
tx_brk(); // send <BRK> tx_brk(); // send <BRK>
sending_ = false;
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }
@@ -397,7 +348,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
// disable rx interrupt // disable rx interrupt
// clear Rx status register, resetting the Rx FIFO and flush it // clear Rx status register, resetting the Rx FIFO and flush it
ETS_UART_INTR_DISABLE(); // ETS_UART_INTR_DISABLE();
emsuart_flush_fifos(); emsuart_flush_fifos();
// send the bytes along the serial line // send the bytes along the serial line
@@ -413,22 +364,15 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
// we got the whole telegram in the Rx buffer // we got the whole telegram in the Rx buffer
// on Rx-BRK (bus collision), we simply enable Rx and leave it // 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. // otherwise we send the final Tx-BRK
// worst case, we'll see an additional Rx-BRK... // worst case, we'll see an additional Rx-BRK...
// neither bus collision nor timeout - send terminating BRK signal // neither bus collision nor timeout - send terminating BRK signal
if (!(USIS(EMSUART_UART) & (1 << UIBD))) { if (!(USIS(EMSUART_UART) & (1 << UIBD))) {
// no bus collision - send terminating BRK signal // no bus collision - send terminating BRK signal
USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK> tx_brk();
uint16_t timeoutcnt = EMSUART_TX_TIMEOUT;
// wait until BRK detected...
while (!(USIR(EMSUART_UART) & (1 << UIBD)) && (--timeoutcnt > 0)) {
delayMicroseconds(EMSUART_TX_BUSY_WAIT);
}
USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear <BRK>
} }
// ETS_UART_INTR_ENABLE(); // open up the FIFO again to start receiving
ETS_UART_INTR_ENABLE(); // open up the FIFO again to start receiving sending_ = false;
return EMS_TX_STATUS_OK; // send the Tx ok status back return EMS_TX_STATUS_OK; // send the Tx ok status back
} }