Releases: daqifi/daqifi-core
v0.21.0
What's changed
✨ New: typed SD card exception hierarchy
GetSdCardFilesAsync previously swallowed SCPI errors and returned an empty list, making real failures (no card, corrupt filesystem, busy SD subsystem) indistinguishable from an empty directory. This release adds a typed exception hierarchy so callers can show actionable error detail instead of silently seeing zero files.
New exceptions in Daqifi.Core.Device.SdCard:
SdCardOperationException— base exception; carriesRawDeviceResponseandLastScpiErrorSdCardNotPresentException— thrown when the device reports no SD card detectedSdCardFilesystemException— thrown when the device fails to open the directory; includes the device's raw error message inDeviceMessageSdCardBusyException— defined for completeness (currently surfaces as the base type since firmware cannot distinguish busy from timeout on the wire)
Empty directory (no errors, no content lines) still returns an empty list — that behavior is unchanged. (#182)
Bug fix: UDP discovery now works on hosts with virtual network adapters
On Windows with WSL2 mirrored networking, Hyper-V, VPN, or VirtualBox, the virtual NIC frequently shares a subnet with the real WiFi/Ethernet adapter. The previous single UdpClient bound to IPAddress.Any could route broadcasts out the wrong NIC and misattribute replies, causing discovery to silently return zero devices even when the hardware was reachable.
WiFiDeviceFinder now binds one UdpClient per physical NIC and skips virtual/tunnel adapters (vEthernet, Hyper-V, WSL, VirtualBox, VMware, TAP). Each socket's bound IP is used directly as LocalInterfaceAddress — no more subnet-match guessing.
Note:
DeviceDiscoveredmay now be invoked concurrently from multiple per-NIC receive loops. The existing contract did not guarantee single-threaded invocation, but subscribers should be thread-safe. (#180)
Full changelog
v0.20.0
Highlights
✨ New: streaming CSV exporter
A storage-agnostic CSV export pipeline now lives in Daqifi.Core.Logging.Export. Any consumer that can produce timestamped channel samples — desktop's EF/SQLite store, SD-card log files, headless capture buffers, future UIs — can plug into it without re-implementing row formatting, timestamp bucketing, or rolling averages.
public interface ISampleSource
{
IReadOnlyList<ChannelDescriptor> GetChannels();
ValueTask<int> GetSampleCountAsync(CancellationToken ct = default);
IAsyncEnumerable<SampleRow> StreamSamples(CancellationToken ct = default);
}
await new CsvExporter().ExportAsync(source, writer, options, progress, cancellationToken);Supports absolute (DateTime.ToString("O")) and relative (F3 seconds from first sample) timestamps, configurable delimiter, all-samples and N-sample rolling-average modes, IProgress<int> reporting, and CancellationToken. Invalid ticks render as INVALID({ticks}) in both time modes. All numeric formatting is CultureInfo.InvariantCulture. (#167)
A worked-out adapter example over SdCardLogSession (parsing .bin log files into CSV) is in daqifi-core-example-app#24 — same shape desktop and other consumers will use.
⚠ Breaking changes
- Dropped
net8.0support. Target frameworks are nownet9.0andnet10.0. Consumers still on .NET 8 must upgrade or pin to v0.19.x. (#175)
Other changes
- docs: README updated to reflect the current API surface and target frameworks (#176)
- chore: Coverlet packages bumped 8.0.1 → 10.0.0 (#177)
- chore: Minor/patch dependency bumps (#178)
Full changelog: v0.19.7...v0.20.0
v0.19.7
Fixes
-
Bound parser stall on oversized-length garbage prefixes (#173)
Streaming stalled indefinitely on USB-Serial when boot-time garbage varint-encoded a large length under the old 1 MB cap. Device LED blinked, buffer grew unbounded, zero
MessageReceivedevents fired. v0.19.6 fixed the unparseable-bytes case (1-byte advance on parse failure); this release fixes the complementary case of bytes that parse as a length prefix but declare an implausibly large frame.MaxMessageSizeBytescapped at 4 KB (real frames are <1 KB; initial-status frames with channel metadata are a few KB at most).- Partial-frame wait path gains a gap gate (declared payload more than 1 KB beyond available bytes is garbage) and a field-tag plausibility check (first body byte must be a valid protobuf tag: wire_type ∈ {0,1,2,5}, field_number ≥ 1).
- Both gates advance only into bytes already identified as garbage — legitimate partial frames that span reads are preserved for the caller to complete.
Regression tests:
RecoversFromOversizedPrefix(bogus varint for 32768 + valid frame behind it) andPreservesPartialFrameAfterGarbage(garbage + truncated real frame →consumedBytesstops at the frame boundary).
Full changelog: v0.19.6...v0.19.7
v0.19.6
Bug fixes
- Protobuf parser resyncs past leading garbage (#169) — Removed the
MaxRetryAttempts = 3cap inProtobufMessageParserthat caused the parser to stall when boot-time bytes (e.g. DTR pulse on Microchip USB-to-Serial chips) landed at the head of the consumer buffer. The parser now resyncs one byte at a time on parse failure, so downstreamMessageReceivedevents fire even when the connect handshake leaves junk in front of the first valid streaming frame. Fixes the desktop Live Graph receiving zero stream messages afterStartStreaming.
Performance
- Avoid per-attempt
byte[]allocation in the resync loop by usingMessageParser<T>.ParseFrom(ReadOnlySpan<byte>)(#169).
v0.19.5
What's Changed
- chore: Bump the minor-and-patch group with 1 update by @dependabot[bot] in #154
- chore: Bump coverlet.collector and coverlet.msbuild from 6.0.4 to 8.0.1 by @dependabot[bot] in #155
- chore: Bump coverlet.msbuild from 6.0.4 to 8.0.1 by @dependabot[bot] in #156
- fix: re-enable LAN after stopping SD card logging by @tylerkron in #159
- fix: correct EnableAdcChannels docs from binary to decimal bitmask by @tylerkron in #160
Full Changelog: v0.19.4...v0.19.5
v0.19.4
What's Changed
- chore: Bump the minor-and-patch group with 3 updates by @dependabot[bot] in #151
- fix: add LAN disable and SD stream interface setup to StartSdCardLoggingAsync by @tylerkron in #153
Full Changelog: v0.19.3...v0.19.4
v0.19.3
What's Changed
- fix: scale raw ADC values and fix timestamps in SD card parser by @tylerkron in #150
- fix: scale raw ADC values in CSV and JSON SD card parsers by @tylerkron in #152
Full Changelog: v0.19.1...v0.19.3
v0.19.2
Bug Fixes
- SD card parser: scale raw ADC values —
ScaleRawAnalogValuesnow only requiresResolution > 0to apply scaling, using default calibration (M=1, B=0) when calibration arrays are absent. Previously, missingCalibrationValuescaused raw ADC counts to be returned unscaled even when resolution/port-range/internal-scale were available. - SD card parser: fix timestamp reconstruction —
FallbackTimestampFrequencynow defaults to 50 MHz (Nyquist device clock) so tick-to-time conversion works even when firmware omitsTimestampFreqfrom SD card log files. - SD card parser: merge paired analog/digital messages — Consecutive protobuf messages with the same
MsgTimeStampare merged into a single sample entry, fixing duplicate sample counts. - CSV/JSON parsers: merge ConfigurationOverride —
ConfigurationOverridenow fills gaps in file-parsed config instead of replacing it entirely. File-derived values (timestamp frequency, serial number, etc.) take precedence; the override fills in zero/null fields. This preventsFromDevice()(which setsTimestampFrequency=0) from collapsing timestamps in CSV/JSON parsing.
Full Changelog
v0.19.1
What's Changed
- fix: fix USB streaming — AnalogInDataFloat support and USB stream interface init by @tylerkron in #149
Full Changelog: v0.19.0...v0.19.1
v0.19.0
What's Changed
- chore: Bump the minor-and-patch group with 2 updates by @dependabot[bot] in #142
- Remove desktop integration compatibility layer by @tylerkron in #148
Full Changelog: v0.18.3...v0.19.0