v0.4 release

This commit is contained in:
DreamSourceLab 2014-09-24 18:43:42 +08:00
parent 5d7e3237b7
commit 9eb36b33b9
170 changed files with 10539 additions and 4321 deletions

View File

@ -19,10 +19,13 @@
## along with this program. If not, see <http://www.gnu.org/licenses/>.
##
cmake_minimum_required(VERSION 2.6)
cmake_minimum_required(VERSION 2.8.6)
include(FindPkgConfig)
include(GNUInstallDirs)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMake")
project(DSLogic)
#===============================================================================
@ -31,22 +34,27 @@ project(DSLogic)
option(DISABLE_WERROR "Build without -Werror" TRUE)
option(ENABLE_SIGNALS "Build with UNIX signals" TRUE)
option(ENABLE_DECODE "Build with libsigrokdecode" TRUE)
option(ENABLE_COTIRE "Enable cotire" FALSE)
option(ENABLE_TESTS "Enable unit tests" FALSE)
option(STATIC_PKGDEPS_LIBS "Statically link to (pkgconfig) libraries" FALSE)
option(STATIC_PKGDEPS_LIBS "Statically link to (pkg-config) libraries" FALSE)
option(FORCE_QT4 "Force use of Qt4 even if Qt5 is available" FALSE)
if(WIN32)
# On Windows/MinGW we need to statically link to libraries.
# This option is user configurable, but enable it by default on win32.
set(STATIC_PKGDEPS_LIBS TRUE)
# For boost-thread we need two additional settings on win32:
set(Boost_USE_STATIC_LIBS on)
add_definitions(-DBOOST_THREAD_USE_LIB)
# Windsws does not support UNIX signals
# Windows does not support UNIX signals.
set(ENABLE_SIGNALS FALSE)
endif()
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
FORCE)
endif()
#===============================================================================
#= Dependencies
#-------------------------------------------------------------------------------
@ -55,26 +63,35 @@ list(APPEND PKGDEPS
"libsigrok4DSLogic >= 0.2.0"
"libusb-1.0 >= 1.0.16"
)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/")
if(ENABLE_DECODE)
list(APPEND PKGDEPS "libsigrokdecode>=0.3.0")
endif()
find_package(PkgConfig)
pkg_check_modules(PKGDEPS REQUIRED ${PKGDEPS})
find_package(Qt4 REQUIRED)
# Find the platform's thread library (needed for boost-thread).
# This will set ${CMAKE_THREAD_LIBS_INIT} to the correct, OS-specific value.
find_package(Threads)
if(WIN32)
# On Windows/MinGW the we need to use 'thread_win32' instead of 'thread'.
# The library is named libboost_thread_win32* (not libboost_thread*).
find_package(Boost 1.42 COMPONENTS system thread_win32 REQUIRED)
if(FORCE_QT4)
set(Qt5Core_FOUND FALSE)
else()
find_package(Boost 1.42 COMPONENTS system thread REQUIRED)
find_package(Qt5Core QUIET)
endif()
if(Qt5Core_FOUND)
message("-- Using Qt5")
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Gui REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
set(QT_INCLUDE_DIRS ${Qt5Gui_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS})
set(QT_LIBRARIES Qt5::Gui Qt5::Widgets)
add_definitions(${Qt5Gui_DEFINITIONS} ${Qt5Widgets_DEFINITIONS})
else()
find_program(QT_QMAKE_EXECUTABLE NAMES qmake4 qmake-qt4 qmake-mac)
find_package(Qt4 REQUIRED)
endif()
find_package(Threads)
find_package(Boost 1.42 COMPONENTS filesystem system thread REQUIRED)
find_package(libusb-1.0 REQUIRED)
#===============================================================================
@ -85,7 +102,7 @@ set(DS_TITLE DSLogic)
set(DS_DESCRIPTION "A GUI for DSLogic")
set(DS_VERSION_MAJOR 0)
set(DS_VERSION_MINOR 3)
set(DS_VERSION_MINOR 4)
set(DS_VERSION_MICRO 0)
set(DS_VERSION_STRING
${DS_VERSION_MAJOR}.${DS_VERSION_MINOR}.${DS_VERSION_MICRO}
@ -105,31 +122,28 @@ set(DSLogic_SOURCES
pv/devicemanager.cpp
pv/mainwindow.cpp
pv/sigsession.cpp
pv/storesession.cpp
pv/data/analog.cpp
pv/data/analogsnapshot.cpp
pv/data/dso.cpp
pv/data/dsosnapshot.cpp
pv/data/group.cpp
pv/data/groupsnapshot.cpp
pv/data/logic.cpp
pv/data/logicsnapshot.cpp
pv/data/signaldata.cpp
pv/data/snapshot.cpp
pv/data/dso.cpp
pv/data/dsosnapshot.cpp
pv/decoder/decoder.cpp
pv/decoder/decoderfactory.cpp
pv/decoder/democonfig.cpp
pv/decoder/ds1wire.cpp
pv/decoder/dsdmx512.cpp
pv/decoder/dsi2c.cpp
pv/decoder/dsserial.cpp
pv/decoder/dsspi.cpp
pv/device/devinst.cpp
pv/device/device.cpp
pv/device/file.cpp
pv/device/inputfile.cpp
pv/device/sessionfile.cpp
pv/dialogs/about.cpp
pv/dialogs/connect.cpp
pv/dialogs/deviceoptions.cpp
pv/dialogs/search.cpp
pv/dock/fakelineedit.cpp
pv/dialogs/storeprogress.cpp
pv/dock/dsotriggerdock.cpp
pv/dock/measuredock.cpp
pv/dock/protocoldock.cpp
pv/dock/searchdock.cpp
pv/dock/triggerdock.cpp
pv/prop/bool.cpp
@ -137,80 +151,116 @@ set(DSLogic_SOURCES
pv/prop/enum.cpp
pv/prop/int.cpp
pv/prop/property.cpp
pv/prop/string.cpp
pv/prop/binding/binding.cpp
pv/prop/binding/binding_deviceoptions.cpp
pv/toolbars/devicebar.cpp
pv/prop/binding/deviceoptions.cpp
pv/prop/binding/decoderoptions.cpp
pv/toolbars/filebar.cpp
pv/toolbars/logobar.cpp
pv/toolbars/samplingbar.cpp
pv/toolbars/trigbar.cpp
pv/view/analogsignal.cpp
pv/view/cursor.cpp
pv/view/devmode.cpp
pv/view/dsldial.cpp
pv/view/dsosignal.cpp
pv/view/groupsignal.cpp
pv/view/header.cpp
pv/view/logicsignal.cpp
pv/view/protocolsignal.cpp
pv/view/ruler.cpp
pv/view/selectableitem.cpp
pv/view/signal.cpp
pv/view/timemarker.cpp
pv/view/trace.cpp
pv/view/view.cpp
pv/view/viewport.cpp
pv/view/dsosignal.cpp
pv/view/dsldial.cpp
pv/dock/dsotriggerdock.cpp
pv/widgets/fakelineedit.cpp
)
set(DSLogic_HEADERS
pv/sigsession.h
pv/mainwindow.h
pv/decoder/democonfig.h
pv/dock/fakelineedit.h
pv/dock/measuredock.h
pv/dock/protocoldock.h
pv/dock/searchdock.h
pv/dock/triggerdock.h
pv/sigsession.h
pv/storesession.h
pv/device/devinst.h
pv/dialogs/about.h
pv/dialogs/connect.h
pv/dialogs/deviceoptions.h
pv/dialogs/search.h
pv/toolbars/samplingbar.h
pv/toolbars/devicebar.h
pv/dialogs/storeprogress.h
pv/dock/dsotriggerdock.h
pv/dock/measuredock.h
pv/dock/searchdock.h
pv/dock/triggerdock.h
pv/prop/bool.h
pv/prop/double.h
pv/prop/enum.h
pv/prop/int.h
pv/prop/property.h
pv/prop/string.h
pv/toolbars/filebar.h
pv/toolbars/logobar.h
pv/toolbars/samplingbar.h
pv/toolbars/trigbar.h
pv/data/dso.h
pv/data/dsosnapshot.h
pv/view/cursor.h
pv/view/devmode.h
pv/view/header.h
pv/view/ruler.h
pv/view/selectableitem.h
pv/view/timemarker.h
pv/view/groupsignal.h
pv/view/protocolsignal.h
pv/view/trace.h
pv/view/view.h
pv/view/dsosignal.h
pv/view/viewport.h
pv/view/dsldial.h
pv/dock/dsotriggerdock.h
pv/widgets/fakelineedit.h
)
set(DSLogic_FORMS
pv/dialogs/about.ui
pv/decoder/dmx512config.ui
pv/decoder/i2cconfig.ui
pv/decoder/serialconfig.ui
pv/decoder/spiconfig.ui
pv/decoder/wire1config.ui
)
set(DSLogic_RESOURCES
DSLogic.qrc
)
if(ENABLE_DECODE)
list(APPEND DSLogic_SOURCES
pv/dock/protocoldock.cpp
pv/data/decoderstack.cpp
pv/data/decode/annotation.cpp
pv/data/decode/decoder.cpp
pv/data/decode/row.cpp
pv/data/decode/rowdata.cpp
pv/prop/binding/decoderoptions.cpp
pv/view/decodetrace.cpp
pv/widgets/decodergroupbox.cpp
pv/widgets/decodermenu.cpp
)
list(APPEND DSLogic_HEADERS
pv/dock/protocoldock.h
pv/data/decoderstack.h
pv/view/decodetrace.h
pv/widgets/decodergroupbox.h
pv/widgets/decodermenu.h
)
endif()
if(WIN32)
# Use the DSLogic icon for the DSLogic.exe executable.
set(CMAKE_RC_COMPILE_OBJECT "${CMAKE_RC_COMPILER} -O coff -I${CMAKE_CURRENT_SOURCE_DIR} <SOURCE> <OBJECT>")
enable_language(RC)
list(APPEND DSLogic_SOURCES DSLogic.rc)
endif()
if(Qt5Core_FOUND)
qt5_wrap_cpp(DSLogic_HEADERS_MOC ${DSLogic_HEADERS})
qt5_wrap_ui(DSLogic_FORMS_HEADERS ${DSLogic_FORMS})
qt5_add_resources(DSLogic_RESOURCES_RCC ${DSLogic_RESOURCES})
else()
qt4_wrap_cpp(DSLogic_HEADERS_MOC ${DSLogic_HEADERS})
qt4_wrap_ui(DSLogic_FORMS_HEADERS ${DSLogic_FORMS})
qt4_add_resources(DSLogic_RESOURCES_RCC ${DSLogic_RESOURCES})
include(${QT_USE_FILE})
endif()
#===============================================================================
#= Global Definitions
@ -219,6 +269,10 @@ include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS})
add_definitions(-Wall -Wextra -Wno-return-type -Wno-ignored-qualifiers)
if(ENABLE_DECODE)
add_definitions(-DENABLE_DECODE)
endif()
if(NOT DISABLE_WERROR)
add_definitions(-Werror)
endif()
@ -231,6 +285,7 @@ include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${Boost_INCLUDE_DIRS}
${QT_INCLUDE_DIRS}
)
if(STATIC_PKGDEPS_LIBS)
@ -255,11 +310,16 @@ set(DSLOGIC_LINK_LIBS
if(STATIC_PKGDEPS_LIBS)
link_directories(${PKGDEPS_STATIC_LIBRARY_DIRS})
list(APPEND DSLOGIC_LINK_LIBS ${PKGDEPS_STATIC_LIBRARIES})
if(WIN32)
# Workaround for a MinGW linking issue.
list(APPEND PULSEVIEW_LINK_LIBS "-llzma -llcms2")
endif()
else()
link_directories(${PKGDEPS_LIBRARY_DIRS})
list(APPEND DSLOGIC_LINK_LIBS ${PKGDEPS_LIBRARIES})
endif()
add_executable(${PROJECT_NAME}
${DSLogic_SOURCES}
${DSLogic_HEADERS_MOC}
@ -273,6 +333,12 @@ if(WIN32)
# Pass -mwindows so that no "DOS box" will open when PulseView is started.
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-mwindows")
endif()
if(ENABLE_COTIRE)
include(cotire)
cotire(${PROJECT_NAME})
endif()
set_target_properties(${PROJECT_NAME} PROPERTIES INSTALL_RPATH "/usr/local/lib")
#===============================================================================
@ -282,7 +348,8 @@ set_target_properties(${PROJECT_NAME} PROPERTIES INSTALL_RPATH "/usr/local/lib")
# Install the executable.
install(TARGETS ${PROJECT_NAME} DESTINATION bin/)
install(FILES res/DSLogic.fw DESTINATION bin/res/)
install(FILES res/DSLogic.bin DESTINATION bin/res/)
install(FILES res/DSLogic33.bin DESTINATION bin/res/)
install(FILES res/DSLogic50.bin DESTINATION bin/res/)
#===============================================================================
#= Packaging (handled by CPack)

View File

@ -4,14 +4,12 @@
<file>icons/next.png</file>
<file>icons/pre.png</file>
<file>icons/file.png</file>
<file>icons/photo.png</file>
<file>icons/save.png</file>
<file>icons/open.png</file>
<file>icons/params.png</file>
<file>stylesheet.qss</file>
<file>icons/down-arrow.png</file>
<file>icons/slider-handle.png</file>
<file>icons/set.png</file>
<file>icons/add.png</file>
<file>icons/del.png</file>
<file>icons/trigger.png</file>
@ -20,14 +18,22 @@
<file>icons/protocol.png</file>
<file>icons/logo_noColor.png</file>
<file>icons/logo_color.png</file>
<file>icons/logo_muColor.png</file>
<file>icons/about.png</file>
<file>icons/capture.png</file>
<file>icons/stop.png</file>
<file>icons/start.png</file>
<file>icons/dsl_logo.png</file>
<file>icons/logo.png</file>
<file>icons/checkbox.png</file>
<file>icons/radiobutton.png</file>
<file>icons/decoder-hidden.png</file>
<file>icons/decoder-shown.png</file>
<file>icons/instant.png</file>
<file>icons/trigger_dis.png</file>
<file>icons/file_dis.png</file>
<file>icons/measure_dis.png</file>
<file>icons/protocol_dis.png</file>
<file>icons/search-bar_dis.png</file>
<file>icons/params_dis.png</file>
<file>icons/gear.png</file>
<file>icons/wiki.png</file>
</qresource>
</RCC>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 B

BIN
DSLogic-gui/icons/gear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 B

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 632 B

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 648 B

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 789 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 1007 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 978 B

BIN
DSLogic-gui/icons/wiki.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -21,7 +21,7 @@
*/
#ifdef ENABLE_SIGROKDECODE
#ifdef ENABLE_DECODE
#include <libsigrokdecode/libsigrokdecode.h> /* First, so we avoid a _POSIX_C_SOURCE warning. */
#endif
@ -33,12 +33,15 @@
#include <QtGui/QApplication>
#include <QDebug>
#include <QFile>
#include <QDir>
#include "pv/devicemanager.h"
#include "pv/mainwindow.h"
#include "config.h"
char decoders_path[256];
void usage()
{
fprintf(stdout,
@ -85,7 +88,7 @@ int main(int argc, char *argv[])
const int loglevel = atoi(optarg);
sr_log_loglevel_set(loglevel);
#ifdef ENABLE_SIGROKDECODE
#ifdef ENABLE_DECODE
srd_log_loglevel_set(loglevel);
#endif
@ -118,7 +121,12 @@ int main(int argc, char *argv[])
do {
#ifdef ENABLE_SIGROKDECODE
#ifdef ENABLE_DECODE
QDir dir(QCoreApplication::applicationDirPath());
assert(dir.cd("decoders"));
std::string str = dir.absolutePath().toStdString() + "/";
strcpy(decoders_path, str.c_str());
// Initialise libsigrokdecode
if (srd_init(NULL) != SRD_OK) {
qDebug() << "ERROR: libsigrokdecode init failed.";
@ -148,7 +156,7 @@ int main(int argc, char *argv[])
qDebug() << e.what();
}
#ifdef ENABLE_SIGROKDECODE
#ifdef ENABLE_DECODE
// Destroy libsigrokdecode
srd_exit();
#endif

View File

@ -30,11 +30,17 @@ using namespace std;
namespace pv {
namespace data {
Analog::Analog(unsigned int num_probes, uint64_t samplerate) :
SignalData(num_probes, samplerate)
Analog::Analog(unsigned int num_probes) :
SignalData(),
_num_probes(num_probes)
{
}
int Analog::get_num_probes() const
{
return _num_probes;
}
void Analog::push_snapshot(boost::shared_ptr<AnalogSnapshot> &snapshot)
{
_snapshots.push_front(snapshot);
@ -45,5 +51,10 @@ deque< boost::shared_ptr<AnalogSnapshot> >& Analog::get_snapshots()
return _snapshots;
}
void Analog::clear()
{
_snapshots.clear();
}
} // namespace data
} // namespace pv

View File

@ -37,7 +37,9 @@ class AnalogSnapshot;
class Analog : public SignalData
{
public:
Analog(unsigned int num_probes, uint64_t samplerate);
Analog(unsigned int num_probes);
int get_num_probes() const;
void push_snapshot(
boost::shared_ptr<AnalogSnapshot> &snapshot);
@ -45,7 +47,10 @@ public:
std::deque< boost::shared_ptr<AnalogSnapshot> >&
get_snapshots();
void clear();
private:
const unsigned int _num_probes;
std::deque< boost::shared_ptr<AnalogSnapshot> > _snapshots;
};

View File

@ -75,6 +75,8 @@ void AnalogSnapshot::append_payload(
const uint16_t* AnalogSnapshot::get_samples(
int64_t start_sample, int64_t end_sample) const
{
(void)end_sample;
assert(start_sample >= 0);
assert(start_sample < (int64_t)get_sample_count());
assert(end_sample >= 0);

View File

@ -0,0 +1,74 @@
/*
* 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 <libsigrokdecode/libsigrokdecode.h>
}
#include <vector>
#include <assert.h>
#include "annotation.h"
namespace pv {
namespace data {
namespace decode {
Annotation::Annotation(const srd_proto_data *const pdata) :
_start_sample(pdata->start_sample),
_end_sample(pdata->end_sample)
{
assert(pdata);
const srd_proto_data_annotation *const pda =
(const srd_proto_data_annotation*)pdata->data;
assert(pda);
_format = pda->ann_format;
const char *const *annotations = (char**)pda->ann_text;
while(*annotations) {
_annotations.push_back(QString::fromUtf8(*annotations));
annotations++;
}
}
uint64_t Annotation::start_sample() const
{
return _start_sample;
}
uint64_t Annotation::end_sample() const
{
return _end_sample;
}
int Annotation::format() const
{
return _format;
}
const std::vector<QString>& Annotation::annotations() const
{
return _annotations;
}
} // namespace decode
} // namespace data
} // namespace pv

View File

@ -0,0 +1,55 @@
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2013 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 DSLOGIC_PV_VIEW_DECODE_ANNOTATION_H
#define DSLOGIC_PV_VIEW_DECODE_ANNOTATION_H
#include <stdint.h>
#include <QString>
struct srd_proto_data;
namespace pv {
namespace data {
namespace decode {
class Annotation
{
public:
Annotation(const srd_proto_data *const pdata);
uint64_t start_sample() const;
uint64_t end_sample() const;
int format() const;
const std::vector<QString>& annotations() const;
private:
uint64_t _start_sample;
uint64_t _end_sample;
int _format;
std::vector<QString> _annotations;
};
} // namespace decode
} // namespace data
} // namespace pv
#endif // DSLOGIC_PV_VIEW_DECODE_ANNOTATION_H

View File

@ -0,0 +1,185 @@
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2013 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 <libsigrok4DSLogic/libsigrok.h>
#include <libsigrokdecode/libsigrokdecode.h>
#include "decoder.h"
#include <pv/view/logicsignal.h>
using boost::shared_ptr;
using std::set;
using std::map;
using std::string;
namespace pv {
namespace data {
namespace decode {
Decoder::Decoder(const srd_decoder *const dec) :
_decoder(dec),
_shown(true),
_shown_back(true),
_shown_setted(false),
_setted(true)
{
}
Decoder::~Decoder()
{
for (map<string, GVariant*>::const_iterator i = _options.begin();
i != _options.end(); i++)
g_variant_unref((*i).second);
}
const srd_decoder* Decoder::decoder() const
{
return _decoder;
}
bool Decoder::shown() const
{
return _shown;
}
void Decoder::show(bool show)
{
_shown_back = show;
_shown_setted = true;
}
void Decoder::commit_show()
{
if (_shown_setted) {
_shown = _shown_back;
_shown_setted = false;
}
}
const map<const srd_channel*, shared_ptr<view::LogicSignal> >&
Decoder::channels() const
{
return _probes;
}
void Decoder::set_probes(std::map<const srd_channel*,
boost::shared_ptr<view::LogicSignal> > probes)
{
_probes_back = probes;
_setted = true;
}
const std::map<std::string, GVariant*>& Decoder::options() const
{
return _options;
}
void Decoder::set_option(const char *id, GVariant *value)
{
assert(value);
g_variant_ref(value);
_options_back[id] = value;
_setted = true;
}
bool Decoder::commit()
{
if (_setted) {
_probes = _probes_back;
_options = _options_back;
_setted = false;
return true;
} else {
return false;
}
}
bool Decoder::have_required_probes() const
{
for (GSList *l = _decoder->channels; l; l = l->next) {
const srd_channel *const pdch = (const srd_channel*)l->data;
assert(pdch);
if (_probes.find(pdch) == _probes.end())
return false;
}
return true;
}
set< shared_ptr<pv::data::Logic> > Decoder::get_data()
{
set< shared_ptr<pv::data::Logic> > data;
for(map<const srd_channel*, shared_ptr<view::LogicSignal> >::
const_iterator i = _probes.begin();
i != _probes.end(); i++)
{
shared_ptr<view::LogicSignal> signal((*i).second);
assert(signal);
data.insert(signal->logic_data());
}
return data;
}
srd_decoder_inst* Decoder::create_decoder_inst(srd_session *session, int unit_size) const
{
GHashTable *const opt_hash = g_hash_table_new_full(g_str_hash,
g_str_equal, g_free, (GDestroyNotify)g_variant_unref);
for (map<string, GVariant*>::const_iterator i = _options.begin();
i != _options.end(); i++)
{
GVariant *const value = (*i).second;
g_variant_ref(value);
g_hash_table_replace(opt_hash, (void*)g_strdup(
(*i).first.c_str()), value);
}
srd_decoder_inst *const decoder_inst = srd_inst_new(
session, _decoder->id, opt_hash);
g_hash_table_destroy(opt_hash);
if(!decoder_inst)
return NULL;
// Setup the probes
GHashTable *const probes = g_hash_table_new_full(g_str_hash,
g_str_equal, g_free, (GDestroyNotify)g_variant_unref);
for(map<const srd_channel*, shared_ptr<view::LogicSignal> >::
const_iterator i = _probes.begin();
i != _probes.end(); i++)
{
shared_ptr<view::LogicSignal> signal((*i).second);
GVariant *const gvar = g_variant_new_int32(
signal->probe()->index);
g_variant_ref_sink(gvar);
g_hash_table_insert(probes, (*i).first->id, gvar);
}
srd_inst_channel_set_all(decoder_inst, probes, unit_size);
return decoder_inst;
}
} // decode
} // data
} // pv

View File

@ -0,0 +1,101 @@
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2013 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 DSLOGIC_PV_DATA_DECODE_DECODER_H
#define DSLOGIC_PV_DATA_DECODE_DECODER_H
#include <map>
#include <set>
#include <boost/shared_ptr.hpp>
#include <glib.h>
struct srd_decoder;
struct srd_decoder_inst;
struct srd_channel;
struct srd_session;
namespace pv {
namespace view {
class LogicSignal;
}
namespace data {
class Logic;
namespace decode {
class Decoder
{
public:
Decoder(const srd_decoder *const decoder);
virtual ~Decoder();
const srd_decoder* decoder() const;
bool shown() const;
void show(bool show = true);
void commit_show();
const std::map<const srd_channel*,
boost::shared_ptr<view::LogicSignal> >& channels() const;
void set_probes(std::map<const srd_channel*,
boost::shared_ptr<view::LogicSignal> > probes);
const std::map<std::string, GVariant*>& options() const;
void set_option(const char *id, GVariant *value);
bool have_required_probes() const;
srd_decoder_inst* create_decoder_inst(
srd_session *session, int unit_size) const;
std::set< boost::shared_ptr<pv::data::Logic> > get_data();
bool commit();
private:
const srd_decoder *const _decoder;
bool _shown;
bool _shown_back;
bool _shown_setted;
std::map<const srd_channel*, boost::shared_ptr<pv::view::LogicSignal> >
_probes;
std::map<std::string, GVariant*> _options;
std::map<const srd_channel*, boost::shared_ptr<pv::view::LogicSignal> >
_probes_back;
std::map<std::string, GVariant*> _options_back;
bool _setted;
};
} // namespace decode
} // namespace data
} // namespace pv
#endif // DSLOGIC_PV_DATA_DECODE_DECODER_H

View File

@ -0,0 +1,72 @@
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2014 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 "row.h"
#include <libsigrokdecode/libsigrokdecode.h>
namespace pv {
namespace data {
namespace decode {
Row::Row() :
_decoder(NULL),
_row(NULL)
{
}
Row::Row(const srd_decoder *decoder, const srd_decoder_annotation_row *row) :
_decoder(decoder),
_row(row)
{
}
const srd_decoder* Row::decoder() const
{
return _decoder;
}
const srd_decoder_annotation_row* Row::row() const
{
return _row;
}
const QString Row::title() const
{
if (_decoder && _decoder->name && _row && _row->desc)
return QString("%1: %2")
.arg(QString::fromUtf8(_decoder->name))
.arg(QString::fromUtf8(_row->desc));
if (_decoder && _decoder->name)
return QString::fromUtf8(_decoder->name);
if (_row && _row->desc)
return QString::fromUtf8(_row->desc);
return QString();
}
bool Row::operator<(const Row &other) const
{
return (_decoder < other._decoder) ||
(_decoder == other._decoder && _row < other._row);
}
} // decode
} // data
} // pv

View File

@ -0,0 +1,59 @@
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2014 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 DSLOGIC_PV_DATA_DECODE_ROW_H
#define DSLOGIC_PV_DATA_DECODE_ROW_H
#include <vector>
#include "annotation.h"
struct srd_decoder;
struct srd_decoder_annotation_row;
namespace pv {
namespace data {
namespace decode {
class Row
{
public:
Row();
Row(const srd_decoder *decoder,
const srd_decoder_annotation_row *row = NULL);
const srd_decoder* decoder() const;
const srd_decoder_annotation_row* row() const;
const QString title() const;
bool operator<(const Row &other) const;
private:
const srd_decoder *_decoder;
const srd_decoder_annotation_row *_row;
};
} // decode
} // data
} // pv
#endif // DSLOGIC_PV_DATA_DECODE_ROW_H

View File

@ -0,0 +1,68 @@
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2014 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 "rowdata.h"
using std::max;
using std::vector;
namespace pv {
namespace data {
namespace decode {
RowData::RowData() :
_max_annotation(0)
{
}
uint64_t RowData::get_max_sample() const
{
if (_annotations.empty())
return 0;
return _annotations.back().end_sample();
}
uint64_t RowData::get_max_annotation() const
{
return _max_annotation;
}
void RowData::get_annotation_subset(
vector<pv::data::decode::Annotation> &dest,
uint64_t start_sample, uint64_t end_sample) const
{
for (vector<Annotation>::const_iterator i = _annotations.begin();
i != _annotations.end(); i++)
if ((*i).end_sample() > start_sample &&
(*i).start_sample() <= end_sample)
dest.push_back(*i);
}
void RowData::push_annotation(const Annotation &a)
{
_annotations.push_back(a);
_max_annotation = max(_max_annotation, a.end_sample() - a.start_sample());
}
} // decode
} // data
} // pv

View File

@ -0,0 +1,59 @@
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2014 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 DSLOGIC_PV_DATA_DECODE_ROWDATA_H
#define DSLOGIC_PV_DATA_DECODE_ROWDATA_H
#include <vector>
#include "annotation.h"
namespace pv {
namespace data {
namespace decode {
class RowData
{
public:
RowData();
public:
uint64_t get_max_sample() const;
uint64_t get_max_annotation() const;
/**
* Extracts sorted annotations between two period into a vector.
*/
void get_annotation_subset(
std::vector<pv::data::decode::Annotation> &dest,
uint64_t start_sample, uint64_t end_sample) const;
void push_annotation(const Annotation &a);
private:
uint64_t _max_annotation;
std::vector<Annotation> _annotations;
};
}
} // data
} // pv
#endif // DSLOGIC_PV_DATA_DECODE_ROWDATA_H

View File

@ -0,0 +1,526 @@
/*
* 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 <libsigrokdecode/libsigrokdecode.h>
#include <boost/foreach.hpp>
#include <boost/thread/thread.hpp>
#include <stdexcept>
#include <QDebug>
#include "decoderstack.h"
#include <pv/data/logic.h>
#include <pv/data/logicsnapshot.h>
#include <pv/data/decode/decoder.h>
#include <pv/data/decode/annotation.h>
#include <pv/sigsession.h>
#include <pv/view/logicsignal.h>
using boost::lock_guard;
using boost::mutex;
using boost::optional;
using boost::shared_ptr;
using boost::unique_lock;
using std::deque;
using std::make_pair;
using std::max;
using std::min;
using std::list;
using std::map;
using std::pair;
using std::vector;
using namespace pv::data::decode;
namespace pv {
namespace data {
const double DecoderStack::DecodeMargin = 1.0;
const double DecoderStack::DecodeThreshold = 0.2;
const int64_t DecoderStack::DecodeChunkLength = 1024 * 1024;
const unsigned int DecoderStack::DecodeNotifyPeriod = 1;
mutex DecoderStack::_global_decode_mutex;
DecoderStack::DecoderStack(pv::SigSession &session,
const srd_decoder *const dec) :
_session(session),
_sample_count(0),
_frame_complete(false),
_samples_decoded(0),
_decode_state(Stopped),
_options_changed(false)
{
connect(&_session, SIGNAL(frame_began()),
this, SLOT(on_new_frame()));
connect(&_session, SIGNAL(data_received()),
this, SLOT(on_data_received()));
connect(&_session, SIGNAL(frame_ended()),
this, SLOT(on_frame_ended()));
_stack.push_back(shared_ptr<decode::Decoder>(
new decode::Decoder(dec)));
}
DecoderStack::~DecoderStack()
{
// if (_decode_thread.joinable()) {
// _decode_thread.interrupt();
// _decode_thread.join();
// }
stop_decode();
}
const std::list< boost::shared_ptr<decode::Decoder> >&
DecoderStack::stack() const
{
return _stack;
}
void DecoderStack::push(boost::shared_ptr<decode::Decoder> decoder)
{
assert(decoder);
_stack.push_back(decoder);
}
void DecoderStack::remove(int index)
{
assert(index >= 0);
assert(index < (int)_stack.size());
// Find the decoder in the stack
list< shared_ptr<Decoder> >::iterator iter = _stack.begin();
for(int i = 0; i < index; i++, iter++)
assert(iter != _stack.end());
// Delete the element
_stack.erase(iter);
}
int64_t DecoderStack::samples_decoded() const
{
lock_guard<mutex> decode_lock(_output_mutex);
return _samples_decoded;
}
std::vector< std::pair<decode::Row, bool> > DecoderStack::get_visible_rows() const
{
lock_guard<mutex> lock(_output_mutex);
std::vector< std::pair<decode::Row, bool> > rows;
BOOST_FOREACH (const shared_ptr<decode::Decoder> &dec, _stack)
{
assert(dec);
const srd_decoder *const decc = dec->decoder();
assert(dec->decoder());
// Add a row for the decoder if it doesn't have a row list
if (!decc->annotation_rows)
rows.push_back(make_pair(Row(decc), dec->shown()));
// Add the decoder rows
for (const GSList *l = decc->annotation_rows; l; l = l->next)
{
const srd_decoder_annotation_row *const ann_row =
(srd_decoder_annotation_row *)l->data;
assert(ann_row);
rows.push_back(make_pair(Row(decc, ann_row), dec->shown()));
}
}
return rows;
}
void DecoderStack::get_annotation_subset(
std::vector<pv::data::decode::Annotation> &dest,
const Row &row, uint64_t start_sample,
uint64_t end_sample) const
{
lock_guard<mutex> lock(_output_mutex);
std::map<const Row, decode::RowData>::const_iterator iter =
_rows.find(row);
if (iter != _rows.end())
(*iter).second.get_annotation_subset(dest,
start_sample, end_sample);
}
uint64_t DecoderStack::get_max_annotation(const Row &row)
{
lock_guard<mutex> lock(_output_mutex);
std::map<const Row, decode::RowData>::const_iterator iter =
_rows.find(row);
if (iter != _rows.end())
return (*iter).second.get_max_annotation();
return 0;
}
bool DecoderStack::has_annotations(const Row &row) const
{
lock_guard<mutex> lock(_output_mutex);
std::map<const Row, decode::RowData>::const_iterator iter =
_rows.find(row);
if (iter != _rows.end())
if(0 == (*iter).second.get_max_sample())
return false;
else
return true;
else
return false;
}
QString DecoderStack::error_message()
{
lock_guard<mutex> lock(_output_mutex);
return _error_message;
}
void DecoderStack::clear()
{
_sample_count = 0;
_frame_complete = false;
_samples_decoded = 0;
_error_message = QString();
_rows.clear();
_class_rows.clear();
}
void DecoderStack::stop_decode()
{
if(_decode_state == Stopped)
return;
if (_decode_thread.get()) {
_decode_thread->interrupt();
_decode_thread->join();
_decode_state = Stopped;
}
_decode_thread.reset();
}
void DecoderStack::begin_decode()
{
shared_ptr<pv::view::LogicSignal> logic_signal;
shared_ptr<pv::data::Logic> data;
if (!_options_changed)
return;
// if (_decode_thread.joinable()) {
// _decode_thread.interrupt();
// _decode_thread.join();
// }
stop_decode();
clear();
// Check that all decoders have the required channels
BOOST_FOREACH(const shared_ptr<decode::Decoder> &dec, _stack)
if (!dec->have_required_probes()) {
_error_message = tr("One or more required channels "
"have not been specified");
return;
}
// Add classes
BOOST_FOREACH (const shared_ptr<decode::Decoder> &dec, _stack)
{
assert(dec);
const srd_decoder *const decc = dec->decoder();
assert(dec->decoder());
// Add a row for the decoder if it doesn't have a row list
if (!decc->annotation_rows)
_rows[Row(decc)] = decode::RowData();
// Add the decoder rows
for (const GSList *l = decc->annotation_rows; l; l = l->next)
{
const srd_decoder_annotation_row *const ann_row =
(srd_decoder_annotation_row *)l->data;
assert(ann_row);
const Row row(decc, ann_row);
// Add a new empty row data object
_rows[row] = decode::RowData();
// Map out all the classes
for (const GSList *ll = ann_row->ann_classes;
ll; ll = ll->next)
_class_rows[make_pair(decc,
GPOINTER_TO_INT(ll->data))] = row;
}
}
// We get the logic data of the first channel in the list.
// This works because we are currently assuming all
// LogicSignals have the same data/snapshot
BOOST_FOREACH (const shared_ptr<decode::Decoder> &dec, _stack)
if (dec && !dec->channels().empty() &&
((logic_signal = (*dec->channels().begin()).second)) &&
((data = logic_signal->logic_data())))
break;
if (!data)
return;
// Check we have a snapshot of data
const deque< shared_ptr<pv::data::LogicSnapshot> > &snapshots =
data->get_snapshots();
if (snapshots.empty())
return;
_snapshot = snapshots.front();
// Get the samplerate and start time
_start_time = data->get_start_time();
_samplerate = data->samplerate();
if (_samplerate == 0.0)
_samplerate = 1.0;
//_decode_thread = boost::thread(&DecoderStack::decode_proc, this);
_decode_thread.reset(new boost::thread(&DecoderStack::decode_proc, this));
}
uint64_t DecoderStack::get_max_sample_count() const
{
uint64_t max_sample_count = 0;
for (map<const Row, RowData>::const_iterator i = _rows.begin();
i != _rows.end(); i++)
max_sample_count = max(max_sample_count,
(*i).second.get_max_sample());
return max_sample_count;
}
boost::optional<uint64_t> DecoderStack::wait_for_data() const
{
unique_lock<mutex> input_lock(_input_mutex);
while(!boost::this_thread::interruption_requested() &&
!_frame_complete && (uint64_t)_samples_decoded >= _sample_count)
_input_cond.wait(input_lock);
return boost::make_optional(
!boost::this_thread::interruption_requested() &&
((uint64_t)_samples_decoded < _sample_count || !_frame_complete),
_sample_count);
}
void DecoderStack::decode_data(
const uint64_t sample_count, const unsigned int unit_size,
srd_session *const session)
{
//uint8_t chunk[DecodeChunkLength];
uint8_t *chunk = NULL;
chunk = (uint8_t *)realloc(chunk, DecodeChunkLength);
const uint64_t chunk_sample_count =
DecodeChunkLength / _snapshot->unit_size();
for (uint64_t i = 0;
!boost::this_thread::interruption_requested() &&
i < sample_count;
i += chunk_sample_count)
{
//lock_guard<mutex> decode_lock(_global_decode_mutex);
const uint64_t chunk_end = min(
i + chunk_sample_count, sample_count);
_snapshot->get_samples(chunk, i, chunk_end);
if (srd_session_send(session, i, i + sample_count, chunk,
(chunk_end - i) * unit_size) != SRD_OK) {
_error_message = tr("Decoder reported an error");
break;
}
{
lock_guard<mutex> lock(_output_mutex);
_samples_decoded = chunk_end;
}
if (i % DecodeNotifyPeriod == 0)
new_decode_data();
}
_options_changed = false;
decode_done();
//new_decode_data();
}
void DecoderStack::decode_proc()
{
lock_guard<mutex> decode_lock(_global_decode_mutex);
optional<uint64_t> sample_count;
srd_session *session;
srd_decoder_inst *prev_di = NULL;
assert(_snapshot);
// Create the session
srd_session_new(&session);
assert(session);
_decode_state = Running;
// Create the decoders
const unsigned int unit_size = _snapshot->unit_size();
BOOST_FOREACH(const shared_ptr<decode::Decoder> &dec, _stack)
{
srd_decoder_inst *const di = dec->create_decoder_inst(session, unit_size);
if (!di)
{
_error_message = tr("Failed to create decoder instance");
srd_session_destroy(session);
return;
}
if (prev_di)
srd_inst_stack (session, prev_di, di);
prev_di = di;
}
// Get the intial sample count
{
unique_lock<mutex> input_lock(_input_mutex);
sample_count = _sample_count = _snapshot->get_sample_count();
}
// Start the session
srd_session_metadata_set(session, SRD_CONF_SAMPLERATE,
g_variant_new_uint64((uint64_t)_samplerate));
srd_pd_output_callback_add(session, SRD_OUTPUT_ANN,
DecoderStack::annotation_callback, this);
srd_session_start(session);
// do {
// decode_data(*sample_count, unit_size, session);
// } while(_error_message.isEmpty() && (sample_count = wait_for_data()));
decode_data(*sample_count, unit_size, session);
// Destroy the session
srd_session_destroy(session);
_decode_state = Stopped;
}
void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder)
{
assert(pdata);
assert(decoder);
DecoderStack *const d = (DecoderStack*)decoder;
assert(d);
lock_guard<mutex> lock(d->_output_mutex);
const Annotation a(pdata);
// Find the row
assert(pdata->pdo);
assert(pdata->pdo->di);
const srd_decoder *const decc = pdata->pdo->di->decoder;
assert(decc);
map<const Row, decode::RowData>::iterator row_iter = d->_rows.end();
// Try looking up the sub-row of this class
const map<pair<const srd_decoder*, int>, Row>::const_iterator r =
d->_class_rows.find(make_pair(decc, a.format()));
if (r != d->_class_rows.end())
row_iter = d->_rows.find((*r).second);
else
{
// Failing that, use the decoder as a key
row_iter = d->_rows.find(Row(decc));
}
assert(row_iter != d->_rows.end());
if (row_iter == d->_rows.end()) {
qDebug() << "Unexpected annotation: decoder = " << decc <<
", format = " << a.format();
assert(0);
return;
}
// Add the annotation
(*row_iter).second.push_annotation(a);
}
void DecoderStack::on_new_frame()
{
//begin_decode();
}
void DecoderStack::on_data_received()
{
// {
// unique_lock<mutex> lock(_input_mutex);
// if (_snapshot)
// _sample_count = _snapshot->get_sample_count();
// }
// _input_cond.notify_one();
}
void DecoderStack::on_frame_ended()
{
// {
// unique_lock<mutex> lock(_input_mutex);
// if (_snapshot)
// _frame_complete = true;
// }
// _input_cond.notify_one();
_options_changed = true;
begin_decode();
}
int DecoderStack::cur_rows_size()
{
int rows_size = 0;
for (map<const Row, RowData>::const_iterator i = _rows.begin();
i != _rows.end(); i++)
if ((*i).second.get_max_sample() != 0)
rows_size++;
if (rows_size == 0)
return 1;
else
return rows_size;
}
void DecoderStack::options_changed(bool changed)
{
_options_changed = changed;
}
} // namespace data
} // namespace pv

View File

@ -0,0 +1,185 @@
/*
* 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 DSLOGIC_PV_DATA_DECODERSTACK_H
#define DSLOGIC_PV_DATA_DECODERSTACK_H
#include "signaldata.h"
#include <list>
#include <boost/optional.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <QObject>
#include <QString>
#include <pv/data/decode/row.h>
#include <pv/data/decode/rowdata.h>
struct srd_decoder;
struct srd_decoder_annotation_row;
struct srd_channel;
struct srd_proto_data;
struct srd_session;
namespace DecoderStackTest {
class TwoDecoderStack;
}
namespace pv {
class SigSession;
namespace view {
class LogicSignal;
}
namespace data {
class LogicSnapshot;
namespace decode {
class Annotation;
class Decoder;
}
class Logic;
class DecoderStack : public QObject, public SignalData
{
Q_OBJECT
private:
static const double DecodeMargin;
static const double DecodeThreshold;
static const int64_t DecodeChunkLength;
static const unsigned int DecodeNotifyPeriod;
public:
enum decode_state {
Stopped,
Running
};
public:
DecoderStack(pv::SigSession &_session,
const srd_decoder *const decoder);
virtual ~DecoderStack();
const std::list< boost::shared_ptr<decode::Decoder> >& stack() const;
void push(boost::shared_ptr<decode::Decoder> decoder);
void remove(int index);
int64_t samples_decoded() const;
std::vector< std::pair<decode::Row, bool> > get_visible_rows() const;
/**
* Extracts sorted annotations between two period into a vector.
*/
void get_annotation_subset(
std::vector<pv::data::decode::Annotation> &dest,
const decode::Row &row, uint64_t start_sample,
uint64_t end_sample) const;
uint64_t get_max_annotation(const decode::Row &row);
bool has_annotations(const decode::Row &row) const;
QString error_message();
void clear();
uint64_t get_max_sample_count() const;
void begin_decode();
void stop_decode();
int cur_rows_size();
void options_changed(bool changed);
private:
boost::optional<uint64_t> wait_for_data() const;
void decode_data(const uint64_t sample_count,
const unsigned int unit_size, srd_session *const session);
void decode_proc();
static void annotation_callback(srd_proto_data *pdata,
void *decoder);
private slots:
void on_new_frame();
void on_data_received();
void on_frame_ended();
signals:
void new_decode_data();
void decode_done();
private:
pv::SigSession &_session;
/**
* This mutex prevents more than one decode operation occuring
* concurrently.
* @todo A proper solution should be implemented to allow multiple
* decode operations.
*/
static boost::mutex _global_decode_mutex;
std::list< boost::shared_ptr<decode::Decoder> > _stack;
boost::shared_ptr<pv::data::LogicSnapshot> _snapshot;
mutable boost::mutex _input_mutex;
mutable boost::condition_variable _input_cond;
uint64_t _sample_count;
bool _frame_complete;
mutable boost::mutex _output_mutex;
int64_t _samples_decoded;
std::map<const decode::Row, decode::RowData> _rows;
std::map<std::pair<const srd_decoder*, int>, decode::Row> _class_rows;
QString _error_message;
std::auto_ptr<boost::thread> _decode_thread;
decode_state _decode_state;
bool _options_changed;
friend class DecoderStackTest::TwoDecoderStack;
};
} // namespace data
} // namespace pv
#endif // DSLOGIC_PV_DATA_DECODERSTACK_H

