Files
DP44/enriched-qwen3-coder-next/DataPRO/Modules/Hardware/HardwareList/Model.md

270 lines
14 KiB
Markdown
Raw Normal View History

2026-04-17 14:55:32 -04:00
---
source_files:
- DataPRO/Modules/Hardware/HardwareList/Model/HardwareChannelAssignment.cs
- DataPRO/Modules/Hardware/HardwareList/Model/SLICE6TreeNode.cs
- DataPRO/Modules/Hardware/HardwareList/Model/Hardware.cs
generated_at: "2026-04-16T04:38:28.250792+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "e010e06b613fee2c"
---
# HardwareList.Model Module Documentation
## 1. Purpose
This module provides data models and persistence logic for representing and managing hardware devices (DAS units) in the DataPRO diagnostics system. It defines core entities (`HardwareChannelAssignment`, `SLICE6TreeNode`, `HardwareModel`) that model hardware topology, channel assignments, and device metadata. The module enables querying device hierarchies (e.g., SLICE6DB parent-child relationships), persisting association changes to the database, and exposing hardware properties for UI binding (via `INotifyPropertyChanged`). It serves as the data layer for the Hardware List view, supporting configuration, sorting, filtering, and calibration tracking.
## 2. Public Interface
### `HardwareChannelAssignment`
- **`HardwareChannelAssignment(string channelNumber, string sensor, string name)`**
Constructor. Initializes immutable properties with provided values. Represents a mapping between a hardware channel, its connected sensor type, and a user-defined name.
- **`string ChannelNumber { get; }`**
Channel identifier (e.g., "CH1", "A0").
- **`string Sensor { get; }`**
Type of sensor connected to the channel.
- **`string Name { get; }`**
User-assigned name for the channel.
---
### `SLICE6TreeNode`
- **`SLICE6TreeNode(int dasId, string serialNumber, int port, int number, int positionOnChain)`**
Constructor. Initializes properties for a SLICE6 device node in a tree structure.
- **`int DASId { get; set; }`**
Primary key ID from the DAS database table.
- **`string SerialNumber { get; set; }`**
Device serial number.
- **`int Port { get; set; }`**
Physical port number on the S6DB (distributor) to which the device is connected.
- **`string PortString { get; }`**
Readable string representation of `Port`; returns `"---"` if `Port < 0`.
- **`int Number { get; set; }`**
Order of the device on the S6DB (i.e., its position index among siblings).
- **`int PositionOnChain { get; set; }`**
Position of the device within its daisy-chain on a given port.
- **`string PositionOnChainString { get; }`**
Readable string representation of `PositionOnChain`; returns `"---"` if `PositionOnChain < 0`.
- **`static ISLICE6TreeNode[] GetAvailableTreeNodes(string serialNumberParent)`**
Queries the database for all SLICE6 devices *not* associated with `serialNumberParent`. Returns an array of `ISLICE6TreeNode` instances sorted by `SerialNumber`. Returns empty array if `serialNumberParent` is null/empty.
- **`static ISLICE6TreeNode[] GetTreeNodes(string serialNumberParent)`**
Queries the database for all SLICE6 devices *associated* with `serialNumberParent`. Returns an array of `ISLICE6TreeNode` instances sorted by `Number` (i.e., `PositionOnDistributor`). Returns empty array if `serialNumberParent` is null/empty.
- **`static void SwapNodes(string serialNumberA, string serialNumberB)`**
Swaps all child devices between two SLICE6DB units (`serialNumberA` and `serialNumberB`) in the database. *Note: There is a bug in the implementation—both `listA` and `listB` are associated to `serialNumberB` in the second `Associate` call, not `serialNumberA` and `serialNumberB` respectively.*
- **`static void SaveAssociations(string serialNumber, ISLICE6TreeNode[] attachedSLICE6)`**
Commits the current association state of SLICE6 devices to a parent SLICE6DB (`serialNumber`). First clears all existing associations for `serialNumber`, then updates each device in `attachedSLICE6` with its new `ParentDAS`, `PositionOnDistributor`, `PositionOnChain`, and `Port`.
---
### `HardwareModel`
- **`HardwareModel(IISOHardware d, ...)`**
Constructor. Populates properties from an `IISOHardware` instance and calculates derived values (e.g., `CalDueDate`, `ChannelCount`). Requires calibration period parameters per hardware type.
- **`int DASId { get; set; }`**
Database ID of the device.
- **`bool Disabled { get; set; }`**
Whether the device is disabled.
- **`string SerialNumber { get; set; }`**
Device serial number.
- **`string HardwareType { get; set; }`**
Localized string description of the hardware type (e.g., `"SLICE6_BASE"`).
- **`string ChannelCount { get; set; }`**
Human-readable string listing channel types and counts (e.g., `"8 Analog, 2 Digital In"`).
- **`bool HasIncludedChildren { get; set; }`**
Indicates if this device has child devices marked as `Included`.
- **`string Firmware { get; set; }`**
Firmware version string.
- **`double? MaxSampleRate { get; set; }`**
Maximum supported sample rate (Hz); `null` if unknown or not applicable.
- **`double TestSampleRate { get; set; }`**
Current test/sample rate selected for the device.
- **`double TestAAFilterRateHz { get; set; }`**
Anti-aliasing filter rate (Hz) corresponding to `TestSampleRate`.
- **`DateTime? CalDate { get; set; }`**
Last calibration date.
- **`DateTime? CalDueDate { get; set; }`**
Calculated calibration due date based on `CalDate` and hardware-specific period.
- **`string[] AvailableSampleRates { get; set; }`**
Array of available sample rate strings (e.g., `["1000", "2000"]`).
- **`string SelectedSampleRateItem { get; set; }`**
Currently selected sample rate string.
- **`int SelectedSampleRateIndex { get; set; }`**
Index of the current sample rate in `_availableSampleRates`. Setter updates `TestSampleRate` and `TestAAFilterRateHz`.
- **`object Hardware { get; set; }`**
Backing `IISOHardware` instance.
- **`int AnalogChannels { get; set; }`**
Number of analog input channels.
- **`int SquibChannels { get; set; }`**
Number of squib (explosive device) channels.
- **`int DigitalInChannels { get; set; }`**, **`int DigitalOutChannels { get; set; }`**, **`int UartChannels { get; set; }`**, **`int StreamOutChannels { get; set; }`**, **`int StreamInChannels { get; set; }`**, **`int CanChannels { get; set; }`**
Channel counts for respective interface types.
- **`string IPAddress { get; set; }`**
IP address or `"USB"` if connected via USB.
- **`bool Included { get; set; }`**
Whether the device is included in the current configuration.
- **`double DSPStreamingFilter { get; set; }`**
DSP streaming filter value.
- **`DTS.Common.ClockSyncProfile MasterProfile { get; set; }`**, **`DTS.Common.ClockSyncProfile SlaveProfile { get; set; }`**
Clock synchronization profiles (master/slave).
- **`bool IsClockMaster { get; set; }`**
Whether the device is configured as a clock master. Only valid if `IsClockedDAS` is true.
- **`bool IsClockedDAS { get; }`**
Returns `true` if the device type supports clocking (e.g., SLICE6, S6A_EthernetRecorder, TSR_AIR).
- **`byte PTPDomainID { get; set; }`**
PTP domain ID for precision time protocol.
- **`bool IsPTPSync { get; }`**
Returns `true` if PTP synchronization is active (E2E profile in use).
- **`bool MixedRates { get; set; }`**
Whether the device is part of a mixed-sample-rate configuration.
- **`bool IsDistributor { get; }`**
Returns `true` if the device is a distributor (e.g., SLICE6DB, SLICE_Distributor).
- **`bool IsBattery { get; }`**
Returns `true` if the device is a PowerPro.
- **`bool IsTSRAIR { get; }`**
Returns `true` if the device is a TSR_AIR or embedded sensor type.
- **`bool IncludedAndNotMixedRatesAndCompactOrNotDistributor { get; }`**, **`bool IncludedAndMixedRatesAndCompact { get; }`**
Derived UI flags for conditional rendering.
- **`string ParentDAS { get; set; }`**
Serial number of the parent device (distributor).
- **`int PositionOnChain { get; set; }`**, **`int PositionOnDistributor { get; set; }`**, **`int Port { get; set; }`**
Position metadata for hierarchical placement.
- **`bool HasTreeView { get; set; }`**
Indicates if a tree view should be shown for this device (e.g., for SLICE6DB).
- **`string SerialNumberDisplay { get; }`**
Display name: `SerialNumber` unless `StandIn` is true, in which case it returns the hardware type description.
- **`static IHardware[] GetAvailableSLICE6DB(string serialNumber)`**
Returns all SLICE6DB devices (including `SLICE6DB_InDummy`) not currently assigned to any parent, excluding `serialNumber`.
- **`void DetermineChannelCount(bool showCompact, IHardware[] allHardware)`**
Updates `ChannelCount` and `MaxSampleRate` based on device type and child devices. For distributors, calculates min sample rate among children if `showCompact` is true.
- **`void SetIncluded(bool bIncluded)`**, **`void SetMixedRates(bool mixedRates)`**
Updates state and fires property change notifications.
- **`bool Filter(string term)`**
Returns `true` if `SerialNumber`, `Firmware`, or `HardwareType` contains `term` (case-insensitive).
- **`class HardwareComparer : IComparer<IHardware>`**
Implements sorting for `IHardware` objects. Supports sorting by `HardwareListTags` (e.g., `SerialNumber`, `CalDate`, `FirstUseDate`). Handles nulls and `double?/DateTime?` comparisons. `FirstUseDate` sorts nulls last when valid.
---
## 3. Invariants
- **`SLICE6TreeNode`**
- `Port`, `Number`, and `PositionOnChain` must be non-negative integers for valid hardware placements. Negative values are represented as `"---"` in UI via `PortString`/`PositionOnChainString`.
- `GetAvailableTreeNodes` and `GetTreeNodes` only query devices with `Type = SLICE6_Base` and `Position ≠ 'Prototype'` (for `GetAvailableTreeNodes`).
- `SwapNodes` assumes all child devices of both parents are retrieved in one query and re-associated. *Bug: Both lists are associated to `serialNumberB`.*
- **`HardwareModel`**
- `CalDueDate` is derived from `CalDate` (or `FirstUseDate` if `IsFirstUseValid`) plus a hardware-specific calibration period.
- `MaxSampleRate` is `null` if `d.MaxSampleRate` is `<= 0` or `uint.MaxValue`.
- `IsClockedDAS` is determined by a fixed set of `HardwareTypes`.
- `Included` and `MixedRates` flags affect derived properties (`IncludedAndNotMixedRatesAndCompactOrNotDistributor`, `IncludedAndMixedRatesAndCompact`).
- `ChannelCount` for distributors is `"N/A"` if `showCompact` is false or no children exist.
- **General**
- All database operations use `DTS.Common.Storage.DbOperations.GetSQLCommand()` and explicitly dispose connections in `finally` blocks.
- `HardwareModel` instances are constructed with a non-null `HardwareListViewModel` (`_vm`) reference for event callbacks.
## 4. Dependencies
### Dependencies *of* this module:
- **`DTS.Common.*`**
- `DTS.Common.Base.BasePropertyChanged` (base class for `SLICE6TreeNode`)
- `DTS.Common.Storage.DbOperations` (database access)
- `DTS.Common.Enums.Hardware.HardwareTypes` (device type enumeration)
- `DTS.Common.Interface.DASFactory.Diagnostics.IISOHardware`, `IHardware` (hardware abstraction interfaces)
- `DTS.Common.Converters.EnumDescriptionTypeConverter` (localized enum descriptions)
- `DTS.Common.ClockSyncProfile` (clock sync profiles)
- **`HardwareList.Resources.StringResources`**
- Used for localized strings (e.g., `"Analog"`, `"USB"`, `"N/A"`).
### Dependencies *on* this module:
- **`HardwareList.HardwareListViewModel`**
- Passed into `HardwareModel` constructor; used for event callbacks (`FireSampleRate`, `FireClockMaster`, etc.).
- **UI Layer**
- `HardwareModel` properties (e.g., `Included`, `CalDueDate`, `ChannelCount`) are bound to views.
- `SLICE6TreeNode` is used to populate tree views for SLICE6DB hierarchies.
- **HardwareList Module**
- `HardwareList.Model` is the core data model for the `HardwareList` module.
## 5. Gotchas
- **`SLICE6TreeNode.SwapNodes` Bug**:
The `Associate` method is called twice—once for `listA` with `serialNumberB`, and again for `listB` *also* with `serialNumberB`. This means devices originally under `serialNumberB` are incorrectly moved to `serialNumberB` (no-op), and devices under `serialNumberA` are moved to `serialNumberB`, but the reverse move does not occur. The intended behavior is likely `Associate(serialNumberB, listA)` and `Associate(serialNumberA, listB)`.
- **`HardwareModel.CalDueDate` Calculation**:
Uses `FirstUseDate` only if `IsFirstUseValid` is true. If `FirstUseDate` is `null` and `IsFirstUseValid` is true, it defaults to `DateTime.Today`. This may cause unexpected recalculations if `FirstUseDate` is set later.
- **`HardwareModel.TestSampleRate` Setter Side Effect**:
Setting `TestSampleRate` triggers `OnPropertyChanged("SelectedSampleRateIndex")`, but the getter for `SelectedSampleRateIndex` re-computes `SelectedSampleRateItem` and calls `_vm.FireSampleRate`. This could cause redundant UI updates if `TestSampleRate` is set multiple times.
- **`HardwareModel.DetermineChannelCount` for Distributors**:
`MaxSampleRate` is recalculated as the *minimum* sample rate of child devices. If children have no sample rate (`null`), `ChannelCount` becomes `"N/A"` and `MaxSampleRate` is set to `null`. This may mask missing configuration.
- **`HardwareModel.Filter` Case Sensitivity**:
Filtering is case-insensitive (`term.ToLower()`), but `SerialNumberDisplay` uses `isoHW.StandIn` logic, which may cause display mismatches if `StandIn` is toggled dynamically.
- **`HardwareModel.Hardware` is `object`**:
The `Hardware` property is typed as `object`, requiring casting to `IISOHardware` for type-specific checks (e.g., `IsClockedDAS`, `IsDistributor`). This risks runtime errors if the underlying type is not `IISOHardware`.
- **`SLICE6TreeNode` SQL Injection Risk**:
`GetAvailableTreeNodes` uses string interpolation for `HardwareTypes.SLICE6_Base` in the `WHERE` clause (`[(int)HardwareTypes.SLICE6_Base]`). While the enum value is fixed, this pattern is fragile and error-prone.
- **`HardwareModel` Constructor Side Effects**:
The constructor calls `d.GetChannelsString(...)` and computes `CalDueDate` based on `d.DASTypeEnum`. If `Hardware` is `null` or `DASTypeEnum` is invalid, it throws `ArgumentOutOfRangeException`.
- **`HardwareComparer.NumericCompare` Logic**:
For `double`/`DateTime`, `a > b` returns `-1` (descending order), but the method returns `1` for all other cases. This may cause inconsistent sorting if types are mixed (e.g., `double` vs `DateTime`).