Files
DP44/DataPRO/Modules/TestSetups/Imports/TTS/ViewModel/ReadFileViewModel.cs
2026-04-17 14:55:32 -04:00

1098 lines
53 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using DTS.Common.Base;
using DTS.Common.Classes;
using DTS.Common.Enums;
using DTS.Common.Enums.TTS;
using DTS.Common.Events;
using DTS.Common.Interface;
using DTS.Common.Interface.TestSetups.Imports.TTS.ReadFile;
using DTS.Common.Utilities.Logging;
using DTS.Common.Utils;
using Prism.Events;
using Unity;
using DTS.Common.Interactivity;
using Prism.Regions;
using Prism.Commands;
using TTSImport.Model;
using TTSImport.Properties;
using DTS.SensorDB;
using TTSImport.Resources;
using DTS.Common.Interface.Sensors;
using DTS.Common.Classes.Groups.ChannelSettings;
using DTS.Common.Enums.Sensors;
// ReSharper disable CheckNamespace
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable InconsistentNaming
namespace TTSImport
{
/// <summary>
/// this class handles ReadFile functionality
/// </summary>
[PartCreationPolicy(CreationPolicy.Shared)]
public class ReadFileViewModel : IReadFileViewModel
{
/// <summary>
/// The Status and Progress bars
/// </summary>
public IStatusAndProgressBarView StatusAndProgressBarView { get; private set; }
/// <summary>
/// The ReadFile view
/// </summary>
public IReadFileView View { get; set; }
private string _fileToImport = string.Empty;
public string FileToImport
{
get => _fileToImport;
set
{
_fileToImport = value;
OnPropertyChanged("FileToImport");
}
}
private IEventAggregator _eventAggregator { get; set; }
private IRegionManager _regionManager;
private IUnityContainer UnityContainer { get; set; }
public InteractionRequest<Notification> NotificationRequest { get; private set; }
public InteractionRequest<Confirmation> ConfirmationRequest { get; private set; }
/// <summary>
/// Creates a new instance of the TechnologyDomainEditViewModel.
/// </summary>
/// <param name="readFileView">The ReadFile View.</param>
/// <param name="view"></param>
/// <param name="regionManager">The logical placeholder defined within the application's UI (in the shell or within views) into which views are displayed.</param>
/// <param name="eventAggregator">The EventAggregator which allows different components to publish/subscribe to events without being coupled to each other.</param>
/// <param name="unityContainer">The unityContainer.</param>
public ReadFileViewModel(IReadFileView view, IRegionManager regionManager, IEventAggregator eventAggregator,
IUnityContainer unityContainer)
{
View = view;
View.DataContext = this;
NotificationRequest = new InteractionRequest<Notification>();
ConfirmationRequest = new InteractionRequest<Confirmation>();
_eventAggregator = eventAggregator;
UnityContainer = unityContainer;
_regionManager = regionManager;
_eventAggregator.GetEvent<RaiseNotification>().Subscribe(OnRaiseNotification);
_eventAggregator.GetEvent<BusyIndicatorChangeNotification>()
.Subscribe(OnBusyIndicatorNotification, ThreadOption.PublisherThread, true);
_eventAggregator.GetEvent<TTSImportReadXMLFileResponseEvent>()
.Subscribe(OnXMLFileRead, ThreadOption.UIThread, true);
}
#region Methods
/// <summary>
/// handles when an XML TTS file has been read
/// </summary>
/// <param name="arg"></param>
private void OnXMLFileRead(TTSImportReadXMLFileResponseEventArg arg)
{
if (null != arg.TestSetup && null != arg.TTSSetup && !arg.Errors.Any())
{
ProcessToyotaXMLFile(arg);
//let any consumers know that file has been read and processed
var statusArg = new ReadFileStatusArg { Status = true, TTSSetup = arg.TTSSetup };
_eventAggregator.GetEvent<TTSImportReadFileStatusEvent>().Publish(statusArg);
//mark as done
SetStatus(StringResources.ImportTestSetup_PossibleStatus_Done);
return;
}
//if we have an error message push it to user
if (arg.Errors.Any())
{
_eventAggregator.GetEvent<PageErrorEvent>().Publish(new PageErrorArg(arg.Errors, null));
}
//finally, mark as failed
SetStatus(StringResources.ImportTestSetup_PossibleStatus_Failed);
}
public void Cleanup() //Duplicate of ImportTestSetup
{
}
public Task CleanupAsync()
{
return Task.CompletedTask;
}
public void Initialize()
{
}
public void Initialize(object parameter)
{
}
public void Initialize(object parameter, object model)
{
}
public Task InitializeAsync()
{
StatusAndProgressBarView = GetStatusAndProgressBarView(this);
return Task.CompletedTask;
}
public Task InitializeAsync(object parameter)
{
return Task.CompletedTask;
}
public void Activated()
{
}
/// <summary>
/// Private Event handler for OnBusyIndicatorNotification event.
/// </summary>
private void OnBusyIndicatorNotification(bool eventArg)
{
IsBusy = eventArg;
}
/// <summary>
/// Private Event handler for RaiseNotification event.
/// </summary>
private void OnRaiseNotification(NotificationContentEventArgs eventArgsWithTitle)
{
// The NotificationRequest.Raise triggers the Invoke() method of the PopupWindowAction object to show the NotificationWindow window
// Notification object expects a NotificationContentEventArgsWithoutTitle object and a Title string.
var eventArgsWithoutTitle = new NotificationContentEventArgs(eventArgsWithTitle.Message, "",
eventArgsWithTitle.Image, string.Empty);
NotificationRequest.Raise(new Notification
{
Content = eventArgsWithoutTitle,
Title = eventArgsWithTitle.Title
});
}
private readonly StatusAndProgressBarEventArgs statusAndProgressBarEventArgs = new StatusAndProgressBarEventArgs();
public void SetStatus(string status)
{
SetStatus(status, string.Empty);
}
/// <summary>
/// Sets the text, background color, progress value, and/or progress visibility
/// </summary>
/// <param name="status"></param>
public void SetStatus(string status, string error)
{
switch (status)
{
case "Waiting": //change this to string resources but use the same one in DataPRO and here???
statusAndProgressBarEventArgs.StatusColor =
DTS.Common.BrushesAndColors.Brush_ApplicationStatus_Waiting.Color;
statusAndProgressBarEventArgs.ProgressBarVisibility = Visibility.Collapsed;
break;
case "Working":
statusAndProgressBarEventArgs.StatusColor =
DTS.Common.BrushesAndColors.Brush_ApplicationStatus_Busy.Color;
statusAndProgressBarEventArgs.ProgressValue = 0;
statusAndProgressBarEventArgs.ProgressBarVisibility = Visibility.Visible;
break;
case "Failed":
statusAndProgressBarEventArgs.StatusColor =
DTS.Common.BrushesAndColors.Brush_ApplicationStatus_Failed.Color;
statusAndProgressBarEventArgs.ProgressBarVisibility = Visibility.Collapsed;
break;
case "Done":
statusAndProgressBarEventArgs.StatusColor =
DTS.Common.BrushesAndColors.Brush_ApplicationStatus_Complete.Color;
statusAndProgressBarEventArgs.ProgressBarVisibility = Visibility.Collapsed;
break;
}
statusAndProgressBarEventArgs.StatusText = status;
statusAndProgressBarEventArgs.ErrorText = error;
statusAndProgressBarEventArgs.Requester = this;
_eventAggregator.GetEvent<StatusAndProgressBarEvent>().Publish(statusAndProgressBarEventArgs);
}
/// <summary>
/// Sets the progress value on the Status and Progress bar
/// </summary>
/// <param name="progress"></param>
public void SetProgress(double progress)
{
statusAndProgressBarEventArgs.ProgressValue = (int)progress;
statusAndProgressBarEventArgs.Requester = this;
_eventAggregator.GetEvent<StatusAndProgressBarEvent>().Publish(statusAndProgressBarEventArgs);
}
private IStatusAndProgressBarView GetStatusAndProgressBarView(IBaseViewModel parent)
{
var view = UnityContainer.Resolve<IStatusAndProgressBarView>();
var viewModel = UnityContainer.Resolve<IStatusAndProgressBarViewModel>();
view.DataContext = viewModel;
viewModel.Initialize(parent);
return view;
}
/// <summary>
/// Browse to import file
/// </summary>
private DelegateCommand _browseClicked;
public DelegateCommand BrowseClicked => _browseClicked ?? (_browseClicked = new DelegateCommand(BrowseMethod));
public void BrowseMethod()
{
FileToImport = string.Empty;
using (var fo = new System.Windows.Forms.OpenFileDialog())
{
fo.CheckFileExists = true;
fo.CheckPathExists = true;
fo.Filter = @"TTS (*.csv, *.xml)|*.csv; *.xml|All Files (*.*)|*.*";
fo.FilterIndex = Settings.Default.DefaultTestImportMethod;
if (fo.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
Settings.Default.DefaultTestImportMethod = fo.FilterIndex;
Settings.Default.Save();
FileToImport = fo.FileName;
}
ReadFile(FileToImport, _defaultSampleRate, _defaultRecordingMode, _defaultTTSPreTrigger, _defaultTTSPostTrigger,
_defaultTTSROIStart, _defaultTTSROIEnd, _defaultRequireEIDsFound, _defaultDigitalInputMode, _squibDefaults);
}
public void ReadFile(string importFile, double defaultSampleRate, RecordingModes defaultRecordingMode, double defaultTTSPreTrigger, double defaultTTSPostTrigger,
double defaultTTSROIStart, double defaultTTSROIEnd, bool defaultRequireEIDsFound, string defaultDigitalInputMode, ISquibSettingDefaults squibDefaults)
{
SetStatus(StringResources.ImportTestSetup_PossibleStatus_Working);
FileToImport = importFile;
_defaultSampleRate = defaultSampleRate;
_defaultRecordingMode = defaultRecordingMode;
_defaultTTSPreTrigger = defaultTTSPreTrigger;
_defaultTTSPostTrigger = defaultTTSPostTrigger;
_defaultTTSROIStart = defaultTTSROIStart;
_defaultTTSROIEnd = defaultTTSROIEnd;
_defaultRequireEIDsFound = defaultRequireEIDsFound;
_defaultDigitalInputMode = defaultDigitalInputMode;
_squibDefaults = squibDefaults;
var data = new WorkFunctionThreadData();
ThreadPool.QueueUserWorkItem(ReadFileWorkThread, data);
}
private void SetAppBusy()
{
_eventAggregator.GetEvent<BusyIndicatorChangeNotification>().Publish(true);
}
private void SetAppAvailable()
{
_eventAggregator.GetEvent<BusyIndicatorChangeNotification>().Publish(false);
}
private void ReadFileWorkThread(object obj)
{
SetAppBusy();
//_sensorSerialToHwId.Clear();
var data = obj as WorkFunctionThreadData;
try
{
ITTSSetup setup;
string error = string.Empty;
ReadFileStatusArg statusArg;
switch (Path.GetExtension(FileToImport))
{
case ".csv":
setup = ProcessToyotaCSVFile(FileToImport, ref error);
if (setup == null)
{
statusArg = new ReadFileStatusArg { Status = false, ErrorMessage = error };
_eventAggregator.GetEvent<TTSImportReadFileStatusEvent>().Publish(statusArg);
}
else
{
if (!string.IsNullOrWhiteSpace(error))
{
_eventAggregator.GetEvent<PageErrorEvent>().Publish(new PageErrorArg(new[] { error }, null));
}
statusArg = new ReadFileStatusArg { Status = true, TTSSetup = setup };
_eventAggregator.GetEvent<TTSImportReadFileStatusEvent>().Publish(statusArg);
SetStatus(StringResources.ImportTestSetup_PossibleStatus_Done);
}
break;
case ".xml":
_eventAggregator.GetEvent<AppStatusEvent>().Publish(AppStatusArg.Busy);
var setupToPass = new TTSTestSetup() { SquibDefaults = _squibDefaults };
_eventAggregator.GetEvent<TTSImportReadXMLFileRequestEvent>()
.Publish(new TTSImportReadXMLFileRequestArg(FileToImport, setupToPass));
break;
default:
SetStatus(StringResources.ImportTestSetup_PossibleStatus_Failed,
StringResources.ImportTestSetup_MustBeCSVOrXML);
return;
}
}
catch (Exception ex)
{
APILogger.Log("failed to read file: ", ex);
SetStatus(StringResources.ImportTestSetup_PossibleStatus_Failed, ex.Message);
}
finally
{
data?.DoneEvent.Set();
SetAppAvailable();
}
}
/// <summary>
/// returns true if the file is an old style tts file(prior to 18396)
/// it does this simply by counting the number of fields in the line
/// </summary>
/// <param name="fields"></param>
/// <returns></returns>
private bool IsOldSchoolFile(string[] fields)
{
return fields.Length > 20;
}
/// <summary>
/// returns the Toyota field/column corresponding to the column index
/// if the input is the old style it uses the old rules, other wise it uses the columns specified in
/// 18396 TTS import has too many columns and it makes confusion
/// it makes this determination by counting the columns present, if there's atleast 20 it'll use the old order
/// </summary>
private ToyotaFieldOrder GetToyotaField(string[] line, int curToken)
{
//original format
if (IsOldSchoolFile(line)) { return (ToyotaFieldOrder)curToken; }
var allFields = Enum.GetValues(typeof(ToyotaFieldOrder)).Cast<ToyotaFieldOrder>().ToArray();
var list = new List<ToyotaFieldOrder>();
foreach (var field in allFields)
{
var supportLevel = FieldSupportAttribute.GetSupportLevel(field);
if (supportLevel == FieldSupportLevel.RemovedParameter) { continue; }
list.Add(field);
}
if (curToken >= list.Count) { throw new Exception($"Invalid parameter, field {curToken}"); }
return list[curToken];
}
public ITTSSetup ProcessToyotaCSVFile(string importFile, ref string error)
{
var errors = new List<string>();
var records = new List<ITTSChannelRecord>();
var setup = new TTSTestSetup()
{
Filename = importFile,
SampleRate = _defaultSampleRate,
Mode = _defaultRecordingMode,
PreTrigger = _defaultTTSPreTrigger,
PostTrigger = _defaultTTSPostTrigger,
ROIStart = Math.Max(_defaultTTSROIStart, _defaultTTSPreTrigger * -1),
ROIEnd = Math.Min(_defaultTTSROIEnd, _defaultTTSPostTrigger),
RequireEIDFound = _defaultRequireEIDsFound,
DefaultDigitalInputMode = _defaultDigitalInputMode,
SquibDefaults = _squibDefaults
};
setup.PreAssignedSensorIdAndHwId = new Tuple<string, string>[0];
setup.OriginalImportFile = importFile;
try
{
var totalLines = 0.0D;
using (var parser =
new Microsoft.VisualBasic.FileIO.TextFieldParser(importFile, Encoding.GetEncoding("Shift-JIS"),
true))
{
while (!parser.EndOfData)
{
parser.ReadLine();
totalLines++;
}
}
using (var parser =
new Microsoft.VisualBasic.FileIO.TextFieldParser(importFile, Encoding.GetEncoding("Shift-JIS"),
true))
{
parser.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited;
parser.SetDelimiters(",");
setup.Line1 = parser.ReadLine();
setup.Line2 = parser.ReadLine();
setup.DummyList = new string[8];
if (setup.Line2 != null)
{
var fields = setup.Line2.Split(',');
setup.TestId = fields[0];
if (5 < fields.Length)
{
setup.DummyList[0] = fields[1];
setup.DummyList[2] = fields[2];
setup.DummyList[4] = fields[3];
setup.DummyList[6] = fields[4];
}
}
setup.Line3 = parser.ReadLine();
if (setup.Line3 != null)
{
var fields = setup.Line3.Split(',');
if (5 < fields.Length)
{
setup.DummyList[1] = fields[1];
setup.DummyList[3] = fields[2];
setup.DummyList[5] = fields[3];
setup.DummyList[7] = fields[4];
}
}
setup.Line4 = parser.ReadLine();
while (!parser.EndOfData)
{
var bErrored = false;
var fields = parser.ReadFields();
var record = new TTSChannelRecord();
for (var curToken = 0; curToken < fields.Length; curToken++)
{
//squid (and digital) don't have the rest of the columns filled out ...
if (curToken >= 5 && record.IsSquib || curToken >= 3 && record.IsDigitalInput ||
curToken >= 3 && record.IsDigitalOutput)
{
continue;
}
if (curToken >= (int)ToyotaFieldOrder.KyowaSpecificField_1)
{
var curValue = Utils.EscapeString(fields[curToken]);
if (curValue.Equals(TTSChannelRecord.DIAGNOSTICSMODE, StringComparison.OrdinalIgnoreCase))
{
record.DiagnosticsMode = true;
}
continue;
} //ignore fields after ours.
var value = Utils.EscapeString(fields[curToken]);
try
{
#region Another very long switch
var field = GetToyotaField(fields, curToken);
//if remaining but not used, just silently don't use the value passed in ... ignore it (unless it's an old school file, in which case do what we used to do)
if (FieldSupportAttribute.GetSupportLevel(field) == FieldSupportLevel.RemainedButNotUsed && !IsOldSchoolFile(fields)) { continue; }
switch (field)
{
case ToyotaFieldOrder.ChannelNumber: //A
if (int.TryParse(value, out int channelNumber))
{
record.ChannelNumber = channelNumber;
}
else
{
//FB12439: Reserved Sensors no longer supported
if (!errors.Contains(StringResources.ReservedSensorFound)) errors.Add(StringResources.ReservedSensorFound);
bErrored = true;
}
break;
case ToyotaFieldOrder.ChannelCode: //B
if (!string.IsNullOrWhiteSpace(value))
{
if (DuplicateChannelCode(value, records))
{
error = string.Format(StringResources.ImportTestSetup_DuplicateChannelCode, value);
SetStatus(StringResources.ImportTestSetup_PossibleStatus_Failed, error);
return null;
}
record.ChannelCode = value;
record.OriginallyRequestedChannel = true;
if (value.StartsWith("DO"))
{
var rest = value.Substring(2);
if (rest.StartsWith("_"))
{
rest = rest.Substring(1);
}
if (int.TryParse(rest, out var tempInt))
{
record.IsDigitalOutput = true;
}
}
else if (value.StartsWith("DI"))
{
var rest = value.Substring(2);
if (rest.StartsWith("_"))
{
rest = rest.Substring(1);
}
if (int.TryParse(rest, out var temptInt))
{
record.IsDigitalInput = true;
}
}
else if (value.StartsWith("SQ") ||
value.StartsWith("TF"))
{
record.IsSquib = true;
record.LimitDuration = true;
}
}
else
{
record.OriginallyRequestedChannel = false;
}
break;
case ToyotaFieldOrder.JCodeOrDescription: //C
if (!string.IsNullOrWhiteSpace(record.ChannelCode))
{
if (string.IsNullOrWhiteSpace(value))
{
record.IsJCodeValid = false;
}
if (DuplicateJCode(value, records))
{
record.IsJCodeValid = false;
}
}
record.JCodeOrDescription = value;
break;
case ToyotaFieldOrder.ChannelRange: //D
if (double.TryParse(value, out double dChannelRange))
{
record.ChannelRange = dChannelRange;
record.SquibFireDelayMs = dChannelRange;
}
break;
case ToyotaFieldOrder.ChannelFilterHz: //E
if (int.TryParse(value, out int iTemp))
{
record.ChannelFilterHz = iTemp;
record.SquibFireDurationMs = (iTemp != 0 ? iTemp : _squibDefaults.FireDurationMS);
}
break;
case ToyotaFieldOrder.SensorID: //F
record.SensorEID = value;
break;
case ToyotaFieldOrder.SensorSerialNumber: //G
if (DuplicateSensorSerialNumber(value, records))
{
error = string.Format(StringResources.ImportTestSetup_DuplicateSensorSerialNumber, value);
SetStatus(StringResources.ImportTestSetup_PossibleStatus_Failed, error);
return null;
}
record.SensorSerialNumber = value;
break;
case ToyotaFieldOrder.SensorSensitivity: //H
if (double.TryParse(value, out double d))
{
record.SensorSensitivity = d;
}
break;
case ToyotaFieldOrder.SensorExcitationVolts: //I
if (double.TryParse(value, out d))
{
record.SensorExcitationVolts = d;
}
break;
case ToyotaFieldOrder.SensorCapacity: //J
if (double.TryParse(value, out d))
{
record.SensorCapacity = d;
}
break;
case ToyotaFieldOrder.SensorEU: //K
record.SensorEU = value;
break;
case ToyotaFieldOrder.SensorPolarity: //L
record.SensorPolarity = value == "+" || value == "1";
break;
case ToyotaFieldOrder.ChannelType: //M
if (!string.IsNullOrWhiteSpace(value))
{
record.ChannelType =
new DTS.Common.Utilities.DescriptionAttributeCoder<ToyotaBridgeType>()
.EncodeAttributeValue(value);
}
break;
case ToyotaFieldOrder.Description: //N
//FB12439: removed "no duplicate description" requirement from FB11238
record.Description = value;
break;
case ToyotaFieldOrder.ProportionalToExcitation: //O
if ("mv/v/eu" == value.ToLower())
{
record.ProportionalToExcitation = true;
}
else
{
record.ProportionalToExcitation = false;
}
break;
case ToyotaFieldOrder.BridgeResistance: //P
if (double.TryParse(value, out d))
{
record.BridgeResistance = d;
}
break;
case ToyotaFieldOrder.InitialOffsetVoltage: //Q
if (double.TryParse(value, out d))
{
record.InitialOffsetVoltage = d;
}
break;
case ToyotaFieldOrder.InitialOffsetVoltageTolerance: //R
if (double.TryParse(value, out d))
{
record.InitialOffsetVoltageTolerance = d;
}
break;
case ToyotaFieldOrder.RemoveOffset: //S
record.RemoveOffset = "1" == value;
break;
case ToyotaFieldOrder.ZeroMethod: //T
try
{
if (string.IsNullOrWhiteSpace(value))
{
record.ZeroMethod = ToyotaZeroMethods.AverageOverTime;
}
else
{
record.ZeroMethod =
new DTS.Common.Utilities.DescriptionAttributeCoder<ToyotaZeroMethods>()
.EncodeAttributeValue(value);
}
}
catch
{
record.ZeroMethod = ToyotaZeroMethods.AverageOverTime;
}
break;
case ToyotaFieldOrder.CableCompensationMultiplier: //U
if (double.TryParse(value, NumberStyles.Any,
System.Globalization.CultureInfo.InvariantCulture, out var dTemp))
{
record.CableMultiplier = dTemp;
}
break;
case ToyotaFieldOrder.InitialEUInMV: //V
if (double.TryParse(value, out d))
{
record.InitialEUInMV = d;
}
break;
case ToyotaFieldOrder.InitialEUInEU: //W
if (double.TryParse(value, out d))
{
record.InitialEUInEU = d;
}
break;
case ToyotaFieldOrder.IRTRACCExponent: //X
if (double.TryParse(value, out d))
{
record.IRTraccExponent = d;
}
break;
case ToyotaFieldOrder.PolynomialConstant: //Y
if (double.TryParse(value, out d))
{
record.PolynomialConstant = d;
}
break;
case ToyotaFieldOrder.PolynomialCoefficentC: //Z
if (double.TryParse(value, out d))
{
record.PolynomialCoefficientC = d;
}
break;
case ToyotaFieldOrder.PolynomialCoefficentB: //AA
if (double.TryParse(value, out d))
{
record.PolynomialCoefficentB = d;
}
break;
case ToyotaFieldOrder.PolynomialCoefficentA: //AB
if (double.TryParse(value, out d))
{
record.PolynomialCoefficientA = d;
}
break;
case ToyotaFieldOrder.PolynomialCoefficentAlpha: //AC
if (double.TryParse(value, out d))
{
record.PolynomialCoefficientAlpha = d;
}
break;
case ToyotaFieldOrder.ISOCode: //AD
record.ISOCode = value;
break;
case ToyotaFieldOrder.ISODescription: //AE
record.ISODescription = value;
break;
case ToyotaFieldOrder.ISOPolarity: //AF
record.ISOPolarity = value;
break;
case ToyotaFieldOrder.KyowaSpecificField_1: //AG
// http://fogbugz/fogbugz/default.asp?5433
break;
default:
throw new NotSupportedException(
"ImportTestSetup::ProcessToyotaFile unknown field: " + fields[curToken]);
}
#endregion Another very long switch
}
catch (Exception ex)
{
errors.Add($"field {curToken} error {ex.Message} (check input locale)");
bErrored = true;
}
}
if (bErrored) continue;
if (record.IsDigitalInput || record.IsDigitalOutput || record.IsSquib)
{
record.SensorEU = "V"; //What is this for?
record.SensorSerialNumber = record.JCodeOrDescription;
}
// FB12439: TTS Sensors need to be in DB first
if (record.IsSquib || record.IsDigitalInput || record.IsDigitalOutput)
{
//we can use test specific values?
}
else
{
var sd = SensorsCollection.SensorsList.GetSensorBySerialNumber(record.SensorSerialNumber);
if (null == sd)
{
error = string.Format(StringResources.SensorNotFound, record.SensorSerialNumber);
SetStatus(StringResources.ImportTestSetup_PossibleStatus_Failed, error);
return null;
}
else if (sd.IsAnalog() && !IsOldSchoolFile(fields))
{
//18396 TTS import has too many columns and it makes confusion
//these fields now come exclusively from the db and not from the import anymore
var latestCal = SensorCalibrationList.GetLatestCalibrationBySerialNumber(sd);
if (null != latestCal)
{
record.SensorSensitivity = latestCal.Records.Records[0].Sensitivity;
}
record.SensorEID = sd.EID;
record.CableMultiplier = 1;
record.SensorCapacity = sd.Capacity;
}
}
record.IsChannelCodeValid = !string.IsNullOrWhiteSpace(record.ChannelCode) &&
record.ChannelCode != TTSChannelRecord.NONE;
records.Add(record);
SetProgress(records.Count / totalLines * 100);
}
}
}
catch (Exception ex)
{
errors.Add(ex.Message);
}
error += string.Join(Environment.NewLine, errors.ToArray());
setup.Channels = records.ToArray();
SetProgress(100);
return setup;
}
private bool DuplicateSensorSerialNumber(string sensorSerialNumber, List<ITTSChannelRecord> records)
{
return records.Exists(record => record.SensorSerialNumber == sensorSerialNumber);
}
private bool DuplicateChannelCode(string channelCode, List<ITTSChannelRecord> records)
{
return records.Exists(record => record.ChannelCode == channelCode);
}
private bool DuplicateJCode(string jcode, List<ITTSChannelRecord> records)
{
return false;
}
private bool DuplicateDescription(string description, List<ITTSChannelRecord> records)
{
return records.Exists(record => record.Description == description);
}
/// <summary>
/// ProcessToyotaXMLFile
/// 14698 Cannot import XML file generated from TTS and auto advance to "Hardware Scan" nav step
/// once the xml file has been read we can manipulate the TTSSetup and TTSChannelRecords to
/// create the information needed as if we had read a CSV to start
/// </summary>
/// <param name="arg"></param>
public void ProcessToyotaXMLFile(TTSImportReadXMLFileResponseEventArg arg)
{
var records = new List<ITTSChannelRecord>();
var preAssignedChannels = new List<Tuple<string, string>>();
//process the channels from xml and create tts records
var channels = arg.TestSetup.GetChannels();
foreach (var ch in channels)
{
if (ch.IsBlank() || ch.IsDisabled) { continue; }
var newCh = new TTSChannelRecord();
if (ch.SensorValid)
{
//not sure why this is done, but it was being done in ProcessSensor previously, so I preserved it...
ch.SensorData.UUID = ch.SensorData.SerialNumber;
//declare a newchannel using the sensor data, this will set a bunch of channel properties using the sensor ...
newCh = new TTSChannelRecord((SensorData)ch.SensorData);
//now some properties are not set using the sensor in 2.4 and 2.5, so we have to set those explicitly
//those properties will come from the channel or channel settings
newCh.ISOCode = ch.IsoCode;
newCh.ISODescription = ch.IsoChannelName;
newCh.ChannelCode = ch.UserCode;
newCh.Description = ch.UserChannelName;
//in modern channel settings these properties are explicit to the sensor type (digital out,squib)
//but are common in older xml and in tts channel records ...
var limit = false;
var delay = double.NaN;
var duration = double.NaN;
foreach (var setting in ch.ChannelSettings)
{
switch (setting.SettingName)
{
case ChannelSettingBase.ACTIVE_VALUE:
case ChannelSettingBase.DEFAULT_VALUE:
//ignore?
break;
case ChannelSettingBase.DIMODE:
newCh.DigitalInputMode = (DigitalInputModes)setting.IntValue;
break;
case ChannelSettingBase.CFC:
ch.SensorData.FilterClassIso = setting.Value;
break;
case ChannelSettingBase.POLARITY:
newCh.SensorPolarity = setting.Value == "+";
break;
case ChannelSettingBase.RANGE:
newCh.ChannelRange = setting.DoubleValue;
break;
case ChannelSettingBase.DIGITALOUT_DELAY:
newCh.DigitalOutputDelay = setting.DoubleValue;
break;
case ChannelSettingBase.DIGITALOUT_DURATION:
newCh.DigitalOutputDuration = setting.DoubleValue;
break;
case ChannelSettingBase.DIGITALOUT_LIMIT_DURATION:
if (setting.BoolValue) { limit = true; }
break;
case ChannelSettingBase.OUTPUT_MODE:
newCh.DigitalOutputMode = (DigitalOutputModes)setting.IntValue;
break;
case ChannelSettingBase.SQUIB_DELAY:
newCh.SquibFireDelayMs = setting.DoubleValue;
break;
case ChannelSettingBase.SQUIB_DURATION:
newCh.SquibFireDurationMs = setting.DoubleValue;
break;
case ChannelSettingBase.SQUIB_LIMIT_DURATION:
if (setting.BoolValue) { limit = true; }
break;
case ChannelSettingBase.SQMODE:
newCh.SquibFireMode = (SquibFireMode)setting.IntValue;
break;
case ChannelSettingBase.SQUIB_CURRENT:
newCh.SquibFireCurrent = setting.DoubleValue;
break;
case ChannelSettingBase.POSITION: break; //ignore, this should be stored in ISOCode
case ChannelSettingBase.ZEROMETHOD:
var zmType = (DTS.Common.Enums.Sensors.ZeroMethodType)Enum.Parse(typeof(DTS.Common.Enums.Sensors.ZeroMethodType), setting.Value);
switch (zmType)
{
case DTS.Common.Enums.Sensors.ZeroMethodType.AverageOverTime:
newCh.ZeroMethod = ToyotaZeroMethods.AverageOverTime;
break;
case DTS.Common.Enums.Sensors.ZeroMethodType.UsePreEventDiagnosticsZero:
newCh.ZeroMethod = ToyotaZeroMethods.UsePreEventDiagnosticsZero;
break;
case DTS.Common.Enums.Sensors.ZeroMethodType.None:
newCh.ZeroMethod = ToyotaZeroMethods.None;
break;
}
break;
case ChannelSettingBase.ZEROMETHODSTART:
case ChannelSettingBase.ZEROMETHODEND:
case ChannelSettingBase.USERVALUE1:
case ChannelSettingBase.USERVALUE3:
case ChannelSettingBase.INITIAL_OFFSET:
break;
case ChannelSettingBase.USERVALUE2:
newCh.CableMultiplier = setting.DoubleValue;
break;
case "LimitDuration": //deprecated, only needed for migrating to current version xml?
limit = setting.BoolValue;
break;
case "Delay": //deprecated, only needed for migrating to current version xml?
delay = setting.DoubleValue;
break;
case "Duration": //deprecated, only needed for migrating to current version xml?
duration = setting.DoubleValue;
break;
case ChannelSettingBase.FilterClass:
break;
default: throw new NotImplementedException("unknown setting: " + setting.SettingName);
}
}
newCh.LimitDuration = limit;
if (!double.IsNaN(delay))
{
newCh.DigitalOutputDelay = delay;
newCh.SquibFireDelayMs = delay;
}
if (!double.IsNaN(duration))
{
newCh.DigitalOutputDuration = duration;
newCh.SquibFireDurationMs = duration;
}
if (ch.HardwareValid)
{
preAssignedChannels.Add(new Tuple<string, string>(ch.SensorData.SerialNumber,
ch.HardwareChannel.GetId()));
}
records.Add(newCh);
}
}
var recordLookup = records.ToDictionary(r => r.SensorSerialNumber);
arg.TTSSetup.PreAssignedSensorIdAndHwId = preAssignedChannels.ToArray();
arg.TTSSetup.Channels = records.ToArray();
//finally process level triggers, now TTS has a set number of level triggers, which are all empty by default
//we want to just set those level triggers properly if we have a level trigger from xml
if (arg.LevelTriggers.Any())
{
for (var i = 0; i < arg.LevelTriggers.Length && i < arg.TTSSetup.LevelTriggers.Length; i++)
{
var ltXml = arg.LevelTriggers[i];
var ltSetup = arg.TTSSetup.LevelTriggers[i];
if (!recordLookup.ContainsKey(ltXml.SensorSerialNumber))
{
continue;
}
ltSetup.Channel = recordLookup[ltXml.SensorSerialNumber];
ltSetup.ValueEU = ltXml.Threshold;
}
}
}
#endregion
private double _defaultSampleRate;
private RecordingModes _defaultRecordingMode;
private double _defaultTTSPreTrigger;
private double _defaultTTSPostTrigger;
private double _defaultTTSROIStart;
private double _defaultTTSROIEnd;
private ISquibSettingDefaults _squibDefaults;
public bool _defaultRequireEIDsFound;
public string _defaultDigitalInputMode;
public bool IsDirty { get; private set; }
private bool _isBusy = false;
public bool IsBusy
{
get => _isBusy;
set
{
_isBusy = value;
OnPropertyChanged("IsBusy");
}
}
private bool _isMenuIncluded = false;
public bool IsMenuIncluded
{
get => _isMenuIncluded;
set
{
_isMenuIncluded = value;
OnPropertyChanged("IsMenuIncluded");
}
}
private bool _isNavigationIncluded = false;
public bool IsNavigationIncluded
{
get => _isNavigationIncluded;
set
{
_isNavigationIncluded = value;
OnPropertyChanged("IsNavigationIncluded");
}
}
#region properties
/// <summary>
/// all properties that are exposed
/// </summary>
public enum PropertyNames
{
ImportFileName
}
private string _importFileName = "";
/// <summary>
/// full path to import file
/// </summary>
public string ImportFileName
{
get => _importFileName;
set
{
_importFileName = value;
OnPropertyChanged(PropertyNames.ImportFileName.ToString());
}
}
#endregion
///<summary>
///Occurs when a property value changes.
///</summary>
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}