1239 lines
35 KiB
C#
1239 lines
35 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.
|
|
-------------------------------------------------------------------------*/
|
|
|
|
|
|
// Ignore Spelling: ocp ovp
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Net.Sockets;
|
|
using System.Text;
|
|
using Raytheon.Common;
|
|
using Raytheon.Units;
|
|
using NLog;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Linq;
|
|
using Raytheon.Instruments.PowerSupply;
|
|
using System.Threading;
|
|
|
|
namespace Raytheon.Instruments
|
|
{
|
|
/// <summary>
|
|
/// A class to control a power supply system.
|
|
/// </summary>
|
|
public class PowerSupplySystemKeysight : IPowerSupplySystem, IDisposable
|
|
{
|
|
#region PrivateClassMembers
|
|
|
|
private byte[] _readBuffer;
|
|
private NetworkStream _tcpStream;
|
|
private readonly SortedDictionary<string, IDCPwr> _powerModuleMap;
|
|
private Dictionary<string, PowerSupplyModuleInfo> _powerModuleInfoDict = new Dictionary<string, PowerSupplyModuleInfo>();
|
|
|
|
//@@@ Don't want this here, but until the interface can change..this is the only option
|
|
private readonly SortedDictionary<string, double> _powerModuleInitialVoltageSetpoint;
|
|
private string _name;
|
|
private object _syncObj = new Object();
|
|
private const int _READ_TIMEOUT = 5000;
|
|
private readonly List<int> _moduleNumbersThatHaveBeenAdded;
|
|
private readonly PowerScpiCommands _scpiCommands;
|
|
private State _state;
|
|
private readonly string _address;
|
|
private readonly int _port;
|
|
private SelfTestResult _selfTestResult;
|
|
private readonly bool _shallWeCoupleOutputProtection;
|
|
|
|
private List<string> _groupedModules;
|
|
private List<string> _coupledModules;
|
|
|
|
/// <summary>
|
|
/// NLog logger
|
|
/// </summary>
|
|
private readonly ILogger _logger;
|
|
/// <summary>
|
|
/// Raytheon configuration
|
|
/// </summary>
|
|
private readonly IConfigurationManager _configurationManager;
|
|
private readonly IConfiguration _configuration;
|
|
private IConfigurationFile _powerSupplySystemConfig;
|
|
|
|
#endregion
|
|
|
|
#region PublicFuctions
|
|
|
|
/// <summary>
|
|
/// PowerSupplySystemKeysight factory constructor
|
|
/// </summary>
|
|
/// <param name="deviceName"></param>
|
|
/// <param name="configurationManager"></param>
|
|
/// <param name="logger"></param>
|
|
public PowerSupplySystemKeysight(string deviceName, IConfigurationManager configurationManager, ILogger logger)
|
|
{
|
|
const int READ_BUFFER_SIZE = 512;
|
|
|
|
Name = deviceName;
|
|
|
|
_logger = logger;
|
|
|
|
_configurationManager = configurationManager;
|
|
_configuration = _configurationManager.GetConfiguration(Name);
|
|
|
|
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
|
string powerSupplySystemDefPath = _configuration.GetConfigurationValue(deviceName, PowerSupply.ConfigXml.POWER_SUPPLY_SYSTEM_DEF_FILEPATH.ToString());
|
|
|
|
if (!Path.IsPathRooted(powerSupplySystemDefPath))
|
|
powerSupplySystemDefPath = Path.GetFullPath(Path.Combine(assemblyFolder, powerSupplySystemDefPath));
|
|
|
|
_powerSupplySystemConfig = new ConfigurationFile(powerSupplySystemDefPath);
|
|
|
|
_address = _powerSupplySystemConfig.ReadValue(deviceName, PowerSupply.ConfigIni.ETHERNET_ADDRESS.ToString());
|
|
Int32.TryParse(_powerSupplySystemConfig.ReadValue(deviceName, PowerSupply.ConfigIni.ETHERNET_PORT.ToString()), out _port);
|
|
_port = _powerSupplySystemConfig.ReadValue(deviceName, PowerSupply.ConfigIni.ETHERNET_PORT.ToString(), 1);
|
|
|
|
_shallWeCoupleOutputProtection = _powerSupplySystemConfig.ReadValue(deviceName, PowerSupply.ConfigIni.ENABLE_OUTPUT_COUPLING_PROTECTION.ToString(), false);
|
|
|
|
_readBuffer = new byte[READ_BUFFER_SIZE];
|
|
_powerModuleInitialVoltageSetpoint = new SortedDictionary<string, double>(StringComparer.InvariantCultureIgnoreCase);
|
|
_moduleNumbersThatHaveBeenAdded = new List<int>();
|
|
_powerModuleMap = new SortedDictionary<string, IDCPwr>(StringComparer.InvariantCultureIgnoreCase);
|
|
|
|
var scpiDefPath = _powerSupplySystemConfig.ReadValue(deviceName, PowerSupply.ConfigIni.SCPI_DEF_FILEPATH.ToString());
|
|
if (!Path.IsPathRooted(scpiDefPath))
|
|
scpiDefPath = Path.GetFullPath(Path.Combine(assemblyFolder, scpiDefPath));
|
|
_scpiCommands = new PowerScpiCommands(scpiDefPath);
|
|
|
|
_state = State.Uninitialized;
|
|
_selfTestResult = SelfTestResult.Unknown;
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public bool ClearErrors()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public string DetailedStatus
|
|
{
|
|
get
|
|
{
|
|
return "This is a Keysight Scpi Power Supply System called " + _name;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public bool DisplayEnabled
|
|
{
|
|
get
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
set
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (value == true)
|
|
{
|
|
// send the command
|
|
string command = _scpiCommands._SET_FRONTPANEL_ENABLE_CMD + "\n";
|
|
IOWrite(command);
|
|
}
|
|
else
|
|
{
|
|
string command = _scpiCommands._SET_FRONTPANEL_DISABLE_CMD + "\n";
|
|
IOWrite(command);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dispose of this object.
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
Dispose(true);
|
|
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Error(ex, ex.Message);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public bool FrontPanelEnabled
|
|
{
|
|
get
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
set
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (value == true)
|
|
{
|
|
// send the command
|
|
string command = _scpiCommands._SET_FRONTPANEL_ENABLE_CMD + "\n";
|
|
IOWrite(command);
|
|
}
|
|
else
|
|
{
|
|
string command = _scpiCommands._SET_FRONTPANEL_DISABLE_CMD + "\n";
|
|
IOWrite(command);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the error code.
|
|
/// </summary>
|
|
/// <param name="errorCode">The error code.</param>
|
|
/// <returns>The error description.</returns>
|
|
public string GetErrorCode(out int errorCode)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
// not calling IOQuery() here so IOQuery() can call GetErrorCode() after each query
|
|
|
|
string command = _scpiCommands._READ_ERROR_CODE_CMD + "\n";
|
|
|
|
byte[] commandBuffer = Encoding.ASCII.GetBytes(command);
|
|
|
|
// send the data out
|
|
CommInterfaceWrite(commandBuffer);
|
|
|
|
// clear our buffer
|
|
Array.Clear(_readBuffer, 0, _readBuffer.Length);
|
|
|
|
// read the response
|
|
string rspStr = GetResponse();
|
|
|
|
// parse the response
|
|
string[] tokens = rspStr.Split(',');
|
|
|
|
errorCode = Util.ConvertStringToInt32(tokens[0]);
|
|
|
|
// it should always be 2
|
|
if (tokens.Length >= 2)
|
|
{
|
|
return tokens[1];
|
|
}
|
|
else
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the names of the modules in this system
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public List<string> GetModuleNames()
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
List<string> moduleNames = new List<string>();
|
|
|
|
foreach (KeyValuePair<string, IDCPwr> modules in _powerModuleMap)
|
|
{
|
|
moduleNames.Add(modules.Key);
|
|
}
|
|
|
|
return moduleNames;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the dictionary that contains configuration information for each module
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public Dictionary<string, PowerSupplyModuleInfo> GetPowerSupplyModuleInfoDict(string powerSystem)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
return _powerModuleInfoDict;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the overcurrent protection setting.
|
|
/// </summary>
|
|
/// <param name="name">The module to get the overcurrent protection setting.</param>
|
|
/// <returns>The current (Amps).</returns>
|
|
public double GetOverCurrentSetting(string name)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(name.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::GetOverCurrentSetting() - could not find supply: " + name.ToUpper() + " in System " + _name);
|
|
}
|
|
|
|
return _powerModuleMap[name.ToUpper()].CurrentLimit.Amps;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the overvoltage protection setting.
|
|
/// </summary>
|
|
/// <param name="name">The module to get the overvoltage protection setting.</param>
|
|
/// <returns>The voltage (Volts).</returns>
|
|
public double GetOverVoltageSetting(string name)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(name.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::GetOverVoltageSetting() - could not find supply: " + name.ToUpper() + " in System " + _name);
|
|
}
|
|
|
|
return _powerModuleMap[name.ToUpper()].OverVoltageProtection.Volts;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public double GetSlewRate(string name)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(name.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::GetSlewRate() - could not find supply: " + name.ToUpper() + " in System " + _name);
|
|
}
|
|
|
|
throw new NotImplementedException();
|
|
|
|
//return _powerModuleMap[name.ToUpper()].GetSlewRate();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the voltage setpoint.
|
|
/// </summary>
|
|
/// <param name="name">The module to get the voltage setpoint setting.</param>
|
|
/// <returns>the voltage setpoint (Volts).</returns>
|
|
public double GetVoltageSetting(string name)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(name.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::GetVoltageSetting() - could not find supply: " + name.ToUpper() + " In System " + _name);
|
|
}
|
|
|
|
return _powerModuleMap[name.ToUpper()].OutputVoltage.Volts;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public InstrumentMetadata Info
|
|
{
|
|
get
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public void Initialize()
|
|
{
|
|
// if we have not yet been initialized, go ahead and create the socket
|
|
if (_state == State.Uninitialized)
|
|
{
|
|
try
|
|
{
|
|
TcpClient powerSupplySocketConn = new TcpClient(_address, _port);
|
|
// connect to the supply and setup stream
|
|
_tcpStream = powerSupplySocketConn.GetStream();
|
|
_tcpStream.ReadTimeout = _READ_TIMEOUT;
|
|
|
|
Reset();
|
|
|
|
string coupledModules = _powerSupplySystemConfig.ReadValue(Name, PowerSupply.ConfigIni.COUPLED_MODULES.ToString());
|
|
string groupedModules = _powerSupplySystemConfig.ReadValue(Name, PowerSupply.ConfigIni.GROUPED_MODULES.ToString());
|
|
|
|
string moduleDef = _powerSupplySystemConfig.ReadValue(Name, PowerSupply.ConfigIni.MODULE_DEFINITION.ToString());
|
|
_coupledModules = coupledModules.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
|
_groupedModules = groupedModules.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
|
List<string> powerModules = moduleDef.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
|
|
|
bool systemRebooted = false;
|
|
if (_groupedModules.Count() > 1)
|
|
GroupModules(_groupedModules, out systemRebooted);
|
|
else if (_coupledModules.Count() > 1)
|
|
CoupleModules(_coupledModules);
|
|
|
|
if (systemRebooted)
|
|
{
|
|
_tcpStream.Close();
|
|
powerSupplySocketConn.Close();
|
|
powerSupplySocketConn = new TcpClient(_address, _port);
|
|
_tcpStream = powerSupplySocketConn.GetStream();
|
|
_tcpStream.ReadTimeout = _READ_TIMEOUT;
|
|
}
|
|
|
|
if (_groupedModules.Count() > 1)
|
|
{
|
|
powerModules.Clear();
|
|
// since modules are grouped, we pick the first module as the representative module
|
|
powerModules.Add(_groupedModules[0]);
|
|
}
|
|
|
|
double overCurrentProtection;
|
|
double overVoltageProtection;
|
|
double voltageSetpoint;
|
|
double maxVoltageSetpoint;
|
|
double minVoltageSetpoint;
|
|
double slewRateVoltsPerSecond;
|
|
double inRushDelaySecs;
|
|
int moduleNumber = -1;
|
|
for (int i = 0; i < powerModules.Count(); i++)
|
|
{
|
|
string moduleName = powerModules[i];
|
|
|
|
int.TryParse(_powerSupplySystemConfig.ReadValue($"{Name}.{moduleName}", PowerSupply.ConfigIni.INDEX.ToString()), out moduleNumber);
|
|
Double.TryParse(_powerSupplySystemConfig.ReadValue($"{Name}.{moduleName}", PowerSupply.ConfigIni.OCP.ToString()), out overCurrentProtection);
|
|
Double.TryParse(_powerSupplySystemConfig.ReadValue($"{Name}.{moduleName}", PowerSupply.ConfigIni.OVP.ToString()), out overVoltageProtection);
|
|
Double.TryParse(_powerSupplySystemConfig.ReadValue($"{Name}.{moduleName}", PowerSupply.ConfigIni.VOLTAGE_SETPOINT.ToString()), out voltageSetpoint);
|
|
Double.TryParse(_powerSupplySystemConfig.ReadValue($"{Name}.{moduleName}", PowerSupply.ConfigIni.MIN_VOLTAGE.ToString()), out minVoltageSetpoint);
|
|
Double.TryParse(_powerSupplySystemConfig.ReadValue($"{Name}.{moduleName}", PowerSupply.ConfigIni.MAX_VOLTAGE.ToString()), out maxVoltageSetpoint);
|
|
|
|
try
|
|
{
|
|
if (!Double.TryParse(_powerSupplySystemConfig.ReadValue($"{Name}.{moduleName}", PowerSupply.ConfigIni.VOLTAGE_SLEW_RATE.ToString()), out slewRateVoltsPerSecond))
|
|
slewRateVoltsPerSecond = -1.0;
|
|
}
|
|
catch
|
|
{
|
|
slewRateVoltsPerSecond = -1.0;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (!Double.TryParse(_powerSupplySystemConfig.ReadValue($"{Name}.{moduleName}", PowerSupply.ConfigIni.IN_RUSH_DELAY_SECS.ToString()), out inRushDelaySecs))
|
|
inRushDelaySecs = -1.0;
|
|
}
|
|
catch
|
|
{
|
|
inRushDelaySecs = -1.0;
|
|
}
|
|
|
|
_powerModuleInfoDict[moduleName] = new PowerSupplyModuleInfo(moduleNumber, overCurrentProtection, overVoltageProtection, voltageSetpoint, slewRateVoltsPerSecond, minVoltageSetpoint, maxVoltageSetpoint);
|
|
|
|
// create and initialize the power module
|
|
IDCPwr powerSupply = new PowerSupplyKeysight(moduleName, _scpiCommands, overCurrentProtection, overVoltageProtection, voltageSetpoint, maxVoltageSetpoint, minVoltageSetpoint, inRushDelaySecs, slewRateVoltsPerSecond, _tcpStream, moduleNumber);
|
|
|
|
// remember that we have added this module
|
|
_moduleNumbersThatHaveBeenAdded.Add(moduleNumber);
|
|
|
|
// remember the module name
|
|
_powerModuleMap.Add(moduleName.ToUpper(), powerSupply);
|
|
|
|
// remember the initial voltage setpoint
|
|
_powerModuleInitialVoltageSetpoint.Add(moduleName.ToUpper(), voltageSetpoint);
|
|
|
|
powerSupply.Initialize();
|
|
}
|
|
|
|
if (_shallWeCoupleOutputProtection == true)
|
|
{
|
|
EnableOutputProtectionCoupling();
|
|
}
|
|
|
|
_state = State.Ready;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::Initialize() - expected the state of System " + _name + " to be Uninitialized, state was: " + _state.ToString());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Query the output state.
|
|
/// </summary>
|
|
/// <param name="name">The module to query.</param>
|
|
/// <returns>The output state. True = On, False = Off.</returns>
|
|
public bool IsOutputOn(string name)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(name.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::IsOutputOn() - could not find supply: " + name.ToUpper() + " In System " + _name);
|
|
}
|
|
|
|
return _powerModuleMap[name.ToUpper()].Enabled;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send a command to the power supply and get the response.
|
|
/// </summary>
|
|
/// <param name="commandString">The command to send.</param>
|
|
/// <returns>The power supply response.</returns>
|
|
public string IOQuery(string commandString)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
// not calling IOWrite() so IOWrite() can check for errors after each write
|
|
|
|
// convert to a byte array
|
|
byte[] commandBuffer = Encoding.ASCII.GetBytes(commandString);
|
|
|
|
// send the data out
|
|
CommInterfaceWrite(commandBuffer);
|
|
|
|
// clear our buffer
|
|
Array.Clear(_readBuffer, 0, _readBuffer.Length);
|
|
|
|
// read from the response
|
|
string rspStr = GetResponse();
|
|
|
|
// check for errors
|
|
int errorCode = -1;
|
|
string err = GetErrorCode(out errorCode);
|
|
if (errorCode != 0)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::IOQuery() - System " + _name + " returned error: " + err);
|
|
}
|
|
|
|
return rspStr;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends a SCPI Command to the instrument.
|
|
/// </summary>
|
|
/// <param name="commandString">The SCPI Command to be sent to the instrument.</param>
|
|
public void IOWrite(string commandString)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
// convert to a byte array
|
|
byte[] commandBuffer = Encoding.ASCII.GetBytes(commandString);
|
|
|
|
// send the data out
|
|
CommInterfaceWrite(commandBuffer);
|
|
|
|
// check for errors
|
|
int errorCode = -1;
|
|
string err = GetErrorCode(out errorCode);
|
|
if (errorCode != 0)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::IOWrite() - System " + _name + " returned error: " + err);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Control the power supply internal mechanical relay state
|
|
/// </summary>
|
|
/// <param name="name">The module to act on</param>
|
|
/// <param name="shallWeConnect">True to connect, false to disconnect</param>
|
|
public void MechanicalRelayOutputControl(string name, bool shallWeConnect)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(name.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::MechanicalRelayOutputControl() - could not find supply: " + name.ToUpper() + " In System " + _name);
|
|
}
|
|
|
|
_powerModuleMap[name.ToUpper()].MechanicalRelayOutputControl(shallWeConnect);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read the current.
|
|
/// </summary>
|
|
/// <param name="name">The name of the module.</param>
|
|
/// <returns>The current (Amps).</returns>
|
|
public double MeasureCurrent(string name)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(name.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::MeasureCurrent() - could not find supply: " + name.ToUpper() + " In System " + _name);
|
|
}
|
|
|
|
return _powerModuleMap[name.ToUpper()].MeasureCurrent().Amps;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read the voltage.
|
|
/// </summary>
|
|
/// <param name="name">The name of the module.</param>
|
|
/// <returns>The voltage (Volts).</returns>
|
|
public double MeasureVoltage(string name)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(name.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::MeasureVoltage() - could not find supply: " + name.ToUpper() + " In System " + _name);
|
|
}
|
|
|
|
return _powerModuleMap[name.ToUpper()].MeasureVoltage().Volts;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public string Name
|
|
{
|
|
get
|
|
{
|
|
return _name;
|
|
}
|
|
set { _name = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Turn the output off.
|
|
/// </summary>
|
|
/// <param name="name">The name of the module.</param>
|
|
public void Off(string name)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(name.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::Off() - could not find supply: " + name.ToUpper() + " In System " + _name);
|
|
}
|
|
|
|
_powerModuleMap[name.ToUpper()].Enabled = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Turn the output on.
|
|
/// </summary>
|
|
/// <param name="name">The name of the module.</param>
|
|
public void On(string name)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(name.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::On() - could not find supply: " + name.ToUpper() + " In System " + _name);
|
|
}
|
|
|
|
_powerModuleMap[name.ToUpper()].Enabled = true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public SelfTestResult PerformSelfTest()
|
|
{
|
|
try
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
// change the timeout to account for the long self test
|
|
CommSetReadTimeout(30000);
|
|
|
|
// send the command and get the response
|
|
string command = _scpiCommands._SELFTEST_CMD + "\n";
|
|
string rspStr = IOQuery(command);
|
|
|
|
// parse the response
|
|
string[] tokens = rspStr.Split('\n');
|
|
|
|
int rsp = Util.ConvertStringToInt32(tokens[0]);
|
|
|
|
if (rsp != 0)
|
|
{
|
|
_selfTestResult = SelfTestResult.Fail;
|
|
string errorMsg = "PowerSupplySystemKeysight::PerformSelfTest() - System " + _name + " returned an error: " + rsp.ToString();
|
|
throw new Exception(errorMsg);
|
|
}
|
|
|
|
_selfTestResult = SelfTestResult.Pass;
|
|
|
|
return SelfTestResult.Pass;
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
_selfTestResult = SelfTestResult.Fail;
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// restore the timeout
|
|
CommSetReadTimeout(_READ_TIMEOUT);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read the overvoltage and overcurrent protection status.
|
|
/// </summary>
|
|
/// <param name="name">The name of the module.</param>
|
|
/// <returns>The binary sum of all bits (decimal value) set in the Questionable Status Enable register.</returns>
|
|
public int ReadProtectionStatus(string name)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(name.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::ReadProtectionStatus() - could not find supply: " + name.ToUpper() + " In System " + _name);
|
|
}
|
|
|
|
return _powerModuleMap[name.ToUpper()].ReadProtectionStatus();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// reads power data
|
|
/// </summary>
|
|
/// <param name="name"></param>
|
|
/// <returns>A Power Data Object</returns>
|
|
public PowerData ReadPowerData(string name)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
// voltage, voltage setpoint, current, output status
|
|
double voltage = MeasureVoltage(name);
|
|
double voltageSetpoint = GetVoltageSetting(name);
|
|
double current = MeasureCurrent(name);
|
|
bool outputStatus = IsOutputOn(name);
|
|
int faultStatus = ReadProtectionStatus(name);
|
|
double overVoltageProtection = GetOverVoltageSetting(name);
|
|
double overCurrentProtection = GetOverCurrentSetting(name);
|
|
|
|
return new PowerData(voltage, voltageSetpoint, overVoltageProtection, current, overCurrentProtection, outputStatus, faultStatus);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// reads power data
|
|
/// </summary>
|
|
/// <param name="moduleName"></param>
|
|
/// <param name="voltage"></param>
|
|
/// <param name="voltageSetpoint"></param>
|
|
/// <param name="current"></param>
|
|
/// <param name="outputStatus"></param>
|
|
/// <param name="faultStatus"></param>
|
|
public void ReadPowerData(string moduleName, out double voltage, out double voltageSetpoint, out double current, out bool outputStatus, out int faultStatus)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
// voltage, voltage setpoint, current, output status
|
|
voltage = MeasureVoltage(moduleName);
|
|
voltageSetpoint = GetVoltageSetting(moduleName);
|
|
current = MeasureCurrent(moduleName);
|
|
outputStatus = IsOutputOn(moduleName);
|
|
faultStatus = ReadProtectionStatus(moduleName);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resets the instrument
|
|
/// </summary>
|
|
public void Reset()
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
// send the command
|
|
string command = _scpiCommands._RESET_CMD + "\n";
|
|
IOWrite(command);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public SelfTestResult SelfTestResult
|
|
{
|
|
get
|
|
{
|
|
return _selfTestResult;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Changes the setpoint voltage back to the value that was passed into the constructor
|
|
/// </summary>
|
|
/// <param name="name">The name of the power module</param>
|
|
public void SetInitialVoltage(string name)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(name.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::SetInitialVoltage() - could not find supply: " + name.ToUpper() + " In System " + _name);
|
|
}
|
|
|
|
double initializeVoltage = _powerModuleInitialVoltageSetpoint[name.ToUpper()];
|
|
|
|
SetVoltageSetpoint(name.ToUpper(), initializeVoltage);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the slew rate
|
|
/// </summary>
|
|
/// <param name="commandedSlew">slew in volts per second</param>
|
|
public void SetSlewRate(string name, double commandedSlew)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(name.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::SetSlewRate() - could not find supply: " + name.ToUpper() + " In System " + _name);
|
|
}
|
|
|
|
throw new NotImplementedException();
|
|
|
|
//_powerModuleMap[name.ToUpper()].SetSlewRate(commandedSlew);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the OCP value
|
|
/// </summary>
|
|
/// <param name="moduleName">The name of the power module</param>
|
|
/// <param name="ocpValue">The value in amps to set as the OCP</param>
|
|
public void SetOverCurrentProtection(string moduleName, double ocpValue)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(moduleName.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::SetOverCurrentrotection() - could not find supply: " + moduleName.ToUpper() + " In System " + _name);
|
|
}
|
|
|
|
_powerModuleMap[moduleName.ToUpper()].CurrentLimit = Current.FromAmps(ocpValue);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="moduleName">The name of the module</param>
|
|
/// <param name="ovpValue">The value in volts to set as the OVP</param>
|
|
public void SetOverVoltageProtection(string moduleName, double ovpValue)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(moduleName.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::SetOverVoltageProtection() - could not find supply: " + moduleName.ToUpper() + " In System " + _name);
|
|
}
|
|
|
|
_powerModuleMap[moduleName.ToUpper()].OverVoltageProtection = Voltage.FromVolts(ovpValue);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the voltage setpoint.
|
|
/// </summary>
|
|
/// <param name="name">The name of the module.</param>
|
|
/// <param name="volts">The desired voltage (in volts).</param>
|
|
public void SetVoltageSetpoint(string name, double volts)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (_powerModuleMap.ContainsKey(name.ToUpper()) == false)
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::SetVoltageSetpoint() - could not find supply: " + name.ToUpper() + " In System " + _name);
|
|
}
|
|
|
|
_powerModuleMap[name.ToUpper()].OutputVoltage = Voltage.FromVolts(volts);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Turns off each supply, resets the system and disposes the socket
|
|
/// </summary>
|
|
public void Shutdown()
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
string errorMsg = "";
|
|
|
|
if (_state == State.Ready)
|
|
{
|
|
try
|
|
{
|
|
foreach (KeyValuePair<string, IDCPwr> entry in _powerModuleMap)
|
|
{
|
|
entry.Value.Shutdown();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Error(ex, ex.Message);
|
|
}
|
|
|
|
try
|
|
{
|
|
//Reset System
|
|
Reset();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Error(ex, ex.Message);
|
|
}
|
|
|
|
_state = State.Uninitialized;
|
|
}
|
|
|
|
// the stream was created in the constructor, dispose of it here
|
|
try
|
|
{
|
|
if (_tcpStream != null)
|
|
{
|
|
_tcpStream.Dispose();
|
|
_tcpStream = null;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Error(ex, ex.Message);
|
|
}
|
|
|
|
if (errorMsg != "")
|
|
{
|
|
throw new Exception("PowerSupplySystemKeysight::ShutdDown() - System " + _name + " Had an error: " + errorMsg);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public State Status
|
|
{
|
|
get
|
|
{
|
|
return _state;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Turn off the watchdog capability.
|
|
/// </summary>
|
|
public void WatchdogDisable()
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
// send the command
|
|
string command = _scpiCommands._SET_WATCHDOGOFF_CMD + "\n";
|
|
IOWrite(command);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Turn on the watchdog capability.
|
|
/// </summary>
|
|
/// <param name="time">The watchdog time in seconds.</param>
|
|
public void WatchdogEnable(uint time)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
string timeCommand = _scpiCommands._SET_WATCHDOGDELAY_CMD + " " + time.ToString() + "\n";
|
|
IOWrite(timeCommand);
|
|
|
|
// send the command
|
|
string onCommand = _scpiCommands._SET_WATCHDOGON_CMD + "\n";
|
|
IOWrite(onCommand);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// gets system name
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public string GetSystemName()
|
|
{
|
|
return _name;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PrivateFuctions
|
|
/// <summary>
|
|
/// The Finalizer.
|
|
/// </summary>
|
|
~PowerSupplySystemKeysight()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read data from the comm interface
|
|
/// </summary>
|
|
private string GetResponse()
|
|
{
|
|
string response = String.Empty;
|
|
|
|
int bytesRead = _tcpStream.Read(_readBuffer, 0, _readBuffer.Length);
|
|
|
|
if (bytesRead > 0)
|
|
{
|
|
response = Encoding.ASCII.GetString(_readBuffer, 0, bytesRead);
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the comm interface timeout
|
|
/// </summary>
|
|
/// <param name="readTimeout"></param>
|
|
private void CommSetReadTimeout(int readTimeout)
|
|
{
|
|
_tcpStream.ReadTimeout = readTimeout;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write data to the comm interface
|
|
/// </summary>
|
|
private void CommInterfaceWrite(byte[] dataToWrite)
|
|
{
|
|
_tcpStream.Write(dataToWrite, 0, dataToWrite.Length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dispose of this object.
|
|
/// </summary>
|
|
/// <param name="disposing">True = currently disposing, False = not disposing.</param>
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
lock (_syncObj)
|
|
{
|
|
if (disposing)
|
|
{
|
|
if (_state == State.Ready)
|
|
{
|
|
try
|
|
{
|
|
foreach (KeyValuePair<string, IDCPwr> entry in _powerModuleMap)
|
|
{
|
|
entry.Value.Shutdown();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Error(ex, ex.Message);
|
|
}
|
|
|
|
try
|
|
{
|
|
//Reset System
|
|
Reset();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Error(ex, ex.Message);
|
|
}
|
|
|
|
_state = State.Uninitialized;
|
|
}
|
|
|
|
// the stream was created in the constructor, dispose of it here if it is not null (Could be null if Shutdown() was called)
|
|
try
|
|
{
|
|
if (_tcpStream != null)
|
|
{
|
|
_tcpStream.Dispose();
|
|
_tcpStream = null;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Error(ex, ex.Message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Turns on the output protection coupling
|
|
/// </summary>
|
|
private void EnableOutputProtectionCoupling()
|
|
{
|
|
string command = _scpiCommands._SET_COUPLE_OUTPUT_PROTECT_ON_CMD + "\n";
|
|
IOWrite(command);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Group Modules Together
|
|
/// </summary>
|
|
/// <param name="modules"></param>
|
|
private void GroupModules(List<string> moduleNameList, out bool systemRebooted)
|
|
{
|
|
// 1. Group the channels
|
|
string groupListToDefine = "(@";
|
|
string groupListToQuery = "";
|
|
string moduleNumber = "";
|
|
|
|
systemRebooted = false;
|
|
|
|
for (int i = 0; i < moduleNameList.Count; i++)
|
|
{
|
|
moduleNumber = _powerSupplySystemConfig.ReadValue(moduleNameList[i], PowerSupply.ConfigIni.INDEX.ToString());
|
|
|
|
groupListToDefine += moduleNumber;
|
|
groupListToQuery += moduleNumber;
|
|
|
|
// add a ',' if this is not the final element in the list
|
|
if (i < moduleNameList.Count() - 1)
|
|
{
|
|
groupListToDefine += ",";
|
|
groupListToQuery += ",";
|
|
}
|
|
else
|
|
{
|
|
groupListToDefine += ")";
|
|
}
|
|
}
|
|
|
|
groupListToQuery = "\"" + groupListToQuery + "\"\n";
|
|
|
|
// see if channels are grouped
|
|
string queryGroupCommand = _scpiCommands._QUERY_COUPLE_CHANNELS_CMD+ "\n";
|
|
|
|
for (int i = 1; i <= 2; i++)
|
|
{
|
|
string respStr = IOQuery(queryGroupCommand);
|
|
|
|
// if modules are not grouped
|
|
if (respStr != groupListToQuery)
|
|
{
|
|
groupListToDefine += "\n";
|
|
|
|
string groupCommand = _scpiCommands._SET_GROUP_DEFINE_CMD + " " + groupListToDefine;
|
|
|
|
IOWrite(groupCommand);
|
|
}
|
|
else if (i == 1)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
string command = _scpiCommands._REBOOT_CMD + "\n";
|
|
// after grouping the modules, need to reboot system for it to take effect
|
|
IOWrite(command);
|
|
|
|
// wait 20 seconds for reboot
|
|
Thread.Sleep(20000);
|
|
|
|
systemRebooted = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Couple modules together (output synchronization)
|
|
/// </summary>
|
|
/// <param name="moduleNameList"></param>
|
|
private void CoupleModules(List<string> moduleNameList)
|
|
{
|
|
string coupleListToDefine = "";
|
|
string moduleNumber = "";
|
|
|
|
for (int i = 0; i < moduleNameList.Count(); i++)
|
|
{
|
|
moduleNumber = _powerSupplySystemConfig.ReadValue($"{Name}.{moduleNameList[i]}", PowerSupply.ConfigIni.INDEX.ToString());
|
|
|
|
coupleListToDefine += moduleNumber;
|
|
|
|
// add a ',' if this is not the final element in the list
|
|
if (i < moduleNameList.Count() - 1)
|
|
{
|
|
coupleListToDefine += ",";
|
|
}
|
|
}
|
|
|
|
coupleListToDefine += "\n";
|
|
|
|
// see if channels are coupled
|
|
string queryCoupleChannelCommand = _scpiCommands._QUERY_COUPLE_CHANNELS_CMD + "\n";
|
|
|
|
for (int i = 1; i <= 2; i++)
|
|
{
|
|
string respStr = IOQuery(queryCoupleChannelCommand);
|
|
|
|
string queryCoupleStateCommand = _scpiCommands._QUERY_COUPLE_STATE_CMD + "\n";
|
|
string respStr2 = IOQuery(queryCoupleStateCommand);
|
|
|
|
if (coupleListToDefine != respStr || respStr2 == "0\n")
|
|
{
|
|
// send command to couple modules
|
|
string command = _scpiCommands._SET_COUPLE_CHANNELS_CMD + " " + coupleListToDefine;
|
|
IOWrite(command);
|
|
|
|
// turn coupling on
|
|
command = _scpiCommands._SET_COUPLE_ON_CMD + "\n";
|
|
IOWrite(command);
|
|
|
|
// output protection on
|
|
command = _scpiCommands._SET_COUPLE_OUTPUT_PROTECT_ON_CMD + "\n";
|
|
IOWrite(command);
|
|
}
|
|
else if (i == 1)
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|