瀏覽代碼

Track pause state via tracking_is_paused(), harden GGA/auto-pause edge cases

- Add tracking_is_paused() and use it everywhere pause state was
  re-derived from System.tracking_paused/tracking_auto_paused directly
- Move per-epoch GGA/GSA/logged tracking out of System into a static
  struct local to nmea.c (partial parse state, not global data)
- Bail out of gp_gga_parse() early on any missing NMEA field instead of
  reading past a short/malformed sentence
- Split gps_settings_changed() out of gps_initialize() so the SBAS/GNSS
  settings menu can apply a change immediately instead of re-running the
  module boot sequence
- Cap auto_pause.anchor_sample_count so it can't wrap around and corrupt
  the running average
- Gate auto-pause's own pause decision on gps_fix_trustworthy(), matching
  the resume checks
- Run auto_pause_process() before gpx_process_point() so a pause/resume
  decision is made before the point using it is written
- Widen format_time()'s seconds argument to unsigned long (soft/display.c)
- Mirror all of the above in gps-test-tool's PC build, plus bound the
  \r\n append against fgets() filling the line buffer to capacity
k4be 1 周之前
父節點
當前提交
36f399eae4
共有 10 個文件被更改,包括 127 次插入 和 71 次删除
  1. 6 2
      gps-test-tool/main.c
  2. 4 3
      gps-test-tool/main.h
  3. 13 3
      soft/autopause.c
  4. 2 2
      soft/display.c
  5. 7 7
      soft/gpx.c
  6. 5 1
      soft/main.c
  7. 1 3
      soft/main.h
  8. 86 47
      soft/nmea.c
  9. 1 1
      soft/nmea.h
  10. 2 2
      soft/settings.c

+ 6 - 2
gps-test-tool/main.c

@@ -157,7 +157,11 @@ int process_nmea_file(const char *input_file, const char *output_gpx,
             line[len-1] = '\0';
             len--;
         }
