Initial check-in
This commit is contained in:
275
Source/Program/Program.cs
Normal file
275
Source/Program/Program.cs
Normal file
@@ -0,0 +1,275 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// UNCLASSIFIED
|
||||
/*-------------------------------------------------------------------------
|
||||
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
|
||||
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
|
||||
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
|
||||
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
|
||||
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
|
||||
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
|
||||
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
|
||||
COMPANY.
|
||||
|
||||
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
|
||||
GOVERNMENT.
|
||||
|
||||
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
||||
-------------------------------------------------------------------------*/
|
||||
using NationalInstruments.TestStand.Interop.API;
|
||||
using NLog;
|
||||
using Raytheon.Instruments;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Raytheon.Common;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for interfacing with any Test Executive such as third party test executive such as Test Stand
|
||||
/// DO NOT implement IDisposable interface for this class. If there are unmanaged resources that need to be freed,
|
||||
/// do it in the destructor.
|
||||
///
|
||||
/// </summary>
|
||||
public partial class Program
|
||||
{
|
||||
#region PrivateMemberVariables
|
||||
// the one and only program
|
||||
private static Program _program;
|
||||
|
||||
private object _terminateTestSyncObj = new object();
|
||||
private bool _terminateTestInitiated = false;
|
||||
|
||||
// simulation
|
||||
private readonly bool _isThereHardware;
|
||||
|
||||
// file management
|
||||
private string _partNumber;
|
||||
private string _serialNumber;
|
||||
|
||||
private List<BasicThread> _threadList = new List<BasicThread>();
|
||||
|
||||
private IInstrumentManager _instrumentManager;
|
||||
|
||||
private ILogger _logger;
|
||||
|
||||
private object _fatalErrorMsgFromThreadSyncObj = new object();
|
||||
private string _fatalErrorMsgFromThread;
|
||||
|
||||
#endregion
|
||||
|
||||
internal SequenceContext _testStandSeqContext;
|
||||
internal UutInfo _uutInfo;
|
||||
internal EventManager _eventManager = new EventManager();
|
||||
internal FileAndFolderManager _fileAndFolderManager;
|
||||
internal IConfigurationFile _programConfig { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of this class. Only one instance is allowed
|
||||
/// </summary>
|
||||
/// <param name="partNumber">The UUT part number</param>
|
||||
/// <param name="serialNumber">The UUT serial number</param>
|
||||
/// <param name="isThereHardware">false for simulation</param>
|
||||
/// <returns></returns>
|
||||
public static Program Instance(string partNumber = "", string serialNumber = "", bool isThereHardware = true, object testStandSeqContext = null)
|
||||
{
|
||||
if (_program == null)
|
||||
{
|
||||
_program = new Program(partNumber, serialNumber, isThereHardware, testStandSeqContext);
|
||||
}
|
||||
|
||||
return _program;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is only meant to be called from third-party test executive such as TestStand.
|
||||
/// By settting this object to null, Garbage collection is initiated on this objects and any objects created by this object
|
||||
/// with the exception of static objects. Static objects needs to be explicitly killed by setting them to null
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static void KillInstance()
|
||||
{
|
||||
if (_program != null)
|
||||
{
|
||||
// signal to all running threads to exit
|
||||
_program._eventManager[EventManager.Events.GLOBAL_QUIT].Set();
|
||||
|
||||
UutPowerAction uutPowerAction = new UutPowerAction();
|
||||
uutPowerAction.UutPowerOff();
|
||||
|
||||
// needs to kill all the support threads since they could be accessing GUI
|
||||
_program.KillSupportThreads();
|
||||
|
||||
// Because the GuiManager class starts a STA thread to manage WPF GUIs
|
||||
// the destructor doesn't get called if we don't shut down the STA thread first
|
||||
// so we explicitly call Dispose here to shutdown the thread. This is a special case.
|
||||
// All other classes call Dispose() in their Destructor
|
||||
_program.GetGuiManager()?.Dispose();
|
||||
|
||||
// this starts garbage collection on this object which then in turn start garbage collection
|
||||
// on all objects it created
|
||||
_program = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The private constructor
|
||||
/// </summary>
|
||||
/// <param name="partNumber">the UUT part number</param>
|
||||
/// <param name="serialNumber">the UUT serial number</param>
|
||||
/// <param name="isThereHardware">false for simulation</param>
|
||||
private Program(string partNumber, string serialNumber, bool isThereHardware, object testStandSeqContext)
|
||||
{
|
||||
// this line is for when this is called from third-party test executive such as TestStand. Without this, NLOG library won't be able to find the NLog.config file
|
||||
NLog.LogManager.Setup().LoadConfigurationFromFile(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "NLog.config"));
|
||||
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
_programConfig = new ConfigurationFile(Path.Combine(assemblyFolder, GeneralConstants.ProgramConfigFilename));
|
||||
|
||||
_fileAndFolderManager = new FileAndFolderManager(_programConfig);
|
||||
|
||||
if (testStandSeqContext != null)
|
||||
{
|
||||
_testStandSeqContext = testStandSeqContext as SequenceContext;
|
||||
}
|
||||
|
||||
// make sure PN/SN are valid (TS may not pass in the PN)
|
||||
if (partNumber == "" || partNumber == null)
|
||||
{
|
||||
partNumber = "DefaultPN";
|
||||
}
|
||||
|
||||
if (serialNumber == "" || serialNumber == null)
|
||||
{
|
||||
serialNumber = "DefaultSN";
|
||||
}
|
||||
|
||||
_partNumber = partNumber;
|
||||
_serialNumber = serialNumber;
|
||||
_isThereHardware = isThereHardware;
|
||||
|
||||
// Initialze all other configuration that the program needs
|
||||
_uutInfo = new UutInfo(_partNumber, _serialNumber);
|
||||
|
||||
try
|
||||
{
|
||||
var configFolder = Path.Combine(assemblyFolder, Raytheon.Common.GeneralConstants.InstrumentConfigFolder);
|
||||
_instrumentManager = new GeneralInstrumentManager(assemblyFolder, configFolder, _isThereHardware);
|
||||
_instrumentManager.Initialize();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizer
|
||||
/// </summary>
|
||||
~Program()
|
||||
{
|
||||
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ...");
|
||||
|
||||
if (_testStandSeqContext != null)
|
||||
{
|
||||
// clear any setting that we have added for any steps in the Setup Group
|
||||
for (int i = 0; i < _testStandSeqContext.Sequence.GetNumSteps(StepGroups.StepGroup_Setup); i++)
|
||||
{
|
||||
_testStandSeqContext.Sequence.GetStep(i, StepGroups.StepGroup_Setup).PostExpression = "";
|
||||
}
|
||||
|
||||
// clear any setting that we have added for any steps in the Main Group
|
||||
for (int i = 0; i < _testStandSeqContext.Sequence.GetNumSteps(StepGroups.StepGroup_Main); i++)
|
||||
{
|
||||
_testStandSeqContext.Sequence.GetStep(i, StepGroups.StepGroup_Main).PostExpression = "";
|
||||
_testStandSeqContext.Sequence.GetStep(i, StepGroups.StepGroup_Main).AdditionalResults.CustomResults.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void KillSupportThreads()
|
||||
{
|
||||
foreach (BasicThread thread in _threadList)
|
||||
{
|
||||
thread.Quit();
|
||||
thread.WaitForExit();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// All code module should not throw exception into teststand and let teststand handle the exception
|
||||
/// We give the teststand step a nice error message and tell teststand to go to cleanup
|
||||
/// If we are not calling into code from teststand, then we throw exception as usual
|
||||
/// Call this only from code executing on the main TestStand thread
|
||||
/// </summary>
|
||||
/// <param name="ex"></param>
|
||||
/// <returns></returns>
|
||||
private void TerminateTestOnMainThreadError(Exception ex)
|
||||
{
|
||||
if (_testStandSeqContext != null)
|
||||
{
|
||||
lock (_terminateTestSyncObj)
|
||||
{
|
||||
if (!_terminateTestInitiated)
|
||||
{
|
||||
// tells teststand there's a exception occurred and give it the error message
|
||||
_testStandSeqContext.Step.PostExpression = $"Step.Result.Error.Msg=\"{ex.Message} \", Step.Result.Error.Occurred=True";
|
||||
|
||||
_testStandSeqContext.Step.ResultStatus = "Error";
|
||||
|
||||
// tells TestStand to go to clean up
|
||||
_testStandSeqContext.StepGroup = StepGroups.StepGroup_Cleanup;
|
||||
_testStandSeqContext.NextStepIndex = 0;
|
||||
|
||||
_terminateTestInitiated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
throw ex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Support threads such as monitor threads need a way to stop the sequence if it encounters an error
|
||||
/// This function is meant to be called from FailureMonitorThread which monitors any error signaled by any
|
||||
/// support thread.
|
||||
/// </summary>
|
||||
/// <param name=""></param>
|
||||
/// <returns></returns>
|
||||
internal void TerminateTestOnSupportThreadError()
|
||||
{
|
||||
if (_testStandSeqContext != null)
|
||||
{
|
||||
lock (_terminateTestSyncObj)
|
||||
{
|
||||
if (!_terminateTestInitiated)
|
||||
{
|
||||
// tells teststand there's a exception occurred and give it the error message
|
||||
_testStandSeqContext.SequenceErrorMessage = _fatalErrorMsgFromThread + " ";
|
||||
_testStandSeqContext.SequenceErrorOccurred = true;
|
||||
|
||||
// tells TestStand to go to clean up
|
||||
_testStandSeqContext.StepGroup = StepGroups.StepGroup_Cleanup;
|
||||
_testStandSeqContext.NextStepIndex = 0;
|
||||
|
||||
_terminateTestInitiated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetFatalErrorMsgFromThread(string errorMsg)
|
||||
{
|
||||
lock(_fatalErrorMsgFromThreadSyncObj)
|
||||
{
|
||||
if (String.IsNullOrEmpty(_fatalErrorMsgFromThread))
|
||||
{
|
||||
_fatalErrorMsgFromThread = errorMsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user