Files
ESP32C3-0.42OLED-OS/components/sys_core/sys_uart.c
T

192 lines
5.5 KiB
C

#include "sys_uart.h"
#include <string.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
static const char *TAG = "SYS_UART";
static uint8_t s_rx_ring[SYS_UART_BUFFER_SIZE];
static uint32_t s_rx_head = 0; /* Total lifetime received bytes (monotonic) */
static uint32_t s_tx_total = 0;
static uint32_t s_baud_rate = SYS_UART_DEFAULT_BAUD;
static SemaphoreHandle_t s_uart_mutex = NULL;
static bool s_initialized = false;
static void uart_rx_task(void *pvParameters)
{
uint8_t tmp_buf[256];
while (1) {
int len = uart_read_bytes(SYS_UART_NUM, tmp_buf, sizeof(tmp_buf), pdMS_TO_TICKS(20));
if (len > 0) {
if (xSemaphoreTake(s_uart_mutex, pdMS_TO_TICKS(50)) == pdTRUE) {
for (int i = 0; i < len; i++) {
s_rx_ring[s_rx_head % SYS_UART_BUFFER_SIZE] = tmp_buf[i];
s_rx_head++;
}
xSemaphoreGive(s_uart_mutex);
}
}
}
}
esp_err_t sys_uart_init(uint32_t baud_rate)
{
if (s_initialized) {
return ESP_OK;
}
if (baud_rate == 0) {
baud_rate = SYS_UART_DEFAULT_BAUD;
}
s_baud_rate = baud_rate;
s_uart_mutex = xSemaphoreCreateMutex();
if (!s_uart_mutex) {
ESP_LOGE(TAG, "Failed to create UART mutex");
return ESP_ERR_NO_MEM;
}
uart_config_t uart_config = {
.baud_rate = (int)s_baud_rate,
.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_DEFAULT,
};
esp_err_t err = uart_driver_install(SYS_UART_NUM, 1024, 1024, 0, NULL, 0);
if (err != ESP_OK) {
ESP_LOGE(TAG, "uart_driver_install failed: %s", esp_err_to_name(err));
return err;
}
err = uart_param_config(SYS_UART_NUM, &uart_config);
if (err != ESP_OK) {
ESP_LOGE(TAG, "uart_param_config failed: %s", esp_err_to_name(err));
return err;
}
err = uart_set_pin(SYS_UART_NUM, SYS_UART_PIN_TX, SYS_UART_PIN_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "uart_set_pin failed: %s", esp_err_to_name(err));
return err;
}
/* Enable internal pull-up on RX to prevent floating line noise / framing errors */
gpio_set_pull_mode(SYS_UART_PIN_RX, GPIO_PULLUP_ONLY);
gpio_pullup_en(SYS_UART_PIN_RX);
memset(s_rx_ring, 0, sizeof(s_rx_ring));
s_rx_head = 0;
s_tx_total = 0;
s_initialized = true;
xTaskCreate(uart_rx_task, "uart_rx_task", 3072, NULL, 5, NULL);
ESP_LOGI(TAG, "Hardware UART initialized on TX:GPIO%d, RX:GPIO%d @ %lu baud",
SYS_UART_PIN_TX, SYS_UART_PIN_RX, (unsigned long)s_baud_rate);
return ESP_OK;
}
esp_err_t sys_uart_set_baud_rate(uint32_t baud_rate)
{
if (!s_initialized || baud_rate == 0) return ESP_ERR_INVALID_STATE;
esp_err_t err = uart_set_baudrate(SYS_UART_NUM, baud_rate);
if (err == ESP_OK) {
s_baud_rate = baud_rate;
uart_flush_input(SYS_UART_NUM);
ESP_LOGI(TAG, "Baud rate changed to %lu", (unsigned long)baud_rate);
}
return err;
}
uint32_t sys_uart_get_baud_rate(void)
{
return s_baud_rate;
}
esp_err_t sys_uart_write(const uint8_t *data, size_t len)
{
if (!s_initialized || !data || len == 0) return ESP_ERR_INVALID_ARG;
int sent = uart_write_bytes(SYS_UART_NUM, data, len);
if (sent > 0) {
if (xSemaphoreTake(s_uart_mutex, pdMS_TO_TICKS(50)) == pdTRUE) {
s_tx_total += (uint32_t)sent;
xSemaphoreGive(s_uart_mutex);
}
return ESP_OK;
}
return ESP_FAIL;
}
esp_err_t sys_uart_write_str(const char *str)
{
if (!str) return ESP_ERR_INVALID_ARG;
return sys_uart_write((const uint8_t *)str, strlen(str));
}
size_t sys_uart_read_delta(uint32_t from_seq, uint8_t *out_buf, size_t max_len, uint32_t *new_seq)
{
if (!s_initialized || !out_buf || max_len == 0) {
if (new_seq) *new_seq = from_seq;
return 0;
}
size_t bytes_copied = 0;
if (xSemaphoreTake(s_uart_mutex, pdMS_TO_TICKS(50)) == pdTRUE) {
uint32_t current_head = s_rx_head;
if (from_seq > current_head) {
from_seq = current_head;
}
uint32_t available = current_head - from_seq;
if (available > SYS_UART_BUFFER_SIZE) {
/* Client is too far behind, catch up to buffer start */
from_seq = current_head - SYS_UART_BUFFER_SIZE;
available = SYS_UART_BUFFER_SIZE;
}
if (available > max_len) {
available = max_len;
}
for (size_t i = 0; i < available; i++) {
out_buf[i] = s_rx_ring[(from_seq + i) % SYS_UART_BUFFER_SIZE];
}
bytes_copied = available;
if (new_seq) {
*new_seq = from_seq + available;
}
xSemaphoreGive(s_uart_mutex);
} else {
if (new_seq) *new_seq = from_seq;
}
return bytes_copied;
}
void sys_uart_get_stats(uint32_t *rx_count, uint32_t *tx_count)
{
if (xSemaphoreTake(s_uart_mutex, pdMS_TO_TICKS(50)) == pdTRUE) {
if (rx_count) *rx_count = s_rx_head;
if (tx_count) *tx_count = s_tx_total;
xSemaphoreGive(s_uart_mutex);
} else {
if (rx_count) *rx_count = s_rx_head;
if (tx_count) *tx_count = s_tx_total;
}
}
void sys_uart_clear_rx_buffer(void)
{
if (xSemaphoreTake(s_uart_mutex, pdMS_TO_TICKS(50)) == pdTRUE) {
memset(s_rx_ring, 0, sizeof(s_rx_ring));
xSemaphoreGive(s_uart_mutex);
}
}