Files
banban/docs/app_nitz_test.md
T

7.0 KiB

纯 APP NITZ 校时实机测试

当前 test/time-fix 在 PDP 首次激活后自动启动 NITZ 测试,替换上一版自动 NTP 测试。只改 APP;本次没有修改、编译或烧录内核,不依赖之前添加的内核诊断接口。NTP 测试源文件保留但不参与当前 APP 构建。此模块不访问时间服务器域名或 UDP 123,使用设备已有的运营商 NITZ 查询接口。

新增 SYS 读取探测

当前版本在 NITZ 测试之前运行 [APP-SYS-PROBE],只使用当前源码声明过的函数签名和 APP 已有 AT 接口,不读取旧 AXF,不修改内核,不调用 talkingq_time_diag_snapshot_v1。原有 TIME-DIAG 日志是否可用,不影响本探测。

  • 动态查找 PMIC_RTC_GetTime_Count 和 GetTimeZone。如果原内核本来就导出这两个名字,调用 SYS_OFFSET=0,减去网络时区分钟数,间隔 3 秒读取两次,检查合理范围和推进量。找不到就输出 direct_sys=unavailable,不添加内核导出、不尝试固定地址。
  • 输出 time(NULL)、ql_rtc_get_time_ex() 作为对照,不把 get_time_ex 的名称当成读 SYS 的证据。
  • 通过 ql_atcmd_send_sync 连续两轮读取 AT+QLTS=0、AT+QLTS=1、AT+QLTS=2、AT+CCLK?。两轮间隔 3 秒,每个 AT 请求超时参数为 2 秒。记录返回码、运行计数和原始响应;本型号不支持时允许返回 ERROR。两个 QLTS 候选模式是否提供有效当前时间,需根据原始日志对照确认。
  • 本探测没有 RTC 设置调用。direct_sys=candidate 仅表示现有 SYS 函数可读、时间范围和推进正常,仍需与实际 UTC 核对;AT 返回成功也不等于已确认来源。

刷入后提供从 [APP-SYS-PROBE] begin 到 finished 的完整输出。若 QLTS 返回正确且推进的当前时间,可进一步实现 APP 校时;若所有接口缺失/返回错误或只返回 APP 旧时间,该路线仍未得到可用依据。后续 NITZ 测试保持原有写入条件,快照冻结时不写 RTC。

编译和测试

在现有 Windows 环境执行 build.bat app,按现有流程更新 APP 镜像。保持原内核、原 RTC/NVM 状态。核对 APP 构建成功及镜像容量后启动设备,保留从开机到测试结束、再到一次实际 WSS 连接尝试的完整串口日志。

应看到:

[TIME-DIAG] nitz_enabled=1 app_nitz_test=once_after_pdp ntp_test=off
[APP-SYS-PROBE] begin version=1 read_only=1 kernel_diag_used=0
[APP-SYS-PROBE] exports sys_count=... network_zone=...
...
[APP-SYS-PROBE] finished rtc_not_written=1
[APP-NITZ-TEST] begin version=2 source=operator_nitz ntp=off

本机只进行了主机模拟测试和 ARM 目标语法检查,尚未完成 Windows 完整固件构建或实机测试。

实际流程

  1. 检查原内核是否导出公开 SDK 接口 ql_nw_get_nitz_time_info、ql_localtime_r、ql_rtc_set_time、ql_rtc_get_time。
  2. 查询运营商 NITZ,输出完整原始字符串、返回值、abs_time、leap_sec 和查询耗时。支持 SDK 文档格式 YY/MM/DD HH:MM:SS +32 00 、紧凑格式 YY/MM/DD,HH:MM:SS+32,以及实机已返回的无正号、一位夏令时格式 YY/MM/DD HH:MM:SS 32 0。严格检查日期、闰年、时区及 UTC 范围(2024 年起,至 signed 32 位秒数上限)。不把语义未明确的 abs_time 当 Unix 时间戳使用。
  3. 间隔 3 秒再次查询。两次 UTC 必须向前推进,并与系统运行计数的增量相差不超过 1 秒,时区相同;单次查询超过 2 秒不采用。冻结的 NITZ 快照不写入 APP。最多尝试 3 组,组间等待 5 秒。
  4. 使用 NITZ 的 UT 日期字段生成 UTC 秒数。时区字段以 15 分钟为单位,只记录,不再次从 UT 扣除。这个解释依据仓库旧 SDK 镜像的 NITZ 转换逻辑:UT 日期转换后加时区生成 SYS 本地日历。原始值和解释会保留在日志中,供实机核对。
  5. 通过 SDK ql_localtime_r 按现有 PMIC 时区把 UTC 转成 APP RTC 日历,再调用 ql_rtc_set_time。不改时区、不操作 app_ever 或内部跟随标记、不直接写 NVM 文件。
  6. 读回 ql_rtc_get_time 日历和 time(NULL) 的 UTC 返回值,两者都必须与目标相差不超过 3 秒,并且 SDK 返回成功,才输出 PASS。设置后无论成功失败,都结束本次测试,避免反复写 RTC。

测试任务独立运行,不等待它就可以继续 MQTT 流程。每次启动完成一次测试;仅任务创建失败时允许下一次 PDP 激活重试。此版本没有周期重校、WSS 启动等待或主动重连逻辑,不是完整发布方案。

日志判断

以下是格式示例,不是设备实测结果:

[APP-NITZ-TEST] sample attempt=1 index=1 rc=0 raw="26/10/26 06:00:00 +32 00" abs_time=0 leap_sec=0 query_ms=...
[APP-NITZ-TEST] parsed utc=... zone_quarters=32 zone_minutes=480
[APP-NITZ-TEST] freshness advance_s=3 elapsed_s=3 drift_s=0
[APP-NITZ-TEST] set_begin app_before=... expected_utc=... pmic_zone_minutes=480 app_calendar=2026-10-26T14:00:03
[APP-NITZ-TEST] readback set_rc=0 rtc_rc=0 app_after=... expected_utc=... delta_s=0 calendar=...
[APP-NITZ-TEST] PASS source=nitz app_utc=verified wss_requires_separate_handshake_check=1
[APP-NITZ-TEST] finished one_test_per_boot=1
  • sdk_api_unavailable:原内核缺少所需公开接口,本次不写 RTC。
  • stage=parse:时间为空、格式不支持或日期/范围无效。保留 sample 原文以便分析。
  • stage=freshness:两次时间冻结、跳变或与运行计时不符,不采用。若三组都失败,会输出 no_fresh_nitz rtc_not_written=1。
  • stage=local_calendar:SDK 时区转换未产生可用日历,不写 RTC。
  • stage=app_clock_verification:设置返回失败,或者读回 UTC/日历不符。需要分析是否有时区或 APP RTC 写入问题。

PASS 只证明 NITZ 候选值推进正常、APP 写入和读回相符,无法单独证明运营商绝对时间准确或当前固件的 NITZ UT 语义与旧 SDK 完全一致。实机仍需把原始 NITZ、APP UTC 和实际北京时间对照,尤其检查整 8 小时偏差。它也不等于 WSS 握手或 OTA 下载成功;这两项继续看后续实际连接日志,TLS 校验保持开启。

SDK 可能只提供 NITZ 最近一次通知的快照;如出现冻结拒绝,不应去掉新鲜度检查直接写入,应据日志评估带接收时刻的 NITZ 事件或已有业务服务器授时路径。本测试不注册新网络回调,不抢占现有网络事件处理。

主机回归

python3 tools/test_app_nitz_test.py 编译实际 C 模块,模拟 API 缺失、查询失败、空串、无终止符、无效日期、冻结时间、UTC 跨天、时区转换、运行计数回绕、signed 32 位边界、首次查询失败恢复、写入失败、读回偏差及任务创建失败。启用 ASan/UBSan;不发送设备或公网数据。

python3 tools/test_app_sys_time_probe.py 对实际 SYS/AT 探测模块验证 10 种场景:接口缺失、动态读取、无效/冻结时间、AT 错误、无终止符响应、tick 回绕等。测试不链接 RTC setter 或新增诊断接口;主机测试不证明本型号支持 QLTS。