Stream our own position to the phone/UI while mesh position sharing is opt-in (#11270)
* Position: stream our own position to the phone/UI while mesh sharing is opt-in Position broadcasts became opt-in in 2.8 (#10929): with every public channel at position_precision 0, sendOurPosition() finds no eligible channel and returns without queueing anything, so the connected phone or on-device UI never sees the node's own GPS fix ("GPS looks dead" on standalone MUI devices even though the receiver has a lock). Mirror device telemetry's local delivery: once a minute, when the toPhone queue is idle, stream our own position to the connected client at full precision. The packet is handed straight to sendToPhone() and never touches the mesh, so the per-channel opt-in and the public-channel precision clamp still govern everything on the air. Also stop logging "Send pos ... to mesh" before the channel scan has found an eligible channel; when sharing is disabled everywhere the skip is now logged explicitly instead of pretending a send happened. The cadence gate is a pure static (shouldSendPositionToPhone) alongside the existing broadcast-policy helpers, with unit tests covering the first-send, cadence, gating, and millis() rollover cases. * Review: only advance phone cadence on a queued packet; drop the ms==0 sentinel sendOurPositionToPhone() now reports whether a packet actually reached the phone queue, and runOnce() stamps the cadence only on success, so a guard or allocation failure retries on the next tick instead of waiting out a minute. The never-sent state is a dedicated hasSentPositionToPhone flag rather than lastPhoneSendMs == 0, so a send stamped exactly at millis() == 0 still holds the cadence. New regression test covers that case; existing cases updated to the explicit flag. * Review: align the rollover test fixture with its documented elapsed times lastSent now sits exactly 30,000 ms before the uint32 wrap, so the two cases are precisely 70,000 ms (sends) and 40,000 ms (held) - the previous comments claimed 70s/20s against actual elapsed values of 70,001/40,001 ms.
This commit is contained in:
@@ -56,6 +56,56 @@ static void test_effectiveInterval_zeroFloorIsNoOp()
|
||||
TEST_ASSERT_EQUAL_UINT32(60000U, PositionModule::effectiveBroadcastIntervalMs(60000U, true, 0U));
|
||||
}
|
||||
|
||||
// Local phone/UI play: positions are opt-in on the mesh, but our own position still streams to
|
||||
// the connected phone at a fixed cadence (mirroring telemetry's local delivery).
|
||||
|
||||
// A never-sent state streams immediately once a valid position exists, regardless of the clock.
|
||||
static void test_sendToPhone_firstSendIsImmediate()
|
||||
{
|
||||
TEST_ASSERT_TRUE(PositionModule::shouldSendPositionToPhone(true, true, false, 5000U, 0U, 60000U));
|
||||
TEST_ASSERT_TRUE(PositionModule::shouldSendPositionToPhone(true, true, false, 0U, 0U, 60000U));
|
||||
}
|
||||
|
||||
static void test_sendToPhone_holdsUntilCadenceElapses()
|
||||
{
|
||||
TEST_ASSERT_FALSE(PositionModule::shouldSendPositionToPhone(true, true, true, 59999U, 1U, 60000U));
|
||||
}
|
||||
|
||||
static void test_sendToPhone_sendsWhenCadenceElapses()
|
||||
{
|
||||
TEST_ASSERT_TRUE(PositionModule::shouldSendPositionToPhone(true, true, true, 60001U, 1U, 60000U));
|
||||
}
|
||||
|
||||
// No valid local position yet (e.g. GPS has no fix since boot): nothing to stream.
|
||||
static void test_sendToPhone_requiresValidPosition()
|
||||
{
|
||||
TEST_ASSERT_FALSE(PositionModule::shouldSendPositionToPhone(false, true, true, 60001U, 1U, 60000U));
|
||||
}
|
||||
|
||||
// A backed-up toPhone queue means no client is draining it; don't pile on.
|
||||
static void test_sendToPhone_requiresIdlePhoneQueue()
|
||||
{
|
||||
TEST_ASSERT_FALSE(PositionModule::shouldSendPositionToPhone(true, false, true, 60001U, 1U, 60000U));
|
||||
}
|
||||
|
||||
// millis() rollover: unsigned subtraction keeps the elapsed math correct across the wrap.
|
||||
static void test_sendToPhone_survivesMillisRollover()
|
||||
{
|
||||
constexpr uint32_t lastSent = UINT32_MAX - 29999U; // exactly 30,000 ms before the wrap to 0
|
||||
// "now" 40s after the wrap: 70,000 ms elapsed >= the 60s cadence, so it sends.
|
||||
TEST_ASSERT_TRUE(PositionModule::shouldSendPositionToPhone(true, true, true, 40000U, lastSent, 60000U));
|
||||
// "now" 10s after the wrap: only 40,000 ms elapsed, still held.
|
||||
TEST_ASSERT_FALSE(PositionModule::shouldSendPositionToPhone(true, true, true, 10000U, lastSent, 60000U));
|
||||
}
|
||||
|
||||
// Regression: a send stamped at millis()==0 must still hold the cadence - the never-sent state
|
||||
// is the everSentToPhone flag, not a lastSentMs==0 sentinel.
|
||||
static void test_sendToPhone_sentAtTimeZeroStillHoldsCadence()
|
||||
{
|
||||
TEST_ASSERT_FALSE(PositionModule::shouldSendPositionToPhone(true, true, true, 30000U, 0U, 60000U));
|
||||
TEST_ASSERT_TRUE(PositionModule::shouldSendPositionToPhone(true, true, true, 60000U, 0U, 60000U));
|
||||
}
|
||||
|
||||
void setUp(void) {}
|
||||
|
||||
void tearDown(void) {}
|
||||
@@ -74,6 +124,13 @@ void setup()
|
||||
RUN_TEST(test_effectiveInterval_movingKeepsConfigured);
|
||||
RUN_TEST(test_effectiveInterval_longConfiguredWinsOverFloor);
|
||||
RUN_TEST(test_effectiveInterval_zeroFloorIsNoOp);
|
||||
RUN_TEST(test_sendToPhone_firstSendIsImmediate);
|
||||
RUN_TEST(test_sendToPhone_holdsUntilCadenceElapses);
|
||||
RUN_TEST(test_sendToPhone_sendsWhenCadenceElapses);
|
||||
RUN_TEST(test_sendToPhone_requiresValidPosition);
|
||||
RUN_TEST(test_sendToPhone_requiresIdlePhoneQueue);
|
||||
RUN_TEST(test_sendToPhone_survivesMillisRollover);
|
||||
RUN_TEST(test_sendToPhone_sentAtTimeZeroStillHoldsCadence);
|
||||
exit(UNITY_END());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user