- capture timeout added

- auto-trigger initials
This commit is contained in:
Wiesner András 2022-05-11 18:13:41 +02:00
parent dcf7126db3
commit 3b09caaeb0
8 changed files with 105 additions and 56 deletions

View File

@ -11,7 +11,7 @@ MultiStreamOscilloscope::MultiStreamOscilloscope() {
mTriggerPosition_percent = TRIGGER_POS_PERCENT_DEF; mTriggerPosition_percent = TRIGGER_POS_PERCENT_DEF;
mCapturePeriod_ns = DRAW_WINDOW_PERIOD_NS_DEF; mCapturePeriod_ns = DRAW_WINDOW_PERIOD_NS_DEF;
verticalScale = VOLT_PER_BIN_DEF; verticalScale = VOLT_PER_BIN_DEF;
mTrigState = {false, false, -1, false }; mTrigState = {false, false, -1, false, false};
mFIFOBlockCnt = 0; mFIFOBlockCnt = 0;
mCaptureLength = 0; mCaptureLength = 0;
@ -23,11 +23,11 @@ void MultiStreamOscilloscope::setup(const std::vector<in_addr_t> &nodes, const A
// calculate buffer parameters // calculate buffer parameters
mCaptureLength = ceil(mCapturePeriod_ns / 1E+09 * acqFmt.sampling_rate_Hz); // calculate draw window period in samples 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 // setup channel buffers
mpChBufs.resize(mChCnt); mpChBufs.resize(mChCnt);
for (auto& chBuf: mpChBufs) { for (auto &chBuf: mpChBufs) {
chBuf.reset(new ChannelBuffer<SamplePoint>(mAcqFmt.mch_samples_per_packet, mFIFOBlockCnt)); chBuf.reset(new ChannelBuffer<SamplePoint>(mAcqFmt.mch_samples_per_packet, mFIFOBlockCnt));
} }
@ -82,9 +82,9 @@ bool MultiStreamOscilloscope::input(size_t ch, const std::shared_ptr<Timestamp>
sample *= verticalScale; sample *= verticalScale;
// save sample point // save sample point
SamplePoint& sp = mpAssemblyBuffer.get()[i]; SamplePoint &sp = mpAssemblyBuffer.get()[i];
sp.t = pTime.get()[i].to_ns(); sp.t = pTime.get()[i].to_ns();
sp.x = sample; sp.y = sample;
} }
// push new block of samples onto the FIFO // push new block of samples onto the FIFO
@ -101,11 +101,13 @@ bool MultiStreamOscilloscope::input(size_t ch, const std::shared_ptr<Timestamp>
int64_t tag = mpChBufs[ch]->copyBlock(mTriggerProbeBlock_idx, mpTriggerBuffer.get()); // TODO magic constant!... int64_t tag = mpChBufs[ch]->copyBlock(mTriggerProbeBlock_idx, mpTriggerBuffer.get()); // TODO magic constant!...
size_t i = 0; size_t i = 0;
int64_t trigTime = 0;
if (!mTrigState.trigd) { // if not triggered externally if (!mTrigState.trigd) { // if not triggered externally
while (i < mAcqFmt.mch_samples_per_packet) { while (i < mAcqFmt.mch_samples_per_packet) {
const SamplePoint &samplePoint = mpTriggerBuffer.get()[i]; // get sample 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 if (mTrigState.trigd) { // break if trigger is successful
trigTime = trigger->t_trig;
break; break;
} }
i++; // increase index i++; // increase index
@ -122,8 +124,8 @@ bool MultiStreamOscilloscope::input(size_t ch, const std::shared_ptr<Timestamp>
int64_t captureEnd = captureStart + mCaptureLength; int64_t captureEnd = captureStart + mCaptureLength;
// get time of trigger occurred // get time of trigger occurred
SamplePoint trigSP = mpChBufs[ch]->getElementByTag(mTrigState.triggerSampleTag); //SamplePoint trigSP = mpChBufs[ch]->getElementByTag(mTrigState.triggerSampleTag);
int64_t t0 = trigSP.t; int64_t t0 = trigTime;
// get eldest sample's timestamp on the trigger channel // get eldest sample's timestamp on the trigger channel
int64_t t_eldest_trigger = mpChBufs[ch]->getEldestSample().t; int64_t t_eldest_trigger = mpChBufs[ch]->getEldestSample().t;
@ -131,7 +133,7 @@ bool MultiStreamOscilloscope::input(size_t ch, const std::shared_ptr<Timestamp>
// TODO now full synchronicity is assumed // TODO now full synchronicity is assumed
// copy samples from each channel // copy samples from each channel
for (size_t k = 0; k < mChCnt; k++) { 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; int64_t t_offset, offset_index = 0;
if (k != ch) { // we are NOT processing the trigger channel, since it's the reference 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; mTrigState.armed = true;
} }
std::vector<std::vector<MultiStreamOscilloscope::SamplePoint>> MultiStreamOscilloscope::capture() { void MultiStreamOscilloscope::enableAutoTrigger(bool en) {
std::unique_lock<std::mutex> lock(mCapture_mtx); mTrigState.autoTrigger;
mCapture_cv.wait(lock, [this] { return mTrigState.samplesReady; }); // wait for data to become available }
auto samples = mCaptureBuffers; // copy buffer std::vector<std::vector<MultiStreamOscilloscope::SamplePoint>> MultiStreamOscilloscope::capture(size_t timeout_ms) {
mTrigState.samplesReady = false; // invalidate samples std::unique_lock<std::mutex> lock(mCapture_mtx);
return samples;
// 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<int64_t> MultiStreamOscilloscope::getScreenTimeLimits() const {
int64_t lowerLimit, upperLimit; int64_t lowerLimit, upperLimit;
lowerLimit = -ceil(mTriggerPosition_percent / 100.0 * mCapturePeriod_ns); lowerLimit = -ceil(mTriggerPosition_percent / 100.0 * mCapturePeriod_ns);
upperLimit = mCapturePeriod_ns + lowerLimit; upperLimit = mCapturePeriod_ns + lowerLimit;
return std::vector<int64_t>({ lowerLimit, upperLimit }); return std::vector<int64_t>({lowerLimit, upperLimit});
} }

View File

@ -20,11 +20,11 @@ public:
public: public:
struct SamplePoint { struct SamplePoint {
int64_t t; // time int64_t t; // time
double x; // sample data double y; // sample data
SamplePoint() { SamplePoint() {
t = 0; t = 0;
x = 0; y = 0;
} }
}; };
@ -56,6 +56,7 @@ private:
bool trigd; // indicates if trigger has fired bool trigd; // indicates if trigger has fired
int64_t triggerSampleTag; int64_t triggerSampleTag;
bool samplesReady; // samples have been transferred to the output buffer bool samplesReady; // samples have been transferred to the output buffer
bool autoTrigger; // auto-trigger on/off
} mTrigState; } mTrigState;
public: public:
void setup(const std::vector<in_addr_t> &nodes, const AcquisitionFormat &acqFmt) override; void setup(const std::vector<in_addr_t> &nodes, const AcquisitionFormat &acqFmt) override;
@ -73,7 +74,8 @@ public:
void triggerNow(); // make the scope trigger regardless conditions void triggerNow(); // make the scope trigger regardless conditions
void armTrigger(); // arm trigger for next acquisition void armTrigger(); // arm trigger for next acquisition
std::vector<std::vector<MultiStreamOscilloscope::SamplePoint>> capture(); // wait for captured data TODO to be renamed void enableAutoTrigger(bool en); // enable or disable auto trigger
std::vector<std::vector<MultiStreamOscilloscope::SamplePoint>> capture(size_t timeout_ms = 0); // wait for captured data TODO to be renamed
}; };

View File

@ -142,7 +142,7 @@ void MultiStreamReceiver::fnRecv(MultiStreamReceiver *pMSR) {
// limit on time difference variation // limit on time difference variation
double timeDiffVariation_ns = 1E+09 / pMSR->mAcqFmt.sampling_rate_Hz * TS_VALIDITY_RANGE; 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 // allocate buffer for interpolated timestamps
std::shared_ptr<Timestamp> pTSBuf(new Timestamp[pMSR->mAcqFmt.mch_samples_per_packet]); std::shared_ptr<Timestamp> pTSBuf(new Timestamp[pMSR->mAcqFmt.mch_samples_per_packet]);
@ -196,12 +196,12 @@ void MultiStreamReceiver::fnRecv(MultiStreamReceiver *pMSR) {
} }
// check index continuity // 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) + ")"); Logger::logLine("NON-CONTINUOUS packet indices! (" + std::to_string(lastIndex) + " -> " + std::to_string(aph.index) + ")");
// TODO Should skip here? // TODO Should skip here?
} }
lastIndex = aph.index; lastIndex = aph.index;*/
// ----------- TIME PROCESSING --------------- // ----------- TIME PROCESSING ---------------

