v1.6.0
Verified end-to-end against a DAQiFi Nyquist Nq1 (firmware 3.7.2) over USB: serial discovery, connect + populated init, 100 Hz streaming with live acquisition statistics, mid-stream diagnostics, PWM/digital interlock, SD card list/storage/record/download/parse, and LAN chip info all pass. Full unit suite green (7,171 tests) on net9.0 and net10.0.
Highlights
- Analog outputs are real channels you can see and write — a device's DACs now show up in
Channelsalongside its inputs, with their voltage range, resolution, and last-commanded value, instead of being a write-only command you had to know the syntax for. Writes are range-checked against what the device itself reported before anything reaches the wire, and a stage/latch pair lets several outputs change together. An MCP agent can drive them too, not just read them. Analog output is NQ3 hardware;Supports(DeviceFeature.AnalogOutput)tells you whether the board in front of you has it. (#526, #546) - "Am I actually getting the sample rate I asked for?" —
AcquisitionStatisticsanswers that question from the samples themselves: measured rate, per-channel counts and value ranges, sample-interval spread, out-of-order counts, and how far behind the device's own clock the host is running. On our bench Nyquist it immediately surfaced that firmware 3.7.2 streams at 79.6% of the requested rate — the kind of thing that used to require hand-rolled instrumentation. (#518) - A short SD download is now a failed download — a transfer that ended early used to be handed back as if it were the whole file, so a truncated log looked like a complete one. Core now checks the size it received against the size the device promised and raises a clear error instead. An SD download also takes exclusive ownership of the device for its duration, so a command issued on another thread can no longer interleave and corrupt the file. (#540, #506)
- The per-configuration sample-rate cap moved into Core — the ceiling a given channel selection can actually sustain was previously computed in the MCP server alone, leaving the desktop app and every other consumer without it. Every consumer now gets the same answer from one place. (#513)
Features
- An MCP agent can read a measurement and read back what it recorded to the SD card, not just configure the device. (#524, #511)
- Channels say what a reading means, not just what it measures — unit and scaling metadata travel with the channel. (#523)
Firmware & device behavior
- Three log-related commands stalled for a full 3 seconds each waiting for a reply the device had already sent; they now return as soon as the answer arrives. (#542)
- Reading diagnostic counters mid-stream reported a silently incomplete answer as a complete one — it now raises rather than under-reporting. (#541)
- Digital writes are blocked while PWM is driving that channel, instead of being silently ignored by the firmware. (#473)
- An idle connected device no longer burns CPU every second. (#514)
Fixes
- A live
await foreachover samples now ends when the device does, instead of hanging forever. A clean disconnect ends the loop normally; an unplug or lost link throws, so an acquisition cut short can't be mistaken for one that finished. (#507) - The synchronous
Connect()helpers no longer freeze a UI thread. (#508) Send()racing a disconnect fails with a typed error instead of aNullReferenceException. (#503)- A throwing
StatusChangedsubscriber no longer kills auto-reconnect or leaks the port handle. (#504) - The backlog of sends parked during a long exclusive operation is now capped. (#505)
discover_devicesno longer gives up on a device that just needed a moment — the MCP timeout floor went from 250 ms to 1 s. (#475)
Performance
- Parsing an SD log no longer loads the whole file into memory first. (#520)
- Streaming stopped rebuilding the channel map and copying the buffer on every frame. (#512)
- Serial discovery no longer spends half its time waiting on its own reader thread, and
discover_devicesstarts both transports at once instead of waiting one out. (#509, #510)
Internal
DaqifiStreamingDevicecontinues splitting into focused collaborators — the text-exchange engine is now its own type, and the file gives up the operation lock and its send backlog. (part of #344 — #479, #530)BootloaderSessionDevicemoved into Core so it owns the bootloader stand-in, and the bootloader's duplicated wire constants were single-sourced. (#478, #519)- The
DaqifiStreamingDevicedowncast is gone from the device surface. (#476) - One connected-guard replaces fifty copies of it. (#521)
- New test coverage for the MCP tool layer against an attached device, the PIC32 bootloader exchanges, the SD card text protocol, the WiFi updater's edge cases, and Linux serial-port identification. (#525, #527, #528, #522, #529)
Full Changelog: v1.5.0...v1.6.0