Big changes
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
// **********************************************************************************************************
|
||||
// BITCommand.cs
|
||||
// 8/31/2023
|
||||
// NGI - Next Generation Interceptor
|
||||
//
|
||||
// Contract No. HQ0856-21-C-0003/1022000209
|
||||
//
|
||||
// DISTRIBUTION STATEMENT F: FURTHER DISSEMINATION ONLY AS DIRECTED BY
|
||||
// MISSILE DEFENSE AGENCY, MDA/GMY NEXT GENERATION INTERCEPTOR PROJECT
|
||||
// OFFICE (DATE OF DETERMINATION 14 JUNE 2021) OR HIGHER DOD AUTHORITY.
|
||||
// OTHER REQUESTS FOR THIS DOCUMENT SHALL BE REFERRED TO: MISSILE DEFENSE
|
||||
// AGENCY, CONTRACTS DIRECTORATE, ATTN: GMY‐K, BLDG. 5222 MARTIN ROAD,
|
||||
// REDSTONE ARSENAL, AL 35898.
|
||||
//
|
||||
// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA WHOSE EXPORT IS
|
||||
// RESTRICTED BY THE ARMS EXPORT CONTROL ACT (TITLE 22, U.S.C.,
|
||||
// SECTION 2751, ET SEQ.) OR THE EXPORT ADMINISTRATION ACT OF 1979
|
||||
// (TITLE 50 U.S.C. APP. 2401 ET SEQ.), AS AMENDED. VIOLATIONS OF
|
||||
// THESE EXPORT LAWS ARE SUBJECT TO SEVERE CRIMINAL PENALTIES.
|
||||
// DISSEMINATE IN ACCORDANCE WITH PROVISIONS OF DOD DIRECTIVE 5230.25.
|
||||
//
|
||||
// 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)
|
||||
// **********************************************************************************************************
|
||||
// Ignore Spelling: Deserialized
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace BitGenSoftMeasurementManagerLib
|
||||
{
|
||||
|
||||
[XmlType(TypeName = "ResponseMessageType")]
|
||||
public enum ResponseMessageType
|
||||
{
|
||||
U, // Unknown or Undefined
|
||||
R, // Required
|
||||
E, // Error
|
||||
P // Parametric
|
||||
}
|
||||
|
||||
[XmlType(TypeName = "ParamType")]
|
||||
public enum ParameterType
|
||||
{
|
||||
U, // Unknown or Undefined will default to string
|
||||
N, // Numeric
|
||||
S, // String
|
||||
A, // Array
|
||||
P // p-data array
|
||||
}
|
||||
|
||||
|
||||
[XmlType(TypeName = "BITResponseMsg")]
|
||||
public class BITResponseMsg
|
||||
{
|
||||
[XmlAttribute("type")]
|
||||
public ResponseMessageType ResponseType { get; set; }
|
||||
|
||||
[XmlText]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
[XmlType("Value")]
|
||||
public class BITParameter
|
||||
{
|
||||
[XmlAttribute(AttributeName = "name")]
|
||||
public string Key { get; set; }
|
||||
|
||||
[XmlAttribute(AttributeName = "type")]
|
||||
public ParameterType ParameterType { get; set; }
|
||||
|
||||
[XmlAttribute(AttributeName = "delim")]
|
||||
public string Delim { get; set; }
|
||||
|
||||
[XmlText]
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class BITCommand
|
||||
{
|
||||
[XmlElement(ElementName = "Command")]
|
||||
public string Command { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "CommandTimeout")]
|
||||
public uint CommandTimeout { get; set; }
|
||||
|
||||
[XmlArray("CommandParameters")]
|
||||
[XmlArrayItem("Value", Type = typeof(BITParameter))]
|
||||
public List<BITParameter> CommandParameters { get; set; } = new List<BITParameter>();
|
||||
|
||||
[XmlArray("CommandResponses")]
|
||||
[XmlArrayItem("BITResponseMsg", Type = typeof(BITResponseMsg))]
|
||||
public List<BITResponseMsg> CommandResponses { get; set; } = new List<BITResponseMsg>();
|
||||
|
||||
[XmlElement(ElementName = "ParametricResponse")]
|
||||
public string ParametricResponse { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "ParametricTimeout")]
|
||||
public uint ParametricTimeout { get; set; }
|
||||
|
||||
[XmlArray("ResponseParameters")]
|
||||
[XmlArrayItem("Value", Type = typeof(BITParameter))]
|
||||
public List<BITParameter> ResponseParameters { get; set; } = new List<BITParameter>();
|
||||
|
||||
/// <summary>
|
||||
/// converts one hex parameter string into parameter array
|
||||
/// </summary>
|
||||
public void UnfoldHexParameters()
|
||||
{
|
||||
if (!CommandParameters.Any(p => p.ParameterType == ParameterType.P))
|
||||
return;
|
||||
|
||||
var paramList = CommandParameters.Where(p => p.ParameterType == ParameterType.P).ToList();
|
||||
List<BITParameter> removeList = new List<BITParameter>();
|
||||
foreach (BITParameter param in paramList)
|
||||
{
|
||||
AddPDataArrayValues(param.Key, param.Value, param.Delim);
|
||||
removeList.Add(param);
|
||||
}
|
||||
CommandParameters.RemoveAll(c => removeList.Contains(c));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// takes a hex string and breaks it up into individual characters
|
||||
/// then inserts them as parameters
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="delim"></param>
|
||||
private void AddPDataArrayValues(string key, string value, string delim)
|
||||
{
|
||||
var parms = BreakByPages(value, delim);
|
||||
|
||||
int index = 0;
|
||||
foreach (var item in parms)
|
||||
{
|
||||
string itemKey = $"{key}[{index++}]";
|
||||
string itemValue = item;
|
||||
CommandParameters.Add(new BITParameter { Key = itemKey, Value = itemValue } );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// takes a large hex string and breaks it in multiple pages based on the known header
|
||||
/// adjusts the size of the page to be divisible by 4 bytes
|
||||
/// and also adds a 12 byte footer of zero values to the end of the page
|
||||
/// </summary>
|
||||
/// <param name="hexStr"></param>
|
||||
/// <param name="header"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<string> BreakByPages(string hexStr, string header)
|
||||
{
|
||||
const int footerSize = 12;
|
||||
string[] pages = hexStr.Split(new[] { header }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (string page in pages)
|
||||
{
|
||||
string completePage = header + page;
|
||||
int pageSize = (completePage.Length + 7) & ~7;
|
||||
string paddedPage = completePage.PadRight(pageSize + (footerSize * 2), '0');
|
||||
IEnumerable<string> hexChars = BreakIntoHexCharacters(paddedPage);
|
||||
foreach (string hexChar in hexChars)
|
||||
{
|
||||
yield return hexChar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// takes a large string of hex characters and breaks it into individual hex values
|
||||
/// then yields these values to the calling code
|
||||
/// </summary>
|
||||
/// <param name="hexString"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<string> BreakIntoHexCharacters(string hexString)
|
||||
{
|
||||
int characterSize = 2;
|
||||
int length = hexString.Length;
|
||||
for (int i = 0; i < length; i += characterSize)
|
||||
{
|
||||
if (i + characterSize > length)
|
||||
{
|
||||
hexString = hexString.PadRight(i + characterSize, '0');
|
||||
}
|
||||
yield return "0x" + hexString.Substring(i, characterSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,936 @@
|
||||
// **********************************************************************************************************
|
||||
// BitGenSoftMeasurementManager.cs
|
||||
// 7/28/2022
|
||||
// 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 Raytheon.Instruments;
|
||||
using Raytheon.Instruments.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using BitGenSoftMeasurementManagerLib;
|
||||
|
||||
namespace MeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Bit Gen Soft Measurement Manager class
|
||||
/// </summary>
|
||||
public class BitGenSoftMeasurementManager : IDisposable
|
||||
{
|
||||
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private readonly Dictionary<string, IBit> _bitNodes = new Dictionary<string, IBit>();
|
||||
|
||||
private readonly IInstrumentManager _instrumentManager;
|
||||
private IConfigurationManager _configurationManager;
|
||||
private int _checkForMessageIntervalMs = 10;
|
||||
/// <summary>
|
||||
/// constructor that will create a list of BIT instruments
|
||||
/// </summary>
|
||||
/// <param name="instrumentManager"></param>
|
||||
/// <param name="instrumentNames"></param>
|
||||
public BitGenSoftMeasurementManager(IInstrumentManager instrumentManager, List<string> instrumentNames)
|
||||
: this(instrumentManager)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (string instrumentName in instrumentNames)
|
||||
{
|
||||
var bitNode = (IBit)_instrumentManager.GetGenericInstrument(instrumentName);
|
||||
if (bitNode == null)
|
||||
{
|
||||
_logger.Error("Error creating TCP BIT device, check your settings");
|
||||
}
|
||||
else
|
||||
{
|
||||
_bitNodes.Add(instrumentName, bitNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"Unable to create BIT instrument\n{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// in case instrument manager was passed from upper level
|
||||
/// </summary>
|
||||
/// <param name="instrumentManager"></param>
|
||||
private BitGenSoftMeasurementManager(IInstrumentManager instrumentManager)
|
||||
{
|
||||
_instrumentManager = instrumentManager;
|
||||
InitializeConfigurationManager();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// initializes configuration manager,
|
||||
/// will use configuration path from General Instrument Manager if available
|
||||
/// otherwise will try to use the instruments path
|
||||
/// </summary>
|
||||
private void InitializeConfigurationManager()
|
||||
{
|
||||
string defaultPath;
|
||||
if (_instrumentManager is GeneralInstrumentManager generalinstrumentManager)
|
||||
{
|
||||
defaultPath = generalinstrumentManager._configLocation;
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultPath = _instrumentManager._partsLocation;
|
||||
}
|
||||
|
||||
_configurationManager = new RaytheonConfigurationManager(defaultPath);
|
||||
|
||||
var config = _configurationManager.GetConfiguration("BitGenSoftMeasurementManager");
|
||||
|
||||
_checkForMessageIntervalMs = config.GetConfigurationValue("Settings", "CheckForMessageIntervalMs", 10);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// initialize COE nodes based on test type
|
||||
/// </summary>
|
||||
/// <param name="instrumentName"></param>
|
||||
/// <param name="testType"></param>
|
||||
public void InitNodes()
|
||||
{
|
||||
foreach (var node in _bitNodes)
|
||||
{
|
||||
try
|
||||
{
|
||||
IBit bitNode = node.Value;
|
||||
bitNode.Initialize();
|
||||
bitNode.Open();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// close all connections
|
||||
/// </summary>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var bitNode in _bitNodes)
|
||||
{
|
||||
bitNode.Value?.Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// straight pass-through the message and parameters
|
||||
/// </summary>
|
||||
/// <param name="messageId"></param>
|
||||
/// <param name="timeoutInMs"></param>
|
||||
/// <param name="messageParams"></param>
|
||||
/// <returns></returns>
|
||||
public bool RunBIT(string messageId, uint timeoutInMs, IEnumerable<KeyValuePair<string, string>> messageParams = null)
|
||||
{
|
||||
if (_bitNodes.Any())
|
||||
{
|
||||
IBit bitNode = _bitNodes.First().Value;
|
||||
return bitNode.RunBIT(messageId, timeoutInMs, messageParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error($"Unable to locate BIT node. No nodes defined");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// straight pass-through the message and parameters
|
||||
/// </summary>
|
||||
/// <param name="instrumentName"></param>
|
||||
/// <param name="messageId"></param>
|
||||
/// <param name="timeoutInMs"></param>
|
||||
/// <param name="messageParams"></param>
|
||||
/// <returns></returns>
|
||||
public bool RunBIT(string instrumentName, string messageId, uint timeoutInMs, IEnumerable<KeyValuePair<string, string>> messageParams = null)
|
||||
{
|
||||
if (_bitNodes.ContainsKey(instrumentName))
|
||||
{
|
||||
return _bitNodes[instrumentName].RunBIT(messageId, timeoutInMs, messageParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error($"Unable to locate BIT node {instrumentName}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// always runs the request on the first node,
|
||||
/// </summary>
|
||||
/// <param name="messageIdOut"></param>
|
||||
/// <param name="messageIdIn"></param>
|
||||
/// <param name="timeoutInMs"></param>
|
||||
/// <param name="messageParams"></param>
|
||||
/// <returns></returns>
|
||||
public BitTestResults RunBITWaitForResults(string messageIdOut,
|
||||
string messageIdIn,
|
||||
uint timeoutInMs,
|
||||
IEnumerable<KeyValuePair<string, string>> messageParams = null)
|
||||
{
|
||||
if (_bitNodes.Any())
|
||||
{
|
||||
IBit bitNode = _bitNodes.First().Value;
|
||||
return bitNode.RunBITWaitForResults(messageIdOut, messageIdIn, timeoutInMs, messageParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error($"Unable to locate BIT node. No nodes defined");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// run BIT message and wait for result from the instrument based on the name
|
||||
/// </summary>
|
||||
/// <param name="instrumentName"></param>
|
||||
/// <param name="messageIdOut"></param>
|
||||
/// <param name="messageIdIn"></param>
|
||||
/// <param name="timeoutInMs"></param>
|
||||
/// <param name="messageParams"></param>
|
||||
/// <returns></returns>
|
||||
public BitTestResults RunBITWaitForResults(string instrumentName,
|
||||
string messageIdOut,
|
||||
string messageIdIn,
|
||||
uint timeoutInMs,
|
||||
IEnumerable<KeyValuePair<string, string>> messageParams = null)
|
||||
{
|
||||
if (_bitNodes.ContainsKey(instrumentName))
|
||||
{
|
||||
return _bitNodes[instrumentName].RunBITWaitForResults(messageIdOut, messageIdIn, timeoutInMs, messageParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error($"Unable to locate BIT node {instrumentName}");
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RunBITWaitForResults for the whole list of BIT Commands
|
||||
/// runs on the first node
|
||||
/// </summary>
|
||||
/// <param name="commands"></param>
|
||||
/// <returns></returns>
|
||||
public List<BitTestResults> RunBITWaitForResultsList(List<BITCommand> commands)
|
||||
{
|
||||
if (_bitNodes.Any())
|
||||
{
|
||||
return RunBITWaitForResultsList(commands, _bitNodes.First().Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error("Unable to locate BIT node. No nodes defined");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RunBITWaitForResults for the whole list of BIT Commands
|
||||
/// </summary>
|
||||
/// <param name="instrumentName"></param>
|
||||
/// <param name="commands"></param>
|
||||
/// <returns></returns>
|
||||
public List<BitTestResults> RunBITWaitForResultsList(string instrumentName, List<BITCommand> commands)
|
||||
{
|
||||
if (_bitNodes.ContainsKey(instrumentName))
|
||||
{
|
||||
return RunBITWaitForResultsList(commands, _bitNodes[instrumentName]);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error($"Unable to locate BIT node {instrumentName}");
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs BIT command and returns the results as a list
|
||||
/// </summary>
|
||||
/// <param name="commands"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<BitTestResults>> RunBITWaitForResultsListAsync(List<BITCommand> commands)
|
||||
{
|
||||
if (_bitNodes.Any())
|
||||
{
|
||||
return await RunBITWaitForResultsListAsync(commands, _bitNodes.First().Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error("Unable to locate BIT node. No nodes defined");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs BIT command for specific instrument and returns the results as a list
|
||||
/// </summary>
|
||||
/// <param name="instrumentName"></param>
|
||||
/// <param name="commands"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<BitTestResults>> RunBITWaitForResultsListAsync(string instrumentName, List<BITCommand> commands)
|
||||
{
|
||||
if (_bitNodes.ContainsKey(instrumentName))
|
||||
{
|
||||
return await RunBITWaitForResultsListAsync(commands, _bitNodes[instrumentName]);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error($"Unable to locate BIT node {instrumentName}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// asynchronously runs BIT command and waits for multiple results including parametric messages
|
||||
/// </summary>
|
||||
/// <param name="instrumentName">BIT instrument to run command</param>
|
||||
/// <param name="bitCommandId">main command</param>
|
||||
/// <param name="timeout">timeout value in ms for the main response</param>
|
||||
/// <param name="commandParams">optional parameters for the main command</param>
|
||||
/// <param name="parametricResponseIds">list of additional response messages with their respective timeouts to wait for</param>
|
||||
/// <param name="timeout2">parametric timeout value in ms</param>
|
||||
/// <param name="errorMessageId">nack response id when provided will be expected as a possible response for either main response or parametric response</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public async Task<List<BitTestResults>> RunBITWaitForResultsAsync( string instrumentName,
|
||||
string bitCommandId,
|
||||
int retries,
|
||||
uint timeout,
|
||||
IEnumerable<KeyValuePair<string, string>> commandParams = null,
|
||||
List<string> parametricResponseIds = null,
|
||||
uint timeout2 = 0,
|
||||
string errorMessageId = null)
|
||||
{
|
||||
IBit bitGenSoftManager = _bitNodes[instrumentName] ?? throw new Exception("BitGenSoftManager is null. Unable to perform operation.");
|
||||
|
||||
BITCommand command = BuildBITCommand(bitCommandId, retries, timeout, commandParams, parametricResponseIds, timeout2, errorMessageId);
|
||||
|
||||
return await RunBITWaitForResultsListAsync(new List<BITCommand> { command }, bitGenSoftManager);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// keep reading any of the messages from the list
|
||||
/// </summary>
|
||||
/// <param name="instrumentName"></param>
|
||||
/// <param name="parametricResponseIds"></param>
|
||||
/// <param name="timeOut"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public async Task KeepReadingBitResultsListAsync(string instrumentName, List<string> parametricResponseIds, CancellationToken token)
|
||||
{
|
||||
IBit bitNode = _bitNodes[instrumentName] ?? throw new Exception("BitGenSoftManager is null. Unable to perform operation.");
|
||||
await KeepReadingBitResultsListAsync(parametricResponseIds, token, bitNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// keep reading any of the messages from the list from the first node
|
||||
/// </summary>
|
||||
/// <param name="parametricResponseIds"></param>
|
||||
/// <param name="timeOut"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public async Task KeepReadingBitResultsListAsync(List<string> parametricResponseIds, CancellationToken token)
|
||||
{
|
||||
IBit bitNode = _bitNodes.First().Value;
|
||||
await KeepReadingBitResultsListAsync(parametricResponseIds, token, bitNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// looking for a any of the messages from the list
|
||||
/// </summary>
|
||||
/// <param name="instrumentName"></param>
|
||||
/// <param name="parametricResponseIds"></param>
|
||||
/// <param name="timeOut"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public async Task<List<BitTestResults>> GetBitResultsListAsync(string instrumentName, List<string> parametricResponseIds, int timeOut)
|
||||
{
|
||||
IBit bitNode = _bitNodes[instrumentName] ?? throw new Exception("BitGenSoftManager is null. Unable to perform operation.");
|
||||
return await GetBitResultsListAsync(parametricResponseIds, timeOut, bitNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// looking for a any of the messages from the list on the first node
|
||||
/// </summary>
|
||||
/// <param name="parametricResponseIds"></param>
|
||||
/// <param name="timeOut"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public async Task<List<BitTestResults>> GetBitResultsListAsync(List<string> parametricResponseIds, int timeOut)
|
||||
{
|
||||
IBit bitNode = _bitNodes.First().Value;
|
||||
return await GetBitResultsListAsync(parametricResponseIds, timeOut, bitNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// look for results in the node until either result was found or canceled
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="responseId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<BitTestResults> GetBITResultsAsync(CancellationToken token, string responseId)
|
||||
{
|
||||
IBit bitNode = _bitNodes.First().Value;
|
||||
return await GetBITResultsAsync(token, responseId, bitNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// look for results in the node until either result was found or canceled
|
||||
/// </summary>
|
||||
/// <param name="instrumentName"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="responseId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<BitTestResults> GetBITResultsAsync(string instrumentName, CancellationToken token, string responseId)
|
||||
{
|
||||
IBit bitNode = _bitNodes[instrumentName] ?? throw new Exception("BitGenSoftManager is null. Unable to perform operation.");
|
||||
return await GetBITResultsAsync(token, responseId, bitNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// look for results in either node
|
||||
/// </summary>
|
||||
/// <param name="messageId"></param>
|
||||
/// <returns></returns>
|
||||
public BitTestResults GetBITResults(string messageId)
|
||||
{
|
||||
_logger.Trace($"Getting BIT result for: {messageId}.");
|
||||
if (_bitNodes.Any())
|
||||
{
|
||||
IBit bitNode = _bitNodes.First().Value;
|
||||
return bitNode.GetBITResults(messageId);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// look for results in either node
|
||||
/// </summary>
|
||||
/// <param name="instrumentName"></param>
|
||||
/// <param name="messageId"></param>
|
||||
/// <returns></returns>
|
||||
public BitTestResults GetBITResults(string instrumentName, string messageId)
|
||||
{
|
||||
_logger.Trace($"{instrumentName} Getting BIT result for: {messageId}.");
|
||||
return _bitNodes.ContainsKey(instrumentName) ? _bitNodes[instrumentName].GetBITResults(messageId) : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// opens a folder parse XML files for BITCommand definitions and returns a list
|
||||
/// </summary>
|
||||
/// <param name="dir"></param>
|
||||
/// <returns></returns>
|
||||
public Dictionary<string, List<BITCommand>> GetBITCommands(string directoryPath)
|
||||
{
|
||||
Dictionary<string, List<BITCommand>> bitCommands = new Dictionary<string, List<BITCommand>>();
|
||||
|
||||
try
|
||||
{
|
||||
string[] xmlFiles;
|
||||
if (directoryPath.EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
xmlFiles = new string[] {directoryPath};
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get all XML files recursively in the specified directory
|
||||
xmlFiles = Directory.GetFiles(directoryPath, "*.xml", SearchOption.TopDirectoryOnly);
|
||||
}
|
||||
|
||||
foreach (string xmlFile in xmlFiles)
|
||||
{
|
||||
ConfigurationFile configFile = new ConfigurationFile(xmlFile);
|
||||
|
||||
List<string> sections = configFile.ReadAllSections();
|
||||
|
||||
foreach (string section in sections)
|
||||
{
|
||||
List<BITCommand> commands = configFile.ReadList<BITCommand>(section, "BIT_CMD");
|
||||
if(bitCommands.ContainsKey(section))
|
||||
{
|
||||
_logger.Warn($"Found a duplicate BIT configuration section {section}, overwriting from {xmlFile} file.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Trace($"Adding {section} commands from {xmlFile} file");
|
||||
}
|
||||
bitCommands[section] = commands;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, $"Error reading BIT Command definitions in {directoryPath}");
|
||||
throw;
|
||||
}
|
||||
|
||||
return bitCommands;
|
||||
}
|
||||
|
||||
#region Private functions
|
||||
|
||||
/// <summary>
|
||||
/// will keep pumping messages from the receiving queue until canceled
|
||||
/// </summary>
|
||||
/// <param name="parametricResponseIds"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="bitNode"></param>
|
||||
/// <returns></returns>
|
||||
private async Task KeepReadingBitResultsListAsync(List<string> parametricResponseIds, CancellationToken token, IBit bitNode)
|
||||
{
|
||||
_logger.Trace($"{bitNode.Name} Start continuously reading these messages: {string.Join(", ", parametricResponseIds)}.");
|
||||
|
||||
Dictionary<uint, int> score = new Dictionary<uint, int>();
|
||||
do
|
||||
{
|
||||
foreach (var responseId in parametricResponseIds)
|
||||
{
|
||||
BitTestResults bitTestresults = await GetBITResultsAsync(token, responseId, bitNode);
|
||||
|
||||
if (bitTestresults != null && !string.IsNullOrEmpty(bitTestresults.Label))
|
||||
{
|
||||
if(uint.TryParse(bitTestresults.Label, out uint label))
|
||||
{
|
||||
if(!score.ContainsKey(label))
|
||||
{
|
||||
score.Add(label, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
score[label]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//await Task.Delay(_checkForMessageIntervalMs);
|
||||
} while (!token.IsCancellationRequested);
|
||||
|
||||
foreach (var item in score)
|
||||
{
|
||||
_logger.Trace($"{bitNode.Name} Dequeued the total of {item.Value} BIT messages for 0x{item.Key:X} label");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="parametricResponseIds"></param>
|
||||
/// <param name="timeOut"></param>
|
||||
/// <param name="node"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<List<BitTestResults>> GetBitResultsListAsync(List<string> parametricResponseIds, int timeOut, IBit node)
|
||||
{
|
||||
_logger.Trace($"{node.Name} Start continuously getting BIT results for these messages: {string.Join(", ", parametricResponseIds)}.");
|
||||
|
||||
List<BitTestResults> results = new List<BitTestResults>();
|
||||
|
||||
CancellationTokenSource tokenSource = new CancellationTokenSource();
|
||||
List<Task<BitTestResults>> responseTasks = new List<Task<BitTestResults>>();
|
||||
|
||||
foreach (var responseId in parametricResponseIds)
|
||||
{
|
||||
responseTasks.Add(GetBITResultsAsync(tokenSource.Token, responseId, node));
|
||||
}
|
||||
|
||||
Task timeoutTask = Task.Delay(timeOut);
|
||||
var completedTask = await Task.WhenAny(responseTasks.Concat(new[] { timeoutTask }));
|
||||
|
||||
tokenSource.Cancel();
|
||||
tokenSource.Dispose();
|
||||
|
||||
if (completedTask == timeoutTask)
|
||||
{
|
||||
_logger.Warn($"Timed out after {timeOut} ms while waiting on parametrized response message(s) {string.Join(", ", parametricResponseIds)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var completedResults = responseTasks.Where(t => t.Status == TaskStatus.RanToCompletion && t.Result != null).Select(t => t.Result);
|
||||
results.AddRange(completedResults);
|
||||
}
|
||||
|
||||
_logger.Trace($"{node.Name} Completed getting BIT results for these messages: {string.Join(", ", parametricResponseIds)}, found {results?.Count} results");
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// look for results in the node until either result was found or canceled
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="responseId"></param>
|
||||
/// <param name="node"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<BitTestResults> GetBITResultsAsync(CancellationToken token, string responseId, IBit node)
|
||||
{
|
||||
//_logger.Trace($"{node.Name} Start waiting for BIT message: {responseId}.");
|
||||
|
||||
BitTestResults bitTestResults = null;
|
||||
do
|
||||
{
|
||||
await Task.Delay(_checkForMessageIntervalMs);
|
||||
try
|
||||
{
|
||||
bitTestResults = node.GetBITResults(responseId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, ex.Message);
|
||||
break;
|
||||
}
|
||||
} while (bitTestResults == null && !token.IsCancellationRequested);
|
||||
|
||||
//_logger.Trace($"{node.Name} Done waiting for BIT message: {responseId}.");
|
||||
|
||||
return bitTestResults;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// builds a command from parameters
|
||||
/// </summary>
|
||||
/// <param name="bitCommandId"></param>
|
||||
/// <param name="retries"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="commandParams"></param>
|
||||
/// <param name="parametricResponseIds"></param>
|
||||
/// <param name="timeout2"></param>
|
||||
/// <param name="errorMessageId"></param>
|
||||
/// <returns></returns>
|
||||
private static BITCommand BuildBITCommand(string bitCommandId,
|
||||
int retries,
|
||||
uint timeout,
|
||||
IEnumerable<KeyValuePair<string, string>> commandParams = null,
|
||||
List<string> parametricResponseIds = null,
|
||||
uint timeout2 = 0,
|
||||
string errorMessageId = null)
|
||||
{
|
||||
BITCommand bitCommand = new BITCommand
|
||||
{
|
||||
Command = bitCommandId,
|
||||
CommandTimeout = timeout,
|
||||
CommandParameters = new List<BITParameter>(),
|
||||
CommandResponses = new List<BITResponseMsg>(),
|
||||
ParametricResponse = retries.ToString(),
|
||||
ParametricTimeout = timeout2
|
||||
};
|
||||
|
||||
if (commandParams != null)
|
||||
{
|
||||
foreach (var commandParameter in commandParams)
|
||||
{
|
||||
bitCommand.CommandParameters.Add(new BITParameter
|
||||
{
|
||||
Key = commandParameter.Key,
|
||||
Value = commandParameter.Value,
|
||||
ParameterType = ParameterType.U
|
||||
});
|
||||
}
|
||||
}
|
||||
if(parametricResponseIds != null)
|
||||
{
|
||||
foreach (var response in parametricResponseIds)
|
||||
{
|
||||
bitCommand.CommandResponses.Add(new BITResponseMsg
|
||||
{
|
||||
Name = response,
|
||||
ResponseType = ResponseMessageType.P
|
||||
});
|
||||
}
|
||||
}
|
||||
if(!string.IsNullOrEmpty(errorMessageId))
|
||||
{
|
||||
bitCommand.CommandResponses.Add(new BITResponseMsg
|
||||
{
|
||||
Name = errorMessageId,
|
||||
ResponseType = ResponseMessageType.E
|
||||
});
|
||||
}
|
||||
|
||||
return bitCommand;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="commands"></param>
|
||||
/// <param name="node"></param>
|
||||
/// <returns></returns>
|
||||
private List<BitTestResults> RunBITWaitForResultsList(List<BITCommand> commands, IBit node)
|
||||
{
|
||||
List<BitTestResults> results = new List<BitTestResults>();
|
||||
|
||||
foreach (var command in commands)
|
||||
{
|
||||
string bitCommand = command.Command;
|
||||
string bitResponseId = ResponseGroupForFirstBITCall(command);
|
||||
uint timeout = command.CommandTimeout;
|
||||
uint timeout2 = command.ParametricTimeout;
|
||||
string strParamerticResponse = command.ParametricResponse;
|
||||
int retries = 0;
|
||||
if (int.TryParse(strParamerticResponse, out int tmpretries))
|
||||
{
|
||||
retries = tmpretries;
|
||||
}
|
||||
List<KeyValuePair<string, string>> commandParams = ConvertCommandParameters(command.CommandParameters);
|
||||
int runIndex = 0;
|
||||
do
|
||||
{
|
||||
runIndex++;
|
||||
try
|
||||
{
|
||||
var result = node.RunBITWaitForResults(bitCommand, bitResponseId, timeout, commandParams);
|
||||
results.Add(result);
|
||||
}
|
||||
catch (BitTimeoutException)
|
||||
{
|
||||
_logger.Warn($"Timeout after {timeout} ms on BIT command {bitCommand} waiting for result {bitResponseId}, retry number {runIndex}");
|
||||
if (runIndex == retries)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
} while (results == null && runIndex <= retries);
|
||||
|
||||
var responseGroup = ResponseGroupListForParameterBITCall(command);
|
||||
|
||||
if (responseGroup == null || !responseGroup.Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
ParallelOptions options = new ParallelOptions
|
||||
{
|
||||
CancellationToken = cts.Token,
|
||||
MaxDegreeOfParallelism = Environment.ProcessorCount
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
Parallel.ForEach(responseGroup, options, item =>
|
||||
{
|
||||
var totalWaitTimeMs = _checkForMessageIntervalMs;
|
||||
BitTestResults parametricresults;
|
||||
do
|
||||
{
|
||||
parametricresults = node.GetBITResults(item);
|
||||
|
||||
if (parametricresults != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread.Sleep(_checkForMessageIntervalMs);
|
||||
totalWaitTimeMs += _checkForMessageIntervalMs;
|
||||
}
|
||||
} while (totalWaitTimeMs < timeout2 && !cts.IsCancellationRequested);
|
||||
|
||||
if (parametricresults == null && !cts.IsCancellationRequested)
|
||||
{
|
||||
_logger.Warn($"Timed out while waiting on parametrized response message(s) for {command.Command} command");
|
||||
}
|
||||
|
||||
if (parametricresults != null)
|
||||
{
|
||||
// replace earlier results (confirmation message) with parametric results
|
||||
results.Add(parametricresults);
|
||||
cts.Cancel();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_logger.Trace($"Done waiting on parametrized response message(s) for {command.Command} command");
|
||||
}
|
||||
finally
|
||||
{
|
||||
cts.Dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// runs bit command and then
|
||||
/// </summary>
|
||||
/// <param name="commands"></param>
|
||||
/// <param name="node"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<List<BitTestResults>> RunBITWaitForResultsListAsync(List<BITCommand> commands, IBit node)
|
||||
{
|
||||
List<BitTestResults> results = new List<BitTestResults>();
|
||||
|
||||
foreach (var command in commands)
|
||||
{
|
||||
string bitCommand = command.Command;
|
||||
string bitResponseId = ResponseGroupForFirstBITCall(command);
|
||||
uint timeout = command.CommandTimeout;
|
||||
uint timeout2 = command.ParametricTimeout;
|
||||
string strParamerticResponse = command.ParametricResponse;
|
||||
int retries = 0;
|
||||
if (int.TryParse(strParamerticResponse, out int tmpretries))
|
||||
{
|
||||
retries = tmpretries;
|
||||
}
|
||||
List<KeyValuePair<string, string>> commandParams = ConvertCommandParameters(command.CommandParameters);
|
||||
int runIndex = 0;
|
||||
do
|
||||
{
|
||||
runIndex++;
|
||||
try
|
||||
{
|
||||
var result = await Task.Run(() => node.RunBITWaitForResults(bitCommand, bitResponseId, timeout, commandParams));
|
||||
results.Add(result);
|
||||
}
|
||||
catch (BitTimeoutException)
|
||||
{
|
||||
_logger.Warn($"Timeout after {timeout} ms on BIT command {bitCommand} waiting for result {bitResponseId}, retry number {runIndex}");
|
||||
if (runIndex == retries)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
} while (results == null && runIndex <= retries);
|
||||
|
||||
var responseGroup = ResponseGroupListForParameterBITCall(command);
|
||||
|
||||
if (responseGroup == null || !responseGroup.Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var paramResults = await GetBitResultsListAsync(responseGroup, (int)timeout2, node);
|
||||
if (paramResults != null)
|
||||
{
|
||||
results.AddRange(paramResults);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// for the initial BIT message expect to find R (main Response)
|
||||
/// if any responses marked as E (error) add it to the list as alternative expected response, separated by comma
|
||||
/// </summary>
|
||||
/// <param name="command"></param>
|
||||
/// <returns></returns>
|
||||
private static string ResponseGroupForFirstBITCall(BITCommand command)
|
||||
{
|
||||
StringBuilder resp = new StringBuilder();
|
||||
var tempMainResponseGroup = command.CommandResponses.Where(m => m.ResponseType != ResponseMessageType.E).ToList();
|
||||
if (tempMainResponseGroup != null)
|
||||
{
|
||||
// check for Rs first and if no messages marked with Rs than check for Us
|
||||
var mainResponse = tempMainResponseGroup.FirstOrDefault(m => m.ResponseType == ResponseMessageType.R);
|
||||
if (mainResponse != null)
|
||||
{
|
||||
resp.Append(mainResponse.Name);
|
||||
}
|
||||
}
|
||||
|
||||
// append all error message ids
|
||||
foreach (var item in command.CommandResponses.Where(m => m.ResponseType == ResponseMessageType.E))
|
||||
{
|
||||
resp.Append(',');
|
||||
resp.Append(item.Name);
|
||||
}
|
||||
|
||||
return resp.ToString();
|
||||
}
|
||||
/// <summary>
|
||||
/// for subsequent parameter response look for either P (parameterized) or U (undefined)
|
||||
/// if any responses marked as E (error) add it to the list as alternative expected response
|
||||
/// </summary>
|
||||
/// <param name="command"></param>
|
||||
/// <returns></returns>
|
||||
private static List<string> ResponseGroupListForParameterBITCall(BITCommand command)
|
||||
{
|
||||
List<string> resp = new List<string>();
|
||||
bool parameterizedRespExpected = false;
|
||||
var tempMainResponseGroup = command.CommandResponses.Where(m => m.ResponseType != ResponseMessageType.E).ToList();
|
||||
if (tempMainResponseGroup != null)
|
||||
{
|
||||
// check for Rs first and if no messages marked with Rs than check for Us
|
||||
var mainResponse = tempMainResponseGroup.FirstOrDefault(m => m.ResponseType == ResponseMessageType.P || m.ResponseType == ResponseMessageType.U);
|
||||
if (mainResponse != null)
|
||||
{
|
||||
resp.Add(mainResponse.Name);
|
||||
parameterizedRespExpected = true;
|
||||
}
|
||||
}
|
||||
if (parameterizedRespExpected)
|
||||
{
|
||||
// append all error message ids
|
||||
foreach (var item in command.CommandResponses.Where(m => m.ResponseType == ResponseMessageType.E))
|
||||
{
|
||||
resp.Add(item.Name);
|
||||
}
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
private static List<KeyValuePair<string, string>> ConvertCommandParameters(List<BITParameter> @in)
|
||||
{
|
||||
List<KeyValuePair<string, string>> parameters = new List<KeyValuePair<string, string>>();
|
||||
foreach (var parameter in @in)
|
||||
{
|
||||
parameters.Add(new KeyValuePair<string, string>(parameter.Key, parameter.Value));
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>BitGenSoftMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Bit GenSoft Measurement Manager</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLog" Version="5.0.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.InstrumentManager.GeneralInstrumentManager" Version="1.5.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.BIT.Contracts" Version="1.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,491 @@
|
||||
// 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 BitMeasurementManagerLib;
|
||||
using Raytheon.Instruments;
|
||||
using Raytheon.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using static BitMeasurementManagerLib.BitConfigurableMessageFactory;
|
||||
using NLog;
|
||||
|
||||
namespace MeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class interfaces to a host application for the purpose of sending and receiving messages to/from a UUT
|
||||
/// </summary>
|
||||
public class BitMeasurementManager : IDisposable
|
||||
{
|
||||
#region PublicClassMembers
|
||||
/// <summary>
|
||||
/// A delegate for host applications to get notified once a particular message arrives
|
||||
/// </summary>
|
||||
/// <param name="messageId">The message id that was received</param>
|
||||
/// <param name="messageDataLength">The number of bytes in the message</param>
|
||||
/// <param name="errorCode">An error code</param>
|
||||
public delegate void MessageReceivedDelegate(uint messageId, uint messageDataLength, int errorCode);
|
||||
#endregion
|
||||
|
||||
#region PrivateClassMembers
|
||||
private ICommDevice _commNode;
|
||||
private ICommDevice _commDevice;
|
||||
private BitMsgHandler _msgHandler;
|
||||
private BitMessageIDs _messageIds;
|
||||
private uint _readWorkerBufferSize;
|
||||
private uint _readWorkerRestTimeMs;
|
||||
private string _bitResultsFieldName;
|
||||
private static object _syncObj = new Object();
|
||||
|
||||
private static NLog.ILogger _logger;
|
||||
|
||||
#endregion
|
||||
|
||||
#region PrivateFuctions
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this object.
|
||||
/// </summary>
|
||||
/// <param name="disposing">True = currently disposing, False = not disposing.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_commNode != null)
|
||||
{
|
||||
_commNode.Shutdown();
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (_msgHandler != null)
|
||||
{
|
||||
_msgHandler.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write bytes onto an interface
|
||||
/// </summary>
|
||||
/// <param name="message">the bytes to send</param>
|
||||
/// <param name="numBytesToSend">the number of bytes to send</param>
|
||||
private void SendMessage(byte[] message, uint numBytesToSend)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
uint numBytesSent = 0;
|
||||
|
||||
_msgHandler.WriteOutgoingDataToLog(message, (int)numBytesToSend);
|
||||
|
||||
numBytesSent = _commNode.Write(message, numBytesToSend);
|
||||
|
||||
if (numBytesSent != numBytesToSend)
|
||||
{
|
||||
throw new Exception("Sent " + numBytesSent.ToString() + " bytes, expected to send " + numBytesToSend.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send out a message and wait for a response
|
||||
/// </summary>
|
||||
/// <param name="messageToSend">The message to send</param>
|
||||
/// <param name="timeoutInMs">Timeout in ms</param>
|
||||
/// <returns></returns>
|
||||
private BitConfigurableMessage SendMessageGetRsp(BitConfigurableMessage messageToSend, uint timeoutInMs)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
uint cmdMessageId = messageToSend.GetMessageId();
|
||||
uint rspMessageId = _messageIds.GetResponseId(cmdMessageId);
|
||||
|
||||
// reset the rsp event
|
||||
BitMsgRxBuffer.Instance().ResetReceiveEvent(rspMessageId);
|
||||
|
||||
// send out the message
|
||||
SendMessage(messageToSend);
|
||||
|
||||
// wait for the response
|
||||
bool didWeGetTheMsg = BitMsgRxBuffer.Instance().WaitForRspMsg(rspMessageId, timeoutInMs);
|
||||
|
||||
if (didWeGetTheMsg == false)
|
||||
{
|
||||
throw new Exception("Did not receive msg: " + rspMessageId.ToString());
|
||||
}
|
||||
|
||||
return GetNewestMessage(rspMessageId);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
public BitMeasurementManager(IInstrumentManager instrumentManager,
|
||||
string measurementDefFile,
|
||||
string comDeviceName,
|
||||
string comNodeName,
|
||||
string binDataLogFilename,
|
||||
string asciiDataLogFileName,
|
||||
MessageReceivedDelegate callback)
|
||||
{
|
||||
const string CONFIGURATION_INI_SECTION_NAME = "CONFIGURATION";
|
||||
|
||||
try
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
IniFile ini = new IniFile(measurementDefFile);
|
||||
|
||||
// hold onto the UUT byte order and header def
|
||||
bool shallWeByteSwap = Convert.ToBoolean(ini.ReadValue(CONFIGURATION_INI_SECTION_NAME, "SHALL_WE_BYTE_SWAP"));
|
||||
BitMsgEndianControl.Instance(shallWeByteSwap, ini);
|
||||
|
||||
_bitResultsFieldName = ini.ReadValue(CONFIGURATION_INI_SECTION_NAME, "BIT_RESULTS_FIELD_NAME");
|
||||
|
||||
string messageDefFile = ini.ReadValue(CONFIGURATION_INI_SECTION_NAME, "MESSAGE_DEF_FILE");
|
||||
string messageInpuStr = ini.ReadValue(CONFIGURATION_INI_SECTION_NAME, "MESSAGE_INPUT_TYPE");
|
||||
FactoryType bitMsgFactoryType = (FactoryType)Enum.Parse(typeof(FactoryType), messageInpuStr, true);
|
||||
|
||||
// initialize the BitMessageFactory
|
||||
BitConfigurableMessageFactory.Instance(messageDefFile, bitMsgFactoryType);
|
||||
|
||||
// initialize the Message ID List, set each message size and set the rsp IDs
|
||||
_messageIds = new BitMessageIDs();
|
||||
Dictionary<uint, BitConfigurableMessage> allMessages = BitConfigurableMessageFactory.Instance().RetreiveAllMessages();
|
||||
foreach (var msg in allMessages.Values)
|
||||
{
|
||||
uint messageId = msg.GetMessageId();
|
||||
uint msgRspId = msg.GetMessageRspId();
|
||||
_messageIds.AddId(messageId);
|
||||
|
||||
if (msgRspId != 0xffffffff)
|
||||
{
|
||||
_messageIds.SetRspId(messageId, msgRspId);
|
||||
}
|
||||
|
||||
_messageIds.SetMsgSize(msg.GetMessageId(), msg.GetEntireMsgLength());
|
||||
}
|
||||
|
||||
|
||||
BitMsgRxBuffer.Instance(_messageIds);
|
||||
|
||||
//_isThereHardware = isThereHardware;
|
||||
|
||||
uint parseBufferSize = Convert.ToUInt32(ini.ReadValue(CONFIGURATION_INI_SECTION_NAME, "PARSE_BUFFER_SIZE"));
|
||||
|
||||
bool shallWeLogOutgoingBinData = Convert.ToBoolean(ini.ReadValue("LOGGING", "SHALL_WE_LOG_OUTGOING_BIN"));
|
||||
bool shallWeLogOutgoingAsciiData = Convert.ToBoolean(ini.ReadValue("LOGGING", "SHALL_WE_LOG_OUTGOING_ASCII"));
|
||||
bool shallWeLogIncomingBinData = Convert.ToBoolean(ini.ReadValue("LOGGING", "SHALL_WE_LOG_INCOMING_BIN"));
|
||||
bool shallWeLogIncomingAsciiData = Convert.ToBoolean(ini.ReadValue("LOGGING", "SHALL_WE_LOG_INCOMING__ASCII"));
|
||||
bool shallWeLogParserVerboseInfo = Convert.ToBoolean(ini.ReadValue("LOGGING", "SHALL_WE_LOG_VERBOSE_PARSER_INFO"));
|
||||
|
||||
// get the CRC check info
|
||||
uint crcMask = Convert.ToUInt32(ini.ReadValue("CRC_STATUS", "BITMASK"), 16);
|
||||
string crcFieldName = ini.ReadValue("CRC_STATUS", "CRC_FIELD_LOGICAL_NAME");
|
||||
|
||||
// create the message handler
|
||||
_msgHandler = new BitMsgHandler(_messageIds, callback, parseBufferSize, binDataLogFilename, asciiDataLogFileName, shallWeLogOutgoingBinData, shallWeLogOutgoingAsciiData, shallWeLogIncomingBinData, shallWeLogIncomingAsciiData, crcMask, crcFieldName, shallWeLogParserVerboseInfo);
|
||||
|
||||
// create the communication device
|
||||
_commDevice = instrumentManager.GetInstrument<ICommDevice>(comDeviceName);
|
||||
_commDevice?.Initialize();
|
||||
|
||||
// get the read thread buffer size and thread rate
|
||||
_readWorkerBufferSize = Convert.ToUInt32(ini.ReadValue(CONFIGURATION_INI_SECTION_NAME, "READ_WORKER_BUFFER_SIZE"));
|
||||
_readWorkerRestTimeMs = Convert.ToUInt32(ini.ReadValue(CONFIGURATION_INI_SECTION_NAME, "READ_WORKER_REST_TIME_MS"));
|
||||
|
||||
// create the communication node
|
||||
_commNode = instrumentManager.GetInstrument<ICommDevice>(comNodeName);
|
||||
_commNode?.Initialize();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Finalizer
|
||||
/// </summary>
|
||||
~BitMeasurementManager()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dataToAdd"></param>
|
||||
public void AddDataTestFunction(byte[] dataToAdd)
|
||||
{
|
||||
_msgHandler.AddData(dataToAdd, (uint)dataToAdd.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the data files
|
||||
/// </summary>
|
||||
public void CloseDataFiles()
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
_msgHandler.CloseDataFiles();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiate a message object. The host configure its parameters prior to sending it
|
||||
/// </summary>
|
||||
/// <param name="messageId">The message id for the message to create</param>
|
||||
/// <returns>The message object</returns>
|
||||
public BitConfigurableMessage CreateMessage(uint messageId)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
BitConfigurableMessage message = BitConfigurableMessageFactory.Instance().RetreiveMessage(messageId);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release the resources
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public TType GetDataItemByName<TType>(BitConfigurableMessage message, string name)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
return message.GetDataItemByName<TType>(name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="dataItemName"></param>
|
||||
/// <returns></returns>
|
||||
public uint GetDataItemByNameUint(BitConfigurableMessage message, string dataItemName)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
uint dataValue = GetDataItemByName<uint>(message, dataItemName);
|
||||
|
||||
return dataValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of message IDs that are supported
|
||||
/// </summary>
|
||||
/// <returns>A list of message Ids</returns>
|
||||
public List<uint> GetSupportedMessages()
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
List<uint> mesages = _messageIds.GetAllIds();
|
||||
|
||||
return mesages;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the newest message in the buffer
|
||||
/// </summary>
|
||||
/// <param name="rspMessageId">The message ID to Retrieve</param>
|
||||
/// <param name="shallWeDeleteOthers">True to delete all of the other messages of this ID</param>
|
||||
/// <returns>The retrieved message</returns>
|
||||
public BitConfigurableMessage GetNewestMessage(uint rspMessageId, bool shallWeDeleteOthers = true)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
BitConfigurableMessage messageToReturn = BitMsgRxBuffer.Instance().GetNewestMessage(rspMessageId, shallWeDeleteOthers);
|
||||
|
||||
return messageToReturn;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the oldest message in the buffer
|
||||
/// </summary>
|
||||
/// <param name="rspMessageId">The message ID to Retrieve</param>
|
||||
/// <returns>The retrieved message</returns>
|
||||
public BitConfigurableMessage GetOldestMessage(uint rspMessageId)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
BitConfigurableMessage messageToReturn = BitMsgRxBuffer.Instance().GetOldestMessage(rspMessageId);
|
||||
|
||||
return messageToReturn;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the communication device, if it is already open, it closes it and then reopens it
|
||||
/// </summary>
|
||||
public void OpenCommDevice()
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
// shut it down and reinitialize
|
||||
_commNode.Shutdown();
|
||||
_commNode.Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs a BIT test, return the test results
|
||||
/// </summary>
|
||||
/// <param name="messageId"></param>
|
||||
/// <param name="timeoutInMs">The number of ms to wait for a response</param>
|
||||
/// <param name="messageParams"></param>
|
||||
/// <returns>The test result register</returns>
|
||||
public uint RunBitTest(uint messageId, uint timeoutInMs, params object[] messageParams)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
BitConfigurableMessage cmdMessage = BitConfigurableMessageFactory.Instance().RetreiveMessage(messageId);
|
||||
if (messageParams.Length > 0)
|
||||
{
|
||||
cmdMessage.SetParams(messageParams);
|
||||
}
|
||||
BitConfigurableMessage rspMessage = SendMessageGetRsp(cmdMessage, timeoutInMs);
|
||||
uint testResult = rspMessage.GetDataItemByName<uint>(_bitResultsFieldName.ToUpper());
|
||||
return testResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="messageId"></param>
|
||||
/// <param name="messageParams"></param>
|
||||
/// <returns></returns>
|
||||
public void SendMessage(uint messageId, params object[] messageParams)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
BitConfigurableMessage cmdMessage = BitConfigurableMessageFactory.Instance().RetreiveMessage(messageId);
|
||||
|
||||
if (messageParams.Length > 0)
|
||||
{
|
||||
cmdMessage.SetParams(messageParams);
|
||||
}
|
||||
|
||||
SendMessage(cmdMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send out a message and wait for a response
|
||||
/// </summary>
|
||||
/// <param name="messageId">The message ID to send</param>
|
||||
/// <param name="messageParams"></param>
|
||||
/// <returns>The response message for the command that was sent</returns>
|
||||
public BitConfigurableMessage SendMessageGetRsp(uint messageId, uint timeoutInMs, params object[] messageParams)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
BitConfigurableMessage cmdMessage = BitConfigurableMessageFactory.Instance().RetreiveMessage(messageId);
|
||||
|
||||
if (messageParams.Length > 0)
|
||||
{
|
||||
cmdMessage.SetParams(messageParams);
|
||||
}
|
||||
|
||||
BitConfigurableMessage rspMessage = SendMessageGetRsp(cmdMessage, timeoutInMs);
|
||||
return rspMessage;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send out a message on the comm interface
|
||||
/// </summary>
|
||||
/// <param name="message">The message to send</param>
|
||||
public void SendMessage(BitConfigurableMessage message)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
// get the ascii msg for logging just before sending
|
||||
string asciiMessage = message.ToString();
|
||||
|
||||
// get the formatted gu message
|
||||
uint messageNumBytes = message.GetEntireMsgLength();
|
||||
|
||||
// allocate an array to hold onto the data that we will send
|
||||
byte[] messageDataToSend = new byte[messageNumBytes];
|
||||
|
||||
// get a pointer to the data
|
||||
GCHandle messagePinnedArray = GCHandle.Alloc(messageDataToSend, GCHandleType.Pinned);
|
||||
IntPtr pMessageData = messagePinnedArray.AddrOfPinnedObject();
|
||||
|
||||
// get the encoded data to send
|
||||
message.Format(pMessageData);
|
||||
|
||||
// free the ptr
|
||||
messagePinnedArray.Free();
|
||||
|
||||
// log the data
|
||||
_msgHandler.WriteOutgoingDataToLog(asciiMessage);
|
||||
|
||||
// send the data
|
||||
SendMessage(messageDataToSend, messageNumBytes);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable or Disable the Callback for a specific message
|
||||
/// </summary>
|
||||
/// <param name="msgId"></param>
|
||||
/// <param name="shallWeEnableCallback"></param>
|
||||
public void SetCallbackControl(uint msgId, bool shallWeEnableCallback)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
_msgHandler.SetCallbackControl(msgId, shallWeEnableCallback);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>BitMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Bit Measurement Manager</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.0</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLog" Version="5.0.0" />
|
||||
<PackageReference Include="Raytheon.Common" Version="1.0.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.CommDevice.Contracts" Version="1.2.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.InstrumentManager.Contracts" Version="1.8.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\SupportProjects\ExcelZip\ExcelZip.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,50 @@
|
||||
// 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 BitMeasurementManagerLib
|
||||
{
|
||||
public interface IConfigurableDataItem
|
||||
{
|
||||
Type DataType { get;}
|
||||
|
||||
object Data { get; set; }
|
||||
|
||||
string GetDataItemName();
|
||||
|
||||
BitConfigurableMessage.DataItemType GetDataItemType();
|
||||
|
||||
int GetNumDataItems();
|
||||
|
||||
string GetDefaultValueStr();
|
||||
}
|
||||
|
||||
|
||||
public interface IConfigurableDataItem<TData> : IConfigurableDataItem
|
||||
{
|
||||
new TData Data { get; set;}
|
||||
|
||||
new string GetDataItemName();
|
||||
|
||||
new BitConfigurableMessage.DataItemType GetDataItemType();
|
||||
|
||||
new int GetNumDataItems();
|
||||
|
||||
new string GetDefaultValueStr();
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
namespace BitMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// A spot to hold application constants
|
||||
/// </summary>
|
||||
internal static class BitInterfaceManagerConstants
|
||||
{
|
||||
// data types
|
||||
internal static readonly string FLOAT_DATA_TYPE = "FLOAT";
|
||||
internal static readonly string UINT_DATA_TYPE = "UINT";
|
||||
internal static readonly string UINT_HEX_DATA_TYPE = "UINT_HEX";
|
||||
internal static readonly string USHORT_HEX_DATA_TYPE = "USHORT_HEX";
|
||||
internal static readonly string USHORT_DATA_TYPE = "USHORT";
|
||||
internal static readonly string BYTE_HEX_DATA_TYPE = "BYTE_HEX";
|
||||
internal static readonly string BYTE_ARRAY_HEX_DATA_TYPE = "BYTE_ARRAY_HEX";
|
||||
internal static readonly string DOUBLE_DATA_TYPE = "DOUBLE";
|
||||
internal static readonly string ULONG_DATA_TYPE = "ULONG";
|
||||
internal static readonly string ULONG_HEX_DATA_TYPE = "ULONG_HEX";
|
||||
internal static readonly string BITS_DATA_TYPE = "BITS";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
// 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;
|
||||
|
||||
namespace BitMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton for holding onto message objects
|
||||
/// </summary>
|
||||
internal class BitMsgEndianControl
|
||||
{
|
||||
#region PublicMembers
|
||||
public struct HeaderDef
|
||||
{
|
||||
public int msgIdByteLocation;
|
||||
public int msgIdDataLen;
|
||||
public int secondaryMsgIdByteLocation;
|
||||
public int secondaryMsgIdDataLen;
|
||||
public uint secondaryMsgIdExpectedValue;
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region PrivateClassMembers
|
||||
// class variables
|
||||
private static BitMsgEndianControl _msgEndianControlInstance;
|
||||
private bool _shallWeSwap;
|
||||
private HeaderDef _headerDef;
|
||||
#endregion
|
||||
|
||||
#region PrivateFuctions
|
||||
/// <summary>
|
||||
/// The constructor
|
||||
/// </summary>
|
||||
private BitMsgEndianControl(bool shallWeSwap, IniFile defFile)
|
||||
{
|
||||
_shallWeSwap = shallWeSwap;
|
||||
|
||||
_headerDef.msgIdByteLocation = Convert.ToInt32(defFile.ReadValue("MSG_HEADER_DEF", "MSG_ID_LOCATION"));
|
||||
_headerDef.msgIdDataLen = Convert.ToInt32(defFile.ReadValue("MSG_HEADER_DEF", "MSG_ID_DATA_LEN"));
|
||||
_headerDef.secondaryMsgIdByteLocation = Convert.ToInt32(defFile.ReadValue("MSG_HEADER_DEF", "SECONDARY_MSG_ID_LOCATION"));
|
||||
_headerDef.secondaryMsgIdDataLen = Convert.ToInt32(defFile.ReadValue("MSG_HEADER_DEF", "SECONDARY_MSG_ID_DATA_LEN"));
|
||||
_headerDef.secondaryMsgIdExpectedValue = Convert.ToUInt32(defFile.ReadValue("MSG_HEADER_DEF", "SECONDARY_MSG_ID_EXPECTED_VALUE"), 16);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
/// The way to get access to this singleton
|
||||
/// <param name="shallWeSwap"></param>
|
||||
/// <returns>the instance to this class</returns>
|
||||
internal static BitMsgEndianControl Instance(bool shallWeSwap = true, IniFile defFile = null)
|
||||
{
|
||||
if (_msgEndianControlInstance == null)
|
||||
{
|
||||
_msgEndianControlInstance = new BitMsgEndianControl(shallWeSwap, defFile);
|
||||
}
|
||||
|
||||
return _msgEndianControlInstance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal HeaderDef GetHeaderDef()
|
||||
{
|
||||
return _headerDef;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal bool ShallWeSwap()
|
||||
{
|
||||
return _shallWeSwap;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
// 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 System.Collections.Generic;
|
||||
using Raytheon.Common;
|
||||
|
||||
namespace BitMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton for holding onto message objects
|
||||
/// </summary>
|
||||
internal class BitMsgRxBuffer
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
// class variables
|
||||
private static BitMsgRxBuffer _msgBufferInstance;
|
||||
private static object _syncObj = new Object();
|
||||
private BitMessageIDs _messageIds;
|
||||
private Dictionary<uint, List<BitConfigurableMessage>> _msgList;
|
||||
private Dictionary<uint, AutoResetEvent> _receivedMsgEvents;
|
||||
#endregion
|
||||
|
||||
#region PrivateFuctions
|
||||
|
||||
/// <summary>
|
||||
/// The constructor
|
||||
/// </summary>
|
||||
private BitMsgRxBuffer(BitMessageIDs messageIds)
|
||||
{
|
||||
_messageIds = messageIds;
|
||||
|
||||
_msgList = new Dictionary<uint, List<BitConfigurableMessage>>();
|
||||
|
||||
// create an event for each msg.
|
||||
_receivedMsgEvents = new Dictionary<uint, AutoResetEvent>();
|
||||
|
||||
List<uint> msgIds = _messageIds.GetAllIds();
|
||||
|
||||
foreach (uint id in msgIds)
|
||||
{
|
||||
_receivedMsgEvents[id] = new AutoResetEvent(false);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
/// The way to get access to this singleton
|
||||
/// </summary>
|
||||
/// <returns>the instance to this class</returns>
|
||||
internal static BitMsgRxBuffer Instance(BitMessageIDs messageIds = null)
|
||||
{
|
||||
if (_msgBufferInstance == null)
|
||||
{
|
||||
_msgBufferInstance = new BitMsgRxBuffer(messageIds);
|
||||
}
|
||||
|
||||
return _msgBufferInstance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a message to this buffer
|
||||
/// </summary>
|
||||
/// <param name="msg">The message to add</param>
|
||||
/// <param name="shouldWeDeleteOthers">flag for if the other messages of this type should be deleted from the buffer</param>
|
||||
internal void AddMsg(BitConfigurableMessage msg, bool shouldWeDeleteOthers = true)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
uint msgId = msg.GetMessageId();
|
||||
|
||||
if (shouldWeDeleteOthers == true)
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitMsgRxBuffer::AddMsg() - clearing list for " + msgId.ToString(), ErrorLogger.LogLevel.INFO);
|
||||
ClearList(msgId);
|
||||
}
|
||||
|
||||
if (_msgList.ContainsKey(msgId) == false)
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitMsgRxBuffer::AddMsg() - creating new list for " + msgId.ToString(), ErrorLogger.LogLevel.INFO);
|
||||
_msgList[msgId] = new List<BitConfigurableMessage>();
|
||||
}
|
||||
|
||||
ErrorLogger.Instance().Write("BitMsgRxBuffer::AddMsg() - Adding " + msgId.ToString() + " to the list", ErrorLogger.LogLevel.INFO);
|
||||
_msgList[msgId].Add(msg);
|
||||
|
||||
_receivedMsgEvents[msgId].Set();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all messages from the buffer
|
||||
/// </summary>
|
||||
internal void ClearAllMsgs()
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
foreach (uint id in _msgList.Keys)
|
||||
{
|
||||
ClearList(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all messages of the command type from the buffer
|
||||
/// </summary>
|
||||
/// <param name="id">The message id to remove</param>
|
||||
internal void ClearList(uint id)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (_msgList.ContainsKey(id) == true)
|
||||
{
|
||||
_msgList[id].Clear();
|
||||
|
||||
_msgList.Remove(id);
|
||||
|
||||
_receivedMsgEvents[id].Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the oldest message in the buffer
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the message to get</param>
|
||||
/// <returns>The oldest message in the buffer</returns>
|
||||
internal BitConfigurableMessage GetOldestMessage(uint id)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (_msgList.ContainsKey(id))
|
||||
{
|
||||
List<BitConfigurableMessage> list = _msgList[id];
|
||||
|
||||
if (list.Count == 0)
|
||||
{
|
||||
throw new Exception("BitMsgRxBuffer::GetOldestMessage() - there are no messges in the queue for id: " + id.ToString());
|
||||
}
|
||||
|
||||
BitConfigurableMessage oldestMsg = list[0];
|
||||
|
||||
list.RemoveAt(0);
|
||||
|
||||
return oldestMsg;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("BitMsgRxBuffer::GetOldestMessage() - no message exists with id: " + id.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the most recent message from the buffer
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the message to get</param>
|
||||
/// <param name="shouldWeDeleteOthers">flag controlling if the other messages of this type should be deleted</param>
|
||||
/// <returns>The message</returns>
|
||||
internal BitConfigurableMessage GetNewestMessage(uint id, bool shouldWeDeleteOthers = true)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (_msgList.ContainsKey(id))
|
||||
{
|
||||
List<BitConfigurableMessage> list = _msgList[id];
|
||||
|
||||
BitConfigurableMessage newestMsg = list[list.Count - 1];
|
||||
|
||||
list.RemoveAt(list.Count - 1);
|
||||
|
||||
if (shouldWeDeleteOthers == true)
|
||||
{
|
||||
ClearList(id);
|
||||
}
|
||||
|
||||
return newestMsg;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("BitMsgRxBuffer::GetNewestMessage() - no message exists with id: " + id.ToString("X"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of messages of this type in the buffer
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the message to get</param>
|
||||
/// <returns>the number of messages of this type in the buffer</returns>
|
||||
internal int GetNumMsgsInQueue(uint id)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (_msgList.ContainsKey(id) == true)
|
||||
{
|
||||
return _msgList[id].Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal void ResetReceiveEvent(uint id)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
_receivedMsgEvents[id].Reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wait for a message to get added to the buffer
|
||||
/// </summary>
|
||||
/// <param name="id">The message id to wait for</param>
|
||||
/// <param name="timeoutMs">The amount of time in ms to wait</param>
|
||||
/// <returns>true if the message arrived, false if it did not</returns>
|
||||
internal bool WaitForRspMsg(uint id, uint timeoutMs)
|
||||
{
|
||||
return _receivedMsgEvents[id].WaitOne((int)timeoutMs);
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
// 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;
|
||||
using Raytheon.Common;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace BitMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface to sending/receiving data over TCP sockets
|
||||
/// </summary>
|
||||
internal class BitSimCommDeviceNode : ICommDevice, IDisposable
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private ICommDevice _commDevice;
|
||||
private BitMessageIDs _messageIds;
|
||||
private IWorkerInterface _socketReadWorker;
|
||||
private Thread _socketReadThread;
|
||||
private readonly string _name;
|
||||
private SelfTestResult _selfTestResult;
|
||||
private State _state;
|
||||
#endregion
|
||||
|
||||
#region PrivateFunctions
|
||||
/// <summary>
|
||||
/// The finalizer. Necessary for quitting the read thread
|
||||
/// </summary>
|
||||
~BitSimCommDeviceNode()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Quit the threads associated with the node
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
State initialState = _state;
|
||||
|
||||
// close the socket and threads
|
||||
try
|
||||
{
|
||||
if (initialState == State.Ready)
|
||||
{
|
||||
Shutdown();
|
||||
|
||||
_commDevice.Shutdown();
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// dispose of the resources
|
||||
try
|
||||
{
|
||||
if (initialState == State.Ready)
|
||||
{
|
||||
_socketReadWorker.Dispose();
|
||||
_state = State.Uninitialized;
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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 PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="name">The name of this instance</param>
|
||||
/// <param name="messageIds"></param>
|
||||
/// <param name="msgHandler"></param>
|
||||
/// <param name="commReadWorkerBufferSize"></param>
|
||||
/// <param name="readWorkerRestTimeInMs"></param>
|
||||
public BitSimCommDeviceNode(string name, ICommDevice commDevice, BitMessageIDs messageIds, MsgDevice msgHandler, uint commReadWorkerBufferSize = 100000, uint readWorkerRestTimeInMs = 10)
|
||||
{
|
||||
_name = name;
|
||||
|
||||
_commDevice = commDevice;
|
||||
|
||||
_messageIds = messageIds;
|
||||
|
||||
_socketReadWorker = new CommReadWorker(this, msgHandler, commReadWorkerBufferSize, readWorkerRestTimeInMs);
|
||||
_socketReadThread = new Thread(_socketReadWorker.DoWork);
|
||||
|
||||
// start the read thread
|
||||
_socketReadThread.Start();
|
||||
|
||||
_selfTestResult = SelfTestResult.Unknown;
|
||||
|
||||
_state = State.Uninitialized;
|
||||
}
|
||||
|
||||
public void Open()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool ClearErrors()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool DisplayEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string DetailedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return "This is a BIT Comm Sim Device Node " + _name;
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the device
|
||||
/// </summary>
|
||||
/*public void Close()
|
||||
{
|
||||
const int THREAD_QUIT_TIMEOUT_MS = 3000;
|
||||
|
||||
// tell the thread to quit
|
||||
_socketReadWorker.QuitWork();
|
||||
|
||||
// close the socket which the thread might be blocked on
|
||||
_commDevice.Close();
|
||||
|
||||
if (_socketReadThread.IsAlive)
|
||||
{
|
||||
bool didThreadQuit = _socketReadThread.Join(THREAD_QUIT_TIMEOUT_MS);
|
||||
|
||||
if (didThreadQuit == false)
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitSimCommDeviceNode::Close() - Logging Thread did not quit as expected, aborting it");
|
||||
_socketReadThread.Abort();
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitSimCommDeviceNode::Close() - Logging Thread quit successfully after join", ErrorLogger.LogLevel.INFO);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitSimCommDeviceNode::Close() - Logging Thread quit successfully", ErrorLogger.LogLevel.INFO);
|
||||
}
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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>
|
||||
///
|
||||
/// </summary>
|
||||
public bool FrontPanelEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public InstrumentMetadata Info
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
_commDevice.Initialize();
|
||||
_state = State.Ready;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public SelfTestResult PerformSelfTest()
|
||||
{
|
||||
return _commDevice.SelfTestResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read data from the socket
|
||||
/// </summary>
|
||||
/// <param name="dataRead">The data that was read</param>
|
||||
/// <returns>the number of bytes read</returns>
|
||||
public uint Read(ref byte[] dataRead)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
Close();
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="readTimeout"></param>
|
||||
public void SetReadTimeout(uint readTimeout)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public SelfTestResult SelfTestResult
|
||||
{
|
||||
get
|
||||
{
|
||||
return _selfTestResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public State Status
|
||||
{
|
||||
get
|
||||
{
|
||||
return _state;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void Shutdown()
|
||||
{
|
||||
const int THREAD_QUIT_TIMEOUT_MS = 3000;
|
||||
|
||||
if (_state == State.Ready)
|
||||
{
|
||||
// tell the thread to quit
|
||||
_socketReadWorker.QuitWork();
|
||||
|
||||
// close the socket which the thread might be blocked on
|
||||
_commDevice.Shutdown();
|
||||
|
||||
if (_socketReadThread.IsAlive)
|
||||
{
|
||||
bool didThreadQuit = _socketReadThread.Join(THREAD_QUIT_TIMEOUT_MS);
|
||||
|
||||
if (didThreadQuit == false)
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitSimCommDeviceNode::Close() - Logging Thread did not quit as expected, aborting it");
|
||||
_socketReadThread.Abort();
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitSimCommDeviceNode::Close() - Logging Thread quit successfully after join", ErrorLogger.LogLevel.INFO);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitSimCommDeviceNode::Close() - Logging Thread quit successfully", ErrorLogger.LogLevel.INFO);
|
||||
}
|
||||
}
|
||||
|
||||
_state = State.Uninitialized;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send data on the socket
|
||||
/// </summary>
|
||||
/// <param name="dataToSend">The data to send</param>
|
||||
/// <param name="numBytesToWrite">The number of bytes to write from the dataToSend buffer</param>
|
||||
/// <returns>The number of bytes sent</returns>
|
||||
public uint Write(byte[] dataToSend, uint numBytesToWrite)
|
||||
{
|
||||
// determine the id and get create the rsp message
|
||||
IntPtr pDataPtr = Marshal.AllocHGlobal(dataToSend.Length);
|
||||
Marshal.Copy(dataToSend, 0, pDataPtr, dataToSend.Length);
|
||||
uint commandId = BitConfigurableMessageHeader.GetMessageId(pDataPtr, (uint)dataToSend.Length);
|
||||
Marshal.FreeHGlobal(pDataPtr);
|
||||
|
||||
bool isThereAResponse = _messageIds.IsThereAResponseMessage(commandId);
|
||||
|
||||
// if there is a rsp msg, create a dummy msg
|
||||
if (isThereAResponse == true)
|
||||
{
|
||||
uint rspId = _messageIds.GetResponseId(commandId);
|
||||
BitConfigurableMessage rspMessage = BitConfigurableMessageFactory.Instance().RetreiveMessage(rspId);
|
||||
BitMsgRxBuffer.Instance().AddMsg(rspMessage);
|
||||
//uint msgLen = rspMessage.GetEntireMsgLength();
|
||||
//byte[] simData = new byte[msgLen];
|
||||
//_msgHandler.AddData();
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
return (uint)dataToSend.Length;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
// 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.Threading;
|
||||
|
||||
namespace Raytheon.Instruments
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface to sending/receiving data over comm devices
|
||||
/// </summary>
|
||||
internal class CommDeviceNode : ICommDevice, IDisposable
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private ICommDevice _commDevice;
|
||||
private IWorkerInterface _socketReadWorker;
|
||||
private Thread _socketReadThread;
|
||||
private readonly string _name;
|
||||
private SelfTestResult _selfTestResult;
|
||||
private State _state;
|
||||
|
||||
private uint _commReadWorkerBufferSize;
|
||||
private uint _readWorkerRestTimeInMs;
|
||||
private MsgDevice _msgHandler;
|
||||
|
||||
#endregion
|
||||
|
||||
#region PrivateFuctions
|
||||
/// <summary>
|
||||
/// The finalizer. Necessary for quitting the read thread
|
||||
/// </summary>
|
||||
~CommDeviceNode()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Quit the threads associated with the node
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
State initialState = _state;
|
||||
|
||||
// close the socket and threads
|
||||
try
|
||||
{
|
||||
if (initialState == State.Ready)
|
||||
{
|
||||
Shutdown();
|
||||
_commDevice.Shutdown();
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// dispose of the resources
|
||||
try
|
||||
{
|
||||
if (initialState == State.Ready)
|
||||
{
|
||||
_socketReadWorker.Dispose();
|
||||
_state = State.Uninitialized;
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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 PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
/// The constructor
|
||||
/// </summary>
|
||||
/// <param name="name">The name of this instance</param>
|
||||
/// <param name="commDevice">The communication device</param>
|
||||
/// <param name="msgHandler">The message handler for this interface</param>
|
||||
/// <param name="commReadWorkerBufferSize">The number of bytes for the buffer internal to this class. Each individual read will read upto this buffer size (or until the timeout happens)</param>
|
||||
/// <param name="readWorkerRestTimeInMs">Number of ms to reset between read calls on the comm interface</param>
|
||||
public CommDeviceNode(string name, ICommDevice commDevice, MsgDevice msgHandler, uint commReadWorkerBufferSize = 100000, uint readWorkerRestTimeInMs = 10)
|
||||
{
|
||||
_name = name;
|
||||
_commDevice = commDevice;
|
||||
|
||||
_commReadWorkerBufferSize = commReadWorkerBufferSize;
|
||||
_readWorkerRestTimeInMs = readWorkerRestTimeInMs;
|
||||
_msgHandler = msgHandler;
|
||||
|
||||
Open();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts communication thread
|
||||
/// </summary>
|
||||
public void Open()
|
||||
{
|
||||
_socketReadWorker = new CommReadWorker(this, _msgHandler, _commReadWorkerBufferSize, _readWorkerRestTimeInMs);
|
||||
_socketReadThread = new Thread(_socketReadWorker.DoWork);
|
||||
|
||||
// start the read thread
|
||||
_socketReadThread.Start();
|
||||
|
||||
_selfTestResult = SelfTestResult.Unknown;
|
||||
_state = State.Uninitialized;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// there is no error msg repository
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool ClearErrors()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool DisplayEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string DetailedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return "This is a Comm Sim Device Node " + _name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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>
|
||||
///
|
||||
/// </summary>
|
||||
public bool FrontPanelEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public InstrumentMetadata Info
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
_commDevice.Initialize();
|
||||
_state = State.Ready;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public SelfTestResult PerformSelfTest()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read data from the socket
|
||||
/// </summary>
|
||||
/// <param name="dataRead">The data that was read</param>
|
||||
/// <returns>the number of bytes read</returns>
|
||||
public uint Read(ref byte[] dataRead)
|
||||
{
|
||||
return _commDevice.Read(ref dataRead);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets communications
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
Close();
|
||||
Open();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="readTimeout"></param>
|
||||
public void SetReadTimeout(uint readTimeout)
|
||||
{
|
||||
_commDevice.SetReadTimeout(readTimeout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public SelfTestResult SelfTestResult
|
||||
{
|
||||
get
|
||||
{
|
||||
return _selfTestResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public State Status
|
||||
{
|
||||
get
|
||||
{
|
||||
return _state;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close communications
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close communications
|
||||
/// </summary>
|
||||
public void Shutdown()
|
||||
{
|
||||
if (_state == State.Ready)
|
||||
{
|
||||
const int THREAD_QUIT_TIMEOUT_MS = 3000;
|
||||
|
||||
// tell the thread to quit
|
||||
_socketReadWorker.QuitWork();
|
||||
|
||||
// close the socket which the thread might be blocked on
|
||||
_commDevice.Shutdown();
|
||||
|
||||
if (_socketReadThread.IsAlive)
|
||||
{
|
||||
bool didThreadQuit = _socketReadThread.Join(THREAD_QUIT_TIMEOUT_MS);
|
||||
|
||||
if (didThreadQuit == false)
|
||||
{
|
||||
ErrorLogger.Instance().Write("CommDeviceNode::Close() - Logging Thread did not quit as expected, aborting it");
|
||||
_socketReadThread.Abort();
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorLogger.Instance().Write("CommDeviceNode::Close() - Logging Thread quit successfully after join", ErrorLogger.LogLevel.INFO);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorLogger.Instance().Write("CommDeviceNode::Close() - Logging Thread quit successfully", ErrorLogger.LogLevel.INFO);
|
||||
}
|
||||
}
|
||||
|
||||
_state = State.Uninitialized;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send data on the socket
|
||||
/// </summary>
|
||||
/// <param name="dataToSend">The data to send</param>
|
||||
/// <param name="numBytesToWrite">The number of bytes to write from the dataToSend buffer</param>
|
||||
/// <returns>The number of bytes sent</returns>
|
||||
public uint Write(byte[] dataToSend, uint numBytesToWrite)
|
||||
{
|
||||
return _commDevice.Write(dataToSend, numBytesToWrite);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
// 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 System.Net.Sockets;
|
||||
using Raytheon.Instruments;
|
||||
using Raytheon.Common;
|
||||
|
||||
namespace Raytheon.Instruments
|
||||
{
|
||||
/// <summary>
|
||||
/// Takes raw data from an ICommDevice and throws it in a buffer
|
||||
/// </summary>
|
||||
internal class CommReadWorker : IWorkerInterface
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private ICommDevice _commNode;
|
||||
private MsgDevice _msgHandler;
|
||||
private bool _threadQuitControl;
|
||||
private AutoResetEvent _quitEvent;
|
||||
private byte[] _dataRead;
|
||||
private readonly uint _timeToRestBetweenReadsInMs;
|
||||
#endregion
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="commNode">The communication interface</param>
|
||||
/// <param name="msghandler">The message handler for received data</param>
|
||||
/// <param name="bufferSize">The number of bytes for the buffer internal to this class. Each individual read will read upto this buffer size (or until the timeout happens)</param>
|
||||
/// <param name="timeToRestBetweenReadsInMs">Number of ms to rest after a read call</param>
|
||||
public CommReadWorker(ICommDevice commNode, MsgDevice msghandler, uint bufferSize, uint timeToRestBetweenReadsInMs)
|
||||
{
|
||||
_commNode = commNode;
|
||||
_threadQuitControl = false;
|
||||
_msgHandler = msghandler;
|
||||
_quitEvent = new AutoResetEvent(false);
|
||||
_dataRead = new byte[bufferSize];
|
||||
_timeToRestBetweenReadsInMs = timeToRestBetweenReadsInMs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizer
|
||||
/// </summary>
|
||||
~CommReadWorker()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this object. Needed for releasing thread/comm resources
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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>
|
||||
/// Reads the socket and puts data into a buffer
|
||||
/// </summary>
|
||||
public void DoWork()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (_threadQuitControl == false)
|
||||
{
|
||||
try
|
||||
{
|
||||
uint numBytesRead = _commNode.Read(ref _dataRead);
|
||||
|
||||
// add into buffer
|
||||
if (numBytesRead > 0)
|
||||
{
|
||||
_msgHandler.AddData(_dataRead, numBytesRead);
|
||||
}
|
||||
|
||||
// not using timeToRestBetweenReadsInMs. Just going to wait 1 ms and get back to the read
|
||||
if (_quitEvent.WaitOne(1))
|
||||
{
|
||||
ErrorLogger.Instance().Write("CommReadWorker::DoWork() - received signal to quit", ErrorLogger.LogLevel.INFO);
|
||||
_threadQuitControl = true;
|
||||
}
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
if (e.SocketErrorCode == SocketError.TimedOut)
|
||||
{
|
||||
//expected
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorLogger.Instance().Write("CommReadWorker::DoWork() - " + e.Message, ErrorLogger.LogLevel.ERROR);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ErrorLogger.Instance().Write("CommReadWorker::DoWork() - " + e.Message, ErrorLogger.LogLevel.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
ErrorLogger.Instance().Write("CommReadWorker::DoWork() - exiting", ErrorLogger.LogLevel.INFO);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Commands the worker to stop
|
||||
/// </summary>
|
||||
public void QuitWork()
|
||||
{
|
||||
_quitEvent.Set();
|
||||
_threadQuitControl = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this object
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_quitEvent.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,961 @@
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace BitMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class implements a message that can be put on a communication interface
|
||||
/// </summary>
|
||||
public class BitConfigurableMessage
|
||||
{
|
||||
#region PublicClassMembers
|
||||
public enum DataItemType
|
||||
{
|
||||
FLOAT,
|
||||
UINT,
|
||||
UINT_HEX,
|
||||
USHORT_HEX,
|
||||
USHORT,
|
||||
BYTE_HEX,
|
||||
BYTE_ARRAY_HEX,
|
||||
DOUBLE,
|
||||
ULONG,
|
||||
ULONG_HEX,
|
||||
BITS
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PrivateClassMembers
|
||||
public List<IConfigurableDataItem> _dataItems;
|
||||
public Dictionary<string, int> _byteArrayCount;
|
||||
public Dictionary<string, int> _bitCount;
|
||||
private string _messageName;
|
||||
private uint _entireMsgLen;
|
||||
private uint _messageId;
|
||||
private uint _rspMessageId;
|
||||
#endregion
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
/// Copy constructor
|
||||
/// </summary>
|
||||
/// <param name="rhs">The object to copy</param>
|
||||
public BitConfigurableMessage(BitConfigurableMessage rhs)
|
||||
{
|
||||
// copy over the basic types
|
||||
_messageId = rhs._messageId;
|
||||
_rspMessageId = rhs._rspMessageId;
|
||||
_messageName = String.Copy(rhs._messageName);
|
||||
|
||||
// _entireMsgLen will get set when we add the data items
|
||||
_entireMsgLen = 0;
|
||||
|
||||
// initialize the objects
|
||||
_dataItems = new List<IConfigurableDataItem>();
|
||||
_byteArrayCount = new Dictionary<string, int>();
|
||||
_bitCount = new Dictionary<string, int>();
|
||||
|
||||
// copy the data items over
|
||||
foreach (IConfigurableDataItem dataItem in rhs._dataItems)
|
||||
{
|
||||
AddDataItem(dataItem.GetDataItemName(), dataItem.GetDataItemType(), dataItem.GetNumDataItems(), dataItem.GetDefaultValueStr());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="messageId"></param>
|
||||
/// <param name="rspMessageId"></param>
|
||||
/// <param name="messageName"></param>
|
||||
public BitConfigurableMessage(uint messageId, uint rspMessageId, string messageName)
|
||||
{
|
||||
_messageId = messageId;
|
||||
|
||||
_rspMessageId = rspMessageId;
|
||||
|
||||
_messageName = messageName;
|
||||
|
||||
_entireMsgLen = 0;
|
||||
|
||||
_dataItems = new List<IConfigurableDataItem>();
|
||||
|
||||
_byteArrayCount = new Dictionary<string, int>();
|
||||
|
||||
_bitCount = new Dictionary<string, int>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public uint GetMessageId()
|
||||
{
|
||||
return _messageId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public uint GetMessageRspId()
|
||||
{
|
||||
return _rspMessageId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dataItemName"></param>
|
||||
/// <param name="dataItemType"></param>
|
||||
/// <param name="numItems"></param>
|
||||
/// <param name="defaultValue"></param>
|
||||
public void AddDataItem(string dataItemName, DataItemType dataItemType, int numItems, string defaultValue)
|
||||
{
|
||||
if (numItems < 1)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessage::AddDataItem() - numItems is not valid: " + numItems + ", data item name is: " + dataItemName);
|
||||
}
|
||||
|
||||
if (numItems > 1 && (dataItemType != DataItemType.BYTE_ARRAY_HEX && dataItemType != DataItemType.BITS))
|
||||
{
|
||||
throw new Exception("BitConfigurableMessage::AddDataItem() - numItems greater than one only allowed for hex byte arrays and BITs: " + numItems + ", data item name is: " + dataItemName);
|
||||
}
|
||||
|
||||
if (dataItemType == DataItemType.UINT)
|
||||
{
|
||||
uint value = Convert.ToUInt32(defaultValue);
|
||||
BitConfigurableMessageDataItem<uint> dataItem = new BitConfigurableMessageDataItem<uint>(dataItemName, dataItemType, value, defaultValue, numItems);
|
||||
_entireMsgLen += (uint)(4 * numItems);
|
||||
_dataItems.Add(dataItem);
|
||||
}
|
||||
else if (dataItemType == DataItemType.UINT_HEX)
|
||||
{
|
||||
uint value = Convert.ToUInt32(defaultValue, 16);
|
||||
BitConfigurableMessageDataItem<uint> dataItem = new BitConfigurableMessageDataItem<uint>(dataItemName, dataItemType, value, defaultValue, numItems);
|
||||
_entireMsgLen += (uint)(4 * numItems);
|
||||
_dataItems.Add(dataItem);
|
||||
}
|
||||
else if (dataItemType == DataItemType.FLOAT)
|
||||
{
|
||||
float value = (float)Convert.ToDouble(defaultValue);
|
||||
BitConfigurableMessageDataItem<float> dataItem = new BitConfigurableMessageDataItem<float>(dataItemName, dataItemType, value, defaultValue, numItems);
|
||||
_entireMsgLen += (uint)(4 * numItems);
|
||||
_dataItems.Add(dataItem);
|
||||
}
|
||||
else if (dataItemType == DataItemType.USHORT)
|
||||
{
|
||||
ushort value = Convert.ToUInt16(defaultValue);
|
||||
BitConfigurableMessageDataItem<ushort> dataItem = new BitConfigurableMessageDataItem<ushort>(dataItemName, dataItemType, value, defaultValue, numItems);
|
||||
_entireMsgLen += (uint)(2 * numItems);
|
||||
_dataItems.Add(dataItem);
|
||||
}
|
||||
else if (dataItemType == DataItemType.USHORT_HEX)
|
||||
{
|
||||
ushort value = Convert.ToUInt16(defaultValue, 16);
|
||||
BitConfigurableMessageDataItem<ushort> dataItem = new BitConfigurableMessageDataItem<ushort>(dataItemName, dataItemType, value, defaultValue, numItems);
|
||||
_entireMsgLen += (uint)(2 * numItems);
|
||||
_dataItems.Add(dataItem);
|
||||
}
|
||||
else if (dataItemType == DataItemType.DOUBLE)
|
||||
{
|
||||
double value = Convert.ToDouble(defaultValue);
|
||||
BitConfigurableMessageDataItem<double> dataItem = new BitConfigurableMessageDataItem<double>(dataItemName, dataItemType, value, defaultValue, numItems);
|
||||
_entireMsgLen += (uint)(8 * numItems);
|
||||
_dataItems.Add(dataItem);
|
||||
}
|
||||
else if (dataItemType == DataItemType.ULONG)
|
||||
{
|
||||
ulong value = Convert.ToUInt64(defaultValue);
|
||||
BitConfigurableMessageDataItem<ulong> dataItem = new BitConfigurableMessageDataItem<ulong>(dataItemName, dataItemType, value, defaultValue, numItems);
|
||||
_entireMsgLen += (uint)(8 * numItems);
|
||||
_dataItems.Add(dataItem);
|
||||
}
|
||||
else if (dataItemType == DataItemType.ULONG_HEX)
|
||||
{
|
||||
ulong value = Convert.ToUInt64(defaultValue, 16);
|
||||
BitConfigurableMessageDataItem<ulong> dataItem = new BitConfigurableMessageDataItem<ulong>(dataItemName, dataItemType, value, defaultValue, numItems);
|
||||
_entireMsgLen += (uint)(8 * numItems);
|
||||
_dataItems.Add(dataItem);
|
||||
}
|
||||
else if (dataItemType == DataItemType.BYTE_HEX)
|
||||
{
|
||||
byte value = Convert.ToByte(defaultValue, 16);
|
||||
BitConfigurableMessageDataItem<byte> dataItem = new BitConfigurableMessageDataItem<byte>(dataItemName, dataItemType, value, defaultValue, numItems);
|
||||
_entireMsgLen += (uint)(1 * numItems);
|
||||
_dataItems.Add(dataItem);
|
||||
}
|
||||
else if (dataItemType == DataItemType.BITS)
|
||||
{
|
||||
if (numItems > 8)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessage::AddDataItem() - trying to add bit field: " + dataItemName + " that has more than 8 bits, bit fields are required to be less than 8 bits at this time");
|
||||
}
|
||||
|
||||
// query how many bit fields have been added
|
||||
// use this later when updating the number of bytes in the message
|
||||
int totalBitPrevCount = 0;
|
||||
foreach (KeyValuePair<string, int> entry in _bitCount)
|
||||
{
|
||||
totalBitPrevCount += entry.Value;
|
||||
}
|
||||
|
||||
|
||||
//intention integer division
|
||||
uint numBytesPrevAdded = (uint)(totalBitPrevCount / 8);
|
||||
|
||||
int totalBitPrevCountRemander = totalBitPrevCount % 8;
|
||||
|
||||
// if remander is not 0, bump up the byte count by 1
|
||||
if (totalBitPrevCountRemander != 0)
|
||||
{
|
||||
numBytesPrevAdded++;
|
||||
}
|
||||
|
||||
// convert value to a byte and create the data item
|
||||
defaultValue = defaultValue.Replace("0b", "");
|
||||
defaultValue = defaultValue.Replace("0B", "");
|
||||
byte value = Convert.ToByte(defaultValue, 2);
|
||||
BitConfigurableMessageDataItem<byte> dataItem = new BitConfigurableMessageDataItem<byte>(dataItemName, dataItemType, value, defaultValue, numItems);
|
||||
_dataItems.Add(dataItem);
|
||||
|
||||
// store the number of bits for this items
|
||||
_bitCount[dataItemName.ToUpper()] = numItems;
|
||||
|
||||
// now that we updated the bit fields, query how many bit fields there are
|
||||
int totalBitCount = 0;
|
||||
foreach (KeyValuePair<string, int> entry in _bitCount)
|
||||
{
|
||||
totalBitCount += entry.Value;
|
||||
}
|
||||
|
||||
// intentional integer division
|
||||
uint numBytesToAdd = (uint)(totalBitCount / 8);
|
||||
int totalBitCountRemander = totalBitCount % 8;
|
||||
|
||||
// if remander is not 0, bump up the byte count by 1
|
||||
if (totalBitCountRemander != 0)
|
||||
{
|
||||
numBytesToAdd++;
|
||||
}
|
||||
|
||||
// increment the message length we crossed a byte boundary with the total number of bits
|
||||
_entireMsgLen += numBytesToAdd - numBytesPrevAdded;
|
||||
}
|
||||
else if (dataItemType == DataItemType.BYTE_ARRAY_HEX)
|
||||
{
|
||||
byte value = Convert.ToByte(defaultValue, 16);
|
||||
|
||||
byte[] data = new byte[numItems];
|
||||
|
||||
for (int i = 0; i < numItems; i++)
|
||||
{
|
||||
data[i] = value;
|
||||
}
|
||||
|
||||
BitConfigurableMessageDataItem<Array> dataItem = new BitConfigurableMessageDataItem<Array>(dataItemName, dataItemType, data, defaultValue, numItems);
|
||||
|
||||
_dataItems.Add(dataItem);
|
||||
|
||||
_entireMsgLen += (uint)(1 * numItems);
|
||||
|
||||
_byteArrayCount[dataItemName.ToUpper()] = numItems;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("BitConfigurableMessage::AddDataItem() - Unsupported data item type: " + dataItemType.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="pData"></param>
|
||||
public void Format(IntPtr pData)
|
||||
{
|
||||
IntPtr pDataLocation = pData;
|
||||
|
||||
// should we byte swap
|
||||
bool shallWeSwap = BitMsgEndianControl.Instance().ShallWeSwap();
|
||||
|
||||
// format the data
|
||||
List<IConfigurableDataItem> formattedData = _dataItems;
|
||||
|
||||
for (int i = 0; i < formattedData.Count; i++)
|
||||
{
|
||||
IConfigurableDataItem dataItem = _dataItems[i];
|
||||
DataItemType itemType = dataItem.GetDataItemType();
|
||||
string itemName = dataItem.GetDataItemName();
|
||||
object itemValue = dataItem.Data;
|
||||
|
||||
int dataItemSize = 0;
|
||||
|
||||
if (itemValue is float)// if (itemType == DataItemType.FLOAT)
|
||||
{
|
||||
float data = (float)itemValue;
|
||||
|
||||
if (shallWeSwap == true)
|
||||
{
|
||||
itemValue = Util.Swap(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
itemValue = data;
|
||||
}
|
||||
|
||||
dataItemSize = 4;
|
||||
|
||||
//copy data from our data items, info the buffer
|
||||
Marshal.StructureToPtr(itemValue, pDataLocation, true);
|
||||
}
|
||||
else if (itemValue is uint)
|
||||
{
|
||||
uint data = (uint)itemValue;
|
||||
|
||||
if (shallWeSwap == true)
|
||||
{
|
||||
itemValue = Util.Swap(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
itemValue = data;
|
||||
}
|
||||
|
||||
dataItemSize = 4;
|
||||
|
||||
//copy data from our data items, info the buffer
|
||||
Marshal.StructureToPtr(itemValue, pDataLocation, true);
|
||||
}
|
||||
else if (itemValue is ushort)
|
||||
{
|
||||
ushort data = (ushort)itemValue;
|
||||
|
||||
if (shallWeSwap == true)
|
||||
{
|
||||
itemValue = Util.Swap(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
itemValue = data;
|
||||
}
|
||||
|
||||
dataItemSize = 2;
|
||||
|
||||
//copy data from our data items, info the buffer
|
||||
Marshal.StructureToPtr(itemValue, pDataLocation, true);
|
||||
}
|
||||
else if (itemValue is byte)
|
||||
{
|
||||
// handle the case where we stored an array of BITS as a byte
|
||||
if (itemType == DataItemType.BITS)
|
||||
{
|
||||
// grab the value of the first bit item
|
||||
byte totalBitItemValue = (byte)itemValue;
|
||||
|
||||
// queue up the rest of the BITs to the next byte boundary
|
||||
int totalBitsProcessed = dataItem.GetNumDataItems();
|
||||
|
||||
for (int j = i + 1; totalBitsProcessed < 8; j++)
|
||||
{
|
||||
// grab the next data items
|
||||
IConfigurableDataItem bitDataItem = _dataItems[j];
|
||||
DataItemType bitItemType = bitDataItem.GetDataItemType();
|
||||
|
||||
// the next item should be BITS
|
||||
if (bitItemType != DataItemType.BITS)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessage::Format() - Bit fields not consecutive out to byte boundary for msg ID: " + _messageId.ToString("X8"));
|
||||
}
|
||||
|
||||
int bitItemNumBites = bitDataItem.GetNumDataItems();
|
||||
byte bitItemValue = (byte)bitDataItem.Data;
|
||||
uint mask = (uint)((1 << bitItemNumBites) - 1) << totalBitsProcessed;
|
||||
|
||||
// mask in the next bit value
|
||||
byte valueToMaskIn = (byte)((bitItemValue << totalBitsProcessed) & mask);
|
||||
totalBitItemValue = (byte)(totalBitItemValue | valueToMaskIn);
|
||||
|
||||
// increment the bit counter
|
||||
totalBitsProcessed += bitItemNumBites;
|
||||
|
||||
// increment the outer loop counter since we just processed it
|
||||
i++;
|
||||
}
|
||||
|
||||
// double check that we are on a byte boundary
|
||||
//int byteBoundaryRemainder = totalBitsProcessed % 8;
|
||||
if (totalBitsProcessed != 8)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessage::Format() - Bit fields not equal to 8 for msg ID: " + _messageId.ToString("X8"));
|
||||
}
|
||||
|
||||
dataItemSize = 1;
|
||||
|
||||
// hold onto the total bit item value
|
||||
itemValue = (byte)totalBitItemValue;
|
||||
|
||||
//copy data from our data items, info the buffer
|
||||
Marshal.StructureToPtr(itemValue, pDataLocation, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
itemValue = (byte)itemValue;
|
||||
|
||||
dataItemSize = 1;
|
||||
|
||||
//copy data from our data items, info the buffer
|
||||
Marshal.StructureToPtr(itemValue, pDataLocation, true);
|
||||
}
|
||||
}
|
||||
else if (itemValue is double)
|
||||
{
|
||||
itemValue = (double)itemValue;
|
||||
|
||||
dataItemSize = 8;
|
||||
|
||||
//copy data from our data items, info the buffer
|
||||
Marshal.StructureToPtr(itemValue, pDataLocation, true);
|
||||
}
|
||||
else if (itemValue is ulong)
|
||||
{
|
||||
itemValue = (ulong)itemValue;
|
||||
|
||||
dataItemSize = 8;
|
||||
|
||||
//copy data from our data items, info the buffer
|
||||
Marshal.StructureToPtr(itemValue, pDataLocation, true);
|
||||
}
|
||||
else if (itemValue is Array)
|
||||
{
|
||||
IEnumerable en = (IEnumerable)itemValue;
|
||||
byte[] arrayTemp = en.OfType<byte>().ToArray();
|
||||
dataItemSize = arrayTemp.Length;
|
||||
Marshal.Copy(arrayTemp, 0, pDataLocation, dataItemSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("BitConfigurableMessage::Format() - Unsupported data item type: " + itemType.ToString());
|
||||
}
|
||||
|
||||
// increment the pointer
|
||||
pDataLocation = IntPtr.Add(pDataLocation, dataItemSize);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dataItemName"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] GetDataItemByName_ByteArray(string dataItemName)
|
||||
{
|
||||
for (int i = 0; i < _dataItems.Count; i++)
|
||||
{
|
||||
if (_dataItems[i].GetDataItemName().ToUpper() == dataItemName.ToUpper())
|
||||
{
|
||||
if (_dataItems[i].GetDataItemType() != DataItemType.BYTE_ARRAY_HEX)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessage::GetDataItemByName_ByteArray() - item was not a byte array: " + dataItemName);
|
||||
}
|
||||
|
||||
IEnumerable en = (IEnumerable)_dataItems[i].Data;
|
||||
byte[] dataToReturn = en.OfType<byte>().ToArray();
|
||||
return dataToReturn;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("BitConfigurableMessage::GetDataItemByName_ByteArray() - Could not find data item: " + dataItemName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dataItemName"></param>
|
||||
/// <returns></returns>
|
||||
public T GetDataItemByName<T>(string dataItemName)
|
||||
{
|
||||
for (int i = 0; i < _dataItems.Count; i++)
|
||||
{
|
||||
if (_dataItems[i].GetDataItemName().ToUpper() == dataItemName.ToUpper())
|
||||
{
|
||||
T value = (T)Convert.ChangeType(_dataItems[i].Data, typeof(T));
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("BitConfigurableMessage::GetDataItemByName() - Could not find data item: " + dataItemName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public uint GetEntireMsgLength()
|
||||
{
|
||||
return _entireMsgLen;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="pData"></param>
|
||||
public void Parse(IntPtr pData)
|
||||
{
|
||||
// should we byte swap
|
||||
bool shallWeSwap = BitMsgEndianControl.Instance().ShallWeSwap();
|
||||
|
||||
IntPtr pMsgDataPtr = pData;
|
||||
|
||||
for (int i = 0; i < _dataItems.Count; i++)
|
||||
{
|
||||
IConfigurableDataItem item = _dataItems[i];
|
||||
|
||||
object itemData = item.Data;
|
||||
|
||||
if (itemData is float)
|
||||
{
|
||||
float itemValue = 0;
|
||||
|
||||
unsafe
|
||||
{
|
||||
float* pFloatItem = (float*)pMsgDataPtr;
|
||||
|
||||
itemValue = *pFloatItem;
|
||||
}
|
||||
|
||||
if (shallWeSwap == true)
|
||||
{
|
||||
itemValue = Util.Swap(itemValue);
|
||||
}
|
||||
|
||||
item.Data = itemValue;
|
||||
|
||||
_dataItems[i] = item;
|
||||
|
||||
pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 4);
|
||||
}
|
||||
else if (itemData is uint)
|
||||
{
|
||||
uint itemValue = 0;
|
||||
|
||||
unsafe
|
||||
{
|
||||
uint* pUInt32Item = (uint*)pMsgDataPtr;
|
||||
|
||||
itemValue = *pUInt32Item;
|
||||
}
|
||||
|
||||
if (shallWeSwap == true)
|
||||
{
|
||||
itemValue = Util.Swap(itemValue);
|
||||
}
|
||||
|
||||
item.Data = itemValue;
|
||||
|
||||
_dataItems[i] = item;
|
||||
|
||||
pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 4);
|
||||
}
|
||||
else if (itemData is ushort)
|
||||
{
|
||||
ushort itemValue = 0;
|
||||
|
||||
unsafe
|
||||
{
|
||||
ushort* pUInt16Item = (ushort*)pMsgDataPtr;
|
||||
|
||||
itemValue = *pUInt16Item;
|
||||
}
|
||||
|
||||
if (shallWeSwap == true)
|
||||
{
|
||||
itemValue = Util.Swap(itemValue);
|
||||
}
|
||||
|
||||
item.Data = itemValue;
|
||||
|
||||
_dataItems[i] = item;
|
||||
|
||||
pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 2);
|
||||
}
|
||||
else if (itemData is double)
|
||||
{
|
||||
double itemValue = 0;
|
||||
|
||||
unsafe
|
||||
{
|
||||
double* pDoubleItem = (double*)pMsgDataPtr;
|
||||
|
||||
itemValue = *pDoubleItem;
|
||||
}
|
||||
|
||||
if (shallWeSwap == true)
|
||||
{
|
||||
itemValue = Util.Swap(itemValue);
|
||||
}
|
||||
|
||||
item.Data = itemValue;
|
||||
|
||||
_dataItems[i] = item;
|
||||
|
||||
pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 8);
|
||||
}
|
||||
else if (itemData is ulong)
|
||||
{
|
||||
ulong itemValue = 0;
|
||||
|
||||
unsafe
|
||||
{
|
||||
ulong* pUlongItem = (ulong*)pMsgDataPtr;
|
||||
|
||||
itemValue = *pUlongItem;
|
||||
}
|
||||
|
||||
if (shallWeSwap == true)
|
||||
{
|
||||
itemValue = Util.Swap(itemValue);
|
||||
}
|
||||
|
||||
item.Data = itemValue;
|
||||
|
||||
_dataItems[i] = item;
|
||||
|
||||
pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 8);
|
||||
}
|
||||
else if (itemData is byte)
|
||||
{
|
||||
// handle the case where we are storing bit arrays as a byte
|
||||
if (item.GetDataItemType() == DataItemType.BITS)
|
||||
{
|
||||
// grab the value of the first bit item
|
||||
byte rawDataValue = 0;
|
||||
|
||||
// Grab the byte from the msg pointer
|
||||
unsafe
|
||||
{
|
||||
byte* pUInt8Item = (byte*)pMsgDataPtr;
|
||||
|
||||
rawDataValue = *pUInt8Item;
|
||||
}
|
||||
|
||||
// set the first data item
|
||||
uint mask = (uint)((1 << item.GetNumDataItems()) - 1);
|
||||
item.Data = (byte)(rawDataValue & mask);
|
||||
_dataItems[i] = item;
|
||||
int totalBitsProcessed = item.GetNumDataItems();
|
||||
|
||||
// set the rest of the data items
|
||||
for (int j = i + 1; totalBitsProcessed < 8; j++)
|
||||
{
|
||||
IConfigurableDataItem bitDataItem = _dataItems[j];
|
||||
|
||||
DataItemType bitItemType = bitDataItem.GetDataItemType();
|
||||
|
||||
// the next item should be BITS
|
||||
if (bitItemType != DataItemType.BITS)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessage::Parse() - Bit fields not consecutive out to byte boundary for msg ID: " + _messageId.ToString("X8"));
|
||||
}
|
||||
|
||||
// shift the data into the beggining of the byte and mask out the other bits
|
||||
mask = (uint)((1 << bitDataItem.GetNumDataItems()) - 1);
|
||||
bitDataItem.Data = (byte)((rawDataValue >> totalBitsProcessed) & mask);
|
||||
_dataItems[j] = bitDataItem;
|
||||
|
||||
// increment the bit counter
|
||||
totalBitsProcessed += bitDataItem.GetNumDataItems();
|
||||
|
||||
// increment the outer loop counter since we just processed it
|
||||
i++;
|
||||
}
|
||||
|
||||
// double check that we are on a byte boundary
|
||||
//int byteBoundaryRemainder = totalBitsProcessed % 8;
|
||||
if (totalBitsProcessed != 8)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessage::Parse() - Bit fields not on byte boundary forequal to 8 msg ID: " + _messageId.ToString("X8"));
|
||||
}
|
||||
|
||||
pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte itemValue = 0;
|
||||
|
||||
unsafe
|
||||
{
|
||||
byte* pUInt8Item = (byte*)pMsgDataPtr;
|
||||
|
||||
itemValue = *pUInt8Item;
|
||||
}
|
||||
|
||||
item.Data = itemValue;
|
||||
|
||||
_dataItems[i] = item;
|
||||
|
||||
pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 1);
|
||||
}
|
||||
}
|
||||
else if (itemData is Array)
|
||||
{
|
||||
int numBytes = _byteArrayCount[item.GetDataItemName().ToUpper()];
|
||||
byte[] data = new byte[numBytes];
|
||||
|
||||
unsafe
|
||||
{
|
||||
for (int byteCounter = 0; byteCounter < numBytes; byteCounter++)
|
||||
{
|
||||
byte* pUInt8Item = (byte*)pMsgDataPtr;
|
||||
data[byteCounter] = *pUInt8Item;
|
||||
pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 1);
|
||||
}
|
||||
}
|
||||
|
||||
item.Data = data;
|
||||
|
||||
_dataItems[i] = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("BitConfigurableMessage::Parse() - Unsupported data item type: " + item.GetDataItemType().ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the params of the message.
|
||||
/// This function will iterate over the list of params passed in and sequentially set the data items in the message starting at the data item at index 0
|
||||
/// </summary>
|
||||
/// <param name="messageParams">an array of params</param>
|
||||
public void SetParams(params object[] messageParams)
|
||||
{
|
||||
if (messageParams.Length > _dataItems.Count)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessage::SetParams() - number of supplied parameters: " + messageParams.Length.ToString() + ", is larger than the number of parameters in the definition file: " + _dataItems.Count.ToString());
|
||||
}
|
||||
|
||||
for (int i = 0; i < messageParams.Length; i++)
|
||||
{
|
||||
IConfigurableDataItem item = _dataItems[i];
|
||||
|
||||
object itemData = item.Data;
|
||||
|
||||
if (itemData is uint)
|
||||
{
|
||||
item.Data = Convert.ToUInt32(messageParams[i]);
|
||||
_dataItems[i] = item;
|
||||
}
|
||||
else if (itemData is float)
|
||||
{
|
||||
item.Data = Convert.ToDouble(messageParams[i]);
|
||||
_dataItems[i] = item;
|
||||
}
|
||||
else if (itemData is ushort)
|
||||
{
|
||||
item.Data = Convert.ToUInt16(messageParams[i]);
|
||||
_dataItems[i] = item;
|
||||
}
|
||||
else if (itemData is double)
|
||||
{
|
||||
item.Data = Convert.ToDouble(messageParams[i]);
|
||||
_dataItems[i] = item;
|
||||
}
|
||||
else if (itemData is ulong)
|
||||
{
|
||||
item.Data = Convert.ToUInt64(messageParams[i]);
|
||||
_dataItems[i] = item;
|
||||
}
|
||||
else if (itemData is byte)
|
||||
{
|
||||
item.Data = Convert.ToByte(messageParams[i]);
|
||||
_dataItems[i] = item;
|
||||
|
||||
// doesnt matter if it is of types BITs or not, the configurable data item already knows
|
||||
/*if (item.GetDataItemType() == DataItemType.BITS)
|
||||
{
|
||||
item.Data = Convert.ToByte(messageParams[i]);
|
||||
_dataItems[i] = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Data = Convert.ToByte(messageParams[i]);
|
||||
_dataItems[i] = item;
|
||||
}*/
|
||||
}
|
||||
else if (itemData is Array)
|
||||
{
|
||||
// convert object to byte array
|
||||
IEnumerable en = (IEnumerable)messageParams[i];
|
||||
byte[] data = en.OfType<byte>().ToArray();
|
||||
item.Data = data;
|
||||
_dataItems[i] = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("BitConfigurableMessage::SetParams() - unknown type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
string dataToReturn = "Description: " + _messageName + "\r\n";
|
||||
dataToReturn += "Payload Data:\r\n";
|
||||
|
||||
for (int i = 0; i < _dataItems.Count; i++)
|
||||
{
|
||||
IConfigurableDataItem dataItem = _dataItems[i];
|
||||
DataItemType itemType = dataItem.GetDataItemType();
|
||||
string itemName = dataItem.GetDataItemName();
|
||||
object itemValue = dataItem.Data;
|
||||
|
||||
if (itemValue is uint)
|
||||
{
|
||||
if (itemValue == null)
|
||||
{
|
||||
dataToReturn += " " + itemName + ":Not Set\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
uint data = (uint)itemValue;
|
||||
|
||||
dataToReturn += " " + itemName + ":" + "0x" + data.ToString("X8") + "\r\n";
|
||||
}
|
||||
}
|
||||
else if (itemValue is ushort)
|
||||
{
|
||||
if (itemValue == null)
|
||||
{
|
||||
dataToReturn += " " + itemName + ":Not Set\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ushort data = (ushort)itemValue;
|
||||
|
||||
dataToReturn += " " + itemName + ":" + "0x" + data.ToString("X4") + "\r\n";
|
||||
}
|
||||
}
|
||||
else if (itemValue is double)
|
||||
{
|
||||
if (itemValue == null)
|
||||
{
|
||||
dataToReturn += " " + itemName + ":Not Set\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
double data = (double)itemValue;
|
||||
|
||||
dataToReturn += " " + itemName + ":" + data + "\r\n";
|
||||
}
|
||||
}
|
||||
else if (itemValue is ulong)
|
||||
{
|
||||
if (itemValue == null)
|
||||
{
|
||||
dataToReturn += " " + itemName + ":Not Set\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ulong data = (ulong)itemValue;
|
||||
|
||||
dataToReturn += " " + itemName + ":" + data + "\r\n";
|
||||
}
|
||||
}
|
||||
else if (itemValue is byte)
|
||||
{
|
||||
if (itemValue == null)
|
||||
{
|
||||
dataToReturn += " " + itemName + ":Not Set\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (itemType == DataItemType.BITS)
|
||||
{
|
||||
byte data = (byte)itemValue;
|
||||
|
||||
string binString = Convert.ToString(data, 2).PadLeft(dataItem.GetNumDataItems(), '0');
|
||||
|
||||
dataToReturn += " " + itemName + ":" + "0b" + binString + "\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
byte data = (byte)itemValue;
|
||||
|
||||
dataToReturn += " " + itemName + ":" + "0x" + data.ToString("X2") + "\r\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (itemValue is Array)
|
||||
{
|
||||
string arrayDataStr = "";
|
||||
|
||||
if (itemValue == null)
|
||||
{
|
||||
arrayDataStr += " " + itemName + ":Not Set" + "\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
IEnumerable en = (IEnumerable)itemValue;
|
||||
byte[] arrayTemp = en.OfType<byte>().ToArray();
|
||||
StringBuilder hex = new StringBuilder(arrayTemp.Length * 2);
|
||||
foreach (byte b in arrayTemp)
|
||||
hex.AppendFormat("{0:x2}", b);
|
||||
|
||||
arrayDataStr += " " + itemName + ":" + hex.ToString() + "\r\n";
|
||||
}
|
||||
|
||||
dataToReturn += arrayDataStr;
|
||||
}
|
||||
else if (itemValue is float)
|
||||
{
|
||||
if (itemValue == null)
|
||||
{
|
||||
dataToReturn += " " + itemName + ":Not Set\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
float data = (float)itemValue;
|
||||
|
||||
dataToReturn += " " + itemName + ":" + data + "\r\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dataToReturn += " " + itemName + ":" + "UNKNOWN TYPE:" + itemType + "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
return dataToReturn + "\r\n";
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -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 System;
|
||||
|
||||
namespace BitMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TData"></typeparam>
|
||||
public class BitConfigurableMessageDataItem<TData> : IConfigurableDataItem<TData>
|
||||
{
|
||||
#region PublicClassMembers
|
||||
#endregion
|
||||
|
||||
#region PrivateClassMembers
|
||||
private string _dataItemName;
|
||||
private int _numItems;
|
||||
private string _defaultValueStr;
|
||||
private BitConfigurableMessage.DataItemType _dataItemType;
|
||||
#endregion
|
||||
|
||||
#region PublicFunctions
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dataItemName"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="dataValue"></param>
|
||||
public BitConfigurableMessageDataItem(string dataItemName, BitConfigurableMessage.DataItemType type, TData dataValue, string defaultValueStr, int numItems)
|
||||
{
|
||||
_dataItemName = dataItemName;
|
||||
_dataItemType = type;
|
||||
_defaultValueStr = defaultValueStr;
|
||||
_numItems = numItems;
|
||||
Data = dataValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public Type DataType
|
||||
{
|
||||
get { return typeof(TData); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
object IConfigurableDataItem.Data
|
||||
{
|
||||
get { return Data; }
|
||||
set { Data = (TData)value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public TData Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetDataItemName()
|
||||
{
|
||||
return _dataItemName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetDefaultValueStr()
|
||||
{
|
||||
return _defaultValueStr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public BitConfigurableMessage.DataItemType GetDataItemType()
|
||||
{
|
||||
return _dataItemType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetNumDataItems()
|
||||
{
|
||||
return _numItems;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
// 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;
|
||||
|
||||
namespace BitMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class creates BitConfigurableMessage objects
|
||||
/// </summary>
|
||||
internal class BitConfigurableMessageExcelFactory : BitConfigurableMessageFactory
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private Dictionary<uint, BitConfigurableMessage> _messageDictionary;
|
||||
#endregion
|
||||
|
||||
#region PrivateFuctions
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
public BitConfigurableMessageExcelFactory(string filename)
|
||||
{
|
||||
const int MIN_ROWS = 3;
|
||||
const int MIN_COLS = 4;
|
||||
|
||||
ExcelReader reader = null;
|
||||
|
||||
try
|
||||
{
|
||||
_messageDictionary = new Dictionary<uint, BitConfigurableMessage>();
|
||||
|
||||
reader = new ExcelReader(filename);
|
||||
|
||||
List<string> sheetNamesList = reader.ReadAllSheetNames();
|
||||
|
||||
foreach (string sheet in sheetNamesList)
|
||||
{
|
||||
// read the whole sheet and split on the lines
|
||||
string entireSheet = reader.ReadAllRows(sheet, 1, 1);
|
||||
string[] allRows = entireSheet.Split('\n');
|
||||
|
||||
// check that there is the min number of rows
|
||||
if (allRows.Length < MIN_ROWS)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageExcelFactory::BitConfigurableMessageExcelFactory() - Sheet ID: " + sheet + " does not have the min amount of rows: " + MIN_ROWS.ToString());
|
||||
}
|
||||
|
||||
// grab the first line where the command ID should be
|
||||
string messageIdLine = allRows[1];
|
||||
string[] messageIdLineTokens = messageIdLine.Split(',');
|
||||
|
||||
// check for the min number of columns
|
||||
if (messageIdLineTokens.Length < MIN_COLS)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageExcelFactory::BitConfigurableMessageExcelFactory() - Sheet ID: " + sheet + " line 1 does not have the min amount of Cols: " + MIN_COLS.ToString());
|
||||
}
|
||||
|
||||
// grab the message ID
|
||||
uint msgId = Convert.ToUInt32(messageIdLineTokens[3], 16);
|
||||
|
||||
// grab the line with the response msg ID
|
||||
string rspMessageIdLine = allRows[2];
|
||||
string[] rspMessageIdLineTokens = rspMessageIdLine.Split(',');
|
||||
|
||||
// check the number of cols
|
||||
if (rspMessageIdLineTokens.Length < MIN_COLS)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageExcelFactory::BitConfigurableMessageExcelFactory() - Sheet ID: " + sheet + " line 2 does not have the min amount of Cols: " + MIN_COLS.ToString());
|
||||
}
|
||||
|
||||
// grab the rsp msg ID
|
||||
uint rspMsgId = Convert.ToUInt32(rspMessageIdLineTokens[3], 16);
|
||||
|
||||
// create the message
|
||||
BitConfigurableMessage msg = new BitConfigurableMessage(msgId, rspMsgId, sheet);
|
||||
|
||||
// process the sheet to create the message object
|
||||
// we already processed the first two lines, start at 3
|
||||
for (int i = 3; i < allRows.Length; i++)
|
||||
{
|
||||
var line = allRows[i];
|
||||
var values = line.Split(',');
|
||||
|
||||
if (values.Length < MIN_COLS)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageExcelFactory::BitConfigurableMessageExcelFactory() - Sheet ID: " + msgId.ToString("X8") + " does not have all of the fields populated");
|
||||
}
|
||||
|
||||
string dataItemName = values[0].Trim().ToUpper();
|
||||
string fieldType = values[1].Trim().ToUpper();
|
||||
string numberOfItemsTemp = values[2].Trim().ToUpper();
|
||||
numberOfItemsTemp = numberOfItemsTemp.Replace(",", "");
|
||||
int numberOfItems = Convert.ToInt32(numberOfItemsTemp);
|
||||
string defaultValue = values[3].Trim().ToUpper();
|
||||
|
||||
BitConfigurableMessage.DataItemType dataType = BitConfigurableMessage.DataItemType.FLOAT;
|
||||
|
||||
if (fieldType == BitInterfaceManagerConstants.FLOAT_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.FLOAT;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.UINT_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.UINT;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.UINT_HEX_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.UINT_HEX;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.USHORT_HEX_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.USHORT_HEX;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.USHORT_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.USHORT;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.BYTE_HEX_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.BYTE_HEX;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.BYTE_ARRAY_HEX_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.BYTE_ARRAY_HEX;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.DOUBLE_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.DOUBLE;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.ULONG_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.ULONG;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.ULONG_HEX_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.ULONG_HEX;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.BITS_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.BITS;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageExcelFactory::BitConfigurableMessageExcelFactory() - Unknown type: " + values[1]);
|
||||
}
|
||||
|
||||
msg.AddDataItem(dataItemName, dataType, numberOfItems, defaultValue);
|
||||
}
|
||||
|
||||
_messageDictionary[msgId] = msg;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (reader != null)
|
||||
{
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="messageId"></param>
|
||||
/// <returns></returns>
|
||||
protected override BitConfigurableMessage CreateMessage(uint messageId)
|
||||
{
|
||||
if (_messageDictionary.ContainsKey(messageId) == false)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageExcelFactory:CreateMessage() - unknown ID: " + messageId.ToString("X8") + ", make sure this ID is defined in the definition ini file");
|
||||
}
|
||||
|
||||
return new BitConfigurableMessage(_messageDictionary[messageId]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override Dictionary<uint, BitConfigurableMessage> GetAllMessages()
|
||||
{
|
||||
return _messageDictionary;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
// 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 ExcelZipLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
namespace BitMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class creates BitConfigurableMessage objects
|
||||
/// </summary>
|
||||
internal class BitConfigurableMessageExcelZipFactory : BitConfigurableMessageFactory
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private Dictionary<uint, BitConfigurableMessage> _messageDictionary;
|
||||
#endregion
|
||||
|
||||
#region PrivateFuctions
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <param name="msgIds"></param>
|
||||
public BitConfigurableMessageExcelZipFactory(string filename)
|
||||
{
|
||||
const int MIN_ROWS = 3;
|
||||
const int MIN_COLS = 4;
|
||||
|
||||
try
|
||||
{
|
||||
_messageDictionary = new Dictionary<uint, BitConfigurableMessage>();
|
||||
|
||||
List<worksheet> allWorkSheets = Workbook.Worksheets(filename);
|
||||
|
||||
foreach (worksheet sheet in allWorkSheets)
|
||||
{
|
||||
string test = sheet.ToString();
|
||||
|
||||
// check that there is the min number of rows
|
||||
if (sheet.Rows.Count < MIN_ROWS)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageExcelZipFactory::BitConfigurableMessageExcelZipFactory() - Sheet ID: " + sheet + " does not have the min amount of rows: " + MIN_ROWS.ToString());
|
||||
}
|
||||
|
||||
// grab the command ID Row
|
||||
Row cmdIdRow = sheet.Rows[1];
|
||||
|
||||
if (cmdIdRow.Cells.Length < MIN_COLS)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageExcelZipFactory::BitConfigurableMessageExcelZipFactory() - Sheet ID: " + sheet + " line 1 does not have the min amount of Cols: " + MIN_COLS.ToString());
|
||||
}
|
||||
|
||||
string msgIdStr = cmdIdRow.Cells[3].Text.Trim().ToUpper();
|
||||
|
||||
uint msgId = Convert.ToUInt32(msgIdStr, 16);
|
||||
|
||||
// grab the rsp ID Row
|
||||
Row rspIdRow = sheet.Rows[2];
|
||||
|
||||
if (rspIdRow.Cells.Length < MIN_COLS)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageExcelZipFactory::BitConfigurableMessageExcelZipFactory() - Sheet ID: " + sheet + " line 1 does not have the min amount of Cols: " + MIN_COLS.ToString());
|
||||
}
|
||||
|
||||
string rspMsgIdStr = rspIdRow.Cells[3].Text.Trim().ToUpper();
|
||||
|
||||
// grab the rsp msg ID
|
||||
uint rspMsgId = Convert.ToUInt32(rspMsgIdStr, 16);
|
||||
|
||||
// create the message
|
||||
BitConfigurableMessage msg = new BitConfigurableMessage(msgId, rspMsgId, msgId.ToString("X8"));
|
||||
|
||||
//remove header, cmd ID and rsp ID rows from worksheet
|
||||
sheet.Rows.Remove(sheet.Rows[0]);
|
||||
sheet.Rows.Remove(sheet.Rows[0]);
|
||||
sheet.Rows.Remove(sheet.Rows[0]);
|
||||
|
||||
// process the sheet to create the message object
|
||||
// start at 1 to skip the file header
|
||||
foreach (Row row in sheet.Rows)
|
||||
{
|
||||
if (row.Cells.Length < MIN_COLS)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageExcelZipFactory::BitConfigurableMessageFactory() - Sheet ID: " + msgId.ToString("X8") + " does not have all of the fields populated");
|
||||
}
|
||||
|
||||
string dataItemName = row.Cells[0].Text.Trim().ToUpper();
|
||||
|
||||
string fieldType = row.Cells[1].Text.Trim().ToUpper();
|
||||
string numberOfItemsTemp = row.Cells[2].Text.Trim().ToUpper();
|
||||
numberOfItemsTemp = numberOfItemsTemp.Replace(",", "");
|
||||
int numberOfItems = Convert.ToInt32(numberOfItemsTemp);
|
||||
string defaultValue = row.Cells[3].Text.Trim().ToUpper();
|
||||
|
||||
BitConfigurableMessage.DataItemType dataType = BitConfigurableMessage.DataItemType.FLOAT;
|
||||
|
||||
if (fieldType == BitInterfaceManagerConstants.FLOAT_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.FLOAT;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.UINT_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.UINT;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.UINT_HEX_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.UINT_HEX;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.USHORT_HEX_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.USHORT_HEX;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.USHORT_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.USHORT;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.BYTE_HEX_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.BYTE_HEX;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.BYTE_ARRAY_HEX_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.BYTE_ARRAY_HEX;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.DOUBLE_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.DOUBLE;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.ULONG_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.ULONG;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.ULONG_HEX_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.ULONG_HEX;
|
||||
}
|
||||
else if (fieldType == BitInterfaceManagerConstants.BITS_DATA_TYPE.ToUpper())
|
||||
{
|
||||
dataType = BitConfigurableMessage.DataItemType.BITS;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageExcelZipFactory::BitConfigurableMessageExcelZipFactory() - Unknown type: " + row.FilledCells[0].ToString());
|
||||
}
|
||||
|
||||
msg.AddDataItem(dataItemName, dataType, numberOfItems, defaultValue);
|
||||
}
|
||||
|
||||
// hold onto the message object
|
||||
_messageDictionary[msgId] = msg;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="messageId"></param>
|
||||
/// <returns></returns>
|
||||
protected override BitConfigurableMessage CreateMessage(uint messageId)
|
||||
{
|
||||
if (_messageDictionary.ContainsKey(messageId) == false)
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageExcelZipFactory:CreateMessage() - unknown ID: " + messageId.ToString("X8") + ", make sure this ID is defined in the definition ini file");
|
||||
}
|
||||
|
||||
return new BitConfigurableMessage(_messageDictionary[messageId]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override Dictionary<uint, BitConfigurableMessage> GetAllMessages()
|
||||
{
|
||||
return _messageDictionary;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// 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;
|
||||
|
||||
namespace BitMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class creates BitConfigurableMessage objects
|
||||
/// </summary>
|
||||
internal abstract class BitConfigurableMessageFactory
|
||||
{
|
||||
internal enum FactoryType
|
||||
{
|
||||
EXCEL,
|
||||
EXCEL_ZIP
|
||||
};
|
||||
|
||||
private static BitConfigurableMessageFactory _bitFactoryInstance;
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
public static BitConfigurableMessageFactory Instance(string inputFileName = "", FactoryType type = FactoryType.EXCEL_ZIP)
|
||||
{
|
||||
if (_bitFactoryInstance == null)
|
||||
{
|
||||
if (type == FactoryType.EXCEL)
|
||||
{
|
||||
_bitFactoryInstance = new BitConfigurableMessageExcelFactory(inputFileName);
|
||||
}
|
||||
else if (type == FactoryType.EXCEL_ZIP)
|
||||
{
|
||||
_bitFactoryInstance = new BitConfigurableMessageExcelZipFactory(inputFileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageFactory::Instance() - unsupport input type: " + type.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return _bitFactoryInstance;
|
||||
}
|
||||
|
||||
protected abstract Dictionary<uint, BitConfigurableMessage> GetAllMessages();
|
||||
|
||||
protected abstract BitConfigurableMessage CreateMessage(uint messageId);
|
||||
|
||||
public Dictionary<uint, BitConfigurableMessage> RetreiveAllMessages()
|
||||
{
|
||||
return _bitFactoryInstance.GetAllMessages();
|
||||
}
|
||||
|
||||
public BitConfigurableMessage RetreiveMessage(uint messageId)
|
||||
{
|
||||
return _bitFactoryInstance.CreateMessage(messageId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -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.Common;
|
||||
using System;
|
||||
|
||||
namespace BitMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class implements a message header that is used by the BitConfigurableMessage
|
||||
/// </summary>
|
||||
public static class BitConfigurableMessageHeader
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
|
||||
#endregion
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="pData"></param>
|
||||
/// <returns></returns>
|
||||
public static uint GetMessageId(IntPtr pData, uint numBytesInPdata)
|
||||
{
|
||||
return GetCmdMessageId(pData, numBytesInPdata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="pData"></param>
|
||||
/// <param name="isSecondaryIdUsed"></param>
|
||||
/// <returns></returns>
|
||||
public static uint GetSecondaryMessageId(IntPtr pData, uint numBytesInPdata, out bool isSecondaryIdUsed)
|
||||
{
|
||||
return GetSecondaryCmdMessageId(pData, numBytesInPdata, out isSecondaryIdUsed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="pData"></param>
|
||||
/// <param name="isSecondaryIdUsed"></param>
|
||||
/// <returns></returns>
|
||||
private static uint GetSecondaryCmdMessageId(IntPtr pData, uint numBytesInPdata, out bool isSecondaryIdUsed)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
isSecondaryIdUsed = false;
|
||||
|
||||
bool shallWeSwap = BitMsgEndianControl.Instance().ShallWeSwap();
|
||||
|
||||
BitMsgEndianControl.HeaderDef headerDef = BitMsgEndianControl.Instance().GetHeaderDef();
|
||||
|
||||
// is there enough data?
|
||||
if (numBytesInPdata <= headerDef.secondaryMsgIdByteLocation + headerDef.secondaryMsgIdDataLen)
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitConfigurableMessageHeader::GetSecondaryCmdMessageId() - not enough data form a header. Buffer contained " + Convert.ToString(numBytesInPdata) + " bytes, needed " + (headerDef.secondaryMsgIdByteLocation + headerDef.secondaryMsgIdDataLen).ToString() + " for a header", ErrorLogger.LogLevel.INFO);
|
||||
throw new Exception("BitConfigurableMessageHeader::GetSecondaryCmdMessageId() - not enough data form a header. Buffer contained " + Convert.ToString(numBytesInPdata) + " bytes, needed " + (headerDef.secondaryMsgIdByteLocation + headerDef.secondaryMsgIdDataLen).ToString() + " for a header");
|
||||
}
|
||||
|
||||
if (headerDef.secondaryMsgIdByteLocation == 0)
|
||||
{
|
||||
isSecondaryIdUsed = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
isSecondaryIdUsed = true;
|
||||
|
||||
uint cmdId = 0;
|
||||
|
||||
if (headerDef.secondaryMsgIdDataLen == 1)
|
||||
{
|
||||
byte* pCmdIdBytePtr = (byte*)pData.ToPointer() + headerDef.secondaryMsgIdByteLocation;
|
||||
|
||||
cmdId = pCmdIdBytePtr[0];
|
||||
}
|
||||
else if (headerDef.secondaryMsgIdDataLen == 2)
|
||||
{
|
||||
ushort* pCmdIdUshortPtr = (ushort*)pData.ToPointer() + headerDef.secondaryMsgIdByteLocation;
|
||||
|
||||
ushort cmdIdTemp = (ushort)pCmdIdUshortPtr[0];
|
||||
|
||||
if (shallWeSwap == true)
|
||||
{
|
||||
cmdIdTemp = Util.Swap(cmdIdTemp);
|
||||
}
|
||||
|
||||
cmdId = cmdIdTemp;
|
||||
}
|
||||
else if (headerDef.secondaryMsgIdDataLen == 4)
|
||||
{
|
||||
uint* pCmdIdUInttPtr = (uint*)pData.ToPointer() + headerDef.secondaryMsgIdByteLocation;
|
||||
|
||||
cmdId = (uint)pCmdIdUInttPtr[0];
|
||||
|
||||
if (shallWeSwap == true)
|
||||
{
|
||||
cmdId = Util.Swap(cmdId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageHeader::GetSecondaryCmdMessageId() - unhandled Cmd ID data length: " + headerDef.msgIdDataLen);
|
||||
}
|
||||
|
||||
return cmdId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// getter for the message id
|
||||
/// </summary>
|
||||
/// <returns>The id</returns>
|
||||
private static uint GetCmdMessageId(IntPtr pData, uint numBytesInPdata)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
bool shallWeSwap = BitMsgEndianControl.Instance().ShallWeSwap();
|
||||
|
||||
BitMsgEndianControl.HeaderDef headerDef = BitMsgEndianControl.Instance().GetHeaderDef();
|
||||
|
||||
// is there enough data?
|
||||
if (numBytesInPdata <= headerDef.msgIdByteLocation + headerDef.msgIdDataLen)
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitConfigurableMessageHeader::GetCmdMessageId() - not enough data form a header. Buffer contained " + Convert.ToString(numBytesInPdata) + " bytes, needed " + (headerDef.msgIdByteLocation + headerDef.msgIdDataLen).ToString() + " for a header", ErrorLogger.LogLevel.INFO);
|
||||
throw new Exception("BitConfigurableMessageHeader::GetCmdMessageId() - not enough data form a header. Buffer contained " + Convert.ToString(numBytesInPdata) + " bytes, needed " + (headerDef.msgIdByteLocation + headerDef.msgIdDataLen).ToString() + " for a header");
|
||||
}
|
||||
|
||||
uint cmdId = 0;
|
||||
|
||||
if (headerDef.msgIdDataLen == 1)
|
||||
{
|
||||
byte* pCmdIdBytePtr = (byte*)pData.ToPointer() + headerDef.msgIdByteLocation;
|
||||
|
||||
cmdId = pCmdIdBytePtr[0];
|
||||
}
|
||||
else if (headerDef.msgIdDataLen == 2)
|
||||
{
|
||||
ushort* pCmdIdUshortPtr = (ushort*)pData.ToPointer() + headerDef.msgIdByteLocation;
|
||||
|
||||
ushort cmdIdTemp = (ushort)pCmdIdUshortPtr[0];
|
||||
|
||||
if (shallWeSwap == true)
|
||||
{
|
||||
cmdIdTemp = Util.Swap(cmdIdTemp);
|
||||
}
|
||||
|
||||
cmdId = cmdIdTemp;
|
||||
}
|
||||
else if (headerDef.msgIdDataLen == 4)
|
||||
{
|
||||
uint* pCmdIdUInttPtr = (uint*)pData.ToPointer() + headerDef.msgIdByteLocation;
|
||||
|
||||
cmdId = (uint)pCmdIdUInttPtr[0];
|
||||
|
||||
if (shallWeSwap == true)
|
||||
{
|
||||
cmdId = Util.Swap(cmdId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("BitConfigurableMessageHeader::GetCmdMessageId() - unhandled Cmd ID data length: " + headerDef.msgIdDataLen);
|
||||
}
|
||||
|
||||
return cmdId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Getter for the header length
|
||||
/// The Header is considered to be all of the data up to the message ID
|
||||
/// </summary>
|
||||
/// <returns>The header length in bytes. The head Length is the number of bytes from the beginning of the message through the message ID</returns>
|
||||
public static uint GetHeaderSize()
|
||||
{
|
||||
BitMsgEndianControl.HeaderDef headerDef = BitMsgEndianControl.Instance().GetHeaderDef();
|
||||
|
||||
int idSize = headerDef.msgIdByteLocation + headerDef.msgIdDataLen;
|
||||
|
||||
return (uint)idSize;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
// 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;
|
||||
|
||||
namespace BitMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal class BitMessageIDs
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private Dictionary<uint, uint> _idToSizeMap;
|
||||
private Dictionary<uint, uint> _cmdIdToRspIdMap;
|
||||
private List<uint> _msgIds;
|
||||
#endregion
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal BitMessageIDs()
|
||||
{
|
||||
_idToSizeMap = new Dictionary<uint, uint>();
|
||||
_cmdIdToRspIdMap = new Dictionary<uint, uint>();
|
||||
_msgIds = new List<uint>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="messageId"></param>
|
||||
internal void AddId(uint messageId)
|
||||
{
|
||||
_idToSizeMap.Add(messageId, 0);
|
||||
_msgIds.Add(messageId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
internal bool ContainsId(uint id)
|
||||
{
|
||||
return _idToSizeMap.ContainsKey(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal List<uint> GetAllIds()
|
||||
{
|
||||
return _msgIds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="cmdId"></param>
|
||||
/// <returns></returns>
|
||||
internal uint GetResponseId(uint cmdId)
|
||||
{
|
||||
if (_cmdIdToRspIdMap.ContainsKey(cmdId) == false)
|
||||
{
|
||||
throw new Exception("BitMessageIDs::GetResponseId() - cmdIdToRspIdMap does not contains messageId: " + cmdId.ToString("X8"));
|
||||
}
|
||||
|
||||
return _cmdIdToRspIdMap[cmdId];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
internal uint GetSize(uint id)
|
||||
{
|
||||
if (_idToSizeMap.ContainsKey(id) == false)
|
||||
{
|
||||
throw new Exception("BitMessageIDs::GetSize() - _idToSizeMap does not contais messageId: " + id.ToString("X8"));
|
||||
}
|
||||
|
||||
return _idToSizeMap[id];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="cmdId"></param>
|
||||
/// <returns></returns>
|
||||
internal bool IsThereAResponseMessage(uint cmdId)
|
||||
{
|
||||
if (_cmdIdToRspIdMap.ContainsKey(cmdId) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="msgId"></param>
|
||||
/// <param name="numBytes"></param>
|
||||
internal void SetMsgSize(uint msgId, uint numBytes)
|
||||
{
|
||||
_idToSizeMap[msgId] = numBytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="cmdId"></param>
|
||||
/// <param name="rspId"></param>
|
||||
internal void SetRspId(uint cmdId, uint rspId)
|
||||
{
|
||||
_cmdIdToRspIdMap[cmdId] = rspId;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,389 @@
|
||||
// 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 Raytheon.Common;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BitMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles received messages from the UUT
|
||||
/// </summary>
|
||||
internal class BitMsgHandler : MsgDevice
|
||||
{
|
||||
#region PublicClassMembers
|
||||
public enum ErrorCodes
|
||||
{
|
||||
NO_ERROR = 0,
|
||||
UNKNOWN_MSG_ID = 1
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region PrivateClassMembers
|
||||
private static object _syncObj = new Object();
|
||||
private BinaryWriter _binWriter;
|
||||
private StreamWriter _asciiWriter;
|
||||
private MeasurementManagerLib.BitMeasurementManager.MessageReceivedDelegate _callback;
|
||||
private SortedDictionary<uint, bool> _callbackControl;
|
||||
private readonly BitMessageIDs _messageIds;
|
||||
private readonly bool _shallWeLogOutgoingBinData;
|
||||
private readonly bool _shallWeLogOutgoingAsciiData;
|
||||
private readonly bool _shallWeLogIncomingBinData;
|
||||
private readonly bool _shallWeLogIncomingAsciiData;
|
||||
private readonly uint _bitmask;
|
||||
private readonly string _crcFieldName;
|
||||
#endregion
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
/// The constructor
|
||||
/// </summary>
|
||||
/// <param name="callback">Host callback for received messages</param>
|
||||
/// <param name="bufferSize">The size of the internal parsing buffer</param>
|
||||
/// <param name="binLogFileName">THe binary file log name</param>
|
||||
/// <param name="asciiLogFileName">The ascii file log name</param>
|
||||
/// <param name="shallWeLogOutgoingBinData"></param>
|
||||
/// <param name="shallWeLogOutgoingAsciiData"></param>
|
||||
/// <param name="shallWeLogIncomingBinData"></param>
|
||||
/// <param name="shallWeLogIncomingAsciiData"></param>
|
||||
unsafe public BitMsgHandler(BitMessageIDs messageIds, MeasurementManagerLib.BitMeasurementManager.MessageReceivedDelegate callback, uint bufferSize, string binLogFileName, string asciiLogFileName, bool shallWeLogOutgoingBinData, bool shallWeLogOutgoingAsciiData, bool shallWeLogIncomingBinData, bool shallWeLogIncomingAsciiData, uint crcBitmask, string crcFieldName, bool shallWePerformVerboseParserLogging)
|
||||
: base(new BitMsgParser(messageIds, shallWePerformVerboseParserLogging), bufferSize)
|
||||
{
|
||||
_messageIds = messageIds;
|
||||
|
||||
// hold onto the callback
|
||||
_callback = callback;
|
||||
|
||||
_shallWeLogOutgoingBinData = shallWeLogOutgoingBinData;
|
||||
_shallWeLogOutgoingAsciiData = shallWeLogOutgoingAsciiData;
|
||||
_shallWeLogIncomingBinData = shallWeLogIncomingBinData;
|
||||
_shallWeLogIncomingAsciiData = shallWeLogIncomingAsciiData;
|
||||
|
||||
_bitmask = crcBitmask;
|
||||
_crcFieldName = crcFieldName;
|
||||
|
||||
// set all messages to not issue a callback. Host can change it as necessary
|
||||
_callbackControl = new SortedDictionary<uint, bool>();
|
||||
List<uint> msgIds = messageIds.GetAllIds();
|
||||
|
||||
foreach (uint id in msgIds)
|
||||
{
|
||||
_callbackControl[id] = false;
|
||||
}
|
||||
|
||||
_binWriter = null;
|
||||
|
||||
_asciiWriter = null;
|
||||
|
||||
SetLogFileNames(binLogFileName, asciiLogFileName);
|
||||
|
||||
// set the callback
|
||||
base.SetCompleteMessageCallback(this.OnCompleteMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The finalizer
|
||||
/// </summary>
|
||||
~BitMsgHandler()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add data to the buffer. For this Handler, we are just going to log out the data
|
||||
/// </summary>
|
||||
/// <param name="data">The data to add</param>
|
||||
/// <param name="numBytes">The number of bytes in the data buffer</param>
|
||||
public override void AddData(byte[] data, uint numBytes)
|
||||
{
|
||||
// log out raw data and add to buffer for processing
|
||||
lock (_syncObj)
|
||||
{
|
||||
WriteIncomingDataToLog(data, (int)numBytes);
|
||||
|
||||
AddToBuffer(data, numBytes);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all data from the buffer. We are just logging out data, no buffer to clear
|
||||
/// </summary>
|
||||
public void ClearData()
|
||||
{
|
||||
ClearBuffer();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void CloseDataFiles()
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (_binWriter != null)
|
||||
{
|
||||
_binWriter.Close();
|
||||
_binWriter.Dispose();
|
||||
_binWriter = null;
|
||||
}
|
||||
|
||||
if (_asciiWriter != null)
|
||||
{
|
||||
_asciiWriter.Close();
|
||||
_asciiWriter.Dispose();
|
||||
_asciiWriter = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The callback function for when a complete message is received. We are just logging out data, no messages to handle.
|
||||
/// </summary>
|
||||
/// <param name="msgId">The id of the message received</param>
|
||||
/// <param name="pData">The data for the message received</param>
|
||||
/// <param name="numBytes">the number of bytes in pData</param>
|
||||
/// <param name="errorCode">The parser error code</param>
|
||||
unsafe public void OnCompleteMessage(uint msgId, IntPtr pData, uint numBytes, uint errorCode)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_messageIds.ContainsId(msgId) == false)
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitMsgHandler::OnCompleteMessage() - detected unknown msg id: " + msgId.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
// create the msg and parse it
|
||||
BitConfigurableMessage msg = BitConfigurableMessageFactory.Instance().RetreiveMessage(msgId);
|
||||
msg.Parse(pData);
|
||||
|
||||
int callbackValue = 0;
|
||||
|
||||
// check for crc errors
|
||||
if (_bitmask != 0x00000000)
|
||||
{
|
||||
uint rawStatus = msg.GetDataItemByName<uint>(_crcFieldName);
|
||||
var maskedStatus = rawStatus & _bitmask;
|
||||
|
||||
if (maskedStatus != 0)
|
||||
{
|
||||
ErrorLogger.Instance().Write($"Message Status register indicates that a CRC error may have occurred. Raw status read: 0x{rawStatus:X8}. Masked status value: 0x{maskedStatus:X8}");
|
||||
callbackValue = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// get the ascii msg
|
||||
string asciiMessage = msg.ToString();
|
||||
|
||||
// log it
|
||||
WriteIncomingDataToLog(asciiMessage);
|
||||
|
||||
// add the message to the buffer in case the host wants it
|
||||
BitMsgRxBuffer.Instance().AddMsg(msg, false);
|
||||
|
||||
// issue callback if requested
|
||||
uint id = msg.GetMessageId();
|
||||
|
||||
if (_callbackControl[id] == true)
|
||||
{
|
||||
_callback(id, msg.GetEntireMsgLength(), callbackValue);
|
||||
}
|
||||
|
||||
// some debugging
|
||||
ErrorLogger.Instance().Write("BitMsgHandler::HandleMsg() - added message " + msgId.ToString("X8") + " to buffer ", ErrorLogger.LogLevel.INFO);
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
//@@@ need to flow error to the host
|
||||
ErrorLogger.Instance().Write("BitMsgHandler::HandleMsg() - caught an error: " + err.Message, ErrorLogger.LogLevel.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribe a callback to a specific msg
|
||||
/// </summary>
|
||||
/// <param name="msgId">The msg to subscribe to</param>
|
||||
/// <param name="shallWeIssueCallback">true to get the callbacks, false to not get them</param>
|
||||
public void SetCallbackControl(uint msgId, bool shallWeIssueCallback)
|
||||
{
|
||||
_callbackControl[msgId] = shallWeIssueCallback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the data file log names. Closes the previous file and opens a new one
|
||||
/// </summary>
|
||||
/// <param name="binLogFileName">The binary file log name</param>
|
||||
/// <param name="asciiLogFileName">The ascii file log name</param>
|
||||
public void SetLogFileNames(string binFileName, string asciiFileName)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (_binWriter != null)
|
||||
{
|
||||
_binWriter.Close();
|
||||
}
|
||||
|
||||
_binWriter = new BinaryWriter(File.Open(binFileName, FileMode.Create));
|
||||
|
||||
if (_asciiWriter != null)
|
||||
{
|
||||
_asciiWriter.Close();
|
||||
}
|
||||
|
||||
_asciiWriter = new StreamWriter(File.Open(asciiFileName, FileMode.Create));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the message handler
|
||||
/// </summary>
|
||||
public void QuitHandler()
|
||||
{
|
||||
base.QuitThread();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write bin data to a file
|
||||
/// </summary>
|
||||
/// <param name="data">The data to write</param>
|
||||
/// <param name="numBytes">The number of bytes to write</param>
|
||||
public void WriteIncomingDataToLog(byte[] data, int numBytes)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (_binWriter == null && _shallWeLogIncomingBinData == true)
|
||||
{
|
||||
throw new Exception("BitMsgHandler::WriteIncomingDataToLog() - Trying to log bin data before the log file is open");
|
||||
}
|
||||
else if (_shallWeLogIncomingBinData == true)
|
||||
{
|
||||
// write the data out and flush it for immediate viewing
|
||||
_binWriter.Write(data, 0, (int)numBytes);
|
||||
_binWriter.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write ascii data to a log file. Prepends a timestamp to the data
|
||||
/// </summary>
|
||||
/// <param name="data">The data to write</param>
|
||||
public void WriteIncomingDataToLog(string data)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (_asciiWriter == null && _shallWeLogIncomingAsciiData == true)
|
||||
{
|
||||
throw new Exception("BitMsgHandler::WriteIncomingDataToLog() - Trying to log ascii data before the log file is open");
|
||||
}
|
||||
else if (_shallWeLogIncomingAsciiData == true)
|
||||
{
|
||||
string timestamp = "Time: " + Util.GetTimeString();
|
||||
|
||||
string dataToLog = timestamp + "\r\n" + data;
|
||||
|
||||
_asciiWriter.WriteLine(dataToLog);
|
||||
|
||||
_asciiWriter.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write bin data to a file
|
||||
/// </summary>
|
||||
/// <param name="data">The data to write</param>
|
||||
/// <param name="numBytes">The number of bytes to write</param>
|
||||
public void WriteOutgoingDataToLog(byte[] data, int numBytes)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (_binWriter == null && _shallWeLogOutgoingBinData == true)
|
||||
{
|
||||
throw new Exception("BitMsgHandler::WriteOutgoingDataToLog() - Trying to log bin data before the log file is open");
|
||||
}
|
||||
else if (_shallWeLogOutgoingBinData == true)
|
||||
{
|
||||
_binWriter.Write(data, 0, numBytes);
|
||||
|
||||
_binWriter.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write ascii data to a log file. Prepends a timestamp to the data
|
||||
/// </summary>
|
||||
/// <param name="data">The data to write</param>
|
||||
public void WriteOutgoingDataToLog(string data)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (_asciiWriter == null && _shallWeLogOutgoingAsciiData == true)
|
||||
{
|
||||
throw new Exception("BitMsgHandler::WriteOutgoingDataToLog() - Trying to log ascii data before the log file is open");
|
||||
}
|
||||
else if (_shallWeLogOutgoingAsciiData == true)
|
||||
{
|
||||
string timestamp = "Time: " + Util.GetTimeString();
|
||||
|
||||
string dataToLog = timestamp + "\r\n" + data;
|
||||
|
||||
_asciiWriter.WriteLine(dataToLog);
|
||||
|
||||
_asciiWriter.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
// call the parent dispose first
|
||||
base.Dispose(disposing);
|
||||
|
||||
// now dispose of our resources
|
||||
if (_binWriter != null)
|
||||
{
|
||||
_binWriter.Dispose();
|
||||
}
|
||||
|
||||
if (_asciiWriter != null)
|
||||
{
|
||||
_asciiWriter.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
// 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;
|
||||
|
||||
namespace BitMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Parses out messages that go between the VRSUI and the Test Controller
|
||||
/// This class is meant to be used by both the test controller and the VRSUI, so it parses out messages that target either of those systems
|
||||
/// </summary>
|
||||
internal class BitMsgParser : IMsgParser
|
||||
{
|
||||
#region PublicClassMembers
|
||||
|
||||
#endregion
|
||||
|
||||
#region PrivateClassMembers
|
||||
private readonly BitMessageIDs _messageIdToSizeMap;
|
||||
private BitMsgEndianControl.HeaderDef _headerDef;
|
||||
private readonly bool _shallWePerformVerboseParserLogging;
|
||||
#endregion
|
||||
|
||||
#region PrivateFuctions
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="pData"></param>
|
||||
/// <param name="numBytesInPdata"></param>
|
||||
/// <param name="bytesToRemove"></param>
|
||||
/// <param name="messageId"></param>
|
||||
/// <param name="errorCode"></param>
|
||||
/// <returns></returns>
|
||||
private bool HandleData(IntPtr pData, uint numBytesInPdata, ref uint bytesToRemove, ref uint messageId, ref uint errorCode)
|
||||
{
|
||||
// check to see if we have enough data for at least a standard header
|
||||
uint payloadHeaderSize = BitConfigurableMessageHeader.GetHeaderSize();
|
||||
|
||||
if (numBytesInPdata < payloadHeaderSize)
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitMsgParser::HandleData() - not enough data in the buffer to form a header. Buffer contained " + Convert.ToString(numBytesInPdata) + " bytes, needed " + payloadHeaderSize.ToString() + " for a header", ErrorLogger.LogLevel.INFO);
|
||||
bytesToRemove = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint id = BitConfigurableMessageHeader.GetMessageId(pData, numBytesInPdata);
|
||||
bool isSecondaryIdUsed = false;
|
||||
uint secondaryId = BitConfigurableMessageHeader.GetSecondaryMessageId(pData, numBytesInPdata, out isSecondaryIdUsed);
|
||||
|
||||
// check that this is an expected message
|
||||
if (_messageIdToSizeMap.ContainsId(id) == false)
|
||||
{
|
||||
uint numBytesToRemove = Resync(pData, numBytesInPdata);
|
||||
string msg = "BitMsgParser::HandleData() - unknown id received: " + id.ToString("X8") + " When resyncing threw away " + numBytesToRemove.ToString() + " Bytes";
|
||||
ErrorLogger.Instance().Write(msg, ErrorLogger.LogLevel.ERROR);
|
||||
bytesToRemove = numBytesToRemove;
|
||||
return false;
|
||||
}
|
||||
|
||||
// look at secondary ID if applicable
|
||||
if (isSecondaryIdUsed == true)
|
||||
{
|
||||
if (secondaryId != _headerDef.secondaryMsgIdExpectedValue)
|
||||
{
|
||||
uint numBytesToRemove = Resync(pData, numBytesInPdata);
|
||||
string msg = "BitMsgParser::HandleData() - detected seondary ID: " + secondaryId.ToString("X8") + " was not as expected: " + _headerDef.secondaryMsgIdExpectedValue.ToString("X8") + " When resyncing threw away " + numBytesToRemove.ToString() + " Bytes";
|
||||
ErrorLogger.Instance().Write(msg, ErrorLogger.LogLevel.ERROR);
|
||||
bytesToRemove = numBytesToRemove;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint msgSize = _messageIdToSizeMap.GetSize(id);
|
||||
|
||||
// do we have enough data to make the complete message
|
||||
if (numBytesInPdata < msgSize)
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitMsgParser::HandleData() - not enough data in the buffer to form a entire message. Buffer contained " + Convert.ToString(numBytesInPdata) + " bytes, expected msg size is: " + msgSize.ToString(), ErrorLogger.LogLevel.INFO);
|
||||
// need to wait for more data
|
||||
bytesToRemove = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// everything has checked out, set the return params
|
||||
bytesToRemove = msgSize;
|
||||
|
||||
if (_shallWePerformVerboseParserLogging == true)
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitMsgParser::HandleData() - found msg: " + id.ToString() + " which has " + msgSize.ToString() + " bytes", ErrorLogger.LogLevel.INFO);
|
||||
}
|
||||
|
||||
messageId = id;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="pData"></param>
|
||||
/// <param name="numBytesInPdata"></param>
|
||||
/// <returns>The number of bytes to remove from the buffer</returns>
|
||||
private uint Resync(IntPtr pData, uint numBytesInPdata)
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitMsgParser::Resync() - Begin", ErrorLogger.LogLevel.INFO);
|
||||
|
||||
// increment pData by 1
|
||||
pData = IntPtr.Add(pData, 1);
|
||||
|
||||
// keep track of how many bytes to remove
|
||||
uint bytesToRemove = 1;
|
||||
|
||||
// update bytes remaining
|
||||
numBytesInPdata = numBytesInPdata - 1;
|
||||
|
||||
bool didWeFindMsg = false;
|
||||
|
||||
while (didWeFindMsg == false)
|
||||
{
|
||||
// check to see if we have enough data for at least a standard header
|
||||
uint payloadHeaderSize = BitConfigurableMessageHeader.GetHeaderSize();
|
||||
|
||||
if (numBytesInPdata < payloadHeaderSize)
|
||||
{
|
||||
ErrorLogger.Instance().Write("BitMsgParser::Resync() - not enough data in the buffer to form a header. Buffer contained " + Convert.ToString(numBytesInPdata) + " bytes, needed " + payloadHeaderSize.ToString() + " for a header. Removing " + bytesToRemove.ToString() + " bytes", ErrorLogger.LogLevel.INFO);
|
||||
break;
|
||||
}
|
||||
|
||||
uint id = BitConfigurableMessageHeader.GetMessageId(pData, numBytesInPdata);
|
||||
bool isSecondaryIdUsed = false;
|
||||
uint secondaryId = BitConfigurableMessageHeader.GetSecondaryMessageId(pData, numBytesInPdata, out isSecondaryIdUsed);
|
||||
|
||||
// check that this is an expected message
|
||||
if (_messageIdToSizeMap.ContainsId(id) == false)
|
||||
{
|
||||
// need to keep looking
|
||||
// increment pData by 1
|
||||
pData = IntPtr.Add(pData, 1);
|
||||
|
||||
// keep track of how many bytes to remove
|
||||
bytesToRemove++;
|
||||
|
||||
// update bytes remaining
|
||||
numBytesInPdata--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// look at secondary ID if applicable
|
||||
if (isSecondaryIdUsed == true)
|
||||
{
|
||||
if (secondaryId != _headerDef.secondaryMsgIdExpectedValue)
|
||||
{
|
||||
// need to keep looking
|
||||
// increment pData by 1
|
||||
pData = IntPtr.Add(pData, 1);
|
||||
|
||||
// keep track of how many bytes to remove
|
||||
bytesToRemove++;
|
||||
|
||||
// update bytes remaining
|
||||
numBytesInPdata--;
|
||||
}
|
||||
else
|
||||
{
|
||||
didWeFindMsg = true;
|
||||
ErrorLogger.Instance().Write("BitMsgParser::Resync() - Detected message ID: " + id.ToString("X8") + ". Detected Secondary ID: " + secondaryId.ToString("X8") + " Resync complete. Removing " + bytesToRemove.ToString() + " Bytes", ErrorLogger.LogLevel.INFO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
didWeFindMsg = true;
|
||||
ErrorLogger.Instance().Write("BitMsgParser::Resync() - Detected message ID: " + id.ToString("X8") + ". Resync complete. Removing " + bytesToRemove.ToString() + " Bytes", ErrorLogger.LogLevel.INFO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ErrorLogger.Instance().Write("BitMsgParser::Resync() - returning " + bytesToRemove.ToString(), ErrorLogger.LogLevel.INFO);
|
||||
|
||||
return bytesToRemove;
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="messageIds"></param>
|
||||
/// <param name="shallWePerformVerboseParserLogging"></param>
|
||||
public BitMsgParser(BitMessageIDs messageIds, bool shallWePerformVerboseParserLogging)
|
||||
{
|
||||
// Using it to hold onto valid message ids and the size
|
||||
_messageIdToSizeMap = messageIds;
|
||||
_shallWePerformVerboseParserLogging = shallWePerformVerboseParserLogging;
|
||||
_headerDef = BitMsgEndianControl.Instance().GetHeaderDef();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Search the data buffer for the next valid message
|
||||
/// </summary>
|
||||
/// <param name="pData">The data buffer to search</param>
|
||||
/// <param name="numBytesInPdata">The number of bytes in pData</param>
|
||||
/// <param name="bytesToRemove">The number of bytes to remove from the buffer</param>
|
||||
/// <param name="messageId">The message id of the message that was found</param>
|
||||
/// <returns>true if a message was found, false otherwise</returns>
|
||||
public bool Run(IntPtr pData, uint numBytesInPdata, ref uint bytesToRemove, ref uint messageId, ref uint errorCode)
|
||||
{
|
||||
// default error code to 0;
|
||||
errorCode = 0;
|
||||
|
||||
return HandleData(pData, numBytesInPdata, ref bytesToRemove, ref messageId, ref errorCode);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,498 @@
|
||||
// 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;
|
||||
using Raytheon.Common;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using ChillerCartMeasurementManagerLib;
|
||||
using NLog;
|
||||
|
||||
namespace MeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class manages chiller instruments and provides an abstraction
|
||||
/// </summary>
|
||||
public class ChillerCartMeasurementManager : IDisposable
|
||||
{
|
||||
#region PublicMembers
|
||||
public delegate void ChillerDelegate(double temperature, double coolantSetpoint, int errorCode);
|
||||
public delegate void FlowMeterDelegate(double flow, int errorCode);
|
||||
public delegate void TemperatureDelegate(double temperature, int errorCode);
|
||||
#endregion
|
||||
|
||||
#region PrivateMembers
|
||||
private readonly IChiller _chiller;
|
||||
private readonly IFlowMeter _flowMeter;
|
||||
private readonly ITempMonitor _tempMonitor;
|
||||
private ChillerDataLogWorker _chillerDataLogWorker;
|
||||
private Thread _chillerDataLogThread;
|
||||
private FlowMeterDataLogWorker _flowMeterDataLogWorker;
|
||||
private Thread _flowMeterDataLogThread;
|
||||
private TempDataLogWorker _tempMonDataLogWorker;
|
||||
private Thread _tempMonDataLogThread;
|
||||
|
||||
private static NLog.ILogger _logger;
|
||||
|
||||
#endregion
|
||||
|
||||
#region PrivateFunctions
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this object's resources
|
||||
/// </summary>
|
||||
/// <param name="disposing">Currently disposing</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// stop the logging if it is still running
|
||||
try
|
||||
{
|
||||
ChillerLogStop();
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
|
||||
// stop the logging if it is still running
|
||||
try
|
||||
{
|
||||
FlowMeterLogStop();
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
|
||||
// stop the logging if it is still running
|
||||
try
|
||||
{
|
||||
TemperatureSensorLogStop();
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
|
||||
// dispose the thread
|
||||
try
|
||||
{
|
||||
if (_chillerDataLogWorker != null)
|
||||
{
|
||||
_chillerDataLogWorker.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
|
||||
// dispose the thread
|
||||
try
|
||||
{
|
||||
if (_flowMeterDataLogWorker != null)
|
||||
{
|
||||
_flowMeterDataLogWorker.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
|
||||
// dispose the thread
|
||||
try
|
||||
{
|
||||
if (_tempMonDataLogWorker != null)
|
||||
{
|
||||
_tempMonDataLogWorker.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
|
||||
// dispose other resources
|
||||
if (_chiller != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_chiller.Shutdown();
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
if (_flowMeter != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_flowMeter.Shutdown();
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
if (_tempMonitor != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_tempMonitor.Shutdown();
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ErrorLogger.Instance().Dispose();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Finalizer
|
||||
/// </summary>
|
||||
~ChillerCartMeasurementManager()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PublicFunctions
|
||||
|
||||
/// <summary>
|
||||
/// constructor that uses instrument manager to create an instrument
|
||||
/// </summary>
|
||||
/// <param name="instrumentManager"></param>
|
||||
/// <param name="chillerName"></param>
|
||||
/// <param name="flowMeeterName"></param>
|
||||
/// <param name="tempSensorName"></param>
|
||||
/// <param name="isThereHardware"></param>
|
||||
/// <param name="errorLog"></param>
|
||||
public ChillerCartMeasurementManager(IInstrumentManager instrumentManager, string chillerName, string flowMeeterName, string tempSensorName, string errorLog)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
// these gets created in the start logging functions
|
||||
_chillerDataLogWorker = null;
|
||||
_chillerDataLogThread = null;
|
||||
_flowMeterDataLogWorker = null;
|
||||
_flowMeterDataLogThread = null;
|
||||
_tempMonDataLogWorker = null;
|
||||
_tempMonDataLogThread = null;
|
||||
|
||||
_chiller = null;
|
||||
_flowMeter = null;
|
||||
_tempMonitor = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(chillerName))
|
||||
{
|
||||
_chiller = instrumentManager.GetInstrument<IChiller>(chillerName);
|
||||
_chiller?.Initialize();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(flowMeeterName))
|
||||
{
|
||||
_flowMeter = instrumentManager.GetInstrument<IFlowMeter>(flowMeeterName);
|
||||
_flowMeter?.Initialize();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tempSensorName))
|
||||
{
|
||||
_tempMonitor = instrumentManager.GetInstrument<ITempMonitor>(tempSensorName);
|
||||
_tempMonitor?.Initialize();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double ChillerGetCoolantTemperature()
|
||||
{
|
||||
return _chiller.GetCoolantTemperature();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double ChillerGetCoolantTemperatureSetpoint()
|
||||
{
|
||||
return _chiller.GetCoolantSetpoint();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void ChillerDisableFlow()
|
||||
{
|
||||
_chiller.DisableFlow();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void ChillerEnableFlow()
|
||||
{
|
||||
_chiller.EnableFlow();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <param name="threadRestTimeMs"></param>
|
||||
/// <param name="callback">An optional delegate for the host to receive the data</param>
|
||||
public void ChillerLogStart(string filename, int threadRestTimeMs, ChillerCartMeasurementManager.ChillerDelegate callback)
|
||||
{
|
||||
if (_chillerDataLogWorker != null)
|
||||
{
|
||||
//Should not be logging. Stop Logger
|
||||
ChillerLogStop();
|
||||
_chillerDataLogWorker.Dispose();
|
||||
}
|
||||
|
||||
//Start logging on a new thread. Also, start calling callback with requested data
|
||||
_chillerDataLogWorker = new ChillerDataLogWorker(this, filename, threadRestTimeMs, callback);
|
||||
_chillerDataLogThread = new Thread(_chillerDataLogWorker.DoWork);
|
||||
_chillerDataLogThread.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void ChillerLogStop()
|
||||
{
|
||||
const int THREAD_QUIT_TIMEOUT = 3000;
|
||||
|
||||
//Is the logger running
|
||||
if (_chillerDataLogWorker != null)
|
||||
{
|
||||
_chillerDataLogWorker.QuitWork();
|
||||
|
||||
if ((_chillerDataLogThread != null) && (_chillerDataLogThread.IsAlive))
|
||||
{
|
||||
bool didThreadQuit = _chillerDataLogThread.Join(THREAD_QUIT_TIMEOUT);
|
||||
|
||||
if (didThreadQuit == false)
|
||||
{
|
||||
_logger?.Error("Logging Thread did not quit as expected, aborting it");
|
||||
_chillerDataLogThread.Abort();
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger?.Info("Logging Thread quit successfully after join");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger?.Info("Logging Thread quit successfully");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="setpoint"></param>
|
||||
public void ChillerSetCoolantTemperature(double setpoint)
|
||||
{
|
||||
_chiller.SetCoolantTemperature(setpoint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//Do not rethrow. Exception from error logger that has already been garbage collected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <param name="threadRestTimeMs"></param>
|
||||
/// <param name="callback">An optional delegate for the host to receive the data</param>
|
||||
public void FlowMeterLogStart(string filename, int threadRestTimeMs, ChillerCartMeasurementManager.FlowMeterDelegate callback)
|
||||
{
|
||||
if (_flowMeterDataLogWorker != null)
|
||||
{
|
||||
//Should not be logging. Stop logger
|
||||
FlowMeterLogStop();
|
||||
_flowMeterDataLogWorker.Dispose();
|
||||
}
|
||||
|
||||
//Start logging on a new thread. Also, start calling callback with requested data
|
||||
_flowMeterDataLogWorker = new FlowMeterDataLogWorker(this, filename, threadRestTimeMs, callback);
|
||||
_flowMeterDataLogThread = new Thread(_flowMeterDataLogWorker.DoWork);
|
||||
_flowMeterDataLogThread.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void FlowMeterLogStop()
|
||||
{
|
||||
const int THREAD_QUIT_TIMEOUT = 5000;
|
||||
|
||||
//Are we logging
|
||||
if (_flowMeterDataLogWorker != null)
|
||||
{
|
||||
_flowMeterDataLogWorker.QuitWork();
|
||||
|
||||
if ((_flowMeterDataLogThread != null) && (_flowMeterDataLogThread.IsAlive))
|
||||
{
|
||||
bool didThreadQuit = _flowMeterDataLogThread.Join(THREAD_QUIT_TIMEOUT);
|
||||
|
||||
if (didThreadQuit == false)
|
||||
{
|
||||
_logger?.Error("Logging Thread did not quit as expected, aborting it");
|
||||
_flowMeterDataLogThread.Abort();
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger?.Info("Logging Thread quit successfully after join");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger?.Info("Logging Thread quit successfully");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double FlowMeterReadFlow()
|
||||
{
|
||||
return _flowMeter.ReadFlow();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double TemperatureSensorReadTemperature()
|
||||
{
|
||||
return _tempMonitor.ReadTemperature();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the temperature sensor log thread
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <param name="threadRestTimeMs"></param>
|
||||
/// <param name="callback">An optional delegate for the host to receive the data</param>
|
||||
public void TemperatureSensorLogStart(string filename, int threadRestTimeMs, ChillerCartMeasurementManager.TemperatureDelegate callback)
|
||||
{
|
||||
if (_tempMonDataLogWorker != null)
|
||||
{
|
||||
//Should not be logging. Stop logger
|
||||
TemperatureSensorLogStop();
|
||||
_tempMonDataLogWorker.Dispose();
|
||||
}
|
||||
|
||||
//Start logging on a new thread. Also, start calling callback with requested data
|
||||
_tempMonDataLogWorker = new TempDataLogWorker(this, filename, threadRestTimeMs, callback);
|
||||
_tempMonDataLogThread = new Thread(_tempMonDataLogWorker.DoWork);
|
||||
_tempMonDataLogThread.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop the temperature sensor log thread
|
||||
/// </summary>
|
||||
public void TemperatureSensorLogStop()
|
||||
{
|
||||
const int THREAD_QUIT_TIMEOUT = 3000;
|
||||
|
||||
//Are we logging
|
||||
if (_tempMonDataLogWorker != null)
|
||||
{
|
||||
_tempMonDataLogWorker.QuitWork();
|
||||
|
||||
if ((_tempMonDataLogThread != null) && (_tempMonDataLogThread.IsAlive))
|
||||
{
|
||||
bool didThreadQuit = _tempMonDataLogThread.Join(THREAD_QUIT_TIMEOUT);
|
||||
|
||||
if (didThreadQuit == false)
|
||||
{
|
||||
_logger?.Error("Logging Thread did not quit as expected, aborting it");
|
||||
_tempMonDataLogThread.Abort();
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger?.Info("Logging Thread quit successfully after join");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger?.Info("Logging Thread quit successfully");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>ChillerCartMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Chiller Cart Measurement Manager</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLog" Version="5.0.0" />
|
||||
<PackageReference Include="Raytheon.Common" Version="1.0.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.InstrumentManager.Contracts" Version="1.8.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.Chiller.Contracts" Version="1.0.3" />
|
||||
<PackageReference Include="Raytheon.Instruments.FlowMeter.Contracts" Version="1.0.3" />
|
||||
<PackageReference Include="Raytheon.Instruments.TempMonitor.Contracts" Version="1.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,209 @@
|
||||
// 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 Raytheon.Common;
|
||||
using System.IO;
|
||||
using MeasurementManagerLib;
|
||||
|
||||
namespace ChillerCartMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// A worker class that will periodically query the chiller for its status and log it out
|
||||
/// </summary>
|
||||
internal class ChillerDataLogWorker : IWorkerInterface
|
||||
{
|
||||
#region PrivateMembers
|
||||
private bool _threadQuitControl;
|
||||
private bool _createHeader;
|
||||
private AutoResetEvent _quitEvent;
|
||||
private StreamWriter _fileWriter;
|
||||
private readonly ChillerCartMeasurementManager _controller;
|
||||
private readonly ChillerCartMeasurementManager.ChillerDelegate _callback;
|
||||
private readonly string _logFileName;
|
||||
private readonly int _threadRestTimeMs;
|
||||
#endregion
|
||||
|
||||
#region PrivateFunctions
|
||||
/// <summary>
|
||||
/// Finalizer
|
||||
/// </summary>
|
||||
~ChillerDataLogWorker()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_fileWriter.Dispose();
|
||||
|
||||
_quitEvent.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="controller"></param>
|
||||
/// <param name="logFileName"></param>
|
||||
/// <param name="threadRestTimeMs"></param>
|
||||
/// <param name="callback"></param>
|
||||
public ChillerDataLogWorker(ChillerCartMeasurementManager controller, string logFileName, int threadRestTimeMs, ChillerCartMeasurementManager.ChillerDelegate callback)
|
||||
{
|
||||
_threadQuitControl = false;
|
||||
_quitEvent = new AutoResetEvent(false);
|
||||
|
||||
_createHeader = true;
|
||||
|
||||
_controller = controller;
|
||||
|
||||
_callback = callback;
|
||||
_threadRestTimeMs = threadRestTimeMs;
|
||||
_logFileName = logFileName;
|
||||
|
||||
|
||||
//If file exists
|
||||
if (File.Exists(_logFileName))
|
||||
{
|
||||
_createHeader = false;
|
||||
}
|
||||
|
||||
//Create file or append to file
|
||||
_fileWriter = new StreamWriter(_logFileName, true);
|
||||
_fileWriter.AutoFlush = true;
|
||||
|
||||
//Create the header for the new file
|
||||
if (_createHeader)
|
||||
{
|
||||
_fileWriter.WriteLine("Time, Temperature, Temperature Setpoint");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this object. Needed for releasing thread/comm resources
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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>
|
||||
///
|
||||
/// </summary>
|
||||
public void DoWork()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (_threadQuitControl == false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_quitEvent.WaitOne(_threadRestTimeMs))
|
||||
{
|
||||
_threadQuitControl = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
double temperature = _controller.ChillerGetCoolantTemperature();
|
||||
double temperatureSetpoint = _controller.ChillerGetCoolantTemperatureSetpoint();
|
||||
|
||||
string logData = Util.GetTimeString() + ", Temperature: " + temperature.ToString() + ", TemperatureSetpoint: " + temperatureSetpoint.ToString();
|
||||
|
||||
_fileWriter.WriteLine(logData);
|
||||
|
||||
//Invoke the callback if valid
|
||||
if (_callback != null && _threadQuitControl == false)
|
||||
{
|
||||
_callback.Invoke(temperature, temperatureSetpoint, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string msg = e.Message;
|
||||
ErrorLogger.Instance().Write(msg + "\r\n" + e.StackTrace, ErrorLogger.LogLevel.ERROR);
|
||||
|
||||
_fileWriter.WriteLine(Util.GetTimeString() + ", " + msg);
|
||||
|
||||
//Send error code to callback if valid
|
||||
_callback?.Invoke(-1, -1, -1);
|
||||
}
|
||||
}
|
||||
ErrorLogger.Instance().Write("ChillerCartDataLogWorker::DoWork() - exiting", ErrorLogger.LogLevel.INFO);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
|
||||
|
||||
//Send error code to callback if valid
|
||||
_callback?.Invoke(-1, -1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the thread, closes the datalogger and calls move file
|
||||
/// </summary>
|
||||
public void QuitWork()
|
||||
{
|
||||
_threadQuitControl = true;
|
||||
|
||||
_quitEvent.Set();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
// 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 Raytheon.Common;
|
||||
using System.IO;
|
||||
using MeasurementManagerLib;
|
||||
|
||||
namespace ChillerCartMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// A worker class that will periodically query the flow meter for its status and log it out
|
||||
/// </summary>
|
||||
internal class FlowMeterDataLogWorker : IWorkerInterface
|
||||
{
|
||||
#region PrivateMembers
|
||||
private bool _threadQuitControl;
|
||||
private bool _createHeader;
|
||||
private AutoResetEvent _quitEvent;
|
||||
private StreamWriter _fileWriter;
|
||||
private readonly ChillerCartMeasurementManager _controller;
|
||||
private readonly ChillerCartMeasurementManager.FlowMeterDelegate _callback;
|
||||
private readonly string _logFileName;
|
||||
private readonly int _threadRestTimeMs;
|
||||
#endregion
|
||||
|
||||
#region PrivateFunctions
|
||||
/// <summary>
|
||||
/// Finalizer
|
||||
/// </summary>
|
||||
~FlowMeterDataLogWorker()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_fileWriter.Dispose();
|
||||
|
||||
_quitEvent.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="controller"></param>
|
||||
/// <param name="logFileName"></param>
|
||||
/// <param name="threadRestTimeMs"></param>
|
||||
/// <param name="callback"></param>
|
||||
public FlowMeterDataLogWorker(ChillerCartMeasurementManager controller, string logFileName, int threadRestTimeMs, ChillerCartMeasurementManager.FlowMeterDelegate callback)
|
||||
{
|
||||
_threadQuitControl = false;
|
||||
_quitEvent = new AutoResetEvent(false);
|
||||
|
||||
_createHeader = true;
|
||||
|
||||
_controller = controller;
|
||||
|
||||
_callback = callback;
|
||||
_threadRestTimeMs = threadRestTimeMs;
|
||||
_logFileName = logFileName;
|
||||
|
||||
//If file exists
|
||||
if (File.Exists(_logFileName))
|
||||
{
|
||||
_createHeader = false;
|
||||
}
|
||||
|
||||
//Create file or append to file
|
||||
_fileWriter = new StreamWriter(_logFileName, true);
|
||||
_fileWriter.AutoFlush = true;
|
||||
|
||||
//Create the header for the new file
|
||||
if (_createHeader)
|
||||
{
|
||||
_fileWriter.WriteLine("Time, Flow");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this object. Needed for releasing thread/comm resources
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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>
|
||||
///
|
||||
/// </summary>
|
||||
public void DoWork()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (_threadQuitControl == false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_quitEvent.WaitOne(_threadRestTimeMs))
|
||||
{
|
||||
_threadQuitControl = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
double flow = _controller.FlowMeterReadFlow();
|
||||
|
||||
string logData = Util.GetTimeString() + "," + flow.ToString();
|
||||
|
||||
_fileWriter.WriteLine(logData);
|
||||
|
||||
//Invoke the callback if valid
|
||||
if (_callback != null && _threadQuitControl == false)
|
||||
{
|
||||
_callback.Invoke(flow, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string msg = e.Message;
|
||||
|
||||
ErrorLogger.Instance().Write(msg + "\r\n" + e.StackTrace, ErrorLogger.LogLevel.ERROR);
|
||||
|
||||
_fileWriter.WriteLine(Util.GetTimeString() + ", " + msg);
|
||||
|
||||
//Invoke the callback if valid
|
||||
if (_callback != null && _threadQuitControl == false)
|
||||
{
|
||||
_callback.Invoke(-1, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
ErrorLogger.Instance().Write("FlowMeterDataLogWorker::DoWork() - exiting", ErrorLogger.LogLevel.INFO);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
|
||||
|
||||
//Send error code to callback if valid
|
||||
if (_callback != null && _threadQuitControl == false)
|
||||
{
|
||||
_callback.Invoke(-1, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the thread, closes the datalogger and calls move file
|
||||
/// </summary>
|
||||
public void QuitWork()
|
||||
{
|
||||
_threadQuitControl = true;
|
||||
|
||||
_quitEvent.Set();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
// 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 Raytheon.Common;
|
||||
using System.IO;
|
||||
using MeasurementManagerLib;
|
||||
|
||||
namespace ChillerCartMeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// A worker class that will periodically query the temperature sensor for its status and log it out
|
||||
/// </summary>
|
||||
internal class TempDataLogWorker : IWorkerInterface
|
||||
{
|
||||
#region PrivateMembers
|
||||
private bool _threadQuitControl;
|
||||
private bool _createHeader;
|
||||
private AutoResetEvent _quitEvent;
|
||||
private StreamWriter _fileWriter;
|
||||
private readonly ChillerCartMeasurementManager _controller;
|
||||
private readonly ChillerCartMeasurementManager.TemperatureDelegate _callback;
|
||||
private readonly string _logFileName;
|
||||
private readonly int _threadRestTimeMs;
|
||||
|
||||
#endregion
|
||||
|
||||
#region PrivateFunctions
|
||||
/// <summary>
|
||||
/// Finalizer
|
||||
/// </summary>
|
||||
~TempDataLogWorker()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_fileWriter.Dispose();
|
||||
|
||||
_quitEvent.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="controller"></param>
|
||||
/// <param name="logFileName"></param>
|
||||
/// <param name="threadRestTimeMs"></param>
|
||||
/// <param name="callback"></param>
|
||||
public TempDataLogWorker(ChillerCartMeasurementManager controller, string logFileName, int threadRestTimeMs, ChillerCartMeasurementManager.TemperatureDelegate callback)
|
||||
{
|
||||
_threadQuitControl = false;
|
||||
_quitEvent = new AutoResetEvent(false);
|
||||
|
||||
_createHeader = true;
|
||||
|
||||
_controller = controller;
|
||||
|
||||
_callback = callback;
|
||||
_threadRestTimeMs = threadRestTimeMs;
|
||||
_logFileName = logFileName;
|
||||
|
||||
//If file exists
|
||||
if (File.Exists(_logFileName))
|
||||
{
|
||||
_createHeader = false;
|
||||
}
|
||||
|
||||
//Create file or append to file
|
||||
_fileWriter = new StreamWriter(_logFileName, true);
|
||||
_fileWriter.AutoFlush = true;
|
||||
|
||||
//Create the header for the new file
|
||||
if (_createHeader)
|
||||
{
|
||||
_fileWriter.WriteLine("Time, Temperature, Temperature Setpoint");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this object. Needed for releasing thread/comm resources
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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>
|
||||
///
|
||||
/// </summary>
|
||||
public void DoWork()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (_threadQuitControl == false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_quitEvent.WaitOne(_threadRestTimeMs))
|
||||
{
|
||||
_threadQuitControl = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
double temp = _controller.TemperatureSensorReadTemperature();
|
||||
|
||||
string logData = Util.GetTimeString() + ", Flow: " + temp.ToString();
|
||||
|
||||
_fileWriter.WriteLine(logData);
|
||||
|
||||
//Invoke the callback if valid
|
||||
if (_callback != null && _threadQuitControl == false)
|
||||
{
|
||||
_callback.Invoke(temp, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string msg = e.Message;
|
||||
ErrorLogger.Instance().Write(msg + "\r\n" + e.StackTrace, ErrorLogger.LogLevel.ERROR);
|
||||
|
||||
_fileWriter.WriteLine(Util.GetTimeString() + ", " + msg);
|
||||
|
||||
//Send error code to callback if valid
|
||||
_callback?.Invoke(-1, -1);
|
||||
}
|
||||
}
|
||||
ErrorLogger.Instance().Write("TempDataLogWorker::DoWork() - exiting", ErrorLogger.LogLevel.INFO);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
|
||||
|
||||
//Send error code to callback if valid
|
||||
_callback(-1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the thread, closes the datalogger and calls move file
|
||||
/// </summary>
|
||||
public void QuitWork()
|
||||
{
|
||||
_threadQuitControl = true;
|
||||
|
||||
_quitEvent.Set();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
using Raytheon.Instruments;
|
||||
using CryoMeasurementManagerLib;
|
||||
|
||||
using System;
|
||||
|
||||
namespace MeasurementManagerLib
|
||||
{
|
||||
public class CryoMeasurementManager
|
||||
{
|
||||
private bool _isThereHardware;
|
||||
private ICommDevice _commDevice;
|
||||
private ICommDevice _serialDevice;
|
||||
|
||||
public CryoMeasurementManager(bool isThereHardware, string measurementDefFile, string instrumentDefFile, string errorLogFileName)
|
||||
{
|
||||
if (measurementDefFile == null)
|
||||
{
|
||||
throw new ArgumentNullException("CryoMeasurementManager::CryoMeasurementManager() - measurementDefFile input parameter is null.");
|
||||
}
|
||||
if (instrumentDefFile == null)
|
||||
{
|
||||
throw new ArgumentNullException("CryoMeasurementManager::CryoMeasurementManager() - instrumentDefFile input parameter is null.");
|
||||
}
|
||||
if (errorLogFileName == null)
|
||||
{
|
||||
throw new ArgumentNullException("CryoMeasurementManager::CryoMeasurementManager() - errorLogFileName input parameter is null.");
|
||||
}
|
||||
_isThereHardware = isThereHardware;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// constructor that uses instrument manager to create an instrument
|
||||
/// </summary>
|
||||
/// <param name="instrumentManaegr"></param>
|
||||
/// <param name="commDeviceName"></param>
|
||||
/// <param name="serialDeviceName"></param>
|
||||
/// <param name="isThereHardware"></param>
|
||||
/// <param name="errorLogFileName"></param>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public CryoMeasurementManager(IInstrumentManager instrumentManaegr, string commDeviceName, string serialDeviceName, bool isThereHardware, string errorLogFileName)
|
||||
{
|
||||
if (errorLogFileName == null)
|
||||
{
|
||||
throw new ArgumentNullException("CryoMeasurementManager::CryoMeasurementManager() - errorLogFileName input parameter is null.");
|
||||
}
|
||||
_isThereHardware = isThereHardware;
|
||||
|
||||
if(!string.IsNullOrEmpty(commDeviceName))
|
||||
{
|
||||
_commDevice = instrumentManaegr.GetInstrument<ICommDevice>(commDeviceName);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(serialDeviceName))
|
||||
{
|
||||
_serialDevice = instrumentManaegr.GetInstrument<ICommDevice>(serialDeviceName);
|
||||
}
|
||||
}
|
||||
|
||||
public CryoMeasurementManager(string instrumentName, string errorLogFileName, bool isThereHardware)
|
||||
{
|
||||
_isThereHardware = isThereHardware;
|
||||
}
|
||||
|
||||
|
||||
private void SendMessageGetResponse(CryoMessage message)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void StartFastCoolDown(object[] inputs)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void StartLogging(string fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void StartSlowCoolDown(object[] inputs)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void StopLogging()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>CryoMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Cryo Measurement Manager</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLog" Version="5.0.0" />
|
||||
<PackageReference Include="Raytheon.Common" Version="1.0.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.InstrumentManager.Contracts" Version="1.8.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.CommDevice.Contracts" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
|
||||
namespace CryoMeasurementManagerLib
|
||||
{
|
||||
public class CryoMessage
|
||||
{
|
||||
protected string _command;
|
||||
|
||||
protected uint _id;
|
||||
|
||||
public CryoMessage(int id)
|
||||
{
|
||||
}
|
||||
|
||||
public void Extract()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetCommand()
|
||||
{
|
||||
string str;
|
||||
try
|
||||
{
|
||||
str = "@@@DEFAULT RETURN STRING;";
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public uint GetId()
|
||||
{
|
||||
uint num;
|
||||
try
|
||||
{
|
||||
num = 0;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public void Insert()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
// 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 Raytheon.Instruments.GeneralIO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
||||
namespace MeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class manages IDIO instruments and provides an abstraction
|
||||
/// </summary>
|
||||
public class DioMeasurementManager : IDisposable
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private SortedDictionary<string, IGeneralIO> _signalNameToObjectMap = new SortedDictionary<string, IGeneralIO>();
|
||||
|
||||
private static NLog.ILogger _logger;
|
||||
#endregion
|
||||
|
||||
#region PublicClassFunctions
|
||||
|
||||
/// <summary>
|
||||
/// constructor with the instrument manager
|
||||
/// </summary>
|
||||
/// <param name="instrumentManager">General Instrument Manager</param>
|
||||
public DioMeasurementManager(IInstrumentManager instrumentManager)
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
ICollection<object> dioModuleList = instrumentManager.GetInstruments(typeof(IGeneralIO));
|
||||
// populate the maps
|
||||
foreach (IGeneralIO dioModule in dioModuleList)
|
||||
{
|
||||
dioModule.Initialize();
|
||||
|
||||
List<string> signalNames = dioModule.GetSignalNames();
|
||||
|
||||
foreach (string signalName in signalNames)
|
||||
{
|
||||
if (_signalNameToObjectMap.ContainsKey(signalName.ToUpper()))
|
||||
{
|
||||
throw new Exception("There is more than 1 DIO card that have the same signal name: " + signalName);
|
||||
}
|
||||
|
||||
_signalNameToObjectMap[signalName.ToUpper()] = dioModule;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this objects resources
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//Do not rethrow. Exception from error logger that has already been garbage collected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the state(0 or 1) of an input signal
|
||||
/// </summary>
|
||||
/// <param name="signalName">The signal to get the state of</param>
|
||||
/// <returns>0 if the signal is low, 1 if the signal is high</returns>
|
||||
public IODatatypes.BitState GetInputSignalState(string signalName)
|
||||
{
|
||||
return _signalNameToObjectMap[signalName.ToUpper()].GetBitState(signalName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the state of an output signal
|
||||
/// </summary>
|
||||
/// <param name="signalName">The name of the output signal</param>
|
||||
/// <param name="data">The state, 0 for low, 1 for high, 2 for logic Z</param>
|
||||
/// <param name="timeToSleepMs">number of ms to wait after setting signal</param>
|
||||
public void SetOutputSignalState(string signalName, IODatatypes.BitState state, uint timeToSleepMs = 100)
|
||||
{
|
||||
_signalNameToObjectMap[signalName.ToUpper()].SetBit(signalName, state);
|
||||
|
||||
// wait a bit
|
||||
Thread.Sleep((int)timeToSleepMs);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PrivateClassFunctions
|
||||
|
||||
/// <summary>
|
||||
/// The Finalizer
|
||||
/// </summary>
|
||||
~DioMeasurementManager()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
foreach (KeyValuePair<string, IGeneralIO> entry in _signalNameToObjectMap)
|
||||
{
|
||||
try
|
||||
{
|
||||
entry.Value.Shutdown();
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ErrorLogger.Instance().Dispose();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>DioMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Dio Measurement Manager</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLog" Version="5.0.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.InstrumentManager.Contracts" Version="1.8.0" />
|
||||
<PackageReference Include="Raytheon.Common" Version="1.0.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.GeneralIO.Contracts" Version="1.7.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,384 @@
|
||||
// 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;
|
||||
|
||||
namespace MeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class manages IFpgaComm instruments and provides an abstraction
|
||||
/// </summary>
|
||||
public class FpgaMeasurementManager : IDisposable
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
// fpga name to object
|
||||
private readonly Dictionary<string, IFpgaComm> _fpgaDeviceMap;
|
||||
// fpga to MemoryMap
|
||||
private readonly Dictionary<string, MemoryMap> _fpgaMemMaps;
|
||||
|
||||
private static NLog.ILogger _logger;
|
||||
#endregion
|
||||
|
||||
#region PrivateFuctions
|
||||
|
||||
/// <summary>
|
||||
/// Finalizer.
|
||||
/// </summary>
|
||||
~FpgaMeasurementManager()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposing
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
foreach (KeyValuePair<string, IFpgaComm> entry in _fpgaDeviceMap)
|
||||
{
|
||||
try
|
||||
{
|
||||
entry.Value.Shutdown();
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the communication to the fpga
|
||||
/// </summary>
|
||||
/// <param name="fpga">the name of the fpga as defined in the config file</param>
|
||||
private void Initialize(string fpga)
|
||||
{
|
||||
if (_fpgaDeviceMap.ContainsKey(fpga.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("could not find device: " + fpga);
|
||||
}
|
||||
|
||||
_fpgaDeviceMap[fpga].Initialize(fpga);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
/// constructor with instrument manager
|
||||
/// </summary>
|
||||
/// <param name="instrumentManager"></param>
|
||||
/// <param name="instrumentNames"></param>
|
||||
/// <param name="instrumentDefFile"></param>
|
||||
public FpgaMeasurementManager(IInstrumentManager instrumentManager, List<string> instrumentNames, string instrumentDefFile)
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
_fpgaDeviceMap = new Dictionary<string, IFpgaComm>();
|
||||
|
||||
foreach (string name in instrumentNames)
|
||||
{
|
||||
_fpgaDeviceMap[name] = instrumentManager.GetInstrument<IFpgaComm>(name);
|
||||
_fpgaDeviceMap[name]?.Initialize(name);
|
||||
}
|
||||
|
||||
// setup the memory maps
|
||||
_fpgaMemMaps = new Dictionary<string, MemoryMap>(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
ConfigurationFile ini = new ConfigurationFile(instrumentDefFile);
|
||||
|
||||
foreach (KeyValuePair<string, IFpgaComm> entry in _fpgaDeviceMap)
|
||||
{
|
||||
string memMapFile = ini.ReadValue<string>(entry.Key, "MEM_MAP");
|
||||
|
||||
if (memMapFile.ToUpper().Trim() != "NONE")
|
||||
{
|
||||
_fpgaMemMaps.Add(entry.Key.ToUpper(), new MemoryMap(memMapFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of resources
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//Do not rethrow. Exception from error logger that has already been garbage collected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the comm device
|
||||
/// </summary>
|
||||
/// <param name="fpga"></param>
|
||||
/// <returns></returns>
|
||||
public IFpgaComm GetFpgaCommDevice(string fpga)
|
||||
{
|
||||
if (_fpgaDeviceMap.ContainsKey(fpga.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("could not find device: " + fpga);
|
||||
}
|
||||
|
||||
return _fpgaDeviceMap[fpga.ToUpper()];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all of the fpga names
|
||||
/// </summary>
|
||||
/// <returns>A list of fpga device names</returns>
|
||||
public List<string> GetFpgaNames()
|
||||
{
|
||||
List<string> fpgaList = new List<string>();
|
||||
|
||||
foreach (KeyValuePair<string, IFpgaComm> entry in _fpgaDeviceMap)
|
||||
{
|
||||
fpgaList.Add(entry.Key);
|
||||
}
|
||||
|
||||
return fpgaList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a register that is defined by a memory map logical name
|
||||
/// If a subitem is commanded, this returns just the value of the subitems
|
||||
/// </summary>
|
||||
/// <param name="fpga">the name of the fpga as defined in the config file</param>
|
||||
/// <param name="memMapItemName">The name of the mem map item in the memory map file</param>
|
||||
/// <returns></returns>
|
||||
public uint RegisterRead(string fpga, string memMapItemName)
|
||||
{
|
||||
if (_fpgaMemMaps.ContainsKey(fpga.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("no memory map exists for fpga: " + fpga);
|
||||
}
|
||||
|
||||
MemoryMap.MemoryMapFields fields = _fpgaMemMaps[fpga.ToUpper()].GetRegisterInfoByString(memMapItemName);
|
||||
|
||||
uint registerValue = _fpgaDeviceMap[fpga.ToUpper()].Read(fpga, fields._address);
|
||||
|
||||
uint itemValue = Util.ParseRegisterItem(registerValue, fields._startBit, fields._numBits);
|
||||
|
||||
return itemValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a register given an address
|
||||
/// </summary>
|
||||
/// <param name="fpga">the name of the fpga as defined in the config file</param>
|
||||
/// <param name="address">the address to read</param>
|
||||
/// <returns></returns>
|
||||
public uint RegisterRead(string fpga, uint address)
|
||||
{
|
||||
if (_fpgaDeviceMap.ContainsKey(fpga.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("could not find device: " + fpga);
|
||||
}
|
||||
|
||||
return _fpgaDeviceMap[fpga.ToUpper()].Read(fpga, address);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a register given an address with optional offset
|
||||
/// </summary>
|
||||
/// <param name="fpga"></param>
|
||||
/// <param name="memMapItemName"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public uint RegisterRead(string fpga, string memMapItemName, uint offset = 0)
|
||||
{
|
||||
if (_fpgaMemMaps.ContainsKey(fpga.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("no memory map exists for fpga: " + fpga);
|
||||
}
|
||||
|
||||
MemoryMap.MemoryMapFields fields = _fpgaMemMaps[fpga.ToUpper()].GetRegisterInfoByString(memMapItemName);
|
||||
|
||||
uint registerValue = _fpgaDeviceMap[fpga.ToUpper()].Read(fpga, fields._address + offset);
|
||||
|
||||
uint itemValue = Util.ParseRegisterItem(registerValue, fields._startBit, fields._numBits);
|
||||
|
||||
return itemValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// reads block from fpga
|
||||
/// </summary>
|
||||
/// <param name="fpga"></param>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="numberOfWordsToRead"></param>
|
||||
/// <param name="shallWeIncrementAddress"></param>
|
||||
/// <param name="dataRead"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public void ReadBlock(string fpga, uint address, uint numberOfWordsToRead, bool shallWeIncrementAddress, ref uint[] dataRead)
|
||||
{
|
||||
if (_fpgaDeviceMap.ContainsKey(fpga.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("FpgaMeasurementManager::ReadBlock - could not find device: " + fpga);
|
||||
}
|
||||
|
||||
if (address == 0)
|
||||
{
|
||||
_fpgaDeviceMap[fpga.ToUpper()].ReadBlock(fpga, address, numberOfWordsToRead, shallWeIncrementAddress, ref dataRead);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Not yet implemented");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a register given an address
|
||||
/// </summary>
|
||||
/// <param name="fpga">the name of the fpga as defined in the config file</param>
|
||||
/// <param name="address">The address to write to</param>
|
||||
/// <param name="dataToWrite">The data to write to the register</param>
|
||||
public void RegisterWrite(string fpga, uint address, uint dataToWrite)
|
||||
{
|
||||
if (_fpgaDeviceMap.ContainsKey(fpga.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("could not find device: " + fpga);
|
||||
}
|
||||
|
||||
_fpgaDeviceMap[fpga.ToUpper().ToUpper()].Write(fpga, address, dataToWrite);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// write a register that is defined by a memory map logical name
|
||||
/// If a sub item is commanded, the current values of the other items remain unchanged
|
||||
/// </summary>
|
||||
/// <param name="fpga">the name of the fpga as defined in the config file</param>
|
||||
/// <param name="memMapItemName">The name of the mem map item in the memory map file</param>
|
||||
/// <param name="dataToWrite">The data to write to the register</param>
|
||||
/// <param name="offset">The offset off of memMapItemName</param>
|
||||
public void RegisterWrite(string fpga, string memMapItemName, uint dataToWrite, uint offset = 0)
|
||||
{
|
||||
if (_fpgaMemMaps.ContainsKey(fpga.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("no memory map exists for fpga: " + fpga);
|
||||
}
|
||||
|
||||
MemoryMap.MemoryMapFields fields = _fpgaMemMaps[fpga.ToUpper()].GetRegisterInfoByString(memMapItemName);
|
||||
|
||||
uint address = fields._address + offset;
|
||||
|
||||
// if commanded to write to a sub register, only write out those bits
|
||||
if (fields._numBits < 32)
|
||||
{
|
||||
// read existing value
|
||||
uint originalValue = RegisterRead(fpga, address);
|
||||
|
||||
//Apply inverse mask to current register contents to zero out just the bits we want to write
|
||||
uint maskValue = Util.ApplyBitMask(originalValue, fields._startBit, fields._numBits, true);
|
||||
|
||||
// Shift the desired data to set to match the zeroed register
|
||||
dataToWrite = dataToWrite << fields._startBit;
|
||||
|
||||
dataToWrite = maskValue | dataToWrite;
|
||||
}
|
||||
|
||||
_fpgaDeviceMap[fpga.ToUpper()].Write(fpga, address, dataToWrite);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="fpga"></param>
|
||||
/// <param name="memMapItemName"></param>
|
||||
/// <param name="dataToWrite"></param>
|
||||
/// <param name="offset"></param>
|
||||
public void RegisterWriteBlock(string fpga, string memMapItemName, uint numWordsToWrite, uint[] dataToWrite, bool shallWeIncrementAddress, uint offset = 0)
|
||||
{
|
||||
if (_fpgaMemMaps.ContainsKey(fpga.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("no memory map exists for fpga: " + fpga);
|
||||
}
|
||||
|
||||
MemoryMap.MemoryMapFields fields = _fpgaMemMaps[fpga.ToUpper()].GetRegisterInfoByString(memMapItemName);
|
||||
|
||||
uint address = fields._address + offset;
|
||||
|
||||
// if commanded to write to a sub register, only write out those bits
|
||||
if (fields._numBits < 32)
|
||||
{
|
||||
throw new Exception("can only write a block of data to a 32 bit register. fpga: " + fpga);
|
||||
}
|
||||
|
||||
_fpgaDeviceMap[fpga.ToUpper()].WriteBlock(fpga, address, numWordsToWrite, dataToWrite, shallWeIncrementAddress);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the default value (as specified in the memory map) to the register
|
||||
/// If a sub item is commanded, the current values of the other items remain unchanged
|
||||
/// </summary>
|
||||
/// <param name="fpga">The name of the FPGA</param>
|
||||
/// <param name="memMapItemName">The memory map item which we will restore the default.</param>
|
||||
public void RegisterWriteDefault(string fpga, string memMapItemName)
|
||||
{
|
||||
if (_fpgaMemMaps.ContainsKey(fpga.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("no memory map exists for fpga: " + fpga);
|
||||
}
|
||||
|
||||
MemoryMap.MemoryMapFields fields = _fpgaMemMaps[fpga.ToUpper()].GetRegisterInfoByString(memMapItemName);
|
||||
|
||||
uint dataToWrite = fields._regDefault;
|
||||
|
||||
// if commanded to write to a sub register, only write out those bits
|
||||
if (fields._numBits < 32)
|
||||
{
|
||||
// read existing value
|
||||
uint originalValue = RegisterRead(fpga, fields._address);
|
||||
|
||||
//Apply inverse mask to current register contents to zero out just the bits we want to write
|
||||
uint maskValue = Util.ApplyBitMask(originalValue, fields._startBit, fields._numBits, true);
|
||||
|
||||
// Shift the desired data to set to match the zeroed register
|
||||
dataToWrite = dataToWrite << fields._startBit;
|
||||
|
||||
dataToWrite = maskValue | dataToWrite;
|
||||
}
|
||||
|
||||
_fpgaDeviceMap[fpga.ToUpper()].Write(fpga, fields._address, dataToWrite);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>FpgaMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Fpga Measurement Manager</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.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.InstrumentManager.Contracts" Version="1.8.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.FpgaComm.Contracts" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,286 @@
|
||||
// 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.Linq;
|
||||
|
||||
namespace MeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class provides an abstraction for running jtag jobs via the command line
|
||||
/// </summary>
|
||||
public class JtagMeasurementManager : IDisposable
|
||||
{
|
||||
#region PrivateMembers
|
||||
private readonly IJtag _jtag;
|
||||
private Dictionary<string, JtagJobInfo> _jtagMeasurements;
|
||||
private static NLog.ILogger _logger;
|
||||
#endregion
|
||||
|
||||
#region PrivateFunctions
|
||||
|
||||
/// <summary>
|
||||
/// Finalizer.
|
||||
/// </summary>
|
||||
~JtagMeasurementManager()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_jtag.Shutdown();
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//Do not rethrow. Exception from error logger that has already been garbage collected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses Measurement Definition File
|
||||
/// </summary>
|
||||
/// <param name="configurationFile"></param>
|
||||
private void ParseMeasurementDef(ConfigurationFile configurationFile)
|
||||
{
|
||||
const string BSX_FILE_PATH_KEY = "BSX_FILE_PATH";
|
||||
const string BSX_FILE_KEY = "BSX_FILE";
|
||||
const string BSX_COMMAND_LINE_KEY = "BSX_FILE_COMMAND_LINE";
|
||||
|
||||
const string USE_DIAG_CMD_LINE1_KEY = "USE_DIAG_CMD_LINE_1";
|
||||
const string DIAG_FILE1_KEY = "DIAG_FILE_1";
|
||||
const string DIAG_CMD_LINE1_KEY = "DIAG_CMD_LINE_1";
|
||||
|
||||
const string USE_DIAG_CMD_LINE2_KEY = "USE_DIAG_CMD_LINE_2";
|
||||
const string DIAG_FILE2_KEY = "DIAG_FILE_2";
|
||||
const string DIAG_CMD_LINE2_KEY = "DIAG_CMD_LINE_2";
|
||||
|
||||
// read in all of the sections
|
||||
List<string> sections = configurationFile.ReadAllSections();
|
||||
|
||||
foreach (string section in sections)
|
||||
{
|
||||
string bsxFilePath = configurationFile.ReadValue<string>(section, BSX_FILE_PATH_KEY);
|
||||
string bsxFile = configurationFile.ReadValue<string>(section, BSX_FILE_KEY);
|
||||
string bsxCmdLine = configurationFile.ReadValue<string>(section, BSX_COMMAND_LINE_KEY);
|
||||
|
||||
bool useDiag1 = configurationFile.ReadValue<bool>(section, USE_DIAG_CMD_LINE1_KEY);
|
||||
string diag1File = "Not Set";
|
||||
string diag1CmdLine = "Not Set";
|
||||
if (useDiag1 == true)
|
||||
{
|
||||
diag1File = configurationFile.ReadValue<string>(section, DIAG_FILE1_KEY);
|
||||
diag1CmdLine = configurationFile.ReadValue<string>(section, DIAG_CMD_LINE1_KEY);
|
||||
}
|
||||
|
||||
bool useDiag2 = configurationFile.ReadValue<bool>(section, USE_DIAG_CMD_LINE2_KEY);
|
||||
string diag2File = "Not Set";
|
||||
string diag2CmdLine = "Not Set";
|
||||
if (useDiag2 == true)
|
||||
{
|
||||
diag2File = configurationFile.ReadValue<string>(section, DIAG_FILE2_KEY);
|
||||
diag2CmdLine = configurationFile.ReadValue<string>(section, DIAG_CMD_LINE2_KEY);
|
||||
}
|
||||
|
||||
JtagJobInfo info = new JtagJobInfo
|
||||
{
|
||||
bsxFilePath = bsxFilePath,
|
||||
bsxFile = bsxFile,
|
||||
bsxFileCommandline = bsxCmdLine,
|
||||
|
||||
shallWeUseDiag1 = useDiag1,
|
||||
diag1File = diag1File,
|
||||
diag1CmdLine = diag1CmdLine,
|
||||
|
||||
shallWeUseDiag2 = useDiag2,
|
||||
diag2File = diag2File,
|
||||
diag2CmdLine = diag2CmdLine
|
||||
};
|
||||
|
||||
_jtagMeasurements.Add(section.ToUpper(), info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Parses Measurement Definition File
|
||||
/// </summary>
|
||||
/// <param name="measurementDefFile"></param>
|
||||
private void ParseMeasurementDef(string measurementDefFile)
|
||||
{
|
||||
const string BSX_FILE_PATH_KEY = "BSX_FILE_PATH";
|
||||
const string BSX_FILE_KEY = "BSX_FILE";
|
||||
const string BSX_COMMAND_LINE_KEY = "BSX_FILE_COMMAND_LINE";
|
||||
|
||||
const string USE_DIAG_CMD_LINE1_KEY = "USE_DIAG_CMD_LINE_1";
|
||||
const string DIAG_FILE1_KEY = "DIAG_FILE_1";
|
||||
const string DIAG_CMD_LINE1_KEY = "DIAG_CMD_LINE_1";
|
||||
|
||||
const string USE_DIAG_CMD_LINE2_KEY = "USE_DIAG_CMD_LINE_2";
|
||||
const string DIAG_FILE2_KEY = "DIAG_FILE_2";
|
||||
const string DIAG_CMD_LINE2_KEY = "DIAG_CMD_LINE_2";
|
||||
|
||||
// read in all of the sections
|
||||
IniFile ini = new IniFile(measurementDefFile);
|
||||
List<string> sections = ini.ReadAllSections();
|
||||
|
||||
foreach (string section in sections)
|
||||
{
|
||||
string bsxFilePath = ini.ReadValue(section, BSX_FILE_PATH_KEY);
|
||||
string bsxFile = ini.ReadValue(section, BSX_FILE_KEY);
|
||||
string bsxCmdLine = ini.ReadValue(section, BSX_COMMAND_LINE_KEY);
|
||||
|
||||
bool useDiag1 = Convert.ToBoolean(ini.ReadValue(section, USE_DIAG_CMD_LINE1_KEY));
|
||||
string diag1File = "Not Set";
|
||||
string diag1CmdLine = "Not Set";
|
||||
if (useDiag1 == true)
|
||||
{
|
||||
diag1File = ini.ReadValue(section, DIAG_FILE1_KEY);
|
||||
diag1CmdLine = ini.ReadValue(section, DIAG_CMD_LINE1_KEY);
|
||||
}
|
||||
|
||||
bool useDiag2 = Convert.ToBoolean(ini.ReadValue(section, USE_DIAG_CMD_LINE2_KEY));
|
||||
string diag2File = "Not Set";
|
||||
string diag2CmdLine = "Not Set";
|
||||
if (useDiag2 == true)
|
||||
{
|
||||
diag2File = ini.ReadValue(section, DIAG_FILE2_KEY);
|
||||
diag2CmdLine = ini.ReadValue(section, DIAG_CMD_LINE2_KEY);
|
||||
}
|
||||
|
||||
JtagJobInfo info = new JtagJobInfo();
|
||||
info.bsxFilePath = bsxFilePath;
|
||||
info.bsxFile = bsxFile;
|
||||
info.bsxFileCommandline = bsxCmdLine;
|
||||
|
||||
info.shallWeUseDiag1 = useDiag1;
|
||||
info.diag1File = diag2File;
|
||||
info.diag1CmdLine = diag1CmdLine;
|
||||
|
||||
info.shallWeUseDiag2 = useDiag2;
|
||||
info.diag2File = diag2File;
|
||||
info.diag2CmdLine = diag2CmdLine;
|
||||
|
||||
_jtagMeasurements.Add(section.ToUpper(), info);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
/// constructor that uses instrument manager
|
||||
/// </summary>
|
||||
/// <param name="instrumentManager"></param>
|
||||
/// <param name="instrumentName"></param>
|
||||
/// <param name="measurementDefFile"></param>
|
||||
public JtagMeasurementManager(IInstrumentManager instrumentManager, string instrumentName, string measurementDefFile = "")
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
_jtagMeasurements = new Dictionary<string, JtagJobInfo>(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
_jtag = instrumentManager.GetInstrument<IJtag>(instrumentName);
|
||||
_jtag?.Initialize();
|
||||
|
||||
if (string.IsNullOrEmpty(measurementDefFile))
|
||||
measurementDefFile = "JtagMeasurementManager.xml";
|
||||
|
||||
// parse the ini file for measurement definitions
|
||||
ParseMeasurementDef(new ConfigurationFile(measurementDefFile));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of resources
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//Do not rethrow. Exception from error logger that has already been garbage collected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<string> GetJtagMeasurementList()
|
||||
{
|
||||
return _jtagMeasurements.Keys.ToList();
|
||||
//List<string> measurements = new List<string>();
|
||||
//foreach (KeyValuePair<string, JtagJobInfo> entry in _jtagMeasurements)
|
||||
//{
|
||||
// measurements.Add(entry.Key);
|
||||
//}
|
||||
//return measurements;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform a JTAG job
|
||||
/// </summary>
|
||||
/// <param name="jobName">The name of the job as defined in the input def file</param>
|
||||
/// <returns></returns>
|
||||
public int PerformJtagJob(string jobName)
|
||||
{
|
||||
if (_jtagMeasurements.ContainsKey(jobName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find measurement: " + jobName);
|
||||
}
|
||||
|
||||
JtagJobInfo measurement = _jtagMeasurements[jobName.ToUpper()];
|
||||
|
||||
return _jtag.PerformJtagJob(measurement);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>JtagMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Jtag Measurement Manager</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.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.InstrumentManager.Contracts" Version="1.8.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.Jtag.Contracts" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,225 @@
|
||||
using Raytheon.Instruments;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MeasurementManagerLib
|
||||
{
|
||||
public class OpticalBenchMeasurementManager
|
||||
{
|
||||
private readonly ICommDevice _opticalBench;
|
||||
|
||||
/// <summary>
|
||||
/// constructor that uses instrument manager
|
||||
/// </summary>
|
||||
/// <param name="instrumentManager"></param>
|
||||
/// <param name="instrumentName"></param>
|
||||
/// <param name="measurementDefFile"></param>
|
||||
/// <param name="instrumentDefFile"></param>
|
||||
public OpticalBenchMeasurementManager(IInstrumentManager instrumentManager, string instrumentName, string measurementDefFile, string instrumentDefFile)
|
||||
{
|
||||
_opticalBench = instrumentManager.GetInstrument<ICommDevice>(instrumentName);
|
||||
_opticalBench?.Initialize();
|
||||
}
|
||||
|
||||
public void CloseShutter()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> GetTargetWheelNames()
|
||||
{
|
||||
List<string> strs;
|
||||
try
|
||||
{
|
||||
strs = null;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
return strs;
|
||||
}
|
||||
|
||||
public void MoveSeekerAbs(double az, double el)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveSeekerAbs(double az, double el, double rl)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenShutter()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetBackgroundScene(int scene)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetBlackBodySetpointTemperature(double temperature)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetChopperFrequency(double frequency)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetChopperOff()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetChopperOn()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFilterWheel(int filter)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTargetPosition(double az, double el)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTargetSize(double size)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTargetSource(int source)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTargetWheel(string targetName)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFocus(double position)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void CenterTargetOnPixel(int pixelX, int pixelY, double chopperRate, double minAmp, double maxOE)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadProfile()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>OpticalBenchMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Optical Bench Measurement Manager</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLog" Version="5.0.0" />
|
||||
<PackageReference Include="Raytheon.Common" Version="1.0.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.InstrumentManager.Contracts" Version="1.8.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.CommDevice.Contracts" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,780 @@
|
||||
// UNCLASSIFIED
|
||||
/*-------------------------------------------------------------------------
|
||||
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
|
||||
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
|
||||
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
|
||||
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
|
||||
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
|
||||
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
|
||||
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
|
||||
COMPANY.
|
||||
|
||||
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
|
||||
GOVERNMENT.
|
||||
|
||||
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Ignore Spelling: Selftest ovp ocp
|
||||
|
||||
using NLog;
|
||||
using Raytheon.Instruments;
|
||||
using Raytheon.Instruments.PowerSupply;
|
||||
using Raytheon.Common;
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace MeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry point for the library that controls power supplies.
|
||||
/// This class parses out the definition of all power supplies in a system and provides control to the host.
|
||||
/// In simple cases, the host only needs to fill in the ini file and use the OutputDisable() and OutputEnable() functions.
|
||||
/// A variety of other capability is exposed for more complex applications.
|
||||
/// </summary>
|
||||
public class PowerSupplyMeasurementManager : IDisposable
|
||||
{
|
||||
#region PublicClassMembers
|
||||
/// <summary>
|
||||
/// A callback definition for the power monitor.
|
||||
/// The host may pass in this delegate to PowerLogStart() to receive callbacks from the monitor thread.
|
||||
/// </summary>
|
||||
/// <param name="retData">The callback returns a comma delimited string of the format: "System, Module, voltage, voltage setpoint, current, output status, fault status";</param>
|
||||
/// <param name="errorCode">If an exception is thrown in the monitor thread, this value will be set to -1, else it will be 0;</param>
|
||||
public delegate void PowerMonitorDelegate(List<PowerMonitorCallbackData> retData, int errorCode);
|
||||
|
||||
#endregion
|
||||
|
||||
#region PrivateClassMembers
|
||||
// power system name to power system object
|
||||
private SortedDictionary<string, IPowerSupplySystem> _powerSystemNameToObjectMap;
|
||||
|
||||
// power module name to power system object
|
||||
private SortedDictionary<string, IPowerSupplySystem> _powerModuleNameToObjectMap;
|
||||
private PowerSupplyDataLogWorker _dataLogWorker;
|
||||
private Thread _dataLogThread;
|
||||
|
||||
// these are used to remember the logging thread params if the host is loading new power def files
|
||||
string _prevPowerLogFileName;
|
||||
int _prevPowerLogRestTime;
|
||||
PowerMonitorDelegate _prevPowerLogCallback;
|
||||
|
||||
private static NLog.ILogger _logger;
|
||||
private IInstrumentManager _instrumentManager;
|
||||
|
||||
private string _powerSystemWithFailedSelfTest = String.Empty;
|
||||
|
||||
#endregion
|
||||
|
||||
#region PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
/// will create an array of power systems with power supplies
|
||||
/// </summary>
|
||||
/// <param name="instrumentManager"></param>
|
||||
/// <param name="powerSupplySystems"></param>
|
||||
public PowerSupplyMeasurementManager(IInstrumentManager instrumentManager)
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
_instrumentManager = instrumentManager;
|
||||
|
||||
_powerSystemNameToObjectMap = new SortedDictionary<string, IPowerSupplySystem>();
|
||||
|
||||
// create some maps to support the functions the MAL input
|
||||
_powerSystemNameToObjectMap = new SortedDictionary<string, IPowerSupplySystem>(StringComparer.InvariantCultureIgnoreCase);
|
||||
_powerModuleNameToObjectMap = new SortedDictionary<string, IPowerSupplySystem>(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
ICollection<object> powerSystemList = _instrumentManager.GetInstruments(typeof(IPowerSupplySystem));
|
||||
// populate the maps
|
||||
foreach (IPowerSupplySystem powerSystem in powerSystemList)
|
||||
{
|
||||
powerSystem.Initialize();
|
||||
_powerSystemNameToObjectMap[powerSystem.Name.ToUpper()] = powerSystem;
|
||||
|
||||
List<string> moduleNames = powerSystem.GetModuleNames();
|
||||
|
||||
foreach (string moduleName in moduleNames)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()))
|
||||
{
|
||||
throw new Exception("There is more than 1 power system that have the same module name: " + moduleName);
|
||||
}
|
||||
|
||||
_powerModuleNameToObjectMap[moduleName.ToUpper()] = powerSystem;
|
||||
}
|
||||
}
|
||||
|
||||
PerformPowerSupplySelfTests();
|
||||
|
||||
if (_powerSystemWithFailedSelfTest != String.Empty)
|
||||
{
|
||||
throw new Exception($"{_powerSystemWithFailedSelfTest}'s self-test failed.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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)
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
private void PerformPowerSupplySelfTests()
|
||||
{
|
||||
_logger.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
|
||||
|
||||
string errorMsg = String.Empty;
|
||||
|
||||
ICollection<object> powerSystemList = _instrumentManager.GetInstruments(typeof(IPowerSupplySystem));
|
||||
|
||||
Task[] taskArray = new Task[powerSystemList.Count];
|
||||
|
||||
int index = 0;
|
||||
foreach (IPowerSupplySystem powerSystem in powerSystemList)
|
||||
{
|
||||
// perform self test on power system
|
||||
Task task = Task.Factory.StartNew(() => PerformPowerSupplySelfTestTask(powerSystem));
|
||||
taskArray.SetValue(task,index++);
|
||||
}
|
||||
|
||||
Task.WaitAll(taskArray);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform self test on power supply system
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
private void PerformPowerSupplySelfTestTask(IPowerSupplySystem powerSystem)
|
||||
{
|
||||
SelfTestResult result = SelfTestResult.Pass;
|
||||
|
||||
_logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() for {powerSystem.Name} is running...");
|
||||
|
||||
try
|
||||
{
|
||||
result = powerSystem.PerformSelfTest();
|
||||
|
||||
if (result == SelfTestResult.Fail && String.IsNullOrEmpty(_powerSystemWithFailedSelfTest))
|
||||
{
|
||||
_powerSystemWithFailedSelfTest = powerSystem.Name;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger?.Error(ex.Message + "\n" + ex.StackTrace);
|
||||
}
|
||||
|
||||
_logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() for {powerSystem.Name} is exiting...");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disable the power supply display interface.
|
||||
/// </summary>
|
||||
/// <param name="powerSystem">The name of the system to disable, as defined in the config file</param>
|
||||
public void DisplayDisable(string powerSystem)
|
||||
{
|
||||
if (_powerSystemNameToObjectMap.ContainsKey(powerSystem.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find power system: " + powerSystem);
|
||||
}
|
||||
|
||||
_powerSystemNameToObjectMap[powerSystem.ToUpper()].DisplayEnabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable the power supply display interface.
|
||||
/// </summary>
|
||||
/// <param name="powerSystem">The name of the system to disable, as defined in the config file</param>
|
||||
public void DisplayEnable(string powerSystem)
|
||||
{
|
||||
if (_powerSystemNameToObjectMap.ContainsKey(powerSystem.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find power system: " + powerSystem);
|
||||
}
|
||||
|
||||
_powerSystemNameToObjectMap[powerSystem.ToUpper()].DisplayEnabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this object.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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>
|
||||
/// Get all of the power module names
|
||||
/// </summary>
|
||||
/// <returns>Array of the system/module names.</returns>
|
||||
public List<string> GetPowerModuleList()
|
||||
{
|
||||
List<string> powerModules = new List<string>();
|
||||
|
||||
foreach (KeyValuePair<string, IPowerSupplySystem> item in _powerModuleNameToObjectMap)
|
||||
{
|
||||
powerModules.Add(item.Key);
|
||||
}
|
||||
|
||||
return powerModules;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the power module names for a given system
|
||||
/// </summary>
|
||||
/// <returns>Array of the system/module names.</returns>
|
||||
public List<string> GetPowerSupplyList(string powerSystem)
|
||||
{
|
||||
if (_powerSystemNameToObjectMap.ContainsKey(powerSystem.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Unknown power system: " + powerSystem);
|
||||
}
|
||||
|
||||
return _powerSystemNameToObjectMap[powerSystem.ToUpper()].GetModuleNames();
|
||||
}//GetPowerSupplyModuleInfoDict
|
||||
|
||||
/// <summary>
|
||||
/// Get the dictionary that contains configuration information for each module
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Dictionary<string, PowerSupplyModuleInfo> GetPowerSupplyModuleInfoDict(string powerSystem)
|
||||
{
|
||||
if (_powerSystemNameToObjectMap.ContainsKey(powerSystem.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Unknown power system: " + powerSystem);
|
||||
}
|
||||
|
||||
return _powerSystemNameToObjectMap[powerSystem.ToUpper()].GetPowerSupplyModuleInfoDict(powerSystem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Power System names.
|
||||
/// </summary>
|
||||
/// <returns>Array of power system names, as defined in the config file</returns>
|
||||
public List<string> GetPowerSupplySystemList()
|
||||
{
|
||||
List<string> powerSystems = new List<string>();
|
||||
|
||||
foreach (KeyValuePair<string, IPowerSupplySystem> item in _powerSystemNameToObjectMap)
|
||||
{
|
||||
powerSystems.Add(item.Key);
|
||||
}
|
||||
|
||||
return powerSystems;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query the supply and returns the programed OCP. Should match what was in the definition file.
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The name of the power supply.</param>
|
||||
/// <returns>The programmed overcurrent protection value</returns>
|
||||
public double GetOverCurrentProtection(string moduleName)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
return _powerModuleNameToObjectMap[moduleName.ToUpper()].GetOverCurrentSetting(moduleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query the supply and returns the programed OVP. Should match what was in the definition file.
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The name of the power supply.</param>
|
||||
/// <returns>The programmed overvoltage protection value.</returns>
|
||||
public double GetOverVoltageProtection(string moduleName)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
return _powerModuleNameToObjectMap[moduleName.ToUpper()].GetOverVoltageSetting(moduleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query the supply and returns the programed slew rate
|
||||
/// </summary>
|
||||
/// <param name="moduleName"></param>
|
||||
/// <returns>The programmed slew rate</returns>
|
||||
public double GetSlewRate(string moduleName)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
return _powerModuleNameToObjectMap[moduleName.ToUpper()].GetSlewRate(moduleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query the system that contains the passed in module and returns the system error code.
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The module to query.</param>
|
||||
/// <param name="errorCode">The error code.</param>
|
||||
/// <returns>The string form of the error code. Will be empty string if there is no error.</returns>
|
||||
public string GetSystemErrorCode(string moduleName, out int errorCode)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
return _powerModuleNameToObjectMap[moduleName.ToUpper()].GetErrorCode(out errorCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query the supply and returns the programmed voltage setpoint.
|
||||
/// After construction, this should match what was in the definition file.
|
||||
/// The host may override the value by calling SetVoltageSetpoint().
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The name of the power supply.</param>
|
||||
/// <returns>The programmed voltage setpoint.</returns>
|
||||
public double GetVoltageSetpoint(string moduleName)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
return _powerModuleNameToObjectMap[moduleName.ToUpper()].GetVoltageSetting(moduleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query the supply and returns true if output is enabled.
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The name of the power supply.</param>
|
||||
/// <returns>True if output is enabled, false if it is not enabled.</returns>
|
||||
public bool IsPowerSupplyOn(string moduleName)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
return _powerModuleNameToObjectMap[moduleName.ToUpper()].IsOutputOn(moduleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a SCPI command to the power system and reads the response
|
||||
/// </summary>
|
||||
/// <param name="powerSystem">The name of the power system.</param>
|
||||
/// <param name="command">The SCPI command to send</param>
|
||||
/// <returns></returns>
|
||||
public string IOQuery(string powerSystem, string command)
|
||||
{
|
||||
if (_powerSystemNameToObjectMap.ContainsKey(powerSystem.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find power system: " + powerSystem);
|
||||
}
|
||||
|
||||
return _powerSystemNameToObjectMap[powerSystem.ToUpper()].IOQuery(command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a SCPI command to the power system
|
||||
/// </summary>
|
||||
/// <param name="powerSystem">The name of the power system.</param>
|
||||
/// <param name="command">The SCPI command to send</param>
|
||||
public void IOWrite(string powerSystem, string command)
|
||||
{
|
||||
if (_powerSystemNameToObjectMap.ContainsKey(powerSystem.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find power system: " + powerSystem);
|
||||
}
|
||||
|
||||
_powerSystemNameToObjectMap[powerSystem.ToUpper()].IOWrite(command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the current of a module.
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The module to read.</param>
|
||||
/// <returns>The current (Amps).</returns>
|
||||
public double MeasureCurrent(string moduleName)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
return _powerModuleNameToObjectMap[moduleName.ToUpper()].MeasureCurrent(moduleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query the supply for its voltage.
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The module to read.</param>
|
||||
/// <returns>The voltage (Volts).</returns>
|
||||
public double MeasureVoltage(string moduleName)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
return _powerModuleNameToObjectMap[moduleName.ToUpper()].MeasureVoltage(moduleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disable the output of the power supply.
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The name of the power supply module.</param>
|
||||
public void OutputDisable(string moduleName)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
_powerModuleNameToObjectMap[moduleName.ToUpper()].Off(moduleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable the output of the power supply.
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The name of the module to enable.</param>
|
||||
public void OutputEnable(string moduleName)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
_powerModuleNameToObjectMap[moduleName.ToUpper()].On(moduleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// start logging of power supply data.
|
||||
/// Queries the list of all power modules.
|
||||
/// Logs data to the define path.
|
||||
/// Returns data to defined callback function.
|
||||
/// </summary>
|
||||
/// <param name="fileName">Path to create the log file.</param>
|
||||
/// <param name="threadRestTimeMs">The time to wait between queries.</param>
|
||||
/// <param name="callback">Function to call. Null can be passed in in which case no hot callback will be issued</param>
|
||||
public void PowerLogStart(string fileName, int threadRestTimeMs, PowerMonitorDelegate callback)
|
||||
{
|
||||
// if we have been running before, stop just in case the host did not
|
||||
if (_dataLogWorker != null)
|
||||
{
|
||||
PowerLogStop();
|
||||
|
||||
_dataLogWorker.Dispose();
|
||||
}
|
||||
|
||||
_dataLogWorker = new PowerSupplyDataLogWorker(this, fileName, threadRestTimeMs, callback);
|
||||
|
||||
_dataLogThread = new Thread(_dataLogWorker.DoWork);
|
||||
|
||||
// start the thread back up
|
||||
_dataLogThread.Start();
|
||||
|
||||
_prevPowerLogFileName = fileName;
|
||||
_prevPowerLogRestTime = threadRestTimeMs;
|
||||
_prevPowerLogCallback = callback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// stops logging data and closes the file.
|
||||
/// </summary>
|
||||
public void PowerLogStop()
|
||||
{
|
||||
// Wait up to 5 seconds for the thread to quit
|
||||
const int THREAD_QUIT_TIMEOUT_MS = 5000;
|
||||
|
||||
string functionName = $"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}()";
|
||||
|
||||
if (_dataLogWorker != null)
|
||||
{
|
||||
_dataLogWorker.QuitWork();
|
||||
|
||||
if ((_dataLogThread != null) && _dataLogThread.IsAlive)
|
||||
{
|
||||
bool didThreadQuit = _dataLogThread.Join(THREAD_QUIT_TIMEOUT_MS);
|
||||
|
||||
if (didThreadQuit == false)
|
||||
{
|
||||
_logger.Error($"{functionName} - Logging Thread did not quit as expected, aborting it");
|
||||
_dataLogThread.Abort();
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("{functionName} - Logging Thread quit successfully after join");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("{functionName} - Logging Thread quit successfully");
|
||||
}
|
||||
}
|
||||
|
||||
_prevPowerLogFileName = null;
|
||||
_prevPowerLogRestTime = 0;
|
||||
_prevPowerLogCallback = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Control the power supply internal mechanical relay state
|
||||
/// </summary>
|
||||
/// <param name="shallWeConnect">True to connect, false to disconnect</param>
|
||||
public void MechanicalRelayOutputControl(string moduleName, bool shallWeConnect)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
_powerModuleNameToObjectMap[moduleName.ToUpper()].MechanicalRelayOutputControl(moduleName, shallWeConnect);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query all power supply data in a single call.
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The name of the module to query.</param>
|
||||
/// <param name="voltage">The voltage that was read.</param>
|
||||
/// <param name="voltageSetpoint">The voltage setpoint that was read.</param>
|
||||
/// <param name="current">The current that was read.</param>
|
||||
/// <param name="outputStatus">The output status. True if output is enabled, false if output is disabled.</param>
|
||||
/// <param name="faultStatus">The value of the fault status register. See power supply docs for meaning (0 means no fault).</param>
|
||||
/*public void ReadPowerData(string moduleName, out double voltage, out double voltageSetpoint, out double current, out bool outputStatus, out int faultStatus)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("PowerSupplyManager::ReadPowerData() - could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
_powerModuleNameToObjectMap[moduleName.ToUpper()].ReadPowerData(moduleName, out voltage, out voltageSetpoint, out current, out outputStatus, out faultStatus);
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// Query all power supply data in a single call.
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The name of the module to query.</param>
|
||||
public PowerData ReadPowerData(string moduleName)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
return _powerModuleNameToObjectMap[moduleName.ToUpper()].ReadPowerData(moduleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="moduleName"></param>
|
||||
/// <returns></returns>
|
||||
public int ReadProtectionStatus(string moduleName)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
return _powerModuleNameToObjectMap[moduleName.ToUpper()].ReadProtectionStatus(moduleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the setpoint voltage to the value contained in the ini file
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The module to reset</param>
|
||||
public void SetInitialVoltage(string moduleName)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
_powerModuleNameToObjectMap[moduleName.ToUpper()].SetInitialVoltage(moduleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Every power supply gets its voltage set to what was in the ini file
|
||||
/// </summary>
|
||||
public void SetInitialVoltageAll()
|
||||
{
|
||||
List<string> powerModules = GetPowerModuleList();
|
||||
foreach (string powerModule in powerModules)
|
||||
{
|
||||
SetInitialVoltage(powerModule);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the slew rate in volts per second
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The name of the power module</param>
|
||||
/// <param name="slewRate">slew in volts per second</param>
|
||||
/*public void SetSlewRate(string moduleName, double slewRate)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("PowerSupplyManager::SetSlewRate() - could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
_powerModuleNameToObjectMap[moduleName.ToUpper()].SetSlewRate(moduleName, slewRate);
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="moduleName"></param>
|
||||
/// <param name="ocpValue"></param>
|
||||
public void SetOverCurrentProtection(string moduleName, double ocpValue)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
_powerModuleNameToObjectMap[moduleName.ToUpper()].SetOverCurrentProtection(moduleName, ocpValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="moduleName"></param>
|
||||
/// <param name="ovpValue"></param>
|
||||
public void SetOverVoltageProtection(string moduleName, double ovpValue)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
_powerModuleNameToObjectMap[moduleName.ToUpper()].SetOverVoltageProtection(moduleName, ovpValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the setpoint voltage of a module.
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The module to set.</param>
|
||||
/// <param name="setpointVoltage">The setpoint voltage.</param>
|
||||
public void SetVoltageSetpoint(string moduleName, double setpointVoltage)
|
||||
{
|
||||
if (_powerModuleNameToObjectMap.ContainsKey(moduleName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find module: " + moduleName);
|
||||
}
|
||||
|
||||
_powerModuleNameToObjectMap[moduleName.ToUpper()].SetVoltageSetpoint(moduleName, setpointVoltage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disable the power system watchdog.
|
||||
/// </summary>
|
||||
/// <param name="powerSystem">The power system to act on.</param>
|
||||
public void WatchdogDisable(string powerSystem)
|
||||
{
|
||||
if (_powerSystemNameToObjectMap.ContainsKey(powerSystem.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find power system: " + powerSystem);
|
||||
}
|
||||
|
||||
_powerSystemNameToObjectMap[powerSystem.ToUpper()].WatchdogDisable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable the power system watchdog.
|
||||
/// </summary>
|
||||
/// <param name="powerSystem">The system to act on.</param>
|
||||
/// <param name="timeInSeconds">The number of seconds for the watchdog.</param>
|
||||
public void WatchdogEnable(string powerSystem, uint timeInSeconds)
|
||||
{
|
||||
if (_powerSystemNameToObjectMap.ContainsKey(powerSystem.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("Could not find power system: " + powerSystem);
|
||||
}
|
||||
|
||||
_powerSystemNameToObjectMap[powerSystem.ToUpper()].WatchdogEnable(timeInSeconds);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PrivateClassFunctions
|
||||
/// <summary>
|
||||
/// The Finalizer
|
||||
/// </summary>
|
||||
~PowerSupplyMeasurementManager()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this object.
|
||||
/// </summary>
|
||||
/// <param name="disposing">True = currently disposing, False = not disposing.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_logger.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
|
||||
|
||||
// stop the logging if it is still running
|
||||
try
|
||||
{
|
||||
PowerLogStop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex.Message + "\r\n" + ex.StackTrace);
|
||||
}
|
||||
|
||||
// dispose the thread
|
||||
try
|
||||
{
|
||||
if (_dataLogWorker != null)
|
||||
{
|
||||
_dataLogWorker.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex.Message + "\r\n" + ex.StackTrace);
|
||||
}
|
||||
|
||||
// dispose of the other resources
|
||||
foreach (KeyValuePair<string, IPowerSupplySystem> entry in _powerSystemNameToObjectMap)
|
||||
{
|
||||
try
|
||||
{
|
||||
entry.Value.Shutdown();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex.Message + "\r\n" + ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>PowerSupplyMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Power Supply Measurement Manager</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLog" Version="5.0.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.InstrumentManager.Contracts" Version="1.8.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.PowerSupplySystem.Contracts" Version="1.3.0" />
|
||||
<PackageReference Include="Raytheon.Common" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,246 @@
|
||||
// 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.Threading;
|
||||
using Raytheon.Common;
|
||||
using System.IO;
|
||||
using Raytheon.Instruments;
|
||||
using Raytheon.Instruments.PowerSupply;
|
||||
|
||||
namespace MeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// A worker for iterating through each supply in the system, querying its' data, logging it out, and issuing callbacks to the host
|
||||
/// </summary>
|
||||
internal class PowerSupplyDataLogWorker : IWorkerInterface
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
|
||||
private bool _threadQuitControl;
|
||||
private AutoResetEvent _quitEvent;
|
||||
private StreamWriter _fileWriter;
|
||||
private readonly string _logFilePath;
|
||||
private readonly int _threadRestTimeMs;
|
||||
private readonly PowerSupplyMeasurementManager.PowerMonitorDelegate _callback;
|
||||
private readonly PowerSupplyMeasurementManager _controller;
|
||||
|
||||
#endregion
|
||||
|
||||
#region PrivateFunctions
|
||||
|
||||
/// <summary>
|
||||
/// Finalizer
|
||||
/// </summary>
|
||||
~PowerSupplyDataLogWorker()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release of resources
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_fileWriter.Dispose();
|
||||
|
||||
_quitEvent.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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 PublicFuctions
|
||||
|
||||
/// <summary>
|
||||
/// The constructor
|
||||
/// </summary>
|
||||
/// <param name="controller">The controller for the power supplies</param>
|
||||
/// <param name="fileName">The file name to log the data to</param>
|
||||
/// <param name="threadRestTimeMs">The number os ms to rest after each iteration through the loop</param>
|
||||
/// <param name="callback">The host callback function. If null, no callback is issued</param>
|
||||
public PowerSupplyDataLogWorker(PowerSupplyMeasurementManager controller, string fileName, int threadRestTimeMs, PowerSupplyMeasurementManager.PowerMonitorDelegate callback)
|
||||
{
|
||||
_controller = controller;
|
||||
|
||||
// these gets set in SetControlParams
|
||||
_logFilePath = fileName;
|
||||
_callback = callback;
|
||||
_threadRestTimeMs = threadRestTimeMs;
|
||||
|
||||
_fileWriter = new StreamWriter(_logFilePath, true);
|
||||
|
||||
_threadQuitControl = false;
|
||||
_quitEvent = new AutoResetEvent(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this object. Needed for releasing thread/comm resources
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
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>
|
||||
/// Loops thorugh each supply in the system, queries the status, logs it out and calls the host callback
|
||||
/// </summary>
|
||||
public void DoWork()
|
||||
{
|
||||
try
|
||||
{
|
||||
//Used to handle the labels at the top of the CSV log file generated
|
||||
const string LOG_PREFIX = "DateTime,Module,Voltage,VoltageSetpoint,Current,IsOutputOn,fault status";
|
||||
|
||||
// callback error codes
|
||||
const int NO_ERROR = 0;
|
||||
const int ERROR = -1;
|
||||
|
||||
List<string> powerModules = _controller.GetPowerModuleList();
|
||||
|
||||
_fileWriter.WriteLine(LOG_PREFIX);
|
||||
|
||||
while (_threadQuitControl == false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_quitEvent.WaitOne(_threadRestTimeMs))
|
||||
{
|
||||
_threadQuitControl = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//string callbackData = CALLBACK_PREFIX;
|
||||
List<PowerMonitorCallbackData> callBackDataList = new List<PowerMonitorCallbackData>();
|
||||
|
||||
//get data from each supply
|
||||
foreach (string powerModule in powerModules)
|
||||
{
|
||||
// check for quit event and exit if needed
|
||||
if (_quitEvent.WaitOne(1) == true)
|
||||
{
|
||||
_threadQuitControl = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
PowerData data = _controller.ReadPowerData(powerModule);
|
||||
|
||||
PowerMonitorCallbackData callbackData;
|
||||
callbackData.powerModule = powerModule;
|
||||
callbackData.voltage = data.Voltage;
|
||||
callbackData.voltageSetpoint = data.VoltageSetpoint;
|
||||
callbackData.current = data.Current;
|
||||
callbackData.outputStatus = data.OutputStatus;
|
||||
callbackData.ovpocpStatus = data.FaultStatus;
|
||||
callbackData.overVoltageProtectionValue = data.OverVoltageProtection;
|
||||
callbackData.overCurrentProtectionValue = data.OverCurrentProtection;
|
||||
|
||||
callBackDataList.Add(callbackData);
|
||||
|
||||
string log = Util.GetTimeString() + "," + powerModule + "," + Convert.ToString(data.Voltage) + "," + Convert.ToString(data.VoltageSetpoint) + "," + Convert.ToString(data.Current) + "," + Convert.ToString(data.OutputStatus) + "," + Convert.ToString(data.FaultStatus);
|
||||
|
||||
// log out the data
|
||||
_fileWriter.WriteLine(log);
|
||||
_fileWriter.Flush();
|
||||
|
||||
// check for quit event and exit if needed
|
||||
if (_quitEvent.WaitOne(1) == true)
|
||||
{
|
||||
_threadQuitControl = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point our return and log strings are both built, so return back the data string on the callback
|
||||
if (_callback != null && _threadQuitControl == false && callBackDataList.Count != 0)
|
||||
{
|
||||
_callback(callBackDataList, NO_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string msg = e.Message;
|
||||
|
||||
ErrorLogger.Instance().Write(msg + "\r\n" + e.StackTrace, ErrorLogger.LogLevel.ERROR);
|
||||
|
||||
_fileWriter.WriteLine(Util.GetTimeString() + ", " + msg);
|
||||
|
||||
// if callbacks are enabled, alert the host to the error
|
||||
if (_callback != null && _threadQuitControl == false)
|
||||
{
|
||||
_callback(null, ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ErrorLogger.Instance().Write("PowerSupplyDataLogWorker::DoWork() - exiting", ErrorLogger.LogLevel.INFO);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the thread, closes the datalogger and calls move file
|
||||
/// </summary>
|
||||
public void QuitWork()
|
||||
{
|
||||
_threadQuitControl = true;
|
||||
|
||||
_quitEvent.Set();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,369 @@
|
||||
// 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.Linq;
|
||||
|
||||
namespace MeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class manages ISwitch instruments (That act as Relays) and provides an abstraction
|
||||
/// </summary>
|
||||
public class RelayMeasurementManager : IDisposable
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
public enum InitialState
|
||||
{
|
||||
OPEN,
|
||||
CLOSED
|
||||
};
|
||||
|
||||
[Serializable]
|
||||
public class RelayInfo
|
||||
{
|
||||
public string RelayModule { get; set; }
|
||||
public string Relay { get; set; }
|
||||
|
||||
public List<string> Relays { get; set; } = new List<string>();
|
||||
|
||||
public InitialState InitialState { get; set; }
|
||||
|
||||
public RelayInfo()
|
||||
{
|
||||
InitialState = InitialState.OPEN;
|
||||
RelayModule = string.Empty;
|
||||
Relay = string.Empty;
|
||||
}
|
||||
|
||||
public RelayInfo(string relayModule, string relay, InitialState initialState)
|
||||
{
|
||||
RelayModule = relayModule;
|
||||
Relay = relay;
|
||||
InitialState = initialState;
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly object _syncObj = new Object();
|
||||
private readonly Dictionary<string, ISwitch> _relayCards;
|
||||
private readonly Dictionary<string, RelayInfo> _relayMeasurementMap;
|
||||
|
||||
private const string RELAY_MEASUREMENTS = "RelayMeasurements";
|
||||
|
||||
//const char COMMA_DELIM = ',';
|
||||
private const char FIELD_DELIM = '|';
|
||||
private const char DASH_DELIM = '-';
|
||||
|
||||
private static NLog.ILogger _logger;
|
||||
|
||||
#endregion
|
||||
|
||||
#region PrivateClassFunctions
|
||||
|
||||
/// <summary>
|
||||
/// The Finalizer
|
||||
/// </summary>
|
||||
~RelayMeasurementManager()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Confirm each relay entry in the measurement file refers back to a card in the instrument file
|
||||
/// </summary>
|
||||
private void CheckForValidRelayFormat()
|
||||
{
|
||||
foreach (KeyValuePair<string, RelayInfo> entry in _relayMeasurementMap)
|
||||
{
|
||||
RelayInfo relays = entry.Value;
|
||||
|
||||
if (_relayCards.ContainsKey(relays.RelayModule) == false)
|
||||
{
|
||||
throw new Exception("relay card field does not exist: " + relays.RelayModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
foreach (KeyValuePair<string, ISwitch> relayCard in _relayCards)
|
||||
{
|
||||
if (_relayCards[relayCard.Key] != null)
|
||||
{
|
||||
_relayCards[relayCard.Key].Shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//Do not rethrow. Exception from error logger that has already been garbage collected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the ini file for measurement definitions
|
||||
/// Populates the Dictionaries with the enum names and ini file data
|
||||
/// </summary>
|
||||
private void ParseMeasurementDef(string defFile)
|
||||
{
|
||||
IniFile iniReader = new IniFile(defFile);
|
||||
|
||||
// read in all of the sections
|
||||
List<string> keys = iniReader.ReadAllKeys(RELAY_MEASUREMENTS);
|
||||
|
||||
foreach (string key in keys)
|
||||
{
|
||||
string value = iniReader.ReadValue(RELAY_MEASUREMENTS, key);
|
||||
|
||||
List<string> field = value.Split(FIELD_DELIM).ToList();
|
||||
|
||||
if (field.Count != 2)
|
||||
{
|
||||
throw new Exception("expected two fields on line: " + value);
|
||||
}
|
||||
|
||||
string relayItem = field[0];
|
||||
|
||||
List<string> relayDef = relayItem.Split(DASH_DELIM).ToList();
|
||||
|
||||
if (relayDef.Count != 2)
|
||||
{
|
||||
throw new Exception("Relay Entry : " + relayItem + " did not have two tokens as expected");
|
||||
}
|
||||
|
||||
string relayCard = relayDef[0].Trim().ToUpper();
|
||||
string relay = relayDef[1].Trim();
|
||||
|
||||
InitialState initState = (InitialState)Enum.Parse(typeof(InitialState), field[1], true);
|
||||
|
||||
RelayInfo relayInfo = new RelayInfo(relayCard, relay, initState);
|
||||
|
||||
_relayMeasurementMap[key.ToUpper()] = relayInfo;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PublicClassFunctions
|
||||
|
||||
/// <summary>
|
||||
/// constructor that uses instrument manager for building instruments
|
||||
/// </summary>
|
||||
/// <param name="instrumentManager"></param>
|
||||
/// <param name="instrumentNames"></param>
|
||||
/// <param name="logFileName"></param>
|
||||
public RelayMeasurementManager(IInstrumentManager instrumentManager, List<string> instrumentNames, string configFileName = "")
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
_relayMeasurementMap = new Dictionary<string, RelayInfo>();
|
||||
_relayCards = new Dictionary<string, ISwitch>();
|
||||
|
||||
foreach (string name in instrumentNames)
|
||||
{
|
||||
_relayCards[name] = instrumentManager.GetInstrument<ISwitch>(name);
|
||||
_relayCards[name]?.Initialize();
|
||||
}
|
||||
|
||||
if(string.IsNullOrEmpty(configFileName))
|
||||
{
|
||||
configFileName = "RelayMeasurementManager.xml";
|
||||
}
|
||||
|
||||
ConfigurationFile configurationFile = new ConfigurationFile(configFileName);
|
||||
|
||||
List<RelayInfo> relayInfoList = configurationFile.ReadList(RELAY_MEASUREMENTS, "Relays", new List<RelayInfo>());
|
||||
|
||||
foreach (var relayInfo in relayInfoList)
|
||||
{
|
||||
_relayMeasurementMap[relayInfo.RelayModule] = relayInfo;
|
||||
}
|
||||
|
||||
CheckForValidRelayFormat();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this objects resources
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//Do not rethrow. Exception from error logger that has already been garbage collected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="measurementName"></param>
|
||||
public void ConnectRelay(string measurementName)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (_relayMeasurementMap.ContainsKey(measurementName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("could not find measurement: " + measurementName);
|
||||
}
|
||||
|
||||
//get the card and relay
|
||||
RelayInfo relayInfo = _relayMeasurementMap[measurementName];
|
||||
|
||||
//close all defined relays for measurement
|
||||
if (relayInfo.Relays.Any())
|
||||
{
|
||||
foreach (var relay in relayInfo.Relays)
|
||||
{
|
||||
_relayCards[relayInfo.RelayModule.ToUpper()].Connect(relay);
|
||||
}
|
||||
}
|
||||
|
||||
//close the relay
|
||||
if (!string.IsNullOrEmpty(relayInfo.Relay))
|
||||
{
|
||||
_relayCards[relayInfo.RelayModule.ToUpper()].Connect(relayInfo.Relay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="measurementName"></param>
|
||||
public void DisconnectRelay(string measurementName)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (_relayMeasurementMap.ContainsKey(measurementName.ToUpper()) == false)
|
||||
{
|
||||
throw new Exception("could not find measurement: " + measurementName);
|
||||
}
|
||||
|
||||
//get the card and relay
|
||||
RelayInfo relayInfo = _relayMeasurementMap[measurementName];
|
||||
|
||||
//open all defined relays for measurement
|
||||
if (relayInfo.Relays.Any())
|
||||
{
|
||||
foreach (var relay in relayInfo.Relays)
|
||||
{
|
||||
_relayCards[relayInfo.RelayModule.ToUpper()].Disconnect(relay);
|
||||
}
|
||||
}
|
||||
|
||||
//open the relays
|
||||
if (!string.IsNullOrEmpty(relayInfo.Relay))
|
||||
{
|
||||
_relayCards[relayInfo.RelayModule.ToUpper()].Disconnect(relayInfo.Relay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of relay measurements
|
||||
/// </summary>
|
||||
/// <returns>A list of relays</returns>
|
||||
public List<string> GetRelayMeasurementList()
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
List<string> relayList = new List<string>();
|
||||
|
||||
foreach (KeyValuePair<string, RelayInfo> name in _relayMeasurementMap)
|
||||
{
|
||||
relayList.Add(name.Key);
|
||||
}
|
||||
|
||||
return relayList;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void ResetToInitialState()
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
foreach (KeyValuePair<string, RelayInfo> item in _relayMeasurementMap)
|
||||
{
|
||||
InitialState initState = item.Value.InitialState;
|
||||
string relayItem = item.Key;
|
||||
|
||||
if (initState == InitialState.CLOSED)
|
||||
{
|
||||
ConnectRelay(relayItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
DisconnectRelay(relayItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Command a self test on the Relay instrument
|
||||
/// </summary>
|
||||
/*public uint SelfTest()
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
SelfTestResult result = _dio.PerformSelfTest();
|
||||
|
||||
return (uint)result;
|
||||
}
|
||||
}*/
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>RelayMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Relay Measurement Manager Library</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.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.InstrumentManager.Contracts" Version="1.8.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.Switch.Contracts" Version="1.6.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>RfMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Rf Measurement Manager Library</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.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.InstrumentManager.Contracts" Version="1.8.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.PowerMeter.Contracts" Version="3.1.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.SignalGenerator.Contracts" Version="1.0.3" />
|
||||
<PackageReference Include="Raytheon.Instruments.SpecAnalyzer.Contracts" Version="1.1.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.Switch.Contracts" Version="1.6.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>SpaceChamberLspsMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Space Chamber LSPS Measurement Manager</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.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.InstrumentManager.Contracts" Version="1.8.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.LspsChamber.Contracts" Version="1.0.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.NetCdfData.Contracts" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,647 @@
|
||||
using Raytheon.Instruments;
|
||||
using STE_Library_Common;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace SpaceChamberVOBMeasurementManagerLib
|
||||
{
|
||||
public class SpaceChamberVOBMeasurementManager
|
||||
{
|
||||
private int _galicFwPos;
|
||||
|
||||
private bool _bit;
|
||||
|
||||
private string _errorDesc;
|
||||
|
||||
private bool _focusState;
|
||||
|
||||
private ICommDevice _commDevice;
|
||||
|
||||
private bool _isThereHardware;
|
||||
|
||||
private Thread _vobMonitorHealthThread;
|
||||
|
||||
private IWorkerInterface _vobMonitorHealthWorker;
|
||||
|
||||
private IMsgParser _vobMsgParser;
|
||||
|
||||
private Thread _vobUpdateThread;
|
||||
|
||||
private IWorkerInterface _vobUpdateWorker;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// constructor that uses instrument manager for creating an instrument
|
||||
/// </summary>
|
||||
/// <param name="instrumentManager"></param>
|
||||
/// <param name="deviceName"></param>
|
||||
public SpaceChamberVOBMeasurementManager(IInstrumentManager instrumentManager, string deviceName)
|
||||
{
|
||||
_commDevice = instrumentManager.GetInstrument<ICommDevice>(deviceName);
|
||||
_commDevice?.Initialize();
|
||||
}
|
||||
|
||||
public SpaceChamberVOBMeasurementManager(bool isThereHardware, string measurementDefFile, string instrumentDefFile)
|
||||
{
|
||||
if (measurementDefFile == null)
|
||||
{
|
||||
throw new ArgumentNullException("SpaceChamberVOBMeasurementManager::SpaceChamberVOBMeasurementManager() - measurementDefFile input parameter is null.");
|
||||
}
|
||||
if (instrumentDefFile == null)
|
||||
{
|
||||
throw new ArgumentNullException("SpaceChamberVOBMeasurementManager::SpaceChamberVOBMeasurementManager() - instrumentDefFile input parameter is null.");
|
||||
}
|
||||
this._isThereHardware = isThereHardware;
|
||||
}
|
||||
|
||||
public void BalanceOnPixelLocation()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void bbSetTemp(double temp, int timeout)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void chopperPowerOff()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void closeRgaGateValve()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void closeUutGateValve()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteProfilePoint(int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void disableAxis()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void enableAxis()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void galilcFocusMove(double destination, float speed, int mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void galilChopperSetFrequency(double frequency, int timeout)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public bool galilMono1Grating()
|
||||
{
|
||||
bool flag;
|
||||
try
|
||||
{
|
||||
flag = false;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
public void getAxesStatus()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void getBeamAngles()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void getBits()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public double getCoarseAngle()
|
||||
{
|
||||
double num;
|
||||
try
|
||||
{
|
||||
num = 0;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public void getCoarseSelection()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public double getFocusPosition()
|
||||
{
|
||||
double num;
|
||||
try
|
||||
{
|
||||
num = double.MaxValue;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public bool getFocusState()
|
||||
{
|
||||
bool flag;
|
||||
try
|
||||
{
|
||||
flag = false;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
public double getMirrorAngles()
|
||||
{
|
||||
double num;
|
||||
try
|
||||
{
|
||||
num = 0;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public void getRGAGateValveState()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public int getTargetWheelPos()
|
||||
{
|
||||
int num;
|
||||
try
|
||||
{
|
||||
num = 0;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public void getUutGateValveState()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void getVacuumPressures()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void getVacuumSetpoints()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void homeAxis()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void homeTargetWheel()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void homeXyAxes()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void homeXyuAxes()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void loadProfile()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void openRgaGateValve()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void openUutGateValve()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void quit()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void resetProfile()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void runProfile(int mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void SendMessageGetResponse(string command)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void setAxisPosAbs(double position, double speed)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void setAxisPosRel(double position, double speed)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetBackgroundScene(int scene)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetChopperFrequency(double frequency)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetChopperOff()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetChopperOn()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void setCoarseSel()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTargetPosition(double az, double el)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTargetSize(double size)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTargetSource(int source)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void setTargetWheel(int pos)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void setXyPos(double azPos, double elPos, double speed)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void stopAllAxes()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void stopTargetWheel()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void VssMonoSetWaveLength(double wave)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
public void CenterTargetOnPixel(int pixelX, int pixelY, double chopperRate, double minAmp, double maxOE)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFocus(double position)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\CTS.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472</TargetFrameworks>
|
||||
<AssemblyName>SpaceChamberVOBMeasurementManager</AssemblyName>
|
||||
<RootNamespace>SpaceChamberVOBMeasurementManager</RootNamespace>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Space Chamber VOB Measurement Manager</Description>
|
||||
<Company>Raytheon Technologies</Company>
|
||||
<Authors>TEEC</Authors>
|
||||
<Copyright>Copyright © Raytheon Technologies $(Year)</Copyright>
|
||||
<Version>$(Version)$(Suffix)</Version>
|
||||
<OutputType>Library</OutputType>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Configurations>Debug;Release;Deploy</Configurations>
|
||||
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
|
||||
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<NoWarn>NU5118</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Raytheon.Instruments.InstrumentManager.Contracts" Version="1.7.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SpaceChamberVOBMeasurementInstruments\SpaceChamberVOBMeasurementInstruments.csproj">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Common\Interfaces\IMsgParser.cs">
|
||||
<Link>Interfaces\IMsgParser.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Common\Interfaces\IWorkerInterface.cs">
|
||||
<Link>Interfaces\IWorkerInterface.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="..\Common\readme.md" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target DependsOnTargets="ResolveReferences" Name="CopyProjectReferencesToPackage">
|
||||
<ItemGroup>
|
||||
<BuildOutputInPackage Include="$(OutputPath)*.dll" Exclude="$(TargetPath)" />
|
||||
<BuildOutputInPackage Include="$(OutputPath)*.xml" Exclude="$(TargetPath)" />
|
||||
<BuildOutputInPackage Include="$(OutputPath)*.pdb" Exclude="$(TargetPath)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="DeleteStaleFiles" BeforeTargets="Build">
|
||||
<ItemGroup>
|
||||
<StaleFiles Include="$(MSBuildProjectDirectory)\$(OutputPath)*.nupkg" />
|
||||
</ItemGroup>
|
||||
<Message Text="Deleting Stale Files: @(StaleFiles, '%0A')" Condition="'@(StaleFiles->Count())' > 0" />
|
||||
<Delete Files="@(StaleFiles)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="Pack" Condition="'$(Configuration)' == 'Deploy'">
|
||||
<Exec Command="dotnet nuget push --source "TSRealNuget_Dev" --api-key az $(MSBuildProjectDirectory)\$(OutputPath)*.nupkg" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>SwitchMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Switch Measurement Manager</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLog" Version="5.0.0" />
|
||||
<PackageReference Include="Raytheon.Common" Version="1.0.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.InstrumentManager.Contracts" Version="1.8.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.Switch.Contracts" Version="1.6.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.Dmm.Contracts" Version="2.6.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.OscilloScope.Contracts" Version="1.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<section name="SwitchMeasurement_Lib.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
|
||||
<section name="TestStationCGuts_Lib.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
<applicationSettings>
|
||||
<SwitchMeasurement_Lib.Properties.Settings>
|
||||
<setting name="SwitchMeasurementLib_LxiPiCards_PiCards" serializeAs="String">
|
||||
<value>http://lxidevice/bin/PiCards</value>
|
||||
</setting>
|
||||
</SwitchMeasurement_Lib.Properties.Settings>
|
||||
<TestStationCGuts_Lib.Properties.Settings>
|
||||
<setting name="TestStationVsuLib_LxiPiCards_PiCards" serializeAs="String">
|
||||
<value>http://lxidevice/bin/PiCards</value>
|
||||
</setting>
|
||||
</TestStationCGuts_Lib.Properties.Settings>
|
||||
</applicationSettings>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup><system.serviceModel>
|
||||
<bindings />
|
||||
<client />
|
||||
</system.serviceModel>
|
||||
</configuration>
|
||||
@@ -0,0 +1,335 @@
|
||||
// **********************************************************************************************************
|
||||
// TelemetryMeasurementManager.cs
|
||||
// 2/19/2024
|
||||
// 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 Raytheon.Instruments;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MeasurementManagerLib
|
||||
{
|
||||
internal class TelemetryClient
|
||||
{
|
||||
public ICommAsync Client { get; set; }
|
||||
public CancellationTokenSource TokenSource { get; set; }
|
||||
public string BaseDirectory { get; set; }
|
||||
public string BaseFileName { get; set; }
|
||||
public int BufferSize { get; set; }
|
||||
public FileRecordingMode FileRecordingMode { get; set; }
|
||||
}
|
||||
|
||||
// create a resulting file based on mode
|
||||
public enum FileRecordingMode
|
||||
{
|
||||
/// <summary>
|
||||
/// use default configuration value
|
||||
/// </summary>
|
||||
Undefined,
|
||||
/// <summary>
|
||||
/// user client provided name as is
|
||||
/// overwrite the existing file
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// append date time at the end of the base file name
|
||||
/// </summary>
|
||||
UnigueDateTime,
|
||||
/// <summary>
|
||||
/// append rolling index number at the end of the file name
|
||||
/// </summary>
|
||||
UniqueIndex
|
||||
}
|
||||
|
||||
public class TelemetryMeasurementManager : IDisposable
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly Dictionary<string, TelemetryClient> _clients = new Dictionary<string, TelemetryClient>();
|
||||
|
||||
private const string DefaultConfigurationName = "TelemetryManager.xml";
|
||||
|
||||
/// <summary>
|
||||
/// adds multiple instruments for Telemetry or any other data collection
|
||||
/// </summary>
|
||||
/// <param name="instrumentManager"></param>
|
||||
/// <param name="instrumentNames"></param>
|
||||
/// <param name="configName"></param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public TelemetryMeasurementManager(IInstrumentManager instrumentManager, List<string> instrumentNames, string configName = "")
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
if (instrumentNames == null)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(instrumentNames));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(configName))
|
||||
{
|
||||
configName = DefaultConfigurationName;
|
||||
}
|
||||
IConfigurationFile config = new ConfigurationFile(configName);
|
||||
|
||||
instrumentNames.ForEach(i => AddInstrument(instrumentManager, i, config));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// starts recording for the first instrument
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="recordingMode"></param>
|
||||
public void StartRecording(string fileName = "", FileRecordingMode recordingMode = FileRecordingMode.UnigueDateTime)
|
||||
{
|
||||
StartRecording(_clients.FirstOrDefault().Key, fileName, recordingMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// starts recording for the specified instrument
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="instrumentName"></param>
|
||||
/// <param name="recordingMode"></param>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public void StartRecording(string instrumentName, string fileName = "", FileRecordingMode recordingMode = FileRecordingMode.Undefined)
|
||||
{
|
||||
if (string.IsNullOrEmpty(instrumentName) || !_clients.ContainsKey(instrumentName))
|
||||
{
|
||||
throw new InvalidOperationException($"No Telemetry Instrument Found for {instrumentName}.");
|
||||
}
|
||||
|
||||
var telemetryClient = _clients[instrumentName];
|
||||
|
||||
var client = telemetryClient.Client;
|
||||
var token = telemetryClient.TokenSource.Token;
|
||||
if(string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
fileName = telemetryClient.BaseFileName;
|
||||
}
|
||||
if(recordingMode == FileRecordingMode.Undefined)
|
||||
{
|
||||
recordingMode = telemetryClient.FileRecordingMode;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(telemetryClient.BaseDirectory))
|
||||
{
|
||||
// The directory does not exist, so create it
|
||||
Directory.CreateDirectory(telemetryClient.BaseDirectory);
|
||||
Console.WriteLine($"Directory '{telemetryClient.BaseDirectory}' created successfully.");
|
||||
}
|
||||
|
||||
string filePath = Path.Combine(telemetryClient.BaseDirectory, fileName);
|
||||
string uniqueFileName;
|
||||
|
||||
if(recordingMode == FileRecordingMode.UnigueDateTime)
|
||||
{
|
||||
uniqueFileName = GenerateUniqueFileNameDyDateTime(filePath);
|
||||
}
|
||||
else if(recordingMode == FileRecordingMode.UniqueIndex)
|
||||
{
|
||||
uniqueFileName = GenerateUniqueFileNameByIndex(filePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
uniqueFileName = fileName;
|
||||
if(File.Exists(uniqueFileName))
|
||||
{
|
||||
File.Delete(uniqueFileName);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Debug($"Starting Recording in {uniqueFileName}");
|
||||
|
||||
try
|
||||
{
|
||||
client.Initialize();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, ex.Message);
|
||||
throw;
|
||||
}
|
||||
|
||||
var fileStream = new FileStream(uniqueFileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, bufferSize: telemetryClient.BufferSize, useAsync: true);
|
||||
|
||||
// use a thread from the thread pool and provide a function to write incoming data into a file
|
||||
Task.Run(async () => await client.KeepReadingAsync(token, async (byte[] incomingData) =>
|
||||
{
|
||||
await fileStream?.WriteAsync(incomingData, 0, incomingData.Length);
|
||||
}).ContinueWith((r) =>
|
||||
{
|
||||
// done recording
|
||||
if (r.IsFaulted)
|
||||
{
|
||||
_logger.Error(r.Exception, r.Exception.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Info($"Telemetry Manager Recording Completed for {uniqueFileName}");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
client?.Close();
|
||||
client = null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
fileStream?.Dispose();
|
||||
fileStream = null;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// stops recording
|
||||
/// </summary>
|
||||
public void StopRecording()
|
||||
{
|
||||
_logger.Debug("Stopping Recording.");
|
||||
|
||||
foreach (var instrumentName in _clients.Keys)
|
||||
{
|
||||
StopRecording(instrumentName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// stops recording for specific instrument name
|
||||
/// </summary>
|
||||
/// <param name="instrumentName"></param>
|
||||
public void StopRecording(string instrumentName)
|
||||
{
|
||||
if (!_clients.ContainsKey(instrumentName))
|
||||
return;
|
||||
|
||||
_logger.Debug($"Stopping Recording for {instrumentName}.");
|
||||
|
||||
var telemetryClient = _clients[instrumentName];
|
||||
var tokenSource = telemetryClient.TokenSource;
|
||||
|
||||
if (!tokenSource.IsCancellationRequested)
|
||||
{
|
||||
tokenSource.Cancel();
|
||||
}
|
||||
tokenSource.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup code
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
StopRecording();
|
||||
|
||||
foreach (var tokenClient in _clients.Values)
|
||||
{
|
||||
var client = tokenClient?.Client;
|
||||
client?.Close();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// generates unique file name
|
||||
/// </summary>
|
||||
/// <param name="existingFilePath"></param>
|
||||
/// <returns></returns>
|
||||
private static string GenerateUniqueFileNameDyDateTime(string existingFilePath)
|
||||
{
|
||||
string directory = Path.GetDirectoryName(existingFilePath);
|
||||
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(existingFilePath);
|
||||
string extension = Path.GetExtension(existingFilePath);
|
||||
|
||||
// Append a timestamp to the original filename
|
||||
string uniqueFileName = $"{fileNameWithoutExtension}_{DateTime.Now:MMddHHmmss}{extension}";
|
||||
|
||||
// Combine with the directory path
|
||||
return Path.Combine(directory, uniqueFileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// generates unique file name based on rolling index
|
||||
/// </summary>
|
||||
/// <param name="existingFilePath"></param>
|
||||
/// <returns></returns>
|
||||
private static string GenerateUniqueFileNameByIndex(string existingFilePath)
|
||||
{
|
||||
string directoryPath = Path.GetDirectoryName(existingFilePath);
|
||||
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(existingFilePath);
|
||||
string extension = Path.GetExtension(existingFilePath);
|
||||
|
||||
int index = 1; // Initialize the rolling index
|
||||
while (File.Exists(Path.Combine(directoryPath, $"{fileNameWithoutExtension}_{index}{extension}")))
|
||||
{
|
||||
index++; // Increment the index until a unique file name is found
|
||||
}
|
||||
|
||||
// return appended index to the original filename
|
||||
return Path.Combine(directoryPath, $"{fileNameWithoutExtension}_{index}{extension}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// adds single instrument to the collection
|
||||
/// </summary>
|
||||
/// <param name="instrumentManager"></param>
|
||||
/// <param name="instrumentName"></param>
|
||||
/// <param name="config"></param>
|
||||
private void AddInstrument(IInstrumentManager instrumentManager, string instrumentName, IConfigurationFile config)
|
||||
{
|
||||
_logger.Info($"TelemetryMeasurementManager - Adding Instrument Name {instrumentName}\nConfiguration {config.FileName}");
|
||||
|
||||
string baseDirectory = config.ReadValue($"Telemetry_{instrumentName}", "Directory", $"./{instrumentName}");
|
||||
string baseFileName = config.ReadValue($"Telemetry_{instrumentName}", "BaseFileName", $"./{instrumentName}");
|
||||
FileRecordingMode fileRecordingMode = config.ReadValue($"Telemetry_{instrumentName}", "FileRecordingMode", FileRecordingMode.UnigueDateTime);
|
||||
|
||||
int bufferSize = config.ReadValue($"Telemetry_{instrumentName}", "BufferSize", 4096);
|
||||
|
||||
_clients.Add(instrumentName, new TelemetryClient
|
||||
{
|
||||
Client = (ICommAsync)instrumentManager.GetGenericInstrument(instrumentName),
|
||||
TokenSource = new CancellationTokenSource(),
|
||||
BaseDirectory = baseDirectory,
|
||||
BaseFileName = baseFileName,
|
||||
BufferSize = bufferSize,
|
||||
FileRecordingMode = fileRecordingMode,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>TelemetryMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Telemetry Measurement Manager</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.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.InstrumentManager.Contracts" Version="1.8.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.CommAsync.Contracts" Version="1.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,257 @@
|
||||
// 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.Instruments;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace MeasurementManagerLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class manages IVideoRecorder instruments and provides an abstraction
|
||||
/// </summary>
|
||||
public class VideoRecorderMeasurementManager : IDisposable
|
||||
{
|
||||
#region PublicClassMembers
|
||||
public enum AttributeType
|
||||
{
|
||||
STRING,
|
||||
INT,
|
||||
FLOAT
|
||||
};
|
||||
|
||||
public struct NcdfAttribute
|
||||
{
|
||||
public AttributeType type;
|
||||
public string key;
|
||||
public string value;
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region PrivateClassMembers
|
||||
private IVideoRecorder _videoRecorder;
|
||||
private static NLog.ILogger _logger;
|
||||
#endregion
|
||||
|
||||
#region PrivateClassFunctions
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (_videoRecorder != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_videoRecorder.Shutdown();
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PublicClassFunctions
|
||||
|
||||
public VideoRecorderMeasurementManager(IInstrumentManager instrumentManager, string deviceName)
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
_videoRecorder = instrumentManager.GetInstrument<IVideoRecorder>(deviceName);
|
||||
_videoRecorder?.Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Finalizer
|
||||
/// </summary>
|
||||
~VideoRecorderMeasurementManager()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the attributes from attributeFile(Created by CreateAttributeFile()) and insert them into videoFile
|
||||
/// </summary>
|
||||
/// <param name="videoFile"></param>
|
||||
/// <param name="attributeFile"></param>
|
||||
public void AddNcdfAttributes(string videoFile, string attributeFile)
|
||||
{
|
||||
_videoRecorder.AddNcdfAttributes(videoFile, attributeFile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connect to the video recorder
|
||||
/// </summary>
|
||||
public void Connect()
|
||||
{
|
||||
_videoRecorder.Connect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an attribute file that the video recorders can consume
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to create</param>
|
||||
/// <param name="attributeList">A list of attributes to place in the file</param>
|
||||
public static void CreateAttributeFile(string fileName, List<NcdfAttribute> attributeList)
|
||||
{
|
||||
const char DELIM = '\t';
|
||||
|
||||
// Create a file to write to.
|
||||
using (StreamWriter writer = File.CreateText(fileName))
|
||||
{
|
||||
foreach (NcdfAttribute attribute in attributeList)
|
||||
{
|
||||
string type = Convert.ToInt32(attribute.type).ToString();
|
||||
string lineToWrite = type + DELIM + attribute.key + DELIM + attribute.value;
|
||||
writer.WriteLine(lineToWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect from the video recorder
|
||||
/// </summary>
|
||||
public void Disconnect()
|
||||
{
|
||||
_videoRecorder.Disconnect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this object
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Error(err.Message + "\r\n" + err.StackTrace);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//Do not rethrow. Exception from error logger that has already been garbage collected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// record video to the hard drive. This function returns once the grab has begun, Use WaitForGrabToComplete() to know when the grab is completed
|
||||
/// </summary>
|
||||
/// <param name="numberOfFrames">The number of frames to collect</param>
|
||||
/// <param name="saveFormat">0 for binary, 1 for ncdf</param>
|
||||
public void GrabVideoToDisk(uint numberOfFrames, uint saveFormat)
|
||||
{
|
||||
var saveFormatTemp = VideoSaveFormat.BIN;
|
||||
|
||||
if ((VideoSaveFormat)saveFormat == VideoSaveFormat.BIN)
|
||||
{
|
||||
saveFormatTemp = VideoSaveFormat.BIN;
|
||||
}
|
||||
else if ((VideoSaveFormat)saveFormat == VideoSaveFormat.NCDF)
|
||||
{
|
||||
saveFormatTemp = VideoSaveFormat.NCDF;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("saveFormat must be 0 or 1: " + saveFormat.ToString());
|
||||
}
|
||||
|
||||
_videoRecorder.GrabVideoToDisk(numberOfFrames, saveFormatTemp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query the video system for its hard drive status
|
||||
/// </summary>
|
||||
/// <param name="driveSpace1">The number of free Gigabytes</param>
|
||||
/// <param name="driveSpace2">The number of free Gigabytes</param>
|
||||
/// <param name="driveSpace3">The number of free Gigabytes</param>
|
||||
/// <param name="driveSpace4">The number of free Gigabytes</param>
|
||||
public void QueryHardDrive(ref float driveSpace1, ref float driveSpace2, ref float driveSpace3, ref float driveSpace4)
|
||||
{
|
||||
_videoRecorder.QueryHardDrive(ref driveSpace1, ref driveSpace2, ref driveSpace3, ref driveSpace4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move a file to new location/new name
|
||||
/// </summary>
|
||||
/// <param name="fromFile">The abs location of the file to move</param>
|
||||
/// <param name="toFile">The abs location to move to</param>
|
||||
/// <param name="moveControl">0 to move the file (via a rename on the recording system), 1 to copy the file and then delete the orginal (may take a long time if file is large)</param>
|
||||
public void MoveFile(string fromFile, string toFile, uint moveControl)
|
||||
{
|
||||
MoveControl moveControlTemp = MoveControl.MOVE;
|
||||
|
||||
if ((MoveControl)moveControl == MoveControl.MOVE)
|
||||
{
|
||||
moveControlTemp = MoveControl.MOVE;
|
||||
}
|
||||
else if ((MoveControl)moveControl == MoveControl.COPY_AND_DELETE)
|
||||
{
|
||||
moveControlTemp = MoveControl.COPY_AND_DELETE;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("moveControl must be 0 or 1: " + moveControlTemp.ToString());
|
||||
}
|
||||
|
||||
_videoRecorder.MoveFile(fromFile, toFile, moveControlTemp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Command the video recorder to display live video
|
||||
/// </summary>
|
||||
public void ShowLiveVideo()
|
||||
{
|
||||
_videoRecorder.ShowLiveVideo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Command the video recorder to stop live video display
|
||||
/// </summary>
|
||||
public void StopLiveVideo()
|
||||
{
|
||||
_videoRecorder.StopLiveVideo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// After calling GrabVideoToDisk(), use this function to know when the grab is complete
|
||||
/// </summary>
|
||||
/// <param name="timeoutms">The number of milliseconds to wait for the grab complete message</param>
|
||||
/// <returns></returns>
|
||||
public string WaitForGrabToComplete(int timeoutms)
|
||||
{
|
||||
return _videoRecorder.WaitForGrabToComplete(timeoutms);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)Solution.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>VideoRecorderMeasurementManager</AssemblyName>
|
||||
<Product>Composable Test Software Library</Product>
|
||||
<Description>Video Recorder Measurement Manager</Description>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- Static versioning (Suitable for Development) -->
|
||||
<!-- Disable the line below for dynamic versioning -->
|
||||
<Version>1.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLog" Version="5.0.0" />
|
||||
<PackageReference Include="Raytheon.Common" Version="1.0.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.InstrumentManager.Contracts" Version="1.8.0" />
|
||||
<PackageReference Include="Raytheon.Instruments.VideoRecorder.Contracts" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user