Skip to content

api: a timed-out SD LIST is indistinguishable from an empty SD card #396

Closed

Description

@cptkoolbeenz

Summary

GetSdCardFilesAsync returns an empty list both when the SD card genuinely has no files and when the device never answered. Clients cannot tell the two apart, so a device that is unreachable — or merely slow — is reported to users as a healthy, empty card.

Trace (v1.3.0)

  • DaqifiDevice.ExecuteTextCommandCoreAsync breaks out of its phase-1 wait after responseTimeoutMs and returns the lines collected so far — an empty collection — rather than throwing.
  • DaqifiStreamingDevice.ThrowIfSdCardListError then treats that as success; its own closing comment says "No error lines and no content lines — empty directory. Caller continues."
  • SdCardFileListParser.ParseFileList([]) yields an empty list.

Net: timeout and empty-directory are the same observable result.

Why it matters more now

Over USB this was mostly masked — an unplug faults the serial transport and Core throws. With SD file transfer over WiFi (#347) the ambiguity became reachable in normal operation: a silently dead TCP link (see #394 — no read-error hook or keepalive, so IsConnected stays true) or plain WiFi congestion that pushes the reply past the ~3 s phase-1 window both produce a clean "empty card".

Downstream, the Avalonia port rendered "SD card OK · 0 files" for an unreachable device holding data (daqifi-avalonia#2).

Current downstream mitigation, and why it is only partial

The port now corroborates a zero-length list with GetSdCardStorageAsync, whose parser cannot read a missing reply as success and throws. That converts "always wrong on a dead link" into "wrong only when the LIST was lost but the link recovered within one round-trip".

It cannot do better: a successful storage query proves the device answered a later request, not that the LIST was complete. A truncated or selectively-lost LIST still reads as a short/empty directory. The complete fix has to be in Core, which is the only layer that knows a reply never arrived.

Suggested fix

Make "no reply" distinguishable from "empty reply" on the text path — any of:

  1. Throw on phase-1 timeout when zero lines were collected (a TimeoutException/DeviceNotRespondingException), rather than returning an empty collection. Cleanest, but a behavior change for any caller relying on empty-on-timeout.
  2. Return a result type carrying TimedOut/Completed alongside the lines, and have GetSdCardFilesAsync throw when the list came back timed-out-and-empty.
  3. Terminator-aware LIST parsing — if the firmware emits an end-of-listing marker, require it before treating a listing as complete; absence means truncated, not empty.

(1) or (2) also fixes the truncation case, which no downstream mitigation can reach.

Filed from a downstream audit of the Avalonia port; companion to #394 and #395.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions