Big changes

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

View File

@@ -0,0 +1,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: GMYK, 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);
}
}
}
}

View File

@@ -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
}
}

View File

@@ -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>

View File

@@ -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
}
}

View File

@@ -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>

View File

@@ -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();
}
}

View File

@@ -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";
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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>

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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>

View File

@@ -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;
}
}
}
}

View File

@@ -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
}
}

View File

@@ -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>

View File

@@ -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
}
}

View File

@@ -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>

View File

@@ -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
}
}

View File

@@ -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>

View File

@@ -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;
}
}
}
}

View File

@@ -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>

View File

@@ -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
}
}

View File

@@ -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>

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;
}
}
}
}

View File

@@ -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-&gt;Count())' &gt; 0" />
<Delete Files="@(StaleFiles)" />
</Target>
<Target Name="PostBuild" AfterTargets="Pack" Condition="'$(Configuration)' == 'Deploy'">
<Exec Command="dotnet nuget push --source &quot;TSRealNuget_Dev&quot; --api-key az $(MSBuildProjectDirectory)\$(OutputPath)*.nupkg" />
</Target>
</Project>

View File

@@ -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>

View File

@@ -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>

View File

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

View File

@@ -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>

View File

@@ -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
}
}

View File

@@ -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>