diff --git a/Readme.md b/Readme.md
index ae0f70c38..3b05ec01c 100644
--- a/Readme.md
+++ b/Readme.md
@@ -116,13 +116,13 @@ Done since the fork
- Enhanced channel analyzer: enhanced scope and spectrum displays as mentioned above, make the spectrum display synchronous to scope (hence triggerable a la E4406A).
- Sort channel plugins by delta frequency and type before saving to preset
- Implemented scope pre-trigger delay
+ - Implemented variable scope memory depth
+ - Implemented trigger delay
=====
To Do
=====
- - Variable scope memory depth
- - Trigger delay
- Enhance presets management (Edit, Move, Import/Export from/to human readable format like JSON)
- Level calibration
- Enhance WFM (stereo, RDS?)
diff --git a/include-gpl/dsp/scopevis.h b/include-gpl/dsp/scopevis.h
index b5cfd652e..04804b0e9 100644
--- a/include-gpl/dsp/scopevis.h
+++ b/include-gpl/dsp/scopevis.h
@@ -24,7 +24,13 @@ public:
ScopeVis(GLScope* glScope = NULL);
- void configure(MessageQueue* msgQueue, TriggerChannel triggerChannel, Real triggerLevel, bool triggerPositiveEdge, uint triggerPre, uint traceSize);
+ void configure(MessageQueue* msgQueue,
+ TriggerChannel triggerChannel,
+ Real triggerLevel,
+ bool triggerPositiveEdge,
+ uint triggerPre,
+ uint triggerDelay,
+ uint traceSize);
void setOneShot(bool oneShot);
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
@@ -46,11 +52,17 @@ private:
Real getTriggerLevel() const { return m_triggerLevel; }
Real getTriggerPositiveEdge() const { return m_triggerPositiveEdge; }
uint getTriggerPre() const { return m_triggerPre; }
+ uint getTriggerDelay() const { return m_triggerDelay; }
uint getTraceSize() const { return m_traceSize; }
- static MsgConfigureScopeVis* create(int triggerChannel, Real triggerLevel, bool triggerPositiveEdge, uint triggerPre, uint traceSize)
+ static MsgConfigureScopeVis* create(int triggerChannel,
+ Real triggerLevel,
+ bool triggerPositiveEdge,
+ uint triggerPre,
+ uint triggerDelay,
+ uint traceSize)
{
- return new MsgConfigureScopeVis(triggerChannel, triggerLevel, triggerPositiveEdge, triggerPre, traceSize);
+ return new MsgConfigureScopeVis(triggerChannel, triggerLevel, triggerPositiveEdge, triggerPre, triggerDelay, traceSize);
}
private:
@@ -58,22 +70,44 @@ private:
Real m_triggerLevel;
bool m_triggerPositiveEdge;
uint m_triggerPre;
+ uint m_triggerDelay;
uint m_traceSize;
- MsgConfigureScopeVis(int triggerChannel, Real triggerLevel, bool triggerPositiveEdge, uint triggerPre, uint traceSize) :
+ MsgConfigureScopeVis(int triggerChannel,
+ Real triggerLevel,
+ bool triggerPositiveEdge,
+ uint triggerPre,
+ uint triggerDelay,
+ uint traceSize) :
Message(),
m_triggerChannel(triggerChannel),
m_triggerLevel(triggerLevel),
m_triggerPositiveEdge(triggerPositiveEdge),
m_triggerPre(triggerPre),
+ m_triggerDelay(triggerDelay),
m_traceSize(traceSize)
{ }
};
+ /**
+ * TriggerState:
+ *
+ * send a Trigger condition +--------------------+
+ * dummy trace - Immediate m_triggerOneShot | |
+ * Config -------------> Untriggered ----------------------------------> Triggered ----------------> WaitForReset |
+ * ^ ^ | ^ | | ^ |
+ * | | | - Delayed Delay expired | | | | setOneShot(true)|
+ * | | +---------------------> Delay ----------------+ | | +-----------------+
+ * | | !m_triggerOneShot | |
+ * | +--------------------------------------------------+ setOneShot(false) |
+ * +-------------------------------------------------------------------------------+
+ */
enum TriggerState {
- Untriggered,
- Triggered,
- WaitForReset
+ Untriggered, //!< Search for trigger
+ Config, //!< New configuration has just been received
+ Triggered, //!< Trigger was kicked off
+ WaitForReset, //!< Wait for release from GUI
+ Delay //!< Trigger delay engaged
};
GLScope* m_glScope;
@@ -85,9 +119,11 @@ private:
TriggerChannel m_triggerChannel;
Real m_triggerLevel;
bool m_triggerPositiveEdge;
- uint m_triggerPre; //!< Pre-trigger delay in number of samples
+ uint m_triggerPre; //!< Pre-trigger delay in number of samples
bool m_triggerOneShot;
bool m_armed;
+ uint m_triggerDelay; //!< Trigger delay in number of trace sizes
+ uint m_triggerDelayCount; //!< trace sizes delay counter
int m_sampleRate;
SampleVector::const_iterator m_triggerPoint;
diff --git a/include-gpl/gui/glscopegui.h b/include-gpl/gui/glscopegui.h
index 5d5afbc4a..8ba9b0aef 100644
--- a/include-gpl/gui/glscopegui.h
+++ b/include-gpl/gui/glscopegui.h
@@ -52,6 +52,7 @@ private:
qint32 m_triggerLevel; // percent
bool m_triggerPositiveEdge;
qint32 m_triggerPre;
+ qint32 m_triggerDelay;
qint32 m_traceLenMult;
static const qreal amps[11];
@@ -65,6 +66,7 @@ private:
void setAmpOfsDisplay();
void setTrigLevelDisplay();
void setTrigPreDisplay();
+ void setTrigDelayDisplay();
private slots:
void on_amp_valueChanged(int value);
@@ -78,6 +80,7 @@ private slots:
void on_gridIntensity_valueChanged(int index);
void on_traceIntensity_valueChanged(int index);
void on_trigPre_valueChanged(int value);
+ void on_trigDelay_valueChanged(int value);
void on_horizView_clicked();
void on_vertView_clicked();
diff --git a/sdrbase/dsp/scopevis.cpp b/sdrbase/dsp/scopevis.cpp
index a08f5f7c8..3a8447cf1 100644
--- a/sdrbase/dsp/scopevis.cpp
+++ b/sdrbase/dsp/scopevis.cpp
@@ -20,6 +20,8 @@ ScopeVis::ScopeVis(GLScope* glScope) :
m_triggerLevel(0.0),
m_triggerPositiveEdge(true),
m_triggerPre(0),
+ m_triggerDelay(0),
+ m_triggerDelayCount(0),
m_triggerOneShot(false),
m_armed(false),
m_sampleRate(0)
@@ -29,9 +31,15 @@ ScopeVis::ScopeVis(GLScope* glScope) :
m_traceback.resize(20*m_traceChunkSize);
}
-void ScopeVis::configure(MessageQueue* msgQueue, TriggerChannel triggerChannel, Real triggerLevel, bool triggerPositiveEdge, uint triggerPre, uint traceSize)
+void ScopeVis::configure(MessageQueue* msgQueue,
+ TriggerChannel triggerChannel,
+ Real triggerLevel,
+ bool triggerPositiveEdge,
+ uint triggerPre,
+ uint triggerDelay,
+ uint traceSize)
{
- Message* cmd = MsgConfigureScopeVis::create(triggerChannel, triggerLevel, triggerPositiveEdge, triggerPre, traceSize);
+ Message* cmd = MsgConfigureScopeVis::create(triggerChannel, triggerLevel, triggerPositiveEdge, triggerPre, triggerDelay, traceSize);
cmd->submit(msgQueue, this);
}
@@ -77,6 +85,30 @@ void ScopeVis::feed(SampleVector::const_iterator begin, SampleVector::const_iter
{
break;
}
+ if(m_triggerState == Config)
+ {
+ m_glScope->newTrace(m_trace, m_sampleRate); // send a dummy trace
+ m_triggerState = Untriggered;
+ }
+ if(m_triggerState == Delay)
+ {
+ int count = end - begin;
+ if (count > (int)(m_trace.size() - m_fill))
+ {
+ count = m_trace.size() - m_fill;
+ }
+ begin += count;
+ m_fill += count;
+ if(m_fill >= m_trace.size())
+ {
+ m_fill = 0;
+ m_triggerDelayCount--;
+ if (m_triggerDelayCount == 0)
+ {
+ m_triggerState = Triggered;
+ }
+ }
+ }
if(m_triggerState == Untriggered)
{
while(begin < end)
@@ -88,14 +120,23 @@ void ScopeVis::feed(SampleVector::const_iterator begin, SampleVector::const_iter
{
if (m_armed)
{
- m_triggerState = Triggered;
m_armed = false;
- m_triggerPoint = begin;
- // fill beginning of m_trace with delayed samples from the trace memory FIFO. Increment m_fill accordingly.
- if (m_triggerPre) { // do this process only if there is a pre-trigger delay
- std::copy(m_traceback.end() - m_triggerPre - 1, m_traceback.end() - 1, m_trace.begin());
- m_fill = m_triggerPre; // Increment m_fill accordingly (from 0).
- }
+ if (m_triggerDelay > 0)
+ {
+ m_triggerDelayCount = m_triggerDelay;
+ m_fill = 0;
+ m_triggerState = Delay;
+ }
+ else
+ {
+ m_triggerState = Triggered;
+ m_triggerPoint = begin;
+ // fill beginning of m_trace with delayed samples from the trace memory FIFO. Increment m_fill accordingly.
+ if (m_triggerPre) { // do this process only if there is a pre-trigger delay
+ std::copy(m_traceback.end() - m_triggerPre - 1, m_traceback.end() - 1, m_trace.begin());
+ m_fill = m_triggerPre; // Increment m_fill accordingly (from 0).
+ }
+ }
break;
}
}
@@ -154,7 +195,7 @@ bool ScopeVis::handleMessageKeep(Message* message)
} else if(MsgConfigureScopeVis::match(message)) {
MsgConfigureScopeVis* conf = (MsgConfigureScopeVis*)message;
m_tracebackCount = 0;
- m_triggerState = Untriggered;
+ m_triggerState = Config;
m_triggerChannel = (TriggerChannel) conf->getTriggerChannel();
m_triggerLevel = conf->getTriggerLevel();
m_triggerPositiveEdge = conf->getTriggerPositiveEdge();
@@ -162,6 +203,7 @@ bool ScopeVis::handleMessageKeep(Message* message)
if (m_triggerPre >= m_traceback.size()) {
m_triggerPre = m_traceback.size() - 1; // top sample in FIFO is always the triggering one (pre-trigger delay = 0)
}
+ m_triggerDelay = conf->getTriggerDelay();
uint newSize = conf->getTraceSize();
if (newSize != m_trace.size()) {
m_trace.resize(newSize);
@@ -174,6 +216,7 @@ bool ScopeVis::handleMessageKeep(Message* message)
<< " m_triggerLevel: " << m_triggerLevel
<< " m_triggerPositiveEdge: " << (m_triggerPositiveEdge ? "edge+" : "edge-")
<< " m_preTrigger: " << m_triggerPre
+ << " m_triggerDelay: " << m_triggerDelay
<< " m_traceSize: " << m_trace.size() << std::endl;
return true;
/*
diff --git a/sdrbase/gui/glscopegui.cpp b/sdrbase/gui/glscopegui.cpp
index e787cd676..7423d0243 100644
--- a/sdrbase/gui/glscopegui.cpp
+++ b/sdrbase/gui/glscopegui.cpp
@@ -29,6 +29,7 @@ GLScopeGUI::GLScopeGUI(QWidget* parent) :
m_triggerLevel(0.0),
m_triggerPositiveEdge(true),
m_triggerPre(0),
+ m_triggerDelay(0),
m_traceLenMult(20)
{
ui->setupUi(this);
@@ -62,6 +63,12 @@ void GLScopeGUI::resetToDefaults()
m_timeOffset = 0;
m_amplification = 0;
m_displayGridIntensity = 5;
+ m_triggerChannel = ScopeVis::TriggerFreeRun;
+ m_triggerLevel = 0.0;
+ m_triggerPositiveEdge = true;
+ m_triggerPre = 0;
+ m_triggerDelay = 0;
+ m_traceLenMult = 20;
applySettings();
}
@@ -83,6 +90,7 @@ QByteArray GLScopeGUI::serialize() const
s.writeS32(12, m_displayTraceIntensity);
s.writeS32(13, m_triggerPre);
s.writeS32(14, m_traceLenMult);
+ s.writeS32(15, m_triggerDelay);
return s.final();
}
@@ -122,6 +130,9 @@ bool GLScopeGUI::deserialize(const QByteArray& data)
d.readS32(14, &m_traceLenMult, 20);
ui->traceLen->setValue(m_traceLenMult);
setTraceLenDisplay();
+ d.readS32(15, &m_triggerDelay, 0);
+ ui->trigDelay->setValue(m_triggerDelay);
+ setTrigDelayDisplay();
applySettings();
applyTriggerSettings();
return true;
@@ -194,6 +205,7 @@ void GLScopeGUI::applyTriggerSettings()
triggerLevel,
m_triggerPositiveEdge,
preTriggerSamples,
+ m_triggerDelay,
m_traceLenMult * ScopeVis::m_traceChunkSize);
}
@@ -250,6 +262,7 @@ void GLScopeGUI::on_scope_traceSizeChanged(int)
setTraceLenDisplay();
setTimeOfsDisplay();
setTrigPreDisplay();
+ setTrigDelayDisplay();
applySettings();
applyTriggerSettings();
}
@@ -261,6 +274,7 @@ void GLScopeGUI::on_scope_sampleRateChanged(int)
setTraceLenDisplay();
setTimeOfsDisplay();
setTrigPreDisplay();
+ setTrigDelayDisplay();
applySettings();
applyTriggerSettings();
}
@@ -307,6 +321,32 @@ void GLScopeGUI::setTraceLenDisplay()
else ui->traceLenText->setText(tr("%1\ns").arg(t * 1.0));
}
+void GLScopeGUI::setTrigDelayDisplay()
+{
+ uint n_samples_delay = m_traceLenMult * ScopeVis::m_traceChunkSize * m_triggerDelay;
+
+ if (n_samples_delay < 1000) {
+ ui->trigDelayText->setToolTip(tr("%1S").arg(n_samples_delay));
+ } else if (n_samples_delay < 1000000) {
+ ui->trigDelayText->setToolTip(tr("%1kS").arg(n_samples_delay/1000.0));
+ } else if (n_samples_delay < 1000000000) {
+ ui->trigDelayText->setToolTip(tr("%1MS").arg(n_samples_delay/1000000.0));
+ } else {
+ ui->trigDelayText->setToolTip(tr("%1GS").arg(n_samples_delay/1000000000.0));
+ }
+
+ m_sampleRate = m_glScope->getSampleRate();
+ qreal t = (n_samples_delay * 1.0 / m_sampleRate);
+
+ if(t < 0.000001)
+ ui->trigDelayText->setText(tr("%1\nns").arg(t * 1000000000.0));
+ else if(t < 0.001)
+ ui->trigDelayText->setText(tr("%1\nµs").arg(t * 1000000.0));
+ else if(t < 1.0)
+ ui->trigDelayText->setText(tr("%1\nms").arg(t * 1000.0));
+ else ui->trigDelayText->setText(tr("%1\ns").arg(t * 1.0));
+}
+
void GLScopeGUI::setTimeOfsDisplay()
{
qreal dt = m_glScope->getTraceSize() * (m_timeOffset/100.0) / m_sampleRate;
@@ -364,7 +404,7 @@ void GLScopeGUI::on_timeOfs_valueChanged(int value)
void GLScopeGUI::on_trigPre_valueChanged(int value)
{
- if ((value < 0) || (value > 99)) {
+ if ((value < 0) || (value > 100)) {
return;
}
m_triggerPre = value;
@@ -372,6 +412,16 @@ void GLScopeGUI::on_trigPre_valueChanged(int value)
applyTriggerSettings();
}
+void GLScopeGUI::on_trigDelay_valueChanged(int value)
+{
+ if ((value < 0) || (value > 100)) {
+ return;
+ }
+ m_triggerDelay = value;
+ setTrigDelayDisplay();
+ applyTriggerSettings();
+}
+
void GLScopeGUI::on_dataMode_currentIndexChanged(int index)
{
m_displayData = index;
diff --git a/sdrbase/gui/glscopegui.ui b/sdrbase/gui/glscopegui.ui
index 5cce46ec3..9e5e88e55 100644
--- a/sdrbase/gui/glscopegui.ui
+++ b/sdrbase/gui/glscopegui.ui
@@ -752,6 +752,33 @@
+ -
+
+
+ Dly
+
+
+
+ -
+
+
+ 100
+
+
+ 1
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ 0
+
+
+
-