View File

@ -29,8 +29,8 @@ using namespace std;
namespace pv {
namespace data {
Dso::Dso(unsigned int num_probes, uint64_t samplerate) :
SignalData(num_probes, samplerate)
Dso::Dso(int num_probes) :
SignalData(num_probes)
{
}
@ -44,5 +44,10 @@ deque< boost::shared_ptr<DsoSnapshot> >& Dso::get_snapshots()
return _snapshots;
}
void Dso::clear()
{
_snapshots.clear();
}
} // namespace data
} // namespace pv

View File

@ -36,7 +36,7 @@ class DsoSnapshot;
class Dso : public SignalData
{
public:
Dso(unsigned int num_probes, uint64_t samplerate);
Dso(int num_probes);
void push_snapshot(
boost::shared_ptr<DsoSnapshot> &snapshot);
@ -44,6 +44,8 @@ public:
std::deque< boost::shared_ptr<DsoSnapshot> >&
get_snapshots();
void clear();
private:
std::deque< boost::shared_ptr<DsoSnapshot> > _snapshots;
};

View File

@ -73,6 +73,8 @@ void DsoSnapshot::append_payload(const sr_datafeed_dso &dso)
const uint8_t *DsoSnapshot::get_samples(
int64_t start_sample, int64_t end_sample, uint16_t index) const
{
(void)end_sample;
assert(start_sample >= 0);
assert(start_sample < (int64_t)get_sample_count());
assert(end_sample >= 0);

View File

@ -30,8 +30,8 @@ using namespace std;
namespace pv {
namespace data {
Group::Group(unsigned int num_probes, uint64_t samplerate) :
SignalData(num_probes, samplerate)
Group::Group() :
SignalData()
{
}
@ -45,5 +45,10 @@ deque< boost::shared_ptr<GroupSnapshot> >& Group::get_snapshots()
return _snapshots;
}
void Group::clear()
{
_snapshots.clear();
}
} // namespace data
} // namespace pv

