using DTS.Common.Classes.Sensors; using DTS.Common.Enums; using DTS.Common.Import.ImportOptions; using DTS.Common.Import.Parsers; using DTS.Common.Interface.Sensors; using DTS.Common.SharedResource.Strings; using DTS.Common.Storage; using DTS.SensorDB; using DTS.Slice.Users; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Xml.Linq; using static DTS.Common.Enums.Sensors.SensorConstants; 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); } /// /// Adjusts squibs measurement type if appropriate /// http://manuscript.dts.local/f/cases/44393/GM-SQUIB-imports-require-initiator-signal-not-voltage /// private static void SetSquibMeasurementType(ISensorData sd) { if (sd.IsSquib() && UseInitSignalTOM) { sd.SquibMeasurementType = SquibMeasurementType.INIT_SIGNAL; } } //FB 44299 private static void SetSensorTypeInSensorDataTags(SensorData sensorData, string tag) { if (string.IsNullOrEmpty(tag)) { return; } var allTags = new List(); //FB 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); } 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(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(new[] { StringResources.ImportSensorsPreviewControl_EQXVersionReadError })); return importObject; } } if (eQXEdition > MAX_EQX_VERSION_SUPPORT) { _importNotification.ReportErrors(new List(new[] { string.Format(StringResources.ImportSensorsPreviewControl_EQXVersionError, eQXEdition, MAX_EQX_VERSION_SUPPORT) })); return importObject; } _eqxSensorDatabase.Read(filename, (List readErrors) => { _importNotification.ReportErrors(readErrors); }, EQXUseSerialNumberFieldForSN, UseZeroForUnfiltered, ImportCreateDynamicGroups); var sensors = _eqxSensorDatabase.GetSensors(); var lookup = new Dictionary(); 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; } /// /// returns a list of any excitation errors for sensors in the import file /// created for EQX processing /// 15609 Sensors not usable after EQX import /// /// private List GetExcitationErrors() { if (null == _eqxSensorDatabase) { return new List(); } var errors = new List(); 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; } } }