Big changes

This commit is contained in:
Duc
2025-03-13 12:04:22 -07:00
parent c689fcb7f9
commit ffa9905494
748 changed files with 199255 additions and 3743 deletions

View File

@@ -0,0 +1,287 @@
// UNCLASSIFIED
/*-------------------------------------------------------------------------
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
COMPANY.
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
GOVERNMENT.
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
-------------------------------------------------------------------------*/
using System;
using System.IO.Ports;
using System.Net.Sockets;
using System.Threading;
using NLog;
using Raytheon.Common;
namespace Raytheon.Instruments
{
/// <summary>
/// Flow Meter class used to interact with flow meter.
/// It supports the Omega DPF20 when configured to slave mode (where data is pulled as opposed to pushed).
/// Set to slave mode on the front panel
/// </summary>
public class FlowMeterOmegaDPF20 : IFlowMeter
{
#region PublicMembers
public enum FlowMeterMode
{
MASTER,
SLAVE
};
#endregion
#region PrivateMembers
//Prevent Collisions
private static object _sync = new object();
//Ethernet Communication
private readonly string _ipAddr;
private readonly int _port;
private readonly byte _flowMeterAddress;
private readonly FlowMeterOmegaDPF20.FlowMeterMode _mode;
private const int _READ_BUFFER_SIZE = 1024;
private const int _READ_TIMEOUT = 5500;
private byte[] _readBuffer;
private NetworkStream _tcpStream;
TcpClient _flowSocket;
/// <summary>
/// NLog logger
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// Raytheon configuration
/// </summary>
private readonly IConfigurationManager _configurationManager;
private readonly IConfiguration _configuration;
public string DetailedStatus => throw new NotImplementedException();
public bool DisplayEnabled { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public bool FrontPanelEnabled { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public InstrumentMetadata Info => throw new NotImplementedException();
public string Name {get; set;}
public SelfTestResult SelfTestResult => throw new NotImplementedException();
public State Status => throw new NotImplementedException();
#endregion
#region PrivateFunctions
/// <summary>
/// Destructor
/// </summary>
~FlowMeterOmegaDPF20()
{
Dispose(false);
}
/// <summary>
/// Dispose of this object's resources
/// </summary>
/// <param name="disposing">Currently disposing</param>
protected virtual void Dispose(bool disposing)
{
try
{
if (disposing)
{
//Close Connection (if available)
_tcpStream?.Close();
_flowSocket?.Close();
}
}
catch (Exception)
{
try
{
//ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
}
catch (Exception)
{
//Do not rethrow. Exception from error logger that has already been garbage collected
}
}
}
#endregion
#region PublicFunctions
/// <summary>
/// FlowMeterOmegaDPF20 factory constructor
/// </summary>
/// <param name="deviceName"></param>
/// <param name="configurationManager"></param>
public FlowMeterOmegaDPF20(string deviceName, IConfigurationManager configurationManager, ILogger logger)
{
Name = deviceName;
_logger = logger;
_configurationManager = configurationManager;
_configuration = _configurationManager.GetConfiguration(Name);
_ipAddr = _configuration.GetConfigurationValue("FlowMeterOmegaDPF20", "IpAddr", "");
_port = _configuration.GetConfigurationValue("FlowMeterOmegaDPF20", "Port", 0);
_readBuffer = new byte[_READ_BUFFER_SIZE];
//Create and open a socket to flow meter
_flowSocket = new TcpClient(_ipAddr, _port);
_tcpStream = _flowSocket.GetStream();
_tcpStream.ReadTimeout = _READ_TIMEOUT;
}
/// <summary>
/// Constructor for the DPF20 flow meter. It makes a socket connection upon construction
/// </summary>
/// <param name="name">The name. Anything the hosts wants it to be</param>
/// <param name="ipAddress">IP Address of the flow meter server</param>
/// <param name="port">Port of the flow meter server</param>
/// <param name="flowMeterAddress">The address on the front display of the flow meter</param>
/// <param name="mode">The mode on the front display of the flow meter</param>
public FlowMeterOmegaDPF20(string name, string ipAddress, int port, byte flowMeterAddress, FlowMeterOmegaDPF20.FlowMeterMode mode)
{
Name = name;
_logger = LogManager.GetCurrentClassLogger();
_ipAddr = ipAddress;
_port = port;
_flowMeterAddress = flowMeterAddress;
_mode = mode;
//Initialize read buffer
_readBuffer = new byte[_READ_BUFFER_SIZE];
//Create and open a socket to flow meter
_flowSocket = new TcpClient(_ipAddr, _port);
_tcpStream = _flowSocket.GetStream();
_tcpStream.ReadTimeout = _READ_TIMEOUT;
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <param name="comPortName"></param>
/// <param name="delayBeforeReadMs"></param>
/// <param name="baudRate"></param>
/// <param name="parity"></param>
/// <param name="dataBits"></param>
/// <param name="stopBits"></param>
/// <param name="flowMeterAddress">The address on the front display of the flow meter</param>
/// <param name="mode">The mode on the front display of the flow meter</param>
public FlowMeterOmegaDPF20(string name, string comPortName, uint delayBeforeReadMs, int baudRate = 115200, Parity parity = Parity.None, int dataBits = 8, StopBits stopBits = StopBits.One, byte flowMeterAddress = 128, FlowMeterOmegaDPF20.FlowMeterMode mode = FlowMeterMode.SLAVE)
{
throw new NotImplementedException();
}
// This code added to correctly implement the disposable pattern.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")]
public void Dispose()
{
try
{
lock (_sync)
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
catch (Exception ex)
{
_logger.Error(ex.Message);
}
}
/// <summary>
/// Query the flow rate from the flow meter
/// </summary>
/// <returns>the flow rate.</returns>
public double ReadFlow()
{
lock (_sync)
{
if (_mode == FlowMeterMode.SLAVE)
{
byte[] cmd = FlowMeterOmegaDPF20DataParser.CreateReadFlowCmd(_flowMeterAddress);
_tcpStream.Write(cmd, 0, cmd.Length);
int numBytesRead = _tcpStream.Read(_readBuffer, 0, _readBuffer.Length);
double flow = FlowMeterOmegaDPF20DataParser.ParseReadFlowRsp(_readBuffer, numBytesRead);
return flow;
}
else if (_mode == FlowMeterMode.MASTER)
{
const int EXPECTED_DATA_LEN = 18;
// ensure we have at least one full message
// need at least 35 bytes (worst case partial msg plus a full message)
int numBytesAvailable = _flowSocket.Available;
while (numBytesAvailable < (EXPECTED_DATA_LEN * 2) - 1)
{
Thread.Sleep(5);
numBytesAvailable = _flowSocket.Available;
}
byte[] readBuf = new byte[numBytesAvailable];
int numBytesRead = _tcpStream.Read(readBuf, 0, readBuf.Length);
double flow = FlowMeterOmegaDPF20DataParser.ParseMasterFlowMsg(readBuf, numBytesRead);
return flow;
}
else
{
throw new Exception("unknown mode: " + _mode.ToString());
}
}
}
public bool ClearErrors()
{
throw new NotImplementedException();
}
public void Initialize()
{
throw new NotImplementedException();
}
public SelfTestResult PerformSelfTest()
{
throw new NotImplementedException();
}
public void Reset()
{
throw new NotImplementedException();
}
public void Shutdown()
{
throw new NotImplementedException();
}
#endregion
}
}

View File

@@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(SolutionDir)Solution.props" />
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<AssemblyName>Raytheon.Instruments.FlowMeterOmegaDPF20</AssemblyName>
<Product>Flow Meter Omega DPF20 implementation</Product>
<Description>Flow Meter Omega DPF20 implementation</Description>
<OutputType>Library</OutputType>
<!-- Static versioning (Suitable for Development) -->
<!-- Disable the line below for dynamic versioning -->
<Version>1.0.0</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NLog" Version="5.0.0" />
<PackageReference Include="Raytheon.Common" Version="1.0.0" />
<PackageReference Include="Raytheon.Instruments.FlowMeter.Contracts" Version="1.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FlowMeterSim\FlowMeterSim.csproj" />
</ItemGroup>
<!-- Copy all *.dlls and *.pdb in the output folder to a temp folder -->
<Target Name="CopyFiles" AfterTargets="AfterBuild">
<ItemGroup>
<FILES_1 Include="$(OutDir)*.dll" />
<FILES_2 Include="$(OutDir)*.pdb" />
</ItemGroup>
<Copy SourceFiles="@(FILES_1)" DestinationFolder="$(HalTempFolder)" />
<Copy SourceFiles="@(FILES_2)" DestinationFolder="$(HalTempFolder)" />
</Target>
</Project>

View File

@@ -0,0 +1,304 @@
// 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.Runtime.InteropServices;
using System.Text;
using Raytheon.Common;
namespace Raytheon.Instruments
{
/// <summary>
/// Parse and Format Util for the DPF2 flow meter serial interface
/// </summary>
internal static class FlowMeterOmegaDPF20DataParser
{
#region PublicMembers
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct HeaderStruct
{
public byte startOfFrame;//2
public byte frameType;//32,33,35,36,37,38
public byte reserved;//32
public byte orginAddress;//32 + real value
public byte destinationAddress;//32 + real value
public byte registerLocation;//32 + real value
public byte reserved2;//32
public byte dataLength;//num data bytes that follow
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ReadDisplayCmdStruct
{
public HeaderStruct header;
public FooterStruct footer;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ReadDisplayRspStruct
{
public HeaderStruct header;
public byte byte1;
public byte byte2;
public byte byte3;
public byte byte4;
public byte byte5;
public byte byte6;
public byte byte7;
public byte byte8;
public FooterStruct footer;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct FooterStruct
{
public byte crc;
public byte endOfFrame;//3
};
#endregion
#region PublicFunctions
/// <summary>
/// Calculate the CRC per the DPF20 manual
/// </summary>
/// <param name="data">The data to run the crc on</param>
/// <param name="numBytesToProcess">The number of bytes to use for the crc</param>
/// <returns></returns>
public static byte PerformCrc(byte[] data, int numBytesToProcess)
{
byte crc = 0;
for (int i = 0; i < numBytesToProcess; i++)
{
crc = (byte)(crc ^ data[i]);
}
if (crc < 32)
{
crc = (byte)~crc;
}
return crc;
}
/// <summary>
/// Creates the byte array for the read display command
/// </summary>
/// <returns>a byte array that is the command to send to the meter to read the display</returns>
public static byte[] CreateReadFlowCmd(byte flowMeterAddress)
{
// populate the header per the manual
HeaderStruct header = new HeaderStruct();
header.startOfFrame = 2;
header.frameType = 36;
header.reserved = 32;
header.orginAddress = 32;
header.destinationAddress = (byte)(flowMeterAddress + 32);
header.registerLocation = 32;
header.reserved2 = 32;
header.dataLength = 32;
// populate the footer
FooterStruct footer = new FooterStruct();
footer.crc = 0;// set at end of function
footer.endOfFrame = 3;
// create the message
ReadDisplayCmdStruct cmd = new ReadDisplayCmdStruct();
cmd.header = header;
cmd.footer = footer;
// allocate the final buffer
int messageSize = (int)(System.Runtime.InteropServices.Marshal.SizeOf(typeof(ReadDisplayCmdStruct)));
byte[] buff = new byte[messageSize];
//Get a pointer to the Buffer
GCHandle pinnedArray = GCHandle.Alloc(buff, GCHandleType.Pinned);
//Pinned pointer to array
IntPtr pData = pinnedArray.AddrOfPinnedObject();
//Place message into buffer
Marshal.StructureToPtr(cmd, pData, true);
//Release array pointer
pinnedArray.Free();
// calculate and set crc
byte calculatedCrc = PerformCrc(buff, 8);
buff[8] = calculatedCrc;
return buff;
}
/// <summary>
/// Parse out the flow from the read display response
/// </summary>
/// <param name="data"></param>
/// <param name="numBytes"></param>
/// <returns></returns>
public static double ParseReadFlowRsp(byte[] data, int numBytes)
{
const int DISPLAY_REGISTER = 32;
const int DATA_OFFSET = 32;
const int EXPECTED_MSG_ID = 37;
const int EXPECTED_DATA_LEN = 18;
if (numBytes < 18)
{
throw new Exception("Need at least " + EXPECTED_DATA_LEN + " to form the rsp message, received: " + numBytes);
}
// get a pointer to the data
GCHandle messagePinnedArray = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr pMessageData = messagePinnedArray.AddrOfPinnedObject();
// populate the structure
ReadDisplayRspStruct msgStruct = (ReadDisplayRspStruct)Marshal.PtrToStructure(pMessageData, typeof(ReadDisplayRspStruct));
// free the ptr
messagePinnedArray.Free();
if (msgStruct.header.frameType != EXPECTED_MSG_ID)
{
throw new Exception("expected msg id: " + EXPECTED_MSG_ID + ", received: " + msgStruct.header.frameType);
}
// subtract the DATA_OFFSET because that is what the manual says to do:)
int numDataBytes = msgStruct.header.dataLength - DATA_OFFSET;
int headerSize = (int)(System.Runtime.InteropServices.Marshal.SizeOf(typeof(HeaderStruct)));
byte calculatedCrc = PerformCrc(data, numDataBytes + headerSize);
byte receivedCrc = msgStruct.footer.crc;
if (calculatedCrc != receivedCrc)
{
throw new Exception("calculated crc: " + calculatedCrc + ", is not equal to the received crc: " + receivedCrc);
}
// confirm the from register
int fromRegister = msgStruct.header.registerLocation;
if (fromRegister != DISPLAY_REGISTER)
{
throw new Exception("from register: " + fromRegister + ", is not the expected register: " + DISPLAY_REGISTER);
}
// get the data
byte[] dataPayload = new byte[numDataBytes];
Array.Copy(data, headerSize, dataPayload, 0, numDataBytes);
// convert it to a string
string rspStr = Encoding.ASCII.GetString(dataPayload);
//Convert string value to double and return
return double.Parse(rspStr);
}
/// <summary>
/// parse out flow from the master flow message (ID 35)
/// </summary>
/// <returns>the flow rate.</returns>
public static double ParseMasterFlowMsg(byte[] data, int numBytes)
{
const int DISPLAY_REGISTER = 32;
const int DATA_OFFSET = 32;
const int EXPECTED_MSG_ID = 35;
const int EXPECTED_DATA_LEN = 18;
// start of message data pattern
byte[] startOfMesage = new byte[] { 2, 35 };
// data search index
int searchIndex = 0;
// need at least 18 bytes
if (numBytes < EXPECTED_DATA_LEN)
{
throw new Exception("Need at least " + EXPECTED_DATA_LEN + " to form the rsp message, received: " + numBytes);
}
// if there are more than two messages, just need the end of the buffer
// worst case scenario for 1 complete message would be 35 bytes (17 from an incomplete message and then 18 for the complete one)
else if (numBytes >= (EXPECTED_DATA_LEN * 2) - 1)
{
searchIndex = numBytes - ((EXPECTED_DATA_LEN * 2) - 1);
}
int finalMsgStartIndex = Util.ByteArraySearch(data, searchIndex, startOfMesage);
if (finalMsgStartIndex == -1)
{
throw new Exception("Could not find start of message");
}
else if((numBytes - finalMsgStartIndex) < EXPECTED_DATA_LEN)
{
throw new Exception("Found start of message, but not enough bytes for a complete message");
}
byte[] messagePayload = new byte[EXPECTED_DATA_LEN];
Array.Copy(data, finalMsgStartIndex, messagePayload, 0, EXPECTED_DATA_LEN);
// get a pointer to the data
GCHandle messagePinnedArray = GCHandle.Alloc(messagePayload, GCHandleType.Pinned);
IntPtr pMessageData = messagePinnedArray.AddrOfPinnedObject();
// populate the structure
HeaderStruct headerStruct = (HeaderStruct)Marshal.PtrToStructure(pMessageData, typeof(HeaderStruct));
// free the ptr
messagePinnedArray.Free();
if (headerStruct.frameType != EXPECTED_MSG_ID)
{
throw new Exception("expected msg id: " + EXPECTED_MSG_ID + ", received: " + headerStruct.frameType);
}
// subtract the DATA_OFFSET because that is what the manual says to do:)
int numDataBytes = headerStruct.dataLength - DATA_OFFSET;
int headerSize = (int)(System.Runtime.InteropServices.Marshal.SizeOf(typeof(HeaderStruct)));
// confirm the crc
byte calculatedCrc = PerformCrc(messagePayload, numDataBytes + headerSize);
byte receivedCrc = messagePayload[numDataBytes + headerSize];
if (calculatedCrc != receivedCrc)
{
throw new Exception("calculated crc: " + calculatedCrc + ", is not equal to the received crc: " + receivedCrc);
}
// confirm the from register
int fromRegister = headerStruct.registerLocation;
if (fromRegister != DISPLAY_REGISTER)
{
throw new Exception("from register: " + fromRegister + ", is not the expected register: " + DISPLAY_REGISTER);
}
// get the data
byte[] dataPayload = new byte[numDataBytes];
Array.Copy(messagePayload, headerSize, dataPayload, 0, numDataBytes);
// convert to a string
string rspStr = Encoding.ASCII.GetString(dataPayload);
//Convert string value to double and return
return double.Parse(rspStr);
}
#endregion
}
}

View File

@@ -0,0 +1,139 @@
// **********************************************************************************************************
// FlowMeterOmegaDPF20Factory.cs
// 2/20/2023
// NGI - Next Generation Interceptor
//
// Contract No. HQ0856-21-C-0003/1022000209
//
// THIS DOCUMENT DOES NOT CONTAIN TECHNOLOGY OR TECHNICAL DATA CONTROLLED UNDER EITHER THE U.S.
// INTERNATIONAL TRAFFIC IN ARMS REGULATIONS OR THE U.S. EXPORT ADMINISTRATION REGULATIONS.
//
// 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.
//
// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
//
// DESTRUCTION NOTICE: FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN DOD 5220.22-M,
// NATIONAL INDUSTRIAL SECURITY PROGRAM OPERATING MANUAL, FEBRUARY 2006,
// INCORPORATING CHANGE 1, MARCH 28, 2013, CHAPTER 5, SECTION 7, OR DODM 5200.01-VOLUME 3,
// DOD INFORMATION SECURITY PROGRAM: PROTECTION OF CLASSIFIED INFORMATION, ENCLOSURE 3,
// SECTION 17. FOR CONTROLLED UNCLASSIFIED INFORMATION FOLLOW THE PROCEDURES IN DODM 5200.01-VOLUME 4,
// INFORMATION SECURITY PROGRAM: CONTROLLED UNCLASSIFIED INFORMATION.
//
// CONTROLLED BY: MISSILE DEFENSE AGENCY
// CONTROLLED BY: GROUND-BASED MIDCOURSE DEFENSE PROGRAM OFFICE
// CUI CATEGORY: CTI
// DISTRIBUTION/DISSEMINATION CONTROL: F
// POC: Alex Kravchenko (1118268)
// **********************************************************************************************************
using NLog;
using Raytheon.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Reflection;
namespace Raytheon.Instruments
{
[ExportInstrumentFactory(ModelNumber = "FlowMeterOmegaDPF20Factory")]
public class FlowMeterOmegaDPF20Factory : IInstrumentFactory
{
/// <summary>
/// The supported interfaces
/// </summary>
private readonly List<Type> _supportedInterfaces = new List<Type>();
private ILogger _logger;
private readonly IConfigurationManager _configurationManager;
private const string DefaultConfigPath = @"C:\ProgramData\Raytheon\InstrumentManagerService";
private static string DefaultPath;
public FlowMeterOmegaDPF20Factory(string defaultConfigPath = DefaultConfigPath)
: this(null, defaultConfigPath)
{
}
/// <summary>
/// COECommDeviceInstrumentFactory injection constructor
/// </summary>
/// <param name="configManager"></param>
/// <param name="simEngine"></param>
/// <param name="logger"></param>
[ImportingConstructor]
public FlowMeterOmegaDPF20Factory([Import(AllowDefault = false)] IConfigurationManager configManager,
[Import(AllowDefault = true)] string defaultConfigPath = null)
{
DefaultPath = defaultConfigPath;
if (LogManager.Configuration == null)
{
var assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(assemblyFolder + "\\nlog.config");
}
_configurationManager = configManager ?? GetConfigurationManager();
_supportedInterfaces.Add(typeof(IFlowMeter));
}
/// <summary>
/// Gets the instrument
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public IInstrument GetInstrument(string name)
{
try
{
_logger = LogManager.GetLogger(name);
return new FlowMeterOmegaDPF20(name, _configurationManager, _logger);
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// Gets the instrument
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public object GetInstrument(string name, bool simulateHw)
{
try
{
_logger = LogManager.GetLogger(name);
if (simulateHw)
return new FlowMeterSim(name, _configurationManager, _logger);
else
return new FlowMeterOmegaDPF20(name, _configurationManager, _logger);
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// Gets supported interfaces
/// </summary>
/// <returns></returns>
public ICollection<Type> GetSupportedInterfaces()
{
return _supportedInterfaces.ToArray();
}
/// <summary>
/// returns configuration based on the predefined path or default path c:/ProgramData/Raytheon/InstrumentManagerService
/// </summary>
/// <returns></returns>
private static IConfigurationManager GetConfigurationManager()
{
return string.IsNullOrEmpty(DefaultPath) ? new RaytheonConfigurationManager() : new RaytheonConfigurationManager(DefaultPath);
}
}
}

View File

@@ -0,0 +1,378 @@
// UNCLASSIFIED
/*-------------------------------------------------------------------------
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
COMPANY.
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
GOVERNMENT.
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
-------------------------------------------------------------------------*/
using System;
using System.IO.Ports;
using System.Net.Sockets;
using System.Text;
using NLog;
using Raytheon.Common;
namespace Raytheon.Instruments
{
/// <summary>
/// Flow Meter class used to interact with M1676 flow meter
/// </summary>
public class FlowMeterOmegaM1676 : IFlowMeter
{
#region PrivateMembers
//Commands
private const string _CARRIAGE_RTN = "\r";
private const string _FLOW = "@U?V";
private const string _GET_VERSION = "@U?SC";
private const string _SET_CONFIG = "@U?SP2B";
private const string _SET_DEC_POINT = "@U?SP2A0";
private const string _SET_SCALE_1ST_BYTE = "@U?SP2F";
private const string _SET_SCALE_2ND_BYTE = "@U?SP30";
private const string _SET_SCALE_3RD_BYTE = "@U?SP31";
//Prevent Collisions
private static object _sync = new object();
//Ethernet Communication
private readonly string _ipAddr;
private readonly int _port;
private const int _READ_BUFFER_SIZE = 1024;
private const int _READ_TIMEOUT = 5000;
private byte[] _readBuffer;
private NetworkStream _tcpStream;
/// <summary>
/// NLog logger
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// Raytheon configuration
/// </summary>
private readonly IConfigurationManager _configurationManager;
private readonly IConfiguration _configuration;
public string DetailedStatus => throw new NotImplementedException();
public bool DisplayEnabled { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public bool FrontPanelEnabled { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public InstrumentMetadata Info => throw new NotImplementedException();
public string Name { get; set;}
public SelfTestResult SelfTestResult => throw new NotImplementedException();
public State Status => throw new NotImplementedException();
#endregion
#region PrivateFunctions
/// <summary>
/// Destructor
/// </summary>
~FlowMeterOmegaM1676()
{
Dispose(false);
}
/// <summary>
/// Open socket to the flow meter
/// </summary>
private void ConnectEthernet()
{
//Create and open a socket to flow meter
TcpClient flowSocket = new TcpClient(_ipAddr, _port);
_tcpStream = flowSocket.GetStream();
_tcpStream.ReadTimeout = _READ_TIMEOUT;
}
/// <summary>
/// Turn off the alarm feature of the flow meter
/// </summary>
private void ConfigureAlarm()
{
lock (_sync)
{
//Turn off the Alarm in the response messages -> 000001
SendMessageNoResponse(_SET_CONFIG + "01");
}
}
/// <summary>
/// Used to set the decimal place of the measurement and display:
/// 0 --> Auto Range
/// 1 --> FFFFFF.
/// 2 --> FFFFF.F
/// 3 --> FFFF.FF
/// 4 --> FFF.FFF
/// 5 --> FF.FFFF
/// 6 --> F.FFFFF
/// </summary>
/// <param name="option">Set the decimal place of the measurement.</param>
private void ConfigureDecimalOutput(int option)
{
lock (_sync)
{
if (option < 0)
{
option = 0;
}
else if (option > 6)
{
option = 0;
}
SendMessageNoResponse(_SET_DEC_POINT + option.ToString());
}
}
/// <summary>
/// Configure the scale factor to .002 (per CIL manual)
/// </summary>
private void ConfigureScaleFactor()
{
lock (_sync)
{
//Per manual .002 --> 0x400002
//Send a byte at a time (0x40, 0x00, 0x02)
SendMessageNoResponse(_SET_SCALE_1ST_BYTE + "02");
SendMessageNoResponse(_SET_SCALE_2ND_BYTE + "00");
SendMessageNoResponse(_SET_SCALE_3RD_BYTE + "40");
}
}
/// <summary>
/// Dispose of this object's resources
/// </summary>
/// <param name="disposing">Currently disposing</param>
protected virtual void Dispose(bool disposing)
{
try
{
if (disposing)
{
//Close Connection (if available)
_tcpStream?.Close();
}
}
catch (Exception)
{
try
{
//ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
}
catch (Exception)
{
//Do not rethrow. Exception from error logger that has already been garbage collected
}
}
}
/// <summary>
/// Send a command to the flow meter and request a response
/// </summary>
/// <param name="cmd">Command to send.</param>
/// <returns>Response from the flow meter.</returns>
private string SendMessageGetResponse(string cmd)
{
lock (_sync)
{
//Send the data
SendMessageNoResponse(cmd);
//clear the buffer
Array.Clear(_readBuffer, 0, _readBuffer.Length);
//read from the response buffer
int numBytesRead = _tcpStream.Read(_readBuffer, 0, _readBuffer.Length);
//convert response to a string
string rspStr = Encoding.ASCII.GetString(_readBuffer);
//Check Response
if (rspStr.Contains(_CARRIAGE_RTN))
{
//Parse string ("/r")
char[] delimit = { '\r' };
string[] parsed = rspStr.Split(delimit, StringSplitOptions.RemoveEmptyEntries);
//Return parsed message
return parsed[0];
}
else
{
throw new Exception("Command message not successful");
}
}
}
/// <summary>
/// Send a command to the flow meter
/// </summary>
/// <param name="cmd">The command to send</param>
private void SendMessageNoResponse(string cmd)
{
lock (_sync)
{
//Format the command before sending
string commandString = cmd + _CARRIAGE_RTN;
//convert to byte array for sending
byte[] commandBuffer = Encoding.ASCII.GetBytes(commandString);
//send the data
_tcpStream.Write(commandBuffer, 0, commandBuffer.Length);
}
}
#endregion
#region PublicFunctions
/// <summary>
/// FlowMeterOmegaM1676 factory constructor
/// </summary>
/// <param name="deviceName"></param>
/// <param name="configurationManager"></param>
public FlowMeterOmegaM1676(string deviceName, IConfigurationManager configurationManager, ILogger logger)
{
Name = deviceName;
_logger = logger;
_configurationManager = configurationManager;
_configuration = _configurationManager.GetConfiguration(Name);
_ipAddr = _configuration.GetConfigurationValue("FlowMeterOmegaM1676", "IpAddr", "");
_port = _configuration.GetConfigurationValue("FlowMeterOmegaM1676", "Port", 0);
_readBuffer = new byte[_READ_BUFFER_SIZE];
//Connect to and configure device
ConnectEthernet();
//Configuration
ConfigureAlarm();
ConfigureDecimalOutput(4);
ConfigureScaleFactor();
}
/// <summary>
/// Constructor for the M1676 flow meter. Forms a socket connection upon construction
/// </summary>
/// <param name="name">The name. Anything the host wants it to be</param>
/// <param name="ipAddress">IP Address of the flow meter</param>
/// <param name="port">Port of the flow meter</param>
public FlowMeterOmegaM1676(string name, string ipAddress, int port)
{
Name = name;
_logger = LogManager.GetCurrentClassLogger();
_ipAddr = ipAddress;
_port = port;
//Initialize read buffer
_readBuffer = new byte[_READ_BUFFER_SIZE];
//Connect to and configure device
ConnectEthernet();
//Configuration
ConfigureAlarm();
ConfigureDecimalOutput(4);
ConfigureScaleFactor();
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <param name="comPortName"></param>
/// <param name="delayBeforeReadMs"></param>
/// <param name="baudRate"></param>
/// <param name="parity"></param>
/// <param name="dataBits"></param>
/// <param name="stopBits"></param>
public FlowMeterOmegaM1676(string name, string comPortName, uint delayBeforeReadMs, int baudRate = 115200, Parity parity = Parity.None, int dataBits = 8, StopBits stopBits = StopBits.One)
{
throw new NotImplementedException();
}
// This code added to correctly implement the disposable pattern.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")]
public void Dispose()
{
try
{
lock (_sync)
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
catch (Exception)
{
try
{
//ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
}
catch (Exception)
{
//Do not rethrow. Exception from error logger that has already been garbage collected
}
}
}
/// <summary>
/// Query the flow rate from the flow meter
/// </summary>
/// <returns>the flow rate.</returns>
public double ReadFlow()
{
lock (_sync)
{
string rsp = SendMessageGetResponse(_FLOW);
//Convert string value to double and return
return double.Parse(rsp);
}
}
public bool ClearErrors()
{
throw new NotImplementedException();
}
public void Initialize()
{
throw new NotImplementedException();
}
public SelfTestResult PerformSelfTest()
{
throw new NotImplementedException();
}
public void Reset()
{
throw new NotImplementedException();
}
public void Shutdown()
{
throw new NotImplementedException();
}
#endregion
}
}

View File

@@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(SolutionDir)Solution.props" />
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<AssemblyName>Raytheon.Instruments.FlowMeterOmegaM1676</AssemblyName>
<Product>FLow Meter Omega M1676 implementation</Product>
<Description>Flow Meter Omega M1676 implementation</Description>
<OutputType>Library</OutputType>
<!-- Static versioning (Suitable for Development) -->
<!-- Disable the line below for dynamic versioning -->
<Version>1.0.0</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NLog" Version="5.0.0" />
<PackageReference Include="Raytheon.Common" Version="1.0.0" />
<PackageReference Include="Raytheon.Instruments.FlowMeter.Contracts" Version="1.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FlowMeterSim\FlowMeterSim.csproj" />
</ItemGroup>
<!-- Copy all *.dlls and *.pdb in the output folder to a temp folder -->
<Target Name="CopyFiles" AfterTargets="AfterBuild">
<ItemGroup>
<FILES_1 Include="$(OutDir)*.dll" />
<FILES_2 Include="$(OutDir)*.pdb" />
</ItemGroup>
<Copy SourceFiles="@(FILES_1)" DestinationFolder="$(HalTempFolder)" />
<Copy SourceFiles="@(FILES_2)" DestinationFolder="$(HalTempFolder)" />
</Target>
</Project>

View File

@@ -0,0 +1,139 @@
// **********************************************************************************************************
// FlowMeterOmegaM1676Factory.cs
// 2/20/2023
// NGI - Next Generation Interceptor
//
// Contract No. HQ0856-21-C-0003/1022000209
//
// THIS DOCUMENT DOES NOT CONTAIN TECHNOLOGY OR TECHNICAL DATA CONTROLLED UNDER EITHER THE U.S.
// INTERNATIONAL TRAFFIC IN ARMS REGULATIONS OR THE U.S. EXPORT ADMINISTRATION REGULATIONS.
//
// 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.
//
// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
//
// DESTRUCTION NOTICE: FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN DOD 5220.22-M,
// NATIONAL INDUSTRIAL SECURITY PROGRAM OPERATING MANUAL, FEBRUARY 2006,
// INCORPORATING CHANGE 1, MARCH 28, 2013, CHAPTER 5, SECTION 7, OR DODM 5200.01-VOLUME 3,
// DOD INFORMATION SECURITY PROGRAM: PROTECTION OF CLASSIFIED INFORMATION, ENCLOSURE 3,
// SECTION 17. FOR CONTROLLED UNCLASSIFIED INFORMATION FOLLOW THE PROCEDURES IN DODM 5200.01-VOLUME 4,
// INFORMATION SECURITY PROGRAM: CONTROLLED UNCLASSIFIED INFORMATION.
//
// CONTROLLED BY: MISSILE DEFENSE AGENCY
// CONTROLLED BY: GROUND-BASED MIDCOURSE DEFENSE PROGRAM OFFICE
// CUI CATEGORY: CTI
// DISTRIBUTION/DISSEMINATION CONTROL: F
// POC: Alex Kravchenko (1118268)
// **********************************************************************************************************
using NLog;
using Raytheon.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Reflection;
namespace Raytheon.Instruments
{
[ExportInstrumentFactory(ModelNumber = "FlowMeterOmegaM1676Factory")]
public class FlowMeterOmegaM1676Factory : IInstrumentFactory
{
/// <summary>
/// The supported interfaces
/// </summary>
private readonly List<Type> _supportedInterfaces = new List<Type>();
private ILogger _logger;
private readonly IConfigurationManager _configurationManager;
private const string DefaultConfigPath = @"C:\ProgramData\Raytheon\InstrumentManagerService";
private static string DefaultPath;
public FlowMeterOmegaM1676Factory(string defaultConfigPath = DefaultConfigPath)
: this(null, defaultConfigPath)
{
}
/// <summary>
/// COECommDeviceInstrumentFactory injection constructor
/// </summary>
/// <param name="configManager"></param>
/// <param name="simEngine"></param>
/// <param name="logger"></param>
[ImportingConstructor]
public FlowMeterOmegaM1676Factory([Import(AllowDefault = false)] IConfigurationManager configManager,
[Import(AllowDefault = true)] string defaultConfigPath = null)
{
DefaultPath = defaultConfigPath;
if (LogManager.Configuration == null)
{
var assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(assemblyFolder + "\\nlog.config");
}
_configurationManager = configManager ?? GetConfigurationManager();
_supportedInterfaces.Add(typeof(IFlowMeter));
}
/// <summary>
/// Gets the instrument
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public IInstrument GetInstrument(string name)
{
try
{
_logger = LogManager.GetLogger(name);
return new FlowMeterOmegaM1676(name, _configurationManager, _logger);
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// Gets the instrument
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public object GetInstrument(string name, bool simulateHw)
{
try
{
_logger = LogManager.GetLogger(name);
if (simulateHw)
return new FlowMeterSim(name, _configurationManager, _logger);
else
return new FlowMeterOmegaM1676(name, _configurationManager, _logger);
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// Gets supported interfaces
/// </summary>
/// <returns></returns>
public ICollection<Type> GetSupportedInterfaces()
{
return _supportedInterfaces.ToArray();
}
/// <summary>
/// returns configuration based on the predefined path or default path c:/ProgramData/Raytheon/InstrumentManagerService
/// </summary>
/// <returns></returns>
private static IConfigurationManager GetConfigurationManager()
{
return string.IsNullOrEmpty(DefaultPath) ? new RaytheonConfigurationManager() : new RaytheonConfigurationManager(DefaultPath);
}
}
}

View File

@@ -0,0 +1,198 @@
// 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.Threading;
using NLog;
using Raytheon.Common;
namespace Raytheon.Instruments
{
/// <summary>
/// Flow Meter Sim Class
/// </summary>
public class FlowMeterSim : IFlowMeter
{
#region PrivateMembers
private static object _sync = new object();
public string DetailedStatus => throw new NotImplementedException();
public bool DisplayEnabled { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public bool FrontPanelEnabled { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public InstrumentMetadata Info => throw new NotImplementedException();
public string Name { get; set; }
public SelfTestResult SelfTestResult => throw new NotImplementedException();
public State Status => throw new NotImplementedException();
/// <summary>
/// Destructor
/// </summary>
~FlowMeterSim()
{
Dispose(false);
}
/// <summary>
/// NLog logger
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// Raytheon configuration
/// </summary>
private readonly IConfigurationManager _configurationManager;
private readonly IConfiguration _configuration;
#endregion
#region PrivateFunctions
/// <summary>
/// Dispose of this object's resources
/// </summary>
/// <param name="disposing">Currently disposing</param>
protected virtual void Dispose(bool disposing)
{
try
{
if (disposing)
{
}
}
catch (Exception)
{
try
{
//ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
}
catch (Exception)
{
//Do not rethrow. Exception from error logger that has already been garbage collected
}
}
}
#endregion
#region PublicFunctions
/// <summary>
/// FlowMeterOmegaDPF20 factory constructor
/// </summary>
/// <param name="deviceName"></param>
/// <param name="configurationManager"></param>
public FlowMeterSim(string deviceName, IConfigurationManager configurationManager, ILogger logger)
{
Name = deviceName;
_logger = logger;
_configurationManager = configurationManager;
_configuration = _configurationManager.GetConfiguration(Name);
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
public FlowMeterSim(string name)
{
Name = name;
_logger = LogManager.GetCurrentClassLogger();
}
// This code added to correctly implement the disposable pattern.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")]
public void Dispose()
{
try
{
lock (_sync)
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
catch (Exception)
{
try
{
//ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
}
catch (Exception)
{
//Do not rethrow. Exception from error logger that has already been garbage collected
}
}
}
/// <summary>
/// Query the flow rate from the flow meter
/// </summary>
/// <returns>the flow rate.</returns>
public double ReadFlow()
{
lock (_sync)
{
double max = 0.15;
double min = .35;
Random rnd = new Random();
double seed = rnd.NextDouble();
double dataToReturn = (seed * (max - min)) + min;
Thread.Sleep(100);
return dataToReturn;
}
}
public bool ClearErrors()
{
throw new NotImplementedException();
}
public void Initialize()
{
throw new NotImplementedException();
}
public SelfTestResult PerformSelfTest()
{
throw new NotImplementedException();
}
public void Reset()
{
throw new NotImplementedException();
}
public void Shutdown()
{
throw new NotImplementedException();
}
#endregion
}
}

View File

@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(SolutionDir)Solution.props" />
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<AssemblyName>Raytheon.Instruments.FlowMeterSim</AssemblyName>
<Product>Flow Meter SIM implementation</Product>
<Description>Flow Meter SIM implementation</Description>
<OutputType>Library</OutputType>
<!-- Static versioning (Suitable for Development) -->
<!-- Disable the line below for dynamic versioning -->
<Version>1.0.0</Version>
</PropertyGroup>
<PropertyGroup>
<NoWarn>NU1603</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NLog" Version="5.0.0" />
<PackageReference Include="Raytheon.Common" Version="1.0.0" />
<PackageReference Include="Raytheon.Instruments.FlowMeter.Contracts" Version="1.0.3" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,136 @@
// **********************************************************************************************************
// FlowMeterSimFactory.cs
// 2/20/2023
// NGI - Next Generation Interceptor
//
// Contract No. HQ0856-21-C-0003/1022000209
//
// THIS DOCUMENT DOES NOT CONTAIN TECHNOLOGY OR TECHNICAL DATA CONTROLLED UNDER EITHER THE U.S.
// INTERNATIONAL TRAFFIC IN ARMS REGULATIONS OR THE U.S. EXPORT ADMINISTRATION REGULATIONS.
//
// 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.
//
// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
//
// DESTRUCTION NOTICE: FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN DOD 5220.22-M,
// NATIONAL INDUSTRIAL SECURITY PROGRAM OPERATING MANUAL, FEBRUARY 2006,
// INCORPORATING CHANGE 1, MARCH 28, 2013, CHAPTER 5, SECTION 7, OR DODM 5200.01-VOLUME 3,
// DOD INFORMATION SECURITY PROGRAM: PROTECTION OF CLASSIFIED INFORMATION, ENCLOSURE 3,
// SECTION 17. FOR CONTROLLED UNCLASSIFIED INFORMATION FOLLOW THE PROCEDURES IN DODM 5200.01-VOLUME 4,
// INFORMATION SECURITY PROGRAM: CONTROLLED UNCLASSIFIED INFORMATION.
//
// CONTROLLED BY: MISSILE DEFENSE AGENCY
// CONTROLLED BY: GROUND-BASED MIDCOURSE DEFENSE PROGRAM OFFICE
// CUI CATEGORY: CTI
// DISTRIBUTION/DISSEMINATION CONTROL: F
// POC: Alex Kravchenko (1118268)
// **********************************************************************************************************
using NLog;
using Raytheon.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Reflection;
namespace Raytheon.Instruments
{
[ExportInstrumentFactory(ModelNumber = "FlowMeterSimFactory")]
public class FlowMeterSimFactory : IInstrumentFactory
{
/// <summary>
/// The supported interfaces
/// </summary>
private readonly List<Type> _supportedInterfaces = new List<Type>();
private ILogger _logger;
private readonly IConfigurationManager _configurationManager;
private const string DefaultConfigPath = @"C:\ProgramData\Raytheon\InstrumentManagerService";
private static string DefaultPath;
public FlowMeterSimFactory(string defaultConfigPath = DefaultConfigPath)
: this(null, defaultConfigPath)
{
}
/// <summary>
/// COECommDeviceInstrumentFactory injection constructor
/// </summary>
/// <param name="configManager"></param>
/// <param name="simEngine"></param>
/// <param name="logger"></param>
[ImportingConstructor]
public FlowMeterSimFactory([Import(AllowDefault = false)] IConfigurationManager configManager,
[Import(AllowDefault = true)] string defaultConfigPath = null)
{
DefaultPath = defaultConfigPath;
if (LogManager.Configuration == null)
{
var assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(assemblyFolder + "\\nlog.config");
}
_configurationManager = configManager ?? GetConfigurationManager();
_supportedInterfaces.Add(typeof(IFlowMeter));
}
/// <summary>
/// Gets the instrument
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public IInstrument GetInstrument(string name)
{
try
{
_logger = LogManager.GetLogger(name);
return new FlowMeterSim(name, _configurationManager, _logger);
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// Gets the instrument
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public object GetInstrument(string name, bool simulateHw)
{
try
{
_logger = LogManager.GetLogger(name);
return new FlowMeterSim(name, _configurationManager, _logger);
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// Gets supported interfaces
/// </summary>
/// <returns></returns>
public ICollection<Type> GetSupportedInterfaces()
{
return _supportedInterfaces.ToArray();
}
/// <summary>
/// returns configuration based on the predefined path or default path c:/ProgramData/Raytheon/InstrumentManagerService
/// </summary>
/// <returns></returns>
private static IConfigurationManager GetConfigurationManager()
{
return string.IsNullOrEmpty(DefaultPath) ? new RaytheonConfigurationManager() : new RaytheonConfigurationManager(DefaultPath);
}
}
}