Major upgrade
This commit is contained in:
253
Source/Program/Actions/PerformSttoAction.cs
Normal file
253
Source/Program/Actions/PerformSttoAction.cs
Normal file
@@ -0,0 +1,253 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// 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.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Xml;
|
||||
using NLog;
|
||||
using ProgramLib.GUI.Model;
|
||||
using ProgramLib.GUI.View;
|
||||
using ProgramLib.GUI.ViewModel;
|
||||
using Raytheon.Common.PdelWriter.Utilities;
|
||||
using static MeasurementManagerLib.SwitchMeasurementManager;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Perform Safe-to-turn-on (STTO)
|
||||
/// </summary>
|
||||
internal class PerformSttoAction : BasicAction
|
||||
{
|
||||
private List<string> _dmmResistanceMeasurements = new List<string>();
|
||||
private static NLog.ILogger _logger;
|
||||
|
||||
private Exception _exceptionFromSuportThread;
|
||||
|
||||
public PerformSttoAction()
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the action
|
||||
/// </summary>
|
||||
public override void Run()
|
||||
{
|
||||
// No need to perform STTO when connected to real missile because signals are not looped back to the switch matrix
|
||||
if (!Program.Instance().IsThereHardware || Program.Instance().UutInfo.UutBuildLevel == UutInfo.BuildLevel.SELF_TEST)
|
||||
{
|
||||
ParseDmmResistanceMeasurementList();
|
||||
|
||||
Task.Factory.StartNew(() => PerformSttoTask());
|
||||
ProgramLib.Program.Instance().GuiManager[ProgramGuiManager.WINDOWS.DEFAULT].Dispatcher.Invoke((Action)delegate
|
||||
{
|
||||
ProgramLib.Program.Instance().GuiManager[ProgramGuiManager.WINDOWS.IMPEDANCE_CHECK].ShowDialog();
|
||||
});
|
||||
|
||||
if (_exceptionFromSuportThread != null)
|
||||
{
|
||||
throw new Exception("Check inner exception.", _exceptionFromSuportThread);
|
||||
}
|
||||
|
||||
RecordDateOfSucessfulSelfTestRunToLog();
|
||||
}
|
||||
else
|
||||
throw new Exception("Please connect W5 cable to perform STTO checks");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record date of successful self test run to log
|
||||
/// </summary>
|
||||
private void RecordDateOfSucessfulSelfTestRunToLog()
|
||||
{
|
||||
if (Program.Instance().IsThereHardware)
|
||||
{
|
||||
XmlDocumentWrapper doc = new XmlDocumentWrapper(Program.Instance().FileAndFolderManager.GetFile(FileAndFolderManager.Files.CABLE_SELF_TEST_RUN_LOG));
|
||||
XmlNode node = doc.GetNode(CableSelfTestConfigXml.SelfTestPath);
|
||||
|
||||
bool existingNodeFound = false;
|
||||
|
||||
while (node != null)
|
||||
{
|
||||
if (node.Attributes[CableSelfTestConfigXml.UniversalCableAttributeName] != null && String.Equals(node.Attributes[CableSelfTestConfigXml.UniversalCableAttributeName].Value, Program.Instance().UutInfo.UniversalCableId.ToString(), StringComparison.OrdinalIgnoreCase)
|
||||
&& node.Attributes[CableSelfTestConfigXml.SacrificialCableAttributeName] != null && String.Equals(node.Attributes[CableSelfTestConfigXml.SacrificialCableAttributeName].Value, Program.Instance().UutInfo.SacrificialCableId.ToString(), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Dictionary<string, string> attributesDict = new Dictionary<string, string>();
|
||||
attributesDict[CableSelfTestConfigXml.LastRunDateAttributeName] = DateTime.Now.ToString("MM/dd/yyyy");
|
||||
|
||||
doc.ChangeNode(node, attributesDict);
|
||||
|
||||
existingNodeFound = true;
|
||||
break;
|
||||
}
|
||||
node = node.NextSibling;
|
||||
}
|
||||
|
||||
if (!existingNodeFound)
|
||||
{
|
||||
Dictionary<string, string> attributesDict = new Dictionary<string, string>();
|
||||
attributesDict[CableSelfTestConfigXml.UniversalCableAttributeName] = Program.Instance().UutInfo.UniversalCableId.ToString();
|
||||
attributesDict[CableSelfTestConfigXml.SacrificialCableAttributeName] = Program.Instance().UutInfo.SacrificialCableId.ToString();
|
||||
attributesDict[CableSelfTestConfigXml.LastRunDateAttributeName] = DateTime.Now.ToString("MM/dd/yyyy");
|
||||
doc.AddNode(CableSelfTestConfigXml.SelfTestPath, attributesDict);
|
||||
}
|
||||
|
||||
doc.SaveToFile();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse resistance measurement list
|
||||
/// </summary>
|
||||
private void ParseDmmResistanceMeasurementList()
|
||||
{
|
||||
string SECTION_NAME = "_STTO";
|
||||
|
||||
string cable = "W3";
|
||||
if (ProgramLib.Program.Instance().UutInfo.SacrificialCableId == UutInfo.SacrificialCable.W4)
|
||||
{
|
||||
cable = "W4";
|
||||
}
|
||||
|
||||
SECTION_NAME = cable + SECTION_NAME;
|
||||
|
||||
List<string> keys = Program.Instance().ProgramSpecificConfig.ReadAllKeys(SECTION_NAME);
|
||||
foreach (string key in keys)
|
||||
{
|
||||
_dmmResistanceMeasurements.Add(Program.Instance().ProgramSpecificConfig.ReadValue(SECTION_NAME, key));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform Safe-to-turn-on checks
|
||||
/// </summary>
|
||||
private void PerformSttoTask()
|
||||
{
|
||||
ImpedanceDataModel impedanceDataModel;
|
||||
ImpedanceCheckWindow impedanceCheckWindow = (ImpedanceCheckWindow)ProgramLib.Program.Instance().GuiManager[ProgramGuiManager.WINDOWS.IMPEDANCE_CHECK];
|
||||
bool sttoSuccess = true;
|
||||
int firstFailIndex = -1;
|
||||
|
||||
try
|
||||
{
|
||||
_logger?.Debug($"{this.GetType().Name}::PerformSttoTask() running...");
|
||||
|
||||
string measurementStatus = "PASSED";
|
||||
|
||||
ImpedanceCheckWindowViewModel.Images passFailImage = ImpedanceCheckWindowViewModel.Images.PASS_CHECK;
|
||||
impedanceCheckWindow.ViewModel.ClearData();
|
||||
|
||||
string sttoFailMsg = String.Empty;
|
||||
int loopCount = 0;
|
||||
|
||||
foreach (string measurement in _dmmResistanceMeasurements)
|
||||
{
|
||||
TestResult pdelResultInfo = new TestResult();
|
||||
measurementStatus = "PASSED";
|
||||
passFailImage = ImpedanceCheckWindowViewModel.Images.PASS_CHECK;
|
||||
impedanceDataModel = new ImpedanceDataModel();
|
||||
DMMResistanceMeasurementFields dmmResistanceMeasurementInfo = Program.Instance().MalMeasurementLibManager.SwitchMeasurementManager.DmmResistanceMeasurements[measurement];
|
||||
double testResult = Program.Instance().MalMeasurementLibManager.SwitchMeasurementManager.DmmReadResistance(measurement);
|
||||
|
||||
if (testResult < dmmResistanceMeasurementInfo._lowerLimit || testResult > dmmResistanceMeasurementInfo._upperLimit)
|
||||
{
|
||||
passFailImage = ImpedanceCheckWindowViewModel.Images.FAIL_CHECK;
|
||||
measurementStatus = "FAILED";
|
||||
sttoSuccess = false;
|
||||
}
|
||||
|
||||
string cableAndPinId = dmmResistanceMeasurementInfo._cableAndPinId;
|
||||
if (Program.Instance().UutInfo.UniversalCableId == UutInfo.UniversalCable.W2)
|
||||
cableAndPinId = Regex.Replace(cableAndPinId, UutInfo.UniversalCable.W1.ToString() + @"_", UutInfo.UniversalCable.W2.ToString() + @"_", RegexOptions.IgnoreCase);
|
||||
|
||||
impedanceDataModel.PassFailImagePath = impedanceCheckWindow.ViewModel.ImageToResourcePathDict[passFailImage];
|
||||
impedanceDataModel.Description = $"{measurement}, {cableAndPinId} Measured {Util.AutoFormatNumberToString(testResult)} Range [{Util.AutoFormatNumberToString(dmmResistanceMeasurementInfo._lowerLimit)}, {Util.AutoFormatNumberToString(dmmResistanceMeasurementInfo._upperLimit)}]";
|
||||
|
||||
if (sttoSuccess == false && String.IsNullOrEmpty(sttoFailMsg))
|
||||
{
|
||||
sttoFailMsg = impedanceDataModel.Description;
|
||||
}
|
||||
|
||||
if (Program.TestStandSeqContext != null)
|
||||
{
|
||||
Program.TestStandSeqContext.Step.AdditionalResults.CustomResults.Insert($"\"{measurement}, {cableAndPinId}\"", $"\"Measured: {Util.AutoFormatNumberToString(testResult)} Range [{Util.AutoFormatNumberToString(dmmResistanceMeasurementInfo._lowerLimit)}, {Util.AutoFormatNumberToString(dmmResistanceMeasurementInfo._upperLimit)}] - {measurementStatus}\"");
|
||||
|
||||
TestStand.ProgramManager.SaveOriginalStepSetting(ProgramLib.Program.TestStandSeqContext.Step.StepIndex, ProgramLib.Program.TestStandSeqContext.StepGroup, ProgramLib.Program.TestStandSeqContext.Step.PostExpression, true);
|
||||
}
|
||||
|
||||
impedanceCheckWindow.ViewModel.AddData(impedanceDataModel);
|
||||
|
||||
pdelResultInfo.PCode = dmmResistanceMeasurementInfo._pcode;
|
||||
pdelResultInfo.TestName = dmmResistanceMeasurementInfo._cableAndPinId;
|
||||
pdelResultInfo.MeasuredValue = Math.Round(testResult, 5);
|
||||
pdelResultInfo.Result = PassFailStatus.Fail;
|
||||
if (measurementStatus == "PASSED")
|
||||
{
|
||||
pdelResultInfo.Result = PassFailStatus.Pass;
|
||||
}
|
||||
|
||||
ProgramLib.Program.Instance().PcodeTestResultList.List.Add(pdelResultInfo);
|
||||
|
||||
if (!sttoSuccess && firstFailIndex == -1)
|
||||
{
|
||||
firstFailIndex = loopCount;
|
||||
}
|
||||
|
||||
loopCount++;
|
||||
}
|
||||
|
||||
if (!sttoSuccess)
|
||||
{
|
||||
throw new Exception(sttoFailMsg);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_exceptionFromSuportThread = ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ProgramLib.Program.Instance().PdelData.TestStopTime = DateTime.Now;
|
||||
if (!sttoSuccess)
|
||||
{
|
||||
impedanceCheckWindow.Dispatcher.Invoke((Action)delegate
|
||||
{
|
||||
impedanceCheckWindow.btnClose.Visibility = Visibility.Visible;
|
||||
|
||||
// scroll to the first failed item
|
||||
if (firstFailIndex != -1)
|
||||
{
|
||||
impedanceCheckWindow.lvImpedanceCheck.ScrollIntoView(impedanceCheckWindow.lvImpedanceCheck.Items.GetItemAt(firstFailIndex));
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
impedanceCheckWindow.Dispatcher.Invoke((Action)delegate
|
||||
{
|
||||
impedanceCheckWindow.Hide();
|
||||
});
|
||||
}
|
||||
|
||||
_logger?.Debug($"{this.GetType().Name}::PerformSttoTask() exiting...");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
302
Source/Program/Actions/PerformTacticalUartCommAction.cs
Normal file
302
Source/Program/Actions/PerformTacticalUartCommAction.cs
Normal file
@@ -0,0 +1,302 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// 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.Threading;
|
||||
using NLog;
|
||||
using Raytheon.Instruments;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Send Test Messages to UUT via TCP sockets
|
||||
/// </summary>
|
||||
internal class PerformTacticalUartCommAction : BasicAction
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private static NLog.ILogger _logger;
|
||||
|
||||
private ICommDevice _serialDevice;
|
||||
|
||||
private List<byte> _receiveByteList = new List<byte>();
|
||||
|
||||
private int _expectedPbitAggregate;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public PerformTacticalUartCommAction()
|
||||
{
|
||||
string expectedPbitAggregate;
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
string serialDeviceInstanceName = Program.Instance().ProgramSpecificConfig.ReadValue("UART_INFO", "SERIAL_DEVICE_INSTANCE_NAME");
|
||||
expectedPbitAggregate = Program.Instance().ProgramSpecificConfig.ReadValue("PBIT_INFO", "SUCCESSFUL_PBIT_AGGREGATE_VALUE");
|
||||
_expectedPbitAggregate = Convert.ToInt32(expectedPbitAggregate, 16);
|
||||
_serialDevice = (ICommDevice)Program.Instance().InstrumentManager.GetGenericInstrument(serialDeviceInstanceName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the action
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
|
||||
|
||||
if (Program.Instance().IsUutPwrOn)
|
||||
{
|
||||
SendHandshakeAndGetResponse();
|
||||
SendAckNackAndGetResponse();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Cannot send message to UUT because UUT is not powered on.");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send AckNack message and get response
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public void SendAckNackAndGetResponse()
|
||||
{
|
||||
UartAckNackMessage msg = new UartAckNackMessage(0x0C, 1);
|
||||
List<byte> msgByteList = Util.StructToByteList(msg).ToList();
|
||||
// remove checksum byte
|
||||
msgByteList.RemoveAt(msgByteList.Count - 1);
|
||||
msgByteList.Add(Util.GetTwosComplimentChecksum(msgByteList.ToArray()));
|
||||
_serialDevice.Write(msgByteList.ToArray(), (uint)msgByteList.Count);
|
||||
_logger.Info($"Raw AckNackMsg Sent: {Util.ByteArrayToHexString(msgByteList.ToArray())}");
|
||||
|
||||
UartPbitResultMessage pbitMsg = new UartPbitResultMessage();
|
||||
List<byte> pbitMsgByteList = Util.StructToByteList(pbitMsg).ToList();
|
||||
|
||||
_logger.Info($"Waiting for PBIT Result from UUT");
|
||||
byte[] byteArray;
|
||||
DateTime startDateTime = DateTime.Now;
|
||||
TimeSpan ts = DateTime.Now - startDateTime;
|
||||
const int MAX_PBIT_WAIT_SEC = 7;
|
||||
List<byte> pBitReceivedByteList = new List<byte>();
|
||||
bool pBitMsgFound = false;
|
||||
while (ts.TotalSeconds < MAX_PBIT_WAIT_SEC)
|
||||
{
|
||||
ts = DateTime.Now - startDateTime;
|
||||
|
||||
if (TacticalUartReadThread._byteQueue.Count > 0)
|
||||
{
|
||||
TacticalUartReadThread._byteQueue.TryDequeue(out byteArray);
|
||||
_receiveByteList.AddRange(byteArray);
|
||||
}
|
||||
else
|
||||
Thread.Sleep(100);
|
||||
|
||||
if (_receiveByteList.Count < pbitMsgByteList.Count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
bool needMoreData = false;
|
||||
do
|
||||
{
|
||||
if (_receiveByteList[index] == pbitMsg.Id)
|
||||
{
|
||||
pBitReceivedByteList = _receiveByteList.Skip(index).Take(_receiveByteList.Count - index).ToList();
|
||||
if (pBitReceivedByteList.Count < pbitMsgByteList.Count)
|
||||
{
|
||||
_receiveByteList = pBitReceivedByteList;
|
||||
needMoreData = true;
|
||||
break;
|
||||
}
|
||||
|
||||
pBitReceivedByteList = pBitReceivedByteList.Skip(0).Take(pbitMsgByteList.Count).ToList();
|
||||
if (Util.GetTwosComplimentChecksum(pBitReceivedByteList.Skip(0).Take(pbitMsgByteList.Count - 1).ToArray()) != pBitReceivedByteList[pBitReceivedByteList.Count - 1])
|
||||
{
|
||||
index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
int numBytesToRemove = index + pBitReceivedByteList.Count;
|
||||
|
||||
if (numBytesToRemove == _receiveByteList.Count)
|
||||
_receiveByteList.Clear();
|
||||
else
|
||||
_receiveByteList = _receiveByteList.Skip(numBytesToRemove).Take(_receiveByteList.Count - numBytesToRemove).ToList();
|
||||
|
||||
pBitMsgFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
index++;
|
||||
|
||||
if (index == _receiveByteList.Count)
|
||||
{
|
||||
_receiveByteList.Clear();
|
||||
needMoreData = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
|
||||
if (!needMoreData)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pBitMsgFound)
|
||||
{
|
||||
_logger.Info($"Raw Msg Received: {Util.ByteArrayToHexString(pBitReceivedByteList.ToArray(), pbitMsgByteList.Count)}");
|
||||
|
||||
UartPbitResultMessage rsp = Util.ByteArrayToStruct<UartPbitResultMessage>(pBitReceivedByteList.ToArray());
|
||||
_logger.Info($"PbitResult Fields: PbitFinalResult={rsp.PbitFinalResult}, PbitAggregate=0x{rsp.PbitAggregate.ToString("X4")}, GSP_Temp={rsp.GspTemp} C, Lifetime_Time={rsp.LifetimeTime} sec, Lifetime_Count={rsp.LifetimeCount}");
|
||||
|
||||
if (rsp.PbitAggregate != _expectedPbitAggregate)
|
||||
{
|
||||
_logger.Error("UUT's PBIT failed.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Timed out waiting for PBIT result.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send Handshake message and get response
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public void SendHandshakeAndGetResponse()
|
||||
{
|
||||
UartHandshakeMessage handshakeMsg = new UartHandshakeMessage(0xCCAAFFEEDDAAEEDD, 0xDDEEAADDEEFFAACC);
|
||||
List<byte> handshakeMsgByteList = Util.StructToByteList(handshakeMsg).ToList();
|
||||
// remove checksum byte
|
||||
handshakeMsgByteList.RemoveAt(handshakeMsgByteList.Count - 1);
|
||||
handshakeMsgByteList.Add(Util.GetTwosComplimentChecksum(handshakeMsgByteList.ToArray()));
|
||||
_serialDevice.Write(handshakeMsgByteList.ToArray(), (uint)handshakeMsgByteList.Count);
|
||||
_logger.Info($"Raw HandshakeMsg Sent: {Util.ByteArrayToHexString(handshakeMsgByteList.ToArray())}");
|
||||
|
||||
_logger.Info($"Waiting for HandshakeMsg from UUT");
|
||||
byte[] byteArray;
|
||||
DateTime startDateTime = DateTime.Now;
|
||||
TimeSpan ts = DateTime.Now - startDateTime;
|
||||
const int MAX_HANDSHAKE_WAIT_SEC = 7;
|
||||
List<byte> handshakeReceivedByteList = new List<byte>();
|
||||
bool handshakeMsgFound = false;
|
||||
double secondCount = 0.0;
|
||||
while (ts.TotalSeconds < MAX_HANDSHAKE_WAIT_SEC)
|
||||
{
|
||||
ts = DateTime.Now - startDateTime;
|
||||
|
||||
if (ts.TotalSeconds > secondCount)
|
||||
{
|
||||
_serialDevice.Write(handshakeMsgByteList.ToArray(), (uint)handshakeMsgByteList.Count);
|
||||
_logger.Info($"Raw HandshakeMsg Sent: {Util.ByteArrayToHexString(handshakeMsgByteList.ToArray())}");
|
||||
secondCount = ts.TotalSeconds;
|
||||
}
|
||||
|
||||
if (TacticalUartReadThread._byteQueue.Count > 0)
|
||||
{
|
||||
TacticalUartReadThread._byteQueue.TryDequeue(out byteArray);
|
||||
_receiveByteList.AddRange(byteArray);
|
||||
}
|
||||
else
|
||||
Thread.Sleep(100);
|
||||
|
||||
if (_receiveByteList.Count < handshakeMsgByteList.Count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
bool needMoreData = false;
|
||||
do
|
||||
{
|
||||
if (_receiveByteList[index] == handshakeMsg.Id)
|
||||
{
|
||||
handshakeReceivedByteList = _receiveByteList.Skip(index).Take(_receiveByteList.Count - index).ToList();
|
||||
if (handshakeReceivedByteList.Count < handshakeMsgByteList.Count)
|
||||
{
|
||||
_receiveByteList = handshakeReceivedByteList;
|
||||
needMoreData = true;
|
||||
break;
|
||||
}
|
||||
|
||||
handshakeReceivedByteList = handshakeReceivedByteList.Skip(0).Take(handshakeMsgByteList.Count).ToList();
|
||||
if (Util.GetTwosComplimentChecksum(handshakeReceivedByteList.Skip(0).Take(handshakeMsgByteList.Count - 1).ToArray()) != handshakeReceivedByteList[handshakeReceivedByteList.Count - 1])
|
||||
{
|
||||
index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
int numBytesToRemove = index + handshakeReceivedByteList.Count;
|
||||
|
||||
if (numBytesToRemove == _receiveByteList.Count)
|
||||
_receiveByteList.Clear();
|
||||
else
|
||||
_receiveByteList = _receiveByteList.Skip(numBytesToRemove).Take(_receiveByteList.Count - numBytesToRemove).ToList();
|
||||
|
||||
handshakeMsgFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
index++;
|
||||
|
||||
if (index == _receiveByteList.Count)
|
||||
{
|
||||
_receiveByteList.Clear();
|
||||
needMoreData = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
|
||||
if (!needMoreData)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (handshakeMsgFound)
|
||||
{
|
||||
_logger.Info($"Raw Msg Received: {Util.ByteArrayToHexString(handshakeReceivedByteList.ToArray(), handshakeMsgByteList.Count)}");
|
||||
|
||||
UartHandshakeMessage rsp = Util.ByteArrayToStruct<UartHandshakeMessage>(handshakeReceivedByteList.ToArray());
|
||||
_logger.Info($"Handshake Fields: Pattern1=0x{rsp.Pattern1.ToString("X8")}, Pattern2=0x{rsp.Pattern2.ToString("X8")}");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Timed out waiting for HandshakeMsg.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
130
Source/Program/Actions/SendCoeAdnucMsgToUutAction.cs
Normal file
130
Source/Program/Actions/SendCoeAdnucMsgToUutAction.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// 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 NLog;
|
||||
using Raytheon.Common.Coe;
|
||||
using Raytheon.Instruments;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Send COE Message to UUT
|
||||
/// </summary>
|
||||
internal class SendCoeAdnucMsgToUutAction : BasicAction
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private static NLog.ILogger _logger;
|
||||
|
||||
private string _coeDeviceName;
|
||||
private string _msgName = "NgsriAdnucStateMsg";
|
||||
|
||||
public static Coe.MmgrState mMgrState = Coe.MmgrState.NOT_SET;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="coeDeviceName">name of COE device</param>
|
||||
/// <returns></returns>
|
||||
public SendCoeAdnucMsgToUutAction(string coeDeviceName)
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
_coeDeviceName = coeDeviceName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the action
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
|
||||
|
||||
if (Program.Instance().IsUutPwrOn)
|
||||
{
|
||||
CoeResponseMsgData missionManagerMsg = null;
|
||||
bool firstMissionManagerMsgReceived = false;
|
||||
const int MAX_RETRIES = 5;
|
||||
int retry = 0;
|
||||
CoeFieldData val = null;
|
||||
mMgrState = Coe.MmgrState.NOT_SET;
|
||||
Coe.MmgrState desiredMmgrState = Coe.MmgrState.CALIBRATION;
|
||||
|
||||
string missionManagerMessageName = "MissionManagerMsgLL";
|
||||
_logger.Info($"Waiting for message {missionManagerMessageName}");
|
||||
do
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
missionManagerMsg = Program.Instance().MalMeasurementLibManager.CoeMeasurementManager.GetNextResponseInQueue(_coeDeviceName, missionManagerMessageName);
|
||||
|
||||
if (missionManagerMsg != null)
|
||||
{
|
||||
if (!firstMissionManagerMsgReceived)
|
||||
firstMissionManagerMsgReceived = true;
|
||||
|
||||
val = missionManagerMsg.GetFieldData("data.mmgrState");
|
||||
|
||||
if (Enum.TryParse(val.FieldValue, out mMgrState))
|
||||
{
|
||||
_logger.Info($"Current mission state: {mMgrState.ToString()}");
|
||||
|
||||
if (mMgrState == desiredMmgrState)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Warn($"Invalid mission state: {val.FieldValue}");
|
||||
}
|
||||
}
|
||||
} while (retry++ < MAX_RETRIES && (missionManagerMsg == null || mMgrState != desiredMmgrState));
|
||||
|
||||
if (!firstMissionManagerMsgReceived)
|
||||
{
|
||||
throw new Exception($"Timed out waiting for Mission Manager's state message");
|
||||
}
|
||||
|
||||
if (mMgrState != desiredMmgrState)
|
||||
{
|
||||
throw new Exception($"Timed out waiting for Mission Manager to transition to {desiredMmgrState}");
|
||||
}
|
||||
|
||||
Thread.Sleep(1000);
|
||||
Message msg = Program.Instance().MalMeasurementLibManager.CoeMeasurementManager.CreateMessage(_coeDeviceName, _msgName);
|
||||
string adnucState = "2";
|
||||
msg.Set("data.adnucState", adnucState);
|
||||
var parms = msg.GetParameters();
|
||||
_logger.Info($"Sending {_msgName}, adnucState={adnucState}");
|
||||
Program.Instance().MalMeasurementLibManager.CoeMeasurementManager.SendMessage(_coeDeviceName, _msgName, parms);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Cannot send message to UUT because UUT is not powered on.");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
130
Source/Program/Actions/SendCoeBatteryGoodMsgToUutAction.cs
Normal file
130
Source/Program/Actions/SendCoeBatteryGoodMsgToUutAction.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// 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 NLog;
|
||||
using Raytheon.Common.Coe;
|
||||
using Raytheon.Instruments;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Send COE Message to UUT
|
||||
/// </summary>
|
||||
internal class SendCoeBatteryGoodMsgToUutAction : BasicAction
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private static NLog.ILogger _logger;
|
||||
|
||||
private string _coeDeviceName;
|
||||
private string _msgName = "UmbilicalRetractBatteryGoodMsg";
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="coeDeviceName">name of COE device</param>
|
||||
/// <returns></returns>
|
||||
public SendCoeBatteryGoodMsgToUutAction(string coeDeviceName)
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
_coeDeviceName = coeDeviceName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the action
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
|
||||
|
||||
if (Program.Instance().IsUutPwrOn)
|
||||
{
|
||||
if (SendCoeUncageMsgToUutAction.mMgrState == Coe.MmgrState.ACQUISITION)
|
||||
{
|
||||
CoeResponseMsgData missionManagerMsg = null;
|
||||
bool firstMissionManagerMsgReceived = false;
|
||||
const int MAX_RETRIES = 5;
|
||||
int retry = 0;
|
||||
CoeFieldData val = null;
|
||||
Coe.MmgrState mMgrState = Coe.MmgrState.NOT_SET;
|
||||
Coe.MmgrState desiredMmgrState = Coe.MmgrState.PRELAUNCH;
|
||||
|
||||
string missionManagerMessageName = "MissionManagerMsgLL";
|
||||
_logger.Info($"Waiting for message {missionManagerMessageName}");
|
||||
do
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
missionManagerMsg = Program.Instance().MalMeasurementLibManager.CoeMeasurementManager.GetNextResponseInQueue(_coeDeviceName, missionManagerMessageName);
|
||||
|
||||
if (missionManagerMsg != null)
|
||||
{
|
||||
if (!firstMissionManagerMsgReceived)
|
||||
firstMissionManagerMsgReceived = true;
|
||||
|
||||
val = missionManagerMsg.GetFieldData("data.mmgrState");
|
||||
|
||||
if (Enum.TryParse(val.FieldValue, out mMgrState))
|
||||
{
|
||||
_logger.Info($"Current mission state: {mMgrState.ToString()}");
|
||||
|
||||
if (mMgrState == desiredMmgrState)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Warn($"Invalid mission state: {val.FieldValue}");
|
||||
}
|
||||
}
|
||||
} while (retry++ < MAX_RETRIES && (missionManagerMsg == null || mMgrState != desiredMmgrState));
|
||||
|
||||
if (!firstMissionManagerMsgReceived)
|
||||
{
|
||||
throw new Exception($"Timed out waiting for Mission Manager's state message");
|
||||
}
|
||||
|
||||
if (mMgrState != desiredMmgrState)
|
||||
{
|
||||
throw new Exception($"Timed out waiting for Mission Manager to transition to {desiredMmgrState}");
|
||||
}
|
||||
|
||||
Message msg = Program.Instance().MalMeasurementLibManager.CoeMeasurementManager.CreateMessage(_coeDeviceName, _msgName);
|
||||
string batteryGoodState = "1";
|
||||
msg.Set("data.umbilicalRetractBatteryGood", batteryGoodState);
|
||||
var parms = msg.GetParameters();
|
||||
_logger.Info($"Sending {_msgName}, umbilicalRetractBatteryGood={batteryGoodState}");
|
||||
Program.Instance().MalMeasurementLibManager.CoeMeasurementManager.SendMessage(_coeDeviceName, _msgName, parms);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Cannot send message to UUT because UUT is not powered on.");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
132
Source/Program/Actions/SendCoeUncageMsgToUutAction.cs
Normal file
132
Source/Program/Actions/SendCoeUncageMsgToUutAction.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// 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 NLog;
|
||||
using Raytheon.Common.Coe;
|
||||
using Raytheon.Instruments;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Send COE Message to UUT
|
||||
/// </summary>
|
||||
internal class SendCoeUncageMsgToUutAction : BasicAction
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private static NLog.ILogger _logger;
|
||||
|
||||
private string _coeDeviceName;
|
||||
private string _msgName = "CageStateMsg";
|
||||
|
||||
public static Coe.MmgrState mMgrState = Coe.MmgrState.NOT_SET;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="coeDeviceName">name of COE device</param>
|
||||
/// <returns></returns>
|
||||
public SendCoeUncageMsgToUutAction(string coeDeviceName)
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
_coeDeviceName = coeDeviceName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the action
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
|
||||
|
||||
if (Program.Instance().IsUutPwrOn)
|
||||
{
|
||||
if (SendCoeAdnucMsgToUutAction.mMgrState == Coe.MmgrState.CALIBRATION)
|
||||
{
|
||||
CoeResponseMsgData missionManagerMsg = null;
|
||||
bool firstMissionManagerMsgReceived = false;
|
||||
const int MAX_RETRIES = 5;
|
||||
int retry = 0;
|
||||
CoeFieldData val = null;
|
||||
mMgrState = Coe.MmgrState.NOT_SET;
|
||||
Coe.MmgrState desiredMmgrState = Coe.MmgrState.ACQUISITION;
|
||||
|
||||
string missionManagerMessageName = "MissionManagerMsgLL";
|
||||
_logger.Info($"Waiting for message {missionManagerMessageName}");
|
||||
do
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
missionManagerMsg = Program.Instance().MalMeasurementLibManager.CoeMeasurementManager.GetNextResponseInQueue(_coeDeviceName, missionManagerMessageName);
|
||||
|
||||
if (missionManagerMsg != null)
|
||||
{
|
||||
if (!firstMissionManagerMsgReceived)
|
||||
firstMissionManagerMsgReceived = true;
|
||||
|
||||
val = missionManagerMsg.GetFieldData("data.mmgrState");
|
||||
|
||||
if (Enum.TryParse(val.FieldValue, out mMgrState))
|
||||
{
|
||||
_logger.Info($"Current mission state: {mMgrState.ToString()}");
|
||||
|
||||
if (mMgrState == desiredMmgrState)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Warn($"Invalid mission state: {val.FieldValue}");
|
||||
}
|
||||
}
|
||||
} while (retry++ < MAX_RETRIES && (missionManagerMsg == null || mMgrState != desiredMmgrState));
|
||||
|
||||
if (!firstMissionManagerMsgReceived)
|
||||
{
|
||||
throw new Exception($"Timed out waiting for Mission Manager's state message");
|
||||
}
|
||||
|
||||
if (mMgrState != desiredMmgrState)
|
||||
{
|
||||
throw new Exception($"Timed out waiting for Mission Manager to transition to {desiredMmgrState}");
|
||||
}
|
||||
|
||||
Message msg = Program.Instance().MalMeasurementLibManager.CoeMeasurementManager.CreateMessage(_coeDeviceName, _msgName);
|
||||
string cageState = "1";
|
||||
msg.Set("data.uncaged", cageState);
|
||||
var parms = msg.GetParameters();
|
||||
_logger.Info($"Sending {_msgName}, uncaged={cageState}");
|
||||
Program.Instance().MalMeasurementLibManager.CoeMeasurementManager.SendMessage(_coeDeviceName, _msgName, parms);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Cannot send message to UUT because UUT is not powered on.");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
234
Source/Program/Actions/SendTestMessageToUutAction.cs
Normal file
234
Source/Program/Actions/SendTestMessageToUutAction.cs
Normal 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using NLog;
|
||||
using ProgramLib.GUI.View;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Send Test Messages to UUT via TCP sockets
|
||||
/// </summary>
|
||||
internal class SendTestMessageToUutAction : BasicAction
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private static NLog.ILogger _logger;
|
||||
private string _messageName;
|
||||
private string _iniKeyForData;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="messageName">name of the message that is defined in the UutTestMessages.XML file</param>
|
||||
/// <param name="iniKeyForData">section name in the ProgramSpecific.ini that specifies the values for data fields in this message</param>
|
||||
/// <returns></returns>
|
||||
public SendTestMessageToUutAction(string messageName, string iniKeyForData = null)
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
_messageName = messageName;
|
||||
_iniKeyForData = iniKeyForData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the action
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
|
||||
|
||||
if (Program.Instance().IsUutPwrOn)
|
||||
{
|
||||
SendMessageToUut();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Cannot send message to UUT because UUT is not powered on.");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send message to UUT
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private void SendMessageToUut()
|
||||
{
|
||||
string msfrTestCase = null;
|
||||
if (Program.Instance().EthernetSocketManager.GetTcpClient(TcpClientNames.UUT_TEST_PORT) != null)
|
||||
{
|
||||
if (String.Equals(_messageName, "MSFRParameterMsg", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
MsfrTestCasesWindow win = (MsfrTestCasesWindow)ProgramLib.Program.Instance().GuiManager[ProgramLib.ProgramGuiManager.WINDOWS.MSFR_TEST_CASES];
|
||||
|
||||
ProgramLib.Program.Instance().GuiManager[ProgramGuiManager.WINDOWS.DEFAULT].Dispatcher.Invoke((Action)delegate
|
||||
{
|
||||
if (win.cbMsfrTestCases.SelectedItem != null)
|
||||
msfrTestCase = win.cbMsfrTestCases.SelectedValue.ToString();
|
||||
});
|
||||
|
||||
if (!String.IsNullOrEmpty(msfrTestCase))
|
||||
{
|
||||
int index = msfrTestCase.IndexOf('.');
|
||||
_iniKeyForData = $"TEST_CASE_{msfrTestCase.Substring(0, index)}";
|
||||
}
|
||||
else
|
||||
throw new Exception("No MSFR test case was specified");
|
||||
}
|
||||
byte[] byteArray = ConstructByteArrayFromMessageData();
|
||||
Program.Instance().EthernetSocketManager.GetTcpClient(TcpClientNames.UUT_TEST_PORT).Write(byteArray);
|
||||
string desc = $"Sent {_messageName}.";
|
||||
if (String.Equals(_messageName, "MSFRParameterMsg", StringComparison.OrdinalIgnoreCase))
|
||||
desc += $" Test case: {msfrTestCase}";
|
||||
_logger.Info(desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Cannot send message to UUT because socket connection hasn't been established.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pack all data in the message to byte array to be sent
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private byte[] ConstructByteArrayFromMessageData()
|
||||
{
|
||||
List<byte> byteList = new List<byte>();
|
||||
string val = String.Empty;
|
||||
string sourceError = String.Empty;
|
||||
|
||||
if (Program.Instance().UutInfo.UutTestMessageDict.ContainsKey(_messageName))
|
||||
{
|
||||
string[] dataArray = Program.Instance().ProgramSpecificConfig.ReadValue(_messageName, _iniKeyForData).Split(',');
|
||||
int dataArrayIndex = -1;
|
||||
if (String.Equals(_messageName, "MSFRParameterMsg", StringComparison.OrdinalIgnoreCase))
|
||||
dataArrayIndex++;
|
||||
|
||||
foreach (UutTestMessageDataFieldInfo item in Program.Instance().UutInfo.UutTestMessageDict[_messageName])
|
||||
{
|
||||
dataArrayIndex++;
|
||||
val = item.Value;
|
||||
if (String.Equals(item.Value, "not_set", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
sourceError = $"Key: {_iniKeyForData}. Section: {_messageName}. File: {Program.Instance().ProgramSpecificConfig.FileName}";
|
||||
val = dataArray[dataArrayIndex].Trim();
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceError = $"Message: {_messageName}. Data Field: {item.Name}. File: {Program.Instance().UutInfo.UutTestMessageConfigFilePath}";
|
||||
}
|
||||
|
||||
string type = item.Type.ToLower();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case "string":
|
||||
if (val.Length > item.ByteCount)
|
||||
{
|
||||
throw new Exception($"The value {val} exceeds the allowable length of {item.ByteCount} characters. {sourceError}");
|
||||
}
|
||||
else if (val.Length < item.ByteCount)
|
||||
{
|
||||
for (int i = val.Length; i < item.ByteCount; i++)
|
||||
{
|
||||
val += '\0';
|
||||
}
|
||||
}
|
||||
|
||||
byteList.AddRange(Encoding.ASCII.GetBytes(val));
|
||||
|
||||
break;
|
||||
case "bool":
|
||||
if (val == "1")
|
||||
val = "true";
|
||||
else if (val == "0")
|
||||
val = "false";
|
||||
if (bool.TryParse(val, out bool boolVal))
|
||||
{
|
||||
byteList.Add(Convert.ToByte(boolVal));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"The value {val} is not of type {item.Type}. It must be either true/false. {sourceError}");
|
||||
}
|
||||
break;
|
||||
case "uint8":
|
||||
if (byte.TryParse(val, out byte byteVal))
|
||||
{
|
||||
byteList.Add(byteVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"The value {val} is not of type {item.Type}. {sourceError}");
|
||||
}
|
||||
break;
|
||||
case "uint32":
|
||||
if (UInt32.TryParse(val, out UInt32 uint32Val))
|
||||
{
|
||||
byteList.AddRange(BitConverter.GetBytes(uint32Val));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"The value {val} is not of type {item.Type}. {sourceError}");
|
||||
}
|
||||
break;
|
||||
case "double":
|
||||
if (Double.TryParse(val, out Double doubleVal))
|
||||
{
|
||||
byteList.AddRange(BitConverter.GetBytes(doubleVal));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"The value {val} is not of type {item.Type}. {sourceError}");
|
||||
}
|
||||
break;
|
||||
case "float":
|
||||
if (float.TryParse(val, out float floatVal))
|
||||
{
|
||||
byteList.AddRange(BitConverter.GetBytes(floatVal));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"The value {val} is not of type {item.Type}. {sourceError}");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"{item.Type} is not a supported type. {sourceError}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Message {_messageName} does not exist in {Program.Instance().UutInfo.UutTestMessageConfigFilePath}.");
|
||||
}
|
||||
|
||||
return byteList.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Source/Program/Actions/StartTacticalUartReadThreadAction.cs
Normal file
60
Source/Program/Actions/StartTacticalUartReadThreadAction.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// 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 NLog;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Start tactical UART read thread
|
||||
/// </summary>
|
||||
internal class StartTacticalUartReadThreadAction : BasicAction
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private static NLog.ILogger _logger;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public StartTacticalUartReadThreadAction()
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the action
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
|
||||
|
||||
TacticalUartReadThread tacticalUartReadThread = new TacticalUartReadThread();
|
||||
tacticalUartReadThread.Start();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
137
Source/Program/Actions/UartLoopBackAction.cs
Normal file
137
Source/Program/Actions/UartLoopBackAction.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// 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 NLog;
|
||||
using Raytheon.Instruments;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Perform UART loopback test
|
||||
/// </summary>
|
||||
internal class UartLoopBackAction : BasicAction
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private static NLog.ILogger _logger;
|
||||
|
||||
private ICommDevice _serialDevice;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public UartLoopBackAction()
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
string serialDeviceInstanceName = Program.Instance().ProgramSpecificConfig.ReadValue("UART_INFO", "SERIAL_DEVICE_INSTANCE_NAME");
|
||||
_serialDevice = (ICommDevice)Program.Instance().InstrumentManager.GetGenericInstrument(serialDeviceInstanceName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the action
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
|
||||
|
||||
SendCommandAndGetResponse();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send commnd and get response
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public void SendCommandAndGetResponse()
|
||||
{
|
||||
UartHandshakeMessage msg = new UartHandshakeMessage(0xCCAAFFEEDDAAEEDD, 0xDDEEAADDEEFFAACC);
|
||||
List<byte> msgByteList = Util.StructToByteList(msg).ToList();
|
||||
// remove checksum byte
|
||||
msgByteList.RemoveAt(msgByteList.Count - 1);
|
||||
msgByteList.Add(Util.GetTwosComplimentChecksum(msgByteList.ToArray()));
|
||||
_serialDevice.Write(msgByteList.ToArray(), (uint)msgByteList.Count);
|
||||
_logger.Info($"Raw message sent: {Util.ByteArrayToHexString(msgByteList.ToArray())}");
|
||||
|
||||
List<byte> receiveByteList = new List<byte>();
|
||||
byte[] receiveByteArray = null;
|
||||
uint totalBytesRead = 0;
|
||||
|
||||
_logger.Info($"Waiting for message to be looped back...");
|
||||
|
||||
uint numBytesRead = _serialDevice.Read(ref receiveByteArray);
|
||||
// this is for loopback, we read too fast and we're only getting partial data
|
||||
if (numBytesRead < msgByteList.Count)
|
||||
{
|
||||
_serialDevice.SetReadTimeout(100);
|
||||
try
|
||||
{
|
||||
do
|
||||
{
|
||||
totalBytesRead += numBytesRead;
|
||||
receiveByteList.AddRange(receiveByteArray.Skip(0).Take((int)numBytesRead).ToArray());
|
||||
receiveByteArray = null;
|
||||
numBytesRead = _serialDevice.Read(ref receiveByteArray);
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
catch { }
|
||||
// reset to default timeout
|
||||
_serialDevice.SetReadTimeout();
|
||||
receiveByteArray = receiveByteList.ToArray();
|
||||
}
|
||||
else
|
||||
totalBytesRead = numBytesRead;
|
||||
|
||||
_logger.Info($"Raw Msg Received: {Util.ByteArrayToHexString(receiveByteArray, (int)totalBytesRead)}");
|
||||
|
||||
if (totalBytesRead != msgByteList.Count)
|
||||
{
|
||||
throw new Exception($"Unexpected message size. Expected msg size: {msgByteList.Count}. Actual msg size: {totalBytesRead}");
|
||||
}
|
||||
|
||||
bool loopbackSuccess = true;
|
||||
for (int i = 0; i < totalBytesRead; i++)
|
||||
{
|
||||
if (msgByteList[i] != receiveByteArray[i])
|
||||
{
|
||||
loopbackSuccess = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!loopbackSuccess)
|
||||
{
|
||||
throw new Exception($"Messages sent and received don't match");
|
||||
}
|
||||
|
||||
_logger.Info($"UART loopback is successful.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// 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 ProgramLib.GUI.Model;
|
||||
using ProgramLib.GUI.View;
|
||||
using ProgramLib.GUI.ViewModel;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
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...");
|
||||
|
||||
if (Program.Instance()._isUutPwrOn)
|
||||
{
|
||||
Program.Instance().MalMeasurementLibManager.PowerSupplyMeasurementManager.OutputDisable("STE_PVM_5V");
|
||||
// enable front panel
|
||||
Program.Instance().MalMeasurementLibManager.PowerSupplyMeasurementManager.DisplayEnable("STE_POWER_SUPPLY_SYSTEM");
|
||||
|
||||
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.LIVE_DATA].Dispatcher.Invoke((Action)delegate
|
||||
{
|
||||
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.LIVE_DATA].Hide();
|
||||
});
|
||||
|
||||
Program.Instance().EventManager[EventManager.Events.UUT_POWER_ON].Reset();
|
||||
Program.Instance().EventManager[EventManager.Events.UUT_POWER_OFF].Set();
|
||||
|
||||
Program.Instance()._isUutPwrOn = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
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...");
|
||||
|
||||
if (!Program.Instance()._isUutPwrOn)
|
||||
{
|
||||
Task.Factory.StartNew(() => PerformSttoTask());
|
||||
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.IMPEDANCE_CHECK].Dispatcher.Invoke((Action)delegate
|
||||
{
|
||||
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.LIVE_DATA].Hide();
|
||||
|
||||
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.IMPEDANCE_CHECK].ShowDialog();
|
||||
});
|
||||
|
||||
if (_sttoSuccess)
|
||||
{
|
||||
Program.Instance().PowerSupplySharedData.ResetAll();
|
||||
|
||||
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.IMPEDANCE_CHECK].Dispatcher.Invoke((Action)delegate
|
||||
{
|
||||
ProgramLib.Program.Instance().GetGuiManager()[ProgramGuiManager.WINDOWS.LIVE_DATA].Show();
|
||||
});
|
||||
|
||||
Program.Instance().MalMeasurementLibManager.PowerSupplyMeasurementManager.OutputEnable("STE_PVM_5V");
|
||||
|
||||
// disable front panel
|
||||
Program.Instance().MalMeasurementLibManager.PowerSupplyMeasurementManager.DisplayDisable("STE_POWER_SUPPLY_SYSTEM");
|
||||
|
||||
Program.Instance().EventManager[EventManager.Events.UUT_POWER_OFF].Reset();
|
||||
Program.Instance().EventManager[EventManager.Events.UUT_POWER_ON].Set();
|
||||
|
||||
Program.Instance()._isUutPwrOn = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(fatalErrorMsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("UUT power is already on.");
|
||||
}
|
||||
}
|
||||
}
|
||||
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...");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
128
Source/Program/Actions/UutPowerOffAction.cs
Normal file
128
Source/Program/Actions/UutPowerOffAction.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// 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.Xml;
|
||||
using NLog;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Power off UUT
|
||||
/// </summary>
|
||||
internal class UutPowerOffAction : BasicAction
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private static NLog.ILogger _logger;
|
||||
|
||||
private static object _syncObj = new object();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public UutPowerOffAction()
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the action
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (Program.Instance().IsUutPwrOn)
|
||||
{
|
||||
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
|
||||
|
||||
foreach (var item in ProgramLib.Program.Instance().PowerModulesToBePowered)
|
||||
Program.Instance().MalMeasurementLibManager.PowerSupplyMeasurementManager.OutputDisable(item);
|
||||
|
||||
RecordPowerOffTimeToFile();
|
||||
|
||||
// enable front panel
|
||||
//Program.Instance().MalMeasurementLibManager.PowerSupplyMeasurementManager.DisplayEnable("STE_POWER_SUPPLY_SYSTEM");
|
||||
|
||||
Program.Instance().EventManager[EventManager.Events.UUT_POWER_ON].Reset();
|
||||
Program.Instance().EventManager[EventManager.Events.UUT_POWER_OFF].Set();
|
||||
|
||||
Program.Instance().IsUutPwrOn = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse ini file for modules to be powered on
|
||||
/// </summary>
|
||||
public void ParseProgramSpecificConfig()
|
||||
{
|
||||
try
|
||||
{
|
||||
List<string> keys = Program.Instance().ProgramSpecificConfig.ReadAllKeys(ProgramSpecificConfigIni.POWER_MODULES_TO_BE_POWERED.ToString());
|
||||
foreach (string key in keys)
|
||||
{
|
||||
string powerSupplyModule = Program.Instance().ProgramSpecificConfig.ReadValue(ProgramSpecificConfigIni.POWER_MODULES_TO_BE_POWERED.ToString(), key);
|
||||
|
||||
if (!Program.Instance().PowerModulesToBePowered.Contains(powerSupplyModule, StringComparer.OrdinalIgnoreCase))
|
||||
Program.Instance().PowerModulesToBePowered.Add(powerSupplyModule);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record power off time
|
||||
/// </summary>
|
||||
private void RecordPowerOffTimeToFile()
|
||||
{
|
||||
XmlDocumentWrapper doc = new XmlDocumentWrapper(Program.Instance().FileAndFolderManager.GetFile(FileAndFolderManager.Files.TEST_RUN_LOG));
|
||||
|
||||
XmlNode node = doc.GetNode(TestRunConfigXml.TestRunPowerPath);
|
||||
|
||||
XmlAttribute onDateAttr = node.Attributes[TestRunConfigXml.TestRunPowerOnDateAttributeName];
|
||||
XmlAttribute onTimeAttr = node.Attributes[TestRunConfigXml.TestRunPowerOnTimeAttributeName];
|
||||
DateTime powerOnDateTime = DateTime.Parse($"{onDateAttr.Value} {onTimeAttr.Value}");
|
||||
|
||||
DateTime dt = DateTime.Now;
|
||||
int duration = (int)dt.Subtract(powerOnDateTime).TotalSeconds;
|
||||
Dictionary<string, string> attributesDict = new Dictionary<string, string>();
|
||||
attributesDict[TestRunConfigXml.TestRunPowerOffDateAttributeName] = dt.ToString("MM/dd/yyyy");
|
||||
attributesDict[TestRunConfigXml.TestRunPowerOffTimeAttributeName] = dt.ToString("HH:mm:ss");
|
||||
attributesDict[TestRunConfigXml.TestRunPowerOnDurationAttributeName] = duration.ToString();
|
||||
|
||||
doc.ChangeNode(node, attributesDict);
|
||||
|
||||
doc.SaveToFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
130
Source/Program/Actions/UutPowerOnAction.cs
Normal file
130
Source/Program/Actions/UutPowerOnAction.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// 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 NLog;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Power on UUT
|
||||
/// </summary>
|
||||
internal class UutPowerOnAction : BasicAction
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private static NLog.ILogger _logger;
|
||||
|
||||
private static object _syncObj = new object();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public UutPowerOnAction()
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the action
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (!Program.Instance().IsUutPwrOn)
|
||||
{
|
||||
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
|
||||
|
||||
Program.Instance().TestStation.VerifyCableSelfTestHasRun();
|
||||
|
||||
if (Program.Instance().PowerModulesToBePowered.Count == 0)
|
||||
{
|
||||
ParseProgramSpecificConfig();
|
||||
}
|
||||
|
||||
Program.Instance().PowerSupplySharedData.ResetAll();
|
||||
|
||||
foreach (var item in ProgramLib.Program.Instance().PowerModulesToBePowered)
|
||||
Program.Instance().MalMeasurementLibManager.PowerSupplyMeasurementManager.OutputEnable(item);
|
||||
|
||||
RecordPowerOnTimeToFile();
|
||||
|
||||
// disable front panel
|
||||
//Program.Instance().MalMeasurementLibManager.PowerSupplyMeasurementManager.DisplayDisable("STE_POWER_SUPPLY_SYSTEM");
|
||||
|
||||
Program.Instance().EventManager[EventManager.Events.UUT_POWER_OFF].Reset();
|
||||
Program.Instance().EventManager[EventManager.Events.UUT_POWER_ON].Set();
|
||||
|
||||
Program.Instance().IsUutPwrOn = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("UUT power is already on.");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse ini file for modules to be powered on
|
||||
/// </summary>
|
||||
public void ParseProgramSpecificConfig()
|
||||
{
|
||||
try
|
||||
{
|
||||
List<string> keys = Program.Instance().ProgramSpecificConfig.ReadAllKeys(ProgramSpecificConfigIni.POWER_MODULES_TO_BE_POWERED.ToString());
|
||||
foreach (string key in keys)
|
||||
{
|
||||
string powerSupplyModule = Program.Instance().ProgramSpecificConfig.ReadValue(ProgramSpecificConfigIni.POWER_MODULES_TO_BE_POWERED.ToString(), key);
|
||||
|
||||
if (!Program.Instance().PowerModulesToBePowered.Contains(powerSupplyModule, StringComparer.OrdinalIgnoreCase))
|
||||
Program.Instance().PowerModulesToBePowered.Add(powerSupplyModule);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record power on time
|
||||
/// </summary>
|
||||
private void RecordPowerOnTimeToFile()
|
||||
{
|
||||
XmlDocumentWrapper doc = new XmlDocumentWrapper(Program.Instance().FileAndFolderManager.GetFile(FileAndFolderManager.Files.TEST_RUN_LOG));
|
||||
|
||||
Dictionary<string, string> attributesDict = new Dictionary<string, string>();
|
||||
attributesDict[TestRunConfigXml.TestRunPowerOnDateAttributeName] = DateTime.Now.ToString("MM/dd/yyyy");
|
||||
attributesDict[TestRunConfigXml.TestRunPowerOnTimeAttributeName] = DateTime.Now.ToString("HH:mm:ss");
|
||||
doc.AddNode(TestRunConfigXml.TestRunPowerPath, attributesDict, null, XmlDocumentWrapper.AddNodePosition.First);
|
||||
|
||||
doc.SaveToFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
93
Source/Program/Actions/UutTestPortConnectAction.cs
Normal file
93
Source/Program/Actions/UutTestPortConnectAction.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// 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 NLog;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Start TCP client and connect to the UUT
|
||||
/// </summary>
|
||||
internal class UutTestPortConnectAction : BasicAction
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private static NLog.ILogger _logger;
|
||||
private string _uutIpAddress = String.Empty;
|
||||
private int _uutTestPortTcp = -1;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public UutTestPortConnectAction()
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the action
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
|
||||
|
||||
if (Program.Instance().IsUutPwrOn)
|
||||
{
|
||||
if (Program.Instance().EthernetSocketManager.GetTcpClient(TcpClientNames.UUT_TEST_PORT) == null)
|
||||
{
|
||||
ParseProgramSpecificConfig();
|
||||
TcpClient tcpClient = new TcpClient(_uutIpAddress, _uutTestPortTcp);
|
||||
tcpClient.Initialize();
|
||||
tcpClient.Connect();
|
||||
Program.Instance().EthernetSocketManager.AddTcpClient(TcpClientNames.UUT_TEST_PORT, tcpClient);
|
||||
}
|
||||
else
|
||||
Program.Instance().EthernetSocketManager.GetTcpClient(TcpClientNames.UUT_TEST_PORT).Connect();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Cannot connect to UUT test port because UUT is not powered on.");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse ini file
|
||||
/// </summary>
|
||||
public void ParseProgramSpecificConfig()
|
||||
{
|
||||
try
|
||||
{
|
||||
_uutIpAddress = Program.Instance().ProgramSpecificConfig.ReadValue(ProgramSpecificConfigIni.UUT_INFO.ToString(), ProgramSpecificConfigIni.UUT_IP_ADDRESS.ToString());
|
||||
Int32.TryParse(Program.Instance().ProgramSpecificConfig.ReadValue(ProgramSpecificConfigIni.UUT_INFO.ToString(), ProgramSpecificConfigIni.UUT_TEST_PORT_TCP.ToString()), out _uutTestPortTcp);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
65
Source/Program/Actions/UutTestPortDisconnectAction.cs
Normal file
65
Source/Program/Actions/UutTestPortDisconnectAction.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// 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 NLog;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Disconnect TCP connection from UUT
|
||||
/// </summary>
|
||||
internal class UutTestPortDisconnectAction : BasicAction
|
||||
{
|
||||
#region PrivateClassMembers
|
||||
private static NLog.ILogger _logger;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public UutTestPortDisconnectAction()
|
||||
{
|
||||
_logger = LogManager.GetCurrentClassLogger();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the action
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() method...");
|
||||
|
||||
if (Program.Instance().IsUutPwrOn)
|
||||
{
|
||||
if (Program.Instance().EthernetSocketManager.GetTcpClient(TcpClientNames.UUT_TEST_PORT) != null)
|
||||
{
|
||||
Program.Instance().EthernetSocketManager.GetTcpClient(TcpClientNames.UUT_TEST_PORT).Disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user