d6a56266b7
Groundwork for burst acquisition: the scope needs to report and transfer a whole multi-row FastFrame acquisition, and the BBD needs to gate its trigger output per row rather than staying armed for the scan. tektronix_base - get_fastframe_max_frames() exposes HORizontal:FASTframe:MAXFRames?, which is what sizes a burst once the horizontal settings are fixed. - transfer_fastframe_bulk() pulls a burst as one contiguous buffer. Unlike transfer_fastframe it does not assume how the scope frames the response: it accumulates until the expected byte count is reached, so one large IEEE block and one block per frame both work. - set_data_encoding() / set_data_width() make the transfer format settable instead of inherited from whatever the front panel was left on. - read_raw() had two real defects. The length-digit read used a bare recv() and only checked the length afterwards, so a short read raised "Failed to read data length" on a perfectly good transfer; it now goes through a _recv_exact() helper, as does the trailing separator. And a #0 indeterminate-length block was parsed as int("") -> ValueError. #0 is normally delimited by EOI, which a raw socket never sees, so read_raw now takes expected_bytes to size it. The bulk transfer relies on this. pybbd202 - arm_scan_gate(axis, armed) raises and drops the max-velocity trigger output the scope's AND-gate uses. A burst spans several rows with the scope running throughout, so the gate must be low for the flyback or the return move reaches max velocity and injects frames between rows. - set_trigger_verified() reads the mode back after setting it. set_trigger is fire-and-forget over the shared TX queue; burst mode toggles the gate between every row, where a dropped change silently corrupts the file rather than failing loudly. - set_trigger_gate_off() so the scan can leave the output idle on exit. - TRIGOUT_GATE_OFF is deliberately marked unverified. §7.6 of the BBD203 protocol doc describes `mode` as an enumeration capping at 0x11, which contradicts the bitmask this driver actually sends (TRIGOUT_MAXV = 0x90, known working), so the doc cannot settle which value idles the pin low. The engine's preflight check resolves it on the rig instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>