--- source_files: - DataPRO/Modules/DatabaseImporter/DatabaseImport/SensorDB/SensorRange.cs - DataPRO/Modules/DatabaseImporter/DatabaseImport/SensorDB/SensorDB.cs - DataPRO/Modules/DatabaseImporter/DatabaseImport/SensorDB/DigitalInputSetting.cs - DataPRO/Modules/DatabaseImporter/DatabaseImport/SensorDB/DigitalOutputSetting.cs - DataPRO/Modules/DatabaseImporter/DatabaseImport/SensorDB/SquibSetting.cs - DataPRO/Modules/DatabaseImporter/DatabaseImport/SensorDB/FilterClass.cs - DataPRO/Modules/DatabaseImporter/DatabaseImport/SensorDB/SensorCalibrationList.cs - DataPRO/Modules/DatabaseImporter/DatabaseImport/SensorDB/CalibrationRecords.cs - DataPRO/Modules/DatabaseImporter/DatabaseImport/SensorDB/IsoCode.cs - DataPRO/Modules/DatabaseImporter/DatabaseImport/SensorDB/SensorsCollection.cs - DataPRO/Modules/DatabaseImporter/DatabaseImport/SensorDB/SensorCalibration.cs generated_at: "2026-04-16T04:31:14.887778+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "927e0a96c4cf2bf8" --- # Sensor Database Module Documentation ## 1. Purpose This module provides data structures and services for importing, managing, and accessing sensor configuration and calibration data from a database into the DataPRO system. It defines concrete types for various sensor categories (analog, digital input, digital output, squib), their associated calibration records, and supporting classes for ISO code parsing, filter classification, and range definitions. The module acts as the data layer abstraction for sensor metadata, enabling consistent representation of sensor properties, calibration parameters, and configuration settings across the application. ## 2. Public Interface ### Classes #### `SensorRange` - **`SensorRange(string value)`** Parses a comma-separated string of three doubles into `Low`, `Medium`, and `High` properties. Throws `InvalidDataException` if the input does not contain exactly three values. - **`SensorRange(double low, double medium, double high)`** Constructor that directly initializes `Low`, `Medium`, and `High` properties. #### `LowHigh` - **`LowHigh(double low, double high)`** Constructor initializing `Low` and `High` properties. - **`LowHigh(string value)`** Parses a comma-separated string of two doubles into `Low` and `High`. Throws `InvalidDataException` if fewer than two values are present. Uses `InvariantCulture` for parsing. #### `FilterClass` - **`FilterClass(FilterClassType fc)`** Constructor initializing `FClass` and `Frequency` based on predefined CFC filter types. Throws `Exception` for unknown types. - **`FilterClass(string fclass)`** Constructor parsing a string representation (e.g., `"17"`, `"CFC60"`, `"1000"`, `"AdHoc"`) into `FClass` and `Frequency`. Supports numeric codes, CFC names, and arbitrary numeric values for `AdHoc`. - **`ToString()`** Returns a human-readable string representation (e.g., `"17 (CFC10)"`, `"None"`, `"100"` for `AdHoc`). - **`FilterClassType` enum**: `None = 0`, `AdHoc = -1`, `CFC10 = 17`, `CFC60 = 100`, `CFC180 = 300`, `CFC600 = 1000`, `CFC1000 = 1650`. #### `IsoCode` - **`IsoCode(string isoCode)`** Constructor initializing the 16-character ISO code. Truncates or pads with `'?'` as needed. - **`StringRepresentation` property (string)** Gets/sets the full 16-character ISO code string. - **Component properties** (all `string` type, each representing a fixed-width segment): - `TestObject` (1 char, index 0) - `Position` (1 char, index 1) - `MainLocation` (4 chars, indices 2–5) - `FineLocation1` (2 chars, indices 6–7) - `FineLocation2` (2 chars, indices 8–9) - `FineLocation3` (2 chars, indices 10–11) - `PhysicalDimension` (2 chars, indices 12–13) - `Direction` (1 char, index 14) - `FilterClass` (1 char, index 15) Each property setter pads with `'?'` or truncates as needed; empty or null inputs default to `'?'`. #### `SensorCalibration` - **`SensorCalibration()`** Default constructor. - **`SensorCalibration(string s)`** Deserializes from a `ListSeparator`-delimited string (see `SEPARATOR_REPLACEMENT`). - **`SensorCalibration(DataRow dr)`** Populates from a database row using `DbOperations.SensorDB.SensorCalibrationFields` enum. - **`SensorCalibration(SensorCalibration sc)`** Copy constructor. - **`FromSerializedString(string s)`** Deserializes from a string using `SEPARATOR_REPLACEMENT` (`"__SC__"`) to escape list separators. - **`NewDigitalSC()`** Static factory returning a default calibration for digital sensors (`Sensitivity=1`, `EngineeringUnits="V"`, `Excitation=Volt5`, `IsProportional=false`, `RemoveOffset=false`). - **`GetLatestCalibrationBySerialNumberAndExcitation(SensorData sd, ExcitationVoltageOption exc)`** Static method delegating to `SensorCalibrationList.GetLatestCalibrationBySerialNumberAndExcitation`. - **`CompareTo(SensorCalibration other)`** Implements `IComparable`: sorts descending by `CalibrationDate`, then `ModifyDate`, then `CalVersion`. - **Properties**: - `CalVersion` (`long`) - `CalibrationDate` (`DateTime`) - `ModifyDate` (`DateTime`) - `SerialNumber` (`string`) - `Username` (`string`) - `Records` (`CalibrationRecords`) - `IsProportional` (`bool`, read-only logic: `!NonLinear && _isProportional`) - `RemoveOffset` (`bool`, read-only logic: `!NonLinear && _bRemoveOffset`) - `NonLinear` (`bool`) - `LocalOnly` (`bool`) - `ZeroMethod` (`ZeroMethod`) - `InitialOffset` (`InitialOffset`) - `CertificationDocuments` (`string[]`) #### `SensorCalibrationList` - **`Reload()`** Static method that clears and rebuilds the internal `_calibrationList` singleton instance (thread-safe via `LOCK`). - **`GetLatestCalibrationBySerialNumberAndExcitation(SensorData sd, ExcitationVoltageOption exc)`** Static method returning the most recent calibration for a given sensor and excitation. Returns `SensorCalibration.NewDigitalSC()` for digital/squib types. Uses `_cachedCalibrations` if available; otherwise queries `_calibrationList`. - **`DeleteAll()`** Static method calling stored procedure `sp_SensorCalibrationsDelete`, clearing `_calibrationList._calibrations`, and logging errors. #### `CalibrationRecords` - **`CalibrationRecords()`** Default constructor initializing `Records` to a single default `CalibrationRecord`. - **`CalibrationRecords(string records)`** Parses a serialized string using `"__x__"` as primary separator and `"___xx___"` as backup escape sequence. - **`CalibrationRecords(CalibrationRecords copy)`** Deep copy constructor. - **`FromSerializedString(string s)`** Parses serialized string into `Records` array. #### `CalibrationRecord` - **`CalibrationRecord()`** Default constructor initializing `Poly` to a new `LinearizationFormula`. - **`CalibrationRecord(string s)`** Parses from a `ListSeparator`-delimited string (e.g., `";"` in `InvariantCulture`). - **`CalibrationRecord(CalibrationRecord copy)`** Copy constructor. - **`FromString(string s)`** Deserializes from a `ListSeparator`-delimited string. Uses `"x_Separator_x"` as escape sequence for list separators. - **Properties**: - `Sensitivity` (`double`) - `ZeroPoint` (`double`, computed from `Poly.ZeroPositionIntercept / Poly.CalibrationFactor` if `Poly.CalibrationFactor != 0`, else stored `_zeroPoint`) - `Poly` (`LinearizationFormula`) - `AtCapacity` (`bool`) - `EngineeringUnits` (`string`, default `"g"`) - `SensitivityUnits` (`SensUnits`, default `NONE`) - `Excitation` (`ExcitationVoltageOption`, default `Volt5`) - `CapacityOutputIsBasedOn` (`double`, default `1.0`) #### `DigitalInputSetting` - **`DigitalInputSetting(IDataRecord reader)`** Constructor populating from database record using `DbOperations.DigitalInputSettings.Fields` enum. Calls `SetDefaults(this)` first. Catches and logs exceptions. - **`SetDefaults(SensorData sd)`** Static method setting default values for digital input sensors (e.g., `Bridge=DigitalInput`, `Capacity=1`, `DisplayUnit="V"`, `Shunt=ShuntMode.None`). #### `DigitalOutputSetting` - **`DigitalOutputSetting()`** Default constructor calling `SetDefaults(this)`. - **`DigitalOutputSetting(IDataRecord reader)`** Constructor populating from database record using `DbOperations.DigitalOutputSettings.Fields` enum. Sets `Bridge` to `TOMDigital` before calling `SetDefaults(this)`. - **`ChannelDescription` property** Getter returns `SerialNumber`; setter assigns to `SerialNumber` and raises `PropertyChanged("ChannelDescription")`. - **`SetDefaults(SensorData sd)`** Static method setting defaults for digital output sensors (e.g., `Bridge=TOMDigital`, `SupportedExcitation=[Volt5]`, `DisplayUnit="V"`). #### `SquibSetting` - **`SquibSetting(IDataRecord reader)`** Constructor populating from database record using `DbOperations.Squib.Fields` enum. Calls `SetDefaults(this)` first, then overrides with DB values. Ensures `Comment` is non-null (defaults to `SerialNumber` if empty). - **`SquibDescription` property** Getter returns `SerialNumber`; setter assigns to `SerialNumber` and raises `PropertyChanged("SquibDescription")`. - **`ArticleId` property** Getter returns `Id`; setter assigns to `Id` and raises `PropertyChanged("ArticleId")`. - **`BypassCurrentFilter` / `BypassVoltageFilter` properties** Boolean properties with `SetProperty` pattern for `INotifyPropertyChanged`. - **`SetDefaults(SensorData sd)`** Static method setting defaults for squib sensors (e.g., `Bridge=SQUIB`, `Capacity=5`, `SupportedExcitation=[Volt5]`, `DisplayUnit="V"`). #### `SensorsCollection` - **`SensorsList` property** Static singleton property (thread-safe via `Lock`). - **`GetSensorBySerialNumber(string serialNumber, bool excludeBroken = true, bool bUseCache = true)`** Returns a `SensorData` (or derived type) by serial number. Checks cache first if `bUseCache`. Queries database via stored procedures in order: `sp_SensorsAnalogGet`, `sp_SensorsDigitalInGet`, `sp_SensorsSquibGet`, `sp_SensorsDigitalOutGet`. Returns `null` if not found. Handles test-specific digital output serial numbers. - **`DeleteAll()`** Static method calling `sp_SensorDeleteAll` stored procedure, then calling `SensorCalibrationList.DeleteAll()`, and raising `OnPropertyChanged("AllSensors")`. - **`HookedUp` property** Controls whether `OnPropertyChanged` events are raised (if `false`, events suppressed). ### Enums #### `ShuntMode` (SensorDB.cs) `None`, `Emulation`, `Internal`, `External` #### `BridgeLeg` (SensorDB.cs) `First`, `Second`, `Third`, `Fourth` #### `CouplingModes` (SensorDB.cs) `AC = 0`, `DC` ## 3. Invariants - **`SensorRange`**: Must contain exactly three comma-separated numeric values; otherwise, `InvalidDataException` is thrown. - **`LowHigh`**: Must contain at least two comma-separated numeric values; otherwise, `InvalidDataException` is thrown. - **`FilterClass`**: `Frequency` is always set to the numeric value corresponding to `FClass` (e.g., `CFC10` → `17.0`). `AdHoc` type stores arbitrary numeric frequency. - **`IsoCode`**: The internal `_isoCodeFull` array is always exactly 16 characters. Any component property setter ensures its segment is exactly the correct width (1, 2, or 4 chars) by padding with `'?'` or truncating. Invalid/empty inputs default to `'?'`. - **`SensorCalibration`**: - `IsProportional` and `RemoveOffset` are forced to `false` when `NonLinear` is `true`. - `ZeroPoint` in `CalibrationRecord` is computed from `Poly` if possible; otherwise, it uses the stored `_zeroPoint`. - Serialization uses `SEPARATOR_REPLACEMENT = "__SC__"` to escape list separators. - **`CalibrationRecords`**: Uses `"__x__"` as primary separator and `"___xx___"` as escape sequence during serialization/deserialization. - **`CalibrationRecord`**: Uses `InvariantCulture` for numeric parsing and `"x_Separator_x"` as escape sequence for list separators. - **`DigitalInputSetting`, `DigitalOutputSetting`, `SquibSetting`**: All inherit from `SensorData` and call `SetDefaults()` during construction to ensure consistent baseline properties. ## 4. Dependencies ### Internal Dependencies (from source) - **`DbOperations`**: Used for database field names (`DbOperations.*.Fields.*`), SQL command creation (`GetSQLCommand`), and stored procedure names (`DbOperationsEnum.StoredProcedure.*`). - **`Test.Module.Channel.Sensor`**: Referenced for `BridgeType`, `SensUnits`, and `ExcitationVoltageOptions`. - **`ZeroMethod`**, **`InitialOffset`**, **`LinearizationFormula`**, **`SensorData`**: Referenced but not included in the provided source files. Their definitions are assumed to exist elsewhere in the codebase. - **`ICalibrationRecords`**, **`ISensorCalibration`**: Interfaces implemented by `CalibrationRecords` and `SensorCalibration` respectively. ### External Dependencies - **System**: `System`, `System.ComponentModel`, `System.Data`, `System.Data.SqlClient`, `System.Globalization`, `System.Linq`, `System.Text`, `System.Xml`. - **Database**: SQL Server stored procedures: - `sp_SensorDeleteAll` - `sp_SensorCalibrationsDelete` - `sp_SensorsAnalogGet` - `sp_SensorsDigitalInGet` - `sp_SensorsSquibGet` - `sp_SensorsDigitalOutGet` ### Dependencies on this Module - `SensorsCollection.SensorsList` is used to retrieve sensor configurations by serial number. - `SensorCalibrationList.GetLatestCalibrationBySerialNumberAndExcitation` is used to retrieve calibration data. - `SensorRange`, `LowHigh`, `FilterClass`, `IsoCode` are likely used for parsing configuration strings and ISO codes elsewhere in the system. ## 5. Gotchas - **`SensorRange` constructor**: Throws `InvalidDataException` for malformed input, but no validation is performed on the numeric values (e.g., `Low > Medium` is allowed). - **`LowHigh` constructor**: Uses `InvariantCulture` for parsing, but `SensorRange` does not specify culture—assumes current culture or default parsing behavior. - **`FilterClass` constructor**: Ambiguity in parsing `"1000"`: matches both `CFC600` (1000 Hz) and `CFC1000` (1650 Hz)? The code prioritizes exact numeric match (`case 1000` → `CFC600`), but `"CFC1000"` string match would take precedence if present. - **`IsoCode`**: Setter for `StringRepresentation` pads with `'0'` if input is shorter than 16 chars, but constructor pads with `'?'`. Inconsistent behavior. - **`CalibrationRecord.ZeroPoint`**: The computed value depends on `Poly.CalibrationFactor`; if `Poly` is uninitialized or `CalibrationFactor == 0`, the stored `_zeroPoint` is returned. This could lead to stale or incorrect values if `Poly` is modified after `ZeroPoint` is set. - **`SensorCalibrationList.GetLatestCalibrationBySerialNumberAndExcitation`**: Uses `_cachedCalibrations` if available, but this field is never populated in the provided source—likely populated elsewhere (e.g., during `Reload()` or initial load). If `_cachedCalibrations` is null, it falls back to `_calibrationList`, which may be uninitialized if `Reload()` hasn’t been called. - **`SensorCalibrationList.DeleteAll()`**: Clears `_calibrationList._calibrations` but does not clear `_cachedCalibrations`, potentially leaving stale data in memory. - **`DigitalInputSetting` constructor**: Assigns `Comment = UserValue1` (line 25), but `UserValue1` is also assigned from `DbOperations.DigitalInputSettings.Fields.UserValue1.ToString()` (line 18). This may be intentional, but could be a source of confusion. - **`SquibSetting` constructor**: Assigns `Comment = UserValue1` after reading from DB, but then reassigns `Comment = SerialNumber` if `Comment` is null/whitespace. This double-assignment is redundant and could be simplified. - **`DigitalOutputSetting.ChannelDescription`**: Setter modifies `SerialNumber` and raises `PropertyChanged("ChannelDescription")`. This is unusual—typically, a property named `ChannelDescription` would not mutate `SerialNumber`. - **`SensorCalibration` serialization**: Uses `SEPARATOR_REPLACEMENT = "__SC__"` to escape list separators, but `CalibrationRecord` uses `"x_Separator_x"`—different escaping schemes for nested serialization. - **`SensorCalibrationList` constructor**: The private constructor contains a comment indicating removed code that “appeared it would never work (wrong parameters to sql sp)”, suggesting potential instability or incomplete implementation. - **`SensorsCollection.GetSensorBySerialNumber`**: Does not use the `excludeBroken` parameter in the provided code—broken sensors are not filtered out despite the parameter name. - **`SensorCalibrationList.GetLatestCalibrationBySerialNumberAndExcitation`**: Returns `SensorCalibration.NewDigitalSC()` for digital/squib sensors, but this default calibration may not reflect actual sensor behavior (e.g., `Sensitivity=1` is arbitrary).