Przeglądaj źródła

autopause: reset stationary-time counter on a fix gap

auto_pause.point_counter (the running count towards auto_pause_time)
was never reset when a fix was lost and reacquired - it just kept
counting through the gap, with no visibility into how long the gap
was or whether the device kept moving during it. Reacquiring a fix
that was lost while genuinely moving could then satisfy the
stationary-time threshold within moments of regaining signal, using
mostly pre-gap progress towards a threshold meant to require
persistent, continuous stationary time.

Verified against a real ~7.5 minute signal-loss log: point_counter was
frozen at a near-complete count going into the gap, and only needed a
handful of post-reacquisition points to reach auto_pause_time and
trigger a pause.

Share fix-gap detection (previously private to gpx.c) via a new
fix_gap_detected() in main.c, called once per accepted point before
both auto_pause_process() (new auto_pause_reset_gap(): resets
point_counter/speed_counter/prev_distance, and re-anchors the
resume-by-distance check if already paused) and gpx_process_point()
(gpx_reset_gap(), unchanged in behavior, just extracted so both
callers share one gap check instead of gpx.c silently owning it).
k4be 1 tydzień temu
rodzic
commit
949903cef6
8 zmienionych plików z 91 dodań i 27 usunięć
  1. 5 0
      gps-test-tool/main.c
  2. 10 0
      gps-test-tool/main.h
  3. 23 0
      soft/autopause.c
  4. 1 0
      soft/autopause.h
  5. 22 27
      soft/gpx.c
  6. 1 0
      soft/gpx.h
  7. 28 0
      soft/main.c
  8. 1 0
      soft/main.h

+ 5 - 0
gps-test-tool/main.c

