From e6f80c8474d7884fc4b7a4d40ca5e7c5018954b3 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 1 Feb 2017 18:31:16 +0100 Subject: [PATCH] New scope: interim state (3) --- sdrbase/dsp/scopevisng.cpp | 202 ++++++++++++++++++++---------------- sdrbase/dsp/scopevisng.h | 127 +++++++++++++++++++---- sdrbase/util/doublebuffer.h | 2 + 3 files changed, 226 insertions(+), 105 deletions(-) diff --git a/sdrbase/dsp/scopevisng.cpp b/sdrbase/dsp/scopevisng.cpp index c81d4807b..1a30a4fa9 100644 --- a/sdrbase/dsp/scopevisng.cpp +++ b/sdrbase/dsp/scopevisng.cpp @@ -38,16 +38,17 @@ ScopeVisNG::ScopeVisNG(GLScopeNG* glScope) : m_currentTriggerIndex(0), m_triggerState(TriggerUntriggered), m_traceSize(m_traceChunkSize), + m_memTraceSize(0), m_traceStart(true), m_traceFill(0), m_zTraceIndex(-1), m_traceCompleteCount(0), m_timeOfsProMill(0), - m_sampleRate(0) + m_sampleRate(0), + m_traceDiscreteMemory(10) { setObjectName("ScopeVisNG"); - m_tracebackBuffers.resize(1); - m_tracebackBuffers[0].resize(4*m_traceChunkSize); + m_traceDiscreteMemory.resize(m_traceChunkSize); // arbitrary } ScopeVisNG::~ScopeVisNG() @@ -114,8 +115,6 @@ void ScopeVisNG::removeTrigger(uint32_t triggerIndex) void ScopeVisNG::feed(const SampleVector::const_iterator& cbegin, const SampleVector::const_iterator& end, bool positiveOnly) { - uint32_t feedIndex = 0; // TODO: redefine feed interface so it can be passed a feed index - if (m_triggerState == TriggerFreeRun) { m_triggerPoint = cbegin; } @@ -142,19 +141,51 @@ void ScopeVisNG::feed(const SampleVector::const_iterator& cbegin, const SampleVe return; } - m_tracebackBuffers[feedIndex].write(cbegin, end); SampleVector::const_iterator begin(cbegin); - TriggerCondition& triggerCondition = m_triggerConditions[m_currentTriggerIndex]; + + // memory storage + + if ((m_triggerState == TriggerFreeRun) && (m_triggerConditions.size() > 0)) + { + m_traceDiscreteMemory.current().write(cbegin, end); + + if (m_traceDiscreteMemory.current().absoluteFill() < m_traceSize) + { + return; // not enough samples in memory + } + } + else + { + // TODO: continuous memory + } // trigger process - if ((m_triggerConditions.size() > 0) && (feedIndex == triggerCondition.m_triggerData.m_inputIndex)) + + if ((m_triggerConditions.size() > 0) && ((m_triggerState == TriggerUntriggered) || (m_triggerState == TriggerDelay))) { + TriggerCondition& triggerCondition = m_triggerConditions[m_currentTriggerIndex]; // current trigger condition + while (begin < end) { - if (m_triggerState == TriggerUntriggered) - { - bool condition = triggerCondition.m_projector->run(*begin) > triggerCondition.m_triggerData.m_triggerLevel; - bool trigger; + if (m_triggerState == TriggerDelay) + { + if (triggerCondition.m_triggerDelayCount > 0) + { + triggerCondition.m_triggerDelayCount--; // pass + } + else // delay expired => fire this trigger + { + if (!nextTrigger()) // finished + { + m_traceStart = true; // start trace processing + break; + } + } + } + else // look for trigger + { + bool condition = triggerCondition.m_projector->run(*begin) > triggerCondition.m_triggerData.m_triggerLevel; + bool trigger; if (triggerCondition.m_triggerData.m_triggerBothEdges) { trigger = triggerCondition.m_prevCondition ^ condition; @@ -162,103 +193,68 @@ void ScopeVisNG::feed(const SampleVector::const_iterator& cbegin, const SampleVe trigger = condition ^ !triggerCondition.m_triggerData.m_triggerPositiveEdge; } - if (trigger) + if (trigger) // trigger condition { - if (triggerCondition.m_triggerData.m_triggerDelay > 0) + if (triggerCondition.m_triggerData.m_triggerDelay > 0) // there is a delay => initialize the delay { triggerCondition.m_triggerDelayCount = triggerCondition.m_triggerData.m_triggerDelay; m_triggerState == TriggerDelay; } else { - if (triggerCondition.m_triggerCounter > 0) - { - triggerCondition.m_triggerCounter--; - m_triggerState = TriggerUntriggered; - } - else - { - // next trigger - m_currentTriggerIndex++; - - if (m_currentTriggerIndex == m_triggerConditions.size()) - { - m_currentTriggerIndex = 0; - m_triggerState = TriggerTriggered; - m_triggerPoint = begin; - triggerCondition.m_triggerCounter = triggerCondition.m_triggerData.m_triggerCounts; - m_traceStart = true; - break; - } - else - { - m_triggerState = TriggerUntriggered; - } - } + if (!nextTrigger()) // finished + { + m_traceStart = true; // start trace processing + break; + } } } - } - else if (m_triggerState == TriggerDelay) - { - if (triggerCondition.m_triggerDelayCount > 0) - { - triggerCondition.m_triggerDelayCount--; - } - else - { - triggerCondition.m_triggerDelayCount = 0; - - // next trigger - m_currentTriggerIndex++; - - if (m_currentTriggerIndex == m_triggerConditions.size()) - { - m_currentTriggerIndex = 0; - m_triggerState = TriggerTriggered; - m_triggerPoint = begin; - triggerCondition.m_triggerCounter = triggerCondition.m_triggerData.m_triggerCounts; - m_traceStart = true; - break; - } - else - { - // initialize a new trace - m_triggerState = TriggerUntriggered; - m_traceCompleteCount = 0; - m_triggerState = TriggerUntriggered; - - feed(begin, end, positiveOnly); // process the rest of samples - } - } - } - else - { - break; - } + } ++begin; } // begin < end } // trace process - if ((m_triggerConditions.size() == 0) || (m_triggerState == TriggerTriggered)) + if ((m_triggerState == TriggerFreeRun) || (m_triggerConditions.size() == 0) || (m_triggerState == TriggerTriggered)) { // trace back if (m_traceStart) { int count = end - begin; // number of samples in traceback buffer past the current point - std::vector::iterator itTrace = m_traces.begin(); + int maxTraceDelay = 0; - for (;itTrace != m_traces.end(); ++itTrace) + for (std::vector::iterator itTrace = m_traces.begin(); itTrace != m_traces.end(); ++itTrace) { - if (itTrace->m_traceData.m_inputIndex == feedIndex) - { - // TODO: store current point in traceback (current - count) - SampleVector::const_iterator startPoint = m_tracebackBuffers[feedIndex].getCurrent() - count; - SampleVector::const_iterator prevPoint = m_tracebackBuffers[feedIndex].getCurrent() - count - m_preTriggerDelay - itTrace->m_traceData.m_traceDelay; - processPrevTrace(prevPoint, startPoint, itTrace); - } + if (itTrace->m_traceData.m_traceDelay > maxTraceDelay) + { + maxTraceDelay = itTrace->m_traceData.m_traceDelay; + } + } + + if ((m_triggerState != TriggerFreeRun) && (m_triggerConditions.size() > 0)) // trigger mode + { + processPrevTraces(count + m_preTriggerDelay + maxTraceDelay, count, m_traceDiscreteMemory.current()); + } + else + { + // TODO: continuous memory mode + } + + + + + for (std::vector::iterator itTrace = m_traces.begin(); itTrace != m_traces.end(); ++itTrace) + { + if ((m_triggerState != TriggerFreeRun) && (m_triggerConditions.size() > 0)) // trigger mode + { + SampleVector::const_iterator prevPoint = startPoint - m_preTriggerDelay - itTrace->m_traceData.m_traceDelay; + } + else // free run mode + { + // TODO: + } } m_traceStart = false; @@ -316,7 +312,39 @@ void ScopeVisNG::feed(const SampleVector::const_iterator& cbegin, const SampleVe } } -void ScopeVisNG::processPrevTrace(SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, std::vector::iterator& trace) +bool ScopeVisNG::nextTrigger() +{ + TriggerCondition& triggerCondition = m_triggerConditions[m_currentTriggerIndex]; // current trigger condition + + if (triggerCondition.m_triggerData.m_triggerRepeat > 0) + { + if (triggerCondition.m_triggerCounter < triggerCondition.m_triggerData.m_triggerRepeat) + { + triggerCondition.m_triggerCounter++; + m_triggerState = TriggerUntriggered; // repeat operations for next occurence + return true; + } + else + { + triggerCondition.m_triggerCounter = 0; // reset for next time + } + } + + if (m_currentTriggerIndex < m_triggerConditions.size()) + { + m_currentTriggerIndex++; + m_triggerState = TriggerUntriggered; // repeat operations for next trigger + return true; // not final keep going + } + + // now this is really finished + m_triggerState == TriggerTriggered; + m_currentTriggerIndex = 0; + return false; // final +} + +// TODO: should handle previous and live traces the same way from a stored buffer +void ScopeVisNG::processPrevTraces(int beginPoint, int endPoint, TraceBackBuffer& traceBuffer) { int shift = (m_timeOfsProMill / 1000.0) * m_traceSize; float posLimit = 1.0 / trace->m_traceData.m_amp; diff --git a/sdrbase/dsp/scopevisng.h b/sdrbase/dsp/scopevisng.h index 952cd9eb5..06dabfb03 100644 --- a/sdrbase/dsp/scopevisng.h +++ b/sdrbase/dsp/scopevisng.h @@ -78,7 +78,7 @@ public: bool m_triggerPositiveEdge; //!< Trigger on the positive edge (else negative) bool m_triggerBothEdges; //!< Trigger on both edges (else only one) uint32_t m_triggerDelay; //!< Delay before the trigger is kicked off in number of samples - uint32_t m_triggerCounts; //!< Number of trigger conditions before the final decisive trigger + uint32_t m_triggerRepeat; //!< Number of trigger conditions before the final decisive trigger TriggerData() : m_projectionType(ProjectionReal), @@ -87,7 +87,7 @@ public: m_triggerPositiveEdge(true), m_triggerBothEdges(false), m_triggerDelay(0), - m_triggerCounts(0) + m_triggerRepeat(0) {} }; @@ -115,8 +115,6 @@ public: SampleVector::const_iterator getTriggerPoint() const { return m_triggerPoint; } private: - typedef DoubleBufferSimple TraceBuffer; - // === messages === // --------------------------------------------- class MsgConfigureScopeVisNG : public Message { @@ -345,6 +343,9 @@ private: }; + /** + * Trigger stuff + */ enum TriggerState { TriggerFreeRun, //!< Trigger is disabled @@ -391,6 +392,95 @@ private: } }; + /** + * Complex trace stuff + */ + typedef DoubleBufferSimple TraceBuffer; + + struct TraceBackBuffer + { + TraceBuffer m_traceBuffer; + SampleVector::iterator m_endPoint; + + TraceBackBuffer() + { + m_startPoint = m_traceBuffer.getCurrent(); + m_endPoint = m_traceBuffer.getCurrent(); + } + + void resize(uint32_t size) + { + m_traceBuffer.resize(size); + } + + void write(const SampleVector::const_iterator begin, const SampleVector::const_iterator end) + { + m_traceBuffer.write(begin, end); + } + + unsigned int absoluteFill() const { + return m_traceBuffer.absoluteFill(); + } + + SampleVector::iterator current() { return m_traceBuffer.getCurrent(); } + }; + + struct TraceBackDiscreteMemory + { + std::vector m_traceBackBuffers; + uint32_t m_memSize; + uint32_t m_currentMemIndex; + + /** + * Give memory size in number of traces + */ + TraceBackDiscreteMemory(uint32_t size) : m_memSize(size), m_currentMemIndex(0) + { + m_traceBackBuffers.resize(m_memSize); + } + + /** + * Resize all trace buffers in memory + */ + void resize(uint32_t size) + { + for (std::vector::iterator it = m_traceBackBuffers.begin(); it != m_traceBackBuffers.end(); ++it) + { + it->resize(size); + } + } + + /** + * Move index forward by one position and return reference to the trace at this position + */ + TraceBackBuffer &store() + { + m_currentMemIndex = m_currentMemIndex < m_memSize ? m_currentMemIndex+1 : 0; + m_traceBackBuffers[m_currentMemIndex].reset(); + return m_traceBackBuffers[m_currentMemIndex]; // new trace + } + + /** + * Recalls trace at shift positions back. Therefore 0 is current. Wraps around memory size. + */ + TraceBackBuffer& recall(uint32_t shift) + { + int index = (m_currentMemIndex + (m_memSize - (shift % m_memSize))) % m_memSize; + return m_traceBackBuffers[index]; + } + + /** + * Return trace at current memory position + */ + TraceBackBuffer& current() + { + return m_traceBackBuffers[m_currentMemIndex]; + } + }; + + /** + * Displayable trace stuff + */ struct Trace : public DisplayTrace { Projector *m_projector; //!< Projector transform from complex trace to real (displayable) trace @@ -440,23 +530,24 @@ private: }; GLScopeNG* m_glScope; - std::vector m_tracebackBuffers; //!< One complex (Sample type) trace buffer per input source or feed - DoubleBufferSimple m_traceback; //!< FIFO to handle delayed processes - int m_preTriggerDelay; //!< Pre-trigger delay in number of samples + int m_preTriggerDelay; //!< Pre-trigger delay in number of samples std::vector m_triggerConditions; //!< Chain of triggers - int m_currentTriggerIndex; //!< Index of current index in the chain - TriggerState m_triggerState; //!< Current trigger state - std::vector m_traces; //!< One trace control object per display trace allocated to X, Y[n] or Z - int m_traceSize; //!< Size of traces in number of samples - int m_timeOfsProMill; //!< Start trace shift in 1/1000 trace size - bool m_traceStart; //!< Trace is at start point - int m_traceFill; //!< Count of samples accumulated into trace - int m_zTraceIndex; //!< Index of the trace used for Z input (luminance or false colors) - int m_traceCompleteCount; //!< Count of completed traces - SampleVector::const_iterator m_triggerPoint; //!< Trigger start location in the samples vector + int m_currentTriggerIndex; //!< Index of current index in the chain + TriggerState m_triggerState; //!< Current trigger state + std::vector m_traces; //!< One trace control object per display trace allocated to X, Y[n] or Z + int m_traceSize; //!< Size of traces in number of samples + int m_memTraceSize; //!< Trace size in memory in number of samples up to trace size + int m_timeOfsProMill; //!< Start trace shift in 1/1000 trace size + bool m_traceStart; //!< Trace is at start point + int m_traceFill; //!< Count of samples accumulated into trace + int m_zTraceIndex; //!< Index of the trace used for Z input (luminance or false colors) + int m_traceCompleteCount; //!< Count of completed traces + SampleVector::const_iterator m_triggerPoint; //!< Trigger start location in the samples vector int m_sampleRate; + TraceBackDiscreteMemory m_traceDiscreteMemory; //!< Complex trace memory for triggered states TODO: vectorize when more than on input is allowed - void processPrevTrace(SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, std::vector::iterator& trace); + bool nextTrigger(); + void processPrevTraces(int beginPoint, int endPoint, TraceBackBuffer& traceBuffer); }; diff --git a/sdrbase/util/doublebuffer.h b/sdrbase/util/doublebuffer.h index a15df77de..6e27b81f4 100644 --- a/sdrbase/util/doublebuffer.h +++ b/sdrbase/util/doublebuffer.h @@ -67,6 +67,8 @@ public: } typename std::vector::iterator getCurrent() const { return m_current + m_size; } + unsigned int absoluteFill() const { return m_current - m_data.begin(); } + void reset() { m_current = m_data.begin(); } private: int m_size;