This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
using System;
using System.ComponentModel;
using DTS.Common.Interface;
namespace TTSImport.Model
{
public class SummaryChannel : ISummaryChannel
{
private string _channelType = string.Empty;
public string ChannelType { get => _channelType; set { _channelType = value; OnPropertyChanged("ChannelType"); } }
private int _assigned;
public int Assigned { get => _assigned; set { _assigned = value; OnPropertyChanged("Assigned"); } }
private string _unassigned = string.Empty;
public string Unassigned { get => _unassigned; set { _unassigned = value; OnPropertyChanged("Unassigned"); } }
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -0,0 +1,491 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using DTS.Common.Events;
using DTS.Common.Events.TTSImport;
using DTS.Common.Interface.DataRecorders;
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 DTS.DASLib.Service;
// ReSharper disable CheckNamespace
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable InconsistentNaming
namespace TTSImport
{
/// <summary>
/// this class handles Level Trigger edit/create functionality
/// </summary>
[PartCreationPolicy(CreationPolicy.Shared)]
public class TOMChannelsViewModel : ITOMChannelsViewModel
{
/// <summary>
/// The Hardware Scan view
/// </summary>
public ITOMChannelsView View { get; set; }
private IEventAggregator _eventAggregator { get; }
private IRegionManager _regionManager;
private IUnityContainer UnityContainer { get; }
public InteractionRequest<Notification> NotificationRequest { get; }
public InteractionRequest<Confirmation> ConfirmationRequest { get; }
/// <summary>
/// Creates a new instance of the TechnologyDomainEditViewModel.
/// </summary>
/// <param name="view">The ITOMChannelsView.</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 TOMChannelsViewModel(ITOMChannelsView 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<AssignedChannelsChangedEvent>().Subscribe(OnAssignedChannelsChangedEvent,
ThreadOption.PublisherThread, true);
_eventAggregator.GetEvent<TTSImportHardwareScanFinishedEvent>()
.Subscribe(OnHardwareScanComplete, ThreadOption.PublisherThread, true);
_eventAggregator.GetEvent<TTSImportReadFileStatusEvent>().Subscribe(OnReadFileFinished, ThreadOption.PublisherThread, true);
}
#region Methods
private void OnReadFileFinished(ReadFileStatusArg statusArg)
{
_setup = statusArg.TTSSetup;
_hardware = null;
}
private void OnHardwareScanComplete(List<IDASHardware> hardware)
{
_hardware = hardware;
}
private void OnAssignedChannelsChangedEvent(ITTSSetup setup)
{
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
OnAssignedChannelsChangedEvent(setup);
}));
return;
}
_setup = setup;
if (null == _hardware || null == _setup) { return; }
var channels = new ObservableCollection<Model.DASChannel>();
var remainingChannels = new ObservableCollection<ITTSChannelRecord>();
var channelIdToChannel = new Dictionary<string, Model.DASChannel>();
foreach (var das in _hardware)
{
var ichannels = das.GetIHardwareChannels();
for (var i = 0; i < ichannels.Length; i += 2)
{
var ch = ichannels[i];
if (!ch.IsSquib) { continue; }
var newChannel = new Model.DASChannel(ch);
channels.Add(newChannel);
channelIdToChannel[ch.GetId()] = newChannel;
}
}
foreach (var channelRecord in _setup.Channels)
{
if (channelRecord.IsEmptyRecord)
{
continue;
}
if (!channelRecord.IsSquib)
{
continue;
}
if (!channelRecord.IsChannelCodeValid)
{
continue;
}
if (channelRecord.ChannelCode == TTSChannelRecord.NONE)
{
continue;
}
if (null != channelRecord.HardwareChannel)
{
if (channelIdToChannel.ContainsKey(channelRecord.HardwareChannel.GetId()))
{
channelIdToChannel[channelRecord.HardwareChannel.GetId()].SetITTSChannelRecord(channelRecord);
}
}
else
{
remainingChannels.Add(channelRecord);
}
}
DASChannels = channels;
RemainingChannels = remainingChannels;
OnPropertyChanged("DASChannels");
OnPropertyChanged("RemainingChannels");
}
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
private ITTSSetup _setup;
private IList<IDASHardware> _hardware;
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");
}
}
public bool AssignEnabled { get; set; }
public bool RemoveEnabled { get; set; }
public bool EnableOrDisableEnabled { get; set; }
public ObservableCollection<Model.DASChannel> DASChannels { get; set; } = new ObservableCollection<Model.DASChannel>();
public ObservableCollection<ITTSChannelRecord> RemainingChannels { get; set; } =
new ObservableCollection<ITTSChannelRecord>();
private ITTSChannelRecord _selectedRemainingChannel;
public ITTSChannelRecord SelectedRemainingChannel
{
get => _selectedRemainingChannel;
set
{
_selectedRemainingChannel = value;
if (null == _selectedRemainingChannel || null == SelectedDASChannel) return;
AssignEnabled = true;
OnPropertyChanged("AssignEnabled");
}
}
private void DetermineRemoveEnableStatus()
{
if (_selectedDASChannel?.Channel != null)
{
if (!string.IsNullOrWhiteSpace(_selectedDASChannel.EID) &&
_selectedDASChannel.EID == _selectedDASChannel.Channel.SensorEID)
{
//can only be replaced, can't be removed
RemoveEnabled = false;
}
RemoveEnabled = true;
}
else
{
RemoveEnabled = false;
}
OnPropertyChanged("RemoveEnabled");
AssignEnabled = null != _selectedDASChannel && null != _selectedRemainingChannel;
OnPropertyChanged("AssignEnabled");
EnableOrDisableEnabled = _selectedDASChannel?.Channel != null;
OnPropertyChanged("EnableOrDisableEnabled");
OnPropertyChanged("EnableOrDisableText");
}
private Model.DASChannel _selectedDASChannel;
public Model.DASChannel SelectedDASChannel
{
get => _selectedDASChannel;
set
{
_selectedDASChannel = value;
DetermineRemoveEnableStatus();
}
}
public string EnableOrDisableText
{
get
{
if (SelectedDASChannel?.Channel == null)
{
return StringResources.Analog_Enable;
}
return SelectedDASChannel.Channel.Disabled
? StringResources.Analog_Enable
: StringResources.Analog_Disable;
}
}
#endregion Properties
#region Commands
#region assign
/// <summary>
/// Assign a channel code to a channel
/// </summary>
private DelegateCommand _assignCommand;
public DelegateCommand AssignCommand => _assignCommand ?? (_assignCommand = new DelegateCommand(Assign));
private void Assign()
{
if (SelectedRemainingChannel == null) { return; }
_eventAggregator.GetEvent<TTSImportTestSetupChangedEvent>().Publish(_setup);
//BEFORE we go any further, check the state of sensor ids
//if the channel has a sensor id AND there's a sensor on the channel with the same id
//then prompt on replacing the id
//IF the channel has a sensor id and there's no sensor on the channel BUT the new sensor has a different id
//then prompt on replacing the id
var bReplacingID = false;
if (!string.IsNullOrWhiteSpace(SelectedDASChannel.EID))
{
if (null != SelectedRemainingChannel && SelectedRemainingChannel.SensorEID != SelectedDASChannel.EID)
{
bReplacingID = true;
}
//if existing channel has this ID, we will need to clear out the old id and assign a new one...
if (null != SelectedDASChannel.Channel && SelectedDASChannel.Channel.SensorEID == SelectedDASChannel.EID)
{
bReplacingID = true;
}
}
if (bReplacingID)
{
Task.Run(() =>
{
var dialogResult = MessageBox.Show(StringResources.AssignSensorPrompt, StringResources.UserFeedbackRequired, MessageBoxButton.YesNo);
if (dialogResult == MessageBoxResult.Yes)
{
Application.Current.Dispatcher.BeginInvoke(new Action(AssignWork));
}
});
return;
}
AssignWork();
}
/// <summary>
/// assigns a channel record to a physical channel
/// </summary>
private void AssignWork()
{
if (null != SelectedDASChannel.Channel)
{
if (!string.IsNullOrWhiteSpace(SelectedDASChannel.EID))
{
SelectedDASChannel.Channel.SensorEID = "";
}
RemainingChannels.Add(SelectedDASChannel.Channel);
}
if (!string.IsNullOrWhiteSpace(SelectedDASChannel.EID))
{
SelectedRemainingChannel.SensorEID = SelectedDASChannel.EID;
}
SelectedDASChannel.SetITTSChannelRecord(SelectedRemainingChannel);
var channel = SelectedRemainingChannel;
var index = RemainingChannels.IndexOf(channel);
SelectedRemainingChannel = null;
RemainingChannels.Remove(channel);
if (index < RemainingChannels.Count)
{
SelectedRemainingChannel = RemainingChannels[index];
OnPropertyChanged("SelectedRemainingChannel");
}
else if (RemainingChannels.Count > 0)
{
SelectedRemainingChannel = RemainingChannels[index - 1];
OnPropertyChanged("SelectedRemainingChannel");
}
CollectionViewSource.GetDefaultView(DASChannels)?.Refresh();
index = DASChannels.IndexOf(SelectedDASChannel);
for (var i = index; i < DASChannels.Count; i++)
{
var dasChannel = DASChannels[i];
if (null != dasChannel.Channel) { continue; }
SelectedDASChannel = dasChannel;
OnPropertyChanged("SelectedDASChannel");
return;
}
//didn't find a match, start from the beginning?
for (var i = 0; i < index; i++)
{
var dasChannel = DASChannels[i];
if (null != dasChannel.Channel)
{
continue;
}
SelectedDASChannel = dasChannel;
OnPropertyChanged("SelectedDASChannel");
return;
}
//if we get here there's no new channel to go to, but we need to set the remove/enable/disable button status
OnPropertyChanged("SelectedDASChannel");
DetermineRemoveEnableStatus();
}
#endregion
#region remove
private DelegateCommand _removeCommand;
public DelegateCommand RemoveCommand => _removeCommand ?? (_removeCommand = new DelegateCommand(Remove));
/// <summary>
/// remove a hardware channel assignment (does not remove the channel from the test setup though?)
/// </summary>
private void Remove()
{
if (null == SelectedDASChannel || null == SelectedDASChannel.Channel) { return; }
_eventAggregator.GetEvent<TTSImportTestSetupChangedEvent>().Publish(_setup);
RemainingChannels.Add(SelectedDASChannel.Channel);
SelectedDASChannel.SetITTSChannelRecord(null);
CollectionViewSource.GetDefaultView(DASChannels)?.Refresh();
var index = DASChannels.IndexOf(SelectedDASChannel);
for (var i = index; i < DASChannels.Count; i++)
{
if (null == DASChannels[i].Channel) { continue; }
SelectedDASChannel = DASChannels[i];
OnPropertyChanged("SelectedDASChannel");
return;
}
for (var i = 0; i < index; i++)
{
if (null == DASChannels[i].Channel) { continue; }
SelectedDASChannel = DASChannels[i];
OnPropertyChanged("SelectedDASChannel");
return;
}
//if we get here there's no new channel to go to, but we need to set the remove/enable/disable button status
OnPropertyChanged("SelectedDASChannel");
DetermineRemoveEnableStatus();
}
#endregion
#region enableordisable
private DelegateCommand _enableOrDisableCommand;
public DelegateCommand EnableOrDisableCommand =>
_enableOrDisableCommand ?? (_enableOrDisableCommand = new DelegateCommand(EnableOrDisable));
/// <summary>
/// enables or disables a channel in the test.
/// </summary>
private void EnableOrDisable()
{
if (SelectedDASChannel?.Channel == null) { return; }
SelectedDASChannel.Channel.Disabled = !SelectedDASChannel.Channel.Disabled;
SelectedDASChannel.Disabled = SelectedDASChannel.Channel.Disabled;
OnPropertyChanged("EnableOrDisableText");
_eventAggregator.GetEvent<TTSImportTestSetupChangedEvent>().Publish(_setup);
}
#endregion
#endregion
/// <inheritdoc />
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -0,0 +1,438 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Added" xml:space="preserve">
<value>Added</value>
</data>
<data name="Analog_Assign" xml:space="preserve">
<value>適用</value>
</data>
<data name="Analog_Disable" xml:space="preserve">
<value>無効</value>
</data>
<data name="Analog_Enable" xml:space="preserve">
<value>有効</value>
</data>
<data name="Analog_Remove" xml:space="preserve">
<value>削除</value>
</data>
<data name="Assigned" xml:space="preserve">
<value>アサイン</value>
</data>
<data name="BatteryVoltageStatusColumn" xml:space="preserve">
<value>バッテリーステータス</value>
</data>
<data name="Browse" xml:space="preserve">
<value>フォルダの参照</value>
</data>
<data name="CableMultiplier" xml:space="preserve">
<value>ケーブル長補正</value>
</data>
<data name="Capacity" xml:space="preserve">
<value>定格容量</value>
</data>
<data name="CHAN" xml:space="preserve">
<value>DAS CH</value>
</data>
<data name="ChannelType" xml:space="preserve">
<value>CH 種類</value>
</data>
<data name="Channel_Summary" xml:space="preserve">
<value>チャンネル 一覧</value>
</data>
<data name="Code" xml:space="preserve">
<value>CH名</value>
</data>
<data name="DASChannel" xml:space="preserve">
<value>DAS CH</value>
</data>
<data name="DASChannels" xml:space="preserve">
<value>DAS チャンネル</value>
</data>
<data name="DASSerial" xml:space="preserve">
<value>DAS シリアル番号</value>
</data>
<data name="DAS_Summary" xml:space="preserve">
<value>DAS 一覧</value>
</data>
<data name="EID" xml:space="preserve">
<value>EID</value>
</data>
<data name="EIDFound" xml:space="preserve">
<value>EID 数</value>
</data>
<data name="EULabel" xml:space="preserve">
<value>単位</value>
</data>
<data name="HWSerialNumber" xml:space="preserve">
<value>HW SN</value>
</data>
<data name="Import" xml:space="preserve">
<value>xml 保存</value>
</data>
<data name="ImportFile" xml:space="preserve">
<value>入力ファイルの選択</value>
</data>
<data name="ImportTestSetup_PossibleStatus_Done" xml:space="preserve">
<value>完了</value>
</data>
<data name="ImportTestSetup_PossibleStatus_Failed" xml:space="preserve">
<value>Failed</value>
</data>
<data name="ImportTestSetup_PossibleStatus_Working" xml:space="preserve">
<value>処理中</value>
</data>
<data name="InputVoltageStatusColumn" xml:space="preserve">
<value>入力電圧ステータス</value>
</data>
<data name="JCode" xml:space="preserve">
<value>センサー詳細</value>
</data>
<data name="Mode" xml:space="preserve">
<value>モード</value>
</data>
<data name="Name" xml:space="preserve">
<value>Name</value>
</data>
<data name="NONE" xml:space="preserve">
<value>-----</value>
</data>
<data name="Polarity" xml:space="preserve">
<value>±</value>
</data>
<data name="PostTrigger" xml:space="preserve">
<value>トリガー後 (sec)</value>
</data>
<data name="PreTrigger" xml:space="preserve">
<value>トリガー前 (sec)</value>
</data>
<data name="Range" xml:space="preserve">
<value>要求レンジ</value>
</data>
<data name="RemainingChannels" xml:space="preserve">
<value>未処理チャンネル</value>
</data>
<data name="Requested" xml:space="preserve">
<value>要求チャンネル</value>
</data>
<data name="RunTest" xml:space="preserve">
<value>試験実施</value>
</data>
<data name="SampleRate" xml:space="preserve">
<value>サンプル周波数 (per sec)</value>
</data>
<data name="Sens" xml:space="preserve">
<value>校正値</value>
</data>
<data name="SensorSN" xml:space="preserve">
<value>センサー SN</value>
</data>
<data name="SerialNumber" xml:space="preserve">
<value>センサー SN</value>
</data>
<data name="TestLength" xml:space="preserve">
<value>試験時間 (sec)</value>
</data>
<data name="TestSetupName" xml:space="preserve">
<value>テストセットアップ名:</value>
</data>
<data name="ToyotaCode" xml:space="preserve">
<value>Toyota Code</value>
</data>
<data name="Type" xml:space="preserve">
<value>CH 種類</value>
</data>
<data name="Unassigned" xml:space="preserve">
<value>未アサイン</value>
</data>
<data name="ValueEU" xml:space="preserve">
<value>VAL (EU)</value>
</data>
<data name="ValuePercent" xml:space="preserve">
<value>VAL (%)</value>
</data>
<data name="AssignSensorPrompt" xml:space="preserve">
<value>Assign sensor? ID on the channel will be applied to the sensor and removed from any other sensors.</value>
</data>
<data name="UserFeedbackRequired" xml:space="preserve">
<value>User feedback required</value>
</data>
<data name="Current" xml:space="preserve">
<value>電流 (amp)</value>
</data>
<data name="Delay" xml:space="preserve">
<value>遅延時間 (ms)</value>
</data>
<data name="Duration" xml:space="preserve">
<value>持続時間 (ms)</value>
</data>
<data name="LimitDuration" xml:space="preserve">
<value>持続時間制限</value>
</data>
<data name="ResHighTolerance" xml:space="preserve">
<value>抵抗値 上限. (Ω)</value>
</data>
<data name="ResLowTolerance" xml:space="preserve">
<value>抵抗値 加減. (Ω)</value>
</data>
<data name="CH" xml:space="preserve">
<value>CH</value>
</data>
<data name="EditFile_AddCode" xml:space="preserve">
<value>CH名追加</value>
</data>
<data name="EditFile_DeleteCode" xml:space="preserve">
<value>CH名削除</value>
</data>
<data name="EditFile_Replace" xml:space="preserve">
<value>センサー交換</value>
</data>
<data name="Filter" xml:space="preserve">
<value>ソフトウエアフィルター</value>
</data>
<data name="ImportTestSetup_MustBeCSVOrXML" xml:space="preserve">
<value>TTS import requires either .csv or .xml input file</value>
</data>
<data name="ImportTestSetup_NoOriginalCSV" xml:space="preserve">
<value>TTS import requires a .csv filename in the OriginalImportFile attribute</value>
</data>
<data name="ImportTestSetup_UnexpectedZeroMethod" xml:space="preserve">
<value>is an unexpected zero method type. Only None, AverageOverTime, and UsePreEventDiagnosticsZero are allowed</value>
</data>
<data name="JHyphenCode" xml:space="preserve">
<value>センサー詳細</value>
</data>
<data name="NumChannelsAndSensors" xml:space="preserve">
<value>要求チャンネル数:{0}, 予備センサー数:{1}</value>
</data>
<data name="SaveFile" xml:space="preserve">
<value>ファイル保存</value>
</data>
<data name="Search" xml:space="preserve">
<value>検索</value>
</data>
<data name="TestName" xml:space="preserve">
<value>試験No</value>
</data>
<data name="Table_NA" xml:space="preserve">
<value>---</value>
</data>
<data name="Analog" xml:space="preserve">
<value>アナログ</value>
</data>
<data name="DigitalIn" xml:space="preserve">
<value>Digital In</value>
</data>
<data name="TOM" xml:space="preserve">
<value>TOM</value>
</data>
<data name="AllowEIDToBlankChannelChallenge" xml:space="preserve">
<value>The sensor {0} has an EID, but no EID was found.\r\n\r\nPress OK to clear the EID for {0} and assign the sensor.\r\nPress Cancel to leave the EID unchanged and the sensor unassigned.</value>
</data>
<data name="ROIEnd" xml:space="preserve">
<value>ダウンロード終了時間 (sec)</value>
</data>
<data name="ROIStart" xml:space="preserve">
<value>ダウンロード開始時間 (sec)</value>
</data>
<data name="ImportTestSetup_DuplicateSensorSerialNumber" xml:space="preserve">
<value>{0} が2箇所以上あります。</value>
</data>
<data name="ImportTestSetup_DuplicateChannelCode" xml:space="preserve">
<value>{0} が2箇所以上あります。</value>
</data>
<data name="ImportTestSetup_DuplicateDescription" xml:space="preserve">
<value>{0} が2箇所以上あります。</value>
</data>
<data name="DIn" xml:space="preserve">
<value>D In</value>
</data>
<data name="DOut" xml:space="preserve">
<value>D Out</value>
</data>
<data name="ECM" xml:space="preserve">
<value>ECM</value>
</data>
<data name="G5" xml:space="preserve">
<value>G5</value>
</data>
<data name="Rack" xml:space="preserve">
<value>Rack</value>
</data>
<data name="SPD" xml:space="preserve">
<value>SPD</value>
</data>
<data name="SPS" xml:space="preserve">
<value>SPS</value>
</data>
<data name="SPT" xml:space="preserve">
<value>SPT</value>
</data>
<data name="Squib" xml:space="preserve">
<value>スクイブ</value>
</data>
<data name="Total" xml:space="preserve">
<value>合計</value>
</data>
<data name="Units" xml:space="preserve">
<value>単位</value>
</data>
<data name="AssignSensorExcitationError" xml:space="preserve">
<value>Sensor Assignment Error</value>
</data>
<data name="InvalidExcitationAssignment" xml:space="preserve">
<value>{0} V 印加電圧をサポートしていません。</value>
</data>
<data name="MissingECMSWarning" xml:space="preserve">
<value>以下の IP Addresses の機器は応答していません. 対象機器を再起動してください。</value>
</data>
<data name="Warning" xml:space="preserve">
<value>警告!</value>
</data>
<data name="EmptyChannelCodeWarning" xml:space="preserve">
<value>Non empty channel codes are required, please complete channel codes to continue</value>
</data>
<data name="TestId" xml:space="preserve">
<value>試験番号</value>
</data>
<data name="TESTID_PREFIX_SUFFIX_None" xml:space="preserve">
<value>[-----]</value>
</data>
<data name="TESTID_PREFIX_SUFFIX_TestSetupName" xml:space="preserve">
<value>[テストセットアップ名]</value>
</data>
<data name="TESTID_PREFIX_SUFFIX_TimeStamp" xml:space="preserve">
<value>[タイムスタンプ]</value>
</data>
<data name="EditFile_ADDDI" xml:space="preserve">
<value>DI追加</value>
</data>
<data name="EditFile_AddSquib" xml:space="preserve">
<value>スクイブ追加</value>
</data>
<data name="AAF_SLICE" xml:space="preserve">
<value>アンチエイリアスフィルター SLICE : {0}</value>
</data>
<data name="AAF_TDAS" xml:space="preserve">
<value>アンチエイリアスフィルター TDAS : {0}</value>
</data>
<data name="ExcitationNotSupportedByChannel" xml:space="preserve">
<value> {0} V 印加電圧はこのDASでは使用できません。</value>
</data>
</root>

View File

@@ -0,0 +1,30 @@
using DTS.Common.Interface;
namespace TTSImport
{
/// <summary>
/// Interaction logic for SummaryView.xaml
/// </summary>
public partial class SummaryView : ISummaryView
{
public SummaryView()
{
InitializeComponent();
}
public void UpdateTestIds(string[] serializedValues)
{
ctrlTestId.PopulateAllTestIdPrefixSuffixValues(serializedValues);
}
public void SetTestName(string testName)
{
ctrlTestId.TestName = testName;
ctrlTestId.TestSetupLabel = testName;
}
public string GetTestId()
{
return ctrlTestId.GetTestId();
}
}
}

View File

@@ -0,0 +1,861 @@
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;
}
}
}
}
}

View File

