This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,721 @@
using DTS.Common.Interface.Channels;
using DTS.Common.Interface.DASFactory;
using DTS.Common.Interface.DASFactory.Config;
using DTS.Common.Interface.Sensors;
using DTS.Common.Interface.StatusAndProgressBar;
using DTS.Common.Utilities.Logging;
using DTS.DASLib.Service.StateMachine.StatusAndParameters.Configure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace DTS.DASLib.Service.StateMachine
{
public class ConfigureStatusInformation : IStatusInfo
{
/// <summary>
/// all possible status that can be relayed to consumers
/// </summary>
public enum StatusValues
{
ApplyingConfiguration,
AutoResolvingChannels,
ManuallyResolvedChannels,
Completed,
Cancelling,
Cancelled,
ChannelOutOfPosition,
NoChannelsAssigned,
AllChannelsResolved,
EIDNotFound,
ApplyConfigFailed,
AppliedConfiguration,
PrepareForDiagnostics,
PrepareForDiagnosticsFailed,
PrepareForDiagnosticsSuccess,
LowPower,
LowPowerSuccess,
LowPowerFailure
}
/// <summary>
/// no channels are currently assigned
/// </summary>
public bool NoChannelsAssigned { get; internal set; } = true;
/// <summary>
/// all channels to be resolved are resolved
/// </summary>
public bool AllChannelsResolved { get; internal set; } = false;
/// <summary>
/// one or more channels are out of position with respect to how
/// they requested to be positioned (they are on a different channel than they were specified to be on)
/// </summary>
public bool ChannelsOutOfPosition { get; internal set; } = false;
/// <summary>
/// all units that were to be configured were configured
/// </summary>
public bool HaveAppliedConfigAllUnits { get; set; } = false;
/// <summary>
/// signals a cancel request
/// </summary>
public ManualResetEvent CancelEvent = new ManualResetEvent(false);
/// <summary>
/// signals when work is finished
/// </summary>
public ManualResetEvent DoneEvent = new ManualResetEvent(false);
/// <summary>
/// action to take on completion of work
/// </summary>
public ActionCompleteDelegate CompleteAction { get; set; }
/// <summary>
/// action to take on progress notification
/// </summary>
public SetProgressValueDelegate ProgressAction { get; set; }
/// <summary>
/// action to take on a status notification
/// </summary>
public StatusIntDelegate StatusAction { get; set; }
/// <summary>
/// action to take on extended status notification
/// </summary>
public StatusExIntDelegate StatusExAction { get; set; }
/// <summary>
/// holds references to all units which were successfully configured
/// </summary>
public IDASCommunication[] UnitsConfigured { get; set; } = new IDASCommunication[0];
/// <summary>
/// task for turning excitation on/off, used for monitoring task or interrupting
/// </summary>
private Task _ExcitationTask = null;
/// <summary>
/// task for applying configuration, used for monitoring task or interrupting
/// </summary>
private Task _ApplyConfigTask = null;
/// <summary>
/// used to canel running task
/// returns when task is cancelled or completed
/// </summary>
/// <returns></returns>
public async Task Cancel()
{
CancelEvent.Set();
StatusAction?.Invoke((int)StatusValues.Cancelling);
//simulate time spent waiting for cancel to be acknowledged
Thread.Sleep(100);
DoneEvent.WaitOne();
StatusAction?.Invoke((int)StatusValues.Cancelled);
}
/// <summary>
/// turns on power (if requested and appropriate)
/// </summary>
private void PrepareForDiagnostics()
{
var param = States.Instance.Configure.Status.ConfigureParameters;
var status = States.Instance.Configure.Status.ConfigureStatus;
var global = States.Instance.Configure.Status.GlobalStatusInformation;
var dasFactory = States.Instance.Configure.DASFactory;
//make sure we have some units to turn on, if not fail task
if (!status.UnitsConfigured.Any())
{
StatusAction?.Invoke((int)StatusValues.PrepareForDiagnosticsFailed);
return;
}
ProgressAction?.Invoke(0D);
StatusAction?.Invoke((int)StatusValues.PrepareForDiagnostics);
//record if any units fail to turn on excitation
var bPassed = true;
var mre = new ManualResetEvent(false);
try
{
using (var diagnosticsService = new DiagnosticsService())
{
var units = status.UnitsConfigured.ToList();
diagnosticsService.PrepareForDiagnostics(units,
PrePostResults.PreEventDiagnosticsResult,
param.SampleRateLookup,
param.AAFRateLookup,
(ServiceBase.CallbackData data) =>
{
switch (data.Status)
{
case ServiceBase.CallbackData.CallbackStatus.Success:
StatusExAction?.Invoke((int)StatusValues.PrepareForDiagnosticsSuccess, data.Target);
global.AddUnitAtHighPower(data.Target);
break;
case ServiceBase.CallbackData.CallbackStatus.Failure:
bPassed = false;
StatusExAction?.Invoke((int)StatusValues.PrepareForDiagnosticsFailed, data.Target);
break;
case ServiceBase.CallbackData.CallbackStatus.AllFinished:
mre.Set();
break;
}
},
units);
}
}
catch (Exception ex)
{
bPassed = false;
throw ex;
}
var timeWaited = 0;
while (!mre.WaitOne(PREPARE_SPIN_TIME, false))
{
timeWaited += PREPARE_SPIN_TIME;
ProgressAction?.Invoke(100D * timeWaited / EXPECTED_PREPARE_TIME);
}
if (bPassed)
{
StatusAction?.Invoke((int)StatusValues.PrepareForDiagnosticsSuccess);
States.Instance.ConfigureStart.Status.GlobalStatusInformation.ExcitationOn = true;
}
else
{
StatusAction?.Invoke((int)StatusValues.PrepareForDiagnosticsFailed);
}
}
private const int PREPARE_SPIN_TIME = 200;
private const int EXPECTED_PREPARE_TIME = 8000;
/// <summary>
/// lock used to control thread access to shared resources
/// [like UnitsConfigured]
/// </summary>
private static readonly object MyLock = new object();
private void AddConfiguredDevice(IDASCommunication device)
{
lock (MyLock)
{
if (UnitsConfigured.Contains(device)) { return; }
var list = new List<IDASCommunication>();
list.AddRange(UnitsConfigured);
list.Add(device);
UnitsConfigured = list.ToArray();
}
StatusExAction?.Invoke((int)StatusValues.AppliedConfiguration, device);
}
/// <summary>
/// Turns off excitation, returns immediately
/// </summary>
public void TurnOffExcitation()
{
var param = States.Instance.ConfigureStart.Status.ConfigureParameters;
//reset the flag that got us here
param.TurnOffExcitation = false;
var status = States.Instance.ConfigureStart.Status.ConfigureStatus;
var dasFactory = States.Instance.ConfigureStart.DASFactory;
_ExcitationTask = Task.Run(() =>
{
StatusAction?.Invoke((int)StatusValues.LowPower);
var units = dasFactory.GetDASList();
var anyFailed = false;
try
{
var mre = new ManualResetEvent(false);
using (var service = new ArmingService())
{
service.EnterLowPowerMode(units, (ServiceBase.CallbackData data) =>
{
switch (data.Status)
{
case ServiceBase.CallbackData.CallbackStatus.Success:
StatusExAction?.Invoke((int)StatusValues.LowPowerSuccess, data.Target);
break;
case ServiceBase.CallbackData.CallbackStatus.AllFinished:
mre.Set();
break;
case ServiceBase.CallbackData.CallbackStatus.Failure:
anyFailed = true;
StatusExAction?.Invoke((int)StatusValues.LowPowerFailure, data.Target);
break;
}
}, units);
}
mre.WaitOne();
}
catch (Exception ex)
{
APILogger.Log(ex);
}
//if any failed to turn off record the error
//if all turned off, then set the global status param that excitation is now known off
if (anyFailed)
{
StatusAction?.Invoke((int)StatusValues.LowPowerFailure);
}
else
{
States.Instance.ConfigureStart.Status.GlobalStatusInformation.ExcitationOn = false;
StatusAction?.Invoke((int)StatusValues.LowPowerSuccess);
}
StatusAction?.Invoke((int)StatusValues.Completed);
CompleteAction?.Invoke();
DoneEvent.Set();
});
}
/// <summary>
/// starts ApplyConfig process, returns immediately
/// </summary>
public void ApplyConfig()
{
DoneEvent.Reset();
var param = States.Instance.ConfigureStart.Status.ConfigureParameters;
if (param.TurnOffExcitation)
{
TurnOffExcitation();
return;
}
var unitsToConfigure = param.UnitsToConfigure.ToList();
var dasFactory = States.Instance.ConfigureStart.DASFactory;
_ApplyConfigTask = Task.Run(() =>
{
//the user could just be turning on power, in which case the configuration is already set
//if the flag for set configuration is set, then set the configuration, otherwise don't
if (param.SetConfiguration)
{
HaveAppliedConfigAllUnits = false;
StatusAction?.Invoke((int)StatusValues.ApplyingConfiguration);
//check if we are supposed to configure a unit, but it's not available
//mark it failed if the unit is not available
var units = dasFactory.GetDASList();
foreach (var unit in unitsToConfigure)
{
if (!units.Contains(unit))
{
unitsToConfigure.Remove(unit);
StatusExAction?.Invoke((int)StatusValues.ApplyConfigFailed, unit);
}
}
var mre = new ManualResetEvent(false);
if (unitsToConfigure.Any())
{
using (var configService = new ConfigurationService())
{
configService.SetConfiguration(unitsToConfigure, param.DoStrictCheck, param.EventConfig,
(data) =>
{
switch (data.Status)
{
case ServiceBase.CallbackData.CallbackStatus.AllFinished:
mre.Set();
break;
case ServiceBase.CallbackData.CallbackStatus.Progress:
ProgressAction?.Invoke(data.ProgressValue);
break;
case ServiceBase.CallbackData.CallbackStatus.Failure:
StatusExAction?.Invoke((int)StatusValues.ApplyConfigFailed, data.Target,
data.ErrorMessage, data.ErrorException);
break;
case ServiceBase.CallbackData.CallbackStatus.Success:
AddConfiguredDevice(data.Target);
break;
}
}, unitsToConfigure,
param.ErrorRequiringActionAction,
param.DummyConfig,
param.MaxAAF,
param.ConfigureDigitalOutputs,
param.TurnOffAAFRealtime,
param.DSPFilterType,
param.DiscardDiagnostics);
}
}
mre.WaitOne();
//check that all the units that should have been configured were
var allConfigured = Array.TrueForAll(param.UnitsToConfigure, d => UnitsConfigured.Contains(d));
HaveAppliedConfigAllUnits = allConfigured;
}
//finally turn on power UNLESS the user has specified not to (most likely by pressing "Low Power" button)
//but also potentially by a property setting
if (!CancelEvent.WaitOne(1, false))
{
if (param.PrepareForDiagnostics && !param.SkipTurnOnPower)
{
PrepareForDiagnostics();
}
CompleteAction?.Invoke();
}
StatusAction?.Invoke((int)StatusValues.Completed);
DoneEvent.Set();
});
}
/// <summary>
/// holds channels that are not resolved for one reason or another
/// </summary>
private readonly List<GroupChannelWithMeta> _unresolvedChannels = new List<GroupChannelWithMeta>();
/// <summary>
/// holds channels that are now resolved/assigned
/// </summary>
private readonly List<GroupChannelWithMeta> _resolvedChannels = new List<GroupChannelWithMeta>();
private bool IsUnresolved(IGroupChannel ch)
{
return _unresolvedChannels.Exists(channel => channel.Channel == ch);
}
private bool IsResolved(IGroupChannel ch)
{
return _resolvedChannels.Exists(channel => channel.Channel == ch);
}
private void AddResolvedChannel(IGroupChannel channel,
IDASChannel hwChannel,
bool eidOutOfPlace,
ConfigureStatusParameters param,
IDictionary<IDASChannel, IDASCommunication> lookupChannelToDAS,
ISensorData sd,
bool missingEID)
{
//remove any possible duplicates
_resolvedChannels.RemoveAll(ch => ch.Channel == channel);
_unresolvedChannels.RemoveAll(ch => ch.Channel == channel);
var meta = new GroupChannelWithMeta()
{
Channel = channel,
ChannelConflict = false,
ConflictingChannel = null,
DASChannel = hwChannel,
EIDOutOfPlace = eidOutOfPlace,
HWChannelIncompatible = false,
MissingID = missingEID,
MissingSensor = false
};
_resolvedChannels.Add(meta);
//set the hardware in the group if needed
var includedHardware = channel.Group.IncludedHardware.ToList();
var hwId = param.GetDatabaseIdAction(lookupChannelToDAS[hwChannel]);
if (!includedHardware.Contains(hwId))
{
includedHardware.Add(hwId);
}
channel.Group.SetIncludedHardware(includedHardware.ToArray());
//set the calibration
if (hwChannel is AnalogInputDASChannel aic)
{
foreach (var e in sd.SupportedExcitation)
{
if (!aic.IsSupported(e))
{
continue;
}
var sc = param.GetCalibrationAction(sd, e);
if (null == sc) { continue; }
param.SetSensorCalibrationAction(sd, sc);
break;
}
}
}
private void AddUnresolvedChannel(IGroupChannel ch,
bool bChannelConflict,
IGroupChannel conflictingChannel,
bool EIDOutOfPlace,
bool hwChannelIncompatible,
bool hwNotFound,
bool missingId,
bool missingSensor)
{
//remove any possible duplicates
_resolvedChannels.RemoveAll(channel => channel.Channel == ch);
_unresolvedChannels.RemoveAll(channel => channel.Channel == ch);
var meta = new GroupChannelWithMeta()
{
Channel = ch,
ChannelConflict = bChannelConflict,
ConflictingChannel = conflictingChannel,
DASChannel = null,
EIDOutOfPlace = EIDOutOfPlace,
HWChannelIncompatible = hwChannelIncompatible,
HWNotFound = hwNotFound,
MissingID = missingId,
MissingSensor = missingSensor
};
_unresolvedChannels.Add(meta);
}
private bool IsHWChannelResolved(IDASChannel channel)
{
return _resolvedChannels.Exists(ch => ch.DASChannel == channel);
}
public void ManuallyUnresolveChannel(IGroupChannel channel)
{
if (!IsResolved(channel))
{
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.ChannelNotAssigned);
}
var resolvedChannel = _resolvedChannels.First(ch => ch.Channel == channel);
if (resolvedChannel.AssignedByEID)
{
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.EID_Locked);
}
AddUnresolvedChannel(channel, false, null, false, false, resolvedChannel.HWNotFound, resolvedChannel.MissingID,
false);
}
public void ManuallyResolveChannel(IGroupChannel channel, IDASChannel hardwareChannel)
{
var param = States.Instance.ConfigureStart.Status.ConfigureParameters;
GetIdToHardwareLookup(param, out var lookupIDToHardware, out var lookupChannelToDAS,
out var lookupDAStoChannel);
if (channel.IsBlank())
{
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.BlankChannel);
}
if (channel.IsDisabled)
{
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.ChannelDisabled);
}
if (channel.SensorId < 0)
{
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.NoSensor);
}
var sd = param.GetSensorAction(channel);
if (null == sd)
{
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.SensorNotFound);
}
var compatible = IsSensorHwCompatible(hardwareChannel, sd);
if (SensorCompatiblilityResponse.Compatible != compatible)
{
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.IncompatibleHardware);
}
//alright, looks ok ... unless there's something on that channel already ...
if (IsHWChannelResolved(hardwareChannel))
{
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.ChannelAlreadyAssigned);
}
//ok, well make sure it's we didn't find the EID for the channel already on a channel, if so ... it's locked on
//that channel
bool bFoundEID = false;
if (IsResolved(channel))
{
var resolvedChannel = _resolvedChannels.First(ch => ch.Channel == channel);
if (resolvedChannel.AssignedByEID)
{
if (resolvedChannel.DASChannel != hardwareChannel)
{
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.EID_Locked);
}
//nothing to do ...
bFoundEID = true;
}
}
//determine if we should have found an EID and didn't
var bMissingEID = !string.IsNullOrWhiteSpace(sd.EID) && !bFoundEID;
//if we are missing an ID, and aren't allowed to assign to a channel without an id, then don't allow it
if (bMissingEID && !param.AllowSensorIdToBlankChannel)
{
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.EIDRequiredAndMissing);
}
//add as a resolved channel
AddResolvedChannel(channel, hardwareChannel, false, param, lookupChannelToDAS, sd, bMissingEID);
AllChannelsResolved = _unresolvedChannels.Any();
}
/// <summary>
/// thrown by manually resolve/unresolve functions
/// </summary>
public class InvalidAssignmentException : Exception
{
public enum Reasons
{
BlankChannel,
NoSensor,
ChannelDisabled,
SensorNotFound,
IncompatibleHardware,
ChannelAlreadyAssigned,
EID_Locked, //sensor is already locked by EID to a different channel
EIDRequiredAndMissing,
ChannelNotAssigned
}
public IGroupChannel GroupChannel { get; private set; }
public Reasons Reason { get; private set; }
public InvalidAssignmentException(IGroupChannel channel, Reasons reason)
: base($"{reason.ToString()} - {channel}")
{
Reason = reason;
GroupChannel = channel;
}
}
/// <summary>
/// sensor is not compatible with hardware, but maybe in the future we'll want to know why
/// even though right now it's just "hw incompatible"
/// </summary>
internal enum SensorCompatiblilityResponse
{
Compatible,
DigitalInputNotSupportedOnHWChannel,
DigitalInputModeNotSupportedOnHWChannel,
BridgeModeNotSupportedOnHWChannel,
SquibFireModeNotSupportedOnHWChannel,
NoSupportedExcitationOnHWChannel
}
/// <summary>
/// check if sensor can run on the channel in question
/// checks excitation, bridge, sensor type, etc
/// </summary>
/// <param name="hwid"></param>
/// <param name="sd"></param>
/// <returns></returns>
private SensorCompatiblilityResponse IsSensorHwCompatible(IDASChannel hwChannel, ISensorData sd)
{
switch (hwChannel)
{
case AnalogInputDASChannel aic:
if (aic.SupportedBridges.Contains(sd.Bridge))
{
if (aic.DigitalInputChannel)
{
if (!sd.IsDigitalInput())
{
//hardware is digital, sensor is not, it's not compatible
return SensorCompatiblilityResponse.DigitalInputNotSupportedOnHWChannel;
}
else if (!aic.SupportedDigitalInputModes.Contains(sd.InputMode))
{
//sensor and hardware are digital, but the input mode is not supported
return SensorCompatiblilityResponse.DigitalInputModeNotSupportedOnHWChannel;
}
}
else
{
var param = States.Instance.ConfigureStart.Status.ConfigureParameters;
var excitationPassed = (from e in sd.SupportedExcitation
where aic.SupportedExcitation.Contains(e)
select param.GetCalibrationAction(sd, e)).Any(sc => null != sc);
if (!excitationPassed)
{
//there's no supported excitation match
return SensorCompatiblilityResponse.NoSupportedExcitationOnHWChannel;
}
}
}
else
{
//the hardware does not support the bridge mode of the sensor ...
return SensorCompatiblilityResponse.BridgeModeNotSupportedOnHWChannel;
}
break;
case OutputSquibChannel _:
var squibChannel = (OutputSquibChannel)hwChannel;
if (!sd.IsSquib())
{
//hardware channel is squib, sensor is not
return SensorCompatiblilityResponse.BridgeModeNotSupportedOnHWChannel;
}
else if (!squibChannel.SupportedSquibFireModes.Contains(sd.SquibFireMode))
{
//hardware and sensor are squib, but fire mode not supported by hardware
return SensorCompatiblilityResponse.SquibFireModeNotSupportedOnHWChannel;
}
break;
case OutputTOMDigitalChannel _:
if (!sd.IsDigitalOutput())
{
//hardware channel is digital output, sensor is not
return SensorCompatiblilityResponse.BridgeModeNotSupportedOnHWChannel;
}
break;
}
return SensorCompatiblilityResponse.Compatible;
}
/// <summary>
/// returns sensor EID to hardware channel mapping as determined from connected units
/// </summary>
/// <param name="param"></param>
/// <param name="lookupChannelToDAS">hardware channel to IDASCommunication</param>
/// <param name="lookupIDToHardware">eid to hardware channel</param>
/// <returns></returns>
private void GetIdToHardwareLookup(ConfigureStatusParameters param,
out IDictionary<string, IDASChannel> lookupIDToHardware,
out IDictionary<IDASChannel, IDASCommunication> lookupChannelToDAS,
out IDictionary<int, IDictionary<int, IDASChannel>> lookupDASToChannel
)
{
lookupIDToHardware = new Dictionary<string, IDASChannel>();
lookupChannelToDAS = new Dictionary<IDASChannel, IDASCommunication>();
lookupDASToChannel = new Dictionary<int, IDictionary<int, IDASChannel>>();
foreach (var unit in param.UnitsToConfigure)
{
//why is there no config data?
if (null == unit.ConfigData)
{
continue;
}
var dasid = param.GetDatabaseIdAction(unit);
if (!lookupDASToChannel.ContainsKey(dasid))
{
lookupDASToChannel.Add(dasid, new Dictionary<int, IDASChannel>());
}
foreach (var module in unit.ConfigData.Modules)
{
foreach (var channel in module.Channels)
{
lookupChannelToDAS[channel] = unit;
lookupDASToChannel[dasid][channel.Number] = channel;
if (null != channel.IDs && channel.IDs.Length > 0)
{
var id = channel.IDs[0].ID;
if (!string.IsNullOrWhiteSpace(id))
{
lookupIDToHardware[id] = channel;
}
}
}
}
}
}
/// <summary>
/// resets all status to defaults
/// </summary>
public void Reset()
{
NoChannelsAssigned = true;
AllChannelsResolved = false;
ChannelsOutOfPosition = false;
HaveAppliedConfigAllUnits = false;
StatusAction = null;
CompleteAction = null;
ProgressAction = null;
UnitsConfigured = new IDASCommunication[0];
_unresolvedChannels.Clear();
_resolvedChannels.Clear();
_ExcitationTask = null;
_ApplyConfigTask = null;
}
}
}

