862 lines
38 KiB
C#
862 lines
38 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
using System.ComponentModel.Composition;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Data;
|
|
using DTS.Common.Events;
|
|
using DTS.Common.Interface.TestSetups.Imports.TTS;
|
|
using DTS.Common.Interface.TestSetups.Imports.TTS.ReadFile;
|
|
using Prism.Events;
|
|
using Unity;
|
|
using DTS.Common.Interactivity;
|
|
using Prism.Regions;
|
|
using Prism.Commands;
|
|
using TTSImport.Model;
|
|
using TTSImport.Resources;
|
|
using Application = System.Windows.Application;
|
|
|
|
namespace TTSImport
|
|
{
|
|
/// <summary>
|
|
/// this class handles Level Trigger edit/create functionality
|
|
/// </summary>
|
|
[PartCreationPolicy(CreationPolicy.Shared)]
|
|
public class EditFileViewModel : IEditFileViewModel
|
|
{
|
|
/// <summary>
|
|
/// The Hardware Scan view
|
|
/// </summary>
|
|
public IEditFileView View { get; set; }
|
|
private const string DOUBLEUPTO15 = "0.###############"; //Write up to 15 decimal places to .csv
|
|
private const string STRINGWRITEFORMAT_CHANNELRANGE = DOUBLEUPTO15;
|
|
private const string STRINGWRITEFORMAT_SENSITIVITY = DOUBLEUPTO15;
|
|
private const string STRINGWRITEFORMAT_CAPACITY = DOUBLEUPTO15;
|
|
|
|
private IEventAggregator _eventAggregator { get; }
|
|
private IRegionManager _regionManager;
|
|
private IUnityContainer UnityContainer { get; }
|
|
|
|
public InteractionRequest<Notification> NotificationRequest { get; }
|
|
public InteractionRequest<Confirmation> ConfirmationRequest { get; }
|
|
|
|
///<summary>
|
|
///Occurs when a property value changes.
|
|
///</summary>
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
public void OnPropertyChanged(string propertyName)
|
|
{
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
switch (propertyName)
|
|
{
|
|
case "TestName":
|
|
ChangeValidationIsNeeded = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#region constructors and initializers
|
|
/// <summary>
|
|
/// Creates a new instance of the TechnologyDomainEditViewModel.
|
|
/// </summary>
|
|
/// <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 EditFileViewModel(EditFileView 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<TTSImportReadFileStatusEvent>().Subscribe(OnReadFileFinished, ThreadOption.PublisherThread, true);
|
|
}
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
/// <summary>
|
|
/// filters the available sensors from the db by the given text
|
|
/// we keep two lists, allchannels and SystemSensors
|
|
/// SystemSensors only holds those that aren't in use and are
|
|
/// available
|
|
/// </summary>
|
|
/// <param name="text"></param>
|
|
public void Search(string text)
|
|
{
|
|
SystemSensors.Clear();
|
|
//build a list of sensors already used to exclude those sensors
|
|
var hash = new HashSet<string>();
|
|
foreach (var ch in RequiredChannels)
|
|
{
|
|
hash.Add(ch.SensorSerialNumber);
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(text))
|
|
{
|
|
//nothing to sort
|
|
foreach (var s in _allChannels)
|
|
{
|
|
if (!hash.Contains(s.SensorSerialNumber))
|
|
{
|
|
SystemSensors.Add(s);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
text = text.ToLower();
|
|
foreach (var s in _allChannels)
|
|
{
|
|
if (s.SensorSerialNumber.ToLower().Contains(text))
|
|
{
|
|
if (!hash.Contains(s.SensorSerialNumber))
|
|
{
|
|
SystemSensors.Add(s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
private void OnReadFileFinished(ReadFileStatusArg statusArg)
|
|
{
|
|
if (!Application.Current.Dispatcher.CheckAccess())
|
|
{
|
|
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
|
{
|
|
OnReadFileFinished(statusArg);
|
|
}));
|
|
return;
|
|
}
|
|
if (!statusArg.Status) return;
|
|
_setup = statusArg.TTSSetup;
|
|
}
|
|
|
|
public void InitializeView()
|
|
{
|
|
if (_setup == null) return;
|
|
|
|
//turn off Change Validation and remove old channels/sensors, if any
|
|
ChangeValidationIsNeeded = false;
|
|
RequiredChannels.Clear();
|
|
SystemSensors.Clear();
|
|
//will turn Change Validation back on
|
|
TestName = _setup.TestId;
|
|
SaveFileEnabled = false;
|
|
|
|
var requiredChannels = new ObservableCollection<ITTSChannelRecord>();
|
|
_allChannels.Clear();
|
|
|
|
foreach (var channelRecord in _setup.Channels)
|
|
{
|
|
if (channelRecord.IsDigitalOutput) { continue; }
|
|
if (channelRecord.ChannelCode != TTSChannelRecord.NONE)
|
|
{
|
|
//isn't a "reserved sensor"
|
|
var requiredChannel = channelRecord.Copy();
|
|
requiredChannel.Parent = this;
|
|
requiredChannels.Add(requiredChannel);
|
|
}
|
|
}
|
|
foreach (var sensor in DTS.SensorDB.SensorsCollection.SensorsList.GetAllSensors(false))
|
|
{
|
|
if (sensor.IsDigitalOutput()) { continue; }
|
|
if (sensor.IsTestSpecificSquib) { continue; }
|
|
if (sensor.IsTestSpecificDigitalIn) { continue; }
|
|
_allChannels.Add(new TTSChannelRecord(sensor) { Parent = this });
|
|
}
|
|
RequiredChannels = requiredChannels;
|
|
Search(_searchText);
|
|
ValidateChannelCodes();
|
|
ValidateJCodes();
|
|
_originalHash = GenerateHash();
|
|
NumChannelsAndSensors = string.Format(StringResources.NumChannelsAndSensors, RequiredChannels.Count, SystemSensors.Count);
|
|
SaveFileEnabled = false;
|
|
}
|
|
|
|
private string GenerateHash()
|
|
{
|
|
var bytes = new List<byte>();
|
|
foreach (var rc in RequiredChannels)
|
|
{
|
|
bytes.AddRange(rc.GetBytes());
|
|
}
|
|
foreach (var rs in SystemSensors)
|
|
{
|
|
bytes.AddRange(rs.GetBytes());
|
|
}
|
|
|
|
var sha = new SHA256Managed();
|
|
var hash = sha.ComputeHash(bytes.ToArray());
|
|
return BitConverter.ToString(hash).Replace("-", string.Empty);
|
|
}
|
|
public void Cleanup()
|
|
{
|
|
}
|
|
|
|
public Task CleanupAsync()
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
}
|
|
|
|
public void Initialize(object parameter)
|
|
{
|
|
}
|
|
|
|
public void Initialize(object parameter, object model)
|
|
{
|
|
}
|
|
|
|
public Task InitializeAsync()
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task InitializeAsync(object parameter)
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public void Activated()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Private Event handler for RaiseNotification 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
|
|
});
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
/// <summary>
|
|
/// this is the list of all channels, this is a superset while SystemSensors is the subset
|
|
/// this contains some records we don't want
|
|
/// </summary>
|
|
private readonly List<ITTSChannelRecord> _allChannels = new List<ITTSChannelRecord>();
|
|
/// <summary>
|
|
/// this is the current text the user is search for in available channels/sensors
|
|
/// </summary>
|
|
private readonly string _searchText = "";
|
|
private ITTSSetup _setup;
|
|
public bool ChangeValidationIsNeeded { get; set; }
|
|
public bool IsDirty { get; private set; }
|
|
private bool _isBusy;
|
|
|
|
public bool IsBusy
|
|
{
|
|
get => _isBusy;
|
|
set
|
|
{ _isBusy = value; OnPropertyChanged("IsBusy"); }
|
|
}
|
|
|
|
private bool _isMenuIncluded;
|
|
|
|
public bool IsMenuIncluded
|
|
{
|
|
get => _isMenuIncluded;
|
|
set
|
|
{ _isMenuIncluded = value; OnPropertyChanged("IsMenuIncluded"); }
|
|
}
|
|
|
|
private bool _isNavigationIncluded;
|
|
|
|
public bool IsNavigationIncluded
|
|
{
|
|
get => _isNavigationIncluded;
|
|
set
|
|
{ _isNavigationIncluded = value; OnPropertyChanged("IsNavigationIncluded"); }
|
|
}
|
|
|
|
private bool _isTestNameValid;
|
|
public bool IsTestNameValid { get => _isTestNameValid; set { _isTestNameValid = value; OnPropertyChanged("IsTestNameValid"); } }
|
|
|
|
private string _testName = string.Empty;
|
|
public string TestName
|
|
{
|
|
get => _testName;
|
|
set
|
|
{
|
|
_testName = value;
|
|
IsTestNameValid = !string.IsNullOrWhiteSpace(value);
|
|
OnPropertyChanged("TestName");
|
|
}
|
|
}
|
|
private DelegateCommand<string> _testNameLostFocus;
|
|
public DelegateCommand<string> TestNameLostFocus => _testNameLostFocus ?? (_testNameLostFocus = new DelegateCommand<string>(TestNameLostFocusMethod));
|
|
public void TestNameLostFocusMethod(string code)
|
|
{
|
|
if (!ChangeValidationIsNeeded) return;
|
|
ValidateChange();
|
|
}
|
|
private bool _saveFileEnabled;
|
|
public bool SaveFileEnabled
|
|
{
|
|
get => _saveFileEnabled;
|
|
set
|
|
{
|
|
_saveFileEnabled = value;
|
|
OnPropertyChanged("SaveFileEnabled");
|
|
|
|
EnableOrDisableButtons();
|
|
}
|
|
}
|
|
|
|
private string _numChannelsAndSensors = string.Empty;
|
|
public string NumChannelsAndSensors
|
|
{
|
|
get => _numChannelsAndSensors;
|
|
set { _numChannelsAndSensors = value; OnPropertyChanged("NumChannelsAndSensors"); }
|
|
}
|
|
|
|
private bool _replaceEnabled;
|
|
public bool ReplaceEnabled
|
|
{
|
|
get => _replaceEnabled;
|
|
set { _replaceEnabled = value; OnPropertyChanged("ReplaceEnabled"); }
|
|
}
|
|
|
|
private bool _addCodeEnabled;
|
|
public bool AddCodeEnabled
|
|
{
|
|
get => _addCodeEnabled;
|
|
set { _addCodeEnabled = value; OnPropertyChanged("AddCodeEnabled"); }
|
|
}
|
|
|
|
private bool _deleteCodeEnabled;
|
|
public bool DeleteCodeEnabled
|
|
{
|
|
get => _deleteCodeEnabled;
|
|
set { _deleteCodeEnabled = value; OnPropertyChanged("DeleteCodeEnabled"); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// stores a hash representing the state of channels at the time they were read in
|
|
/// this is used to determine if any changes of significance were made in edit file
|
|
/// </summary>
|
|
private string _originalHash;
|
|
|
|
private ObservableCollection<ITTSChannelRecord> _requiredChannels = new ObservableCollection<ITTSChannelRecord>();
|
|
public ObservableCollection<ITTSChannelRecord> RequiredChannels
|
|
{
|
|
get => _requiredChannels;
|
|
set
|
|
{ _requiredChannels = value; OnPropertyChanged("RequiredChannels"); }
|
|
}
|
|
private ObservableCollection<ITTSChannelRecord> _systemSensors = new ObservableCollection<ITTSChannelRecord>();
|
|
public ObservableCollection<ITTSChannelRecord> SystemSensors
|
|
{
|
|
get => _systemSensors;
|
|
set
|
|
{ _systemSensors = value; OnPropertyChanged("SystemSensors"); }
|
|
}
|
|
|
|
private ITTSChannelRecord _selectedRequiredChannel;
|
|
public ITTSChannelRecord SelectedRequiredChannel
|
|
{
|
|
get => _selectedRequiredChannel;
|
|
set
|
|
{
|
|
_selectedRequiredChannel = value; OnPropertyChanged("SelectedRequiredChannel");
|
|
|
|
EnableOrDisableButtons();
|
|
}
|
|
}
|
|
|
|
private ITTSChannelRecord _selectedSystemSensor;
|
|
public ITTSChannelRecord SelectedSystemSensor
|
|
{
|
|
get => _selectedSystemSensor;
|
|
set
|
|
{
|
|
_selectedSystemSensor = value;
|
|
OnPropertyChanged("SelectedSystemSensor");
|
|
EnableOrDisableButtons();
|
|
}
|
|
}
|
|
|
|
private void EnableOrDisableButtons()
|
|
{
|
|
if (null == _selectedRequiredChannel || null == _selectedSystemSensor) { ReplaceEnabled = false; }
|
|
else if (_selectedRequiredChannel.IsDigitalInput)
|
|
{
|
|
ReplaceEnabled = _selectedSystemSensor.IsDigitalInput;
|
|
}
|
|
else if (_selectedRequiredChannel.IsDigitalOutput)
|
|
{
|
|
ReplaceEnabled = _selectedSystemSensor.IsDigitalOutput;
|
|
}
|
|
else if (_selectedRequiredChannel.IsSquib)
|
|
{
|
|
ReplaceEnabled = _selectedSystemSensor.IsSquib;
|
|
}
|
|
else
|
|
{
|
|
ReplaceEnabled = !(_selectedSystemSensor.IsSquib
|
|
|| _selectedSystemSensor.IsDigitalInput ||
|
|
_selectedSystemSensor.IsDigitalOutput);
|
|
}
|
|
|
|
|
|
AddCodeEnabled = _selectedSystemSensor != null;
|
|
DeleteCodeEnabled = _selectedRequiredChannel != null;
|
|
}
|
|
#endregion Properties
|
|
|
|
#region Commands
|
|
/// <summary>
|
|
/// Browse to import file
|
|
/// </summary>
|
|
private DelegateCommand _saveFileClicked;
|
|
public DelegateCommand SaveFileClicked => _saveFileClicked ?? (_saveFileClicked = new DelegateCommand(SaveFileMethod));
|
|
public void SaveFileMethod()
|
|
{
|
|
using (var sfd = new System.Windows.Forms.SaveFileDialog())
|
|
{
|
|
var fullFilePath = Path.GetFullPath(_setup.OriginalImportFile);
|
|
sfd.Filter = @"TTS import (*.csv)|*.csv";
|
|
sfd.RestoreDirectory = true;
|
|
sfd.FilterIndex = 0;
|
|
var fi = new FileInfo(fullFilePath);
|
|
|
|
sfd.FileName = fi.Name;
|
|
|
|
if (fi.DirectoryName != null) sfd.InitialDirectory = Path.GetFullPath(fi.DirectoryName);
|
|
var result = sfd.ShowDialog();
|
|
if (result != System.Windows.Forms.DialogResult.OK) return;
|
|
fullFilePath = sfd.FileName;
|
|
|
|
var csv = new StringBuilder();
|
|
|
|
var newRow = _setup.Line1;
|
|
csv.Append(newRow + Environment.NewLine);
|
|
|
|
newRow = _setup.Line2;
|
|
_setup.TestId = TestName;
|
|
if (_setup.Line2 != null)
|
|
{
|
|
var fields = _setup.Line2.Split(',');
|
|
var newLine2 = fields.Where((t, index) => index > 0).Aggregate(_setup.TestId, (current, t) => current + "," + t);
|
|
newRow = newLine2;
|
|
}
|
|
csv.Append(newRow + Environment.NewLine);
|
|
|
|
newRow = _setup.Line3;
|
|
csv.Append(newRow + Environment.NewLine);
|
|
|
|
newRow = _setup.Line4;
|
|
csv.Append(newRow + Environment.NewLine);
|
|
|
|
//Order the required channels first
|
|
var channelList = RequiredChannels.ToList();
|
|
|
|
_setup.Channels = channelList.ToArray();
|
|
|
|
foreach (var channel in _setup.Channels)
|
|
{
|
|
var channelNumber = channel.ChannelNumber.ToString();
|
|
var channelCode = channel.ChannelCode;
|
|
var channelRange = channel.IsSquib ? channel.SquibFireDelayMs.ToString(STRINGWRITEFORMAT_CHANNELRANGE) : channel.ChannelRange.ToString(STRINGWRITEFORMAT_CHANNELRANGE); //Write up to 15 decimal places to .csv
|
|
var channelFilter = channel.IsSquib ? channel.SquibFireDurationMs.ToString(STRINGWRITEFORMAT_CHANNELRANGE) : channel.ChannelFilterHz.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
|
if (channel.ChannelCode == TTSChannelRecord.NONE)
|
|
{
|
|
//Blank the following fields from reserved sensors
|
|
channelNumber = "";
|
|
channelCode = "";
|
|
channelRange = "";
|
|
channelFilter = "";
|
|
}
|
|
|
|
var sensorSensitivity = channel.SensorSensitivity.ToString(STRINGWRITEFORMAT_SENSITIVITY); //Write up to 15 decimal places to .csv
|
|
var sensorExcitationVolts = channel.SensorExcitationVolts.ToString("0.#");
|
|
var sensorCapacity = channel.SensorCapacity.ToString(STRINGWRITEFORMAT_CAPACITY); //Write up to 15 decimal places to .csv
|
|
var sensorPolarity = channel.SensorPolarity ? "+" : "-";
|
|
|
|
//Only FullBridge and HalfBridge contain a space
|
|
string channelType;
|
|
switch (channel.ChannelType)
|
|
{
|
|
case DTS.Common.Enums.TTS.ToyotaBridgeType.FullBridge:
|
|
channelType = "Full Bridge";
|
|
break;
|
|
case DTS.Common.Enums.TTS.ToyotaBridgeType.HalfBridge:
|
|
channelType = "Half Bridge";
|
|
break;
|
|
default:
|
|
channelType = channel.ChannelType.ToString();
|
|
break;
|
|
}
|
|
|
|
var proportionalToExcitation = channel.ProportionalToExcitation ? "mv/V/EU" : "";
|
|
var bridgeResistance = channel.BridgeResistance.ToString("0.#");
|
|
var initialOffsetVoltage = channel.InitialOffsetVoltage.ToString("0.#");
|
|
var initialOffsetVoltageTolerance = channel.InitialOffsetVoltageTolerance.ToString("0.#");
|
|
var removeOffset = channel.RemoveOffset ? "1" : "0";
|
|
var zeroMethod = ((int)channel.ZeroMethod).ToString();
|
|
var initialEUInMv = double.IsNaN(channel.InitialEUInMV) ? "" : channel.InitialEUInMV.ToString("0.##");
|
|
var initialEUInEU = double.IsNaN(channel.InitialEUInEU) ? "" : channel.InitialEUInEU.ToString("0.##");
|
|
var iRTraccExponent = double.IsNaN(channel.IRTraccExponent) ? "" : channel.IRTraccExponent.ToString("0.##");
|
|
var polynomialConstant = double.IsNaN(channel.PolynomialConstant) ? "" : channel.PolynomialConstant.ToString("0.##");
|
|
var polynomialCoefficientC = double.IsNaN(channel.PolynomialCoefficientC) ? "" : channel.PolynomialCoefficientC.ToString("0.##");
|
|
var polynomialCoefficentB = double.IsNaN(channel.PolynomialCoefficentB) ? "" : channel.PolynomialCoefficentB.ToString("0.##");
|
|
var polynomialCoefficientA = double.IsNaN(channel.PolynomialCoefficientA) ? "" : channel.PolynomialCoefficientA.ToString("0.##");
|
|
var polynomialCoefficientAlpha = double.IsNaN(channel.PolynomialCoefficientAlpha) ? "" : channel.PolynomialCoefficientAlpha.ToString("0.##");
|
|
var diagnosticsMode = channel.DiagnosticsMode ? TTSChannelRecord.DIAGNOSTICSMODE : "";
|
|
|
|
if (channel.IsDigitalInput)
|
|
{
|
|
channelRange = string.Empty;
|
|
channelFilter = string.Empty;
|
|
}
|
|
|
|
if (channel.IsDigitalOutput)
|
|
{
|
|
//14708 Squib appears to be unassigned when using edit file during TTS import
|
|
//I changed this to be consistent with the reader, which only reads the first 3
|
|
//fields for digital outputs
|
|
newRow = $"{channelNumber},{channelCode},{channel.JCodeOrDescription}{Environment.NewLine}";
|
|
}
|
|
|
|
if (channel.IsDigitalInput || channel.IsSquib)
|
|
{
|
|
//14708 Squib appears to be unassigned when using edit file during TTS import
|
|
//don't wipe out EID or serial number, these are valid fields for these sensors
|
|
//isocode and description should be valid too? as well as channel description?
|
|
//note that the import reads up to the serial number, so no point it writing more
|
|
newRow =
|
|
$"{channelNumber},{channelCode},{channel.JCodeOrDescription},{channelRange},{channelFilter},{channel.SensorEID},{channel.SensorSerialNumber}{Environment.NewLine}";
|
|
}
|
|
else
|
|
{
|
|
newRow = $"{channelNumber},{channelCode},{channel.JCodeOrDescription},{channelRange},{channelFilter},{channel.SensorEID},{channel.SensorSerialNumber},{sensorSensitivity},{sensorExcitationVolts},{sensorCapacity},{channel.SensorEU}," +
|
|
$"{sensorPolarity},{channelType},{channel.Description},{proportionalToExcitation},{bridgeResistance},{initialOffsetVoltage},{initialOffsetVoltageTolerance},{removeOffset},{zeroMethod},{channel.CableMultiplier.ToString(System.Globalization.CultureInfo.InvariantCulture)}," +
|
|
$"{initialEUInMv},{initialEUInEU},{iRTraccExponent},{polynomialConstant},{polynomialCoefficientC},{polynomialCoefficentB},{polynomialCoefficientA},{polynomialCoefficientAlpha},{channel.ISOCode},{channel.ISODescription},{channel.ISOPolarity},{diagnosticsMode}{Environment.NewLine}";
|
|
}
|
|
|
|
csv.Append(newRow);
|
|
}
|
|
|
|
File.WriteAllText(fullFilePath, csv.ToString(), Encoding.GetEncoding("Shift-JIS"));
|
|
_setup.OriginalImportFile = fullFilePath;
|
|
}
|
|
SaveFileEnabled = false;
|
|
//Enable future nav steps since changes have been saved
|
|
_eventAggregator.GetEvent<TTSImportSavedChangesStatusEvent>().Publish(true);
|
|
_originalHash = GenerateHash();
|
|
}
|
|
|
|
|
|
#region Replace
|
|
/// <summary>
|
|
/// Swap the assignments of a Required Channel and a Reserved Sensor
|
|
/// </summary>
|
|
private DelegateCommand _replaceCommand;
|
|
public DelegateCommand ReplaceCommand => _replaceCommand ?? (_replaceCommand = new DelegateCommand(Replace));
|
|
private void Replace()
|
|
{
|
|
//11574 replace button removed JCode and range and filter from an "add code" channel in edit file
|
|
//we preserve the original channel settings when doing replace
|
|
//Initialize a Reserved Sensor that's about to become a Required Channel
|
|
SelectedSystemSensor.ChannelNumber = SelectedRequiredChannel.ChannelNumber;
|
|
SelectedSystemSensor.ChannelCode = SelectedRequiredChannel.ChannelCode;
|
|
SelectedRequiredChannel.ChannelCode = TTSChannelRecord.NONE;
|
|
SelectedSystemSensor.JCodeOrDescription = SelectedRequiredChannel.JCodeOrDescription;
|
|
SelectedSystemSensor.ChannelRange = SelectedRequiredChannel.ChannelRange;
|
|
SelectedSystemSensor.ChannelFilterHz = SelectedRequiredChannel.ChannelFilterHz;
|
|
|
|
// Save off the channels that are about to be removed from their old lists
|
|
var savedSelectedSystemSensor = SelectedSystemSensor;
|
|
var savedSelectedRequiredChannel = SelectedRequiredChannel;
|
|
|
|
//Save the indices of the channels that are about to be removed from their old lists
|
|
var selectedRequiredChannelIndex = RequiredChannels.IndexOf(SelectedRequiredChannel);
|
|
var selectedSystemSensorIndex = SystemSensors.IndexOf(SelectedSystemSensor);
|
|
|
|
//Remove the channels from their old lists
|
|
RequiredChannels.Remove(SelectedRequiredChannel);
|
|
SystemSensors.Remove(SelectedSystemSensor);
|
|
|
|
//Insert the saved channels into their new lists
|
|
RequiredChannels.Insert(selectedRequiredChannelIndex, savedSelectedSystemSensor);
|
|
SystemSensors.Insert(selectedSystemSensorIndex, savedSelectedRequiredChannel);
|
|
|
|
//Re-select the same rows in the tables
|
|
SelectedRequiredChannel = RequiredChannels[selectedRequiredChannelIndex];
|
|
SelectedSystemSensor = SystemSensors[selectedSystemSensorIndex];
|
|
|
|
UpdateAndValidate();
|
|
}
|
|
#endregion Replace
|
|
|
|
#region Add Code
|
|
private DelegateCommand _addCodeCommand;
|
|
public DelegateCommand AddCodeCommand => _addCodeCommand ?? (_addCodeCommand = new DelegateCommand(AddCode));
|
|
/// <summary>
|
|
/// remove a hardware channel assignment(does not remove the channel from the test setup though?)
|
|
/// </summary>
|
|
private void AddCode()
|
|
{
|
|
AddSystemSensor();
|
|
UpdateAndValidate();
|
|
}
|
|
|
|
private void AddSystemSensor()
|
|
{
|
|
var maxChannelNumber = RequiredChannels.Select(requiredChannel => requiredChannel.ChannelNumber).Concat(new[] { 0 }).Max();
|
|
SelectedSystemSensor.ChannelNumber = maxChannelNumber + 1;
|
|
SelectedSystemSensor.ChannelCode = string.Empty;
|
|
SelectedSystemSensor.JCodeOrDescription = string.Empty;
|
|
SelectedSystemSensor.ChannelRange = 0;
|
|
SelectedSystemSensor.ChannelFilterHz = -1;
|
|
RequiredChannels.Add(SelectedSystemSensor);
|
|
|
|
var selectedSystemSensorIndex = SystemSensors.IndexOf(SelectedSystemSensor);
|
|
SystemSensors.Remove(SelectedSystemSensor);
|
|
if (SystemSensors.Count > 0)
|
|
{
|
|
//If removing from the end of the list, set the previous record to Selected, otherwise set next record to Selected
|
|
SelectedSystemSensor = selectedSystemSensorIndex == SystemSensors.Count ? SystemSensors[selectedSystemSensorIndex - 1] : SystemSensors[selectedSystemSensorIndex];
|
|
}
|
|
}
|
|
#endregion Add Code
|
|
|
|
private DelegateCommand _addSquibCommand;
|
|
|
|
public DelegateCommand AddSquibCommand =>
|
|
_addSquibCommand ?? (_addSquibCommand = new DelegateCommand(AddSquib));
|
|
private void AddSquib()
|
|
{
|
|
var maxChannelNumber = RequiredChannels.Select(requiredChannel => requiredChannel.ChannelNumber).Concat(new[] { 0 }).Max();
|
|
var channelRecord = new TTSChannelRecord();
|
|
channelRecord.ChannelNumber = ++maxChannelNumber;
|
|
channelRecord.IsSquib = true;
|
|
int maxSquibNumber = 0;
|
|
foreach (var rc in RequiredChannels)
|
|
{
|
|
if (!rc.IsSquib) continue;
|
|
var channelCode = rc.ChannelCode.Replace("TF", "").Replace("SQ", "");
|
|
if (int.TryParse(channelCode, out var temp))
|
|
{
|
|
maxSquibNumber = Math.Max(temp, maxSquibNumber);
|
|
}
|
|
}
|
|
maxSquibNumber++;
|
|
channelRecord.ChannelCode = $"SQ{maxSquibNumber}";
|
|
channelRecord.JCodeOrDescription = string.Empty;
|
|
channelRecord.LimitDuration = true;
|
|
channelRecord.ChannelRange = (int)channelRecord.SquibFireDelayMs;
|
|
channelRecord.SquibFireDurationMs = _setup.DefaultSquibFireDurationMs;
|
|
channelRecord.ChannelFilterHz = (int)channelRecord.SquibFireDurationMs; //-1;
|
|
channelRecord.Parent = this;
|
|
RequiredChannels.Add(channelRecord);
|
|
Validate();
|
|
}
|
|
|
|
private DelegateCommand _addDICommand;
|
|
|
|
public DelegateCommand ADDDICommand =>
|
|
_addDICommand ?? (_addDICommand = new DelegateCommand(AddDI));
|
|
|
|
private void AddDI()
|
|
{
|
|
var maxChannelNumber = RequiredChannels.Select(requiredChannel => requiredChannel.ChannelNumber).Concat(new[] { 0 }).Max();
|
|
var channelRecord = new TTSChannelRecord();
|
|
channelRecord.ChannelNumber = ++maxChannelNumber;
|
|
channelRecord.IsDigitalInput = true;
|
|
int maxDINumber = 0;
|
|
foreach (var rc in RequiredChannels)
|
|
{
|
|
if (!rc.IsDigitalInput) continue;
|
|
var channelCode = rc.ChannelCode.Replace("DI", "");
|
|
if (int.TryParse(channelCode, out var temp))
|
|
{
|
|
maxDINumber = Math.Max(temp, maxDINumber);
|
|
}
|
|
}
|
|
maxDINumber++;
|
|
channelRecord.ChannelCode = $"DI{maxDINumber}";
|
|
channelRecord.JCodeOrDescription = string.Empty;
|
|
channelRecord.ChannelFilterHz = -1;
|
|
channelRecord.Parent = this;
|
|
channelRecord.IsChannelCodeValid = true;
|
|
RequiredChannels.Add(channelRecord);
|
|
}
|
|
|
|
#region Delete Code
|
|
private DelegateCommand _deleteCodeCommand;
|
|
public DelegateCommand DeleteCodeCommand =>
|
|
_deleteCodeCommand ?? (_deleteCodeCommand = new DelegateCommand(DeleteCode));
|
|
/// <summary>
|
|
/// enables or disables a channel in the test.
|
|
/// </summary>
|
|
private void DeleteCode()
|
|
{
|
|
DeleteRequiredChannel();
|
|
UpdateAndValidate();
|
|
}
|
|
|
|
private void DeleteRequiredChannel()
|
|
{
|
|
if (null == SelectedRequiredChannel) { return; }
|
|
SelectedRequiredChannel.ChannelCode = TTSChannelRecord.NONE; //So that when it's saved, these fields will be set to empty strings, but if it's re-Added, force user to enter a value.
|
|
SelectedRequiredChannel.JCodeOrDescription = string.Empty; //In case it's re-Added, force user to enter a value.
|
|
SelectedRequiredChannel.ChannelRange = 0; //In case it's re-Added, force user to enter a value.
|
|
SelectedRequiredChannel.ChannelFilterHz = -1; //In case it's re-Added, force user to choose a filter or "None".
|
|
SelectedRequiredChannel.HardwareChannel = null;
|
|
SystemSensors.Add(SelectedRequiredChannel);
|
|
|
|
var selectedRequiredChannelIndex = RequiredChannels.IndexOf(SelectedRequiredChannel);
|
|
RequiredChannels.Remove(SelectedRequiredChannel);
|
|
if (RequiredChannels.Count > 0)
|
|
{
|
|
//Ensure the channels don't have any gaps
|
|
foreach (var channel in RequiredChannels)
|
|
{
|
|
channel.ChannelNumber = RequiredChannels.IndexOf(channel) + 1;
|
|
}
|
|
|
|
//If removing from the end of the list, set the previous record to Selected, otherwise set next record to Selected
|
|
SelectedRequiredChannel = selectedRequiredChannelIndex == RequiredChannels.Count ? RequiredChannels[selectedRequiredChannelIndex - 1] : RequiredChannels[selectedRequiredChannelIndex];
|
|
}
|
|
}
|
|
#endregion Delete Code
|
|
|
|
private void UpdateAndValidate()
|
|
{
|
|
NumChannelsAndSensors = string.Format(StringResources.NumChannelsAndSensors, RequiredChannels.Count, SystemSensors.Count);
|
|
EnableOrDisableButtons();
|
|
ValidateChange();
|
|
CollectionViewSource.GetDefaultView(RequiredChannels)?.Refresh();
|
|
}
|
|
#endregion Commands
|
|
|
|
/// <summary>
|
|
/// Returns True if all fields are valid, False if not
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public bool Validate()
|
|
{
|
|
var duplicates = RequiredChannels.GroupBy(x => x.ChannelCode).Any(g => g.Count() > 1);
|
|
return !duplicates && IsTestNameValid && RequiredChannels.All(x => x.IsChannelCodeValid /*&& x.IsJCodeValid*/ &&
|
|
(x.IsRangeValid || x.RangeVisible != System.Windows.Visibility.Visible) &&
|
|
(x.IsFilterValid || x.FilterVisible != System.Windows.Visibility.Visible));
|
|
}
|
|
|
|
/// <summary>
|
|
/// returns true if there are any changes that have not been saved yet
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private bool HasUnsavedChanges()
|
|
{
|
|
var hash = GenerateHash();
|
|
return hash != _originalHash;
|
|
}
|
|
/// <summary>
|
|
/// If all fields are valid after a change, enables the Save File button and returns True.
|
|
/// If not all fields are valid after a change, disables the Save File button and returns False.
|
|
/// Disables all future nav steps (they will be enabled when the Save File button is clicked).
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public bool ValidateChange(ITTSChannelRecord record = null)
|
|
{
|
|
//Enable the Save File button if everything is valid
|
|
ValidateChannelCodes();
|
|
ValidateJCodes();
|
|
bool bValid = Validate();
|
|
SaveFileEnabled = bValid && HasUnsavedChanges();
|
|
|
|
//Prevent calls to Validate if losing focus on an unchanged control, for example
|
|
ChangeValidationIsNeeded = false;
|
|
|
|
//Disable future nav steps since changes have been made but not saved, or are just or are just invalid
|
|
_eventAggregator.GetEvent<TTSImportSavedChangesStatusEvent>().Publish(!SaveFileEnabled);
|
|
return SaveFileEnabled;
|
|
}
|
|
|
|
private void ValidateChannelCodes()
|
|
{
|
|
var channelCodeToChannel = new Dictionary<string, ITTSChannelRecord>();
|
|
foreach (var channel in RequiredChannels)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(channel.ChannelCode))
|
|
{
|
|
channel.IsChannelCodeValid = false;
|
|
}
|
|
else if (channel.ChannelCode == TTSChannelRecord.NONE)
|
|
{
|
|
channel.IsChannelCodeValid = false;
|
|
}
|
|
else if (channelCodeToChannel.ContainsKey(channel.ChannelCode))
|
|
{
|
|
channelCodeToChannel[channel.ChannelCode].IsChannelCodeValid = false;
|
|
channel.IsChannelCodeValid = false;
|
|
}
|
|
else
|
|
{
|
|
channelCodeToChannel[channel.ChannelCode] = channel;
|
|
channel.IsChannelCodeValid = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ValidateJCodes()
|
|
{
|
|
var channelJCodeToChannel = new Dictionary<string, ITTSChannelRecord>();
|
|
foreach (var channel in RequiredChannels)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(channel.JCodeOrDescription))
|
|
{
|
|
channel.IsJCodeValid = false;
|
|
}
|
|
//else if (channelJCodeToChannel.ContainsKey(channel.JCodeOrDescription))
|
|
//{
|
|
// channelJCodeToChannel[channel.JCodeOrDescription].IsJCodeValid = false;
|
|
// channel.IsJCodeValid = false;
|
|
//}
|
|
else
|
|
{
|
|
channelJCodeToChannel[channel.JCodeOrDescription] = channel;
|
|
channel.IsJCodeValid = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|