@@ -0,0 +1,302 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using DTS.Common.Events;
using DTS.Common.Events.TTSImport;
using DTS.Common.Interface.DataRecorders;
using DTS.Common.Interface.TestSetups.Imports.TTS.DOChannels;
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;
// ReSharper disable CheckNamespace
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable InconsistentNaming
namespace TTSImport
{
/// <summary>
/// this class handles Level Trigger edit/create functionality
/// </summary>
[PartCreationPolicy(CreationPolicy.Shared)]
public class DigitalOutputChannelsViewModel : IDigitalOutputChannelsViewModel
{
/// <summary>
/// The Hardware Scan view
/// </summary>
public IDigitalOutputChannelsView View { get; set; }
private IEventAggregator _eventAggregator { get; }
private IRegionManager _regionManager;
private IUnityContainer UnityContainer { get; }
public InteractionRequest<Notification> NotificationRequest { get; }
public InteractionRequest<Confirmation> ConfirmationRequest { get; }
/// <summary>
/// Creates a new instance of the TechnologyDomainEditViewModel.
/// </summary>
/// <param name="view">The IDigitalOutputChannelsView.</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 DigitalOutputChannelsViewModel(IDigitalOutputChannelsView 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<AssignedChannelsChangedEvent>().Subscribe(OnAssignedChannelsChangedEvent,
ThreadOption.PublisherThread, true);
_eventAggregator.GetEvent<TTSImportHardwareScanFinishedEvent>()
.Subscribe(OnHardwareScanComplete, ThreadOption.PublisherThread, true);
_eventAggregator.GetEvent<EIDMappingEvent>()
.Subscribe(OnEIDComplete, ThreadOption.PublisherThread, true);
}
#region Methods
private void OnEIDComplete(IDictionary<string, string> sensorIdToChannelId)
{
var channelIdToSensorId = new Dictionary<string, string>();
using (var e = sensorIdToChannelId.GetEnumerator())
{
while (e.MoveNext())
{
channelIdToSensorId[e.Current.Value] = e.Current.Key;
}
}
_hardwareChannelIdToSensorId = channelIdToSensorId;
}
private void OnHardwareScanComplete(List<IDASHardware> hardware)
{
_hardware = hardware;
}
private void OnAssignedChannelsChangedEvent(ITTSSetup setup)
{
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
OnAssignedChannelsChangedEvent(setup);
}));
return;
}
_setup = setup;
if (null == _hardware || null == _setup) { return; }
var channels = new ObservableCollection<DASChannel>();
var channelIdToChannelRecord = new Dictionary<string, ITTSChannelRecord>();
foreach (var ch in _setup.Channels)
{
if (!ch.IsDigitalOutput) { continue; }
if (null == ch.HardwareChannel) { continue; }
if (ch.ChannelCode == TTSChannelRecord.NONE) { continue; }
channelIdToChannelRecord[ch.HardwareChannel.GetId()] = ch;
}
var channelIdToDASChannel = new Dictionary<string, DASChannel>();
foreach (var das in _hardware)
{
var ichannels = das.GetIHardwareChannels();
foreach (var ch in ichannels)
{
if (!ch.IsDigitalOut) { continue; }
var newChannel = new DASChannel(ch, _setup);
if (_hardwareChannelIdToSensorId.ContainsKey(ch.GetId()))
{
newChannel.EID = _hardwareChannelIdToSensorId[ch.GetId()];
}
channels.Add(newChannel);
channelIdToDASChannel[newChannel.HardwareChannel.GetId()] = newChannel;
if (channelIdToChannelRecord.ContainsKey(ch.GetId()))
{
newChannel.SetITTSChannelRecord(channelIdToChannelRecord[ch.GetId()]);
newChannel.Channel.ChannelCode = $"Digital Out {ch.ToString()}";
newChannel.Channel.SensorSerialNumber = newChannel.Channel.ChannelCode;
}
}
}
using (var enumChannels = channelIdToDASChannel.GetEnumerator())
{
while (enumChannels.MoveNext())
{
if (null == enumChannels.Current.Value.Channel)
{
//CREATE new channel
var ch = new TTSChannelRecord();
ch.ChannelCode = $"Digital Out {enumChannels.Current.Value.HardwareChannel?.ToString()}";
ch.IsChannelCodeValid = true;
ch.IsDigitalOutput = true;
ch.SensorEU = "V";
ch.HardwareChannel = enumChannels.Current.Value.HardwareChannel;
//ch.SensorSerialNumber = ch.ChannelCode;
enumChannels.Current.Value.SetITTSChannelRecord(ch);
}
}
}
DASChannels = channels;
OnPropertyChanged("DASChannels");
CollectionViewSource.GetDefaultView(DASChannels)?.Refresh();
}
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
private ITTSSetup _setup;
private IList<IDASHardware> _hardware;
private IDictionary<string, string> _hardwareChannelIdToSensorId = new Dictionary<string, string>();
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");
}
}
public ObservableCollection<DASChannel> DASChannels { get; set; } = new ObservableCollection<DASChannel>();
private DASChannel _selectedDASChannel;
public DASChannel SelectedDASChannel
{
get => _selectedDASChannel;
set => _selectedDASChannel = value;
}
public string EnableOrDisableText
{
get
{
if (SelectedDASChannel?.Channel == null)
{
return StringResources.Analog_Enable;
}
return SelectedDASChannel.Channel.Disabled
? StringResources.Analog_Enable
: StringResources.Analog_Disable;
}
}
#endregion Properties
#region Commands
#endregion
/// <inheritdoc />
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -0,0 +1,211 @@
<base:BaseView x:Class="TTSImport.EditFileView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:base="clr-namespace:DTS.Common.Base;assembly=DTS.Common"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:strings="clr-namespace:TTSImport"
xmlns:converters="clr-namespace:DTS.Common.Converters;assembly=DTS.Common"
xmlns:controls="clr-namespace:DTS.Common.Controls;assembly=DTS.Common"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="768" d:DesignWidth="1100">
<base:BaseView.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Themes/CommonStyles.xaml"/>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Themes/brushes.xaml"/>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Controls/combobox.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="ListView">
<Setter Property="ItemContainerStyle" Value="{StaticResource TTS_ListViewItemStyle}"/>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource TTS_TextBoxStyle}"/>
<Style TargetType="TextBlock" BasedOn="{StaticResource TTS_TextBlockStyle}"/>
<Style TargetType="CheckBox" BasedOn="{StaticResource PageContentCheckBoxStyle}" />
<Style TargetType="ComboBox" BasedOn="{StaticResource TTS_ComboBoxStyle}"/>
<Style TargetType="Button" BasedOn="{StaticResource TTS_ButtonStyle}"/>
<Style TargetType="GridViewColumnHeader" BasedOn="{StaticResource Gray_GridViewColumnHeaderStyle}"/>
<converters:BooleanToBorderThicknessConverter x:Key="BooleanToBorderThickness" />
<converters:BooleanToColorConverter x:Key="BooleanToColor" />
<converters:BooleanToColorConverter x:Key="BooleanToWarningColor" WarningBrush="True" />
</ResourceDictionary>
</base:BaseView.Resources>
<Grid Background="{DynamicResource Brush_ApplicationContentBackground}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<Button Content="{strings:TranslateExtension SaveFile}" IsEnabled="{Binding SaveFileEnabled}" AutomationProperties.AutomationId="SaveFileButton" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding SaveFileClicked}" AutomationProperties.AutomationId="SaveFileClickedCommand" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<TextBlock Text="{strings:TranslateExtension TestName}" AutomationProperties.AutomationId="TestNameTextBlock" />
<TextBox Text="{Binding TestName, UpdateSourceTrigger=PropertyChanged, FallbackValue=NO_LABEL}" Width="500"
BorderBrush="{Binding IsTestNameValid, Converter={StaticResource BooleanToColor}}"
BorderThickness="{Binding IsTestNameValid, Converter={StaticResource BooleanToBorderThickness}}" AutomationProperties.AutomationId="TestNameTextBox" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<i:InvokeCommandAction Command="{Binding TestNameLostFocus}" CommandParameter="{Binding TestName}" AutomationProperties.AutomationId="TestNameLostFocusCommand" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right">
<TextBlock Text="{strings:TranslateExtension Search}" AutomationProperties.AutomationId="SearchTextBlock" Margin="3,0" VerticalAlignment="Center"/>
<TextBox Text="{Binding Search}" AutomationProperties.AutomationId="SearchTextBox" Width="200" TextChanged="TextBox_TextChanged"/>
</StackPanel>
</Grid>
<TextBlock Text="{Binding NumChannelsAndSensors, FallbackValue=NO_LABEL}" HorizontalAlignment="Left" AutomationProperties.AutomationId="NumChannelAndSensorsTextBlock" />
</StackPanel>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ListView Grid.Row="0" Grid.Column="0" ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding RequiredChannels}" SelectedItem="{Binding SelectedRequiredChannel}" AutomationProperties.AutomationId="RequiredChannelsListView" >
<ListView.View>
<controls:AutoSizedGridView>
<GridViewColumn Header="{strings:TranslateExtension CH}" Width="50" DisplayMemberBinding="{Binding ChannelNumber}" AutomationProperties.AutomationId="ChannelNumber" />
<GridViewColumn Header="{strings:TranslateExtension Code}" AutomationProperties.AutomationId="ChannelCode" >
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBox Text="{Binding ChannelCode, UpdateSourceTrigger=PropertyChanged}" MinWidth="180" AutomationProperties.AutomationId="ChannelCodeTextBox"
BorderBrush="{Binding IsChannelCodeValid, Converter={StaticResource BooleanToColor}}"
BorderThickness="{Binding IsChannelCodeValid, Converter={StaticResource BooleanToBorderThickness}}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<i:InvokeCommandAction Command="{Binding ControlLostFocus}" CommandParameter="{Binding ChannelCode}" AutomationProperties.AutomationId="ChannelCodeLostFocusCommand" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension JHyphenCode}" AutomationProperties.AutomationId="JCode" >
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBox Text="{Binding JCodeOrDescription, UpdateSourceTrigger=PropertyChanged}" MinWidth="180"
BorderBrush="{Binding IsJCodeValid, Converter={StaticResource BooleanToWarningColor}}"
BorderThickness="{Binding IsJCodeValid, Converter={StaticResource BooleanToBorderThickness}}" AutomationProperties.AutomationId="JCodeTextBox" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<i:InvokeCommandAction Command="{Binding ControlLostFocus}" CommandParameter="{Binding JCodeOrDescription}" AutomationProperties.AutomationId="JCodeOrDescriptionLostFocusCommand" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Range}" AutomationProperties.AutomationId="Range" >
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBox Text="{Binding ChannelRangeString}" MinWidth="120" Visibility="{Binding RangeVisible}"
BorderBrush="{Binding IsRangeValid, Converter={StaticResource BooleanToColor}}"
BorderThickness="{Binding IsRangeValid, Converter={StaticResource BooleanToBorderThickness}}" AutomationProperties.AutomationId="RangeTextBox" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<i:InvokeCommandAction Command="{Binding ControlLostFocus}" CommandParameter="{Binding ChannelRangeString}" AutomationProperties.AutomationId="RangeControlLostFocusCommand"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Filter}" AutomationProperties.AutomationId="Filter" >
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<ComboBox ItemsSource="{Binding Filters}" MinWidth="70"
SelectedItem="{Binding FilterString, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding FilterVisible}"
BorderBrush="{Binding IsFilterValid, Converter={StaticResource BooleanToColor}}"
BorderThickness="{Binding IsFilterValid, Converter={StaticResource BooleanToBorderThickness}}"
AutomationProperties.AutomationId="FilterComboBox">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding FilterSelectionChanged}"
CommandParameter="{Binding FilterString}" AutomationProperties.AutomationId="FilterSelectionChangedCommand" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension SensorSN}">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock MinWidth="170" Text="{Binding SensorSerialNumber}" AutomationProperties.AutomationId="SensorSerialNumber"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</controls:AutoSizedGridView>
</ListView.View>
</ListView>
<StackPanel Orientation="Vertical" VerticalAlignment="Center" Grid.Row="0" Grid.Column="1">
<Button Content="{strings:TranslateExtension EditFile_Replace}" IsEnabled="{Binding ReplaceEnabled}" Width="85" AutomationProperties.AutomationId="ReplaceButton" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding ReplaceCommand}" AutomationProperties.AutomationId="ReplaceCommand" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Content="{strings:TranslateExtension EditFile_AddCode}" IsEnabled="{Binding AddCodeEnabled}" Width="85" AutomationProperties.AutomationId="AddCodeButton" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding AddCodeCommand}" AutomationProperties.AutomationId="AddCodeCommand" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Content="{strings:TranslateExtension EditFile_DeleteCode}" IsEnabled="{Binding DeleteCodeEnabled}" Width="85" AutomationProperties.AutomationId="DeleteCodeButton" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding DeleteCodeCommand}" AutomationProperties.AutomationId="DeleteCodeCommand" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Content="{strings:TranslateExtension EditFile_AddSquib}" Width="85" AutomationProperties.AutomationId="AddSquibButton" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding AddSquibCommand}" AutomationProperties.AutomationId="AddSquibCommand" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Content="{strings:TranslateExtension EditFile_ADDDI}" Width="85" AutomationProperties.AutomationId="ADDDIButton" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding ADDDICommand}" AutomationProperties.AutomationId="ADDDICommand" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
<ListView Grid.Row="0" Grid.Column="2"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding SystemSensors}"
SelectedItem="{Binding SelectedSystemSensor}" AutomationProperties.AutomationId="SystemSensorsListView" >
<ListView.View>
<GridView>
<GridViewColumn Header="{strings:TranslateExtension SensorSN}" Width="200">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding SensorSerialNumber}" AutomationProperties.AutomationId="SysSensorSerialNumber" />
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Grid>
</base:BaseView>

View File

@@ -0,0 +1,159 @@
<base:BaseView x:Class="TTSImport.SummaryView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:base="clr-namespace:DTS.Common.Base;assembly=DTS.Common"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ttsImport="clr-namespace:TTSImport"
xmlns:converters="clr-namespace:DTS.Common.Converters;assembly=DTS.Common"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:controls="clr-namespace:DTS.Common.Controls;assembly=DTS.Common"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="768" d:DesignWidth="1366">
<base:BaseView.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Themes/CommonStyles.xaml"/>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Themes/brushes.xaml"/>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Controls/combobox.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="ListView">
<Setter Property="ItemContainerStyle" Value="{StaticResource TTS_ListViewItemStyle}"/>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource TTS_TextBoxStyle}">
<Setter Property="Margin" Value="0,0,3,3"/>
</Style>
<Style TargetType="TextBlock" BasedOn="{StaticResource TTS_TextBlockStyle}">
<Setter Property="Margin" Value="0,0,3,3"/>
<Setter Property="VerticalAlignment" Value="Top"/>
</Style>
<Style TargetType="CheckBox" BasedOn="{StaticResource PageContentCheckBoxStyle}" />
<Style TargetType="ComboBox" BasedOn="{StaticResource TTS_ComboBoxStyle}">
<Setter Property="Height" Value="28"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Width" Value="150"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Margin" Value="0,0,3,3"/>
</Style>
<Style TargetType="Button" BasedOn="{StaticResource TTS_ButtonStyle}"/>
<Style TargetType="GridViewColumnHeader" BasedOn="{StaticResource Gray_GridViewColumnHeaderStyle}"/>
<Style TargetType="xctk:DoubleUpDown" BasedOn="{StaticResource PageContentXCDoubleUpDown}">
<Setter Property="Increment" Value="0.1"/>
<Setter Property="Width" Value="150"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Margin" Value="0,0,3,3"/>
</Style>
<converters:NonZeroToColorConverter x:Key="NonZeroToColor" />
<converters:BooleanToBorderThicknessConverter x:Key="BooleanToBorderThickness" />
<converters:BooleanToColorConverter x:Key="BooleanToColor" />
</ResourceDictionary>
</base:BaseView.Resources>
<Grid Background="{DynamicResource Brush_ApplicationContentBackground}" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<controls:CommonStatusRibbon Content="{Binding StatusAndProgressBarView}" Grid.Row="0" Grid.ColumnSpan="3" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="{ttsImport:TranslateExtension ImportFile}" VerticalAlignment="Top"/>
<TextBlock Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding ImportFileName}" VerticalAlignment="Top" AutomationProperties.AutomationId="ImportFileName" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="{ttsImport:TranslateExtension TestSetupName}" VerticalAlignment="Top"/>
<TextBox Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding TestSetupName}" Width="150" VerticalAlignment="Top" AutomationProperties.AutomationId="TestSetupName" />
<Button Grid.Row="2" Grid.Column="2" Background="White" Content="{ttsImport:TranslateExtension Import}" Width="150"
IsEnabled="{Binding ImportEnabled}" HorizontalAlignment="Left" AutomationProperties.AutomationId="btnImport" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding ImportClicked}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<TextBlock Grid.Row="3" Grid.Column="0" Text="{ttsImport:TranslateExtension TestId}"/>
<StackPanel Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Orientation="Horizontal">
<controls:TestIdControl x:Name="ctrlTestId" AutomationProperties.AutomationId="TestIdControl"/>
<Button Background="White" Content="{ttsImport:TranslateExtension RunTest}" Width="150"
Visibility="{Binding RunTestVisible}" HorizontalAlignment="Left" AutomationProperties.AutomationId="btnRunTest" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding RunTestClicked}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
<TextBlock Grid.Row="4" Grid.Column="0" Text="{ttsImport:TranslateExtension SampleRate}" VerticalAlignment="Top"/>
<ComboBox Grid.Row="4" Grid.Column="1" AutomationProperties.AutomationId="SampleRateComboBox"
ItemsSource="{Binding AvailableSampleRates}" SelectedItem ="{Binding SampleRate, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Grid.Row="5" Grid.Column="0" Text="{ttsImport:TranslateExtension Mode}"/>
<ComboBox Grid.Row="5" Grid.Column="1" AutomationProperties.AutomationId="ModeComboBox"
ItemsSource="{Binding AvailableRecordingModes}"
SelectedItem="{Binding RecordingMode, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Grid.Row="6" Grid.Column="0" Text="{ttsImport:TranslateExtension PreTrigger}" Visibility="{Binding SummaryPreTriggerVisibility}" />
<xctk:DoubleUpDown Grid.Row="6" Grid.Column="1" Value="{Binding PreTrigger}" Minimum="0" AutomationProperties.AutomationId="PreTriggerUpDown"
Visibility="{Binding SummaryPreTriggerVisibility}"/>
<TextBlock Grid.Row="7" Grid.Column="0" Text="{Binding PostTriggerOrTestLength}" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<xctk:DoubleUpDown Grid.Row="7" Grid.Column="1" Value="{Binding PostTrigger}" Minimum="0" AutomationProperties.AutomationId="PostTriggerUpDown" />
<TextBlock Grid.Row="8" Grid.Column="0" Text="{ttsImport:TranslateExtension ROIStart}" VerticalAlignment="Top" HorizontalAlignment="Left" />
<xctk:DoubleUpDown Grid.Row="8" Grid.Column="1" Value="{Binding ROIStart}" AutomationProperties.AutomationId="ROIStartUpDown"
BorderBrush="{Binding IsROIStartValid, Converter={StaticResource BooleanToColor}}"
BorderThickness="{Binding IsROIStartValid, Converter={StaticResource BooleanToBorderThickness}}"/>
<TextBlock Grid.Row="9" Grid.Column="0" Text="{ttsImport:TranslateExtension ROIEnd}" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<xctk:DoubleUpDown Grid.Row="9" Grid.Column="1" Value="{Binding ROIEnd}" AutomationProperties.AutomationId="ROIEndUpDown"
BorderBrush="{Binding IsROIEndValid, Converter={StaticResource BooleanToColor}}"
BorderThickness="{Binding IsROIEndValid, Converter={StaticResource BooleanToBorderThickness}}"/>
<TextBlock Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="3" Text="{Binding AAF_TDAS}" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<TextBlock Grid.Row="11" Grid.Column="0" Grid.ColumnSpan="3" Text="{Binding AAF_SLICE}" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<ScrollViewer Grid.Row="12" Grid.Column="0" Grid.ColumnSpan="3" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<ListView ItemsSource="{Binding SummaryChannelList}" HorizontalAlignment="Left">
<ListView.View>
<GridView>
<GridViewColumn Header="{ttsImport:TranslateExtension Type}" Width="100" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ChannelType,FallbackValue='Channel Type'}" Width="100" AutomationProperties.AutomationId="ChannelType" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{ttsImport:TranslateExtension Assigned}" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Assigned,FallbackValue='Assigned'}" Width="100" AutomationProperties.AutomationId="Assigned" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{ttsImport:TranslateExtension Unassigned}" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Unassigned,FallbackValue='Unassigned'}" Width="100" Background="{Binding Unassigned, Converter={StaticResource NonZeroToColor}}" AutomationProperties.AutomationId="Unassigned" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</ScrollViewer>
</Grid>
</base:BaseView>

View File

@@ -0,0 +1,622 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using DTS.Common.Events;
using DTS.Common.Events.TTSImport;
using DTS.Common.Interface.DataRecorders;
using DTS.Common.Interface.TestSetups.Imports.TTS;
using DTS.Common.Interface.TestSetups.Imports.TTS.ReadFile;
using DTS.Common.Utilities.Logging;
using TTSImport.Resources;
using Application = System.Windows.Application;
using DASChannel = TTSImport.Model.DASChannel;
using MessageBox = System.Windows.MessageBox;
using DTS.Common.DAS.Concepts;
using DTS.Common.Enums;
using TTSImport.Model;
using Prism.Events;
using Unity;
using DTS.Common.Interactivity;
using Prism.Regions;
using Prism.Commands;
// ReSharper disable CheckNamespace
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable InconsistentNaming
namespace TTSImport
{
/// <summary>
/// this class handles Level Trigger edit/create functionality
/// </summary>
[PartCreationPolicy(CreationPolicy.Shared)]
public class AnalogChannelsViewModel : IAnalogChannelsViewModel
{
/// <summary>
/// The Hardware Scan view
/// </summary>
public IAnalogChannelsView View { get; set; }
private IEventAggregator _eventAggregator { get; }
private IRegionManager _regionManager;
private IUnityContainer UnityContainer { get; }
public InteractionRequest<Notification> NotificationRequest { get; }
public InteractionRequest<Confirmation> ConfirmationRequest { get; }
/// <inheritdoc />
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#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 AnalogChannelsViewModel(IAnalogChannelsView 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<AssignedChannelsChangedEvent>().Subscribe(OnAssignedChannelsChangedEvent,
ThreadOption.PublisherThread, true);
_eventAggregator.GetEvent<TTSImportHardwareScanFinishedEvent>()
.Subscribe(OnHardwareScanComplete, ThreadOption.PublisherThread, true);
_eventAggregator.GetEvent<EIDMappingEvent>()
.Subscribe(OnEIDComplete, ThreadOption.PublisherThread, true);
}
#endregion
#region Methods
private void OnEIDComplete(IDictionary<string, string> sensorIdToChannelId)
{
var channelIdToSensorId = new Dictionary<string, string>();
using (var e = sensorIdToChannelId.GetEnumerator())
{
while (e.MoveNext())
{
channelIdToSensorId[e.Current.Value] = e.Current.Key;
}
}
_hardwareChannelIdToSensorId = channelIdToSensorId;
}
public string Validate()
{
var bEmptyChannelCodes = false;
foreach (var channel in DASChannels)
{
if (null == channel.Channel)
{
continue;
}
if (string.IsNullOrWhiteSpace(channel.ToyotaCode))
{
bEmptyChannelCodes = true;
}
}
return bEmptyChannelCodes ? StringResources.EmptyChannelCodeWarning : string.Empty;
}
private void OnHardwareScanComplete(List<IDASHardware> hardware)
{
_hardware = hardware;
}
private void OnAssignedChannelsChangedEvent(ITTSSetup setup)
{
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
OnAssignedChannelsChangedEvent(setup);
}));
return;
}
_setup = setup;
if (null == _hardware || null == _setup) { return; }
var channels = new ObservableCollection<DASChannel>();
var remainingChannels = new ObservableCollection<ITTSChannelRecord>();
var channelIdToDASChannel = new Dictionary<string, DASChannel>();
foreach (var das in _hardware)
{
if (das.IsSLICEEthernetController) { continue; }
var ichannels = das.GetIHardwareChannels();
foreach (var ch in ichannels)
{
if (!ch.IsAnalog) { continue; }
var newChannel = new DASChannel(ch);
if (_hardwareChannelIdToSensorId.ContainsKey(ch.GetId()))
{
newChannel.EID = _hardwareChannelIdToSensorId[ch.GetId()];
}
channels.Add(newChannel);
channelIdToDASChannel[newChannel.HardwareChannel.GetId()] = newChannel;
}
}
foreach (var channelRecord in _setup.Channels)
{
if (channelRecord.IsEmptyRecord) { continue; }
if (channelRecord.IsDigitalInput) { continue; }
if (channelRecord.IsDigitalOutput) { continue; }
if (channelRecord.IsSquib) { continue; }
if (!channelRecord.IsChannelCodeValid) { continue; }
if (channelRecord.ChannelCode == TTSChannelRecord.NONE) { continue; }
if (null != channelRecord.HardwareChannel)
{
var key = channelRecord.HardwareChannel.GetId();
if (channelIdToDASChannel.ContainsKey(key))
{
channelIdToDASChannel[key].SetITTSChannelRecord(channelRecord);
}
}
else
{
remainingChannels.Add(channelRecord);
}
}
DASChannels = channels;
RemainingChannels = remainingChannels;
OnPropertyChanged("DASChannels");
OnPropertyChanged("RemainingChannels");
}
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
private ITTSSetup _setup;
private IList<IDASHardware> _hardware;
private IDictionary<string, string> _hardwareChannelIdToSensorId = new Dictionary<string, string>();
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");
}
}
public bool AssignEnabled { get; set; }
public bool RemoveEnabled { get; set; }
public bool EnableOrDisableEnabled { get; set; }
public ObservableCollection<DASChannel> DASChannels { get; set; } = new ObservableCollection<DASChannel>();
public ObservableCollection<ITTSChannelRecord> RemainingChannels { get; set; } =
new ObservableCollection<ITTSChannelRecord>();
private ITTSChannelRecord _selectedRemainingChannel;
public ITTSChannelRecord SelectedRemainingChannel
{
get => _selectedRemainingChannel;
set
{
_selectedRemainingChannel = value;
if (null == _selectedRemainingChannel || null == SelectedDASChannel) return;
AssignEnabled = true;
OnPropertyChanged("AssignEnabled");
}
}
private DASChannel _selectedDASChannel;
public DASChannel SelectedDASChannel
{
get => _selectedDASChannel;
set
{
_selectedDASChannel = value;
DetermineRemoveEnableStatus();
}
}
public void DetermineRemoveEnableStatus()
{
if (_selectedDASChannel?.Channel != null)
{
if (!string.IsNullOrWhiteSpace(_selectedDASChannel.EID) &&
_selectedDASChannel.EID == _selectedDASChannel.Channel.SensorEID)
{
//can only be replaced, can't be removed
RemoveEnabled = false;
}
RemoveEnabled = true;
}
else
{
RemoveEnabled = false;
}
OnPropertyChanged("RemoveEnabled");
AssignEnabled = null != _selectedDASChannel && null != _selectedRemainingChannel;
OnPropertyChanged("AssignEnabled");
EnableOrDisableEnabled = null != _selectedDASChannel && null != _selectedDASChannel.Channel;
OnPropertyChanged("EnableOrDisableEnabled");
OnPropertyChanged("EnableOrDisableText");
}
public string EnableOrDisableText
{
get
{
if (SelectedDASChannel?.Channel == null)
{
return StringResources.Analog_Enable;
}
return SelectedDASChannel.Channel.Disabled
? StringResources.Analog_Enable
: StringResources.Analog_Disable;
}
}
#endregion Properties
#region Commands
#region assign
/// <summary>
/// Assign a channel code to a channel
/// </summary>
private DelegateCommand _assignCommand;
public DelegateCommand AssignCommand => _assignCommand ?? (_assignCommand = new DelegateCommand(Assign));
private void Assign()
{
if (SelectedRemainingChannel == null) { return; }
var error = string.Empty;
if (!VoltageIsValid(SelectedRemainingChannel, SelectedDASChannel, out error))
{
var window = Application.Current.MainWindow;
if (null == window) { return; }
MessageBox.Show(window, error, StringResources.AssignSensorExcitationError, MessageBoxButton.OK);
return;
}
_eventAggregator.GetEvent<TTSImportTestSetupChangedEvent>().Publish(_setup);
//BEFORE we go any further, check the state of sensor ids
//if the channel has a sensor id AND there's a sensor on the channel with the same id
//then prompt on replacing the id
//IF the channel has a sensor id and there's no sensor on the channel BUT the new sensor has a different id
//then prompt on replacing the id
var bReplacingID = false;
if (!string.IsNullOrWhiteSpace(SelectedDASChannel.EID))
{
if (null != SelectedRemainingChannel && SelectedRemainingChannel.SensorEID != SelectedDASChannel.EID)
{
bReplacingID = true;
}
//if existing channel has this ID, we will need to clear out the old id and assign a new one...
if (null != SelectedDASChannel.Channel &&
SelectedDASChannel.Channel.SensorEID == SelectedDASChannel.EID)
{
bReplacingID = true;
}
}
else if (_setup.RequireEIDFound && !string.IsNullOrWhiteSpace(SelectedRemainingChannel.SensorEID))
{
var window = Application.Current.MainWindow;
if (null == window) { return; }
var msg = string.Format(StringResources.AllowEIDToBlankChannelChallenge, SelectedRemainingChannel.SensorSerialNumber);
msg = msg.Replace("\\r\\n", "\r\n");
var dialogResult = MessageBox.Show(window, msg, StringResources.UserFeedbackRequired, MessageBoxButton.OKCancel);
APILogger.Log(msg, $"User pressed {dialogResult.ToString()}");
if (dialogResult == MessageBoxResult.OK)
{
SelectedRemainingChannel.SensorEID = string.Empty;
AssignWork();
}
return;
}
if (bReplacingID)
{
var window = Application.Current.MainWindow;
if (null == window) { return; }
var dialogResult = MessageBox.Show(window, StringResources.AssignSensorPrompt, StringResources.UserFeedbackRequired, MessageBoxButton.YesNo);
APILogger.Log(StringResources.AssignSensorPrompt, $"User pressed {dialogResult.ToString()}");
if (dialogResult == MessageBoxResult.Yes)
{
AssignWork();
}
return;
}
AssignWork();
}
/// <summary>
/// returns True if the sensor's voltage is supported by the hardware channel, or an error message and False if not
/// </summary>
/// <param name="selectedRemainingChannel"></param>
/// <param name="selectedDASChannel"></param>
/// <param name="error"></param>
/// <returns></returns>
private bool VoltageIsValid(ITTSChannelRecord selectedRemainingChannel, DASChannel selectedDASChannel, out string error)
{
error = string.Empty;
var voltageEnum = ExcitationVoltageOptions.ExcitationVoltageOption.Undefined;
try
{
voltageEnum = Test.Module.Channel.Sensor.GetExcitationVoltageEnumFromMagnitude(selectedRemainingChannel.SensorExcitationVolts);
}
catch { } //GetExcitationVoltageEnumFromMagnitude will throw an exception if an invalid voltage is passed to it
if (selectedDASChannel.HardwareChannel.IsSupportedExcitation(voltageEnum)) return true;
error = string.Format(StringResources.InvalidExcitationAssignment, selectedRemainingChannel.SensorExcitationVolts);
return false;
}
/// <summary>
/// removes the channel as a selected channel for any level triggers
/// removes the channel as a possible channel for any level triggers
/// </summary>
/// <param name="channel"></param>
private void RemoveFromLevelTriggers(ITTSChannelRecord channel)
{
if (null != _setup)
{
foreach (var lt in _setup.LevelTriggers)
{
lt.Remove(channel);
}
}
}
/// <summary>
/// adds the channel as a possible channel to any level triggers
/// </summary>
/// <param name="channel"></param>
private void AddToLevelTriggers(ITTSChannelRecord channel)
{
if (null != _setup)
{
foreach (var lt in _setup.LevelTriggers)
{
lt.Add(channel);
}
}
}
/// <summary>
/// assigns a channel record to a physical channel
/// </summary>
private void AssignWork()
{
if (null == SelectedDASChannel || null == SelectedRemainingChannel) { return; }
var excitation =
Test.Module.Channel.Sensor.GetExcitationVoltageEnumFromMagnitude(SelectedRemainingChannel
.SensorExcitationVolts);
if (!SelectedDASChannel.HardwareChannel.IsSupportedExcitation(excitation))
{
var window = Application.Current.MainWindow;
if (null == window) { return; }
var msg = string.Format(StringResources.ExcitationNotSupportedByChannel, excitation.ToString());
var result = MessageBox.Show(window, msg, StringResources.Warning, MessageBoxButton.OK);
APILogger.Log(msg, $"user pressed {result.ToString()}");
return;
}
if (null != SelectedDASChannel.Channel)
{
if (!string.IsNullOrWhiteSpace(SelectedDASChannel.EID))
{
SelectedDASChannel.Channel.SensorEID = "";
}
RemainingChannels.Add(SelectedDASChannel.Channel);
RemoveFromLevelTriggers(SelectedDASChannel.Channel);
}
if (!string.IsNullOrWhiteSpace(SelectedDASChannel.EID))
{
SelectedRemainingChannel.SensorEID = SelectedDASChannel.EID;
}
SelectedDASChannel.SetITTSChannelRecord(SelectedRemainingChannel);
AddToLevelTriggers(SelectedDASChannel.Channel);
var channel = SelectedRemainingChannel;
var index = RemainingChannels.IndexOf(channel);
SelectedRemainingChannel = null;
RemainingChannels.Remove(channel);
CollectionViewSource.GetDefaultView(DASChannels)?.Refresh();
if (index < RemainingChannels.Count)
{
SelectedRemainingChannel = RemainingChannels[index];
OnPropertyChanged("SelectedRemainingChannel");
}
else if (RemainingChannels.Count > 0)
{
SelectedRemainingChannel = RemainingChannels[index - 1];
OnPropertyChanged("SelectedRemainingChannel");
}
index = DASChannels.IndexOf(SelectedDASChannel);
for (var i = index; i < DASChannels.Count; i++)
{
var dasChannel = DASChannels[i];
if (null != dasChannel.Channel) { continue; }
SelectedDASChannel = dasChannel;
OnPropertyChanged("SelectedDASChannel");
return;
}
//didn't find a match, start from the beginning?
for (var i = 0; i < index; i++)
{
var dasChannel = DASChannels[i];
if (null != dasChannel.Channel)
{
continue;
}
SelectedDASChannel = dasChannel;
OnPropertyChanged("SelectedDASChannel");
return;
}
//if we get here there's no new channel to go to, change remove/enable/disable button status
OnPropertyChanged("SelectedDASChannel");
DetermineRemoveEnableStatus();
}
#endregion
#region remove
private DelegateCommand _removeCommand;
public DelegateCommand RemoveCommand => _removeCommand ?? (_removeCommand = new DelegateCommand(Remove));
/// <summary>
/// remove a hardware channel assignment (does not remove the channel from the test setup though?)
/// </summary>
private void Remove()
{
if (null == SelectedDASChannel || null == SelectedDASChannel.Channel) { return; }
_eventAggregator.GetEvent<TTSImportTestSetupChangedEvent>().Publish(_setup);
RemainingChannels.Add(SelectedDASChannel.Channel);
SelectedDASChannel.SetITTSChannelRecord(null);
CollectionViewSource.GetDefaultView(DASChannels)?.Refresh();
var index = DASChannels.IndexOf(SelectedDASChannel);
for (var i = index; i < DASChannels.Count; i++)
{
if (null == DASChannels[i].Channel) { continue; }
SelectedDASChannel = DASChannels[i];
OnPropertyChanged("SelectedDASChannel");
return;
}
for (var i = 0; i < index; i++)
{
if (null == DASChannels[i].Channel) { continue; }
SelectedDASChannel = DASChannels[i];
OnPropertyChanged("SelectedDASChannel");
return;
}
//if we get here there's no new channel to go to, but we need to set the remove/enable/disable button status
OnPropertyChanged("SelectedDASChannel");
DetermineRemoveEnableStatus();
}
#endregion
#region enableordisable
private DelegateCommand _enableOrDisableCommand;
public DelegateCommand EnableOrDisableCommand =>
_enableOrDisableCommand ?? (_enableOrDisableCommand = new DelegateCommand(EnableOrDisable));
/// <summary>
/// enables or disables a channel in the test.
/// </summary>
private void EnableOrDisable()
{
if (SelectedDASChannel?.Channel == null) { return; }
SelectedDASChannel.Channel.Disabled = !SelectedDASChannel.Channel.Disabled;
SelectedDASChannel.Disabled = SelectedDASChannel.Channel.Disabled;
if (SelectedDASChannel.Channel.Disabled)
{
RemoveFromLevelTriggers(SelectedDASChannel.Channel);
}
else
{
AddToLevelTriggers(SelectedDASChannel.Channel);
}
OnPropertyChanged("EnableOrDisableText");
_eventAggregator.GetEvent<TTSImportTestSetupChangedEvent>().Publish(_setup);
}
#endregion
#endregion
}
}

View File

@@ -0,0 +1,162 @@
<base:BaseView x:Class="TTSImport.TOMChannelsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="768" d:DesignWidth="1366"
xmlns:base="clr-namespace:DTS.Common.Base;assembly=DTS.Common"
xmlns:controls="clr-namespace:DTS.Common.Controls;assembly=DTS.Common"
xmlns:converters="clr-namespace:DTS.Common.Converters;assembly=DTS.Common"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:strings="clr-namespace:TTSImport"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
<base:BaseView.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Themes/CommonStyles.xaml"/>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Controls/combobox.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="ListView">
<Setter Property="ItemContainerStyle" Value="{StaticResource TTS_ListViewItemStyle}"/>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource TTS_TextBoxStyle}"/>
<Style TargetType="TextBlock" BasedOn="{StaticResource TTS_TextBlockStyle}"/>
<Style TargetType="CheckBox" BasedOn="{StaticResource PageContentCheckBoxStyle}" />
<Style TargetType="ComboBox" BasedOn="{StaticResource TTS_ComboBoxStyle}"/>
<Style TargetType="Button" BasedOn="{StaticResource TTS_ButtonStyle}"/>
<Style TargetType="GridViewColumnHeader" BasedOn="{StaticResource Gray_GridViewColumnHeaderStyle}"/>
<Style TargetType="xctk:DoubleUpDown" BasedOn="{StaticResource PageContentXCDoubleUpDown}">
<Setter Property="UpdateValueOnEnterKey" Value="True" />
</Style>
<BooleanToVisibilityConverter x:Key="BoolToVisibility" />
</ResourceDictionary>
</base:BaseView.Resources>
<Grid Background="{DynamicResource Brush_ApplicationContentBackground}"
ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<WrapPanel Orientation="Vertical" VerticalAlignment="Center" Grid.Column="1">
<Button Content="{strings:TranslateExtension Analog_Assign}" IsEnabled="{Binding AssignEnabled}" Width="85" AutomationProperties.AutomationId="TOM_AssignButton">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding AssignCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Content="{strings:TranslateExtension Analog_Remove}" IsEnabled="{Binding RemoveEnabled}" Width="85" AutomationProperties.AutomationId="TOM_RemoveButton">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding RemoveCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Content="{Binding EnableOrDisableText,FallbackValue=Enable}" IsEnabled="{Binding EnableOrDisableEnabled}" Width="85" AutomationProperties.AutomationId="TOM_EnableDisableButton">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding EnableOrDisableCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</WrapPanel>
<GroupBox Header="{strings:TranslateExtension RemainingChannels}" AutomationProperties.AutomationId="RemainingChannelsGroupBox" Grid.Column="2">
<ListView ItemsSource="{Binding RemainingChannels}" SelectedItem="{Binding SelectedRemainingChannel}" AutomationProperties.AutomationId="RemainingChannelsListView">
<ListView.View>
<GridView AutomationProperties.AutomationId="RemainingChannelsGridView">
<GridViewColumn Header="{strings:TranslateExtension ToyotaCode}" >
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock MinWidth="130" Text="{Binding ChannelCode}" AutomationProperties.AutomationId="RemainingChannelsChannelCode"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</GroupBox>
<GroupBox Header="{strings:TranslateExtension DASChannels}" AutomationProperties.AutomationId="DASChannelsGroupBox" Grid.Column="0">
<ListView ItemsSource="{Binding DASChannels}" SelectedItem="{Binding SelectedDASChannel}" AutomationProperties.AutomationId="DASChannelsListView">
<ListView.View>
<controls:AutoSizedGridView AutomationProperties.AutomationId="DASChannelsGridView">
<GridViewColumn Header="{strings:TranslateExtension DASChannel}" AutomationProperties.AutomationId="DASChannel">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding DASChannelString}" MinWidth="230" AutomationProperties.AutomationId="DASChannelTextBlock"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Code}" AutomationProperties.AutomationId="ToyotaCode">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBox Text="{Binding ToyotaCode}" MinWidth="70" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="ToyotaCodeTextBox"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension JHyphenCode}" AutomationProperties.AutomationId="Name">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBox Text="{Binding Name}" MinWidth="140" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="NameTextBox"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Mode}" AutomationProperties.AutomationId="Mode">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<ComboBox MinWidth="270" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="ModeComboBox"
ItemsSource="{Binding SquibFireModes}" SelectedItem="{Binding SquibFireMode, UpdateSourceTrigger=PropertyChanged}" Padding="0" Height="28"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Current}" AutomationProperties.AutomationId="Current">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<xctk:DoubleUpDown Value="{Binding SquibFireCurrent}" MinWidth="70" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="CurrentUpDown"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Delay}" AutomationProperties.AutomationId="Delay">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<xctk:DoubleUpDown Value="{Binding SquibFireDelayMs}" MinWidth="70" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="DelayUpDown" Minimum="0" Maximum="99000"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension LimitDuration}" AutomationProperties.AutomationId="LimitDuration">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<CheckBox MinWidth="70" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="LimitDurationCheckBox" IsChecked="{Binding LimitDuration}"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Duration}" AutomationProperties.AutomationId="Duration">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<xctk:DoubleUpDown Value="{Binding SquibFireDurationMs}" MinWidth="70" Visibility="{Binding LimitDuration, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="DurationUpDown" Minimum=".20" Maximum="25.5"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension ResLowTolerance}" AutomationProperties.AutomationId="ResLowTolerance">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<xctk:DoubleUpDown Value="{Binding SquibFireResistanceLowOhm}" MinWidth="70" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="ResLowToleranceUpDown" Maximum="8" Minimum="1"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension ResHighTolerance}" AutomationProperties.AutomationId="ResHighTolerance">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<xctk:DoubleUpDown Value="{Binding SquibFireResistanceHighOhm}" MinWidth="70" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="ResHighToleranceUpDown" Maximum="8" Minimum="1"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</controls:AutoSizedGridView>
</ListView.View>
</ListView>
</GroupBox>
</Grid>
</base:BaseView>

View File

@@ -0,0 +1,20 @@
using System;
using System.Windows.Markup;
namespace TTSImport
{
[MarkupExtensionReturnTypeAttribute(typeof(string))]
public class TranslateExtension : MarkupExtension
{
private readonly string _key;
public TranslateExtension(string key) { _key = key; }
public const string NotFound = "#stringnotfound#";
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (string.IsNullOrEmpty(_key)) { return NotFound; }
return Resources.StringResources.ResourceManager.GetString(_key) ?? NotFound + " " + _key;
}
}
}

View File

@@ -0,0 +1,9 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="TTSImport.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="DefaultTestImportMethod" Type="System.Int32" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="TTSImport.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
</sectionGroup>
</configSections>
<userSettings>
<TTSImport.Properties.Settings>
<setting name="DefaultTestImportMethod" serializeAs="String">
<value>0</value>
</setting>
</TTSImport.Properties.Settings>
</userSettings>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/></startup></configuration>

View File

@@ -0,0 +1,87 @@
<base:BaseView x:Class="TTSImport.DigitalOutputChannelsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="768" d:DesignWidth="1366"
xmlns:controls="clr-namespace:DTS.Common.Controls;assembly=DTS.Common"
xmlns:converters="clr-namespace:DTS.Common.Converters;assembly=DTS.Common"
xmlns:base="clr-namespace:DTS.Common.Base;assembly=DTS.Common"
xmlns:strings="clr-namespace:TTSImport"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
<base:BaseView.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Themes/CommonStyles.xaml"/>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Controls/combobox.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="ListView">
<Setter Property="ItemContainerStyle" Value="{StaticResource TTS_ListViewItemStyle}"/>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource TTS_TextBoxStyle}"/>
<Style TargetType="TextBlock" BasedOn="{StaticResource TTS_TextBlockStyle}"/>
<Style TargetType="CheckBox" BasedOn="{StaticResource PageContentCheckBoxStyle}" />
<Style TargetType="ComboBox" BasedOn="{StaticResource TTS_ComboBoxStyle}"/>
<Style TargetType="Button" BasedOn="{StaticResource TTS_ButtonStyle}"/>
<Style TargetType="GridViewColumnHeader" BasedOn="{StaticResource Gray_GridViewColumnHeaderStyle}"/>
<converters:BooleanToVisibilityConverter x:Key="BoolToVisibility" />
</ResourceDictionary>
</base:BaseView.Resources>
<Grid Background="{DynamicResource Brush_ApplicationContentBackground}">
<GroupBox Header="{strings:TranslateExtension DASChannels}" AutomationProperties.AutomationId="DODASChannelsGroupBox">
<ListView ItemsSource="{Binding DASChannels}" SelectedItem="{Binding SelectedDASChannel}" AutomationProperties.AutomationId="DASChannelsListView">
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Disabled}" Value="True">
<Setter Property="Background" Value="Gray" />
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Resources>
<ListView.View>
<controls:AutoSizedGridView AutomationProperties.AutomationId="DASChannelsGridView">
<GridViewColumn Header="{strings:TranslateExtension DASChannel}">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding DASChannelString}" MinWidth="230" AutomationProperties.AutomationId="DASChannelTextBlock"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Mode}" AutomationProperties.AutomationId="Mode">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<ComboBox MinWidth="270" AutomationProperties.AutomationId="ModeComboBox" ItemsSource="{Binding OutputModes}" SelectedItem="{Binding DigitalOutputMode, UpdateSourceTrigger=PropertyChanged}" Padding="0" Height="28"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Delay}" AutomationProperties.AutomationId="Delay">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<xctk:DoubleUpDown Value="{Binding DigitalOutputDelayMs}" MinWidth="70" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="DelayUpDown" Minimum="0" Maximum="99000"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension LimitDuration}" AutomationProperties.AutomationId="LimitDuration">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<CheckBox MinWidth="70" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="LimitDurationCheckBox" IsChecked="{Binding LimitDuration}"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Duration}" AutomationProperties.AutomationId="Duration">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<xctk:DoubleUpDown Value="{Binding DigitalOutputDurationMs}" MinWidth="70" Visibility="{Binding LimitDuration, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="DurationUpDown" />
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</controls:AutoSizedGridView>
</ListView.View>
</ListView>
</GroupBox>
</Grid>
</base:BaseView>

View File

@@ -0,0 +1,93 @@
<base:BaseView x:Class="TTSImport.LevelTriggerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:base="clr-namespace:DTS.Common.Base;assembly=DTS.Common"
xmlns:strings="clr-namespace:TTSImport"
xmlns:xceed="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit"
xmlns:controls="clr-namespace:DTS.Common.Controls;assembly=DTS.Common"
xmlns:converters="clr-namespace:DTS.Common.Converters;assembly=DTS.Common"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="768" d:DesignWidth="1366">
<base:BaseView.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Themes/CommonStyles.xaml"/>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Controls/combobox.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="ListView">
<Setter Property="ItemContainerStyle" Value="{StaticResource TTS_ListViewItemStyle}"/>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource TTS_TextBoxStyle}"/>
<Style TargetType="TextBlock" BasedOn="{StaticResource TTS_TextBlockStyle}"/>
<Style TargetType="CheckBox" BasedOn="{StaticResource PageContentCheckBoxStyle}" />
<Style TargetType="ComboBox" BasedOn="{StaticResource TTS_ComboBoxStyle}"/>
<Style TargetType="Button" BasedOn="{StaticResource TTS_ButtonStyle}"/>
<Style TargetType="GridViewColumnHeader" BasedOn="{StaticResource Gray_GridViewColumnHeaderStyle}"/>
<BooleanToVisibilityConverter x:Key="BoolToVisibility" />
</ResourceDictionary>
</base:BaseView.Resources>
<Grid Background="{DynamicResource Brush_ApplicationContentBackground}" >
<ListView ItemsSource="{Binding LevelTriggers, UpdateSourceTrigger=PropertyChanged}" AutomationProperties.AutomationId="LevelTriggersListView">
<ListView.View>
<controls:AutoSizedGridView AutomationProperties.AutomationId="LevelTriggersGridView">
<GridViewColumn Header="{strings:TranslateExtension Code}" AutomationProperties.AutomationId="ChannelCode">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<ComboBox SelectedItem="{Binding Channel}" ItemsSource="{Binding AvailableChannels, UpdateSourceTrigger=PropertyChanged}"
MinWidth="235" DisplayMemberPath="ChannelCode" AutomationProperties.AutomationId="ChannelCodeComboBox"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension JHyphenCode}" >
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock MinWidth="80" Text="{Binding JCode,FallbackValue='JCODE'}" AutomationProperties.AutomationId="JCode"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension ValuePercent}" AutomationProperties.AutomationId="ValuePercent">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<xceed:DoubleUpDown Value="{Binding ValuePercent}" MinWidth="70" DefaultValue="0"
Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="ValuePercentUpDown"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension ValueEU}" AutomationProperties.AutomationId="ValueEU">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<xceed:DoubleUpDown Value="{Binding ValueEU}" MinWidth="70" DefaultValue="0"
Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="ValueEUUpDown"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension EULabel}" AutomationProperties.AutomationId="EU">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock MinWidth="100" Text="{Binding EULabel}" AutomationProperties.AutomationId="EUTextBlock" />
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension HWSerialNumber}" AutomationProperties.AutomationId="HWChannelInfo">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock MinWidth="250" Text="{Binding HWSerialNumber}" AutomationProperties.AutomationId="HWChannelInfoTextBlock" />
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension CHAN}" AutomationProperties.AutomationId="ChannelNumber">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding ChannelNumber,FallbackValue='001',StringFormat={}{0:000}}" AutomationProperties.AutomationId="ChannelNumberTextBlock" MinWidth="85" TextAlignment="Right"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</controls:AutoSizedGridView>
</ListView.View>
</ListView>
</Grid>
</base:BaseView>

View File

@@ -0,0 +1,17 @@
using DTS.Common.Interface.TestSetups.Imports.TTS;
// ReSharper disable CheckNamespace
namespace TTSImport
{
/// <summary>
/// Interaction logic for HardwareScanView.xaml
/// </summary>
public partial class TOMChannelsView : ITOMChannelsView
{
public TOMChannelsView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,38 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TTSImport.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.10.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
public int DefaultTestImportMethod {
get {
return ((int)(this["DefaultTestImportMethod"]));
}
set {
this["DefaultTestImportMethod"] = value;
}
}
}
}

View File

@@ -0,0 +1,117 @@
<base:BaseView x:Class="TTSImport.DigitalInputChannelsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:base="clr-namespace:DTS.Common.Base;assembly=DTS.Common"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:strings="clr-namespace:TTSImport"
xmlns:controls="clr-namespace:DTS.Common.Controls;assembly=DTS.Common"
xmlns:converters="clr-namespace:DTS.Common.Converters;assembly=DTS.Common"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="768" d:DesignWidth="1366">
<base:BaseView.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Themes/CommonStyles.xaml"/>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Controls/combobox.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="ListView">
<Setter Property="ItemContainerStyle" Value="{StaticResource TTS_ListViewItemStyle}"/>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource TTS_TextBoxStyle}"/>
<Style TargetType="TextBlock" BasedOn="{StaticResource TTS_TextBlockStyle}"/>
<Style TargetType="CheckBox" BasedOn="{StaticResource PageContentCheckBoxStyle}" />
<Style TargetType="ComboBox" BasedOn="{StaticResource TTS_ComboBoxStyle}"/>
<Style TargetType="Button" BasedOn="{StaticResource TTS_ButtonStyle}"/>
<Style TargetType="GridViewColumnHeader" BasedOn="{StaticResource Gray_GridViewColumnHeaderStyle}"/>
<converters:BooleanToVisibilityConverter x:Key="BoolToVisibility" />
</ResourceDictionary>
</base:BaseView.Resources>
<Grid Background="{DynamicResource Brush_ApplicationContentBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<GroupBox Header="{strings:TranslateExtension DASChannels}" AutomationProperties.AutomationId="DASChannelsGroupBox" Grid.Column="0">
<ListView ItemsSource="{Binding DASChannels}" SelectedItem="{Binding SelectedDASChannel}" AutomationProperties.AutomationId="DASChannelsListView">
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Disabled}" Value="True">
<Setter Property="Background" Value="Gray" />
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Resources>
<ListView.View>
<controls:AutoSizedGridView AutomationProperties.AutomationId="DASChannelsGridView">
<GridViewColumn Header="{strings:TranslateExtension DASChannel}" AutomationProperties.AutomationId="DASChannel">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding DASChannelString}" MinWidth="230" AutomationProperties.AutomationId="DASChannelTextBlock"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Code}" AutomationProperties.AutomationId="ToyotaCode">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBox Text="{Binding ToyotaCode}" MinWidth="70" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="ToyotaCodeTextBox"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension JHyphenCode}" AutomationProperties.AutomationId="Name">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBox Text="{Binding Name}" MinWidth="140" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="NameTextBox"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</controls:AutoSizedGridView>
</ListView.View>
</ListView>
</GroupBox>
<StackPanel Orientation="Vertical" VerticalAlignment="Center" Grid.Column="1">
<Button Content="{strings:TranslateExtension Analog_Assign}" IsEnabled="{Binding AssignEnabled}" Width="85" AutomationProperties.AutomationId="DI_AssignButton">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding AssignCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Content="{strings:TranslateExtension Analog_Remove}" IsEnabled="{Binding RemoveEnabled}" Width="85" AutomationProperties.AutomationId="DI_RemoveButton">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding RemoveCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Content="{Binding EnableOrDisableText,FallbackValue=Enable}" IsEnabled="{Binding EnableOrDisableEnabled}" Width="85" AutomationProperties.AutomationId="DI_EnableDisableButton">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding EnableOrDisableCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
<GroupBox Header="{strings:TranslateExtension RemainingChannels}" AutomationProperties.AutomationId="RemainingChannelsGroupBox" Grid.Column="2">
<ListView ItemsSource="{Binding RemainingChannels}" SelectedItem="{Binding SelectedRemainingChannel}" AutomationProperties.AutomationId="RemainingChannelsListView">
<ListView.View>
<controls:AutoSizedGridView AutomationProperties.AutomationId="RemainingChannelsGridView">
<GridViewColumn Header="{strings:TranslateExtension ToyotaCode}" AutomationProperties.AutomationId="ToyotaCode">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding ChannelCode}" MinWidth="130" AutomationProperties.AutomationId="ToyotaCodeTextBlock"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</controls:AutoSizedGridView>
</ListView.View>
</ListView>
</GroupBox>
</Grid>
</base:BaseView>

View File