-        /* Add back \r\n for gps_parse */
+        /* 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 */
@@ -165,8 +169,8 @@ int process_nmea_file(const char *input_file, const char *output_gpx,
             /* 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) {
-                gpx_process_point(&location, &gpx_file);
                 auto_pause_process();
+                gpx_process_point(&location, &gpx_file);
                 point_count++;
             }
         }

+ 4 - 3
gps-test-tool/main.h

@@ -240,9 +240,6 @@ struct system_s {
     unsigned sat_count_low:1;
     unsigned sbas:1;
     unsigned satellites_used:5;
-    unsigned epoch_gga_ok:1;
-    unsigned epoch_gsa_ok:1;
-    unsigned epoch_logged:1;
 };
 
 /* Location structure */
@@ -282,6 +279,10 @@ static inline unsigned char get_flag(unsigned char flag) {
  * calls into them. */
 unsigned char is_paused(void); /* soft/gpx.c, via gpx_wrapper.c */
 
+static inline unsigned char tracking_is_paused(void) {
+    return System.tracking_paused || System.tracking_auto_paused;
+}
+
 static inline time_t get_pause_time(void) {
     time_t res = System.pause_time;
     if (System.current_pause_start < System.time_start)

+ 13 - 3
soft/autopause.c

@@ -104,7 +104,12 @@ void auto_pause_process(void) {
 		if (hdop_threshold_m > resume_threshold_m)
 			resume_threshold_m = hdop_threshold_m;
 
-		auto_pause.anchor_sample_count++;
+		/* Capped well below the 16-bit wraparound point: once the running
+		 * average has this many samples behind it, one more changes it
+		 * negligibly anyway, and letting the count wrap to 0 would make the
+		 * very next sample overwrite the whole average with itself. */
+		if (auto_pause.anchor_sample_count < 60000)
+			auto_pause.anchor_sample_count++;
 		auto_pause.pause_anchor.lat += (location.lat - auto_pause.pause_anchor.lat) / auto_pause.anchor_sample_count;
 		auto_pause.pause_anchor.lon += (location.lon - auto_pause.pause_anchor.lon) / auto_pause.anchor_sample_count;
 
@@ -120,14 +125,19 @@ void auto_pause_process(void) {
 	if (++auto_pause.point_counter < System.conf.auto_pause_time)
 		return;
 	auto_pause.point_counter = 0;
-	if (!System.tracking_auto_paused) {
+	if (!System.tracking_auto_paused && gps_fix_trustworthy()) {
 		/* Net displacement over this window can be small even while genuinely
 		 * moving throughout it - a winding path folding back on itself, or a
 		 * short out-and-back - and pausing on that alone, only to have the
 		 * very next sample or two immediately satisfy the speed-based resume
 		 * above, is itself a spurious (if brief) pause. If the logger is
 		 * already moving fast enough to resume on its own right now, don't
-		 * pause it in the first place. */
+		 * pause it in the first place.
+		 *
+		 * Gated on gps_fix_trustworthy(), matching the resume checks above:
+		 * System.distance itself must stay ungated (it's the odometer), but
+		 * a run of untrustworthy fixes must not be allowed to decide a pause
+		 * transition either way here - it's simply skipped for this window. */
 		if ((System.distance - auto_pause.prev_distance)/100 <= System.conf.auto_pause_dist
 			&& System.speed < System.conf.auto_pause_speed)
 			auto_pause_activate(); /* pause: not enough net movement, and not currently moving fast */

+ 2 - 2
soft/display.c

@@ -236,8 +236,8 @@ void disp_func_elevation_gain(void) {
 	xsprintf(disp.line2, PSTR("Zjazd: %.1fm"), (float)System.elevation_loss / 10.0);
 }
 
-static void format_time(char *buf, unsigned int seconds) {
-	unsigned int hours;
+static void format_time(char *buf, unsigned long int seconds) {
+	unsigned long int hours;
 	unsigned char mins, secs;
 
 	hours = seconds / 3600;

+ 7 - 7
soft/gpx.c

@@ -141,13 +141,13 @@ void gpx_save_single_point(struct location_s *loc) {
 }
 
 unsigned char is_paused(void) {
-	return gpx.paused;
+	return tracking_is_paused();
 }
 
 unsigned char gpx_write(struct location_s *loc, FIL *file) {
 	unsigned int bw;
 	const char *time;
-	unsigned char paused = System.tracking_paused || System.tracking_auto_paused;
+	unsigned char paused = tracking_is_paused();
 
 	if (paused) {
 		if (!gpx.paused) {
@@ -193,8 +193,8 @@ unsigned char gpx_close(FIL *file) {
 void gpx_process_point(struct location_s *loc, FIL *file){
 	float lon_est, lon_err, lat_est, lat_err, dist;
 	struct location_s *ptr;
-	struct location_s nloc;
-	struct location_s filtered_loc;
+	static struct location_s nloc;
+	static struct location_s filtered_loc;
 
 	if (gpx.point_count < System.conf.skip_points) { /* Skipping initial points */
 		gpx.point_count++;
@@ -361,7 +361,7 @@ float distance(struct location_s *pos1, struct location_s *pos2){
 }
 
 void add_distance(float dist) {
-	unsigned char paused = System.tracking_paused || System.tracking_auto_paused;
+	unsigned char paused = tracking_is_paused();
 	if (!paused)
 		System.distance += (dist+0.005)*100.0;
 	if (get_flag(CONFFLAG_VERBOSE_LOG))
@@ -371,7 +371,7 @@ void add_distance(float dist) {
 /* Unfiltered (raw), per-point gain/loss - kept only for comparison against the
  * filtered (dead-band+smoothed) totals in the periodic status line/session summary. */
 void add_elevation(float ele_change) {
-	unsigned char paused = System.tracking_paused || System.tracking_auto_paused;
+	unsigned char paused = tracking_is_paused();
 	if (!paused) {
 		if (ele_change > 0) {
 			System.elevation_gain_raw += (ele_change+0.05)*10.0;
@@ -398,7 +398,7 @@ void add_elevation_filtered(float amount, unsigned char is_gain) {
  * result, so that a step in the smoothed altitude only counts once it clears
  * the dead-band, and only the amount past the dead-band edge is credited. */
 float elevation_process(float alt, time_t time) {
-	unsigned char paused = System.tracking_paused || System.tracking_auto_paused;
+	unsigned char paused = tracking_is_paused();
 	unsigned long int alt_dm;
 	float delta;
 

+ 5 - 1
soft/main.c

@@ -415,6 +415,10 @@ unsigned int get_logging_time(void) {
 	return utc - System.time_start - get_pause_time();
 }
 
+unsigned char tracking_is_paused(void) {
+	return System.tracking_paused || System.tracking_auto_paused;
+}
+
 __flash const char __open_msg[] = "Open %s\r\n";
 
 /*-----------------------------------------------------------------------*/
@@ -598,8 +602,8 @@ int main (void)
 					break;
 				}
 				if (System.location_valid == LOC_VALID_NEW) { /* a new point */
-					gpx_process_point(&location, &gpx_file);
 					auto_pause_process();
+					gpx_process_point(&location, &gpx_file);
 				}
 				wdt_reset();
 				if (FLAGS & F_SYNC) {

+ 1 - 3
soft/main.h

@@ -214,9 +214,6 @@ struct system_s {
 	unsigned tracking_auto_paused:1;
 	unsigned open_new_file:1;
 	unsigned sat_count_low:1;
-	unsigned epoch_gga_ok:1; // set once GGA has been parsed for the current epoch (since the last RMC)
-	unsigned epoch_gsa_ok:1; // set once GSA has been parsed for the current epoch (since the last RMC)
-	unsigned epoch_logged:1; // set once nmea_epoch_complete() has fired for the current epoch
 };
 
 struct location_s {
@@ -281,6 +278,7 @@ void sleep(void);
 void reset_counters(void);
 time_t get_pause_time(void);
 unsigned int get_logging_time(void);
+unsigned char tracking_is_paused(void);
 unsigned int get_avg_speed_x100(void);
 unsigned int get_dist_avg_speed_x100(void);
 

+ 86 - 47
soft/nmea.c

@@ -66,6 +66,15 @@ BYTE gp_comp (const char *str1, __flash const char *str2)
 	return c;
 }
 
+/* Per-epoch GGA/GSA/logged tracking for nmea_epoch_complete() - partial parse
+ * state, not global "fully cooked" data, so kept local to this file rather
+ * than on System. */
+static struct {
+	unsigned char gga_ok : 1;
+	unsigned char gsa_ok : 1;
+	unsigned char logged : 1;
+} epoch;
+
 #define FIELD_BUF_LEN	32
 
 /* Get a column item */
@@ -126,7 +135,7 @@ unsigned int gp_val(const char *db, unsigned char count) {
 static unsigned char speed_sample_high_history;
 
 static void speed_sample_process(double speed_kmh) {
-	unsigned char paused = System.tracking_paused || System.tracking_auto_paused;
+	unsigned char paused = tracking_is_paused();
 	unsigned char fix_trustworthy = gps_fix_trustworthy();
 
 	System.speed = speed_kmh+0.5;
@@ -156,9 +165,9 @@ static time_t gp_rmc_parse(const char *str) {
 	struct tm tmc;
 	double speed_knots;
 
-	System.epoch_gga_ok = 0;
-	System.epoch_gsa_ok = 0;
-	System.epoch_logged = 0;
+	epoch.gga_ok = 0;
+	epoch.gsa_ok = 0;
+	epoch.logged = 0;
 
 	p = gp_col(str, 1);		/* Get h:m:s */
 	if (!p)
@@ -205,8 +214,10 @@ static void gp_gga_parse(const char *str) {
 	double tmp;
 
 	p = gp_col(str, 7); /* satellites used */
+	if (!p)
+		return;
 	System.satellites_used = atoi(p);
-	System.epoch_gga_ok = 1;
+	epoch.gga_ok = 1;
 
 	if (System.satellites_used >= System.conf.min_sats) {
 		System.sat_count_low = 0;
@@ -216,16 +227,20 @@ static void gp_gga_parse(const char *str) {
 
 	/* check validity */
 	p = gp_col(str, 6);
+	if (!p)
+		return;
 	if (*p == '0') {
 		System.location_valid = LOC_INVALID;
 		return;
 	}
-	
+
 	if (!System.sat_count_low)
 		System.location_valid = LOC_VALID_NEW; /* don't accept the coordinates otherwise, even if reported valid */
 
 	/* parse location */
 	p = gp_col(str, 2);		/* latitude */
+	if (!p)
+		return;
 	location.lat = gp_val(p, 2);	/* degrees */
 	p += 2;
 	xatof(&p, &tmp);	/* minutes */
@@ -233,10 +248,14 @@ static void gp_gga_parse(const char *str) {
 	location.lat += tmp;
 
 	p = gp_col(str, 3);	/* N/S */
+	if (!p)
+		return;
 	if (*p != 'N')
 		location.lat = -location.lat;
-	
+
 	p = gp_col(str, 4);		/* longitude */
+	if (!p)
+		return;
 	location.lon = gp_val(p, 3);	/* degrees */
 	p += 3;
 	xatof(&p, &tmp);	/* minutes */
@@ -244,16 +263,22 @@ static void gp_gga_parse(const char *str) {
 	location.lon += tmp;
 
 	p = gp_col(str, 5); /* E/W */
+	if (!p)
+		return;
 	if (*p != 'E')
 		location.lon = -location.lon;
-	
+
 	p = gp_col(str, 6); /* fix type */
+	if (!p)
+		return;
 	if (*p == '2')
 		System.sbas = 1;
 	else
 		System.sbas = 0;
-	
+
 	p = gp_col(str, 9); /* MSL altitude */
+	if (!p)
+		return;
 	xatof(&p, &tmp);
 	location.alt = tmp;
 
@@ -289,7 +314,7 @@ static void gp_gsa_parse(const char *str) {
 		xatof(&p, &hdop);
 		System.hdop_x100 = (unsigned int)(hdop*100.0 + 0.5);
 	}
-	System.epoch_gsa_ok = 1;
+	epoch.gsa_ok = 1;
 }
 
 /* Returns 1 exactly once per epoch (the moment both GGA and GSA have been
@@ -298,8 +323,8 @@ static void gp_gsa_parse(const char *str) {
  * see a stale value left over from a previous epoch or an earlier line -
  * regardless of which order the receiver sends GGA/GSA in. */
 unsigned char nmea_epoch_complete(void) {
-	if (System.epoch_gga_ok && System.epoch_gsa_ok && !System.epoch_logged) {
-		System.epoch_logged = 1;
+	if (epoch.gga_ok && epoch.gsa_ok && !epoch.logged) {
+		epoch.logged = 1;
 		return 1;
 	}
 	return 0;
@@ -408,11 +433,57 @@ void uart0_put_wrap(int c) {
 	uart0_put((char)c);
 }
 
-void gps_initialize(void) {
+/* Sends the SBAS-enable/disable and GNSS-mode commands for the currently
+ * configured settings. Used both as the second step of gps_initialize()'s
+ * boot sequence, and directly as the settings menu's .changed callback for
+ * the SBAS/GNSS-mode entries - the latter must apply the just-changed
+ * setting immediately, regardless of System.gps_initialized, rather than
+ * going through gps_initialize()'s boot state machine (which would instead
+ * re-send the GNSS-mode query if called before the module's PMTK011 boot
+ * line has been seen). */
+void gps_settings_changed(void) {
 	/*
-	 * PMTK355: query gnss search mode (will fail if only GPS is supported)
 	 * PMTK353: set gnss search mode (GPS/Galileo/Glonass/Beidou)
 	 * PMTK313: enable SBAS
+	 */
+	if (get_flag(CONFFLAG_ENABLE_SBAS)) {
+		xfprintf(uart0_put_wrap, PSTR("$PMTK313,1*2E\r\n"));
+		xputs_P(PSTR("SBAS enable sent\r\n"));
+	} else {
+		xfprintf(uart0_put_wrap, PSTR("$PMTK313,0*2F\r\n"));
+		xputs_P(PSTR("SBAS disable sent\r\n"));
+	}
+	if (!System.gps_only) {
+		switch (System.conf.gnss_mode) {
+			default:
+			case GNSS_MODE_GPS_GLONASS_GALILEO:
+				xfprintf(uart0_put_wrap, PSTR("$PMTK353,1,1,1,0,0*2A\r\n"));
+				break;
+			case GNSS_MODE_GPS:
+				xfprintf(uart0_put_wrap, PSTR("$PMTK353,1,0,0,0,0*2A\r\n"));
+				break;
+			case GNSS_MODE_GPS_GALILEO:
+				xfprintf(uart0_put_wrap, PSTR("$PMTK353,1,0,1,0,0*2B\r\n"));
+				break;
+			case GNSS_MODE_GALILEO:
+				xfprintf(uart0_put_wrap, PSTR("$PMTK353,0,0,1,0,0*2A\r\n"));
+				break;
+			case GNSS_MODE_GPS_BEIDOU:
+				xfprintf(uart0_put_wrap, PSTR("$PMTK353,1,0,0,0,1*2B\r\n"));
+				break;
+			case GNSS_MODE_BEIDOU:
+				xfprintf(uart0_put_wrap, PSTR("$PMTK353,0,0,0,0,1*2A\r\n"));
+				break;
+		}
+		xputs_P(PSTR("GNSS mode setting sent\r\n"));
+	} else {
+		System.conf.gnss_mode = GNSS_MODE_GPS;
+	}
+}
+
+void gps_initialize(void) {
+	/*
+	 * PMTK355: query gnss search mode (will fail if only GPS is supported)
 	 * PMTK605: query firmware release; the reply (PMTK705) is logged
 	 *          verbatim by the generic PMTK passthrough in gps_parse()
 	 */
@@ -424,39 +495,7 @@ void gps_initialize(void) {
 			System.gps_initialized = GPS_INIT_QUERY_SENT;
 			break;
 		case GPS_INIT_QUERY_SENT:
-			if (get_flag(CONFFLAG_ENABLE_SBAS)) {
-				xfprintf(uart0_put_wrap, PSTR("$PMTK313,1*2E\r\n"));
-				xputs_P(PSTR("SBAS enable sent\r\n"));
-			} else {
-				xfprintf(uart0_put_wrap, PSTR("$PMTK313,0*2F\r\n"));
-				xputs_P(PSTR("SBAS disable sent\r\n"));
-			}
-			if (!System.gps_only) {
-				switch (System.conf.gnss_mode) {
-					default:
-					case GNSS_MODE_GPS_GLONASS_GALILEO:
-						xfprintf(uart0_put_wrap, PSTR("$PMTK353,1,1,1,0,0*2A\r\n"));
-						break;
-					case GNSS_MODE_GPS:
-						xfprintf(uart0_put_wrap, PSTR("$PMTK353,1,0,0,0,0*2A\r\n"));
-						break;
-					case GNSS_MODE_GPS_GALILEO:
-						xfprintf(uart0_put_wrap, PSTR("$PMTK353,1,0,1,0,0*2B\r\n"));
-						break;
-					case GNSS_MODE_GALILEO:
-						xfprintf(uart0_put_wrap, PSTR("$PMTK353,0,0,1,0,0*2A\r\n"));
-						break;
-					case GNSS_MODE_GPS_BEIDOU:
-						xfprintf(uart0_put_wrap, PSTR("$PMTK353,1,0,0,0,1*2B\r\n"));
-						break;
-					case GNSS_MODE_BEIDOU:
-						xfprintf(uart0_put_wrap, PSTR("$PMTK353,0,0,0,0,1*2A\r\n"));
-						break;
-				}
-				xputs_P(PSTR("GNSS mode setting sent\r\n"));
-			} else {
-				System.conf.gnss_mode = GNSS_MODE_GPS;
-			}
+			gps_settings_changed();
 			break;
 		default:
 			break;

+ 1 - 1
soft/nmea.h

@@ -5,8 +5,8 @@
 time_t gps_parse(const char *str);
 UINT get_line(char *buff, UINT sz_buf);
 void gps_initialize(void);
+void gps_settings_changed(void);
 void check_min_sat_limit(void);
 unsigned char gps_fix_trustworthy(void);
 unsigned char nmea_epoch_complete(void);
-unsigned char nmea_epoch_complete(void);
 

+ 2 - 2
soft/settings.c

@@ -184,7 +184,7 @@ __flash const struct menu_pos settings_menu_list[] = {
 		.type = MENU_TYPE_SETTING_BOOL,
 		.name = _msg_enable_sbas,
 		.index = CONFFLAG_ENABLE_SBAS,
-		.changed = gps_initialize,
+		.changed = gps_settings_changed,
 	},
 	{
 		.type = MENU_TYPE_SETTING_U8,
@@ -198,7 +198,7 @@ __flash const struct menu_pos settings_menu_list[] = {
 		.name = _msg_gnss_type,
 		.index = CONF_U8_GNSS_MODE,
 		.display = display_current_gnss_mode,
-		.changed = gps_initialize,
+		.changed = gps_settings_changed,
 	},
 	{
 		.type = MENU_TYPE_SETTING_BOOL,