diff --git a/DSLogic-gui/CMakeLists.txt b/DSLogic-gui/CMakeLists.txt index f2e563d151b8f002049d5ee72e18ed786f09cc50..6e7dd10e38031675195ebdecb814f84bee3a3994 100644 --- a/DSLogic-gui/CMakeLists.txt +++ b/DSLogic-gui/CMakeLists.txt @@ -19,10 +19,13 @@ ## along with this program. If not, see . ## -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" ) +if(ENABLE_DECODE) + list(APPEND PKGDEPS "libsigrokdecode>=0.3.0") +endif() -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/") - 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(FORCE_QT4) + set(Qt5Core_FOUND FALSE) +else() + find_package(Qt5Core QUIET) +endif() -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(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_package(Boost 1.42 COMPONENTS system thread REQUIRED) + 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 ) -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}) +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} ") + 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,8 +269,12 @@ 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) + 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) diff --git a/DSLogic-gui/DSLogic.qrc b/DSLogic-gui/DSLogic.qrc index d7b5e8a1cec5041e15847848565e799bde00eb72..1efbf6b5a84a9af3dbb49f859b27a65885df3687 100644 --- a/DSLogic-gui/DSLogic.qrc +++ b/DSLogic-gui/DSLogic.qrc @@ -4,14 +4,12 @@ icons/next.png icons/pre.png icons/file.png - icons/photo.png icons/save.png icons/open.png icons/params.png stylesheet.qss icons/down-arrow.png icons/slider-handle.png - icons/set.png icons/add.png icons/del.png icons/trigger.png @@ -20,14 +18,22 @@ icons/protocol.png icons/logo_noColor.png icons/logo_color.png - icons/logo_muColor.png icons/about.png icons/capture.png icons/stop.png icons/start.png icons/dsl_logo.png icons/logo.png - icons/checkbox.png - icons/radiobutton.png + icons/decoder-hidden.png + icons/decoder-shown.png + icons/instant.png + icons/trigger_dis.png + icons/file_dis.png + icons/measure_dis.png + icons/protocol_dis.png + icons/search-bar_dis.png + icons/params_dis.png + icons/gear.png + icons/wiki.png diff --git a/DSLogic-gui/icons/about.png b/DSLogic-gui/icons/about.png index b2a3208e8d92c5ee7301f03d3b5586322005c49c..b249edb13e0c36023c71e0f8b116f25fa23d931e 100644 Binary files a/DSLogic-gui/icons/about.png and b/DSLogic-gui/icons/about.png differ diff --git a/DSLogic-gui/icons/capture.png b/DSLogic-gui/icons/capture.png index 7b7db85b0b07fee20fb85f609b7b342a97737bd9..15e44bf8998b6843e87968d4fc4bd6e72f3aa875 100644 Binary files a/DSLogic-gui/icons/capture.png and b/DSLogic-gui/icons/capture.png differ diff --git a/DSLogic-gui/icons/decoder-hidden.png b/DSLogic-gui/icons/decoder-hidden.png new file mode 100644 index 0000000000000000000000000000000000000000..215b5ada038497ff658eedb6b5887706700644b7 Binary files /dev/null and b/DSLogic-gui/icons/decoder-hidden.png differ diff --git a/DSLogic-gui/icons/decoder-shown.png b/DSLogic-gui/icons/decoder-shown.png new file mode 100644 index 0000000000000000000000000000000000000000..d745e24fc1cef63e7b5d73b97dc2fe3da3282a0d Binary files /dev/null and b/DSLogic-gui/icons/decoder-shown.png differ diff --git a/DSLogic-gui/icons/file.png b/DSLogic-gui/icons/file.png index 563dc4773aa918368485d73b4d85bbe1d0d9fb2d..06a9f281245fbb9af02219f6384e293b61b73de4 100644 Binary files a/DSLogic-gui/icons/file.png and b/DSLogic-gui/icons/file.png differ diff --git a/DSLogic-gui/icons/file_dis.png b/DSLogic-gui/icons/file_dis.png new file mode 100644 index 0000000000000000000000000000000000000000..71eb703df680221c17dd72973143e4d06bb2e956 Binary files /dev/null and b/DSLogic-gui/icons/file_dis.png differ diff --git a/DSLogic-gui/icons/gear.png b/DSLogic-gui/icons/gear.png new file mode 100644 index 0000000000000000000000000000000000000000..2c52b8df040f5a7f65386cd77baf5679c0552836 Binary files /dev/null and b/DSLogic-gui/icons/gear.png differ diff --git a/DSLogic-gui/icons/instant.png b/DSLogic-gui/icons/instant.png new file mode 100644 index 0000000000000000000000000000000000000000..ac1b5d0350ac95b7454885f08afcde3f6c6f05c7 Binary files /dev/null and b/DSLogic-gui/icons/instant.png differ diff --git a/DSLogic-gui/icons/logo_color.png b/DSLogic-gui/icons/logo_color.png index 730f3b247319914815fec91ead000b73b2ac5fb0..1b820058a26601ca0248f70f6e4bcf698af92700 100644 Binary files a/DSLogic-gui/icons/logo_color.png and b/DSLogic-gui/icons/logo_color.png differ diff --git a/DSLogic-gui/icons/logo_noColor.png b/DSLogic-gui/icons/logo_noColor.png index eccc8c4a548c06a7a670e9616fd32db7292afe38..a245df3959e6fef33409e5c01d5dac36f16af13c 100644 Binary files a/DSLogic-gui/icons/logo_noColor.png and b/DSLogic-gui/icons/logo_noColor.png differ diff --git a/DSLogic-gui/icons/measure.png b/DSLogic-gui/icons/measure.png index a00a19e810e5d95c05c50c4b19faf23c834dfe4a..f0b28b7fbb7158669868980c12cd9cb5f67afcfd 100644 Binary files a/DSLogic-gui/icons/measure.png and b/DSLogic-gui/icons/measure.png differ diff --git a/DSLogic-gui/icons/measure_dis.png b/DSLogic-gui/icons/measure_dis.png new file mode 100644 index 0000000000000000000000000000000000000000..244eb97940ef585830cdb642b50c062b79d12f99 Binary files /dev/null and b/DSLogic-gui/icons/measure_dis.png differ diff --git a/DSLogic-gui/icons/next.png b/DSLogic-gui/icons/next.png index 95ec60ff20e0121141a0efe46b0f8519f11bcacd..9e86ecf6472b9b0332d72dd9a042bab6aa62be12 100644 Binary files a/DSLogic-gui/icons/next.png and b/DSLogic-gui/icons/next.png differ diff --git a/DSLogic-gui/icons/open.png b/DSLogic-gui/icons/open.png index 35c395c50f51bd2c47d2ab327b6ad16f48c8e866..df9cf3f961e8670a8115aac59e775e44f33f5dce 100644 Binary files a/DSLogic-gui/icons/open.png and b/DSLogic-gui/icons/open.png differ diff --git a/DSLogic-gui/icons/params.png b/DSLogic-gui/icons/params.png index 9432007e39dec4e45bf999556c22f925bbe02361..5b5af1745e41cdc0e01c37a6ccc94f40bd91cfb9 100644 Binary files a/DSLogic-gui/icons/params.png and b/DSLogic-gui/icons/params.png differ diff --git a/DSLogic-gui/icons/params_dis.png b/DSLogic-gui/icons/params_dis.png new file mode 100644 index 0000000000000000000000000000000000000000..67811f26785ef29a24942c5f1d43f9cba1a6445b Binary files /dev/null and b/DSLogic-gui/icons/params_dis.png differ diff --git a/DSLogic-gui/icons/pre.png b/DSLogic-gui/icons/pre.png index f09cdc9a879384266b38de008884a4004199fc8e..1eac2f4e8105f121ae3820514bb59bd97821980b 100644 Binary files a/DSLogic-gui/icons/pre.png and b/DSLogic-gui/icons/pre.png differ diff --git a/DSLogic-gui/icons/protocol.png b/DSLogic-gui/icons/protocol.png index 23aff7725b83b0eb156b677e1294b3cb5a4783ac..b1a9cf44b8ff9e6409db8e25da051ffcab193ff6 100644 Binary files a/DSLogic-gui/icons/protocol.png and b/DSLogic-gui/icons/protocol.png differ diff --git a/DSLogic-gui/icons/protocol_dis.png b/DSLogic-gui/icons/protocol_dis.png new file mode 100644 index 0000000000000000000000000000000000000000..3238fcfce2313e054efcc22ea91d727c8ed8c540 Binary files /dev/null and b/DSLogic-gui/icons/protocol_dis.png differ diff --git a/DSLogic-gui/icons/save.png b/DSLogic-gui/icons/save.png index 805dc0eb1d0a3354cca82c893d772fe4f4c799ba..f32906a47e4c1b3a1fe729564fe3158162b3cdc4 100644 Binary files a/DSLogic-gui/icons/save.png and b/DSLogic-gui/icons/save.png differ diff --git a/DSLogic-gui/icons/search-bar.png b/DSLogic-gui/icons/search-bar.png index 09053b8658dae85be074f2d6a441f8c6930c6508..ee7e1121a04e4ae9ad6682f9d63ef267bc92dab2 100644 Binary files a/DSLogic-gui/icons/search-bar.png and b/DSLogic-gui/icons/search-bar.png differ diff --git a/DSLogic-gui/icons/search-bar_dis.png b/DSLogic-gui/icons/search-bar_dis.png new file mode 100644 index 0000000000000000000000000000000000000000..81805a6041d02d6b38861343f436062a22ebeb54 Binary files /dev/null and b/DSLogic-gui/icons/search-bar_dis.png differ diff --git a/DSLogic-gui/icons/start.png b/DSLogic-gui/icons/start.png index f3c624d64baef634edb1284c1e121223497277bd..badd73e5d6b54eab43d63ea2571e3250d59577d1 100644 Binary files a/DSLogic-gui/icons/start.png and b/DSLogic-gui/icons/start.png differ diff --git a/DSLogic-gui/icons/stop.png b/DSLogic-gui/icons/stop.png index 2b2c9829c3f6b212cac652e0055efa091ce18d24..a6fd48db029b6eb2da839a5f12cfd209eb5361dc 100644 Binary files a/DSLogic-gui/icons/stop.png and b/DSLogic-gui/icons/stop.png differ diff --git a/DSLogic-gui/icons/trigger.png b/DSLogic-gui/icons/trigger.png index 6b36974db65e896dc4ab61e5c11a4762f19e1ec3..9eeba7f33b8c68f6fde0dc6629c87e0e149ba5ff 100644 Binary files a/DSLogic-gui/icons/trigger.png and b/DSLogic-gui/icons/trigger.png differ diff --git a/DSLogic-gui/icons/trigger_dis.png b/DSLogic-gui/icons/trigger_dis.png new file mode 100644 index 0000000000000000000000000000000000000000..0a0ed1902c082e1d10aba566978c78c98b63b0b1 Binary files /dev/null and b/DSLogic-gui/icons/trigger_dis.png differ diff --git a/DSLogic-gui/icons/wiki.png b/DSLogic-gui/icons/wiki.png new file mode 100644 index 0000000000000000000000000000000000000000..aa9d2d58f83f40e9c4c97b40ab0e58006140424b Binary files /dev/null and b/DSLogic-gui/icons/wiki.png differ diff --git a/DSLogic-gui/main.cpp b/DSLogic-gui/main.cpp index 807f3ced7dedade6b5aa3c6de6b8924fca2706bd..1de0511ae7589cea65e744d38287fcca90cd5436 100644 --- a/DSLogic-gui/main.cpp +++ b/DSLogic-gui/main.cpp @@ -21,7 +21,7 @@ */ -#ifdef ENABLE_SIGROKDECODE +#ifdef ENABLE_DECODE #include /* First, so we avoid a _POSIX_C_SOURCE warning. */ #endif @@ -33,12 +33,15 @@ #include #include #include +#include #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 diff --git a/DSLogic-gui/pv/data/analog.cpp b/DSLogic-gui/pv/data/analog.cpp index d4e6304ca0f6f0f412ea2f44daf636fe28464c5d..0d55909de1f0411167ed5fb86c40b09f6c83bd47 100644 --- a/DSLogic-gui/pv/data/analog.cpp +++ b/DSLogic-gui/pv/data/analog.cpp @@ -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 &snapshot) { _snapshots.push_front(snapshot); @@ -45,5 +51,10 @@ deque< boost::shared_ptr >& Analog::get_snapshots() return _snapshots; } +void Analog::clear() +{ + _snapshots.clear(); +} + } // namespace data } // namespace pv diff --git a/DSLogic-gui/pv/data/analog.h b/DSLogic-gui/pv/data/analog.h index 281b936c703a2e4be5464aafaebb3aae43bf8916..1009d011187664520e2fb56807221fe44531e114 100644 --- a/DSLogic-gui/pv/data/analog.h +++ b/DSLogic-gui/pv/data/analog.h @@ -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 &snapshot); @@ -45,7 +47,10 @@ public: std::deque< boost::shared_ptr >& get_snapshots(); + void clear(); + private: + const unsigned int _num_probes; std::deque< boost::shared_ptr > _snapshots; }; diff --git a/DSLogic-gui/pv/data/analogsnapshot.cpp b/DSLogic-gui/pv/data/analogsnapshot.cpp index f613983c08d3bba5499cc916388526b3d5e051c9..d5260157d602f3642a9f57feddd7e34ee154f35b 100644 --- a/DSLogic-gui/pv/data/analogsnapshot.cpp +++ b/DSLogic-gui/pv/data/analogsnapshot.cpp @@ -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); diff --git a/DSLogic-gui/pv/data/decode/annotation.cpp b/DSLogic-gui/pv/data/decode/annotation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c3c744005c6e2c020f8fb042c2a7ff4a8934e989 --- /dev/null +++ b/DSLogic-gui/pv/data/decode/annotation.cpp @@ -0,0 +1,74 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * 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 +} + +#include +#include + +#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& Annotation::annotations() const +{ + return _annotations; +} + +} // namespace decode +} // namespace data +} // namespace pv diff --git a/DSLogic-gui/pv/data/decode/annotation.h b/DSLogic-gui/pv/data/decode/annotation.h new file mode 100644 index 0000000000000000000000000000000000000000..2ca15d782f618906d96b83f74245ca09be879074 --- /dev/null +++ b/DSLogic-gui/pv/data/decode/annotation.h @@ -0,0 +1,55 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2013 Joel Holdsworth + * + * 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 + +#include + +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& annotations() const; + +private: + uint64_t _start_sample; + uint64_t _end_sample; + int _format; + std::vector _annotations; +}; + +} // namespace decode +} // namespace data +} // namespace pv + +#endif // DSLOGIC_PV_VIEW_DECODE_ANNOTATION_H diff --git a/DSLogic-gui/pv/data/decode/decoder.cpp b/DSLogic-gui/pv/data/decode/decoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ae072fc9eaedbc2ad46fe7d3e7b89b41dccaf49 --- /dev/null +++ b/DSLogic-gui/pv/data/decode/decoder.cpp @@ -0,0 +1,185 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2013 Joel Holdsworth + * + * 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 +#include + +#include "decoder.h" + +#include + +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::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 >& +Decoder::channels() const +{ + return _probes; +} + +void Decoder::set_probes(std::map > probes) +{ + _probes_back = probes; + _setted = true; +} + +const std::map& 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 > Decoder::get_data() +{ + set< shared_ptr > data; + for(map >:: + const_iterator i = _probes.begin(); + i != _probes.end(); i++) + { + shared_ptr 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::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_iterator i = _probes.begin(); + i != _probes.end(); i++) + { + shared_ptr 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 diff --git a/DSLogic-gui/pv/data/decode/decoder.h b/DSLogic-gui/pv/data/decode/decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..f1b4b0857982ff8fb840896b085c5b1d351f6673 --- /dev/null +++ b/DSLogic-gui/pv/data/decode/decoder.h @@ -0,0 +1,101 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2013 Joel Holdsworth + * + * 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 +#include + +#include + +#include + +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 >& channels() const; + void set_probes(std::map > probes); + + const std::map& 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 > get_data(); + + bool commit(); + +private: + const srd_decoder *const _decoder; + + bool _shown; + bool _shown_back; + bool _shown_setted; + + std::map > + _probes; + std::map _options; + + std::map > + _probes_back; + std::map _options_back; + + bool _setted; +}; + +} // namespace decode +} // namespace data +} // namespace pv + +#endif // DSLOGIC_PV_DATA_DECODE_DECODER_H diff --git a/DSLogic-gui/pv/data/decode/row.cpp b/DSLogic-gui/pv/data/decode/row.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2aabf0f93fc0fc5dfa1237dd48d759126df28d9c --- /dev/null +++ b/DSLogic-gui/pv/data/decode/row.cpp @@ -0,0 +1,72 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + +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 diff --git a/DSLogic-gui/pv/data/decode/row.h b/DSLogic-gui/pv/data/decode/row.h new file mode 100644 index 0000000000000000000000000000000000000000..6d73c41952d81ba975cd10ca860cde2cb844dad3 --- /dev/null +++ b/DSLogic-gui/pv/data/decode/row.h @@ -0,0 +1,59 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + +#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 diff --git a/DSLogic-gui/pv/data/decode/rowdata.cpp b/DSLogic-gui/pv/data/decode/rowdata.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d3ed27f5a9673520157a744d6d1f35cb7bcecf4 --- /dev/null +++ b/DSLogic-gui/pv/data/decode/rowdata.cpp @@ -0,0 +1,68 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + +#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 &dest, + uint64_t start_sample, uint64_t end_sample) const +{ + for (vector::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 diff --git a/DSLogic-gui/pv/data/decode/rowdata.h b/DSLogic-gui/pv/data/decode/rowdata.h new file mode 100644 index 0000000000000000000000000000000000000000..5fddd95fb0e861abca6ec0fc7e9f1b091fb71508 --- /dev/null +++ b/DSLogic-gui/pv/data/decode/rowdata.h @@ -0,0 +1,59 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + +#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 &dest, + uint64_t start_sample, uint64_t end_sample) const; + + void push_annotation(const Annotation &a); + +private: + uint64_t _max_annotation; + std::vector _annotations; +}; + +} +} // data +} // pv + +#endif // DSLOGIC_PV_DATA_DECODE_ROWDATA_H diff --git a/DSLogic-gui/pv/data/decoderstack.cpp b/DSLogic-gui/pv/data/decoderstack.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e5ca87554a4ae2948bb88df34ce9008081e5133 --- /dev/null +++ b/DSLogic-gui/pv/data/decoderstack.cpp @@ -0,0 +1,526 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * 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 + +#include +#include + +#include + +#include + +#include "decoderstack.h" + +#include +#include +#include +#include +#include +#include + +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( + new decode::Decoder(dec))); +} + +DecoderStack::~DecoderStack() +{ +// if (_decode_thread.joinable()) { +// _decode_thread.interrupt(); +// _decode_thread.join(); +// } + stop_decode(); +} + +const std::list< boost::shared_ptr >& +DecoderStack::stack() const +{ + return _stack; +} + +void DecoderStack::push(boost::shared_ptr 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 >::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 decode_lock(_output_mutex); + return _samples_decoded; +} + +std::vector< std::pair > DecoderStack::get_visible_rows() const +{ + lock_guard lock(_output_mutex); + + std::vector< std::pair > rows; + + BOOST_FOREACH (const shared_ptr &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 &dest, + const Row &row, uint64_t start_sample, + uint64_t end_sample) const +{ + lock_guard lock(_output_mutex); + + std::map::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 lock(_output_mutex); + + std::map::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 lock(_output_mutex); + + std::map::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 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 logic_signal; + shared_ptr 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 &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 &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 &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 > &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_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 DecoderStack::wait_for_data() const +{ + unique_lock 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 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 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 decode_lock(_global_decode_mutex); + + optional 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 &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 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 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::iterator row_iter = d->_rows.end(); + + // Try looking up the sub-row of this class + const map, 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 lock(_input_mutex); +// if (_snapshot) +// _sample_count = _snapshot->get_sample_count(); +// } +// _input_cond.notify_one(); +} + +void DecoderStack::on_frame_ended() +{ +// { +// unique_lock 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_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 diff --git a/DSLogic-gui/pv/data/decoderstack.h b/DSLogic-gui/pv/data/decoderstack.h new file mode 100644 index 0000000000000000000000000000000000000000..8ea1d26cbfdbbca8fe5fe4b647e782f83151582b --- /dev/null +++ b/DSLogic-gui/pv/data/decoderstack.h @@ -0,0 +1,185 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * 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 + +#include +#include +#include + +#include +#include + +#include +#include + +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 >& stack() const; + void push(boost::shared_ptr decoder); + void remove(int index); + + int64_t samples_decoded() const; + + std::vector< std::pair > get_visible_rows() const; + + /** + * Extracts sorted annotations between two period into a vector. + */ + void get_annotation_subset( + std::vector &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 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 > _stack; + + boost::shared_ptr _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 _rows; + + std::map, decode::Row> _class_rows; + + QString _error_message; + + std::auto_ptr _decode_thread; + decode_state _decode_state; + + bool _options_changed; + + friend class DecoderStackTest::TwoDecoderStack; +}; + +} // namespace data +} // namespace pv + +#endif // DSLOGIC_PV_DATA_DECODERSTACK_H diff --git a/DSLogic-gui/pv/data/dso.cpp b/DSLogic-gui/pv/data/dso.cpp index fc967ffd5b66bdd5a3e27649165f420382930615..a72f3b28bbc89c989afb649186fbac6d256f07bf 100644 --- a/DSLogic-gui/pv/data/dso.cpp +++ b/DSLogic-gui/pv/data/dso.cpp @@ -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 >& Dso::get_snapshots() return _snapshots; } +void Dso::clear() +{ + _snapshots.clear(); +} + } // namespace data } // namespace pv diff --git a/DSLogic-gui/pv/data/dso.h b/DSLogic-gui/pv/data/dso.h index 591fa27390ac6eca30098743844a320491ba7c9a..8ab51378e24e53702c692a356abc23586486eb12 100644 --- a/DSLogic-gui/pv/data/dso.h +++ b/DSLogic-gui/pv/data/dso.h @@ -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 &snapshot); @@ -44,6 +44,8 @@ public: std::deque< boost::shared_ptr >& get_snapshots(); + void clear(); + private: std::deque< boost::shared_ptr > _snapshots; }; diff --git a/DSLogic-gui/pv/data/dsosnapshot.cpp b/DSLogic-gui/pv/data/dsosnapshot.cpp index fb05e5d817e5140b3e67ce250ab86338a90460f0..f5f46fb6ab191904458594302487550b21b13681 100644 --- a/DSLogic-gui/pv/data/dsosnapshot.cpp +++ b/DSLogic-gui/pv/data/dsosnapshot.cpp @@ -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); diff --git a/DSLogic-gui/pv/data/group.cpp b/DSLogic-gui/pv/data/group.cpp index 6df3ee88b69a6a8189045b7690f3dc508936ab9f..362d595f7bf2f8525cb7f25e7b3d90b2b059e9bc 100644 --- a/DSLogic-gui/pv/data/group.cpp +++ b/DSLogic-gui/pv/data/group.cpp @@ -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 >& Group::get_snapshots() return _snapshots; } +void Group::clear() +{ + _snapshots.clear(); +} + } // namespace data } // namespace pv diff --git a/DSLogic-gui/pv/data/group.h b/DSLogic-gui/pv/data/group.h index c55f6e93fc95836aeb98a5a1597b0b90fe0d2572..0ee105fe9e7191dbaf0bd114852843467067e267 100644 --- a/DSLogic-gui/pv/data/group.h +++ b/DSLogic-gui/pv/data/group.h @@ -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 &snapshot); @@ -45,6 +45,8 @@ public: std::deque< boost::shared_ptr >& get_snapshots(); + void clear(); + private: std::deque< boost::shared_ptr > _snapshots; }; diff --git a/DSLogic-gui/pv/data/groupsnapshot.cpp b/DSLogic-gui/pv/data/groupsnapshot.cpp index 939ffca651b2272d12610f95ce9315da3aca1df6..085f69714afc6593870d1c81aa18a2ba1f3ae18d 100644 --- a/DSLogic-gui/pv/data/groupsnapshot.cpp +++ b/DSLogic-gui/pv/data/groupsnapshot.cpp @@ -59,7 +59,7 @@ GroupSnapshot::GroupSnapshot(const boost::shared_ptr &_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(); } diff --git a/DSLogic-gui/pv/data/logic.cpp b/DSLogic-gui/pv/data/logic.cpp index 4cdfe2ae2416c96f882deec97bd2bb37c68fede9..f45aac6de3fc353521bf13539b27522c933e733b 100644 --- a/DSLogic-gui/pv/data/logic.cpp +++ b/DSLogic-gui/pv/data/logic.cpp @@ -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 >& Logic::get_snapshots() return _snapshots; } +void Logic::clear() +{ + _snapshots.clear(); +} + } // namespace data } // namespace pv diff --git a/DSLogic-gui/pv/data/logic.h b/DSLogic-gui/pv/data/logic.h index d7e23d36685080c25cba2fcf88a1b9bd9e5959cb..b6b958b7434cfbd9f2806670341d0a66bf504b81 100644 --- a/DSLogic-gui/pv/data/logic.h +++ b/DSLogic-gui/pv/data/logic.h @@ -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 &snapshot); @@ -45,6 +47,8 @@ public: std::deque< boost::shared_ptr >& get_snapshots(); + void clear(); + private: std::deque< boost::shared_ptr > _snapshots; }; diff --git a/DSLogic-gui/pv/data/logicsnapshot.cpp b/DSLogic-gui/pv/data/logicsnapshot.cpp index 9a6b2d2e0746ceb6bef0fc8b064bb55d24d0c3d8..621b4aaa1646a1bb99ce06d6fb771661da248829 100644 --- a/DSLogic-gui/pv/data/logicsnapshot.cpp +++ b/DSLogic-gui/pv/data/logicsnapshot.cpp @@ -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 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 &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 lock(_mutex); const uint64_t block_length = (uint64_t)max(min_length, 1.0f); diff --git a/DSLogic-gui/pv/data/logicsnapshot.h b/DSLogic-gui/pv/data/logicsnapshot.h index 5a3bff88c2a33fef6c4ad211a67e854b6d8d0f98..f618c10f95d3a05e9503f1931570bd542af27198 100644 --- a/DSLogic-gui/pv/data/logicsnapshot.h +++ b/DSLogic-gui/pv/data/logicsnapshot.h @@ -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); diff --git a/DSLogic-gui/pv/data/signaldata.cpp b/DSLogic-gui/pv/data/signaldata.cpp index 355640af97295ea15667fd5855f63b10dc124a76..0dede45f2a510211285e281ef4d008fc18c82e49 100644 --- a/DSLogic-gui/pv/data/signaldata.cpp +++ b/DSLogic-gui/pv/data/signaldata.cpp @@ -20,27 +20,31 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #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 +double SignalData::samplerate() const { - return _num_probes; + return _samplerate; } -double SignalData::get_samplerate() const +void SignalData::set_samplerate(double samplerate) { - return _samplerate; + assert(samplerate > 0); + _samplerate = samplerate; + clear(); } double SignalData::get_start_time() const @@ -48,5 +52,16 @@ 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 diff --git a/DSLogic-gui/pv/data/signaldata.h b/DSLogic-gui/pv/data/signaldata.h index be5280a9f3d1d8ff5038523e401ff91057a7ddfa..0d8fdd7a50a77d7be9687a8249486a8d963d24c9 100644 --- a/DSLogic-gui/pv/data/signaldata.h +++ b/DSLogic-gui/pv/data/signaldata.h @@ -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 diff --git a/DSLogic-gui/pv/data/snapshot.cpp b/DSLogic-gui/pv/data/snapshot.cpp index f05452a0394fb2f77be2b0ad9dbbc2a2119ab8a7..6c2480d56e2495208f8dcb61f1eb043f68537558 100644 --- a/DSLogic-gui/pv/data/snapshot.cpp +++ b/DSLogic-gui/pv/data/snapshot.cpp @@ -54,6 +54,7 @@ Snapshot::~Snapshot() int Snapshot::init(uint64_t _total_sample_len) { + boost::lock_guard 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 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 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 lock(_mutex); diff --git a/DSLogic-gui/pv/data/snapshot.h b/DSLogic-gui/pv/data/snapshot.h index 5968c4bf13d7ad989f5d02dbba167ec635f65d18..784f33385266dd0747e1077f7beb698a1e41d639 100644 --- a/DSLogic-gui/pv/data/snapshot.h +++ b/DSLogic-gui/pv/data/snapshot.h @@ -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); diff --git a/DSLogic-gui/pv/device/device.cpp b/DSLogic-gui/pv/device/device.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6b1063c3990264935028fa1ed725a6dc6ffc74b4 --- /dev/null +++ b/DSLogic-gui/pv/device/device.cpp @@ -0,0 +1,105 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + +#include + +#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 diff --git a/DSLogic-gui/pv/device/device.h b/DSLogic-gui/pv/device/device.h new file mode 100644 index 0000000000000000000000000000000000000000..a5aa5f464eda40935747cb2c2ad0ff1a13ce4a91 --- /dev/null +++ b/DSLogic-gui/pv/device/device.h @@ -0,0 +1,52 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 diff --git a/DSLogic-gui/pv/device/devinst.cpp b/DSLogic-gui/pv/device/devinst.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c0ba08740fbcad1531ee25e912f6ce71e75619c5 --- /dev/null +++ b/DSLogic-gui/pv/device/devinst.cpp @@ -0,0 +1,203 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + +#include + +#include + +#include "devinst.h" + +#include + +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(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 diff --git a/DSLogic-gui/pv/device/devinst.h b/DSLogic-gui/pv/device/devinst.h new file mode 100644 index 0000000000000000000000000000000000000000..aab7d5709a7fbde56042e2e0f6c666f07efdc484 --- /dev/null +++ b/DSLogic-gui/pv/device/devinst.h @@ -0,0 +1,132 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + +#include + +#include + +#include + +#include + +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 diff --git a/DSLogic-gui/pv/device/file.cpp b/DSLogic-gui/pv/device/file.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e864b02201791f61418ba71a4a17156fe450260 --- /dev/null +++ b/DSLogic-gui/pv/device/file.cpp @@ -0,0 +1,67 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + +#include + +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 diff --git a/DSLogic-gui/pv/device/file.h b/DSLogic-gui/pv/device/file.h new file mode 100644 index 0000000000000000000000000000000000000000..e4d57968f0d1005b681d3e34f7899889b6833451 --- /dev/null +++ b/DSLogic-gui/pv/device/file.h @@ -0,0 +1,50 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + +#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 diff --git a/DSLogic-gui/pv/device/inputfile.cpp b/DSLogic-gui/pv/device/inputfile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..13a3d181b3c5f85652beda5f9416a364fab34b4d --- /dev/null +++ b/DSLogic-gui/pv/device/inputfile.cpp @@ -0,0 +1,144 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + +#include +#include +#include + +#include "inputfile.h" + +#include + +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 diff --git a/DSLogic-gui/pv/device/inputfile.h b/DSLogic-gui/pv/device/inputfile.h new file mode 100644 index 0000000000000000000000000000000000000000..1ad3b34fbd7e6ccd6b3672fffd725fb9090ed113 --- /dev/null +++ b/DSLogic-gui/pv/device/inputfile.h @@ -0,0 +1,69 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + +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 diff --git a/DSLogic-gui/pv/device/sessionfile.cpp b/DSLogic-gui/pv/device/sessionfile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c996436a7416b9c280d45211544ea2a852409b57 --- /dev/null +++ b/DSLogic-gui/pv/device/sessionfile.cpp @@ -0,0 +1,76 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + +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 diff --git a/DSLogic-gui/pv/device/sessionfile.h b/DSLogic-gui/pv/device/sessionfile.h new file mode 100644 index 0000000000000000000000000000000000000000..ef1845eb782893ed9e26dfb318819fd5c8bbe84a --- /dev/null +++ b/DSLogic-gui/pv/device/sessionfile.h @@ -0,0 +1,48 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 diff --git a/DSLogic-gui/pv/devicemanager.cpp b/DSLogic-gui/pv/devicemanager.cpp index 66e35007d79f3ca09f93125ef538999cb27732c7..a6c1f1bc6eac469173d34b3bc0383044af39d603 100644 --- a/DSLogic-gui/pv/devicemanager.cpp +++ b/DSLogic-gui/pv/devicemanager.cpp @@ -22,6 +22,8 @@ #include "devicemanager.h" +#include "device/devinst.h" +#include "device/device.h" #include "sigsession.h" #include @@ -34,9 +36,17 @@ #include #include +#include + #include -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& DeviceManager::devices() const +const std::list > &DeviceManager::devices() const { return _devices; } -int DeviceManager::use_device(sr_dev_inst *sdi, SigSession *owner) -{ - assert(sdi); - assert(owner); - - if (sr_dev_open(sdi) != SR_OK) - return SR_ERR; - - _used_devices[sdi] = owner; - return SR_OK; -} - -void DeviceManager::release_device(sr_dev_inst *sdi) +void DeviceManager::add_device(boost::shared_ptr device) { - assert(sdi); - - // Notify the owner, and removed the device from the used device list - _used_devices[sdi]->release_device(sdi); - _used_devices.erase(sdi); + assert(device); - sr_dev_close(sdi); + if (std::find(_devices.begin(), _devices.end(), device) == + _devices.end()) + _devices.push_front(device); } -list DeviceManager::driver_scan( +std::list > DeviceManager::driver_scan( struct sr_dev_driver *const driver, GSList *const drvopts) { - list driver_devices; + list< shared_ptr > driver_devices; assert(driver); // Remove any device instances from this driver from the device // list. They will not be valid after the scan. - list::iterator i = _devices.begin(); + list< shared_ptr >::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 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( + 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 @@ -165,17 +141,16 @@ void DeviceManager::init_drivers() void DeviceManager::release_devices() { - // Release all the used devices - for (map::iterator i = _used_devices.begin(); - i != _used_devices.end();) - release_device((*i++).first); - - _used_devices.clear(); + // Release all the used devices + BOOST_FOREACH(shared_ptr dev, _devices) { + assert(dev); + dev->release(); + } - // Clear all the drivers - sr_dev_driver **const drivers = sr_driver_list(); - for (sr_dev_driver **driver = drivers; *driver; driver++) - sr_dev_clear(*driver); + // Clear all the drivers + sr_dev_driver **const drivers = sr_driver_list(); + for (sr_dev_driver **driver = drivers; *driver; driver++) + sr_dev_clear(*driver); } void DeviceManager::scan_all_drivers() @@ -188,53 +163,22 @@ void DeviceManager::scan_all_drivers() void DeviceManager::release_driver(struct sr_dev_driver *const driver) { - assert(driver); -// map::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::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++; - } - - // Clear all the old device instances from this driver - sr_dev_clear(driver); -} + BOOST_FOREACH(shared_ptr dev, _devices) { + assert(dev); + if(dev->dev_inst()->driver == driver) + dev->release(); + } -bool DeviceManager::compare_devices(const sr_dev_inst *const a, - const sr_dev_inst *const b) -{ - return format_device_title(a).compare(format_device_title(b)) < 0; + // Clear all the old device instances from this driver + sr_dev_clear(driver); } -int DeviceManager::test_device(sr_dev_inst *sdi) +bool DeviceManager::compare_devices(boost::shared_ptr a, + boost::shared_ptr b) { - 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 diff --git a/DSLogic-gui/pv/devicemanager.h b/DSLogic-gui/pv/devicemanager.h index 0fc63963c76eb8afcb8ace1053e69bfcab9bf98d..94bd8962ce2e0693929d5f2381a693d4374fe516 100644 --- a/DSLogic-gui/pv/devicemanager.h +++ b/DSLogic-gui/pv/devicemanager.h @@ -47,6 +47,10 @@ namespace pv { class SigSession; +namespace device { +class DevInst; +} + class DeviceManager { public: @@ -54,36 +58,29 @@ public: ~DeviceManager(); - const std::list& devices() const; - - int use_device(sr_dev_inst *sdi, SigSession *owner); + const std::list< boost::shared_ptr >& devices() const; - void release_device(sr_dev_inst *sdi); + void add_device(boost::shared_ptr device); - std::list driver_scan( + std::list< boost::shared_ptr > 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 a, + boost::shared_ptr b); private: struct sr_context *const _sr_ctx; - std::list _devices; - std::map _used_devices; + std::list< boost::shared_ptr > _devices; }; } // namespace pv diff --git a/DSLogic-gui/pv/dialogs/deviceoptions.cpp b/DSLogic-gui/pv/dialogs/deviceoptions.cpp index 726fc92af138d93b9b2d787d386bb4c9342a9619..a09dca2e4edbbbbf74b253af83b465b52ca697e3 100644 --- a/DSLogic-gui/pv/dialogs/deviceoptions.cpp +++ b/DSLogic-gui/pv/dialogs/deviceoptions.cpp @@ -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 > &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 > &properties = _device_options_binding.properties(); BOOST_FOREACH(boost::shared_ptr 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 diff --git a/DSLogic-gui/pv/dialogs/deviceoptions.h b/DSLogic-gui/pv/dialogs/deviceoptions.h index ad804d229e2a6cdab86bbce3b8edeb82e0313b0f..3db2e92dfb95b42fc9a2c27a17a008de9f7ba9b5 100644 --- a/DSLogic-gui/pv/dialogs/deviceoptions.h +++ b/DSLogic-gui/pv/dialogs/deviceoptions.h @@ -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 _probes_checkBox_list; QGroupBox _props_box; - QComboBox _mode_comboBox; QVBoxLayout _props_box_layout; QDialogButtonBox _button_box; diff --git a/DSLogic-gui/pv/dialogs/storeprogress.cpp b/DSLogic-gui/pv/dialogs/storeprogress.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f608f548b5122fa416b46be5ef41202de68eb50c --- /dev/null +++ b/DSLogic-gui/pv/dialogs/storeprogress.cpp @@ -0,0 +1,84 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + +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 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 diff --git a/DSLogic-gui/pv/dialogs/storeprogress.h b/DSLogic-gui/pv/dialogs/storeprogress.h new file mode 100644 index 0000000000000000000000000000000000000000..dde071ccb23c512afbbc5844b61b1913f1c14c2d --- /dev/null +++ b/DSLogic-gui/pv/dialogs/storeprogress.h @@ -0,0 +1,65 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + +#include + +#include + +#include + +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 diff --git a/DSLogic-gui/pv/dock/dsotriggerdock.cpp b/DSLogic-gui/pv/dock/dsotriggerdock.cpp index d8f8277db6514c48f654c9bb6278359a28738263..b2b22e853a2326c4de7d2e3ca61d6f4658a6a134 100644 --- a/DSLogic-gui/pv/dock/dsotriggerdock.cpp +++ b/DSLogic-gui/pv/dock/dsotriggerdock.cpp @@ -23,6 +23,7 @@ #include "dsotriggerdock.h" #include "../sigsession.h" +#include "../device/devinst.h" #include #include @@ -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 { diff --git a/DSLogic-gui/pv/dock/dsotriggerdock.h b/DSLogic-gui/pv/dock/dsotriggerdock.h index 5c135c45934743b3416770c2639594c9724617bf..72095d0ec8c29704702943157e38fab0657dc800 100644 --- a/DSLogic-gui/pv/dock/dsotriggerdock.h +++ b/DSLogic-gui/pv/dock/dsotriggerdock.h @@ -52,6 +52,7 @@ public: void device_change(); signals: + void set_trig_pos(quint64 trig_pos); private slots: void pos_changed(int pos); diff --git a/DSLogic-gui/pv/dock/measuredock.cpp b/DSLogic-gui/pv/dock/measuredock.cpp index 43c43cf547d5ddd8cc3a1362807399fcee0c22d0..26dcd6f8dac569067c23403df3c632d330db1ff5 100644 --- a/DSLogic-gui/pv/dock/measuredock.cpp +++ b/DSLogic-gui/pv/dock/measuredock.cpp @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #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 #include @@ -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("|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), 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("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::Iterator i = _cursor_pushButton_list.begin(); @@ -136,20 +168,12 @@ void MeasureDock::cursor_update() for (QVector::Iterator i = _curpos_label_list.begin(); i != _curpos_label_list.end(); i++) delete (*i); - for (QVector::Iterator i = _curvalue_label_list.begin(); - i != _curvalue_label_list.end(); i++) - delete (*i); - for (QVector::Iterator i = _radix_comboBox_list.begin(); - i != _radix_comboBox_list.end(); i++) - delete (*i); for (QVector::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::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)); } } diff --git a/DSLogic-gui/pv/dock/measuredock.h b/DSLogic-gui/pv/dock/measuredock.h index 738de43fa18589b128e73886c9991cbc91bddc7e..e360774765a0bd3ee4b1c31cd21f7f75cbb9259d 100644 --- a/DSLogic-gui/pv/dock/measuredock.h +++ b/DSLogic-gui/pv/dock/measuredock.h @@ -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 _cursor_pushButton_list; QVector _curpos_label_list; - QVector _curvalue_label_list; - QVector _radix_comboBox_list; QVector _space_label_list; }; diff --git a/DSLogic-gui/pv/dock/protocoldock.cpp b/DSLogic-gui/pv/dock/protocoldock.cpp index ed8c5729ab5c688d7cea6296506e66078dd3b2b5..3b05627d5d3618a890736e6cb32682910bd98935 100644 --- a/DSLogic-gui/pv/dock/protocoldock.cpp +++ b/DSLogic-gui/pv/dock/protocoldock.cpp @@ -22,13 +22,17 @@ #include "protocoldock.h" -#include "../decoder/democonfig.h" #include "../sigsession.h" +#include "../view/decodetrace.h" +#include "../device/devinst.h" #include #include #include #include +#include + +#include 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 _sel_probes = dlg.get_sel_probes(); - QMap & _options = dlg.get_options(); - QMap _options_index = dlg.get_options_index(); + srd_decoder *const decoder = + (srd_decoder*)(_protocol_combobox->itemData(_protocol_combobox->currentIndex())).value(); + if (_session.add_decoder(decoder)) { + //std::list _sel_probes = dlg.get_sel_probes(); + //QMap & _options = dlg.get_options(); + //QMap _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(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 _sel_probes = dlg.get_sel_probes(); - QMap & _options = dlg.get_options(); - QMap _options_index = dlg.get_options_index(); - - _session.rst_protocol_analyzer(rst_index, _sel_probes, _options, _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 _sel_probes = dlg.get_sel_probes(); + //QMap & _options = dlg.get_options(); + //QMap _options_index = dlg.get_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(); diff --git a/DSLogic-gui/pv/dock/protocoldock.h b/DSLogic-gui/pv/dock/protocoldock.h index 2165af130ce8cb0611badd9f8dc57a7a71ae02e1..c60e6cdd490000a9e5bd096a4124dba8f537360a 100644 --- a/DSLogic-gui/pv/dock/protocoldock.h +++ b/DSLogic-gui/pv/dock/protocoldock.h @@ -24,6 +24,8 @@ #ifndef DSLOGIC_PV_PROTOCOLDOCK_H #define DSLOGIC_PV_PROTOCOLDOCK_H +#include + #include #include #include @@ -36,8 +38,6 @@ #include -#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; diff --git a/DSLogic-gui/pv/dock/searchdock.cpp b/DSLogic-gui/pv/dock/searchdock.cpp index fc079b7fb4ca689e6d8027ab63b18efb633ff91d..04b919186d9ad7cc85682c76b02d4ab55b583a09 100644 --- a/DSLogic-gui/pv/dock/searchdock.cpp +++ b/DSLogic-gui/pv/dock/searchdock.cpp @@ -30,6 +30,7 @@ #include "../dialogs/search.h" #include "../data/snapshot.h" #include "../data/logicsnapshot.h" +#include "../device/devinst.h" #include #include @@ -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); diff --git a/DSLogic-gui/pv/dock/searchdock.h b/DSLogic-gui/pv/dock/searchdock.h index c29f061db7d5d2241c5326ef5874bdba7f2904d3..7d748fc24c84ae90fafb7c0adb5a13b03682dfc0 100644 --- a/DSLogic-gui/pv/dock/searchdock.h +++ b/DSLogic-gui/pv/dock/searchdock.h @@ -45,7 +45,7 @@ #include -#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 diff --git a/DSLogic-gui/pv/dock/triggerdock.cpp b/DSLogic-gui/pv/dock/triggerdock.cpp index d5fc8904e16a1b5980633e4875f6a70e7e1d7b28..4d5e78cb6320f09db693e10dfb1e4b64a5d50f15 100644 --- a/DSLogic-gui/pv/dock/triggerdock.cpp +++ b/DSLogic-gui/pv/dock/triggerdock.cpp @@ -23,6 +23,7 @@ #include "triggerdock.h" #include "../sigsession.h" +#include "../device/devinst.h" #include #include @@ -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 { diff --git a/DSLogic-gui/pv/mainwindow.cpp b/DSLogic-gui/pv/mainwindow.cpp index 9a7bb8469ad23ed6851d9ca130fc1f1b6bfc8ca8..db501b696ae4be02216f1e8447f0fceb1555e946 100644 --- a/DSLogic-gui/pv/mainwindow.cpp +++ b/DSLogic-gui/pv/mainwindow.cpp @@ -21,12 +21,14 @@ */ -#ifdef ENABLE_SIGROKDECODE +#ifdef ENABLE_DECODE #include +#include "dock/protocoldock.h" #endif #include #include +#include #include #include @@ -41,27 +43,32 @@ #include #include #include +#include +#include #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 #include #include +#include #include -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())); -} - -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); - } -} + connect(_view, SIGNAL(mode_changed()), this, + SLOT(update_device_list())); + + // 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); - - const list &devices = _device_manager.devices(); - _device_bar->set_device_list(devices); - - if (!selected_device && !devices.empty()) { - // Fall back to the first device in the list. - selected_device = devices.front(); + assert(_sampling_bar); - // 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(); - } else { - show_session_error("Open Device Failed", - "the selected device can't be opened!"); - } - } - -// #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 -} - -void MainWindow::device_change() -{ - assert(_device_bar); - - struct sr_dev_inst *selected_device; - - const list &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(); - // 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(); + 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!"); - device_detach(); + _sampling_bar->enable_toggle(true); } -// #ifdef HAVE_LA_DSLOGIC - _session.stop_hotplug_proc(); - _session.start_hotplug_proc(boost::bind(&MainWindow::session_error, this, - QString("Hotplug failed"), _1)); -// #endif - + shared_ptr 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(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)); + } + 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(), - 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) { - _session.stop_capture(); - _session.start_capture(_sampling_bar->get_record_length(), - boost::bind(&MainWindow::session_error, this, - QString("Capture failed"), _1)); - } + _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)); + break; + + case SigSession::Running: + _session.stop_capture(); + 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,15 +436,20 @@ 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 > 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 s, sigs) { + shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + if (dsoSig->get_vDialActive()) { + dsoSig->go_vDialNext(); + update(); + break; + } + } + } + break; + case Qt::Key_Down: + BOOST_FOREACH(const shared_ptr s, sigs) { + shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + if (dsoSig->get_vDialActive()) { + dsoSig->go_vDialPre(); + update(); + break; + } + } + } + break; + default: + QWidget::keyPressEvent((QKeyEvent *)event); + } + return true; + } + return false; +} + } // namespace pv diff --git a/DSLogic-gui/pv/mainwindow.h b/DSLogic-gui/pv/mainwindow.h index 9be748aa850a95adf8e7ca72969910363c4fc1af..c1bd1cc6286bea8a6c96374db0e2ee440947fb69 100644 --- a/DSLogic-gui/pv/mainwindow.h +++ b/DSLogic-gui/pv/mainwindow.h @@ -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,35 +76,29 @@ private: void session_error(const QString text, const QString info_text); - /** - * 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(); + 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(); void show_session_error( const QString text, const QString info_text); - void device_selected(); - void run_stop(); - void test_data_error(); + void instant_stop(); - void capture_state_changed(int state); - - void init(); + void test_data_error(); - void update(); + void capture_state_changed(int state); void on_protocol(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; diff --git a/DSLogic-gui/pv/prop/binding/binding.cpp b/DSLogic-gui/pv/prop/binding/binding.cpp index e2ddd6a89906cf4c6e69ef3b0d49a35a3ac92667..6fcacf8d6a19f924079f5cfcdd22ccd63ca945c4 100644 --- a/DSLogic-gui/pv/prop/binding/binding.cpp +++ b/DSLogic-gui/pv/prop/binding/binding.cpp @@ -20,9 +20,16 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + +#include + +#include #include "binding.h" +using boost::shared_ptr; + namespace pv { namespace prop { namespace binding { @@ -32,6 +39,58 @@ const std::vector< boost::shared_ptr >& Binding::properties() return _properties; } +void Binding::commit() +{ + BOOST_FOREACH(shared_ptr p, _properties) { + assert(p); + p->commit(); + } +} + +void Binding::add_properties_to_form(QFormLayout *layout, + bool auto_commit) const +{ + assert(layout); + + BOOST_FOREACH(shared_ptr 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 diff --git a/DSLogic-gui/pv/prop/binding/binding.h b/DSLogic-gui/pv/prop/binding/binding.h index fdf4fe8d6e212df49bf83423173777f6ebe313b3..dd521711c123d39d5862dac7d96186c6da0a383e 100644 --- a/DSLogic-gui/pv/prop/binding/binding.h +++ b/DSLogic-gui/pv/prop/binding/binding.h @@ -24,9 +24,14 @@ #ifndef DSLOGIC_PV_PROP_BINDING_BINDING_H #define DSLOGIC_PV_PROP_BINDING_BINDING_H +#include + #include #include +#include + +class QFormLayout; class QWidget; namespace pv { @@ -41,6 +46,16 @@ class Binding public: const std::vector< boost::shared_ptr >& 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 > _properties; diff --git a/DSLogic-gui/pv/prop/binding/decoderoptions.cpp b/DSLogic-gui/pv/prop/binding/decoderoptions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c9005bb440f3085ca5ccc00cdf77038e100d21df --- /dev/null +++ b/DSLogic-gui/pv/prop/binding/decoderoptions.cpp @@ -0,0 +1,148 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2013 Joel Holdsworth + * + * 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 + +#include "decoderoptions.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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 decoder_stack, + shared_ptr 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 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(new Double(name, 2, "", + none, none, getter, setter)); + else if (g_variant_is_of_type(opt->def, G_VARIANT_TYPE("x"))) + prop = shared_ptr( + new Int(name, "", none, getter, setter)); + else if (g_variant_is_of_type(opt->def, G_VARIANT_TYPE("s"))) + prop = shared_ptr( + new String(name, getter, setter)); + else + continue; + + _properties.push_back(prop); + } +} + +shared_ptr DecoderOptions::bind_enum( + const QString &name, const srd_decoder_option *option, + Property::Getter getter, Property::Setter setter) +{ + vector< pair > 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(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& options = _decoder->options(); + map::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 diff --git a/DSLogic-gui/pv/prop/binding/decoderoptions.h b/DSLogic-gui/pv/prop/binding/decoderoptions.h new file mode 100644 index 0000000000000000000000000000000000000000..eaae51dc2d775e0e5a3b35c8a17c176a9ba4c20e --- /dev/null +++ b/DSLogic-gui/pv/prop/binding/decoderoptions.h @@ -0,0 +1,66 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2013 Joel Holdsworth + * + * 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 + +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 decoder_stack, + boost::shared_ptr decoder); + +private: + static boost::shared_ptr 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 _decoder_stack; + boost::shared_ptr _decoder; +}; + +} // binding +} // prop +} // pv + +#endif // DSLOGIC_PV_PROP_BINDING_DECODEROPTIONS_H diff --git a/DSLogic-gui/pv/prop/binding/deviceoptions.cpp b/DSLogic-gui/pv/prop/binding/deviceoptions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ffc1f7b41d330204e849aefbc14588aaad5cc79 --- /dev/null +++ b/DSLogic-gui/pv/prop/binding/deviceoptions.cpp @@ -0,0 +1,274 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 + +#include +#include + +#include + +#include "deviceoptions.h" + +#include +#include +#include +#include + +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(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( + 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 printer) +{ + GVariant *gvar; + GVariantIter iter; + vector< pair > 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( + 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 > range) +{ + _properties.push_back(boost::shared_ptr( + 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( + 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 + diff --git a/DSLogic-gui/pv/prop/bool.cpp b/DSLogic-gui/pv/prop/bool.cpp index 996cbde2f1ee468a1e8c121cf24ab4d55b3f700d..12f2f45cf6b27470a14fed3dc15aec62699014b1 100644 --- a/DSLogic-gui/pv/prop/bool.cpp +++ b/DSLogic-gui/pv/prop/bool.cpp @@ -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 diff --git a/DSLogic-gui/pv/prop/bool.h b/DSLogic-gui/pv/prop/bool.h index a48f52f2a74d344c76156b36dd9e46cefa1052dd..7c65608d809f96804706179c73e72655c62a2e53 100644 --- a/DSLogic-gui/pv/prop/bool.h +++ b/DSLogic-gui/pv/prop/bool.h @@ -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; }; diff --git a/DSLogic-gui/pv/prop/double.cpp b/DSLogic-gui/pv/prop/double.cpp index b8045759e387eabd6effe765910e6acd1820cdd7..ebc1ba137571ea565bf94d68a7c07b3c06d17559 100644 --- a/DSLogic-gui/pv/prop/double.cpp +++ b/DSLogic-gui/pv/prop/double.cpp @@ -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 diff --git a/DSLogic-gui/pv/prop/double.h b/DSLogic-gui/pv/prop/double.h index 47ef17de398200ab03dd62c6aedbaa9358a2c21f..79b110072cba7b41a7f86610275ebd2cbc5d71bc 100644 --- a/DSLogic-gui/pv/prop/double.h +++ b/DSLogic-gui/pv/prop/double.h @@ -37,6 +37,8 @@ namespace prop { class Double : public Property { + Q_OBJECT; + public: Double(QString name, int decimals, QString suffix, boost::optional< std::pair > 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; diff --git a/DSLogic-gui/pv/prop/enum.cpp b/DSLogic-gui/pv/prop/enum.cpp index edf6584abe0552a2688df90babfb8250058b3d4f..8e96c5ec2512a2c82e4706b71600f658bc1cb814 100644 --- a/DSLogic-gui/pv/prop/enum.cpp +++ b/DSLogic-gui/pv/prop/enum.cpp @@ -40,6 +40,9 @@ Enum::Enum(QString name, _values(values), _selector(NULL) { + for (vector< pair >::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 Enum::on_current_item_changed(int) +{ + commit(); +} + } // prop } // pv diff --git a/DSLogic-gui/pv/prop/enum.h b/DSLogic-gui/pv/prop/enum.h index c26e512e14aa430e7e636807f8a6ac8881719b81..0e14a1d8925b1a263f2d8212f8a2349eb0f92461 100644 --- a/DSLogic-gui/pv/prop/enum.h +++ b/DSLogic-gui/pv/prop/enum.h @@ -36,16 +36,21 @@ namespace prop { class Enum : public Property { + Q_OBJECT; + public: Enum(QString name, std::vector > 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 > _values; diff --git a/DSLogic-gui/pv/prop/int.cpp b/DSLogic-gui/pv/prop/int.cpp index 741b87963d5eb5943b5b6497981f556c6ab0f590..cf5fd5bc06c45a8d2b0a6db2cd4c21cf83d848b0 100644 --- a/DSLogic-gui/pv/prop/int.cpp +++ b/DSLogic-gui/pv/prop/int.cpp @@ -21,14 +21,31 @@ */ +#include #include +#include #include #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,41 +58,145 @@ 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) { - if (_spin_box) - return _spin_box; - - _spin_box = new QSpinBox(parent); - _spin_box->setSuffix(_suffix); - if (_range) - _spin_box->setRange((int)_range->first, (int)_range->second); - - GVariant *const value = _getter ? _getter() : NULL; - if (value) { - _spin_box->setValue((int)g_variant_get_int64(value)); - g_variant_unref(value); - } - - return _spin_box; + 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); + + _spin_box->setValue((int)int_val); + + if (auto_commit) + connect(_spin_box, SIGNAL(valueChanged(int)), + this, SLOT(on_value_changed(int))); + + return _spin_box; } void Int::commit() { - assert(_setter); - - if (!_spin_box) - return; + assert(_setter); + + if (!_spin_box) + return; + + 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); +} - _setter(g_variant_new_int64(_spin_box->value())); +void Int::on_value_changed(int) +{ + commit(); } } // prop diff --git a/DSLogic-gui/pv/prop/int.h b/DSLogic-gui/pv/prop/int.h index b9ae22bae847fe89ed371c60aeb60fa274af0f94..81ea7dd037a4cedb1e7666a6a9a029e7900b4625 100644 --- a/DSLogic-gui/pv/prop/int.h +++ b/DSLogic-gui/pv/prop/int.h @@ -37,6 +37,8 @@ namespace prop { class Int : public Property { + Q_OBJECT; + public: Int(QString name, QString suffix, boost::optional< std::pair > 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 > _range; + GVariant *_value; QSpinBox *_spin_box; }; diff --git a/DSLogic-gui/pv/prop/property.h b/DSLogic-gui/pv/prop/property.h index 61e880cd8c6b379fdbd737c9165034cdb5732dd8..d1f3e51ec38bd2f25c00ad17545f864c0373cd2b 100644 --- a/DSLogic-gui/pv/prop/property.h +++ b/DSLogic-gui/pv/prop/property.h @@ -36,8 +36,10 @@ class QWidget; namespace pv { namespace prop { -class Property +class Property : public QObject { + Q_OBJECT; + public: typedef boost::function Getter; typedef boost::function 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; diff --git a/DSLogic-gui/pv/prop/string.cpp b/DSLogic-gui/pv/prop/string.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7fcc656958b9fed74d6f91c89f29e2ebe58d429e --- /dev/null +++ b/DSLogic-gui/pv/prop/string.cpp @@ -0,0 +1,77 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2013 Joel Holdsworth + * + * 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 + +#include +#include + +#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 diff --git a/DSLogic-gui/pv/prop/string.h b/DSLogic-gui/pv/prop/string.h new file mode 100644 index 0000000000000000000000000000000000000000..0caf565d6a9c8c3cee7bfff47cd7b808f83ac8ed --- /dev/null +++ b/DSLogic-gui/pv/prop/string.h @@ -0,0 +1,52 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2013 Joel Holdsworth + * + * 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 diff --git a/DSLogic-gui/pv/sigsession.cpp b/DSLogic-gui/pv/sigsession.cpp index 27d7946223e85dbbdcc793a2eeffa77e5173b9e1..bb6f23801e6c26b2abe8f5d29aaf5ac0cbbf5a55 100644 --- a/DSLogic-gui/pv/sigsession.cpp +++ b/DSLogic-gui/pv/sigsession.cpp @@ -20,10 +20,17 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifdef ENABLE_DECODE +#include +#endif #include "sigsession.h" +#include "mainwindow.h" #include "devicemanager.h" +#include "device/device.h" +#include "device/file.h" + #include "data/analog.h" #include "data/analogsnapshot.h" #include "data/dso.h" @@ -32,23 +39,36 @@ #include "data/logicsnapshot.h" #include "data/group.h" #include "data/groupsnapshot.h" +#include "data/decoderstack.h" +#include "data/decode/decoder.h" + #include "view/analogsignal.h" #include "view/dsosignal.h" #include "view/logicsignal.h" #include "view/groupsignal.h" -#include "view/protocolsignal.h" -#include "decoder/decoder.h" -#include "decoder/decoderfactory.h" +#include "view/decodetrace.h" #include +#include +#include #include #include #include -using namespace boost; -using namespace std; +using boost::dynamic_pointer_cast; +using boost::function; +using boost::lock_guard; +using boost::mutex; +using boost::shared_ptr; +using std::list; +using std::map; +using std::set; +using std::string; +using std::vector; +using std::deque; +using std::min; namespace pv { @@ -59,10 +79,8 @@ SigSession* SigSession::_session = NULL; SigSession::SigSession(DeviceManager &device_manager) : _device_manager(device_manager), - _sdi(NULL), _capture_state(Init), - _last_sample_rate(1), - _total_sample_len(1) + _instant(false) { // TODO: This should not be necessary _session = this; @@ -70,134 +88,107 @@ SigSession::SigSession(DeviceManager &device_manager) : _hot_detach = false; _adv_trigger = false; _group_cnt = 0; - _protocol_cnt = 0; - _decoderFactory = new decoder::DecoderFactory(); ds_trigger_init(); - - _vDial_changed = false; - _hDial_changed = false; - _dso_ctrl_channel = 0; - register_hotplug_callback(); + register_hotplug_callback(); } SigSession::~SigSession() { - stop_capture(); - - if (_sampling_thread.get()) - _sampling_thread->join(); - _sampling_thread.reset(); - + stop_capture(); if (_hotplug_handle) { stop_hotplug_proc(); deregister_hotplug_callback(); } - ds_trigger_destroy(); - stop_dso_ctrl_proc(); + + _dev_inst->release(); // TODO: This should not be necessary _session = NULL; } -quint64 SigSession::get_last_sample_rate() const -{ - return _last_sample_rate; -} - -quint64 SigSession::get_total_sample_len() const +boost::shared_ptr SigSession::get_device() const { - return _total_sample_len; + return _dev_inst; } -void SigSession::set_total_sample_len(quint64 length) +void SigSession::set_device(shared_ptr dev_inst) throw(QString) { - _total_sample_len = length; -} + using pv::device::Device; -struct sr_dev_inst* SigSession::get_device() const -{ - return _sdi; -} + // Ensure we are not capturing before setting the device + stop_capture(); -int SigSession::set_device(struct sr_dev_inst *sdi) -{ - int ret = SR_ERR; - - if (_sdi == NULL) { - ret = _device_manager.use_device(sdi, this); - _sdi = sdi; - set_capture_state(Init); - } else if (sdi != _sdi) { - ret = _device_manager.use_device(sdi, this); - _device_manager.release_device(_sdi); - _sdi = sdi; - set_capture_state(Init); - } else { - ret = SR_OK; + if (_dev_inst) { + sr_session_datafeed_callback_remove_all(); + _dev_inst->release(); } - return ret; + _dev_inst = dev_inst; + _decode_traces.clear(); + _group_traces.clear(); + + if (_dev_inst) { + _dev_inst->use(this); + sr_session_datafeed_callback_add(data_feed_in_proc, NULL); + device_setted(); + } } -void SigSession::release_device(struct sr_dev_inst *sdi) -{ - (void)sdi; - assert(_capture_state != Running); - _sdi = NULL; +void SigSession::set_file(const string &name) throw(QString) +{ + // Deslect the old device, because file type detection in File::create + // destorys the old session inside libsigrok. + set_device(shared_ptr()); + set_device(shared_ptr(device::File::create(name))); } void SigSession::save_file(const std::string &name){ - if (_sdi->mode == LOGIC) { - const deque< boost::shared_ptr > &snapshots = - _logic_data->get_snapshots(); - if (snapshots.empty()) - return; - - const boost::shared_ptr &snapshot = - snapshots.front(); - - sr_session_save(name.c_str(), _sdi, - (unsigned char*)snapshot->get_data(), - snapshot->get_unit_size(), - snapshot->get_sample_count()); - } else if (_sdi->mode == DSO){ - const deque< boost::shared_ptr > &snapshots = - _dso_data->get_snapshots(); - if (snapshots.empty()) - return; + const deque< boost::shared_ptr > &snapshots = + _logic_data->get_snapshots(); + if (snapshots.empty()) + return; - const boost::shared_ptr &snapshot = - snapshots.front(); + const boost::shared_ptr &snapshot = + snapshots.front(); - sr_session_save(name.c_str(), _sdi, - (unsigned char*)snapshot->get_data(), - snapshot->get_unit_size(), - snapshot->get_sample_count()); - } else { - const deque< boost::shared_ptr > &snapshots = - _analog_data->get_snapshots(); - if (snapshots.empty()) - return; - - const boost::shared_ptr &snapshot = - snapshots.front(); + sr_session_save(name.c_str(), _dev_inst->dev_inst(), + (unsigned char*)snapshot->get_data(), + snapshot->unit_size(), + snapshot->get_sample_count()); +} - sr_session_save(name.c_str(), _sdi, - (unsigned char*)snapshot->get_data(), - snapshot->get_unit_size(), - snapshot->get_sample_count()); +void SigSession::set_default_device() +{ + shared_ptr default_device; + const list< shared_ptr > &devices = + _device_manager.devices(); + + if (!devices.empty()) { + // Fall back to the first device in the list. + default_device = devices.front(); + + // Try and find the DSLogic device and select that by default + BOOST_FOREACH (shared_ptr dev, devices) + if (dev->dev_inst() && + strcmp(dev->dev_inst()->driver->name, + "DSLogic") == 0) { + default_device = dev; + break; + } + set_device(default_device); } } -void SigSession::load_file(const string &name, - boost::function error_handler) +void SigSession::release_device(device::DevInst *dev_inst) { - stop_capture(); - _sampling_thread.reset(new boost::thread( - &SigSession::load_thread_proc, this, name, - error_handler)); + (void)dev_inst; + assert(_dev_inst.get() == dev_inst); + + assert(_capture_state != Running); + _dev_inst = shared_ptr(); + //_dev_inst.reset(); } SigSession::capture_state SigSession::get_capture_state() const @@ -206,21 +197,23 @@ SigSession::capture_state SigSession::get_capture_state() const return _capture_state; } -void SigSession::start_capture(uint64_t record_length, - boost::function error_handler) +void SigSession::start_capture(bool instant, + boost::function error_handler) { stop_capture(); // Check that a device instance has been selected. - if (!_sdi) { + if (!_dev_inst) { qDebug() << "No device selected"; return; } + assert(_dev_inst->dev_inst()); + // Check that at least one probe is enabled const GSList *l; - for (l = _sdi->probes; l; l = l->next) { - sr_probe *const probe = (sr_probe*)l->data; + for (l = _dev_inst->dev_inst()->channels; l; l = l->next) { + sr_channel *const probe = (sr_channel*)l->data; assert(probe); if (probe->enabled) break; @@ -230,32 +223,16 @@ void SigSession::start_capture(uint64_t record_length, return; } - // Check that at least one signal channel is active under DSO mode - if (_sdi->mode == DSO) { - bool active = false; - BOOST_FOREACH(const shared_ptr s, _signals) - { - assert(s); - if (s->get_active()) { - active = true; - break; - } - } - if (!active) { - error_handler(tr("No channels enabled.")); - return; - } - } - // Begin the session + _instant = instant; _sampling_thread.reset(new boost::thread( - &SigSession::sample_thread_proc, this, _sdi, - record_length, error_handler)); + &SigSession::sample_thread_proc, this, _dev_inst, + error_handler)); } void SigSession::stop_capture() { - if (get_capture_state() == Stopped) + if (get_capture_state() != Running) return; sr_session_stop(); @@ -271,75 +248,27 @@ vector< boost::shared_ptr > SigSession::get_signals() return _signals; } -vector< boost::shared_ptr > SigSession::get_pro_signals() +vector< boost::shared_ptr > SigSession::get_group_signals() { boost::lock_guard lock(_signals_mutex); - return _protocol_signals; + return _group_traces; } -int SigSession::get_logic_probe_cnt(const sr_dev_inst *sdi) +set< shared_ptr > SigSession::get_data() const { - unsigned int logic_probe_cnt = 0; - // Detect what data types we will receive - for (const GSList *l = sdi->probes; l; l = l->next) { - const sr_probe *const probe = (const sr_probe *)l->data; - if (!probe->enabled) - continue; - - switch(probe->type) { - case SR_PROBE_LOGIC: - logic_probe_cnt++; - break; - } - } - - return logic_probe_cnt; -} - -int SigSession::get_dso_probe_cnt(const sr_dev_inst *sdi) -{ - unsigned int dso_probe_cnt = 0; - for (const GSList *l = sdi->probes; l; l = l->next) { - const sr_probe *const probe = (const sr_probe *)l->data; - if (!probe->enabled) - continue; - - switch(probe->type) { - case SR_PROBE_DSO: - dso_probe_cnt++; - break; - } + lock_guard lock(_signals_mutex); + set< shared_ptr > data; + BOOST_FOREACH(const shared_ptr sig, _signals) { + assert(sig); + data.insert(sig->data()); } - return dso_probe_cnt; -} - -int SigSession::get_analog_probe_cnt(const sr_dev_inst *sdi) -{ - unsigned int analog_probe_cnt = 0; - for (const GSList *l = sdi->probes; l; l = l->next) { - const sr_probe *const probe = (const sr_probe *)l->data; - if (!probe->enabled) - continue; - - switch(probe->type) { - case SR_PROBE_ANALOG: - analog_probe_cnt++; - break; - } - } - - return analog_probe_cnt; -} - -boost::shared_ptr SigSession::get_data() -{ - return _logic_data; + return data; } void* SigSession::get_buf(int& unit_size, uint64_t &length) { - if (_sdi->mode == LOGIC) { + if (_dev_inst->dev_inst()->mode == LOGIC) { const deque< boost::shared_ptr > &snapshots = _logic_data->get_snapshots(); if (snapshots.empty()) @@ -348,10 +277,10 @@ void* SigSession::get_buf(int& unit_size, uint64_t &length) const boost::shared_ptr &snapshot = snapshots.front(); - unit_size = snapshot->get_unit_size(); + unit_size = snapshot->unit_size(); length = snapshot->get_sample_count(); return snapshot->get_data(); - } else if (_sdi->mode == DSO) { + } else if (_dev_inst->dev_inst()->mode == DSO) { const deque< boost::shared_ptr > &snapshots = _dso_data->get_snapshots(); if (snapshots.empty()) @@ -360,7 +289,7 @@ void* SigSession::get_buf(int& unit_size, uint64_t &length) const boost::shared_ptr &snapshot = snapshots.front(); - unit_size = snapshot->get_unit_size(); + unit_size = snapshot->unit_size(); length = snapshot->get_sample_count(); return snapshot->get_data(); } else { @@ -372,12 +301,18 @@ void* SigSession::get_buf(int& unit_size, uint64_t &length) const boost::shared_ptr &snapshot = snapshots.front(); - unit_size = snapshot->get_unit_size(); + unit_size = snapshot->unit_size(); length = snapshot->get_sample_count(); return snapshot->get_data(); } } +void SigSession::set_sample_rate(uint64_t sample_rate) +{ + if (_capture_state != Stopped) + sample_rate_changed(sample_rate); +} + void SigSession::set_capture_state(capture_state state) { boost::lock_guard lock(_sampling_mutex); @@ -386,42 +321,17 @@ void SigSession::set_capture_state(capture_state state) capture_state_changed(state); } -void SigSession::load_thread_proc(const string name, - boost::function error_handler) -{ - if (sr_session_load(name.c_str()) != SR_OK) { - error_handler(tr("Failed to load file.")); - return; - } - - sr_session_datafeed_callback_add(data_feed_in_proc, NULL); - - if (sr_session_start() != SR_OK) { - error_handler(tr("Failed to start session.")); - return; - } - - set_capture_state(Running); - - sr_session_run(); - sr_session_destroy(); - - set_capture_state(Stopped); - - // Confirm that SR_DF_END was received - assert(!_cur_logic_snapshot); - assert(!_cur_dso_snapshot); - assert(!_cur_analog_snapshot); -} - -void SigSession::sample_thread_proc(struct sr_dev_inst *sdi, - uint64_t record_length, - boost::function error_handler) +void SigSession::sample_thread_proc(shared_ptr dev_inst, + boost::function error_handler) { - assert(sdi); + assert(dev_inst); + assert(dev_inst->dev_inst()); assert(error_handler); - if (!_adv_trigger) { + if (_instant) { + /* disable trigger under instant mode */ + ds_trigger_set_en(false); + } else if (!_adv_trigger) { /* simple trigger check trigger_enable */ ds_trigger_set_en(false); BOOST_FOREACH(const boost::shared_ptr s, _signals) @@ -437,36 +347,17 @@ void SigSession::sample_thread_proc(struct sr_dev_inst *sdi, ds_trigger_set_en(true); } - sr_session_new(); - sr_session_datafeed_callback_add(data_feed_in_proc, NULL); - - if (sr_session_dev_add(sdi) != SR_OK) { - error_handler(tr("Failed to use device.")); - sr_session_destroy(); - return; - } - - // Set the sample limit - if (sr_config_set(sdi, SR_CONF_LIMIT_SAMPLES, - g_variant_new_uint64(record_length)) != SR_OK) { - error_handler(tr("Failed to configure " - "time-based sample limit.")); - sr_session_destroy(); + try { + dev_inst->start(); + } catch(const QString e) { + error_handler(e); return; } receive_data(0); set_capture_state(Running); - if (sr_session_start() != SR_OK) { - error_handler(tr("Failed to start session.")); - set_capture_state(Stopped); - return; - } - - sr_session_run(); - sr_session_destroy(); - + dev_inst->run(); set_capture_state(Stopped); // Confirm that SR_DF_END was received @@ -475,133 +366,57 @@ void SigSession::sample_thread_proc(struct sr_dev_inst *sdi, assert(!_cur_analog_snapshot); } -void SigSession::feed_in_header(const sr_dev_inst *sdi) +void SigSession::read_sample_rate(const sr_dev_inst *const sdi) { - boost::shared_ptr signal; - GVariant *gvar; - uint64_t sample_rate = 0; - unsigned int logic_probe_count = 0; - unsigned int dso_probe_count = 0; - unsigned int dso_channel_count = 0; - unsigned int analog_probe_count = 0; - - // Detect what data types we will receive - for (const GSList *l = sdi->probes; l; l = l->next) { - const sr_probe *const probe = (const sr_probe *)l->data; - if (!probe->enabled) - continue; - - switch(probe->type) { - case SR_PROBE_LOGIC: - logic_probe_count++; - break; - - case SR_PROBE_DSO: - dso_probe_count++; - break; - - case SR_PROBE_ANALOG: - analog_probe_count++; - break; - } - } - - // Read out the sample rate - assert(sdi->driver); - - int ret = sr_config_get(sdi->driver, SR_CONF_SAMPLERATE, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get samplerate\n"); - return; - } - sample_rate = g_variant_get_uint64(gvar); - g_variant_unref(gvar); - -// ret = sr_config_get(sdi->driver, SR_CONF_LIMIT_SAMPLES, -// &gvar, sdi); -// if (ret != SR_OK) { -// qDebug("Failed to get total samples"); -// return; -// } -// if (g_variant_get_uint64(gvar) != 0) -// _total_sample_len = g_variant_get_uint64(gvar); -// g_variant_unref(gvar); - - if (sample_rate != _last_sample_rate) { - _last_sample_rate = sample_rate; - sample_rate_changed(sample_rate); - } - ret = sr_config_get(sdi->driver, SR_CONF_EN_CH0, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get ENABLE of DSO channel 0\n"); - return; - } - dso_channel_count += g_variant_get_boolean(gvar); - ret = sr_config_get(sdi->driver, SR_CONF_EN_CH1, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get ENABLE of DSO channel 1\n"); - return; - } - dso_channel_count += g_variant_get_boolean(gvar); - - - // Create data containers for the coming data snapshots - { - boost::lock_guard data_lock(_data_mutex); - - if (logic_probe_count != 0) { - _logic_data.reset(new data::Logic( - logic_probe_count, sample_rate)); - assert(_logic_data); - - _group_data.reset(new data::Group(logic_probe_count, sample_rate)); - assert(_group_data); - } - - if (dso_probe_count != 0) { - _dso_data.reset(new data::Dso(dso_channel_count, sample_rate)); - assert(_dso_data); - } - - if (analog_probe_count != 0) { - _analog_data.reset(new data::Analog(analog_probe_count, sample_rate)); - assert(_analog_data); - } - } + GVariant *gvar; + uint64_t sample_rate = 0; - // Set Signal data + // Read out the sample rate + if(sdi->driver) { - BOOST_FOREACH(const boost::shared_ptr s, _signals) - { - assert(s); - s->set_data(_logic_data, _dso_data, _analog_data, _group_data); + const int ret = sr_config_get(sdi->driver, sdi, NULL, NULL, SR_CONF_SAMPLERATE, &gvar); + if (ret != SR_OK) { + qDebug("Failed to get samplerate\n"); + return; } - receive_data(0); - //signals_changed(); + sample_rate = g_variant_get_uint64(gvar); + g_variant_unref(gvar); + } + + // Set the sample rate of all data + const set< shared_ptr > data_set = get_data(); + BOOST_FOREACH(shared_ptr data, data_set) { + assert(data); + data->set_samplerate(sample_rate); } } +void SigSession::feed_in_header(const sr_dev_inst *sdi) +{ + read_sample_rate(sdi); + //receive_data(0); +} + void SigSession::add_group() { std::list probe_index_list; std::vector< boost::shared_ptr >::iterator i = _signals.begin(); while (i != _signals.end()) { - if ((*i)->get_type() == view::Signal::DS_LOGIC && (*i)->selected()) + if ((*i)->get_type() == view::Trace::DS_LOGIC && (*i)->selected()) probe_index_list.push_back((*i)->get_index()); i++; } if (probe_index_list.size() > 1) { //_group_data.reset(new data::Group(_last_sample_rate)); - const boost::shared_ptr signal = boost::shared_ptr( + if (_group_data->get_snapshots().empty()) + _group_data->set_samplerate(_dev_inst->get_sample_rate()); + const boost::shared_ptr signal( new view::GroupSignal("New Group", - _group_data, probe_index_list, _signals.size(), _group_cnt)); - _signals.push_back(signal); + _group_data, probe_index_list, _group_cnt)); + _group_traces.push_back(signal); _group_cnt++; if (_capture_state == Stopped) { @@ -623,82 +438,26 @@ void SigSession::add_group() void SigSession::del_group() { - std::vector< boost::shared_ptr >::iterator i = _signals.begin(); - while (i != _signals.end()) { - if ((*i)->get_type() == view::Signal::DS_GROUP) { - if ((*i)->selected()) { - std::vector< boost::shared_ptr >::iterator j = _signals.begin(); - while(j != _signals.end()) { - if ((*j)->get_order() > (*i)->get_order()) - (*j)->set_order((*j)->get_order() - 1); - if ((*j)->get_sec_index() > (*i)->get_sec_index()) - (*j)->set_sec_index((*j)->get_sec_index() - 1); - j++; - } - - _group_data->get_snapshots().at((*i)->get_sec_index()).reset(); - std::deque< boost::shared_ptr >::iterator k = _group_data->get_snapshots().begin(); - k += (*i)->get_sec_index(); - _group_data->get_snapshots().erase(k); - - (*i).reset(); - i = _signals.erase(i); - - _group_cnt--; - continue; + std::vector< boost::shared_ptr >::iterator i = _group_traces.begin(); + while (i != _group_traces.end()) { + if ((*i)->selected()) { + std::vector< boost::shared_ptr >::iterator j = _group_traces.begin(); + while(j != _group_traces.end()) { + if ((*j)->get_sec_index() > (*i)->get_sec_index()) + (*j)->set_sec_index((*j)->get_sec_index() - 1); + j++; } - } - i++; - } - - signals_changed(); - data_updated(); -} - -void SigSession::add_protocol(std::list probe_index_list, decoder::Decoder *decoder) -{ - assert(_logic_data); - std::vector< boost::shared_ptr >::iterator i = _signals.begin(); - while (i != _signals.end()) { - (*i)->set_order((*i)->get_order() + 1); - i++; - } - - if (probe_index_list.size() > 0) { - //_group_data.reset(new data::Group(_last_sample_rate)); - const boost::shared_ptr signal = boost::shared_ptr( - new view::ProtocolSignal(decoder->get_decode_name(), - _logic_data, decoder, probe_index_list, 0, _protocol_cnt)); - _signals.push_back(signal); - _protocol_cnt++; + _group_data->get_snapshots().at((*i)->get_sec_index()).reset(); + std::deque< boost::shared_ptr >::iterator k = _group_data->get_snapshots().begin(); + k += (*i)->get_sec_index(); + _group_data->get_snapshots().erase(k); - signals_changed(); - data_updated(); - } -} + (*i).reset(); + i = _group_traces.erase(i); -void SigSession::del_protocol(int protocol_index) -{ - std::vector< boost::shared_ptr >::iterator i = _signals.begin(); - while (i != _signals.end()) { - if ((*i)->get_type() == view::Signal::DS_PROTOCOL) { - if ((*i)->get_sec_index() == protocol_index) { - std::vector< boost::shared_ptr >::iterator j = _signals.begin(); - while(j != _signals.end()) { - if ((*j)->get_order() > (*i)->get_order()) - (*j)->set_order((*j)->get_order() - 1); - if ((*j)->get_sec_index() > (*i)->get_sec_index()) - (*j)->set_sec_index((*j)->get_sec_index() - 1); - j++; - } - - (*i).reset(); - i = _signals.erase(i); - - _protocol_cnt--; - break; - } + _group_cnt--; + continue; } i++; } @@ -707,105 +466,63 @@ void SigSession::del_protocol(int protocol_index) data_updated(); } -void SigSession::del_signal(std::vector< boost::shared_ptr >::iterator i) +void SigSession::init_signals() { - std::vector< boost::shared_ptr >::iterator j = _signals.begin(); - while(j != _signals.end()) { - if ((*j)->get_order() > (*i)->get_order()) - (*j)->set_order((*j)->get_order() - 1); - j++; - } - - (*i).reset(); - _signals.erase(i); -} + assert(_dev_inst); + stop_capture(); -void SigSession::init_signals(const sr_dev_inst *sdi) -{ boost::shared_ptr signal; - GVariant *gvar; - uint64_t sample_rate = 0; unsigned int logic_probe_count = 0; unsigned int dso_probe_count = 0; - unsigned int dso_channel_count = 0; unsigned int analog_probe_count = 0; - uint64_t vdiv; - uint64_t timebase; - bool coupling; - bool active; - int ret; - - // Detect what data types we will receive - for (const GSList *l = sdi->probes; l; l = l->next) { - const sr_probe *const probe = (const sr_probe *)l->data; - if (!probe->enabled) - continue; - switch(probe->type) { - case SR_PROBE_LOGIC: - logic_probe_count++; - break; - case SR_PROBE_DSO: - dso_probe_count++; - break; + // Clear the decode traces + _decode_traces.clear(); - case SR_PROBE_ANALOG: - analog_probe_count++; - break; - } - } - - // Read out the sample rate - assert(sdi->driver); + // Detect what data types we will receive + if(_dev_inst) { + assert(_dev_inst->dev_inst()); + for (const GSList *l = _dev_inst->dev_inst()->channels; + l; l = l->next) { + const sr_channel *const probe = (const sr_channel *)l->data; - ret = sr_config_get(sdi->driver, SR_CONF_SAMPLERATE, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get samplerate\n"); - return; - } - sample_rate = g_variant_get_uint64(gvar); + switch(probe->type) { + case SR_CHANNEL_LOGIC: + if(probe->enabled) + logic_probe_count++; + break; - if (sample_rate != _last_sample_rate) { - _last_sample_rate = sample_rate; - sample_rate_changed(sample_rate); - } + case SR_CHANNEL_DSO: + dso_probe_count++; + break; - ret = sr_config_get(sdi->driver, SR_CONF_EN_CH0, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get ENABLE of DSO channel 0\n"); - return; - } - dso_channel_count += g_variant_get_boolean(gvar); - ret = sr_config_get(sdi->driver, SR_CONF_EN_CH1, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get ENABLE of DSO channel 1\n"); - return; + case SR_CHANNEL_ANALOG: + if(probe->enabled) + analog_probe_count++; + break; + } + } } - dso_channel_count += g_variant_get_boolean(gvar); // Create data containers for the coming data snapshots { if (logic_probe_count != 0) { - _logic_data.reset(new data::Logic( - logic_probe_count, sample_rate)); + _logic_data.reset(new data::Logic(logic_probe_count)); assert(_logic_data); - _group_data.reset(new data::Group(logic_probe_count, sample_rate)); + _group_data.reset(new data::Group()); assert(_group_data); _group_cnt = 0; } if (dso_probe_count != 0) { - _dso_data.reset(new data::Dso(dso_channel_count, sample_rate)); + _dso_data.reset(new data::Dso(dso_probe_count)); assert(_dso_data); } if (analog_probe_count != 0) { - _analog_data.reset(new data::Analog(analog_probe_count, sample_rate)); + _analog_data.reset(new data::Analog(analog_probe_count)); assert(_analog_data); } } @@ -814,240 +531,79 @@ void SigSession::init_signals(const sr_dev_inst *sdi) { _signals.clear(); - for (const GSList *l = sdi->probes; l; l = l->next) { - const sr_probe *const probe = - (const sr_probe *)l->data; + for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { + const sr_channel *const probe = + (const sr_channel *)l->data; assert(probe); - if (!probe->enabled) - continue; - + signal.reset(); switch(probe->type) { - case SR_PROBE_LOGIC: - signal = boost::shared_ptr( - new view::LogicSignal(probe->name, - _logic_data, probe->index, _signals.size())); + case SR_CHANNEL_LOGIC: + if (probe->enabled) + signal = boost::shared_ptr( + new view::LogicSignal(_dev_inst, _logic_data, probe)); break; - case SR_PROBE_DSO: - if (probe->index == 0) { - ret = sr_config_get(sdi->driver, SR_CONF_VDIV0, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get VDIV of channel 0\n"); - return; - } - vdiv = g_variant_get_uint64(gvar); - ret = sr_config_get(sdi->driver, SR_CONF_TIMEBASE, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get TIMEBASE\n"); - return; - } - timebase = g_variant_get_uint64(gvar); - ret = sr_config_get(sdi->driver, SR_CONF_COUPLING0, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get AC COUPLING of channel 0\n"); - return; - } - coupling = g_variant_get_boolean(gvar); - ret = sr_config_get(sdi->driver, SR_CONF_EN_CH0, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get ENABLE of channel 0\n"); - return; - } - active = g_variant_get_boolean(gvar); - } else if (probe->index == 1) { - ret = sr_config_get(sdi->driver, SR_CONF_VDIV1, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get VDIV of channel 1\n"); - return; - } - vdiv = g_variant_get_uint64(gvar); - ret = sr_config_get(sdi->driver, SR_CONF_TIMEBASE, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get TIMEBASE\n"); - return; - } - timebase = g_variant_get_uint64(gvar); - ret = sr_config_get(sdi->driver, SR_CONF_COUPLING1, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get AC COUPLING of channel 1\n"); - return; - } - coupling = g_variant_get_boolean(gvar); - ret = sr_config_get(sdi->driver, SR_CONF_EN_CH1, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get ENABLE of channel 1\n"); - return; - } - active = g_variant_get_boolean(gvar); - } - signal = boost::shared_ptr( - new view::DsoSignal(probe->name, - _dso_data, probe->index, _signals.size(), vdiv, timebase, coupling, active)); + case SR_CHANNEL_DSO: + signal = shared_ptr( + new view::DsoSignal(_dev_inst, _dso_data, probe)); break; - case SR_PROBE_ANALOG: - signal = boost::shared_ptr( - new view::AnalogSignal(probe->name, - _analog_data, probe->index, _signals.size())); + case SR_CHANNEL_ANALOG: + if (probe->enabled) + signal = shared_ptr( + new view::AnalogSignal(_dev_inst, _analog_data, probe)); break; } - - _signals.push_back(signal); + if(signal.get()) + _signals.push_back(signal); } signals_changed(); data_updated(); } - g_variant_unref(gvar); } -void SigSession::update_signals(const sr_dev_inst *sdi) +void SigSession::reload() { - boost::shared_ptr signal; - QMap probes_en_table; - QMap signals_en_table; - int index = 0; - GVariant *gvar; - uint64_t vdiv; - uint64_t timebase; - bool coupling; - bool active; - int ret; + assert(_dev_inst); - std::vector< boost::shared_ptr >::iterator i = _signals.begin(); - while (i != _signals.end()) { - if (((*i)->get_type() == view::Signal::DS_LOGIC || - (*i)->get_type() == view::Signal::DS_DSO || - (*i)->get_type() == view::Signal::DS_ANALOG)) - signals_en_table.insert((*i)->get_index(), 1); - i++; - } + if (_capture_state == Running) + stop_capture(); - index = 0; - for (const GSList *l = sdi->probes; l; l = l->next) { - const sr_probe *const probe = - (const sr_probe *)l->data; - assert(probe); - probes_en_table.insert(index, probe->enabled); - if (probe->enabled && !signals_en_table.contains(index)) { - i = _signals.begin(); - while (i != _signals.end()) { - (*i)->set_order((*i)->get_order() + 1); - i++; - } + boost::shared_ptr signal; + + // Make the logic probe list + { + _signals.clear(); + for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { + const sr_channel *const probe = + (const sr_channel *)l->data; + assert(probe); + signal.reset(); switch(probe->type) { - case SR_PROBE_LOGIC: - signal = boost::shared_ptr( - new view::LogicSignal(probe->name, - _logic_data, probe->index, 0)); + case SR_CHANNEL_LOGIC: + if (probe->enabled) + signal = boost::shared_ptr( + new view::LogicSignal(_dev_inst, _logic_data, probe)); break; - case SR_PROBE_DSO: - if (probe->index == 0) { - ret = sr_config_get(sdi->driver, SR_CONF_VDIV0, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get VDIV of channel 0\n"); - return; - } - vdiv = g_variant_get_uint64(gvar); - ret = sr_config_get(sdi->driver, SR_CONF_TIMEBASE, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get TIMEBASE\n"); - return; - } - timebase = g_variant_get_uint64(gvar); - ret = sr_config_get(sdi->driver, SR_CONF_COUPLING0, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get AC COUPLING of channel 0\n"); - return; - } - coupling = g_variant_get_boolean(gvar); - ret = sr_config_get(sdi->driver, SR_CONF_EN_CH0, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get ENABLE of channel 0\n"); - return; - } - active = g_variant_get_boolean(gvar); - } else if (probe->index == 1) { - ret = sr_config_get(sdi->driver, SR_CONF_VDIV1, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get VDIV of channel 1\n"); - return; - } - vdiv = g_variant_get_uint64(gvar); - ret = sr_config_get(sdi->driver, SR_CONF_TIMEBASE, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get TIMEBASE\n"); - return; - } - timebase = g_variant_get_uint64(gvar); - ret = sr_config_get(sdi->driver, SR_CONF_COUPLING1, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get AC COUPLING of channel 1\n"); - return; - } - coupling = g_variant_get_boolean(gvar); - ret = sr_config_get(sdi->driver, SR_CONF_EN_CH1, - &gvar, sdi); - if (ret != SR_OK) { - qDebug("Failed to get ENABLE of channel 1\n"); - return; - } - active = g_variant_get_boolean(gvar); - } - signal = boost::shared_ptr( - new view::DsoSignal(probe->name, - _dso_data, probe->index, _signals.size(), vdiv, timebase, coupling, active)); + case SR_CHANNEL_DSO: + signal = shared_ptr( + new view::DsoSignal(_dev_inst,_dso_data, probe)); break; - case SR_PROBE_ANALOG: - signal = boost::shared_ptr( - new view::AnalogSignal(probe->name, - _analog_data, probe->index, 0)); + case SR_CHANNEL_ANALOG: + if (probe->enabled) + signal = shared_ptr( + new view::AnalogSignal(_dev_inst, _analog_data, probe)); break; } - _signals.push_back(signal); + if (signal.get()) + _signals.push_back(signal); } - index++; - } - - i = _signals.begin(); - while (i != _signals.end()) { - if (((*i)->get_type() == view::Signal::DS_LOGIC || - (*i)->get_type() == view::Signal::DS_DSO || - (*i)->get_type() == view::Signal::DS_ANALOG) && - probes_en_table.value((*i)->get_index()) == false) { - std::vector< boost::shared_ptr >::iterator j = _signals.begin(); - while(j != _signals.end()) { - if ((*j)->get_order() > (*i)->get_order()) - (*j)->set_order((*j)->get_order() - 1); - j++; - } - - (*i).reset(); - i = _signals.erase(i); - continue; - } - i++; } signals_changed(); - data_updated(); } void SigSession::feed_in_meta(const sr_dev_inst *sdi, @@ -1092,11 +648,19 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) { // Create a new data snapshot _cur_logic_snapshot = boost::shared_ptr( - new data::LogicSnapshot(logic, _total_sample_len, 1)); + new data::LogicSnapshot(logic, _dev_inst->get_sample_limit(), 1)); if (_cur_logic_snapshot->buf_null()) + { stop_capture(); - else + } else { _logic_data->push_snapshot(_cur_logic_snapshot); + } + + // @todo Putting this here means that only listeners querying + // for logic will be notified. Currently the only user of + // frame_began is DecoderStack, but in future we need to signal + // this after both analog and logic sweeps have begun. + frame_began(); } else { @@ -1105,6 +669,7 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) } receive_data(logic.length/logic.unitsize); + data_received(); //data_updated(); } @@ -1122,7 +687,7 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) { // Create a new data snapshot _cur_dso_snapshot = boost::shared_ptr( - new data::DsoSnapshot(dso, _total_sample_len, _dso_data->get_num_probes())); + new data::DsoSnapshot(dso, _dev_inst->get_sample_limit(), _dso_data->get_num_probes())); if (_cur_dso_snapshot->buf_null()) stop_capture(); else @@ -1152,7 +717,7 @@ void SigSession::feed_in_analog(const sr_datafeed_analog &analog) { // Create a new data snapshot _cur_analog_snapshot = boost::shared_ptr( - new data::AnalogSnapshot(analog, _total_sample_len, _analog_data->get_num_probes())); + new data::AnalogSnapshot(analog, _dev_inst->get_sample_limit(), _analog_data->get_num_probes())); if (_cur_analog_snapshot->buf_null()) stop_capture(); else @@ -1209,24 +774,24 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, { { boost::lock_guard lock(_data_mutex); - BOOST_FOREACH(const boost::shared_ptr s, _signals) + BOOST_FOREACH(const boost::shared_ptr g, _group_traces) { - assert(s); - if (s->get_type() == view::Signal::DS_GROUP) { - _cur_group_snapshot = boost::shared_ptr( - new data::GroupSnapshot(_logic_data->get_snapshots().front(), s->get_index_list())); - //_cur_group_snapshot->append_payload(); - _group_data->push_snapshot(_cur_group_snapshot); - _cur_group_snapshot.reset(); - } - if (s->get_type() == view::Signal::DS_PROTOCOL) { - s->get_decoder()->decode(); - } + assert(g); + + _cur_group_snapshot = boost::shared_ptr( + new data::GroupSnapshot(_logic_data->get_snapshots().front(), g->get_index_list())); + _group_data->push_snapshot(_cur_group_snapshot); } - _cur_logic_snapshot.reset(); + _cur_logic_snapshot.reset(); _cur_dso_snapshot.reset(); _cur_analog_snapshot.reset(); } + for (vector< shared_ptr >::iterator i = + _decode_traces.begin(); + i != _decode_traces.end(); + i++) + (*i)->decoder()->stop_decode(); + frame_ended(); break; } } @@ -1240,81 +805,6 @@ void SigSession::data_feed_in_proc(const struct sr_dev_inst *sdi, _session->data_feed_in(sdi, packet); } -QVector > > SigSession::get_decoders() const -{ - return _decoders; -} - -void SigSession::add_protocol_analyzer(int decoder_index, std::list _sel_probes, - QMap & _options, QMap _options_index) -{ - decoder::Decoder *decoder; - - // new different docoder according to protocol_list in decoder.h - decoder = _decoderFactory->createDecoder(decoder_index, _logic_data, _sel_probes, _options, _options_index); - - // if current data is valid, do decode - if (_logic_data) - decoder->decode(); - _decoders.push_back(std::pair >(decoder, _sel_probes)); - -// // config signal's attribute for display -// BOOST_FOREACH(const int _index, _sel_probes) { -// _signals.at(_index)->set_decoder(decoder); -// } - - // add protocol decoder signal - add_protocol(_sel_probes, decoder); -} - -void SigSession::rst_protocol_analyzer(int rst_index, std::list _sel_probes, - QMap & _options, QMap _options_index) -{ - // if current data is valid, redo decode - if (_logic_data) - _decoders.at(rst_index).first->recode(_sel_probes, _options, _options_index); - - BOOST_FOREACH(const boost::shared_ptr s, _signals) - { - assert(s); - if (s->get_decoder() == _decoders.at(rst_index).first) { - s->set_index_list(s->get_decoder()->get_probes()); - break; - } - } - - // update protocol signal - signals_changed(); - data_updated(); -} - -void SigSession::del_protocol_analyzer(int protocol_index) -{ - assert(protocol_index < _decoders.size()); - //delete (_decoders.at(protocol_index)).first; - -// BOOST_FOREACH(const int _index, (_decoders.at(protocol_index)).second) { -// _signals.at(_index)->del_decoder(); -// } - del_protocol(protocol_index); - - _decoders.remove(protocol_index); -} - -std::list SigSession::get_decode_probes(int decode_index) -{ - assert(decode_index >= 0); - assert(decode_index < _decoders.size()); - return _decoders.at(decode_index).first->get_probes(); -} - -QMap SigSession::get_decode_options_index(int decode_index) -{ - assert(decode_index >= 0); - assert(decode_index < _decoders.size()); - return _decoders.at(decode_index).first->get_options_index(); -} - /* * hotplug function */ @@ -1344,7 +834,7 @@ void SigSession::hotplug_proc(boost::function error_handle (void)error_handler; - if (!_sdi) + if (!_dev_inst) return; tv.tv_sec = tv.tv_usec = 0; @@ -1355,7 +845,6 @@ void SigSession::hotplug_proc(boost::function error_handle qDebug("DSLogic hardware attached!"); device_attach(); _hot_attach = false; - break; } if (_hot_detach) { qDebug("DSLogic hardware detached!"); @@ -1364,7 +853,6 @@ void SigSession::hotplug_proc(boost::function error_handle _dso_data.reset(); _analog_data.reset(); _hot_detach = false; - break; } boost::this_thread::sleep(boost::posix_time::millisec(100)); } @@ -1424,91 +912,148 @@ void SigSession::set_adv_trigger(bool adv_trigger) } -/* - * oscilloscope control - */ -void SigSession::start_dso_ctrl_proc(boost::function error_handler) +uint16_t SigSession::get_dso_ch_num() { - - // Begin the dso control thread - _dso_ctrl_thread.reset(new boost::thread( - &SigSession::dso_ctrl_proc, this, error_handler)); - + uint16_t num_channels = 0; + BOOST_FOREACH(const shared_ptr s, _signals) + { + assert(s); + //if (dynamic_pointer_cast(s) && s->enabled()) { + if (dynamic_pointer_cast(s)) { + num_channels++; + } + } + return num_channels; } -void SigSession::stop_dso_ctrl_proc() +#ifdef ENABLE_DECODE +bool SigSession::add_decoder(srd_decoder *const dec) { + bool ret = false; + map > probes; + shared_ptr decoder_stack; - if (_dso_ctrl_thread.get()) { - _dso_ctrl_thread->interrupt(); - _dso_ctrl_thread->join(); + try + { + //lock_guard lock(_signals_mutex); + + // Create the decoder + decoder_stack = shared_ptr( + new data::DecoderStack(*this, dec)); + + // Make a list of all the probes + std::vector all_probes; + for(const GSList *i = dec->channels; i; i = i->next) + all_probes.push_back((const srd_channel*)i->data); + for(const GSList *i = dec->opt_channels; i; i = i->next) + all_probes.push_back((const srd_channel*)i->data); + + assert(decoder_stack); + assert(!decoder_stack->stack().empty()); + assert(decoder_stack->stack().front()); + decoder_stack->stack().front()->set_probes(probes); + + // Create the decode signal + shared_ptr d( + new view::DecodeTrace(*this, decoder_stack, + _decode_traces.size())); + if (d->create_popup()) { + _decode_traces.push_back(d); + ret = true; + } + } + catch(std::runtime_error e) + { + return false; } - _dso_ctrl_thread.reset(); -} - -int SigSession::set_dso_ctrl(int key) -{ - int ret; - if (key== SR_CONF_TIMEBASE) { - uint64_t timebase = _signals.at(0)->get_hDialValue(); - ret = sr_config_set(_sdi, key, g_variant_new_uint64(timebase)); - } else if (key == SR_CONF_VDIV0) { - uint64_t vdiv = _signals.at(0)->get_vDialValue(); - ret = sr_config_set(_sdi, key, g_variant_new_uint64(vdiv)); - } else if (key == SR_CONF_VDIV1) { - uint64_t vdiv = _signals.at(1)->get_vDialValue(); - ret = sr_config_set(_sdi, key, g_variant_new_uint64(vdiv)); - } else if (key == SR_CONF_COUPLING0) { - bool acdc = _signals.at(0)->get_acCoupling(); - ret = sr_config_set(_sdi, key, g_variant_new_boolean(acdc)); - } else if (key == SR_CONF_COUPLING1) { - bool acdc = _signals.at(1)->get_acCoupling(); - ret = sr_config_set(_sdi, key, g_variant_new_boolean(acdc)); - } else if (key == SR_CONF_EN_CH0) { - bool enable = _signals.at(0)->get_active(); - ret = sr_config_set(_sdi, key, g_variant_new_boolean(enable)); - dso_ch_changed(get_dso_ch_num()); - } else if (key == SR_CONF_EN_CH1) { - bool enable = _signals.at(1)->get_active(); - ret = sr_config_set(_sdi, key, g_variant_new_boolean(enable)); - dso_ch_changed(get_dso_ch_num()); + if (ret) { + signals_changed(); + // Do an initial decode + decoder_stack->begin_decode(); + data_updated(); } return ret; } -uint16_t SigSession::get_dso_ch_num() +vector< shared_ptr > SigSession::get_decode_signals() const { - uint16_t num_channels = 0; - BOOST_FOREACH(const shared_ptr s, _signals) + lock_guard lock(_signals_mutex); + return _decode_traces; +} + +void SigSession::remove_decode_signal(view::DecodeTrace *signal) +{ + for (vector< shared_ptr >::iterator i = + _decode_traces.begin(); + i != _decode_traces.end(); + i++) + if ((*i).get() == signal) + { + _decode_traces.erase(i); + signals_changed(); + return; + } +} + +void SigSession::remove_decode_signal(int index) +{ + int cur_index = 0; + for (vector< shared_ptr >::iterator i = + _decode_traces.begin(); + i != _decode_traces.end(); + i++) { - assert(s); - if (s->get_active()) { - num_channels++; + if (cur_index == index) + { + _decode_traces.erase(i); + signals_changed(); + return; } + cur_index++; } - return num_channels; } -void SigSession::dso_ctrl_proc(boost::function error_handler) +void SigSession::rst_decoder(int index) { - (void)error_handler; - try { - while(_session) { - if (!_sdi) { - // do nothing - } else if (strcmp(_sdi->driver->name, "Demo") == 0) { - - } else if (strcmp(_sdi->driver->name, "DSLogic") == 0) { - + int cur_index = 0; + for (vector< shared_ptr >::iterator i = + _decode_traces.begin(); + i != _decode_traces.end(); + i++) + { + if (cur_index == index) + { + if ((*i)->create_popup()) + { + (*i)->decoder()->stop_decode(); + (*i)->decoder()->begin_decode(); + data_updated(); } - boost::this_thread::sleep(boost::posix_time::millisec(100)); + return; } - } catch(...) { - qDebug("Interrupt exception for oscilloscope control thread was thrown."); + cur_index++; } - qDebug("Oscilloscope control thread exit!"); } +void SigSession::rst_decoder(view::DecodeTrace *signal) +{ + for (vector< shared_ptr >::iterator i = + _decode_traces.begin(); + i != _decode_traces.end(); + i++) + if ((*i).get() == signal) + { + if ((*i)->create_popup()) + { + (*i)->decoder()->stop_decode(); + (*i)->decoder()->begin_decode(); + data_updated(); + } + return; + } +} +#endif + } // namespace pv diff --git a/DSLogic-gui/pv/sigsession.h b/DSLogic-gui/pv/sigsession.h index a8d8cfb2f4d3b4607aee267c709617be4888ba95..28fd79f1b289b3760735ad9abb57db0de2127101 100644 --- a/DSLogic-gui/pv/sigsession.h +++ b/DSLogic-gui/pv/sigsession.h @@ -31,6 +31,9 @@ #include #include +#include +#include +#include #include #include @@ -43,11 +46,15 @@ #include #include +struct srd_decoder; +struct srd_channel; + namespace pv { class DeviceManager; namespace data { +class SignalData; class Analog; class AnalogSnapshot; class Dso; @@ -58,8 +65,14 @@ class Group; class GroupSnapshot; } +namespace device { +class DevInst; +} + namespace view { class Signal; +class GroupSignal; +class DecodeTrace; } namespace decoder { @@ -86,69 +99,61 @@ public: ~SigSession(); - struct sr_dev_inst* get_device() const; + boost::shared_ptr get_device() const; /** * Sets device instance that will be used in the next capture session. */ - int set_device(struct sr_dev_inst *sdi); + void set_device(boost::shared_ptr dev_inst) + throw(QString); - void release_device(struct sr_dev_inst *sdi); - - void load_file(const std::string &name, - boost::function error_handler); + void set_file(const std::string &name) + throw(QString); void save_file(const std::string &name); + void set_default_device(); + + void release_device(device::DevInst *dev_inst); + capture_state get_capture_state() const; - void start_capture(uint64_t record_length, + void start_capture(bool instant, boost::function error_handler); void stop_capture(); + std::set< boost::shared_ptr > get_data() const; + std::vector< boost::shared_ptr > get_signals(); - std::vector< boost::shared_ptr > - get_pro_signals(); - - int get_logic_probe_cnt(const struct sr_dev_inst *sdi); - int get_dso_probe_cnt(const struct sr_dev_inst *sdi); - int get_analog_probe_cnt(const struct sr_dev_inst *sdi); - - void init_signals(const struct sr_dev_inst *sdi); - - void update_signals(const struct sr_dev_inst *sdi); - void add_group(); + std::vector< boost::shared_ptr > + get_group_signals(); - void del_group(); +#ifdef ENABLE_DECODE + bool add_decoder(srd_decoder *const dec); - void add_protocol(std::list probe_index_list, decoder::Decoder *decoder); + std::vector< boost::shared_ptr > + get_decode_signals() const; - void del_protocol(int protocol_index); + void remove_decode_signal(view::DecodeTrace *signal); - void del_signal(std::vector< boost::shared_ptr >::iterator i); + void remove_decode_signal(int index); - boost::shared_ptr get_data(); + void rst_decoder(int index); - void* get_buf(int& unit_size, uint64_t& length); + void rst_decoder(view::DecodeTrace *signal); - quint64 get_last_sample_rate() const; +#endif - quint64 get_total_sample_len() const; - void set_total_sample_len(quint64 length); + void init_signals(); - QVector > > get_decoders() const; + void add_group(); - void add_protocol_analyzer(int decoder_index, std::list _sel_probes, - QMap &_options, QMap _options_index); - void rst_protocol_analyzer(int rst_index, std::list _sel_probes, - QMap &_options, QMap _options_index); - void del_protocol_analyzer(int protocol_index); + void del_group(); - std::list get_decode_probes(int decode_index); - QMap get_decode_options_index(int decode_index); + void* get_buf(int& unit_size, uint64_t& length); void start_hotplug_proc(boost::function error_handler); void stop_hotplug_proc(); @@ -157,21 +162,33 @@ public: void set_adv_trigger(bool adv_trigger); - void start_dso_ctrl_proc(boost::function error_handler); - void stop_dso_ctrl_proc(); - int set_dso_ctrl(int key); uint16_t get_dso_ch_num(); + + void set_sample_rate(uint64_t sample_rate); private: void set_capture_state(capture_state state); + void read_sample_rate(const sr_dev_inst *const sdi); + private: - // thread for sample/load - void load_thread_proc(const std::string name, - boost::function error_handler); - void sample_thread_proc(struct sr_dev_inst *sdi, - uint64_t record_length, - boost::function error_handler); + /** + * 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, + boost::function error_handler, + sr_input_format *format = NULL); + + void sample_thread_proc(boost::shared_ptr dev_inst, + boost::function error_handler); // data feed void feed_in_header(const sr_dev_inst *sdi); @@ -186,11 +203,9 @@ private: static void data_feed_in_proc(const struct sr_dev_inst *sdi, const struct sr_datafeed_packet *packet, void *cb_data); - void hotplug_proc(boost::function error_handler); - static int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, - libusb_hotplug_event event, void *user_data); - - void dso_ctrl_proc(boost::function error_handler); + void hotplug_proc(boost::function error_handler); + static int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, + libusb_hotplug_event event, void *user_data); private: DeviceManager &_device_manager; @@ -198,19 +213,18 @@ private: /** * The device instance that will be used in the next capture session. */ - struct sr_dev_inst *_sdi; + boost::shared_ptr _dev_inst; mutable boost::mutex _sampling_mutex; capture_state _capture_state; + bool _instant; mutable boost::mutex _signals_mutex; std::vector< boost::shared_ptr > _signals; + std::vector< boost::shared_ptr > _group_traces; + std::vector< boost::shared_ptr > _decode_traces; - decoder::DecoderFactory *_decoderFactory; - QVector< std::pair > > _decoders; - std::vector< boost::shared_ptr > _protocol_signals; - - mutable boost::mutex _data_mutex; + mutable boost::mutex _data_mutex; boost::shared_ptr _logic_data; boost::shared_ptr _cur_logic_snapshot; boost::shared_ptr _dso_data; @@ -220,14 +234,9 @@ private: boost::shared_ptr _group_data; boost::shared_ptr _cur_group_snapshot; int _group_cnt; - int _protocol_cnt; std::auto_ptr _sampling_thread; - quint64 _last_sample_rate; - - quint64 _total_sample_len; - libusb_hotplug_callback_handle _hotplug_handle; std::auto_ptr _hotplug; bool _hot_attach; @@ -235,11 +244,6 @@ private: bool _adv_trigger; - bool _vDial_changed; - bool _hDial_changed; - uint16_t _dso_ctrl_channel; - std::auto_ptr _dso_ctrl_thread; - signals: void capture_state_changed(int state); @@ -247,7 +251,7 @@ signals: void data_updated(); - void sample_rate_changed(quint64 sample_rate); + void sample_rate_changed(uint64_t sample_rate); void receive_data(quint64 length); @@ -260,8 +264,16 @@ signals: void dso_ch_changed(uint16_t num); -public slots: + void frame_began(); + + void data_received(); + void frame_ended(); + + void device_setted(); + +public slots: + void reload(); private: // TODO: This should not be necessary. Multiple concurrent diff --git a/DSLogic-gui/pv/storesession.cpp b/DSLogic-gui/pv/storesession.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2270ae5d45074dc62388cf203a99703b4f16e32b --- /dev/null +++ b/DSLogic-gui/pv/storesession.cpp @@ -0,0 +1,195 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 "storesession.h" + +#include +#include +#include +#include + +using boost::dynamic_pointer_cast; +using boost::mutex; +using boost::shared_ptr; +using boost::thread; +using boost::lock_guard; +using std::deque; +using std::make_pair; +using std::min; +using std::pair; +using std::set; +using std::string; +using std::vector; + +namespace pv { + +const size_t StoreSession::BlockSize = 1024 * 1024; + +StoreSession::StoreSession(const std::string &file_name, + SigSession &session) : + _file_name(file_name), + _session(session), + _units_stored(0), + _unit_count(0) +{ +} + +StoreSession::~StoreSession() +{ + wait(); +} + +pair StoreSession::progress() const +{ + lock_guard lock(_mutex); + return make_pair(_units_stored, _unit_count); +} + +const QString& StoreSession::error() const +{ + lock_guard lock(_mutex); + return _error; +} + +bool StoreSession::start() +{ + set< shared_ptr > data_set = + _session.get_data(); + const vector< shared_ptr > sigs(_session.get_signals()); + + // Check we have logic data + if (data_set.empty() || sigs.empty()) { + _error = tr("No data to save."); + return false; + } + + if (data_set.size() > 1) { + _error = tr("DSLogic currently only has support for " + "storing a single data stream."); + return false; + } + + // Get the logic data + //shared_ptr data; + if (!(data = dynamic_pointer_cast(*data_set.begin()))) { + _error = tr("DSLogic currently only has support for " + "storing a logic data."); + return false; + } + + // Get the snapshot + const deque< shared_ptr > &snapshots = + data->get_snapshots(); + + if (snapshots.empty()) { + _error = tr("No snapshots to save."); + return false; + } + + const shared_ptr snapshot(snapshots.front()); + assert(snapshot); + + // Make a list of probes + char **const probes = new char*[sigs.size() + 1]; + for (size_t i = 0; i < sigs.size(); i++) { + shared_ptr sig(sigs[i]); + assert(sig); + probes[i] = strdup(sig->get_name().toUtf8().constData()); + } + probes[sigs.size()] = NULL; + + // Begin storing + if (sr_session_save_init(_file_name.c_str(), + data->samplerate(), probes) != SR_OK) { + _error = tr("Error while saving."); + return false; + } + + // Delete the probes array + for (size_t i = 0; i <= sigs.size(); i++) + free(probes[i]); + delete[] probes; + + _thread = boost::thread(&StoreSession::store_proc, this, snapshot); + return true; +} + +void StoreSession::wait() +{ + if (_thread.joinable()) + _thread.join(); +} + +void StoreSession::cancel() +{ + _thread.interrupt(); +} + +void StoreSession::store_proc(shared_ptr snapshot) +{ + assert(snapshot); + + uint64_t start_sample = 0; + + /// TODO: Wrap this in a std::unique_ptr when we transition to C++11 + uint8_t *const data = new uint8_t[BlockSize]; + assert(data); + + const int unit_size = snapshot->unit_size(); + assert(unit_size != 0); + + { + lock_guard lock(_mutex); + _unit_count = snapshot->get_sample_count(); + } + + const unsigned int samples_per_block = BlockSize / unit_size; + + while (!boost::this_thread::interruption_requested() && + start_sample < _unit_count) + { + progress_updated(); + + const uint64_t end_sample = min( + start_sample + samples_per_block, _unit_count); + snapshot->get_samples(data, start_sample, end_sample); + + if(sr_session_append(_file_name.c_str(), data, unit_size, + end_sample - start_sample) != SR_OK) + { + _error = tr("Error while saving."); + break; + } + + start_sample = end_sample; + + { + lock_guard lock(_mutex); + _units_stored = start_sample; + } + } + + progress_updated(); + + delete[] data; +} + +} // pv diff --git a/DSLogic-gui/pv/storesession.h b/DSLogic-gui/pv/storesession.h new file mode 100644 index 0000000000000000000000000000000000000000..c8937603287aac61c8ea5826915fde5abc7408a8 --- /dev/null +++ b/DSLogic-gui/pv/storesession.h @@ -0,0 +1,83 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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_STORESESSION_H +#define DSLOGIC_PV_STORESESSION_H + +#include + +#include + +#include + +#include + +namespace pv { + +class SigSession; + +namespace data { +class LogicSnapshot; +} + +class StoreSession : public QObject +{ + Q_OBJECT + +private: + static const size_t BlockSize; + +public: + StoreSession(const std::string &file_name, + SigSession &session); + + ~StoreSession(); + + std::pair progress() const; + + const QString& error() const; + + bool start(); + + void wait(); + + void cancel(); + +private: + void store_proc(boost::shared_ptr snapshot); + +signals: + void progress_updated(); + +private: + const std::string _file_name; + SigSession &_session; + + boost::thread _thread; + + mutable boost::mutex _mutex; + uint64_t _units_stored; + uint64_t _unit_count; + QString _error; +}; + +} // pv + +#endif // DSLOGIC_PV_STORESESSION_H diff --git a/DSLogic-gui/pv/toolbars/filebar.cpp b/DSLogic-gui/pv/toolbars/filebar.cpp index 112422318a44073d92c2d7627bfdb26a8017b851..80ff5b778d226de4bb290b8b40b6e26f75a4a3d8 100644 --- a/DSLogic-gui/pv/toolbars/filebar.cpp +++ b/DSLogic-gui/pv/toolbars/filebar.cpp @@ -31,6 +31,7 @@ #include #include "filebar.h" +#include "../device/devinst.h" #include @@ -80,23 +81,14 @@ FileBar::FileBar(SigSession &session, QWidget *parent) : void FileBar::on_actionOpen_triggered() { + // Show the dialog const QString file_name = QFileDialog::getOpenFileName( - this, tr("Open File"), "", - tr("DSLogic Sessions (*.dsl)")); + this, tr("Open File"), "", tr( + "DSLogic Sessions (*.dsl)")); if (!file_name.isEmpty()) load_file(file_name); } -void FileBar::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(&FileBar::session_error, this, - errorMessage, infoMessage)); -} - void FileBar::session_error( const QString text, const QString info_text) { @@ -118,23 +110,31 @@ void FileBar::show_session_error( void FileBar::on_actionSave_triggered() { + //save(); int unit_size; uint64_t length; void* buf = _session.get_buf(unit_size, length); - if (buf != NULL) { - const QString file_name = QFileDialog::getSaveFileName( - this, tr("Save File"), "", - tr("DSLogic Session (*.dsl)")); - if (!file_name.isEmpty()) { - _session.save_file(file_name.toStdString()); - } - } else { + if (!buf) { QMessageBox msg(this); msg.setText("File Save"); msg.setInformativeText("No Data to Save!"); msg.setStandardButtons(QMessageBox::Ok); msg.setIcon(QMessageBox::Warning); msg.exec(); + } else if (_session.get_device()->dev_inst()->mode != LOGIC) { + QMessageBox msg(this); + msg.setText("File Save"); + msg.setInformativeText("DSLogic currently only support saving logic data to file!"); + msg.setStandardButtons(QMessageBox::Ok); + msg.setIcon(QMessageBox::Warning); + msg.exec(); + }else { + const QString file_name = QFileDialog::getSaveFileName( + this, tr("Save File"), "", + tr("DSLogic Session (*.dsl)")); + if (!file_name.isEmpty()) { + _session.save_file(file_name.toStdString()); + } } } @@ -146,6 +146,8 @@ void FileBar::on_actionCapture_triggered() void FileBar::enable_toggle(bool enable) { _file_button.setDisabled(!enable); + _file_button.setIcon(enable ? QIcon(":/icons/file.png") : + QIcon(":/icons/file_dis.png")); } } // namespace toolbars diff --git a/DSLogic-gui/pv/toolbars/filebar.h b/DSLogic-gui/pv/toolbars/filebar.h index e0760f86c36e1aadf336b3cd02fe75170ed9b603..67567b3e85b246eefe32f6e049b0bab1f5a58ac0 100644 --- a/DSLogic-gui/pv/toolbars/filebar.h +++ b/DSLogic-gui/pv/toolbars/filebar.h @@ -43,13 +43,15 @@ public: void enable_toggle(bool enable); private: - void load_file(QString file_name); + void session_error( const QString text, const QString info_text); void show_session_error( const QString text, const QString info_text); signals: + void load_file(QString); + void save(); void on_screenShot(); private slots: diff --git a/DSLogic-gui/pv/toolbars/logobar.cpp b/DSLogic-gui/pv/toolbars/logobar.cpp index 9aa17f81a2a598f52c5e9fba792f937a0b97a897..9954e500f29f740bfefb767d88b888db24c3ae30 100644 --- a/DSLogic-gui/pv/toolbars/logobar.cpp +++ b/DSLogic-gui/pv/toolbars/logobar.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include "logobar.h" #include "../dialogs/about.h" @@ -52,6 +54,15 @@ LogoBar::LogoBar(SigSession &session, QWidget *parent) : _logo_button.addAction(_about); connect(_about, SIGNAL(triggered()), this, SLOT(on_actionAbout_triggered())); + _wiki = new QAction(this); + _wiki->setText(QApplication::translate( + "File", "&Wiki", 0, QApplication::UnicodeUTF8)); + _wiki->setIcon(QIcon::fromTheme("file", + QIcon(":/icons/wiki.png"))); + _wiki->setObjectName(QString::fromUtf8("actionWiki")); + _logo_button.addAction(_wiki); + connect(_wiki, SIGNAL(triggered()), this, SLOT(on_actionWiki_triggered())); + _logo_button.setPopupMode(QToolButton::InstantPopup); _logo_button.setIcon(QIcon(":/icons/logo_noColor.png")); @@ -97,6 +108,12 @@ void LogoBar::on_actionAbout_triggered() dlg.exec(); } +void LogoBar::on_actionWiki_triggered() +{ + QDesktopServices::openUrl( + QUrl(QLatin1String("http://www.dreamsourcelab.com/wiki"))); +} + void LogoBar::enable_toggle(bool enable) { _logo_button.setDisabled(!enable); diff --git a/DSLogic-gui/pv/toolbars/logobar.h b/DSLogic-gui/pv/toolbars/logobar.h index df5508a4b0f2eced3997777d90502c2071f23532..06132719bd3f2bc0a5c432bfb2e6a612583a2dbe 100644 --- a/DSLogic-gui/pv/toolbars/logobar.h +++ b/DSLogic-gui/pv/toolbars/logobar.h @@ -45,7 +45,6 @@ public: void dslogic_connected(bool conn); private: - void load_file(QString file_name); void session_error( const QString text, const QString info_text); void show_session_error( @@ -55,6 +54,7 @@ signals: private slots: void on_actionAbout_triggered(); + void on_actionWiki_triggered(); private: bool _enable; @@ -63,6 +63,7 @@ private: QToolButton _logo_button; QAction *_about; + QAction *_wiki; }; diff --git a/DSLogic-gui/pv/toolbars/samplingbar.cpp b/DSLogic-gui/pv/toolbars/samplingbar.cpp index 028393930a2983c56a39ac0e3ce72a9496acd30f..dd29b0d095ed82e1565a19bc0e685a37c0c35b42 100644 --- a/DSLogic-gui/pv/toolbars/samplingbar.cpp +++ b/DSLogic-gui/pv/toolbars/samplingbar.cpp @@ -35,7 +35,15 @@ #include "samplingbar.h" -using namespace std; +#include "../devicemanager.h" +#include "../device/devinst.h" +#include "../dialogs/deviceoptions.h" + +using boost::shared_ptr; +using std::map; +using std::max; +using std::min; +using std::string; namespace pv { namespace toolbars { @@ -84,93 +92,153 @@ const uint64_t SamplingBar::DSLogic_RecordLengths[15] = { const uint64_t SamplingBar::DSLogic_DefaultRecordLength = 16777216; -SamplingBar::SamplingBar(QWidget *parent) : +SamplingBar::SamplingBar(SigSession &session, QWidget *parent) : QToolBar("Sampling Bar", parent), - _record_length_selector(this), - _sample_rate_list(this), + _session(session), + _enable(true), + _device_selector(this), + _updating_device_selector(false), + _configure_button(this), + _sample_count(this), + _sample_rate(this), + _updating_sample_rate(false), + _updating_sample_count(false), _icon_stop(":/icons/stop.png"), _icon_start(":/icons/start.png"), - _run_stop_button(this) + _icon_instant(":/icons/instant.png"), + _run_stop_button(this), + _instant_button(this), + _instant(false) { setMovable(false); + connect(&_device_selector, SIGNAL(currentIndexChanged (int)), + this, SLOT(on_device_selected())); + connect(&_configure_button, SIGNAL(clicked()), + this, SLOT(on_configure())); connect(&_run_stop_button, SIGNAL(clicked()), this, SLOT(on_run_stop())); + connect(&_instant_button, SIGNAL(clicked()), + this, SLOT(on_instant_stop())); + + _configure_button.setIcon(QIcon::fromTheme("configure", + QIcon(":/icons/params.png"))); + _run_stop_button.setIcon(_icon_start); + _instant_button.setIcon(_icon_instant); // for (size_t i = 0; i < countof(RecordLengths); i++) // { // const uint64_t &l = RecordLengths[i]; // char *const text = ds_si_string_u64(l, " samples"); -// _record_length_selector.addItem(QString(text), +// _sample_count.addItem(QString(text), // qVariantFromValue(l)); // g_free(text); // if (l == DefaultRecordLength) -// _record_length_selector.setCurrentIndex(i); +// _sample_count.setCurrentIndex(i); // } - _record_length_selector.setSizeAdjustPolicy(QComboBox::AdjustToContents); + _sample_count.setSizeAdjustPolicy(QComboBox::AdjustToContents); set_sampling(false); //_run_stop_button.setToolButtonStyle(Qt::ToolButtonTextBesideIcon); _run_stop_button.setObjectName(tr("run_stop_button")); + connect(&_sample_rate, SIGNAL(currentIndexChanged(int)), + this, SLOT(on_samplerate_sel(int))); + addWidget(new QLabel(tr(" "))); - addWidget(&_record_length_selector); + addWidget(&_device_selector); + addWidget(&_configure_button); + addWidget(&_sample_count); addWidget(new QLabel(tr(" @ "))); - _sample_rate_list_action = addWidget(&_sample_rate_list); + addWidget(&_sample_rate); addWidget(&_run_stop_button); - - connect(&_sample_rate_list, SIGNAL(currentIndexChanged(int)), - this, SLOT(on_sample_rate_changed())); + addWidget(&_instant_button); } -void SamplingBar::set_device(struct sr_dev_inst *sdi) +void SamplingBar::set_device_list( + const std::list< shared_ptr > &devices, + shared_ptr selected) { - assert(sdi); - _sdi = sdi; - if (strcmp(sdi->driver->name, "DSLogic") == 0) { - _record_length_selector.clear(); - for (size_t i = 0; i < countof(DSLogic_RecordLengths); i++) - { - const uint64_t &l = DSLogic_RecordLengths[i]; - char *const text = sr_iec_string_u64(l, " samples"); - _record_length_selector.addItem(QString(text), - qVariantFromValue(l)); - g_free(text); - - if (l == DSLogic_DefaultRecordLength) - _record_length_selector.setCurrentIndex(i); - } - } else { - for (size_t i = 0; i < countof(RecordLengths); i++) - { - const uint64_t &l = RecordLengths[i]; - char *const text = sr_si_string_u64(l, " samples"); - _record_length_selector.addItem(QString(text), - qVariantFromValue(l)); - g_free(text); - - if (l == DefaultRecordLength) - _record_length_selector.setCurrentIndex(i); - } + int selected_index = -1; + + assert(selected); + + _updating_device_selector = true; + + _device_selector.clear(); + _device_selector_map.clear(); + + BOOST_FOREACH (shared_ptr dev_inst, devices) { + assert(dev_inst); + const string title = dev_inst->format_device_title(); + const void *id = dev_inst->get_id(); + assert(id); + + if (selected == dev_inst) + selected_index = _device_selector.count(); + + _device_selector_map[id] = dev_inst; + _device_selector.addItem(title.c_str(), + qVariantFromValue((void*)id)); } + + // The selected device should have been in the list + assert(selected_index != -1); + _device_selector.setCurrentIndex(selected_index); + + update_sample_rate_selector(); + update_sample_count_selector(); + update_scale(); + + _updating_device_selector = false; +} + +shared_ptr SamplingBar::get_selected_device() const +{ + const int index = _device_selector.currentIndex(); + if (index < 0) + return shared_ptr(); + + const void *const id = + _device_selector.itemData(index).value(); + assert(id); + + map >:: + const_iterator iter = _device_selector_map.find(id); + if (iter == _device_selector_map.end()) + return shared_ptr(); + + return shared_ptr((*iter).second); +} + +void SamplingBar::on_configure() +{ + int ret; + shared_ptr dev_inst = get_selected_device(); + assert(dev_inst); + + pv::dialogs::DeviceOptions dlg(this, dev_inst->dev_inst()); + ret = dlg.exec(); + if (ret == QDialog::Accepted) + device_updated(); } uint64_t SamplingBar::get_record_length() const { - const int index = _record_length_selector.currentIndex(); + const int index = _sample_count.currentIndex(); if (index < 0) return 0; - return _record_length_selector.itemData(index).value(); + return _sample_count.itemData(index).value(); } void SamplingBar::set_record_length(uint64_t length) { - for (int i = 0; i < _record_length_selector.count(); i++) { - if (length == _record_length_selector.itemData( + for (int i = 0; i < _sample_count.count(); i++) { + if (length == _sample_count.itemData( i).value()) { - _record_length_selector.setCurrentIndex(i); + _sample_count.setCurrentIndex(i); break; } } @@ -178,26 +246,43 @@ void SamplingBar::set_record_length(uint64_t length) void SamplingBar::set_sampling(bool sampling) { - _run_stop_button.setIcon(sampling ? _icon_stop : _icon_start); - //_run_stop_button.setText(sampling ? " Stop" : "Start"); + if (_instant) + _instant_button.setIcon(sampling ? _icon_stop : _icon_instant); + else + _run_stop_button.setIcon(sampling ? _icon_stop : _icon_start); + + if (!sampling) { + _run_stop_button.setEnabled(true); + _instant_button.setEnabled(true); + } } void SamplingBar::set_sample_rate(uint64_t sample_rate) { - for (int i = 0; i < _sample_rate_list.count(); i++) { - if (sample_rate == _sample_rate_list.itemData( - i).value()) { - _sample_rate_list.setCurrentIndex(i); - // Set the samplerate - if (sr_config_set(_sdi, SR_CONF_SAMPLERATE, - g_variant_new_uint64(sample_rate)) != SR_OK) { - qDebug() << "Failed to configure samplerate."; - return; - } + for (int i = _sample_rate.count() - 1; i >= 0; i--) { + uint64_t cur_index_sample_rate = _sample_rate.itemData( + i).value(); + if (sample_rate >= cur_index_sample_rate) { + _sample_rate.setCurrentIndex(i); + // commit the samplerate + commit_sample_rate(); break; } } +} +void SamplingBar::set_sample_limit(uint64_t sample_limit) +{ + for (int i = 0; i < _sample_count.count(); i++) { + uint64_t cur_index_sample_limit = _sample_count.itemData( + i).value(); + if (sample_limit <= cur_index_sample_limit) { + _sample_count.setCurrentIndex(i); + // commit the samplecount + commit_sample_count(); + break; + } + } } void SamplingBar::update_sample_rate_selector() @@ -205,134 +290,266 @@ void SamplingBar::update_sample_rate_selector() GVariant *gvar_dict, *gvar_list; const uint64_t *elements = NULL; gsize num_elements; - //QAction *selector_action = NULL; - assert(_sample_rate_list_action); + if (_updating_sample_rate) + return; - if (!_sdi) - return; + const shared_ptr dev_inst = get_selected_device(); + if (!dev_inst) + return; - if (sr_config_list(_sdi->driver, SR_CONF_SAMPLERATE, - &gvar_dict, _sdi) != SR_OK) - return; + assert(!_updating_sample_rate); + _updating_sample_rate = true; - _sample_rate_list_action->setVisible(false); + if (!(gvar_dict = dev_inst->list_config(NULL, SR_CONF_SAMPLERATE))) + { + _sample_rate.clear(); + _sample_rate.show(); + _updating_sample_rate = false; + return; + } if ((gvar_list = g_variant_lookup_value(gvar_dict, "samplerates", G_VARIANT_TYPE("at")))) { elements = (const uint64_t *)g_variant_get_fixed_array( gvar_list, &num_elements, sizeof(uint64_t)); - _sample_rate_list.clear(); + _sample_rate.clear(); for (unsigned int i = 0; i < num_elements; i++) { char *const s = sr_samplerate_string(elements[i]); - _sample_rate_list.addItem(QString(s), + _sample_rate.addItem(QString(s), qVariantFromValue(elements[i])); g_free(s); } - _sample_rate_list.show(); + _sample_rate.show(); g_variant_unref(gvar_list); - - //selector_action = _sample_rate_list_action; } + _updating_sample_rate = false; g_variant_unref(gvar_dict); - _sample_rate_list_action->setVisible(true); update_sample_rate_selector_value(); } void SamplingBar::update_sample_rate_selector_value() { - GVariant *gvar; - uint64_t samplerate; + if (_updating_sample_rate) + return; - assert(_sdi); + const uint64_t samplerate = get_selected_device()->get_sample_rate(); - if (sr_config_get(_sdi->driver, SR_CONF_SAMPLERATE, - &gvar, _sdi) != SR_OK) { - qDebug() << - "WARNING: Failed to get value of sample rate"; - return; - } - samplerate = g_variant_get_uint64(gvar); - g_variant_unref(gvar); + assert(!_updating_sample_rate); + _updating_sample_rate = true; - assert(_sample_rate_list_action); + for (int i = 0; i < _sample_rate.count(); i++) + if (samplerate == _sample_rate.itemData( + i).value()) + _sample_rate.setCurrentIndex(i); - if (_sample_rate_list_action->isVisible()) - { - for (int i = 0; i < _sample_rate_list.count(); i++) - if (samplerate == _sample_rate_list.itemData( - i).value()) - _sample_rate_list.setCurrentIndex(i); - } + _updating_sample_rate = false; } void SamplingBar::commit_sample_rate() { - GVariant *gvar; uint64_t sample_rate = 0; uint64_t last_sample_rate = 0; - assert(_sdi); + if (_updating_sample_rate) + return; - assert(_sample_rate_list_action); + assert(!_updating_sample_rate); + _updating_sample_rate = true; - if (_sample_rate_list_action->isVisible()) - { - const int index = _sample_rate_list.currentIndex(); - if (index >= 0) - sample_rate = _sample_rate_list.itemData( - index).value(); - } + const int index = _sample_rate.currentIndex(); + if (index >= 0) + sample_rate = _sample_rate.itemData( + index).value(); if (sample_rate == 0) return; // Get last samplerate - if (sr_config_get(_sdi->driver, SR_CONF_SAMPLERATE, - &gvar, _sdi) != SR_OK) { - qDebug() << - "WARNING: Failed to get value of sample rate"; - return; - } - last_sample_rate = g_variant_get_uint64(gvar); - g_variant_unref(gvar); + last_sample_rate = get_selected_device()->get_sample_rate(); // Set the samplerate - if (sr_config_set(_sdi, SR_CONF_SAMPLERATE, - g_variant_new_uint64(sample_rate)) != SR_OK) { - qDebug() << "Failed to configure samplerate."; - return; - } + get_selected_device()->set_config(NULL, NULL, + SR_CONF_SAMPLERATE, + g_variant_new_uint64(sample_rate)); + + if (last_sample_rate != sample_rate) + update_scale(); + + _updating_sample_rate = false; +} + +void SamplingBar::on_samplerate_sel(int index) +{ + uint64_t sample_rate = 0; + uint64_t last_sample_rate = 0; + + if (index >= 0) + sample_rate = _sample_rate.itemData( + index).value(); + + const sr_dev_inst* _sdi = get_selected_device()->dev_inst(); + assert(_sdi); + + // Get last samplerate + last_sample_rate = get_selected_device()->get_sample_rate(); if (strcmp(_sdi->driver->name, "DSLogic") == 0 && _sdi->mode != DSO) { if ((last_sample_rate == SR_MHZ(200)&& sample_rate != SR_MHZ(200)) || (last_sample_rate != SR_MHZ(200) && sample_rate == SR_MHZ(200)) || (last_sample_rate == SR_MHZ(400)&& sample_rate != SR_MHZ(400)) || - (last_sample_rate != SR_MHZ(400) && sample_rate == SR_MHZ(400))) - device_reload(); + (last_sample_rate != SR_MHZ(400) && sample_rate == SR_MHZ(400))) { + + // Set the samplerate + get_selected_device()->set_config(NULL, NULL, + SR_CONF_SAMPLERATE, + g_variant_new_uint64(sample_rate)); + device_updated(); + update_scale(); + } } } -void SamplingBar::on_sample_rate_changed() +void SamplingBar::update_sample_count_selector() { - commit_sample_rate(); + GVariant *gvar_dict, *gvar_list; + const uint64_t *elements = NULL; + gsize num_elements; + + if (_updating_sample_count) + return; + + const shared_ptr dev_inst = get_selected_device(); + if (!dev_inst) + return; + + assert(!_updating_sample_count); + _updating_sample_count = true; + + if (!(gvar_dict = dev_inst->list_config(NULL, SR_CONF_LIMIT_SAMPLES))) + { + _sample_count.clear(); + _sample_count.show(); + _updating_sample_count = false; + return; + } + + if ((gvar_list = g_variant_lookup_value(gvar_dict, + "samplecounts", G_VARIANT_TYPE("at")))) + { + elements = (const uint64_t *)g_variant_get_fixed_array( + gvar_list, &num_elements, sizeof(uint64_t)); + _sample_count.clear(); + + for (unsigned int i = 0; i < num_elements; i++) + { + char *const s = sr_samplecount_string(elements[i]); + _sample_count.addItem(QString(s), + qVariantFromValue(elements[i])); + g_free(s); + } + + _sample_count.show(); + g_variant_unref(gvar_list); + } + + _updating_sample_count = false; + + g_variant_unref(gvar_dict); + update_sample_count_selector_value(); +} + +void SamplingBar::update_sample_count_selector_value() +{ + if (_updating_sample_count) + return; + + const uint64_t samplecount = get_selected_device()->get_sample_limit(); + + assert(!_updating_sample_count); + _updating_sample_count = true; + + for (int i = 0; i < _sample_count.count(); i++) + if (samplecount == _sample_count.itemData( + i).value()) + _sample_count.setCurrentIndex(i); + + _updating_sample_count = false; +} + +void SamplingBar::commit_sample_count() +{ + uint64_t sample_count = 0; + uint64_t last_sample_count = 0; + + if (_updating_sample_count) + return; + + assert(!_updating_sample_count); + _updating_sample_count = true; + + + const int index = _sample_count.currentIndex(); + if (index >= 0) + sample_count = _sample_count.itemData( + index).value(); + + if (sample_count == 0) + return; + + // Get last samplecount + last_sample_count = get_selected_device()->get_sample_limit(); + + // Set the samplecount + get_selected_device()->set_config(NULL, NULL, + SR_CONF_LIMIT_SAMPLES, + g_variant_new_uint64(sample_count)); + + _updating_sample_count = false; + + if (sample_count != last_sample_count) + update_scale(); } void SamplingBar::on_run_stop() { commit_sample_rate(); + commit_sample_count(); + _instant = false; run_stop(); } +void SamplingBar::on_instant_stop() +{ + commit_sample_rate(); + commit_sample_count(); + _instant = true; + instant_stop(); +} + +void SamplingBar::on_device_selected() +{ + if (_updating_device_selector) + return; + + const shared_ptr dev_inst = get_selected_device(); + if (!dev_inst) + return; + + _session.set_device(dev_inst); + + device_selected(); +} + void SamplingBar::enable_toggle(bool enable) { - _record_length_selector.setDisabled(!enable); - _sample_rate_list.setDisabled(!enable); + _sample_count.setDisabled(!enable); + _sample_rate.setDisabled(!enable); } void SamplingBar::enable_run_stop(bool enable) @@ -340,5 +557,10 @@ void SamplingBar::enable_run_stop(bool enable) _run_stop_button.setDisabled(!enable); } +void SamplingBar::enable_instant(bool enable) +{ + _instant_button.setDisabled(!enable); +} + } // namespace toolbars } // namespace pv diff --git a/DSLogic-gui/pv/toolbars/samplingbar.h b/DSLogic-gui/pv/toolbars/samplingbar.h index d02b8e26675a8d0005653016e053236c43b32415..8718d2db8eef286aa3e88723be0d51e058960190 100644 --- a/DSLogic-gui/pv/toolbars/samplingbar.h +++ b/DSLogic-gui/pv/toolbars/samplingbar.h @@ -27,6 +27,9 @@ #include #include +#include + +#include #include #include @@ -34,10 +37,23 @@ #include +#include "../sigsession.h" + struct st_dev_inst; class QAction; namespace pv { + +class SigSession; + +namespace device { +class DevInst; +} + +namespace dialogs { +class deviceoptions; +} + namespace toolbars { class SamplingBar : public QToolBar @@ -51,46 +67,76 @@ private: static const uint64_t DSLogic_DefaultRecordLength; public: - SamplingBar(QWidget *parent); + SamplingBar(SigSession &session, QWidget *parent); + + void set_device_list(const std::list< boost::shared_ptr > &devices, + boost::shared_ptr selected); + + boost::shared_ptr get_selected_device() const; uint64_t get_record_length() const; void set_record_length(uint64_t length); void set_sampling(bool sampling); - void update_sample_rate_selector(); - void set_sample_rate(uint64_t sample_rate); - - void set_device(struct sr_dev_inst *sdi); void enable_toggle(bool enable); void enable_run_stop(bool enable); + void enable_instant(bool enable); + +public slots: + void set_sample_rate(uint64_t sample_rate); + void set_sample_limit(uint64_t sample_limit); + signals: void run_stop(); - void device_reload(); + void instant_stop(); + void device_selected(); + void device_updated(); + void update_scale(); private: + void update_sample_rate_selector(); void update_sample_rate_selector_value(); + void update_sample_count_selector(); + void update_sample_count_selector_value(); void commit_sample_rate(); + void commit_sample_count(); private slots: - void on_sample_rate_changed(); void on_run_stop(); + void on_instant_stop(); + void on_device_selected(); + void on_samplerate_sel(int index); + +public slots: + void on_configure(); private: + SigSession &_session; + bool _enable; - struct sr_dev_inst *_sdi; + QComboBox _device_selector; + std::map > + _device_selector_map; + bool _updating_device_selector; - QComboBox _record_length_selector; + QToolButton _configure_button; - QComboBox _sample_rate_list; - QAction *_sample_rate_list_action; + QComboBox _sample_count; + QComboBox _sample_rate; + bool _updating_sample_rate; + bool _updating_sample_count; QIcon _icon_stop; QIcon _icon_start; + QIcon _icon_instant; QToolButton _run_stop_button; + QToolButton _instant_button; + + bool _instant; }; } // namespace toolbars diff --git a/DSLogic-gui/pv/toolbars/trigbar.cpp b/DSLogic-gui/pv/toolbars/trigbar.cpp index f60b7523626a84b707803bcdb32c45d1812e267b..b0078e8f3581521f8575ce79012d818f3f55cbbe 100644 --- a/DSLogic-gui/pv/toolbars/trigbar.cpp +++ b/DSLogic-gui/pv/toolbars/trigbar.cpp @@ -50,7 +50,9 @@ TrigBar::TrigBar(QWidget *parent) : _trig_button.setCheckable(true); _protocol_button.setIcon(QIcon::fromTheme("trig", QIcon(":/icons/protocol.png"))); +#ifdef ENABLE_DECODE _protocol_button.setCheckable(true); +#endif _measure_button.setIcon(QIcon::fromTheme("trig", QIcon(":/icons/measure.png"))); _measure_button.setCheckable(true); @@ -90,6 +92,35 @@ void TrigBar::enable_toggle(bool enable) _protocol_button.setDisabled(!enable); _measure_button.setDisabled(!enable); _search_button.setDisabled(!enable); + + _trig_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/trigger.png")) : + QIcon::fromTheme("trig", QIcon(":/icons/trigger_dis.png"))); + _protocol_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/protocol.png")) : + QIcon::fromTheme("trig", QIcon(":/icons/protocol_dis.png"))); + _measure_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/measure.png")) : + QIcon::fromTheme("trig", QIcon(":/icons/measure_dis.png"))); + _search_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/search-bar.png")) : + QIcon::fromTheme("trig", QIcon(":/icons/search-bar_dis.png"))); +} + +void TrigBar::close_all() +{ + if (_trig_button.isChecked()) { + _trig_button.setChecked(false); + on_trigger(false); + } + if (_protocol_button.isChecked()) { + _protocol_button.setChecked(false); + on_protocol(false); + } + if (_measure_button.isChecked()) { + _measure_button.setChecked(false); + on_measure(false); + } + if(_search_button.isChecked()) { + _search_button.setChecked(false); + on_search(false); + } } } // namespace toolbars diff --git a/DSLogic-gui/pv/toolbars/trigbar.h b/DSLogic-gui/pv/toolbars/trigbar.h index bc9333cd579482bb031a2969a7309d85735c12b5..ae3cac818e964b1aa0477936643e4fe25a93f5eb 100644 --- a/DSLogic-gui/pv/toolbars/trigbar.h +++ b/DSLogic-gui/pv/toolbars/trigbar.h @@ -38,6 +38,8 @@ public: void enable_toggle(bool enable); + void close_all(); + signals: void on_protocol(bool visible); void on_trigger(bool visible); diff --git a/DSLogic-gui/pv/view/analogsignal.cpp b/DSLogic-gui/pv/view/analogsignal.cpp index 2e62bfad59c2f710c41a4a611eed9118d15b0574..ec251ac35b7d13522a250092b80fd46a97c8517c 100644 --- a/DSLogic-gui/pv/view/analogsignal.cpp +++ b/DSLogic-gui/pv/view/analogsignal.cpp @@ -28,6 +28,7 @@ #include "analogsignal.h" #include "pv/data/analog.h" #include "pv/data/analogsnapshot.h" +#include "view.h" using namespace boost; using namespace std; @@ -50,12 +51,13 @@ const QColor AnalogSignal::SignalColours[4] = { const float AnalogSignal::EnvelopeThreshold = 256.0f; -AnalogSignal::AnalogSignal(QString name, boost::shared_ptr data, - int probe_index, int order) : - Signal(name, probe_index, DS_ANALOG, order), +AnalogSignal::AnalogSignal(boost::shared_ptr dev_inst, + boost::shared_ptr data, + const sr_channel * const probe) : + Signal(dev_inst, probe, DS_ANALOG), _data(data) { - _colour = SignalColours[probe_index % countof(SignalColours)]; + _colour = SignalColours[probe->index % countof(SignalColours)]; _scale = _signalHeight * 1.0f / 65536; } @@ -63,18 +65,9 @@ AnalogSignal::~AnalogSignal() { } -void AnalogSignal::set_data(boost::shared_ptr _logic_data, - boost::shared_ptr _dso_data, - boost::shared_ptr _analog_data, - boost::shared_ptr _group_data) +shared_ptr AnalogSignal::data() const { - (void)_dso_data; - (void)_logic_data; - (void)_group_data; - - assert(_analog_data); - - _data = _analog_data; + return _data; } void AnalogSignal::set_scale(float scale) @@ -82,16 +75,18 @@ void AnalogSignal::set_scale(float scale) _scale = scale; } -void AnalogSignal::paint(QPainter &p, int y, int left, int right, double scale, - double offset) +void AnalogSignal::paint_mid(QPainter &p, int left, int right) { - assert(scale > 0); - assert(_data); - assert(right >= left); + assert(_data); + assert(_view); + assert(right >= left); - //paint_axis(p, y, left, right); + const int y = get_y() + _signalHeight * 0.5; + const double scale = _view->scale(); + assert(scale > 0); + const double offset = _view->offset(); - const deque< boost::shared_ptr > &snapshots = + const deque< shared_ptr > &snapshots = _data->get_snapshots(); if (snapshots.empty()) return; @@ -104,7 +99,7 @@ void AnalogSignal::paint(QPainter &p, int y, int left, int right, double scale, return; const double pixels_offset = offset / scale; - const double samplerate = _data->get_samplerate(); + const double samplerate = _data->samplerate(); const double start_time = _data->get_start_time(); const int64_t last_sample = max((int64_t)(snapshot->get_sample_count() - 1), (int64_t)0); const double samples_per_pixel = samplerate * scale; @@ -210,19 +205,5 @@ const std::vector< std::pair > AnalogSignal::cur_edges() const } -void AnalogSignal::set_decoder(pv::decoder::Decoder *decoder) -{ - (void)decoder; -} - -decoder::Decoder *AnalogSignal::get_decoder() -{ - return NULL; -} - -void AnalogSignal::del_decoder() -{ -} - } // namespace view } // namespace pv diff --git a/DSLogic-gui/pv/view/analogsignal.h b/DSLogic-gui/pv/view/analogsignal.h index b954487c05df49eeea5d3de9c6d2ac4b1ba9589c..33d0bed9831db1f9475f2fed7f5237ea6de87c84 100644 --- a/DSLogic-gui/pv/view/analogsignal.h +++ b/DSLogic-gui/pv/view/analogsignal.h @@ -42,43 +42,31 @@ class AnalogSignal : public Signal { private: static const QColor SignalColours[4]; - static const float EnvelopeThreshold; - + static const int NumSpanY = 5; + static const int NumMiniSpanY = 5; + static const int NumSpanX = 10; public: - AnalogSignal(QString name, - boost::shared_ptr data, int probe_index, int order); + AnalogSignal(boost::shared_ptr dev_inst, + boost::shared_ptr data, + const sr_channel * const probe); virtual ~AnalogSignal(); + boost::shared_ptr data() const; + void set_scale(float scale); /** * Paints the signal with a QPainter * @param p the QPainter to paint into. - * @param y the y-coordinate to draw the signal at. * @param left the x-coordinate of the left edge of the signal. * @param right the x-coordinate of the right edge of the signal. - * @param scale the scale in seconds per pixel. - * @param offset the time to show at the left hand edge of - * the view in seconds. **/ - void paint(QPainter &p, int y, int left, int right, double scale, - double offset); + void paint_mid(QPainter &p, int left, int right); const std::vector< std::pair > cur_edges() const; - void set_decoder(pv::decoder::Decoder *decoder); - - pv::decoder::Decoder* get_decoder(); - - void del_decoder(); - - void set_data(boost::shared_ptr _logic_data, - boost::shared_ptr _dso_data, - boost::shared_ptr _analog_data, - boost::shared_ptr _group_data); - private: void paint_trace(QPainter &p, const boost::shared_ptr &snapshot, diff --git a/DSLogic-gui/pv/view/decodetrace.cpp b/DSLogic-gui/pv/view/decodetrace.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0be377782c815facbcc74135a96db7019a418153 --- /dev/null +++ b/DSLogic-gui/pv/view/decodetrace.cpp @@ -0,0 +1,833 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * 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 +} + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "decodetrace.h" + +#include "../sigsession.h" +#include "../data/decoderstack.h" +#include "../data/decode/decoder.h" +#include "../data/logic.h" +#include "../data/logicsnapshot.h" +#include "../data/decode/annotation.h" +#include "../view/logicsignal.h" +#include "../view/view.h" +#include "../widgets/decodergroupbox.h" +#include "../widgets/decodermenu.h" +#include "../device/devinst.h" + +using boost::dynamic_pointer_cast; +using boost::shared_ptr; +using std::list; +using std::max; +using std::map; +using std::min; +using std::vector; + +namespace pv { +namespace view { + +const QColor DecodeTrace::DecodeColours[4] = { + QColor(0xEF, 0x29, 0x29), // Red + QColor(0xFC, 0xE9, 0x4F), // Yellow + QColor(0x8A, 0xE2, 0x34), // Green + QColor(0x72, 0x9F, 0xCF) // Blue +}; + +const QColor DecodeTrace::ErrorBgColour = QColor(0xEF, 0x29, 0x29); +const QColor DecodeTrace::NoDecodeColour = QColor(0x88, 0x8A, 0x85); + +const int DecodeTrace::ArrowSize = 4; +const double DecodeTrace::EndCapWidth = 5; +const int DecodeTrace::DrawPadding = 100; + +const QColor DecodeTrace::Colours[16] = { + QColor(0xEF, 0x29, 0x29), + QColor(0xF6, 0x6A, 0x32), + QColor(0xFC, 0xAE, 0x3E), + QColor(0xFB, 0xCA, 0x47), + QColor(0xFC, 0xE9, 0x4F), + QColor(0xCD, 0xF0, 0x40), + QColor(0x8A, 0xE2, 0x34), + QColor(0x4E, 0xDC, 0x44), + QColor(0x55, 0xD7, 0x95), + QColor(0x64, 0xD1, 0xD2), + QColor(0x72, 0x9F, 0xCF), + QColor(0xD4, 0x76, 0xC4), + QColor(0x9D, 0x79, 0xB9), + QColor(0xAD, 0x7F, 0xA8), + QColor(0xC2, 0x62, 0x9B), + QColor(0xD7, 0x47, 0x6F) +}; + +const QColor DecodeTrace::OutlineColours[16] = { + QColor(0x77, 0x14, 0x14), + QColor(0x7B, 0x35, 0x19), + QColor(0x7E, 0x57, 0x1F), + QColor(0x7D, 0x65, 0x23), + QColor(0x7E, 0x74, 0x27), + QColor(0x66, 0x78, 0x20), + QColor(0x45, 0x71, 0x1A), + QColor(0x27, 0x6E, 0x22), + QColor(0x2A, 0x6B, 0x4A), + QColor(0x32, 0x68, 0x69), + QColor(0x39, 0x4F, 0x67), + QColor(0x6A, 0x3B, 0x62), + QColor(0x4E, 0x3C, 0x5C), + QColor(0x56, 0x3F, 0x54), + QColor(0x61, 0x31, 0x4D), + QColor(0x6B, 0x23, 0x37) +}; + +DecodeTrace::DecodeTrace(pv::SigSession &session, + boost::shared_ptr decoder_stack, int index) : + Trace(QString::fromUtf8( + decoder_stack->stack().front()->decoder()->name), Trace::DS_DECODER), + _session(session), + _decoder_stack(decoder_stack), + _show_hide_mapper(this) +{ + assert(_decoder_stack); + + _colour = DecodeColours[index % countof(DecodeColours)]; + + connect(_decoder_stack.get(), SIGNAL(new_decode_data()), + this, SLOT(on_new_decode_data())); + connect(_decoder_stack.get(), SIGNAL(decode_done()), + this, SLOT(on_decode_done())); + connect(&_show_hide_mapper, SIGNAL(mapped(int)), + this, SLOT(on_show_hide_decoder(int))); +} + +bool DecodeTrace::enabled() const +{ + return true; +} + +const boost::shared_ptr& DecodeTrace::decoder() const +{ + return _decoder_stack; +} + +void DecodeTrace::set_view(pv::view::View *view) +{ + assert(view); + Trace::set_view(view); +} + +void DecodeTrace::paint_back(QPainter &p, int left, int right) +{ + QPen pen(Signal::dsGray); + pen.setStyle(Qt::DotLine); + p.setPen(pen); + const double sigY = get_y() - (_signalHeight - _view->get_signalHeight())*0.5; + p.drawLine(left, sigY, right, sigY); +} + +void DecodeTrace::paint_mid(QPainter &p, int left, int right) +{ + using namespace pv::data::decode; + + const double scale = _view->scale(); + assert(scale > 0); + + double samplerate = _decoder_stack->samplerate(); + + _cur_row_headings.clear(); + + // Show sample rate as 1Hz when it is unknown + if (samplerate == 0.0) + samplerate = 1.0; + + const double pixels_offset = (_view->offset() - + _decoder_stack->get_start_time()) / scale; + const double samples_per_pixel = samplerate * scale; + + const uint64_t start_sample = (uint64_t)max((left + pixels_offset) * + samples_per_pixel, 0.0); + const uint64_t end_sample = (uint64_t)max((right + pixels_offset) * + samples_per_pixel, 0.0); + + const int annotation_height = _view->get_signalHeight(); + + assert(_decoder_stack); + const QString err = _decoder_stack->error_message(); + if (!err.isEmpty()) + { + //draw_unresolved_period(p, _view->get_signalHeight(), left, right, + // samples_per_pixel, pixels_offset); + draw_error(p, err, left, right); + return; + } + + // Draw the hatching + if (draw_unresolved_period(p, _view->get_signalHeight(), left, right)) + return; + + // Iterate through the rows + assert(_view); + int y = get_y() - (_signalHeight - _view->get_signalHeight())*0.5; + + assert(_decoder_stack); + + const std::vector< std::pair > rows(_decoder_stack->get_visible_rows()); + for (size_t i = 0; i < rows.size(); i++) + { + const Row &row = rows[i].first; + const bool shown = rows[i].second; + + if (!shown && _decoder_stack->has_annotations(row)) { + draw_unshown_row(p, y, _view->get_signalHeight(), left, right); + y += _view->get_signalHeight(); + _cur_row_headings.push_back(row.title()); + continue; + } + + size_t base_colour = 0x13579BDF; + boost::hash_combine(base_colour, this); + boost::hash_combine(base_colour, row.decoder()); + boost::hash_combine(base_colour, row.row()); + base_colour >>= 16; + + const uint64_t max_annotation = + _decoder_stack->get_max_annotation(row); + const double max_annWidth = max_annotation / samples_per_pixel; + if (max_annWidth > 5) { + vector annotations; + _decoder_stack->get_annotation_subset(annotations, row, + start_sample, end_sample); + if (!annotations.empty()) { + BOOST_FOREACH(const Annotation &a, annotations) + draw_annotation(a, p, get_text_colour(), + annotation_height, left, right, + samples_per_pixel, pixels_offset, y, + base_colour); + } + } else if (max_annWidth != 0){ + draw_nodetail(p, annotation_height, left, right, y, base_colour); + } + if (max_annWidth != 0) { + y += _view->get_signalHeight(); + _cur_row_headings.push_back(row.title()); + } + } +} + +void DecodeTrace::paint_fore(QPainter &p, int left, int right) +{ + using namespace pv::data::decode; + + (void)right; + + const int row_height = _view->get_signalHeight(); + + for (size_t i = 0; i < _cur_row_headings.size(); i++) + { + const int y = (i + 0.5) * row_height + get_y() - _signalHeight * 0.5; + + p.setPen(QPen(Qt::NoPen)); + p.setBrush(QApplication::palette().brush(QPalette::WindowText)); + + if (i != 0) + { + const QPointF points[] = { + QPointF(left, y - ArrowSize), + QPointF(left + ArrowSize, y), + QPointF(left, y + ArrowSize) + }; + p.drawPolygon(points, countof(points)); + } + + const QRect r(left + ArrowSize * 2, y - row_height / 2, + right - left, row_height); + const QString h(_cur_row_headings[i]); + const int f = Qt::AlignLeft | Qt::AlignVCenter | + Qt::TextDontClip; + + // Draw the outline + QFont font=p.font(); + font.setPointSize(DefaultFontSize); + p.setFont(font); + p.setPen(QApplication::palette().color(QPalette::Base)); + for (int dx = -1; dx <= 1; dx++) + for (int dy = -1; dy <= 1; dy++) + if (dx != 0 && dy != 0) + p.drawText(r.translated(dx, dy), f, h); + + // Draw the text + p.setPen(QApplication::palette().color(QPalette::WindowText)); + p.drawText(r, f, h); + } +} + +bool DecodeTrace::create_popup() +{ + // Clear the layout + + // Transfer the layout and the child widgets to a temporary widget + // which then goes out of scope destroying the layout and all the child + // widgets. + //if (_popup_form) + // QWidget().setLayout(_popup_form); + + int ret = false; + QDialog popup; + QFormLayout popup_form; + popup.setLayout(&popup_form); + populate_popup_form(&popup, &popup_form); + + if (QDialog::Accepted == popup.exec()) + { + BOOST_FOREACH(shared_ptr dec, + _decoder_stack->stack()) + { + dec->commit_show(); + if (dec->commit()) { + _decoder_stack->options_changed(true); + ret = true; + } + } + return ret; + } + else + return false; +} + + +void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) +{ + using pv::data::decode::Decoder; + + assert(form); + assert(parent); + assert(_decoder_stack); + + // Add the decoder options + _bindings.clear(); + _probe_selectors.clear(); + _decoder_forms.clear(); + + const list< shared_ptr >& stack = _decoder_stack->stack(); + + if (stack.empty()) + { + QLabel *const l = new QLabel( + tr("

No decoders in the stack

")); + l->setAlignment(Qt::AlignCenter); + form->addRow(l); + } + else + { + list< shared_ptr >::const_iterator iter = + stack.begin(); + for (int i = 0; i < (int)stack.size(); i++, iter++) { + shared_ptr dec(*iter); + create_decoder_form(i, dec, parent, form); + } + + form->addRow(new QLabel( + tr("* Required channels"), parent)); + } + + // Add stacking button + pv::widgets::DecoderMenu *const decoder_menu = + new pv::widgets::DecoderMenu(parent); + connect(decoder_menu, SIGNAL(decoder_selected(srd_decoder*)), + this, SLOT(on_stack_decoder(srd_decoder*))); + connect(decoder_menu, SIGNAL(selected()), + parent, SLOT(accept())); + + QPushButton *const stack_button = + new QPushButton(tr("Stack Decoder"), parent); + stack_button->setMenu(decoder_menu); + + QHBoxLayout *stack_button_box = new QHBoxLayout; + stack_button_box->addWidget(stack_button, 0, Qt::AlignLeft); + form->addRow(stack_button_box); + + // Add ButtonBox (OK/Cancel) + QDialogButtonBox *button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, + Qt::Horizontal, parent); + connect(button_box, SIGNAL(accepted()), parent, SLOT(accept())); + connect(button_box, SIGNAL(rejected()), parent, SLOT(reject())); + + QHBoxLayout *confirm_button_box = new QHBoxLayout; + confirm_button_box->addWidget(button_box, 0, Qt::AlignRight); + form->addRow(confirm_button_box); +} + +void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, + QPainter &p, QColor text_color, int h, int left, int right, + double samples_per_pixel, double pixels_offset, int y, + size_t base_colour) const +{ + const double start = max(a.start_sample() / samples_per_pixel - + pixels_offset, (double)left); + const double end = min(a.end_sample() / samples_per_pixel - + pixels_offset, (double)right); + + const size_t colour = (base_colour + a.format()) % countof(Colours); + const QColor &fill = Colours[colour]; + const QColor &outline = OutlineColours[colour]; + + if (start > right + DrawPadding || end < left - DrawPadding) + return; + + if (a.start_sample() == a.end_sample()) + draw_instant(a, p, fill, outline, text_color, h, + start, y); + else + draw_range(a, p, fill, outline, text_color, h, + start, end, y); +} + +void DecodeTrace::draw_nodetail(QPainter &p, + int h, int left, int right, int y, + size_t base_colour) const +{ + const QRectF nodetail_rect(left, y - h/2 + 0.5, right - left, h); + const size_t colour = base_colour % countof(Colours); + const QColor &fill = Colours[colour]; + + p.setPen(Qt::white); + p.setBrush(fill); + p.drawRect(nodetail_rect); + p.drawText(nodetail_rect, Qt::AlignCenter | Qt::AlignVCenter, "Zoom in for more detials"); +} + +void DecodeTrace::draw_instant(const pv::data::decode::Annotation &a, QPainter &p, + QColor fill, QColor outline, QColor text_color, int h, double x, int y) const +{ + const QString text = a.annotations().empty() ? + QString() : a.annotations().back(); + const double w = min((double)p.boundingRect(QRectF(), 0, text).width(), + 0.0) + h; + const QRectF rect(x - w / 2, y - h / 2, w, h); + + p.setPen(outline); + p.setBrush(fill); + p.drawRoundedRect(rect, h / 2, h / 2); + + p.setPen(text_color); + QFont font=p.font(); + font.setPointSize(DefaultFontSize); + p.setFont(font); + p.drawText(rect, Qt::AlignCenter | Qt::AlignVCenter, text); +} + +void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p, + QColor fill, QColor outline, QColor text_color, int h, double start, + double end, int y) const +{ + const double top = y + .5 - h / 2; + const double bottom = y + .5 + h / 2; + const vector annotations = a.annotations(); + + p.setPen(outline); + p.setBrush(fill); + + // If the two ends are within 2 pixel, draw a vertical line + if (start + 2.0 > end) + { + p.drawLine(QPointF(start, top), QPointF(start, bottom)); + return; + } + + double cap_width = min((end - start) / 4, EndCapWidth); + + QPointF pts[] = { + QPointF(start, y + .5f), + QPointF(start + cap_width, top), + QPointF(end - cap_width, top), + QPointF(end, y + .5f), + QPointF(end - cap_width, bottom), + QPointF(start + cap_width, bottom) + }; + + p.setPen(Qt::white); + p.drawConvexPolygon(pts, countof(pts)); + + if (annotations.empty()) + return; + + QRectF rect(start + cap_width, y - h / 2, + end - start - cap_width * 2, h); + if (rect.width() <= 4) + return; + + p.setPen(text_color); + + // Try to find an annotation that will fit + QString best_annotation; + int best_width = 0; + + BOOST_FOREACH(const QString &a, annotations) { + const int w = p.boundingRect(QRectF(), 0, a).width(); + if (w <= rect.width() && w > best_width) + best_annotation = a, best_width = w; + } + + if (best_annotation.isEmpty()) + best_annotation = annotations.back(); + + // If not ellide the last in the list + QFont font=p.font(); + font.setPointSize(DefaultFontSize); + p.setFont(font); + p.drawText(rect, Qt::AlignCenter, p.fontMetrics().elidedText( + best_annotation, Qt::ElideRight, rect.width())); +} + +void DecodeTrace::draw_error(QPainter &p, const QString &message, + int left, int right) +{ + const int y = get_y(); + + p.setPen(ErrorBgColour.darker()); + p.setBrush(ErrorBgColour); + + const QRectF bounding_rect = + QRectF(left, INT_MIN / 2 + y, right - left, INT_MAX); + const QRectF text_rect = p.boundingRect(bounding_rect, + Qt::AlignCenter, message); + const float r = text_rect.height() / 4; + + p.drawRoundedRect(text_rect.adjusted(-r, -r, r, r), r, r, + Qt::AbsoluteSize); + + p.setPen(get_text_colour()); + QFont font=p.font(); + font.setPointSize(DefaultFontSize); + p.setFont(font); + p.drawText(text_rect, message); +} + +bool DecodeTrace::draw_unresolved_period(QPainter &p, int h, int left, + int right) +{ + using namespace pv::data; + using pv::data::decode::Decoder; + + assert(_decoder_stack); + + shared_ptr data; + shared_ptr logic_signal; + + const int64_t sample_count = _session.get_device()->get_sample_limit(); + if (sample_count == 0) + return true; + + const int64_t samples_decoded = _decoder_stack->samples_decoded(); + if (sample_count == samples_decoded) + return false; + + const int y = get_y(); +// const double start = max(samples_decoded / +// samples_per_pixel - pixels_offset, left - 1.0); +// const double end = min(sample_count / samples_per_pixel - +// pixels_offset, right + 1.0); + const QRectF no_decode_rect(left, y - h/2 + 0.5, right - left, h); + + p.setPen(QPen(Qt::NoPen)); + p.setBrush(Qt::white); + p.drawRect(no_decode_rect); + + p.setPen(NoDecodeColour); + p.setBrush(QBrush(NoDecodeColour, Qt::Dense7Pattern)); + p.drawRect(no_decode_rect); + + const int progress100 = ceil(samples_decoded * 100.0 / sample_count); + p.setPen(dsLightBlue); + QFont font=p.font(); + font.setPointSize(_view->get_signalHeight()*2/3); + font.setBold(true); + p.setFont(font); + p.drawText(no_decode_rect, Qt::AlignCenter | Qt::AlignVCenter, QString::number(progress100)+"%"); + + return true; +} + +void DecodeTrace::draw_unshown_row(QPainter &p, int y, int h, int left, + int right) +{ + const QRectF unshown_rect(left, y - h/2 + 0.5, right - left, h); + + p.setPen(QPen(Qt::NoPen)); + p.setBrush(QBrush(NoDecodeColour, Qt::Dense7Pattern)); + p.drawRect(unshown_rect); + + p.setPen(dsLightBlue); + QFont font=p.font(); + font.setPointSize(_view->get_signalHeight()*2/3); + font.setBold(true); + p.setFont(font); + p.drawText(unshown_rect, Qt::AlignCenter | Qt::AlignVCenter, "Unshown"); +} + +void DecodeTrace::create_decoder_form(int index, + shared_ptr &dec, QWidget *parent, + QFormLayout *form) +{ + const GSList *l; + + assert(dec); + const srd_decoder *const decoder = dec->decoder(); + assert(decoder); + + pv::widgets::DecoderGroupBox *const group = + new pv::widgets::DecoderGroupBox( + QString::fromUtf8(decoder->name)); + group->set_decoder_visible(dec->shown()); + + _show_hide_mapper.setMapping(group, index); + connect(group, SIGNAL(show_hide_decoder()), + &_show_hide_mapper, SLOT(map())); + + QFormLayout *const decoder_form = new QFormLayout; + group->add_layout(decoder_form); + + // Add the mandatory channels + for(l = decoder->channels; l; l = l->next) { + const struct srd_channel *const pdch = + (struct srd_channel *)l->data; + QComboBox *const combo = create_probe_selector(parent, dec, pdch); + connect(combo, SIGNAL(currentIndexChanged(int)), + this, SLOT(on_probe_selected(int))); + decoder_form->addRow(tr("%1 (%2) *") + .arg(QString::fromUtf8(pdch->name)) + .arg(QString::fromUtf8(pdch->desc)), combo); + + const ProbeSelector s = {combo, dec, pdch}; + _probe_selectors.push_back(s); + } + + // Add the optional channels + for(l = decoder->opt_channels; l; l = l->next) { + const struct srd_channel *const pdch = + (struct srd_channel *)l->data; + QComboBox *const combo = create_probe_selector(parent, dec, pdch); + connect(combo, SIGNAL(currentIndexChanged(int)), + this, SLOT(on_probe_selected(int))); + decoder_form->addRow(tr("%1 (%2)") + .arg(QString::fromUtf8(pdch->name)) + .arg(QString::fromUtf8(pdch->desc)), combo); + + const ProbeSelector s = {combo, dec, pdch}; + _probe_selectors.push_back(s); + } + + // Add the options + shared_ptr binding( + new prop::binding::DecoderOptions(_decoder_stack, dec)); + binding->add_properties_to_form(decoder_form, true); + + _bindings.push_back(binding); + + form->addRow(group); + _decoder_forms.push_back(group); +} + +QComboBox* DecodeTrace::create_probe_selector( + QWidget *parent, const shared_ptr &dec, + const srd_channel *const pdch) +{ + assert(dec); + + const vector< shared_ptr > sigs(_session.get_signals()); + + assert(_decoder_stack); + const map >::const_iterator probe_iter = + dec->channels().find(pdch); + + QComboBox *selector = new QComboBox(parent); + + selector->addItem("-", qVariantFromValue((void*)NULL)); + + if (probe_iter == dec->channels().end()) + selector->setCurrentIndex(0); + + for(size_t i = 0; i < sigs.size(); i++) { + const shared_ptr s(sigs[i]); + assert(s); + + if (dynamic_pointer_cast(s) && s->enabled()) + { + selector->addItem(s->get_name(), + qVariantFromValue((void*)s.get())); + if ((*probe_iter).second == s) + selector->setCurrentIndex(i + 1); + } + } + + return selector; +} + +void DecodeTrace::commit_decoder_probes(shared_ptr &dec) +{ + assert(dec); + + map > probe_map; + const vector< shared_ptr > sigs(_session.get_signals()); + + _index_list.clear(); + BOOST_FOREACH(const ProbeSelector &s, _probe_selectors) + { + if(s._decoder != dec) + break; + + const LogicSignal *const selection = + (LogicSignal*)s._combo->itemData( + s._combo->currentIndex()).value(); + + BOOST_FOREACH(shared_ptr sig, sigs) + if(sig.get() == selection) { + probe_map[s._pdch] = + dynamic_pointer_cast(sig); + _index_list.push_back(sig->get_index()); + break; + } + } + + dec->set_probes(probe_map); +} + +void DecodeTrace::commit_probes() +{ + assert(_decoder_stack); + BOOST_FOREACH(shared_ptr dec, + _decoder_stack->stack()) + commit_decoder_probes(dec); + + //_decoder_stack->begin_decode(); +} + +void DecodeTrace::on_new_decode_data() +{ + if (_view && _view->session().get_capture_state() == SigSession::Stopped) + _view->data_updated(); +} + +void DecodeTrace::on_decode_done() +{ + if (_view) { + _view->set_need_update(true); + _view->signals_changed(); + } +} + +void DecodeTrace::on_delete() +{ + _session.remove_decode_signal(this); +} + +void DecodeTrace::on_probe_selected(int) +{ + commit_probes(); +} + +void DecodeTrace::on_stack_decoder(srd_decoder *decoder) +{ + assert(decoder); + assert(_decoder_stack); + _decoder_stack->push(shared_ptr( + new data::decode::Decoder(decoder))); + //_decoder_stack->begin_decode(); + + create_popup(); +} + +void DecodeTrace::on_show_hide_decoder(int index) +{ + using pv::data::decode::Decoder; + + const list< shared_ptr > stack(_decoder_stack->stack()); + + // Find the decoder in the stack + list< shared_ptr >::const_iterator iter = stack.begin(); + for(int i = 0; i < index; i++, iter++) + assert(iter != stack.end()); + + shared_ptr dec = *iter; + assert(dec); + + const bool show = !dec->shown(); + dec->show(show); + + assert(index < (int)_decoder_forms.size()); + _decoder_forms[index]->set_decoder_visible(show); + + //_view->set_need_update(true); +} + + +int DecodeTrace::rows_size() +{ + return _decoder_stack->cur_rows_size(); +} + +void DecodeTrace::paint_type_options(QPainter &p, int right, bool hover, int action) +{ + (void)hover; + (void)action; + + int y = get_y(); + const QRectF group_index_rect = get_rect("groupIndex", y, right); + QString index_string; + int last_index; + p.setPen(Qt::transparent); + p.setBrush(dsBlue); + p.drawRect(group_index_rect); + std::list::iterator i = _index_list.begin(); + last_index = (*i); + index_string = QString::number(last_index); + while (++i != _index_list.end()) { + if ((*i) == last_index + 1 && index_string.indexOf("-") < 3 && index_string.indexOf("-") > 0) + index_string.replace(QString::number(last_index), QString::number((*i))); + else if ((*i) == last_index + 1) + index_string = QString::number((*i)) + "-" + index_string; + else + index_string = QString::number((*i)) + "," + index_string; + last_index = (*i); + } + p.setPen(Qt::white); + p.drawText(group_index_rect, Qt::AlignRight | Qt::AlignVCenter, index_string); +} + +} // namespace view +} // namespace pv diff --git a/DSLogic-gui/pv/view/decodetrace.h b/DSLogic-gui/pv/view/decodetrace.h new file mode 100644 index 0000000000000000000000000000000000000000..fe0f5f72cee03ae23a93cd4079604386ae7ff8b0 --- /dev/null +++ b/DSLogic-gui/pv/view/decodetrace.h @@ -0,0 +1,204 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * 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_DECODETRACE_H +#define DSLOGIC_PV_VIEW_DECODETRACE_H + +#include "trace.h" + +#include +#include + +#include +#include +#include + +#include + +#include + +struct srd_channel; +struct srd_decoder; + +class QComboBox; + +namespace pv { + +class SigSession; + +namespace data { +class DecoderStack; + +namespace decode { +class Annotation; +class Decoder; +class Row; +} +} + +namespace widgets { +class DecoderGroupBox; +} + +namespace view { + +class DecodeTrace : public Trace +{ + Q_OBJECT + +private: + struct ProbeSelector + { + const QComboBox *_combo; + const boost::shared_ptr _decoder; + const srd_channel *_pdch; + }; + +private: + static const QColor DecodeColours[4]; + static const QColor ErrorBgColour; + static const QColor NoDecodeColour; + + static const int ArrowSize; + static const double EndCapWidth; + static const int DrawPadding; + + static const QColor Colours[16]; + static const QColor OutlineColours[16]; + + static const int DefaultFontSize = 8; + +public: + DecodeTrace(pv::SigSession &session, + boost::shared_ptr decoder_stack, + int index); + + bool enabled() const; + + const boost::shared_ptr& decoder() const; + + void set_view(pv::view::View *view); + + /** + * Paints the background layer of the trace with a QPainter + * @param p the QPainter to paint into. + * @param left the x-coordinate of the left edge of the signal. + * @param right the x-coordinate of the right edge of the signal. + **/ + void paint_back(QPainter &p, int left, int right); + + /** + * Paints the mid-layer of the trace with a QPainter + * @param p the QPainter to paint into. + * @param left the x-coordinate of the left edge of the signal + * @param right the x-coordinate of the right edge of the signal + **/ + void paint_mid(QPainter &p, int left, int right); + + /** + * Paints the foreground layer of the trace with a QPainter + * @param p the QPainter to paint into. + * @param left the x-coordinate of the left edge of the signal + * @param right the x-coordinate of the right edge of the signal + **/ + void paint_fore(QPainter &p, int left, int right); + + bool create_popup(); + + int rows_size(); + +protected: + void paint_type_options(QPainter &p, int right, bool hover, int action); + +private: + void populate_popup_form(QWidget *parent, QFormLayout *form); + + void draw_annotation(const pv::data::decode::Annotation &a, QPainter &p, + QColor text_colour, int text_height, int left, int right, + double samples_per_pixel, double pixels_offset, int y, + size_t base_colour) const; + void draw_nodetail(QPainter &p, + int text_height, int left, int right, int y, + size_t base_colour) const; + + void draw_instant(const pv::data::decode::Annotation &a, QPainter &p, + QColor fill, QColor outline, QColor text_color, int h, double x, + int y) const; + + void draw_range(const pv::data::decode::Annotation &a, QPainter &p, + QColor fill, QColor outline, QColor text_color, int h, double start, + double end, int y) const; + + void draw_error(QPainter &p, const QString &message, + int left, int right); + + bool draw_unresolved_period(QPainter &p, int h, int left, + int right); + + void draw_unshown_row(QPainter &p, int y, int h, int left, + int right); + + void create_decoder_form(int index, + boost::shared_ptr &dec, + QWidget *parent, QFormLayout *form); + + QComboBox* create_probe_selector(QWidget *parent, + const boost::shared_ptr &dec, + const srd_channel *const pdch); + + void commit_decoder_probes( + boost::shared_ptr &dec); + + void commit_probes(); + +private slots: + void on_new_decode_data(); + + void on_delete(); + + void on_probe_selected(int); + + void on_stack_decoder(srd_decoder *decoder); + + void on_show_hide_decoder(int index); + + void on_decode_done(); + +private: + pv::SigSession &_session; + boost::shared_ptr _decoder_stack; + + uint64_t _decode_start, _decode_end; + + std::list< boost::shared_ptr > + _bindings; + + std::list _probe_selectors; + std::vector _decoder_forms; + + std::vector _cur_row_headings; + + QSignalMapper _show_hide_mapper; +}; + +} // namespace view +} // namespace pv + +#endif // DSLOGIC_PV_VIEW_DECODETRACE_H diff --git a/DSLogic-gui/pv/view/devmode.cpp b/DSLogic-gui/pv/view/devmode.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb97a0c27e1958573ca39e15f36bb8b802121205 --- /dev/null +++ b/DSLogic-gui/pv/view/devmode.cpp @@ -0,0 +1,194 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2014 DreamSourceLab + * + * 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 "devmode.h" +#include "view.h" +#include "trace.h" +#include "../sigsession.h" +#include "../device/devinst.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +using boost::shared_ptr; +using namespace std; + +namespace pv { +namespace view { + +DevMode::DevMode(View &parent) : + QWidget(&parent), + _view(parent), + layout(new QGridLayout(this)) + +{ + setLayout(layout); +} + +void DevMode::set_device() +{ + int index = 0; + const boost::shared_ptr dev_inst = _view.session().get_device(); + + assert(dev_inst); + + _mode_button_list.clear(); + delete layout; + layout = new QGridLayout(this); + + for (GSList *l = dev_inst->get_dev_mode_list(); + l; l = l->next) { + sr_dev_mode *mode = (sr_dev_mode *)l->data; + + shared_ptr mode_button = shared_ptr(new QPushButton(NULL)); + mode_button->setFlat(true); + mode_button->setText(mode->name); + + _mode_button_list[mode_button] = mode; + + connect(mode_button.get(), SIGNAL(clicked()), this, SLOT(on_mode_change())); + + layout->addWidget(mode_button.get(), index / GRID_COLS, index % GRID_COLS); + layout->addWidget(new QWidget(), index / GRID_COLS, GRID_COLS); + layout->setColumnStretch(GRID_COLS, 1); + index++; + } + + setLayout(layout); + update(); +} + +void DevMode::paintEvent(QPaintEvent*) +{ + using pv::view::Trace; + + QStyleOption o; + o.initFrom(this); + QPainter painter(this); + style()->drawPrimitive(QStyle::PE_Widget, &o, &painter, this); + + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(Qt::NoPen); + for(std::map, sr_dev_mode *>::const_iterator i = _mode_button_list.begin(); + i != _mode_button_list.end(); i++) { + const boost::shared_ptr dev_inst = _view.session().get_device(); + assert(dev_inst); + if (dev_inst->dev_inst()->mode == (*i).second->mode) + painter.setBrush(Trace::dsBlue); + else + painter.setBrush(Trace::dsGray); + + painter.drawRoundedRect((*i).first->geometry(), 4, 4); + } + + painter.end(); +} + +void DevMode::on_mode_change() +{ + const boost::shared_ptr dev_inst = _view.session().get_device(); + assert(dev_inst); + QPushButton *button = qobject_cast(sender()); + + for(std::map, sr_dev_mode *>::const_iterator i = _mode_button_list.begin(); + i != _mode_button_list.end(); i++) { + if ((*i).first.get() == button) { + if (dev_inst->dev_inst()->mode != (*i).second->mode) { + dev_inst->set_config(NULL, NULL, + SR_CONF_DEVICE_MODE, + g_variant_new_int16((*i).second->mode)); + + mode_changed(); + + if (dev_inst->dev_inst()->mode == DSO && + strcmp(dev_inst->dev_inst()->driver->name, "DSLogic") == 0) { + bool zero_adjusted = false; + GVariant *gvar = dev_inst->get_config(NULL, NULL, SR_CONF_ZERO); + if (gvar != NULL) { + zero_adjusted = g_variant_get_boolean(gvar); + g_variant_unref(gvar); + } else { + qDebug() << "ERROR: config_get SR_CONF_ZERO failed."; + } + + if (!zero_adjusted) { + 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 = dev_inst->set_config(NULL, NULL, + SR_CONF_ZERO, + g_variant_new_boolean(TRUE)); + if (!ret) { + 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(); + } + } + } + } + } + } +} + +void DevMode::mousePressEvent(QMouseEvent *event) +{ + assert(event); + (void)event; +} + +void DevMode::mouseReleaseEvent(QMouseEvent *event) +{ + assert(event); + (void)event; +} + +void DevMode::mouseMoveEvent(QMouseEvent *event) +{ + assert(event); + _mouse_point = event->pos(); + update(); +} + +void DevMode::leaveEvent(QEvent*) +{ + _mouse_point = QPoint(-1, -1); + update(); +} + +} // namespace view +} // namespace pv diff --git a/DSLogic-gui/pv/view/devmode.h b/DSLogic-gui/pv/view/devmode.h new file mode 100644 index 0000000000000000000000000000000000000000..7e15a5072dbfb5b0dd8fc8cf3adf70c2bba040a6 --- /dev/null +++ b/DSLogic-gui/pv/view/devmode.h @@ -0,0 +1,90 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2014 DreamSourceLab + * + * 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_DEVMODE_H +#define DSLOGIC_PV_VIEW_DEVMODE_H + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace pv { + +namespace device{ +class DevInst; +} + +namespace view { + +class View; + +class DevMode : public QWidget +{ + Q_OBJECT + +private: + static const int GRID_COLS = 3; + +public: + DevMode(View &parent); + +private: + void paintEvent(QPaintEvent *event); + +private: + void mousePressEvent(QMouseEvent * event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void leaveEvent(QEvent *event); + +public slots: + void set_device(); + void on_mode_change(); + +private slots: + +signals: + void mode_changed(); + +private: + View &_view; + + QGridLayout * layout; + std::map , sr_dev_mode *> _mode_button_list; + QPoint _mouse_point; +}; + +} // namespace view +} // namespace pv + +#endif // DSLOGIC_PV_VIEW_DEVMODE_H diff --git a/DSLogic-gui/pv/view/dsosignal.cpp b/DSLogic-gui/pv/view/dsosignal.cpp index d11108ba257d777c748c9f356a642bf57861b961..b2b34a0d8eb5f2230da744435da1038a2c332597 100644 --- a/DSLogic-gui/pv/view/dsosignal.cpp +++ b/DSLogic-gui/pv/view/dsosignal.cpp @@ -27,6 +27,11 @@ #include "dsosignal.h" #include "pv/data/dso.h" #include "pv/data/dsosnapshot.h" +#include "view.h" +#include "../sigsession.h" +#include "../device/devinst.h" + +#include using namespace boost; using namespace std; @@ -34,6 +39,55 @@ using namespace std; namespace pv { namespace view { +const uint64_t DsoSignal::vDialValue[DsoSignal::vDialValueCount] = { + 5, + 10, + 20, + 50, + 100, + 200, + 500, + 1000, + 2000, + 5000, +}; +const QString DsoSignal::vDialUnit[DsoSignal::vDialUnitCount] = { + "mv", + "v", +}; + +const uint64_t DsoSignal::hDialValue[DsoSignal::hDialValueCount] = { + 10, + 20, + 50, + 100, + 200, + 500, + 1000, + 2000, + 5000, + 10000, + 20000, + 50000, + 100000, + 200000, + 500000, + 1000000, + 2000000, + 5000000, + 10000000, + 20000000, + 50000000, + 100000000, +}; + +const QString DsoSignal::hDialUnit[DsoSignal::hDialUnitCount] = { + "ns", + "us", + "ms", + "s", +}; + const QColor DsoSignal::SignalColours[4] = { QColor(238, 178, 17, 200), // dsYellow QColor(0, 153, 37, 200), // dsGreen @@ -44,35 +98,74 @@ const QColor DsoSignal::SignalColours[4] = { const float DsoSignal::EnvelopeThreshold = 256.0f; -DsoSignal::DsoSignal(QString name, boost::shared_ptr data, - int probe_index, int order, uint64_t vdiv, uint64_t timebase, bool coupling, bool active) : - Signal(name, probe_index, DS_DSO, order), - _data(data) +const int DsoSignal::UpMargin = 30; +const int DsoSignal::DownMargin = 30; +const int DsoSignal::RightMargin = 30; + +DsoSignal::DsoSignal(boost::shared_ptr dev_inst, + shared_ptr data, + const sr_channel * const probe): + Signal(dev_inst, probe, DS_DSO), + _data(data), + _scale(0), + _vDialActive(false), + _hDialActive(false), + _trig_vpos(probe->index * 0.5 + 0.25), + _zeroPos(probe->index * 0.5 + 0.25) { - _colour = SignalColours[probe_index % countof(SignalColours)]; - _scale = _windowHeight * 1.0f / 256; - _vDial->set_value(vdiv); - _hDial->set_value(timebase); - _acCoupling = coupling; - _active = active; + QVector vValue; + QVector vUnit; + QVector hValue; + QVector hUnit; + for(quint64 i = 0; i < vDialValueCount; i++) + vValue.append(vDialValue[i]); + for(quint64 i = 0; i < vDialUnitCount; i++) + vUnit.append(vDialUnit[i]); + + for(quint64 i = 0; i < hDialValueCount; i++) + hValue.append(hDialValue[i]); + for(quint64 i = 0; i < hDialUnitCount; i++) + hUnit.append(hDialUnit[i]); + + _vDial = new dslDial(vDialValueCount, vDialValueStep, vValue, vUnit); + _hDial = new dslDial(hDialValueCount, hDialValueStep, hValue, hUnit); + + _colour = SignalColours[probe->index % countof(SignalColours)]; + + GVariant* gvar; + + gvar = dev_inst->get_config(probe, NULL, SR_CONF_VDIV); + if (gvar != NULL) { + _vDial->set_value(g_variant_get_uint64(gvar)); + g_variant_unref(gvar); + } else { + qDebug() << "ERROR: config_get SR_CONF_VDIV failed."; + } + + gvar = dev_inst->get_config(NULL, NULL, SR_CONF_TIMEBASE); + if (gvar != NULL) { + _hDial->set_value(g_variant_get_uint64(gvar)); + g_variant_unref(gvar); + } else { + qDebug() << "ERROR: config_get SR_CONF_TIMEBASE failed."; + } + + gvar = dev_inst->get_config(probe, NULL, SR_CONF_COUPLING); + if (gvar != NULL) { + _acCoupling = g_variant_get_boolean(gvar); + g_variant_unref(gvar); + } else { + qDebug() << "ERROR: config_get SR_CONF_COUPLING failed."; + } } DsoSignal::~DsoSignal() { } -void DsoSignal::set_data(boost::shared_ptr _logic_data, - boost::shared_ptr _dso_data, - boost::shared_ptr _analog_data, - boost::shared_ptr _group_data) +shared_ptr DsoSignal::data() const { - (void)_analog_data; - (void)_logic_data; - (void)_group_data; - - assert(_dso_data); - - _data = _dso_data; + return _data; } void DsoSignal::set_scale(float scale) @@ -80,47 +173,333 @@ void DsoSignal::set_scale(float scale) _scale = scale; } -void DsoSignal::paint(QPainter &p, int y, int left, int right, double scale, - double offset) +void DsoSignal::set_enable(bool enable) { - assert(scale > 0); - assert(_data); - assert(right >= left); + _dev_inst->set_config(_probe, NULL, SR_CONF_EN_CH, + g_variant_new_boolean(enable)); + _view->set_need_update(true); + _view->update(); +} - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); - if (snapshots.empty()) - return; +bool DsoSignal::get_vDialActive() const +{ + return _vDialActive; +} - _scale = _windowHeight * 1.0f / 256; - const boost::shared_ptr &snapshot = - snapshots.front(); - - const uint16_t number_channels = snapshot->get_channel_num(); - if ((unsigned int)get_index() >= number_channels) - return; - - const double pixels_offset = offset / scale; - const double samplerate = _data->get_samplerate(); - const double start_time = _data->get_start_time(); - const int64_t last_sample = max((int64_t)(snapshot->get_sample_count() - 1), (int64_t)0); - const double samples_per_pixel = samplerate * scale; - const double start = samplerate * (offset - start_time); - const double end = start + samples_per_pixel * (right - left); - - const int64_t start_sample = min(max((int64_t)floor(start), - (int64_t)0), last_sample); - const int64_t end_sample = min(max((int64_t)ceil(end) + 1, - (int64_t)0), last_sample); - - if (samples_per_pixel < EnvelopeThreshold) - paint_trace(p, snapshot, y, left, - start_sample, end_sample, - pixels_offset, samples_per_pixel, number_channels); - else - paint_envelope(p, snapshot, y, left, - start_sample, end_sample, - pixels_offset, samples_per_pixel); +void DsoSignal::set_vDialActive(bool active) +{ + if (enabled()) + _vDialActive = active; +} + +bool DsoSignal::go_vDialPre() +{ + if (enabled() && !_vDial->isMin()) { + _vDial->set_sel(_vDial->get_sel() - 1); + _dev_inst->set_config(_probe, NULL, SR_CONF_VDIV, + g_variant_new_uint64(_vDial->get_value())); + return true; + } else { + return false; + } +} + +bool DsoSignal::go_vDialNext() +{ + if (enabled() && !_vDial->isMax()) { + _vDial->set_sel(_vDial->get_sel() + 1); + _dev_inst->set_config(_probe, NULL, SR_CONF_VDIV, + g_variant_new_uint64(_vDial->get_value())); + return true; + } else { + return false; + } +} + +bool DsoSignal::get_hDialActive() const +{ + return _hDialActive; +} + +void DsoSignal::set_hDialActive(bool active) +{ + if (enabled()) + _hDialActive = active; +} + +bool DsoSignal::go_hDialPre() +{ + if (!_hDial->isMin()) { + _hDial->set_sel(_hDial->get_sel() - 1); + int ch_num = _view->session().get_dso_ch_num(); + uint64_t sample_limit = _view->session().get_device()->get_sample_limit(); + uint64_t sample_rate = min((uint64_t)(sample_limit * pow(10, 9) / (_hDial->get_value() * DS_CONF_DSO_HDIVS)), + (uint64_t)(DS_MAX_DSO_SAMPLERATE / ch_num)); + _view->session().set_sample_rate(sample_rate); + const double scale = _hDial->get_value() * pow(10, -9) * DS_CONF_DSO_HDIVS / get_view_rect().width(); + _view->set_scale_offset(scale, _view->offset()); + _dev_inst->set_config(_probe, NULL, SR_CONF_TIMEBASE, + g_variant_new_uint64(_hDial->get_value())); + return true; + } else { + return false; + } +} + +bool DsoSignal::go_hDialNext() +{ + if (!_hDial->isMax()) { + _hDial->set_sel(_hDial->get_sel() + 1); + int ch_num = _view->session().get_dso_ch_num(); + uint64_t sample_limit = _view->session().get_device()->get_sample_limit(); + uint64_t sample_rate = min((uint64_t)(sample_limit * pow(10, 9) / (_hDial->get_value() * DS_CONF_DSO_HDIVS)), + (uint64_t)(DS_MAX_DSO_SAMPLERATE / ch_num)); + _view->session().set_sample_rate(sample_rate); + const double scale = _hDial->get_value() * pow(10, -9) * DS_CONF_DSO_HDIVS / get_view_rect().width(); + _view->set_scale_offset(scale, _view->offset()); + _dev_inst->set_config(_probe, NULL, SR_CONF_TIMEBASE, + g_variant_new_uint64(_hDial->get_value())); + return true; + } else { + return false; + } +} + +uint64_t DsoSignal::get_vDialValue() const +{ + return _vDial->get_value(); +} + +uint64_t DsoSignal::get_hDialValue() const +{ + return _hDial->get_value(); +} + +uint16_t DsoSignal::get_vDialSel() const +{ + return _vDial->get_sel(); +} + +uint16_t DsoSignal::get_hDialSel() const +{ + return _hDial->get_sel(); +} + +bool DsoSignal::get_acCoupling() const +{ + return _acCoupling; +} + +void DsoSignal::set_acCoupling(bool coupling) +{ + if (enabled()) { + _acCoupling = coupling; + _dev_inst->set_config(_probe, NULL, SR_CONF_COUPLING, + g_variant_new_boolean(_acCoupling)); + } +} + +int DsoSignal::get_trig_vpos() const +{ + return _trig_vpos * get_view_rect().height() + UpMargin; +} + +void DsoSignal::set_trig_vpos(int pos) +{ + assert(_view); + if (enabled()) { + double delta = min((double)max(pos - UpMargin, 0), get_view_rect().height()) * 1.0f / get_view_rect().height() - _zeroPos; + delta = min(delta, 0.5); + delta = max(delta, -0.5); + _trig_vpos = _zeroPos + delta; + + int trig_value = (-delta * 255.0f + 0x80); + + _dev_inst->set_config(_probe, NULL, SR_CONF_TRIGGER_VALUE, + g_variant_new_uint16(trig_value)); + } +} + +int DsoSignal::get_zeroPos() +{ + return _zeroPos * get_view_rect().height() + UpMargin; +} + +void DsoSignal::set_zeroPos(int pos) +{ + if (enabled()) { + double delta = _trig_vpos - _zeroPos; + _zeroPos = min((double)max(pos - UpMargin, 0), get_view_rect().height()) * 1.0f / get_view_rect().height(); + _trig_vpos = min(max(_zeroPos + delta, 0.0), 1.0); + } +} + +QRectF DsoSignal::get_view_rect() const +{ + assert(_view); + return QRectF(0, UpMargin, + _view->viewport()->width() - RightMargin, + _view->viewport()->height() - UpMargin - DownMargin); +} + +void DsoSignal::paint_back(QPainter &p, int left, int right) +{ + assert(_view); + + int i, j; + const int height = _view->viewport()->height() - UpMargin - DownMargin; + const int width = right - left - RightMargin; + + p.setPen(Qt::NoPen); + p.setBrush(Trace::dsBack); + p.drawRect(left, UpMargin, width, height); + + p.setPen(Trace::dsLightBlue); + p.drawLine(left, UpMargin/2, left + width, UpMargin/2); + const uint64_t sample_len = _dev_inst->get_sample_limit(); + const double samplerate = _dev_inst->get_sample_rate(); + const double samples_per_pixel = samplerate * _view->scale(); + const double shown_rate = min(samples_per_pixel * width * 1.0f / sample_len, 1.0); + const double start_time = _data->get_start_time(); + const double start = samplerate * (_view->offset() - start_time); + const double shown_offset = min(start / sample_len, 1.0) * width; + const double shown_len = shown_rate * width; + const QPointF left_edge[] = {QPoint(shown_offset + 3, UpMargin/2 - 6), + QPoint(shown_offset, UpMargin/2 - 6), + QPoint(shown_offset, UpMargin/2 + 6), + QPoint(shown_offset + 3, UpMargin/2 + 6)}; + const QPointF right_edge[] = {QPoint(shown_offset + shown_len - 3, UpMargin/2 - 6), + QPoint(shown_offset + shown_len , UpMargin/2 - 6), + QPoint(shown_offset + shown_len , UpMargin/2 + 6), + QPoint(shown_offset + shown_len - 3, UpMargin/2 + 6)}; + p.drawPolyline(left_edge, countof(left_edge)); + p.drawPolyline(right_edge, countof(right_edge)); + p.setBrush(Trace::dsBlue); + p.drawRect(shown_offset, UpMargin/2 - 3, shown_len, 6); + + QPen pen(Signal::dsFore); + pen.setStyle(Qt::DotLine); + p.setPen(pen); + const double spanY =height * 1.0f / 10; + for (i = 1; i <= DS_CONF_DSO_VDIVS; i++) { + const double posY = spanY * i + UpMargin; + p.drawLine(left, posY, right - RightMargin, posY); + const double miniSpanY = spanY / 5; + for (j = 1; j < 5; j++) { + p.drawLine(width / 2.0f - 10, posY - miniSpanY * j, + width / 2.0f + 10, posY - miniSpanY * j); + } + } + const double spanX = width * 1.0f / 10; + for (i = 1; i <= DS_CONF_DSO_HDIVS; i++) { + const double posX = spanX * i; + p.drawLine(posX, UpMargin, + posX, height + UpMargin); + const double miniSpanX = spanX / 5; + for (j = 1; j < 5; j++) { + p.drawLine(posX - miniSpanX * j, height / 2.0f + UpMargin - 10, + posX - miniSpanX * j, height / 2.0f + UpMargin + 10); + } + } +} + +void DsoSignal::paint_mid(QPainter &p, int left, int right) +{ + assert(_data); + assert(_view); + assert(right >= left); + + if (enabled()) { + const int height = _view->viewport()->height() - UpMargin - DownMargin; + const int width = right - left - RightMargin; + + const int y = get_zeroPos() + height * 0.5; + const double scale = _view->scale(); + assert(scale > 0); + const double offset = _view->offset(); + + const deque< boost::shared_ptr > &snapshots = + _data->get_snapshots(); + if (snapshots.empty()) + return; + + _scale = height * 1.0f / 256; + const shared_ptr &snapshot = + snapshots.front(); + + const uint16_t number_channels = snapshot->get_channel_num(); + if ((unsigned int)get_index() >= number_channels) + return; + + const double pixels_offset = offset / scale; + //const double samplerate = _data->samplerate(); + const double samplerate = _dev_inst->get_sample_rate(); + const double start_time = _data->get_start_time(); + const int64_t last_sample = max((int64_t)(snapshot->get_sample_count() - 1), (int64_t)0); + const double samples_per_pixel = samplerate * scale; + const double start = samplerate * (offset - start_time); + const double end = start + samples_per_pixel * width; + + const int64_t start_sample = min(max((int64_t)floor(start), + (int64_t)0), last_sample); + const int64_t end_sample = min(max((int64_t)ceil(end) + 1, + (int64_t)0), last_sample); + + if (samples_per_pixel < EnvelopeThreshold) + paint_trace(p, snapshot, y, left, + start_sample, end_sample, + pixels_offset, samples_per_pixel, number_channels); + else + paint_envelope(p, snapshot, y, left, + start_sample, end_sample, + pixels_offset, samples_per_pixel); + } +} + +void DsoSignal::paint_fore(QPainter &p, int left, int right) +{ + assert(_view); + + QPen pen(Signal::dsGray); + pen.setStyle(Qt::DotLine); + p.setPen(pen); + p.drawLine(left, get_zeroPos(), right - RightMargin, get_zeroPos()); + + if(enabled()) { + const QPointF mouse_point = _view->hover_point(); + const QRectF label_rect = get_trig_rect(left, right); + const bool hover = label_rect.contains(mouse_point); + + // Paint the trig line + const QPointF points[] = { + QPointF(right - label_rect.width()*1.5, get_trig_vpos()), + label_rect.topLeft(), + label_rect.topRight(), + label_rect.bottomRight(), + label_rect.bottomLeft() + }; + + p.setPen(Qt::transparent); + p.setBrush(hover ? _colour.dark() : _colour); + p.drawPolygon(points, countof(points)); + + // paint the _trig_vpos line + p.setPen(QPen(_colour, 1, Qt::DashLine)); + p.drawLine(left, get_trig_vpos(), right - label_rect.width()*1.5, get_trig_vpos()); + + // Paint the text + p.setPen(Qt::white); + p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "T"); + } +} + +QRectF DsoSignal::get_trig_rect(int left, int right) const +{ + (void)left; + + return QRectF(right - SquareWidth, + get_trig_vpos() - SquareWidth / 2, + SquareWidth, SquareWidth); } void DsoSignal::paint_trace(QPainter &p, @@ -140,11 +519,15 @@ void DsoSignal::paint_trace(QPainter &p, QPointF *points = new QPointF[sample_count]; QPointF *point = points; + float top = get_view_rect().top(); + float bottom = get_view_rect().bottom(); for (int64_t sample = start; sample < end; sample++) { const float x = (sample / samples_per_pixel - pixels_offset) + left; uint8_t offset = samples[(sample - start)*num_channels]; - *point++ = QPointF(x, - y - offset * _scale); + if (offset >0 && offset < 0xff) { + const float yp = min(bottom, max(top, y - offset * _scale)); + *point++ = QPointF(x, yp); + } } p.drawPolyline(points, point - points); @@ -206,18 +589,30 @@ const std::vector< std::pair > DsoSignal::cur_edges() const } -void DsoSignal::set_decoder(pv::decoder::Decoder *decoder) -{ - (void)decoder; -} - -decoder::Decoder *DsoSignal::get_decoder() -{ - return NULL; -} - -void DsoSignal::del_decoder() +void DsoSignal::paint_type_options(QPainter &p, int right, bool hover, int action) { + int y = get_y(); + const QRectF vDial_rect = get_rect("vDial", y, right); + const QRectF hDial_rect = get_rect("hDial", y, right); + const QRectF acdc_rect = get_rect("acdc", y, right); + const QRectF chEn_rect = get_rect("chEn", y, right); + + QColor vDial_color = _vDialActive ? dsActive : dsDisable; + QColor hDial_color = _hDialActive ? dsActive : dsDisable; + _vDial->paint(p, vDial_rect, vDial_color); + _hDial->paint(p, hDial_rect, hDial_color); + + p.setPen(Qt::transparent); + p.setBrush((hover && action == CHEN) ? _colour.darker() : _colour); + p.drawRect(chEn_rect); + p.setPen(Qt::white); + p.drawText(chEn_rect, Qt::AlignCenter | Qt::AlignVCenter, enabled() ? "EN" : "DIS"); + + p.setPen(Qt::transparent); + p.setBrush(enabled() ? ((hover && action == ACDC) ? _colour.darker() : _colour) : dsDisable); + p.drawRect(acdc_rect); + p.setPen(Qt::white); + p.drawText(acdc_rect, Qt::AlignCenter | Qt::AlignVCenter, _acCoupling ? "AC" : "DC"); } } // namespace view diff --git a/DSLogic-gui/pv/view/dsosignal.h b/DSLogic-gui/pv/view/dsosignal.h index e22680a08c8065f4e640c360cfa19b29bd351e41..c6b6626793be74b7ef8a32a6517f9a9460d5a640 100644 --- a/DSLogic-gui/pv/view/dsosignal.h +++ b/DSLogic-gui/pv/view/dsosignal.h @@ -42,43 +42,99 @@ class DsoSignal : public Signal { private: static const QColor SignalColours[4]; - static const float EnvelopeThreshold; + static const int HitCursorMargin = 3; + static const uint64_t vDialValueCount = 10; + static const uint64_t vDialValueStep = 1000; + static const uint64_t vDialUnitCount = 2; + static const uint64_t hDialValueCount = 22; + static const uint64_t hDialValueStep = 1000; + static const uint64_t hDialUnitCount = 4; + static const uint64_t vDialValue[vDialValueCount]; + static const QString vDialUnit[vDialUnitCount]; + + static const uint64_t hDialValue[hDialValueCount]; + static const QString hDialUnit[hDialUnitCount]; + + static const int UpMargin; + static const int DownMargin; + static const int RightMargin; + public: - DsoSignal(QString name, - boost::shared_ptr data, int probe_index, int order, - uint64_t vdiv, uint64_t timebase, bool coupling, bool active); + DsoSignal(boost::shared_ptr dev_inst, + boost::shared_ptr data, + const sr_channel * const probe); virtual ~DsoSignal(); + boost::shared_ptr data() const; + void set_scale(float scale); + /** + * + */ + void set_enable(bool enable); + bool get_vDialActive() const; + void set_vDialActive(bool active); + bool get_hDialActive() const; + void set_hDialActive(bool active); + bool go_vDialPre(); + bool go_vDialNext(); + bool go_hDialPre(); + bool go_hDialNext(); + uint64_t get_vDialValue() const; + uint64_t get_hDialValue() const; + uint16_t get_vDialSel() const; + uint16_t get_hDialSel() const; + bool get_acCoupling() const; + void set_acCoupling(bool coupling); + void set_trig_vpos(int pos); + int get_trig_vpos() const; + + /** + * Gets the mid-Y position of this signal. + */ + int get_zeroPos(); + + /** + * Sets the mid-Y position of this signal. + */ + void set_zeroPos(int pos); + + /** + * Paints the background layer of the trace with a QPainter + * @param p the QPainter to paint into. + * @param left the x-coordinate of the left edge of the signal + * @param right the x-coordinate of the right edge of the signal + **/ + void paint_back(QPainter &p, int left, int right); + /** * Paints the signal with a QPainter * @param p the QPainter to paint into. - * @param y the y-coordinate to draw the signal at. * @param left the x-coordinate of the left edge of the signal. * @param right the x-coordinate of the right edge of the signal. - * @param scale the scale in seconds per pixel. - * @param offset the time to show at the left hand edge of - * the view in seconds. **/ - void paint(QPainter &p, int y, int left, int right, double scale, - double offset); + void paint_mid(QPainter &p, int left, int right); - const std::vector< std::pair > cur_edges() const; + /** + * Paints the signal with a QPainter + * @param p the QPainter to paint into. + * @param left the x-coordinate of the left edge of the signal. + * @param right the x-coordinate of the right edge of the signal. + **/ + void paint_fore(QPainter &p, int left, int right); - void set_decoder(pv::decoder::Decoder *decoder); + const std::vector< std::pair > cur_edges() const; - pv::decoder::Decoder* get_decoder(); + QRectF get_view_rect() const; - void del_decoder(); + QRectF get_trig_rect(int left, int right) const; - void set_data(boost::shared_ptr _logic_data, - boost::shared_ptr _dso_data, - boost::shared_ptr _analog_data, - boost::shared_ptr _group_data); +protected: + void paint_type_options(QPainter &p, int right, bool hover, int action); private: void paint_trace(QPainter &p, @@ -95,6 +151,15 @@ private: private: boost::shared_ptr _data; float _scale; + + dslDial *_vDial; + dslDial *_hDial; + bool _vDialActive; + bool _hDialActive; + bool _acCoupling; + + double _trig_vpos; + double _zeroPos; }; } // namespace view diff --git a/DSLogic-gui/pv/view/groupsignal.cpp b/DSLogic-gui/pv/view/groupsignal.cpp index 5330c067a1806d74ee90d2483b40ac9c523053a3..1ba1bfece2dc6898dd128928e3a9af5c19dd22e2 100644 --- a/DSLogic-gui/pv/view/groupsignal.cpp +++ b/DSLogic-gui/pv/view/groupsignal.cpp @@ -28,6 +28,7 @@ #include "groupsignal.h" #include "pv/data/group.h" #include "pv/data/groupsnapshot.h" +#include "view.h" using namespace boost; using namespace std; @@ -45,8 +46,8 @@ const QColor GroupSignal::SignalColours[4] = { const float GroupSignal::EnvelopeThreshold = 256.0f; GroupSignal::GroupSignal(QString name, boost::shared_ptr data, - std::list probe_index_list, int order, int group_index) : - Signal(name, probe_index_list, DS_GROUP, order, group_index), + std::list probe_index_list, int group_index) : + Trace(name, probe_index_list, DS_GROUP, group_index), _data(data) { _colour = SignalColours[probe_index_list.front() % countof(SignalColours)]; @@ -57,18 +58,14 @@ GroupSignal::~GroupSignal() { } -void GroupSignal::set_data(boost::shared_ptr _logic_data, - boost::shared_ptr _dso_data, - boost::shared_ptr _analog_data, - boost::shared_ptr _group_data) +bool GroupSignal::enabled() const { - (void)_logic_data; - (void)_dso_data; - (void)_analog_data; - - assert(_group_data); + return true; +} - _data = _group_data; +shared_ptr GroupSignal::data() const +{ + return _data; } void GroupSignal::set_scale(float scale) @@ -76,15 +73,18 @@ void GroupSignal::set_scale(float scale) _scale = scale; } -void GroupSignal::paint(QPainter &p, int y, int left, int right, double scale, - double offset) +void GroupSignal::paint_mid(QPainter &p, int left, int right) { - assert(scale > 0); - assert(_data); - assert(right >= left); + assert(_data); + assert(_view); + assert(right >= left); + + const int y = get_y() + _signalHeight * 0.5; + const double scale = _view->scale(); + assert(scale > 0); + const double offset = _view->offset(); _scale = _signalHeight * 1.0f / pow(2, _index_list.size()); - paint_axis(p, y, left, right); const deque< boost::shared_ptr > &snapshots = _data->get_snapshots(); @@ -95,7 +95,7 @@ void GroupSignal::paint(QPainter &p, int y, int left, int right, double scale, snapshots.at(_sec_index); const double pixels_offset = offset / scale; - const double samplerate = _data->get_samplerate(); + const double samplerate = _data->samplerate(); const double start_time = _data->get_start_time(); const int64_t last_sample = snapshot->get_sample_count() - 1; const double samples_per_pixel = samplerate * scale; @@ -196,18 +196,32 @@ const std::vector< std::pair > GroupSignal::cur_edges() const } -void GroupSignal::set_decoder(pv::decoder::Decoder *decoder) -{ - (void)decoder; -} - -decoder::Decoder *GroupSignal::get_decoder() -{ - return NULL; -} - -void GroupSignal::del_decoder() +void GroupSignal::paint_type_options(QPainter &p, int right, bool hover, int action) { + (void)hover; + (void)action; + + int y = get_y(); + const QRectF group_index_rect = get_rect("groupIndex", y, right); + QString index_string; + int last_index; + p.setPen(Qt::transparent); + p.setBrush(dsBlue); + p.drawRect(group_index_rect); + std::list::iterator i = _index_list.begin(); + last_index = (*i); + index_string = QString::number(last_index); + while (++i != _index_list.end()) { + if ((*i) == last_index + 1 && index_string.indexOf("-") < 3 && index_string.indexOf("-") > 0) + index_string.replace(QString::number(last_index), QString::number((*i))); + else if ((*i) == last_index + 1) + index_string = QString::number((*i)) + "-" + index_string; + else + index_string = QString::number((*i)) + "," + index_string; + last_index = (*i); + } + p.setPen(Qt::white); + p.drawText(group_index_rect, Qt::AlignRight | Qt::AlignVCenter, index_string); } } // namespace view diff --git a/DSLogic-gui/pv/view/groupsignal.h b/DSLogic-gui/pv/view/groupsignal.h index d38d1be4d5970f0afe8734b1a38b5102b99dd85b..04c1bba2cd7dfd0176afb71e6042569f05135790 100644 --- a/DSLogic-gui/pv/view/groupsignal.h +++ b/DSLogic-gui/pv/view/groupsignal.h @@ -41,7 +41,7 @@ class GroupSnapshot; namespace view { -class GroupSignal : public Signal +class GroupSignal : public Trace { private: static const QColor SignalColours[4]; @@ -51,37 +51,31 @@ private: public: GroupSignal(QString name, boost::shared_ptr data, - std::list probe_index_list, int order, int group_index); + std::list probe_index_list, int group_index); virtual ~GroupSignal(); + /** + * Returns true if the trace is visible and enabled. + */ + bool enabled() const; + + boost::shared_ptr data() const; + void set_scale(float scale); /** * Paints the signal with a QPainter * @param p the QPainter to paint into. - * @param y the y-coordinate to draw the signal at. * @param left the x-coordinate of the left edge of the signal. * @param right the x-coordinate of the right edge of the signal. - * @param scale the scale in seconds per pixel. - * @param offset the time to show at the left hand edge of - * the view in seconds. **/ - void paint(QPainter &p, int y, int left, int right, double scale, - double offset); + void paint_mid(QPainter &p, int left, int right); const std::vector< std::pair > cur_edges() const; - void set_decoder(pv::decoder::Decoder *decoder); - - pv::decoder::Decoder* get_decoder(); - - void del_decoder(); - - void set_data(boost::shared_ptr _logic_data, - boost::shared_ptr _dso_data, - boost::shared_ptr _analog_data, - boost::shared_ptr _group_data); +protected: + void paint_type_options(QPainter &p, int right, bool hover, int action); private: void paint_trace(QPainter &p, diff --git a/DSLogic-gui/pv/view/header.cpp b/DSLogic-gui/pv/view/header.cpp index 6803e3ac404762739743e40183050f1ba22cad00..8301fb3e06b9152f8768bf30e0d7bc4e72c5f58d 100644 --- a/DSLogic-gui/pv/view/header.cpp +++ b/DSLogic-gui/pv/view/header.cpp @@ -24,8 +24,14 @@ #include "header.h" #include "view.h" -#include "signal.h" +#include "trace.h" +#include "dsosignal.h" +#include "logicsignal.h" +#include "analogsignal.h" +#include "groupsignal.h" +#include "decodetrace.h" #include "../sigsession.h" +#include "../device/devinst.h" #include @@ -70,8 +76,8 @@ Header::Header(View &parent) : connect(nameEdit, SIGNAL(editingFinished()), this, SLOT(on_action_set_name_triggered())); - connect(&_view, SIGNAL(signals_moved()), - this, SLOT(on_signals_moved())); + connect(&_view, SIGNAL(traces_moved()), + this, SLOT(on_traces_moved())); } @@ -83,30 +89,28 @@ int Header::get_nameEditWidth() return 0; } -boost::shared_ptr Header::get_mSig( +boost::shared_ptr Header::get_mTrace( int &action, const QPoint &pt) { const int w = width(); - const vector< boost::shared_ptr > sigs( - _view.session().get_signals()); + const vector< boost::shared_ptr > traces( + _view.get_traces()); - const int v_offset = _view.v_offset(); - BOOST_FOREACH(const boost::shared_ptr s, sigs) + BOOST_FOREACH(const boost::shared_ptr t, traces) { - assert(s); + assert(t); - if ((action = s->pt_in_rect(s->get_v_offset() - v_offset - _view.get_signalHeight() / 2, - w, pt))) - return s; + if ((action = t->pt_in_rect(t->get_y(), w, pt))) + return t; } - return boost::shared_ptr(); + return boost::shared_ptr(); } void Header::paintEvent(QPaintEvent*) { - using pv::view::Signal; + using pv::view::Trace; QStyleOption o; o.initFrom(this); @@ -114,47 +118,22 @@ void Header::paintEvent(QPaintEvent*) style()->drawPrimitive(QStyle::PE_Widget, &o, &painter, this); const int w = width(); - int action; - const vector< boost::shared_ptr > sigs( - _view.session().get_signals()); + int action = 0; + const vector< boost::shared_ptr > traces( + _view.get_traces()); //QPainter painter(this); //painter.setRenderHint(QPainter::Antialiasing); - const int v_offset = _view.v_offset(); - const bool dragging = !_drag_sigs.empty(); - BOOST_FOREACH(const boost::shared_ptr s, sigs) + const bool dragging = !_drag_traces.empty(); + BOOST_FOREACH(const boost::shared_ptr t, traces) { - assert(s); + assert(t); - const int y = s->get_v_offset() - v_offset - _view.get_signalHeight() / 2; + const int y = t->get_y(); const bool highlight = !dragging && - (action = s->pt_in_rect(y, w, _mouse_point)); - s->paint_label(painter, y, w, highlight, action); - // Paint the Backgroud - painter.setRenderHint(QPainter::Antialiasing, false); - painter.setPen(Signal::dsGray); - if (s->selected() && _moveFlag) { - if (s->get_type() == Signal::DS_ANALOG) { - painter.drawLine(0, s->get_old_v_offset() - v_offset - s->get_signalHeight(), - w, s->get_old_v_offset() - v_offset - s->get_signalHeight()); - painter.drawLine(0, s->get_old_v_offset() - v_offset, - w, s->get_old_v_offset() - v_offset); - } else if (s->get_type() == Signal::DS_LOGIC){ - painter.drawLine(0, s->get_old_v_offset() - v_offset + 10, - w, s->get_old_v_offset() - v_offset + 10); - } - } else { - if (s->get_type() == Signal::DS_ANALOG) { - painter.drawLine(0, s->get_v_offset() - v_offset, - w, s->get_v_offset() - v_offset); - painter.drawLine(0, s->get_v_offset() - v_offset - s->get_signalHeight(), - w, s->get_v_offset() - v_offset - s->get_signalHeight()); - } else if (s->get_type() == Signal::DS_LOGIC) { - painter.drawLine(0, s->get_v_offset() - v_offset + 10, - w, s->get_v_offset() - v_offset + 10); - } - } + (action = t->pt_in_rect(y, w, _mouse_point)); + t->paint_label(painter, w, highlight, action); } painter.end(); @@ -164,126 +143,116 @@ void Header::mousePressEvent(QMouseEvent *event) { assert(event); - const vector< boost::shared_ptr > sigs( - _view.session().get_signals()); + const vector< boost::shared_ptr > traces( + _view.get_traces()); int action; if (event->button() & Qt::LeftButton) { _mouse_down_point = event->pos(); - // Save the offsets of any signals which will be dragged - BOOST_FOREACH(const boost::shared_ptr s, sigs) - if (s->selected()) - _drag_sigs.push_back( - make_pair(s, s->get_v_offset())); + // Save the offsets of any Traces which will be dragged + BOOST_FOREACH(const boost::shared_ptr t, traces) + if (t->selected()) + _drag_traces.push_back( + make_pair(t, t->get_v_offset())); - // Select the signal if it has been clicked - const boost::shared_ptr mSig = - get_mSig(action, event->pos()); - if (action == Signal::COLOR && mSig) { + // Select the Trace if it has been clicked + const boost::shared_ptr mTrace = + get_mTrace(action, event->pos()); + if (action == Trace::COLOR && mTrace) { _colorFlag = true; - } else if (action == Signal::NAME && mSig) { + } else if (action == Trace::NAME && mTrace) { _nameFlag = true; - } else if (action == Signal::LABEL && mSig) { - if (mSig->selected()) - mSig->select(false); + } else if (action == Trace::LABEL && mTrace) { + if (mTrace->selected()) + mTrace->select(false); else { - if (mSig->get_type() != Signal::DS_DSO) - mSig->select(true); + if (mTrace->get_type() != Trace::DS_DSO) + mTrace->select(true); if (~QApplication::keyboardModifiers() & Qt::ControlModifier) - _drag_sigs.clear(); + _drag_traces.clear(); - // Add the signal to the drag list - if (event->button() & Qt::LeftButton) - _drag_sigs.push_back( - make_pair(mSig, - (mSig->get_type() == Signal::DS_DSO) ? mSig->get_zeroPos() : mSig->get_v_offset())); + // Add the Trace to the drag list + if (event->button() & Qt::LeftButton) { + _drag_traces.push_back(make_pair(mTrace, mTrace->get_zeroPos())); + } } - mSig->set_old_v_offset(mSig->get_v_offset()); - } else if (action == Signal::POSTRIG && mSig) { - if (mSig->get_trig() == Signal::POSTRIG) - mSig->set_trig(0); + mTrace->set_old_v_offset(mTrace->get_v_offset()); + } else if (action == Trace::POSTRIG && mTrace) { + if (mTrace->get_trig() == Trace::POSTRIG) + mTrace->set_trig(0); else - mSig->set_trig(Signal::POSTRIG); - } else if (action == Signal::HIGTRIG && mSig) { - if (mSig->get_trig() == Signal::HIGTRIG) - mSig->set_trig(0); + mTrace->set_trig(Trace::POSTRIG); + } else if (action == Trace::HIGTRIG && mTrace) { + if (mTrace->get_trig() == Trace::HIGTRIG) + mTrace->set_trig(0); else - mSig->set_trig(Signal::HIGTRIG); - } else if (action == Signal::NEGTRIG && mSig) { - if (mSig->get_trig() == Signal::NEGTRIG) - mSig->set_trig(0); + mTrace->set_trig(Trace::HIGTRIG); + } else if (action == Trace::NEGTRIG && mTrace) { + if (mTrace->get_trig() == Trace::NEGTRIG) + mTrace->set_trig(0); else - mSig->set_trig(Signal::NEGTRIG); - } else if (action == Signal::LOWTRIG && mSig) { - if (mSig->get_trig() == Signal::LOWTRIG) - mSig->set_trig(0); + mTrace->set_trig(Trace::NEGTRIG); + } else if (action == Trace::LOWTRIG && mTrace) { + if (mTrace->get_trig() == Trace::LOWTRIG) + mTrace->set_trig(0); else - mSig->set_trig(Signal::LOWTRIG); - } else if (action == Signal::EDGETRIG && mSig) { - if (mSig->get_trig() == Signal::EDGETRIG) - mSig->set_trig(0); + mTrace->set_trig(Trace::LOWTRIG); + } else if (action == Trace::EDGETRIG && mTrace) { + if (mTrace->get_trig() == Trace::EDGETRIG) + mTrace->set_trig(0); else - mSig->set_trig(Signal::EDGETRIG); - } else if (action == Signal::VDIAL && mSig) { - BOOST_FOREACH(const shared_ptr s, sigs) { - s->set_hDialActive(false); - if (s != mSig) { - s->set_vDialActive(false); - } - } - mSig->set_vDialActive(!mSig->get_vDialActive()); - } else if (action == Signal::HDIAL && mSig) { - if (mSig->get_hDialActive()) { - BOOST_FOREACH(const shared_ptr s, sigs) { - s->set_vDialActive(false); - s->set_hDialActive(false); - } - } else { - BOOST_FOREACH(const shared_ptr s, sigs) { - s->set_vDialActive(false); - s->set_hDialActive(true); + mTrace->set_trig(Trace::EDGETRIG); + } else if (action == Trace::VDIAL && mTrace) { + shared_ptr dsoSig; + BOOST_FOREACH(const shared_ptr t, traces) { + if (dsoSig = dynamic_pointer_cast(t)) { + dsoSig->set_hDialActive(false); + if (t != mTrace) { + dsoSig->set_vDialActive(false); + } } } - } else if (action == Signal::CHEN && mSig) { - int channel; - if (mSig->get_index() == 0) { - bool last = 1; - channel = 0; - BOOST_FOREACH(const shared_ptr s, sigs) { - if (s->get_index() != 0 && s->get_active()) { - QMessageBox msg(this); - msg.setText("Tips"); - msg.setInformativeText("If only one channel want, Channel0 has a higher maximum sample rate!"); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Information); - msg.exec(); - s->set_active(!s->get_active()); - last = 0; - channel = s->get_index(); - break; + if (dsoSig = dynamic_pointer_cast(mTrace)) + dsoSig->set_vDialActive(!dsoSig->get_vDialActive()); + } else if (action == Trace::HDIAL && mTrace) { + shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(mTrace)) { + if (dsoSig->get_hDialActive()) { + BOOST_FOREACH(const shared_ptr t, traces) { + if(dsoSig = dynamic_pointer_cast(t)) { + dsoSig->set_vDialActive(false); + dsoSig->set_hDialActive(false); + } + } + } else { + BOOST_FOREACH(const shared_ptr t, traces) { + if(dsoSig = dynamic_pointer_cast(t)) { + dsoSig->set_vDialActive(false); + dsoSig->set_hDialActive(true); + } } } - if (last) - mSig->set_active(!mSig->get_active()); - } else { - mSig->set_active(!mSig->get_active()); - channel = mSig->get_index(); } - ch_changed(channel); - } else if (action == Signal::ACDC && mSig) { - mSig->set_acCoupling(!mSig->get_acCoupling()); - acdc_changed(mSig->get_index()); + } else if (action == Trace::CHEN && mTrace) { + shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(mTrace)) { + dsoSig->set_enable(!dsoSig->enabled()); + } + } else if (action == Trace::ACDC && mTrace) { + shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(mTrace)) + dsoSig->set_acCoupling(!dsoSig->get_acCoupling()); } if (~QApplication::keyboardModifiers() & Qt::ControlModifier) { - // Unselect all other signals because the Ctrl is not + // Unselect all other Traces because the Ctrl is not // pressed - BOOST_FOREACH(const boost::shared_ptr s, sigs) - if (s != mSig) - s->select(false); + BOOST_FOREACH(const shared_ptr t, traces) + if (t != mTrace) + t->select(false); } update(); } @@ -295,26 +264,27 @@ void Header::mouseReleaseEvent(QMouseEvent *event) // judge for color / name / trigger / move int action; - const boost::shared_ptr mSig = - get_mSig(action, event->pos()); - if (mSig){ - if (action == Signal::COLOR && _colorFlag) { - _context_signal = mSig; + const boost::shared_ptr mTrace = + get_mTrace(action, event->pos()); + if (mTrace){ + if (action == Trace::COLOR && _colorFlag) { + _context_trace = mTrace; changeColor(event); _view.set_need_update(true); - } else if (action == Signal::NAME && _nameFlag) { - _context_signal = mSig; + } else if (action == Trace::NAME && _nameFlag) { + _context_trace = mTrace; changeName(event); } } if (_moveFlag) { - move(event); + //move(event); + _view.signals_changed(); _view.set_need_update(true); } _colorFlag = false; _nameFlag = false; _moveFlag = false; - _drag_sigs.clear(); + _drag_traces.clear(); _view.normalize_layout(); } @@ -323,30 +293,24 @@ void Header::wheelEvent(QWheelEvent *event) assert(event); if (event->orientation() == Qt::Vertical) { - const vector< shared_ptr > sigs( - _view.session().get_signals()); + const vector< shared_ptr > traces( + _view.get_traces()); // Vertical scrolling double shift = event->delta() / 20.0; - if (shift > 1.0) { - BOOST_FOREACH(const shared_ptr s, sigs) { - if (s->get_vDialActive()) { - if(s->go_vDialNext()) - vDial_changed(s->get_index()); - break; - } else if (s->get_hDialActive()) { - if(s->go_hDialNext()) - hDial_changed(0); - } - } - } else if (shift < -1.0) { - BOOST_FOREACH(const shared_ptr s, sigs) { - if (s->get_vDialActive()) { - if(s->go_vDialPre()) - vDial_changed(s->get_index()); + BOOST_FOREACH(const shared_ptr t, traces) { + shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(t)) { + if (dsoSig->get_vDialActive()) { + if (shift > 1.0) + dsoSig->go_vDialNext(); + else if (shift < -1.0) + dsoSig->go_vDialPre(); break; - } else if (s->get_hDialActive()) { - if(s->go_hDialPre()) - hDial_changed(0); + } else if (dsoSig->get_hDialActive()) { + if (shift > 1.0) + dsoSig->go_hDialNext(); + else if (shift < -1.0) + dsoSig->go_hDialPre(); } } } @@ -354,145 +318,11 @@ void Header::wheelEvent(QWheelEvent *event) } } -void Header::move(QMouseEvent *event) -{ - bool _moveValid = false; - bool _moveUp = false; - bool firstCheck = true; - const vector< boost::shared_ptr > sigs( - _view.session().get_signals()); - boost::shared_ptr minDragSig; - boost::shared_ptr maxDragSig; - int minOffset; - int minOldOffset; - int maxOffset; - int maxOldOffset; - int targetOffset; - std::list, - int> >::iterator minJ; - std::list, - int> >::iterator maxJ; - int targetOrder; - - // reCalculate _v_offset of all signals after dragging release - if ((event->button() == Qt::LeftButton)) { - while (!_drag_sigs.empty()) { - minOffset = INT_MAX; - maxOffset = 0; - for (std::list, - int> >::iterator i = _drag_sigs.begin(); - i != _drag_sigs.end(); i++) { - const boost::shared_ptr sig((*i).first); - if (sig) { - if (sig->get_v_offset() < minOffset) { - minDragSig = sig; - minOldOffset = (*i).second; - minOffset = sig->get_v_offset(); - minJ = i; - } - if (sig->get_v_offset() > maxOffset) { - maxDragSig = sig; - maxOldOffset = (*i).second; - maxOffset = sig->get_v_offset(); - maxJ = i; - } - } - } - if (minOffset > minOldOffset) { - _moveUp = false; - _drag_sigs.erase(maxJ); - } else { - _moveUp = true; - _drag_sigs.erase(minJ); - } - if (!_moveValid && firstCheck){ - firstCheck = false; - BOOST_FOREACH(const boost::shared_ptr s, sigs) { - if (_moveUp) { - if (s->selected()) { - if ((minOffset <= s->get_old_v_offset()) && (minOffset > (s->get_old_v_offset() - _view.get_spanY()))) { - _moveValid = true; - targetOffset = s->get_old_v_offset(); - targetOrder = s->get_order(); - break; - } - } else { - if ((minOffset <= s->get_v_offset()) && (minOffset > (s->get_v_offset() - _view.get_spanY()))) { - _moveValid = true; - targetOffset = s->get_v_offset(); - targetOrder = s->get_order(); - break; - } - } - } else { - if (s->selected()) { - if ((maxOffset >= s->get_old_v_offset()) && (maxOffset < (s->get_old_v_offset() + _view.get_spanY()))) { - _moveValid = true; - targetOffset = s->get_old_v_offset(); - targetOrder = s->get_order(); - break; - } - } else { - if ((maxOffset >= s->get_v_offset()) && (maxOffset < (s->get_v_offset() + _view.get_spanY()))) { - _moveValid = true; - targetOffset = s->get_v_offset(); - targetOrder = s->get_order(); - break; - } - } - } - } - } - if (_moveValid) { - BOOST_FOREACH(const boost::shared_ptr s, sigs) { - if (_moveUp) { - if (s->selected() && s == minDragSig) { - s->set_v_offset(targetOffset); - s->set_order(targetOrder); - s->select(false); - } else if (!s->selected() && s->get_v_offset() >= targetOffset && s->get_v_offset() < minOldOffset) { - s->set_v_offset(s->get_v_offset() + _view.get_spanY()); - s->set_order(s->get_order() + 1); - } - } else { - if (s->selected() && s == maxDragSig) { - s->set_v_offset(targetOffset); - s->set_order(targetOrder); - s->select(false); - } else if (!s->selected() && s->get_v_offset() <= targetOffset && s->get_v_offset() > maxOldOffset) { - s->set_v_offset(s->get_v_offset() - _view.get_spanY()); - s->set_order(s->get_order() - 1); - } - } - } - if (_moveUp) { - targetOffset += _view.get_spanY(); - targetOrder++; - } else { - targetOffset -= _view.get_spanY(); - targetOrder--; - } - } - } - if (_moveValid) { - signals_moved(); - } else { - BOOST_FOREACH(const boost::shared_ptr s, sigs) { - if (s->selected()) { - s->set_v_offset(s->get_old_v_offset()); - s->select(false); - } - } - } - } - _moveValid = false; -} - void Header::changeName(QMouseEvent *event) { if ((event->button() == Qt::LeftButton)) { header_resize(); - nameEdit->setText(_context_signal->get_name()); + nameEdit->setText(_context_trace->get_name()); nameEdit->selectAll(); nameEdit->setFocus(); nameEdit->show(); @@ -503,9 +333,9 @@ void Header::changeName(QMouseEvent *event) void Header::changeColor(QMouseEvent *event) { if ((event->button() == Qt::LeftButton)) { - const QColor new_color = QColorDialog::getColor(_context_signal->get_colour(), this, tr("Set Channel Colour")); + const QColor new_color = QColorDialog::getColor(_context_trace->get_colour(), this, tr("Set Channel Colour")); if (new_color.isValid()) - _context_signal->set_colour(new_color); + _context_trace->set_colour(new_color); } } @@ -514,17 +344,17 @@ void Header::mouseMoveEvent(QMouseEvent *event) assert(event); _mouse_point = event->pos(); - // Move the signals if we are dragging - if (!_drag_sigs.empty()) { + // Move the Traces if we are dragging + if (!_drag_traces.empty()) { const int delta = event->pos().y() - _mouse_down_point.y(); - for (std::list, - int> >::iterator i = _drag_sigs.begin(); - i != _drag_sigs.end(); i++) { - const boost::shared_ptr sig((*i).first); + for (std::list, + int> >::iterator i = _drag_traces.begin(); + i != _drag_traces.end(); i++) { + const boost::shared_ptr sig((*i).first); if (sig) { int y = (*i).second + delta; - if (sig->get_type() != Signal::DS_DSO) { + if (sig->get_type() != Trace::DS_DSO) { const int y_snap = ((y + View::SignalSnapGridSize / 2) / View::SignalSnapGridSize) * @@ -533,20 +363,19 @@ void Header::mouseMoveEvent(QMouseEvent *event) _moveFlag = true; sig->set_v_offset(y_snap); } - // Ensure the signal is selected + // Ensure the Trace is selected sig->select(true); } else { - if (y < 0) - y = 0; - else if (y > height()) - y = height(); - sig->set_zeroPos(y); - sig->select(false); - signals_moved(); + shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(sig)) { + dsoSig->set_zeroPos(y); + dsoSig->select(false); + traces_moved(); + } } } } - //signals_moved(); + //traces_moved(); } update(); } @@ -561,33 +390,33 @@ void Header::contextMenuEvent(QContextMenuEvent *event) { int action; - const boost::shared_ptr s = get_mSig(action, _mouse_point); + const boost::shared_ptr t = get_mTrace(action, _mouse_point); - if (!s || !s->selected() || action != Signal::LABEL) + if (!t || !t->selected() || action != Trace::LABEL) return; QMenu menu(this); - if (s->get_type() == Signal::DS_LOGIC) + if (t->get_type() == Trace::DS_LOGIC) menu.addAction(_action_add_group); - else if (s->get_type() == Signal::DS_GROUP) + else if (t->get_type() == Trace::DS_GROUP) menu.addAction(_action_del_group); - _context_signal = s; + _context_trace = t; menu.exec(event->globalPos()); - _context_signal.reset(); + _context_trace.reset(); } void Header::on_action_set_name_triggered() { - boost::shared_ptr context_signal = _context_signal; - if (!context_signal) + boost::shared_ptr context_Trace = _context_trace; + if (!context_Trace) return; if (nameEdit->isModified()) { - context_signal->set_name(nameEdit->text()); - if (context_signal->get_type() == Signal::DS_LOGIC || - context_signal->get_type() == Signal::DS_ANALOG) - sr_dev_probe_name_set(_view.session().get_device(), context_signal->get_index(), nameEdit->text().toUtf8().constData()); + context_Trace->set_name(nameEdit->text()); + if (context_Trace->get_type() == Trace::DS_LOGIC || + context_Trace->get_type() == Trace::DS_ANALOG) + sr_dev_probe_name_set(_view.session().get_device()->dev_inst(), context_Trace->get_index(), nameEdit->text().toUtf8().constData()); } nameEdit->hide(); @@ -604,7 +433,7 @@ void Header::on_action_del_group_triggered() _view.session().del_group(); } -void Header::on_signals_moved() +void Header::on_traces_moved() { update(); } @@ -612,9 +441,9 @@ void Header::on_signals_moved() void Header::header_resize() { //if (nameEdit->isVisible()) { - if (_context_signal) { - const int y = _context_signal->get_v_offset() - _view.v_offset() - _view.get_signalHeight() / 2; - nameEdit->move(QPoint(_context_signal->get_leftWidth(), y - nameEdit->height() / 2)); + if (_context_trace) { + const int y = _context_trace->get_y(); + nameEdit->move(QPoint(_context_trace->get_leftWidth(), y - nameEdit->height() / 2)); } } diff --git a/DSLogic-gui/pv/view/header.h b/DSLogic-gui/pv/view/header.h index 3e16f273a67133093b346910c8a3b5b5cc8e7449..4c76f60e64b8f6a3a4127139258ca58d6b41ca65 100644 --- a/DSLogic-gui/pv/view/header.h +++ b/DSLogic-gui/pv/view/header.h @@ -36,7 +36,7 @@ namespace pv { namespace view { -class Signal; +class Trace; class View; class Header : public QWidget @@ -47,7 +47,7 @@ public: Header(View &parent); private: - boost::shared_ptr get_mSig( + boost::shared_ptr get_mTrace( int &action, const QPoint &pt); @@ -62,7 +62,6 @@ private: void wheelEvent(QWheelEvent *event); void contextMenuEvent(QContextMenuEvent *event); - void move(QMouseEvent *event); void changeName(QMouseEvent *event); void changeColor(QMouseEvent *event); @@ -77,13 +76,12 @@ private slots: void on_action_del_group_triggered(); - void on_signals_moved(); + void on_traces_moved(); signals: - void signals_moved(); + void traces_moved(); void header_updated(); void vDial_changed(quint16); - void hDial_changed(quint16); void acdc_changed(quint16); void ch_changed(quint16); @@ -99,10 +97,10 @@ private: QLineEdit *nameEdit; - std::list, int> > - _drag_sigs; + std::list, int> > + _drag_traces; - boost::shared_ptr _context_signal; + boost::shared_ptr _context_trace; QAction *_action_add_group; QAction *_action_del_group; diff --git a/DSLogic-gui/pv/view/logicsignal.cpp b/DSLogic-gui/pv/view/logicsignal.cpp index f9fae1055317968ee267b1d7028da4620b950743..52a454e2e87a8fb896211664157b0521e412f35b 100644 --- a/DSLogic-gui/pv/view/logicsignal.cpp +++ b/DSLogic-gui/pv/view/logicsignal.cpp @@ -29,6 +29,7 @@ #include "view.h" #include "pv/data/logic.h" #include "pv/data/logicsnapshot.h" +#include "view.h" using namespace boost; using namespace std; @@ -65,50 +66,50 @@ const QColor LogicSignal::SignalColours[8] = { const int LogicSignal::StateHeight = 12; const int LogicSignal::StateRound = 5; -LogicSignal::LogicSignal(QString name, boost::shared_ptr data, - int probe_index, int order) : - Signal(name, probe_index, DS_LOGIC, order), - _probe_index(probe_index), - _data(data), - _need_decode(false), - _decoder(NULL) +LogicSignal::LogicSignal(boost::shared_ptr dev_inst, + boost::shared_ptr data, + const sr_channel * const probe) : + Signal(dev_inst, probe, DS_LOGIC), + _data(data) { - assert(_probe_index >= 0); - _colour = SignalColours[_probe_index % countof(SignalColours)]; + assert(probe->index >= 0); + _colour = SignalColours[probe->index % countof(SignalColours)]; } LogicSignal::~LogicSignal() { } -void LogicSignal::set_data(boost::shared_ptr _logic_data, - boost::shared_ptr _dso_data, - boost::shared_ptr _analog_data, - boost::shared_ptr _group_data) +const sr_channel* LogicSignal::probe() const { - (void)_dso_data; - (void)_analog_data; - (void)_group_data; - - assert(_logic_data); + return _probe; +} - if (!_cur_edges.empty()) - _cur_edges.clear(); +shared_ptr LogicSignal::data() const +{ + return _data; +} - _data = _logic_data; +shared_ptr LogicSignal::logic_data() const +{ + return _data; } -void LogicSignal::paint(QPainter &p, int y, int left, int right, - double scale, double offset) +void LogicSignal::paint_mid(QPainter &p, int left, int right) { using pv::view::View; QLineF *line; - assert(scale > 0); assert(_data); + assert(_view); assert(right >= left); + const int y = get_y() + _signalHeight * 0.5; + const double scale = _view->scale(); + assert(scale > 0); + const double offset = _view->offset(); + const float high_offset = y - _signalHeight + 0.5f; const float low_offset = y + 0.5f; @@ -119,8 +120,10 @@ void LogicSignal::paint(QPainter &p, int y, int left, int right, const boost::shared_ptr &snapshot = snapshots.front(); + if (snapshot->buf_null()) + return; - double samplerate = _data->get_samplerate(); + double samplerate = _data->samplerate(); // Show sample rate as 1Hz when it is unknown if (samplerate == 0.0) @@ -136,8 +139,9 @@ void LogicSignal::paint(QPainter &p, int y, int left, int right, snapshot->get_subsampled_edges(_cur_edges, min(max((int64_t)floor(start), (int64_t)0), last_sample), min(max((int64_t)ceil(end), (int64_t)0), last_sample), - samples_per_pixel / Oversampling, _probe_index); - assert(_cur_edges.size() >= 2); + samples_per_pixel / Oversampling, _probe->index); + if (_cur_edges.size() < 2) + return; // Paint the edges const unsigned int edge_count = 2 * _cur_edges.size() - 3; @@ -163,61 +167,6 @@ void LogicSignal::paint(QPainter &p, int y, int left, int right, p.setPen(_colour); p.drawLines(edge_lines, edge_count); delete[] edge_lines; - - if (_need_decode) { - assert(_decoder); - _decoder->get_subsampled_states(_cur_states, - min(max((int64_t)floor(start), (int64_t)0), last_sample), - min(max((int64_t)ceil(end), (int64_t)0), last_sample), - samples_per_pixel); - - const float top_offset = y - (_signalHeight + StateHeight) / 2.0f; - const uint64_t sig_mask = 1ULL << _probe_index; - const uint8_t *const init_ptr = (uint8_t*)snapshot->get_data(); - const uint8_t *src_ptr; - const int unit_size = snapshot->get_unit_size(); - uint64_t value; - uint64_t finalValue = 0; - - if (!_cur_states.empty()) { - _decoder->fill_color_table(_color_table); - _decoder->fill_state_table(_state_table); - - vector::const_iterator i; - for ( i = _cur_states.begin(); i != _cur_states.end(); i++) { - finalValue = 0; - const uint64_t index = (*i).index; - const uint64_t samples = (*i).samples; - const int64_t x = (index / samples_per_pixel - - pixels_offset) + left; - const int64_t width = samples / samples_per_pixel; - - if ((*i).type == decoder::DEC_DATA) { - src_ptr = init_ptr + index * unit_size; - for (uint64_t j = 0; j < samples; j++) { - value = (*(uint64_t*)src_ptr & sig_mask); - if (_probe_index - j > 0) - value = value >> (_probe_index - j); - else - value = value << (j - _probe_index); - finalValue |= value; - src_ptr += unit_size; - } - } - - p.setBrush(_color_table.at((*i).state)); - const QRectF state_rect = QRectF(x, top_offset, width, StateHeight); - p.drawRoundedRect(state_rect, StateRound, StateRound); - p.setPen(Qt::black); - if ((*i).type == decoder::DEC_CMD) - p.drawText(state_rect, Qt::AlignCenter | Qt::AlignVCenter, - _state_table.at((*i).state)); - else if ((*i).type == decoder::DEC_DATA) - p.drawText(state_rect, Qt::AlignCenter | Qt::AlignVCenter, - _state_table.at((*i).state) + "0x" + QString::number(finalValue, 16).toUpper()); - } - } - } } void LogicSignal::paint_caps(QPainter &p, QLineF *const lines, @@ -248,22 +197,80 @@ const std::vector< std::pair > LogicSignal::cur_edges() const return _cur_edges; } -void LogicSignal::set_decoder(pv::decoder::Decoder *decoder) -{ - assert(decoder); - _need_decode = true; - _decoder = decoder; -} - -decoder::Decoder *LogicSignal::get_decoder() -{ - return _decoder; -} - -void LogicSignal::del_decoder() +void LogicSignal::paint_type_options(QPainter &p, int right, bool hover, int action) { - _need_decode = false; - _decoder = NULL; + int y = get_y(); + const QRectF posTrig_rect = get_rect("posTrig", y, right); + const QRectF higTrig_rect = get_rect("higTrig", y, right); + const QRectF negTrig_rect = get_rect("negTrig", y, right); + const QRectF lowTrig_rect = get_rect("lowTrig", y, right); + const QRectF edgeTrig_rect = get_rect("edgeTrig", y, right); + + p.setPen(Qt::transparent); + p.setBrush(((hover && action == POSTRIG) || (_trig == POSTRIG)) ? + dsYellow : + dsBlue); + p.drawRect(posTrig_rect); + p.setBrush(((hover && action == HIGTRIG) || (_trig == HIGTRIG)) ? + dsYellow : + dsBlue); + p.drawRect(higTrig_rect); + p.setBrush(((hover && action == NEGTRIG) || (_trig == NEGTRIG)) ? + dsYellow : + dsBlue); + p.drawRect(negTrig_rect); + p.setBrush(((hover && action == LOWTRIG) || (_trig == LOWTRIG)) ? + dsYellow : + dsBlue); + p.drawRect(lowTrig_rect); + p.setBrush(((hover && action == EDGETRIG) || (_trig == EDGETRIG)) ? + dsYellow : + dsBlue); + p.drawRect(edgeTrig_rect); + + p.setPen(QPen(Qt::blue, 1, Qt::DotLine)); + p.setBrush(Qt::transparent); + p.drawLine(posTrig_rect.right(), posTrig_rect.top() + 3, + posTrig_rect.right(), posTrig_rect.bottom() - 3); + p.drawLine(higTrig_rect.right(), higTrig_rect.top() + 3, + higTrig_rect.right(), higTrig_rect.bottom() - 3); + p.drawLine(negTrig_rect.right(), negTrig_rect.top() + 3, + negTrig_rect.right(), negTrig_rect.bottom() - 3); + p.drawLine(lowTrig_rect.right(), lowTrig_rect.top() + 3, + lowTrig_rect.right(), lowTrig_rect.bottom() - 3); + + p.setPen(QPen(Qt::white, 2, Qt::SolidLine)); + p.setBrush(Qt::transparent); + p.drawLine(posTrig_rect.left() + 5, posTrig_rect.bottom() - 5, + posTrig_rect.center().x(), posTrig_rect.bottom() - 5); + p.drawLine(posTrig_rect.center().x(), posTrig_rect.bottom() - 5, + posTrig_rect.center().x(), posTrig_rect.top() + 5); + p.drawLine(posTrig_rect.center().x(), posTrig_rect.top() + 5, + posTrig_rect.right() - 5, posTrig_rect.top() + 5); + + p.drawLine(higTrig_rect.left() + 5, higTrig_rect.top() + 5, + higTrig_rect.right() - 5, higTrig_rect.top() + 5); + + p.drawLine(negTrig_rect.left() + 5, negTrig_rect.top() + 5, + negTrig_rect.center().x(), negTrig_rect.top() + 5); + p.drawLine(negTrig_rect.center().x(), negTrig_rect.top() + 5, + negTrig_rect.center().x(), negTrig_rect.bottom() - 5); + p.drawLine(negTrig_rect.center().x(), negTrig_rect.bottom() - 5, + negTrig_rect.right() - 5, negTrig_rect.bottom() - 5); + + p.drawLine(lowTrig_rect.left() + 5, lowTrig_rect.bottom() - 5, + lowTrig_rect.right() - 5, lowTrig_rect.bottom() - 5); + + p.drawLine(edgeTrig_rect.left() + 5, edgeTrig_rect.top() + 5, + edgeTrig_rect.center().x() - 2, edgeTrig_rect.top() + 5); + p.drawLine(edgeTrig_rect.center().x() + 2 , edgeTrig_rect.top() + 5, + edgeTrig_rect.right() - 5, edgeTrig_rect.top() + 5); + p.drawLine(edgeTrig_rect.center().x(), edgeTrig_rect.top() + 7, + edgeTrig_rect.center().x(), edgeTrig_rect.bottom() - 7); + p.drawLine(edgeTrig_rect.left() + 5, edgeTrig_rect.bottom() - 5, + edgeTrig_rect.center().x() - 2, edgeTrig_rect.bottom() - 5); + p.drawLine(edgeTrig_rect.center().x() + 2, edgeTrig_rect.bottom() - 5, + edgeTrig_rect.right() - 5, edgeTrig_rect.bottom() - 5); } } // namespace view diff --git a/DSLogic-gui/pv/view/logicsignal.h b/DSLogic-gui/pv/view/logicsignal.h index fa407f2d1558bff3f4912f62eb19ee45d0ecad92..b1e8721a1d7fc7b2907af41c9cdb1540c4dd2025 100644 --- a/DSLogic-gui/pv/view/logicsignal.h +++ b/DSLogic-gui/pv/view/logicsignal.h @@ -25,7 +25,6 @@ #define DSLOGIC_PV_LOGICSIGNAL_H #include "signal.h" -#include "../decoder/decoder.h" #include @@ -55,36 +54,30 @@ private: static const int StateRound; public: - LogicSignal(QString name, - boost::shared_ptr data, - int probe_index, int order); + LogicSignal(boost::shared_ptr dev_inst, + boost::shared_ptr data, + const sr_channel * const probe); virtual ~LogicSignal(); - void set_data(boost::shared_ptr _logic_data, - boost::shared_ptr _dso_data, - boost::shared_ptr _analog_data, - boost::shared_ptr _group_data); + const sr_channel* probe() const; + + boost::shared_ptr data() const; + + boost::shared_ptr logic_data() const; + /** * Paints the signal with a QPainter * @param p the QPainter to paint into. - * @param y the y-coordinate to draw the signal at. * @param left the x-coordinate of the left edge of the signal. * @param right the x-coordinate of the right edge of the signal. - * @param scale the scale in seconds per pixel. - * @param offset the time to show at the left hand edge of - * the view in seconds. **/ - void paint(QPainter &p, int y, int left, int right, double scale, - double offset); + void paint_mid(QPainter &p, int left, int right); const std::vector< std::pair > cur_edges() const; - void set_decoder(pv::decoder::Decoder *decoder); - - pv::decoder::Decoder* get_decoder(); - - void del_decoder(); +protected: + void paint_type_options(QPainter &p, int right, bool hover, int action); private: @@ -94,15 +87,8 @@ private: float x_offset, float y_offset); private: - int _probe_index; boost::shared_ptr _data; std::vector< std::pair > _cur_edges; - - bool _need_decode; - pv::decoder::Decoder * _decoder; - std::vector _cur_states; - std::vector< QColor > _color_table; - std::vector< QString > _state_table; }; } // namespace view diff --git a/DSLogic-gui/pv/view/ruler.cpp b/DSLogic-gui/pv/view/ruler.cpp index f049beb60f9f22dcfc95867f2f5e8fc7f4cd163e..43f40137b2c636f8ec8ace6849ed50f39e6719b5 100644 --- a/DSLogic-gui/pv/view/ruler.cpp +++ b/DSLogic-gui/pv/view/ruler.cpp @@ -27,6 +27,8 @@ #include "view.h" #include "viewport.h" #include "../sigsession.h" +#include "../device/devinst.h" +#include "dsosignal.h" #include @@ -39,6 +41,9 @@ #include #include +#include + +using namespace boost; using namespace std; namespace pv { @@ -63,7 +68,7 @@ const QColor Ruler::CursorColor[8] = QColor(46, 205, 113, 200), QColor(53, 152, 220, 200), QColor(154, 89, 181, 200), - QColor(52, 73, 94 , 200), + QColor(52, 73, 94, 200), QColor(242, 196, 15, 200), QColor(231, 126, 34, 200), QColor(232, 76, 61, 200)}; @@ -405,7 +410,7 @@ void Ruler::draw_logic_tick_mark(QPainter &p) const double MinValueSpacing = 16.0f; const int ValueMargin = 5; - const double abs_min_period = 10.0f / _view.session().get_last_sample_rate(); + const double abs_min_period = 10.0f / _view.session().get_device()->get_sample_rate(); double min_width = SpacingIncrement; double typical_width; @@ -415,7 +420,11 @@ void Ruler::draw_logic_tick_mark(QPainter &p) // Find tick spacing, and number formatting that does not cause // value to collide. - _min_period = cur_period_scale * abs_min_period; + if (_view.session().get_device()->dev_inst()->mode == DSO) { + _min_period = _view.session().get_device()->get_time_base() * pow(10, -9); + } else { + _min_period = cur_period_scale * abs_min_period; + } const int order = (int)floorf(log10f(_min_period)); //const double order_decimal = pow(10, order); const unsigned int prefix = (order - FirstSIPrefixPower) / 3; @@ -459,7 +468,7 @@ void Ruler::draw_logic_tick_mark(QPainter &p) const double inc_text_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, AlignLeft | AlignTop, - format_time(tick_period - minor_tick_period, + format_time(minor_tick_period, minor_prefix)).width() + MinValueSpacing; do { const double t = t0 + division * minor_tick_period; @@ -485,7 +494,7 @@ void Ruler::draw_logic_tick_mark(QPainter &p) AlignCenter | AlignTop | TextDontClip, format_time(t, prefix)); //else if ((tick_period / _view.scale() > width() / 4) && (minor_tick_period / _view.scale() > inc_text_width)) - else if (minor_tick_period / _view.scale() > 1.2 * inc_text_width) + else if (minor_tick_period / _view.scale() > 1.1 * inc_text_width) p.drawText(x, 2 * ValueMargin, 0, minor_tick_y1 + ValueMargin, AlignCenter | AlignTop | TextDontClip, format_time(t - major_t, minor_prefix)); @@ -495,7 +504,7 @@ void Ruler::draw_logic_tick_mark(QPainter &p) division++; - } while (x < width()); + } while (x < _view.get_max_width()); // Draw the cursors if (!_view.get_cursorList().empty()) { @@ -509,10 +518,10 @@ void Ruler::draw_logic_tick_mark(QPainter &p) _view.on_cursor_moved(); } if (_view.trig_cursor_shown()) { - _view.get_trig_cursor()->paint_fix_label(p, rect(), prefix, 'T', Signal::dsLightRed); + _view.get_trig_cursor()->paint_fix_label(p, rect(), prefix, 'T', Trace::dsLightRed); } if (_view.search_cursor_shown()) { - _view.get_search_cursor()->paint_fix_label(p, rect(), prefix, 'S', Signal::dsLightBlue); + _view.get_search_cursor()->paint_fix_label(p, rect(), prefix, 'S', Trace::dsLightBlue); } } diff --git a/DSLogic-gui/pv/view/selectableitem.cpp b/DSLogic-gui/pv/view/selectableitem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e849dba9227e4925eb848a7ece6b08948678c678 --- /dev/null +++ b/DSLogic-gui/pv/view/selectableitem.cpp @@ -0,0 +1,57 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2013 Joel Holdsworth + * Copyright (C) 2014 DreamSourceLab + * + * 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 "selectableitem.h" + +#include +#include +#include + +namespace pv { +namespace view { + +const int SelectableItem::HighlightRadius = 6; + +SelectableItem::SelectableItem() : + _selected(false) +{ +} + +bool SelectableItem::selected() const +{ + return _selected; +} + +void SelectableItem::select(bool select) +{ + _selected = select; +} + +QPen SelectableItem::highlight_pen() +{ + return QPen(QApplication::palette().brush( + QPalette::Highlight), HighlightRadius, + Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); +} + +} // namespace view +} // namespace pv diff --git a/DSLogic-gui/pv/view/selectableitem.h b/DSLogic-gui/pv/view/selectableitem.h new file mode 100644 index 0000000000000000000000000000000000000000..f952f828325694abea674a817c0250da320caa46 --- /dev/null +++ b/DSLogic-gui/pv/view/selectableitem.h @@ -0,0 +1,69 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2013 Joel Holdsworth + * Copyright (C) 2014 DreamSourceLab + * + * 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_SELECTABLEITEM_H +#define DSLOGIC_PV_SELECTABLEITEM_H + +#include + +#include + +class QAction; +class QMenu; +class QWidget; + +namespace pv { + +namespace view { + +class SelectableItem : public QObject +{ + Q_OBJECT + +private: + static const int HighlightRadius; + +public: + SelectableItem(); + +public: + /** + * Returns true if the signal has been selected by the user. + */ + bool selected() const; + + /** + * Selects or deselects the signal. + */ + void select(bool select = true); + +protected: + static QPen highlight_pen(); + +private: + bool _selected; +}; + +} // namespace view +} // namespace pv + +#endif // DSLOGIC_PV_SELECTABLEITEM_H diff --git a/DSLogic-gui/pv/view/signal.cpp b/DSLogic-gui/pv/view/signal.cpp index 11ef3198b1a70b8f916c0147b65eb305d84be521..828e7fc4a6a521989780a751ff89c4d29b15fca8 100644 --- a/DSLogic-gui/pv/view/signal.cpp +++ b/DSLogic-gui/pv/view/signal.cpp @@ -29,673 +29,22 @@ #include "signal.h" #include "view.h" +#include "../device/devinst.h" namespace pv { namespace view { -const QColor Signal::dsBlue = QColor(17, 133, 209, 255); -const QColor Signal::dsYellow = QColor(238, 178, 17, 255); -const QColor Signal::dsRed = QColor(213, 15, 37, 255); -const QColor Signal::dsGreen = QColor(0, 153, 37, 255); -const QColor Signal::dsGray = QColor(0x88, 0x8A, 0x85, 100); -const QColor Signal::dsDisable = QColor(0x88, 0x8A, 0x85, 200); -const QColor Signal::dsActive = QColor(17, 133, 209, 255); -const QColor Signal::dsLightBlue = QColor(17, 133, 209, 150); -const QColor Signal::dsLightRed = QColor(213, 15, 37, 150); -const QPen Signal::SignalAxisPen = QColor(128, 128, 128, 64); - -const quint64 Signal::vDialValue[Signal::vDialValueCount] = { - 5, - 10, - 20, - 50, - 100, - 200, - 500, - 1000, - 2000, - 5000, -}; -const QString Signal::vDialUnit[Signal::vDialUnitCount] = { - "mv", - "v", -}; - -const quint64 Signal::hDialValue[Signal::hDialValueCount] = { - 10, - 20, - 50, - 100, - 200, - 500, - 1000, - 2000, - 5000, - 10000, - 20000, - 50000, - 100000, - 200000, - 500000, - 1000000, - 2000000, - 5000000, - 10000000, - 20000000, - 50000000, - 100000000, - 200000000, - 500000000, - 1000000000, -}; -const QString Signal::hDialUnit[Signal::hDialUnitCount] = { - "ns", - "us", - "ms", - "s", -}; - -Signal::Signal(QString name, int index, int type, int order) : - _type(type), - _order(order), - _sec_index(0), - _name(name), - _v_offset(0), - _signalHeight(30), - _selected(false), - _trig(0), - _vDialActive(false), - _hDialActive(false), - _acCoupling(false), - _active(true), - _windowHeight(0) -{ - _index_list.push_back(index); - if (_type == DS_DSO) { - QVector vValue; - QVector vUnit; - QVector hValue; - QVector hUnit; - for(quint64 i = 0; i < Signal::vDialValueCount; i++) - vValue.append(Signal::vDialValue[i]); - for(quint64 i = 0; i < Signal::vDialUnitCount; i++) - vUnit.append(Signal::vDialUnit[i]); - - for(quint64 i = 0; i < Signal::hDialValueCount; i++) - hValue.append(Signal::hDialValue[i]); - for(quint64 i = 0; i < Signal::hDialUnitCount; i++) - hUnit.append(Signal::hDialUnit[i]); - - _vDial = new dslDial(vDialValueCount, vDialValueStep, vValue, vUnit); - _hDial = new dslDial(hDialValueCount, hDialValueStep, hValue, hUnit); - _vDial->set_sel(0); - _hDial->set_sel(0); - - _trig_vpos = 0; - _trig_en = true; - } -} - -Signal::Signal(QString name, std::list index_list, int type, int order, int sec_index) : - _type(type), - _index_list(index_list), - _order(order), - _sec_index(sec_index), - _name(name), - _v_offset(0), - _signalHeight(30), - _selected(false), - _trig(0), - _vDialActive(false), - _hDialActive(false), - _acCoupling(false), - _active(true) -{ - if (_type == DS_DSO) { - QVector vValue; - QVector vUnit; - QVector hValue; - QVector hUnit; - for(quint64 i = 0; i < Signal::vDialValueCount; i++) - vValue.append(Signal::vDialValue[i]); - for(quint64 i = 0; i < Signal::vDialUnitCount; i++) - vUnit.append(Signal::vDialUnit[i]); - - for(quint64 i = 0; i < Signal::hDialValueCount; i++) - hValue.append(Signal::hDialValue[i]); - for(quint64 i = 0; i < Signal::hDialUnitCount; i++) - hUnit.append(Signal::hDialUnit[i]); - - _vDial = new dslDial(Signal::vDialValueCount, Signal::vDialValueStep, vValue, vUnit); - _hDial = new dslDial(Signal::hDialValueCount, Signal::hDialValueStep, hValue, hUnit); - _vDial->set_sel(0); - _hDial->set_sel(0); - } -} - -int Signal::get_type() const -{ - return _type; -} - -int Signal::get_order() const -{ - return _order; -} - -void Signal::set_order(int order) -{ - assert(order >= 0); - - _order = order; -} - -int Signal::get_leftWidth() const -{ - return SquareWidth + Margin; -} - -int Signal::get_rightWidth() const -{ - return 2 * Margin + SquareNum * SquareWidth + 1.5 * SquareWidth; -} - -int Signal::get_headerHeight() const -{ - return SquareWidth; -} - -int Signal::get_index() const -{ - return _index_list.front(); -} - -std::list &Signal::get_index_list() -{ - return _index_list; -} - -void Signal::set_index_list(std::list index_list) -{ - assert(index_list.size() != 0); - - _index_list = index_list; -} - -int Signal::get_sec_index() const -{ - return _sec_index; -} - -void Signal::set_sec_index(int sec_index) -{ - _sec_index = sec_index; -} - -QString Signal::get_name() const +Signal::Signal(boost::shared_ptr dev_inst, + const sr_channel *const probe, int type) : + Trace(probe->name, probe->index, type), + _dev_inst(dev_inst), + _probe(probe) { - return _name; } -void Signal::set_name(QString name) +bool Signal::enabled() const { - _name = name; -} - -QColor Signal::get_colour() const -{ - return _colour; -} - -void Signal::set_colour(QColor colour) -{ - _colour = colour; -} - -int Signal::get_v_offset() const -{ - return _v_offset; -} - -void Signal::set_v_offset(int v_offset) -{ - _v_offset = v_offset; -} - -int Signal::get_old_v_offset() const -{ - return _old_v_offset; -} - -void Signal::set_old_v_offset(int v_offset) -{ - _old_v_offset = v_offset; -} - -int Signal::get_signalHeight() const -{ - return _signalHeight; -} - -void Signal::set_signalHeight(int height) -{ - _signalHeight = height; -} - -bool Signal::selected() const -{ - return _selected; -} - -void Signal::select(bool select) -{ - _selected = select; -} - -int Signal::get_trig() const -{ - return _trig; -} - -void Signal::set_trig(int trig) -{ - _trig = trig; - if (trig == 0) - ds_trigger_probe_set(_index_list.front(), 'X', 'X'); - else if (trig == POSTRIG) - ds_trigger_probe_set(_index_list.front(), 'R', 'X'); - else if (trig == HIGTRIG) - ds_trigger_probe_set(_index_list.front(), '1', 'X'); - else if (trig == NEGTRIG) - ds_trigger_probe_set(_index_list.front(), 'F', 'X'); - else if (trig == LOWTRIG) - ds_trigger_probe_set(_index_list.front(), '0', 'X'); - else if (trig == EDGETRIG) - ds_trigger_probe_set(_index_list.front(), 'C', 'X'); -} - -bool Signal::get_vDialActive() const -{ - return _vDialActive; -} - -void Signal::set_vDialActive(bool active) -{ - _vDialActive = active; -} - -bool Signal::go_vDialPre() -{ - assert(_type == DS_DSO); - - if (!_vDial->isMin()) { - _vDial->set_sel(_vDial->get_sel() - 1); - return true; - } else { - return false; - } -} - -bool Signal::go_vDialNext() -{ - assert(_type == DS_DSO); - - if (!_vDial->isMax()) { - _vDial->set_sel(_vDial->get_sel() + 1); - return true; - } else { - return false; - } -} - -bool Signal::get_hDialActive() const -{ - return _hDialActive; -} - -void Signal::set_hDialActive(bool active) -{ - _hDialActive = active; -} - -bool Signal::go_hDialPre() -{ - assert(_type == DS_DSO); - - if (!_hDial->isMin()) { - _hDial->set_sel(_hDial->get_sel() - 1); - return true; - } else { - return false; - } -} - -bool Signal::go_hDialNext() -{ - assert(_type == DS_DSO); - - if (!_hDial->isMax()) { - _hDial->set_sel(_hDial->get_sel() + 1); - return true; - } else { - return false; - } -} - -quint64 Signal::get_vDialValue() const -{ - return _vDial->get_value(); -} - -quint64 Signal::get_hDialValue() const -{ - return _hDial->get_value(); -} - -uint16_t Signal::get_vDialSel() const -{ - return _vDial->get_sel(); -} - -uint16_t Signal::get_hDialSel() const -{ - return _hDial->get_sel(); -} - -bool Signal::get_acCoupling() const -{ - return _acCoupling; -} - -void Signal::set_acCoupling(bool coupling) -{ - _acCoupling = coupling; -} - -bool Signal::get_active() const -{ - return _active; -} - -void Signal::set_active(bool active) -{ - _active = active; -} - -int Signal::get_zeroPos() const -{ - return _zeroPos; -} - -void Signal::set_zeroPos(int pos) -{ - _zeroPos = pos; -} - -int Signal::get_windowHeight() const -{ - return _windowHeight; -} - -void Signal::set_windowHeight(int height) -{ - _windowHeight = height; -} - -int Signal::get_trig_vpos() const -{ - return _trig_vpos; -} - -void Signal::set_trig_vpos(int value) -{ - _trig_vpos = value; -} - -void Signal::paint_label(QPainter &p, int y, int right, bool hover, int action) -{ - compute_text_size(p); - - const QRectF color_rect = get_rect("color", y, right); - const QRectF name_rect = get_rect("name", y, right); - const QRectF label_rect = get_rect("label", (_type == DS_DSO) ? _zeroPos : y, right); - - p.setRenderHint(QPainter::Antialiasing); - // Paint the ColorButton - p.setPen(Qt::transparent); - p.setBrush(_active ? _colour : dsDisable); - p.drawRect(color_rect); - - // Paint the signal name - p.setPen(_active ? Qt::black : dsDisable); - p.drawText(name_rect, Qt::AlignLeft | Qt::AlignVCenter, _name); - - // Paint the trigButton - if (_type == DS_LOGIC) { - const QRectF posTrig_rect = get_rect("posTrig", y, right); - const QRectF higTrig_rect = get_rect("higTrig", y, right); - const QRectF negTrig_rect = get_rect("negTrig", y, right); - const QRectF lowTrig_rect = get_rect("lowTrig", y, right); - const QRectF edgeTrig_rect = get_rect("edgeTrig", y, right); - - p.setPen(Qt::transparent); - p.setBrush(((hover && action == POSTRIG) || (_trig == POSTRIG)) ? - dsYellow : - dsBlue); - p.drawRect(posTrig_rect); - p.setBrush(((hover && action == HIGTRIG) || (_trig == HIGTRIG)) ? - dsYellow : - dsBlue); - p.drawRect(higTrig_rect); - p.setBrush(((hover && action == NEGTRIG) || (_trig == NEGTRIG)) ? - dsYellow : - dsBlue); - p.drawRect(negTrig_rect); - p.setBrush(((hover && action == LOWTRIG) || (_trig == LOWTRIG)) ? - dsYellow : - dsBlue); - p.drawRect(lowTrig_rect); - p.setBrush(((hover && action == EDGETRIG) || (_trig == EDGETRIG)) ? - dsYellow : - dsBlue); - p.drawRect(edgeTrig_rect); - - p.setPen(QPen(Qt::blue, 1, Qt::DotLine)); - p.setBrush(Qt::transparent); - p.drawLine(posTrig_rect.right(), posTrig_rect.top() + 3, - posTrig_rect.right(), posTrig_rect.bottom() - 3); - p.drawLine(higTrig_rect.right(), higTrig_rect.top() + 3, - higTrig_rect.right(), higTrig_rect.bottom() - 3); - p.drawLine(negTrig_rect.right(), negTrig_rect.top() + 3, - negTrig_rect.right(), negTrig_rect.bottom() - 3); - p.drawLine(lowTrig_rect.right(), lowTrig_rect.top() + 3, - lowTrig_rect.right(), lowTrig_rect.bottom() - 3); - - p.setPen(QPen(Qt::white, 2, Qt::SolidLine)); - p.setBrush(Qt::transparent); - p.drawLine(posTrig_rect.left() + 5, posTrig_rect.bottom() - 5, - posTrig_rect.center().x(), posTrig_rect.bottom() - 5); - p.drawLine(posTrig_rect.center().x(), posTrig_rect.bottom() - 5, - posTrig_rect.center().x(), posTrig_rect.top() + 5); - p.drawLine(posTrig_rect.center().x(), posTrig_rect.top() + 5, - posTrig_rect.right() - 5, posTrig_rect.top() + 5); - - p.drawLine(higTrig_rect.left() + 5, higTrig_rect.top() + 5, - higTrig_rect.right() - 5, higTrig_rect.top() + 5); - - p.drawLine(negTrig_rect.left() + 5, negTrig_rect.top() + 5, - negTrig_rect.center().x(), negTrig_rect.top() + 5); - p.drawLine(negTrig_rect.center().x(), negTrig_rect.top() + 5, - negTrig_rect.center().x(), negTrig_rect.bottom() - 5); - p.drawLine(negTrig_rect.center().x(), negTrig_rect.bottom() - 5, - negTrig_rect.right() - 5, negTrig_rect.bottom() - 5); - - p.drawLine(lowTrig_rect.left() + 5, lowTrig_rect.bottom() - 5, - lowTrig_rect.right() - 5, lowTrig_rect.bottom() - 5); - - p.drawLine(edgeTrig_rect.left() + 5, edgeTrig_rect.top() + 5, - edgeTrig_rect.center().x() - 2, edgeTrig_rect.top() + 5); - p.drawLine(edgeTrig_rect.center().x() + 2 , edgeTrig_rect.top() + 5, - edgeTrig_rect.right() - 5, edgeTrig_rect.top() + 5); - p.drawLine(edgeTrig_rect.center().x(), edgeTrig_rect.top() + 7, - edgeTrig_rect.center().x(), edgeTrig_rect.bottom() - 7); - p.drawLine(edgeTrig_rect.left() + 5, edgeTrig_rect.bottom() - 5, - edgeTrig_rect.center().x() - 2, edgeTrig_rect.bottom() - 5); - p.drawLine(edgeTrig_rect.center().x() + 2, edgeTrig_rect.bottom() - 5, - edgeTrig_rect.right() - 5, edgeTrig_rect.bottom() - 5); - } else if (_type == DS_GROUP || _type == DS_PROTOCOL) { - const QRectF group_index_rect = get_rect("groupIndex", y, right); - QString index_string; - int last_index; - p.setPen(Qt::transparent); - p.setBrush(dsBlue); - p.drawRect(group_index_rect); - std::list::iterator i = _index_list.begin(); - last_index = (*i); - index_string = QString::number(last_index); - while (++i != _index_list.end()) { - if ((*i) == last_index + 1 && index_string.indexOf("-") < 3 && index_string.indexOf("-") > 0) - index_string.replace(QString::number(last_index), QString::number((*i))); - else if ((*i) == last_index + 1) - index_string = QString::number((*i)) + "-" + index_string; - else - index_string = QString::number((*i)) + "," + index_string; - last_index = (*i); - } - p.setPen(Qt::white); - p.drawText(group_index_rect, Qt::AlignRight | Qt::AlignVCenter, index_string); - } else if (_type == DS_DSO) { - const QRectF vDial_rect = get_rect("vDial", y, right); - const QRectF hDial_rect = get_rect("hDial", y, right); - const QRectF acdc_rect = get_rect("acdc", y, right); - const QRectF chEn_rect = get_rect("chEn", y, right); - - QColor vDial_color = _vDialActive ? dsActive : dsDisable; - QColor hDial_color = _hDialActive ? dsActive : dsDisable; - _vDial->paint(p, vDial_rect, vDial_color); - _hDial->paint(p, hDial_rect, hDial_color); - - p.setPen(Qt::transparent); - p.setBrush((hover && action == CHEN) ? _colour.darker() : _colour); - p.drawRect(chEn_rect); - p.setPen(Qt::white); - p.drawText(chEn_rect, Qt::AlignCenter | Qt::AlignVCenter, _active ? "EN" : "DIS"); - - p.setPen(Qt::transparent); - p.setBrush(_active ? ((hover && action == ACDC) ? _colour.darker() : _colour) : dsDisable); - p.drawRect(acdc_rect); - p.setPen(Qt::white); - p.drawText(acdc_rect, Qt::AlignCenter | Qt::AlignVCenter, _acCoupling ? "AC" : "DC"); - } - - // Paint the label - if (_active) { - const QPointF points[] = { - label_rect.topLeft(), - label_rect.topRight(), - QPointF(right, (_type == DS_DSO) ? _zeroPos : y), - label_rect.bottomRight(), - label_rect.bottomLeft() - }; - - p.setPen(Qt::transparent); - if (_type == DS_DSO) - p.setBrush(((hover && action == LABEL) || _selected) ? _colour.darker() : _colour); - else - p.setBrush(((hover && action == LABEL) || _selected) ? dsYellow : dsBlue); - p.drawPolygon(points, countof(points)); - - p.setPen(QPen(Qt::blue, 1, Qt::DotLine)); - p.setBrush(Qt::transparent); - p.drawLine(label_rect.right(), label_rect.top() + 3, - label_rect.right(), label_rect.bottom() - 3); - - // Paint the text - p.setPen(Qt::white); - if (_type == DS_GROUP) - p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "G"); - else if (_type == DS_ANALOG) - p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "A"); - else if (_type == DS_PROTOCOL) - p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "D"); - else - p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, QString::number(_index_list.front())); - } -} - -void Signal::paint_trig(QPainter &p, int left, int right, bool hover) -{ - if (_type == DS_DSO) { - const QRectF label_rect = get_rect("dsoTrig", -1, right); - // Paint the trig line - if (_trig_en) { - const QPointF points[] = { - QPointF(right - label_rect.width()*1.5, _trig_vpos), - label_rect.topLeft(), - label_rect.topRight(), - label_rect.bottomRight(), - label_rect.bottomLeft() - }; - - p.setPen(Qt::transparent); - p.setBrush(_colour); - p.drawPolygon(points, countof(points)); - - // paint the _trig_vpos line - p.setPen(QPen(_colour, hover ? 2 : 1, Qt::DashLine)); - p.drawLine(left, _trig_vpos, right - label_rect.width()*1.5, _trig_vpos); - - // Paint the text - p.setPen(Qt::white); - p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "T"); - } - } -} - -int Signal::pt_in_rect(int y, int right, const QPoint &point) -{ - const QRectF color = get_rect("color", y, right); - const QRectF name = get_rect("name", y, right); - const QRectF posTrig = get_rect("posTrig", y, right); - const QRectF higTrig = get_rect("higTrig", y, right); - const QRectF negTrig = get_rect("negTrig", y, right); - const QRectF lowTrig = get_rect("lowTrig", y, right); - const QRectF edgeTrig = get_rect("edgeTrig", y, right); - const QRectF label = get_rect("label", (_type == DS_DSO) ? _zeroPos : y, right); - const QRectF vDial = get_rect("vDial", y, right); - const QRectF hDial = get_rect("hDial", y, right); - const QRectF chEn = get_rect("chEn", y, right); - const QRectF acdc = get_rect("acdc", y, right); - const QRectF dsoTrig = get_rect("dsoTrig", 0, right); - - if (color.contains(point) && _active) - return COLOR; - else if (name.contains(point) && _active) - return NAME; - else if (posTrig.contains(point) && _type == DS_LOGIC) - return POSTRIG; - else if (higTrig.contains(point) && _type == DS_LOGIC) - return HIGTRIG; - else if (negTrig.contains(point) && _type == DS_LOGIC) - return NEGTRIG; - else if (lowTrig.contains(point) && _type == DS_LOGIC) - return LOWTRIG; - else if (edgeTrig.contains(point) && _type == DS_LOGIC) - return EDGETRIG; - else if (label.contains(point) && _active) - return LABEL; - else if (vDial.contains(point) && _type == DS_DSO && _active) - return VDIAL; - else if (hDial.contains(point) && _type == DS_DSO && _active) - return HDIAL; - else if (chEn.contains(point) && _type == DS_DSO) - return CHEN; - else if (acdc.contains(point) && _type == DS_DSO && _active) - return ACDC; - else if (dsoTrig.contains(point) && _type == DS_DSO && _active) - return DSOTRIG; - else - return 0; + return _probe->enabled; } void Signal::paint_axis(QPainter &p, int y, int left, int right) @@ -704,91 +53,5 @@ void Signal::paint_axis(QPainter &p, int y, int left, int right) p.drawLine(QPointF(left, y + 0.5f), QPointF(right, y + 0.5f)); } -void Signal::compute_text_size(QPainter &p) -{ - _text_size = QSize( - p.boundingRect(QRectF(), 0, "99").width(), - p.boundingRect(QRectF(), 0, "99").height()); -} - -QRectF Signal::get_rect(const char *s, int y, int right) -{ - const QSizeF color_size(SquareWidth, SquareWidth); - const QSizeF name_size(right - get_leftWidth() - get_rightWidth(), SquareWidth); - //const QSizeF label_size(_text_size.width() + Margin, SquareWidth); - const QSizeF label_size(SquareWidth, SquareWidth); - - if (!strcmp(s, "name")) - return QRectF( - get_leftWidth(), - y - name_size.height() / 2, - name_size.width(), name_size.height()); - else if (!strcmp(s, "label")) - return QRectF( - right - 1.5f * label_size.width(), - y - SquareWidth / 2, - label_size.width(), label_size.height()); - else if (!strcmp(s, "posTrig")) - return QRectF( - get_leftWidth() + name_size.width() + Margin, - y - SquareWidth / 2, - SquareWidth, SquareWidth); - else if (!strcmp(s, "higTrig")) - return QRectF( - get_leftWidth() + name_size.width() + SquareWidth + Margin, - y - SquareWidth / 2, - SquareWidth, SquareWidth); - else if (!strcmp(s, "negTrig")) - return QRectF( - get_leftWidth() + name_size.width() + 2 * SquareWidth + Margin, - y - SquareWidth / 2, - SquareWidth, SquareWidth); - else if (!strcmp(s, "lowTrig")) - return QRectF( - get_leftWidth() + name_size.width() + 3 * SquareWidth + Margin, - y - SquareWidth / 2, - SquareWidth, SquareWidth); - else if (!strcmp(s, "edgeTrig")) - return QRectF( - get_leftWidth() + name_size.width() + 4 * SquareWidth + Margin, - y - SquareWidth / 2, - SquareWidth, SquareWidth); - else if (!strcmp(s, "groupIndex")) - return QRectF( - get_leftWidth() + name_size.width() + Margin, - y - SquareWidth / 2, - SquareWidth * SquareNum, SquareWidth); - else if (!strcmp(s, "vDial")) - return QRectF( - get_leftWidth() + name_size.width() + SquareWidth*0.5 + Margin, - y - SquareWidth * SquareNum, - SquareWidth * (SquareNum-1), SquareWidth * (SquareNum-1)); - else if (!strcmp(s, "hDial")) - return QRectF( - get_leftWidth() + name_size.width() + SquareWidth*0.5 + Margin, - y + SquareWidth * 1.5, - SquareWidth * (SquareNum-1), SquareWidth * (SquareNum-1)); - else if (!strcmp(s, "chEn")) - return QRectF( - get_leftWidth() + name_size.width() + SquareWidth*0.75 + Margin, - y - SquareWidth / 2, - SquareWidth * 1.5, SquareWidth); - else if (!strcmp(s, "acdc")) - return QRectF( - get_leftWidth() + name_size.width() + SquareWidth*2.75 + Margin, - y - SquareWidth / 2, - SquareWidth * 1.5, SquareWidth); - else if (!strcmp(s, "dsoTrig")) - return QRectF( - right - label_size.width(), - _trig_vpos - SquareWidth / 2, - label_size.width(), label_size.height()); - else - return QRectF( - 2, - y - SquareWidth / 2, - SquareWidth, SquareWidth); -} - } // namespace view } // namespace pv diff --git a/DSLogic-gui/pv/view/signal.h b/DSLogic-gui/pv/view/signal.h index 842031442b7207b5c7feb7739c7e9952aa52605a..9f7cd981a3e421e1809ae9753395b3cdba7dbb6a 100644 --- a/DSLogic-gui/pv/view/signal.h +++ b/DSLogic-gui/pv/view/signal.h @@ -36,251 +36,48 @@ #include #include "libsigrok4DSLogic/libsigrok.h" -#include "dsldial.h" +#include "trace.h" namespace pv { namespace data { class SignalData; -class Logic; -class Dso; -class Analog; -class Group; } -namespace decoder { -class Decoder; +namespace device { +class DevInst; } namespace view { -class Signal +class Signal : public Trace { private: - static const int SquareWidth = 20; - static const int Margin = 3; - static const int SquareNum = 5; - static const quint64 vDialValueCount = 10; - static const quint64 vDialValueStep = 1000; - static const quint64 vDialUnitCount = 2; - static const quint64 hDialValueCount = 25; - static const quint64 hDialValueStep = 1000; - static const quint64 hDialUnitCount = 4; - static const quint64 vDialValue[vDialValueCount]; - static const QString vDialUnit[vDialUnitCount]; - - static const quint64 hDialValue[hDialValueCount]; - static const QString hDialUnit[hDialUnitCount]; - -public: - static const int COLOR = 1; - static const int NAME = 2; - static const int POSTRIG = 3; - static const int HIGTRIG = 4; - static const int NEGTRIG = 5; - static const int LOWTRIG = 6; - static const int EDGETRIG = 7; - static const int LABEL = 8; - static const int VDIAL = 9; - static const int HDIAL = 10; - static const int CHEN = 11; - static const int ACDC = 12; - static const int DSOTRIG = 13; - - static const QColor dsBlue; - static const QColor dsYellow; - static const QColor dsRed; - static const QColor dsGreen; - static const QColor dsGray; - static const QColor dsDisable; - static const QColor dsActive; - static const QColor dsLightBlue; - static const QColor dsLightRed; - static const QPen SignalAxisPen; - - enum {DS_LOGIC = 0, DS_ANALOG, DS_GROUP, DS_PROTOCOL, DS_DSO}; protected: - Signal(QString name, int index, int type, int order); - Signal(QString name, std::list index_list, int type, int order, int sec_index); + Signal(boost::shared_ptr dev_inst, + const sr_channel * const probe, int type); public: - int get_type() const; - int get_order() const; - void set_order(int order); - - /** - * Gets the header area size - */ - int get_leftWidth() const; - int get_rightWidth() const; - int get_headerHeight() const; - int get_index() const; - std::list &get_index_list(); - void set_index_list(std::list index_list); - int get_sec_index() const; - void set_sec_index(int sec_index); - - /** - * Gets the name of this signal. - */ - QString get_name() const; - - /** - * Sets the name of the signal. - */ - void set_name(QString name); - - /** - * Get the colour of the signal. - */ - QColor get_colour() const; - - /** - * Set the colour of the signal. - */ - void set_colour(QColor colour); - - /** - * Gets the vertical layout offset of this signal. - */ - int get_v_offset() const; - - /** - * Sets the vertical layout offset of this signal. - */ - void set_v_offset(int v_offset); - - /** - * Gets the height of this signal. - */ - int get_signalHeight() const; - - /** - * Sets the height of this signal. - */ - void set_signalHeight(int height); + virtual boost::shared_ptr data() const = 0; - /** - * Gets the old vertical layout offset of this signal. - */ - int get_old_v_offset() const; + virtual const std::vector< std::pair > cur_edges() const = 0; /** - * Sets the old vertical layout offset of this signal. + * Returns true if the trace is visible and enabled. */ - void set_old_v_offset(int v_offset); - - /** - * Returns true if the signal has been selected by the user. - */ - bool selected() const; - - /** - * Selects or deselects the signal. - */ - void select(bool select = true); - - /* - * - */ - int get_trig() const; - void set_trig(int trig); - - /* - * - */ - bool get_vDialActive() const; - void set_vDialActive(bool active); - bool get_hDialActive() const; - void set_hDialActive(bool active); - bool go_vDialPre(); - bool go_vDialNext(); - bool go_hDialPre(); - bool go_hDialNext(); - quint64 get_vDialValue() const; - quint64 get_hDialValue() const; - uint16_t get_vDialSel() const; - uint16_t get_hDialSel() const; - bool get_acCoupling() const; - void set_acCoupling(bool coupling); - bool get_active() const; - void set_active(bool active); - int get_zeroPos() const; - void set_zeroPos(int pos); - int get_windowHeight() const; - void set_windowHeight(int height); - void set_trig_vpos(int value); - int get_trig_vpos() const; - - /** - * Paints the signal with a QPainter - * @param p the QPainter to paint into. - * @param y the y-coordinate to draw the signal at - * @param left the x-coordinate of the left edge of the signal - * @param right the x-coordinate of the right edge of the signal - * @param scale the scale in seconds per pixel. - * @param offset the time to show at the left hand edge of - * the view in seconds. - **/ - virtual void paint(QPainter &p, int y, int left, int right, - double scale, double offset) = 0; - - virtual const std::vector< std::pair > cur_edges() const = 0; - - virtual void set_decoder(pv::decoder::Decoder *decoder) = 0; - - virtual pv::decoder::Decoder* get_decoder() = 0; - - virtual void del_decoder() = 0; - - virtual void set_data(boost::shared_ptr _logic_data, - boost::shared_ptr _dso_data, - boost::shared_ptr _analog_data, - boost::shared_ptr _group_data) = 0; + bool enabled() const; /** * Paints the signal label into a QGLWidget. * @param p the QPainter to paint into. - * @param y the y-coordinate of the signal. * @param right the x-coordinate of the right edge of the header * area. * @param hover true if the label is being hovered over by the mouse. + * @param action mouse position for hover */ - virtual void paint_label(QPainter &p, int y, int right, - bool hover, int action); - - virtual void paint_trig(QPainter &p, int left, int right, - bool hover); - - /** - * Determines if a point is in the header rect. - * 1 - in color rect - * 2 - in name rect - * 3 - in posTrig rect - * 4 - in higTrig rect - * 5 - in negTrig rect - * 6 - in lowTrig rect - * 7 - in label rect - * 0 - not - * @param y the y-coordinate of the signal. - * @param right the x-coordinate of the right edge of the header - * area. - * @param point the point to test. - */ - int pt_in_rect(int y, int right, - const QPoint &point); - - /** - * Computes the outline rectangle of a label. - * @param p the QPainter to lay out text with. - * @param y the y-coordinate of the signal. - * @param right the x-coordinate of the right edge of the header - * area. - * @return Returns the rectangle of the signal label. - */ - QRectF get_rect(const char *s, int y, int right); + //virtual void paint_label(QPainter &p, int right, bool hover, int action); protected: @@ -293,41 +90,9 @@ protected: */ void paint_axis(QPainter &p, int y, int left, int right); -private: - - /** - * Computes an caches the size of the label text. - */ - void compute_text_size(QPainter &p); - protected: - int _type; - std::list _index_list; - int _order; - int _sec_index; - QString _name; - QColor _colour; - int _v_offset; - int _old_v_offset; - - int _signalHeight; - - bool _selected; - - int _trig; - - QSizeF _text_size; - dslDial *_vDial; - dslDial *_hDial; - bool _vDialActive; - bool _hDialActive; - bool _acCoupling; - bool _active; - int _zeroPos; - int _windowHeight; - - int _trig_vpos; - bool _trig_en; + boost::shared_ptr _dev_inst; + const sr_channel *const _probe; }; } // namespace view diff --git a/DSLogic-gui/pv/view/trace.cpp b/DSLogic-gui/pv/view/trace.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5175f0485bf1d9a69a5d6e92679f41d94503d643 --- /dev/null +++ b/DSLogic-gui/pv/view/trace.cpp @@ -0,0 +1,474 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2013 Joel Holdsworth + * Copyright (C) 2014 DreamSourceLab + * + * 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 + +#include +#include + +#include +#include +#include + +#include "trace.h" +#include "view.h" +#include "../device/devinst.h" +#include "../sigsession.h" + +namespace pv { +namespace view { + +const QColor Trace::dsBlue = QColor(17, 133, 209, 255); +const QColor Trace::dsYellow = QColor(238, 178, 17, 255); +const QColor Trace::dsRed = QColor(213, 15, 37, 255); +const QColor Trace::dsGreen = QColor(0, 153, 37, 200); +const QColor Trace::dsGray = QColor(0x88, 0x8A, 0x85, 60); +const QColor Trace::dsFore = QColor(0xff, 0xff, 0xff, 255); +const QColor Trace::dsBack = QColor(0x16, 0x18, 0x23, 255); +const QColor Trace::dsDisable = QColor(0x88, 0x8A, 0x85, 200); +const QColor Trace::dsActive = QColor(17, 133, 209, 255); +const QColor Trace::dsLightBlue = QColor(17, 133, 209, 150); +const QColor Trace::dsLightRed = QColor(213, 15, 37, 150); +const QPen Trace::SignalAxisPen = QColor(128, 128, 128, 64); + +const QPen Trace::AxisPen(QColor(128, 128, 128, 64)); +const int Trace::LabelHitPadding = 2; + +Trace::Trace(QString name, int type) : + _name(name), + _v_offset(0), + _type(type), + _sec_index(0), + _signalHeight(30), + _trig(0) +{ +} + +Trace::Trace(QString name, int index, int type) : + _name(name), + _v_offset(0), + _type(type), + _sec_index(0), + _signalHeight(30), + _trig(0) +{ + _index_list.push_back(index); +} + +Trace::Trace(QString name, std::list index_list, int type, int sec_index) : + _name(name), + _v_offset(0), + _type(type), + _index_list(index_list), + _sec_index(sec_index), + _signalHeight(30), + _trig(0) +{ +} + +QString Trace::get_name() const +{ + return _name; +} + +void Trace::set_name(QString name) +{ + _name = name; +} + +QColor Trace::get_colour() const +{ + return _colour; +} + +void Trace::set_colour(QColor colour) +{ + _colour = colour; +} + +int Trace::get_v_offset() const +{ + return _v_offset; +} + +void Trace::set_v_offset(int v_offset) +{ + _v_offset = v_offset; +} + + +int Trace::get_type() const +{ + return _type; +} + +int Trace::get_index() const +{ + return _index_list.front(); +} + +std::list &Trace::get_index_list() +{ + return _index_list; +} + +void Trace::set_index_list(std::list index_list) +{ + assert(index_list.size() != 0); + + _index_list = index_list; +} + +int Trace::get_sec_index() const +{ + return _sec_index; +} + +void Trace::set_sec_index(int sec_index) +{ + _sec_index = sec_index; +} + +int Trace::get_old_v_offset() const +{ + return _old_v_offset; +} + +void Trace::set_old_v_offset(int v_offset) +{ + _old_v_offset = v_offset; +} + +int Trace::get_zeroPos() +{ + return _v_offset - _view->v_offset(); +} + +int Trace::get_signalHeight() const +{ + return _signalHeight; +} + +void Trace::set_signalHeight(int height) +{ + _signalHeight = height; +} + +int Trace::get_trig() const +{ + return _trig; +} + +void Trace::set_trig(int trig) +{ + _trig = trig; + if (trig == 0) + ds_trigger_probe_set(_index_list.front(), 'X', 'X'); + else if (trig == POSTRIG) + ds_trigger_probe_set(_index_list.front(), 'R', 'X'); + else if (trig == HIGTRIG) + ds_trigger_probe_set(_index_list.front(), '1', 'X'); + else if (trig == NEGTRIG) + ds_trigger_probe_set(_index_list.front(), 'F', 'X'); + else if (trig == LOWTRIG) + ds_trigger_probe_set(_index_list.front(), '0', 'X'); + else if (trig == EDGETRIG) + ds_trigger_probe_set(_index_list.front(), 'C', 'X'); +} + +void Trace::set_view(pv::view::View *view) +{ + assert(view); + _view = view; +} + +void Trace::paint_back(QPainter &p, int left, int right) +{ + QPen pen(Signal::dsGray); + pen.setStyle(Qt::DotLine); + p.setPen(pen); + const double sigY = get_y(); + p.drawLine(left, sigY, right, sigY); +} + +void Trace::paint_mid(QPainter &p, int left, int right) +{ + (void)p; + (void)left; + (void)right; +} + +void Trace::paint_fore(QPainter &p, int left, int right) +{ + (void)p; + (void)left; + (void)right; +} + +void Trace::paint_label(QPainter &p, int right, bool hover, int action) +{ + compute_text_size(p); + const int y = get_y(); + + const QRectF color_rect = get_rect("color", y, right); + const QRectF name_rect = get_rect("name", y, right); + const QRectF label_rect = get_rect("label", get_zeroPos(), right); + + p.setRenderHint(QPainter::Antialiasing); + // Paint the ColorButton + p.setPen(Qt::transparent); + p.setBrush(enabled() ? _colour : dsDisable); + p.drawRect(color_rect); + + // Paint the signal name + p.setPen(enabled() ? Qt::black : dsDisable); + p.drawText(name_rect, Qt::AlignLeft | Qt::AlignVCenter, _name); + + // Paint the trigButton + paint_type_options(p, right, hover, action); + + // Paint the label + if (enabled()) { + const QPointF points[] = { + label_rect.topLeft(), + label_rect.topRight(), + QPointF(right, get_zeroPos()), + label_rect.bottomRight(), + label_rect.bottomLeft() + }; + + p.setPen(Qt::transparent); + if (_type == DS_DSO) + p.setBrush(((hover && action == LABEL) || selected()) ? _colour.darker() : _colour); + else + p.setBrush(((hover && action == LABEL) || selected()) ? dsYellow : dsBlue); + p.drawPolygon(points, countof(points)); + + p.setPen(QPen(Qt::blue, 1, Qt::DotLine)); + p.setBrush(Qt::transparent); + p.drawLine(label_rect.right(), label_rect.top() + 3, + label_rect.right(), label_rect.bottom() - 3); + + // Paint the text + p.setPen(Qt::white); + if (_type == DS_GROUP) + p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "G"); + else if (_type == DS_ANALOG) + p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "A"); + else if (_type == DS_DECODER) + p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "D"); + else + p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, QString::number(_index_list.front())); + } +} + +void Trace::paint_type_options(QPainter &p, int right, bool hover, int action) +{ + (void)p; + (void)right; + (void)hover; + (void)action; +} + +int Trace::pt_in_rect(int y, int right, const QPoint &point) +{ + const QRectF color = get_rect("color", y, right); + const QRectF name = get_rect("name", y, right); + const QRectF posTrig = get_rect("posTrig", y, right); + const QRectF higTrig = get_rect("higTrig", y, right); + const QRectF negTrig = get_rect("negTrig", y, right); + const QRectF lowTrig = get_rect("lowTrig", y, right); + const QRectF edgeTrig = get_rect("edgeTrig", y, right); + const QRectF label = get_rect("label", get_zeroPos(), right); + const QRectF vDial = get_rect("vDial", y, right); + const QRectF hDial = get_rect("hDial", y, right); + const QRectF chEn = get_rect("chEn", y, right); + const QRectF acdc = get_rect("acdc", y, right); + const QRectF dsoTrig = get_rect("dsoTrig", 0, right); + + if (color.contains(point) && enabled()) + return COLOR; + else if (name.contains(point) && enabled()) + return NAME; + else if (posTrig.contains(point) && _type == DS_LOGIC) + return POSTRIG; + else if (higTrig.contains(point) && _type == DS_LOGIC) + return HIGTRIG; + else if (negTrig.contains(point) && _type == DS_LOGIC) + return NEGTRIG; + else if (lowTrig.contains(point) && _type == DS_LOGIC) + return LOWTRIG; + else if (edgeTrig.contains(point) && _type == DS_LOGIC) + return EDGETRIG; + else if (label.contains(point) && enabled()) + return LABEL; + else if (vDial.contains(point) && _type == DS_DSO && enabled()) + return VDIAL; + else if (hDial.contains(point) && _type == DS_DSO && enabled()) + return HDIAL; + else if (chEn.contains(point) && _type == DS_DSO) + return CHEN; + else if (acdc.contains(point) && _type == DS_DSO && enabled()) + return ACDC; + else if (dsoTrig.contains(point) && _type == DS_DSO && enabled()) + return DSOTRIG; + else + return 0; +} + +void Trace::paint_axis(QPainter &p, int y, int left, int right) +{ + p.setPen(SignalAxisPen); + p.drawLine(QPointF(left, y + 0.5f), QPointF(right, y + 0.5f)); +} + +void Trace::compute_text_size(QPainter &p) +{ + _text_size = QSize( + p.boundingRect(QRectF(), 0, "99").width(), + p.boundingRect(QRectF(), 0, "99").height()); +} + +QRectF Trace::get_rect(const char *s, int y, int right) +{ + const QSizeF color_size(SquareWidth, SquareWidth); + const QSizeF name_size(right - get_leftWidth() - get_rightWidth(), SquareWidth); + //const QSizeF label_size(_text_size.width() + Margin, SquareWidth); + const QSizeF label_size(SquareWidth, SquareWidth); + + if (!strcmp(s, "name")) + return QRectF( + get_leftWidth(), + y - name_size.height() / 2, + name_size.width(), name_size.height()); + else if (!strcmp(s, "label")) + return QRectF( + right - 1.5f * label_size.width(), + y - SquareWidth / 2, + label_size.width(), label_size.height()); + else if (!strcmp(s, "posTrig")) + return QRectF( + get_leftWidth() + name_size.width() + Margin, + y - SquareWidth / 2, + SquareWidth, SquareWidth); + else if (!strcmp(s, "higTrig")) + return QRectF( + get_leftWidth() + name_size.width() + SquareWidth + Margin, + y - SquareWidth / 2, + SquareWidth, SquareWidth); + else if (!strcmp(s, "negTrig")) + return QRectF( + get_leftWidth() + name_size.width() + 2 * SquareWidth + Margin, + y - SquareWidth / 2, + SquareWidth, SquareWidth); + else if (!strcmp(s, "lowTrig")) + return QRectF( + get_leftWidth() + name_size.width() + 3 * SquareWidth + Margin, + y - SquareWidth / 2, + SquareWidth, SquareWidth); + else if (!strcmp(s, "edgeTrig")) + return QRectF( + get_leftWidth() + name_size.width() + 4 * SquareWidth + Margin, + y - SquareWidth / 2, + SquareWidth, SquareWidth); + else if (!strcmp(s, "groupIndex")) + return QRectF( + get_leftWidth() + name_size.width() + Margin, + y - SquareWidth / 2, + SquareWidth * SquareNum, SquareWidth); + else if (!strcmp(s, "vDial")) + return QRectF( + get_leftWidth() + name_size.width() + SquareWidth*0.5 + Margin, + y - SquareWidth * SquareNum, + SquareWidth * (SquareNum-1), SquareWidth * (SquareNum-1)); + else if (!strcmp(s, "hDial")) + return QRectF( + get_leftWidth() + name_size.width() + SquareWidth*0.5 + Margin, + y + SquareWidth * 1.5, + SquareWidth * (SquareNum-1), SquareWidth * (SquareNum-1)); + else if (!strcmp(s, "chEn")) + return QRectF( + get_leftWidth() + name_size.width() + SquareWidth*0.75 + Margin, + y - SquareWidth / 2, + SquareWidth * 1.5, SquareWidth); + else if (!strcmp(s, "acdc")) + return QRectF( + get_leftWidth() + name_size.width() + SquareWidth*2.75 + Margin, + y - SquareWidth / 2, + SquareWidth * 1.5, SquareWidth); + else + return QRectF( + 2, + y - SquareWidth / 2, + SquareWidth, SquareWidth); +} + +QRectF Trace::get_view_rect() const +{ + assert(_view); + return QRectF(0, 0, _view->viewport()->width(), _view->viewport()->height()); +} + +int Trace::get_y() const +{ + return _v_offset - _view->v_offset(); +} + +QColor Trace::get_text_colour() const +{ + return (_colour.lightness() > 64) ? Qt::black : Qt::white; +} + +void Trace::on_text_changed(const QString &text) +{ + set_name(text); + text_changed(); +} + +void Trace::on_colour_changed(const QColor &colour) +{ + set_colour(colour); + colour_changed(); +} + +int Trace::rows_size() +{ + return 1; +} + +int Trace::get_leftWidth() const +{ + return SquareWidth + Margin; +} + +int Trace::get_rightWidth() const +{ + return 2 * Margin + SquareNum * SquareWidth + 1.5 * SquareWidth; +} + +int Trace::get_headerHeight() const +{ + return SquareWidth; +} + +} // namespace view +} // namespace pv diff --git a/DSLogic-gui/pv/view/trace.h b/DSLogic-gui/pv/view/trace.h new file mode 100644 index 0000000000000000000000000000000000000000..b31ca1818fb1b0ae84b591e3f004804eb057a32f --- /dev/null +++ b/DSLogic-gui/pv/view/trace.h @@ -0,0 +1,314 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2013 Joel Holdsworth + * Copyright (C) 2014 DreamSourceLab + * + * 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_TRACE_H +#define DSLOGIC_PV_VIEW_TRACE_H + +#include +#include +#include +#include +#include + +#include + +#include "selectableitem.h" +#include "dsldial.h" + +class QFormLayout; + +namespace pv { +namespace view { + +class View; + +class Trace : public SelectableItem +{ + Q_OBJECT + +private: + static const int Margin = 3; + static const int SquareNum = 5; + static const QPen AxisPen; + static const int LabelHitPadding; + +public: + static const int SquareWidth = 20; + static const int COLOR = 1; + static const int NAME = 2; + static const int POSTRIG = 3; + static const int HIGTRIG = 4; + static const int NEGTRIG = 5; + static const int LOWTRIG = 6; + static const int EDGETRIG = 7; + static const int LABEL = 8; + static const int VDIAL = 9; + static const int HDIAL = 10; + static const int CHEN = 11; + static const int ACDC = 12; + static const int DSOTRIG = 13; + + static const QColor dsBlue; + static const QColor dsYellow; + static const QColor dsRed; + static const QColor dsGreen; + static const QColor dsGray; + static const QColor dsFore; + static const QColor dsBack; + static const QColor dsDisable; + static const QColor dsActive; + static const QColor dsLightBlue; + static const QColor dsLightRed; + static const QPen SignalAxisPen; + +protected: + Trace(QString name, int type); + Trace(QString name, int index, int type); + Trace(QString name, std::list index_list, int type, int sec_index); + +public: + enum {DS_LOGIC = 0, DS_ANALOG, DS_GROUP, DS_DSO, DS_DECODER}; + +public: + /** + * Gets the name of this signal. + */ + QString get_name() const; + + /** + * Sets the name of the signal. + */ + virtual void set_name(QString name); + + /** + * Get the colour of the signal. + */ + QColor get_colour() const; + + /** + * Set the colour of the signal. + */ + void set_colour(QColor colour); + + /** + * Gets the vertical layout offset of this signal. + */ + int get_v_offset() const; + + /** + * Sets the vertical layout offset of this signal. + */ + void set_v_offset(int v_offset); + + /** + * Gets trace type + */ + int get_type() const; + + /** + * Index process + */ + int get_index() const; + std::list &get_index_list(); + void set_index_list(std::list index_list); + int get_sec_index() const; + void set_sec_index(int sec_index); + + /** + * Gets the height of this signal. + */ + int get_signalHeight() const; + + /** + * Sets the height of this signal. + */ + void set_signalHeight(int height); + + /** + * Geom + */ + int get_leftWidth() const; + int get_rightWidth() const; + int get_headerHeight() const; + + /** + * Gets the old vertical layout offset of this signal. + */ + int get_old_v_offset() const; + + /** + * Sets the old vertical layout offset of this signal. + */ + void set_old_v_offset(int v_offset); + + virtual int get_zeroPos(); + + /** + * + */ + int get_trig() const; + void set_trig(int trig); + + /** + * Returns true if the trace is visible and enabled. + */ + virtual bool enabled() const = 0; + + virtual void set_view(pv::view::View *view); + + /** + * Paints the background layer of the trace with a QPainter + * @param p the QPainter to paint into. + * @param left the x-coordinate of the left edge of the signal + * @param right the x-coordinate of the right edge of the signal + **/ + virtual void paint_back(QPainter &p, int left, int right); + + /** + * Paints the mid-layer of the trace with a QPainter + * @param p the QPainter to paint into. + * @param left the x-coordinate of the left edge of the signal + * @param right the x-coordinate of the right edge of the signal + **/ + virtual void paint_mid(QPainter &p, int left, int right); + + /** + * Paints the foreground layer of the trace with a QPainter + * @param p the QPainter to paint into. + * @param left the x-coordinate of the left edge of the signal + * @param right the x-coordinate of the right edge of the signal + **/ + virtual void paint_fore(QPainter &p, int left, int right); + + /** + * Paints the trace label. + * @param p the QPainter to paint into. + * @param right the x-coordinate of the right edge of the header + * area. + * @param hover true if the label is being hovered over by the mouse. + * @param action mouse position for hover + */ + virtual void paint_label(QPainter &p, int right, bool hover, int action); + + /** + * Gets the y-offset of the axis. + */ + int get_y() const; + + /** + * Determines if a point is in the header rect. + * 1 - in color rect + * 2 - in name rect + * 3 - in posTrig rect + * 4 - in higTrig rect + * 5 - in negTrig rect + * 6 - in lowTrig rect + * 7 - in label rect + * 0 - not + * @param y the y-coordinate of the signal. + * @param right the x-coordinate of the right edge of the header + * area. + * @param point the point to test. + */ + int pt_in_rect(int y, int right, + const QPoint &point); + + /** + * Computes the outline rectangle of a label. + * @param p the QPainter to lay out text with. + * @param y the y-coordinate of the signal. + * @param right the x-coordinate of the right edge of the header + * area. + * @return Returns the rectangle of the signal label. + */ + QRectF get_rect(const char *s, int y, int right); + + virtual int rows_size(); + + virtual QRectF get_view_rect() const; + +protected: + + /** + * Gets the text colour. + * @remarks This colour is computed by comparing the lightness + * of the trace colour against a threshold to determine whether + * white or black would be more visible. + */ + QColor get_text_colour() const; + + /** + * Paints a zero axis across the viewport. + * @param p the QPainter to paint into. + * @param y the y-offset of the axis. + * @param left the x-coordinate of the left edge of the view. + * @param right the x-coordinate of the right edge of the view. + */ + void paint_axis(QPainter &p, int y, int left, int right); + + /** + * Paints optoins for different trace type. + * @param p the QPainter to paint into. + * @param right the x-coordinate of the right edge of the header + * area. + * @param hover true if the label is being hovered over by the mouse. + * @param action mouse position for hover + */ + virtual void paint_type_options(QPainter &p, int right, bool hover, int action); + +private: + + /** + * Computes an caches the size of the label text. + */ + void compute_text_size(QPainter &p); + +private slots: + void on_text_changed(const QString &text); + + void on_colour_changed(const QColor &colour); + +signals: + void visibility_changed(); + void text_changed(); + void colour_changed(); + +protected: + pv::view::View *_view; + + QString _name; + QColor _colour; + int _v_offset; + int _type; + std::list _index_list; + int _sec_index; + int _old_v_offset; + int _signalHeight; + int _trig; + + QSizeF _text_size; +}; + +} // namespace view +} // namespace pv + +#endif // DSLOGIC_PV_VIEW_TRACE_H diff --git a/DSLogic-gui/pv/view/view.cpp b/DSLogic-gui/pv/view/view.cpp index fdd8624cecab01f551b005173b0a12e8b9999d40..30c3f3d3228be10a853e8695a354492f573e30e1 100644 --- a/DSLogic-gui/pv/view/view.cpp +++ b/DSLogic-gui/pv/view/view.cpp @@ -32,12 +32,16 @@ #include #include +#include "decodetrace.h" #include "header.h" +#include "devmode.h" #include "ruler.h" #include "signal.h" +#include "dsosignal.h" #include "view.h" #include "viewport.h" +#include "../device/devinst.h" #include "pv/sigsession.h" #include "pv/data/logic.h" #include "pv/data/logicsnapshot.h" @@ -61,16 +65,13 @@ const QColor View::CursorAreaColour(220, 231, 243); const QSizeF View::LabelPadding(4, 4); -const int View::WellPixelsPerSample = 1.0f; -const double View::MaxViewRate = 1.0f; - View::View(SigSession &session, QWidget *parent) : QAbstractScrollArea(parent), _session(session), _viewport(new Viewport(*this)), _ruler(new Ruler(*this)), _header(new Header(*this)), - _data_length(0), + _devmode(new DevMode(*this)), _scale(1e-8), _preScale(1e-6), _maxscale(1e9), @@ -81,6 +82,7 @@ View::View(SigSession &session, QWidget *parent) : _updating_scroll(false), _need_update(false), _show_cursors(false), + _trig_pos(0), _hover_point(-1, -1) { setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); @@ -90,46 +92,42 @@ View::View(SigSession &session, QWidget *parent) : connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(v_scroll_value_changed(int))); + setViewportMargins(headerWidth(), RulerHeight, 0, 0); + setViewport(_viewport); + connect(&_session, SIGNAL(signals_changed()), this, SLOT(signals_changed())); connect(&_session, SIGNAL(data_updated()), this, SLOT(data_updated())); - connect(&_session, SIGNAL(sample_rate_changed(quint64)), - this, SLOT(sample_rate_changed(quint64))); connect(&_session, SIGNAL(receive_data(quint64)), this, SLOT(receive_data(quint64))); connect(&_session, SIGNAL(receive_trigger(quint64)), this, SLOT(set_trig_pos(quint64))); - connect(_header, SIGNAL(signals_moved()), - this, SLOT(on_signals_moved())); + connect(&_session, SIGNAL(device_setted()), + _devmode, SLOT(set_device())); + connect(_devmode, SIGNAL(mode_changed()), + this, SIGNAL(mode_changed())); + + connect(_header, SIGNAL(traces_moved()), + this, SLOT(on_traces_moved())); connect(_header, SIGNAL(header_updated()), this, SLOT(header_updated())); - connect(_header, SIGNAL(vDial_changed(quint16)), - this, SLOT(vDial_changed(quint16))); - connect(_header, SIGNAL(hDial_changed(quint16)), - this, SLOT(hDial_changed(quint16))); - connect(_header, SIGNAL(acdc_changed(quint16)), - this, SLOT(acdc_changed(quint16))); - connect(_header, SIGNAL(ch_changed(quint16)), - this, SLOT(ch_changed(quint16))); - - setViewportMargins(headerWidth(), RulerHeight, 0, 0); - setViewport(_viewport); _viewport->installEventFilter(this); _ruler->installEventFilter(this); _header->installEventFilter(this); + _devmode->installEventFilter(this); _viewport->setObjectName(tr("ViewArea_viewport")); _ruler->setObjectName(tr("ViewArea_ruler")); _header->setObjectName(tr("ViewArea_header")); _show_trig_cursor = false; - _trig_cursor = new Cursor(*this, Signal::dsLightRed, 0); + _trig_cursor = new Cursor(*this, Trace::dsLightRed, 0); _show_search_cursor = false; _search_pos = 0; - _search_cursor = new Cursor(*this, Signal::dsLightBlue, _search_pos); + _search_cursor = new Cursor(*this, Trace::dsLightBlue, _search_pos); } SigSession& View::session() @@ -184,23 +182,24 @@ void View::zoom(double steps, int offset) _preOffset = _offset; const double cursor_offset = _offset + _scale * offset; - if (_session.get_device()->mode != DSO) { + if (_session.get_device()->dev_inst()->mode != DSO) { _scale *= pow(3.0/2.0, -steps); _scale = max(min(_scale, _maxscale), _minscale); - } else { + }else { const vector< shared_ptr > sigs(_session.get_signals()); - if (steps > 0.5) { - BOOST_FOREACH(const shared_ptr s, sigs) - s->go_hDialNext(); - } else if(steps < -0.5) { - BOOST_FOREACH(const shared_ptr s, sigs) - s->go_hDialPre(); + BOOST_FOREACH(const shared_ptr s, sigs) { + shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + if(steps > 0.5) + dsoSig->go_hDialPre(); + else if (steps < -0.5) + dsoSig->go_hDialNext(); + } } - _scale = sigs.at(0)->get_hDialValue() * pow(10, -9) * Viewport::NumSpanX / _viewport->width(); } _offset = cursor_offset - _scale * offset; const double MinOffset = -(_scale * (_viewport->width() * (1 - MaxViewRate))); - const double MaxOffset = _data_length * 1.0f / _session.get_last_sample_rate() - + const double MaxOffset = _session.get_device()->get_sample_time() - _scale * (_viewport->width() * MaxViewRate); _offset = max(min(_offset, MaxOffset), MinOffset); @@ -220,16 +219,16 @@ void View::set_scale_offset(double scale, double offset) _preScale = _scale; _preOffset = _offset; - if (_session.get_device()->mode != DSO) - _scale = max(min(scale, _maxscale), _minscale); + _scale = max(min(scale, _maxscale), _minscale); const double MinOffset = -(_scale * (_viewport->width() * (1 - MaxViewRate))); - const double MaxOffset = _data_length * 1.0f / _session.get_last_sample_rate() + const double MaxOffset = _session.get_device()->get_sample_time() - _scale * (_viewport->width() * MaxViewRate); _offset = max(min(offset, MaxOffset), MinOffset); if (_scale != _preScale || _offset != _preOffset) { update_scroll(); + _header->update(); _ruler->update(); _viewport->update(); } @@ -245,6 +244,36 @@ void View::set_preScale_preOffset() set_scale_offset(_preScale, _preOffset); } +vector< shared_ptr > View::get_traces() const +{ + const vector< shared_ptr > sigs(_session.get_signals()); +#ifdef ENABLE_DECODE + const vector< shared_ptr > decode_sigs( + _session.get_decode_signals()); + vector< shared_ptr > traces( + sigs.size() + decode_sigs.size()); +#else + vector< shared_ptr > traces(sigs.size()); +#endif + + vector< shared_ptr >::iterator i = traces.begin(); + i = copy(sigs.begin(), sigs.end(), i); +#ifdef ENABLE_DECODE + i = copy(decode_sigs.begin(), decode_sigs.end(), i); +#endif + + stable_sort(traces.begin(), traces.end(), compare_trace_v_offsets); + return traces; +} + +bool View::compare_trace_v_offsets(const shared_ptr &a, + const shared_ptr &b) +{ + assert(a); + assert(b); + return a->get_v_offset() < b->get_v_offset(); +} + bool View::cursors_shown() const { return _show_cursors; @@ -283,7 +312,7 @@ void View::show_search_cursor(bool show) void View::set_trig_pos(quint64 trig_pos) { - const double time = trig_pos * 1.0f / _session.get_last_sample_rate(); + const double time = trig_pos * 1.0f / _session.get_device()->get_sample_rate(); _trig_pos = trig_pos; _trig_cursor->set_time(time); _show_trig_cursor = true; @@ -296,7 +325,7 @@ void View::set_search_pos(uint64_t search_pos) { //assert(search_pos >= 0); - const double time = search_pos * 1.0f / _session.get_last_sample_rate(); + const double time = search_pos * 1.0f / _session.get_device()->get_sample_rate(); _search_pos = search_pos; _search_cursor->set_time(time); set_scale_offset(_scale, time - _scale * _viewport->width() / 2); @@ -321,15 +350,15 @@ const QPointF& View::hover_point() const void View::normalize_layout() { - const vector< boost::shared_ptr > sigs(_session.get_signals()); + const vector< shared_ptr > traces(get_traces()); int v_min = INT_MAX; - BOOST_FOREACH(const boost::shared_ptr s, sigs) - v_min = min(s->get_v_offset(), v_min); + BOOST_FOREACH(const shared_ptr t, traces) + v_min = min(t->get_v_offset(), v_min); const int delta = -min(v_min, 0); - BOOST_FOREACH(boost::shared_ptr s, sigs) - s->set_v_offset(s->get_v_offset() + delta); + BOOST_FOREACH(shared_ptr t, traces) + t->set_v_offset(t->get_v_offset() + delta); verticalScrollBar()->setSliderPosition(_v_offset + delta); v_scroll_value_changed(verticalScrollBar()->sliderPosition()); @@ -343,16 +372,16 @@ int View::get_spanY() int View::get_signalHeight() { - return SignalHeight; + return _signalHeight; } void View::get_scroll_layout(double &length, double &offset) const { - const boost::shared_ptr sig_data = _session.get_data(); - if (!sig_data) + const set< shared_ptr > data_set = _session.get_data(); + if (data_set.empty()) return; - length = _data_length / (sig_data->get_samplerate() * _scale); + length = _session.get_device()->get_sample_time() / _scale; offset = _offset / _scale; } @@ -385,31 +414,63 @@ void View::update_scroll() // Set the vertical scrollbar verticalScrollBar()->setPageStep(areaSize.height()); verticalScrollBar()->setRange(0, - _viewport->get_total_height() + SignalMargin - - areaSize.height()); + _viewport->get_total_height() - areaSize.height()); } -void View::reset_signal_layout() +void View::update_scale() { - if (_session.get_signals().size()) - SignalHeight = - ((_viewport->height() - horizontalScrollBar()->height()) / - _session.get_signals().size()) - - 2 * SignalMargin; + const uint64_t sample_rate = _session.get_device()->get_sample_rate(); + assert(sample_rate > 0); + + if (_session.get_device()->dev_inst()->mode != DSO) { + _scale = (1.0f / sample_rate) / WellPixelsPerSample; + _maxscale = _session.get_device()->get_sample_time() / (get_max_width() * MaxViewRate); + } else { + _scale = _session.get_device()->get_time_base() * 10.0f / get_max_width() * pow(10, -9); + _maxscale = 1e9; + } - int offset = SignalMargin + SignalHeight; - _spanY = SignalHeight + 2 * SignalMargin; + _minscale = (1.0f / sample_rate) / MaxPixelsPerSample; + _offset = 0; + _preScale = _scale; + _preOffset = _offset; + + const double time = _trig_pos * 1.0f / sample_rate; + _trig_cursor->set_time(time); + + _ruler->update(); + _viewport->update(); +} + +void View::signals_changed() +{ + int total_rows = 0; + const vector< shared_ptr > traces(get_traces()); + BOOST_FOREACH(const shared_ptr t, traces) + { + assert(t); + if (dynamic_pointer_cast(t) || + t->enabled()) + total_rows += t->rows_size(); + } - const vector< boost::shared_ptr > sigs(_session.get_signals()); - BOOST_FOREACH(boost::shared_ptr s, sigs) { - s->set_signalHeight(SignalHeight); - s->set_windowHeight(_viewport->height()); - //s->set_v_offset(offset); - //offset += SignalHeight + 2 * SignalMargin; - s->set_v_offset(offset + s->get_order() * _spanY); - s->set_zeroPos(_viewport->height()*0.5); + const double height = (_viewport->height() + - horizontalScrollBar()->height() + - 2 * SignalMargin * traces.size()) * 1.0 / total_rows; + + _signalHeight = (int)((height <= 0) ? 1 : height); + _spanY = _signalHeight + 2 * SignalMargin; + int next_v_offset = SignalMargin; + BOOST_FOREACH(shared_ptr t, traces) { + t->set_view(this); + const double traceHeight = _signalHeight*t->rows_size(); + t->set_signalHeight((int)traceHeight); + t->set_v_offset(next_v_offset + 0.5 * traceHeight + SignalMargin); + next_v_offset += traceHeight + 2 * SignalMargin; } - normalize_layout(); + + header_updated(); + normalize_layout(); } bool View::eventFilter(QObject *object, QEvent *event) @@ -467,14 +528,13 @@ int View::headerWidth() QFont font = QApplication::font(); QFontMetrics fm(font); - int fontWidth=fm.width("A"); - const vector< shared_ptr > sigs(_session.get_signals()); - if (!sigs.empty()){ - BOOST_FOREACH(const shared_ptr s, sigs) { - maxNameWidth = max(s->get_name().length() * fontWidth, maxNameWidth); - maxLeftWidth = max(s->get_leftWidth(), maxLeftWidth); - maxRightWidth = max(s->get_rightWidth(), maxRightWidth); + const vector< shared_ptr > traces(get_traces()); + if (!traces.empty()){ + BOOST_FOREACH(const shared_ptr t, traces) { + maxNameWidth = max(fm.boundingRect(t->get_name()).width(), maxNameWidth); + maxLeftWidth = max(t->get_leftWidth(), maxLeftWidth); + maxRightWidth = max(t->get_rightWidth(), maxRightWidth); } } maxNameWidth = max(_header->get_nameEditWidth(), maxNameWidth); @@ -489,11 +549,14 @@ void View::resizeEvent(QResizeEvent*) { update_margins(); update_scroll(); - if (_session.get_capture_state() == SigSession::Stopped) { - _maxscale = (_data_length * 1.0f / _session.get_last_sample_rate()) / (_viewport->width() * MaxViewRate); - _scale = min(_scale, _maxscale); - } - reset_signal_layout(); + if (_session.get_device()->dev_inst()->mode == DSO) + _scale = _session.get_device()->get_time_base() * pow(10, -9) * DS_CONF_DSO_HDIVS / get_max_width(); + + _maxscale = _session.get_device()->get_sample_time() / (get_max_width() * MaxViewRate); + _scale = min(_scale, _maxscale); + + signals_changed(); + _ruler->update(); _header->header_resize(); _need_update = true; } @@ -506,7 +569,7 @@ void View::h_scroll_value_changed(int value) _preOffset = _offset; const double MinOffset = -(_scale * (_viewport->width() * (1 - MaxViewRate))); - const double MaxOffset = _data_length * 1.0f / _session.get_last_sample_rate() + const double MaxOffset = _session.get_device()->get_sample_time() - _scale * (_viewport->width() * MaxViewRate); const int range = horizontalScrollBar()->maximum(); @@ -533,19 +596,8 @@ void View::v_scroll_value_changed(int value) _viewport->update(); } -void View::signals_changed() -{ - reset_signal_layout(); -} - void View::data_updated() { - // Get the new data length - _data_length = max(_session.get_total_sample_len(), (quint64)1000); - _maxscale = (_data_length * 1.0f / _session.get_last_sample_rate()) / (_viewport->width() * MaxViewRate); - if(_session.get_device()->mode != DSO) - _scale = min(_scale, _maxscale); - setViewportMargins(headerWidth(), RulerHeight, 0, 0); update_margins(); @@ -563,6 +615,8 @@ void View::update_margins() _viewport->width(), _viewport->y()); _header->setGeometry(0, _viewport->y(), _viewport->x(), _viewport->height()); + _devmode->setGeometry(0, 0, + _viewport->x(), _viewport->y()); } void View::header_updated() @@ -577,33 +631,18 @@ void View::header_updated() _header->update(); } -void View::sample_rate_changed(quint64 sample_rate) -{ - assert(sample_rate > 0); - - if (_session.get_device()->mode != DSO) - _scale = (1.0f / sample_rate) / WellPixelsPerSample; - - _minscale = (1.0f / sample_rate) / (_viewport->width() * MaxViewRate); - _offset = 0; - _preScale = _scale; - _preOffset = _offset; - - _ruler->update(); - _viewport->update(); -} - void View::marker_time_changed() { _ruler->update(); _viewport->update(); } -void View::on_signals_moved() +void View::on_traces_moved() { update_scroll(); + _need_update = true; _viewport->update(); - //signals_moved(); + //traces_moved(); } /* @@ -689,16 +728,6 @@ QString View::get_cm_delta(int index1, int index2) get_cursor_time(index2))); } -QString View::get_cm_delta_cnt(int index1, int index2) -{ - if (index1 == index2) - return "0"; - - return QString::number( - floor(abs(get_cursor_time(index1) - - get_cursor_time(index2)) * _session.get_data()->get_samplerate())); -} - double View::get_cursor_time(int index) { assert(index < (int)_cursorList.size()); @@ -713,6 +742,15 @@ double View::get_cursor_time(int index) } } +uint64_t View::get_cursor_samples(int index) +{ + const double time = get_cursor_time(index); + const uint64_t sample_rate = _session.get_device()->get_sample_limit(); + assert(sample_rate !=0); + + return time*sample_rate; +} + void View::on_mouse_moved() { mouse_moved(); @@ -733,38 +771,15 @@ void View::on_state_changed(bool stop) _viewport->stop_trigger_timer(); } -void View::vDial_changed(uint16_t channel) -{ - if (channel == 0) - _session.set_dso_ctrl(SR_CONF_VDIV0); - else - _session.set_dso_ctrl(SR_CONF_VDIV1); -} - -void View::hDial_changed(uint16_t channel) +int View::get_max_width() { + int max_width = 0; const vector< shared_ptr > sigs(_session.get_signals()); - _session.set_dso_ctrl(SR_CONF_TIMEBASE); - _scale = sigs.at(channel)->get_hDialValue() * pow(10, -9) * Viewport::NumSpanX / _viewport->width(); - _ruler->update(); - _viewport->update(); - update_scroll(); -} - -void View::acdc_changed(uint16_t channel) -{ - if (channel == 0) - _session.set_dso_ctrl(SR_CONF_COUPLING0); - else - _session.set_dso_ctrl(SR_CONF_COUPLING1); -} + BOOST_FOREACH(const shared_ptr s, sigs) { + max_width = max((double)max_width, s->get_view_rect().width()); + } -void View::ch_changed(uint16_t channel) -{ - if (channel == 0) - _session.set_dso_ctrl(SR_CONF_EN_CH0); - else - _session.set_dso_ctrl(SR_CONF_EN_CH1); + return max_width; } } // namespace view diff --git a/DSLogic-gui/pv/view/view.h b/DSLogic-gui/pv/view/view.h index 61a3eeabf0e48590b547ac2573b88089752c6e28..b268792d3c5fc83ea94d6cd7c8a5a6ae418fc09f 100644 --- a/DSLogic-gui/pv/view/view.h +++ b/DSLogic-gui/pv/view/view.h @@ -26,9 +26,16 @@ #include +#include +#include + +#include +#include + #include #include +#include "../data/signaldata.h" #include "cursor.h" #include "signal.h" @@ -39,7 +46,9 @@ class SigSession; namespace view { class Header; +class DevMode; class Ruler; +class Trace; class Viewport; class View : public QAbstractScrollArea { @@ -60,9 +69,9 @@ public: static const QSizeF LabelPadding; - static const int WellPixelsPerSample; - - static const double MaxViewRate; + static const int WellPixelsPerSample = 10.0f; + static const double MaxViewRate = 1.0f; + static const int MaxPixelsPerSample = 100.0f; public: explicit View(SigSession &session, QWidget *parent = 0); @@ -92,6 +101,8 @@ public: void set_scale_offset(double scale, double offset); void set_preScale_preOffset(); + std::vector< boost::shared_ptr > get_traces() const; + /** * Returns true if cursors are displayed. false otherwise. */ @@ -146,39 +157,45 @@ public: void set_need_update(bool need_update); bool need_update() const; + uint64_t get_cursor_samples(int index); QString get_mm_width(); QString get_mm_period(); QString get_mm_freq(); QString get_cm_time(int index); QString get_cm_delta(int index1, int index2); - QString get_cm_delta_cnt(int index1, int index2); void on_mouse_moved(); void on_cursor_moved(); void on_state_changed(bool stop); + int get_max_width(); + signals: void hover_point_changed(); - void signals_moved(); + void traces_moved(); void cursor_update(); void mouse_moved(); void cursor_moved(); + void mode_changed(); + private: void get_scroll_layout(double &length, double &offset) const; void update_scroll(); - void reset_signal_layout(); - void update_margins(); double get_cursor_time(int index); + static bool compare_trace_v_offsets( + const boost::shared_ptr &a, + const boost::shared_ptr &b); + private: bool eventFilter(QObject *object, QEvent *event); @@ -188,32 +205,25 @@ private: public slots: void set_measure_en(int enable); - void hDial_changed(quint16 channel); + void signals_changed(); + void data_updated(); + void update_scale(); private slots: void h_scroll_value_changed(int value); void v_scroll_value_changed(int value); - void signals_changed(); - void data_updated(); - void marker_time_changed(); - void on_signals_moved(); + void on_traces_moved(); void header_updated(); - void sample_rate_changed(quint64 sample_rate); - void receive_data(quint64 length); void set_trig_pos(quint64 trig_pos); - void vDial_changed(quint16 channel); - void acdc_changed(quint16 channel); - void ch_changed(quint16 channel); - private: SigSession &_session; @@ -221,8 +231,7 @@ private: Viewport *_viewport; Ruler *_ruler; Header *_header; - - uint64_t _data_length; + DevMode *_devmode; /// The view time scale in seconds per pixel. double _scale; @@ -235,7 +244,7 @@ private: double _preOffset; int _spanY; - int SignalHeight; + int _signalHeight; int _v_offset; bool _updating_scroll; diff --git a/DSLogic-gui/pv/view/viewport.cpp b/DSLogic-gui/pv/view/viewport.cpp index 9a59aa8b18292045c57402fea56a66511cfdab56..c4eaed0de38167e397fa27fdf7723ddae033ed39 100644 --- a/DSLogic-gui/pv/view/viewport.cpp +++ b/DSLogic-gui/pv/view/viewport.cpp @@ -26,6 +26,8 @@ #include "ruler.h" #include "signal.h" +#include "dsosignal.h" +#include "../device/devinst.h" #include "../data/logic.h" #include "../data/logicsnapshot.h" #include "../sigsession.h" @@ -41,11 +43,6 @@ using namespace std; namespace pv { namespace view { -const int Viewport::HitCursorMargin = 3; -const int Viewport::NumSpanY = 5; -const int Viewport::NumMiniSpanY = 5; -const int Viewport::NumSpanX = 10; - Viewport::Viewport(View &parent) : QWidget(&parent), _view(parent), @@ -70,8 +67,8 @@ Viewport::Viewport(View &parent) : triggered = false; timer_cnt = 0; - connect(&_view, SIGNAL(signals_moved()), - this, SLOT(on_signals_moved())); + connect(&_view, SIGNAL(traces_moved()), + this, SLOT(on_traces_moved())); connect(&trigger_timer, SIGNAL(timeout()), this, SLOT(on_trigger_timer())); } @@ -79,32 +76,42 @@ Viewport::Viewport(View &parent) : int Viewport::get_total_height() const { int h = 0; - const vector< boost::shared_ptr > sigs( - _view.session().get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { - assert(s); - //h = max(s->get_v_offset() + _view.get_signalHeight(), h); - h = max(s->get_v_offset(), h); - } + + const vector< shared_ptr > traces(_view.get_traces()); + BOOST_FOREACH(const shared_ptr t, traces) { + assert(t); + h += (int)(t->get_signalHeight()); + } + h += 2 * View::SignalMargin; return h; } +QPoint Viewport::get_mouse_point() const +{ + return _mouse_point; +} + void Viewport::paintEvent(QPaintEvent *event) { (void)event; using pv::view::Signal; - int i, j; + QStyleOption o; o.initFrom(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this); - //QPainter p(this); - p.setRenderHint(QPainter::Antialiasing); + const vector< shared_ptr > traces(_view.get_traces()); + BOOST_FOREACH(const shared_ptr t, traces) + { + assert(t); + t->paint_back(p, 0, width()); + } - if (_view.session().get_device()->mode == LOGIC) { + p.setRenderHint(QPainter::Antialiasing); + if (_view.session().get_device()->dev_inst()->mode == LOGIC) { switch(_view.session().get_capture_state()) { case SigSession::Init: break; @@ -122,79 +129,23 @@ void Viewport::paintEvent(QPaintEvent *event) paintSignals(p); } + BOOST_FOREACH(const shared_ptr t, traces) + { + assert(t); + if (t->enabled()) + t->paint_fore(p, 0, width()); + } + p.setRenderHint(QPainter::Antialiasing, false); if (_view.get_signalHeight() != _curSignalHeight) _curSignalHeight = _view.get_signalHeight(); - const vector< boost::shared_ptr > sigs( - _view.session().get_signals()); - - BOOST_FOREACH(const boost::shared_ptr s, sigs) { - assert(s); - //paint_axis(p, y, left, right); - p.setPen(Signal::dsGray); - const double sigY = s->get_v_offset() - _view.v_offset(); - - if (s->get_type() == Signal::DS_ANALOG) { - p.drawLine(0, sigY, width(), sigY); - const double spanY = (s->get_signalHeight()) * 1.0f / NumSpanY; - for (i = 1; i <= NumSpanY; i++) { - const double posY = sigY - spanY * i; - p.drawLine(0, posY, width(), posY); - const double miniSpanY = spanY / NumMiniSpanY; - for (j = 1; j < NumMiniSpanY; j++) { - p.drawLine(width() / 2.0f - 10, posY + miniSpanY * j, - width() / 2.0f + 10, posY + miniSpanY * j); - } - } - const double spanX = width() * 1.0f / NumSpanX; - for (i = 1; i < NumSpanX; i++) { - p.drawLine(0 + spanX * i, sigY, - 0 + spanX * i, sigY - s->get_signalHeight()); - } - } else if (s->get_type() == Signal::DS_LOGIC) { - p.drawLine(0, sigY + 10, width(), sigY + 10); - } - } - - if (_view.session().get_device()->mode == DSO) { - - p.setPen(Signal::dsGray); - p.setPen(Qt::DotLine); - - const double spanY =height() * 1.0f / 10; - for (i = 1; i < 11; i++) { - const double posY = spanY * i; - p.drawLine(0, posY, width(), posY); - const double miniSpanY = spanY / 5; - for (j = 1; j < 5; j++) { - p.drawLine(width() / 2.0f - 10, posY - miniSpanY * j, - width() / 2.0f + 10, posY - miniSpanY * j); - } - } - const double spanX = width() * 1.0f / 10; - for (i = 1; i < 11; i++) { - const double posX = spanX * i; - p.drawLine(posX, 0, - posX, height()); - const double miniSpanX = spanX / 5; - for (j = 1; j < 5; j++) { - p.drawLine(posX - miniSpanX * j, height() / 2.0f - 10, - posX - miniSpanX * j, height() / 2.0f + 10); - } - } - } p.end(); } void Viewport::paintSignals(QPainter &p) { - const vector< boost::shared_ptr > sigs( - _view.session().get_signals()); -// const vector< boost::shared_ptr > pro_sigs( -// _view.session().get_pro_signals()); - // Plot the signal - const int v_offset = _view.v_offset(); + const vector< shared_ptr > traces(_view.get_traces()); if (_view.scale() != _curScale || _view.offset() != _curOffset || _view.get_signalHeight() != _curSignalHeight || @@ -208,29 +159,17 @@ void Viewport::paintSignals(QPainter &p) QPainter dbp(&pixmap); dbp.initFrom(this); p.setRenderHint(QPainter::Antialiasing, false); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { - assert(s); - if (s->get_active()) - s->paint(dbp, ((s->get_type() == Signal::DS_DSO) ? s->get_zeroPos() + height()*0.5 : s->get_v_offset() - v_offset), 0, width(), - _view.scale(), _view.offset()); + BOOST_FOREACH(const shared_ptr t, traces) + { + assert(t); + if (t->enabled()) + t->paint_mid(dbp, 0, width()); } -// p.setRenderHint(QPainter::Antialiasing); -// BOOST_FOREACH(const boost::shared_ptr s, pro_sigs) { -// assert(s); -// s->paint(dbp, s->get_v_offset() - v_offset, 0, width(), -// _view.scale(), _view.offset()); -// } + _view.set_need_update(false); } p.drawPixmap(0, 0, pixmap); - // plot trig line in DSO mode - BOOST_FOREACH(const shared_ptr s, sigs) { - assert(s); - if (s->get_active() && s->get_type() == Signal::DS_DSO) - s->paint_trig(p, 0, width(), qAbs(_mouse_point.y() - s->get_trig_vpos()) <= HitCursorMargin ); - } - // plot cursors if (_view.cursors_shown()) { list::iterator i = _view.get_cursorList().begin(); @@ -242,21 +181,6 @@ void Viewport::paintSignals(QPainter &p) (*i)->paint(p, rect(), 1); else (*i)->paint(p, rect(), 0); - if (!_view.session().get_data()->get_snapshots().empty()) { - uint64_t _hit_sample = floor((*i)->time() * _view.session().get_last_sample_rate()); - if (_hit_sample > _total_receive_len) { - (*i)->set_time(0); - } else { - QRectF valueRect = QRectF(cursorX + 3, height()-20, 100, 20); - p.setPen(Qt::black); - p.drawLine(cursorX, height()-13, cursorX + 3, height()-10); - p.drawLine(cursorX, height()-7, cursorX + 3, height()-10); - p.drawText(valueRect, Qt::AlignLeft | Qt::AlignVCenter, - "Value: " + - QString::number((uint16_t)_view.session().get_data()->get_snapshots().front()->get_sample(_hit_sample))); - } - } - i++; } } @@ -270,7 +194,7 @@ void Viewport::paintSignals(QPainter &p) // plot zoom rect if (_zoom_rect_visible) { p.setPen(Qt::NoPen); - p.setBrush(Signal::dsLightBlue); + p.setBrush(Trace::dsLightBlue); p.drawRect(_zoom_rect); } @@ -284,14 +208,15 @@ void Viewport::paintProgress(QPainter &p) { using pv::view::Signal; - const quint64 _total_sample_len = _view.session().get_total_sample_len(); + const quint64 _total_sample_len = _view.session().get_device()->get_sample_limit(); double progress = -(_total_receive_len * 1.0f / _total_sample_len * 360 * 16); + int captured_progress = 0; p.setPen(Qt::gray); const QPoint cenPos = QPoint(width() / 2, height() / 2); const int radius = min(0.3 * width(), 0.3 * height()); p.drawEllipse(cenPos, radius - 2, radius - 2); - p.setPen(QPen(Signal::dsGreen, 4, Qt::SolidLine)); + p.setPen(QPen(Trace::dsGreen, 4, Qt::SolidLine)); p.drawArc(cenPos.x() - radius, cenPos.y() - radius, 2* radius, 2 * radius, 180 * 16, progress); p.setPen(Qt::gray); @@ -356,21 +281,53 @@ void Viewport::paintProgress(QPainter &p) const int trigger_radius = min(0.02 * width(), 0.02 * height()); p.setPen(Qt::NoPen); - p.setBrush((timer_cnt % 3) == 0 ? Signal::dsLightBlue : Signal::dsGray); + p.setBrush((timer_cnt % 3) == 0 ? Trace::dsLightBlue : Trace::dsGray); p.drawEllipse(cenLeftPos, trigger_radius, trigger_radius); - p.setBrush((timer_cnt % 3) == 1 ? Signal::dsLightBlue : Signal::dsGray); + p.setBrush((timer_cnt % 3) == 1 ? Trace::dsLightBlue : Trace::dsGray); p.drawEllipse(cenPos, trigger_radius, trigger_radius); - p.setBrush((timer_cnt % 3) == 2 ? Signal::dsLightBlue : Signal::dsGray); + p.setBrush((timer_cnt % 3) == 2 ? Trace::dsLightBlue : Trace::dsGray); p.drawEllipse(cenRightPos, trigger_radius, trigger_radius); + + sr_status status; + if (sr_status_get(_view.session().get_device()->dev_inst(), &status) == SR_OK){ + const bool triggred = status.trig_hit & 0x01; + const uint32_t captured_cnt = (status.captured_cnt0 + + (status.captured_cnt1 << 8) + + (status.captured_cnt2 << 16) + + (status.captured_cnt3 << 24)); + captured_progress = captured_cnt * 100.0 / _total_sample_len; + + + p.setPen(Trace::dsLightBlue); + QFont font=p.font(); + font.setPointSize(10); + font.setBold(true); + p.setFont(font); + QRect status_rect = QRect(cenPos.x() - radius, cenPos.y() + radius * 0.4, radius * 2, radius * 0.5); + if (triggred) + p.drawText(status_rect, + Qt::AlignCenter | Qt::AlignVCenter, + "Triggered! " + QString::number(captured_progress)+"% Captured"); + else + p.drawText(status_rect, + Qt::AlignCenter | Qt::AlignVCenter, + "Waiting for Trigger! " + QString::number(captured_progress)+"% Captured"); + } + } else { const int progress100 = ceil(progress / -3.6 / 16); - p.setPen(QColor(0, 0, 0, 50)); + p.setPen(Trace::dsGreen); QFont font=p.font(); font.setPointSize(50); font.setBold(true); p.setFont(font); p.drawText(rect(), Qt::AlignCenter | Qt::AlignVCenter, QString::number(progress100)+"%"); } + + p.setPen(QPen(Trace::dsLightBlue, 4, Qt::SolidLine)); + const int int_radius = max(radius - 4, 0); + p.drawArc(cenPos.x() - int_radius, cenPos.y() - int_radius, 2* int_radius, 2 * int_radius, 180 * 16, -captured_progress*3.6*16); + } void Viewport::mousePressEvent(QMouseEvent *event) @@ -403,16 +360,14 @@ void Viewport::mousePressEvent(QMouseEvent *event) const vector< shared_ptr > sigs(_view.session().get_signals()); BOOST_FOREACH(const shared_ptr s, sigs) { assert(s); - if (s->get_active() && - s->get_type() == Signal::DS_DSO && - qAbs(_mouse_point.y() - s->get_trig_vpos()) <= HitCursorMargin) { - if (_drag_sig) - _drag_sig.reset(); - else - _drag_sig = s; + shared_ptr dsoSig; + if ((dsoSig = dynamic_pointer_cast(s)) && + dsoSig->get_trig_rect(0, width()).contains(_mouse_point)) { + _drag_sig = s; break; } } + update(); } } @@ -427,38 +382,32 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) } if (event->buttons() & Qt::LeftButton) { - _view.set_scale_offset(_view.scale(), - _mouse_down_offset + - (_mouse_down_point - event->pos()).x() * - _view.scale()); - measure(); - } - - if (!(event->buttons() || Qt::NoButton)) { if (_drag_sig) { - uint16_t trig_value = 0; - int vpos = _mouse_point.y(); - if (vpos < 0) - vpos = 0; - else if (vpos > height()) - vpos = height(); - _drag_sig->set_trig_vpos(vpos); - - const vector< shared_ptr > sigs(_view.session().get_signals()); - BOOST_FOREACH(const shared_ptr s, sigs) { - assert(s); - if (s->get_active() && - s->get_type() == Signal::DS_DSO) { - trig_value += (((uint16_t)(255 - s->get_trig_vpos()*1.0/height()*255)) << 8*s->get_index()); - } - } - sr_config_set(_view.session().get_device(), - SR_CONF_TRIGGER_VALUE, g_variant_new_uint16(trig_value)); + shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(_drag_sig)) + dsoSig->set_trig_vpos(_mouse_point.y()); + } else { + _view.set_scale_offset(_view.scale(), + _mouse_down_offset + + (_mouse_down_point - event->pos()).x() * + _view.scale()); + measure(); } + } + if (!(event->buttons() || Qt::NoButton)) { + uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); TimeMarker* grabbed_marker = _view.get_ruler()->get_grabbed_cursor(); if (_view.cursors_shown() && grabbed_marker) { - grabbed_marker->set_time(_view.offset() + _view.hover_point().x() * _view.scale()); + const double cur_time = _view.offset() + _view.hover_point().x() * _view.scale(); + const double pos = cur_time * sample_rate; + const double pos_delta = pos - (int)pos; + if ( pos_delta < HitCursorTimeMargin) + grabbed_marker->set_time(1.0 / sample_rate * floor(pos)); + else if (pos_delta > (1.0 - HitCursorTimeMargin)) + grabbed_marker->set_time(1.0 / sample_rate * ceil(pos)); + else + grabbed_marker->set_time(cur_time); } measure(); } @@ -479,12 +428,17 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) _view.set_scale_offset(newScale, newOffset); } + if(_drag_sig) + _drag_sig.reset(); + update(); } void Viewport::mouseDoubleClickEvent(QMouseEvent *event) { assert (event); + (void)event; + if (_view.scale() == _view.get_maxscale()) _view.set_preScale_preOffset(); else @@ -518,7 +472,7 @@ void Viewport::leaveEvent(QEvent *) update(); } -void Viewport::on_signals_moved() +void Viewport::on_traces_moved() { update(); } @@ -530,8 +484,8 @@ void Viewport::set_receive_len(quint64 length) start_trigger_timer(333); } else { stop_trigger_timer(); - if (_total_receive_len + length > _view.session().get_total_sample_len()) - _total_receive_len = _view.session().get_total_sample_len(); + if (_total_receive_len + length > _view.session().get_device()->get_sample_limit()) + _total_receive_len = _view.session().get_device()->get_sample_limit(); else _total_receive_len += length; } @@ -540,19 +494,21 @@ void Viewport::set_receive_len(quint64 length) void Viewport::measure() { + uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); + const vector< boost::shared_ptr > sigs(_view.session().get_signals()); BOOST_FOREACH(const boost::shared_ptr s, sigs) { assert(s); const int curY = _view.hover_point().y(); const double curX = _view.hover_point().x(); - if (curY <= View::SignalMargin || s->get_type() != Signal::DS_LOGIC) { + if (curY <= View::SignalMargin || s->get_type() != Trace::DS_LOGIC) { _measure_shown = false; break; - } else if ( curY < s->get_v_offset() && - curY > (s->get_v_offset() - _view.get_signalHeight())) { + } else if ( curY < s->get_y() + _view.get_signalHeight() * 0.5 && + curY > (s->get_y() - _view.get_signalHeight() * 0.5)) { if (s->cur_edges().size() > 2) { const double pixels_offset = _view.offset() / _view.scale(); - const double samples_per_pixel = _view.session().get_last_sample_rate() * _view.scale(); + const double samples_per_pixel = sample_rate * _view.scale(); uint64_t findIndex = curX / width() * s->cur_edges().size(); uint64_t left_findIndex = 0; @@ -586,7 +542,7 @@ void Viewport::measure() _cur_thdX = 0; } - _cur_midY = s->get_v_offset() - 0.5 * _view.get_signalHeight(); + _cur_midY = s->get_y(); break; } } else if (curX < pre_edge_x) { @@ -600,8 +556,8 @@ void Viewport::measure() } } break; - } else if (curY >= s->get_v_offset() && - curY <= (s->get_v_offset() + 2 * View::SignalMargin)){ + } else if (curY >= s->get_y() + _view.get_signalHeight() && + curY <= (s->get_y() + _view.get_signalHeight() + 2 * View::SignalMargin)){ _measure_shown = false; break; }else { @@ -613,8 +569,8 @@ void Viewport::measure() const uint64_t delta_sample = _nxt_sample - _cur_sample; const uint64_t delta1_sample = _thd_sample - _cur_sample; //assert(delta_sample >= 0); - const double delta_time = delta_sample * 1.0f / _view.session().get_last_sample_rate(); - const double delta1_time = delta1_sample * 1.0f / _view.session().get_last_sample_rate(); + const double delta_time = delta_sample * 1.0f / sample_rate; + const double delta1_time = delta1_sample * 1.0f / sample_rate; const int order = (int)floorf(log10f(delta_time)); unsigned int prefix = (15 + order) / 3; assert(prefix < 9); diff --git a/DSLogic-gui/pv/view/viewport.h b/DSLogic-gui/pv/view/viewport.h index c373c78370c91b01160160904b30152b78684bf0..0d89e9e03d94454d53b4b591d63e813d00db2445 100644 --- a/DSLogic-gui/pv/view/viewport.h +++ b/DSLogic-gui/pv/view/viewport.h @@ -46,16 +46,16 @@ class Viewport : public QWidget Q_OBJECT public: - static const int HitCursorMargin; - static const int NumSpanY; - static const int NumMiniSpanY; - static const int NumSpanX; + static const int HitCursorMargin = 10; + static const double HitCursorTimeMargin = 0.3; public: explicit Viewport(View &parent); int get_total_height() const; + QPoint get_mouse_point() const; + void set_receive_len(quint64 length); QString get_mm_width(); @@ -85,7 +85,7 @@ private: void measure(); private slots: - void on_signals_moved(); + void on_traces_moved(); void on_trigger_timer(); private: diff --git a/DSLogic-gui/pv/widgets/decodergroupbox.cpp b/DSLogic-gui/pv/widgets/decodergroupbox.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f90ad0d16023a699b0bd1785065b7d43e43f564 --- /dev/null +++ b/DSLogic-gui/pv/widgets/decodergroupbox.cpp @@ -0,0 +1,69 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2013 Joel Holdsworth + * + * 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 "decodergroupbox.h" + +#include +#include +#include +#include + +#include + +namespace pv { +namespace widgets { + +DecoderGroupBox::DecoderGroupBox(QString title, QWidget *parent) : + QWidget(parent), + _layout(new QGridLayout), + _show_hide_button(QIcon(":/icons/decoder-shown.png"), QString(), this) +{ + _layout->setContentsMargins(0, 0, 0, 0); + setLayout(_layout); + + _layout->addWidget(new QLabel(QString("

%1

").arg(title)), + 0, 0); + _layout->setColumnStretch(0, 1); + + QHBoxLayout *const toolbar = new QHBoxLayout; + _layout->addLayout(toolbar, 0, 1); + + _show_hide_button.setFlat(true); + //_show_hide_button.setIconSize(QSize(16, 16)); + connect(&_show_hide_button, SIGNAL(clicked()), + this, SIGNAL(show_hide_decoder())); + toolbar->addWidget(&_show_hide_button); +} + +void DecoderGroupBox::add_layout(QLayout *layout) +{ + assert(layout); + _layout->addLayout(layout, 1, 0, 1, 2); +} + +void DecoderGroupBox::set_decoder_visible(bool visible) +{ + _show_hide_button.setIcon(QIcon(visible ? + ":/icons/decoder-shown.png" : + ":/icons/decoder-hidden.png")); +} + +} // widgets +} // pv diff --git a/DSLogic-gui/pv/widgets/decodergroupbox.h b/DSLogic-gui/pv/widgets/decodergroupbox.h new file mode 100644 index 0000000000000000000000000000000000000000..c63d6b9b03f631e921220d1ae8bdea9f1fd326c3 --- /dev/null +++ b/DSLogic-gui/pv/widgets/decodergroupbox.h @@ -0,0 +1,54 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2013 Joel Holdsworth + * + * 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_WIDGETS_DECODERGROUPBOX_H +#define DSLOGIC_PV_WIDGETS_DECODERGROUPBOX_H + +#include + +class QGridLayout; +class QToolBar; + +namespace pv { +namespace widgets { + +class DecoderGroupBox : public QWidget +{ + Q_OBJECT + +public: + DecoderGroupBox(QString title, QWidget *parent = NULL); + + void add_layout(QLayout *layout); + + void set_decoder_visible(bool visible); + +signals: + void show_hide_decoder(); + +private: + QGridLayout *const _layout; + QPushButton _show_hide_button; +}; + +} // widgets +} // pv + +#endif // DSLOGIC_PV_WIDGETS_DECODERGROUPBOX_H diff --git a/DSLogic-gui/pv/widgets/decodermenu.cpp b/DSLogic-gui/pv/widgets/decodermenu.cpp new file mode 100644 index 0000000000000000000000000000000000000000..94bdd14b7ed5c2ba9fc189ce727d1d0fe5a94f27 --- /dev/null +++ b/DSLogic-gui/pv/widgets/decodermenu.cpp @@ -0,0 +1,75 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2013 Joel Holdsworth + * + * 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 + +#include "decodermenu.h" +#include + +namespace pv { +namespace widgets { + +DecoderMenu::DecoderMenu(QWidget *parent, bool first_level_decoder) : + QMenu(parent), + _mapper(this) +{ + 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 (first_level_decoder == have_probes) { + QAction *const action = + addAction(QString::fromUtf8(d->name)); + action->setData(qVariantFromValue(l->data)); + _mapper.setMapping(action, action); + connect(action, SIGNAL(triggered()), + &_mapper, SLOT(map())); + } + } + g_slist_free(l); + + connect(&_mapper, SIGNAL(mapped(QObject*)), + this, SLOT(on_action(QObject*))); +} + +int DecoderMenu::decoder_name_cmp(const void *a, const void *b) +{ + return strcmp(((const srd_decoder*)a)->name, + ((const srd_decoder*)b)->name); +} + +void DecoderMenu::on_action(QObject *action) +{ + assert(action); + srd_decoder *const dec = + (srd_decoder*)((QAction*)action)->data().value(); + assert(dec); + + selected(); + decoder_selected(dec); +} + +} // widgets +} // pv diff --git a/DSLogic-gui/pv/widgets/decodermenu.h b/DSLogic-gui/pv/widgets/decodermenu.h new file mode 100644 index 0000000000000000000000000000000000000000..a4aca66a44a4126568a0437b071dec13b0e270bc --- /dev/null +++ b/DSLogic-gui/pv/widgets/decodermenu.h @@ -0,0 +1,58 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2013 Joel Holdsworth + * + * 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_WIDGETS_DECODERMENU_H +#define DSLOGIC_PV_WIDGETS_DECODERMENU_H + +#include +#include + +struct srd_decoder; + +namespace pv { +namespace widgets { + +class DecoderMenu : public QMenu +{ + Q_OBJECT; + +public: + DecoderMenu(QWidget *parent, bool first_level_decoder = false); + +private: + static int decoder_name_cmp(const void *a, const void *b); + + +private slots: + void on_action(QObject *action); + +signals: + void decoder_selected(srd_decoder *decoder); + void selected(); + +private: + QSignalMapper _mapper; +}; + +} // widgets +} // pv + +#endif // DSLOGIC_PV_WIDGETS_DECODERMENU_H diff --git a/DSLogic-gui/pv/widgets/fakelineedit.cpp b/DSLogic-gui/pv/widgets/fakelineedit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7423b44308cd2ffdf29c2e00fcd2514700ca601e --- /dev/null +++ b/DSLogic-gui/pv/widgets/fakelineedit.cpp @@ -0,0 +1,42 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 "fakelineedit.h" +#include + +namespace pv { +namespace widgets { + +FakeLineEdit::FakeLineEdit(QLineEdit *parent) : + QLineEdit(parent) +{ +} + +void FakeLineEdit::mousePressEvent(QMouseEvent *event) +{ + if (event->button() & Qt::LeftButton) { + trigger(); + } +} + +} // namespace widgets +} // namespace pv diff --git a/DSLogic-gui/pv/widgets/fakelineedit.h b/DSLogic-gui/pv/widgets/fakelineedit.h new file mode 100644 index 0000000000000000000000000000000000000000..d6b340467018c0e745e4123d284f9f5d6ce206c4 --- /dev/null +++ b/DSLogic-gui/pv/widgets/fakelineedit.h @@ -0,0 +1,53 @@ +/* + * This file is part of the DSLogic-gui project. + * DSLogic-gui is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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_WIDGETS_FAKELINEEDIT_H +#define DSLOGIC_PV_WIDGETS_FAKELINEEDIT_H + +#include + +namespace pv { + +class SigSession; + +namespace widgets { + +class FakeLineEdit : public QLineEdit +{ + Q_OBJECT +public: + explicit FakeLineEdit(QLineEdit *parent = 0); + +private: + void mousePressEvent(QMouseEvent * event); + +signals: + void trigger(); + +public slots: + +}; + +} // namespace widgets +} // namespace pv + +#endif // DSLOGIC_PV_WIDGETS_FAKELINEEDIT_H diff --git a/DSLogic-gui/res/DSLogic.fw b/DSLogic-gui/res/DSLogic.fw index 813f8fe2c36e37d4f255b55b7161f3a8a669f335..fa7e5f31cb8e178d304a49af7df0730777e622ba 100644 Binary files a/DSLogic-gui/res/DSLogic.fw and b/DSLogic-gui/res/DSLogic.fw differ diff --git a/DSLogic-gui/res/DSLogic33.bin b/DSLogic-gui/res/DSLogic33.bin new file mode 100644 index 0000000000000000000000000000000000000000..bed5785ccb3e162618cf117606256e790dca3234 Binary files /dev/null and b/DSLogic-gui/res/DSLogic33.bin differ diff --git a/DSLogic-gui/res/DSLogic50.bin b/DSLogic-gui/res/DSLogic50.bin new file mode 100644 index 0000000000000000000000000000000000000000..421c3bf0037aede8fe7218b142017468b6e2bf24 Binary files /dev/null and b/DSLogic-gui/res/DSLogic50.bin differ diff --git a/DSLogic-gui/stylesheet.qss b/DSLogic-gui/stylesheet.qss index 7245f278f5de0411ac9a08c0a889f6d8f639f999..c3465a9f3e2a50c7f98784a4e10434a79c4a6070 100644 --- a/DSLogic-gui/stylesheet.qss +++ b/DSLogic-gui/stylesheet.qss @@ -41,14 +41,14 @@ QToolButton { min-width: 50px; } -QPushButton:hover, -QToolButton:hover { +QPushButton:hover, QPushButton:pressed, +QToolButton:hover, QToolButton:pressed { background-color: rgb(238, 178, 17, 200); } -QPushButton:pressed, -QToolButton:pressed { - background-color: rgb(238, 178, 17, 255); +QPushButton:checked, +QToolButton:checked { + background-color: rgb(255, 255, 255, 50); } QPushButton { diff --git a/INSTALL b/INSTALL index 9868881f7376f8074619fed7904c597dc96accc3..df6a9a4d4108d443509e85c9410841c2ca860fe7 100644 --- a/INSTALL +++ b/INSTALL @@ -76,8 +76,29 @@ Building: $ sudo make install +Step3: Build libsigrokdecode -Step3: Build DSLogic-gui +Installing the requirements: + +Example on Debian/Ubuntu (please check your respective distro's package manager tool if you use other distros): + +$ sudo apt-get install git-core gcc make autoconf automake libtool pkg-config libglib2.0-dev python3-dev + +Fedora (18, 19, 20): + +$ sudo yum install git gcc make autoconf automake libtool pkgconfig glib2-devel python3-devel check-devel + +Building: + +$ git clone git://sigrok.org/libsigrokdecode +$ cd libsigrokdecode +$ ./autogen.sh +$ ./configure +$ make +$ sudo make install + + +Step4: Build DSLogic-gui Installing the requirements: diff --git a/NEWS b/NEWS index 9b9ff0852c28ca5dddded4b396b6dd5b3fd4d0dc..c45e943a384f4de480b4d58541c7f50d9ae02b11 100644 --- a/NEWS +++ b/NEWS @@ -1,30 +1,46 @@ -0.1.0 (2013-12-15) ------------------- +0.4 (2014-09-24) +----------------- + * Add protocol decoders (38) support + * Improve the hardware configuration under various platforms + * Add different thresholds support + * Add options for input filter under logic analyzer mode + * Add instant capture(trigger ignore) under logic analyzer mode + * Add detail capture status display under logic analyzer mode + * Add quick button for mode shift + * Redesign the GUI for oscilloscope + * Add flexible sample rate support under oscilloscope mode + * Fix trigger value setting issue + * Improve trigger method under oscilloscope mode + * Add shortcut keys for major operations + * Fix other bugs - * Initial release. - -0.2.0 (2014-04-13) ------------------- - - * Add DSLogic hardware support. +0.3 (2014-06-29) +----------------- + * Add DSLogic Oscilloscope module support. + * Fix data display issue when not all channels be enabled. + * Fix issue of data mirrored to other channels. + * Fix radiobutton/checkbox display issue under certain windows theme. + * Add new simple trigger type + * Fix bugs of trigger setting and detection + * Fix other minior issues. + * Clean up the git repository 0.2.1 (2014-05-08) ------------------ - * Add wireless extension hardware support. * Fix libusb_error_io issue on Linux when sample rate >= 100MHz. * Fix channel enable/disable bug. * Fix device options config issue. * Fix some display issues of UI. + +0.2.0 (2014-04-13) +------------------ + * Add DSLogic hardware support. + +0.1.0 (2013-12-15) +------------------ + * Initial release. + + - 0.3 (2014-06-29) - ----------------- - * Add DSLogic Oscilloscope module support. - * Fix data display issue when not all channels be enabled. - * Fix issue of data mirrored to other channels. - * Fix radiobutton/checkbox display issue under certain windows theme. - * Add new simple trigger type - * Fix bugs of trigger setting and detection - * Fix other minior issues. - * Clean up the git repository diff --git a/libsigrok4DSLogic/device.c b/libsigrok4DSLogic/device.c index cca0bcd33d5e99b8c9790a90bf7d0f9d2d323667..39f81250db165d50bda779c03b567ab8f0352177 100644 --- a/libsigrok4DSLogic/device.c +++ b/libsigrok4DSLogic/device.c @@ -47,12 +47,12 @@ */ /** @private */ -SR_PRIV struct sr_probe *sr_probe_new(int index, int type, - gboolean enabled, const char *name) +SR_PRIV struct sr_channel *sr_channel_new(int index, int type, + gboolean enabled, const char *name) { - struct sr_probe *probe; + struct sr_channel *probe; - if (!(probe = g_try_malloc0(sizeof(struct sr_probe)))) { + if (!(probe = g_try_malloc0(sizeof(struct sr_channel)))) { sr_err("Probe malloc failed."); return NULL; } @@ -86,7 +86,7 @@ SR_API int sr_dev_probe_name_set(const struct sr_dev_inst *sdi, int probenum, const char *name) { GSList *l; - struct sr_probe *probe; + struct sr_channel *probe; int ret; if (!sdi) { @@ -95,7 +95,7 @@ SR_API int sr_dev_probe_name_set(const struct sr_dev_inst *sdi, } ret = SR_ERR_ARG; - for (l = sdi->probes; l; l = l->next) { + for (l = sdi->channels; l; l = l->next) { probe = l->data; if (probe->index == probenum) { g_free(probe->name); @@ -123,14 +123,14 @@ SR_API int sr_dev_probe_enable(const struct sr_dev_inst *sdi, int probenum, gboolean state) { GSList *l; - struct sr_probe *probe; + struct sr_channel *probe; int ret; if (!sdi) return SR_ERR_ARG; ret = SR_ERR_ARG; - for (l = sdi->probes; l; l = l->next) { + for (l = sdi->channels; l; l = l->next) { probe = l->data; if (probe->index == probenum) { probe->enabled = state; @@ -160,14 +160,14 @@ SR_API int sr_dev_trigger_set(const struct sr_dev_inst *sdi, int probenum, const char *trigger) { GSList *l; - struct sr_probe *probe; + struct sr_channel *probe; int ret; if (!sdi) return SR_ERR_ARG; ret = SR_ERR_ARG; - for (l = sdi->probes; l; l = l->next) { + for (l = sdi->channels; l; l = l->next) { probe = l->data; if (probe->index == probenum) { /* If the probe already has a trigger, kill it first. */ @@ -208,7 +208,7 @@ SR_API gboolean sr_dev_has_option(const struct sr_dev_inst *sdi, int key) if (!sdi || !sdi->driver || !sdi->driver->config_list) return FALSE; - if (sdi->driver->config_list(SR_CONF_DEVICE_OPTIONS, &gvar, NULL) != SR_OK) + if (sdi->driver->config_list(SR_CONF_DEVICE_OPTIONS, &gvar, NULL, NULL) != SR_OK) return FALSE; ret = FALSE; @@ -243,7 +243,7 @@ SR_PRIV struct sr_dev_inst *sr_dev_inst_new(int mode, int index, int status, sdi->vendor = vendor ? g_strdup(vendor) : NULL; sdi->model = model ? g_strdup(model) : NULL; sdi->version = version ? g_strdup(version) : NULL; - sdi->probes = NULL; + sdi->channels = NULL; sdi->conn = NULL; sdi->priv = NULL; @@ -253,24 +253,24 @@ SR_PRIV struct sr_dev_inst *sr_dev_inst_new(int mode, int index, int status, /** @private */ SR_PRIV void sr_dev_probes_free(struct sr_dev_inst *sdi) { - struct sr_probe *probe; + struct sr_channel *probe; GSList *l; - for (l = sdi->probes; l; l = l->next) { + for (l = sdi->channels; l; l = l->next) { probe = l->data; g_free(probe->name); g_free(probe); } - sdi->probes = NULL; + sdi->channels = NULL; } SR_PRIV void sr_dev_inst_free(struct sr_dev_inst *sdi) { - struct sr_probe *probe; + struct sr_channel *probe; GSList *l; - for (l = sdi->probes; l; l = l->next) { + for (l = sdi->channels; l; l = l->next) { probe = l->data; g_free(probe->name); g_free(probe); @@ -368,6 +368,14 @@ SR_API GSList *sr_dev_list(const struct sr_dev_driver *driver) return NULL; } +SR_API GSList *sr_dev_mode_list(const struct sr_dev_driver *driver) +{ + if (driver && driver->dev_mode_list) + return driver->dev_mode_list(); + else + return NULL; +} + SR_API int sr_dev_clear(const struct sr_dev_driver *driver) { if (driver && driver->dev_clear) diff --git a/libsigrok4DSLogic/hardware/DSLogic/command.c b/libsigrok4DSLogic/hardware/DSLogic/command.c index 33b95e305271e72175141cc4748c82ecb7132aae..dbdb06a20a9baf034d8eec15ae5c43ad0d6033bc 100644 --- a/libsigrok4DSLogic/hardware/DSLogic/command.c +++ b/libsigrok4DSLogic/hardware/DSLogic/command.c @@ -59,30 +59,16 @@ SR_PRIV int command_get_revid_version(libusb_device_handle *devhdl, } SR_PRIV int command_start_acquisition(libusb_device_handle *devhdl, - uint64_t samplerate, gboolean samplewide) + uint64_t samplerate, gboolean samplewide, gboolean la_mode) { struct cmd_start_acquisition cmd; int delay = 0, ret; - /* Compute the sample rate. */ -// if (samplewide && samplerate > MAX_16BIT_SAMPLE_RATE) { -// sr_err("Unable to sample at %" PRIu64 "Hz " -// "when collecting 16-bit samples.", samplerate); -// return SR_ERR; -// } + (void) samplerate; -// if ((SR_MHZ(48) % samplerate) == 0) { -// cmd.flags = CMD_START_FLAGS_CLK_48MHZ; -// delay = SR_MHZ(48) / samplerate - 1; -// if (delay > MAX_SAMPLE_DELAY) -// delay = 0; -// } + cmd.flags = la_mode ? CMD_START_FLAGS_MODE_LA : 0; -// if (delay == 0 && (SR_MHZ(30) % samplerate) == 0) { -// cmd.flags = CMD_START_FLAGS_CLK_30MHZ; -// delay = SR_MHZ(30) / samplerate - 1; -// } - cmd.flags = CMD_START_FLAGS_CLK_30MHZ; + cmd.flags |= CMD_START_FLAGS_CLK_30MHZ; delay = 0; sr_info("GPIF delay = %d, clocksource = %sMHz.", delay, @@ -142,9 +128,9 @@ SR_PRIV int command_fpga_config(libusb_device_handle *devhdl) int ret; /* ... */ - cmd.byte0 = (uint8_t)XC6SLX9_BYTE_CNT; - cmd.byte1 = (uint8_t)(XC6SLX9_BYTE_CNT >> 8); - cmd.byte2 = (uint8_t)(XC6SLX9_BYTE_CNT >> 16); + cmd.byte0 = (uint8_t)0; + cmd.byte1 = (uint8_t)0; + cmd.byte2 = (uint8_t)0; /* Send the control message. */ ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR | @@ -206,3 +192,21 @@ SR_PRIV int command_dso_ctrl(libusb_device_handle *devhdl, uint32_t command) return SR_OK; } + +SR_PRIV int command_get_status(libusb_device_handle *devhdl, + struct sr_status *status) +{ + int ret; + + ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_ENDPOINT_IN, CMD_STATUS, 0x0000, 0x0000, + (unsigned char *)status, sizeof(struct sr_status), 3000); + + if (ret < 0) { + sr_err("Unable to get version info: %s.", + libusb_error_name(ret)); + return SR_ERR; + } + + return SR_OK; +} diff --git a/libsigrok4DSLogic/hardware/DSLogic/command.h b/libsigrok4DSLogic/hardware/DSLogic/command.h index 37f00c7d022bcc913b6a75247be50ebbc22acb5f..e13901448959057625da7c1844ce93524c9f6c2f 100644 --- a/libsigrok4DSLogic/hardware/DSLogic/command.h +++ b/libsigrok4DSLogic/hardware/DSLogic/command.h @@ -30,12 +30,16 @@ #define CMD_CONFIG 0xb3 #define CMD_SETTING 0xb4 #define CMD_CONTROL 0xb5 +#define CMD_STATUS 0xb6 +#define CMD_START_FLAGS_MODE_POS 4 #define CMD_START_FLAGS_WIDE_POS 5 #define CMD_START_FLAGS_CLK_SRC_POS 6 #define CMD_START_FLAGS_STOP_POS 7 -#define CMD_START_FLAGS_SAMPLE_8BIT (0 << CMD_START_FLAGS_WIDE_POS) +#define CMD_START_FLAGS_MODE_LA (1 << CMD_START_FLAGS_MODE_POS) + +#define CMD_START_FLAGS_SAMPLE_8BIT (0 << CMD_START_FLAGS_WIDE_POS) #define CMD_START_FLAGS_SAMPLE_16BIT (1 << CMD_START_FLAGS_WIDE_POS) #define CMD_START_FLAGS_CLK_30MHZ (0 << CMD_START_FLAGS_CLK_SRC_POS) @@ -82,7 +86,7 @@ SR_PRIV int command_get_fw_version(libusb_device_handle *devhdl, SR_PRIV int command_get_revid_version(libusb_device_handle *devhdl, uint8_t *revid); SR_PRIV int command_start_acquisition(libusb_device_handle *devhdl, - uint64_t samplerate, gboolean samplewide); + uint64_t samplerate, gboolean samplewide, gboolean la_mode); SR_PRIV int command_stop_acquistition(libusb_device_handle *devhdl); SR_PRIV int command_fpga_config(libusb_device_handle *devhdl); @@ -90,4 +94,7 @@ SR_PRIV int command_fpga_setting(libusb_device_handle *devhdl, uint32_t setting_ SR_PRIV int command_dso_ctrl(libusb_device_handle *devhdl, uint32_t command); +SR_PRIV int command_get_status(libusb_device_handle *devhdl, + struct sr_status *status); + #endif diff --git a/libsigrok4DSLogic/hardware/DSLogic/dslogic.c b/libsigrok4DSLogic/hardware/DSLogic/dslogic.c index f107406200ec274b38f0dbc9669ea161986fee94..fb5d512088e51d4285892e5cd961c2190598c8ce 100644 --- a/libsigrok4DSLogic/hardware/DSLogic/dslogic.c +++ b/libsigrok4DSLogic/hardware/DSLogic/dslogic.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -38,7 +39,29 @@ #endif static const int cons_buffer_size = 1024 * 16; -static const int dso_buffer_size = 1024 * 16; +static const int dso_buffer_size = SR_KB(32); +static struct sr_dev_mode mode_list[] = { + {"LA", LOGIC}, + {"DAQ", ANALOG}, + {"OSC", DSO}, +}; + +static const char *opmodes[] = { + "Normal", + "Internal Test", + "External Test", + "DRAM Loopback Test", +}; + +static const char *thresholds[] = { + "1.8/2.5/3.3V Level", + "5.0V Level", +}; + +static const char *filters[] = { + "None", + "1 Sample Clock", +}; static const int32_t hwopts[] = { SR_CONF_CONN, @@ -55,8 +78,11 @@ static const int32_t hwcaps[] = { }; static const int32_t hwoptions[] = { - SR_CONF_CLOCK_TYPE, SR_CONF_OPERATION_MODE, + SR_CONF_THRESHOLD, + SR_CONF_FILTER, + SR_CONF_CLOCK_TYPE, + SR_CONF_CLOCK_EDGE, }; static const char *probe_names[] = { @@ -87,6 +113,41 @@ static const uint64_t samplerates[] = { SR_MHZ(400), }; +//static const uint64_t samplecounts[] = { +// SR_KB(1), +// SR_KB(2), +// SR_KB(5), +// SR_KB(10), +// SR_KB(20), +// SR_KB(50), +// SR_KB(100), +// SR_KB(200), +// SR_KB(500), +// SR_MB(1), +// SR_MB(2), +// SR_MB(5), +// SR_MB(10), +// SR_MB(16), +//}; + +static const uint64_t samplecounts[] = { + SR_KB(1), + SR_KB(2), + SR_KB(8), + SR_KB(8), + SR_KB(16), + SR_KB(32), + SR_KB(64), + SR_KB(128), + SR_KB(256), + SR_KB(512), + SR_MB(1), + SR_MB(2), + SR_MB(4), + SR_MB(8), + SR_MB(16), +}; + SR_PRIV struct sr_dev_driver DSLogic_driver_info; static struct sr_dev_driver *di = &DSLogic_driver_info; @@ -186,10 +247,11 @@ static int fpga_setting(const struct sr_dev_inst *sdi) ((devc->op_mode == SR_OP_EXTERNAL_TEST) << 14) + ((devc->op_mode == SR_OP_LOOPBACK_TEST) << 13) + trigger->trigger_en + - ((sdi->mode > 0) << 4) + (devc->clock_type << 1) + + ((sdi->mode > 0) << 4) + (devc->clock_type << 1) + (devc->clock_edge << 1) + (((devc->cur_samplerate == SR_MHZ(200) && sdi->mode != DSO) || (sdi->mode == ANALOG)) << 5) + ((devc->cur_samplerate == SR_MHZ(400)) << 6) + - ((sdi->mode == ANALOG) << 7); + ((sdi->mode == ANALOG) << 7) + + ((devc->filter == SR_FILTER_1T) << 8); setting.divider = (uint32_t)ceil(SR_MHZ(100) * 1.0 / devc->cur_samplerate); setting.count = (uint32_t)(devc->limit_samples); setting.trig_pos = (uint32_t)(trigger->trigger_pos / 100.0f * devc->limit_samples); @@ -213,8 +275,8 @@ static int fpga_setting(const struct sr_dev_inst *sdi) setting.trig_logic1[0] = (trigger->trigger_logic[TriggerStages] << 1) + trigger->trigger1_inv[TriggerStages]; for (i = 1; i < NUM_TRIGGER_STAGES; i++) { - setting.trig_mask0[i] = 1; - setting.trig_mask1[i] = 1; + setting.trig_mask0[i] = 0xff; + setting.trig_mask1[i] = 0xff; setting.trig_value0[i] = 0; setting.trig_value1[i] = 0; @@ -274,22 +336,28 @@ static int fpga_config(struct libusb_device_handle *hdl, const char *filename) int offset, chunksize, ret, result; unsigned char *buf; int transferred; + uint64_t filesize; + struct stat f_stat; - if (!(buf = g_try_malloc(XC6SLX9_BYTE_CNT))) { - sr_err("FPGA configure bit malloc failed."); - return SR_ERR; - } sr_info("Configure FPGA using %s", filename); if ((fw = g_fopen(filename, "rb")) == NULL) { sr_err("Unable to open FPGA bit file %s for reading: %s", filename, strerror(errno)); return SR_ERR; } + if (stat(filename, &f_stat) == -1) + return SR_ERR; + + filesize = (uint64_t)f_stat.st_size; + if (!(buf = g_try_malloc(filesize))) { + sr_err("FPGA configure bit malloc failed."); + return SR_ERR; + } result = SR_OK; offset = 0; while (1) { - chunksize = fread(buf, 1, XC6SLX9_BYTE_CNT, fw); + chunksize = fread(buf, 1, filesize, fw); if (chunksize == 0) break; @@ -434,7 +502,7 @@ static int DSLogic_dev_open(struct sr_dev_inst *sdi) static int configure_probes(const struct sr_dev_inst *sdi) { struct dev_context *devc; - struct sr_probe *probe; + struct sr_channel *probe; GSList *l; int probe_bit, stage, i; char *tc; @@ -446,13 +514,13 @@ static int configure_probes(const struct sr_dev_inst *sdi) } stage = -1; - for (l = sdi->probes; l; l = l->next) { - probe = (struct sr_probe *)l->data; + for (l = sdi->channels; l; l = l->next) { + probe = (struct sr_channel *)l->data; if (probe->enabled == FALSE) continue; - if ((probe->index > 7 && probe->type == SR_PROBE_LOGIC) || - (probe->type == SR_PROBE_ANALOG || probe->type == SR_PROBE_DSO)) + if ((probe->index > 7 && probe->type == SR_CHANNEL_LOGIC) || + (probe->type == SR_CHANNEL_ANALOG || probe->type == SR_CHANNEL_DSO)) devc->sample_wide = TRUE; else devc->sample_wide = FALSE; @@ -495,22 +563,18 @@ static struct dev_context *DSLogic_dev_new(void) devc->profile = NULL; devc->fw_updated = 0; - devc->cur_samplerate = 0; - devc->limit_samples = 0; + devc->cur_samplerate = DEFAULT_SAMPLERATE; + devc->limit_samples = DEFAULT_SAMPLELIMIT; devc->sample_wide = 0; devc->clock_type = FALSE; + devc->clock_edge = FALSE; devc->op_mode = SR_OP_NORMAL; - devc->vdiv0 = 1000; - devc->vdiv1 = 1000; - devc->timebase = 100; - devc->coupling0 = FALSE; - devc->coupling1 = FALSE; - devc->en_ch0 = TRUE; - devc->en_ch1 = FALSE; + devc->th_level = SR_TH_3V3; + devc->filter = SR_FILTER_NONE; + devc->timebase = 10000; devc->trigger_slope = DSO_TRIGGER_RISING; devc->trigger_source = DSO_TRIGGER_AUTO; - devc->trigger_vpos = 0xffff; - devc->trigger_hpos = 0x80; + devc->trigger_hpos = 0x0; devc->zero = FALSE; return devc; @@ -529,13 +593,18 @@ static int init(struct sr_context *sr_ctx) static int set_probes(struct sr_dev_inst *sdi, int num_probes) { int j; - struct sr_probe *probe; + struct sr_channel *probe; for (j = 0; j < num_probes; j++) { - if (!(probe = sr_probe_new(j, (sdi->mode == LOGIC) ? SR_PROBE_LOGIC : ((sdi->mode == DSO) ? SR_PROBE_DSO : SR_PROBE_ANALOG), + if (!(probe = sr_channel_new(j, (sdi->mode == LOGIC) ? SR_CHANNEL_LOGIC : ((sdi->mode == DSO) ? SR_CHANNEL_DSO : SR_CHANNEL_ANALOG), TRUE, probe_names[j]))) return SR_ERR; - sdi->probes = g_slist_append(sdi->probes, probe); + if (sdi->mode == DSO) { + probe->vdiv = 1000; + probe->coupling = FALSE; + probe->trig_value = 0x80; + } + sdi->channels = g_slist_append(sdi->channels, probe); } return SR_OK; } @@ -544,22 +613,22 @@ static int adjust_probes(struct sr_dev_inst *sdi, int num_probes) { int j; GSList *l; - struct sr_probe *probe; + struct sr_channel *probe; GSList *p; assert(num_probes > 0); - j = g_slist_length(sdi->probes); + j = g_slist_length(sdi->channels); while(j < num_probes) { - if (!(probe = sr_probe_new(j, (sdi->mode == LOGIC) ? SR_PROBE_LOGIC : ((sdi->mode == DSO) ? SR_PROBE_DSO : SR_PROBE_ANALOG), + if (!(probe = sr_channel_new(j, (sdi->mode == LOGIC) ? SR_CHANNEL_LOGIC : ((sdi->mode == DSO) ? SR_CHANNEL_DSO : SR_CHANNEL_ANALOG), TRUE, probe_names[j]))) return SR_ERR; - sdi->probes = g_slist_append(sdi->probes, probe); + sdi->channels = g_slist_append(sdi->channels, probe); j++; } while(j > num_probes) { - g_slist_delete_link(sdi->probes, g_slist_last(sdi->probes)); + g_slist_delete_link(sdi->channels, g_slist_last(sdi->channels)); j--; } @@ -684,6 +753,18 @@ static GSList *dev_list(void) return ((struct drv_context *)(di->priv))->instances; } +static GSList *dev_mode_list(void) +{ + GSList *l = NULL; + int i; + + for(i = 0; i < ARRAY_SIZE(mode_list); i++) { + l = g_slist_append(l, &mode_list[i]); + } + + return l; +} + static int dev_open(struct sr_dev_inst *sdi) { struct sr_usb_dev_inst *usb; @@ -753,7 +834,16 @@ static int dev_open(struct sr_dev_inst *sdi) /* Takes >= 10ms for the FX2 to be ready for FPGA configure. */ g_usleep(10 * 1000); char filename[256]; - sprintf(filename,"%s%s",config_path,devc->profile->fpga_bit); + switch(devc->th_level) { + case SR_TH_3V3: + sprintf(filename,"%s%s",config_path,devc->profile->fpga_bit33); + break; + case SR_TH_5V0: + sprintf(filename,"%s%s",config_path,devc->profile->fpga_bit50); + break; + default: + return SR_ERR; + } const char *fpga_bit = filename; ret = fpga_config(usb->devhdl, fpga_bit); if (ret != SR_OK) { @@ -761,12 +851,6 @@ static int dev_open(struct sr_dev_inst *sdi) } } - if (devc->cur_samplerate == 0) { - /* Samplerate hasn't been set; default to the slowest one. */ - //devc->cur_samplerate = samplerates[0]; - devc->cur_samplerate = samplerates[sizeof(samplerates)/sizeof(uint64_t) - 3]; - } - return SR_OK; } @@ -804,12 +888,16 @@ static int cleanup(void) return ret; } -static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi) +static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, + const struct sr_channel *ch, + const struct sr_channel_group *cg) { struct dev_context *devc; struct sr_usb_dev_inst *usb; char str[128]; + (void)cg; + switch (id) { case SR_CONF_CONN: if (!sdi || !sdi->conn) @@ -840,53 +928,50 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi) devc = sdi->priv; *data = g_variant_new_boolean(devc->clock_type); break; - case SR_CONF_OPERATION_MODE: + case SR_CONF_CLOCK_EDGE: if (!sdi) return SR_ERR; devc = sdi->priv; - *data = g_variant_new_string(opmodes[devc->op_mode]); + *data = g_variant_new_boolean(devc->clock_edge); break; - case SR_CONF_VDIV0: + case SR_CONF_OPERATION_MODE: if (!sdi) return SR_ERR; devc = sdi->priv; - *data = g_variant_new_uint64(devc->vdiv0); + *data = g_variant_new_string(opmodes[devc->op_mode]); break; - case SR_CONF_VDIV1: + case SR_CONF_FILTER: if (!sdi) return SR_ERR; devc = sdi->priv; - *data = g_variant_new_uint64(devc->vdiv1); + *data = g_variant_new_string(filters[devc->filter]); break; - case SR_CONF_TIMEBASE: + case SR_CONF_THRESHOLD: if (!sdi) return SR_ERR; devc = sdi->priv; - *data = g_variant_new_uint64(devc->timebase); + *data = g_variant_new_string(thresholds[devc->th_level]); break; - case SR_CONF_COUPLING0: - if (!sdi) + case SR_CONF_VDIV: + if (!ch) return SR_ERR; - devc = sdi->priv; - *data = g_variant_new_boolean(devc->coupling0); + *data = g_variant_new_uint64(ch->vdiv); break; - case SR_CONF_COUPLING1: + case SR_CONF_TIMEBASE: if (!sdi) return SR_ERR; devc = sdi->priv; - *data = g_variant_new_boolean(devc->coupling1); + *data = g_variant_new_uint64(devc->timebase); break; - case SR_CONF_EN_CH0: - if (!sdi) + case SR_CONF_COUPLING: + if (!ch) return SR_ERR; - devc = sdi->priv; - *data = g_variant_new_boolean(devc->en_ch0); + *data = g_variant_new_boolean(ch->coupling); break; - case SR_CONF_EN_CH1: - if (!sdi) + case SR_CONF_EN_CH: + if (!ch) return SR_ERR; - devc = sdi->priv; - *data = g_variant_new_boolean(devc->en_ch1); + *data = g_variant_new_boolean(ch->enabled); break; case SR_CONF_TRIGGER_SLOPE: if (!sdi) @@ -901,10 +986,9 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi) *data = g_variant_new_byte(devc->trigger_source); break; case SR_CONF_TRIGGER_VALUE: - if (!sdi) + if (!ch) return SR_ERR; - devc = sdi->priv; - *data = g_variant_new_uint16(devc->trigger_vpos); + *data = g_variant_new_uint16(ch->trig_value); break; case SR_CONF_HORIZ_TRIGGERPOS: if (!sdi) @@ -912,6 +996,12 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi) devc = sdi->priv; *data = g_variant_new_uint16(devc->trigger_hpos); break; + case SR_CONF_ZERO: + if (!sdi) + return SR_ERR; + devc = sdi->priv; + *data = g_variant_new_boolean(devc->zero); + break; default: return SR_ERR_NA; } @@ -919,29 +1009,30 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi) return SR_OK; } -static uint32_t dso_cmd_gen(struct sr_dev_inst *sdi, int channel, int id) +static uint32_t dso_cmd_gen(struct sr_dev_inst *sdi, struct sr_channel* ch, int id) { struct dev_context *devc; uint32_t cmd = 0; - int cmd_channel; + int channel_cnt = 0; + GSList *l; devc = sdi->priv; switch (id) { - case SR_CONF_VDIV0: - case SR_CONF_VDIV1: - case SR_CONF_EN_CH0: - case SR_CONF_EN_CH1: + case SR_CONF_VDIV: + case SR_CONF_EN_CH: case SR_CONF_TIMEBASE: - case SR_CONF_COUPLING0: - case SR_CONF_COUPLING1: - if (devc->en_ch0 && !devc->en_ch1) - cmd_channel = -1; - else if (devc->en_ch0 && devc->en_ch1) - cmd_channel = channel; + case SR_CONF_COUPLING: + for (l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + if (probe->enabled) + channel_cnt += probe->index + 0x1; + } + if (channel_cnt == 0) + return 0x0; // --VDBS - switch((cmd_channel == 1) ? devc->vdiv1 : devc->vdiv0){ + switch(ch->vdiv){ case 5: cmd += 0x247000; break; case 10: cmd += 0x23D000; break; case 20: cmd += 0x22F000; break; @@ -955,22 +1046,33 @@ static uint32_t dso_cmd_gen(struct sr_dev_inst *sdi, int channel, int id) default: cmd += 0x21100; break; } // --DC/AC - if(((cmd_channel == 1) ? devc->coupling1 : devc->coupling0)) + if(ch->coupling) cmd += 0x100000; // --Channel - if(cmd_channel == 0) +// if(channel_cnt == 1) +// cmd += 0xC00000; +// else if(ch->index == 0) +// cmd += 0x400000; +// else if(ch->index == 1) +// cmd += 0x800000; +// else +// cmd += 0x000000; + if(ch->index == 0) cmd += 0x400000; - else if(cmd_channel == 1) + else if(ch->index == 1) cmd += 0x800000; - else if(cmd_channel == -1) - cmd += 0xC00000; else cmd += 0x000000; // --Header cmd += 0x55000000; break; + case SR_CONF_SAMPLERATE: + cmd += 0x4; + uint32_t divider = (uint32_t)ceil(SR_MHZ(100) * 1.0 / devc->cur_samplerate - 1); + cmd += divider << 8; + break; case SR_CONF_HORIZ_TRIGGERPOS: cmd += 0x8; cmd += devc->trigger_hpos << 8; @@ -985,7 +1087,10 @@ static uint32_t dso_cmd_gen(struct sr_dev_inst *sdi, int channel, int id) break; case SR_CONF_TRIGGER_VALUE: cmd += 0x14; - cmd += devc->trigger_vpos << 8; + for (l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + cmd += probe->trig_value << (8 * (probe->index + 1)); + } break; case SR_CONF_ZERO: cmd += 0x18; @@ -1000,13 +1105,17 @@ static uint32_t dso_cmd_gen(struct sr_dev_inst *sdi, int channel, int id) return cmd; } -static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi) +static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, + struct sr_channel *ch, + const struct sr_channel_group *cg ) { struct dev_context *devc; const char *stropt; int ret, num_probes; struct sr_usb_dev_inst *usb; + (void)cg; + if (sdi->status != SR_ST_ACTIVE) return SR_ERR; @@ -1021,33 +1130,39 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi) } else { adjust_probes(sdi, 16); } + ret = SR_OK; + } else if(sdi->mode == DSO) { + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_SAMPLERATE)); } - ret = SR_OK; + } else if (id == SR_CONF_CLOCK_TYPE) { devc->clock_type = g_variant_get_boolean(data); ret = SR_OK; - }else if (id == SR_CONF_LIMIT_SAMPLES) { + } else if (id == SR_CONF_CLOCK_EDGE) { + devc->clock_edge = g_variant_get_boolean(data); + ret = SR_OK; + } else if (id == SR_CONF_LIMIT_SAMPLES) { devc->limit_samples = g_variant_get_uint64(data); ret = SR_OK; } else if (id == SR_CONF_DEVICE_MODE) { - stropt = g_variant_get_string(data, NULL); + sdi->mode = g_variant_get_int16(data); ret = SR_OK; - if (!strcmp(stropt, mode_strings[LOGIC])) { - sdi->mode = LOGIC; + if (sdi->mode == LOGIC) { num_probes = devc->profile->dev_caps & DEV_CAPS_16BIT ? 16 : 8; - } else if (!strcmp(stropt, mode_strings[DSO])) { + } else if (sdi->mode == DSO) { sdi->mode = DSO; num_probes = devc->profile->dev_caps & DEV_CAPS_16BIT ? MAX_DSO_PROBES_NUM : 1; - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_DSO_SYNC)); + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_DSO_SYNC)); if (ret != SR_OK) sr_dbg("%s: DSO configuration sync failed", __func__); - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_VDIV0)); + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, sdi->channels->data, SR_CONF_VDIV)); if (ret == SR_OK) sr_dbg("%s: Initial setting for DSO mode", __func__); else sr_dbg("%s: Initial setting for DSO mode failed", __func__); - } else { - sdi->mode = ANALOG; + devc->cur_samplerate = DS_MAX_DSO_SAMPLERATE / num_probes; + devc->limit_samples = DS_MAX_DSO_DEPTH / num_probes; + } else if (sdi->mode == ANALOG){ num_probes = devc->profile->dev_caps & DEV_CAPS_16BIT ? MAX_ANALOG_PROBES_NUM : 1; } sr_dev_probes_free(sdi); @@ -1069,78 +1184,91 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi) } sr_dbg("%s: setting pattern to %d", __func__, devc->op_mode); - } else if (id == SR_CONF_EN_CH0) { - devc->en_ch0 = g_variant_get_boolean(data); - if (sdi->mode == DSO) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_EN_CH0)); + } else if (id == SR_CONF_THRESHOLD) { + stropt = g_variant_get_string(data, NULL); + ret = SR_OK; + if (!strcmp(stropt, thresholds[SR_TH_3V3])) { + devc->th_level = SR_TH_3V3; + } else if (!strcmp(stropt, thresholds[SR_TH_5V0])) { + devc->th_level = SR_TH_5V0; + } else { + ret = SR_ERR; } - if (ret == SR_OK) - sr_dbg("%s: setting ENABLE of channel 0 to %d", - __func__, devc->en_ch0); - else - sr_dbg("%s: setting ENABLE of channel 0 to %d", - __func__, devc->en_ch0); - } else if (id == SR_CONF_EN_CH1) { - devc->en_ch1 = g_variant_get_boolean(data); - if (sdi->mode == DSO) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_EN_CH1)); + if ((ret = command_fpga_config(usb->devhdl)) != SR_OK) { + sr_err("Send FPGA configure command failed!"); + } else { + /* Takes >= 10ms for the FX2 to be ready for FPGA configure. */ + g_usleep(10 * 1000); + char filename[256]; + switch(devc->th_level) { + case SR_TH_3V3: + sprintf(filename,"%s%s",config_path,devc->profile->fpga_bit33); + break; + case SR_TH_5V0: + sprintf(filename,"%s%s",config_path,devc->profile->fpga_bit50); + break; + default: + return SR_ERR; + } + const char *fpga_bit = filename; + ret = fpga_config(usb->devhdl, fpga_bit); + if (ret != SR_OK) { + sr_err("Configure FPGA failed!"); + } } - if (ret == SR_OK) - sr_dbg("%s: setting ENABLE of channel 1 to %d", - __func__, devc->en_ch1); - else - sr_dbg("%s: setting ENABLE of channel 1 to %d", - __func__, devc->en_ch1); - } else if (id == SR_CONF_VDIV0) { - devc->vdiv0 = g_variant_get_uint64(data); - if (sdi->mode == DSO) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_VDIV0)); + sr_dbg("%s: setting threshold to %d", + __func__, devc->th_level); + } else if (id == SR_CONF_FILTER) { + stropt = g_variant_get_string(data, NULL); + ret = SR_OK; + if (!strcmp(stropt, filters[SR_FILTER_NONE])) { + devc->filter = SR_FILTER_NONE; + } else if (!strcmp(stropt, filters[SR_FILTER_1T])) { + devc->filter = SR_FILTER_1T; + } else { + ret = SR_ERR; } - if (ret == SR_OK) - sr_dbg("%s: setting VDIV of channel 0 to %d mv", - __func__, devc->vdiv0); - else - sr_dbg("%s: setting VDIV of channel 0 to %d mv failed", - __func__, devc->vdiv0); - } else if (id == SR_CONF_VDIV1) { - devc->vdiv1 = g_variant_get_uint64(data); + sr_dbg("%s: setting threshold to %d", + __func__, devc->th_level); + } else if (id == SR_CONF_EN_CH) { + ch->enabled = g_variant_get_boolean(data); if (sdi->mode == DSO) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_VDIV1)); + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, ch, SR_CONF_EN_CH)); } if (ret == SR_OK) - sr_dbg("%s: setting VDIV of channel 1 to %d mv", - __func__, devc->vdiv1); + sr_dbg("%s: setting ENABLE of channel %d to %d", + __func__, ch->index, ch->enabled); else - sr_dbg("%s: setting VDIV of channel 1 to %d mv failed", - __func__, devc->vdiv1); - } else if (id == SR_CONF_TIMEBASE) { - devc->timebase = g_variant_get_uint64(data); - } else if (id == SR_CONF_COUPLING0) { - devc->coupling0 = g_variant_get_boolean(data); + sr_dbg("%s: setting ENABLE of channel %d to %d", + __func__, ch->index, ch->enabled); + } else if (id == SR_CONF_VDIV) { + ch->vdiv = g_variant_get_uint64(data); if (sdi->mode == DSO) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_COUPLING0)); + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, ch, SR_CONF_VDIV)); } if (ret == SR_OK) - sr_dbg("%s: setting AC COUPLING of channel 0 to %d", - __func__, devc->coupling0); + sr_dbg("%s: setting VDIV of channel %d to %d mv", + __func__, ch->index, ch->vdiv); else - sr_dbg("%s: setting AC COUPLING of channel 0 to %d failed", - __func__, devc->coupling0); - } else if (id == SR_CONF_COUPLING1) { - devc->coupling1 = g_variant_get_boolean(data); + sr_dbg("%s: setting VDIV of channel %d to %d mv failed", + __func__, ch->index, ch->vdiv); + } else if (id == SR_CONF_TIMEBASE) { + devc->timebase = g_variant_get_uint64(data); + } else if (id == SR_CONF_COUPLING) { + ch->coupling = g_variant_get_boolean(data); if (sdi->mode == DSO) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_COUPLING0)); + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, ch, SR_CONF_COUPLING)); } if (ret == SR_OK) - sr_dbg("%s: setting AC COUPLING of channel 1 to %d", - __func__, devc->coupling1); + sr_dbg("%s: setting AC COUPLING of channel %d to %d", + __func__, ch->index, ch->coupling); else - sr_dbg("%s: setting AC COUPLING of channel 1 to %d failed", - __func__, devc->coupling1); - } else if (id == SR_CONF_TRIGGER_SLOPE) { + sr_dbg("%s: setting AC COUPLING of channel %d to %d failed", + __func__, ch->index, ch->coupling); + } else if (id == SR_CONF_TRIGGER_SLOPE) { devc->trigger_slope = g_variant_get_byte(data); if (sdi->mode == DSO) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_TRIGGER_SLOPE)); + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_TRIGGER_SLOPE)); } if (ret == SR_OK) sr_dbg("%s: setting DSO Trigger Slope to %d", @@ -1151,7 +1279,7 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi) } else if (id == SR_CONF_TRIGGER_SOURCE) { devc->trigger_source = g_variant_get_byte(data); if (sdi->mode == DSO) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_TRIGGER_SOURCE)); + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_TRIGGER_SOURCE)); } if (ret == SR_OK) sr_dbg("%s: setting DSO Trigger Source to %d", @@ -1160,18 +1288,18 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi) sr_dbg("%s: setting DSO Trigger Source to %d failed", __func__, devc->trigger_source); } else if (id == SR_CONF_TRIGGER_VALUE) { - devc->trigger_vpos = g_variant_get_uint16(data); + ch->trig_value = g_variant_get_uint16(data); if (sdi->mode == DSO) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_TRIGGER_VALUE)); + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, ch, SR_CONF_TRIGGER_VALUE)); } if (ret == SR_OK) - sr_dbg("%s: setting DSO Trigger Value to %d", - __func__, devc->trigger_vpos); + sr_dbg("%s: setting channel %d Trigger Value to %d", + __func__, ch->index, ch->trig_value); else sr_dbg("%s: setting DSO Trigger Value to %d failed", - __func__, devc->trigger_vpos); + __func__, ch->index, ch->trig_value); } else if (id == SR_CONF_HORIZ_TRIGGERPOS) { - devc->trigger_hpos = g_variant_get_uint32(data); + devc->trigger_hpos = g_variant_get_uint16(data) * devc->limit_samples / 100.0f; if (sdi->mode == DSO) { ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_HORIZ_TRIGGERPOS)); } @@ -1199,12 +1327,14 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi) return ret; } -static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) +static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg) { GVariant *gvar; GVariantBuilder gvb; (void)sdi; + (void)cg; switch (key) { case SR_CONF_SCAN_OPTIONS: @@ -1234,12 +1364,25 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); *data = g_variant_builder_end(&gvb); break; + case SR_CONF_LIMIT_SAMPLES: + g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); + gvar = g_variant_new_from_data(G_VARIANT_TYPE("at"), + samplecounts, ARRAY_SIZE(samplecounts)*sizeof(uint64_t), TRUE, NULL, NULL); + g_variant_builder_add(&gvb, "{sv}", "samplecounts", gvar); + *data = g_variant_builder_end(&gvb); + break; case SR_CONF_TRIGGER_TYPE: *data = g_variant_new_string(TRIGGER_TYPE); break; case SR_CONF_OPERATION_MODE: *data = g_variant_new_strv(opmodes, ARRAY_SIZE(opmodes)); break; + case SR_CONF_THRESHOLD: + *data = g_variant_new_strv(thresholds, ARRAY_SIZE(thresholds)); + break; + case SR_CONF_FILTER: + *data = g_variant_new_strv(filters, ARRAY_SIZE(filters)); + break; default: return SR_ERR_NA; } @@ -1495,7 +1638,7 @@ static void receive_transfer(struct libusb_transfer *transfer) } else if ((*(struct sr_dev_inst *)(devc->cb_data)).mode == DSO) { packet.type = SR_DF_DSO; packet.payload = &dso; - dso.probes = (*(struct sr_dev_inst *)(devc->cb_data)).probes; + dso.probes = (*(struct sr_dev_inst *)(devc->cb_data)).channels; dso.num_samples = transfer->actual_length / sample_width; dso.mq = SR_MQ_VOLTAGE; dso.unit = SR_UNIT_VOLT; @@ -1504,7 +1647,7 @@ static void receive_transfer(struct libusb_transfer *transfer) } else { packet.type = SR_DF_ANALOG; packet.payload = &analog; - analog.probes = (*(struct sr_dev_inst *)(devc->cb_data)).probes; + analog.probes = (*(struct sr_dev_inst *)(devc->cb_data)).channels; analog.num_samples = transfer->actual_length / sample_width; analog.mq = SR_MQ_VOLTAGE; analog.unit = SR_UNIT_VOLT; @@ -1813,32 +1956,31 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) } } if (sdi->mode == DSO) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_VDIV0)); - if (ret != SR_OK) { - sr_err("Set VDIV of channel 0 command failed!"); - return ret; - } - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_VDIV1)); - if (ret != SR_OK) { - sr_err("Set VDIV of channel 1 command failed!"); - return ret; + GSList *l; + for(l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe, SR_CONF_VDIV)); + if (ret != SR_OK) { + sr_err("Set VDIV of channel %d command failed!", probe->index); + return ret; + } } - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_HORIZ_TRIGGERPOS)); + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_HORIZ_TRIGGERPOS)); if (ret != SR_OK) { sr_err("Set Horiz Trigger Position command failed!"); return ret; } - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_TRIGGER_SLOPE)); + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_TRIGGER_SLOPE)); if (ret != SR_OK) { sr_err("Set Trigger Slope command failed!"); return ret; } - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_TRIGGER_SOURCE)); + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_TRIGGER_SOURCE)); if (ret != SR_OK) { sr_err("Set Trigger Source command failed!"); return ret; } - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_TRIGGER_VALUE)); + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_TRIGGER_VALUE)); if (ret != SR_OK) { sr_err("Set Trigger Value command failed!"); return ret; @@ -1846,7 +1988,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) } if ((ret = command_start_acquisition (usb->devhdl, - devc->cur_samplerate, devc->sample_wide)) != SR_OK) { + devc->cur_samplerate, devc->sample_wide, (sdi->mode == LOGIC))) != SR_OK) { abort_acquisition(devc); return ret; } @@ -1935,6 +2077,25 @@ static int dev_test(struct sr_dev_inst *sdi) } } +static int dev_status_get(struct sr_dev_inst *sdi, struct sr_status *status) +{ + if (sdi) { + struct sr_usb_dev_inst *usb; + int ret; + + usb = sdi->conn; + ret = command_get_status(usb->devhdl, status); + if (ret != SR_OK) { + sr_err("Device don't exist!"); + return SR_ERR; + } else { + return SR_OK; + } + } else { + return SR_ERR; + } +} + SR_PRIV struct sr_dev_driver DSLogic_driver_info = { .name = "DSLogic", .longname = "DSLogic (generic driver for DSLogic LA)", @@ -1943,13 +2104,15 @@ SR_PRIV struct sr_dev_driver DSLogic_driver_info = { .cleanup = cleanup, .scan = scan, .dev_list = dev_list, + .dev_mode_list = dev_mode_list, .dev_clear = dev_clear, .config_get = config_get, .config_set = config_set, .config_list = config_list, .dev_open = dev_open, .dev_close = dev_close, - .dev_test = dev_test, + .dev_test = dev_test, + .dev_status_get = dev_status_get, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, diff --git a/libsigrok4DSLogic/hardware/DSLogic/dslogic.h b/libsigrok4DSLogic/hardware/DSLogic/dslogic.h index a62dc659f87072000cbbe179c170035d933d5c75..1066c8d6b07ced6e2d904f86ba0cf97557407e93 100644 --- a/libsigrok4DSLogic/hardware/DSLogic/dslogic.h +++ b/libsigrok4DSLogic/hardware/DSLogic/dslogic.h @@ -56,14 +56,12 @@ #define DEV_CAPS_16BIT (1 << DEV_CAPS_16BIT_POS) -#define XC3S250E_BYTE_CNT 169216 -//#define XC6SLX9_BYTE_CNT 341160 -#define XC6SLX9_BYTE_CNT 340884 -//#define XC6SLX9_BYTE_CNT 340604 - #define MAX_ANALOG_PROBES_NUM 9 #define MAX_DSO_PROBES_NUM 2 +#define DEFAULT_SAMPLERATE SR_MHZ(100) +#define DEFAULT_SAMPLELIMIT SR_MB(16) + struct DSLogic_profile { uint16_t vid; uint16_t pid; @@ -74,7 +72,8 @@ struct DSLogic_profile { const char *firmware; - const char *fpga_bit; + const char *fpga_bit33; + const char *fpga_bit50; uint32_t dev_caps; }; @@ -85,10 +84,11 @@ static const struct DSLogic_profile supported_fx2[3] = { */ {0x2A0E, 0x0001, NULL, "DSLogic", NULL, "DSLogic.fw", - "DSLogic.bin", + "DSLogic33.bin", + "DSLogic50.bin", DEV_CAPS_16BIT}, - { 0, 0, 0, 0, 0, 0, 0 } + { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; enum { @@ -102,7 +102,7 @@ enum { struct dev_context { const struct DSLogic_profile *profile; - /* + /* * Since we can't keep track of an DSLogic device after upgrading * the firmware (it renumerates into a different device address * after the upgrade) this is like a global lock. No device will open @@ -117,21 +117,17 @@ struct dev_context { /* Operational settings */ gboolean sample_wide; gboolean clock_type; + gboolean clock_edge; uint16_t op_mode; + uint16_t th_level; + uint16_t filter; uint16_t trigger_mask[NUM_TRIGGER_STAGES]; uint16_t trigger_value[NUM_TRIGGER_STAGES]; int trigger_stage; uint16_t trigger_buffer[NUM_TRIGGER_STAGES]; - uint64_t vdiv0; - uint64_t vdiv1; uint64_t timebase; - gboolean coupling0; - gboolean coupling1; - gboolean en_ch0; - gboolean en_ch1; uint8_t trigger_slope; uint8_t trigger_source; - uint16_t trigger_vpos; uint32_t trigger_hpos; gboolean zero; diff --git a/libsigrok4DSLogic/hardware/demo/demo.c b/libsigrok4DSLogic/hardware/demo/demo.c index 15ef903cfe2a44e169aabd4f8cbd46c7ed1ad8a9..faa786f80ad7a7b3a0392bb3a88623a106c504d9 100644 --- a/libsigrok4DSLogic/hardware/demo/demo.c +++ b/libsigrok4DSLogic/hardware/demo/demo.c @@ -72,6 +72,12 @@ static const char *pattern_strings[] = { "Random", }; +static struct sr_dev_mode mode_list[] = { + {"LA", LOGIC}, + {"DAQ", ANALOG}, + {"OSC", DSO}, +}; + /* Private, per-device-instance driver context. */ struct dev_context { struct sr_dev_inst *sdi; @@ -85,13 +91,7 @@ struct dev_context { void *cb_data; int64_t starttime; int stop; - gboolean en_ch0; - gboolean en_ch1; - uint64_t vdiv0; - uint64_t vdiv1; uint64_t timebase; - gboolean coupling0; - gboolean coupling1; int trigger_stage; uint16_t trigger_mask; @@ -128,8 +128,26 @@ static const uint64_t samplerates[] = { SR_MHZ(50), SR_MHZ(100), SR_MHZ(200), + SR_MHZ(400), }; +static const uint64_t samplecounts[] = { + SR_KB(1), + SR_KB(2), + SR_KB(4), + SR_KB(8), + SR_KB(16), + SR_KB(32), + SR_KB(64), + SR_KB(128), + SR_KB(256), + SR_KB(512), + SR_MB(1), + SR_MB(2), + SR_MB(4), + SR_MB(8), + SR_MB(16), +}; /* We name the probes 0-7 on our demo driver. */ @@ -167,7 +185,7 @@ static int hw_init(struct sr_context *sr_ctx) static GSList *hw_scan(GSList *options) { struct sr_dev_inst *sdi; - struct sr_probe *probe; + struct sr_channel *probe; struct drv_context *drvc; struct dev_context *devc; GSList *devices; @@ -195,38 +213,34 @@ static GSList *hw_scan(GSList *options) } devc->sdi = sdi; - devc->cur_samplerate = SR_MHZ(200); - devc->limit_samples = 0; + devc->cur_samplerate = SR_MHZ(100); + devc->limit_samples = SR_MB(1); devc->limit_msec = 0; devc->sample_generator = PATTERN_SINE; - devc->vdiv0 = 1000; - devc->vdiv1 = 1000; - devc->timebase = 100; - devc->coupling0 = FALSE; - devc->coupling1 = FALSE; + devc->timebase = 100000; sdi->priv = devc; if (sdi->mode == LOGIC) { for (i = 0; probe_names[i]; i++) { - if (!(probe = sr_probe_new(i, SR_PROBE_LOGIC, TRUE, + if (!(probe = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, probe_names[i]))) return NULL; - sdi->probes = g_slist_append(sdi->probes, probe); + sdi->channels = g_slist_append(sdi->channels, probe); } } else if (sdi->mode == DSO) { for (i = 0; i < DS_MAX_DSO_PROBES_NUM; i++) { - if (!(probe = sr_probe_new(i, SR_PROBE_DSO, TRUE, + if (!(probe = sr_channel_new(i, SR_CHANNEL_DSO, TRUE, probe_names[i]))) return NULL; - sdi->probes = g_slist_append(sdi->probes, probe); + sdi->channels = g_slist_append(sdi->channels, probe); } } else if (sdi->mode == ANALOG) { for (i = 0; i < DS_MAX_ANALOG_PROBES_NUM; i++) { - if (!(probe = sr_probe_new(i, SR_PROBE_ANALOG, TRUE, + if (!(probe = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE, probe_names[i]))) return NULL; - sdi->probes = g_slist_append(sdi->probes, probe); + sdi->channels = g_slist_append(sdi->channels, probe); } } @@ -238,6 +252,18 @@ static GSList *hw_dev_list(void) return ((struct drv_context *)(di->priv))->instances; } +static GSList *hw_dev_mode_list(void) +{ + GSList *l = NULL; + int i; + + for(i = 0; i < ARRAY_SIZE(mode_list); i++) { + l = g_slist_append(l, &mode_list[i]); + } + + return l; +} + static int hw_dev_open(struct sr_dev_inst *sdi) { (void)sdi; @@ -282,9 +308,13 @@ static int hw_cleanup(void) return ret; } -static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi) +static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, + const struct sr_channel *ch, + const struct sr_channel_group *cg) { - struct dev_context *const devc = sdi->priv; + (void) cg; + + struct dev_context *const devc = sdi->priv; switch (id) { case SR_CONF_SAMPLERATE: @@ -297,31 +327,22 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi) *data = g_variant_new_uint64(devc->limit_msec); break; case SR_CONF_DEVICE_MODE: - *data = g_variant_new_string(mode_strings[sdi->mode]); + *data = g_variant_new_int16(sdi->mode); break; case SR_CONF_PATTERN_MODE: *data = g_variant_new_string(pattern_strings[devc->sample_generator]); break; - case SR_CONF_VDIV0: - *data = g_variant_new_uint64(devc->vdiv0); - break; - case SR_CONF_VDIV1: - *data = g_variant_new_uint64(devc->vdiv1); + case SR_CONF_VDIV: + *data = g_variant_new_uint64(ch->vdiv); break; case SR_CONF_TIMEBASE: *data = g_variant_new_uint64(devc->timebase); break; - case SR_CONF_COUPLING0: - *data = g_variant_new_uint64(devc->coupling0); - break; - case SR_CONF_COUPLING1: - *data = g_variant_new_uint64(devc->coupling1); - break; - case SR_CONF_EN_CH0: - *data = g_variant_new_uint64(devc->en_ch0); + case SR_CONF_COUPLING: + *data = g_variant_new_uint64(ch->coupling); break; - case SR_CONF_EN_CH1: - *data = g_variant_new_uint64(devc->en_ch1); + case SR_CONF_EN_CH: + *data = g_variant_new_uint64(ch->enabled); break; default: return SR_ERR_NA; @@ -330,11 +351,15 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi) return SR_OK; } -static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi) +static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, + struct sr_channel *ch, + const struct sr_channel_group *cg) { int i, ret; const char *stropt; - struct sr_probe *probe; + struct sr_channel *probe; + + (void) cg; struct dev_context *const devc = sdi->priv; @@ -359,37 +384,39 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi) devc->limit_msec); ret = SR_OK; } else if (id == SR_CONF_DEVICE_MODE) { - stropt = g_variant_get_string(data, NULL); + sdi->mode = g_variant_get_int16(data); ret = SR_OK; - if (!strcmp(stropt, mode_strings[LOGIC])) { - sdi->mode = LOGIC; + if (sdi->mode == LOGIC) { sr_dev_probes_free(sdi); for (i = 0; probe_names[i]; i++) { - if (!(probe = sr_probe_new(i, SR_PROBE_LOGIC, TRUE, + if (!(probe = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, probe_names[i]))) ret = SR_ERR; else - sdi->probes = g_slist_append(sdi->probes, probe); + sdi->channels = g_slist_append(sdi->channels, probe); } - } else if (!strcmp(stropt, mode_strings[DSO])) { - sdi->mode = DSO; + } else if (sdi->mode == DSO) { sr_dev_probes_free(sdi); for (i = 0; i < DS_MAX_DSO_PROBES_NUM; i++) { - if (!(probe = sr_probe_new(i, SR_PROBE_DSO, TRUE, + if (!(probe = sr_channel_new(i, SR_CHANNEL_DSO, TRUE, probe_names[i]))) ret = SR_ERR; - else - sdi->probes = g_slist_append(sdi->probes, probe); + else { + probe->vdiv = 1000; + probe->coupling = FALSE; + probe->trig_value = 0x80; + sdi->channels = g_slist_append(sdi->channels, probe); + } } - } else if (!strcmp(stropt, mode_strings[ANALOG])) { - sdi->mode = ANALOG; + devc->limit_samples = SR_MB(1); + } else if (sdi->mode == ANALOG) { sr_dev_probes_free(sdi); for (i = 0; i < DS_MAX_ANALOG_PROBES_NUM; i++) { - if (!(probe = sr_probe_new(i, SR_PROBE_ANALOG, TRUE, + if (!(probe = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE, probe_names[i]))) ret = SR_ERR; else - sdi->probes = g_slist_append(sdi->probes, probe); + sdi->channels = g_slist_append(sdi->channels, probe); } } else { ret = SR_ERR; @@ -413,40 +440,25 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi) } sr_dbg("%s: setting pattern to %d", __func__, devc->sample_generator); - } else if (id == SR_CONF_EN_CH0) { - devc->en_ch0 = g_variant_get_boolean(data); - sr_dbg("%s: setting ENABLE of channel 0 to %d", __func__, - devc->en_ch0); - ret = SR_OK; - } else if (id == SR_CONF_EN_CH1) { - devc->en_ch1 = g_variant_get_boolean(data); - sr_dbg("%s: setting ENABLE of channel 1 to %d", __func__, - devc->en_ch1); + } else if (id == SR_CONF_EN_CH) { + ch->enabled = g_variant_get_boolean(data); + sr_dbg("%s: setting ENABLE of channel %d to %d", __func__, + ch->index, ch->enabled); ret = SR_OK; - } else if (id == SR_CONF_VDIV0) { - devc->vdiv0 = g_variant_get_uint64(data); - sr_dbg("%s: setting VDIV of channel 0 to %" PRIu64, __func__, - devc->vdiv0); - ret = SR_OK; - } else if (id == SR_CONF_VDIV1) { - devc->vdiv1 = g_variant_get_uint64(data); - sr_dbg("%s: setting VDIV of channel 1 to %" PRIu64, __func__, - devc->vdiv1); + } else if (id == SR_CONF_VDIV) { + ch->vdiv = g_variant_get_uint64(data); + sr_dbg("%s: setting VDIV of channel %d to %" PRIu64, __func__, + ch->index, ch->vdiv); ret = SR_OK; } else if (id == SR_CONF_TIMEBASE) { devc->timebase = g_variant_get_uint64(data); sr_dbg("%s: setting TIMEBASE to %" PRIu64, __func__, devc->timebase); ret = SR_OK; - } else if (id == SR_CONF_COUPLING0) { - devc->coupling0 = g_variant_get_boolean(data); - sr_dbg("%s: setting AC COUPLING of channel 0 to %d", __func__, - devc->coupling0); - ret = SR_OK; - } else if (id == SR_CONF_COUPLING1) { - devc->coupling1 = g_variant_get_boolean(data); - sr_dbg("%s: setting AC COUPLING of channel 1 to %d", __func__, - devc->coupling1); + } else if (id == SR_CONF_COUPLING) { + ch->coupling = g_variant_get_boolean(data); + sr_dbg("%s: setting AC COUPLING of channel %d to %d", __func__, + ch->index, ch->coupling); ret = SR_OK; } else { ret = SR_ERR_NA; @@ -455,12 +467,14 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi) return ret; } -static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) +static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg) { GVariant *gvar; GVariantBuilder gvb; (void)sdi; + (void)cg; switch (key) { case SR_CONF_DEVICE_OPTIONS: @@ -484,8 +498,12 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); *data = g_variant_builder_end(&gvb); break; - case SR_CONF_DEVICE_MODE: - *data = g_variant_new_strv(mode_strings, ARRAY_SIZE(mode_strings)); + case SR_CONF_LIMIT_SAMPLES: + g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); + gvar = g_variant_new_from_data(G_VARIANT_TYPE("at"), + samplecounts, ARRAY_SIZE(samplecounts)*sizeof(uint64_t), TRUE, NULL, NULL); + g_variant_builder_add(&gvb, "{sv}", "samplecounts", gvar); + *data = g_variant_builder_end(&gvb); break; case SR_CONF_PATTERN_MODE: *data = g_variant_new_strv(pattern_strings, ARRAY_SIZE(pattern_strings)); @@ -498,7 +516,8 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) } static void samples_generator(uint16_t *buf, uint64_t size, - struct dev_context *devc) + const struct sr_dev_inst *sdi, + struct dev_context *devc) { static uint16_t p = 0; uint64_t i; @@ -508,45 +527,75 @@ static void samples_generator(uint16_t *buf, uint64_t size, case PATTERN_SINE: /* Sine */ for (i = 0; i < size; i++) { if (i%CONST_LEN == 0) { - demo_data = 0x8000 * sin(2 * PI * p / 0xffff) + 0x8000; - p += CONST_LEN; + //demo_data = 0x8000 * sin(2 * PI * p / 0xffff) + 0x8000; + demo_data = 0x20 * (sin(2 * PI * p / 0xff) + 1); + p++; + } + GSList *l; + struct sr_channel *probe; + for (l = sdi->channels; l; l = l->next) { + probe = (struct sr_channel *)l->data; + *(buf + i) += ((probe->coupling ? 0x60 : 0x80) + demo_data) << (probe->index * 8); } - *(buf + i) = demo_data; } break; case PATTERN_SQUARE: for (i = 0; i < size; i++) { if (i%CONST_LEN == 0) { - demo_data = p > 0x7fff ? 0xf000 : 0x1000; - p += CONST_LEN; + demo_data = p > 0x7fff ? 0xa0a0 : 0x6060; + p += CONST_LEN * 10; } *(buf + i) = demo_data; + GSList *l; + struct sr_channel *probe; + for (l = sdi->channels; l; l = l->next) { + probe = (struct sr_channel *)l->data; + *(buf + i) += (probe->coupling ? 0x00 : 0x20) << (probe->index * 8); + } } break; case PATTERN_TRIANGLE: for (i = 0; i < size; i++) { if (i%CONST_LEN == 0) { - demo_data = p > 0x7fff ? 0xffff * (2.0f * (0x10000 - p) / 0x10000) : - 0xffff * (2.0f * p / 0x10000); - p += CONST_LEN; + demo_data = p > 0x7fff ? 0x40 * (1 + (0x8000 - p * 1.0f) / 0x8000) : + 0x40 * (p * 1.0f / 0x8000); + p += CONST_LEN * 10; + } + *(buf + i) = demo_data + (demo_data << 8); + GSList *l; + struct sr_channel *probe; + for (l = sdi->channels; l; l = l->next) { + probe = (struct sr_channel *)l->data; + *(buf + i) += (probe->coupling ? 0x60 : 0x80) << (probe->index * 8); } - *(buf + i) = demo_data; } break; case PATTERN_SAWTOOTH: for (i = 0; i < size; i++) { if (i%CONST_LEN == 0) { - demo_data = p; - p += CONST_LEN; + demo_data = p & 0x003f; + p ++; + } + *(buf + i) = demo_data + (demo_data << 8); + GSList *l; + struct sr_channel *probe; + for (l = sdi->channels; l; l = l->next) { + probe = (struct sr_channel *)l->data; + *(buf + i) += (probe->coupling ? 0x60 : 0x80) << (probe->index * 8); } - *(buf + i) = demo_data; } break; case PATTERN_RANDOM: /* Random */ for (i = 0; i < size; i++) { if (i%CONST_LEN == 0) - demo_data = (uint16_t)(rand() * (0x10000 * 1.0f / RAND_MAX)); - *(buf + i) = demo_data; + demo_data = (uint16_t)(rand() * (0x40 * 1.0f / RAND_MAX)); + *(buf + i) = demo_data + (demo_data << 8); + GSList *l; + struct sr_channel *probe; + for (l = sdi->channels; l; l = l->next) { + probe = (struct sr_channel *)l->data; + *(buf + i) += (probe->coupling ? 0x60 : 0x80) << (probe->index * 8); + } } break; default: @@ -599,7 +648,7 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) while (samples_to_send > 0) { sending_now = MIN(samples_to_send, BUFSIZE); - samples_generator(buf, sending_now, devc); + samples_generator(buf, sending_now, sdi, devc); if (devc->trigger_stage != 0) { for (i = 0; i < sending_now; i++) { @@ -643,7 +692,7 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) } else if (sdi->mode == DSO) { packet.type = SR_DF_DSO; packet.payload = &dso; - dso.probes = sdi->probes; + dso.probes = sdi->channels; dso.num_samples = sending_now; dso.mq = SR_MQ_VOLTAGE; dso.unit = SR_UNIT_VOLT; @@ -652,7 +701,7 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) }else { packet.type = SR_DF_ANALOG; packet.payload = &analog; - analog.probes = sdi->probes; + analog.probes = sdi->channels; analog.num_samples = sending_now; analog.mq = SR_MQ_VOLTAGE; analog.unit = SR_UNIT_VOLT; @@ -779,6 +828,21 @@ static int hw_dev_test(struct sr_dev_inst *sdi) return SR_ERR; } +static int hw_dev_status_get(struct sr_dev_inst *sdi, struct sr_status *status) +{ + if (sdi) { + struct dev_context *const devc = sdi->priv; + status->trig_hit = (devc->trigger_stage == 0); + status->captured_cnt0 = devc->samples_counter; + status->captured_cnt1 = devc->samples_counter >> 8; + status->captured_cnt2 = devc->samples_counter >> 16; + status->captured_cnt3 = devc->samples_counter >> 32; + return SR_OK; + } else { + return SR_ERR; + } +} + SR_PRIV struct sr_dev_driver demo_driver_info = { .name = "demo", .longname = "Demo driver and pattern generator", @@ -787,6 +851,7 @@ SR_PRIV struct sr_dev_driver demo_driver_info = { .cleanup = hw_cleanup, .scan = hw_scan, .dev_list = hw_dev_list, + .dev_mode_list = hw_dev_mode_list, .dev_clear = clear_instances, .config_get = config_get, .config_set = config_set, @@ -794,6 +859,7 @@ SR_PRIV struct sr_dev_driver demo_driver_info = { .dev_open = hw_dev_open, .dev_close = hw_dev_close, .dev_test = hw_dev_test, + .dev_status_get = hw_dev_status_get, .dev_acquisition_start = hw_dev_acquisition_start, .dev_acquisition_stop = hw_dev_acquisition_stop, .priv = NULL, diff --git a/libsigrok4DSLogic/hwdriver.c b/libsigrok4DSLogic/hwdriver.c index b0c2f41104a68a718078a4cf1d9c1c36ea39d928..d42063b79047dc7ea1c3cb10057ce73edb9fd199 100644 --- a/libsigrok4DSLogic/hwdriver.c +++ b/libsigrok4DSLogic/hwdriver.c @@ -59,10 +59,10 @@ static struct sr_config_info sr_config_info_data[] = { "Sample rate", NULL}, {SR_CONF_CLOCK_TYPE, SR_T_BOOL, "clocktype", "Using External Clock", NULL}, + {SR_CONF_CLOCK_EDGE, SR_T_BOOL, "clockedge", + "Using Clock Negedge", NULL}, {SR_CONF_CAPTURE_RATIO, SR_T_UINT64, "captureratio", "Pre-trigger capture ratio", NULL}, - {SR_CONF_DEVICE_MODE, SR_T_CHAR, "device", - "Device Mode", NULL}, {SR_CONF_PATTERN_MODE, SR_T_CHAR, "pattern", "Pattern mode", NULL}, {SR_CONF_TRIGGER_TYPE, SR_T_CHAR, "triggertype", @@ -80,19 +80,17 @@ static struct sr_config_info sr_config_info_data[] = { {SR_CONF_TIMEBASE, SR_T_RATIONAL_PERIOD, "timebase", "Time base", NULL}, {SR_CONF_FILTER, SR_T_CHAR, "filter", - "Filter targets", NULL}, - {SR_CONF_VDIV0, SR_T_RATIONAL_VOLT, "vdiv", + "Filter Targets", NULL}, + {SR_CONF_VDIV, SR_T_RATIONAL_VOLT, "vdiv", "Volts/div", NULL}, - {SR_CONF_VDIV1, SR_T_RATIONAL_VOLT, "vdiv", - "Volts/div", NULL}, - {SR_CONF_COUPLING0, SR_T_CHAR, "coupling", - "Coupling", NULL}, - {SR_CONF_COUPLING1, SR_T_CHAR, "coupling", + {SR_CONF_COUPLING, SR_T_CHAR, "coupling", "Coupling", NULL}, {SR_CONF_DATALOG, SR_T_BOOL, "datalog", "Datalog", NULL}, {SR_CONF_OPERATION_MODE, SR_T_CHAR, "operation", "Operation Mode", NULL}, + {SR_CONF_THRESHOLD, SR_T_CHAR, "threshold", + "Threshold Level", NULL}, {0, 0, NULL, NULL, NULL}, }; @@ -266,8 +264,11 @@ SR_PRIV void sr_config_free(struct sr_config *src) * but this is not to be flagged as an error by the caller; merely * as an indication that it's not applicable. */ -SR_API int sr_config_get(const struct sr_dev_driver *driver, int key, - GVariant **data, const struct sr_dev_inst *sdi) +SR_API int sr_config_get(const struct sr_dev_driver *driver, + const struct sr_dev_inst *sdi, + const struct sr_channel *ch, + const struct sr_channel_group *cg, + int key, GVariant **data) { int ret; @@ -277,7 +278,7 @@ SR_API int sr_config_get(const struct sr_dev_driver *driver, int key, if (!driver->config_get) return SR_ERR_ARG; - if ((ret = driver->config_get(key, data, sdi)) == SR_OK) { + if ((ret = driver->config_get(key, data, sdi, ch, cg)) == SR_OK) { /* Got a floating reference from the driver. Sink it here, * caller will need to unref when done with it. */ g_variant_ref_sink(*data); @@ -300,7 +301,10 @@ SR_API int sr_config_get(const struct sr_dev_driver *driver, int key, * but this is not to be flagged as an error by the caller; merely * as an indication that it's not applicable. */ -SR_API int sr_config_set(const struct sr_dev_inst *sdi, int key, GVariant *data) +SR_API int sr_config_set(const struct sr_dev_inst *sdi, + const struct sr_channel *ch, + const struct sr_channel_group *cg, + int key, GVariant *data) { int ret; @@ -311,7 +315,7 @@ SR_API int sr_config_set(const struct sr_dev_inst *sdi, int key, GVariant *data) else if (!sdi->driver->config_set) ret = SR_ERR_ARG; else - ret = sdi->driver->config_set(key, data, sdi); + ret = sdi->driver->config_set(key, data, sdi, ch, cg); g_variant_unref(data); @@ -336,8 +340,10 @@ SR_API int sr_config_set(const struct sr_dev_inst *sdi, int key, GVariant *data) * but this is not to be flagged as an error by the caller; merely * as an indication that it's not applicable. */ -SR_API int sr_config_list(const struct sr_dev_driver *driver, int key, - GVariant **data, const struct sr_dev_inst *sdi) +SR_API int sr_config_list(const struct sr_dev_driver *driver, + const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg, + int key, GVariant **data) { int ret; @@ -345,7 +351,7 @@ SR_API int sr_config_list(const struct sr_dev_driver *driver, int key, ret = SR_ERR; else if (!driver->config_list) ret = SR_ERR_ARG; - else if ((ret = driver->config_list(key, data, sdi)) == SR_OK) + else if ((ret = driver->config_list(key, data, sdi, cg)) == SR_OK) g_variant_ref_sink(*data); return ret; @@ -372,7 +378,33 @@ SR_API const struct sr_config_info *sr_config_info_get(int key) } /** - * Get information about an configuration key, by name. + * Get status about an acquisition + * + * @param sdi The device instance. + * @param status A pointer to a struct sr_capture_status. + * + * @return SR_OK upon success or SR_ERR in case of error. Note SR_ERR_ARG + * may be returned by the driver indicating it doesn't know that key, + * but this is not to be flagged as an error by the caller; merely + * as an indication that it's not applicable. + */ +SR_API int sr_status_get(const struct sr_dev_inst *sdi, + struct sr_status *status) +{ + int ret; + + if (!sdi->driver) + ret = SR_ERR; + else if (!sdi->driver->dev_status_get) + ret = SR_ERR_ARG; + else + ret = sdi->driver->dev_status_get(sdi, status); + + return ret; +} + +/** + * Get status about an acquisition. * * @param optname The configuration key. * @@ -381,14 +413,14 @@ SR_API const struct sr_config_info *sr_config_info_get(int key) */ SR_API const struct sr_config_info *sr_config_info_name_get(const char *optname) { - int i; + int i; - for (i = 0; sr_config_info_data[i].key; i++) { - if (!strcmp(sr_config_info_data[i].id, optname)) - return &sr_config_info_data[i]; - } + for (i = 0; sr_config_info_data[i].key; i++) { + if (!strcmp(sr_config_info_data[i].id, optname)) + return &sr_config_info_data[i]; + } - return NULL; + return NULL; } /* Unnecessary level of indirection follows. */ diff --git a/libsigrok4DSLogic/input/in_binary.c b/libsigrok4DSLogic/input/in_binary.c index 2d52c306e20c2ab36e6bbba07b80877a8612dca1..261156c5e413375da250120f4d4286c9211b234d 100644 --- a/libsigrok4DSLogic/input/in_binary.c +++ b/libsigrok4DSLogic/input/in_binary.c @@ -52,7 +52,7 @@ static int format_match(const char *filename) static int init(struct sr_input *in, const char *filename) { - struct sr_probe *probe; + struct sr_channel *probe; int num_probes, i; char name[SR_MAX_PROBENAME_LEN + 1]; char *param; @@ -90,9 +90,9 @@ static int init(struct sr_input *in, const char *filename) for (i = 0; i < num_probes; i++) { snprintf(name, SR_MAX_PROBENAME_LEN, "%d", i); /* TODO: Check return value. */ - if (!(probe = sr_probe_new(i, SR_PROBE_LOGIC, TRUE, name))) + if (!(probe = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, name))) return SR_ERR; - in->sdi->probes = g_slist_append(in->sdi->probes, probe); + in->sdi->channels = g_slist_append(in->sdi->channels, probe); } return SR_OK; @@ -113,7 +113,7 @@ static int loadfile(struct sr_input *in, const char *filename) if ((fd = open(filename, O_RDONLY)) == -1) return SR_ERR; - num_probes = g_slist_length(in->sdi->probes); + num_probes = g_slist_length(in->sdi->channels); /* Send header packet to the session bus. */ std_session_send_df_header(in->sdi, LOG_PREFIX); diff --git a/libsigrok4DSLogic/input/in_vcd.c b/libsigrok4DSLogic/input/in_vcd.c index a143b1cb3f50aff9dd0e8134871c6b26f15f8148..9db0c0b05b5264104912e44110362c654509490c 100644 --- a/libsigrok4DSLogic/input/in_vcd.c +++ b/libsigrok4DSLogic/input/in_vcd.c @@ -318,7 +318,7 @@ static int format_match(const char *filename) static int init(struct sr_input *in, const char *filename) { - struct sr_probe *probe; + struct sr_channel *probe; int num_probes, i; char name[SR_MAX_PROBENAME_LEN + 1]; char *param; @@ -377,13 +377,13 @@ static int init(struct sr_input *in, const char *filename) for (i = 0; i < num_probes; i++) { snprintf(name, SR_MAX_PROBENAME_LEN, "%d", i); - if (!(probe = sr_probe_new(i, SR_PROBE_LOGIC, TRUE, name))) + if (!(probe = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, name))) { release_context(ctx); return SR_ERR; } - in->sdi->probes = g_slist_append(in->sdi->probes, probe); + in->sdi->channels = g_slist_append(in->sdi->channels, probe); } return SR_OK; diff --git a/libsigrok4DSLogic/input/in_wav.c b/libsigrok4DSLogic/input/in_wav.c index 773b6b8e90cab7db04adab3059318023108b87d4..500dc09a391d688fc4d9b24ff9347f83f8a57681 100644 --- a/libsigrok4DSLogic/input/in_wav.c +++ b/libsigrok4DSLogic/input/in_wav.c @@ -92,7 +92,7 @@ static int format_match(const char *filename) static int init(struct sr_input *in, const char *filename) { - struct sr_probe *probe; + struct sr_channel *probe; struct context *ctx; char buf[40], probename[8]; int i; @@ -121,9 +121,9 @@ static int init(struct sr_input *in, const char *filename) for (i = 0; i < ctx->num_channels; i++) { snprintf(probename, 8, "CH%d", i + 1); - if (!(probe = sr_probe_new(0, SR_PROBE_ANALOG, TRUE, probename))) + if (!(probe = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, probename))) return SR_ERR; - in->sdi->probes = g_slist_append(in->sdi->probes, probe); + in->sdi->channels = g_slist_append(in->sdi->channels, probe); } return SR_OK; @@ -185,7 +185,7 @@ static int loadfile(struct sr_input *in, const char *filename) } packet.type = SR_DF_ANALOG; packet.payload = &analog; - analog.probes = in->sdi->probes; + analog.probes = in->sdi->channels; analog.num_samples = chunk_samples; analog.mq = 0; analog.unit = 0; diff --git a/libsigrok4DSLogic/libsigrok-internal.h b/libsigrok4DSLogic/libsigrok-internal.h index aa8086ea0d922e8d286eb4ea1a4b8110d98243e2..14cc713fa3ba827b76ed69a6a0697fe9b7db7eb7 100644 --- a/libsigrok4DSLogic/libsigrok-internal.h +++ b/libsigrok4DSLogic/libsigrok-internal.h @@ -83,8 +83,8 @@ SR_PRIV int sr_err(const char *format, ...); /*--- device.c --------------------------------------------------------------*/ -SR_PRIV struct sr_probe *sr_probe_new(int index, int type, - gboolean enabled, const char *name); +SR_PRIV struct sr_channel *sr_channel_new(int index, int type, + gboolean enabled, const char *name); SR_PRIV void sr_dev_probes_free(struct sr_dev_inst *sdi); /* Generic device instances */ diff --git a/libsigrok4DSLogic/libsigrok.h b/libsigrok4DSLogic/libsigrok.h index da82e0577e24483e1b8b927019014be3ea9ec2d8..1b5fd8dde9a85b5a32c6eceed5119ef79f8f4417 100644 --- a/libsigrok4DSLogic/libsigrok.h +++ b/libsigrok4DSLogic/libsigrok.h @@ -87,13 +87,6 @@ enum { */ }; -#define SR_MAX_PROBENAME_LEN 32 -#define DS_MAX_ANALOG_PROBES_NUM 8 -#define DS_MAX_DSO_PROBES_NUM 2 -#define TriggerStages 16 -#define TriggerProbes 16 -#define TriggerCountBits 16 - /* Handy little macros */ #define SR_HZ(n) (n) #define SR_KHZ(n) ((n) * (uint64_t)(1000ULL)) @@ -107,6 +100,19 @@ enum { #define SR_MB(n) ((n) * (uint64_t)(1048576ULL)) #define SR_GB(n) ((n) * (uint64_t)(1073741824ULL)) +#define SR_MAX_PROBENAME_LEN 32 +#define DS_MAX_ANALOG_PROBES_NUM 8 +#define DS_MAX_DSO_PROBES_NUM 2 +#define TriggerStages 16 +#define TriggerProbes 16 +#define TriggerCountBits 16 + +#define DS_MAX_DSO_SAMPLERATE SR_MHZ(200) +#define DS_MAX_DSO_DEPTH SR_KB(32) + +#define DS_CONF_DSO_HDIVS 10 +#define DS_CONF_DSO_VDIVS 10 + /** libsigrok loglevels. */ enum { SR_LOG_NONE = 0, /**< Output no messages at all. */ @@ -568,9 +574,9 @@ struct sr_output_format { }; enum { - SR_PROBE_LOGIC = 10000, - SR_PROBE_DSO, - SR_PROBE_ANALOG, + SR_CHANNEL_LOGIC = 10000, + SR_CHANNEL_DSO, + SR_CHANNEL_ANALOG, }; enum { @@ -579,19 +585,26 @@ enum { ANALOG = 2, }; -static const char *mode_strings[] = { - "Logic Analyzer", - "Oscilloscope", - "Data Acquisition", -}; - -struct sr_probe { - /* The index field will go: use g_slist_length(sdi->probes) instead. */ +struct sr_channel { + /* The index field will go: use g_slist_length(sdi->channels) instead. */ int index; int type; gboolean enabled; char *name; char *trigger; + uint64_t vdiv; + gboolean coupling; + uint8_t trig_value; +}; + +/** Structure for groups of channels that have common properties. */ +struct sr_channel_group { + /** Name of the channel group. */ + char *name; + /** List of sr_channel structs of the channels belonging to this group. */ + GSList *channels; + /** Private data for driver use. */ + void *priv; }; struct sr_config { @@ -607,6 +620,14 @@ struct sr_config_info { char *description; }; +struct sr_status { + uint8_t trig_hit; + uint8_t captured_cnt3; + uint8_t captured_cnt2; + uint8_t captured_cnt1; + uint8_t captured_cnt0; +}; + enum { /*--- Device classes ------------------------------------------------*/ @@ -710,17 +731,14 @@ enum { /** Zero */ SR_CONF_ZERO, - /** Volts/div. */ - SR_CONF_VDIV0, - SR_CONF_VDIV1, + /** Volts/div for dso channel. */ + SR_CONF_VDIV, - /** Coupling. */ - SR_CONF_COUPLING0, - SR_CONF_COUPLING1, + /** Coupling for dso channel. */ + SR_CONF_COUPLING, - /** Channel enable*/ - SR_CONF_EN_CH0, - SR_CONF_EN_CH1, + /** Channel enable for dso channel. */ + SR_CONF_EN_CH, /** Trigger types. */ SR_CONF_TRIGGER_TYPE, @@ -737,9 +755,15 @@ enum { /** clock type (internal/external) */ SR_CONF_CLOCK_TYPE, + /** clock edge (posedge/negedge) */ + SR_CONF_CLOCK_EDGE, + /** Device operation mode */ SR_CONF_OPERATION_MODE, + /** Device sample threshold */ + SR_CONF_THRESHOLD, + /*--- Special stuff -------------------------------------------------*/ /** Scan options supported by the driver. */ @@ -794,17 +818,30 @@ enum { }; struct sr_dev_inst { - struct sr_dev_driver *driver; - int index; - int status; - int inst_type; + /** Device driver. */ + struct sr_dev_driver *driver; + /** Index of device in driver. */ + int index; + /** Device instance status. SR_ST_NOT_FOUND, etc. */ + int status; + /** Device instance type. SR_INST_USB, etc. */ + int inst_type; + /** Device mode. LA/DAQ/OSC, etc. */ int mode; - char *vendor; - char *model; - char *version; - GSList *probes; - void *conn; - void *priv; + /** Device vendor. */ + char *vendor; + /** Device model. */ + char *model; + /** Device version. */ + char *version; + /** List of channels. */ + GSList *channels; + /** List of sr_channel_group structs */ + GSList *channel_groups; + /** Device instance connection data (used?) */ + void *conn; + /** Device instance private data (used?) */ + void *priv; }; /** Types of device instances (sr_dev_inst). */ @@ -841,15 +878,29 @@ enum { SR_OP_LOOPBACK_TEST = 3, }; -static const char *opmodes[] = { - "Normal", - "Internal Test", - "External Test", - "DRAM Loopback Test", +/** Device threshold level. */ +enum { + /** 1.8/2.5/3.3 level */ + SR_TH_3V3 = 0, + /** 5.0 level */ + SR_TH_5V0 = 1, +}; + +/** Device input filter. */ +enum { + /** None */ + SR_FILTER_NONE = 0, + /** One clock cycle */ + SR_FILTER_1T = 1, }; extern char config_path[256]; +struct sr_dev_mode { + char *name; + int mode; +}; + struct sr_dev_driver { /* Driver-specific */ char *name; @@ -859,18 +910,27 @@ struct sr_dev_driver { int (*cleanup) (void); GSList *(*scan) (GSList *options); GSList *(*dev_list) (void); - int (*dev_clear) (void); - int (*config_get) (int id, GVariant **data, - const struct sr_dev_inst *sdi); - int (*config_set) (int id, GVariant *data, - const struct sr_dev_inst *sdi); - int (*config_list) (int info_id, GVariant **data, - const struct sr_dev_inst *sdi); + GSList *(*dev_mode_list) (void); + int (*dev_clear) (void); + + int (*config_get) (int id, GVariant **data, + const struct sr_dev_inst *sdi, + const struct sr_channel *ch, + const struct sr_channel_group *cg); + int (*config_set) (int id, GVariant *data, + const struct sr_dev_inst *sdi, + const struct sr_channel *ch, + const struct sr_channel_group *cg); + int (*config_list) (int info_id, GVariant **data, + const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg); /* Device-specific */ int (*dev_open) (struct sr_dev_inst *sdi); int (*dev_close) (struct sr_dev_inst *sdi); int (*dev_test) (struct sr_dev_inst *sdi); + int (*dev_status_get) (struct sr_dev_inst *sdi, + struct sr_status *status); int (*dev_acquisition_start) (const struct sr_dev_inst *sdi, void *cb_data); int (*dev_acquisition_stop) (struct sr_dev_inst *sdi, diff --git a/libsigrok4DSLogic/output/out_analog.c b/libsigrok4DSLogic/output/out_analog.c index 684f8826bf2c3c38e43d050801eb9c49f119cf79..e1efdad3e4666afff8b5ebcaaedf8ae1254a5b2b 100644 --- a/libsigrok4DSLogic/output/out_analog.c +++ b/libsigrok4DSLogic/output/out_analog.c @@ -41,7 +41,7 @@ struct context { static int init(struct sr_output *o) { struct context *ctx; - struct sr_probe *probe; + struct sr_channel *probe; GSList *l; sr_spew("Initializing output module."); @@ -57,7 +57,7 @@ static int init(struct sr_output *o) /* Get the number of probes and their names. */ ctx->probelist = g_ptr_array_new(); - for (l = o->sdi->probes; l; l = l->next) { + for (l = o->sdi->channels; l; l = l->next) { probe = l->data; if (!probe || !probe->enabled) continue; @@ -190,7 +190,7 @@ static int receive(struct sr_output *o, const struct sr_dev_inst *sdi, const struct sr_datafeed_packet *packet, GString **out) { const struct sr_datafeed_analog *analog; - struct sr_probe *probe; + struct sr_channel *probe; GSList *l; const float *fdata; int i, p; diff --git a/libsigrok4DSLogic/output/out_csv.c b/libsigrok4DSLogic/output/out_csv.c index 0a7c50443efdb6454941375fcdada8443a59e6df..6eec47e7dee2a11c65c8a9b4f600e2d8ee81d9c6 100644 --- a/libsigrok4DSLogic/output/out_csv.c +++ b/libsigrok4DSLogic/output/out_csv.c @@ -57,7 +57,7 @@ struct context { static int init(struct sr_output *o) { struct context *ctx; - struct sr_probe *probe; + struct sr_channel *probe; GSList *l; GVariant *gvar; int num_probes; @@ -81,7 +81,7 @@ static int init(struct sr_output *o) o->internal = ctx; /* Get the number of probes, and the unitsize. */ - for (l = o->sdi->probes; l; l = l->next) { + for (l = o->sdi->channels; l; l = l->next) { probe = l->data; if (probe->enabled) ctx->num_enabled_probes++; @@ -89,10 +89,10 @@ static int init(struct sr_output *o) ctx->unitsize = (ctx->num_enabled_probes + 7) / 8; - num_probes = g_slist_length(o->sdi->probes); + num_probes = g_slist_length(o->sdi->channels); - if (sr_config_get(o->sdi->driver, SR_CONF_SAMPLERATE, &gvar, - o->sdi) == SR_OK) { + if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL, + SR_CONF_SAMPLERATE, &gvar) == SR_OK) { ctx->samplerate = g_variant_get_uint64(gvar); g_variant_unref(gvar); } else @@ -112,7 +112,7 @@ static int init(struct sr_output *o) /* Columns / channels */ g_string_append_printf(ctx->header, "; Channels (%d/%d): ", ctx->num_enabled_probes, num_probes); - for (l = o->sdi->probes; l; l = l->next) { + for (l = o->sdi->channels; l; l = l->next) { probe = l->data; if (probe->enabled) g_string_append_printf(ctx->header, "%s, ", probe->name); diff --git a/libsigrok4DSLogic/output/out_vcd.c b/libsigrok4DSLogic/output/out_vcd.c index 04d7fcbbb1a60103c20f9f16b47d33a8c230f6c4..7c00acb7f64005eb1a89cf1696e5dde5fff70d10 100644 --- a/libsigrok4DSLogic/output/out_vcd.c +++ b/libsigrok4DSLogic/output/out_vcd.c @@ -51,7 +51,7 @@ $comment\n Acquisition with %d/%d probes at %s\n$end\n"; static int init(struct sr_output *o) { struct context *ctx; - struct sr_probe *probe; + struct sr_channel *probe; GSList *l; GVariant *gvar; int num_probes, i; @@ -67,7 +67,7 @@ static int init(struct sr_output *o) ctx->num_enabled_probes = 0; ctx->probeindices = g_array_new(FALSE, FALSE, sizeof(int)); - for (l = o->sdi->probes; l; l = l->next) { + for (l = o->sdi->channels; l; l = l->next) { probe = l->data; if (!probe->enabled) continue; @@ -82,7 +82,7 @@ static int init(struct sr_output *o) ctx->unitsize = (ctx->num_enabled_probes + 7) / 8; ctx->header = g_string_sized_new(512); - num_probes = g_slist_length(o->sdi->probes); + num_probes = g_slist_length(o->sdi->channels); /* timestamp */ t = time(NULL); @@ -95,8 +95,8 @@ static int init(struct sr_output *o) g_string_append_printf(ctx->header, "$version %s %s $end\n", PACKAGE, PACKAGE_VERSION); - if (sr_config_get(o->sdi->driver, SR_CONF_SAMPLERATE, &gvar, - o->sdi) == SR_OK) { + if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL, + SR_CONF_SAMPLERATE, &gvar) == SR_OK) { ctx->samplerate = g_variant_get_uint64(gvar); g_variant_unref(gvar); if (!((samplerate_s = sr_samplerate_string(ctx->samplerate)))) { @@ -129,7 +129,7 @@ static int init(struct sr_output *o) g_string_append_printf(ctx->header, "$scope module %s $end\n", PACKAGE); /* Wires / channels */ - for (i = 0, l = o->sdi->probes; l; l = l->next, i++) { + for (i = 0, l = o->sdi->channels; l; l = l->next, i++) { probe = l->data; if (!probe->enabled) continue; diff --git a/libsigrok4DSLogic/output/text/text.c b/libsigrok4DSLogic/output/text/text.c index a2b8b20ec0962ee2baf11e000d5e549c2ecb57e9..99d20dfdd8e42ad56a88ae4e959f0e128c32ae3e 100644 --- a/libsigrok4DSLogic/output/text/text.c +++ b/libsigrok4DSLogic/output/text/text.c @@ -81,7 +81,7 @@ SR_PRIV void flush_linebufs(struct context *ctx, uint8_t *outbuf) SR_PRIV int init(struct sr_output *o, int default_spl, enum outputmode mode) { struct context *ctx; - struct sr_probe *probe; + struct sr_channel *probe; GSList *l; GVariant *gvar; uint64_t samplerate; @@ -97,7 +97,7 @@ SR_PRIV int init(struct sr_output *o, int default_spl, enum outputmode mode) ctx->num_enabled_probes = 0; ctx->probenames = NULL; - for (l = o->sdi->probes; l; l = l->next) { + for (l = o->sdi->channels; l; l = l->next) { probe = l->data; if (!probe->enabled) continue; @@ -128,9 +128,9 @@ SR_PRIV int init(struct sr_output *o, int default_spl, enum outputmode mode) } snprintf(ctx->header, 511, "%s\n", PACKAGE_STRING); - num_probes = g_slist_length(o->sdi->probes); - if (sr_config_get(o->sdi->driver, SR_CONF_SAMPLERATE, &gvar, - o->sdi) == SR_OK) { + num_probes = g_slist_length(o->sdi->channels); + if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL, + SR_CONF_SAMPLERATE, &gvar) == SR_OK) { samplerate = g_variant_get_uint64(gvar); g_variant_unref(gvar); if (!(samplerate_s = sr_samplerate_string(samplerate))) { diff --git a/libsigrok4DSLogic/proto.h b/libsigrok4DSLogic/proto.h index 93b9b8862dd6439aafee8f81b72835de6587ebe0..6e87d0ef43138b1fe03858c9f375f63468791f01 100644 --- a/libsigrok4DSLogic/proto.h +++ b/libsigrok4DSLogic/proto.h @@ -53,6 +53,7 @@ SR_API int sr_dev_trigger_set(const struct sr_dev_inst *sdi, int probenum, const char *trigger); SR_API gboolean sr_dev_has_option(const struct sr_dev_inst *sdi, int key); SR_API GSList *sr_dev_list(const struct sr_dev_driver *driver); +SR_API GSList *sr_dev_mode_list(const struct sr_dev_driver *driver); SR_API int sr_dev_clear(const struct sr_dev_driver *driver); SR_API int sr_dev_open(struct sr_dev_inst *sdi); SR_API int sr_dev_close(struct sr_dev_inst *sdi); @@ -70,14 +71,22 @@ SR_API struct sr_dev_driver **sr_driver_list(void); SR_API int sr_driver_init(struct sr_context *ctx, struct sr_dev_driver *driver); SR_API GSList *sr_driver_scan(struct sr_dev_driver *driver, GSList *options); -SR_API int sr_config_get(const struct sr_dev_driver *driver, int key, - GVariant **data, const struct sr_dev_inst *sdi); -SR_API int sr_config_set(const struct sr_dev_inst *sdi, int key, - GVariant *data); -SR_API int sr_config_list(const struct sr_dev_driver *driver, int key, - GVariant **data, const struct sr_dev_inst *sdi); +SR_API int sr_config_get(const struct sr_dev_driver *driver, + const struct sr_dev_inst *sdi, + const struct sr_channel *ch, + const struct sr_channel_group *cg, + int key, GVariant **data); +SR_API int sr_config_set(const struct sr_dev_inst *sdi, + const struct sr_channel *ch, + const struct sr_channel_group *cg, + int key, GVariant *data); +SR_API int sr_config_list(const struct sr_dev_driver *driver, + const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg, + int key, GVariant **data); SR_API const struct sr_config_info *sr_config_info_get(int key); SR_API const struct sr_config_info *sr_config_info_name_get(const char *optname); +SR_API int sr_status_get(const struct sr_dev_inst *sdi, struct sr_status *status); /*--- session.c -------------------------------------------------------------*/ @@ -90,6 +99,7 @@ SR_API struct sr_session *sr_session_new(void); SR_API int sr_session_destroy(void); SR_API int sr_session_dev_remove_all(void); SR_API int sr_session_dev_add(const struct sr_dev_inst *sdi); +SR_API int sr_session_dev_list(GSList **devlist); /* Datafeed setup */ SR_API int sr_session_datafeed_callback_remove_all(void); @@ -102,6 +112,10 @@ SR_API int sr_session_run(void); SR_API int sr_session_stop(void); SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, unsigned char *buf, int unitsize, int units); +SR_API int sr_session_save_init(const char *filename, uint64_t samplerate, + char **channels); +SR_API int sr_session_append(const char *filename, unsigned char *buf, + int unitsize, int units); SR_API int sr_session_source_add(int fd, int events, int timeout, sr_receive_data_callback_t cb, const struct sr_dev_inst *sdi); SR_API int sr_session_source_add_pollfd(GPollFD *pollfd, int timeout, @@ -125,6 +139,7 @@ SR_API struct sr_output_format **sr_output_list(void); SR_API char *sr_si_string_u64(uint64_t x, const char *unit); SR_API char *sr_iec_string_u64(uint64_t x, const char *unit); SR_API char *sr_samplerate_string(uint64_t samplerate); +SR_API char *sr_samplecount_string(uint64_t samplecount); SR_API char *sr_period_string(uint64_t frequency); SR_API char *sr_voltage_string(uint64_t v_p, uint64_t v_q); SR_API char **sr_parse_triggerstring(const struct sr_dev_inst *sdi, diff --git a/libsigrok4DSLogic/session.c b/libsigrok4DSLogic/session.c index 13f39a40c91354a65b8d4be69e93d840552866fc..3a4423824ef8754552019a2bdbcfcd52491e8e9e 100644 --- a/libsigrok4DSLogic/session.c +++ b/libsigrok4DSLogic/session.c @@ -129,6 +129,34 @@ SR_API int sr_session_destroy(void) return SR_OK; } +/** + * List all device instances attached to the current session. + * + * @param devlist A pointer where the device instance list will be + * stored on return. If no devices are in the session, + * this will be NULL. Each element in the list points + * to a struct sr_dev_inst *. + * The list must be freed by the caller, but not the + * elements pointed to. + * + * @retval SR_OK Success. + * @retval SR_ERR Invalid argument. + * + * @since 0.3.0 + */ +SR_API int sr_session_dev_list(GSList **devlist) +{ + + *devlist = NULL; + + if (!session) + return SR_ERR; + + *devlist = g_slist_copy(session->devs); + + return SR_OK; +} + /** * Remove all the devices from the current session. * diff --git a/libsigrok4DSLogic/session_driver.c b/libsigrok4DSLogic/session_driver.c index b040c07272eea7db84491b4ef4920dc11601f607..5963d428e8d7fd0bc5aefdc4e0c3c998cb1b41ca 100644 --- a/libsigrok4DSLogic/session_driver.c +++ b/libsigrok4DSLogic/session_driver.c @@ -40,6 +40,9 @@ #define CHUNKSIZE (512 * 1024) /** @endcond */ +static uint64_t samplerates[1]; +static uint64_t samplecounts[1]; + struct session_vdev { char *sessionfile; char *capturefile; @@ -100,9 +103,9 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *cb_sdi) } else { /* done with this capture file */ zip_fclose(vdev->capfile); - g_free(vdev->capturefile); - g_free(vdev); - sdi->priv = NULL; + //g_free(vdev->capturefile); + //g_free(vdev); + //sdi->priv = NULL; } } @@ -116,16 +119,16 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *cb_sdi) } /* driver callbacks */ -static int hw_cleanup(void); +static int dev_clear(void); -static int hw_init(struct sr_context *sr_ctx) +static int init(struct sr_context *sr_ctx) { (void)sr_ctx; return SR_OK; } -static int hw_cleanup(void) +static int dev_clear(void) { GSList *l; @@ -137,7 +140,7 @@ static int hw_cleanup(void) return SR_OK; } -static int hw_dev_open(struct sr_dev_inst *sdi) +static int dev_open(struct sr_dev_inst *sdi) { if (!(sdi->priv = g_try_malloc0(sizeof(struct session_vdev)))) { sr_err("%s: sdi->priv malloc failed", __func__); @@ -149,6 +152,18 @@ static int hw_dev_open(struct sr_dev_inst *sdi) return SR_OK; } +static int dev_close(struct sr_dev_inst *sdi) +{ + const struct session_vdev *const vdev = sdi->priv; + g_free(vdev->sessionfile); + g_free(vdev->capturefile); + + g_free(sdi->priv); + sdi->priv = NULL; + + return SR_OK; +} + static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi) { struct session_vdev *vdev; @@ -184,6 +199,7 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi) switch (id) { case SR_CONF_SAMPLERATE: vdev->samplerate = g_variant_get_uint64(data); + samplerates[0] = vdev->samplerate; sr_info("Setting samplerate to %" PRIu64 ".", vdev->samplerate); break; case SR_CONF_SESSIONFILE: @@ -199,6 +215,8 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi) break; case SR_CONF_LIMIT_SAMPLES: vdev->total_samples = g_variant_get_uint64(data); + samplecounts[0] = vdev->total_samples; + sr_info("Setting limit samples to %" PRIu64 ".", vdev->total_samples); break; case SR_CONF_CAPTURE_NUM_PROBES: vdev->num_probes = g_variant_get_uint64(data); @@ -213,6 +231,8 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi) static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) { + GVariant *gvar; + GVariantBuilder gvb; (void)sdi; @@ -223,6 +243,22 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"), hwcaps, ARRAY_SIZE(hwcaps)*sizeof(int32_t), TRUE, NULL, NULL); break; + case SR_CONF_SAMPLERATE: + g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); +// gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates, +// ARRAY_SIZE(samplerates), sizeof(uint64_t)); + gvar = g_variant_new_from_data(G_VARIANT_TYPE("at"), + samplerates, ARRAY_SIZE(samplerates)*sizeof(uint64_t), TRUE, NULL, NULL); + g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); + *data = g_variant_builder_end(&gvb); + break; + case SR_CONF_LIMIT_SAMPLES: + g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); + gvar = g_variant_new_from_data(G_VARIANT_TYPE("at"), + samplecounts, ARRAY_SIZE(samplecounts)*sizeof(uint64_t), TRUE, NULL, NULL); + g_variant_builder_add(&gvb, "{sv}", "samplecounts", gvar); + *data = g_variant_builder_end(&gvb); + break; default: return SR_ERR_ARG; } @@ -230,7 +266,7 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) return SR_OK; } -static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi, +static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct zip_stat zs; @@ -271,16 +307,23 @@ static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi, /** @private */ SR_PRIV struct sr_dev_driver session_driver = { - .name = "virtual-session", - .longname = "Session-emulating driver", - .api_version = 1, - .init = hw_init, - .cleanup = hw_cleanup, - .config_get = config_get, - .config_set = config_set, - .config_list = config_list, - .dev_open = hw_dev_open, - .dev_close = NULL, - .dev_acquisition_start = hw_dev_acquisition_start, - .dev_acquisition_stop = NULL, + .name = "virtual-session", + .longname = "Session-emulating driver", + .api_version = 1, + .init = init, + .cleanup = dev_clear, + .scan = NULL, + .dev_list = NULL, + .dev_mode_list = NULL, + .dev_clear = dev_clear, + .config_get = config_get, + .config_set = config_set, + .config_list = config_list, + .dev_open = dev_open, + .dev_close = dev_close, + .dev_test = NULL, + .dev_status_get = NULL, + .dev_acquisition_start = dev_acquisition_start, + .dev_acquisition_stop = NULL, + .priv = NULL, }; diff --git a/libsigrok4DSLogic/session_file.c b/libsigrok4DSLogic/session_file.c index 43ba01c37d6ae74af8e26185fe283330437f8476..f5592e4f3a20aefa1a8b3f18d03fdbac0c764ce8 100644 --- a/libsigrok4DSLogic/session_file.c +++ b/libsigrok4DSLogic/session_file.c @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #include #include #include "config.h" /* Needed for PACKAGE_VERSION and others. */ @@ -51,6 +54,55 @@ extern struct sr_session *session; extern SR_PRIV struct sr_dev_driver session_driver; +/** @private */ +SR_PRIV int sr_sessionfile_check(const char *filename) +{ + struct stat st; + struct zip *archive; + struct zip_file *zf; + struct zip_stat zs; + int version, ret; + char s[11]; + + if (!filename) + return SR_ERR_ARG; + + if (stat(filename, &st) == -1) { + sr_err("Couldn't stat %s: %s", filename, strerror(errno)); + return SR_ERR; + } + + if (!(archive = zip_open(filename, 0, &ret))) + /* No logging: this can be used just to check if it's + * a sigrok session file or not. */ + return SR_ERR; + + /* check "version" */ + version = 0; + if (!(zf = zip_fopen(archive, "version", 0))) { + sr_dbg("Not a sigrok session file: no version found."); + return SR_ERR; + } + if ((ret = zip_fread(zf, s, 10)) == -1) + return SR_ERR; + zip_fclose(zf); + s[ret] = 0; + version = strtoull(s, NULL, 10); + if (version > 2) { + sr_dbg("Cannot handle sigrok session file version %d.", version); + return SR_ERR; + } + sr_spew("Detected sigrok session file version %d.", version); + + /* read "metadata" */ + if (zip_stat(archive, "metadata", 0, &zs) == -1) { + sr_dbg("Not a valid sigrok session file."); + return SR_ERR; + } + + return SR_OK; +} + /** * Load the session from the specified filename. * @@ -68,7 +120,7 @@ SR_API int sr_session_load(const char *filename) struct zip_file *zf; struct zip_stat zs; struct sr_dev_inst *sdi; - struct sr_probe *probe; + struct sr_channel *probe; int ret, probenum, devcnt, version, i, j; uint64_t tmp_u64, total_probes, enabled_probes, p; char **sections, **keys, *metafile, *val, s[11]; @@ -130,32 +182,32 @@ SR_API int sr_session_load(const char *filename) sr_dev_open(sdi); sr_session_dev_add(sdi); sdi->driver->config_set(SR_CONF_SESSIONFILE, - g_variant_new_string(filename), sdi); + g_variant_new_string(filename), sdi, NULL, NULL); sdi->driver->config_set(SR_CONF_CAPTUREFILE, - g_variant_new_string(val), sdi); + g_variant_new_string(val), sdi, NULL, NULL); g_ptr_array_add(capturefiles, val); } else if (!strcmp(keys[j], "samplerate")) { sr_parse_sizestring(val, &tmp_u64); sdi->driver->config_set(SR_CONF_SAMPLERATE, - g_variant_new_uint64(tmp_u64), sdi); + g_variant_new_uint64(tmp_u64), sdi, NULL, NULL); } else if (!strcmp(keys[j], "unitsize")) { tmp_u64 = strtoull(val, NULL, 10); sdi->driver->config_set(SR_CONF_CAPTURE_UNITSIZE, - g_variant_new_uint64(tmp_u64), sdi); + g_variant_new_uint64(tmp_u64), sdi, NULL, NULL); } else if (!strcmp(keys[j], "total samples")) { tmp_u64 = strtoull(val, NULL, 10); sdi->driver->config_set(SR_CONF_LIMIT_SAMPLES, - g_variant_new_uint64(tmp_u64), sdi); + g_variant_new_uint64(tmp_u64), sdi, NULL, NULL); } else if (!strcmp(keys[j], "total probes")) { total_probes = strtoull(val, NULL, 10); sdi->driver->config_set(SR_CONF_CAPTURE_NUM_PROBES, - g_variant_new_uint64(total_probes), sdi); + g_variant_new_uint64(total_probes), sdi, NULL, NULL); for (p = 0; p < total_probes; p++) { snprintf(probename, SR_MAX_PROBENAME_LEN, "%" PRIu64, p); - if (!(probe = sr_probe_new(p, SR_PROBE_LOGIC, TRUE, + if (!(probe = sr_channel_new(p, SR_CHANNEL_LOGIC, TRUE, probename))) return SR_ERR; - sdi->probes = g_slist_append(sdi->probes, probe); + sdi->channels = g_slist_append(sdi->channels, probe); } } else if (!strncmp(keys[j], "probe", 5)) { if (!sdi) @@ -202,7 +254,7 @@ SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, GSList *l; GVariant *gvar; FILE *meta; - struct sr_probe *probe; + struct sr_channel *probe; struct zip *zipfile; struct zip_source *versrc, *metasrc, *logicsrc; int tmpfile, ret, probecnt; @@ -237,10 +289,10 @@ SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, fprintf(meta, "capturefile = data\n"); fprintf(meta, "unitsize = %d\n", unitsize); fprintf(meta, "total samples = %d\n", units); - fprintf(meta, "total probes = %d\n", g_slist_length(sdi->probes)); + fprintf(meta, "total probes = %d\n", g_slist_length(sdi->channels)); if (sr_dev_has_option(sdi, SR_CONF_SAMPLERATE)) { - if (sr_config_get(sdi->driver, SR_CONF_SAMPLERATE, - &gvar, sdi) == SR_OK) { + if (sr_config_get(sdi->driver, sdi, NULL, NULL, SR_CONF_SAMPLERATE, + &gvar) == SR_OK) { samplerate = g_variant_get_uint64(gvar); s = sr_samplerate_string(samplerate); fprintf(meta, "samplerate = %s\n", s); @@ -249,7 +301,7 @@ SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, } } probecnt = 1; - for (l = sdi->probes; l; l = l->next) { + for (l = sdi->channels; l; l = l->next) { probe = l->data; if (probe->enabled) { if (probe->name) @@ -283,4 +335,229 @@ SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, return SR_OK; } +/** + * Initialize a saved session file. + * + * @param filename The name of the filename to save the current session as. + * Must not be NULL. + * @param samplerate The samplerate to store for this session. + * @param channels A NULL-terminated array of strings containing the names + * of all the channels active in this session. + * + * @retval SR_OK Success + * @retval SR_ERR_ARG Invalid arguments + * @retval SR_ERR Other errors + * + * @since 0.3.0 + */ +SR_API int sr_session_save_init(const char *filename, uint64_t samplerate, + char **channels) +{ + FILE *meta; + struct zip *zipfile; + struct zip_source *versrc, *metasrc; + int tmpfile, cnt, ret, i; + char version[1], metafile[32], *s; + + if (!filename) { + sr_err("%s: filename was NULL", __func__); + return SR_ERR_ARG; + } + + /* Quietly delete it first, libzip wants replace ops otherwise. */ + unlink(filename); + if (!(zipfile = zip_open(filename, ZIP_CREATE, &ret))) + return SR_ERR; + + /* "version" */ + version[0] = '2'; + if (!(versrc = zip_source_buffer(zipfile, version, 1, 0))) + return SR_ERR; + if (zip_add(zipfile, "version", versrc) == -1) { + sr_info("error saving version into zipfile: %s", + zip_strerror(zipfile)); + return SR_ERR; + } + + /* init "metadata" */ + strcpy(metafile, "sigrok-meta-XXXXXX"); + if ((tmpfile = g_mkstemp(metafile)) == -1) + return SR_ERR; + close(tmpfile); + meta = g_fopen(metafile, "wb"); + fprintf(meta, "[global]\n"); + fprintf(meta, "sigrok version = %s\n", PACKAGE_VERSION); + + /* metadata */ + fprintf(meta, "[device 1]\n"); + + /* metadata */ + fprintf(meta, "capturefile = logic-1\n"); + cnt = 0; + for (i = 0; channels[i]; i++) + cnt++; + fprintf(meta, "total probes = %d\n", cnt); + s = sr_samplerate_string(samplerate); + fprintf(meta, "samplerate = %s\n", s); + g_free(s); + + for (i = 0; channels[i]; i++) + fprintf(meta, "probe%d = %s\n", i + 1, channels[i]); + + fclose(meta); + + if (!(metasrc = zip_source_file(zipfile, metafile, 0, -1))) { + unlink(metafile); + return SR_ERR; + } + if (zip_add(zipfile, "metadata", metasrc) == -1) { + unlink(metafile); + return SR_ERR; + } + + if ((ret = zip_close(zipfile)) == -1) { + sr_info("error saving zipfile: %s", zip_strerror(zipfile)); + unlink(metafile); + return SR_ERR; + } + + unlink(metafile); + + return SR_OK; +} + +/** + * Append data to an existing session file. + * + * The session file must have been created with sr_session_save_init() + * or sr_session_save() beforehand. + * + * @param filename The name of the filename to append to. Must not be NULL. + * @param buf The data to be appended. + * @param unitsize The number of bytes per sample. + * @param units The number of samples. + * + * @retval SR_OK Success + * @retval SR_ERR_ARG Invalid arguments + * @retval SR_ERR Other errors + * + * @since 0.3.0 + */ +SR_API int sr_session_append(const char *filename, unsigned char *buf, + int unitsize, int units) +{ + struct zip *archive; + struct zip_source *logicsrc; + zip_int64_t num_files; + struct zip_file *zf; + struct zip_stat zs; + struct zip_source *metasrc; + GKeyFile *kf; + GError *error; + gsize len; + int chunk_num, next_chunk_num, tmpfile, ret, i; + const char *entry_name; + char *metafile, tmpname[32], chunkname[16]; + + if ((ret = sr_sessionfile_check(filename)) != SR_OK) + return ret; + + if (!(archive = zip_open(filename, 0, &ret))) + return SR_ERR; + + if (zip_stat(archive, "metadata", 0, &zs) == -1) + return SR_ERR; + + metafile = g_malloc(zs.size); + zf = zip_fopen_index(archive, zs.index, 0); + zip_fread(zf, metafile, zs.size); + zip_fclose(zf); + + /* + * If the file was only initialized but doesn't yet have any + * data it in, it won't have a unitsize field in metadata yet. + */ + error = NULL; + kf = g_key_file_new(); + if (!g_key_file_load_from_data(kf, metafile, zs.size, 0, &error)) { + sr_err("Failed to parse metadata: %s.", error->message); + return SR_ERR; + } + g_free(metafile); + tmpname[0] = '\0'; + if (!g_key_file_has_key(kf, "device 1", "unitsize", &error)) { + if (error && error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) { + sr_err("Failed to check unitsize key: %s", error ? error->message : "?"); + return SR_ERR; + } + /* Add unitsize field. */ + g_key_file_set_integer(kf, "device 1", "unitsize", unitsize); + metafile = g_key_file_to_data(kf, &len, &error); + strcpy(tmpname, "sigrok-meta-XXXXXX"); + if ((tmpfile = g_mkstemp(tmpname)) == -1) + return SR_ERR; + if (write(tmpfile, metafile, len) < 0) { + sr_dbg("Failed to create new metadata: %s", strerror(errno)); + g_free(metafile); + unlink(tmpname); + return SR_ERR; + } + close(tmpfile); + if (!(metasrc = zip_source_file(archive, tmpname, 0, -1))) { + sr_err("Failed to create zip source for metadata."); + g_free(metafile); + unlink(tmpname); + return SR_ERR; + } + if (zip_replace(archive, zs.index, metasrc) == -1) { + sr_err("Failed to replace metadata file."); + g_free(metafile); + unlink(tmpname); + return SR_ERR; + } + g_free(metafile); + } + g_key_file_free(kf); + + next_chunk_num = 1; + num_files = zip_get_num_entries(archive, 0); + for (i = 0; i < num_files; i++) { + entry_name = zip_get_name(archive, i, 0); + if (strncmp(entry_name, "logic-1", 7)) + continue; + if (strlen(entry_name) == 7) { + /* This file has no extra chunks, just a single "logic-1". + * Rename it to "logic-1-1" * and continue with chunk 2. */ + if (zip_rename(archive, i, "logic-1-1") == -1) { + sr_err("Failed to rename 'logic-1' to 'logic-1-1'."); + unlink(tmpname); + return SR_ERR; + } + next_chunk_num = 2; + break; + } else if (strlen(entry_name) > 8 && entry_name[7] == '-') { + chunk_num = strtoull(entry_name + 8, NULL, 10); + if (chunk_num >= next_chunk_num) + next_chunk_num = chunk_num + 1; + } + } + snprintf(chunkname, 15, "logic-1-%d", next_chunk_num); + if (!(logicsrc = zip_source_buffer(archive, buf, units * unitsize, FALSE))) { + unlink(tmpname); + return SR_ERR; + } + if (zip_add(archive, chunkname, logicsrc) == -1) { + unlink(tmpname); + return SR_ERR; + } + if ((ret = zip_close(archive)) == -1) { + sr_info("error saving session file: %s", zip_strerror(archive)); + unlink(tmpname); + return SR_ERR; + } + unlink(tmpname); + + return SR_OK; +} + /** @} */ diff --git a/libsigrok4DSLogic/strutil.c b/libsigrok4DSLogic/strutil.c index 68efe7e797e58e912f639c068f90b2115afabe2b..1b05ebc469ceb84b671137acdaaaad15f6467e53 100644 --- a/libsigrok4DSLogic/strutil.c +++ b/libsigrok4DSLogic/strutil.c @@ -82,7 +82,7 @@ SR_API char *sr_si_string_u64(uint64_t x, const char *unit) return g_strdup_printf("%" PRIu64 " k%s", x / SR_KHZ(1), unit); } else if ((x >= SR_KHZ(1)) && (x % SR_KHZ(1) != 0)) { - return g_strdup_printf("%" PRIu64 ".%" PRIu64 " k%s", + return g_strdup_printf("%" PRIu64 ".%" PRIu64 " K%s", x / SR_KHZ(1), x % SR_KHZ(1), unit); } else { return g_strdup_printf("%" PRIu64 " %s", x, unit); @@ -115,19 +115,19 @@ SR_API char *sr_iec_string_u64(uint64_t x, const char *unit) if ((x >= SR_GB(1)) && (x % SR_GB(1) == 0)) { return g_strdup_printf("%" PRIu64 " G%s", x / SR_GB(1), unit); } else if ((x >= SR_GB(1)) && (x % SR_GB(1) != 0)) { - return g_strdup_printf("%" PRIu64 ".%" PRIu64 " G%s", + return g_strdup_printf("%" PRIu64 ".%" PRIu64 "G%s", x / SR_GB(1), x % SR_GB(1), unit); } else if ((x >= SR_MB(1)) && (x % SR_MB(1) == 0)) { return g_strdup_printf("%" PRIu64 " M%s", x / SR_MB(1), unit); } else if ((x >= SR_MB(1)) && (x % SR_MB(1) != 0)) { - return g_strdup_printf("%" PRIu64 ".%" PRIu64 " M%s", + return g_strdup_printf("%" PRIu64 ".%" PRIu64 "M%s", x / SR_MB(1), x % SR_MB(1), unit); } else if ((x >= SR_KB(1)) && (x % SR_KB(1) == 0)) { return g_strdup_printf("%" PRIu64 " k%s", x / SR_KB(1), unit); } else if ((x >= SR_KB(1)) && (x % SR_KB(1) != 0)) { - return g_strdup_printf("%" PRIu64 ".%" PRIu64 " k%s", + return g_strdup_printf("%" PRIu64 ".%" PRIu64 "K%s", x / SR_KB(1), x % SR_KB(1), unit); } else { return g_strdup_printf("%" PRIu64 " %s", x, unit); @@ -154,6 +154,22 @@ SR_API char *sr_samplerate_string(uint64_t samplerate) return sr_si_string_u64(samplerate, "Hz"); } +/** + * Convert a numeric samplecount value to its "natural" string representation. + * + * E.g. a value of 16384 would be converted to "16 K" + * + * @param samplecount. + * + * @return A g_try_malloc()ed string representation of the samplecount value, + * or NULL upon errors. The caller is responsible to g_free() the + * memory. + */ +SR_API char *sr_samplecount_string(uint64_t samplecount) +{ + return sr_iec_string_u64(samplecount, " Samples"); +} + /** * Convert a numeric frequency value to the "natural" string representation * of its period. @@ -263,13 +279,13 @@ SR_API char **sr_parse_triggerstring(const struct sr_dev_inst *sdi, { GSList *l; GVariant *gvar; - struct sr_probe *probe; + struct sr_channel *probe; int max_probes, probenum, i; char **tokens, **triggerlist, *trigger, *tc; const char *trigger_types; gboolean error; - max_probes = g_slist_length(sdi->probes); + max_probes = g_slist_length(sdi->channels); error = FALSE; if (!(triggerlist = g_try_malloc0(max_probes * sizeof(char *)))) { @@ -277,7 +293,7 @@ SR_API char **sr_parse_triggerstring(const struct sr_dev_inst *sdi, return NULL; } - if (sdi->driver->config_list(SR_CONF_TRIGGER_TYPE, &gvar, sdi) != SR_OK) { + if (sdi->driver->config_list(SR_CONF_TRIGGER_TYPE, &gvar, sdi, NULL) != SR_OK) { sr_err("%s: Device doesn't support any triggers.", __func__); return NULL; } @@ -286,8 +302,8 @@ SR_API char **sr_parse_triggerstring(const struct sr_dev_inst *sdi, tokens = g_strsplit(triggerstring, ",", max_probes); for (i = 0; tokens[i]; i++) { probenum = -1; - for (l = sdi->probes; l; l = l->next) { - probe = (struct sr_probe *)l->data; + for (l = sdi->channels; l; l = l->next) { + probe = (struct sr_channel *)l->data; if (probe->enabled && !strncmp(probe->name, tokens[i], strlen(probe->name))) {