@@ -0,0 +1,613 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using DTS.Common.Base;
using DTS.Common.Classes;
using DTS.Common.Events;
using DTS.Common.Events.TTSImport;
using DTS.Common.Interface;
using DTS.Common.Interface.DataRecorders;
using DTS.Common.Interface.TestSetups.Imports.TTS.HardwareScan;
using DTS.Common.Interface.TestSetups.Imports.TTS.ReadFile;
using DTS.Common.Utilities.Logging;
using Prism.Events;
using Unity;
using DTS.Common.Interactivity;
using Prism.Regions;
using Prism.Commands;
using TTSImport.Model;
// ReSharper disable CheckNamespace
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable InconsistentNaming
namespace TTSImport
{
/// <summary>
/// this class handles Hardware Scan functionality
/// </summary>
[PartCreationPolicy(CreationPolicy.Shared)]
public class HardwareScanViewModel : IHardwareScanViewModel
{
/// <summary>
/// The Status and Progress bars
/// </summary>
public IStatusAndProgressBarView StatusAndProgressBarView { get; private set; }
/// <summary>
/// The Hardware Scan view
/// </summary>
public IHardwareScanView View { get; set; }
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="hardwareScanView">The Hardware Scan 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 HardwareScanViewModel(IHardwareScanView hardwareScanView, IRegionManager regionManager,
IEventAggregator eventAggregator, IUnityContainer unityContainer)
{
View = hardwareScanView;
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);
_eventAggregator.GetEvent<TTSImportHardwareScanFinishedEvent>().Subscribe(OnHardwareScanFinished, ThreadOption.PublisherThread, true);
_eventAggregator.GetEvent<AssignedChannelsChangedEvent>().Subscribe(OnAssignedChannelsChangedEvent, ThreadOption.PublisherThread, true);
}
#region Methods
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()
{
StatusAndProgressBarView = GetStatusAndProgressBarView(this);
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
});
}
private readonly StatusAndProgressBarEventArgs statusAndProgressBarEventArgs = new StatusAndProgressBarEventArgs();
/// <summary>
/// Sets the text, background color, progress value, and/or progress visibility
/// </summary>
/// <param name="status"></param>
public void SetStatus(string status)
{
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.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;
}
private void OnReadFileFinished(ReadFileStatusArg statusArg)
{
if (statusArg.Status)
{
_setup = statusArg.TTSSetup;
}
}
public void HardwareScan()
{
SetStatus(Resources.StringResources
.ImportTestSetup_PossibleStatus_Working); //use string resource (same both here and where passed)
var data = new WorkFunctionThreadData();
ThreadPool.QueueUserWorkItem(HardwareScanWorkThread, data);
}
void HardwareScanWorkThread(object obj)
{
ITTSSetup temp = null;
//Blank out the tables before re-scanning
HardwareRecords[0].Update(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
DasSummaryList = new List<IDASHardware>();
ChannelSummaryList = new List<ChannelSummary>();
_eventAggregator.GetEvent<TTSImportHardwareScanRunEvent>().Publish(temp); //temp not needed?
}
private void UpdateUnitCount(IDASHardware hardwareRecord, ref uint sps, ref uint spd, ref uint spt, ref uint ecm,
ref uint g5, ref uint rack)
{
if (hardwareRecord.SerialNumber.Length < 3)
{
return;
}
var firstThree = hardwareRecord.SerialNumber.Substring(0, 3).ToLower();
switch (firstThree)
{
case "spt": spt++; break;
case "spd": spd++; break;
case "sps": sps++; break;
case "spe": ecm++; break;
case "slt": spt++; break;
case "sld": spd++; break;
case "sle": ecm++; break;
case "sls": sps++; break;
case "sg5": g5++; break;
}
var firstTwo = hardwareRecord.SerialNumber.Substring(0, 2).ToLower();
switch (firstTwo)
{
case "dr": rack++; break;
case "lr": rack++; break;
case "5m": g5++; break;
}
}
/// <summary>
/// returns IP addresses for which SLICE2 modules have been found without a corresponding ECM/SLE
/// </summary>
/// <param name="hardwareRecords"></param>
/// <returns></returns>
private static IEnumerable<string> GetMissingECMIPAddresses(List<IDASHardware> hardwareRecords)
{
var foundECMIPAddresses = new HashSet<string>();
var missingECMIPAddresses = new List<string>();
foreach (var hardwareRecord in hardwareRecords)
{
if (!hardwareRecord.IsSLICEEthernetController) continue;
var ipAddress = hardwareRecord.Connection;
var index = ipAddress.IndexOf(':');
if (index > 0)
{
ipAddress = ipAddress.Substring(0, index);
}
foundECMIPAddresses.Add(ipAddress);
}
foreach (var hardwareRecord in hardwareRecords)
{
if (hardwareRecord.SerialNumber.Length < 3) { continue; }
var ipAddress = hardwareRecord.Connection.ToLower();
var index = ipAddress.IndexOf(':');
if (index > 0)
{
ipAddress = ipAddress.Substring(0, index);
}
if (foundECMIPAddresses.Contains(ipAddress)) { continue; }
if (missingECMIPAddresses.Contains(ipAddress)) { continue; }
var firstThree = hardwareRecord.SerialNumber.Substring(0, 3).ToLower();
switch (firstThree)
{
case "spt":
case "spd":
case "sps":
case "slt":
case "sld":
case "sls":
if (ipAddress.Contains("usb") || ipAddress.Length < 6) { continue; }
missingECMIPAddresses.Add(ipAddress);
break;
}
}
return missingECMIPAddresses;
}
/// <summary>
/// Fill in the table of DAS that are in the database and connected
/// </summary>
/// <param name="hardwareRecords"></param>
private void OnHardwareScanFinished(List<IDASHardware> hardwareRecords)
{
//Create mapping from IP address to ECM/SDB/Rack
var connectionToParent =
hardwareRecords.Where(hardwareRecord => hardwareRecord.IsSLICEEthernetController ||
hardwareRecord.IsTDASRack()).ToDictionary(hardwareRecord => hardwareRecord.Connection, hardwareRecord => hardwareRecord.SerialNumber);
var moduleRecords = new List<IDASHardware>();
uint analog = 0;
uint din = 0;
uint dout = 0;
uint squib = 0;
uint sps = 0;
uint spd = 0;
uint spt = 0;
uint ecm = 0;
uint g5 = 0;
uint rack = 0;
var missingECMIPS = GetMissingECMIPAddresses(hardwareRecords);
if (missingECMIPS.Any())
{
var prompt = $"{Resources.StringResources.MissingECMSWarning}\r\n";
prompt += string.Join("\r\n", missingECMIPS.ToArray());
var mreLocal = new ManualResetEvent(false);
APILogger.Log("MessageBox", prompt);
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
var window = Application.Current.MainWindow;
if (null == window)
{
return;
}
MessageBox.Show(window, prompt, Resources.StringResources.Warning,
MessageBoxButton.OK, MessageBoxImage.Warning);
mreLocal.Set();
}));
mreLocal.WaitOne();
}
foreach (var hardwareRecord in hardwareRecords)
{
//We don't want to list bridges, but we do want to list modules in a TDAS Rack, and DAS connected via ECM, SDB, and USB.
//Modules in a TDAS Rack have IsModule() == false.
//DAS connected via ECM or SDB have a hardwareRecord.Connection that's in the connectionToParent dictionary above.
//DAS connected via USB have a hardwareRecord.Connection == "USB".
if (hardwareRecord.IsModule() &&
!connectionToParent.ContainsKey(hardwareRecord.Connection) &&
hardwareRecord.Connection != "USB") continue;
UpdateUnitCount(hardwareRecord, ref sps, ref spd, ref spt, ref ecm, ref g5, ref rack);
//We want to display TDAS Racks, ECM, and SDBs in a separate row for their battery and
//voltage status but also as a parent of their connected DAS.
if (!hardwareRecord.IsSLICEEthernetController && !hardwareRecord.IsTDASRack())
{
//Display the DAS with its associated parent (TDAS Rack/ECM/SDB)
var parentDAS = connectionToParent.ContainsKey(hardwareRecord.Connection)
? connectionToParent[hardwareRecord.Connection]
: hardwareRecord.ParentDAS;
if (!string.IsNullOrWhiteSpace(parentDAS))
{
//DAS connected via USB have a blank ParentDAS
//When the hardwareRecord.ToString() override is implemented for all DAS types, the following
//can be modified to use it. Currently, only Slice DAS connected via ECM return "<parent>:<das>".
hardwareRecord.SerialNumberFamily = "[" + parentDAS + ":" + hardwareRecord.SerialNumber + "]";
}
else
{
hardwareRecord.SerialNumberFamily = hardwareRecord.SerialNumber;
}
UpdateChannelCount(hardwareRecord, ref analog, ref squib, ref din, ref dout);
}
else
{
hardwareRecord.SerialNumberFamily = hardwareRecord.SerialNumber;
if (hardwareRecord.IsTDASRack())
{
UpdateChannelCount(hardwareRecord, ref analog, ref squib, ref din, ref dout);
}
}
moduleRecords.Add(hardwareRecord);
}
HardwareRecords[0].Update(analog, squib, din, dout, ecm, sps, spt, spd, g5, rack);
DasSummaryList = moduleRecords;
SetStatus(hardwareRecords.Any()
? Resources.StringResources.ImportTestSetup_PossibleStatus_Done
: Resources.StringResources.ImportTestSetup_PossibleStatus_Failed);
}
/// <summary>
/// counts the number of analog/squib/digitalin/digitalout on given hardware and updates count
/// </summary>
/// <param name="hardwareRecord"></param>
/// <param name="analog"></param>
/// <param name="squib"></param>
/// <param name="din"></param>
/// <param name="dout"></param>
private static void UpdateChannelCount(IDASHardware hardwareRecord, ref uint analog, ref uint squib, ref uint din,
ref uint dout)
{
var channels = hardwareRecord.GetIHardwareChannels();
for (var i = 0; i < channels.Length; i++)
{
var ch = channels[i];
if (ch.IsAnalog)
{
analog++;
}
else if (ch.IsDigitalIn)
{
din++;
}
else if (ch.IsDigitalOut)
{
dout++;
}
else if (ch.IsSquib)
{
squib++;
i++;//skip the next squib
}
}
}
/// <summary>
/// Sets a global dictionary to be used by SetChannelSummaryList
/// </summary>
private void OnAssignedChannelsChangedEvent(ITTSSetup setup)
{
SetChannelSummaryList(_setup.Channels);
}
/// <summary>
/// Fill in the table of channels that were found in the Read File step
/// </summary>
/// <param name="channelRecords"></param>
public void SetChannelSummaryList(ITTSChannelRecord[] channelRecords)
{
const int Requested = 0;
const int Assigned = 1;
const int Unassigned = 2;
var tomChannels = new[] { 0, 0, 0 };
var digitalInChannels = new[] { 0, 0, 0 };
var analogChannels = new[] { 0, 0, 0 };
foreach (var channelRecord in channelRecords)
{
if (string.Equals(channelRecord.ChannelCode, TTSChannelRecord.NONE, StringComparison.CurrentCultureIgnoreCase)) continue;
if (channelRecord.IsSquib)
{
tomChannels[Requested] += 1;
if (channelRecord.HardwareChannel != null && channelRecord.HardwareChannel.IsSquib)
{
tomChannels[Assigned] += 1;
}
else
{
tomChannels[Unassigned] += 1;
}
}
else if (channelRecord.IsDigitalInput)
{
digitalInChannels[Requested] += 1;
if (channelRecord.HardwareChannel != null && channelRecord.HardwareChannel.IsDigitalIn)
{
digitalInChannels[Assigned] += 1;
}
else
{
digitalInChannels[Unassigned] += 1;
}
}
else if (!channelRecord.IsDigitalOutput)
{
//Must be analog
analogChannels[Requested] += 1;
if (channelRecord.HardwareChannel != null && channelRecord.HardwareChannel.IsAnalog)
{
analogChannels[Assigned] += 1;
}
else
{
analogChannels[Unassigned] += 1;
}
}
}
var temp = new List<ChannelSummary>();
var channel = new ChannelSummary
{
ChannelType = Resources.StringResources.Analog,
Requested = analogChannels[Requested],
Assigned = analogChannels[Assigned],
Unassigned = analogChannels[Unassigned],
};
temp.Add(channel);
channel = new ChannelSummary
{
ChannelType = Resources.StringResources.TOM,
Requested = tomChannels[Requested],
Assigned = tomChannels[Assigned],
Unassigned = tomChannels[Unassigned],
};
temp.Add(channel);
channel = new ChannelSummary
{
ChannelType = Resources.StringResources.DigitalIn,
Requested = digitalInChannels[Requested],
Assigned = digitalInChannels[Assigned],
Unassigned = digitalInChannels[Unassigned],
};
temp.Add(channel);
ChannelSummaryList = temp;
}
#endregion
#region Properties
private ITTSSetup _setup;
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");
}
}
private List<IDASHardware> _dasSummaryList = new List<IDASHardware>();
public List<IDASHardware> DasSummaryList
{
get => _dasSummaryList;
set
{
_dasSummaryList = value;
OnPropertyChanged("DasSummaryList");
}
}
private readonly IHardwareSummaryRecord[] _hardwareRecords = { new HardwareSummaryRecord() };
public IHardwareSummaryRecord[] HardwareRecords => _hardwareRecords;
private List<ChannelSummary> _channelSummaryList = new List<ChannelSummary>();
public List<ChannelSummary> ChannelSummaryList
{
get => _channelSummaryList;
set
{
_channelSummaryList = value;
OnPropertyChanged("ChannelSummaryList");
}
}
#endregion Properties
#region Commands
#endregion
///<summary>
///Occurs when a property value changes.
///</summary>
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -0,0 +1,481 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using DTS.Common.Events;
using DTS.Common.Events.TTSImport;
using DTS.Common.Interface.DataRecorders;
using DTS.Common.Interface.TestSetups.Imports.TTS.DIChannels;
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;
// ReSharper disable CheckNamespace
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable InconsistentNaming
namespace TTSImport
{
/// <summary>
/// this class handles Level Trigger edit/create functionality
/// </summary>
[PartCreationPolicy(CreationPolicy.Shared)]
public class DigitalInputChannelsViewModel : IDigitalInputChannelsViewModel
{
/// <summary>
/// The Hardware Scan view
/// </summary>
public IDigitalInputChannelsView View { get; set; }
private IEventAggregator _eventAggregator { get; }
private IRegionManager _regionManager;
private IUnityContainer UnityContainer { get; }
public InteractionRequest<Notification> NotificationRequest { get; }
public InteractionRequest<Confirmation> ConfirmationRequest { get; }
/// <summary>
/// Creates a new instance of the TechnologyDomainEditViewModel.
/// </summary>
/// <param name="view">The IDigitalInputChannelsView.</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 DigitalInputChannelsViewModel(IDigitalInputChannelsView 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<AssignedChannelsChangedEvent>().Subscribe(OnAssignedChannelsChangedEvent,
ThreadOption.PublisherThread, true);
_eventAggregator.GetEvent<TTSImportHardwareScanFinishedEvent>()
.Subscribe(OnHardwareScanComplete, ThreadOption.PublisherThread, true);
}
#region Methods
private void OnHardwareScanComplete(List<IDASHardware> hardware)
{
_hardware = hardware;
}
private void OnAssignedChannelsChangedEvent(ITTSSetup setup)
{
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
OnAssignedChannelsChangedEvent(setup);
}));
return;
}
_setup = setup;
if (null == _hardware || null == _setup) { return; }
var channels = new ObservableCollection<DASChannel>();
var remainingChannels = new ObservableCollection<ITTSChannelRecord>();
var channelIdToChannelRecord = new Dictionary<string, DASChannel>();
foreach (var das in _hardware)
{
var ichannels = das.GetIHardwareChannels();
foreach (var ch in ichannels)
{
if (!ch.IsDigitalIn) { continue; }
var newChannel = new DASChannel(ch);
channels.Add(newChannel);
channelIdToChannelRecord[ch.GetId()] = newChannel;
}
}
foreach (var channelRecord in _setup.Channels)
{
if (channelRecord.IsEmptyRecord)
{
continue;
}
if (!channelRecord.IsDigitalInput)
{
continue;
}
if (!channelRecord.IsChannelCodeValid)
{
continue;
}
if (channelRecord.ChannelCode == TTSChannelRecord.NONE)
{
continue;
}
if (null != channelRecord.HardwareChannel &&
channelIdToChannelRecord.ContainsKey(channelRecord.HardwareChannel.GetId()))
{
channelIdToChannelRecord[channelRecord.HardwareChannel.GetId()].SetITTSChannelRecord(channelRecord);
}
else
{
remainingChannels.Add(channelRecord);
}
}
DASChannels = channels;
RemainingChannels = remainingChannels;
OnPropertyChanged("DASChannels");
OnPropertyChanged("RemainingChannels");
}
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
private ITTSSetup _setup;
private IList<IDASHardware> _hardware;
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");
}
}
public bool AssignEnabled { get; set; }
public bool RemoveEnabled { get; set; }
public bool EnableOrDisableEnabled { get; set; }
public ObservableCollection<DASChannel> DASChannels { get; set; } = new ObservableCollection<DASChannel>();
public ObservableCollection<ITTSChannelRecord> RemainingChannels { get; set; } =
new ObservableCollection<ITTSChannelRecord>();
private ITTSChannelRecord _selectedRemainingChannel;
public ITTSChannelRecord SelectedRemainingChannel
{
get => _selectedRemainingChannel;
set
{
_selectedRemainingChannel = value;
if (null == _selectedRemainingChannel || null == SelectedDASChannel) return;
AssignEnabled = true;
OnPropertyChanged("AssignEnabled");
}
}
private DASChannel _selectedDASChannel;
public DASChannel SelectedDASChannel
{
get => _selectedDASChannel;
set
{
_selectedDASChannel = value;
DetermineRemoveEnableStatus();
}
}
private void DetermineRemoveEnableStatus()
{
if (_selectedDASChannel?.Channel != null)
{
if (!string.IsNullOrWhiteSpace(_selectedDASChannel.EID) &&
_selectedDASChannel.EID == _selectedDASChannel.Channel.SensorEID)
{
//can only be replaced, can't be removed
RemoveEnabled = false;
}
RemoveEnabled = true;
}
else
{
RemoveEnabled = false;
}
OnPropertyChanged("RemoveEnabled");
AssignEnabled = null != _selectedDASChannel && null != _selectedRemainingChannel;
OnPropertyChanged("AssignEnabled");
EnableOrDisableEnabled = _selectedDASChannel?.Channel != null;
OnPropertyChanged("EnableOrDisableEnabled");
OnPropertyChanged("EnableOrDisableText");
}
public string EnableOrDisableText
{
get
{
if (SelectedDASChannel?.Channel == null)
{
return StringResources.Analog_Enable;
}
return SelectedDASChannel.Channel.Disabled
? StringResources.Analog_Enable
: StringResources.Analog_Disable;
}
}
#endregion Properties
#region Commands
#region assign
/// <summary>
/// Assign a channel code to a channel
/// </summary>
private DelegateCommand _assignCommand;
public DelegateCommand AssignCommand => _assignCommand ?? (_assignCommand = new DelegateCommand(Assign));
private void Assign()
{
if (SelectedRemainingChannel == null) { return; }
_eventAggregator.GetEvent<TTSImportTestSetupChangedEvent>().Publish(_setup);
//BEFORE we go any further, check the state of sensor ids
//if the channel has a sensor id AND there's a sensor on the channel with the same id
//then prompt on replacing the id
//IF the channel has a sensor id and there's no sensor on the channel BUT the new sensor has a different id
//then prompt on replacing the id
var bReplacingID = false;
if (!string.IsNullOrWhiteSpace(SelectedDASChannel.EID))
{
if (null != SelectedRemainingChannel && SelectedRemainingChannel.SensorEID != SelectedDASChannel.EID)
{
bReplacingID = true;
}
//if existing channel has this ID, we will need to clear out the old id and assign a new one...
if (null != SelectedDASChannel.Channel && SelectedDASChannel.Channel.SensorEID == SelectedDASChannel.EID)
{
bReplacingID = true;
}
}
if (bReplacingID)
{
Task.Run(() =>
{
var dialogResult = MessageBox.Show(StringResources.AssignSensorPrompt, StringResources.UserFeedbackRequired, MessageBoxButton.YesNo);
if (dialogResult == MessageBoxResult.Yes)
{
Application.Current.Dispatcher.BeginInvoke(new Action(AssignWork));
}
});
return;
}
AssignWork();
}
/// <summary>
/// assigns a channel record to a physical channel
/// </summary>
private void AssignWork()
{
if (null != SelectedDASChannel.Channel)
{
if (!string.IsNullOrWhiteSpace(SelectedDASChannel.EID))
{
SelectedDASChannel.Channel.SensorEID = "";
}
RemainingChannels.Add(SelectedDASChannel.Channel);
}
if (!string.IsNullOrWhiteSpace(SelectedDASChannel.EID))
{
SelectedRemainingChannel.SensorEID = SelectedDASChannel.EID;
}
SelectedRemainingChannel.DigitalInputMode = DTS.Common.Enums.DigitalInputModes.CCNO;
SelectedDASChannel.SetITTSChannelRecord(SelectedRemainingChannel);
var channel = SelectedRemainingChannel;
var index = RemainingChannels.IndexOf(channel);
SelectedRemainingChannel = null;
RemainingChannels.Remove(channel);
CollectionViewSource.GetDefaultView(DASChannels)?.Refresh();
if (index < RemainingChannels.Count)
{
SelectedRemainingChannel = RemainingChannels[index];
OnPropertyChanged("SelectedRemainingChannel");
}
else if (RemainingChannels.Count > 0)
{
SelectedRemainingChannel = RemainingChannels[index - 1];
OnPropertyChanged("SelectedRemainingChannel");
}
index = DASChannels.IndexOf(SelectedDASChannel);
for (var i = index; i < DASChannels.Count; i++)
{
var dasChannel = DASChannels[i];
if (null != dasChannel.Channel) { continue; }
SelectedDASChannel = dasChannel;
OnPropertyChanged("SelectedDASChannel");
return;
}
//didn't find a match, start from the beginning?
for (var i = 0; i < index; i++)
{
var dasChannel = DASChannels[i];
if (null != dasChannel.Channel)
{
continue;
}
SelectedDASChannel = dasChannel;
OnPropertyChanged("SelectedDASChannel");
return;
}
//if we get here there's no new channel to go to, but we need to set the remove/enable/disable button status
OnPropertyChanged("SelectedDASChannel");
DetermineRemoveEnableStatus();
}
#endregion
#region remove
private DelegateCommand _removeCommand;
public DelegateCommand RemoveCommand => _removeCommand ?? (_removeCommand = new DelegateCommand(Remove));
/// <summary>
/// remove a hardware channel assignment (does not remove the channel from the test setup though?)
/// </summary>
private void Remove()
{
if (null == SelectedDASChannel || null == SelectedDASChannel.Channel) { return; }
_eventAggregator.GetEvent<TTSImportTestSetupChangedEvent>().Publish(_setup);
RemainingChannels.Add(SelectedDASChannel.Channel);
SelectedDASChannel.SetITTSChannelRecord(null);
CollectionViewSource.GetDefaultView(DASChannels)?.Refresh();
var index = DASChannels.IndexOf(SelectedDASChannel);
for (var i = index; i < DASChannels.Count; i++)
{
if (null == DASChannels[i].Channel) { continue; }
SelectedDASChannel = DASChannels[i];
OnPropertyChanged("SelectedDASChannel");
return;
}
for (var i = 0; i < index; i++)
{
if (null == DASChannels[i].Channel) { continue; }
SelectedDASChannel = DASChannels[i];
OnPropertyChanged("SelectedDASChannel");
return;
}
//if we get here there's no new channel to go to, but we need to set the remove/enable/disable button status
OnPropertyChanged("SelectedDASChannel");
DetermineRemoveEnableStatus();
}
#endregion
#region enableordisable
private DelegateCommand _enableOrDisableCommand;
public DelegateCommand EnableOrDisableCommand =>
_enableOrDisableCommand ?? (_enableOrDisableCommand = new DelegateCommand(EnableOrDisable));
/// <summary>
/// enables or disables a channel in the test.
/// </summary>
private void EnableOrDisable()
{
if (SelectedDASChannel?.Channel == null) { return; }
SelectedDASChannel.Channel.Disabled = !SelectedDASChannel.Channel.Disabled;
SelectedDASChannel.Disabled = SelectedDASChannel.Channel.Disabled;
OnPropertyChanged("EnableOrDisableText");
_eventAggregator.GetEvent<TTSImportTestSetupChangedEvent>().Publish(_setup);
}
#endregion
#endregion
/// <inheritdoc />
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -0,0 +1,105 @@
using System;
using DTS.Common.Enums;
using DTS.Common.Interface.TestSetups.Imports.TTS.LevelTrigger;
using DTS.Common.Interface.TestSetups.Imports.TTS.ReadFile;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Text;
using DTS.Common.Interface.Sensors;
namespace TTSImport.Model
{
public class TTSTestSetup : ITTSSetup
{
public double SampleRate { get; set; }
public RecordingModes Mode { get; set; }
public double TestLength => PreTrigger + PostTrigger;
public double PreTrigger { get; set; }
public double PostTrigger { get; set; }
public double ROIStart { get; set; }
public double ROIEnd { get; set; }
public string Filename { get; set; }
public string TestId { get; set; }
/// <summary>
/// The first 4 lines of the .csv file are needed if a new .csv is to be created
/// </summary>
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
public string Line4 { get; set; }
public string[] DummyList { get; set; }
public ITTSChannelRecord[] Channels { get; set; }
public ILevelTrigger[] LevelTriggers { get; set; }
public string OriginalImportFile { get; set; }
/// <summary>
/// If True, HybridRecorder is added to CircularBuffer and Recorder as choices.
/// </summary>
public bool AllowAdvancedRecordingModes { get; set; }
/// <summary>
/// if True, Active Ram and Active Ram Multiple events are valid modes
/// http://manuscript.dts.local/f/cases/31841/Add-support-for-Active-RAM-mode
/// </summary>
public bool AllowActiveRecordingModes { get; set; }
public bool AllowTSRAIRRecordingModes { get; set; }
/// <inheritdoc />
/// <summary>
/// allows consumers to specify whether EIDs must be found for sensors to be used
/// </summary>
public bool RequireEIDFound { get; set; }
/// <summary>
/// The value from DataPRO.config.exe
/// </summary>
public string DefaultDigitalInputMode { get; set; }
public ISquibSettingDefaults SquibDefaults { get; set; }
/// <summary>
/// The value from DataPRO.config.exe
/// </summary>
public double DefaultSquibFireDurationMs { get; set; }
/// <summary>
/// this holds sensor to hardware assignments that are pre-existing before the user even scans hardware
/// this can only happen through the XML import
/// the assignments are removed once they are made, but persist across hardware scans until they are made (for instance if the hardware
/// is not present in the first hardwarescan the assignments will remain till the hardware is found).
/// this is not true if the user has already manually assigned the channel
/// </summary>
public Tuple<string, string>[] PreAssignedSensorIdAndHwId { get; set; }
private const int NUM_LEVEL_TRIGGERS = 6;
public TTSTestSetup()
{
DummyList = new string[8];
Channels = new ITTSChannelRecord[0];
LevelTriggers = new ILevelTrigger[NUM_LEVEL_TRIGGERS];
for (var i = 0; i < NUM_LEVEL_TRIGGERS; i++)
{
LevelTriggers[i] = new TTSLevelTriggerRecord(this);
}
}
public new string GetHashCode()
{
var bytes = new List<byte>();
bytes.AddRange(BitConverter.GetBytes(SampleRate));
bytes.AddRange(BitConverter.GetBytes((int)Mode));
bytes.AddRange(BitConverter.GetBytes(PreTrigger));
bytes.AddRange(BitConverter.GetBytes(PostTrigger));
bytes.AddRange(BitConverter.GetBytes(ROIStart));
bytes.AddRange(BitConverter.GetBytes(ROIEnd));
bytes.AddRange(Encoding.UTF8.GetBytes(TestId ?? ""));
foreach (var ch in Channels)
{
bytes.AddRange(ch.GetBytes());
}
foreach (var lt in LevelTriggers)
{
bytes.AddRange(lt.GetBytes());
}
var sha = new SHA256Managed();
var hash = sha.ComputeHash(bytes.ToArray());
var hashString = BitConverter.ToString(hash).Replace("-", string.Empty);
return hashString;
}
}
}

View File

@@ -0,0 +1,21 @@
using DTS.Common.Interface;
namespace TTSImport
{
/// <summary>
/// Interaction logic for ReadFileView.xaml
/// </summary>
public partial class ReadFileView : IReadFileView
{
public ReadFileView()
{
InitializeComponent();
}
public void Connect(int connectionId, object target)
{
}
}
}

View File

