From 3b09caaeb0d6764ef49fe2daa49d98ca84a494db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiesner=20Andr=C3=A1s?= Date: Wed, 11 May 2022 18:13:41 +0200 Subject: [PATCH] - capture timeout added - auto-trigger initials --- libwfr/src/MultiStreamOscilloscope.cpp | 58 ++++++++++++++++++-------- libwfr/src/MultiStreamOscilloscope.h | 8 ++-- libwfr/src/MultiStreamReceiver.cpp | 6 +-- libwfr/src/Trigger.cpp | 24 +++++++---- libwfr/src/Trigger.h | 8 ++-- main.cpp | 2 +- python/runtime/main.py | 51 ++++++++++++++-------- python/src/wfsmodule.cpp | 4 +- 8 files changed, 105 insertions(+), 56 deletions(-) diff --git a/libwfr/src/MultiStreamOscilloscope.cpp b/libwfr/src/MultiStreamOscilloscope.cpp index 175a92c..6828f21 100644 --- a/libwfr/src/MultiStreamOscilloscope.cpp +++ b/libwfr/src/MultiStreamOscilloscope.cpp @@ -11,7 +11,7 @@ MultiStreamOscilloscope::MultiStreamOscilloscope() { mTriggerPosition_percent = TRIGGER_POS_PERCENT_DEF; mCapturePeriod_ns = DRAW_WINDOW_PERIOD_NS_DEF; verticalScale = VOLT_PER_BIN_DEF; - mTrigState = {false, false, -1, false }; + mTrigState = {false, false, -1, false, false}; mFIFOBlockCnt = 0; mCaptureLength = 0; @@ -23,11 +23,11 @@ void MultiStreamOscilloscope::setup(const std::vector &nodes, const A // calculate buffer parameters mCaptureLength = ceil(mCapturePeriod_ns / 1E+09 * acqFmt.sampling_rate_Hz); // calculate draw window period in samples - mFIFOBlockCnt = 4 * ceil(mCaptureLength / acqFmt.mch_samples_per_packet); // TODO magic... + mFIFOBlockCnt = 10 * ceil(mCaptureLength / acqFmt.mch_samples_per_packet); // TODO magic... // setup channel buffers mpChBufs.resize(mChCnt); - for (auto& chBuf: mpChBufs) { + for (auto &chBuf: mpChBufs) { chBuf.reset(new ChannelBuffer(mAcqFmt.mch_samples_per_packet, mFIFOBlockCnt)); } @@ -82,9 +82,9 @@ bool MultiStreamOscilloscope::input(size_t ch, const std::shared_ptr sample *= verticalScale; // save sample point - SamplePoint& sp = mpAssemblyBuffer.get()[i]; + SamplePoint &sp = mpAssemblyBuffer.get()[i]; sp.t = pTime.get()[i].to_ns(); - sp.x = sample; + sp.y = sample; } // push new block of samples onto the FIFO @@ -101,11 +101,13 @@ bool MultiStreamOscilloscope::input(size_t ch, const std::shared_ptr int64_t tag = mpChBufs[ch]->copyBlock(mTriggerProbeBlock_idx, mpTriggerBuffer.get()); // TODO magic constant!... size_t i = 0; + int64_t trigTime = 0; if (!mTrigState.trigd) { // if not triggered externally while (i < mAcqFmt.mch_samples_per_packet) { const SamplePoint &samplePoint = mpTriggerBuffer.get()[i]; // get sample - mTrigState.trigd = trigger->sample(samplePoint.x); // probe if causes a trigger + mTrigState.trigd = trigger->sample(samplePoint.y, samplePoint.t); // probe if causes a trigger if (mTrigState.trigd) { // break if trigger is successful + trigTime = trigger->t_trig; break; } i++; // increase index @@ -122,8 +124,8 @@ bool MultiStreamOscilloscope::input(size_t ch, const std::shared_ptr int64_t captureEnd = captureStart + mCaptureLength; // get time of trigger occurred - SamplePoint trigSP = mpChBufs[ch]->getElementByTag(mTrigState.triggerSampleTag); - int64_t t0 = trigSP.t; + //SamplePoint trigSP = mpChBufs[ch]->getElementByTag(mTrigState.triggerSampleTag); + int64_t t0 = trigTime; // get eldest sample's timestamp on the trigger channel int64_t t_eldest_trigger = mpChBufs[ch]->getEldestSample().t; @@ -131,7 +133,7 @@ bool MultiStreamOscilloscope::input(size_t ch, const std::shared_ptr // TODO now full synchronicity is assumed // copy samples from each channel for (size_t k = 0; k < mChCnt; k++) { - auto& chBuf = *(mpChBufs[k]); // acquire channel buffer + auto &chBuf = *(mpChBufs[k]); // acquire channel buffer int64_t t_offset, offset_index = 0; if (k != ch) { // we are NOT processing the trigger channel, since it's the reference @@ -189,13 +191,35 @@ void MultiStreamOscilloscope::armTrigger() { mTrigState.armed = true; } -std::vector> MultiStreamOscilloscope::capture() { - std::unique_lock lock(mCapture_mtx); - mCapture_cv.wait(lock, [this] { return mTrigState.samplesReady; }); // wait for data to become available +void MultiStreamOscilloscope::enableAutoTrigger(bool en) { + mTrigState.autoTrigger; +} - auto samples = mCaptureBuffers; // copy buffer - mTrigState.samplesReady = false; // invalidate samples - return samples; +std::vector> MultiStreamOscilloscope::capture(size_t timeout_ms) { + std::unique_lock lock(mCapture_mtx); + + // arm trigger if not armed + if (!mTrigState.armed) { + armTrigger(); + } + + // wait for data + if (timeout_ms > 0) { + mCapture_cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), [this] { return mTrigState.samplesReady; }); // wait for data to become available + } else { + mCapture_cv.wait(lock, [this] { return mTrigState.samplesReady; }); // ... + } + + // handle data or skip + if (mTrigState.samplesReady) { + mTrigState.samplesReady = false; + return mCaptureBuffers; + } else { + if (mTrigState.autoTrigger) { + mTrigState.trigd = true; // trigger if auto-trigger is enabled + } + return {}; + } } // ---------------------------------------- @@ -220,5 +244,5 @@ std::vector MultiStreamOscilloscope::getScreenTimeLimits() const { int64_t lowerLimit, upperLimit; lowerLimit = -ceil(mTriggerPosition_percent / 100.0 * mCapturePeriod_ns); upperLimit = mCapturePeriod_ns + lowerLimit; - return std::vector({ lowerLimit, upperLimit }); -} + return std::vector({lowerLimit, upperLimit}); +} \ No newline at end of file diff --git a/libwfr/src/MultiStreamOscilloscope.h b/libwfr/src/MultiStreamOscilloscope.h index 8d22f00..05da284 100644 --- a/libwfr/src/MultiStreamOscilloscope.h +++ b/libwfr/src/MultiStreamOscilloscope.h @@ -20,11 +20,11 @@ public: public: struct SamplePoint { int64_t t; // time - double x; // sample data + double y; // sample data SamplePoint() { t = 0; - x = 0; + y = 0; } }; @@ -56,6 +56,7 @@ private: bool trigd; // indicates if trigger has fired int64_t triggerSampleTag; bool samplesReady; // samples have been transferred to the output buffer + bool autoTrigger; // auto-trigger on/off } mTrigState; public: void setup(const std::vector &nodes, const AcquisitionFormat &acqFmt) override; @@ -73,7 +74,8 @@ public: void triggerNow(); // make the scope trigger regardless conditions void armTrigger(); // arm trigger for next acquisition - std::vector> capture(); // wait for captured data TODO to be renamed + void enableAutoTrigger(bool en); // enable or disable auto trigger + std::vector> capture(size_t timeout_ms = 0); // wait for captured data TODO to be renamed }; diff --git a/libwfr/src/MultiStreamReceiver.cpp b/libwfr/src/MultiStreamReceiver.cpp index d496ff3..de9ac17 100644 --- a/libwfr/src/MultiStreamReceiver.cpp +++ b/libwfr/src/MultiStreamReceiver.cpp @@ -142,7 +142,7 @@ void MultiStreamReceiver::fnRecv(MultiStreamReceiver *pMSR) { // limit on time difference variation double timeDiffVariation_ns = 1E+09 / pMSR->mAcqFmt.sampling_rate_Hz * TS_VALIDITY_RANGE; - uint32_t lastIndex = 0; + //uint32_t lastIndex = 0; // allocate buffer for interpolated timestamps std::shared_ptr pTSBuf(new Timestamp[pMSR->mAcqFmt.mch_samples_per_packet]); @@ -196,12 +196,12 @@ void MultiStreamReceiver::fnRecv(MultiStreamReceiver *pMSR) { } // check index continuity - if (lastIndex > 0 && (aph.index) != (lastIndex + 1)) { + /*if (lastIndex > 0 && (aph.index) != (lastIndex + 1)) { Logger::logLine("NON-CONTINUOUS packet indices! (" + std::to_string(lastIndex) + " -> " + std::to_string(aph.index) + ")"); // TODO Should skip here? } - lastIndex = aph.index; + lastIndex = aph.index;*/ // ----------- TIME PROCESSING --------------- diff --git a/libwfr/src/Trigger.cpp b/libwfr/src/Trigger.cpp index bf3d047..0959944 100644 --- a/libwfr/src/Trigger.cpp +++ b/libwfr/src/Trigger.cpp @@ -12,9 +12,10 @@ TriggerSettings::TriggerSettings() { void TriggerSettings::reset() { mFirstSample = true; ch = 0; + t_trig = 0; } -bool TriggerSettings::sample(double x) { +bool TriggerSettings::sample(double y, int64_t t) { return false; // never trigger } @@ -29,28 +30,33 @@ EdgeTrigger::EdgeTrigger() { void EdgeTrigger::reset() { TriggerSettings::reset(); - x_prev = 0; + y_prev = 0; } -bool EdgeTrigger::sample(double x) { +bool EdgeTrigger::sample(double y, int64_t t) { // do not act on first sample if (mFirstSample) { mFirstSample = false; - x_prev = x; + y_prev = y; + t_prev = t; return false; } bool trig = false; // on every other sample... - if (((edge == RISING) && (x_prev < level && x > level)) || - ((edge == FALLING) && (x_prev > level && x < level))) { - trig = true; + if (((edge == RISING) && (y_prev < level && y > level)) || + ((edge == FALLING) && (y_prev > level && y < level))) { + trig = true; // triggered + + // compute exact trigger time + t_trig = t - llabs((level - y) / (y - y_prev) * (t - t_prev)); } - //std::cout << x << " - " << level << std::endl; + //std::cout << y << " - " << level << std::endl; - x_prev = x; + y_prev = y; + t_prev = t; return trig; } diff --git a/libwfr/src/Trigger.h b/libwfr/src/Trigger.h index 7e6ca90..80a28ba 100644 --- a/libwfr/src/Trigger.h +++ b/libwfr/src/Trigger.h @@ -14,11 +14,12 @@ protected: bool mFirstSample; // indicates the latest sample was the first since the last reset public: size_t ch; // channel to probe + int64_t t_trig; // exact trigger time expressed relative to trigger sample time point public: TriggerSettings(); virtual void reset(); // reset trigger internal state - virtual bool sample(double x); // insert sample into the trigger + virtual bool sample(double y, int64_t t); // insert sample into the trigger }; // Simple edge trigger @@ -26,14 +27,15 @@ struct EdgeTrigger : public TriggerSettings, public ICreatable { public: enum EdgeType { RISING, FALLING }; private: - double x_prev; // previous sample + double y_prev; // previous sample + int64_t t_prev; // .... sample time point public: double level; // trigger level EdgeType edge; // edge direction public: EdgeTrigger(); // constr. void reset() override; - bool sample(double x) override; + bool sample(double y, int64_t t) override; }; #endif //WFR_APP_TRIGGER_H diff --git a/main.cpp b/main.cpp index 8c20967..a1d7c58 100644 --- a/main.cpp +++ b/main.cpp @@ -61,7 +61,7 @@ int main(int argc, char * argv[]) { beacon->execCmdOnAllNodes("snd connect 10.42.0.1 20220"); osc->armTrigger(); - auto samples = osc->capture(); + auto samples = osc->capture(0); beacon->execCmdOnAllNodes("snd disconnect"); msr.stop(); diff --git a/python/runtime/main.py b/python/runtime/main.py index 31d246f..5df09cb 100644 --- a/python/runtime/main.py +++ b/python/runtime/main.py @@ -1,7 +1,7 @@ import time import sys -sys.path.extend(['/home/epagris/EGYETEM/DIPTERV2/wfr/python/module']) +sys.path.extend(['../module']) import pywfs @@ -11,6 +11,9 @@ from matplotlib import pyplot as plt from matplotlib import animation as anim import time +LOCAL_ADDR = "192.168.1.204" +nodes = [ "192.168.1.180" ] + # ---------- CONNECT TO AND PREPARE SAMPLING SYSTEM ----------- # enable logging onto STDOUT @@ -18,9 +21,9 @@ pywfs.Logger.start() # discover nodes on the network b = pywfs.ServerBeacon() -b.setInterfaceAddr("10.42.0.1") +b.setInterfaceAddr(LOCAL_ADDR) b.singleScan() -nodes = b.getNodesOnNetwork() +#nodes = b.getNodesOnNetwork() # query acquisition format (assume all nodes are identical in this aspect) f = b.queryFromNode(nodes[0], "snd acqformat mr") @@ -37,19 +40,25 @@ ch_n = msr.getChannelCount() # create oscilloscope data feeder object osc = pywfs.MultiStreamOscilloscope.create() +#index = 2 * nodes.index("192.168.1.180") + # create a slope trigger edge_trigger = pywfs.EdgeTrigger() -edge_trigger.level = 0.2 +edge_trigger.level = 0.1 edge_trigger.edge = pywfs.FALLING +#edge_trigger.ch = 0 + index +edge_trigger.ch = 0 osc.trigger = edge_trigger -osc.setScreenPeriod(int(20e+06)) +osc.setScreenPeriod(int(10e+06)) # start listening for samples msr.listen(osc) # enable network sample transmission from every device -b.execCmdOnAllNodes("snd connect 10.42.0.1 20220") +#b.execCmdOnAllNodes("snd connect 10.42.0.1 20220") +for node in nodes: + b.execCmdOnNode(node, "snd connect " + LOCAL_ADDR) # # data collection @@ -68,6 +77,10 @@ def data_gen(): real_time_last = time.time() index_last = 0 + screen_lim = osc.getScreenTimeLimits() + T = [screen_lim[0] * 1e-09, screen_lim[1] * 1e-09] + Y = [0, 0] + for i in itertools.count(): # FPS measurement real_time = time.time() @@ -78,21 +91,23 @@ def data_gen(): # data collection osc.armTrigger() # arm trigger - channels = osc.capture() # wait for captured data + channels = osc.capture(200) # wait for captured data - T = list() - Y = list() + # if we have incoming data + if (len(channels) > 0): + T = list() + Y = list() - for ch in channels: - t = list() - y_t = list() + for ch in channels: + t = list() + y_t = list() - for sp in ch: - t.append(sp.t * 1E-09) - y_t.append(sp.x) + for sp in ch: + t.append(sp.t * 1E-09) + y_t.append(sp.y) - T.append(t) - Y.append(y_t) + T.append(t) + Y.append(y_t) yield T, Y @@ -135,4 +150,4 @@ plt.show() # disconnect nodes b.execCmdOnAllNodes("snd disconnect") -msr.close() \ No newline at end of file +msr.close() diff --git a/python/src/wfsmodule.cpp b/python/src/wfsmodule.cpp index d853ce0..b3eae87 100644 --- a/python/src/wfsmodule.cpp +++ b/python/src/wfsmodule.cpp @@ -81,7 +81,7 @@ PYBIND11_MODULE(pywfs, m) { .def_readwrite("verticalScale", &MultiStreamOscilloscope::verticalScale) .def("armTrigger", &MultiStreamOscilloscope::armTrigger) .def("triggerNow", &MultiStreamOscilloscope::triggerNow) - .def("capture", &MultiStreamOscilloscope::capture) + .def("capture", &MultiStreamOscilloscope::capture, "timeout_ms"_a = 0) .def("getChannelCount", &MultiStreamOscilloscope::getChannelCount) .def("setScreenPeriod", &MultiStreamOscilloscope::setScreenPeriod) .def("getScreenPeriod", &MultiStreamOscilloscope::getScreenPeriod) @@ -94,7 +94,7 @@ PYBIND11_MODULE(pywfs, m) { py::class_(m, "SamplePoint") .def(py::init<>()) .def_readwrite("t", &MultiStreamOscilloscope::SamplePoint::t) - .def_readwrite("x", &MultiStreamOscilloscope::SamplePoint::x); + .def_readwrite("y", &MultiStreamOscilloscope::SamplePoint::y); // TriggerSettings py::class_>(m, "TriggerSettings")