feat(channel): validate AnalogChannel bounds + cover bipolar scaling (closes #300, #297) - #328
Conversation
closes #300, closes #297) Add bounds validation to AnalogChannel's resolution/range/calibration inputs so physically-nonsensical values can't silently produce wrong scaled samples (#300), and lock in signed/bipolar scaling behavior with explicit test coverage plus a range-polarity accessor for consuming UIs (#297). #300 — validation: - Constructor and setters now reject out-of-range resolution (outside the 255..16,777,216 max-count band), non-positive/oversized PortRange (0 < x <= 50 V), zero/NaN/Infinity/oversized scale factors (CalibrationM, InternalScaleM), NaN/Infinity/oversized CalibrationB, and non-finite Min/MaxValue. Bounds exposed as public consts. Negative CalibrationM is still allowed (signal inversion); zero CalibrationB is still allowed. - Device population (DaqifiDevice.PopulateAnalogChannels) sanitizes device-reported coefficients before they reach the validating setters: corrupt values fall back to safe defaults and log, mirroring the existing analog_in_res=0 handling — so a corrupted status frame can neither crash channel population nor propagate garbage into every scaled sample. #297 — bipolar/signed scaling: - Add explicit GetScaledValue coverage for negative/signed raw counts across representative bipolar range + calibration combinations (sign, zero-point, symmetry, offset-after-gain, inverting slope). - Add IAnalogChannel.IsBipolar (derived from the configured MinValue) so range-selection UIs can branch on polarity without hardcoding assumptions. Firmware confirmation of signed two's-complement emission remains tracked separately. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PR Summary by QodoValidate AnalogChannel scaling bounds and add bipolar/signed scaling coverage
AI Description
Diagram
High-Level Assessment
Files changed (5)
|
Code Review by Qodo
Context used 1.
|
…Qodo #328) PopulateAnalogChannels only treated analog_in_res==0 as needing a fallback, so a corrupted status frame carrying a non-zero out-of-range resolution (e.g. 1, uint.MaxValue) would reach the AnalogChannel constructor's new ValidateResolution check, throw, and abort channel population mid-stream. It would also install a bad resolution into reused channels via UpdateScalingFromStatus. Extend the existing "assumed" fallback to cover anything outside [MinResolution, MaxResolution], so both the new-channel and reuse paths receive a sanitized resolution. UpdateScalingFromStatus stays a non-throwing trusted writer; the status boundary remains the single sanitization point. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Re Qodo's optional finding "CalibrationM allows negative values": keeping this as designed. Ticket #300 scopes "reject zero/negative" to |
Summary
Hardens
AnalogChannelagainst physically-nonsensical scaling inputs (#300) and locks in signed/bipolar scaling behavior with explicit test coverage plus a range-polarity accessor for consuming UIs (#297).Closes #300. Closes #297.
#300 — bounds validation
PortRange/CalibrationM/CalibrationB/InternalScaleM/MinValue/MaxValuesetters now reject invalid values with informativeArgumentOutOfRangeExceptions, consistent with the existing constructor style:[255, 16_777_216](8–24 bit).0 < x <= 50V.±1e6. Negative allowed (signal inversion); zero rejected (discards the measurement).±1e6. Zero allowed.public consts.DaqifiDevice.PopulateAnalogChannelssanitizes device-reported coefficients (NaN/Infinity/out-of-range/zero-scale) to safe defaults with aTracelog before they reach the validating setters — mirroring the existinganalog_in_res=0fallback. A corrupted status frame can neither crash channel population mid-stream nor silently propagate garbage into scaled samples.#297 — bipolar / signed scaling
GetScaledValuecoverage for negative/signed raw counts across representative bipolar range + calibration combinations: full-/half-scale sign, zero-point, symmetry about zero, offset-after-signed-gain, and inverting slope.IAnalogChannel.IsBipolar(derived from the configuredMinValue) so range-selection UIs can branch on polarity without hardcoding per-device assumptions. Firmware confirmation that differential inputs emit signed two's-complement counts remains tracked separately (out of scope here).Tests
AnalogChannelTests: validation (valid/invalid/boundary) + signed/bipolar scaling +IsBipolar.ChannelPopulationTests: regression test that a status frame with corrupt scaling values yields defaulted channels without throwing.Bench test
Built the example CLI against this worktree's
Daqifi.Coreand streamed a real Nyquist over USB (/dev/cu.usbmodem1101, 10 Hz, ch0+1, 3 s): channels populated, samples flowed with validation active, exit code 0 — normal device data passes the new validation unaffected.🤖 Generated with Claude Code