@@ -0,0 +1,376 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Data;
using DTS.Common.DAS.Concepts;
using DTS.Common.Enums;
using DTS.Common.Events;
using DTS.Common.Events.TTSImport;
using DTS.Common.Interface;
using DTS.Common.Interface.DataRecorders;
using DTS.Common.Interface.TestSetups.Imports.TTS.LevelTrigger;
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;
// ReSharper disable CheckNamespace
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable InconsistentNaming
namespace TTSImport
{
/// <summary>
/// this class handles Level Trigger edit/create functionality
/// </summary>
[PartCreationPolicy(CreationPolicy.Shared)]
public class LevelTriggerViewModel : ILevelTriggerViewModel
{
/// <summary>
/// The Hardware Scan view
/// </summary>
public ILevelTriggerView View { get; set; }
private IEventAggregator _eventAggregator { get; }
private IRegionManager _regionManager;
private IUnityContainer UnityContainer { get; }
public InteractionRequest<Notification> NotificationRequest { get; }
public InteractionRequest<Confirmation> ConfirmationRequest { get; }
/// <summary>
/// Creates a new instance of the TechnologyDomainEditViewModel.
/// </summary>
/// <param name="levelTriggerView">The Level Trigger 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 LevelTriggerViewModel(ILevelTriggerView levelTriggerView, IRegionManager regionManager,
IEventAggregator eventAggregator, IUnityContainer unityContainer)
{
View = levelTriggerView;
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);
_eventAggregator.GetEvent<EIDMappingEvent>().Subscribe(OnEIDMapping, ThreadOption.PublisherThread, true);
_eventAggregator.GetEvent<TTSImportHardwareScanFinishedEvent>().Subscribe(OnHardwareScanFinished, ThreadOption.PublisherThread, true);
_eventAggregator.GetEvent<TTSImportSavedChangesStatusEvent>().Subscribe(OnImportSavedChanges, ThreadOption.PublisherThread, true);
}
#region Methods
private void OnImportSavedChanges(bool bSaved)
{
if (bSaved)
{
UpdateLevelTriggers();
}
}
private void OnHardwareScanFinished(List<IDASHardware> hardware)
{
_hardware = hardware;
}
private void OnReadFileFinished(ReadFileStatusArg statusArg)
{
if (statusArg.Status)
{
_setup = statusArg.TTSSetup;
}
}
private IDictionary<string, string> _sensorIdToChannelId = new Dictionary<string, string>();
private void OnEIDMapping(IDictionary<string, string> sensorIdToChannelId)
{
_sensorIdToChannelId = sensorIdToChannelId;
UpdateLevelTriggers();
}
private void UpdateLevelTriggers()
{
if (null == _setup)
{
return;
}
if (null == _hardware || !_hardware.Any())
{
return;
}
var channelIdToDASChannel = new Dictionary<string, DASChannel>();
var channelIdToIChannel = new Dictionary<string, IHardwareChannel>();
var availableSquibChannels = new Queue<IHardwareChannel>();
var availableDigitalInputChannels = new Queue<IHardwareChannel>();
foreach (var h in _hardware)
{
var channels = h.GetIHardwareChannels();
foreach (var ch in channels)
{
//Create a DASChannel so that voltage can be validated below
channelIdToDASChannel[ch.GetId()] = new DASChannel(ch);
channelIdToIChannel[ch.GetId()] = ch;
if (ch.IsDigitalIn)
{
availableDigitalInputChannels.Enqueue(ch);
}
else if (ch.IsSquib)
{
availableSquibChannels.Enqueue(ch);
}
}
}
//handle pre-assigned channels if any
//these are channels which we know the sensor should be assigned to a given hardware channel ahead of time
//we do this before the EID check so that EID will override it
if (_setup.PreAssignedSensorIdAndHwId.Any())
{
var remainingPreassigned = new List<Tuple<string, string>>();
foreach (var tuple in _setup.PreAssignedSensorIdAndHwId)
{
var sensorId = tuple.Item1;
var hwId = tuple.Item2;
if (!channelIdToIChannel.ContainsKey(hwId))
{
remainingPreassigned.Add(tuple);
continue;
}
var matches = from ch in _setup.Channels where ch.SensorSerialNumber == sensorId select ch;
if (matches.Any())
{
var ittsChannel = matches.First();
//do not make the assignment if the user has already assigned the channel to a different hardware channel
//this would happen if the user scanned, didn't find the hardware, went to analog channels, assigned the sensor
//then finally went to hardware scan and then DID find the hardware. in this case just ignore the preassignment
if (null == ittsChannel.HardwareChannel)
{
var hardwareChannel = channelIdToIChannel[hwId];
var excitation = Test.Module.Channel.Sensor.GetExcitationVoltageEnumFromMagnitude(ittsChannel.SensorExcitationVolts);
//if we have a hardware assignment, but the excitation is no longer valid, then don't make the assignment
if (hardwareChannel.IsAnalog && !hardwareChannel.IsSupportedExcitation(excitation))
{
continue;
}
ittsChannel.HardwareChannel = hardwareChannel;
}
}
}
//if there are any remaining channels, these are hardware assignments that we didn't find hardware for, and we still need
//to look for assignment
_setup.PreAssignedSensorIdAndHwId = remainingPreassigned.ToArray();
}
foreach (var channel in _setup.Channels)
{
if (null != channel.HardwareChannel &&
!channelIdToIChannel.ContainsKey(channel.HardwareChannel.GetId()))
{
//hardware no longer present, unassign
channel.HardwareChannel = null;
}
if (string.IsNullOrWhiteSpace(channel.SensorEID))
{
//11245 TOM and DI channels in TTS imports without IDs should have sensors assigned automatically
if (channel.IsSquib)
{
if (availableSquibChannels.Any())
{
var first = availableSquibChannels.Dequeue();
channel.HardwareChannel = first;
//first channel voltage/initiation, second current, etc
var second = availableSquibChannels.Dequeue();
}
}
else if (channel.IsDigitalInput)
{
if (availableDigitalInputChannels.Any())
{
var first = availableDigitalInputChannels.Dequeue();
channel.HardwareChannel = first;
}
}
continue;
}
if (!_sensorIdToChannelId.ContainsKey(channel.SensorEID) ||
!channelIdToDASChannel.ContainsKey(_sensorIdToChannelId[channel.SensorEID]) ||
!VoltageIsValid(channel, channelIdToDASChannel[_sensorIdToChannelId[channel.SensorEID]])
//the below condition I think was missing a not, it appears to be looking for channels that don't have a valid channel code
//but DO have a valid match for sensor id ... this is probably a reserve channel where the sensor was still found that it's looking for
//15643 Sensors with EID do not remain assigned after import of XML produced from TTS import
//changed it again ... this is inhibiting sensors from being assigned, additionally tested it with a sensor without a valid channel code but
//a valid eid, and it worked fine
|| (_sensorIdToChannelId.ContainsKey(channel.SensorEID) && !channel.IsChannelCodeValid)
)
{
//unassign hardware if one is assigned, sensor id wasn't found or the sensor has an invalid excitation voltage for this hardware
//or the channel does have a jcode
channel.HardwareChannel = null;
continue;
}
var channelId = _sensorIdToChannelId[channel.SensorEID];
if (!channelIdToIChannel.ContainsKey(channelId)) continue;
channel.HardwareChannel = channelIdToIChannel[channelId];
}
foreach (var lt in _setup.LevelTriggers)
{
lt.Refresh();
}
OnPropertyChanged("LevelTriggers");
_eventAggregator.GetEvent<AssignedChannelsChangedEvent>().Publish(_setup);
CollectionViewSource.GetDefaultView(LevelTriggers)?.Refresh();
}
/// <summary>
/// returns True if the sensor's voltage is supported by the hardware channel, False if not
/// </summary>
/// <param name="selectedRemainingChannel"></param>
/// <param name="selectedDASChannel"></param>
/// <returns></returns>
private bool VoltageIsValid(ITTSChannelRecord selectedRemainingChannel, DASChannel selectedDASChannel)
{
var voltageEnum = ExcitationVoltageOptions.ExcitationVoltageOption.Undefined;
try
{
voltageEnum = Test.Module.Channel.Sensor.GetExcitationVoltageEnumFromMagnitude(selectedRemainingChannel.SensorExcitationVolts);
}
catch { } //GetExcitationVoltageEnumFromMagnitude will throw an exception if an invalid voltage is passed to it
return selectedDASChannel.HardwareChannel.IsSupportedExcitation(voltageEnum);
}
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
private IList<IDASHardware> _hardware;
private ITTSSetup _setup;
public ILevelTrigger[] LevelTriggers => _setup?.LevelTriggers;
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");
}
}
#endregion Properties
#region Commands
#endregion
///<summary>
///Occurs when a property value changes.
///</summary>
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -0,0 +1,18 @@
using DTS.Common.Interface.TestSetups.Imports.TTS.DOChannels;
// ReSharper disable CheckNamespace
namespace TTSImport
{
/// <inheritdoc cref="IDigitalOutputChannelsView" />
/// <summary>
/// Interaction logic for HardwareScanView.xaml
/// </summary>
public partial class DigitalOutputChannelsView : IDigitalOutputChannelsView
{
public DigitalOutputChannelsView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,27 @@
using System;
using System.ComponentModel;
using DTS.Common.Interface;
namespace TTSImport.Model
{
public class ChannelSummary : IChannelSummary
{
private string _channelType = String.Empty;
public string ChannelType { get => _channelType; set { _channelType = value; OnPropertyChanged("ChannelType"); } }
private int _requested = 0;
public int Requested { get => _requested; set { _requested = value; OnPropertyChanged("Requested"); } }
private int _assigned = 0;
public int Assigned { get => _assigned; set { _assigned = value; OnPropertyChanged("Assigned"); } }
private int _unassigned = 0;
public int Unassigned { get => _unassigned; set { _unassigned = value; OnPropertyChanged("Unassigned"); } }
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.ComponentModel;
using DTS.Common.Interface;
namespace TTSImport.Model
{
public class DasSummary : IDasSummary
{
private string _dasSerial;
public string DASSerial { get => _dasSerial; set { _dasSerial = value; OnPropertyChanged("DASSerial"); } }
private string _eidFound;
public string EIDFound { get => _eidFound; set { _eidFound = value; OnPropertyChanged("EIDFound"); } }
private string _batteryVoltageStatus;
public string BatteryVoltageStatus { get => _batteryVoltageStatus; set { _batteryVoltageStatus = value; OnPropertyChanged("BatteryVoltageStatus"); } }
private System.Windows.Media.SolidColorBrush _batteryVoltageColor;
public System.Windows.Media.SolidColorBrush BatteryVoltageColor { get => _batteryVoltageColor; set { _batteryVoltageColor = value; OnPropertyChanged("BatteryVoltageColor"); } }
private string _inputVoltageStatus;
public string InputVoltageStatus { get => _inputVoltageStatus; set { _inputVoltageStatus = value; OnPropertyChanged("InputVoltageStatus"); } }
private System.Windows.Media.SolidColorBrush _inputVoltageColor;
public System.Windows.Media.SolidColorBrush InputVoltageColor { get => _inputVoltageColor; set { _inputVoltageColor = value; OnPropertyChanged("InputVoltageColor"); } }
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -0,0 +1,17 @@
using DTS.Common.Interface.TestSetups.Imports.TTS;
// ReSharper disable CheckNamespace
namespace TTSImport
{
/// <summary>
/// Interaction logic for HardwareScanView.xaml
/// </summary>
public partial class AnalogChannelsView : IAnalogChannelsView
{
public AnalogChannelsView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,162 @@
using DTS.Common.Base;
using DTS.Common.Interface.TestSetups.Imports.TTS.HardwareScan;
namespace TTSImport.Model
{
public class HardwareSummaryRecord : BasePropertyChanged, IHardwareSummaryRecord
{
private uint _dout;
public uint DOut
{
get => _dout;
set
{
_dout = value;
OnPropertyChanged("DOut");
}
}
private uint _din;
public uint DIn
{
get => _din;
set
{
_din = value;
OnPropertyChanged("DIn");
}
}
private uint _squib;
public uint Squib
{
get => _squib;
set
{
_squib = value;
OnPropertyChanged("Squib");
}
}
private uint _analog;
public uint Analog
{
get => _analog;
set
{
_analog = value;
OnPropertyChanged("Analog");
}
}
private uint _sps;
public uint SPS
{
get => _sps;
set
{
_sps = value;
OnPropertyChanged("SPS");
}
}
private uint _spd;
public uint SPD
{
get => _spd;
set
{
_spd = value;
OnPropertyChanged("SPD");
}
}
private uint _spt;
public uint SPT
{
get => _spt;
set
{
_spt = value;
OnPropertyChanged("SPT");
}
}
private uint _ecm;
public uint ECM
{
get => _ecm;
set
{
_ecm = value;
OnPropertyChanged("ECM");
}
}
private uint _rack;
public uint Rack
{
get => _rack;
set
{
_rack = value;
OnPropertyChanged("Rack");
}
}
private uint _g5;
public uint G5
{
get => _g5;
set
{
_g5 = value;
OnPropertyChanged("G5");
}
}
private uint _total;
public uint Total
{
get => _total;
private set
{
_total = value;
OnPropertyChanged("Total");
}
}
public void UpdateTotal()
{
Total = Analog + Squib + DIn + DOut;
}
public void Update(uint analog, uint squib, uint din, uint dout, uint ecm, uint sps, uint spt, uint spd,
uint g5,
uint rack)
{
Analog = analog;
Squib = squib;
DIn = din;
DOut = dout;
ECM = ecm;
SPS = sps;
SPT = spt;
SPD = spd;
G5 = g5;
Rack = rack;
UpdateTotal();
}
}
}

View File

@@ -0,0 +1,16 @@
using System.Threading;
namespace TTSImport.Model
{
public class WorkFunctionThreadData
{
public ManualResetEvent CancelEvent { get; }
public ManualResetEvent DoneEvent { get; }
public WorkFunctionThreadData()
{
CancelEvent = new ManualResetEvent(false);
DoneEvent = new ManualResetEvent(false);
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("TTSImport")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("DTS")]
[assembly: AssemblyProduct("TTSImport")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a8ff540f-f22a-45ae-a63b-4984ed74c654")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,158 @@
using System;
using System.ComponentModel.Composition;
using System.Windows.Media.Imaging;
using DTS.Common;
using DTS.Common.Interface;
using DTS.Common.Interface.TestSetups.Imports.TTS;
using DTS.Common.Interface.TestSetups.Imports.TTS.DIChannels;
using DTS.Common.Interface.TestSetups.Imports.TTS.DOChannels;
using Prism.Ioc;
using Prism.Modularity;
using TTSImport;
using Unity;
// ReSharper disable CheckNamespace
// ReSharper disable RedundantAttributeUsageProperty
// ReSharper disable UnusedParameter.Local
[assembly: TTSImportModuleName]
[assembly: TTSImportModuleImageAttribute]
namespace TTSImport
{
[Export(typeof(IModule))]
[Module(ModuleName = "TTSImportModule")]
public class TTSImportModule : IModule
{
/// <summary>
/// Injected unity container
/// </summary>
private readonly IUnityContainer _unityContainer;
/// <summary>
/// Initializes a new instance of the <see cref="TTSImportModule"/> class.
/// </summary>
/// <param name="unityContainer">Obtained reference of the unity container by using dependency injection.</param>
public TTSImportModule(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
public void Initialize()
{
// Register View & View-Model with Unity dependency injection container as a singleton.
_unityContainer.RegisterType<IHardwareScanView, HardwareScanView>();
_unityContainer.RegisterType<IHardwareScanViewModel, HardwareScanViewModel>();
_unityContainer.RegisterType<IEditFileView, EditFileView>();
_unityContainer.RegisterType<IEditFileViewModel, EditFileViewModel>();
_unityContainer.RegisterType<ISummaryView, SummaryView>();
_unityContainer.RegisterType<ISummaryViewModel, SummaryViewModel>();
_unityContainer.RegisterType<IReadFileView, ReadFileView>();
_unityContainer.RegisterType<IReadFileViewModel, ReadFileViewModel>();
_unityContainer.RegisterType<ILevelTriggerView, LevelTriggerView>();
_unityContainer.RegisterType<ILevelTriggerViewModel, LevelTriggerViewModel>();
_unityContainer.RegisterType<IAnalogChannelsView, AnalogChannelsView>();
_unityContainer.RegisterType<IAnalogChannelsViewModel, AnalogChannelsViewModel>();
_unityContainer.RegisterType<ITOMChannelsView, TOMChannelsView>();
_unityContainer.RegisterType<ITOMChannelsViewModel, TOMChannelsViewModel>();
_unityContainer.RegisterType<IDigitalInputChannelsView, DigitalInputChannelsView>();
_unityContainer.RegisterType<IDigitalInputChannelsViewModel, DigitalInputChannelsViewModel>();
_unityContainer.RegisterType<IDigitalOutputChannelsView, DigitalOutputChannelsView>();
_unityContainer.RegisterType<IDigitalOutputChannelsViewModel, DigitalOutputChannelsViewModel>();
}
public void OnInitialized(IContainerProvider containerProvider)
{
throw new NotImplementedException();
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
throw new NotImplementedException();
}
}
/// <summary>
/// Attribute class contains assembly name
/// </summary>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
public class TTSImportModuleNameAttribute : TextAttribute
{
public TTSImportModuleNameAttribute() : this(null) { }
public TTSImportModuleNameAttribute(string s)
{
AssemblyName = AssemblyNames.TTSImport.ToString();
}
public override string AssemblyName { get; }
public override Type GetAttributeType()
{
return typeof(TextAttribute);
}
public override string GetAssemblyName()
{
return AssemblyName;
}
}
/// <summary>
/// Attribute class contains assembly image and name - used on the Main screen to SummaryModule available components
/// </summary>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
public class TTSImportModuleImageAttribute : ImageAttribute
{
private BitmapImage _img;
public TTSImportModuleImageAttribute() : this(null) { }
public override BitmapImage AssemblyImage
{
get { _img = AssemblyInfo.GetImage(AssemblyNames.TTSImport.ToString()); return _img; }
}
public TTSImportModuleImageAttribute(string s)
{
_img = AssemblyInfo.GetImage(AssemblyNames.TTSImport.ToString());
}
public override Type GetAttributeType()
{
return typeof(ImageAttribute);
}
public override BitmapImage GetAssemblyImage()
{
return AssemblyImage;
}
private string _name;
public override string AssemblyName
{
get { _name = AssemblyNames.TTSImport.ToString(); return _name; }
}
public override string GetAssemblyName()
{
return AssemblyName;
}
private string _group;
public override string AssemblyGroup
{
get { _group = eAssemblyGroups.Prepare.ToString(); return _group; }
}
public override string GetAssemblyGroup()
{
return AssemblyGroup;
}
private eAssemblyRegion _region;
public override eAssemblyRegion AssemblyRegion
{
get { _region = eAssemblyRegion.TTSImportRegion; return _region; }
}
public override eAssemblyRegion GetAssemblyRegion()
{
return AssemblyRegion;
}
}
}

View File

@@ -0,0 +1,450 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Added" xml:space="preserve">
<value>Added</value>
</data>
<data name="Analog_Assign" xml:space="preserve">
<value>Assign</value>
</data>
<data name="Analog_Disable" xml:space="preserve">
<value>Disable</value>
</data>
<data name="Analog_Enable" xml:space="preserve">
<value>Enable</value>
</data>
<data name="Analog_Remove" xml:space="preserve">
<value>Remove</value>
</data>
<data name="Assigned" xml:space="preserve">
<value>Assigned</value>
</data>
<data name="BatteryVoltageStatusColumn" xml:space="preserve">
<value>Battery Voltage Status</value>
</data>
<data name="Browse" xml:space="preserve">
<value>Browse</value>
</data>
<data name="CableMultiplier" xml:space="preserve">
<value>Cable Multiplier</value>
</data>
<data name="Capacity" xml:space="preserve">
<value>Capacity</value>
</data>
<data name="CHAN" xml:space="preserve">
<value>CHAN</value>
</data>
<data name="ChannelType" xml:space="preserve">
<value>Channel Type</value>
</data>
<data name="Channel_Summary" xml:space="preserve">
<value>Channel Summary</value>
</data>
<data name="Code" xml:space="preserve">
<value>Code</value>
</data>
<data name="DASChannel" xml:space="preserve">
<value>DAS Channel</value>
</data>
<data name="DASChannels" xml:space="preserve">
<value>DAS Channels</value>
</data>
<data name="DASSerial" xml:space="preserve">
<value>DAS Serial</value>
</data>
<data name="DAS_Summary" xml:space="preserve">
<value>DAS Summary</value>
</data>
<data name="EID" xml:space="preserve">
<value>EID</value>
</data>
<data name="EIDFound" xml:space="preserve">
<value>EID Found</value>
</data>
<data name="EULabel" xml:space="preserve">
<value>EU Label</value>
</data>
<data name="HWSerialNumber" xml:space="preserve">
<value>HW SN</value>
</data>
<data name="Import" xml:space="preserve">
<value>Import</value>
</data>
<data name="ImportFile" xml:space="preserve">
<value>Import File</value>
</data>
<data name="ImportTestSetup_PossibleStatus_Done" xml:space="preserve">
<value>Done</value>
</data>
<data name="ImportTestSetup_PossibleStatus_Failed" xml:space="preserve">
<value>Failed</value>
</data>
<data name="ImportTestSetup_PossibleStatus_Working" xml:space="preserve">
<value>Working</value>
</data>
<data name="InputVoltageStatusColumn" xml:space="preserve">
<value>Input Voltage Status</value>
</data>
<data name="JCode" xml:space="preserve">
<value>JCode</value>
</data>
<data name="Mode" xml:space="preserve">
<value>Mode</value>
</data>
<data name="Name" xml:space="preserve">
<value>Name</value>
</data>
<data name="NONE" xml:space="preserve">
<value>NONE</value>
</data>
<data name="Polarity" xml:space="preserve">
<value>Polarity</value>
</data>
<data name="PostTrigger" xml:space="preserve">
<value>Post Trigger (sec)</value>
</data>
<data name="PreTrigger" xml:space="preserve">
<value>Pre Trigger (sec)</value>
</data>
<data name="Range" xml:space="preserve">
<value>Range</value>
</data>
<data name="RemainingChannels" xml:space="preserve">
<value>Remaining Channels</value>
</data>
<data name="Requested" xml:space="preserve">
<value>Requested</value>
</data>
<data name="RunTest" xml:space="preserve">
<value>Run Test</value>
</data>
<data name="SampleRate" xml:space="preserve">
<value>Sample Rate (per sec)</value>
</data>
<data name="Sens" xml:space="preserve">
<value>Sens</value>
</data>
<data name="SensorSN" xml:space="preserve">
<value>Sensor SN</value>
</data>
<data name="SerialNumber" xml:space="preserve">
<value>Sensor SN</value>
</data>
<data name="TestLength" xml:space="preserve">
<value>Test Length (sec)</value>
</data>
<data name="TestSetupName" xml:space="preserve">
<value>Test Setup Name:</value>
</data>
<data name="ToyotaCode" xml:space="preserve">
<value>Toyota Code</value>
</data>
<data name="Type" xml:space="preserve">
<value>Type</value>
</data>
<data name="Unassigned" xml:space="preserve">
<value>Unassigned</value>
</data>
<data name="ValueEU" xml:space="preserve">
<value>VAL (EU)</value>
</data>
<data name="ValuePercent" xml:space="preserve">
<value>VAL (%)</value>
</data>
<data name="AssignSensorPrompt" xml:space="preserve">
<value>Assign sensor? ID on the channel will be applied to the sensor and removed from any other sensors.</value>
</data>
<data name="UserFeedbackRequired" xml:space="preserve">
<value>User feedback required</value>
</data>
<data name="Current" xml:space="preserve">
<value>Current (amp)</value>
</data>
<data name="Delay" xml:space="preserve">
<value>Delay (ms)</value>
</data>
<data name="Duration" xml:space="preserve">
<value>Duration (ms)</value>
</data>
<data name="LimitDuration" xml:space="preserve">
<value>Limit duration</value>
</data>
<data name="ResHighTolerance" xml:space="preserve">
<value>Res. High Tol. (Ω)</value>
</data>
<data name="ResLowTolerance" xml:space="preserve">
<value>Res. Low Tol. (Ω)</value>
</data>
<data name="CH" xml:space="preserve">
<value>CH</value>
</data>
<data name="EditFile_AddCode" xml:space="preserve">
<value>Add Code</value>
</data>
<data name="EditFile_DeleteCode" xml:space="preserve">
<value>Delete Code</value>
</data>
<data name="EditFile_Replace" xml:space="preserve">
<value>Replace</value>
</data>
<data name="Filter" xml:space="preserve">
<value>Filter</value>
</data>
<data name="ImportTestSetup_MustBeCSVOrXML" xml:space="preserve">
<value>TTS import requires either .csv or .xml input file</value>
</data>
<data name="ImportTestSetup_NoOriginalCSV" xml:space="preserve">
<value>TTS import requires a .csv filename in the OriginalImportFile attribute</value>
</data>
<data name="ImportTestSetup_UnexpectedZeroMethod" xml:space="preserve">
<value>is an unexpected zero method type. Only None, AverageOverTime, and UsePreEventDiagnosticsZero are allowed</value>
</data>
<data name="JHyphenCode" xml:space="preserve">
<value>J-Code</value>
</data>
<data name="NumChannelsAndSensors" xml:space="preserve">
<value>{0} Required Channel(s), {1} System Sensor(s)</value>
</data>
<data name="SaveFile" xml:space="preserve">
<value>Save File</value>
</data>
<data name="Search" xml:space="preserve">
<value>Search</value>
</data>
<data name="TestName" xml:space="preserve">
<value>Test Name</value>
</data>
<data name="Table_NA" xml:space="preserve">
<value>---</value>
</data>
<data name="Analog" xml:space="preserve">
<value>Analog</value>
</data>
<data name="DigitalIn" xml:space="preserve">
<value>Digital In</value>
</data>
<data name="TOM" xml:space="preserve">
<value>TOM</value>
</data>
<data name="AllowEIDToBlankChannelChallenge" xml:space="preserve">
<value>The sensor {0} has an EID, but no EID was found.\r\n\r\nPress OK to clear the EID for {0} and assign the sensor.\r\nPress Cancel to leave the EID unchanged and the sensor unassigned.</value>
</data>
<data name="ROIEnd" xml:space="preserve">
<value>ROI End (sec)</value>
</data>
<data name="ROIStart" xml:space="preserve">
<value>ROI Start (sec)</value>
</data>
<data name="ImportTestSetup_DuplicateSensorSerialNumber" xml:space="preserve">
<value>{0} is a duplicate Sensor Serial Number.</value>
</data>
<data name="ImportTestSetup_DuplicateChannelCode" xml:space="preserve">
<value>{0} is a duplicate Channel Code.</value>
</data>
<data name="ImportTestSetup_DuplicateDescription" xml:space="preserve">
<value>{0} is a duplicate Description.</value>
</data>
<data name="DIn" xml:space="preserve">
<value>D In</value>
</data>
<data name="DOut" xml:space="preserve">
<value>D Out</value>
</data>
<data name="ECM" xml:space="preserve">
<value>ECM</value>
</data>
<data name="G5" xml:space="preserve">
<value>G5</value>
</data>
<data name="Rack" xml:space="preserve">
<value>Rack</value>
</data>
<data name="SPD" xml:space="preserve">
<value>SPD</value>
</data>
<data name="SPS" xml:space="preserve">
<value>SPS</value>
</data>
<data name="SPT" xml:space="preserve">
<value>SPT</value>
</data>
<data name="Squib" xml:space="preserve">
<value>Squib</value>
</data>
<data name="Total" xml:space="preserve">
<value>Total</value>
</data>
<data name="Units" xml:space="preserve">
<value>Units</value>
</data>
<data name="AssignSensorExcitationError" xml:space="preserve">
<value>Sensor Assignment Error</value>
</data>
<data name="InvalidExcitationAssignment" xml:space="preserve">
<value>Hardware does not support {0} volt excitation.</value>
</data>
<data name="MissingECMSWarning" xml:space="preserve">
<value>Devices at the following IP Addresses were unresponsive. Please reconnect or power cycle the units.</value>
</data>
<data name="Warning" xml:space="preserve">
<value>Warning</value>
</data>
<data name="EmptyChannelCodeWarning" xml:space="preserve">
<value>Non empty channel codes are required, please complete channel codes to continue</value>
</data>
<data name="TestId" xml:space="preserve">
<value>Test Id</value>
</data>
<data name="TESTID_PREFIX_SUFFIX_None" xml:space="preserve">
<value>[None]</value>
</data>
<data name="TESTID_PREFIX_SUFFIX_TestSetupName" xml:space="preserve">
<value>[Test Setup Name]</value>
</data>
<data name="TESTID_PREFIX_SUFFIX_TimeStamp" xml:space="preserve">
<value>[Time Stamp]</value>
</data>
<data name="EditFile_ADDDI" xml:space="preserve">
<value>Add DI</value>
</data>
<data name="EditFile_AddSquib" xml:space="preserve">
<value>Add Squib</value>
</data>
<data name="AAF_SLICE" xml:space="preserve">
<value>Requested SLICE AAF: {0}</value>
</data>
<data name="AAF_TDAS" xml:space="preserve">
<value>Requested TDAS AAF: {0}</value>
</data>
<data name="ExcitationNotSupportedByChannel" xml:space="preserve">
<value>Sensor excitation {0} not supported by channel</value>
</data>
<data name="ImportTestSetup_DuplicateJCode" xml:space="preserve">
<value>JCode {0} is a duplicate</value>
</data>
<data name="ImportTestSetup_EmptyJCode" xml:space="preserve">
<value>record {0} has an empty J-Code</value>
</data>
<data name="ReservedSensorFound" xml:space="preserve">
<value>Reserved Sensor(s) found in file. These are now unsupported and were skipped.</value>
</data>
<data name="SensorNotFound" xml:space="preserve">
<value>Sensor "{0}" not found in database</value>
</data>
</root>

View File

@@ -0,0 +1,209 @@
<base:BaseView x:Class="TTSImport.HardwareScanView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="768" d:DesignWidth="1366"
xmlns:base="clr-namespace:DTS.Common.Base;assembly=DTS.Common"
xmlns:strings="clr-namespace:TTSImport"
xmlns:converters="clr-namespace:DTS.Common.Converters;assembly=DTS.Common"
xmlns:controls="clr-namespace:DTS.Common.Controls;assembly=DTS.Common">
<base:BaseView.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Themes/brushes.xaml"/>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Controls/combobox.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="ListView">
<Setter Property="ItemContainerStyle" Value="{StaticResource TTS_ListViewItemStyle}"/>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource TTS_TextBoxStyle}"/>
<Style TargetType="TextBlock" BasedOn="{StaticResource TTS_TextBlockStyle}"/>
<Style TargetType="CheckBox" BasedOn="{StaticResource PageContentCheckBoxStyle}" />
<Style TargetType="ComboBox" BasedOn="{StaticResource TTS_ComboBoxStyle}"/>
<Style TargetType="Button" BasedOn="{StaticResource TTS_ButtonStyle}"/>
<Style TargetType="GridViewColumnHeader" BasedOn="{StaticResource Gray_GridViewColumnHeaderStyle}"/>
<converters:NonZeroToColorConverter x:Key="NonZeroToColor" />
</ResourceDictionary>
</base:BaseView.Resources>
<Grid Background="{DynamicResource Brush_ApplicationContentBackground}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<controls:CommonStatusRibbon Content="{Binding StatusAndProgressBarView}" Grid.Row="0" Grid.ColumnSpan="3" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"/>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<Grid Background="{DynamicResource Brush_ApplicationContentBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<GroupBox Header="{strings:TranslateExtension DAS_Summary}" Grid.Row="1" Grid.Column="0"
AutomationProperties.AutomationId="DASSummaryGroupBox" HorizontalAlignment="Left">
<WrapPanel Orientation="Vertical">
<ListView ItemsSource="{Binding HardwareRecords}">
<ListView.View>
<GridView>
<GridViewColumn Header="{strings:TranslateExtension ECM}" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ECM,FallbackValue='100'}" Width="40" AutomationProperties.AutomationId="ECM" TextAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension SPS}" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding SPS,FallbackValue='100'}" Width="40" AutomationProperties.AutomationId="SPS" TextAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension SPT}" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding SPT,FallbackValue='100'}" Width="40" AutomationProperties.AutomationId="SPT" TextAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension SPD}" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding SPD,FallbackValue='100'}" Width="43" AutomationProperties.AutomationId="SPD" TextAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension G5}" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding G5,FallbackValue='100'}" Width="43" AutomationProperties.AutomationId="G5" TextAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Rack}" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Rack,FallbackValue='100'}" Width="43" AutomationProperties.AutomationId="Rack" TextAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Analog}" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Analog,FallbackValue='100'}" Width="43" AutomationProperties.AutomationId="Analog" TextAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Squib}" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Squib,FallbackValue='100'}" Width="43" AutomationProperties.AutomationId="Squib" TextAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension DIn}" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding DIn,FallbackValue='100'}" Width="43" AutomationProperties.AutomationId="DIn" TextAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension DOut}" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding DOut,FallbackValue='100'}" Width="43" AutomationProperties.AutomationId="Dout" TextAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Total}" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Total,FallbackValue='100'}" Width="43" AutomationProperties.AutomationId="Total" TextAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<ListView ItemsSource="{Binding DasSummaryList}">
<ListView.View>
<GridView>
<GridViewColumn Header="{strings:TranslateExtension DASSerial}" Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding SerialNumberFamily,FallbackValue='DAS Serial'}" Width="190" AutomationProperties.AutomationId="SerialNumber" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension EIDFound}" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate> <TextBlock Text="{Binding EIDFound,FallbackValue='EID Found'}" Width="100" AutomationProperties.AutomationId="EIDFound" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension InputVoltageStatusColumn}" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding InputVoltageStatus,FallbackValue='Input Voltage'}" Width="150" Background="{Binding InputVoltageColor}" AutomationProperties.AutomationId="InputVoltageStatus" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension BatteryVoltageStatusColumn}" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding BatteryVoltageStatus,FallbackValue='Battery Voltage'}" Width="150" Background="{Binding BatteryVoltageColor}" AutomationProperties.AutomationId="BatteryVoltageStatus" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</WrapPanel>
</GroupBox>
<GroupBox Header="{strings:TranslateExtension Channel_Summary}" Grid.Row="1" Grid.Column="2"
AutomationProperties.AutomationId="ChannelSummaryGroupBox" HorizontalAlignment="Left" VerticalAlignment="Top">
<ListView ItemsSource="{Binding ChannelSummaryList}" >
<ListView.View>
<GridView>
<GridViewColumn Header="{strings:TranslateExtension ChannelType}" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ChannelType,FallbackValue='Channel Type'}" Width="100" AutomationProperties.AutomationId="ChannelType" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Requested}" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Requested,FallbackValue='Requested'}" Width="100" AutomationProperties.AutomationId="Requested" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Assigned}" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Assigned,FallbackValue='Assigned'}" Width="100" AutomationProperties.AutomationId="Assigned" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Unassigned}" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Unassigned,FallbackValue='Unassigned'}" Width="100" Background="{Binding Unassigned, Converter={StaticResource NonZeroToColor}}" AutomationProperties.AutomationId="Unassigned" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</GroupBox>
</Grid>
</ScrollViewer>
</Grid>
</base:BaseView>

