diff --git a/source/TS.NET.Engine/Servers/DataServer.cs b/source/TS.NET.Engine/Servers/DataServer.cs index ee2b381..3c08f9b 100644 --- a/source/TS.NET.Engine/Servers/DataServer.cs +++ b/source/TS.NET.Engine/Servers/DataServer.cs @@ -137,12 +137,29 @@ protected override void OnReceived(byte[] buffer, long offset, long size) //logger.LogDebug("WaveformHeader: " + header.ToString()); for (byte channelIndex = 0; channelIndex < processing.CurrentChannelCount; channelIndex++) - { + { ThunderscopeChannel thunderscopeChannel = configuration.Channels[channelIndex]; - chHeader.chNum = channelIndex; chHeader.scale = (float)(thunderscopeChannel.ActualVoltFullScale / 255.0); chHeader.offset = (float)thunderscopeChannel.VoltOffset; + // If this is the trigger channel and the data is triggered, then run trigger interpolation and set trigphase value + if ((((int)bridge.Processing.TriggerChannel) - 1) == channelIndex && bridge.Triggered) + { + var signedData = bridge.AcquiredRegionI8; + // Get the trigger index. If it's greater than 0, then do trigger interpolation. + int index = (int)(bridge.Processing.TriggerDelayFs / femtosecondsPerSample); + if (index > 0) + { + float fa = (chHeader.scale * signedData[index - 1]) - chHeader.offset; + float fb = (chHeader.scale * signedData[index]) - chHeader.offset; + float triggerLevel = (chHeader.scale * bridge.Processing.TriggerLevel) + chHeader.offset; + float slope = fb - fa; + float delta = triggerLevel - fa; + float trigphase = delta / slope; + chHeader.trigphase = femtosecondsPerSample * (1 - trigphase); + //logger.LogTrace("Trigger phase: {0:F6}, first {1}, second {2}", chHeader.trigphase, fa, fb); + } + } Send(new ReadOnlySpan(&chHeader, sizeof(ChannelHeader))); bytesSent += (ulong)sizeof(ChannelHeader); diff --git a/source/TS.NET.Engine/Tasks/ProcessingThread.cs b/source/TS.NET.Engine/Tasks/ProcessingThread.cs index f9c19cf..28b6ed2 100644 --- a/source/TS.NET.Engine/Tasks/ProcessingThread.cs +++ b/source/TS.NET.Engine/Tasks/ProcessingThread.cs @@ -327,7 +327,7 @@ private static void Loop( var bridgeSpan = bridge.AcquiringRegionI8; uint endOffset = (uint)triggerChannelBuffer.Length - captureEndIndices[i]; circularBuffer1.Read(bridgeSpan.Slice(0, channelLength), endOffset); - bridge.DataWritten(); + bridge.DataWritten(triggered: true); bridge.SwitchRegionIfNeeded(); if (singleTriggerLatch) // If this was a single trigger, reset the singleTrigger & runTrigger latches @@ -345,7 +345,7 @@ private static void Loop( { var bridgeSpan = bridge.AcquiringRegionI8; circularBuffer1.Read(bridgeSpan.Slice(0, channelLength), 0); - bridge.DataWritten(); + bridge.DataWritten(triggered: false); bridge.SwitchRegionIfNeeded(); forceTriggerLatch = false; @@ -405,7 +405,7 @@ private static void Loop( uint endOffset = (uint)triggerChannelBuffer.Length - captureEndIndices[i]; circularBuffer1.Read(bridgeSpan.Slice(0, channelLength), endOffset); circularBuffer2.Read(bridgeSpan.Slice(channelLength, channelLength), endOffset); - bridge.DataWritten(); + bridge.DataWritten(triggered: true); bridge.SwitchRegionIfNeeded(); if (singleTriggerLatch) // If this was a single trigger, reset the singleTrigger & runTrigger latches @@ -424,7 +424,7 @@ private static void Loop( var bridgeSpan = bridge.AcquiringRegionI8; circularBuffer1.Read(bridgeSpan.Slice(0, channelLength), 0); circularBuffer2.Read(bridgeSpan.Slice(channelLength, channelLength), 0); - bridge.DataWritten(); + bridge.DataWritten(triggered: false); bridge.SwitchRegionIfNeeded(); forceTriggerLatch = false; @@ -493,7 +493,7 @@ private static void Loop( circularBuffer2.Read(bridgeSpan.Slice(channelLength, channelLength), endOffset); circularBuffer3.Read(bridgeSpan.Slice(channelLength + channelLength, channelLength), endOffset); circularBuffer4.Read(bridgeSpan.Slice(channelLength + channelLength + channelLength, channelLength), endOffset); - bridge.DataWritten(); + bridge.DataWritten(triggered: true); bridge.SwitchRegionIfNeeded(); if (singleTriggerLatch) // If this was a single trigger, reset the singleTrigger & runTrigger latches @@ -514,7 +514,7 @@ private static void Loop( circularBuffer2.Read(bridgeSpan.Slice(channelLength, channelLength), 0); circularBuffer3.Read(bridgeSpan.Slice(channelLength + channelLength, channelLength), 0); circularBuffer4.Read(bridgeSpan.Slice(channelLength + channelLength + channelLength, channelLength), 0); - bridge.DataWritten(); + bridge.DataWritten(triggered: false); bridge.SwitchRegionIfNeeded(); forceTriggerLatch = false; @@ -575,7 +575,7 @@ void SingleChannelStream(int channelLength) streamSampleCounter -= channelLength; var bridgeSpan = bridge.AcquiringRegionI8; circularBuffer1.Read(bridgeSpan.Slice(0, channelLength), 0); // TODO - work out if this should be zero? - bridge.DataWritten(); + bridge.DataWritten(triggered: false); bridge.SwitchRegionIfNeeded(); } } @@ -588,7 +588,7 @@ void DualChannelStream(int channelLength) var bridgeSpan = bridge.AcquiringRegionI8; circularBuffer1.Read(bridgeSpan.Slice(0, channelLength), 0); // TODO - work out if this should be zero? circularBuffer2.Read(bridgeSpan.Slice(channelLength, channelLength), 0); - bridge.DataWritten(); + bridge.DataWritten(triggered: false); bridge.SwitchRegionIfNeeded(); } } @@ -603,7 +603,7 @@ void QuadChannelStream(int channelLength) circularBuffer2.Read(bridgeSpan.Slice(channelLength, channelLength), 0); circularBuffer3.Read(bridgeSpan.Slice(channelLength + channelLength, channelLength), 0); circularBuffer4.Read(bridgeSpan.Slice(channelLength + channelLength + channelLength, channelLength), 0); - bridge.DataWritten(); + bridge.DataWritten(triggered: false); bridge.SwitchRegionIfNeeded(); } } diff --git a/source/TS.NET/Memory/Structs/ThunderscopeDataBridgeHeader.cs b/source/TS.NET/Memory/Structs/ThunderscopeDataBridgeHeader.cs index d7018fe..14be9ea 100644 --- a/source/TS.NET/Memory/Structs/ThunderscopeDataBridgeHeader.cs +++ b/source/TS.NET/Memory/Structs/ThunderscopeDataBridgeHeader.cs @@ -27,6 +27,7 @@ internal struct ThunderscopeDataBridgeHeader internal ThunderscopeHardwareConfig Hardware; // 2 + 4*32, read only from UI perspective, UI uses SCPI interface to change configuration internal ThunderscopeProcessingConfig Processing; // 37 bytes, read only from UI perspective, UI uses SCPI interface to change configuration internal ThunderscopeDataMonitoring Monitoring; // 16 bytes, Read only from UI perspective, UI optionally displays these values + internal bool Triggered; // Indicate if acquired data was triggered (i.e. to run trigger interpolation or not) // BridgeConfig is set once from config file or hard coded // HardwareConfig, ProcessingConfig & DataMonitoring is runtime variable diff --git a/source/TS.NET/Memory/Structs/ThunderscopeProcessingConfig.cs b/source/TS.NET/Memory/Structs/ThunderscopeProcessingConfig.cs index 6ccd3db..40bf0ff 100644 --- a/source/TS.NET/Memory/Structs/ThunderscopeProcessingConfig.cs +++ b/source/TS.NET/Memory/Structs/ThunderscopeProcessingConfig.cs @@ -16,7 +16,6 @@ public struct ThunderscopeProcessingConfig // Idempotent so that UI doesn't ha public short TriggerLevel; // Uint: count (typically raw ADC value) public ushort TriggerHysteresis; // Unit: count (typically raw ADC value) - public BoxcarAveraging BoxcarAveraging; // U32 } } diff --git a/source/TS.NET/Memory/ThunderscopeDataBridgeReader.cs b/source/TS.NET/Memory/ThunderscopeDataBridgeReader.cs index a1f9eca..22174c1 100644 --- a/source/TS.NET/Memory/ThunderscopeDataBridgeReader.cs +++ b/source/TS.NET/Memory/ThunderscopeDataBridgeReader.cs @@ -115,6 +115,15 @@ public ThunderscopeDataMonitoring Monitoring } } + public bool Triggered + { + get + { + GetHeader(); + return header.Triggered; + } + } + public bool RequestAndWaitForData(int millisecondsTimeout) { // Firstly check if any data has already been loaded diff --git a/source/TS.NET/Memory/ThunderscopeDataBridgeWriter.cs b/source/TS.NET/Memory/ThunderscopeDataBridgeWriter.cs index d7132af..1629bf5 100644 --- a/source/TS.NET/Memory/ThunderscopeDataBridgeWriter.cs +++ b/source/TS.NET/Memory/ThunderscopeDataBridgeWriter.cs @@ -21,6 +21,7 @@ public class ThunderscopeDataBridgeWriter : IDisposable private bool dataRequested = false; private bool acquiringRegionFilledAndWaitingForReader = false; private readonly uint cachedDataWidth; + private bool triggered = false; public Span AcquiringRegionI8 { get { return GetAcquiringRegionI8(); } } public ThunderscopeDataMonitoring Monitoring { get { return header.Monitoring; } } @@ -121,17 +122,19 @@ public void SwitchRegionIfNeeded() ThunderscopeMemoryAcquiringRegion.RegionB => ThunderscopeMemoryAcquiringRegion.RegionA, _ => throw new InvalidDataException("Enum value not handled, add enum value to switch") }; + header.Triggered = triggered; SetHeader(); dataResponseSemaphore.Release(); // Allow UI to use the acquired region } } - public void DataWritten() + public void DataWritten(bool triggered) { header.Monitoring.TotalAcquisitions++; if (acquiringRegionFilledAndWaitingForReader) header.Monitoring.DroppedAcquisitions++; acquiringRegionFilledAndWaitingForReader = true; + this.triggered = triggered; SetHeader(); }