diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bf72415 --- /dev/null +++ b/.gitignore @@ -0,0 +1,369 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +Source/TestStand/Reports +Source/Nuget/cache/ +Source/Nuget/SolutionPackages + +Thumbs.db + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +#*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/Source/Instruments/EthernetSockets/CommDeviceTcpClient/TcpClient.cs b/Source/Instruments/EthernetSockets/CommDeviceTcpClient/TcpClient.cs new file mode 100644 index 0000000..e8f6fbf --- /dev/null +++ b/Source/Instruments/EthernetSockets/CommDeviceTcpClient/TcpClient.cs @@ -0,0 +1,299 @@ +/*------------------------------------------------------------------------- +// 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.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +namespace Raytheon.Instruments.EthernetSockets +{ + /// + /// Class for controlling a TCP client communication device + /// + public class TcpClient : ICommDevice + { + #region PrivateClassMembers + + private Socket _sock; + private string _remoteAddress; + private int _remotePort; + private IPEndPoint _remoteEP = null; + private IPAddress _ipAddress = null; + private object _syncObj = new object(); + + private readonly string _name; + private State _state; + + /// + /// NLog logger + /// + private static ILogger _logger; + /// + /// Raytheon configuration + /// + private readonly IConfigurationManager _configurationManager; + private readonly IConfiguration _configuration; + + #endregion + + public bool ClearErrors() => false; + public bool FrontPanelEnabled { get => false; set => throw new NotImplementedException(); } + public bool DisplayEnabled { get => false; set => throw new NotImplementedException(); } + public string DetailedStatus => $"This is a TCP/IP Device called {_name}"; + public InstrumentMetadata Info => throw new NotImplementedException(); + public State Status => _state; + public string Name => _name; + public SelfTestResult PerformSelfTest() => SelfTestResult; + public SelfTestResult SelfTestResult => SelfTestResult.Unknown; + public void Open() => Initialize(); + public void Close() => Disconnect(); + public void Shutdown() => Disconnect(); + public void Reset() + { + Close(); + Open(); + } + + #region Public Functions + + /// + /// CommDevice factory constructor + /// + /// + /// + public TcpClient(string deviceInstanceName, IConfigurationManager configurationManager, ILogger logger, string remoteAddress = "", int remotePort = 0) + { + _name = deviceInstanceName; + + _state = State.Uninitialized; + + _logger = logger; + + _configurationManager = configurationManager; + + // configuration obtained from [deviceInstanceName].xml file + _configuration = _configurationManager.GetConfiguration(Name); + + if (string.IsNullOrEmpty(remoteAddress)) + { + _remoteAddress = _configuration.GetConfigurationValue(deviceInstanceName, TcpClientConfigXml.REMOTE_ADDRESS.ToString(), "127.0.0.1"); + } + else + { + _remoteAddress = remoteAddress; + } + + if (remotePort == 0) + { + _remotePort = _configuration.GetConfigurationValue(deviceInstanceName, TcpClientConfigXml.REMOTE_PORT.ToString(), 0); + } + else + { + _remotePort = remotePort; + } + } + + /// + /// 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/Instruments/EthernetSockets/CommDeviceTcpClient/TcpClient.csproj b/Source/Instruments/EthernetSockets/CommDeviceTcpClient/TcpClient.csproj new file mode 100644 index 0000000..fb157c4 --- /dev/null +++ b/Source/Instruments/EthernetSockets/CommDeviceTcpClient/TcpClient.csproj @@ -0,0 +1,33 @@ + + + + + net472 + Library + Raytheon.Instruments.EthernetSockets.TcpClient + Raytheon.Instruments + CommDevice TCP implementation + CommDevice TCP implementation + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + Raytheon Technologies + TEEC + Copyright © Raytheon Technologies $([System.DateTime]::get_now().ToString("yyyy")) + + + + + + 1.0.0 + Debug;Release;Deploy + + + + + + + + + + + diff --git a/Source/Instruments/EthernetSockets/CommDeviceTcpClient/TcpClientConfigXml.cs b/Source/Instruments/EthernetSockets/CommDeviceTcpClient/TcpClientConfigXml.cs new file mode 100644 index 0000000..a7f3f0d --- /dev/null +++ b/Source/Instruments/EthernetSockets/CommDeviceTcpClient/TcpClientConfigXml.cs @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- +// 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.EthernetSockets +{ + public enum TcpClientConfigXml + { + // List all the keys here + REMOTE_ADDRESS, + REMOTE_PORT + } +} diff --git a/Source/Instruments/EthernetSockets/CommDeviceTcpClient/TcpClientFactory.cs b/Source/Instruments/EthernetSockets/CommDeviceTcpClient/TcpClientFactory.cs new file mode 100644 index 0000000..74411ff --- /dev/null +++ b/Source/Instruments/EthernetSockets/CommDeviceTcpClient/TcpClientFactory.cs @@ -0,0 +1,122 @@ +/*------------------------------------------------------------------------- +// 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.EthernetSockets +{ + [ExportInstrumentFactory(ModelNumber = "EthernetSocketsTcpClientFactory")] + public class TcpClientFactory : 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 TcpClientFactory(string defaultConfigPath = DefaultConfigPath) + : this(null, defaultConfigPath) + { + } + + /// + /// COECommDeviceInstrumentFactory injection constructor + /// + /// + /// + /// + [ImportingConstructor] + public TcpClientFactory([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(ICommDevice)); + } + + /// + /// Gets the instrument + /// + /// + /// + public IInstrument GetInstrument(string name) + { + try + { + return new TcpClient(name, _configurationManager, _logger); + } + catch (Exception ex) + { + _logger.Error(ex, $"Unable to construct {name} instrument instance"); + return null; + } + } + + /// + /// Gets the instrument + /// + /// + /// + public object GetInstrument(string name, bool simulateHw) + { + try + { + return new TcpClient(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/Instruments/GeneralIntsrumentManager/GeneralInstrumentManager.cs b/Source/Instruments/GeneralIntsrumentManager/GeneralInstrumentManager.cs new file mode 100644 index 0000000..bba565b --- /dev/null +++ b/Source/Instruments/GeneralIntsrumentManager/GeneralInstrumentManager.cs @@ -0,0 +1,878 @@ +/*------------------------------------------------------------------------- +// 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.ComponentModel.Composition; +using Raytheon.Communication; +using Raytheon.Communication.Rpc; +using Raytheon.Logging; +using Raytheon.Composition; +using Raytheon.Common; +using System.Xml.Linq; +using Microsoft.Win32; +using System.IO; +using System.ServiceProcess; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Collections.ObjectModel; +using System.Reflection; +using System.IO.Ports; + +namespace Raytheon.Instruments +{ + public enum Mode + { + /// + /// instruments must be managed by the service (like RINSS) + /// + Service, + /// + /// ignore the service and initialize instruments directly + /// + StandAlone, + /// + /// dynamically identify if instrument service is running + /// + Auto + } + + /// + /// hybrid implementation of the instrument manager interface + /// will check if + /// + public class GeneralInstrumentManager : IInstrumentManager, IPartImportsSatisfiedNotification + { + #region Private Fields + + private readonly bool _haveService; + + private IUms _umsHost; + private IUmsClient _instrumentManager; + private IUmsClient _rpcInstrumentManagerHost; + + private bool _partsLoaded { get; set; } + + /// + /// PartsLocation - where the instrument manager should get it's MEF components + /// + public string _partsLocation { get; set; } + /// + /// ConfigLocation - where the configuration manager stores config files + /// specifically Instruments.xml + /// + public string _configLocation { get; set; } + + private List _availableInstruments = new List(); + private readonly Dictionary _factoryMap = new Dictionary(); + + private readonly Dictionary _instruments = new Dictionary(); + private readonly HashSet _instrumentTypes = new HashSet(); + + // simulation + private readonly bool _isThereHardware; + + #endregion + + #region Constants + + private const string NO_SERVER = "Client for communication to the server has not been setup"; + private const string SECTION = "RpcClient"; + + private const string RegistryValue = @"ConsumerInstrumentManagerPartsDirectory"; + + private const string RegistryValueNoRINSS = @"InstrumentManagerPartsDirectory"; + + private const string RegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Raytheon"; + + private const string DefaultName = "Default"; + private const string DefaultIP = "127.0.0.1"; + private const string DefaultPort = "8006"; + private const string DefaultMedia = "Tcp"; + private const string DefaultSerializer = "Fusion"; + + #endregion + + #region Imports + + [ImportMany(typeof(IInstrumentFactory))] + private Lazy[] InstrumentFactories { get; set; } + + [Import(typeof(IUmsFactory))] + private Lazy LazyUmsFactory { get; set; } + private IUmsFactory UmsFactory { get { return LazyUmsFactory?.Value; } } + + [Import(typeof(IConfigurationManager))] + private Lazy LazyConfigManager { get; set; } + private IConfigurationManager ConfigManager { get { return LazyConfigManager?.Value; } } + + [Import(typeof(IUmsClientFactory))] + private Lazy LazyUmsClientFactory { get; set; } + private IUmsClientFactory UmsClientFactory { get { return LazyUmsClientFactory?.Value; } } + + [Import(typeof(ILogFactory), AllowDefault = true)] + private Lazy LazyLogFactory { get; set; } + private ILogFactory LogFactory { get { return LazyLogFactory?.Value; } } + + + [ImportMany(typeof(IInstrumentProxyFactory))] + private Lazy[] ProxyFactories { get; set; } + + #endregion + + #region Logging + private static ILogger _logger; + + private static ILogger GetLogger() + { + FusionLogManager.Changed += l => _logger = l.GetLogger(); + return _logger; + } + #endregion + + /// + /// default constructor + /// in Auto mode the Instrument Manager will use RINSS based on the service running status + /// in Service mode the Instrument Manager must have the RINSS Service running + /// in StandAlone mode the Instrument Manager will ignore RINSS + /// + public GeneralInstrumentManager(Mode mode = Mode.Auto) + { + _haveService = CheckServiceRunningStatus("RINSS"); + if (mode == Mode.Service && !_haveService) + { + throw new Exception("RINSS Service is not running for Service mode"); + } + + if (mode == Mode.StandAlone) + { + _haveService = false; + } + + _logger = GetLogger(); + } + + /// + /// constructor to be used when no RINSS available to set parts location + /// + /// + public GeneralInstrumentManager(string partsLocation, Mode mode = Mode.Auto) + : this(mode) + { + _partsLocation = partsLocation; + } + + /// + /// constructor to be used when no RINSS available to set parts location and configuration location + /// + /// + /// + /// + public GeneralInstrumentManager(string partsLocation, string configLocation, bool isThereHardware = true, Mode mode = Mode.Auto) + : this(partsLocation, mode) + { + _configLocation= configLocation; + _isThereHardware = isThereHardware; + + } + + /// + /// Initializes this instance. + /// + public void Initialize() + { + try + { + //Setup the instrument part path + if (!string.IsNullOrWhiteSpace(_partsLocation) && !Directory.Exists(_partsLocation)) + { + _logger.Error($"Unable to id parts in this location: {_partsLocation}"); + _partsLocation = string.Empty; + } + + SetupPath(); + + //load the instruments + if (!_partsLoaded) + { + LoadParts(); + } + + if(_haveService) + { + // 1. Create the Ums Client + CreateUmsClient(); + _logger.Debug("created client"); + + // 2. Find out what instruments are available + _availableInstruments = new List(_rpcInstrumentManagerHost.Contract.EnumRpcInstruments()); + _logger.Debug("geting list of availible instruments"); + + // 3. Find all the instrument interfaces supported by proxy factories + InitializeFactories(); + _logger.Debug("initialized all the factories"); + } + else + { + //configure all the instruments found + ConfigureInstruments(); + } + } + catch (CompositionException ex) + { + _logger.ErrorException(ex, "Error in composition during Consumer Instrument Manager initialization"); + throw; + } + catch (Exception ex) + { + _logger.ErrorException(ex, "Error initializing the instrument manager"); + throw; + } + } + + /// + /// InitializeInstruments - init all the instruments + /// + public void InitializeInstruments() + { + _logger.Info("Instrument initialization complete"); + } + + /// + /// InitializeInstrument - inits a specific instrument + /// + /// instrument's unique name + public void InitializeInstrument(string instName) + { + } + + /// + /// implementation for IPartImportsSatisfiedNotification interface + /// + public void OnImportsSatisfied() + { + if (LogFactory != null && LogFactory != null) + { + FusionLogManager.Current = LogFactory; + } + } + + /// + /// Gets the generic instrument. + /// + /// The name. + /// + public IInstrument GetGenericInstrument(string name) + { + _logger.Trace("In ConsumerInstrumentManager in method GetGenericInstrument with name: {0} ", name); + return GetInstrument(name); + } + + /// + /// gets a specific instrument by name + /// the name should match one of the names in Instruments.xml file + /// + /// + /// + /// + public T GetInstrument(string name) where T : class + { + _logger.Trace($"Starting GetInstrument with name: {name}"); + + object inst = null; + if (_haveService) + { + try + { + string interfaceName = typeof(T).FullName; + if (typeof(IInstrument).FullName == interfaceName) + { + _logger.Trace($"GetInstrument with typeof(IInstrument).FullName == interfaceName: {interfaceName}"); + + //get the real interface behind the scenes + //first find the appropriate factory + RpcInstrumentDescriptor correctDesc = _availableInstruments.FirstOrDefault((desc) => 0 == string.Compare(name, desc.InstrumentName, true)); + if (null != correctDesc) + { + _logger.Trace($"GetInstrument with correctDesc.name: {correctDesc.InstrumentName}"); + + string temp = correctDesc.InstrumentInterfaces.FirstOrDefault(); + if (!string.IsNullOrWhiteSpace(temp)) + { + interfaceName = temp; + } + } + + _logger.Debug("Requested generic instrument, found {0} to be the correct interface", interfaceName); + } + + if (InstrumentIsAvailable(name) && FactoryIsAvailable(interfaceName)) + { + _logger.Trace($"GetInstrument with InstrumentIsAvailable(name) && FactoryIsAvailable(interfaceName) name: {name}, interfaceName: {interfaceName}"); + + IInstrumentProxyFactory factory = _factoryMap.Where((t) => 0 == string.Compare(t.Key, interfaceName, true)) + .Select(t => t.Value) + .FirstOrDefault(); + + if (null != factory) + { + inst = factory.GetInstrument(name); + _logger.Trace($"GetInstrument got an instrument (name: {name}) from factory: {factory}, interfaceName: {interfaceName}"); + } + else + { + _logger.Warn($"Could not find factory for interface: {interfaceName}, instrument: {name}"); + } + } + } + catch (InstrumentException ex) + { + _logger.WarnException(ex, ex.Message); + } + } + else + { + _instruments.TryGetValue(name.ToLower(), out inst); + } + + _logger.Trace($"GetInstrument returning with inst: {inst}"); + + return inst as T; + } + + /// + /// returns a collection of instrument names + /// + /// + public ICollection GetInstrumentNames() + { + _logger.Trace("Returning instrument list"); + + if (_haveService) + { + return _instrumentManager.Contract.GetInstrumentNames(); + } + else + { + return new ReadOnlyCollection(_instruments.Keys.ToList()); + } + } + + public string[] GetInstrumentNamesArray() + { + _logger.Debug("Getting Instrument Names Array"); + return GetInstrumentNames().ToArray(); + } + + /// + /// Gets instruments collection + /// + /// + public ICollection GetInstruments() + { + _logger.Debug("GetInstruments with null"); + return GetInstruments(null); + } + + /// + /// Gets instruments collection by type + /// + /// + /// + public ICollection GetInstruments(Type type) + { + _logger.Debug($"Entering GetInstruments with type {type}"); + + var instruments = new List(); + + if (_haveService) + { + if (null == _rpcInstrumentManagerHost) + { + _logger.Warn(NO_SERVER); + } + else + { + //gather all the instruments of the requested type + if (null == type) + { + type = typeof(IInstrument); + } + + _logger.Debug("GetInstruments geting collection"); + + var collection = from avail in _availableInstruments + where avail.InstrumentInterfaces.Contains(type.FullName) + select avail; + + _logger.Debug("GetInstruments got collection count = " + collection.Count()); + + MethodInfo method = typeof(GeneralInstrumentManager).GetMethod("GetInstrument"); + MethodInfo generic = method.MakeGenericMethod(type); + + foreach (var item in collection) + { + object[] objs = { item.InstrumentName }; + IInstrument created = generic.Invoke(this, objs) as IInstrument; + instruments.Add(created); + } + } + } + else + { + if(type == null) + { + instruments.AddRange(_instruments.Values); + } + else + { + foreach (var inst in _instruments.Values) + { + if (type.IsAssignableFrom(inst.GetType())) + { + instruments.Add(inst); + } + } + } + } + + return new ReadOnlyCollection(instruments); + } + + /// + /// returns instrument array of specific type + /// + /// + /// + /// + public object[] GetInstrumentsArray(Type type) + { + if (null == type) + { + throw new ArgumentNullException("type", "GetInstrumentsArray, cannot get null instrument types"); + } + + _logger.Debug($"GetInstrumentsArray with type {type}"); + + return GetInstruments(type).ToArray(); + } + + /// + /// returns instrument array + /// + /// + public object[] GetInstrumentsArray() + { + _logger.Debug("Get Instruments Array"); + return GetInstruments().ToArray(); + } + + /// + /// Shuts down this instance. + /// Close out the RPC host connection. Does not close / shutdown RINSS or any + /// + public void Shutdown() + { + _logger.Info("Shutting down instruments"); + + if (_haveService) + { + _rpcInstrumentManagerHost.Close(); + } + else + { + ShutdownInstruments(); + } + _logger.Info("Instrument shut down complete"); + } + + /// + /// Shuts down the instruments. + /// + public void ShutdownInstruments() + { + } + + /// + /// Shutdowns the instrument. + /// + /// Name of the inst. + public void ShutdownInstrument(string instName) + { + } + + #region Private Functions + + /// + /// for the Auto mode will check if RINSS available + /// + /// + /// + private bool CheckServiceRunningStatus(string serviceName) + { + if(!DoesServiceExist(serviceName)) + return false; + + ServiceController sc = new ServiceController(serviceName); + return sc.Status == ServiceControllerStatus.Running; + } + private static bool DoesServiceExist(string serviceName) + { + return ServiceController.GetServices().Any(serviceController => serviceController.ServiceName.Equals(serviceName)); + } + + /// + /// Load parts with RINSS running or without RINSS + /// + private void LoadParts() + { + _logger.Debug($"Loading Parts from path {_partsLocation}"); + + //install we are assuming will put the needed parts into a directory ./Parts just off the + //directory where the assembly is + MefHelper helper = new MefHelper(false, false); + try + { + helper.AddCatalog(_partsLocation, true); + helper.Container.ComposeParts(this); + + if(_haveService) + { + if (null == ConfigManager || null == UmsClientFactory || null == UmsFactory) + { + throw new CompositionException($"General Instrument Manager has null MEF components, please check MEF plugin location: {_partsLocation}"); + } + } + else + { + if (null == ConfigManager || null == InstrumentFactories) + { + throw new CompositionException($"Error during MEF composition, check MEF Part Location: {_partsLocation}"); + } + } + + _partsLoaded = true; + if(!string.IsNullOrEmpty(_configLocation)) + ConfigManager.ConfigurationStoragePath = _configLocation; + } + catch (CompositionException ex) + { + _logger.ErrorException(ex, ex.Message); + } + } + + /// + /// will set up path where either proxy instruments are (in case when RINSS running) + /// or where the actual instruments are (in case RINSS not running) + /// + /// + /// + /// + /// + private void SetupPath() + { + _logger.Trace("Setting up Instrument Manager parts location"); + if (string.IsNullOrEmpty(_partsLocation)) + { + string pf86 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86); + string pf = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); + + //ATEasy and other apps are messing with the previously used ./Parts locations + //so we have moved to using a registry entry that is created on install and refers + //to the directory installed to, the PartsLocation property still allows for custom directories + //to be used for the Consumer Instrument Manager + string defaultPath = _haveService ? $"{pf86}\\Raytheon\\RINSS-ConsumerIM\\Parts" : $"{pf86}\\Raytheon\\RINSS\\Parts\\CommonModuleInstruments"; + if (Environment.OSVersion.Version.Major < 6) + { + //if we are windows xp, then we need to look in a different default directory + defaultPath = _haveService ? $"{pf}\\Raytheon\\RINSS-ConsumerIM\\Parts" : $"{pf}\\Raytheon\\RINSS\\Parts\\CommonModuleInstruments"; + } + + var keyName = RegistryKey; + var valueName = _haveService ? RegistryValue : RegistryValueNoRINSS; + + string path = (string)Registry.GetValue(keyName, valueName, defaultPath); + + if (string.IsNullOrWhiteSpace(path) || !Directory.Exists(path)) + { + path = defaultPath; + } + + _partsLocation = path; + } + _logger.Trace($"Mef parts load Location is: {_partsLocation}"); + } + + /// + /// creates Umc client used in remote procedure calls + /// + /// + private void CreateUmsClient() + { + _logger.Trace("Loading Proxy Instrument Configuration Settings"); + + string configName = "ProxyInstruments"; + IConfiguration config = ConfigManager.GetConfiguration(configName); + + if (null == config) + { + string errorMessage = string.Format(@"Could not get configuration file, check configuration location for file: {0}", configName); + _logger.Error(errorMessage); + throw new ArgumentNullException(errorMessage); + } + + string rpcName = config.GetConfigurationValue(SECTION, "Name", string.Empty); + + //if the configuration element does not exist, then create the defaults + if (string.IsNullOrWhiteSpace(rpcName)) + { + _logger.Info("No Rpc Client Instrument Manager configuration found, creating default"); + config.SetConfigurationValue(SECTION, "Name", DefaultName); + config.SetConfigurationValue(SECTION, "IPAddress", DefaultIP); + config.SetConfigurationValue(SECTION, "Port", DefaultPort); + config.SetConfigurationValue(SECTION, "MediaType", DefaultMedia); + config.SetConfigurationValue(SECTION, "SerializerType", DefaultSerializer); + } + + _logger.Trace("Consumer Instrument Manager is creating Ums Client"); + + if (null == UmsClientFactory || null == UmsFactory) + { + var ex = new ArgumentNullException(string.Format("Ums components are null, please check MEF plugin location: {0}", _partsLocation)); + _logger.ErrorException(ex, ex.Message); + throw ex; + } + + string name = config.GetConfigurationValue(SECTION, "Name", DefaultName); + string ipAddress = config.GetConfigurationValue(SECTION, "IPAddress", DefaultIP); + string hostPort = config.GetConfigurationValue(SECTION, "Port", DefaultPort); + string mediaType = config.GetConfigurationValue(SECTION, "MediaType", DefaultMedia); + string serializerType = config.GetConfigurationValue(SECTION, "SerializerType", DefaultSerializer); + + //we already checked for null above! + _umsHost = UmsFactory.GetInstance(name, ipAddress, hostPort, UmsInstanceType.Client, mediaType, serializerType); + + //open a client for the instrument manager + _instrumentManager = UmsClientFactory.GetClient(_umsHost); + _instrumentManager.Open(); + + //open a client for the host server + _rpcInstrumentManagerHost = UmsClientFactory.GetClient(_umsHost); + _rpcInstrumentManagerHost.Open(); + } + + /// + /// will initialize factories for instuments managed under RINSS + /// + private void InitializeFactories() + { + _logger.Debug($"InitializeFactories ProxyFactories count = {ProxyFactories.Count()}"); + + foreach (var fact in ProxyFactories) + { + _logger.Debug("InitializeFactories fact=" + fact.Value); + //initialize each factory so it can create the clients + fact.Value.Initialize(_umsHost, UmsClientFactory); + + //map out the factories with their interface names + var availableInterfaces = fact.Value.GetSupportedInterfaces(); + _logger.Debug($"InitializeFactories availableInterfaces count = {availableInterfaces.Count}"); + + foreach (var face in availableInterfaces) + { + _logger.Debug($"InitializeFactories Interface = {face}"); + _factoryMap.Add(face.ToLower(), fact.Value); + } + } + } + + /// + /// will configure instruments when not managed by Service + /// + /// + private void ConfigureInstruments() + { + _logger.Info("Configuring Instruments"); + IConfiguration config = ConfigManager.GetConfiguration("Instruments"); + + if (null == config) + { + throw new ConfigurationException("could not find configuration file"); + } + + string rawConfig = config.GetXmlConfiguration("Instruments"); + if (string.IsNullOrWhiteSpace(rawConfig)) + { + _logger.Warn("No RPC configuration found, creating default 'Instruments'"); + config.SetXmlConfiguration("Instruments", new XElement("Instrument", + new XElement("Name", "Sample"), + new XElement("Factory", "Sample")).ToString()); + rawConfig = config.GetXmlConfiguration("Instruments"); + } + + _instrumentTypes.Add(typeof(IInstrument)); + if (0 == InstrumentFactories.Count()) + { + _logger.Warn($"There are no instrument factories registered using the following path: {Path.GetFullPath(_partsLocation)}"); + } + + XElement xmlConfig = XElement.Parse(rawConfig); + if (null == xmlConfig) + { + throw new ConfigurationException("could not parse configuration file"); + } + + var decendants = xmlConfig.Descendants("Instrument"); + if (null != decendants) + { + foreach (var instrument in decendants) + { + var instName = instrument.Element("Name").Value; + var instFactory = instrument.Element("Factory").Value; + _logger.Trace($"In ConfigureInstruments before factory call with XML name: {instName} and XML factory: {instFactory}"); + var factory = (from f in InstrumentFactories + where !string.IsNullOrWhiteSpace(f.Metadata.ModelNumber) && f.Metadata.ModelNumber.Equals(instFactory, StringComparison.OrdinalIgnoreCase) + select f).FirstOrDefault(); + + if (factory != null) + { + object inst = null; + try + { + // instantiate the applicable instrument + inst = factory.Value.GetInstrument(instName, !_isThereHardware); + _logger.Info($"Creating instrument '{instName}'"); + } + catch (Exception ex) + { + _logger.WarnException(ex, ex.Message); + inst = null; + } + + if (null == inst) + { + _logger.Warn($"Could not create the instrument: {instName}"); + } + else + { + var supported = factory.Value.GetSupportedInterfaces(); + if (null != supported) + { + //add the instrument + string txt = $"Adding instrument: Name - {instName}, Type - {inst.GetType()}"; + _instruments.Add(instName.ToLower(), inst); + foreach (var supportedInterface in supported) + { + _instrumentTypes.Add(supportedInterface); + _logger.Info($"{txt}, Interface - {supportedInterface}"); + } + } + else + { + _logger.Warn($"Did not see any supported interfaces for: {instName}"); + } + } + } + else + { + _logger.Warn($"{instName} did not have a matching factory with supported type {instFactory}"); + + if (InstrumentFactories.Count() > 0) + { + var factories = new StringBuilder(); + factories.Append("Available Factory types loaded: "); + foreach (var kvp in InstrumentFactories) + { + factories.AppendLine(); + factories.AppendFormat(" {0}", kvp.Metadata.ModelNumber); + } + _logger.Info(factories.ToString()); + } + } + } + } + else + { + _logger.Warn("could not find instrument section of configuration"); + } + } + + /// + /// checks if instrument is available + /// + /// + /// + private bool InstrumentIsAvailable(string name) + { + //check if our host has a instrument by this name available to us + if (!_availableInstruments.Any(t => 0 == string.Compare(t.InstrumentName, name, true))) + { + _logger.Warn($"{name} instrument not available"); + return false; + } + return true; + } + + /// + /// checks if instrument factory is available + /// + /// + /// + private bool FactoryIsAvailable(string interfaceName) + { + bool bReturn = false; + + if (typeof(IInstrument).FullName == interfaceName) + { + _logger.Debug($"In GeneralInstrumentManager in method FactoryIsAvailable with typeof(IInstrument).FullName == interfaceName : {interfaceName}"); + bReturn = true; + } + else + { + //check if we have a factory that supports this interface + var sb = new StringBuilder(); + foreach (KeyValuePair x in _factoryMap) + { + sb.Append("FactoryMap IInstrumentProxyFactory: key = "); + sb.Append(x.Key); + sb.Append(" value = "); + sb.Append(x.Value); + sb.Append(" supportedInterfaces = "); + sb.Append(x.Value.GetSupportedInterfaces()); + sb.Append(Environment.NewLine); + } + + _logger.Debug(sb.ToString()); + + var kvp = _factoryMap.Where((t) => 0 == string.Compare(t.Key, interfaceName, true)) + .Select(t => new { t.Key, t.Value }) + .FirstOrDefault(); + + if (null == kvp) + { + _logger.Warn($"{interfaceName} interface proxy factory not found"); + } + bReturn = kvp != null; + } + return bReturn; + } + + #endregion + + } +} diff --git a/Source/Instruments/GeneralIntsrumentManager/GeneralIntsrumentManager.csproj b/Source/Instruments/GeneralIntsrumentManager/GeneralIntsrumentManager.csproj new file mode 100644 index 0000000..304b978 --- /dev/null +++ b/Source/Instruments/GeneralIntsrumentManager/GeneralIntsrumentManager.csproj @@ -0,0 +1,35 @@ + + + + net472 + Library + Raytheon.Instruments.InstrumentManager.GeneralInstrumentManager + Raytheon.Instruments + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + Raytheon Technologies + General Instrument Manager + TEEC + Copyright © Raytheon Technologies $([System.DateTime]::get_now().ToString("yyyy")) + Instrument Manager that works with RINSS or without RINSS + + 1.4.1 + Debug;Release;Deploy + + + + + + + + + + + + + + + + + + diff --git a/Source/Instruments/PowerSupplies/Keysight67XX/KeysightN67XX.csproj b/Source/Instruments/PowerSupplies/Keysight67XX/KeysightN67XX.csproj new file mode 100644 index 0000000..eadf81c --- /dev/null +++ b/Source/Instruments/PowerSupplies/Keysight67XX/KeysightN67XX.csproj @@ -0,0 +1,43 @@ + + + + + net472 + Library + Raytheon.Instruments.PowerSupplies.Keysight67XX + Raytheon.Instruments + Keysight 67XX Series Power Supply + Keysight 67XX Series Power Supply + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + Raytheon Technologies + TEEC + Copyright © Raytheon Technologies $(Year) + + + + + + 1.0.0 + + + + + + + + + + + + + + + + + + + diff --git a/Source/Instruments/PowerSupplies/Keysight67XX/KeysightN67xxPowerFactory.cs b/Source/Instruments/PowerSupplies/Keysight67XX/KeysightN67xxPowerFactory.cs new file mode 100644 index 0000000..f5cbe95 --- /dev/null +++ b/Source/Instruments/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/Instruments/PowerSupplies/Keysight67XX/KeysightN67xxPowerModule.cs b/Source/Instruments/PowerSupplies/Keysight67XX/KeysightN67xxPowerModule.cs new file mode 100644 index 0000000..91a647e --- /dev/null +++ b/Source/Instruments/PowerSupplies/Keysight67XX/KeysightN67xxPowerModule.cs @@ -0,0 +1,663 @@ +/*------------------------------------------------------------------------- +// 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(), Raytheon.Common.GeneralConstants.DefaultConfigValue); + int port = 0; + Int32.TryParse(_config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.ETHERNET_PORT.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out port); + string moduleDef = _config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.MODULE_DEFINITION.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue); + string coupledModules = _config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.COUPLED_MODULES.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue); + string groupedModules = _config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.GROUPED_MODULES.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue); + + List 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(), Raytheon.Common.GeneralConstants.DefaultConfigValue); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.OCP.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out ocp); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.OVP.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out ovp); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.VOLTAGE_SETPOINT.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out voltageSetPoint); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.VOLTAGE_SLEW_RATE.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out voltageSlewRate); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.MIN_VOLTAGE.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out minVoltage); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.MAX_VOLTAGE.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out maxVoltage); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.MIN_CURRENT.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out minCurrent); + Double.TryParse(_config.ReadValue(moduleName, PowerSupplyConfigIni.MAX_CURRENT.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), 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 + { + get { SemObj?.Release(); throw new NotImplementedException(); } + 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(), Raytheon.Common.GeneralConstants.DefaultConfigValue); + + 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(), Raytheon.Common.GeneralConstants.DefaultConfigValue); + + 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/Instruments/PowerSupplies/Keysight67XX/KeysightN67xxPowerSupply.cs b/Source/Instruments/PowerSupplies/Keysight67XX/KeysightN67xxPowerSupply.cs new file mode 100644 index 0000000..bb39909 --- /dev/null +++ b/Source/Instruments/PowerSupplies/Keysight67XX/KeysightN67xxPowerSupply.cs @@ -0,0 +1,125 @@ +// UNCLASSIFIED +/*------------------------------------------------------------------------- +RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +COMPANY. + +THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. +GOVERNMENT. + +UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +-------------------------------------------------------------------------*/ + +using NLog; +using Raytheon.Common; +using Raytheon.Instruments.EthernetSockets; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +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(), $".\\{Raytheon.Common.GeneralConstants.InstrumentConfigFolder}\\{deviceInstanceName}.ini")); + } + + /// + /// 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 + { + if (!(powerDeviceId == null || powerDeviceId.GetType().IsEnum)) + { + throw new ArgumentException($"{nameof(powerDeviceId)} must be an enumerated type or null"); + } + + _powerSupplyModule.GetSemphamore().WaitOne(); + + if (powerDeviceId != null) + _powerSupplyModule.SetActivePowerModule(powerDeviceId.ToString()); + + 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/Instruments/PowerSupplies/Keysight67XX/KeysightPowerSupplyScpiCommands.cs b/Source/Instruments/PowerSupplies/Keysight67XX/KeysightPowerSupplyScpiCommands.cs new file mode 100644 index 0000000..12694dd --- /dev/null +++ b/Source/Instruments/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/Instruments/PowerSupplies/PowerSupplySim/PowerSupplyModuleSim.cs b/Source/Instruments/PowerSupplies/PowerSupplySim/PowerSupplyModuleSim.cs new file mode 100644 index 0000000..61e9a33 --- /dev/null +++ b/Source/Instruments/PowerSupplies/PowerSupplySim/PowerSupplyModuleSim.cs @@ -0,0 +1,253 @@ +/*------------------------------------------------------------------------- +// 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.Text; +using System.Threading.Tasks; + +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(), Raytheon.Common.GeneralConstants.DefaultConfigValue); + string coupledModules = config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.COUPLED_MODULES.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue); + string groupedModules = config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.GROUPED_MODULES.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue); + + List 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(), Raytheon.Common.GeneralConstants.DefaultConfigValue); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.OCP.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out ocp); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.OVP.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out ovp); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.VOLTAGE_SETPOINT.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out voltageSetPoint); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.VOLTAGE_SLEW_RATE.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out voltageSlewRate); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.MIN_VOLTAGE.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out minVoltage); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.MAX_VOLTAGE.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out maxVoltage); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.MIN_CURRENT.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out minCurrent); + Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.MAX_CURRENT.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), 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 + { + get { SemObj?.Release(); throw new NotImplementedException(); } + 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].lowerCurrentLimit_ + PowerModuleInfoDict[ActivePowerModule].upperCurrentLimit_) / 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/Instruments/PowerSupplies/PowerSupplySim/PowerSupplySim.cs b/Source/Instruments/PowerSupplies/PowerSupplySim/PowerSupplySim.cs new file mode 100644 index 0000000..cccd885 --- /dev/null +++ b/Source/Instruments/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 NLog; +using Raytheon.Common; +using System; +using System.Collections.Generic; +using System.Configuration; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +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", $".\\{Raytheon.Common.GeneralConstants.InstrumentConfigFolder}\\{deviceInstanceName}.ini")); + } + + /// + /// 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 + { + if (!(powerDeviceId == null || powerDeviceId.GetType().IsEnum)) + { + throw new ArgumentException($"{nameof(powerDeviceId)} must be an enumerated type or null"); + } + + _powerSupplyModule.GetSemphamore().WaitOne(); + + if (powerDeviceId != null) + _powerSupplyModule.SetActivePowerModule(powerDeviceId.ToString()); + + return _powerSupplyModule; + } + } + } +} diff --git a/Source/Instruments/PowerSupplies/PowerSupplySim/PowerSupplySim.csproj b/Source/Instruments/PowerSupplies/PowerSupplySim/PowerSupplySim.csproj new file mode 100644 index 0000000..64384fc --- /dev/null +++ b/Source/Instruments/PowerSupplies/PowerSupplySim/PowerSupplySim.csproj @@ -0,0 +1,41 @@ + + + + + net472 + Library + Raytheon.Instruments.PowerSupplies.Simulation + Raytheon.Instruments + Power Supply Simulation + Power Supply Simulation + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + Raytheon Technologies + TEEC + Copyright © Raytheon Technologies $([System.DateTime]::get_now().ToString("yyyy")) + + + + + + 1.0.0 + Debug;Release;Deploy + + + + + + + + + + + + + + + + + diff --git a/Source/Instruments/PowerSupplies/PowerSupplySim/PowerSupplySimFactory.cs b/Source/Instruments/PowerSupplies/PowerSupplySim/PowerSupplySimFactory.cs new file mode 100644 index 0000000..fae00d2 --- /dev/null +++ b/Source/Instruments/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/Interfaces/ICommDevice/CommDevice.Contracts.csproj b/Source/Interfaces/ICommDevice/CommDevice.Contracts.csproj new file mode 100644 index 0000000..d3d1df5 --- /dev/null +++ b/Source/Interfaces/ICommDevice/CommDevice.Contracts.csproj @@ -0,0 +1,26 @@ + + + + net472 + Library + Raytheon.Instruments.CommDevice.Contracts + Raytheon.Instruments + ICommDevice interface definition + true + Raytheon Technologies + HAL + TEEC + Copyright © Raytheon Technologies $([System.DateTime]::get_now().ToString("yyyy")) + + 1.0.0 + Debug;Release;Deploy + + + + + + + + + + diff --git a/Source/Interfaces/ICommDevice/ICommDevice.cs b/Source/Interfaces/ICommDevice/ICommDevice.cs new file mode 100644 index 0000000..e85c655 --- /dev/null +++ b/Source/Interfaces/ICommDevice/ICommDevice.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 Raytheon.Communication; + +namespace Raytheon.Instruments +{ + /// + /// An interface to any device that you can write and read to/from + /// + public interface ICommDevice : IInstrument + { + /// + /// Close the communication interface + /// + [UmsCommand("ICommDevice.Close")] + void Close(); + + /// + /// Open the communication interface + /// + [UmsCommand("ICommDevice.Open")] + void Open(); + + /// + /// Reads data from a communication device + /// + /// + /// number of bytes read + [UmsCommand("ICommDevice.Read")] + uint Read(ref byte[] dataRead); + + /// + /// Set the timeout on a read + /// + /// + [UmsCommand("ICommDevice.SetReadTimeout")] + void SetReadTimeout(uint timeout); + + /// + /// Writes data to a communication device + /// + /// + /// + /// the number of bytes written + [UmsCommand("ICommDevice.Write")] + uint Write(byte[] data, uint numBytesToWrite); + } +} diff --git a/Source/Interfaces/IInstrument/GlobalSuppressions.cs b/Source/Interfaces/IInstrument/GlobalSuppressions.cs new file mode 100644 index 0000000..c0182f8 --- /dev/null +++ b/Source/Interfaces/IInstrument/GlobalSuppressions.cs @@ -0,0 +1,18 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. +// +// To add a suppression to this file, right-click the message in the +// Error List, point to "Suppress Message(s)", and click +// "In Project Suppression File". +// You do not need to add suppressions to this file manually. + +using System.Diagnostics.CodeAnalysis; + + +[assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames")] +[assembly: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "RINSS")] +[assembly: SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Scope = "member", Target = "Raytheon.Instruments.IInstrumentProxyFactory.#GetSupportedInterfaces()")] +[assembly: SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Scope = "member", Target = "Raytheon.Instruments.IInstrumentFactory.#GetSupportedInterfaces()")] +[assembly: SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable", Scope = "type", Target = "Raytheon.Instruments.InstrumentException")] diff --git a/Source/Interfaces/IInstrument/IInstrument.cs b/Source/Interfaces/IInstrument/IInstrument.cs new file mode 100644 index 0000000..2a9a35a --- /dev/null +++ b/Source/Interfaces/IInstrument/IInstrument.cs @@ -0,0 +1,151 @@ +// ****************************************************************************************** +// ** ** +// ** 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. ** +// ** ** +// ** WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE ** +// ** EXPORT OR DISCLOSURE TO NON-U.S.PERSONS, WHEREVER LOCATED, IS RESTRICTED ** +// ** BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R.SECTION ** +// ** 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS(EAR) (15 C.F.R.SECTION ** +// ** 730-774). THIS DOCUMENT CANNOT BE EXPORTED(E.G., PROVIDED TO A SUPPLIER ** +// ** OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S.PERSON, WHEREVER ** +// ** LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS ** +// ** BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S.GOVERNMENT ** +// ** APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL ** +// ** PENALTIES. ** +// ** ** +// ** CAPITAL EQUIPMENT/SOFTWARE: THIS TECHNICAL DATA WAS DEVELOPED OR ACQUIRED ** +// ** EXCLUSIVELY AT CONTRACTOR EXPENSE AND IS INTENDED FOR USE ON MULTIPLE ** +// ** PROJECTS/PROGRAMS. ** +// ** ** +// ******************************************************************************************* +using System; +using Raytheon.Communication; + +namespace Raytheon.Instruments +{ + /// + /// IInstrument - RINSS generic instrument interface, that all instruments MUST implement + /// + public interface IInstrument + { + /// + /// ClearErrors - clear existing errors but leave options in current state + /// + /// returns true if errors are successfully cleared + [UmsCommand("RINSS.IInstrument.ClearErrors")] + bool ClearErrors(); + + /// + /// DetailedStatus - will contain detailed information about the current state of the instrument + /// + String DetailedStatus + { + [UmsCommand("RINSS.IInstrument.GetDetailedStatus")] + get; + } + + /// + /// 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 + /// + bool DisplayEnabled + { + [UmsCommand("RINSS.IInstrument.GetDisplayEnabled")] + get; + + [UmsCommand("RINSS.IInstrument.SetDisplayEnabled")] + 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 + /// + bool FrontPanelEnabled + { + [UmsCommand("RINSS.IInstrument.GetFrontPanelEnabled")] + get; + + [UmsCommand("RINSS.IInstrument.SetFrontPanelEnabled")] + set; + } + + /// + /// Info - extra instrument information, currently only model number information + /// + InstrumentMetadata Info + { + [UmsCommand("RINSS.IInstrument.GetInfo")] + get; + } + + /// + /// Initialize - remove any state knowledge from the hardware and call any + /// initialize methods needed. this may take time and differs only + /// from reset by the fact it may power cycle or do something more than + /// settings to the instrument + /// + [UmsCommand("RINSS.IInstrument.Initialize")] + void Initialize(); + + /// + /// Name - unique identifier for the instrument + /// + string Name + { + [UmsCommand("RINSS.IInstrument.GetName")] + get; + } + + /// + /// PerformSelfTest - do a hardware self test + /// + /// result of the self test + [UmsCommand("RINSS.IInstrument.PerformSelfTest")] + SelfTestResult PerformSelfTest(); + + /// + /// Reset - put state of the unit back to startup state + /// + [UmsCommand("RINSS.IInstrument.Reset")] + void Reset(); + + /// + /// SelfTestResult - end result of the hardware self test performed + /// + SelfTestResult SelfTestResult + { + [UmsCommand("RINSS.IInstrument.GetSelfTestResult")] + get; + } + + /// + /// Shutdown - could potentially turn off the instrument + /// + [UmsCommand("RINSS.IInstrument.Shutdown")] + void Shutdown(); + + /// + /// Status - current state infromation + /// + State Status + { + [UmsCommand("RINSS.IInstrument.GetStatus")] + get; + } + } +} diff --git a/Source/Interfaces/IInstrument/IInstrumentFactory.cs b/Source/Interfaces/IInstrument/IInstrumentFactory.cs new file mode 100644 index 0000000..9961191 --- /dev/null +++ b/Source/Interfaces/IInstrument/IInstrumentFactory.cs @@ -0,0 +1,65 @@ +// ****************************************************************************************** +// ** ** +// ** 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. ** +// ** ** +// ** WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE ** +// ** EXPORT OR DISCLOSURE TO NON-U.S.PERSONS, WHEREVER LOCATED, IS RESTRICTED ** +// ** BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R.SECTION ** +// ** 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS(EAR) (15 C.F.R.SECTION ** +// ** 730-774). THIS DOCUMENT CANNOT BE EXPORTED(E.G., PROVIDED TO A SUPPLIER ** +// ** OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S.PERSON, WHEREVER ** +// ** LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS ** +// ** BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S.GOVERNMENT ** +// ** APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL ** +// ** PENALTIES. ** +// ** ** +// ** CAPITAL EQUIPMENT/SOFTWARE: THIS TECHNICAL DATA WAS DEVELOPED OR ACQUIRED ** +// ** EXCLUSIVELY AT CONTRACTOR EXPENSE AND IS INTENDED FOR USE ON MULTIPLE ** +// ** PROJECTS/PROGRAMS. ** +// ** ** +// ******************************************************************************************* +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Raytheon.Communication; + +namespace Raytheon.Instruments +{ + /// + /// IInstrumentFactory - interface for RINSS's factory pattern, each of these should create + /// instruments of the types they support + /// + public interface IInstrumentFactory + { + /// + /// GetInstrument - main call to a factory to get an instrument it can create + /// + /// do not pass IInstrument objects via RPC, it is a copy of the object + /// unique name of the instrument + /// null if instrument cannot be found, otherwise the instrument implementation + IInstrument GetInstrument(string name); + + object GetInstrument(string name, bool simulateHw); + + /// + /// GetSupportedInterfaces - used to get all the types of instruments a factory could be used + /// to create. + /// + /// collection of specific instrument types it can create + [UmsCommand("RINSS.IInstrumentFactory.GetSupportedInterfaces")] + ICollection GetSupportedInterfaces(); + } +} diff --git a/Source/Interfaces/IInstrument/IInstrumentFactoryInfo.cs b/Source/Interfaces/IInstrument/IInstrumentFactoryInfo.cs new file mode 100644 index 0000000..9d14501 --- /dev/null +++ b/Source/Interfaces/IInstrument/IInstrumentFactoryInfo.cs @@ -0,0 +1,50 @@ +// ****************************************************************************************** +// ** ** +// ** 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. ** +// ** ** +// ** WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE ** +// ** EXPORT OR DISCLOSURE TO NON-U.S.PERSONS, WHEREVER LOCATED, IS RESTRICTED ** +// ** BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R.SECTION ** +// ** 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS(EAR) (15 C.F.R.SECTION ** +// ** 730-774). THIS DOCUMENT CANNOT BE EXPORTED(E.G., PROVIDED TO A SUPPLIER ** +// ** OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S.PERSON, WHEREVER ** +// ** LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS ** +// ** BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S.GOVERNMENT ** +// ** APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL ** +// ** PENALTIES. ** +// ** ** +// ** CAPITAL EQUIPMENT/SOFTWARE: THIS TECHNICAL DATA WAS DEVELOPED OR ACQUIRED ** +// ** EXCLUSIVELY AT CONTRACTOR EXPENSE AND IS INTENDED FOR USE ON MULTIPLE ** +// ** PROJECTS/PROGRAMS. ** +// ** ** +// ******************************************************************************************* +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Raytheon.Instruments +{ + /// + /// IInstrumentFactoryInfo - interface for meta data about the instrument factory + /// + public interface IInstrumentFactoryInfo + { + /// + /// ModelNumber - a unique identifier for the instrument factory + /// + string ModelNumber { get; } + } +} diff --git a/Source/Interfaces/IInstrument/IInstrumentProxyFactory.cs b/Source/Interfaces/IInstrument/IInstrumentProxyFactory.cs new file mode 100644 index 0000000..8cabfe4 --- /dev/null +++ b/Source/Interfaces/IInstrument/IInstrumentProxyFactory.cs @@ -0,0 +1,70 @@ +// ****************************************************************************************** +// ** ** +// ** 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. ** +// ** ** +// ** WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE ** +// ** EXPORT OR DISCLOSURE TO NON-U.S.PERSONS, WHEREVER LOCATED, IS RESTRICTED ** +// ** BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R.SECTION ** +// ** 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS(EAR) (15 C.F.R.SECTION ** +// ** 730-774). THIS DOCUMENT CANNOT BE EXPORTED(E.G., PROVIDED TO A SUPPLIER ** +// ** OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S.PERSON, WHEREVER ** +// ** LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS ** +// ** BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S.GOVERNMENT ** +// ** APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL ** +// ** PENALTIES. ** +// ** ** +// ** CAPITAL EQUIPMENT/SOFTWARE: THIS TECHNICAL DATA WAS DEVELOPED OR ACQUIRED ** +// ** EXCLUSIVELY AT CONTRACTOR EXPENSE AND IS INTENDED FOR USE ON MULTIPLE ** +// ** PROJECTS/PROGRAMS. ** +// ** ** +// ******************************************************************************************* +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Raytheon.Communication; +using Raytheon.Communication.Rpc; + +namespace Raytheon.Instruments +{ + /// + /// IInstrumentProxyFactory - interface to a proxy instrument factory, used to identify + /// the ums piece that will do the proxy'ing + /// + public interface IInstrumentProxyFactory + { + /// + /// Initialize - sets up the factory with the ums components it needs to distribute + /// the proxy instruments + /// + /// the port used to proxy + /// the factory associated with port to create the clients + void Initialize(IUms umsHost, IUmsClientFactory umsClientFactory); + + /// + /// GetInstrument - get a proxy'd instrument + /// + /// unique name of the instrument + /// null if the instrument does not exist and the instrument implementation if it does + IInstrument GetInstrument(string name); + + /// + /// GetSupportedInterfaces - discovery about the factory to find out which instruments + /// it provides proxies to + /// + /// collection of supported interface names + ICollection GetSupportedInterfaces(); + } +} diff --git a/Source/Interfaces/IInstrument/Instrument.Contracts.cd b/Source/Interfaces/IInstrument/Instrument.Contracts.cd new file mode 100644 index 0000000..49a6de3 --- /dev/null +++ b/Source/Interfaces/IInstrument/Instrument.Contracts.cd @@ -0,0 +1,33 @@ + + + + + + AAgAABAGAAAAAQCAAAAAAAgAQAAAAAAAQAAAAAAAAAA= + InstrumentProxyFactory.cs + + + + + + + AAAAAAAEAAAABQAAIAAAAQYEAAAAAAAQAAAAAEAAiAA= + IInstrument.cs + + + + + + AAgAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAA= + IInstrumentFactory.cs + + + + + + AAgAAAAAAAAAAQAAAAAAAAgAAAAAAAAAAAAAAAAAAAA= + IInstrumentProxyFactory.cs + + + + \ No newline at end of file diff --git a/Source/Interfaces/IInstrument/Instrument.cs b/Source/Interfaces/IInstrument/Instrument.cs new file mode 100644 index 0000000..cd3f576 --- /dev/null +++ b/Source/Interfaces/IInstrument/Instrument.cs @@ -0,0 +1,104 @@ +// ****************************************************************************************** +// ** ** +// ** 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. ** +// ** ** +// ** WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE ** +// ** EXPORT OR DISCLOSURE TO NON-U.S.PERSONS, WHEREVER LOCATED, IS RESTRICTED ** +// ** BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R.SECTION ** +// ** 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS(EAR) (15 C.F.R.SECTION ** +// ** 730-774). THIS DOCUMENT CANNOT BE EXPORTED(E.G., PROVIDED TO A SUPPLIER ** +// ** OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S.PERSON, WHEREVER ** +// ** LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS ** +// ** BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S.GOVERNMENT ** +// ** APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL ** +// ** PENALTIES. ** +// ** ** +// ** CAPITAL EQUIPMENT/SOFTWARE: THIS TECHNICAL DATA WAS DEVELOPED OR ACQUIRED ** +// ** EXCLUSIVELY AT CONTRACTOR EXPENSE AND IS INTENDED FOR USE ON MULTIPLE ** +// ** PROJECTS/PROGRAMS. ** +// ** ** +// ******************************************************************************************* +using Raytheon.Communication; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Raytheon.Instruments +{ + public abstract class Instrument + { + /// + /// DetailedStatus - will contain detailed information about the current state of the instrument + /// + public string DetailedStatus + { + get; + set; + } + + /// + /// Info - extra instrument information, currently only model number information + /// + public InstrumentMetadata Info + { + get; + set; + } + + /// + /// Name - unique identifier for the instrument + /// + public string Name + { + get; + set; + } + + /// + /// Status - current state infromation + /// + public State Status + { + get; + set; + } + + /// + /// ClearErrors - clear existing errors but leave options in current state + /// + /// returns true if errors are successfully cleared + public abstract bool ClearErrors(); + + /// + /// Initialize - remove any state knowledge from the hardware and call any + /// initialize methods needed. this may take time and differs only + /// from reset by the fact it may power cycle or do something more than + /// settings to the instrument + /// + public abstract void Initialize(); + + /// + /// Reset - put state of the unit back to startup state + /// + public abstract void Reset(); + + /// + /// Shutdown - could potentially turn off the instrument + /// + public abstract void Shutdown(); + } +} diff --git a/Source/Interfaces/IInstrument/InstrumentException.cs b/Source/Interfaces/IInstrument/InstrumentException.cs new file mode 100644 index 0000000..67dab56 --- /dev/null +++ b/Source/Interfaces/IInstrument/InstrumentException.cs @@ -0,0 +1,146 @@ +// ****************************************************************************************** +// ** ** +// ** 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. ** +// ** ** +// ** WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE ** +// ** EXPORT OR DISCLOSURE TO NON-U.S.PERSONS, WHEREVER LOCATED, IS RESTRICTED ** +// ** BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R.SECTION ** +// ** 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS(EAR) (15 C.F.R.SECTION ** +// ** 730-774). THIS DOCUMENT CANNOT BE EXPORTED(E.G., PROVIDED TO A SUPPLIER ** +// ** OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S.PERSON, WHEREVER ** +// ** LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS ** +// ** BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S.GOVERNMENT ** +// ** APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL ** +// ** PENALTIES. ** +// ** ** +// ** CAPITAL EQUIPMENT/SOFTWARE: THIS TECHNICAL DATA WAS DEVELOPED OR ACQUIRED ** +// ** EXCLUSIVELY AT CONTRACTOR EXPENSE AND IS INTENDED FOR USE ON MULTIPLE ** +// ** PROJECTS/PROGRAMS. ** +// ** ** +// ******************************************************************************************* +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; + +namespace Raytheon.Instruments +{ + /// + /// InstrumentException - an exception that can be thrown by all instruments + /// while processing any instruction + /// can be used as a base class + /// + [DataContract] + public class InstrumentException : Exception + { + [DataMember] + private string _message = string.Empty; + + [DataMember] + private int _errorCode = 0; + + /// + /// Message - readable information associated with the exception + /// + public override string Message + { + get + { + return _message; + } + } + + /// + /// ErrorCode - code associated with error involved with this exception + /// + public int ErrorCode + { + get { return _errorCode; } + set { _errorCode = value; } + } + + /// + /// InstrumentException - default constructor + /// + public InstrumentException() + : base() + { + } + + /// + /// InstrumentException - constructor with a message as parameter + /// + /// message about the exception + public InstrumentException(string message) + : base() + { + _message = message; + } + + /// + /// InstrumentException - constructor that takes an error code + /// + /// the error code + public InstrumentException(int errorCode) + : base() + { + _errorCode = errorCode; + } + + /// + /// InstrumentException - constructor that takes an error code and message + /// + /// the error code + /// the message + public InstrumentException(int errorCode, string message) + : base() + { + _message = message; + _errorCode = errorCode; + } + + /// + /// InstrumentException - constructor that takes an error message and inner exception + /// + /// the message + /// an inner exception + public InstrumentException(string message, Exception innerException) + : base(message, innerException) + { + _message = message; + } + + /// + /// InstrumentException - protected constructor + /// + /// serialization info + /// context + protected InstrumentException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// GetObjectData - override for serialization + /// + /// how to serialize + /// context + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + } + } +} diff --git a/Source/Interfaces/IInstrument/InstrumentFactory.Metadata.cs b/Source/Interfaces/IInstrument/InstrumentFactory.Metadata.cs new file mode 100644 index 0000000..712e546 --- /dev/null +++ b/Source/Interfaces/IInstrument/InstrumentFactory.Metadata.cs @@ -0,0 +1,65 @@ +// ****************************************************************************************** +// ** ** +// ** 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. ** +// ** ** +// ** WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE ** +// ** EXPORT OR DISCLOSURE TO NON-U.S.PERSONS, WHEREVER LOCATED, IS RESTRICTED ** +// ** BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R.SECTION ** +// ** 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS(EAR) (15 C.F.R.SECTION ** +// ** 730-774). THIS DOCUMENT CANNOT BE EXPORTED(E.G., PROVIDED TO A SUPPLIER ** +// ** OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S.PERSON, WHEREVER ** +// ** LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS ** +// ** BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S.GOVERNMENT ** +// ** APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL ** +// ** PENALTIES. ** +// ** ** +// ** CAPITAL EQUIPMENT/SOFTWARE: THIS TECHNICAL DATA WAS DEVELOPED OR ACQUIRED ** +// ** EXCLUSIVELY AT CONTRACTOR EXPENSE AND IS INTENDED FOR USE ON MULTIPLE ** +// ** PROJECTS/PROGRAMS. ** +// ** ** +// ******************************************************************************************* +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.ComponentModel.Composition; + +namespace Raytheon.Instruments +{ + /// + /// ExportInstrumentFactoryAttribute - attribute to allow MEF to figure all the factories out + /// + [MetadataAttribute] + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + public sealed class ExportInstrumentFactoryAttribute : ExportAttribute, IInstrumentFactoryInfo + { + /// + /// Initializes a new instance of the class. + /// + public ExportInstrumentFactoryAttribute() + : base(typeof(IInstrumentFactory)) + { + + } + + /// + /// Gets or sets the model number. + /// + /// + /// The model number. + /// + public string ModelNumber { get; set; } + } +} diff --git a/Source/Interfaces/IInstrument/InstrumentMetadata.cs b/Source/Interfaces/IInstrument/InstrumentMetadata.cs new file mode 100644 index 0000000..4b518a6 --- /dev/null +++ b/Source/Interfaces/IInstrument/InstrumentMetadata.cs @@ -0,0 +1,55 @@ +// ****************************************************************************************** +// ** ** +// ** 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. ** +// ** ** +// ** WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE ** +// ** EXPORT OR DISCLOSURE TO NON-U.S.PERSONS, WHEREVER LOCATED, IS RESTRICTED ** +// ** BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R.SECTION ** +// ** 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS(EAR) (15 C.F.R.SECTION ** +// ** 730-774). THIS DOCUMENT CANNOT BE EXPORTED(E.G., PROVIDED TO A SUPPLIER ** +// ** OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S.PERSON, WHEREVER ** +// ** LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS ** +// ** BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S.GOVERNMENT ** +// ** APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL ** +// ** PENALTIES. ** +// ** ** +// ** CAPITAL EQUIPMENT/SOFTWARE: THIS TECHNICAL DATA WAS DEVELOPED OR ACQUIRED ** +// ** EXCLUSIVELY AT CONTRACTOR EXPENSE AND IS INTENDED FOR USE ON MULTIPLE ** +// ** PROJECTS/PROGRAMS. ** +// ** ** +// ******************************************************************************************* +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.ComponentModel.Composition; +using System.Diagnostics.CodeAnalysis; + +namespace Raytheon.Instruments +{ + /// + /// InstrumentMetadata - any instrument information not needed for running + /// + [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] + [MetadataAttribute] + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public sealed class InstrumentMetadata : ExportAttribute + { + /// + /// ModelNumber - the model number for the instrument + /// + public string ModelNumber { get; set; } + } +} diff --git a/Source/Interfaces/IInstrument/InstrumentProxyFactory.cs b/Source/Interfaces/IInstrument/InstrumentProxyFactory.cs new file mode 100644 index 0000000..85a31a6 --- /dev/null +++ b/Source/Interfaces/IInstrument/InstrumentProxyFactory.cs @@ -0,0 +1,161 @@ +// ****************************************************************************************** +// ** ** +// ** 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. ** +// ** ** +// ** WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE ** +// ** EXPORT OR DISCLOSURE TO NON-U.S.PERSONS, WHEREVER LOCATED, IS RESTRICTED ** +// ** BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R.SECTION ** +// ** 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS(EAR) (15 C.F.R.SECTION ** +// ** 730-774). THIS DOCUMENT CANNOT BE EXPORTED(E.G., PROVIDED TO A SUPPLIER ** +// ** OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S.PERSON, WHEREVER ** +// ** LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS ** +// ** BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S.GOVERNMENT ** +// ** APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL ** +// ** PENALTIES. ** +// ** ** +// ** CAPITAL EQUIPMENT/SOFTWARE: THIS TECHNICAL DATA WAS DEVELOPED OR ACQUIRED ** +// ** EXCLUSIVELY AT CONTRACTOR EXPENSE AND IS INTENDED FOR USE ON MULTIPLE ** +// ** PROJECTS/PROGRAMS. ** +// ** ** +// ******************************************************************************************* +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Raytheon.Communication; +using Raytheon.Communication.Rpc; +using System.Globalization; + +namespace Raytheon.Instruments +{ + /// + /// Generic (and abstract) proxy factory for helping to do all of the work that needs to + /// be done in proxy factories. All that needs implementation is the GetSupportedInterfaces + /// method, this will be up to the impl + /// + /// What shall be done is a proxy factory for every interface should be declared in + /// a dll. Then a consumer would import via MEF all the factories and use them appropriately + /// + public abstract class InstrumentProxyFactory : IInstrumentProxyFactory + where T : class + { + #region Private Fields + + //as of right now these do not appear to need access to the implementing class + private IUms _UmsHost; + private IUmsClientFactory _UmsClientFactory; + + //Added a GetProxy method for access to a specific proxy + private Dictionary> _Proxies; + + #endregion + + #region IInstrumentProxyFactory Members + + /// + /// This must be called to initialize a factory with a media port to create the client + /// + /// host for the client factory to use to create the proxy + /// client factory to use to create proxies + public virtual void Initialize(IUms umsHost, IUmsClientFactory umsClientFactory) + { + _Proxies = new Dictionary>(); + _UmsClientFactory = umsClientFactory; + _UmsHost = umsHost; + } + + /// + /// This is the call any client rpc instrument manager would use to get the proxy + /// it will return the specific instrument proxy which can be cast to a generic + /// IInstrument if needed, the only way to cast to a derived type is to return one + /// in the first place since they are proxies + /// + /// instrument name + /// the Type proxy (not the IInstrument) + public virtual IInstrument GetInstrument(string name) + { + return GetSpecificInstrument(name) as IInstrument; + } + + /// + /// Implementing class must provide the interfaces it supports + /// Since this is purely an interface driven proxy the acutal implementation + /// under the hood of the Interfaces matters not + /// + /// collection of interfaces it can create proxies to + public abstract ICollection GetSupportedInterfaces(); + + #endregion + + #region Protected Methods + + /// + /// returns the specific instruments proxy, this is a generic operation so put into abstract class + /// + /// instrument name + /// the specific instruments proxy + protected virtual T GetSpecificInstrument(string name) + { + if (null == _Proxies) + { + string message = typeof(T).FullName + " Factory not initialized, proxy container not created"; + throw new InstrumentException(message); + } + + if (!_Proxies.ContainsKey(name)) + { + var proxy = CreateProxy(name); + _Proxies.Add(name, proxy); + } + + return _Proxies[name].Contract; + } + + /// + /// added to allow an implementing class to get access to proxies so that it may add properties or + /// whatever else needs to be done to the objects + /// + /// instrument name + /// the proxy to that specific instrument + protected IUmsClient GetProxy(string proxyName) + { + IUmsClient proxy = null; + _Proxies.TryGetValue(proxyName, out proxy); + return proxy; + } + + /// + /// creates the proxy, this is a generic operation, so put into the abstract class + /// + /// instrument name + /// the proxy to the given instrument + protected virtual IUmsClient CreateProxy(string proxyName) + { + if (null == _UmsClientFactory || null == _UmsHost) + { + string message = typeof(T).FullName + " Factory not initialized, ums information is null"; + throw new InstrumentException(message); + } + + IUmsClient proxy = _UmsClientFactory.GetClient(_UmsHost); + proxy.AddProperty("instName", proxyName); + proxy.Open(); + + return proxy; + } + + #endregion + } +} diff --git a/Source/Interfaces/IInstrument/Instruments.Contracts.csproj b/Source/Interfaces/IInstrument/Instruments.Contracts.csproj new file mode 100644 index 0000000..8f41ca7 --- /dev/null +++ b/Source/Interfaces/IInstrument/Instruments.Contracts.csproj @@ -0,0 +1,25 @@ + + + + net472 + Library + Raytheon.Instruments.Contracts + Raytheon.Instruments + Raytheon Technologies + Raytheon Configuration + Base Instrument interface and export attribute + TEEC + Copyright © Raytheon Technologies $([System.DateTime]::get_now().ToString("yyyy")) + True + + 1.5.0.0 + Debug;Release;Deploy + + + + + + + + + \ No newline at end of file diff --git a/Source/Interfaces/IInstrument/SelfTestResult.cs b/Source/Interfaces/IInstrument/SelfTestResult.cs new file mode 100644 index 0000000..5312786 --- /dev/null +++ b/Source/Interfaces/IInstrument/SelfTestResult.cs @@ -0,0 +1,63 @@ +// ****************************************************************************************** +// ** ** +// ** 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. ** +// ** ** +// ** WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE ** +// ** EXPORT OR DISCLOSURE TO NON-U.S.PERSONS, WHEREVER LOCATED, IS RESTRICTED ** +// ** BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R.SECTION ** +// ** 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS(EAR) (15 C.F.R.SECTION ** +// ** 730-774). THIS DOCUMENT CANNOT BE EXPORTED(E.G., PROVIDED TO A SUPPLIER ** +// ** OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S.PERSON, WHEREVER ** +// ** LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS ** +// ** BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S.GOVERNMENT ** +// ** APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL ** +// ** PENALTIES. ** +// ** ** +// ** CAPITAL EQUIPMENT/SOFTWARE: THIS TECHNICAL DATA WAS DEVELOPED OR ACQUIRED ** +// ** EXCLUSIVELY AT CONTRACTOR EXPENSE AND IS INTENDED FOR USE ON MULTIPLE ** +// ** PROJECTS/PROGRAMS. ** +// ** ** +// ******************************************************************************************* +using System.Runtime.Serialization; + +namespace Raytheon.Instruments +{ + /// + /// SelfTestResult - an enumeration for passing, failing or unknown state + /// of a self test. + /// + [DataContract] + public enum SelfTestResult + { + /// + /// SelfTestResult.Unknown - this indicates it is unknown what the self test result + /// is currently. + /// + [EnumMember] + Unknown, + + /// + /// SelfTestResult.Pass - last time the self test was run, it passed. + /// + [EnumMember] + Pass, + + /// + /// SelfTestResult.Fail - last time teh self test was run, it failed. + /// + [EnumMember] + Fail, + } +} diff --git a/Source/Interfaces/IInstrument/State.cs b/Source/Interfaces/IInstrument/State.cs new file mode 100644 index 0000000..59f0a79 --- /dev/null +++ b/Source/Interfaces/IInstrument/State.cs @@ -0,0 +1,88 @@ +// ****************************************************************************************** +// ** ** +// ** 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. ** +// ** ** +// ** WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE ** +// ** EXPORT OR DISCLOSURE TO NON-U.S.PERSONS, WHEREVER LOCATED, IS RESTRICTED ** +// ** BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R.SECTION ** +// ** 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS(EAR) (15 C.F.R.SECTION ** +// ** 730-774). THIS DOCUMENT CANNOT BE EXPORTED(E.G., PROVIDED TO A SUPPLIER ** +// ** OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S.PERSON, WHEREVER ** +// ** LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS ** +// ** BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S.GOVERNMENT ** +// ** APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL ** +// ** PENALTIES. ** +// ** ** +// ** CAPITAL EQUIPMENT/SOFTWARE: THIS TECHNICAL DATA WAS DEVELOPED OR ACQUIRED ** +// ** EXCLUSIVELY AT CONTRACTOR EXPENSE AND IS INTENDED FOR USE ON MULTIPLE ** +// ** PROJECTS/PROGRAMS. ** +// ** ** +// ******************************************************************************************* +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; + +namespace Raytheon.Instruments +{ + /// + /// State - enumeration for the states a instrument could be in + /// + [DataContract] + public enum State + { + /// + /// State.Ready - the up and running waiting on instructions + /// + [EnumMember] + Ready, + + /// + /// State.Busy - the instrument cannot be tasked it is already processing + /// some command or instruction that cannot be interrupted + /// + [EnumMember] + Busy, + + /// + /// State.CommunicationFailure - the instrument is in error right now and the + /// software component has lost connection with + /// the instrument + /// + [EnumMember] + CommunicationFailure, + + /// + /// State.HardwareFailure - the hardware has failed and cannot recover from some + /// error + /// + [EnumMember] + HardwareFailure, + + /// + /// State.InternalError - driver error internal to the software + /// + [EnumMember] + InternalError, + + /// + /// State.Uninitialized - an unknown state as the instrument must be initialized to + /// understand it's current state. + /// + [EnumMember] + Uninitialized, + } +} diff --git a/Source/Interfaces/IInstrumentManager/GlobalSuppressions.cs b/Source/Interfaces/IInstrumentManager/GlobalSuppressions.cs new file mode 100644 index 0000000..bbf9c70 --- /dev/null +++ b/Source/Interfaces/IInstrumentManager/GlobalSuppressions.cs @@ -0,0 +1,11 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. +// +// To add a suppression to this file, right-click the message in the +// Error List, point to "Suppress Message(s)", and click +// "In Project Suppression File". +// You do not need to add suppressions to this file manually. + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1014:MarkAssembliesWithClsCompliant")] diff --git a/Source/Interfaces/IInstrumentManager/IInstrumentManager.cs b/Source/Interfaces/IInstrumentManager/IInstrumentManager.cs new file mode 100644 index 0000000..e40147f --- /dev/null +++ b/Source/Interfaces/IInstrumentManager/IInstrumentManager.cs @@ -0,0 +1,158 @@ +// ****************************************************************************************** +// ** ** +// ** 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. ** +// ** ** +// ** WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE ** +// ** EXPORT OR DISCLOSURE TO NON-U.S.PERSONS, WHEREVER LOCATED, IS RESTRICTED ** +// ** BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R.SECTION ** +// ** 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS(EAR) (15 C.F.R.SECTION ** +// ** 730-774). THIS DOCUMENT CANNOT BE EXPORTED(E.G., PROVIDED TO A SUPPLIER ** +// ** OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S.PERSON, WHEREVER ** +// ** LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS ** +// ** BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S.GOVERNMENT ** +// ** APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL ** +// ** PENALTIES. ** +// ** ** +// ** CAPITAL EQUIPMENT/SOFTWARE: THIS TECHNICAL DATA WAS DEVELOPED OR ACQUIRED ** +// ** EXCLUSIVELY AT CONTRACTOR EXPENSE AND IS INTENDED FOR USE ON MULTIPLE ** +// ** PROJECTS/PROGRAMS. ** +// ** ** +// ******************************************************************************************* +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Raytheon.Communication; +using System.Diagnostics.CodeAnalysis; + +namespace Raytheon.Instruments +{ + /// + /// Instrument manager interface. + /// + /// + /// An instrument manager is responsible for loading all of the instrument plugins and providing an interface for retrieving those instruments. + /// + [UmsContract] + public interface IInstrumentManager + { + /// + /// Gets an instrument by name. + /// + /// The name. + /// The instrument + /// This function cannot be named the same as the Generic method GetInstrument/ + /// because certain test executives do not support generics, and will throw an AmbiguousMatchException. + IInstrument GetGenericInstrument(string name); + + /// + /// Gets an instrument by name. + /// + /// The name. + /// The instrument + T GetInstrument(string name) where T : class; + + /// + /// Gets all instruments currently loaded. + /// + /// collection of all known instruments + ICollection GetInstruments(); + + /// + /// Gets all instruments currently loaded. + /// + /// array of all known instruments + [UmsCommand("IInstrumentManager.GetInstrumentsArray")] + object[] GetInstrumentsArray(); + + /// + /// Gets the instruments of the given type. + /// + /// The type. + /// all known instruments of a certain type + ICollection GetInstruments(Type type); + + /// + /// Gets the instruments of the given type. + /// + /// The type. + /// array of instruments of the specified type + object[] GetInstrumentsArray(Type type); + + /// + /// Initializes the instrument manager + /// + [UmsCommand("IInstrumentManager.Initialize")] + void Initialize(); + + /// + /// Sets/Gets the part location + /// Added Dec 2013 to better clarify where the part locations are loading from + /// and to be able to set it before initialization + /// + string _partsLocation + { + get; + set; + } + + /// + /// Closes the instrument manager + /// + void Shutdown(); + + /// + /// Returns a collection of instrument names loaded. + /// + /// all the known instrument's unique name + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + [UmsCommand("IInstrumentManager.GetInstrumentNames")] + ICollection GetInstrumentNames(); + + /// + /// Returns a collection of instrument names loaded. + /// + /// all the known instrument names in array form + [UmsCommand("IInstrumentManager.GetInstrumentNamesArray")] + string[] GetInstrumentNamesArray(); + + /// + /// Initializes all of the instruments. + /// + [UmsCommand("IInstrumentManager.InitializeInstruments")] + void InitializeInstruments(); + + /// + /// Initializes the instrument. + /// + /// Name of the inst. + [UmsCommand("IInstrumentManager.InitializeInstrument")] + void InitializeInstrument(string instName); + + /// + /// Shuts down all of the instruments. + /// + [UmsCommand("IInstrumentManager.ShutdownInstruments")] + void ShutdownInstruments(); + + /// + /// Shutdowns the instrument. + /// + /// Name of the inst. + [UmsCommand("IInstrumentManager.ShutdownInstrument")] + void ShutdownInstrument(string instName); + + } +} diff --git a/Source/Interfaces/IInstrumentManager/Instruments.InstrumentManager.Contracts.csproj b/Source/Interfaces/IInstrumentManager/Instruments.InstrumentManager.Contracts.csproj new file mode 100644 index 0000000..da6120c --- /dev/null +++ b/Source/Interfaces/IInstrumentManager/Instruments.InstrumentManager.Contracts.csproj @@ -0,0 +1,26 @@ + + + + net472 + Library + Raytheon.Instruments.InstrumentManager.Contracts + Raytheon.Instruments + Raytheon Technologies + Raytheon Configuration + Instrument Manager Interface + TEEC + Copyright © Raytheon Technologies $([System.DateTime]::get_now().ToString("yyyy")) + True + + 1.7.1.0 + Debug;Release;Deploy + + + + + + + + + + \ No newline at end of file diff --git a/Source/Interfaces/PowerSupply/PowerSupply.Contracts.csproj b/Source/Interfaces/PowerSupply/PowerSupply.Contracts.csproj new file mode 100644 index 0000000..ecc1000 --- /dev/null +++ b/Source/Interfaces/PowerSupply/PowerSupply.Contracts.csproj @@ -0,0 +1,25 @@ + + + + net472 + Library + Raytheon.Instruments.PowerSupply.Contracts + Raytheon.Instruments + PowerSupply Interface + true + Raytheon Technologies + HAL + TEEC + Copyright © Raytheon Technologies $([System.DateTime]::get_now().ToString("yyyy")) + 1.1.0.0 + Debug;Release;Deploy + + + + + + + + + + diff --git a/Source/Interfaces/PowerSupply/PowerSupply.cs b/Source/Interfaces/PowerSupply/PowerSupply.cs new file mode 100644 index 0000000..d197945 --- /dev/null +++ b/Source/Interfaces/PowerSupply/PowerSupply.cs @@ -0,0 +1,53 @@ +/*------------------------------------------------------------------------- +// 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; + } + } +} diff --git a/Source/Interfaces/PowerSupply/PowerSupplyConfigIni.cs b/Source/Interfaces/PowerSupply/PowerSupplyConfigIni.cs new file mode 100644 index 0000000..c1c8c3d --- /dev/null +++ b/Source/Interfaces/PowerSupply/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/Interfaces/PowerSupply/PowerSupplyConfigXml.cs b/Source/Interfaces/PowerSupply/PowerSupplyConfigXml.cs new file mode 100644 index 0000000..676aed9 --- /dev/null +++ b/Source/Interfaces/PowerSupply/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/Interfaces/PowerSupply/PowerSupplyModule.cs b/Source/Interfaces/PowerSupply/PowerSupplyModule.cs new file mode 100644 index 0000000..71a8ef1 --- /dev/null +++ b/Source/Interfaces/PowerSupply/PowerSupplyModule.cs @@ -0,0 +1,205 @@ +/*------------------------------------------------------------------------- +// 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 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 + { + 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/Interfaces/PowerSupply/PowerSupplyModuleInfo.cs b/Source/Interfaces/PowerSupply/PowerSupplyModuleInfo.cs new file mode 100644 index 0000000..492a90e --- /dev/null +++ b/Source/Interfaces/PowerSupply/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; + lowerVoltageLimit_ = -1.0; + upperVoltageLimit_ = -1.0; + lowerCurrentLimit_ = -1.0; + upperCurrentLimit_ = -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; + lowerVoltageLimit_ = minVoltage; + upperVoltageLimit_ = maxVoltage; + lowerCurrentLimit_ = minCurrent; + upperCurrentLimit_ = maxCurrent; + isOn_ = false; + faultStatus = -1; + + moduleNameFormat = "(@" + moduleIndex + ")"; + } + + public string moduleNameFormat; + public double overCurrentProtection_; + public double overVoltageProtection_; + public double lowerVoltageLimit_; + public double upperVoltageLimit_; + public double lowerCurrentLimit_; + public double upperCurrentLimit_; + public double voltageSetpoint_; + public double voltageSlewRate_; + public bool isOn_; + public int faultStatus; + } +} diff --git a/Source/MeasurementManagers/PowerSupplyMeasurementManager/PowerModuleMeasurementManager.cs b/Source/MeasurementManagers/PowerSupplyMeasurementManager/PowerModuleMeasurementManager.cs new file mode 100644 index 0000000..0583c29 --- /dev/null +++ b/Source/MeasurementManagers/PowerSupplyMeasurementManager/PowerModuleMeasurementManager.cs @@ -0,0 +1,139 @@ +/*------------------------------------------------------------------------- +// UNCLASSIFIED +/*------------------------------------------------------------------------- +RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +COMPANY. + +THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. +GOVERNMENT. + +UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +-------------------------------------------------------------------------*/ +using NLog; +using Raytheon.Common; +using Raytheon.Instruments; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Threading; +using System.Threading.Tasks; + +namespace Raytheon +{ + /// + /// Class for controlling all power supplies + /// + public class PowerModuleMeasurementManager + { + #region PrivateClassMembers + /// + /// NLog logger + /// + private static NLog.ILogger _logger; + + private PowerSupply _powerSupply; + + private IConfigurationFile _powerOffAndSelfTestConfig; + + #endregion + + public bool FrontPanelEnabled + { + get + { + if (_powerSupply != null) + { + return _powerSupply[null].FrontPanelEnabled; + } + else + return true; + } + + set + { + if (_powerSupply != null) + { + _powerSupply[null].FrontPanelEnabled = value; + } + } + } + + /// + /// constructor + /// + /// the name specified in the Instruments.xml file + public PowerModuleMeasurementManager(PowerSupply powerSupply, IConfigurationFile powerOffAndSelfTestConfig) + { + _logger = LogManager.GetCurrentClassLogger(); + + _powerSupply = powerSupply; + _powerOffAndSelfTestConfig = powerOffAndSelfTestConfig; + } + + /// + /// The Finalizer + /// + ~PowerModuleMeasurementManager() + { + _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ..."); + } + + /// + /// Initialize the instrument(s) + /// + public void Initialize() + { + _logger.Trace($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method..."); + } + + /// + /// Shuts down manager, clears resources + /// + public void Shutdown() + { + _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method..."); + _powerSupply.Shutdown(); + } + + /// + /// Read various power supply data + /// + public void ReadPowerSupplyData(object module, out double voltage, out double current, out double voltageSetPoint, out bool isOn, out int faultStatus) + { + _powerSupply[module].ReadPowerSupplyData(out voltage, out current, out voltageSetPoint, out isOn, out faultStatus); + } + + /// + /// Enable the output of the power supply. + /// + /// The name of the module to enable. + public void OutputEnable(object module) + { + _powerSupply[module].On(); + } + + /// + /// Disable the output of the power supply. + /// + /// + /// + public void OutputDisable(object module) + { + _powerSupply[module].ReadPowerSupplyData(out double voltage, out double current, out double voltageSetPoint, out bool isOn, out int faultStatus); + + if (isOn) + { + _powerSupply[module].Off(); + + // save the time of this power off to file + MeasurementManager.PowerSupply.Util.SaveTime(_powerSupply.Name, DateTime.Now.ToString(), null, _powerOffAndSelfTestConfig); + } + } + } +} diff --git a/Source/MeasurementManagers/PowerSupplyMeasurementManager/PowerSupplyMeasurementManager .cs b/Source/MeasurementManagers/PowerSupplyMeasurementManager/PowerSupplyMeasurementManager .cs new file mode 100644 index 0000000..cf4484e --- /dev/null +++ b/Source/MeasurementManagers/PowerSupplyMeasurementManager/PowerSupplyMeasurementManager .cs @@ -0,0 +1,218 @@ +/*------------------------------------------------------------------------- +// UNCLASSIFIED +/*------------------------------------------------------------------------- +RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +COMPANY. + +THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. +GOVERNMENT. + +UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +-------------------------------------------------------------------------*/ +using NLog; +using Raytheon.Common; +using Raytheon.Instruments; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Raytheon +{ + /// + /// Class for controlling all power supplies + /// + public class PowerSupplyMeasurementManager + { + #region PrivateClassMembers + /// + /// NLog logger + /// + private static NLog.ILogger _logger; + + private IConfigurationFile _powerOffAndSelfTestConfig; + + private IInstrumentManager _instrumentManager; + + private Dictionary _powerSystemNameToPowerModuleMeasurementManagerDict = new Dictionary(); + + string _powerSystemWithFailedSelfTest = String.Empty; + + #endregion + + /// + /// constructor + /// + /// the name specified in the Instruments.xml file + public PowerSupplyMeasurementManager(IInstrumentManager instrumentManager, string powerSupplySelfTestLogFile) + { + _logger = LogManager.GetCurrentClassLogger(); + + _powerOffAndSelfTestConfig = new ConfigurationFile(powerSupplySelfTestLogFile); + + _instrumentManager = instrumentManager; + } + + /// + /// The Finalizer + /// + ~PowerSupplyMeasurementManager() + { + _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ..."); + } + + /// + /// Implement Indexer to obtain a powermodulemeasurementmanager + /// + /// + /// + public PowerModuleMeasurementManager this[object powerSystemId] + { + get + { + if (!powerSystemId.GetType().IsEnum) + { + throw new ArgumentException($"{nameof(powerSystemId)} must be an enumerated type"); + } + + if (!_powerSystemNameToPowerModuleMeasurementManagerDict.ContainsKey(powerSystemId.ToString())) + { + throw new Exception($"Invalid power supply system: {powerSystemId.ToString()}"); + } + + return _powerSystemNameToPowerModuleMeasurementManagerDict[powerSystemId.ToString()]; + } + } + + /// + /// Initialize the instrument(s) + /// + public void Initialize() + { + _logger.Trace($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method..."); + + PerformSelfTest(); + + if (_powerSystemWithFailedSelfTest != String.Empty) + { + throw new Exception($"{_powerSystemWithFailedSelfTest}'s self-test failed."); + } + } + + /// + /// Perform self test on power supply system + /// Self test for each power system takes a while, so we don't want to run self test every time we initialize the power system + /// So we only want to run self test under 2 conditions: + /// 1. Certain time has elapsed since last power off + /// 2. Certain time has elapsed since last self test run ( in the absence of power off time) + /// + /// + /// + private async void PerformSelfTest() + { + _logger.Trace($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method..."); + + string errorMsg = String.Empty; + + Dictionary> powerSystemToSelfTestTaskDict = new Dictionary>(); + + bool allSelfTestsPassed = true; + + ICollection psList = _instrumentManager.GetInstruments(typeof(PowerSupply)); + + foreach (PowerSupply ps in psList) + { + ps.Initialize(); + + // perform self test on power system + Task task = PerformSelfTestTask(ps); + powerSystemToSelfTestTaskDict[ps.Name] = task; + } + + foreach (var item in powerSystemToSelfTestTaskDict) + { + // wait for self test on power system to finish + SelfTestResult result = await item.Value; + + if (result == SelfTestResult.Fail && String.IsNullOrEmpty(_powerSystemWithFailedSelfTest)) + { + allSelfTestsPassed = false; + _powerSystemWithFailedSelfTest = item.Key; + } + } + + if (allSelfTestsPassed) + { + foreach (PowerSupply ps in psList) + { + _powerSystemNameToPowerModuleMeasurementManagerDict[ps.Name] = new PowerModuleMeasurementManager(ps, _powerOffAndSelfTestConfig); + } + } + } + + /// + /// Perform self test on power supply system + /// Self test for each power system takes a while, so we don't want to run self test every time we initialize the power system + /// So we only want to run self test under 2 conditions: + /// 1. Certain time has elapsed since last power off + /// 2. Certain time has elapsed since last self test run ( in the absence of power off time) + /// + /// + /// + private Task PerformSelfTestTask(PowerSupply ps) + { + SelfTestResult result = SelfTestResult.Pass; + + _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() for {ps.Name} is running..."); + + try + { + bool performSelfTest = false; + const int HOURS_ELAPSED = 2; + + string lastSaveTime = MeasurementManager.PowerSupply.Util.GetLastSavedTime(ps.Name, _powerOffAndSelfTestConfig); + + if (DateTime.TryParse(lastSaveTime, out DateTime dt)) + { + // if this power supply system has been turn off for a certain number of hours, then we want to perform self test on it + if (DateTime.Now.Subtract(dt).TotalHours >= HOURS_ELAPSED) + { + performSelfTest = true; + } + } + else { performSelfTest = true; } + + if (performSelfTest) + { + _logger?.Info($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() executing self-test for {ps.Name}..."); + + result = ps[null].PerformSelfTest(); + + if (result == SelfTestResult.Pass) + { + // save the time of this self test to file + MeasurementManager.PowerSupply.Util.SaveTime(ps.Name, null, DateTime.Now.ToString(), _powerOffAndSelfTestConfig); + } + } + else + _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() skipping self-test for {ps.Name}..."); + } + catch (Exception ex) + { + _logger?.Error(ex.Message + "\n" + ex.StackTrace); + } + + _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() for {ps.Name} is exiting..."); + + return Task.FromResult(result); + } + + + } +} diff --git a/Source/MeasurementManagers/PowerSupplyMeasurementManager/PowerSupplyMeasurementManager.csproj b/Source/MeasurementManagers/PowerSupplyMeasurementManager/PowerSupplyMeasurementManager.csproj new file mode 100644 index 0000000..9ebb66f --- /dev/null +++ b/Source/MeasurementManagers/PowerSupplyMeasurementManager/PowerSupplyMeasurementManager.csproj @@ -0,0 +1,38 @@ + + + + + net472 + Library + Raytheon.InstrumentManagers.PowerSupplyManager + Raytheon.InstrumentManagers + Power Supply Manager Implementation + Provide access to the actual power supplies + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + Raytheon Technologies + TEEC + Copyright © Raytheon Technologies $([System.DateTime]::get_now().ToString("yyyy")) + + + + + + 1.0.0 + Debug;Release;Deploy + + + + + + + + + + + + + + + + diff --git a/Source/MeasurementManagers/PowerSupplyMeasurementManager/PowerSupplySelfTestTime.cs b/Source/MeasurementManagers/PowerSupplyMeasurementManager/PowerSupplySelfTestTime.cs new file mode 100644 index 0000000..5d2184c --- /dev/null +++ b/Source/MeasurementManagers/PowerSupplyMeasurementManager/PowerSupplySelfTestTime.cs @@ -0,0 +1,64 @@ +/*------------------------------------------------------------------------- +// 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; +using System.IO; +using System.Xml.Serialization; + +namespace Raytheon +{ + /// + /// Serialiable class to store self test and power off time to XML + /// and restore info from XML to this class + /// + [Serializable] + public class PowerSupplySelfTestTime + { + [XmlAttribute("power_system")] + public string _powerSystem { get; set; } + + // date and time of last power off of a power module + [XmlAttribute("power_off_time")] + public string _powerOffTime { get; set; } + + // date and time of last successful self test + [XmlAttribute("self_test_time")] + public string _selfTestTime { get; set; } + + /// + /// constructor + /// + public PowerSupplySelfTestTime() + { + _powerOffTime = Raytheon.Common.GeneralConstants.DefaultConfigValue; + _powerSystem = Raytheon.Common.GeneralConstants.DefaultConfigValue; + _selfTestTime = Raytheon.Common.GeneralConstants.DefaultConfigValue; + } + + /// + /// constructor + /// + public PowerSupplySelfTestTime(string powerSystem, string powerOffTime, string selfTestTime) + { + _powerOffTime = powerOffTime; + _powerSystem = powerSystem; + _selfTestTime = selfTestTime; + } + } +} \ No newline at end of file diff --git a/Source/MeasurementManagers/PowerSupplyMeasurementManager/Util.cs b/Source/MeasurementManagers/PowerSupplyMeasurementManager/Util.cs new file mode 100644 index 0000000..2a036b1 --- /dev/null +++ b/Source/MeasurementManagers/PowerSupplyMeasurementManager/Util.cs @@ -0,0 +1,115 @@ +/*------------------------------------------------------------------------- +// 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.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Raytheon.MeasurementManager.PowerSupply +{ + /// + /// Define non-specific constants + /// + internal static class Util + { + /// + /// Read from the XML file the time for this power system + /// If time of power off is available, we return this time + /// If time of last self test run is available, we return this time + /// + /// + /// + public static string GetLastSavedTime(string powerSystem, IConfigurationFile powerOffAndSelfTestConfig) + { + string savedTime = ""; + string powerOffTime = ""; + string selfTestTime = ""; + + List powerOffEntryListTemp = new List(); + + List powerOffEntryList = powerOffAndSelfTestConfig.ReadList(nameof(PowerSupplySelfTestTime), nameof(PowerSupplySelfTestTime), powerOffEntryListTemp); + + foreach (var powerOffEntry in powerOffEntryList) + { + if (powerOffEntry._powerSystem == powerSystem) + { + if (DateTime.TryParse(powerOffEntry._powerOffTime, out DateTime dt)) + powerOffTime = powerOffEntry._powerOffTime; + + if (DateTime.TryParse(powerOffEntry._selfTestTime, out dt)) + selfTestTime = powerOffEntry._selfTestTime; + } + } + + if (String.IsNullOrEmpty(powerOffTime)) + savedTime = selfTestTime; + else if (String.IsNullOrEmpty(selfTestTime)) + savedTime = powerOffTime; + else if (!String.IsNullOrEmpty(powerOffTime) && !String.IsNullOrEmpty(selfTestTime)) + { + if (DateTime.TryParse(powerOffTime, out DateTime powerOffDt) && DateTime.TryParse(selfTestTime, out DateTime selfTestDt)) + { + if (DateTime.Compare(powerOffDt, selfTestDt) == 1) + savedTime = powerOffTime; + else + savedTime = selfTestTime; + } + } + + return savedTime; + } + + /// + /// Save time of power off or self test event + /// + /// + /// + public static void SaveTime(string powerSystem, string powerOffTime, string selfTestTime, IConfigurationFile powerOffAndSelfTestConfig) + { + List powerOffEntryListTemp = new List(); + + List powerOffEntryList = powerOffAndSelfTestConfig.ReadList(nameof(PowerSupplySelfTestTime), nameof(PowerSupplySelfTestTime), powerOffEntryListTemp); + + var entry = powerOffEntryList.Find(b => b._powerSystem == powerSystem); + + if (entry != null) + { + if (!string.IsNullOrEmpty(powerOffTime)) + entry._powerOffTime = powerOffTime; + + if (!string.IsNullOrEmpty(selfTestTime)) + entry._selfTestTime = selfTestTime; + } + else + { + PowerSupplySelfTestTime data = new PowerSupplySelfTestTime(powerSystem, powerOffTime, selfTestTime); + if (string.IsNullOrEmpty(powerOffTime)) + data._powerOffTime = Raytheon.Common.GeneralConstants.DefaultConfigValue; + + if (string.IsNullOrEmpty(selfTestTime)) + data._selfTestTime = Raytheon.Common.GeneralConstants.DefaultConfigValue; + + powerOffEntryList.Add(data); + } + + powerOffAndSelfTestConfig.WriteList(nameof(PowerSupplySelfTestTime), nameof(PowerSupplySelfTestTime), powerOffEntryList); + } + } +} diff --git a/Source/Nuget/NugetOrg/communitytoolkit.mvvm.8.3.2.nupkg b/Source/Nuget/NugetOrg/communitytoolkit.mvvm.8.3.2.nupkg new file mode 100644 index 0000000..5e482ed Binary files /dev/null and b/Source/Nuget/NugetOrg/communitytoolkit.mvvm.8.3.2.nupkg differ diff --git a/Source/Nuget/NugetOrg/microsoft.bcl.asyncinterfaces.8.0.0.nupkg b/Source/Nuget/NugetOrg/microsoft.bcl.asyncinterfaces.8.0.0.nupkg new file mode 100644 index 0000000..f707fc6 Binary files /dev/null and b/Source/Nuget/NugetOrg/microsoft.bcl.asyncinterfaces.8.0.0.nupkg differ diff --git a/Source/Nuget/NugetOrg/system.buffers.4.5.1.nupkg b/Source/Nuget/NugetOrg/system.buffers.4.5.1.nupkg new file mode 100644 index 0000000..f7ee6b2 Binary files /dev/null and b/Source/Nuget/NugetOrg/system.buffers.4.5.1.nupkg differ diff --git a/Source/Nuget/NugetOrg/system.componentmodel.annotations.5.0.0.nupkg b/Source/Nuget/NugetOrg/system.componentmodel.annotations.5.0.0.nupkg new file mode 100644 index 0000000..d318110 Binary files /dev/null and b/Source/Nuget/NugetOrg/system.componentmodel.annotations.5.0.0.nupkg differ diff --git a/Source/Nuget/NugetOrg/system.memory.4.5.5.nupkg b/Source/Nuget/NugetOrg/system.memory.4.5.5.nupkg new file mode 100644 index 0000000..9d654e2 Binary files /dev/null and b/Source/Nuget/NugetOrg/system.memory.4.5.5.nupkg differ diff --git a/Source/Nuget/NugetOrg/system.numerics.vectors.4.5.0.nupkg b/Source/Nuget/NugetOrg/system.numerics.vectors.4.5.0.nupkg new file mode 100644 index 0000000..0ef4637 Binary files /dev/null and b/Source/Nuget/NugetOrg/system.numerics.vectors.4.5.0.nupkg differ diff --git a/Source/Nuget/NugetOrg/system.runtime.compilerservices.unsafe.6.0.0.nupkg b/Source/Nuget/NugetOrg/system.runtime.compilerservices.unsafe.6.0.0.nupkg new file mode 100644 index 0000000..3052c31 Binary files /dev/null and b/Source/Nuget/NugetOrg/system.runtime.compilerservices.unsafe.6.0.0.nupkg differ diff --git a/Source/Nuget/NugetOrg/system.threading.tasks.extensions.4.5.4.nupkg b/Source/Nuget/NugetOrg/system.threading.tasks.extensions.4.5.4.nupkg new file mode 100644 index 0000000..a608bc5 Binary files /dev/null and b/Source/Nuget/NugetOrg/system.threading.tasks.extensions.4.5.4.nupkg differ diff --git a/Source/Nuget/TSRealPackages/microsoft.codecoverage.17.5.0.nupkg b/Source/Nuget/TSRealPackages/microsoft.codecoverage.17.5.0.nupkg new file mode 100644 index 0000000..110e213 Binary files /dev/null and b/Source/Nuget/TSRealPackages/microsoft.codecoverage.17.5.0.nupkg differ diff --git a/Source/Nuget/TSRealPackages/microsoft.net.test.sdk.17.5.0.nupkg b/Source/Nuget/TSRealPackages/microsoft.net.test.sdk.17.5.0.nupkg new file mode 100644 index 0000000..ab6e3e3 Binary files /dev/null and b/Source/Nuget/TSRealPackages/microsoft.net.test.sdk.17.5.0.nupkg differ diff --git a/Source/Nuget/TSRealPackages/mstest.testadapter.3.0.2.nupkg b/Source/Nuget/TSRealPackages/mstest.testadapter.3.0.2.nupkg new file mode 100644 index 0000000..bb5e160 Binary files /dev/null and b/Source/Nuget/TSRealPackages/mstest.testadapter.3.0.2.nupkg differ diff --git a/Source/Nuget/TSRealPackages/mstest.testframework.3.0.2.nupkg b/Source/Nuget/TSRealPackages/mstest.testframework.3.0.2.nupkg new file mode 100644 index 0000000..61969e0 Binary files /dev/null and b/Source/Nuget/TSRealPackages/mstest.testframework.3.0.2.nupkg differ diff --git a/Source/Nuget/TSRealPackages/nlog.5.0.0.nupkg b/Source/Nuget/TSRealPackages/nlog.5.0.0.nupkg new file mode 100644 index 0000000..1eb0d66 Binary files /dev/null and b/Source/Nuget/TSRealPackages/nlog.5.0.0.nupkg differ diff --git a/Source/Nuget/TSRealPackages/raytheon.communication.rpc.contracts.1.8.1.13.nupkg b/Source/Nuget/TSRealPackages/raytheon.communication.rpc.contracts.1.8.1.13.nupkg new file mode 100644 index 0000000..e394613 Binary files /dev/null and b/Source/Nuget/TSRealPackages/raytheon.communication.rpc.contracts.1.8.1.13.nupkg differ diff --git a/Source/Nuget/TSRealPackages/raytheon.communication.ums.core.contracts.1.1.2.1.nupkg b/Source/Nuget/TSRealPackages/raytheon.communication.ums.core.contracts.1.1.2.1.nupkg new file mode 100644 index 0000000..0e203f1 Binary files /dev/null and b/Source/Nuget/TSRealPackages/raytheon.communication.ums.core.contracts.1.1.2.1.nupkg differ diff --git a/Source/Nuget/TSRealPackages/raytheon.communication.ums.rpc.attributes.1.0.4.1.nupkg b/Source/Nuget/TSRealPackages/raytheon.communication.ums.rpc.attributes.1.0.4.1.nupkg new file mode 100644 index 0000000..5934c53 Binary files /dev/null and b/Source/Nuget/TSRealPackages/raytheon.communication.ums.rpc.attributes.1.0.4.1.nupkg differ diff --git a/Source/Nuget/TSRealPackages/raytheon.composition.1.0.0.14.nupkg b/Source/Nuget/TSRealPackages/raytheon.composition.1.0.0.14.nupkg new file mode 100644 index 0000000..47b6eb8 Binary files /dev/null and b/Source/Nuget/TSRealPackages/raytheon.composition.1.0.0.14.nupkg differ diff --git a/Source/Nuget/TSRealPackages/raytheon.configuration.2.6.1.nupkg b/Source/Nuget/TSRealPackages/raytheon.configuration.2.6.1.nupkg new file mode 100644 index 0000000..1195fbe Binary files /dev/null and b/Source/Nuget/TSRealPackages/raytheon.configuration.2.6.1.nupkg differ diff --git a/Source/Nuget/TSRealPackages/raytheon.configuration.contracts.2.3.0.nupkg b/Source/Nuget/TSRealPackages/raytheon.configuration.contracts.2.3.0.nupkg new file mode 100644 index 0000000..8f9a6f0 Binary files /dev/null and b/Source/Nuget/TSRealPackages/raytheon.configuration.contracts.2.3.0.nupkg differ diff --git a/Source/Nuget/TSRealPackages/raytheon.instruments.rpcinstrumentmanager.contracts.1.1.1.nupkg b/Source/Nuget/TSRealPackages/raytheon.instruments.rpcinstrumentmanager.contracts.1.1.1.nupkg new file mode 100644 index 0000000..203e9d9 Binary files /dev/null and b/Source/Nuget/TSRealPackages/raytheon.instruments.rpcinstrumentmanager.contracts.1.1.1.nupkg differ diff --git a/Source/Nuget/TSRealPackages/raytheon.logging.contracts.1.3.0.nupkg b/Source/Nuget/TSRealPackages/raytheon.logging.contracts.1.3.0.nupkg new file mode 100644 index 0000000..a07e5c4 Binary files /dev/null and b/Source/Nuget/TSRealPackages/raytheon.logging.contracts.1.3.0.nupkg differ diff --git a/Source/Program.props b/Source/Program.props new file mode 100644 index 0000000..084e1b6 --- /dev/null +++ b/Source/Program.props @@ -0,0 +1,31 @@ + + + + + $([System.DateTime]::get_now().ToString("yyyy")) + + $(Year) + $([System.DateTime]::get_now().ToString("MM")) + $([System.DateTime]::get_now().ToString("dd")) + $([MSBuild]::Divide($([System.DateTime]::get_Now().get_TimeOfDay().get_TotalMinutes()), 2).ToString('F0')) + + $(Major).$(Minor).$(Build).$(Revision) + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Program.sln b/Source/Program.sln new file mode 100644 index 0000000..a866412 --- /dev/null +++ b/Source/Program.sln @@ -0,0 +1,151 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34408.163 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Program", "Program\Program.csproj", "{00896DC5-536A-4036-85A9-B9E7F9FB712E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests", "UnitTests\UnitTests.csproj", "{9425542E-2602-4043-8583-1378BD959589}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Program", "_Program", "{4D2003A8-CBCB-498C-9186-355650A84D41}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interfaces", "Interfaces", "{B966EB5E-29AF-4641-A4EF-EB77444FE06A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Instruments.Contracts", "Interfaces\IInstrument\Instruments.Contracts.csproj", "{CDC73C19-53A6-47B3-9B53-54D99C551EC2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Instruments.InstrumentManager.Contracts", "Interfaces\IInstrumentManager\Instruments.InstrumentManager.Contracts.csproj", "{481E843F-3E5F-45E6-8CC9-2FE5D750038A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Instruments", "Instruments", "{2075F72F-BBE8-48A2-B7CA-4401FEDA5457}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeneralIntsrumentManager", "Instruments\GeneralIntsrumentManager\GeneralIntsrumentManager.csproj", "{3484D84A-5374-422D-B087-D16F9911749B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PowerSupplies", "PowerSupplies", "{69413672-FD51-480A-B8D5-3E1C7B720929}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EthernetSockets", "EthernetSockets", "{2CF1CAF6-8241-46A0-BC97-CF69F2F14C90}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TcpClient", "Instruments\EthernetSockets\CommDeviceTcpClient\TcpClient.csproj", "{4B168939-2EC4-4710-B7C9-E41F6E4C6A23}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommDevice.Contracts", "Interfaces\ICommDevice\CommDevice.Contracts.csproj", "{372502DE-CB7B-4DBB-A669-0639BDAB0CFC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerSupply.Contracts", "Interfaces\PowerSupply\PowerSupply.Contracts.csproj", "{2E6A9882-5CCD-4737-8170-2DF0943E5F3E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerSupplySim", "Instruments\PowerSupplies\PowerSupplySim\PowerSupplySim.csproj", "{E43692A0-43F8-40EB-A5F4-0F5F15FC1055}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KeysightN67XX", "Instruments\PowerSupplies\Keysight67XX\KeysightN67XX.csproj", "{4FDBF1AB-19BE-419D-B2E6-B9D236F40914}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MeasurementManagers", "MeasurementManagers", "{C440909C-8430-4BFC-ADAD-2144BFFA050F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerSupplyMeasurementManager", "MeasurementManagers\PowerSupplyMeasurementManager\PowerSupplyMeasurementManager.csproj", "{143332EA-D6A2-456E-991D-7710B911F2D5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProgramGui", "ProgramGUI\ProgramGui.csproj", "{44C9E245-6152-4EC9-ACE4-577FE366FCBD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Raytheon.Common", "Raytheon.Common\Raytheon.Common.csproj", "{E51671D2-86BE-4BCC-B7AF-2749CEDB19F2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Deploy|Any CPU = Deploy|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {00896DC5-536A-4036-85A9-B9E7F9FB712E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {00896DC5-536A-4036-85A9-B9E7F9FB712E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {00896DC5-536A-4036-85A9-B9E7F9FB712E}.Deploy|Any CPU.ActiveCfg = Debug|Any CPU + {00896DC5-536A-4036-85A9-B9E7F9FB712E}.Deploy|Any CPU.Build.0 = Debug|Any CPU + {00896DC5-536A-4036-85A9-B9E7F9FB712E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {00896DC5-536A-4036-85A9-B9E7F9FB712E}.Release|Any CPU.Build.0 = Release|Any CPU + {9425542E-2602-4043-8583-1378BD959589}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9425542E-2602-4043-8583-1378BD959589}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9425542E-2602-4043-8583-1378BD959589}.Deploy|Any CPU.ActiveCfg = Debug|Any CPU + {9425542E-2602-4043-8583-1378BD959589}.Deploy|Any CPU.Build.0 = Debug|Any CPU + {9425542E-2602-4043-8583-1378BD959589}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9425542E-2602-4043-8583-1378BD959589}.Release|Any CPU.Build.0 = Release|Any CPU + {CDC73C19-53A6-47B3-9B53-54D99C551EC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CDC73C19-53A6-47B3-9B53-54D99C551EC2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CDC73C19-53A6-47B3-9B53-54D99C551EC2}.Deploy|Any CPU.ActiveCfg = Debug|Any CPU + {CDC73C19-53A6-47B3-9B53-54D99C551EC2}.Deploy|Any CPU.Build.0 = Debug|Any CPU + {CDC73C19-53A6-47B3-9B53-54D99C551EC2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CDC73C19-53A6-47B3-9B53-54D99C551EC2}.Release|Any CPU.Build.0 = Release|Any CPU + {481E843F-3E5F-45E6-8CC9-2FE5D750038A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {481E843F-3E5F-45E6-8CC9-2FE5D750038A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {481E843F-3E5F-45E6-8CC9-2FE5D750038A}.Deploy|Any CPU.ActiveCfg = Debug|Any CPU + {481E843F-3E5F-45E6-8CC9-2FE5D750038A}.Deploy|Any CPU.Build.0 = Debug|Any CPU + {481E843F-3E5F-45E6-8CC9-2FE5D750038A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {481E843F-3E5F-45E6-8CC9-2FE5D750038A}.Release|Any CPU.Build.0 = Release|Any CPU + {3484D84A-5374-422D-B087-D16F9911749B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3484D84A-5374-422D-B087-D16F9911749B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3484D84A-5374-422D-B087-D16F9911749B}.Deploy|Any CPU.ActiveCfg = Debug|Any CPU + {3484D84A-5374-422D-B087-D16F9911749B}.Deploy|Any CPU.Build.0 = Debug|Any CPU + {3484D84A-5374-422D-B087-D16F9911749B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3484D84A-5374-422D-B087-D16F9911749B}.Release|Any CPU.Build.0 = Release|Any CPU + {4B168939-2EC4-4710-B7C9-E41F6E4C6A23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4B168939-2EC4-4710-B7C9-E41F6E4C6A23}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4B168939-2EC4-4710-B7C9-E41F6E4C6A23}.Deploy|Any CPU.ActiveCfg = Deploy|Any CPU + {4B168939-2EC4-4710-B7C9-E41F6E4C6A23}.Deploy|Any CPU.Build.0 = Deploy|Any CPU + {4B168939-2EC4-4710-B7C9-E41F6E4C6A23}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4B168939-2EC4-4710-B7C9-E41F6E4C6A23}.Release|Any CPU.Build.0 = Release|Any CPU + {372502DE-CB7B-4DBB-A669-0639BDAB0CFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {372502DE-CB7B-4DBB-A669-0639BDAB0CFC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {372502DE-CB7B-4DBB-A669-0639BDAB0CFC}.Deploy|Any CPU.ActiveCfg = Deploy|Any CPU + {372502DE-CB7B-4DBB-A669-0639BDAB0CFC}.Deploy|Any CPU.Build.0 = Deploy|Any CPU + {372502DE-CB7B-4DBB-A669-0639BDAB0CFC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {372502DE-CB7B-4DBB-A669-0639BDAB0CFC}.Release|Any CPU.Build.0 = Release|Any CPU + {2E6A9882-5CCD-4737-8170-2DF0943E5F3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2E6A9882-5CCD-4737-8170-2DF0943E5F3E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2E6A9882-5CCD-4737-8170-2DF0943E5F3E}.Deploy|Any CPU.ActiveCfg = Deploy|Any CPU + {2E6A9882-5CCD-4737-8170-2DF0943E5F3E}.Deploy|Any CPU.Build.0 = Deploy|Any CPU + {2E6A9882-5CCD-4737-8170-2DF0943E5F3E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2E6A9882-5CCD-4737-8170-2DF0943E5F3E}.Release|Any CPU.Build.0 = Release|Any CPU + {E43692A0-43F8-40EB-A5F4-0F5F15FC1055}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E43692A0-43F8-40EB-A5F4-0F5F15FC1055}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E43692A0-43F8-40EB-A5F4-0F5F15FC1055}.Deploy|Any CPU.ActiveCfg = Deploy|Any CPU + {E43692A0-43F8-40EB-A5F4-0F5F15FC1055}.Deploy|Any CPU.Build.0 = Deploy|Any CPU + {E43692A0-43F8-40EB-A5F4-0F5F15FC1055}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E43692A0-43F8-40EB-A5F4-0F5F15FC1055}.Release|Any CPU.Build.0 = Release|Any CPU + {4FDBF1AB-19BE-419D-B2E6-B9D236F40914}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4FDBF1AB-19BE-419D-B2E6-B9D236F40914}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4FDBF1AB-19BE-419D-B2E6-B9D236F40914}.Deploy|Any CPU.ActiveCfg = Debug|Any CPU + {4FDBF1AB-19BE-419D-B2E6-B9D236F40914}.Deploy|Any CPU.Build.0 = Debug|Any CPU + {4FDBF1AB-19BE-419D-B2E6-B9D236F40914}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4FDBF1AB-19BE-419D-B2E6-B9D236F40914}.Release|Any CPU.Build.0 = Release|Any CPU + {143332EA-D6A2-456E-991D-7710B911F2D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {143332EA-D6A2-456E-991D-7710B911F2D5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {143332EA-D6A2-456E-991D-7710B911F2D5}.Deploy|Any CPU.ActiveCfg = Deploy|Any CPU + {143332EA-D6A2-456E-991D-7710B911F2D5}.Deploy|Any CPU.Build.0 = Deploy|Any CPU + {143332EA-D6A2-456E-991D-7710B911F2D5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {143332EA-D6A2-456E-991D-7710B911F2D5}.Release|Any CPU.Build.0 = Release|Any CPU + {44C9E245-6152-4EC9-ACE4-577FE366FCBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {44C9E245-6152-4EC9-ACE4-577FE366FCBD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44C9E245-6152-4EC9-ACE4-577FE366FCBD}.Deploy|Any CPU.ActiveCfg = Deploy|Any CPU + {44C9E245-6152-4EC9-ACE4-577FE366FCBD}.Deploy|Any CPU.Build.0 = Deploy|Any CPU + {44C9E245-6152-4EC9-ACE4-577FE366FCBD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {44C9E245-6152-4EC9-ACE4-577FE366FCBD}.Release|Any CPU.Build.0 = Release|Any CPU + {E51671D2-86BE-4BCC-B7AF-2749CEDB19F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E51671D2-86BE-4BCC-B7AF-2749CEDB19F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E51671D2-86BE-4BCC-B7AF-2749CEDB19F2}.Deploy|Any CPU.ActiveCfg = Deploy|Any CPU + {E51671D2-86BE-4BCC-B7AF-2749CEDB19F2}.Deploy|Any CPU.Build.0 = Deploy|Any CPU + {E51671D2-86BE-4BCC-B7AF-2749CEDB19F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E51671D2-86BE-4BCC-B7AF-2749CEDB19F2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {00896DC5-536A-4036-85A9-B9E7F9FB712E} = {4D2003A8-CBCB-498C-9186-355650A84D41} + {CDC73C19-53A6-47B3-9B53-54D99C551EC2} = {B966EB5E-29AF-4641-A4EF-EB77444FE06A} + {481E843F-3E5F-45E6-8CC9-2FE5D750038A} = {B966EB5E-29AF-4641-A4EF-EB77444FE06A} + {3484D84A-5374-422D-B087-D16F9911749B} = {2075F72F-BBE8-48A2-B7CA-4401FEDA5457} + {69413672-FD51-480A-B8D5-3E1C7B720929} = {2075F72F-BBE8-48A2-B7CA-4401FEDA5457} + {2CF1CAF6-8241-46A0-BC97-CF69F2F14C90} = {2075F72F-BBE8-48A2-B7CA-4401FEDA5457} + {4B168939-2EC4-4710-B7C9-E41F6E4C6A23} = {2CF1CAF6-8241-46A0-BC97-CF69F2F14C90} + {372502DE-CB7B-4DBB-A669-0639BDAB0CFC} = {B966EB5E-29AF-4641-A4EF-EB77444FE06A} + {2E6A9882-5CCD-4737-8170-2DF0943E5F3E} = {B966EB5E-29AF-4641-A4EF-EB77444FE06A} + {E43692A0-43F8-40EB-A5F4-0F5F15FC1055} = {69413672-FD51-480A-B8D5-3E1C7B720929} + {4FDBF1AB-19BE-419D-B2E6-B9D236F40914} = {69413672-FD51-480A-B8D5-3E1C7B720929} + {143332EA-D6A2-456E-991D-7710B911F2D5} = {C440909C-8430-4BFC-ADAD-2144BFFA050F} + {44C9E245-6152-4EC9-ACE4-577FE366FCBD} = {4D2003A8-CBCB-498C-9186-355650A84D41} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {CA9C7EC5-FDF7-444C-99C8-7BDBE8AF4EDB} + EndGlobalSection +EndGlobal diff --git a/Source/Program/Actions/UutPowerAction.cs b/Source/Program/Actions/UutPowerAction.cs new file mode 100644 index 0000000..1cee122 --- /dev/null +++ b/Source/Program/Actions/UutPowerAction.cs @@ -0,0 +1,220 @@ +/*------------------------------------------------------------------------- +// 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 ProgramLib; +using NLog; +using Raytheon.Common; +using Raytheon.Instruments; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using ProgramGui; +using ProgramGui.Model; +using ProgramGui.View; +using ProgramGui.ViewModel; +using System.Windows; +using Raytheon; + +namespace ProgramLib +{ + internal class UutPowerAction + { + #region PrivateClassMembers + private static NLog.ILogger _logger; + + private static object powerSyncObj = new object(); + + private bool _sttoSuccess = true; + + private string fatalErrorMsg; + + #endregion + + public UutPowerAction() + { + _logger = LogManager.GetCurrentClassLogger(); + } + + ~UutPowerAction() + { + _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ..."); + } + + /// + /// Power off UUT + /// + /// + /// + public void UutPowerOff() + { + try + { + lock (powerSyncObj) + { + _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method..."); + + Program.Instance().GetPowerSupplyMeasurementManager()[PowerSupplyConstants.POWER_DEVICE.STE_POWER_SUPPLY_SYSTEM].OutputDisable(ProgramLib.PowerSupplyConstants.POWER_DEVICE.STE_PVM_5V); + // enable front panel + Program.Instance().GetPowerSupplyMeasurementManager()[PowerSupplyConstants.POWER_DEVICE.STE_POWER_SUPPLY_SYSTEM].FrontPanelEnabled = true; + + // signal to PowerSupplyReadThread to stop monitoring power + Program.Instance()._eventManager[EventManager.Events.UUT_POWER_OFF].Set(); + + ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.MAIN].Dispatcher.Invoke((Action)delegate + { + ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.MAIN].Hide(); + }); + } + } + catch (Exception) + { + throw; + } + } + + /// + /// Power on UUT + /// + /// + /// + public void UutPowerOn() + { + try + { + lock (powerSyncObj) + { + _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method..."); + + Program.Instance().GetPowerSupplyMeasurementManager()[PowerSupplyConstants.POWER_DEVICE.STE_POWER_SUPPLY_SYSTEM].ReadPowerSupplyData(ProgramLib.PowerSupplyConstants.POWER_DEVICE.STE_PVM_5V, out double voltage, out double current, out double voltageSetPoint, out bool isOn, out int faultStatus); + + if (!isOn) + { + Task.Factory.StartNew(() => PerformSttoTask()); + ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.IMPEDANCE_CHECK].Dispatcher.Invoke((Action)delegate + { + ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.MAIN].Hide(); + + ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.IMPEDANCE_CHECK].ShowDialog(); + }); + + if (_sttoSuccess) + { + ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.IMPEDANCE_CHECK].Dispatcher.Invoke((Action)delegate + { + ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.MAIN].Show(); + }); + + Program.Instance().GetPowerSupplyMeasurementManager()[PowerSupplyConstants.POWER_DEVICE.STE_POWER_SUPPLY_SYSTEM].OutputEnable(ProgramLib.PowerSupplyConstants.POWER_DEVICE.STE_PVM_5V); + + // disable front panel + Program.Instance().GetPowerSupplyMeasurementManager()[PowerSupplyConstants.POWER_DEVICE.STE_POWER_SUPPLY_SYSTEM].FrontPanelEnabled = false; + + // signal to PowerSupplyReadThread to start monitoring power + Program.Instance()._eventManager[EventManager.Events.UUT_POWER_ON].Set(); + } + else + { + throw new Exception(fatalErrorMsg); + } + } + } + } + catch (Exception) + { + throw; + } + } + + private async void PerformSttoTask() + { + ImpedanceDataModel impedanceDataModel; + ImpedanceCheckWindow impedanceCheckWindow = (ImpedanceCheckWindow)ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.IMPEDANCE_CHECK]; + + try + { + _logger?.Debug($"{this.GetType().Name}::PerformSttoTask() running..."); + + bool forceFail = false; + string measurementStatus = "PASSED"; + + ImpedanceCheckWindowViewModel.Images passFailImage = ImpedanceCheckWindowViewModel.Images.PASS_CHECK; + impedanceCheckWindow._viewModel.ClearData(); + int MAX_ITERATION = 15; + int cableNum = 17; + int cablePin1 = 5; + int cablePin2 = 7; + int measurement = 5; + string measurementName; + for (int i = 1; i <= MAX_ITERATION; i++) + { + measurementName = $"P{cableNum}_P{cablePin1++}_P{cableNum++}_P{cablePin2++}"; + impedanceDataModel = new ImpedanceDataModel(); + if (i == MAX_ITERATION / 2 && forceFail) + { + passFailImage = ImpedanceCheckWindowViewModel.Images.FAIL_CHECK; + measurementStatus = "FAILED"; + _sttoSuccess = false; + } + + impedanceDataModel.PassFailImagePath = impedanceCheckWindow._viewModel._imageToResourcePathDict[passFailImage]; + impedanceDataModel.Description = $"{measurementName} Measured {measurement} Range [0,50]"; + + if (Program.Instance()._testStandSeqContext != null) + { + Program.Instance()._testStandSeqContext.Step.AdditionalResults.CustomResults.Insert($"\"{measurementName}\"", $"\"Measured: {measurement++} Range [0,50] - {measurementStatus}\""); + } + + impedanceCheckWindow._viewModel.AddData(impedanceDataModel); + + if (!_sttoSuccess) + { + fatalErrorMsg = impedanceDataModel.Description; + throw new Exception(fatalErrorMsg); + } + + await Task.Delay(300); + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + finally + { + if (!_sttoSuccess) + { + impedanceCheckWindow.Dispatcher.Invoke((Action)delegate + { + impedanceCheckWindow.btnClose.Visibility = Visibility.Visible; + }); + } + else + { + impedanceCheckWindow.Dispatcher.Invoke((Action)delegate + { + impedanceCheckWindow.Hide(); + }); + } + + _logger?.Debug($"{this.GetType().Name}::PerformSttoTask() exiting..."); + } + } + } +} diff --git a/Source/Program/Common/BaseClass/BasicThread.cs b/Source/Program/Common/BaseClass/BasicThread.cs new file mode 100644 index 0000000..ba41ccd --- /dev/null +++ b/Source/Program/Common/BaseClass/BasicThread.cs @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------- +// 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; +using System.Threading.Tasks; + +namespace ProgramLib +{ + /// + /// Abstract base class for all threads + /// + internal abstract class BasicThread + { + protected Thread _thread; + + /// + /// Spawn thread and start it + /// + /// + /// + public void Start() + { + _thread = new Thread(new ThreadStart(DoWork)); + _thread.Start(); + } + + /// + /// Method that executes on the thread. + /// Child class must implement this method + /// + /// + /// + protected abstract void DoWork(); + + /// + /// Tells thread to quit + /// + /// + /// + public virtual void Quit() { } + + /// + /// Wait for thread to exit + /// + /// + /// + public virtual void WaitForExit() + { + if (_thread != null) + { + // wait for thread to terminate + _thread.Join(); + } + } + } +} diff --git a/Source/Program/Common/ConfigLogic/GeneralConstants.cs b/Source/Program/Common/ConfigLogic/GeneralConstants.cs new file mode 100644 index 0000000..2eec039 --- /dev/null +++ b/Source/Program/Common/ConfigLogic/GeneralConstants.cs @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- +// 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 ProgramLib +{ + /// + /// Define non-specific constants + /// + internal static class GeneralConstants + { + public const string ProgramConfigFilename = "config.ini"; + public const string DefaultConfigValue = "NOTSET"; + } +} diff --git a/Source/Program/Common/ConfigLogic/PowerSupplyConstants.cs b/Source/Program/Common/ConfigLogic/PowerSupplyConstants.cs new file mode 100644 index 0000000..9603279 --- /dev/null +++ b/Source/Program/Common/ConfigLogic/PowerSupplyConstants.cs @@ -0,0 +1,42 @@ +/*------------------------------------------------------------------------- +// 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 ProgramLib +{ + /// + /// Power supply constants + /// + internal static class PowerSupplyConstants + { + public enum POWER_DEVICE + { + STE_POWER_SUPPLY_SYSTEM, + + // Power modules + UUT_REF_3_3V, + STE_PVM_5V, + STE_GU_INTERFACE_RELAYS_25V, + STE_GU_INTERFACE_RF_INTERFACE_5V, + } + } +} diff --git a/Source/Program/Common/ConfigLogic/ProgramConfigIni.cs b/Source/Program/Common/ConfigLogic/ProgramConfigIni.cs new file mode 100644 index 0000000..73fd3c6 --- /dev/null +++ b/Source/Program/Common/ConfigLogic/ProgramConfigIni.cs @@ -0,0 +1,41 @@ +/*------------------------------------------------------------------------- +// 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 ProgramLib +{ + /// + /// Define all the sections and keys that exists in the INI file + /// + internal enum ProgramConfigIni + { + // list all the sections here + GENERAL, + + // list all the keys here + DATA_BASE_PATH, + DATA_TEMP_PATH, + APP_BASE_PATH, + POWER_SUPPLY_SELF_TEST_DATETIME, + POWER_SUPPLY_READ_RATE + } +} diff --git a/Source/Program/Common/ConfigLogic/UutInfo.cs b/Source/Program/Common/ConfigLogic/UutInfo.cs new file mode 100644 index 0000000..298fba6 --- /dev/null +++ b/Source/Program/Common/ConfigLogic/UutInfo.cs @@ -0,0 +1,69 @@ +/*------------------------------------------------------------------------- +// 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; + +namespace ProgramLib +{ + /// + /// Store UUT information + /// + internal class UutInfo + { + #region PublicMembers + #endregion + + #region PrivateClassMembers + // class variables + private readonly string _partNumber; + private readonly string _serialNumber; + #endregion + + #region PrivateFuctions + /// + /// The constructor + /// + public UutInfo(string partNumber, string serialNumber) + { + _partNumber = partNumber; + _serialNumber = serialNumber; + } + #endregion + + #region PublicFuctions + + /// + /// + /// + /// + internal string GetPartNumber() + { + return _partNumber; + } + + /// + /// + /// + /// + internal string GetSerialNumber() + { + return _serialNumber; + } + + #endregion + } +} diff --git a/Source/Program/Common/Misc/EventGroup.cs b/Source/Program/Common/Misc/EventGroup.cs new file mode 100644 index 0000000..fa79fe9 --- /dev/null +++ b/Source/Program/Common/Misc/EventGroup.cs @@ -0,0 +1,154 @@ +/*------------------------------------------------------------------------- +// 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; +using System.Threading.Tasks; + +namespace ProgramLib +{ + /// + /// Class that maps event array index to any event enumeration and wraps the WaitHandle.WaitAny() function + /// Use case: + /// When calling WaitHandle.WaitAny(EventArray), it only returns the index of the event in the array that is being signalled. + /// Refering to an index of the array to know which event it is is not ideal. We want to be able to refer to an enumeration instead + /// Usage: + /// In class that uses this class, must define a enumeration + /// public enum Events + /// { + /// EVENT1, + /// EVENT2, + /// EVENT3, + /// EVENTN + /// + /// // DO NOT change the name + /// // This must be the last member in the enum + /// EVENT_TIMED_OUT + /// } + /// Dictionary dict = new Dictionary(); + /// dict[Events.EVENT1] = new ManualResetEvent(false); + /// dict[Events.EVENT2] = new AutoResetEvent(false); + /// dict[Events.EVENT3] = new ManualResetEvent(false); + /// dict[Events.EVENTN] = new AutoResetEvent(false); + /// dict[Events.EVENT_TIMED_OUT] = null; + /// + /// EventGroup eventGroup = new EventGroup(dict); + /// + /// Events id = eventGroup.WaitAny([Optional_timeout]); + /// + /// if (id == Events.EVENT_TIMED_OUT){} // only if timeout was specified + /// if (id == Events.EVENT1){} + /// + /// + internal class EventGroup + { + Dictionary _eventDict = null; + T2[] _eventArray = null; + + /// + /// Constructor + /// + private EventGroup() + { + } + + /// + /// Constructor + /// The event enum passed in must be defined in the following format: + /// public enum Events + /// { + /// EVENT1, + /// EVENT2, + /// EVENT3, + /// EVENTN + /// + /// // DO NOT change the name + /// // This must be the last member in the enum + /// EVENT_TIMED_OUT + /// } + /// + /// A dictionary that contains event enum that is associated to an event object + public EventGroup(Dictionary eventDict) + { + if (eventDict == null) + throw new Exception($"{nameof(eventDict)} cannot be null"); + + if (!eventDict.First().Key.GetType().IsEnum) + { + throw new Exception($"{nameof(eventDict)}'s key must be an enumerated type"); + } + + // get the last element in the dictionary + var element = eventDict.ElementAt(eventDict.Count - 1); + + // check if the name of the last enum member is what we expect + string actualNameOfLastEnumMember = ((Enum)Convert.ChangeType(element.Key, typeof(Enum))).ToString(); + + string expectedNameOfLastEnumMember = "EVENT_TIMED_OUT"; + if (actualNameOfLastEnumMember != expectedNameOfLastEnumMember) + { + throw new Exception($"Enum {element.Key.GetType().Name} must have {expectedNameOfLastEnumMember} as its last member. {nameof(eventDict)} must have {expectedNameOfLastEnumMember} as the last key in the dictionary"); + } + + if (eventDict.First().Value.GetType().BaseType != typeof(EventWaitHandle)) + { + throw new Exception($"{nameof(eventDict)}'s value must be ManualResetEvent or AutoResetEvent type"); + } + _eventDict = eventDict; + + _eventArray = new T2[_eventDict.Count - 1]; + + int index = 0; + foreach (KeyValuePair entry in _eventDict) + { + if (index < _eventDict.Count - 1) + _eventArray[index++] = entry.Value; + } + } + + /// + /// Return the enumerated event based on the index of the event in the event array that is being signalled + /// + /// time out in milliseconds + public T1 WaitAny(int? timeoutMilliseconds = null) + { + int index = 0; + T1 eventId = default; + + if (timeoutMilliseconds == null) + index = WaitHandle.WaitAny((EventWaitHandle[])Convert.ChangeType(_eventArray, typeof(EventWaitHandle[]))); + else + index = WaitHandle.WaitAny((EventWaitHandle[])Convert.ChangeType(_eventArray, typeof(EventWaitHandle[])), (int)timeoutMilliseconds); + + if (index == WaitHandle.WaitTimeout) + { + var element = _eventDict.ElementAt(_eventDict.Count - 1); + eventId = element.Key; + } + else + { + var element = _eventDict.ElementAt(index); + eventId = element.Key; + } + + return eventId; + } + } +} diff --git a/Source/Program/Common/Misc/EventManager.Datatypes.cs b/Source/Program/Common/Misc/EventManager.Datatypes.cs new file mode 100644 index 0000000..48933db --- /dev/null +++ b/Source/Program/Common/Misc/EventManager.Datatypes.cs @@ -0,0 +1,39 @@ +/*------------------------------------------------------------------------- +// 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 ProgramLib +{ + /// + /// Partial class... defines all the types that this class needs + /// + internal partial class EventManager + { + public enum Events + { + GLOBAL_QUIT, + UUT_POWER_ON, + UUT_POWER_OFF, + FATAL_FAILURE + } + } +} diff --git a/Source/Program/Common/Misc/EventManager.cs b/Source/Program/Common/Misc/EventManager.cs new file mode 100644 index 0000000..100e213 --- /dev/null +++ b/Source/Program/Common/Misc/EventManager.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; +using System.Threading.Tasks; + +namespace ProgramLib +{ + /// + /// Stores global events that any thread can use to monitor + /// + internal partial class EventManager + { + private EventWaitHandle[] _events = new EventWaitHandle[Enum.GetValues(typeof(Events)).Cast().Max() + 1]; + + // specify which event should have to be manually reset + List _manualEventList = new List + { + Events.GLOBAL_QUIT, + Events.FATAL_FAILURE + }; + + /// + /// The private constructor + /// + public EventManager() + { + for (int i = 0; i < _events.Count(); i++) + { + if (_manualEventList.Contains((Events)i)) + { + _events[i] = new ManualResetEvent(false); + } + else + _events[i] = new AutoResetEvent(false); + } + } + + /// + /// Implement Indexer to obtain an event object + /// + /// + /// + public EventWaitHandle this[Events eventId] + { + get + { + return _events[(int)eventId]; + } + } + } +} diff --git a/Source/Program/Common/Misc/FileAndFolderManager.Datatypes.cs b/Source/Program/Common/Misc/FileAndFolderManager.Datatypes.cs new file mode 100644 index 0000000..bf4a78c --- /dev/null +++ b/Source/Program/Common/Misc/FileAndFolderManager.Datatypes.cs @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------- +// 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 ProgramLib +{ + /// + /// Partial class... defines all the types that this class needs + /// + internal partial class FileAndFolderManager + { + public enum Folders + { + // List data folder + its subfolders + DATA, + DATA_TEMP, + + // List app folder + its folders + APP + } + + public enum Files + { + POWER_SUPPLY_SELF_TEST_DATETIME + } + } +} diff --git a/Source/Program/Common/Misc/FileAndFolderManager.cs b/Source/Program/Common/Misc/FileAndFolderManager.cs new file mode 100644 index 0000000..ffdc1e0 --- /dev/null +++ b/Source/Program/Common/Misc/FileAndFolderManager.cs @@ -0,0 +1,120 @@ +/*------------------------------------------------------------------------- +// 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.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Raytheon.Common; + +namespace ProgramLib +{ + /// + /// Partial class... this is the main class responsible for parsing config.ini in order + /// to construct file paths and folder paths + /// + internal partial class FileAndFolderManager + { + private Dictionary foldersDict = new Dictionary(); + private Dictionary filesDict = new Dictionary(); + + private IConfigurationFile _programConfig; + + /// + /// The private constructor + /// + /// the UUT part number + public FileAndFolderManager(IConfigurationFile programConfig) + { + _programConfig = programConfig; + + buildFolders(); + createFolders(); + buildFiles(); + } + + /// + /// Build folder paths so we can acccess them later + /// + /// + /// + private void buildFolders() + { + string dataBasePath = _programConfig.ReadValue(ProgramConfigIni.GENERAL.ToString(), ProgramConfigIni.DATA_BASE_PATH.ToString(), "NOT SET"); + foldersDict[Folders.DATA] = dataBasePath; + + string val = _programConfig.ReadValue(ProgramConfigIni.GENERAL.ToString(), ProgramConfigIni.DATA_TEMP_PATH.ToString(), "NOT SET"); + foldersDict[Folders.DATA_TEMP] = Path.Combine(dataBasePath, val); + + string appBasePath = _programConfig.ReadValue(ProgramConfigIni.GENERAL.ToString(), ProgramConfigIni.APP_BASE_PATH.ToString(), "NOT SET"); + foldersDict[Folders.APP] = dataBasePath; + } + + /// + /// We create all the necessary folders + /// + /// + /// + private void createFolders() + { + Directory.CreateDirectory(foldersDict[Folders.DATA_TEMP]); + } + + /// + /// Build file paths so we can acccess them later + /// + /// + /// + private void buildFiles() + { + string val = _programConfig.ReadValue(ProgramConfigIni.GENERAL.ToString(), ProgramConfigIni.POWER_SUPPLY_SELF_TEST_DATETIME.ToString(), "NOT SET"); + filesDict[Files.POWER_SUPPLY_SELF_TEST_DATETIME] = Path.Combine(foldersDict[Folders.DATA_TEMP], val); + } + + /// + /// Return the full folder path + /// + /// + /// + public string getFolder(Folders folder) + { + if (foldersDict.ContainsKey(folder)) + { + return foldersDict[folder]; + } + else + throw new Exception($"{folder.ToString()} is invalid"); + } + + /// + /// Return the full file path + /// + /// + /// + public string getFile(Files file) + { + if (filesDict.ContainsKey(file)) + { + return filesDict[file]; + } + else + throw new Exception($"{file.ToString()} is invalid"); + } + } +} diff --git a/Source/Program/Dependencies/NLogWrapper.Part.dll b/Source/Program/Dependencies/NLogWrapper.Part.dll new file mode 100644 index 0000000..7a303d5 Binary files /dev/null and b/Source/Program/Dependencies/NLogWrapper.Part.dll differ diff --git a/Source/Program/Dependencies/NationalInstruments.TestStand.Interop.API.dll b/Source/Program/Dependencies/NationalInstruments.TestStand.Interop.API.dll new file mode 100644 index 0000000..28a2084 Binary files /dev/null and b/Source/Program/Dependencies/NationalInstruments.TestStand.Interop.API.dll differ diff --git a/Source/Program/Dependencies/RINSS/Castle.Core.dll b/Source/Program/Dependencies/RINSS/Castle.Core.dll new file mode 100644 index 0000000..af61d76 Binary files /dev/null and b/Source/Program/Dependencies/RINSS/Castle.Core.dll differ diff --git a/Source/Program/Dependencies/RINSS/Raytheon.Communication.Rpc.Contracts.dll b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Rpc.Contracts.dll new file mode 100644 index 0000000..432a336 Binary files /dev/null and b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Rpc.Contracts.dll differ diff --git a/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Core.Contracts.dll b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Core.Contracts.dll new file mode 100644 index 0000000..79af495 Binary files /dev/null and b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Core.Contracts.dll differ diff --git a/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Core.dll b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Core.dll new file mode 100644 index 0000000..7b2beaa Binary files /dev/null and b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Core.dll differ diff --git a/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Media.Contracts.dll b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Media.Contracts.dll new file mode 100644 index 0000000..af8d337 Binary files /dev/null and b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Media.Contracts.dll differ diff --git a/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Media.Tcp.dll b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Media.Tcp.dll new file mode 100644 index 0000000..9199c78 Binary files /dev/null and b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Media.Tcp.dll differ diff --git a/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.MessageSerializer.Contracts.dll b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.MessageSerializer.Contracts.dll new file mode 100644 index 0000000..766c963 Binary files /dev/null and b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.MessageSerializer.Contracts.dll differ diff --git a/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.MessageSerializer.Fusion.dll b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.MessageSerializer.Fusion.dll new file mode 100644 index 0000000..95443e0 Binary files /dev/null and b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.MessageSerializer.Fusion.dll differ diff --git a/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Rpc.Attributes.dll b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Rpc.Attributes.dll new file mode 100644 index 0000000..b77a9d7 Binary files /dev/null and b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Rpc.Attributes.dll differ diff --git a/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Rpc.dll b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Rpc.dll new file mode 100644 index 0000000..e932afc Binary files /dev/null and b/Source/Program/Dependencies/RINSS/Raytheon.Communication.Ums.Rpc.dll differ diff --git a/Source/Program/Dependencies/RINSS/Raytheon.Configuration.Contracts.dll b/Source/Program/Dependencies/RINSS/Raytheon.Configuration.Contracts.dll new file mode 100644 index 0000000..1a759fe Binary files /dev/null and b/Source/Program/Dependencies/RINSS/Raytheon.Configuration.Contracts.dll differ diff --git a/Source/Program/Dependencies/RINSS/Raytheon.Logging.Contracts.dll b/Source/Program/Dependencies/RINSS/Raytheon.Logging.Contracts.dll new file mode 100644 index 0000000..ded57fb Binary files /dev/null and b/Source/Program/Dependencies/RINSS/Raytheon.Logging.Contracts.dll differ diff --git a/Source/Program/InstrumentConfigFile/Instruments.xml b/Source/Program/InstrumentConfigFile/Instruments.xml new file mode 100644 index 0000000..6369820 --- /dev/null +++ b/Source/Program/InstrumentConfigFile/Instruments.xml @@ -0,0 +1,20 @@ + + + +
+ +
+
+ + + + TCP_CLIENT_1 + EthernetSocketsTcpClientFactory + + + STE_POWER_SUPPLY_SYSTEM + PowerSupplyKeysightN67xxFactory + + + +
\ No newline at end of file diff --git a/Source/Program/InstrumentConfigFile/STE_POWER_SUPPLY_SYSTEM.ini b/Source/Program/InstrumentConfigFile/STE_POWER_SUPPLY_SYSTEM.ini new file mode 100644 index 0000000..2752410 --- /dev/null +++ b/Source/Program/InstrumentConfigFile/STE_POWER_SUPPLY_SYSTEM.ini @@ -0,0 +1,59 @@ +[GENERAL] +ETHERNET_ADDRESS = localhost +ETHERNET_PORT = 5025 +MODULE_DEFINITION = UUT_REF_3_3V, STE_PVM_5V, STE_GU_INTERFACE_RELAYS_25V, STE_GU_INTERFACE_RF_INTERFACE_5V +; 0 means no coupled modules. +; couple means turning on/off any one of the module, turns on/off the others +COUPLED_MODULES = STE_PVM_5V, STE_GU_INTERFACE_RELAYS_25V, STE_GU_INTERFACE_RF_INTERFACE_5V +; 0 means no grouped modules. +; group means turning combining 2 or more modules thus acting as one module +GROUPED_MODULES = 0 +INTERFACE = ETHERNET + +; GU | KW | KWSIM | SELFTEST | ZERO VOLTAGE +[UUT_REF_3_3V] +INDEX = 1 +OCP = 2.0 +OVP = 4.0 +VOLTAGE_SETPOINT = 3.3 + +MIN_VOLTAGE = 3.0 +MAX_VOLTAGE = 3.75 +MAX_CURRENT = 2.0 +MIN_CURRENT = -0.25 + +[STE_PVM_5V] +INDEX = 2 +OCP = 2.0 +OVP = 8.0 +VOLTAGE_SETPOINT = 5.0 + +; STE Power (PVM and peripherals) supply settings +MIN_VOLTAGE = 4.0 +MAX_VOLTAGE = 5.5 +MAX_CURRENT = 1.5 +MIN_CURRENT = -.25 + +[STE_GU_INTERFACE_RELAYS_25V] +INDEX = 3 +OCP = 3.0 +OVP = 34.0 +VOLTAGE_SETPOINT = 25.0 + +; STE Power (GU interface and Relays) Supply settings +MIN_VOLTAGE = 22.0 +MAX_VOLTAGE = 30.0 +MAX_CURRENT = 3.0 +MIN_CURRENT = -0.25 + +[STE_GU_INTERFACE_RF_INTERFACE_5V] +INDEX = 4 +OCP = 5.0 +OVP = 6.5 +VOLTAGE_SETPOINT = 5.0 + +; STE Power (PVM and peripherals) supply settings +MIN_VOLTAGE = 4.0 +MAX_VOLTAGE = 6.3 +MAX_CURRENT = 4.5 +MIN_CURRENT = -.25 \ No newline at end of file diff --git a/Source/Program/InstrumentConfigFile/STE_POWER_SUPPLY_SYSTEM.xml b/Source/Program/InstrumentConfigFile/STE_POWER_SUPPLY_SYSTEM.xml new file mode 100644 index 0000000..9daa01d --- /dev/null +++ b/Source/Program/InstrumentConfigFile/STE_POWER_SUPPLY_SYSTEM.xml @@ -0,0 +1,9 @@ + + + +
+ +
+
+ +
\ No newline at end of file diff --git a/Source/Program/MiscConfigFile/NLog.config b/Source/Program/MiscConfigFile/NLog.config new file mode 100644 index 0000000..86df6fa --- /dev/null +++ b/Source/Program/MiscConfigFile/NLog.config @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Program/Program.Actions.cs b/Source/Program/Program.Actions.cs new file mode 100644 index 0000000..1fcb828 --- /dev/null +++ b/Source/Program/Program.Actions.cs @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------- +// 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 ProgramGui; +using Raytheon.Instruments; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace ProgramLib +{ + public partial class Program + { + public void UutPowerOn() + { + try + { + _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method..."); + + UutPowerAction uutPowerAction = new UutPowerAction(); + + uutPowerAction.UutPowerOn(); + + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + + // DO NOT THROW in this block + // this function will handle the error accordingly since we could be calling this from third-party test executive like TestStand + TerminateTestOnMainThreadError(ex); + } + } + + public void UutPowerOff() + { + try + { + _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method..."); + + UutPowerAction uutPowerAction = new UutPowerAction(); + + uutPowerAction.UutPowerOff(); + + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + + // DO NOT THROW in this block + // this function will handle the error accordingly since we could be calling this from third-party test executive like TestStand + TerminateTestOnMainThreadError(ex); + } + } + } +} diff --git a/Source/Program/Program.MeasurementManager.cs b/Source/Program/Program.MeasurementManager.cs new file mode 100644 index 0000000..f584458 --- /dev/null +++ b/Source/Program/Program.MeasurementManager.cs @@ -0,0 +1,149 @@ +/*------------------------------------------------------------------------- +// 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; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Raytheon.Instruments; +using Raytheon.Common; +using NLog; +using System.Windows.Interop; +using ProgramGui; +using NationalInstruments.TestStand.Interop.API; +using System.Runtime.ExceptionServices; + +namespace ProgramLib +{ + /// + /// Initialization of measurement managers and get methods + /// + public partial class Program + { + // Declare all the instrument managers here + private PowerSupplyMeasurementManager _psManager = null; + private ProgramGuiManager _guiManager = null; + + /// + /// Initialize power supply measurement manager + /// + /// + /// + public void InitializePowerSupplyMeasurementManager() + { + try + { + _psManager = new PowerSupplyMeasurementManager(_instrumentManager, _fileAndFolderManager.getFile(FileAndFolderManager.Files.POWER_SUPPLY_SELF_TEST_DATETIME)); + _psManager.Initialize(); + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + + // DO NOT THROW in this block + // this function will handle the error accordingly since we could be calling this from third-party test executive like TestStand + TerminateTestOnMainThreadError(ex); + } + } + + /// + /// Initialize GUI manager + /// + /// + /// + public void InitializeGuiManager() + { + try + { + _guiManager = new ProgramGuiManager(); + _guiManager.Initialize(); + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + + // DO NOT THROW in this block + // this function will handle the error accordingly since we could be calling this from third-party test executive like TestStand + TerminateTestOnMainThreadError(ex); + } + } + + /// + /// Start all the monitor/read threads here + /// Call this only after ProgramGuiManager and PowerSupplyManager has been initialized since these threads could be + /// accessing those objects + /// + /// + /// + public void InitializeSupportThreads() + { + try + { + if (_threadList.Count() == 0) + { + _threadList.Add(new FailureMonitorThread()); + _threadList.Last().Start(); + + ICollection psList = _instrumentManager.GetInstruments(typeof(PowerSupply)); + + foreach (PowerSupply ps in psList) + { + _threadList.Add(new PowerSupplyReadThread(ps.Name)); + _threadList.Last().Start(); + } + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + + // DO NOT THROW in this block + // this function will handle the error accordingly since we could be calling this from third-party test executive like TestStand + TerminateTestOnMainThreadError(ex); + } + } + + /// + /// Get power supply manager object + /// + /// + /// + public PowerSupplyMeasurementManager GetPowerSupplyMeasurementManager() + { + if (_psManager == null) + InitializePowerSupplyMeasurementManager(); + + return _psManager; + } + + /// + /// Get Gui manager object + /// + /// + /// + public ProgramGuiManager GetGuiManager() + { + if (_guiManager == null) + InitializeGuiManager(); + + return _guiManager; + } + } +} diff --git a/Source/Program/Program.cs b/Source/Program/Program.cs new file mode 100644 index 0000000..8b45853 --- /dev/null +++ b/Source/Program/Program.cs @@ -0,0 +1,275 @@ +/*------------------------------------------------------------------------- +// UNCLASSIFIED +/*------------------------------------------------------------------------- +RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +COMPANY. + +THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. +GOVERNMENT. + +UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +-------------------------------------------------------------------------*/ +using NationalInstruments.TestStand.Interop.API; +using NLog; +using Raytheon.Instruments; +using System; +using System.IO; +using System.Reflection; +using System.Collections.Generic; +using System.Linq; +using Raytheon.Common; + +namespace ProgramLib +{ + /// + /// Class for interfacing with any Test Executive such as third party test executive such as Test Stand + /// DO NOT implement IDisposable interface for this class. If there are unmanaged resources that need to be freed, + /// do it in the destructor. + /// + /// + public partial class Program + { + #region PrivateMemberVariables + // the one and only program + private static Program _program; + + private object _terminateTestSyncObj = new object(); + private bool _terminateTestInitiated = false; + + // simulation + private readonly bool _isThereHardware; + + // file management + private string _partNumber; + private string _serialNumber; + + private List _threadList = new List(); + + private IInstrumentManager _instrumentManager; + + private ILogger _logger; + + private object _fatalErrorMsgFromThreadSyncObj = new object(); + private string _fatalErrorMsgFromThread; + + #endregion + + internal SequenceContext _testStandSeqContext; + internal UutInfo _uutInfo; + internal EventManager _eventManager = new EventManager(); + internal FileAndFolderManager _fileAndFolderManager; + internal IConfigurationFile _programConfig { get; private set; } + + /// + /// Create an instance of this class. Only one instance is allowed + /// + /// The UUT part number + /// The UUT serial number + /// false for simulation + /// + public static Program Instance(string partNumber = "", string serialNumber = "", bool isThereHardware = true, object testStandSeqContext = null) + { + if (_program == null) + { + _program = new Program(partNumber, serialNumber, isThereHardware, testStandSeqContext); + } + + return _program; + } + + /// + /// This function is only meant to be called from third-party test executive such as TestStand. + /// By settting this object to null, Garbage collection is initiated on this objects and any objects created by this object + /// with the exception of static objects. Static objects needs to be explicitly killed by setting them to null + /// + /// + public static void KillInstance() + { + if (_program != null) + { + // signal to all running threads to exit + _program._eventManager[EventManager.Events.GLOBAL_QUIT].Set(); + + UutPowerAction uutPowerAction = new UutPowerAction(); + uutPowerAction.UutPowerOff(); + + // needs to kill all the support threads since they could be accessing GUI + _program.KillSupportThreads(); + + // Because the GuiManager class starts a STA thread to manage WPF GUIs + // the destructor doesn't get called if we don't shut down the STA thread first + // so we explicitly call Dispose here to shutdown the thread. This is a special case. + // All other classes call Dispose() in their Destructor + _program.GetGuiManager()?.Dispose(); + + // this starts garbage collection on this object which then in turn start garbage collection + // on all objects it created + _program = null; + } + } + + /// + /// The private constructor + /// + /// the UUT part number + /// the UUT serial number + /// false for simulation + private Program(string partNumber, string serialNumber, bool isThereHardware, object testStandSeqContext) + { + // this line is for when this is called from third-party test executive such as TestStand. Without this, NLOG library won't be able to find the NLog.config file + NLog.LogManager.Setup().LoadConfigurationFromFile(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "NLog.config")); + + _logger = LogManager.GetCurrentClassLogger(); + + string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + _programConfig = new ConfigurationFile(Path.Combine(assemblyFolder, GeneralConstants.ProgramConfigFilename)); + + _fileAndFolderManager = new FileAndFolderManager(_programConfig); + + if (testStandSeqContext != null) + { + _testStandSeqContext = testStandSeqContext as SequenceContext; + } + + // make sure PN/SN are valid (TS may not pass in the PN) + if (partNumber == "" || partNumber == null) + { + partNumber = "DefaultPN"; + } + + if (serialNumber == "" || serialNumber == null) + { + serialNumber = "DefaultSN"; + } + + _partNumber = partNumber; + _serialNumber = serialNumber; + _isThereHardware = isThereHardware; + + // Initialze all other configuration that the program needs + _uutInfo = new UutInfo(_partNumber, _serialNumber); + + try + { + var configFolder = Path.Combine(assemblyFolder, Raytheon.Common.GeneralConstants.InstrumentConfigFolder); + _instrumentManager = new GeneralInstrumentManager(assemblyFolder, configFolder, _isThereHardware); + _instrumentManager.Initialize(); + } + catch (Exception) + { + } + } + + /// + /// Finalizer + /// + ~Program() + { + _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ..."); + + if (_testStandSeqContext != null) + { + // clear any setting that we have added for any steps in the Setup Group + for (int i = 0; i < _testStandSeqContext.Sequence.GetNumSteps(StepGroups.StepGroup_Setup); i++) + { + _testStandSeqContext.Sequence.GetStep(i, StepGroups.StepGroup_Setup).PostExpression = ""; + } + + // clear any setting that we have added for any steps in the Main Group + for (int i = 0; i < _testStandSeqContext.Sequence.GetNumSteps(StepGroups.StepGroup_Main); i++) + { + _testStandSeqContext.Sequence.GetStep(i, StepGroups.StepGroup_Main).PostExpression = ""; + _testStandSeqContext.Sequence.GetStep(i, StepGroups.StepGroup_Main).AdditionalResults.CustomResults.Clear(); + } + } + } + + private void KillSupportThreads() + { + foreach (BasicThread thread in _threadList) + { + thread.Quit(); + thread.WaitForExit(); + } + } + + /// + /// All code module should not throw exception into teststand and let teststand handle the exception + /// We give the teststand step a nice error message and tell teststand to go to cleanup + /// If we are not calling into code from teststand, then we throw exception as usual + /// Call this only from code executing on the main TestStand thread + /// + /// + /// + private void TerminateTestOnMainThreadError(Exception ex) + { + if (_testStandSeqContext != null) + { + lock (_terminateTestSyncObj) + { + if (!_terminateTestInitiated) + { + // tells teststand there's a exception occurred and give it the error message + _testStandSeqContext.Step.PostExpression = $"Step.Result.Error.Msg=\"{ex.Message} \", Step.Result.Error.Occurred=True"; + + _testStandSeqContext.Step.ResultStatus = "Error"; + + // tells TestStand to go to clean up + _testStandSeqContext.StepGroup = StepGroups.StepGroup_Cleanup; + _testStandSeqContext.NextStepIndex = 0; + + _terminateTestInitiated = true; + } + } + } + else + throw ex; + } + + /// + /// Support threads such as monitor threads need a way to stop the sequence if it encounters an error + /// This function is meant to be called from FailureMonitorThread which monitors any error signaled by any + /// support thread. + /// + /// + /// + internal void TerminateTestOnSupportThreadError() + { + if (_testStandSeqContext != null) + { + lock (_terminateTestSyncObj) + { + if (!_terminateTestInitiated) + { + // tells teststand there's a exception occurred and give it the error message + _testStandSeqContext.SequenceErrorMessage = _fatalErrorMsgFromThread + " "; + _testStandSeqContext.SequenceErrorOccurred = true; + + // tells TestStand to go to clean up + _testStandSeqContext.StepGroup = StepGroups.StepGroup_Cleanup; + _testStandSeqContext.NextStepIndex = 0; + + _terminateTestInitiated = true; + } + } + } + } + + internal void SetFatalErrorMsgFromThread(string errorMsg) + { + lock(_fatalErrorMsgFromThreadSyncObj) + { + if (String.IsNullOrEmpty(_fatalErrorMsgFromThread)) + { + _fatalErrorMsgFromThread = errorMsg; + } + } + } + } +} diff --git a/Source/Program/Program.csproj b/Source/Program/Program.csproj new file mode 100644 index 0000000..bbf14ae --- /dev/null +++ b/Source/Program/Program.csproj @@ -0,0 +1,77 @@ + + + + net472 + Library + Program + true + Program DLL serves as starting test point + Raytheon Technologies + NGSRI Program + TEEC + Copyright © Raytheon Technologies $([System.DateTime]::get_now().ToString("yyyy")) + true + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + + + + + + 1.0.0 + Debug;Release;Deploy + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\ProgramLib\Dependencies\NationalInstruments.TestStand.Interop.API.dll + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Program/ProgramConfigFile/config.ini b/Source/Program/ProgramConfigFile/config.ini new file mode 100644 index 0000000..39f0483 --- /dev/null +++ b/Source/Program/ProgramConfigFile/config.ini @@ -0,0 +1,13 @@ +[GENERAL] +; specify data folder and all subfolders in it +DATA_BASE_PATH = C:\NGSRI\Data +DATA_TEMP_PATH = Temp + +; specify app folder and all subfolders in it +APP_BASE_PATH = C:\NGSRI\App + +; Log names +POWER_SUPPLY_SELF_TEST_DATETIME = power_supply_self_test_datetime.xml + +; Rates for tasks/threads (secs) +POWER_SUPPLY_READ_RATE = 2 \ No newline at end of file diff --git a/Source/Program/Threads/FailureMonitorThread.cs b/Source/Program/Threads/FailureMonitorThread.cs new file mode 100644 index 0000000..8b8a8a3 --- /dev/null +++ b/Source/Program/Threads/FailureMonitorThread.cs @@ -0,0 +1,99 @@ +/*------------------------------------------------------------------------- +// 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 ProgramGui.Model; +using ProgramGui; +using ProgramLib; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace ProgramLib +{ + /// + /// Monitor fatal failure signaled by other threads + /// + internal class FailureMonitorThread : BasicThread + { + private enum Events + { + GLOBAL_QUIT, + FATAL_FAILURE, + + // DO NOT change the name + // This must be the last member in the enum + EVENT_TIMED_OUT + } + + private ILogger _logger; + + /// + /// Constructor + /// + public FailureMonitorThread() + { + _logger = LogManager.GetCurrentClassLogger(); + } + + /// + /// Destructor + /// + ~FailureMonitorThread() + { + _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ..."); + } + + /// + /// Method that executes on the thread. + /// + protected override void DoWork() + { + _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() is running..."); + + try + { + Dictionary eventDict = new Dictionary(); + eventDict[Events.GLOBAL_QUIT] = Program.Instance()._eventManager[EventManager.Events.GLOBAL_QUIT]; + eventDict[Events.FATAL_FAILURE] = Program.Instance()._eventManager[EventManager.Events.FATAL_FAILURE]; + eventDict[Events.EVENT_TIMED_OUT] = null; + + EventGroup eventGroup = new EventGroup(eventDict); + + Events id = eventGroup.WaitAny(); + + if (id == Events.FATAL_FAILURE) + { + UutPowerAction uutPowerAction = new UutPowerAction(); + uutPowerAction.UutPowerOff(); + + Program.Instance().TerminateTestOnSupportThreadError(); + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + + _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() is exiting..."); + + } + } +} diff --git a/Source/Program/Threads/PowerSupplyReadThread.cs b/Source/Program/Threads/PowerSupplyReadThread.cs new file mode 100644 index 0000000..c80b638 --- /dev/null +++ b/Source/Program/Threads/PowerSupplyReadThread.cs @@ -0,0 +1,202 @@ +/*------------------------------------------------------------------------- +// 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 ProgramGui; +using ProgramGui.Model; +using ProgramGui.ViewModel; +using ProgramLib; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace ProgramLib +{ + internal class PowerSupplyReadThread : BasicThread + { + private enum Events + { + GLOBAL_QUIT, + UUT_POWER_ON, + UUT_POWER_OFF, + + // DO NOT change the name + // This must be the last member in the enum + EVENT_TIMED_OUT + } + + private ILogger _logger; + private MainWindow _mainWindow; + private string _powerSupplySystemName; + + private Dictionary _powerModuleToPowerDataModelDict = new Dictionary(); + private PassthroughData _passthroughData = null; + + public PowerSupplyReadThread(string powerSupplySystemName) + { + _logger = LogManager.GetCurrentClassLogger(); + + _powerSupplySystemName = powerSupplySystemName; + + _mainWindow = (MainWindow)ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.MAIN]; + + _powerModuleToPowerDataModelDict["UUT_P20V"] = new PowerModuleDataModel(); + _powerModuleToPowerDataModelDict["UUT_N20V"] = new PowerModuleDataModel(); + + _passthroughData = new PassthroughData(_mainWindow.datagridPassthroughData.Columns.Count); + + ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.MAIN].Dispatcher.Invoke((Action)delegate + { + _mainWindow._mainWindowViewModel.AddPowerData(_powerModuleToPowerDataModelDict); + _mainWindow._mainWindowViewModel.AddPassthroughData(_passthroughData.GetPassthroughDataModelDict()); + }); + } + + ~PowerSupplyReadThread() + { + _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ..."); + } + + protected override void DoWork() + { + _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() for {_powerSupplySystemName} is running..."); + + try + { + Dictionary eventDict = new Dictionary(); + eventDict[Events.GLOBAL_QUIT] = Program.Instance()._eventManager[EventManager.Events.GLOBAL_QUIT]; + eventDict[Events.UUT_POWER_ON] = Program.Instance()._eventManager[EventManager.Events.UUT_POWER_ON]; + eventDict[Events.EVENT_TIMED_OUT] = null; + + EventGroup eventGroup = new EventGroup(eventDict); + + while (true) + { + Events id = eventGroup.WaitAny(); + + if (id == Events.UUT_POWER_ON) + { + ReadPowerSupplyData(); + } + else + break; + } + } + catch (Exception ex) + { + _logger?.Error(ex.Message + "\n" + ex.StackTrace); + } + + _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() for {_powerSupplySystemName} is exiting..."); + + } + + private void ReadPowerSupplyData() + { + int pollRateMs = 1000; + _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() for {_powerSupplySystemName} is running..."); + + try + { + Dictionary eventDict = new Dictionary(); + eventDict[Events.GLOBAL_QUIT] = Program.Instance()._eventManager[EventManager.Events.GLOBAL_QUIT]; + eventDict[Events.UUT_POWER_OFF] = Program.Instance()._eventManager[EventManager.Events.UUT_POWER_OFF]; + eventDict[Events.EVENT_TIMED_OUT] = null; + + EventGroup eventGroup = new EventGroup(eventDict); + + Random rnd = new Random(); + while (true) + { + Events id = eventGroup.WaitAny(pollRateMs); + + if (id == Events.EVENT_TIMED_OUT) + { + rnd = new Random(); + + _mainWindow._mainWindowViewModel.UutPowerLedImagePath = _mainWindow._mainWindowViewModel._imageToResourcePathDict[MainWindowViewModel.Images.LED_OFF]; + float num = 20.0f + GenerateRandomFraction(); + _powerModuleToPowerDataModelDict["UUT_P20V"].ActualVoltage = num.ToString("0.00"); + _powerModuleToPowerDataModelDict["UUT_P20V"].ExpectedVoltage = "20.0"; + Thread.Sleep(100); + num = 1.0f + GenerateRandomFraction(); + _powerModuleToPowerDataModelDict["UUT_P20V"].ActualCurrent = num.ToString("0.00"); + _powerModuleToPowerDataModelDict["UUT_P20V"].ExpectedCurrent = "1.0"; + Thread.Sleep(100); + num = 20.0f + GenerateRandomFraction(); + _powerModuleToPowerDataModelDict["UUT_N20V"].ActualVoltage = num.ToString("0.00"); + _powerModuleToPowerDataModelDict["UUT_N20V"].ExpectedVoltage = "20.0"; + Thread.Sleep(200); + _mainWindow._mainWindowViewModel.UutPowerLedImagePath = _mainWindow._mainWindowViewModel._imageToResourcePathDict[MainWindowViewModel.Images.LED_ON]; + + num = 5.0f + GenerateRandomFraction(); + _powerModuleToPowerDataModelDict["UUT_N20V"].ActualCurrent = num.ToString("0.00"); + _powerModuleToPowerDataModelDict["UUT_N20V"].ExpectedCurrent = "1.0"; + Thread.Sleep(100); + num = 70.0f + GenerateRandomFraction(); + _passthroughData.SetValue(PassthroughData.Variables.VAR1, num.ToString("0.00")); + + Thread.Sleep(100); + num = 30.0f + GenerateRandomFraction(); + _passthroughData.SetValue(PassthroughData.Variables.VAR2, num.ToString("0.00")); + Thread.Sleep(200); + _mainWindow._mainWindowViewModel.UutPowerLedImagePath = _mainWindow._mainWindowViewModel._imageToResourcePathDict[MainWindowViewModel.Images.LED_OFF]; + num = 40.0f + GenerateRandomFraction(); + _passthroughData.SetValue(PassthroughData.Variables.VAR3, num.ToString("0.00")); + Thread.Sleep(100); + num = 50.0f + GenerateRandomFraction(); + _passthroughData.SetValue(PassthroughData.Variables.VAR4, num.ToString("0.00")); + Thread.Sleep(100); + num = 60.0f + GenerateRandomFraction(); + _passthroughData.SetValue(PassthroughData.Variables.VAR5, num.ToString("0.00")); + Thread.Sleep(200); + _mainWindow._mainWindowViewModel.UutPowerLedImagePath = _mainWindow._mainWindowViewModel._imageToResourcePathDict[MainWindowViewModel.Images.LED_ON]; + num = 10.0f + GenerateRandomFraction(); + _passthroughData.SetValue(PassthroughData.Variables.VAR6, num.ToString("0.00")); + } + else + break; + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + + _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() for {_powerSupplySystemName} is exiting..."); + } + + static float GenerateRandomFraction() + { + Random rnd = new Random(); + int randNum = 0; + const int minimum = 1; + + randNum = rnd.Next(20); + + if (randNum <= minimum) + { + randNum += minimum; + } + + return (float)(1.0 / (float)randNum); + } + } +} diff --git a/Source/ProgramGUI/MainWindow.xaml b/Source/ProgramGUI/MainWindow.xaml new file mode 100644 index 0000000..a76c784 --- /dev/null +++ b/Source/ProgramGUI/MainWindow.xaml @@ -0,0 +1,773 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + M 0,0 L 3.5,4 L 7,0 Z + M 0,4 L 3.5,0 L 7,4 Z + M 0,0 L 4,3.5 L 0,7 Z + F1 M 10.0,1.2 L 4.7,9.1 L 4.5,9.1 L 0,5.2 L 1.3,3.5 L 4.3,6.1L 8.3,0 L 10.0,1.2 Z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [App Title Here] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Placeholder + + Placeholder + + + + + + + diff --git a/Source/ProgramGUI/MainWindow.xaml.cs b/Source/ProgramGUI/MainWindow.xaml.cs new file mode 100644 index 0000000..eaca930 --- /dev/null +++ b/Source/ProgramGUI/MainWindow.xaml.cs @@ -0,0 +1,69 @@ +using ProgramGui.Model; +using ProgramGui.View; +using ProgramGui.ViewModel; +using System; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media.Imaging; +using System.Windows.Threading; + +namespace ProgramGui +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindowViewModel _mainWindowViewModel; + + public ImpedanceCheckWindow _impedanceCheckWindow; + + public MainWindow() + { + InitializeComponent(); + + Uri iconUri = new Uri("pack://application:,,,/ProgramGui;component/Resources/Icons/app.ico"); + this.Icon = BitmapFrame.Create(iconUri); + + WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen; + + _mainWindowViewModel = new MainWindowViewModel(this); + DataContext = _mainWindowViewModel; + } + + private void btnClose_Click(object sender, RoutedEventArgs e) + { + this.Hide(); + } + + private void btnMax_Click(object sender, RoutedEventArgs e) + { + if (this.WindowState == WindowState.Maximized) + { + this.WindowState = WindowState.Normal; + imgMax.Source = new BitmapImage(new System.Uri("pack://application:,,,/Resources/Images/Title_Bar_Buttons/maximize.png")); + } + else + { + this.WindowState = WindowState.Maximized; + imgMax.Source = new BitmapImage(new System.Uri("pack://application:,,,/Resources/Images/Title_Bar_Buttons/restore.png")); + } + } + + private void btnMin_Click(object sender, RoutedEventArgs e) + { + this.WindowState = WindowState.Minimized; + } + + private void Window_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + DragMove(); + } + } +} diff --git a/Source/ProgramGUI/Model/ImpedanceDataModel.cs b/Source/ProgramGUI/Model/ImpedanceDataModel.cs new file mode 100644 index 0000000..7b94feb --- /dev/null +++ b/Source/ProgramGUI/Model/ImpedanceDataModel.cs @@ -0,0 +1,13 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace ProgramGui.Model +{ + public partial class ImpedanceDataModel : ObservableObject + { + [ObservableProperty] + private string passFailImagePath; + + [ObservableProperty] + private string description; + } +} diff --git a/Source/ProgramGUI/Model/PassthroughData.Types.cs b/Source/ProgramGUI/Model/PassthroughData.Types.cs new file mode 100644 index 0000000..00b0ebc --- /dev/null +++ b/Source/ProgramGUI/Model/PassthroughData.Types.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProgramGui.Model +{ + public partial class PassthroughData + { + private struct VariableInfo + { + // index into where the item is located in the dictionary + public int passthroughDataModelDictIndex { get; set; } + // index into where the item is located in the data model + // the data model contains more than one item + public int passthroughDataModelItemIndex { get; set; } + } + public enum Variables + { + VAR1, + VAR2, + VAR3, + VAR4, + VAR5, + VAR6, + VAR7, + VAR8, + VAR9, + VAR10, + VAR11, + VAR12, + VAR13, + VAR14, + VAR15, + VAR16, + VAR17, + VAR18, + VAR19, + VAR20, + VAR21, + VAR22, + VAR23, + VAR24, + VAR25, + VAR26, + VAR27, + VAR28, + VAR29, + VAR30, + VAR31, + VAR32, + VAR33, + VAR34, + VAR35, + VAR36, + VAR37, + VAR38, + VAR39, + VAR40, + VAR41, + VAR42, + }; + + private Dictionary _variableEnumToDescriptionDict = new Dictionary + { + { Variables.VAR1, "IDA Temp" }, + { Variables.VAR2, "FPGA Temp" }, + { Variables.VAR3, "IDA Bias" }, + { Variables.VAR4, "TINT" }, + { Variables.VAR5, "Pitch" }, + { Variables.VAR6, "Yaw" }, + { Variables.VAR7, "Roll" }, + }; + } +} diff --git a/Source/ProgramGUI/Model/PassthroughData.cs b/Source/ProgramGUI/Model/PassthroughData.cs new file mode 100644 index 0000000..df0f8b3 --- /dev/null +++ b/Source/ProgramGUI/Model/PassthroughData.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace ProgramGui.Model +{ + public partial class PassthroughData + { + private int _datagridColumnCount = 0; + // this dictionary stores variable and the info needed to locate it in the passthroughdatamodel dictionary which contains a 2-d array + private Dictionary _variableEnumToVariableInfoDict = new Dictionary(); + + // this dictionary stores variable and its corresponding data model + private Dictionary> _rowNumberToPassthroughDataDict = new Dictionary>(); + + public PassthroughData(int datagridColumnCount) + { + _datagridColumnCount = datagridColumnCount; + VariableInfo variableInfo = new VariableInfo(); + + int dictIndex = 0; + int colIndex = 0; + // contruct a 2-d array of strings based on the list of Variables + foreach (Variables enumVar in Enum.GetValues(typeof(Variables))) + { + if (_rowNumberToPassthroughDataDict.Count == 0 || colIndex == _datagridColumnCount) + { + dictIndex++; + _rowNumberToPassthroughDataDict[dictIndex] = new ObservableCollection(new string[_datagridColumnCount]); + colIndex = 0; + } + + // name of the variable + _rowNumberToPassthroughDataDict[dictIndex][colIndex] = String.Empty; + variableInfo.passthroughDataModelItemIndex = colIndex++; + + // value of the variable + _rowNumberToPassthroughDataDict[dictIndex][colIndex++] = String.Empty; + + // save the row index so we can refer to this item + variableInfo.passthroughDataModelDictIndex = dictIndex; + + // save the column index of this item so we can refer to this item + _variableEnumToVariableInfoDict[enumVar] = variableInfo; + } + } + + public Dictionary> GetPassthroughDataModelDict() + { + return _rowNumberToPassthroughDataDict; + } + + public void SetValue(Variables variableName, string val) + { + _rowNumberToPassthroughDataDict[_variableEnumToVariableInfoDict[variableName].passthroughDataModelDictIndex][_variableEnumToVariableInfoDict[variableName].passthroughDataModelItemIndex] = _variableEnumToDescriptionDict[variableName]; + _rowNumberToPassthroughDataDict[_variableEnumToVariableInfoDict[variableName].passthroughDataModelDictIndex][_variableEnumToVariableInfoDict[variableName].passthroughDataModelItemIndex + 1] = val; + } + } +} diff --git a/Source/ProgramGUI/Model/PowerModuleDataModel.cs b/Source/ProgramGUI/Model/PowerModuleDataModel.cs new file mode 100644 index 0000000..09db259 --- /dev/null +++ b/Source/ProgramGUI/Model/PowerModuleDataModel.cs @@ -0,0 +1,17 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace ProgramGui.Model +{ + public partial class PowerModuleDataModel : ObservableObject + { + [ObservableProperty] + private string expectedVoltage; + [ObservableProperty] + private string actualVoltage; + [ObservableProperty] + private string expectedCurrent; + [ObservableProperty] + private string actualCurrent; + + } +} diff --git a/Source/ProgramGUI/ProgramGui.csproj b/Source/ProgramGUI/ProgramGui.csproj new file mode 100644 index 0000000..be777e1 --- /dev/null +++ b/Source/ProgramGUI/ProgramGui.csproj @@ -0,0 +1,68 @@ + + + + net472 + Library + ProgramGui + true + NGSRI Program GUI + Raytheonn Technologies + NGSRI Program GUI + TEEC + Copyright © Raytheon Technologies $([System.DateTime]::get_now().ToString("yyyy")) + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + + + false + + + + + 1.0.0 + Debug;Release;Deploy + Resources\Icons\app.ico + 8.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/ProgramGUI/ProgramGuiManager.cs b/Source/ProgramGUI/ProgramGuiManager.cs new file mode 100644 index 0000000..99a4e9f --- /dev/null +++ b/Source/ProgramGUI/ProgramGuiManager.cs @@ -0,0 +1,114 @@ +using NLog; +using ProgramGui.View; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Threading; + +namespace ProgramGui +{ + public class ProgramGuiManager : IDisposable + { + #region Private Members + private Thread _guiManagerThread; + private static NLog.ILogger _logger; + private Dictionary _windowDict = new Dictionary(); + private ManualResetEvent _allGuiInitializedEvent = new ManualResetEvent(false); + private bool _isDisposed = false; + #endregion + + #region Public Members + public enum WINDOWS + { + MAIN, + IMPEDANCE_CHECK + } + #endregion + + /// + /// constructor + /// + public ProgramGuiManager() + { + _logger = LogManager.GetCurrentClassLogger(); + } + + /// + /// The Finalizer + /// Do not call Dispose() in here + /// + ~ProgramGuiManager() + { + _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ..."); + } + + public Window this[WINDOWS window] + { + get { return _windowDict[window]; } + } + + /// + /// Initialize all the GUIs + /// + public void Initialize() + { + _guiManagerThread = new Thread(new ThreadStart(GuiManagerThread)); + _guiManagerThread.SetApartmentState(ApartmentState.STA); + _guiManagerThread.Start(); + + _allGuiInitializedEvent.WaitOne(); + } + + private void GuiManagerThread() + { + _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() is running..."); + + // instantiate all the windows here + _windowDict[WINDOWS.MAIN] = new MainWindow(); + _windowDict[WINDOWS.IMPEDANCE_CHECK] = new ImpedanceCheckWindow(); + + _allGuiInitializedEvent.Set(); + + // Enter the event queue + Dispatcher.Run(); + + _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() is exiting..."); + } + + /// + /// Dispose of this object. + /// + public void Dispose() + { + _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ..."); + + try + { + if (!_isDisposed) + { + _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() disposing"); + + _windowDict?.First().Value.Dispatcher.Invoke((Action)delegate + { + // shut down all windows + foreach (var entry in _windowDict) + { + entry.Value.Close(); + } + // kill the GuiManagerthread + Dispatcher.CurrentDispatcher.InvokeShutdown(); + }); + + _isDisposed = true; + } + } + catch (Exception) + { + } + } + } +} diff --git a/Source/ProgramGUI/Properties/Resources.Designer.cs b/Source/ProgramGUI/Properties/Resources.Designer.cs new file mode 100644 index 0000000..22b0fd3 --- /dev/null +++ b/Source/ProgramGUI/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ProgramGui.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DataGrid.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Source/ProgramGUI/Properties/Resources.resx b/Source/ProgramGUI/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Source/ProgramGUI/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/ProgramGUI/Properties/Settings.Designer.cs b/Source/ProgramGUI/Properties/Settings.Designer.cs new file mode 100644 index 0000000..0dbd834 --- /dev/null +++ b/Source/ProgramGUI/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ProgramGui.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.8.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Source/ProgramGUI/Properties/Settings.settings b/Source/ProgramGUI/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/Source/ProgramGUI/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Source/ProgramGUI/Resources/Icons/app.ico b/Source/ProgramGUI/Resources/Icons/app.ico new file mode 100644 index 0000000..5060c9d Binary files /dev/null and b/Source/ProgramGUI/Resources/Icons/app.ico differ diff --git a/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/close_black.png b/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/close_black.png new file mode 100644 index 0000000..d8823ba Binary files /dev/null and b/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/close_black.png differ diff --git a/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/close_white.png b/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/close_white.png new file mode 100644 index 0000000..5446623 Binary files /dev/null and b/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/close_white.png differ diff --git a/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/maximize.png b/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/maximize.png new file mode 100644 index 0000000..f5631ac Binary files /dev/null and b/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/maximize.png differ diff --git a/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/minimize.png b/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/minimize.png new file mode 100644 index 0000000..15c87f7 Binary files /dev/null and b/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/minimize.png differ diff --git a/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/restore.png b/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/restore.png new file mode 100644 index 0000000..67ea757 Binary files /dev/null and b/Source/ProgramGUI/Resources/Images/Title_Bar_Buttons/restore.png differ diff --git a/Source/ProgramGUI/Resources/Images/black-led.png b/Source/ProgramGUI/Resources/Images/black-led.png new file mode 100644 index 0000000..695839f Binary files /dev/null and b/Source/ProgramGUI/Resources/Images/black-led.png differ diff --git a/Source/ProgramGUI/Resources/Images/green-check-mark.png b/Source/ProgramGUI/Resources/Images/green-check-mark.png new file mode 100644 index 0000000..c7fefdc Binary files /dev/null and b/Source/ProgramGUI/Resources/Images/green-check-mark.png differ diff --git a/Source/ProgramGUI/Resources/Images/green-led.png b/Source/ProgramGUI/Resources/Images/green-led.png new file mode 100644 index 0000000..05c8cc3 Binary files /dev/null and b/Source/ProgramGUI/Resources/Images/green-led.png differ diff --git a/Source/ProgramGUI/Resources/Images/missile.png b/Source/ProgramGUI/Resources/Images/missile.png new file mode 100644 index 0000000..7328f61 Binary files /dev/null and b/Source/ProgramGUI/Resources/Images/missile.png differ diff --git a/Source/ProgramGUI/Resources/Images/red-cross-mark.png b/Source/ProgramGUI/Resources/Images/red-cross-mark.png new file mode 100644 index 0000000..c1407a2 Binary files /dev/null and b/Source/ProgramGUI/Resources/Images/red-cross-mark.png differ diff --git a/Source/ProgramGUI/Resources/Images/red-led.png b/Source/ProgramGUI/Resources/Images/red-led.png new file mode 100644 index 0000000..8031ab3 Binary files /dev/null and b/Source/ProgramGUI/Resources/Images/red-led.png differ diff --git a/Source/ProgramGUI/Resources/Images/yellow-led.png b/Source/ProgramGUI/Resources/Images/yellow-led.png new file mode 100644 index 0000000..504ca93 Binary files /dev/null and b/Source/ProgramGUI/Resources/Images/yellow-led.png differ diff --git a/Source/ProgramGUI/View/ImpedanceCheckWindow.xaml b/Source/ProgramGUI/View/ImpedanceCheckWindow.xaml new file mode 100644 index 0000000..f2ddae5 --- /dev/null +++ b/Source/ProgramGUI/View/ImpedanceCheckWindow.xaml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + Impedance Check + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/ProgramGUI/View/ImpedanceCheckWindow.xaml.cs b/Source/ProgramGUI/View/ImpedanceCheckWindow.xaml.cs new file mode 100644 index 0000000..e96a9ae --- /dev/null +++ b/Source/ProgramGUI/View/ImpedanceCheckWindow.xaml.cs @@ -0,0 +1,62 @@ +using ProgramGui.ViewModel; +using System; +using System.Collections.Specialized; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media.Imaging; +using System.Windows.Threading; + +namespace ProgramGui.View +{ + /// + /// Interaction logic for ImpedanceCheckWindow.xaml + /// + public partial class ImpedanceCheckWindow : Window + { + public ImpedanceCheckWindowViewModel _viewModel; + + public ImpedanceCheckWindow() + { + InitializeComponent(); + + Uri iconUri = new Uri("pack://application:,,,/ProgramGui;component/Resources/Icons/app.ico"); + this.Icon = BitmapFrame.Create(iconUri); + + WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen; + + btnClose.Visibility = Visibility.Hidden; + + ((INotifyCollectionChanged)lvImpedanceCheck.Items).CollectionChanged += ListView_CollectionChanged; + + _viewModel = new ImpedanceCheckWindowViewModel(this); + DataContext = _viewModel; + } + + protected override void OnContentRendered(EventArgs e) + { + base.OnContentRendered(e); + + // call the delegate to perform STTO + } + + private void Window_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + DragMove(); + } + + private void btnClose_Click(object sender, RoutedEventArgs e) + { + this.Hide(); + } + + private void ListView_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (e.Action == NotifyCollectionChangedAction.Add) + { + // scroll the new item into view + lvImpedanceCheck.ScrollIntoView(e.NewItems[0]); + } + } + } +} diff --git a/Source/ProgramGUI/ViewModel/ImpedanceCheckWindowViewModel.cs b/Source/ProgramGUI/ViewModel/ImpedanceCheckWindowViewModel.cs new file mode 100644 index 0000000..6315b12 --- /dev/null +++ b/Source/ProgramGUI/ViewModel/ImpedanceCheckWindowViewModel.cs @@ -0,0 +1,53 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using ProgramGui.Model; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Windows; +using System.Windows.Threading; + +namespace ProgramGui.ViewModel +{ + public class ImpedanceCheckWindowViewModel : ObservableObject + { + private Window _window; + public enum Images + { + PASS_CHECK, + FAIL_CHECK + } + + public Dictionary _imageToResourcePathDict = new Dictionary() + { + {Images.PASS_CHECK, @"pack://application:,,,/ProgramGui;component/Resources/Images/green-check-mark.png" }, + {Images.FAIL_CHECK, @"pack://application:,,,/ProgramGui;component/Resources/Images/red-cross-mark.png" } + }; + + #region Data Bindings + public ObservableCollection _listviewImpedanceDatatems { get; set; } + + #endregion Data Bindings + + public ImpedanceCheckWindowViewModel(Window window) + { + _window = window; + _listviewImpedanceDatatems = new ObservableCollection(); + } + + public void AddData(ImpedanceDataModel item) + { + _window.Dispatcher.Invoke((Action)delegate + { + _listviewImpedanceDatatems.Add(item); + }); + } + + public void ClearData() + { + _window.Dispatcher.Invoke((Action)delegate + { + _listviewImpedanceDatatems.Clear(); + }); + } + } +} diff --git a/Source/ProgramGUI/ViewModel/MainWindowViewModel.cs b/Source/ProgramGUI/ViewModel/MainWindowViewModel.cs new file mode 100644 index 0000000..342a086 --- /dev/null +++ b/Source/ProgramGUI/ViewModel/MainWindowViewModel.cs @@ -0,0 +1,74 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using ProgramGui.Model; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace ProgramGui.ViewModel +{ + public partial class MainWindowViewModel : ObservableObject + { + public enum Images + { + LED_ON, + LED_OFF + } + + private Window _window; + + public Dictionary _imageToResourcePathDict = new Dictionary() + { + {Images.LED_ON, @"pack://application:,,,/ProgramGui;component/Resources/Images/green-led.png" }, + {Images.LED_OFF, @"pack://application:,,,/ProgramGui;component/Resources/Images/black-led.png" } + }; + + #region Data Bindings + public ObservableCollection _dataGridPowerDatatems { get; set; } + + // 2-dimensional data array + // inner ObservableCollection<> is the columns + // outer ObservableCollection is the row + public ObservableCollection> _dataGridPassthroughDatatems { get; set; } + + [ObservableProperty] + private string uutPowerLedImagePath; + + [ObservableProperty] + private string tePowerLedImagePath; + + #endregion Data Bindings + + public MainWindowViewModel(Window window) + { + _window = window; + _dataGridPowerDatatems = new ObservableCollection(); + _dataGridPassthroughDatatems = new ObservableCollection>(); + + UutPowerLedImagePath = _imageToResourcePathDict[Images.LED_OFF]; + TePowerLedImagePath = _imageToResourcePathDict[Images.LED_ON]; + } + + public void AddPowerData(Dictionary powerModuleToPowerDataModelDict) + { + foreach (var item in powerModuleToPowerDataModelDict) + { + _dataGridPowerDatatems.Add(item.Value); + } + } + + public void AddPassthroughData(Dictionary> rowNumberToPassthroughDataDict) + { + _window.Dispatcher.Invoke((Action)delegate + { + foreach (var item in rowNumberToPassthroughDataDict) + { + _dataGridPassthroughDatatems.Add(item.Value); + } + }); + } + } +} diff --git a/Source/Raytheon.Common/GeneralConstants.cs b/Source/Raytheon.Common/GeneralConstants.cs new file mode 100644 index 0000000..0f30524 --- /dev/null +++ b/Source/Raytheon.Common/GeneralConstants.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.Common +{ + public static class GeneralConstants + { + public const string InstrumentConfigFolder = "InstrumentConfig"; + public const string DefaultConfigValue = "NOTSET"; + } +} diff --git a/Source/Raytheon.Common/Raytheon.Common.csproj b/Source/Raytheon.Common/Raytheon.Common.csproj new file mode 100644 index 0000000..dda7df4 --- /dev/null +++ b/Source/Raytheon.Common/Raytheon.Common.csproj @@ -0,0 +1,23 @@ + + + + net472 + Library + Raytheon.Common + Raytheon Technologies + Raytheon Common Library + Raytheon Common Library + TEEC + Copyright © Raytheon Technologies $([System.DateTime]::get_now().ToString("yyyy")) + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + + + + + + 1.0.0 + Debug;Release;Deploy + + + \ No newline at end of file diff --git a/Source/TestStand/power_on.ini b/Source/TestStand/power_on.ini new file mode 100644 index 0000000..3b81706 Binary files /dev/null and b/Source/TestStand/power_on.ini differ diff --git a/Source/TestStand/power_on.seq b/Source/TestStand/power_on.seq new file mode 100644 index 0000000..3e6a31e Binary files /dev/null and b/Source/TestStand/power_on.seq differ diff --git a/Source/UnitTests/ProgramUnitTest.cs b/Source/UnitTests/ProgramUnitTest.cs new file mode 100644 index 0000000..82f0b37 --- /dev/null +++ b/Source/UnitTests/ProgramUnitTest.cs @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------- +// 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 Microsoft.VisualStudio.TestTools.UnitTesting; +using System; + +using NLog; +using ProgramLib; +using System.Threading; +using ProgramGui.Model; +using System.Collections.Generic; +using ProgramGui; +using ProgramGui.ViewModel; +using System.Threading.Tasks; +using System.Windows; +using ProgramGui.View; + +namespace UnitTests +{ + [TestClass] + public class ProgramUnitTest + { + private ILogger _logger; + + public ProgramUnitTest() + { + _logger = LogManager.GetCurrentClassLogger(); + } + + [TestMethod] + public void PowerSupplyTest() + { + try + { + ProgramLib.Program.Instance("partNumber", "SerialNumber", false); + ProgramLib.Program.Instance().InitializePowerSupplyMeasurementManager(); + ProgramLib.Program.Instance().InitializeGuiManager(); + ProgramLib.Program.Instance().InitializeSupportThreads(); + + int runs = 2; + int i = 0; + while (i++ < runs) + { + ProgramLib.Program.Instance().UutPowerOn(); + Thread.Sleep(10000); + ProgramLib.Program.Instance().UutPowerOff(); + Thread.Sleep(5000); + ProgramLib.Program.Instance().UutPowerOn(); + Thread.Sleep(10000); + ProgramLib.Program.Instance().UutPowerOff(); + Thread.Sleep(5000); + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + } +} diff --git a/Source/UnitTests/UnitTests.csproj b/Source/UnitTests/UnitTests.csproj new file mode 100644 index 0000000..d8aa33d --- /dev/null +++ b/Source/UnitTests/UnitTests.csproj @@ -0,0 +1,91 @@ + + + + net472 + 8.0 + true + en-US + UnitTests + UnitTestsLib + Raytheon Technologies + TEEC + Library + False + false + enable + true + Debug;Release + + + + + + 3.0.2 + + + 3.0.2 + + + + {2DF8D04C-5BFA-101B-BDE5-00AA0044DE52} + 2 + 8 + 0 + primary + False + True + + + {00020813-0000-0000-C000-000000000046} + 1 + 9 + 0 + primary + False + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/nuget.config b/Source/nuget.config new file mode 100644 index 0000000..108d151 --- /dev/null +++ b/Source/nuget.config @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/readme.txt b/Source/readme.txt new file mode 100644 index 0000000..e22e76b --- /dev/null +++ b/Source/readme.txt @@ -0,0 +1,24 @@ +Issue 1: +On initial check-in or doing a new pull, Git will fail with long file name issue + +Add the following to registry (there's alreawdy a longpath.reg in the how-to folder file created so just run that): + "LongPathsEnabled"=dword:00000001 to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem + +Make sure Git for Windows is installed +Open command prompt in admin mode and run: git config --system core.longpaths true + +----------------------------------------------------------------------------------------- +Issue 2: + +If the solution folder is located in some long path, Visual Studio will not be able to extract Raytheon.Instruments.InstrumentManager.GeneralInstrumentManager.1.4.1.nupkg +to cache folder. Even if we manually move the DLL to the cache folder, Visuao Studio will not see it + +Find a location where the path is not too long and it will build. So work out of there instead + +----------------------------------------------------------------------------------------- +Issue 3: +If building for the first time after doing a Git pull, it will fail because there are a few packages that need to be built first and published to the "SolutionPackages" folder +since other projects that depend on packages in that folder. + +So if the build fails, keep building until succeeds. Takes about 5 tries +