1402 lines
45 KiB
C#
1402 lines
45 KiB
C#
// UNCLASSIFIED
|
|
/*-------------------------------------------------------------------------
|
|
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
|
|
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
|
|
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
|
|
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
|
|
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
|
|
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
|
|
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
|
|
COMPANY.
|
|
|
|
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
|
|
GOVERNMENT.
|
|
|
|
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
|
-------------------------------------------------------------------------*/
|
|
|
|
using NLog;
|
|
using Raytheon.Common;
|
|
using Raytheon.Instruments;
|
|
using Raytheon.Instruments.Dmm;
|
|
using Raytheon.Units;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
|
|
namespace MeasurementManagerLib
|
|
{
|
|
/// <summary>
|
|
/// The interface to the instruments contained in the vsu test station.
|
|
/// This class reads in test station configuration ini file that contains:
|
|
/// - DMM measurement definitions
|
|
/// The host of this class can invoke those measurements by commanding the this class with the ini file string names
|
|
/// which insulates the caller from having to know the details of that measurement
|
|
/// </summary>
|
|
public class SwitchMeasurementManager : IDisposable
|
|
{
|
|
#region PublicMembers
|
|
|
|
/// <summary>
|
|
/// Type of DMM Resistance Measurements
|
|
/// </summary>
|
|
public enum DMMResistanceType
|
|
{
|
|
TWO,
|
|
FOUR,
|
|
};
|
|
|
|
public enum DMMVoltageType
|
|
{
|
|
DC,
|
|
AC,
|
|
};
|
|
|
|
public delegate void SwitchMeasurementDelegate();
|
|
|
|
/// <summary>
|
|
/// Struct for holding on to DMM measurement definitions
|
|
/// </summary>
|
|
public struct DMMFrequencyMeasurementFields
|
|
{
|
|
public readonly double _range;
|
|
public readonly double _resolution;
|
|
public readonly double _scaleFactor;
|
|
public readonly int _delay;
|
|
public List<string> _relays;
|
|
public readonly double _voltRange;
|
|
public readonly double _numReads;
|
|
|
|
public DMMFrequencyMeasurementFields(double range, double resolution, int delay, double scaleFactor, List<string> relays, double voltRange, double numReads)
|
|
{
|
|
_range = range;
|
|
_resolution = resolution;
|
|
_delay = delay;
|
|
_scaleFactor = scaleFactor;
|
|
_relays = relays;
|
|
_voltRange = voltRange;
|
|
_numReads = numReads;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Struct for holding on to DMM measurement definitions
|
|
/// </summary>
|
|
public struct DMMVoltageMeasurementFields
|
|
{
|
|
public readonly double _range;
|
|
public readonly double _resolution;
|
|
public readonly double _scaleFactor;
|
|
public readonly int _delay;
|
|
public List<string> _relays;
|
|
public DMMVoltageType _voltageType;
|
|
|
|
public DMMVoltageMeasurementFields(double range, double resolution, int delay, double scaleFactor, List<string> relays, DMMVoltageType voltageType)
|
|
{
|
|
_range = range;
|
|
_resolution = resolution;
|
|
_delay = delay;
|
|
_scaleFactor = scaleFactor;
|
|
_relays = relays;
|
|
_voltageType = voltageType;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Struct for holding on to DMM measurement definitions
|
|
/// </summary>
|
|
public struct DMMResistanceMeasurementFields
|
|
{
|
|
public readonly string _pcode;
|
|
public readonly double _range;
|
|
public readonly double _resolution;
|
|
public readonly double _scaleFactor;
|
|
public readonly int _delay;
|
|
public List<string> _relays;
|
|
public DMMResistanceType _dmmResistanceType;
|
|
public readonly string _cableAndPinId;
|
|
public readonly double _lowerLimit;
|
|
public readonly double _upperLimit;
|
|
|
|
public DMMResistanceMeasurementFields(string pcode, double range, double resolution, int delay, double scaleFactor, List<string> relays, DMMResistanceType type, string cableAndPinId, double lowerLimit, double upperLimit)
|
|
{
|
|
_pcode = pcode;
|
|
_range = range;
|
|
_resolution = resolution;
|
|
_delay = delay;
|
|
_scaleFactor = scaleFactor;
|
|
_relays = relays;
|
|
_dmmResistanceType = type;
|
|
_cableAndPinId = cableAndPinId;
|
|
_lowerLimit = lowerLimit;
|
|
_upperLimit = upperLimit;
|
|
}
|
|
}
|
|
|
|
public struct SwitchMeasurementFields
|
|
{
|
|
public List<string> _relays;
|
|
|
|
public SwitchMeasurementFields(List<string> relays)
|
|
{
|
|
_relays = relays;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// State for a trigger edge.
|
|
/// </summary>
|
|
public enum ScopeEdge
|
|
{
|
|
FALLING = 0,
|
|
RISING,
|
|
HOLDING
|
|
};
|
|
|
|
public readonly struct ScopePulseWidthMeasurementFields
|
|
{
|
|
public readonly List<string> _relays;
|
|
public readonly int _channelNumber;
|
|
public readonly ScopeEdge _edge;
|
|
public readonly double _timePerDivision;
|
|
public readonly double _timeOffset;
|
|
public readonly double _triggerLevel;
|
|
public readonly double _voltageOffset;
|
|
public readonly double _voltageScale;
|
|
public readonly string _inputImpedance;
|
|
//public readonly double m_measurementTime;
|
|
public readonly int _delay;
|
|
public readonly bool _shallWeSaveImage;
|
|
public readonly int _maxTriggerWaitTime;
|
|
|
|
public ScopePulseWidthMeasurementFields(List<string> relays, int channelNumber, ScopeEdge edge, double timePerDivision, double timeOffset, double triggerLevel, double voltageOffset, double voltageScale, string inputImpedance, int delay, bool shallWeSaveImage, int maxTriggerWaitTime)
|
|
{
|
|
_relays = relays;
|
|
_channelNumber = channelNumber;
|
|
_edge = edge;
|
|
_inputImpedance = inputImpedance;
|
|
_timePerDivision = timePerDivision;
|
|
_timeOffset = timeOffset;
|
|
_triggerLevel = triggerLevel;
|
|
_voltageOffset = voltageOffset;
|
|
_voltageScale = voltageScale;
|
|
_delay = delay;
|
|
_shallWeSaveImage = shallWeSaveImage;
|
|
_maxTriggerWaitTime = maxTriggerWaitTime;
|
|
}
|
|
}
|
|
|
|
public readonly struct ScopeFrequencyMeasurementFields
|
|
{
|
|
public readonly List<string> _relays;
|
|
public readonly int _channelNumber;
|
|
public readonly ScopeEdge _edge;
|
|
public readonly double _timePerDivision;
|
|
public readonly double _timeOffset;
|
|
public readonly double _triggerLevel;
|
|
public readonly double _voltageOffset;
|
|
public readonly double _voltageScale;
|
|
public readonly string _inputImpedance;
|
|
//public readonly double m_measurementTime;
|
|
public readonly int _delay;
|
|
public readonly bool _shallWeSaveImage;
|
|
public readonly int _maxTriggerWaitTime;
|
|
|
|
public ScopeFrequencyMeasurementFields(List<string> relays, int channelNumber, ScopeEdge edge, double timePerDivision, double timeOffset, double triggerLevel, double voltageOffset, double voltageScale, string inputImpedance, int delay, bool shallWeSaveImage, int maxTriggerWaitTime)
|
|
{
|
|
_relays = relays;
|
|
_channelNumber = channelNumber;
|
|
_edge = edge;
|
|
_inputImpedance = inputImpedance;
|
|
_timePerDivision = timePerDivision;
|
|
_timeOffset = timeOffset;
|
|
_triggerLevel = triggerLevel;
|
|
_voltageOffset = voltageOffset;
|
|
_voltageScale = voltageScale;
|
|
_delay = delay;
|
|
_shallWeSaveImage = shallWeSaveImage;
|
|
_maxTriggerWaitTime = maxTriggerWaitTime;
|
|
}
|
|
}
|
|
|
|
//public Dictionary<string, DMMFrequencyMeasurementFields> _dmmFrequencyMeasurements = new Dictionary<string, DMMFrequencyMeasurementFields>(StringComparer.InvariantCultureIgnoreCase);
|
|
public Dictionary<string, DMMFrequencyMeasurementFields> DmmFrequencyMeasurements
|
|
{
|
|
get { return _dmmFrequencyMeasurements; }
|
|
set { _dmmFrequencyMeasurements = value; CheckForDmmFrequencyConfigValidity(); }
|
|
}
|
|
public Dictionary<string, DMMResistanceMeasurementFields> DmmResistanceMeasurements
|
|
{
|
|
get { return _dmmResistanceMeasurements; }
|
|
set { _dmmResistanceMeasurements = value; CheckForDmmResistanceConfigValidity(); }
|
|
}
|
|
public Dictionary<string, DMMVoltageMeasurementFields> DmmVoltageMeasurements
|
|
{
|
|
get { return _dmmVoltageMeasurements; }
|
|
set { _dmmVoltageMeasurements = value; CheckForDmmVoltageConfigValidity(); }
|
|
}
|
|
public Dictionary<string, SwitchMeasurementFields> SwitchMeasurements { get; set; }
|
|
public Dictionary<string, ScopeFrequencyMeasurementFields> ScopeFreqMeasurements
|
|
{
|
|
get { return _scopeFreqMeasurements; }
|
|
set { _scopeFreqMeasurements = value; CheckForScopeFrequencyConfigValidity(); }
|
|
}
|
|
public Dictionary<string, ScopePulseWidthMeasurementFields> ScopePulseWidthMeasurements
|
|
{
|
|
get { return _scopePulseWidthMeasurements; }
|
|
set { _scopePulseWidthMeasurements = value; CheckForScopePulseWidthConfigValidity(); }
|
|
}
|
|
public List<string> RelayExclusionList { get; set; }
|
|
|
|
#endregion
|
|
|
|
|
|
#region PrivateClassMembers
|
|
/// <summary>
|
|
/// private class members
|
|
/// </summary>
|
|
private readonly IDmm _dmm;
|
|
private readonly IOscilloScope _scope;
|
|
|
|
private readonly Dictionary<string, ISwitch> _switchCards;
|
|
|
|
private static readonly object _syncObj = new Object();
|
|
|
|
private static NLog.ILogger _logger;
|
|
|
|
private Dictionary<string, DMMResistanceMeasurementFields> _dmmResistanceMeasurements;
|
|
private Dictionary<string, DMMFrequencyMeasurementFields> _dmmFrequencyMeasurements;
|
|
private Dictionary<string, DMMVoltageMeasurementFields> _dmmVoltageMeasurements;
|
|
private Dictionary<string, ScopeFrequencyMeasurementFields> _scopeFreqMeasurements;
|
|
private Dictionary<string, ScopePulseWidthMeasurementFields> _scopePulseWidthMeasurements;
|
|
|
|
#endregion
|
|
|
|
|
|
#region PrivateFunctions
|
|
|
|
/// <summary>
|
|
/// The Finalizer
|
|
/// </summary>
|
|
~SwitchMeasurementManager()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check configuration information is correct
|
|
/// </summary>
|
|
private void CheckForDmmResistanceConfigValidity()
|
|
{
|
|
foreach (KeyValuePair<string, DMMResistanceMeasurementFields> entry in DmmResistanceMeasurements)
|
|
{
|
|
List<string> relays = entry.Value._relays;
|
|
|
|
foreach (string relayDef in relays)
|
|
{
|
|
string[] relayInfo = relayDef.Split('-');
|
|
if (relayInfo.Length != 2)
|
|
{
|
|
throw new Exception("Dmm resistance measurement relay format is not correct: " + relayDef);
|
|
}
|
|
|
|
if (_switchCards.ContainsKey(relayInfo[0].ToUpper()) == false)
|
|
{
|
|
throw new Exception("Dmm resistance measurement relay card field does not exist: " + relayInfo[0]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check configuration information is correct
|
|
/// </summary>
|
|
private void CheckForDmmFrequencyConfigValidity()
|
|
{
|
|
foreach (KeyValuePair<string, DMMFrequencyMeasurementFields> entry in DmmFrequencyMeasurements)
|
|
{
|
|
List<string> relays = entry.Value._relays;
|
|
|
|
foreach (string relayDef in relays)
|
|
{
|
|
string[] relayInfo = relayDef.Split('-');
|
|
if (relayInfo.Length != 2)
|
|
{
|
|
throw new Exception("Dmm frequency measurement relay format is not correct: " + relayDef);
|
|
}
|
|
|
|
if (_switchCards.ContainsKey(relayInfo[0].ToUpper()) == false)
|
|
{
|
|
throw new Exception("Dmm frequency measurement relay card field does not exist: " + relayInfo[0]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check configuration information is correct
|
|
/// </summary>
|
|
private void CheckForDmmVoltageConfigValidity()
|
|
{
|
|
foreach (KeyValuePair<string, DMMVoltageMeasurementFields> entry in DmmVoltageMeasurements)
|
|
{
|
|
List<string> relays = entry.Value._relays;
|
|
|
|
foreach (string relayDef in relays)
|
|
{
|
|
string[] relayInfo = relayDef.Split('-');
|
|
if (relayInfo.Length != 2)
|
|
{
|
|
throw new Exception("Dmm voltage measurement relay format is not correct: " + relayDef);
|
|
}
|
|
|
|
if (_switchCards.ContainsKey(relayInfo[0].ToUpper()) == false)
|
|
{
|
|
throw new Exception("Dmm voltage measurement relay card field does not exist: " + relayInfo[0]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check configuration information is correct
|
|
/// </summary>
|
|
private void CheckForScopeFrequencyConfigValidity()
|
|
{
|
|
foreach (KeyValuePair<string, ScopeFrequencyMeasurementFields> entry in ScopeFreqMeasurements)
|
|
{
|
|
List<string> relays = entry.Value._relays;
|
|
|
|
foreach (string relayDef in relays)
|
|
{
|
|
string[] relayInfo = relayDef.Split('-');
|
|
if (relayInfo.Length != 2)
|
|
{
|
|
throw new Exception("Scope frequency measurement relay format is not correct: " + relayDef);
|
|
}
|
|
|
|
if (_switchCards.ContainsKey(relayInfo[0].ToUpper()) == false)
|
|
{
|
|
throw new Exception("Scope frequency measurement relay card field does not exist: " + relayInfo[0]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check configuration information is correct
|
|
/// </summary>
|
|
private void CheckForScopePulseWidthConfigValidity()
|
|
{
|
|
foreach (KeyValuePair<string, ScopePulseWidthMeasurementFields> entry in ScopePulseWidthMeasurements)
|
|
{
|
|
List<string> relays = entry.Value._relays;
|
|
|
|
foreach (string relayDef in relays)
|
|
{
|
|
string[] relayInfo = relayDef.Split('-');
|
|
if (relayInfo.Length != 2)
|
|
{
|
|
throw new Exception("Scope pulse width measurement relay format is not correct: " + relayDef);
|
|
}
|
|
|
|
if (_switchCards.ContainsKey(relayInfo[0].ToUpper()) == false)
|
|
{
|
|
throw new Exception("Scope pulse width measurement relay card field does not exist: " + relayInfo[0]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check a list of relays against a list of not allowed relays
|
|
/// </summary>
|
|
/// <param name="relaysToCheck"></param>
|
|
/// <returns>True if everything is good and checks out, false if relaysToCheck contains a relay on the not allowed list</returns>
|
|
private bool CheckRelayVerificationList(List<string> relaysToCheck)
|
|
{
|
|
for (int i = 0; i < relaysToCheck.Count; i++)
|
|
{
|
|
string relayToCheck = relaysToCheck[i];
|
|
|
|
for (int j = 0; j < RelayExclusionList.Count; j++)
|
|
{
|
|
string notAllowedRelay = RelayExclusionList[j];
|
|
|
|
if (relayToCheck.ToUpper() == notAllowedRelay.ToUpper())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="measurementName"></param>
|
|
/// <param name="measurementRelays"></param>
|
|
/// <param name="measurement"></param>
|
|
/// <param name="type"></param>
|
|
/// <param name="delayAfterClosingRelay"></param>
|
|
private void ConfigureDmmSettingsAndCloseAnyRelays(string measurementName, out List<string> measurementRelays, out DMMResistanceMeasurementFields measurement, out MeasurementFunction type, bool delayAfterClosingRelay = true)
|
|
{
|
|
if (DmmResistanceMeasurements.ContainsKey(measurementName.ToUpper()) == false)
|
|
{
|
|
throw new Exception("could not find measurement: " + measurementName);
|
|
}
|
|
|
|
measurement = DmmResistanceMeasurements[measurementName.ToUpper()];
|
|
measurementRelays = measurement._relays;
|
|
|
|
byte desiredMeasurementType = (byte)measurement._dmmResistanceType;
|
|
|
|
SwitchRelayClose(measurementRelays);
|
|
|
|
if (delayAfterClosingRelay)
|
|
{
|
|
Thread.Sleep(measurement._delay);
|
|
}
|
|
|
|
type = Raytheon.Instruments.Dmm.MeasurementFunction.TwoWireResistance;
|
|
if (measurement._dmmResistanceType == DMMResistanceType.TWO)
|
|
{
|
|
type = Raytheon.Instruments.Dmm.MeasurementFunction.TwoWireResistance;
|
|
}
|
|
else if (measurement._dmmResistanceType == DMMResistanceType.FOUR)
|
|
{
|
|
type = Raytheon.Instruments.Dmm.MeasurementFunction.FourWireResistance;
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("unknown resistance type: " + measurement._dmmResistanceType.ToString());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dispose of this objects resources
|
|
/// </summary>
|
|
/// <param name="disposing"></param>
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
if (_dmm != null)
|
|
{
|
|
try
|
|
{
|
|
_dmm.Shutdown();
|
|
}
|
|
catch (Exception err)
|
|
{
|
|
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
|
}
|
|
}
|
|
|
|
if (_switchCards != null)
|
|
{
|
|
foreach (KeyValuePair<string, ISwitch> switchCard in _switchCards)
|
|
{
|
|
try
|
|
{
|
|
if (_switchCards[switchCard.Key] != null)
|
|
{
|
|
_switchCards[switchCard.Key].Shutdown();
|
|
}
|
|
}
|
|
catch (Exception err)
|
|
{
|
|
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_scope != null)
|
|
{
|
|
try
|
|
{
|
|
_scope.Shutdown();
|
|
}
|
|
catch (Exception err)
|
|
{
|
|
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
ErrorLogger.Instance().Dispose();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// nothing to do
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Will command the switch cards close a specified list of relays
|
|
/// </summary>
|
|
/// <param name="relayList"></param>
|
|
private void SwitchRelayClose(List<string> relayList)
|
|
{
|
|
// open all relays on the switch. Just extra layer of protection so we don't short out the relays
|
|
SwitchRelayOpenAll();
|
|
Thread.Sleep(10);
|
|
|
|
// verify none of the relays are on the exclusion list
|
|
bool areRelaysOk = CheckRelayVerificationList(relayList);
|
|
|
|
if (areRelaysOk == false)
|
|
{
|
|
throw new Exception("Commanded relay is not allowed");
|
|
}
|
|
|
|
foreach (string combo in relayList)
|
|
{
|
|
//break out the card and relay
|
|
string[] cardRelay = combo.Split('-');
|
|
string cardObject = cardRelay[0].Trim();
|
|
string relay = cardRelay[1].Trim();
|
|
|
|
//close the relays
|
|
_switchCards[cardObject.ToUpper()].Connect(relay);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Will command the switch card open all relays or the specified list of relays
|
|
/// </summary>
|
|
/// <param name="relayList">Optional list of relays to open</param>
|
|
private void SwitchRelayOpen(List<string> relayList)
|
|
{
|
|
foreach (string combo in relayList)
|
|
{
|
|
//break out the card and relay
|
|
string[] cardRelay = combo.Split('-');
|
|
string cardObject = cardRelay[0].Trim();
|
|
string relay = cardRelay[1].Trim();
|
|
|
|
//open the relays
|
|
_switchCards[cardObject.ToUpper()].Disconnect(relay);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Opens all relays on all switch cards
|
|
/// </summary>
|
|
private void SwitchRelayOpenAll()
|
|
{
|
|
foreach (KeyValuePair<string, ISwitch> switchCard in _switchCards)
|
|
{
|
|
_switchCards[switchCard.Key].DisconnectAll();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PublicFunctions
|
|
|
|
/// <summary>
|
|
/// constructor that uses instrument manager for creating an instrument
|
|
/// </summary>
|
|
/// <param name="instrumentManager"></param>
|
|
/// <param name="switchCardNames"></param>
|
|
/// <param name="dmmName"></param>
|
|
/// <param name="scopeName"></param>
|
|
/// <param name="logFileName"></param>
|
|
public SwitchMeasurementManager(IInstrumentManager instrumentManager)
|
|
{
|
|
_logger = LogManager.GetCurrentClassLogger();
|
|
|
|
_switchCards = new Dictionary<string, ISwitch>();
|
|
|
|
ICollection<object> switchCardList = instrumentManager.GetInstruments(typeof(ISwitch));
|
|
foreach (ISwitch switchCard in switchCardList)
|
|
{
|
|
_switchCards[switchCard.Name] = switchCard;
|
|
_switchCards[switchCard.Name]?.Initialize();
|
|
}
|
|
|
|
ICollection<object> dmmList = instrumentManager.GetInstruments(typeof(IDmm));
|
|
if (dmmList.Count > 0)
|
|
{
|
|
_dmm = (IDmm)dmmList.First();
|
|
_dmm.Initialize();
|
|
}
|
|
|
|
ICollection<object> scopeList = instrumentManager.GetInstruments(typeof(IOscilloScope));
|
|
if (scopeList.Count > 0)
|
|
{
|
|
_scope = (IOscilloScope)dmmList.First();
|
|
_scope.Initialize();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dispose of this objects resources
|
|
/// </summary>
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")]
|
|
public void Dispose()
|
|
{
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
Dispose(true);
|
|
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|
|
catch (Exception err)
|
|
{
|
|
try
|
|
{
|
|
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
//Do not rethrow. Exception from error logger that has already been garbage collected
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A getter for the list of frequency measurements (as defined in the input def file)
|
|
/// </summary>
|
|
/// <returns>A list of frequency measurements</returns>
|
|
public List<string> DmmGetFrequencyMeasurementList()
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
List<string> measurements = new List<string>();
|
|
|
|
foreach (KeyValuePair<string, DMMFrequencyMeasurementFields> entry in DmmFrequencyMeasurements)
|
|
{
|
|
measurements.Add(entry.Key);
|
|
}
|
|
|
|
return measurements;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A getter for the list of resistance measurements (as defined in the input def file)
|
|
/// </summary>
|
|
/// <returns>A list of resistance measurements</returns>
|
|
public List<string> DmmGetResistanceMeasurementList()
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
List<string> measurements = new List<string>();
|
|
|
|
foreach (KeyValuePair<string, DMMResistanceMeasurementFields> entry in DmmResistanceMeasurements)
|
|
{
|
|
measurements.Add(entry.Key);
|
|
}
|
|
|
|
return measurements;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make a DMM frequency measurement
|
|
/// </summary>
|
|
/// <param name="measurementName">frequency measurement to make (the name from the input def file)</param>
|
|
/// <returns>The measured frequency</returns>
|
|
public double DmmReadFrequency(string measurementName)
|
|
{
|
|
// hold onto the relays for the catch
|
|
List<string> measurementRelays = null;
|
|
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (DmmFrequencyMeasurements.ContainsKey(measurementName.ToUpper()) == false)
|
|
{
|
|
throw new Exception("could not find measurement: " + measurementName);
|
|
}
|
|
|
|
// grab the measurement params
|
|
DMMFrequencyMeasurementFields measurement = DmmFrequencyMeasurements[measurementName.ToUpper()];
|
|
|
|
measurementRelays = measurement._relays;
|
|
|
|
// close the relays
|
|
SwitchRelayClose(measurementRelays);
|
|
|
|
// wait a bit
|
|
Thread.Sleep(measurement._delay);
|
|
|
|
// make the measurement
|
|
_dmm.ConfigureFrequencyMeasurement(Raytheon.Instruments.Dmm.MeasurementFunction.Frequency, Frequency.FromHertz(measurement._voltRange), Frequency.FromHertz(measurement._resolution));
|
|
|
|
double returnValue = _dmm.MeasureFrequency(100).Hertz;
|
|
|
|
// Multiply by the scale factor
|
|
returnValue = returnValue * measurement._scaleFactor;
|
|
|
|
// return the measurement
|
|
return returnValue;
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// open the relays
|
|
if (measurementRelays != null)
|
|
{
|
|
SwitchRelayOpen(measurementRelays);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make a DMM resistance measurement
|
|
/// </summary>
|
|
/// <param name="measurementName">The resistance measurement to make (the name from the input def file)</param>
|
|
/// <returns>The measured resistance</returns>
|
|
public double DmmReadResistance(string measurementName)
|
|
{
|
|
// hold onto the relays for the catch
|
|
List<string> measurementRelays = null;
|
|
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
ConfigureDmmSettingsAndCloseAnyRelays(measurementName, out measurementRelays, out DMMResistanceMeasurementFields measurement, out MeasurementFunction type);
|
|
|
|
// make the measurement
|
|
_dmm.ConfigureResistanceMeasurement(type, Resistance.FromOhms(measurement._range), Resistance.FromOhms(measurement._resolution));
|
|
double returnValue = _dmm.MeasureResistance(100).Ohms;
|
|
|
|
// Multiply by the scale factor
|
|
returnValue *= measurement._scaleFactor;
|
|
|
|
// return the measurement
|
|
return returnValue;
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// open the relays
|
|
if (measurementRelays != null)
|
|
{
|
|
SwitchRelayOpen(measurementRelays);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make a DMM resistance measurement up to intNumberOfReadings times or when the measurement is within percentRangeToStopInDecimal of the previous measurement
|
|
/// </summary>
|
|
/// <returns>The measured resistance</returns>
|
|
public double DmmReadResistanceAndStopReadingWithinACertainRange(string measurementName, double percentRangeToStopInDecimal, int maxNumberOfReadings = 50)
|
|
{
|
|
// hold onto the relays for the catch
|
|
List<string> measurementRelays = null;
|
|
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
ConfigureDmmSettingsAndCloseAnyRelays(measurementName, out measurementRelays, out DMMResistanceMeasurementFields measurement, out MeasurementFunction type, false);
|
|
|
|
var returnValue = 0.0;
|
|
var lastReadLess = 0.0;
|
|
var lastReadPlus = 0.0;
|
|
var numOfReadings = 0;
|
|
do
|
|
{
|
|
Thread.Sleep(measurement._delay);
|
|
lastReadLess = returnValue * (1 - percentRangeToStopInDecimal);
|
|
lastReadPlus = returnValue * (1 + percentRangeToStopInDecimal);
|
|
|
|
_dmm.ConfigureResistanceMeasurement(type, Resistance.FromOhms(measurement._range), Resistance.FromOhms(measurement._resolution));
|
|
returnValue = _dmm.MeasureResistance(100).Ohms;
|
|
numOfReadings++;
|
|
} while (!(lastReadLess <= returnValue && returnValue <= lastReadPlus) && numOfReadings < maxNumberOfReadings);
|
|
|
|
returnValue *= measurement._scaleFactor;
|
|
|
|
return returnValue;
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// open the relays
|
|
if (measurementRelays != null)
|
|
{
|
|
SwitchRelayOpen(measurementRelays);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A getter for the list of voltage measurements(as defined in the input def file)
|
|
/// </summary>
|
|
/// <returns>A list of voltage measurements</returns>
|
|
public List<string> DmmGetVoltageMeasurementList()
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
List<string> measurements = new List<string>();
|
|
|
|
foreach (KeyValuePair<string, DMMVoltageMeasurementFields> entry in DmmVoltageMeasurements)
|
|
{
|
|
measurements.Add(entry.Key);
|
|
}
|
|
|
|
return measurements;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// make a DMM voltage measurement
|
|
/// </summary>
|
|
/// <param name="measurementName">The measurement to make(the name from the input def file)</param>
|
|
/// <returns>The measured voltage</returns>
|
|
public double DmmReadVoltage(string measurementName)
|
|
{
|
|
// hold onto the relays for the catch
|
|
List<string> measurementRelays = null;
|
|
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (DmmVoltageMeasurements.ContainsKey(measurementName.ToUpper()) == false)
|
|
{
|
|
throw new Exception("could not find measurement: " + measurementName);
|
|
}
|
|
|
|
DMMVoltageMeasurementFields measurement = DmmVoltageMeasurements[measurementName.ToUpper()];
|
|
|
|
measurementRelays = measurement._relays;
|
|
|
|
//Select DMM Resistance Measurement Type
|
|
byte desiredMeasurementType = (byte)measurement._voltageType;
|
|
|
|
// close the relays
|
|
SwitchRelayClose(measurementRelays);
|
|
|
|
// wait a bit
|
|
Thread.Sleep(measurement._delay);
|
|
|
|
// make the measurement
|
|
_dmm.ConfigureVoltageMeasurement(Raytheon.Instruments.Dmm.MeasurementFunction.DCVolts, Voltage.FromVolts(measurement._range), Voltage.FromVolts(measurement._resolution));
|
|
|
|
double returnVal = _dmm.MeasureVoltage(100).Volts;
|
|
|
|
// Multiply by the scale factor
|
|
returnVal = returnVal * measurement._scaleFactor;
|
|
|
|
// return the measurement
|
|
return returnVal;
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// open the relays
|
|
if (measurementRelays != null)
|
|
{
|
|
SwitchRelayOpen(measurementRelays);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A getter for the list of scope freq measurements(as defined in the input def file)
|
|
/// </summary>
|
|
/// <returns>A list of scope freq measurements</returns>
|
|
public List<string> ScopeGetFrequencyMeasurementList()
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
List<string> measurements = new List<string>();
|
|
|
|
foreach (KeyValuePair<string, ScopeFrequencyMeasurementFields> entry in ScopeFreqMeasurements)
|
|
{
|
|
measurements.Add(entry.Key);
|
|
}
|
|
|
|
return measurements;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A getter for the list of scope freq measurements(as defined in the input def file)
|
|
/// </summary>
|
|
/// <returns>A list of scope freq measurements</returns>
|
|
public List<string> ScopeGetPulseWidthMeasurementList()
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
List<string> measurements = new List<string>();
|
|
|
|
foreach (KeyValuePair<string, ScopePulseWidthMeasurementFields> entry in ScopePulseWidthMeasurements)
|
|
{
|
|
measurements.Add(entry.Key);
|
|
}
|
|
|
|
return measurements;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make a fall time measurement with the scope
|
|
/// </summary>
|
|
/// <param name="measurementName">The measurement to make(the name from the input def file)</param>
|
|
/// <returns></returns>
|
|
public double ScopeReadFallTime(string measurementName)
|
|
{
|
|
// hold onto the relays for the catch
|
|
List<string> measurementRelays = null;
|
|
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
//@@@ port over from RKV
|
|
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// open the relays
|
|
if (measurementRelays != null)
|
|
{
|
|
SwitchRelayOpen(measurementRelays);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make a frequency measurement with the scope
|
|
/// </summary>
|
|
/// <param name="measurementName">The measurement to make(the name from the input def file)</param>
|
|
/// <returns></returns>
|
|
public double ScopeReadFrequency(string measurementName)
|
|
{
|
|
// hold onto the relays for the catch
|
|
List<string> measurementRelays = null;
|
|
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (ScopeFreqMeasurements.ContainsKey(measurementName.ToUpper()) == false)
|
|
{
|
|
throw new Exception("could not find measurement: " + measurementName);
|
|
}
|
|
|
|
ScopeFrequencyMeasurementFields measurement = ScopeFreqMeasurements[measurementName.ToUpper()];
|
|
|
|
measurementRelays = measurement._relays;
|
|
|
|
// close the relays
|
|
SwitchRelayClose(measurementRelays);
|
|
|
|
// wait a bit
|
|
Thread.Sleep(measurement._delay);
|
|
|
|
// setup channel
|
|
_scope.ConfigureChannel(measurement._channelNumber, measurement._timePerDivision, measurement._timeOffset, measurement._voltageOffset, measurement._voltageScale, measurement._inputImpedance);
|
|
|
|
//Set-up trigger
|
|
bool useRisingEdge = true;
|
|
if (measurement._edge != ScopeEdge.RISING)
|
|
{
|
|
useRisingEdge = false;
|
|
}
|
|
|
|
_scope.SetupTrigger(useRisingEdge, measurement._channelNumber, measurement._triggerLevel);
|
|
|
|
bool hasScopeTriggered = false;
|
|
|
|
// look for trigger up to the timeout time
|
|
DateTime delayEndTime = DateTime.Now.AddMilliseconds(measurement._maxTriggerWaitTime);
|
|
while (hasScopeTriggered == false && DateTime.Now < delayEndTime)
|
|
{
|
|
// wait a bit and check the trigger again
|
|
Thread.Sleep(100);
|
|
hasScopeTriggered = _scope.HasItTriggered();
|
|
}
|
|
|
|
// Check if scope is triggered.
|
|
if (hasScopeTriggered == false)
|
|
{
|
|
throw new Exception("The scope trigger operation is not completed.");
|
|
}
|
|
|
|
double freq = _scope.MeasureFrequency(measurement._channelNumber);
|
|
|
|
// save the image
|
|
if (measurement._shallWeSaveImage == true)
|
|
{
|
|
_scope.SaveImage(measurementName);
|
|
}
|
|
|
|
return freq;
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// open the relays
|
|
if (measurementRelays != null)
|
|
{
|
|
SwitchRelayOpen(measurementRelays);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make a max voltage measurement with the scope
|
|
/// </summary>
|
|
/// <param name="measurementName">The measurement to make(the name from the input def file)</param>
|
|
/// <returns></returns>
|
|
public double ScopeReadMaxVoltage(string measurementName)
|
|
{
|
|
// hold onto the relays for the catch
|
|
List<string> measurementRelays = null;
|
|
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
//@@@ port over from RKV
|
|
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// open the relays
|
|
if (measurementRelays != null)
|
|
{
|
|
SwitchRelayOpen(measurementRelays);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make a min voltage measurement with the scope
|
|
/// </summary>
|
|
/// <param name="measurementName">The measurement to make(the name from the input def file)</param>
|
|
/// <returns></returns>
|
|
public double ScopeReadMinVoltage(string measurementName)
|
|
{
|
|
// hold onto the relays for the catch
|
|
List<string> measurementRelays = null;
|
|
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
//@@@ port over from RKV
|
|
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// open the relays
|
|
if (measurementRelays != null)
|
|
{
|
|
SwitchRelayOpen(measurementRelays);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// make a pulse width measurement with the scope
|
|
/// </summary>
|
|
/// <param name="measurementName">The measurement to make(the name from the input def file)</param>
|
|
/// <returns></returns>
|
|
public double ScopeReadPulseWidth(string measurementName)
|
|
{
|
|
// hold onto the relays for the catch
|
|
List<string> measurementRelays = null;
|
|
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (ScopePulseWidthMeasurements.ContainsKey(measurementName.ToUpper()) == false)
|
|
{
|
|
throw new Exception("could not find measurement: " + measurementName);
|
|
}
|
|
|
|
ScopePulseWidthMeasurementFields measurement = ScopePulseWidthMeasurements[measurementName.ToUpper()];
|
|
|
|
measurementRelays = measurement._relays;
|
|
|
|
// close the relays
|
|
SwitchRelayClose(measurementRelays);
|
|
|
|
// wait a bit
|
|
Thread.Sleep(measurement._delay);
|
|
|
|
// setup channel
|
|
_scope.ConfigureChannel(measurement._channelNumber, measurement._timePerDivision, measurement._timeOffset, measurement._voltageOffset, measurement._voltageScale, measurement._inputImpedance);
|
|
|
|
//Set-up trigger
|
|
bool useRisingEdge = true;
|
|
if (measurement._edge != ScopeEdge.RISING)
|
|
{
|
|
useRisingEdge = false;
|
|
}
|
|
|
|
_scope.SetupTrigger(useRisingEdge, measurement._channelNumber, measurement._triggerLevel);
|
|
|
|
bool hasScopeTriggered = false;
|
|
|
|
// look for trigger up to the timeout time
|
|
DateTime delayEndTime = DateTime.Now.AddMilliseconds(measurement._maxTriggerWaitTime);
|
|
while (hasScopeTriggered == false && DateTime.Now < delayEndTime)
|
|
{
|
|
// wait a bit and check the trigger again
|
|
Thread.Sleep(100);
|
|
hasScopeTriggered = _scope.HasItTriggered();
|
|
}
|
|
|
|
// Check if scope is triggered.
|
|
if (hasScopeTriggered == false)
|
|
{
|
|
throw new Exception("The scope trigger operation is not completed.");
|
|
}
|
|
|
|
double pulseWidth = _scope.MeasurePulseWidth(measurement._channelNumber);
|
|
|
|
// save the image
|
|
if (measurement._shallWeSaveImage == true)
|
|
{
|
|
_scope.SaveImage(measurementName);
|
|
}
|
|
|
|
return pulseWidth;
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// open the relays
|
|
if (measurementRelays != null)
|
|
{
|
|
SwitchRelayOpen(measurementRelays);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make a rise time measurement with the scope
|
|
/// </summary>
|
|
/// <param name="measurementName">The measurement to make(the name from the input def file)</param>
|
|
/// <returns></returns>
|
|
public double ScopeReadRiseTime(string measurementName)
|
|
{
|
|
// hold onto the relays for the catch
|
|
List<string> measurementRelays = null;
|
|
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
//@@@ port over from RKV
|
|
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// open the relays
|
|
if (measurementRelays != null)
|
|
{
|
|
SwitchRelayOpen(measurementRelays);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make a voltage level measurement with the scope
|
|
/// </summary>
|
|
/// <param name="measurementName">The measurement to make(the name from the input def file)</param>
|
|
/// <returns></returns>
|
|
public double ScopeReadVoltageLevel(string measurementName)
|
|
{
|
|
// hold onto the relays for the catch
|
|
List<string> measurementRelays = null;
|
|
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
//@@@ port over from RKV
|
|
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// open the relays
|
|
if (measurementRelays != null)
|
|
{
|
|
SwitchRelayOpen(measurementRelays);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public void ScopeSelfTest()
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
SelfTestResult res = _scope.PerformSelfTest();
|
|
|
|
if (res != SelfTestResult.Pass)
|
|
{
|
|
throw new Exception("did not pass, the result was: " + res.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends a SCPI command to the scope and reads the response
|
|
/// </summary>
|
|
/// <param name="command">The SCPI command to send</param>
|
|
/// <returns></returns>
|
|
public string ScopeIOQuery(string command)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
return _scope.IOQuery(command);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends a SCPI command to the scope
|
|
/// </summary>
|
|
/// <param name="command">The SCPI command to send</param>
|
|
public void ScopeIOWrite(string command)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
_scope.IOWrite(command);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="switchControlName"></param>
|
|
/// <param name="shallWeClose"></param>
|
|
/*public void SwitchControl(string switchControlName, bool shallWeClose)
|
|
{
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
}*/
|
|
|
|
/// <summary>
|
|
/// Closes the switches defined in the config file, then issues a callback to the host to invoke some stimulus and make a measurement, then opens the relays
|
|
/// </summary>
|
|
/// <param name="switchMeasurementTestName">The measurement to make(the name from the input def file)</param>
|
|
/// <param name="callback">The function to call after the switches have been set</param>
|
|
public void SwitchMeasurement(string switchMeasurementTestName, SwitchMeasurementDelegate callback)
|
|
{
|
|
// hold onto the relays for the catch
|
|
List<string> measurementRelays = null;
|
|
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (SwitchMeasurements.ContainsKey(switchMeasurementTestName.ToUpper()) == false)
|
|
{
|
|
throw new Exception("could not find measurement: " + switchMeasurementTestName);
|
|
}
|
|
|
|
// grab the relays
|
|
measurementRelays = SwitchMeasurements[switchMeasurementTestName]._relays;
|
|
|
|
// close the relays
|
|
SwitchRelayClose(measurementRelays);
|
|
|
|
//Call the Callback for Measurement so the host can do what they need to do
|
|
callback();
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// open the relays
|
|
if (measurementRelays != null)
|
|
{
|
|
SwitchRelayOpen(measurementRelays);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |