using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using DTS.Common.DAS.Concepts; using System.Threading; using System.Windows.Forms; using DTS.Common.DASResource; using DTS.Common.Interface.DASFactory; using Arm = DTS.DASLib.Command.SLICE.Arm; using Disarm = DTS.DASLib.Command.SLICE.Disarm; using EnableFaultChecking = DTS.DASLib.Command.SLICE.EnableFaultChecking; using DTS.DASLib.Command.SLICE; using DTS.Common.Utilities.Logging; using System.Text; using DTS.DASLib.Service.Classes.SLICE; using System.Net.NetworkInformation; using DTS.Common.Enums.Sensors; using DTS.Common.Interface.Communication; using DTS.Common.Interface.Connection; using DTS.Common.Enums.DASFactory; using DTS.Common.Interface.StatusAndProgressBar; using DTS.Common.Enums; using DTS.DASLib.Service.Interfaces; using DTS.Common; using DTS.Common.ICommunication; using DTS.DASLib.Command; using TiltMIF; using DTS.DASLib.Command.SLICE.DownloadCommands; using DTS.Common.Constant.DASSpecific; using DTS.Common.Enums.Hardware; using DTS.Common.Classes.DASFactory; using DTS.Common.Interface.DASFactory.Download; namespace DTS.DASLib.Service { public class SLICE6DB : SLICE2_Base, IConfigurationActions, IDiagnosticsActions, ITriggerCheckActions, IRealTimeActions, IArmActions, IDownloadActions, IClockSyncActions where T : IConnection, new() { protected override uint[] GetExtendedFaultFlags(int eventIndex) { try { var qee = new QueryArmAttribute(this) { Key = AttributeTypes.ArmAndEventAttributes.ExtFaultFlags }; qee.SyncExecute(); return (uint[])qee.Value; } catch (Exception ex) { APILogger.Log(ex); } return new uint[] { 0, 0, 0, 0 }; } protected override void SetArmAttribute(AttributeTypes.ArmAndEventAttributes key, DFConstantsAndEnums.RecordingMode value) { var mode = value; switch (mode) { case DFConstantsAndEnums.RecordingMode.MultipleEventRAMActive: mode = DFConstantsAndEnums.RecordingMode.AutoCircularBufferMode; break; case DFConstantsAndEnums.RecordingMode.RAMActive: mode = DFConstantsAndEnums.RecordingMode.CircularBuffer; break; } base.SetArmAttribute(key, mode); } /// /// whether RTC battery (Yuba) is present /// public bool RTCBatteryPresent { get; set; } = false; /// /// the serial number of the RTC battery if present /// public uint? RTCSerialNumber { get; set; } = null; /// /// the RTC production date if present and set /// public DateTime? RTCProductionDate { get; set; } = null; /// /// the RTC battery install date if present and set /// public DateTime? RTCBatteryInstallationDate { get; set; } = null; /// /// returns true if device supports start inversion, false otherwise /// /// /// true if unit supports start inversion, false otherwise public override bool SupportsStartInversion() => HardwareConstants.SupportsStartInversion(GetHardwareType(), ProtocolVersion); /// /// returns true if device supports trigger inversion, false otherwise /// /// /// true if unit supports trigger inversion, false otherwise public override bool SupportsTriggerInversion() => HardwareConstants.SupportsTriggerInversion(GetHardwareType(), ProtocolVersion); public override bool? ChargingEnabled { get { return true; } } /// /// populates the connected devices field /// public override void QueryConnectedDevices() { List connectedDevices = new List(); if (!RunTestVariables.InRunTest || RunTestVariables.QueryConnectedDevicesInRunTest) { if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryEthernetMacTable)) { } else { var cmd = new QueryEthernetMacIpTable(this); cmd.UpdateBuffer = false; cmd.SyncExecute(); var ips = new List(); foreach (var entry in cmd.MacIpTable) { string address = Encoding.UTF8.GetString(entry.Mac, 0, 18); address = address.Replace("\0", " ").Split(' ')[0]; string ip = Encoding.UTF8.GetString(entry.Ip, 0, 16); ip = ip.Replace("\0", " ").Split(' ')[0]; string sn = Encoding.UTF8.GetString(entry.Sn, 0, 10); sn = sn.Replace("\0", " ").Split(' ')[0]; string location = Encoding.UTF8.GetString(entry.Location, 0, 10); location = location.Replace("\0", " ").Split(' ')[0]; string version = Encoding.UTF8.GetString(entry.Version, 0, 5); version = version.Replace("\0", " ").Split(' ')[0]; var s6 = new S6DBConnectedDevice(entry.Port, entry.Down, new PhysicalAddress(entry.Mac), ip, sn, location, version); connectedDevices.Add(s6); ips.Add(ip); } APILogger.Log($"{SerialNumber} has attached {string.Join(", ", ips.ToArray())}"); } } ((ICommunication)this).DASInfo.SetConnectedDevices(connectedDevices.ToArray()); } void IConfigurationActions.SetFirstUseDate(DateTime firstUseDate, ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Error("Not supported"); } void ITriggerCheckActions.PreStartTriggerCheck(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); LaunchAsyncWorker("SliceDB.StartTriggerCheck", AsyncPreStartTriggerCheckSLICE6DB, info); } void ITriggerCheckActions.PostStartTriggerCheck(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); LaunchAsyncWorker("SliceDB.StartTriggerCheck", AsyncPostStartTriggerCheckSLICE6DB, info); } /// /// returns true if the devices is an ethernet distributor /// for now that is SLICEDb, SLICE ECM, SLICE6DB /// these are devices that we talk through, but not to for device communication /// a rack we communicate with the modules by talking to the rack, so it's not a distributor /// /// returns true if the devices is an ethernet distributor public override bool IsEthernetDistributor() { return true; } public override bool IsSlice6Distributor() { return true; } public override bool IsBattery() { return false; } public override bool IsTSRAIR() { return false; } public new bool IsSlice6Air() { return false; } public override bool IsScheduleEventCountSupported() { return false; } private const int UNKNOWN_REVISION = -1; //unknown private const int REVISION_WIAMAN1 = 0; //original WIAMan private const int REVISION_WIAMAN2 = 2; //WIAMan RevB private const int REVISION_AIR = 4; //SLICE 6 AIR DB public enum S6DBModes { WIAMAN, //settings for WIAMAN implementation of S6DB INDUMMY, //settings for THOR implementation of S6DB AIR //settings for S6DB AIR } public S6DBModes S6DBMode { get; set; } = S6DBModes.INDUMMY; /// /// there is not a DAS, so no nominal ranges are returned /// always throws an exception as there are no acceptable nominal ranges /// /// /// public override double[] GetNominalRanges(SensorConstants.BridgeType bridge) { throw new NotImplementedException(); } /// /// Distributors carry a single module with a single channel by old SLICEWare tradition /// public override int MaxModules { get => 1; set {; } } /// /// Distributors don't collect or filter data, so safe to say they don't introduce any phase shifts. /// /// /// /// /// public override ulong GetPhaseShiftSamples(uint ModuleIndex, double ActualSampleRate, uint HardwareAAF, ulong originalT0) { return 0; } /// /// Distributor does not do flash erase, so returns success immediately /// /// /// public void BeginBackgroundFlashErase(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } /// /// Unit is not capable of flash erase or background flash erase /// public bool SupportsBackgroundFlashErase => false; /// /// returns whether unit has started background flash erase /// public bool BackgroundFlashEraseStarted => false; /// /// there's no background flash erase on Distributors /// returns null /// public DateTime? BackgroundFlashEraseStartTime => null; /// /// there's no DAS display order currently for SLICE6 Distributors /// /// public override int GetDASDisplayOrder() { return -1; } /// /// there's no channels for SLICE6 Distributors. /// /// public override int[] GetChannelDisplayOrder() { return new[] { -1 }; } /// /// can't set the DAS display order for SLICE6 distributors /// throws not supported exception /// /// public override void SetDASDisplayOrder(int order) { throw new NotSupportedException("Not supported for Slice6DB"); } /// /// setting channel order is not supported on SLICE6 distributor, /// throws not supported exception /// /// public override void SetChannelDisplayOrder(int[] order) { throw new NotSupportedException("Not supported for Slice6DB"); } /// /// does not have a diagnostic sample rate, so requirediagnosticsampleratematch isn't needed /// /// public override bool RequireDiagnosticRateMatchSampleRate() { return false; } /// /// this might be useful for SLICE6 Db, but not known yet. /// public override DateTime SystemBaseTime => DateTime.MinValue; /// /// SLICE6 Distributor is not range limited by bandwidth /// public override bool RangeBandwidthLimited => false; /// /// readies unit for arming, currently nothing additional is done for SLICE6 DB /// /// /// /// /// /// /// /// /// public void ReadyForArming(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode, int maxNumberEvents, bool DummyArm, bool SysMode) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } public void CorrectT0s(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Error("Not supported"); return; } /// /// SLICE6 doesn't store event info, so right now this just returns success right away, there's nothing to do /// /// /// /// /// /// /// /// /// /// public void SetEventInfo(int eventIndex, string id, Guid guid, ulong totalSamples, ulong[] triggerSamples, ulong startRecordSample, UInt32 eventHasDownloaded, ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } /// /// SLICE6 DB doesn't store anything, so it's max memory is unlimited /// /// public override long MaxMemory() { return long.MaxValue; } /// /// SLICE6 DB doesn't record anything, so it's max sample rate is unlimited /// /// public override uint MaxSampleRate(int numberOfConfiguredChannels) { return uint.MaxValue; } /// /// SLICE6 doesn't record anything, so it's min sample rate is 0 /// /// public override uint MinSampleRate() { return uint.MinValue; } public override uint MaxAAFilterRate() { return MaxAAFilterRateHz; } /// /// this is a duplicate class of SLICEDb.SDBAsyncInfo, we might want to just use that one, but it is marked private there /// private class SDBAsyncInfo { public ServiceCallback Callback { get; set; } public object UserData { get; set; } public object FunctionData { get; set; } public SDBAsyncInfo(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", "SDB ERROR", 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", "SDB ERROR", 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", "SDB ERROR", 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", "SDB ERROR", ex); } } } void IConfigurationActions.CheckAAFilterRate(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); info.Success(); } /// /// Verify that the ConfigData property is correctly constructed /// /// Set to true if your're arming public void VerifyConfig(bool DoStrictCheck) { VerifyConfig(DoStrictCheck, null); } void IConfigurationActions.ResetHardwareLines(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice6DB.ResetHardwareLines", AsyncResetHardwareLines, info); } protected virtual void AsyncResetHardwareLines(object asyncInfo) { if (!(asyncInfo is SliceServiceAsyncInfo info)) { return; } if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines)) { info.Success(); return; } //performance improvement, don't set polarity when a system doesn't need to //[reduce # of commands] if (RunTestVariables.InRunTest && RunTestVariables.DontSetPolarityInRunTest) { //don't set } else { try { var ssaStart = new SetSystemAttribute(this); var ssaTrigger = new SetSystemAttribute(this); ssaStart.SetValue(AttributeTypes.SystemAttributes.StartRecordPolarity, (byte)(InvertStart ? 1 : 0), true); ssaTrigger.SetValue(AttributeTypes.SystemAttributes.TriggerPolarity, (byte)(InvertTrigger ? 1 : 0), true); ssaStart.SyncExecute(); ssaTrigger.SyncExecute(); var ssi = new SetSwitchImmediate(this) { DeviceID = 0x00, Switch = (byte)Switches.BaseSwitches.TriggerOut, SwitchText = Switches.BaseSwitches.TriggerOut.ToString(), Setting = InvertTrigger ? Convert.ToByte(1) : Convert.ToByte(0) }; ssi.SyncExecute(); } catch (Exception ex) { APILogger.Log(ex); } } info.Success(); } public void VerifyConfig(bool DoStrictCheck, ErrorCallback failedChallengeFunc) { if (!DoStrictCheck) return; if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines)) return; var query = new InitializeHardwareLines(this) { CheckStartForShort = true, CheckTriggerForShort = true }; try { query.SyncExecute(); if (query.StartRecordShorted && !IgnoreShortedStart) { //Start Shorted throw new StartShortedException(string.Format(Strings.StartRecordShorted, SerialNumber)); } if (query.TriggerInputShorted && !IgnoreShortedTrigger) { //Trigger Shorted throw new TriggerShortedException(string.Format(Strings.TriggerShorted, SerialNumber)); } } catch (Exception ex) { InitializeHardwareLines.Log(ex, query); } } /// /// SLICE6 DB does not have a safety switch and is always in the right safety switch state, so /// return sucess immediately /// /// /// /// public void CheckSafetyState(bool bArmed, ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } /// /// there is nothing to configure in SLICE6DB currently, so it just returns immediately /// /// /// /// /// /// public void Configure(ServiceCallback callback, object userData, bool EventConfig, bool dummyConfig, double[] maxAAF, bool configureDigitalOutput, uint crc) { var info = new SliceConfigServiceAsyncInfo(callback, userData, EventConfig, crc, true) { DummyConfig = dummyConfig, ConfigureDigitalOutput = configureDigitalOutput }; LaunchAsyncWorker("Slice.Configure", AsyncConfigure, info); } void IConfigurationActions.ApplyLevelTriggers(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice6DB.ApplyLevelTriggers", AsyncApplyLevelTriggers, info); } protected override void AsyncApplyLevelTriggers(object asyncInfo) { var info = (SliceServiceAsyncInfo)asyncInfo; info.Success(); } protected override void AsyncConfigure(object configAsyncInfo) { var info = (SliceConfigServiceAsyncInfo)configAsyncInfo; if (ConfigData != null && ConfigData.Modules.Any()) { try { var saa = new SetArmAttribute(this); saa.SetValue(AttributeTypes.ArmAndEventAttributes.SampleRate, ConfigData.Modules[0].SampleRateHz, true); saa.SyncExecute(); var ssaV = new SetSystemAttributeSLICE6DB(this); //input min, input max, battery min, battery max var requirements = new[] { InputLowVoltage, InputHighVoltage, BatteryLowVoltage, BatteryHighVoltage }; ssaV.SetValue(AttributeTypes.SystemAttributesSLICE6DB.VoltageRequirements, requirements, true); ssaV.SyncExecute(); } catch (Exception ex) { APILogger.Log("failed to configure", SerialNumber, ex); info.Error(ex.Message); return; } } ConfigureHasBeenRun = true; if (info.DiscardDiagnostics) { DiagnosticsHasBeenRun = false; } info.Progress(100); info.Success(); } /// /// retrieves information on Yuba/RTC and populates properties /// private void GetYubaInfo() { try { var rtcRamGet = new TiltSensorGet(this) { Tilt_id = 0xFF, Sub_cmd = TiltSensorMif.RtcRam, Data_Offset = 0, Data_Length = 6 }; rtcRamGet.SyncExecute(); var inputData = rtcRamGet.Data; if (null == inputData) { //no error, so Yuba present, however the bytes are null, so the battery lost power ... RTCBatteryPresent = true; RTCProductionDate = null; RTCSerialNumber = null; RTCBatteryInstallationDate = null; return; } RTCSerialNumber = rtcRamGet.RTCSerialNumber; if (0 < rtcRamGet.RTCProductionDaysSince1970) { RTCProductionDate = (new DateTime(1970, 1, 1)).AddDays(rtcRamGet.RTCProductionDaysSince1970); } else { //yuba present, but attribute has a value of 0, which is invalid RTCProductionDate = null; } if (0 < rtcRamGet.RTCBatteryInstallationDaysSince1970) { RTCBatteryInstallationDate = (new DateTime(1970, 1, 1)).AddDays(rtcRamGet.RTCBatteryInstallationDaysSince1970); } else { //yuba present, but attribute has a value of 0, which is invalid RTCBatteryInstallationDate = null; } RTCBatteryPresent = true; } catch (Exception ex) { //Yuba not present RTCBatteryPresent = false; RTCProductionDate = null; RTCSerialNumber = null; RTCBatteryInstallationDate = null; APILogger.Log("failed to retrieve RTC information", ex); } } protected override void AsyncQueryConfiguration(object configAsyncInfo) { if (RunTestVariables.InRunTest && RunTestVariables.Assumed_S6DB_ProtocolVersion > 0) { S6DBMode = S6DBModes.WIAMAN; } else { //26821 Add query of BaseFirmwareBuildID for SLICE PRO/ 1.5/ S6/S6A/PowerPRO/S6DB/S6DB3/ TSR AIR for Logs QueryBaseFirmwareBuildId(); switch (QueryHardwareRevision()) { case REVISION_WIAMAN1: case REVISION_WIAMAN2: S6DBMode = S6DBModes.WIAMAN; break; case REVISION_AIR: S6DBMode = S6DBModes.AIR; break; default: //includes THOR types and fallback to unknown S6DBMode = S6DBModes.INDUMMY; break; } } GetYubaInfo(); // get attached tilt sensor I2C ids var activeTilts = new List(); try { if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryExternalTiltInfo)) { List tiltIds = new List(); ushort numTilt; byte[] tiltAddr; var tiltSensorGet = new TiltSensorGet(this) { Sub_cmd = TiltSensorMif.TiltSenosrList }; tiltSensorGet.SyncExecute(); numTilt = tiltSensorGet.NumberOfTilt; tiltAddr = tiltSensorGet.Tilt_Address; for (int i = 0; i < numTilt; i++) { tiltIds.Add(tiltAddr[i]); } foreach (var tID in tiltIds) { tiltSensorGet = new TiltSensorGet(this, 600000) { Tilt_id = tID, Sub_cmd = TiltSensorMif.TiltSensorEEPROM, Data_Offset = 0, Data_Length = 256 }; tiltSensorGet.SyncExecute(); var tiltMif = new Tilt_MIF(tiltSensorGet.Data); if (tiltMif.ArmChecklist) { activeTilts.Add(new Common.Classes.Hardware.ExternalTilt() { SerialNumber = tiltMif.SerialNumber, TiltID = tID, SystemLocation = tiltMif.Location, SystemID = tiltMif.SystemID, }); } } } } catch (Exception ex) { APILogger.Log(ex); } DASInfo.ActiveExternalTilts = activeTilts; base.AsyncQueryConfiguration(configAsyncInfo); } /// /// Retrieve configuration from DAS and store it in the ConfigData property /// SLICE6 DB doesn't have a configuration or storage, so it returns immediately /// /// The function to call with information /// Whatever you want to pass along public void QueryConfiguration(ServiceCallback callback, object userData) { if (RunTestVariables.InRunTest && RunTestVariables.Assumed_S6DB_ProtocolVersion > 0) { S6DBMode = S6DBModes.WIAMAN; } else { switch (QueryHardwareRevision()) { case REVISION_WIAMAN1: case REVISION_WIAMAN2: S6DBMode = S6DBModes.WIAMAN; break; case REVISION_AIR: S6DBMode = S6DBModes.AIR; break; default: //includes THOR types and fallback to unknown S6DBMode = S6DBModes.INDUMMY; break; } } GetYubaInfo(); var info = new SDBAsyncInfo(callback, userData); ConfigData = new ConfigurationData { Modules = new DASModule[] { new DASModule(0, this) } }; ConfigData.Modules[0].Channels = new DASChannel[] { new AnalogInputDASChannel((DASModule)ConfigData.Modules[0], 0) }; ConfigData.IDs = new EID[0]; ConfigData.TestID = ""; ConfigData.Description = ""; info.Success(); } /// /// Retrieve hardware revision from DAS /// protected new int QueryHardwareRevision() { if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.HardwareRevision)) { return UNKNOWN_REVISION; } else { try { var qsa = new QuerySystemAttributeSLICE6DB(this); qsa.Key = AttributeTypes.SystemAttributesSLICE6DB.BaseHardwareRevision; qsa.SyncExecute(); return Convert.ToInt32(qsa.Value); } catch (Exception ex) { APILogger.Log("failed to get hardware revision", ex); } return UNKNOWN_REVISION; } } /// /// Retrieve the EID's and store it in the ConfigData property /// /// The function to call with information /// Whatever you want to pass along public void UpdateIDs(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } /// /// not sure the purpose of this function, but there are no ids on a distributor, so return immediately /// /// /// /// /// public void UpdateId(ServiceCallback callback, object userData, DASModule module, DASChannel channel) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } /// /// If any of the units to run diagnostics are in /// /// DTS.DASLib.Service.ArmingService.EnterLowPowerMode then the analog circuits must be "warmed up" before accurate /// diagnostics can be performed. If the units have not been placed into /// DTS.DASLib.Service.ArmingService.EnterLowPowerMode then there is no need to call /// this but since it is quite important habitually calling it everytime /// diagnostics are performed would be beneficial. /// /// The firmware will use this sample rate when /// collecting diagnostics data from the channel. /// The firmware will use this Anti-Aliasing /// filter when collectin diagnostics data from the channel. /// The function to call with information. /// Whatever you want to pass along. public void PrepareForBridgeResistanceMeasurement(UInt32 DiagnosticsSampleRateHz, float DiagnosticsAAFilterFrequencyHz, ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } public void GetBridgeMeasurement(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } void IDiagnosticsActions.MeasureTransferSpeed(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } /// /// Perform diagnostics based on the property ChannelDiagnostics and stuff the /// result in ChannelDiagnosticsResults /// /// sample rate /// AA Filter rate /// The function to call with information /// Whatever you want to pass along public void PrepareForDiagnostics(UInt32 DiagnosticsSampleRateHz, float DiagnosticsAAFilterFrequencyHz, PrePostResults WhichResult, ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } public void PerformArmChecks(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); LaunchAsyncWorker("Slice6DB.PerformArmChecks", new WaitCallback(AsyncPerformArmChecks), info); } protected virtual bool SupportsTemperatureCheck => true; protected virtual bool SupportsTiltCheck => true; protected virtual bool SupportsClockSyncCheck => true; private void AsyncPerformArmChecks(object o) { var info = o as SDBAsyncInfo; var dasResults = new ArmCheckResults(); info.Progress(25); if (null != ArmCheckActions) { GetBaseInputs(); if (ArmCheckActions.PerformBatteryVoltageCheck) { if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.Diagnostics)) { if (dasResults.BatteryVoltage != null) { if (dasResults.BatteryVoltage != null) { try { dasResults.BatteryVoltage[0] = BaseInput.BatteryMilliVolts / 1000D; } catch (Exception ex) { APILogger.Log("Failed to get Battery voltage", ex); } } } } } info.Progress(50); if (ArmCheckActions.PerformInputVoltageCheck) { if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.Diagnostics)) { try { dasResults.InputVoltage = BaseInput.InputMilliVolts / 1000D; } catch (Exception ex) { APILogger.Log("Failed to get Input voltage", ex); } } } if (ArmCheckActions.PerformSquibResistanceCheck) { // No Squibs in SDB or ECM } if (ArmCheckActions.PerformEventLineCheck) { ((ITriggerCheckActions)this).DoTriggerCheckSync(); } if (ArmCheckActions.PerformSensorIdCheck) { //not needed } if (ArmCheckActions.PerformTemperatureCheck && SupportsTemperatureCheck) { // Temperature var keys = Enum.GetValues(typeof(DFConstantsAndEnums.TempLogChannelBits)).Cast().ToArray(); dasResults.TemperaturesPre = new float[keys.Length]; for (var i = 0; i < keys.Length; i++) { dasResults.TemperaturesPre[i] = float.NaN; } var qsa = new QuerySystemAttributeSLICE6DB(this) { Key = AttributeTypes.SystemAttributesSLICE6DB.S6DBbaseEnvTempLoggingConfig, }; qsa.SyncExecute(); if (qsa.Value is ushort[] config) { var tempConfig = new TemperatureConfig(config); var s6DBDiagChannels = tempConfig.GetMeasurementChannels(); foreach (var diagChan in s6DBDiagChannels) { var measure = new MeasureS6DBDiagnosticChannel(this); measure.Channel = diagChan; measure.SyncExecute(); dasResults.TemperaturesPre[(int)tempConfig.GetChannelBitForDiagChannel(diagChan)] = measure.Measurement; } } } if (ArmCheckActions.PerformClockSyncCheck && IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.PTPSyncStatus) && SupportsClockSyncCheck) { //SLICE 6, S6DB, etc. var query = new Ptp1588GetSyncStatus(this); try { query.SyncExecute(); var syncStatus = new Dictionary(); List sources = Enum.GetValues(typeof(DTS.Common.InputClockSource)).Cast().ToList(); for (int i = 1; i < sources.Count; i++) { // init all sources not synced syncStatus.Add(sources[i], false); } syncStatus[DTS.Common.InputClockSource.PTP] = (Ptp1588Commands.PtpSyncStatus.Synced == query.SyncStatus); dasResults.InputClockLocks = syncStatus; } catch (Exception ex) { info.Error(ex.Message, ex); } } if (ArmCheckActions.PerformTiltSensorCheck && SupportsTiltCheck) { GetTiltResults(dasResults); } } info.Progress(100); dasResults.SensorIds = null; dasResults.SquibResistances = null; ArmCheckResults = dasResults; info.Success(); } public void SaveTiltSensorDataPre(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); LaunchAsyncWorker("SliceDB.SaveTiltSensorData", AsyncSaveTiltSensorDataPre, info); } private void AsyncSaveTiltSensorDataPre(object o) { if (!(o is SDBAsyncInfo info)) { return; } if (DASInfo.ActiveExternalTilts.Count > 0) { if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryTiltSensorData) && SupportsTiltCheck) { try { // Get Tilt Cals TiltSensorGet tiltSensorGet; foreach (var tiltInfo in DASInfo.ActiveExternalTilts) { tiltSensorGet = new TiltSensorGet(this, 600000) { Tilt_id = tiltInfo.TiltID, Sub_cmd = TiltSensorMif.TiltSensorEEPROM, Data_Offset = 0, Data_Length = 256 }; tiltSensorGet.SyncExecute(); var curMif = new Tilt_MIF(tiltSensorGet.Data); curMif.PreEventADCAxis1 = ArmCheckResults.IndexedTiltSensorDataPre[tiltInfo.TiltID][0]; curMif.PreEventADCAxis2 = ArmCheckResults.IndexedTiltSensorDataPre[tiltInfo.TiltID][1]; curMif.PreEventADCAxis3 = ArmCheckResults.IndexedTiltSensorDataPre[tiltInfo.TiltID][2]; var tiltSensorSet = new TiltSensorSet(this, 600000); var payload = curMif.GetBytes(); tiltSensorSet.SetEEPROM(tiltInfo.TiltID, 0, payload); tiltSensorSet.SyncExecute(); } } catch (CanceledException) { info.Cancel(); } catch (Exception ex) { info.Error(ex.Message, ex); } } } info.Success(); } public void SaveTemperaturesPre(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); LaunchAsyncWorker("SliceDB.SaveTiltSensorData", AsyncSaveTemperaturesPre, info); } private void AsyncSaveTemperaturesPre(object asyncInfo) { var info = asyncInfo as SDBAsyncInfo; Debug.Assert(info != null, "info != null"); if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.InSliceTemperatureCPre) && SupportsTemperatureCheck) { var setTS = new SetArmAttribute(this); setTS.SetValue(AttributeTypes.ArmAndEventAttributes.preEventTempHumidity1234, ArmCheckResults.TemperaturesPre, true); setTS.SyncExecute(); } info.Success(); } /// /// Perform diagnostics based on the property ChannelDiagnostics and stuff the /// result in ChannelDiagnosticsResults /// /// The function to call with information /// Whatever you want to pass along public void DiagnosAndGetResults(int EventNumber, PrePostResults WhichResult, ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); DiagnosticsHasBeenRun = true; BaseInput = new BaseInputValues(); GetBaseInputs(); ClearChannelDiagnosticsResults(false); info.Success(); } private class EventDiagnosticsAsyncPacket { public SliceServiceAsyncInfo Info { get; set; } public int EventNumber { get; set; } public PrePostResults WhichResult { get; set; } } /// /// Retrieve the results from the implicit pre and post event diagnostics /// /// Which event number to Retrieve from /// The pre or post test results? /// The function to call with information /// Whatever you want to pass along public void GetEventDiagnosticsResults(int EventNumber, PrePostResults WhichResult, ServiceCallback callback, object userData) { var packet = new EventDiagnosticsAsyncPacket(); packet.Info = new SliceServiceAsyncInfo(callback, userData); packet.EventNumber = EventNumber; packet.WhichResult = WhichResult; LaunchAsyncWorker("Slice6DB.GetEventDiagnosticsResults", new WaitCallback(AsyncGetEventDiagnosticsResults), packet); } private void AsyncGetEventDiagnosticsResults(object asyncInfo) { var packet = (EventDiagnosticsAsyncPacket)asyncInfo; ModuleDiagnosticsResult[] resultArray = null; #region Temperature var temperatureDataPre = new float[] { float.NaN, float.NaN, float.NaN, float.NaN, float.NaN, float.NaN, float.NaN, float.NaN }; var temperatureDataPost = new float[] { float.NaN, float.NaN, float.NaN, float.NaN, float.NaN, float.NaN, float.NaN, float.NaN }; if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.InSliceTemperatureCPre) && SupportsTemperatureCheck) { //Get the saved values from the Arm Checklist query (if any) try { var query = new QueryArmAttribute(this) { Key = AttributeTypes.ArmAndEventAttributes.preEventTempHumidity1234 }; query.SyncExecute(); temperatureDataPre = query.Value as float[]; } catch (Exception ex) { APILogger.Log(ex); } } resultArray = new ModuleDiagnosticsResult[1] { new ModuleDiagnosticsResult() }; resultArray[0].TemperatureLocation1Pre = temperatureDataPre[0]; resultArray[0].TemperatureLocation2Pre = temperatureDataPre[1]; resultArray[0].TemperatureLocation3Pre = temperatureDataPre[2]; resultArray[0].TemperatureLocation4Pre = temperatureDataPre[3]; //temperatureDataPre[4-7] can contain humidity readings in the future resultArray[0].TemperatureLocation1Post = temperatureDataPost[0]; resultArray[0].TemperatureLocation2Post = temperatureDataPost[1]; resultArray[0].TemperatureLocation3Post = temperatureDataPost[2]; resultArray[0].TemperatureLocation4Post = temperatureDataPost[3]; //temperatureDataPost[4-7] can contain humidity readings in the future #endregion ModuleDiagnosticsResults = resultArray; packet.Info.Success(); } public void SquibFireCheckArm(double delay, double duration, ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } public void TriggerCheckTrigger(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } public void TriggerCheckDownload(double delay, double duration, float dummyAAFilterFrequencyHz, uint dummySampleRateHz, ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } /// /// This flag is used to tell if arm attributes should be defaulted when arming /// or not. It also serves to let the user know that this DAS has not been /// diagnosed. /// public override bool DiagnosticsHasBeenRun { get => true; set {; } } /// /// this flag is used to tell if configure has been run /// this is used prior to when diagnostic results are needed, like the /// diagnostics tab or the acquire tab [when running acquire] /// public override bool ConfigureHasBeenRun { get => true; set {; } } /// /// Count how many channels are configured. /// /// Number of configured channels. public override int NumberOfConfiguredChannels() { return 0; } /// /// Count how many channels we have (regardless if they are configured or not). /// /// Total number of channels public override int NumberOfChannels() { return 0; } public override bool SupportsAutoArm() { return true; } public override bool SupportsLevelTrigger() { return false; } public override bool SupportsMultipleEvents() { return true; } public override bool SupportsRealtime() { return false; } /// /// whether the DASbase actually controls the DAQ for modules /// in the case of TDAS, the modules actually are responsible for the DAQ and the /// rack is just a middleman /// this is relevant because if the DAQ is controlled by the base then the sample numbers /// should match for all modules. /// /// public override bool ControlsDAQ() { return false; } /// /// tell DAS to start sending data at specific rate /// /// How many samples per second to receive /// the amount of time to sleep between samples /// 0 is ok /// The function to call with information /// Whatever you want to pass along /// /// channels to operate on, added for /// 10572 implement SW side for single command streaming realtime /// void IRealTimeActions.RealTime(int samplesPerSec, int msBetweenSamples, ServiceCallback callback, object userData, bool allowMultipleSampleRealtime, int moduleIndex, ManualResetEvent stopEvent, byte[] channels, double aaf, int minCallbackUpdateTimeMs, bool UseUDPStreaming, string hostIPAddress) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } void IRealTimeActions.RealTimePolling(ServiceCallback callback, object userData, ManualResetEvent mre, byte[] channels) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } /// /// Stop sending real time data /// /// The function to call with information /// Whatever you want to pass along void IRealTimeActions.ExitRealTimeMode(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } void IRealTimeActions.RealTimeTiltPolling(ServiceCallback callback, object userData, ManualResetEvent stopEvent) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } /// /// Start an asynchronous flash erase on a single DAS. /// /// /// public void BeginFlashErase(ServiceCallback callback, object userData, bool DummyArm) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } /// /// Query a single DAS for flash erase progress and an errors that have occurred. /// /// The function to call with update information /// public void QueryFlashEraseStatus(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } /// /// Arm a single DAS now /// /// The function to call with information /// Whatever you want to pass along /// A unique GUID that this event will be tagged /// with public void ArmNow(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode, int maxNumberEvents, bool SysMode) { var info = new SDBAsyncInfo(callback, userData); if (null != ConfigData && ConfigData.Modules.Any()) { var saa = new SetArmAttribute(this); var postTriggerSamples = Convert.ToUInt64(ConfigData.Modules[0].PostTriggerSeconds * ConfigData.Modules[0].SampleRateHz); saa.SetValue(AttributeTypes.ArmAndEventAttributes.PostTriggerSamplesRequested, postTriggerSamples, true); saa.SyncExecute(); saa = new SetArmAttribute(this); var preTriggerSamples = 0UL; if (ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBuffer || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.a16_CircularBufferAndStreamSubSampleMode || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.RAMActive || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.MultipleEventRAMActive) { preTriggerSamples = Convert.ToUInt64(Math.Abs(ConfigData.Modules[0].PreTriggerSeconds * ConfigData.Modules[0].SampleRateHz)); } saa.SetValue(AttributeTypes.ArmAndEventAttributes.PreTriggerSamplesRequested, preTriggerSamples, true); saa.SyncExecute(); SetArmMode(ConfigData.Modules[0].RecordingMode); } try { var arm = new Arm(this); arm.SyncExecute(); //17812 DataPRO does not issue EnableFaultChecking when running with POWER PRO and a single DAS //UI code was setting this for non ethernet distributors DASArmStatus.IsArmed = true; SetDASArmStatus(); } catch (Exception ex) { info.Error(ex.Message, ex); return; } info.Success(); } public void PrepareForArmNow(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode, int maxNumberEvents, bool SysMode) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } void IArmActions.ReArm(ServiceCallback callback, object userData, bool autoArm, bool arm, bool repeatEnable) { var info = new SDBAsyncInfo(callback, userData); info.Error("NotSupported"); } public void PreparedArmNow(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode, int maxNumberEvents, bool SysMode) { var info = new SDBAsyncInfo(callback, userData); var saa = new SetArmAttribute(this); var postTriggerSamples = Convert.ToUInt64(ConfigData.Modules[0].PostTriggerSeconds * ConfigData.Modules[0].SampleRateHz); saa.SetValue(AttributeTypes.ArmAndEventAttributes.PostTriggerSamplesRequested, postTriggerSamples, true); saa.SyncExecute(); saa = new SetArmAttribute(this); var preTriggerSamples = 0UL; if (ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBuffer || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.a16_CircularBufferAndStreamSubSampleMode || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.RAMActive || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.MultipleEventRAMActive) { preTriggerSamples = Convert.ToUInt64(Math.Abs(ConfigData.Modules[0].PreTriggerSeconds * ConfigData.Modules[0].SampleRateHz)); } saa.SetValue(AttributeTypes.ArmAndEventAttributes.PreTriggerSamplesRequested, preTriggerSamples, true); saa.SyncExecute(); SetArmMode(ConfigData.Modules[0].RecordingMode); try { SetRTCBaseTime(); } catch (Exception ex) { APILogger.Log(ex); } try { var arm = new Arm(this); arm.SyncExecute(); } catch (Exception ex) { info.Error(ex.Message, ex); return; } info.Success(); } /// /// Arm multiple chained DAS now /// /// The function to call with information /// Whatever you want to pass along public void EnableFaultChecking(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); try { if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.EnableFaultChecking) && DFConstantsAndEnums.AllowEnableFaultCheckingOnS6DB) { var efc = new EnableFaultChecking(this); efc.SyncExecute(); } info.Success(); } catch (Exception ex) { APILogger.Log("failed to enable fault checking, ", ex); info.Error(ex.Message); } } public void CheckAlreadyLevelTriggered(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); LaunchAsyncWorker("SliceDB.CheckAlreadyLevelTriggered", AsyncCheckAlreadyLevelTriggered, info); } private void AsyncCheckAlreadyLevelTriggered(object asyncInfo) { var info = asyncInfo as SDBAsyncInfo; Debug.Assert(info != null, "info != null"); try { foreach (var m in ConfigData.Modules) { foreach (var ch in m.Channels) { if (!(ch is AnalogInputDASChannel analog)) continue; analog.AlreadyLevelTriggered = false; analog.MeasuredEULevelTriggerCheck = double.NaN; } } info.Success(); } catch (Exception ex) { info.Error(ex.Message, ex); } } /// /// Disarm the DAS /// /// The function to call with information /// Whatever you want to pass along public void Disarm(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.Arm)) { try { //14731 - Dont issue a Disarm to a S6DB that isn't armed var quats = new QueryArmAndTriggerStatus(this); quats.SyncExecute(); if (quats.IsArmed) { var disarm = new Disarm(this); disarm.SyncExecute(); } } catch (Exception) { } } info.Success(); } /// /// DisAutoArm the DAS /// /// The function to call with information /// Whatever you want to pass along public void DisAutoArm(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } /// /// Download the data specified in the WhatToDownload property /// /// The function to call with information /// Whatever you want to pass along public void Download(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } /// /// Cancel the current operation /// public void Cancel() { } /// /// Clear the cancel flag /// public void ClearCancel() { } /// /// Retrieve info about available events to download /// /// The function to call with information /// Whatever you want to pass along void IDownloadActions.QueryDownload(ServiceCallback callback, object userData, int eventIndex, TDASServiceSetupInfo setupInfo) { var info = new QueryDownloadAsyncInfo(callback, userData, eventIndex); LaunchAsyncWorker("Slice.QueryDownload", new WaitCallback(AsyncQueryDownload), info); } protected override void AsyncQueryDownload(object asyncInfo) { var info = asyncInfo as QueryDownloadAsyncInfo; // since we don't know exact how many XML attributes, modules or channels that's in the // configuration, we guess on the high end. // (44 per stored config + 4 + 3 per module + 3 per channel) * number of events // equals 44 + 4 + 30 + 90 = 168 per event const int StepsPerEvent = 168; try { var EventCount = new QueryTotalEventCount(this); EventCount.SyncExecute(); // 6 * modules + 44 var progress = new QueryDownloadProgress(info, StepsPerEvent * EventCount.Count, 1); // we'll also freshen up the cached event GUIDs // NOT IF WE ARE QUERYING A SPECIFIC GUID var eventGuids = new Guid[EventCount.Count]; var faultFlags = new ushort[EventCount.Count]; var armAttempts = new byte[EventCount.Count]; var extendedFaultIds = new List(); var dlReport = new DownloadReport(); var eventIdx = 0; if (0 > info.EventIndex) { dlReport.Events = new DownloadReport.EventInfo[1]; } //S6DB only can handle 1 event ... extendedFaultIds.Add(GetExtendedFaultFlags(0)); // the object to store it all in var eventInfo = new DownloadReport.EventInfo(); eventInfo.TestID = DFConstantsAndEnums.MADEUPEVENT_TESTID; eventInfo.Description = Constants.DUMMY_MOD_DESCRIP_S6DB; // Make a list for new modules and create module for on board temp readings var eventModules = new List() { CreateDummyModule() }; #region Slice6TiltSensor if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryTiltSensorData) && DASInfo.ActiveExternalTilts.Count > 0) { // Get Tilt Cals TiltSensorGet tiltSensorGet; int modArrayIndex = 1; foreach (var tiltInfo in DASInfo.ActiveExternalTilts) { tiltSensorGet = new TiltSensorGet(this, 600000) { Tilt_id = tiltInfo.TiltID, Sub_cmd = TiltSensorMif.TiltSensorEEPROM, Data_Offset = 0, Data_Length = 256 }; tiltSensorGet.SyncExecute(); var curMif = new Tilt_MIF(tiltSensorGet.Data); var tiltSensorDataPre = new short[] { curMif.PreEventADCAxis1, curMif.PreEventADCAxis2, curMif.PreEventADCAxis3 }; var mountOffsets = Test.Module.GetMountOffsetsOrTargetsFromAxisInfo( new float[] { curMif.MountOffsetAxis1, curMif.MountOffsetAxis2, curMif.MountOffsetAxis3 }, curMif.AxisToIgnore); var targetAxis = Test.Module.GetMountOffsetsOrTargetsFromAxisInfo( new float[] { curMif.TargetAngleAxis1, curMif.TargetAngleAxis2, curMif.TargetAngleAxis3 }, curMif.AxisToIgnore); var tiltAxes = Test.Module.GetTiltAxesFromAxisInfo( new string[] { curMif.AxisLabel1.ToString(), curMif.AxisLabel2.ToString(), curMif.AxisLabel3.ToString() }, new bool[] { curMif.InvertAxis1, curMif.InvertAxis2, curMif.InvertAxis3 }); var tiltDataEU = Test.Module.GetTiltDegreesEU( tiltSensorDataPre, curMif.GetTiltCalibrations(), tiltAxes, curMif.AxisToIgnore, mountOffsets ); var module = CreateDummyModule(); module.ModuleArrayIndex = modArrayIndex++; module.TiltSensorAxisXDegreesPre = tiltDataEU[0]; module.TiltSensorAxisYDegreesPre = tiltDataEU[1]; module.TiltSensorAxisZDegreesPre = tiltDataEU[2]; module.SystemID = curMif.SystemID; module.SystemLocation = curMif.Location; module.MountOffsetAxisOne = mountOffsets[0]; module.MountOffsetAxisTwo = mountOffsets[1]; module.TargetAxisOne = targetAxis[0]; module.TargetAxisTwo = targetAxis[1]; module.TargetAngleAxisX = curMif.TargetAngleAxis1; module.TargetAngleAxisY = curMif.TargetAngleAxis2; module.TargetAngleAxisZ = curMif.TargetAngleAxis3; module.AxisIgnored = curMif.AxisToIgnore; module.TiltAxes = tiltAxes; module.TiltID = tiltInfo.TiltID; module.TiltSerialNumber = curMif.SerialNumber; eventModules.Add(module); } } #endregion progress.Step(); eventInfo.Modules = eventModules.ToArray(); if (0 > info.EventIndex) { // store it in the object dlReport.Events[eventIdx] = eventInfo; } else { EventInfo.Events[eventIdx] = eventInfo; } if (info.EventIndex >= 0) { //only download if we are downloading a specific event, if index <0 we aren't downloading DownloadTemperatureCSV(info); } // now assigned the data to the public property if (0 > info.EventIndex) { SetEventInfo(dlReport); } SetEventFaultFlags(faultFlags); ((IDownload)this)?.SetExtendedFaultFlags(extendedFaultIds.ToArray()); SetEventGuids(eventGuids); SetEventArmAttemps(armAttempts); info.Success(); } catch (CanceledException) { info.Cancel(); } catch (Exception ex) { info.Error(ex.Message, ex); } } //private const int TEMPERATURE_CONFIG_CHANNEL_FIELD = 2; //private DFConstantsAndEnums.TempLogChannelBits GetFirstMatch(DFConstantsAndEnums.TempLogChannelBits config, DFConstantsAndEnums.TempLogChannelBits? bitToSkip) //{ // var flags = Enum.GetValues(typeof(DFConstantsAndEnums.TempLogChannelBits)).Cast().ToArray(); // foreach (var flag in flags) // { // if (null != bitToSkip && flag == (DFConstantsAndEnums.TempLogChannelBits)bitToSkip) { continue; } // if (config.HasFlag(flag)) { return flag; } // } // return 0; //} /// /// retrieves any Temp Log information and returns it to caller /// private void DownloadTemperatureCSV(object o) { var info = (QueryDownloadAsyncInfo)o; try { var qsa = new QuerySystemAttributeSLICE6DB(this) { Key = AttributeTypes.SystemAttributesSLICE6DB.S6DBbaseEnvTempLoggingConfig, }; qsa.SyncExecute(); if (!(qsa.Value is ushort[] config)) { return; } var tempConfig = new TemperatureConfig(config); var channels = tempConfig.GetChannelsArray(); var channel1 = channels.Length > 0 ? channels[0] : -1; var channel2 = channels.Length > 1 ? channels[1] : -1; var query = new QueryTempLogFile(this); query.SyncExecute(); var timeStamps = new List(); var sensor1 = new List(); var sensor2 = new List(); foreach (var tuple in query.TempData) { timeStamps.Add(tuple.Item1); sensor1.Add(tuple.Item2); sensor2.Add(tuple.Item3); } var data = new ServiceCallbackData() { Status = ServiceCallbackData.CallbackStatus.NewData }; data.UserData = info.userData; data.SetNewTemperatureData(new ServiceCallbackData.TemperatureData() { Sensor1 = sensor1.ToArray(), Sensor2 = sensor2.ToArray(), Timestamps = timeStamps.ToArray(), Channel1 = channel1, Channel2 = channel2 }); info.callback.Invoke(data); info.Success(); } catch (Exception ex) { info.Error(ex.Message, ex); } } private DASModule CreateDummyModule() { // take the module from the stored config return new DASModule() { Description = DTS.Common.Constants.DUMMY_MOD_DESCRIP_S6DB, NumberOfSamples = 0, RequestedPostTriggerSeconds = 0, RequestedPreTriggerSeconds = 0, PostTriggerSeconds = 0, PreTriggerSeconds = 0, RecordingMode = 0, SampleRateHz = 0, StartRecordSampleNumber = 0, TriggerSampleNumbers = new ulong[] { 0 }, OwningDAS = this, StartRecordTimestampSec = 0, StartRecordTimestampNanoSec = 0, TriggerTimestampSec = 0, TriggerTimestampNanoSec = 0, PTPMasterSync = false, SystemID = string.Empty, SystemLocation = string.Empty, TiltSensorAxisXDegreesPre = double.NaN, TiltSensorAxisYDegreesPre = double.NaN, TiltSensorAxisZDegreesPre = double.NaN, TiltSensorAxisXDegreesPost = double.NaN, TiltSensorAxisYDegreesPost = double.NaN, TiltSensorAxisZDegreesPost = double.NaN, TemperatureLocation1Pre = float.NaN, TemperatureLocation2Pre = float.NaN, TemperatureLocation3Pre = float.NaN, TemperatureLocation4Pre = float.NaN, TemperatureLocation1Post = float.NaN, TemperatureLocation2Post = float.NaN, TemperatureLocation3Post = float.NaN, TemperatureLocation4Post = float.NaN, InputVoltage = float.NaN, BatteryVoltage = float.NaN, Channels = new AnalogInputDASChannel[0], }; } /// /// Figure out if events have been downloaded /// /// The function to call with information /// Whatever you want to pass along public void QueryDownloadedStatus(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } /// /// Update the recorded trigger sample numbers in HW /// /// The function to call with information /// Whatever you want to pass along public void SetTriggerSampleNumbers(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } #region Trigger check //13820 With the S6 ATD and a SLICE PRO system in the setup, consistently see Trigger Check Fail private void AsyncPreStartTriggerCheckSLICE6DB(object o) { var info = (SDBAsyncInfo)o; try { //11012 fix trigger check in "status line check", "arm checklist", and "arm" for slice6 db //handle a non latched trigger that has already pulsed on a SLICE6DB //by setting to triggered, if we read the trigger and it's not triggered presumably the hardware is shorted var ssi = new SetSwitchImmediate(this); ssi.DeviceID = 0x00; ssi.Switch = (byte)Switches.BaseSwitches.TriggerOut; ssi.SwitchText = Switches.BaseSwitches.TriggerOut.ToString(); ssi.Setting = 0x01; ssi.SyncExecute(); ssi.Setting = 0x00; ssi.SyncExecute(); // wait for one shot //Per LP and MS, the max of the cap on SP DB is 2.4, so we should be using 3s for safety reasons on one shot //this had previously been 1.7 for S6DB only Thread.Sleep(DFConstantsAndEnums.OneShotWaitTimeMs); } catch (Exception ex) { APILogger.Log(ex); info.Error(ex.Message); return; } info.Success(); } //13820 With the S6 ATD and a SLICE PRO system in the setup, consistently see Trigger Check Fail protected virtual void AsyncPostStartTriggerCheckSLICE6DB(object o) { var info = (SDBAsyncInfo)o; var query = new InitializeHardwareLines(this); try { //with the SLICE6DB, it will pulse high the trigger out when it recongizes a trigger, however this is a one time pulse //so if this has already happened, the trigger will remain low (not shorted) when we manually force it to shorted //per issue 11012 try { query.SyncExecute(); } catch (Exception ex) { //apparently IHL throws an exception if it's shorted, so handle this silently as a known thing //log if it's another exception if (ex.Message.ToLower().Contains("shorted")) { SetDASArmStatus(new ArmStatus() { IsArmed = true, IsTriggered = true }, true); info.Error("TriggerInputShorted"); return; } } } catch (Exception ex) { InitializeHardwareLines.Log(ex, query); info.Error(ex.Message); return; } SetDASArmStatus(new ArmStatus() { IsArmed = true, IsTriggered = false }, true); info.Success(); } private void AsyncStartTriggerCheckSLICE6DB(object o) { var info = (SDBAsyncInfo)o; //13820 With the S6 ATD and a SLICE PRO system in the setup, consistently see Trigger Check Fail //S6DB waits until PostStartTriggerCheck to check status SetDASArmStatus(new ArmStatus() { IsArmed = true, IsTriggered = false }, true); info.Success(); } public void StartTriggerCheck(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); LaunchAsyncWorker("SliceDB.StartTriggerCheck", AsyncStartTriggerCheckSLICE6DB, info); } public void DoTriggerCheck(ServiceCallback callback, object userData) { //this was supposed to be async, why is it executing synchronously? I dont' know //but I'm preserving it as is [dtm] 2019-05-23 SDBAsyncInfo info = null; if (null != callback) { info = new SDBAsyncInfo(callback, userData); } DoTriggerCheckSync(); info?.Success(); } /// /// do the synchronous version of trigger check /// public void DoTriggerCheckSync() { if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines)) { var query = new InitializeHardwareLines(this) { LogCommands = true }; try { try { query.SyncExecute(); } catch (Exception ex) { //IHL can throw an exception if the trigger is shorted, we don't want this //but if it's anything else go and rethrow the exception if (!ex.Message.ToLower().Contains("shorted")) { throw; } } var oldStatus = DASArmStatus; var status = new ArmStatus { IsTriggered = query.TriggerInputShorted, IsArmed = query.TriggerInputShorted || query.StartRecordShorted }; //10601 Trigger Check can miss the pulse generated by HW //we have to latch the trigger status for the S6DB ... since it does one shot pulse if (null != oldStatus) { status.IsArmed = status.IsArmed || oldStatus.IsArmed; status.IsTriggered = status.IsTriggered || oldStatus.IsTriggered; } status.IsTriggerShorted = status.IsTriggered; status.IsStartShorted = status.IsArmed; SetDASArmStatus(status, true); } catch (Exception ex) { APILogger.Log("Failed to get trigger state", ex); InitializeHardwareLines.Log(ex, query); } } } public void DoStartCheck(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines)) { var query = new InitializeHardwareLines(this); try { query.SyncExecute(); var status = new ArmStatus { IsArmed = true, IsRecording = query.StartRecordShorted || query.TriggerInputShorted }; SetDASArmStatus(status, true); } catch (Exception ex) { InitializeHardwareLines.Log(ex, query); } } info.Success(); } public void CancelTriggerCheck(ServiceCallback callback, object userData) { var info = new SDBAsyncInfo(callback, userData); info.Success(); } public override bool CheckAAF(float rate) { return true; } /// /// the UDP settings to broadcast auto arm status to on auto arm boot /// 17583 Monitor Test UI /// public string AutoArmUDPSetting { get; set; } = "239.1.2.3:8504"; /// /// /// Auto Arm a single DAS now /// /// The function to call with information /// Whatever you want to pass along /// A unique GUID that this event will be tagged /// with /// /// /// /// void IArmActions.AutoArmNow(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode, uint diagnosticsDelayMs, int maxNumberEvents, bool repeatEnable, bool preserveDiagnostics) { var info = new SDBAsyncInfo(callback, userData); try { SetRTCBaseTime(); } catch (Exception ex) { APILogger.Log(ex); } if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmUDPSetting)) { try { var set = new SetSystemAttributeSLICE6DB(this); set.SetValue(AttributeTypes.SystemAttributesSLICE6DB.AUTOARMUDP_ADDRESS, AutoArmUDPSetting, true); set.SyncExecute(); } catch (Exception ex) { APILogger.Log(ex); } } info.Success(); } public override bool SupportsTimeSynchronization => true; private readonly Dictionary SLICE6DB_MinimumProtocols = new Dictionary(); public override void InitMinProto() { // SLICE 6 DB Protocol Limitations SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.BaseSystemTime] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SLICE2_OneWireID] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.HardwareRevision] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.HardwareConfiguration] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.EventFaultFlags] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.EventArmAttempts] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryActualSampleRateImmediate] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.VoltageSysAttributes] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryArmAndTriggerStatus_VoltageReadings] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.BaseCalibrationDate] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.IgnoreShortedStartEvent] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.ResetAttributeStore] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MeasureBaseDiagnosticChannel] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.InSliceTemperatureCPre] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.FileData] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.PTPSyncStatus] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetClockSyncConfig] = SLICE6DB.MIN_PROTOCOL_VER; // SLICE_DB Protocol Limitations SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.Arm] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.EnableFaultChecking] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.OnOverride] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.OMAP_GPIO] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryBatteryVoltage] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.Diagnostics] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StartRealtimeStream] = SLICE6DB.MIN_PROTOCOL_VER; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryEthernetMacTable] = SLICE6DB.MIN_PROTOCOL_QUERYMACTABLE; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryTempLogFile] = SLICE6DB.MIN_PROTOCOL_QUERYTEMPLOGFILE; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryTiltSensorData] = SLICE6DB.MIN_PROTOCOL_TILT; SLICE6DB_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryExternalTiltInfo] = SLICE6DB.MIN_PROTOCOL_TILT; MinimumProtocols = SLICE6DB_MinimumProtocols; } #endregion #region IClockSyncActions public virtual void SetClockSyncConfig(ServiceCallback callback, object userData, ClockSyncProfile profile) { var info = new SliceServiceAsyncInfo(callback, userData) { functionData = profile }; var packet = new SetClockSyncConfigPacket(info); LaunchAsyncWorker("Slice.SetClockSyncConfig", AsyncSetClockSyncConfig, packet); } public virtual void GetClockSyncStatus(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); var packet = new GetClockSyncStatusPacket(info); LaunchAsyncWorker("Slice.GetClockSyncStatus", AsyncGetClockSyncStatus, packet); } public virtual void GetPTPDomainID(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); var packet = new GetPTPDomainIDPacket(info); LaunchAsyncWorker("Slice.GetPTPDomainID", AsyncGetPTPDomainID, packet); } public virtual void SetPTPDomainID(ServiceCallback callback, object userData, byte domainID) { var info = new SliceServiceAsyncInfo(callback, userData) { functionData = domainID }; var packet = new SetPTPDomainIDPacket(info); LaunchAsyncWorker("Slice.SetPTPDomainID", AsyncSetPTPDomainID, packet); } #endregion protected override void GetTiltResults(ArmCheckResults dasResults) { dasResults.TiltSensorDataPre = null; dasResults.TiltDegrees = null; dasResults.IndexedTiltDegrees = new Dictionary(); dasResults.IndexedTiltSensorDataPre = new Dictionary(); if (DASInfo.ActiveExternalTilts.Count > 0) { if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryTiltSensorData)) { // Get Tilt Cals //var tiltMifs = new Dictionary(); TiltSensorGet tiltSensorGet; foreach (var tiltInfo in DASInfo.ActiveExternalTilts) { tiltSensorGet = new TiltSensorGet(this, 600000) { Tilt_id = tiltInfo.TiltID, Sub_cmd = TiltSensorMif.TiltSensorEEPROM, Data_Offset = 0, Data_Length = 256 }; tiltSensorGet.SyncExecute(); var curMif = new Tilt_MIF(tiltSensorGet.Data); tiltSensorGet = new TiltSensorGet(this, 600000) { Sub_cmd = TiltSensorMif.TiltSensorData, Tilt_id = tiltInfo.TiltID }; tiltSensorGet.SyncExecute(); short[] axisADCData = new short[3]; axisADCData[0] = tiltSensorGet.Channel1ValueAdc; axisADCData[1] = tiltSensorGet.Channel2ValueAdc; axisADCData[2] = tiltSensorGet.Channel3ValueAdc; dasResults.IndexedTiltSensorDataPre[tiltInfo.TiltID] = axisADCData; dasResults.IndexedTiltDegrees[tiltInfo.TiltID] = Test.Module.GetTiltDegreesEU(axisADCData, curMif.GetTiltCalibrations(), Test.Module.GetTiltAxesFromAxisInfo( new string[] { curMif.AxisLabel1.ToString(), curMif.AxisLabel2.ToString(), curMif.AxisLabel3.ToString() }, new bool[] { curMif.InvertAxis1, curMif.InvertAxis2, curMif.InvertAxis3 }), curMif.AxisToIgnore, Test.Module.GetMountOffsetsOrTargetsFromAxisInfo( new float[] { curMif.MountOffsetAxis1, curMif.MountOffsetAxis2, curMif.MountOffsetAxis3 }, curMif.AxisToIgnore) ); } } } } } }