This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
---
source_files:
- DataPRO/IService/Classes/CAN/CANConfig.cs
- DataPRO/IService/Classes/CAN/CANModuleConfig.cs
generated_at: "2026-04-16T03:56:57.762497+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "49767c75e3daaeaa"
---
# CAN
## Documentation: CAN Configuration Module (`DTS.DASLib.Service`)
---
### 1. Purpose
This module provides XML-based serialization and deserialization for CAN (Controller Area Network) hardware configuration data in the DAS (Data Acquisition System) service layer. It enables persistent storage and retrieval of system-wide CAN module configurations (`CANConfig`) and per-module settings (`CANModuleConfig`), including channel definitions, recording parameters, and firmware metadata. The classes implement `IXmlSerializable` to support custom XML formatting, allowing configuration files to be stored in a human-readable and version-tolerant manner under the `DASConfigs` subdirectory relative to the executing assembly.
---
### 2. Public Interface
#### `CANConfig` class
- **`public Dictionary<string, CANModuleConfig> Modules { get; }`**
Read-only dictionary mapping module serial numbers (string keys) to `CANModuleConfig` instances. Represents all configured CAN modules.
- **`public string FileName { get; }`**
Full path to the XML file from which this `CANConfig` instance was loaded (or to which it will be written). Set only during construction.
- **`public CANConfig()`**
Default constructor. Initializes an empty configuration with no modules or file association.
- **`public CANConfig(string fileName, bool deleteIfPresent)`**
Constructor that attempts to load configuration from `fileName` (relative to `DASConfigs/` subdirectory). If `deleteIfPresent` is `true`, the file is deleted before loading (resulting in an empty config). If `false`, the file is read via `ReadXml`. Exceptions during file I/O or XML parsing are logged via `APILogger`.
- **`public void SetModule(CANModuleConfig module)`**
Inserts or updates a module in the `_modules` dictionary using `module.SerialNumber` as the key. No validation beyond key existence.
- **`public CANModuleConfig GetModule(CANModuleConfig module)`**
Returns the module stored under `module.SerialNumber`. If not present, inserts the provided `module` instance into the dictionary and returns it. *Note: This mutates the config even when the module is not yet known.*
- **`public XmlSchema GetSchema()`**
Returns `null`. Required by `IXmlSerializable` but unused.
- **`public void ReadXml(XmlReader reader)`**
Deserializes XML starting at `<CANConfig>` root. Reads a `<Modules>` section containing multiple `<CANModule>` elements. Each `<CANModule>` is deserialized into a `CANModuleConfig` and added via `SetModule`.
- **`public void WriteXml(XmlWriter writer)`**
Serializes the configuration as `<CANConfig><Modules>...</Modules></CANConfig>`. Each `CANModuleConfig` is written via its own `WriteXml` method, with `writer.Flush()` called after writing the `<Modules>` start tag and after each module.
#### `CANModuleConfig` class
- **`public string SerialNumber { get; set; }`**
Unique identifier for the CAN module (used as dictionary key in `CANConfig.Modules`).
- **`public string TestId { get; set; }`**
Identifier for the test associated with this module.
- **`public string TestDescription { get; set; }`**
Human-readable description of the test.
- **`public DFConstantsAndEnums.RecordingMode RecordingMode { get; set; }`**
Recording mode enum (e.g., continuous, event-triggered). Defaults to `InvalidArmMode`.
- **`public float AAFilterRateHz { get; set; }`**
Anti-aliasing filter rate in Hz. Default `0`.
- **`public double PreTriggerSeconds { get; set; }`**
Duration (seconds) of data to capture *before* a trigger event. Default `0`.
- **`public double PostTriggerSeconds { get; set; }`**
Duration (seconds) of data to capture *after* a trigger event. Default `0`.
- **`public string FirmwareVersion { get; set; }`**
Firmware version string reported by the module.
- **`public UInt64? MaxEventStorageSpaceInBytes { get; set; }`**
Optional maximum storage space (in bytes) for event-triggered recordings. Nullable; defaults to `0`.
- **`public int ModuleArrayIndex { get; set; }`**
Index of the module in a logical array (e.g., for ordering). Default `0`.
- **`public string FileName { get; }`**
Full path to the XML file from which this module config was loaded. Set only during construction.
- **`public CANModuleConfig()`**
Default constructor. Initializes all properties to defaults.
- **`public CANModuleConfig(string fileName)`**
Constructor that loads configuration from `fileName` (relative to `DASConfigs/`). Logs errors on failure.
- **`public void SetChannel(CANInputDASChannel channel)`**
Inserts or updates a channel in the internal `_channels` dictionary using `channel.ModuleChannelNumber` as the key.
- **`public CANInputDASChannel GetChannel(CANInputDASChannel channel)`**
Returns the channel stored under `channel.ModuleChannelNumber`. If not present, inserts the provided `channel` and returns it. *Note: Mutates config on miss.*
- **`public XmlSchema GetSchema()`**
Returns `null`. Required by `IXmlSerializable` but unused.
- **`public void ReadXml(XmlReader reader)`**
Deserializes XML starting at `<CANModule>`. Reads scalar properties (`SerialNumber`, `TestId`, etc.) and the `<Channels>` section. For `RecordingMode`, `AAFilterRateHz`, `PreTriggerSeconds`, `PostTriggerSeconds`, and `MaxEventStorageSpaceInBytes`, parsing errors are logged and defaults retained. `ModuleArrayIndex` is read via `ReadModuleArray`, which silently ignores errors (for backward compatibility with older config files).
- **`public void WriteXml(XmlWriter writer)`**
Serializes the module as `<CANModule>...</CANModule>`. Writes all scalar properties and the `<Channels>` section. For each channel, calls `WriteElementStart`, `WriteXml`, and `WriteElementEnd` on the channel object.
- **`public virtual void WriteElementStart(XmlWriter writer)`**
Writes `<CANModule xsi:type="...">` where `...` is the runtime type name (e.g., `CANInputDASChannel`). Allows polymorphic deserialization.
- **`public virtual void WriteElementEnd(XmlWriter writer)`**
Writes `</CANModule>`.
---
### 3. Invariants
- **`SerialNumber` uniqueness**: Within a `CANConfig.Modules` dictionary, keys are `SerialNumber` strings. Duplicate keys are overwritten (not rejected).
- **`ModuleChannelNumber` uniqueness**: Within a `CANModuleConfig._channels` dictionary, keys are `ModuleChannelNumber` integers. Duplicate keys are overwritten.
- **XML structure**: `CANConfig` XML root is `<CANConfig>`, containing `<Modules>` with nested `<CANModule>` elements. `CANModuleConfig` XML root is `<CANModule>`.
- **Backward compatibility**: `ReadModuleArray` silently ignores missing or malformed `ModuleArrayIndex` elements, assuming older config files may lack them.
- **Default values**: All numeric/string properties have non-null defaults (e.g., `""` for strings, `0` for numerics, `InvalidArmMode` for `RecordingMode`). `MaxEventStorageSpaceInBytes` defaults to `0` (not `null`).
- **File paths**: All file paths are constructed relative to the executing assemblys directory, under `DASConfigs/<fileName>`.
---
### 4. Dependencies
- **Internal dependencies**:
- `DTS.Common.Utilities.Logging.APILogger` for error logging (used in constructors, `ReadXml`, `WriteXml`, and `ReadModuleArray`).
- `DTS.Common.Enums.DASFactory.DFConstantsAndEnums.RecordingMode` enum (used in `RecordingMode` property).
- `DASChannel` (base class) and `CANInputDASChannel` (concrete channel type) for channel storage and serialization. *Note: `DASChannel` is referenced but not defined in the provided sources.*
- **External dependencies**:
- `System.Xml`, `System.Xml.Serialization`, `System.IO`, `System.Reflection` (standard .NET libraries).
- File system access (for reading/writing XML files in `DASConfigs/`).
- **Depended upon by**:
Unknown from source alone. Likely consumed by higher-level DAS service components (e.g., configuration managers, CAN interface drivers) that initialize or update CAN module settings.
---
### 5. Gotchas
- **`GetModule`/`GetChannel` mutate on miss**: Both methods add the provided module/channel to the internal dictionary if not found, which may be unintended (e.g., during read-only queries). Consider renaming or clarifying intent.
- **No validation on `SerialNumber`/`ModuleChannelNumber`**: Duplicates are silently overwritten. No uniqueness enforcement beyond dictionary semantics.
- **`ReadModuleArray` swallows errors**: The `catch` block in `ReadModuleArray` ignores all exceptions, potentially masking real issues (e.g., malformed XML). This is intentional for backward compatibility but may complicate debugging.
- **`MaxEventStorageSpaceInBytes` range check is incomplete**: The condition `d >= 0 && d < ulong.MaxValue` allows `d == ulong.MaxValue`, but `Convert.ToUInt64(d)` will throw for `d == ulong.MaxValue` (since `double` may not represent it exactly). Should use `d <= ulong.MaxValue - 1` or similar.
- **No `WriteXml` override for base `DASChannel`**: The `WriteXml` method iterates over `_channels.Values` as `DASChannel`, but only `CANInputDASChannel` is instantiated in `ReadXml`. If other `DASChannel` subclasses exist, `WriteElementStart`/`WriteElementEnd` must be overridden appropriately.
- **Hardcoded path construction**: `Path.Combine(Path.GetDirectoryName(...), "DASConfigs", fileName)` assumes `DASConfigs` is a subdirectory of the assembly directory. May fail in non-standard deployment scenarios (e.g., single-file publish).
- **No XML validation schema**: `GetSchema()` returns `null`, so no schema validation occurs during deserialization. Malformed XML may cause runtime errors or silent data loss.
None identified beyond the above.