--- source_files: - Common/DTS.Common/Classes/ClockSync/IClockSyncProfile.cs - Common/DTS.Common/Classes/ClockSync/ClockSyncProfile.cs - Common/DTS.Common/Classes/ClockSync/ClockSyncProfileConverter.cs - Common/DTS.Common/Classes/ClockSync/ClockSyncProfileCollection.cs generated_at: "2026-04-16T03:15:09.204079+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "e412b56844d5af45" --- # ClockSync ## Documentation: Clock Sync Profile Module ### 1. Purpose This module defines and manages clock synchronization profiles for the DTS system, enabling configuration of different master clock input sources (e.g., PTP IEEE 1588, IRIG-B, GPS, 1PPS). It provides a singleton collection (`ClockSyncProfileCollection`) that loads profile definitions from an XML file (`ClockSyncProfiles.xml`), falling back to a default set if the file is missing. Profiles are represented by the `ClockSyncProfile` class, which implements the `IClockSyncProfile` interface and supports metadata-driven initialization from an enum (`ClockSyncProfileDefaults`). The module also includes a type converter (`ClockSyncProfileConverter`) for UI integration (e.g., property grids), ensuring only visible profiles are exposed and sorted by display order. --- ### 2. Public Interface #### `IClockSyncProfile` (Interface) - **`int ProfileId { get; set; }`** Unique integer identifier for the profile. - **`string ProfileName { get; set; }`** Human-readable name of the profile (e.g., `"PTP IEEE 1588"`). - **`string ProfileDesc { get; set; }`** Description of the profile’s behavior or purpose. - **`int DisplayOrder { get; set; }`** Integer priority for ordering profiles in UI (lower values appear first). - **`bool Visible { get; set; }`** Flag indicating whether the profile should be shown in UI (e.g., property grids). - **`DASRestriction[] FilterRestrictions { get; set; }`** Array of restrictions (of type `DASRestriction`) applied to the profile; used to filter applicable DAS configurations. #### `ClockSyncProfile` (Concrete Implementation) - **`ClockSyncProfile()`** Parameterless constructor for deserialization. - **`ClockSyncProfile(int profileId, string profileName, string profileDesc, int displayOrder, bool visible, DASRestriction[] filterRestrictions)`** Initializes a profile with explicit values via `Initialize()`. - **`ClockSyncProfile(ClockSyncProfileCollection.ClockSyncProfileDefaults defaults, DASRestriction[] restrictions)`** Initializes a profile by extracting metadata (name, description, order, visibility) from the `ClockSyncProfileDefaults` enum using reflection on `[Display]` and `[Browsable]` attributes, then calls `Initialize()`. - **`override string ToString()`** Returns `ProfileName`. #### `ClockSyncProfileConverter` (Type Converter) - **`ClockSyncProfile[] Values { get; }`** Lazily-initialized array of *visible* profiles from the singleton collection, sorted by `DisplayOrder`. Thread-safe via `lock`. - **`override bool CanConvertFrom(...)`** Returns `true` if `sourceType == typeof(string)` (enables string-to-profile conversion by name). - **`override object ConvertFrom(...)`** Converts a string (profile name) to a `ClockSyncProfile` instance by matching `ProfileName` in `Values`. Returns `null` if no match. - **`override bool GetStandardValuesSupported(...)`** Returns `true` (indicates standard values are available). - **`override bool GetStandardValuesExclusive(...)`** Returns `true` (indicates only standard values are valid; no free-text input). - **`override StandardValuesCollection GetStandardValues(...)`** Returns a `StandardValuesCollection` containing *all* profiles from the singleton collection (including non-visible ones). #### `ClockSyncProfileCollection` (Singleton Collection) - **`static ClockSyncProfileCollection GetCollection()`** Thread-safe singleton accessor. Loads profiles from `ClockSyncProfiles.xml` (creating it with defaults if missing). - **`ClockSyncProfile GetClockSyncProfile(string s)`** Returns the first profile matching `ProfileName == s`. If no match, returns the profile with `ProfileId == 0` (typically `"None"`). If neither exists, returns the first item in the collection. - **Constants**: - `NONE_NAME`, `PTPIEEE1588_NAME`, `IRIGB1PPS_NAME`, `GPS1PPS_NAME`, `IRIGB_NAME`, `_1PPS_NAME` Hardcoded string constants for profile names (e.g., `"PTP IEEE 1588"`). - **`ClockSyncProfileDefaults` Enum**: Defines default profile types with `[Display]` and `[Browsable]` attributes: - `None` (ID=0) - `PTPIEEE1588` (ID=1) - `IRIGB1PPS` (ID=2) - `GPS1PPS` (ID=4) - `IRIGB` (ID=8) - `_1PPS` (ID=16) Values use bit-shifted powers of two (e.g., `1 << 0`, `1 << 1`), but IDs are cast to `int` directly in `GetProfileInfo()`. --- ### 3. Invariants - **Singleton Consistency**: `GetCollection()` always returns the same instance after first initialization. - **Profile Visibility Filtering**: `ClockSyncProfileConverter.Values` only includes profiles where `Visible == true`. - **Display Order Sorting**: `ClockSyncProfileConverter.Values` is sorted ascending by `DisplayOrder` (using `int.MaxValue` as fallback for missing order). - **Fallback Profile Selection**: `GetClockSyncProfile(string)` prioritizes exact name match, then `ProfileId == 0`, then first item. - **XML File Handling**: `ClockSyncProfiles.xml` is auto-generated with defaults if missing; existing file is never overwritten. - **Enum Metadata Dependency**: `ClockSyncProfile`’s enum-based constructor relies on `[Display]` and `[Browsable]` attributes being present on `ClockSyncProfileDefaults` members. Missing attributes cause runtime exceptions (e.g., `IndexOutOfRangeException` on `valueAttributes[0]`). --- ### 4. Dependencies - **Internal Dependencies**: - `DTS.Common.Classes.DSP.DASRestriction` (used in `FilterRestrictions`). - `System.ComponentModel.DataAnnotations` (for `[Display]`, `[Browsable]`). - `System.Xml.Serialization` (for XML serialization/deserialization). - `System.Collections.ObjectModel.Collection` (base class). - **External Dependencies**: - `ClockSyncProfileCollection` depends on `DASRestriction` type (defined elsewhere in `DTS.Common`). - `ClockSyncProfileConverter` depends on `ClockSyncProfileCollection` (singleton access). - **Depended Upon By**: - UI components (e.g., property grids) via `ClockSyncProfileConverter`. - Other modules requiring clock sync configuration (e.g., DSP configuration logic). --- ### 5. Gotchas - **Enum ID Mismatch**: `ClockSyncProfileDefaults` uses bit-shifted values (e.g., `1 << 0 = 1`, `1 << 1 = 2`), but `GetProfileInfo()` casts the enum value directly to `int` for `profileId`. This means `IRIGB1PPS` has `ProfileId = 2`, not `1`. Ensure downstream logic does not assume sequential IDs. - **Attribute Dependency**: If `[Display]` or `[Browsable]` attributes are missing on a `ClockSyncProfileDefaults` member, `GetProfileInfo()` throws `IndexOutOfRangeException` (accessing `valueAttributes[0]` without null checks). - **Thread-Safe Lazy Initialization**: `ClockSyncProfileConverter.Values` uses double-checked locking but reinitializes `_values` only once per app domain. Subsequent modifications to the collection (e.g., via `GetCollection().Add(...)`) will *not* update `_values` until the converter is recreated. - **Non-Visible Profiles in StandardValues**: `GetStandardValues()` returns *all* profiles (including non-visible ones), while `Values` returns only visible ones. This inconsistency may confuse consumers expecting uniform filtering. - **Hardcoded XML Filename**: `CLOCKSYNC_PROFILE_XML_FILE = "ClockSyncProfiles.xml"` is hardcoded; no configuration override is provided. - **No Validation on `FilterRestrictions`**: `FilterRestrictions` is a `DASRestriction[]` with no null-checking or validation in constructors. Passing `null` may cause `NullReferenceException` downstream. - **No Profile Modification Support**: The collection is read-only after initialization (via `Collection` base). Adding/removing profiles at runtime requires direct manipulation of `Items`, which bypasses validation. None identified beyond these.