2438 lines
120 KiB
Plaintext
2438 lines
120 KiB
Plaintext
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Linq;
|
||
|
|
using System.Threading;
|
||
|
|
using System.IO;
|
||
|
|
using System.Diagnostics;
|
||
|
|
using System.Globalization;
|
||
|
|
using DTS.DASLib.Command;
|
||
|
|
using DTS.Common.Enums;
|
||
|
|
using DTS.Common.ICommunication;
|
||
|
|
using DTS.DASLib.Command.TDAS;
|
||
|
|
using DTS.Common.Utilities;
|
||
|
|
using DTS.Common.Utilities.Logging;
|
||
|
|
using DTS.Common.Interface.Connection;
|
||
|
|
using DTS.Common.Interface.DASFactory.Diagnostics;
|
||
|
|
using DTS.Common.Enums.DASFactory;
|
||
|
|
using DTS.Common.Interface.DASFactory;
|
||
|
|
|
||
|
|
namespace DTS.DASLib.Service
|
||
|
|
{
|
||
|
|
public partial class TDAS<T> : Communication<T>,
|
||
|
|
IDASCommunication,
|
||
|
|
IConfigurationActions,
|
||
|
|
IDiagnosticsActions,
|
||
|
|
ITriggerCheckActions,
|
||
|
|
IRealTimeActions,
|
||
|
|
IArmActions,
|
||
|
|
IDownloadActions where T : IConnection, new()
|
||
|
|
{
|
||
|
|
public IModuleDiagnosticsResult[] ModuleDiagnosticsResults { get; set; }
|
||
|
|
private class DiagnosticsAsyncPacket
|
||
|
|
{
|
||
|
|
public TDASServiceAsyncInfo info { get; set; }
|
||
|
|
public uint DiagnosticsSampleRateHz { get; set; }
|
||
|
|
public float DiagnosticsAAFilterFrequencyHz { get; set; }
|
||
|
|
public PrePostResults PreOrPost { get; set; }
|
||
|
|
}
|
||
|
|
private class SquibFireCheckArmPacket
|
||
|
|
{
|
||
|
|
public TDASServiceAsyncInfo info { get; set; }
|
||
|
|
public UInt32 DiagnosticsSampleRateHz { get; set; }
|
||
|
|
public float DiagnosticsAAFilterFrequencyHz { get; set; }
|
||
|
|
public double duration;
|
||
|
|
public double delay;
|
||
|
|
}
|
||
|
|
private class DiagnosticsTriggerCheckDownloadPacket
|
||
|
|
{
|
||
|
|
public TDASServiceAsyncInfo info { get; set; }
|
||
|
|
public uint DiagnosticsSampleRateHz { get; set; }
|
||
|
|
public float DiagnosticsAAFilterFrequencyHz { get; set; }
|
||
|
|
public double duration;
|
||
|
|
public double delay;
|
||
|
|
}
|
||
|
|
private class StatusIndicatorPacket
|
||
|
|
{
|
||
|
|
public TDASServiceAsyncInfo info { get; set; }
|
||
|
|
public DiagnosticsStatusIndicatorState state { get; set; }
|
||
|
|
}
|
||
|
|
#region PrepareForDiagnostics
|
||
|
|
|
||
|
|
void IDiagnosticsActions.ClearTriggerOut(ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
var info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
info.Success();
|
||
|
|
}
|
||
|
|
|
||
|
|
void IDiagnosticsActions.ClearLatches(ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
var info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
info.Success();
|
||
|
|
}
|
||
|
|
/// <summary>
|
||
|
|
/// clears any das trigger lines
|
||
|
|
/// </summary>
|
||
|
|
void IDiagnosticsActions.ClearDASTriggerLine(ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
var info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
info.Success();
|
||
|
|
}
|
||
|
|
void IDiagnosticsActions.PerformArmChecks(ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
var info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
LaunchAsyncWorker("TDAS.PerformArmChecks", AsyncPerformArmChecks, info);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void AsyncPerformArmChecks(object o)
|
||
|
|
{
|
||
|
|
var info = o as TDASServiceAsyncInfo;
|
||
|
|
|
||
|
|
var dasResults = new ArmCheckResults();
|
||
|
|
Dictionary<int, double> squibResistances = new Dictionary<int, double>();
|
||
|
|
Dictionary<int, string[]> sensorIds = new Dictionary<int, string[]>();
|
||
|
|
if (null != ArmCheckActions)
|
||
|
|
{
|
||
|
|
if (ArmCheckActions.PerformBatteryVoltageCheck)
|
||
|
|
{
|
||
|
|
if (IsG5())
|
||
|
|
{
|
||
|
|
dasResults.BatteryVoltage = new double?[] { double.NaN };
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (ArmCheckActions.PerformInputVoltageCheck)
|
||
|
|
{
|
||
|
|
if (IsG5() && G5Mode == G5Modes.VDS)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
dasResults.InputVoltage = GetInputVoltageTBCommand(true);
|
||
|
|
}
|
||
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (ArmCheckActions.PerformSquibResistanceCheck)
|
||
|
|
{
|
||
|
|
if (ContainsTOM())
|
||
|
|
{
|
||
|
|
var iChannel = 0;
|
||
|
|
for (var i = 0; i < ConfigData.Modules.Length; i++)
|
||
|
|
{
|
||
|
|
if (DASInfo.Modules[i].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK) { continue; }
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (IsTom((DASModule)ConfigData.Modules[i]))
|
||
|
|
{
|
||
|
|
|
||
|
|
var tsa = new TestSquibArray(this);
|
||
|
|
tsa.ModuleIndex = ConfigData.Modules[i].ModuleArrayIndex;
|
||
|
|
tsa.SyncExecute();
|
||
|
|
for (var ch = 0; ch < tsa.ResistanceOhms.Length; ch++)
|
||
|
|
{
|
||
|
|
squibResistances[iChannel + 2 * ch] = tsa.ResistanceOhms[ch];
|
||
|
|
squibResistances[iChannel + 2 * ch + 1] = tsa.ResistanceOhms[ch];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
||
|
|
iChannel += ConfigData.Modules[i].Channels.Length;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (ArmCheckActions.PerformEventLineCheck)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var ta = new TestAll(this);
|
||
|
|
|
||
|
|
ta.SyncExecute();
|
||
|
|
dasResults.StartLineShorted = ta.StartedRecordingFlag == DFConstantsAndEnums.VoltageStatusColor.Red || ta.StartedRecordingFlag == DFConstantsAndEnums.VoltageStatusColor.Yellow;
|
||
|
|
}
|
||
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var bTriggered = false;
|
||
|
|
for (var i = 0; i < ConfigData.Modules.Length; i++)
|
||
|
|
{
|
||
|
|
if (DASInfo.Modules[i].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK) { continue; }
|
||
|
|
if (i > 0 && IsG5()) { continue; }
|
||
|
|
var qta = new QueryTriggerLine(this);
|
||
|
|
qta.ModuleIndex = i;
|
||
|
|
qta.SyncExecute();
|
||
|
|
if (qta.IsTriggered) { bTriggered = true; }
|
||
|
|
}
|
||
|
|
dasResults.EventLineShorted = bTriggered;
|
||
|
|
}
|
||
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
||
|
|
}
|
||
|
|
if (ArmCheckActions.PerformSensorIdCheck)
|
||
|
|
{
|
||
|
|
if (IsG5())
|
||
|
|
{
|
||
|
|
SensorIDCheckG5(sensorIds);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
SensorIDCheckByModule(sensorIds);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
dasResults.SensorIds = sensorIds;
|
||
|
|
dasResults.SquibResistances = squibResistances;
|
||
|
|
ArmCheckResults = dasResults;
|
||
|
|
info.Success();
|
||
|
|
}
|
||
|
|
/// <summary>
|
||
|
|
/// retrieve all sensors and sets the sensor lookup accordingly
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="sensorIds">lookup, keyed by channel index, values are array of EIDs</param>
|
||
|
|
private void SensorIDCheckG5(Dictionary<int, string[]> sensorIds)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var idx = new RackIDX(this);
|
||
|
|
idx.SyncExecute();
|
||
|
|
for (var i = 0; i < idx.IDs.Count; i++)
|
||
|
|
{
|
||
|
|
sensorIds[i] = idx.IDs[i].ToArray();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
APILogger.Log(ex);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/// <summary>
|
||
|
|
/// populate EID lookup by going module to module
|
||
|
|
/// note that channels being passed in was being set to 0 before getting called so
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="sensorIds">lookup keyed by channel index with values of an array of EIDs for that channel</param>
|
||
|
|
private void SensorIDCheckByModule(Dictionary<int, string[]> sensorIds)
|
||
|
|
{
|
||
|
|
var channels = 0;
|
||
|
|
int moduleIndex = -1;
|
||
|
|
foreach (var module in ConfigData.Modules)
|
||
|
|
{
|
||
|
|
moduleIndex++;
|
||
|
|
if (DASInfo.Modules[moduleIndex].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK) { continue; }
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var read = new ReadSensorIDs(this);
|
||
|
|
read.ModuleIndex = module.ModuleArrayIndex;
|
||
|
|
read.SyncExecute();
|
||
|
|
for (var i = 0; i < read.IDs.Count; i++)
|
||
|
|
{
|
||
|
|
if (IsTom((DASModule)module))
|
||
|
|
{
|
||
|
|
sensorIds[channels + i * 2] = new[] { read.IDs[i] };
|
||
|
|
sensorIds[1 + channels + i * 2] = new[] { read.IDs[i] };
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (!string.IsNullOrWhiteSpace(read.IDs[i].Replace("0", "")))
|
||
|
|
{
|
||
|
|
sensorIds[channels + i] = new[] { read.IDs[i] };
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
APILogger.Log(ex);
|
||
|
|
}
|
||
|
|
channels += module.Channels.Length;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
void IDiagnosticsActions.SaveTiltSensorDataPre(ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
var info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
LaunchAsyncWorker("TDAS.SaveTiltSensorDataPre", AsyncSaveTiltSensorDataPre, info);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void AsyncSaveTiltSensorDataPre(object o)
|
||
|
|
{
|
||
|
|
var info = o as TDASServiceAsyncInfo;
|
||
|
|
info?.Success();
|
||
|
|
}
|
||
|
|
|
||
|
|
void IDiagnosticsActions.SaveTemperaturesPre(ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
var info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
LaunchAsyncWorker("TDAS.SaveTemperaturesPre", AsyncSaveTemperaturesPre, info);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void AsyncSaveTemperaturesPre(object o)
|
||
|
|
{
|
||
|
|
var info = o as TDASServiceAsyncInfo;
|
||
|
|
info?.Success();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc />
|
||
|
|
/// <summary>
|
||
|
|
/// Perform diagnostics based on the property ChannelDiagnostics and stuff the
|
||
|
|
/// result in ChannelDiagnosticsResults
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="DiagnosticsSampleRateHz">the diagnostics sample rate</param>
|
||
|
|
/// <param name="DiagnosticsAAFilterFrequencyHz">the AA filter frequency</param>
|
||
|
|
/// <param name="callback">The function to call with information</param>
|
||
|
|
/// <param name="userData">Whatever you want to pass along</param>
|
||
|
|
void IDiagnosticsActions.PrepareForDiagnostics(uint DiagnosticsSampleRateHz,
|
||
|
|
float DiagnosticsAAFilterFrequencyHz,
|
||
|
|
PrePostResults WhichResult,
|
||
|
|
ServiceCallback callback,
|
||
|
|
object userData)
|
||
|
|
{
|
||
|
|
|
||
|
|
var packet = new DiagnosticsAsyncPacket();
|
||
|
|
packet.info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
packet.DiagnosticsSampleRateHz = DiagnosticsSampleRateHz;
|
||
|
|
packet.DiagnosticsAAFilterFrequencyHz = DiagnosticsAAFilterFrequencyHz;
|
||
|
|
packet.PreOrPost = WhichResult;
|
||
|
|
|
||
|
|
LaunchAsyncWorker("TDAS.PrepareForDiagnostics", AsyncPrepareForDiagnostics, packet);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// the working guts of PrepareForDiagnostics
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="asyncInfo">our async data</param>
|
||
|
|
private void AsyncPrepareForDiagnostics(object asyncInfo)
|
||
|
|
{
|
||
|
|
var packet = asyncInfo as DiagnosticsAsyncPacket;
|
||
|
|
|
||
|
|
SyncPrepareForDiagnostics(packet);
|
||
|
|
|
||
|
|
// we're done
|
||
|
|
packet?.info.Success();
|
||
|
|
}
|
||
|
|
|
||
|
|
private void SyncPrepareForDiagnostics(DiagnosticsAsyncPacket packet)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (packet.PreOrPost != PrePostResults.PreEventDiagnosticsResult) return;
|
||
|
|
var bHasDigitalChannels = false;
|
||
|
|
foreach (var m in ConfigData.Modules)
|
||
|
|
{
|
||
|
|
foreach (var c in m.Channels)
|
||
|
|
{
|
||
|
|
if (c is AnalogInputDASChannel)
|
||
|
|
{
|
||
|
|
if ((c as AnalogInputDASChannel).DigitalInputChannel && c.ConfigurationMode == DFConstantsAndEnums.ConfigMode.Normal) { bHasDigitalChannels = true; break; }
|
||
|
|
}
|
||
|
|
if (bHasDigitalChannels) { break; }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
var samplerate = Convert.ToInt32(packet.DiagnosticsSampleRateHz);
|
||
|
|
if (samplerate > 10000) { samplerate = 10000; }
|
||
|
|
|
||
|
|
var aarate = Convert.ToInt32(packet.DiagnosticsAAFilterFrequencyHz);
|
||
|
|
if (aarate > MaxAAFilterRateHz) { aarate = Convert.ToInt32(MaxAAFilterRateHz); }
|
||
|
|
if (0 == aarate)
|
||
|
|
{
|
||
|
|
if (IsG5()) { aarate = Convert.ToInt32(MaxAAFilterRateHz); }
|
||
|
|
}
|
||
|
|
|
||
|
|
if (DFConstantsAndEnums.DontDoSDL == false)
|
||
|
|
{
|
||
|
|
foreach (var module in ConfigData.Modules)
|
||
|
|
{
|
||
|
|
var dummyChannels = from c in module.Channels
|
||
|
|
where c.ConfigurationMode == DFConstantsAndEnums.ConfigMode.DummyArm
|
||
|
|
select c;
|
||
|
|
|
||
|
|
var goodChannels = from c in module.Channels
|
||
|
|
where c.ConfigurationMode == DFConstantsAndEnums.ConfigMode.Normal
|
||
|
|
select c;
|
||
|
|
if (DASInfo.Modules[module.ModuleArrayIndex].TypeOfModule ==
|
||
|
|
DFConstantsAndEnums.ModuleType.EMPTYBANK)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (IsTom(module))
|
||
|
|
{
|
||
|
|
var sdl = new SetupTOMDASLoad(this);
|
||
|
|
sdl.ArmMode = SetupTOMDASLoad.ARMMode.DIAGW;
|
||
|
|
sdl.ModuleIndex = module.ModuleArrayIndex;
|
||
|
|
sdl.TestId = "D"; //trimmed for performance
|
||
|
|
sdl.TestConfig =
|
||
|
|
$"{"D"}"; //trimmed for performance{SETUPDASREAD_SENTINEL}{module.GetCRC32()}";
|
||
|
|
sdl.TriggerType = SetupTOMDASLoad.TriggerTypes.BUS;
|
||
|
|
sdl.PostADWaitTime = -1;
|
||
|
|
sdl.SampleRate = samplerate;
|
||
|
|
sdl.PostTriggerSeconds = 1;
|
||
|
|
sdl.PreTriggerSeconds = 1;
|
||
|
|
if (null != dummyChannels && dummyChannels.Any() && !bHasDigitalChannels)
|
||
|
|
{
|
||
|
|
sdl.IsDummyArm = true;
|
||
|
|
sdl.CollectData = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
sdl.SyncExecute();
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
packet.info.Error(ex.Message);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
var sdl = new SetupDASLoad(this);
|
||
|
|
var sdlDIM = new SetupDASLoadDIM(this);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (null != dummyChannels && dummyChannels.Any() || null == goodChannels ||
|
||
|
|
!goodChannels.Any())
|
||
|
|
{
|
||
|
|
sdl.SampleRate = samplerate;
|
||
|
|
sdlDIM.SampleRate = samplerate;
|
||
|
|
sdl.IsDummyArm = true;
|
||
|
|
sdlDIM.IsDummyArm = true;
|
||
|
|
sdl.CollectData = false;
|
||
|
|
sdlDIM.CollectData = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
sdl.ArmMode = SetupDASLoad.ARMMode.WAIT;
|
||
|
|
sdlDIM.ArmMode = SetupDASLoadDIM.ArmModes.WAIT;
|
||
|
|
|
||
|
|
sdlDIM.ModuleIndex = module.ModuleArrayIndex;
|
||
|
|
sdl.ModuleIndex = module.ModuleArrayIndex;
|
||
|
|
|
||
|
|
sdlDIM.SampleRate = samplerate;
|
||
|
|
sdl.SampleRate = samplerate;
|
||
|
|
|
||
|
|
sdlDIM.PreTriggerSeconds = 1;
|
||
|
|
sdl.PreTriggerSeconds = 1;
|
||
|
|
|
||
|
|
sdlDIM.PostTriggerSeconds = 1;
|
||
|
|
sdl.PostTriggerSeconds = 1;
|
||
|
|
|
||
|
|
sdl.TestConfig =
|
||
|
|
$"{"D"}"; //trimmed for performance{SETUPDASREAD_SENTINEL}{module.GetCRC32()}";
|
||
|
|
sdlDIM.TestConfig = sdl.TestConfig;
|
||
|
|
|
||
|
|
sdl.TestId = "D"; //trimmed for performance
|
||
|
|
sdlDIM.TestId = sdl.TestId;
|
||
|
|
|
||
|
|
sdl.PostADWaitTime = -1;
|
||
|
|
sdlDIM.PostADWaitTime = -1;
|
||
|
|
|
||
|
|
sdl.TriggerType = SetupDASLoad.TriggerTypes.HW;
|
||
|
|
sdlDIM.TriggerType = SetupDASLoadDIM.TriggerTypes.HW;
|
||
|
|
|
||
|
|
if (0 == aarate && IsG5())
|
||
|
|
{
|
||
|
|
aarate = Convert.ToInt32(MaxAAFilterRateHz);
|
||
|
|
}
|
||
|
|
|
||
|
|
sdl.SetHardwareAAFilter(aarate, MaxAAFilterRateHz);
|
||
|
|
|
||
|
|
}
|
||
|
|
catch (NotSupportedException)
|
||
|
|
{
|
||
|
|
sdl.SetHardwareAAFilter(250, MaxAAFilterRateHz);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
packet.info.Error(ex.Message);
|
||
|
|
}
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (DASInfo.Modules[module.ModuleArrayIndex].TypeOfModule ==
|
||
|
|
DFConstantsAndEnums.ModuleType.ProDIM && !IsG5())
|
||
|
|
{
|
||
|
|
sdlDIM.SyncExecute();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (module.ModuleArrayIndex > 0 && IsG5())
|
||
|
|
{
|
||
|
|
//we only need to do the first (and 4th) module in a g5
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
sdl.SyncExecute();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
packet.info.Error(ex.Message);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TurnOnExcitation();
|
||
|
|
}
|
||
|
|
catch (CanceledException)
|
||
|
|
{
|
||
|
|
// like most tv shows, we have been canceled
|
||
|
|
packet.info.Cancel();
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
packet.info.Error(ex.Message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region PrepareForBridgeResistanceMeasurement
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Perform diagnostics based on the property ChannelDiagnostics and stuff the
|
||
|
|
/// result in ChannelDiagnosticsResults
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="diagnosticsSampleRateHz">the sample rate for diagnostics</param>
|
||
|
|
/// <param name="diagnosticsAAFilterFrequencyHz">the AA filter frequency</param>
|
||
|
|
/// <param name="callback">The function to call with information</param>
|
||
|
|
/// <param name="userData">Whatever you want to pass along</param>
|
||
|
|
void IDiagnosticsActions.PrepareForBridgeResistanceMeasurement(uint diagnosticsSampleRateHz,
|
||
|
|
float diagnosticsAAFilterFrequencyHz,
|
||
|
|
ServiceCallback callback,
|
||
|
|
object userData)
|
||
|
|
{
|
||
|
|
var packet = new DiagnosticsAsyncPacket();
|
||
|
|
packet.info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
packet.DiagnosticsSampleRateHz = diagnosticsSampleRateHz;
|
||
|
|
packet.DiagnosticsAAFilterFrequencyHz = diagnosticsAAFilterFrequencyHz;
|
||
|
|
|
||
|
|
LaunchAsyncWorker("TDAS.PrepareForBridgeResistanceMeasurement", AsyncPrepareForBridgeResistanceMeasurement, packet);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void AsyncPrepareForBridgeResistanceMeasurement(object asyncInfo)
|
||
|
|
{
|
||
|
|
var packet = asyncInfo as DiagnosticsAsyncPacket;
|
||
|
|
Thread.Sleep(100);
|
||
|
|
|
||
|
|
// we're done
|
||
|
|
packet?.info.Success();
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region GetBridgeMeasurement
|
||
|
|
void IDiagnosticsActions.GetBridgeMeasurement(ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
var packet = new DiagnosticsAsyncPacket();
|
||
|
|
packet.info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
|
||
|
|
LaunchAsyncWorker("TDAS.GetBridgeMeasurement", AsyncGetBridgeMeasurement, packet);
|
||
|
|
}
|
||
|
|
|
||
|
|
void IDiagnosticsActions.MeasureTransferSpeed(ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
var info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
info.Success();
|
||
|
|
}
|
||
|
|
|
||
|
|
private void AsyncGetBridgeMeasurement(object asyncInfo)
|
||
|
|
{
|
||
|
|
var packet = asyncInfo as DiagnosticsAsyncPacket;
|
||
|
|
|
||
|
|
//noticed the previous version of this code would only query one channel
|
||
|
|
//and then would set all the rest to null bridge resistance
|
||
|
|
//ideally we query them all
|
||
|
|
//18246 [Internal] Measure Bridge Resistance issue in DP3.1.464
|
||
|
|
try
|
||
|
|
{
|
||
|
|
DiagnosticsResult[] results;
|
||
|
|
if (ChannelDiagnostics != null && ChannelDiagnostics.Length > 0)
|
||
|
|
{
|
||
|
|
results = new DiagnosticsResult[ChannelDiagnostics.Length];
|
||
|
|
for (var idx = 0; idx < ChannelDiagnostics.Length; idx++)
|
||
|
|
{
|
||
|
|
results[idx] = new DiagnosticsResult();
|
||
|
|
results[idx].DASChannelNumber = ChannelDiagnostics[idx].DASChannelNumber;
|
||
|
|
results[idx].EventNumber = DFConstantsAndEnums.EVENT_NUMBER_MEASURE_BRIDGE; // it's not really an event
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// this case will only generate the base input values
|
||
|
|
results = null;
|
||
|
|
}
|
||
|
|
for (var idx = 0; idx < ChannelDiagnostics.Length; idx++)
|
||
|
|
{
|
||
|
|
var moduleIndex = DASInfo.MapDASChannelNumber2ModuleArrayIndex(ChannelDiagnostics[idx].DASChannelNumber);
|
||
|
|
var channelNumber = DASInfo.MapDASChannelNumber2ModuleChannelNumber(ChannelDiagnostics[idx].DASChannelNumber) + 1;
|
||
|
|
var excitation = 0.0;
|
||
|
|
var current = 0.0;
|
||
|
|
var inputRange = 0;
|
||
|
|
if (DASInfo.Modules[0].TypeOfModule == DFConstantsAndEnums.ModuleType.G5Analog)
|
||
|
|
{
|
||
|
|
excitation = G5Mode == G5Modes.VDS ? 2 : 5;
|
||
|
|
current = 0.5;
|
||
|
|
inputRange = 2500;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
excitation = 5;
|
||
|
|
current = 0.8;
|
||
|
|
inputRange = 5000;
|
||
|
|
}
|
||
|
|
|
||
|
|
var bridgeValue = 5000D;
|
||
|
|
var gain = CalculateGainForExpectedBridge(bridgeValue, current, true);
|
||
|
|
|
||
|
|
var sc = new SetupClear(this);
|
||
|
|
sc.ModuleIndex = moduleIndex;
|
||
|
|
sc.SyncExecute();
|
||
|
|
|
||
|
|
const int MAX_ATTEMPTS = 2;
|
||
|
|
for (var attempt = 0; attempt < MAX_ATTEMPTS; attempt++)
|
||
|
|
{
|
||
|
|
if (0.8 * inputRange / gain < bridgeValue * current)
|
||
|
|
{
|
||
|
|
current = (0.8 * inputRange / gain) / bridgeValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
//SCL
|
||
|
|
var scl = new SetupChannelLoad(this, IsG5());
|
||
|
|
scl.ModuleIndex = moduleIndex;
|
||
|
|
scl.Channel = channelNumber;
|
||
|
|
scl.ExcitationSetting = excitation;
|
||
|
|
scl.Gain = gain;
|
||
|
|
scl.ShuntPosition = (int)(2 * bridgeValue);
|
||
|
|
scl.SyncExecute();
|
||
|
|
|
||
|
|
//TEST PREPARE ON
|
||
|
|
var tp = new TestPrepare(this);
|
||
|
|
tp.On = true;
|
||
|
|
tp.ModuleIndex = moduleIndex;
|
||
|
|
tp.SyncExecute();
|
||
|
|
|
||
|
|
//SCR
|
||
|
|
var scr = new SetupChannelRead(this);
|
||
|
|
scr.ModuleIndex = moduleIndex;
|
||
|
|
scr.Channel = channelNumber;
|
||
|
|
scr.SyncExecute();
|
||
|
|
|
||
|
|
gain = scr.Gain;
|
||
|
|
var scaleFactor = (2 * inputRange / gain) / 65536;
|
||
|
|
|
||
|
|
//ZA
|
||
|
|
var za = new ZeroAverage(this);
|
||
|
|
za.ModuleIndex = moduleIndex;
|
||
|
|
za.Channel = channelNumber - 1;
|
||
|
|
za.SyncExecute();
|
||
|
|
|
||
|
|
//SA
|
||
|
|
var sa = new SampleAverageWithFallback(this, moduleIndex);
|
||
|
|
sa.SyncExecute();
|
||
|
|
|
||
|
|
var zero = sa.ChannelValues[channelNumber - 1];
|
||
|
|
|
||
|
|
//Cal DAC
|
||
|
|
var c = new CalDAC(this);
|
||
|
|
c.ModuleIndex = moduleIndex;
|
||
|
|
c.Channel = channelNumber - 1;
|
||
|
|
c.EOrX = 'E';
|
||
|
|
c.Current = current;
|
||
|
|
c.Gain = gain;
|
||
|
|
c.SyncExecute();
|
||
|
|
|
||
|
|
//SA
|
||
|
|
sa = new SampleAverageWithFallback(this, moduleIndex);
|
||
|
|
sa.SyncExecute();
|
||
|
|
var shuntedValue = sa.ChannelValues[channelNumber - 1];
|
||
|
|
|
||
|
|
//Cal DAC
|
||
|
|
c = new CalDAC(this);
|
||
|
|
c.ModuleIndex = moduleIndex;
|
||
|
|
c.Channel = channelNumber - 1;
|
||
|
|
c.EOrX = 'X';
|
||
|
|
c.Current = current;
|
||
|
|
c.SyncExecute();
|
||
|
|
|
||
|
|
bridgeValue = (shuntedValue - zero) * scaleFactor / current;
|
||
|
|
current = 1.0;
|
||
|
|
gain = CalculateGainForExpectedBridge(bridgeValue, current, true); //G5
|
||
|
|
}
|
||
|
|
|
||
|
|
var bridgeResistance = (int)(bridgeValue * 2);
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
results[idx].BridgeResistance = bridgeResistance;
|
||
|
|
}
|
||
|
|
|
||
|
|
SetChannelDiagnosticsResults(results, false);
|
||
|
|
|
||
|
|
Thread.Sleep(100);
|
||
|
|
|
||
|
|
// we're done
|
||
|
|
packet?.info.Success();
|
||
|
|
}
|
||
|
|
catch (CanceledException cex)
|
||
|
|
{
|
||
|
|
var temp = cex.Message;
|
||
|
|
// like most tv shows, we have been canceled
|
||
|
|
packet?.info.Cancel();
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
packet?.info.Error(ex.Message, ex);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
internal double CalculateGainForExpectedBridge(double dBridge, double dCurrent, bool IsG5)
|
||
|
|
{
|
||
|
|
var inputRange = 0;
|
||
|
|
inputRange = IsG5 ? 2500 : 5000;
|
||
|
|
var dGain = Math.Max(3, Math.Floor(0.8 * inputRange / (dBridge * dCurrent)));
|
||
|
|
|
||
|
|
return dGain;
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region CalibrateAndGetResults
|
||
|
|
|
||
|
|
void IDiagnosticsActions.SetStatusIndicator(DiagnosticsStatusIndicatorState state, ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
var packet = new StatusIndicatorPacket();
|
||
|
|
packet.info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
packet.state = state;
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
LaunchAsyncWorker("TDAS.SetStatusIndicator", new WaitCallback(AsyncSetStatusIndicator), packet);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
//This could be due to DAS getting disconnected and AsyncSetStatusIndicator
|
||
|
|
//never getting called so wrap up the use of this thread.
|
||
|
|
packet.info.Error(ex.Message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void AsyncSetStatusIndicator(object asyncInfo)
|
||
|
|
{
|
||
|
|
var packet = asyncInfo as StatusIndicatorPacket;
|
||
|
|
|
||
|
|
var stateString = new DescriptionAttributeCoder<DiagnosticsStatusIndicatorState>().DecodeAttributeValue(packet.state);
|
||
|
|
var sl = new SetLED(this, stateString);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
sl.SyncExecute();
|
||
|
|
packet.info.Success();
|
||
|
|
}
|
||
|
|
catch (Exception e)
|
||
|
|
{
|
||
|
|
//15606 communications error, mark failed
|
||
|
|
APILogger.Log(e);
|
||
|
|
packet.info.Error(e.Message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Perform diagnostics based on the property ChannelDiagnostics and stuff the
|
||
|
|
/// result in ChannelDiagnosticsResults
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="callback">The function to call with information</param>
|
||
|
|
/// <param name="userData">Whatever you want to pass along</param>
|
||
|
|
void IDiagnosticsActions.DiagnosAndGetResults(int EventNumber,
|
||
|
|
PrePostResults WhichResult,
|
||
|
|
ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
|
||
|
|
var packet = new EventDiagnosticsAsyncPacket();
|
||
|
|
packet.info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
|
||
|
|
if (WhichResult == PrePostResults.PreEventDiagnosticsResult)
|
||
|
|
{
|
||
|
|
var info = packet.info;
|
||
|
|
LaunchAsyncWorker("TDAS.DiagnosAndGetResults", AsyncDiagnosAndGetResults, info);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
//Post-test diagnostics for TDAS Rack has already been automatically run, so get the results; for G5, just return the pre-test diagnostics results
|
||
|
|
packet.EventNumber = DFConstantsAndEnums.EVENT_NUMBER_POSTTEST_DIAG;
|
||
|
|
packet.WhichResult = WhichResult;
|
||
|
|
LaunchAsyncWorker("TDAS.GetEventDiagnosticsResults", AsyncGetEventDiagnosticsResults, packet);
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
private bool IsActive(int moduleArrayIndex, int dasChannelNumber, AnalogInputDASChannel analog)
|
||
|
|
{
|
||
|
|
var ss = new SampleAverage(this) { ModuleIndex = moduleArrayIndex };
|
||
|
|
ss.SyncExecute();
|
||
|
|
|
||
|
|
bool bValue;
|
||
|
|
if (IsG5())
|
||
|
|
{
|
||
|
|
bValue = ss.DigitalValues[dasChannelNumber - 32];
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
var index = dasChannelNumber;
|
||
|
|
for (var i = 0; i < moduleArrayIndex; i++)
|
||
|
|
{
|
||
|
|
index -= ConfigData.Modules[i].NumberOfChannels();
|
||
|
|
}
|
||
|
|
bValue = ss.ChannelValues[index] >= 1D;
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (analog.DigitalMode)
|
||
|
|
{
|
||
|
|
case DigitalInputModes.CCNC:
|
||
|
|
return bValue;
|
||
|
|
case DigitalInputModes.CCNO:
|
||
|
|
return !bValue;
|
||
|
|
case DigitalInputModes.THL:
|
||
|
|
return !bValue;
|
||
|
|
case DigitalInputModes.TLH:
|
||
|
|
return bValue;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
/// <summary>
|
||
|
|
/// returns the expected slowest module to run diagnostics on the system, this is a factor of
|
||
|
|
/// number of configured channels and whether they are running offset removal and/or shunt
|
||
|
|
/// 21200 Correct SlowestModule calculation for TDAS
|
||
|
|
/// </summary>
|
||
|
|
/// <returns>module array index of expected slowest module to run diagnostics on rack</returns>
|
||
|
|
private int GetSlowestModule()
|
||
|
|
{
|
||
|
|
var slowestModule = -1;
|
||
|
|
var weightOfSlowest = 0D;
|
||
|
|
foreach (var m in ConfigData.Modules)
|
||
|
|
{
|
||
|
|
if (IsTom(m)) { continue; }
|
||
|
|
var configured = m.NumberOfConfiguredChannels();
|
||
|
|
var weight = (double)configured;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
//http://manuscript.dts.local/f/cases/30004/selecting-DIM-for-slowest-module-can-cause-rack-to-stop-responding
|
||
|
|
if (IsDIM(m))
|
||
|
|
{
|
||
|
|
weight = .9;
|
||
|
|
}
|
||
|
|
//during testing without bridge plugs offset removal seemed by far the longest running
|
||
|
|
//task of diagnostics, however that may be a result of large offsets being present
|
||
|
|
//it is believed (Tim Kippen) that offset removal and shunt will take the most time
|
||
|
|
//so I wanted to add a flat weight each channel requiring offset removal and for
|
||
|
|
//shunt. This may be inaccurate based on how far the offset is from 0, but should still
|
||
|
|
//handle the case of 21200 where there's a module with 8 HFNN vs 8 FFYE
|
||
|
|
//additionally less channels is significantly faster (3s vs 21), so we still want to
|
||
|
|
//consider the total number of channels as a weight as well
|
||
|
|
//I'm weight remove offset and perform shunt slightly higher than my quick test indicates
|
||
|
|
//I should due to observations in customer logs
|
||
|
|
var removeOffsetCount = 0;
|
||
|
|
var performShuntCount = 0;
|
||
|
|
foreach (var channel in m.Channels)
|
||
|
|
{
|
||
|
|
if (!(channel is AnalogInputDASChannel aic)) { continue; }
|
||
|
|
if (aic.RemoveOffset) { removeOffsetCount++; }
|
||
|
|
if (aic.ShuntIsEnabled) { performShuntCount++; }
|
||
|
|
}
|
||
|
|
weight += (removeOffsetCount * DFConstantsAndEnums.TDASRemoveOffsetWeighting)
|
||
|
|
+ (performShuntCount * DFConstantsAndEnums.TDASShuntEmulationWeighting);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
APILogger.Log($"Failed to determine weighting for module {m.ModuleArrayIndex} of {SerialNumber}", ex);
|
||
|
|
}
|
||
|
|
if (weight <= weightOfSlowest) { continue; }
|
||
|
|
slowestModule = m.ModuleArrayIndex;
|
||
|
|
weightOfSlowest = weight;
|
||
|
|
}
|
||
|
|
return slowestModule;
|
||
|
|
}
|
||
|
|
/// <summary>
|
||
|
|
/// the working guts of DiagnosAndGetResults
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="asyncInfo">our async data</param>
|
||
|
|
private void AsyncDiagnosAndGetResults(object asyncInfo)
|
||
|
|
{
|
||
|
|
var info = asyncInfo as TDASServiceAsyncInfo;
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
//this was part of a resharper irmprovement
|
||
|
|
//I'm choosing to assert here as I'm not sure what the
|
||
|
|
//behavior should be if info is null, and this will preserve
|
||
|
|
//the existing behavior, but a little cleaner
|
||
|
|
Debug.Assert(info != null, "info != null");
|
||
|
|
//this call is needed when we are re-running diagnostics ...
|
||
|
|
TurnOnExcitation();
|
||
|
|
|
||
|
|
|
||
|
|
if (null != ChannelDiagnostics && ChannelDiagnostics.Any())
|
||
|
|
{
|
||
|
|
var channelsToRunOn = 0;
|
||
|
|
var channelToRunOn = 0;
|
||
|
|
var bChannelToRunOnIsTOM = false;
|
||
|
|
foreach (var ch in ChannelDiagnostics)
|
||
|
|
{
|
||
|
|
if (ch.AllActionsDisabled()) continue;
|
||
|
|
channelsToRunOn++;
|
||
|
|
channelToRunOn = ch.DASChannelNumber;
|
||
|
|
if (ch.SquibFireCheck)
|
||
|
|
{
|
||
|
|
bChannelToRunOnIsTOM = true;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
bChannelToRunOnIsTOM = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (channelsToRunOn > 0)
|
||
|
|
{
|
||
|
|
|
||
|
|
info.NewData(new ServiceCallbackData.DiagnosticNewData()
|
||
|
|
{
|
||
|
|
Action = ServiceCallbackData.DiagnosticNewData.Actions.QueryModules,
|
||
|
|
DasChannelNumber = 0,
|
||
|
|
Result = ""
|
||
|
|
});
|
||
|
|
BaseInput = new BaseInputValues { InputMilliVolts = 1000D * GetInputVoltageTBCommand(IsG5()) };
|
||
|
|
}
|
||
|
|
var configuredChannelPerModuleArrayIndex = new Dictionary<int, int>();
|
||
|
|
|
||
|
|
// first get the scale factors
|
||
|
|
if (ChannelDiagnosticsResults != null)
|
||
|
|
{
|
||
|
|
foreach (var m in ConfigData.Modules)
|
||
|
|
{
|
||
|
|
var configured = m.NumberOfConfiguredChannels();
|
||
|
|
configuredChannelPerModuleArrayIndex[m.ModuleArrayIndex] = configured;
|
||
|
|
}
|
||
|
|
|
||
|
|
//g5 doesn't seem to like test channel run pre all right now?
|
||
|
|
if (IsG5())
|
||
|
|
{
|
||
|
|
if (IsG5() && G5Mode == G5Modes.VDS)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var ds = new G5DockStat(this, true);
|
||
|
|
ds.SyncExecute();
|
||
|
|
BaseInput.BatteryIsCharging = ds.BatteryCharging;
|
||
|
|
|
||
|
|
//AF - 08/25/2016
|
||
|
|
BaseInput.BatteryMilliVolts = ds.BatteryMilliVolts;
|
||
|
|
}
|
||
|
|
catch (Exception) { /* tolerate failure in case we are not in a VDS */}
|
||
|
|
BaseInput.BatteryMilliVolts = double.NaN;
|
||
|
|
}
|
||
|
|
|
||
|
|
var bRunTestChannelRun = false;
|
||
|
|
if (null != ChannelDiagnostics && ChannelDiagnostics.Any())
|
||
|
|
{
|
||
|
|
foreach (var cd in ChannelDiagnostics)
|
||
|
|
{
|
||
|
|
if (!cd.AllActionsDisabled())
|
||
|
|
{
|
||
|
|
bRunTestChannelRun = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (bRunTestChannelRun)
|
||
|
|
{
|
||
|
|
info.NewData(new ServiceCallbackData.DiagnosticNewData()
|
||
|
|
{
|
||
|
|
Action = ServiceCallbackData.DiagnosticNewData.Actions.TestChannelRun,
|
||
|
|
DasChannelNumber = 0,
|
||
|
|
Result = ""
|
||
|
|
});
|
||
|
|
//could take 6 seconds for each channel, I give it a little leeway beyond that
|
||
|
|
var tp = new TestChannelRun(this, 32 * 9 * 1000)
|
||
|
|
{
|
||
|
|
ChannelIndex = -1,
|
||
|
|
RackCommand = true
|
||
|
|
};
|
||
|
|
tp.SyncExecute();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
|
||
|
|
|
||
|
|
if (1 == channelsToRunOn)
|
||
|
|
{
|
||
|
|
var moduleIndex = DASInfo.MapDASChannelNumber2ModuleArrayIndex(channelToRunOn);
|
||
|
|
var channel = DASInfo.MapDASChannelNumber2ModuleChannelNumber(channelToRunOn);
|
||
|
|
var module = DASInfo.Modules[moduleIndex].ModuleArrayIndex;
|
||
|
|
var tr = new TestChannelRun(this);
|
||
|
|
if (bChannelToRunOnIsTOM)
|
||
|
|
{
|
||
|
|
tr.ChannelIndex = (1 + channel) / 2;
|
||
|
|
}
|
||
|
|
else { tr.ChannelIndex = 1 + channel; }
|
||
|
|
tr.ModuleIndex = module;
|
||
|
|
tr.SyncExecute();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
var slowestModule = GetSlowestModule();
|
||
|
|
//toms have to be treated differnetly, they are in capable of updating with TESTCHANNELRUNBROADCAST and have
|
||
|
|
//to be run directly ...
|
||
|
|
if (slowestModule >= 0)
|
||
|
|
{
|
||
|
|
var qsn = new QuerySerialNumberBroadcast(this, slowestModule);
|
||
|
|
qsn.SyncExecute();
|
||
|
|
|
||
|
|
var tp = new TestChannelRunBroadcast(this,
|
||
|
|
8 * DFConstantsAndEnums.ExpectedMaxTDASDiagnosticRunTimePerChannelMS,
|
||
|
|
slowestModule);
|
||
|
|
tp.SyncExecute();
|
||
|
|
}
|
||
|
|
foreach (var m in ConfigData.Modules)
|
||
|
|
{
|
||
|
|
var configured = m.NumberOfConfiguredChannels();
|
||
|
|
if (configured <= 0 || !IsTom(m)) continue;
|
||
|
|
var tp = new TestChannelRun(this)
|
||
|
|
{
|
||
|
|
ModuleIndex = m.ModuleArrayIndex,
|
||
|
|
ChannelIndex = -1
|
||
|
|
};
|
||
|
|
tp.SyncExecute();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
Thread.Sleep(2000);
|
||
|
|
TestChannelReadAll tcr2 = null;
|
||
|
|
var currentModule = -1;
|
||
|
|
|
||
|
|
for (var i = 0; i < ChannelDiagnostics.Length; i++)
|
||
|
|
{
|
||
|
|
if (ChannelDiagnostics[i].AllActionsDisabled()) continue;
|
||
|
|
var moduleIndex = DASInfo.MapDASChannelNumber2ModuleArrayIndex(ChannelDiagnostics[i].DASChannelNumber);
|
||
|
|
var channel = DASInfo.MapDASChannelNumber2ModuleChannelNumber(ChannelDiagnostics[i].DASChannelNumber);
|
||
|
|
var module = DASInfo.Modules[moduleIndex].ModuleArrayIndex;
|
||
|
|
|
||
|
|
//you can run diagnostics on a single module, which means your diagnostic actions will be smaller and in a different
|
||
|
|
//order than your results, so find the result index separately than the diagnostics we are running through
|
||
|
|
int resultIndex = -1;
|
||
|
|
for (var idx = 0; idx < ChannelDiagnosticsResults.Length; idx++)
|
||
|
|
{
|
||
|
|
if (ChannelDiagnosticsResults[idx].DASChannelNumber == ChannelDiagnostics[i].DASChannelNumber)
|
||
|
|
{
|
||
|
|
resultIndex = i;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//no result in place, won't run this diagnostic action ...
|
||
|
|
if (resultIndex < 0) { continue; }
|
||
|
|
|
||
|
|
if (IsTom(ConfigData.Modules[moduleIndex]))
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
info.NewData(new ServiceCallbackData.DiagnosticNewData()
|
||
|
|
{
|
||
|
|
Action = ServiceCallbackData.DiagnosticNewData.Actions.TestChannelRead,
|
||
|
|
DasChannelNumber = 0,
|
||
|
|
Result = ""
|
||
|
|
});
|
||
|
|
if (1 == channelsToRunOn)
|
||
|
|
{
|
||
|
|
DASInfo.MapDASChannelNumber2ModuleArrayIndex(channelToRunOn);
|
||
|
|
var channel1 = DASInfo.MapDASChannelNumber2ModuleChannelNumber(channelToRunOn);
|
||
|
|
var module1 = DASInfo.Modules[moduleIndex].ModuleArrayIndex;
|
||
|
|
|
||
|
|
var analog = ConfigData.Modules[moduleIndex].Channels[channel] as AnalogInputDASChannel;
|
||
|
|
if (analog.DigitalInputChannel)
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].DigitalInputActiveState = IsActive(module1, channelToRunOn, analog);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
|
||
|
|
var tcRead = new TestChannelRead(this)
|
||
|
|
{
|
||
|
|
ModuleIndex = module1,
|
||
|
|
ChannelIndex = 1 + channel1
|
||
|
|
};
|
||
|
|
tcRead.SyncExecute();
|
||
|
|
|
||
|
|
ChannelDiagnosticsResults[resultIndex].MeasuredExcitationMilliVolts = tcRead.Excitation * 1000D;
|
||
|
|
ChannelDiagnosticsResults[resultIndex].NegativeExcitation = tcRead.NegativeExcitation;
|
||
|
|
|
||
|
|
switch (analog.Excitation)
|
||
|
|
{
|
||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt10:
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ExpectedExcitationMilliVolts = 10000;
|
||
|
|
break;
|
||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt2:
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ExpectedExcitationMilliVolts = 2000;
|
||
|
|
break;
|
||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt5:
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ExpectedExcitationMilliVolts = 5000;
|
||
|
|
break;
|
||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Undefined:
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ExpectedExcitationMilliVolts = 5000;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
throw new InvalidDataException("invalid excitation " + analog.Excitation);
|
||
|
|
}
|
||
|
|
var stddev = tcRead.ZeroStdDevAtGainADC;
|
||
|
|
ChannelDiagnosticsResults[resultIndex].NoisePercentFullScale = 100D * stddev / (-1D * short.MinValue);
|
||
|
|
ChannelDiagnosticsResults[resultIndex].FinalOffsetADC = Convert.ToInt16(tcRead.ZeroAverageADCValue);
|
||
|
|
|
||
|
|
if (ChannelDiagnostics[i].MeasureOffset)
|
||
|
|
{
|
||
|
|
if (ChannelDiagnostics[i].RemoveOffset)
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].AutoZeroPercentDeviation = 100D * ChannelDiagnosticsResults[resultIndex].FinalOffsetADC /
|
||
|
|
short.MaxValue;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].AutoZeroPercentDeviation = null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
try
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ZeroMVInADC = Convert.ToInt16(tcRead.ZeroMvADC);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
APILogger.Log(ex);
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ZeroMVInADC = 0;
|
||
|
|
}
|
||
|
|
try
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ScalefactorMilliVoltsPerADC = tcRead.MvScaleFactorADC;
|
||
|
|
if (ChannelDiagnostics[i].MeasureOffset)
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].MeasuredOffsetMilliVolts = tcRead.SensorOffsetMv;
|
||
|
|
//The following will be subtracted out in GetInitialOffset() of HardwareChannel, but since it's
|
||
|
|
//already accounted for in GetSensorOffsetmV we don't want to subtract anything (unlike SLICE)
|
||
|
|
ChannelDiagnosticsResults[resultIndex].MeasuredInternalOffsetMilliVolts = 0D;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ScalefactorMilliVoltsPerADC = 1;
|
||
|
|
APILogger.Log(ex);
|
||
|
|
}
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (ChannelDiagnostics[i].PerformShuntCheck)
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].MeasuredShuntDeflectionMv = tcRead.ShuntCalibrationDeltaADC *
|
||
|
|
tcRead.MvScaleFactorADC;
|
||
|
|
ChannelDiagnosticsResults[resultIndex].TargetShuntDeflectionMv = analog.ShuntTargetADC *
|
||
|
|
tcRead.MvScaleFactorADC;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].MeasuredShuntDeflectionMv = 1;
|
||
|
|
ChannelDiagnosticsResults[resultIndex].TargetShuntDeflectionMv = 1;
|
||
|
|
APILogger.Log(ex);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
var analog = (AnalogInputDASChannel)ConfigData.Modules[moduleIndex].Channels[channel];
|
||
|
|
if (analog.DigitalInputChannel)
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].DigitalInputActiveState = IsActive(ConfigData.Modules[moduleIndex].ModuleArrayIndex, ChannelDiagnostics[i].DASChannelNumber, analog);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (module != currentModule)
|
||
|
|
{
|
||
|
|
tcr2 = new TestChannelReadAll(this, configuredChannelPerModuleArrayIndex[module])
|
||
|
|
{
|
||
|
|
ModuleIndex = module
|
||
|
|
};
|
||
|
|
currentModule = module;
|
||
|
|
tcr2.SyncExecute();
|
||
|
|
tcr2.CheckData();
|
||
|
|
}
|
||
|
|
ChannelDiagnosticsResults[resultIndex].MeasuredExcitationMilliVolts = tcr2.GetExcitation(1 + channel) * 1000D;
|
||
|
|
ChannelDiagnosticsResults[resultIndex].NegativeExcitation = tcr2.GetNegativeExcitation(1 + channel);
|
||
|
|
|
||
|
|
switch (analog.Excitation)
|
||
|
|
{
|
||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt10:
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ExpectedExcitationMilliVolts = 10000;
|
||
|
|
break;
|
||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt2:
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ExpectedExcitationMilliVolts = 2000;
|
||
|
|
break;
|
||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt5:
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ExpectedExcitationMilliVolts = 5000;
|
||
|
|
break;
|
||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Undefined:
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ExpectedExcitationMilliVolts = 5000;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
throw new InvalidDataException("invalid excitation " + analog.Excitation);
|
||
|
|
}
|
||
|
|
var stddev = tcr2.GetZeroStdDevAtGainADC(1 + channel);
|
||
|
|
ChannelDiagnosticsResults[resultIndex].NoisePercentFullScale = 100D * stddev / (-1D * short.MinValue);
|
||
|
|
ChannelDiagnosticsResults[resultIndex].FinalOffsetADC = Convert.ToInt16(tcr2.GetZeroAverageADCValue(1 + channel));
|
||
|
|
if (ChannelDiagnostics[i].MeasureOffset)
|
||
|
|
{
|
||
|
|
if (ChannelDiagnostics[resultIndex].RemoveOffset)
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].AutoZeroPercentDeviation = 100D * ChannelDiagnosticsResults[i].FinalOffsetADC / short.MaxValue;
|
||
|
|
}
|
||
|
|
else { ChannelDiagnosticsResults[resultIndex].AutoZeroPercentDeviation = null; }
|
||
|
|
}
|
||
|
|
try
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ZeroMVInADC = Convert.ToInt16(tcr2.GetZeromVADC(1 + channel));
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ZeroMVInADC = 0;
|
||
|
|
APILogger.Log(ex);
|
||
|
|
}
|
||
|
|
try
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ScalefactorMilliVoltsPerADC = tcr2.GetmVScaleFactorADC(1 + channel);
|
||
|
|
if (ChannelDiagnostics[i].MeasureOffset)
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].MeasuredOffsetMilliVolts = tcr2.GetSensorOffsetmV(1 + channel);
|
||
|
|
//The following will be subtracted out in GetInitialOffset() of HardwareChannel, but since it's
|
||
|
|
//already accounted for in GetSensorOffsetmV we don't want to subtract anything (unlike SLICE)
|
||
|
|
ChannelDiagnosticsResults[resultIndex].MeasuredInternalOffsetMilliVolts = 0D;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ScalefactorMilliVoltsPerADC = 1;
|
||
|
|
APILogger.Log(ex);
|
||
|
|
}
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (ChannelDiagnostics[i].PerformShuntCheck)
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].MeasuredShuntDeflectionMv =
|
||
|
|
tcr2.GetShuntCalibrationDeltaADC(1 + channel) * tcr2.GetmVScaleFactorADC(1 + channel);
|
||
|
|
ChannelDiagnosticsResults[resultIndex].TargetShuntDeflectionMv =
|
||
|
|
analog.ShuntTargetADC * tcr2.GetmVScaleFactorADC(1 + channel);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].MeasuredShuntDeflectionMv = 1;
|
||
|
|
ChannelDiagnosticsResults[resultIndex].TargetShuntDeflectionMv = 1;
|
||
|
|
APILogger.Log(ex);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
info.Progress(100);
|
||
|
|
info.Success();
|
||
|
|
}
|
||
|
|
catch (CanceledException)
|
||
|
|
{
|
||
|
|
// we have been canceled
|
||
|
|
info.Cancel();
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
if (ex.Data.Contains("Status"))
|
||
|
|
{
|
||
|
|
var cs = ex.Data["Status"] as DFConstantsAndEnums.CommandStatus?;
|
||
|
|
if (cs == DFConstantsAndEnums.CommandStatus.StatusSetupShuntDACOutputExceeded)
|
||
|
|
{
|
||
|
|
info.Error("Shunt DAC output exceeded while running diagnostics on channel.\n Calibration stopped.");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
info.Error(ex.Message, ex);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region GetEventDiagnosticsResults
|
||
|
|
|
||
|
|
private class EventDiagnosticsAsyncPacket
|
||
|
|
{
|
||
|
|
public TDASServiceAsyncInfo info { get; set; }
|
||
|
|
public int EventNumber { get; set; }
|
||
|
|
public PrePostResults WhichResult { get; set; }
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Retrieve the results from the implicit pre and post event diagnostics
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="EventNumber">Which event number to Retrieve from</param>
|
||
|
|
/// <param name="WhichResult">The pre or post test results?</param>
|
||
|
|
/// <param name="callback">The function to call with information</param>
|
||
|
|
/// <param name="userData">Whatever you want to pass along</param>
|
||
|
|
void IDiagnosticsActions.GetEventDiagnosticsResults(int EventNumber,
|
||
|
|
PrePostResults WhichResult,
|
||
|
|
ServiceCallback callback,
|
||
|
|
object userData)
|
||
|
|
{
|
||
|
|
|
||
|
|
//Debug.Assert(WhichResult == PrePostResults.PreEventDiagnosticsResult);
|
||
|
|
var packet = new EventDiagnosticsAsyncPacket();
|
||
|
|
packet.info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
packet.EventNumber = EventNumber;
|
||
|
|
packet.WhichResult = WhichResult;
|
||
|
|
|
||
|
|
LaunchAsyncWorker("TDAS.GetEventDiagnosticsResults", AsyncGetEventDiagnosticsResults, packet);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
private void AsyncGetEventDiagnosticsResults(object asyncInfo)
|
||
|
|
{
|
||
|
|
var packet = asyncInfo as EventDiagnosticsAsyncPacket;
|
||
|
|
var attributeName = "";
|
||
|
|
|
||
|
|
var results = new List<DiagnosticsResult>();
|
||
|
|
try
|
||
|
|
{
|
||
|
|
Debug.Assert(packet != null, "packet != null");
|
||
|
|
for (var i = 0; i < DASInfo.Modules.Length; i++)
|
||
|
|
{
|
||
|
|
var bSkipModule = false;
|
||
|
|
var moduleResults = new List<DiagnosticsResult>();
|
||
|
|
for (var z = 0; z < DASInfo.Modules[i].NumberOfChannels; z++)
|
||
|
|
{
|
||
|
|
var dr = new DiagnosticsResult();
|
||
|
|
DiagnosticsResult drNext = null;
|
||
|
|
if ((z == 0) && (ConfigData.Modules[i].Channels[z].ConfigurationMode == DFConstantsAndEnums.ConfigMode.DummyArm) && !IsG5())
|
||
|
|
{
|
||
|
|
bSkipModule = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (bSkipModule)
|
||
|
|
{
|
||
|
|
dr = null;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
dr.DASChannelNumber = DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(DASInfo.Modules[i].ModuleArrayIndex, z);
|
||
|
|
if (ConfigData.Modules[i].Channels[z].ConfigurationMode == DFConstantsAndEnums.ConfigMode.Normal)
|
||
|
|
{
|
||
|
|
var preOrPost = TestChannelReadCommandString.TestType.Pre;
|
||
|
|
if (ConfigData.Modules[i].Channels[z] is OutputSquibChannel osc)
|
||
|
|
{
|
||
|
|
if (osc.ConfigurationMode != DFConstantsAndEnums.ConfigMode.Normal) { continue; }
|
||
|
|
if (osc.MeasurementType == SquibMeasurementType.CURRENT) { dr = null; continue; }
|
||
|
|
drNext = new DiagnosticsResult { EventNumber = 1 };
|
||
|
|
|
||
|
|
if (packet.WhichResult == PrePostResults.PostEventDiagnosticsResult)
|
||
|
|
{
|
||
|
|
preOrPost = TestChannelReadCommandString.TestType.Post;
|
||
|
|
}
|
||
|
|
var tcr2 = new TestSquibChannelRead(this, preOrPost)
|
||
|
|
{
|
||
|
|
ChannelIndex = 1 + (z / 2),
|
||
|
|
ModuleIndex = ConfigData.Modules[i].ModuleArrayIndex
|
||
|
|
};
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
tcr2.SyncExecute();
|
||
|
|
}
|
||
|
|
catch (Exception)
|
||
|
|
{
|
||
|
|
tcr2 = new TestSquibChannelRead(this)
|
||
|
|
{
|
||
|
|
ChannelIndex = 1 + (z / 2),
|
||
|
|
ModuleIndex = ConfigData.Modules[i].ModuleArrayIndex
|
||
|
|
};
|
||
|
|
}
|
||
|
|
dr.NoisePercentFullScale = 100D * tcr2.VoltageStdDevADC / (-1D * short.MinValue);
|
||
|
|
dr.FinalOffsetADC = Convert.ToInt16(tcr2.VoltagePreZero);
|
||
|
|
|
||
|
|
dr.AutoZeroPercentDeviation = null;//never remove offset on a squib?
|
||
|
|
dr.ScalefactorMilliVoltsPerADC = tcr2.VoltageScaleFactorMv;
|
||
|
|
drNext.NoisePercentFullScale = 100D * tcr2.CurrentStdDevADC / (-1D * short.MinValue);
|
||
|
|
drNext.ScalefactorMilliVoltsPerADC = tcr2.CurrentScaleFactorMv;
|
||
|
|
drNext.FinalOffsetADC = Convert.ToInt16(tcr2.CurrentPreZero);
|
||
|
|
drNext.DASChannelNumber = dr.DASChannelNumber + 1;
|
||
|
|
}
|
||
|
|
else if (ConfigData.Modules[i].Channels[z] is OutputTOMDigitalChannel)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (ConfigData.Modules[i].Channels[z] is AnalogInputDASChannel aic)
|
||
|
|
{
|
||
|
|
if (aic.DigitalInputChannel)
|
||
|
|
{
|
||
|
|
dr.FinalOffsetADC = 0;
|
||
|
|
dr.AutoZeroPercentDeviation = null;
|
||
|
|
dr.ZeroMVInADC = 0;
|
||
|
|
dr.ScalefactorMilliVoltsPerADC = 1;
|
||
|
|
dr.MeasuredOffsetMilliVolts = 0D;
|
||
|
|
dr.MeasuredInternalOffsetMilliVolts = 0D;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if ((packet.WhichResult == PrePostResults.PostEventDiagnosticsResult) && !IsG5())
|
||
|
|
{
|
||
|
|
preOrPost = TestChannelReadCommandString.TestType.Post;
|
||
|
|
}
|
||
|
|
var tcr2 = new TestChannelRead(this, 4000, preOrPost)
|
||
|
|
{
|
||
|
|
ChannelIndex = z + 1,
|
||
|
|
ModuleIndex = ConfigData.Modules[i].ModuleArrayIndex
|
||
|
|
};
|
||
|
|
tcr2.SyncExecute();
|
||
|
|
dr.MeasuredExcitationMilliVolts = tcr2.Excitation * 1000D;
|
||
|
|
dr.NegativeExcitation = tcr2.NegativeExcitation;
|
||
|
|
var analog = ConfigData.Modules[i].Channels[z] as AnalogInputDASChannel;
|
||
|
|
|
||
|
|
switch (analog.Excitation)
|
||
|
|
{
|
||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt10:
|
||
|
|
dr.ExpectedExcitationMilliVolts = 10000;
|
||
|
|
break;
|
||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt2:
|
||
|
|
dr.ExpectedExcitationMilliVolts = 2000;
|
||
|
|
break;
|
||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt5:
|
||
|
|
dr.ExpectedExcitationMilliVolts = 5000;
|
||
|
|
break;
|
||
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Undefined:
|
||
|
|
dr.ExpectedExcitationMilliVolts = 5000;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
throw new InvalidDataException("invalid excitation " + analog.Excitation);
|
||
|
|
}
|
||
|
|
var stddev = tcr2.ZeroStdDevAtGainADC;
|
||
|
|
dr.NoisePercentFullScale = 100D * stddev / (-1D * short.MinValue);
|
||
|
|
dr.FinalOffsetADC = Convert.ToInt16(tcr2.ZeroAverageADCValue);
|
||
|
|
if (analog.RemoveOffset)
|
||
|
|
{
|
||
|
|
dr.AutoZeroPercentDeviation = 100D * (double)dr.FinalOffsetADC / short.MaxValue;
|
||
|
|
}
|
||
|
|
else { dr.AutoZeroPercentDeviation = null; }
|
||
|
|
dr.ZeroMVInADC = Convert.ToInt16(tcr2.ZeroMvADC);
|
||
|
|
dr.ScalefactorMilliVoltsPerADC = tcr2.MvScaleFactorADC;
|
||
|
|
dr.MeasuredOffsetMilliVolts = tcr2.SensorOffsetMv;
|
||
|
|
dr.MeasuredShuntDeflectionMv = tcr2.ShuntCalibrationDeltaADC * tcr2.MvScaleFactorADC;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
dr.EventNumber = 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (null != dr) { moduleResults.Add(dr); }
|
||
|
|
if (null != drNext) { moduleResults.Add(drNext); }
|
||
|
|
}
|
||
|
|
results.AddRange(moduleResults);
|
||
|
|
}
|
||
|
|
|
||
|
|
packet.info.Progress(100);
|
||
|
|
|
||
|
|
SetChannelDiagnosticsResults(results.ToArray(), false);
|
||
|
|
|
||
|
|
packet.info.Success();
|
||
|
|
}
|
||
|
|
catch (CanceledException)
|
||
|
|
{
|
||
|
|
packet.info.Cancel();
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
packet.info.Error(ex.Message + " Attribute: " + attributeName, ex);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
void IDiagnosticsActions.SquibFireCheckArm(double delay, double duration, ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
var packet = new SquibFireCheckArmPacket();
|
||
|
|
packet.info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
packet.duration = duration;
|
||
|
|
packet.delay = delay;
|
||
|
|
|
||
|
|
LaunchAsyncWorker("TDAS.SquibFireCheckArm", AsyncSquibFireCheckArm, packet);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// returns true if a shorted trigger was detected
|
||
|
|
/// 17822 DataPRO and TDAS rack unresponsive during diagnostics
|
||
|
|
/// <summary>
|
||
|
|
private bool CheckShortedTrigger()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var ta = new TestAll(this);
|
||
|
|
ta.Mode = TestAllCommandString.Modes.PREV;
|
||
|
|
ta.SyncExecute();
|
||
|
|
|
||
|
|
ta = new TestAll(this);
|
||
|
|
ta.Mode = TestAllCommandString.Modes.CURR;
|
||
|
|
ta.SyncExecute();
|
||
|
|
if (ta.TriggerFlag == DFConstantsAndEnums.VoltageStatusColor.Red)
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
APILogger.Log("Failed to check for shorted trigger: ", ex);
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
/// <summary>
|
||
|
|
/// the working guts of PrepareForDiagnostics
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="asyncInfo">our async data</param>
|
||
|
|
private void AsyncSquibFireCheckArm(object asyncInfo)
|
||
|
|
{
|
||
|
|
var packet = asyncInfo as SquibFireCheckArmPacket;
|
||
|
|
if (IsG5()) { packet?.info.Success(); return; }
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var bHasTOM = false;
|
||
|
|
foreach (DASModule module in ConfigData.Modules)
|
||
|
|
{
|
||
|
|
if (DASInfo.Modules[module.ModuleArrayIndex].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK) { continue; }
|
||
|
|
if (IsTom(module))
|
||
|
|
{
|
||
|
|
//run test channel run now before arming, can't run it after arming without turning power back on and off
|
||
|
|
//and we need some results from test channel read to process data from the squib fire check.
|
||
|
|
var testChannelRun = new TestChannelRun(this);
|
||
|
|
testChannelRun.ModuleIndex = module.ModuleArrayIndex;
|
||
|
|
testChannelRun.ChannelIndex = -1;
|
||
|
|
testChannelRun.SyncExecute();
|
||
|
|
|
||
|
|
bHasTOM = true;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var sdl = new SetupTOMDASLoad(this);
|
||
|
|
sdl.ModuleIndex = module.ModuleArrayIndex;
|
||
|
|
sdl.ArmMode = SetupTOMDASLoad.ARMMode.DIAGW;
|
||
|
|
sdl.SetHardwareAAFilter(2000, MaxAAFilterRateHz);
|
||
|
|
sdl.SampleRate = 10000;
|
||
|
|
sdl.OutputRate = 0;
|
||
|
|
|
||
|
|
sdl.PreTriggerSeconds = .1D;//we want to have a little pre-trigger time incase delay = 0ms,
|
||
|
|
//we'd like to check that the pre-trigger level is below thresholds.
|
||
|
|
sdl.PostTriggerSeconds = .5D + (packet.delay + packet.duration) / 1000;
|
||
|
|
sdl.PostADWaitTime = -1;
|
||
|
|
sdl.TriggerType = SetupTOMDASLoad.TriggerTypes.BUS;
|
||
|
|
sdl.TestId = "_TESTTRIG_";
|
||
|
|
sdl.TestConfig = $"{"TEST"}{SETUPDASREAD_SENTINEL}{ConfigData.Modules[module.ModuleArrayIndex].GetCRC32()}";
|
||
|
|
sdl.SyncExecute();
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
APILogger.Log("problem with test trigger setup das load ", SerialNumber, ex);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
var sdl = new SetupDASLoad(this);
|
||
|
|
var sdlDIM = new SetupDASLoadDIM(this);
|
||
|
|
|
||
|
|
sdl.ModuleIndex = module.ModuleArrayIndex;
|
||
|
|
sdlDIM.ModuleIndex = module.ModuleArrayIndex;
|
||
|
|
|
||
|
|
sdl.ArmMode = SetupDASLoad.ARMMode.WAIT;
|
||
|
|
sdlDIM.ArmMode = SetupDASLoadDIM.ArmModes.WAIT;
|
||
|
|
|
||
|
|
sdl.SetHardwareAAFilter(2000, MaxAAFilterRateHz);
|
||
|
|
sdl.SampleRate = 10000;
|
||
|
|
sdlDIM.SampleRate = 10000;
|
||
|
|
sdl.OutputRate = 0;
|
||
|
|
sdl.IsDummyArm = false;
|
||
|
|
sdlDIM.IsDummyArm = false;
|
||
|
|
sdl.CollectData = false;
|
||
|
|
sdlDIM.CollectData = false;
|
||
|
|
|
||
|
|
sdl.PreTriggerSeconds = .1D;//we want to have a little pre-trigger time incase delay = 0ms,
|
||
|
|
//we'd like to check that the pre-trigger level is below thresholds.
|
||
|
|
sdlDIM.PreTriggerSeconds = .1D;
|
||
|
|
|
||
|
|
sdl.PostTriggerSeconds = .5D + (packet.delay + packet.duration) / 1000;
|
||
|
|
sdlDIM.PostTriggerSeconds = .5D + (packet.delay + packet.duration) / 1000D;
|
||
|
|
|
||
|
|
sdl.PostADWaitTime = -1;
|
||
|
|
sdlDIM.PostADWaitTime = -1;
|
||
|
|
|
||
|
|
sdl.TriggerType = SetupDASLoad.TriggerTypes.HW;
|
||
|
|
sdlDIM.TriggerType = SetupDASLoadDIM.TriggerTypes.HW;
|
||
|
|
|
||
|
|
sdl.TestId = "TESTTRIG";
|
||
|
|
sdlDIM.TestId = sdl.TestId;
|
||
|
|
|
||
|
|
sdl.TestConfig =
|
||
|
|
$"{"TEST"}{SETUPDASREAD_SENTINEL}{ConfigData.Modules[module.ModuleArrayIndex].GetCRC32()}";
|
||
|
|
sdlDIM.TestConfig = sdl.TestConfig;
|
||
|
|
if (DASInfo.Modules[module.ModuleArrayIndex].TypeOfModule == DFConstantsAndEnums.ModuleType.ProDIM && !IsG5())
|
||
|
|
{
|
||
|
|
sdlDIM.SyncExecute();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (module.ModuleArrayIndex > 0 && IsG5())
|
||
|
|
{
|
||
|
|
//only need to execute on first module in g5
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
sdl.SyncExecute();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (bHasTOM)
|
||
|
|
{
|
||
|
|
//warn if there's a shorted trigger before going any further
|
||
|
|
//17822 DataPRO and TDAS rack unresponsive during diagnostics
|
||
|
|
if (CheckShortedTrigger())
|
||
|
|
{
|
||
|
|
packet?.info.Error("TriggerShorted", new TriggerShortedException(SerialNumber));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
foreach (var module in ConfigData.Modules)
|
||
|
|
{
|
||
|
|
if (DASInfo.Modules[module.ModuleArrayIndex].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK) { continue; }
|
||
|
|
|
||
|
|
var qsn = new QuerySerialNumberBroadcast(this, module.ModuleArrayIndex);
|
||
|
|
qsn.SyncExecute();
|
||
|
|
|
||
|
|
//17717 ModuleArmBroadcast must wait on G5
|
||
|
|
//the module arm broadcast now waits when G5, doesn't when not
|
||
|
|
var mab = new ModuleArmBroadcast(this, module.ModuleArrayIndex, IsG5());
|
||
|
|
mab.SyncExecute();
|
||
|
|
if (!IsG5())
|
||
|
|
{
|
||
|
|
//G5 is waiting on sync execute above, rack is not
|
||
|
|
//thread is to prevent rack from executing another command too
|
||
|
|
//soon
|
||
|
|
//17717 ModuleArmBroadcast must wait on G5
|
||
|
|
Thread.Sleep(2500);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
var asl = new ArmSetupLoad(this);
|
||
|
|
asl.ArmMode = ArmSetupLoad.ArmModes.WAIT;
|
||
|
|
asl.PostADWait = -1;
|
||
|
|
|
||
|
|
asl.RackArmMode = ArmSetupLoad.RackArmModes.SOLO;
|
||
|
|
asl.SampleRate = 10000;
|
||
|
|
asl.SyncExecute();
|
||
|
|
|
||
|
|
var ra = new RackArm(this);
|
||
|
|
ra.ArmState = RackArm.ArmStates.NOW;
|
||
|
|
|
||
|
|
ra.SyncExecute();
|
||
|
|
if (ra.IsErrored) { throw new Exception($"{SerialNumber}:{ra.ResponseData}"); }
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var ta = new TestAll(this);
|
||
|
|
ta.SyncExecute();
|
||
|
|
}
|
||
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
||
|
|
|
||
|
|
}
|
||
|
|
packet?.info.Success();
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
//15606 communications error, record & mark failed
|
||
|
|
APILogger.Log(ex);
|
||
|
|
packet.info.Error(ex.Message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void IDiagnosticsActions.TriggerCheckTrigger(ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
var packet = new DiagnosticsAsyncPacket();
|
||
|
|
packet.info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
|
||
|
|
LaunchAsyncWorker("TDAS.TriggerCheckTrigger", AsyncTriggerCheckTrigger, packet);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// the working guts of PrepareForDiagnostics
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="asyncInfo">our async data</param>
|
||
|
|
private void AsyncTriggerCheckTrigger(object asyncInfo)
|
||
|
|
{
|
||
|
|
var packet = asyncInfo as DiagnosticsAsyncPacket;
|
||
|
|
bool bHasTOM = false;
|
||
|
|
foreach (DASModule module in ConfigData.Modules)
|
||
|
|
{
|
||
|
|
if (IsTom(module)) { bHasTOM = true; }
|
||
|
|
}
|
||
|
|
if (bHasTOM)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var rtc = new RackTriggerCommand(this);
|
||
|
|
rtc.SyncExecute();
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
if (!ex.Message.Contains("already triggered"))
|
||
|
|
{
|
||
|
|
packet.info.Error(ex.Message);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
packet.info.Success();
|
||
|
|
}
|
||
|
|
|
||
|
|
void IDiagnosticsActions.TriggerCheckDownload(double delay, double duration, float diagnosticsAAFilterFrequencyHz, uint diagnosticsSampleRateHz, ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
var packet = new DiagnosticsTriggerCheckDownloadPacket();
|
||
|
|
packet.delay = delay;
|
||
|
|
packet.duration = duration;
|
||
|
|
packet.DiagnosticsAAFilterFrequencyHz = diagnosticsAAFilterFrequencyHz;
|
||
|
|
packet.DiagnosticsSampleRateHz = diagnosticsSampleRateHz;
|
||
|
|
packet.info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
|
||
|
|
LaunchAsyncWorker("TDAS.TriggerCheckDownload", AsyncTriggerCheckDownload, packet);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// the working guts of PrepareForDiagnostics
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="asyncInfo">our async data</param>
|
||
|
|
private void AsyncTriggerCheckDownload(object asyncInfo)
|
||
|
|
{
|
||
|
|
var packet = asyncInfo as DiagnosticsTriggerCheckDownloadPacket;
|
||
|
|
DateTime waitForRack = DateTime.Now;
|
||
|
|
int maxRackWaitSeconds = 10;
|
||
|
|
|
||
|
|
if (!IsG5())
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
while ((waitForRack - DateTime.Now).TotalSeconds < maxRackWaitSeconds)
|
||
|
|
{
|
||
|
|
var arm = new QueryArmStatus(this);
|
||
|
|
arm.SyncExecute();
|
||
|
|
if (arm.Status == QueryArmStatus.ARMStatus.DONE) { break; }
|
||
|
|
Thread.Sleep(1000);
|
||
|
|
}
|
||
|
|
|
||
|
|
//ARM OFF
|
||
|
|
var armOff = new ARMOFF(this);
|
||
|
|
armOff.SyncExecute();
|
||
|
|
}
|
||
|
|
catch (Exception e)
|
||
|
|
{
|
||
|
|
//15606 communications error turning off, mark failed
|
||
|
|
APILogger.Log(e);
|
||
|
|
packet.info.Error(e.Message);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
//nothing to download on a G5 ...
|
||
|
|
if (IsG5())
|
||
|
|
{
|
||
|
|
packet.info.Success();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach (var iDASModule in ConfigData.Modules)
|
||
|
|
{
|
||
|
|
var module = (DASModule)iDASModule;
|
||
|
|
if (module.SerialNumber() == "EMPTY")
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
//note apparently on some units in a squib fire check
|
||
|
|
//TEST PREPARE remains on, I have no idea, that seems like a firmware issue
|
||
|
|
//however we want to explicitly turn off power during the download phase
|
||
|
|
//so that regular diagnostics will properly turn on power
|
||
|
|
//(currently only turns on power if ALL modules have power off)
|
||
|
|
var testPrepareOff = new TestPrepare(this);
|
||
|
|
testPrepareOff.ModuleIndex = module.ModuleArrayIndex;
|
||
|
|
testPrepareOff.On = false;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
testPrepareOff.SyncExecute();
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
APILogger.Log(ex);
|
||
|
|
}
|
||
|
|
if (IsTom(module))
|
||
|
|
{
|
||
|
|
|
||
|
|
if (!IsTom(module)) { continue; }
|
||
|
|
|
||
|
|
//If there exists a module without a configured channel, send it a ?N
|
||
|
|
var moduleHasChannel = false;
|
||
|
|
foreach (var channel in module.Channels)
|
||
|
|
{
|
||
|
|
if (!channel.IsConfigured()) { continue; }
|
||
|
|
if (!(channel is OutputSquibChannel squib)) { continue; }
|
||
|
|
if (squib.MeasurementType == SquibMeasurementType.CURRENT) { continue; }
|
||
|
|
moduleHasChannel = true;
|
||
|
|
}
|
||
|
|
if (!moduleHasChannel)
|
||
|
|
{
|
||
|
|
if (module.SerialNumber() != "EMPTY")
|
||
|
|
{
|
||
|
|
//?N
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var qsn = new QuerySerialNumber(this, 2000);
|
||
|
|
qsn.ModuleIndex = module.ModuleArrayIndex;
|
||
|
|
qsn.SyncExecute();
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
//15606 communications error, mark failed
|
||
|
|
APILogger.Log(ex);
|
||
|
|
packet.info.Error(ex.Message);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
foreach (var channel in module.Channels)
|
||
|
|
{
|
||
|
|
if (!channel.IsConfigured()) { continue; }
|
||
|
|
if (!(channel is OutputSquibChannel squib)) { continue; }
|
||
|
|
if (squib.MeasurementType == SquibMeasurementType.CURRENT) { continue; }
|
||
|
|
try
|
||
|
|
{
|
||
|
|
//surprisingly, don't use the module.samplerate, as it's set for what the test is, but apparently
|
||
|
|
//diagnostics is running at a fixed 10k!
|
||
|
|
const int sps = 10000;
|
||
|
|
var qda = new QueryDataAvailable(this);
|
||
|
|
qda.ModuleIndex = module.ModuleArrayIndex;
|
||
|
|
qda.SyncExecute();
|
||
|
|
|
||
|
|
var d = new Download(this);
|
||
|
|
d.ModuleIndex = module.ModuleArrayIndex;
|
||
|
|
d.DoCurrentDownload = true;
|
||
|
|
d.DoVoltageOrInsertionDownload = false;
|
||
|
|
d.FirstPoint = Convert.ToInt64(-.1D * sps);
|
||
|
|
d.LastPoint = Convert.ToInt64(.5 * sps + (packet.delay + packet.duration) * 10);//since we are doing things in sps 1000, just leave things in ms
|
||
|
|
d.ChannelIndex = Convert.ToInt32(Math.Floor(channel.ModuleChannelNumber / 2D));
|
||
|
|
d.SyncExecute();
|
||
|
|
Thread.Sleep(200);
|
||
|
|
var mydata = d.GetData();
|
||
|
|
|
||
|
|
|
||
|
|
d = new Download(this);
|
||
|
|
d.ModuleIndex = module.ModuleArrayIndex;
|
||
|
|
d.DoCurrentDownload = false;
|
||
|
|
d.DoVoltageOrInsertionDownload = true;
|
||
|
|
d.FirstPoint = Convert.ToInt64(-.1D * sps);
|
||
|
|
d.LastPoint = Convert.ToInt64(.5D * sps + (packet.delay + packet.duration) * 10);//since we are doing things in sps 1000, just leave things in ms
|
||
|
|
d.ChannelIndex = Convert.ToInt32(Math.Floor((double)channel.ModuleChannelNumber) / 2D);
|
||
|
|
d.SyncExecute();
|
||
|
|
Thread.Sleep(200);
|
||
|
|
var mydata2 = d.GetData();
|
||
|
|
|
||
|
|
var convertedCurrentData = new List<double>();
|
||
|
|
var convertedVoltageData = new List<double>();
|
||
|
|
|
||
|
|
var threshold = 0D;
|
||
|
|
//notes http://foghat/dtswiki/index.php?title=Squib_Fire_Test
|
||
|
|
//updated per http://fogbugz/fogbugz/default.asp?4860#26469
|
||
|
|
switch (squib.FireMode)
|
||
|
|
{
|
||
|
|
case SquibFireMode.AC:
|
||
|
|
threshold = 1.5D;
|
||
|
|
break;
|
||
|
|
case SquibFireMode.CAP:
|
||
|
|
threshold = 2.1D;
|
||
|
|
break;
|
||
|
|
case SquibFireMode.CONSTANT:
|
||
|
|
{
|
||
|
|
threshold = .75D * squib.SquibOutputCurrent;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
var indexOverThreshold = int.MaxValue;//marks where we first cross from below threshold to over
|
||
|
|
//we will use this to ensure delay is accurate
|
||
|
|
var indexBelowThresholdAgain = int.MaxValue;
|
||
|
|
//make sure it's > low threshold and < max threshold
|
||
|
|
//we also need to make sure it's above min threshold (and below max) after duration ms
|
||
|
|
//we also need to make sure it's below threshold after the duration.
|
||
|
|
//this is a bad assumption
|
||
|
|
//12058 Run(Channel) sub nav step not functional for squibs in diagnostics.
|
||
|
|
//int resultIndex = DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(module.ModuleArrayIndex, channel.ModuleChannelNumber);
|
||
|
|
var dasChannelNumber =
|
||
|
|
DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(module.ModuleArrayIndex,
|
||
|
|
channel.ModuleChannelNumber);
|
||
|
|
int resultIndex = -1;
|
||
|
|
for (var i = 0; i < ChannelDiagnostics.Length; i++)
|
||
|
|
{
|
||
|
|
if (ChannelDiagnostics[i].DASChannelNumber == dasChannelNumber)
|
||
|
|
{
|
||
|
|
resultIndex = i;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (resultIndex < 0) { continue; }
|
||
|
|
// we need the scale factor results for the channel
|
||
|
|
// note that the test channel run will come during the test squib fire
|
||
|
|
// we lead the results here for processing the squib fire data
|
||
|
|
var tcr3 = new TestSquibChannelRead(
|
||
|
|
this)
|
||
|
|
{
|
||
|
|
ModuleIndex = module.ModuleArrayIndex,
|
||
|
|
ChannelIndex = 1 + (channel.ModuleChannelNumber / 2)
|
||
|
|
};
|
||
|
|
|
||
|
|
tcr3.SyncExecute();
|
||
|
|
|
||
|
|
var scaleFactorMv = tcr3.CurrentScaleFactorMv;
|
||
|
|
var scaleFactorMv2 = tcr3.VoltageScaleFactorMv; // voltage recording channel scale factor
|
||
|
|
var offset = tcr3.CurrentPreZero; // current pre-zero
|
||
|
|
var offset2 = tcr3.VoltagePreZero; // voltage pre-zero
|
||
|
|
|
||
|
|
//we actually want the scale factors from the current channel, not the channel we have right now which is init/volt
|
||
|
|
var dCurrent = 0D;
|
||
|
|
var dVoltage = 0D;
|
||
|
|
for (var i = 0; i < mydata.Length; i++)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
dCurrent = (mydata[i] - offset) * scaleFactorMv;
|
||
|
|
dVoltage = (mydata2[i] - offset2) * scaleFactorMv2;
|
||
|
|
convertedCurrentData.Add(dCurrent);
|
||
|
|
convertedVoltageData.Add(dVoltage);
|
||
|
|
if (indexBelowThresholdAgain != int.MaxValue) continue;
|
||
|
|
if (dCurrent > threshold)
|
||
|
|
{
|
||
|
|
indexOverThreshold = Math.Min(i, indexOverThreshold);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
//only set indexbelowthreshold index once we have gone over the threshold.
|
||
|
|
if (indexOverThreshold < int.MaxValue)
|
||
|
|
{
|
||
|
|
indexBelowThresholdAgain = Math.Min(i, indexBelowThresholdAgain);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception) { }
|
||
|
|
}
|
||
|
|
var actualDelayMS = indexOverThreshold < int.MaxValue ? (indexOverThreshold - .1D * sps) / (sps / 1000D) : 0;
|
||
|
|
var actualDurationMS = (indexBelowThresholdAgain - (double)indexOverThreshold) / (sps / 1000D);//10ksps
|
||
|
|
var deltaDelay = actualDelayMS - squib.DelayMS;
|
||
|
|
var deltaDuration = actualDurationMS - squib.DurationMS;
|
||
|
|
|
||
|
|
var bPassed = true;
|
||
|
|
ChannelDiagnosticsResults[resultIndex].SquibDurationPassed = true;
|
||
|
|
ChannelDiagnosticsResults[resultIndex].SquibDelayPassed = true;
|
||
|
|
if (Math.Abs(deltaDelay) >= 1) { bPassed = false; ChannelDiagnosticsResults[resultIndex].SquibDelayPassed = false; }
|
||
|
|
if (squib.LimitDuration)
|
||
|
|
{
|
||
|
|
if (squib.DurationMS > 6)
|
||
|
|
{
|
||
|
|
if (actualDurationMS < 6) { bPassed = false; ChannelDiagnosticsResults[resultIndex].SquibDurationPassed = false; }
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (Math.Abs(deltaDuration) > .25) { bPassed = false; ChannelDiagnosticsResults[resultIndex].SquibDurationPassed = false; }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (squib.LimitDuration)
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].MeasuredDurationMS = actualDurationMS;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ChannelDiagnosticsResults[resultIndex].MeasuredDurationMS = null;
|
||
|
|
}
|
||
|
|
ChannelDiagnosticsResults[resultIndex].MeasuredDelayMS = actualDelayMS;
|
||
|
|
ChannelDiagnosticsResults[resultIndex].SquibFirePassed = bPassed;
|
||
|
|
|
||
|
|
//we want to start just before the squib was supposed to fire
|
||
|
|
var startIndex = Convert.ToInt32(.099D * sps) + Convert.ToInt32(squib.DelayMS * 10);
|
||
|
|
ChannelDiagnosticsResults[resultIndex].SquibFireCurrentData = convertedCurrentData.GetRange(startIndex,
|
||
|
|
Convert.ToInt32(squib.DurationMS * 10D + 30D)).ToArray();
|
||
|
|
ChannelDiagnosticsResults[resultIndex].SquibFireVoltageData = convertedVoltageData.GetRange(startIndex,
|
||
|
|
Convert.ToInt32(squib.DurationMS * 10D + 30D)).ToArray();
|
||
|
|
|
||
|
|
ChannelDiagnosticsResults[resultIndex].SquibThreshold = threshold;
|
||
|
|
|
||
|
|
var timeAxis = new List<double>(2000);
|
||
|
|
var dCurrentTime = 0D;
|
||
|
|
for (var i = 0; i < ChannelDiagnosticsResults[resultIndex].SquibFireCurrentData.Length; i++)
|
||
|
|
{
|
||
|
|
dCurrentTime = (startIndex + i - 1000D) / (sps / 1000D);
|
||
|
|
timeAxis.Add(dCurrentTime);
|
||
|
|
}
|
||
|
|
ChannelDiagnosticsResults[resultIndex].SquibFireTimeAxis = timeAxis.ToArray();
|
||
|
|
var stddev = tcr3.CurrentStdDevADC;
|
||
|
|
ChannelDiagnosticsResults[resultIndex].NoisePercentFullScale = 100D * stddev / (-1D * short.MinValue);
|
||
|
|
ChannelDiagnosticsResults[resultIndex].FinalOffsetADC = Convert.ToInt16(tcr3.CurrentPreZero);
|
||
|
|
ChannelDiagnosticsResults[resultIndex].AutoZeroPercentDeviation = null;
|
||
|
|
|
||
|
|
ChannelDiagnosticsResults[resultIndex].ScalefactorMilliVoltsPerADC = tcr3.CurrentScaleFactorMv;
|
||
|
|
|
||
|
|
stddev = tcr3.VoltageStdDevADC;
|
||
|
|
ChannelDiagnosticsResults[resultIndex].NoisePercentFullScale = 100D * stddev / (-1D * short.MinValue);
|
||
|
|
ChannelDiagnosticsResults[resultIndex].FinalOffsetADC = Convert.ToInt16(tcr3.VoltagePreZero);
|
||
|
|
ChannelDiagnosticsResults[resultIndex].AutoZeroPercentDeviation = null;
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
//15606 communications error, mark failed
|
||
|
|
APILogger.Log(ex);
|
||
|
|
packet.info.Error(ex.Message);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
//clear download flags
|
||
|
|
//7646 check sensor id navstep shouldn't warn about diagnostic data collection
|
||
|
|
if (ConfigData?.Modules != null)
|
||
|
|
{
|
||
|
|
foreach (var module in ConfigData.Modules)
|
||
|
|
{
|
||
|
|
if (DASInfo.Modules[module.ModuleArrayIndex].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
//only the TOM should have data, rest of modules should be dummy armed
|
||
|
|
//so shorten this by only marking TOM modules as downloaded
|
||
|
|
if (!IsTom(module)) { continue; }
|
||
|
|
var cda = new ClearDataAvailable(this);
|
||
|
|
cda.ModuleIndex = module.ModuleArrayIndex;
|
||
|
|
cda.SyncExecute();
|
||
|
|
//12058 Run (Channel) sub nav step not functional for squibs in diagnostics.
|
||
|
|
//some modules will throw this, I'm unable to find a quick way of determining which ones
|
||
|
|
//but if one does we probably want to continue on to the other modules anyhow...
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (cda.IsErrored)
|
||
|
|
{
|
||
|
|
throw new Exception($"{SerialNumber}:{cda.ResponseData}");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
APILogger.Log(ex);
|
||
|
|
}
|
||
|
|
// Only need to do once for G5
|
||
|
|
if (IsG5())
|
||
|
|
{
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
|
||
|
|
if (!IsG5())
|
||
|
|
{
|
||
|
|
//Turn on excitation and recharge caps
|
||
|
|
var diagnosticsAsyncPacket = new DiagnosticsAsyncPacket();
|
||
|
|
diagnosticsAsyncPacket.info = packet.info;
|
||
|
|
diagnosticsAsyncPacket.DiagnosticsSampleRateHz = packet.DiagnosticsSampleRateHz;
|
||
|
|
diagnosticsAsyncPacket.DiagnosticsAAFilterFrequencyHz = packet.DiagnosticsAAFilterFrequencyHz;
|
||
|
|
diagnosticsAsyncPacket.PreOrPost = PrePostResults.PreEventDiagnosticsResult;
|
||
|
|
SyncPrepareForDiagnostics(diagnosticsAsyncPacket);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
||
|
|
|
||
|
|
packet.info.Success();
|
||
|
|
}
|
||
|
|
|
||
|
|
void IDiagnosticsActions.PerformVoltageCheck(ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
var info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
LaunchAsyncWorker("TDAS.PerformVoltageChecks", new WaitCallback(AsyncVoltageCheck), info);
|
||
|
|
}
|
||
|
|
void IDiagnosticsActions.PerformVoltageCheckTAOnly(ServiceCallback callback, object userData)
|
||
|
|
{
|
||
|
|
var info = new TDASServiceAsyncInfo(callback, userData);
|
||
|
|
LaunchAsyncWorker("TDAS.AsyncVotageCheckTAOnly", new WaitCallback(AsyncVoltageCheckTAOnly), info);
|
||
|
|
}
|
||
|
|
/// <summary>
|
||
|
|
/// Get Voltage status for a hopefully unarmed device
|
||
|
|
/// this should only get called like once onsetactive
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="asyncInfo">our async data</param>
|
||
|
|
private void AsyncVoltageCheckTAOnly(object asyncInfo)
|
||
|
|
{
|
||
|
|
var packet = asyncInfo as TDASServiceAsyncInfo;
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
//using (var ds = new DiagnosticsService())
|
||
|
|
{
|
||
|
|
#region Test All command
|
||
|
|
var ta = new TestAll(this);
|
||
|
|
ta.SyncExecute();
|
||
|
|
#endregion Test All command
|
||
|
|
|
||
|
|
if (BaseInput.BatteryVoltageStatusColor == DFConstantsAndEnums.VoltageStatusColor.Off)
|
||
|
|
{
|
||
|
|
BaseInput.InputVoltageStatus = ta.InputPower.ToString();
|
||
|
|
BaseInput.InputVoltageStatusColor = ta.InputPower;
|
||
|
|
BaseInput.StatusDisplayInput = ta.InputPower.ToString();
|
||
|
|
|
||
|
|
BaseInput.BatteryVoltageStatus = String.Empty;
|
||
|
|
BaseInput.BatteryVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Off;
|
||
|
|
BaseInput.StatusDisplayBattery = TestAll.VoltageStatus.None.ToString();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
BaseInput.InputVoltageStatus = String.Empty;
|
||
|
|
BaseInput.InputVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Off;
|
||
|
|
BaseInput.StatusDisplayInput = TestAll.VoltageStatus.None.ToString();
|
||
|
|
|
||
|
|
BaseInput.BatteryVoltageStatus = ta.InputPower.ToString();
|
||
|
|
BaseInput.BatteryVoltageStatusColor = ta.InputPower;
|
||
|
|
BaseInput.StatusDisplayBattery = ta.InputPower.ToString();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
packet?.Error(ex.Message);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
packet?.Success();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// the working guts of PrepareForDiagnostics
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="asyncInfo">our async data</param>
|
||
|
|
private void AsyncVoltageCheck(object asyncInfo)
|
||
|
|
{
|
||
|
|
var packet = asyncInfo as TDASServiceAsyncInfo;
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
|
||
|
|
var inputMilliVolts = 0D;
|
||
|
|
var inputVoltage = 0D;
|
||
|
|
var inputVoltageStatus = TestAll.VoltageStatus.None.ToString();
|
||
|
|
var inputVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Off;
|
||
|
|
var statusDisplayInput = String.Empty;
|
||
|
|
|
||
|
|
var batteryMilliVolts = 0D;
|
||
|
|
var batteryVoltage = 0D;
|
||
|
|
var batteryIsCharging = true;
|
||
|
|
var batteryVoltageStatus = TestAll.VoltageStatus.High.ToString();
|
||
|
|
var batteryVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Green;
|
||
|
|
var statusDisplayBattery = String.Empty;
|
||
|
|
|
||
|
|
#region G5
|
||
|
|
|
||
|
|
if (IsG5())
|
||
|
|
{
|
||
|
|
var g5DockStat = new G5DockStat(this, true);
|
||
|
|
|
||
|
|
if (G5Mode == G5Modes.VDS)
|
||
|
|
{
|
||
|
|
g5DockStat.SyncExecute();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
g5DockStat.DockStationPresent = false;
|
||
|
|
g5DockStat.BatteryMilliVolts = double.NaN;
|
||
|
|
g5DockStat.BatteryChargeLevel = G5DockStat.BatteryChargeStates.green;
|
||
|
|
g5DockStat.BatteryCharging = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
#region battery
|
||
|
|
|
||
|
|
batteryMilliVolts = g5DockStat.BatteryMilliVolts;
|
||
|
|
var noBattery = double.IsNaN(batteryMilliVolts);
|
||
|
|
batteryVoltage = Math.Round(batteryMilliVolts / 1000D, 2);
|
||
|
|
batteryVoltageStatusColor = noBattery
|
||
|
|
? DFConstantsAndEnums.VoltageStatusColor.Off
|
||
|
|
: G5ConvertBatteryLevel2Color(g5DockStat.BatteryChargeLevel);
|
||
|
|
batteryIsCharging = g5DockStat.BatteryCharging;
|
||
|
|
|
||
|
|
if (noBattery)
|
||
|
|
{
|
||
|
|
statusDisplayBattery = TestAll.VoltageStatus.None.ToString();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (batteryVoltage > MaximumValidBatteryVoltage ||
|
||
|
|
batteryVoltage < MinimumValidBatteryVoltage)
|
||
|
|
{
|
||
|
|
statusDisplayBattery = TestAll.VoltageStatus.None.ToString();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
statusDisplayBattery = batteryVoltage.ToString(CultureInfo.InvariantCulture) + " V " +
|
||
|
|
(batteryIsCharging ? "(+++) " : "(---)");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion battery
|
||
|
|
|
||
|
|
#region input
|
||
|
|
|
||
|
|
//this is always taking from modules, so should always apply .7 (.35*2)
|
||
|
|
inputVoltage = GetInputVoltageTBCommand(true);
|
||
|
|
inputVoltage = Math.Round(inputVoltage, 2);
|
||
|
|
if (noBattery)
|
||
|
|
{
|
||
|
|
inputVoltageStatusColor = ConvertG5InputVoltage2Color(inputVoltage);
|
||
|
|
inputVoltageStatus = ConvertStatusColor2Status(inputVoltageStatusColor);
|
||
|
|
statusDisplayInput = inputVoltage.ToString(CultureInfo.InvariantCulture) + " V";
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (batteryVoltage < MinimumValidBatteryVoltage ||
|
||
|
|
batteryVoltage > MaximumValidBatteryVoltage)
|
||
|
|
{
|
||
|
|
inputVoltageStatusColor = ConvertG5InputVoltage2Color(inputVoltage);
|
||
|
|
statusDisplayInput = $"{inputVoltage.ToString("N2")}V";
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
inputVoltageStatusColor = inputVoltage >= InputHighVoltage
|
||
|
|
? DFConstantsAndEnums.VoltageStatusColor.Green
|
||
|
|
: (InputMediumVoltage <= inputVoltage && inputVoltage < InputHighVoltage)
|
||
|
|
? DFConstantsAndEnums.VoltageStatusColor.Yellow
|
||
|
|
: DFConstantsAndEnums.VoltageStatusColor.Red;
|
||
|
|
inputVoltageStatus = batteryIsCharging
|
||
|
|
? ConvertStatusColor2Status(inputVoltageStatusColor)
|
||
|
|
: TestAll.VoltageStatus.Low.ToString();
|
||
|
|
statusDisplayInput = InputMediumVoltage <= inputVoltage
|
||
|
|
? inputVoltage.ToString(CultureInfo.InvariantCulture) + " V"
|
||
|
|
: inputVoltageStatus;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
#endregion input
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion G5
|
||
|
|
|
||
|
|
#region RACK
|
||
|
|
|
||
|
|
else
|
||
|
|
{
|
||
|
|
#region Test All command
|
||
|
|
|
||
|
|
var ta = new TestAll(this);
|
||
|
|
ta.SyncExecute();
|
||
|
|
|
||
|
|
#endregion Test All command
|
||
|
|
|
||
|
|
#region result processing
|
||
|
|
|
||
|
|
var batteryVoltsResult = GetInputVoltageTBCommand(false);
|
||
|
|
//per 8872 Low voltage reported on TDAS PRO systems is incorrect (and xlsx attached to issue)
|
||
|
|
// 18737 Above max voltage on TDAS does not warn user
|
||
|
|
// 18739 UI incorrect on TDAS when voltage below min
|
||
|
|
var rackInputVoltage = batteryVoltsResult;
|
||
|
|
if (rackInputVoltage > MaximumValidInputVoltage)
|
||
|
|
{
|
||
|
|
inputMilliVolts = rackInputVoltage * 1000;
|
||
|
|
inputVoltage = rackInputVoltage;
|
||
|
|
inputVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Off;
|
||
|
|
batteryMilliVolts = double.NaN;
|
||
|
|
batteryVoltage = double.NaN;
|
||
|
|
batteryVoltageStatus = string.Empty;
|
||
|
|
batteryIsCharging = false;
|
||
|
|
batteryVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Off;
|
||
|
|
statusDisplayInput = "---";
|
||
|
|
statusDisplayBattery = "---";
|
||
|
|
}
|
||
|
|
else if (rackInputVoltage > InputHighVoltage)
|
||
|
|
{
|
||
|
|
inputMilliVolts = rackInputVoltage * 1000;
|
||
|
|
inputVoltage = rackInputVoltage;
|
||
|
|
inputVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Green;
|
||
|
|
batteryMilliVolts = double.NaN;
|
||
|
|
batteryVoltage = double.NaN;
|
||
|
|
batteryVoltageStatus = string.Empty;
|
||
|
|
batteryIsCharging = false;
|
||
|
|
batteryVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Green;
|
||
|
|
statusDisplayInput = string.Format("{0}V", rackInputVoltage.ToString("N1"));
|
||
|
|
statusDisplayBattery = "Charging";
|
||
|
|
}
|
||
|
|
else if (rackInputVoltage > InputMediumVoltage)
|
||
|
|
{
|
||
|
|
inputMilliVolts = rackInputVoltage * 1000;
|
||
|
|
inputVoltage = rackInputVoltage;
|
||
|
|
inputVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Red;
|
||
|
|
batteryMilliVolts = double.NaN;
|
||
|
|
batteryVoltage = double.NaN;
|
||
|
|
batteryVoltageStatus = string.Empty;
|
||
|
|
batteryIsCharging = false;
|
||
|
|
batteryVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Green;
|
||
|
|
statusDisplayInput = "Low";
|
||
|
|
statusDisplayBattery = string.Format("{0}V", rackInputVoltage.ToString("N1"));
|
||
|
|
}
|
||
|
|
else if (rackInputVoltage > InputLowVoltage)
|
||
|
|
{
|
||
|
|
inputMilliVolts = rackInputVoltage * 1000;
|
||
|
|
inputVoltage = rackInputVoltage;
|
||
|
|
inputVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Red;
|
||
|
|
batteryMilliVolts = double.NaN;
|
||
|
|
batteryVoltage = double.NaN;
|
||
|
|
batteryVoltageStatus = string.Empty;
|
||
|
|
batteryIsCharging = false;
|
||
|
|
batteryVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Yellow;
|
||
|
|
statusDisplayInput = "Low";
|
||
|
|
statusDisplayBattery = string.Format("{0}V", rackInputVoltage.ToString("N1"));
|
||
|
|
}
|
||
|
|
else if (rackInputVoltage > MinimumValidInputVoltage)
|
||
|
|
{
|
||
|
|
inputMilliVolts = rackInputVoltage * 1000;
|
||
|
|
inputVoltage = rackInputVoltage;
|
||
|
|
inputVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Red;
|
||
|
|
batteryMilliVolts = double.NaN;
|
||
|
|
batteryVoltage = double.NaN;
|
||
|
|
batteryVoltageStatus = string.Empty;
|
||
|
|
batteryIsCharging = false;
|
||
|
|
batteryVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Red;
|
||
|
|
statusDisplayInput = "Low";
|
||
|
|
statusDisplayBattery = string.Format("{0}V", rackInputVoltage.ToString("N1"));
|
||
|
|
}
|
||
|
|
else //below minimum valid input voltage
|
||
|
|
{
|
||
|
|
inputMilliVolts = rackInputVoltage * 1000;
|
||
|
|
inputVoltage = rackInputVoltage;
|
||
|
|
inputVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Off;
|
||
|
|
batteryMilliVolts = double.NaN;
|
||
|
|
batteryVoltage = double.NaN;
|
||
|
|
batteryIsCharging = false;
|
||
|
|
batteryVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Off;
|
||
|
|
statusDisplayInput = "---";
|
||
|
|
statusDisplayBattery = "---";
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion RACK
|
||
|
|
|
||
|
|
BaseInput = new BaseInputValues
|
||
|
|
{
|
||
|
|
InputMilliVolts = inputMilliVolts,
|
||
|
|
MinimumValidInputVoltage = MinimumValidInputVoltage,
|
||
|
|
MaximumValidInputVoltage = MaximumValidInputVoltage,
|
||
|
|
InputVoltageStatus = inputVoltageStatus,
|
||
|
|
InputVoltageStatusColor = inputVoltageStatusColor,
|
||
|
|
StatusDisplayInput = statusDisplayInput,
|
||
|
|
|
||
|
|
BatteryMilliVolts = batteryMilliVolts,
|
||
|
|
MinimumValidBatteryVoltage = MinimumValidBatteryVoltage,
|
||
|
|
MaximumValidBatteryVoltage = MaximumValidBatteryVoltage,
|
||
|
|
BatteryIsCharging = batteryIsCharging,
|
||
|
|
BatteryVoltageStatus = batteryVoltageStatus,
|
||
|
|
BatteryVoltageStatusColor = batteryVoltageStatusColor,
|
||
|
|
StatusDisplayBattery = statusDisplayBattery
|
||
|
|
};
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
packet?.Error(ex.Message);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
packet?.Success();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Convert unit reported color code to Voltage Status Color
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="color">Color code reported by unit</param>
|
||
|
|
/// <returns>Voltage Status Color</returns>
|
||
|
|
private string ConvertStatusColor2Status(DFConstantsAndEnums.VoltageStatusColor color)
|
||
|
|
{
|
||
|
|
switch (color)
|
||
|
|
{
|
||
|
|
case DFConstantsAndEnums.VoltageStatusColor.Green: return TestAll.VoltageStatus.High.ToString();
|
||
|
|
case DFConstantsAndEnums.VoltageStatusColor.Yellow: return TestAll.VoltageStatus.Medium.ToString();
|
||
|
|
case DFConstantsAndEnums.VoltageStatusColor.Red: return TestAll.VoltageStatus.Low.ToString();
|
||
|
|
default: return TestAll.VoltageStatus.None.ToString();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#region G5 functions
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Returns converted color code (G5 specific)
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="color">Color code for BatteryChargeStates</param>
|
||
|
|
/// <returns>TestAll.VoltageStatusColor</returns>
|
||
|
|
private DFConstantsAndEnums.VoltageStatusColor G5ConvertBatteryLevel2Color(G5DockStat.BatteryChargeStates color)
|
||
|
|
{
|
||
|
|
switch (color)
|
||
|
|
{
|
||
|
|
case G5DockStat.BatteryChargeStates.red: return DFConstantsAndEnums.VoltageStatusColor.Red;
|
||
|
|
case G5DockStat.BatteryChargeStates.yellow: return DFConstantsAndEnums.VoltageStatusColor.Yellow;
|
||
|
|
case G5DockStat.BatteryChargeStates.green: return DFConstantsAndEnums.VoltageStatusColor.Green;
|
||
|
|
default: return DFConstantsAndEnums.VoltageStatusColor.Off;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Returns converted color code (G5 specific)
|
||
|
|
/// 18741: Minimum & under (gray) < InputLow (red) < Input Medium (yellow) < InputHigh (green) < Maximum & over (gray)
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="voltage">input voltage</param>
|
||
|
|
/// <returns>Voltage Status Color</returns>
|
||
|
|
private DFConstantsAndEnums.VoltageStatusColor ConvertG5InputVoltage2Color(double voltage)
|
||
|
|
{
|
||
|
|
if (voltage >= InputMediumVoltage)
|
||
|
|
{
|
||
|
|
return voltage > MaximumValidInputVoltage ? DFConstantsAndEnums.VoltageStatusColor.Off : DFConstantsAndEnums.VoltageStatusColor.Green;
|
||
|
|
}
|
||
|
|
return voltage > InputLowVoltage ? DFConstantsAndEnums.VoltageStatusColor.Yellow : voltage > MinimumValidInputVoltage ? DFConstantsAndEnums.VoltageStatusColor.Red : DFConstantsAndEnums.VoltageStatusColor.Off;
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion G5 functions
|
||
|
|
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Uses 1000S to determine INPUT voltage
|
||
|
|
/// </summary>
|
||
|
|
/// <returns>lowest battery voltage</returns>
|
||
|
|
private double GetInputVoltageTBCommand(bool isG5)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var qm = new QueryModules(this);
|
||
|
|
qm.SyncExecute();
|
||
|
|
if (isG5)
|
||
|
|
{
|
||
|
|
//offset is .35*2 for G5
|
||
|
|
return (qm.ModuleInputPowers.Min() + .7D);
|
||
|
|
}
|
||
|
|
//offset/diode drop is .8 for TDAS.
|
||
|
|
return (qm.ModuleInputPowers.Min() + .8D);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
APILogger.Log(ex);
|
||
|
|
return double.NaN;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|