B7A: QMI DMS time vs VNIIFTRI NTP (DMS = UTC - 0.28 s, sigma 1 ms; NITZ = DMS truncated to 1 s). B7B: a 1970 -> 2026 date -s step is harmless for the modem stack. B7C: aurora-modem probes DMS/NITZ along the start flow and steps CLOCK_REALTIME once at the first valid sample (REG registered/attached), never RTC; background SNTP check (query only) after START OK. 3/3 class-A cold boots PASS (residual +0.04/+0.36/+0.84 s), cache 14fe453a written (B7C_WRITE_VERIFIED) and verified by a normal power-on (V1, +0.26 s). Also publishes the prerequisite R2 (boot-hang / lk eMMC investigation, T4 telnet baseline that B7C builds on) and R3 (autonomous cold boot, NCM loss) material, and extends tools/publish-sanitize.py to r2/, r3/, b7/. Binary images, initramfs, busybox and raw logs stay out (see b7/*/SHA256SUMS).
82 lines
6.9 KiB
Bash
82 lines
6.9 KiB
Bash
#!/bin/sh
|
|
# B7B board-side: validate QMI DMS time -> ONE system clock step 1970 -> DMS UTC (date -u -s @N, aligned to a whole second; NO RTC, NO eMMC)
|
|
# -> post snapshot -> observe OBS s -> temporary /32 route to ONE VNIIFTRI server, ntpd -w (query only), route removed.
|
|
trap '' HUP
|
|
B=/tmp/b7/busybox; O=/tmp/b7b; mkdir -p $O; Q="qmicli -p -d /dev/wwan0qmi0"; D=/run/aurora-modem
|
|
FLOOR=1790928541 # t4 initramfs build time 2026-10-02T08:09:01Z
|
|
Y2026=1767225600; CEIL=$((FLOOR + 5*365*86400)); GPS=315964800; NTPIP=89.109.251.21; OBS=${1:-180}
|
|
ts() { $B adjtimex | awk '/time.tv_sec/{s=$2} /time.tv_usec/{u=$2} END{printf "%d.%06d", s, u}'; }
|
|
up() { cut -d' ' -f1 /proc/uptime; }
|
|
A=$O/b7b-actions.txt; act() { echo "[up $(up) clk $(ts)] $*" >> $A; echo "<5>[b7b] $*" > /dev/kmsg; }
|
|
mm() { mmcli "$@" 2>&1 | tr -d '\033' | sed 's/\[[0-9;]*m//g'; }
|
|
snap() {
|
|
{ echo "=== uptime"; cat /proc/uptime; echo "=== date -u"; date -u; echo "=== adjtimex"; $B adjtimex
|
|
echo "=== rtc (read only)"; cat /sys/class/rtc/rtc0/since_epoch /sys/class/rtc/rtc0/date /sys/class/rtc/rtc0/time
|
|
echo "=== dms"; $Q --dms-get-time; echo "=== nitz"; $Q --nas-get-network-time
|
|
echo "=== mmcli -m any"; mm -m any; echo "=== mmcli -b 1"; mm -b 1
|
|
echo "=== ip"; ip -4 addr show wwan0; ip -4 addr show usb0; ip route
|
|
echo "=== pids"; echo "MM=$(pidof ModemManager) rmtfs=$(pidof rmtfs) qmi-proxy=$(pidof qmi-proxy) telnetd=$(pidof telnetd) udevd=$(pidof udevd) dbus=$(pidof dbus-daemon) polkitd=$(pidof polkitd)"; ps
|
|
echo "=== state"; cat $D/state; echo "=== aurora-modem status"; /etc/init.d/aurora-modem status
|
|
echo "=== lifecycle.log (lines $(wc -l < $D/lifecycle.log))"; tail -n 12 $D/lifecycle.log; echo "=== service.log"; tail -n 4 $D/service.log
|
|
echo "=== mm-0.log tail"; tail -n 15 $D/mm-0.log
|
|
echo "=== dmesg (lines $(dmesg | wc -l)) tail"; dmesg | tail -n 30; } > $1 2>&1; }
|
|
dms_sample() { a=$(ts); r=$($Q --dms-get-time 2>&1); b=$(ts); echo "$r" >> $O/dms-raw.txt
|
|
echo "$a $b $(echo "$r" | sed -n "s/.*System time: '\([0-9]*\).*/\1/p")"; }
|
|
: > $A; act "B7B BEGIN obs=${OBS}s floor=$FLOOR ntp=$NTPIP"
|
|
$B usleep 1 2>/dev/null && act "usleep ok" || act "usleep missing"
|
|
# 1. baseline
|
|
snap $O/b7b-pre.txt; act "pre snapshot done"
|
|
# 2. time-source validation
|
|
T=$O/b7b-time-source.txt; : > $T
|
|
for k in 1 2 3; do echo "DMS$k $(dms_sample)" >> $T; done
|
|
a=$(ts); r=$($Q --nas-get-network-time 2>&1); b=$(ts); echo "$r" > $O/nitz-raw.txt
|
|
nd=$(echo "$r" | sed -n "s/.*3GPP Date: *'\(.*\)'/\1/p"); nt=$(echo "$r" | sed -n "s/.*3GPP Time: *'\(.*\)'/\1/p")
|
|
ne=$(date -u -d "$nd $nt" +%s 2>/dev/null); echo "NITZ $a $b $nd $nt epoch=$ne" >> $T
|
|
awk -v F=$FLOOR -v Y=$Y2026 -v C=$CEIL -v G=$GPS -v NE="$ne" '
|
|
/^DMS/ { n++; if ($4 !~ /^[0-9]+$/) bad="DMS"n" no value"; u=$4/1000+G; m=($2+$3)/2; o[n]=u-m; w[n]=$3-$2; uu[n]=u
|
|
printf "DMS%d utc=%.3f window=%.1fms offset_vs_clock=%.3f\n", n, u, w[n]*1000, o[n] }
|
|
/^NITZ/ { nm=($2+$3)/2; no=(NE+0)-nm; if (NE !~ /^[0-9]+$/) bad="NITZ no value"; printf "NITZ epoch=%s offset_vs_clock=%.3f\n", NE, no }
|
|
END { b=1; for (i=2;i<=n;i++) if (w[i]<w[b]) b=i
|
|
mn=o[1]; mx=o[1]; for (i=2;i<=n;i++) { if (o[i]<mn) mn=o[i]; if (o[i]>mx) mx=o[i] }
|
|
c1=(n==3 && bad==""); c2=(uu[b]>=F); c3=(uu[b]>=Y); c4=(uu[b]<C); c5=((mx-mn)<0.05); d=o[b]-no; c6=(d<2 && d>-2)
|
|
printf "CHECK all values present: %s %s\n", c1?"PASS":"FAIL", bad
|
|
printf "CHECK DMS >= image build 2026-10-02T08:09:01Z (%d): %s\n", F, c2?"PASS":"FAIL"
|
|
printf "CHECK year >= 2026: %s\n", c3?"PASS":"FAIL"
|
|
printf "CHECK not garbage (< build + 5 y; 1980/2017 excluded by floor): %s\n", c4?"PASS":"FAIL"
|
|
printf "CHECK 3 DMS samples consistent (spread %.1f ms < 50): %s\n", (mx-mn)*1000, c5?"PASS":"FAIL"
|
|
printf "CHECK |DMS - NITZ| = %.3f s < 2: %s\n", (d<0?-d:d), c6?"PASS":"FAIL"
|
|
printf "BEST DMS%d offset=%.6f\n", b, o[b]
|
|
print ((c1&&c2&&c3&&c4&&c5&&c6) ? "VERDICT=GO" : "VERDICT=STOP") }' $T > $T.eval
|
|
cat $T.eval >> $T
|
|
grep -q "VERDICT=GO" $T || { act "time source checks FAILED - STOP, clock not changed"; exit 2; }
|
|
OFF=$(sed -n 's/^BEST DMS[0-9] offset=//p' $T); act "checks PASS, DMS offset vs clock $OFF s"
|
|
[ "$2" = dry ] && { act "DRY RUN: stop before clock step"; exit 0; }
|
|
# 3. one clock step, aligned so that the new clock lands on a whole UTC second
|
|
DN0=$(dmesg | wc -l); RTC0=$(cat /sys/class/rtc/rtc0/since_epoch)
|
|
L=$(ts); N=$(awk -v l=$L -v o=$OFF 'BEGIN{printf "%d", int(l+o)+2}'); W=$(awk -v n=$N -v o=$OFF -v l=$(ts) 'BEGIN{w=(n-o)-l-0.004; printf "%d", (w>0?w*1e6:0)}')
|
|
act "step plan: N=$N ($(date -u -d @$N)) local_target=$(awk -v n=$N -v o=$OFF 'BEGIN{printf "%.6f", n-o}') wait_us=$W"
|
|
$B usleep $W; c0=$(ts); date -u -s @$N > $O/date-s.out 2>&1; rc=$?; c1=$(ts)
|
|
act "date -u -s @$N rc=$rc out='$(cat $O/date-s.out)' clk_before=$c0 clk_after=$c1 (no hwclock, RTC untouched)"
|
|
# 4. immediate post snapshot + DMS re-check against the new clock
|
|
snap $O/b7b-post.txt
|
|
for k in 1 2 3; do s=$(dms_sample); echo "$s" | awk -v G=$GPS -v k=$k '{u=$3/1000+G; m=($1+$2)/2; printf "POST DMS%d utc=%.3f clock_mid=%.6f DMS-clock=%+.1f ms window=%.1f ms\n", k, u, m, (u-m)*1000, ($2-$1)*1000}' >> $O/b7b-post.txt; done
|
|
act "post snapshot done; RTC since_epoch before step $RTC0, now $(cat /sys/class/rtc/rtc0/since_epoch)"
|
|
# 5. observe
|
|
V=$O/b7b-observe.txt; echo "# every 5 s: up clock pids state wwan0 lte_ping host_ping lifecycle_lines dmesg_lines rtc; every 15 s mm" > $V
|
|
i=0; while [ $i -lt $OBS ]; do
|
|
l="up=$(up) clk=$(date -u +%T) MM=$(pidof ModemManager) rmtfs=$(pidof rmtfs) qp=$(pidof qmi-proxy) tel=$(pidof telnetd) state=$(cat $D/state) wwan0=$(ip -4 -o addr show wwan0 | awk '{print $4}')"
|
|
l="$l lte=$(ping -c1 -W2 -I wwan0 77.88.8.8 >/dev/null 2>&1 && echo ok || echo FAIL) host=$(ping -c1 -W1 172.16.42.2 >/dev/null 2>&1 && echo up || echo DOWN)"
|
|
l="$l lc=$(wc -l < $D/lifecycle.log) dmesg=$(dmesg | wc -l) rtc=$(cat /sys/class/rtc/rtc0/since_epoch)"
|
|
[ $((i % 15)) = 0 ] && l="$l mm=$(mm -m any | grep -E '\| +(state|registration): ' | awk -F': ' '{print $2}' | tr -d ' ' | tr '\n' '/') bearer1=$(mm -b 1 | grep -m1 'connected:' | awk -F': ' '{print $2}')"
|
|
echo "$l" >> $V; sleep 5; i=$((i+5)); done
|
|
echo "=== dmesg since step (from line $DN0)" >> $V; dmesg | tail -n +$((DN0+1)) >> $V
|
|
echo "=== mm-0.log since step (grep time|clock|timeout|error|warn)" >> $V; grep -iE "time|clock|error|warn" $D/mm-0.log | tail -n 40 >> $V
|
|
act "observe done"
|
|
# 6-9. NTP check (query only)
|
|
C=$O/b7b-ntp-check.txt; SRC=$(ip -4 -o addr show wwan0 | awk '{print $4}' | cut -d/ -f1)
|
|
{ echo "route add $NTPIP/32 dev wwan0 src $SRC"; ip route add $NTPIP/32 dev wwan0 src $SRC && echo ROUTE-ADD-OK; ip route
|
|
echo "clock before: $(ts) $(date -u)"; timeout 14 $B ntpd -w -d -p $NTPIP 2>&1; echo "clock after: $(ts) $(date -u)"
|
|
for k in 1 2 3; do dms_sample | awk -v G=$GPS -v k=$k '{u=$3/1000+G; m=($1+$2)/2; printf "DMS%d DMS-clock=%+.1f ms\n", k, (u-m)*1000}'; done
|
|
ip route del $NTPIP/32 dev wwan0 && echo ROUTE-DEL-OK; ip route; } > $C 2>&1
|
|
act "ntp check done: $(grep 'reply from' $C | awk '{print $5, $6}' | tr '\n' ';')"
|
|
act "B7B END"
|