View File

@ -37,7 +37,7 @@ class GroupSnapshot;
class Group : public SignalData
{
public:
Group(unsigned int num_probes, uint64_t samplerate);
Group();
void push_snapshot(
boost::shared_ptr<GroupSnapshot> &snapshot);
@ -45,6 +45,8 @@ public:
std::deque< boost::shared_ptr<GroupSnapshot> >&
get_snapshots();
void clear();
private:
std::deque< boost::shared_ptr<GroupSnapshot> > _snapshots;
};

View File

@ -59,7 +59,7 @@ GroupSnapshot::GroupSnapshot(const boost::shared_ptr<LogicSnapshot> &_logic_snap
memset(_envelope_levels, 0, sizeof(_envelope_levels));
_data = _logic_snapshot->get_data();
_sample_count = _logic_snapshot->get_sample_count();
_unit_size = _logic_snapshot->get_unit_size();
_unit_size = _logic_snapshot->unit_size();
_index_list = index_list;
append_payload();
}

View File

@ -30,10 +30,9 @@ using namespace std;
namespace pv {
namespace data {
Logic::Logic(unsigned int num_probes, uint64_t samplerate) :
SignalData(num_probes, samplerate)
Logic::Logic(int num_probes) :
SignalData(num_probes)
{
assert(_num_probes > 0);
}
void Logic::push_snapshot(
@ -47,5 +46,10 @@ deque< boost::shared_ptr<LogicSnapshot> >& Logic::get_snapshots()
return _snapshots;
}
void Logic::clear()
{
_snapshots.clear();
}
} // namespace data
} // namespace pv

View File

@ -37,7 +37,9 @@ class LogicSnapshot;
class Logic : public SignalData
{
public:
Logic(unsigned int num_probes, uint64_t samplerate);
Logic(int num_probes);
int get_num_probes() const;
void push_snapshot(
boost::shared_ptr<LogicSnapshot> &snapshot);
@ -45,6 +47,8 @@ public:
std::deque< boost::shared_ptr<LogicSnapshot> >&
get_snapshots();
void clear();
private:
std::deque< boost::shared_ptr<LogicSnapshot> > _snapshots;
};

View File

@ -74,6 +74,22 @@ void LogicSnapshot::append_payload(
append_payload_to_mipmap();
}
void LogicSnapshot::get_samples(uint8_t *const data,
int64_t start_sample, int64_t end_sample) const
{
assert(data);
assert(start_sample >= 0);
assert(start_sample <= (int64_t)_sample_count);
assert(end_sample >= 0);
assert(end_sample <= (int64_t)_sample_count);
assert(start_sample <= end_sample);
//lock_guard<recursive_mutex> lock(_mutex);
const size_t size = (end_sample - start_sample) * _unit_size;
memcpy(data, (const uint8_t*)_data + start_sample * _unit_size, size);
}
void LogicSnapshot::reallocate_mipmap_level(MipMapLevel &m)
{
const uint64_t new_data_length = ((m.length + MipMapDataUnit - 1) /
@ -170,14 +186,6 @@ void LogicSnapshot::append_payload_to_mipmap()
}
}
uint64_t LogicSnapshot::get_sample(uint64_t index) const
{
assert(_data);
assert(index < _sample_count);
return *(uint64_t*)((uint8_t*)_data + index * _unit_size);
}
void LogicSnapshot::get_subsampled_edges(
std::vector<EdgePair> &edges,
uint64_t start, uint64_t end,
@ -194,6 +202,9 @@ void LogicSnapshot::get_subsampled_edges(
assert(sig_index >= 0);
assert(sig_index < 64);
if (!_data)
return;
boost::lock_guard<boost::recursive_mutex> lock(_mutex);
const uint64_t block_length = (uint64_t)max(min_length, 1.0f);

View File

@ -67,7 +67,8 @@ public:
void append_payload(const sr_datafeed_logic &logic);
uint64_t get_sample(uint64_t index) const;
void get_samples(uint8_t *const data,
int64_t start_sample, int64_t end_sample) const;
private:
void reallocate_mipmap_level(MipMapLevel &m);

View File

@ -20,33 +20,48 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <assert.h>
#include "signaldata.h"
namespace pv {
namespace data {
SignalData::SignalData(unsigned int num_probes, double samplerate) :
_num_probes(num_probes),
_samplerate(samplerate),
_start_time(0)
SignalData::SignalData(int num_probes) :
_samplerate(0),
_start_time(0),
_num_probes(num_probes)
{
assert(num_probes >= 0);
}
int SignalData::get_num_probes() const
{
return _num_probes;
}
double SignalData::get_samplerate() const
double SignalData::samplerate() const
{
return _samplerate;
}
void SignalData::set_samplerate(double samplerate)
{
assert(samplerate > 0);
_samplerate = samplerate;
clear();
}
double SignalData::get_start_time() const
{
return _start_time;
}
int SignalData::get_num_probes() const
{
return _num_probes;
}
void SignalData::set_num_probes(int num)
{
assert(num >= 0);
_num_probes = num;
}
} // namespace data
} // namespace pv

View File

@ -32,17 +32,24 @@ namespace data {
class SignalData
{
public:
SignalData(unsigned int num_probes, double samplerate);
SignalData(int num_probes = 1);
public:
double get_samplerate() const;
double samplerate() const;
void set_samplerate(double samplerate);
virtual void clear() = 0;
double get_start_time() const;
int get_num_probes() const;
void set_num_probes(int num);
protected:
const unsigned int _num_probes;
const double _samplerate;
const double _start_time;
double _samplerate;
double _start_time;
int _num_probes;
};
} // namespace data

View File

@ -54,6 +54,7 @@ Snapshot::~Snapshot()
int Snapshot::init(uint64_t _total_sample_len)
{
boost::lock_guard<boost::recursive_mutex> lock(_mutex);
_data = malloc(_total_sample_len * _unit_size +
sizeof(uint64_t));
@ -83,7 +84,7 @@ void* Snapshot::get_data() const
return _data;
}
int Snapshot::get_unit_size() const
int Snapshot::unit_size() const
{
boost::lock_guard<boost::recursive_mutex> lock(_mutex);
return _unit_size;
@ -95,6 +96,16 @@ unsigned int Snapshot::get_channel_num() const
return _channel_num;
}
uint64_t Snapshot::get_sample(uint64_t index) const
{
boost::lock_guard<boost::recursive_mutex> lock(_mutex);
assert(_data);
assert(index < _sample_count);
return *(uint64_t*)((uint8_t*)_data + index * _unit_size);
}
void Snapshot::append_data(void *data, uint64_t samples)
{
// boost::lock_guard<boost::recursive_mutex> lock(_mutex);

View File

@ -44,12 +44,14 @@ public:
void * get_data() const;
int get_unit_size() const;
int unit_size() const;
bool buf_null() const;
unsigned int get_channel_num() const;
uint64_t get_sample(uint64_t index) const;
protected:
void append_data(void *data, uint64_t samples);

View File

@ -0,0 +1,105 @@
/*
* This file is part of the DSLogic-gui project.
* DSLogic-gui is based on PulseView.
*
* Copyright (C) 2014 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 <sstream>
#include <libsigrok4DSLogic/libsigrok.h>
#include "device.h"
using std::ostringstream;
using std::string;
namespace pv {
namespace device {
Device::Device(sr_dev_inst *sdi) :
_sdi(sdi)
{
assert(_sdi);
}
sr_dev_inst* Device::dev_inst() const
{
return _sdi;
}
void Device::use(SigSession *owner) throw(QString)
{
DevInst::use(owner);
sr_session_new();
assert(_sdi);
sr_dev_open(_sdi);
if (sr_session_dev_add(_sdi) != SR_OK)
throw QString(tr("Failed to use device."));
}
void Device::release()
{
if (_owner) {
DevInst::release();
sr_session_destroy();
}
sr_dev_close(_sdi);
}
std::string Device::format_device_title() const
{
ostringstream s;
assert(_sdi);
if (_sdi->vendor && _sdi->vendor[0]) {
s << _sdi->vendor;
if ((_sdi->model && _sdi->model[0]) ||
(_sdi->version && _sdi->version[0]))
s << ' ';
}
if (_sdi->model && _sdi->model[0]) {
s << _sdi->model;
if (_sdi->version && _sdi->version[0])
s << ' ';
}
if (_sdi->version && _sdi->version[0])
s << _sdi->version;
return s.str();
}
bool Device::is_trigger_enabled() const
{
assert(_sdi);
for (const GSList *l = _sdi->channels; l; l = l->next) {
const sr_channel *const p = (const sr_channel *)l->data;
assert(p);
if (p->trigger && p->trigger[0] != '\0')
return true;
}
return false;
}
} // device
} // pv

View File

@ -0,0 +1,52 @@
/*
* This file is part of the DSLogic-gui project.
* DSLogic-gui is based on PulseView.
*
* Copyright (C) 2014 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 DSLOGIC_PV_DEVICE_DEVICE_H
#define DSLOGIC_PV_DEVICE_DEVICE_H
#include "devinst.h"
namespace pv {
namespace device {
class Device : public DevInst
{
public:
Device(sr_dev_inst *dev_inst);
sr_dev_inst* dev_inst() const;
void use(SigSession *owner) throw(QString);
void release();
std::string format_device_title() const;
bool is_trigger_enabled() const;
private:
sr_dev_inst *const _sdi;
};
} // device
} // pv
#endif // DSLOGIC_PV_DEVICE_DEVICE_H

View File

@ -0,0 +1,203 @@
/*
* This file is part of the DSLogic-gui project.
* DSLogic-gui is based on PulseView.
*
* Copyright (C) 2014 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 <cassert>
#include <QDebug>
#include <libsigrok4DSLogic/libsigrok.h>
#include "devinst.h"
#include <pv/sigsession.h>
namespace pv {
namespace device {
DevInst::DevInst() :
_owner(NULL)
{
_id = malloc(1);
}
DevInst::~DevInst()
{
assert(_id);
free(_id);
}
void* DevInst::get_id() const
{
assert(_id);
return _id;
}
void DevInst::use(SigSession *owner) throw(QString)
{
assert(owner);
assert(!_owner);
_owner = owner;
}
void DevInst::release()
{
if (_owner) {
_owner->release_device(this);
_owner = NULL;
}
}
SigSession* DevInst::owner() const
{
return _owner;
}
GVariant* DevInst::get_config(const sr_channel *ch, const sr_channel_group *group, int key)
{
GVariant *data = NULL;
assert(_owner);
sr_dev_inst *const sdi = dev_inst();
assert(sdi);
if (sr_config_get(sdi->driver, sdi, ch, group, key, &data) != SR_OK)
return NULL;
return data;
}
bool DevInst::set_config(const sr_channel *ch, const sr_channel_group *group, int key, GVariant *data)
{
assert(_owner);
sr_dev_inst *const sdi = dev_inst();
assert(sdi);
if(sr_config_set(sdi, ch, group, key, data) == SR_OK) {
config_changed();
return true;
}
return false;
}
GVariant* DevInst::list_config(const sr_channel_group *group, int key)
{
GVariant *data = NULL;
assert(_owner);
sr_dev_inst *const sdi = dev_inst();
assert(sdi);
if (sr_config_list(sdi->driver, sdi, group, key, &data) != SR_OK)
return NULL;
return data;
}
void DevInst::enable_probe(const sr_channel *probe, bool enable)
{
assert(_owner);
sr_dev_inst *const sdi = dev_inst();
assert(sdi);
for (const GSList *p = sdi->channels; p; p = p->next)
if (probe == p->data) {
const_cast<sr_channel*>(probe)->enabled = enable;
config_changed();
return;
}
// Probe was not found in the device
assert(0);
}
uint64_t DevInst::get_sample_limit()
{
uint64_t sample_limit;
GVariant* gvar = get_config(NULL, NULL, SR_CONF_LIMIT_SAMPLES);
if (gvar != NULL) {
sample_limit = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
} else {
sample_limit = 0U;
}
return sample_limit;
}
uint64_t DevInst::get_sample_rate()
{
uint64_t sample_rate;
GVariant* gvar = get_config(NULL, NULL, SR_CONF_SAMPLERATE);
if (gvar != NULL) {
sample_rate = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
} else {
sample_rate = 0U;
}
return sample_rate;
}
uint64_t DevInst::get_time_base()
{
uint64_t time_base;
GVariant* gvar = get_config(NULL, NULL, SR_CONF_TIMEBASE);
if (gvar != NULL) {
time_base = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
} else {
time_base = 0U;
}
return time_base;
}
double DevInst::get_sample_time()
{
uint64_t sample_rate = get_sample_rate();
uint64_t sample_limit = get_sample_limit();
double sample_time;
if (sample_rate == 0)
sample_time = 0;
else
sample_time = sample_limit * 1.0f / sample_rate;
return sample_time;
}
GSList* DevInst::get_dev_mode_list()
{
assert(_owner);
sr_dev_inst *const sdi = dev_inst();
assert(sdi);
return sr_dev_mode_list(sdi->driver);
}
bool DevInst::is_trigger_enabled() const
{
return false;
}
void DevInst::start()
{
if (sr_session_start() != SR_OK)
throw tr("Failed to start session.");
}
void DevInst::run()
{
sr_session_run();
}
} // device
} // pv

View File

@ -0,0 +1,132 @@
/*
* This file is part of the DSLogic-gui project.
* DSLogic-gui is based on PulseView.
*
* Copyright (C) 2014 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 DSLOGIC_PV_DEVICE_DEVINST_H
#define DSLOGIC_PV_DEVICE_DEVINST_H
#include <string>
#include <boost/shared_ptr.hpp>
#include <QObject>
#include <glib.h>
#include <stdint.h>
struct sr_dev_inst;
struct sr_channel;
struct sr_channel_group;
namespace pv {
class SigSession;
namespace device {
class DevInst : public QObject
{
Q_OBJECT
protected:
DevInst();
~DevInst();
public:
virtual sr_dev_inst* dev_inst() const = 0;
virtual void use(SigSession *owner) throw(QString);
virtual void release();
SigSession* owner() const;
virtual std::string format_device_title() const = 0;
GVariant* get_config(const sr_channel *ch, const sr_channel_group *group, int key);
bool set_config(const sr_channel *ch, const sr_channel_group *group, int key, GVariant *data);
GVariant* list_config(const sr_channel_group *group, int key);
void enable_probe(const sr_channel *probe, bool enable = true);
/**
* @brief Gets the sample limit from the driver.
*
* @return The returned sample limit from the driver, or 0 if the
* sample limit could not be read.
*/
uint64_t get_sample_limit();
/**
* @brief Gets the sample rate from the driver.
*
* @return The returned sample rate from the driver, or 0 if the
* sample rate could not be read.
*/
uint64_t get_sample_rate();
/**
* @brief Gets the sample time from the driver.
*
* @return The returned sample time from the driver, or 0 if the
* sample time could not be read.
*/
double get_sample_time();
/**
* @brief Gets the time base from the driver.
*
* @return The returned time base from the driver, or 0 if the
* time base could not be read.
*/
uint64_t get_time_base();
/**
* @brief Gets the device mode list from the driver.
*
* @return The returned device mode list from the driver, or NULL if the
* mode list could not be read.
*/
GSList* get_dev_mode_list();
virtual bool is_trigger_enabled() const;
public:
virtual void start();
virtual void run();
virtual void* get_id() const;
signals:
void config_changed();
protected:
SigSession *_owner;
void *_id;
};
} // device
} // pv
#endif // DSLOGIC_PV_DEVICE_DEVINST_H

