docs(series4): what THOR's "status check" actually is -- 11 commands, 563 MB/month
First capture through bridges/mm_link.py, with THOR polling a unit over the bench
link at "check connection every 5 s / check status every 5 s".
A status check is ELEVEN commands, not one:
POLL -> DEVICE_INFO -> 0x49 -> 0x5C -> MONITOR_STATUS -> SETUP_NAME_READ
-> STORAGE_RANGE -> 0x02 -> OPERATOR -> 0x47 -> CALLHOME_CFG
Each check opens a NEW TCP connection, runs all eleven exchanges in ~300 ms and
closes it. Measured over 21 consecutive checks: 236 B out, 936 B back, plus a
full handshake each time -- about 2.2 KB per check.
At the observed cadence that is 18.8 MB/day, 563 MB/month, per unit. On a
metered cellular plan that is real money, and most of it is waste: the check
re-reads the call-home config, operator name, active setup name and full device
info every ten seconds, none of which changes. SETUP_NAME_READ alone returns 274
bytes a time. POLL + MONITOR_STATUS answers "alive?" and "monitoring?" in two
commands and 131 bytes.
Both intervals set to 5 s yields one combined pass every 10.1 s, steady across
eight measured connections. So the two settings are not independent 5-second
timers, which is a plausible reason changing them appears to do nothing.
REVISES an earlier hypothesis. Because idle polling reconnects every cycle, a
silently-dead link is LESS dangerous while idle than I assumed -- a dead socket
fails at connect and the next cycle retries. The exposure is during OPERATIONS:
THOR held one connection from 00:30 to 00:47 last night while downloading events
and pushing setups. A link dying mid-operation leaves it waiting on a socket the
OS will not fail for ~2 h. The blackhole test should therefore be run during a
download, not while idle.
Also fixes a mislabel in mm_link.py: the SUB byte is DLE-escaped when its value is
0x02/0x03/0x04/0x10, so reading it raw reported SUB 0x02 as "SUB_10".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ru8Lg9HkkYvX9VWWo65SmL
This commit is contained in:
+8
-2
@@ -170,10 +170,16 @@ class FrameSniffer:
|
||||
return # wait for more bytes
|
||||
body = self.buf[start:end + 1]
|
||||
del self.buf[:end + 1]
|
||||
# sub sits at a fixed spot once the leading framing is skipped
|
||||
# SUB sits at a fixed spot past the leading framing -- but it is
|
||||
# DLE-escaped when its own value is 0x02/0x03/0x04/0x10, so a raw
|
||||
# read reports 0x10 for those. SUB 0x02 was being logged as
|
||||
# "SUB_10" until this was handled.
|
||||
off = 5 if self.is_request else 3
|
||||
if len(body) > off:
|
||||
yield body[off], len(body)
|
||||
sub = body[off]
|
||||
if sub == DLE and len(body) > off + 1:
|
||||
sub = body[off + 1]
|
||||
yield sub, len(body)
|
||||
|
||||
|
||||
class Link:
|
||||
|
||||
Reference in New Issue
Block a user