code wiki / (root) / nx_iot_clock_master.nx

nx_iot_clock_master.nx

buildroot/runtime/nx_iot_clock_master.nx

15797 B390 linesdepth 0pulls 0 transitivereach 1 importersview sourcekind librarytopic iot
docsdependenciesstructsconstsfunctions

about

nx_iot_clock_master.nx -- single monotonic tick source for the hub. Roadmap: NISHI_IOT_HUB_ROADMAP.md Epoch 4 (SYNCHRONIZE). S-class invariants: S0 (bit-equal per tick) + S3 (atomic scene transitions composed by callers) + S6 (no cloud) + S7 (sealed-enum verdict on every operation). Why this primitive exists (gap-analysis F1/F3 closure): Every IoT incumbent that runs scenes lets each device animate off its own local crystal -- Home Assistant fires a set-command then the bulb's firmware times the fade. N crystals drift, N timers trip at different real-times, scenes desync minute by minute. We replace that with a single hub-side monotonic tick that every device-driver advances against. No bulb runs an autonomous animation; every frame is computed at the hub at tick T and the command emitted before tick T+1. Per cardinal feedback-honest-perf-verdict-no-aspirational-claims, this is the structural difference that makes S3 deliverable -- not a heuristic, an architecture. What this primitive does today: - holds a tick state (i64 monotonic counter + wall-ms anchor) - advances ticks on demand against sys_now_ms() - supports a pre-stage queue: callers register "at tick K, run callback X with arg A" -- a fixed-capacity sorted insert - drain_due() returns the IDs of every entry whose target_tick is <= current; caller dispatches them in returned order What it doesn't do yet (queued, separate slices): - UDP multicast tick broadcast for multi-device sync -- queued for nx_iot_scene_atomic.nx; this primitive is the on-hub scheduler only - per-device ack tracking for committed ticks -- belongs in nx_iot_watchdog.nx - tick-time NTP correction -- v2; v1 trusts sys_now_ms Wire-up notes for the hub daemon: The hub's main loop calls nx_iot_clock_tick(state) in a busy-poll with a small sys_sleep_ms(33) at the bottom for 30 Hz cadence.

dependencies 0 imports · 1 importers

nx_iot_clock_master.nx nx_iot_clock_master_test.nx

imports: none

imported by: nx_iot_clock_master_test.nx

structs

145struct IotClockState
166struct IotClockEntry

consts

111const NX_IOT_TICK_VERDICT_UNKNOWN: i64 = 0
112const NX_IOT_TICK_VERDICT_OK: i64 = 1
113const NX_IOT_TICK_VERDICT_NO_ADVANCE: i64 = 2 // same wall-ms as before
114const NX_IOT_TICK_VERDICT_OVERFLOW: i64 = 3 // queue saturated
115const NX_IOT_TICK_VERDICT_NOT_FOUND: i64 = 4 // cancel/peek miss
116const NX_IOT_TICK_VERDICT_BAD_ARG: i64 = 5
117const NX_IOT_TICK_VERDICT_N: i64 = 6
132const NX_IOT_TICK_RATE_HZ: i64 = 30
133const NX_IOT_TICK_PERIOD_MS: i64 = 33 // 1000 / 30 rounded down

functions

104func nx_iot_tick_min(a: i64, b: i64) -> i64
119func nx_iot_tick_verdict_is_valid(v: i64) -> i64
called by 1: main
174func nx_iot_clock_init(state: *IotClockState, queue_cap: i64,
called by 1: main
193func nx_iot_clock_tick(state: *IotClockState, wall_ms_now: i64,
called by 1: main
213func nx_iot_clock_schedule(state: *IotClockState, queue: *IotClockEntry,
called by 1: main
276func nx_iot_clock_drain_due(state: *IotClockState, queue: *IotClockEntry,
called by 1: main calls 1: nx_iot_tick_min
341func nx_iot_clock_cancel(state: *IotClockState, queue: *IotClockEntry,
called by 1: main
381func nx_iot_clock_peek_next(state: *IotClockState, queue: *IotClockEntry,
called by 1: main