View File

@ -0,0 +1,67 @@
/*
* This file is part of the DSLogic-gui project.
* DSLogic-gui is based on PulseView.
*
* Copyright (C) 2014 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 "file.h"
#include "inputfile.h"
#include "sessionfile.h"
#include <boost/filesystem.hpp>
#include <libsigrok4DSLogic/libsigrok.h>
using std::string;
namespace pv {
namespace device {
File::File(const std::string path) :
_path(path)
{
}
std::string File::format_device_title() const
{
return boost::filesystem::path(_path).filename().string();
}
File* File::create(const string &name)
{
if (sr_session_load(name.c_str()) == SR_OK) {
GSList *devlist = NULL;
sr_session_dev_list(&devlist);
sr_session_destroy();
if (devlist) {
sr_dev_inst *const sdi = (sr_dev_inst*)devlist->data;
g_slist_free(devlist);
if (sdi) {
sr_dev_close(sdi);
sr_dev_clear(sdi->driver);
return new SessionFile(name);
}
}
}
return new InputFile(name);
}
} // device
} // pv

View File

@ -0,0 +1,50 @@
/*
* This file is part of the DSLogic-gui project.
* DSLogic-gui is based on PulseView.
*
* Copyright (C) 2014 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 DSLOGIC_PV_DEVICE_FILE_H
#define DSLOGIC_PV_DEVICE_FILE_H
#include <string>
#include "devinst.h"
namespace pv {
namespace device {
class File : public DevInst
{
protected:
File(const std::string path);
public:
static File* create(const std::string &name);
public:
std::string format_device_title() const;
protected:
const std::string _path;
};
} // device
} // pv
#endif // DSLOGIC_PV_DEVICE_FILE_H

View File

@ -0,0 +1,144 @@
/*
* This file is part of the DSLogic-gui project.
* DSLogic-gui is based on PulseView.
*
* Copyright (C) 2014 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 <cassert>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "inputfile.h"
#include <libsigrok4DSLogic/libsigrok.h>
using std::string;
namespace pv {
namespace device {
InputFile::InputFile(const std::string &path) :
File(path),
_input(NULL)
{
}
sr_dev_inst* InputFile::dev_inst() const
{
assert(_input);
return _input->sdi;
}
void InputFile::use(SigSession *owner) throw(QString)
{
assert(!_input);
_input = load_input_file_format(_path, NULL);
File::use(owner);
sr_session_new();
if (sr_session_dev_add(_input->sdi) != SR_OK)
throw tr("Failed to add session device.");
}
void InputFile::release()
{
if (!_owner)
return;
assert(_input);
File::release();
sr_dev_close(_input->sdi);
sr_session_destroy();
_input = NULL;
}
sr_input_format* InputFile::determine_input_file_format(
const string &filename)
{
int i;
/* If there are no input formats, return NULL right away. */
sr_input_format *const *const inputs = sr_input_list();
if (!inputs) {
g_critical("No supported input formats available.");
return NULL;
}
/* Otherwise, try to find an input module that can handle this file. */
for (i = 0; inputs[i]; i++) {
if (inputs[i]->format_match(filename.c_str()))
break;
}
/* Return NULL if no input module wanted to touch this. */
if (!inputs[i]) {
g_critical("Error: no matching input module found.");
return NULL;
}
return inputs[i];
}
sr_input* InputFile::load_input_file_format(const string &filename,
sr_input_format *format)
{
struct stat st;
sr_input *in;
if (!format && !(format =
determine_input_file_format(filename.c_str()))) {
/* The exact cause was already logged. */
throw tr("Failed to load file");
}
if (stat(filename.c_str(), &st) == -1)
throw tr("Failed to load file");
/* Initialize the input module. */
if (!(in = new sr_input)) {
throw tr("Failed to allocate input module.");
}
in->format = format;
in->param = NULL;
if (in->format->init &&
in->format->init(in, filename.c_str()) != SR_OK) {
throw tr("Failed to load file");
}
return in;
}
void InputFile::start()
{
}
void InputFile::run()
{
assert(_input);
assert(_input->format);
assert(_input->format->loadfile);
_input->format->loadfile(_input, _path.c_str());
}
} // device
} // pv

View File

@ -0,0 +1,69 @@
/*
* This file is part of the DSLogic-gui project.
* DSLogic-gui is based on PulseView.
*
* Copyright (C) 2014 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 DSLOGIC_PV_DEVICE_INPUTFILE_H
#define DSLOGIC_PV_DEVICE_INPUTFILE_H
#include "file.h"
#include <string>
struct sr_input;
struct sr_input_format;
namespace pv {
namespace device {
class InputFile : public File
{
public:
InputFile(const std::string &path);
sr_dev_inst* dev_inst() const;
virtual void use(SigSession *owner) throw(QString);
virtual void release();
virtual void start();
virtual void run();
private:
/**
* Attempts to autodetect the format. Failing that
* @param filename The filename of the input file.
* @return A pointer to the 'struct sr_input_format' that should be used,
* or NULL if no input format was selected or auto-detected.
*/
static sr_input_format* determine_input_file_format(
const std::string &filename);
static sr_input* load_input_file_format(const std::string &filename,
sr_input_format *format);
private:
sr_input *_input;
};
} // device
} // pv
#endif // DSLOGIC_PV_DEVICE_INPUTFILE_H

View File

