Skip to content

docs: fix stale IStreamingDevice claim and document SampleReceived pipeline - #291

Merged
tylerkron merged 5 commits into
mainfrom
claude/github-issue-284-c7628a
Jul 11, 2026
Merged

docs: fix stale IStreamingDevice claim and document SampleReceived pipeline#291
tylerkron merged 5 commits into
mainfrom
claude/github-issue-284-c7628a

Conversation

@tylerkron

Copy link
Copy Markdown
Contributor

Summary

  • Corrects DEVICE_INTERFACES.md's false claim that IStreamingDevice is "primarily implemented in the desktop application" — documents DaqifiStreamingDevice and the five interfaces it actually implements (IStreamingDevice, INetworkConfigurable, ISdCardOperations, ILanChipInfoProvider, IDeviceDiagnostics).
  • Documents the decoded per-channel IChannel.SampleReceived pipeline (feat(streaming): decoded per-frame sample pipeline — raise per-channel SampleReceived from the live stream (#242) #279) — previously undocumented in any markdown file — in README's quickstart/capability row and DEVICE_INTERFACES.md's Streaming Data section, alongside the existing raw MessageReceived path.
  • Adds the missing ConnectSerialAsync/ConnectSerial/ConnectFromDeviceInfo overloads to the factory method table.
  • Mentions the digital-output and PWM MCP tools in the MCP server pitch (README.md).
  • Removes a dangling "streaming-evolution plan" reference in src/Daqifi.Mcp/README.md (no such doc exists).
  • Fixes stale Reboot/SystemInfo names in ScpiMessageProducer XML doc examples to the actual RebootDevice/GetDeviceInfo members.

Closes #284

Test plan

  • dotnet build Daqifi.Core.sln — 0 warnings, 0 errors
  • dotnet test Daqifi.Core.sln — 1387 passed, 2 skipped, 0 failed
  • Docs-only changes reviewed manually for accuracy against current source

🤖 Generated with Claude Code

…peline (#284)

- Correct DEVICE_INTERFACES.md's false claim that IStreamingDevice is
  desktop-only; document DaqifiStreamingDevice and the interfaces it
  actually implements (IStreamingDevice, INetworkConfigurable,
  ISdCardOperations, ILanChipInfoProvider, IDeviceDiagnostics).
- Document the decoded per-channel SampleReceived pipeline (#279) in
  README's quickstart/capability row and DEVICE_INTERFACES.md's
  Streaming Data section, alongside the existing raw MessageReceived path.
- Add missing ConnectSerialAsync/ConnectSerial/ConnectFromDeviceInfo
  overloads to the factory method table.
- Mention DIO/PWM tools in the MCP server pitch.
- Remove dangling "streaming-evolution plan" reference with no doc.
- Fix stale Reboot/SystemInfo names in ScpiMessageProducer XML doc
  examples to the actual RebootDevice/GetDeviceInfo members.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@tylerkron
tylerkron requested a review from a team as a code owner July 10, 2026 23:07
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Docs: correct IStreamingDevice ownership and document SampleReceived streaming pipeline

📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Correct interface docs to reflect DaqifiStreamingDevice and its implemented capabilities.
• Document the decoded per-channel IChannel.SampleReceived streaming path alongside
 MessageReceived.
• Fix stale SCPI XML-doc examples and remove an invalid MCP README reference.
Diagram

graph TD
  A["Client code"] --> B["DaqifiDeviceFactory"] --> C["DaqifiStreamingDevice"] --> D["IChannel"] --> E["SampleReceived (decoded)"]
  C --> F["MessageReceived (raw)"]
  G["Docs (README + DEVICE_INTERFACES)"] --> E
  G --> F
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Generate API/interface docs from source (DocFX/Markdown include)
  • ➕ Reduces drift between docs and actual members/implementations
  • ➕ Can auto-publish interface tables and member names
  • ➖ Adds tooling and build/publish complexity
  • ➖ Still requires curated narrative docs for usage patterns like streaming
2. Make README/docs snippets compile-checked (snippet tests)
  • ➕ Prevents stale examples (e.g., renamed SCPI producers)
  • ➕ Catches missing using/API changes early
  • ➖ Requires test harness and snippet extraction conventions
  • ➖ May slow CI slightly and adds maintenance overhead

Recommendation: The PR’s approach (directly correcting and expanding the markdown plus fixing XML-doc examples) is the right immediate fix for #284. Consider a follow-up to compile-check documentation snippets and/or generate API reference sections to prevent future staleness (the SCPI rename mismatch is a good example of drift).

Files changed (4) +75 / -19

Documentation (4) +75 / -19
README.mdUpdate MCP pitch and quickstart to use per-channel SampleReceived +11/-12

Update MCP pitch and quickstart to use per-channel SampleReceived

• Expands the MCP server description to include DIO/PWM control. Replaces the quickstart streaming example from raw 'MessageReceived' frames to decoded per-channel 'IChannel.SampleReceived', and clarifies that 'MessageReceived' remains available for raw protobuf consumption.

README.md

DEVICE_INTERFACES.mdCorrect IStreamingDevice notes, document DaqifiStreamingDevice, and add streaming guidance +58/-1

Correct IStreamingDevice notes, document DaqifiStreamingDevice, and add streaming guidance

• Fixes the incorrect claim that 'IStreamingDevice' is primarily implemented in the desktop app, and documents 'DaqifiStreamingDevice' plus the interfaces it implements. Updates the factory method table to include missing serial and sync overloads, and adds a new section explaining the 'SampleReceived' pipeline vs raw 'MessageReceived' frames.

docs/DEVICE_INTERFACES.md

ScpiMessageProducer.csFix XML-doc examples to use current SCPI producer member names +5/-5

Fix XML-doc examples to use current SCPI producer member names

• Updates the class and member XML documentation examples to reference 'RebootDevice' and 'GetDeviceInfo' instead of stale names ('Reboot', 'SystemInfo'). No runtime logic changes.

src/Daqifi.Core/Communication/Producers/ScpiMessageProducer.cs

README.mdRemove dangling reference to a non-existent streaming evolution plan +1/-1

Remove dangling reference to a non-existent streaming evolution plan

• Deletes an outdated note that referenced a missing document, leaving the SD logging behavior description accurate and self-contained.

src/Daqifi.Mcp/README.md

@qodo-code-review

qodo-code-review Bot commented Jul 10, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 📜 Skill insights (0)

Context used

Grey Divider


Action required

1. Docs sample skips decode state ✓ Resolved 🐞 Bug ≡ Correctness
Description
The documentation examples subscribe to IChannel.SampleReceived but enable ADC channels and start
streaming via raw SCPI device.Send(...), which bypasses the library’s stateful APIs so
DaqifiStreamingDevice.IsStreaming and channel.IsEnabled are never set and the
decode/SampleReceived pipeline won’t run. The per-channel snippet also enumerates the live
device.Channels list, which can be repopulated concurrently and throw during LINQ enumeration
unless snapshotting is used.
Code

docs/DEVICE_INTERFACES.md[R283-300]

+```csharp
+using Daqifi.Core.Channel;
+
+using var device = await DaqifiDeviceFactory.ConnectTcpAsync("192.168.1.100", 9760);
+
+var ai0 = device.Channels.First(c => c.Type == ChannelType.Analog && c.ChannelNumber == 0);
+ai0.SampleReceived += (sender, e) =>
+{
+    Console.WriteLine($"{e.Channel.Name}: {e.Sample.Value} (raw: {e.Sample.RawValue}, {e.Sample.Timestamp})");
+};
+
+device.Send(ScpiMessageProducer.EnableAdcChannels("1")); // Enable channel 0
+device.Send(ScpiMessageProducer.StartStreaming(100));    // 100 Hz
+
+await Task.Delay(TimeSpan.FromSeconds(10));
+
+device.Send(ScpiMessageProducer.StopStreaming);
+```
Relevance

⭐⭐⭐ High

Team previously accepted fixing racy device.Channels enumeration and prefers stateful
channel-management APIs over raw SCPI in examples.

PR-#280
PR-#277
PR-#250

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The decode path that maps incoming frames into per-channel samples and raises SampleReceived is
gated on DaqifiStreamingDevice.IsStreaming, which is only flipped by calling StartStreaming(),
and analog sample decoding targets only channels whose IsEnabled flag is true—set via
EnableChannel(s) rather than by sending raw SCPI commands. In addition, DaqifiDevice.Channels is
documented in-code as a live view over a backing list, so enumerating it directly (e.g., with LINQ)
can fail if the list is repopulated concurrently, and a dedicated snapshot method exists to make
enumeration safe.

src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[171-240]
src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[286-330]
src/Daqifi.Core/Device/DaqifiDevice.cs[67-94]
src/Daqifi.Core/Device/IStreamingDevice.cs[11-52]
src/Daqifi.Core/Device/DaqifiDevice.cs[1125-1212]
PR-#280

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The docs examples intended to demonstrate the decoded `IChannel.SampleReceived` pipeline currently start streaming and enable ADC channels via raw SCPI `device.Send(EnableAdcChannels(...))` / `device.Send(StartStreaming(...))`, which bypasses the library’s stateful streaming/channel APIs. As a result, `DaqifiStreamingDevice.IsStreaming` remains false and `channel.IsEnabled` is not set, so frames are not decoded into samples and `SampleReceived` won’t fire; additionally, the per-channel sample snippet enumerates `device.Channels` directly even though it is a live view that can change concurrently.

## Issue Context
- `DaqifiStreamingDevice` only decodes frames into per-channel samples when `IsStreaming == true`, and `IsStreaming` is set by `StartStreaming()`.
- Analog sample decoding only includes channels where `channel.IsEnabled == true`, which is set by `EnableChannel(...)` / `EnableChannels(...)`.
- `DaqifiDevice.Channels` is a live view over the backing list and can be repopulated concurrently; `GetChannelsSnapshot()` exists specifically to allow safe enumeration.
- If raw SCPI streaming/enabling is kept in docs, it should be positioned as “raw frames” behavior and explicitly note that `SampleReceived` won’t fire when bypassing `StartStreaming()`/`EnableChannel()`.

## Fix Focus Areas
- docs/DEVICE_INTERFACES.md[272-306]
- README.md[34-49]
- src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[171-240]
- src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[286-330]
- src/Daqifi.Core/Device/DaqifiDevice.cs[67-94]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread docs/DEVICE_INTERFACES.md
tylerkron and others added 3 commits July 10, 2026 17:18
…ul API

Qodo review on #291: the new SampleReceived examples subscribed to the
event but drove streaming/channel-enable through raw device.Send(...)
SCPI calls, which never set the local IsStreaming/IsEnabled state the
decode pipeline gates on — so SampleReceived would never have fired as
written. Cast to DaqifiStreamingDevice and use EnableChannel/
StreamingFrequency/StartStreaming instead, and switch to
GetChannelsSnapshot() to avoid enumerating the live, concurrently
mutable Channels list. Verified both snippets compile against the
built library.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@tylerkron
tylerkron merged commit 7299e03 into main Jul 11, 2026
1 check passed
@tylerkron
tylerkron deleted the claude/github-issue-284-c7628a branch July 11, 2026 04:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Docs refresh: decoded SampleReceived pipeline is undocumented; DEVICE_INTERFACES.md misdescribes IStreamingDevice

1 participant