From fd85735c937b87f36d036a0fab5c4395ba87444d Mon Sep 17 00:00:00 2001 From: Duc Date: Thu, 13 Mar 2025 17:41:23 -0700 Subject: [PATCH] My improved version of PowerSupply and TcpClient implementation --- .../Keysight67XX/KeysightN67XX.csproj | 28 + .../Keysight67XX/KeysightN67xxPowerFactory.cs | 117 ++++ .../Keysight67XX/KeysightN67xxPowerModule.cs | 662 ++++++++++++++++++ .../Keysight67XX/KeysightN67xxPowerSupply.cs | 121 ++++ .../KeysightPowerSupplyScpiCommands.cs | 80 +++ .../PowerSupplyBasic/PowerSupply.cs | 63 ++ .../PowerSupplyBasic/PowerSupplyBasic.csproj | 20 + .../PowerSupplyBasic/PowerSupplyConfigIni.cs | 47 ++ .../PowerSupplyBasic/PowerSupplyConfigXml.cs | 31 + .../PowerSupplyBasic/PowerSupplyModule.cs | 207 ++++++ .../PowerSupplyBasic/PowerSupplyModuleInfo.cs | 70 ++ .../PowerSupplySim/PowerSupplyModuleSim.cs | 250 +++++++ .../PowerSupplySim/PowerSupplySim.cs | 119 ++++ .../PowerSupplySim/PowerSupplySim.csproj | 32 + .../PowerSupplySim/PowerSupplySimFactory.cs | 114 +++ Source/DucLib/TcpClient/TcpClient.cs | 226 ++++++ Source/DucLib/TcpClient/TcpClient.csproj | 21 + Source/Program.sln | 41 ++ 18 files changed, 2249 insertions(+) create mode 100644 Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67XX.csproj create mode 100644 Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67xxPowerFactory.cs create mode 100644 Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67xxPowerModule.cs create mode 100644 Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67xxPowerSupply.cs create mode 100644 Source/DucLib/PowerSupplies/Keysight67XX/KeysightPowerSupplyScpiCommands.cs create mode 100644 Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupply.cs create mode 100644 Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyBasic.csproj create mode 100644 Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyConfigIni.cs create mode 100644 Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyConfigXml.cs create mode 100644 Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyModule.cs create mode 100644 Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyModuleInfo.cs create mode 100644 Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplyModuleSim.cs create mode 100644 Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplySim.cs create mode 100644 Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplySim.csproj create mode 100644 Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplySimFactory.cs create mode 100644 Source/DucLib/TcpClient/TcpClient.cs create mode 100644 Source/DucLib/TcpClient/TcpClient.csproj diff --git a/Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67XX.csproj b/Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67XX.csproj new file mode 100644 index 0000000..e832d16 --- /dev/null +++ b/Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67XX.csproj @@ -0,0 +1,28 @@ + + + + + net472 + Library + Raytheon.Instruments.PowerSupplies.Keysight67XX + Keysight 67XX Series Power Supply + Keysight 67XX Series Power Supply + + + + + + 1.0.0 + + + + + + + + + + + + + diff --git a/Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67xxPowerFactory.cs b/Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67xxPowerFactory.cs new file mode 100644 index 0000000..f5cbe95 --- /dev/null +++ b/Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67xxPowerFactory.cs @@ -0,0 +1,117 @@ +/*------------------------------------------------------------------------- +// 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 System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using System.Reflection; + +namespace Raytheon.Instruments.PowerSupplies +{ + [ExportInstrumentFactory(ModelNumber = "PowerSupplyKeysightN67xxFactory")] + public class KeysightN67xxPowerFactory : IInstrumentFactory + { + /// + /// The supported interfaces + /// + private readonly List _supportedInterfaces = new List(); + private static ILogger _logger; + private readonly IConfigurationManager _configurationManager; + private const string DefaultConfigPath = @"C:\ProgramData\Raytheon\InstrumentManagerService"; + private static string DefaultPath; + + public KeysightN67xxPowerFactory(string defaultConfigPath = DefaultConfigPath) + : this(null, defaultConfigPath) + { + } + + /// + /// COECommDeviceInstrumentFactory injection constructor + /// + /// + /// + /// + [ImportingConstructor] + public KeysightN67xxPowerFactory([Import(AllowDefault = false)] IConfigurationManager configManager, + [Import(AllowDefault = true)] string defaultConfigPath = null) + { + DefaultPath = defaultConfigPath; + _logger = LogManager.GetCurrentClassLogger(); + + if (NLog.LogManager.Configuration == null) + { + var assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + NLog.LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(assemblyFolder + "\\nlog.config"); + } + + _configurationManager = configManager ?? GetConfigurationManager(); + _supportedInterfaces.Add(typeof(PowerSupply)); + } + + /// + /// Gets the instrument + /// + /// + /// + public IInstrument GetInstrument(string name) + { + return null; + } + + /// + /// Gets the instrument + /// + /// + /// + public object GetInstrument(string name, bool simulateHw) + { + try + { + if (simulateHw) + return new PowerSupplySim(name, _configurationManager, _logger); + else + return new KeysightN67xxPowerSupply(name, _configurationManager, _logger); + } + catch (Exception ex) + { + _logger.Error(ex, $"Unable to construct {name} instrument instance"); + return null; + } + } + + /// + /// Gets supported interfaces + /// + /// + public ICollection GetSupportedInterfaces() + { + return _supportedInterfaces.ToArray(); + } + + /// + /// returns confiuration based on the predefined path or default path c:/ProgramData/Raytheon/InstrumentManagerService + /// + /// + private static IConfigurationManager GetConfigurationManager() + { + return string.IsNullOrEmpty(DefaultPath) ? new RaytheonConfigurationManager() : new RaytheonConfigurationManager(DefaultPath); + } + } +} \ No newline at end of file diff --git a/Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67xxPowerModule.cs b/Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67xxPowerModule.cs new file mode 100644 index 0000000..c9408dd --- /dev/null +++ b/Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67xxPowerModule.cs @@ -0,0 +1,662 @@ +/*------------------------------------------------------------------------- +// 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 System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Raytheon.Instruments.PowerSupplies +{ + /// + /// Class to simulate any power supply module + /// + class KeysightN67xxPowerModule : PowerSupplyModule + { + private List _groupedModules; + private List _coupledModules; + private string _powerSupplySystemName; + private EthernetSockets.TcpClient _tcpClient; + IConfigurationFile _config; + + private ILogger _logger; + + /// + /// Constructor + /// + public KeysightN67xxPowerModule(string iniFilePath, string powerSupplySystemName) + { + _logger = LogManager.GetCurrentClassLogger(); + _powerSupplySystemName = powerSupplySystemName; + + _config = new ConfigurationFile(iniFilePath); + + string ipAddress = _config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.ETHERNET_ADDRESS.ToString()); + int port = 0; + Int32.TryParse(_config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.ETHERNET_PORT.ToString()), out port); + string moduleDef = _config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.MODULE_DEFINITION.ToString()); + string coupledModules = _config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.COUPLED_MODULES.ToString()); + string groupedModules = _config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.GROUPED_MODULES.ToString()); + + PowerModules = moduleDef.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries).ToList(); + _coupledModules = coupledModules.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries).ToList(); + _groupedModules = groupedModules.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries).ToList(); + + _tcpClient = new EthernetSockets.TcpClient(ipAddress, port); + _tcpClient.Initialize(); + _tcpClient.Connect(); + + ResetPowerSupplySystem(); + + bool systemRebooted = false; + if (_groupedModules.Count() > 1) + GroupModules(_groupedModules, out systemRebooted); + else if (_coupledModules.Count() > 1) + CoupleModules(_coupledModules); + + if (systemRebooted) + { + _tcpClient.Disconnect(); + _tcpClient.Connect(); + } + + if (_groupedModules.Count() > 1) + { + PowerModules.Clear(); + // since modules are grouped, we pick the first module as the representative module + PowerModules.Add(_groupedModules[0]); + } + + // build the power module map + string moduleIndex = ""; + double ovp = 0.0; + double ocp = 0.0; + double voltageSetPoint = 0.0; + double voltageSlewRate = -1.0; + + double minVoltage = 0.0; + double maxVoltage = 0.0; + double minCurrent = 0.0; + double maxCurrent = 0.0; + + for (int i = 0; i < PowerModules.Count(); i++) + { + string moduleName = PowerModules[i]; + + moduleIndex = _config.ReadValue(moduleName, PowerSupplyConfigIni.INDEX.ToString()); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.OCP.ToString()), out ocp); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.OVP.ToString()), out ovp); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.VOLTAGE_SETPOINT.ToString()), out voltageSetPoint); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.VOLTAGE_SLEW_RATE.ToString()), out voltageSlewRate); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.MIN_VOLTAGE.ToString()), out minVoltage); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.MAX_VOLTAGE.ToString()), out maxVoltage); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.MIN_CURRENT.ToString()), out minCurrent); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.MAX_CURRENT.ToString()), out maxCurrent); + + PowerModuleInfoDict[moduleName] = new Raytheon.Instruments.PowerSupplies.PowerSupplyModuleInfo(moduleIndex, ocp, ovp, voltageSetPoint, voltageSlewRate, minVoltage, maxVoltage, minCurrent, maxCurrent); + + ActivePowerModule = moduleName; + SetConstantVoltageMode(); + SetAndConfirmOvp(); + SetAndConfirmOcp(); + SetAndConfirmVoltageSetpoint(); + SetAndConfirmVoltageSlewRate(); + } + } + + /// + /// Enable or Disable Front Panel + /// + /// + /// + public override bool DisplayEnabled + { + set + { + SemObj?.Release(); + } + } + + /// + /// Enable or disable Front Panel + /// + /// + /// + public override bool FrontPanelEnabled + { + set + { + string command; + + try + { + lock (SyncObj) + { + if (value) + command = KeysightPowerSupplyScpiCommands.SET_FRONTPANEL_ENABLE_CMD + "\n"; + else + command = KeysightPowerSupplyScpiCommands.SET_FRONTPANEL_DISABLE_CMD + "\n"; + + SendCommand(command); + } + } + finally { SemObj?.Release(); } + } + } + + /// + /// Turn on power module's output + /// + /// + /// + public override void On() + { + try + { + lock (SyncObj) + { + CheckActivePowerModuleValidity(); + + string command = KeysightPowerSupplyScpiCommands.SET_OUTPUT_ENABLE_CMD + "," + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + SendCommand(command); + } + } + finally { SemObj?.Release(); } + } + + /// + /// Turn off power module's output + /// + /// + /// + public override void Off() + { + try + { + lock (SyncObj) + { + CheckActivePowerModuleValidity(); + + string command = KeysightPowerSupplyScpiCommands.SET_OUTPUT_DISABLE_CMD + "," + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + SendCommand(command); + } + } + finally { SemObj?.Release(); } + } + + /// + /// Perform self test + /// + /// + /// + public override SelfTestResult PerformSelfTest() + { + try + { + lock (SyncObj) + { + string command = KeysightPowerSupplyScpiCommands.SELFTEST_CMD + "\n"; + + string rsp = SendCommandAndGetResponse(command); + + string[] stringVec = rsp.Split(','); + + int status = -1; + Int32.TryParse(stringVec[0], out status); + + if (status != 0) + { + SelfTestResult = SelfTestResult.Fail; + throw new Exception($"{_powerSupplySystemName}'s self-test failed with error code: {status}"); + } + else + SelfTestResult = SelfTestResult.Pass; + } + } + finally { SemObj?.Release(); } + + return SelfTestResult; + } + + /// + /// Set constant voltage mode + /// + /// + /// + private void SetConstantVoltageMode() + { + lock (SyncObj) + { + string command = KeysightPowerSupplyScpiCommands.SET_CONSTANT_VOLTAGE_CMD + "," + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + SendCommand(command); + } + } + + /// + /// Set and Confirm OVP + /// + /// + /// + private void SetAndConfirmOvp() + { + lock (SyncObj) + { + string command = KeysightPowerSupplyScpiCommands.SET_OVP_CMD + " " + PowerModuleInfoDict[ActivePowerModule].overVoltageProtection_ + "," + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + SendCommand(command); + + command = KeysightPowerSupplyScpiCommands.READ_OVP_CMD + " " + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + string rsp = SendCommandAndGetResponse(command); + double ovp = 0.0; + + Double.TryParse(rsp, out ovp); + + if (ovp != PowerModuleInfoDict[ActivePowerModule].overVoltageProtection_) + throw new Exception($"Unable to set OVP. Expected OVP: {PowerModuleInfoDict[ActivePowerModule].overVoltageProtection_}. Actual: {ovp}"); + } + } + + /// + /// Set and Confirm OCP + /// + /// + /// + private void SetAndConfirmOcp() + { + lock (SyncObj) + { + string command = KeysightPowerSupplyScpiCommands.SET_OCP_CMD + " " + PowerModuleInfoDict[ActivePowerModule].overVoltageProtection_ + "," + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + SendCommand(command); + + command = KeysightPowerSupplyScpiCommands.READ_OCP_CMD + " " + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + string rsp = SendCommandAndGetResponse(command); + double ocp = 0.0; + + Double.TryParse(rsp, out ocp); + + if (ocp != PowerModuleInfoDict[ActivePowerModule].overVoltageProtection_) + throw new Exception($"Unable to set OCP. Expected OCP: {PowerModuleInfoDict[ActivePowerModule].overVoltageProtection_}. Actual: {ocp}"); + } + } + + /// + /// Set and Confirm Voltage Setpoint + /// + /// + /// + private void SetAndConfirmVoltageSetpoint() + { + lock (SyncObj) + { + string command = KeysightPowerSupplyScpiCommands.SET_VOLTAGE_SETPOINT_CMD + " " + PowerModuleInfoDict[ActivePowerModule].voltageSetpoint_ + "," + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + SendCommand(command); + + command = KeysightPowerSupplyScpiCommands.READ_VOLTAGE_SETPOINT_CMD + " " + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + string rsp = SendCommandAndGetResponse(command); + double voltage = 0.0; + + Double.TryParse(rsp, out voltage); + + if (voltage != PowerModuleInfoDict[ActivePowerModule].voltageSetpoint_) + throw new Exception($"Unable to set Voltage Setpoint. Expected Voltage Setpoint: {PowerModuleInfoDict[ActivePowerModule].voltageSetpoint_}. Actual: {voltage}"); + } + } + + /// + /// Set and Confirm Slew Rate + /// + /// + /// + private void SetAndConfirmVoltageSlewRate() + { + lock (SyncObj) + { + if (PowerModuleInfoDict[ActivePowerModule].voltageSlewRate_ > 0.0) + { + string command = KeysightPowerSupplyScpiCommands.SET_VOLTAGE_SLEW_RATE_CMD + " " + PowerModuleInfoDict[ActivePowerModule].voltageSlewRate_ + "," + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + SendCommand(command); + + command = KeysightPowerSupplyScpiCommands.READ_VOLTAGE_SLEW_RATE_CMD + " " + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + string rsp = SendCommandAndGetResponse(command); + double voltageSlewRate = 0.0; + + Double.TryParse(rsp, out voltageSlewRate); + + if (voltageSlewRate != PowerModuleInfoDict[ActivePowerModule].voltageSlewRate_) + throw new Exception($"Unable to set Voltage Slew Rate. Expected Voltage Slew Rate: {PowerModuleInfoDict[ActivePowerModule].voltageSlewRate_}. Actual: {voltageSlewRate}"); + } + } + } + + /// + /// Get error code + /// + /// + /// + protected override string GetErrorCode(out int errorCode) + { + errorCode = 0; + string rtn = ""; + + lock (SyncObj) + { + string command = KeysightPowerSupplyScpiCommands.READ_ERROR_CODE_CMD + "\n"; + + string rsp = SendCommandAndGetResponse(command); + + string[] stringVec = rsp.Split(','); + + Int32.TryParse(stringVec[0], out errorCode); + + if (stringVec.Length > 1) + { + rtn = stringVec[1]; + } + } + + + return rtn; + } + + /// + /// Read voltage + /// + /// + /// + protected override double ReadVoltage() + { + double val = 0.0; + + lock (SyncObj) + { + string command = KeysightPowerSupplyScpiCommands.READ_VOLTAGE_CMD + " " + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + string rsp = SendCommandAndGetResponse(command); + + Double.TryParse(rsp, out val); + } + + return val; + } + + /// + /// Read current + /// + /// + /// + protected override double ReadCurrent() + { + double val = 0.0; + + lock (SyncObj) + { + string command = KeysightPowerSupplyScpiCommands.READ_CURRENT_CMD + " " + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + string rsp = SendCommandAndGetResponse(command); + + Double.TryParse(rsp, out val); + } + + return val; + + } + + /// + /// Read protection status + /// + /// + /// + protected override int ReadProtectionStatus() + { + int val = -1; + + lock (SyncObj) + { + string command = KeysightPowerSupplyScpiCommands.READ_PROTECTION_STATUS_CMD + " " + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + string rsp = SendCommandAndGetResponse(command); + + Int32.TryParse(rsp, out val); + } + + return val; + } + + /// + /// Determine if module's output is on + /// + /// + /// + protected override bool IsOutputOn() + { + bool isOn = false; + + lock (SyncObj) + { + string command = KeysightPowerSupplyScpiCommands.READ_OUTPUT_STATUS_CMD + " " + PowerModuleInfoDict[ActivePowerModule].moduleNameFormat + "\n"; + + string rsp = SendCommandAndGetResponse(command); + + int status = -1; + + Int32.TryParse(rsp, out status); + + if (status == 1) + { + isOn = true; + } + } + + return isOn; + } + + /// + /// When modules are grouped, they act as one module + /// + /// + /// + private void GroupModules(List moduleList, out bool systemRebooted) + { + // 1. Group the channels + string groupListToDefine = "(@"; + string groupListToQuery = ""; + string moduleNumber = ""; + + systemRebooted = false; + + for (int i = 0; i < moduleList.Count; i++) + { + moduleNumber = _config.ReadValue(moduleList[i], PowerSupplyConfigIni.INDEX.ToString()); + + groupListToDefine += moduleNumber; + groupListToQuery += moduleNumber; + + // add a ',' if this is not the final element in the list + if (i < moduleList.Count() - 1) + { + groupListToDefine += ","; + groupListToQuery += ","; + } + else + { + groupListToDefine += ")"; + } + } + + groupListToQuery = "\"" + groupListToQuery + "\"\n"; + + // see if channels are grouped + string queryGroupCommand = KeysightPowerSupplyScpiCommands.QUERY_GROUP_CHANNELS + "\n"; + + for (int i = 1; i <= 2; i++) + { + string respStr = SendCommandAndGetResponse(queryGroupCommand); + + // if modules are not grouped + if (respStr != groupListToQuery) + { + groupListToDefine += "\n"; + + string groupCommand = KeysightPowerSupplyScpiCommands.SET_GROUP_DEFINE_CMD + " " + groupListToDefine; + + SendCommand(groupCommand); + } + else if (i == 1) + { + break; + } + else + { + string command = KeysightPowerSupplyScpiCommands.REBOOT_CMD + "\n"; + // after grouping the modules, need to reboot system for it to take effect + SendCommand(command); + + // wait 20 seconds for reboot + Thread.Sleep(20000); + + systemRebooted = true; + } + } + } + + /// + /// When modules are coupled, they turned on and off in unison + /// i.e turn on/off one module, all other coupled modules will automatically turn on/off + /// + /// + /// + private void CoupleModules(List moduleList) + { + string coupleListToDefine = ""; + string moduleNumber = ""; + + for (int i = 0; i < moduleList.Count(); i++) + { + moduleNumber = _config.ReadValue(moduleList[i], PowerSupplyConfigIni.INDEX.ToString()); + + coupleListToDefine += moduleNumber; + + // add a ',' if this is not the final element in the list + if (i < moduleList.Count() - 1) + { + coupleListToDefine += ","; + } + } + + coupleListToDefine += "\n"; + + // see if channels are grouped + string queryCoupleChannelCommand = KeysightPowerSupplyScpiCommands.QUERY_COUPLE_CHANNELS + "\n"; + + for (int i = 1; i <= 2; i++) + { + string respStr = SendCommandAndGetResponse(queryCoupleChannelCommand); + + string queryCoupleStateCommand = KeysightPowerSupplyScpiCommands.QUERY_COUPLE_STATE + "\n"; + string respStr2 = SendCommandAndGetResponse(queryCoupleStateCommand); + + if (coupleListToDefine != respStr || respStr2 == "0\n") + { + // send command to couple modules + string command = KeysightPowerSupplyScpiCommands.SET_COUPLE_CHANNELS_CMD + " " + coupleListToDefine; + SendCommand(command); + + // turn coupling on + command = KeysightPowerSupplyScpiCommands.SET_COUPLE_ON_CMD + "\n"; + SendCommand(command); + + // output protection on + command = KeysightPowerSupplyScpiCommands.SET_COUPLE_OUTPUT_PROTECT_ON_CMD + "\n"; + SendCommand(command); + } + else if (i == 1) + break; + } + } + + /// + /// Reset Power Supply System + /// + /// + /// + private void ResetPowerSupplySystem() + { + // send the command + string command = KeysightPowerSupplyScpiCommands.RESET_CMD + "\n"; + SendCommand(command); + } + + /// + /// Send command + /// + /// + /// + private void SendCommand(string command) + { + lock (SyncObj) + { + byte[] msg = Encoding.ASCII.GetBytes(command); + + _tcpClient.Write(msg, (uint)msg.Length); + } + } + + /// + /// Send command and get response + /// + /// + /// + private string SendCommandAndGetResponse(string command) + { + lock (SyncObj) + { + byte[] readBuf = new byte[100]; + _tcpClient.SetReadTimeout(2000); + + int bytesRec = 0; + + SendCommand(command); + + try + { + bytesRec = (int)_tcpClient.Read(ref readBuf); + } + catch (SocketException ex) + { + throw new Exception("SocketException Error Code: " + ex.ErrorCode + $" ({((SocketError)ex.ErrorCode).ToString()})"); + } + + return Encoding.ASCII.GetString(readBuf, 0, bytesRec); + } + } + } +} diff --git a/Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67xxPowerSupply.cs b/Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67xxPowerSupply.cs new file mode 100644 index 0000000..1c03014 --- /dev/null +++ b/Source/DucLib/PowerSupplies/Keysight67XX/KeysightN67xxPowerSupply.cs @@ -0,0 +1,121 @@ +// 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 System; +using System.IO; +using System.Reflection; +using NLog; +using Raytheon.Common; + +namespace Raytheon.Instruments.PowerSupplies +{ + /// + /// Class for controlling a Keysightt N6700 Series Power Supply System + /// + public class KeysightN67xxPowerSupply : PowerSupply + { + private string _iniFilePath; + + private static ILogger _logger; + private readonly IConfigurationManager _configurationManager; + private readonly IConfiguration _configuration; + + /// + /// Constructor + /// + public KeysightN67xxPowerSupply(string deviceInstanceName, IConfigurationManager configurationManager, ILogger logger) + { + Name = deviceInstanceName; + _logger = logger; + _configurationManager = configurationManager; + + // configuration obtained from [deviceInstanceName].xml file + _configuration = _configurationManager.GetConfiguration(Name); + + string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + _iniFilePath = Path.Combine(assemblyFolder, _configuration.GetConfigurationValue(deviceInstanceName, PowerSupplyConfigXml.INI_FILE_PATH.ToString())); + } + + /// + /// Perform shutdown + /// + /// + /// + public override void Shutdown() + { + } + + /// + /// Perform reset + /// + /// + /// + public override void Reset() + { + } + + /// + /// Clear errors + /// + /// + /// + public override bool ClearErrors() + { + return true; + } + + /// + /// Implement Indexer in order to access a specific power module + /// + /// + /// + public override PowerSupplyModule this[object powerDeviceId] + { + get + { + string powerDeviceName = String.Empty; + + if (powerDeviceId != null && (powerDeviceId.GetType().IsEnum || powerDeviceId is string)) + { + powerDeviceName = powerDeviceId.ToString(); + } + else if (powerDeviceId != null) + { + throw new ArgumentException($"{nameof(powerDeviceId)} must be null or enumerated or string type"); + } + + _powerSupplyModule.GetSemphamore().WaitOne(); + + if (powerDeviceId != null) + _powerSupplyModule.SetActivePowerModule(powerDeviceName); + + return _powerSupplyModule; + } + } + + /// + /// Group or couple modules as specified in config file + /// Gather information for each power module from config file + /// + /// + /// + public override void Initialize() + { + _powerSupplyModule = new KeysightN67xxPowerModule(_iniFilePath, Name); + } + } +} diff --git a/Source/DucLib/PowerSupplies/Keysight67XX/KeysightPowerSupplyScpiCommands.cs b/Source/DucLib/PowerSupplies/Keysight67XX/KeysightPowerSupplyScpiCommands.cs new file mode 100644 index 0000000..12694dd --- /dev/null +++ b/Source/DucLib/PowerSupplies/Keysight67XX/KeysightPowerSupplyScpiCommands.cs @@ -0,0 +1,80 @@ +/*------------------------------------------------------------------------- +// 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 System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Raytheon.Instruments.PowerSupplies +{ + public static class KeysightPowerSupplyScpiCommands + { + public static string CLEAR_CMD = "*CLS"; + public static string RESET_CMD = "*RST"; + public static string SELFTEST_CMD = "*TST?"; + public static string READ_ERROR_CODE_CMD = "SYST:ERR?"; + public static string REBOOT_CMD = "SYST:REB"; + + // panel disable/enable commands + public static string SET_FRONTPANEL_DISABLE_CMD = "SYST:COMM:RLST RWL"; + public static string SET_FRONTPANEL_ENABLE_CMD = "SYST:COMM:RLST REM"; + + // watchdog commands + public static string SET_WATCHDOGDELAY_CMD = "OUTP:PROT:WDOG:DEL"; + public static string SET_WATCHDOGON_CMD = "OUTP:PROT:WDOG ON"; + public static string SET_WATCHDOGOFF_CMD = "OUTP:PROT:WDOG OFF"; + + // coupling commands + public static string SET_COUPLE_CHANNELS_CMD = "OUTP:COUP:CHAN"; + public static string SET_COUPLE_ON_CMD = "OUTP:COUP ON"; + public static string SET_COUPLE_OUTPUT_PROTECT_ON_CMD = "OUTP:PROT:COUP ON"; + public static string QUERY_COUPLE_CHANNELS = "OUTP:COUP:CHAN?"; + public static string QUERY_COUPLE_STATE = "OUTP:COUP?"; + + // Grouping Commands + public static string SET_GROUP_DEFINE_CMD = "SYST:GRO:DEF"; + public static string UNGROUP_ALL_CHANNELS_CMD = "SYST:GRO:DEL:ALL"; + public static string QUERY_GROUP_CHANNELS = "SYST:GRO:CAT?"; + + // current commands + public static string SET_OCP_CMD = "CURR:LEV"; + public static string SET_OCP_ON_CMD = "CURR:PROT:STAT ON"; + public static string READ_CURRENT_CMD = "MEAS:CURR?"; + public static string READ_OCP_CMD = "CURR:LEV?"; + + // voltage commands + public static string SET_OVP_CMD = "VOLT:PROT"; + public static string SET_VOLTAGE_SLEW_RATE_CMD = "VOLT:SLEW"; + public static string SET_VOLTAGE_SETPOINT_CMD = "VOLT:LEV"; + public static string SET_CONSTANT_VOLTAGE_CMD = "STAT:OPER:ENAB 1"; + public static string READ_VOLTAGE_CMD = "MEAS:VOLT?"; + public static string READ_VOLTAGE_SETPOINT_CMD = "VOLT?"; + public static string READ_OVP_CMD = "VOLT:PROT?"; + public static string READ_VOLTAGE_SLEW_RATE_CMD = "VOLT:SLEW?"; + + // set output commands + public static string SET_OUTPUT_DISABLE_CMD = "OUTP OFF"; + public static string SET_OUTPUT_ENABLE_CMD = "OUTP ON"; + + //query status + public static string READ_OUTPUT_STATUS_CMD = "OUTP?"; + public static string READ_ERROR_STATUS_CMD = "SYST:ERR?"; + public static string READ_PROTECTION_STATUS_CMD = "STAT:QUES:COND?"; + } +} diff --git a/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupply.cs b/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupply.cs new file mode 100644 index 0000000..960964b --- /dev/null +++ b/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupply.cs @@ -0,0 +1,63 @@ +/*------------------------------------------------------------------------- +// 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 System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Raytheon.Instruments +{ + /// + /// Base class that defines interface for power supply systems + /// + public abstract class PowerSupply : Instrument + { + protected PowerSupplyModule _powerSupplyModule; + + /// + /// Implement Indexer in order to access a specific power module + /// + /// + /// + public virtual PowerSupplyModule this[object i] + { + get { return null; } + } + + /// + /// Get power supply module info dictionary + /// + /// + /// + public Dictionary GetPowerSupplyModuleInfoDict() + { + return _powerSupplyModule.PowerModuleInfoDict; + } + + /// + /// Get power supply module names + /// + /// + /// + public List GetPowerSupplyModuleNames() + { + return _powerSupplyModule.PowerModules; + } + } +} diff --git a/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyBasic.csproj b/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyBasic.csproj new file mode 100644 index 0000000..02bf060 --- /dev/null +++ b/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyBasic.csproj @@ -0,0 +1,20 @@ + + + + net472 + Library + Raytheon.Instruments.PowerSupplyBasic + PowerSupply Basic + PowerSupply Basic + + 1.1.0.0 + + + + + + + + + + diff --git a/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyConfigIni.cs b/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyConfigIni.cs new file mode 100644 index 0000000..c1c8c3d --- /dev/null +++ b/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyConfigIni.cs @@ -0,0 +1,47 @@ +/*------------------------------------------------------------------------- +// 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 System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Raytheon.Instruments.PowerSupplies +{ + public enum PowerSupplyConfigIni + { + // list all the sections here + GENERAL, + + // list all the keys here + ETHERNET_ADDRESS, + ETHERNET_PORT, + MODULE_DEFINITION, + COUPLED_MODULES, + GROUPED_MODULES, + INDEX, + OCP, + OVP, + VOLTAGE_SETPOINT, + VOLTAGE_SLEW_RATE, + MIN_VOLTAGE, + MAX_VOLTAGE, + MIN_CURRENT, + MAX_CURRENT + } +} diff --git a/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyConfigXml.cs b/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyConfigXml.cs new file mode 100644 index 0000000..676aed9 --- /dev/null +++ b/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyConfigXml.cs @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- +// 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 System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Raytheon.Instruments.PowerSupplies +{ + public enum PowerSupplyConfigXml + { + // list all the keys here + INI_FILE_PATH + } +} diff --git a/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyModule.cs b/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyModule.cs new file mode 100644 index 0000000..178fbd8 --- /dev/null +++ b/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyModule.cs @@ -0,0 +1,207 @@ +/*------------------------------------------------------------------------- +// 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 Raytheon.Instruments.PowerSupplies; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Raytheon.Instruments +{ + /// + /// Base class that defines interface for power supply modules + /// + public abstract class PowerSupplyModule + { + protected Semaphore SemObj = new System.Threading.Semaphore(initialCount: 1, maximumCount: 1); + protected object SyncObj = new object(); + protected string ActivePowerModule; + + public List PowerModules { get; protected set; } + + public Dictionary PowerModuleInfoDict { get; protected set; } + + /// + /// Constructor + /// + public PowerSupplyModule() + { + PowerModuleInfoDict = new Dictionary(); + } + + /// + /// DisplayEnabled - some instruments will be no-op, but likely needed on all + /// will shut down any display on the hardware to hide any + /// classified information if visible + /// + public virtual bool DisplayEnabled + { + get; + set; + } + + /// + /// FrontPanelEnabled - some instruments will be no-op, but likely needed on all + /// has the ability to disable any panel buttons, so that + /// the hardware may not be changed by human touch + /// + public virtual bool FrontPanelEnabled + { + private get; + set; + } + + /// + /// SelfTestResult - end result of the hardware self test performed + /// + public SelfTestResult SelfTestResult + { + get; + set; + } + + /// + /// PerformSelfTest - do a hardware self test + /// + /// result of the self test + public abstract SelfTestResult PerformSelfTest(); + + /// + /// Set active module + /// + /// + /// + public void SetActivePowerModule(string activePowerModule) + { + ActivePowerModule = activePowerModule; + } + + /// + /// Check if active module is valid + /// + /// + /// + protected void CheckActivePowerModuleValidity() + { + if (ActivePowerModule == null || ActivePowerModule.Length == 0) + throw new Exception($"{nameof(ActivePowerModule)} is not set"); + + if (!PowerModuleInfoDict.ContainsKey(ActivePowerModule)) + throw new Exception($"Invalid power module: {ActivePowerModule}"); + } + + /// + /// Return semaphore + /// + /// + /// + public Semaphore GetSemphamore() { return SemObj; } + + /// + /// Turn on power module's output + /// + /// + /// + public abstract void On(); + + /// + /// Turn off power module's output + /// + /// + /// + public abstract void Off(); + + /// + /// Determine if module's output is on + /// + /// + /// + protected virtual bool IsOutputOn() + { + bool isOn = false; + + lock (SyncObj) + { + CheckActivePowerModuleValidity(); + + isOn = PowerModuleInfoDict[ActivePowerModule].isOn_; + } + + return isOn; + } + + /// + /// Read power supply module's data all at once + /// + /// + /// + public virtual void ReadPowerSupplyData(out double volts, out double current, out double voltSetpoint, out bool isOn, out int faultStatus) + { + volts = 0.0; + current = 0.0; + voltSetpoint = 0.0; + isOn = false; + faultStatus = 0; + try + { + lock (SyncObj) + { + CheckActivePowerModuleValidity(); + + volts = ReadVoltage(); + current = ReadCurrent(); + voltSetpoint = PowerModuleInfoDict[ActivePowerModule].voltageSetpoint_; + isOn = IsOutputOn(); + faultStatus = ReadProtectionStatus(); + } + } + finally { SemObj?.Release(); }; + } + + /// + /// Read voltage + /// + /// + /// + protected abstract double ReadVoltage(); + + /// + /// Read current + /// + /// + /// + protected abstract double ReadCurrent(); + + /// + /// Read protection status + /// + /// + /// + protected abstract int ReadProtectionStatus(); + + /// + /// Get error code + /// + /// + /// + protected abstract string GetErrorCode(out int errorCode); + } +} diff --git a/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyModuleInfo.cs b/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyModuleInfo.cs new file mode 100644 index 0000000..443722f --- /dev/null +++ b/Source/DucLib/PowerSupplies/PowerSupplyBasic/PowerSupplyModuleInfo.cs @@ -0,0 +1,70 @@ +/*------------------------------------------------------------------------- +// 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 System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Raytheon.Instruments.PowerSupplies +{ + public class PowerSupplyModuleInfo + { + public PowerSupplyModuleInfo() + { + overCurrentProtection_ = -1.0; + overVoltageProtection_ = -1.0; + voltageSetpoint_ = -1.0; + voltageSlewRate_ = -1.0; + voltageLowerLimit_ = -1.0; + voltageUpperLimit_ = -1.0; + currentLowerLimit_ = -1.0; + currentUpperLimit_ = -1.0; + isOn_ = false; + faultStatus = -1; + } + + public PowerSupplyModuleInfo(string moduleIndex, double overCurrentProtection, double overVoltageProtection, double voltageSetpoint, double voltageSlewRate, double minVoltage, double maxVoltage, double minCurrent, double maxCurrent) + { + overCurrentProtection_ = overCurrentProtection; + overVoltageProtection_ = overVoltageProtection; + voltageSetpoint_ = voltageSetpoint; + voltageSlewRate_ = voltageSlewRate; + voltageLowerLimit_ = minVoltage; + voltageUpperLimit_ = maxVoltage; + currentLowerLimit_ = minCurrent; + currentUpperLimit_ = maxCurrent; + isOn_ = false; + faultStatus = -1; + + moduleNameFormat = "(@" + moduleIndex + ")"; + } + + public string moduleNameFormat; + public double overCurrentProtection_; + public double overVoltageProtection_; + public double voltageLowerLimit_; + public double voltageUpperLimit_; + public double currentLowerLimit_; + public double currentUpperLimit_; + public double voltageSetpoint_; + public double voltageSlewRate_; + public bool isOn_; + public int faultStatus; + } +} diff --git a/Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplyModuleSim.cs b/Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplyModuleSim.cs new file mode 100644 index 0000000..b789ec5 --- /dev/null +++ b/Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplyModuleSim.cs @@ -0,0 +1,250 @@ +/*------------------------------------------------------------------------- +// 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 System; +using System.Collections.Generic; +using System.Linq; +using NLog; +using Raytheon.Common; + +namespace Raytheon.Instruments.PowerSupplies +{ + /// + /// Class to simulate any power supply module + /// + class PowerSupplyModuleSim : PowerSupplyModule + { + private List _groupedModules; + private List _coupledModules; + private string _powerSupplySystemName; + private bool _frontPanelEnabled = true; + + private ILogger _logger; + + /// + /// Constructor + /// + public PowerSupplyModuleSim(string iniFilePath, string powerSupplySystemName) + { + _logger = LogManager.GetCurrentClassLogger(); + _powerSupplySystemName = powerSupplySystemName; + + IConfigurationFile config = new ConfigurationFile(iniFilePath); + + string moduleDef = config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.MODULE_DEFINITION.ToString()); + string coupledModules = config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.COUPLED_MODULES.ToString()); + string groupedModules = config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.GROUPED_MODULES.ToString()); + + PowerModules = moduleDef.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries).ToList(); + _coupledModules = coupledModules.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries).ToList(); + _groupedModules = groupedModules.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries).ToList(); + + if (_groupedModules.Count() > 1) + { + PowerModules.Clear(); + // since modules are grouped, we pick the first module as the representative module + PowerModules.Add(_groupedModules[0]); + } + + // build the power module map + string moduleIndex = ""; + double ovp = 0.0; + double ocp = 0.0; + double voltageSetPoint = 0.0; + double voltageSlewRate = 0.0; + + double minVoltage = 0.0; + double maxVoltage = 0.0; + double minCurrent = 0.0; + double maxCurrent = 0.0; + + for (int i = 0; i < PowerModules.Count(); i++) + { + string moduleName = PowerModules[i]; + + moduleIndex = config.ReadValue(moduleName, PowerSupplyConfigIni.INDEX.ToString()); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.OCP.ToString()), out ocp); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.OVP.ToString()), out ovp); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.VOLTAGE_SETPOINT.ToString()), out voltageSetPoint); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.VOLTAGE_SLEW_RATE.ToString()), out voltageSlewRate); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.MIN_VOLTAGE.ToString()), out minVoltage); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.MAX_VOLTAGE.ToString()), out maxVoltage); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.MIN_CURRENT.ToString()), out minCurrent); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.MAX_CURRENT.ToString()), out maxCurrent); + + PowerModuleInfoDict[moduleName] = new Raytheon.Instruments.PowerSupplies.PowerSupplyModuleInfo(moduleIndex, ocp, ovp, voltageSetPoint, voltageSlewRate, minVoltage, maxVoltage, minCurrent, maxCurrent); + } + } + + /// + /// Enable or Disable Front Panel + /// + /// + /// + public override bool DisplayEnabled + { + set { SemObj?.Release(); } + } + + /// + /// Enable or disable Front Panel + /// + /// + /// + public override bool FrontPanelEnabled + { + set {_frontPanelEnabled = value; SemObj?.Release(); } + } + + /// + /// Turn on power module's output + /// + /// + /// + public override void On() + { + try + { + lock (SyncObj) + { + CheckActivePowerModuleValidity(); + + if (_coupledModules.Contains(ActivePowerModule)) + { + foreach (string module in _coupledModules) + { + PowerModuleInfoDict[module].isOn_ = true; + } + } + else + PowerModuleInfoDict[ActivePowerModule].isOn_ = true; + } + } + finally { SemObj?.Release(); } + } + + /// + /// Turn off power module's output + /// + /// + /// + public override void Off() + { + try + { + lock (SyncObj) + { + CheckActivePowerModuleValidity(); + + if (_coupledModules.Contains(ActivePowerModule)) + { + foreach (string module in _coupledModules) + { + PowerModuleInfoDict[module].isOn_ = false; + } + } + else + PowerModuleInfoDict[ActivePowerModule].isOn_ = false; + } + } + finally { SemObj?.Release(); }; + } + + /// + /// Perform self test + /// + /// + /// + public override SelfTestResult PerformSelfTest() + { + try + { + lock (SyncObj) + { + SelfTestResult = SelfTestResult.Pass; + } + } + finally { SemObj?.Release(); }; + + return SelfTestResult; + } + + /// + /// Read voltage + /// + /// + /// + protected override double ReadVoltage() + { + double val = 0.0; + + lock (SyncObj) + { + if (PowerModuleInfoDict[ActivePowerModule].isOn_) + val = PowerModuleInfoDict[ActivePowerModule].voltageSetpoint_; + } + + return val; + } + + /// + /// Read current + /// + /// + /// + protected override double ReadCurrent() + { + double val = 0.0; + + lock (SyncObj) + { + if (PowerModuleInfoDict[ActivePowerModule].isOn_) + val = (PowerModuleInfoDict[ActivePowerModule].currentLowerLimit_ + PowerModuleInfoDict[ActivePowerModule].currentUpperLimit_) / 2.0; + } + + return val; + } + + /// + /// Read protection status + /// + /// + /// + protected override int ReadProtectionStatus() + { + lock (SyncObj) + { + return 0; + } + } + + /// + /// Get error code + /// + /// + /// + protected override string GetErrorCode(out int errorCode) + { + lock (SyncObj) + { + errorCode = 0; + return ""; + } + } + + } +} diff --git a/Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplySim.cs b/Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplySim.cs new file mode 100644 index 0000000..48d19a5 --- /dev/null +++ b/Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplySim.cs @@ -0,0 +1,119 @@ +/*------------------------------------------------------------------------- +// 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 System; +using System.IO; +using System.Reflection; +using NLog; +using Raytheon.Common; + +namespace Raytheon.Instruments.PowerSupplies +{ + /// + /// Class to simulate any power supply system + /// + public class PowerSupplySim : PowerSupply + { + private string _iniFilePath; + + private static ILogger _logger; + private readonly IConfigurationManager _configurationManager; + private readonly IConfiguration _configuration; + + /// + /// Constructor + /// + public PowerSupplySim(string deviceInstanceName, IConfigurationManager configurationManager, ILogger logger) + { + Name = deviceInstanceName; + _logger = logger; + _configurationManager = configurationManager; + _configuration = _configurationManager.GetConfiguration(Name); + + string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + _iniFilePath = Path.Combine(assemblyFolder,_configuration.GetConfigurationValue(deviceInstanceName, "IniFilePath")); + } + + /// + /// Perform shutdown + /// + /// + /// + public override void Shutdown() + { + } + + /// + /// Perform reset + /// + /// + /// + public override void Reset() + { + } + + /// + /// Clear errors + /// + /// + /// + public override bool ClearErrors() + { + return true; + } + + /// + /// Group or couple modules as specified in config file + /// Gather information for each power module from config file + /// + /// + /// + public override void Initialize() + { + _powerSupplyModule = new PowerSupplyModuleSim(_iniFilePath, Name); + } + + /// + /// Implement Indexer to obtain a power module + /// + /// + /// + public override PowerSupplyModule this[object powerDeviceId] + { + get + { + string powerDeviceName = String.Empty; + + if (powerDeviceId != null && (powerDeviceId.GetType().IsEnum || powerDeviceId is string)) + { + powerDeviceName = powerDeviceId.ToString(); + } + else if (powerDeviceId != null) + { + throw new ArgumentException($"{nameof(powerDeviceId)} must be null or enumerated or string type"); + } + + _powerSupplyModule.GetSemphamore().WaitOne(); + + if (powerDeviceId != null) + _powerSupplyModule.SetActivePowerModule(powerDeviceName); + + return _powerSupplyModule; + } + } + } +} diff --git a/Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplySim.csproj b/Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplySim.csproj new file mode 100644 index 0000000..87ccde8 --- /dev/null +++ b/Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplySim.csproj @@ -0,0 +1,32 @@ + + + + + net472 + Library + Raytheon.Instruments.PowerSupplies.Simulation + Power Supply Simulation + Power Supply Simulation + + + + + + 1.0.0 + + + + + + + + + + + + + + + diff --git a/Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplySimFactory.cs b/Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplySimFactory.cs new file mode 100644 index 0000000..fae00d2 --- /dev/null +++ b/Source/DucLib/PowerSupplies/PowerSupplySim/PowerSupplySimFactory.cs @@ -0,0 +1,114 @@ +/*------------------------------------------------------------------------- +// 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 System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using System.Reflection; + +namespace Raytheon.Instruments.PowerSupplies +{ + [ExportInstrumentFactory(ModelNumber = "PowerSupplySimulationFactory")] + public class PowerSupplySimulationFactory : IInstrumentFactory + { + /// + /// The supported interfaces + /// + private readonly List _supportedInterfaces = new List(); + private static ILogger _logger; + private readonly IConfigurationManager _configurationManager; + private const string DefaultConfigPath = @"C:\ProgramData\Raytheon\InstrumentManagerService"; + private static string DefaultPath; + + public PowerSupplySimulationFactory(string defaultConfigPath = DefaultConfigPath) + : this(null, defaultConfigPath) + { + } + + /// + /// COECommDeviceInstrumentFactory injection constructor + /// + /// + /// + /// + [ImportingConstructor] + public PowerSupplySimulationFactory([Import(AllowDefault = false)] IConfigurationManager configManager, + [Import(AllowDefault = true)] string defaultConfigPath = null) + { + DefaultPath = defaultConfigPath; + _logger = LogManager.GetCurrentClassLogger(); + + if (NLog.LogManager.Configuration == null) + { + var assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + NLog.LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(assemblyFolder + "\\nlog.config"); + } + + _configurationManager = configManager ?? GetConfigurationManager(); + _supportedInterfaces.Add(typeof(PowerSupply)); + } + + /// + /// Gets the instrument + /// + /// + /// + public IInstrument GetInstrument(string name) + { + return null; + } + + /// + /// Gets the instrument + /// + /// + /// + public object GetInstrument(string name, bool simulateHw) + { + try + { + return new PowerSupplySim(name, _configurationManager, _logger); + } + catch (Exception ex) + { + _logger.Error(ex, $"Unable to construct {name} instrument instance"); + return null; + } + } + + /// + /// Gets supported interfaces + /// + /// + public ICollection GetSupportedInterfaces() + { + return _supportedInterfaces.ToArray(); + } + + /// + /// returns confiuration based on the predefined path or default path c:/ProgramData/Raytheon/InstrumentManagerService + /// + /// + private static IConfigurationManager GetConfigurationManager() + { + return string.IsNullOrEmpty(DefaultPath) ? new RaytheonConfigurationManager() : new RaytheonConfigurationManager(DefaultPath); + } + } +} \ No newline at end of file diff --git a/Source/DucLib/TcpClient/TcpClient.cs b/Source/DucLib/TcpClient/TcpClient.cs new file mode 100644 index 0000000..16572e1 --- /dev/null +++ b/Source/DucLib/TcpClient/TcpClient.cs @@ -0,0 +1,226 @@ +/*------------------------------------------------------------------------- +// 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 System; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Text.RegularExpressions; + +namespace Raytheon.Instruments.EthernetSockets +{ + /// + /// Class for controlling a TCP client communication device + /// + public class TcpClient + { + #region PrivateClassMembers + + private Socket _sock; + private string _remoteAddress; + private int _remotePort; + private IPEndPoint _remoteEP = null; + private IPAddress _ipAddress = null; + private object _syncObj = new object(); + + #endregion + + #region Public Functions + + /// + /// Constructor + /// + /// + /// + public TcpClient(string remoteAddress, int remotePort) + { + _remoteAddress = remoteAddress; + _remotePort = remotePort; + } + + /// + /// initialize instrument + /// + public void Initialize() + { + // if remoteAddress is a hostname + if (!IPAddress.TryParse(_remoteAddress, out _ipAddress)) + { + string preferredSubnet = ""; + + IPHostEntry host = Dns.GetHostEntry(_remoteAddress); + foreach (IPAddress ip in host.AddressList) + { + AddressFamily af = ip.AddressFamily; + if (af == AddressFamily.InterNetwork) + { + if (preferredSubnet != String.Empty) + { + if (Regex.IsMatch(ip.ToString(), preferredSubnet, RegexOptions.IgnoreCase)) + _ipAddress = ip; + } + else + _ipAddress = ip; + + if (_ipAddress != null) + break; + } + } + } + + if (_ipAddress != null) + { + if (_remoteEP == null) + _remoteEP = new IPEndPoint(_ipAddress, _remotePort); + } + else + throw new Exception($"Unable to create IPEndPoint to {_remoteAddress}, port {_remotePort}"); + + if (_sock == null) + _sock = new Socket(_ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + } + + /// + /// Connect to remote host + /// + /// + public void Connect() + { + lock (_syncObj) + { + try + { + if (!_sock.Connected && IsRemoteHostAlive()) + _sock.Connect(_remoteEP); + } + catch (ObjectDisposedException) + { + _sock = new Socket(_ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + if (IsRemoteHostAlive()) + _sock.Connect(_remoteEP); + } + catch (Exception) { throw; } + } + } + + /// + /// Disconnect from remote host + /// + /// + public void Disconnect() + { + lock (_syncObj) + { + if (_sock.Connected) + { + _sock.Shutdown(SocketShutdown.Both); + _sock.Disconnect(true); + _sock.Close(); + } + } + } + + /// + /// Ping if remote host is alive + /// + /// true/false + bool IsRemoteHostAlive() + { + bool isRemoteHostAlive = true; + + //Do a ping test to see if the server is reachable + try + { + Ping pingTest = new Ping(); + PingReply reply = pingTest.Send(_ipAddress); + if (reply.Status != IPStatus.Success) + isRemoteHostAlive = false; + } + catch (PingException) + { + isRemoteHostAlive = false; + } + + //See if the tcp state is ok + if (_sock.Poll(5000, SelectMode.SelectRead) && (_sock.Available == 0)) + { + isRemoteHostAlive = false; + } + + return isRemoteHostAlive; + } + + /// + /// Read data from the device. + /// + /// + /// + /// The number of bytes read + public uint Read(ref byte[] dataBuf) + { + int bytesRec = 0; + lock (_syncObj) + { + try + { + bytesRec = _sock.Receive(dataBuf); + } + catch (SocketException) + { + bytesRec = 0; + } + } + + return (uint)bytesRec; + } + + /// + /// Sets the read timeout + /// + /// + public void SetReadTimeout(uint timeoutMs) + { + _sock.ReceiveTimeout = (int)timeoutMs; + } + + /// + /// Write data to device. + /// + /// + /// The number of bytes written + public uint Write(byte[] dataBuf, uint numBytesToWrite) + { + int bytesWritten = 0; + lock (_syncObj) + { + try + { + bytesWritten = _sock.Send(dataBuf, (int)numBytesToWrite, SocketFlags.None); + } + catch (SocketException) + { + bytesWritten = 0; + } + } + + return (uint)bytesWritten; + } + + #endregion + } +} diff --git a/Source/DucLib/TcpClient/TcpClient.csproj b/Source/DucLib/TcpClient/TcpClient.csproj new file mode 100644 index 0000000..0e8afd5 --- /dev/null +++ b/Source/DucLib/TcpClient/TcpClient.csproj @@ -0,0 +1,21 @@ + + + + + net472 + Library + TcpClient + TCP Client implementation + TCP Client implementation + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + + + + + + 1.0.0 + Debug;Release;Deploy + + + diff --git a/Source/Program.sln b/Source/Program.sln index 02375ec..4441917 100644 --- a/Source/Program.sln +++ b/Source/Program.sln @@ -362,6 +362,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerSupplyMeasurementManag EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Program", "Program\Program.csproj", "{FAFB2DB1-AF3A-4F78-8BBB-124C51C4D62A}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DucLib", "DucLib", "{F20B097A-6283-426E-A9B5-D71E498E4A78}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TcpClient", "DucLib\TcpClient\TcpClient.csproj", "{4D2E2A24-9FD4-49C9-8448-F7006ED790B8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeysightN67XX", "DucLib\PowerSupplies\Keysight67XX\KeysightN67XX.csproj", "{CCD1C6AA-2C4E-40E1-8233-20875B5833D3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerSupplySim", "DucLib\PowerSupplies\PowerSupplySim\PowerSupplySim.csproj", "{059FF15F-D78A-4727-BA84-16836EB9F2DF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerSupplyBasic", "DucLib\PowerSupplies\PowerSupplyBasic\PowerSupplyBasic.csproj", "{675101BD-867F-4268-838B-F1E673B9007A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PowerSupplies", "PowerSupplies", "{C2277D2F-C982-420A-AD8D-82452A83793B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1071,6 +1083,30 @@ Global {FAFB2DB1-AF3A-4F78-8BBB-124C51C4D62A}.Deploy|Any CPU.Build.0 = Deploy|Any CPU {FAFB2DB1-AF3A-4F78-8BBB-124C51C4D62A}.Release|Any CPU.ActiveCfg = Release|Any CPU {FAFB2DB1-AF3A-4F78-8BBB-124C51C4D62A}.Release|Any CPU.Build.0 = Release|Any CPU + {4D2E2A24-9FD4-49C9-8448-F7006ED790B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D2E2A24-9FD4-49C9-8448-F7006ED790B8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D2E2A24-9FD4-49C9-8448-F7006ED790B8}.Deploy|Any CPU.ActiveCfg = Deploy|Any CPU + {4D2E2A24-9FD4-49C9-8448-F7006ED790B8}.Deploy|Any CPU.Build.0 = Deploy|Any CPU + {4D2E2A24-9FD4-49C9-8448-F7006ED790B8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D2E2A24-9FD4-49C9-8448-F7006ED790B8}.Release|Any CPU.Build.0 = Release|Any CPU + {CCD1C6AA-2C4E-40E1-8233-20875B5833D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CCD1C6AA-2C4E-40E1-8233-20875B5833D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CCD1C6AA-2C4E-40E1-8233-20875B5833D3}.Deploy|Any CPU.ActiveCfg = Debug|Any CPU + {CCD1C6AA-2C4E-40E1-8233-20875B5833D3}.Deploy|Any CPU.Build.0 = Debug|Any CPU + {CCD1C6AA-2C4E-40E1-8233-20875B5833D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CCD1C6AA-2C4E-40E1-8233-20875B5833D3}.Release|Any CPU.Build.0 = Release|Any CPU + {059FF15F-D78A-4727-BA84-16836EB9F2DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {059FF15F-D78A-4727-BA84-16836EB9F2DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {059FF15F-D78A-4727-BA84-16836EB9F2DF}.Deploy|Any CPU.ActiveCfg = Deploy|Any CPU + {059FF15F-D78A-4727-BA84-16836EB9F2DF}.Deploy|Any CPU.Build.0 = Deploy|Any CPU + {059FF15F-D78A-4727-BA84-16836EB9F2DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {059FF15F-D78A-4727-BA84-16836EB9F2DF}.Release|Any CPU.Build.0 = Release|Any CPU + {675101BD-867F-4268-838B-F1E673B9007A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {675101BD-867F-4268-838B-F1E673B9007A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {675101BD-867F-4268-838B-F1E673B9007A}.Deploy|Any CPU.ActiveCfg = Deploy|Any CPU + {675101BD-867F-4268-838B-F1E673B9007A}.Deploy|Any CPU.Build.0 = Deploy|Any CPU + {675101BD-867F-4268-838B-F1E673B9007A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {675101BD-867F-4268-838B-F1E673B9007A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1223,6 +1259,11 @@ Global {9BE7316F-AA0D-46C5-9AC4-1038697884A0} = {22A60CBA-5ADA-47C6-95B4-EAEC014EC878} {C402EA41-F756-4270-946C-D3DC4E1BAEB5} = {CE2D75B9-FC4A-41C6-84B8-AD838A70C1FF} {FAFB2DB1-AF3A-4F78-8BBB-124C51C4D62A} = {4D2003A8-CBCB-498C-9186-355650A84D41} + {4D2E2A24-9FD4-49C9-8448-F7006ED790B8} = {F20B097A-6283-426E-A9B5-D71E498E4A78} + {CCD1C6AA-2C4E-40E1-8233-20875B5833D3} = {C2277D2F-C982-420A-AD8D-82452A83793B} + {059FF15F-D78A-4727-BA84-16836EB9F2DF} = {C2277D2F-C982-420A-AD8D-82452A83793B} + {675101BD-867F-4268-838B-F1E673B9007A} = {C2277D2F-C982-420A-AD8D-82452A83793B} + {C2277D2F-C982-420A-AD8D-82452A83793B} = {F20B097A-6283-426E-A9B5-D71E498E4A78} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {CA9C7EC5-FDF7-444C-99C8-7BDBE8AF4EDB}