// 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 NationalInstruments.NI4882;
using NLog;
using Raytheon.Common;
using Raytheon.Units;
using System;
using System.Collections.Generic;
using System.IO.Ports;
namespace Raytheon.Instruments
{
///
/// This class interfaces to a Keysight N3300 Eload system
///
public class EloadSystemScpiKeysight : IELoadSystem
{
#region PrivateClassMembers
private enum ControlInterface
{
COM_PORT,
GPIB
}
// system commands
private const string _CLEAREVENTREG = "*CLS";
private const string _CLEARSERVICEREQUEST = "*SRE 0";
private const string _CLEAREVENTSTATUSENABLEREGISTER = "*ESE 0";
private const string _ERRORCODE = "SYST:ERR?";
private const string _RESET = "*RST";
private const string _SELFTEST = "*TST?";
private string _systemName;
private SerialPort _serialPort;
private Device _gpibDevice;
private ControlInterface _interface;
private readonly SortedDictionary _eloadChannelMap;
private readonly bool _isThereHardware;
private static object _syncObj = new Object();
// default the timeout for responses to 5 seconds
private const int _READ_TIMEOUT = 5000;
///
/// NLog logger
///
private readonly ILogger _logger;
///
/// Raytheon configuration
///
private readonly IConfigurationManager _configurationManager;
private readonly IConfiguration _configuration;
public string DetailedStatus { get; protected set; }
public bool DisplayEnabled { get; set; }
public bool FrontPanelEnabled { get; set; }
public InstrumentMetadata Info { get; set; }
public string Name { get; protected set; }
public SelfTestResult SelfTestResult => PerformSelfTest();
public State Status { get; set; }
#endregion
#region PrivateFuctions
///
/// Send a SCPI Command to the instrument and get a response.
///
/// The command to send.
/// The instrument response.
private string IOQuery(string commandString)
{
// not calling IOWrite() so IOWrite() can check for errors after each write
string rsp = "";
if (_interface == ControlInterface.COM_PORT)
{
_serialPort.WriteLine(commandString);
rsp = _serialPort.ReadLine();
}
else if (_interface == ControlInterface.GPIB)
{
_gpibDevice.Write(commandString);
rsp = _gpibDevice.ReadString();
}
else
{
throw new Exception("unknown interface type: " + _interface.ToString());
}
rsp = rsp.Replace("\r", "");
// check for errors
int err = 0;
string errorMsg = GetErrorCode(out err);
if (err != 0)
{
throw new Exception(errorMsg);
}
return rsp;
}
///
/// Sends a SCPI Command to the instrument.
///
/// The command to send.
private void IOWrite(string commandString)
{
if (_interface == ControlInterface.COM_PORT)
{
_serialPort.WriteLine(commandString);
}
else if (_interface == ControlInterface.GPIB)
{
_gpibDevice.Write(commandString);
}
else
{
throw new Exception("unknown interface type: " + _interface.ToString());
}
int err = 0;
string errorMsg = GetErrorCode(out err);
if (err != 0)
{
throw new Exception(errorMsg);
}
}
///
/// Resets the instrument and clears event registers, error queue,
/// service request enable register, and event status enable register.
///
private void Reset()
{
IOWrite(_RESET);
IOWrite(_CLEAREVENTREG);
IOWrite(_CLEARSERVICEREQUEST);
IOWrite(_CLEAREVENTSTATUSENABLEREGISTER);
}
#endregion
#region PublicFuctions
///
/// FlowMeterOmegaDPF20 factory constructor
///
///
///
public EloadSystemScpiKeysight(string deviceName, IConfigurationManager configurationManager, ILogger logger)
{
Name = deviceName;
_logger = logger;
_configurationManager = configurationManager;
_configuration = _configurationManager.GetConfiguration(Name);
_gpibDevice = null;
_serialPort = _configuration.GetConfigurationValue("ELoadScpiKeysight", "SerialPort", new SerialPort());
var flowControl = _configuration.GetConfigurationValue("ELoadScpiKeysight", "FlowControl", Handshake.None);
try
{
_interface = ControlInterface.COM_PORT;
_systemName = Name;
_serialPort.Open();
_serialPort.ReadTimeout = _READ_TIMEOUT;
_serialPort.Handshake = flowControl;
Reset();
_eloadChannelMap = new SortedDictionary(StringComparer.InvariantCultureIgnoreCase);
}
catch (Exception)
{
if (_serialPort.IsOpen == true)
{
_serialPort.Close();
}
throw;
}
}
///
/// The constructor for com port interface which open up the comm port, resets the system and waits for additional commands
///
/// The COM port name as it exists in windows device manager.
/// The bit rate of the host computer COM port.
/// The parity setting of the host computer. 0 = None, 1 = Odd, 2 = Even, 3 = Mark, 4 = Space.
/// The number of bits of data sent per transfer.
/// The number of stop bits used by host computer.
/// Handshake method. 0 = None, 1 = XonXoff, 2 = RTS, 3 = RTSXonXoff.
/// Software operation mode. True = Hardware available, False = Simulation Only.
public EloadSystemScpiKeysight(string systemName, string comPortName, int baudRate, Parity parity, int dataBits, StopBits stopBits, Handshake flowControl, bool isThereHardware)
{
try
{
_logger = LogManager.GetCurrentClassLogger();
_interface = ControlInterface.COM_PORT;
_systemName = systemName;
_isThereHardware = isThereHardware;
_serialPort = null;
_gpibDevice = null;
if (_isThereHardware == true)
{
_serialPort = new SerialPort(comPortName, baudRate, parity, dataBits, stopBits);
_serialPort.Open();
_serialPort.ReadTimeout = _READ_TIMEOUT;
_serialPort.Handshake = flowControl;
Reset();
}
_eloadChannelMap = new SortedDictionary(StringComparer.InvariantCultureIgnoreCase);
}
catch (Exception ex)
{
if (_serialPort.IsOpen == true)
{
_serialPort.Close();
}
_logger.Error(ex.Message);
throw;
}
}
///
/// The constructor for gpib interface which open up the comm port, resets the system and waits for additional commands
///
///
///
///
///
public EloadSystemScpiKeysight(string systemName, int boardNumber, byte primaryAddress, bool isThereHardware)
{
try
{
_interface = ControlInterface.GPIB;
_systemName = systemName;
_isThereHardware = isThereHardware;
_serialPort = null;
_gpibDevice = null;
if (_isThereHardware == true)
{
_gpibDevice = new Device(boardNumber, primaryAddress);
//@@@ TBD if this make the newline go out after each write
_gpibDevice.EndOfStringCharacter = 0xa;
_gpibDevice.IOTimeout = TimeoutValue.T3s;
Reset();
}
_eloadChannelMap = new SortedDictionary(StringComparer.InvariantCultureIgnoreCase);
}
catch (Exception)
{
if (_gpibDevice != null)
{
_gpibDevice.Dispose();
_gpibDevice = null;
}
throw;
}
}
///
/// The finalizer
///
~EloadSystemScpiKeysight()
{
Dispose(false);
}
///
/// Add an Eload to the system.
///
/// The name of the channel (module) for reference.
/// The channel number for the Eload..
/// The operation mode of the channel. Modes: Resistance, Voltage, Current.
/// The operation point of the load. This can be a voltage, current, or resistance
/// Overcurrent setpoint that will turn off the channel if exceeded.
/// Overvoltage setpoint that will turn off channel if exceeded (double check).
public void AddEloadChannel(string name, int channelNumber, EloadModuleMode mode, double setpoint, Current overCurrentProtection, Voltage overVoltageProtection)
{
try
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(name.ToUpper()) == true)
{
throw new Exception("system already contains a module named: " + name.ToUpper());
}
IEload eload;
if (_isThereHardware)
{
if (_interface == ControlInterface.COM_PORT)
{
eload = new ELoadScpiKeysight(_serialPort, channelNumber, mode, setpoint, overCurrentProtection.Amps, overVoltageProtection.Volts);
}
else if (_interface == ControlInterface.GPIB)
{
eload = new ELoadScpiKeysight(_gpibDevice, channelNumber, mode, setpoint, overCurrentProtection.Amps, overVoltageProtection.Volts);
}
else
{
throw new Exception("unknown interface: " + _interface.ToString());
}
}
else
{
eload = new EloadSim(channelNumber, mode, setpoint, overCurrentProtection.Amps, overVoltageProtection.Volts);
}
_eloadChannelMap.Add(name.ToUpper(), eload);
}
}
catch (Exception)
{
if (_interface == ControlInterface.COM_PORT)
{
_serialPort.Close();
}
else if (_interface == ControlInterface.GPIB)
{
_gpibDevice.Dispose();
_gpibDevice = null;
}
throw;
}
}
///
/// Dispose of this object's resources.
///
public void Dispose()
{
try
{
Dispose(true);
GC.SuppressFinalize(this);
}
catch (Exception)
{
try
{
//ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
}
catch (Exception)
{
//Do not rethrow. Exception from error logger that has already been garbage collected
}
}
}
///
/// Get the error code.
///
/// The error code.
public string GetErrorCode(out int errorCode)
{
lock (_syncObj)
{
if (_isThereHardware == true)
{
// not calling IOQuery() here so IOQuery() can call GetErrorCode() after each query
string rsp = "";
if (_interface == ControlInterface.COM_PORT)
{
_serialPort.WriteLine(_ERRORCODE);
rsp = _serialPort.ReadLine();
}
else if (_interface == ControlInterface.GPIB)
{
_gpibDevice.Write(_ERRORCODE);
rsp = _gpibDevice.ReadString();
}
else
{
throw new Exception("unknown interface type: " + _interface.ToString());
}
rsp = rsp.Replace("\r", "");
string[] tokens = rsp.Split(',');
errorCode = Util.ConvertStringToInt32(tokens[0]);
// it should always be 2
if (tokens.Length >= 2)
{
return tokens[1];
}
else
{
return "";
}
}
else
{
errorCode = 0;
return "";
}
}
}
///
///
///
///
public List GetModuleNames()
{
lock (_syncObj)
{
List moduleNames = new List();
foreach (KeyValuePair modules in _eloadChannelMap)
{
moduleNames.Add(modules.Key);
}
return moduleNames;
}
}
///
///
///
///
public string GetSystemName()
{
lock (_syncObj)
{
return _systemName;
}
}
///
/// Query if the Eload input is on.
///
/// The name of the Eload.
/// Status of Eload. True = On, False = Off.
public bool IsInputOn(string channelName)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
bool status = _eloadChannelMap[channelName.ToUpper()].IsInputOn();
return status;
}
}
///
/// Turn off the Eload input.
///
/// The name of the Eload.
public void Disable(string channelName)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
_eloadChannelMap[channelName.ToUpper()].Disable();
}
}
///
/// Turn on the Eload input.
///
/// The name of the Eload.
public void Enable(string channelName)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
_eloadChannelMap[channelName.ToUpper()].Enable();
}
}
///
///
///
///
///
///
public string IOQuery(string channelName, string command)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
return _eloadChannelMap[channelName.ToUpper()].IOQuery(command);
}
}
///
///
///
///
///
public void IOWrite(string channelName, string command)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
_eloadChannelMap[channelName.ToUpper()].IOWrite(command);
}
}
///
/// Reads the current of the Eload.
///
/// The name of the Eload.
/// Measured current (Amps).
public Current ReadCurrent(string channelName)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
var value = _eloadChannelMap[channelName.ToUpper()].ReadCurrent();
return value;
}
}
///
/// Reads all Eload data (voltage, current, resistance, setpoint, input state, mode).
///
/// The name of the Eload.
/// The measured voltage (Volts).
/// The measured current (Amps).
/// The measured resistance (Ohms).
/// The setpoint of the Eload. Depends on mode of operation.
/// The state of the Eload.
/// The mode of the Eload.
public void ReadData(string channelName, out Voltage voltage, out Current current, out Resistance resistance, out double setpoint, out bool isInputOn, out EloadModuleMode mode, out ushort status)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
voltage = _eloadChannelMap[channelName.ToUpper()].ReadVoltage();
current = _eloadChannelMap[channelName.ToUpper()].ReadCurrent();
resistance = _eloadChannelMap[channelName.ToUpper()].ReadResistance();
setpoint = _eloadChannelMap[channelName.ToUpper()].ReadSetpoint();
isInputOn = _eloadChannelMap[channelName.ToUpper()].IsInputOn();
mode = _eloadChannelMap[channelName.ToUpper()].ReadMode();
status = _eloadChannelMap[channelName.ToUpper()].ReadProtectionStatus();
}
}
///
/// Reads the mode of the Eload
///
/// The name of the Eload.
/// The mode
public EloadModuleMode ReadMode(string channelName)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
EloadModuleMode value = _eloadChannelMap[channelName.ToUpper()].ReadMode();
return value;
}
}
///
/// Reads the overcurrent setting from an Eload.
///
/// The name of the Eload.
/// Overcurrent setting (Amps).
public Current ReadOverCurrentProtection(string channelName)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
var value = _eloadChannelMap[channelName.ToUpper()].ReadOverCurrentProtection();
return value;
}
}
///
/// Reads the overvoltage setting from an Eload.
///
/// The name of the Eload.
/// Overvoltage setting (Volts).
public Voltage ReadOverVoltageProtection(string channelName)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
var value = _eloadChannelMap[channelName.ToUpper()].ReadOverVoltageProtection();
return value;
}
}
///
/// Read the resistance.
///
/// The name of the Eload.
/// The resistance (Ohms).
public Resistance ReadResistance(string channelName)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
var value = _eloadChannelMap[channelName.ToUpper()].ReadResistance();
return value;
}
}
///
/// Reads the setpoint of the Eload.
///
/// The name of the Eload.
/// The setpoint. Depends on mode.
public double ReadSetpoint(string channelName)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
return _eloadChannelMap[channelName.ToUpper()].ReadSetpoint();
}
}
///
/// Reads the voltage of the Eload.
///
/// The name of the Eload.
/// The voltage (Volts)
public Voltage ReadVoltage(string channelName)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
var value = _eloadChannelMap[channelName.ToUpper()].ReadVoltage();
return value;
}
}
///
/// Reads the protection status from an Eload.
///
/// The name of the Eload.
/// Protection status register.
public ushort ReadProtectionStatus(string channelName)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
ushort value = _eloadChannelMap[channelName.ToUpper()].ReadProtectionStatus();
return value;
}
}
///
/// Run a self-test.
///
public void Selftest()
{
try
{
// change the timeout to account for the long self test to 30 seconds
if (_interface == ControlInterface.COM_PORT)
{
//@@@ is this the right time?
_serialPort.ReadTimeout = 30000;
}
else if (_interface == ControlInterface.GPIB)
{
//@@@ TBD
}
else
{
throw new Exception("unknown interface type: " + _interface.ToString());
}
// send the command
string rspStr = IOQuery(_SELFTEST);
// parse the response
string[] tokens = rspStr.Split('\n');
int rsp = Util.ConvertStringToInt32(tokens[0]);
if (rsp != 0)
{
string errorMsg = "returned an error: " + rsp.ToString();
throw new Exception(errorMsg);
}
}
catch (Exception)
{
throw;
}
finally
{
// restore the timeout
if (_interface == ControlInterface.COM_PORT)
{
_serialPort.ReadTimeout = _READ_TIMEOUT;
}
else if (_interface == ControlInterface.GPIB)
{
//@@@ TBD
}
else
{
throw new Exception("unknown interface type: " + _interface.ToString());
}
}
}
///
/// Resets all channels to config file values
///
public void SetInitialSetting(string module)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(module.ToUpper()) == false)
{
throw new Exception("could not find load: " + module.ToUpper());
}
_eloadChannelMap[module.ToUpper()].SetInitialSetting();
}
}
///
/// Resets all channels to config file values
///
public void SetInitialSettingAll()
{
lock (_syncObj)
{
foreach (KeyValuePair eload in _eloadChannelMap)
{
_eloadChannelMap[eload.Key].SetInitialSetting();
}
}
}
///
/// Change the operation mode of the Eload.
///
/// The name of the Eload.
/// The desired Eload mode.
public void SetMode(string channelName, EloadModuleMode mode)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
_eloadChannelMap[channelName.ToUpper()].SetMode(mode);
}
}
///
/// Change the setpoint and operation mode of the Eload.
///
/// The name of the Eload.
/// The desired setpoint of the Eload.
/// The desired Eload mode.
public void SetSetpoint(string channelName, double newSetpoint, EloadModuleMode mode)
{
lock (_syncObj)
{
if (_eloadChannelMap.ContainsKey(channelName.ToUpper()) == false)
{
throw new Exception("could not find module: " + channelName.ToUpper());
}
_eloadChannelMap[channelName.ToUpper()].SetSetpoint(newSetpoint, mode);
}
}
///
/// Dispose of this objects resources
///
/// True = currently disposing, False = not disposing.
protected virtual void Dispose(bool disposing)
{
try
{
lock (_syncObj)
{
if (disposing)
{
foreach (KeyValuePair entry in _eloadChannelMap)
{
entry.Value.Shutdown();
}
if (_serialPort != null)
{
Reset();
_serialPort.Dispose();
_serialPort = null;
}
if (_gpibDevice != null)
{
Reset();
_gpibDevice.Dispose();
_gpibDevice = null;
}
}
}
}
catch (Exception)
{
try
{
//ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
}
catch (Exception)
{
//Do not rethrow. Exception from error logger that has already been garbage collected
}
}
}
public bool ClearErrors()
{
throw new NotImplementedException();
}
public void Initialize()
{
throw new NotImplementedException();
}
public SelfTestResult PerformSelfTest()
{
throw new NotImplementedException();
}
void IInstrument.Reset()
{
throw new NotImplementedException();
}
public void Shutdown()
{
throw new NotImplementedException();
}
#endregion
}
}