test: calibrate APP RTC from first valid NITZ snapshot after PDP

This commit is contained in:
chenjintao
2026-10-26 16:59:08 +08:00
parent f8df812f45
commit 884ab54255
5 changed files with 86 additions and 98 deletions
@@ -84,7 +84,6 @@ SRC_FILES+= \
mqtt_connect_diag.c \
time_diag.c \
app_nitz_test.c \
app_sys_time_probe.c \
vad_det.c \
sleep_wake.c \
battery.c \
@@ -7,14 +7,12 @@
#include "ql_nw.h"
#include "ql_rtc.h"
#include "app_nitz_test.h"
#include "app_sys_time_probe.h"
/* SDK wrapper uses the same PMIC timezone as time(); no libc TZ assumptions. */
extern struct tm *ql_localtime_r(const time_t *, struct tm *);
#define MIN_EPOCH 1704067200LL
#define MAX_EPOCH 2147483647LL
#define ATTEMPTS 3
#define SAMPLE_MS 3000U
static ql_task_t test_task;
static int test_started;
@@ -110,8 +108,11 @@ static int get_sample(int attempt, int index, nitz_sample *sample)
printf("[APP-NITZ-TEST] rejected stage=parse reason=%d\r\n", parsed);
return -1;
}
/* A long blocking query makes the timestamp's age ambiguous. */
if (sample->ticks - began > 400U) return -1;
/* Bound query delay; this does not establish the age of a cached NITZ. */
if (sample->ticks - began > 400U) {
printf("[APP-NITZ-TEST] rejected stage=slow_query rtc_not_written=1\r\n");
return -1;
}
printf("[APP-NITZ-TEST] parsed utc=%ld zone_quarters=%d zone_minutes=%d\r\n",
(long)sample->utc, sample->zone_quarters, sample->zone_quarters * 15);
return 0;
@@ -181,42 +182,31 @@ static int write_and_verify(const nitz_sample *reference)
static void nitz_test_worker(void *arg)
{
nitz_sample first, second;
nitz_sample sample;
int attempt;
long long advance, elapsed, drift;
unsigned int span;
(void)arg;
app_sys_time_probe_run();
printf("[APP-NITZ-TEST] begin version=2 source=operator_nitz ntp=off\r\n");
printf("[APP-NITZ-TEST] begin version=3 source=operator_nitz ntp=off "
"policy=first_valid_after_pdp sys_probe=off\r\n");
if (!m_get_api_ptr || !m_get_api_ptr("ql_nw_get_nitz_time_info") ||
!m_get_api_ptr("ql_localtime_r") || !m_get_api_ptr("ql_rtc_set_time") ||
!m_get_api_ptr("ql_rtc_get_time")) {
printf("[APP-NITZ-TEST] FAIL stage=sdk_api_unavailable\r\n");
goto done;
}
/* Device experiment: use the first valid operator snapshot promptly after
* PDP activation. A snapshot need not advance between API reads. Its actual
* network reception time is unknown; readback alone cannot establish age. */
for (attempt = 1; attempt <= ATTEMPTS; ++attempt) {
if (get_sample(attempt, 1, &first) == 0) {
ql_rtos_task_sleep_ms(SAMPLE_MS);
if (get_sample(attempt, 2, &second) == 0) {
span = second.ticks - first.ticks; /* unsigned handles tick wrap */
elapsed = span / 200U;
advance = (long long)second.utc - first.utc;
drift = advance - elapsed;
printf("[APP-NITZ-TEST] freshness advance_s=%lld elapsed_s=%lld "
"drift_s=%lld\r\n", advance, elapsed, drift);
if (span >= 400U && span <= 2000U && advance > 0 &&
drift >= -1 && drift <= 1 &&
first.zone_quarters == second.zone_quarters) {
write_and_verify(&second);
goto done; /* Never repeat an uncertain RTC write. */
}
printf("[APP-NITZ-TEST] rejected stage=freshness "
"cached_or_inconsistent_nitz=1 rtc_not_written=1\r\n");
}
if (get_sample(attempt, 1, &sample) == 0) {
printf("[APP-NITZ-TEST] snapshot_selected attempt=%d utc=%ld "
"age=unknown first_valid_after_pdp=1 max_rtc_writes=1\r\n",
attempt, (long)sample.utc);
write_and_verify(&sample);
goto done; /* No repeated write, even on setter/readback failure. */
}
if (attempt < ATTEMPTS) ql_rtos_task_sleep_ms(5000);
}
printf("[APP-NITZ-TEST] FAIL stage=no_fresh_nitz rtc_not_written=1\r\n");
printf("[APP-NITZ-TEST] FAIL stage=no_valid_nitz rtc_not_written=1\r\n");
done:
printf("[APP-NITZ-TEST] finished one_test_per_boot=1\r\n");
ql_rtos_task_delete(NULL);
@@ -201,7 +201,7 @@ int app_net_mgt_init()
// ql_rtos_semaphore_create(&g_ql_ntp_sem,0);
ql_rtc_set_nitz_mode(1);
printf("[TIME-DIAG] nitz_enabled=1 app_nitz_test=once_after_pdp ntp_test=off\r\n");
printf("[TIME-DIAG] nitz_enabled=1 app_nitz_test=first_valid_after_pdp ntp_test=off sys_probe=off\r\n");
talkingq_time_diag_log("nitz-enabled");
ql_task_t appTaskRef = NULL;