Files
DP44/enriched-qwen3-coder-next/DataPRO/DASFactory.md

190 lines
12 KiB
Markdown
Raw Normal View History

2026-04-17 14:55:32 -04:00
---
source_files:
- DataPRO/DASFactory/DASFactory.AutoDiscovery.cs
- DataPRO/DASFactory/DASFactory.WinUSB.cs
- DataPRO/DASFactory/DASFactory.CDCUSB.cs
- DataPRO/DASFactory/DASFactory.Ribeye.cs
- DataPRO/DASFactory/DASFactory.WindowsNotification.cs
- DataPRO/DASFactory/DistributorSocket.cs
- DataPRO/DASFactory/DASFactory.HID.cs
generated_at: "2026-04-16T03:50:36.719547+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "440f548bb3fa7458"
---
# DASFactory
**Documentation Page: DASFactory Device Discovery and Handling Module**
---
### 1. Purpose
This module implements device discovery and lifecycle management for multiple hardware interface types (UDP multicast, HID, WinUSB, CDCUSB, and Ethernet-based Ribeye) within the DAS (Data Acquisition System) factory framework. It enables background scanning for UDP-based devices via multicast, real-time detection of USB/HID device insertion/removal via Windows notifications, and structured connection/disconnection workflows for each device type. The module serves as the core infrastructure for dynamically managing connected DAS devices in the system, ensuring devices are correctly identified, validated, and integrated into the broader DAS ecosystem.
---
### 2. Public Interface
The module contains **no public classes**—all classes (`AutoDiscovery`, `WinUSBHandling`, `CDCUSBHandling`, `RibeyeHandling`, `HIDHandling`, `WindowsNotification`, `DistributorSocket`) are declared `internal`. Therefore, there is **no public surface area** exposed by this module.
However, the following **internal classes and methods** constitute the functional interface used by other internal modules (e.g., `DASFactory`):
#### `AutoDiscovery`
- `void StartMulticastAutoDiscovery()`
Starts a background task that periodically polls for UDP devices via `_dasFactory.AutoDiscoverMulticast(...)`. Uses a `CancellationToken` for cancellation. Ensures only one scan task runs at a time via `_multicastLock`.
- `void StopMulticastAutoDiscovery()`
Cancels the active scan task and waits for it to complete. Disposes and recreates the `CancellationTokenSource` if previously cancelled.
- `IDiscoveredDevice[] GetDiscoveredDevices()`
Returns a snapshot (copy) of all discovered devices since the last `StartMulticastAutoDiscovery()` call. Thread-safe via `_multicastLock`.
#### `WinUSBHandling`
- Inherits from `WindowsNotification`.
- Overrides `NotificationDeviceArrived`, `NotificationDeviceRemoved`.
- `public override void UpdateConnectedDevices()`
Enumerates connected WinUSB devices, checks for duplicates, and connects new ones.
- `public override void UpdateDisconnectedDevices()`
Detects and disconnects devices that are no longer present.
- `public override void UpdateDeviceSetups()`
Sets `this` as the handler for the associated `IDeviceSetup`.
#### `CDCUSBHandling`
- Inherits from `WindowsNotification`.
- Overrides `NotificationDeviceArrived`, `NotificationDeviceRemoved`.
- `public override void UpdateConnectedDevices()`
Enumerates CDCUSB devices (filtered by registry keys in `GetListOfConnectedDevices()`), checks for duplicates, and connects new ones.
- `public override void UpdateDisconnectedDevices()`
Detects and disconnects removed CDCUSB devices.
- `public override void UpdateDeviceSetups()`
Sets `this` as the handler for the associated `IDeviceSetup`.
#### `RibeyeHandling`
- Implements `IDeviceSetup`.
- `bool QueryInformation(ConnectedDevice dev)`
Queries device metadata (serial number, LED count, firmware, supported modes/rates) via protocol commands (`QueryArmAndTriggerStatus`, `QuerySerialNumber`, `QueryNumberOfLEDs`). On failure, sets `dev.InUpdateMode = true`.
- `ICommunication GetICommunication()` / `GetICommunication(ConnectedDevice dev)`
Returns `EthernetRibeye` instances.
- `IConnectedDevice GetIConnectedDevice(ICommunication comm)`
Wraps `EthernetRibeye` in `ConnectedEthernetRibeye`.
- `bool IsCorrectType(ConnectedDevice dev)`
Returns `true` if `dev.Dev is ConnectedEthernetRibeye`.
- `DASType GetDASType()``ETHERNET_RIBEYE`
- `Guid GetGuid()``Guid.Empty`
- `int GetProductId()` / `string GetProductIdString()``0` / `string.Empty`
- `void SetHandler(DeviceHandling handler)` → no-op.
#### `WindowsNotification`
- Abstract base class for device notification handlers.
- Constructor registers for Windows device notifications via `DeviceManagement.RegisterForDeviceNotifications(...)`.
- `protected abstract void NotificationDeviceArrived(ref Message m)`
Called on device arrival (via `NotificationWndProc`).
- `protected abstract void NotificationDeviceRemoved(ref Message m)`
Called on device removal.
- `protected virtual void NotificationWndProc(ref Message m)`
Filters `WM_DEVICECHANGE` messages for `DBT_DEVICEARRIVAL` / `DBT_DEVICEREMOVECOMPLETE`, dispatching to abstract handlers.
#### `DistributorSocket`
- `public bool IsConnected()`
Returns `true` if `_sock` is non-null and connected.
- `public void Disconnect()`
Shuts down and closes the socket, disposes resources.
- `public bool ReadLine(ref string target, ref bool stopFlag)`
Reads a line from `_reader` with retry logic (up to `MAX_CONSECUTIVE_READ_ERRORS = 2`). Logs each message.
- `public void SendAck()` / `SendNak()`
Sends `"ACK"` or `"NAK"` over `_writer`, with logging and error handling.
- `public bool KeepAliveEnabled()`
Sends a keep-alive configuration string (`<...>`) to the remote endpoint and waits for a response. Sets `_keepAliveEnabled = true` on success.
- `public void Dispose()`
Closes and disposes the socket.
---
### 3. Invariants
- **`AutoDiscovery`**
- `_scanTask` is `null` or completed only when no scan is running.
- `_scanTask` is never started if already running (`lock` + null/completed check).
- `_discoveredDevices` list is **append-only**: existing entries are never updated or removed during discovery; only new devices (by unique `Serial`) are added.
- `ClearDiscoveredDevices()` is called at the start of each `DiscoveryWork` iteration.
- Cancellation token is **not reusable**; once cancelled, a new `CancellationTokenSource` is created.
- **`WinUSBHandling`, `CDCUSBHandling`, `HIDHandling`**
- Device path lists are deduplicated (case-insensitive) before use.
- `CheckForConnectedWinUSBDups()` / `CheckForConnectedCDCUSBDups()` throw if duplicate device paths are detected.
- `GetListOfConnectedDevices()` returns a list of device paths; for CDCUSB, paths must contain at least one registry key from `CDCUSBConnection.RegKeys` (case-insensitive substring match).
- `ConnectWinUSBTimeout` / `ConnectCDCUSBTimeout` / `ConnectHIDTimeout` are set to `60000`, `60000`, and `1000` ms respectively.
- **`RibeyeHandling`**
- `Samplerate2AAFilterDict` is immutable and pre-populated with 9 sample rates (500100000 Hz), each mapped to `sampleRate / 5.0F`.
- `QueryInformation` may silently retry `QueryArmAndTriggerStatus` on first boot (CRC initialization issue).
- Module serial numbers are derived as `<DAS serial>-<Index>`; firmware versions default to `"0000"`.
- **`WindowsNotification`**
- A hidden `NotificationForm` is created and shown (then hidden) to receive Windows messages.
- Device notification registration is mandatory; failure throws an exception.
- `RecipientHandle` and `DeviceNotifyHandle` are initialized in the constructor.
- **`DistributorSocket`**
- TCP keep-alive is enabled and configured via `IOControlCode.KeepAliveValues`.
- Connection retry loop respects `slicedbCanConnect`, `whKillMe`, and `_bShutDownByNow` flags.
- `ReadLine` fails if `stopFlag` is true or `MAX_CONSECUTIVE_READ_ERRORS` is exceeded.
---
### 4. Dependencies
#### Internal Dependencies (from source):
- **`DTS.Common.*` namespaces**:
- `DTS.Common.Enums.DASFactory` (`DFConstantsAndEnums`, `MultiCastDeviceClasses`)
- `DTS.Common.Interface.DASFactory` (`IDASFactory`, `IDiscoveredDevice`, `IDeviceSetup`)
- `DTS.Common.DASResource`, `DTS.Common.DAS.Concepts`, `DTS.Common.ICommunication`, `DTS.Common.Utilities.Logging`, `DTS.Common.WINUSBConnection`, `DTS.Common.USBFramework`
- **`DTS.DASLib.*` namespaces**:
- `DTS.DASLib.Command.*` (e.g., `Ribeye` commands: `QueryArmAndTriggerStatus`, `QuerySerialNumber`, `QueryNumberOfLEDs`)
- `DTS.DASLib.Connection.*`, `DTS.DASLib.Communication`, `DTS.DASLib.Service`
- **System namespaces**:
- `System.Collections.Concurrent`, `System.Threading`, `System.Windows.Forms`, `System.Net.Sockets`, `System.Runtime.InteropServices`
#### External Dependencies:
- Windows API (via `DeviceManagement`, `FileIODeclarations`, `HIDeclarations`) for device enumeration and HID access.
- `MyDeviceManagement.FindDeviceFromGuid(...)` (from `DTS.Common.USBFramework`) for device path enumeration.
- `CDCUSBConnection.RegKeys` (from `DTS.Common.WINUSBConnection`) for CDCUSB path filtering.
#### Inferred Usage:
- `AutoDiscovery` is used by `DASFactory` (via `_dasFactory` field) to enable multicast discovery.
- `WinUSBHandling`, `CDCUSBHandling`, `HIDHandling`, `RibeyeHandling` are instantiated and wired into `DASFactory` for their respective device types.
- `DistributorSocket` is used for remote communication (e.g., with a "slice db" server), likely in distributed acquisition scenarios.
---
### 5. Gotchas
- **`AutoDiscovery`**
- Cancellation is **not idempotent**: once `tokenSource.Cancel()` is called, `tokenSource` is disposed and a new one is created. Reusing the same instance after cancellation is impossible.
- `DiscoveryWork` always clears `_discoveredDevices` at the start of each loop iteration, meaning only devices discovered in the *current* scan cycle are retained (unless `StartMulticastAutoDiscovery` is called again).
- `GetDiscoveredDevices()` returns a copy (`ToArray()`), but the internal list is not versioned—concurrent `UpdateDevices` calls may overwrite each others additions if not for the lock.
- **`WinUSBHandling`, `CDCUSBHandling`, `HIDHandling`**
- Device path deduplication uses `string.IsNullOrEmpty(t)` and case-insensitive `Equals`, but `GetAllHIDDevices()` and `GetListOfConnectedDevices()` may return `null` on failure (not an empty list), which downstream code must handle.
- `HIDHandling.ReadRegKeys()` silently clears `RegKeys` on exception; if registry access fails, no devices will match in `NotificationDeviceArrived`.
- In `HIDHandling.NotificationDeviceArrived`, if `RegKeys` is empty (e.g., due to registry error), the device is ignored—even if its valid—until `ReadRegKeys()` is called again (e.g., on next arrival).
- `WinUSBHandling` and `CDCUSBHandling` both call `CheckForConnected...Dups()` and throw if duplicates are found—this is a **hard failure**, not a warning.
- **`RibeyeHandling`**
- `QueryInformation` may fail silently on first boot (CRC issue), but only retries once. If the second attempt fails, `QueryInformation` returns `false` and sets `dev.InUpdateMode = true`.
- `Samplerate2AAFilterDict` is shared across all instances (static), but only 9 sample rates are supported. Using unsupported rates will cause a `KeyNotFoundException` if accessed.
- `GetGuid()` returns `Guid.Empty`, implying this device type may not use GUID-based enumeration (unlike WinUSB/CDCUSB/HID).
- **`WindowsNotification`**
- `NotificationForm` is created on the main thread; accessing it from other threads (e.g., in `Dispose`) is unsafe and commented-out code warns about cross-thread violations.
- Device notification registration failure throws immediately in the constructor—no fallback.
- **`DistributorSocket`**
- `KeepAliveEnabled()` sends a configuration string but does **not** verify the remote response beyond reading a non-empty line. It does not parse `<ACK>` (commented out).
- `ReadLine` may return an empty string if `stopFlag` is set or errors exceed threshold—callers must check the return value.
- `SLICE_DB_PORT = 8200` is hardcoded; no configuration support.
- **General**
- All timeout values (`ConnectWinUSBTimeout`, etc.) are hardcoded in constructors and not configurable at runtime.
- Logging uses `APILogger.LogString(...)` and `APILogger.Log(...)`, but no structured error codes—debugging relies on log parsing.
- No unit tests or validation for `IDeviceSetup` implementations beyond type checks (`IsCorrectType`).