Files
2025-10-24 15:18:11 -07:00

349 lines
9.8 KiB
C#

// Ignore Spelling: Geu Sdlc
using System;
using System.Threading;
using NLog;
using Raytheon.Common;
using Raytheon.GuidedElectronicsUnit;
namespace Raytheon.Instruments
{
public class CommDeviceGeuSdlc : ICommDevice, IDisposable
{
#region PrivateClassMembers
private GuidedElectronicsUnit.GuidedElectronicsUnit _guidanceElectronicsUnit;
private readonly bool _idQuery = false;
private readonly bool _reset = false;
private readonly SelfTestResult _selfTestResult;
private State _state;
private readonly string _instrumentDriverSetup;
private readonly int _pollingRate;
private static readonly object _syncObj = new object();
private readonly ILogger _logger;
private readonly IConfigurationManager _configurationManager;
private readonly IConfiguration _configuration;
#endregion
#region PrivatelassFunctions
/// <summary>
/// The Finalizer
/// </summary>
~CommDeviceGeuSdlc()
{
Dispose(false);
}
/// <summary>
/// Dispose of the resources contained by this object
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// close resources
try
{
if (_state == State.Ready)
{
_guidanceElectronicsUnit.Close();
_guidanceElectronicsUnit.Dispose();
_state = State.Uninitialized;
}
}
catch (Exception)
{
try
{
}
catch (Exception)
{
//Do not rethrow. Exception from error logger that has already been garbage collected
}
}
}
}
/// <summary>
/// Some HSS corrections
/// </summary>
/// <param name="data"></param>
/// <param name="numDWords"></param>
private static unsafe void PerformHssSwirl(ref byte[] data, uint numDWords)
{
fixed (byte* pBytePtr = &data[0])
{
for (int i = 0; i < numDWords; i++)
{
// swap the first word
ushort* pWord1 = (ushort*)pBytePtr + (i * 2);
*pWord1 = Util.Swap(*pWord1);
//swap the second word
ushort* pWord2 = (ushort*)pBytePtr + ((i * 2) + 1);
*pWord2 = Util.Swap(*pWord2);
// now swap the dword
uint* pDWord = (uint*)pBytePtr + i;
*pDWord = Util.SwapHighAndLowBytes(*pDWord);
}
}
}
#endregion
#region PublicClassFunctions
bool IInstrument.DisplayEnabled { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
bool IInstrument.FrontPanelEnabled { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
InstrumentMetadata IInstrument.Info => throw new NotImplementedException();
/// <summary>
/// CommDevice factory constructor
/// </summary>
/// <param name="deviceName"></param>
/// <param name="configurationManager"></param>
public CommDeviceGeuSdlc(string deviceName, IConfigurationManager configurationManager)
{
Name = deviceName;
_guidanceElectronicsUnit = null;
_selfTestResult = SelfTestResult.Unknown;
_state = State.Uninitialized;
_logger = LogManager.GetLogger($"{this.GetType().Name} - {deviceName}");
_configurationManager = configurationManager;
_configuration = _configurationManager.GetConfiguration(Name);
_idQuery = _configuration.GetConfigurationValue("CommDeviceGeuSdlc", "IdQuery", true);
_reset = _configuration.GetConfigurationValue("CommDeviceGeuSdlc", "Reset", true);
_instrumentDriverSetup = _configuration.GetConfigurationValue("CommDeviceGeuSdlc", "InstrumentDriverSetup", "");
_pollingRate = _configuration.GetConfigurationValue("CommDeviceGeuSdlc", "PollingRate", 10);
}
/// <summary>
/// The constructor. Does not initialize anything. Use Initialize() to create the handle to the hardware
/// </summary>
/// <param name="deviceName"></param>
/// <param name="idQuery"></param>
/// <param name="reset"></param>
public CommDeviceGeuSdlc(string deviceName, bool idQuery, bool reset, string instrumentDriverSetup = "", int pollingRate = 10)
{
Name = deviceName;
_idQuery = idQuery;
_reset = reset;
_guidanceElectronicsUnit = null;
_selfTestResult = SelfTestResult.Unknown;
_state = State.Uninitialized;
_instrumentDriverSetup = instrumentDriverSetup;
_pollingRate = pollingRate;
_logger = LogManager.GetLogger($"{this.GetType().Name} - {deviceName}");
}
/// <summary>
///
/// </summary>
/// <returns></returns>
bool IInstrument.ClearErrors()
{
throw new NotImplementedException();
}
/// <summary>
///
/// </summary>
public string DetailedStatus
{
get
{
return "This is a HSS GEU SDLC Device called " + Name;
}
}
/// <summary>
/// Dispose of the resources contained by this object
/// </summary>
public void Dispose()
{
try
{
Dispose(true);
GC.SuppressFinalize(this);
}
catch (Exception err)
{
_logger.Error(err.Message + "\r\n" + err.StackTrace);
}
}
/// <summary>
/// Create a handle to the hardware
/// </summary>
public void Initialize()
{
const uint AUTO_FWDING_ADDR = 0x00080100;
const uint WRITE_OFFSET = 0x00200000;
const uint ENABLE_AUTO_FWDING = 0b0000_0001;
const uint ENABLE_TLP_HDR = 0b0000_0010;
//const uint INSERT_MSG_CNT = 0b0000_0100;
_guidanceElectronicsUnit = new GuidedElectronicsUnit.GuidedElectronicsUnit(Name, _idQuery, _reset,
$"QueryInstrStatus=true, Simulate=false, DriverSetup= {_instrumentDriverSetup}, PollingInterval={_pollingRate}");
_guidanceElectronicsUnit.LowLevel.HSSub9100.EnableIO = ControlState.Enabled;
_guidanceElectronicsUnit.LowLevel.HSSub9100.WriteRegister(AUTO_FWDING_ADDR + WRITE_OFFSET, ENABLE_AUTO_FWDING | ENABLE_TLP_HDR);
_state = State.Ready;
}
/// <summary>
///
/// </summary>
public string Name { get; protected set; }
/// <summary>
///
/// </summary>
/// <returns></returns>
SelfTestResult IInstrument.PerformSelfTest()
{
throw new NotImplementedException();
}
/// <summary>
///
/// </summary>
/// <param name="dataRead"></param>
/// <returns></returns>
uint ICommDevice.Read(ref byte[] dataRead)
{
if (_guidanceElectronicsUnit == null)
{
return 0;
}
byte[] sdlcMsgs = new byte[0];
lock (_syncObj)
{
// read all of the data that is available
sdlcMsgs = _guidanceElectronicsUnit.GsKwSyncronousDataLinkControl.FetchMessageData();
}
if (sdlcMsgs.Length > dataRead.Length)
{
throw new Exception("The data buffer that the host provided is: " + dataRead.Length + " bytes, there are: " + sdlcMsgs.Length + " bytes of SDLC data. Need to increase the host buffer size");
}
Buffer.BlockCopy(sdlcMsgs, 0, dataRead, 0, sdlcMsgs.Length);
return (uint)sdlcMsgs.Length;
}
/// <summary>
///
/// </summary>
void IInstrument.Reset()
{
lock (_syncObj)
{
_guidanceElectronicsUnit.Close();
_state = State.Uninitialized;
Thread.Sleep(500);
Initialize();
}
}
/// <summary>
///
/// </summary>
public SelfTestResult SelfTestResult
{
get
{
return _selfTestResult;
}
}
/// <summary>
///
/// </summary>
/// <param name="timeoutMs"></param>
void ICommDevice.SetReadTimeout(uint timeoutMs)
{
throw new NotImplementedException();
}
/// <summary>
///
/// </summary>
void IInstrument.Shutdown()
{
lock (_syncObj)
{
if (_guidanceElectronicsUnit != null)
{
_guidanceElectronicsUnit.LowLevel.HSSub9100.EnableIO = ControlState.Disabled;
_guidanceElectronicsUnit.Close();
_guidanceElectronicsUnit.Dispose();
_state = State.Uninitialized;
}
}
}
/// <summary>
///
/// </summary>
public State Status
{
get
{
return _state;
}
}
/// <summary>
///
/// </summary>
/// <param name="data"></param>
/// <param name="numBytesToWrite"></param>
/// <returns></returns>
uint ICommDevice.Write(byte[] data, uint numBytesToWrite)
{
lock (_syncObj)
{
if (numBytesToWrite % 4 != 0)
{
throw new Exception("Data is not dword aligned");
}
// do all of the HSS Tx only byte order corrections
PerformHssSwirl(ref data, numBytesToWrite / 4);
var tempArr = new uint[data.Length / 4];
Buffer.BlockCopy(data, 0, tempArr, 0, (int)numBytesToWrite);
_guidanceElectronicsUnit.GsKwSyncronousDataLinkControl.SendMessage(tempArr);
}
return numBytesToWrite;
}
public void Close()
{
}
public void Open()
{
}
#endregion
}
}