283 lines
12 KiB
C#
283 lines
12 KiB
C#
|
|
using DTS.Common.SharedResource.Strings;
|
|||
|
|
using DTS.SensorDB;
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Globalization;
|
|||
|
|
using System.Linq;
|
|||
|
|
using static DTS.Common.Enums.Sensors.SensorConstants;
|
|||
|
|
using System.IO;
|
|||
|
|
using DTS.Common.Enums;
|
|||
|
|
using DTS.Slice.Users;
|
|||
|
|
using DTS.Common.Import.ImportOptions;
|
|||
|
|
using System.Xml.Linq;
|
|||
|
|
using DTS.Common.Import.Parsers;
|
|||
|
|
using DTS.Common.Storage;
|
|||
|
|
using DTS.Common.Classes.Sensors;
|
|||
|
|
using DTS.Common.Interface.Sensors;
|
|||
|
|
|
|||
|
|
namespace DTS.Common.Import
|
|||
|
|
{
|
|||
|
|
public class EQXSensorsParser : ParseVariantBase
|
|||
|
|
{
|
|||
|
|
private readonly User _currentUser;
|
|||
|
|
private readonly IImportNotification _importNotification;
|
|||
|
|
private readonly EquipmentExchange.EQXSensorDatabase _eqxSensorDatabase;
|
|||
|
|
private readonly EqxImportOptions _eqxImportOptions;
|
|||
|
|
public EQXSensorsParser(IImportNotification importNotification, User user, EqxImportOptions eqxImportOptions,
|
|||
|
|
EquipmentExchange.EQXSensorDatabase eqxSensorDatabase)
|
|||
|
|
{
|
|||
|
|
_currentUser = user;
|
|||
|
|
_importNotification = importNotification;
|
|||
|
|
_eqxSensorDatabase = eqxSensorDatabase;
|
|||
|
|
_eqxImportOptions = eqxImportOptions;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const float MAX_EQX_VERSION_SUPPORT = 1.5F;
|
|||
|
|
public bool ImportCreateDynamicGroups { get; set; }
|
|||
|
|
public bool EQXUseSerialNumberFieldForSN { get; set; }
|
|||
|
|
public bool UseZeroForUnfiltered { get; set; }
|
|||
|
|
|
|||
|
|
public override void Parse(ref ImportObject importObject)
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrEmpty(FileName))
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (importObject == null)
|
|||
|
|
{
|
|||
|
|
throw new ArgumentNullException("importObject", "importObject can't be null or empty");
|
|||
|
|
}
|
|||
|
|
importObject = ParseSensor(importObject, FileName);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
//FB 44299
|
|||
|
|
private static void SetSensorTypeInSensorDataTags(SensorData sensorData, string tag)
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrEmpty(tag)) { return; }
|
|||
|
|
|
|||
|
|
var allTags = new List<string>();
|
|||
|
|
//FB 44299 copied the code from DataPRO sensor, I am not sure why it created a copy of SensorData
|
|||
|
|
var sensorDataCopy = new SensorData(sensorData);
|
|||
|
|
var currentTags = sensorDataCopy.GetTagsArray(DbOperations.TagsGet);
|
|||
|
|
if (currentTags != null && currentTags.Any())
|
|||
|
|
{
|
|||
|
|
allTags.AddRange(currentTags);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!allTags.Contains(tag))
|
|||
|
|
{
|
|||
|
|
allTags.Add(tag);
|
|||
|
|
}
|
|||
|
|
// Set the tags
|
|||
|
|
sensorData.SetTags(allTags.ToArray(), DbOperations.GetSQLCommand, DbOperations.TagsGet, DbOperations.TagsGetId, DbOperations.TagsInsert);
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// Adjusts squibs measurement type if appropriate
|
|||
|
|
/// http://manuscript.dts.local/f/cases/44299/SW-Re-Implement-GM-ISF-Style-Real-Time-tags-for-EQX-import
|
|||
|
|
/// </summary>
|
|||
|
|
private void SetSquibMeasurementType(ISensorData sd)
|
|||
|
|
{
|
|||
|
|
if (sd.IsSquib() && UseInitSignalTOM)
|
|||
|
|
{
|
|||
|
|
sd.SquibMeasurementType = SquibMeasurementType.INIT_SIGNAL;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
private ImportObject ParseSensor(ImportObject importObject, string filename)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
int currentDone = 0;
|
|||
|
|
var lines = File.ReadAllLines(filename);
|
|||
|
|
|
|||
|
|
int totalCount = lines.Count();
|
|||
|
|
XDocument xDoc = null;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
xDoc = XDocument.Load(filename);
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
_importNotification.ReportErrors(new List<string>(new[] { StringResources.ImportSensorsPreviewControl_EQXFileXMLError, ex.Message }));
|
|||
|
|
|
|||
|
|
return importObject;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
float eQXEdition = MAX_EQX_VERSION_SUPPORT;
|
|||
|
|
var fileInfo = xDoc.Elements("Sensors").Select(x => x.Elements("FileInfo")).FirstOrDefault();
|
|||
|
|
if (fileInfo.Any())
|
|||
|
|
{
|
|||
|
|
var eQXEditionString = fileInfo.Select(x => x.Attribute("DataFormatEdition").Value).FirstOrDefault();
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
eQXEdition = Convert.ToSingle(eQXEditionString, CultureInfo.InvariantCulture);
|
|||
|
|
}
|
|||
|
|
catch
|
|||
|
|
{
|
|||
|
|
_importNotification.ReportErrors(new List<string>(new[] { StringResources.ImportSensorsPreviewControl_EQXVersionReadError }));
|
|||
|
|
return importObject;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (eQXEdition > MAX_EQX_VERSION_SUPPORT)
|
|||
|
|
{
|
|||
|
|
_importNotification.ReportErrors(new List<string>(new[] { string.Format(StringResources.ImportSensorsPreviewControl_EQXVersionError, eQXEdition, MAX_EQX_VERSION_SUPPORT) }));
|
|||
|
|
return importObject;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_eqxSensorDatabase.Read(filename, (List<string> readErrors) => { _importNotification.ReportErrors(readErrors); }, EQXUseSerialNumberFieldForSN, UseZeroForUnfiltered, ImportCreateDynamicGroups);
|
|||
|
|
|
|||
|
|
var sensors = _eqxSensorDatabase.GetSensors();
|
|||
|
|
var lookup = new Dictionary<string, bool>();
|
|||
|
|
var increment = Convert.ToInt32(lines.Length / (double)sensors.Length);
|
|||
|
|
foreach (var sd in sensors)
|
|||
|
|
{
|
|||
|
|
var sc = _eqxSensorDatabase.GetCalibrations(sd.UUID);
|
|||
|
|
if (0 == currentDone % 10)
|
|||
|
|
{
|
|||
|
|
_importNotification.SetProgress(100D * currentDone / totalCount);
|
|||
|
|
}
|
|||
|
|
//check to see if the sensor had a NULL IDModuleString, if so
|
|||
|
|
//check for an existing EID and use that rather than wiping out the EID
|
|||
|
|
//18467 Missing IDModuleString in e2x file import is clearing the EID on sensor import
|
|||
|
|
if (_eqxSensorDatabase.SensorHasNullIDModule(sd.UUID) && _eqxSensorDatabase.GetSensorNullIdModuleValue(sd.UUID))
|
|||
|
|
{
|
|||
|
|
var existing = SensorsCollection.SensorsList.GetSensorBySerialNumber(sd.SerialNumber);
|
|||
|
|
if (null != existing)
|
|||
|
|
{
|
|||
|
|
sd.EID = existing.EID;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var sensorType = ChannelTypeUtility.ParseSensorKnownChannelType(sd.SerialNumber);
|
|||
|
|
SetSensorTypeInSensorDataTags(sd, sensorType);
|
|||
|
|
|
|||
|
|
SetSquibMeasurementType(sd);
|
|||
|
|
|
|||
|
|
currentDone += increment;
|
|||
|
|
|
|||
|
|
if (!string.IsNullOrEmpty(sd.SerialNumber))
|
|||
|
|
{
|
|||
|
|
importObject.AddSensorLookup(sd.SerialNumber, sd);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!string.IsNullOrEmpty(sd.SerialNumber))
|
|||
|
|
{
|
|||
|
|
importObject.AddCalibrationLookup(sd.SerialNumber, sc);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// this is for compatability for import test setups
|
|||
|
|
if (importObject.Sensors().FirstOrDefault(s => s.SerialNumber == sd.SerialNumber) == null)
|
|||
|
|
{
|
|||
|
|
importObject.AddSensor(sd);
|
|||
|
|
}
|
|||
|
|
importObject.AddSensorChannelCodeLookup(sd.SettingName, sd.SerialNumber);
|
|||
|
|
// this is for compatability for import test setups
|
|||
|
|
importObject.AddCalibrations(sc);
|
|||
|
|
|
|||
|
|
var key = $"{sd.Manufacturer}_{sd.Model}";
|
|||
|
|
sc.Sort();
|
|||
|
|
|
|||
|
|
if (!lookup.ContainsKey(key) && sc.Any())
|
|||
|
|
{
|
|||
|
|
var model = FactorySensorModel.CreateModelFromSensor(sd, sc[0], _currentUser);
|
|||
|
|
importObject.AddSensorModelLookup(key, model);
|
|||
|
|
lookup[key] = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//15609 Sensors not usable after EQX import
|
|||
|
|
//warn on invalid excitation problems
|
|||
|
|
var errors = GetExcitationErrors();
|
|||
|
|
|
|||
|
|
//TODO Report the errors
|
|||
|
|
|
|||
|
|
return importObject;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// returns a list of any excitation errors for sensors in the import file
|
|||
|
|
/// created for EQX processing
|
|||
|
|
/// 15609 Sensors not usable after EQX import
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
private List<string> GetExcitationErrors()
|
|||
|
|
{
|
|||
|
|
if (null == _eqxSensorDatabase) { return new List<string>(); }
|
|||
|
|
var errors = new List<string>();
|
|||
|
|
var sensors = _eqxSensorDatabase.GetSensors();
|
|||
|
|
foreach (var sd in sensors)
|
|||
|
|
{
|
|||
|
|
switch (sd.Bridge)
|
|||
|
|
{
|
|||
|
|
case BridgeType.DigitalInput:
|
|||
|
|
case BridgeType.SQUIB:
|
|||
|
|
case BridgeType.TOMDigital:
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var hasValidCal = false;
|
|||
|
|
if (_eqxSensorDatabase.ContainsCalibration(sd.UUID))
|
|||
|
|
{
|
|||
|
|
var cals = _eqxSensorDatabase.GetCalibrations(sd.UUID);
|
|||
|
|
foreach (var cal in cals)
|
|||
|
|
{
|
|||
|
|
if (!cal.IsProportional)
|
|||
|
|
{
|
|||
|
|
hasValidCal = true;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
if (sd.SupportedExcitation.Contains(cal.Records.Records.First().Excitation))
|
|||
|
|
{
|
|||
|
|
hasValidCal = true;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
var error = string.Format(
|
|||
|
|
StringResources.Error_SensorNoCalibrationExcitationNotSupported,
|
|||
|
|
sd.ToDisplayString(), cal.Records.Records.First().Excitation.ToString());
|
|||
|
|
if (!errors.Contains(error)) { errors.Add(error); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
switch (cal.Records.Records.First().Excitation)
|
|||
|
|
{
|
|||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Undefined:
|
|||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt2_5:
|
|||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt3:
|
|||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt1:
|
|||
|
|
{
|
|||
|
|
var error = string.Format(StringResources.Error_SensorCalibrationNotSupported,
|
|||
|
|
sd.ToDisplayString(), cal.Records.Records.First().Excitation.ToString());
|
|||
|
|
if (errors.Contains(error)) { errors.Add(error); }
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt2:
|
|||
|
|
break;
|
|||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt5:
|
|||
|
|
break;
|
|||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt10:
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!hasValidCal)
|
|||
|
|
{
|
|||
|
|
var error = string.Format(StringResources.Error_SensorCalibrationNone, sd.ToDisplayString());
|
|||
|
|
if (!errors.Contains(error))
|
|||
|
|
{
|
|||
|
|
errors.Add(error);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return errors;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|