#include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "freertos/semphr.h" #include "os/os.h" #include "uart_port.h" #include "drivers/chip/gpio.h" #include "driver/uart.h" #include "hal/uart_ll.h" #include "drivers/data_port/sb_data_port.h" #define CONFIG_SYS_LOG_DUMP_ON 0 #define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_WRN #define SYS_LOG_DOMAIN "UART" #include "sys_log.h" #define _MAX_UART_NUM 3 #define UART_IN_TAST_STK_SIZE 2304 typedef struct { uint16_t size; uint8_t data[0]; } __fifo_data_t; typedef struct { int uart_num; int baudrate; int tx_pin; int rx_pin; int rx_task_priority; uint16_t buffer_size; uint8_t frame_ms; volatile uint16_t buffer_used; os_work_t *rx_resume_work; QueueHandle_t event_queue; os_thread_t rx_thread_hdl; union { os_pipe_t rx_pipe; os_fifo_t rx_fifo; }; } __uart_data_t; static void _uart_rx_thread(void *parmas) { uart_event_t event; int ret = 0; int len = 0; int rx_len = 0; __uart_data_t *uart_data = ((sb_data_port_t *)parmas)->data; const uint32_t TMP_BUF_LEN = 1024; uint8_t tmpbuffer[TMP_BUF_LEN]; TickType_t tick = portMAX_DELAY; uint16_t recv_total = 0; os_time_t rx_time = 0; for (;;) { if (xQueueReceive(uart_data->event_queue, (void *)&event, tick)) { switch (event.type) { case UART_DATA: { rx_len = event.size; while (rx_len > 0) { if (uart_data->frame_ms == 0) { len = (rx_len > TMP_BUF_LEN) ? TMP_BUF_LEN : rx_len; ret = uart_read_bytes(uart_data->uart_num, tmpbuffer, len, portMAX_DELAY); if (ret <= 0) { break; } rx_len -= ret; // 将数据写入ringbuffer,由外部轮询ringbuffer uint8_t *p = tmpbuffer; for (int i = 0; i < 100 && ret != 0; i++) { int write_result = os_pipe_fifo_fill(&uart_data->rx_pipe, p, ret); p = &((uint8_t *)p)[write_result]; ret -= write_result; if (ret != 0) { os_thread_sleep(10); } } if (ret != 0) { SYS_LOG_ERR("write data to rx_pipe_obj failed, remain: %d bytes", ret); } } else { len = sizeof(tmpbuffer) - recv_total; if (len > rx_len) { len = rx_len; } ret = uart_read_bytes(uart_data->uart_num, &tmpbuffer[recv_total], len, portMAX_DELAY); if (ret <= 0) { break; } rx_len -= ret; recv_total += ret; if (recv_total >= sizeof(tmpbuffer)) { rx_time = os_get_sys_time() - uart_data->frame_ms - 1; // 使退出 switch 后的超时条件必定成立而立即保存数据 break; } rx_time = os_get_sys_time(); } } } break; // Event of HW FIFO overflow detected case UART_FIFO_OVF: SYS_LOG_WRN("hw fifo overflow"); // If fifo overflow happened, you should consider adding flow control for your application. // The ISR has already reset the rx FIFO, uart_flush_input(uart_data->uart_num); xQueueReset(uart_data->event_queue); break; // Event of UART ring buffer full case UART_BUFFER_FULL: SYS_LOG_WRN("ring buffer full"); // If buffer full happened, you should consider encreasing your buffer size uart_flush_input(uart_data->uart_num); xQueueReset(uart_data->event_queue); break; // Event of UART RX break detected case UART_BREAK: SYS_LOG_WRN("uart rx break"); break; // Event of UART parity check error case UART_PARITY_ERR: SYS_LOG_WRN("uart parity error"); break; // Event of UART frame error case UART_FRAME_ERR: SYS_LOG_WRN("uart frame error"); break; // Others default: SYS_LOG_WRN("uart event type: %d", event.type); break; } } if (uart_data->frame_ms != 0) { if (os_get_sys_time() - rx_time > uart_data->frame_ms) { if (recv_total > 0) { while (uart_data->buffer_used >= uart_data->buffer_size) { os_thread_sleep(1); } __fifo_data_t *fifo_data = os_fifo_alloc(sizeof(__fifo_data_t) + recv_total); if (fifo_data) { os_scheduler_suspend(); uart_data->buffer_used += recv_total + sizeof(((__fifo_data_t *)0)->size); os_scheduler_resume(); fifo_data->size = recv_total; memcpy(fifo_data->data, tmpbuffer, recv_total); os_fifo_put(&uart_data->rx_fifo, fifo_data); } recv_total = 0; tick = 1; } else { tick = portMAX_DELAY; } } else { tick = 1; } } } } static void uart_port_initialize(sb_data_port_t *port) { __uart_data_t *uart_data = port->data; uart_config_t uart_config; memset(&uart_config, 0, sizeof(uart_config)); uart_config.baud_rate = uart_data->baudrate; uart_config.data_bits = UART_DATA_8_BITS; uart_config.parity = UART_PARITY_DISABLE; uart_config.stop_bits = UART_STOP_BITS_1; uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; esp_err_t ret = uart_set_pin(uart_data->uart_num, uart_data->tx_pin, uart_data->rx_pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); if (ret != ESP_OK) { SYS_LOG_ERR("failed to set uart pin:%d, %d", uart_data->uart_num, ret); return; } ret = uart_param_config(uart_data->uart_num, &uart_config); if (ret != ESP_OK) { SYS_LOG_ERR("failed to set uart param:%d, %d", uart_data->uart_num, ret); return; } ret = uart_driver_install(uart_data->uart_num, 0x400, 0x400, 3, &(uart_data->event_queue), 0); if (ret != ESP_OK) { SYS_LOG_ERR("failed to uart_driver_install:%d, %d", uart_data->uart_num, ret); return; } uart_disable_intr_mask(uart_data->uart_num, UART_INTR_BRK_DET); // 关闭检测UART_BREAK中断,防止过多的UART_BREAK导致的程序异常 SYS_LOG_INF("uart_driver_install ok. (%d, %d, %d, %d, %d, %d)", uart_data->uart_num, 0x400, 0x400, 3, (uint32_t)&uart_data->event_queue, 0); } static int _uart_port_start(sb_data_port_t *port) { __uart_data_t *uart_data = port->data; SYS_LOG_INF("uart start, uartnum:%d", uart_data->uart_num); if (uart_data->frame_ms == 0) { if (!os_pipe_is_valid(&uart_data->rx_pipe)) { if (os_pipe_create(&uart_data->rx_pipe, uart_data->buffer_size) != OS_OK) { port->vtable->stop(port); return -1; } os_pipe_regist(&uart_data->rx_pipe, uart_data->rx_resume_work, 0); } } else { if (!os_fifo_q_is_valid(&uart_data->rx_fifo)) { if (os_fifo_q_create(&uart_data->rx_fifo) != OS_OK) { port->vtable->stop(port); return -1; } os_fifo_q_regist(&uart_data->rx_fifo, uart_data->rx_resume_work, 0); } uart_data->buffer_used = 0; } if (!uart_is_driver_installed(uart_data->uart_num)) { uart_port_initialize(port); } if (!os_thread_is_valid(&uart_data->rx_thread_hdl)) { if (os_thread_create(&uart_data->rx_thread_hdl, "uart_rx", _uart_rx_thread, port, UART_IN_TAST_STK_SIZE, uart_data->rx_task_priority) != OS_OK) { SYS_LOG_WRN("task create fail"); port->vtable->stop(port); return -1; } } return 0; } static int _uart_port_stop(sb_data_port_t *port) { __uart_data_t *uart_data = port->data; if (os_thread_is_valid(&uart_data->rx_thread_hdl)) { os_thread_delete(&uart_data->rx_thread_hdl); } if (uart_is_driver_installed(uart_data->uart_num)) { uart_driver_delete(uart_data->uart_num); } if (uart_data->frame_ms == 0) { if (os_pipe_is_valid(&uart_data->rx_pipe)) { os_pipe_delete(&uart_data->rx_pipe); } } else { if (os_fifo_q_is_valid(&uart_data->rx_fifo)) { os_fifo_q_delete(&uart_data->rx_fifo); } } return 0; } static int _uart_port_write(sb_data_port_t *port, const void *data, uint32_t size) { __uart_data_t *uart_data = port->data; int ret = uart_write_bytes(uart_data->uart_num, data, size); if (ret > 0) { SYS_LOG_DUMP(data, ret, 0, 0); } return ret; } static int _uart_port_read(sb_data_port_t *port, void *data, uint32_t size) { __uart_data_t *uart_data = port->data; int ret; if (uart_data->frame_ms == 0) { ret = os_pipe_fifo_read(&uart_data->rx_pipe, data, size); } else { __fifo_data_t *fifo_data = os_fifo_take(&uart_data->rx_fifo, 0); if (fifo_data) { ret = size < fifo_data->size ? size : fifo_data->size; if (data) { memcpy(data, fifo_data->data, ret); } os_fifo_free(fifo_data); os_scheduler_suspend(); uart_data->buffer_used -= ret + sizeof(((__fifo_data_t *)0)->size); os_scheduler_resume(); } else { ret = 0; } } if (ret > 0) { SYS_LOG_DUMP(data, ret, 0, 0); } return ret; } static bool _uart_port_is_start(sb_data_port_t *port) { if (port == NULL) { return false; } __uart_data_t *uart_data = port->data; if (uart_data == NULL) { return false; } if (uart_data->frame_ms == 0) { if (!os_pipe_is_valid(&uart_data->rx_pipe)) { return false; } } else { if (!os_fifo_q_is_valid(&uart_data->rx_fifo)) { return false; } } return true; } static uint32_t _uart_port_get_rx_length(sb_data_port_t *port) { __uart_data_t *uart_data = port->data; if (uart_data->frame_ms == 0) { return os_pipe_get_valid_size(&uart_data->rx_pipe); } else { __fifo_data_t *fifo_data = os_fifo_peek_head(&uart_data->rx_fifo); if (fifo_data) { return fifo_data->size; } else { return 0; } } } static sb_data_port_vtable_t const s_uart_vtable = { .start = _uart_port_start, .stop = _uart_port_stop, .write = _uart_port_write, .read = _uart_port_read, .is_started = _uart_port_is_start, .get_rx_length = _uart_port_get_rx_length, }; int sb_uart_port_init(void) { return 0; } /** * @brief * * @param uart_num 串口号 0..n * @param baudrate 波特率 * @param tx_pin TXD 引脚 * @param rx_pin RXD 引脚 * @param rx_task_priority 内部接收任务的优先级 * @param buffer_size 接收缓存大小 * @param frame_ms 0: 数据流, > 0: 最少连续有 n 毫秒没有收到数据时成为一帧 * @param rx_resume_work 当收到新数据时唤醒的工作项,可设置为 NULL * @return sb_data_port_t* */ sb_data_port_t *sb_uart_port_bind(int uart_num, int baudrate, int tx_pin, int rx_pin, int rx_task_priority, uint16_t buffer_size, uint8_t frame_ms, os_work_t *rx_resume_work) { static sb_data_port_t s_uart_port[_MAX_UART_NUM]; static __uart_data_t s_uart_data[_MAX_UART_NUM]; sb_data_port_t *port = &s_uart_port[uart_num]; __uart_data_t *uart_data = &s_uart_data[uart_num]; SYS_ASSERT(uart_num < _MAX_UART_NUM, ""); SYS_ASSERT(port->data == NULL, "The interface has already been bound"); // SYS_ASSERT(baudrate > 0, ""); uart_data->uart_num = uart_num; uart_data->baudrate = baudrate; uart_data->tx_pin = tx_pin; uart_data->rx_pin = rx_pin; uart_data->rx_task_priority = rx_task_priority; uart_data->buffer_size = buffer_size; uart_data->frame_ms = frame_ms; uart_data->rx_resume_work = rx_resume_work; port->vtable = &s_uart_vtable; port->data = uart_data; return port; } void sb_uart_port_unbind(sb_data_port_t *port) { if (_uart_port_is_start(port)) { _uart_port_stop(port); __uart_data_t *uart_data = port->data; drv_gpio_pin_configure(uart_data->tx_pin, _GPIO_DIR_IN, _GPIO_PUD_PULL_UP); drv_gpio_pin_configure(uart_data->rx_pin, _GPIO_DIR_IN, _GPIO_PUD_PULL_UP); port->data = NULL; } }