set(VERSION 0.1.0)
set(pulseview_SOURCES
- about.cpp
- datasnapshot.cpp
- logicdata.cpp
- logicdatasnapshot.cpp
- logicsignal.cpp
main.cpp
- mainwindow.cpp
- samplingbar.cpp
- signaldata.cpp
- sigsession.cpp
- signal.cpp
+ pv/about.cpp
+ pv/datasnapshot.cpp
+ pv/logicdata.cpp
+ pv/logicdatasnapshot.cpp
+ pv/logicsignal.cpp
+ pv/mainwindow.cpp
+ pv/samplingbar.cpp
+ pv/signaldata.cpp
+ pv/sigsession.cpp
+ pv/signal.cpp
pv/view/header.cpp
pv/view/ruler.cpp
pv/view/view.cpp
)
set(pulseview_HEADERS
- about.h
- mainwindow.h
- samplingbar.h
- sigsession.h
+ pv/about.h
+ pv/mainwindow.h
+ pv/samplingbar.h
+ pv/sigsession.h
pv/view/header.h
pv/view/ruler.h
pv/view/view.h
)
set(pulseview_FORMS
- about.ui
+ pv/about.ui
)
set(pulseview_RESOURCES
)
set(pulseview_TEST_SOURCES
+ pv/datasnapshot.cpp
+ pv/logicdatasnapshot.cpp
test/logicdatasnapshot.cpp
test/test.cpp
- datasnapshot.cpp
- logicdatasnapshot.cpp
)
qt4_wrap_cpp(pulseview_HEADERS_MOC ${pulseview_HEADERS})
if(WIN32)
include_directories(
${include_directories}
+ ${CMAKE_CURRENT_BINARY_DIR}
${Boost_INCLUDE_DIRS}
${PKGDEPS_STATIC_INCLUDE_DIRS}
)
else(WIN32)
include_directories(
${include_directories}
+ ${CMAKE_CURRENT_BINARY_DIR}
${Boost_INCLUDE_DIRS}
${PKGDEPS_INCLUDE_DIRS}
)
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-extern "C" {
-#include <sigrokdecode.h>
-}
-
-#include <QTextDocument>
-
-#include "about.h"
-#include "ui_about.h"
-
-extern "C" {
-/* __STDC_FORMAT_MACROS is required for PRIu64 and friends (in C++). */
-#define __STDC_FORMAT_MACROS
-#include <glib.h>
-#include <libsigrok/libsigrok.h>
-}
-
-About::About(QWidget *parent) :
- QDialog(parent),
- ui(new Ui::About)
-{
- GSList *l;
- struct sr_dev_driver **drivers;
- struct sr_input_format **inputs;
- struct sr_output_format **outputs;
- struct srd_decoder *dec;
- QString s;
-
- ui->setupUi(this);
-
- /* Setup the version field */
- ui->versionInfo->setText(tr("%1 %2<br />%3<br /><a href=\"%4\">%4</a>")
- .arg(QApplication::applicationName())
- .arg(QApplication::applicationVersion())
- .arg(tr("GNU GPL, version 2 or later"))
- .arg(QApplication::organizationDomain()));
-
- s.append("<table>");
-
- /* Set up the supported field */
- s.append("<tr><td colspan=\"2\"><b>" +
- tr("Supported hardware drivers:") +
- "</b></td></tr>");
- drivers = sr_driver_list();
- for (int i = 0; drivers[i]; ++i) {
- s.append(QString("<tr><td><i>%1</i></td><td>%2</td></tr>")
- .arg(QString(drivers[i]->name))
- .arg(QString(drivers[i]->longname)));
- }
-
- s.append("<tr><td colspan=\"2\"><b>" +
- tr("Supported input formats:") +
- "</b></td></tr>");
- inputs = sr_input_list();
- for (int i = 0; inputs[i]; ++i) {
- s.append(QString("<tr><td><i>%1</i></td><td>%2</td></tr>")
- .arg(QString(inputs[i]->id))
- .arg(QString(inputs[i]->description)));
- }
-
- s.append("<tr><td colspan=\"2\"><b>" +
- tr("Supported output formats:") +
- "</b></td></tr>");
- outputs = sr_output_list();
- for (int i = 0; outputs[i]; ++i) {
- s.append(QString("<tr><td><i>%1</i></td><td>%2</td></tr>")
- .arg(QString(outputs[i]->id))
- .arg(QString(outputs[i]->description)));
- }
-
- s.append("<tr><td colspan=\"2\"><b>" +
- tr("Supported protocol decoders:") +
- "</b></td></tr>");
- for (l = srd_decoder_list(); l; l = l->next) {
- dec = (struct srd_decoder *)l->data;
- s.append(QString("<tr><td><i>%1</i></td><td>%2</td></tr>")
- .arg(QString(dec->id))
- .arg(QString(dec->longname)));
- }
-
- s.append("</table>");
-
- supportedDoc.reset(new QTextDocument(this));
- supportedDoc->setHtml(s);
- ui->supportList->setDocument(supportedDoc.get());
-}
-
-About::~About()
-{
- delete ui;
-}
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef ABOUT_H
-#define ABOUT_H
-
-#include <QDialog>
-
-#include <memory>
-
-class QTextDocument;
-
-namespace Ui {
-class About;
-}
-
-class About : public QDialog
-{
- Q_OBJECT
-
-public:
- explicit About(QWidget *parent = 0);
- ~About();
-
-private:
- Ui::About *ui;
- std::auto_ptr<QTextDocument> supportedDoc;
-};
-
-#endif // ABOUT_H
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>About</class>
- <widget class="QDialog" name="About">
- <property name="windowModality">
- <enum>Qt::WindowModal</enum>
- </property>
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>600</width>
- <height>400</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>About</string>
- </property>
- <property name="whatsThis">
- <string/>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="icon">
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="pulseview.qrc">:/icons/sigrok-logo-notext.png</pixmap>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLabel" name="versionInfo">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QTextBrowser" name="supportList"/>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <resources>
- <include location="pulseview.qrc"/>
- </resources>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>About</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>248</x>
- <y>254</y>
- </hint>
- <hint type="destinationlabel">
- <x>157</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>About</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>316</x>
- <y>260</y>
- </hint>
- <hint type="destinationlabel">
- <x>286</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "datasnapshot.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-DataSnapshot::DataSnapshot(int unit_size) :
- _data(NULL),
- _sample_count(0),
- _unit_size(unit_size)
-{
- assert(_unit_size > 0);
-}
-
-DataSnapshot::~DataSnapshot()
-{
- free(_data);
-}
-
-uint64_t DataSnapshot::get_sample_count()
-{
- return _sample_count;
-}
-
-void DataSnapshot::append_data(void *data, uint64_t samples)
-{
- _data = realloc(_data, (_sample_count + samples) * _unit_size);
- memcpy((uint8_t*)_data + _sample_count * _unit_size,
- data, samples * _unit_size);
- _sample_count += samples;
-}
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-extern "C" {
-#include <libsigrok/libsigrok.h>
-}
-
-class DataSnapshot
-{
-public:
- DataSnapshot(int unit_size);
-
- virtual ~DataSnapshot();
-
- uint64_t get_sample_count();
-
-protected:
- void append_data(void *data, uint64_t samples);
-
-protected:
- void *_data;
- uint64_t _sample_count;
- int _unit_size;
-};
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "logicdata.h"
-#include "logicdatasnapshot.h"
-
-using namespace boost;
-using namespace std;
-
-LogicData::LogicData(const sr_datafeed_meta_logic &meta) :
- SignalData(meta.samplerate > 0 ? meta.samplerate : 1),
- _num_probes(meta.num_probes)
-{
-}
-
-int LogicData::get_num_probes() const
-{
- return _num_probes;
-}
-
-void LogicData::push_snapshot(
- boost::shared_ptr<LogicDataSnapshot> &snapshot)
-{
- _snapshots.push_front(snapshot);
-}
-
-deque< shared_ptr<LogicDataSnapshot> >& LogicData::get_snapshots()
-{
- return _snapshots;
-}
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "signaldata.h"
-
-#include <boost/shared_ptr.hpp>
-#include <deque>
-
-extern "C" {
-#include <libsigrok/libsigrok.h>
-}
-
-class LogicDataSnapshot;
-
-class LogicData : public SignalData
-{
-public:
- LogicData(const sr_datafeed_meta_logic &meta);
-
- int get_num_probes() const;
-
- void push_snapshot(
- boost::shared_ptr<LogicDataSnapshot> &snapshot);
-
- std::deque< boost::shared_ptr<LogicDataSnapshot> >&
- get_snapshots();
-
-private:
- const int _num_probes;
- std::deque< boost::shared_ptr<LogicDataSnapshot> >
- _snapshots;
-};
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "extdef.h"
-
-#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include <boost/foreach.hpp>
-
-#include "logicdatasnapshot.h"
-
-using namespace std;
-
-const int LogicDataSnapshot::MipMapScalePower = 4;
-const int LogicDataSnapshot::MipMapScaleFactor = 1 << MipMapScalePower;
-const float LogicDataSnapshot::LogMipMapScaleFactor = logf(MipMapScaleFactor);
-const uint64_t LogicDataSnapshot::MipMapDataUnit = 64*1024; // bytes
-
-LogicDataSnapshot::LogicDataSnapshot(
- const sr_datafeed_logic &logic) :
- DataSnapshot(logic.unitsize),
- _last_append_sample(0)
-{
- memset(_mip_map, 0, sizeof(_mip_map));
- append_payload(logic);
-}
-
-LogicDataSnapshot::~LogicDataSnapshot()
-{
- BOOST_FOREACH(MipMapLevel &l, _mip_map)
- free(l.data);
-}
-
-void LogicDataSnapshot::append_payload(
- const sr_datafeed_logic &logic)
-{
- assert(_unit_size == logic.unitsize);
-
- append_data(logic.data, logic.length);
-
- // Generate the first mip-map from the data
- append_payload_to_mipmap();
-}
-
-void LogicDataSnapshot::reallocate_mip_map(MipMapLevel &m)
-{
- const uint64_t new_data_length = ((m.length + MipMapDataUnit - 1) /
- MipMapDataUnit) * MipMapDataUnit;
- if(new_data_length > m.data_length)
- {
- m.data_length = new_data_length;
- m.data = realloc(m.data, new_data_length * _unit_size);
- }
-}
-
-void LogicDataSnapshot::append_payload_to_mipmap()
-{
- MipMapLevel &m0 = _mip_map[0];
- uint64_t prev_length;
- const uint8_t *src_ptr;
- uint8_t *dest_ptr;
- uint64_t accumulator;
- unsigned int diff_counter;
-
- // Expand the data buffer to fit the new samples
- prev_length = m0.length;
- m0.length = _sample_count / MipMapScaleFactor;
-
- // Break off if there are no new samples to compute
- if(m0.length == prev_length)
- return;
-
- reallocate_mip_map(m0);
-
- dest_ptr = (uint8_t*)m0.data + prev_length * _unit_size;
-
- // Iterate through the samples to populate the first level mipmap
- accumulator = 0;
- diff_counter = MipMapScaleFactor;
- const uint8_t *end_src_ptr = (uint8_t*)_data +
- m0.length * _unit_size * MipMapScaleFactor;
- for(src_ptr = (uint8_t*)_data +
- prev_length * _unit_size * MipMapScaleFactor;
- src_ptr < end_src_ptr;)
- {
- // Accumulate transitions which have occurred in this sample
- accumulator = 0;
- diff_counter = MipMapScaleFactor;
- while(diff_counter-- > 0)
- {
- const uint64_t sample = *(uint64_t*)src_ptr;
- accumulator |= _last_append_sample ^ sample;
- _last_append_sample = sample;
- src_ptr += _unit_size;
- }
-
- *(uint64_t*)dest_ptr = accumulator;
- dest_ptr += _unit_size;
- }
-
- // Compute higher level mipmaps
- for(int level = 1; level < ScaleStepCount; level++)
- {
- MipMapLevel &m = _mip_map[level];
- const MipMapLevel &ml = _mip_map[level-1];
-
- // Expand the data buffer to fit the new samples
- prev_length = m.length;
- m.length = ml.length / MipMapScaleFactor;
-
- // Break off if there are no more samples to computed
- if(m.length == prev_length)
- break;
-
- reallocate_mip_map(m);
-
- // Subsample the level lower level
- src_ptr = (uint8_t*)ml.data +
- _unit_size * prev_length * MipMapScaleFactor;
- const uint8_t *end_dest_ptr =
- (uint8_t*)m.data + _unit_size * m.length;
- for(dest_ptr = (uint8_t*)m.data +
- _unit_size * prev_length;
- dest_ptr < end_dest_ptr;
- dest_ptr += _unit_size)
- {
- accumulator = 0;
- diff_counter = MipMapScaleFactor;
- while(diff_counter-- > 0)
- {
- accumulator |= *(uint64_t*)src_ptr;
- src_ptr += _unit_size;
- }
-
- *(uint64_t*)dest_ptr = accumulator;
- }
- }
-}
-
-uint64_t LogicDataSnapshot::get_sample(uint64_t index) const
-{
- assert(_data);
- assert(index >= 0 && index < _sample_count);
-
- return *(uint64_t*)((uint8_t*)_data + index * _unit_size);
-}
-
-void LogicDataSnapshot::get_subsampled_edges(
- std::vector<EdgePair> &edges,
- int64_t start, int64_t end,
- float min_length, int sig_index)
-{
- int64_t index = start;
- int level;
- bool last_sample;
- bool fast_forward;
-
- assert(start >= 0);
- assert(end <= get_sample_count());
- assert(start <= end);
- assert(min_length > 0);
- assert(sig_index >= 0);
- assert(sig_index < SR_MAX_NUM_PROBES);
-
- const int64_t block_length = (int64_t)max(min_length, 1.0f);
- const int min_level = max((int)floorf(logf(min_length) /
- LogMipMapScaleFactor) - 1, 0);
- const uint64_t sig_mask = 1ULL << sig_index;
-
- // Store the initial state
- last_sample = (get_sample(start) & sig_mask) != 0;
- edges.push_back(pair<int64_t, bool>(index++, last_sample));
-
- while(index + block_length <= end)
- {
- //----- Continue to search -----//
- level = min_level;
- fast_forward = true;
-
- if(min_length < MipMapScaleFactor)
- {
- // Search individual samples up to the beginning of
- // the next first level mip map block
- const uint64_t final_index = min(end,
- pow2_ceil(index, MipMapScalePower));
-
- for(index;
- index < final_index &&
- (index & ~(~0 << MipMapScalePower)) != 0;
- index++)
- {
- const bool sample =
- (get_sample(index) & sig_mask) != 0;
-
- // If there was a change we cannot fast forward
- if(sample != last_sample) {
- fast_forward = false;
- break;
- }
- }
- }
- else
- {
- // If resolution is less than a mip map block,
- // round up to the beginning of the mip-map block
- // for this level of detail
- const int min_level_scale_power =
- (level + 1) * MipMapScalePower;
- index = pow2_ceil(index, min_level_scale_power);
- if(index >= end)
- break;
-
- // We can fast forward only if there was no change
- const bool sample =
- (get_sample(index) & sig_mask) != 0;
- fast_forward = last_sample == sample;
- }
-
- if(fast_forward) {
-
- // Fast forward: This involves zooming out to higher
- // levels of the mip map searching for changes, then
- // zooming in on them to find the point where the edge
- // begins.
-
- // Slide right and zoom out at the beginnings of mip-map
- // blocks until we encounter a change
- while(1) {
- const int level_scale_power =
- (level + 1) * MipMapScalePower;
- const uint64_t offset =
- index >> level_scale_power;
- assert(offset >= 0);
-
- // Check if we reached the last block at this
- // level, or if there was a change in this block
- if(offset >= _mip_map[level].length ||
- (get_subsample(level, offset) &
- sig_mask))
- break;
-
- if((offset & ~(~0 << MipMapScalePower)) == 0) {
- // If we are now at the beginning of a
- // higher level mip-map block ascend one
- // level
- if(level + 1 >= ScaleStepCount ||
- !_mip_map[level + 1].data)
- break;
-
- level++;
- } else {
- // Slide right to the beginning of the
- // next mip map block
- index = pow2_ceil(index + 1,
- level_scale_power);
- }
- }
-
- // Zoom in, and slide right until we encounter a change,
- // and repeat until we reach min_level
- while(1) {
- assert(_mip_map[level].data);
-
- const int level_scale_power =
- (level + 1) * MipMapScalePower;
- const uint64_t offset =
- index >> level_scale_power;
- assert(offset >= 0);
-
- // Check if we reached the last block at this
- // level, or if there was a change in this block
- if(offset >= _mip_map[level].length ||
- (get_subsample(level, offset) &
- sig_mask)) {
- // Zoom in unless we reached the minimum
- // zoom
- if(level == min_level)
- break;
-
- level--;
- } else {
- // Slide right to the beginning of the
- // next mip map block
- index = pow2_ceil(index + 1,
- level_scale_power);
- }
- }
-
- // If individual samples within the limit of resolution,
- // do a linear search for the next transition within the
- // block
- if(min_length < MipMapScaleFactor) {
- for(index; index < end; index++) {
- const bool sample = (get_sample(index) &
- sig_mask) != 0;
- if(sample != last_sample)
- break;
- }
- }
- }
-
- //----- Store the edge -----//
-
- // Take the last sample of the quanization block
- const int64_t final_index = index + block_length;
- if(index + block_length > end)
- break;
-
- // Store the final state
- const bool final_sample =
- (get_sample(final_index - 1) & sig_mask) != 0;
- edges.push_back(pair<int64_t, bool>(index, final_sample));
-
- index = final_index;
- last_sample = final_sample;
- }
-
- // Add the final state
- edges.push_back(pair<int64_t, bool>(end,
- get_sample(end) & sig_mask));
-}
-
-uint64_t LogicDataSnapshot::get_subsample(int level, uint64_t offset) const
-{
- assert(level >= 0);
- assert(_mip_map[level].data);
- return *(uint64_t*)((uint8_t*)_mip_map[level].data +
- _unit_size * offset);
-}
-
-int64_t LogicDataSnapshot::pow2_ceil(int64_t x, unsigned int power)
-{
- const int64_t p = 1 << power;
- return ((x < 0) ? x : (x + p - 1)) / p * p;
-}
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "datasnapshot.h"
-
-#include <utility>
-#include <vector>
-
-namespace LogicDataSnapshotTest {
- class Pow2;
- class Basic;
- class LargeData;
- class Pulses;
- class LongPulses;
-}
-
-class LogicDataSnapshot : public DataSnapshot
-{
-private:
- struct MipMapLevel
- {
- uint64_t length;
- uint64_t data_length;
- void *data;
- };
-
-private:
- static const int ScaleStepCount = 10;
- static const int MipMapScalePower;
- static const int MipMapScaleFactor;
- static const float LogMipMapScaleFactor;
- static const uint64_t MipMapDataUnit;
-
-public:
- typedef std::pair<int64_t, bool> EdgePair;
-
-public:
- LogicDataSnapshot(const sr_datafeed_logic &logic);
-
- virtual ~LogicDataSnapshot();
-
- void append_payload(const sr_datafeed_logic &logic);
-
-private:
- void reallocate_mip_map(MipMapLevel &m);
-
- void append_payload_to_mipmap();
-
-public:
- uint64_t get_sample(uint64_t index) const;
-
- /**
- * Parses a logic data snapshot to generate a list of transitions
- * in a time interval to a given level of detail.
- * @param[out] edges The vector to place the edges into.
- * @param[in] start The start sample index.
- * @param[in] end The end sample index.
- * @param[in] min_length The minimum number of samples that
- * can be resolved at this level of detail.
- * @param[in] sig_index The index of the signal.
- **/
- void get_subsampled_edges(std::vector<EdgePair> &edges,
- int64_t start, int64_t end,
- float min_length, int sig_index);
-
-private:
- uint64_t get_subsample(int level, uint64_t offset) const;
-
- static int64_t pow2_ceil(int64_t x, unsigned int power);
-
-private:
- struct MipMapLevel _mip_map[ScaleStepCount];
- uint64_t _last_append_sample;
-
- friend class LogicDataSnapshotTest::Pow2;
- friend class LogicDataSnapshotTest::Basic;
- friend class LogicDataSnapshotTest::LargeData;
- friend class LogicDataSnapshotTest::Pulses;
- friend class LogicDataSnapshotTest::LongPulses;
-};
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <math.h>
-
-#include "extdef.h"
-
-#include "logicdata.h"
-#include "logicdatasnapshot.h"
-#include "logicsignal.h"
-
-using namespace boost;
-using namespace std;
-
-const float LogicSignal::Margin = 10.0f;
-const float LogicSignal::Oversampling = 2.0f;
-
-const QColor LogicSignal::EdgeColour(0x80, 0x80, 0x80);
-const QColor LogicSignal::HighColour(0x00, 0xC0, 0x00);
-const QColor LogicSignal::LowColour(0xC0, 0x00, 0x00);
-
-const QColor LogicSignal::LogicSignalColours[10] = {
- QColor(0x16, 0x19, 0x1A), // Black
- QColor(0x8F, 0x52, 0x02), // Brown
- QColor(0xCC, 0x00, 0x00), // Red
- QColor(0xF5, 0x79, 0x00), // Orange
- QColor(0xED, 0xD4, 0x00), // Yellow
- QColor(0x73, 0xD2, 0x16), // Green
- QColor(0x34, 0x65, 0xA4), // Blue
- QColor(0x75, 0x50, 0x7B), // Violet
- QColor(0x88, 0x8A, 0x85), // Grey
- QColor(0xEE, 0xEE, 0xEC), // White
-};
-
-LogicSignal::LogicSignal(QString name, shared_ptr<LogicData> data,
- int probe_index) :
- Signal(name),
- _data(data),
- _probe_index(probe_index)
-{
- assert(_probe_index >= 0);
-}
-
-void LogicSignal::paint(QPainter &p, const QRect &rect, double scale,
- double offset)
-{
- QLineF *line;
-
- vector< pair<int64_t, bool> > edges;
-
- assert(scale > 0);
- assert(_data);
-
- const float high_offset = rect.top() + Margin;
- const float low_offset = rect.bottom() - Margin;
-
- const deque< shared_ptr<LogicDataSnapshot> > &snapshots =
- _data->get_snapshots();
- if(snapshots.empty())
- return;
-
- const shared_ptr<LogicDataSnapshot> &snapshot = snapshots.front();
-
- const double pixels_offset = offset / scale;
- const double samplerate = _data->get_samplerate();
- const double start_time = _data->get_start_time();
- const int64_t last_sample = snapshot->get_sample_count() - 1;
- const double samples_per_pixel = samplerate * scale;
- const double start = samplerate * (offset - start_time);
- const double end = start + samples_per_pixel * rect.width();
-
- snapshot->get_subsampled_edges(edges,
- min(max((int64_t)floor(start), (int64_t)0), last_sample),
- min(max((int64_t)ceil(end), (int64_t)0), last_sample),
- samples_per_pixel / Oversampling, _probe_index);
- assert(edges.size() >= 2);
-
- // Paint the edges
- const unsigned int edge_count = edges.size() - 2;
- QLineF *const edge_lines = new QLineF[edge_count];
- line = edge_lines;
-
- for(vector<LogicDataSnapshot::EdgePair>::const_iterator i =
- edges.begin() + 1;
- i != edges.end() - 1; i++) {
- const int x = (int)((*i).first / samples_per_pixel -
- pixels_offset) + rect.left();
- *line++ = QLineF(x, high_offset, x, low_offset);
- }
-
- p.setPen(EdgeColour);
- p.drawLines(edge_lines, edge_count);
- delete[] edge_lines;
-
- // Paint the caps
- const unsigned int max_cap_line_count = (edges.size() - 1);
- QLineF *const cap_lines = new QLineF[max_cap_line_count];
-
- p.setPen(HighColour);
- paint_caps(p, cap_lines, edges, true, samples_per_pixel,
- pixels_offset, rect.left(), high_offset);
- p.setPen(LowColour);
- paint_caps(p, cap_lines, edges, false, samples_per_pixel,
- pixels_offset, rect.left(), low_offset);
-
- delete[] cap_lines;
-}
-
-int LogicSignal::paint_caps(QPainter &p, QLineF *const lines,
- vector< pair<int64_t, bool> > &edges, bool level,
- double samples_per_pixel, double pixels_offset, int x_offset,
- int y_offset)
-{
- QLineF *line = lines;
-
- for(vector<LogicDataSnapshot::EdgePair>::const_iterator i = edges.begin();
- i != (edges.end() - 1); i++)
- if((*i).second == level) {
- *line++ = QLineF(
- (int)((*i).first / samples_per_pixel -
- pixels_offset) + x_offset, y_offset,
- (int)((*(i+1)).first / samples_per_pixel -
- pixels_offset) + x_offset, y_offset);
- }
-
- p.drawLines(lines, line - lines);
-}
-
-QColor LogicSignal::get_colour() const
-{
- return LogicSignalColours[_probe_index % countof(LogicSignalColours)];
-}
-
-int LogicSignal::get_nominal_offset(const QRect &rect) const
-{
- return rect.bottom() - Margin;
-}
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "signal.h"
-
-#include <boost/shared_ptr.hpp>
-
-class LogicData;
-
-class LogicSignal : public Signal
-{
-private:
- static const float Margin;
- static const float Oversampling;
-
- static const QColor EdgeColour;
- static const QColor HighColour;
- static const QColor LowColour;
-
- static const QColor LogicSignalColours[10];
-
-public:
- LogicSignal(QString name,
- boost::shared_ptr<LogicData> data,
- int probe_index);
-
- /**
- * Paints the signal with a QPainter
- * @param p the QPainter to paint into.
- * @param rect the rectangular area to draw the trace into.
- * @param scale the scale in seconds per pixel.
- * @param offset the time to show at the left hand edge of
- * the view in seconds.
- **/
- void paint(QPainter &p, const QRect &rect, double scale, double offset);
-
-private:
-
- int paint_caps(QPainter &p, QLineF *const lines,
- std::vector< std::pair<int64_t, bool> > &edges,
- bool level, double samples_per_pixel, double pixels_offset,
- int x_offset, int y_offset);
-
- /**
- * Get the colour of the logic signal
- */
- QColor get_colour() const;
-
- /**
- * When painting into the rectangle, calculate the y
- * offset of the zero point.
- **/
- int get_nominal_offset(const QRect &rect) const;
-
-private:
- int _probe_index;
- boost::shared_ptr<LogicData> _data;
-};
#include <QtGui/QApplication>
#include <QDebug>
-#include "mainwindow.h"
+#include "pv/mainwindow.h"
int main(int argc, char *argv[])
{
}
/* Initialise the main window */
- MainWindow w;
+ pv::MainWindow w;
w.show();
/* Run the application */
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-extern "C" {
-#include <sigrokdecode.h>
-}
-
-#include <QAction>
-#include <QApplication>
-#include <QButtonGroup>
-#include <QFileDialog>
-#include <QMenu>
-#include <QMenuBar>
-#include <QStatusBar>
-#include <QVBoxLayout>
-#include <QWidget>
-
-#include "about.h"
-#include "mainwindow.h"
-#include "samplingbar.h"
-#include "pv/view/view.h"
-
-extern "C" {
-/* __STDC_FORMAT_MACROS is required for PRIu64 and friends (in C++). */
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdarg.h>
-#include <glib.h>
-#include <libsigrok/libsigrok.h>
-}
-
-MainWindow::MainWindow(QWidget *parent) :
- QMainWindow(parent)
-{
- setup_ui();
-}
-
-void MainWindow::setup_ui()
-{
- setObjectName(QString::fromUtf8("MainWindow"));
-
- resize(1024, 768);
-
- // Set the window icon
- QIcon icon;
- icon.addFile(QString::fromUtf8(":/icons/sigrok-logo-notext.png"),
- QSize(), QIcon::Normal, QIcon::Off);
- setWindowIcon(icon);
-
- // Setup the UI actions
- _action_about = new QAction(this);
- _action_about->setObjectName(QString::fromUtf8("actionAbout"));
-
- _action_view_zoom_in = new QAction(this);
- _action_view_zoom_in->setIcon(QIcon::fromTheme("zoom-in"));
- _action_view_zoom_in->setObjectName(QString::fromUtf8("actionViewZoomIn"));
-
- _action_view_zoom_out = new QAction(this);
- _action_view_zoom_out->setIcon(QIcon::fromTheme("zoom-out"));
- _action_view_zoom_out->setObjectName(QString::fromUtf8("actionViewZoomOut"));
-
- _action_open = new QAction(this);
- _action_open->setIcon(QIcon::fromTheme("document-open"));
- _action_open->setObjectName(QString::fromUtf8("actionOpen"));
-
- // Setup the menu bar
- _menu_bar = new QMenuBar(this);
- _menu_bar->setGeometry(QRect(0, 0, 400, 25));
-
- _menu_file = new QMenu(_menu_bar);
- _menu_file->addAction(_action_open);
-
- _menu_view = new QMenu(_menu_bar);
- _menu_view->addAction(_action_view_zoom_in);
- _menu_view->addAction(_action_view_zoom_out);
-
- _menu_help = new QMenu(_menu_bar);
- _menu_help->addAction(_action_about);
-
- _menu_bar->addAction(_menu_file->menuAction());
- _menu_bar->addAction(_menu_view->menuAction());
- _menu_bar->addAction(_menu_help->menuAction());
-
- setMenuBar(_menu_bar);
- QMetaObject::connectSlotsByName(this);
-
- // Setup the toolbars
- _toolbar = new QToolBar(this);
- _toolbar->addAction(_action_open);
- _toolbar->addSeparator();
- _toolbar->addAction(_action_view_zoom_in);
- _toolbar->addAction(_action_view_zoom_out);
- addToolBar(_toolbar);
-
- _sampling_bar = new SamplingBar(this);
- connect(_sampling_bar, SIGNAL(run_stop()), this,
- SLOT(run_stop()));
- addToolBar(_sampling_bar);
-
- // Setup the central widget
- _central_widget = new QWidget(this);
- _vertical_layout = new QVBoxLayout(_central_widget);
- _vertical_layout->setSpacing(6);
- _vertical_layout->setContentsMargins(0, 0, 0, 0);
- setCentralWidget(_central_widget);
-
- // Setup the status bar
- _status_bar = new QStatusBar(this);
- setStatusBar(_status_bar);
-
- setWindowTitle(QApplication::translate("MainWindow", "PulseView", 0,
- QApplication::UnicodeUTF8));
-
- _action_open->setText(QApplication::translate("MainWindow", "&Open...", 0, QApplication::UnicodeUTF8));
- _action_view_zoom_in->setText(QApplication::translate("MainWindow", "Zoom &In", 0, QApplication::UnicodeUTF8));
- _action_view_zoom_out->setText(QApplication::translate("MainWindow", "Zoom &Out", 0, QApplication::UnicodeUTF8));
- _action_about->setText(QApplication::translate("MainWindow", "&About...", 0, QApplication::UnicodeUTF8));
-
- _menu_file->setTitle(QApplication::translate("MainWindow", "&File", 0, QApplication::UnicodeUTF8));
- _menu_view->setTitle(QApplication::translate("MainWindow", "&View", 0, QApplication::UnicodeUTF8));
- _menu_help->setTitle(QApplication::translate("MainWindow", "&Help", 0, QApplication::UnicodeUTF8));
-
- _view = new pv::view::View(_session, this);
- _vertical_layout->addWidget(_view);
-}
-
-void MainWindow::on_actionOpen_triggered()
-{
- QString file_name = QFileDialog::getOpenFileName(
- this, tr("Open File"), "",
- tr("Sigrok Sessions (*.sr)"));
- _session.load_file(file_name.toStdString());
-}
-
-void MainWindow::on_actionViewZoomIn_triggered()
-{
- _view->zoom(1);
-}
-
-void MainWindow::on_actionViewZoomOut_triggered()
-{
- _view->zoom(-1);
-}
-
-void MainWindow::on_actionAbout_triggered()
-{
- About dlg(this);
- dlg.exec();
-}
-
-void MainWindow::run_stop()
-{
- _session.start_capture(
- _sampling_bar->get_selected_device(),
- _sampling_bar->get_record_length(),
- _sampling_bar->get_sample_rate());
-}
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef MAINWINDOW_H
-#define MAINWINDOW_H
-
-#include <QMainWindow>
-
-#include "sigsession.h"
-
-class SamplingBar;
-
-namespace pv {
-namespace view {
-class View;
-}
-}
-
-class QAction;
-class QMenuBar;
-class QMenu;
-class QVBoxLayout;
-class QStatusBar;
-class QToolBar;
-class QWidget;
-
-class MainWindow : public QMainWindow
-{
- Q_OBJECT
-
-public:
- explicit MainWindow(QWidget *parent = 0);
-
-private:
- void setup_ui();
-
-private:
-
- SigSession _session;
- pv::view::View *_view;
-
- QAction *_action_open;
- QAction *_action_view_zoom_in;
- QAction *_action_view_zoom_out;
- QAction *_action_about;
-
- QMenuBar *_menu_bar;
- QMenu *_menu_file;
- QMenu *_menu_view;
- QMenu *_menu_help;
-
- QWidget *_central_widget;
- QVBoxLayout *_vertical_layout;
-
- QToolBar *_toolbar;
- SamplingBar *_sampling_bar;
- QStatusBar *_status_bar;
-
-private slots:
-
- void on_actionOpen_triggered();
-
- void on_actionViewZoomIn_triggered();
-
- void on_actionViewZoomOut_triggered();
-
- void on_actionAbout_triggered();
-
- void run_stop();
-};
-
-#endif // MAINWINDOW_H
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+extern "C" {
+#include <sigrokdecode.h>
+}
+
+#include <QTextDocument>
+
+#include "about.h"
+#include <ui_about.h>
+
+extern "C" {
+/* __STDC_FORMAT_MACROS is required for PRIu64 and friends (in C++). */
+#define __STDC_FORMAT_MACROS
+#include <glib.h>
+#include <libsigrok/libsigrok.h>
+}
+
+namespace pv {
+
+About::About(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::About)
+{
+ GSList *l;
+ struct sr_dev_driver **drivers;
+ struct sr_input_format **inputs;
+ struct sr_output_format **outputs;
+ struct srd_decoder *dec;
+ QString s;
+
+ ui->setupUi(this);
+
+ /* Setup the version field */
+ ui->versionInfo->setText(tr("%1 %2<br />%3<br /><a href=\"%4\">%4</a>")
+ .arg(QApplication::applicationName())
+ .arg(QApplication::applicationVersion())
+ .arg(tr("GNU GPL, version 2 or later"))
+ .arg(QApplication::organizationDomain()));
+
+ s.append("<table>");
+
+ /* Set up the supported field */
+ s.append("<tr><td colspan=\"2\"><b>" +
+ tr("Supported hardware drivers:") +
+ "</b></td></tr>");
+ drivers = sr_driver_list();
+ for (int i = 0; drivers[i]; ++i) {
+ s.append(QString("<tr><td><i>%1</i></td><td>%2</td></tr>")
+ .arg(QString(drivers[i]->name))
+ .arg(QString(drivers[i]->longname)));
+ }
+
+ s.append("<tr><td colspan=\"2\"><b>" +
+ tr("Supported input formats:") +
+ "</b></td></tr>");
+ inputs = sr_input_list();
+ for (int i = 0; inputs[i]; ++i) {
+ s.append(QString("<tr><td><i>%1</i></td><td>%2</td></tr>")
+ .arg(QString(inputs[i]->id))
+ .arg(QString(inputs[i]->description)));
+ }
+
+ s.append("<tr><td colspan=\"2\"><b>" +
+ tr("Supported output formats:") +
+ "</b></td></tr>");
+ outputs = sr_output_list();
+ for (int i = 0; outputs[i]; ++i) {
+ s.append(QString("<tr><td><i>%1</i></td><td>%2</td></tr>")
+ .arg(QString(outputs[i]->id))
+ .arg(QString(outputs[i]->description)));
+ }
+
+ s.append("<tr><td colspan=\"2\"><b>" +
+ tr("Supported protocol decoders:") +
+ "</b></td></tr>");
+ for (l = srd_decoder_list(); l; l = l->next) {
+ dec = (struct srd_decoder *)l->data;
+ s.append(QString("<tr><td><i>%1</i></td><td>%2</td></tr>")
+ .arg(QString(dec->id))
+ .arg(QString(dec->longname)));
+ }
+
+ s.append("</table>");
+
+ supportedDoc.reset(new QTextDocument(this));
+ supportedDoc->setHtml(s);
+ ui->supportList->setDocument(supportedDoc.get());
+}
+
+About::~About()
+{
+ delete ui;
+}
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ABOUT_H
+#define ABOUT_H
+
+#include <QDialog>
+
+#include <memory>
+
+class QTextDocument;
+
+namespace Ui {
+class About;
+}
+
+namespace pv {
+
+class About : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit About(QWidget *parent = 0);
+ ~About();
+
+private:
+ Ui::About *ui;
+ std::auto_ptr<QTextDocument> supportedDoc;
+};
+
+} // namespace pv
+
+#endif // ABOUT_H
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>About</class>
+ <widget class="QDialog" name="About">
+ <property name="windowModality">
+ <enum>Qt::WindowModal</enum>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>400</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>About</string>
+ </property>
+ <property name="whatsThis">
+ <string/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="icon">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="pixmap">
+ <pixmap resource="pulseview.qrc">:/icons/sigrok-logo-notext.png</pixmap>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="versionInfo">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QTextBrowser" name="supportList"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="pulseview.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>About</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>About</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "datasnapshot.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace pv {
+
+DataSnapshot::DataSnapshot(int unit_size) :
+ _data(NULL),
+ _sample_count(0),
+ _unit_size(unit_size)
+{
+ assert(_unit_size > 0);
+}
+
+DataSnapshot::~DataSnapshot()
+{
+ free(_data);
+}
+
+uint64_t DataSnapshot::get_sample_count()
+{
+ return _sample_count;
+}
+
+void DataSnapshot::append_data(void *data, uint64_t samples)
+{
+ _data = realloc(_data, (_sample_count + samples) * _unit_size);
+ memcpy((uint8_t*)_data + _sample_count * _unit_size,
+ data, samples * _unit_size);
+ _sample_count += samples;
+}
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+extern "C" {
+#include <libsigrok/libsigrok.h>
+}
+
+namespace pv {
+
+class DataSnapshot
+{
+public:
+ DataSnapshot(int unit_size);
+
+ virtual ~DataSnapshot();
+
+ uint64_t get_sample_count();
+
+protected:
+ void append_data(void *data, uint64_t samples);
+
+protected:
+ void *_data;
+ uint64_t _sample_count;
+ int _unit_size;
+};
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "logicdata.h"
+#include "logicdatasnapshot.h"
+
+using namespace boost;
+using namespace std;
+
+namespace pv {
+
+LogicData::LogicData(const sr_datafeed_meta_logic &meta) :
+ SignalData(meta.samplerate > 0 ? meta.samplerate : 1),
+ _num_probes(meta.num_probes)
+{
+}
+
+int LogicData::get_num_probes() const
+{
+ return _num_probes;
+}
+
+void LogicData::push_snapshot(
+ boost::shared_ptr<LogicDataSnapshot> &snapshot)
+{
+ _snapshots.push_front(snapshot);
+}
+
+deque< shared_ptr<LogicDataSnapshot> >& LogicData::get_snapshots()
+{
+ return _snapshots;
+}
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "signaldata.h"
+
+#include <boost/shared_ptr.hpp>
+#include <deque>
+
+extern "C" {
+#include <libsigrok/libsigrok.h>
+}
+
+namespace pv {
+
+class LogicDataSnapshot;
+
+class LogicData : public SignalData
+{
+public:
+ LogicData(const sr_datafeed_meta_logic &meta);
+
+ int get_num_probes() const;
+
+ void push_snapshot(
+ boost::shared_ptr<LogicDataSnapshot> &snapshot);
+
+ std::deque< boost::shared_ptr<LogicDataSnapshot> >&
+ get_snapshots();
+
+private:
+ const int _num_probes;
+ std::deque< boost::shared_ptr<LogicDataSnapshot> >
+ _snapshots;
+};
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "extdef.h"
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <boost/foreach.hpp>
+
+#include "logicdatasnapshot.h"
+
+using namespace std;
+
+namespace pv {
+
+const int LogicDataSnapshot::MipMapScalePower = 4;
+const int LogicDataSnapshot::MipMapScaleFactor = 1 << MipMapScalePower;
+const float LogicDataSnapshot::LogMipMapScaleFactor = logf(MipMapScaleFactor);
+const uint64_t LogicDataSnapshot::MipMapDataUnit = 64*1024; // bytes
+
+LogicDataSnapshot::LogicDataSnapshot(
+ const sr_datafeed_logic &logic) :
+ DataSnapshot(logic.unitsize),
+ _last_append_sample(0)
+{
+ memset(_mip_map, 0, sizeof(_mip_map));
+ append_payload(logic);
+}
+
+LogicDataSnapshot::~LogicDataSnapshot()
+{
+ BOOST_FOREACH(MipMapLevel &l, _mip_map)
+ free(l.data);
+}
+
+void LogicDataSnapshot::append_payload(
+ const sr_datafeed_logic &logic)
+{
+ assert(_unit_size == logic.unitsize);
+
+ append_data(logic.data, logic.length);
+
+ // Generate the first mip-map from the data
+ append_payload_to_mipmap();
+}
+
+void LogicDataSnapshot::reallocate_mip_map(MipMapLevel &m)
+{
+ const uint64_t new_data_length = ((m.length + MipMapDataUnit - 1) /
+ MipMapDataUnit) * MipMapDataUnit;
+ if(new_data_length > m.data_length)
+ {
+ m.data_length = new_data_length;
+ m.data = realloc(m.data, new_data_length * _unit_size);
+ }
+}
+
+void LogicDataSnapshot::append_payload_to_mipmap()
+{
+ MipMapLevel &m0 = _mip_map[0];
+ uint64_t prev_length;
+ const uint8_t *src_ptr;
+ uint8_t *dest_ptr;
+ uint64_t accumulator;
+ unsigned int diff_counter;
+
+ // Expand the data buffer to fit the new samples
+ prev_length = m0.length;
+ m0.length = _sample_count / MipMapScaleFactor;
+
+ // Break off if there are no new samples to compute
+ if(m0.length == prev_length)
+ return;
+
+ reallocate_mip_map(m0);
+
+ dest_ptr = (uint8_t*)m0.data + prev_length * _unit_size;
+
+ // Iterate through the samples to populate the first level mipmap
+ accumulator = 0;
+ diff_counter = MipMapScaleFactor;
+ const uint8_t *end_src_ptr = (uint8_t*)_data +
+ m0.length * _unit_size * MipMapScaleFactor;
+ for(src_ptr = (uint8_t*)_data +
+ prev_length * _unit_size * MipMapScaleFactor;
+ src_ptr < end_src_ptr;)
+ {
+ // Accumulate transitions which have occurred in this sample
+ accumulator = 0;
+ diff_counter = MipMapScaleFactor;
+ while(diff_counter-- > 0)
+ {
+ const uint64_t sample = *(uint64_t*)src_ptr;
+ accumulator |= _last_append_sample ^ sample;
+ _last_append_sample = sample;
+ src_ptr += _unit_size;
+ }
+
+ *(uint64_t*)dest_ptr = accumulator;
+ dest_ptr += _unit_size;
+ }
+
+ // Compute higher level mipmaps
+ for(int level = 1; level < ScaleStepCount; level++)
+ {
+ MipMapLevel &m = _mip_map[level];
+ const MipMapLevel &ml = _mip_map[level-1];
+
+ // Expand the data buffer to fit the new samples
+ prev_length = m.length;
+ m.length = ml.length / MipMapScaleFactor;
+
+ // Break off if there are no more samples to computed
+ if(m.length == prev_length)
+ break;
+
+ reallocate_mip_map(m);
+
+ // Subsample the level lower level
+ src_ptr = (uint8_t*)ml.data +
+ _unit_size * prev_length * MipMapScaleFactor;
+ const uint8_t *end_dest_ptr =
+ (uint8_t*)m.data + _unit_size * m.length;
+ for(dest_ptr = (uint8_t*)m.data +
+ _unit_size * prev_length;
+ dest_ptr < end_dest_ptr;
+ dest_ptr += _unit_size)
+ {
+ accumulator = 0;
+ diff_counter = MipMapScaleFactor;
+ while(diff_counter-- > 0)
+ {
+ accumulator |= *(uint64_t*)src_ptr;
+ src_ptr += _unit_size;
+ }
+
+ *(uint64_t*)dest_ptr = accumulator;
+ }
+ }
+}
+
+uint64_t LogicDataSnapshot::get_sample(uint64_t index) const
+{
+ assert(_data);
+ assert(index >= 0 && index < _sample_count);
+
+ return *(uint64_t*)((uint8_t*)_data + index * _unit_size);
+}
+
+void LogicDataSnapshot::get_subsampled_edges(
+ std::vector<EdgePair> &edges,
+ int64_t start, int64_t end,
+ float min_length, int sig_index)
+{
+ int64_t index = start;
+ int level;
+ bool last_sample;
+ bool fast_forward;
+
+ assert(start >= 0);
+ assert(end <= get_sample_count());
+ assert(start <= end);
+ assert(min_length > 0);
+ assert(sig_index >= 0);
+ assert(sig_index < SR_MAX_NUM_PROBES);
+
+ const int64_t block_length = (int64_t)max(min_length, 1.0f);
+ const int min_level = max((int)floorf(logf(min_length) /
+ LogMipMapScaleFactor) - 1, 0);
+ const uint64_t sig_mask = 1ULL << sig_index;
+
+ // Store the initial state
+ last_sample = (get_sample(start) & sig_mask) != 0;
+ edges.push_back(pair<int64_t, bool>(index++, last_sample));
+
+ while(index + block_length <= end)
+ {
+ //----- Continue to search -----//
+ level = min_level;
+ fast_forward = true;
+
+ if(min_length < MipMapScaleFactor)
+ {
+ // Search individual samples up to the beginning of
+ // the next first level mip map block
+ const uint64_t final_index = min(end,
+ pow2_ceil(index, MipMapScalePower));
+
+ for(index;
+ index < final_index &&
+ (index & ~(~0 << MipMapScalePower)) != 0;
+ index++)
+ {
+ const bool sample =
+ (get_sample(index) & sig_mask) != 0;
+
+ // If there was a change we cannot fast forward
+ if(sample != last_sample) {
+ fast_forward = false;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // If resolution is less than a mip map block,
+ // round up to the beginning of the mip-map block
+ // for this level of detail
+ const int min_level_scale_power =
+ (level + 1) * MipMapScalePower;
+ index = pow2_ceil(index, min_level_scale_power);
+ if(index >= end)
+ break;
+
+ // We can fast forward only if there was no change
+ const bool sample =
+ (get_sample(index) & sig_mask) != 0;
+ fast_forward = last_sample == sample;
+ }
+
+ if(fast_forward) {
+
+ // Fast forward: This involves zooming out to higher
+ // levels of the mip map searching for changes, then
+ // zooming in on them to find the point where the edge
+ // begins.
+
+ // Slide right and zoom out at the beginnings of mip-map
+ // blocks until we encounter a change
+ while(1) {
+ const int level_scale_power =
+ (level + 1) * MipMapScalePower;
+ const uint64_t offset =
+ index >> level_scale_power;
+ assert(offset >= 0);
+
+ // Check if we reached the last block at this
+ // level, or if there was a change in this block
+ if(offset >= _mip_map[level].length ||
+ (get_subsample(level, offset) &
+ sig_mask))
+ break;
+
+ if((offset & ~(~0 << MipMapScalePower)) == 0) {
+ // If we are now at the beginning of a
+ // higher level mip-map block ascend one
+ // level
+ if(level + 1 >= ScaleStepCount ||
+ !_mip_map[level + 1].data)
+ break;
+
+ level++;
+ } else {
+ // Slide right to the beginning of the
+ // next mip map block
+ index = pow2_ceil(index + 1,
+ level_scale_power);
+ }
+ }
+
+ // Zoom in, and slide right until we encounter a change,
+ // and repeat until we reach min_level
+ while(1) {
+ assert(_mip_map[level].data);
+
+ const int level_scale_power =
+ (level + 1) * MipMapScalePower;
+ const uint64_t offset =
+ index >> level_scale_power;
+ assert(offset >= 0);
+
+ // Check if we reached the last block at this
+ // level, or if there was a change in this block
+ if(offset >= _mip_map[level].length ||
+ (get_subsample(level, offset) &
+ sig_mask)) {
+ // Zoom in unless we reached the minimum
+ // zoom
+ if(level == min_level)
+ break;
+
+ level--;
+ } else {
+ // Slide right to the beginning of the
+ // next mip map block
+ index = pow2_ceil(index + 1,
+ level_scale_power);
+ }
+ }
+
+ // If individual samples within the limit of resolution,
+ // do a linear search for the next transition within the
+ // block
+ if(min_length < MipMapScaleFactor) {
+ for(index; index < end; index++) {
+ const bool sample = (get_sample(index) &
+ sig_mask) != 0;
+ if(sample != last_sample)
+ break;
+ }
+ }
+ }
+
+ //----- Store the edge -----//
+
+ // Take the last sample of the quanization block
+ const int64_t final_index = index + block_length;
+ if(index + block_length > end)
+ break;
+
+ // Store the final state
+ const bool final_sample =
+ (get_sample(final_index - 1) & sig_mask) != 0;
+ edges.push_back(pair<int64_t, bool>(index, final_sample));
+
+ index = final_index;
+ last_sample = final_sample;
+ }
+
+ // Add the final state
+ edges.push_back(pair<int64_t, bool>(end,
+ get_sample(end) & sig_mask));
+}
+
+uint64_t LogicDataSnapshot::get_subsample(int level, uint64_t offset) const
+{
+ assert(level >= 0);
+ assert(_mip_map[level].data);
+ return *(uint64_t*)((uint8_t*)_mip_map[level].data +
+ _unit_size * offset);
+}
+
+int64_t LogicDataSnapshot::pow2_ceil(int64_t x, unsigned int power)
+{
+ const int64_t p = 1 << power;
+ return ((x < 0) ? x : (x + p - 1)) / p * p;
+}
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "datasnapshot.h"
+
+#include <utility>
+#include <vector>
+
+namespace LogicDataSnapshotTest {
+ class Pow2;
+ class Basic;
+ class LargeData;
+ class Pulses;
+ class LongPulses;
+}
+
+namespace pv {
+
+class LogicDataSnapshot : public DataSnapshot
+{
+private:
+ struct MipMapLevel
+ {
+ uint64_t length;
+ uint64_t data_length;
+ void *data;
+ };
+
+private:
+ static const int ScaleStepCount = 10;
+ static const int MipMapScalePower;
+ static const int MipMapScaleFactor;
+ static const float LogMipMapScaleFactor;
+ static const uint64_t MipMapDataUnit;
+
+public:
+ typedef std::pair<int64_t, bool> EdgePair;
+
+public:
+ LogicDataSnapshot(const sr_datafeed_logic &logic);
+
+ virtual ~LogicDataSnapshot();
+
+ void append_payload(const sr_datafeed_logic &logic);
+
+private:
+ void reallocate_mip_map(MipMapLevel &m);
+
+ void append_payload_to_mipmap();
+
+public:
+ uint64_t get_sample(uint64_t index) const;
+
+ /**
+ * Parses a logic data snapshot to generate a list of transitions
+ * in a time interval to a given level of detail.
+ * @param[out] edges The vector to place the edges into.
+ * @param[in] start The start sample index.
+ * @param[in] end The end sample index.
+ * @param[in] min_length The minimum number of samples that
+ * can be resolved at this level of detail.
+ * @param[in] sig_index The index of the signal.
+ **/
+ void get_subsampled_edges(std::vector<EdgePair> &edges,
+ int64_t start, int64_t end,
+ float min_length, int sig_index);
+
+private:
+ uint64_t get_subsample(int level, uint64_t offset) const;
+
+ static int64_t pow2_ceil(int64_t x, unsigned int power);
+
+private:
+ struct MipMapLevel _mip_map[ScaleStepCount];
+ uint64_t _last_append_sample;
+
+ friend class LogicDataSnapshotTest::Pow2;
+ friend class LogicDataSnapshotTest::Basic;
+ friend class LogicDataSnapshotTest::LargeData;
+ friend class LogicDataSnapshotTest::Pulses;
+ friend class LogicDataSnapshotTest::LongPulses;
+};
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <math.h>
+
+#include "extdef.h"
+
+#include "logicdata.h"
+#include "logicdatasnapshot.h"
+#include "logicsignal.h"
+
+using namespace boost;
+using namespace std;
+
+namespace pv {
+
+const float LogicSignal::Margin = 10.0f;
+const float LogicSignal::Oversampling = 2.0f;
+
+const QColor LogicSignal::EdgeColour(0x80, 0x80, 0x80);
+const QColor LogicSignal::HighColour(0x00, 0xC0, 0x00);
+const QColor LogicSignal::LowColour(0xC0, 0x00, 0x00);
+
+const QColor LogicSignal::LogicSignalColours[10] = {
+ QColor(0x16, 0x19, 0x1A), // Black
+ QColor(0x8F, 0x52, 0x02), // Brown
+ QColor(0xCC, 0x00, 0x00), // Red
+ QColor(0xF5, 0x79, 0x00), // Orange
+ QColor(0xED, 0xD4, 0x00), // Yellow
+ QColor(0x73, 0xD2, 0x16), // Green
+ QColor(0x34, 0x65, 0xA4), // Blue
+ QColor(0x75, 0x50, 0x7B), // Violet
+ QColor(0x88, 0x8A, 0x85), // Grey
+ QColor(0xEE, 0xEE, 0xEC), // White
+};
+
+LogicSignal::LogicSignal(QString name, shared_ptr<LogicData> data,
+ int probe_index) :
+ Signal(name),
+ _data(data),
+ _probe_index(probe_index)
+{
+ assert(_probe_index >= 0);
+}
+
+void LogicSignal::paint(QPainter &p, const QRect &rect, double scale,
+ double offset)
+{
+ QLineF *line;
+
+ vector< pair<int64_t, bool> > edges;
+
+ assert(scale > 0);
+ assert(_data);
+
+ const float high_offset = rect.top() + Margin;
+ const float low_offset = rect.bottom() - Margin;
+
+ const deque< shared_ptr<LogicDataSnapshot> > &snapshots =
+ _data->get_snapshots();
+ if(snapshots.empty())
+ return;
+
+ const shared_ptr<LogicDataSnapshot> &snapshot = snapshots.front();
+
+ const double pixels_offset = offset / scale;
+ const double samplerate = _data->get_samplerate();
+ const double start_time = _data->get_start_time();
+ const int64_t last_sample = snapshot->get_sample_count() - 1;
+ const double samples_per_pixel = samplerate * scale;
+ const double start = samplerate * (offset - start_time);
+ const double end = start + samples_per_pixel * rect.width();
+
+ snapshot->get_subsampled_edges(edges,
+ min(max((int64_t)floor(start), (int64_t)0), last_sample),
+ min(max((int64_t)ceil(end), (int64_t)0), last_sample),
+ samples_per_pixel / Oversampling, _probe_index);
+ assert(edges.size() >= 2);
+
+ // Paint the edges
+ const unsigned int edge_count = edges.size() - 2;
+ QLineF *const edge_lines = new QLineF[edge_count];
+ line = edge_lines;
+
+ for(vector<LogicDataSnapshot::EdgePair>::const_iterator i =
+ edges.begin() + 1;
+ i != edges.end() - 1; i++) {
+ const int x = (int)((*i).first / samples_per_pixel -
+ pixels_offset) + rect.left();
+ *line++ = QLineF(x, high_offset, x, low_offset);
+ }
+
+ p.setPen(EdgeColour);
+ p.drawLines(edge_lines, edge_count);
+ delete[] edge_lines;
+
+ // Paint the caps
+ const unsigned int max_cap_line_count = (edges.size() - 1);
+ QLineF *const cap_lines = new QLineF[max_cap_line_count];
+
+ p.setPen(HighColour);
+ paint_caps(p, cap_lines, edges, true, samples_per_pixel,
+ pixels_offset, rect.left(), high_offset);
+ p.setPen(LowColour);
+ paint_caps(p, cap_lines, edges, false, samples_per_pixel,
+ pixels_offset, rect.left(), low_offset);
+
+ delete[] cap_lines;
+}
+
+int LogicSignal::paint_caps(QPainter &p, QLineF *const lines,
+ vector< pair<int64_t, bool> > &edges, bool level,
+ double samples_per_pixel, double pixels_offset, int x_offset,
+ int y_offset)
+{
+ QLineF *line = lines;
+
+ for(vector<LogicDataSnapshot::EdgePair>::const_iterator i = edges.begin();
+ i != (edges.end() - 1); i++)
+ if((*i).second == level) {
+ *line++ = QLineF(
+ (int)((*i).first / samples_per_pixel -
+ pixels_offset) + x_offset, y_offset,
+ (int)((*(i+1)).first / samples_per_pixel -
+ pixels_offset) + x_offset, y_offset);
+ }
+
+ p.drawLines(lines, line - lines);
+}
+
+QColor LogicSignal::get_colour() const
+{
+ return LogicSignalColours[_probe_index % countof(LogicSignalColours)];
+}
+
+int LogicSignal::get_nominal_offset(const QRect &rect) const
+{
+ return rect.bottom() - Margin;
+}
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "signal.h"
+
+#include <boost/shared_ptr.hpp>
+
+namespace pv {
+
+class LogicData;
+
+class LogicSignal : public Signal
+{
+private:
+ static const float Margin;
+ static const float Oversampling;
+
+ static const QColor EdgeColour;
+ static const QColor HighColour;
+ static const QColor LowColour;
+
+ static const QColor LogicSignalColours[10];
+
+public:
+ LogicSignal(QString name,
+ boost::shared_ptr<LogicData> data,
+ int probe_index);
+
+ /**
+ * Paints the signal with a QPainter
+ * @param p the QPainter to paint into.
+ * @param rect the rectangular area to draw the trace into.
+ * @param scale the scale in seconds per pixel.
+ * @param offset the time to show at the left hand edge of
+ * the view in seconds.
+ **/
+ void paint(QPainter &p, const QRect &rect, double scale, double offset);
+
+private:
+
+ int paint_caps(QPainter &p, QLineF *const lines,
+ std::vector< std::pair<int64_t, bool> > &edges,
+ bool level, double samples_per_pixel, double pixels_offset,
+ int x_offset, int y_offset);
+
+ /**
+ * Get the colour of the logic signal
+ */
+ QColor get_colour() const;
+
+ /**
+ * When painting into the rectangle, calculate the y
+ * offset of the zero point.
+ **/
+ int get_nominal_offset(const QRect &rect) const;
+
+private:
+ int _probe_index;
+ boost::shared_ptr<LogicData> _data;
+};
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+extern "C" {
+#include <sigrokdecode.h>
+}
+
+#include <QAction>
+#include <QApplication>
+#include <QButtonGroup>
+#include <QFileDialog>
+#include <QMenu>
+#include <QMenuBar>
+#include <QStatusBar>
+#include <QVBoxLayout>
+#include <QWidget>
+
+#include "about.h"
+#include "mainwindow.h"
+#include "samplingbar.h"
+#include "pv/view/view.h"
+
+extern "C" {
+/* __STDC_FORMAT_MACROS is required for PRIu64 and friends (in C++). */
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <glib.h>
+#include <libsigrok/libsigrok.h>
+}
+
+namespace pv {
+
+MainWindow::MainWindow(QWidget *parent) :
+ QMainWindow(parent)
+{
+ setup_ui();
+}
+
+void MainWindow::setup_ui()
+{
+ setObjectName(QString::fromUtf8("MainWindow"));
+
+ resize(1024, 768);
+
+ // Set the window icon
+ QIcon icon;
+ icon.addFile(QString::fromUtf8(":/icons/sigrok-logo-notext.png"),
+ QSize(), QIcon::Normal, QIcon::Off);
+ setWindowIcon(icon);
+
+ // Setup the UI actions
+ _action_about = new QAction(this);
+ _action_about->setObjectName(QString::fromUtf8("actionAbout"));
+
+ _action_view_zoom_in = new QAction(this);
+ _action_view_zoom_in->setIcon(QIcon::fromTheme("zoom-in"));
+ _action_view_zoom_in->setObjectName(QString::fromUtf8("actionViewZoomIn"));
+
+ _action_view_zoom_out = new QAction(this);
+ _action_view_zoom_out->setIcon(QIcon::fromTheme("zoom-out"));
+ _action_view_zoom_out->setObjectName(QString::fromUtf8("actionViewZoomOut"));
+
+ _action_open = new QAction(this);
+ _action_open->setIcon(QIcon::fromTheme("document-open"));
+ _action_open->setObjectName(QString::fromUtf8("actionOpen"));
+
+ // Setup the menu bar
+ _menu_bar = new QMenuBar(this);
+ _menu_bar->setGeometry(QRect(0, 0, 400, 25));
+
+ _menu_file = new QMenu(_menu_bar);
+ _menu_file->addAction(_action_open);
+
+ _menu_view = new QMenu(_menu_bar);
+ _menu_view->addAction(_action_view_zoom_in);
+ _menu_view->addAction(_action_view_zoom_out);
+
+ _menu_help = new QMenu(_menu_bar);
+ _menu_help->addAction(_action_about);
+
+ _menu_bar->addAction(_menu_file->menuAction());
+ _menu_bar->addAction(_menu_view->menuAction());
+ _menu_bar->addAction(_menu_help->menuAction());
+
+ setMenuBar(_menu_bar);
+ QMetaObject::connectSlotsByName(this);
+
+ // Setup the toolbars
+ _toolbar = new QToolBar(this);
+ _toolbar->addAction(_action_open);
+ _toolbar->addSeparator();
+ _toolbar->addAction(_action_view_zoom_in);
+ _toolbar->addAction(_action_view_zoom_out);
+ addToolBar(_toolbar);
+
+ _sampling_bar = new SamplingBar(this);
+ connect(_sampling_bar, SIGNAL(run_stop()), this,
+ SLOT(run_stop()));
+ addToolBar(_sampling_bar);
+
+ // Setup the central widget
+ _central_widget = new QWidget(this);
+ _vertical_layout = new QVBoxLayout(_central_widget);
+ _vertical_layout->setSpacing(6);
+ _vertical_layout->setContentsMargins(0, 0, 0, 0);
+ setCentralWidget(_central_widget);
+
+ // Setup the status bar
+ _status_bar = new QStatusBar(this);
+ setStatusBar(_status_bar);
+
+ setWindowTitle(QApplication::translate("MainWindow", "PulseView", 0,
+ QApplication::UnicodeUTF8));
+
+ _action_open->setText(QApplication::translate("MainWindow", "&Open...", 0, QApplication::UnicodeUTF8));
+ _action_view_zoom_in->setText(QApplication::translate("MainWindow", "Zoom &In", 0, QApplication::UnicodeUTF8));
+ _action_view_zoom_out->setText(QApplication::translate("MainWindow", "Zoom &Out", 0, QApplication::UnicodeUTF8));
+ _action_about->setText(QApplication::translate("MainWindow", "&About...", 0, QApplication::UnicodeUTF8));
+
+ _menu_file->setTitle(QApplication::translate("MainWindow", "&File", 0, QApplication::UnicodeUTF8));
+ _menu_view->setTitle(QApplication::translate("MainWindow", "&View", 0, QApplication::UnicodeUTF8));
+ _menu_help->setTitle(QApplication::translate("MainWindow", "&Help", 0, QApplication::UnicodeUTF8));
+
+ _view = new pv::view::View(_session, this);
+ _vertical_layout->addWidget(_view);
+}
+
+void MainWindow::on_actionOpen_triggered()
+{
+ QString file_name = QFileDialog::getOpenFileName(
+ this, tr("Open File"), "",
+ tr("Sigrok Sessions (*.sr)"));
+ _session.load_file(file_name.toStdString());
+}
+
+void MainWindow::on_actionViewZoomIn_triggered()
+{
+ _view->zoom(1);
+}
+
+void MainWindow::on_actionViewZoomOut_triggered()
+{
+ _view->zoom(-1);
+}
+
+void MainWindow::on_actionAbout_triggered()
+{
+ About dlg(this);
+ dlg.exec();
+}
+
+void MainWindow::run_stop()
+{
+ _session.start_capture(
+ _sampling_bar->get_selected_device(),
+ _sampling_bar->get_record_length(),
+ _sampling_bar->get_sample_rate());
+}
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+#include "sigsession.h"
+
+class QAction;
+class QMenuBar;
+class QMenu;
+class QVBoxLayout;
+class QStatusBar;
+class QToolBar;
+class QWidget;
+
+namespace pv {
+
+class SamplingBar;
+
+namespace view {
+class View;
+}
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget *parent = 0);
+
+private:
+ void setup_ui();
+
+private:
+
+ SigSession _session;
+ pv::view::View *_view;
+
+ QAction *_action_open;
+ QAction *_action_view_zoom_in;
+ QAction *_action_view_zoom_out;
+ QAction *_action_about;
+
+ QMenuBar *_menu_bar;
+ QMenu *_menu_file;
+ QMenu *_menu_view;
+ QMenu *_menu_help;
+
+ QWidget *_central_widget;
+ QVBoxLayout *_vertical_layout;
+
+ QToolBar *_toolbar;
+ SamplingBar *_sampling_bar;
+ QStatusBar *_status_bar;
+
+private slots:
+
+ void on_actionOpen_triggered();
+
+ void on_actionViewZoomIn_triggered();
+
+ void on_actionViewZoomOut_triggered();
+
+ void on_actionAbout_triggered();
+
+ void run_stop();
+};
+
+} // namespace pv
+
+#endif // MAINWINDOW_H
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <assert.h>
+
+#include <boost/foreach.hpp>
+
+extern "C" {
+#include <libsigrok/libsigrok.h>
+}
+
+#include <QAction>
+
+#include "samplingbar.h"
+
+namespace pv {
+
+const uint64_t SamplingBar::RecordLengths[11] = {
+ 1000000,
+ 2000000,
+ 5000000,
+ 10000000,
+ 25000000,
+ 50000000,
+ 100000000,
+ 250000000,
+ 500000000,
+ 1000000000,
+ 10000000000
+};
+
+SamplingBar::SamplingBar(QWidget *parent) :
+ QToolBar("Sampling Bar", parent),
+ _device_selector(this),
+ _record_length_selector(this),
+ _sample_rate_list(this),
+ _run_stop_button(this)
+{
+ connect(&_run_stop_button, SIGNAL(clicked()), this, SIGNAL(run_stop()));
+ connect(&_device_selector, SIGNAL(currentIndexChanged (int)),
+ this, SLOT(on_device_selected()));
+
+ _sample_rate_value.setDecimals(0);
+ _sample_rate_value.setSuffix("Hz");
+
+ BOOST_FOREACH(uint64_t l, RecordLengths)
+ {
+ char *const text = sr_si_string_u64(l, " samples");
+ _record_length_selector.addItem(QString(text),
+ qVariantFromValue(l));
+ g_free(text);
+ }
+
+ _run_stop_button.setText("Run");
+
+ addWidget(&_device_selector);
+ addWidget(&_record_length_selector);
+ _sample_rate_list_action = addWidget(&_sample_rate_list);
+ _sample_rate_value_action = addWidget(&_sample_rate_value);
+ addWidget(&_run_stop_button);
+
+ update_device_selector();
+ update_sample_rate_selector();
+}
+
+struct sr_dev_inst* SamplingBar::get_selected_device() const
+{
+ const int index = _device_selector.currentIndex();
+ if(index < 0)
+ return NULL;
+
+ return (sr_dev_inst*)_device_selector.itemData(
+ index).value<void*>();
+}
+
+uint64_t SamplingBar::get_record_length() const
+{
+ const int index = _record_length_selector.currentIndex();
+ if(index < 0)
+ return 0;
+
+ return _record_length_selector.itemData(index).value<uint64_t>();
+}
+
+uint64_t SamplingBar::get_sample_rate() const
+{
+ assert(_sample_rate_value_action);
+ assert(_sample_rate_list_action);
+
+ if(_sample_rate_value_action->isVisible())
+ return (uint64_t)_sample_rate_value.value();
+ else if(_sample_rate_list_action->isVisible())
+ {
+ const int index = _sample_rate_list.currentIndex();
+ if(index < 0)
+ return 0;
+
+ return _sample_rate_list.itemData(index).value<uint64_t>();
+ }
+
+ return 0;
+}
+
+void SamplingBar::update_device_selector()
+{
+ GSList *devices = NULL;
+
+ /* Scan all drivers for all devices. */
+ struct sr_dev_driver **const drivers = sr_driver_list();
+ for (struct sr_dev_driver **driver = drivers; *driver; driver++) {
+ GSList *tmpdevs = sr_driver_scan(*driver, NULL);
+ for (GSList *l = tmpdevs; l; l = l->next)
+ devices = g_slist_append(devices, l->data);
+ g_slist_free(tmpdevs);
+ }
+
+ for (GSList *l = devices; l; l = l->next) {
+ sr_dev_inst *const sdi = (sr_dev_inst*)l->data;
+
+ QString title;
+ if (sdi->vendor && sdi->vendor[0])
+ title += sdi->vendor + QString(" ");
+ if (sdi->model && sdi->model[0])
+ title += sdi->model + QString(" ");
+ if (sdi->version && sdi->version[0])
+ title += sdi->version + QString(" ");
+
+ _device_selector.addItem(title, qVariantFromValue(
+ (void*)sdi));
+ }
+
+ g_slist_free(devices);
+}
+
+void SamplingBar::update_sample_rate_selector()
+{
+ const sr_dev_inst *const sdi = get_selected_device();
+ const struct sr_samplerates *samplerates;
+
+ assert(_sample_rate_value_action);
+ assert(_sample_rate_list_action);
+
+ if (sr_info_get(sdi->driver, SR_DI_SAMPLERATES,
+ (const void **)&samplerates, sdi) != SR_OK)
+ return;
+
+ _sample_rate_list_action->setVisible(false);
+ _sample_rate_value_action->setVisible(false);
+
+ if (samplerates->step)
+ {
+ _sample_rate_value.setRange(
+ samplerates->low, samplerates->high);
+ _sample_rate_value.setSingleStep(samplerates->step);
+ _sample_rate_value_action->setVisible(true);
+ }
+ else
+ {
+ _sample_rate_list.clear();
+ for (const uint64_t *rate = samplerates->list;
+ *rate; rate++)
+ _sample_rate_list.addItem(
+ sr_samplerate_string(*rate),
+ qVariantFromValue(*rate));
+ _sample_rate_list.show();
+ _sample_rate_list_action->setVisible(true);
+ }
+}
+
+void SamplingBar::on_device_selected()
+{
+ update_sample_rate_selector();
+}
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SAMPLINGBAR_H
+#define SAMPLINGBAR_H
+
+#include <stdint.h>
+
+#include <QComboBox>
+#include <QDoubleSpinBox>
+#include <QToolBar>
+#include <QToolButton>
+
+class QAction;
+
+namespace pv {
+
+class SamplingBar : public QToolBar
+{
+ Q_OBJECT
+
+private:
+ static const uint64_t RecordLengths[11];
+
+public:
+ SamplingBar(QWidget *parent);
+
+ struct sr_dev_inst* get_selected_device() const;
+ uint64_t get_record_length() const;
+ uint64_t get_sample_rate() const;
+
+signals:
+ void run_stop();
+
+private:
+ void update_device_selector();
+ void update_sample_rate_selector();
+
+private slots:
+ void on_device_selected();
+
+private:
+ QComboBox _device_selector;
+
+ QComboBox _record_length_selector;
+
+ QComboBox _sample_rate_list;
+ QAction *_sample_rate_list_action;
+ QDoubleSpinBox _sample_rate_value;
+ QAction *_sample_rate_value_action;
+
+ QToolButton _run_stop_button;
+};
+
+} // namespace pv
+
+#endif // SAMPLINGBAR_H
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "signal.h"
+
+#include "extdef.h"
+
+namespace pv {
+
+const QSizeF Signal::LabelPadding(4, 0);
+
+Signal::Signal(QString name) :
+ _name(name)
+{
+}
+
+QString Signal::get_name() const
+{
+ return _name;
+}
+
+void Signal::paint_label(QPainter &p, const QRect &rect)
+{
+ p.setBrush(get_colour());
+
+ const QString text(_name);
+ const QColor colour = get_colour();
+
+ const QSizeF text_size = p.boundingRect(
+ QRectF(0, 0, rect.width(), 0), 0, text).size();
+
+ const float nominal_offset = get_nominal_offset(rect);
+ const QSizeF label_size(
+ text_size.width() + LabelPadding.width() * 2,
+ text_size.height() + LabelPadding.height() * 2);
+ const float label_arrow_length = label_size.height() / 2;
+ const QRectF label_rect(
+ rect.right() - label_arrow_length - label_size.width(),
+ nominal_offset - label_size.height() / 2,
+ label_size.width(), label_size.height());
+
+ // Paint the label
+ const QPointF points[] = {
+ label_rect.topLeft(),
+ label_rect.topRight(),
+ QPointF(rect.right(), nominal_offset),
+ label_rect.bottomRight(),
+ label_rect.bottomLeft()
+ };
+
+ const QPointF highlight_points[] = {
+ QPointF(label_rect.left() + 1, label_rect.top() + 1),
+ QPointF(label_rect.right(), label_rect.top() + 1),
+ QPointF(rect.right() - 1, nominal_offset),
+ QPointF(label_rect.right(), label_rect.bottom() - 1),
+ QPointF(label_rect.left() + 1, label_rect.bottom() - 1)
+ };
+
+ p.setPen(Qt::transparent);
+ p.setBrush(colour);
+ p.drawPolygon(points, countof(points));
+
+ p.setPen(colour.lighter());
+ p.setBrush(Qt::transparent);
+ p.drawPolygon(highlight_points, countof(highlight_points));
+
+ p.setPen(colour.darker());
+ p.setBrush(Qt::transparent);
+ p.drawPolygon(points, countof(points));
+
+ // Paint the text
+ p.setPen((colour.lightness() > 64) ? Qt::black : Qt::white);
+ p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, text);
+}
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <boost/shared_ptr.hpp>
+
+#include <QPainter>
+#include <QRect>
+#include <QString>
+
+#include <stdint.h>
+
+namespace pv {
+
+class SignalData;
+
+class Signal
+{
+private:
+ static const QSizeF LabelPadding;
+
+protected:
+ Signal(QString name);
+
+public:
+ QString get_name() const;
+
+ /**
+ * Paints the signal with a QPainter
+ * @param p the QPainter to paint into.
+ * @param rect the rectangular area to draw the trace into.
+ * @param scale the scale in seconds per pixel.
+ * @param offset the time to show at the left hand edge of
+ * the view in seconds.
+ **/
+ virtual void paint(QPainter &p, const QRect &rect, double scale,
+ double offset) = 0;
+
+ /**
+ * Paints the signal label into a QGLWidget.
+ * @param p the QPainter to paint into.
+ * @param rect the rectangular area to draw the label into.
+ */
+ virtual void paint_label(QPainter &p, const QRect &rect);
+
+protected:
+
+ /**
+ * Get the colour of the logic signal
+ */
+ virtual QColor get_colour() const = 0;
+
+ /**
+ * When painting into the rectangle, calculate the y
+ * offset of the zero point.
+ **/
+ virtual int get_nominal_offset(const QRect &rect) const = 0;
+
+protected:
+ QString _name;
+};
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "signaldata.h"
+
+using namespace std;
+
+namespace pv {
+
+SignalData::SignalData(double samplerate) :
+ _samplerate(samplerate),
+ _start_time(0)
+{
+}
+
+double SignalData::get_samplerate() const
+{
+ return _samplerate;
+}
+
+double SignalData::get_start_time() const
+{
+ return _start_time;
+}
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+
+namespace pv {
+
+class SignalData
+{
+public:
+ SignalData(double samplerate);
+
+public:
+ double get_samplerate() const;
+ double get_start_time() const;
+
+protected:
+ const double _samplerate;
+ const double _start_time;
+};
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "sigsession.h"
+
+#include "logicdata.h"
+#include "logicdatasnapshot.h"
+#include "logicsignal.h"
+
+#include <QDebug>
+
+#include <assert.h>
+
+using namespace boost;
+using namespace std;
+
+namespace pv {
+
+// TODO: This should not be necessary
+SigSession* SigSession::_session = NULL;
+
+SigSession::SigSession()
+{
+ // TODO: This should not be necessary
+ _session = this;
+}
+
+SigSession::~SigSession()
+{
+ // TODO: This should not be necessary
+ _session = NULL;
+}
+
+void SigSession::load_file(const std::string &name)
+{
+ if (sr_session_load(name.c_str()) == SR_OK) {
+ /* sigrok session file */
+ sr_session_datafeed_callback_add(data_feed_in_proc);
+ sr_session_start();
+ sr_session_run();
+ sr_session_stop();
+ }
+}
+
+void SigSession::start_capture(struct sr_dev_inst *sdi,
+ uint64_t record_length, uint64_t sample_rate)
+{
+ sr_session_new();
+ sr_session_datafeed_callback_add(data_feed_in_proc);
+
+ if (sr_session_dev_add(sdi) != SR_OK) {
+ qDebug() << "Failed to use device.";
+ sr_session_destroy();
+ return;
+ }
+
+ if (sr_dev_config_set(sdi, SR_HWCAP_LIMIT_SAMPLES,
+ &record_length) != SR_OK) {
+ qDebug() << "Failed to configure time-based sample limit.";
+ sr_session_destroy();
+ return;
+ }
+
+ if (sr_dev_config_set(sdi, SR_HWCAP_SAMPLERATE,
+ &sample_rate) != SR_OK) {
+ qDebug() << "Failed to configure samplerate.";
+ sr_session_destroy();
+ return;
+ }
+
+ if (sr_session_start() != SR_OK) {
+ qDebug() << "Failed to start session.";
+ return;
+ }
+
+ sr_session_run();
+ sr_session_destroy();
+}
+
+vector< shared_ptr<Signal> >& SigSession::get_signals()
+{
+ return _signals;
+}
+
+boost::shared_ptr<LogicData> SigSession::get_data()
+{
+ return _logic_data;
+}
+
+void SigSession::data_feed_in(const struct sr_dev_inst *sdi,
+ struct sr_datafeed_packet *packet)
+{
+ assert(sdi);
+ assert(packet);
+
+ switch (packet->type) {
+ case SR_DF_HEADER:
+ _signals.clear();
+ break;
+
+ case SR_DF_META_LOGIC:
+ {
+ assert(packet->payload);
+
+ const sr_datafeed_meta_logic &meta_logic =
+ *(sr_datafeed_meta_logic*)packet->payload;
+
+ // Create an empty LogiData for coming data snapshots
+ _logic_data.reset(new LogicData(meta_logic));
+ assert(_logic_data);
+ if(!_logic_data)
+ break;
+
+ // Add the signals
+ for (int i = 0; i < meta_logic.num_probes; i++)
+ {
+ const sr_probe *const probe =
+ (const sr_probe*)g_slist_nth_data(
+ sdi->probes, i);
+ if(probe->enabled)
+ {
+ boost::shared_ptr<LogicSignal> signal(
+ new LogicSignal(probe->name,
+ _logic_data,
+ probe->index));
+ _signals.push_back(signal);
+ }
+ }
+
+ break;
+ }
+
+ case SR_DF_LOGIC:
+
+ assert(packet->payload);
+ if(!_cur_logic_snapshot)
+ {
+ // Create a new data snapshot
+ _cur_logic_snapshot = shared_ptr<LogicDataSnapshot>(
+ new LogicDataSnapshot(
+ *(sr_datafeed_logic*)packet->payload));
+ _logic_data->push_snapshot(_cur_logic_snapshot);
+ }
+ else
+ {
+ // Append to the existing data snapshot
+ _cur_logic_snapshot->append_payload(
+ *(sr_datafeed_logic*)packet->payload);
+ }
+
+ break;
+
+ case SR_DF_END:
+ _cur_logic_snapshot.reset();
+ data_updated();
+ break;
+ }
+}
+
+void SigSession::data_feed_in_proc(const struct sr_dev_inst *sdi,
+ struct sr_datafeed_packet *packet)
+{
+ assert(_session);
+ _session->data_feed_in(sdi, packet);
+}
+
+} // namespace pv
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SIGSESSION_H
+#define SIGSESSION_H
+
+#include <boost/shared_ptr.hpp>
+
+#include <string>
+#include <vector>
+
+#include <QObject>
+
+extern "C" {
+#include <libsigrok/libsigrok.h>
+}
+
+namespace pv {
+
+class LogicData;
+class LogicDataSnapshot;
+class Signal;
+
+class SigSession : public QObject
+{
+ Q_OBJECT
+
+public:
+ SigSession();
+
+ ~SigSession();
+
+ void load_file(const std::string &name);
+
+ void start_capture(struct sr_dev_inst* sdi, uint64_t record_length,
+ uint64_t sample_rate);
+
+ std::vector< boost::shared_ptr<Signal> >&
+ get_signals();
+
+ boost::shared_ptr<LogicData> get_data();
+
+private:
+ void data_feed_in(const struct sr_dev_inst *sdi,
+ struct sr_datafeed_packet *packet);
+
+ static void data_feed_in_proc(const struct sr_dev_inst *sdi,
+ struct sr_datafeed_packet *packet);
+
+private:
+ std::vector< boost::shared_ptr<Signal> > _signals;
+ boost::shared_ptr<LogicData> _logic_data;
+ boost::shared_ptr<LogicDataSnapshot> _cur_logic_snapshot;
+
+signals:
+ void data_updated();
+
+private:
+ // TODO: This should not be necessary. Multiple concurrent
+ // sessions should should be supported and it should be
+ // possible to associate a pointer with a sr_session.
+ static SigSession *_session;
+};
+
+} // namespace pv
+
+#endif // SIGSESSION_H
#include "header.h"
#include "view.h"
-#include "../../signal.h"
-#include "../../sigsession.h"
+#include "../signal.h"
+#include "../sigsession.h"
#include <assert.h>
#include "view.h"
#include "viewport.h"
-#include "../../logicdata.h"
-#include "../../logicdatasnapshot.h"
-#include "../../sigsession.h"
+#include "../logicdata.h"
+#include "../logicdatasnapshot.h"
+#include "../sigsession.h"
using namespace boost;
using namespace std;
#include <QAbstractScrollArea>
+namespace pv {
+
class SigSession;
-namespace pv {
namespace view {
class Header;
#include "view.h"
#include "viewport.h"
-#include "../../sigsession.h"
-#include "../../signal.h"
+#include "../sigsession.h"
+#include "../signal.h"
#include <QMouseEvent>
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <assert.h>
-
-#include <boost/foreach.hpp>
-
-extern "C" {
-#include <libsigrok/libsigrok.h>
-}
-
-#include <QAction>
-
-#include "samplingbar.h"
-
-const uint64_t SamplingBar::RecordLengths[11] = {
- 1000000,
- 2000000,
- 5000000,
- 10000000,
- 25000000,
- 50000000,
- 100000000,
- 250000000,
- 500000000,
- 1000000000,
- 10000000000
-};
-
-SamplingBar::SamplingBar(QWidget *parent) :
- QToolBar("Sampling Bar", parent),
- _device_selector(this),
- _record_length_selector(this),
- _sample_rate_list(this),
- _run_stop_button(this)
-{
- connect(&_run_stop_button, SIGNAL(clicked()), this, SIGNAL(run_stop()));
- connect(&_device_selector, SIGNAL(currentIndexChanged (int)),
- this, SLOT(on_device_selected()));
-
- _sample_rate_value.setDecimals(0);
- _sample_rate_value.setSuffix("Hz");
-
- BOOST_FOREACH(uint64_t l, RecordLengths)
- {
- char *const text = sr_si_string_u64(l, " samples");
- _record_length_selector.addItem(QString(text),
- qVariantFromValue(l));
- g_free(text);
- }
-
- _run_stop_button.setText("Run");
-
- addWidget(&_device_selector);
- addWidget(&_record_length_selector);
- _sample_rate_list_action = addWidget(&_sample_rate_list);
- _sample_rate_value_action = addWidget(&_sample_rate_value);
- addWidget(&_run_stop_button);
-
- update_device_selector();
- update_sample_rate_selector();
-}
-
-struct sr_dev_inst* SamplingBar::get_selected_device() const
-{
- const int index = _device_selector.currentIndex();
- if(index < 0)
- return NULL;
-
- return (sr_dev_inst*)_device_selector.itemData(
- index).value<void*>();
-}
-
-uint64_t SamplingBar::get_record_length() const
-{
- const int index = _record_length_selector.currentIndex();
- if(index < 0)
- return 0;
-
- return _record_length_selector.itemData(index).value<uint64_t>();
-}
-
-uint64_t SamplingBar::get_sample_rate() const
-{
- assert(_sample_rate_value_action);
- assert(_sample_rate_list_action);
-
- if(_sample_rate_value_action->isVisible())
- return (uint64_t)_sample_rate_value.value();
- else if(_sample_rate_list_action->isVisible())
- {
- const int index = _sample_rate_list.currentIndex();
- if(index < 0)
- return 0;
-
- return _sample_rate_list.itemData(index).value<uint64_t>();
- }
-
- return 0;
-}
-
-void SamplingBar::update_device_selector()
-{
- GSList *devices = NULL;
-
- /* Scan all drivers for all devices. */
- struct sr_dev_driver **const drivers = sr_driver_list();
- for (struct sr_dev_driver **driver = drivers; *driver; driver++) {
- GSList *tmpdevs = sr_driver_scan(*driver, NULL);
- for (GSList *l = tmpdevs; l; l = l->next)
- devices = g_slist_append(devices, l->data);
- g_slist_free(tmpdevs);
- }
-
- for (GSList *l = devices; l; l = l->next) {
- sr_dev_inst *const sdi = (sr_dev_inst*)l->data;
-
- QString title;
- if (sdi->vendor && sdi->vendor[0])
- title += sdi->vendor + QString(" ");
- if (sdi->model && sdi->model[0])
- title += sdi->model + QString(" ");
- if (sdi->version && sdi->version[0])
- title += sdi->version + QString(" ");
-
- _device_selector.addItem(title, qVariantFromValue(
- (void*)sdi));
- }
-
- g_slist_free(devices);
-}
-
-void SamplingBar::update_sample_rate_selector()
-{
- const sr_dev_inst *const sdi = get_selected_device();
- const struct sr_samplerates *samplerates;
-
- assert(_sample_rate_value_action);
- assert(_sample_rate_list_action);
-
- if (sr_info_get(sdi->driver, SR_DI_SAMPLERATES,
- (const void **)&samplerates, sdi) != SR_OK)
- return;
-
- _sample_rate_list_action->setVisible(false);
- _sample_rate_value_action->setVisible(false);
-
- if (samplerates->step)
- {
- _sample_rate_value.setRange(
- samplerates->low, samplerates->high);
- _sample_rate_value.setSingleStep(samplerates->step);
- _sample_rate_value_action->setVisible(true);
- }
- else
- {
- _sample_rate_list.clear();
- for (const uint64_t *rate = samplerates->list;
- *rate; rate++)
- _sample_rate_list.addItem(
- sr_samplerate_string(*rate),
- qVariantFromValue(*rate));
- _sample_rate_list.show();
- _sample_rate_list_action->setVisible(true);
- }
-}
-
-void SamplingBar::on_device_selected()
-{
- update_sample_rate_selector();
-}
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef SAMPLINGBAR_H
-#define SAMPLINGBAR_H
-
-#include <stdint.h>
-
-#include <QComboBox>
-#include <QDoubleSpinBox>
-#include <QToolBar>
-#include <QToolButton>
-
-class QAction;
-
-class SamplingBar : public QToolBar
-{
- Q_OBJECT
-
-private:
- static const uint64_t RecordLengths[11];
-
-public:
- SamplingBar(QWidget *parent);
-
- struct sr_dev_inst* get_selected_device() const;
- uint64_t get_record_length() const;
- uint64_t get_sample_rate() const;
-
-signals:
- void run_stop();
-
-private:
- void update_device_selector();
- void update_sample_rate_selector();
-
-private slots:
- void on_device_selected();
-
-private:
- QComboBox _device_selector;
-
- QComboBox _record_length_selector;
-
- QComboBox _sample_rate_list;
- QAction *_sample_rate_list_action;
- QDoubleSpinBox _sample_rate_value;
- QAction *_sample_rate_value_action;
-
- QToolButton _run_stop_button;
-};
-
-#endif // SAMPLINGBAR_H
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "signal.h"
-
-#include "extdef.h"
-
-const QSizeF Signal::LabelPadding(4, 0);
-
-Signal::Signal(QString name) :
- _name(name)
-{
-}
-
-QString Signal::get_name() const
-{
- return _name;
-}
-
-void Signal::paint_label(QPainter &p, const QRect &rect)
-{
- p.setBrush(get_colour());
-
- const QString text(_name);
- const QColor colour = get_colour();
-
- const QSizeF text_size = p.boundingRect(
- QRectF(0, 0, rect.width(), 0), 0, text).size();
-
- const float nominal_offset = get_nominal_offset(rect);
- const QSizeF label_size(
- text_size.width() + LabelPadding.width() * 2,
- text_size.height() + LabelPadding.height() * 2);
- const float label_arrow_length = label_size.height() / 2;
- const QRectF label_rect(
- rect.right() - label_arrow_length - label_size.width(),
- nominal_offset - label_size.height() / 2,
- label_size.width(), label_size.height());
-
- // Paint the label
- const QPointF points[] = {
- label_rect.topLeft(),
- label_rect.topRight(),
- QPointF(rect.right(), nominal_offset),
- label_rect.bottomRight(),
- label_rect.bottomLeft()
- };
-
- const QPointF highlight_points[] = {
- QPointF(label_rect.left() + 1, label_rect.top() + 1),
- QPointF(label_rect.right(), label_rect.top() + 1),
- QPointF(rect.right() - 1, nominal_offset),
- QPointF(label_rect.right(), label_rect.bottom() - 1),
- QPointF(label_rect.left() + 1, label_rect.bottom() - 1)
- };
-
- p.setPen(Qt::transparent);
- p.setBrush(colour);
- p.drawPolygon(points, countof(points));
-
- p.setPen(colour.lighter());
- p.setBrush(Qt::transparent);
- p.drawPolygon(highlight_points, countof(highlight_points));
-
- p.setPen(colour.darker());
- p.setBrush(Qt::transparent);
- p.drawPolygon(points, countof(points));
-
- // Paint the text
- p.setPen((colour.lightness() > 64) ? Qt::black : Qt::white);
- p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, text);
-}
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <boost/shared_ptr.hpp>
-
-#include <QPainter>
-#include <QRect>
-#include <QString>
-
-#include <stdint.h>
-
-class SignalData;
-
-class Signal
-{
-private:
- static const QSizeF LabelPadding;
-
-protected:
- Signal(QString name);
-
-public:
- QString get_name() const;
-
- /**
- * Paints the signal with a QPainter
- * @param p the QPainter to paint into.
- * @param rect the rectangular area to draw the trace into.
- * @param scale the scale in seconds per pixel.
- * @param offset the time to show at the left hand edge of
- * the view in seconds.
- **/
- virtual void paint(QPainter &p, const QRect &rect, double scale,
- double offset) = 0;
-
- /**
- * Paints the signal label into a QGLWidget.
- * @param p the QPainter to paint into.
- * @param rect the rectangular area to draw the label into.
- */
- virtual void paint_label(QPainter &p, const QRect &rect);
-
-protected:
-
- /**
- * Get the colour of the logic signal
- */
- virtual QColor get_colour() const = 0;
-
- /**
- * When painting into the rectangle, calculate the y
- * offset of the zero point.
- **/
- virtual int get_nominal_offset(const QRect &rect) const = 0;
-
-protected:
- QString _name;
-};
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "signaldata.h"
-
-using namespace std;
-
-SignalData::SignalData(double samplerate) :
- _samplerate(samplerate),
- _start_time(0)
-{
-}
-
-double SignalData::get_samplerate() const
-{
- return _samplerate;
-}
-
-double SignalData::get_start_time() const
-{
- return _start_time;
-}
\ No newline at end of file
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdint.h>
-
-class SignalData
-{
-public:
- SignalData(double samplerate);
-
-public:
- double get_samplerate() const;
- double get_start_time() const;
-
-protected:
- const double _samplerate;
- const double _start_time;
-};
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "sigsession.h"
-
-#include "logicdata.h"
-#include "logicdatasnapshot.h"
-#include "logicsignal.h"
-
-#include <QDebug>
-
-#include <assert.h>
-
-using namespace boost;
-using namespace std;
-
-// TODO: This should not be necessary
-SigSession* SigSession::_session = NULL;
-
-SigSession::SigSession()
-{
- // TODO: This should not be necessary
- _session = this;
-}
-
-SigSession::~SigSession()
-{
- // TODO: This should not be necessary
- _session = NULL;
-}
-
-void SigSession::load_file(const std::string &name)
-{
- if (sr_session_load(name.c_str()) == SR_OK) {
- /* sigrok session file */
- sr_session_datafeed_callback_add(data_feed_in_proc);
- sr_session_start();
- sr_session_run();
- sr_session_stop();
- }
-}
-
-void SigSession::start_capture(struct sr_dev_inst *sdi,
- uint64_t record_length, uint64_t sample_rate)
-{
- sr_session_new();
- sr_session_datafeed_callback_add(data_feed_in_proc);
-
- if (sr_session_dev_add(sdi) != SR_OK) {
- qDebug() << "Failed to use device.";
- sr_session_destroy();
- return;
- }
-
- if (sr_dev_config_set(sdi, SR_HWCAP_LIMIT_SAMPLES,
- &record_length) != SR_OK) {
- qDebug() << "Failed to configure time-based sample limit.";
- sr_session_destroy();
- return;
- }
-
- if (sr_dev_config_set(sdi, SR_HWCAP_SAMPLERATE,
- &sample_rate) != SR_OK) {
- qDebug() << "Failed to configure samplerate.";
- sr_session_destroy();
- return;
- }
-
- if (sr_session_start() != SR_OK) {
- qDebug() << "Failed to start session.";
- return;
- }
-
- sr_session_run();
- sr_session_destroy();
-}
-
-vector< shared_ptr<Signal> >& SigSession::get_signals()
-{
- return _signals;
-}
-
-boost::shared_ptr<LogicData> SigSession::get_data()
-{
- return _logic_data;
-}
-
-void SigSession::data_feed_in(const struct sr_dev_inst *sdi,
- struct sr_datafeed_packet *packet)
-{
- assert(sdi);
- assert(packet);
-
- switch (packet->type) {
- case SR_DF_HEADER:
- _signals.clear();
- break;
-
- case SR_DF_META_LOGIC:
- {
- assert(packet->payload);
-
- const sr_datafeed_meta_logic &meta_logic =
- *(sr_datafeed_meta_logic*)packet->payload;
-
- // Create an empty LogiData for coming data snapshots
- _logic_data.reset(new LogicData(meta_logic));
- assert(_logic_data);
- if(!_logic_data)
- break;
-
- // Add the signals
- for (int i = 0; i < meta_logic.num_probes; i++)
- {
- const sr_probe *const probe =
- (const sr_probe*)g_slist_nth_data(
- sdi->probes, i);
- if(probe->enabled)
- {
- boost::shared_ptr<LogicSignal> signal(
- new LogicSignal(probe->name,
- _logic_data,
- probe->index));
- _signals.push_back(signal);
- }
- }
-
- break;
- }
-
- case SR_DF_LOGIC:
-
- assert(packet->payload);
- if(!_cur_logic_snapshot)
- {
- // Create a new data snapshot
- _cur_logic_snapshot = shared_ptr<LogicDataSnapshot>(
- new LogicDataSnapshot(
- *(sr_datafeed_logic*)packet->payload));
- _logic_data->push_snapshot(_cur_logic_snapshot);
- }
- else
- {
- // Append to the existing data snapshot
- _cur_logic_snapshot->append_payload(
- *(sr_datafeed_logic*)packet->payload);
- }
-
- break;
-
- case SR_DF_END:
- _cur_logic_snapshot.reset();
- data_updated();
- break;
- }
-}
-
-void SigSession::data_feed_in_proc(const struct sr_dev_inst *sdi,
- struct sr_datafeed_packet *packet)
-{
- assert(_session);
- _session->data_feed_in(sdi, packet);
-}
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef SIGSESSION_H
-#define SIGSESSION_H
-
-#include <boost/shared_ptr.hpp>
-
-#include <string>
-#include <vector>
-
-#include <QObject>
-
-extern "C" {
-#include <libsigrok/libsigrok.h>
-}
-
-class LogicData;
-class LogicDataSnapshot;
-class Signal;
-
-class SigSession : public QObject
-{
- Q_OBJECT
-
-public:
- SigSession();
-
- ~SigSession();
-
- void load_file(const std::string &name);
-
- void start_capture(struct sr_dev_inst* sdi, uint64_t record_length,
- uint64_t sample_rate);
-
- std::vector< boost::shared_ptr<Signal> >&
- get_signals();
-
- boost::shared_ptr<LogicData> get_data();
-
-private:
- void data_feed_in(const struct sr_dev_inst *sdi,
- struct sr_datafeed_packet *packet);
-
- static void data_feed_in_proc(const struct sr_dev_inst *sdi,
- struct sr_datafeed_packet *packet);
-
-private:
- std::vector< boost::shared_ptr<Signal> > _signals;
- boost::shared_ptr<LogicData> _logic_data;
- boost::shared_ptr<LogicDataSnapshot> _cur_logic_snapshot;
-
-signals:
- void data_updated();
-
-private:
- // TODO: This should not be necessary. Multiple concurrent
- // sessions should should be supported and it should be
- // possible to associate a pointer with a sr_session.
- static SigSession *_session;
-};
-
-#endif // SIGSESSION_H
#include <boost/test/unit_test.hpp>
#include "../extdef.h"
-#include "../logicdatasnapshot.h"
+#include "../pv/logicdatasnapshot.h"
using namespace std;
+using pv::LogicDataSnapshot;
+
BOOST_AUTO_TEST_SUITE(LogicDataSnapshotTest)
void push_logic(LogicDataSnapshot &s, unsigned int length, uint8_t value)