1345 lines
62 KiB
C#
1345 lines
62 KiB
C#
using DTS.Common.DAS.Concepts;
|
|
using DTS.Common.DASResource;
|
|
using DTS.Common.Enums.DASFactory;
|
|
using DTS.Common.ICommunication;
|
|
using DTS.Common.Interface.Connection;
|
|
using DTS.Common.Interface.DASFactory;
|
|
using DTS.Common.Interface.DASFactory.Download;
|
|
using DTS.Common.Utilities.Logging;
|
|
using DTS.DASLib.Command;
|
|
using DTS.DASLib.Command.SLICE;
|
|
using DTS.DASLib.Command.SLICE.DownloadCommands;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Windows.Forms;
|
|
|
|
namespace DTS.DASLib.Service
|
|
{
|
|
public partial class Slice<T> : Communication<T>,
|
|
IDASCommunication,
|
|
IConfigurationActions,
|
|
IDiagnosticsActions,
|
|
ITriggerCheckActions,
|
|
IRealTimeActions,
|
|
IArmActions,
|
|
IDownloadActions where T : IConnection, new()
|
|
{
|
|
|
|
public virtual DateTime SystemBaseTime => DateTime.MinValue;
|
|
public virtual bool SupportsTimeSynchronization => false;
|
|
public virtual bool RangeBandwidthLimited => false;
|
|
public virtual bool RequireDiagnosticRateMatchSampleRate() { return false; }
|
|
|
|
#region Downloading
|
|
|
|
public class SliceSetEventInfoAsync : SliceServiceAsyncInfo
|
|
{
|
|
public string Id { get; set; }
|
|
public Guid Guid { get; set; }
|
|
public int EventIndex { get; set; }
|
|
public ulong StartRecordSample { get; set; }
|
|
public ulong TotalSamples { get; set; }
|
|
public ulong[] TriggerSamples { get; set; }
|
|
public uint EventHasDownloaded { get; set; }
|
|
public SliceSetEventInfoAsync(ServiceCallback callback,
|
|
object userData,
|
|
int eventIndex,
|
|
ulong startRecordSample,
|
|
ulong totalSamples,
|
|
ulong[] triggerSamples,
|
|
Guid guid,
|
|
string id,
|
|
uint eventHasDownloaded)
|
|
: base(callback, userData)
|
|
{
|
|
EventIndex = eventIndex;
|
|
StartRecordSample = startRecordSample;
|
|
TriggerSamples = triggerSamples;
|
|
TotalSamples = totalSamples;
|
|
Id = id;
|
|
Guid = guid;
|
|
EventHasDownloaded = eventHasDownloaded;
|
|
}
|
|
}
|
|
/// <inheritdoc cref="IDownloadActions" />
|
|
void IDownloadActions.CorrectT0s(ServiceCallback callback, object userData)
|
|
{
|
|
var info = new SliceServiceAsyncInfo(callback, userData);
|
|
LaunchAsyncWorker("Slice.CorretT0s", new WaitCallback(AsyncCorrectT0s), info);
|
|
}
|
|
|
|
/// <summary>
|
|
/// scans data to find where railed data starts and attempts to identify T0 in the dataset
|
|
/// </summary>
|
|
/// <param name="asyncInfo"></param>
|
|
protected virtual void AsyncCorrectT0s(object asyncInfo)
|
|
{
|
|
if (!(asyncInfo is SliceServiceAsyncInfo info)) { return; }
|
|
try
|
|
{
|
|
//scan through for a channel that is configured, then look for a T0 and start of railed data
|
|
for (var moduleIdx = 0; moduleIdx < ConfigData.Modules.Length; moduleIdx++)
|
|
{
|
|
var module = ConfigData.Modules[moduleIdx];
|
|
for (var channelIdx = 0; channelIdx < module.Channels.Length; channelIdx++)
|
|
{
|
|
var channel = module.Channels[channelIdx];
|
|
if (!channel.IsConfigured()) { continue; }
|
|
if (!FindRailAndT0(channel.Number, out var railIdx, out var t0Idx, info))
|
|
{
|
|
//failed to find railed data (maybe it was railed from the start)
|
|
//try again on the next channel ...
|
|
continue;
|
|
}
|
|
//we found a T0 and start of railed data, set T0 and total samples recorded attributes
|
|
info.NewData(DFConstantsAndEnums.T0CorrectionStatus.SettingAttributes);
|
|
SetT0AndTotalSamples(t0Idx, railIdx);
|
|
info.Success();
|
|
return;
|
|
}
|
|
}
|
|
info.Error($"T0 correction not available");
|
|
return;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
info.Error(ex.Message, ex);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// sets the TriggerSampleNumber and TotalSamplesRecorded attributes to
|
|
/// the requested values
|
|
/// </summary>
|
|
/// <param name="t0Idx"></param>
|
|
/// <param name="railIdx"></param>
|
|
protected void SetT0AndTotalSamples(ulong t0Idx, ulong railIdx)
|
|
{
|
|
var sea = new SetEventAttribute(this);
|
|
sea.SetValue(AttributeTypes.ArmAndEventAttributes.TriggerSampleNumber, t0Idx, true);
|
|
sea.SyncExecute();
|
|
|
|
sea = new SetEventAttribute(this);
|
|
sea.SetValue(AttributeTypes.ArmAndEventAttributes.TotalSamplesRecorded, railIdx - 1, true);
|
|
sea.SyncExecute();
|
|
}
|
|
/// <summary>
|
|
/// scans for when a rail starts and a possible T0 as defined by a local max peak or local min trough
|
|
/// returns true if rail is found, however note that a railindex of T0 means that the data is starting
|
|
/// off railed and never recorded.
|
|
/// railed data must be railed for a certain number of samples to be railed
|
|
/// (defined by T0_REQUIRED_CONSECUTIVE_RAILS)
|
|
/// makes use of FindRail to find the rail, and then FindT0 to find the t0, so this
|
|
/// is an aggregator of those functions
|
|
/// </summary>
|
|
/// <param name="channel">channel to scan on</param>
|
|
/// <param name="railIndex">index of where railed data starts</param>
|
|
/// <param name="T0Index">index of max/min local peak/trough</param>
|
|
/// <returns></returns>
|
|
protected bool FindRailAndT0(int channel, out ulong railIndex, out ulong T0Index,
|
|
SliceServiceAsyncInfo info)
|
|
{
|
|
info.NewData(DFConstantsAndEnums.T0CorrectionStatus.ScanningForPowerLoss);
|
|
railIndex = 0;
|
|
T0Index = 0;
|
|
var start = 0UL;
|
|
var end = Convert.ToUInt64(MaxMemory());
|
|
|
|
var samples = GetSamples(channel, start, start + T0_SAMPLING_SIZE);
|
|
//if no samples were retrieved then there are other issues preventing getting data ...
|
|
//(like maybe corruption or other missing event data)
|
|
if (0 == samples.Length) { return false; }
|
|
//first check to see that we don't start with railed data, if we do
|
|
//we can just stop right away
|
|
if (FindRailStart(samples, out var railStart, out _))
|
|
{
|
|
if (railStart == 0)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
railIndex = railStart;
|
|
}
|
|
start += T0_SAMPLING_SIZE;
|
|
}
|
|
while (0 == railIndex)
|
|
{
|
|
//we'll search binary from start to end, so find where that is
|
|
var delta = (end - start) / 2;
|
|
var segment = start + delta;
|
|
//we'll be requesting T0_SAMPLING_SIZE samples, so try to put
|
|
//our midpoint in the middle of that number of samples as well
|
|
if (segment >= T0_SAMPLING_SIZE)
|
|
{
|
|
segment -= T0_SAMPLING_SIZE / 2;
|
|
}
|
|
samples = GetSamples(channel, segment, segment + T0_SAMPLING_SIZE);
|
|
//if there are 0 samples then there is nothing we can probe ...
|
|
var allRailed = false;
|
|
if (0 == samples.Length)
|
|
{
|
|
end = segment;
|
|
allRailed = true;
|
|
}
|
|
else
|
|
{
|
|
if (FindRailStart(samples, out railStart, out allRailed))
|
|
{
|
|
//if we found the start of railed data AND we all samples aren't railed
|
|
//then we did actually find the start of railed data, so record it and stop looking for it
|
|
if (!allRailed)
|
|
{
|
|
railIndex = segment + railStart;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (end - start <= T0_SAMPLING_SIZE)
|
|
{
|
|
//didn't find the rail and we searched all the samples in this block and those
|
|
//are all the samples were we could find it...
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (allRailed)
|
|
{
|
|
//if all the data was railed, then the start of railed data is before our current point
|
|
//move the end of where we are looking accordingly
|
|
//now the segment is T0_SAMPLING_SIZE # of samples, so we could slide this even further
|
|
end = segment;
|
|
}
|
|
else
|
|
{
|
|
//if we didn't find the start of railed data and it's not all railed, that
|
|
//means the start of railed data must happen after our current point
|
|
//adjust the start point where we are looking accordingly
|
|
start = segment + T0_SAMPLING_SIZE;
|
|
}
|
|
}
|
|
}
|
|
//if our rail index > 0, then it's possible there's a T0 we can find via max/min peak/trough
|
|
if (railIndex > 0)
|
|
{
|
|
APILogger.Log($"{SerialNumber} appears to rail at {railIndex}");
|
|
info.NewData(DFConstantsAndEnums.T0CorrectionStatus.ScanningForPeaksAndTroughs);
|
|
T0Index = FindT0(channel, railIndex);
|
|
}
|
|
return railIndex != 0;
|
|
}
|
|
private const int FIND_T0_UPDATE_FREQUENCY = 10000;
|
|
/// <summary>
|
|
/// scans the channel data from 0 to the where rail is hit looking for peaks and troughs
|
|
/// </summary>
|
|
/// <param name="channel">channel to look at on das</param>
|
|
/// <param name="railIndex">the index of where railed data starts at</param>
|
|
/// <returns>index of guessed T0</returns>
|
|
private ulong FindT0(int channel, ulong railIndex)
|
|
{
|
|
var samples = GetSamples(channel, 0, railIndex);
|
|
//if we receive no samples there is nowhere to look for the T0 ...
|
|
if (0 == samples.Length)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//we want to find the max/min peak value, so goes down after (or up on min);
|
|
var min = short.MaxValue;
|
|
var max = short.MinValue;
|
|
var minIndex = -1;
|
|
var maxIndex = -1;
|
|
|
|
//go to sample -1 as we are looking for a peak or trough, so the next sample has to go up from trough or down from peak
|
|
for (var i = 1; i < samples.Length - 1; i++)
|
|
{
|
|
if (0 == i % FIND_T0_UPDATE_FREQUENCY)
|
|
{
|
|
APILogger.Log($"{SerialNumber} : Find T0 : {100 * i / samples.Length:F0}%");
|
|
}
|
|
var adc = samples[i];
|
|
if (adc < min)
|
|
{
|
|
//a local bottom found, we are < min and the next is greater
|
|
if (samples[i + 1] > adc)
|
|
{
|
|
min = adc;
|
|
minIndex = i;
|
|
}
|
|
}
|
|
if (adc > max)
|
|
{
|
|
if (samples[i + 1] < adc)
|
|
{
|
|
//a local peak found, we are > max and the next is lesser
|
|
max = adc;
|
|
maxIndex = i;
|
|
}
|
|
}
|
|
}
|
|
APILogger.Log($"{SerialNumber} has min:{min}@{minIndex} and max:{max}@{maxIndex}");
|
|
//it could be a trough or a peak, find which has a larger difference and go with it
|
|
if (Math.Abs(min) > max)
|
|
{
|
|
return (ulong)minIndex;
|
|
}
|
|
return (ulong)maxIndex;
|
|
}
|
|
/// <summary>
|
|
/// attempts to find the start of railed data
|
|
/// </summary>
|
|
/// <param name="samples">samples to check for rails in</param>
|
|
/// <param name="railStart">index of where railed data starts (relative to the samples input)</param>
|
|
/// <param name="startsRailed">all data is railed from the start (relative to samples input)</param>
|
|
/// <returns>true if railed data was found</returns>
|
|
private bool FindRailStart(short[] samples, out ulong railStart, out bool startsRailed)
|
|
{
|
|
//we require REQUIRED_CONS_RAILS, so only go up to length - required number
|
|
for (var i = 0; i < samples.Length - T0_REQUIRED_CONSECUTIVE_RAILS; i++)
|
|
{
|
|
//if we find a railed sample, then check the next x samples are also railed
|
|
if (IsRailed(samples[i]))
|
|
{
|
|
var isValid = true;
|
|
for (var consecutive = 0; consecutive < T0_REQUIRED_CONSECUTIVE_RAILS; consecutive++)
|
|
{
|
|
if (!IsRailed(samples[i + consecutive]))
|
|
{
|
|
//for an optimization we could jump to i+consecutive +1 since we know the next possible
|
|
//start of rail is there ...
|
|
isValid = false;
|
|
break;
|
|
}
|
|
}
|
|
if (isValid)
|
|
{
|
|
//we found our required number of samples, so set the index and return
|
|
railStart = (ulong)i;
|
|
startsRailed = 0 == railStart;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
//we didn't find the start of railed data
|
|
railStart = 0UL;
|
|
startsRailed = false;
|
|
return false;
|
|
}
|
|
/// <summary>
|
|
/// tests whether a sample is railed
|
|
/// </summary>
|
|
/// <param name="sample"></param>
|
|
/// <returns></returns>
|
|
private bool IsRailed(short sample)
|
|
{
|
|
return sample == short.MinValue || sample == short.MaxValue;
|
|
}
|
|
/// <summary>
|
|
/// how many samples to grab when probing dataset
|
|
/// we want a number that is around the max a DAS will return,
|
|
/// however because of page boundaries this we still have no
|
|
/// idea how many file operations will hit on the DAS
|
|
/// </summary>
|
|
private const int T0_SAMPLING_SIZE = 900;
|
|
/// <summary>
|
|
/// when detecting railed data data must be railed for atleast this
|
|
/// number of consecutive samples to avoid situations where a signal
|
|
/// is bouncing off of a rail or is on the rail but has some noise
|
|
/// and isn't in fact railed
|
|
/// </summary>
|
|
private const int T0_REQUIRED_CONSECUTIVE_RAILS = 5;
|
|
private const int T0_LOGDOWNLOAD_CUTOFF = 100000;
|
|
private const ulong T0_LOGDOWNLOAD_FREQUENCY_PERCENT = 5UL;
|
|
/// <summary>
|
|
/// returns all the samples for device between start and end
|
|
/// </summary>
|
|
/// <param name="channel">channel to query</param>
|
|
/// <param name="start">start sample index</param>
|
|
/// <param name="end">last sample index to include</param>
|
|
/// <returns></returns>
|
|
protected short[] GetSamples(int channel, ulong start, ulong end)
|
|
{
|
|
var numNeeded = end - start;
|
|
var newData = new List<short>();
|
|
var dr = new DownloadRequest();
|
|
dr.DASChannelNumber = DownloadRequest.ALL_CHANNELS;
|
|
dr.EventNumber = 0;
|
|
dr.StartSample = start;
|
|
dr.EndSample = end;
|
|
SetWhatToDownload(dr, false);
|
|
var waitHandle = new ManualResetEvent(false);
|
|
ulong count = 0;
|
|
var lastUpdate = 0UL;
|
|
Download((ServiceCallbackData data) =>
|
|
{
|
|
switch (data.Status)
|
|
{
|
|
case ServiceCallbackData.CallbackStatus.Success:
|
|
waitHandle.Set();
|
|
break;
|
|
case ServiceCallbackData.CallbackStatus.NewData:
|
|
foreach (var dataSample in data.DataSamples)
|
|
{
|
|
newData.AddRange(dataSample.Data[channel]);
|
|
count += (ulong)dataSample.Data[channel].Length;
|
|
if (numNeeded > T0_LOGDOWNLOAD_CUTOFF)
|
|
{
|
|
var percent = 100 * count / numNeeded;
|
|
if ((percent - lastUpdate) > T0_LOGDOWNLOAD_FREQUENCY_PERCENT)
|
|
{
|
|
lastUpdate = percent;
|
|
APILogger.Log($"{SerialNumber} : Downloading: {percent}%");
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ServiceCallbackData.CallbackStatus.Failure:
|
|
waitHandle.Set();
|
|
break;
|
|
}
|
|
}, this);
|
|
waitHandle.WaitOne();
|
|
return newData.ToArray();
|
|
}
|
|
void IDownloadActions.SetEventInfo(int eventIndex, string id,
|
|
Guid guid,
|
|
ulong totalSamples,
|
|
ulong[] triggerSamples,
|
|
ulong startRecordSample,
|
|
uint eventHasDownloaded,
|
|
ServiceCallback callback,
|
|
object userData)
|
|
{
|
|
var info = new SliceSetEventInfoAsync(callback, userData, eventIndex,
|
|
startRecordSample, totalSamples, triggerSamples, guid, id, eventHasDownloaded);
|
|
|
|
LaunchAsyncWorker("Slice.SetEventInfo", new WaitCallback(AsyncSetEventInfo), info);
|
|
}
|
|
private void AsyncSetEventInfo(object asyncInfo)
|
|
{
|
|
var info = asyncInfo as SliceSetEventInfoAsync;
|
|
try
|
|
{
|
|
if (!string.IsNullOrEmpty(info.Id))
|
|
{
|
|
var sea = new SetEventAttribute(this);
|
|
sea.EventNumber = Convert.ToUInt16(info.EventIndex);
|
|
sea.SetValue(AttributeTypes.ArmAndEventAttributes.Name, info.Id.ToCharArray(), true);
|
|
sea.SyncExecute();
|
|
}
|
|
if (Guid.Empty != info.Guid)
|
|
{
|
|
var sea = new SetEventAttribute(this);
|
|
sea.SetValue(AttributeTypes.ArmAndEventAttributes.EventGuid, info.Guid.ToString(), true);
|
|
sea.EventNumber = Convert.ToUInt16(info.EventIndex);
|
|
sea.SyncExecute();
|
|
}
|
|
if (ulong.MaxValue != info.StartRecordSample)
|
|
{
|
|
var sea = new SetEventAttribute(this);
|
|
sea.EventNumber = Convert.ToUInt16(info.EventIndex);
|
|
sea.SetValue(AttributeTypes.ArmAndEventAttributes.StartRecordSampleNumber, info.StartRecordSample, true);
|
|
sea.SyncExecute();
|
|
}
|
|
if (ulong.MaxValue != info.TotalSamples)
|
|
{
|
|
var sea = new SetEventAttribute(this);
|
|
sea.EventNumber = Convert.ToUInt16(info.EventIndex);
|
|
sea.SetValue(AttributeTypes.ArmAndEventAttributes.TotalSamplesRecorded, info.TotalSamples, true);
|
|
sea.SyncExecute();
|
|
}
|
|
if (null != info.TriggerSamples)
|
|
{
|
|
var sea = new SetEventAttribute(this);
|
|
sea.EventNumber = Convert.ToUInt16(info.EventIndex);
|
|
sea.SetValue(AttributeTypes.ArmAndEventAttributes.TriggerSampleNumber, info.TriggerSamples[0], true);
|
|
sea.SyncExecute();
|
|
}
|
|
if (uint.MaxValue != info.EventHasDownloaded)
|
|
{
|
|
var sea = new SetEventAttribute(this);
|
|
sea.EventNumber = Convert.ToUInt16(info.EventIndex);
|
|
sea.SetValue(AttributeTypes.ArmAndEventAttributes.EventHasBeenDownloaded, info.EventHasDownloaded, true);
|
|
sea.SyncExecute();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
info.Error("Failed to set event info", ex);
|
|
return;
|
|
}
|
|
info.Success();
|
|
}
|
|
public virtual long MaxMemory()
|
|
{
|
|
if (null == DASInfo || 0 == DASInfo.NumberOfBytesPerSampleClock) { return 0L; }
|
|
return (long)(DASInfo.MaxEventStorageSpaceInBytes / DASInfo.NumberOfBytesPerSampleClock);
|
|
}
|
|
public virtual uint MaxSampleRate(int numberOfConfiguredChannels)
|
|
{
|
|
int modules = DASInfo.Modules.Length;
|
|
return modules > 0 ? Convert.ToUInt32(120000 / modules) : 120000;
|
|
}
|
|
public virtual uint MinSampleRate()
|
|
{
|
|
return 5;
|
|
}
|
|
public virtual uint MaxAAFilterRate()
|
|
{
|
|
return MaxSampleRate(0) / 5;
|
|
}
|
|
protected class SliceDownloadState : SliceServiceAsyncInfo
|
|
{
|
|
public IDownloadRequest Request;
|
|
public ulong SamplesDownloaded; // how many samples have we downloaded so far
|
|
|
|
public QueryEventDataBase DownloadCommand;
|
|
|
|
public SliceDownloadState(ServiceCallback cb, object cbObj, IDownloadRequest _Request)
|
|
: base(cb, cbObj)
|
|
{
|
|
Request = _Request;
|
|
SamplesDownloaded = 0;
|
|
DownloadCommand = null;
|
|
}
|
|
}
|
|
|
|
protected class SliceUARTDownloadState : SliceServiceAsyncInfo
|
|
{
|
|
public IUARTDownloadRequest Request;
|
|
public ulong BytesDownloaded; // how many bytes have we downloaded so far
|
|
|
|
public QueryUARTEventData DownloadCommand;
|
|
|
|
public SliceUARTDownloadState(ServiceCallback cb, object cbObj, IUARTDownloadRequest _request)
|
|
: base(cb, cbObj)
|
|
{
|
|
Request = _request;
|
|
BytesDownloaded = 0;
|
|
DownloadCommand = null;
|
|
}
|
|
}
|
|
|
|
public virtual void Download(ServiceCallback callback, object userData)
|
|
{
|
|
if (!Connected)
|
|
{
|
|
// "Slice.Download: Not currently connected"
|
|
throw new Exception(Strings.Slice_Download_Err1);
|
|
}
|
|
|
|
if (WhatToDownload.SamplesToSkip < 2)
|
|
{
|
|
// no sub-sampling
|
|
var state = new SliceDownloadState(callback, userData, WhatToDownload);
|
|
ThreadPool.QueueUserWorkItem(ExtraDownloadStart, state);
|
|
}
|
|
else
|
|
{
|
|
var state = new SliceDownloadState(callback, userData, WhatToDownload);
|
|
LaunchAsyncWorker("Slice.Download", DownloadSubSampled, state);
|
|
}
|
|
}
|
|
|
|
protected virtual void ExtraDownloadStart(object obj)
|
|
{
|
|
try
|
|
{
|
|
DownloadEventStartCmd(obj as SliceDownloadState);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log("MessageBox", Strings.SLICEDownloadExtraDownloadStartError, ex);
|
|
}
|
|
}
|
|
protected virtual QueryEventDataBase GetQueryEventData()
|
|
{
|
|
return new QueryEventDataBase(this, AbstractCommandBase.Default_IO_Timeout);
|
|
}
|
|
protected virtual void DownloadEventStartCmd(SliceDownloadState state)
|
|
{
|
|
try
|
|
{
|
|
if (state.SamplesDownloaded >= state.Request.EndSample - state.Request.StartSample + 1) return;
|
|
state.DownloadCommand = GetQueryEventData();
|
|
state.DownloadCommand.LogCommands = false;
|
|
state.DownloadCommand.EventNumber = state.Request.EventNumber;
|
|
state.DownloadCommand.Channel = state.Request.DASChannelNumber;
|
|
if (state.Request.DASChannelNumber == DownloadRequest.ALL_CHANNELS)
|
|
{
|
|
state.DownloadCommand.ChannelsDownloaded = IsTOM() ?
|
|
9 : EventInfo.Events[state.Request.EventNumber].Modules.Sum(module => module.NumberOfChannels());
|
|
}
|
|
state.DownloadCommand.LastSample = state.Request.EndSample;
|
|
// Ask for the next batch of samples
|
|
state.DownloadCommand.FirstSample = state.Request.StartSample + state.SamplesDownloaded;
|
|
state.DownloadCommand.Execute(DownloadEventCallback, state);
|
|
}
|
|
catch (CanceledException)
|
|
{
|
|
state.Cancel();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
state.Error(ex.Message, ex);
|
|
}
|
|
}
|
|
|
|
protected CommandReceiveAction DownloadEventCallback(ICommandReport report)
|
|
{
|
|
var state = report.CallbackObject as SliceDownloadState;
|
|
try
|
|
{
|
|
if (report.Status == CommandStatus.Failure)
|
|
{
|
|
// no, it didn't work out
|
|
// "Slice.Download: BAD DATA"
|
|
state.Error(Strings.Slice_DownloadEventCallback_Err1);
|
|
return CommandReceiveAction.StopReceiving;
|
|
}
|
|
if (report.Status == CommandStatus.Canceled)
|
|
{
|
|
// user wants us to bail out
|
|
state.Cancel();
|
|
return CommandReceiveAction.StopReceiving;
|
|
}
|
|
var rep = report as QueryEventDataReport;
|
|
// OK, we have our data block
|
|
state.SamplesDownloaded += (ulong)state.DownloadCommand.Count;
|
|
var channelsToUse = IsTOM() ? 16 : state.DownloadCommand.ChannelsDownloaded;
|
|
var newData = new short[channelsToUse][];
|
|
for (var channelIdx = 0; channelIdx < state.DownloadCommand.ChannelsDownloaded; channelIdx++)
|
|
{
|
|
newData[channelIdx] = rep.Data[channelIdx].ToArray();
|
|
}
|
|
for (var channelIdx = state.DownloadCommand.ChannelsDownloaded; channelIdx < channelsToUse; channelIdx++)
|
|
{
|
|
newData[channelIdx] = rep.Data[0].ToArray();//Hack alert: In the case of a TOM, we only request 9 channels, but need to return 16 total
|
|
}
|
|
state.NewData(newData, 0, ulong.MinValue, ulong.MinValue);
|
|
double ratio = Math.Min(1.0, state.SamplesDownloaded / (double)(state.Request.EndSample - state.Request.StartSample + 1));
|
|
state.Progress((int)(ratio * 100.0));
|
|
|
|
// if we have it all we're done
|
|
if (state.SamplesDownloaded < (state.Request.EndSample - state.Request.StartSample + 1))
|
|
{
|
|
// otherwise, update parameters and call again
|
|
DownloadEventStartCmd(state);
|
|
}
|
|
else
|
|
{
|
|
var config = GetConfigAttributes(this);//new ConfigAttributes(this);
|
|
config.SetEventDownloaded(state.Request.EventNumber, 1);
|
|
state.Success();
|
|
}
|
|
}
|
|
catch (CanceledException)
|
|
{
|
|
state.Cancel();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
state.Error(ex.Message, ex);
|
|
}
|
|
return CommandReceiveAction.StopReceiving;
|
|
}
|
|
|
|
private void DownloadSubSampled(object asyncInfo)
|
|
{
|
|
var state = asyncInfo as SliceDownloadState;
|
|
|
|
try
|
|
{
|
|
var NumberOfChannels = EventInfo.Events[WhatToDownload.EventNumber].Modules.Sum(module => module.NumberOfChannels());
|
|
|
|
// these two are per channel of course
|
|
ulong TotalNumberOfSamples = WhatToDownload.EndSample - WhatToDownload.StartSample + 1;
|
|
ulong NumberOfSubSamples = TotalNumberOfSamples / WhatToDownload.SamplesToSkip;
|
|
|
|
// allocate array to return to user
|
|
var SubSampledData = new short[NumberOfChannels][];
|
|
for (var idx = 0; idx < NumberOfChannels; idx++)
|
|
{
|
|
SubSampledData[idx] = new short[NumberOfSubSamples];
|
|
}
|
|
|
|
// loop thru and get our samples
|
|
var SubSampleIdx = 0;
|
|
for (var sampleIdx = WhatToDownload.StartSample;
|
|
sampleIdx < WhatToDownload.EndSample && (ulong)SubSampleIdx < NumberOfSubSamples;
|
|
sampleIdx += WhatToDownload.SamplesToSkip)
|
|
{
|
|
var newData = GetSingleSample(WhatToDownload.EventNumber, NumberOfChannels, sampleIdx);
|
|
|
|
// loop thru the channels and get data from cmd
|
|
for (var channelIdx = 0; channelIdx < NumberOfChannels; channelIdx++)
|
|
{
|
|
SubSampledData[channelIdx][SubSampleIdx] = newData[channelIdx][0];
|
|
}
|
|
SubSampleIdx++;
|
|
|
|
// calculate where we are
|
|
double ratio = Math.Min(1.0, SubSampleIdx / (double)NumberOfSubSamples);
|
|
state.Progress((int)(ratio * 100.0));
|
|
Application.DoEvents();
|
|
}
|
|
// send data to user
|
|
state.NewData(SubSampledData, 0, ulong.MinValue, ulong.MinValue);
|
|
state.Success();
|
|
}
|
|
catch (CanceledException)
|
|
{
|
|
state.Cancel();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
state.Error(ex.Message, ex);
|
|
}
|
|
}
|
|
|
|
private short[][] GetSingleSample(ushort eventNumber, int numberOfChannels, ulong sampleNumber)
|
|
{
|
|
// create cmd
|
|
//var DownloadCommand = new QueryEventData(this);
|
|
var DownloadCommand = GetQueryEventData();
|
|
|
|
// we don't want to log this
|
|
DownloadCommand.LogCommands = false;
|
|
|
|
// the event number to retrive
|
|
DownloadCommand.EventNumber = eventNumber;
|
|
|
|
// the channels to get
|
|
DownloadCommand.Channel = DownloadRequest.ALL_CHANNELS;
|
|
DownloadCommand.ChannelsDownloaded = numberOfChannels;
|
|
|
|
// the sample to get
|
|
DownloadCommand.FirstSample = sampleNumber;
|
|
DownloadCommand.LastSample = sampleNumber;
|
|
|
|
// call HW to get samples
|
|
DownloadCommand.SyncExecute();
|
|
|
|
// allocate array to return to user
|
|
var newData = new short[numberOfChannels][];
|
|
|
|
// loop thru the channels and get data from cmd
|
|
for (var channelIdx = 0; channelIdx < numberOfChannels; channelIdx++)
|
|
{
|
|
DownloadCommand.GetChannelData(channelIdx, out newData[channelIdx]);
|
|
}
|
|
|
|
return newData;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Query download
|
|
public virtual bool CheckAAF(float rate) { return true; }
|
|
public class QueryDownloadProgress
|
|
{
|
|
private SliceServiceAsyncInfo info;
|
|
private readonly int TotalNumberOfSteps;
|
|
private int CurrentStep;
|
|
|
|
public QueryDownloadProgress(SliceServiceAsyncInfo _info, int steps, int initialStep)
|
|
{
|
|
info = _info;
|
|
TotalNumberOfSteps = steps;
|
|
CurrentStep = initialStep;
|
|
report();
|
|
}
|
|
|
|
private void report()
|
|
{
|
|
if (CurrentStep <= TotalNumberOfSteps && TotalNumberOfSteps > 0)
|
|
{
|
|
var step = (int)(CurrentStep / (double)TotalNumberOfSteps * 100.0);
|
|
info.Progress(step);
|
|
}
|
|
else
|
|
{
|
|
info.Progress(100);
|
|
}
|
|
}
|
|
|
|
public void Step()
|
|
{
|
|
CurrentStep++;
|
|
report();
|
|
}
|
|
}
|
|
|
|
internal class QueryDownloadAsyncInfo : SliceServiceAsyncInfo
|
|
{
|
|
public int EventIndex { get; set; }
|
|
public QueryDownloadAsyncInfo(ServiceCallback callback, object userData, int eventIndex)
|
|
: base(callback, userData)
|
|
{
|
|
EventIndex = eventIndex;
|
|
}
|
|
}
|
|
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 void GetEventTimeStampInfo(int eventIdx, out uint startRecordTimestampSec,
|
|
out uint triggerTimestampSec, out uint startRecordTimestampNanoSec,
|
|
out uint triggerTimestampNanoSec, out bool pTPMasterSync)
|
|
{
|
|
startRecordTimestampSec = 0;
|
|
triggerTimestampSec = 0;
|
|
startRecordTimestampNanoSec = 0;
|
|
triggerTimestampNanoSec = 0;
|
|
pTPMasterSync = false;
|
|
|
|
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.PTPTimestamp))
|
|
{
|
|
try
|
|
{
|
|
var qea = new QueryEventAttribute(this);
|
|
qea.EventNumber = Convert.ToUInt16(eventIdx);
|
|
qea.Key = AttributeTypes.ArmAndEventAttributes.ADCStartTimeStampSecNanoSec;
|
|
qea.SyncExecute();
|
|
startRecordTimestampSec = ((uint[])qea.Value)[0];
|
|
startRecordTimestampNanoSec = ((uint[])qea.Value)[1];
|
|
}
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
|
|
|
try
|
|
{
|
|
var qea = new QueryEventAttribute(this);
|
|
qea.EventNumber = Convert.ToUInt16(eventIdx);
|
|
qea.Key = AttributeTypes.ArmAndEventAttributes.TriggerTimeStampSecNanoSec;
|
|
qea.SyncExecute();
|
|
triggerTimestampSec = ((uint[])qea.Value)[0];
|
|
triggerTimestampNanoSec = ((uint[])qea.Value)[1];
|
|
}
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
|
|
|
try
|
|
{
|
|
uint lockedTime, outOfSyncTime;
|
|
var qea = new QueryEventAttribute(this);
|
|
qea.EventNumber = Convert.ToUInt16(eventIdx);
|
|
qea.Key = AttributeTypes.ArmAndEventAttributes.PtpSyncLockedTimeSec;
|
|
qea.SyncExecute();
|
|
lockedTime = (uint)qea.Value;
|
|
|
|
qea.EventNumber = Convert.ToUInt16(eventIdx);
|
|
qea.Key = AttributeTypes.ArmAndEventAttributes.PtpOutOfSyncTimeSec;
|
|
qea.SyncExecute();
|
|
outOfSyncTime = (uint)qea.Value;
|
|
if (lockedTime > outOfSyncTime)
|
|
{
|
|
pTPMasterSync = true;
|
|
}
|
|
else { pTPMasterSync = false; }
|
|
}
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
|
}
|
|
}
|
|
protected virtual 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
|
|
{
|
|
if (info.EventIndex < 0) { RetrieveDASBootCount(); }
|
|
else { TurnOffDiagnosticsMode(); }
|
|
var EventCount = new QueryTotalEventCount(this);
|
|
EventCount.SyncExecute();
|
|
|
|
var config = GetConfigAttributes(this);//new ConfigAttributes(this);
|
|
|
|
// 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 faultFlagsEx = new ushort[EventCount.Count];
|
|
var armAttempts = new byte[EventCount.Count];
|
|
var extendedFaultFlags = new List<uint[]>();
|
|
|
|
var dlReport = new DownloadReport();
|
|
//22295 Since all SLICE6Air DAS derive from IUARTDownload, SLICE6Air Ethernet Recorders
|
|
//would fall in here and create a UARTEvent if we didn't call IsSLICE6ERFirmware. An issue
|
|
//(FB 23347) was opened to draw attention to possibly modifying this workaround.
|
|
if ((this is IUARTDownload) && !(DFConstantsAndEnums.IsSLICE6ERFirmware(FirmwareVersion)) && (0 > info.EventIndex))
|
|
{
|
|
dlReport.UARTEvents = new DownloadReport.UARTEventInfo[EventCount.Count];
|
|
for (var eventIdx = 0; eventIdx < EventCount.Count; eventIdx++)
|
|
{
|
|
if (info.EventIndex >= 0 && eventIdx != info.EventIndex) { continue; }
|
|
var uartInfo = new QueryUARTEventInfo(this) { EventNumber = (ushort)eventIdx };
|
|
uartInfo.SyncExecute();
|
|
// the object to store it all in
|
|
var uartEventInfo = new DownloadReport.UARTEventInfo()
|
|
{
|
|
EventNumber = uartInfo.EventNumber,
|
|
DataPresent = uartInfo.DataPresent,
|
|
DataDownloaded = uartInfo.DataDownloaded,
|
|
TotalByteCount = uartInfo.TotalByteCount,
|
|
TriggerByteCount = uartInfo.TriggerByteCount,
|
|
StartTimestamp = uartInfo.StartTimestamp,
|
|
EndTimestamp = uartInfo.EndTimestamp,
|
|
BaudRate = uartInfo.BaudRate
|
|
};
|
|
if (0 > info.EventIndex)
|
|
{
|
|
// store it in the object
|
|
dlReport.UARTEvents[eventIdx] = uartEventInfo;
|
|
}
|
|
else { EventInfo.UARTEvents[eventIdx] = uartEventInfo; }
|
|
}
|
|
}
|
|
if (0 > info.EventIndex)
|
|
{
|
|
dlReport.Events = new DownloadReport.EventInfo[EventCount.Count];
|
|
}
|
|
for (var eventIdx = 0; eventIdx < EventCount.Count; eventIdx++)
|
|
{
|
|
GetEventTimeStampInfo(eventIdx, out var startRecordTimestampSec,
|
|
out var triggerTimestampSec, out var startRecordTimestampNanoSec, out var triggerTimestampNanoSec,
|
|
out var pTPMasterSync);
|
|
if (info.EventIndex >= 0 && eventIdx != info.EventIndex) { continue; }
|
|
extendedFaultFlags.Add(GetExtendedFaultFlags(eventIdx));
|
|
// Retrieved the stored configuration
|
|
var storedConfigStr = config.RetrieveEventXMLConfig(eventIdx, progress, this); // I/O * n
|
|
|
|
// convert it from XML to object
|
|
var storedConfig = ConfigurationData.DeserializeFromString(storedConfigStr);
|
|
|
|
// the object to store it all in
|
|
var eventInfo = new DownloadReport.EventInfo();
|
|
|
|
// get the event level values
|
|
eventInfo.Description = config.GetEventDescription(eventIdx); // I/O
|
|
try
|
|
{
|
|
if (null != ConfigData) { eventInfo.Description = ConfigData.Description; }
|
|
}
|
|
catch (Exception) { }
|
|
progress.Step();
|
|
eventInfo.TestID = config.GetEventID(eventIdx, this).TrimEnd(new char[] { '\0' }); ; // I/O
|
|
progress.Step();
|
|
eventInfo.EventNumber = eventIdx;
|
|
progress.Step();
|
|
try
|
|
{
|
|
//eventInfo.TestGUID = config.GetEventGuid(eventIdx); // I/O
|
|
eventInfo.TestGUID = GetEventGuid(eventIdx);
|
|
}
|
|
catch (Exception) { eventInfo.TestGUID = Guid.NewGuid(); }
|
|
try
|
|
{
|
|
eventInfo.FaultFlags = config.GetEventFaultFlags(eventIdx);
|
|
eventInfo.FaultFlagsEx = config.GetEventFaultFlagsEx(eventIdx);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log("could not get fault flags", ex);
|
|
}
|
|
try
|
|
{
|
|
eventInfo.ArmAttempts = config.GetEventArmAttempts(eventIdx);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log("could not get arm attempts", ex);
|
|
}
|
|
eventGuids[eventIdx] = eventInfo.TestGUID;
|
|
faultFlags[eventIdx] = eventInfo.FaultFlags;
|
|
faultFlagsEx[eventIdx] = eventInfo.FaultFlagsEx;
|
|
armAttempts[eventIdx] = eventInfo.ArmAttempts;
|
|
eventInfo.HasBeenDownloaded = config.EventHasBeenDownloaded(eventIdx, out uint flag); // I/O
|
|
progress.Step();
|
|
|
|
// figure out how many modules we have
|
|
var numberOfChannels = GetEventTotalChannels(eventIdx); // I/O
|
|
progress.Step();
|
|
var numberOfModules = config.CalculateNumberOfModules(storedConfig, numberOfChannels, IsTOM());
|
|
var numberOfUARTs = config.CalculateNumberOfUARTs(storedConfig);
|
|
var numberOfStreamOuts = config.CalculateNumberOfStreamOuts(storedConfig);
|
|
var numberOfStreamIns = config.CalculateNumberOfStreamIns(storedConfig);
|
|
// make sure we have the right number of modules
|
|
// make sure we have the right number of UARTs FB18363
|
|
if (numberOfModules + numberOfUARTs + numberOfStreamOuts + numberOfStreamIns != storedConfig.Modules.Length)
|
|
{
|
|
// "Slice.QueryDownload: The information in the recorder is corrupt"
|
|
info.Error(Strings.Slice_QueryDownload_Err1);
|
|
//SS: need to add code here to try to extract enough info
|
|
return;
|
|
}
|
|
|
|
eventInfo.Modules = new DASModule[numberOfModules];
|
|
var numberOfSamples = config.GetEventTotalSamples(eventIdx); // I/O
|
|
var triggerSampleNumber = config.GetEventTriggerSampleNumber(eventIdx); // I/O
|
|
var eventStartRecordSampleNumber = config.GetEventStartRecordSampleNumber(eventIdx); // I/O
|
|
var eventStartTime = config.GetEventStartTime(eventIdx); // I/O
|
|
var levelTriggerOffsetCorrection = config.GetEventLevelTriggerT0AdjustmentSamples(eventIdx);
|
|
var levelTriggerSeen = config.GetEventLevelTriggerSeen(eventIdx);
|
|
var actualSampleRate = config.GetEventSamplerate(eventIdx);
|
|
var stackActualSampleRate = config.GetEventStackSamplerate(eventIdx);
|
|
// 17873 download should only use event attributes rather than arm attributes
|
|
var factors = config.GetEventScaleFactors(eventIdx);
|
|
var aafilter = config.GetEventAAFilter(eventIdx);
|
|
var currentChannel = 0;
|
|
//toyota boshoku -flat data issue zendesk 5702?
|
|
//basically make sure we are using the event attribute ScaleFactorMvADC and not what is in the
|
|
//xml
|
|
for (var moduleIdx = 0; moduleIdx < numberOfModules; moduleIdx++)
|
|
{
|
|
// take the module from the stored config
|
|
var module = (DASModule)storedConfig.Modules[moduleIdx];
|
|
|
|
module.SampleRateHz = Convert.ToUInt32(actualSampleRate);
|
|
module.EmbeddedSampleRateHz = stackActualSampleRate;
|
|
|
|
/// <DesignNote topic="Level Trigger Configuration" author="PKXH">
|
|
/// Amongst other things, the level trigger offset correction, if it exists, is getting applied
|
|
/// to the module trigger sample numbers below. There shouldn't be any danger of this value being
|
|
/// erroneously applied to outside "tweaking" since the only outside tweak should only ever happen
|
|
/// if there was no trigger. Still I'm a little concerned that this value will still be invisibly
|
|
/// applied to user-overridden trigger sample numbers. We could conceivably guard against this
|
|
/// situation with an "original trigger sample number" concept, which we could then check against
|
|
/// and not re-apply things like level trigger offset correction if the current value doesn't
|
|
/// match it, implying it has been manually overridden.
|
|
/// </DesignNote>
|
|
|
|
// now update the module with dynamic data
|
|
module.OwningDAS = this;
|
|
module.NumberOfSamples = numberOfSamples;
|
|
progress.Step();
|
|
module.TriggerSampleNumbers = new ulong[1]; // only one so far
|
|
var phaseShift = GetPhaseShiftSamples(Convert.ToUInt32(1 + module.ModuleArrayIndex), Convert.ToDouble(actualSampleRate), Convert.ToUInt32(aafilter), triggerSampleNumber);
|
|
|
|
module.TriggerSampleNumbers[0] = triggerSampleNumber + phaseShift;
|
|
eventInfo.WasTriggered = module.TriggerSampleNumbers[0] > 0;
|
|
progress.Step();
|
|
|
|
module.StartRecordSampleNumber = 0;
|
|
if (module.RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBuffer
|
|
|| module.RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART
|
|
|| module.RecordingMode == DFConstantsAndEnums.RecordingMode.AutoCircularBufferMode
|
|
|| module.RecordingMode == DFConstantsAndEnums.RecordingMode.a16_CircularBufferAndStreamSubSampleMode
|
|
|| module.RecordingMode == DFConstantsAndEnums.RecordingMode.RAMActive
|
|
|| module.RecordingMode == DFConstantsAndEnums.RecordingMode.MultipleEventRAMActive)
|
|
{
|
|
ulong preTriggerSamples = Convert.ToUInt64(System.Math.Abs(module.PreTriggerSeconds * module.SampleRateHz + 1D));
|
|
if (preTriggerSamples < module.TriggerSampleNumbers[0])
|
|
{
|
|
module.StartRecordSampleNumber = module.TriggerSampleNumbers[0] - preTriggerSamples;
|
|
}
|
|
}
|
|
else if (module.RecordingMode == DFConstantsAndEnums.RecordingMode.AutoActiveMode ||
|
|
module.RecordingMode == DFConstantsAndEnums.RecordingMode.AerospaceWithMotion)
|
|
{
|
|
ulong preTriggerSamples = Convert.ToUInt64(System.Math.Abs(module.PreTriggerSeconds * module.SampleRateHz + 1D));
|
|
if (preTriggerSamples < module.TriggerSampleNumbers[0])
|
|
{
|
|
module.StartRecordSampleNumber = eventStartRecordSampleNumber;
|
|
}
|
|
}
|
|
|
|
#region Get_PTP_Event_Timestamp
|
|
|
|
|
|
module.StartRecordTimestampSec = startRecordTimestampSec;
|
|
module.TriggerTimestampSec = triggerTimestampSec;
|
|
module.StartRecordTimestampNanoSec = startRecordTimestampNanoSec;
|
|
module.TriggerTimestampNanoSec = triggerTimestampNanoSec;
|
|
module.PTPMasterSync = pTPMasterSync;
|
|
#endregion
|
|
|
|
#region Slice6TiltSensor
|
|
|
|
var tiltSensorDataPre = new short[3];
|
|
|
|
module.TiltSensorAxisXDegreesPre = double.NaN;
|
|
module.TiltSensorAxisYDegreesPre = double.NaN;
|
|
module.TiltSensorAxisZDegreesPre = double.NaN;
|
|
module.TiltSensorAxisXDegreesPost = double.NaN;
|
|
module.TiltSensorAxisYDegreesPost = double.NaN;
|
|
module.TiltSensorAxisZDegreesPost = double.NaN;
|
|
|
|
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.InSliceTiltSensorADCPre))
|
|
{
|
|
// Get the saved values from the final pre - test query(if any)
|
|
try
|
|
{
|
|
var query = new QueryEventAttribute(this)
|
|
{
|
|
Key = AttributeTypes.ArmAndEventAttributes.tiltSensorPreEventADC
|
|
};
|
|
query.SyncExecute();
|
|
tiltSensorDataPre = query.Value as short[];
|
|
}
|
|
catch (System.Exception ex) { APILogger.Log(ex); }
|
|
|
|
var tiltSensorCals = new double[18];
|
|
for (int tiltCalKeyOffset = 0; tiltCalKeyOffset < 18; tiltCalKeyOffset++)
|
|
{
|
|
var qSA_BS6 = new QuerySystemAttribute_BridgeSlice6(this);
|
|
qSA_BS6.DeviceID = 1;
|
|
qSA_BS6.Key = (AttributeTypes.SystemAttributes_BridgeSlice6)((int)AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_1 + tiltCalKeyOffset);
|
|
qSA_BS6.SyncExecute();
|
|
tiltSensorCals[tiltCalKeyOffset] = (float)qSA_BS6.Value;
|
|
}
|
|
|
|
var tiltDataEU = Test.Module.GetTiltDegreesEU(tiltSensorDataPre, tiltSensorCals, module.TiltAxes, module.AxisIgnored, new float[] { (float)module.MountOffsetAxisOne, (float)module.MountOffsetAxisTwo });
|
|
module.TiltSensorAxisXDegreesPre = tiltDataEU[0];
|
|
module.TiltSensorAxisYDegreesPre = tiltDataEU[1];
|
|
module.TiltSensorAxisZDegreesPre = tiltDataEU[2];
|
|
}
|
|
|
|
#endregion
|
|
|
|
progress.Step();
|
|
|
|
// update the channel info
|
|
for (var channelIdx = 0; channelIdx < module.Channels.Length; channelIdx++)
|
|
{
|
|
var channel = (DASChannel)module.Channels[channelIdx];
|
|
|
|
channel.OwningModule = module;
|
|
channel.EventStartTime = eventStartTime;
|
|
|
|
if (channel is AnalogInputDASChannel analog)
|
|
{
|
|
if (analog.ScalefactorMilliVoltsPerADC != factors[currentChannel])
|
|
{
|
|
//2019-04-11 toyota boshoku flatline data issue
|
|
APILogger.Log(
|
|
$"{SerialNumber}:{analog.Number} has a mismatched XML scale factor vs attribute scale factor ({analog.ScalefactorMilliVoltsPerADC} vs {factors[currentChannel]})");
|
|
analog.ScalefactorMilliVoltsPerADC = factors[currentChannel];
|
|
}
|
|
}
|
|
|
|
// CGO
|
|
// This is a hacked change for now to support 00G8 and prior firmware
|
|
// in the 1.04 release of SLICEWare. This and the other CGO commented
|
|
// block of code need more general cleanup before 1.05.
|
|
if (null == levelTriggerOffsetCorrection)
|
|
{
|
|
channel.LevelTriggerT0AdjustmentSamples = 0;
|
|
}
|
|
else if (currentChannel < levelTriggerOffsetCorrection.Length)
|
|
{
|
|
channel.LevelTriggerT0AdjustmentSamples = levelTriggerOffsetCorrection[currentChannel];
|
|
}
|
|
else
|
|
{
|
|
channel.LevelTriggerT0AdjustmentSamples = 0;
|
|
}
|
|
|
|
if (null == levelTriggerSeen)
|
|
{
|
|
channel.LevelTriggerSeen = false;
|
|
}
|
|
else if (currentChannel < levelTriggerSeen.Length)
|
|
{
|
|
channel.LevelTriggerSeen = levelTriggerSeen[currentChannel];
|
|
}
|
|
else
|
|
{
|
|
channel.LevelTriggerSeen = false;
|
|
}
|
|
|
|
currentChannel++;
|
|
progress.Step();
|
|
}
|
|
|
|
// store it in the object
|
|
eventInfo.Modules[moduleIdx] = module;
|
|
}
|
|
|
|
if (0 > info.EventIndex)
|
|
{
|
|
// store it in the object
|
|
dlReport.Events[eventIdx] = eventInfo;
|
|
}
|
|
else { EventInfo.Events[eventIdx] = eventInfo; }
|
|
}
|
|
// now assigned the data to the public property
|
|
if (0 > info.EventIndex)
|
|
{
|
|
SetEventInfo(dlReport);
|
|
}
|
|
|
|
SetEventFaultFlags(faultFlags);
|
|
((IDownload)this)?.SetExtendedFaultFlags(extendedFaultFlags.ToArray());
|
|
SetEventGuids(eventGuids);
|
|
SetEventArmAttemps(armAttempts);
|
|
|
|
info.Success();
|
|
}
|
|
catch (CanceledException)
|
|
{
|
|
info.Cancel();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
info.Error(ex.Message, ex);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Query downloaded status
|
|
|
|
void IDownloadActions.QueryDownloadedStatus(ServiceCallback callback, object userData)
|
|
{
|
|
var info = new SliceServiceAsyncInfo(callback, userData);
|
|
|
|
LaunchAsyncWorker("Slice.QueryDownloadedStatus", new WaitCallback(AsyncQueryDownloadedStatus), info);
|
|
}
|
|
|
|
private void AsyncQueryDownloadedStatus(object asyncInfo)
|
|
{
|
|
var info = asyncInfo as SliceServiceAsyncInfo;
|
|
|
|
try
|
|
{
|
|
var EventCount = new QueryTotalEventCount(this);
|
|
EventCount.SyncExecute();
|
|
|
|
var config = GetConfigAttributes(this);//new ConfigAttributes(this);
|
|
|
|
var progress = new QueryDownloadProgress(info, EventCount.Count + 1, 1);
|
|
|
|
var eventDownloadedStatus = new bool[EventCount.Count];
|
|
var eventGuids = new Guid[EventCount.Count];
|
|
for (int eventIdx = 0; eventIdx < EventCount.Count; eventIdx++)
|
|
{
|
|
eventDownloadedStatus[eventIdx] = config.EventHasBeenDownloaded(eventIdx, out uint flag); // I/O
|
|
progress.Step();
|
|
try
|
|
{
|
|
eventGuids[eventIdx] = GetEventGuid(eventIdx);
|
|
}
|
|
catch (Exception) { eventGuids[eventIdx] = Guid.NewGuid(); }
|
|
}
|
|
// now assigned the data to the public property
|
|
SetEventDownloadStatus(eventDownloadedStatus);
|
|
SetEventGuids(eventGuids);
|
|
info.Success();
|
|
}
|
|
catch (CanceledException)
|
|
{
|
|
info.Cancel();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
info.Error(ex.Message, ex);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Set trigger sample numbers
|
|
|
|
void IDownloadActions.SetTriggerSampleNumbers(ServiceCallback callback, object userData)
|
|
{
|
|
var info = new SliceServiceAsyncInfo(callback, userData);
|
|
|
|
LaunchAsyncWorker("Slice.SetTriggerSampleNumbers", new WaitCallback(AsyncSetTriggerSampleNumbers), info);
|
|
}
|
|
|
|
private void AsyncSetTriggerSampleNumbers(object asyncInfo)
|
|
{
|
|
var info = asyncInfo as SliceServiceAsyncInfo;
|
|
|
|
try
|
|
{
|
|
if (EventInfo == null || EventInfo.Events == null || EventInfo.Events.Length == 0 ||
|
|
EventInfo.Events[0].Modules == null || EventInfo.Events[0].Modules.Length == 0)
|
|
{
|
|
info.Error("SetTriggerSampleNumbers: EventInfo, Events or Modules are null or empty");
|
|
return;
|
|
}
|
|
|
|
var config = GetConfigAttributes(this);//new ConfigAttributes(this);
|
|
|
|
for (int eventIdx = 0; eventIdx < EventInfo.Events.Length; eventIdx++)
|
|
{
|
|
if (EventInfo.Events[eventIdx].Modules != null && EventInfo.Events[eventIdx].Modules.Length > 0 &&
|
|
EventInfo.Events[eventIdx].Modules[0].TriggerSampleNumbers.Length > 0)
|
|
{
|
|
// we only support 1 trigger at this point
|
|
config.SetEventTriggerSampleNumber(eventIdx, EventInfo.Events[eventIdx].Modules[0].TriggerSampleNumbers[0]);
|
|
}
|
|
}
|
|
|
|
info.Success();
|
|
}
|
|
catch (CanceledException)
|
|
{
|
|
info.Cancel();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
info.Error(ex.Message, ex);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Set downloaded
|
|
void IDownloadActions.SetDownloaded(ServiceCallback callback, object userData)
|
|
{
|
|
var info = new SliceServiceAsyncInfo(callback, userData);
|
|
|
|
LaunchAsyncWorker("Slice.SetDownloaded", new WaitCallback(AsyncSetDownloaded), info);
|
|
}
|
|
|
|
private void AsyncSetDownloaded(object asyncInfo)
|
|
{
|
|
var info = asyncInfo as SliceServiceAsyncInfo;
|
|
|
|
try
|
|
{
|
|
if (EventInfo == null || EventInfo.Events == null || EventInfo.Events.Length == 0 ||
|
|
EventInfo.Events[0].Modules == null || EventInfo.Events[0].Modules.Length == 0)
|
|
{
|
|
info.Error("SetDownloaded: EventInfo, Events or Modules are null or empty");
|
|
return;
|
|
}
|
|
|
|
var config = GetConfigAttributes(this);
|
|
|
|
for (var eventIdx = 0; eventIdx < EventInfo.Events.Length; eventIdx++)
|
|
{
|
|
if (EventInfo.Events[eventIdx].Modules != null && EventInfo.Events[eventIdx].Modules.Length > 0 &&
|
|
EventInfo.Events[eventIdx].Modules[0].TriggerSampleNumbers.Length > 0)
|
|
{
|
|
config.SetEventDownloaded(eventIdx, 1);
|
|
}
|
|
}
|
|
|
|
info.Success();
|
|
}
|
|
catch (CanceledException)
|
|
{
|
|
info.Cancel();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
info.Error(ex.Message, ex);
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|