Splits hardware-test concerns into two reusable modules and rebuilds
test_mum_alm_animation.py on top of them.
- frame_io.py — generic LDF-driven I/O class. Knows nothing about
ALM. Three access levels:
high: send/receive/read_signal by frame and signal name
mid: pack/unpack — bytes ↔ signals without I/O
low: send_raw/receive_raw — bypass the LDF entirely
Plus introspection: frame, frame_id, frame_length. Frame lookups
are cached per FrameIO instance.
- alm_helpers.py — ALM_Node domain helpers built on FrameIO.
AlmTester class bound to (fio, nad) exposes:
force_off, read_led_state, wait_for_state,
measure_animating_window, assert_pwm_matches_rgb,
assert_pwm_wo_comp_matches_rgb
Plus pure utilities (ntc_kelvin_to_celsius, pwm_within_tol) and
the LED-state / pacing / PWM-tolerance constants. PWM assertions
use vendor/rgb_to_pwm.py (compute_pwm) at the runtime
Tj_Frame_NTC temperature.
- test_mum_alm_animation.py rewritten:
* fio + alm fixtures replace the previous dict-based _ctx
* SETUP / PROCEDURE / ASSERT / TEARDOWN section markers
* test_mode1_fade now wraps its ConfigFrame change in
try/finally so EnableCompensation is restored even on
assertion failure (was leaking state into later tests)
* test_disable_compensation_pwm_wo_comp uses the four-phase
pattern explicitly
Sibling imports work because pytest's default rootdir mode puts the
test file's directory on sys.path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>