init
This commit is contained in:
923
DataPRO/IService/Classes/SLICEService/SLICE Service.Realtime.cs
Normal file
923
DataPRO/IService/Classes/SLICEService/SLICE Service.Realtime.cs
Normal file
@@ -0,0 +1,923 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using DTS.Common.ICommunication;
|
||||
using DTS.DASLib.Command.SLICE;
|
||||
using DTS.Common.Utilities.Logging;
|
||||
using DTS.DASLib.Command;
|
||||
using DTS.DASLib.Command.SLICE.RealtimeCommands;
|
||||
using DTS.Common.Interface.Connection;
|
||||
using DTS.Common.Enums.DASFactory;
|
||||
using DTS.Common.Interface.DASFactory;
|
||||
using System.Threading.Tasks;
|
||||
using DTS.Common.Enums;
|
||||
using DTS.Common.Classes.DASFactory;
|
||||
|
||||
namespace DTS.DASLib.Service
|
||||
{
|
||||
public partial class Slice<T> : Communication<T>,
|
||||
IDASCommunication,
|
||||
IConfigurationActions,
|
||||
IDiagnosticsActions,
|
||||
ITriggerCheckActions,
|
||||
IRealTimeActions,
|
||||
IArmActions,
|
||||
IDownloadActions where T : IConnection, new()
|
||||
{
|
||||
#region Real time
|
||||
public virtual bool ControlsDAQ() { return true; }
|
||||
|
||||
public virtual bool SupportsRealtime()
|
||||
{
|
||||
return !IsTOM();
|
||||
}
|
||||
|
||||
public virtual bool SupportsMultipleEvents() { return IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.MultipleAndHybridEvents); }
|
||||
public virtual bool SupportsMultipleConfigurations() { return IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.MultipleConfigurations); }
|
||||
public virtual bool SupportsAutoArm() { return IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArm); }
|
||||
public virtual bool SupportsLevelTrigger() { return IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.LevelTrigger); }
|
||||
public bool SupportsHardwareInputCheck() { return IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines); }
|
||||
protected bool _bSupportsMultipleSampleRealtime = true;
|
||||
public bool SupportsMultipleSampleRealtime() { return _bSupportsMultipleSampleRealtime; }
|
||||
|
||||
|
||||
protected class RealTimeAsyncPacket
|
||||
{
|
||||
public SliceServiceAsyncInfo Info { get; set; }
|
||||
public Timer Timer { get; set; }
|
||||
public int SamplesPerSecond { get; set; }
|
||||
public int MillisecBetweenSamples { get; set; }
|
||||
public bool AllowMultipleSampleRealtime { get; set; }
|
||||
public ManualResetEvent StopEvent { get; set; }
|
||||
public byte[] Channels { get; set; }
|
||||
public double AAF { get; set; }
|
||||
public int minCallbackUpdateTimeMs { get; set; }
|
||||
public bool UseUDPStreaming { get; set; } = false;
|
||||
public int StreamPortOffset { get; set; }
|
||||
public string HostIPAddress { get; set; } = IPAddress.Any.ToString();
|
||||
}
|
||||
|
||||
protected class RealTimeTiltAsyncPacket
|
||||
{
|
||||
public SliceServiceAsyncInfo Info { get; set; }
|
||||
public double[] TiltInDegrees { get; set; }
|
||||
public ManualResetEvent StopEvent { get; set; }
|
||||
}
|
||||
|
||||
// FB15313: Add UDP streaming options
|
||||
protected class RealTimeUDPStreamProfileAsyncPacket
|
||||
{
|
||||
public SliceServiceAsyncInfo Info { get; set; }
|
||||
public UDPStreamProfile Profile { get; set; }
|
||||
public string UDPAddress { get; set; }
|
||||
public ushort TimeDataChannelId { get; set; }
|
||||
public uint[] TMNSConfig { get; set; }
|
||||
public ushort DataChannelId { get; set; }
|
||||
public ushort IRIGTimeDataPacketIntervalMs { get; set; }
|
||||
}
|
||||
|
||||
void IRealTimeActions.RealTime(int samplesPerSecond,
|
||||
int millisecBetweenSamples,
|
||||
ServiceCallback callback,
|
||||
object userData,
|
||||
bool allowMultipleSampleRealtime,
|
||||
int moduleIndex,
|
||||
ManualResetEvent stopEvent,
|
||||
byte[] channels,
|
||||
double aaf,
|
||||
int minCallbackUpdateTimeMs,
|
||||
bool UseUDPStreaming,
|
||||
string hostIPAddress)
|
||||
{
|
||||
var packet = new RealTimeAsyncPacket();
|
||||
packet.StopEvent = stopEvent;
|
||||
packet.Info = new SliceServiceAsyncInfo(callback, userData);
|
||||
packet.MillisecBetweenSamples = millisecBetweenSamples;
|
||||
packet.SamplesPerSecond = samplesPerSecond;
|
||||
packet.AllowMultipleSampleRealtime = allowMultipleSampleRealtime;
|
||||
packet.Channels = channels;
|
||||
packet.AAF = aaf;
|
||||
packet.minCallbackUpdateTimeMs = minCallbackUpdateTimeMs;
|
||||
packet.UseUDPStreaming = UseUDPStreaming;
|
||||
packet.StreamPortOffset = moduleIndex; // FB15388: udp ports must be unique, start index-0 unit at the default and iterate offset from there
|
||||
packet.HostIPAddress = hostIPAddress;
|
||||
LaunchAsyncWorker("Slice.RealTime", AsyncRealTime, packet);
|
||||
}
|
||||
|
||||
void IRealTimeActions.RealTimePolling(ServiceCallback callback,
|
||||
object userData,
|
||||
ManualResetEvent stopEvent,
|
||||
byte[] channels)
|
||||
{
|
||||
var packet = new RealTimeAsyncPacket
|
||||
{
|
||||
StopEvent = stopEvent,
|
||||
Info = new SliceServiceAsyncInfo(callback, userData),
|
||||
Channels = channels
|
||||
};
|
||||
LaunchAsyncWorker("Slice.RealtimePolling", AsyncRealTimePolling, packet);
|
||||
}
|
||||
/// <summary>
|
||||
/// returns an object implementing IGetRealtimeSamples capable of returning realtime samples
|
||||
/// </summary>
|
||||
/// <param name="iCommunication"></param>
|
||||
/// <param name="bPolling">whether realtime is polling or not</param>
|
||||
/// <returns></returns>
|
||||
protected virtual IGetRealtimeSamples GetRealtimeSamplesClass(DTS.Common.Interface.DASFactory.ICommunication iCommunication, bool bPolling = false)
|
||||
{
|
||||
return new GetRealtimeSamples(iCommunication, 2000, bPolling);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// indicates whether the DAS supports streaming
|
||||
/// 10572 implement SW side for single command streaming realtime
|
||||
/// </summary>
|
||||
public virtual bool SupportsIndividualChannelRealtimeStreaming => false;
|
||||
|
||||
/// <summary>
|
||||
/// indicates whether the das supports udp streaming
|
||||
/// 15160 Port UDP Realtime Stream from FWTU
|
||||
/// </summary>
|
||||
public virtual bool SupportsUDPRealtimeStreaming => false;
|
||||
/// <summary>
|
||||
/// depending on firmware, some devices will send back all channels even if you request less while others will send back what's requested.
|
||||
/// DataPRO is always expecting all channels to be returned. fix for these models is to always request all
|
||||
/// 31829 Datapro s6air br shows noise in realtime view chart that is not real noise and does not show up in fwtu realtime or recorded
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual byte[] GetRTChannelIndices(RealTimeAsyncPacket packet)
|
||||
{
|
||||
return packet.Channels;
|
||||
}
|
||||
/// <summary>
|
||||
/// this is the minimum of time between data callbacks for realtime
|
||||
/// this should be moved to the settings file, but it is fine here
|
||||
/// for now since there is the ms between samples setting and
|
||||
/// only the g8 and older firmware need to request samples at a fast rate
|
||||
/// </summary>
|
||||
//protected const int MIN_CALLBACK_UPDATE_TIME = 20;
|
||||
private void AsyncRealTime(object asyncInfo)
|
||||
{
|
||||
var packet = asyncInfo as RealTimeAsyncPacket;
|
||||
try
|
||||
{
|
||||
var ssaPolarity = new SetSystemAttribute(this, AbstractCommandBase.Default_IO_Timeout);
|
||||
ssaPolarity.SetValue(AttributeTypes.SystemAttributes.TriggerPolarity, (byte)(InvertTrigger ? 1 : 0), true);
|
||||
ssaPolarity.SyncExecute();
|
||||
ssaPolarity = new SetSystemAttribute(this, AbstractCommandBase.Default_IO_Timeout);
|
||||
ssaPolarity.SetValue(AttributeTypes.SystemAttributes.StartRecordPolarity, (byte)(InvertStart ? 1 : 0), true);
|
||||
ssaPolarity.SyncExecute();
|
||||
|
||||
// Set sample rate and adjustable anti-alias filter frequency in the
|
||||
// hardware based on the milliseconds between samples parameter that
|
||||
// was passed in via the RealTimeAsyncPacket object. Keep the filter
|
||||
// -3dB point at 1/5 the frequency of the sample rate.
|
||||
// number of samples per second
|
||||
var rtSampleRate = Convert.ToUInt32(packet.SamplesPerSecond);
|
||||
var uiMillisecondsBetweenSamples = packet.MillisecBetweenSamples;
|
||||
var setSampleRate = new SetRealtimeSampleRate(this);
|
||||
setSampleRate.SetValue(rtSampleRate);
|
||||
setSampleRate.SyncExecute();
|
||||
|
||||
var lastUpdate = DateTime.MinValue;
|
||||
StreamReaderUDP streamReader = null;
|
||||
|
||||
if (SupportsIndividualChannelRealtimeStreaming)
|
||||
{
|
||||
try
|
||||
{
|
||||
var saa = new SetArmAttribute(this);
|
||||
saa.SetValue(AttributeTypes.ArmAndEventAttributes.RealtimeAAFilterFrequencyHz,
|
||||
Convert.ToSingle(packet.AAF), true);
|
||||
saa.SyncExecute();
|
||||
|
||||
if (packet.UseUDPStreaming && SupportsUDPRealtimeStreaming)
|
||||
{
|
||||
//FB 18152 find the host ip
|
||||
string dasIp;
|
||||
string hostIpAddress = "";
|
||||
if (Common.Utils.NetworkUtils.TryParseConnectionString(ConnectString, out dasIp))
|
||||
{
|
||||
hostIpAddress = Common.Utils.PingUtils.DasToHost[dasIp].HostIpAddress;
|
||||
}
|
||||
else
|
||||
{ // We should not get here since SupportsUDPRealtimeStreaming is false for USB devices but just in case have a guard
|
||||
APILogger.Log("Streaming realtime with UDP is not supported for USB devices.");
|
||||
return;
|
||||
}
|
||||
|
||||
var udpAddress = new UriBuilder(DFConstantsAndEnums.RealtimeUDPAddress);
|
||||
udpAddress.Port += packet.StreamPortOffset;
|
||||
streamReader = new StreamReaderUDP(udpAddress.Uri.AbsoluteUri, hostIpAddress, UDPStreamProfile.DTS_UDP, packet.Channels);
|
||||
|
||||
var startTimeStampRealtime = new StartTimeStampStreamMode(this);
|
||||
startTimeStampRealtime.ParamsToSend = streamReader.cmdline.ToArray();
|
||||
startTimeStampRealtime.SyncExecute();
|
||||
}
|
||||
else
|
||||
{
|
||||
var startRT = new StartRealtimeStreamingMode(this, GetRTChannelIndices(packet));
|
||||
startRT.SyncExecute();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
APILogger.Log(ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var startRT = new StartRealtimeMode(this);
|
||||
startRT.SupportsMultipleSampleRealtime =
|
||||
packet.AllowMultipleSampleRealtime && SupportsMultipleSampleRealtime();
|
||||
startRT.SyncExecute();
|
||||
}
|
||||
var sampleNumbers = new List<ulong>(100);
|
||||
var timeStamps = new List<ulong>(100);
|
||||
var sequenceNumbers = new List<ulong>(100);
|
||||
var data = new List<short[][]>(100);
|
||||
// start calling for RT data
|
||||
|
||||
var getRTdata = GetRealtimeSamplesClass(this);
|
||||
getRTdata.LogCommands = false;
|
||||
|
||||
var numChannels = 0;
|
||||
|
||||
foreach (var mod in DASInfo.Modules)
|
||||
{
|
||||
switch (mod.TypeOfModule)
|
||||
{
|
||||
case DFConstantsAndEnums.ModuleType.EmbeddedMicrophone:
|
||||
case DFConstantsAndEnums.ModuleType.EmbeddedMagnetometer:
|
||||
case DFConstantsAndEnums.ModuleType.EmbeddedMagnetInput:
|
||||
case DFConstantsAndEnums.ModuleType.UART:
|
||||
case DFConstantsAndEnums.ModuleType.StreamOut:
|
||||
case DFConstantsAndEnums.ModuleType.StreamIn:
|
||||
continue;
|
||||
default:
|
||||
numChannels += (int)mod.NumberOfChannels;
|
||||
break;
|
||||
}
|
||||
}
|
||||
getRTdata.Channels = (ushort)numChannels;
|
||||
if (SerialNumber.StartsWith("SPD") || SerialNumber.StartsWith("SLD"))
|
||||
{
|
||||
if (getRTdata is RealtimeStreamingNextSamples cmd)
|
||||
{
|
||||
cmd.DigitalInput = true;
|
||||
var transitions = new List<bool>();
|
||||
foreach (var mod in ConfigData.Modules)
|
||||
{
|
||||
foreach (var channel in mod.Channels)
|
||||
{
|
||||
var aic = (AnalogInputDASChannel)channel;
|
||||
switch (aic.DigitalMode)
|
||||
{
|
||||
case DigitalInputModes.CCNC:
|
||||
case DigitalInputModes.CCNO:
|
||||
transitions.Add(false);
|
||||
break;
|
||||
case DigitalInputModes.THL:
|
||||
case DigitalInputModes.TLH:
|
||||
transitions.Add(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
cmd.TransitionMode = transitions.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
while (!packet.StopEvent.WaitOne(0, false))
|
||||
{
|
||||
if (null != streamReader)
|
||||
{
|
||||
try
|
||||
{
|
||||
var udpPacket = streamReader.Read();
|
||||
if (null != udpPacket)
|
||||
{
|
||||
data.Add(udpPacket.ChannelData);
|
||||
sampleNumbers.Add(udpPacket.SampleNumber);
|
||||
timeStamps.Add( /*Convert.ToUInt64(udpPacket.TimeStamp)*/0);
|
||||
sequenceNumbers.Add(udpPacket.SequenceNumber);
|
||||
|
||||
var newData = new NewDataData(data.ToArray(), sampleNumbers.ToArray(),
|
||||
timeStamps.ToArray(),
|
||||
sequenceNumbers.ToArray());
|
||||
|
||||
Task.Run(() => { packet.Info.NewData(newData); });
|
||||
|
||||
sampleNumbers.Clear();
|
||||
timeStamps.Clear();
|
||||
sequenceNumbers.Clear();
|
||||
data.Clear();
|
||||
}
|
||||
}
|
||||
catch (SocketException sox) //FB15531: Don't silently consume realtime errors
|
||||
{
|
||||
//if it's a timeout it could just be that there's no data yet,
|
||||
//give the device a chance to send data
|
||||
if (sox.SocketErrorCode != SocketError.TimedOut)
|
||||
{
|
||||
throw sox;
|
||||
}
|
||||
}
|
||||
catch (CommandException ce)
|
||||
{
|
||||
if (ce.Error == CommandErrorReason.ReceiveFailed ||
|
||||
ce.Error == CommandErrorReason.SendFailed)
|
||||
{
|
||||
packet.Info.Error(ce.Message, new Common.Classes.Connection.NotConnectedException(ce.Message));
|
||||
return;
|
||||
}
|
||||
//15909 Crash in Realtime when connection is lost
|
||||
//in the case of a communication error in start realtime, notify consumer
|
||||
packet.Info.Error(ce.Message, ce);
|
||||
return;
|
||||
}
|
||||
catch (Common.Classes.Connection.NotConnectedException nce)
|
||||
{
|
||||
//15909 Crash in Realtime when connection is lost
|
||||
//in the case of a communication error in start realtime, notify consumer
|
||||
packet.Info.Error(nce.Message, nce);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Trace.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// call HW to get RT samples
|
||||
try
|
||||
{
|
||||
getRTdata.SyncExecute();
|
||||
|
||||
}
|
||||
catch (CommandException ce)
|
||||
{
|
||||
if (ce.Error == CommandErrorReason.ReceiveFailed ||
|
||||
ce.Error == CommandErrorReason.SendFailed)
|
||||
{
|
||||
packet.Info.Error(ce.Message, new Common.Classes.Connection.NotConnectedException(ce.Message));
|
||||
return;
|
||||
}
|
||||
//15909 Crash in Realtime when connection is lost
|
||||
//in the case of a communication error in start realtime, notify consumer
|
||||
packet.Info.Error(ce.Message, ce);
|
||||
return;
|
||||
}
|
||||
catch (Common.Classes.Connection.NotConnectedException nce)
|
||||
{
|
||||
//15909 Crash in Realtime when connection is lost
|
||||
//in the case of a communication error in start realtime, notify consumer
|
||||
packet.Info.Error(nce.Message, nce);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
APILogger.Log(ex);
|
||||
}
|
||||
|
||||
if (getRTdata.SamplesReturned > 0)
|
||||
{
|
||||
var rtData = new short[getRTdata.Channels][];
|
||||
for (int idx = 0; idx < getRTdata.Channels; idx++)
|
||||
{
|
||||
rtData[idx] = getRTdata.GetChannelData(idx);
|
||||
}
|
||||
|
||||
sampleNumbers.Add(getRTdata.SampleNumber);
|
||||
timeStamps.Add(getRTdata.TimeStamp);
|
||||
sequenceNumbers.Add(getRTdata.SequenceNumber);
|
||||
data.Add(rtData);
|
||||
}
|
||||
|
||||
if (DateTime.Now.Subtract(lastUpdate).TotalMilliseconds >= packet.minCallbackUpdateTimeMs)
|
||||
{
|
||||
lastUpdate = DateTime.Now;
|
||||
|
||||
if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.StartRealtimeStream))
|
||||
{
|
||||
var ihl =
|
||||
new InitializeHardwareLines(this, AbstractCommandBase.Default_IO_Timeout);
|
||||
ihl.LogCommands = false;
|
||||
try
|
||||
{
|
||||
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands
|
||||
.InitHardwareInputLines) &&
|
||||
!packet.StopEvent.WaitOne(0, false))
|
||||
{
|
||||
ihl.SyncExecute();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
} //TODO: Where is an Exception?
|
||||
|
||||
var d1 = new short[1][];
|
||||
|
||||
d1[0] = new short[2];
|
||||
d1[0][0] = (short)(ihl.StartRecordShorted ? 1 : 0);
|
||||
d1[0][1] = (short)(ihl.TriggerInputShorted ? 1 : 0);
|
||||
|
||||
data.Add(d1);
|
||||
sampleNumbers.Add(ulong.MaxValue);
|
||||
timeStamps.Add(ulong.MinValue);
|
||||
sequenceNumbers.Add(ulong.MinValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Thread.Sleep(50);
|
||||
}
|
||||
|
||||
ThreadPool.QueueUserWorkItem(packet.Info.NewData,
|
||||
new NewDataData(data.ToArray(), sampleNumbers.ToArray(), timeStamps.ToArray(),
|
||||
sequenceNumbers.ToArray()));
|
||||
|
||||
sampleNumbers.Clear();
|
||||
timeStamps.Clear();
|
||||
sequenceNumbers.Clear();
|
||||
data.Clear();
|
||||
}
|
||||
}
|
||||
Thread.Sleep(uiMillisecondsBetweenSamples);
|
||||
}
|
||||
var endRealtime = new EndRealtimeMode(this);
|
||||
endRealtime.SyncExecute();
|
||||
packet.Info.Success();
|
||||
}
|
||||
catch (CanceledException)
|
||||
{
|
||||
packet.Info.Cancel();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
packet.Info.Error(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
private void AsyncRealTimePolling(object asyncInfo)
|
||||
{
|
||||
var packet = asyncInfo as RealTimeAsyncPacket;
|
||||
|
||||
try
|
||||
{
|
||||
var ssaPolarity = new SetSystemAttribute(this, AbstractCommandBase.Default_IO_Timeout);
|
||||
ssaPolarity.SetValue(AttributeTypes.SystemAttributes.TriggerPolarity, (byte)(InvertTrigger ? 1 : 0), true);
|
||||
ssaPolarity.SyncExecute();
|
||||
ssaPolarity = new SetSystemAttribute(this, AbstractCommandBase.Default_IO_Timeout);
|
||||
ssaPolarity.SetValue(AttributeTypes.SystemAttributes.StartRecordPolarity, (byte)(InvertStart ? 1 : 0), true);
|
||||
ssaPolarity.SyncExecute();
|
||||
|
||||
// Set sample rate and adjustable anti-alias filter frequency in the
|
||||
// hardware based on the milliseconds between samples parameter that
|
||||
// was passed in via the RealTimeAsyncPacket object. Keep the filter
|
||||
// -3dB point at 1/5 the frequency of the sample rate.
|
||||
// number of samples per second
|
||||
var rtSampleRate = Convert.ToUInt32(50);
|
||||
const int uiMillisecondsBetweenSamples = 200;
|
||||
var setSampleRate = new SetRealtimeSampleRate(this);
|
||||
setSampleRate.SetValue(rtSampleRate);
|
||||
setSampleRate.SyncExecute();
|
||||
|
||||
|
||||
DateTime lastUpdate = DateTime.MinValue;
|
||||
// set RT mode in HW
|
||||
var startRT = new StartRealtimeMode(this);
|
||||
startRT.SupportsMultipleSampleRealtime = true;
|
||||
startRT.SyncExecute();
|
||||
var sampleNumbers = new List<ulong>(100);
|
||||
var timeStamps = new List<ulong>(100);
|
||||
var sequenceNumbers = new List<ulong>(100);
|
||||
var data = new List<short[][]>(100);
|
||||
// start calling for RT data
|
||||
var getRTdata = GetRealtimeSamplesClass(this, true);
|
||||
getRTdata.LogCommands = false;
|
||||
getRTdata.Channels = (ushort)DASInfo.Modules.Sum(m => m.NumberOfChannels);
|
||||
while (!packet.StopEvent.WaitOne(0, false))
|
||||
{
|
||||
// call HW to get RT samples
|
||||
try
|
||||
{
|
||||
getRTdata.SyncExecute();
|
||||
}
|
||||
catch (Exception ex) { APILogger.Log(ex); }
|
||||
if (getRTdata.SamplesReturned > 0)
|
||||
{
|
||||
var rtData = new short[getRTdata.Channels][];
|
||||
for (var idx = 0; idx < getRTdata.Channels; idx++)
|
||||
{
|
||||
rtData[idx] = getRTdata.GetChannelData(idx);
|
||||
}
|
||||
sampleNumbers.Add(getRTdata.SampleNumber);
|
||||
timeStamps.Add(getRTdata.TimeStamp);
|
||||
sequenceNumbers.Add(getRTdata.SequenceNumber);
|
||||
data.Add(rtData);
|
||||
}
|
||||
if (DateTime.Now.Subtract(lastUpdate).TotalMilliseconds >= packet.minCallbackUpdateTimeMs)
|
||||
{
|
||||
lastUpdate = DateTime.Now;
|
||||
|
||||
var ihl = new InitializeHardwareLines(this, AbstractCommandBase.Default_IO_Timeout);
|
||||
ihl.LogCommands = false;
|
||||
try
|
||||
{
|
||||
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines) && !packet.StopEvent.WaitOne(0, false))
|
||||
{
|
||||
ihl.SyncExecute();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { APILogger.Log(ex); }
|
||||
|
||||
if (Common.Constants.CheckStatusLinesInRealtime)
|
||||
{
|
||||
var d1 = new short[1][];
|
||||
|
||||
d1[0] = new short[2];
|
||||
d1[0][0] = (short)(ihl.StartRecordShorted ? 1 : 0);
|
||||
d1[0][1] = (short)(ihl.TriggerInputShorted ? 1 : 0);
|
||||
|
||||
data.Add(d1);
|
||||
sampleNumbers.Add(ulong.MaxValue);
|
||||
}
|
||||
//15244 Cannot run meter mode in realtime
|
||||
timeStamps.Add(ulong.MinValue);
|
||||
ThreadPool.QueueUserWorkItem(packet.Info.NewData, new NewDataData(data.ToArray(), sampleNumbers.ToArray(), timeStamps.ToArray(), sequenceNumbers.ToArray()));
|
||||
|
||||
sampleNumbers.Clear();
|
||||
timeStamps.Clear();
|
||||
sequenceNumbers.Clear();
|
||||
data.Clear();
|
||||
}
|
||||
Thread.Sleep(uiMillisecondsBetweenSamples);
|
||||
}
|
||||
var exitRT = new EndRealtimeMode(this);
|
||||
exitRT.SyncExecute();
|
||||
packet.Info.Success();
|
||||
}
|
||||
catch (CanceledException)
|
||||
{
|
||||
packet.Info.Cancel();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
packet.Info.Error(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
void IRealTimeActions.ExitRealTimeMode(ServiceCallback callback, object userData)
|
||||
{
|
||||
var info = new SliceServiceAsyncInfo(callback, userData);
|
||||
|
||||
LaunchAsyncWorker("Slice.ExitRealTimeMode", new WaitCallback(AsyncExitRealTimeMode), info);
|
||||
}
|
||||
|
||||
private void AsyncExitRealTimeMode(object asyncInfo)
|
||||
{
|
||||
var info = asyncInfo as SliceServiceAsyncInfo;
|
||||
if (!SupportsRealtime())
|
||||
{
|
||||
if (null != DASArmStatus) DASArmStatus.IsInRealtime = false;// FB15550: Update IsInRealtime flag if we exit RT so DataPRO is aware
|
||||
info.Success();
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var exitRT = new EndRealtimeMode(this);
|
||||
exitRT.SyncExecute();
|
||||
if (null != DASArmStatus && RecordingModeExtensions.IsAStreamMode((DFConstantsAndEnums.RecordingMode)DASArmStatus.RecordingMode))
|
||||
{
|
||||
//for safety unset the auto arm flag in case the user reboots ...
|
||||
DisAutoArm();
|
||||
}
|
||||
if (null != DASArmStatus) DASArmStatus.IsInRealtime = false; // FB15550: Update IsInRealtime flag if we exit RT so DataPRO is aware
|
||||
info.Success();
|
||||
}
|
||||
catch (CanceledException)
|
||||
{
|
||||
info.Cancel();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
info.Error(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
void IRealTimeActions.RealTimeTiltPolling(ServiceCallback callback,
|
||||
object userData,
|
||||
ManualResetEvent stopEvent)
|
||||
|
||||
{
|
||||
var packet = new RealTimeTiltAsyncPacket();
|
||||
packet.StopEvent = stopEvent;
|
||||
packet.Info = new SliceServiceAsyncInfo(callback, userData);
|
||||
LaunchAsyncWorker("Slice.RealTimeTiltPolling", AsyncRealTimeTiltPolling, packet);
|
||||
}
|
||||
|
||||
private void AsyncRealTimeTiltPolling(object asyncInfo)
|
||||
{
|
||||
var packet = asyncInfo as RealTimeTiltAsyncPacket;
|
||||
|
||||
try
|
||||
{
|
||||
while (!packet.StopEvent.WaitOne(0, false))
|
||||
{
|
||||
var axisADCData = new short[3] { 0, 0, 0 };
|
||||
var calFactor = new double[3] { 1, 1, 1 };
|
||||
var zeroData = new double[3] { 0, 0, 0 };
|
||||
|
||||
// Get raw tilt ADC
|
||||
var qtsd = new QueryTiltSensorData(this);
|
||||
qtsd.DeviceID = 1;
|
||||
qtsd.SyncExecute();
|
||||
axisADCData[0] = qtsd.Channel1ValueAdc;
|
||||
axisADCData[1] = qtsd.Channel2ValueAdc;
|
||||
axisADCData[2] = qtsd.Channel3ValueAdc;
|
||||
|
||||
//Get tilt sensor scale factors
|
||||
var scaleFactorGPerADC = new float[3] { 1, 1, 1 };
|
||||
if (RunTestVariables.InRunTest && RunTestVariables.TiltSensorScaleFactor > 0)
|
||||
{
|
||||
scaleFactorGPerADC = new[]
|
||||
{
|
||||
RunTestVariables.TiltSensorScaleFactor, RunTestVariables.TiltSensorScaleFactor,
|
||||
RunTestVariables.TiltSensorScaleFactor
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
var scaleFactorQuery = new QueryArmAttribute(this)
|
||||
{
|
||||
Key = AttributeTypes.ArmAndEventAttributes.InSliceTiltSensorScaleFactorGPerADC
|
||||
};
|
||||
scaleFactorQuery.SyncExecute();
|
||||
scaleFactorGPerADC = scaleFactorQuery.Value as float[];
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
int dominantAxis = (axisADCData.Max() < Math.Abs(axisADCData.Min())) ?
|
||||
Array.IndexOf(axisADCData, axisADCData.Min()) : Array.IndexOf(axisADCData, axisADCData.Max());
|
||||
|
||||
var query = new QuerySystemAttribute_BridgeSlice6(this);
|
||||
query.DeviceID = 1;
|
||||
|
||||
try
|
||||
{
|
||||
query.Key = AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_1;
|
||||
query.SyncExecute();
|
||||
calFactor[0] = Convert.ToDouble(query.Value) == 0D ? 1D : Convert.ToDouble(query.Value);
|
||||
|
||||
query.Key = AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_7;
|
||||
query.SyncExecute();
|
||||
calFactor[1] = Convert.ToDouble(query.Value) == 0D ? 1D : Convert.ToDouble(query.Value);
|
||||
|
||||
query.Key = AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_13;
|
||||
query.SyncExecute();
|
||||
calFactor[2] = Convert.ToDouble(query.Value) == 0D ? 1D : Convert.ToDouble(query.Value);
|
||||
}
|
||||
catch { }
|
||||
|
||||
|
||||
// Calculate Accel Data
|
||||
var accelData = new double[3];
|
||||
for (int i = 0; i < accelData.Length; i++)
|
||||
{
|
||||
var channel_2G = (axisADCData[i] / calFactor[i]) * scaleFactorGPerADC[i];
|
||||
if (channel_2G > 1)
|
||||
{
|
||||
channel_2G = 1;
|
||||
}
|
||||
else if (channel_2G < -1)
|
||||
{
|
||||
channel_2G = -1;
|
||||
}
|
||||
|
||||
accelData[i] = channel_2G;
|
||||
}
|
||||
|
||||
|
||||
bool positivePolarity = (axisADCData[dominantAxis] > 0);
|
||||
|
||||
switch (dominantAxis)
|
||||
{
|
||||
case 0:
|
||||
query.Key = AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_2;
|
||||
break;
|
||||
case 1:
|
||||
query.Key = AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_8;
|
||||
break;
|
||||
case 2:
|
||||
query.Key = AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_14;
|
||||
break;
|
||||
default:
|
||||
query.Key = AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_2;
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
query.SyncExecute();
|
||||
zeroData[dominantAxis] = Convert.ToDouble(query.Value);
|
||||
}
|
||||
catch { }
|
||||
|
||||
var query2 = new QuerySystemAttribute_BridgeSlice6(this);
|
||||
query2.DeviceID = 1;
|
||||
|
||||
switch (dominantAxis)
|
||||
{
|
||||
case 0:
|
||||
query.Key = positivePolarity ? AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_9 : AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_10;
|
||||
query2.Key = positivePolarity ? AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_15 : AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_16;
|
||||
break;
|
||||
case 1:
|
||||
query.Key = positivePolarity ? AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_3 : AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_4;
|
||||
query2.Key = positivePolarity ? AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_17 : AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_18;
|
||||
break;
|
||||
case 2:
|
||||
query.Key = positivePolarity ? AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_5 : AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_6;
|
||||
query2.Key = positivePolarity ? AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_11 : AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_12;
|
||||
break;
|
||||
default:
|
||||
query.Key = positivePolarity ? AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_9 : AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_10;
|
||||
query2.Key = positivePolarity ? AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_15 : AttributeTypes.SystemAttributes_BridgeSlice6.TILTSENSOR_CAL_16;
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
query.SyncExecute();
|
||||
query2.SyncExecute();
|
||||
|
||||
switch (dominantAxis)
|
||||
{
|
||||
case 0:
|
||||
zeroData[1] = Convert.ToDouble(query.Value);
|
||||
zeroData[2] = Convert.ToDouble(query2.Value);
|
||||
break;
|
||||
case 1:
|
||||
zeroData[0] = Convert.ToDouble(query.Value);
|
||||
zeroData[2] = Convert.ToDouble(query2.Value);
|
||||
break;
|
||||
case 2:
|
||||
zeroData[0] = Convert.ToDouble(query.Value);
|
||||
zeroData[1] = Convert.ToDouble(query2.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Calculate Tilt Data
|
||||
var Sx = (axisADCData[0] - zeroData[0]) / calFactor[0];
|
||||
var Sy = (axisADCData[1] - zeroData[1]) / calFactor[1];
|
||||
var Sz = (axisADCData[2] - zeroData[2]) / calFactor[2];
|
||||
var SG = Math.Sqrt(Math.Pow(Sx, 2) + Math.Pow(Sy, 2) + Math.Pow(Sz, 2));
|
||||
|
||||
var tiltInDegrees = new double[3];
|
||||
tiltInDegrees[0] = (180.0 / Math.PI) * Math.Asin(Sx / SG);
|
||||
tiltInDegrees[1] = (180.0 / Math.PI) * Math.Asin(Sy / SG);
|
||||
tiltInDegrees[2] = (180.0 / Math.PI) * Math.Asin(Sz / SG);
|
||||
|
||||
TiltAxisData = tiltInDegrees.ToList();
|
||||
ThreadPool.QueueUserWorkItem(packet.Info.NewData, new ServiceCallbackData.TiltNewData()
|
||||
{
|
||||
TiltData = tiltInDegrees,
|
||||
AccelData = accelData,
|
||||
});
|
||||
}
|
||||
packet.Info.Success();
|
||||
|
||||
}
|
||||
catch (CanceledException)
|
||||
{
|
||||
packet.Info.Cancel();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
packet.Info.Error(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public string UDPStreamAddress
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
// FB15313: Add UDP Streaming options
|
||||
void IRealTimeActions.SetUDPStreamProfile(ServiceCallback callback, object userData,
|
||||
UDPStreamProfile streamProfile, string udpAddress, ushort timeChannelId, ushort dataChannelId,
|
||||
uint[] tmnsConfig, ushort irigTimeDataPacketIntervalMs)
|
||||
{
|
||||
var packet = new RealTimeUDPStreamProfileAsyncPacket()
|
||||
{
|
||||
Info = new SliceServiceAsyncInfo(callback, userData),
|
||||
Profile = streamProfile,
|
||||
UDPAddress = udpAddress,
|
||||
TimeDataChannelId = timeChannelId,
|
||||
DataChannelId = dataChannelId,
|
||||
TMNSConfig = tmnsConfig,
|
||||
IRIGTimeDataPacketIntervalMs = irigTimeDataPacketIntervalMs
|
||||
};
|
||||
|
||||
LaunchAsyncWorker("Slice.SetUDPStreamProfile", AsyncSetUDPStreamProfile, packet);
|
||||
}
|
||||
|
||||
private void AsyncSetUDPStreamProfile(object asyncInfo)
|
||||
{
|
||||
var packet = asyncInfo as RealTimeUDPStreamProfileAsyncPacket;
|
||||
|
||||
try
|
||||
{
|
||||
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.UDPRealtimeStream))
|
||||
{
|
||||
var rtUDPAddress = packet.UDPAddress;
|
||||
var profile = (byte)packet.Profile;
|
||||
var timeChannelId = packet.TimeDataChannelId;
|
||||
var dataChannelId = packet.DataChannelId;
|
||||
var tmnsConfig = new TMNSConfig(packet.TMNSConfig);
|
||||
|
||||
var udpAddress = new UriBuilder(rtUDPAddress);
|
||||
byte[] tmp = Encoding.ASCII.GetBytes(udpAddress.Uri.AbsoluteUri.TrimEnd('/'));
|
||||
byte[] ipport = new byte[28];
|
||||
for (int i = 0; i < tmp.Length; i++)
|
||||
{
|
||||
ipport[i] = tmp[i];
|
||||
}
|
||||
|
||||
var ssaUDPStreamProfile = new StreamConfigUDPSet(this, AbstractCommandBase.Default_IO_Timeout)
|
||||
{
|
||||
Stream_Profile_Number = profile,
|
||||
Irig106Config0 = timeChannelId,
|
||||
Irig106Config1 = dataChannelId,
|
||||
TMNS_PCMSubFrameId = tmnsConfig.TMNS_PCMSubFrameId,
|
||||
TMNS_MsgId = tmnsConfig.TMNS_MsgId,
|
||||
TMNS_PCMMinorPerMajor = tmnsConfig.TMNS_PCMMinorPerMajor,
|
||||
TMNS_TMATSPortNumber = tmnsConfig.TMNS_TMATSPortNumber,
|
||||
IENAUDP_PortNumber = tmnsConfig.IENAUDP_PortNumber,
|
||||
TMNS5 = tmnsConfig.TMNS5,
|
||||
TMNS6 = tmnsConfig.TMNS6,
|
||||
TMNS7 = tmnsConfig.TMNS7,
|
||||
UdpIpPort = ipport
|
||||
};
|
||||
ssaUDPStreamProfile.SyncExecute();
|
||||
UDPStreamAddress = udpAddress.Uri.AbsoluteUri.TrimEnd('/');
|
||||
// FB15354: Enforce IRIG Time Data Packet Interval in order to read streaming data in NetView, etc.
|
||||
var ssaIRIGTimeData = new SetSystemAttributeSLICE2(this, AbstractCommandBase.Default_IO_Timeout);
|
||||
ssaIRIGTimeData.SetValue(AttributeTypes.SystemAttributesSLICE2.S6A_IrigTimeDataPacketIntervalMsec, packet.IRIGTimeDataPacketIntervalMs.ToString(), true);
|
||||
ssaIRIGTimeData.SyncExecute();
|
||||
}
|
||||
packet.Info.Success();
|
||||
}
|
||||
catch (CanceledException)
|
||||
{
|
||||
packet.Info.Cancel();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
packet.Info.Error(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
void IRealTimeActions.GetUDPStreamProfile(ServiceCallback callback, object userData)
|
||||
{
|
||||
var info = new SliceServiceAsyncInfo(callback, userData);
|
||||
LaunchAsyncWorker("Slice.GetUDPStreamProfile", AsyncGetUDPStreamProfile, info);
|
||||
}
|
||||
|
||||
private void AsyncGetUDPStreamProfile(object asyncInfo)
|
||||
{
|
||||
var info = asyncInfo as SliceServiceAsyncInfo;
|
||||
try
|
||||
{
|
||||
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.UDPRealtimeStream))
|
||||
{
|
||||
var qsaUDPStreamProfile = new StreamConfigUDPGet(this, AbstractCommandBase.Default_IO_Timeout);
|
||||
qsaUDPStreamProfile.SyncExecute();
|
||||
var len = Array.IndexOf(qsaUDPStreamProfile.UdpIpPort, (byte)0x00);
|
||||
UDPStreamAddress = Encoding.ASCII.GetString(qsaUDPStreamProfile.UdpIpPort, 0, len < 0 ? qsaUDPStreamProfile.UdpIpPort.Length : len);
|
||||
}
|
||||
info.Success();
|
||||
}
|
||||
catch (CanceledException)
|
||||
{
|
||||
info.Cancel();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
info.Error(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user