View File

@@ -0,0 +1,257 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B77A01D2-6C47-4740-A9C8-72D92B058E78}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>TTSImport</RootNamespace>
<AssemblyName>TTSImport</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>CODE_ANALYSIS;DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<RunCodeAnalysis>false</RunCodeAnalysis>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>CODE_ANALYSIS;DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<RunCodeAnalysis>true</RunCodeAnalysis>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Practices.ServiceLocation">
<HintPath>..\..\..\..\..\Common\DTS.Common\lib\PrismLibrary\Microsoft.Practices.ServiceLocation.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="Microsoft.Xaml.Behaviors">
<HintPath>..\..\..\..\..\Common\DTS.Common\lib\PrismLibrary\Microsoft.Xaml.Behaviors.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="Prism">
<HintPath>..\..\..\..\..\Common\DTS.Common\lib\PrismLibrary\Prism.dll</HintPath>
</Reference>
<Reference Include="Prism.Unity.Wpf">
<HintPath>..\..\..\..\..\Common\DTS.Common\lib\PrismLibrary\Prism.Unity.Wpf.dll</HintPath>
</Reference>
<Reference Include="Prism.Wpf">
<HintPath>..\..\..\..\..\Common\DTS.Common\lib\PrismLibrary\Prism.Wpf.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Security" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Windows.Interactivity">
<HintPath>..\..\..\..\..\Common\DTS.Common\lib\System.Windows.Interactivity.dll</HintPath>
</Reference>
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="Unity.Abstractions">
<HintPath>..\..\..\..\..\Common\DTS.Common\lib\PrismLibrary\Unity.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Unity.Container">
<HintPath>..\..\..\..\..\Common\DTS.Common\lib\PrismLibrary\Unity.Container.dll</HintPath>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="Xceed.Wpf.Toolkit">
<HintPath>..\..\..\..\..\Common\DTS.Common\lib\Xceed.Wpf.Toolkit\Xceed.Wpf.Toolkit.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Model\DASChannel.cs" />
<Compile Include="Model\HardwareSummaryRecord.cs" />
<Compile Include="Model\SummaryChannel.cs" />
<Compile Include="Model\ChannelSummary.cs" />
<Compile Include="Model\TTSChannelRecord.cs" />
<Compile Include="Model\TTSLevelTriggerRecord.cs" />
<Compile Include="Model\TTSTestSetup.cs" />
<Compile Include="Model\WorkFunctionThreadData.cs" />
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
<Compile Include="Resources\StringResources.ja.Designer.cs" />
<Compile Include="TTSImportModule.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resources\StringResources.Designer.cs">
<DependentUpon>StringResources.resx</DependentUpon>
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
</Compile>
<Compile Include="Resources\TranslateExtension.cs" />
<Compile Include="ViewModel\EditFileViewModel.cs" />
<Compile Include="ViewModel\DigitalInputChannelsViewModel.cs" />
<Compile Include="ViewModel\DigitalOutputChannelsViewModel.cs" />
<Compile Include="ViewModel\TOMChannelsViewModel.cs" />
<Compile Include="ViewModel\AnalogChannelsViewModel.cs" />
<Compile Include="ViewModel\LevelTriggerViewModel.cs" />
<Compile Include="ViewModel\HardwareScanViewModel.cs" />
<Compile Include="ViewModel\ReadFileViewModel.cs" />
<Compile Include="ViewModel\SummaryViewModel.cs" />
<Compile Include="View\EditFileView.xaml.cs">
<DependentUpon>EditFileView.xaml</DependentUpon>
</Compile>
<Compile Include="View\DigitalInputChannelsView.xaml.cs">
<DependentUpon>DigitalInputChannelsView.xaml</DependentUpon>
</Compile>
<Compile Include="View\DigitalOutputChannelsView.xaml.cs">
<DependentUpon>DigitalOutputChannelsView.xaml</DependentUpon>
</Compile>
<Compile Include="View\TOMChannelsView.xaml.cs">
<DependentUpon>TOMChannelsView.xaml</DependentUpon>
</Compile>
<Compile Include="View\AnalogChannelsView.xaml.cs">
<DependentUpon>AnalogChannelsView.xaml</DependentUpon>
</Compile>
<Compile Include="View\LevelTriggerView.xaml.cs">
<DependentUpon>LevelTriggerView.xaml</DependentUpon>
</Compile>
<Compile Include="View\HardwareScanView.xaml.cs">
<DependentUpon>HardwareScanView.xaml</DependentUpon>
</Compile>
<Compile Include="View\ReadFileView.xaml.cs">
<DependentUpon>ReadFileView.xaml</DependentUpon>
</Compile>
<Compile Include="View\SummaryView.xaml.cs">
<DependentUpon>SummaryView.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\StringResources.ja.resx">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Resources\StringResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>StringResources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\Common\DTS.Common.Core\DTS.Common.Core.csproj">
<Project>{fab1f470-1574-4301-b56e-d3364aa93679}</Project>
<Name>DTS.Common.Core</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\..\Common\DTS.Common.DAS.Concepts\DTS.Common.DAS.Concepts.csproj">
<Project>{03D8C736-36EB-4CD1-A6D9-130452B23239}</Project>
<Name>DTS.Common.DAS.Concepts</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\..\Common\DTS.Common.ISO\DTS.Common.ISO.csproj">
<Project>{4dccddd1-032f-430c-9a6f-231daca4fbd0}</Project>
<Name>DTS.Common.ISO</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\..\Common\DTS.Common.Storage\DTS.Common.Storage.csproj">
<Project>{e0d1a7d0-dce8-403d-ba85-5a5d66ba1313}</Project>
<Name>DTS.Common.Storage</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\..\Common\DTS.Common.Utilities\DTS.Common.Utilities.csproj">
<Project>{03eace47-ea59-44ac-b49d-956e4dc4d618}</Project>
<Name>DTS.Common.Utilities</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\..\Common\DTS.Common\DTS.Common.csproj">
<Project>{114edc77-f3b5-4576-a91b-40818d503b55}</Project>
<Name>DTS.Common</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\IService\IService.csproj">
<Project>{c9c45b72-05a3-4962-bc13-a78b1f4b1925}</Project>
<Name>IService</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\SensorDB\SensorDB.csproj">
<Project>{444ef10c-046e-47ad-a9a5-17318d488723}</Project>
<Name>SensorDB</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Users\Users.csproj">
<Project>{BE8D217D-6DA9-4BCA-B62A-A82325B33979}</Project>
<Name>Users</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<Page Include="View\EditFileView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="View\DigitalInputChannelsView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="View\DigitalOutputChannelsView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="View\TOMChannelsView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="View\AnalogChannelsView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="View\LevelTriggerView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="View\HardwareScanView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="View\ReadFileView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="View\SummaryView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,485 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using DTS.Common.Interface.DataRecorders;
using DTS.Common.Interface.TestSetups.Imports.TTS.ReadFile;
using DTS.Common.Enums;
namespace TTSImport.Model
{
/// <summary>
/// this class represents a hardware channel + some additional meta information (mostly the TTSChannelRecord or sensor that might be assigned)
/// It's currently for use in AnalogChannelsViewModel
/// </summary>
public class DASChannel : DependencyObject, INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public bool SetProperty<T>(ref T storage, T value, string propertyName = null)
{
if (Equals(storage, value)) return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
public void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region enums and constants
public const string POSITIVE = "+";
public const string NEGATIVE = "-";
public IEnumerable<string> Polarities => new[] { POSITIVE, NEGATIVE };
public IEnumerable<SquibFireMode> SquibFireModes => new[]
{
SquibFireMode.CAP, SquibFireMode.CONSTANT
};
public IEnumerable<DigitalOutputModes> OutputModes => new[]
{
DigitalOutputModes.NONE,
DigitalOutputModes.CCNO,
DigitalOutputModes.CCNC,
DigitalOutputModes.FVHL,
DigitalOutputModes.FVLH
};
#endregion
#region constructors and initializers
public DASChannel(IHardwareChannel channel)
{
HardwareChannel = channel;
}
public DASChannel(IHardwareChannel channel, ITTSSetup setup)
{
HardwareChannel = channel;
TestSetup = setup;
}
public ITTSSetup TestSetup { get; }
#endregion
#region properties
/// <summary>
/// the digital output mode (if relevant)
/// </summary>
public DigitalOutputModes DigitalOutputMode
{
get => Channel?.DigitalOutputMode ?? DigitalOutputModes.NONE;
set
{
if (Channel.DigitalOutputMode == value) return;
if (Channel.DigitalOutputMode == DigitalOutputModes.NONE)
{
//Add to the Test Setup
AddDigitalOutputChannel();
}
else if (value == DigitalOutputModes.NONE)
{
//Remove from the Test Setup
RemoveDigitalOutputChannel();
}
Channel.DigitalOutputMode = value;
Channel.IsModified = true;
OnPropertyChanged("IsActive");
}
}
/// <summary>
/// the delay between trigger and output (if relevant)
/// </summary>
public double DigitalOutputDelayMs
{
get => Channel?.DigitalOutputDelay ?? 0D;
set
{
if (null != Channel)
{
Channel.DigitalOutputDelay = value;
Channel.IsModified = true;
}
}
}
/// <summary>
/// the duration of output after output started (if relevant)
/// </summary>
public double DigitalOutputDurationMs
{
get => Channel?.DigitalOutputDuration ?? 100D;
set
{
if (null != Channel)
{
Channel.DigitalOutputDuration = value;
Channel.IsModified = true;
}
}
}
/// <summary>
/// the polarity of the sensor associated with this hardware channel (if any)
/// </summary>
public string Polarity
{
get
{
if (null != Channel)
{
return Channel.SensorPolarity ? POSITIVE : NEGATIVE;
}
return POSITIVE;
}
set
{
if (null != Channel)
{
Channel.SensorPolarity = value == POSITIVE;
}
}
}
public SquibFireMode SquibFireMode
{
get
{
if (null != Channel)
{
return Channel.SquibFireMode;
}
return SquibFireMode.CAP;
}
set
{
if (null != Channel)
{
Channel.SquibFireMode = value;
Channel.IsModified = true;
}
}
}
/// <summary>
/// whether this channel should be considered disabled or not
/// disabled channels will exist in the test setup but won't be used during run test
/// </summary>
public bool Disabled
{
get => (bool)GetValue(DisabledProperty);
set => SetValue(DisabledProperty, value);
}
/// <summary>
/// this is the Toyota channel record associated with the hardware channel
/// can be null if there's no sensor associated
/// </summary>
public ITTSChannelRecord Channel { get; private set; }
/// <summary>
/// a string representation of the hardware channel (eg [SPS00001] ch 13)
/// </summary>
public string DASChannelString => HardwareChannel?.ToString() ?? "";
/// <summary>
/// the Channel code associated with the physical hardware channel (if any)
/// </summary>
public string ToyotaCode
{
get => Channel?.ChannelCode ?? "";
set
{
if (null != Channel)
{
Channel.ChannelCode = value;
Channel.IsModified = true;
}
}
}
/// <summary>
/// the electronic id on the physical channel (if any)
/// </summary>
public string EID { get; set; }
/// <summary>
/// the "name" of the channel, if any (is blank if no TTSRecord associated with this channel)
/// </summary>
public string Name
{
get => Channel?.JCodeOrDescription ?? "";
set
{
if (null != Channel)
{
Channel.JCodeOrDescription = value;
Channel.IsModified = true;
}
}
}
/// <summary>
/// the serial number for a sensor on this channel (if any)
/// </summary>
public string SerialNumber => Channel?.SensorSerialNumber ?? "";
public string SensitivityString => Sensitivity.ToString("N12");
/// <summary>
/// the sensitivity of the sensor on this channel (if any)
/// </summary>
public double Sensitivity => Channel?.SensorSensitivity ?? 0D;
/// <summary>
/// true as long as there is a TTS record associated with this physical channel
/// </summary>
public bool IsActive
{
get
{
if (null == Channel) return false;
if (null != Channel.HardwareChannel && Channel.HardwareChannel.IsDigitalOut)
{
return Channel.DigitalOutputMode != DigitalOutputModes.NONE;
}
return true;
}
}
/// <summary>
/// the capacity of the sensor associated with this physical channel (if any)
/// </summary>
public double Capacity => Channel?.SensorCapacity ?? 0D;
/// <summary>
/// the range of the sensor associated with this physical channel (if any)
/// </summary>
public double Range
{
get => Channel?.ChannelRange ?? 0D;
set
{
if (null != Channel)
{
Channel.ChannelRange = value;
Channel.IsModified = true;
}
}
}
public double CableMultiplier
{
get => Channel?.CableMultiplier ?? 1D;
set
{
if (null != Channel)
{
Channel.CableMultiplier = value;
Channel.IsModified = true;
}
}
}
/// <summary>
/// the delay in ms between trigger and squib fire
/// </summary>
public double SquibFireDelayMs
{
get => Channel?.SquibFireDelayMs ?? 0D;
set
{
if (null != Channel)
{
Channel.SquibFireDelayMs = value;
Channel.IsModified = true;
}
}
}
/// <summary>
/// the limit for current (amps)
/// </summary>
public double SquibFireCurrent
{
get => Channel?.SquibFireCurrent ?? 0D;
set
{
if (null != Channel)
{
Channel.SquibFireCurrent = value;
Channel.IsModified = true;
}
}
}
/// <summary>
/// whether to limit the duration or not of squib fire
/// </summary>
public bool LimitDuration
{
get
{
if (null == Channel) { return false; }
if (Channel.IsDigitalOutput && Channel.DigitalOutputMode == DigitalOutputModes.NONE) { return false; }
return Channel.LimitDuration;
}
set
{
if (null != Channel)
{
Channel.LimitDuration = value;
Channel.IsModified = true;
OnPropertyChanged("LimitDuration");
}
}
}
/// <summary>
/// the duration of the squib fire in ms from the start of firing
/// (if limiting duration)
/// </summary>
public double SquibFireDurationMs
{
get => Channel?.SquibFireDurationMs ?? .20D;
set
{
if (null != Channel)
{
Channel.SquibFireDurationMs = value;
Channel.IsModified = true;
}
}
}
/// <summary>
/// the squib resistance tolerance low value (ohms)
/// </summary>
public double SquibFireResistanceLowOhm
{
get => Channel?.SquibFireResistanceLowOhm ?? 1D;
set
{
if (null != Channel)
{
Channel.SquibFireResistanceLowOhm = value;
Channel.IsModified = true;
}
}
}
/// <summary>
/// the squib resistance tolerance high value (ohms)
/// </summary>
public double SquibFireResistanceHighOhm
{
get => Channel?.SquibFireResistanceHighOhm ?? 8D;
set
{
if (null != Channel)
{
Channel.SquibFireResistanceHighOhm = value;
Channel.IsModified = true;
}
}
}
/// <summary>
/// this is the hardware channel we are wrapping
/// </summary>
public IHardwareChannel HardwareChannel { get; }
#endregion
#region dependency properties
/// <summary>
/// the disabled property allows controls to make use of Disabled in styles, allow us to have a specific style for when a DASChannel is disabled
/// </summary>
public static readonly DependencyProperty DisabledProperty =
DependencyProperty.Register("Disabled", typeof(bool), typeof(DASChannel), new PropertyMetadata(false));
#endregion
#region methods
/// <summary>
/// Assigns this hardware to that TTSChannelRecord, or that channel record to this physical hardware
/// [depending on the POV]
/// </summary>
/// <param name="channel">the channel being assigned (can be null if removing a sensor from a physical channel)</param>
public void SetITTSChannelRecord(ITTSChannelRecord channel)
{
//if we are assigning something to this DASChannel, then any existing sensor
//record on this channel is no longer on it, so unassign the hardwareassignment to existing
if (null != Channel)
{
Channel.HardwareChannel = null;
}
Channel = channel;
//now assign the hardware channel on the channelrecord to this hardware channel
if (null != channel)
{
channel.HardwareChannel = HardwareChannel;
}
//clean up the ui
OnPropertyChanged("ToyotaCode");
OnPropertyChanged("EID");
OnPropertyChanged("Name");
OnPropertyChanged("SerialNumber");
OnPropertyChanged("SensitivityString");
OnPropertyChanged("IsActive");
OnPropertyChanged("Capacity");
OnPropertyChanged("Range");
OnPropertyChanged("Polarity");
OnPropertyChanged("CableMultiplier");
OnPropertyChanged("SquibFireDelayMs");
OnPropertyChanged("SquibFireCurrent");
OnPropertyChanged("LimitDuration");
OnPropertyChanged("SquibFireDurationMs");
OnPropertyChanged("SquibFireResistanceLowOhm");
OnPropertyChanged("SquibFireResistanceHighOhm");
OnPropertyChanged("InputMode");
OnPropertyChanged("OutputMode");
OnPropertyChanged("DigitalOutputDelayMs");
OnPropertyChanged("DigitalOutputDurationMs");
Disabled = channel?.Disabled ?? false;
}
/// <summary>
/// Adds a Digital Output channel to the Test Setup when DigitalOutputMode
/// changes from None to something other than None.
/// </summary>
private void AddDigitalOutputChannel()
{
var newChannels = new List<ITTSChannelRecord>(TestSetup.Channels);
newChannels.Add(Channel);
TestSetup.Channels = newChannels.ToArray();
}
/// <summary>
/// Removes a Digital Output channel from the Test Setup when DigitalOutputMode
/// changes to None.
/// </summary>
private void RemoveDigitalOutputChannel()
{
var newChannels = new List<ITTSChannelRecord>();
foreach (var channel in TestSetup.Channels)
{
if (channel.HardwareChannel != Channel.HardwareChannel)
{
newChannels.Add(channel);
}
}
TestSetup.Channels = newChannels.ToArray();
}
#endregion
}
}

View File