@ -0,0 +1,76 @@
/*
* This file is part of the DSLogic-gui project.
* DSLogic-gui is based on PulseView.
*
* Copyright (C) 2014 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 "sessionfile.h"
#include <libsigrok4DSLogic//libsigrok.h>
namespace pv {
namespace device {
SessionFile::SessionFile(const std::string &path) :
File(path),
_sdi(NULL)
{
}
sr_dev_inst* SessionFile::dev_inst() const
{
return _sdi;
}
void SessionFile::use(SigSession *owner) throw(QString)
{
assert(!_sdi);
if (sr_session_load(_path.c_str()) != SR_OK)
throw tr("Failed to open file.\n");
GSList *devlist = NULL;
sr_session_dev_list(&devlist);
if (!devlist || !devlist->data) {
if (devlist)
g_slist_free(devlist);
throw tr("Failed to start session.");
}
_sdi = (sr_dev_inst*)devlist->data;
g_slist_free(devlist);
File::use(owner);
}
void SessionFile::release()
{
if (!_owner)
return;
assert(_sdi);
File::release();
sr_dev_close(_sdi);
sr_dev_clear(_sdi->driver);
sr_session_destroy();
_sdi = NULL;
}
} // device
} // pv

View File

@ -0,0 +1,48 @@
/*
* This file is part of the DSLogic-gui project.
* DSLogic-gui is based on PulseView.
*
* Copyright (C) 2014 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 DSLOGIC_PV_DEVICE_SESSIONFILE_H
#define DSLOGIC_PV_DEVICE_SESSIONFILE_H
#include "file.h"
namespace pv {
namespace device {
class SessionFile : public File
{
public:
SessionFile(const std::string &path);
sr_dev_inst* dev_inst() const;
virtual void use(SigSession *owner) throw(QString);
virtual void release();
private:
sr_dev_inst *_sdi;
};
} // device
} // pv
#endif // DSLOGIC_PV_DEVICE_SESSIONFILE_H

View File

@ -22,6 +22,8 @@
#include "devicemanager.h"
#include "device/devinst.h"
#include "device/device.h"
#include "sigsession.h"
#include <cassert>
@ -34,9 +36,17 @@
#include <QDebug>
#include <QDir>
#include <boost/foreach.hpp>
#include <libsigrok4DSLogic/libsigrok.h>
using namespace std;
using boost::shared_ptr;
using std::list;
using std::map;
using std::ostringstream;
using std::runtime_error;
using std::string;
char config_path[256];
namespace pv {
@ -53,57 +63,47 @@ DeviceManager::~DeviceManager()
release_devices();
}
const std::list<sr_dev_inst*>& DeviceManager::devices() const
const std::list<boost::shared_ptr<device::DevInst> > &DeviceManager::devices() const
{
return _devices;
}
int DeviceManager::use_device(sr_dev_inst *sdi, SigSession *owner)
void DeviceManager::add_device(boost::shared_ptr<pv::device::DevInst> device)
{
assert(sdi);
assert(owner);
assert(device);
if (sr_dev_open(sdi) != SR_OK)
return SR_ERR;
_used_devices[sdi] = owner;
return SR_OK;
if (std::find(_devices.begin(), _devices.end(), device) ==
_devices.end())
_devices.push_front(device);
}
void DeviceManager::release_device(sr_dev_inst *sdi)
{
assert(sdi);
// Notify the owner, and removed the device from the used device list
_used_devices[sdi]->release_device(sdi);
_used_devices.erase(sdi);
sr_dev_close(sdi);
}
list<sr_dev_inst*> DeviceManager::driver_scan(
std::list<boost::shared_ptr<device::DevInst> > DeviceManager::driver_scan(
struct sr_dev_driver *const driver, GSList *const drvopts)
{
list<sr_dev_inst*> driver_devices;
list< shared_ptr<device::DevInst> > driver_devices;
assert(driver);
// Remove any device instances from this driver from the device
// list. They will not be valid after the scan.
list<sr_dev_inst*>::iterator i = _devices.begin();
list< shared_ptr<device::DevInst> >::iterator i = _devices.begin();
while (i != _devices.end()) {
if ((*i)->driver == driver)
if ((*i)->dev_inst() &&
(*i)->dev_inst()->driver == driver) {
(*i)->release();
i = _devices.erase(i);
else
} else {
i++;
}
}
// Release this driver and all it's attached devices
release_driver(driver);
// Clear all the old device instances from this driver
sr_dev_clear(driver);
//release_driver(driver);
// Check If DSLogic driver
if (strcmp(driver->name, "DSLogic") == 0) {
QDir dir(QApplication::applicationDirPath());
QDir dir(QCoreApplication::applicationDirPath());
if (!dir.cd("res"))
return driver_devices;
std::string str = dir.absolutePath().toStdString() + "/";
@ -113,43 +113,19 @@ list<sr_dev_inst*> DeviceManager::driver_scan(
// Do the scan
GSList *const devices = sr_driver_scan(driver, drvopts);
for (GSList *l = devices; l; l = l->next)
driver_devices.push_back((sr_dev_inst*)l->data);
driver_devices.push_front(shared_ptr<device::DevInst>(
new device::Device((sr_dev_inst*)l->data)));
g_slist_free(devices);
driver_devices.sort(compare_devices);
//driver_devices.sort(compare_devices);
// Add the scanned devices to the main list
_devices.insert(_devices.end(), driver_devices.begin(),
driver_devices.end());
_devices.sort(compare_devices);
//_devices.sort(compare_devices);
return driver_devices;
}
string DeviceManager::format_device_title(const sr_dev_inst *const sdi)
{
ostringstream s;
assert(sdi);
if (sdi->vendor && sdi->vendor[0]) {
s << sdi->vendor;
if ((sdi->model && sdi->model[0]) ||
(sdi->version && sdi->version[0]))
s << ' ';
}
if (sdi->model && sdi->model[0]) {
s << sdi->model;
if (sdi->version && sdi->version[0])
s << ' ';
}
if (sdi->version && sdi->version[0])
s << sdi->version;
return s.str();
}
void DeviceManager::init_drivers()
{
// Initialise all libsigrok drivers
@ -166,11 +142,10 @@ void DeviceManager::init_drivers()
void DeviceManager::release_devices()
{
// Release all the used devices
for (map<sr_dev_inst*, SigSession*>::iterator i = _used_devices.begin();
i != _used_devices.end();)
release_device((*i++).first);
_used_devices.clear();
BOOST_FOREACH(shared_ptr<device::DevInst> dev, _devices) {
assert(dev);
dev->release();
}
// Clear all the drivers
sr_dev_driver **const drivers = sr_driver_list();
@ -188,53 +163,22 @@ void DeviceManager::scan_all_drivers()
void DeviceManager::release_driver(struct sr_dev_driver *const driver)
{
assert(driver);
// map<sr_dev_inst*, SigSession*>::iterator i = _used_devices.begin();
// while(i != _used_devices.end()) {
// if((*i).first->driver == driver)
// {
// // Notify the current owner of the device
// (*i).second->release_device((*i).first);
// // Close the device instance
// sr_dev_close((*i).first);
// // Remove it from the used device list
// i = _used_devices.erase(i);
// } else {
// i++;
// }
// }
for (map<sr_dev_inst*, SigSession*>::iterator i = _used_devices.begin();
i != _used_devices.end();)
if((*i).first->driver == driver)
{
// Notify the current owner of the device
(*i).second->release_device((*i).first);
// Close the device instance
sr_dev_close((*i).first);
// Remove it from the used device list
_used_devices.erase(i++);
} else {
i++;
BOOST_FOREACH(shared_ptr<device::DevInst> dev, _devices) {
assert(dev);
if(dev->dev_inst()->driver == driver)
dev->release();
}
// Clear all the old device instances from this driver
sr_dev_clear(driver);
}
bool DeviceManager::compare_devices(const sr_dev_inst *const a,
const sr_dev_inst *const b)
bool DeviceManager::compare_devices(boost::shared_ptr<device::DevInst> a,
boost::shared_ptr<device::DevInst> b)
{
return format_device_title(a).compare(format_device_title(b)) < 0;
}
int DeviceManager::test_device(sr_dev_inst *sdi)
{
assert(sdi);
return sdi->driver->dev_test(sdi);
assert(a);
assert(b);
return a->format_device_title().compare(b->format_device_title()) <= 0;
}
} // namespace pv

View File

@ -47,6 +47,10 @@ namespace pv {
class SigSession;
namespace device {
class DevInst;
}
class DeviceManager
{
public:
@ -54,36 +58,29 @@ public:
~DeviceManager();
const std::list<sr_dev_inst*>& devices() const;
const std::list< boost::shared_ptr<pv::device::DevInst> >& devices() const;
int use_device(sr_dev_inst *sdi, SigSession *owner);
void add_device(boost::shared_ptr<pv::device::DevInst> device);
void release_device(sr_dev_inst *sdi);
std::list<sr_dev_inst*> driver_scan(
std::list< boost::shared_ptr<pv::device::DevInst> > driver_scan(
struct sr_dev_driver *const driver,
GSList *const drvopts = NULL);
static std::string format_device_title(const sr_dev_inst *const sdi);
void scan_all_drivers();
int test_device(sr_dev_inst *sdi);
private:
void init_drivers();
void release_devices();
void scan_all_drivers();
void release_driver(struct sr_dev_driver *const driver);
static bool compare_devices(const sr_dev_inst *const a,
const sr_dev_inst *const b);
static bool compare_devices(boost::shared_ptr<device::DevInst> a,
boost::shared_ptr<device::DevInst> b);
private:
struct sr_context *const _sr_ctx;
std::list<sr_dev_inst*> _devices;
std::map<sr_dev_inst*, pv::SigSession*> _used_devices;
std::list< boost::shared_ptr<pv::device::DevInst> > _devices;
};
} // namespace pv

View File

@ -42,7 +42,6 @@ DeviceOptions::DeviceOptions(QWidget *parent, struct sr_dev_inst *sdi) :
_layout(this),
_probes_box(tr("Channels"), this),
_props_box(tr("Mode"), this),
_mode_comboBox(this),
_button_box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
Qt::Horizontal, this),
_device_options_binding(sdi)
@ -50,11 +49,6 @@ DeviceOptions::DeviceOptions(QWidget *parent, struct sr_dev_inst *sdi) :
setWindowTitle(tr("Configure Device"));
setLayout(&_layout);
_last_mode = sdi->mode;
_mode_comboBox.addItem(mode_strings[LOGIC]);
_mode_comboBox.addItem(mode_strings[DSO]);
_mode_comboBox.addItem(mode_strings[ANALOG]);
_mode_comboBox.setCurrentIndex(_sdi->mode);
_props_box.setLayout(&_props_box_layout);
_props_box_layout.addWidget(get_property_form());
_layout.addWidget(&_props_box);
@ -68,9 +62,6 @@ DeviceOptions::DeviceOptions(QWidget *parent, struct sr_dev_inst *sdi) :
connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept()));
connect(&_button_box, SIGNAL(rejected()), this, SLOT(reject()));
connect(&_mode_comboBox, SIGNAL(currentIndexChanged(QString)),
this, SLOT(mode_changed(QString)));
}
void DeviceOptions::accept()
@ -79,7 +70,6 @@ void DeviceOptions::accept()
QDialog::accept();
_last_mode = _sdi->mode;
// Commit the properties
const vector< boost::shared_ptr<pv::prop::Property> > &properties =
_device_options_binding.properties();
@ -90,8 +80,8 @@ void DeviceOptions::accept()
// Commit the probes
int index = 0;
for (const GSList *l = _sdi->probes; l; l = l->next) {
sr_probe *const probe = (sr_probe*)l->data;
for (const GSList *l = _sdi->channels; l; l = l->next) {
sr_channel *const probe = (sr_channel*)l->data;
assert(probe);
probe->enabled = (_probes_checkBox_list.at(index)->checkState() == Qt::Checked);
@ -104,8 +94,6 @@ void DeviceOptions::reject()
using namespace Qt;
QDialog::reject();
// Mode Recovery
sr_config_set(_sdi, SR_CONF_DEVICE_MODE, g_variant_new_string(_mode_comboBox.itemText(_last_mode).toLocal8Bit()));
}
QWidget* DeviceOptions::get_property_form()
@ -114,7 +102,6 @@ QWidget* DeviceOptions::get_property_form()
QFormLayout *const layout = new QFormLayout(form);
form->setLayout(layout);
layout->addRow("Device Mode", &_mode_comboBox);
const vector< boost::shared_ptr<pv::prop::Property> > &properties =
_device_options_binding.properties();
BOOST_FOREACH(boost::shared_ptr<pv::prop::Property> p, properties)
@ -144,8 +131,8 @@ void DeviceOptions::setup_probes()
_probes_label_list.clear();
_probes_checkBox_list.clear();
for (const GSList *l = _sdi->probes; l; l = l->next) {
sr_probe *const probe = (sr_probe*)l->data;
for (const GSList *l = _sdi->channels; l; l = l->next) {
sr_channel *const probe = (sr_channel*)l->data;
assert(probe);
QLabel *probe_label = new QLabel(QString::number(probe->index), this);
@ -192,13 +179,5 @@ void DeviceOptions::disable_all_probes()
set_all_probes(false);
}
void DeviceOptions::mode_changed(QString mode)
{
(void)mode;
// Commit mode
sr_config_set(_sdi, SR_CONF_DEVICE_MODE, g_variant_new_string(_mode_comboBox.currentText().toLocal8Bit()));
setup_probes();
}
} // namespace dialogs
} // namespace pv

View File

@ -64,12 +64,9 @@ private:
private slots:
void enable_all_probes();
void disable_all_probes();
void mode_changed(QString mode);
private:
struct sr_dev_inst *const _sdi;
int _last_mode;
QVBoxLayout _layout;
QGroupBox _probes_box;
@ -78,7 +75,6 @@ private:
QVector <QCheckBox *> _probes_checkBox_list;
QGroupBox _props_box;
QComboBox _mode_comboBox;
QVBoxLayout _props_box_layout;
QDialogButtonBox _button_box;

View File

@ -0,0 +1,84 @@
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2014 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 "storeprogress.h"
#include <QMessageBox>
namespace pv {
namespace dialogs {
StoreProgress::StoreProgress(const QString &file_name,
SigSession &session, QWidget *parent) :
QProgressDialog(tr("Saving..."), tr("Cancel"), 0, 0, parent),
_session(file_name.toStdString(), session)
{
connect(&_session, SIGNAL(progress_updated()),
this, SLOT(on_progress_updated()));
}
StoreProgress::~StoreProgress()
{
_session.wait();
}
void StoreProgress::run()
{
if (_session.start())
show();
else
show_error();
}
void StoreProgress::show_error()
{
QMessageBox msg(parentWidget());
msg.setText(tr("Failed to save session."));
msg.setInformativeText(_session.error());
msg.setStandardButtons(QMessageBox::Ok);
msg.setIcon(QMessageBox::Warning);
msg.exec();
}
void StoreProgress::closeEvent(QCloseEvent*)
{
_session.cancel();
}
void StoreProgress::on_progress_updated()
{
const std::pair<uint64_t, uint64_t> p = _session.progress();
assert(p.first <= p.second);
setValue(p.first);
setMaximum(p.second);
const QString err = _session.error();
if (!err.isEmpty()) {
show_error();
close();
}
if (p.first == p.second)
close();
}
} // dialogs
} // pv

View File

@ -0,0 +1,65 @@
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2014 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 DSLOGIC_PV_DIALOGS_SAVEPROGRESS_H
#define DSLOGIC_PV_DIALOGS_SAVEPROGRESS_H
#include <set>
#include <boost/shared_ptr.hpp>
#include <QProgressDialog>
#include <pv/storesession.h>
namespace pv {
class SigSession;
namespace dialogs {
class StoreProgress : public QProgressDialog
{
Q_OBJECT
public:
StoreProgress(const QString &file_name, SigSession &session,
QWidget *parent = 0);
virtual ~StoreProgress();
void run();
private:
void show_error();
void closeEvent(QCloseEvent*);
private slots:
void on_progress_updated();
private:
pv::StoreSession _session;
};
} // dialogs
} // pv
#endif // PULSEVIEW_PV_DIALOGS_SAVEPROGRESS_H

View File

@ -23,6 +23,7 @@
#include "dsotriggerdock.h"
#include "../sigsession.h"
#include "../device/devinst.h"
#include <QObject>
#include <QLabel>
@ -135,11 +136,10 @@ void DsoTriggerDock::paintEvent(QPaintEvent *)
void DsoTriggerDock::pos_changed(int pos)
{
int ret;
quint32 real_pos;
real_pos = pos*_session.get_total_sample_len()/100.0f;
real_pos = (_session.get_last_sample_rate() > SR_MHZ(100)) ? real_pos/2 : real_pos;
ret = sr_config_set(_session.get_device(), SR_CONF_HORIZ_TRIGGERPOS, g_variant_new_uint32(real_pos));
if (ret != SR_OK) {
ret = _session.get_device()->set_config(NULL, NULL,
SR_CONF_HORIZ_TRIGGERPOS,
g_variant_new_uint16((uint16_t)pos));
if (!ret) {
QMessageBox msg(this);
msg.setText("Trigger Setting Issue");
msg.setInformativeText("Change horiz trigger position failed!");
@ -147,6 +147,10 @@ void DsoTriggerDock::pos_changed(int pos)
msg.setIcon(QMessageBox::Warning);
msg.exec();
}
uint64_t sample_limit = _session.get_device()->get_sample_limit();
uint64_t trig_pos = sample_limit * pos / 100;
set_trig_pos(trig_pos);
}
void DsoTriggerDock::source_changed()
@ -154,8 +158,10 @@ void DsoTriggerDock::source_changed()
int id = source_group->checkedId();
int ret;
ret = sr_config_set(_session.get_device(), SR_CONF_TRIGGER_SOURCE, g_variant_new_byte(id));
if (ret != SR_OK) {
ret = _session.get_device()->set_config(NULL, NULL,
SR_CONF_TRIGGER_SOURCE,
g_variant_new_byte(id));
if (!ret) {
QMessageBox msg(this);
msg.setText("Trigger Setting Issue");
msg.setInformativeText("Change trigger source failed!");
@ -170,8 +176,10 @@ void DsoTriggerDock::type_changed()
int id = type_group->checkedId();
int ret;
ret = sr_config_set(_session.get_device(), SR_CONF_TRIGGER_SLOPE, g_variant_new_byte(id));
if (ret != SR_OK) {
ret = _session.get_device()->set_config(NULL, NULL,
SR_CONF_TRIGGER_SLOPE,
g_variant_new_byte(id));
if (!ret) {
QMessageBox msg(this);
msg.setText("Trigger Setting Issue");
msg.setInformativeText("Change trigger type failed!");
@ -183,7 +191,7 @@ void DsoTriggerDock::type_changed()
void DsoTriggerDock::device_change()
{
if (strcmp(_session.get_device()->driver->name, "DSLogic") != 0) {
if (strcmp(_session.get_device()->dev_inst()->driver->name, "DSLogic") != 0) {
position_spinBox->setDisabled(true);
position_slider->setDisabled(true);
} else {

View File

@ -52,6 +52,7 @@ public:
void device_change();
signals:
void set_trig_pos(quint64 trig_pos);
private slots:
void pos_changed(int pos);

View File

@ -20,6 +20,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <math.h>
#include "measuredock.h"
#include "../sigsession.h"
@ -27,6 +28,9 @@
#include "../view/view.h"
#include "../view/timemarker.h"
#include "../view/ruler.h"
#include "../view/logicsignal.h"
#include "../data/signaldata.h"
#include "../data/snapshot.h"
#include <QObject>
#include <QPainter>
@ -34,6 +38,8 @@
#include "libsigrok4DSLogic/libsigrok.h"
using boost::shared_ptr;
namespace pv {
namespace dock {
@ -71,23 +77,42 @@ MeasureDock::MeasureDock(QWidget *parent, View &view, SigSession &session) :
_cursor_groupBox = new QGroupBox("Cursor measurement", this);
_t1_comboBox = new QComboBox(this);
_t2_comboBox = new QComboBox(this);
_delta_label = new QLabel("#####", this);
_cnt_label = new QLabel("#####", this);
_t3_comboBox = new QComboBox(this);
_delta_label_t1t2 = new QLabel("#####", this);
_cnt_label_t1t2 = new QLabel("#####", this);
_delta_label_t2t3 = new QLabel("#####", this);
_cnt_label_t2t3 = new QLabel("#####", this);
_delta_label_t1t3 = new QLabel("#####", this);
_cnt_label_t1t3 = new QLabel("#####", this);
_t1_last_index = 0;
_t2_last_index = 0;
_t3_last_index = 0;
_cursor_layout = new QGridLayout();
_cursor_layout->addWidget(new QLabel("T1: ", this), 0, 0);
_cursor_layout->addWidget(_t1_comboBox, 0, 1);
_cursor_layout->addWidget(new QLabel("T2: ", this), 1, 0);
_cursor_layout->addWidget(_t2_comboBox, 1, 1);
_cursor_layout->addWidget(new QLabel("|T2 - T1|: ", this), 2, 0);
_cursor_layout->addWidget(_delta_label, 2, 1);
_cursor_layout->addWidget(new QLabel("Delta Samples: ", this), 2, 2);
_cursor_layout->addWidget(_cnt_label, 2, 3);
_cursor_layout->addWidget(new QLabel("T3: ", this), 2, 0);
_cursor_layout->addWidget(_t3_comboBox, 2, 1);
_cursor_layout->addWidget(new QLabel("Cursors", this), 4, 0);
_cursor_layout->addWidget(new QLabel("Time/Samples", this), 4, 1);
_cursor_layout->addWidget(new QLabel("Sample Value", this), 4, 2);
_cursor_layout->addWidget(new QLabel("Value Radix", this), 4, 3);
_cursor_layout->addWidget(new QLabel("|T2 - T1|: ", this), 3, 0);
_cursor_layout->addWidget(_delta_label_t1t2, 3, 1);
_cursor_layout->addWidget(new QLabel("Delta Samples: ", this), 3, 2);
_cursor_layout->addWidget(_cnt_label_t1t2, 3, 3);
_cursor_layout->addWidget(new QLabel("|T3 - T2|: ", this), 4, 0);
_cursor_layout->addWidget(_delta_label_t2t3, 4, 1);
_cursor_layout->addWidget(new QLabel("Delta Samples: ", this), 4, 2);
_cursor_layout->addWidget(_cnt_label_t2t3, 4, 3);
_cursor_layout->addWidget(new QLabel("|T3 - T1|: ", this), 5, 0);
_cursor_layout->addWidget(_delta_label_t1t3, 5, 1);
_cursor_layout->addWidget(new QLabel("Delta Samples: ", this), 5, 2);
_cursor_layout->addWidget(_cnt_label_t1t3, 5, 3);
_cursor_layout->addWidget(new QLabel("Cursors", this), 6, 0);
_cursor_layout->addWidget(new QLabel("Time/Samples", this), 6, 1);
_cursor_layout->addWidget(new QLabel(this), 0, 4);
_cursor_layout->addWidget(new QLabel(this), 1, 4);
@ -106,6 +131,7 @@ MeasureDock::MeasureDock(QWidget *parent, View &view, SigSession &session) :
connect(_t1_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update()));
connect(_t2_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update()));
connect(_t3_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update()));
connect(_fen_checkBox, SIGNAL(stateChanged(int)), &_view, SLOT(set_measure_en(int)));
}
@ -124,10 +150,16 @@ void MeasureDock::paintEvent(QPaintEvent *)
void MeasureDock::cursor_update()
{
using namespace pv::data;
int index = 1;
disconnect(_t1_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update()));
disconnect(_t2_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update()));
disconnect(_t3_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update()));
_t1_comboBox->clear();
_t2_comboBox->clear();
_t3_comboBox->clear();
if (!_cursor_pushButton_list.empty()) {
for (QVector<QPushButton *>::Iterator i = _cursor_pushButton_list.begin();
@ -136,20 +168,12 @@ void MeasureDock::cursor_update()
for (QVector<QLabel *>::Iterator i = _curpos_label_list.begin();
i != _curpos_label_list.end(); i++)
delete (*i);
for (QVector<QLabel *>::Iterator i = _curvalue_label_list.begin();
i != _curvalue_label_list.end(); i++)
delete (*i);
for (QVector<QComboBox *>::Iterator i = _radix_comboBox_list.begin();
i != _radix_comboBox_list.end(); i++)
delete (*i);
for (QVector<QLabel *>::Iterator i = _space_label_list.begin();
i != _space_label_list.end(); i++)
delete (*i);
_cursor_pushButton_list.clear();
_curpos_label_list.clear();
_curvalue_label_list.clear();
_radix_comboBox_list.clear();
_space_label_list.clear();
}
@ -158,33 +182,37 @@ void MeasureDock::cursor_update()
QString curCursor = "Cursor "+QString::number(index);
_t1_comboBox->addItem(curCursor);
_t2_comboBox->addItem(curCursor);
_t3_comboBox->addItem(curCursor);
QPushButton *_cursor_pushButton = new QPushButton(curCursor, this);
QLabel *_curpos_label = new QLabel(_view.get_cm_time(index - 1), this);
QLabel *_curvalue_label = new QLabel("####", this);
QComboBox *_radix_comboBox = new QComboBox(this);
_radix_comboBox->addItem("Bin");
_radix_comboBox->addItem("Oct");
_radix_comboBox->addItem("Dec");
_radix_comboBox->addItem("Hex");
QString _cur_text = _view.get_cm_time(index - 1) + "/" + QString::number(_view.get_cursor_samples(index - 1));
QLabel *_curpos_label = new QLabel(_cur_text, this);
QLabel *_space_label = new QLabel(this);
_cursor_pushButton_list.push_back(_cursor_pushButton);
_curpos_label_list.push_back(_curpos_label);
_curvalue_label_list.push_back(_curvalue_label);
_radix_comboBox_list.push_back(_radix_comboBox);
_space_label_list.push_back(_space_label);
_cursor_layout->addWidget(_cursor_pushButton, 4 + index, 0);
_cursor_layout->addWidget(_curpos_label, 4 + index, 1);
_cursor_layout->addWidget(_curvalue_label, 4 + index, 2);
_cursor_layout->addWidget(_radix_comboBox, 4 + index, 3);
_cursor_layout->addWidget(_space_label, 4 + index, 4);
_cursor_layout->addWidget(_cursor_pushButton, 6 + index, 0);
_cursor_layout->addWidget(_curpos_label, 6 + index, 1);
_cursor_layout->addWidget(_space_label, 6 + index, 2);
connect(_cursor_pushButton, SIGNAL(clicked()), this, SLOT(goto_cursor()));
index++;
}
if (_t1_last_index < _t1_comboBox->count())
_t1_comboBox->setCurrentIndex(_t1_last_index);
if (_t2_last_index < _t2_comboBox->count())
_t2_comboBox->setCurrentIndex(_t2_last_index);
if (_t3_last_index < _t3_comboBox->count())
_t3_comboBox->setCurrentIndex(_t3_last_index);
connect(_t1_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update()));
connect(_t2_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update()));
connect(_t3_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update()));
delta_update();
update();
}
@ -202,7 +230,8 @@ void MeasureDock::cursor_moved()
int index = 0;
for(std::list<Cursor*>::iterator i = _view.get_cursorList().begin();
i != _view.get_cursorList().end(); i++) {
_curpos_label_list.at(index)->setText(_view.get_cm_time(index));
QString _cur_text = _view.get_cm_time(index) + "/" + QString::number(_view.get_cursor_samples(index));
_curpos_label_list.at(index)->setText(_cur_text);
//_curvalue_label_list.at(index)->setText(_view.get_cm_value(index));
index++;
}
@ -212,11 +241,28 @@ void MeasureDock::cursor_moved()
void MeasureDock::delta_update()
{
_t1_last_index = std::max(_t1_comboBox->currentIndex(), 0);
_t2_last_index = std::max(_t2_comboBox->currentIndex(), 0);
_t3_last_index = std::max(_t3_comboBox->currentIndex(), 0);
if (_t1_comboBox->count() != 0 && _t2_comboBox->count() != 0) {
int t1_index = _t1_comboBox->currentIndex();
int t2_index = _t2_comboBox->currentIndex();
_delta_label->setText(_view.get_cm_delta(t1_index, t2_index));
_cnt_label->setText(_view.get_cm_delta_cnt(t1_index, t2_index));
uint64_t delta = abs(_view.get_cursor_samples(_t1_last_index) -
_view.get_cursor_samples(_t2_last_index));
_delta_label_t1t2->setText(_view.get_cm_delta(_t1_last_index, _t2_last_index));
_cnt_label_t1t2->setText(QString::number(delta));
}
if (_t2_comboBox->count() != 0 && _t2_comboBox->count() != 0) {
uint64_t delta = abs(_view.get_cursor_samples(_t2_last_index) -
_view.get_cursor_samples(_t3_last_index));
_delta_label_t2t3->setText(_view.get_cm_delta(_t2_last_index, _t3_last_index));
_cnt_label_t2t3->setText(QString::number(delta));
}
if (_t1_comboBox->count() != 0 && _t3_comboBox->count() != 0) {
uint64_t delta = abs(_view.get_cursor_samples(_t1_last_index) -
_view.get_cursor_samples(_t3_last_index));
_delta_label_t1t3->setText(_view.get_cm_delta(_t1_last_index, _t3_last_index));
_cnt_label_t1t3->setText(QString::number(delta));
}
}

View File

@ -91,13 +91,19 @@ private:
QGroupBox *_cursor_groupBox;
QComboBox *_t1_comboBox;
QComboBox *_t2_comboBox;
QLabel *_delta_label;
QLabel *_cnt_label;
QComboBox *_t3_comboBox;
QLabel *_delta_label_t1t2;
QLabel *_cnt_label_t1t2;
QLabel *_delta_label_t2t3;
QLabel *_cnt_label_t2t3;
QLabel *_delta_label_t1t3;
QLabel *_cnt_label_t1t3;
int _t1_last_index;
int _t2_last_index;
int _t3_last_index;
QVector <QPushButton *> _cursor_pushButton_list;
QVector <QLabel *> _curpos_label_list;
QVector <QLabel *> _curvalue_label_list;
QVector <QComboBox *> _radix_comboBox_list;
QVector <QLabel *> _space_label_list;
};

View File

@ -22,13 +22,17 @@
#include "protocoldock.h"
#include "../decoder/democonfig.h"
#include "../sigsession.h"
#include "../view/decodetrace.h"
#include "../device/devinst.h"
#include <QObject>
#include <QHBoxLayout>
#include <QPainter>
#include <QMessageBox>
#include <QFormLayout>
#include <boost/shared_ptr.hpp>
namespace pv {
namespace dock {
@ -49,10 +53,21 @@ ProtocolDock::ProtocolDock(QWidget *parent, SigSession &session) :
QIcon(":/icons/del.png")));
_del_all_button->setCheckable(true);
_protocol_combobox = new QComboBox(this);
for (int i = 0; decoder::protocol_list[i] != NULL;) {
_protocol_combobox->addItem(decoder::protocol_list[i]);
i++;
GSList *l = g_slist_sort(g_slist_copy(
(GSList*)srd_decoder_list()), decoder_name_cmp);
for(; l; l = l->next)
{
const srd_decoder *const d = (srd_decoder*)l->data;
assert(d);
const bool have_probes = (d->channels || d->opt_channels) != 0;
if (true == have_probes) {
_protocol_combobox->addItem(QString::fromUtf8(d->name), qVariantFromValue(l->data));
}
}
g_slist_free(l);
hori_layout->addWidget(_add_button);
hori_layout->addWidget(_del_all_button);
hori_layout->addWidget(_protocol_combobox);
@ -74,6 +89,12 @@ ProtocolDock::~ProtocolDock()
{
}
int ProtocolDock::decoder_name_cmp(const void *a, const void *b)
{
return strcmp(((const srd_decoder*)a)->name,
((const srd_decoder*)b)->name);
}
void ProtocolDock::paintEvent(QPaintEvent *)
{
QStyleOption opt;
@ -84,7 +105,7 @@ void ProtocolDock::paintEvent(QPaintEvent *)
void ProtocolDock::add_protocol()
{
if (_session.get_device()->mode != LOGIC) {
if (_session.get_device()->dev_inst()->mode != LOGIC) {
QMessageBox msg(this);
msg.setText("Protocol Analyzer");
msg.setInformativeText("Protocol Analyzer is only valid in Digital Mode!");
@ -92,11 +113,12 @@ void ProtocolDock::add_protocol()
msg.setIcon(QMessageBox::Warning);
msg.exec();
} else {
pv::decoder::DemoConfig dlg(this, _session.get_device(), _protocol_combobox->currentIndex());
if (dlg.exec()) {
std::list <int > _sel_probes = dlg.get_sel_probes();
QMap <QString, QVariant>& _options = dlg.get_options();
QMap <QString, int> _options_index = dlg.get_options_index();
srd_decoder *const decoder =
(srd_decoder*)(_protocol_combobox->itemData(_protocol_combobox->currentIndex())).value<void*>();
if (_session.add_decoder(decoder)) {
//std::list <int > _sel_probes = dlg.get_sel_probes();
//QMap <QString, QVariant>& _options = dlg.get_options();
//QMap <QString, int> _options_index = dlg.get_options_index();
QPushButton *_del_button = new QPushButton(this);
QPushButton *_set_button = new QPushButton(this);
@ -105,7 +127,7 @@ void ProtocolDock::add_protocol()
QIcon(":/icons/del.png")));
_set_button->setFlat(true);
_set_button->setIcon(QIcon::fromTheme("protocol",
QIcon(":/icons/set.png")));
QIcon(":/icons/gear.png")));
QLabel *_protocol_label = new QLabel(this);
_del_button->setCheckable(true);
@ -129,7 +151,7 @@ void ProtocolDock::add_protocol()
_hori_layout_list.push_back(hori_layout);
_layout->insertLayout(_del_button_list.size(), hori_layout);
_session.add_protocol_analyzer(_protocol_combobox->currentIndex(), _sel_probes, _options, _options_index);
//_session.add_protocol_analyzer(_protocol_combobox->currentIndex(), _sel_probes, _options, _options_index);
}
}
}
@ -141,15 +163,16 @@ void ProtocolDock::rst_protocol()
i != _set_button_list.end(); i++) {
QPushButton *button = qobject_cast<QPushButton *>(sender());
if ((*i) == button) {
pv::decoder::DemoConfig dlg(this, _session.get_device(), _protocol_index_list.at(rst_index));
dlg.set_config(_session.get_decode_probes(rst_index), _session.get_decode_options_index(rst_index));
if (dlg.exec()) {
std::list <int > _sel_probes = dlg.get_sel_probes();
QMap <QString, QVariant>& _options = dlg.get_options();
QMap <QString, int> _options_index = dlg.get_options_index();
//pv::decoder::DemoConfig dlg(this, _session.get_device(), _protocol_index_list.at(rst_index));
//dlg.set_config(_session.get_decode_probes(rst_index), _session.get_decode_options_index(rst_index));
//if (dlg.exec()) {
//std::list <int > _sel_probes = dlg.get_sel_probes();
//QMap <QString, QVariant>& _options = dlg.get_options();
//QMap <QString, int> _options_index = dlg.get_options_index();
_session.rst_protocol_analyzer(rst_index, _sel_probes, _options, _options_index);
}
//_session.rst_protocol_analyzer(rst_index, _sel_probes, _options, _options_index);
//}
_session.rst_decoder(rst_index);
break;
}
rst_index++;
@ -170,7 +193,7 @@ void ProtocolDock::del_protocol()
delete _set_button_list.at(del_index);
delete _protocol_label_list.at(del_index);
_session.del_protocol_analyzer(0);
_session.remove_decode_signal(0);
del_index++;
}
_hori_layout_list.clear();
@ -204,7 +227,7 @@ void ProtocolDock::del_protocol()
_protocol_label_list.remove(del_index);
_protocol_index_list.remove(del_index);
_session.del_protocol_analyzer(del_index);
_session.remove_decode_signal(del_index);
break;
}
@ -225,7 +248,7 @@ void ProtocolDock::del_all_protocol()
delete _set_button_list.at(del_index);
delete _protocol_label_list.at(del_index);
_session.del_protocol_analyzer(0);
_session.remove_decode_signal(0);
del_index++;
}
_hori_layout_list.clear();

View File

@ -24,6 +24,8 @@
#ifndef DSLOGIC_PV_PROTOCOLDOCK_H
#define DSLOGIC_PV_PROTOCOLDOCK_H
#include <libsigrokdecode/libsigrokdecode.h>
#include <QDockWidget>
#include <QPushButton>
#include <QComboBox>
@ -36,8 +38,6 @@
#include <libsigrok4DSLogic/libsigrok.h>
#include "../decoder/decoder.h"
namespace pv {
class SigSession;
@ -64,6 +64,7 @@ private slots:
void del_protocol();
private:
static int decoder_name_cmp(const void *a, const void *b);
private:
SigSession &_session;

View File

@ -30,6 +30,7 @@
#include "../dialogs/search.h"
#include "../data/snapshot.h"
#include "../data/logicsnapshot.h"
#include "../device/devinst.h"
#include <QObject>
#include <QPainter>
@ -45,6 +46,7 @@ namespace pv {
namespace dock {
using namespace pv::view;
using namespace pv::widgets;
SearchDock::SearchDock(QWidget *parent, View &view, SigSession &session) :
QWidget(parent),
@ -197,7 +199,7 @@ void SearchDock::on_next()
void SearchDock::on_set()
{
dialogs::Search dlg(this, _session.get_device(), _pattern);
dialogs::Search dlg(this, _session.get_device()->dev_inst(), _pattern);
if (dlg.exec()) {
_pattern = dlg.get_pattern();
_pattern.remove(QChar(' '), Qt::CaseInsensitive);

View File

@ -45,7 +45,7 @@
#include <libsigrok4DSLogic/libsigrok.h>
#include "fakelineedit.h"
#include "../widgets/fakelineedit.h"
namespace pv {
@ -55,6 +55,10 @@ namespace view {
class View;
}
namespace widgets {
class FakeLineEdit;
}
namespace dock {
class SearchDock : public QWidget
@ -86,7 +90,7 @@ private:
QPushButton _pre_button;
QPushButton _nxt_button;
FakeLineEdit* _search_value;
widgets::FakeLineEdit* _search_value;
};
} // namespace dock

View File

@ -23,6 +23,7 @@
#include "triggerdock.h"
#include "../sigsession.h"
#include "../device/devinst.h"
#include <QObject>
#include <QGridLayout>
@ -209,7 +210,7 @@ void TriggerDock::simple_trigger()
void TriggerDock::adv_trigger()
{
if (strcmp(_session.get_device()->driver->name, "DSLogic") == 0) {
if (strcmp(_session.get_device()->dev_inst()->driver->name, "DSLogic") == 0) {
widget_enable();
ds_trigger_set_mode(ADV_TRIGGER);
_session.set_adv_trigger(true);
@ -341,7 +342,7 @@ void TriggerDock::pos_changed(int pos)
void TriggerDock::device_change()
{
if (strcmp(_session.get_device()->driver->name, "DSLogic") != 0) {
if (strcmp(_session.get_device()->dev_inst()->driver->name, "DSLogic") != 0) {
position_spinBox->setDisabled(true);
position_slider->setDisabled(true);
} else {

View File

@ -21,12 +21,14 @@
*/
#ifdef ENABLE_SIGROKDECODE
#ifdef ENABLE_DECODE
#include <libsigrokdecode/libsigrokdecode.h>
#include "dock/protocoldock.h"
#endif
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/shared_ptr.hpp>
#include <QAction>
#include <QApplication>
@ -41,27 +43,32 @@
#include <QDockWidget>
#include <QDebug>
#include <QDesktopWidget>
#include <QKeyEvent>
#include <QEvent>
#include "mainwindow.h"
#include "devicemanager.h"
#include "device/device.h"
#include "device/file.h"
#include "dialogs/about.h"
#include "dialogs/connect.h"
#include "dialogs/storeprogress.h"
#include "toolbars/samplingbar.h"
#include "toolbars/devicebar.h"
#include "toolbars/trigbar.h"
#include "toolbars/filebar.h"
#include "toolbars/logobar.h"
#include "dock/protocoldock.h"
#include "dock/triggerdock.h"
#include "dock/dsotriggerdock.h"
#include "dock/measuredock.h"
#include "dock/searchdock.h"
#include "view/view.h"
#include "view/trace.h"
#include "view/signal.h"
#include "view/dsosignal.h"
/* __STDC_FORMAT_MACROS is required for PRIu64 and friends (in C++). */
#define __STDC_FORMAT_MACROS
@ -69,9 +76,13 @@
#include <stdint.h>
#include <stdarg.h>
#include <glib.h>
#include <list>
#include <libsigrok4DSLogic/libsigrok.h>
using namespace std;
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
using std::list;
using std::vector;
namespace pv {
@ -110,103 +121,10 @@ void MainWindow::setup_ui()
_vertical_layout->setContentsMargins(0, 0, 0, 0);
setCentralWidget(_central_widget);
// // Setup the menu bar
// _menu_bar = new QMenuBar(this);
// _menu_bar->setGeometry(QRect(0, 0, 400, 25));
// // File Menu
// _menu_file = new QMenu(_menu_bar);
// _menu_file->setTitle(QApplication::translate(
// "MainWindow", "&File", 0, QApplication::UnicodeUTF8));
// _action_open = new QAction(this);
// _action_open->setText(QApplication::translate(
// "MainWindow", "&Open...", 0, QApplication::UnicodeUTF8));
// _action_open->setIcon(QIcon::fromTheme("document-open",
// QIcon(":/icons/document-open.png")));
// _action_open->setObjectName(QString::fromUtf8("actionOpen"));
// _menu_file->addAction(_action_open);
// _menu_file->addSeparator();
// _action_connect = new QAction(this);
// _action_connect->setText(QApplication::translate(
// "MainWindow", "&Connect to Device...", 0,
// QApplication::UnicodeUTF8));
// _action_connect->setObjectName(QString::fromUtf8("actionConnect"));
// _menu_file->addAction(_action_connect);
// _menu_file->addSeparator();
// _action_quit = new QAction(this);
// _action_quit->setText(QApplication::translate(
// "MainWindow", "&Quit", 0, QApplication::UnicodeUTF8));
// _action_quit->setIcon(QIcon::fromTheme("application-exit",
// QIcon(":/icons/application-exit.png")));
// _action_quit->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
// _action_quit->setObjectName(QString::fromUtf8("actionQuit"));
// _menu_file->addAction(_action_quit);
// // View Menu
// _menu_view = new QMenu(_menu_bar);
// _menu_view->setTitle(QApplication::translate(
// "MainWindow", "&View", 0, QApplication::UnicodeUTF8));
// _action_view_zoom_in = new QAction(this);
// _action_view_zoom_in->setText(QApplication::translate(
// "MainWindow", "Zoom &In", 0, QApplication::UnicodeUTF8));
// _action_view_zoom_in->setIcon(QIcon::fromTheme("zoom-in",
// QIcon(":/icons/zoom-in.png")));
// _action_view_zoom_in->setObjectName(
// QString::fromUtf8("actionViewZoomIn"));
// _menu_view->addAction(_action_view_zoom_in);
// _action_view_zoom_out = new QAction(this);
// _action_view_zoom_out->setText(QApplication::translate(
// "MainWindow", "Zoom &Out", 0, QApplication::UnicodeUTF8));
// _action_view_zoom_out->setIcon(QIcon::fromTheme("zoom-out",
// QIcon(":/icons/zoom-out.png")));
// _action_view_zoom_out->setObjectName(
// QString::fromUtf8("actionViewZoomOut"));
// _menu_view->addAction(_action_view_zoom_out);
// _menu_view->addSeparator();
// _action_view_show_cursors = new QAction(this);
// _action_view_show_cursors->setCheckable(true);
// _action_view_show_cursors->setChecked(_view->cursors_shown());
// _action_view_show_cursors->setShortcut(QKeySequence(Qt::Key_C));
// _action_view_show_cursors->setObjectName(
// QString::fromUtf8("actionViewShowCursors"));
// _action_view_show_cursors->setText(QApplication::translate(
// "MainWindow", "Show &Cursors", 0, QApplication::UnicodeUTF8));
// _menu_view->addAction(_action_view_show_cursors);
// // Help Menu
// _menu_help = new QMenu(_menu_bar);
// _menu_help->setTitle(QApplication::translate(
// "MainWindow", "&Help", 0, QApplication::UnicodeUTF8));
// _action_about = new QAction(this);
// _action_about->setObjectName(QString::fromUtf8("actionAbout"));
// _action_about->setText(QApplication::translate(
// "MainWindow", "&About...", 0, QApplication::UnicodeUTF8));
// _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);
//QMenuBar *_void_menu = new QMenuBar(this);
//setMenuBar(_void_menu);
//QMetaObject::connectSlotsByName(this);
// Setup the sampling bar
_sampling_bar = new toolbars::SamplingBar(this);
_sampling_bar = new toolbars::SamplingBar(_session, this);
_trig_bar = new toolbars::TrigBar(this);
_file_bar = new toolbars::FileBar(_session, this);
_device_bar = new toolbars::DeviceBar(this);
_logo_bar = new toolbars::LogoBar(_session, this);
connect(_trig_bar, SIGNAL(on_protocol(bool)), this,
@ -217,9 +135,14 @@ void MainWindow::setup_ui()
SLOT(on_measure(bool)));
connect(_trig_bar, SIGNAL(on_search(bool)), this,
SLOT(on_search(bool)));
connect(_file_bar, SIGNAL(load_file(QString)), this,
SLOT(load_file(QString)));
connect(_file_bar, SIGNAL(save()), this,
SLOT(on_save()));
connect(_file_bar, SIGNAL(on_screenShot()), this,
SLOT(on_screenShot()));
#ifdef ENABLE_DECODE
// protocol dock
_protocol_dock=new QDockWidget(tr("Protocol"),this);
_protocol_dock->setFeatures(QDockWidget::NoDockWidgetFeatures);
@ -228,6 +151,8 @@ void MainWindow::setup_ui()
//dock::ProtocolDock *_protocol_widget = new dock::ProtocolDock(_protocol_dock, _session);
_protocol_widget = new dock::ProtocolDock(_protocol_dock, _session);
_protocol_dock->setWidget(_protocol_widget);
qDebug() << "Protocol decoder enabled!\n";
#endif
// trigger dock
_trigger_dock=new QDockWidget(tr("Trigger Setting..."),this);
_trigger_dock->setFeatures(QDockWidget::NoDockWidgetFeatures);
@ -248,41 +173,25 @@ void MainWindow::setup_ui()
_view = new pv::view::View(_session, this);
_vertical_layout->addWidget(_view);
// Populate the device list and select the initially selected device
update_device_list();
connect(_device_bar, SIGNAL(device_selected()), this,
SLOT(device_selected()));
// connect(_device_bar, SIGNAL(device_selected()), this,
// SLOT(init()));
connect(_device_bar, SIGNAL(device_updated()), this,
SLOT(update()));
connect(_sampling_bar, SIGNAL(device_reload()), this,
SLOT(init()));
connect(_sampling_bar, SIGNAL(device_selected()), this,
SLOT(update_device_list()));
connect(_sampling_bar, SIGNAL(device_updated()), &_session,
SLOT(reload()));
connect(_sampling_bar, SIGNAL(run_stop()), this,
SLOT(run_stop()));
connect(_sampling_bar, SIGNAL(instant_stop()), this,
SLOT(instant_stop()));
connect(_sampling_bar, SIGNAL(update_scale()), _view,
SLOT(update_scale()));
connect(_dso_trigger_widget, SIGNAL(set_trig_pos(quint64)), _view,
SLOT(set_trig_pos(quint64)));
addToolBar(_sampling_bar);
addToolBar(_trig_bar);
addToolBar(_device_bar);
addToolBar(_file_bar);
addToolBar(_logo_bar);
// Setup the dockWidget
// protocol dock
// _protocol_dock=new QDockWidget(tr("Protocol"),this);
// _protocol_dock->setFeatures(QDockWidget::NoDockWidgetFeatures);
// _protocol_dock->setAllowedAreas(Qt::RightDockWidgetArea);
// _protocol_dock->setVisible(false);
// //dock::ProtocolDock *_protocol_widget = new dock::ProtocolDock(_protocol_dock, _session);
// _protocol_widget = new dock::ProtocolDock(_protocol_dock, _session);
// _protocol_dock->setWidget(_protocol_widget);
// // trigger dock
// _trigger_dock=new QDockWidget(tr("Trigger Setting..."),this);
// _trigger_dock->setFeatures(QDockWidget::NoDockWidgetFeatures);
// _trigger_dock->setAllowedAreas(Qt::RightDockWidgetArea);
// _trigger_dock->setVisible(false);
// dock::TriggerDock *_trigger_widget = new dock::TriggerDock(_trigger_dock, _session);
// _trigger_dock->setWidget(_trigger_widget);
// measure dock
_measure_dock=new QDockWidget(tr("Measurement"),this);
_measure_dock->setFeatures(QDockWidget::NoDockWidgetFeatures);
@ -300,10 +209,9 @@ void MainWindow::setup_ui()
_search_widget = new dock::SearchDock(_search_dock, *_view, _session);
_search_dock->setWidget(_search_widget);
_protocol_dock->setObjectName(tr("protocolDock"));
_trigger_dock->setObjectName(tr("triggerDock"));
#ifdef ENABLE_DECODE
addDockWidget(Qt::RightDockWidgetArea,_protocol_dock);
#endif
addDockWidget(Qt::RightDockWidgetArea,_trigger_dock);
addDockWidget(Qt::RightDockWidgetArea,_dso_trigger_dock);
addDockWidget(Qt::RightDockWidgetArea, _measure_dock);
@ -322,8 +230,8 @@ void MainWindow::setup_ui()
SLOT(device_detach()));
connect(&_session, SIGNAL(test_data_error()), this,
SLOT(test_data_error()));
connect(&_session, SIGNAL(dso_ch_changed(uint16_t)), this,
SLOT(dso_ch_changed(uint16_t)));
connect(&_session, SIGNAL(sample_rate_changed(uint64_t)), _sampling_bar,
SLOT(set_sample_rate(uint64_t)));
connect(_view, SIGNAL(cursor_update()), _measure_widget,
SLOT(cursor_update()));
@ -331,28 +239,28 @@ void MainWindow::setup_ui()
SLOT(cursor_moved()));
connect(_view, SIGNAL(mouse_moved()), _measure_widget,
SLOT(mouse_moved()));
}
connect(_view, SIGNAL(mode_changed()), this,
SLOT(update_device_list()));
void MainWindow::init()
{
_protocol_widget->del_all_protocol();
_trigger_widget->device_change();
if (_session.get_device())
_session.init_signals(_session.get_device());
if (_session.get_device()->mode == DSO) {
_sampling_bar->set_record_length(DefaultDSODepth*2);
_sampling_bar->set_sample_rate(DefaultDSORate*2);
_sampling_bar->enable_toggle(false);
_view->hDial_changed(0);
} else if(_session.get_device()->mode == LOGIC) {
_sampling_bar->enable_toggle(true);
}
}
// event filter
_view->installEventFilter(this);
_sampling_bar->installEventFilter(this);
_trig_bar->installEventFilter(this);
_file_bar->installEventFilter(this);
_logo_bar->installEventFilter(this);
_dso_trigger_dock->installEventFilter(this);
_trigger_dock->installEventFilter(this);
#ifdef ENABLE_DECODE
_protocol_dock->installEventFilter(this);
#endif
_measure_dock->installEventFilter(this);
_search_dock->installEventFilter(this);
void MainWindow::update()
{
if (_session.get_device())
_session.update_signals(_session.get_device());
// Populate the device list and select the initially selected device
_session.set_default_device();
update_device_list();
_session.start_hotplug_proc(boost::bind(&MainWindow::session_error, this,
QString("Hotplug failed"), _1));
}
void MainWindow::session_error(
@ -363,92 +271,55 @@ void MainWindow::session_error(
Q_ARG(QString, info_text));
}
void MainWindow::update_device_list(struct sr_dev_inst *selected_device)
void MainWindow::update_device_list()
{
assert(_device_bar);
assert(_sampling_bar);
const list<sr_dev_inst*> &devices = _device_manager.devices();
_device_bar->set_device_list(devices);
_view->show_trig_cursor(false);
_trigger_widget->device_change();
#ifdef ENABLE_DECODE
_protocol_widget->del_all_protocol();
#endif
_trig_bar->close_all();
if (!selected_device && !devices.empty()) {
// Fall back to the first device in the list.
selected_device = devices.front();
// Try and find the demo device and select that by default
BOOST_FOREACH (struct sr_dev_inst *sdi, devices)
if (strcmp(sdi->driver->name, "DSLogic") == 0) {
selected_device = sdi;
}
}
if (selected_device) {
if (_session.set_device(selected_device) == SR_OK) {
_device_bar->set_selected_device(selected_device, false);
_sampling_bar->set_device(selected_device);
_sampling_bar->update_sample_rate_selector();
_logo_bar->dslogic_connected(strcmp(selected_device->driver->name, "DSLogic") == 0);
init();
if (_session.get_device()->dev_inst()->mode == DSO) {
_sampling_bar->enable_toggle(false);
} else {
show_session_error("Open Device Failed",
"the selected device can't be opened!");
}
_sampling_bar->enable_toggle(true);
}
// #ifdef HAVE_LA_DSLOGIC
_session.start_hotplug_proc(boost::bind(&MainWindow::session_error, this,
QString("Hotplug failed"), _1));
_session.start_dso_ctrl_proc(boost::bind(&MainWindow::session_error, this,
QString("Hotplug failed"), _1));
// #endif
shared_ptr<pv::device::DevInst> selected_device = _session.get_device();
_device_manager.add_device(selected_device);
_sampling_bar->set_device_list(_device_manager.devices(), selected_device);
_session.init_signals();
if(dynamic_pointer_cast<pv::device::File>(selected_device)) {
const QString errorMessage(
QString("Failed to capture file data!"));
const QString infoMessage;
_session.start_capture(true, boost::bind(&MainWindow::session_error, this,
errorMessage, infoMessage));
}
void MainWindow::device_change()
{
assert(_device_bar);
struct sr_dev_inst *selected_device;
const list<sr_dev_inst*> &devices = _device_manager.devices();
_device_bar->set_device_list(devices);
// Fall back to the first device in the list.
selected_device = devices.front();
// Try and find the demo device and select that by default
BOOST_FOREACH (struct sr_dev_inst *sdi, devices)
if (strcmp(sdi->driver->name, "DSLogic") == 0) {
selected_device = sdi;
}
if (_session.set_device(selected_device) == SR_OK) {;
_device_bar->set_selected_device(selected_device, true);
_sampling_bar->set_device(selected_device);
_sampling_bar->update_sample_rate_selector();
_logo_bar->dslogic_connected(strcmp(selected_device->driver->name, "DSLogic") == 0);
init();
} else {
// show_session_error("Open Device Failed",
// "the selected device can't be opened!");
device_detach();
}
// #ifdef HAVE_LA_DSLOGIC
_session.stop_hotplug_proc();
_session.start_hotplug_proc(boost::bind(&MainWindow::session_error, this,
QString("Hotplug failed"), _1));
// #endif
if (strcmp(selected_device->dev_inst()->driver->name, "DSLogic") == 0)
_logo_bar->dslogic_connected(true);
else
_logo_bar->dslogic_connected(false);
}
void MainWindow::load_file(QString file_name)
{
const QString errorMessage(
QString("Failed to load file %1").arg(file_name));
const QString infoMessage;
_session.load_file(file_name.toStdString(),
boost::bind(&MainWindow::session_error, this,
errorMessage, infoMessage));
try {
_session.set_file(file_name.toStdString());
} catch(QString e) {
show_session_error(tr("Failed to load ") + file_name, e);
_session.set_default_device();
update_device_list();
return;
}
update_device_list();
}
void MainWindow::show_session_error(
@ -462,50 +333,9 @@ void MainWindow::show_session_error(
msg.exec();
}
void MainWindow::device_selected()
{
if (_session.set_device(_device_bar->get_selected_device()) == SR_OK) {;
_sampling_bar->set_device(_device_bar->get_selected_device());
_sampling_bar->update_sample_rate_selector();
_view->show_trig_cursor(false);
_trigger_dock->setVisible(false);
_dso_trigger_dock->setVisible(false);
_protocol_dock->setVisible(false);
_measure_dock->setVisible(false);
_search_dock->setVisible(false);
init();
} else {
show_session_error("Open Device Failed",
"the selected device can't be opened!");
}
if (_device_bar->get_selected_device()->mode == DSO) {
QMessageBox msg(this);
msg.setText("Zero Adjustment");
msg.setInformativeText("Please left both of channels unconnect for zero adjustment!");
msg.setStandardButtons(QMessageBox::Ok);
msg.setIcon(QMessageBox::Warning);
msg.exec();
int ret = sr_config_set(_device_bar->get_selected_device(), SR_CONF_ZERO, g_variant_new_boolean(TRUE));
if (ret != SR_OK) {
QMessageBox msg(this);
msg.setText("Zero Adjustment Issue");
msg.setInformativeText("Can't send out the command of zero adjustment!");
msg.setStandardButtons(QMessageBox::Ok);
msg.setIcon(QMessageBox::Warning);
msg.exec();
} else {
run_stop();
g_usleep(100000);
run_stop();
}
}
}
void MainWindow::device_attach()
{
_session.stop_hotplug_proc();
//_session.stop_hot_plug_proc();
if (_session.get_capture_state() == SigSession::Running)
_session.stop_capture();
@ -517,12 +347,13 @@ void MainWindow::device_attach()
if (*driver)
_device_manager.driver_scan(*driver);
device_change();
_session.set_default_device();
update_device_list();
}
void MainWindow::device_detach()
{
_session.stop_hotplug_proc();
//_session.stop_hot_plug_proc();
if (_session.get_capture_state() == SigSession::Running)
_session.stop_capture();
@ -534,18 +365,19 @@ void MainWindow::device_detach()
if (*driver)
_device_manager.driver_scan(*driver);
device_change();
_session.set_default_device();
update_device_list();
}
void MainWindow::run_stop()
{
_sampling_bar->enable_run_stop(false);
_sampling_bar->enable_instant(false);
switch(_session.get_capture_state()) {
case SigSession::Init:
case SigSession::Stopped:
_view->show_trig_cursor(false);
_session.set_total_sample_len(_sampling_bar->get_record_length());
_session.start_capture(_sampling_bar->get_record_length(),
_session.start_capture(false,
boost::bind(&MainWindow::session_error, this,
QString("Capture failed"), _1));
break;
@ -558,29 +390,25 @@ void MainWindow::run_stop()
_sampling_bar->enable_run_stop(true);
}
void MainWindow::dso_ch_changed(uint16_t num)
void MainWindow::instant_stop()
{
if(num == 1) {
_sampling_bar->set_record_length(DefaultDSODepth*2);
_sampling_bar->set_sample_rate(DefaultDSORate*2);
_session.set_total_sample_len(_sampling_bar->get_record_length());
if (_session.get_capture_state() == SigSession::Running) {
_session.stop_capture();
_session.start_capture(_sampling_bar->get_record_length(),
_sampling_bar->enable_instant(false);
_sampling_bar->enable_run_stop(false);
switch(_session.get_capture_state()) {
case SigSession::Init:
case SigSession::Stopped:
_view->show_trig_cursor(false);
_session.start_capture(true,
boost::bind(&MainWindow::session_error, this,
QString("Capture failed"), _1));
}
} else {
_sampling_bar->set_record_length(DefaultDSODepth);
_sampling_bar->set_sample_rate(DefaultDSORate);
_session.set_total_sample_len(_sampling_bar->get_record_length());
if (_session.get_capture_state() == SigSession::Running) {
break;
case SigSession::Running:
_session.stop_capture();
_session.start_capture(_sampling_bar->get_record_length(),
boost::bind(&MainWindow::session_error, this,
QString("Capture failed"), _1));
}
break;
}
g_usleep(1000);
_sampling_bar->enable_instant(true);
}
void MainWindow::test_data_error()
@ -596,12 +424,11 @@ void MainWindow::test_data_error()
void MainWindow::capture_state_changed(int state)
{
if (_session.get_device()->mode != DSO) {
if (_session.get_device()->dev_inst()->mode != DSO) {
_sampling_bar->enable_toggle(state != SigSession::Running);
_trig_bar->enable_toggle(state != SigSession::Running);
_measure_dock->widget()->setEnabled(state != SigSession::Running);
}
_device_bar->enable_toggle(state != SigSession::Running);
_file_bar->enable_toggle(state != SigSession::Running);
_sampling_bar->set_sampling(state == SigSession::Running);
_view->on_state_changed(state != SigSession::Running);
@ -609,16 +436,21 @@ void MainWindow::capture_state_changed(int state)
void MainWindow::on_protocol(bool visible)
{
#ifdef ENABLE_DECODE
_protocol_dock->setVisible(visible);
#endif
}
void MainWindow::on_trigger(bool visible)
{
if (_session.get_device()->mode != DSO)
if (_session.get_device()->dev_inst()->mode != DSO) {
_trigger_dock->setVisible(visible);
else
_dso_trigger_dock->setVisible(false);
} else {
_trigger_dock->setVisible(false);
_dso_trigger_dock->setVisible(visible);
}
}
void MainWindow::on_measure(bool visible)
{
@ -648,4 +480,104 @@ void MainWindow::on_screenShot()
pixmap.save(fileName, format.toAscii());
}
void MainWindow::on_save()
{
using pv::dialogs::StoreProgress;
// Stop any currently running capture session
_session.stop_capture();
// Show the dialog
const QString file_name = QFileDialog::getSaveFileName(
this, tr("Save File"), "", tr("DSLogic Sessions (*.dsl)"));
if (file_name.isEmpty())
return;
StoreProgress *dlg = new StoreProgress(file_name, _session, this);
dlg->run();
}
bool MainWindow::eventFilter(QObject *object, QEvent *event)
{
(void) object;
if( event->type() == QEvent::KeyPress ) {
const vector< shared_ptr<view::Signal> > sigs(
_session.get_signals());
QKeyEvent *ke = (QKeyEvent *) event;
switch(ke->key()) {
case Qt::Key_S:
run_stop();
break;
case Qt::Key_I:
instant_stop();
break;
case Qt::Key_T:
if (_session.get_device()->dev_inst()->mode == DSO)
on_trigger(!_dso_trigger_dock->isVisible());
else
on_trigger(!_trigger_dock->isVisible());
break;
case Qt::Key_D:
on_protocol(!_protocol_dock->isVisible());
break;
case Qt::Key_M:
on_measure(!_measure_dock->isVisible());
break;
case Qt::Key_R:
on_search(!_search_dock->isVisible());
break;
case Qt::Key_O:
_sampling_bar->on_configure();
break;
case Qt::Key_PageUp:
_view->set_scale_offset(_view->scale(),
_view->offset() - _view->scale()*_view->viewport()->width());
break;
case Qt::Key_PageDown:
_view->set_scale_offset(_view->scale(),
_view->offset() + _view->scale()*_view->viewport()->width());
break;
case Qt::Key_Left:
_view->zoom(1);
break;
case Qt::Key_Right:
_view->zoom(-1);
break;
case Qt::Key_Up:
BOOST_FOREACH(const shared_ptr<view::Signal> s, sigs) {
shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(s)) {
if (dsoSig->get_vDialActive()) {
dsoSig->go_vDialNext();
update();
break;
}
}
}
break;
case Qt::Key_Down:
BOOST_FOREACH(const shared_ptr<view::Signal> s, sigs) {
shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(s)) {
if (dsoSig->get_vDialActive()) {
dsoSig->go_vDialPre();
update();
break;
}
}
}
break;
default:
QWidget::keyPressEvent((QKeyEvent *)event);
}
return true;
}
return false;
}
} // namespace pv

View File

@ -45,7 +45,6 @@ class DeviceManager;
namespace toolbars {
class SamplingBar;
class DeviceBar;
class TrigBar;
class FileBar;
class LogoBar;
@ -67,10 +66,6 @@ class MainWindow : public QMainWindow
{
Q_OBJECT
private:
static const int DefaultDSODepth = 8192;
static const int DefaultDSORate = 100000000;
public:
explicit MainWindow(DeviceManager &device_manager,
const char *open_file_name = NULL,
@ -81,36 +76,30 @@ private:
void session_error(const QString text, const QString info_text);
bool eventFilter(QObject *object, QEvent *event);
private slots:
void load_file(QString file_name);
/**
* Updates the device list in the sampling bar, and updates the
* selection.
* @param selected_device The device to select, or NULL if the
* first device in the device list should be selected.
*/
void update_device_list(
struct sr_dev_inst *selected_device = NULL);
void device_change();
private slots:
void load_file(QString file_name);
void update_device_list();
void show_session_error(
const QString text, const QString info_text);
void device_selected();
void run_stop();
void instant_stop();
void test_data_error();
void capture_state_changed(int state);
void init();
void update();
void on_protocol(bool visible);
void on_trigger(bool visible);
@ -121,15 +110,14 @@ private slots:
void on_screenShot();
void on_save();
/*
* hotplug slot function
*/
void device_attach();
void device_detach();
/* */
void dso_ch_changed(uint16_t num);
private:
DeviceManager &_device_manager;
@ -155,13 +143,15 @@ private:
QVBoxLayout *_vertical_layout;
toolbars::SamplingBar *_sampling_bar;
toolbars::DeviceBar *_device_bar;
toolbars::TrigBar *_trig_bar;
toolbars::FileBar *_file_bar;
toolbars::LogoBar *_logo_bar;
#ifdef ENABLE_DECODE
QDockWidget *_protocol_dock;
dock::ProtocolDock *_protocol_widget;
#endif
QDockWidget *_trigger_dock;
QDockWidget *_dso_trigger_dock;
dock::TriggerDock *_trigger_widget;

View File

@ -20,9 +20,16 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <boost/foreach.hpp>
#include <QFormLayout>
#include <pv/prop/property.h>
#include "binding.h"
using boost::shared_ptr;
namespace pv {
namespace prop {
namespace binding {
@ -32,6 +39,58 @@ const std::vector< boost::shared_ptr<Property> >& Binding::properties()
return _properties;
}
void Binding::commit()
{
BOOST_FOREACH(shared_ptr<pv::prop::Property> p, _properties) {
assert(p);
p->commit();
}
}
void Binding::add_properties_to_form(QFormLayout *layout,
bool auto_commit) const
{
assert(layout);
BOOST_FOREACH(shared_ptr<pv::prop::Property> p, _properties)
{
assert(p);
QWidget *const widget = p->get_widget(layout->parentWidget(),
auto_commit);
if (p->labeled_widget())
layout->addRow(widget);
else
layout->addRow(p->name(), widget);
}
}
QWidget* Binding::get_property_form(QWidget *parent,
bool auto_commit) const
{
QWidget *const form = new QWidget(parent);
QFormLayout *const layout = new QFormLayout(form);
form->setLayout(layout);
add_properties_to_form(layout, auto_commit);
return form;
}
QString Binding::print_gvariant(GVariant *const gvar)
{
QString s;
if (g_variant_is_of_type(gvar, G_VARIANT_TYPE("s")))
s = QString::fromUtf8(g_variant_get_string(gvar, NULL));
else
{
gchar *const text = g_variant_print(gvar, FALSE);
s = QString::fromUtf8(text);
g_free(text);
}
return s;
}
} // binding
} // prop
} // pv

View File

@ -24,9 +24,14 @@
#ifndef DSLOGIC_PV_PROP_BINDING_BINDING_H
#define DSLOGIC_PV_PROP_BINDING_BINDING_H
#include <glib.h>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <QString>
class QFormLayout;
class QWidget;
namespace pv {
@ -41,6 +46,16 @@ class Binding
public:
const std::vector< boost::shared_ptr<Property> >& properties();
void commit();
void add_properties_to_form(QFormLayout *layout,
bool auto_commit = false) const;
QWidget* get_property_form(QWidget *parent,
bool auto_commit = false) const;
static QString print_gvariant(GVariant *const gvar);
protected:
std::vector< boost::shared_ptr<Property> > _properties;

View File

@ -0,0 +1,148 @@
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2013 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 <libsigrokdecode/libsigrokdecode.h>
#include "decoderoptions.h"
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/none_t.hpp>
#include <pv/data/decoderstack.h>
#include <pv/data/decode/decoder.h>
#include <pv/prop/double.h>
#include <pv/prop/enum.h>
#include <pv/prop/int.h>
#include <pv/prop/string.h>
using boost::bind;
using boost::none;
using boost::shared_ptr;
using std::make_pair;
using std::map;
using std::pair;
using std::string;
using std::vector;
namespace pv {
namespace prop {
namespace binding {
DecoderOptions::DecoderOptions(
shared_ptr<pv::data::DecoderStack> decoder_stack,
shared_ptr<data::decode::Decoder> decoder) :
_decoder_stack(decoder_stack),
_decoder(decoder)
{
assert(_decoder);
const srd_decoder *const dec = _decoder->decoder();
assert(dec);
for (GSList *l = dec->options; l; l = l->next)
{
const srd_decoder_option *const opt =
(srd_decoder_option*)l->data;
const QString name = QString::fromUtf8(opt->desc);
const Property::Getter getter = bind(
&DecoderOptions::getter, this, opt->id);
const Property::Setter setter = bind(
&DecoderOptions::setter, this, opt->id, _1);
shared_ptr<Property> prop;
if (opt->values)
prop = bind_enum(name, opt, getter, setter);
else if (g_variant_is_of_type(opt->def, G_VARIANT_TYPE("d")))
prop = shared_ptr<Property>(new Double(name, 2, "",
none, none, getter, setter));
else if (g_variant_is_of_type(opt->def, G_VARIANT_TYPE("x")))
prop = shared_ptr<Property>(
new Int(name, "", none, getter, setter));
else if (g_variant_is_of_type(opt->def, G_VARIANT_TYPE("s")))
prop = shared_ptr<Property>(
new String(name, getter, setter));
else
continue;
_properties.push_back(prop);
}
}
shared_ptr<Property> DecoderOptions::bind_enum(
const QString &name, const srd_decoder_option *option,
Property::Getter getter, Property::Setter setter)
{
vector< pair<GVariant*, QString> > values;
for (GSList *l = option->values; l; l = l->next) {
GVariant *const var = (GVariant*)l->data;
assert(var);
values.push_back(make_pair(var, print_gvariant(var)));
}
return shared_ptr<Property>(new Enum(name, values, getter, setter));
}
GVariant* DecoderOptions::getter(const char *id)
{
GVariant *val = NULL;
assert(_decoder);
// Get the value from the hash table if it is already present
const map<string, GVariant*>& options = _decoder->options();
map<string, GVariant*>::const_iterator iter = options.find(id);
if (iter != options.end())
val = (*iter).second;
else
{
assert(_decoder->decoder());
// Get the default value if not
for (GSList *l = _decoder->decoder()->options; l; l = l->next)
{
const srd_decoder_option *const opt =
(srd_decoder_option*)l->data;
if (strcmp(opt->id, id) == 0) {
val = opt->def;
break;
}
}
}
if (val)
g_variant_ref(val);
return val;
}
void DecoderOptions::setter(const char *id, GVariant *value)
{
assert(_decoder);
_decoder->set_option(id, value);
}
} // binding
} // prop
} // pv

View File

@ -0,0 +1,66 @@
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2013 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 DSLOGIC_PV_PROP_BINDING_DECODEROPTIONS_H
#define DSLOGIC_PV_PROP_BINDING_DECODEROPTIONS_H
#include "binding.h"
#include <pv/prop/property.h>
struct srd_decoder_option;
namespace pv {
namespace data {
class DecoderStack;
namespace decode {
class Decoder;
}
}
namespace prop {
namespace binding {
class DecoderOptions : public Binding
{
public:
DecoderOptions(boost::shared_ptr<pv::data::DecoderStack> decoder_stack,
boost::shared_ptr<pv::data::decode::Decoder> decoder);
private:
static boost::shared_ptr<Property> bind_enum(const QString &name,
const srd_decoder_option *option,
Property::Getter getter, Property::Setter setter);
GVariant* getter(const char *id);
void setter(const char *id, GVariant *value);
private:
boost::shared_ptr<pv::data::DecoderStack> _decoder_stack;
boost::shared_ptr<pv::data::decode::Decoder> _decoder;
};
} // binding
} // prop
} // pv
#endif // DSLOGIC_PV_PROP_BINDING_DECODEROPTIONS_H

View File

@ -0,0 +1,274 @@
/*
* This file is part of the DSLogic-gui project.
* DSLogic-gui is based on PulseView.
*
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
* Copyright (C) 2013 DreamSourceLab <dreamsourcelab@dreamsourcelab.com>
*
* 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/bind.hpp>
#include <QDebug>
#include <QObject>
#include <stdint.h>
#include "deviceoptions.h"
#include <pv/prop/bool.h>
#include <pv/prop/double.h>
#include <pv/prop/enum.h>
#include <pv/prop/int.h>
using namespace boost;
using namespace std;
namespace pv {
namespace prop {
namespace binding {
DeviceOptions::DeviceOptions(struct sr_dev_inst *sdi) :
_sdi(sdi)
{
GVariant *gvar_opts, *gvar_list;
gsize num_opts;
if ((sr_config_list(sdi->driver, sdi, NULL, SR_CONF_DEVICE_CONFIGS,
&gvar_opts) != SR_OK))
/* Driver supports no device instance options. */
return;
const int *const options = (const int32_t *)g_variant_get_fixed_array(
gvar_opts, &num_opts, sizeof(int32_t));
for (unsigned int i = 0; i < num_opts; i++) {
const struct sr_config_info *const info =
sr_config_info_get(options[i]);
if (!info)
continue;
const int key = info->key;
if(sr_config_list(_sdi->driver, _sdi, NULL, key, &gvar_list) != SR_OK)
gvar_list = NULL;
const QString name(info->name);
switch(key)
{
case SR_CONF_SAMPLERATE:
bind_samplerate(name, gvar_list);
break;
case SR_CONF_CAPTURE_RATIO:
bind_int(name, key, "%", pair<int64_t, int64_t>(0, 100));
break;
case SR_CONF_PATTERN_MODE:
case SR_CONF_BUFFERSIZE:
case SR_CONF_TRIGGER_SOURCE:
case SR_CONF_FILTER:
case SR_CONF_COUPLING:
case SR_CONF_EN_CH:
case SR_CONF_OPERATION_MODE:
case SR_CONF_THRESHOLD:
case SR_CONF_ZERO:
bind_enum(name, key, gvar_list);
break;
case SR_CONF_RLE:
bind_bool(name, key);
break;
case SR_CONF_CLOCK_TYPE:
case SR_CONF_CLOCK_EDGE:
bind_bool(name, key);
break;
case SR_CONF_TIMEBASE:
bind_enum(name, key, gvar_list, print_timebase);
break;
case SR_CONF_VDIV:
bind_enum(name, key, gvar_list, print_vdiv);
break;
default:
gvar_list = NULL;
}
if (gvar_list)
g_variant_unref(gvar_list);
}
g_variant_unref(gvar_opts);
}
GVariant* DeviceOptions::config_getter(
const struct sr_dev_inst *sdi, int key)
{
GVariant *data = NULL;
if (sr_config_get(sdi->driver, sdi, NULL, NULL, key, &data) != SR_OK) {
qDebug() <<
"WARNING: Failed to get value of config id" << key;
return NULL;
}
return data;
}
void DeviceOptions::config_setter(
const struct sr_dev_inst *sdi, int key, GVariant* value)
{
if (sr_config_set(sdi, NULL, NULL, key, value) != SR_OK)
qDebug() << "WARNING: Failed to set value of sample rate";
}
void DeviceOptions::bind_bool(const QString &name, int key)
{
_properties.push_back(boost::shared_ptr<Property>(
new Bool(name, bind(config_getter, _sdi, key),
bind(config_setter, _sdi, key, _1))));
}
void DeviceOptions::bind_enum(const QString &name, int key,
GVariant *const gvar_list, boost::function<QString (GVariant*)> printer)
{
GVariant *gvar;
GVariantIter iter;
vector< pair<GVariant*, QString> > values;
assert(gvar_list);
g_variant_iter_init (&iter, gvar_list);
while ((gvar = g_variant_iter_next_value (&iter)))
values.push_back(make_pair(gvar, printer(gvar)));
_properties.push_back(boost::shared_ptr<Property>(
new Enum(name, values,
bind(config_getter, _sdi, key),
bind(config_setter, _sdi, key, _1))));
}
void DeviceOptions::bind_int(const QString &name, int key, QString suffix,
optional< std::pair<int64_t, int64_t> > range)
{
_properties.push_back(boost::shared_ptr<Property>(
new Int(name, suffix, range,
bind(config_getter, _sdi, key),
bind(config_setter, _sdi, key, _1))));
}
QString DeviceOptions::print_gvariant(GVariant *const gvar)
{
QString s;
if (g_variant_is_of_type(gvar, G_VARIANT_TYPE("s")))
s = QString(g_variant_get_string(gvar, NULL));
else
{
gchar *const text = g_variant_print(gvar, FALSE);
s = QString(text);
g_free(text);
}
return s;
}
void DeviceOptions::bind_samplerate(const QString &name,
GVariant *const gvar_list)
{
GVariant *gvar_list_samplerates;
assert(gvar_list);
if ((gvar_list_samplerates = g_variant_lookup_value(gvar_list,
"samplerate-steps", G_VARIANT_TYPE("at"))))
{
gsize num_elements;
const uint64_t *const elements =
(const uint64_t *)g_variant_get_fixed_array(
gvar_list_samplerates, &num_elements, sizeof(uint64_t));
assert(num_elements == 3);
_properties.push_back(boost::shared_ptr<Property>(
new Double(name, 0, QObject::tr("Hz"),
make_pair((double)elements[0], (double)elements[1]),
(double)elements[2],
bind(samplerate_double_getter, _sdi),
bind(samplerate_double_setter, _sdi, _1))));
g_variant_unref(gvar_list_samplerates);
}
else if ((gvar_list_samplerates = g_variant_lookup_value(gvar_list,
"samplerates", G_VARIANT_TYPE("at"))))
{
bind_enum(name, SR_CONF_SAMPLERATE,
gvar_list_samplerates, print_samplerate);
g_variant_unref(gvar_list_samplerates);
}
}
QString DeviceOptions::print_samplerate(GVariant *const gvar)
{
char *const s = sr_samplerate_string(
g_variant_get_uint64(gvar));
const QString qstring(s);
g_free(s);
return qstring;
}
GVariant* DeviceOptions::samplerate_double_getter(
const struct sr_dev_inst *sdi)
{
GVariant *const gvar = config_getter(sdi, SR_CONF_SAMPLERATE);
if(!gvar)
return NULL;
GVariant *const gvar_double = g_variant_new_double(
g_variant_get_uint64(gvar));
g_variant_unref(gvar);
return gvar_double;
}
void DeviceOptions::samplerate_double_setter(
struct sr_dev_inst *sdi, GVariant *value)
{
GVariant *const gvar = g_variant_new_uint64(
g_variant_get_double(value));
config_setter(sdi, SR_CONF_SAMPLERATE, gvar);
}
QString DeviceOptions::print_timebase(GVariant *const gvar)
{
uint64_t p, q;
g_variant_get(gvar, "(tt)", &p, &q);
return QString(sr_period_string(p * q));
}
QString DeviceOptions::print_vdiv(GVariant *const gvar)
{
uint64_t p, q;
g_variant_get(gvar, "(tt)", &p, &q);
return QString(sr_voltage_string(p, q));
}
} // binding
} // prop
} // pv

View File

@ -43,7 +43,7 @@ Bool::~Bool()
{
}
QWidget* Bool::get_widget(QWidget *parent)
QWidget* Bool::get_widget(QWidget *parent, bool auto_commit)
{
if (_check_box)
return _check_box;
@ -58,6 +58,10 @@ QWidget* Bool::get_widget(QWidget *parent)
g_variant_unref(value);
}
if (auto_commit)
connect(_check_box, SIGNAL(stateChanged(int)),
this, SLOT(on_state_changed(int)));
return _check_box;
}
@ -77,5 +81,11 @@ void Bool::commit()
_check_box->checkState() == Qt::Checked));
}
void Bool::on_state_changed(int)
{
commit();
}
} // prop
} // pv

