Documentation
¶
Overview ¶
Package sdwire provides a Go SDK for controlling SDWireC and SDWire3 devices. SDWire devices are USB-controlled SD card multiplexers that allow switching an SD card between a Device Under Test (DUT) and a Test System (TS).
This is a fork of github.com/fcjr/sdwire with SDWire3 support and fixes.
Index ¶
- Constants
- Variables
- type DeviceController
- type DeviceGeneration
- type DeviceInfo
- type DeviceState
- type FlashOption
- func WithBlockDevTimeout(d time.Duration) FlashOption
- func WithFlashMinDarkTime(d time.Duration) FlashOption
- func WithFlashProgress(fn func(written, total int64)) FlashOption
- func WithMaxDeviceSize(bytes int64) FlashOption
- func WithWriteRetries(n int) FlashOption
- func WithWriteTiming(fn func(offset int64, size int, took time.Duration)) FlashOption
- type ModeOption
- type Option
- type PowerFunc
- type SDWire
- func (s *SDWire) Close() error
- func (s *SDWire) FlashAndBoot(ctx context.Context, imagePath string, opts ...FlashOption) error
- func (s *SDWire) GetManufacturer() string
- func (s *SDWire) GetProduct() string
- func (s *SDWire) GetSerial() string
- func (s *SDWire) HasTargetPower() bool
- func (s *SDWire) Info() DeviceInfo
- func (s *SDWire) Mode() (SwitchMode, error)
- func (s *SDWire) PowerCycle(minOff time.Duration) error
- func (s *SDWire) SetMode(mode SwitchMode, opts ...ModeOption) error
- func (s *SDWire) SetTargetPower(fn PowerFunc)
- func (s *SDWire) String() string
- func (s *SDWire) TargetPower(on bool) error
- type SwitchMode
Constants ¶
const ( SDWireCVID = 0x04E8 SDWireCPID = 0x6001 SDWireCProductName = "sd-wire" SDWire3VID = 0x0BDA SDWire3PID = 0x0316 )
const DefaultMinDarkTime = 8 * time.Second
DefaultMinDarkTime is the minimum time PowerCycle keeps the target board's power off when no explicit minimum is given. Small DUT boards can ride through a mains interruption of a couple of seconds on PSU bulk capacitance without actually resetting, so a genuine power cycle needs a longer guaranteed dark time.
Variables ¶
var ErrNoDeviceFound = errors.New("no matching SDWire device found")
ErrNoDeviceFound is wrapped into every "not found" error returned by the selectBy* functions (and used directly by New()). It lets connect() distinguish "nothing matched" — worth trying the hubpower cache fallback for — from an ambiguous-match error, which should be returned as-is rather than silently resolved by a cache lookup. It is exported so callers (e.g. the sdwire CLI) can tell "device isn't there right now" apart from other connection failures.
Functions ¶
This section is empty.
Types ¶
type DeviceController ¶
type DeviceController interface {
// SetMode switches the SD card between the target device and the host computer.
SetMode(mode SwitchMode) error
// Mode reads back which side the SD card is currently connected to, where the
// underlying mechanism allows an honest readback.
Mode() (SwitchMode, error)
// Close releases any USB device handles the controller owns.
Close() error
}
DeviceController defines the interface for controlling different SDWire device generations.
type DeviceGeneration ¶
type DeviceGeneration int
DeviceGeneration represents the generation/type of SDWire device.
const ( // GenerationSDWireC represents the original SDWireC device using FTDI control. GenerationSDWireC DeviceGeneration = iota // GenerationSDWire3 represents the SDWire3 device using kernel driver attach/detach. GenerationSDWire3 )
func (DeviceGeneration) String ¶
func (g DeviceGeneration) String() string
String returns a human-readable description of the device generation.
type DeviceInfo ¶
type DeviceInfo struct {
Serial string
Product string
Manufacturer string
Generation DeviceGeneration
// Bus is the USB bus the device was enumerated on.
Bus int
// PortPath is the physical path of parent hub ports leading to the
// device, as reported by gousb's DeviceDesc.Path.
PortPath []int
}
DeviceInfo contains identifying information about an SDWire device.
func ListDevices ¶
func ListDevices() ([]*DeviceInfo, error)
ListDevices discovers all connected SDWire devices and returns their information. This is useful for device enumeration before connecting to a specific device.
func Revive ¶ added in v0.3.0
func Revive(selector string, opts ...Option) (DeviceInfo, error)
Revive power-cycles the hub port an SDWire3 is (or was) attached to and waits for it to re-enumerate: the software equivalent of unplugging the device and plugging it back in.
It exists for a reader that has stopped answering and been torn off the bus by the OS — a state a USB port reset does not clear, and which leaves the device invisible to ListDevices, so no ordinary selector can reach it. The port is held dark for readerRevivePause rather than merely reset, since a crashed reader can latch up through a shorter interruption.
selector may be:
- a location ("1-1.1.3"), resolved from live USB topology — the hub is still there even when the device on it isn't, so this works with no cache entry at all, or an ambiguous one;
- a serial or port-suffixed identity, matched against the hub-port cache;
- "", which requires the cache to hold exactly one entry.
The revived device's info is returned, and its hub port re-cached under the identity it enumerated with.
func (DeviceInfo) Identity ¶
func (d DeviceInfo) Identity() string
Identity returns the device's serial number, suffixed with its USB port path, e.g. "20120501030900000.1.1.3". This matches the identity format used by the Badger-Embedded Python sdwire CLI, and is needed because all Realtek SDWire3 devices share the same hardcoded USB serial number. A device with an empty PortPath returns its bare serial number.
func (DeviceInfo) Location ¶
func (d DeviceInfo) Location() string
Location returns the device's USB topology location in Linux sysfs style, e.g. "1-1.1.3". Devices with no parent hub ports in their path (an empty PortPath) return just the bus number, e.g. "1".
type DeviceState ¶ added in v0.3.0
type DeviceState struct {
Info DeviceInfo
Mode SwitchMode
// Attached reports whether the device was enumerated on USB. False
// means it is known only from the hub-port cache: its remembered port
// is either unpowered (an SDWire3 in target mode) or powered with
// nothing enumerated on it — an empty socket, or a reader that has
// stopped answering and been torn off the bus by the OS.
Attached bool
}
DeviceState is an SDWire and the mode its card is currently switched to.
func ListDeviceStates ¶ added in v0.3.0
func ListDeviceStates(opts ...Option) ([]DeviceState, error)
ListDeviceStates returns every SDWire this host knows about, with the mode each one's card is switched to: the devices currently enumerated on USB, plus every hub-port cache entry that is not currently producing one.
It never powers a port on or off — an SDWire3 sitting in target mode stays there — so unlike the New-family constructors it is safe to call just to see what is around. Cache-derived entries are a claim about a remembered location rather than a device seen now: see DeviceState.Attached.
type FlashOption ¶
type FlashOption func(*flashOptions)
FlashOption customizes a FlashAndBoot call.
func WithBlockDevTimeout ¶
func WithBlockDevTimeout(d time.Duration) FlashOption
WithBlockDevTimeout sets how long FlashAndBoot waits for the reader's block device to appear after switching to host mode. The default is 30 seconds.
func WithFlashMinDarkTime ¶
func WithFlashMinDarkTime(d time.Duration) FlashOption
WithFlashMinDarkTime sets the minimum time FlashAndBoot keeps the target board's power off before powering it back on, matching (*SDWire). PowerCycle's minOff semantics. The default is DefaultMinDarkTime.
func WithFlashProgress ¶
func WithFlashProgress(fn func(written, total int64)) FlashOption
WithFlashProgress configures a callback invoked after each chunk is written during FlashAndBoot, reporting bytes written so far and the total image size.
func WithMaxDeviceSize ¶
func WithMaxDeviceSize(bytes int64) FlashOption
WithMaxDeviceSize sets the sanity cap FlashAndBoot refuses to write past, guarding against a mis-mapped block device. The default is 2TiB.
func WithWriteRetries ¶ added in v0.3.0
func WithWriteRetries(n int) FlashOption
WithWriteRetries sets how many times a flash will recover from the reader dropping off the bus mid-write — power-cycling its hub port and resuming from the last completed chunk — before giving up. Zero disables the recovery, failing on the first such error as a plain write error.
func WithWriteTiming ¶ added in v0.3.0
func WithWriteTiming(fn func(offset int64, size int, took time.Duration)) FlashOption
WithWriteTiming registers a callback invoked after each chunk is written to the card, with the chunk's offset within the image, its size in bytes, and how long the write itself took (excluding reading the image).
It exists to make the shape of a flash measurable: a reader whose internal buffer is backing up shows up here as chunk times climbing well before it stalls outright.
type ModeOption ¶
type ModeOption func(*modeOptions)
ModeOption customizes a single SetMode call.
func WithoutUnmount ¶
func WithoutUnmount() ModeOption
WithoutUnmount skips the automatic unmount of the reader's mounted volumes that SetMode(ModeTarget) performs by default.
type Option ¶
type Option func(*options)
Option customizes a newly constructed SDWire.
func WithHostWaitTimeout ¶
WithHostWaitTimeout sets how long to wait for an SDWire3 to re-enumerate after switching to ModeHost (or while powering one on from the hub cache fallback) before giving up. The default is 20 seconds.
func WithHubCachePath ¶
WithHubCachePath overrides where the on-disk hub-port cache is read from and written to, in place of hubpower.DefaultCachePath().
func WithLegacySDWire3Switching ¶
func WithLegacySDWire3Switching() Option
WithLegacySDWire3Switching makes SDWire3 devices use the legacy kernel-driver detach/reset controller instead of the default VBUS port-power controller. That mechanism is not known to reliably move the SD card mux (see sdwire3Controller's doc comment), but may work on some native Linux setups; it is never the default.
func WithTargetPower ¶
WithTargetPower configures the PowerFunc used to control power to the target board (the Device Under Test) attached via this SDWire.
func WithWarningHandler ¶
WithWarningHandler configures a callback that receives non-fatal warning messages generated while operating a device, such as an SDWire3 sitting behind a ganged-power-switching hub. The default silently discards them.
func WithoutRevive ¶
func WithoutRevive() Option
WithoutRevive disables the hub-cache revive fallback: when no attached device matches, connect() returns the not-found error as-is instead of powering on a cached hub port and waiting for the device to reappear. Read-only callers (e.g. the sdwire CLI's `state` command) use this so they never have the side effect of switching an SDWire3 that is intentionally powered off in target mode back to host mode.
type PowerFunc ¶
PowerFunc controls power delivery to the target board (the Device Under Test) — not to the SDWire itself. Implementations should block until the requested power state has taken effect.
type SDWire ¶
type SDWire struct {
// contains filtered or unexported fields
}
SDWire represents a connected SDWire device that can switch an SD card between a target device and host computer.
func New ¶
New connects to the first available SDWire device. This is a convenience function for single-device setups. The returned SDWire must be closed with Close() when done.
func NewWithIdentity ¶
NewWithIdentity connects to a specific SDWire device using either the suffixed form returned by DeviceInfo.Identity() (e.g. "20120501030900000.1.1.3") or the form returned by DeviceInfo.Location() (e.g. "1-1.1.3"). Use NewWithSerial instead to match on a bare serial number. The returned SDWire must be closed with Close() when done.
func NewWithSerial ¶
NewWithSerial connects to a specific SDWire device by its serial number. serial may be a plain USB serial number, or the suffixed form returned by DeviceInfo.Identity() (e.g. "20120501030900000.1.1.3") to disambiguate devices that share a serial number, such as SDWire3s. If a plain serial matches more than one attached device, an error is returned listing the Identity() of each candidate. The returned SDWire must be closed with Close() when done.
func (*SDWire) Close ¶
Close releases the SDWire's controller (and any USB device handle(s) it holds) and its gousb.Context. Always call this when done with the device.
func (*SDWire) FlashAndBoot ¶
FlashAndBoot writes the image at imagePath to this SDWire's SD card and boots the target from it:
- Powers off the target (a no-op if no PowerFunc is configured; see WithTargetPower), recording when power was cut.
- Switches to host mode and waits for the reader's block device to appear.
- Checks the image fits the device (and the device fits a sanity cap), then unmounts any mounted volumes on it.
- Raw-writes the image to the device in chunks, reporting progress. If the reader drops off the bus mid-write — see WithWriteRetries — its hub port is power-cycled and the write resumes where it stopped.
- Switches back to target mode.
- Tops up the dark time begun in step 1 to at least the configured minimum, then powers the target back on.
Because a target board normally only probes its SD slot at boot (see (*SDWire).SetMode), step 6's power-on is what actually makes the newly written card visible to it. If no PowerFunc is configured, step 6 is skipped entirely and the caller is responsible for booting the target themselves.
Each step checks ctx before proceeding, so a cancelled context stops the operation at the next opportunity (including between write chunks).
func (*SDWire) GetManufacturer ¶
GetManufacturer returns the device's USB manufacturer name.
func (*SDWire) GetProduct ¶
GetProduct returns the device's USB product name.
func (*SDWire) HasTargetPower ¶
HasTargetPower reports whether a PowerFunc has been configured.
func (*SDWire) Info ¶
func (s *SDWire) Info() DeviceInfo
Info returns the DeviceInfo this SDWire was connected with, including its USB topology (Bus, PortPath) and the Identity()/Location() helpers derived from them. Useful for callers (e.g. the sdwire CLI) that connected via a partial selector — a bare serial, or a configured device name — and need the fully-resolved identity of the device they ended up with.
func (*SDWire) Mode ¶
func (s *SDWire) Mode() (SwitchMode, error)
Mode reads back which side the SD card is currently connected to. Not all controllers can answer honestly — see the relevant DeviceController's Mode doc comment (in particular, WithLegacySDWire3Switching's controller cannot).
func (*SDWire) PowerCycle ¶
PowerCycle power-cycles the target board: power off, a guaranteed dark time, then power on. minOff sets the minimum time power stays off; values <= 0 fall back to DefaultMinDarkTime. PowerCycle never sleeps for less than the requested dark time. If no PowerFunc is configured, PowerCycle is a no-op that returns nil without sleeping.
func (*SDWire) SetMode ¶
func (s *SDWire) SetMode(mode SwitchMode, opts ...ModeOption) error
SetMode switches the SD card between the target device and the host computer.
For SDWire3 devices (the default; see WithLegacySDWire3Switching for the legacy kernel-driver-based mechanism), this works by cutting or restoring VBUS on the SDWire3's upstream USB hub port, rather than by any command understood by the SDWire3 itself:
- ModeTarget cuts power to the SDWire3 reader. Losing power drops it off the bus entirely, and the now-unpowered mux passes the SD card through to the target — typically within about a second.
- ModeHost restores power. The reader re-enumerates at its USB power-on default (card connected to the host); the resulting block device typically appears roughly 6 seconds later.
Because a target board normally only probes its SD slot at boot or on a card-detect edge, it will not notice a card that arrived via ModeTarget until it is rebooted or power-cycled — see (*SDWire).PowerCycle.
SDWireC devices switch instantly via FTDI CBUS bits and have no such caveat.
Before switching to ModeTarget, any volumes mounted from this SDWire's reader are unmounted (see Unmount in internal/blockdev; on macOS a politely-dissented unmount is retried with force, since the data is flushed either way and the card is leaving the host regardless). Pass WithoutUnmount to skip this. If the reader's block device cannot be located at all, the switch proceeds — there is nothing mounted to lose — but an actual failed unmount aborts the switch rather than yanking a mounted filesystem away.
func (*SDWire) SetTargetPower ¶
SetTargetPower configures the function used to control power to the target board. Pass nil to remove any previously configured PowerFunc.
func (*SDWire) TargetPower ¶
TargetPower turns power to the target board on or off. If no PowerFunc has been configured, this is a documented no-op that returns nil.
type SwitchMode ¶
type SwitchMode int
SwitchMode represents the SD card connection mode.
const ( // ModeTarget connects the SD card to the target device being tested. ModeTarget SwitchMode = iota // ModeHost connects the SD card to the host computer for flashing/access. ModeHost )
const ModeUnknown SwitchMode = -1
ModeUnknown indicates a DeviceController could not determine which side the SD card is currently connected to (for example, a hub port that is powered but whose device has not finished re-enumerating yet).
func CachedPortState ¶
func CachedPortState(selector string, opts ...Option) (SwitchMode, string, error)
CachedPortState reports an SDWire3's mode purely from the on-disk hub cache and a hub port-status read, WITHOUT powering anything on or off — safe for a device that is currently powered off (in target mode). This is the read-only counterpart to New's cache-revive fallback: it never causes an SDWire3 sitting in target mode to switch to host mode as a side effect of being asked about it.
selector may be "" (which requires exactly one cached entry, erroring and listing candidates otherwise), or a serial / port-suffixed identity / location matched with the same rules as NewWithSerial / NewWithIdentity.
Alongside the mode, CachedPortState returns the matched cache entry's identity (its DeviceInfo.Identity() form) — useful for callers (e.g. the sdwire CLI) that need to display which device they read state for. The returned error is nil unless the cache itself couldn't be read, no entry matched selector, or opening the hub / reading its port status failed (which is expected for a genuinely stale or unreachable cache entry).
func (SwitchMode) String ¶
func (m SwitchMode) String() string
String returns a human-readable description of the switch mode.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
sdwire
command
Command sdwire is a CLI for controlling SDWireC and SDWire3 USB SD-card multiplexers, and a drop-in replacement for the Python sdwire CLI's list/state/switch commands.
|
Command sdwire is a CLI for controlling SDWireC and SDWire3 USB SD-card multiplexers, and a drop-in replacement for the Python sdwire CLI's list/state/switch commands. |
|
Package hubpower controls USB hub downstream port power (VBUS) over gousb.
|
Package hubpower controls USB hub downstream port power (VBUS) over gousb. |
|
internal
|
|
|
blockdev
Package blockdev locates, sizes, and prepares for writing the whole-disk block device backing a specific USB mass-storage device — typically an SDWire reader switched into host mode — identified by its USB vendor/product ID and its physical bus/port location.
|
Package blockdev locates, sizes, and prepares for writing the whole-disk block device backing a specific USB mass-storage device — typically an SDWire reader switched into host mode — identified by its USB vendor/product ID and its physical bus/port location. |
|
Package power documents the contract for SDWire target-power plugins.
|
Package power documents the contract for SDWire target-power plugins. |
|
meross
Package meross drives Meross smart plugs (MSS315 and compatible models) over their local HTTP API, with no dependency on the Meross cloud at runtime.
|
Package meross drives Meross smart plugs (MSS315 and compatible models) over their local HTTP API, with no dependency on the Meross cloud at runtime. |