@@ -41,6 +41,7 @@ __flash const char *uart_log_mode_names[] = {
 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 */
@@ -169,6 +170,10 @@ 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) {
+                if (fix_gap_detected(location.time)) {
+                    auto_pause_reset_gap();
+                    gpx_reset_gap();
+                }
                 auto_pause_process();
                 gpx_process_point(&location, &gpx_file);
                 point_count++;

+ 10 - 0
gps-test-tool/main.h

@@ -308,6 +308,15 @@ static inline void pause_time_end(void) {
     System.current_pause_start = 0;
 }
 
+/* Kept in sync with soft/main.c's fix_gap_detected() - see there for the
+ * full rationale. */
+static inline unsigned char fix_gap_detected(time_t point_time) {
+    static time_t last_point_time = 0;
+    unsigned char gap = last_point_time && point_time - last_point_time > 3;
+    last_point_time = point_time;
+    return gap;
+}
+
 static inline time_t get_pause_time(void) {
     time_t res = System.pause_time;
     if (is_paused() && System.current_pause_start && System.current_pause_start >= System.time_start)
@@ -368,6 +377,7 @@ void gps_powered_on(void);
  * of what this tool's output looks like. It calls beep(), which is
  * meaningless on PC and stubbed out here. */
 void auto_pause_process(void);
+void auto_pause_reset_gap(void);
 unsigned char gps_fix_trustworthy(void);
 static inline void beep(unsigned int len, unsigned char cnt) { (void)len; (void)cnt; }
 

+ 23 - 0
soft/autopause.c

@@ -61,6 +61,29 @@ static void auto_pause_activate(void) {
 	beep(50, 3);
 }
 
+/* Call once, whenever fix_gap_detected() reports a gap on the point about to
+ * be passed to auto_pause_process(). Without this, point_counter keeps
+ * counting straight through the gap with no idea how long it was or whether
+ * the device kept moving during it, so reacquiring a fix that was lost while
+ * genuinely moving could satisfy the stationary-time threshold within
+ * moments, using mostly pre-gap progress - the opposite of what the
+ * threshold is meant to require (persistent time actually stationary). */
+void auto_pause_reset_gap(void) {
+	auto_pause.point_counter = 0;
+	auto_pause.speed_counter = 0;
+	auto_pause.prev_distance = System.distance;
+	if (System.tracking_auto_paused) {
+		/* Same reasoning as auto_pause_activate()'s anchor init: re-anchor on
+		 * the fix regained after the gap, not wherever the device was when
+		 * the fix was lost - it may have moved (or been carried) an unknown
+		 * distance in between, which resume-by-distance must not read as an
+		 * instant departure from a now-stale anchor. */
+		auto_pause.pause_anchor = location;
+		auto_pause.anchor_sample_count = 1;
+		auto_pause.resume_high_history = 0;
+	}
+}
+
 void auto_pause_process(void) {
 	if (System.tracking_paused || !get_flag(CONFFLAG_AUTO_PAUSE)) { /* remove auto-pause */
 		System.tracking_auto_paused = 0;

+ 1 - 0
soft/autopause.h

@@ -12,3 +12,4 @@ struct auto_pause_s {
 extern struct auto_pause_s auto_pause;
 
 void auto_pause_process(void);
+void auto_pause_reset_gap(void);

+ 22 - 27
soft/gpx.c

@@ -70,7 +70,6 @@ static struct gpx_s {
 	unsigned char avg_count;
 	unsigned char paused;
 	unsigned char point_count;
-	time_t last_point_time; /* time of the last point seen by gpx_process_point(), to detect a fix gap */
 	struct avg_store_s avg_store;
 	struct location_s last_saved;
 	struct location_s last_distance_point; /* Last accepted point for distance calculation */
@@ -116,7 +115,6 @@ unsigned char gpx_init(FIL *file) {
 	gpx.last_distance_point.lat = 0;
 	gpx.last_distance_point.time = 0;
 	gpx.elevation.initialized = 0;
-	gpx.last_point_time = 0;
 	gpx.point_count = 0;
 
 	gpx.paused = 1; /* make it add a <trkseg> tag */
@@ -197,17 +195,28 @@ unsigned char gpx_close(FIL *file) {
 	return f_close(file);
 }
 
-/* A fix normally arrives about once a second; treat a longer gap between
- * accepted points as a fix having been lost and reacquired (regardless of
- * why the epochs in between were rejected/absent - fix loss, a 2D fix, poor
- * HDOP, or the receiver simply not producing lines), even without an
- * explicit auto-pause. A freshly reacquired fix can take a few seconds to
- * converge (seen after a real signal loss: a nominally-3D, in-range-HDOP fix
- * still a couple hundred meters off in altitude until more satellites come
- * in), the same way a fix has never been trusted right after power-on -
- * so re-run the existing skip_points warm-up, and reset the Kalman/window
- * state that would otherwise splice the old and new fixes together. */
-#define FIX_GAP_SECONDS	3
+/* Call once, whenever fix_gap_detected() reports a gap on the point about to
+ * be passed to gpx_process_point() - see fix_gap_detected()'s comment for why
+ * a gap (regardless of cause: fix loss, a 2D fix, poor HDOP, or the receiver
+ * simply not producing lines) needs handling at all. Reset the Kalman/window
+ * state that would otherwise splice the old and new fixes together, and
+ * re-run the existing skip_points warm-up: a freshly reacquired fix can carry
+ * a wildly wrong position/altitude for a few seconds while it converges (seen
+ * after a real signal loss - a nominally-3D, in-range-HDOP fix still a couple
+ * hundred meters off in altitude until more satellites came in), the same way
+ * a fix has never been trusted right after power-on. */
+void gpx_reset_gap(void) {
+	if (get_flag(CONFFLAG_VERBOSE_LOG))
+		xputs_P(PSTR("FIX GAP: resetting warm-up/filter state\r\n"));
+	kalman_init(&gpx.kalman[0]);
+	kalman_init(&gpx.kalman[1]);
+	gpx.prev_points.count = 0;
+	gpx.avg_count = 0;
+	gpx.avg_store.lat = 0;
+	gpx.avg_store.lon = 0;
+	gpx.avg_store.time = 0;
+	gpx.point_count = 0;
+}
 
 void gpx_process_point(struct location_s *loc, FIL *file){
 	float lon_est, lon_err, lat_est, lat_err, dist;
@@ -218,20 +227,6 @@ void gpx_process_point(struct location_s *loc, FIL *file){
 	if (tracking_is_paused())
 		System.points_paused++;
 
-	if (gpx.last_point_time && loc->time - gpx.last_point_time > FIX_GAP_SECONDS) {
-		if (get_flag(CONFFLAG_VERBOSE_LOG))
-			xputs_P(PSTR("FIX GAP: resetting warm-up/filter state\r\n"));
-		kalman_init(&gpx.kalman[0]);
-		kalman_init(&gpx.kalman[1]);
-		gpx.prev_points.count = 0;
-		gpx.avg_count = 0;
-		gpx.avg_store.lat = 0;
-		gpx.avg_store.lon = 0;
-		gpx.avg_store.time = 0;
-		gpx.point_count = 0;
-	}
-	gpx.last_point_time = loc->time;
-
 	if (gpx.point_count < System.conf.skip_points) { /* Skipping initial points */
 		gpx.point_count++;
 		System.points_skipped++;

+ 1 - 0
soft/gpx.h

@@ -8,6 +8,7 @@ unsigned char gpx_init(FIL *file);
 unsigned char gpx_write(struct location_s *loc, FIL *file);
 unsigned char gpx_close(FIL *file);
 void gpx_process_point(struct location_s *loc, FIL *file);
+void gpx_reset_gap(void);
 void gpx_save_single_point(struct location_s *loc);
 float distance(struct location_s *pos1, struct location_s *pos2);
 void add_distance(float dist);

+ 28 - 0
soft/main.c

@@ -403,6 +403,30 @@ unsigned int get_dist_avg_speed_x100(void) {
 	return (unsigned int)((unsigned long int)System.distance * 36UL / (10UL * moving));
 }
 
+/* A fix normally arrives about once a second; treat a longer gap between
+ * accepted points as a fix having been lost and reacquired (regardless of
+ * why the epochs in between were rejected/absent - fix loss, a 2D fix, poor
+ * HDOP, or the receiver simply not producing lines). Shared by
+ * gpx_process_point() (resets the Kalman/averaging warm-up, the same as
+ * after power-on - a freshly reacquired fix can carry a wildly wrong
+ * position/altitude for a few seconds) and auto_pause_process() (resets the
+ * stationary-time counter - otherwise it keeps counting through the gap
+ * with no visibility into how long the gap was or whether the device kept
+ * moving during it, and can trip a pause within moments of reacquiring a
+ * fix that was actually lost while the device was genuinely still moving).
+ * Called at most once per accepted point (the main loop below calls it
+ * before both), so a single static last-seen time is enough - two callers
+ * checking independently would each need their own copy and could disagree
+ * about where the gap boundary was. */
+#define FIX_GAP_SECONDS	3
+
+unsigned char fix_gap_detected(time_t point_time) {
+	static time_t last_point_time = 0;
+	unsigned char gap = last_point_time && point_time - last_point_time > FIX_GAP_SECONDS;
+	last_point_time = point_time;
+	return gap;
+}
+
 /* Call exactly once, at the moment tracking_paused/tracking_auto_paused
  * actually transitions to true (auto_pause_activate(), tracking_pause()) -
  * not deferred until the next accepted point, which may never come before
@@ -638,6 +662,10 @@ int main (void)
 					break;
 				}
 				if (System.location_valid == LOC_VALID_NEW) { /* a new point */
+					if (fix_gap_detected(location.time)) {
+						auto_pause_reset_gap();
+						gpx_reset_gap();
+					}
 					auto_pause_process();
 					gpx_process_point(&location, &gpx_file);
 				}

+ 1 - 0
soft/main.h

@@ -285,6 +285,7 @@ unsigned int get_logging_time(void);
 unsigned char tracking_is_paused(void);
 void pause_time_start(void);
 void pause_time_end(void);
+unsigned char fix_gap_detected(time_t point_time);
 unsigned int get_avg_speed_x100(void);
 unsigned int get_dist_avg_speed_x100(void);