Files
2026-04-17 14:55:32 -04:00

111 lines
8.7 KiB
Markdown

---
source_files:
- Common/DTS.Common.IConnection/USBConnection/WINUSBConnection/WINUSBDeviceApi.cs
- Common/DTS.Common.IConnection/USBConnection/WINUSBConnection/CDCUSBConnection.cs
- Common/DTS.Common.IConnection/USBConnection/WINUSBConnection/WINUSBConnection.cs
generated_at: "2026-04-16T11:50:38.580755+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "2043cd8e3c0f04ef"
---
# Documentation: DTS.Common.WINUSBConnection
## 1. Purpose
This module provides USB connectivity abstractions within the `DTS.Common.WINUSBConnection` namespace. It contains two concrete implementations of the `IConnection` interface: `CDCUSBConnection`, which wraps a standard `System.IO.Ports.SerialPort` for CDC (Communications Device Class) USB devices, and `WINUSBConnection`, which provides low-level communication via the native `winusb.dll` API for custom WinUSB devices. Additionally, it defines the internal P/Invoke signatures and data structures required to interact with the Windows WinUSB driver stack.
## 2. Public Interface
### Class: `CDCUSBConnection`
Implements `IConnection`. Represents a USB device connection via a virtual COM port (CDC).
* **`void Create(string connectString, string hostIPAddress)`**
* Parses the `connectString` to match against registry keys in `RegKeys`. If a match is found, it retrieves the `PortName` from the registry (`Device Parameters` subkey) and configures the internal `SerialPort` instance.
* **`IAsyncResult BeginConnect(AsyncCallback cb, object state)`**
* Initiates an asynchronous connection. Queues the connection logic to the thread pool.
* **`void EndConnect(IAsyncResult ar)`**
* Completes the asynchronous connection. Configures the serial port (BaudRate, DataBits, etc.) and calls `_comPort.Open()`. Sets `Connected` to `true`.
* **`IAsyncResult BeginSend(byte[] buffer, int offset, int size, AsyncCallback cb, object state)`**
* Initiates an asynchronous send operation.
* **`int EndSend(IAsyncResult ar)`**
* Completes the send operation. Writes data to the internal `_comPort` using `_comPort.Write`.
* **`Task<int> SendAsync(byte[] sendBuffer, int bufferStartOffset, int bufferSizeToSend)`**
* Task-based asynchronous wrapper for `BeginSend`/`EndSend`.
* **`IAsyncResult BeginReceive(byte[] buffer, int offset, int size, AsyncCallback cb, object state)`**
* Initiates an asynchronous receive operation.
* **`int EndReceive(IAsyncResult ar)`**
* Completes the receive operation. Reads data from `_comPort`. **Note:** This method blocks in a loop (`Thread.Sleep(1)`) until at least one byte is read.
* **`IAsyncResult BeginDisconnect(bool reuseSocket, AsyncCallback cb, Object state)`**
* Initiates an asynchronous disconnect.
* **`void EndDisconnect(IAsyncResult ar)`**
* Completes the disconnect. Closes and disposes the internal `_comPort`.
* **Properties**
* `bool Connected`: Gets the current connection state.
* `string ConnectString`: Returns the device pathname.
* `IList<string> RegKeys`: Static property that lazily loads registry keys for the device from `SYSTEM\CurrentControlSet\Enum\USB\`.
### Class: `WINUSBConnection`
Implements `IConnection`. Represents a USB device connection using the native WinUSB driver.
* **`void Create(string connectString, string hostIPAddress)`**
* Stores the `connectString` in the `ConnectString` property.
* **`IAsyncResult BeginConnect(AsyncCallback cb, object state)`**
* Initiates an asynchronous connection. Throws `NotConnectedException` if already connected.
* **`void EndConnect(IAsyncResult ar)`**
* Completes the connection. Instantiates a new `WinUsbDevice`, retrieves a device handle via `GetDeviceHandle`, and initializes the device via `InitializeDevice`. Uses a mutex (`_usbConnectionMutex`) to synchronize access.
* **`IAsyncResult BeginSend(byte[] buffer, int offset, int size, AsyncCallback cb, object state)`**
* Initiates an asynchronous send. Validates buffer parameters.
* **`int EndSend(IAsyncResult ar)`**
* Completes the send. Checks `MyDevInfo.UseHybridBulkIntMode`. If true, calls `SendViaInterruptTransfer`; otherwise, calls `SendViaBulkTransfer`.
* **`Task<int> SendAsync(byte[] sendBuffer, int bufferStartOffset, int bufferSizeToSend)`**
* Task-based asynchronous wrapper for `BeginSend`/`EndSend`.
* **`IAsyncResult BeginReceive(byte[] buffer, int offset, int size, AsyncCallback cb, object state)`**
* Initiates an asynchronous receive.
* **`int EndReceive(IAsyncResult ar)`**
* Completes the receive. Reads data via `ReadViaBulkTransfer`. Blocks in a loop (`Thread.Sleep(1)`) until bytes are read. Returns 0 if the connection fails or closes.
* **`IAsyncResult BeginDisconnect(bool reuseSocket, AsyncCallback cb, Object state)`**
* Initiates an asynchronous disconnect.
* **`void EndDisconnect(IAsyncResult ar)`**
* Completes the disconnect. Calls `DisposeSliceDev` to release the WinUSB handle.
* **Properties**
* `bool Connected`: Gets the current connection state.
* `string ConnectString`: Gets the device pathname.
### Internal Class: `WinUsbDevice` (Partial)
Defines P/Invoke signatures and structures for `winusb.dll`.
* **Structs**: `USBConfigurationDescriptor`, `USBInterfaceDescriptor`, `WinUSBPipeInformation`, `WinUSBSetupPacket`.
* **Enums**: `PolicyType`, `USBDPipeTypes`, `USBDeviceSpeeds`.
* **Methods**: `WinUsb_Initialize`, `WinUsb_Free`, `WinUsb_ControlTransfer`, `WinUsb_ReadPipe`, `WinUsb_WritePipe`, `WinUsb_QueryPipe`, `WinUsb_SetPipePolicy`, etc.
## 3. Invariants
* **Registry Dependency (CDCUSBConnection)**: The `CDCUSBConnection` requires the device to be registered under `SYSTEM\CurrentControlSet\Enum\USB\` with a Vendor ID of `VID_1CB9` and Product ID of `PID_001A`. The `Create` method cannot resolve the port name if these registry keys are missing.
* **Thread Safety (WINUSBConnection)**: The `WINUSBConnection.EndConnect` and `DisposeSliceDev` methods rely on a named Mutex (`"USBConnection"`) to prevent race conditions during device initialization and disposal.
* **Disposal State**: Both connection classes track `Disposed` and `Disposing` flags. Methods generally do not proceed if `Disposed` is true.
* **APM Pattern**: Both classes implement the Asynchronous Programming Model (APM) using internal `IAsyncResult` implementations (`UsbRecAsyncResult` and `WinUSBRecAsyncResult`). Callbacks are invoked via `ThreadPool.QueueUserWorkItem`.
## 4. Dependencies
### Internal Dependencies
* `DTS.Common.Interface.Connection`: Implements `IConnection`.
* `DTS.Common.DASResource`: Uses localized strings for exception messages (e.g., `Strings.CDCUSBConnection_BeginConnect_Err1`).
* `DTS.Common.Utilities.Logging`: Uses `APILogger` for logging exceptions and status messages.
* `DTS.Common.USBFramework`: Uses `DeviceManagement` class (in `WINUSBConnection`).
* `DTS.Common.Classes.Connection`: Uses `NotConnectedException`.
### External Dependencies
* `System.IO.Ports`: Used by `CDCUSBConnection` for `SerialPort`.
* `System.Runtime.InteropServices`: Used for P/Invoke attributes.
* `Microsoft.Win32`: Used for registry access (`RegistryKey`, `SafeFileHandle`).
* `winusb.dll`: Native Windows DLL imported by `WinUsbDevice`.
## 5. Gotchas
* **Blocking Async Reads**: The `EndReceive` methods in both `CDCUSBConnection` and `WINUSBConnection` contain `while` loops that sleep (`Thread.Sleep(1)`) if zero bytes are read. This effectively makes the "asynchronous" operation blocking and consumes a thread pool thread while waiting for data.
* **Recursive Comment**: The `Create(string connectString)` method in both connection classes contains a commented-out line `//Create(connectString);` with a note "this is recursive!". This suggests a historical bug or confusion regarding method overloads.
* **Empty Soft Disconnect**: `SoftConnect` and `SoftDisconnect` methods are implemented but empty. The comments explicitly state they do nothing because there is no soft disconnect option implemented.
* **Hardcoded Device IDs**: `CDCUSBConnection` hardcodes `DTS_VENDOR_ID` (0x1CB9) and `DTS_TSR2_CDCUSB_PRODUCT_ID_STR` ("PID_001A"). It will not work with other USB devices.
* **Partial Class Source**: `WinUsbDevice` is defined as `internal sealed partial class`. The logic for `GetDeviceHandle`, `InitializeDevice`, `SendViaBulkTransfer`, etc., is referenced in `WINUSBConnection` but is **not present in the provided source files** (likely in another file part of the partial class definition).
* **Hybrid Mode Logic**: `WINUSBConnection.EndSend` switches between interrupt and bulk transfers based on a boolean `UseHybridBulkIntMode` located on a `MyDevInfo` object. The definition of `MyDevInfo` is not visible in the provided source.