Skip to content

dsd-neo Scanner: power cycle an upstream USB hub when the RTL-SDR wedges - #41

Merged
dsward2 merged 3 commits into
mainfrom
feature/usb-hub-power-cycle
Oct 26, 2026
Merged

dsward2 merged 3 commits into
mainfrom
feature/usb-hub-power-cycle

Conversation

@dsward2

@dsward2 dsward2 commented Oct 23, 2026

Copy link
Copy Markdown
Owner

Summary

  • A wedged RTL-SDR only recovers when it loses power. With the dongles on a hub that can't switch its own ports (ganged), the hub above it can: its port is switched off and on via uhubctl, dropping the downstream hub and every dongle on it.
  • New USBHubPower.swift: settings, uhubctl listing parser, and a cycler that validates hub location, hub USB ID, port device ID and per-port switching before doing anything.
  • DsdNeoScanner: after the existing 3 silent restarts, power cycles the hub once per run, waits for the dongle to reappear (found again by serial, since its USB index can change), and relaunches dsd-neo before giving up.
  • dsd-neo Scanner tab: "USB Hub Power" section (enable, hub-port picker, Refresh, "Power Cycle Now").

Test plan

  • Unit tests: parser (real uhubctl output), validation refusals, settings round trip; full suite 114 tests pass
  • Manual uhubctl -l 2-2.1 -p 1 -a cycle on the real hub: both dongles (00000360, 00000180) re-enumerated
  • UI section and the automatic recovery path not yet exercised in the running app

🤖 Generated with Claude Code

dsward2 and others added 2 commits October 23, 2026 15:30
A wedged RTL-SDR only recovers when it loses power. When the dongles sit on
a ganged hub that uhubctl can't switch per port, the hub above it often can:
cutting its port drops the downstream hub and every dongle on it.

- USBHubPower.swift: settings (hub location + USB ID, port, downstream device
  ID), a uhubctl listing parser, and a cycler that refuses to switch anything
  but the hub/port/device the user chose (topology changes are reported, not
  guessed). The recovery waits for the dongle to re-enumerate and finds it by
  serial, since its USB index can change.
- DsdNeoScanner: after the 3 silent restarts, cycle the hub once per run and
  relaunch dsd-neo on the dongle's new index before giving up.
- dsd-neo Scanner tab: "USB Hub Power" section with hub-port picker and a
  "Power Cycle Now" test button.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…cling

- USBTree: reads the USB tree from `ioreg -a -p IOUSB -l`, converts location
  IDs to uhubctl paths, marks which ports uhubctl can switch, and finds the
  RTL-SDRs that lose power with a port.
- USBHubPowerController: shared state (chosen port, tree, cycle outcome).
- "USB Tree" window: indented hierarchy with RTL-SDRs shown; ports of hubs
  that can switch power are selectable, everything else is dimmed; Refresh and
  Power Cycle Now… (confirms, naming the RTL-SDRs affected).
- Commands > USB Tree… (⇧⌘U) and Power Cycle USB Hub….
- dsd-neo Scanner's USB Hub Power section now shows the chosen port and opens
  the tree instead of using a flat picker.
- AppleEvents `usb hub status`, `usb tree`, `power cycle usb hub` (returns at
  once; the outcome is in the status) for AntennaHead's web page.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@dsward2

dsward2 commented Oct 23, 2026

Copy link
Copy Markdown
Owner Author

Update: adds the USB Tree window (indented hierarchy with RTL-SDRs, dimmed where a port can't be switched), Commands > USB Tree… / Power Cycle USB Hub…, and the AppleEvents used by dsward2/AntennaHead#81.

A "Hub requirements" disclosure in the dsd-neo Scanner's USB Hub Power
section, a note in the USB Tree window when no hub can switch ports, and a
SETUP.md section: uhubctl installed, PPPS ("ppps" vs "ganged"), the switchable
hub being the one above the RTL-SDRs' hub, hubs that don't really cut power,
self-powered hubs, USB 3 companion ports, and sudo.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@dsward2
dsward2 merged commit 1847c34 into main Oct 26, 2026
1 check passed
@dsward2
dsward2 deleted the feature/usb-hub-power-cycle branch October 26, 2026 16:18
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.

1 participant