27 #include <qwt_abstract_scale_draw.h> 28 #include <qwt_global.h> 29 #include <qwt_plot_legenditem.h> 30 #include <qwt_scale_map.h> 37 setRenderHint(QwtPlotItem::RenderAntialiased);
38 const QColor color(Qt::black);
45 setPaintAttribute(QwtPlotCanvas::BackingStore,
false);
46 if (QwtPainter::isX11GraphicsSystem()) {
47 if (testPaintAttribute(QwtPlotCanvas::BackingStore)) {
48 setAttribute(Qt::WA_PaintOnScreen,
true);
49 setAttribute(Qt::WA_NoSystemBackground,
true);
55 void Oscilloscope::Canvas::setupPalette()
57 QPalette pal = palette();
58 QLinearGradient gradient;
59 gradient.setCoordinateMode(QGradient::StretchToDeviceMode);
60 gradient.setColorAt(1.0, QColor(Qt::white));
61 pal.setBrush(QPalette::Window, QBrush(gradient));
62 pal.setColor(QPalette::WindowText, Qt::green);
69 , d_directPainter(new QwtPlotDirectPainter())
70 , grid(new QwtPlotGrid())
71 , origin(new QwtPlotMarker())
72 , scaleMapY(new QwtScaleMap())
73 , scaleMapX(new QwtScaleMap())
75 , timer(new QTimer(this))
78 plotLayout()->setAlignCanvasToScales(
true);
87 this->grid->attach(
this);
90 setAxisMaxMajor(QwtPlot::xBottom,
static_cast<int>(divX));
91 setAxisMaxMajor(QwtPlot::yLeft,
static_cast<int>(divY));
94 enableAxis(QwtPlot::yLeft,
false);
95 enableAxis(QwtPlot::xBottom,
false);
98 setAxisScale(QwtPlot::yLeft, -1.0, 1.0);
99 setAxisScale(QwtPlot::xBottom, 0.0, 1000.0);
102 setAxisAutoScale(QwtPlot::yLeft,
false);
103 setAxisAutoScale(QwtPlot::xBottom,
false);
106 this->origin->setLineStyle(QwtPlotMarker::Cross);
107 this->origin->setValue(500.0, 0.0);
109 this->origin->attach(
this);
112 this->scaleMapY->setPaintInterval(-1.0, 1.0);
113 this->scaleMapX->setPaintInterval(0.0, 1000.0);
116 this->legendItem->attach(
this);
117 this->legendItem->setMaxColumns(1);
124 #if QWT_VERSION >= 0X060200 125 this->legendItem->setAlignmentInCanvas(
126 static_cast<Qt::Alignment
>(Qt::AlignTop | Qt::AlignRight));
128 this->legendItem->setAlignment(
129 static_cast<Qt::Alignment
>(Qt::AlignTop | Qt::AlignRight));
132 this->legendItem->setBorderRadius(8);
133 this->legendItem->setMargin(4);
134 this->legendItem->setSpacing(2);
135 this->legendItem->setItemMargin(0);
136 this->legendItem->setBackgroundBrush(QBrush(QColor(225, 225, 225)));
137 this->legendItem->attach(
this);
144 this->timer->setTimerType(Qt::PreciseTimer);
145 QObject::connect(timer, SIGNAL(timeout()),
this, SLOT(
process_data()));
146 this->timer->start(
static_cast<int>(this->refresh));
151 delete d_directPainter;
164 this->isPaused.store(value);
170 const std::unique_lock<std::shared_mutex> lock(this->m_channel_mutex);
171 auto iter = std::find_if(this->channels.begin(),
172 this->channels.end(),
174 { return chan.endpoint == probeInfo; });
175 if (iter != this->channels.end()) {
179 chan.
curve =
new QwtPlotCurve;
182 chan.
xbuffer.assign(this->buffer_size, 0.0);
183 chan.
ybuffer.assign(this->buffer_size, 0.0);
193 chan.
curve->setPen(pen);
194 chan.
curve->attach(
this);
195 this->channels.push_back(chan);
200 const std::shared_lock<std::shared_mutex> lock(this->m_channel_mutex);
201 auto iter = std::find_if(this->channels.begin(),
202 this->channels.end(),
204 { return chan.endpoint == probeInfo; });
205 return iter != this->channels.end();
210 const std::unique_lock<std::shared_mutex> lock(this->m_channel_mutex);
211 auto iter = std::find_if(this->channels.begin(),
212 this->channels.end(),
214 { return chan.endpoint == probeInfo; });
215 if (iter == this->channels.end()) {
218 iter->curve->detach();
220 iter->curve =
nullptr;
221 channels.erase(iter);
227 std::vector<IO::endpoint> all_block_endpoints;
228 std::shared_lock<std::shared_mutex> read_lock(this->m_channel_mutex);
229 for (
auto& channel : channels) {
230 if (channel.endpoint.block == block) {
231 all_block_endpoints.push_back(channel.endpoint);
235 for (
const auto&
endpoint : all_block_endpoints) {
242 this->d_directPainter->reset();
243 QwtPlot::resizeEvent(event);
248 const std::shared_lock<std::shared_mutex> lock(this->m_channel_mutex);
249 return channels.size();
254 const std::unique_lock<std::shared_mutex> lock(this->m_channel_mutex);
255 for (
auto& chan : this->channels) {
256 chan.timebuffer.assign(this->buffer_size, 0);
257 chan.xbuffer.assign(this->buffer_size, 0);
258 chan.ybuffer.assign(this->buffer_size, 0);
259 chan.xtransformed.assign(this->buffer_size, 0);
260 chan.ytransformed.assign(this->buffer_size, 0);
267 const std::unique_lock<std::shared_mutex> lock(this->m_channel_mutex);
268 this->buffer_size.store(size);
269 this->sample_buffer.assign(buffer_size, {});
270 for (
auto& chan : this->channels) {
271 chan.timebuffer.assign(this->buffer_size, 0);
272 chan.xbuffer.assign(this->buffer_size, 0);
273 chan.ybuffer.assign(this->buffer_size, 0);
274 chan.xtransformed.assign(this->buffer_size, 0);
275 chan.ytransformed.assign(this->buffer_size, 0);
282 return this->buffer_size.load();
287 const std::shared_lock<std::shared_mutex> lock(this->m_channel_mutex);
288 return horizontal_scale_ns;
293 const std::unique_lock<std::shared_mutex> lock(this->m_channel_mutex);
294 horizontal_scale_ns = value;
295 if (value >= 1000000000) {
297 }
else if (value >= 1000000) {
299 }
else if (value >= 1000) {
308 return static_cast<size_t>(divX);
313 return static_cast<size_t>(divY);
323 const std::unique_lock<std::shared_mutex> lock(this->m_channel_mutex);
325 timer->setInterval(
static_cast<int>(refresh));
330 const std::unique_lock<std::shared_mutex> lock(this->m_channel_mutex);
331 auto chan_loc = std::find_if(this->channels.begin(),
332 this->channels.end(),
334 { return chann.endpoint == endpoint; });
335 if (chan_loc == channels.end()) {
338 chan_loc->scale = scale;
343 const std::shared_lock<std::shared_mutex> lock(this->m_channel_mutex);
344 auto chan_loc = std::find_if(this->channels.begin(),
345 this->channels.end(),
347 { return chann.endpoint == endpoint; });
348 if (chan_loc == channels.end()) {
351 return chan_loc->scale;
356 const std::unique_lock<std::shared_mutex> lock(this->m_channel_mutex);
357 auto chan_loc = std::find_if(this->channels.begin(),
358 this->channels.end(),
360 { return chann.endpoint == endpoint; });
361 if (chan_loc == channels.end()) {
364 chan_loc->offset = offset;
369 const std::shared_lock<std::shared_mutex> lock(this->m_channel_mutex);
370 auto chan_loc = std::find_if(this->channels.begin(),
371 this->channels.end(),
373 { return chann.endpoint == endpoint; });
374 if (chan_loc == channels.end()) {
377 return chan_loc->offset;
381 const QString& label)
383 const std::unique_lock<std::shared_mutex> lock(this->m_channel_mutex);
384 auto chan_loc = std::find_if(this->channels.begin(),
385 this->channels.end(),
387 { return chann.endpoint == endpoint; });
388 if (chan_loc == channels.end()) {
391 chan_loc->curve->setTitle(label);
396 const std::shared_lock<std::shared_mutex> lock(this->m_channel_mutex);
397 auto chan_loc = std::find_if(this->channels.begin(),
398 this->channels.end(),
400 { return chann.endpoint == endpoint; });
401 if (chan_loc == channels.end()) {
404 return chan_loc->curve->pen().color();
409 const std::shared_lock<std::shared_mutex> lock(this->m_channel_mutex);
410 auto chan_loc = std::find_if(this->channels.begin(),
411 this->channels.end(),
413 { return chann.endpoint == endpoint; });
414 if (chan_loc == channels.end()) {
417 return chan_loc->curve->pen().style();
422 const std::shared_lock<std::shared_mutex> lock(this->m_channel_mutex);
423 auto chan_loc = std::find_if(this->channels.begin(),
424 this->channels.end(),
426 { return chann.endpoint == endpoint; });
427 if (chan_loc == channels.end()) {
430 return chan_loc->curve->pen().width();
435 const std::shared_lock<std::shared_mutex> lock(this->m_channel_mutex);
436 auto chan_loc = std::find_if(this->channels.begin(),
437 this->channels.end(),
439 { return chann.endpoint == endpoint; });
440 if (chan_loc != channels.end()) {
441 chan_loc->curve->setPen(pen);
447 this->m_trigger_info.threshold = threshold;
452 return this->m_trigger_info.threshold;
458 if (isPaused.load() || this->channels.empty()) {
461 int64_t max_time = 0;
462 int64_t local_max_time = 0;
463 for (
const auto& chan : this->channels) {
465 *std::max_element(chan.timebuffer.begin(), chan.timebuffer.end());
466 if (local_max_time > max_time) {
467 max_time = local_max_time;
470 const int64_t min_time = (max_time - horizontal_scale_ns * divX);
472 const auto max_window_time =
static_cast<double>(max_time - min_time);
473 const double min_window_time = 0.0;
474 scaleMapX->setScaleInterval(min_window_time, max_window_time);
475 size_t ringbuffer_index = 0;
476 for (
auto& channel : this->channels) {
477 channel.xtransformed.assign(this->buffer_size, 0);
478 channel.ytransformed.assign(this->buffer_size, 0);
479 scaleMapY->setScaleInterval(-channel.scale *
static_cast<double>(divY) / 2,
480 channel.scale *
static_cast<double>(divY) / 2);
481 for (
size_t i = 0; i < channel.xbuffer.size(); i++) {
482 ringbuffer_index = (i + channel.data_indx) % this->buffer_size;
484 static_cast<double>(channel.timebuffer[i] - min_time);
487 channel.xtransformed[i] =
488 scaleMapX->transform(channel.xbuffer[ringbuffer_index]);
489 channel.ytransformed[i] =
490 scaleMapY->transform(channel.ybuffer[ringbuffer_index]);
496 channel.curve->setSamples(channel.xtransformed.data(),
497 channel.ytransformed.data(),
498 static_cast<int>(channel.ytransformed.size()));
507 const std::shared_lock<std::shared_mutex> lock(this->m_channel_mutex);
509 size_t sample_count = 0;
510 size_t array_indx = 0;
511 const size_t sample_capacity_bytes =
513 for (
auto& channel : this->channels) {
517 bytes = channel.fifo->read(sample_buffer.data(), sample_capacity_bytes),
521 for (
size_t i = 0; i < sample_count; i++) {
522 array_indx = (i + channel.data_indx) % this->buffer_size;
523 channel.timebuffer[array_indx] = sample_buffer[i].time;
524 channel.ybuffer[array_indx] = sample_buffer[i].value;
527 (channel.data_indx + sample_count) % this->buffer_size;
531 sample_buffer.assign(this->buffer_size, {0, 0.0});
void setDataSize(size_t size)
double getChannelScale(IO::endpoint endpoint)
void removeChannel(IO::endpoint probeInfo)
void setTriggerThreshold(double threshold)
void setChannelLabel(IO::endpoint endpoint, const QString &label)
void setChannelPen(IO::endpoint endpoint, const QPen &pen)
int getChannelWidth(IO::endpoint endpoint)
double getChannelOffset(IO::endpoint endpoint)
QColor getChannelColor(IO::endpoint endpoint)
void setChannelOffset(IO::endpoint endpoint, double offset)
double getTriggerThreshold() const
size_t getDataSize() const
Scope(const Scope &)=delete
void setRefresh(size_t r)
void createChannel(IO::endpoint probeInfo, RT::OS::Fifo *fifo)
Qt::PenStyle getChannelStyle(IO::endpoint endpoint)
size_t getRefresh() const
void resizeEvent(QResizeEvent *event) override
void setDivT(int64_t value)
void removeBlockChannels(IO::Block *block)
void setPause(bool value)
bool channelRegistered(IO::endpoint probeInfo)
void setChannelScale(IO::endpoint endpoint, double scale)
struct IO::endpoint endpoint
struct Oscilloscope::sample sample
constexpr std::array< Qt::PenStyle, 5 > penStyles
const std::array< QColor, 7 > penColors
std::vector< double > ytransformed
std::vector< double > ybuffer
std::vector< int64_t > timebuffer
std::vector< double > xtransformed
std::vector< double > xbuffer