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,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);
}
}
}