--- 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-16T02:09:52.794052+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "2043cd8e3c0f04ef" --- # Documentation: USB Connection Modules ## 1. Purpose This module provides two distinct USB-based connection implementations (`CDCUSBConnection` and `WINUSBConnection`) that implement the `IConnection` interface for communicating with DTS hardware devices. `CDCUSBConnection` emulates a serial port over USB using the Windows `SerialPort` class (CDC–Communication Device Class), while `WINUSBConnection` uses the native Windows WinUSB API (`winusb.dll`) for direct USB communication. Both modules support asynchronous I/O operations (`BeginConnect`, `EndConnect`, `BeginSend`, `EndSend`, etc.), resource disposal, and registry-based device enumeration for the DTS vendor ID `0x1CB9` and specific product IDs. ## 2. Public Interface ### `CDCUSBConnection` - **`public bool IsSoftDisconnected { get; }`** Always returns `false`. Soft disconnect is not supported for CDCUSB. - **`public void SoftConnect()`** No-op. Soft connect is not supported. - **`public void SoftDisconnect()`** No-op. Soft disconnect is not supported. - **`public double GetCurrentUploadRate()`** Returns `0.0`. Upload rate is not tracked. - **`public double GetCurrentDownloadRate()`** Returns `0.0`. Download rate is not tracked. - **`public string PortName { get; set; }`** Gets or sets the COM port name (e.g., `"COM3"`) used for serial communication. - **`public string ConnectString { get; }`** Returns the `_devicePathname` passed to `Create`. Used as a device identifier. - **`public bool Connected { get; }`** Returns `_Connected`, indicating whether the underlying `SerialPort` is open. - **`public event EventHandler OnDisconnected`** Event raised on disconnection (currently unused in this implementation). - **`public static IList RegKeys { get; }`** Lazily-initialized list of registry subkey names under the DTS CDCUSB device path (`USB\VID_1CB9&PID_001A`). Used to locate device-specific COM port names. - **`public CDCUSBConnection()`** Constructor initializing internal state (`_Connected = false`, `Disposed = false`, `Disposing = false`). - **`public void Create(string connectString, string hostIPAddress)`** Parses `connectString` to match a registry key in `RegKeys`, then reads the `"PortName"` value from the device’s registry `"Device Parameters"` subkey and assigns it to `PortName`. Sets `_devicePathname = connectString`. - **`public IAsyncResult BeginConnect(AsyncCallback cb, object state)`** Returns an `IAsyncResult` (`UsbRecAsyncResult`) and queues a callback via `ThreadPool.QueueUserWorkItem`. Does *not* perform the actual connection. - **`public void EndConnect(IAsyncResult ar)`** Opens the `SerialPort` using configured `_baudRate`, `_parity`, `_stopBits`, `DATA_BITS`, and `PortName`. Sets `_Connected = true` on success. - **`public IAsyncResult BeginSend(byte[] buffer, int offset, int size, AsyncCallback cb, object state)`** Returns `UsbRecAsyncResult` with buffer metadata. Actual write occurs in `EndSend`. - **`public int EndSend(IAsyncResult ar)`** Writes `buffer` (using `size` and `offset` from `UsbRecAsyncResult`) to `_comPort.Write(...)`. Returns `size`. - **`public Task SendAsync(...)`** Wraps `BeginSend`/`EndSend` in a `Task`. - **`public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, AsyncCallback cb, object state)`** Returns `UsbRecAsyncResult` with buffer metadata. - **`public int EndReceive(IAsyncResult ar)`** Reads from `_comPort.Read(...)` in a loop until at least one byte is read (sleeps 1 ms between retries). Returns number of bytes read. - **`public IAsyncResult BeginDisconnect(...)`** Returns `UsbRecAsyncResult`. Actual disconnect occurs in `EndDisconnect`. - **`public void EndDisconnect(IAsyncResult ar)`** Closes and disposes `_comPort`, sets `_Connected = false`. - **`public void Dispose()` / `protected virtual void Dispose(bool)`** Implements `IDisposable`. Closes `_comPort` if open, sets `Disposed = true`. - **`public void Bind(int port)` / `public void Listen(int backlog)` / `public IAsyncResult BeginAccept(...)` / `public IConnection EndAccept(...)`** All throw `NotSupportedException`. ### `WINUSBConnection` - **`public bool IsSoftDisconnected { get; }`** Always returns `false`. Soft disconnect is not supported. - **`public void SoftConnect()` / `public void SoftDisconnect()`** No-op. - **`public double GetCurrentUploadRate()` / `public double GetCurrentDownloadRate()`** Return `0.0`. - **`public bool Connected { get; private set; }`** Indicates whether the device is connected via WinUSB. - **`public string ConnectString { get; private set; }`** Stores the device path passed to `Create`. - **`public event EventHandler OnDisconnected`** Event for disconnection notifications (currently unused). - **`public void Create(string connectString, string hostIPAddress)`** Stores `connectString` in `ConnectString`. - **`public IAsyncResult BeginConnect(AsyncCallback cb, object state)`** Validates `_sliceDev == null && !Connected`. Returns `WinUSBRecAsyncResult`, waits synchronously on `AsyncWaitHandle` before returning. - **`public void EndConnect(IAsyncResult ar)`** Instantiates `_sliceDev = new WinUsbDevice()`, calls `_sliceDev.GetDeviceHandle(ConnectString)` and `_sliceDev.InitializeDevice()`. Sets `Connected = true` on success. Logs and throws `NotConnectedException` on failure. - **`public IAsyncResult BeginSend(byte[] buffer, int offset, int size, AsyncCallback cb, object state)`** Validates connection and buffer parameters. Returns `WinUSBRecAsyncResult`. - **`public int EndSend(IAsyncResult ar)`** Copies buffer data, then calls `_sliceDev.SendViaInterruptTransfer(...)` or `_sliceDev.SendViaBulkTransfer(...)` depending on `MyDevInfo.UseHybridBulkIntMode`. Throws on failure. - **`public Task SendAsync(...)`** Wraps `BeginSend`/`EndSend`. - **`public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, AsyncCallback cb, object state)`** Validates connection and buffer parameters. Returns `WinUSBRecAsyncResult`. - **`public int EndReceive(IAsyncResult ar)`** Calls `_sliceDev.ReadViaBulkTransfer(...)` in a loop until `bytesRead > 0` or failure. Copies data into `rar.Buffer`. Returns bytes read. - **`public IAsyncResult BeginDisconnect(...)`** Validates `_sliceDev != null`. Sets `Connected = false`, returns `WinUSBRecAsyncResult`. - **`public void EndDisconnect(IAsyncResult ar)`** Calls `DisposeSliceDev()` to release WinUSB handle. - **`public void Dispose()` / `protected virtual void Dispose(bool)`** Implements `IDisposable`. Disposes `_wusbDeviceManagement` and calls `DisposeSliceDev()`. Uses `Mutex _usbConnectionMutex` for thread safety. - **`public void Bind(int port)` / `public void Listen(int backlog)` / `public IAsyncResult BeginAccept(...)` / `public IConnection EndAccept(...)`** All throw `NotSupportedException`. ### `WinUsbDevice` (internal) - **`internal const uint DEVICE_SPEED = 1`** Used with `WinUsb_QueryDeviceInformation`. - **`internal const byte USB_ENDPOINT_DIRECTION_MASK = 0x80`** Mask to determine endpoint direction (IN/OUT). - **`internal enum PolicyType`** Defines WinUSB pipe policies: `ShortPacketTerminate`, `AutoClearStall`, `PipeTransferTimeout`, etc. - **`internal enum USBDPipeTypes`** Pipe types: `UsbdPipeTypeControl`, `UsbdPipeTypeIsochronous`, `UsbdPipeTypeBulk`, `UsbdPipeTypeInterrupt`. - **`internal enum USBDeviceSpeeds`** Device speeds: `UsbLowSpeed`, `UsbFullSpeed`, `UsbHighSpeed`. - **`internal struct USBConfigurationDescriptor`** P/Invoke struct for USB configuration descriptor. - **`internal struct USBInterfaceDescriptor`** P/Invoke struct for USB interface descriptor. - **`internal struct WinUSBPipeInformation`** P/Invoke struct for pipe info: `PipeTypes`, `PipeId`, `MaximumPacketSize`, `Interval`. - **`internal struct WinUSBSetupPacket`** P/Invoke struct for control transfer setup packet. - **`internal static extern bool WinUsb_ControlTransfer(...)`** Sends control transfers. - **`internal static extern bool WinUsb_Initialize(...)`** Initializes WinUSB interface handle. - **`internal static extern bool WinUsb_Free(...)`** Frees WinUSB interface handle. - **`internal static extern bool WinUsb_QueryDeviceInformation(...)`** Retrieves device info (e.g., speed) using `DEVICE_SPEED`. - **`internal static extern bool WinUsb_QueryInterfaceSettings(...)`** Queries interface settings. - **`internal static extern bool WinUsb_QueryPipe(...)`** Queries pipe info. - **`internal static extern bool WinUsb_ReadPipe(...)`** Reads from a pipe. - **`internal static extern bool WinUsb_WritePipe(...)`** Writes to a pipe. - **`internal static extern bool WinUsb_SetPipePolicy(...)`** Sets pipe policy (byte value). **Alias**: `WinUsb_SetPipePolicy1` for `PIPE_TRANSFER_TIMEOUT` (uses `uint` value). ## 3. Invariants - **`Connected` state** - `CDCUSBConnection`: `_Connected` is `true` only when `_comPort.IsOpen == true`. - `WINUSBConnection`: `Connected` is `true` only after `_sliceDev.GetDeviceHandle(...)` and `_sliceDev.InitializeDevice()` both succeed. - **`ConnectString` usage** - `CDCUSBConnection`: Used to match registry keys for COM port lookup. - `WINUSBConnection`: Passed to `_sliceDev.GetDeviceHandle(...)` to locate device. - **Thread safety** - `WINUSBConnection` uses `_usbConnectionMutex` around `WinUsbDevice` disposal. - `CDCUSBConnection.RegKeys` uses `KEY_LOCK` for lazy initialization. - **Asynchronous pattern** - `Begin*` methods queue work to `ThreadPool` via `NetCallbackFix`, which invokes the callback. - `End*` methods perform actual I/O and signal `AsyncWaitHandle.Set()`. - **No soft disconnect** Both `CDCUSBConnection` and `WINUSBConnection` have no-op `SoftConnect`/`SoftDisconnect`. - **No socket operations** `Bind`, `Listen`, `BeginAccept`, `EndAccept` throw `NotSupportedException` in both classes. ## 4. Dependencies ### Imports / External Dependencies - **Windows API**: `winusb.dll` (for `WINUSBConnection` via P/Invoke in `WinUsbDevice`). - **.NET Framework**: - `System.IO.Ports.SerialPort` (for `CDCUSBConnection`). - `System.Threading`, `System.Threading.Tasks`, `System.Runtime.InteropServices`. - `Microsoft.Win32.Registry` (for registry enumeration). - **Internal DTS modules** (from namespace imports): - `DTS.Common.DASResource` (string resources, e.g., `DASResource.Strings.*`). - `DTS.Common.Interface.Connection` (`IConnection` interface). - `DTS.Common.Utilities.Logging` (`APILogger`). - `DTS.Common.USBFramework` (likely contains `DeviceManagement`). - `DTS.Common.Classes.Connection` (likely contains `NotConnectedException`). ### Dependencies on Other Modules - `WINUSBConnection` depends on `DeviceManagement` and `WinUsbDevice` (defined in same namespace). - `CDCUSBConnection` depends on `DASResource.Strings` for exception messages. ### Dependencies *by* This Module - `IConnection` interface (consumed by higher layers). - `DeviceManagement` (used by `WINUSBConnection` for device lifecycle management). ## 5. Gotchas - **`Create` recursion** Both `CDCUSBConnection.Create(string)` and `WINUSBConnection.Create(string)` contain commented-out recursive calls (`//Create(connectString); - this is recursive!`). This suggests a historical bug or incomplete refactoring. - **`BeginConnect` blocking in `WINUSBConnection`** `WINUSBConnection.BeginConnect` calls `rar.AsyncWaitHandle.WaitOne()` *before returning*, making it effectively synchronous despite being an "Async" pattern. This violates the expected non-blocking behavior of `Begin*` methods. - **`EndConnect` in `WINUSBConnection` throws if already connected** `EndConnect` checks `if (_sliceDev != null || Connected)` and throws `NotConnectedException`, but `BeginConnect` already sets `Connected = false` *before* the async work. This is inconsistent and may cause confusion. - **`EndReceive` busy-waits** `CDCUSBConnection.EndReceive` and `WINUSBConnection.EndReceive` both use tight loops with `Thread.Sleep(1)` when no data is available. This can cause high CPU usage. - **`WinUSB_SetPipePolicy` vs `WinUsb_SetPipePolicy1`** Two separate P/Invoke declarations exist for `WinUsb_SetPipePolicy`, with `WinUsb_SetPipePolicy1` used *only* for `PIPE_TRANSFER_TIMEOUT` (which requires a `uint` instead of `byte`). This is error-prone and not enforced by the API. - **`RegKeys` is static and lazily initialized** `CDCUSBConnection.RegKeys` is a static property. If the registry changes after first access, the list will be stale until app restart. - **No error propagation in `NetCallbackFix`** Exceptions in `NetCallbackFix` are caught and logged, but the callback is still invoked. This may leave callers expecting an exception to be thrown in `End*`. - **`IsSoftDisconnected` always false** Both classes report `IsSoftDisconnected = false`, but the interface contract may expect it to reflect a real state. This could mislead callers. - **`GetConnectionData()` returns `""`** Both classes return empty strings. This may indicate incomplete implementation. - **`Flags` property unused** `System.Net.Sockets.SocketFlags Flags { get; set; }` is exposed but never used in either class. - **`USB_ENDPOINT_DIRECTION_MASK` is internal** While defined, it is not used in the provided source. May be used elsewhere in the codebase.