|
@@ -20,7 +20,16 @@ struct auto_pause_s auto_pause;
|
|
|
* quiet window before the speed-based check or the next window catches the
|
|
* quiet window before the speed-based check or the next window catches the
|
|
|
* resume), a false resume pollutes the moving/stopped split and the
|
|
* resume), a false resume pollutes the moving/stopped split and the
|
|
|
* odometer for as long as it isn't caught. */
|
|
* odometer for as long as it isn't caught. */
|
|
|
-#define AUTO_PAUSE_RESUME_DIST_MULT_X100 150 /* 1.5x the configured distance threshold */
|
|
|
|
|
|
|
+#define AUTO_PAUSE_RESUME_MIN_DIST_M 15 /* resume distance-from-anchor floor, regardless of HDOP */
|
|
|
|
|
+#define AUTO_PAUSE_RESUME_HDOP_MULT 5 /* ...and scale up from there by this many meters per HDOP unit -
|
|
|
|
|
+ * a standard rule-of-thumb for GPS position error (HDOP x a typical
|
|
|
|
|
+ * few-meter UERE), so a poor fix needs to move further to count */
|
|
|
|
|
+#define AUTO_PAUSE_RESUME_HISTORY_LEN 7 /* the resume condition must hold for most (see MIN_COUNT below) of
|
|
|
|
|
+ * the last this-many samples, not just instantaneously - the same
|
|
|
|
|
+ * persistence idea used for the speed cap, so a few seconds of
|
|
|
|
|
+ * genuine drift-free movement are needed, not one lucky sample */
|
|
|
|
|
+#define AUTO_PAUSE_RESUME_HISTORY_MASK ((1U << AUTO_PAUSE_RESUME_HISTORY_LEN) - 1)
|
|
|
|
|
+#define AUTO_PAUSE_RESUME_MIN_COUNT 5
|
|
|
|
|
|
|
|
static void auto_unpause(void) {
|
|
static void auto_unpause(void) {
|
|
|
if (!System.tracking_auto_paused)
|
|
if (!System.tracking_auto_paused)
|
|
@@ -38,6 +47,13 @@ static void auto_pause_activate(void) {
|
|
|
* instantly flip-flopping straight back out of the pause this just
|
|
* instantly flip-flopping straight back out of the pause this just
|
|
|
* activated. */
|
|
* activated. */
|
|
|
auto_pause.speed_counter = 0;
|
|
auto_pause.speed_counter = 0;
|
|
|
|
|
+ /* Anchor the resume-by-distance check on where the pause actually
|
|
|
|
|
+ * started, then let it drift towards the running average of positions
|
|
|
|
|
+ * seen while paused (steadier than any single fix - see
|
|
|
|
|
+ * auto_pause_process()). */
|
|
|
|
|
+ auto_pause.pause_anchor = location;
|
|
|
|
|
+ auto_pause.anchor_sample_count = 1;
|
|
|
|
|
+ auto_pause.resume_high_history = 0;
|
|
|
log_pause_event(1);
|
|
log_pause_event(1);
|
|
|
beep(50, 3);
|
|
beep(50, 3);
|
|
|
}
|
|
}
|
|
@@ -70,15 +86,41 @@ void auto_pause_process(void) {
|
|
|
auto_pause.speed_counter = 0;
|
|
auto_pause.speed_counter = 0;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ /* Resume-by-distance: compared against an anchor updated to the running
|
|
|
|
|
+ * average position seen while paused (steadier than any single fix),
|
|
|
|
|
+ * scaled by HDOP (a poor fix needs to move further to count), and
|
|
|
|
|
+ * required to persist for most of a short window rather than firing on
|
|
|
|
|
+ * one sample - stationary GPS jitter (well under a meter per second) can
|
|
|
|
|
+ * otherwise accumulate across enough net-movement windows to look like a
|
|
|
|
|
+ * real departure. Evaluated every accepted point, not gated on the
|
|
|
|
|
+ * auto_pause_time window below (that window is for the pause trigger
|
|
|
|
|
+ * only), so the persistence history has one sample per point. */
|
|
|
|
|
+ if (System.tracking_auto_paused && gps_fix_trustworthy()) {
|
|
|
|
|
+ float resume_threshold_m = AUTO_PAUSE_RESUME_MIN_DIST_M;
|
|
|
|
|
+ float hdop_threshold_m = (System.hdop_x100/100.0f) * AUTO_PAUSE_RESUME_HDOP_MULT;
|
|
|
|
|
+ float dist_from_anchor_m;
|
|
|
|
|
+ unsigned char resumed_this_sample;
|
|
|
|
|
+
|
|
|
|
|
+ if (hdop_threshold_m > resume_threshold_m)
|
|
|
|
|
+ resume_threshold_m = hdop_threshold_m;
|
|
|
|
|
+
|
|
|
|
|
+ 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;
|
|
|
|
|
+
|
|
|
|
|
+ dist_from_anchor_m = distance(&location, &auto_pause.pause_anchor);
|
|
|
|
|
+ resumed_this_sample = dist_from_anchor_m > resume_threshold_m;
|
|
|
|
|
+ auto_pause.resume_high_history = (auto_pause.resume_high_history << 1) | resumed_this_sample;
|
|
|
|
|
+ if (__builtin_popcount(auto_pause.resume_high_history & AUTO_PAUSE_RESUME_HISTORY_MASK) >= AUTO_PAUSE_RESUME_MIN_COUNT) {
|
|
|
|
|
+ auto_pause.point_counter = 0;
|
|
|
|
|
+ auto_unpause();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
if (++auto_pause.point_counter < System.conf.auto_pause_time)
|
|
if (++auto_pause.point_counter < System.conf.auto_pause_time)
|
|
|
return;
|
|
return;
|
|
|
auto_pause.point_counter = 0;
|
|
auto_pause.point_counter = 0;
|
|
|
- if (System.tracking_auto_paused) {
|
|
|
|
|
- unsigned long int resume_threshold = (unsigned long int)System.conf.auto_pause_dist
|
|
|
|
|
- * AUTO_PAUSE_RESUME_DIST_MULT_X100 / 100;
|
|
|
|
|
- if ((System.distance - auto_pause.prev_distance)/100 > resume_threshold)
|
|
|
|
|
- auto_unpause(); /* unpause when distance exceeded */
|
|
|
|
|
- } else {
|
|
|
|
|
|
|
+ if (!System.tracking_auto_paused) {
|
|
|
/* Net displacement over this window can be small even while genuinely
|
|
/* Net displacement over this window can be small even while genuinely
|
|
|
* moving throughout it - a winding path folding back on itself, or a
|
|
* 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
|
|
* short out-and-back - and pausing on that alone, only to have the
|