test: probe existing SYS clock access and AT time queries from APP
This commit is contained in:
@@ -84,6 +84,7 @@ 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,6 +7,7 @@
|
||||
#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 *);
|
||||
@@ -52,13 +53,14 @@ static int two_digits(const char *s)
|
||||
return (s[0] - '0') * 10 + s[1] - '0';
|
||||
}
|
||||
|
||||
/* Accept SDK documented "YY/MM/DD HH:MM:SS +32 00" and compact
|
||||
/* Accept actual "YY/MM/DD HH:MM:SS 32 0", documented signed format, and compact
|
||||
* "YY/MM/DD,HH:MM:SS+32". NITZ UT is UTC; zone is metadata, not subtracted.
|
||||
* abs_time/leap_sec have insufficient documented semantics to use as epoch. */
|
||||
static int parse_nitz(const char *s, time_t *epoch, int *zone)
|
||||
{
|
||||
size_t n = strlen(s), pos = 17;
|
||||
int yy, mo, dd, hh, mm, ss, q, dst;
|
||||
int yy, mo, dd, hh, mm, ss, q, dst, negative = 0;
|
||||
size_t start;
|
||||
long long value;
|
||||
if (n < 20 || s[2] != '/' || s[5] != '/' ||
|
||||
(s[8] != ' ' && s[8] != ',') || s[11] != ':' || s[14] != ':') return -1;
|
||||
@@ -66,16 +68,23 @@ static int parse_nitz(const char *s, time_t *epoch, int *zone)
|
||||
hh = two_digits(s + 9); mm = two_digits(s + 12); ss = two_digits(s + 15);
|
||||
if (yy < 0 || calendar_epoch(2000 + yy, mo, dd, hh, mm, ss, &value) != 0 ||
|
||||
value < MIN_EPOCH || value > MAX_EPOCH) return -2;
|
||||
/* Actual SDK output is also "26/10/26 08:00:10 32 0". */
|
||||
if (s[pos] == ' ') ++pos;
|
||||
if (n < pos + 3 || (s[pos] != '+' && s[pos] != '-')) return -3;
|
||||
q = two_digits(s + pos + 1);
|
||||
if (q < 0 || q > 56 || (s[pos] == '-' && q > 48)) return -3;
|
||||
*zone = s[pos] == '-' ? -q : q;
|
||||
pos += 3;
|
||||
else if (s[pos] != '+' && s[pos] != '-') return -3;
|
||||
if (s[pos] == '+' || s[pos] == '-') negative = s[pos++] == '-';
|
||||
start = pos;
|
||||
q = 0;
|
||||
while (pos < n && s[pos] >= '0' && s[pos] <= '9' && pos - start < 2)
|
||||
q = q * 10 + s[pos++] - '0';
|
||||
if (pos == start || q > 56 || (negative && q > 48)) return -3;
|
||||
*zone = negative ? -q : q;
|
||||
if (pos < n) {
|
||||
if (n != pos + 3 || s[pos] != ' ') return -4;
|
||||
dst = two_digits(s + pos + 1);
|
||||
if (dst < 0 || dst > 2) return -4;
|
||||
if (s[pos++] != ' ') return -4;
|
||||
start = pos;
|
||||
dst = 0;
|
||||
while (pos < n && s[pos] >= '0' && s[pos] <= '9' && pos - start < 2)
|
||||
dst = dst * 10 + s[pos++] - '0';
|
||||
if (pos == start || pos != n || dst > 2) return -4;
|
||||
}
|
||||
*epoch = (time_t)value;
|
||||
return 0;
|
||||
@@ -177,7 +186,8 @@ static void nitz_test_worker(void *arg)
|
||||
long long advance, elapsed, drift;
|
||||
unsigned int span;
|
||||
(void)arg;
|
||||
printf("[APP-NITZ-TEST] begin version=1 source=operator_nitz ntp=off\r\n");
|
||||
app_sys_time_probe_run();
|
||||
printf("[APP-NITZ-TEST] begin version=2 source=operator_nitz ntp=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")) {
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "ql_func.h"
|
||||
#include "ql_rtos.h"
|
||||
#include "ql_rtc.h"
|
||||
#include "ql_atcmd.h"
|
||||
#include "app_sys_time_probe.h"
|
||||
|
||||
/* Exact signatures from the existing kernel pmic_rtc.h/duster.h.
|
||||
* Lookup only: never add exports, use fixed addresses, or use our diagnostic API.
|
||||
* SYS_OFFSET is 0 in pmic_rtc.h. Missing exports are an expected result. */
|
||||
typedef unsigned int (*sys_count_fn)(int);
|
||||
typedef int (*zone_minutes_fn)(void);
|
||||
|
||||
static void probe_sys_exports(void)
|
||||
{
|
||||
sys_count_fn get_count;
|
||||
zone_minutes_fn get_zone;
|
||||
unsigned int raw[2], ticks[2];
|
||||
int zone[2], i;
|
||||
long long utc[2], advance, elapsed, drift;
|
||||
|
||||
get_count = (sys_count_fn)(intptr_t)m_get_api_ptr("PMIC_RTC_GetTime_Count");
|
||||
get_zone = (zone_minutes_fn)(intptr_t)m_get_api_ptr("GetTimeZone");
|
||||
printf("[APP-SYS-PROBE] exports sys_count=%d network_zone=%d\r\n",
|
||||
get_count != NULL, get_zone != NULL);
|
||||
if (!get_count || !get_zone) {
|
||||
printf("[APP-SYS-PROBE] direct_sys=unavailable no_kernel_change=1\r\n");
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < 2; ++i) {
|
||||
raw[i] = get_count(0);
|
||||
zone[i] = get_zone();
|
||||
ticks[i] = ql_rtos_get_systicks();
|
||||
utc[i] = (long long)raw[i] - (long long)zone[i] * 60;
|
||||
printf("[APP-SYS-PROBE] direct index=%d raw=%lu zone_minutes=%d "
|
||||
"utc=%lld ticks=%lu\r\n", i + 1, (unsigned long)raw[i],
|
||||
zone[i], utc[i], (unsigned long)ticks[i]);
|
||||
if (i == 0) ql_rtos_task_sleep_ms(3000);
|
||||
}
|
||||
elapsed = (ticks[1] - ticks[0]) / 200U;
|
||||
advance = utc[1] - utc[0];
|
||||
drift = advance - elapsed;
|
||||
if (utc[0] >= 1704067200LL && utc[1] <= 2147483647LL &&
|
||||
zone[0] >= -720 && zone[0] <= 840 && zone[0] == zone[1] &&
|
||||
elapsed >= 2 && elapsed <= 10 && advance > 0 && drift >= -1 && drift <= 1) {
|
||||
printf("[APP-SYS-PROBE] direct_sys=candidate advancing=1 "
|
||||
"advance_s=%lld elapsed_s=%lld external_utc_check_required=1\r\n",
|
||||
advance, elapsed);
|
||||
} else {
|
||||
printf("[APP-SYS-PROBE] direct_sys=rejected advance_s=%lld "
|
||||
"elapsed_s=%lld drift_s=%lld\r\n", advance, elapsed, drift);
|
||||
}
|
||||
}
|
||||
|
||||
static void probe_app_rtc(int round)
|
||||
{
|
||||
ql_rtc_time_t calendar;
|
||||
int rc;
|
||||
printf("[APP-SYS-PROBE] app round=%d utc=%ld ticks=%lu\r\n",
|
||||
round, (long)time(NULL), (unsigned long)ql_rtos_get_systicks());
|
||||
if (!m_get_api_ptr("ql_rtc_get_time_ex")) {
|
||||
printf("[APP-SYS-PROBE] rtc_ex=unavailable\r\n");
|
||||
return;
|
||||
}
|
||||
memset(&calendar, 0, sizeof(calendar));
|
||||
rc = ql_rtc_get_time_ex(&calendar);
|
||||
printf("[APP-SYS-PROBE] rtc_ex round=%d rc=%d calendar="
|
||||
"%04d-%02d-%02dT%02d:%02d:%02d source_not_assumed=1\r\n",
|
||||
round, rc, calendar.tm_year, calendar.tm_mon, calendar.tm_mday,
|
||||
calendar.tm_hour, calendar.tm_min, calendar.tm_sec);
|
||||
}
|
||||
|
||||
static void probe_at(int round, char *command, const char *label)
|
||||
{
|
||||
char response[256];
|
||||
unsigned int began = ql_rtos_get_systicks(), ended;
|
||||
int rc, terminated;
|
||||
size_t i;
|
||||
memset(response, 0, sizeof(response));
|
||||
rc = ql_atcmd_send_sync(command, response, sizeof(response), NULL, 2);
|
||||
ended = ql_rtos_get_systicks();
|
||||
terminated = memchr(response, '\0', sizeof(response)) != NULL;
|
||||
response[sizeof(response) - 1] = '\0';
|
||||
for (i = 0; response[i]; ++i)
|
||||
if ((unsigned char)response[i] < 32 || response[i] == '"') response[i] = ' ';
|
||||
printf("[APP-SYS-PROBE] at round=%d query=%s rc=%d duration_ms=%lu "
|
||||
"ticks=%lu terminated=%d raw=\"%s\"\r\n", round, label, rc,
|
||||
(unsigned long)(ended - began) * 5UL, (unsigned long)ended,
|
||||
terminated, response);
|
||||
}
|
||||
|
||||
void app_sys_time_probe_run(void)
|
||||
{
|
||||
int round;
|
||||
printf("[APP-SYS-PROBE] begin version=1 read_only=1 kernel_diag_used=0\r\n");
|
||||
if (!m_get_api_ptr) {
|
||||
printf("[APP-SYS-PROBE] FAIL stage=api_lookup_unavailable\r\n");
|
||||
goto done;
|
||||
}
|
||||
probe_sys_exports();
|
||||
if (!m_get_api_ptr("ql_atcmd_send_sync")) {
|
||||
printf("[APP-SYS-PROBE] at=unavailable\r\n");
|
||||
goto done;
|
||||
}
|
||||
for (round = 1; round <= 2; ++round) {
|
||||
probe_app_rtc(round);
|
||||
/* QLTS support/semantics on this model must be established on-device.
|
||||
* Mode 0 may be a snapshot; mode 1/2 on supported models advances.
|
||||
* CCLK is comparison only; it may expose the same broken APP RTC. */
|
||||
probe_at(round, "AT+QLTS=0\r\n", "QLTS_0");
|
||||
probe_at(round, "AT+QLTS=1\r\n", "QLTS_1");
|
||||
probe_at(round, "AT+QLTS=2\r\n", "QLTS_2");
|
||||
probe_at(round, "AT+CCLK?\r\n", "CCLK");
|
||||
if (round == 1) ql_rtos_task_sleep_ms(3000);
|
||||
}
|
||||
done:
|
||||
printf("[APP-SYS-PROBE] finished rtc_not_written=1\r\n");
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef APP_SYS_TIME_PROBE_H
|
||||
#define APP_SYS_TIME_PROBE_H
|
||||
|
||||
/* Run in the existing time-test worker; read only, no new kernel dependency. */
|
||||
void app_sys_time_probe_run(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user