View File

@ -33,16 +33,21 @@ namespace prop {
class Bool : public Property
{
Q_OBJECT;
public:
Bool(QString name, Getter getter, Setter setter);
virtual ~Bool();
QWidget* get_widget(QWidget *parent);
QWidget* get_widget(QWidget *parent, bool auto_commit);
bool labeled_widget() const;
void commit();
private slots:
void on_state_changed(int);
private:
QCheckBox *_check_box;
};

View File

@ -53,7 +53,7 @@ Double::~Double()
{
}
QWidget* Double::get_widget(QWidget *parent)
QWidget* Double::get_widget(QWidget *parent, bool auto_commit)
{
if (_spin_box)
return _spin_box;
@ -73,6 +73,10 @@ QWidget* Double::get_widget(QWidget *parent)
g_variant_unref(value);
}
if (auto_commit)
connect(_spin_box, SIGNAL(valueChanged(double)),
this, SLOT(on_value_changed(double)));
return _spin_box;
}
@ -86,5 +90,10 @@ void Double::commit()
_setter(g_variant_new_double(_spin_box->value()));
}
void Double::on_value_changed(double)
{
commit();
}
} // prop
} // pv

View File

@ -37,6 +37,8 @@ namespace prop {
class Double : public Property
{
Q_OBJECT;
public:
Double(QString name, int decimals, QString suffix,
boost::optional< std::pair<double, double> > range,
@ -46,10 +48,13 @@ public:
virtual ~Double();
QWidget* get_widget(QWidget *parent);
QWidget* get_widget(QWidget *parent, bool auto_commit);
void commit();
private slots:
void on_value_changed(double);
private:
const int _decimals;
const QString _suffix;

View File

@ -40,6 +40,9 @@ Enum::Enum(QString name,
_values(values),
_selector(NULL)
{
for (vector< pair<GVariant*, QString> >::const_iterator i =
_values.begin(); i != _values.end(); i++)
g_variant_ref((*i).first);
}
Enum::~Enum()
@ -48,12 +51,14 @@ Enum::~Enum()
g_variant_unref(_values[i].first);
}
QWidget* Enum::get_widget(QWidget *parent)
QWidget* Enum::get_widget(QWidget *parent, bool auto_commit)
{
if (_selector)
return _selector;
GVariant *const value = _getter ? _getter() : NULL;
if (!value)
return NULL;
_selector = new QComboBox(parent);
for (unsigned int i = 0; i < _values.size(); i++) {
@ -65,6 +70,10 @@ QWidget* Enum::get_widget(QWidget *parent)
g_variant_unref(value);
if (auto_commit)
connect(_selector, SIGNAL(currentIndexChanged(int)),
this, SLOT(on_current_item_changed(int)));
return _selector;
}
@ -82,5 +91,10 @@ void Enum::commit()
_setter((GVariant*)_selector->itemData(index).value<void*>());
}
void Enum::on_current_item_changed(int)
{
commit();
}
} // prop
} // pv

View File

@ -36,16 +36,21 @@ namespace prop {
class Enum : public Property
{
Q_OBJECT;
public:
Enum(QString name, std::vector<std::pair<GVariant*, QString> > values,
Getter getter, Setter setter);
virtual ~Enum();
QWidget* get_widget(QWidget *parent);
QWidget* get_widget(QWidget *parent, bool auto_commit);
void commit();
private slots:
void on_current_item_changed(int);
private:
const std::vector< std::pair<GVariant*, QString> > _values;

View File

@ -21,14 +21,31 @@
*/
#include <stdint.h>
#include <assert.h>
#include <math.h>
#include <QSpinBox>
#include "int.h"
using boost::optional;
using namespace std;
using namespace boost;
#define INT8_MIN (-0x7f - 1)
#define INT16_MIN (-0x7fff - 1)
#define INT32_MIN (-0x7fffffff - 1)
#define INT64_MIN (-0x7fffffffffffffff - 1)
#define INT8_MAX 0x7f
#define INT16_MAX 0x7fff
#define INT32_MAX 0x7fffffff
#define INT64_MAX 0x7fffffffffffffff
#define UINT8_MAX 0xff
#define UINT16_MAX 0xffff
#define UINT32_MAX 0xffffffff
#define UINT64_MAX 0xffffffffffffffff
namespace pv {
namespace prop {
@ -41,29 +58,96 @@ Int::Int(QString name,
Property(name, getter, setter),
_suffix(suffix),
_range(range),
_value(NULL),
_spin_box(NULL)
{
}
Int::~Int()
{
if (_value)
g_variant_unref(_value);
}
QWidget* Int::get_widget(QWidget *parent)
QWidget* Int::get_widget(QWidget *parent, bool auto_commit)
{
int64_t int_val = 0, range_min = 0, range_max = 0;
if (_spin_box)
return _spin_box;
if (_value)
g_variant_unref(_value);
_value = _getter ? _getter() : NULL;
if (!_value)
return NULL;
_spin_box = new QSpinBox(parent);
_spin_box->setSuffix(_suffix);
const GVariantType *const type = g_variant_get_type(_value);
assert(type);
if (g_variant_type_equal(type, G_VARIANT_TYPE_BYTE))
{
int_val = g_variant_get_byte(_value);
range_min = 0, range_max = UINT8_MAX;
}
else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT16))
{
int_val = g_variant_get_int16(_value);
range_min = INT16_MIN, range_max = INT16_MAX;
}
else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT16))
{
int_val = g_variant_get_uint16(_value);
range_min = 0, range_max = UINT16_MAX;
}
else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT32))
{
int_val = g_variant_get_int32(_value);
range_min = INT32_MIN, range_max = INT32_MAX;
}
else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT32))
{
int_val = g_variant_get_uint32(_value);
range_min = 0, range_max = UINT32_MAX;
}
else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT64))
{
int_val = g_variant_get_int64(_value);
range_min = INT64_MIN, range_max = INT64_MAX;
}
else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT64))
{
int_val = g_variant_get_uint64(_value);
range_min = 0, range_max = UINT64_MAX;
}
else
{
// Unexpected value type.
assert(0);
}
// @todo Sigrok supports 64-bit quantities, but Qt does not have a
// standard widget to allow the values to be modified over the full
// 64-bit range on 32-bit machines. To solve the issue we need a
// custom widget.
range_min = max(range_min, (int64_t)INT_MIN);
range_max = min(range_max, (int64_t)INT_MAX);
if (_range)
_spin_box->setRange((int)_range->first, (int)_range->second);
else
_spin_box->setRange((int)range_min, (int)range_max);
GVariant *const value = _getter ? _getter() : NULL;
if (value) {
_spin_box->setValue((int)g_variant_get_int64(value));
g_variant_unref(value);
}
_spin_box->setValue((int)int_val);
if (auto_commit)
connect(_spin_box, SIGNAL(valueChanged(int)),
this, SLOT(on_value_changed(int)));
return _spin_box;
}
@ -75,7 +159,44 @@ void Int::commit()
if (!_spin_box)
return;
_setter(g_variant_new_int64(_spin_box->value()));
assert(_value);
GVariant *new_value = NULL;
const GVariantType *const type = g_variant_get_type(_value);
assert(type);
if (g_variant_type_equal(type, G_VARIANT_TYPE_BYTE))
new_value = g_variant_new_byte(_spin_box->value());
else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT16))
new_value = g_variant_new_int16(_spin_box->value());
else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT16))
new_value = g_variant_new_uint16(_spin_box->value());
else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT32))
new_value = g_variant_new_int32(_spin_box->value());
else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT32))
new_value = g_variant_new_int32(_spin_box->value());
else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT64))
new_value = g_variant_new_int64(_spin_box->value());
else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT64))
new_value = g_variant_new_uint64(_spin_box->value());
else
{
// Unexpected value type.
assert(0);
}
assert(new_value);
g_variant_unref(_value);
g_variant_ref(new_value);
_value = new_value;
_setter(new_value);
}
void Int::on_value_changed(int)
{
commit();
}
} // prop