@@ -0,0 +1,16 @@
using DTS.Common.Interface;
// ReSharper disable CheckNamespace
namespace TTSImport
{
/// <summary>
/// Interaction logic for HardwareScanView.xaml
/// </summary>
public partial class LevelTriggerView : ILevelTriggerView
{
public LevelTriggerView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,166 @@
<base:BaseView x:Class="TTSImport.AnalogChannelsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:base="clr-namespace:DTS.Common.Base;assembly=DTS.Common"
xmlns:controls="clr-namespace:DTS.Common.Controls;assembly=DTS.Common"
xmlns:converters="clr-namespace:DTS.Common.Converters;assembly=DTS.Common"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:strings="clr-namespace:TTSImport"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="768" d:DesignWidth="1366"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
<base:BaseView.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Themes/CommonStyles.xaml"/>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Controls/combobox.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="ListView">
<Setter Property="ItemContainerStyle" Value="{StaticResource TTS_ListViewItemStyle}"/>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource TTS_TextBoxStyle}"/>
<Style TargetType="TextBlock" BasedOn="{StaticResource TTS_TextBlockStyle}"/>
<Style TargetType="CheckBox" BasedOn="{StaticResource PageContentCheckBoxStyle}" />
<Style TargetType="ComboBox" BasedOn="{StaticResource TTS_ComboBoxStyle}"/>
<Style TargetType="Button" BasedOn="{StaticResource TTS_ButtonStyle}"/>
<Style TargetType="GridViewColumnHeader" BasedOn="{StaticResource Gray_GridViewColumnHeaderStyle}"/>
<converters:BooleanToVisibilityConverter x:Key="BoolToVisibility" />
</ResourceDictionary>
</base:BaseView.Resources>
<Grid Background="{DynamicResource Brush_ApplicationContentBackground}"
ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<WrapPanel Orientation="Vertical" VerticalAlignment="Center" Grid.Column="1">
<Button Content="{strings:TranslateExtension Analog_Assign}" IsEnabled="{Binding AssignEnabled}" Width="85" AutomationProperties.AutomationId="Analog_AssignButton">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding AssignCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Content="{strings:TranslateExtension Analog_Remove}" IsEnabled="{Binding RemoveEnabled}" Width="85" AutomationProperties.AutomationId="Analog_RemoveButton">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding RemoveCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Content="{Binding EnableOrDisableText,FallbackValue=Enable}" IsEnabled="{Binding EnableOrDisableEnabled}" Width="85" AutomationProperties.AutomationId="Analog_EnableDisableButton">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding EnableOrDisableCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</WrapPanel>
<GroupBox Header="{strings:TranslateExtension RemainingChannels}" Grid.Column="2"
AutomationProperties.AutomationId="RemainingChannelsGroupBox">
<ListView ItemsSource="{Binding RemainingChannels}" SelectedItem="{Binding SelectedRemainingChannel}" AutomationProperties.AutomationId="RemainingChannelsListView">
<ListView.View>
<controls:AutoSizedGridView AutomationProperties.AutomationId="RemainingChannelsGridView">
<GridViewColumn Header="{strings:TranslateExtension Code}" AutomationProperties.AutomationId="ToyotaCode">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding ChannelCode}" MinWidth="130" AutomationProperties.AutomationId="ToyotaCodeTextBlock"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension SensorSN}" AutomationProperties.AutomationId="SensorSN">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding SensorSerialNumber}" MinWidth="130" AutomationProperties.AutomationId="SensorSNTextBlock"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</controls:AutoSizedGridView>
</ListView.View>
</ListView>
</GroupBox>
<GroupBox Header="{strings:TranslateExtension DASChannels}" Grid.Column="0"
AutomationProperties.AutomationId="DASChannelsGroupBox">
<ListView ItemsSource="{Binding DASChannels}" SelectedItem="{Binding SelectedDASChannel}" AutomationProperties.AutomationId="DASChannelsListView">
<ListView.View>
<controls:AutoSizedGridView AutomationProperties.AutomationId="DASChannelsGridView">
<GridViewColumn Header="{strings:TranslateExtension DASChannel}">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding DASChannelString}" MinWidth="130" AutomationProperties.AutomationId="DASChannelTextBlock"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Code}" AutomationProperties.AutomationId="ToyotaCode">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBox Text="{Binding ToyotaCode}" MinWidth="70" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="ToyotaCodeTextBox"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension EID}" >
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding EID}" MinWidth="100" AutomationProperties.AutomationId="EIDTextBlock"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension JHyphenCode}" AutomationProperties.AutomationId="Name">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBox Text="{Binding Name}" MinWidth="100" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="NameTextBox"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension SerialNumber}">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding SerialNumber}" MinWidth="80" AutomationProperties.AutomationId="SerialNumberTextBlock" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" />
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Sens}" AutomationProperties.AutomationId="Sensitivity">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding SensitivityString}" MinWidth="100" AutomationProperties.AutomationId="SensitivityTextBlock" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" />
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Capacity}" AutomationProperties.AutomationId="Capacity">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding Capacity}" MinWidth="50" AutomationProperties.AutomationId="CapacityTextBlock" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" />
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Range}" AutomationProperties.AutomationId="Range">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<xctk:DoubleUpDown ShowButtonSpinner="False" Value="{Binding Range}" MinWidth="50" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="RangeUpDown"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension Polarity}" AutomationProperties.AutomationId="Polarity">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<ComboBox ItemsSource="{Binding Polarities}" SelectedItem="{Binding Polarity, UpdateSourceTrigger=PropertyChanged}" Width="50" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="PolarityComboBox"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{strings:TranslateExtension CableMultiplier}" AutomationProperties.AutomationId="CableMultiplier">
<GridViewColumn.CellTemplate>
<ItemContainerTemplate>
<xctk:DoubleUpDown Value="{Binding CableMultiplier}" MinWidth="70" Visibility="{Binding IsActive, Converter={StaticResource BoolToVisibility}, ConverterParameter=HIDE}" AutomationProperties.AutomationId="CableMultiplierUpDown"/>
</ItemContainerTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</controls:AutoSizedGridView>
</ListView.View>
</ListView>
</GroupBox>
</Grid>
</base:BaseView>

View File

@@ -0,0 +1,16 @@
using DTS.Common.Interface;
// ReSharper disable CheckNamespace
namespace TTSImport
{
/// <summary>
/// Interaction logic for HardwareScanView.xaml
/// </summary>
public partial class HardwareScanView : IHardwareScanView
{
public HardwareScanView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,751 @@
using System;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Threading.Tasks;
using System.Windows;
using DTS.Common.Events;
using DTS.Common.Interface;
using DTS.Common.Interface.TestSetups.Imports.TTS.ReadFile;
using Prism.Events;
using Unity;
using DTS.Common.Interactivity;
using Prism.Regions;
using Prism.Commands;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using DTS.Common;
using DTS.Common.Interface.DataRecorders;
using DTS.Common.Base;
using DTS.Common.Classes;
using DTS.Common.Enums;
using DTS.Common.Events.TTSImport;
using TTSImport.Model;
using TTSImport.Resources;
// ReSharper disable CheckNamespace
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable InconsistentNaming
namespace TTSImport
{
/// <summary>
/// this class handles Summary functionality
/// </summary>
[PartCreationPolicy(CreationPolicy.Shared)]
public class SummaryViewModel : ISummaryViewModel
{
/// <summary>
/// The Status and Progress bars
/// </summary>
public IStatusAndProgressBarView StatusAndProgressBarView { get; private set; }
/// <summary>
/// The Summary view
/// </summary>
public ISummaryView View { get; set; }
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="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 SummaryViewModel(ISummaryView 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);
_eventAggregator.GetEvent<TTSImportTestSetupChangedEvent>().Subscribe(OnTestSetupChanged, ThreadOption.PublisherThread, true);
}
#region Methods
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()
{
StatusAndProgressBarView = GetStatusAndProgressBarView(this);
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
});
}
public string GetTestId()
{
return null == View ? "" : View.GetTestId();
}
private void OnReadFileFinished(ReadFileStatusArg statusArg)
{
TestSetupImported = false;
if (!statusArg.Status) return;
_setup = statusArg.TTSSetup;
View?.SetTestName(_setup.TestId);
OnPropertyChanged(PropertyNames.ImportFileName.ToString());
OnPropertyChanged(PropertyNames.TestSetupName.ToString());
OnPropertyChanged(PropertyNames.SampleRate.ToString());
OnPropertyChanged(PropertyNames.RecordingMode.ToString());
OnPropertyChanged(PropertyNames.TestLength.ToString());
OnPropertyChanged(PropertyNames.PreTrigger.ToString());
OnPropertyChanged(PropertyNames.PostTrigger.ToString());
OnPropertyChanged(PropertyNames.ROIStart.ToString());
OnPropertyChanged(PropertyNames.ROIEnd.ToString());
OnPropertyChanged(PropertyNames.AAF_TDAS.ToString());
OnPropertyChanged(PropertyNames.AAF_SLICE.ToString());
}
private void OnTestSetupChanged(ITTSSetup setup)
{
TestSetupImported = false;
}
public void UpdateUI()
{
SampleRate = _setup.SampleRate;
SetAvailableRecordingModes();
RecordingMode = _setup.Mode;
SetChannelList();
TestSetupComplete = !SummaryChannelList.Exists(channelType => (channelType.Unassigned != "0") && (channelType.Unassigned != Resources.StringResources.Table_NA));
if (!TestSetupComplete || Array.Exists(_setup.Channels, channel => channel.IsModified) || Array.Exists(_setup.LevelTriggers, levelTrigger => levelTrigger.IsModified))
{
TestSetupImported = false;
}
}
private List<double> _availableSampleRates = new List<double>();
public List<double> AvailableSampleRates
{
get => _availableSampleRates;
set
{
_availableSampleRates = value;
OnPropertyChanged("AvailableSampleRates");
}
}
public void SetAvailableSampleRates(int[] values)
{
AvailableSampleRates.Clear();
var minSampleRate = (double)values.Min();
var maxSampleRate = (double)values.Max();
foreach (var channel in _setup.Channels)
{
if (channel.HardwareChannel == null) continue;
minSampleRate = Math.Max(channel.HardwareChannel.GetParentDAS().GetMinSampleRateDouble(), minSampleRate);
maxSampleRate = Math.Min(channel.HardwareChannel.GetParentDAS().GetMaxSampleRateDouble(), maxSampleRate);
}
foreach (var sampleRate in values)
{
if (sampleRate >= minSampleRate && sampleRate <= maxSampleRate)
{
AvailableSampleRates.Add(sampleRate);
}
}
}
public string AAF_TDAS => string.Format(StringResources.AAF_TDAS, !_aafExceptions.ContainsKey(SampleRate) ? (SampleRate / 5) : _aafExceptions[SampleRate][0]);
public string AAF_SLICE => string.Format(StringResources.AAF_SLICE, !_aafExceptions.ContainsKey(SampleRate) ? (SampleRate / 5) : _aafExceptions[SampleRate][1]);
private Dictionary<double, List<double>> _aafExceptions = new Dictionary<double, List<double>>();
public void SetAAFExceptions(Dictionary<double, List<double>> values)
{
_aafExceptions.Clear();
_aafExceptions = values;
}
public List<RecordingModes> AvailableRecordingModes { get; } = new List<RecordingModes>();
private void SetAvailableRecordingModes()
{
AvailableRecordingModes.Clear();
AvailableRecordingModes.Add(RecordingModes.CircularBuffer);
AvailableRecordingModes.Add(RecordingModes.Recorder);
if (_setup.AllowAdvancedRecordingModes)
{
AvailableRecordingModes.Add(RecordingModes.HybridRecorder);
}
}
public void SetSerializedTestIdValues(string[] values)
{
View?.UpdateTestIds(values);
}
/// <summary>
/// Fill in the table of channels, including those added after the file was read
/// </summary>
public void SetChannelList()
{
const int Assigned = 0;
const int Unassigned = 1;
var analogChannels = new[] { 0, 0 };
var tomChannels = new[] { 0, 0 };
var digitalInChannels = new[] { 0, 0 };
var levelTriggers = new[] { 0, 0 };
foreach (var channelRecord in _setup.Channels)
{
if (string.Equals(channelRecord.ChannelCode, TTSChannelRecord.NONE, StringComparison.CurrentCultureIgnoreCase) || channelRecord.Disabled) continue;
if (channelRecord.IsSquib)
{
if (channelRecord.HardwareChannel != null && channelRecord.HardwareChannel.IsSquib)
{
tomChannels[Assigned] += 1;
}
else
{
tomChannels[Unassigned] += 1;
}
}
else if (channelRecord.IsDigitalInput)
{
if (channelRecord.HardwareChannel != null && channelRecord.HardwareChannel.IsDigitalIn)
{
digitalInChannels[Assigned] += 1;
}
else
{
digitalInChannels[Unassigned] += 1;
}
}
else if (!channelRecord.IsDigitalOutput)
{
if (channelRecord.HardwareChannel != null && channelRecord.HardwareChannel.IsAnalog)
{
analogChannels[Assigned] += 1;
}
else
{
analogChannels[Unassigned] += 1;
}
}
}
foreach (var levelTrigger in _setup.LevelTriggers)
{
if (!string.IsNullOrWhiteSpace(levelTrigger.Code))
{
levelTriggers[Assigned] += 1;
}
}
var temp = new List<SummaryChannel>();
var channel = new SummaryChannel
{
ChannelType = "Analog", //internationalize these
Assigned = analogChannels[Assigned],
Unassigned = analogChannels[Unassigned].ToString()
};
temp.Add(channel);
channel = new SummaryChannel
{
ChannelType = "TOM",
Assigned = tomChannels[Assigned],
Unassigned = tomChannels[Unassigned].ToString()
};
temp.Add(channel);
channel = new SummaryChannel
{
ChannelType = "Digital In",
Assigned = digitalInChannels[Assigned],
Unassigned = digitalInChannels[Unassigned].ToString()
};
temp.Add(channel);
channel = new SummaryChannel
{
ChannelType = "Level Trigger",
Assigned = levelTriggers[Assigned],
Unassigned = Resources.StringResources.Table_NA
};
temp.Add(channel);
SummaryChannelList = temp;
}
private readonly StatusAndProgressBarEventArgs statusAndProgressBarEventArgs = new StatusAndProgressBarEventArgs();
/// <summary>
/// Sets the text, background color, progress value, and/or progress visibility
/// </summary>
/// <param name="status"></param>
/// <param name="error"></param>
public void SetStatus(string status, string error = default(string)) //default(string) is null
{
switch (status)
{
case "Waiting": //change this to string resources but use the same one in DataPRO and here???
statusAndProgressBarEventArgs.StatusColor = BrushesAndColors.Brush_ApplicationStatus_Waiting.Color;
statusAndProgressBarEventArgs.ProgressBarVisibility = Visibility.Collapsed;
break;
case "Working":
statusAndProgressBarEventArgs.StatusColor = BrushesAndColors.Brush_ApplicationStatus_Busy.Color;
statusAndProgressBarEventArgs.ProgressValue = 0;
statusAndProgressBarEventArgs.ProgressBarVisibility = Visibility.Visible;
break;
case "Failed":
TestSetupImported = false;
statusAndProgressBarEventArgs.StatusColor = BrushesAndColors.Brush_ApplicationStatus_Failed.Color;
statusAndProgressBarEventArgs.ProgressBarVisibility = Visibility.Collapsed;
break;
case "Done":
TestSetupImported = true;
foreach (var ch in _setup.Channels)
{
ch.IsModified = false;
}
foreach (var lt in _setup.LevelTriggers)
{
lt.IsModified = false;
}
statusAndProgressBarEventArgs.StatusColor = BrushesAndColors.Brush_ApplicationStatus_Complete.Color;
statusAndProgressBarEventArgs.ProgressBarVisibility = Visibility.Collapsed;
break;
}
if (!string.IsNullOrEmpty(error))
{
statusAndProgressBarEventArgs.StatusText = status + " - " + error;
}
else
{
statusAndProgressBarEventArgs.StatusText = status;
}
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;
}
#endregion
#region Properties
private ITTSSetup _setup;
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");
}
}
private List<SummaryChannel> _summaryChannelList = new List<SummaryChannel>();
public List<SummaryChannel> SummaryChannelList
{
get => _summaryChannelList;
set
{
_summaryChannelList = value;
OnPropertyChanged("SummaryChannelList");
}
}
private bool _testSetupComplete;
public bool TestSetupComplete
{
get => _testSetupComplete;
set
{
_testSetupComplete = value;
OnPropertyChanged("ImportEnabled");
}
}
private bool _testSetupImported;
public bool TestSetupImported
{
get => _testSetupImported;
set
{
_testSetupImported = value;
OnPropertyChanged("RunTestVisible");
}
}
public bool ImportEnabled => TestSetupComplete & IsROIValid;
public Visibility RunTestVisible => TestSetupImported ? Visibility.Visible : Visibility.Hidden;
public Visibility SummaryPreTriggerVisibility => RecordingMode == RecordingModes.CircularBuffer ? Visibility.Visible : Visibility.Collapsed;
public string PostTriggerOrTestLength => RecordingMode == RecordingModes.CircularBuffer ? StringResources.PostTrigger : StringResources.TestLength;
private bool _isROIStartValid = true;
public bool IsROIStartValid
{
get => _isROIStartValid;
set
{
_isROIStartValid = value;
OnPropertyChanged("IsROIStartValid");
}
}
private bool _isROIEndValid = true;
public bool IsROIEndValid
{
get => _isROIEndValid;
set
{
_isROIEndValid = value;
OnPropertyChanged("IsROIEndValid");
}
}
private void CalculateROIValid()
{
if (null == _setup)
{
IsROIEndValid = true;
IsROIStartValid = true;
return;
}
if (_setup.ROIEnd < _setup.ROIStart)
{
IsROIStartValid = false;
IsROIEndValid = false;
return;
}
if (RecordingMode == RecordingModes.Recorder)
{
IsROIStartValid = true;
IsROIEndValid = !(_setup.ROIEnd - _setup.ROIStart > _setup.PostTrigger);
}
else
{
IsROIEndValid = !(_setup.ROIEnd > _setup.PostTrigger);
IsROIStartValid = !(Math.Abs(_setup.ROIStart) > _setup.PreTrigger);
}
}
public bool IsROIValid
{
get
{
CalculateROIValid();
return IsROIStartValid && IsROIEndValid;
}
}
//=> RecordingMode != RecordingModes.Recorder || !(_setup.ROIEnd - _setup.ROIStart > _setup.PostTrigger);
#endregion Properties
#region Commands
/// <summary>
/// browse to a file to import, should be xml, maybe needs a few other criteria
/// </summary>
private DelegateCommand _importCommand;
public DelegateCommand ImportClicked => _importCommand ?? (_importCommand = new DelegateCommand(ImportMethod));
private void ImportMethod()
{
_eventAggregator.GetEvent<TTSImportSummaryImportEvent>().Publish(_setup);
}
/// <summary>
/// Run the test since the Run Test button was clicked
/// </summary>
private DelegateCommand _runTestCommand;
public DelegateCommand RunTestClicked =>
_runTestCommand ?? (_runTestCommand = new DelegateCommand(RunTestMethod));
private void RunTestMethod()
{
SetStatus(Resources.StringResources.ImportTestSetup_PossibleStatus_Working); //use string resource (same both here and where passed)
ThreadPool.QueueUserWorkItem(RunTestWorkThread, null);
}
void RunTestWorkThread(object obj)
{
_eventAggregator.GetEvent<TTSImportSummaryRunTestEvent>().Publish(_setup);
}
#endregion
#region properties
/// <summary>
/// all properties that are exposed
/// </summary>
public enum PropertyNames
{
ImportFileName,
TestSetupName,
SampleRate,
RecordingMode,
TestLength,
PreTrigger,
PostTrigger,
ROIStart,
ROIEnd,
AAF_TDAS,
AAF_SLICE,
AllowAdvancedRecordingModes,
AllowTSRAIRRecordingModes
}
/// <summary>
/// full path to import file
/// </summary>
public string ImportFileName => _setup?.Filename ?? "";
public string TestSetupName
{
get => _setup?.TestId ?? "";
set
{
TestSetupImported = false;
_setup.TestId = value;
View?.SetTestName(_setup.TestId);
}
}
public double SampleRate
{
get => _setup?.SampleRate ?? 10000;
set
{
if (_setup.SampleRate != value)
{
TestSetupImported = false;
_setup.SampleRate = value;
}
OnPropertyChanged(PropertyNames.SampleRate.ToString());
OnPropertyChanged(PropertyNames.AAF_TDAS.ToString());
OnPropertyChanged(PropertyNames.AAF_SLICE.ToString());
}
}
private void OnPropertyChanged(PropertyNames sampleRate)
{
throw new NotImplementedException();
}
public RecordingModes RecordingMode
{
get => _setup?.Mode ?? RecordingModes.CircularBuffer;
set
{
if (_setup.Mode != value)
{
TestSetupImported = false;
switch (value)
{
case RecordingModes.CircularBuffer:
case RecordingModes.Recorder:
case RecordingModes.HybridRecorder:
_setup.Mode = value;
break;
default:
_setup.Mode = RecordingModes.CircularBuffer;
break;
}
}
OnPropertyChanged("RecordingMode");
OnPropertyChanged("SummaryPreTriggerVisibility");
OnPropertyChanged("PostTriggerOrTestLength");
OnPropertyChanged("IsROIValid");
OnPropertyChanged("ImportEnabled");
}
}
public string PreTrigger
{
get => _setup?.PreTrigger.ToString("0.00") ?? "";
set
{
if (!double.TryParse(value, out double preTrigger)) return;
//if (preTrigger * -1 > _setup.ROIStart) ROIStart = (preTrigger * -1).ToString("0.00");
//if (preTrigger * -1 > _setup.ROIEnd) ROIEnd = (preTrigger * -1).ToString("0.00");
TestSetupImported = false;
_setup.PreTrigger = preTrigger;
OnPropertyChanged("PreTrigger");
OnPropertyChanged("IsROIValid");
OnPropertyChanged("ImportEnabled");
}
}
public string PostTrigger
{
get => _setup?.PostTrigger.ToString("0.00") ?? "";
set
{
if (!double.TryParse(value, out double postTrigger)) return;
//if (postTrigger < _setup.ROIStart) ROIStart = postTrigger.ToString("0.00");
//if (postTrigger < _setup.ROIEnd) ROIEnd = postTrigger.ToString("0.00");
TestSetupImported = false;
_setup.PostTrigger = postTrigger;
OnPropertyChanged("PostTrigger");
OnPropertyChanged("IsROIValid");
OnPropertyChanged("ImportEnabled");
}
}
public string ROIStart
{
get => _setup?.ROIStart.ToString("0.00") ?? "";
set
{
if (!double.TryParse(value, out double roiStart)) return;
if (roiStart < _setup.PreTrigger * -1 || roiStart > _setup.PostTrigger || roiStart > _setup.ROIEnd) return;
TestSetupImported = false;
_setup.ROIStart = roiStart;
OnPropertyChanged("ROIStart");
OnPropertyChanged("IsROIValid");
OnPropertyChanged("ImportEnabled");
}
}
public string ROIEnd
{
get => _setup?.ROIEnd.ToString("0.00") ?? "";
set
{
if (!double.TryParse(value, out double roiEnd)) return;
if (roiEnd < _setup.PreTrigger * -1 || roiEnd > _setup.PostTrigger || roiEnd < _setup.ROIStart) return;
TestSetupImported = false;
_setup.ROIEnd = roiEnd;
OnPropertyChanged("ROIEnd");
OnPropertyChanged("IsROIValid");
OnPropertyChanged("ImportEnabled");
}
}
#endregion
///<summary>
///Occurs when a property value changes.
///</summary>
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -0,0 +1,53 @@
<base:BaseView x:Class="TTSImport.ReadFileView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:base="clr-namespace:DTS.Common.Base;assembly=DTS.Common"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:root="clr-namespace:TTSImport"
xmlns:controls="clr-namespace:DTS.Common.Controls;assembly=DTS.Common">
<base:BaseView.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/DTS.Common;component/Themes/CommonStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="TextBlock" BasedOn="{StaticResource PageContentTextStyle}" >
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Margin" Value="5" />
</Style>
<Style TargetType="TextBox">
<Setter Property="Margin" Value="5" />
</Style>
<Style TargetType="Button">
<Setter Property="Margin" Value="5" />
</Style>
</ResourceDictionary>
</base:BaseView.Resources>
<Grid Background="{DynamicResource Brush_ApplicationContentBackground}" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="160"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ContentControl Content="{Binding StatusAndProgressBarView}" Grid.Row="0" Grid.ColumnSpan="4" Height="100" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="{root:TranslateExtension ImportFile}" VerticalAlignment="Top"/>
<Button Grid.Row="1" Grid.Column="1" Content="{root:TranslateExtension Browse}" Width="150" HorizontalAlignment="Left" AutomationProperties.AutomationId="btnBrowse" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding BrowseClicked}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<TextBlock Grid.Row="1" Grid.Column="2" TextWrapping="Wrap" Height="40"
Text="{Binding FileToImport, FallbackValue='C:\\Data\\Long Path Here\\Data\\Long Path Here\\Data\\Long Path Here\\Data\\Long Path Here\\Data\\Long Path Here\\Import.csv'}" x:Name="tbExportFile"
AutomationProperties.AutomationId="FileToImport" />
</Grid>
</base:BaseView>

View File

