- 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;
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<in_addr_t> &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<SamplePoint>(mAcqFmt.mch_samples_per_packet, mFIFOBlockCnt));
}
@ -82,9 +82,9 @@ bool MultiStreamOscilloscope::input(size_t ch, const std::shared_ptr<Timestamp>
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<Timestamp>
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<Timestamp>
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<Timestamp>
// 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<std::vector<MultiStreamOscilloscope::SamplePoint>> MultiStreamOscilloscope::capture() {
std::unique_lock<std::mutex> 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<std::vector<MultiStreamOscilloscope::SamplePoint>> MultiStreamOscilloscope::capture(size_t timeout_ms) {
std::unique_lock<std::mutex> 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<int64_t> MultiStreamOscilloscope::getScreenTimeLimits() const {
int64_t lowerLimit, upperLimit;
lowerLimit = -ceil(mTriggerPosition_percent / 100.0 * mCapturePeriod_ns);
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:
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<in_addr_t> &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<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
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<Timestamp> 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 ---------------

View File

@ -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;
}

View File

@ -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<EdgeTrigger> {
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

View File

@ -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();

View File

@ -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()
msr.close()

View File

@ -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_<MultiStreamOscilloscope::SamplePoint>(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_<TriggerSettings, std::shared_ptr<TriggerSettings>>(m, "TriggerSettings")