mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-11 18:29:52 +03:00
176 lines
5.9 KiB
C++
176 lines
5.9 KiB
C++
/*
|
|
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
|
* Copyright 2020-2023 Paul Derbyshire
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* ESP32 UART port by @ArwedL and improved by @MichaelDvP. See https://github.com/emsesp/EMS-ESP/issues/380
|
|
*/
|
|
|
|
#ifndef EMSESP_STANDALONE
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "freertos/queue.h"
|
|
#include "driver/uart.h"
|
|
#include "soc/uart_reg.h"
|
|
#include "uart/emsuart_esp32.h"
|
|
#include "emsesp.h"
|
|
|
|
namespace emsesp {
|
|
|
|
static QueueHandle_t uart_queue;
|
|
uint8_t tx_mode_ = 0xFF;
|
|
|
|
/*
|
|
* receive task, wait for break and call incoming_telegram
|
|
*/
|
|
void EMSuart::uart_event_task(void * pvParameters) {
|
|
uart_event_t event;
|
|
uint8_t telegram[EMS_MAXBUFFERSIZE];
|
|
uint8_t length = 0;
|
|
|
|
while (1) {
|
|
//Waiting for UART event.
|
|
if (xQueueReceive(uart_queue, (void *)&event, portMAX_DELAY)) {
|
|
if (event.type == UART_DATA) {
|
|
length += event.size;
|
|
} else if (event.type == UART_BREAK) {
|
|
if (length == 2 || (length >= 6 && length <= EMS_MAXBUFFERSIZE)) {
|
|
uart_read_bytes(EMSUART_NUM, telegram, length, portMAX_DELAY);
|
|
// if (telegram[0] && !telegram[length - 1]) {
|
|
EMSESP::incoming_telegram(telegram, (uint8_t)(length - 1));
|
|
// }
|
|
} else {
|
|
// flush buffer up to break
|
|
uint8_t buf[length];
|
|
uart_read_bytes(EMSUART_NUM, buf, length, portMAX_DELAY);
|
|
}
|
|
length = 0;
|
|
} else if (event.type == UART_BUFFER_FULL) {
|
|
uart_flush_input(EMSUART_NUM);
|
|
length = 0;
|
|
}
|
|
}
|
|
}
|
|
vTaskDelete(NULL);
|
|
}
|
|
|
|
/*
|
|
* init UART driver
|
|
*/
|
|
void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t tx_gpio) {
|
|
if (tx_mode_ == 0xFF) {
|
|
uart_config_t uart_config = {
|
|
.baud_rate = EMSUART_BAUD,
|
|
.data_bits = UART_DATA_8_BITS,
|
|
.parity = UART_PARITY_DISABLE,
|
|
.stop_bits = UART_STOP_BITS_1,
|
|
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
|
.source_clk = UART_SCLK_APB,
|
|
};
|
|
uart_param_config(EMSUART_NUM, &uart_config);
|
|
uart_set_pin(EMSUART_NUM, tx_gpio, rx_gpio, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
|
uart_driver_install(EMSUART_NUM, 129, 0, (EMS_MAXBUFFERSIZE + 1) * 2, &uart_queue, 0); // buffer must be > fifo
|
|
uart_set_rx_full_threshold(EMSUART_NUM, 1);
|
|
uart_set_rx_timeout(EMSUART_NUM, 0); // disable
|
|
|
|
// note esp32s3 crashes with 2k stacksize, stack overflow here sometimes wipes settingsfiles.
|
|
xTaskCreate(uart_event_task, "uart_event_task", 2560, NULL, configMAX_PRIORITIES - 1, NULL);
|
|
}
|
|
tx_mode_ = tx_mode;
|
|
uart_enable_intr_mask(EMSUART_NUM, UART_BRK_DET_INT_ENA | UART_RXFIFO_FULL_INT_ENA);
|
|
}
|
|
|
|
/*
|
|
* Stop, disable interrupt
|
|
*/
|
|
void EMSuart::stop() {
|
|
if (tx_mode_ != 0xFF) { // only call after driver initialisation
|
|
uart_disable_intr_mask(EMSUART_NUM, UART_BRK_DET_INT_ENA | UART_RXFIFO_FULL_INT_ENA);
|
|
// TODO should we xTaskSuspend() the event task here?
|
|
}
|
|
};
|
|
|
|
/*
|
|
* Sends a 1-byte poll, ending with a <BRK>
|
|
*/
|
|
void EMSuart::send_poll(const uint8_t data) {
|
|
transmit(&data, 1);
|
|
}
|
|
|
|
/*
|
|
* Send data to Tx line, ending with a <BRK>
|
|
* buf contains the CRC and len is #bytes including the CRC
|
|
* returns code, 1=success
|
|
*/
|
|
uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
|
|
if (len == 0 || len >= EMS_MAXBUFFERSIZE) {
|
|
return EMS_TX_STATUS_ERR;
|
|
}
|
|
|
|
if (tx_mode_ == 0) {
|
|
return EMS_TX_STATUS_OK;
|
|
}
|
|
|
|
if (tx_mode_ == EMS_TXMODE_HW) { // hardware controlled mode
|
|
uart_write_bytes_with_break(EMSUART_NUM, buf, len, 10);
|
|
return EMS_TX_STATUS_OK;
|
|
}
|
|
|
|
if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ with long delay
|
|
for (uint8_t i = 0; i < len; i++) {
|
|
uart_write_bytes(EMSUART_NUM, &buf[i], 1);
|
|
delayMicroseconds(EMSUART_TX_WAIT_PLUS);
|
|
}
|
|
uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV);
|
|
delayMicroseconds(EMSUART_TX_BRK_PLUS);
|
|
uart_set_line_inverse(EMSUART_NUM, 0);
|
|
return EMS_TX_STATUS_OK;
|
|
}
|
|
|
|
if (tx_mode_ == EMS_TXMODE_HT3) { // HT3 with 7 bittimes delay
|
|
for (uint8_t i = 0; i < len; i++) {
|
|
uart_write_bytes(EMSUART_NUM, &buf[i], 1);
|
|
delayMicroseconds(EMSUART_TX_WAIT_HT3);
|
|
}
|
|
uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV);
|
|
delayMicroseconds(EMSUART_TX_BRK_HT3);
|
|
uart_set_line_inverse(EMSUART_NUM, 0);
|
|
return EMS_TX_STATUS_OK;
|
|
}
|
|
|
|
// mode 1: wait for echo after each byte
|
|
for (uint8_t i = 0; i < len; i++) {
|
|
size_t rx0, rx1;
|
|
uart_get_buffered_data_len(EMSUART_NUM, &rx0);
|
|
uart_write_bytes(EMSUART_NUM, &buf[i], 1);
|
|
uint16_t timeoutcnt = EMSUART_TX_TIMEOUT;
|
|
do {
|
|
delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles...
|
|
uart_get_buffered_data_len(EMSUART_NUM, &rx1);
|
|
} while ((rx1 == rx0) && (--timeoutcnt));
|
|
}
|
|
uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV);
|
|
delayMicroseconds(EMSUART_TX_BRK_EMS);
|
|
uart_set_line_inverse(EMSUART_NUM, 0);
|
|
return EMS_TX_STATUS_OK;
|
|
}
|
|
|
|
} // namespace emsesp
|
|
|
|
#endif
|