diff --git a/components/app_console/CMakeLists.txt b/components/app_console/CMakeLists.txt index bc510cd..edaf434 100644 --- a/components/app_console/CMakeLists.txt +++ b/components/app_console/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRCS "app_console.c" INCLUDE_DIRS "." - PRIV_REQUIRES console wifi_cfg wifi_controller iperf nvs_flash) + PRIV_REQUIRES console wifi_cfg wifi_controller iperf nvs_flash gps_sync) diff --git a/components/app_console/app_console.c b/components/app_console/app_console.c index 4c92e46..77cd881 100644 --- a/components/app_console/app_console.c +++ b/components/app_console/app_console.c @@ -4,6 +4,7 @@ #include "argtable3/argtable3.h" #include "wifi_cfg.h" #include "iperf.h" +#include "gps_sync.h" #include "wifi_controller.h" #include "esp_wifi.h" #include "nvs.h" @@ -11,6 +12,7 @@ #include #include #include +#include // --- Helper: Prompt Update --- // Updates the "esp32>" vs "esp32*>" prompt based on dirty state @@ -127,7 +129,7 @@ static void register_nvs_cmd(void) { } // ============================================================================ -// COMMAND: gps (Configure GPS) +// COMMAND: gps (Configure & Status) // ============================================================================ static struct { struct arg_lit *enable; @@ -150,14 +152,13 @@ static int cmd_gps(int argc, char **argv) { } nvs_handle_t h; - // Open 'storage' namespace where iperf/system settings live esp_err_t err = nvs_open("storage", NVS_READWRITE, &h); if (err != ESP_OK) { printf("Error opening NVS: %s\n", esp_err_to_name(err)); return 1; } - // Handle Actions + // --- HANDLE SETTERS --- bool changed = false; if (gps_args.enable->count > 0) { nvs_set_u8(h, "gps_enabled", 1); @@ -169,18 +170,54 @@ static int cmd_gps(int argc, char **argv) { changed = true; } - // Commit if changed if (changed) nvs_commit(h); - // Read back status (Default is 1/True if key missing) + // --- DISPLAY STATUS --- + // 1. NVS State uint8_t val = 1; if (nvs_get_u8(h, "gps_enabled", &val) != ESP_OK) val = 1; - printf("GPS NVS State: %s\n", val ? "ENABLED" : "DISABLED"); - nvs_close(h); - // Refresh prompt dirty state if needed (though this setting requires reboot) + // 2. Runtime Status + if (val) { + gps_timestamp_t ts = gps_get_timestamp(); + int64_t pps_age = gps_get_pps_age_ms(); + + printf("Status: %s\n", ts.synced ? "SYNCED" : "SEARCHING"); + + // Print Raw NMEA --- + char nmea_buf[128]; + gps_get_last_nmea(nmea_buf, sizeof(nmea_buf)); + + // Remove trailing \r\n for cleaner printing + size_t len = strlen(nmea_buf); + if (len > 0 && (nmea_buf[len-1] == '\r' || nmea_buf[len-1] == '\n')) nmea_buf[len-1] = 0; + if (len > 1 && (nmea_buf[len-2] == '\r' || nmea_buf[len-2] == '\n')) nmea_buf[len-2] = 0; + + printf("Last NMEA: [%s]\n", nmea_buf); + // --------------------------- + + if (pps_age < 0) { + printf("PPS Signal: NEVER DETECTED\n"); + } else if (pps_age > 1100) { + printf("PPS Signal: LOST (Last seen %" PRId64 " ms ago)\n", pps_age); + } else { + printf("PPS Signal: ACTIVE (Age: %" PRId64 " ms)\n", pps_age); + } + + if (ts.gps_us > 0) { + time_t now_sec = ts.gps_us / 1000000; + struct tm tm_info; + gmtime_r(&now_sec, &tm_info); + char time_buf[64]; + strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S UTC", &tm_info); + printf("Current Time: %s\n", time_buf); + } else { + printf("Current Time: (System Epoch)\n"); + } + } + end_cmd(); return 0; } @@ -188,13 +225,13 @@ static int cmd_gps(int argc, char **argv) { static void register_gps_cmd(void) { gps_args.enable = arg_lit0(NULL, "enable", "Enable GPS"); gps_args.disable = arg_lit0(NULL, "disable", "Disable GPS"); - gps_args.status = arg_lit0(NULL, "status", "Show Config"); + gps_args.status = arg_lit0(NULL, "status", "Show Status"); gps_args.help = arg_lit0("h", "help", "Help"); gps_args.end = arg_end(2); const esp_console_cmd_t cmd = { .command = "gps", - .help = "Configure GPS (Enable/Disable)", + .help = "Configure GPS", .func = &cmd_gps, .argtable = &gps_args }; diff --git a/components/gps_sync/gps_sync.c b/components/gps_sync/gps_sync.c index 12c51c8..915a521 100644 --- a/components/gps_sync/gps_sync.c +++ b/components/gps_sync/gps_sync.c @@ -24,6 +24,7 @@ static bool gps_has_fix = false; static bool use_gps_for_logs = false; static SemaphoreHandle_t sync_mutex; static volatile bool force_sync_update = true; +static char s_last_nmea_line[128] = ""; // PPS interrupt // Stores the monotonic time of the rising edge of the PPS signal @@ -78,6 +79,15 @@ static bool parse_gprmc(const char* nmea, struct tm* tm_out, bool* valid) { return true; } +// --- PPS Age Getter --- +int64_t gps_get_pps_age_ms(void) { + if (last_pps_monotonic == 0) + return -1; // Never seen + + int64_t now = esp_timer_get_time(); + return (now - last_pps_monotonic) / 1000; +} + void gps_force_next_update(void) { force_sync_update = true; ESP_LOGW(TAG, "Requesting forced GPS sync update"); @@ -112,6 +122,13 @@ static void gps_task(void* arg) { if (data == '\n' || data == '\r') { if (pos > 0) { line[pos] = '\0'; + + // Read NMEA string over UART + xSemaphoreTake(sync_mutex, portMAX_DELAY); + strncpy(s_last_nmea_line, line, sizeof(s_last_nmea_line) - 1); + s_last_nmea_line[sizeof(s_last_nmea_line) - 1] = '\0'; + xSemaphoreGive(sync_mutex); + struct tm gps_tm; bool valid_fix; @@ -268,6 +285,14 @@ void gps_sync_init(const gps_sync_config_t *config, bool use_gps_log_timestamps) xTaskCreate(gps_task, "gps_task", 4096, NULL, 5, NULL); } +void gps_get_last_nmea(char *buf, size_t max_len) { + if (!buf || max_len == 0) return; + xSemaphoreTake(sync_mutex, portMAX_DELAY); + strncpy(buf, s_last_nmea_line, max_len); + buf[max_len - 1] = '\0'; + xSemaphoreGive(sync_mutex); +} + gps_timestamp_t gps_get_timestamp(void) { gps_timestamp_t ts; // Capture raw monotonic time diff --git a/components/gps_sync/gps_sync.h b/components/gps_sync/gps_sync.h index 1e5c10d..6ed0b85 100644 --- a/components/gps_sync/gps_sync.h +++ b/components/gps_sync/gps_sync.h @@ -23,8 +23,16 @@ typedef struct { void gps_sync_init(const gps_sync_config_t *config, bool use_gps_log_timestamps); void gps_force_next_update(void); + +// --- Getters --- gps_timestamp_t gps_get_timestamp(void); int64_t gps_get_monotonic_ms(void); bool gps_is_synced(void); + +// Check health of the physical PPS signal +int64_t gps_get_pps_age_ms(void); +void gps_get_last_nmea(char *buf, size_t max_len); + +// --- Logging Hooks --- uint32_t gps_log_timestamp(void); int gps_log_vprintf(const char *fmt, va_list args);