View File

@@ -0,0 +1,988 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Threading;
using System.Xml.Serialization;
using System.IO;
using System.Diagnostics;
using DTS.Common.Utilities.Logging;
using DTS.DASLib.Command.SLICE;
using DTS.DASLib.Command;
using DTS.DASLib.Service;
using DTS.Slice.Service;
using DTS.Common.DAS.Concepts;
using DTS.Common.DASResource;
using DTS.Common.Enums;
using DTS.Common.ICommunication;
using DTS.Common.Enums.Sensors;
using DTS.Common.Interface.Connection;
using DTS.Common.Interface.DASFactory.Download;
using DTS.Common.Enums.DASFactory;
using DTS.Common.Interface.DASFactory;
namespace DTS.DASLib.Service
{
public partial class TDAS<T> : Communication<T>,
IDASCommunication,
IConfigurationActions,
IDiagnosticsActions,
ITriggerCheckActions,
IRealTimeActions,
IArmActions,
IDownloadActions where T : IConnection, new()
{
#region Downloading
public class TDASSetEventInfoAsync : TDASServiceAsyncInfo
{
public int EventIndex { get; set; }
public UInt32 EventHasDownloaded { get; set; }
public TDASSetEventInfoAsync(ServiceCallback callback,
object userData,
int eventIndex,
UInt32 eventHasDownloaded)
: base(callback, userData)
{
EventIndex = eventIndex;
EventHasDownloaded = eventHasDownloaded;
}
}
public void CorrectT0s(ServiceCallback callback, object userData)
{
var asyncInfo = new TDASServiceAsyncInfo(callback, userData);
asyncInfo.Error("Not supported");
return;
}
void IDownloadActions.SetEventInfo(int eventindex,
string id,
Guid guid,
ulong totalSamples,
ulong[] triggerSamples,
ulong startRecordSample,
UInt32 eventHasDownloaded,
ServiceCallback callback,
object userData)
{
var info = new TDASSetEventInfoAsync(callback, userData, eventindex, eventHasDownloaded);
LaunchAsyncWorker("TDAS.SetEventInfo", new WaitCallback(AsyncSetEventInfo), info);
}
private void AsyncSetEventInfo(object asyncInfo)
{
var info = asyncInfo as TDASSetEventInfoAsync;
try
{
if (UInt32.MaxValue != info.EventHasDownloaded)
{
foreach (DASModule module in ConfigData.Modules)
{
if (DASInfo.Modules[module.ModuleArrayIndex].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK)
{
continue;
}
Command.TDAS.ClearDataAvailable cda = new DTS.DASLib.Command.TDAS.ClearDataAvailable(this);
cda.ModuleIndex = module.ModuleArrayIndex;
cda.SyncExecute();
if (cda.IsErrored) { throw new Exception(string.Format("{0}:{1}", SerialNumber, cda.ResponseData)); }
// Only need to do once for G5
if (IsG5()) { break; }
}
}
}
catch (System.Exception ex)
{
info.Error("Failed to set event downloaded status", ex);
return;
}
info.Success();
}
void IDownloadActions.Download(ServiceCallback callback, object userData)
{
if (!Connected)
{
// "Slice.Download: Not currently connected"
throw new Exception(string.Format(Strings.TDAS_Download_NotConnected, ((InfoResult)DASInfo).OwningDAS.SerialNumber));
}
var state = new TDASDownloadState(callback, userData, WhatToDownload);
LaunchAsyncWorker("TDAS.Download", new WaitCallback(TDASDownload), state);
}
private class TDASDownloadState : TDASServiceAsyncInfo
{
public IDownloadRequest Request;
public ulong SamplesDownloaded; // how many samples have we downloaded so far
public Command.TDAS.Download DownloadCommand;
public TDASDownloadState(ServiceCallback cb, object cbObj, IDownloadRequest _Request)
: base(cb, cbObj)
{
Request = _Request;
SamplesDownloaded = 0;
DownloadCommand = null;
}
}
private static string ToByteFormat(int valIn, int digits)
{
var bitsString = new StringBuilder(digits);
int mask = (1 << digits - 1);
for (int i = 0; i < digits; i++)
{
bitsString.Append((valIn & mask) != 0 ? "1" : "0");
mask >>= 1;
}
return bitsString.ToString();
}
/// <summary>
/// reflects the number of channels on a TOM module (4 SQUIB x 2 channels (squib + current) + 8 digital)
/// </summary>
private const int TOM_CHANNEL_COUNT = 16;
private void TDASDownload(object asyncInfo)
{
var state = asyncInfo as TDASDownloadState;
try
{
int NumberOfChannels = 0;
ulong moduleZerosT0 = 0;
foreach (var module in EventInfo.Events[WhatToDownload.EventNumber].Modules)
{
//Since "What to Download" was calculated using the last module with configured channel's trigger point,
//set moduleZerosT0 here on the same basis so that the delta calculation below is correct.
if ((module.TriggerSampleNumbers != null) && (module.NumberOfConfiguredChannels() > 0))
{
moduleZerosT0 = module.TriggerSampleNumbers[0];
}
//if ((module.Channels.Length > 0) && module.Channels[0].ConfigurationMode != DASChannel.ConfigMode.DummyArm)
//20088 TDAS Download with unused TOM fails.
//TOM modules are included in NewData even if they are dummy armed
//so include them in the count
if (module.IsDummyArmed() && (!IsG5()) && !IsTom(module)) { continue; }
else
{
NumberOfChannels += module.NumberOfChannels();
}
}
ulong totalNumberOfSamples = 1 + WhatToDownload.EndSample - WhatToDownload.StartSample;
//const uint downloadChunkSize = 16384;
ulong downloadChunkSize = 1 + WhatToDownload.EndSample - WhatToDownload.StartSample;
ulong samplesDownloaded = 0;
int channelsToDownload = 0;
foreach (var iDASModule in EventInfo.Events[WhatToDownload.EventNumber].Modules)
{
var m = (DASModule)iDASModule;
if ((m.Channels.Length > 0) && (!(IsTom(m) && (m.Channels[0].ConfigurationMode == DFConstantsAndEnums.ConfigMode.DummyArm))))
{
//If DummyArm and a G5, then count the channels; if a TOM don't
foreach (var ch in m.Channels)
{
if (ch is DTS.DASLib.Service.AnalogInputDASChannel)
{
var aic = ch as DTS.DASLib.Service.AnalogInputDASChannel;
if (aic.ConfigurationMode == DFConstantsAndEnums.ConfigMode.Normal)
{
channelsToDownload++;
}
}
else if (ch is DTS.DASLib.Service.OutputSquibChannel)
{
var osc = ch as DTS.DASLib.Service.OutputSquibChannel;
if (osc.ConfigurationMode == DFConstantsAndEnums.ConfigMode.Normal)
{
channelsToDownload++;
}
}
}
}
}
int channelsDownloaded = 0;
for (ulong z = WhatToDownload.StartSample; z <= WhatToDownload.EndSample; z += downloadChunkSize)
{
ulong end = z + downloadChunkSize;
bool bDigitalDownload = false;
if (end > WhatToDownload.EndSample) { end = WhatToDownload.EndSample; }
short[][] newData = new short[NumberOfChannels][];
for (int i = 0; i < NumberOfChannels; i++)
{
newData[i] = new short[end + 1 - z];
}
int channelIdx = -1;
for (int i = 0; i < EventInfo.Events[WhatToDownload.EventNumber].Modules.Length && z < WhatToDownload.EndSample; i++)
{
if (EventInfo.Events[WhatToDownload.EventNumber].Modules[i].IsDummyArmed())
{
if (IsG5())
{
//Unlike modules in a rack that don't have channels, G5 modules that don't have channels must all be downloaded (and then purged)
channelIdx += EventInfo.Events[WhatToDownload.EventNumber].Modules[i].Channels.Count();
}
//20088A TDAS Download with unused TOM fails.
//TOM channels are included in the NewData structure
//even when dummyarmed, so we must account for it if we see it
if (IsTom(EventInfo.Events[WhatToDownload.EventNumber].Modules[i]))
{
channelIdx += TOM_CHANNEL_COUNT;
}
continue;
}
DASModule mod = (DASModule)EventInfo.Events[WhatToDownload.EventNumber].Modules[i];
//tdas wants start, end, but wants it specified in terms of - = pretrigger,
//+ = post trigger, so we have to convert.
long start = 0;
long stop = 0;
//we make the adjustment here because the "What to Download" was calculated using
//the last module with configured channel's trigger point, but trigger points in tdas are module specific
//so we just adjust by the difference in triggers.
double delta = mod.TriggerSampleNumbers[0] - (double)moduleZerosT0;
//hack to move everything to the the left in the window (by moving the data download to the right
//this seems inaccurate but is consistent with the TDC viewer.
//http://fogbugz/fogbugz/default.asp?7084#45268
//DTM - 2016-09-28 we are now _UNDOING_ thing change, per TJK
double startSample = (double)(z + delta);
double endSample = (double)(end + delta) + 1;
startSample -= mod.PreTriggerSeconds * mod.SampleRateHz;
endSample -= 1 + mod.PreTriggerSeconds * mod.SampleRateHz;
start = Convert.ToInt64(startSample);
stop = Convert.ToInt64(endSample);
//also per CPB and TJK we are one sample too far, so don't do the below adjustment...
//start -= 1;
//stop -= 1;
//NOW per TJK, ADD a sample, for
//http://fogbugz/fogbugz/default.asp?8747
start += 1;
stop += 1;
short[] dimData = new short[0];
bool bIsDIM = !IsG5() &&
EventInfo.Events[WhatToDownload.EventNumber].Modules[i].SerialNumber()
.StartsWith("DIM");
if (bIsDIM)
{
Command.TDAS.Download download = new Command.TDAS.Download(this);
download.ChannelIndex = 0;
download.ModuleIndex = mod.ModuleArrayIndex;
download.FirstPoint = start;
download.LastPoint = stop;
download.SyncExecute();
dimData = download.GetData();
}
for (int k = 0; k < EventInfo.Events[WhatToDownload.EventNumber].Modules[i].Channels.Length; k++)
{
channelIdx++;
if (EventInfo.Events[WhatToDownload.EventNumber].Modules[i].Channels[k].ConfigurationMode != DFConstantsAndEnums.ConfigMode.Normal)
{
continue;
}
//DIMS send there data with all 16 channels per each short
//so to get one channel we've already gotten all channels, so to increase efficiency, we process all channels at the same time here as well
if (bIsDIM)
{
if (dimData.Length > 0)
{
//note that k doesn't necessarily start at 0, so we just start wherever k started at
//first we initialize the data structures since we know how much data we will have
for (int curChannel = k;
curChannel <
EventInfo.Events[WhatToDownload.EventNumber].Modules[i].Channels.Length;
curChannel++)
{
//we also have to keep in mind, we might have started at 1, and we are adding in the "current" channel index
//this is OK with digital channels, because at worse we'll write blank data into the next modules channels, which aren't downloaded yet
//[ideally we'd keep track of which channel we are in the module as well, rather than just overall in the DAS]
//but we need to make sure we don't index out of range ...
if ((curChannel + channelIdx) < newData.Length)
{
newData[curChannel + channelIdx] = new short[dimData.Length];
}
}
//for each data point, break out all the remaining channels and store the bits
//we store them as ADC, which is wasteful, but consistent with Slice pro dim
for (int iDataIndex = 0; iDataIndex < dimData.Length; iDataIndex++)
{
System.Collections.Specialized.BitVector32 bv =
new System.Collections.Specialized.BitVector32(
Convert.ToInt32(dimData[iDataIndex]));
for (int curChannel = k;
curChannel <
EventInfo.Events[WhatToDownload.EventNumber].Modules[i].Channels.Length;
curChannel++)
{
//bit vectors expect a bit mask, our bit mask is just the one channel we are interested in
if (bv[(1 << curChannel)])
{
//cur channel starts at k, so we are inserting at just channelIdx, which is what we want
//as we increase curChannel we are at channelIdx+1, +2, etc.
newData[(curChannel - k) + channelIdx][iDataIndex] = short.MaxValue;
}
else
{
newData[(curChannel - k) + channelIdx][iDataIndex] = short.MinValue;
}
}
}
//update progress
int numberOfDigitalIns = EventInfo.Events[WhatToDownload.EventNumber].Modules[i].Channels.Length - k;
channelsDownloaded += numberOfDigitalIns;
state.Progress((int)(100D * channelsDownloaded / channelsToDownload));
channelIdx += numberOfDigitalIns - 1;//we are ++ at the begining, so we have to subtract one here as numberOfDigitalIns is inclusive
}
//we've finished all channels in this module, since it's a DIM ...
k = EventInfo.Events[WhatToDownload.EventNumber].Modules[i].Channels.Length;
continue;
}
if (EventInfo.Events[WhatToDownload.EventNumber].Modules[i].Channels[k] is DTS.DASLib.Service.AnalogInputDASChannel &&
(EventInfo.Events[WhatToDownload.EventNumber].Modules[i].Channels[k] as DTS.DASLib.Service.AnalogInputDASChannel).TypeOfBridge == SensorConstants.BridgeType.DigitalInput
&& IsG5())
{//download digital all at once
bDigitalDownload = true;
continue;
}
Command.TDAS.Download download = new DTS.DASLib.Command.TDAS.Download(this);
if (IsTom(mod))
{
OutputSquibChannel osc = EventInfo.Events[WhatToDownload.EventNumber].Modules[i].Channels[k] as OutputSquibChannel;
if (null == osc) { continue; }
switch (osc.MeasurementType)
{
case SquibMeasurementType.INIT_SIGNAL:
case SquibMeasurementType.VOLTAGE:
download.DoVoltageOrInsertionDownload = true;
break;
case SquibMeasurementType.CURRENT:
case SquibMeasurementType.NONE:
default:
download.DoCurrentDownload = true;
break;
}
}
download.ModuleIndex = mod.ModuleArrayIndex;
download.ChannelIndex = k;
if (IsTom(mod))
{
download.ChannelIndex = Convert.ToInt32(System.Math.Floor(download.ChannelIndex / 2D));
}
download.FirstPoint = start;
download.LastPoint = stop;
try
{
download.SyncExecute();
}
catch (System.Exception ex)
{
APILogger.Log("Failed to download: ", ex);
download = new Command.TDAS.Download(this, download);
download.SyncExecute();
}
newData[channelIdx] = download.GetData();
channelsDownloaded++;
state.Progress((int)(100D * channelsDownloaded / channelsToDownload));
}
}
if (bDigitalDownload && IsG5())
{
Command.TDAS.Download download = new DTS.DASLib.Command.TDAS.Download(this);
download.ModuleIndex = 0;
var mod = EventInfo.Events[0].Modules[0];
long start = 0;
long stop = 0;
//we make the adjustment here because the "What to Download" was calculated using
//the last module's trigger point, but trigger points in tdas are module specific
//so we just adjust by the difference in triggers.
double delta = mod.TriggerSampleNumbers[0] - (double)moduleZerosT0;
double startSample = (double)(z + delta);
double endSample = (double)(end + delta);
startSample -= mod.PreTriggerSeconds * mod.SampleRateHz;
endSample -= 1 + mod.PreTriggerSeconds * mod.SampleRateHz;
start = Convert.ToInt64(startSample);
stop = Convert.ToInt64(endSample);
// Similar to analog channels, this is a somewhat emperically determined adjustment that is suspect.
// In contrast, these adjustments are expected to be 1 more sample because the digital channels do not have a filter,
// and therefore do not have the same phase delay.
download.FirstPoint = start - 1;
download.LastPoint = stop - 1;
download.Digital = true;
download.Bank = 1;
try
{
download.SyncExecute();
}
catch (System.Exception ex)
{
APILogger.Log("failed; ", ex);
download = new Command.TDAS.Download(this, download);
download.SyncExecute();
}
short[] data = download.GetData();
for (int i = 0; i < 16; i++)
{
if (newData[32 + i].Length < data.Length) { newData[32 + i] = new short[data.Length]; }
}
//each short is actually 16 channels of binary data, so we have to parse it out and convert it to ADC for the purpose of the .chn files
for (int iDataIndex = 0; iDataIndex < data.Length; iDataIndex++)
{
System.Collections.Specialized.BitVector32 bv = new System.Collections.Specialized.BitVector32(Convert.ToInt32(data[iDataIndex]));
//there's another trick in here that we've preserved from TDC, we invert the incoming bit. We do this so that the data appears like
//contact closure normally open
for (int iChannelIdx = 0; iChannelIdx < 16; iChannelIdx++)
{
//also note that the bitvector [] operator expects a bitmask, not an index ...
if (bv[(1 << iChannelIdx)]) { newData[32 + iChannelIdx][iDataIndex] = short.MinValue; }
else { newData[32 + iChannelIdx][iDataIndex] = short.MaxValue; }
}
}
}
state.SamplesDownloaded = end - z;
state.NewData(newData, state.SamplesDownloaded + 1, ulong.MinValue, ulong.MinValue);
samplesDownloaded += downloadChunkSize;
double ratio = Convert.ToDouble(samplesDownloaded) / Convert.ToDouble(totalNumberOfSamples);
if (ratio > 1) { ratio = 1; }
//double ratio = Math.Min(1.0, (double)end / (double)(state.Request.EndSample - state.Request.StartSample + 1));
state.Progress((int)(ratio * 100.0));
}
//foreach (DASModule module in ConfigData.Modules)
foreach (DASModule module in EventInfo.Events[WhatToDownload.EventNumber].Modules)
{
try
{
if (DASInfo.Modules[module.ModuleArrayIndex].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK
|| module.IsDummyArmed())
{
continue;
}
Command.TDAS.ClearDataAvailable cda = new DTS.DASLib.Command.TDAS.ClearDataAvailable(this);
cda.ModuleIndex = module.ModuleArrayIndex;
cda.SyncExecute();
if (IsG5()) { continue; } // only need to do it once
}
catch (System.Exception ex)
{
APILogger.Log("Failed to set event downloaded status", ex);
}
}
//state.NewData(data.ToArray(), WhatToDownload.EndSample-WhatToDownload.StartSample);
state.Progress(100);
// send data to user
state.Success();
}
catch (CanceledException)
{
state.Cancel();
}
catch (System.Exception ex)
{
state.Error(ex.Message, ex);
}
}
#endregion
#region Query download
void IDownloadActions.QueryDownload(ServiceCallback callback, object userData, int eventIndex, TDASServiceSetupInfo setupInfo)
{
var info = new TDASServiceAsyncInfo(callback, userData);
TDASDownloadServiceAsyncInfo dlSetupInfo = new TDASDownloadServiceAsyncInfo(info, setupInfo);
if (eventIndex > 0) { info.Error("only single event support for TDAS"); }
else { LaunchAsyncWorker("TDAS.QueryDownload", new WaitCallback(AsyncQueryDownloadedStatus), dlSetupInfo); }
}
#endregion
#region Query downloaded status
void IDownloadActions.QueryDownloadedStatus(ServiceCallback callback, object userData)
{
var info = new TDASServiceAsyncInfo(callback, userData);
var dlSetupInfo = new TDASDownloadServiceAsyncInfo(info, null);
LaunchAsyncWorker("TDAS.QueryDownloadedStatus", new WaitCallback(AsyncQueryDownloadedStatus), dlSetupInfo);
}
private void AsyncQueryDownloadedStatus(object asyncInfo)
{
var downloadInfo = asyncInfo as TDASDownloadServiceAsyncInfo;
var info = downloadInfo.info;
var setupInfo = downloadInfo.setupInfo;
try
{
var eventDownloadStatus = new List<bool>();
var eventIDs = new List<string>();
var eventDescriptions = new List<string>();
//List<string> eventDescriptions = new List<string>();
var eventGUIDs = new List<Guid>();
var faultFlags = new List<ushort>();
var dasModulesPerEvent = new List<List<DASModule>>();
DateTime eventStartTime = DateTime.Now;
int levelTriggerAdjustment = 0;
//turn off lights & clear serial on racks
//var qse = new Command.TDAS.QuerySerialNumberBroadcast(this, -1);
//qse.SyncExecute();
for (int i = 0; i < DASInfo.Modules.Length; i++)
{
string testConfig = "";
string testDescription = "";
double actualSampleRate = 1D;
float hardwareFilterRate = 1F;
Command.TDAS.SetupDASLoad.ARMMode recordingMode = Command.TDAS.SetupDASLoad.ARMMode.WAIT;
if (DASInfo.Modules[i].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK)
{
TDASModuleConfig tConfig = new TDASModuleConfig(DASInfo.Modules[i].SerialNumber + ".xml");
DASModule module = new DASModule(DASInfo.Modules[i].ModuleArrayIndex, this);
module.StartRecordSampleNumber = 0;
module.PreTriggerSeconds = 0;
module.PostTriggerSeconds = 0;
module.NumberOfSamples = ulong.MaxValue;
module.TriggerSampleNumbers = new UInt64[1];
module.TriggerSampleNumbers[0] = 0;
module.Channels = new DASChannel[DASInfo.Modules[i].NumberOfChannels];
module.AAFilterRateHz = hardwareFilterRate;
module.SampleRateHz = Convert.ToUInt32(System.Math.Abs(actualSampleRate));
if (ConfigData != null)
{
module.Channels = (DASChannel[])ConfigData.Modules[i].Channels.Clone();
}
// update the channel info
for (uint channelIdx = 0; channelIdx < module.Channels.Length; channelIdx++)
{
module.Channels[channelIdx].EventStartTime = eventStartTime;
}
if (dasModulesPerEvent.Count > 0)
{
//dasModulesPerEvent.Add(new List<DASModule>());
dasModulesPerEvent[dasModulesPerEvent.Count - 1].Add(module);
}
}
else
{
Command.TDAS.QueryDataAvailable qda = new DTS.DASLib.Command.TDAS.QueryDataAvailable(this);
qda.ModuleIndex = DASInfo.Modules[i].ModuleArrayIndex;
qda.SyncExecute();
if (null == qda.EventCodes || qda.EventCodes.Length == 0) { APILogger.Log(string.Format("No events found on {0}:{1}", SerialNumber, DASInfo.Modules[i].SerialNumber)); continue; }
try
{
//if (IsTom(ConfigData.Modules[i]))
if (IsTom(DASInfo.Modules[i].TypeOfModule))
{
if ((setupInfo == null) || ((setupInfo.CheckoutMode != null) && (setupInfo.SamplesPerSecond == null)))
{
//We were not called from the Download tile
Command.TDAS.SetupTOMDASRead sdr = new DTS.DASLib.Command.TDAS.SetupTOMDASRead(this);
sdr.ModuleIndex = DASInfo.Modules[i].ModuleArrayIndex;
sdr.SyncExecute();
string sTemp = sdr.TestConfig;
string[] tokens = sTemp.Split(SETUPDASREAD_SENTINEL);
if (tokens.Length >= 2) { testConfig = tokens[0]; testDescription = tokens[1]; }
else { testConfig = tokens[0]; }
//testConfig = sdr.TestConfig;
actualSampleRate = sdr.ActualSampleRate;
if ((setupInfo != null) && ((bool)setupInfo.CheckoutMode))
{
actualSampleRate = Math.Abs(actualSampleRate);
}
hardwareFilterRate = sdr.HardwareFilter;
recordingMode = sdr.ArmMode;
}
else
{
//We were called from the Download tile, which means that SDL was not done, so SDR above would have failed
GetUserSelectedSetupInfo(setupInfo, ref testConfig, ref testDescription, ref actualSampleRate, ref hardwareFilterRate, ref recordingMode);
}
}
else
{
if (DASInfo.Modules[i].TypeOfModule == DFConstantsAndEnums.ModuleType.ProDIM && !IsG5())
{
if ((setupInfo == null) || ((setupInfo.CheckoutMode != null) && (setupInfo.SamplesPerSecond == null)))
{
//We were not called from the Download tile
Command.TDAS.SetupDASReadDIM sdr = new DTS.DASLib.Command.TDAS.SetupDASReadDIM(this);
sdr.ModuleIndex = DASInfo.Modules[i].ModuleArrayIndex;
sdr.SyncExecute();
string sTemp = sdr.TestConfig;
string[] tokens = sTemp.Split(SETUPDASREAD_SENTINEL);
if (2 <= tokens.Length)
{
testConfig = tokens[0];
testDescription = tokens[1];
}
else
{
testConfig = tokens[0];
testDescription = tokens[0];
}
recordingMode = sdr.ArmMode;
actualSampleRate = sdr.ActualSampleRate;
}
else
{
//We were called from the Download tile, which means that SDL was not done, so SDR above would have failed
GetUserSelectedSetupInfo(setupInfo, ref testConfig, ref testDescription, ref actualSampleRate, ref hardwareFilterRate, ref recordingMode);
}
}
else
{
if ((setupInfo == null) || ((setupInfo.CheckoutMode != null) && (setupInfo.SamplesPerSecond == null)))
{
//We were not called from the Download tile
Command.TDAS.SetupDASRead sdr = new DTS.DASLib.Command.TDAS.SetupDASRead(this);
sdr.ModuleIndex = DASInfo.Modules[i].ModuleArrayIndex;
sdr.SyncExecute();
string sTemp = sdr.TestConfig;
string[] tokens = sTemp.Split(SETUPDASREAD_SENTINEL);
if (2 <= tokens.Length)
{
testConfig = tokens[0];
testDescription = tokens[1];
}
else
{
testConfig = tokens[0];
testDescription = tokens[0];
}
actualSampleRate = sdr.ActualSampleRate;
hardwareFilterRate = sdr.HardwareFilter;
recordingMode = sdr.ArmMode;
}
else
{
//We were called from the Download tile, which means that SDL was not done, so SDR above would have failed
GetUserSelectedSetupInfo(setupInfo, ref testConfig, ref testDescription, ref actualSampleRate, ref hardwareFilterRate, ref recordingMode);
}
}
}
}
catch (System.Exception ex)
{
APILogger.Log("Error get SDR", ex);
}
//Command.TDAS.QueryDataAvailable qda = new DTS.DASLib.Command.TDAS.QueryDataAvailable(this);
//qda.ModuleIndex = DASInfo.Modules[i].ModuleArrayIndex;
//qda.SyncExecute();
TDASModuleConfig tConfig = new TDASModuleConfig(DASInfo.Modules[i].SerialNumber + ".xml");
//if (null != qda.eventCodes && qda.eventCodes.Length > 0)
{
foreach (string eventCode in qda.EventCodes)
{
if (!eventIDs.Contains(eventCode))
{
if (testConfig.Length > 0)
{
try
{
eventGUIDs.Add(new Guid("11111111111111111111111111111111"));
}
catch (System.Exception ex)
{
APILogger.Log("invalid test guid - ", testConfig, ex);
continue;
}
}
else { continue; }
eventIDs.Add(eventCode);
eventDescriptions.Add(testDescription);
//eventGUIDs.Add(Guid.Empty);
faultFlags.Add(0);
eventDownloadStatus.Add(qda.IsDownloaded);
dasModulesPerEvent.Add(new List<DASModule>());
}
DASModule module = new DASModule(DASInfo.Modules[i].ModuleArrayIndex, this);
switch (recordingMode)
{
case Command.TDAS.SetupDASLoad.ARMMode.WAIT:
module.RecordingMode = DFConstantsAndEnums.RecordingMode.CircularBuffer;
break;
case Command.TDAS.SetupDASLoad.ARMMode.TAPE:
module.RecordingMode = DFConstantsAndEnums.RecordingMode.RecorderMode;
break;
}
module.StartRecordSampleNumber = 0;
module.PreTriggerSeconds = System.Math.Truncate(100D * qda.PreTriggerSamples / actualSampleRate) / 100D;
module.PostTriggerSeconds = System.Math.Truncate(100D * qda.PostTriggerSamples / actualSampleRate) / 100D;
module.NumberOfSamples = Convert.ToUInt64(qda.PreTriggerSamples + qda.PostTriggerSamples);
module.TriggerSampleNumbers = new UInt64[1];
module.TriggerSampleNumbers[0] = Convert.ToUInt64(qda.PreTriggerSamples + 1);
ulong phaseshift = GetPhaseShiftSamples(Convert.ToUInt32(module.ModuleArrayIndex), actualSampleRate, Convert.ToUInt32(hardwareFilterRate), module.TriggerSampleNumbers[0]);
module.TriggerSampleNumbers[0] += phaseshift;
module.Channels = new DASChannel[DASInfo.Modules[i].NumberOfChannels];
module.AAFilterRateHz = hardwareFilterRate;
module.SampleRateHz = Convert.ToUInt32(System.Math.Abs(actualSampleRate));
if (null != ConfigData)
{
module.Channels = (DASChannel[])ConfigData.Modules[i].Channels.Clone();
// update the channel info
for (uint channelIdx = 0; channelIdx < module.Channels.Length; channelIdx++)
{
module.Channels[channelIdx].EventStartTime = eventStartTime;
}
dasModulesPerEvent[eventIDs.IndexOf(eventCode)].Add(module);
}
if (qda.LevelTriggerOffset > levelTriggerAdjustment)
{
levelTriggerAdjustment = qda.LevelTriggerOffset;
}
}
}
}
}
if (0 < dasModulesPerEvent.Count() && 0 < dasModulesPerEvent[0].Count())
{
foreach (DASModule tempModule in dasModulesPerEvent[0])
{
foreach (var channel in tempModule.Channels)
{
channel.LevelTriggerT0AdjustmentSamples = levelTriggerAdjustment;
}
}
}
SetEventGuids(eventGUIDs.ToArray());
SetEventFaultFlags(faultFlags.ToArray());
DownloadReport dlReport = new DownloadReport();
dlReport.Events = new DownloadReport.EventInfo[EventGuids.Length];
for (int eventIndex = 0; eventIndex < EventGuids.Length; eventIndex++)
{
dlReport.Events[eventIndex] = new DownloadReport.EventInfo();
dlReport.Events[eventIndex].Description = eventDescriptions[eventIndex];
dlReport.Events[eventIndex].EventNumber = eventIndex;
dlReport.Events[eventIndex].TestID = eventIDs[eventIndex];
dlReport.Events[eventIndex].HasBeenDownloaded = false;
dlReport.Events[eventIndex].WasTriggered = false;
dlReport.Events[eventIndex].TestGUID = EventGuids[eventIndex];
dlReport.Events[eventIndex].ClearFaults();
dlReport.Events[eventIndex].Modules = dasModulesPerEvent[eventIndex].ToArray();
}
for (int eventIndex = 0; eventIndex < EventGuids.Length; eventIndex++)
{
double minPre = double.MaxValue;
double minPost = double.MaxValue;
bool dummyArmed = true;
foreach (var module in dasModulesPerEvent[eventIndex])
{
if (DASInfo.Modules[module.ModuleArrayIndex].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK) { continue; }
if ((module.PreTriggerSeconds >= 0) && (module.PostTriggerSeconds >= 0))
{
// Negative trigger seconds are from dummy-armed modules
minPre = System.Math.Min(module.PreTriggerSeconds, minPre);
minPost = System.Math.Min(module.PostTriggerSeconds, minPost);
dummyArmed = false;
}
}
if (0 == dlReport.Events[eventIndex].Modules.Length) { }
else
{
if (!dummyArmed)
{
ulong numberOfSamples = Convert.ToUInt64((minPre + minPost) * dlReport.Events[eventIndex].Modules[0].SampleRateHz);
for (int i = 0; i < dlReport.Events[eventIndex].Modules.Length; i++)
{
DASModule module = (DASModule)dlReport.Events[eventIndex].Modules[i];
module.PreTriggerSeconds = minPre;
module.PostTriggerSeconds = minPost;
module.TriggerSampleNumbers = new ulong[]
{
Convert.ToUInt64(minPre*System.Math.Abs(module.SampleRateHz))
};
// If not triggered, racks return 0 and G5s return number of samples
if ((module.TriggerSampleNumbers[0] > 0) && (module.TriggerSampleNumbers[0] < numberOfSamples))
{
dlReport.Events[eventIndex].WasTriggered = true;
}
//the above statement the pretrigger seconds appears to be off by one sample, so I adjust it here as
//there might already be a lot of different side effects to changing the pre trigger time.
if (module.TriggerSampleNumbers[0] > 0) { module.TriggerSampleNumbers[0] = module.TriggerSampleNumbers[0] - 1; }
module.NumberOfSamples = numberOfSamples;
//module.NumberOfSamples = Convert.ToUInt64(qda.PreTriggerSamples + qda.PostTriggerSamples);
}
}
}
}
//normalize the data here just for sanity sake.
//IE, set start to min(abs(preTrigger))
//set end to min(abs(posttrigger))
//set t0 to min(abs(preTrigger))
SetEventInfo(dlReport);
SetEventDownloadStatus(eventDownloadStatus.ToArray());
if (null != EventInfo && EventInfo.Events.Length > 0)
{
for (int i = 0; i < EventInfo.Events.Length && i < EventDownloadedStatus.Length; i++)
{
if (EventInfo.Events[i].TestID == "TESTTRIG") { EventDownloadedStatus[i] = true; }
}
}
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (System.Exception ex)
{
info.Error(ex.Message, ex);
}
}
private void GetUserSelectedSetupInfo(TDASServiceSetupInfo setupInfo, ref string testConfig, ref string testDescription, ref double actualSampleRate,
ref float hardwareFilterRate, ref Command.TDAS.SetupDASLoad.ARMMode recordingMode)
{
if (setupInfo == null)
{
testConfig = "";
testDescription = "";
actualSampleRate = 1D;
hardwareFilterRate = 1F;
recordingMode = Command.TDAS.SetupDASLoad.ARMMode.WAIT;
}
else
{
// If this was from the Download tile, use the SETUP that the user selected
testConfig = "UsingUser-specifiedTestSetup";
testDescription = setupInfo.SetupDescription;
actualSampleRate = (double)setupInfo.SamplesPerSecond;
hardwareFilterRate = setupInfo.HardwareFilterRateHz;
switch (setupInfo.RecordingMode)
{
case DFConstantsAndEnums.RecordingMode.CircularBuffer:
case DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART:
recordingMode = Command.TDAS.SetupDASLoad.ARMMode.WAIT;
break;
case DFConstantsAndEnums.RecordingMode.RecorderMode:
case DFConstantsAndEnums.RecordingMode.RecorderModePlusUART:
case DFConstantsAndEnums.RecordingMode.a14_NormalRecorderAndStreamSubSampleMode:
recordingMode = Command.TDAS.SetupDASLoad.ARMMode.TAPE;
break;
default:
recordingMode = Command.TDAS.SetupDASLoad.ARMMode.WAIT;
break;
}
}
}
#endregion
#region Set trigger sample numbers
void IDownloadActions.SetTriggerSampleNumbers(ServiceCallback callback, object userData)
{
throw new NotSupportedException("SetTriggerSampleNumbers not supported for TDAS");
}
#endregion
#region Set downloaded
void IDownloadActions.SetDownloaded(ServiceCallback callback, object userData)
{
var info = new TDASSetEventInfoAsync(callback, userData, 0, 1);
//FB12656: Launch synchronously. This call needs the full round-trip (4s) before proceeding with other commands
CallSyncMethod("TDAS.SetDownloaded", SendClearDataAvailable, info);
}
private void SendClearDataAvailable(object asyncInfo)
{
var info = asyncInfo as TDASSetEventInfoAsync;
try
{
if (UInt32.MaxValue != info.EventHasDownloaded)
{
foreach (DASModule module in ConfigData.Modules)
{
if (DASInfo.Modules[module.ModuleArrayIndex].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK
|| module.IsDummyArmed())
{
continue;
}
Command.TDAS.ClearDataAvailable cda = new DTS.DASLib.Command.TDAS.ClearDataAvailable(this);
cda.ModuleIndex = module.ModuleArrayIndex;
cda.SyncExecute();
if (cda.IsErrored) { throw new Exception(string.Format("{0}:{1}", SerialNumber, cda.ResponseData)); }
// Only need to do once for G5
if (IsG5()) { break; }
}
}
}
catch (System.Exception ex)
{
info.Error("Failed to set event downloaded status", ex);
return;
}
info.Success();
}
#endregion
}
}