@@ -0,0 +1,18 @@
using DTS.Common.Interface.TestSetups.Imports.TTS.DIChannels;
// ReSharper disable CheckNamespace
namespace TTSImport
{
/// <inheritdoc cref="IDigitalInputChannelsView" />
/// <summary>
/// Interaction logic for HardwareScanView.xaml
/// </summary>
public partial class DigitalInputChannelsView : IDigitalInputChannelsView
{
public DigitalInputChannelsView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,29 @@
using DTS.Common.Interface.TestSetups.Imports.TTS;
using System.Windows.Controls;
namespace TTSImport
{
/// <summary>
/// Interaction logic for EditFileView.xaml
/// </summary>
public partial class EditFileView : IEditFileView
{
public EditFileView()
{
InitializeComponent();
}
/// <summary>
/// handles when textbox text is changed
/// this signals that we need to filter the available sensors
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var tb = (TextBox)sender;
var text = tb.Text;
var vm = (IEditFileViewModel)tb.DataContext;
vm.Search(text);
}
}
}

View File

@@ -0,0 +1,325 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DTS.Common.Base;
using DTS.Common.Interface.TestSetups.Imports.TTS.LevelTrigger;
using DTS.Common.Interface.TestSetups.Imports.TTS.ReadFile;
using DTS.Common.Utilities.Logging;
namespace TTSImport.Model
{
/// <summary>
/// this class represents a level trigger for TTS
/// for a level trigger you need a sensor and a hardware channel
/// the role of the sensor is fulfulled by a ITTSChannelRecord for TTS level triggers
/// </summary>
public class TTSLevelTriggerRecord : BasePropertyChanged, ILevelTrigger
{
#region properties
/// <summary>
/// the channel code of the channel record this level trigger applies to (if any)
/// </summary>
public string Code => Channel?.ChannelCode ?? "";
/// <summary>
/// the JCODE of the channel record associated with this level trigger (if any)
/// </summary>
public string JCode => Channel?.JCodeOrDescription ?? "";
/// <summary>
/// the level trigger is expressed in EU, but the UI
/// lets you convert between a % of full scale and an explicit EU value
/// </summary>
private double _valuePercent;
public double ValuePercent
{
get => _valuePercent;
set
{
_valuePercent = value;
IsModified = true;
RecalculateEUValue();
}
}
/// <summary>
/// the EU threshold for the level trigger
/// </summary>
private double _valueEU = 0D;
public double ValueEU
{
get => _valueEU;
set
{
_valueEU = value;
IsModified = true;
RecalculatePercent();
}
}
/// <summary>
/// the engineering units for the sensor associated with the level trigger (if any)
/// </summary>
public string EULabel => Channel?.SensorEU ?? "";
/// <summary>
/// the display string of the hardware channel associated with the level trigger (if any)
/// </summary>
public string HWSerialNumber => Channel?.HardwareChannel?.ToString() ?? "";
/// <summary>
/// the TTS channel number of the channel associated with the sensor associated with this level trigger (if any)
/// </summary>
public int ChannelNumber => Channel?.ChannelNumber ?? 0;
/// <summary>
/// the TTS channel record associated with this physical channel (if any)
/// </summary>
private ITTSChannelRecord _channel;
public ITTSChannelRecord Channel
{
get => _channel;
set
{
_channel = value;
IsModified = true;
OnPropertyChanged("Code");
OnPropertyChanged("JCode");
OnPropertyChanged("EULabel");
OnPropertyChanged("HWSerialNumber");
OnPropertyChanged("ChannelNumber");
OnPropertyChanged("IsActive");
//we've just set this level trigger, which potentially affects other level triggers
//it might be sufficient to just raise the available channels notification, but
//the refresh method will do that
foreach (var lt in TestSetup.LevelTriggers)
{
if (lt == this) { continue; }
lt.Refresh();
}
}
}
private const int MAX_G5_LEVELTRIGGER = 2;
/// <summary>
/// the test setup from which all channels come
/// and to which the level trigger itself is associated with
/// </summary>
public ITTSSetup TestSetup { get; }
/// <summary>
/// available channels/sensors that could be chosen to associate this level trigger with
/// requires that channel has a channel code and an associated physical hardware channel
/// already
/// </summary>
public ITTSChannelRecord[] AvailableChannels
{
get
{
//we want to make sure no code is reused
//and we want to make sure no sim is reused
var existingCodesHash = new HashSet<string>();
var existingSIMs = new HashSet<string>();
//make sure only 2 per G5
//g5 serial to level trigger count
var existingG5 = new Dictionary<string, int>();
foreach (var lt in TestSetup.LevelTriggers)
{
if (lt == this)
{
continue;
}
if (null == lt.Channel) continue;
existingCodesHash.Add(lt.Channel.ChannelCode);
if (null == lt.Channel.HardwareChannel) continue;
if (lt.Channel.HardwareChannel.GetParentDAS().IsTDASRack())
{
existingSIMs.Add(lt.Channel.HardwareChannel.ModuleSerialNumber);
}
else if (lt.Channel.HardwareChannel.GetParentDAS().IsG5())
{
var key = lt.Channel.HardwareChannel.GetParentDAS().SerialNumber;
if (!existingG5.ContainsKey(key))
{
existingG5[key] = 1;
}
else
{
existingG5[key] = existingG5[key] + 1;
}
}
}
var channels = new List<ITTSChannelRecord> { new TTSChannelRecord() };
if (null == TestSetup) return channels.ToArray();
foreach (var ch in TestSetup.Channels)
{
if (ch.Disabled) { continue; }
if (ch.IsEmptyRecord)
{
channels.Add(ch);
}
else if (null != ch.HardwareChannel)
{
//Digital Input channels must be initialized to either the default in the config file, or CCNO if a G5
if (ch.IsDigitalInput)
{
ch.DigitalInputMode = DTS.Common.Enums.DigitalInputModes.CCNO;
}
if (ch.IsDigitalInput || ch.IsDigitalOutput || ch.IsSquib) { continue; }
//only allow analog linear sensors
switch (ch.ChannelType)
{
case DTS.Common.Enums.TTS.ToyotaBridgeType.FullBridge:
case DTS.Common.Enums.TTS.ToyotaBridgeType.HalfBridge:
case DTS.Common.Enums.TTS.ToyotaBridgeType.Voltage:
case DTS.Common.Enums.TTS.ToyotaBridgeType.PotentionmeterFullBridge:
case DTS.Common.Enums.TTS.ToyotaBridgeType.PotentionmeterHalfBridge:
break;
//full bridge, half bridge are allowed, everything else ignore
default:
continue;
}
if (existingCodesHash.Contains(ch.ChannelCode)) { continue; }
if (existingSIMs.Contains(ch.HardwareChannel.ModuleSerialNumber))
{
continue;
}
if (ch.HardwareChannel.GetParentDAS().IsG5())
{
var key = ch.HardwareChannel.GetParentDAS().SerialNumber;
if (existingG5.ContainsKey(key))
{
if (existingG5[key] >= MAX_G5_LEVELTRIGGER)
{
continue;
}
}
}
channels.Add(ch);
}
}
return channels.ToArray();
}
}
/// <summary>
/// returns true if there's an associated sensor and physical hardware channel for this level trigger
/// </summary>
public bool IsActive
{
get
{
if (null == Channel)
{
return false;
}
return !Channel.IsEmptyRecord;
}
}
public bool IsModified { get; set; }
#endregion
#region methods
public byte[] GetBytes()
{
var bytes = new List<byte>();
if (!IsActive) return bytes.ToArray();
bytes.AddRange(Encoding.UTF8.GetBytes(Code ?? ""));
bytes.AddRange(Encoding.UTF8.GetBytes(JCode ?? ""));
bytes.AddRange(BitConverter.GetBytes(ValueEU));
bytes.AddRange(Encoding.UTF8.GetBytes(HWSerialNumber ?? ""));
return bytes.ToArray();
}
/// <summary>
/// recalculates the EU threshold based on the current percentage of full scale threshold
/// </summary>
private void RecalculateEUValue()
{
if (null != Channel)
{
_valueEU = ValuePercent / 100D * Channel.ChannelRange;
OnPropertyChanged("ValueEU");
}
}
/// <summary>
/// recalculates the threshold as a % of full scale based on current EU threshold
/// </summary>
private void RecalculatePercent()
{
if (null != Channel)
{
_valuePercent = 100D * ValueEU / Channel.ChannelRange;
OnPropertyChanged("ValuePercent");
}
}
public override string ToString()
{
return Code;
}
private volatile bool _bInRefresh = false;
/// <summary>
/// refreshes what the available channels are
/// </summary>
public void Refresh()
{
try
{
if (_bInRefresh) { return; }
_bInRefresh = true;
var channels = AvailableChannels;
OnPropertyChanged("AvailableChannels");
//if there's a channel assigned make sure it's an available channel ...
//if not then reverse the channel assignment
//this might happen if the user removed the hardware assignment
if (null == Channel)
{
return;
}
var matches = from ch in channels where ch == Channel select ch;
if (matches.Any()) return;
var match = (from ch in channels where ch.ChannelCode == Channel.ChannelCode select ch).FirstOrDefault();
if (null != match)
{
Channel = match;
return;
}
Channel = null;
}
catch (Exception ex)
{
APILogger.Log(ex);
}
finally { _bInRefresh = false; }
}
/// <inheritdoc />
/// <summary>
/// adds the channel as a possible channel for level trigger
/// </summary>
/// <param name="channel"></param>
public void Add(ITTSChannelRecord channel)
{
OnPropertyChanged("AvailableChannels");
}
/// <inheritdoc />
/// <summary>
/// removes the channel as a possible channel for level trigger,
/// unassigns channel if currently assigned
/// </summary>
/// <param name="channel"></param>
public void Remove(ITTSChannelRecord channel)
{
if (Channel != channel) return;
Channel = null;
OnPropertyChanged("AvailableChannels");
}
#endregion
#region constructors
public TTSLevelTriggerRecord(ITTSSetup setup)
{
TestSetup = setup;
}
#endregion
}
}

View File

@@ -0,0 +1,563 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using DTS.Common.DAS.Concepts;
using DTS.Common.Enums;
using DTS.Common.Enums.Sensors;
using DTS.Common.Enums.TTS;
using DTS.Common.Interface.DataRecorders;
using DTS.Common.Interface.TestSetups.Imports.TTS;
using DTS.Common.Interface.TestSetups.Imports.TTS.ReadFile;
using DTS.SensorDB;
using Prism.Commands;
using TTSImport.Resources;
namespace TTSImport.Model
{
/// <inheritdoc />
/// <summary>
/// this class represents a line in the TTS import CSV,
/// </summary>
public class TTSChannelRecord : DTS.Common.Base.BasePropertyChanged, ITTSChannelRecord
{
#region INotifyPropertyChanged
public override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
switch (propertyName)
{
case "ChannelCode":
case "JCodeOrDescription":
case "ChannelRange":
case "ChannelFilterHz":
if (Parent != null)
{
Parent.ChangeValidationIsNeeded = true;
}
break;
}
}
#endregion
#region enums
public const string CFC1000 = "1650";
public const string CFC600 = "1000";
public const string CFC180 = "300";
public const string CFC60 = "100";
public const string CFC10 = "17";
public const string NONE = "None";
public IEnumerable<string> Filters => new[] { CFC1000, CFC600, CFC180, CFC60, CFC10, NONE };
public const string DIAGNOSTICSMODE = "DIAGNOSTICSMODE";
#endregion enums
private const string SYSTEMSETTING = "0.###";
private string STRINGDISPLAYFORMAT_CHANNELRANGE = SYSTEMSETTING; //Get the value from the UI in System Settings
public IEditFileViewModel Parent { get; set; }
private int _channelNumber;
public int ChannelNumber
{
get => _channelNumber;
set => SetProperty(ref _channelNumber, value, "ChannelNumber");
}
private string _channelCode;
public string ChannelCode
{
get => _channelCode ?? "";
set => SetProperty(ref _channelCode, value, "ChannelCode");
}
private string _jCodeOrDescription;
public string JCodeOrDescription
{
get => _jCodeOrDescription ?? "";
set
{
_jCodeOrDescription = value;
IsJCodeValid = !string.IsNullOrEmpty(value);
OnPropertyChanged("JCodeOrDescription");
}
}
private double _channelRange;
public double ChannelRange
{
get => _channelRange;
set
{
_channelRange = value;
IsRangeValid = !double.IsNaN(value) && value > 0;
OnPropertyChanged("ChannelRange");
}
}
public string ChannelRangeString
{
get => ChannelRange <= 0 ? string.Empty : ChannelRange.ToString(STRINGDISPLAYFORMAT_CHANNELRANGE); //Should use the UI setting
set
{
if (double.TryParse(value, out double range))
{
ChannelRange = range;
IsRangeValid = true;
}
else
{
ChannelRange = double.NaN;
IsRangeValid = false;
}
OnPropertyChanged("ChannelRangeString");
}
}
public Visibility RangeVisible
{
get
{
if (!IsSquib && !IsDigitalInput && !IsDigitalOutput)
{
return Visibility.Visible;
}
return Visibility.Hidden;
}
}
private int _channelFilterHz;
public int ChannelFilterHz
{
get => _channelFilterHz;
set
{
_channelFilterHz = value;
IsFilterValid = value != -1;
OnPropertyChanged("ChannelFilterHz");
}
}
public string FilterString
{
get => ChannelFilterHz <= 0 ? "" : ChannelFilterHz.ToString("F0");
set
{
if (int.TryParse(value, out int filter) || filter > 0)
{
if (filter == 1650 || filter == 1000 || filter == 300 || filter == 100 || filter == 17)
{
ChannelFilterHz = filter;
IsFilterValid = true;
}
else
{
ChannelFilterHz = -1;
IsFilterValid = false;
}
}
else
{
ChannelFilterHz = 0;
IsFilterValid = true; //Is this right?
}
OnPropertyChanged("FilterString");
}
}
public Visibility FilterVisible
{
get
{
if (!IsSquib && !IsDigitalInput && !IsDigitalOutput)
{
return Visibility.Visible;
}
return Visibility.Hidden;
}
}
private string _sensorSerialNumber;
public string SensorSerialNumber
{
get => _sensorSerialNumber ?? "";
set => SetProperty(ref _sensorSerialNumber, value, "SensorSerialNumber");
}
private DelegateCommand<string> _controlLostFocus;
public DelegateCommand<string> ControlLostFocus => _controlLostFocus ?? (_controlLostFocus = new DelegateCommand<string>(ControlLostFocusMethod));
public void ControlLostFocusMethod(string code)
{
if (!Parent.ChangeValidationIsNeeded) return;
Parent.ValidateChange(this);
}
private DelegateCommand<string> _filterSelectionChanged;
public DelegateCommand<string> FilterSelectionChanged => _filterSelectionChanged ?? (_filterSelectionChanged = new DelegateCommand<string>(FilterSelectionChangedMethod));
public void FilterSelectionChangedMethod(string code)
{
if (!Parent.ChangeValidationIsNeeded) return;
Parent.ValidateChange();
}
public string SensorEID { get; set; }
public double SensorSensitivity { get; set; }
public double SensorExcitationVolts { get; set; }
public double SensorCapacity { get; set; }
public string SensorEU { get; set; }
public bool SensorPolarity { get; set; }
public ToyotaBridgeType ChannelType { get; set; }
public string Description { get; set; }
public bool ProportionalToExcitation { get; set; }
public double BridgeResistance { get; set; }
public double InitialOffsetVoltage { get; set; }
public double InitialOffsetVoltageTolerance { get; set; }
public bool RemoveOffset { get; set; }
public ToyotaZeroMethods ZeroMethod { get; set; }
public double CableMultiplier { get; set; }
public double InitialEUInMV { get; set; }
public double InitialEUInEU { get; set; }
public double IRTraccExponent { get; set; }
public double PolynomialConstant { get; set; }
public double PolynomialCoefficientC { get; set; }
public double PolynomialCoefficentB { get; set; }
public double PolynomialCoefficientA { get; set; }
public double PolynomialCoefficientAlpha { get; set; }
public string ISOCode { get; set; }
public string ISODescription { get; set; }
public string ISOPolarity { get; set; }
public bool IsSquib { get; set; }
public bool IsDigitalInput { get; set; }
public bool IsDigitalOutput { get; set; }
public IHardwareChannel HardwareChannel { get; set; }
/// <inheritdoc />
/// <summary>
/// returns true if the record is empty (no channel code and no sensor serial number)
/// </summary>
public bool IsEmptyRecord => ChannelCode == StringResources.NONE && string.IsNullOrWhiteSpace(SensorSerialNumber);
/// <summary>
/// returns whether the channelcode is valid or not
/// </summary>
private bool _isChannelCodeValid;
public bool IsChannelCodeValid
{
get => _isChannelCodeValid;
set => SetProperty(ref _isChannelCodeValid, value, "IsChannelCodeValid");
}
private bool _isJCodeValid;
public bool IsJCodeValid
{
get => _isJCodeValid;
set => SetProperty(ref _isJCodeValid, value, "IsJCodeValid");
}
private bool _isRangeValid;
public bool IsRangeValid
{
get => _isRangeValid;
set => SetProperty(ref _isRangeValid, value, "IsRangeValid");
}
private bool _isFilterValid;
public bool IsFilterValid
{
get => _isFilterValid;
set => SetProperty(ref _isFilterValid, value, "IsFilterValid");
}
/// <inheritdoc />
/// <summary>
/// disabled channels are channels which are in the test setup, but aren't used during run test
/// </summary>
public bool Disabled { get; set; }
/// <inheritdoc />
/// <summary>
/// for squibs, controls the squib fire mode
/// </summary>
public SquibFireMode SquibFireMode { get; set; }
/// <inheritdoc />
/// <summary>
/// the delay in ms between trigger and squib fire
/// </summary>
public double SquibFireDelayMs { get; set; }
/// <inheritdoc />
/// <summary>
/// the limit for current (amps)
/// </summary>
public double SquibFireCurrent { get; set; }
/// <inheritdoc />
/// <summary>
/// whether to limit the duration or not of squib fire
/// </summary>
public bool LimitDuration { get; set; }
/// <summary>
/// the duration of the squib fire in ms from the start of firing
/// (if limiting duration)
/// </summary>
private double _squibFireDurationMs;
public double SquibFireDurationMs
{
get => _squibFireDurationMs;
set => _squibFireDurationMs = value < DTS.DASLib.Service.OutputSquibChannel.DEFAULT_MIN_FIRE_DURATION_MS
? DTS.DASLib.Service.OutputSquibChannel.DEFAULT_MIN_FIRE_DURATION_MS
: value > DTS.DASLib.Service.OutputSquibChannel.DEFAULT_MAX_FIRE_DURATION_MS
? DTS.DASLib.Service.OutputSquibChannel.DEFAULT_MAX_FIRE_DURATION_MS
: value;
}
/// <inheritdoc />
/// <summary>
/// the squib resistance tolerance low value (ohms)
/// </summary>
public double SquibFireResistanceLowOhm { get; set; }
/// <inheritdoc />
/// <summary>
/// the squib resistance tolerance high value (ohms)
/// </summary>
public double SquibFireResistanceHighOhm { get; set; }
/// <inheritdoc />
/// <summary>
/// digital input mode (if relevant)
/// </summary>
public DigitalInputModes DigitalInputMode { get; set; }
/// <inheritdoc />
/// <summary>
/// the digital output mode (if relevant)
/// </summary>
public DigitalOutputModes DigitalOutputMode { get; set; }
/// <inheritdoc />
/// <summary>
/// the delay between trigger and output (if relevant)
/// </summary>
public double DigitalOutputDelay { get; set; }
/// <inheritdoc />
/// <summary>
/// the duration of output after output started (if relevant)
/// </summary>
public double DigitalOutputDuration { get; set; }
/// <inheritdoc />
/// <summary>
/// controls whether the channel should be marked as diagnostics mode or not
/// note that diagnostics mode is only used when the configuration supports diagnostics mode
/// even if the sensor has diagnosticsmode set to true
/// </summary>
public bool DiagnosticsMode { get; set; }
private void InitValues()
{
ChannelCode = NONE;
InitialEUInMV = double.NaN;
InitialEUInEU = double.NaN;
IRTraccExponent = double.NaN;
PolynomialConstant = double.NaN;
PolynomialCoefficentB = double.NaN;
PolynomialCoefficientA = double.NaN;
PolynomialCoefficientAlpha = double.NaN;
PolynomialCoefficientC = double.NaN;
ISOCode = "";
ISODescription = "";
SquibFireMode = SquibFireMode.CAP;
SquibFireResistanceHighOhm = 8D;
SquibFireResistanceLowOhm = 1D;
SquibFireCurrent = 3D;
SquibFireDurationMs = 0.20D;
DigitalInputMode = DigitalInputModes.CCNO;
DigitalOutputMode = DigitalOutputModes.NONE;
DiagnosticsMode = false;
}
public TTSChannelRecord()
{
InitValues();
}
public TTSChannelRecord(SensorData sd)
{
InitValues();
if (sd == null
|| sd.Filter == null
|| sd.Calibration == null
|| sd.Calibration.Records == null
|| sd.Calibration.Records.Records == null
|| sd.Calibration.Records.Records[0] == null
|| sd.Calibration.Records.Records[0].Poly == null) return;
BridgeResistance = sd.BridgeResistance;
CableMultiplier = double.TryParse(sd.UserValue2, NumberStyles.Any, CultureInfo.InvariantCulture, out var d) ? d : 1D;
ChannelCode = sd.UserSerialNumber;
ChannelFilterHz = (int)sd.Filter.Frequency;
ChannelRange = sd.RangeHigh;
ChannelRangeString = sd.RangeHigh.ToString(CultureInfo.InvariantCulture);
//Channel Type
switch (sd.Bridge)
{
case SensorConstants.BridgeType.DigitalInput:
IsDigitalInput = true;
break;
case SensorConstants.BridgeType.QuarterBridge:
break;
case SensorConstants.BridgeType.HalfBridge_SigPlus:
ChannelType = ToyotaBridgeType.HalfBridge;
break;
case SensorConstants.BridgeType.FullBridge:
ChannelType = ToyotaBridgeType.FullBridge;
break;
case SensorConstants.BridgeType.SQUIB:
IsSquib = true;
break;
case SensorConstants.BridgeType.TOMDigital:
IsDigitalOutput = true;
break;
}
if (sd.Calibration.NonLinear)
{
switch (sd.Calibration.IRTraccCalculationType)
{
case NonLinearStyles.IRTraccDiagnosticsZero:
case NonLinearStyles.IRTraccAverageOverTime:
case NonLinearStyles.IRTraccZeroMMmV:
ChannelType = ToyotaBridgeType.IRTRACC;
break;
case NonLinearStyles.Polynomial:
ChannelType = ToyotaBridgeType.LinearChestPot;
break;
}
}
Description = sd.Comment;
InitialEUInEU = sd.Calibration.InitialOffsets.Offsets[0].EU;
InitialEUInMV = sd.Calibration.InitialOffsets.Offsets[0].MV;
InitialOffsetVoltage = sd.OffsetToleranceHigh - Math.Abs(sd.OffsetToleranceLow);
InitialOffsetVoltageTolerance = (sd.OffsetToleranceHigh + Math.Abs(sd.OffsetToleranceLow)) / 2.0;
if (sd.Calibration.NonLinear && !sd.Calibration.Records.Records[0].Poly.LinearizationExponent
.Equals(0.0))
{
IRTraccExponent = sd.Calibration.Records.Records[0].Poly.LinearizationExponent;
}
ISOCode = sd.ISOCode;
ISODescription = string.Empty;
ISOPolarity = sd.Polarity;
JCodeOrDescription = sd.Comment;
LimitDuration = sd.LimitDuration;
if (sd.Calibration.Records.Records[0].Poly.PolynomialExponents.Length == 5)
{
PolynomialCoefficientA = sd.Calibration.Records.Records[0].Poly.PolynomialCoefficients[3];
PolynomialCoefficientAlpha = sd.Calibration.Records.Records[0].Poly.PolynomialCoefficients[4];
PolynomialCoefficentB = sd.Calibration.Records.Records[0].Poly.PolynomialCoefficients[2];
PolynomialCoefficientC = sd.Calibration.Records.Records[0].Poly.PolynomialCoefficients[1];
PolynomialConstant = sd.Calibration.Records.Records[0].Poly.PolynomialCoefficients[0];
}
ProportionalToExcitation = sd.Calibration.IsProportional;
RemoveOffset = sd.Calibration.RemoveOffset;
SensorCapacity = sd.Capacity;
SensorEID = sd.EID;
SensorEU = sd.Calibration.Records.Records[0].EngineeringUnits;
SensorExcitationVolts = Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(sd.Calibration.Records.Records[0].Excitation);
SensorPolarity = !sd.Invert; //positive polarity means do not invert, invert means negative polarity
if (sd.Calibration.NonLinear)
{
switch (sd.Calibration.IRTraccCalculationType)
{
case NonLinearStyles.IRTraccAverageOverTime:
SensorSensitivity = sd.Calibration.Records.Records[0].Poly.PolynomialSensitivity;
break;
case NonLinearStyles.IRTraccDiagnosticsZero:
break;
case NonLinearStyles.IRTraccZeroMMmV:
break;
}
}
else
{
SensorSensitivity = sd.Calibration.Records.Records[0].Sensitivity;
}
SensorSerialNumber = sd.SerialNumber;
SquibFireCurrent = sd.SquibOutputCurrent;
SquibFireDelayMs = sd.SquibFireDelayMS;
SquibFireDurationMs = sd.SquibFireDurationMS;
SquibFireMode = sd.SquibFireMode;
SquibFireResistanceHighOhm = sd.SquibToleranceHigh;
SquibFireResistanceLowOhm = sd.SquibToleranceLow;
DigitalOutputMode = sd.DigitalOutputMode;
DigitalInputMode = sd.InputMode;
DigitalOutputDelay = sd.DigitalOutputDelayMS;
DigitalOutputDuration = sd.DigitalOutputDurationMS;
LimitDuration = sd.LimitDuration;
//Latest info from Takashi
switch (sd.Calibration.ZeroMethods.Methods[0].Method)
{
case ZeroMethodType.None: ZeroMethod = ToyotaZeroMethods.None; break;
case ZeroMethodType.AverageOverTime: ZeroMethod = ToyotaZeroMethods.AverageOverTime; break;
case ZeroMethodType.UsePreEventDiagnosticsZero: ZeroMethod = ToyotaZeroMethods.UsePreEventDiagnosticsZero; break;
}
IsChannelCodeValid = !string.IsNullOrWhiteSpace(ChannelCode) && ChannelCode != NONE;
}
public ITTSChannelRecord Copy()
{
return (TTSChannelRecord)MemberwiseClone();
}
public bool OriginallyRequestedChannel { get; set; }
public bool IsModified { get; set; }
public byte[] GetBytes()
{
var bytes = new List<byte>();
bytes.AddRange(BitConverter.GetBytes(ChannelNumber));
bytes.AddRange(System.Text.Encoding.UTF8.GetBytes(ChannelCode ?? ""));
bytes.AddRange(System.Text.Encoding.UTF8.GetBytes(JCodeOrDescription ?? ""));
bytes.AddRange(BitConverter.GetBytes(ChannelRange));
bytes.AddRange(BitConverter.GetBytes(ChannelFilterHz));
bytes.AddRange(System.Text.Encoding.UTF8.GetBytes(SensorEID ?? ""));
bytes.AddRange(System.Text.Encoding.UTF8.GetBytes(SensorSerialNumber ?? ""));
bytes.AddRange(BitConverter.GetBytes(SensorSensitivity));
bytes.AddRange(BitConverter.GetBytes(SensorExcitationVolts));
bytes.AddRange(BitConverter.GetBytes(SensorCapacity));
bytes.AddRange(System.Text.Encoding.UTF8.GetBytes(SensorEU ?? ""));
bytes.AddRange(BitConverter.GetBytes(SensorPolarity));
bytes.AddRange(BitConverter.GetBytes((int)ChannelType));
bytes.AddRange(System.Text.Encoding.UTF8.GetBytes(Description ?? ""));
bytes.AddRange(BitConverter.GetBytes(ProportionalToExcitation));
bytes.AddRange(BitConverter.GetBytes(BridgeResistance));
bytes.AddRange(BitConverter.GetBytes(InitialOffsetVoltage));
bytes.AddRange(BitConverter.GetBytes(InitialOffsetVoltageTolerance));
bytes.AddRange(BitConverter.GetBytes(RemoveOffset));
bytes.AddRange(BitConverter.GetBytes((int)ZeroMethod));
bytes.AddRange(BitConverter.GetBytes(Disabled));
if (IsSquib)
{
bytes.AddRange(BitConverter.GetBytes((int)SquibFireMode));
bytes.AddRange(BitConverter.GetBytes(SquibFireDelayMs));
bytes.AddRange(BitConverter.GetBytes(LimitDuration));
if (LimitDuration)
{
bytes.AddRange(BitConverter.GetBytes(SquibFireDurationMs));
}
bytes.AddRange(BitConverter.GetBytes(SquibFireCurrent));
bytes.AddRange(BitConverter.GetBytes(SquibFireResistanceLowOhm));
bytes.AddRange(BitConverter.GetBytes(SquibFireResistanceHighOhm));
}
if (IsDigitalInput)
{
bytes.AddRange(BitConverter.GetBytes((int)DigitalInputMode));
}
if (!IsDigitalOutput) return bytes.ToArray();
bytes.AddRange(BitConverter.GetBytes((int)DigitalOutputMode));
bytes.AddRange(BitConverter.GetBytes(DigitalOutputDelay));
bytes.AddRange(BitConverter.GetBytes(DigitalOutputDuration));
return bytes.ToArray();
}
}
}