Skip to content
b1ugPublic

About

Gopher Interface Devices for USB HID

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Latest commit

 

History

14 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gid - Gopher Interface Devices

Go Reference Go Report Card GitHub Actions CircleCI

Yet another Go package tailored for interacting with USB Human Interface Devices (HID).

This package facilitates cross-platform communications with HID devices on macOS, Linux, and Windows. Behind the scenes, it employs boombuler/hid as its foundation and broadens its functionalities by reading feature reports from USB HID devices, and its Linux implementation is a derivative of dolmen-go/hid, which wraps hidapi.

Divergent from comprehensive USB HID packages, gid chiefly focuses on offering support limited to HID devices with feature reports across major platforms. Our primary spotlight is the ThingM blink(1) devices.

Compatible Operating Systems

The native backends target the following systems:

  • macOS: Through its native IOKit framework
  • Linux: Leverages libusb 1.0+
  • Windows: Utilizes native Windows HID library

The original project recorded tests on these systems. These historical results do not establish compatibility of the current candidate with those OS versions:

  • macOS Ventura 13.5.2 (on Apple M1 Chip)
  • Windows 10 x64 - Build 19045
  • Windows 11 x64 - Build 22621
  • Raspberry Pi OS 64-bit Bullseye (on Raspberry Pi 3 Model B)

The original hardware test target was:

  • ThingM blink(1) mk2

Limitations

This package is designed to support minimum USB HID functionality needed for ThingM blink(1) on major platforms only. Therefore, not all HID features have been implemented.

Continuous integration and hardware tests

The repository's native CI configuration builds the CGO backend and runs tests (including the Go race detector) on Ubuntu 24.04 amd64/arm64, macOS 15 arm64/Intel, and Windows Server 2022 amd64, with Go 1.26.x and 1.27.x. The runner labels are explicit; see GitHub's current standard runner list. Go 1.13.15 is checked separately on Ubuntu 22.04 to retain the module's source compatibility floor. This does not establish a minimum supported OS version or verify old systems, Raspberry Pi OS, or device I/O on hosted runners.

The current development candidate is on validation/runtime-gid; it is separate from the frozen PR #2 at f520a7e. CI results apply to their exact checked-out commits. The runtime integration run passed all eight jobs with GID 7d9978d, including Windows amd64 and 386/WOW64 software tests. See the Chinese candidate validation record for the commits, failed attempt, local checks and remaining hardware work.

By default, tests do not enumerate or open host HID devices. Real enumeration requires GID_TEST_ENUMERATE=1. To opt in to an open/close smoke test, select an exact device path from an explicitly authorized gid.Devices() enumeration:

GID_TEST_DEVICE_PATH='your-platform-specific-device-path' go test -run '^TestOpenSelectedDevice$' -v .

The selected-device test fails if that device cannot be found or opened. It does not write reports. Report I/O, firmware compatibility, unplug/replug behavior, and concurrent access still require separate tests with the intended hardware. CGO_ENABLED=0 selects an unsupported-platform stub; a successful build in that mode is not evidence that the native HID backend works.

Report buffers and device lifetime

Output and feature reports start with a report ID; use zero for an unnumbered report and include at least one payload byte after that zero. Empty buffers and a lone zero ID return an error. This also replaces Linux's former empty-buffer no-op. Linux input Read remains a stream read and accepts any nonempty buffer.

Windows pads writes to the collection's reported size and rejects oversized data instead of silently truncating it. Counted reads return only the number of bytes placed in the caller's buffer, with io.ErrShortBuffer if necessary. Windows input-report IOCTLs may return a zero byte count despite filling the buffer; that native count and the filled data are preserved. Input Read has platform-specific behavior and is not a portable event-stream contract.

On macOS, synchronous I/O and Close hold the same lock for the complete native operation. Repeated Close is safe, and closed-handle operations return errors. The synchronous backend does not register asynchronous removal callbacks; disconnects surface as I/O errors, and callers must still call Close and open a new device after re-enumeration. Close waits for pending native I/O and has no guaranteed deadline. Physical unplug/replug still requires hardware testing.

In the current Linux candidate, every implemented I/O operation pins the native handle through the call and error-string copy. Close rejects new operations, waits for active leases and disposes once. Input Read uses internal 100 ms native wait slices to observe closing while retaining its blocking public behavior. Reads and writes can overlap; a write that causes input is not blocked behind the waiting read. The slice is not a close deadline: native calls, the vendored clock behavior and the read-thread join can still delay completion.

In the current Windows candidate, Close publishes closing, requests CancelIoEx, waits for active operations and closes the handle once. Each overlapped operation retains its own C-allocated payload, OVERLAPPED and event until native completion is collected. A late-issued operation also requests its own cancellation if closing has begun. Requesting cancellation does not release resources early. Synchronous HidD_SetFeature and driver behavior can still delay Close. Native Windows software tests cover pending named-pipe cancellation; they do not validate physical HID or guarantee a close deadline. The enumeration candidate also bounds string copying and uses the native C detail-structure size; HID metadata failures leave optional strings empty rather than reusing another field. See the Windows validation notes and metadata regression record.

These lifetime guards do not serialize a multi-call application protocol. A request-write/response-read transaction still needs an application-level owner or lock. No operation provides a portable context or timeout contract, and disconnect recovery still requires closing, re-enumerating and opening a new handle. Physical Linux/Windows USB and blink(1) mk3 behavior remain unverified.

Darwin native errors now preserve their existing text while exposing the raw IOKit code through NativePlatform() / NativeCode(). Other platforms' errors have not been unified into that diagnostic contract. See native error details.

The Darwin metadata candidate no longer opens a whole HID manager while enumerating. FindDevices prefilters nonzero VID/PID values in IOKit and retains exact Go filtering for zero metadata IDs, including legacy missing/non-number properties normalized to zero. Devices retains all-device metadata discovery. DeviceInfo.Open uses the same candidate policy and opens only the exact selected path. Real host enumeration tests require GID_TEST_ENUMERATE=1, and actual device opening still requires GID_TEST_DEVICE_PATH. Skipped hardware tests are not hardware validation. See the Darwin matching and test boundaries. Optional Darwin string metadata is type-checked before calling CoreFoundation string APIs; missing or non-string values become empty strings. See the Darwin string metadata boundary and its software-only crash regression test.

On Linux, FindDevices(vendor, product) passes IDs to HIDAPI before its string-query device opens, then retains exact Go equality: zero IDs in the public API are literal values, even though native HIDAPI uses them as wildcard candidates. Devices() keeps full discovery. The embedded libusb can still attempt earlier USB-node read/write access on old or unavailable sysfs paths; this is not a promise that discovery never opens unrelated devices. Windows discovery uses zero-access metadata handles, not generic read/write handles. See the Linux discovery scope and software validation.

Credits and License

License: MIT

The gid package owes its genesis to the following repositories:

The included dependencies carry the following licenses:

Being open-source, the gid package is licensed under the widely-accepted MIT license.

About

Gopher Interface Devices for USB HID

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages