From f18a6a97f2c69b273af97e14e41fe55f5528dee2 Mon Sep 17 00:00:00 2001 From: Jasper van Bourgognie Date: Wed, 30 Sep 2015 15:02:26 +0200 Subject: [PATCH 1/7] SmartScope: fix minimal acquisition depth --- Devices/SmartScope.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Devices/SmartScope.cs b/Devices/SmartScope.cs index 5e37822..fcdd9c5 100644 --- a/Devices/SmartScope.cs +++ b/Devices/SmartScope.cs @@ -76,7 +76,7 @@ bool DiscardPreviousAcquisition internal static double BASE_SAMPLE_PERIOD = 10e-9; //10MHz sample rate private const int OVERVIEW_BUFFER_SIZE = 2048; - private const int ACQUISITION_DEPTH_MIN = 128; //Size of RAM + private const int ACQUISITION_DEPTH_MIN = OVERVIEW_BUFFER_SIZE; //Size of RAM private const int ACQUISITION_DEPTH_MAX = 512 * 1024;//4 * 1024 * 1024; //Size of RAM private const int ACQUISITION_DEPTH_DEFAULT = 512 * 1024; private const int BYTES_PER_BURST = 64; From 94041c2014b638a5af84b2368d27cca97ccb68ea Mon Sep 17 00:00:00 2001 From: Jasper van Bourgognie Date: Wed, 30 Sep 2015 15:03:53 +0200 Subject: [PATCH 2/7] IScope: added documentation IScope: added getter for VerticalRange IScope: added getter for AcquisitionMode --- Devices/DeviceManager.cs | 4 + Devices/DummyScope.cs | 7 ++ Devices/IScope.cs | 171 +++++++++++++++++++++++++++++++++- Devices/SmartScopeSettings.cs | 25 +++-- 4 files changed, 198 insertions(+), 9 deletions(-) diff --git a/Devices/DeviceManager.cs b/Devices/DeviceManager.cs index 07d3a23..4c25c45 100644 --- a/Devices/DeviceManager.cs +++ b/Devices/DeviceManager.cs @@ -15,6 +15,10 @@ public class DeviceManager { DeviceConnectHandler connectHandler; IDevice device; + /// + /// Gets the fallback device. + /// + /// The fallback device when no device is detected public IDevice fallbackDevice { get; private set; } Thread pollThread; #if WINDOWS diff --git a/Devices/DummyScope.cs b/Devices/DummyScope.cs index 65718a5..5952dbb 100644 --- a/Devices/DummyScope.cs +++ b/Devices/DummyScope.cs @@ -189,6 +189,9 @@ public AcquisitionMode AcquisitionMode this.acquisitionMode = value; } } + get { + return this.acquisitionMode; + } } public bool Running { @@ -243,6 +246,10 @@ public AnalogTriggerValue TriggerAnalog public void SetVerticalRange(AnalogChannel ch, float minimum, float maximum) { } + public float[] GetVerticalRange(AnalogChannel ch) + { + return new float[] { -100f, 100f }; + } public void SetProbeDivision(AnalogChannel ch, ProbeDivision division) { ChannelConfig[ch].probeDivision = division; diff --git a/Devices/IScope.cs b/Devices/IScope.cs index ed955ba..a112da7 100644 --- a/Devices/IScope.cs +++ b/Devices/IScope.cs @@ -36,6 +36,14 @@ public enum TriggerModes { Analog, Digital, External }; public enum TriggerDirection { RISING = 0, FALLING = 1 }; public enum Coupling { AC, DC }; public enum AcquisitionMode { SINGLE = 2, NORMAL = 1, AUTO = 0}; + /// + /// Digital trigger value. + /// L Low + /// H High + /// R Rising edge + /// F Falling edge + /// X Don't care + /// public enum DigitalTriggerValue { L, H, R, F, X }; /// /// Describes an analog trigger @@ -63,55 +71,214 @@ public AnalogTriggerValue Copy() public interface IScope : IDevice { + /// + /// Method to synchronously fetch scope data + /// + /// The scope data. DataPackageScope GetScopeData(); + /// + /// The DataSourceScope allows you to register a callback which + /// is called whenever new data comes in. + /// + /// Mind that the DataSourceScope must be started in order for the + /// fetch thread to run. + /// + /// The data source scope. DataSources.DataSource DataSourceScope { get; } + /// + /// Enabel or disable rolling mode using this property + /// bool Rolling { get; set; } + /// + /// Start or stop the scope using this property + /// bool Running { get; set; } + /// + /// True when the scope can go into rolling mode + /// bool CanRoll { get; } + /// + /// True when the acquistion will be stopped after the current one + /// bool StopPending { get; } + /// + /// True when the scope is awaiting a trigger condition to occur. + /// bool AwaitingTrigger { get; } + /// + /// True when the scope is armed and waiting for a trigger + /// bool Armed { get; } void Pause(); void Resume(); /* Acquisition & Trigger */ + + /// + /// When the sample rate is sufficiently low and data comes in slower than + /// the transfer rate of the scope to host, the scope can optionally stream + /// data yet available before the entire acqusition buffer is filled. + /// + /// When false, the scope will wait for the acquisition to complete before + /// streaming data to host. This ensures that only a single and viewport-complete + /// data package will reach the host per acquisition. If viewport settings are changed + /// while the current acquisition is not completed yet though, the scope can still + /// send data of that ongoing acquisition. + /// + /// In this mode, use the to + /// distinguish between different acquisitions. + /// bool PreferPartial { get; set; } - AcquisitionMode AcquisitionMode { set; } + /// + /// Sets the acquisition mode which defines the trigger behavoir + /// AUTO results in a timeout when no trigger is detected within 5ms + /// NORMAL a trigger is required for the acquisition to complete + /// SINGLE once a trigger is detected, the running acquisition will finalise + /// and the scope will stop after that. + /// + /// The acquisition mode. + AcquisitionMode AcquisitionMode { get; set; } + /// + /// Gets or sets the length of the acquisition buffer (in seconds) + /// + /// The length of the acquisition buffer (in seconds) double AcquisitionLength { get; set; } + /// + /// Gets the sample period in seconds + /// + /// The sample period in seconds double SamplePeriod { get; } + /// + /// Gets the longest possible acquisition buffer (in seconds). + /// double AcquisitionLengthMax { get; } + /// + /// Gets the shortest possible acquisition buffer (in seconds). + /// double AcquisitionLengthMin { get; } + + /// + /// Gets or sets the acquisition buffer depth (in samples) + /// uint AcquisitionDepth { get; set; } + /// + /// Gets or sets the trigger hold off from the first sample of the acquisition buffer (in seconds) + /// + /// The trigger hold off. double TriggerHoldOff { get; set; } + /// + /// Gets the trigger mode (Analog, digital or external) + /// TriggerModes TriggerMode { get; } + /// + /// Gets or sets the analog trigger value + /// + /// The analog trigger value. AnalogTriggerValue TriggerAnalog { get; set; } + /// + /// Sets the digital trigger + /// + /// The digital trigger. Dictionary TriggerDigital { set; } + /// + /// Gets or sets the width of the trigger (in samples) + /// + /// The width of the trigger (in samples). uint TriggerWidth { get; set; } + /// + /// Gets or sets the voltage threshold needed to cross before a trigger is considered valid + /// + /// The trigger threshold (volts). float TriggerThreshold { get; set; } + /// + /// Gets or sets a value indicating whether this send overview buffer with each acquisition + /// + /// true if send overview buffer; otherwise, false. bool SendOverviewBuffer { get; set; } + /// + /// Calling this results in a trigger force + /// void ForceTrigger(); /* Channel specifics */ + /// + /// Sets the coupling (AC or DC) for an analog input channel + /// + /// Channel. + /// Coupling (AC/DC). void SetCoupling(AnalogChannel channel, Coupling coupling); Coupling GetCoupling(AnalogChannel channel); + /// + /// Sets the voltage range of an analog input channel + /// + /// Channel. + /// Minimum. + /// Maximum. void SetVerticalRange(AnalogChannel channel, float minimum, float maximum); + float[] GetVerticalRange(AnalogChannel channel); + /// + /// Sets the voltage offset of an analog input channel. + /// + /// WARNING: this offset is dicated by the vertical range. Check + /// GetYOffsetMax/Min() for the possible range + /// + /// Channel. + /// Offset. void SetYOffset(AnalogChannel channel, float offset); float GetYOffset(AnalogChannel channel); + /// + /// Gets the maximal voltage offset for the current voltage range + /// + /// Maximum voltage offset + /// Ch. float GetYOffsetMax(AnalogChannel ch); + /// + /// Gets the minimal voltage offset for the current voltage range + /// + /// Minimum voltage offset + /// Ch. float GetYOffsetMin(AnalogChannel ch); + /// + /// Sets the probe division (x1, x10, x100) + /// + /// Ch. + /// Division. void SetProbeDivision(AnalogChannel ch, ProbeDivision division); ProbeDivision GetProbeDivision(AnalogChannel ch); /* Logic Analyser */ + /// + /// Gets or sets a value indicating whether this 's logic analyser is enabled. + /// + /// true if logic analyser enabled; otherwise, false. bool LogicAnalyserEnabled { get; set; } + /// + /// Which analog channel to discard to use for the logic analyser data + /// + /// The analog channel sacrificed for logic analyser data. AnalogChannel ChannelSacrificedForLogicAnalyser { set; } - /* Viewport */ + /* Viewport */ + /// + /// Sets the view port. + /// The viewport is the section of the acquisition buffer which is streamed to the host. + /// It is subsampled so that it fits within 2048 samples. + /// + /// When the scope is stopped, the acquisition buffer can be downloaded completely to the + /// host, without subsampling, but this can take several seconds. Instead, the viewport + /// can be changed when only interested in a section of the acquisition buffer, potentially + /// coarser than the effective sample rate. + /// + /// Offset of the first sample of the acquisition (in seconds) + /// Timespan of the viewport void SetViewPort(double offset, double timespan); double ViewPortTimeSpan { get; } double ViewPortOffset { get; } + /// + /// Commits the settings to the scope + /// void CommitSettings(); } diff --git a/Devices/SmartScopeSettings.cs b/Devices/SmartScopeSettings.cs index f8d47d7..eeb50ac 100644 --- a/Devices/SmartScopeSettings.cs +++ b/Devices/SmartScopeSettings.cs @@ -169,6 +169,11 @@ public float GetYOffset(AnalogChannel channel) public float GetYOffsetMax(AnalogChannel channel) { return ConvertYOffsetByteToVoltage(channel, yOffsetMax); } public float GetYOffsetMin(AnalogChannel channel) { return ConvertYOffsetByteToVoltage(channel, yOffsetMin); } + + //The voltage range for div/mul = 1/1 + float baseVoltageRangeMin = -0.6345f; //V + float baseVoltageRangeMax = 0.6769f; //V + /// /// Sets and uploads the divider and multiplier what are optimal for the requested range /// @@ -178,11 +183,7 @@ public float GetYOffset(AnalogChannel channel) public void SetVerticalRange(AnalogChannel channel, float minimum, float maximum) { if (!Connected) return; - //The voltage range for div/mul = 1/1 - //20140808: these seem to be OK: on div0/mult0 the ADC input range is approx 1.3V - float baseMin = -0.6345f; //V - float baseMax = 0.6769f; //V - + //Walk through dividers/multipliers till requested range fits //this walk assumes it starts with the smallest range, and that range is only increasing int dividerIndex = 0; @@ -195,9 +196,9 @@ public void SetVerticalRange(AnalogChannel channel, float minimum, float maximum dividerIndex= i / rom.computedMultipliers.Length; multIndex = rom.computedMultipliers.Length - (i % rom.computedMultipliers.Length) - 1; if ( - (ProbeScaleHostToScope(channel, maximum) < baseMax * rom.computedDividers[dividerIndex] / rom.computedMultipliers[multIndex]) + (ProbeScaleHostToScope(channel, maximum) < baseVoltageRangeMax * rom.computedDividers[dividerIndex] / rom.computedMultipliers[multIndex]) && - (ProbeScaleHostToScope(channel, minimum) > baseMin * rom.computedDividers[dividerIndex] / rom.computedMultipliers[multIndex]) + (ProbeScaleHostToScope(channel, minimum) > baseVoltageRangeMin * rom.computedDividers[dividerIndex] / rom.computedMultipliers[multIndex]) ) break; } @@ -212,6 +213,16 @@ public void SetVerticalRange(AnalogChannel channel, float minimum, float maximum //SetTriggerThreshold(this.triggerThreshold); } } + public float[] GetVerticalRange(AnalogChannel channel) + { + int dividerIndex = Array.IndexOf (validDividers, channelSettings [channel].divider); + int multIndex = Array.IndexOf (validMultipliers, channelSettings [channel].multiplier); + return new float[] { + ProbeScaleScopeToHost(channel, (float)(baseVoltageRangeMin * rom.computedDividers[dividerIndex] / rom.computedMultipliers[multIndex])), + + ProbeScaleScopeToHost(channel, (float)(baseVoltageRangeMax * rom.computedDividers[dividerIndex] / rom.computedMultipliers[multIndex])) + }; + } public void SetProbeDivision(AnalogChannel ch, ProbeDivision division) { From 628414651dca3b7787c7454368cb338c58621adb Mon Sep 17 00:00:00 2001 From: Jasper van Bourgognie Date: Wed, 30 Sep 2015 17:54:32 +0200 Subject: [PATCH 3/7] Demoted some INFO logs to Debug --- Devices/IScope.cs | 2 +- Devices/SmartScope.cs | 10 +++++----- Devices/SmartScopeFlashHelpers.cs | 2 +- Hardware/InterfaceManagerLibUsb.cs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Devices/IScope.cs b/Devices/IScope.cs index a112da7..f12f3e9 100644 --- a/Devices/IScope.cs +++ b/Devices/IScope.cs @@ -277,7 +277,7 @@ public interface IScope : IDevice double ViewPortOffset { get; } /// - /// Commits the settings to the scope + /// Commits the settings to the device /// void CommitSettings(); } diff --git a/Devices/SmartScope.cs b/Devices/SmartScope.cs index fcdd9c5..b0ccddf 100644 --- a/Devices/SmartScope.cs +++ b/Devices/SmartScope.cs @@ -296,7 +296,7 @@ private void CalibrateAdc() SetTriggerByte(127); LogicAnalyserEnabled = false; Running = true; - Logger.Info("Calibrating ADC timing"); + Logger.Debug("Calibrating ADC timing"); CommitSettings(); //If the adc timing value is not the default (being 0, the first one in the list) @@ -305,20 +305,20 @@ private void CalibrateAdc() { if (TestAdcRamp()) { - Logger.Info("ADC calibration OK with value from ROM = " + AdcTimingValue); + Logger.Debug("ADC calibration OK with value from ROM = " + AdcTimingValue); return; } } foreach(byte timingValue in adcTimingValues) { - Logger.Info("Testing ADC timing value [" + timingValue + "]"); + Logger.Debug("Testing ADC timing value [" + timingValue + "]"); AdcMemory[MAX19506.DATA_CLK_TIMING].Set(timingValue); CommitSettings(); //Note: ForceTrigger won't work here yet since Ready is still false if (TestAdcRamp()) { - Logger.Info("ADC calibration OK with value " + timingValue); + Logger.Debug("ADC calibration OK with value " + timingValue); AdcTimingValue = timingValue; return; } @@ -402,7 +402,7 @@ private void Configure() CalibrateAdc(); - Logger.Info("Found good ADC timing value [" + AdcTimingValue + "]"); + Logger.Debug("Found good ADC timing value [" + AdcTimingValue + "]"); AcquisitionDepth = ACQUISITION_DEPTH_DEFAULT; CommitSettings(); diff --git a/Devices/SmartScopeFlashHelpers.cs b/Devices/SmartScopeFlashHelpers.cs index 82bc267..1488ef9 100644 --- a/Devices/SmartScopeFlashHelpers.cs +++ b/Devices/SmartScopeFlashHelpers.cs @@ -52,7 +52,7 @@ private bool FlashFpga () return false; } - Logger.Info("Got firmware of length " + firmware.Length); + Logger.Debug("Got firmware of length " + firmware.Length); //Send FW to FPGA try { diff --git a/Hardware/InterfaceManagerLibUsb.cs b/Hardware/InterfaceManagerLibUsb.cs index a6d3f4f..dabb71c 100644 --- a/Hardware/InterfaceManagerLibUsb.cs +++ b/Hardware/InterfaceManagerLibUsb.cs @@ -156,7 +156,7 @@ private void OnDeviceNotifyEvent(object sender, DeviceNotifyEventArgs e) C.Logger.Debug("LibUSB device arrival"); if (e.Device == null || e.Device.IdVendor != VID || !PIDs.Contains(e.Device.IdProduct)) { - C.Logger.Info("Not taking this device, PID/VID not a smartscope"); + C.Logger.Debug("Not taking this device, PID/VID not a smartscope"); return; } From 1ff68cdf9094986efc608f59ab46b9ffc5f0c0e4 Mon Sep 17 00:00:00 2001 From: Jasper van Bourgognie Date: Wed, 30 Sep 2015 17:54:42 +0200 Subject: [PATCH 4/7] Stop dataSourceScope when stopping devicemanager --- Devices/DeviceManager.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Devices/DeviceManager.cs b/Devices/DeviceManager.cs index 4c25c45..2149058 100644 --- a/Devices/DeviceManager.cs +++ b/Devices/DeviceManager.cs @@ -88,6 +88,9 @@ private void PollUponStart() public void Stop() { + if (device is IScope) + ((IScope)device).DataSourceScope.Stop (); + if(pollThread != null) pollThread.Join(100); #if ANDROID From ead49416b9b9094e72d6a59745b803047a803072 Mon Sep 17 00:00:00 2001 From: Jasper van Bourgognie Date: Wed, 30 Sep 2015 17:54:49 +0200 Subject: [PATCH 5/7] Commented dataPackageScope --- DataSources/DataPackages/DataPackageScope.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/DataSources/DataPackages/DataPackageScope.cs b/DataSources/DataPackages/DataPackageScope.cs index 201dec6..2b9b597 100644 --- a/DataSources/DataPackages/DataPackageScope.cs +++ b/DataSources/DataPackages/DataPackageScope.cs @@ -13,7 +13,9 @@ public enum DataSourceType Viewport, Overview } - + /// + /// Class representing an oscilloscope acquisition's channel data + /// public class ChannelData { public DataSourceType source { get; private set; } @@ -23,8 +25,22 @@ public class ChannelData /// create a new array and with that, a new ChannelData object /// public Array array { get; private set; } + /// + /// Gets a value indicating whether this is partial, i.e. + /// if more data is required to consider the acquisition complete. This can be false when the acquisition is still ongoing + /// while the data dump has already begun. + /// + /// true if partial; otherwise, false. public bool partial { get; private set; } + /// + /// Time between 2 samples in seconds + /// + /// The sample period. public double samplePeriod { get; private set; } + /// + /// Time offset of the first sample. + /// + /// The time offset. public double timeOffset { get; private set; } public ChannelData(DataSourceType t, Channel channel, Array data, bool partial, double samplePeriod, double timeOffset = 0) { From 41340b25f5e89b43cb866680f9a857a554b6200e Mon Sep 17 00:00:00 2001 From: Jasper van Bourgognie Date: Wed, 30 Sep 2015 18:08:37 +0200 Subject: [PATCH 6/7] Demoted one more log --- Hardware/InterfaceManagerLibUsb.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hardware/InterfaceManagerLibUsb.cs b/Hardware/InterfaceManagerLibUsb.cs index dabb71c..bbf1822 100644 --- a/Hardware/InterfaceManagerLibUsb.cs +++ b/Hardware/InterfaceManagerLibUsb.cs @@ -133,7 +133,7 @@ private void DeviceFound(LibUsbDotNet.UsbDevice scopeUsbDevice) Common.Logger.Warn("Can't re-register device with this serial " + serial); throw new ScopeIOException("This device was already registered. This is a bug"); } - C.Logger.Warn("Device found with serial [" + serial + "]"); + C.Logger.Debug("Device found with serial [" + serial + "]"); interfaces.Add(serial, f); if (onConnect != null) From f43f5bfb9a3e519122e2d3c80ddf85813e9b0ce1 Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Sat, 24 Oct 2015 15:40:52 +0200 Subject: [PATCH 7/7] Byteswap SmartScope.Rom.Map structure as needed when marshalling The Map structure is stored in little endian format in the FLASH. Thus, if the host is big endian, the structure needs to be byteswapped during marshalling. --- Devices/SmartScopeRom.cs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Devices/SmartScopeRom.cs b/Devices/SmartScopeRom.cs index 12e20fc..c81e7cd 100644 --- a/Devices/SmartScopeRom.cs +++ b/Devices/SmartScopeRom.cs @@ -112,6 +112,36 @@ public GainCalibration getCalibration(AnalogChannel ch, double divider, double m return gainCalibration.Where(x => x.channel == ch && x.divider == divider && x.multiplier == multiplier).First(); } + private void ByteSwap(byte[] b, Type t) + { + if (BitConverter.IsLittleEndian) + return; + foreach (var field in t.GetFields()) + { + int subsize = 0; + foreach (var subField in field.FieldType.GetFields()) + { + if (!subField.IsStatic) + subsize = Marshal.SizeOf(subField.FieldType); + } + var offs = Marshal.OffsetOf(t, field.Name).ToInt32(); + var size = Marshal.SizeOf(field.FieldType); + int count = 1; + if (subsize > 0) { + count = size / subsize; + size = subsize; + } + if (size > 1) + { + for (uint i = 0; i < count; i++) + { + Array.Reverse(b, offs, size); + offs += size; + } + } + } + } + private byte[] MapToBytes(Map m) { int size = Marshal.SizeOf(m); @@ -120,6 +150,7 @@ private byte[] MapToBytes(Map m) Marshal.StructureToPtr(m, p, true); Marshal.Copy(p, output, 0, size); + ByteSwap(output, typeof(Map)); Marshal.FreeHGlobal(p); return output; } @@ -129,6 +160,7 @@ private Map BytesToMap(byte[] b) Map m = new Map(); int size = Marshal.SizeOf(m); IntPtr ptr = Marshal.AllocHGlobal(size); + ByteSwap(b, typeof(Map)); Marshal.Copy(b, 0, ptr, size); m = (Map)Marshal.PtrToStructure(ptr, m.GetType());