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,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
}
}