#include "uart_handler.h" #include "protocol.h" #include "driver/uart.h" #include "esp_log.h" #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "cJSON.h" #include #include static const char *TAG = "uart"; static SemaphoreHandle_t tx_mutex; /* Pin assignments -- keep UART0 free for ESP-IDF console/logging */ #define UART_TX_PIN GPIO_NUM_4 #define UART_RX_PIN GPIO_NUM_5 void uart_handler_init(void) { uart_config_t cfg = { .baud_rate = PROTO_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_ERROR_CHECK(uart_param_config(PROTO_UART_NUM, &cfg)); ESP_ERROR_CHECK(uart_set_pin(PROTO_UART_NUM, UART_TX_PIN, UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); ESP_ERROR_CHECK(uart_driver_install(PROTO_UART_NUM, PROTO_RX_BUF_SIZE, PROTO_TX_BUF_SIZE, 0, NULL, 0)); tx_mutex = xSemaphoreCreateMutex(); assert(tx_mutex); ESP_LOGI(TAG, "UART%d ready (TX=%d RX=%d @ %d baud)", PROTO_UART_NUM, UART_TX_PIN, UART_RX_PIN, PROTO_BAUD_RATE); } char *uart_read_line(void) { static char buf[PROTO_MAX_LINE]; int pos = 0; for (;;) { uint8_t byte; int n = uart_read_bytes(PROTO_UART_NUM, &byte, 1, portMAX_DELAY); if (n <= 0) { continue; } if (byte == '\n') { if (pos == 0) { continue; /* skip empty lines */ } buf[pos] = '\0'; return strdup(buf); } if (byte == '\r') { continue; /* ignore carriage returns */ } if (pos < PROTO_MAX_LINE - 1) { buf[pos++] = (char)byte; } else { /* line too long -- discard and reset */ ESP_LOGE(TAG, "line overflow (%d bytes), discarding", pos); pos = 0; } } } void uart_send_line(const char *json_line) { if (!json_line) { return; } xSemaphoreTake(tx_mutex, portMAX_DELAY); size_t len = strlen(json_line); uart_write_bytes(PROTO_UART_NUM, json_line, len); uart_write_bytes(PROTO_UART_NUM, "\n", 1); xSemaphoreGive(tx_mutex); } void uart_send_response(const char *id, const char *status, cJSON *data) { cJSON *root = cJSON_CreateObject(); cJSON_AddStringToObject(root, "type", MSG_TYPE_RESP); cJSON_AddStringToObject(root, "id", id); cJSON_AddStringToObject(root, "status", status); if (data) { cJSON_AddItemToObject(root, "data", data); } else { cJSON_AddObjectToObject(root, "data"); } char *out = cJSON_PrintUnformatted(root); uart_send_line(out); free(out); cJSON_Delete(root); } void uart_send_event(const char *event_name, cJSON *data) { int64_t ts_ms = esp_timer_get_time() / 1000; cJSON *root = cJSON_CreateObject(); cJSON_AddStringToObject(root, "type", MSG_TYPE_EVENT); cJSON_AddStringToObject(root, "event", event_name); if (data) { cJSON_AddItemToObject(root, "data", data); } else { cJSON_AddObjectToObject(root, "data"); } cJSON_AddNumberToObject(root, "ts", (double)ts_ms); char *out = cJSON_PrintUnformatted(root); uart_send_line(out); free(out); cJSON_Delete(root); }