Files
DP44/enriched-qwen3-coder-next/Common/DTS.Common.IConnection/USBConnection/HIDUSBConnection.md
2026-04-17 14:55:32 -04:00

147 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
source_files:
- Common/DTS.Common.IConnection/USBConnection/HIDUSBConnection/HIDUSBConnection.cs
generated_at: "2026-04-16T02:10:22.619594+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "4a9eeb7b8043999a"
---
# Documentation: `HIDUSBConnection` Class
## 1. Purpose
`HIDUSBConnection` is a concrete implementation of the `IConnection` interface that enables communication with a specific HID-class USB device (identified by Vendor ID `0x1CB9` and Product ID `0x0003`, named *HIDSLICE*) using Windows file I/O APIs (`CreateFile`, `ReadFile`, `WriteFile` via overlapped I/O). It abstracts low-level HID report handling (input/output reports) over USB, providing asynchronous send/receive semantics consistent with .NETs `IAsyncResult` pattern. This module exists to support direct, low-latency data transfer to/from embedded hardware (e.g., a data acquisition recorder) where standard socket-based communication is not applicable.
---
## 2. Public Interface
### Constructors & Finalizer
- **`HIDUSBConnection()`**
Initializes the instance, sets up `SECURITY_ATTRIBUTES` for `CreateFile`, and initializes `_Connected = false`.
- **`~HIDUSBConnection()`**
Finalizer that invokes `Dispose(false)` to release unmanaged resources.
### Disposal
- **`void Dispose()`**
Performs deterministic cleanup: calls `Dispose(true)` and suppresses finalization.
- **`protected virtual void Dispose(bool disposing)`**
Releases all handles (`_HIDHandle`, `_ReadHandle`, `_WriteHandle`) via `FileIODeclarations.CloseHandle`, disposes `_MyHID`, and sets `_Connected = false`. Idempotent (`disposed` flag prevents double-disposal).
### Connection Management
- **`void Create(string ConnectString)`**
Stores the device path (`ConnectString`) for later use in `EndConnect`. Does *not* open the device.
- **`IAsyncResult BeginConnect(AsyncCallback cb, object state)`**
Initiates asynchronous connection. Enqueues a work item to invoke `NetCallbackFix`, which in turn invokes the callback on the thread pool. *Actual device opening occurs in `EndConnect`*.
- **`void EndConnect(IAsyncResult ar)`**
Opens the device using `ConnectString` (set via `Create`) via three `CreateFile` calls:
- `_HIDHandle`: for attribute queries (no access rights)
- `_ReadHandle`: for reading input reports (`GENERIC_READ`)
- `_WriteHandle`: for writing output reports (`GENERIC_WRITE`)
Retrieves device attributes (`HidD_GetAttributes`), capabilities (`GetDeviceCapabilities`), and input report buffer size (`GetInputReportBufferSize`). Flushes the input queue. Sets `_Connected = true`. Throws on handle failure or attribute retrieval failure.
- **`IAsyncResult BeginDisconnect(bool reuseSocket, AsyncCallback cb, object state)`**
Asynchronous disconnect. Enqueues a work item to invoke the callback. *Actual cleanup is deferred to `EndDisconnect`*.
- **`void EndDisconnect(IAsyncResult asyncResult)`**
Closes all three handles (`_HIDHandle`, `_ReadHandle`, `_WriteHandle`) and sets `_Connected = false`.
### Properties
- **`bool Connected { get; }`**
Returns `_Connected`.
- **`string ConnectString { get; }`**
Returns `Device_Name` (set via `Create`).
- **`System.Net.Sockets.SocketFlags Flags { get; set; }`**
Property required by `IConnection` interface; unused in this implementation.
- **`string GetConnectionData()`**
Returns `""` (empty string). No meaningful data exposed.
- **`double GetCurrentDownloadRate()`**
Returns `0D`. Rate tracking not implemented.
- **`double GetCurrentUploadRate()`**
Returns `0D`. Rate tracking not implemented.
### Static Utility
- **`static string GetFirstConnectString()`**
Scans all HID devices on the system to find the first device matching `DTS_VID` (`0x1CB9`) and `HIDSLICE_PID` (`0x0003`). Returns the devices path string (e.g., `\\?\hid#vid_1cb9&pid_0003#...`) or `string.Empty` if not found. Uses `HIDDeclarations.HidD_GetHidGuid`, `DeviceManagement.FindDeviceFromGuid`, and `HIDDeclarations.HidD_GetAttributes`.
### I/O Operations
- **`IAsyncResult BeginSend(byte[] buffer, int offset, int size, AsyncCallback cb, object state)`**
Initiates asynchronous send. Validates `_ReadHandle` and `_WriteHandle` are valid. Enqueues callback via `ThreadPool.QueueUserWorkItem`. *Actual transmission occurs in `EndSend`*.
- **`int EndSend(IAsyncResult ar)`**
Writes `buffer[offset..offset+size)` to the device in chunks, respecting `OutputReportByteLength`.
- Prepends each chunk with report ID `0x00` at index `0`.
- Uses `HIDevice.OutputReport.Write` for each chunk.
Returns `size` (number of bytes sent). Throws on invalid handles or write failure.
- **`IAsyncResult BeginReceive(byte[] buffer, int offset, int size, AsyncCallback cb, object state)`**
Initiates asynchronous receive. Validates handles. Enqueues callback. *Actual read occurs in `EndReceive`*.
- **`int EndReceive(IAsyncResult ar)`**
Reads one input report into `InputReportBuffer` via `HIDevice.InputReport.Read`. Copies data (skipping report ID at index `0`) into `buffer[offset..]`. Returns `size` if successful, `0` otherwise. Sets `IsCompleted = true` and signals `AsyncWaitHandle`.
### Unsupported Operations (Throw `NotSupportedException`)
- `BeginAccept`, `EndAccept`, `Bind(int)`, `Listen(int)`
These methods are implemented only to satisfy `IConnection` but are not applicable to HID device communication.
---
## 3. Invariants
- **Device Identity**: Only devices with `VendorID == 0x1CB9` and `ProductID == 0x0003` are accepted.
- **Handle State**: `_HIDHandle`, `_ReadHandle`, and `_WriteHandle` must be valid (non-`INVALID_HANDLE_VALUE`) before `BeginSend`/`BeginReceive` succeeds.
- **Connection State**: `_Connected` is `true` only after successful completion of `EndConnect`, and `false` otherwise (including after `EndDisconnect` or disposal).
- **Report Structure**:
- Input reports: Data starts at index `1`; index `0` is the report ID (ignored).
- Output reports: Data starts at index `1`; index `0` is report ID (set to `0`).
- **Buffer Size**: `InputReportBuffer` is sized to `_MyHID.Capabilities.InputReportByteLength` during `EndConnect`.
- **Disposal Safety**: `Dispose` is idempotent (`disposed` flag prevents re-entry).
- **Asynchronous Pattern**: All async operations (`BeginConnect`, `BeginSend`, etc.) use `HIDUSBRecAsyncResult` and delegate callback invocation to `NetCallbackFix`, which runs on a thread pool thread.
---
## 4. Dependencies
### External Dependencies
- **Windows API (via interop)**:
- `FileIODeclarations.CreateFile`, `CloseHandle`, `FILE_SHARE_*`, `GENERIC_*`, `INVALID_HANDLE_VALUE`, `OPEN_EXISTING`
- `HIDDeclarations.HidD_GetHidGuid`, `HidD_GetAttributes`
- **`DTS.DASLib.Connection.USBFramework`**:
- `HIDevice` class (used for device attributes, capabilities, input/output report handling)
- `DeviceManagement` class (used in `GetFirstConnectString`)
- **`DTS.DASLib.DASResource`**:
- `Strings` resource class (for localized error messages, e.g., `Strings.HIDUSBConnection_EndConnect_Err1`)
- **.NET Framework Core**:
- `System.Runtime.InteropServices` (for `Marshal.SizeOf`, `SECURITY_ATTRIBUTES`)
- `System.Threading` (for `ThreadPool`, `ManualResetEvent`)
- `System.Windows.Forms.MessageBox` (used in `NetCallbackFix` for exception reporting—*potential runtime dependency on WinForms*).
### Implemented Interfaces
- `IConnection` (interface defining the contract; not shown in source but referenced).
### Inferred Consumers
- Any code requiring `IConnection` to communicate with the *HIDSLICE* device (e.g., data acquisition logic, device enumeration UI).
- `GetFirstConnectString` is likely called by device discovery components.
---
## 5. Gotchas
- **Misleading Async Pattern**: `BeginConnect`/`BeginSend`/`BeginReceive` do *not* perform actual I/O; they only enqueue a callback. All work happens in `End*` methods. This deviates from typical .NET async patterns where `Begin*` initiates the operation.
- **No Overlapped I/O**: Despite using `CreateFile` with overlapped semantics (implied by `_ReadHandle`/`_WriteHandle`), the code does *not* use `OVERLAPPED` structures or `ReadFile`/`WriteFile` with completion callbacks. Instead, it relies on synchronous `HIDevice.InputReport.Read`/`Write`, which may block the thread pool thread.
- **Hardcoded Report ID**: Output reports always use `0x00` as the report ID. This assumes the device expects report ID `0`; mismatched IDs will cause silent failures or device errors.
- **WinForms Dependency in Error Handling**: `NetCallbackFix` shows a `MessageBox` on exceptions—a severe anti-pattern for non-UI threads or server environments.
- **`GetFirstConnectString` Hack**: The method scans *all* HID devices and stops at the first match. If multiple *HIDSLICE* devices are connected, behavior is undefined (first found wins).
- **Buffer Size Mismatch in `EndReceive`**: `EndReceive` copies `InputReportBuffer.Length - 1` bytes into the user buffer, but returns `rar.size` regardless. If `rar.size < InputReportBuffer.Length - 1`, the caller may read uninitialized buffer data beyond the actual received payload.
- **No Timeout Handling**: No mechanism for read/write timeouts; operations may block indefinitely.
- **`Flags` Property Unused**: The `SocketFlags` property is implemented but never used.
- **`BeginAccept`/`EndAccept` Misuse**: Throwing `NotSupportedException` for connection-oriented methods suggests this class was adapted from a socket-based `IConnection` implementation without full refactoring.