using System; using System.Collections.Generic; using System.Text; using DTS.DASLib.Command.SLICE; using DTS.Common.DAS.Concepts; using System.IO.Compression; using System.IO; using System.Xml; using DTS.Common.Constant; using DTS.Common.DASResource; using DTS.Common.Interface.DASFactory; using DTS.Common.Utilities.Logging; using DTS.Common.Interface.Connection; using DTS.Common.Enums.DASFactory; using DTS.Common.ICommunication; using DTS.Common; namespace DTS.DASLib.Service { public partial class Slice : Communication, IDASCommunication, IConfigurationActions, IDiagnosticsActions, ITriggerCheckActions, IRealTimeActions, IArmActions, IDownloadActions where T : IConnection, new() { protected virtual ConfigAttributes GetConfigAttributes(DTS.Common.Interface.DASFactory.ICommunication com) { return new ConfigAttributes(com); } protected class ConfigAttributes { protected ICommunication com { get; set; } public ConfigAttributes(DTS.Common.Interface.DASFactory.ICommunication _com) { com = _com; } public virtual void PurgeStaleData(IDASCommunication das) { var cmd = new SetArmAttributesToDefaults(com); cmd.SyncExecute(); // get bridge stuff var dacValues = new ushort[das.ConfigData.NumberOfChannels()]; foreach (var module in das.DASInfo.Modules) { if (module.TypeOfModule == DFConstantsAndEnums.ModuleType.SLICEIEPE) { //call something else //var odQuery = new QuerySystemAttribute_Bridge(com); var odQuery = new QuerySystemAttribute_IEPE(com); odQuery.DeviceID = (byte)(module.ModuleArrayIndex + 1); odQuery.Key = AttributeTypes.SystemAttributes_IEPE.IA_OffsetDACA_Midscale;// OffsetDACA_Midscale; odQuery.SyncExecute(); dacValues[module.ModuleArrayIndex * 3 + 0] = (ushort)odQuery.Value; odQuery.Key = AttributeTypes.SystemAttributes_IEPE.IA_OffsetDACB_Midscale; odQuery.SyncExecute(); dacValues[module.ModuleArrayIndex * 3 + 1] = (ushort)odQuery.Value; odQuery.Key = AttributeTypes.SystemAttributes_IEPE.IA_OffsetDACC_Midscale; odQuery.SyncExecute(); dacValues[module.ModuleArrayIndex * 3 + 2] = (ushort)odQuery.Value; } else { var odQuery = new QuerySystemAttribute_Bridge(com); odQuery.DeviceID = (byte)(module.ModuleArrayIndex + 1); odQuery.Key = AttributeTypes.SystemAttributes_Bridge.OffsetDACA_Midscale; odQuery.SyncExecute(); dacValues[module.ModuleArrayIndex * 3 + 0] = (ushort)odQuery.Value; odQuery.Key = AttributeTypes.SystemAttributes_Bridge.OffsetDACB_Midscale; odQuery.SyncExecute(); dacValues[module.ModuleArrayIndex * 3 + 1] = (ushort)odQuery.Value; odQuery.Key = AttributeTypes.SystemAttributes_Bridge.OffsetDACC_Midscale; odQuery.SyncExecute(); dacValues[module.ModuleArrayIndex * 3 + 2] = (ushort)odQuery.Value; } } // set base stuff var odSet = new SetArmAttribute(com); odSet.SetValue(AttributeTypes.ArmAndEventAttributes.StackChannelOffsetDACSettings, dacValues, true); odSet.SyncExecute(); } #region Arm attribute helpers private void SetArmAttribute(AttributeTypes.ArmAndEventAttributes key, object value, bool ShouldOverwrite) { var set = new SetArmAttribute(com); set.SetValue(key, value, ShouldOverwrite); set.SyncExecute(); } public void SetArmAttribute(AttributeTypes.ArmAndEventAttributes key, DFConstantsAndEnums.RecordingMode value) { if (com is EthernetSlice6Air s6A) { s6A.SetArmAttribute(key, value); } else { SetArmAttribute(key, (byte)value, true); } } public void SetArmAttribute(AttributeTypes.ArmAndEventAttributes key, UInt32 value) { SetArmAttribute(key, value, true); } public void SetArmAttribute(AttributeTypes.ArmAndEventAttributes key, float value) { SetArmAttribute(key, value, true); } public void SetArmAttribute(AttributeTypes.ArmAndEventAttributes key, string value) { var set = new SetArmAttribute(com); var ByteArrayData = Encoding.UTF8.GetBytes(value); set.SetValue(key, ByteArrayData, true); set.SyncExecute(); } public void SetArmAttribute(AttributeTypes.ArmAndEventAttributes key, ulong value) { SetArmAttribute(key, value, true); } public void GetArmAttribute(AttributeTypes.ArmAndEventAttributes key, out DFConstantsAndEnums.RecordingMode value) { var query = new QueryArmAttribute(com); query.Key = key; query.SyncExecute(); if (query.DataType != AttributeTypes.AttributeDataTypes.UInt8) throw new Exception("ConfigurationService.GetArmAttribute.RecordingMode: Found type " + query.DataType); value = (DFConstantsAndEnums.RecordingMode)query.Value; } public void GetArmAttribute(AttributeTypes.ArmAndEventAttributes key, out uint value) { var query = new QueryArmAttribute(com); query.Key = key; query.SyncExecute(); if (query.DataType != AttributeTypes.AttributeDataTypes.UInt32) throw new Exception("ConfigurationService.GetArmAttribute.UInt32: Found type " + query.DataType); value = (uint)query.Value; } public void GetArmAttribute(AttributeTypes.ArmAndEventAttributes key, out uint[] value) { var query = new QueryArmAttribute(com); query.Key = key; query.SyncExecute(); if (query.DataType != AttributeTypes.AttributeDataTypes.UInt32Star) throw new Exception("ConfigurationService.GetArmAttribute.UInt32Star: Found type " + query.DataType); value = (uint[])query.Value; } public void GetArmAttribute(AttributeTypes.ArmAndEventAttributes key, out float value) { var query = new QueryArmAttribute(com); query.Key = key; query.SyncExecute(); if (query.DataType != AttributeTypes.AttributeDataTypes.Float32) throw new Exception("ConfigurationService.GetArmAttribute.float: Found type " + query.DataType); value = (float)query.Value; } public void GetArmAttribute(AttributeTypes.ArmAndEventAttributes key, out string value) { var query = new QueryArmAttribute(com); query.Key = key; query.SyncExecute(); if (query.DataType != AttributeTypes.AttributeDataTypes.Unicode) { throw new Exception("ConfigurationService.GetArmAttribute.string: Found type " + query.DataType); } var values = query.Value as byte[]; value = Encoding.UTF8.GetString(values); } public void GetArmAttribute(AttributeTypes.ArmAndEventAttributes key, out ulong value) { var query = new QueryArmAttribute(com); query.Key = key; query.SyncExecute(); if (query.DataType != AttributeTypes.AttributeDataTypes.UInt64) throw new Exception("ConfigurationService.GetArmAttribute.UInt64: Found type " + query.DataType); value = (ulong)query.Value; } #endregion #region XML attributes protected byte[] GetBytes(FileStore fileStore, string data) { var d = fileStore == FileStore.TestSetup ? Encoding.Unicode.GetBytes(data) : Encoding.UTF8.GetBytes(data); return d; } private string GetString(FileStore fileStore, byte[] data) { var WholeStr = fileStore == FileStore.TestSetup ? Encoding.Unicode.GetString(data) : Encoding.UTF8.GetString(data); return WholeStr; } protected byte[] GetCompressedBytes(byte[] data) { byte[] ByteArrayData = null; using (var s = new MemoryStream()) { using (var gs = new GZipStream(s, CompressionMode.Compress, false)) { gs.Write(data, 0, data.Length); gs.Flush(); gs.Close(); ByteArrayData = s.GetBuffer(); } } return ByteArrayData; } public virtual void StoreXMLConfig(string data, FileStore fileStore) { if (string.IsNullOrEmpty(data)) { return; } // since this might contain multi byte characters, we need to convert it to a byte array first byte[] ByteArrayData = GetCompressedBytes(GetBytes(fileStore, data)); // calc how many we need var NumBlocks = ByteArrayData.Length / Slice.Service.Attribute.MaxSingleAttributeSize; if ((ByteArrayData.Length % Slice.Service.Attribute.MaxSingleAttributeSize) != 0) { NumBlocks++; } // write the blocks // for progress, assume that we'll have about 40 blocks to write var blockWeight = 40.0 / NumBlocks; for (int BlockIdx = 0; BlockIdx < NumBlocks; BlockIdx++) { // contruct the current block int blockLength = ByteArrayData.Length - (BlockIdx * Slice.Service.Attribute.MaxSingleAttributeSize); if (blockLength > Slice.Service.Attribute.MaxSingleAttributeSize) { blockLength = Slice.Service.Attribute.MaxSingleAttributeSize; } var block = new byte[blockLength]; Array.Copy(ByteArrayData, BlockIdx * Slice.Service.Attribute.MaxSingleAttributeSize, block, 0, blockLength); // write it to firmware var AttrSet = new SetArmAttribute(com); var attrNum = (AttributeTypes.ArmAndEventAttributes)(Slice.Service.Attribute.BulkAttributeStartNumber + BlockIdx); AttrSet.SetValue(attrNum, block, AttributeTypes.AttributeDataTypes.Unicode, true); AttrSet.SyncExecute(); } // write our speacial header attribute var InvariantCulture = new System.Globalization.CultureInfo(""); var BlockList = new StringBuilder(Slice.Service.Attribute.BulkAttributeStartNumber.ToString(InvariantCulture), Slice.Service.Attribute.MaxSingleAttributeSize); for (var BlockIdx = 1; BlockIdx < NumBlocks; BlockIdx++) { BlockList.Append("," + (Slice.Service.Attribute.BulkAttributeStartNumber + BlockIdx).ToString(InvariantCulture)); } var HeaderAttrSet = new SetArmAttribute(com); // this attribute only contains digits and commas so it's OK to keep it as Ascii HeaderAttrSet.SetValue(AttributeTypes.ArmAndEventAttributes.StoredConfigIndex, BlockList.ToString(), AttributeTypes.AttributeDataTypes.Ascii, true); HeaderAttrSet.SyncExecute(); if ((FileStore.Diagnostic == fileStore) || (FileStore.Event == fileStore)) { StoreXmlConfigPC(data, "DASConfigs", com.SerialNumber); } } public void StoreXmlConfigPC(string data, string folder, string fn) { try { var folderName = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), folder); var fileName = Path.Combine(folderName, fn); if (!fileName.ToLower().EndsWith(".xml")) { fileName = $"{fileName}.xml"; } if (folder.Equals(Constants.DAS_CONFIGS)) { if (File.Exists(fileName)) { File.Delete(fileName); } using (var file = File.CreateText(fileName)) { file.Write(data); APILogger.Log($"DASConfig file written: {fileName}"); } } else if (folder.Equals(Constants.DAS_TEST_SETUPS)) { //If it already exists, don't delete and then re-write, just use it. if (!File.Exists(fileName)) { if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } using (var file = File.CreateText(fileName)) { file.Write(data); } } } } catch (Exception ex) { APILogger.Log(ex); APILogger.RaiseError(DTS.Common.Strings.Strings.FailedToWritePcConfigFile); } } public enum FileStore { Diagnostic = 0x00, Event = 0x01, TestSetup = 0x02, SpeedTest = 0x03, UserAttributes = 0x04 } public virtual string RetrieveXMLConfig(FileStore filestore, IDASCommunication das) { var WholeStr = string.Empty; try { // first get our special header attribute var AttrGet = new QueryArmAttribute(com); AttrGet.Key = AttributeTypes.ArmAndEventAttributes.StoredConfigIndex; AttrGet.SyncExecute(); // this attribute only contains digits and commas so it's OK to keep it as Ascii (see above) var BlockListStr = AttrGet.Value as string; // still there? if (string.IsNullOrEmpty(BlockListStr)) { // "Slice.RetrieveAttributes: Header attribute as string is empty" throw new Exception(Strings.Slice_RetrieveAttributes_Err2); } var InvariantCulture = new System.Globalization.CultureInfo(""); var BlockListStrArr = BlockListStr.Split(','); var BlockList = new List(); foreach (string NumStr in BlockListStrArr) { if (!ushort.TryParse(NumStr, System.Globalization.NumberStyles.Integer, InvariantCulture, out ushort Number)) { // "Slice.RetrieveAttributes: Header attribute is invalid" throw new System.Exception(Strings.Slice_RetrieveAttributes_Err3); } BlockList.Add(Number); } var allBytes = new List(131072); foreach (var AttrNumber in BlockList) { AttrGet.LogCommands = false; AttrGet.Key = (AttributeTypes.ArmAndEventAttributes)AttrNumber; AttrGet.SyncExecute(); // old version stored the data as Ascii if (AttrGet.DataType == AttributeTypes.AttributeDataTypes.Ascii) { allBytes.AddRange(Encoding.UTF8.GetBytes((AttrGet.Value as string))); } // new version uses Unicode (basically byte[]) else if (AttrGet.DataType == AttributeTypes.AttributeDataTypes.Unicode) { var values = AttrGet.Value as byte[]; allBytes.AddRange(values); } else { // this is really bad! throw new Exception(string.Format("RetrieveXMLConfig: Unknown datatype {0}", AttrGet.DataType.ToString())); } } if (allBytes.Count < 1) { // "Slice.RetrieveAttributes: Attributes are empty" throw new Exception(Strings.Slice_RetrieveAttributes_Err4); } return GetDecompressedString(allBytes.ToArray(), filestore); } catch (Exception ex) { APILogger.Log($"Failed to retrieve xml config - {filestore} on {com.SerialNumber}. Error: {ex}"); if (FileStore.Event == filestore) { //event file store FIRST falls back to diagnostics //which will fall back onto pc if it fails WholeStr = RetrieveXMLConfig(FileStore.Diagnostic, das); } else if (FileStore.Diagnostic == filestore) { //diagnostics falls back to pc WholeStr = RetrieveXmlConfigPC(); } } try { APILogger.ConfLog(com.SerialNumber, "XML Config\n", Common.Utils.Utils.PrettyPrint(WholeStr)); } catch (Exception) { } return WholeStr; } protected string RetrieveXmlConfigPC() { try { var fileName = Path.Combine(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), Constants.DAS_CONFIGS), string.Format("{0}.xml", com.SerialNumber)); if (File.Exists(fileName)) { return File.ReadAllText(fileName); } } catch (Exception ex) { APILogger.Log(ex); } return ""; } /// /// /// /// /// /// protected string GetDecompressedString(byte[] allBytes, FileStore fileStore) { var WholeStr = string.Empty; var gData = new byte[8192]; var crc = new Utilities.Crc32(); var crcBefore = crc.Get(allBytes); APILogger.Log($"RetrieveXmlConfig {com.SerialNumber} crc compressed: {crcBefore} filestore: {fileStore}"); using (var sr = new MemoryStream(allBytes)) { using (var gs = new GZipStream(sr, CompressionMode.Decompress, false)) { using (var ms = new MemoryStream(WholeStr.Length * 10)) { try { var count = gs.Read(gData, 0, gData.Length); while (count > 0) { ms.Write(gData, 0, count); ms.Flush(); count = gs.Read(gData, 0, gData.Length); } gs.Close(); var allBytesAfter = ms.ToArray(); var crcAfter = crc.Get(allBytesAfter); APILogger.Log($"RetrieveXmlConfig {com.SerialNumber} crc uncompressed: {crcAfter} crc compressed: {crcBefore} filestore: {fileStore}"); WholeStr = GetString(fileStore, allBytesAfter); } catch (InvalidDataException ex) { //well perhaps it's not zipped up then! WholeStr = GetString(fileStore, ms.ToArray()); APILogger.Log($"RetreiveXmlConfig {com.SerialNumber} Filestore {fileStore} InvalidDataException {com.SerialNumber} ", ex, WholeStr); APILogger.ConfigReadErrorLogWriter($"{DateTime.Now:yyyy - MM - dd HH: mm:ss.fff} {com.SerialNumber} Filestore {fileStore} crc compressed: {crcBefore} exception: {ex.Message}\n"); throw new Exception("Invalid data", ex); } } } } return WholeStr; } // Attractively format the XML with consistant indentation. /// /// Retrieve the XML string that was split and stored in the Arm attributes /// /// The event number to get it from /// /// The combined XML string public virtual string RetrieveEventXMLConfig(int eventNum, QueryDownloadProgress progress, IDASCommunication das) { // first get our special header attribute var AttrGet = new QueryEventAttribute(com); AttrGet.EventNumber = (ushort)eventNum; AttrGet.Key = AttributeTypes.ArmAndEventAttributes.StoredConfigIndex; AttrGet.SyncExecute(); if (null != progress) { progress.Step(); } var BlockListStr = AttrGet.Value as string; // still there? if (string.IsNullOrEmpty(BlockListStr)) { // "Slice.RetrieveEventAttributes: Header attribute is empty" throw new Exception(Strings.Slice_RetrieveEventAttributes_Err1); } var InvariantCulture = new System.Globalization.CultureInfo(""); var BlockListStrArr = BlockListStr.Split(','); var BlockList = new List(); foreach (var NumStr in BlockListStrArr) { if (!ushort.TryParse(NumStr, System.Globalization.NumberStyles.Integer, InvariantCulture, out ushort Number)) { // "Slice.RetrieveEventAttributes: Header attribute is invalid" throw new System.Exception(Strings.Slice_RetrieveEventAttributes_Err2); } BlockList.Add(Number); } var AllStrings = new StringBuilder(BlockList.Count * Slice.Service.Attribute.MaxSingleAttributeSize); var AllBytes = new List(BlockList.Count * Slice.Service.Attribute.MaxSingleAttributeSize * 2); foreach (var AttrNumber in BlockList) { AttrGet.Key = (AttributeTypes.ArmAndEventAttributes)AttrNumber; AttrGet.LogCommands = false; AttrGet.SyncExecute(); if (null != progress) { progress.Step(); } // old version stored the data as Ascii if (AttrGet.DataType == AttributeTypes.AttributeDataTypes.Ascii) { AllBytes.AddRange(Encoding.UTF8.GetBytes((AttrGet.Value as string))); } // new version uses Unicode (basically byte[]) else if (AttrGet.DataType == AttributeTypes.AttributeDataTypes.Unicode) { var values = AttrGet.Value as byte[]; AllBytes.AddRange(values); } else { // this is really bad! throw new Exception(string.Format("RetrieveXMLConfig: Unknown datatype {0}", AttrGet.DataType.ToString())); } } if (AllBytes.Count < 1) { // "Slice.RetrieveAttributes: Attributes are empty" throw new Exception(Strings.Slice_RetrieveAttributes_Err4); } var WholeStr = GetDecompressedString(AllBytes.ToArray(), FileStore.Event); try { APILogger.ConfLog(com.SerialNumber, "XML Config\n", DTS.Common.Utils.Utils.PrettyPrint(WholeStr)); } catch (Exception) { } return WholeStr; } #endregion public void ConfigureRange(float[] ranges) { // this function shall just set the range attribute for channel var set = new SetArmAttribute(com); set.SetValue(AttributeTypes.ArmAndEventAttributes.StackChannelRangesMillivolts, ranges, true); set.SyncExecute(); } public virtual void ConfigureCoupling(bool[] IsACCoupledArray) { var set = new SetArmAttribute(com, QueryArmAttribute.Default_IO_Timeout); set.SetValue(AttributeTypes.ArmAndEventAttributes.StackChannelACCouplerEnable, IsACCoupledArray, true); set.SyncExecute(); } public virtual void ConfigureBridge(byte[] bridgeModeArray) { var set = new SetArmAttribute(com); set.SetValue(AttributeTypes.ArmAndEventAttributes.StackChannelBridgeCompletionEnable, bridgeModeArray, true); set.SyncExecute(); } public virtual void ConfigureBridgeResistance(ushort[] BridgeResistanceArray) { // this function shall just set the bridge resistance for the channels var set = new SetArmAttribute(com); set.SetValue(AttributeTypes.ArmAndEventAttributes.StackChannelBridgeResistanceOhms, BridgeResistanceArray, true); set.SyncExecute(); } public float[] GetScaleFactors() { // this function shall just get the scale factors for all channels var query = new QueryArmAttribute(com); query.Key = AttributeTypes.ArmAndEventAttributes.StackChannelScaleFactorsMillivoltsPerADC; query.SyncExecute(); return query.Value as float[]; } public float[] GetRanges() { //FB 25526 this function shall just get the stackc hannel ranges for all channels in milli volts var query = new QueryArmAttribute(com); query.Key = AttributeTypes.ArmAndEventAttributes.StackChannelRangesMillivolts; query.SyncExecute(); return query.Value as float[]; } public float[] GetMeasuredOffset() { //FB 25526 this function shall just get the stack channel measured offset for all channels in milli volts var query = new QueryArmAttribute(com); query.Key = AttributeTypes.ArmAndEventAttributes.StackChannelMeasuredOffsetMV; query.SyncExecute(); return query.Value as float[]; } public uint[] GetStackActualSampleRate() { // this function shall just get the scale factors for all channels var query = new QueryArmAttribute(com); query.Key = AttributeTypes.ArmAndEventAttributes.StackActualSampleRateHz; query.SyncExecute(); return query.Value as uint[]; } #region Attributes public uint SampleRate { get { GetArmAttribute(AttributeTypes.ArmAndEventAttributes.SampleRate, out uint Value); return Value; } set => SetArmAttribute(AttributeTypes.ArmAndEventAttributes.SampleRate, value); } public float ActualSampleRate { get { if (((IDASCommunication)com).GetIsStreaming()) { //15949 S6A when streaming does a whole bunch of unnecessary queries //avoid getting this attribute if streaming, it will fail //also avoid returning a 0 for div0 safety reasons? return 10000; } if (com.IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryActualSampleRateImmediate)) { try { GetArmAttribute(AttributeTypes.ArmAndEventAttributes.ActualSampleRateHz, out float Value); return Value; } catch (Exception ex) { APILogger.Log("Failed to get ActualSampleRateHz, ", ex); } } return Convert.ToSingle(SampleRate); } } /// /// Retrieve currently running sample rates for devices with more than one on-board IC (read: TSR-AIR) /// /// /// Collection of current sample rates /// public float[] StackActualSampleRate { get { if (((IDASCommunication)com).GetIsStreaming()) { //Adapted from 15949 for TSR-AIR: Unit is streaming and won't respond to the query, so return maxed out var len = ((IDASCommunication)com).ConfigData.Modules.Length; var rates = new float[len]; for (var i = 0; i < len; i++) { switch (((IDASCommunication)com).ConfigData.Modules[i].ModuleType()) { case DFConstantsAndEnums.ModuleType.EmbeddedLinearAccelHighG: rates[i] = (float)EmbeddedSensors.EmbeddedHighGLinearAccelerometerSampleRateMaximum; break; case DFConstantsAndEnums.ModuleType.EmbeddedLinearAccelLowG: rates[i] = (float)EmbeddedSensors.EmbeddedLowGLinearAccelerometerSampleRateMaximum; break; case DFConstantsAndEnums.ModuleType.EmbeddedAngularAccel: rates[i] = (float)EmbeddedSensors.EmbeddedAngularAccelerometerSampleRateMaximum; break; case DFConstantsAndEnums.ModuleType.EmbeddedAngularRate: rates[i] = (float)EmbeddedSensors.EmbeddedAngularAccelerometerAndRateSensorSampleRateMaximum; break; case DFConstantsAndEnums.ModuleType.EmbeddedAtmospheric: rates[i] = (float)EmbeddedSensors.EmbeddedAtmosphericSensorSampleRateMaximum; break; case DFConstantsAndEnums.ModuleType.EmbeddedClockSecondsAndMarker: case DFConstantsAndEnums.ModuleType.EmbeddedClockNanosAndPad: rates[i] = 0; //it's the encoded timestamp. no sample rate break; default: rates[i] = 10000; //probably shouldn't get here, but default to super-sample rate break; } } return rates; } if (com.IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryStackActualSampleRateImmediate)) { try { var query = new QueryArmAttribute(com); query.Key = AttributeTypes.ArmAndEventAttributes.StackActualSampleRateHz; query.SyncExecute(); return query.Value as float[]; } catch (Exception ex) { APILogger.Log("Failed to get StackActualSampleRateHz, ", ex); } } return null; } } public float AAFilter { get { GetArmAttribute(AttributeTypes.ArmAndEventAttributes.AAFilterFrequency, out float Value); return Value; } set => SetArmAttribute(AttributeTypes.ArmAndEventAttributes.AAFilterFrequency, value); } public string TestID { get { GetArmAttribute(AttributeTypes.ArmAndEventAttributes.Name, out string Value); try { Value = (com as IDASCommunication).ConfigData.TestID; } catch (Exception) { } return Value; } set { SetArmAttribute(AttributeTypes.ArmAndEventAttributes.Name, value); try { (com as IDASCommunication).ConfigData.TestID = value; } catch (Exception) { } } } public string TestSetupUniqueId { get { return (com as IDASCommunication).ConfigData.TestSetupUniqueId; } set { try { (com as IDASCommunication).ConfigData.TestSetupUniqueId = value; } catch (Exception) { } } } public string InstanceID { get { return (com as IDASCommunication).ConfigData.InstanceID; } set { try { (com as IDASCommunication).ConfigData.InstanceID = value; } catch (Exception ex) { APILogger.Log("Failed in ConfigAttributes.InstanceID property", ex); } } } public string TestDescription { get { GetArmAttribute(AttributeTypes.ArmAndEventAttributes.Description, out string Value); try { Value = (com as IDASCommunication).ConfigData.Description; } catch (Exception) { } return Value; } set { if (string.IsNullOrEmpty(value)) { value = " "; } SetArmAttribute(AttributeTypes.ArmAndEventAttributes.Description, value); try { (com as IDASCommunication).ConfigData.Description = value; } catch (Exception) { } } } public ulong PreTriggerSamples { get { GetArmAttribute(AttributeTypes.ArmAndEventAttributes.PreTriggerSamplesRequested, out ulong Value); return Value; } set => SetArmAttribute(AttributeTypes.ArmAndEventAttributes.PreTriggerSamplesRequested, value); } public ulong PostTriggerSamples { get { GetArmAttribute(AttributeTypes.ArmAndEventAttributes.PostTriggerSamplesRequested, out ulong Value); return Value; } set => SetArmAttribute(AttributeTypes.ArmAndEventAttributes.PostTriggerSamplesRequested, value); } public DateTime ScheduledStartTime { get { GetArmAttribute(AttributeTypes.ArmAndEventAttributes.ScheduleUnixTimeIntervalInSec, out UInt32[] Value); var scheduledStartTime = new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(Value[0]); return scheduledStartTime; } set { var epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0); var span = value - epoch; var startTimeInSeconds = Convert.ToUInt32(span.TotalSeconds); //Get existing recording interval var intervalInSeconds = (uint)RecordingInterval; var scheduleUnixTimeIntervalInSec = new UInt32[2] { startTimeInSeconds, intervalInSeconds }; SetArmAttribute(AttributeTypes.ArmAndEventAttributes.ScheduleUnixTimeIntervalInSec, scheduleUnixTimeIntervalInSec, true); } } public int RecordingInterval { get { GetArmAttribute(AttributeTypes.ArmAndEventAttributes.ScheduleUnixTimeIntervalInSec, out UInt32[] Value); var recordingInterval = Value[1]; return (int)recordingInterval; } set { var epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0); //Get existing start time var span = ScheduledStartTime - epoch; var startTimeInSeconds = Convert.ToUInt32(span.TotalSeconds); var intervalInSeconds = Convert.ToUInt32(value * 60); var scheduleUnixTimeIntervalInSec = new UInt32[2] { startTimeInSeconds, intervalInSeconds }; SetArmAttribute(AttributeTypes.ArmAndEventAttributes.ScheduleUnixTimeIntervalInSec, scheduleUnixTimeIntervalInSec, true); } } public DFConstantsAndEnums.RecordingMode TestType { get { GetArmAttribute(AttributeTypes.ArmAndEventAttributes.ArmMode, out DFConstantsAndEnums.RecordingMode Value); return Value; } } #endregion #region Helper functions public uint CalculateNumberOfModules(ConfigurationData config, uint numChannels, bool bIsTOM) { if (bIsTOM) { return 1; } // this is a shortcut for now return numChannels / 3; } public uint CalculateNumberOfUARTs(ConfigurationData config) { var sum = (uint)0; foreach (var idasmod in config.Modules) { foreach (var ch in idasmod.Channels) { if (ch is UARTInputDASChannel) { sum++; break; } } } return sum; } /// /// Returns the number of modules which support output stream /// /// stored xml configuration /// number of modules in xml that contain output stream channels public uint CalculateNumberOfStreamOuts(ConfigurationData config) { var sum = (uint)0; foreach (var idasmod in config.Modules) { foreach (var ch in idasmod.Channels) { if (ch is StreamOutputDASChannel) { sum++; break; } } } return sum; } /// /// Returns the number of modules which support input stream /// /// stored xml configuration /// number of modules in xml that contain output stream channels public uint CalculateNumberOfStreamIns(ConfigurationData config) { var sum = (uint)0; foreach (var idasmod in config.Modules) { foreach (var ch in idasmod.Channels) { if (ch is StreamInputDASChannel) { sum++; break; } } } return sum; } public ulong GetEventTotalSamples(int eventNum) { var samples = 0UL; var eventSamples = new QueryEventAttribute(com); eventSamples.EventNumber = (ushort)eventNum; eventSamples.Key = AttributeTypes.ArmAndEventAttributes.TotalSamplesRecorded; var bFakeNumberOfSamples = false; try { eventSamples.SyncExecute(); samples = (ulong)eventSamples.Value; if (0 == samples) { bFakeNumberOfSamples = true; } } catch (Exception) { bFakeNumberOfSamples = true; } if (bFakeNumberOfSamples) { try { // // Try to get enough info to proceed with a rump download. // var preSamplesRequested = new QueryEventAttribute(com); preSamplesRequested.EventNumber = (ushort)eventNum; preSamplesRequested.Key = AttributeTypes.ArmAndEventAttributes.PreTriggerSamplesRequested; preSamplesRequested.SyncExecute(); var postSamplesRequested = new QueryEventAttribute(com); postSamplesRequested.EventNumber = (ushort)eventNum; postSamplesRequested.Key = AttributeTypes.ArmAndEventAttributes.PostTriggerSamplesRequested; postSamplesRequested.SyncExecute(); samples = (ulong)preSamplesRequested.Value + (ulong)postSamplesRequested.Value + 1L; var totalSamplesRecorded = new SetEventAttribute(com); totalSamplesRecorded.EventNumber = (ushort)eventNum; totalSamplesRecorded.SetValue(AttributeTypes.ArmAndEventAttributes.TotalSamplesRecorded, samples, true); totalSamplesRecorded.SyncExecute(); } catch (Exception ex) { throw new ApplicationException("encountered problem re-querying pre/post samples after initial total sample request failure", ex); } } return samples; } public ulong GetEventTriggerSampleNumber(int eventNum) { var eventTSN = new QueryEventAttribute(com); eventTSN.EventNumber = (ushort)eventNum; eventTSN.Key = AttributeTypes.ArmAndEventAttributes.TriggerSampleNumber; try { eventTSN.SyncExecute(); } catch (Exception) { return 0UL; } return (ulong)eventTSN.Value; } public void SetEventTriggerSampleNumber(int eventNum, ulong sampleNumber) { var eventTSN = new SetEventAttribute(com); eventTSN.EventNumber = (ushort)eventNum; eventTSN.SetValue(AttributeTypes.ArmAndEventAttributes.TriggerSampleNumber, sampleNumber, true); eventTSN.SyncExecute(); } public UInt64 GetEventStartRecordSampleNumber(int eventNum) { var eventSRSN = new QueryEventAttribute(com); eventSRSN.EventNumber = (ushort)eventNum; eventSRSN.Key = AttributeTypes.ArmAndEventAttributes.StartRecordSampleNumber; try { eventSRSN.SyncExecute(); } catch (Exception) { return 0UL; } return (ulong)eventSRSN.Value; } public virtual uint GetEventSamplerate(int eventNum) { var eventSR = new QueryEventAttribute(com); eventSR.EventNumber = (ushort)eventNum; eventSR.Key = AttributeTypes.ArmAndEventAttributes.SampleRate; eventSR.SyncExecute(); return (uint)eventSR.Value; } public uint[] GetEventStackSamplerate(int eventNum) { if (com.IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryStackActualSampleRateImmediate)) { var eventSASR = new QueryEventAttribute(com); eventSASR.EventNumber = (ushort)eventNum; eventSASR.Key = AttributeTypes.ArmAndEventAttributes.StackActualSampleRateHz; eventSASR.SyncExecute(); return (uint[])eventSASR.Value; } return new uint[] { }; } public virtual DateTime GetEventStartTime(int eventNum) { if (com.IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.BaseSystemTime)) { try { // base system time format in BCD. There are 7-byte stream as follow: // byte[0] = seconds: 0-59 // byte[1] = minutes: 0-59 // byte[2] = hours: 0: // byte[3] = days. // byte[4] = weekdays. // byte[5] = months. // byte[6] = years. var query = new QueryEventAttribute(com); query.EventNumber = (ushort)eventNum; query.Key = AttributeTypes.ArmAndEventAttributes.EventTimeStamp; query.SyncExecute(); if (query.Value is byte[] bytes) { if (7 <= bytes.Length) { //this is invalid data, just ignore it if (bytes.Length >= 8 && 0 == bytes[0] && 0 == bytes[1] && 0 == bytes[2] && 0 == bytes[3] && 0 == bytes[4] && 0 == bytes[5] && 0 == bytes[6] && 1 == bytes[7]) { return new DateTime(0); } //if month or day is 0 this is an invalid date, don't try to parse it if (0 == bytes[5] && 0 == bytes[3]) { return new DateTime(0); } //15613 - Don't validate RTC DateTime value from SLICE var dt = new DateTime(bytes[6] + 2000, bytes[5], bytes[3], bytes[2], bytes[1], bytes[0]); return dt; } } } catch (Exception ex) { APILogger.Log(ex); } } return new DateTime(0); } public double GetEventAAFilter(int eventNum) { var eventFF = new QueryEventAttribute(com); eventFF.EventNumber = (ushort)eventNum; eventFF.Key = AttributeTypes.ArmAndEventAttributes.AAFilterFrequency; eventFF.SyncExecute(); var aafilter = (float)eventFF.Value; return aafilter; } public double GetEventExcitation(int eventNum) { var eventExc = new QueryEventAttribute(com); eventExc.EventNumber = (ushort)eventNum; throw new ApplicationException("GetEventExcitation needs to be implemented by channel ..."); } public virtual float[] GetEventScaleFactors(int eventNum) { var query = new QueryEventAttribute(com); query.EventNumber = (ushort)eventNum; query.Key = AttributeTypes.ArmAndEventAttributes.StackChannelScaleFactorsMillivoltsPerADC; query.SyncExecute(); return query.Value as float[]; } /// /// Get the number of "level triggered" samples required for a level trigger to be declared by the DAS. /// /// /// /// The event number for which we want level trigger qualification sample information. /// /// /// /// The number of contiguous "level triggered" samples required for a level trigger event. /// /// private int[] GetLevelTriggerQualificationSamples(int eventNum) { try { if (this is WinUSBSlice6) { return null; } if (this is WinUSBSlice6Air) { return null; } var eventLevTrigQlfSamps = new QueryEventAttribute(com); eventLevTrigQlfSamps.Key = AttributeTypes.ArmAndEventAttributes.LevelTriggerQualificationSamples; eventLevTrigQlfSamps.SyncExecute(); return (int[])(eventLevTrigQlfSamps.Value); } catch (Exception ex) { throw new ApplicationException("encountered problem getting number of level trigger qualification samples from hardware for event " + eventNum.ToString(), ex); } } /// /// Get determination from hardware whether or not the associated DAS has directly experienced a level trigger event. /// /// /// /// The event number for which we want level trigger seen information. /// /// /// /// True if the associated DAS has experienced a level trigger event; False otherwise. /// /// private bool[] GetLevelTriggerSeen(int eventNum) { try { var eventLevTrigSeen = new QueryEventAttribute(com); eventLevTrigSeen.EventNumber = Convert.ToUInt16(eventNum); eventLevTrigSeen.Key = AttributeTypes.ArmAndEventAttributes.LevelTriggerSeen; eventLevTrigSeen.SyncExecute(); return (bool[])(eventLevTrigSeen.Value); } catch (Exception ex) { throw new ApplicationException("encountered problem getting \"level trigger seen\" condition from hardware for event " + eventNum.ToString(), ex); } } /// /// Get number of samples that the associated hardware adjusted its level trigger time value from the time it /// actually issued a trigger fault. This adjustment is necessary because several contiguous level-triggered /// samples are necessary before some flavors of DAS will declare an actual level trigger. Once the hardware has /// determined that a trigger has occured, it must "backdate" the T0 to match the time of the first /// level-triggered sample. This number only exists for hardware that has directly experienced a level trigger /// condition. /// /// /// /// The number of the event we want the adjustment samples for. /// /// /// /// The number of samples that this DAS' trigger time value has been adjusted to compensate for time required /// by the hardware for level trigger evaluation. If the associated hardware did not directly experience the /// level trigger, this value will be null. /// /// public int?[] GetEventLevelTriggerT0AdjustmentSamples(int eventNum) { try { var eventLevTrigT0AdjSamp = new QueryEventAttribute(com); eventLevTrigT0AdjSamp.EventNumber = (ushort)eventNum; eventLevTrigT0AdjSamp.Key = AttributeTypes.ArmAndEventAttributes.LevelTriggerT0AdjustmentSamples; eventLevTrigT0AdjSamp.SyncExecute(); var levelTriggerAdjSamples = (int[])(eventLevTrigT0AdjSamp.Value); var levelTriggerSeen = GetLevelTriggerSeen(eventNum); var finalAdjustment = new int?[levelTriggerAdjSamples.Length]; for (var channel = 0; channel < finalAdjustment.Length; channel++) { finalAdjustment[channel] = (channel < levelTriggerSeen.Length && levelTriggerSeen[channel]) ? levelTriggerAdjSamples[channel] : (int?)null; } return finalAdjustment; } catch (Exception) { // CGO // This is a hacked change for now to support 00G8 and prior firmware // in the 1.04 release of SLICEWare. This and the other CGO commented // block of code need more general cleanup before 1.05. return null; //throw new ApplicationException( "encountered problem getting event level trigger T0 adjustment samples from hardware for event " + eventNum.ToString( ), ex ); } } public bool[] GetEventLevelTriggerSeen(int eventNum) { try { var levelTriggerSeen = GetLevelTriggerSeen(eventNum); return levelTriggerSeen; } catch (Exception) { return new bool[0]; } } public bool EventHasBeenDownloaded(int eventNum, out uint flag) { try { var eventDLFlag = new QueryEventAttribute(com); eventDLFlag.EventNumber = (ushort)eventNum; eventDLFlag.Key = AttributeTypes.ArmAndEventAttributes.EventHasBeenDownloaded; eventDLFlag.SyncExecute(); flag = (uint)eventDLFlag.Value; try { var eventTitle = new QueryEventAttribute(com); eventTitle.EventNumber = (ushort)eventNum; eventTitle.Key = AttributeTypes.ArmAndEventAttributes.Description; eventTitle.SyncExecute(); if (null == eventTitle.Value) { return true; } var desc = Encoding.ASCII.GetString(eventTitle.Value as byte[]); if (desc.Contains("TESTTRIG")) { flag = 1; }//just always mark testtrig data as already downloaded } catch (Exception) { } return 0 != flag; } catch (Exception) { flag = 0; return false; } } public void SetEventDownloaded(int eventNum, uint flag) { var eventDLFlag = new SetEventAttribute(com); eventDLFlag.EventNumber = (ushort)eventNum; eventDLFlag.SetValue(AttributeTypes.ArmAndEventAttributes.EventHasBeenDownloaded, flag, true); eventDLFlag.SyncExecute(); } public string GetEventID(int eventNum, IDASCommunication das) { try { var s = RetrieveEventXMLConfig(eventNum, null, das); var cd = ConfigurationData.DeserializeFromString(s); return cd?.TestID; } catch (Exception) { } var eventName = new QueryEventAttribute(com); eventName.EventNumber = (ushort)eventNum; eventName.Key = AttributeTypes.ArmAndEventAttributes.Name; eventName.SyncExecute(); var values = eventName.Value as byte[]; if (null == values) { return eventName.Value as string; } else { var value = Encoding.UTF8.GetString(values); return value; } } public ushort GetEventFaultFlagsEx(int eventNum) { //currently not implemented by firmware return 0; } public ushort GetEventFaultFlags(int eventNum) { if (com.IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.EventFaultFlags)) { var eventFaultFlags = new QueryEventAttribute(com, QueryEventAttribute.Default_IO_Timeout); eventFaultFlags.EventNumber = (ushort)eventNum; eventFaultFlags.Key = AttributeTypes.ArmAndEventAttributes.FaultFlags; eventFaultFlags.SyncExecute(); return (ushort)eventFaultFlags.Value; } else { return 0; } } public byte GetEventArmAttempts(int eventNum) { if (com.IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.EventArmAttempts)) { var eventArmAttempts = new QueryEventAttribute(com, QueryEventAttribute.Default_IO_Timeout); eventArmAttempts.EventNumber = (ushort)eventNum; eventArmAttempts.Key = AttributeTypes.ArmAndEventAttributes.EventArmAttempts; eventArmAttempts.SyncExecute(); return (byte)eventArmAttempts.Value; } else { return 0; } } public string GetEventDescription(int eventNum) { var eventDescr = new QueryEventAttribute(com); eventDescr.EventNumber = (ushort)eventNum; eventDescr.Key = AttributeTypes.ArmAndEventAttributes.Description; eventDescr.SyncExecute(); if (!(eventDescr.Value is byte[] values) || values.Length == 0) { return eventDescr.Value as string; } var value = Encoding.UTF8.GetString(values); return value; } #endregion } } }