public DataPackageScope GetScopeData() { //Sleep to simulate USB delay System.Threading.Thread.Sleep(usbLatency); TimeSpan timeOffset = DateTime.Now - timeOrigin; if (acquisitionRunning) { lock (viewportUpdateLock) { viewportUpdate = true; } int triggerHoldoffInSamples = 0; int triggerIndex = 0; Dictionary <AnalogChannel, List <float> > waveAnalog = new Dictionary <AnalogChannel, List <float> >(); foreach (AnalogChannel ch in AnalogChannel.List) { waveAnalog.Add(ch, new List <float>((int)waveLength)); } List <byte> waveDigital = new List <byte>(); bool triggerDetected = false; while (true) { AcquisitionMode AcquisitionModeCurrent; lock (acquisitionSettingsLock) { acquisitionBufferAnalog = new Dictionary <AnalogChannel, float[]>(); AcquisitionModeCurrent = acquisitionMode; acquisitionDepthCurrent = AcquisitionDepth; TriggerHoldoffCurrent = triggerHoldoff; SamplePeriodCurrent = SamplePeriod; waveLengthCurrent = waveLength; logicAnalyserChannelCurrent = logicAnalyserChannel; logicAnalyserEnabledCurrent = LogicAnalyserEnabled; } acquistionId++; //Stop trying to find a trigger at some point to avoid running out of memory if (waveAnalog.Where(x => x.Value.Count > GENERATION_LENGTH_MAX).Count() > 0 || waveDigital.Count > GENERATION_LENGTH_MAX) { System.Threading.Thread.Sleep(10); return(null); } foreach (AnalogChannel channel in AnalogChannel.List) { if (logicAnalyserEnabledCurrent && channel == logicAnalyserChannelCurrent) { continue; } float[] wave; switch (waveSource) { case WaveSource.GENERATOR: wave = DummyScope.GenerateWave(waveLengthCurrent, SamplePeriodCurrent, timeOffset.Ticks / 1e7, ChannelConfig[channel]); break; case WaveSource.FILE: wave = GetWaveFromFile(channel, waveLengthCurrent, SamplePeriodCurrent, timeOffset.Ticks / 1e7); break; default: throw new Exception("Unsupported wavesource"); } if (ChannelConfig[channel].coupling == Coupling.AC) { DummyScope.RemoveDcComponent(ref wave, ChannelConfig[channel].frequency, SamplePeriodCurrent); } else { DummyScope.AddDcComponent(ref wave, (float)ChannelConfig[channel].dcOffset); } DummyScope.AddNoise(wave, ChannelConfig[channel].noise); waveAnalog[channel].AddRange(wave); } if (logicAnalyserEnabledCurrent) { waveDigital.AddRange(DummyScope.GenerateWaveDigital(waveLengthCurrent, SamplePeriodCurrent, timeOffset.TotalSeconds)); } triggerHoldoffInSamples = (int)(TriggerHoldoffCurrent / SamplePeriodCurrent); double triggerTimeout = 0.0; if (AcquisitionModeCurrent == AcquisitionMode.AUTO) { triggerTimeout = GENERATION_LENGTH_MAX * SamplePeriodCurrent; //Give up after 10ms } if (logicAnalyserEnabledCurrent && this.triggerValue.mode == TriggerMode.Digital) { triggerDetected = DummyScope.DoTriggerDigital(waveDigital.ToArray(), triggerHoldoffInSamples, digitalTrigger, acquisitionDepthCurrent, out triggerIndex); } else { if (triggerValue.source != TriggerSource.Channel) { throw new Exception("Doing analog trigger but mode is not set to analog!"); } triggerDetected = DummyScope.DoTriggerAnalog(waveAnalog[triggerValue.channel].ToArray(), triggerValue, triggerHoldoffInSamples, triggerThreshold, triggerWidth, acquisitionDepthCurrent, out triggerIndex); } awaitingTrigger = !triggerDetected; if (triggerDetected) { forceTrigger = false; awaitingTrigger = false; break; } if ( forceTrigger || (triggerTimeout > 0 && waveAnalog[AnalogChannel.ChA].Count * SamplePeriodCurrent >= triggerTimeout) ) { forceTrigger = false; triggerIndex = triggerHoldoffInSamples; awaitingTrigger = false; break; } var timePassed = new TimeSpan((long)(waveLengthCurrent * SamplePeriodCurrent * 1e7)); timeOffset = timeOffset.Add(timePassed); } foreach (AnalogChannel channel in AnalogChannel.List) { if (logicAnalyserEnabledCurrent && channel == logicAnalyserChannelCurrent) { continue; } acquisitionBufferAnalog[channel] = DummyScope.CropWave(acquisitionDepthCurrent, waveAnalog[channel].ToArray(), triggerIndex, triggerHoldoffInSamples); } acquisitionBufferDigital = DummyScope.CropWave(acquisitionDepthCurrent, waveDigital.ToArray(), triggerIndex, triggerHoldoffInSamples); if (StopPending) { acquisitionRunning = false; } } lock (viewportUpdateLock) { if (!viewportUpdate) { return(null); } viewportUpdate = false; } if (acquisitionBufferAnalog.Count == null) { return(null); } //Decrease the number of samples till viewport sample period is larger than //or equal to the full sample rate uint samples = VIEWPORT_SAMPLES_MAX; int viewportDecimation = 0; while (true) { viewportDecimation = (int)Math.Ceiling(Math.Log(ViewPortTimeSpan / (samples + 2) / SamplePeriodCurrent, 2)); if (viewportDecimation >= 0) { break; } samples /= 2; } if (viewportDecimation > VIEW_DECIMATION_MAX) { Logger.Warn("Clipping view decimation! better decrease the sample rate!"); viewportDecimation = VIEW_DECIMATION_MAX; } int viewportSamples = (int)(ViewPortTimeSpan / (SamplePeriodCurrent * Math.Pow(2, viewportDecimation))) + 2; int viewportOffsetLocal = (int)(ViewPortOffset / SamplePeriodCurrent); p = new DataPackageScope(this.GetType(), acquisitionDepthCurrent, SamplePeriodCurrent, viewportSamples, (Int64)(ViewPortOffset / SamplePeriodCurrent), TriggerHoldoffCurrent, (Int64)(TriggerHoldoffCurrent / SamplePeriodCurrent), false, acquistionId, TriggerValue); p.FullAcquisitionFetchProgress = 1f; p.samplePeriod[ChannelDataSourceScope.Viewport] = SamplePeriodCurrent * Math.Pow(2, viewportDecimation); p.offset[ChannelDataSourceScope.Viewport] = ViewPortOffset; foreach (AnalogChannel ch in AnalogChannel.List) { if (logicAnalyserEnabledCurrent && ch == logicAnalyserChannelCurrent) { continue; } if (SendOverviewBuffer) { p.SetData(ChannelDataSourceScope.Overview, ch, GetViewport(acquisitionBufferAnalog[ch], 0, (int)(Math.Log(acquisitionDepthCurrent / OVERVIEW_LENGTH, 2)), OVERVIEW_LENGTH)); } p.SetData(ChannelDataSourceScope.Viewport, ch, GetViewport(acquisitionBufferAnalog[ch], viewportOffsetLocal, viewportDecimation, viewportSamples)); p.SetData(ChannelDataSourceScope.Acquisition, ch, acquisitionBufferAnalog[ch]); //set dummy minmax values p.SaturationLowValue[ch] = float.MinValue; p.SaturationHighValue[ch] = float.MaxValue; } if (logicAnalyserEnabledCurrent) { if (SendOverviewBuffer) { p.SetData(ChannelDataSourceScope.Overview, LogicAnalyserChannel.LA, GetViewport(acquisitionBufferDigital, 0, (int)(Math.Log(acquisitionDepthCurrent / OVERVIEW_LENGTH, 2)), OVERVIEW_LENGTH)); } p.SetData(ChannelDataSourceScope.Viewport, LogicAnalyserChannel.LA, GetViewport(acquisitionBufferDigital, viewportOffsetLocal, viewportDecimation, viewportSamples)); p.SetData(ChannelDataSourceScope.Acquisition, LogicAnalyserChannel.LA, acquisitionBufferDigital); } if (acquisitionMode == AcquisitionMode.SINGLE) { acquisitionRunning = false; } return(p); }
public DataPackageScope GetScopeData() { //Sleep to simulate USB delay System.Threading.Thread.Sleep(usbLatency); TimeSpan timeOffset = DateTime.Now - timeOrigin; List <AnalogChannel> channelsToAcquireDataFor = new List <AnalogChannel> (); if (isAudio) { channelsToAcquireDataFor.Add(AnalogChannel.ChA); } else { channelsToAcquireDataFor.AddRange(AnalogChannel.List); } if (acquisitionRunning) { lock (viewportUpdateLock) { viewportUpdate = true; } int triggerHoldoffInSamples = 0; int triggerIndex = 0; Dictionary <AnalogChannel, List <float> > waveAnalog = new Dictionary <AnalogChannel, List <float> >(); foreach (AnalogChannel ch in AnalogChannel.List) { waveAnalog.Add(ch, new List <float>((int)waveLength)); } List <byte> waveDigital = new List <byte>(); bool triggerDetected = false; //loop until trigger condition is met while (true) { //in case the stop button has been pressed, this section makes sure the last-shown acquisition is kept on the display (otherwise it is replaced by a new acquisition) if ((StopPending || !acquisitionRunning) && (lastCommittedDataPackage != null)) { acquisitionRunning = false; return(lastCommittedDataPackage); } AcquisitionMode AcquisitionModeCurrent; lock (acquisitionSettingsLock) { acquisitionBufferAnalog = new Dictionary <AnalogChannel, float[]>(); AcquisitionModeCurrent = acquisitionMode; acquisitionDepthCurrent = AcquisitionDepth; TriggerHoldoffCurrent = triggerHoldoff; SamplePeriodCurrent = SamplePeriod; waveLengthCurrent = waveLength; logicAnalyserChannelCurrent = logicAnalyserChannel; logicAnalyserEnabledCurrent = LogicAnalyserEnabled; } acquistionId++; //Stop trying to find a trigger at some point to avoid running out of memory if (waveAnalog.Where(x => x.Value.Count > GENERATION_LENGTH_MAX).Count() > 0 || waveDigital.Count > GENERATION_LENGTH_MAX) { System.Threading.Thread.Sleep(10); return(null); } foreach (AnalogChannel channel in channelsToAcquireDataFor) { if (logicAnalyserEnabledCurrent && channel == logicAnalyserChannelCurrent) { continue; } float[] wave; if (HardwareInterface == DummyInterface.Generator) { wave = DummyScope.GenerateWave(waveLengthCurrent, SamplePeriodCurrent, timeOffset.Ticks / 1e7, ChannelConfig[channel]); } else if (HardwareInterface == DummyInterface.File) { wave = GetWaveFromFile(channel, waveLengthCurrent, SamplePeriodCurrent, timeOffset.Ticks / 1e7); } #if ANDROID else if (hardwareInterface == DummyInterface.Audio) { //fetch audio data if (audioJack == null) { return(null); } byte[] audioData = new byte[audioBufferLengthInBytes]; int bytesRead = audioJack.Read(audioData, 0, audioBufferLengthInBytes); //2 bytes per sample int watchdog = 0; while (bytesRead <= 0 && watchdog++ < 1000) { System.Threading.Thread.Sleep(1); bytesRead = audioJack.Read(audioData, 0, audioBufferLengthInBytes); //2 bytes per sample } //convert bytes to shorts short[] sampleData = new short[audioData.Length / 2]; Buffer.BlockCopy(audioData, 0, sampleData, 0, sampleData.Length * 2); //and then into floats wave = new float[sampleData.Length]; for (int i = 0; i < wave.Length; i++) { wave [i] = (float)sampleData [i] / (float)short.MaxValue; } //in case of large zoomouts, decimation will be > 0 //FIXME: this is not the best location to do this. time-errors will accumulate. better to do this on eventual wave. but then trigger index etc needs to be adjusted int skip = 1 << (int)decimation; wave = wave.Where((x, i) => i % skip == 0).ToArray(); } #endif else { throw new Exception("Unsupported dummy interface"); } //coupling, noise injection in SW if (!isAudio) { if (ChannelConfig [channel].coupling == Coupling.AC) { DummyScope.RemoveDcComponent(ref wave, ChannelConfig [channel].frequency, SamplePeriodCurrent); } else { DummyScope.AddDcComponent(ref wave, (float)ChannelConfig [channel].dcOffset); } DummyScope.AddNoise(wave, ChannelConfig [channel].noise); } waveAnalog[channel].AddRange(wave); } if (!isAudio && logicAnalyserEnabledCurrent) { waveDigital.AddRange(DummyScope.GenerateWaveDigital(waveLengthCurrent, SamplePeriodCurrent, timeOffset.TotalSeconds)); } triggerHoldoffInSamples = (int)(TriggerHoldoffCurrent / SamplePeriodCurrent); double triggerTimeout = 0.0; if (AcquisitionModeCurrent == AcquisitionMode.AUTO) { triggerTimeout = SamplePeriodCurrent * acquisitionDepthCurrent * 1.0; //Give up after twice the acqbuffer timespan } //detect digital trigger if (logicAnalyserEnabledCurrent && this.triggerValue.mode == TriggerMode.Digital) { triggerDetected = DummyScope.DoTriggerDigital(waveDigital.ToArray(), triggerHoldoffInSamples, digitalTrigger, acquisitionDepthCurrent, out triggerIndex); if (isAudio) { triggerDetected = false; } } else //detect analog trigger { if (triggerValue.source == TriggerSource.External) { triggerDetected = false; } triggerDetected = DummyScope.DoTriggerAnalog(waveAnalog[triggerValue.channel].ToArray(), triggerValue, triggerHoldoffInSamples, triggerThreshold, triggerWidth, acquisitionDepthCurrent, out triggerIndex); } awaitingTrigger = !triggerDetected; //break out of while loop if trigger was detected if (triggerDetected) { forceTrigger = false; awaitingTrigger = false; break; } //break out of while loop if triggerWasForced or synthetical 10ms limit was reached if ( forceTrigger || (triggerTimeout > 0 && waveAnalog[AnalogChannel.ChA].Count * SamplePeriodCurrent >= triggerTimeout) ) { forceTrigger = false; triggerIndex = triggerHoldoffInSamples; awaitingTrigger = false; break; } //keep track of time of first samplemoment var timePassed = new TimeSpan((long)(waveLengthCurrent * SamplePeriodCurrent * 1e7)); timeOffset = timeOffset.Add(timePassed); } //crop wave to only displayable part and store in buffer foreach (AnalogChannel channel in channelsToAcquireDataFor) { if (logicAnalyserEnabledCurrent && channel == logicAnalyserChannelCurrent) { continue; } acquisitionBufferAnalog[channel] = DummyScope.CropWave(acquisitionDepthCurrent, waveAnalog[channel].ToArray(), triggerIndex, triggerHoldoffInSamples); } acquisitionBufferDigital = DummyScope.CropWave(acquisitionDepthCurrent, waveDigital.ToArray(), triggerIndex, triggerHoldoffInSamples); if (StopPending) { acquisitionRunning = false; } } lock (viewportUpdateLock) { if (!viewportUpdate) { return(null); } viewportUpdate = false; } if (acquisitionBufferAnalog.Count == 0) { return(null); } //Decrease the number of samples till viewport sample period is larger than //or equal to the full sample rate uint samples = VIEWPORT_SAMPLES_MAX; int viewportDecimation = 0; while (true) { viewportDecimation = (int)Math.Ceiling(Math.Log(ViewPortTimeSpan / (samples + 2) / SamplePeriodCurrent, 2)); if (viewportDecimation >= 0) { break; } samples /= 2; } if (viewportDecimation > VIEW_DECIMATION_MAX) { Logger.Warn("Clipping view decimation! better decrease the sample rate!"); viewportDecimation = VIEW_DECIMATION_MAX; } int viewportSamples = (int)(ViewPortTimeSpan / (SamplePeriodCurrent * Math.Pow(2, viewportDecimation))) + 2; int viewportOffsetLocal = (int)(ViewPortOffset / SamplePeriodCurrent); p = new DataPackageScope(this.GetType(), acquisitionDepthCurrent, SamplePeriodCurrent, viewportSamples, (Int64)(ViewPortOffset / SamplePeriodCurrent), TriggerHoldoffCurrent, (Int64)(TriggerHoldoffCurrent / SamplePeriodCurrent), false, acquistionId, TriggerValue); p.FullAcquisitionFetchProgress = 1f; p.samplePeriod[ChannelDataSourceScope.Viewport] = SamplePeriodCurrent * Math.Pow(2, viewportDecimation); p.offset[ChannelDataSourceScope.Viewport] = ViewPortOffset; //set values, needed for ETS to work properly if (acquisitionBufferAnalog != null && acquisitionBufferAnalog.ContainsKey(AnalogChannel.ChA)) { p.samplePeriod[ChannelDataSourceScope.Overview] = SamplePeriodCurrent * (float)acquisitionBufferAnalog[AnalogChannel.ChA].Length / (float)OVERVIEW_LENGTH; p.offset[ChannelDataSourceScope.Overview] = 0; } if (acquisitionBufferAnalog.Count == 0) { return(lastCommittedDataPackage); } foreach (AnalogChannel ch in channelsToAcquireDataFor) { if (logicAnalyserEnabledCurrent && ch == logicAnalyserChannelCurrent) { continue; } if (SendOverviewBuffer) { Array arr = GetViewport(acquisitionBufferAnalog[ch], 0, (int)(Math.Log(acquisitionDepthCurrent / OVERVIEW_LENGTH, 2)), OVERVIEW_LENGTH); p.SetData(ChannelDataSourceScope.Overview, ch, arr); } p.SetData(ChannelDataSourceScope.Viewport, ch, GetViewport(acquisitionBufferAnalog[ch], viewportOffsetLocal, viewportDecimation, viewportSamples)); p.SetData(ChannelDataSourceScope.Acquisition, ch, acquisitionBufferAnalog[ch]); //set dummy minmax values p.SaturationLowValue[ch] = float.MinValue; p.SaturationHighValue[ch] = float.MaxValue; //set 20mV as resolution, which is needed for some processors (like freqdetection). Don't go too low, as ETS uses this in its difference detector p.Resolution[ch] = 0.020f; } if (logicAnalyserEnabledCurrent) { if (SendOverviewBuffer) { p.SetData(ChannelDataSourceScope.Overview, LogicAnalyserChannel.LA, GetViewport(acquisitionBufferDigital, 0, (int)(Math.Log(acquisitionDepthCurrent / OVERVIEW_LENGTH, 2)), OVERVIEW_LENGTH)); } p.SetData(ChannelDataSourceScope.Viewport, LogicAnalyserChannel.LA, GetViewport(acquisitionBufferDigital, viewportOffsetLocal, viewportDecimation, viewportSamples)); p.SetData(ChannelDataSourceScope.Acquisition, LogicAnalyserChannel.LA, acquisitionBufferDigital); } if (acquisitionMode == AcquisitionMode.SINGLE) { acquisitionRunning = false; } lastCommittedDataPackage = p; return(p); }