315 lines
9.2 KiB
C
315 lines
9.2 KiB
C
#include "uart_comms.h"
|
|
#include "comms.h"
|
|
#include "bringup.h"
|
|
#include "cJSON.h"
|
|
#include "driver/uart.h"
|
|
#include "esp_log.h"
|
|
#include "esp_system.h"
|
|
#include "esp_task_wdt.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "rtc.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#define TAG "UART"
|
|
|
|
#define UART_NUM UART_NUM_0
|
|
#define BUF_SIZE (1024)
|
|
#define CMD_MAX_LEN (2048)
|
|
|
|
static char cmd_buffer[CMD_MAX_LEN];
|
|
static int cmd_pos = 0;
|
|
static TaskHandle_t uart_task_handle = NULL;
|
|
|
|
// Process GET command
|
|
static void cmd_get(void) {
|
|
printf("\n");
|
|
|
|
cJSON *response = comms_handle_get();
|
|
if (response == NULL) {
|
|
printf("ERROR: Failed to generate GET response\n");
|
|
return;
|
|
}
|
|
|
|
// Pretty print the JSON
|
|
char *json_str = cJSON_Print(response);
|
|
cJSON_Delete(response);
|
|
|
|
if (json_str == NULL) {
|
|
printf("ERROR: Failed to serialize JSON\n");
|
|
return;
|
|
}
|
|
|
|
printf("%s\n", json_str);
|
|
free(json_str);
|
|
}
|
|
|
|
// Process POST command with JSON data
|
|
static void cmd_post(char *json_data) {
|
|
printf("\n");
|
|
|
|
// Parse the JSON input
|
|
cJSON *request = cJSON_Parse(json_data);
|
|
if (request == NULL) {
|
|
const char *error_ptr = cJSON_GetErrorPtr();
|
|
if (error_ptr != NULL) {
|
|
printf("ERROR: JSON parse error before: %s\n", error_ptr);
|
|
} else {
|
|
printf("ERROR: Failed to parse JSON\n");
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Call the unified POST handler
|
|
cJSON *response = NULL;
|
|
(void)comms_handle_post(request, &response);
|
|
cJSON_Delete(request);
|
|
|
|
if (response == NULL) {
|
|
printf("ERROR: Failed to generate POST response\n");
|
|
return;
|
|
}
|
|
|
|
// Pretty print the response
|
|
char *json_str = cJSON_Print(response);
|
|
|
|
// Check for special response flags before deleting
|
|
cJSON *reboot_flag = cJSON_GetObjectItem(response, "reboot");
|
|
cJSON *sleep_flag = cJSON_GetObjectItem(response, "sleep");
|
|
bool should_reboot = cJSON_IsTrue(reboot_flag);
|
|
bool should_sleep = cJSON_IsTrue(sleep_flag);
|
|
|
|
cJSON_Delete(response);
|
|
|
|
if (json_str == NULL) {
|
|
printf("ERROR: Failed to serialize JSON\n");
|
|
return;
|
|
}
|
|
|
|
printf("%s\n", json_str);
|
|
free(json_str);
|
|
|
|
// Handle special actions
|
|
if (should_reboot) {
|
|
printf("\nRebooting in 2 seconds...\n");
|
|
fflush(stdout);
|
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
|
esp_restart();
|
|
}
|
|
|
|
if (should_sleep) {
|
|
printf("\nEntering soft idle in 2 seconds...\n");
|
|
fflush(stdout);
|
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
|
soft_idle_enter();
|
|
}
|
|
}
|
|
|
|
// Process help command
|
|
static void cmd_help(void) {
|
|
printf("\n=== UART JSON Interface ===\n");
|
|
printf("\nCommands:\n");
|
|
printf(" GET - Get complete system status (JSON)\n");
|
|
printf(" POST: {json} - Send command or update parameters (JSON)\n");
|
|
printf(" RTCDEBUG - Dump RTC timekeeping state (time, backup, sleep entry, clock source)\n");
|
|
printf(" HELP - Show this help\n");
|
|
printf("\nPOST JSON Format:\n");
|
|
printf("{\n");
|
|
printf(" \"time\": 1234567, // Set RTC time (optional)\n");
|
|
printf(" \"remaining_dist\": 100, // Set remaining distance (optional)\n");
|
|
printf(" \"cmd\": \"start\", // Execute command (optional)\n");
|
|
printf(" \"parameters\": { // Update parameters (optional)\n");
|
|
printf(" \"PARAM_NAME\": value,\n");
|
|
printf(" \"PARAM_NAME2\": value\n");
|
|
printf(" }\n");
|
|
printf("}\n");
|
|
printf("\nAvailable Commands:\n");
|
|
printf(" start, stop, undo, fwd, rev, up, down, aux\n");
|
|
printf(" reboot, sleep\n");
|
|
printf(" rf_learn, rf_clear_temp, rf_disable, rf_enable, rf_status\n");
|
|
printf(" cal_jack_start, cal_jack_finish, cal_drive_start, cal_drive_finish, cal_get\n");
|
|
printf("\nExamples:\n");
|
|
printf(" GET\n");
|
|
printf(" POST: {\"cmd\":\"start\"}\n");
|
|
printf(" POST: {\"time\":1704067200}\n");
|
|
printf(" POST: {\"parameters\":{\"WIFI_SSID\":\"MyNetwork\",\"WIFI_CHANNEL\":6}}\n");
|
|
printf(" POST: {\"cmd\":\"rf_learn\",\"channel\":0}\n");
|
|
printf("\n");
|
|
}
|
|
|
|
// Parse and execute command
|
|
static void process_command(char *cmd) {
|
|
// Trim leading whitespace
|
|
while (*cmd == ' ' || *cmd == '\t') {
|
|
cmd++;
|
|
}
|
|
|
|
// Ignore empty commands
|
|
if (*cmd == '\0') {
|
|
return;
|
|
}
|
|
|
|
// Route bring-up traffic to the BU parser. BU.BEGIN flips the mode flag
|
|
// so the subsequent lines in the same session come here too.
|
|
if (bringup_mode_is_active() ||
|
|
strncasecmp(cmd, "BU.", 3) == 0) {
|
|
bringup_handle_line(cmd);
|
|
return;
|
|
}
|
|
|
|
// Convert to uppercase for command matching
|
|
char command[16] = {0};
|
|
int i = 0;
|
|
while (cmd[i] && cmd[i] != ' ' && cmd[i] != '\t' && cmd[i] != ':' && i < 15) {
|
|
command[i] = (cmd[i] >= 'a' && cmd[i] <= 'z') ? (cmd[i] - 32) : cmd[i];
|
|
i++;
|
|
}
|
|
command[i] = '\0';
|
|
|
|
// Execute command
|
|
if (strcmp(command, "GET") == 0) {
|
|
cmd_get();
|
|
}
|
|
else if (strcmp(command, "POST") == 0) {
|
|
// Find the start of JSON data (after ':')
|
|
char *json_start = strchr(cmd, ':');
|
|
if (json_start == NULL) {
|
|
printf("ERROR: POST command requires JSON data after ':'\n");
|
|
printf("Usage: POST: {json data}\n");
|
|
return;
|
|
}
|
|
json_start++; // Skip the ':'
|
|
|
|
// Trim whitespace
|
|
while (*json_start == ' ' || *json_start == '\t') {
|
|
json_start++;
|
|
}
|
|
|
|
if (*json_start == '\0') {
|
|
printf("ERROR: No JSON data provided\n");
|
|
return;
|
|
}
|
|
|
|
cmd_post(json_start);
|
|
}
|
|
else if (strcmp(command, "HELP") == 0) {
|
|
cmd_help();
|
|
}
|
|
else if (strcmp(command, "RTCDEBUG") == 0) {
|
|
rtc_print_debug();
|
|
}
|
|
else {
|
|
printf("ERROR: Unknown command '%s'\n", command);
|
|
printf("Type 'HELP' for available commands\n");
|
|
}
|
|
}
|
|
|
|
// UART event task
|
|
void uart_event_task(void *pvParameters) {
|
|
esp_task_wdt_add(NULL);
|
|
uint8_t data[BUF_SIZE];
|
|
|
|
while (1) {
|
|
esp_task_wdt_reset();
|
|
int len = uart_read_bytes(UART_NUM, data, BUF_SIZE - 1, 20 / portTICK_PERIOD_MS);
|
|
|
|
if (len > 0) {
|
|
for (int i = 0; i < len; i++) {
|
|
char c = (char)data[i];
|
|
bool quiet = bringup_mode_is_active();
|
|
|
|
// Echo character (suppressed in bring-up mode — machine-parseable output)
|
|
if (!quiet) { printf("%c", c); fflush(stdout); }
|
|
|
|
// Handle backspace
|
|
if (c == '\b' || c == 127) {
|
|
if (cmd_pos > 0) {
|
|
cmd_pos--;
|
|
if (!quiet) { printf(" \b"); fflush(stdout); }
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Handle newline/carriage return
|
|
if (c == '\n' || c == '\r') {
|
|
cmd_buffer[cmd_pos] = '\0';
|
|
if (!quiet) printf("\n");
|
|
|
|
if (cmd_pos > 0) {
|
|
process_command(cmd_buffer);
|
|
}
|
|
|
|
cmd_pos = 0;
|
|
if (!bringup_mode_is_active()) {
|
|
printf("\n> ");
|
|
fflush(stdout);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Add to buffer if not full
|
|
if (cmd_pos < CMD_MAX_LEN - 1) {
|
|
cmd_buffer[cmd_pos++] = c;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
esp_err_t uart_init(void) {
|
|
// Configure UART
|
|
uart_config_t uart_config = {
|
|
.baud_rate = 115200,
|
|
.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_driver_install(UART_NUM, BUF_SIZE * 2, 0, 0, NULL, 0));
|
|
ESP_ERROR_CHECK(uart_param_config(UART_NUM, &uart_config));
|
|
|
|
// Print startup message
|
|
printf("\n\n");
|
|
printf("========================================\n");
|
|
printf(" UART JSON Interface Ready\n");
|
|
printf("========================================\n");
|
|
printf("Type 'HELP' for available commands\n");
|
|
printf("Type 'GET' to see system status\n");
|
|
printf("\n> ");
|
|
fflush(stdout);
|
|
|
|
// Create UART task
|
|
xTaskCreate(uart_event_task, "uart_event_task", 4096, NULL, 12, &uart_task_handle);
|
|
|
|
ESP_LOGI(TAG, "UART interface started");
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t uart_stop(void) {
|
|
if (uart_task_handle == NULL) {
|
|
ESP_LOGW(TAG, "UART task not running");
|
|
return ESP_OK;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Shutting down UART...");
|
|
|
|
// Wait for UART TX to finish
|
|
uart_wait_tx_done(UART_NUM, pdMS_TO_TICKS(100));
|
|
|
|
// Delete the UART task
|
|
vTaskDelete(uart_task_handle);
|
|
uart_task_handle = NULL;
|
|
|
|
// Small delay to ensure task deletion completes
|
|
vTaskDelay(pdMS_TO_TICKS(10));
|
|
|
|
// Disable UART driver
|
|
uart_driver_delete(UART_NUM);
|
|
|
|
ESP_LOGI(TAG, "UART shutdown complete");
|
|
|
|
return ESP_OK;
|
|
} |