Skip to content

Latest commit

 

History

History
157 lines (122 loc) · 8.47 KB

File metadata and controls

157 lines (122 loc) · 8.47 KB

Bench tests

Tests that talk to real instruments. Off by default — a dotnet test on a machine with no bench runs the whole offline suite and skips these, and must stay green.

Running them

set LEC_BENCH=1
dotnet test --filter "FullyQualifiedName~Bench"

That is the whole setup. Addresses are discovered, not configured — the suite scans the subnet once per run and keys on what each instrument answers to *IDN?.

This is not convenience. All three are on DHCP and they move: the two addresses this file used to carry were both wrong within a day, and 192.168.1.19 — recorded as the scope — had been reassigned to the generator. A test that reaches the wrong instrument fails somewhere deep and confusing instead of at the connection, so a stale default is worse than none.

Variable Default Purpose
LEC_SUBNET 192.168.1 The /24 to scan
LEC_SCOPE (discovered) Skip discovery for the scope
LEC_GENERATOR (discovered) Skip discovery for the generator
LEC_MULTIMETER (discovered) Skip discovery for the multimeter
LEC_SERIAL (none — those tests skip) A serial instrument, e.g. serial://COM3?baud=115200
LEC_BENCH_REPORTS <test bin>/bench-reports Where sweep reports are written

Discovery throws rather than guesses if a family is missing or ambiguous, naming everything it did find. Two scopes on the subnet would otherwise mean the sweep silently picks whichever answered fastest, and produces a confident report about the wrong instrument.

All three connect over VXI-11. The generator exposes no raw socket at all, and the scope's raw port lags replies by one query.

LEC_SERIAL is written down rather than discovered, unlike the three above, and that is the point rather than an omission: a serial port cannot be swept for. The baud rate, framing and flow control have to match before one character gets through, and probing a port that turns out to be a printer is not the harmless connect a TCP probe is (SPEC §17). Whoever has such an instrument knows which port and which speed; there is none on this bench, so those four tests skip even with LEC_BENCH=1.

To check what is reachable without running anything else:

dotnet test --filter "FullyQualifiedName~An_instrument_is_recognised"

What they check

FeatureBenchTests — the things a sweep cannot reach.

  • Each instrument's *IDN? classifies to the family it should. Everything else in the app hangs off this: a wrong answer here gives every button, readout and catalog lookup the wrong answer at once.
  • Every read-only quick command on each profile answers.
  • The scope returns a waveform that decodes — not just the right number of points, which a wrong formula also produces, but sane voltages and monotonic time.
  • The scope returns a screenshot that decodes as an image of a plausible size. This transport once truncated at 64 KB and returned a block that was the right shape and half the picture.
  • The multimeter's readout queries all parse as numbers under invariant culture.
  • Each instrument survives three connect/release cycles. The DS2202's firmware wedges under rapid reconnection, which is what a test run does to it.

SerialBenchTests — the serial transport against a real port, and the only part of it a stand-in cannot prove. The framing is covered offline in ScpiFramingTests against a scripted stream; what needs hardware is that a port opens at the settings it was given, that what comes back identifies, that a second query is not reading the tail of the first (RS-232 has no framing of its own, so an overrun would show up exactly there), and that a query nothing answers times out rather than returning what arrived. Skipped unless LEC_SERIAL says where the instrument is.

CatalogSweepTests — sends every safely-sendable query in a catalog and writes a report.

This is what turns "transcribed from the guide" into "answered on the bench". It cannot fail the build on a rejected command: a catalog covers a model line, and a DS2202 legitimately does not implement everything the MSO2000A guide documents. What it produces is bench-reports/sweep-<instrument>.md listing every command and what came back, plus answered-<instrument>.txt — a plain list, so that stamping benchVerified later is a deliberate act and not a side effect of running tests.

Queries only, and only those needing no argument. A catalog is mostly setting commands, and a sweep that sent them would turn the generator's output on, move the scope's timebase, or arm something. Channel suffixes are filled with 1, which every instrument here has.

Brackets mean two different things and are treated differently. An optional argument is dropped — SAMPle:COUNt? [{MIN|MAX|DEF}] stands without its tail. An optional node is kept: dropping [:VOLTage] from MEASure[:VOLTage]:DC? gives MEASure:DC?, a short form SCPI permits, the guide never prints, and a Siglent SDM answers by hanging — which then reads as a command the instrument does not support. That gives:

Instrument Sendable of catalog
Rigol DS2202 437 1200
Siglent SDG2042X 104 343
Siglent SDM3065X 82 206

Only the Rigol has an error queue in its catalog (:SYSTem:ERRor:NEXT?), so only for the scope can a sweep tell "understood" from "silently ignored". Neither Siglent guide documents one. For those two, an answer is evidence and a timeout is not proof of absence.

The queue is drained after each command rather than read once. :SYSTem:ERRor:NEXT? pops a single error and the queue outlives whatever filled it, so one read attributes whatever is at the head to whoever happens to ask — which marked :MEASure:VPP? as an undefined header on a scope that answers it perfectly well, because two commands earlier had timed out and left their errors behind. That mistake only ever runs one way: a command can be wrongly called rejected, never wrongly credited, so a stamped tick is safe even from a run predating the fix.

Be sparing with the scope. A DS2202 against the MSO2000A catalog meets a few dozen commands it has no option for, each of which kills the link, and it has wedged off the network twice under repeated full sweeps — once needing a power cycle mid-session. One sweep, then leave it alone.

BenchInventoryTests — offline. Records that three of the thirty-six catalogued families have hardware here and thirty-three do not, and fails if a new catalog appears without a decision about which side it falls on. The thirty-three are not outstanding work; there is no such instrument on this bench, and saying so once stops it being re-investigated.

AI extraction

Separate switch, because a run costs money:

set LEC_AI=1
dotnet test --filter "FullyQualifiedName~AiExtraction"

It uses whatever provider and key the app already has — configure it once under Tools ▸ AI Connection and the test reads it from there. Nothing to put anywhere.

The datasheet defaults to the Siglent SDM guide in datasheets/, overridable with LEC_AI_PDF. That default is deliberate: its catalog is hand-transcribed and known, so the test can report what fraction of a model's answer is already among its 206 entries. The last run returned 211 commands, 89% of them recognised.

That fraction is printed, not asserted — a model reading 158 pages will legitimately find commands the hand pass skipped and skip some it found. What is asserted is that something came back and all of it cleared the SCPI shape gate.

It is compared on the header, not with ScpiSyntax.MatchesAny. That answers "does this command a user typed fit this template", and both sides here are templates: feeding it two put the figure at 62% when the truth was near 90, because [SENSe:]CAPacitance:RANGe and SENSe:CAPacitance:RANGe are one command written two ways and it is not built to say so.

Everything unrecognised in that run was checked by hand against the guide text and appears in it verbatim. Nothing was invented. The remaining gap is guide typography the model reproduced faithfully — spaces inside brace groups, and a full-width that really is in Siglent's PDF.

The upload-limit checks in the same file run offline and free.

Safety

Nothing here changes an instrument's settings, turns an output on, or arms anything. The generator tests read its configuration back without touching it. Every test hands the front panel back when it finishes — leaving an instrument locked out is the kind of thing that gets a suite switched off.