Files
DP44/enriched-qwen3-coder-next/Common/DTS.Common.ICommunication.md

248 lines
13 KiB
Markdown
Raw Permalink Normal View History

2026-04-17 14:55:32 -04:00
---
source_files:
- Common/DTS.Common.ICommunication/IDASConnectedDevice.cs
- Common/DTS.Common.ICommunication/ICommunication.cs
- Common/DTS.Common.ICommunication/Communication.cs
generated_at: "2026-04-16T14:07:22.447976+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "b573bb7d2f5d27d0"
---
# Documentation: DTS.Common.ICommunication
## 1. Purpose
This module provides the core communication infrastructure for interacting with DAS (Data Acquisition System) hardware devices. It defines the contract for connected devices via `IDASConnectedDevice`, encapsulates device metadata through `Communication_DASInfo`, and implements an asynchronous, callback-driven communication layer via the abstract `Communication<T>` class. The module handles connection lifecycle management, command execution with timeout handling, cancellation support, and protocol version negotiation for hardware commands.
---
## 2. Public Interface
### IDASConnectedDevice (Interface)
**Namespace:** `DTS.DASLib.Communication`
Describes a device connected to a DAS (e.g., S6 connected to S6DB).
| Property | Type | Description |
|----------|------|-------------|
| `DeviceType` | `HardwareTypes` | The device type of the connected device |
| `Port` | `int` | The port on the DAS which the device is on (0-based) |
| `SpotOnPort` | `int` | The spot on the chain or port the device is on (0-based) |
| `PhysicalAddress` | `PhysicalAddress` | MAC Address or physical address |
| `IPAddress` | `string` | The IP address of the device |
| `SerialNumber` | `string` | The serial number of the device |
| `Location` | `string` | The location of the device |
| `Version` | `string` | The version of the device |
---
### CanceledException (Class)
**Namespace:** `DTS.Common.ICommunication`
A marker exception class extending `ApplicationException` to signal operation cancellation.
---
### Communication_DASInfo (Class)
**Namespace:** `DTS.Common.ICommunication`
**Implements:** `ICommunication_DASInfo`
Encapsulates metadata about a DAS device.
**Properties:**
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `FirstUseDate` | `DateTime?` | `null` | Date of first use; `null` indicates hardware not used since calibration. Only valid when `IsFirstUseDateSupported` is `true` |
| `IsFirstUseDateSupported` | `bool` | `false` | Indicates hardware supports first use dates |
| `IsStreamingSupported` | `bool` | `false` | Indicates whether streaming is supported |
| `ConnectedDevices` | `IDASConnectedDevice[]` | empty array | Devices connected to the DAS (currently only used by SLICE6DB) |
| `SerialNumbers` | `string[]` | - | Array of serial numbers |
| `FirmwareVersions` | `string[]` | - | Array of firmware versions |
**Methods:**
- `void SetConnectedDevices(IDASConnectedDevice[] devices)` — Sets the `ConnectedDevices` array
- `string StackSerialNumber(int devid)` — Returns a stacked serial number string. Returns "N/A" if `SerialNumbers` is null/empty; returns `SerialNumbers[0]::SerialNumbers[devid]` if `devid` is non-zero and valid; otherwise returns `SerialNumbers[0]`
**Constructors:**
- `Communication_DASInfo()` — Default constructor
- `Communication_DASInfo(string[] serials, string[] fwnums)` — Constructs with cloned copies of serial and firmware arrays
---
### Communication\<T\> (Abstract Class)
**Namespace:** `DTS.Common.ICommunication`
**Implements:** `Interface.DASFactory.ICommunication`, `IDisposable`
**Constraint:** `where T : IConnection, new()`
Abstract base class for hardware communication, providing connection management, command execution, and cancellation support.
**Properties:**
| Property | Type | Description |
|----------|------|-------------|
| `ErrorInSetup` | `bool` | Indicates an error occurred during setup |
| `ConnectString` | `string` | Connection string from underlying socket |
| `Connected` | `bool` | Whether the socket is connected |
| `DASInfo` | `ICommunication_DASInfo` | DAS device information |
| `Transport` | `IConnection` | Underlying connection transport (setter throws `NotSupportedException`) |
| `ReceiveBufferSize` | `int` | Receive buffer size; default is 65536 (2^16) |
| `SerialNumber` | `string` | Device serial number |
| `FirmwareVersion` | `string` | Device firmware version; setter triggers `FirmwareVersionUpdated()` |
| `ProtocolVersion` | `byte` | Protocol version for command support checks |
| `MinimumProtocols` | `Dictionary<DFConstantsAndEnums.ProtocolLimitedCommands, byte>` | Maps commands to minimum required protocol versions |
| `FlushTimeoutMilliSec` | `int` | Timeout for flush operations; default is 5ms |
| `ExecuteIsBusy` | `bool` | Thread-safe flag indicating execution lock state |
| `CancelEvent` | `ManualResetEvent` | Event signaling cancellation has occurred |
**Events:**
- `EventHandler OnDisconnected` — Raised when the underlying socket disconnects
**Public Methods:**
- `int CompareTo(Interface.DASFactory.ICommunication dev)` — Compares connection strings (case-insensitive, ordinal)
- `int CompareTo(string conStr)` — Compares connection string to provided string
- `abstract void InitMinProto()` — Must be implemented to populate `MinimumProtocols`
- `bool IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands command)` — Returns `true` if `ProtocolVersion >= GetMinProto(command)`
- `byte GetMinProto(DFConstantsAndEnums.ProtocolLimitedCommands command)` — Returns minimum protocol version for command; returns `0xFF` if not found; throws `NotSupportedException` if `MinimumProtocols` is null
- `void Flush(int timeoutMs)` — Flushes the socket data buffer until empty or timeout
- `byte[] SyncExecute(byte[] byteData, int cbTimeout)`**Throws `NotSupportedException`** (not implemented)
- `void Connect(string connectString, CommunicationCallback callback, object callbackObject, int callbackTimeout, string hostIPAddress)` — Initiates asynchronous connection
- `void Disconnect(bool reuseSocket, CommunicationCallback callback, object callbackObject, int callbackTimeout)` — Initiates asynchronous disconnect
- `void Cancel()` — Sets cancel state with 500ms sleep delay on clear
- `void ForceCancel()` — Sets cancel state with 250ms sleep delay on clear
- `bool IsCanceled()` — Returns current cancel state
- `void ClearCancel()` — Clears cancel state after sleeping
- `void Execute(byte[] byteData, CommunicationCallback cb, object cbObject, int cbTimeout)` — Sends data and processes responses asynchronously
- `void PseudoExecute(byte[] byteData, CommunicationCallback cb, object cbObject, int cbTimeout)` — For commands that only receive data (no send); does not clear buffer
- `void SetupReader()` — Initializes the asynchronous receive loop
- `void Close(int timeout)` — Empty implementation (no-op)
- `void Dispose()` — Implements `IDisposable`
**Protected Methods:**
- `void Lock()` — Empty implementation
- `void Release()` — Empty implementation
- `virtual void FirmwareVersionUpdated()` — Called when `FirmwareVersion` is set
---
### CommunicationReport (Class)
**Namespace:** `DTS.Common.ICommunication`
**Implements:** `ICommunicationReport`
Carries the result of an asynchronous communication operation.
| Property | Type | Description |
|----------|------|-------------|
| `UserState` | `object` | User-provided state object |
| `Result` | `CommunicationResult` | Result enum value |
| `Data` | `byte[]` | Received data (for read operations) |
**Constructor:** `CommunicationReport(object state, CommunicationResult res)`
---
### Communication\<T\>.ActionData (Abstract Nested Class)
Base class for tracking asynchronous operations with timeout handling.
| Property | Description |
|----------|-------------|
| `UserCallback` | `CommunicationCallback` delegate |
| `UserCallbackObject` | User-provided state object |
| `UserTimeout` | Timeout in milliseconds |
| `TimerExpired` | Whether the timeout timer fired |
**Methods:**
- `void StartTimer()` — Starts the timeout timer
- `void KillTimer()` — Stops and disposes the timer
- `bool ReportCanceled()` — Invokes callback with `CommunicationResult.Canceled`
- `abstract bool ReportFailure()` — Must implement failure reporting
- `abstract bool ReportSuccess()` — Must implement success reporting
- `abstract CommunicationResult GetTimeoutResult()` — Must return the timeout-specific result
---
### Communication\<T\>.ExecuteActionData (Nested Class)
Extends `ActionData` for execute operations.
**Additional Methods:**
- `bool ReportReadSuccess(byte[] data)` — Reports successful read with data
- `bool ReportReadTimeout()` — Reports read timeout
- `bool ReportReadDisconnected()` — Reports disconnection during read
---
### Communication\<T\>.PseudoAsyncResult (Nested Class)
Implements `IAsyncResult` for `PseudoExecute` operations.
| Property | Value |
|----------|-------|
| `IsCompleted` | Always `true` |
| `AsyncState` | The `ExecuteActionData` instance |
| `CompletedSynchronously` | Always `true` |
| `AsyncWaitHandle` | Throws `NotImplementedException` |
---
## 3. Invariants
1. **Connection State Consistency**: `sock` is instantiated in the constructor and cannot be replaced via `Transport` setter (throws `NotSupportedException`).
2. **Execute Locking**: `ExecuteIsBusy` must be `false` before setting to `true`, and `true` before setting to `false`. Debug assertions enforce this—violations indicate re-entry or extra unlock bugs.
3. **Port/Spot Indexing**: `Port` and `SpotOnPort` on `IDASConnectedDevice` are 0-based indices.
4. **FirstUseDate Validity**: `FirstUseDate` is only meaningful when `IsFirstUseDateSupported` is `true`.
5. **MinimumProtocols Initialization**: `MinimumProtocols` must be populated by `InitMinProto()` before calling `GetMinProto()` or `IsCommandSupported()`, otherwise `NotSupportedException` is thrown.
6. **Callback Non-Null Assertion**: `ActionData` constructor asserts that the callback parameter is non-null.
7. **Thread ID Consistency**: In `ProcessReceivedData` and `SRRecvCallback`, if the thread ID changes during `WaitWithCondition.Wait`, the method exits early without processing.
---
## 4. Dependencies
### This module depends on:
- `DTS.Common.Enums.Hardware``HardwareTypes` enum
- `DTS.Common.Enums.Communication``CommunicationResult`, `CommunicationConstantsAndEnums`
- `DTS.Common.Enums.DASFactory``DFConstantsAndEnums`
- `DTS.Common.Interface.Communication``ICommunication_DASInfo`, `CommunicationCallback` delegate
- `DTS.Common.Interface.Connection``IConnection`
- `DTS.Common.Classes.Connection` — (referenced but contents not in source)
- `DTS.Common.Utilities.Logging``APILogger`
- `DTS.Common.Utilities``SecureQueue<T>`
- `DTS.Common.Utils``WaitWithCondition`
- `System.Net.NetworkInformation``PhysicalAddress`
- `System.Net.Sockets``SocketException`
- `System.Threading``ManualResetEvent`, `Timer`, `Timeout`
- `System.Threading.Tasks``Task`
### What depends on this module:
- Implementations of `IConnection` (generic constraint `T`)
- Concrete DAS communication implementations that extend `Communication<T>`
- Consumers of `IDASConnectedDevice` for device enumeration
- Consumers of `ICommunication_DASInfo` for device metadata
---
## 5. Gotchas
1. **SyncExecute Not Implemented**: Calling `SyncExecute()` throws `NotSupportedException`. Use `Execute()` with callbacks instead.
2. **Lock/Release Are No-ops**: `Lock()` and `Release()` methods have empty implementations. Any synchronization relying on these is not actually protected.
3. **Close() Does Nothing**: `Close(int timeout)` has an empty body and performs no cleanup.
4. **Cancel Sleep Delays**: `ClearCancel()` sleeps for either 500ms (after `Cancel()`) or 250ms (after `ForceCancel()`) before clearing the cancel state. This can introduce unexpected latency.
5. **Transport Setter Always Throws**: Setting `Transport` throws `NotSupportedException`—the socket cannot be replaced after construction.
6. **PseudoExecute Buffer Behavior**: Unlike `Execute()`, `PseudoExecute()` does not flush the buffer before operation and picks up from wherever the previous `PseudoExecute` left off.
7. **StackSerialNumber Edge Cases**: Returns "N/A" for empty/null `SerialNumbers`, but returns `SerialNumbers[0]` for `devid` values outside valid range (except 0). This may mask indexing errors.
8. **ActionData Timer Race**: The timer callback and `KillTimer()` both check `_timerFired` under a lock, but if the timer fires just before disposal, the callback will still execute.
9. **ReceiveCallback Disconnection Handling**: When `sock.EndReceive` returns 0 bytes, `_receiveCallbackRunning` is set to `false` and `OnDisconnected` is invoked, but the socket state is not explicitly cleaned up.
10. **Extra Communication Logging**: Conditional logging via `DFConstantsAndEnums.ExtraCommunicationLogging` may impact performance if enabled in production.