// 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 /// /// The Finalizer /// ~CommDeviceGeuSdlc() { Dispose(false); } /// /// Dispose of the resources contained by this object /// /// 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 } } } } /// /// Some HSS corrections /// /// /// 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(); /// /// CommDevice factory constructor /// /// /// 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); } /// /// The constructor. Does not initialize anything. Use Initialize() to create the handle to the hardware /// /// /// /// 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}"); } /// /// /// /// bool IInstrument.ClearErrors() { throw new NotImplementedException(); } /// /// /// public string DetailedStatus { get { return "This is a HSS GEU SDLC Device called " + Name; } } /// /// Dispose of the resources contained by this object /// public void Dispose() { try { Dispose(true); GC.SuppressFinalize(this); } catch (Exception err) { _logger.Error(err.Message + "\r\n" + err.StackTrace); } } /// /// Create a handle to the hardware /// 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; } /// /// /// public string Name { get; protected set; } /// /// /// /// SelfTestResult IInstrument.PerformSelfTest() { throw new NotImplementedException(); } /// /// /// /// /// 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; } /// /// /// void IInstrument.Reset() { lock (_syncObj) { _guidanceElectronicsUnit.Close(); _state = State.Uninitialized; Thread.Sleep(500); Initialize(); } } /// /// /// public SelfTestResult SelfTestResult { get { return _selfTestResult; } } /// /// /// /// void ICommDevice.SetReadTimeout(uint timeoutMs) { throw new NotImplementedException(); } /// /// /// void IInstrument.Shutdown() { lock (_syncObj) { if (_guidanceElectronicsUnit != null) { _guidanceElectronicsUnit.LowLevel.HSSub9100.EnableIO = ControlState.Disabled; _guidanceElectronicsUnit.Close(); _guidanceElectronicsUnit.Dispose(); _state = State.Uninitialized; } } } /// /// /// public State Status { get { return _state; } } /// /// /// /// /// /// 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 } }