View File

@ -37,6 +37,8 @@ namespace prop {
class Int : public Property
{
Q_OBJECT;
public:
Int(QString name, QString suffix,
boost::optional< std::pair<int64_t, int64_t> > range,
@ -44,14 +46,18 @@ public:
virtual ~Int();
QWidget* get_widget(QWidget *parent);
QWidget* get_widget(QWidget *parent, bool auto_commit);
void commit();
private slots:
void on_value_changed(int);
private:
const QString _suffix;
const boost::optional< std::pair<int64_t, int64_t> > _range;
GVariant *_value;
QSpinBox *_spin_box;
};

View File

@ -36,8 +36,10 @@ class QWidget;
namespace pv {
namespace prop {
class Property
class Property : public QObject
{
Q_OBJECT;
public:
typedef boost::function<GVariant* ()> Getter;
typedef boost::function<void (GVariant*)> Setter;
@ -48,7 +50,8 @@ protected:
public:
const QString& name() const;
virtual QWidget* get_widget(QWidget *parent) = 0;
virtual QWidget* get_widget(QWidget *parent,
bool auto_commit = false) = 0;
virtual bool labeled_widget() const;
virtual void commit() = 0;

View File

@ -0,0 +1,77 @@
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2013 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 <QLineEdit>
#include <QSpinBox>
#include "string.h"
namespace pv {
namespace prop {
String::String(QString name,
Getter getter,
Setter setter) :
Property(name, getter, setter),
_line_edit(NULL)
{
}
QWidget* String::get_widget(QWidget *parent, bool auto_commit)
{
if (_line_edit)
return _line_edit;
GVariant *const value = _getter ? _getter() : NULL;
if (!value)
return NULL;
_line_edit = new QLineEdit(parent);
_line_edit->setText(QString::fromUtf8(
g_variant_get_string(value, NULL)));
g_variant_unref(value);
if (auto_commit)
connect(_line_edit, SIGNAL(textEdited(const QString&)),
this, SLOT(on_text_edited(const QString&)));
return _line_edit;
}
void String::commit()
{
assert(_setter);
if (!_line_edit)
return;
QByteArray ba = _line_edit->text().toLocal8Bit();
_setter(g_variant_new_string(ba.data()));
}
void String::on_text_edited(const QString&)
{
commit();
}
} // prop
} // pv

View File

@ -0,0 +1,52 @@
/*
* This file is part of the PulseView project.
*
* Copyright (C) 2013 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 DSLOGIC_PV_PROP_STRING_H
#define DSLOGIC_PV_PROP_STRING_H
#include "property.h"
class QLineEdit;
namespace pv {
namespace prop {
class String : public Property
{
Q_OBJECT;
public:
String(QString name, Getter getter, Setter setter);
QWidget* get_widget(QWidget *parent, bool auto_commit);
void commit();
private slots:
void on_text_edited(const QString&);
private:
QLineEdit *_line_edit;
};
} // prop
} // pv
#endif // DSLOGIC_PV_PROP_STRING_H

Some files were not shown because too many files have changed in this diff Show More