View File

@ -12,9 +12,10 @@ TriggerSettings::TriggerSettings() {
void TriggerSettings::reset() { void TriggerSettings::reset() {
mFirstSample = true; mFirstSample = true;
ch = 0; ch = 0;
t_trig = 0;
} }
bool TriggerSettings::sample(double x) { bool TriggerSettings::sample(double y, int64_t t) {
return false; // never trigger return false; // never trigger
} }
@ -29,28 +30,33 @@ EdgeTrigger::EdgeTrigger() {
void EdgeTrigger::reset() { void EdgeTrigger::reset() {
TriggerSettings::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 // do not act on first sample
if (mFirstSample) { if (mFirstSample) {
mFirstSample = false; mFirstSample = false;
x_prev = x; y_prev = y;
t_prev = t;
return false; return false;
} }
bool trig = false; bool trig = false;
// on every other sample... // on every other sample...
if (((edge == RISING) && (x_prev < level && x > level)) || if (((edge == RISING) && (y_prev < level && y > level)) ||
((edge == FALLING) && (x_prev > level && x < level))) { ((edge == FALLING) && (y_prev > level && y < level))) {
trig = true; 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; return trig;
} }

View File

@ -14,11 +14,12 @@ protected:
bool mFirstSample; // indicates the latest sample was the first since the last reset bool mFirstSample; // indicates the latest sample was the first since the last reset
public: public:
size_t ch; // channel to probe size_t ch; // channel to probe
int64_t t_trig; // exact trigger time expressed relative to trigger sample time point
public: public:
TriggerSettings(); TriggerSettings();
virtual void reset(); // reset trigger internal state 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 // Simple edge trigger
@ -26,14 +27,15 @@ struct EdgeTrigger : public TriggerSettings, public ICreatable<EdgeTrigger> {
public: public:
enum EdgeType { RISING, FALLING }; enum EdgeType { RISING, FALLING };
private: private:
double x_prev; // previous sample double y_prev; // previous sample
int64_t t_prev; // .... sample time point
public: public:
double level; // trigger level double level; // trigger level
EdgeType edge; // edge direction EdgeType edge; // edge direction
public: public:
EdgeTrigger(); // constr. EdgeTrigger(); // constr.
void reset() override; void reset() override;
bool sample(double x) override; bool sample(double y, int64_t t) override;
}; };
#endif //WFR_APP_TRIGGER_H #endif //WFR_APP_TRIGGER_H

View File

@ -61,7 +61,7 @@ int main(int argc, char * argv[]) {
beacon->execCmdOnAllNodes("snd connect 10.42.0.1 20220"); beacon->execCmdOnAllNodes("snd connect 10.42.0.1 20220");
osc->armTrigger(); osc->armTrigger();
auto samples = osc->capture(); auto samples = osc->capture(0);
beacon->execCmdOnAllNodes("snd disconnect"); beacon->execCmdOnAllNodes("snd disconnect");
msr.stop(); msr.stop();

View File

@ -1,7 +1,7 @@
import time import time
import sys import sys
sys.path.extend(['/home/epagris/EGYETEM/DIPTERV2/wfr/python/module']) sys.path.extend(['../module'])
import pywfs import pywfs
@ -11,6 +11,9 @@ from matplotlib import pyplot as plt
from matplotlib import animation as anim from matplotlib import animation as anim
import time import time
LOCAL_ADDR = "192.168.1.204"
nodes = [ "192.168.1.180" ]
# ---------- CONNECT TO AND PREPARE SAMPLING SYSTEM ----------- # ---------- CONNECT TO AND PREPARE SAMPLING SYSTEM -----------
# enable logging onto STDOUT # enable logging onto STDOUT
@ -18,9 +21,9 @@ pywfs.Logger.start()
# discover nodes on the network # discover nodes on the network
b = pywfs.ServerBeacon() b = pywfs.ServerBeacon()
b.setInterfaceAddr("10.42.0.1") b.setInterfaceAddr(LOCAL_ADDR)
b.singleScan() b.singleScan()
nodes = b.getNodesOnNetwork() #nodes = b.getNodesOnNetwork()
# query acquisition format (assume all nodes are identical in this aspect) # query acquisition format (assume all nodes are identical in this aspect)
f = b.queryFromNode(nodes[0], "snd acqformat mr") f = b.queryFromNode(nodes[0], "snd acqformat mr")
@ -37,19 +40,25 @@ ch_n = msr.getChannelCount()
# create oscilloscope data feeder object # create oscilloscope data feeder object
osc = pywfs.MultiStreamOscilloscope.create() osc = pywfs.MultiStreamOscilloscope.create()
#index = 2 * nodes.index("192.168.1.180")
# create a slope trigger # create a slope trigger
edge_trigger = pywfs.EdgeTrigger() edge_trigger = pywfs.EdgeTrigger()
edge_trigger.level = 0.2 edge_trigger.level = 0.1
edge_trigger.edge = pywfs.FALLING edge_trigger.edge = pywfs.FALLING
#edge_trigger.ch = 0 + index
edge_trigger.ch = 0
osc.trigger = edge_trigger osc.trigger = edge_trigger
osc.setScreenPeriod(int(20e+06)) osc.setScreenPeriod(int(10e+06))
# start listening for samples # start listening for samples
msr.listen(osc) msr.listen(osc)
# enable network sample transmission from every device # 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 # # data collection
@ -68,6 +77,10 @@ def data_gen():
real_time_last = time.time() real_time_last = time.time()
index_last = 0 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(): for i in itertools.count():
# FPS measurement # FPS measurement
real_time = time.time() real_time = time.time()
@ -78,21 +91,23 @@ def data_gen():
# data collection # data collection
osc.armTrigger() # arm trigger osc.armTrigger() # arm trigger
channels = osc.capture() # wait for captured data channels = osc.capture(200) # wait for captured data
T = list() # if we have incoming data
Y = list() if (len(channels) > 0):
T = list()
Y = list()
for ch in channels: for ch in channels:
t = list() t = list()
y_t = list() y_t = list()
for sp in ch: for sp in ch:
t.append(sp.t * 1E-09) t.append(sp.t * 1E-09)
y_t.append(sp.x) y_t.append(sp.y)
T.append(t) T.append(t)
Y.append(y_t) Y.append(y_t)
yield T, Y yield T, Y
@ -135,4 +150,4 @@ plt.show()
# disconnect nodes # disconnect nodes
b.execCmdOnAllNodes("snd disconnect") b.execCmdOnAllNodes("snd disconnect")
msr.close() msr.close()

View File

@ -81,7 +81,7 @@ PYBIND11_MODULE(pywfs, m) {
.def_readwrite("verticalScale", &MultiStreamOscilloscope::verticalScale) .def_readwrite("verticalScale", &MultiStreamOscilloscope::verticalScale)
.def("armTrigger", &MultiStreamOscilloscope::armTrigger) .def("armTrigger", &MultiStreamOscilloscope::armTrigger)
.def("triggerNow", &MultiStreamOscilloscope::triggerNow) .def("triggerNow", &MultiStreamOscilloscope::triggerNow)
.def("capture", &MultiStreamOscilloscope::capture) .def("capture", &MultiStreamOscilloscope::capture, "timeout_ms"_a = 0)
.def("getChannelCount", &MultiStreamOscilloscope::getChannelCount) .def("getChannelCount", &MultiStreamOscilloscope::getChannelCount)
.def("setScreenPeriod", &MultiStreamOscilloscope::setScreenPeriod) .def("setScreenPeriod", &MultiStreamOscilloscope::setScreenPeriod)
.def("getScreenPeriod", &MultiStreamOscilloscope::getScreenPeriod) .def("getScreenPeriod", &MultiStreamOscilloscope::getScreenPeriod)
@ -94,7 +94,7 @@ PYBIND11_MODULE(pywfs, m) {
py::class_<MultiStreamOscilloscope::SamplePoint>(m, "SamplePoint") py::class_<MultiStreamOscilloscope::SamplePoint>(m, "SamplePoint")
.def(py::init<>()) .def(py::init<>())
.def_readwrite("t", &MultiStreamOscilloscope::SamplePoint::t) .def_readwrite("t", &MultiStreamOscilloscope::SamplePoint::t)
.def_readwrite("x", &MultiStreamOscilloscope::SamplePoint::x); .def_readwrite("y", &MultiStreamOscilloscope::SamplePoint::y);
// TriggerSettings // TriggerSettings
py::class_<TriggerSettings, std::shared_ptr<TriggerSettings>>(m, "TriggerSettings") py::class_<TriggerSettings, std::shared_ptr<TriggerSettings>>(m, "TriggerSettings")