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) { diff --git a/Devices/DeviceManager.cs b/Devices/DeviceManager.cs index 07d3a23..2149058 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 @@ -84,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 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..f12f3e9 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 device + /// void CommitSettings(); } diff --git a/Devices/SmartScope.cs b/Devices/SmartScope.cs index 5e37822..b0ccddf 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; @@ -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/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()); 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) { diff --git a/Hardware/InterfaceManagerLibUsb.cs b/Hardware/InterfaceManagerLibUsb.cs index a6d3f4f..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) @@ -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; }