123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- #include "kbf/uart.h"
- #include <string_view>
- #include <esp_log.h>
- #include <driver/uart.h>
- #include <freertos/FreeRTOS.h>
- #include <freertos/queue.h>
- #include "kbf.h"
- #include "kbf/macros.h"
- using std::string_view;
- using namespace kbf;
- UART::UART(int port, int baudRate) : port(port) {
- ESP_LOGI(TAG, "UART(%d, %d)", port, baudRate);
- if (isDriverInstalled(port)) {
- ABORT("UART driver already installed");
- }
- CHECK(uart_driver_install(port, BUFFER_SIZE, 0, 20, &queue, 0));
- uart_config_t config = {
- .baud_rate = baudRate,
- .data_bits = UART_DATA_8_BITS,
- .parity = UART_PARITY_DISABLE,
- .stop_bits = UART_STOP_BITS_1,
- .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
- .rx_flow_ctrl_thresh = 0,
- .source_clk = UART_SCLK_APB,
- };
- CHECK(uart_param_config(port, &config));
- CHECK(uart_set_pin(port, NO_CHANGE, NO_CHANGE, NO_CHANGE, NO_CHANGE));
- task = new rtos::Task("kbf_uart_" + std::to_string(port), taskFunc, this);
- }
- UART::~UART() {
- ESP_LOGI(TAG, "~UART()");
- esp_err_t err = uart_wait_tx_done(port, WAIT_ON_DESTROY);
- if (err == ESP_ERR_TIMEOUT) {
- ESP_LOGE(TAG, "UART TX not done! Data will be corrupted.");
- } else {
- CHECK_ABORT(err);
- }
- CHECK_ABORT(uart_driver_delete(port));
- }
- void UART::setPins(int rx, int tx, int rts, int cts) const {
- CHECK(uart_set_pin(port, rx, tx, rts, cts));
- }
- bool UART::isDriverInstalled(int port) {
- return uart_is_driver_installed(port);
- }
- void UART::write(const string &data) const {
- ESP_LOGD(TAG, "write(%s); len = %d", data.c_str(), data.size() + 1);
- auto len = uart_write_bytes(port, data.c_str(), data.size() + 1);
- if (len < 0) {
- ESP_LOGE(TAG, "uart_write_bytes returned %d", len);
- return;
- }
- if (len != data.length() + 1) {
- ESP_LOGE(TAG, "sent bytes < data.length()");
- throw kbf::exception::KBFError("UART buffering support not yet implemented");
- }
- }
- string UART::read() {
- ESP_LOGI(TAG, "read()");
- mutex.lock();
- buffer.clear();
- mutex.unlock();
- while (true) {
- // TODO this barely works; either use select or RTOS signals
- mutex.lock();
- if (!buffer.empty()) break;
- mutex.unlock();
- sleep(200); // FIXME keeps the tests from failing... *sad face*
- }
- return buffer;
- }
- void UART::waitFor(const string &signal) {
- while (read() != signal);
- }
- [[noreturn]] void UART::taskFunc(void *uartInstance) {
- auto uart = static_cast<UART *>(uartInstance);
- uart_event_t event;
- while (true) {
- if (xQueueReceive(uart->queue, &event, portMAX_DELAY) == pdFALSE) continue;
- ESP_LOGD(TAG, "event: %d", event.type);
- if (event.type == UART_DATA) {
- if (event.size > BUFFER_SIZE) {
- ESP_LOGE(TAG, "event size (%d) > buffer size (%d)", event.size, BUFFER_SIZE);
- throw kbf::exception::KBFError("fix me");
- }
- auto buf = new char[BUFFER_SIZE];
- int len = uart_read_bytes(uart->port, buf, event.size, portMAX_DELAY);
- if (len < 0) CHECK(len);
- ESP_LOGD(TAG, "read %d bytes", len);
- uart->mutex.lock();
- uart->buffer = buf;
- if (uart->onRead) uart->onRead(uart->buffer, *uart);
- uart->mutex.unlock();
- } else {
- ESP_LOGW(TAG, "unhandled event: %d", event.type);
- }
- }
- }
|