using System; using System.Threading; using DTS.Common.DASResource; using DTS.Common.ICommunication; using DTS.DASLib.Command.SLICE; using DTS.Common.Utilities.Logging; using DTS.Common.Interface.Connection; using DTS.Common.Classes.Connection; using DTS.Common.Interface.DASFactory; using DTS.Common.Enums.DASFactory; using static DTS.Common.Enums.DASFactory.DFConstantsAndEnums; using DTS.Common.Events; using DTS.Common.Enums; using System.Collections.Generic; using DTS.Common.Enums.Sensors; namespace DTS.DASLib.Service { public partial class Slice : Communication, IDASCommunication, IConfigurationActions, IDiagnosticsActions, ITriggerCheckActions, IRealTimeActions, IArmActions, IDownloadActions where T : IConnection, new() { /// /// returns the requested range for an analog channel, making adjustment for nonlinear if needed /// protected static double GetRequestedRange(AnalogInputDASChannel analog, double MvPerEU) { if (null != analog.LinearizationFormula && analog.LinearizationFormula.IsValid()) { switch (analog.LinearizationFormula.NonLinearStyle) { case NonLinearStyles.Polynomial: //polynomial can scale and should bypass this? break; default: if (MvPerEU.Equals(1)) { APILogger.DebugLog($"GetRequestRange HC={analog?.HardwareChannelName ?? "NULL"}, mVPerEu={MvPerEU} - {InputRangeMV}"); return InputRangeMV; } break; } } APILogger.DebugLog($"GetRequestRange HC={analog?.HardwareChannelName ?? "NULL"}, mVPerEu={MvPerEU} DesiredRange={analog.DesiredRangeWithHeadroomEU}"); return analog.DesiredRangeWithHeadroomEU * MvPerEU; } public virtual bool SupportsRemoveLeapSeconds { get => false; } protected void SetRemoveSeconds() { //http://manuscript.dts.local/f/cases/31747/Add-support-for-GPS-Time-leap-seconds if (IsCommandSupported(ProtocolLimitedCommands.RemoveLeapSeconds)) { try { var set = new SetSystemAttributeSLICE6AIR(this); set.SetValue(AttributeTypes.SystemAttributesSLICE6AIR.RemoveLeapSeconds, RunTestVariables.RemoveLeapSeconds ? (byte)1 : (byte)0, true); set.SyncExecute(); } catch (Exception ex) { APILogger.Log(ex); } } } protected virtual QATSExtendedFault[] GetExtendedFaultFlags() { var list = new List(); try { if (!IsCommandSupported(ProtocolLimitedCommands.ExtendedFaultIds)) { return list.ToArray(); } var qee = new QueryArmAttribute(this) { Key = AttributeTypes.ArmAndEventAttributes.ExtFaultFlags, DeviceID = 0 }; qee.SyncExecute(); if (qee.Value is uint[] uints) { var first = uints[0]; for (var i = 0; i < 32; i++) { if (0 != (first & (1 << i))) { list.Add((QATSExtendedFault)(1 << i)); } } } } catch (Exception ex) { APILogger.Log(ex); } return list.ToArray(); } public virtual bool SupportsADCSamplesPerPacket { get => false; } protected void SetADCSamplesPerPacket(int adcPerPacket) { //http://manuscript.dts.local/f/cases/31754/ if (IsCommandSupported(ProtocolLimitedCommands.ADCSamplesPerPacket)) { try { var get = new QuerySystemAttribute(this) { Key = AttributeTypes.SystemAttributes.S6A_IrigStreamBufferConfig }; get.SyncExecute(); var getParams = (ushort[])get.Value; getParams[1] = (ushort)adcPerPacket; var set = new SetSystemAttribute(this); set.SetValue(AttributeTypes.SystemAttributes.S6A_IrigStreamBufferConfig, getParams, true); set.SyncExecute(); } catch (Exception ex) { APILogger.Log(ex); } } else { APILogger.Log($"ADC samples per second not supported by firmware on {SerialNumber}"); } } protected virtual uint[] GetExtendedFaultFlags(int eventIndex) { try { var qee = new QueryEventAttribute(this) { Key = AttributeTypes.ArmAndEventAttributes.ExtFaultFlags, DeviceID = 0, EventNumber = Convert.ToUInt16(eventIndex) }; qee.SyncExecute(); return (uint[])qee.Value; } catch (Exception ex) { APILogger.Log(ex); } return new uint[] { 0, 0, 0, 0 }; } /// /// surfaces an error to the application, if applicable /// http://manuscript.dts.local/f/cases/28312/Surface-Read-does-not-match-write-to-user /// /// protected static void SurfaceApplicationError(string msg) { PageErrorEvent.SurfaceApplicationError(msg); } public ExcitationStatus ExcitationStatus { get; set; } = ExcitationStatus.Unknown; public virtual void SetIsStreamingSupported(bool supported = false) { IsStreamingSupported = false; } public virtual void ReadFirstUseDate() { IsFirstUseDateSupported = false; FirstUseDate = null; } /// /// indicates date of first use /// null indicates the hardware has not been used since calibration /// only valid when IsFirstUseDateSupported is true /// 15524 DAS "First Use Date" /// public DateTime? FirstUseDate { get; set; } = null; /// /// returns whether the hardware supports first use or not /// for hardware to support first use the hardware must support /// storage for user attributes in firmware and also have been /// calibrated by software support hardware first use /// 15524 DAS "First Use Date" /// public bool IsFirstUseDateSupported { get; set; } = false; /// /// indicates whether or not streaming is supported /// 30429 TSR AIRs can enable/disable streaming via the DISABLE_STREAMING_FEATURE system attribute /// public bool IsStreamingSupported { get; set; } = false; public int RecordId { get; set; } = Common.Enums.Hardware.HardwareConstants.INVALID_IDASCOMMUNICATION_RECORD_ID; /// /// returns the total number of channels in the event /// /// /// protected virtual uint GetEventTotalChannels(int eventNum) { var eventTC = new QueryEventAttribute(this); eventTC.EventNumber = (ushort)eventNum; eventTC.Key = AttributeTypes.ArmAndEventAttributes.TotalChannels; eventTC.SyncExecute(); return (byte)eventTC.Value; } public string MACAddress { get; set; } public string[] DownstreamMACAddresses { get; set; } public virtual bool IsEthernetDistributor() { return false; } public virtual bool IsSlice6Distributor() { return false; } public virtual bool IsBattery() { return false; } public virtual bool IsTSRAIR() { return false; } public virtual bool IsSlice6Air() { return false; } public virtual bool IsSlice6AirTc() { return false; } public virtual bool IsScheduleEventCountSupported() { return false; } public class SliceServiceQueryConfigAsyncInfo : SliceServiceAsyncInfo { public uint CRC { get; set; } = 0; public string ConfigString { get; set; } = string.Empty; public bool ReadIds { get; set; } = true; public bool DeviceScaleFactors { get; set; } = true; public SliceServiceQueryConfigAsyncInfo(ServiceCallback _callback, object _userData, uint crc, string strConfig, bool bReadIds, bool bDeviceScaleFactors, bool differentModuleCountsAreOK) : base(_callback, _userData) { CRC = crc; ConfigString = strConfig; ReadIds = bReadIds; DeviceScaleFactors = bDeviceScaleFactors; DifferentModuleCountsAreOK = differentModuleCountsAreOK; } public bool DifferentModuleCountsAreOK { get; set; } = false; } public class SliceServiceQueryTestSetupAsyncInfo : SliceServiceAsyncInfo { public string TestSetupGuid { get; set; } public SliceServiceQueryTestSetupAsyncInfo(ServiceCallback _callback, object _userData, string testSetupGuid) : base(_callback, _userData) { TestSetupGuid = testSetupGuid; } } public class SliceServiceSetTestSetupAsyncInfo : SliceServiceAsyncInfo { public string TestSetupXML { get; set; } public SliceServiceSetTestSetupAsyncInfo(ServiceCallback _callback, object _userData, string testSetupXML) : base(_callback, _userData) { TestSetupXML = testSetupXML; } } public class AutoDetectServiceAsyncInfo : SliceServiceAsyncInfo { public bool QueryConfiguration { get; set; } = true; public AutoDetectServiceAsyncInfo(bool queryConfiguration, ServiceCallback callback, object userData) : base(callback, userData) { QueryConfiguration = queryConfiguration; } } public class SliceServiceAsyncInfo { public ServiceCallback callback { get; set; } public object userData { get; set; } public object functionData { get; set; } public PrePostResults PreOrPost { get; set; } public int? MaxTimeout { get; set; } public SliceServiceAsyncInfo(ServiceCallback _callback, object _userData) { callback = _callback; userData = _userData; } public void Error(string msg, Exception ex) { try { var cbData = new ServiceCallbackData(); cbData.Status = ServiceCallbackData.CallbackStatus.Failure; cbData.ErrorMessage = msg; cbData.ErrorException = ex; cbData.UserData = userData; callback(cbData); } catch (Exception eex) { APILogger.Log("MessageBox", Strings.SLICEAsyncInfoError, eex); } } public void Error(string msg) { Error(msg, null); } public void Progress(int value) { try { var progressData = new ServiceCallbackData(); progressData.Status = ServiceCallbackData.CallbackStatus.ProgressReport; progressData.ProgressValue = value; progressData.UserData = userData; callback(progressData); } catch (Exception ex) { APILogger.Log("MessageBox", Strings.SLICEAsyncInfoProgressError, ex); } } //public void NewData(IList datas, IList SampleNumbers) public void NewData(object obj) { if (obj is ServiceCallbackData.DiagnosticNewData) { var progressData = new ServiceCallbackData(); progressData.Status = ServiceCallbackData.CallbackStatus.NewData; progressData.ProgressValue = 0; progressData.UserData = userData; progressData.SetNewDiagnosticData((obj as ServiceCallbackData.DiagnosticNewData)); callback(progressData); } else if (obj is ServiceCallbackData.TiltNewData) { var progressData = new ServiceCallbackData(); progressData.Status = ServiceCallbackData.CallbackStatus.NewData; progressData.ProgressValue = 0; progressData.UserData = userData; progressData.SetNewTiltData((obj as ServiceCallbackData.TiltNewData)); callback(progressData); } else if (obj is ServiceCallbackData.UARTNewData) { var progressData = new ServiceCallbackData(); progressData.Status = ServiceCallbackData.CallbackStatus.NewData; progressData.ProgressValue = 0; progressData.UserData = userData; progressData.SetNewUARTData(obj as ServiceCallbackData.UARTNewData); callback(progressData); } else if (obj is byte[]) { var progressData = new ServiceCallbackData(); progressData.Status = ServiceCallbackData.CallbackStatus.NewData; progressData.ProgressValue = 0; progressData.SetNewByteData((byte[])obj); progressData.UserData = userData; callback(progressData); } else if (obj is DFConstantsAndEnums.T0CorrectionStatus status) { var progressData = new ServiceCallbackData(); progressData.Status = ServiceCallbackData.CallbackStatus.NewData; progressData.ProgressValue = 0; var i = (int)status; progressData.SetNewByteData(BitConverter.GetBytes(i)); progressData.UserData = userData; callback(progressData); } else { var newdatadata = obj as NewDataData; var datas = newdatadata.datas; var samplenumbers = newdatadata.SampleNumbers; var timeStamps = newdatadata.TimeStamps; var sequenceNumbers = newdatadata.SequenceNumbers; try { var progressData = new ServiceCallbackData(); progressData.Status = ServiceCallbackData.CallbackStatus.NewData; progressData.ProgressValue = 0; progressData.UserData = userData; var sequenceNumber = 0UL; for (int i = 0; i < datas.Length && i < samplenumbers.Length; i++) { //polling apparently doesn't always populate sequence number //to prevent an indexing error just use the last one //18009 DataPRO becomes unusable when trying to put realtime in meter mode if (i < sequenceNumbers.Length) { sequenceNumber = sequenceNumbers[i]; } progressData.AddSampleData(datas[i], samplenumbers[i], timeStamps[i], sequenceNumber); } callback(progressData); } catch (Exception ex) { APILogger.Log("MessageBox", Strings.SLICEAsyncInfoNewDataError, ex); } } } public void NewData(short[][] data, UInt64 samplenumber, ulong timeStamp, ulong sequenceNumber) { try { var progressData = new ServiceCallbackData(); progressData.Status = ServiceCallbackData.CallbackStatus.NewData; progressData.ProgressValue = 0; progressData.UserData = userData; progressData.AddSampleData(data, samplenumber, timeStamp, sequenceNumber); callback(progressData); } catch (Exception ex) { APILogger.Log("MessageBox", Strings.SLICEAsyncInfoNewDataError, ex); } } public void Success() { try { var success = new ServiceCallbackData(); success.Status = ServiceCallbackData.CallbackStatus.Success; success.UserData = userData; callback(success); } catch (Exception ex) { APILogger.Log("MessageBox", Strings.SLICEAsyncInfoSuccessError, ex); } } public void Cancel() { try { var cancelReport = new ServiceCallbackData(); cancelReport.Status = ServiceCallbackData.CallbackStatus.Canceled; cancelReport.ProgressValue = 0; cancelReport.UserData = userData; callback(cancelReport); } catch (Exception ex) { APILogger.Log("MessageBox", Strings.SLICEAsyncInfoCancelError, ex); } } } public void LaunchAsyncWorker(string Invoker, WaitCallback cb, object asyncInfo) { if (!Connected) { // "{0}: Not currently connected" throw new NotConnectedException(string.Format(Strings.Slice_LaunchAsyncWorker_Err1, Invoker)); } if (!ThreadPool.QueueUserWorkItem(cb, asyncInfo)) { // "{0}: Unable to enqueue function" throw new Exception(string.Format(Strings.Slice_LaunchAsyncWorker_Err2, Invoker)); } } /// /// compare to an object to determine equality /// /// /// public override bool Equals(object right) { if (right == null) return false; if (ReferenceEquals(this, right)) return true; var rightSlice = right as Slice; if (rightSlice == null) return false; if (string.IsNullOrEmpty(SerialNumber)) { return string.IsNullOrEmpty(rightSlice.SerialNumber); } if (string.IsNullOrEmpty(rightSlice.SerialNumber)) return false; return SerialNumber == rightSlice.SerialNumber; } /// /// returns identical index for any two 'equal' slice /// /// public override int GetHashCode() { if (string.IsNullOrEmpty(SerialNumber)) return 0; return SerialNumber.GetHashCode(); } } }