/////////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2017 F4EXB // // written by Edouard Griffiths // // // // This program is free software; you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // // the Free Software Foundation as version 3 of the License, or // // // // This program is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY; without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU General Public License V3 for more details. // // // // You should have received a copy of the GNU General Public License // // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// #include #include "scopevisng.h" #include "dsp/dspcommands.h" #include "gui/glscopeng.h" MESSAGE_CLASS_DEFINITION(ScopeVisNG::MsgConfigureScopeVisNG, Message) MESSAGE_CLASS_DEFINITION(ScopeVisNG::MsgScopeVisNGAddTrigger, Message) MESSAGE_CLASS_DEFINITION(ScopeVisNG::MsgScopeVisNGChangeTrigger, Message) MESSAGE_CLASS_DEFINITION(ScopeVisNG::MsgScopeVisNGRemoveTrigger, Message) MESSAGE_CLASS_DEFINITION(ScopeVisNG::MsgScopeVisNGAddTrace, Message) MESSAGE_CLASS_DEFINITION(ScopeVisNG::MsgScopeVisNGChangeTrace, Message) MESSAGE_CLASS_DEFINITION(ScopeVisNG::MsgScopeVisNGRemoveTrace, Message) const uint ScopeVisNG::m_traceChunkSize = 4800; const Real ScopeVisNG::ProjectorMagDB::mult = (10.0f / log2f(10.0f)); ScopeVisNG::ScopeVisNG(GLScopeNG* glScope) : m_glScope(glScope), m_preTriggerDelay(0), 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_traceDiscreteMemory(10), m_freeRun(true), m_maxTraceDelay(0) { setObjectName("ScopeVisNG"); m_traceDiscreteMemory.resize(m_traceChunkSize); // arbitrary m_glScope->setTraces(&m_traces.m_tracesData, &m_traces.m_traces[0]); } ScopeVisNG::~ScopeVisNG() { } void ScopeVisNG::setSampleRate(int sampleRate) { if (sampleRate != m_sampleRate) { m_sampleRate = sampleRate; if (m_glScope) m_glScope->setSampleRate(m_sampleRate); } } void ScopeVisNG::configure(uint32_t traceSize, uint32_t timeOfsProMill, bool freeRun) { Message* cmd = MsgConfigureScopeVisNG::create(traceSize, timeOfsProMill, freeRun); getInputMessageQueue()->push(cmd); } void ScopeVisNG::addTrace(const TraceData& traceData) { Message* cmd = MsgScopeVisNGAddTrace::create(traceData); getInputMessageQueue()->push(cmd); } void ScopeVisNG::changeTrace(const TraceData& traceData, uint32_t traceIndex) { qDebug("ScopeVisNG::changeTrace: trace #%d", traceIndex); Message* cmd = MsgScopeVisNGChangeTrace::create(traceData, traceIndex); getInputMessageQueue()->push(cmd); } void ScopeVisNG::removeTrace(uint32_t traceIndex) { Message* cmd = MsgScopeVisNGRemoveTrace::create(traceIndex); getInputMessageQueue()->push(cmd); } void ScopeVisNG::addTrigger(const TriggerData& triggerData) { Message* cmd = MsgScopeVisNGAddTrigger::create(triggerData); getInputMessageQueue()->push(cmd); } void ScopeVisNG::changeTrigger(const TriggerData& triggerData, uint32_t triggerIndex) { Message* cmd = MsgScopeVisNGChangeTrigger::create(triggerData, triggerIndex); getInputMessageQueue()->push(cmd); } void ScopeVisNG::removeTrigger(uint32_t triggerIndex) { Message* cmd = MsgScopeVisNGRemoveTrigger::create(triggerIndex); getInputMessageQueue()->push(cmd); } void ScopeVisNG::feed(const SampleVector::const_iterator& cbegin, const SampleVector::const_iterator& end, bool positiveOnly) { if (m_freeRun) { m_triggerPoint = cbegin; } else if (m_triggerState == TriggerTriggered) { m_triggerPoint = cbegin; } else if (m_triggerState == TriggerUntriggered) { m_triggerPoint = end; } else if (m_triggerState == TriggerWait) { m_triggerPoint = end; } else { m_triggerPoint = cbegin; } if (m_triggerState == TriggerNewConfig) { m_triggerState = TriggerUntriggered; return; } if ((m_triggerConditions.size() > 0) && (m_triggerState == TriggerWait)) { return; } SampleVector::const_iterator begin(cbegin); // memory storage m_traceDiscreteMemory.current().write(cbegin, end); if (m_traceDiscreteMemory.current().absoluteFill() < m_traceSize) { return; // not enough samples in memory } // trigger process if (!m_freeRun && (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 == 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 m_triggerPoint = begin; 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; } else { trigger = (triggerCondition.m_prevCondition ^ condition) && (condition ^ !triggerCondition.m_triggerData.m_triggerPositiveEdge); } triggerCondition.m_prevCondition = condition; if (trigger) // trigger condition { 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 (!nextTrigger()) // finished { m_traceStart = true; // start trace processing m_triggerPoint = begin; break; } } } } ++begin; } // begin < end } else { m_traceStart = true; } int remainder = -1; int count = end - begin; // number of samples in traceback buffer past the current point SampleVector::iterator nend = m_traceDiscreteMemory.current().current(); SampleVector::iterator nbegin = nend - count; // trace process if ((m_freeRun) || (m_triggerConditions.size() == 0) || (m_triggerState == TriggerTriggered)) { // trace back if ((m_traceStart) && (m_preTriggerDelay + m_maxTraceDelay > 0)) { remainder = processTraces(count + m_preTriggerDelay + m_maxTraceDelay, count, m_traceDiscreteMemory.current(), true); m_traceStart = false; } if (remainder < 0) { // live trace remainder = processTraces(count, 0, m_traceDiscreteMemory.current()); } if (remainder >= 0) // finished { nbegin = nend - remainder; m_traceDiscreteMemory.current().m_endPoint = nbegin; m_traceDiscreteMemory.store(); // next memory trace m_traceCompleteCount = 0; } } // process remainder recursively if (remainder > 0) { feed(nbegin, nend, positiveOnly); } } 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 } int ScopeVisNG::processTraces(int beginPointDelta, int endPointDelta, TraceBackBuffer& traceBuffer, bool traceBack) { SampleVector::iterator begin = traceBuffer.current() - beginPointDelta; SampleVector::const_iterator end = traceBuffer.current() - endPointDelta; int shift = (m_timeOfsProMill / 1000.0) * m_traceSize; while (begin < end) { std::vector::iterator itCtl = m_traces.m_tracesControl.begin(); std::vector::iterator itData = m_traces.m_tracesData.begin(); std::vector::iterator itTrace = m_traces.m_traces[m_traces.currentBufferIndex()].begin(); for (; itCtl != m_traces.m_tracesControl.end(); ++itCtl, ++itData, ++itTrace) { if (traceBack && ((end - begin) > m_preTriggerDelay + itData->m_traceDelay)) { continue; } if (itCtl->m_traceCount[m_traces.currentBufferIndex()] < m_traceSize) { float posLimit = 1.0 / itData->m_amp; float negLimit = -1.0 / itData->m_amp; float v = itCtl->m_projector->run(*begin) * itData->m_amp + itData->m_ofs; if(v > posLimit) { v = posLimit; } else if (v < negLimit) { v = negLimit; } (*itTrace)[2*(itCtl->m_traceCount[m_traces.currentBufferIndex()])] = (itCtl->m_traceCount[m_traces.currentBufferIndex()] - shift); // display x (*itTrace)[2*(itCtl->m_traceCount[m_traces.currentBufferIndex()]) + 1] = v; // display y itCtl->m_traceCount[m_traces.currentBufferIndex()]++; } else { itCtl->m_traceCount[m_traces.currentBufferIndex()]++; if (m_traceCompleteCount < m_traces.size()) { m_traceCompleteCount++; } else // finished { break; } } } ++begin; } if (m_traceCompleteCount == m_traces.size()) // finished { m_glScope->newTraces(&m_traces.m_traces[m_traces.currentBufferIndex()]); m_traces.switchBuffer(); traceBuffer.m_endPoint = begin; return end - begin; // return remainder count } else { return -1; // mark not finished } } void ScopeVisNG::start() { } void ScopeVisNG::stop() { } bool ScopeVisNG::handleMessage(const Message& message) { qDebug() << "ScopeVisNG::handleMessage" << message.getIdentifier(); if (DSPSignalNotification::match(message)) { DSPSignalNotification& notif = (DSPSignalNotification&) message; setSampleRate(notif.getSampleRate()); qDebug() << "ScopeVisNG::handleMessage: DSPSignalNotification: m_sampleRate: " << m_sampleRate; return true; } else if (MsgConfigureScopeVisNG::match(message)) { MsgConfigureScopeVisNG& conf = (MsgConfigureScopeVisNG&) message; uint32_t traceSize = conf.getTraceSize(); uint32_t timeOfsProMill = conf.getTimeOfsProMill(); bool freeRun = conf.getFreeRun(); if (m_traceSize != traceSize) { m_traceSize = traceSize; m_traces.resize(m_traceSize); m_traceDiscreteMemory.resize(m_traceSize); initTraceBuffers(); if (m_glScope) { m_glScope->setTraceSize(m_traceSize); } } if (m_timeOfsProMill != timeOfsProMill) { m_timeOfsProMill = timeOfsProMill; if (m_glScope) { m_glScope->setTimeOfsProMill(m_timeOfsProMill); } } if (freeRun != m_freeRun) { m_freeRun = freeRun; } qDebug() << "ScopeVisNG::handleMessage: MsgConfigureScopeVisNG:" << " m_traceSize: " << m_traceSize << " m_timeOfsProMill: " << m_timeOfsProMill << " m_freeRun: " << m_freeRun; return true; } else if (MsgScopeVisNGAddTrigger::match(message)) { MsgScopeVisNGAddTrigger& conf = (MsgScopeVisNGAddTrigger&) message; m_triggerConditions.push_back(TriggerCondition(conf.getTriggerData())); m_triggerConditions.back().init(); return true; } else if (MsgScopeVisNGChangeTrigger::match(message)) { MsgScopeVisNGChangeTrigger& conf = (MsgScopeVisNGChangeTrigger&) message; int triggerIndex = conf.getTriggerIndex(); if (triggerIndex < m_triggerConditions.size()) { m_triggerConditions[triggerIndex].setData(conf.getTriggerData()); } return true; } else if (MsgScopeVisNGRemoveTrigger::match(message)) { MsgScopeVisNGRemoveTrigger& conf = (MsgScopeVisNGRemoveTrigger&) message; int triggerIndex = conf.getTriggerIndex(); if (triggerIndex < m_triggerConditions.size()) { m_triggerConditions.erase(m_triggerConditions.begin() + triggerIndex); } return true; } else if (MsgScopeVisNGAddTrace::match(message)) { MsgScopeVisNGAddTrace& conf = (MsgScopeVisNGAddTrace&) message; m_traces.addTrace(conf.getTraceData(), m_traceSize); initTraceBuffers(); updateMaxTraceDelay(); return true; } else if (MsgScopeVisNGChangeTrace::match(message)) { MsgScopeVisNGChangeTrace& conf = (MsgScopeVisNGChangeTrace&) message; m_traces.changeTrace(conf.getTraceData(), conf.getTraceIndex()); updateMaxTraceDelay(); m_glScope->updateDisplay(); return true; } else if (MsgScopeVisNGRemoveTrace::match(message)) { MsgScopeVisNGRemoveTrace& conf = (MsgScopeVisNGRemoveTrace&) message; m_traces.removeTrace(conf.getTraceIndex()); updateMaxTraceDelay(); return true; } else { return false; } } void ScopeVisNG::updateMaxTraceDelay() { int maxTraceDelay = 0; for (std::vector::iterator itData = m_traces.m_tracesData.begin(); itData != m_traces.m_tracesData.end(); ++itData) { if (itData->m_traceDelay > maxTraceDelay) { maxTraceDelay = itData->m_traceDelay; } } m_maxTraceDelay = maxTraceDelay; } void ScopeVisNG::initTraceBuffers() { int shift = (m_timeOfsProMill / 1000.0) * m_traceSize; std::vector::iterator it0 = m_traces.m_traces[0].begin(); std::vector::iterator it1 = m_traces.m_traces[1].begin(); for (; it0 != m_traces.m_traces[0].end(); ++it0, ++it1) { for (int i = 0; i < m_traceSize; i++) { (*it0)[2*i] = (i - shift); // display x (*it0)[2*i + 1] = 0.0f; // display y (*it1)[2*i] = (i - shift); // display x (*it1)[2*i + 1] = 0.0f; // display y } } }