SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
scopevis.cpp
Go to the documentation of this file.
1 // Copyright (C) 2017 F4EXB //
3 // written by Edouard Griffiths //
4 // //
5 // This program is free software; you can redistribute it and/or modify //
6 // it under the terms of the GNU General Public License as published by //
7 // the Free Software Foundation as version 3 of the License, or //
8 // (at your option) any later version. //
9 // //
10 // This program is distributed in the hope that it will be useful, //
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
13 // GNU General Public License V3 for more details. //
14 // //
15 // You should have received a copy of the GNU General Public License //
16 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
18 
19 #include <QDebug>
20 #include <QMutexLocker>
21 
22 #include "scopevis.h"
23 #include "dsp/dspcommands.h"
24 #include "gui/glscope.h"
25 
39 
40 const uint ScopeVis::m_traceChunkSize = 4800;
41 
42 
44  m_glScope(glScope),
45  m_preTriggerDelay(0),
46  m_livePreTriggerDelay(0),
47  m_currentTriggerIndex(0),
48  m_focusedTriggerIndex(0),
49  m_triggerState(TriggerUntriggered),
50  m_focusedTraceIndex(0),
51  m_traceSize(m_traceChunkSize),
52  m_liveTraceSize(m_traceChunkSize),
53  m_nbSamples(0),
54  m_timeBase(1),
55  m_timeOfsProMill(0),
56  m_traceStart(true),
57  m_triggerLocation(0),
58  m_sampleRate(0),
59  m_liveSampleRate(0),
60  m_liveLog2Decim(0),
61  m_traceDiscreteMemory(m_nbTraceMemories),
62  m_freeRun(true),
63  m_maxTraceDelay(0),
64  m_triggerOneShot(false),
65  m_triggerWaitForReset(false),
66  m_currentTraceMemoryIndex(0)
67 {
68  setObjectName("ScopeVis");
71  for (int i = 0; i < (int) Projector::nbProjectionTypes; i++) {
72  m_projectorCache[i] = 0.0;
73  }
74 }
75 
77 {
78  for (std::vector<TriggerCondition*>::iterator it = m_triggerConditions.begin(); it != m_triggerConditions.end(); ++ it) {
79  delete *it;
80  }
81 }
82 
83 void ScopeVis::setLiveRate(int sampleRate)
84 {
85  m_liveSampleRate = sampleRate;
86 
87  if (m_currentTraceMemoryIndex == 0) { // update only in live mode
89  }
90 }
91 
92 void ScopeVis::setLiveRateLog2Decim(int log2Decim)
93 {
94  m_liveLog2Decim = log2Decim;
96 }
97 
98 void ScopeVis::setSampleRate(int sampleRate)
99 {
100  qDebug("ScopeVis::setSampleRate: %d S/s", sampleRate);
101  m_sampleRate = sampleRate;
102 
103  if (m_glScope) {
105  }
106 }
107 
108 void ScopeVis::setTraceSize(uint32_t traceSize, bool emitSignal)
109 {
110  m_traceSize = traceSize;
114 
115  if (m_glScope) {
116  m_glScope->setTraceSize(m_traceSize, emitSignal);
117  }
118 }
119 
120 void ScopeVis::setPreTriggerDelay(uint32_t preTriggerDelay, bool emitSignal)
121 {
122  m_preTriggerDelay = preTriggerDelay;
123 
124  if (m_glScope) {
126  }
127 }
128 
129 void ScopeVis::configure(uint32_t traceSize, uint32_t timeBase, uint32_t timeOfsProMill, uint32_t triggerPre, bool freeRun)
130 {
131  Message* cmd = MsgConfigureScopeVisNG::create(traceSize, timeBase, timeOfsProMill, triggerPre, freeRun);
132  getInputMessageQueue()->push(cmd);
133 }
134 
135 void ScopeVis::addTrace(const TraceData& traceData)
136 {
137  qDebug() << "ScopeVis::addTrace:"
138  << " m_amp: " << traceData.m_amp
139  << " m_ofs: " << traceData.m_ofs
140  << " m_traceDelay: " << traceData.m_traceDelay;
141  Message* cmd = MsgScopeVisNGAddTrace::create(traceData);
142  getInputMessageQueue()->push(cmd);
143 }
144 
145 void ScopeVis::changeTrace(const TraceData& traceData, uint32_t traceIndex)
146 {
147  qDebug() << "ScopeVis::changeTrace:"
148  << " trace: " << traceIndex
149  << " m_amp: " << traceData.m_amp
150  << " m_ofs: " << traceData.m_ofs
151  << " m_traceDelay: " << traceData.m_traceDelay;
152  Message* cmd = MsgScopeVisNGChangeTrace::create(traceData, traceIndex);
153  getInputMessageQueue()->push(cmd);
154 }
155 
157 {
158  qDebug() << "ScopeVis::removeTrace:"
159  << " trace: " << traceIndex;
160  Message* cmd = MsgScopeVisNGRemoveTrace::create(traceIndex);
161  getInputMessageQueue()->push(cmd);
162 }
163 
164 void ScopeVis::moveTrace(uint32_t traceIndex, bool upElseDown)
165 {
166  qDebug() << "ScopeVis::moveTrace:"
167  << " trace: " << traceIndex
168  << " up: " << upElseDown;
169  Message* cmd = MsgScopeVisNGMoveTrace::create(traceIndex, upElseDown);
170  getInputMessageQueue()->push(cmd);
171 }
172 
174 {
175  Message* cmd = MsgScopeVisNGFocusOnTrace::create(traceIndex);
176  getInputMessageQueue()->push(cmd);
177 }
178 
179 void ScopeVis::addTrigger(const TriggerData& triggerData)
180 {
181  Message* cmd = MsgScopeVisNGAddTrigger::create(triggerData);
182  getInputMessageQueue()->push(cmd);
183 }
184 
185 void ScopeVis::changeTrigger(const TriggerData& triggerData, uint32_t triggerIndex)
186 {
187  Message* cmd = MsgScopeVisNGChangeTrigger::create(triggerData, triggerIndex);
188  getInputMessageQueue()->push(cmd);
189 }
190 
192 {
193  Message* cmd = MsgScopeVisNGRemoveTrigger::create(triggerIndex);
194  getInputMessageQueue()->push(cmd);
195 }
196 
197 void ScopeVis::moveTrigger(uint32_t triggerIndex, bool upElseDown)
198 {
199  Message* cmd = MsgScopeVisNGMoveTrigger::create(triggerIndex, upElseDown);
200  getInputMessageQueue()->push(cmd);
201 }
202 
204 {
205  Message* cmd = MsgScopeVisNGFocusOnTrigger::create(triggerIndex);
206  getInputMessageQueue()->push(cmd);
207 }
208 
209 void ScopeVis::setOneShot(bool oneShot)
210 {
211  Message* cmd = MsgScopeVisNGOneShot::create(oneShot);
212  getInputMessageQueue()->push(cmd);
213 }
214 
216 {
217  Message* cmd = MsgScopeVisNGMemoryTrace::create(memoryIndex);
218  getInputMessageQueue()->push(cmd);
219 }
220 
221 void ScopeVis::feed(const SampleVector::const_iterator& cbegin, const SampleVector::const_iterator& end, bool positiveOnly)
222 {
223  (void) positiveOnly;
224 
225  if (m_currentTraceMemoryIndex > 0) { // in memory mode live trace is suspended
226  return;
227  }
228 
229  if (!m_mutex.tryLock(0)) { // prevent conflicts with configuration process
230  return;
231  }
232 
233  if (m_freeRun) {
234  m_triggerLocation = end - cbegin;
235  }
236  else if (m_triggerState == TriggerTriggered) {
237  m_triggerLocation = end - cbegin;
238  }
239  else if (m_triggerState == TriggerUntriggered) {
240  m_triggerLocation = 0;
241  }
242  else if (m_triggerWaitForReset) {
243  m_triggerLocation = 0;
244  }
245  else {
246  m_triggerLocation = end - cbegin;
247  }
248 
249  SampleVector::const_iterator begin(cbegin);
250  int triggerPointToEnd;
251 
252  while (begin < end)
253  {
254  if (begin + m_traceSize > end) // buffer smaller than trace size (end - bagin) < m_traceSize
255  {
256  triggerPointToEnd = -1;
257  processTrace(begin, end, triggerPointToEnd); // use all buffer
258  m_triggerLocation = triggerPointToEnd < 0 ? 0 : triggerPointToEnd; // trim negative values
259  m_triggerLocation = m_triggerLocation > end - begin ? end - begin : m_triggerLocation; // trim past begin values
260 
261  begin = end; // effectively breaks out the loop
262  }
263  else // trace size fits in buffer
264  {
265  triggerPointToEnd = -1;
266  processTrace(begin, begin + m_traceSize, triggerPointToEnd); // use part of buffer to fit trace size
267  //m_triggerPoint = begin + m_traceSize - triggerPointToEnd;
268  m_triggerLocation = end - begin + m_traceSize - triggerPointToEnd; // should always refer to end iterator
269  m_triggerLocation = m_triggerLocation < 0 ? 0 : m_triggerLocation; // trim negative values
270  m_triggerLocation = m_triggerLocation > end - begin ? end - begin : m_triggerLocation; // trim past begin values
271 
272  begin += m_traceSize;
273  }
274  }
275 
276  m_mutex.unlock();
277 }
278 
280 {
282  {
283  int traceMemoryIndex = m_traceDiscreteMemory.currentIndex() - m_currentTraceMemoryIndex; // actual index in memory bank
284 
285  if (traceMemoryIndex < 0) {
286  traceMemoryIndex += m_nbTraceMemories;
287  }
288 
289  SampleVector::const_iterator mend = m_traceDiscreteMemory.at(traceMemoryIndex).m_endPoint;
290  SampleVector::const_iterator mbegin = mend - m_traceSize;
291  SampleVector::const_iterator mbegin_tb = mbegin - m_maxTraceDelay;
292  m_nbSamples = m_traceSize + m_maxTraceDelay;
293 
294  processTraces(mbegin_tb, mbegin, true); // traceback
295  processTraces(mbegin, mend, false);
296  }
297 }
298 
299 void ScopeVis::processTrace(const SampleVector::const_iterator& cbegin, const SampleVector::const_iterator& end, int& triggerPointToEnd)
300 {
301  SampleVector::const_iterator begin(cbegin);
302 
303  // memory storage
304 
305  m_traceDiscreteMemory.current().write(cbegin, end);
306 
307  // Removed in 4.2.4 may cause trigger bug
308  // if (m_traceDiscreteMemory.current().absoluteFill() < m_traceSize)
309  // {
310  // return; // not enough samples in memory
311  // }
312 
313  // trigger process
314 
315  if ((m_freeRun) || (m_triggerConditions.size() == 0)) // immediate re-trigger
316  {
318  {
319  m_traceStart = true; // start trace processing
322  }
323  }
324  else if ((m_triggerState == TriggerUntriggered) || (m_triggerState == TriggerDelay)) // look for trigger or past trigger in delay mode
325  {
326  TriggerCondition* triggerCondition = m_triggerConditions[m_currentTriggerIndex]; // current trigger condition
327 
328  while (begin < end)
329  {
330  if (m_triggerState == TriggerDelay) // delayed trigger
331  {
332  if (triggerCondition->m_triggerDelayCount > 0) // skip samples during delay period
333  {
334  begin += triggerCondition->m_triggerDelayCount;
335  triggerCondition->m_triggerDelayCount = 0;
336  continue;
337  }
338  else // process trigger
339  {
340  if (nextTrigger()) // move to next trigger and keep going
341  {
344  ++begin;
345  continue;
346  }
347  else // this was the last trigger then start trace
348  {
349  m_traceStart = true; // start trace processing
353  triggerPointToEnd = end - begin;
354  break;
355  }
356  }
357  }
358 
359  if (m_triggerComparator.triggered(*begin, *triggerCondition)) // matched the current trigger
360  {
361  if (triggerCondition->m_triggerData.m_triggerDelay > 0)
362  {
363  triggerCondition->m_triggerDelayCount = triggerCondition->m_triggerData.m_triggerDelay; // initialize delayed samples counter
365  ++begin;
366  continue;
367  }
368 
369  if (nextTrigger()) // move to next trigger and keep going
370  {
373  }
374  else // this was the last trigger then start trace
375  {
376  m_traceStart = true; // start of trace processing
380  triggerPointToEnd = end - begin;
381  break;
382  }
383  }
384 
385  ++begin;
386  } // look for trigger
387  } // untriggered or delayed
388 
389  // trace process
390 
392  {
393  int remainder;
394  int count = end - begin; // number of samples in traceback buffer past the current point
395  SampleVector::iterator mend = m_traceDiscreteMemory.current().current();
396  SampleVector::iterator mbegin = mend - count;
397 
398  if (m_traceStart) // start of trace processing
399  {
400  // if trace time is 1s or more the display is progressive so we have to clear it first
401 
402  float traceTime = ((float) m_traceSize) / m_sampleRate;
403 
404  if (traceTime >= 1.0f) {
406  }
407 
408  // process until begin point
409 
410  if (m_maxTraceDelay > 0) { // trace back
412  }
413 
414  if (m_preTriggerDelay > 0) { // pre-trigger
415  processTraces(mbegin - m_preTriggerDelay, mbegin);
416  }
417 
418  // process the rest of the trace
419 
420  remainder = processTraces(mbegin, mend);
421  m_traceStart = false;
422  }
423  else // process the current trace
424  {
425  remainder = processTraces(mbegin, mend);
426  }
427 
428  if (remainder >= 0) // finished
429  {
430  mbegin = mend - remainder;
432  m_traceDiscreteMemory.store(m_preTriggerDelay+remainder); // next memory trace.
435 
436  //if (m_glScope) m_glScope->incrementTraceCounter();
437 
438  // process remainder recursively
439  if (remainder != 0)
440  {
441  int mTriggerPointToEnd = -1;
442 
443  processTrace(mbegin, mend, mTriggerPointToEnd);
444 
445  if (mTriggerPointToEnd >= 0) {
446  triggerPointToEnd = mTriggerPointToEnd;
447  }
448 
449  //qDebug("ScopeVis::processTrace: process remainder recursively (%d %d)", mpoint, mTriggerPoint);
450  }
451  }
452  }
453 }
454 
456 {
457  TriggerCondition *triggerCondition = m_triggerConditions[m_currentTriggerIndex]; // current trigger condition
458 
459  if (triggerCondition->m_triggerData.m_triggerRepeat > 0)
460  {
461  if (triggerCondition->m_triggerCounter < triggerCondition->m_triggerData.m_triggerRepeat)
462  {
463  triggerCondition->m_triggerCounter++;
464  return true; // not final keep going
465  }
466  else
467  {
468  triggerCondition->m_triggerCounter = 0; // reset for next time
469  }
470  }
471 
472  if (m_triggerConditions.size() == 0)
473  {
475  return false; // final
476  }
477  else if (m_currentTriggerIndex < m_triggerConditions.size() - 1) // check if next trigger is available
478  {
480  return true; // not final keep going
481  }
482  else
483  {
484  // now this is really finished
486  return false; // final
487  }
488 }
489 
490 int ScopeVis::processTraces(const SampleVector::const_iterator& cbegin, const SampleVector::const_iterator& end, bool traceBack)
491 {
492  SampleVector::const_iterator begin(cbegin);
493  uint32_t shift = (m_timeOfsProMill / 1000.0) * m_traceSize;
494  uint32_t length = m_traceSize / m_timeBase;
495 
496  while ((begin < end) && (m_nbSamples > 0))
497  {
498  std::vector<TraceControl*>::iterator itCtl = m_traces.m_tracesControl.begin();
499  std::vector<TraceData>::iterator itData = m_traces.m_tracesData.begin();
500  std::vector<float *>::iterator itTrace = m_traces.m_traces[m_traces.currentBufferIndex()].begin();
501 
502  for (; itCtl != m_traces.m_tracesControl.end(); ++itCtl, ++itData, ++itTrace)
503  {
504  if (traceBack && ((end - begin) > itData->m_traceDelay)) { // before start of trace
505  continue;
506  }
507 
508  Projector::ProjectionType projectionType = itData->m_projectionType;
509 
510  if ((*itCtl)->m_traceCount[m_traces.currentBufferIndex()] < m_traceSize)
511  {
512  uint32_t& traceCount = (*itCtl)->m_traceCount[m_traces.currentBufferIndex()]; // reference for code clarity
513  float v;
514 
515  if (projectionType == Projector::ProjectionMagLin)
516  {
517  v = ((*itCtl)->m_projector.run(*begin) - itData->m_ofs)*itData->m_amp - 1.0f;
518  }
519  else if (projectionType == Projector::ProjectionMagSq)
520  {
521  Real magsq = (*itCtl)->m_projector.run(*begin);
522  v = (magsq - itData->m_ofs)*itData->m_amp - 1.0f;
523 
524  if ((traceCount >= shift) && (traceCount < shift+length)) // power display overlay values construction
525  {
526  if (traceCount == shift)
527  {
528  (*itCtl)->m_maxPow = 0.0f;
529  (*itCtl)->m_sumPow = 0.0f;
530  (*itCtl)->m_nbPow = 1;
531  }
532 
533  if (magsq > 0.0f)
534  {
535  if (magsq > (*itCtl)->m_maxPow)
536  {
537  (*itCtl)->m_maxPow = magsq;
538  }
539 
540  (*itCtl)->m_sumPow += magsq;
541  (*itCtl)->m_nbPow++;
542  }
543  }
544 
545  if ((m_nbSamples == 1) && ((*itCtl)->m_nbPow > 0)) // on last sample create power display overlay
546  {
547  double avgPow = (*itCtl)->m_sumPow / (*itCtl)->m_nbPow;
548  itData->m_textOverlay = QString("%1 %2").arg((*itCtl)->m_maxPow, 0, 'e', 2).arg(avgPow, 0, 'e', 2);
549  (*itCtl)->m_nbPow = 0;
550  }
551  }
552  else if (projectionType == Projector::ProjectionMagDB)
553  {
554  Real re = begin->m_real / SDR_RX_SCALEF;
555  Real im = begin->m_imag / SDR_RX_SCALEF;
556  double magsq = re*re + im*im;
557  float pdB = log10f(magsq) * 10.0f;
558  float p = pdB - (100.0f * itData->m_ofs);
559  v = ((p/50.0f) + 2.0f)*itData->m_amp - 1.0f;
560 
561  if ((traceCount >= shift) && (traceCount < shift+length)) // power display overlay values construction
562  {
563  if (traceCount == shift)
564  {
565  (*itCtl)->m_maxPow = 0.0f;
566  (*itCtl)->m_sumPow = 0.0f;
567  (*itCtl)->m_nbPow = 1;
568  }
569 
570  if (magsq > 0.0f)
571  {
572  if (magsq > (*itCtl)->m_maxPow)
573  {
574  (*itCtl)->m_maxPow = magsq;
575  }
576 
577  (*itCtl)->m_sumPow += magsq;
578  (*itCtl)->m_nbPow++;
579  }
580  }
581 
582  if ((m_nbSamples == 1) && ((*itCtl)->m_nbPow > 0)) // on last sample create power display overlay
583  {
584  double avgPow = log10f((*itCtl)->m_sumPow / (*itCtl)->m_nbPow)*10.0;
585  double peakPow = log10f((*itCtl)->m_maxPow)*10.0;
586  double peakToAvgPow = peakPow - avgPow;
587  itData->m_textOverlay = QString("%1 %2 %3").arg(peakPow, 0, 'f', 1).arg(avgPow, 0, 'f', 1).arg(peakToAvgPow, 4, 'f', 1, ' ');
588  (*itCtl)->m_nbPow = 0;
589  }
590  }
591  else
592  {
593  v = ((*itCtl)->m_projector.run(*begin) - itData->m_ofs) * itData->m_amp;
594  }
595 
596  if(v > 1.0f) {
597  v = 1.0f;
598  } else if (v < -1.0f) {
599  v = -1.0f;
600  }
601 
602  (*itTrace)[2*traceCount]
603  = traceCount - shift; // display x
604  (*itTrace)[2*traceCount + 1] = v; // display y
605  traceCount++;
606  }
607  }
608 
609  ++begin;
610  m_nbSamples--;
611  }
612 
613  float traceTime = ((float) m_traceSize) / m_sampleRate;
614 
615  if (traceTime >= 1.0f) { // display continuously if trace time is 1 second or more
617  }
618 
619  if (m_nbSamples == 0) // finished
620  {
621  // display only at trace end if trace time is less than 1 second
622  if (traceTime < 1.0f)
623  {
624  if (m_glScope->getProcessingTraceIndex().load() < 0) {
626  }
627  }
628 
629  // switch to next buffer only if it is not being processed by the scope
630  if (m_glScope->getProcessingTraceIndex().load() != (((int) m_traces.currentBufferIndex() + 1) % 2)) {
632  }
633 
634  return end - begin; // return remainder count
635  }
636  else
637  {
638  return -1; // mark not finished
639  }
640 }
641 
643 {
644 }
645 
647 {
648 }
649 
650 bool ScopeVis::handleMessage(const Message& message)
651 {
652  if (DSPSignalNotification::match(message))
653  {
654  DSPSignalNotification& notif = (DSPSignalNotification&) message;
655  setLiveRate(notif.getSampleRate());
656  qDebug() << "ScopeVis::handleMessage: DSPSignalNotification: m_sampleRate: " << m_sampleRate;
657  return true;
658  }
659  else if (MsgConfigureScopeVisNG::match(message))
660  {
661  QMutexLocker configLocker(&m_mutex);
663 
664  uint32_t traceSize = conf.getTraceSize();
665  uint32_t timeBase = conf.getTimeBase();
666  uint32_t timeOfsProMill = conf.getTimeOfsProMill();
667  uint32_t triggerPre = conf.getTriggerPre();
668  bool freeRun = conf.getFreeRun();
669 
670  if (m_traceSize != traceSize)
671  {
672  setTraceSize(traceSize);
673  }
674 
675  if (m_timeBase != timeBase)
676  {
677  m_timeBase = timeBase;
678 
679  if (m_glScope) {
681  }
682  }
683 
684  if (m_timeOfsProMill != timeOfsProMill)
685  {
686  m_timeOfsProMill = timeOfsProMill;
687 
688  if (m_glScope) {
690  }
691  }
692 
693  if (m_preTriggerDelay != triggerPre)
694  {
695  setPreTriggerDelay(triggerPre);
696  }
697 
698  if (freeRun != m_freeRun)
699  {
700  m_freeRun = freeRun;
701  }
702 
703  qDebug() << "ScopeVis::handleMessage: MsgConfigureScopeVisNG:"
704  << " m_traceSize: " << m_traceSize
705  << " m_timeOfsProMill: " << m_timeOfsProMill
706  << " m_preTriggerDelay: " << m_preTriggerDelay
707  << " m_freeRun: " << m_freeRun;
708 
709  if ((m_glScope) && (m_currentTraceMemoryIndex > 0)) {
711  }
712 
713  return true;
714  }
715  else if (MsgScopeVisNGAddTrigger::match(message))
716  {
717  qDebug() << "ScopeVis::handleMessage: MsgScopeVisNGAddTrigger";
718  QMutexLocker configLocker(&m_mutex);
720  m_triggerConditions.push_back(new TriggerCondition(conf.getTriggerData()));
721  m_triggerConditions.back()->initProjector();
722  return true;
723  }
724  else if (MsgScopeVisNGChangeTrigger::match(message))
725  {
726  QMutexLocker configLocker(&m_mutex);
728  uint32_t triggerIndex = conf.getTriggerIndex();
729  qDebug() << "ScopeVis::handleMessage: MsgScopeVisNGChangeTrigger: " << triggerIndex;
730 
731  if (triggerIndex < m_triggerConditions.size())
732  {
733  m_triggerConditions[triggerIndex]->setData(conf.getTriggerData());
734 
735  if (triggerIndex == m_focusedTriggerIndex)
736  {
740  }
741  }
742 
743  return true;
744  }
745  else if (MsgScopeVisNGRemoveTrigger::match(message))
746  {
747  QMutexLocker configLocker(&m_mutex);
749  uint32_t triggerIndex = conf.getTriggerIndex();
750  qDebug() << "ScopeVis::handleMessage: MsgScopeVisNGRemoveTrigger: " << triggerIndex;
751 
752  if (triggerIndex < m_triggerConditions.size())
753  {
754  TriggerCondition *triggerCondition = m_triggerConditions[triggerIndex];
755  m_triggerConditions.erase(m_triggerConditions.begin() + triggerIndex);
756  delete triggerCondition;
757  }
758 
759  return true;
760  }
761  else if (MsgScopeVisNGMoveTrigger::match(message))
762  {
763  QMutexLocker configLocker(&m_mutex);
765  int triggerIndex = conf.getTriggerIndex();
766  qDebug() << "ScopeVis::handleMessage: MsgScopeVisNGMoveTrigger: " << triggerIndex;
767 
768  if (!conf.getMoveUp() && (triggerIndex == 0)) {
769  return true;
770  }
771 
772  int nextTriggerIndex = (triggerIndex + (conf.getMoveUp() ? 1 : -1)) % m_triggerConditions.size();
773 
774  TriggerCondition *nextTrigger = m_triggerConditions[nextTriggerIndex];
775  m_triggerConditions[nextTriggerIndex] = m_triggerConditions[triggerIndex];
776  m_triggerConditions[triggerIndex] = nextTrigger;
777 
781 
782  return true;
783  }
784  else if (MsgScopeVisNGFocusOnTrigger::match(message))
785  {
787  uint32_t triggerIndex = conf.getTriggerIndex();
788  qDebug() << "ScopeVis::handleMessage: MsgScopeVisNGFocusOnTrigger: " << triggerIndex;
789 
790  if (triggerIndex < m_triggerConditions.size())
791  {
792  m_focusedTriggerIndex = triggerIndex;
796  }
797 
798  return true;
799  }
800  else if (MsgScopeVisNGAddTrace::match(message))
801  {
802  qDebug() << "ScopeVis::handleMessage: MsgScopeVisNGAddTrace";
803  QMutexLocker configLocker(&m_mutex);
804  MsgScopeVisNGAddTrace& conf = (MsgScopeVisNGAddTrace&) message;
810  return true;
811  }
812  else if (MsgScopeVisNGChangeTrace::match(message))
813  {
814  QMutexLocker configLocker(&m_mutex);
816  bool doComputeTriggerLevelsOnDisplay = m_traces.isVerticalDisplayChange(conf.getTraceData(), conf.getTraceIndex());
817  uint32_t traceIndex = conf.getTraceIndex();
818  qDebug() << "ScopeVis::handleMessage: MsgScopeVisNGChangeTrace: " << traceIndex;
819  m_traces.changeTrace(conf.getTraceData(), traceIndex);
821  if (doComputeTriggerLevelsOnDisplay) computeDisplayTriggerLevels();
823  return true;
824  }
825  else if (MsgScopeVisNGRemoveTrace::match(message))
826  {
827  QMutexLocker configLocker(&m_mutex);
829  uint32_t traceIndex = conf.getTraceIndex();
830  qDebug() << "ScopeVis::handleMessage: MsgScopeVisNGRemoveTrace: " << traceIndex;
831  m_traces.removeTrace(traceIndex);
835  return true;
836  }
837  else if (MsgScopeVisNGMoveTrace::match(message))
838  {
839  QMutexLocker configLocker(&m_mutex);
841  uint32_t traceIndex = conf.getTraceIndex();
842  qDebug() << "ScopeVis::handleMessage: MsgScopeVisNGMoveTrace: " << traceIndex;
843  m_traces.moveTrace(traceIndex, conf.getMoveUp());
844  //updateMaxTraceDelay();
847  return true;
848  }
849  else if (MsgScopeVisNGFocusOnTrace::match(message))
850  {
852  uint32_t traceIndex = conf.getTraceIndex();
853  qDebug() << "ScopeVis::handleMessage: MsgScopeVisNGFocusOnTrace: " << traceIndex;
854 
855  if (traceIndex < m_traces.m_tracesData.size())
856  {
857  m_focusedTraceIndex = traceIndex;
861  }
862 
863  return true;
864  }
865  else if (MsgScopeVisNGOneShot::match(message))
866  {
867  qDebug() << "ScopeVis::handleMessage: MsgScopeVisNGOneShot";
868  MsgScopeVisNGOneShot& conf = (MsgScopeVisNGOneShot&) message;
869  bool oneShot = conf.getOneShot();
870  m_triggerOneShot = oneShot;
871  if (m_triggerWaitForReset && !oneShot) m_triggerWaitForReset = false;
872  return true;
873  }
874  else if (MsgScopeVisNGMemoryTrace::match(message))
875  {
877  uint32_t memoryIndex = conf.getMemoryIndex();
878  qDebug() << "ScopeVis::handleMessage: MsgScopeVisNGMemoryTrace: " << memoryIndex;
879 
880  if (memoryIndex != m_currentTraceMemoryIndex)
881  {
882  // transition from live mode
883  if (m_currentTraceMemoryIndex == 0)
884  {
887  }
888 
889  m_currentTraceMemoryIndex = memoryIndex;
890 
891  // transition to live mode
892  if (m_currentTraceMemoryIndex == 0)
893  {
894  setLiveRate(m_liveSampleRate); // reset to live rate
895  setTraceSize(m_liveTraceSize, true); // reset to live trace size
896  setPreTriggerDelay(m_livePreTriggerDelay, true); // reset to live pre-trigger delay
897  }
898  else
899  {
901  }
902  }
903  return true;
904  }
905  else
906  {
907  qDebug() << "ScopeVis::handleMessage" << message.getIdentifier() << " not handled";
908  return false;
909  }
910 }
911 
913 {
914  int maxTraceDelay = 0;
915  bool allocateCache = false;
916  uint32_t projectorCounts[(int) Projector::nbProjectionTypes];
917  memset(projectorCounts, 0, ((int) Projector::nbProjectionTypes)*sizeof(uint32_t));
918  std::vector<TraceData>::iterator itData = m_traces.m_tracesData.begin();
919  std::vector<TraceControl*>::iterator itCtrl = m_traces.m_tracesControl.begin();
920 
921  for (; itData != m_traces.m_tracesData.end(); ++itData, ++itCtrl)
922  {
923  if (itData->m_traceDelay > maxTraceDelay)
924  {
925  maxTraceDelay = itData->m_traceDelay;
926  }
927 
928  if (itData->m_projectionType < 0) {
929  itData->m_projectionType = Projector::ProjectionReal;
930  }
931 
932  if (projectorCounts[(int) itData->m_projectionType] > 0)
933  {
934  allocateCache = true;
935  (*itCtrl)->m_projector.setCacheMaster(false);
936  }
937  else
938  {
939  (*itCtrl)->m_projector.setCacheMaster(true);
940  }
941 
942  projectorCounts[(int) itData->m_projectionType]++;
943  }
944 
945  itCtrl = m_traces.m_tracesControl.begin();
946 
947  for (; itCtrl != m_traces.m_tracesControl.end(); ++itCtrl)
948  {
949  if (allocateCache) {
950  (*itCtrl)->m_projector.setCache(m_projectorCache);
951  } else {
952  (*itCtrl)->m_projector.setCache(0);
953  }
954  }
955 
956  m_maxTraceDelay = maxTraceDelay;
957 }
958 
960 {
961  int shift = (m_timeOfsProMill / 1000.0) * m_traceSize;
962 
963  std::vector<float *>::iterator it0 = m_traces.m_traces[0].begin();
964  std::vector<float *>::iterator it1 = m_traces.m_traces[1].begin();
965 
966  for (; it0 != m_traces.m_traces[0].end(); ++it0, ++it1)
967  {
968  for (unsigned int i = 0; i < m_traceSize; i++)
969  {
970  (*it0)[2*i] = (i - shift); // display x
971  (*it0)[2*i + 1] = 0.0f; // display y
972  (*it1)[2*i] = (i - shift); // display x
973  (*it1)[2*i + 1] = 0.0f; // display y
974  }
975  }
976 }
977 
979 {
980  std::vector<TraceData>::iterator itData = m_traces.m_tracesData.begin();
981 
982  for (; itData != m_traces.m_tracesData.end(); ++itData)
983  {
984  if ((m_focusedTriggerIndex < m_triggerConditions.size()) && (m_triggerConditions[m_focusedTriggerIndex]->m_projector.getProjectionType() == itData->m_projectionType))
985  {
986  float level = m_triggerConditions[m_focusedTriggerIndex]->m_triggerData.m_triggerLevel;
987  float levelPowerLin = level + 1.0f;
988  float levelPowerdB = (100.0f * (level - 1.0f));
989  float v;
990 
991  if ((itData->m_projectionType == Projector::ProjectionMagLin) || (itData->m_projectionType == Projector::ProjectionMagSq))
992  {
993  v = (levelPowerLin - itData->m_ofs)*itData->m_amp - 1.0f;
994  }
995  else if (itData->m_projectionType == Projector::ProjectionMagDB)
996  {
997  float ofsdB = itData->m_ofs * 100.0f;
998  v = ((levelPowerdB + 100.0f - ofsdB)*itData->m_amp)/50.0f - 1.0f;
999  }
1000  else
1001  {
1002  v = (level - itData->m_ofs) * itData->m_amp;
1003  }
1004 
1005  if(v > 1.0f) {
1006  v = 1.0f;
1007  } else if (v < -1.0f) {
1008  v = -1.0f;
1009  }
1010 
1011  itData->m_triggerDisplayLevel = v;
1012  }
1013  else
1014  {
1015  itData->m_triggerDisplayLevel = 2.0f;
1016  }
1017  }
1018 }
1019 
1021 {
1022  if (m_currentTraceMemoryIndex > 0) {
1025  } else {
1027  }
1028 }
void addTrigger(const TriggerData &triggerData)
Definition: scopevis.cpp:179
void newTraces(std::vector< float *> *traces)
Definition: glscope.cpp:103
uint32_t m_triggerRepeat
Number of trigger conditions before the final decisive trigger.
Definition: scopevis.h:114
void addTrace(const TraceData &traceData, int traceSize)
Definition: scopevis.h:917
ScopeVis(GLScope *glScope=0)
Definition: scopevis.cpp:43
const TraceData & getTraceData() const
Definition: scopevis.h:415
uint32_t currentBufferIndex() const
Definition: scopevis.h:1013
static MsgScopeVisNGChangeTrigger * create(const TriggerData &triggerData, uint32_t triggerIndex)
Definition: scopevis.h:318
void changeTrigger(const TriggerData &triggerData, uint32_t triggerIndex)
Definition: scopevis.cpp:185
static MsgScopeVisNGRemoveTrigger * create(uint32_t triggerIndex)
Definition: scopevis.h:342
void write(const SampleVector::const_iterator begin, const SampleVector::const_iterator end)
Definition: scopevis.h:653
void changeTrace(const TraceData &traceData, uint32_t traceIndex)
Definition: scopevis.cpp:145
void push(Message *message, bool emitSignal=true)
Push message onto queue.
std::vector< TraceControl * > m_tracesControl
Corresponding traces control data.
Definition: scopevis.h:876
uint32_t m_focusedTriggerIndex
Index of the trigger that has focus.
Definition: scopevis.h:1126
void processTrace(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, int &triggerPointToEnd)
Definition: scopevis.cpp:299
void moveTrigger(uint32_t triggerIndex, bool upElseDown)
Definition: scopevis.cpp:197
void setTraceSize(int trceSize, bool emitSignal=false)
Definition: glscope.cpp:997
uint32_t getTraceIndex() const
Definition: scopevis.h:482
bool m_triggerWaitForReset
In one shot mode suspended until reset by UI.
Definition: scopevis.h:1147
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
void focusOnTrace(uint32_t traceIndex)
Definition: scopevis.cpp:173
int m_liveSampleRate
Sample rate in live mode.
Definition: scopevis.h:1138
void updateGLScopeDisplay()
Definition: scopevis.cpp:1020
void setTraces(std::vector< ScopeVis::TraceData > *tracesData, std::vector< float *> *traces)
Definition: glscope.cpp:97
std::vector< TraceData > m_tracesData
Corresponding traces data.
Definition: scopevis.h:877
Calculate logarithmic (dB) of squared magnitude.
Definition: projector.h:31
void removeTrace(uint32_t traceIndex)
Definition: scopevis.cpp:156
const TriggerData & getTriggerData() const
Definition: scopevis.h:303
TraceBackBuffer & current()
Definition: scopevis.h:758
QMutex m_mutex
Definition: scopevis.h:1144
SampleVector::iterator current()
Definition: scopevis.h:662
ProjectionType
Definition: projector.h:25
void setTriggerPre(uint32_t triggerPre, bool emitSignal=false)
number of samples
Definition: glscope.cpp:965
uint32_t currentIndex() const
Definition: scopevis.h:774
bool nextTrigger()
Returns true if not final.
Definition: scopevis.cpp:455
int m_focusedTraceIndex
Index of the trace that has focus.
Definition: scopevis.h:1129
Trigger is not kicked off yet (or trigger list is empty)
Definition: scopevis.h:565
Gives the number of projections in the enum.
Definition: projector.h:38
void setLiveRate(int sampleRate)
Definition: scopevis.cpp:83
uint32_t m_timeOfsProMill
Start trace shift in 1/1000 trace size.
Definition: scopevis.h:1134
static MsgConfigureScopeVisNG * create(uint32_t traceSize, uint32_t timeBase, uint32_t timeOfsProMill, uint32_t triggerPre, bool freeRun)
Definition: scopevis.h:256
Trigger conditions have been kicked off but it is waiting for delay before final kick off...
Definition: scopevis.h:567
void setFocusedTriggerData(ScopeVis::TriggerData &triggerData)
Definition: glscope.h:75
int m_traceDelay
Trace delay in number of samples.
Definition: scopevis.h:57
unsigned int uint32_t
Definition: rtptypes_win.h:46
static MsgScopeVisNGFocusOnTrace * create(uint32_t traceIndex)
Definition: scopevis.h:500
const TriggerData & getTriggerData() const
Definition: scopevis.h:324
#define SDR_RX_SCALEF
Definition: dsptypes.h:33
void setMemoryIndex(uint32_t memoryIndex)
Definition: scopevis.cpp:215
Real m_projectorCache[(int) Projector::nbProjectionTypes]
Definition: scopevis.h:1145
static MsgScopeVisNGMoveTrigger * create(uint32_t triggerIndex, bool moveUpElseDown)
Definition: scopevis.h:363
void setConfigChanged()
Definition: glscope.h:76
uint32_t getTriggerPre() const
Definition: scopevis.h:269
virtual ~ScopeVis()
Definition: scopevis.cpp:76
uint32_t m_triggerCounter
Counter of trigger occurrences.
Definition: scopevis.h:577
virtual void feed(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, bool positiveOnly)
Definition: scopevis.cpp:221
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
static MsgScopeVisNGMoveTrace * create(uint32_t traceIndex, bool moveUpElseDown)
Definition: scopevis.h:475
uint32_t m_traceSize
Size of traces in number of samples.
Definition: scopevis.h:1130
uint32_t m_livePreTriggerDelay
Pre-trigger delay in number of samples in live mode.
Definition: scopevis.h:1123
void updateDisplay()
Definition: glscope.cpp:1008
uint32_t m_liveTraceSize
Size of traces in number of samples in live mode.
Definition: scopevis.h:1131
static MsgScopeVisNGFocusOnTrigger * create(uint32_t triggerIndex)
Definition: scopevis.h:388
GLScope * m_glScope
Definition: scopevis.h:1121
int m_liveLog2Decim
Sample rate decimation log2 in live mode.
Definition: scopevis.h:1139
static MsgScopeVisNGMemoryTrace * create(uint32_t memoryIndex)
Definition: scopevis.h:542
TraceBackBuffer & at(int index)
Definition: scopevis.h:766
uint32_t m_triggerDelayCount
Counter of samples for delay.
Definition: scopevis.h:576
void configure(uint32_t traceSize, uint32_t timeBase, uint32_t timeOfsProMill, uint32_t triggerPre, bool freeRun)
Definition: scopevis.cpp:129
void focusOnTrigger(uint32_t triggerIndex)
Definition: scopevis.cpp:203
TraceBackBuffer & store(int samplesToReport)
Definition: scopevis.h:736
void moveTrace(uint32_t traceIndex, bool upElseDown)
Definition: scopevis.cpp:164
uint32_t m_timeBase
Trace display time divisor.
Definition: scopevis.h:1133
int m_triggerLocation
Trigger location from end point.
Definition: scopevis.h:1136
int m_maxTraceDelay
Maximum trace delay.
Definition: scopevis.h:1142
int32_t i
Definition: decimators.h:244
uint32_t m_currentTriggerIndex
Index of current index in the chain.
Definition: scopevis.h:1125
static MsgScopeVisNGOneShot * create(bool oneShot)
Definition: scopevis.h:521
void setFocusedTraceIndex(uint32_t traceIndex)
Definition: glscope.cpp:983
void setPreTriggerDelay(uint32_t preTriggerDelay, bool emitSignal=false)
Definition: scopevis.cpp:120
static bool match(const Message *message)
Definition: message.cpp:45
Calculate linear magnitude or modulus.
Definition: projector.h:29
TriggerData m_triggerData
Trigger data.
Definition: scopevis.h:574
virtual void start()
Definition: scopevis.cpp:642
static MsgScopeVisNGChangeTrace * create(const TraceData &traceData, uint32_t traceIndex)
Definition: scopevis.h:430
Calculate linear squared magnitude or power.
Definition: projector.h:30
void switchBuffer()
Definition: scopevis.h:1016
bool m_traceStart
Trace is at start point.
Definition: scopevis.h:1135
void setTimeBase(int timeBase)
Definition: glscope.cpp:958
void setOneShot(bool oneShot)
Definition: scopevis.cpp:209
float m_amp
Amplification factor.
Definition: scopevis.h:52
static const uint32_t m_traceChunkSize
Definition: scopevis.h:150
void setSampleRate(int sampleRate)
Definition: scopevis.cpp:98
void initTraceBuffers()
Definition: scopevis.cpp:959
void resize(uint32_t size)
Definition: scopevis.h:721
bool triggered(const Sample &s, TriggerCondition &triggerCondition)
Definition: scopevis.h:1039
uint32_t m_preTriggerDelay
Pre-trigger delay in number of samples.
Definition: scopevis.h:1122
Traces m_traces
Displayable traces.
Definition: scopevis.h:1128
static const uint32_t m_nbTraceMemories
Definition: scopevis.h:153
void computeDisplayTriggerLevels()
Definition: scopevis.cpp:978
void changeTrace(const TraceData &traceData, uint32_t traceIndex)
Definition: scopevis.h:933
uint32_t getMemoryIndex() const
Definition: scopevis.h:548
void processMemoryTrace()
Definition: scopevis.cpp:279
uint32_t getTriggerIndex() const
Definition: scopevis.h:370
uint32_t getTimeBase() const
Definition: scopevis.h:267
SampleVector::iterator m_endPoint
Definition: scopevis.h:636
const QAtomicInt & getProcessingTraceIndex() const
Definition: glscope.h:82
void setTraceSize(uint32_t traceSize, bool emitSignal=false)
Definition: scopevis.cpp:108
void setTimeOfsProMill(int timeOfsProMill)
Definition: glscope.cpp:976
Trigger has been kicked off.
Definition: scopevis.h:566
int getSampleRate() const
Definition: dspcommands.h:328
void addTrace(const TraceData &traceData)
Definition: scopevis.cpp:135
virtual void stop()
Definition: scopevis.cpp:646
const TraceData & getTraceData() const
Definition: scopevis.h:436
virtual const char * getIdentifier() const
Definition: message.cpp:35
static MsgScopeVisNGRemoveTrace * create(uint32_t traceIndex)
Definition: scopevis.h:454
uint32_t m_triggerDelay
Delay before the trigger is kicked off in number of samples (trigger delay)
Definition: scopevis.h:110
uint32_t getTraceSize() const
Definition: scopevis.h:266
int m_nbSamples
Number of samples yet to process in one complex trace.
Definition: scopevis.h:1132
void resize(int traceSize)
Definition: scopevis.h:989
uint32_t m_currentTraceMemoryIndex
The current index of trace in memory (0: current)
Definition: scopevis.h:1148
int processTraces(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, bool traceBack=false)
Definition: scopevis.cpp:490
static MsgScopeVisNGAddTrace * create(const TraceData &traceData)
Definition: scopevis.h:409
std::vector< TriggerCondition * > m_triggerConditions
Chain of triggers.
Definition: scopevis.h:1124
void moveTrace(uint32_t traceIndex, bool upElseDown)
Definition: scopevis.h:960
bool isVerticalDisplayChange(const TraceData &traceData, uint32_t traceIndex)
Definition: scopevis.h:909
TriggerComparator m_triggerComparator
Compares sample level to trigger level.
Definition: scopevis.h:1143
void setLiveRateLog2Decim(int log2Decim)
Definition: scopevis.cpp:92
TraceBackDiscreteMemory m_traceDiscreteMemory
Complex trace memory for triggered states TODO: vectorize when more than on input is allowed...
Definition: scopevis.h:1140
TriggerState m_triggerState
Current trigger state.
Definition: scopevis.h:1127
void removeTrigger(uint32_t triggerIndex)
Definition: scopevis.cpp:191
float Real
Definition: dsptypes.h:42
uint32_t getTraceIndex() const
Definition: scopevis.h:460
bool m_triggerOneShot
True when one shot mode is active.
Definition: scopevis.h:1146
uint32_t getTraceIndex() const
Definition: scopevis.h:437
float m_ofs
Offset factor.
Definition: scopevis.h:54
int m_sampleRate
Actual sample rate being used.
Definition: scopevis.h:1137
uint32_t getTimeOfsProMill() const
Definition: scopevis.h:268
void setSampleRate(int sampleRate)
Definition: glscope.cpp:950
static MsgScopeVisNGAddTrigger * create(const TriggerData &triggerData)
Definition: scopevis.h:297
void updateMaxTraceDelay()
Definition: scopevis.cpp:912
std::vector< float * > m_traces[2]
Double buffer of traces processed by glScope.
Definition: scopevis.h:878
void removeTrace(uint32_t traceIndex)
Definition: scopevis.h:943
bool m_freeRun
True if free running (trigger globally disabled)
Definition: scopevis.h:1141
Extract real part.
Definition: projector.h:27
virtual bool handleMessage(const Message &message)
Processing of a message. Returns true if message has actually been processed.
Definition: scopevis.cpp:650