| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- /*
- * GPS Test Tool - PC Application
- *
- * Tests GPS filtering and GPX generation using actual embedded code
- * Usage: ./gps-test-tool <input.nmea>
- *
- * Generates:
- * - output_filtered.gpx
- * - output_unfiltered.gpx
- * - debug_filtered.txt
- * - debug_unfiltered.txt
- */
- #define PC_BUILD
- #include "main.h"
- /* Global variables expected by project code */
- volatile struct system_s System;
- struct location_s location;
- time_t utc;
- unsigned char FLAGS = 0;
- volatile unsigned char reset_cause = 0; /* no real MCU reset happened; log_boot_record() reports "UNKNOWN" */
- /* File handle for debug output redirection */
- FILE *debug_output = NULL;
- /* soft/syslog.c's log_config()/log_boot_record() print these; not part of
- * this PC build otherwise (they're normally in soft/settings.c). */
- __flash const char gnss_name_stub[] = "GPS+GLONASS+GALILEO/etc (PC test tool - not tracked per mode)";
- __flash const char *gnss_names[] = {
- gnss_name_stub, gnss_name_stub, gnss_name_stub,
- gnss_name_stub, gnss_name_stub, gnss_name_stub,
- };
- __flash const char uart_log_mode_stub[] = "n/a (PC test tool)";
- __flash const char *uart_log_mode_names[] = {
- uart_log_mode_stub, uart_log_mode_stub, uart_log_mode_stub,
- };
- /* Function prototypes from project files */
- unsigned char gpx_init(FIL *file);
- unsigned char gpx_close(FIL *file);
- void gpx_process_point(struct location_s *loc, FIL *file);
- void gpx_reset_gap(void);
- time_t gps_parse(const char *nmea);
- /* Time function implementation */
- char *get_iso_time(time_t time, unsigned char local) {
- static char output[32];
- struct tm *ct = gmtime(&time);
- sprintf(output, "%04d-%02d-%02dT%02d:%02d:%02d.000Z",
- ct->tm_year + 1900, ct->tm_mon + 1, ct->tm_mday,
- ct->tm_hour, ct->tm_min, ct->tm_sec);
- return output;
- }
- void iso_time_to_filename(char *time) {
- while (*time) {
- switch (*time) {
- case ':': *time = '-'; break;
- case '+': *time = 'p'; break;
- }
- time++;
- }
- }
- /* Reset system state */
- void reset_system(void) {
- memset((void*)&System, 0, sizeof(System));
- memset(&location, 0, sizeof(location));
- System.conf.skip_points = 0; /* Don't skip points for testing */
- /* Match soft/settings.c's defaults_u8, so this tool's auto-pause behavior
- * (enabled below) matches an out-of-the-box device. */
- System.conf.auto_pause_time = 30;
- System.conf.auto_pause_dist = 10;
- System.conf.auto_pause_speed = 3;
- System.conf.min_sats = 4; /* Require at least 4 satellites */
- System.tracking_paused = 0;
- System.tracking_auto_paused = 0;
- System.bat_volt = 4.0f; /* no real ADC here; keeps the status line's v=/bat%= fields sane */
- System.bat_volt_min = 4.0f;
- utc = 0;
- }
- /* Process NMEA file with specified filter setting */
- int process_nmea_file(const char *input_file, const char *output_gpx,
- const char *debug_file, int filters_enabled) {
- FILE *input;
- FIL gpx_file;
- char line[256];
- int point_count = 0;
- /* Open input file */
- input = fopen(input_file, "r");
- if (!input) {
- fprintf(stderr, "Error: Cannot open input file '%s'\n", input_file);
- return 1;
- }
- /* Open debug output file */
- debug_output = fopen(debug_file, "w");
- if (!debug_output) {
- fprintf(stderr, "Error: Cannot open debug file '%s'\n", debug_file);
- fclose(input);
- return 1;
- }
- /* Reset system state */
- reset_system();
- /* Configure filters */
- set_flag(CONFFLAG_DISABLE_FILTERS, !filters_enabled);
- set_flag(CONFFLAG_AUTO_PAUSE, 1);
- gps_powered_on();
- log_boot_record();
- /* Open GPX output file */
- if (f_open(&gpx_file, output_gpx, FA_WRITE | FA_OPEN_ALWAYS) != 0) {
- fprintf(stderr, "Error: Cannot open GPX file '%s'\n", output_gpx);
- fclose(input);
- fclose(debug_output);
- return 1;
- }
- /* Initialize GPX file */
- if (gpx_init(&gpx_file) != 0) {
- fprintf(stderr, "Error: GPX initialization failed\n");
- fclose(input);
- fclose(debug_output);
- f_close(&gpx_file);
- return 1;
- }
- fprintf(debug_output, "=== GPS Test Tool - %s ===\n",
- filters_enabled ? "FILTERS ENABLED" : "FILTERS DISABLED");
- fprintf(debug_output, "Input: %s\n", input_file);
- fprintf(debug_output, "Output: %s\n\n", output_gpx);
- /* Process NMEA file line by line */
- /* Kept in sync with soft/main.c's FIX_HOLD_EPOCHS. */
- #define FIX_HOLD_EPOCHS 5
- unsigned char fix_ok_prev = 0;
- unsigned char fix_hold_counter = 0;
- unsigned char dgps_prev = 0xFF; /* 0xFF: not yet known, suppress the first (non-)transition */
- time_t next_status_utc = 0;
- time_t next_summary_utc = 0;
- while (fgets(line, sizeof(line), input)) {
- size_t len = strlen(line);
- /* Skip empty lines */
- if (len == 0) continue;
- /* Ensure line ends with \r\n as expected by gps_parse */
- if (len > 0 && line[len-1] == '\n') {
- line[len-1] = '\0';
- len--;
- }
- if (len > 0 && line[len-1] == '\r') {
- line[len-1] = '\0';
- len--;
- }
- /* Add back \r\n for gps_parse, bounded: fgets can fill line[] to
- * capacity with no trailing newline, leaving no room for it. */
- if (len + 2 >= sizeof(line))
- len = sizeof(line) - 3;
- line[len] = '\0';
- strcat(line, "\r\n");
- /* Parse NMEA sentence */
- if (gps_parse(line) != 0) {
- /* Valid location data received (RMC parsed) */
- /* Only process if we have valid coordinates from GGA */
- if (System.location_valid == LOC_VALID_NEW || System.location_valid == LOC_VALID) {
- if (fix_gap_detected(location.time)) {
- auto_pause_reset_gap();
- gpx_reset_gap();
- }
- auto_pause_process();
- gpx_process_point(&location, &gpx_file);
- point_count++;
- }
- }
- /* Mirror soft/main.c's system-log event/status triggers, so this
- * tool exercises and lets you review the same log output the
- * firmware produces. There's no real clock here, so pace the
- * periodic status line/session summary off the NMEA timestamps
- * instead of uptime. */
- if (utc) {
- if (nmea_epoch_complete()) {
- unsigned char fix_ok_now = (FLAGS & F_GPSOK) && !System.sat_count_low;
- if (fix_ok_now == fix_ok_prev) {
- fix_hold_counter = 0;
- } else if (++fix_hold_counter >= FIX_HOLD_EPOCHS) {
- fix_hold_counter = 0;
- fix_ok_prev = fix_ok_now;
- if (fix_ok_now)
- log_fix_event();
- else
- log_fix_lost();
- }
- }
- if (System.dgps != dgps_prev) {
- if (dgps_prev != 0xFF)
- log_dgps_transition();
- dgps_prev = System.dgps;
- }
- if (!next_status_utc)
- next_status_utc = utc + 60;
- if (utc >= next_status_utc) {
- log_status_line();
- next_status_utc = utc + 60;
- }
- if (!next_summary_utc)
- next_summary_utc = utc + 3600;
- if (utc >= next_summary_utc) {
- log_session_summary(0);
- next_summary_utc = utc + 3600;
- }
- }
- }
- /* Close GPX file */
- gpx_close(&gpx_file);
- log_session_summary(1);
- /* Print summary */
- {
- unsigned int moving = get_logging_time();
- unsigned long int stopped = get_pause_time();
- /* points_accepted counts every point past all reject checks, at
- * AVG_COUNT=3 samples per written trkpt with filters enabled (1:1
- * with filters disabled, so this is 0 in that mode). */
- unsigned long int averaged_out = System.points_accepted - System.points_written *
- (filters_enabled ? 3UL : 1UL);
- fprintf(debug_output, "\n=== Summary ===\n");
- fprintf(debug_output, "Points processed: %d\n", point_count);
- fprintf(debug_output, "Points during pauses: %lu\n", System.points_paused);
- fprintf(debug_output, "Points skipped (warm-up): %lu\n", System.points_skipped);
- fprintf(debug_output, "Points rejected: %lu\n", System.rejected_count);
- fprintf(debug_output, "Points averaged out: %lu\n", averaged_out);
- fprintf(debug_output, "Points saved: %lu\n", System.points_written);
- fprintf(debug_output, "Total distance: %.2f km\n", System.distance / 100000.0);
- fprintf(debug_output, "Elevation gain: %.1f m\n", System.elevation_gain / 10.0);
- fprintf(debug_output, "Elevation loss: %.1f m\n", System.elevation_loss / 10.0);
- fprintf(debug_output, "Moving time: %uh%02um\n", moving/3600, (moving/60)%60);
- fprintf(debug_output, "Stopped time: %luh%02lum\n", stopped/3600, (stopped/60)%60);
- fprintf(debug_output, "Average speed: %.2f km/h\n", get_avg_speed_x100()/100.0);
- fprintf(debug_output, "Average speed (dist/time): %.2f km/h\n", get_dist_avg_speed_x100()/100.0);
- }
- /* Close files */
- fclose(input);
- fclose(debug_output);
- debug_output = NULL;
- printf("Processed %d points -> %s (filters %s)\n",
- point_count, output_gpx, filters_enabled ? "ON" : "OFF");
- return 0;
- }
- int main(int argc, char *argv[]) {
- int ret;
- printf("GPS Test Tool v1.0\n");
- printf("==================\n\n");
- if (argc != 2) {
- fprintf(stderr, "Usage: %s <input.nmea>\n", argv[0]);
- fprintf(stderr, "\nGenerates:\n");
- fprintf(stderr, " - output_filtered.gpx\n");
- fprintf(stderr, " - output_unfiltered.gpx\n");
- fprintf(stderr, " - debug_filtered.txt\n");
- fprintf(stderr, " - debug_unfiltered.txt\n");
- return 1;
- }
- /* Process with filters enabled */
- printf("Processing with filters ENABLED...\n");
- ret = process_nmea_file(argv[1], "output_filtered.gpx",
- "debug_filtered.txt", 1);
- if (ret != 0) {
- fprintf(stderr, "Failed to process with filters enabled\n");
- return ret;
- }
- /* Process with filters disabled */
- printf("Processing with filters DISABLED...\n");
- ret = process_nmea_file(argv[1], "output_unfiltered.gpx",
- "debug_unfiltered.txt", 0);
- if (ret != 0) {
- fprintf(stderr, "Failed to process with filters disabled\n");
- return ret;
- }
- printf("\nProcessing complete!\n");
- printf("Generated files:\n");
- printf(" - output_filtered.gpx (filters ON)\n");
- printf(" - output_unfiltered.gpx (filters OFF)\n");
- printf(" - debug_filtered.txt (debug output with filters)\n");
- printf(" - debug_unfiltered.txt (debug output without filters)\n");
- return 0;
- }
|