Initial check-in

This commit is contained in:
Duc
2025-01-03 09:50:39 -07:00
parent 45596e360d
commit 1d8f6e4c96
143 changed files with 9835 additions and 0 deletions

View File

@@ -0,0 +1,220 @@
/*-------------------------------------------------------------------------
// 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 ProgramLib;
using NLog;
using Raytheon.Common;
using Raytheon.Instruments;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ProgramGui;
using ProgramGui.Model;
using ProgramGui.View;
using ProgramGui.ViewModel;
using System.Windows;
using Raytheon;
namespace ProgramLib
{
internal class UutPowerAction
{
#region PrivateClassMembers
private static NLog.ILogger _logger;
private static object powerSyncObj = new object();
private bool _sttoSuccess = true;
private string fatalErrorMsg;
#endregion
public UutPowerAction()
{
_logger = LogManager.GetCurrentClassLogger();
}
~UutPowerAction()
{
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ...");
}
/// <summary>
/// Power off UUT
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public void UutPowerOff()
{
try
{
lock (powerSyncObj)
{
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
Program.Instance().GetPowerSupplyMeasurementManager()[PowerSupplyConstants.POWER_DEVICE.STE_POWER_SUPPLY_SYSTEM].OutputDisable(ProgramLib.PowerSupplyConstants.POWER_DEVICE.STE_PVM_5V);
// enable front panel
Program.Instance().GetPowerSupplyMeasurementManager()[PowerSupplyConstants.POWER_DEVICE.STE_POWER_SUPPLY_SYSTEM].FrontPanelEnabled = true;
// signal to PowerSupplyReadThread to stop monitoring power
Program.Instance()._eventManager[EventManager.Events.UUT_POWER_OFF].Set();
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.MAIN].Dispatcher.Invoke((Action)delegate
{
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.MAIN].Hide();
});
}
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// Power on UUT
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public void UutPowerOn()
{
try
{
lock (powerSyncObj)
{
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
Program.Instance().GetPowerSupplyMeasurementManager()[PowerSupplyConstants.POWER_DEVICE.STE_POWER_SUPPLY_SYSTEM].ReadPowerSupplyData(ProgramLib.PowerSupplyConstants.POWER_DEVICE.STE_PVM_5V, out double voltage, out double current, out double voltageSetPoint, out bool isOn, out int faultStatus);
if (!isOn)
{
Task.Factory.StartNew(() => PerformSttoTask());
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.IMPEDANCE_CHECK].Dispatcher.Invoke((Action)delegate
{
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.MAIN].Hide();
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.IMPEDANCE_CHECK].ShowDialog();
});
if (_sttoSuccess)
{
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.IMPEDANCE_CHECK].Dispatcher.Invoke((Action)delegate
{
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.MAIN].Show();
});
Program.Instance().GetPowerSupplyMeasurementManager()[PowerSupplyConstants.POWER_DEVICE.STE_POWER_SUPPLY_SYSTEM].OutputEnable(ProgramLib.PowerSupplyConstants.POWER_DEVICE.STE_PVM_5V);
// disable front panel
Program.Instance().GetPowerSupplyMeasurementManager()[PowerSupplyConstants.POWER_DEVICE.STE_POWER_SUPPLY_SYSTEM].FrontPanelEnabled = false;
// signal to PowerSupplyReadThread to start monitoring power
Program.Instance()._eventManager[EventManager.Events.UUT_POWER_ON].Set();
}
else
{
throw new Exception(fatalErrorMsg);
}
}
}
}
catch (Exception)
{
throw;
}
}
private async void PerformSttoTask()
{
ImpedanceDataModel impedanceDataModel;
ImpedanceCheckWindow impedanceCheckWindow = (ImpedanceCheckWindow)ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.IMPEDANCE_CHECK];
try
{
_logger?.Debug($"{this.GetType().Name}::PerformSttoTask() running...");
bool forceFail = false;
string measurementStatus = "PASSED";
ImpedanceCheckWindowViewModel.Images passFailImage = ImpedanceCheckWindowViewModel.Images.PASS_CHECK;
impedanceCheckWindow._viewModel.ClearData();
int MAX_ITERATION = 15;
int cableNum = 17;
int cablePin1 = 5;
int cablePin2 = 7;
int measurement = 5;
string measurementName;
for (int i = 1; i <= MAX_ITERATION; i++)
{
measurementName = $"P{cableNum}_P{cablePin1++}_P{cableNum++}_P{cablePin2++}";
impedanceDataModel = new ImpedanceDataModel();
if (i == MAX_ITERATION / 2 && forceFail)
{
passFailImage = ImpedanceCheckWindowViewModel.Images.FAIL_CHECK;
measurementStatus = "FAILED";
_sttoSuccess = false;
}
impedanceDataModel.PassFailImagePath = impedanceCheckWindow._viewModel._imageToResourcePathDict[passFailImage];
impedanceDataModel.Description = $"{measurementName} Measured {measurement} Range [0,50]";
if (Program.Instance()._testStandSeqContext != null)
{
Program.Instance()._testStandSeqContext.Step.AdditionalResults.CustomResults.Insert($"\"{measurementName}\"", $"\"Measured: {measurement++} Range [0,50] - {measurementStatus}\"");
}
impedanceCheckWindow._viewModel.AddData(impedanceDataModel);
if (!_sttoSuccess)
{
fatalErrorMsg = impedanceDataModel.Description;
throw new Exception(fatalErrorMsg);
}
await Task.Delay(300);
}
}
catch (Exception ex)
{
_logger.Error(ex.Message + "\n" + ex.StackTrace);
}
finally
{
if (!_sttoSuccess)
{
impedanceCheckWindow.Dispatcher.Invoke((Action)delegate
{
impedanceCheckWindow.btnClose.Visibility = Visibility.Visible;
});
}
else
{
impedanceCheckWindow.Dispatcher.Invoke((Action)delegate
{
impedanceCheckWindow.Hide();
});
}
_logger?.Debug($"{this.GetType().Name}::PerformSttoTask() exiting...");
}
}
}
}

View File

@@ -0,0 +1,74 @@
/*-------------------------------------------------------------------------
// 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.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ProgramLib
{
/// <summary>
/// Abstract base class for all threads
/// </summary>
internal abstract class BasicThread
{
protected Thread _thread;
/// <summary>
/// Spawn thread and start it
/// </summary>
/// <param name=""></param>
/// <returns></returns>
public void Start()
{
_thread = new Thread(new ThreadStart(DoWork));
_thread.Start();
}
/// <summary>
/// Method that executes on the thread.
/// Child class must implement this method
/// </summary>
/// <param name=""></param>
/// <returns></returns>
protected abstract void DoWork();
/// <summary>
/// Tells thread to quit
/// </summary>
/// <param name=""></param>
/// <returns></returns>
public virtual void Quit() { }
/// <summary>
/// Wait for thread to exit
/// </summary>
/// <param name=""></param>
/// <returns></returns>
public virtual void WaitForExit()
{
if (_thread != null)
{
// wait for thread to terminate
_thread.Join();
}
}
}
}

View File

@@ -0,0 +1,34 @@
/*-------------------------------------------------------------------------
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ProgramLib
{
/// <summary>
/// Define non-specific constants
/// </summary>
internal static class GeneralConstants
{
public const string ProgramConfigFilename = "config.ini";
public const string DefaultConfigValue = "NOTSET";
}
}

View File

@@ -0,0 +1,42 @@
/*-------------------------------------------------------------------------
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ProgramLib
{
/// <summary>
/// Power supply constants
/// </summary>
internal static class PowerSupplyConstants
{
public enum POWER_DEVICE
{
STE_POWER_SUPPLY_SYSTEM,
// Power modules
UUT_REF_3_3V,
STE_PVM_5V,
STE_GU_INTERFACE_RELAYS_25V,
STE_GU_INTERFACE_RF_INTERFACE_5V,
}
}
}

View File

@@ -0,0 +1,41 @@
/*-------------------------------------------------------------------------
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ProgramLib
{
/// <summary>
/// Define all the sections and keys that exists in the INI file
/// </summary>
internal enum ProgramConfigIni
{
// list all the sections here
GENERAL,
// list all the keys here
DATA_BASE_PATH,
DATA_TEMP_PATH,
APP_BASE_PATH,
POWER_SUPPLY_SELF_TEST_DATETIME,
POWER_SUPPLY_READ_RATE
}
}

View File

@@ -0,0 +1,69 @@
/*-------------------------------------------------------------------------
// 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 ProgramLib
{
/// <summary>
/// Store UUT information
/// </summary>
internal class UutInfo
{
#region PublicMembers
#endregion
#region PrivateClassMembers
// class variables
private readonly string _partNumber;
private readonly string _serialNumber;
#endregion
#region PrivateFuctions
/// <summary>
/// The constructor
/// </summary>
public UutInfo(string partNumber, string serialNumber)
{
_partNumber = partNumber;
_serialNumber = serialNumber;
}
#endregion
#region PublicFuctions
/// <summary>
///
/// </summary>
/// <returns></returns>
internal string GetPartNumber()
{
return _partNumber;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
internal string GetSerialNumber()
{
return _serialNumber;
}
#endregion
}
}

View File

@@ -0,0 +1,154 @@
/*-------------------------------------------------------------------------
// 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.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ProgramLib
{
/// <summary>
/// Class that maps event array index to any event enumeration and wraps the WaitHandle.WaitAny() function
/// Use case:
/// When calling WaitHandle.WaitAny(EventArray), it only returns the index of the event in the array that is being signalled.
/// Refering to an index of the array to know which event it is is not ideal. We want to be able to refer to an enumeration instead
/// Usage:
/// In class that uses this class, must define a enumeration
/// public enum Events
/// {
/// EVENT1,
/// EVENT2,
/// EVENT3,
/// EVENTN
///
/// // DO NOT change the name
/// // This must be the last member in the enum
/// EVENT_TIMED_OUT
/// }
/// Dictionary<Events, EventWaitHandle> dict = new Dictionary<Events, EventWaitHandle>();
/// dict[Events.EVENT1] = new ManualResetEvent(false);
/// dict[Events.EVENT2] = new AutoResetEvent(false);
/// dict[Events.EVENT3] = new ManualResetEvent(false);
/// dict[Events.EVENTN] = new AutoResetEvent(false);
/// dict[Events.EVENT_TIMED_OUT] = null;
///
/// EventGroup<Events, EventWaitHandle> eventGroup = new EventGroup<Events, EventWaitHandle>(dict);
///
/// Events id = eventGroup.WaitAny([Optional_timeout]);
///
/// if (id == Events.EVENT_TIMED_OUT){} // only if timeout was specified
/// if (id == Events.EVENT1){}
///
/// </summary>
internal class EventGroup<T1,T2>
{
Dictionary<T1, T2> _eventDict = null;
T2[] _eventArray = null;
/// <summary>
/// Constructor
/// </summary>
private EventGroup()
{
}
/// <summary>
/// Constructor
/// The event enum passed in must be defined in the following format:
/// public enum Events
/// {
/// EVENT1,
/// EVENT2,
/// EVENT3,
/// EVENTN
///
/// // DO NOT change the name
/// // This must be the last member in the enum
/// EVENT_TIMED_OUT
/// }
/// </summary>
/// <param name="eventDict">A dictionary that contains event enum that is associated to an event object</param>
public EventGroup(Dictionary<T1, T2> eventDict)
{
if (eventDict == null)
throw new Exception($"{nameof(eventDict)} cannot be null");
if (!eventDict.First().Key.GetType().IsEnum)
{
throw new Exception($"{nameof(eventDict)}'s key must be an enumerated type");
}
// get the last element in the dictionary
var element = eventDict.ElementAt(eventDict.Count - 1);
// check if the name of the last enum member is what we expect
string actualNameOfLastEnumMember = ((Enum)Convert.ChangeType(element.Key, typeof(Enum))).ToString();
string expectedNameOfLastEnumMember = "EVENT_TIMED_OUT";
if (actualNameOfLastEnumMember != expectedNameOfLastEnumMember)
{
throw new Exception($"Enum {element.Key.GetType().Name} must have {expectedNameOfLastEnumMember} as its last member. {nameof(eventDict)} must have {expectedNameOfLastEnumMember} as the last key in the dictionary");
}
if (eventDict.First().Value.GetType().BaseType != typeof(EventWaitHandle))
{
throw new Exception($"{nameof(eventDict)}'s value must be ManualResetEvent or AutoResetEvent type");
}
_eventDict = eventDict;
_eventArray = new T2[_eventDict.Count - 1];
int index = 0;
foreach (KeyValuePair<T1, T2> entry in _eventDict)
{
if (index < _eventDict.Count - 1)
_eventArray[index++] = entry.Value;
}
}
/// <summary>
/// Return the enumerated event based on the index of the event in the event array that is being signalled
/// </summary>
/// <param name="timeoutMilliseconds">time out in milliseconds</param>
public T1 WaitAny(int? timeoutMilliseconds = null)
{
int index = 0;
T1 eventId = default;
if (timeoutMilliseconds == null)
index = WaitHandle.WaitAny((EventWaitHandle[])Convert.ChangeType(_eventArray, typeof(EventWaitHandle[])));
else
index = WaitHandle.WaitAny((EventWaitHandle[])Convert.ChangeType(_eventArray, typeof(EventWaitHandle[])), (int)timeoutMilliseconds);
if (index == WaitHandle.WaitTimeout)
{
var element = _eventDict.ElementAt(_eventDict.Count - 1);
eventId = element.Key;
}
else
{
var element = _eventDict.ElementAt(index);
eventId = element.Key;
}
return eventId;
}
}
}

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.
-------------------------------------------------------------------------*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ProgramLib
{
/// <summary>
/// Partial class... defines all the types that this class needs
/// </summary>
internal partial class EventManager
{
public enum Events
{
GLOBAL_QUIT,
UUT_POWER_ON,
UUT_POWER_OFF,
FATAL_FAILURE
}
}
}

View File

@@ -0,0 +1,70 @@
/*-------------------------------------------------------------------------
// 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.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ProgramLib
{
/// <summary>
/// Stores global events that any thread can use to monitor
/// </summary>
internal partial class EventManager
{
private EventWaitHandle[] _events = new EventWaitHandle[Enum.GetValues(typeof(Events)).Cast<int>().Max() + 1];
// specify which event should have to be manually reset
List<Events> _manualEventList = new List<Events>
{
Events.GLOBAL_QUIT,
Events.FATAL_FAILURE
};
/// <summary>
/// The private constructor
/// </summary>
public EventManager()
{
for (int i = 0; i < _events.Count(); i++)
{
if (_manualEventList.Contains((Events)i))
{
_events[i] = new ManualResetEvent(false);
}
else
_events[i] = new AutoResetEvent(false);
}
}
/// <summary>
/// Implement Indexer to obtain an event object
/// </summary>
/// <param name=""></param>
/// <returns></returns>
public EventWaitHandle this[Events eventId]
{
get
{
return _events[(int)eventId];
}
}
}
}

View File

@@ -0,0 +1,46 @@
/*-------------------------------------------------------------------------
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ProgramLib
{
/// <summary>
/// Partial class... defines all the types that this class needs
/// </summary>
internal partial class FileAndFolderManager
{
public enum Folders
{
// List data folder + its subfolders
DATA,
DATA_TEMP,
// List app folder + its folders
APP
}
public enum Files
{
POWER_SUPPLY_SELF_TEST_DATETIME
}
}
}

View File

@@ -0,0 +1,120 @@
/*-------------------------------------------------------------------------
// 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.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Raytheon.Common;
namespace ProgramLib
{
/// <summary>
/// Partial class... this is the main class responsible for parsing config.ini in order
/// to construct file paths and folder paths
/// </summary>
internal partial class FileAndFolderManager
{
private Dictionary<Folders, string> foldersDict = new Dictionary<Folders, string>();
private Dictionary<Files, string> filesDict = new Dictionary<Files, string>();
private IConfigurationFile _programConfig;
/// <summary>
/// The private constructor
/// </summary>
/// <param name="programConfig">the UUT part number</param>
public FileAndFolderManager(IConfigurationFile programConfig)
{
_programConfig = programConfig;
buildFolders();
createFolders();
buildFiles();
}
/// <summary>
/// Build folder paths so we can acccess them later
/// </summary>
/// <param name="iniObj"></param>
/// <returns></returns>
private void buildFolders()
{
string dataBasePath = _programConfig.ReadValue(ProgramConfigIni.GENERAL.ToString(), ProgramConfigIni.DATA_BASE_PATH.ToString(), "NOT SET");
foldersDict[Folders.DATA] = dataBasePath;
string val = _programConfig.ReadValue(ProgramConfigIni.GENERAL.ToString(), ProgramConfigIni.DATA_TEMP_PATH.ToString(), "NOT SET");
foldersDict[Folders.DATA_TEMP] = Path.Combine(dataBasePath, val);
string appBasePath = _programConfig.ReadValue(ProgramConfigIni.GENERAL.ToString(), ProgramConfigIni.APP_BASE_PATH.ToString(), "NOT SET");
foldersDict[Folders.APP] = dataBasePath;
}
/// <summary>
/// We create all the necessary folders
/// </summary>
/// <param name="iniObj"></param>
/// <returns></returns>
private void createFolders()
{
Directory.CreateDirectory(foldersDict[Folders.DATA_TEMP]);
}
/// <summary>
/// Build file paths so we can acccess them later
/// </summary>
/// <param name="iniObj"></param>
/// <returns></returns>
private void buildFiles()
{
string val = _programConfig.ReadValue(ProgramConfigIni.GENERAL.ToString(), ProgramConfigIni.POWER_SUPPLY_SELF_TEST_DATETIME.ToString(), "NOT SET");
filesDict[Files.POWER_SUPPLY_SELF_TEST_DATETIME] = Path.Combine(foldersDict[Folders.DATA_TEMP], val);
}
/// <summary>
/// Return the full folder path
/// </summary>
/// <param name="folder"></param>
/// <returns></returns>
public string getFolder(Folders folder)
{
if (foldersDict.ContainsKey(folder))
{
return foldersDict[folder];
}
else
throw new Exception($"{folder.ToString()} is invalid");
}
/// <summary>
/// Return the full file path
/// </summary>
/// <param name="iniObj"></param>
/// <returns></returns>
public string getFile(Files file)
{
if (filesDict.ContainsKey(file))
{
return filesDict[file];
}
else
throw new Exception($"{file.ToString()} is invalid");
}
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Configurations>
<IniConfiguration>
<section name="Parts">
<key name="Location" value="C:\Program Files (x86)\Raytheon\RINSS\Parts" />
</section>
</IniConfiguration>
<XmlConfigurations>
<XmlConfiguration name="Instruments">
<Instrument>
<Name>TCP_CLIENT_1</Name>
<Factory>EthernetSocketsTcpClientFactory</Factory>
</Instrument>
<Instrument>
<Name>STE_POWER_SUPPLY_SYSTEM</Name>
<Factory>PowerSupplyKeysightN67xxFactory</Factory>
</Instrument>
</XmlConfiguration>
</XmlConfigurations>
</Configurations>

View File

@@ -0,0 +1,59 @@
[GENERAL]
ETHERNET_ADDRESS = localhost
ETHERNET_PORT = 5025
MODULE_DEFINITION = UUT_REF_3_3V, STE_PVM_5V, STE_GU_INTERFACE_RELAYS_25V, STE_GU_INTERFACE_RF_INTERFACE_5V
; 0 means no coupled modules.
; couple means turning on/off any one of the module, turns on/off the others
COUPLED_MODULES = STE_PVM_5V, STE_GU_INTERFACE_RELAYS_25V, STE_GU_INTERFACE_RF_INTERFACE_5V
; 0 means no grouped modules.
; group means turning combining 2 or more modules thus acting as one module
GROUPED_MODULES = 0
INTERFACE = ETHERNET
; GU | KW | KWSIM | SELFTEST | ZERO VOLTAGE
[UUT_REF_3_3V]
INDEX = 1
OCP = 2.0
OVP = 4.0
VOLTAGE_SETPOINT = 3.3
MIN_VOLTAGE = 3.0
MAX_VOLTAGE = 3.75
MAX_CURRENT = 2.0
MIN_CURRENT = -0.25
[STE_PVM_5V]
INDEX = 2
OCP = 2.0
OVP = 8.0
VOLTAGE_SETPOINT = 5.0
; STE Power (PVM and peripherals) supply settings
MIN_VOLTAGE = 4.0
MAX_VOLTAGE = 5.5
MAX_CURRENT = 1.5
MIN_CURRENT = -.25
[STE_GU_INTERFACE_RELAYS_25V]
INDEX = 3
OCP = 3.0
OVP = 34.0
VOLTAGE_SETPOINT = 25.0
; STE Power (GU interface and Relays) Supply settings
MIN_VOLTAGE = 22.0
MAX_VOLTAGE = 30.0
MAX_CURRENT = 3.0
MIN_CURRENT = -0.25
[STE_GU_INTERFACE_RF_INTERFACE_5V]
INDEX = 4
OCP = 5.0
OVP = 6.5
VOLTAGE_SETPOINT = 5.0
; STE Power (PVM and peripherals) supply settings
MIN_VOLTAGE = 4.0
MAX_VOLTAGE = 6.3
MAX_CURRENT = 4.5
MIN_CURRENT = -.25

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Configurations>
<IniConfiguration>
<section name="STE_POWER_SUPPLY_SYSTEM">
<key name="INI_FILE_PATH" value=".\InstrumentConfig\STE_POWER_SUPPLY_SYSTEM.ini" />
</section>
</IniConfiguration>
<XmlConfigurations />
</Configurations>

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true">
<!--
See http://nlog-project.org/wiki/Configuration_file
for information on customizing logging rules and outputs.
-->
<!-- add your targets here -->
<targets>
<default-wrapper xsi:type="AsyncWrapper" batchSize="1000" overflowAction="Grow" timeToSleepBetweenBatches="1"/>
<target type="FallbackGroup" name="FusionLogging" returnToFirstOnSuccess="true">
<target type="File" name="FileBackup" fileName="${specialFolder:CommonApplicationData}/Raytheon/logs/${shortdate}/${logger}.log" layout="${longdate} | ${logger} | ${message} ${exception}"/>
<target type="File" name="LocalFileBackup" fileName="${basedir}/logs/${shortdate}/${logger}.log" layout="${longdate} | ${logger} | ${message} ${exception}"/>
</target>
<target name="logDashboard" type="Chainsaw" address="udp://127.0.0.1:7777" />
<target xsi:type="File" name="logFiles" fileName="${specialfolder:folder=CommonApplicationData}/Raytheon/logs/${shortdate}/${logger:fsNormalize=true}.log" layout="${log4jxmlevent}" />
<target xsi:type="File" name="RunFile" filename="${specialfolder:folder=CommonApplicationData}/Raytheon/logs/${shortdate}/_All.log" layout="${log4jxmlevent}" />
<target name="console" type="ColoredConsole" layout="${longdate} | ${logger} | ${message} ${exception}"/>
<target name="blackHole" xsi:type="Null" />
</targets>
<!-- add your logging rules here
Log level (lowest to highest):
1. TRACE
2. DEBUG
3. INFO
4. WARN
5. ERROR
6. FATAL
-->
<rules>
<!-- Enable/Disable log level here
To Disable a log level, set "enable" attribute to true
To Enable a log level, set "enable" attribute to false -->
<logger levels="Trace" name="*" writeTo="blackHole" final="true" enabled="false" />
<logger levels="Info" name="*" writeTo="blackHole" final="true" enabled="false" />
<logger levels="Debug" name="*" writeTo="blackHole" final="true" enabled="false" />
<!-- ======================================= -->
<logger name="*" minlevel="Trace" writeTo="RunFile,console,LogDashboard" />
</rules>
</nlog>

View File

@@ -0,0 +1,73 @@
/*-------------------------------------------------------------------------
// 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 ProgramGui;
using Raytheon.Instruments;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ProgramLib
{
public partial class Program
{
public void UutPowerOn()
{
try
{
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
UutPowerAction uutPowerAction = new UutPowerAction();
uutPowerAction.UutPowerOn();
}
catch (Exception ex)
{
_logger.Error(ex.Message + "\n" + ex.StackTrace);
// DO NOT THROW in this block
// this function will handle the error accordingly since we could be calling this from third-party test executive like TestStand
TerminateTestOnMainThreadError(ex);
}
}
public void UutPowerOff()
{
try
{
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
UutPowerAction uutPowerAction = new UutPowerAction();
uutPowerAction.UutPowerOff();
}
catch (Exception ex)
{
_logger.Error(ex.Message + "\n" + ex.StackTrace);
// DO NOT THROW in this block
// this function will handle the error accordingly since we could be calling this from third-party test executive like TestStand
TerminateTestOnMainThreadError(ex);
}
}
}
}

View File

@@ -0,0 +1,149 @@
/*-------------------------------------------------------------------------
// 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;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Raytheon.Instruments;
using Raytheon.Common;
using NLog;
using System.Windows.Interop;
using ProgramGui;
using NationalInstruments.TestStand.Interop.API;
using System.Runtime.ExceptionServices;
namespace ProgramLib
{
/// <summary>
/// Initialization of measurement managers and get methods
/// </summary>
public partial class Program
{
// Declare all the instrument managers here
private PowerSupplyMeasurementManager _psManager = null;
private ProgramGuiManager _guiManager = null;
/// <summary>
/// Initialize power supply measurement manager
/// </summary>
/// <param name=""></param>
/// <returns></returns>
public void InitializePowerSupplyMeasurementManager()
{
try
{
_psManager = new PowerSupplyMeasurementManager(_instrumentManager, _fileAndFolderManager.getFile(FileAndFolderManager.Files.POWER_SUPPLY_SELF_TEST_DATETIME));
_psManager.Initialize();
}
catch (Exception ex)
{
_logger.Error(ex.Message + "\n" + ex.StackTrace);
// DO NOT THROW in this block
// this function will handle the error accordingly since we could be calling this from third-party test executive like TestStand
TerminateTestOnMainThreadError(ex);
}
}
/// <summary>
/// Initialize GUI manager
/// </summary>
/// <param name=""></param>
/// <returns></returns>
public void InitializeGuiManager()
{
try
{
_guiManager = new ProgramGuiManager();
_guiManager.Initialize();
}
catch (Exception ex)
{
_logger.Error(ex.Message + "\n" + ex.StackTrace);
// DO NOT THROW in this block
// this function will handle the error accordingly since we could be calling this from third-party test executive like TestStand
TerminateTestOnMainThreadError(ex);
}
}
/// <summary>
/// Start all the monitor/read threads here
/// Call this only after ProgramGuiManager and PowerSupplyManager has been initialized since these threads could be
/// accessing those objects
/// </summary>
/// <param name=""></param>
/// <returns></returns>
public void InitializeSupportThreads()
{
try
{
if (_threadList.Count() == 0)
{
_threadList.Add(new FailureMonitorThread());
_threadList.Last().Start();
ICollection<object> psList = _instrumentManager.GetInstruments(typeof(PowerSupply));
foreach (PowerSupply ps in psList)
{
_threadList.Add(new PowerSupplyReadThread(ps.Name));
_threadList.Last().Start();
}
}
}
catch (Exception ex)
{
_logger.Error(ex.Message + "\n" + ex.StackTrace);
// DO NOT THROW in this block
// this function will handle the error accordingly since we could be calling this from third-party test executive like TestStand
TerminateTestOnMainThreadError(ex);
}
}
/// <summary>
/// Get power supply manager object
/// </summary>
/// <param name=""></param>
/// <returns></returns>
public PowerSupplyMeasurementManager GetPowerSupplyMeasurementManager()
{
if (_psManager == null)
InitializePowerSupplyMeasurementManager();
return _psManager;
}
/// <summary>
/// Get Gui manager object
/// </summary>
/// <param name=""></param>
/// <returns></returns>
public ProgramGuiManager GetGuiManager()
{
if (_guiManager == null)
InitializeGuiManager();
return _guiManager;
}
}
}

275
Source/Program/Program.cs Normal file
View 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;
}
}
}
}
}

View File

@@ -0,0 +1,77 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(SolutionDir)Program.props" />
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<OutputType>Library</OutputType>
<AssemblyName>Program</AssemblyName>
<UseWPF>true</UseWPF>
<Description>Program DLL serves as starting test point</Description>
<Company>Raytheon Technologies</Company>
<Product>NGSRI Program</Product>
<Authors>TEEC</Authors>
<Copyright>Copyright © Raytheon Technologies $([System.DateTime]::get_now().ToString("yyyy"))</Copyright>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<!-- Dynamic Versioning (Suitable for Release) -->
<!-- <Version>$(Version)$(Suffix)</Version> -->
<!-- Static Versioning (Suitable for Development) -->
<Version>1.0.0</Version>
<Configurations>Debug;Release;Deploy</Configurations>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Raytheon.Configuration" Version="*" />
<PackageReference Include="Raytheon.Configuration.Contracts" Version="*" />
<PackageReference Include="NLog" Version="5.0.0" />
<PackageReference Include="Raytheon.Instruments.InstrumentManager.GeneralInstrumentManager" Version="1.4.1" />
<!--
<PackageReference Include="NGSRI" Version="1.0.0" />
-->
</ItemGroup>
<!-- Copy pdb files for DLLs in nuget packages to output directory-->
<Target Name="IncludeSymbolFiles" AfterTargets="ResolveAssemblyReferences" Condition="@(ReferenceCopyLocalPaths) != ''">
<ItemGroup>
<ReferenceCopyLocalPaths Include="%(ReferenceCopyLocalPaths.RelativeDir)%(ReferenceCopyLocalPaths.Filename).pdb" />
<ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="!Exists('%(FullPath)')" />
</ItemGroup>
</Target>
<ItemGroup>
<ProjectReference Include="..\Instruments\PowerSupplies\Keysight67XX\KeysightN67XX.csproj" />
<ProjectReference Include="..\MeasurementManagers\PowerSupplyMeasurementManager\PowerSupplyMeasurementManager.csproj" />
<ProjectReference Include="..\ProgramGUI\ProgramGui.csproj" />
<ProjectReference Include="..\Raytheon.Common\Raytheon.Common.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="NationalInstruments.TestStand.Interop.API">
<HintPath>..\ProgramLib\Dependencies\NationalInstruments.TestStand.Interop.API.dll</HintPath>
</Reference>
<Reference Include="System.Windows" />
</ItemGroup>
<Target Name="CopyFiles" AfterTargets="AfterBuild">
<ItemGroup>
<FILES_1 Include="Dependencies\*.*" />
<FILES_2 Include="InstrumentConfigFile\*.*" />
<FILES_3 Include="Dependencies\RINSS\*.*" />
</ItemGroup>
<Copy SourceFiles="@(FILES_1)" DestinationFolder="$(OutDir)" />
<Copy SourceFiles="@(FILES_2)" DestinationFolder="$(OutDir)InstrumentConfig" />
<Copy SourceFiles="@(FILES_3)" DestinationFolder="$(OutDir)RINSS" />
<Copy SourceFiles="ProgramConfigFile\config.ini" DestinationFolder="$(OutDir)" />
<Copy SourceFiles="MiscConfigFile\NLog.config" DestinationFolder="$(OutDir)" />
</Target>
<Target Name="ProjClean" AfterTargets="AfterClean">
<RemoveDir Directories="$(OutDir)InstrumentConfig" />
<RemoveDir Directories="$(OutDir)RINSS" />
<Delete Files="$(OutDir)config.ini" />
<Delete Files="$(OutDir)NLog.config" />
<Delete Files="$(OutDir)NLogWrapper.Part.dll" />
</Target>
</Project>

View File

@@ -0,0 +1,13 @@
[GENERAL]
; specify data folder and all subfolders in it
DATA_BASE_PATH = C:\NGSRI\Data
DATA_TEMP_PATH = Temp
; specify app folder and all subfolders in it
APP_BASE_PATH = C:\NGSRI\App
; Log names
POWER_SUPPLY_SELF_TEST_DATETIME = power_supply_self_test_datetime.xml
; Rates for tasks/threads (secs)
POWER_SUPPLY_READ_RATE = 2

View File

@@ -0,0 +1,99 @@
/*-------------------------------------------------------------------------
// 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 ProgramGui.Model;
using ProgramGui;
using ProgramLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ProgramLib
{
/// <summary>
/// Monitor fatal failure signaled by other threads
/// </summary>
internal class FailureMonitorThread : BasicThread
{
private enum Events
{
GLOBAL_QUIT,
FATAL_FAILURE,
// DO NOT change the name
// This must be the last member in the enum
EVENT_TIMED_OUT
}
private ILogger _logger;
/// <summary>
/// Constructor
/// </summary>
public FailureMonitorThread()
{
_logger = LogManager.GetCurrentClassLogger();
}
/// <summary>
/// Destructor
/// </summary>
~FailureMonitorThread()
{
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ...");
}
/// <summary>
/// Method that executes on the thread.
/// </summary>
protected override void DoWork()
{
_logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() is running...");
try
{
Dictionary<Events, EventWaitHandle> eventDict = new Dictionary<Events, EventWaitHandle>();
eventDict[Events.GLOBAL_QUIT] = Program.Instance()._eventManager[EventManager.Events.GLOBAL_QUIT];
eventDict[Events.FATAL_FAILURE] = Program.Instance()._eventManager[EventManager.Events.FATAL_FAILURE];
eventDict[Events.EVENT_TIMED_OUT] = null;
EventGroup<Events, EventWaitHandle> eventGroup = new EventGroup<Events, EventWaitHandle>(eventDict);
Events id = eventGroup.WaitAny();
if (id == Events.FATAL_FAILURE)
{
UutPowerAction uutPowerAction = new UutPowerAction();
uutPowerAction.UutPowerOff();
Program.Instance().TerminateTestOnSupportThreadError();
}
}
catch (Exception ex)
{
_logger.Error(ex.Message + "\n" + ex.StackTrace);
}
_logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() is exiting...");
}
}
}

View File

@@ -0,0 +1,202 @@
/*-------------------------------------------------------------------------
// 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 ProgramGui;
using ProgramGui.Model;
using ProgramGui.ViewModel;
using ProgramLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ProgramLib
{
internal class PowerSupplyReadThread : BasicThread
{
private enum Events
{
GLOBAL_QUIT,
UUT_POWER_ON,
UUT_POWER_OFF,
// DO NOT change the name
// This must be the last member in the enum
EVENT_TIMED_OUT
}
private ILogger _logger;
private MainWindow _mainWindow;
private string _powerSupplySystemName;
private Dictionary<string, PowerModuleDataModel> _powerModuleToPowerDataModelDict = new Dictionary<string, PowerModuleDataModel>();
private PassthroughData _passthroughData = null;
public PowerSupplyReadThread(string powerSupplySystemName)
{
_logger = LogManager.GetCurrentClassLogger();
_powerSupplySystemName = powerSupplySystemName;
_mainWindow = (MainWindow)ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.MAIN];
_powerModuleToPowerDataModelDict["UUT_P20V"] = new PowerModuleDataModel();
_powerModuleToPowerDataModelDict["UUT_N20V"] = new PowerModuleDataModel();
_passthroughData = new PassthroughData(_mainWindow.datagridPassthroughData.Columns.Count);
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.MAIN].Dispatcher.Invoke((Action)delegate
{
_mainWindow._mainWindowViewModel.AddPowerData(_powerModuleToPowerDataModelDict);
_mainWindow._mainWindowViewModel.AddPassthroughData(_passthroughData.GetPassthroughDataModelDict());
});
}
~PowerSupplyReadThread()
{
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ...");
}
protected override void DoWork()
{
_logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() for {_powerSupplySystemName} is running...");
try
{
Dictionary<Events, EventWaitHandle> eventDict = new Dictionary<Events, EventWaitHandle>();
eventDict[Events.GLOBAL_QUIT] = Program.Instance()._eventManager[EventManager.Events.GLOBAL_QUIT];
eventDict[Events.UUT_POWER_ON] = Program.Instance()._eventManager[EventManager.Events.UUT_POWER_ON];
eventDict[Events.EVENT_TIMED_OUT] = null;
EventGroup<Events, EventWaitHandle> eventGroup = new EventGroup<Events, EventWaitHandle>(eventDict);
while (true)
{
Events id = eventGroup.WaitAny();
if (id == Events.UUT_POWER_ON)
{
ReadPowerSupplyData();
}
else
break;
}
}
catch (Exception ex)
{
_logger?.Error(ex.Message + "\n" + ex.StackTrace);
}
_logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() for {_powerSupplySystemName} is exiting...");
}
private void ReadPowerSupplyData()
{
int pollRateMs = 1000;
_logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() for {_powerSupplySystemName} is running...");
try
{
Dictionary<Events, EventWaitHandle> eventDict = new Dictionary<Events, EventWaitHandle>();
eventDict[Events.GLOBAL_QUIT] = Program.Instance()._eventManager[EventManager.Events.GLOBAL_QUIT];
eventDict[Events.UUT_POWER_OFF] = Program.Instance()._eventManager[EventManager.Events.UUT_POWER_OFF];
eventDict[Events.EVENT_TIMED_OUT] = null;
EventGroup<Events, EventWaitHandle> eventGroup = new EventGroup<Events, EventWaitHandle>(eventDict);
Random rnd = new Random();
while (true)
{
Events id = eventGroup.WaitAny(pollRateMs);
if (id == Events.EVENT_TIMED_OUT)
{
rnd = new Random();
_mainWindow._mainWindowViewModel.UutPowerLedImagePath = _mainWindow._mainWindowViewModel._imageToResourcePathDict[MainWindowViewModel.Images.LED_OFF];
float num = 20.0f + GenerateRandomFraction();
_powerModuleToPowerDataModelDict["UUT_P20V"].ActualVoltage = num.ToString("0.00");
_powerModuleToPowerDataModelDict["UUT_P20V"].ExpectedVoltage = "20.0";
Thread.Sleep(100);
num = 1.0f + GenerateRandomFraction();
_powerModuleToPowerDataModelDict["UUT_P20V"].ActualCurrent = num.ToString("0.00");
_powerModuleToPowerDataModelDict["UUT_P20V"].ExpectedCurrent = "1.0";
Thread.Sleep(100);
num = 20.0f + GenerateRandomFraction();
_powerModuleToPowerDataModelDict["UUT_N20V"].ActualVoltage = num.ToString("0.00");
_powerModuleToPowerDataModelDict["UUT_N20V"].ExpectedVoltage = "20.0";
Thread.Sleep(200);
_mainWindow._mainWindowViewModel.UutPowerLedImagePath = _mainWindow._mainWindowViewModel._imageToResourcePathDict[MainWindowViewModel.Images.LED_ON];
num = 5.0f + GenerateRandomFraction();
_powerModuleToPowerDataModelDict["UUT_N20V"].ActualCurrent = num.ToString("0.00");
_powerModuleToPowerDataModelDict["UUT_N20V"].ExpectedCurrent = "1.0";
Thread.Sleep(100);
num = 70.0f + GenerateRandomFraction();
_passthroughData.SetValue(PassthroughData.Variables.VAR1, num.ToString("0.00"));
Thread.Sleep(100);
num = 30.0f + GenerateRandomFraction();
_passthroughData.SetValue(PassthroughData.Variables.VAR2, num.ToString("0.00"));
Thread.Sleep(200);
_mainWindow._mainWindowViewModel.UutPowerLedImagePath = _mainWindow._mainWindowViewModel._imageToResourcePathDict[MainWindowViewModel.Images.LED_OFF];
num = 40.0f + GenerateRandomFraction();
_passthroughData.SetValue(PassthroughData.Variables.VAR3, num.ToString("0.00"));
Thread.Sleep(100);
num = 50.0f + GenerateRandomFraction();
_passthroughData.SetValue(PassthroughData.Variables.VAR4, num.ToString("0.00"));
Thread.Sleep(100);
num = 60.0f + GenerateRandomFraction();
_passthroughData.SetValue(PassthroughData.Variables.VAR5, num.ToString("0.00"));
Thread.Sleep(200);
_mainWindow._mainWindowViewModel.UutPowerLedImagePath = _mainWindow._mainWindowViewModel._imageToResourcePathDict[MainWindowViewModel.Images.LED_ON];
num = 10.0f + GenerateRandomFraction();
_passthroughData.SetValue(PassthroughData.Variables.VAR6, num.ToString("0.00"));
}
else
break;
}
}
catch (Exception ex)
{
_logger.Error(ex.Message + "\n" + ex.StackTrace);
}
_logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() for {_powerSupplySystemName} is exiting...");
}
static float GenerateRandomFraction()
{
Random rnd = new Random();
int randNum = 0;
const int minimum = 1;
randNum = rnd.Next(20);
if (randNum <= minimum)
{
randNum += minimum;
}
return (float)(1.0 / (float)randNum);
}
}
}