diff --git a/.gitignore b/.gitignore index caa12f24..2b0f916e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ *.lo CMakeFiles CMakeCache.txt +*.cxx_parameters autom4te.cache *.cmake !cmake_modules diff --git a/DSView/CMake/FindFFTW.cmake b/DSView/CMake/FindFFTW.cmake new file mode 100644 index 00000000..df9c8b38 --- /dev/null +++ b/DSView/CMake/FindFFTW.cmake @@ -0,0 +1,71 @@ +# - Find FFTW +# Find the native FFTW includes and library +# This module defines +# FFTW_INCLUDE_DIR, where to find fftw3.h, etc. +# FFTW_LIBRARIES, the libraries needed to use FFTW. +# FFTW_FOUND, If false, do not try to use FFTW. +# also defined, but not for general use are +# FFTW_LIBRARY, where to find the FFTW library. + +FIND_PATH(FFTW_INCLUDE_DIR fftw3.h +/usr/local/include +/usr/include +/opt/local/lib +) + +SET(FFTW_NAMES ${FFTW_NAMES} fftw3 fftw3f fftw3-3) +FIND_LIBRARY(FFTW_LIBRARY + NAMES ${FFTW_NAMES} + PATHS /usr/lib /usr/local/lib /opt/locala/lib + ) + +# Find threads part of FFTW + +SET(FFTW_THREADS_NAMES ${FFTW_THREADS_NAMES} fftw3f_threads fftw3_threads fftw3-3_threads) +FIND_LIBRARY(FFTW_THREADS_LIBRARY + NAMES ${FFTW_THREADS_NAMES} + PATHS /usr/lib /usr/local/lib /opt/local/lib + ) + +IF (FFTW_THREADS_LIBRARY AND FFTW_INCLUDE_DIR) + SET(FFTW_THREADS_LIBRARIES ${FFTW_THREADS_LIBRARY}) + SET(FFTW_THREADS_FOUND "YES") +ELSE (FFTW_THREADS_LIBRARY AND FFTW_INCLUDE_DIR) + SET(FFTW_THREADS_FOUND "NO") +ENDIF (FFTW_THREADS_LIBRARY AND FFTW_INCLUDE_DIR) + + +IF (FFTW_THREADS_FOUND) + IF (NOT FFTW_THREADS_FIND_QUIETLY) + MESSAGE(STATUS "Found FFTW threads: ${FFTW_THREADS_LIBRARIES}") + ENDIF (NOT FFTW_THREADS_FIND_QUIETLY) +ELSE (FFTW_THREADS_FOUND) + IF (FFTW_THREADS_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find FFTW threads library") + ENDIF (FFTW_THREADS_FIND_REQUIRED) +ENDIF (FFTW_THREADS_FOUND) + + +IF (FFTW_LIBRARY AND FFTW_INCLUDE_DIR) + SET(FFTW_LIBRARIES ${FFTW_LIBRARY}) + SET(FFTW_FOUND "YES") +ELSE (FFTW_LIBRARY AND FFTW_INCLUDE_DIR) + SET(FFTW_FOUND "NO") +ENDIF (FFTW_LIBRARY AND FFTW_INCLUDE_DIR) + + +IF (FFTW_FOUND) + IF (NOT FFTW_FIND_QUIETLY) + MESSAGE(STATUS "Found FFTW: ${FFTW_LIBRARIES}") + ENDIF (NOT FFTW_FIND_QUIETLY) +ELSE (FFTW_FOUND) + IF (FFTW_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find FFTW library") + ENDIF (FFTW_FIND_REQUIRED) +ENDIF (FFTW_FOUND) + +SET (ON_UNIX ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") +IF (${ON_UNIX}) + SET (FFTW_EXECUTABLE_LIBRARIES fftw3f fftw3f_threads) +ENDIF (${ON_UNIX}) diff --git a/DSView/CMakeLists.txt b/DSView/CMakeLists.txt index c5703c64..fad159d8 100644 --- a/DSView/CMakeLists.txt +++ b/DSView/CMakeLists.txt @@ -93,6 +93,7 @@ find_package(Threads) find_package(Boost 1.42 COMPONENTS filesystem system thread REQUIRED) find_package(libusb-1.0 REQUIRED) +find_package(FFTW REQUIRED) #=============================================================================== #= Config Header @@ -103,7 +104,7 @@ set(DS_DESCRIPTION "A GUI for instruments of DreamSourceLab") set(DS_VERSION_MAJOR 0) set(DS_VERSION_MINOR 9) -set(DS_VERSION_MICRO 5) +set(DS_VERSION_MICRO 6) set(DS_VERSION_STRING ${DS_VERSION_MAJOR}.${DS_VERSION_MINOR}.${DS_VERSION_MICRO} ) @@ -118,107 +119,147 @@ configure_file ( #------------------------------------------------------------------------------- set(DSView_SOURCES - main.cpp - 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/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/deviceoptions.cpp - pv/dialogs/search.cpp - pv/dialogs/storeprogress.cpp - pv/dialogs/streamoptions.cpp - pv/dialogs/waitingdialog.cpp - pv/dialogs/dsomeasure.cpp - pv/dock/dsotriggerdock.cpp - pv/dock/measuredock.cpp - pv/dock/searchdock.cpp - pv/dock/triggerdock.cpp - pv/prop/bool.cpp - pv/prop/double.cpp - 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/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/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/widgets/fakelineedit.cpp + main.cpp + pv/sigsession.cpp + pv/mainwindow.cpp + pv/devicemanager.cpp + pv/data/snapshot.cpp + pv/data/signaldata.cpp + pv/data/logicsnapshot.cpp + pv/data/logic.cpp + pv/data/analogsnapshot.cpp + pv/data/analog.cpp + pv/dialogs/deviceoptions.cpp + pv/prop/property.cpp + pv/prop/int.cpp + pv/prop/enum.cpp + pv/prop/double.cpp + pv/prop/bool.cpp + pv/prop/binding/binding.cpp + pv/toolbars/samplingbar.cpp + pv/view/viewport.cpp + pv/view/view.cpp + pv/view/timemarker.cpp + pv/view/signal.cpp + pv/view/ruler.cpp + pv/view/logicsignal.cpp + pv/view/header.cpp + pv/view/cursor.cpp + pv/view/analogsignal.cpp + pv/prop/binding/binding_deviceoptions.cpp + pv/toolbars/trigbar.cpp + pv/toolbars/filebar.cpp + pv/dock/protocoldock.cpp + pv/dock/triggerdock.cpp + pv/dock/measuredock.cpp + pv/dock/searchdock.cpp + pv/toolbars/logobar.cpp + pv/data/groupsnapshot.cpp + pv/view/groupsignal.cpp + pv/data/group.cpp + pv/dialogs/about.cpp + pv/dialogs/search.cpp + pv/data/dsosnapshot.cpp + pv/data/dso.cpp + pv/view/dsosignal.cpp + pv/view/dsldial.cpp + pv/dock/dsotriggerdock.cpp + pv/view/trace.cpp + pv/view/selectableitem.cpp + pv/data/decoderstack.cpp + pv/data/decode/rowdata.cpp + pv/data/decode/row.cpp + pv/data/decode/decoder.cpp + pv/data/decode/annotation.cpp + pv/view/decodetrace.cpp + pv/prop/binding/decoderoptions.cpp + pv/widgets/fakelineedit.cpp + pv/widgets/decodermenu.cpp + pv/widgets/decodergroupbox.cpp + pv/prop/string.cpp + pv/device/sessionfile.cpp + pv/device/inputfile.cpp + pv/device/file.cpp + pv/device/devinst.cpp + pv/dialogs/storeprogress.cpp + pv/storesession.cpp + pv/view/devmode.cpp + pv/device/device.cpp + pv/dialogs/waitingdialog.cpp + pv/dialogs/dsomeasure.cpp + pv/dialogs/calibration.cpp + pv/data/decodermodel.cpp + pv/dialogs/protocollist.cpp + pv/dialogs/protocolexp.cpp + pv/dialogs/fftoptions.cpp + pv/data/mathstack.cpp + pv/view/mathtrace.cpp + dsapplication.cpp + pv/widgets/viewstatus.cpp + pv/toolbars/titlebar.cpp + pv/mainframe.cpp + pv/widgets/border.cpp + pv/dialogs/dsmessagebox.cpp + pv/dialogs/shadow.cpp + pv/dialogs/dsdialog.cpp ) set(DSView_HEADERS - pv/mainwindow.h - pv/sigsession.h - pv/storesession.h - pv/device/devinst.h - pv/dialogs/about.h - pv/dialogs/deviceoptions.h - pv/dialogs/search.h - pv/dialogs/storeprogress.h - pv/dialogs/streamoptions.h - pv/dialogs/waitingdialog.h - pv/dialogs/dsomeasure.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/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/trace.h - pv/view/view.h - pv/view/viewport.h - pv/widgets/fakelineedit.h + pv/sigsession.h + pv/mainwindow.h + pv/dialogs/deviceoptions.h + pv/prop/property.h + pv/prop/int.h + pv/prop/enum.h + pv/prop/double.h + pv/prop/bool.h + pv/toolbars/samplingbar.h + pv/view/viewport.h + pv/view/view.h + pv/view/timemarker.h + pv/view/ruler.h + pv/view/header.h + pv/view/cursor.h + pv/toolbars/trigbar.h + pv/toolbars/filebar.h + pv/dock/protocoldock.h + pv/dock/triggerdock.h + pv/dock/measuredock.h + pv/dock/searchdock.h + pv/toolbars/logobar.h + pv/dialogs/about.h + pv/dialogs/search.h + pv/dock/dsotriggerdock.h + pv/view/trace.h + pv/view/selectableitem.h + pv/data/decoderstack.h + pv/view/decodetrace.h + pv/widgets/fakelineedit.h + pv/widgets/decodermenu.h + pv/widgets/decodergroupbox.h + pv/prop/string.h + pv/device/devinst.h + pv/dialogs/storeprogress.h + pv/storesession.h + pv/view/devmode.h + pv/dialogs/waitingdialog.h + pv/dialogs/dsomeasure.h + pv/dialogs/calibration.h + pv/dialogs/protocollist.h + pv/dialogs/protocolexp.h + pv/dialogs/fftoptions.h + pv/data/mathstack.h + pv/view/mathtrace.h + pv/widgets/viewstatus.h + pv/toolbars/titlebar.h + pv/mainframe.h + pv/widgets/border.h + pv/dialogs/dsmessagebox.h + pv/dialogs/shadow.h + pv/dialogs/dsdialog.h ) set(DSView_FORMS - pv/dialogs/about.ui ) set(DSView_RESOURCES @@ -310,6 +351,7 @@ set(DSVIEW_LINK_LIBS ${CMAKE_THREAD_LIBS_INIT} ${QT_LIBRARIES} ${LIBUSB_1_LIBRARIES} + ${FFTW_LIBRARIES} ) if(STATIC_PKGDEPS_LIBS) @@ -352,21 +394,11 @@ 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/DSLogic33.bin DESTINATION bin/res/) -install(FILES res/DSLogic50.bin DESTINATION bin/res/) -install(FILES res/DSLogicPro.fw DESTINATION bin/res/) -install(FILES res/DSLogicPro.bin DESTINATION bin/res/) -install(FILES res/DSCope.fw DESTINATION bin/res/) -install(FILES res/DSCope.bin DESTINATION bin/res/) -install(FILES res/DSLogic0.dsc DESTINATION bin/res/) -install(FILES res/DSLogic0.def.dsc DESTINATION bin/res/) -install(FILES res/DSLogic1.dsc DESTINATION bin/res/) -install(FILES res/DSLogic1.def.dsc DESTINATION bin/res/) -install(FILES res/DSLogic2.dsc DESTINATION bin/res/) -install(FILES res/DSLogic2.def.dsc DESTINATION bin/res/) -install(FILES res/DSCope1.dsc DESTINATION bin/res/) -install(FILES res/DSCope1.def.dsc DESTINATION bin/res/) +install(DIRECTORY res DESTINATION share/${PROJECT_NAME}) +install(DIRECTORY ../libsigrokdecode4DSL/decoders DESTINATION share/${PROJECT_NAME}) +install(FILES icons/logo.png DESTINATION share/${PROJECT_NAME} RENAME logo.png) +install(FILES DreamSourceLab.rules DESTINATION /etc/udev/rules.d/) +install(FILES DSView.desktop DESTINATION /usr/share/applications/) #=============================================================================== #= Packaging (handled by CPack) diff --git a/DSView/DSView.desktop b/DSView/DSView.desktop new file mode 100755 index 00000000..fba3202a --- /dev/null +++ b/DSView/DSView.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Version=0.96 +Exec=/usr/local/bin/DSView +Name=DSView +Comment=GUI Program for DreamSourceLab USB-based Instruments +Icon=/usr/local/share/DSView/logo.png +Type=Application +Terminal=false +Categories=Development diff --git a/DSView/DSView.qrc b/DSView/DSView.qrc index 05955d6d..f58808ff 100644 --- a/DSView/DSView.qrc +++ b/DSView/DSView.qrc @@ -36,25 +36,24 @@ icons/gear.png icons/wiki.png icons/wait.gif - icons/file_cn.png - icons/file_dis_cn.png - icons/instant_cn.png - icons/measure_cn.png - icons/measure_dis_cn.png - icons/params_cn.png - icons/params_dis_cn.png - icons/protocol_dis_cn.png - icons/search-bar_cn.png - icons/search-bar_dis_cn.png - icons/start_cn.png - icons/stop_cn.png - icons/trigger_cn.png - icons/trigger_dis_cn.png - icons/protocol_cn.png icons/instant_dis.png - icons/instant_dis_cn.png icons/start_dis.png - icons/start_dis_cn.png icons/settings.png + darkstyle/style.qss + icons/export.png + icons/single.png + icons/single_dis.png + icons/math.png + icons/math_dis.png + icons/fft.png + icons/Blackman.png + icons/Flat_top.png + icons/Hamming.png + icons/Hann.png + icons/Rectangle.png + icons/close.png + icons/maximize.png + icons/minimize.png + icons/restore.png diff --git a/DSView/DreamSourceLab.rules b/DSView/DreamSourceLab.rules new file mode 100644 index 00000000..05f68bad --- /dev/null +++ b/DSView/DreamSourceLab.rules @@ -0,0 +1 @@ +SUBSYSTEM=="usb", ATTRS{idVendor}=="2a0e", MODE="0666" diff --git a/DSView/darkstyle/rc/branch_closed-on.png b/DSView/darkstyle/rc/branch_closed-on.png new file mode 100755 index 00000000..d081e9b3 Binary files /dev/null and b/DSView/darkstyle/rc/branch_closed-on.png differ diff --git a/DSView/darkstyle/rc/branch_closed.png b/DSView/darkstyle/rc/branch_closed.png new file mode 100755 index 00000000..d652159a Binary files /dev/null and b/DSView/darkstyle/rc/branch_closed.png differ diff --git a/DSView/darkstyle/rc/branch_open-on.png b/DSView/darkstyle/rc/branch_open-on.png new file mode 100755 index 00000000..ec372b27 Binary files /dev/null and b/DSView/darkstyle/rc/branch_open-on.png differ diff --git a/DSView/darkstyle/rc/branch_open.png b/DSView/darkstyle/rc/branch_open.png new file mode 100755 index 00000000..66f8e1ac Binary files /dev/null and b/DSView/darkstyle/rc/branch_open.png differ diff --git a/DSView/darkstyle/rc/checkbox_checked.png b/DSView/darkstyle/rc/checkbox_checked.png new file mode 100755 index 00000000..830cfee6 Binary files /dev/null and b/DSView/darkstyle/rc/checkbox_checked.png differ diff --git a/DSView/darkstyle/rc/checkbox_checked_disabled.png b/DSView/darkstyle/rc/checkbox_checked_disabled.png new file mode 100755 index 00000000..cb63cc2f Binary files /dev/null and b/DSView/darkstyle/rc/checkbox_checked_disabled.png differ diff --git a/DSView/darkstyle/rc/checkbox_checked_focus.png b/DSView/darkstyle/rc/checkbox_checked_focus.png new file mode 100755 index 00000000..3cf0e540 Binary files /dev/null and b/DSView/darkstyle/rc/checkbox_checked_focus.png differ diff --git a/DSView/darkstyle/rc/checkbox_indeterminate.png b/DSView/darkstyle/rc/checkbox_indeterminate.png new file mode 100755 index 00000000..41024f76 Binary files /dev/null and b/DSView/darkstyle/rc/checkbox_indeterminate.png differ diff --git a/DSView/darkstyle/rc/checkbox_indeterminate_disabled.png b/DSView/darkstyle/rc/checkbox_indeterminate_disabled.png new file mode 100755 index 00000000..abdc01d9 Binary files /dev/null and b/DSView/darkstyle/rc/checkbox_indeterminate_disabled.png differ diff --git a/DSView/darkstyle/rc/checkbox_indeterminate_focus.png b/DSView/darkstyle/rc/checkbox_indeterminate_focus.png new file mode 100755 index 00000000..a9a16f7e Binary files /dev/null and b/DSView/darkstyle/rc/checkbox_indeterminate_focus.png differ diff --git a/DSView/darkstyle/rc/checkbox_unchecked.png b/DSView/darkstyle/rc/checkbox_unchecked.png new file mode 100755 index 00000000..2159aca9 Binary files /dev/null and b/DSView/darkstyle/rc/checkbox_unchecked.png differ diff --git a/DSView/darkstyle/rc/checkbox_unchecked_disabled.png b/DSView/darkstyle/rc/checkbox_unchecked_disabled.png new file mode 100755 index 00000000..ade721e8 Binary files /dev/null and b/DSView/darkstyle/rc/checkbox_unchecked_disabled.png differ diff --git a/DSView/darkstyle/rc/checkbox_unchecked_focus.png b/DSView/darkstyle/rc/checkbox_unchecked_focus.png new file mode 100755 index 00000000..66f5bf56 Binary files /dev/null and b/DSView/darkstyle/rc/checkbox_unchecked_focus.png differ diff --git a/DSView/darkstyle/rc/close-hover.png b/DSView/darkstyle/rc/close-hover.png new file mode 100755 index 00000000..657943a6 Binary files /dev/null and b/DSView/darkstyle/rc/close-hover.png differ diff --git a/DSView/darkstyle/rc/close-pressed.png b/DSView/darkstyle/rc/close-pressed.png new file mode 100755 index 00000000..937d0059 Binary files /dev/null and b/DSView/darkstyle/rc/close-pressed.png differ diff --git a/DSView/darkstyle/rc/close.png b/DSView/darkstyle/rc/close.png new file mode 100755 index 00000000..bc0f5761 Binary files /dev/null and b/DSView/darkstyle/rc/close.png differ diff --git a/DSView/darkstyle/rc/down_arrow.png b/DSView/darkstyle/rc/down_arrow.png new file mode 100755 index 00000000..e271f7f9 Binary files /dev/null and b/DSView/darkstyle/rc/down_arrow.png differ diff --git a/DSView/darkstyle/rc/down_arrow_disabled.png b/DSView/darkstyle/rc/down_arrow_disabled.png new file mode 100755 index 00000000..5805d984 Binary files /dev/null and b/DSView/darkstyle/rc/down_arrow_disabled.png differ diff --git a/DSView/darkstyle/rc/left_arrow.png b/DSView/darkstyle/rc/left_arrow.png new file mode 100755 index 00000000..f808d2d7 Binary files /dev/null and b/DSView/darkstyle/rc/left_arrow.png differ diff --git a/DSView/darkstyle/rc/left_arrow_disabled.png b/DSView/darkstyle/rc/left_arrow_disabled.png new file mode 100755 index 00000000..f5b9af8a Binary files /dev/null and b/DSView/darkstyle/rc/left_arrow_disabled.png differ diff --git a/DSView/darkstyle/rc/radio_checked.png b/DSView/darkstyle/rc/radio_checked.png new file mode 100755 index 00000000..235e6b0b Binary files /dev/null and b/DSView/darkstyle/rc/radio_checked.png differ diff --git a/DSView/darkstyle/rc/radio_checked_disabled.png b/DSView/darkstyle/rc/radio_checked_disabled.png new file mode 100755 index 00000000..bf0051ed Binary files /dev/null and b/DSView/darkstyle/rc/radio_checked_disabled.png differ diff --git a/DSView/darkstyle/rc/radio_checked_focus.png b/DSView/darkstyle/rc/radio_checked_focus.png new file mode 100755 index 00000000..14b1cb1c Binary files /dev/null and b/DSView/darkstyle/rc/radio_checked_focus.png differ diff --git a/DSView/darkstyle/rc/radio_unchecked.png b/DSView/darkstyle/rc/radio_unchecked.png new file mode 100755 index 00000000..9a4def65 Binary files /dev/null and b/DSView/darkstyle/rc/radio_unchecked.png differ diff --git a/DSView/darkstyle/rc/radio_unchecked_disabled.png b/DSView/darkstyle/rc/radio_unchecked_disabled.png new file mode 100755 index 00000000..6ece890e Binary files /dev/null and b/DSView/darkstyle/rc/radio_unchecked_disabled.png differ diff --git a/DSView/darkstyle/rc/radio_unchecked_focus.png b/DSView/darkstyle/rc/radio_unchecked_focus.png new file mode 100755 index 00000000..27af8112 Binary files /dev/null and b/DSView/darkstyle/rc/radio_unchecked_focus.png differ diff --git a/DSView/darkstyle/rc/right_arrow.png b/DSView/darkstyle/rc/right_arrow.png new file mode 100755 index 00000000..9b0a4e6a Binary files /dev/null and b/DSView/darkstyle/rc/right_arrow.png differ diff --git a/DSView/darkstyle/rc/right_arrow_disabled.png b/DSView/darkstyle/rc/right_arrow_disabled.png new file mode 100755 index 00000000..5c0bee40 Binary files /dev/null and b/DSView/darkstyle/rc/right_arrow_disabled.png differ diff --git a/DSView/darkstyle/rc/sizegrip.png b/DSView/darkstyle/rc/sizegrip.png new file mode 100755 index 00000000..350583aa Binary files /dev/null and b/DSView/darkstyle/rc/sizegrip.png differ diff --git a/DSView/darkstyle/rc/stylesheet-branch-end.png b/DSView/darkstyle/rc/stylesheet-branch-end.png new file mode 100755 index 00000000..cb5d3b51 Binary files /dev/null and b/DSView/darkstyle/rc/stylesheet-branch-end.png differ diff --git a/DSView/darkstyle/rc/stylesheet-branch-more.png b/DSView/darkstyle/rc/stylesheet-branch-more.png new file mode 100755 index 00000000..62711409 Binary files /dev/null and b/DSView/darkstyle/rc/stylesheet-branch-more.png differ diff --git a/DSView/darkstyle/rc/stylesheet-vline.png b/DSView/darkstyle/rc/stylesheet-vline.png new file mode 100755 index 00000000..87536cce Binary files /dev/null and b/DSView/darkstyle/rc/stylesheet-vline.png differ diff --git a/DSView/darkstyle/rc/transparent.png b/DSView/darkstyle/rc/transparent.png new file mode 100755 index 00000000..483df251 Binary files /dev/null and b/DSView/darkstyle/rc/transparent.png differ diff --git a/DSView/darkstyle/rc/undock.png b/DSView/darkstyle/rc/undock.png new file mode 100755 index 00000000..88691d77 Binary files /dev/null and b/DSView/darkstyle/rc/undock.png differ diff --git a/DSView/darkstyle/rc/up_arrow.png b/DSView/darkstyle/rc/up_arrow.png new file mode 100755 index 00000000..abcc7245 Binary files /dev/null and b/DSView/darkstyle/rc/up_arrow.png differ diff --git a/DSView/darkstyle/rc/up_arrow_disabled.png b/DSView/darkstyle/rc/up_arrow_disabled.png new file mode 100755 index 00000000..b9c8e3b5 Binary files /dev/null and b/DSView/darkstyle/rc/up_arrow_disabled.png differ diff --git a/DSView/darkstyle/style.qrc b/DSView/darkstyle/style.qrc new file mode 100755 index 00000000..055e402f --- /dev/null +++ b/DSView/darkstyle/style.qrc @@ -0,0 +1,42 @@ + + + rc/up_arrow_disabled.png + rc/stylesheet-branch-end.png + rc/branch_closed-on.png + rc/stylesheet-vline.png + rc/branch_closed.png + rc/branch_open-on.png + rc/transparent.png + rc/right_arrow_disabled.png + rc/sizegrip.png + rc/close.png + rc/close-hover.png + rc/close-pressed.png + rc/down_arrow.png + rc/left_arrow.png + rc/stylesheet-branch-more.png + rc/up_arrow.png + rc/right_arrow.png + rc/left_arrow_disabled.png + rc/branch_open.png + rc/down_arrow_disabled.png + rc/undock.png + rc/checkbox_checked_disabled.png + rc/checkbox_checked_focus.png + rc/checkbox_checked.png + rc/checkbox_indeterminate.png + rc/checkbox_indeterminate_focus.png + rc/checkbox_unchecked_disabled.png + rc/checkbox_unchecked_focus.png + rc/checkbox_unchecked.png + rc/radio_checked_disabled.png + rc/radio_checked_focus.png + rc/radio_checked.png + rc/radio_unchecked_disabled.png + rc/radio_unchecked_focus.png + rc/radio_unchecked.png + + + style.qss + + diff --git a/DSView/darkstyle/style.qss b/DSView/darkstyle/style.qss new file mode 100755 index 00000000..21455512 --- /dev/null +++ b/DSView/darkstyle/style.qss @@ -0,0 +1,1302 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) <2013-2014> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +QProgressBar:horizontal { + border: 1px solid #3A3939; + text-align: center; + padding: 1px; + background: #201F1F; +} +QProgressBar::chunk:horizontal { + background-color: qlineargradient(spread:reflect, x1:1, y1:0.545, x2:1, y2:0, stop:0 rgba(28, 66, 111, 255), stop:1 rgba(37, 87, 146, 255)); +} + +QToolTip +{ + border: 1px solid #3A3939; + background-color: rgb(90, 102, 117);; + color: white; + padding: 1px; + opacity: 200; +} + +QWidget +{ + color: silver; + background-color: #302F2F; + selection-background-color:#3d8ec9; + selection-color: black; + background-clip: border; + border-image: none; + outline: 0; +} + +QWidget:item:hover +{ + background-color: #78879b; + color: black; +} + +QWidget:item:selected +{ + background-color: #3d8ec9; +} + +QCheckBox +{ + spacing: 5px; + outline: none; + color: #bbb; + margin-bottom: 2px; +} + +QCheckBox:disabled +{ + color: #777777; +} +QCheckBox::indicator, +QGroupBox::indicator +{ + width: 18px; + height: 18px; +} +QGroupBox::indicator +{ + margin-left: 2px; +} + +QCheckBox::indicator:unchecked, +QCheckBox::indicator:unchecked:hover, +QGroupBox::indicator:unchecked, +QGroupBox::indicator:unchecked:hover +{ + image: url(:/qss_icons/rc/checkbox_unchecked.png); +} + +QCheckBox::indicator:unchecked:focus, +QCheckBox::indicator:unchecked:pressed, +QGroupBox::indicator:unchecked:focus, +QGroupBox::indicator:unchecked:pressed +{ + border: none; + image: url(:/qss_icons/rc/checkbox_unchecked_focus.png); +} + +QCheckBox::indicator:checked, +QCheckBox::indicator:checked:hover, +QGroupBox::indicator:checked, +QGroupBox::indicator:checked:hover +{ + image: url(:/qss_icons/rc/checkbox_checked.png); +} + +QCheckBox::indicator:checked:focus, +QCheckBox::indicator:checked:pressed, +QGroupBox::indicator:checked:focus, +QGroupBox::indicator:checked:pressed +{ + border: none; + image: url(:/qss_icons/rc/checkbox_checked_focus.png); +} + +QCheckBox::indicator:indeterminate, +QCheckBox::indicator:indeterminate:hover, +QCheckBox::indicator:indeterminate:pressed +QGroupBox::indicator:indeterminate, +QGroupBox::indicator:indeterminate:hover, +QGroupBox::indicator:indeterminate:pressed +{ + image: url(:/qss_icons/rc/checkbox_indeterminate.png); +} + +QCheckBox::indicator:indeterminate:focus, +QGroupBox::indicator:indeterminate:focus +{ + image: url(:/qss_icons/rc/checkbox_indeterminate_focus.png); +} + +QCheckBox::indicator:checked:disabled, +QGroupBox::indicator:checked:disabled +{ + image: url(:/qss_icons/rc/checkbox_checked_disabled.png); +} + +QCheckBox::indicator:unchecked:disabled, +QGroupBox::indicator:unchecked:disabled +{ + image: url(:/qss_icons/rc/checkbox_unchecked_disabled.png); +} + +QRadioButton +{ + spacing: 5px; + outline: none; + color: #bbb; + margin-bottom: 2px; +} + +QRadioButton:disabled +{ + color: #777777; +} +QRadioButton::indicator +{ + width: 21px; + height: 21px; +} + +QRadioButton::indicator:unchecked, +QRadioButton::indicator:unchecked:hover +{ + image: url(:/qss_icons/rc/radio_unchecked.png); +} + +QRadioButton::indicator:unchecked:focus, +QRadioButton::indicator:unchecked:pressed +{ + border: none; + outline: none; + image: url(:/qss_icons/rc/radio_unchecked_focus.png); +} + +QRadioButton::indicator:checked, +QRadioButton::indicator:checked:hover +{ + border: none; + outline: none; + image: url(:/qss_icons/rc/radio_checked.png); +} + +QRadioButton::indicator:checked:focus, +QRadioButton::indicato::menu-arrowr:checked:pressed +{ + border: none; + outline: none; + image: url(:/qss_icons/rc/radio_checked_focus.png); +} + +QRadioButton::indicator:indeterminate, +QRadioButton::indicator:indeterminate:hover, +QRadioButton::indicator:indeterminate:pressed +{ + image: url(:/qss_icons/rc/radio_indeterminate.png); +} + +QRadioButton::indicator:checked:disabled +{ + outline: none; + image: url(:/qss_icons/rc/radio_checked_disabled.png); +} + +QRadioButton::indicator:unchecked:disabled +{ + image: url(:/qss_icons/rc/radio_unchecked_disabled.png); +} + + +QMenuBar +{ + background-color: #302F2F; + color: silver; +} + +QMenuBar::item +{ + background: transparent; +} + +QMenuBar::item:selected +{ + background: transparent; + border: 1px solid #3A3939; +} + +QMenuBar::item:pressed +{ + border: 1px solid #3A3939; + background-color: #3d8ec9; + color: black; + margin-bottom:-1px; + padding-bottom:1px; +} + +QMenu +{ + border: 1px solid #3A3939; + color: silver; + margin: 0px; +} + +QMenu::item +{ + padding: 5px 30px 5px 30px; + margin-left: 2px; + border: 1px solid transparent; /* reserve space for selection border */ +} + +QMenu::item:selected +{ + color: black; +} + +QMenu::separator { + height: 2px; + background: lightblue; + margin-left: 10px; + margin-right: 5px; +} + +QMenu::indicator { + width: 18px; + height: 18px; +} + +/* non-exclusive indicator = check box style indicator + (see QActionGroup::setExclusive) */ +QMenu::indicator:non-exclusive:unchecked { + image: url(:/qss_icons/rc/checkbox_unchecked.png); +} + +QMenu::indicator:non-exclusive:unchecked:selected { + image: url(:/qss_icons/rc/checkbox_unchecked_disabled.png); +} + +QMenu::indicator:non-exclusive:checked { + image: url(:/qss_icons/rc/checkbox_checked.png); +} + +QMenu::indicator:non-exclusive:checked:selected { + image: url(:/qss_icons/rc/checkbox_checked_disabled.png); +} + +/* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ +QMenu::indicator:exclusive:unchecked { + image: url(:/qss_icons/rc/radio_unchecked.png); +} + +QMenu::indicator:exclusive:unchecked:selected { + image: url(:/qss_icons/rc/radio_unchecked_disabled.png); +} + +QMenu::indicator:exclusive:checked { + image: url(:/qss_icons/rc/radio_checked.png); +} + +QMenu::indicator:exclusive:checked:selected { + image: url(:/qss_icons/rc/radio_checked_disabled.png); +} + +QMenu::right-arrow { + margin: 5px; + image: url(:/qss_icons/rc/right_arrow.png) +} + + +QWidget:disabled +{ + color: #404040; + background-color: #302F2F; +} + +QAbstractItemView +{ + alternate-background-color: #3A3939; + color: silver; + border: 1px solid 3A3939; + border-radius: 2px; + padding: 1px; +} + +QTabWidget:focus, QCheckBox:focus, QRadioButton:focus, QSlider:focus +{ + border: none; +} + +QLineEdit +{ + background-color: #201F1F; + padding: 2px; + border-style: solid; + border: 1px solid #3A3939; + border-radius: 2px; + color: silver; +} + +QGroupBox { + border:1px solid #3A3939; + border-radius: 2px; + margin-top: 20px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top center; + padding-left: 10px; + padding-right: 10px; + padding-top: 10px; +} + +QScrollBar:horizontal +{ + height: 15px; + margin: 3px 15px 3px 15px; + border: 1px transparent #2A2929; + border-radius: 4px; + background-color: #2A2929; +} + +QScrollBar::handle:horizontal +{ + background-color: #605F5F; + min-width: 15px; + border-radius: 4px; +} + +QScrollBar::add-line:horizontal +{ + margin: 0px 3px 0px 3px; + border-image: url(:/qss_icons/rc/right_arrow_disabled.png); + width: 10px; + height: 10px; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal +{ + margin: 0px 3px 0px 3px; + border-image: url(:/qss_icons/rc/left_arrow_disabled.png); + height: 10px; + width: 10px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::add-line:horizontal:hover,QScrollBar::add-line:horizontal:on +{ + border-image: url(:/qss_icons/rc/right_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: right; + subcontrol-origin: margin; +} + + +QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on +{ + border-image: url(:/qss_icons/rc/left_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal +{ + background: none; +} + + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal +{ + background: none; +} + +QScrollBar:vertical +{ + background-color: #2A2929; + width: 15px; + margin: 15px 3px 15px 3px; + border: 1px transparent #2A2929; + border-radius: 4px; +} + +QScrollBar::handle:vertical +{ + background-color: #605F5F; + min-height: 15px; + border-radius: 4px; +} + +QScrollBar::sub-line:vertical +{ + margin: 3px 0px 3px 0px; + border-image: url(:/qss_icons/rc/up_arrow_disabled.png); + height: 10px; + width: 10px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical +{ + margin: 3px 0px 3px 0px; + border-image: url(:/qss_icons/rc/down_arrow_disabled.png); + height: 10px; + width: 10px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover,QScrollBar::sub-line:vertical:on +{ + + border-image: url(:/qss_icons/rc/up_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: top; + subcontrol-origin: margin; +} + + +QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on +{ + border-image: url(:/qss_icons/rc/down_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical +{ + background: none; +} + + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical +{ + background: none; +} + +QTextEdit +{ + background-color: #201F1F; + color: silver; + border: 1px solid #3A3939; + margin: 0; +} + +QPlainTextEdit +{ + background-color: #201F1F;; + color: silver; + border-radius: 2px; + border: 1px solid #3A3939; +} + +QHeaderView::section +{ + background-color: #3A3939; + color: silver; + padding-left: 4px; + border: 1px solid #6c6c6c; +} + +QSizeGrip { + image: url(:/qss_icons/rc/sizegrip.png); + width: 12px; + height: 12px; +} + + +QMenu::separator +{ + height: 1px; + background-color: #3A3939; + color: white; + padding-left: 4px; + margin-left: 10px; + margin-right: 5px; +} + +QFrame +{ + border-radius: 2px; + border: 1px solid #444; +} + +QFrame[frameShape="0"] +{ + border-radius: 2px; + border: 1px transparent #444; +} + +QStackedWidget +{ + border: 1px transparent black; +} + +QToolBar { + border: 1px transparent #393838; + background: 1px solid #302F2F; + font-weight: bold; +} + +QPushButton +{ + color: silver; + background-color: #302F2F; + border-width: 1px; + border-color: #202020; + border-style: solid; + padding-top: 5px; + padding-bottom: 5px; + padding-left: 5px; + padding-right: 5px; + border-radius: 5px; + outline: none; +} + +QPushButton:disabled +{ + background-color: #302F2F; + border-width: 1px; + border-color: #3A3939; + border-style: solid; + padding-top: 5px; + padding-bottom: 5px; + padding-left: 10px; + padding-right: 10px; + border-radius: 5px; + color: #454545; +} + +QComboBox +{ + selection-background-color: #3d8ec9; + background-color: #201F1F; + border-style: solid; + border: 1px solid #3A3939; + border-radius: 2px; + padding: 2px; + min-width: 30px; +} + +QPushButton:checked{ +background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, + stop: 0.5 #6a6868, + stop: 1 #302F2F); +} + +QPushButton:hover +{ +background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, stop: 0.4 #4E4D4D, + stop: 0.5 #6a6868, + stop: 0.6 #4E4D4D, stop: 1 #302F2F); +} + +QComboBox:hover,QAbstractSpinBox:hover,QLineEdit:hover,QTextEdit:hover,QPlainTextEdit:hover,QAbstractView:hover,QTreeView:hover +{ + border: 1px solid #606060; + color: silver; +} + +QComboBox:on +{ + background-color: #626873; + padding-top: 3px; + padding-left: 4px; + selection-background-color: #4a4a4a; +} + +QComboBox QAbstractItemView +{ + background-color: #201F1F; + border-radius: 2px; + border: 1px solid #444; + selection-background-color: #3d8ec9; +} + +QComboBox::drop-down +{ + subcontrol-origin: padding; + subcontrol-position: top right; + width: 15px; + + border-left-width: 0px; + border-left-color: darkgray; + border-left-style: solid; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} + +QComboBox::down-arrow +{ + image: url(:/qss_icons/rc/down_arrow_disabled.png); +} + +QComboBox::down-arrow:on, QComboBox::down-arrow:hover, +QComboBox::down-arrow:focus +{ + image: url(:/qss_icons/rc/down_arrow.png); +} + +QAbstractSpinBox { + padding-top: 2px; + padding-bottom: 2px; + border: 1px solid #3A3939; + background-color: #201F1F; + color: silver; + border-radius: 2px; + min-width: 60px; +} + +QAbstractSpinBox:up-button +{ + background-color: transparent; + subcontrol-origin: border; + subcontrol-position: center right; +} + +QAbstractSpinBox:down-button +{ + background-color: transparent; + subcontrol-origin: border; + subcontrol-position: center left; +} + +QAbstractSpinBox::up-arrow,QAbstractSpinBox::up-arrow:disabled,QAbstractSpinBox::up-arrow:off { + image: url(:/qss_icons/rc/up_arrow_disabled.png); + width: 10px; + height: 10px; +} +QAbstractSpinBox::up-arrow:hover +{ + image: url(:/qss_icons/rc/up_arrow.png); +} + + +QAbstractSpinBox::down-arrow,QAbstractSpinBox::down-arrow:disabled,QAbstractSpinBox::down-arrow:off +{ + image: url(:/qss_icons/rc/down_arrow_disabled.png); + width: 10px; + height: 10px; +} +QAbstractSpinBox::down-arrow:hover +{ + image: url(:/qss_icons/rc/down_arrow.png); +} + + +QLabel +{ + border: 0px solid black; + margin-left: 2px; + margin-right: 2px; +} + +QTabWidget{ + border: 1px transparent black; +} + +QTabWidget::pane { + border: 1px transparent #444; + border-radius: 3px; + padding: 3px; +} + +QTabBar +{ + qproperty-drawBase: 0; + left: 5px; /* move to the right by 5px */ +} + +QTabBar:focus +{ + border: 0px transparent black; +} + +QTabBar::close-button { + image: url(:/qss_icons/rc/close.png); + background: transparent; +} + +QTabBar::close-button:hover +{ + image: url(:/qss_icons/rc/close-hover.png); + background: transparent; +} + +QTabBar::close-button:pressed { + image: url(:/qss_icons/rc/close-pressed.png); + background: transparent; +} + +/* TOP TABS */ +QTabBar::tab:top { + color: #b1b1b1; + border: 1px solid #4A4949; + border-bottom: 1px transparent black; + background-color: #302F2F; + padding: 5px; + border-top-left-radius: 2px; + border-top-right-radius: 2px; +} + +QTabBar::tab:top:!selected +{ + color: #b1b1b1; + background-color: #201F1F; + border: 1px transparent #4A4949; + border-bottom: 1px transparent #4A4949; + border-top-left-radius: 0px; + border-top-right-radius: 0px; +} + +QTabBar::tab:top:!selected:hover { + background-color: #48576b; +} + +/* BOTTOM TABS */ +QTabBar::tab:bottom { + color: #b1b1b1; + border: 1px solid #4A4949; + border-top: 1px transparent black; + background-color: #302F2F; + padding: 5px; + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; +} + +QTabBar::tab:bottom:!selected +{ + color: #b1b1b1; + background-color: #201F1F; + border: 1px transparent #4A4949; + border-top: 1px transparent #4A4949; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; +} + +QTabBar::tab:bottom:!selected:hover { + background-color: #78879b; +} + +/* LEFT TABS */ +QTabBar::tab:left { + color: #b1b1b1; + border: 1px transparent #4A4949; + border-left: 1px transparent black; + background-color: #48576b; + padding: 5px; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; +} + +QTabBar::tab:left:!selected +{ + color: #b1b1b1; + background-color: #302F2F; + border: 1px transparent #4A4949; + border-right: 1px transparent #4A4949; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; +} + +QTabBar::tab:left:hover { + background-color: #48576b; +} + +QTabBar::tab:left:disabled +{ + color: #3A3939; + background-color: #302F2F; + border: 1px transparent #4A4949; + border-right: 1px transparent #4A4949; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; +} + + + +/* RIGHT TABS */ +QTabBar::tab:right { + color: #b1b1b1; + border: 1px solid #4A4949; + border-right: 1px transparent black; + background-color: #302F2F; + padding: 5px; + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; +} + +QTabBar::tab:right:!selected +{ + color: #b1b1b1; + background-color: #201F1F; + border: 1px transparent #4A4949; + border-right: 1px transparent #4A4949; + border-top-left-radius: 0px; + border-bottom-left-radius: 0px; +} + +QTabBar::tab:right:!selected:hover { + background-color: #48576b; +} + +QTabBar QToolButton::right-arrow:enabled { + image: url(:/qss_icons/rc/right_arrow.png); + } + + QTabBar QToolButton::left-arrow:enabled { + image: url(:/qss_icons/rc/left_arrow.png); + } + +QTabBar QToolButton::right-arrow:disabled { + image: url(:/qss_icons/rc/right_arrow_disabled.png); + } + + QTabBar QToolButton::left-arrow:disabled { + image: url(:/qss_icons/rc/left_arrow_disabled.png); + } + + +QDockWidget { + border: 1px transparent #403F3F; + titlebar-close-icon: url(:/qss_icons/rc/close.png); + titlebar-normal-icon: url(:/qss_icons/rc/undock.png); +} + +QDockWidget::title { + border: 1px solid #282727; + background-color: #2b2a2a; +} + +QDockWidget::close-button, QDockWidget::float-button { + border: 1px solid transparent; + border-radius: 2px; + background: transparent; +} + +QDockWidget::close-button:hover, QDockWidget::float-button:hover { + background: rgba(255, 255, 255, 10); +} + +QDockWidget::close-button:pressed, QDockWidget::float-button:pressed { + padding: 1px -1px -1px 1px; + background: rgba(255, 255, 255, 10); +} + +QTreeView, QListView +{ + border: 1px solid #444; + background-color: #201F1F; +} + +QTreeView:branch:selected, QTreeView:branch:hover +{ + background: url(:/qss_icons/rc/transparent.png); +} + +QTreeView::branch:has-siblings:!adjoins-item { + border-image: url(:/qss_icons/rc/transparent.png); +} + +QTreeView::branch:has-siblings:adjoins-item { + border-image: url(:/qss_icons/rc/transparent.png); +} + +QTreeView::branch:!has-children:!has-siblings:adjoins-item { + border-image: url(:/qss_icons/rc/transparent.png); +} + +QTreeView::branch:has-children:!has-siblings:closed, +QTreeView::branch:closed:has-children:has-siblings { + image: url(:/qss_icons/rc/branch_closed.png); +} + +QTreeView::branch:open:has-children:!has-siblings, +QTreeView::branch:open:has-children:has-siblings { + image: url(:/qss_icons/rc/branch_open.png); +} + +QTreeView::branch:has-children:!has-siblings:closed:hover, +QTreeView::branch:closed:has-children:has-siblings:hover { + image: url(:/qss_icons/rc/branch_closed-on.png); + } + +QTreeView::branch:open:has-children:!has-siblings:hover, +QTreeView::branch:open:has-children:has-siblings:hover { + image: url(:/qss_icons/rc/branch_open-on.png); + } + +QListView::item:!selected:hover, QListView::item:!selected:hover, QTreeView::item:!selected:hover { + background: rgba(0, 0, 0, 0); + outline: 0; + color: #FFFFFF +} + +QListView::item:selected:hover, QListView::item:selected:hover, QTreeView::item:selected:hover { + background: #3d8ec9; + color: #FFFFFF; +} + +QSlider::groove:horizontal { + border: 1px solid #3A3939; + height: 8px; + background: #201F1F; + margin: 2px 0; + border-radius: 2px; +} + +QSlider::groove:horizontal:disabled { + border: 1px solid #3A3939; + height: 8px; + background: #282727; + margin: 2px 0; + border-radius: 2px; +} + +QSlider::handle:horizontal { + background: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 silver, stop: 0.2 #a8a8a8, stop: 1 #727272); + border: 1px solid #3A3939; + width: 10px; + height: 14px; + margin: -4px 0; + border-radius: 2px; +} + +QSlider::handle:horizontal:disabled { + background: #4A4949; + border: 1px solid #3A3939; + width: 10px; + height: 14px; + margin: -4px 0; + border-radius: 2px; +} + +QSlider::groove:vertical { + border: 1px solid #3A3939; + width: 8px; + background: #201F1F; + margin: 0 0px; + border-radius: 2px; +} + +QSlider::groove:vertical:disabled { + border: 1px solid #3A3939; + height: 8px; + background: #403F3F; + margin: 2px 0; + border-radius: 2px; +} + +QSlider::handle:vertical { + background: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0.0 silver, + stop: 0.2 #a8a8a8, stop: 1 #727272); + border: 1px solid #3A3939; + width: 14px; + height: 10px; + margin: 0 -4px; + border-radius: 2px; +} + +QSlider::handle:vertical:disabled { + background: #4A4949; + border: 1px solid #3A3939; + width: 14px; + height: 10px; + margin: 0 -4px; + border-radius: 2px; +} + +QToolButton#MaximizeButton { + background-color: transparent; + border-left: 1px solid QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, stop: 0.3 #606060, + stop: 0.5 #707070, + stop: 0.7 #606060, stop: 1 #302F2F); + border-right: 1px solid QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, stop: 0.3 #606060, + stop: 0.5 #707070, + stop: 0.7 #606060, stop: 1 #302F2F); + border-radius: 0px; + margin: 0px; + padding: 0px; +} + +QToolButton#MinimizeButton, +QToolButton#CloseButton { + background-color: transparent; + border: 1px transparent #808080; + border-radius: 0px; + margin: 0px; + padding: 0px; +} + +QToolButton#MinimizeButton:hover, QToolButton#MinimizeButton::menu-button:hover, +QToolButton#MaximizeButton:hover, QToolButton#MaximizeButton::menu-button:hover{ + background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, stop: 0.4 #4E4D4D, + stop: 0.5 #4A4949, + stop: 0.6 #4E4D4D, stop: 1 #302F2F); +} + +QToolButton#CloseButton:hover, QToolButton#CloseButton::menu-button:hover { +background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, stop: 0.2 #A82F2F, + stop: 0.5 #E83E4A, + stop: 0.8 #A82F2F, stop: 1 #302F2F); +} + +QToolButton { + background-color: transparent; + border: 1px transparent #4A4949; + border-radius: 2px; + margin: 3px; + padding: 3px; +} + +QToolButton[popupMode="1"] { /* only for MenuButtonPopup */ + padding-right: 20px; /* make way for the popup button */ + border: 1px transparent #4A4949; + border-radius: 5px; +} + +QToolButton[popupMode="2"] { /* only for InstantPopup */ + padding-right: 10px; /* make way for the popup button */ + border: 1px transparent #4A4949; +} + + +QToolButton:hover, QToolButton::menu-button:hover { + background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, stop: 0.4 #4E4D4D, + stop: 0.5 #4A4949, + stop: 0.6 #4E4D4D, stop: 1 #302F2F); +} + +QToolButton:checked, QToolButton:pressed, +QToolButton::menu-button:pressed { + background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, + stop: 0.5 #4A4949, + stop: 1.0 #302F2F); +} + +/* the subcontrol below is used only in the InstantPopup or DelayedPopup mode */ +QToolButton::menu-indicator { + image: url(:/qss_icons/rc/down_arrow.png); + top: -7px; left: -2px; /* shift it a bit */ +} + +/* the subcontrols below are used only in the MenuButtonPopup mode */ +QToolButton::menu-button { + border: 1px transparent #4A4949; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; + /* 16px width + 4px for border = 20px allocated above */ + width: 16px; + outline: none; +} + +QToolButton::menu-arrow { + image: url(:/qss_icons/rc/down_arrow.png); +} + +QToolButton::menu-arrow:open { + top: 1px; left: 1px; /* shift it a bit */ + border: 1px solid #3A3939; +} + +QPushButton::menu-indicator { + subcontrol-origin: padding; + subcontrol-position: bottom right; + left: 8px; +} + +QTableView +{ + border: 1px transparent #444; + gridline-color: #6c6c6c; + background-color: #201F1F; +} + + +QTableView, QHeaderView +{ + border-radius: 0px; +} + +QTableView::item:pressed, QListView::item:pressed, QTreeView::item:pressed { + background: #78879b; + color: #FFFFFF; +} + +QTableView::item:selected:active, QTreeView::item:selected:active, QListView::item:selected:active { + background: #3d8ec9; + color: #FFFFFF; +} + +QHeaderView +{ + border: 1px transparent; + border-radius: 2px; + margin: 0px; + padding: 0px; +} + +QHeaderView::section { + background-color: #302F2F; + color: silver; + padding: 4px; + border: 1px transparent #6c6c6c; + border-radius: 0px; + text-align: center; +} + +QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one +{ + border-top: 1px transparent #6c6c6c; +} + +QHeaderView::section::vertical +{ + border-top: transparent; +} + +QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one +{ + border-left: 1px transparent #6c6c6c; +} + +QHeaderView::section::horizontal +{ + border-left: transparent; +} + + +QHeaderView::section:checked + { + color: white; + background-color: #5A5959; + } + + /* style the sort indicator */ +QHeaderView::down-arrow { + image: url(:/qss_icons/rc/down_arrow.png); +} + +QHeaderView::up-arrow { + image: url(:/qss_icons/rc/up_arrow.png); +} + + +QTableCornerButton::section { + background-color: #3A3939; + border: 1px solid #3A3939; + border-radius: 2px; +} + +QToolBox { + padding: 3px; + border: 1px transparent black; +} + +QToolBox::tab { + color: #b1b1b1; + background-color: #302F2F; + border: 1px solid #4A4949; + border-bottom: 1px transparent #302F2F; + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + + QToolBox::tab:selected { /* italicize selected tabs */ + font: italic; + background-color: #302F2F; + border-color: #3d8ec9; + } + +QStatusBar::item { + border: 1px solid #3A3939; + border-radius: 2px; + } + +QFrame[height="3"], QFrame[width="3"] { + background-color: #444; +} + +QAbstractScrollArea +{ + border-radius: 2px; + border: 0px transparent #3A3939; + background-color: #302F2F; +} + +QSplitter::handle:horizontal, +QMainWindow::separator +{ + background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, + stop: 0.4 #333333, + stop: 0.5 #404040, + stop: 0.6 #333333, + stop: 1 #302F2F); + color: white; + padding-left: 0px; + spacing: 0px; + width: 3px; + border: 0px solid #202020; +} + +QSplitter::handle:horizontal:hover, +QMainWindow::separator:hover +{ + background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, + stop: 0.1 #333333, + stop: 0.5 #404040, + stop: 0.9 #333333, + stop: 1 #302F2F); + color: white; + padding-left: 0px; + spacing: 0px; + width: 3px; + border: 0px solid #202020; +} + +QSplitter::handle:vertical { + background-color: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0, + stop: 0.0 #302F2F, + stop: 0.3 #505050, + stop: 0.5 #606060, + stop: 0.7 #505050, + stop: 1 #302F2F); + height: 3px; +} + +QSplitter::handle:vertical:hover { + background-color: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0, + stop: 0.0 #302F2F, + stop: 0.1 #505050, + stop: 0.5 #606060, + stop: 0.8 #505050, + stop: 1 #302F2F); + height: 3px; +} diff --git a/DSView/dsapplication.cpp b/DSView/dsapplication.cpp new file mode 100644 index 00000000..9facc855 --- /dev/null +++ b/DSView/dsapplication.cpp @@ -0,0 +1,51 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 "dsapplication.h" + +#include + +DSApplication::DSApplication(int &argc, char **argv): + QApplication(argc, argv) +{ +} + +bool DSApplication::notify(QObject *receiver_, QEvent *event_) +{ + try { + return QApplication::notify(receiver_, event_); + } catch ( std::exception& e ) { + QMessageBox msg(NULL); + msg.setText("Application Error"); + msg.setInformativeText(e.what()); + msg.setStandardButtons(QMessageBox::Ok); + msg.setIcon(QMessageBox::Warning); + msg.exec(); + } catch (...) { + QMessageBox msg(NULL); + msg.setText("Application Error"); + msg.setInformativeText("An unexpected error occurred"); + msg.setStandardButtons(QMessageBox::Ok); + msg.setIcon(QMessageBox::Warning); + msg.exec(); + } + return false; +} diff --git a/DSView/dsapplication.h b/DSView/dsapplication.h new file mode 100644 index 00000000..7e804745 --- /dev/null +++ b/DSView/dsapplication.h @@ -0,0 +1,37 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 DSVIEW_DSAPPLICATION_H +#define DSVIEW_DSAPPLICATION_H + +#include +#include + +class DSApplication : public QApplication +{ +public: + DSApplication(int &argc, char ** argv); + // ~MyApplication(); +private: + bool notify(QObject *receiver_, QEvent *event_); +}; + +#endif // DSVIEW_DSAPPLICATION_H diff --git a/DSView/extdef.h b/DSView/extdef.h index 549c0629..7fc608fe 100644 --- a/DSView/extdef.h +++ b/DSView/extdef.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -29,4 +29,10 @@ #define begin_element(x) (&x[0]) #define end_element(x) (&x[countof(x)]) +enum View_type { + TIME_VIEW, + FFT_VIEW, + ALL_VIEW +}; + #endif // DSVIEW_EXTDEF_H diff --git a/DSView/icons/Blackman.png b/DSView/icons/Blackman.png new file mode 100644 index 00000000..b3a268e5 Binary files /dev/null and b/DSView/icons/Blackman.png differ diff --git a/DSView/icons/Flat_top.png b/DSView/icons/Flat_top.png new file mode 100644 index 00000000..56093184 Binary files /dev/null and b/DSView/icons/Flat_top.png differ diff --git a/DSView/icons/Hamming.png b/DSView/icons/Hamming.png new file mode 100644 index 00000000..c9160ea0 Binary files /dev/null and b/DSView/icons/Hamming.png differ diff --git a/DSView/icons/Hann.png b/DSView/icons/Hann.png new file mode 100644 index 00000000..01d68b1d Binary files /dev/null and b/DSView/icons/Hann.png differ diff --git a/DSView/icons/Rectangle.png b/DSView/icons/Rectangle.png new file mode 100644 index 00000000..cacd4711 Binary files /dev/null and b/DSView/icons/Rectangle.png differ diff --git a/DSView/icons/about.png b/DSView/icons/about.png index ac389095..c8f40c62 100644 Binary files a/DSView/icons/about.png and b/DSView/icons/about.png differ diff --git a/DSView/icons/close.png b/DSView/icons/close.png new file mode 100644 index 00000000..529f2ed1 Binary files /dev/null and b/DSView/icons/close.png differ diff --git a/DSView/icons/export.png b/DSView/icons/export.png new file mode 100644 index 00000000..57ee72ff Binary files /dev/null and b/DSView/icons/export.png differ diff --git a/DSView/icons/fft.png b/DSView/icons/fft.png new file mode 100644 index 00000000..f2e0db4a Binary files /dev/null and b/DSView/icons/fft.png differ diff --git a/DSView/icons/file.png b/DSView/icons/file.png index 2a4715da..78c469cc 100644 Binary files a/DSView/icons/file.png and b/DSView/icons/file.png differ diff --git a/DSView/icons/file_cn.png b/DSView/icons/file_cn.png deleted file mode 100644 index 00096c50..00000000 Binary files a/DSView/icons/file_cn.png and /dev/null differ diff --git a/DSView/icons/file_dis.png b/DSView/icons/file_dis.png index 65373110..5c27e1ae 100644 Binary files a/DSView/icons/file_dis.png and b/DSView/icons/file_dis.png differ diff --git a/DSView/icons/file_dis_cn.png b/DSView/icons/file_dis_cn.png deleted file mode 100644 index b6e24584..00000000 Binary files a/DSView/icons/file_dis_cn.png and /dev/null differ diff --git a/DSView/icons/instant.png b/DSView/icons/instant.png index 2aa5c250..c3e249d3 100644 Binary files a/DSView/icons/instant.png and b/DSView/icons/instant.png differ diff --git a/DSView/icons/instant_cn.png b/DSView/icons/instant_cn.png deleted file mode 100644 index 0e586094..00000000 Binary files a/DSView/icons/instant_cn.png and /dev/null differ diff --git a/DSView/icons/instant_dis.png b/DSView/icons/instant_dis.png old mode 100755 new mode 100644 index e3f8adfc..9c24bf07 Binary files a/DSView/icons/instant_dis.png and b/DSView/icons/instant_dis.png differ diff --git a/DSView/icons/instant_dis_cn.png b/DSView/icons/instant_dis_cn.png deleted file mode 100755 index 4477a544..00000000 Binary files a/DSView/icons/instant_dis_cn.png and /dev/null differ diff --git a/DSView/icons/math.png b/DSView/icons/math.png new file mode 100644 index 00000000..dbb83a78 Binary files /dev/null and b/DSView/icons/math.png differ diff --git a/DSView/icons/math_dis.png b/DSView/icons/math_dis.png new file mode 100644 index 00000000..9850dd5e Binary files /dev/null and b/DSView/icons/math_dis.png differ diff --git a/DSView/icons/maximize.png b/DSView/icons/maximize.png new file mode 100644 index 00000000..bb4bffb8 Binary files /dev/null and b/DSView/icons/maximize.png differ diff --git a/DSView/icons/measure.png b/DSView/icons/measure.png index c858a50d..461bb7c9 100644 Binary files a/DSView/icons/measure.png and b/DSView/icons/measure.png differ diff --git a/DSView/icons/measure_cn.png b/DSView/icons/measure_cn.png deleted file mode 100644 index 71619a88..00000000 Binary files a/DSView/icons/measure_cn.png and /dev/null differ diff --git a/DSView/icons/measure_dis.png b/DSView/icons/measure_dis.png index 8510560a..3f152eee 100644 Binary files a/DSView/icons/measure_dis.png and b/DSView/icons/measure_dis.png differ diff --git a/DSView/icons/measure_dis_cn.png b/DSView/icons/measure_dis_cn.png deleted file mode 100644 index d023a23d..00000000 Binary files a/DSView/icons/measure_dis_cn.png and /dev/null differ diff --git a/DSView/icons/minimize.png b/DSView/icons/minimize.png new file mode 100644 index 00000000..7c9a9fd3 Binary files /dev/null and b/DSView/icons/minimize.png differ diff --git a/DSView/icons/next.png b/DSView/icons/next.png index cc35544b..d3efe6f2 100644 Binary files a/DSView/icons/next.png and b/DSView/icons/next.png differ diff --git a/DSView/icons/params.png b/DSView/icons/params.png index ea7c1a0e..d6a9fff7 100644 Binary files a/DSView/icons/params.png and b/DSView/icons/params.png differ diff --git a/DSView/icons/params_cn.png b/DSView/icons/params_cn.png deleted file mode 100644 index 86e2811f..00000000 Binary files a/DSView/icons/params_cn.png and /dev/null differ diff --git a/DSView/icons/params_dis.png b/DSView/icons/params_dis.png index 277a3266..af2518a7 100644 Binary files a/DSView/icons/params_dis.png and b/DSView/icons/params_dis.png differ diff --git a/DSView/icons/params_dis_cn.png b/DSView/icons/params_dis_cn.png deleted file mode 100644 index fcb8a611..00000000 Binary files a/DSView/icons/params_dis_cn.png and /dev/null differ diff --git a/DSView/icons/pre.png b/DSView/icons/pre.png index f7ccd2eb..ee773259 100644 Binary files a/DSView/icons/pre.png and b/DSView/icons/pre.png differ diff --git a/DSView/icons/protocol.png b/DSView/icons/protocol.png index 91423ec2..acf434e2 100644 Binary files a/DSView/icons/protocol.png and b/DSView/icons/protocol.png differ diff --git a/DSView/icons/protocol_cn.png b/DSView/icons/protocol_cn.png deleted file mode 100644 index 213fd151..00000000 Binary files a/DSView/icons/protocol_cn.png and /dev/null differ diff --git a/DSView/icons/protocol_dis.png b/DSView/icons/protocol_dis.png index b5278b68..3836866f 100644 Binary files a/DSView/icons/protocol_dis.png and b/DSView/icons/protocol_dis.png differ diff --git a/DSView/icons/protocol_dis_cn.png b/DSView/icons/protocol_dis_cn.png deleted file mode 100644 index 005d3add..00000000 Binary files a/DSView/icons/protocol_dis_cn.png and /dev/null differ diff --git a/DSView/icons/restore.png b/DSView/icons/restore.png new file mode 100644 index 00000000..ceaa6235 Binary files /dev/null and b/DSView/icons/restore.png differ diff --git a/DSView/icons/search-bar.png b/DSView/icons/search-bar.png index 20b94274..1e58096d 100644 Binary files a/DSView/icons/search-bar.png and b/DSView/icons/search-bar.png differ diff --git a/DSView/icons/search-bar_cn.png b/DSView/icons/search-bar_cn.png deleted file mode 100644 index b8a249e4..00000000 Binary files a/DSView/icons/search-bar_cn.png and /dev/null differ diff --git a/DSView/icons/search-bar_dis.png b/DSView/icons/search-bar_dis.png index a19d5834..1b2d6955 100644 Binary files a/DSView/icons/search-bar_dis.png and b/DSView/icons/search-bar_dis.png differ diff --git a/DSView/icons/search-bar_dis_cn.png b/DSView/icons/search-bar_dis_cn.png deleted file mode 100644 index f21aa2d4..00000000 Binary files a/DSView/icons/search-bar_dis_cn.png and /dev/null differ diff --git a/DSView/icons/settings.png b/DSView/icons/settings.png old mode 100755 new mode 100644 diff --git a/DSView/icons/single.png b/DSView/icons/single.png new file mode 100644 index 00000000..c0565af0 Binary files /dev/null and b/DSView/icons/single.png differ diff --git a/DSView/icons/single_dis.png b/DSView/icons/single_dis.png new file mode 100644 index 00000000..4e1221f8 Binary files /dev/null and b/DSView/icons/single_dis.png differ diff --git a/DSView/icons/start.png b/DSView/icons/start.png index bd42b602..4c2d7e61 100644 Binary files a/DSView/icons/start.png and b/DSView/icons/start.png differ diff --git a/DSView/icons/start_cn.png b/DSView/icons/start_cn.png deleted file mode 100644 index 6052468a..00000000 Binary files a/DSView/icons/start_cn.png and /dev/null differ diff --git a/DSView/icons/start_dis.png b/DSView/icons/start_dis.png old mode 100755 new mode 100644 index 62eee6d5..56f6e901 Binary files a/DSView/icons/start_dis.png and b/DSView/icons/start_dis.png differ diff --git a/DSView/icons/start_dis_cn.png b/DSView/icons/start_dis_cn.png deleted file mode 100755 index 86531127..00000000 Binary files a/DSView/icons/start_dis_cn.png and /dev/null differ diff --git a/DSView/icons/stop.png b/DSView/icons/stop.png index 969a6999..77aa105d 100644 Binary files a/DSView/icons/stop.png and b/DSView/icons/stop.png differ diff --git a/DSView/icons/stop_cn.png b/DSView/icons/stop_cn.png deleted file mode 100644 index da13d848..00000000 Binary files a/DSView/icons/stop_cn.png and /dev/null differ diff --git a/DSView/icons/trigger.png b/DSView/icons/trigger.png index 5f8f4965..6b1ca1b8 100644 Binary files a/DSView/icons/trigger.png and b/DSView/icons/trigger.png differ diff --git a/DSView/icons/trigger_cn.png b/DSView/icons/trigger_cn.png deleted file mode 100644 index 8f98b4dd..00000000 Binary files a/DSView/icons/trigger_cn.png and /dev/null differ diff --git a/DSView/icons/trigger_dis.png b/DSView/icons/trigger_dis.png index 9c804d0e..eb401cff 100644 Binary files a/DSView/icons/trigger_dis.png and b/DSView/icons/trigger_dis.png differ diff --git a/DSView/icons/trigger_dis_cn.png b/DSView/icons/trigger_dis_cn.png deleted file mode 100644 index e17bfce7..00000000 Binary files a/DSView/icons/trigger_dis_cn.png and /dev/null differ diff --git a/DSView/icons/wait.gif b/DSView/icons/wait.gif index 58279b9f..b3ba36a6 100644 Binary files a/DSView/icons/wait.gif and b/DSView/icons/wait.gif differ diff --git a/DSView/icons/wiki.png b/DSView/icons/wiki.png index 4515019c..8e06ac1d 100644 Binary files a/DSView/icons/wiki.png and b/DSView/icons/wiki.png differ diff --git a/DSView/main.cpp b/DSView/main.cpp index bd131f65..d63b2e7f 100644 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -34,9 +34,11 @@ #include #include #include +#include +#include "dsapplication.h" #include "pv/devicemanager.h" -#include "pv/mainwindow.h" +#include "pv/mainframe.h" #include "config.h" @@ -59,22 +61,11 @@ int main(int argc, char *argv[]) struct sr_context *sr_ctx = NULL; const char *open_file = NULL; - QApplication a(argc, argv); - - // Language -#ifdef LANGUAGE_ZH_CN - QTranslator qtTrans; - qtTrans.load(":/qt_zh_CN"); - a.installTranslator(&qtTrans); - - QTranslator DSViewTrans; - DSViewTrans.load(":/DSView_zh"); - a.installTranslator(&DSViewTrans); -#endif + DSApplication a(argc, argv); // Set some application metadata QApplication::setApplicationVersion(DS_VERSION_STRING); - QApplication::setApplicationName("DSView(Beta)"); + QApplication::setApplicationName("DSView"); QApplication::setOrganizationDomain("http://www.DreamSourceLab.com"); // Parse arguments @@ -129,7 +120,6 @@ int main(int argc, char *argv[]) } do { - #ifdef ENABLE_DECODE // Initialise libsigrokdecode if (srd_init(NULL) != SRD_OK) { @@ -145,12 +135,13 @@ int main(int argc, char *argv[]) // Create the device manager, initialise the drivers pv::DeviceManager device_manager(sr_ctx); - // Initialise the main window - pv::MainWindow w(device_manager, open_file); - QFile qss(":/stylesheet.qss"); - qss.open(QFile::ReadOnly); - a.setStyleSheet(qss.readAll()); - qss.close(); + // Initialise the main frame + pv::MainFrame w(device_manager, open_file); + //QFile qss(":/stylesheet.qss"); + QFile qss(":darkstyle/style.qss"); + qss.open(QFile::ReadOnly); + a.setStyleSheet(qss.readAll()); + qss.close(); w.show(); // Run the application diff --git a/DSView/pv/data/analog.cpp b/DSView/pv/data/analog.cpp index ad0c052f..4d3c5ca5 100644 --- a/DSView/pv/data/analog.cpp +++ b/DSView/pv/data/analog.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -24,6 +24,8 @@ #include "analog.h" #include "analogsnapshot.h" +#include + using namespace boost; using namespace std; @@ -47,7 +49,15 @@ deque< boost::shared_ptr >& Analog::get_snapshots() void Analog::clear() { - _snapshots.clear(); + //_snapshots.clear(); + BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + s->clear(); +} +void Analog::init() +{ + //_snapshots.clear(); + BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + s->init(); } } // namespace data diff --git a/DSView/pv/data/analog.h b/DSView/pv/data/analog.h index b53aff6e..c28b649f 100644 --- a/DSView/pv/data/analog.h +++ b/DSView/pv/data/analog.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -46,6 +46,7 @@ public: get_snapshots(); void clear(); + void init(); private: std::deque< boost::shared_ptr > _snapshots; diff --git a/DSView/pv/data/analogsnapshot.cpp b/DSView/pv/data/analogsnapshot.cpp index 085cf20c..005885c7 100644 --- a/DSView/pv/data/analogsnapshot.cpp +++ b/DSView/pv/data/analogsnapshot.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -46,26 +46,101 @@ const float AnalogSnapshot::LogEnvelopeScaleFactor = logf(EnvelopeScaleFactor); const uint64_t AnalogSnapshot::EnvelopeDataUnit = 64*1024; // bytes -AnalogSnapshot::AnalogSnapshot(const sr_datafeed_analog &analog, uint64_t _total_sample_len, unsigned int channel_num) : - Snapshot(sizeof(uint16_t)*channel_num, _total_sample_len, channel_num) +AnalogSnapshot::AnalogSnapshot() : + Snapshot(sizeof(uint16_t), 1, 1) { - boost::lock_guard lock(_mutex); memset(_envelope_levels, 0, sizeof(_envelope_levels)); - init(_total_sample_len * channel_num); - append_payload(analog); } AnalogSnapshot::~AnalogSnapshot() { - boost::lock_guard lock(_mutex); - BOOST_FOREACH(Envelope &e, _envelope_levels[0]) - free(e.samples); + free_envelop(); +} + +void AnalogSnapshot::free_envelop() +{ + for (unsigned int i = 0; i < _channel_num; i++) { + BOOST_FOREACH(Envelope &e, _envelope_levels[i]) { + if (e.samples) + free(e.samples); + } + } + memset(_envelope_levels, 0, sizeof(_envelope_levels)); +} + +void AnalogSnapshot::init() +{ + boost::lock_guard lock(_mutex); + _sample_count = 0; + _ring_sample_count = 0; + _memory_failed = false; + _last_ended = true; + for (unsigned int i = 0; i < _channel_num; i++) { + for (unsigned int level = 0; level < ScaleStepCount; level++) { + _envelope_levels[i][level].length = 0; + _envelope_levels[i][level].data_length = 0; + } + } +} + +void AnalogSnapshot::clear() +{ + boost::lock_guard lock(_mutex); + free_data(); + free_envelop(); + init(); +} + +void AnalogSnapshot::first_payload(const sr_datafeed_analog &analog, uint64_t total_sample_count, unsigned int channel_num) +{ + _total_sample_count = total_sample_count; + _channel_num = channel_num; + _unit_size = sizeof(uint16_t)*channel_num; + + bool isOk = true; + uint64_t size = _total_sample_count * _unit_size + sizeof(uint64_t); + if (size != _capacity) { + free_data(); + _data = malloc(size); + if (_data) { + free_envelop(); + for (unsigned int i = 0; i < _channel_num; i++) { + uint64_t envelop_count = _total_sample_count / EnvelopeScaleFactor; + for (unsigned int level = 0; level < ScaleStepCount; level++) { + envelop_count = ((envelop_count + EnvelopeDataUnit - 1) / + EnvelopeDataUnit) * EnvelopeDataUnit; + _envelope_levels[i][level].samples = (EnvelopeSample*)malloc(envelop_count * sizeof(EnvelopeSample)); + if (!_envelope_levels[i][level].samples) { + isOk = false; + break; + } + envelop_count = envelop_count / EnvelopeScaleFactor; + } + if (!isOk) + break; + } + } else { + isOk = true; + } + } + + if (isOk) { + _capacity = size; + _memory_failed = false; + append_payload(analog); + _last_ended = false; + } else { + free_data(); + free_envelop(); + _capacity = 0; + _memory_failed = true; + } } void AnalogSnapshot::append_payload( const sr_datafeed_analog &analog) { - boost::lock_guard lock(_mutex); + boost::lock_guard lock(_mutex); append_data(analog.data, analog.num_samples); // Generate the first mip-map from the data @@ -83,8 +158,6 @@ const uint16_t* AnalogSnapshot::get_samples( assert(end_sample < (int64_t)get_sample_count()); assert(start_sample <= end_sample); - boost::lock_guard lock(_mutex); - // uint16_t *const data = new uint16_t[end_sample - start_sample]; // memcpy(data, (uint16_t*)_data + start_sample, sizeof(uint16_t) * // (end_sample - start_sample)); @@ -99,8 +172,6 @@ void AnalogSnapshot::get_envelope_section(EnvelopeSection &s, assert(start <= end); assert(min_length > 0); - boost::lock_guard lock(_mutex); - const unsigned int min_level = max((int)floorf(logf(min_length) / LogEnvelopeScaleFactor) - 1, 0); const unsigned int scale_power = (min_level + 1) * @@ -124,8 +195,8 @@ void AnalogSnapshot::reallocate_envelope(Envelope &e) if (new_data_length > e.data_length) { e.data_length = new_data_length; - e.samples = (EnvelopeSample*)realloc(e.samples, - new_data_length * sizeof(EnvelopeSample)); +// e.samples = (EnvelopeSample*)realloc(e.samples, +// new_data_length * sizeof(EnvelopeSample)); } } @@ -139,7 +210,7 @@ void AnalogSnapshot::append_payload_to_envelope_levels() // Expand the data buffer to fit the new samples prev_length = e0.length; - e0.length = get_sample_count() / EnvelopeScaleFactor; + e0.length = _sample_count / EnvelopeScaleFactor; // Break off if there are no new samples to compute // if (e0.length == prev_length) diff --git a/DSView/pv/data/analogsnapshot.h b/DSView/pv/data/analogsnapshot.h index 3282f257..3f2b015a 100644 --- a/DSView/pv/data/analogsnapshot.h +++ b/DSView/pv/data/analogsnapshot.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -69,10 +69,15 @@ private: static const uint64_t EnvelopeDataUnit; public: - AnalogSnapshot(const sr_datafeed_analog &analog, uint64_t _total_sample_len, unsigned int channel_num); + AnalogSnapshot(); virtual ~AnalogSnapshot(); + void clear(); + void init(); + + void first_payload(const sr_datafeed_analog &analog, uint64_t total_sample_count, unsigned int channel_num); + void append_payload(const sr_datafeed_analog &analog); const uint16_t* get_samples(int64_t start_sample, @@ -82,8 +87,8 @@ public: uint64_t start, uint64_t end, float min_length, int probe_index) const; private: + void free_envelop(); void reallocate_envelope(Envelope &l); - void append_payload_to_envelope_levels(); private: diff --git a/DSView/pv/data/decode/annotation.cpp b/DSView/pv/data/decode/annotation.cpp index a474dd90..f2d30df5 100644 --- a/DSView/pv/data/decode/annotation.cpp +++ b/DSView/pv/data/decode/annotation.cpp @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2016 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 @@ -41,6 +42,7 @@ Annotation::Annotation(const srd_proto_data *const pdata) : assert(pda); _format = pda->ann_class; + _type = pda->ann_type; const char *const *annotations = (char**)pda->ann_text; while(*annotations) { @@ -49,6 +51,12 @@ Annotation::Annotation(const srd_proto_data *const pdata) : } } +Annotation::Annotation() +{ + _start_sample = 0; + _end_sample = 0; +} + Annotation::~Annotation() { _annotations.clear(); @@ -69,6 +77,11 @@ int Annotation::format() const return _format; } +int Annotation::type() const +{ + return _type; +} + const std::vector& Annotation::annotations() const { return _annotations; diff --git a/DSView/pv/data/decode/annotation.h b/DSView/pv/data/decode/annotation.h index a2676bd3..03e208ef 100644 --- a/DSView/pv/data/decode/annotation.h +++ b/DSView/pv/data/decode/annotation.h @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * Copyright (C) 2013 Joel Holdsworth + * Copyright (C) 2016 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 @@ -35,17 +36,20 @@ class Annotation { public: Annotation(const srd_proto_data *const pdata); + Annotation(); ~Annotation(); uint64_t start_sample() const; uint64_t end_sample() const; int format() const; + int type() const; const std::vector& annotations() const; private: uint64_t _start_sample; uint64_t _end_sample; int _format; + int _type; std::vector _annotations; }; diff --git a/DSView/pv/data/decode/decoder.cpp b/DSView/pv/data/decode/decoder.cpp index 00d6a1f5..8d54d7f6 100644 --- a/DSView/pv/data/decode/decoder.cpp +++ b/DSView/pv/data/decode/decoder.cpp @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * 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 @@ -93,11 +94,32 @@ void Decoder::set_option(const char *id, GVariant *value) _setted = true; } +void Decoder::set_decode_region(uint64_t start, uint64_t end) +{ + _decode_start_back = start; + _decode_end_back = end; + if (_decode_start != start || + _decode_end != end) + _setted = true; +} + +uint64_t Decoder::decode_start() const +{ + return _decode_start; +} + +uint64_t Decoder::decode_end() const +{ + return _decode_end; +} + bool Decoder::commit() { if (_setted) { _probes = _probes_back; _options = _options_back; + _decode_start = _decode_start_back; + _decode_end = _decode_end_back; _setted = false; return true; } else { diff --git a/DSView/pv/data/decode/decoder.h b/DSView/pv/data/decode/decoder.h index ae51c1d3..40fde4e6 100644 --- a/DSView/pv/data/decode/decoder.h +++ b/DSView/pv/data/decode/decoder.h @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * 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 @@ -73,6 +74,10 @@ public: std::set< boost::shared_ptr > get_data(); + void set_decode_region(uint64_t start, uint64_t end); + uint64_t decode_start() const; + uint64_t decode_end() const; + bool commit(); private: @@ -88,6 +93,9 @@ private: _probes_back; std::map _options_back; + uint64_t _decode_start, _decode_end; + uint64_t _decode_start_back, _decode_end_back; + bool _setted; }; diff --git a/DSView/pv/data/decode/row.cpp b/DSView/pv/data/decode/row.cpp index 1c0ee9cc..46fb337f 100644 --- a/DSView/pv/data/decode/row.cpp +++ b/DSView/pv/data/decode/row.cpp @@ -68,8 +68,8 @@ const QString Row::title() const bool Row::operator<(const Row &other) const { - return (_decoder < other._decoder) || - (_decoder == other._decoder && _row < other._row); + return (_decoder < other._decoder) || + (_decoder == other._decoder && _row < other._row); } } // decode diff --git a/DSView/pv/data/decode/row.h b/DSView/pv/data/decode/row.h index 6826c0fc..73324302 100644 --- a/DSView/pv/data/decode/row.h +++ b/DSView/pv/data/decode/row.h @@ -46,7 +46,7 @@ public: const QString title() const; - bool operator<(const Row &other) const; + bool operator<(const Row &other) const; private: const srd_decoder *_decoder; diff --git a/DSView/pv/data/decode/rowdata.cpp b/DSView/pv/data/decode/rowdata.cpp index 840459a6..8d3e41e0 100644 --- a/DSView/pv/data/decode/rowdata.cpp +++ b/DSView/pv/data/decode/rowdata.cpp @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * Copyright (C) 2014 Joel Holdsworth + * Copyright (C) 2016 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 @@ -23,6 +24,7 @@ #include "rowdata.h" using std::max; +using std::min; using std::vector; namespace pv { @@ -30,7 +32,8 @@ namespace data { namespace decode { RowData::RowData() : - _max_annotation(0) + _max_annotation(0), + _min_annotation(UINT64_MAX) { } @@ -51,6 +54,11 @@ uint64_t RowData::get_max_annotation() const return _max_annotation; } +uint64_t RowData::get_min_annotation() const +{ + return _min_annotation; +} + void RowData::get_annotation_subset( vector &dest, uint64_t start_sample, uint64_t end_sample) const @@ -62,10 +70,33 @@ void RowData::get_annotation_subset( dest.push_back(*i); } -void RowData::push_annotation(const Annotation &a) +bool RowData::push_annotation(const Annotation &a) { - _annotations.push_back(a); - _max_annotation = max(_max_annotation, a.end_sample() - a.start_sample()); + try { + _annotations.push_back(a); + _max_annotation = max(_max_annotation, a.end_sample() - a.start_sample()); + if (a.end_sample() != a.start_sample()) + _min_annotation = min(_min_annotation, a.end_sample() - a.start_sample()); + return true; + } catch (const std::bad_alloc&) { + return false; + } +} + +uint64_t RowData::get_annotation_size() const +{ + return _annotations.size(); +} + +bool RowData::get_annotation(Annotation &ann, + uint64_t index) const +{ + if (index < _annotations.size()) { + ann = _annotations[index]; + return true; + } else { + return false; + } } } // decode diff --git a/DSView/pv/data/decode/rowdata.h b/DSView/pv/data/decode/rowdata.h index 03076494..40792cb7 100644 --- a/DSView/pv/data/decode/rowdata.h +++ b/DSView/pv/data/decode/rowdata.h @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * Copyright (C) 2014 Joel Holdsworth + * Copyright (C) 2016 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 @@ -34,11 +35,11 @@ class RowData public: RowData(); ~RowData(); - public: uint64_t get_max_sample() const; uint64_t get_max_annotation() const; + uint64_t get_min_annotation() const; /** * Extracts sorted annotations between two period into a vector. */ @@ -46,10 +47,16 @@ public: std::vector &dest, uint64_t start_sample, uint64_t end_sample) const; - void push_annotation(const Annotation &a); + bool push_annotation(const Annotation &a); + + uint64_t get_annotation_size() const; + + bool get_annotation(pv::data::decode::Annotation &ann, + uint64_t index) const; private: uint64_t _max_annotation; + uint64_t _min_annotation; std::vector _annotations; }; diff --git a/DSView/pv/data/decodermodel.cpp b/DSView/pv/data/decodermodel.cpp new file mode 100644 index 00000000..078111a4 --- /dev/null +++ b/DSView/pv/data/decodermodel.cpp @@ -0,0 +1,108 @@ +/* + * This file is part of the DSView project. + * + * Copyright (C) 2016 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 "decoderstack.h" +#include "decodermodel.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace data { + +DecoderModel::DecoderModel(QObject *parent) + : QAbstractTableModel(parent), + _decoder_stack(NULL) +{ +} + +void DecoderModel::setDecoderStack(boost::shared_ptr decoder_stack) +{ + beginResetModel(); + _decoder_stack = decoder_stack; + endResetModel(); +} + +const boost::shared_ptr& DecoderModel::getDecoderStack() const +{ + return _decoder_stack; +} + +int DecoderModel::rowCount(const QModelIndex & /* parent */) const +{ + if (_decoder_stack) + return _decoder_stack->list_annotation_size(); + else + return 100; +} +int DecoderModel::columnCount(const QModelIndex & /* parent */) const +{ + if (_decoder_stack) + return _decoder_stack->list_rows_size(); + else + return 1; +} + +QVariant DecoderModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role == Qt::TextAlignmentRole) { + return int(Qt::AlignLeft | Qt::AlignVCenter); + } else if (role == Qt::DisplayRole) { + if (_decoder_stack) { + pv::data::decode::Annotation ann; + if (_decoder_stack->list_annotation(ann, index.column(), index.row())) { + return ann.annotations().at(0); + } + } + } + return QVariant(); +} + +QVariant DecoderModel::headerData(int section, + Qt::Orientation orientation, + int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Vertical) + return section; + + if (_decoder_stack) { + QString title; + if (_decoder_stack->list_row_title(section, title)) + return title; + } + return QVariant(); +} + +} // namespace data +} // namespace pv diff --git a/DSView/pv/data/decodermodel.h b/DSView/pv/data/decodermodel.h new file mode 100644 index 00000000..09032729 --- /dev/null +++ b/DSView/pv/data/decodermodel.h @@ -0,0 +1,62 @@ +/* + * This file is part of the DSView project. + * + * Copyright (C) 2016 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 DSVIEW_PV_DATA_DECODERMODEL_H +#define DSVIEW_PV_DATA_DECODERMODEL_H + +#include + +#include + +#include + +namespace pv { +namespace data { + +class DecoderStack; + +namespace decode { +class Annotation; +class Decoder; +class Row; +} + +class DecoderModel : public QAbstractTableModel +{ +public: + DecoderModel(QObject *parent = 0); + + int rowCount(const QModelIndex & /*parent*/) const; + int columnCount(const QModelIndex & /*parent*/) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role) const; + + void setDecoderStack(boost::shared_ptr decoder_stack); + const boost::shared_ptr& getDecoderStack() const; + +private: + boost::shared_ptr _decoder_stack; +}; + +} // namespace data +} // namespace pv + +#endif // DSVIEW_PV_DATA_DECODERMODEL_H diff --git a/DSView/pv/data/decoderstack.cpp b/DSView/pv/data/decoderstack.cpp index 1df0abb0..233dcc4d 100644 --- a/DSView/pv/data/decoderstack.cpp +++ b/DSView/pv/data/decoderstack.cpp @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * Copyright (C) 2012 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 @@ -17,12 +18,11 @@ * 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 @@ -56,8 +56,9 @@ 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; +const int64_t DecoderStack::DecodeChunkLength = 4 * 1024; +//const int64_t DecoderStack::DecodeChunkLength = 1024 * 1024; +const unsigned int DecoderStack::DecodeNotifyPeriod = 1024; mutex DecoderStack::_global_decode_mutex; @@ -68,7 +69,8 @@ DecoderStack::DecoderStack(pv::SigSession &session, _frame_complete(false), _samples_decoded(0), _decode_state(Stopped), - _options_changed(false) + _options_changed(false), + _no_memory(false) { connect(&_session, SIGNAL(frame_began()), this, SLOT(on_new_frame())); @@ -79,6 +81,8 @@ DecoderStack::DecoderStack(pv::SigSession &session, _stack.push_back(shared_ptr( new decode::Decoder(dec))); + + build_row(); } DecoderStack::~DecoderStack() @@ -89,7 +93,10 @@ DecoderStack::~DecoderStack() // } stop_decode(); _stack.clear(); - clear(); + _rows.clear(); + _rows_gshow.clear(); + _rows_lshow.clear(); + _class_rows.clear(); } const std::list< boost::shared_ptr >& @@ -102,75 +109,106 @@ void DecoderStack::push(boost::shared_ptr decoder) { assert(decoder); _stack.push_back(decoder); + build_row(); + _options_changed = true; } -void DecoderStack::remove(int index) +void DecoderStack::remove(boost::shared_ptr &decoder) { - 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()); + for(unsigned int i = 0; i < _stack.size(); i++, iter++) + if ((*iter) == decoder) + break; // Delete the element - _stack.erase(iter); + if (iter != _stack.end()) + _stack.erase(iter); + + build_row(); + _options_changed = true; +} + +void DecoderStack::build_row() +{ + _rows.clear(); + // 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) { + const Row row(decc); + _rows[row] = decode::RowData(); + std::map::const_iterator iter = _rows_gshow.find(row); + if (iter == _rows_gshow.end()) { + _rows_gshow[row] = true; + if (row.title().contains("bit", Qt::CaseInsensitive) || + row.title().contains("warning", Qt::CaseInsensitive)) { + _rows_lshow[row] = false; + } else { + _rows_lshow[row] = true; + } + } + } + + // 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(); + std::map::const_iterator iter = _rows_gshow.find(row); + if (iter == _rows_gshow.end()) { + _rows_gshow[row] = true; + if (row.title().contains("bit", Qt::CaseInsensitive) || + row.title().contains("warning", Qt::CaseInsensitive)) { + _rows_lshow[row] = false; + } else { + _rows_lshow[row] = true; + } + } + + // 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; + } + } } int64_t DecoderStack::samples_decoded() const { - lock_guard decode_lock(_output_mutex); + 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); + //lock_guard lock(_output_mutex); - std::map::const_iterator iter = - _rows.find(row); - if (iter != _rows.end()) + 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); + //lock_guard lock(_output_mutex); std::map::const_iterator iter = _rows.find(row); @@ -180,9 +218,57 @@ uint64_t DecoderStack::get_max_annotation(const Row &row) return 0; } +uint64_t DecoderStack::get_min_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_min_annotation(); + + return 0; +} + +std::map DecoderStack::get_rows_gshow() +{ + std::map rows_gshow; + for (std::map::const_iterator i = _rows_gshow.begin(); + i != _rows_gshow.end(); i++) { + rows_gshow[(*i).first] = (*i).second; + } + return rows_gshow; +} + +std::map DecoderStack::get_rows_lshow() +{ + std::map rows_lshow; + for (std::map::const_iterator i = _rows_lshow.begin(); + i != _rows_lshow.end(); i++) { + rows_lshow[(*i).first] = (*i).second; + } + return rows_lshow; +} + +void DecoderStack::set_rows_gshow(const decode::Row row, bool show) +{ + std::map::const_iterator iter = _rows_gshow.find(row); + if (iter != _rows_gshow.end()) { + _rows_gshow[row] = show; + } +} + +void DecoderStack::set_rows_lshow(const decode::Row row, bool show) +{ + std::map::const_iterator iter = _rows_lshow.find(row); + if (iter != _rows_lshow.end()) { + _rows_lshow[row] = show; + } +} + bool DecoderStack::has_annotations(const Row &row) const { - lock_guard lock(_output_mutex); + //lock_guard lock(_output_mutex); std::map::const_iterator iter = _rows.find(row); @@ -195,26 +281,107 @@ bool DecoderStack::has_annotations(const Row &row) const return false; } +uint64_t DecoderStack::list_annotation_size() const +{ + lock_guard lock(_output_mutex); + uint64_t max_annotation_size = 0; + for (map::const_iterator i = _rows.begin(); + i != _rows.end(); i++) { + map::const_iterator iter = _rows_lshow.find((*i).first); + if (iter != _rows_lshow.end() && (*iter).second) + max_annotation_size = max(max_annotation_size, + (*i).second.get_annotation_size()); + } + + return max_annotation_size; +} + +uint64_t DecoderStack::list_annotation_size(uint16_t row_index) const +{ + //lock_guard lock(_output_mutex); + //int row = 0; + for (map::const_iterator i = _rows.begin(); + i != _rows.end(); i++) { + map::const_iterator iter = _rows_lshow.find((*i).first); + if (iter != _rows_lshow.end() && (*iter).second) + if (row_index-- == 0) { + return (*i).second.get_annotation_size(); + } + } + return 0; +} + +bool DecoderStack::list_annotation(pv::data::decode::Annotation &ann, + uint16_t row_index, uint64_t col_index) const +{ + //lock_guard lock(_output_mutex); + for (map::const_iterator i = _rows.begin(); + i != _rows.end(); i++) { + map::const_iterator iter = _rows_lshow.find((*i).first); + if (iter != _rows_lshow.end() && (*iter).second) { + if (row_index-- == 0) { + return (*i).second.get_annotation(ann, col_index); + } + } + } + + return false; +} + + +bool DecoderStack::list_row_title(int row, QString &title) const +{ + //lock_guard lock(_output_mutex); + for (map::const_iterator i = _rows.begin(); + i != _rows.end(); i++) { + map::const_iterator iter = _rows_lshow.find((*i).first); + if (iter != _rows_lshow.end() && (*iter).second) { + if (row-- == 0) { + title = (*i).first.title(); + return 1; + } + } + } + return 0; +} + QString DecoderStack::error_message() { - lock_guard lock(_output_mutex); + //lock_guard lock(_output_mutex); return _error_message; } void DecoderStack::clear() { + //lock_guard decode_lock(_output_mutex); _sample_count = 0; - _frame_complete = false; - _samples_decoded = 0; + _frame_complete = false; + _samples_decoded = 0; + new_decode_data(); _error_message = QString(); - _rows.clear(); - _class_rows.clear(); + for (map::iterator i = _rows.begin(); + i != _rows.end(); i++) + _rows[(*i).first] = decode::RowData(); +// _rows.clear(); +// _rows_gshow.clear(); +// _rows_lshow.clear(); +// _class_rows.clear(); + _no_memory = false; +} + +void DecoderStack::init() +{ + clear(); } void DecoderStack::stop_decode() { - if(_decode_state == Stopped) + //_snapshot.reset(); + + if(_decode_state == Stopped) { + clear(); return; + } if (_decode_thread.get()) { _decode_thread->interrupt(); @@ -222,6 +389,7 @@ void DecoderStack::stop_decode() _decode_state = Stopped; } _decode_thread.reset(); + clear(); } void DecoderStack::begin_decode() @@ -231,14 +399,13 @@ void DecoderStack::begin_decode() if (!_options_changed) return; + _options_changed = false; // 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()) { @@ -247,36 +414,8 @@ void DecoderStack::begin_decode() 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; - } - } +// // Build rows +// build_row(); // We get the logic data of the first channel in the list. // This works because we are currently assuming all @@ -296,12 +435,14 @@ void DecoderStack::begin_decode() if (snapshots.empty()) return; _snapshot = snapshots.front(); + if (_snapshot->empty()) + return; // Get the samplerate and start time _start_time = data->get_start_time(); _samplerate = data->samplerate(); - if (_samplerate == 0.0) - _samplerate = 1.0; + if (_samplerate == 0.0) + return; //_decode_thread = boost::thread(&DecoderStack::decode_proc, this); _decode_thread.reset(new boost::thread(&DecoderStack::decode_proc, this)); @@ -311,8 +452,8 @@ 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++) + for (map::const_iterator i = _rows.begin(); + i != _rows.end(); i++) max_sample_count = max(max_sample_count, (*i).second.get_max_sample()); @@ -321,10 +462,10 @@ uint64_t DecoderStack::get_max_sample_count() const boost::optional DecoderStack::wait_for_data() const { - unique_lock input_lock(_input_mutex); + //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); + //_input_cond.wait(input_lock); return boost::make_optional( !boost::this_thread::interruption_requested() && ((uint64_t)_samples_decoded < _sample_count || !_frame_complete), @@ -332,45 +473,95 @@ boost::optional DecoderStack::wait_for_data() const } void DecoderStack::decode_data( - const uint64_t sample_count, const unsigned int unit_size, - srd_session *const session) + const uint64_t decode_start, const uint64_t decode_end, + const unsigned int unit_size, srd_session *const session) { - //uint8_t chunk[DecodeChunkLength]; uint8_t *chunk = NULL; - //chunk = (uint8_t *)realloc(chunk, DecodeChunkLength); - + uint64_t last_cnt = 0; + uint64_t notify_cnt = (decode_end - decode_start + 1)/100; const uint64_t chunk_sample_count = - DecodeChunkLength / _snapshot->unit_size(); + DecodeChunkLength / _snapshot->unit_size(); + srd_decoder_inst *logic_di = NULL; + // find the first level decoder instant + for (GSList *d = session->di_list; d; d = d->next) { + srd_decoder_inst *di = (srd_decoder_inst *)d->data; + srd_decoder *decoder = di->decoder; + const bool have_probes = (decoder->channels || decoder->opt_channels) != 0; + if (have_probes) { + logic_di = di; + break; + } + } - for (uint64_t i = 0; - !boost::this_thread::interruption_requested() && - i < sample_count; - i += chunk_sample_count) - { + uint64_t entry_cnt = 0; + uint8_t chunk_type = 0; + uint64_t i = decode_start; + char *error = NULL; + while(!boost::this_thread::interruption_requested() && + i < decode_end && !_no_memory) + { //lock_guard decode_lock(_global_decode_mutex); const uint64_t chunk_end = min( - i + chunk_sample_count, sample_count); + i + chunk_sample_count, decode_end); chunk = _snapshot->get_samples(i, chunk_end); - if (srd_session_send(session, i, i + sample_count, chunk, - (chunk_end - i) * unit_size, unit_size) != SRD_OK) { - _error_message = tr("Decoder reported an error"); - break; - } + if (srd_session_send(session, chunk_type, i, chunk_end, chunk, + (chunk_end - i) * unit_size, unit_size, &error) != SRD_OK) { + _error_message = QString::fromLocal8Bit(error); + break; + } - { - lock_guard lock(_output_mutex); - _samples_decoded = chunk_end; - } + if (logic_di && logic_di->logic_mask != 0) { + uint64_t cur_pos = logic_di->cur_pos; + assert(cur_pos < _snapshot->get_sample_count()); + uint64_t sample = _snapshot->get_sample(cur_pos) & logic_di->logic_mask; + if (logic_di->edge_index == -1) { + std::vector pos_vector; + cur_pos++; + for (int j =0 ; j < logic_di->dec_num_channels; j++) { + int index = logic_di->dec_channelmap[j]; + if (index != -1 && (logic_di->logic_mask & (1 << index))) { + bool last_sample = (sample & (1 << index)) ? 1 : 0; + pos_vector.push_back(cur_pos); + _snapshot->get_nxt_edge(pos_vector.back(), last_sample, decode_end, 1, index); + } + } + cur_pos = *std::min_element(pos_vector.begin(), pos_vector.end()); + } else { + bool last_sample = (sample & (1 << logic_di->edge_index)) ? 1 : 0; + do { + cur_pos++; + if (!_snapshot->get_nxt_edge(cur_pos, last_sample, decode_end, 1, logic_di->edge_index)) + break; + sample = _snapshot->get_sample(cur_pos) & logic_di->logic_mask; + last_sample = (sample & (1 << logic_di->edge_index)) ? 1 : 0; + } while(sample != logic_di->exp_logic); + } - if (i % DecodeNotifyPeriod == 0) + i = cur_pos; + if (i >= decode_end) + i = decode_end; + chunk_type = 0; + } else { + i += chunk_sample_count; + chunk_type = 1; + } + + { + lock_guard lock(_output_mutex); + _samples_decoded = i - decode_start + 1; + } + + if ((i - last_cnt) > notify_cnt) { + last_cnt = i; new_decode_data(); - - } - _options_changed = false; + } + entry_cnt++; + } + if (error) + g_free(error); decode_done(); - //new_decode_data(); } void DecoderStack::decode_proc() @@ -380,6 +571,8 @@ void DecoderStack::decode_proc() optional sample_count; srd_session *session; srd_decoder_inst *prev_di = NULL; + uint64_t decode_start = 0; + uint64_t decode_end = 0; assert(_snapshot); @@ -392,6 +585,12 @@ void DecoderStack::decode_proc() // Create the decoders const unsigned int unit_size = _snapshot->unit_size(); + // Get the intial sample count + { + //unique_lock input_lock(_input_mutex); + sample_count = _sample_count = _snapshot->get_sample_count(); + } + BOOST_FOREACH(const shared_ptr &dec, _stack) { srd_decoder_inst *const di = dec->create_decoder_inst(session, unit_size); @@ -407,12 +606,8 @@ void DecoderStack::decode_proc() 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(); + decode_start = dec->decode_start(); + decode_end = min(dec->decode_end(), _sample_count-1); } // Start the session @@ -422,14 +617,15 @@ void DecoderStack::decode_proc() 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); + char *error = NULL; + if (srd_session_start(session, &error) == SRD_OK) + decode_data(decode_start, decode_end, unit_size, session); + else + _error_message = QString::fromLocal8Bit(error); // Destroy the session + if (error) + g_free(error); srd_session_destroy(session); _decode_state = Stopped; @@ -437,7 +633,15 @@ void DecoderStack::decode_proc() uint64_t DecoderStack::sample_count() const { - return _sample_count; + if (_snapshot) + return _snapshot->get_sample_count(); + else + return 0; +} + +uint64_t DecoderStack::sample_rate() const +{ + return _samplerate; } void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) @@ -448,7 +652,10 @@ void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) DecoderStack *const d = (DecoderStack*)decoder; assert(d); - lock_guard lock(d->_output_mutex); + //lock_guard lock(d->_output_mutex); + + if (d->_no_memory) + return; const Annotation a(pdata); @@ -458,29 +665,31 @@ void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) const srd_decoder *const decc = pdata->pdo->di->decoder; assert(decc); - map::iterator row_iter = d->_rows.end(); + 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); + row_iter = d->_rows.find((*r).second); else { // Failing that, use the decoder as a key - row_iter = d->_rows.find(Row(decc)); + 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; - } + 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); + lock_guard lock(d->_output_mutex); + if (!(*row_iter).second.push_annotation(a)) + d->_no_memory = true; } void DecoderStack::on_new_frame() @@ -510,24 +719,33 @@ void DecoderStack::on_frame_ended() begin_decode(); } -int DecoderStack::cur_rows_size() +int DecoderStack::list_rows_size() { + //lock_guard lock(_output_mutex); int rows_size = 0; for (map::const_iterator i = _rows.begin(); - i != _rows.end(); i++) - if ((*i).second.get_max_sample() != 0) + i != _rows.end(); i++) { + map::const_iterator iter = _rows_lshow.find((*i).first); + if (iter != _rows_lshow.end() && (*iter).second) rows_size++; - - if (rows_size == 0) - return 1; - else - return rows_size; + } + return rows_size; } -void DecoderStack::options_changed(bool changed) +bool DecoderStack::options_changed() const +{ + return _options_changed; +} + +void DecoderStack::set_options_changed(bool changed) { _options_changed = changed; } +bool DecoderStack::out_of_memory() const +{ + return _no_memory; +} + } // namespace data } // namespace pv diff --git a/DSView/pv/data/decoderstack.h b/DSView/pv/data/decoderstack.h index b2cd65f8..281a5428 100644 --- a/DSView/pv/data/decoderstack.h +++ b/DSView/pv/data/decoderstack.h @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * Copyright (C) 2012 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 @@ -20,8 +21,7 @@ #ifndef DSVIEW_PV_DATA_DECODERSTACK_H #define DSVIEW_PV_DATA_DECODERSTACK_H - -#include "signaldata.h" +#include #include @@ -32,14 +32,9 @@ #include #include -#include -#include - -struct srd_decoder; -struct srd_decoder_annotation_row; -struct srd_channel; -struct srd_proto_data; -struct srd_session; +#include "../data/decode/row.h" +#include "../data/decode/rowdata.h" +#include "../data/signaldata.h" namespace DecoderStackTest { class TwoDecoderStack; @@ -86,14 +81,13 @@ public: virtual ~DecoderStack(); - const std::list< boost::shared_ptr >& stack() const; + const std::list< boost::shared_ptr >& stack() const; void push(boost::shared_ptr decoder); - void remove(int index); + void remove(boost::shared_ptr& decoder); + void build_row(); int64_t samples_decoded() const; - std::vector< std::pair > get_visible_rows() const; - /** * Extracts sorted annotations between two period into a vector. */ @@ -103,12 +97,29 @@ public: uint64_t end_sample) const; uint64_t get_max_annotation(const decode::Row &row); + uint64_t get_min_annotation(const decode::Row &row); // except instant(end=start) annotation + + std::map get_rows_gshow(); + std::map get_rows_lshow(); + void set_rows_gshow(const decode::Row row, bool show); + void set_rows_lshow(const decode::Row row, bool show); bool has_annotations(const decode::Row &row) const; + uint64_t list_annotation_size() const; + uint64_t list_annotation_size(uint16_t row_index) const; + + + bool list_annotation(decode::Annotation &ann, + uint16_t row_index, uint64_t col_index) const; + + + bool list_row_title(int row, QString &title) const; + QString error_message(); void clear(); + void init(); uint64_t get_max_sample_count() const; @@ -116,16 +127,23 @@ public: void stop_decode(); - int cur_rows_size(); + int list_rows_size(); - void options_changed(bool changed); + bool options_changed() const; + void set_options_changed(bool changed); uint64_t sample_count() const; + uint64_t sample_rate() const; + + bool out_of_memory() const; private: boost::optional wait_for_data() const; - void decode_data(const uint64_t sample_count, +// void decode_data(const uint64_t sample_count, +// const unsigned int unit_size, srd_session *const session); + + void decode_data(const uint64_t decode_start, const uint64_t decode_end, const unsigned int unit_size, srd_session *const session); void decode_proc(); @@ -153,23 +171,25 @@ private: * @todo A proper solution should be implemented to allow multiple * decode operations. */ - static boost::mutex _global_decode_mutex; + 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; + //mutable boost::mutex _input_mutex; + //mutable boost::condition_variable _input_cond; uint64_t _sample_count; bool _frame_complete; - mutable boost::mutex _output_mutex; + mutable boost::recursive_mutex _output_mutex; + //mutable boost::mutex _output_mutex; int64_t _samples_decoded; - std::map _rows; - - std::map, decode::Row> _class_rows; + std::map _rows; + std::map _rows_gshow; + std::map _rows_lshow; + std::map, decode::Row> _class_rows; QString _error_message; @@ -177,6 +197,7 @@ private: decode_state _decode_state; bool _options_changed; + bool _no_memory; friend class DecoderStackTest::TwoDecoderStack; }; diff --git a/DSView/pv/data/dso.cpp b/DSView/pv/data/dso.cpp index 43663737..2a6ce2c7 100644 --- a/DSView/pv/data/dso.cpp +++ b/DSView/pv/data/dso.cpp @@ -2,7 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -23,6 +23,8 @@ #include "dso.h" #include "dsosnapshot.h" +#include + using namespace boost; using namespace std; @@ -46,7 +48,16 @@ deque< boost::shared_ptr >& Dso::get_snapshots() void Dso::clear() { - _snapshots.clear(); + //_snapshots.clear(); + BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + s->clear(); +} + +void Dso::init() +{ + //_snapshots.clear(); + BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + s->init(); } } // namespace data diff --git a/DSView/pv/data/dso.h b/DSView/pv/data/dso.h index be987821..0902972a 100644 --- a/DSView/pv/data/dso.h +++ b/DSView/pv/data/dso.h @@ -2,7 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -45,6 +45,7 @@ public: get_snapshots(); void clear(); + void init(); private: std::deque< boost::shared_ptr > _snapshots; diff --git a/DSView/pv/data/dsosnapshot.cpp b/DSView/pv/data/dsosnapshot.cpp index 4e0e1b26..665c0dbe 100644 --- a/DSView/pv/data/dsosnapshot.cpp +++ b/DSView/pv/data/dsosnapshot.cpp @@ -2,7 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -47,30 +47,106 @@ const uint64_t DsoSnapshot::EnvelopeDataUnit = 4*1024; // bytes const int DsoSnapshot::VrmsScaleFactor = 1 << 8; -DsoSnapshot::DsoSnapshot(const sr_datafeed_dso &dso, uint64_t _total_sample_len, unsigned int channel_num, bool instant) : - Snapshot(sizeof(uint16_t), _total_sample_len, channel_num), +DsoSnapshot::DsoSnapshot() : + Snapshot(sizeof(uint16_t), 1, 1), _envelope_en(false), _envelope_done(false), - _instant(instant) + _instant(false) { - boost::lock_guard lock(_mutex); memset(_envelope_levels, 0, sizeof(_envelope_levels)); - init(_total_sample_len); - append_payload(dso); } DsoSnapshot::~DsoSnapshot() { - boost::lock_guard lock(_mutex); - BOOST_FOREACH(Envelope &e, _envelope_levels[0]) - free(e.samples); + free_envelop(); +} + +void DsoSnapshot::free_envelop() +{ + for (unsigned int i = 0; i < _channel_num; i++) { + BOOST_FOREACH(Envelope &e, _envelope_levels[i]) { + if (e.samples) + free(e.samples); + } + } + memset(_envelope_levels, 0, sizeof(_envelope_levels)); +} + +void DsoSnapshot::init() +{ + boost::lock_guard lock(_mutex); + _sample_count = 0; + _ring_sample_count = 0; + _memory_failed = false; + _last_ended = true; + _envelope_done = false; + for (unsigned int i = 0; i < _channel_num; i++) { + for (unsigned int level = 0; level < ScaleStepCount; level++) { + _envelope_levels[i][level].length = 0; + _envelope_levels[i][level].data_length = 0; + } + } +} + +void DsoSnapshot::clear() +{ + boost::lock_guard lock(_mutex); + free_data(); + free_envelop(); + init(); +} + +void DsoSnapshot::first_payload(const sr_datafeed_dso &dso, uint64_t total_sample_count, unsigned int channel_num, bool instant) +{ + _total_sample_count = total_sample_count; + _channel_num = channel_num; + _instant = instant; + + bool isOk = true; + uint64_t size = _total_sample_count * _unit_size + sizeof(uint64_t); + if (size != _capacity) { + free_data(); + _data = malloc(size); + if (_data) { + free_envelop(); + for (unsigned int i = 0; i < _channel_num; i++) { + uint64_t envelop_count = _total_sample_count / EnvelopeScaleFactor; + for (unsigned int level = 0; level < ScaleStepCount; level++) { + envelop_count = ((envelop_count + EnvelopeDataUnit - 1) / + EnvelopeDataUnit) * EnvelopeDataUnit; + _envelope_levels[i][level].samples = (EnvelopeSample*)malloc(envelop_count * sizeof(EnvelopeSample)); + if (!_envelope_levels[i][level].samples) { + isOk = false; + break; + } + envelop_count = envelop_count / EnvelopeScaleFactor; + } + if (!isOk) + break; + } + } else { + isOk = true; + } + } + + if (isOk) { + _capacity = size; + _memory_failed = false; + append_payload(dso); + _last_ended = false; + } else { + free_data(); + free_envelop(); + _capacity = 0; + _memory_failed = true; + } } void DsoSnapshot::append_payload(const sr_datafeed_dso &dso) { - boost::lock_guard lock(_mutex); + boost::lock_guard lock(_mutex); - if (_channel_num > 0) { + if (_channel_num > 0 && dso.num_samples != 0) { refill_data(dso.data, dso.num_samples, _instant); // Generate the first mip-map from the data @@ -81,6 +157,7 @@ void DsoSnapshot::append_payload(const sr_datafeed_dso &dso) void DsoSnapshot::enable_envelope(bool enable) { + boost::lock_guard lock(_mutex); if (!_envelope_done && enable) append_payload_to_envelope_levels(true); _envelope_en = enable; @@ -89,7 +166,7 @@ void DsoSnapshot::enable_envelope(bool enable) const uint8_t *DsoSnapshot::get_samples( int64_t start_sample, int64_t end_sample, uint16_t index) const { - (void)end_sample; + (void)end_sample; assert(start_sample >= 0); assert(start_sample < (int64_t)get_sample_count()); @@ -97,8 +174,6 @@ const uint8_t *DsoSnapshot::get_samples( assert(end_sample < (int64_t)get_sample_count()); assert(start_sample <= end_sample); - boost::lock_guard lock(_mutex); - // uint16_t *const data = new uint16_t[end_sample - start_sample]; // memcpy(data, (uint16_t*)_data + start_sample, sizeof(uint16_t) * // (end_sample - start_sample)); @@ -113,7 +188,10 @@ void DsoSnapshot::get_envelope_section(EnvelopeSection &s, assert(start <= end); assert(min_length > 0); - boost::lock_guard lock(_mutex); + if (!_envelope_done) { + s.length = 0; + return; + } const unsigned int min_level = max((int)floorf(logf(min_length) / LogEnvelopeScaleFactor) - 1, 0); @@ -124,9 +202,9 @@ void DsoSnapshot::get_envelope_section(EnvelopeSection &s, s.start = start << scale_power; s.scale = 1 << scale_power; - //if (_envelope_levels[probe_index][min_level].length < get_sample_count() / EnvelopeScaleFactor) - // s.length = 0; - //else + if (_envelope_levels[probe_index][min_level].length == 0) + s.length = 0; + else s.length = end - start; // s.samples = new EnvelopeSample[s.length]; // memcpy(s.samples, _envelope_levels[min_level].samples + start, @@ -141,8 +219,8 @@ void DsoSnapshot::reallocate_envelope(Envelope &e) if (new_data_length > e.data_length) { e.data_length = new_data_length; - e.samples = (EnvelopeSample*)realloc(e.samples, - new_data_length * sizeof(EnvelopeSample)); +// e.samples = (EnvelopeSample*)realloc(e.samples, +// new_data_length * sizeof(EnvelopeSample)); } } @@ -240,7 +318,7 @@ void DsoSnapshot::append_payload_to_envelope_levels(bool header) double DsoSnapshot::cal_vrms(double zero_off, int index) const { assert(index >= 0); - assert(index < _channel_num); + //assert(index < _channel_num); // root-meam-squart value double vrms_pre = 0; @@ -249,8 +327,8 @@ double DsoSnapshot::cal_vrms(double zero_off, int index) const // Iterate through the samples to populate the first level mipmap const uint8_t *const stop_src_ptr = (uint8_t*)_data + - _sample_count * _channel_num; - for (const uint8_t *src_ptr = (uint8_t*)_data + index; + get_sample_count() * _channel_num; + for (const uint8_t *src_ptr = (uint8_t*)_data + (index % _channel_num); src_ptr < stop_src_ptr; src_ptr += VrmsScaleFactor * _channel_num) { const uint8_t * begin_src_ptr = @@ -264,7 +342,7 @@ double DsoSnapshot::cal_vrms(double zero_off, int index) const vrms += tmp * tmp; begin_src_ptr += _channel_num; } - vrms = vrms_pre + vrms / _sample_count; + vrms = vrms_pre + vrms / get_sample_count(); vrms_pre = vrms; } vrms = std::pow(vrms, 0.5); @@ -275,7 +353,7 @@ double DsoSnapshot::cal_vrms(double zero_off, int index) const double DsoSnapshot::cal_vmean(int index) const { assert(index >= 0); - assert(index < _channel_num); + //assert(index < _channel_num); // mean value double vmean_pre = 0; @@ -283,8 +361,8 @@ double DsoSnapshot::cal_vmean(int index) const // Iterate through the samples to populate the first level mipmap const uint8_t *const stop_src_ptr = (uint8_t*)_data + - _sample_count * _channel_num; - for (const uint8_t *src_ptr = (uint8_t*)_data + index; + get_sample_count() * _channel_num; + for (const uint8_t *src_ptr = (uint8_t*)_data + (index % _channel_num); src_ptr < stop_src_ptr; src_ptr += VrmsScaleFactor * _channel_num) { const uint8_t * begin_src_ptr = @@ -297,7 +375,7 @@ double DsoSnapshot::cal_vmean(int index) const vmean += *begin_src_ptr; begin_src_ptr += _channel_num; } - vmean = vmean_pre + vmean / _sample_count; + vmean = vmean_pre + vmean / get_sample_count(); vmean_pre = vmean; } diff --git a/DSView/pv/data/dsosnapshot.h b/DSView/pv/data/dsosnapshot.h index eb3788bc..df6376e0 100644 --- a/DSView/pv/data/dsosnapshot.h +++ b/DSView/pv/data/dsosnapshot.h @@ -2,7 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -70,10 +70,15 @@ private: static const int VrmsScaleFactor; public: - DsoSnapshot(const sr_datafeed_dso &dso, uint64_t _total_sample_len, unsigned int channel_num, bool instant); + DsoSnapshot(); virtual ~DsoSnapshot(); + void clear(); + void init(); + + void first_payload(const sr_datafeed_dso &dso, uint64_t total_sample_count, unsigned int channel_num, bool instant); + void append_payload(const sr_datafeed_dso &dso); const uint8_t* get_samples(int64_t start_sample, @@ -88,8 +93,8 @@ public: double cal_vmean(int index) const; private: + void free_envelop(); void reallocate_envelope(Envelope &l); - void append_payload_to_envelope_levels(bool header); private: diff --git a/DSView/pv/data/group.cpp b/DSView/pv/data/group.cpp index e0aab57f..7d027db3 100644 --- a/DSView/pv/data/group.cpp +++ b/DSView/pv/data/group.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -24,6 +23,8 @@ #include "group.h" #include "groupsnapshot.h" +#include + using namespace boost; using namespace std; @@ -47,7 +48,14 @@ deque< boost::shared_ptr >& Group::get_snapshots() void Group::clear() { - _snapshots.clear(); + BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + s->clear(); +} + +void Group::init() +{ + BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + s->init(); } } // namespace data diff --git a/DSView/pv/data/group.h b/DSView/pv/data/group.h index 25f9fb29..1312c6ee 100644 --- a/DSView/pv/data/group.h +++ b/DSView/pv/data/group.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -46,6 +45,7 @@ public: get_snapshots(); void clear(); + void init(); private: std::deque< boost::shared_ptr > _snapshots; diff --git a/DSView/pv/data/groupsnapshot.cpp b/DSView/pv/data/groupsnapshot.cpp index 69a18f1a..e7cac5d3 100644 --- a/DSView/pv/data/groupsnapshot.cpp +++ b/DSView/pv/data/groupsnapshot.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -55,7 +54,7 @@ GroupSnapshot::GroupSnapshot(const boost::shared_ptr &_logic_snap { assert(_logic_snapshot); - boost::lock_guard lock(_mutex); + //boost::lock_guard lock(_mutex); memset(_envelope_levels, 0, sizeof(_envelope_levels)); _data = _logic_snapshot->get_data(); _sample_count = _logic_snapshot->get_sample_count(); @@ -97,20 +96,30 @@ GroupSnapshot::GroupSnapshot(const boost::shared_ptr &_logic_snap GroupSnapshot::~GroupSnapshot() { - boost::lock_guard lock(_mutex); + //boost::lock_guard lock(_mutex); BOOST_FOREACH(Envelope &e, _envelope_levels) free(e.samples); } +void GroupSnapshot::init() +{ + +} + +void GroupSnapshot::clear() +{ + +} + uint64_t GroupSnapshot::get_sample_count() const { - boost::lock_guard lock(_mutex); + //boost::lock_guard lock(_mutex); return _sample_count; } void GroupSnapshot::append_payload() { - boost::lock_guard lock(_mutex); + //boost::lock_guard lock(_mutex); // Generate the first mip-map from the data append_payload_to_envelope_levels(); @@ -127,7 +136,7 @@ const uint16_t* GroupSnapshot::get_samples( int64_t i; uint16_t tmpl, tmpr; - boost::lock_guard lock(_mutex); + //boost::lock_guard lock(_mutex); uint16_t *const data = new uint16_t[end_sample - start_sample]; // memcpy(data, (uint16_t*)_data + start_sample, sizeof(uint16_t) * @@ -156,7 +165,7 @@ void GroupSnapshot::get_envelope_section(EnvelopeSection &s, assert(start <= end); assert(min_length > 0); - boost::lock_guard lock(_mutex); + //boost::lock_guard lock(_mutex); const unsigned int min_level = max((int)floorf(logf(min_length) / LogEnvelopeScaleFactor) - 1, 0); diff --git a/DSView/pv/data/groupsnapshot.h b/DSView/pv/data/groupsnapshot.h index 729b57a7..4d87b001 100644 --- a/DSView/pv/data/groupsnapshot.h +++ b/DSView/pv/data/groupsnapshot.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -80,6 +79,9 @@ public: virtual ~GroupSnapshot(); + void clear(); + void init(); + void append_payload(); uint64_t get_sample_count() const; @@ -97,8 +99,8 @@ private: private: struct Envelope _envelope_levels[ScaleStepCount]; - mutable boost::recursive_mutex _mutex; - void *_data; + //mutable boost::recursive_mutex _mutex; + const void *_data; uint64_t _sample_count; int _unit_size; boost::shared_ptr _signal; diff --git a/DSView/pv/data/logic.cpp b/DSView/pv/data/logic.cpp index 4116942a..ee499f43 100644 --- a/DSView/pv/data/logic.cpp +++ b/DSView/pv/data/logic.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -24,6 +24,8 @@ #include "logic.h" #include "logicsnapshot.h" +#include + using namespace boost; using namespace std; @@ -48,7 +50,16 @@ deque< boost::shared_ptr >& Logic::get_snapshots() void Logic::clear() { - _snapshots.clear(); + //_snapshots.clear(); + BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + s->clear(); +} + +void Logic::init() +{ + //_snapshots.clear(); + BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + s->init(); } } // namespace data diff --git a/DSView/pv/data/logic.h b/DSView/pv/data/logic.h index c7a97158..f163b35c 100644 --- a/DSView/pv/data/logic.h +++ b/DSView/pv/data/logic.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -47,6 +47,8 @@ public: void clear(); + void init(); + private: std::deque< boost::shared_ptr > _snapshots; }; diff --git a/DSView/pv/data/logicsnapshot.cpp b/DSView/pv/data/logicsnapshot.cpp index ebdb904e..40ee3087 100644 --- a/DSView/pv/data/logicsnapshot.cpp +++ b/DSView/pv/data/logicsnapshot.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -23,6 +23,8 @@ #include +#include + #include #include #include @@ -43,21 +45,88 @@ const int LogicSnapshot::MipMapScaleFactor = 1 << MipMapScalePower; const float LogicSnapshot::LogMipMapScaleFactor = logf(MipMapScaleFactor); const uint64_t LogicSnapshot::MipMapDataUnit = 64*1024; // bytes -LogicSnapshot::LogicSnapshot(const sr_datafeed_logic &logic, uint64_t _total_sample_len, unsigned int channel_num) : - Snapshot(logic.unitsize, _total_sample_len, channel_num), - _last_append_sample(0) +LogicSnapshot::LogicSnapshot() : + Snapshot(1, 1, 1), + _last_append_sample(0) { - boost::lock_guard lock(_mutex); - memset(_mip_map, 0, sizeof(_mip_map)); - if (init(_total_sample_len * channel_num) == SR_OK) - append_payload(logic); + memset(_mip_map, 0, sizeof(_mip_map)); } LogicSnapshot::~LogicSnapshot() { - boost::lock_guard lock(_mutex); - BOOST_FOREACH(MipMapLevel &l, _mip_map) - free(l.data); + free_mipmap(); +} + +void LogicSnapshot::free_mipmap() +{ + BOOST_FOREACH(MipMapLevel &l, _mip_map) { + if (l.data) + free(l.data); + } + memset(_mip_map, 0, sizeof(_mip_map)); +} + +void LogicSnapshot::init() +{ + boost::lock_guard lock(_mutex); + _sample_count = 0; + _ring_sample_count = 0; + _memory_failed = false; + _last_ended = true; + for (unsigned int level = 0; level < ScaleStepCount; level++) { + _mip_map[level].length = 0; + _mip_map[level].data_length = 0; + } +} + +void LogicSnapshot::clear() +{ + boost::lock_guard lock(_mutex); + free_data(); + free_mipmap(); + init(); +} + +void LogicSnapshot::first_payload(const sr_datafeed_logic &logic, uint64_t total_sample_count, unsigned int channel_num) +{ + _total_sample_count = total_sample_count; + _channel_num = channel_num; + _unit_size = logic.unitsize; + + bool isOk = true; + uint64_t size = _total_sample_count * _unit_size + sizeof(uint64_t); + if (size != _capacity) { + free_data(); + _data = malloc(size); + if (_data) { + free_mipmap(); + uint64_t mipmap_count = _total_sample_count / MipMapScaleFactor; + for (unsigned int level = 0; level < ScaleStepCount; level++) { + mipmap_count = ((mipmap_count + MipMapDataUnit - 1) / + MipMapDataUnit) * MipMapDataUnit; + _mip_map[level].data = malloc(mipmap_count * _unit_size + sizeof(uint64_t)); + if (!_mip_map[level].data) { + isOk = false; + break; + } + mipmap_count = mipmap_count / MipMapScaleFactor; + } + } else { + isOk = false; + } + } + + if (isOk) { + _capacity = size; + _memory_failed = false; + append_payload(logic); + _last_ended = false; + } else { + free_data(); + free_mipmap(); + _capacity = 0; + _memory_failed = true; + } } void LogicSnapshot::append_payload( @@ -66,7 +135,7 @@ void LogicSnapshot::append_payload( assert(_unit_size == logic.unitsize); assert((logic.length % _unit_size) == 0); - boost::lock_guard lock(_mutex); + boost::lock_guard lock(_mutex); append_data(logic.data, logic.length / _unit_size); @@ -78,13 +147,12 @@ uint8_t * LogicSnapshot::get_samples(int64_t start_sample, int64_t end_sample) c { //assert(data); assert(start_sample >= 0); - assert(start_sample <= (int64_t)_sample_count); + assert(start_sample <= (int64_t)get_sample_count()); assert(end_sample >= 0); - assert(end_sample <= (int64_t)_sample_count); + assert(end_sample <= (int64_t)get_sample_count()); assert(start_sample <= end_sample); (void)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); @@ -100,8 +168,8 @@ void LogicSnapshot::reallocate_mipmap_level(MipMapLevel &m) m.data_length = new_data_length; // Padding is added to allow for the uint64_t write word - m.data = realloc(m.data, new_data_length * _unit_size + - sizeof(uint64_t)); +// m.data = realloc(m.data, new_data_length * _unit_size + +// sizeof(uint64_t)); } } @@ -127,9 +195,9 @@ void LogicSnapshot::append_payload_to_mipmap() dest_ptr = (uint8_t*)m0.data + prev_length * _unit_size; // Iterate through the samples to populate the first level mipmap - const uint8_t *const end_src_ptr = (uint8_t*)_data + + const uint8_t *const end_src_ptr = (uint8_t*)_data + m0.length * _unit_size * MipMapScaleFactor; - for (src_ptr = (uint8_t*)_data + + for (src_ptr = (uint8_t*)_data + prev_length * _unit_size * MipMapScaleFactor; src_ptr < end_src_ptr;) { @@ -192,25 +260,24 @@ void LogicSnapshot::get_subsampled_edges( uint64_t start, uint64_t end, float min_length, int sig_index) { - uint64_t index = start; - bool last_sample; + if (!edges.empty()) + edges.clear(); - assert(end <= get_sample_count()); + if (get_sample_count() == 0) + return; + + assert(end < get_sample_count()); assert(start <= end); assert(min_length > 0); assert(sig_index >= 0); assert(sig_index < 64); - if (!_data) - return; - - boost::lock_guard lock(_mutex); - + uint64_t index = start; + bool last_sample; const uint64_t block_length = (uint64_t)max(min_length, 1.0f); const uint64_t sig_mask = 1ULL << sig_index; - if (!edges.empty()) - edges.clear(); + // Store the initial state last_sample = (get_sample(start) & sig_mask) != 0; edges.push_back(pair(index++, last_sample)); @@ -555,7 +622,7 @@ uint64_t LogicSnapshot::get_subsample(int level, uint64_t offset) const { assert(level >= 0); assert(_mip_map[level].data); - return *(uint64_t*)((uint8_t*)_mip_map[level].data + + return *(uint64_t*)((uint8_t*)_mip_map[level].data + _unit_size * offset); } diff --git a/DSView/pv/data/logicsnapshot.h b/DSView/pv/data/logicsnapshot.h index ba40df84..d1f70635 100644 --- a/DSView/pv/data/logicsnapshot.h +++ b/DSView/pv/data/logicsnapshot.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -61,17 +61,22 @@ public: typedef std::pair EdgePair; public: - LogicSnapshot(const sr_datafeed_logic &logic, uint64_t _total_sample_len, unsigned int channel_num); + LogicSnapshot(); virtual ~LogicSnapshot(); + void clear(); + void init(); + + void first_payload(const sr_datafeed_logic &logic, uint64_t total_sample_count, unsigned int channel_num); + void append_payload(const sr_datafeed_logic &logic); uint8_t * get_samples(int64_t start_sample, int64_t end_sample) const; private: + void free_mipmap(); void reallocate_mipmap_level(MipMapLevel &m); - void append_payload_to_mipmap(); public: diff --git a/DSView/pv/data/mathstack.cpp b/DSView/pv/data/mathstack.cpp new file mode 100644 index 00000000..0bec7874 --- /dev/null +++ b/DSView/pv/data/mathstack.cpp @@ -0,0 +1,246 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2016 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 "mathstack.h" + +#include +#include + +#include +#include +#include +#include + +#define PI 3.1415 + +using namespace boost; +using namespace std; + +namespace pv { +namespace data { + +const QString MathStack::windows_support[5] = { + QT_TR_NOOP("Rectangle"), + QT_TR_NOOP("Hann"), + QT_TR_NOOP("Hamming"), + QT_TR_NOOP("Blackman"), + QT_TR_NOOP("Flat_top") +}; + +const uint64_t MathStack::length_support[5] = { + 1024, + 2048, + 4096, + 8192, + 16384, +}; + +MathStack::MathStack(pv::SigSession &session, int index) : + _session(session), + _index(index), + _dc_ignore(true), + _sample_interval(1), + _math_state(Init), + _fft_plan(NULL) +{ +} + +MathStack::~MathStack() +{ + _xn.clear(); + _xk.clear(); + _power_spectrum.clear(); + if (_fft_plan) + fftw_destroy_plan(_fft_plan); +} + +void MathStack::clear() +{ +} + +void MathStack::init() +{ +} + +int MathStack::get_index() const +{ + return _index; +} + +uint64_t MathStack::get_sample_num() const +{ + return _sample_num; +} + +void MathStack::set_sample_num(uint64_t num) +{ + _sample_num = num; + _xn.resize(_sample_num); + _xk.resize(_sample_num); + _power_spectrum.resize(_sample_num/2+1); + _fft_plan = fftw_plan_r2r_1d(_sample_num, _xn.data(), _xk.data(), + FFTW_R2HC, FFTW_ESTIMATE); +} + +int MathStack::get_windows_index() const +{ + return _windows_index; +} + +void MathStack::set_windows_index(int index) +{ + _windows_index = index; +} + +bool MathStack::dc_ignored() const +{ + return _dc_ignore; +} + +void MathStack::set_dc_ignore(bool ignore) +{ + _dc_ignore = ignore; +} + +int MathStack::get_sample_interval() const +{ + return _sample_interval; +} + +void MathStack::set_sample_interval(int interval) +{ + _sample_interval = interval; +} + +const std::vector MathStack::get_windows_support() const +{ + std::vector windows; + for (size_t i = 0; i < sizeof(windows_support)/sizeof(windows_support[0]); i++) + { + windows.push_back(windows_support[i]); + } + return windows; +} + +const std::vector MathStack::get_length_support() const +{ + std::vector length; + for (size_t i = 0; i < sizeof(length_support)/sizeof(length_support[0]); i++) + { + length.push_back(length_support[i]); + } + return length; +} + +const std::vector MathStack::get_fft_spectrum() const +{ + std::vector empty; + if (_math_state == Stopped) + return _power_spectrum; + else + return empty; +} + +const double MathStack::get_fft_spectrum(uint64_t index) const +{ + if (_math_state == Stopped && index < _power_spectrum.size()) + return _power_spectrum[index]; + else + return -1; +} + +void MathStack::calc_fft() +{ + _math_state = Running; + // Get the dso data + boost::shared_ptr data; + boost::shared_ptr dsoSig; + BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + if (dsoSig = dynamic_pointer_cast(s)) { + if (dsoSig->get_index() == _index && dsoSig->enabled()) { + data = dsoSig->dso_data(); + break; + } + } + } + + if (!data) + return; + + // Check we have a snapshot of data + const deque< boost::shared_ptr > &snapshots = + data->get_snapshots(); + if (snapshots.empty()) + return; + _snapshot = snapshots.front(); + + if (_snapshot->get_sample_count() < _sample_num*_sample_interval) + return; + + // Get the samplerate and start time + _start_time = data->get_start_time(); + _samplerate = data->samplerate(); + if (_samplerate == 0.0) + _samplerate = 1.0; + + // prepare _xn data + const double offset = dsoSig->get_zero_value(); + const double vscale = dsoSig->get_vDialValue() * dsoSig->get_factor() * DS_CONF_DSO_VDIVS / (1000*255.0); + const uint16_t step = _snapshot->get_channel_num() * _sample_interval; + const uint8_t *const samples = _snapshot->get_samples(0, _sample_num*_sample_interval-1, _index); + double wsum = 0; + for (unsigned int i = 0; i < _sample_num; i++) { + double w = window(i, _windows_index); + _xn[i] = ((double)samples[i*step] - offset) * vscale * w; + wsum += w; + } + + // fft + fftw_execute(_fft_plan); + + // calculate power spectrum + _power_spectrum[0] = abs(_xk[0])/wsum; /* DC component */ + for (unsigned int k = 1; k < (_sample_num + 1) / 2; ++k) /* (k < N/2 rounded up) */ + _power_spectrum[k] = sqrt((_xk[k]*_xk[k] + _xk[_sample_num-k]*_xk[_sample_num-k]) * 2) / wsum; + if (_sample_num % 2 == 0) /* N is even */ + _power_spectrum[_sample_num/2] = abs(_xk[_sample_num/2])/wsum; /* Nyquist freq. */ + + _math_state = Stopped; +} + +double MathStack::window(uint64_t i, int type) +{ + const double n_m_1 = _sample_num-1; + switch(type) { + case 1: // Hann window + return 0.5*(1-cos(2*PI*i/n_m_1)); + case 2: // Hamming window + return 0.54-0.46*cos(2*PI*i/n_m_1); + case 3: // Blackman window + return 0.42659-0.49656*cos(2*PI*i/n_m_1) + 0.076849*cos(4*PI*i/n_m_1); + case 4: // Flat_top window + return 1-1.93*cos(2*PI*i/n_m_1)+1.29*cos(4*PI*i/n_m_1)- + 0.388*cos(6*PI*i/n_m_1)+0.028*cos(8*PI*i/n_m_1); + default: + return 1; + } +} + +} // namespace data +} // namespace pv diff --git a/DSView/pv/data/mathstack.h b/DSView/pv/data/mathstack.h new file mode 100644 index 00000000..d9e32423 --- /dev/null +++ b/DSView/pv/data/mathstack.h @@ -0,0 +1,120 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2016 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 DSVIEW_PV_DATA_MATHSTACK_H +#define DSVIEW_PV_DATA_MATHSTACK_H + +#include "signaldata.h" + +#include + +#include +#include +#include + +#include + +#include +#include + +namespace pv { + +class SigSession; + +namespace view { +class DsoSignal; +} + +namespace data { + +class DsoSnapshot; +class Dso; + +class MathStack : public QObject, public SignalData +{ + Q_OBJECT + +private: + static const QString windows_support[5]; + static const uint64_t length_support[5]; + +public: + enum math_state { + Init, + Stopped, + Running + }; + +public: + MathStack(pv::SigSession &_session, int index); + virtual ~MathStack(); + void clear(); + void init(); + + int get_index() const; + + uint64_t get_sample_num() const; + void set_sample_num(uint64_t num); + + int get_windows_index() const; + void set_windows_index(int index); + + const std::vector get_windows_support() const; + const std::vector get_length_support() const; + + bool dc_ignored() const; + void set_dc_ignore(bool ignore); + + int get_sample_interval() const; + void set_sample_interval(int interval); + + const std::vector get_fft_spectrum() const; + const double get_fft_spectrum(uint64_t index) const; + + void calc_fft(); + + double window(uint64_t i, int type); + +signals: + +private: + pv::SigSession &_session; + + int _index; + uint64_t _sample_num; + int _windows_index; + bool _dc_ignore; + int _sample_interval; + + boost::shared_ptr _snapshot; + + std::unique_ptr _math_thread; + math_state _math_state; + + fftw_plan _fft_plan; + std::vector _xn; + std::vector _xk; + std::vector _power_spectrum; +}; + +} // namespace data +} // namespace pv + +#endif // DSVIEW_PV_DATA_MATHSTACK_H diff --git a/DSView/pv/data/signaldata.cpp b/DSView/pv/data/signaldata.cpp index b97e026a..00c7e5ef 100644 --- a/DSView/pv/data/signaldata.cpp +++ b/DSView/pv/data/signaldata.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -42,7 +42,6 @@ void SignalData::set_samplerate(double samplerate) { assert(samplerate > 0); _samplerate = samplerate; - clear(); } double SignalData::get_start_time() const diff --git a/DSView/pv/data/signaldata.h b/DSView/pv/data/signaldata.h index 86279376..7f96312e 100644 --- a/DSView/pv/data/signaldata.h +++ b/DSView/pv/data/signaldata.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -40,6 +40,8 @@ public: virtual void clear() = 0; + virtual void init() = 0; + double get_start_time() const; protected: diff --git a/DSView/pv/data/snapshot.cpp b/DSView/pv/data/snapshot.cpp index 57be15e7..df2c8011 100644 --- a/DSView/pv/data/snapshot.cpp +++ b/DSView/pv/data/snapshot.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -23,6 +23,8 @@ #include "snapshot.h" +#include + #include #include #include @@ -34,81 +36,86 @@ namespace data { Snapshot::Snapshot(int unit_size, uint64_t total_sample_count, unsigned int channel_num) : _data(NULL), + _capacity(0), _channel_num(channel_num), _sample_count(0), _total_sample_count(total_sample_count), _ring_sample_count(0), - _unit_size(unit_size) + _unit_size(unit_size), + _memory_failed(false), + _last_ended(true) { - boost::lock_guard lock(_mutex); - assert(_unit_size > 0); + assert(_unit_size > 0); } Snapshot::~Snapshot() { - boost::lock_guard lock(_mutex); - if (_data != NULL) + free_data(); +} + +void Snapshot::free_data() +{ + if (_data) { free(_data); - _data = NULL; + _data = NULL; + _capacity = 0; + } } -int Snapshot::init(uint64_t _total_sample_len) +bool Snapshot::memory_failed() const { - boost::lock_guard lock(_mutex); - _data = malloc(_total_sample_len * _unit_size + - sizeof(uint64_t)); - - if (_data == NULL) - return SR_ERR_MALLOC; - else - return SR_OK; + return _memory_failed; } -bool Snapshot::buf_null() const +bool Snapshot::empty() const { - if (_data == NULL) + if (get_sample_count() == 0 || _memory_failed || !_data) return true; else return false; } +bool Snapshot::last_ended() const +{ + return _last_ended; +} + +void Snapshot::set_last_ended(bool ended) +{ + _last_ended = ended; +} + uint64_t Snapshot::get_sample_count() const { - boost::lock_guard lock(_mutex); + boost::lock_guard lock(_mutex); return _sample_count; } -void* Snapshot::get_data() const +const void* Snapshot::get_data() const { - boost::lock_guard lock(_mutex); return _data; } int Snapshot::unit_size() const { - boost::lock_guard lock(_mutex); return _unit_size; } unsigned int Snapshot::get_channel_num() const { - boost::lock_guard lock(_mutex); return _channel_num; } uint64_t Snapshot::get_sample(uint64_t index) const { - boost::lock_guard lock(_mutex); - assert(_data); - assert(index < _sample_count); + assert(index < get_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); // _data = realloc(_data, (_sample_count + samples) * _unit_size + // sizeof(uint64_t)); if (_sample_count + samples < _total_sample_count) @@ -131,8 +138,6 @@ void Snapshot::append_data(void *data, uint64_t samples) void Snapshot::refill_data(void *data, uint64_t samples, bool instant) { - boost::lock_guard lock(_mutex); - if (instant) { memcpy((uint8_t*)_data + _sample_count * _channel_num, data, samples*_channel_num); _sample_count = (_sample_count + samples) % (_total_sample_count + 1); diff --git a/DSView/pv/data/snapshot.h b/DSView/pv/data/snapshot.h index b128a83c..5fa3e440 100644 --- a/DSView/pv/data/snapshot.h +++ b/DSView/pv/data/snapshot.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -38,15 +38,20 @@ public: virtual ~Snapshot(); - int init(uint64_t _total_sample_len); + virtual void clear() = 0; + virtual void init() = 0; uint64_t get_sample_count() const; - void * get_data() const; + const void * get_data() const; int unit_size() const; - bool buf_null() const; + bool memory_failed() const; + bool empty() const; + + bool last_ended() const; + void set_last_ended(bool ended); unsigned int get_channel_num() const; @@ -55,15 +60,20 @@ public: protected: void append_data(void *data, uint64_t samples); void refill_data(void *data, uint64_t samples, bool instant); + void free_data(); protected: - mutable boost::recursive_mutex _mutex; - void *_data; + mutable boost::recursive_mutex _mutex; + //std::vector _data; + void* _data; + uint64_t _capacity; unsigned int _channel_num; uint64_t _sample_count; uint64_t _total_sample_count; uint64_t _ring_sample_count; int _unit_size; + bool _memory_failed; + bool _last_ended; }; } // namespace data diff --git a/DSView/pv/device/device.cpp b/DSView/pv/device/device.cpp index 76fd520b..74b021f8 100644 --- a/DSView/pv/device/device.cpp +++ b/DSView/pv/device/device.cpp @@ -44,14 +44,14 @@ sr_dev_inst* Device::dev_inst() const void Device::use(SigSession *owner) throw(QString) { - DevInst::use(owner); + DevInst::use(owner); - sr_session_new(); + sr_session_new(); - assert(_sdi); - sr_dev_open(_sdi); - if (sr_session_dev_add(_sdi) != SR_OK) - throw QString(tr("Failed to use device.")); + assert(_sdi); + sr_dev_open(_sdi); + if (sr_session_dev_add(_sdi) != SR_OK) + throw QString(tr("Failed to use device.")); } void Device::release() diff --git a/DSView/pv/device/devinst.cpp b/DSView/pv/device/devinst.cpp index 731df1fc..347ce869 100644 --- a/DSView/pv/device/devinst.cpp +++ b/DSView/pv/device/devinst.cpp @@ -183,6 +183,13 @@ GSList* DevInst::get_dev_mode_list() return sr_dev_mode_list(sdi); } +QString DevInst::name() +{ + sr_dev_inst *const sdi = dev_inst(); + assert(sdi); + return QString::fromLocal8Bit(sdi->driver->name); +} + bool DevInst::is_trigger_enabled() const { return false; diff --git a/DSView/pv/device/devinst.h b/DSView/pv/device/devinst.h index da441a7f..dec1b525 100644 --- a/DSView/pv/device/devinst.h +++ b/DSView/pv/device/devinst.h @@ -109,6 +109,13 @@ public: */ GSList* get_dev_mode_list(); + /** + * @brief Get the device name from the driver + * + * @return device name + */ + QString name(); + virtual bool is_trigger_enabled() const; public: @@ -119,6 +126,7 @@ public: virtual void* get_id() const; signals: + void device_updated(); void config_changed(); protected: diff --git a/DSView/pv/devicemanager.cpp b/DSView/pv/devicemanager.cpp index 066af640..7b986105 100644 --- a/DSView/pv/devicemanager.cpp +++ b/DSView/pv/devicemanager.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -47,8 +47,6 @@ using std::ostringstream; using std::runtime_error; using std::string; -char config_path[256]; - namespace pv { DeviceManager::DeviceManager(struct sr_context *sr_ctx) : @@ -103,12 +101,9 @@ std::list > DeviceManager::driver_scan( // Check If DSL hardware driver if (strncmp(driver->name, "virtual", 7)) { - QDir dir(QCoreApplication::applicationDirPath()); - if (!dir.cd("res")) + QDir dir(DS_RES_PATH); + if (!dir.exists()) return driver_devices; - QString str = dir.absolutePath() + "/"; - QString str_utf8 = QString::fromLocal8Bit(str.toLocal8Bit()); - strcpy(config_path, str_utf8.toUtf8().data()); } // Do the scan diff --git a/DSView/pv/devicemanager.h b/DSView/pv/devicemanager.h index fde8ad1e..3f0b313a 100644 --- a/DSView/pv/devicemanager.h +++ b/DSView/pv/devicemanager.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 diff --git a/DSView/pv/dialogs/about.cpp b/DSView/pv/dialogs/about.cpp index 6809fd70..93cd4dce 100644 --- a/DSView/pv/dialogs/about.cpp +++ b/DSView/pv/dialogs/about.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -21,45 +21,41 @@ */ -#include +#include +#include #include "about.h" -#include - -/* __STDC_FORMAT_MACROS is required for PRIu64 and friends (in C++). */ -#define __STDC_FORMAT_MACROS -#include -#include - namespace pv { namespace dialogs { About::About(QWidget *parent) : - QDialog(parent), - ui(new Ui::About) + DSDialog(parent, true) { - ui->setupUi(this); + QPixmap pix(":/icons/dsl_logo.png"); + _logo = new QLabel(this); + _logo->setPixmap(pix); + _logo->setAlignment(Qt::AlignCenter); - /* Setup the version field */ - ui->versionInfo->setText(tr("%1 %2
%4") - .arg(QApplication::applicationName()) - .arg(QApplication::applicationVersion()) - .arg(QApplication::organizationDomain())); - ui->versionInfo->setOpenExternalLinks(true); + _info = new QLabel(this); + _info->setText(tr("%1 %2
%4") + .arg(QApplication::applicationName()) + .arg(QApplication::applicationVersion()) + .arg(QApplication::organizationDomain())); + _info->setOpenExternalLinks(true); + _info->setAlignment(Qt::AlignCenter); - connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + QVBoxLayout *xlayout = new QVBoxLayout(); + xlayout->addWidget(_logo); + xlayout->addWidget(_info); + + layout()->addLayout(xlayout); + setTitle(tr("About")); + setFixedWidth(500); } About::~About() { - delete ui; -} - -void About::accept() -{ - using namespace Qt; - QDialog::accept(); } } // namespace dialogs diff --git a/DSView/pv/dialogs/about.h b/DSView/pv/dialogs/about.h index 6d140472..59b14233 100644 --- a/DSView/pv/dialogs/about.h +++ b/DSView/pv/dialogs/about.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -24,18 +24,13 @@ #ifndef DSVIEW_PV_ABOUT_H #define DSVIEW_PV_ABOUT_H -#include - -#include - -namespace Ui { -class About; -} +#include +#include "dsdialog.h" namespace pv { namespace dialogs { -class About : public QDialog +class About : public DSDialog { Q_OBJECT @@ -43,11 +38,9 @@ public: explicit About(QWidget *parent = 0); ~About(); -protected: - void accept(); - private: - Ui::About *ui; + QLabel *_logo; + QLabel *_info; }; } // namespace dialogs diff --git a/DSView/pv/dialogs/about.ui b/DSView/pv/dialogs/about.ui deleted file mode 100644 index d4fef85d..00000000 --- a/DSView/pv/dialogs/about.ui +++ /dev/null @@ -1,69 +0,0 @@ - - - About - - - Qt::WindowModal - - - - 0 - 0 - 600 - 320 - - - - - 600 - 320 - - - - About - - - - - - - - - - - - - - :/icons/dsl_logo.png - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - QDialogButtonBox::Ok - - - - - - - - - - - - diff --git a/DSView/pv/dialogs/calibration.cpp b/DSView/pv/dialogs/calibration.cpp new file mode 100755 index 00000000..f9e7995e --- /dev/null +++ b/DSView/pv/dialogs/calibration.cpp @@ -0,0 +1,304 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 "calibration.h" + +#include + +#include +#include +#include +#include +#include + +#include "libsigrok4DSL/libsigrok.h" +#include "../view/trace.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace dialogs { + +const QString Calibration::VGAIN = QT_TR_NOOP(" VGAIN"); +const QString Calibration::VOFF = QT_TR_NOOP(" VOFF"); + +Calibration::Calibration(QWidget *parent) : + DSDialog(parent) +{ + this->setFixedSize(400, 250); + this->setWindowOpacity(0.7); + this->setModal(false); + + _dev_inst = NULL; + _save_btn = new QPushButton(tr("Save"), this); + _reset_btn = new QPushButton(tr("Reset"), this); + _exit_btn = new QPushButton(tr("Exit"), this); + + _flayout = new QFormLayout(); + _flayout->setVerticalSpacing(10); + _flayout->setFormAlignment(Qt::AlignLeft); + _flayout->setLabelAlignment(Qt::AlignLeft); + _flayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + QGridLayout *glayout = new QGridLayout(); + glayout->setVerticalSpacing(5); + + glayout->addLayout(_flayout, 1, 0, 1, 5); + glayout->addWidget(_save_btn, 2, 0); + glayout->addWidget(new QWidget(this), 2, 1); + glayout->setColumnStretch(1, 1); + glayout->addWidget(_reset_btn, 2, 2); + glayout->addWidget(new QWidget(this), 2, 3); + glayout->setColumnStretch(3, 1); + glayout->addWidget(_exit_btn, 2, 4); + + layout()->addLayout(glayout); + setTitle(tr("Manual Calibration")); + + connect(_save_btn, SIGNAL(clicked()), this, SLOT(on_save())); + connect(_reset_btn, SIGNAL(clicked()), this, SLOT(on_reset())); + connect(_exit_btn, SIGNAL(clicked()), this, SLOT(reject())); +} + +void Calibration::set_device(boost::shared_ptr dev_inst) +{ + assert(dev_inst); + _dev_inst = dev_inst; + + for(std::list::const_iterator i = _slider_list.begin(); + i != _slider_list.end(); i++) { + (*i)->setParent(NULL); + _flayout->removeWidget((*i)); + delete (*i); + } + _slider_list.clear(); + for(std::list::const_iterator i = _label_list.begin(); + i != _label_list.end(); i++) { + (*i)->setParent(NULL); + _flayout->removeWidget((*i)); + delete (*i); + } + _label_list.clear(); + + for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { + sr_channel *const probe = (sr_channel*)l->data; + assert(probe); + + uint64_t vgain = 0, vgain_default = 0; + uint16_t vgain_range = 0; + GVariant* gvar = _dev_inst->get_config(probe, NULL, SR_CONF_VGAIN); + if (gvar != NULL) { + vgain = g_variant_get_uint64(gvar); + g_variant_unref(gvar); + } + gvar = _dev_inst->get_config(probe, NULL, SR_CONF_VGAIN_DEFAULT); + if (gvar != NULL) { + vgain_default = g_variant_get_uint64(gvar); + g_variant_unref(gvar); + } + gvar = _dev_inst->get_config(probe, NULL, SR_CONF_VGAIN_RANGE); + if (gvar != NULL) { + vgain_range = g_variant_get_uint16(gvar); + g_variant_unref(gvar); + } + + QSlider *gain_slider = new QSlider(Qt::Horizontal, this); + gain_slider->setRange(-vgain_range/2, vgain_range/2); + gain_slider->setValue(vgain - vgain_default); + gain_slider->setObjectName(VGAIN+probe->index); + QString gain_string = "Channel" + QString::number(probe->index) + VGAIN; + QLabel *gain_label = new QLabel(gain_string, this); + _flayout->addRow(gain_label, gain_slider); + _slider_list.push_back(gain_slider); + _label_list.push_back(gain_label); + + uint64_t voff = 0; + uint16_t voff_range = 0; + gvar = _dev_inst->get_config(probe, NULL, SR_CONF_VOFF); + if (gvar != NULL) { + voff = g_variant_get_uint16(gvar); + g_variant_unref(gvar); + } + gvar = _dev_inst->get_config(probe, NULL, SR_CONF_VOFF_RANGE); + if (gvar != NULL) { + voff_range = g_variant_get_uint16(gvar); + g_variant_unref(gvar); + } + QSlider *off_slider = new QSlider(Qt::Horizontal, this); + off_slider->setRange(0, voff_range); + off_slider->setValue(voff); + off_slider->setObjectName(VOFF+probe->index); + QString off_string = "Channel" + QString::number(probe->index) + VOFF; + QLabel *off_label = new QLabel(off_string, this); + _flayout->addRow(off_label, off_slider); + _slider_list.push_back(off_slider); + _label_list.push_back(off_label); + + connect(gain_slider, SIGNAL(valueChanged(int)), this, SLOT(set_value(int))); + connect(off_slider, SIGNAL(valueChanged(int)), this, SLOT(set_value(int))); + } + + update(); +} + +void Calibration::accept() +{ + using namespace Qt; + _dev_inst->set_config(NULL, NULL, SR_CONF_CALI, g_variant_new_boolean(false)); + QDialog::accept(); +} + +void Calibration::reject() +{ + using namespace Qt; + _dev_inst->set_config(NULL, NULL, SR_CONF_CALI, g_variant_new_boolean(false)); + QDialog::reject(); +} + +void Calibration::set_value(int value) +{ + QSlider* sc = dynamic_cast(sender()); + + for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { + sr_channel *const probe = (sr_channel*)l->data; + assert(probe); + if (sc->objectName() == VGAIN+probe->index) { + uint64_t vgain_default; + GVariant* gvar = _dev_inst->get_config(probe, NULL, SR_CONF_VGAIN_DEFAULT); + if (gvar != NULL) { + vgain_default = g_variant_get_uint64(gvar); + g_variant_unref(gvar); + _dev_inst->set_config(probe, NULL, SR_CONF_VGAIN, + g_variant_new_uint64(value+vgain_default)); + } + break; + } else if (sc->objectName() == VOFF+probe->index) { + _dev_inst->set_config(probe, NULL, SR_CONF_VOFF, + g_variant_new_uint16(value)); + break; + } + } +} + +void Calibration::on_save() +{ + this->hide(); + QFuture future; + future = QtConcurrent::run([&]{ + //QTime dieTime = QTime::currentTime().addSecs(1); + _dev_inst->set_config(NULL, NULL, SR_CONF_ZERO_SET, + g_variant_new_boolean(true)); + //while( QTime::currentTime() < dieTime ); + }); + Qt::WindowFlags flags = Qt::CustomizeWindowHint; + QProgressDialog dlg(tr("Save Calibration Result... It can take a while."), + tr("Cancel"),0,0,this,flags); + dlg.setWindowModality(Qt::WindowModal); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + dlg.setCancelButton(NULL); + + QFutureWatcher watcher; + connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); + watcher.setFuture(future); + + dlg.exec(); + this->show(); +} + +void Calibration::on_reset() +{ + this->hide(); + QFuture future; + future = QtConcurrent::run([&]{ + //QTime dieTime = QTime::currentTime().addSecs(1); + _dev_inst->set_config(NULL, NULL, SR_CONF_ZERO_LOAD, + g_variant_new_boolean(true)); + reload_value(); + //while( QTime::currentTime() < dieTime ); + }); + Qt::WindowFlags flags = Qt::CustomizeWindowHint; + QProgressDialog dlg(tr("Reset Calibration Result... It can take a while."), + tr("Cancel"),0,0,this,flags); + dlg.setWindowModality(Qt::WindowModal); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + dlg.setCancelButton(NULL); + + QFutureWatcher watcher; + connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); + watcher.setFuture(future); + + dlg.exec(); + this->show(); +} + +void Calibration::reload_value() +{ + for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { + sr_channel *const probe = (sr_channel*)l->data; + assert(probe); + + uint64_t vgain = 0, vgain_default = 0; + uint16_t vgain_range = 0; + GVariant* gvar = _dev_inst->get_config(probe, NULL, SR_CONF_VGAIN); + if (gvar != NULL) { + vgain = g_variant_get_uint64(gvar); + g_variant_unref(gvar); + } + gvar = _dev_inst->get_config(probe, NULL, SR_CONF_VGAIN_DEFAULT); + if (gvar != NULL) { + vgain_default = g_variant_get_uint64(gvar); + g_variant_unref(gvar); + } + gvar = _dev_inst->get_config(probe, NULL, SR_CONF_VGAIN_RANGE); + if (gvar != NULL) { + vgain_range = g_variant_get_uint16(gvar); + g_variant_unref(gvar); + } + + uint64_t voff = 0; + uint16_t voff_range = 0; + gvar = _dev_inst->get_config(probe, NULL, SR_CONF_VOFF); + if (gvar != NULL) { + voff = g_variant_get_uint16(gvar); + g_variant_unref(gvar); + } + gvar = _dev_inst->get_config(probe, NULL, SR_CONF_VOFF_RANGE); + if (gvar != NULL) { + voff_range = g_variant_get_uint16(gvar); + g_variant_unref(gvar); + } + + for(std::list::iterator i = _slider_list.begin(); + i != _slider_list.end(); i++) { + if ((*i)->objectName() == VGAIN+probe->index) { + (*i)->setRange(-vgain_range/2, vgain_range/2); + (*i)->setValue(vgain - vgain_default); + } else if ((*i)->objectName() == VOFF+probe->index) { + (*i)->setRange(0, voff_range); + (*i)->setValue(voff); + } + } + } +} + +} // namespace dialogs +} // namespace pv diff --git a/DSView/pv/dialogs/streamoptions.h b/DSView/pv/dialogs/calibration.h old mode 100644 new mode 100755 similarity index 58% rename from DSView/pv/dialogs/streamoptions.h rename to DSView/pv/dialogs/calibration.h index 03fdcc5b..9e469f1b --- a/DSView/pv/dialogs/streamoptions.h +++ b/DSView/pv/dialogs/calibration.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * Copyright (C) 2016 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 @@ -21,56 +20,60 @@ */ -#ifndef DSVIEW_PV_STREAMOPTIONS_H -#define DSVIEW_PV_STREAMOPTIONS_H +#ifndef DSVIEW_PV_CALIBRATION_H +#define DSVIEW_PV_CALIBRATION_H -#include #include -#include -#include -#include -#include #include -#include #include -#include -#include -#include +#include +#include +#include #include #include -#include +#include "../toolbars/titlebar.h" +#include "dsdialog.h" namespace pv { namespace dialogs { -class StreamOptions : public QDialog +class Calibration : public DSDialog { Q_OBJECT -public: - StreamOptions(QWidget *parent, boost::shared_ptr dev_inst, - uint64_t sample_count, bool stream); +private: + static const QString VGAIN; + static const QString VOFF; +public: + Calibration(QWidget *parent); + + void set_device(boost::shared_ptr dev_inst); protected: void accept(); void reject(); +private slots: + void set_value(int value); + void on_save(); + void on_reset(); + void reload_value(); + private: boost::shared_ptr _dev_inst; - uint64_t _sample_count; - QVBoxLayout _layout; - QRadioButton * _op0; - QRadioButton * _op1; - - bool _stream; - - QDialogButtonBox _button_box; + toolbars::TitleBar *_titlebar; + QPushButton *_save_btn; + QPushButton *_reset_btn; + QPushButton *_exit_btn; + QFormLayout *_flayout; + std::list _slider_list; + std::list _label_list; }; } // namespace dialogs } // namespace pv -#endif // DSVIEW_PV_STREAMOPTIONS_H +#endif // DSVIEW_PV_CALIBRATION_H diff --git a/DSView/pv/dialogs/deviceoptions.cpp b/DSView/pv/dialogs/deviceoptions.cpp index f6a7874e..74f8f557 100644 --- a/DSView/pv/dialogs/deviceoptions.cpp +++ b/DSView/pv/dialogs/deviceoptions.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -27,8 +27,8 @@ #include #include -#include +#include "dsmessagebox.h" #include using namespace boost; @@ -38,19 +38,14 @@ namespace pv { namespace dialogs { DeviceOptions::DeviceOptions(QWidget *parent, boost::shared_ptr dev_inst) : - QDialog(parent), + DSDialog(parent), _dev_inst(dev_inst), - _layout(this), _button_box(QDialogButtonBox::Ok, Qt::Horizontal, this), _device_options_binding(_dev_inst->dev_inst()) { - setWindowTitle(tr("Configure Device")); - setLayout(&_layout); - _props_box = new QGroupBox(tr("Mode"), this); - _props_box->setLayout(&_props_box_layout); - _props_box_layout.addWidget(get_property_form()); + _props_box->setLayout(get_property_form(_props_box)); _layout.addWidget(_props_box); if (_dev_inst->dev_inst()->mode != DSO) { @@ -58,17 +53,25 @@ DeviceOptions::DeviceOptions(QWidget *parent, boost::shared_ptrsetLayout(&_probes_box_layout); _layout.addWidget(_probes_box); - } else { + } else if (_dev_inst->name().contains("DSCope")){ _config_button = new QPushButton(tr("Zero Adjustment"), this); _layout.addWidget(_config_button); connect(_config_button, SIGNAL(clicked()), this, SLOT(zero_adj())); + + _cali_button = new QPushButton(tr("Manual Calibration"), this); + _layout.addWidget(_cali_button); + connect(_cali_button, SIGNAL(clicked()), this, SLOT(on_calibration())); } _layout.addStretch(1); _layout.addWidget(&_button_box); + layout()->addLayout(&_layout); + setTitle(tr("Device Options")); + connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); //connect(&_button_box, SIGNAL(rejected()), this, SLOT(reject())); + connect(_dev_inst.get(), SIGNAL(device_updated()), this, SLOT(reject())); GVariant* gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_OPERATION_MODE); if (gvar != NULL) { @@ -109,28 +112,32 @@ void DeviceOptions::accept() void DeviceOptions::reject() { - accept(); + using namespace Qt; + + QDialog::reject(); } -QWidget* DeviceOptions::get_property_form() +QGridLayout * DeviceOptions::get_property_form(QWidget * parent) { - QWidget *const form = new QWidget(this); - QFormLayout *const layout = new QFormLayout(form); - form->setLayout(layout); + QGridLayout *const layout = new QGridLayout(parent); + layout->setVerticalSpacing(5); const vector< boost::shared_ptr > &properties = _device_options_binding.properties(); - BOOST_FOREACH(boost::shared_ptr p, properties) + int i = 0; + BOOST_FOREACH(boost::shared_ptr p, properties) { assert(p); const QString label = p->labeled_widget() ? QString() : p->name(); + layout->addWidget(new QLabel(label, parent), i, 0); if (label == tr("Operation Mode")) - layout->addRow(label, p->get_widget(form, true)); + layout->addWidget(p->get_widget(parent, true), i, 1); else - layout->addRow(label, p->get_widget(form)); + layout->addWidget(p->get_widget(parent), i, 1); + i++; } - return form; + return layout; } void DeviceOptions::setup_probes() @@ -171,8 +178,8 @@ void DeviceOptions::setup_probes() ch_opts->setChecked(true); } } + g_variant_unref(gvar_opts); } - g_variant_unref(gvar_opts); } for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { @@ -226,21 +233,27 @@ void DeviceOptions::disable_all_probes() void DeviceOptions::zero_adj() { using namespace Qt; - QDialog::reject(); + QDialog::accept(); - QMessageBox msg(this); - msg.setText(tr("Information")); - msg.setInformativeText(tr("Zero adjustment program will be started. This may take a few minutes!")); - //msg.setStandardButtons(QMessageBox::); - msg.addButton(tr("Ok"), QMessageBox::AcceptRole); - msg.addButton(tr("Cancel"), QMessageBox::RejectRole); - msg.setIcon(QMessageBox::Information); - int ret = msg.exec(); - if ( ret == QMessageBox::AcceptRole) { + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Information")); + msg.mBox()->setInformativeText(tr("Zero adjustment program will be started. Please keep all channels out of singal input. It can take a while!")); + //msg.mBox()->setStandardButtons(QMessageBox::); + msg.mBox()->addButton(tr("Ok"), QMessageBox::AcceptRole); + msg.mBox()->addButton(tr("Cancel"), QMessageBox::RejectRole); + msg.mBox()->setIcon(QMessageBox::Information); + if (msg.exec()) { _dev_inst->set_config(NULL, NULL, SR_CONF_ZERO, g_variant_new_boolean(true)); } } +void DeviceOptions::on_calibration() +{ + using namespace Qt; + QDialog::accept(); + _dev_inst->set_config(NULL, NULL, SR_CONF_CALI, g_variant_new_boolean(true)); +} + void DeviceOptions::mode_check() { bool test; diff --git a/DSView/pv/dialogs/deviceoptions.h b/DSView/pv/dialogs/deviceoptions.h index e8cc4ce7..6de30d94 100644 --- a/DSView/pv/dialogs/deviceoptions.h +++ b/DSView/pv/dialogs/deviceoptions.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -42,11 +42,13 @@ #include #include +#include "../toolbars/titlebar.h" +#include "../dialogs/dsdialog.h" namespace pv { namespace dialogs { -class DeviceOptions : public QDialog +class DeviceOptions : public DSDialog { Q_OBJECT @@ -59,7 +61,7 @@ protected: private: - QWidget* get_property_form(); + QGridLayout *get_property_form(QWidget *parent); void setup_probes(); @@ -71,10 +73,12 @@ private slots: void zero_adj(); void mode_check(); void channel_check(); + void on_calibration(); private: boost::shared_ptr _dev_inst; QVBoxLayout _layout; + toolbars::TitleBar *_titlebar; QGroupBox *_probes_box; QGridLayout _probes_box_layout; @@ -82,9 +86,9 @@ private: QVector _probes_checkBox_list; QGroupBox *_props_box; - QVBoxLayout _props_box_layout; QPushButton *_config_button; + QPushButton *_cali_button; QDialogButtonBox _button_box; QTimer _mode_check; diff --git a/DSView/pv/dialogs/dsdialog.cpp b/DSView/pv/dialogs/dsdialog.cpp new file mode 100755 index 00000000..01f4a685 --- /dev/null +++ b/DSView/pv/dialogs/dsdialog.cpp @@ -0,0 +1,145 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 "dsdialog.h" +#include "shadow.h" + +#include +#include +#include +#include +#include + +namespace pv { +namespace dialogs { + +DSDialog::DSDialog(QWidget *parent, bool hasClose) : + QDialog(parent), + _moving(false) +{ + setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); + setAttribute(Qt::WA_TranslucentBackground); + + build_main(hasClose); + + _layout = new QVBoxLayout(this); + _layout->addWidget(_main); + setLayout(_layout); +} + +void DSDialog::accept() +{ + using namespace Qt; + + QDialog::accept(); +} + +void DSDialog::reject() +{ + using namespace Qt; + + QDialog::reject(); +} + +bool DSDialog::eventFilter(QObject *object, QEvent *event) +{ + (void)object; + const QEvent::Type type = event->type(); + const QMouseEvent *const mouse_event = (QMouseEvent*)event; + if (type == QEvent::MouseMove) { + if (_moving && mouse_event->buttons().testFlag(Qt::LeftButton)) { + move(mouse_event->globalPos() - _startPos); + } + return true; + } else if (type == QEvent::MouseButtonPress) { + if (mouse_event->buttons().testFlag(Qt::LeftButton)) { + _moving = true; +#ifndef _WIN32 + _startPos = mouse_event->pos() + + QPoint(_layout->margin(), _layout->margin()) + + QPoint(_layout->spacing(), _layout->spacing()) + + QPoint(_mlayout->margin(), _mlayout->margin()) + + QPoint(_mlayout->spacing(), _mlayout->spacing()); +#else + _startPos = mouse_event->pos() + + QPoint(_layout->margin(), _layout->margin()) + + QPoint(_layout->spacing(), _layout->spacing()); +#endif + } + } else if (type == QEvent::MouseButtonRelease) { + if (mouse_event->buttons().testFlag(Qt::LeftButton)) { + _moving = false; + } + } + return false; +} + +QVBoxLayout* DSDialog::layout() +{ + return _mlayout; +} + +QWidget* DSDialog::mainWidget() +{ + return _main; +} + +void DSDialog::setTitle(QString title) +{ + _titlebar->setTitle(title); +} + +void DSDialog::reload(bool hasClose) +{ + QString title; + if (_titlebar) + title = _titlebar->title(); + if (_main) + delete _main; + + build_main(hasClose); + _titlebar->setTitle(title); + _layout->addWidget(_main); +} + +void DSDialog::build_main(bool hasClose) +{ + _main = new QWidget(this); + _mlayout = new QVBoxLayout(_main); + _main->setLayout(_mlayout); + //_mlayout->setMargin(5); + //_mlayout->setSpacing(5); + + Shadow *bodyShadow = new Shadow(_main); + bodyShadow->setBlurRadius(10.0); + bodyShadow->setDistance(3.0); + bodyShadow->setColor(QColor(0, 0, 0, 80)); + _main->setAutoFillBackground(true); + _main->setGraphicsEffect(bodyShadow); + + _titlebar = new toolbars::TitleBar(false, this, hasClose); + _titlebar->installEventFilter(this); + _mlayout->addWidget(_titlebar); +} + +} // namespace dialogs +} // namespace pv diff --git a/DSView/pv/dialogs/dsdialog.h b/DSView/pv/dialogs/dsdialog.h new file mode 100755 index 00000000..cefc614d --- /dev/null +++ b/DSView/pv/dialogs/dsdialog.h @@ -0,0 +1,68 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 DSVIEW_PV_DSDIALOG_H +#define DSVIEW_PV_DSDIALOG_H + +#include +#include +#include + +#include "../toolbars/titlebar.h" + +namespace pv { +namespace dialogs { + +class DSDialog : public QDialog +{ + Q_OBJECT + +public: + DSDialog(QWidget *parent = 0, bool hasClose = false); + QVBoxLayout *layout(); + QWidget *mainWidget(); + + void setTitle(QString title); + void reload(bool hasClose); + +protected: + void accept(); + void reject(); + //void mousePressEvent(QMouseEvent *event); + //void mouseReleaseEvent(QMouseEvent *event); + bool eventFilter(QObject *object, QEvent *event); +private: + void build_main(bool hasClose); + +private: + QVBoxLayout *_layout; + QVBoxLayout *_mlayout; + QWidget *_main; + toolbars::TitleBar *_titlebar; + bool _moving; + QPoint _startPos; +}; + +} // namespace dialogs +} // namespace pv + +#endif // DSVIEW_PV_DSDIALOG_H diff --git a/DSView/pv/dialogs/dsmessagebox.cpp b/DSView/pv/dialogs/dsmessagebox.cpp new file mode 100755 index 00000000..0491ba3d --- /dev/null +++ b/DSView/pv/dialogs/dsmessagebox.cpp @@ -0,0 +1,130 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 "dsmessagebox.h" +#include "shadow.h" + +#include +#include +#include +#include +#include + +namespace pv { +namespace dialogs { + +DSMessageBox::DSMessageBox(QWidget *parent) : + QDialog(parent), + _moving(false) +{ + setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); + setAttribute(Qt::WA_TranslucentBackground); + _main = new QWidget(this); + QVBoxLayout *mlayout = new QVBoxLayout(_main); + _main->setLayout(mlayout); + + Shadow *bodyShadow = new Shadow(); + bodyShadow->setBlurRadius(10.0); + bodyShadow->setDistance(3.0); + bodyShadow->setColor(QColor(0, 0, 0, 80)); + _main->setAutoFillBackground(true); + _main->setGraphicsEffect(bodyShadow); + + _msg = new QMessageBox(this); + _msg->setWindowFlags(Qt::FramelessWindowHint | Qt::Widget); + + _titlebar = new toolbars::TitleBar(false, this); + _titlebar->setTitle(tr("Message")); + _titlebar->installEventFilter(this); + + mlayout->addWidget(_titlebar); + mlayout->addWidget(_msg); + + _layout = new QVBoxLayout(this); + _layout->addWidget(_main); + setLayout(_layout); + + //connect(_msg, SIGNAL(finished(int)), this, SLOT(accept())); + connect(_msg, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(on_button(QAbstractButton*))); +} + +void DSMessageBox::accept() +{ + using namespace Qt; + + QDialog::accept(); +} + +void DSMessageBox::reject() +{ + using namespace Qt; + + QDialog::reject(); +} + +bool DSMessageBox::eventFilter(QObject *object, QEvent *event) +{ + (void)object; + const QEvent::Type type = event->type(); + const QMouseEvent *const mouse_event = (QMouseEvent*)event; + if (type == QEvent::MouseMove) { + if (_moving && mouse_event->buttons().testFlag(Qt::LeftButton)) { + move(mouse_event->globalPos() - _startPos); + } + return true; + } else if (type == QEvent::MouseButtonPress) { + if (mouse_event->buttons().testFlag(Qt::LeftButton)) { + _moving = true; + _startPos = mouse_event->pos() + + QPoint(_layout->margin(), _layout->margin()) + + QPoint(_layout->spacing(), _layout->spacing()); + } + } else if (type == QEvent::MouseButtonRelease) { + if (mouse_event->buttons().testFlag(Qt::LeftButton)) { + _moving = false; + } + } + return false; +} + +QMessageBox* DSMessageBox::mBox() +{ + return _msg; +} + +int DSMessageBox::exec() +{ + //_msg->show(); + return QDialog::exec(); +} + +void DSMessageBox::on_button(QAbstractButton *btn) +{ + QMessageBox::ButtonRole role = _msg->buttonRole(btn); + if (role == QMessageBox::AcceptRole) + accept(); + else + reject(); +} + +} // namespace dialogs +} // namespace pv diff --git a/DSView/pv/dialogs/dsmessagebox.h b/DSView/pv/dialogs/dsmessagebox.h new file mode 100755 index 00000000..5fc2ea30 --- /dev/null +++ b/DSView/pv/dialogs/dsmessagebox.h @@ -0,0 +1,68 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 DSVIEW_PV_DSMESSAGEBOX_H +#define DSVIEW_PV_DSMESSAGEBOX_H + +#include +#include +#include +#include + +#include "../toolbars/titlebar.h" + +namespace pv { +namespace dialogs { + +class DSMessageBox : public QDialog +{ + Q_OBJECT + +public: + DSMessageBox(QWidget *parent); + QMessageBox *mBox(); + + int exec(); + +protected: + void accept(); + void reject(); + //void mousePressEvent(QMouseEvent *event); + //void mouseReleaseEvent(QMouseEvent *event); + bool eventFilter(QObject *object, QEvent *event); + +private slots: + void on_button(QAbstractButton* btn); + +private: + QVBoxLayout *_layout; + QWidget *_main; + QMessageBox *_msg; + toolbars::TitleBar *_titlebar; + bool _moving; + QPoint _startPos; +}; + +} // namespace dialogs +} // namespace pv + +#endif // DSVIEW_PV_DSMESSAGEBOX_H diff --git a/DSView/pv/dialogs/dsomeasure.cpp b/DSView/pv/dialogs/dsomeasure.cpp index 9bb36909..ec04ee33 100644 --- a/DSView/pv/dialogs/dsomeasure.cpp +++ b/DSView/pv/dialogs/dsomeasure.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * Copyright (C) 2015 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 @@ -22,6 +21,7 @@ #include "dsomeasure.h" +#include "../device/devinst.h" #include #include @@ -36,16 +36,14 @@ namespace pv { namespace dialogs { DsoMeasure::DsoMeasure(QWidget *parent, boost::shared_ptr dsoSig) : - QDialog(parent), + DSDialog(parent), _dsoSig(dsoSig), - _layout(this), _button_box(QDialogButtonBox::Ok, Qt::Horizontal, this) { - setWindowTitle(tr("DSO Measure Options")); - setLayout(&_layout); + setMinimumWidth(300); - for (int i=DsoSignal::DSO_MS_BEGIN+1; iget_ms_string(i), this); checkBox->setProperty("id", QVariant(i)); checkBox->setChecked(dsoSig->get_ms_en(i)); @@ -55,8 +53,13 @@ DsoMeasure::DsoMeasure(QWidget *parent, boost::shared_ptr dsoSig) : _layout.addWidget(&_button_box); + layout()->addLayout(&_layout); + setTitle(tr("Measurements")); + connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); connect(&_button_box, SIGNAL(rejected()), this, SLOT(accept())); + + connect(_dsoSig->get_device().get(), SIGNAL(device_updated()), this, SLOT(reject())); } void DsoMeasure::set_measure(bool en) @@ -78,7 +81,9 @@ void DsoMeasure::accept() void DsoMeasure::reject() { - accept(); + using namespace Qt; + + QDialog::reject(); } } // namespace dialogs diff --git a/DSView/pv/dialogs/dsomeasure.h b/DSView/pv/dialogs/dsomeasure.h index 05a1ba1a..a50689be 100644 --- a/DSView/pv/dialogs/dsomeasure.h +++ b/DSView/pv/dialogs/dsomeasure.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * Copyright (C) 2015 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 @@ -24,13 +23,14 @@ #ifndef DSVIEW_PV_DSOMEASURE_H #define DSVIEW_PV_DSOMEASURE_H -#include #include #include #include -#include +#include "../view/dsosignal.h" +#include "../toolbars/titlebar.h" +#include "dsdialog.h" namespace pv { @@ -40,7 +40,7 @@ class DsoSignal; namespace dialogs { -class DsoMeasure : public QDialog +class DsoMeasure : public DSDialog { Q_OBJECT @@ -56,7 +56,7 @@ protected: private: boost::shared_ptr _dsoSig; - + toolbars::TitleBar *_titlebar; QVBoxLayout _layout; QDialogButtonBox _button_box; }; diff --git a/DSView/pv/dialogs/fftoptions.cpp b/DSView/pv/dialogs/fftoptions.cpp new file mode 100644 index 00000000..d1df974f --- /dev/null +++ b/DSView/pv/dialogs/fftoptions.cpp @@ -0,0 +1,268 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 "fftoptions.h" + +#include + +#include +#include + +#include "../sigsession.h" +#include "../data/mathstack.h" +#include "../view/trace.h" +#include "../view/dsosignal.h" +#include "../view/mathtrace.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace dialogs { + +FftOptions::FftOptions(QWidget *parent, SigSession &session) : + DSDialog(parent), + _session(session), + _button_box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, + Qt::Horizontal, this) +{ + _en_checkbox = new QCheckBox(this); + _len_combobox = new QComboBox(this); + _interval_combobox = new QComboBox(this); + _ch_combobox = new QComboBox(this); + _window_combobox = new QComboBox(this); + _dc_checkbox = new QCheckBox(this); + _dc_checkbox->setChecked(true); + _view_combobox = new QComboBox(this); + _dbv_combobox = new QComboBox(this); + + // setup _ch_combobox + BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + _ch_combobox->addItem(dsoSig->get_name(), qVariantFromValue(dsoSig->get_index())); + } + } + + // setup _window_combobox _len_combobox + _sample_limit = 0; + GVariant* gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_MAX_DSO_SAMPLELIMITS); + if (gvar != NULL) { + _sample_limit = g_variant_get_uint64(gvar) * 0.5; + g_variant_unref(gvar); + } else { + qDebug() << "ERROR: config_get SR_CONF_MAX_DSO_SAMPLELIMITS failed."; + } + std::vector windows; + std::vector length; + std::vector view_modes; + std::vector dbv_ranges; + BOOST_FOREACH(const boost::shared_ptr t, _session.get_math_signals()) { + boost::shared_ptr mathTrace; + if (mathTrace = dynamic_pointer_cast(t)) { + windows = mathTrace->get_math_stack()->get_windows_support(); + length = mathTrace->get_math_stack()->get_length_support(); + view_modes = mathTrace->get_view_modes_support(); + dbv_ranges = mathTrace->get_dbv_ranges(); + break; + } + } + assert(windows.size() > 0); + assert(length.size() > 0); + assert(view_modes.size() > 0); + assert(dbv_ranges.size() > 0); + for (unsigned int i = 0; i < windows.size(); i++) + { + _window_combobox->addItem(windows[i], + qVariantFromValue(i)); + } + for (unsigned int i = 0; i < length.size(); i++) + { + if (length[i] < _sample_limit) + _len_combobox->addItem(QString::number(length[i]), + qVariantFromValue(length[i])); + else + break; + } + assert(_len_combobox->count() > 0); + _len_combobox->setCurrentIndex(_len_combobox->count()-1); + + const int max_interval = _sample_limit/_len_combobox->currentData().toLongLong(); + for (int i = 1; i <= max_interval; i*=2) + { + _interval_combobox->addItem(QString::number(i), + qVariantFromValue(i)); + } + for (unsigned int i = 0; i < view_modes.size(); i++) + { + _view_combobox->addItem(view_modes[i], + qVariantFromValue(i)); + } + assert(_view_combobox->count() > 0); + _view_combobox->setCurrentIndex(_view_combobox->count()-1); + for (unsigned int i = 0; i < dbv_ranges.size(); i++) + { + _dbv_combobox->addItem(QString::number(dbv_ranges[i]), + qVariantFromValue(dbv_ranges[i])); + } + + // load current settings + BOOST_FOREACH(const boost::shared_ptr t, _session.get_math_signals()) { + boost::shared_ptr mathTrace; + if (mathTrace = dynamic_pointer_cast(t)) { + if (mathTrace->enabled()) { + _en_checkbox->setChecked(true); + for (int i = 0; i < _ch_combobox->count(); i++) { + if (mathTrace->get_index() == _ch_combobox->itemData(i).toInt()) { + _ch_combobox->setCurrentIndex(i); + break; + } + } + for (int i = 0; i < _len_combobox->count(); i++) { + if (mathTrace->get_math_stack()->get_sample_num() == _len_combobox->itemData(i).toULongLong()) { + _len_combobox->setCurrentIndex(i); + break; + } + } + _interval_combobox->clear(); + const int max_interval = _sample_limit/_len_combobox->currentData().toLongLong(); + for (int i = 1; i <= max_interval; i*=2) + { + _interval_combobox->addItem(QString::number(i), + qVariantFromValue(i)); + } + for (int i = 0; i < _interval_combobox->count(); i++) { + if (mathTrace->get_math_stack()->get_sample_interval() == _interval_combobox->itemData(i).toInt()) { + _interval_combobox->setCurrentIndex(i); + break; + } + } + for (int i = 0; i < _dbv_combobox->count(); i++) { + if (mathTrace->dbv_range() == _dbv_combobox->itemData(i).toLongLong()) { + _dbv_combobox->setCurrentIndex(i); + break; + } + } + _window_combobox->setCurrentIndex(mathTrace->get_math_stack()->get_windows_index()); + _dc_checkbox->setChecked(mathTrace->get_math_stack()->dc_ignored()); + _view_combobox->setCurrentIndex(mathTrace->view_mode()); + } + } + } + + _hint_label = new QLabel(this); + QString hint_pic= ":/icons/" + _window_combobox->currentText()+".png"; + QPixmap pixmap(hint_pic); + _hint_label->setPixmap(pixmap); + + _glayout = new QGridLayout(); + _glayout->setVerticalSpacing(5); + _glayout->addWidget(new QLabel(tr("FFT Enable: "), this), 0, 0); + _glayout->addWidget(_en_checkbox, 0, 1); + _glayout->addWidget(new QLabel(tr("FFT Length: "), this), 1, 0); + _glayout->addWidget(_len_combobox, 1, 1); + _glayout->addWidget(new QLabel(tr("Sample Interval: "), this), 2, 0); + _glayout->addWidget(_interval_combobox, 2, 1); + _glayout->addWidget(new QLabel(tr("FFT Source: "), this), 3, 0); + _glayout->addWidget(_ch_combobox, 3, 1); + _glayout->addWidget(new QLabel(tr("FFT Window: "), this), 4, 0); + _glayout->addWidget(_window_combobox, 4, 1); + _glayout->addWidget(new QLabel(tr("DC Ignored: "), this), 5, 0); + _glayout->addWidget(_dc_checkbox, 5, 1); + _glayout->addWidget(new QLabel(tr("Y-axis Mode: "), this), 6, 0); + _glayout->addWidget(_view_combobox, 6, 1); + _glayout->addWidget(new QLabel(tr("DBV Range: "), this), 7, 0); + _glayout->addWidget(_dbv_combobox, 7, 1); + _glayout->addWidget(_hint_label, 0, 2, 8, 1); + + + _layout = new QVBoxLayout(); + _layout->addLayout(_glayout); + _layout->addWidget(&_button_box); + + layout()->addLayout(_layout); + setTitle(tr("FFT Options")); + + connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); + connect(&_button_box, SIGNAL(rejected()), this, SLOT(reject())); + connect(_window_combobox, SIGNAL(currentIndexChanged(QString)), this, SLOT(window_changed(QString))); + connect(_len_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(len_changed(int))); + connect(_session.get_device().get(), SIGNAL(device_updated()), this, SLOT(reject())); +} + +void FftOptions::accept() +{ + using namespace Qt; + + QDialog::accept(); + + BOOST_FOREACH(const boost::shared_ptr t, _session.get_math_signals()) { + boost::shared_ptr mathTrace; + if (mathTrace = dynamic_pointer_cast(t)) { + mathTrace->set_enable(false); + if (mathTrace->get_index() == _ch_combobox->currentData().toInt()) { + mathTrace->get_math_stack()->set_dc_ignore(_dc_checkbox->isChecked()); + mathTrace->get_math_stack()->set_sample_num(_len_combobox->currentData().toULongLong()); + mathTrace->get_math_stack()->set_sample_interval(_interval_combobox->currentData().toInt()); + mathTrace->get_math_stack()->set_windows_index(_window_combobox->currentData().toInt()); + mathTrace->set_view_mode(_view_combobox->currentData().toInt()); + //mathTrace->init_zoom(); + mathTrace->set_dbv_range(_dbv_combobox->currentData().toInt()); + mathTrace->set_enable(_en_checkbox->isChecked()); + if (_session.get_capture_state() == SigSession::Stopped && + mathTrace->enabled()) + mathTrace->get_math_stack()->calc_fft(); + } + } + } + _session.mathTraces_rebuild(); +} + +void FftOptions::reject() +{ + using namespace Qt; + + QDialog::reject(); +} + +void FftOptions::window_changed(QString str) +{ + QString hint_pic= ":/icons/" + str +".png"; + QPixmap pixmap(hint_pic); + _hint_label->setPixmap(pixmap); +} + +void FftOptions::len_changed(int index) +{ + int pre_index = _interval_combobox->currentIndex(); + _interval_combobox->clear(); + const int max_interval = _sample_limit/_len_combobox->itemData(index).toLongLong(); + for (int i = 1; i <= max_interval; i*=2) + { + _interval_combobox->addItem(QString::number(i), + qVariantFromValue(i)); + } + _interval_combobox->setCurrentIndex(pre_index); +} + +} // namespace dialogs +} // namespace pv diff --git a/DSView/pv/dialogs/fftoptions.h b/DSView/pv/dialogs/fftoptions.h new file mode 100644 index 00000000..b16dfe60 --- /dev/null +++ b/DSView/pv/dialogs/fftoptions.h @@ -0,0 +1,87 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 DSVIEW_PV_FFTOPTIONS_H +#define DSVIEW_PV_FFTOPTIONS_H + +#include +#include +#include +#include +#include +#include + +#include + +#include "../device/devinst.h" +#include "../toolbars/titlebar.h" +#include "dsdialog.h" + +namespace pv { + +class SigSession; + +namespace dialogs { + +class FftOptions : public DSDialog +{ + Q_OBJECT + +private: + + +public: + FftOptions(QWidget *parent, SigSession &session); + +protected: + void accept(); + void reject(); + +private slots: + void window_changed(QString str); + void len_changed(int index); + +private: + SigSession &_session; + uint64_t _sample_limit; + + toolbars::TitleBar *_titlebar; + QComboBox *_len_combobox; + QComboBox *_interval_combobox; + QCheckBox *_en_checkbox; + QComboBox *_ch_combobox; + QComboBox *_window_combobox; + QCheckBox *_dc_checkbox; + QComboBox *_view_combobox; + QComboBox *_dbv_combobox; + + QLabel *_hint_label; + QGridLayout *_glayout; + QVBoxLayout *_layout; + QDialogButtonBox _button_box; + +}; + +} // namespace dialogs +} // namespace pv + +#endif // DSVIEW_PV_FFTOPTIONS_H diff --git a/DSView/pv/dialogs/protocolexp.cpp b/DSView/pv/dialogs/protocolexp.cpp new file mode 100644 index 00000000..11f24355 --- /dev/null +++ b/DSView/pv/dialogs/protocolexp.cpp @@ -0,0 +1,226 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 "protocolexp.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sigsession.h" +#include "../data/decoderstack.h" +#include "../data/decode/row.h" +#include "../data/decode/annotation.h" +#include "../view/decodetrace.h" +#include "../data/decodermodel.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace dialogs { + +ProtocolExp::ProtocolExp(QWidget *parent, SigSession &session) : + DSDialog(parent), + _session(session), + _button_box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, + Qt::Horizontal, this), + _export_cancel(false) +{ + _format_combobox = new QComboBox(this); + _format_combobox->addItem(tr("Comma-Separated Values (*.csv)")); + _format_combobox->addItem(tr("Text files (*.txt)")); + + _flayout = new QFormLayout(); + _flayout->setVerticalSpacing(5); + _flayout->setFormAlignment(Qt::AlignLeft); + _flayout->setLabelAlignment(Qt::AlignLeft); + _flayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + _flayout->addRow(new QLabel(tr("Export Format: "), this), _format_combobox); + + pv::data::DecoderModel* decoder_model = _session.get_decoder_model(); + const boost::shared_ptr& decoder_stack = decoder_model->getDecoderStack(); + if (decoder_stack) { + int row_index = 0; + const std::map rows = decoder_stack->get_rows_lshow(); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + if ((*i).second) { + QLabel *row_label = new QLabel((*i).first.title(), this); + QRadioButton *row_sel = new QRadioButton(this); + if (row_index == 0) { + row_sel->setChecked(true); + } + _row_label_list.push_back(row_label); + _row_sel_list.push_back(row_sel); + _flayout->addRow(row_label, row_sel); + row_sel->setProperty("index", row_index); + row_sel->setProperty("title", (*i).first.title()); + row_index++; + } + } + } + + _layout = new QVBoxLayout(); + _layout->addLayout(_flayout); + _layout->addWidget(&_button_box); + + layout()->addLayout(_layout); + setTitle(tr("Protocol Export")); + + connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); + connect(&_button_box, SIGNAL(rejected()), this, SLOT(reject())); + connect(_session.get_device().get(), SIGNAL(device_updated()), this, SLOT(reject())); + +} + +void ProtocolExp::accept() +{ + using namespace Qt; + using namespace pv::data::decode; + + QDialog::accept(); + + if (!_row_sel_list.empty()) { + QList supportedFormats; + for (int i = _format_combobox->count() - 1; i >= 0; i--) { + supportedFormats.push_back(_format_combobox->itemText(i)); + } + QString filter; + for(int i = 0; i < supportedFormats.count();i++){ + filter.append(supportedFormats[i]); + if(i < supportedFormats.count() - 1) + filter.append(";;"); + } + const QString DIR_KEY("ProtocolExportPath"); + QSettings settings; + QString default_filter = _format_combobox->currentText(); + QString file_name = QFileDialog::getSaveFileName( + this, tr("Export Data"), settings.value(DIR_KEY).toString(),filter,&default_filter); + if (!file_name.isEmpty()) { + QFileInfo f(file_name); + QStringList list = default_filter.split('.').last().split(')'); + QString ext = list.first(); + if(f.suffix().compare(ext)) + file_name+=tr(".")+ext; + + QDir CurrentDir; + settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(file_name)); + + QFile file(file_name); + file.open(QIODevice::WriteOnly | QIODevice::Text); + QTextStream out(&file); + out.setCodec("UTF-8"); + out.setGenerateByteOrderMark(true); + + QFuture future; + future = QtConcurrent::run([&]{ + _export_cancel = false; + QString title; + int index = 0; + for (std::list::const_iterator i = _row_sel_list.begin(); + i != _row_sel_list.end(); i++) { + if ((*i)->isChecked()) { + title = (*i)->property("title").toString(); + index = (*i)->property("index").toULongLong(); + break; + } + } + out << QString("%1;%2;%3\n") + .arg("ID") + .arg("Time[s]") + .arg(title); + + pv::data::DecoderModel* decoder_model = _session.get_decoder_model(); + const boost::shared_ptr& decoder_stack = decoder_model->getDecoderStack(); + int row_index = 0; + Row row; + const std::map rows_lshow = decoder_stack->get_rows_lshow(); + for (std::map::const_iterator i = rows_lshow.begin(); + i != rows_lshow.end(); i++) { + if ((*i).second) { + if (index == row_index) { + row = (*i).first; + break; + } + row_index++; + } + } + + uint64_t exported = 0; + double time_pre_samples = 1.0 / decoder_stack->samplerate(); + vector annotations; + decoder_stack->get_annotation_subset(annotations, row, + 0, decoder_stack->sample_count()-1); + if (!annotations.empty()) { + BOOST_FOREACH(const Annotation &a, annotations) { + out << QString("%1;%2;%3\n") + .arg(QString::number(exported)) + .arg(QString::number(a.start_sample()*time_pre_samples)) + .arg(a.annotations().at(0)); + exported++; + emit export_progress(exported*100/annotations.size()); + if (_export_cancel) + break; + } + } + }); + Qt::WindowFlags flags = Qt::CustomizeWindowHint; + QProgressDialog dlg(tr("Export Protocol List Result... It can take a while."), + tr("Cancel"),0,100,this,flags); + dlg.setWindowModality(Qt::WindowModal); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + + QFutureWatcher watcher; + connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); + connect(this,SIGNAL(export_progress(int)),&dlg,SLOT(setValue(int))); + connect(&dlg,SIGNAL(canceled()),this,SLOT(cancel_export())); + watcher.setFuture(future); + dlg.exec(); + + future.waitForFinished(); + file.close(); + } + } +} + +void ProtocolExp::reject() +{ + using namespace Qt; + + QDialog::reject(); +} + +void ProtocolExp::cancel_export() +{ + _export_cancel = true; +} + +} // namespace dialogs +} // namespace pv diff --git a/DSView/pv/dialogs/protocolexp.h b/DSView/pv/dialogs/protocolexp.h new file mode 100644 index 00000000..b978c604 --- /dev/null +++ b/DSView/pv/dialogs/protocolexp.h @@ -0,0 +1,86 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 DSVIEW_PV_PROTOCOLEXP_H +#define DSVIEW_PV_PROTOCOLEXP_H + +#include +#include +#include +#include +#include +#include + +#include + +#include "../device/devinst.h" +#include "../prop/binding/deviceoptions.h" +#include "../toolbars/titlebar.h" +#include "dsdialog.h" + +namespace pv { + +class SigSession; + +namespace data { +namespace decode { +class Row; +} +} + +namespace dialogs { + +class ProtocolExp : public DSDialog +{ + Q_OBJECT + +public: + ProtocolExp(QWidget *parent, SigSession &session); + +protected: + void accept(); + void reject(); + +signals: + void export_progress(int percent); + +private slots: + void cancel_export(); + +private: + SigSession &_session; + + toolbars::TitleBar *_titlebar; + QComboBox *_format_combobox; + std::list _row_sel_list; + std::list _row_label_list; + QFormLayout *_flayout; + QVBoxLayout *_layout; + QDialogButtonBox _button_box; + + bool _export_cancel; +}; + +} // namespace dialogs +} // namespace pv + +#endif // DSVIEW_PV_PROTOCOLEXP_H diff --git a/DSView/pv/dialogs/protocollist.cpp b/DSView/pv/dialogs/protocollist.cpp new file mode 100644 index 00000000..fbc51379 --- /dev/null +++ b/DSView/pv/dialogs/protocollist.cpp @@ -0,0 +1,190 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 "protocollist.h" + +#include + +#include +#include + +#include "../sigsession.h" +#include "../data/decoderstack.h" +#include "../data/decode/row.h" +#include "../view/decodetrace.h" +#include "../data/decodermodel.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace dialogs { + +ProtocolList::ProtocolList(QWidget *parent, SigSession &session) : + DSDialog(parent), + _session(session), + _button_box(QDialogButtonBox::Ok, + Qt::Horizontal, this) +{ + pv::data::DecoderModel* decoder_model = _session.get_decoder_model(); + + + _protocol_combobox = new QComboBox(this); + const std::vector< boost::shared_ptr > decode_sigs( + _session.get_decode_signals()); + int index = 0; + BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + _protocol_combobox->addItem(d->get_name()); + if (decoder_model->getDecoderStack() == d->decoder()) + _protocol_combobox->setCurrentIndex(index); + index++; + } + _protocol_combobox->addItem("", qVariantFromValue(NULL)); + if (decoder_model->getDecoderStack() == NULL) + _protocol_combobox->setCurrentIndex(index); + + _flayout = new QFormLayout(); + _flayout->setVerticalSpacing(5); + _flayout->setFormAlignment(Qt::AlignLeft); + _flayout->setLabelAlignment(Qt::AlignLeft); + _flayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + _flayout->addRow(new QLabel(tr("Decoded Protocols: "), this), _protocol_combobox); + + _layout = new QVBoxLayout(); + _layout->addLayout(_flayout); + _layout->addWidget(&_button_box); + + setMinimumWidth(300); + layout()->addLayout(_layout); + setTitle(tr("Protocol List Viewer")); + + connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); + connect(_protocol_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(set_protocol(int))); + set_protocol(_protocol_combobox->currentIndex()); + connect(_session.get_device().get(), SIGNAL(device_updated()), this, SLOT(reject())); + +} + +void ProtocolList::accept() +{ + using namespace Qt; + + QDialog::accept(); +} + +void ProtocolList::reject() +{ + using namespace Qt; + + QDialog::accept(); +} + +void ProtocolList::set_protocol(int index) +{ + (void)index; + + for(std::list::const_iterator i = _show_checkbox_list.begin(); + i != _show_checkbox_list.end(); i++) { + (*i)->setParent(NULL); + _flayout->removeWidget((*i)); + delete (*i); + } + _show_checkbox_list.clear(); + for(std::list::const_iterator i = _show_label_list.begin(); + i != _show_label_list.end(); i++) { + (*i)->setParent(NULL); + _flayout->removeWidget((*i)); + delete (*i); + } + _show_label_list.clear(); + + boost::shared_ptr decoder_stack; + const std::vector< boost::shared_ptr > decode_sigs( + _session.get_decode_signals()); + int cur_index = 0; + BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + if (index == cur_index) { + decoder_stack = d->decoder(); + break; + } + cur_index++; + } + + if (!decoder_stack){ + _session.get_decoder_model()->setDecoderStack(NULL); + return; + } + + _session.get_decoder_model()->setDecoderStack(decoder_stack); + int row_index = 0; + const std::map rows = decoder_stack->get_rows_lshow(); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + QLabel *row_label = new QLabel((*i).first.title(), this); + QCheckBox *row_checkbox = new QCheckBox(this); + //row_checkbox->setChecked(false); + _show_label_list.push_back(row_label); + _show_checkbox_list.push_back(row_checkbox); + _flayout->addRow(row_label, row_checkbox); + + row_checkbox->setChecked((*i).second); + connect(row_checkbox, SIGNAL(clicked(bool)), this, SLOT(on_row_check(bool))); + row_checkbox->setProperty("index", row_index); + row_index++; + } +} + +void ProtocolList::on_row_check(bool show) +{ + QCheckBox *sc = dynamic_cast(sender()); + QVariant id = sc->property("index"); + int index = id.toInt(); + + boost::shared_ptr decoder_stack; + const std::vector< boost::shared_ptr > decode_sigs( + _session.get_decode_signals()); + int cur_index = 0; + BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + if (cur_index == _protocol_combobox->currentIndex()) { + decoder_stack = d->decoder(); + break; + } + cur_index++; + } + + if (!decoder_stack) + return; + + std::map rows = decoder_stack->get_rows_lshow(); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + if (index-- == 0) { + decoder_stack->set_rows_lshow((*i).first, show); + break; + } + } + + _session.get_decoder_model()->setDecoderStack(decoder_stack); +} + +} // namespace dialogs +} // namespace pv diff --git a/DSView/pv/dialogs/protocollist.h b/DSView/pv/dialogs/protocollist.h new file mode 100644 index 00000000..8c4524fd --- /dev/null +++ b/DSView/pv/dialogs/protocollist.h @@ -0,0 +1,77 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 DSVIEW_PV_PROTOCOLLIST_H +#define DSVIEW_PV_PROTOCOLLIST_H + +#include +#include +#include +#include +#include +#include + +#include + +#include "../device/devinst.h" +#include "../prop/binding/deviceoptions.h" +#include "../toolbars/titlebar.h" +#include "dsdialog.h" + +namespace pv { + +class SigSession; + +namespace dialogs { + +class ProtocolList : public DSDialog +{ + Q_OBJECT + +public: + ProtocolList(QWidget *parent, SigSession &session); + +protected: + void accept(); + void reject(); + +private slots: + void set_protocol(int index); + void on_row_check(bool show); + +private: + SigSession &_session; + + toolbars::TitleBar *_titlebar; + QComboBox *_protocol_combobox; + std::list _show_checkbox_list; + std::list _show_label_list; + QFormLayout *_flayout; + QVBoxLayout *_layout; + QDialogButtonBox _button_box; + +}; + +} // namespace dialogs +} // namespace pv + +#endif // DSVIEW_PV_PROTOCOLLIST_H diff --git a/DSView/pv/dialogs/search.cpp b/DSView/pv/dialogs/search.cpp index aeaeb464..1469df78 100644 --- a/DSView/pv/dialogs/search.cpp +++ b/DSView/pv/dialogs/search.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -28,11 +27,11 @@ namespace pv { namespace dialogs { -Search::Search(QWidget *parent, struct sr_dev_inst *sdi, QString pattern) : - QDialog(parent), - _sdi(sdi) +Search::Search(QWidget *parent, boost::shared_ptr dev_inst, QString pattern) : + DSDialog(parent), + _dev_inst(dev_inst) { - assert(_sdi); + assert(_dev_inst); QFont font("Monaco"); font.setStyleHint(QFont::Monospace); @@ -55,18 +54,20 @@ Search::Search(QWidget *parent, struct sr_dev_inst *sdi, QString pattern) : search_buttonBox.addButton(QDialogButtonBox::Cancel); QGridLayout *search_layout = new QGridLayout(); - search_layout->addWidget(search_label, 0, 1); - search_layout->addWidget(new QLabel(tr("Search Value: ")), 1,0, Qt::AlignRight); - search_layout->addWidget(&search_lineEdit, 1, 1); - search_layout->addWidget(new QLabel(" "), 2,0); - search_layout->addWidget(new QLabel(tr("X: Don't care\n0: Low level\n1: High level\nR: Rising edge\nF: Falling edge\nC: Rising/Falling edge")), 3, 0); - search_layout->addWidget(&search_buttonBox, 4, 2); - //search_layout->addStretch(1); + search_layout->setVerticalSpacing(5); + search_layout->addWidget(search_label, 1, 1); + search_layout->addWidget(new QLabel(tr("Search Value: ")), 2,0, Qt::AlignRight); + search_layout->addWidget(&search_lineEdit, 2, 1); + search_layout->addWidget(new QLabel(" "), 3,0); + search_layout->addWidget(new QLabel(tr("X: Don't care\n0: Low level\n1: High level\nR: Rising edge\nF: Falling edge\nC: Rising/Falling edge")), 4, 0); + search_layout->addWidget(&search_buttonBox, 5, 2); - setLayout(search_layout); + layout()->addLayout(search_layout); + setTitle(tr("Search Options")); connect(&search_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(&search_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(_dev_inst.get(), SIGNAL(device_updated()), this, SLOT(reject())); } Search::~Search() diff --git a/DSView/pv/dialogs/search.h b/DSView/pv/dialogs/search.h index 79c7533a..7a9d15ac 100644 --- a/DSView/pv/dialogs/search.h +++ b/DSView/pv/dialogs/search.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -24,7 +23,6 @@ #ifndef DSVIEW_PV_SEARCH_H #define DSVIEW_PV_SEARCH_H -#include #include #include #include @@ -32,17 +30,22 @@ #include #include "../sigsession.h" #include +#include "../toolbars/titlebar.h" +#include "dsdialog.h" +#include "../device/devinst.h" + +#include namespace pv { namespace dialogs { -class Search : public QDialog +class Search : public DSDialog { Q_OBJECT public: - Search(QWidget *parent = 0, sr_dev_inst *sdi = 0, QString pattern = ""); + Search(QWidget *parent = 0, boost::shared_ptr dev_inst = 0, QString pattern = ""); ~Search(); QString get_pattern(); @@ -55,9 +58,10 @@ signals: public slots: private: + toolbars::TitleBar *_titlebar; QLineEdit search_lineEdit; QDialogButtonBox search_buttonBox; - sr_dev_inst *_sdi; + boost::shared_ptr _dev_inst; }; } // namespace decoder diff --git a/DSView/pv/dialogs/shadow.cpp b/DSView/pv/dialogs/shadow.cpp new file mode 100755 index 00000000..0fc91ee4 --- /dev/null +++ b/DSView/pv/dialogs/shadow.cpp @@ -0,0 +1,104 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 "shadow.h" +#include + +QT_BEGIN_NAMESPACE + extern Q_WIDGETS_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0 ); +QT_END_NAMESPACE + +namespace pv { +namespace dialogs { + +Shadow::Shadow(QObject *parent) : + QGraphicsEffect(parent), + _distance(4.0f), + _blurRadius(10.0f), + _color(0, 0, 0, 80) +{ +} + +void Shadow::draw(QPainter* painter) +{ + // if nothing to show outside the item, just draw source + if ((blurRadius() + distance()) <= 0) { + drawSource(painter); + return; + } + + PixmapPadMode mode = QGraphicsEffect::PadToEffectiveBoundingRect; + QPoint offset; + const QPixmap px = sourcePixmap(Qt::DeviceCoordinates, &offset, mode); + + // return if no source + if (px.isNull()) + return; + + // save world transform + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + + // Calculate size for the background image + QSize szi(px.size().width() + 2 * distance(), px.size().height() + 2 * distance()); + + QImage tmp(szi, QImage::Format_ARGB32_Premultiplied); + QPixmap scaled = px.scaled(szi); + tmp.fill(0); + QPainter tmpPainter(&tmp); + tmpPainter.setCompositionMode(QPainter::CompositionMode_Source); + tmpPainter.drawPixmap(QPointF(-distance(), -distance()), scaled); + tmpPainter.end(); + + // blur the alpha channel + QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied); + blurred.fill(0); + QPainter blurPainter(&blurred); + qt_blurImage(&blurPainter, tmp, blurRadius(), false, true); + blurPainter.end(); + + tmp = blurred; + + // blacken the image... + tmpPainter.begin(&tmp); + tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); + tmpPainter.fillRect(tmp.rect(), color()); + tmpPainter.end(); + + // draw the blurred shadow... + painter->drawImage(offset, tmp); + + // draw the actual pixmap... + painter->drawPixmap(offset, px, QRectF()); + + // restore world transform + painter->setWorldTransform(restoreTransform); +} + +QRectF Shadow::boundingRectFor(const QRectF& rect) const +{ + qreal delta = blurRadius() + distance(); + return rect.united(rect.adjusted(-delta, -delta, delta, delta)); +} + +} // namespace dialogs +} // namespace pv diff --git a/DSView/pv/dialogs/shadow.h b/DSView/pv/dialogs/shadow.h new file mode 100755 index 00000000..e37bbbad --- /dev/null +++ b/DSView/pv/dialogs/shadow.h @@ -0,0 +1,59 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 DSVIEW_PV_SHADOW_H +#define DSVIEW_PV_SHADOW_H + +#include +#include + +namespace pv { +namespace dialogs { + +class Shadow : public QGraphicsEffect +{ + Q_OBJECT +public: + explicit Shadow(QObject *parent = 0); + + void draw(QPainter* painter); + QRectF boundingRectFor(const QRectF& rect) const; + + inline void setDistance(qreal distance) { _distance = distance; updateBoundingRect(); } + inline qreal distance() const { return _distance; } + + inline void setBlurRadius(qreal blurRadius) { _blurRadius = blurRadius; updateBoundingRect(); } + inline qreal blurRadius() const { return _blurRadius; } + + inline void setColor(const QColor& color) { _color = color; } + inline QColor color() const { return _color; } + +private: + qreal _distance; + qreal _blurRadius; + QColor _color; +}; + +} // namespace dialogs +} // namespace pv + +#endif // DSVIEW_PV_SHADOW_H diff --git a/DSView/pv/dialogs/storeprogress.cpp b/DSView/pv/dialogs/storeprogress.cpp index f608f548..cbd57200 100644 --- a/DSView/pv/dialogs/storeprogress.cpp +++ b/DSView/pv/dialogs/storeprogress.cpp @@ -19,8 +19,7 @@ */ #include "storeprogress.h" - -#include +#include "dsmessagebox.h" namespace pv { namespace dialogs { @@ -49,11 +48,11 @@ void StoreProgress::run() 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); + dialogs::DSMessageBox msg(parentWidget()); + msg.mBox()->setText(tr("Failed to save session.")); + msg.mBox()->setInformativeText(_session.error()); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); } diff --git a/DSView/pv/dialogs/storeprogress.h b/DSView/pv/dialogs/storeprogress.h index 25c77ab0..c582e3e1 100644 --- a/DSView/pv/dialogs/storeprogress.h +++ b/DSView/pv/dialogs/storeprogress.h @@ -28,6 +28,7 @@ #include #include +#include "../toolbars/titlebar.h" namespace pv { @@ -57,6 +58,8 @@ private slots: private: pv::StoreSession _session; + + toolbars::TitleBar *_titlebar; }; } // dialogs diff --git a/DSView/pv/dialogs/streamoptions.cpp b/DSView/pv/dialogs/streamoptions.cpp deleted file mode 100644 index 610c5beb..00000000 --- a/DSView/pv/dialogs/streamoptions.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * This file is part of the DSView project. - * DSView 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 "streamoptions.h" - -#include - -#include -#include -#include - -#include - -using namespace boost; -using namespace std; - -namespace pv { -namespace dialogs { - -StreamOptions::StreamOptions(QWidget *parent, boost::shared_ptr dev_inst, - uint64_t sample_count, bool stream) : - QDialog(parent), - _dev_inst(dev_inst), - _sample_count(sample_count), - _layout(this), - _stream(stream), - _button_box(QDialogButtonBox::Ok, - Qt::Horizontal, this) -{ - setWindowTitle(tr("Stream Mode Options")); - setLayout(&_layout); - - QLabel *_info = new QLabel(this); - if (_stream) - _info->setText(tr("Stream Mode Active!")); - else - _info->setText(tr("Buffer Mode Active!")); - - _layout.addWidget(_info); - - if (_stream) { - _op0 = new QRadioButton(this); - _op1 = new QRadioButton(this); - _op0->setText(tr("16 Channels, Max 10MHz sample rate")); - _op1->setText(tr(" 8 Channels, Max 25MHz sample rate")); - _layout.addWidget(_op0); - _layout.addWidget(_op1); - - if (_sample_count >= SR_GB(1)) { - _op0->setDisabled(true); - _op1->setChecked(true); - }else{ - _op0->setChecked(true); - } - } - - _layout.addWidget(&_button_box); - - connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); - connect(&_button_box, SIGNAL(rejected()), this, SLOT(accept())); -} - -void StreamOptions::accept() -{ - using namespace Qt; - - uint64_t sample_rate = _dev_inst->get_sample_rate(); - if (_stream) { - if (_op0->isChecked()) - sample_rate = (sample_rate <= SR_MHZ(10)) ? sample_rate : SR_MHZ(10); - else if (_op1->isChecked()) - sample_rate = (sample_rate > SR_MHZ(10) && sample_rate <= SR_MHZ(25)) ? sample_rate : SR_MHZ(25); - } - _dev_inst->set_config(NULL, NULL, - SR_CONF_SAMPLERATE, - g_variant_new_uint64(sample_rate)); - - QDialog::accept(); -} - -void StreamOptions::reject() -{ - accept(); -} - -} // namespace dialogs -} // namespace pv diff --git a/DSView/pv/dialogs/waitingdialog.cpp b/DSView/pv/dialogs/waitingdialog.cpp index 8e2b0e52..c069c61f 100644 --- a/DSView/pv/dialogs/waitingdialog.cpp +++ b/DSView/pv/dialogs/waitingdialog.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -27,6 +26,10 @@ #include #include +#include +#include +#include +#include #include "libsigrok4DSL/libsigrok.h" #include "../view/trace.h" @@ -37,54 +40,74 @@ using namespace std; namespace pv { namespace dialogs { -const QString WaitingDialog::TIPS_INFO = tr("Waiting"); +const QString WaitingDialog::TIPS_WAIT = QT_TR_NOOP("Waiting"); +const QString WaitingDialog::TIPS_FINISHED = QT_TR_NOOP("Finished!"); WaitingDialog::WaitingDialog(QWidget *parent, boost::shared_ptr dev_inst) : - QDialog(parent), + DSDialog(parent), _dev_inst(dev_inst), - _button_box(QDialogButtonBox::Save | QDialogButtonBox::Abort, + _button_box(QDialogButtonBox::Abort, Qt::Horizontal, this) { - this->setFixedSize((GIF_SIZE+TIP_WIDTH)*2, (GIF_SIZE+TIP_HEIGHT)*2); - int midx = this->width() / 2; - int midy = this->height() / 2; + this->setFixedSize((GIF_WIDTH+TIP_WIDTH)*1.2, (GIF_HEIGHT+TIP_HEIGHT)*4); this->setWindowOpacity(0.7); - this->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); label = new QLabel(this); - label->setStyleSheet("background-color: transparent;"); - label->setGeometry(midx-GIF_SIZE/2, midy-GIF_SIZE/2, GIF_SIZE, GIF_SIZE); movie = new QMovie(":/icons/wait.gif"); label->setMovie(movie); + label->setAlignment(Qt::AlignCenter); tips = new QLabel(this); - tips->setText(TIPS_INFO); + tips->setText(TIPS_WAIT); QFont font; font.setPointSize(10); font.setBold(true); tips->setFont(font); - tips->setGeometry(midx-TIP_WIDTH/2, midy+GIF_SIZE/2, TIP_WIDTH, TIP_HEIGHT); + tips->setAlignment(Qt::AlignCenter); index = 0; timer = new QTimer(); connect(timer, SIGNAL(timeout()), this, SLOT(changeText())); - - _button_box.setGeometry(width()-_button_box.width()-30, height()-_button_box.height()-15, - _button_box.width(), _button_box.height()); connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); connect(&_button_box, SIGNAL(rejected()), this, SLOT(reject())); - _button_box.buttons().front()->setVisible(false); + connect(_dev_inst.get(), SIGNAL(device_updated()), this, SLOT(stop())); + + + QVBoxLayout *mlayout = new QVBoxLayout(); + mlayout->addWidget(label, Qt::AlignHCenter); + mlayout->addWidget(tips, Qt::AlignHCenter); + mlayout->addWidget(&_button_box); + + layout()->addLayout(mlayout); + setTitle(tr("Zero Adjustment")); } void WaitingDialog::accept() { using namespace Qt; - movie->stop(); timer->stop(); + QDialog::accept(); - _dev_inst->set_config(NULL, NULL, SR_CONF_ZERO_SET, g_variant_new_boolean(true)); - QDialog::accept(); + QFuture future; + future = QtConcurrent::run([&]{ + //QTime dieTime = QTime::currentTime().addSecs(1); + _dev_inst->set_config(NULL, NULL, SR_CONF_ZERO_SET, + g_variant_new_boolean(true)); + //while( QTime::currentTime() < dieTime ); + }); + Qt::WindowFlags flags = Qt::CustomizeWindowHint; + QProgressDialog dlg(tr("Save Auto Zero Result... It can take a while."), + tr("Cancel"),0,0,this,flags); + dlg.setWindowModality(Qt::WindowModal); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + dlg.setCancelButton(NULL); + + QFutureWatcher watcher; + watcher.setFuture(future); + connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); + + dlg.exec(); } void WaitingDialog::reject() @@ -94,30 +117,65 @@ void WaitingDialog::reject() movie->stop(); timer->stop(); QDialog::reject(); + + QFuture future; + future = QtConcurrent::run([&]{ + //QTime dieTime = QTime::currentTime().addSecs(1); + _dev_inst->set_config(NULL, NULL, SR_CONF_ZERO, g_variant_new_boolean(false)); + _dev_inst->set_config(NULL, NULL, SR_CONF_ZERO_LOAD, + g_variant_new_boolean(true)); + //while( QTime::currentTime() < dieTime ); + }); + Qt::WindowFlags flags = Qt::CustomizeWindowHint; + QProgressDialog dlg(tr("Load Current Setting... It can take a while."), + tr("Cancel"),0,0,this,flags); + dlg.setWindowModality(Qt::WindowModal); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + dlg.setCancelButton(NULL); + + QFutureWatcher watcher; + connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); + watcher.setFuture(future); + + dlg.exec(); } -void WaitingDialog::start() +void WaitingDialog::stop() +{ + using namespace Qt; + + movie->stop(); + timer->stop(); + QDialog::reject(); +} + +int WaitingDialog::start() { movie->start(); timer->start(300); - this->exec(); + return this->exec(); } void WaitingDialog::changeText() { - sr_status status; index++; if(index == WPOINTS_NUM + 1) { - tips->setText(TIPS_INFO); + tips->setText(TIPS_WAIT); index = 0; - sr_status_get(_dev_inst->dev_inst(), &status, 0, 0); - if (!status.zeroing) { - movie->stop(); - movie->jumpToFrame(0); - timer->stop(); - tips->setText(""); - _button_box.buttons().front()->setVisible(true); + + GVariant* gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_ZERO); + if (gvar != NULL) { + bool zero = g_variant_get_boolean(gvar); + g_variant_unref(gvar); + if (!zero) { + movie->stop(); + movie->jumpToFrame(0); + timer->stop(); + tips->setAlignment(Qt::AlignHCenter); + tips->setText(TIPS_FINISHED); + _button_box.addButton(QDialogButtonBox::Save); + } } } else { tips->setText(tips->text()+"."); diff --git a/DSView/pv/dialogs/waitingdialog.h b/DSView/pv/dialogs/waitingdialog.h index a214b45d..68130835 100644 --- a/DSView/pv/dialogs/waitingdialog.h +++ b/DSView/pv/dialogs/waitingdialog.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -24,7 +23,6 @@ #ifndef DSVIEW_PV_WAITINGDIALOG_H #define DSVIEW_PV_WAITINGDIALOG_H -#include #include #include #include @@ -33,24 +31,29 @@ #include #include +#include "../toolbars/titlebar.h" +#include "dsdialog.h" namespace pv { namespace dialogs { -class WaitingDialog : public QDialog +class WaitingDialog : public DSDialog { Q_OBJECT private: static const int GIF_SIZE = 80; + static const int GIF_WIDTH = 220; + static const int GIF_HEIGHT = 20; static const int TIP_WIDTH = 100; static const int TIP_HEIGHT = 40; static const int WPOINTS_NUM = 6; - static const QString TIPS_INFO; + static const QString TIPS_WAIT; + static const QString TIPS_FINISHED; public: WaitingDialog(QWidget *parent, boost::shared_ptr dev_inst); - void start(); + int start(); protected: void accept(); @@ -58,10 +61,11 @@ protected: private slots: void changeText(); + void stop(); private: boost::shared_ptr _dev_inst; - + toolbars::TitleBar *_titlebar; QDialogButtonBox _button_box; int index; diff --git a/DSView/pv/dock/dsotriggerdock.cpp b/DSView/pv/dock/dsotriggerdock.cpp index f825695d..8f6dffbb 100644 --- a/DSView/pv/dock/dsotriggerdock.cpp +++ b/DSView/pv/dock/dsotriggerdock.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -24,13 +23,17 @@ #include "dsotriggerdock.h" #include "../sigsession.h" #include "../device/devinst.h" +#include "../dialogs/dsmessagebox.h" +#include "../view/dsosignal.h" + +#include +#include #include #include #include #include #include -#include #include #include @@ -38,6 +41,9 @@ #include "libsigrok4DSL/libsigrok.h" +using namespace boost; +using namespace std; + namespace pv { namespace dock { @@ -45,6 +51,7 @@ DsoTriggerDock::DsoTriggerDock(QWidget *parent, SigSession &session) : QScrollArea(parent), _session(session) { + this->setWidgetResizable(true); _widget = new QWidget(this); QLabel *position_label = new QLabel(tr("Trigger Position: "), _widget); @@ -57,11 +64,12 @@ DsoTriggerDock::DsoTriggerDock(QWidget *parent, SigSession &session) : connect(position_spinBox, SIGNAL(valueChanged(int)), position_slider, SLOT(setValue(int))); connect(position_slider, SIGNAL(valueChanged(int)), this, SLOT(pos_changed(int))); - QLabel *holdoff_label = new QLabel(tr("Trigger Hold Off Time: "), _widget); + QLabel *holdoff_label = new QLabel(tr("Hold Off Time: "), _widget); holdoff_comboBox = new QComboBox(_widget); holdoff_comboBox->addItem(tr("uS"), qVariantFromValue(1000)); holdoff_comboBox->addItem(tr("mS"), qVariantFromValue(1000000)); holdoff_comboBox->addItem(tr("S"), qVariantFromValue(1000000000)); + holdoff_comboBox->setCurrentIndex(0); holdoff_spinBox = new QSpinBox(_widget); holdoff_spinBox->setRange(0, 999); holdoff_spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); @@ -72,6 +80,11 @@ DsoTriggerDock::DsoTriggerDock(QWidget *parent, SigSession &session) : connect(holdoff_slider, SIGNAL(valueChanged(int)), this, SLOT(hold_changed(int))); connect(holdoff_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(hold_changed(int))); + QLabel *margin_label = new QLabel(tr("Noise Sensitivity: "), _widget); + margin_slider = new QSlider(Qt::Horizontal, _widget); + margin_slider->setRange(0, 15); + connect(margin_slider, SIGNAL(valueChanged(int)), this, SLOT(margin_changed(int))); + QLabel *tSource_labe = new QLabel(tr("Trigger Sources: "), _widget); QRadioButton *auto_radioButton = new QRadioButton(tr("Auto")); @@ -94,6 +107,7 @@ DsoTriggerDock::DsoTriggerDock(QWidget *parent, SigSession &session) : connect(falling_radioButton, SIGNAL(clicked()), this, SLOT(type_changed())); source_group=new QButtonGroup(_widget); + channel_comboBox = new QComboBox(_widget); type_group=new QButtonGroup(_widget); source_group->addButton(auto_radioButton); @@ -114,6 +128,7 @@ DsoTriggerDock::DsoTriggerDock(QWidget *parent, SigSession &session) : QVBoxLayout *layout = new QVBoxLayout(_widget); QGridLayout *gLayout = new QGridLayout(); + gLayout->setVerticalSpacing(5); gLayout->addWidget(position_label, 0, 0); gLayout->addWidget(position_spinBox, 0, 1); gLayout->addWidget(new QLabel(tr("%"), _widget), 0, 2); @@ -122,6 +137,7 @@ DsoTriggerDock::DsoTriggerDock(QWidget *parent, SigSession &session) : gLayout->addWidget(new QLabel(_widget), 2, 0); gLayout->addWidget(tSource_labe, 3, 0); gLayout->addWidget(auto_radioButton, 4, 0); + gLayout->addWidget(channel_comboBox, 4, 1, 1, 3); gLayout->addWidget(ch0_radioButton, 5, 0); gLayout->addWidget(ch1_radioButton, 5, 1, 1, 3); gLayout->addWidget(ch0a1_radioButton, 6, 0); @@ -138,14 +154,18 @@ DsoTriggerDock::DsoTriggerDock(QWidget *parent, SigSession &session) : gLayout->addWidget(holdoff_comboBox, 12, 2); gLayout->addWidget(holdoff_slider, 13, 0, 1, 4); - gLayout->setColumnStretch(3, 1); + gLayout->addWidget(new QLabel(_widget), 14, 0); + gLayout->addWidget(margin_label, 15, 0); + gLayout->addWidget(margin_slider, 16, 0, 1, 4); + + gLayout->setColumnStretch(4, 1); layout->addLayout(gLayout); layout->addStretch(1); _widget->setLayout(layout); this->setWidget(_widget); - _widget->setGeometry(0, 0, sizeHint().width(), 500); + //_widget->setGeometry(0, 0, sizeHint().width(), 500); _widget->setObjectName("dsoTriggerWidget"); } @@ -155,10 +175,10 @@ DsoTriggerDock::~DsoTriggerDock() void DsoTriggerDock::paintEvent(QPaintEvent *) { - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +// QStyleOption opt; +// opt.init(this); +// QPainter p(this); +// style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } void DsoTriggerDock::pos_changed(int pos) @@ -168,17 +188,14 @@ void DsoTriggerDock::pos_changed(int pos) SR_CONF_HORIZ_TRIGGERPOS, g_variant_new_byte((uint8_t)pos)); if (!ret) { - QMessageBox msg(this); - msg.setText(tr("Trigger Setting Issue")); - msg.setInformativeText(tr("Change horiz trigger position failed!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Trigger Setting Issue")); + msg.mBox()->setInformativeText(tr("Change horiz trigger position failed!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->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); + set_trig_pos(pos); } void DsoTriggerDock::hold_changed(int hold) @@ -197,11 +214,27 @@ void DsoTriggerDock::hold_changed(int hold) g_variant_new_uint64(holdoff)); if (!ret) { - QMessageBox msg(this); - msg.setText(tr("Trigger Setting Issue")); - msg.setInformativeText(tr("Change trigger hold off time failed!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Trigger Setting Issue")); + msg.mBox()->setInformativeText(tr("Change trigger hold off time failed!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); + msg.exec(); + } +} + +void DsoTriggerDock::margin_changed(int margin) +{ + int ret; + ret = _session.get_device()->set_config(NULL, NULL, + SR_CONF_TRIGGER_MARGIN, + g_variant_new_byte(margin)); + if (!ret) { + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Trigger Setting Issue")); + msg.mBox()->setInformativeText(tr("Change trigger value sensitivity failed!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); } } @@ -215,11 +248,29 @@ void DsoTriggerDock::source_changed() SR_CONF_TRIGGER_SOURCE, g_variant_new_byte(id)); if (!ret) { - QMessageBox msg(this); - msg.setText(tr("Trigger Setting Issue")); - msg.setInformativeText(tr("Change trigger source failed!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Trigger Setting Issue")); + msg.mBox()->setInformativeText(tr("Change trigger source failed!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); + msg.exec(); + } +} + +void DsoTriggerDock::channel_changed(int ch) +{ + (void)ch; + int ret; + + ret = _session.get_device()->set_config(NULL, NULL, + SR_CONF_TRIGGER_CHANNEL, + g_variant_new_byte(channel_comboBox->currentData().toInt())); + if (!ret) { + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Trigger Setting Issue")); + msg.mBox()->setInformativeText(tr("Change trigger channel failed!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); } } @@ -233,18 +284,18 @@ void DsoTriggerDock::type_changed() SR_CONF_TRIGGER_SLOPE, g_variant_new_byte(id)); if (!ret) { - QMessageBox msg(this); - msg.setText(tr("Trigger Setting Issue")); - msg.setInformativeText(tr("Change trigger type failed!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Trigger Setting Issue")); + msg.mBox()->setInformativeText(tr("Change trigger type failed!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); } } void DsoTriggerDock::device_change() { - if (strcmp(_session.get_device()->dev_inst()->driver->name, "DSLogic") != 0) { + if (_session.get_device()->name() != "DSLogic") { position_spinBox->setDisabled(true); position_slider->setDisabled(true); } else { @@ -255,6 +306,29 @@ void DsoTriggerDock::device_change() void DsoTriggerDock::init() { + if (_session.get_device()->name().contains("virtual")) { + foreach(QAbstractButton * btn, source_group->buttons()) + btn->setDisabled(true); + foreach(QAbstractButton * btn, type_group->buttons()) + btn->setDisabled(true); + holdoff_slider->setDisabled(true); + holdoff_spinBox->setDisabled(true); + holdoff_comboBox->setDisabled(true); + margin_slider->setDisabled(true); + channel_comboBox->setDisabled(true); + return; + } else { + foreach(QAbstractButton * btn, source_group->buttons()) + btn->setDisabled(false); + foreach(QAbstractButton * btn, type_group->buttons()) + btn->setDisabled(false); + holdoff_slider->setDisabled(false); + holdoff_spinBox->setDisabled(false); + holdoff_comboBox->setDisabled(false); + margin_slider->setDisabled(false); + channel_comboBox->setDisabled(false); + } + // TRIGGERPOS GVariant* gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_HORIZ_TRIGGERPOS); @@ -272,6 +346,29 @@ void DsoTriggerDock::init() source_group->button(src)->setChecked(true); } + // setup channel_comboBox + disconnect(channel_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(channel_changed(int))); + channel_comboBox->clear(); + BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + channel_comboBox->addItem(dsoSig->get_name(), qVariantFromValue(dsoSig->get_index())); + } + } + gvar = _session.get_device()->get_config(NULL, NULL, + SR_CONF_TRIGGER_CHANNEL); + if (gvar != NULL) { + uint8_t src = g_variant_get_byte(gvar); + g_variant_unref(gvar); + for (int i = 0; i < channel_comboBox->count(); i++) { + if (src == channel_comboBox->itemData(i).toInt()) { + channel_comboBox->setCurrentIndex(i); + break; + } + } + } + connect(channel_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(channel_changed(int))); + gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_TRIGGER_SLOPE); if (gvar != NULL) { @@ -279,6 +376,39 @@ void DsoTriggerDock::init() g_variant_unref(gvar); type_group->button(slope)->setChecked(true); } + + disconnect(holdoff_slider, SIGNAL(valueChanged(int)), this, SLOT(hold_changed(int))); + disconnect(holdoff_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(hold_changed(int))); + gvar = _session.get_device()->get_config(NULL, NULL, + SR_CONF_TRIGGER_HOLDOFF); + if (gvar != NULL) { + uint64_t holdoff = g_variant_get_uint64(gvar); + g_variant_unref(gvar); + for (int i = holdoff_comboBox->count()-1; i >= 0; i--) { + if (holdoff >= holdoff_comboBox->itemData(i).toDouble()) { + holdoff_comboBox->setCurrentIndex(i); + break; + } + } + if (holdoff_comboBox->currentData().toDouble() == 1000000000) { + holdoff_slider->setRange(0, 10); + } else { + holdoff_slider->setRange(0, 999); + } + holdoff_spinBox->setValue(holdoff * 10.0/holdoff_comboBox->currentData().toDouble()); + } + connect(holdoff_slider, SIGNAL(valueChanged(int)), this, SLOT(hold_changed(int))); + connect(holdoff_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(hold_changed(int))); + + disconnect(margin_slider, SIGNAL(valueChanged(int)), this, SLOT(margin_changed(int))); + gvar = _session.get_device()->get_config(NULL, NULL, + SR_CONF_TRIGGER_MARGIN); + if (gvar != NULL) { + uint8_t margin = g_variant_get_byte(gvar); + g_variant_unref(gvar); + margin_slider->setValue(margin); + } + connect(margin_slider, SIGNAL(valueChanged(int)), this, SLOT(margin_changed(int))); } } // namespace dock diff --git a/DSView/pv/dock/dsotriggerdock.h b/DSView/pv/dock/dsotriggerdock.h index f5c4ac17..5062f5d5 100644 --- a/DSView/pv/dock/dsotriggerdock.h +++ b/DSView/pv/dock/dsotriggerdock.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -56,13 +55,15 @@ public: void init(); signals: - void set_trig_pos(quint64 trig_pos); + void set_trig_pos(int percent); private slots: void pos_changed(int pos); void hold_changed(int hold); + void margin_changed(int margin); void source_changed(); void type_changed(); + void channel_changed(int ch); private: @@ -75,10 +76,13 @@ private: QSpinBox *holdoff_spinBox; QSlider *holdoff_slider; + QSlider *margin_slider; + QSpinBox *position_spinBox; QSlider *position_slider; QButtonGroup *source_group; + QComboBox *channel_comboBox; QButtonGroup *type_group; }; diff --git a/DSView/pv/dock/measuredock.cpp b/DSView/pv/dock/measuredock.cpp index 03cd4e1f..27fe3842 100644 --- a/DSView/pv/dock/measuredock.cpp +++ b/DSView/pv/dock/measuredock.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -67,6 +66,7 @@ MeasureDock::MeasureDock(QWidget *parent, View &view, SigSession &session) : _duty_label = new QLabel("#####", _widget); _mouse_layout = new QGridLayout(); + _mouse_layout->setVerticalSpacing(5); _mouse_layout->addWidget(_fen_checkBox, 0, 0, 1, 4); _mouse_layout->addWidget(new QLabel(tr("W: "), _widget), 1, 0); _mouse_layout->addWidget(_width_label, 1, 1); @@ -93,8 +93,12 @@ MeasureDock::MeasureDock(QWidget *parent, View &view, SigSession &session) : _t1_last_index = 0; _t2_last_index = 0; _t3_last_index = 0; + _t1_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + _t2_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + _t3_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); _cursor_layout = new QGridLayout(_widget); + _cursor_layout->setVerticalSpacing(5); _cursor_layout->addWidget(new QLabel(tr("T1: "), _widget), 0, 0); _cursor_layout->addWidget(_t1_comboBox, 0, 1); _cursor_layout->addWidget(new QLabel(tr("T2: "), _widget), 1, 0); @@ -134,7 +138,7 @@ MeasureDock::MeasureDock(QWidget *parent, View &view, SigSession &session) : connect(_t3_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update())); connect(_fen_checkBox, SIGNAL(stateChanged(int)), &_view, SLOT(set_measure_en(int))); - connect(_view.get_viewport(), SIGNAL(mouse_measure()), this, SLOT(mouse_measure())); + connect(&_view, SIGNAL(measure_updated()), this, SLOT(measure_updated())); this->setWidget(_widget); _widget->setGeometry(0, 0, sizeHint().width(), 2000); @@ -147,10 +151,10 @@ MeasureDock::~MeasureDock() void MeasureDock::paintEvent(QPaintEvent *) { - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +// QStyleOption opt; +// opt.init(this); +// QPainter p(this); +// style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } void MeasureDock::cursor_update() @@ -204,6 +208,9 @@ void MeasureDock::cursor_update() index++; } + _t1_comboBox->setMinimumWidth(_t1_comboBox->sizeHint().width()+30); + _t2_comboBox->setMinimumWidth(_t2_comboBox->sizeHint().width()+30); + _t3_comboBox->setMinimumWidth(_t3_comboBox->sizeHint().width()+30); if (_t1_last_index < _t1_comboBox->count()) _t1_comboBox->setCurrentIndex(_t1_last_index); @@ -220,12 +227,12 @@ void MeasureDock::cursor_update() update(); } -void MeasureDock::mouse_measure() +void MeasureDock::measure_updated() { - _width_label->setText(_view.get_viewport()->get_measure("width")); - _period_label->setText(_view.get_viewport()->get_measure("period")); - _freq_label->setText(_view.get_viewport()->get_measure("frequency")); - _duty_label->setText(_view.get_viewport()->get_measure("duty")); + _width_label->setText(_view.get_measure("width")); + _period_label->setText(_view.get_measure("period")); + _freq_label->setText(_view.get_measure("frequency")); + _duty_label->setText(_view.get_measure("duty")); } void MeasureDock::cursor_moved() diff --git a/DSView/pv/dock/measuredock.h b/DSView/pv/dock/measuredock.h index 6b13ec7d..bb941b0c 100644 --- a/DSView/pv/dock/measuredock.h +++ b/DSView/pv/dock/measuredock.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -74,7 +73,7 @@ private slots: public slots: void cursor_update(); void cursor_moved(); - void mouse_measure(); + void measure_updated(); private: SigSession &_session; diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index 37463923..7a32761b 100644 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -25,36 +24,55 @@ #include "../sigsession.h" #include "../view/decodetrace.h" #include "../device/devinst.h" +#include "../data/decodermodel.h" +#include "../data/decoderstack.h" +#include "../dialogs/protocollist.h" +#include "../dialogs/protocolexp.h" +#include "../dialogs/dsmessagebox.h" #include #include #include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include namespace pv { namespace dock { ProtocolDock::ProtocolDock(QWidget *parent, SigSession &session) : QScrollArea(parent), - _session(session) + _session(session), + _cur_search_index(-1), + _search_edited(false), + _searching(false) { - _widget = new QWidget(this); + _up_widget = new QWidget(this); QHBoxLayout *hori_layout = new QHBoxLayout(); - _add_button = new QPushButton(_widget); + _add_button = new QPushButton(_up_widget); _add_button->setFlat(true); _add_button->setIcon(QIcon::fromTheme("protocol", QIcon(":/icons/add.png"))); - _del_all_button = new QPushButton(_widget); + _del_all_button = new QPushButton(_up_widget); _del_all_button->setFlat(true); _del_all_button->setIcon(QIcon::fromTheme("protocol", QIcon(":/icons/del.png"))); _del_all_button->setCheckable(true); - _protocol_combobox = new QComboBox(_widget); + _protocol_combobox = new QComboBox(_up_widget); GSList *l = g_slist_sort(g_slist_copy( (GSList*)srd_decoder_list()), decoder_name_cmp); @@ -80,43 +98,153 @@ ProtocolDock::ProtocolDock(QWidget *parent, SigSession &session) : connect(_del_all_button, SIGNAL(clicked()), this, SLOT(del_protocol())); - _layout = new QVBoxLayout(); - _layout->addLayout(hori_layout); - _layout->addStretch(1); + _up_layout = new QVBoxLayout(); + _up_layout->addLayout(hori_layout); + _up_layout->addStretch(1); - _widget->setLayout(_layout); + _up_widget->setLayout(_up_layout); + _up_widget->setMinimumHeight(150); - this->setWidget(_widget); - _widget->setGeometry(0, 0, sizeHint().width(), 500); - _widget->setObjectName("protocolWidget"); +// this->setWidget(_widget); +// _widget->setGeometry(0, 0, sizeHint().width(), 500); +// _widget->setObjectName("protocolWidget"); + + _dn_widget = new QWidget(this); + + _dn_set_button = new QPushButton(_dn_widget); + _dn_set_button->setFlat(true); + _dn_set_button->setIcon(QIcon::fromTheme("protocol", + QIcon(":/icons/gear.png"))); + connect(_dn_set_button, SIGNAL(clicked()), + this, SLOT(set_model())); + + _dn_save_button = new QPushButton(_dn_widget); + _dn_save_button->setFlat(true); + _dn_save_button->setIcon(QIcon::fromTheme("protocol", + QIcon(":/icons/save.png"))); + connect(_dn_save_button, SIGNAL(clicked()), + this, SLOT(export_table_view())); + + QHBoxLayout *dn_title_layout = new QHBoxLayout(); + dn_title_layout->addWidget(_dn_set_button, 0, Qt::AlignLeft); + dn_title_layout->addWidget(_dn_save_button, 0, Qt::AlignLeft); + dn_title_layout->addWidget(new QLabel(tr("Protocol List Viewer"), _dn_widget), 1, Qt::AlignLeft); + dn_title_layout->addStretch(1); + + _table_view = new QTableView(_dn_widget); + _table_view->setModel(_session.get_decoder_model()); + _table_view->setAlternatingRowColors(true); + _table_view->setShowGrid(false); + _table_view->horizontalHeader()->setStretchLastSection(true); + _table_view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); + _table_view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + + _pre_button = new QPushButton(_dn_widget); + _nxt_button = new QPushButton(_dn_widget); + _pre_button->setIcon(QIcon::fromTheme("protocol", + QIcon(":/icons/pre.png"))); + _nxt_button->setIcon(QIcon::fromTheme("protocol", + QIcon(":/icons/next.png"))); + connect(_pre_button, SIGNAL(clicked()), + this, SLOT(search_pre())); + connect(_nxt_button, SIGNAL(clicked()), + this, SLOT(search_nxt())); + + QPushButton *search_button = new QPushButton(this); + search_button->setIcon(QIcon::fromTheme("protocol", + QIcon(":/icons/search.png"))); + search_button->setFixedWidth(search_button->height()); + search_button->setDisabled(true); + _search_edit = new QLineEdit(_dn_widget); + _search_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + _search_edit->setPlaceholderText(tr("search")); + QHBoxLayout *search_layout = new QHBoxLayout(); + search_layout->addWidget(search_button); + search_layout->addStretch(1); + search_layout->setContentsMargins(0, 0, 0, 0); + _search_edit->setLayout(search_layout); + _search_edit->setTextMargins(search_button->width(), 0, 0, 0); + + _dn_search_layout = new QHBoxLayout(); + _dn_search_layout->addWidget(_pre_button, 0, Qt::AlignLeft); + _dn_search_layout->addWidget(_search_edit, 1, Qt::AlignLeft); + _dn_search_layout->addWidget(_nxt_button, 0, Qt::AlignRight); + + _matchs_label = new QLabel(_dn_widget); + QHBoxLayout *dn_match_layout = new QHBoxLayout(); + dn_match_layout->addWidget(new QLabel(tr("Matching Items:")), 0, Qt::AlignLeft); + dn_match_layout->addWidget(_matchs_label, 0, Qt::AlignLeft); + dn_match_layout->addStretch(1); + + _dn_layout = new QVBoxLayout(); + _dn_layout->addLayout(dn_title_layout); + _dn_layout->addLayout(_dn_search_layout); + _dn_layout->addLayout(dn_match_layout); + _dn_layout->addWidget(_table_view); + + _dn_widget->setLayout(_dn_layout); + _dn_widget->setMinimumHeight(350); + + _split_widget = new QSplitter(this); + _split_widget->insertWidget(0, _up_widget); + _split_widget->insertWidget(1, _dn_widget); + _split_widget->setOrientation(Qt::Vertical); + _split_widget->setCollapsible(0, false); + _split_widget->setCollapsible(1, false); + //_split_widget->setStretchFactor(1, 1); + //_split_widget + + this->setWidgetResizable(true); + this->setWidget(_split_widget); + //_split_widget->setGeometry(0, 0, sizeHint().width(), 500); + _split_widget->setObjectName("protocolWidget"); + + connect(&_session, SIGNAL(decode_done()), this, SLOT(update_model())); + connect(this, SIGNAL(protocol_updated()), this, SLOT(update_model())); + connect(_table_view, SIGNAL(clicked(QModelIndex)), this, SLOT(item_clicked(QModelIndex))); + connect(_table_view->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), this, SLOT(column_resize(int, int, int))); + //connect(_table_view->verticalScrollBar(), SIGNAL(sliderMoved()), this, SLOT(sliderMoved())); + connect(_search_edit, SIGNAL(editingFinished()), this, SLOT(search_changed())); } ProtocolDock::~ProtocolDock() { } +void ProtocolDock::paintEvent(QPaintEvent *) +{ +// QStyleOption opt; +// opt.init(this); +// QPainter p(this); +// style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + +void ProtocolDock::resizeEvent(QResizeEvent *event) +{ + int width = this->visibleRegion().boundingRect().width(); + width = width - _dn_layout->margin() * 2 - + _dn_search_layout->margin() * 2 - + _dn_search_layout->spacing() * 2 - + _pre_button->width()-_nxt_button->width(); + width = std::max(width, 0); + _search_edit->setMinimumWidth(width); + QScrollArea::resizeEvent(event); +} + 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; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} - void ProtocolDock::add_protocol() { if (_session.get_device()->dev_inst()->mode != LOGIC) { - QMessageBox msg(this); - msg.setText(tr("Protocol Analyzer")); - msg.setInformativeText(tr("Protocol Analyzer is only valid in Digital Mode!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Protocol Analyzer")); + msg.mBox()->setInformativeText(tr("Protocol Analyzer is only valid in Digital Mode!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); } else { srd_decoder *const decoder = @@ -126,15 +254,16 @@ void ProtocolDock::add_protocol() //QMap & _options = dlg.get_options(); //QMap _options_index = dlg.get_options_index(); - QPushButton *_del_button = new QPushButton(_widget); - QPushButton *_set_button = new QPushButton(_widget); + QPushButton *_del_button = new QPushButton(_up_widget); + QPushButton *_set_button = new QPushButton(_up_widget); _del_button->setFlat(true); _del_button->setIcon(QIcon::fromTheme("protocol", QIcon(":/icons/del.png"))); _set_button->setFlat(true); _set_button->setIcon(QIcon::fromTheme("protocol", QIcon(":/icons/gear.png"))); - QLabel *_protocol_label = new QLabel(_widget); + QLabel *_protocol_label = new QLabel(_up_widget); + QLabel *_progress_label = new QLabel(_up_widget); _del_button->setCheckable(true); _protocol_label->setText(_protocol_combobox->currentText()); @@ -147,17 +276,24 @@ void ProtocolDock::add_protocol() _del_button_list.push_back(_del_button); _set_button_list.push_back(_set_button); _protocol_label_list.push_back(_protocol_label); + _progress_label_list.push_back(_progress_label); _protocol_index_list.push_back(_protocol_combobox->currentIndex()); QHBoxLayout *hori_layout = new QHBoxLayout(); hori_layout->addWidget(_set_button); hori_layout->addWidget(_del_button); hori_layout->addWidget(_protocol_label); + hori_layout->addWidget(_progress_label); hori_layout->addStretch(1); _hori_layout_list.push_back(hori_layout); - _layout->insertLayout(_del_button_list.size(), hori_layout); + _up_layout->insertLayout(_del_button_list.size(), hori_layout); - //_session.add_protocol_analyzer(_protocol_combobox->currentIndex(), _sel_probes, _options, _options_index); + // progress connection + const std::vector< boost::shared_ptr > decode_sigs( + _session.get_decode_signals()); + connect(decode_sigs.back().get(), SIGNAL(decoded_progress(int)), this, SLOT(decoded_progress(int))); + + protocol_updated(); } } } @@ -183,6 +319,7 @@ void ProtocolDock::rst_protocol() } rst_index++; } + protocol_updated(); } void ProtocolDock::del_protocol() @@ -193,11 +330,12 @@ void ProtocolDock::del_protocol() int del_index = 0; for (QVector ::const_iterator i = _hori_layout_list.begin(); i != _hori_layout_list.end(); i++) { - _layout->removeItem((*i)); + _up_layout->removeItem((*i)); delete (*i); delete _del_button_list.at(del_index); delete _set_button_list.at(del_index); delete _protocol_label_list.at(del_index); + delete _progress_label_list.at(del_index); _session.remove_decode_signal(0); del_index++; @@ -206,13 +344,14 @@ void ProtocolDock::del_protocol() _del_button_list.clear(); _set_button_list.clear(); _protocol_label_list.clear(); + _progress_label_list.clear(); _protocol_index_list.clear(); } else { - QMessageBox msg(this); - msg.setText(tr("Protocol Analyzer")); - msg.setInformativeText(tr("No Protocol Analyzer to delete!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(NULL); + msg.mBox()->setText(tr("Protocol Analyzer")); + msg.mBox()->setInformativeText(tr("No Protocol Analyzer to delete!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); } } else { @@ -220,26 +359,28 @@ void ProtocolDock::del_protocol() for (QVector ::const_iterator i = _del_button_list.begin(); i != _del_button_list.end(); i++) { if ((*i)->isChecked()) { - _layout->removeItem(_hori_layout_list.at(del_index)); + _up_layout->removeItem(_hori_layout_list.at(del_index)); delete _hori_layout_list.at(del_index); delete _del_button_list.at(del_index); delete _set_button_list.at(del_index); delete _protocol_label_list.at(del_index); + delete _progress_label_list.at(del_index); _hori_layout_list.remove(del_index); _del_button_list.remove(del_index); _set_button_list.remove(del_index); _protocol_label_list.remove(del_index); + _progress_label_list.remove(del_index); _protocol_index_list.remove(del_index); _session.remove_decode_signal(del_index); - break; } del_index++; } } + protocol_updated(); } void ProtocolDock::del_all_protocol() @@ -248,11 +389,12 @@ void ProtocolDock::del_all_protocol() int del_index = 0; for (QVector ::const_iterator i = _hori_layout_list.begin(); i != _hori_layout_list.end(); i++) { - _layout->removeItem((*i)); + _up_layout->removeItem((*i)); delete (*i); delete _del_button_list.at(del_index); delete _set_button_list.at(del_index); delete _protocol_label_list.at(del_index); + delete _progress_label_list.at(del_index); _session.remove_decode_signal(0); del_index++; @@ -261,9 +403,325 @@ void ProtocolDock::del_all_protocol() _del_button_list.clear(); _set_button_list.clear(); _protocol_label_list.clear(); + _progress_label_list.clear(); _protocol_index_list.clear(); + + protocol_updated(); } } +void ProtocolDock::decoded_progress(int progress) +{ + (void) progress; + + int pg = 0; + QString err=""; + const std::vector< boost::shared_ptr > decode_sigs( + _session.get_decode_signals()); + int index = 0; + BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + pg = d->get_progress(); + if (d->decoder()->out_of_memory()) + err = tr("(Out of Memory)"); + QString progress_str = QString::number(pg) + "%" + err; + if (pg == 100) + _progress_label_list.at(index)->setStyleSheet("color:green;"); + else + _progress_label_list.at(index)->setStyleSheet("color:red;"); + _progress_label_list.at(index)->setText(progress_str); + index++; + } + if (pg == 0 || pg % 10 == 1) + update_model(); +} + +void ProtocolDock::set_model() +{ + pv::dialogs::ProtocolList *protocollist_dlg = new pv::dialogs::ProtocolList(this, _session); + protocollist_dlg->exec(); + resize_table_view(_session.get_decoder_model()); + _model_proxy.setSourceModel(_session.get_decoder_model()); + search_done(); +} + +void ProtocolDock::update_model() +{ + pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + const std::vector< boost::shared_ptr > decode_sigs( + _session.get_decode_signals()); + if (decode_sigs.size() == 0) + decoder_model->setDecoderStack(NULL); + else if (!decoder_model->getDecoderStack()) + decoder_model->setDecoderStack(decode_sigs.at(0)->decoder()); + else { + unsigned int index = 0; + BOOST_FOREACH(const boost::shared_ptr d, decode_sigs) { + if (d->decoder() == decoder_model->getDecoderStack()) { + decoder_model->setDecoderStack(d->decoder()); + break; + } + index++; + } + if (index >= decode_sigs.size()) + decoder_model->setDecoderStack(decode_sigs.at(0)->decoder()); + } + _model_proxy.setSourceModel(decoder_model); + search_done(); + resize_table_view(decoder_model); +} + +void ProtocolDock::resize_table_view(data::DecoderModel* decoder_model) +{ + if (decoder_model->getDecoderStack()) { + for (int i = 0; i < decoder_model->columnCount(QModelIndex()) - 1; i++) { + _table_view->resizeColumnToContents(i); + if (_table_view->columnWidth(i) > 200) + _table_view->setColumnWidth(i, 200); + } + int top_row = _table_view->rowAt(0); + int bom_row = _table_view->rowAt(_table_view->height()); + if (bom_row >= top_row && top_row >= 0) { + for (int i = top_row; i <= bom_row; i++) + _table_view->resizeRowToContents(i); + } + } +} + +void ProtocolDock::item_clicked(const QModelIndex &index) +{ + pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); + if (decoder_stack) { + pv::data::decode::Annotation ann; + if (decoder_stack->list_annotation(ann, index.column(), index.row())) { + _session.show_region(ann.start_sample(), ann.end_sample()); + } + } + _table_view->resizeRowToContents(index.row()); + if (index.column() != _model_proxy.filterKeyColumn()) { + _model_proxy.setFilterKeyColumn(index.column()); + _model_proxy.setSourceModel(decoder_model); + search_done(); + } + QModelIndex filterIndex = _model_proxy.mapFromSource(index); + if (filterIndex.isValid()) { + _cur_search_index = filterIndex.row(); + } else { + if (_model_proxy.rowCount() == 0) { + _cur_search_index = -1; + } else { + uint64_t up = 0; + uint64_t dn = _model_proxy.rowCount() - 1; + do { + uint64_t md = (up + dn)/2; + QModelIndex curIndex = _model_proxy.mapToSource(_model_proxy.index(md,_model_proxy.filterKeyColumn())); + if (index.row() == curIndex.row()) { + _cur_search_index = md; + break; + } else if (md == up) { + if (curIndex.row() < index.row() && up < dn) { + QModelIndex nxtIndex = _model_proxy.mapToSource(_model_proxy.index(md+1,_model_proxy.filterKeyColumn())); + if (nxtIndex.row() < index.row()) + md++; + } + _cur_search_index = md + ((curIndex.row() < index.row()) ? 0.5 : -0.5); + break; + } else if (curIndex.row() < index.row()) { + up = md; + } else if (curIndex.row() > index.row()) { + dn = md; + } + }while(1); + } + } +} + +void ProtocolDock::column_resize(int index, int old_size, int new_size) +{ + (void)index; + (void)old_size; + (void)new_size; + pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + if (decoder_model->getDecoderStack()) { + int top_row = _table_view->rowAt(0); + int bom_row = _table_view->rowAt(_table_view->height()); + if (bom_row >= top_row && top_row >= 0) { + for (int i = top_row; i <= bom_row; i++) + _table_view->resizeRowToContents(i); + } + } +} + +void ProtocolDock::export_table_view() +{ + pv::dialogs::ProtocolExp *protocolexp_dlg = new pv::dialogs::ProtocolExp(this, _session); + protocolexp_dlg->exec(); +} + +void ProtocolDock::search_pre() +{ + search_update(); + // now the proxy only contains rows that match the name + // let's take the pre one and map it to the original model + if (_model_proxy.rowCount() == 0) { + _table_view->scrollToTop(); + _table_view->clearSelection(); + _matchs_label->setText(QString::number(0)); + _cur_search_index = -1; + return; + } + int i = 0; + uint64_t rowCount = _model_proxy.rowCount(); + QModelIndex matchingIndex; + pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); + do { + _cur_search_index--; + if (_cur_search_index <= -1 || _cur_search_index >= _model_proxy.rowCount()) + _cur_search_index = _model_proxy.rowCount() - 1; + + matchingIndex = _model_proxy.mapToSource(_model_proxy.index(ceil(_cur_search_index),_model_proxy.filterKeyColumn())); + if (!decoder_stack || !matchingIndex.isValid()) + break; + i = 1; + uint64_t row = matchingIndex.row() + 1; + uint64_t col = matchingIndex.column(); + pv::data::decode::Annotation ann; + bool ann_valid; + while(i < _str_list.size()) { + QString nxt = _str_list.at(i); + do { + ann_valid = decoder_stack->list_annotation(ann, col, row); + row++; + }while(ann_valid && (ann.type() < 100 || ann.type() > 999)); + QString source = ann.annotations().at(0); + if (ann_valid && source.contains(nxt)) + i++; + else + break; + } + }while(i < _str_list.size() && --rowCount); + + if(i >= _str_list.size() && matchingIndex.isValid()){ + _table_view->scrollTo(matchingIndex); + _table_view->setCurrentIndex(matchingIndex); + _table_view->clicked(matchingIndex); + } else { + _table_view->scrollToTop(); + _table_view->clearSelection(); + _matchs_label->setText(QString::number(0)); + _cur_search_index = -1; + } +} + +void ProtocolDock::search_nxt() +{ + search_update(); + // now the proxy only contains rows that match the name + // let's take the pre one and map it to the original model + if (_model_proxy.rowCount() == 0) { + _table_view->scrollToTop(); + _table_view->clearSelection(); + _matchs_label->setText(QString::number(0)); + _cur_search_index = -1; + return; + } + int i = 0; + uint64_t rowCount = _model_proxy.rowCount(); + QModelIndex matchingIndex; + pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); + do { + _cur_search_index++; + if (_cur_search_index < 0 || _cur_search_index >= _model_proxy.rowCount()) + _cur_search_index = 0; + + matchingIndex = _model_proxy.mapToSource(_model_proxy.index(floor(_cur_search_index),_model_proxy.filterKeyColumn())); + if (!decoder_stack || !matchingIndex.isValid()) + break; + i = 1; + uint64_t row = matchingIndex.row() + 1; + uint64_t col = matchingIndex.column(); + pv::data::decode::Annotation ann; + bool ann_valid; + while(i < _str_list.size()) { + QString nxt = _str_list.at(i); + do { + ann_valid = decoder_stack->list_annotation(ann, col, row); + row++; + }while(ann_valid && (ann.type() < 100 || ann.type() > 999)); + QString source = ann.annotations().at(0); + if (ann_valid && source.contains(nxt)) + i++; + else + break; + } + }while(i < _str_list.size() && --rowCount); + + if(i >= _str_list.size() && matchingIndex.isValid()){ + _table_view->scrollTo(matchingIndex); + _table_view->setCurrentIndex(matchingIndex); + _table_view->clicked(matchingIndex); + } else { + _table_view->scrollToTop(); + _table_view->clearSelection(); + _matchs_label->setText(QString::number(0)); + _cur_search_index = -1; + } +} + +void ProtocolDock::search_done() +{ + QString str = _search_edit->text().trimmed(); + QRegExp rx("(-)"); + _str_list = str.split(rx); + _model_proxy.setFilterFixedString(_str_list.first()); + if (_str_list.size() > 1) + _matchs_label->setText("..."); + else + _matchs_label->setText(QString::number(_model_proxy.rowCount())); +} + +void ProtocolDock::search_changed() +{ + _search_edited = true; + _matchs_label->setText("..."); +} + +void ProtocolDock::search_update() +{ + if (!_search_edited) + return; + + pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); + if (!decoder_stack) + return; + + if (decoder_stack->list_annotation_size(_model_proxy.filterKeyColumn()) > ProgressRows) { + QFuture future; + future = QtConcurrent::run([&]{ + search_done(); + }); + Qt::WindowFlags flags = Qt::CustomizeWindowHint; + QProgressDialog dlg(tr("Searching..."), + tr("Cancel"),0,0,this,flags); + dlg.setWindowModality(Qt::WindowModal); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + dlg.setCancelButton(NULL); + + QFutureWatcher watcher; + watcher.setFuture(future); + connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); + + dlg.exec(); + } else { + search_done(); + } + _search_edited = false; + //search_done(); +} + + } // namespace dock } // namespace pv diff --git a/DSView/pv/dock/protocoldock.h b/DSView/pv/dock/protocoldock.h index 248d1862..9a1616fd 100644 --- a/DSView/pv/dock/protocoldock.h +++ b/DSView/pv/dock/protocoldock.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -34,43 +33,83 @@ #include #include #include +#include +#include +#include #include +#include #include +#include "../data/decodermodel.h" + namespace pv { class SigSession; +namespace data { +class DecoderModel; +} + namespace dock { class ProtocolDock : public QScrollArea { Q_OBJECT +public: + static const uint64_t ProgressRows = 100000; + public: ProtocolDock(QWidget *parent, SigSession &session); ~ProtocolDock(); - void paintEvent(QPaintEvent *); - void del_all_protocol(); +protected: + void paintEvent(QPaintEvent *); + void resizeEvent(QResizeEvent *); + signals: + void protocol_updated(); private slots: void add_protocol(); void rst_protocol(); void del_protocol(); + void decoded_progress(int progress); + void set_model(); + void update_model(); + void export_table_view(); + void item_clicked(const QModelIndex &index); + void column_resize(int index, int old_size, int new_size); + void search_pre(); + void search_nxt(); + void search_done(); + void search_changed(); + void search_update(); private: static int decoder_name_cmp(const void *a, const void *b); + void resize_table_view(data::DecoderModel *decoder_model); private: SigSession &_session; + QSortFilterProxyModel _model_proxy; + double _cur_search_index; + QStringList _str_list; - QWidget *_widget; + QSplitter *_split_widget; + QWidget *_up_widget; + QWidget *_dn_widget; + QTableView *_table_view; + QPushButton *_pre_button; + QPushButton *_nxt_button; + QLineEdit *_search_edit; + QHBoxLayout *_dn_search_layout; + QVBoxLayout *_dn_layout; + QLabel *_matchs_label; QPushButton *_add_button; QPushButton *_del_all_button; @@ -78,9 +117,17 @@ private: QVector _del_button_list; QVector _set_button_list; QVector _protocol_label_list; + QVector _progress_label_list; QVector _protocol_index_list; QVector _hori_layout_list; - QVBoxLayout *_layout; + QVBoxLayout *_up_layout; + + QPushButton *_dn_set_button; + QPushButton *_dn_save_button; + + mutable boost::mutex _search_mutex; + bool _search_edited; + bool _searching; }; } // namespace dock diff --git a/DSView/pv/dock/searchdock.cpp b/DSView/pv/dock/searchdock.cpp index 3233b825..e523abaf 100644 --- a/DSView/pv/dock/searchdock.cpp +++ b/DSView/pv/dock/searchdock.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -31,13 +30,16 @@ #include "../data/snapshot.h" #include "../data/logicsnapshot.h" #include "../device/devinst.h" +#include "../dialogs/dsmessagebox.h" #include #include #include #include #include -#include +#include +#include +#include #include #include @@ -60,13 +62,13 @@ SearchDock::SearchDock(QWidget *parent, View &view, SigSession &session) : connect(&_nxt_button, SIGNAL(clicked()), this, SLOT(on_next())); - _pre_button.setIcon(QIcon::fromTheme("search", + _pre_button.setIcon(QIcon::fromTheme("searchDock", QIcon(":/icons/pre.png"))); - _nxt_button.setIcon(QIcon::fromTheme("search", + _nxt_button.setIcon(QIcon::fromTheme("searchDock", QIcon(":/icons/next.png"))); - QPushButton *_search_button = new QPushButton(this); - _search_button->setIcon(QIcon::fromTheme("search", + _search_button = new QPushButton(this); + _search_button->setIcon(QIcon::fromTheme("searchDock", QIcon(":/icons/search.png"))); _search_button->setFixedWidth(_search_button->height()); _search_button->setDisabled(true); @@ -102,14 +104,15 @@ SearchDock::~SearchDock() void SearchDock::paintEvent(QPaintEvent *) { - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +// QStyleOption opt; +// opt.init(this); +// QPainter p(this); +// style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } void SearchDock::on_previous() { + bool ret; uint64_t last_pos; uint8_t *data; int unit_size; @@ -119,31 +122,46 @@ void SearchDock::on_previous() last_pos = _view.get_search_pos(); if (last_pos == 0) { - QMessageBox msg(this); - msg.setText(tr("Search")); - msg.setInformativeText(tr("Search cursor at the start position!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Search")); + msg.mBox()->setInformativeText(tr("Search cursor at the start position!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); return; } else { data = (uint8_t*)_session.get_buf(unit_size, length); if (data == NULL) { - QMessageBox msg(this); - msg.setText(tr("Search")); - msg.setInformativeText(tr("No Sample data!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Search")); + msg.mBox()->setInformativeText(tr("No Sample data!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); return; } else { - const bool ret = search_value(data, unit_size, length, last_pos, 1, value); + QFuture future; + future = QtConcurrent::run([&]{ + ret = search_value(data, unit_size, length, last_pos, 1, value); + }); + Qt::WindowFlags flags = Qt::CustomizeWindowHint; + QProgressDialog dlg(tr("Search Previous..."), + tr("Cancel"),0,0,this,flags); + dlg.setWindowModality(Qt::WindowModal); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + dlg.setCancelButton(NULL); + + QFutureWatcher watcher; + connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); + watcher.setFuture(future); + dlg.exec(); + if (!ret) { - QMessageBox msg(this); - msg.setText(tr("Search")); - msg.setInformativeText(tr("Pattern ") + value + tr(" not found!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Search")); + msg.mBox()->setInformativeText(tr("Pattern ") + value + tr(" not found!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); return; } else { @@ -155,6 +173,7 @@ void SearchDock::on_previous() void SearchDock::on_next() { + bool ret; uint64_t last_pos; int unit_size; uint64_t length; @@ -164,30 +183,45 @@ void SearchDock::on_next() last_pos = _view.get_search_pos(); if (last_pos == length - 1) { - QMessageBox msg(this); - msg.setText(tr("Search")); - msg.setInformativeText(tr("Search cursor at the end position!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Search")); + msg.mBox()->setInformativeText(tr("Search cursor at the end position!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); return; } else { if (data == NULL) { - QMessageBox msg(this); - msg.setText(tr("Search")); - msg.setInformativeText(tr("No Sample data!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Search")); + msg.mBox()->setInformativeText(tr("No Sample data!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); return; } else { - const int ret = search_value(data, unit_size, length, last_pos, 0, value); + QFuture future; + future = QtConcurrent::run([&]{ + ret = search_value(data, unit_size, length, last_pos, 0, value); + }); + Qt::WindowFlags flags = Qt::CustomizeWindowHint; + QProgressDialog dlg(tr("Search Next..."), + tr("Cancel"),0,0,this,flags); + dlg.setWindowModality(Qt::WindowModal); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + dlg.setCancelButton(NULL); + + QFutureWatcher watcher; + connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); + watcher.setFuture(future); + dlg.exec(); + if (!ret) { - QMessageBox msg(this); - msg.setText(tr("Search")); - msg.setInformativeText(tr("Pattern ") + value + tr(" not found!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Search")); + msg.mBox()->setInformativeText(tr("Pattern ") + value + tr(" not found!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); return; } else { @@ -199,12 +233,15 @@ void SearchDock::on_next() void SearchDock::on_set() { - dialogs::Search dlg(this, _session.get_device()->dev_inst(), _pattern); + dialogs::Search dlg(this, _session.get_device(), _pattern); if (dlg.exec()) { _pattern = dlg.get_pattern(); _pattern.remove(QChar(' '), Qt::CaseInsensitive); _pattern = _pattern.toUpper(); _search_value->setText(_pattern); + + QFontMetrics fm = this->fontMetrics(); + _search_value->setFixedWidth(fm.width(_pattern)+_search_button->width()+20); } } diff --git a/DSView/pv/dock/searchdock.h b/DSView/pv/dock/searchdock.h index 2477dcb4..e541cd6b 100644 --- a/DSView/pv/dock/searchdock.h +++ b/DSView/pv/dock/searchdock.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -91,6 +90,7 @@ private: QPushButton _pre_button; QPushButton _nxt_button; widgets::FakeLineEdit* _search_value; + QPushButton *_search_button; }; } // namespace dock diff --git a/DSView/pv/dock/triggerdock.cpp b/DSView/pv/dock/triggerdock.cpp index aea64b19..0256df0c 100644 --- a/DSView/pv/dock/triggerdock.cpp +++ b/DSView/pv/dock/triggerdock.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -24,19 +23,22 @@ #include "triggerdock.h" #include "../sigsession.h" #include "../device/devinst.h" +#include "../dialogs/dsmessagebox.h" #include #include #include #include #include -#include +#include #include "libsigrok4DSL/libsigrok.h" namespace pv { namespace dock { +const int TriggerDock::MinTrigPosition = 1; + TriggerDock::TriggerDock(QWidget *parent, SigSession &session) : QScrollArea(parent), _session(session) @@ -55,10 +57,10 @@ TriggerDock::TriggerDock(QWidget *parent, SigSession &session) : position_label = new QLabel(tr("Trigger Position: "), _widget); position_spinBox = new QSpinBox(_widget); - position_spinBox->setRange(0, 99); + position_spinBox->setRange(MinTrigPosition, 99); position_spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); position_slider = new QSlider(Qt::Horizontal, _widget); - position_slider->setRange(0, 99); + position_slider->setRange(MinTrigPosition, 99); connect(position_slider, SIGNAL(valueChanged(int)), position_spinBox, SLOT(setValue(int))); connect(position_spinBox, SIGNAL(valueChanged(int)), position_slider, SLOT(setValue(int))); @@ -123,6 +125,7 @@ TriggerDock::TriggerDock(QWidget *parent, SigSession &session) : QVBoxLayout *stage_layout = new QVBoxLayout(); QGridLayout *stage_glayout = new QGridLayout(); + stage_glayout->setVerticalSpacing(5); stage_glayout->addWidget(value_exp_label, 1, 0); stage_glayout->addWidget(inv_exp_label, 1, 1); stage_glayout->addWidget(count_exp_label, 1, 2); @@ -186,23 +189,33 @@ TriggerDock::TriggerDock(QWidget *parent, SigSession &session) : _serial_value_lineEdit->setInputMask("X X X X X X X X X X X X X X X X"); _serial_value_lineEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + _serial_vcnt_spinBox = new QSpinBox(_widget); + _serial_vcnt_spinBox->setRange(1, INT32_MAX); + _serial_vcnt_spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); + QLabel *serial_value_exp_label = new QLabel("1 1 1 1 1 1\n5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0", _widget); serial_value_exp_label->setFont(font); QVBoxLayout *serial_layout = new QVBoxLayout(); QGridLayout *serial_glayout = new QGridLayout(); - serial_glayout->addWidget(serial_value_exp_label, 1, 1, 1, 4); + serial_glayout->setVerticalSpacing(5); + serial_glayout->addWidget(serial_value_exp_label, 1, 1, 1, 3); serial_glayout->addWidget(_serial_start_label, 2, 0); - serial_glayout->addWidget(_serial_start_lineEdit, 2, 1, 1, 4); - serial_glayout->addWidget(new QLabel(_widget), 2, 2); + serial_glayout->addWidget(_serial_start_lineEdit, 2, 1, 1, 3); + serial_glayout->addWidget(new QLabel(_widget), 2, 4); serial_glayout->addWidget(_serial_stop_label, 3, 0); - serial_glayout->addWidget(_serial_stop_lineEdit, 3, 1, 1, 4); + serial_glayout->addWidget(_serial_stop_lineEdit, 3, 1, 1, 3); serial_glayout->addWidget(_serial_edge_label, 4, 0); - serial_glayout->addWidget(_serial_edge_lineEdit, 4, 1, 1, 4); - serial_glayout->addWidget(_serial_data_lable, 5, 0); - serial_glayout->addWidget(_serial_data_comboBox, 5, 1); - serial_glayout->addWidget(_serial_value_lable, 6, 0); - serial_glayout->addWidget(_serial_value_lineEdit, 6, 1, 1, 4); + serial_glayout->addWidget(_serial_edge_lineEdit, 4, 1, 1, 3); + + serial_glayout->addWidget(new QLabel(_widget), 5, 0, 1, 5); + serial_glayout->addWidget(_serial_data_lable, 6, 0); + serial_glayout->addWidget(_serial_data_comboBox, 6, 1); + serial_glayout->addWidget(new QLabel(tr("counter"), _widget), 6, 4); + serial_glayout->addWidget(_serial_value_lable, 7, 0); + serial_glayout->addWidget(_serial_value_lineEdit, 7, 1, 1, 3); + serial_glayout->addWidget(_serial_vcnt_spinBox, 7, 4); + serial_glayout->addWidget(new QLabel(_widget), 7, 5); serial_layout->addLayout(serial_glayout); serial_layout->addSpacing(20); serial_layout->addWidget(new QLabel(tr("X: Don't care\n0: Low level\n1: High level\nR: Rising edge\nF: Falling edge\nC: Rising/Falling edge"))); @@ -232,6 +245,7 @@ TriggerDock::TriggerDock(QWidget *parent, SigSession &session) : QVBoxLayout *layout = new QVBoxLayout(_widget); QGridLayout *gLayout = new QGridLayout(); + gLayout->setVerticalSpacing(5); gLayout->addWidget(simple_radioButton, 0, 0); gLayout->addWidget(adv_radioButton, 1, 0); gLayout->addWidget(position_label, 2, 0); @@ -259,10 +273,10 @@ TriggerDock::~TriggerDock() void TriggerDock::paintEvent(QPaintEvent *) { - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +// QStyleOption opt; +// opt.init(this); +// QPainter p(this); +// style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } void TriggerDock::simple_trigger() @@ -274,7 +288,7 @@ void TriggerDock::simple_trigger() void TriggerDock::adv_trigger() { - if (strcmp(_session.get_device()->dev_inst()->driver->name, "DSLogic") == 0) { + if (_session.get_device()->name() == "DSLogic") { bool stream = false; GVariant *gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_STREAM); if (gvar != NULL) { @@ -282,22 +296,22 @@ void TriggerDock::adv_trigger() g_variant_unref(gvar); } if (stream) { - QMessageBox msg(this); - msg.setText(tr("Trigger")); - msg.setInformativeText(tr("Stream Mode Don't Support Advanced Trigger!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Trigger")); + msg.mBox()->setInformativeText(tr("Stream Mode Don't Support Advanced Trigger!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); simple_radioButton->setChecked(true); } else { widget_enable(0); } } else { - QMessageBox msg(this); - msg.setText(tr("Trigger")); - msg.setInformativeText(tr("Advanced Trigger need DSLogic Hardware Support!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Trigger")); + msg.mBox()->setInformativeText(tr("Advanced Trigger need DSLogic Hardware Support!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); simple_radioButton->setChecked(true); } @@ -346,8 +360,8 @@ void TriggerDock::device_change() maxRange = 99; else maxRange = max_hd_depth*70 / sample_limits; - position_spinBox->setRange(0, maxRange); - position_slider->setRange(0, maxRange); + position_spinBox->setRange(MinTrigPosition, maxRange); + position_slider->setRange(MinTrigPosition, maxRange); @@ -357,7 +371,7 @@ void TriggerDock::device_change() g_variant_unref(gvar); } - if (!strncmp(_session.get_device()->dev_inst()->driver->name, "virtual", 7) || + if (_session.get_device()->name().contains("virtual") || stream) { simple_radioButton->setChecked(true); simple_trigger(); @@ -436,10 +450,16 @@ bool TriggerDock::commit_trigger() } // trigger count update - for (i = 0; i < stages_comboBox->currentText().toInt(); i++) { - ds_trigger_stage_set_count(i, TriggerProbes, - _count0_spinBox_list.at(i)->value() - 1, - _count1_spinBox_list.at(i)->value() - 1); + if (_adv_tabWidget->currentIndex() == 0) { + for (i = 0; i < stages_comboBox->currentText().toInt(); i++) { + ds_trigger_stage_set_count(i, TriggerProbes, + _count0_spinBox_list.at(i)->value() - 1, + _count1_spinBox_list.at(i)->value() - 1); + } + } else if(_adv_tabWidget->currentIndex() == 1){ + ds_trigger_stage_set_count(4, TriggerProbes, + _serial_vcnt_spinBox->value() - 1, + 0); } return 1; } @@ -482,6 +502,7 @@ QJsonObject TriggerDock::get_session() trigSes["triggerClock"] = _serial_edge_lineEdit->text(); trigSes["triggerChannel"] = _serial_data_comboBox->currentIndex(); trigSes["triggerData"] = _serial_value_lineEdit->text(); + trigSes["triggerVcnt"] = _serial_vcnt_spinBox->value(); return trigSes; } @@ -518,6 +539,7 @@ void TriggerDock::set_session(QJsonObject ses) _serial_edge_lineEdit->setText(ses["triggerClock"].toString()); _serial_data_comboBox->setCurrentIndex(ses["triggerChannel"].toDouble()); _serial_value_lineEdit->setText(ses["triggerData"].toString()); + _serial_vcnt_spinBox->setValue(ses["triggerVcnt"].toDouble()); } } // namespace dock diff --git a/DSView/pv/dock/triggerdock.h b/DSView/pv/dock/triggerdock.h index 4d9fd4ec..6533b03e 100644 --- a/DSView/pv/dock/triggerdock.h +++ b/DSView/pv/dock/triggerdock.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -55,6 +54,9 @@ class TriggerDock : public QScrollArea { Q_OBJECT +private: + static const int MinTrigPosition; + public: TriggerDock(QWidget *parent, SigSession &session); ~TriggerDock(); @@ -125,6 +127,8 @@ private: QComboBox *_serial_data_comboBox; QLabel *_serial_value_lable; QLineEdit *_serial_value_lineEdit; + QLabel *_serial_vcnt_lable; + QSpinBox *_serial_vcnt_spinBox; }; } // namespace dock diff --git a/DSView/pv/mainframe.cpp b/DSView/pv/mainframe.cpp new file mode 100644 index 00000000..777119eb --- /dev/null +++ b/DSView/pv/mainframe.cpp @@ -0,0 +1,374 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 "mainframe.h" + +#include "toolbars/titlebar.h" +#include "mainwindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace pv { + +MainFrame::MainFrame(DeviceManager &device_manager, + const char *open_file_name) +{ + setAttribute(Qt::WA_TranslucentBackground); + // Make this a borderless window which can't + // be resized or moved via the window system + setWindowFlags(Qt::FramelessWindowHint); + setMinimumHeight(680); + setMinimumWidth(800); + //resize(1024, 768); + + // Set the window icon + QIcon icon; + icon.addFile(QString::fromUtf8(":/icons/logo.png"), + QSize(), QIcon::Normal, QIcon::Off); + setWindowIcon(icon); + + _moving = false; + _startPos = None; + _freezing = false; + _minimized = false; + + // MainWindow + _mainWindow = new MainWindow(device_manager, open_file_name, this); + _mainWindow->setWindowFlags(Qt::Widget); + + // Title + _titleBar = new toolbars::TitleBar(true, this); + _titleBar->installEventFilter(this); + _titleBar->setTitle(_mainWindow->windowTitle()); + + QVBoxLayout *vbox = new QVBoxLayout(); + vbox->setMargin(0); + vbox->setSpacing(0); + vbox->addWidget(_titleBar); + vbox->addWidget(_mainWindow); + + _top_left = new widgets::Border (TopLeft, this); + _top_left->setFixedSize(Margin, Margin); + _top_left->installEventFilter(this); + _top = new widgets::Border (Top, this); + _top->setFixedHeight(Margin); + _top->installEventFilter(this); + _top_right = new widgets::Border (TopRight, this); + _top_right->setFixedSize(Margin, Margin); + _top_right->installEventFilter(this); + + _left = new widgets::Border (Left, this); + _left->setFixedWidth(Margin); + _left->installEventFilter(this); + _right = new widgets::Border (Right, this); + _right->setFixedWidth(Margin); + _right->installEventFilter(this); + + _bottom_left = new widgets::Border (BottomLeft, this); + _bottom_left->setFixedSize(Margin, Margin); + _bottom_left->installEventFilter(this); + _bottom = new widgets::Border (Bottom, this); + _bottom->setFixedHeight(Margin); + _bottom->installEventFilter(this); + _bottom_right = new widgets::Border (BottomRight, this); + _bottom_right->setFixedSize(Margin, Margin); + _bottom_right->installEventFilter(this); + + _layout = new QGridLayout(this); + _layout->setMargin(0); + _layout->setSpacing(0); + _layout->addWidget(_top_left, 0, 0); + _layout->addWidget(_top, 0, 1); + _layout->addWidget(_top_right, 0, 2); + _layout->addWidget(_left, 1, 0); + _layout->addLayout(vbox, 1, 1); + _layout->addWidget(_right, 1, 2); + _layout->addWidget(_bottom_left, 2, 0); + _layout->addWidget(_bottom, 2, 1); + _layout->addWidget(_bottom_right, 2, 2); + + connect(&_timer, SIGNAL(timeout()), this, SLOT(unfreezing())); + readSettings(); +} + +void MainFrame::changeEvent(QEvent* event) +{ + QFrame::changeEvent(event); + QWindowStateChangeEvent* win_event = static_cast< QWindowStateChangeEvent* >(event); + if(win_event->type() == QEvent::WindowStateChange) { + if (win_event->oldState() & Qt::WindowMinimized) { + if (_minimized) { + readSettings(); + _minimized = false; + } + } + } +} + + +void MainFrame::resizeEvent(QResizeEvent *event) +{ + QFrame::resizeEvent(event); + if (isMaximized()) { + hide_border(); + } else { + show_border(); + } + _titleBar->setRestoreButton(isMaximized()); + _layout->update(); +} + +void MainFrame::closeEvent(QCloseEvent *event) +{ + _mainWindow->session_save(); + writeSettings(); + event->accept(); +} + +void MainFrame::unfreezing() +{ + _freezing = false; +} + +void MainFrame::hide_border() +{ + _top_left->setVisible(false); + _top_right->setVisible(false); + _top->setVisible(false); + _left->setVisible(false); + _right->setVisible(false); + _bottom_left->setVisible(false); + _bottom->setVisible(false); + _bottom_right->setVisible(false); +} + +void MainFrame::show_border() +{ + _top_left->setVisible(true); + _top_right->setVisible(true); + _top->setVisible(true); + _left->setVisible(true); + _right->setVisible(true); + _bottom_left->setVisible(true); + _bottom->setVisible(true); + _bottom_right->setVisible(true); +} + +void MainFrame::showNormal() +{ + show_border(); + QFrame::showNormal(); +} + +void MainFrame::showMaximized() +{ + hide_border(); + QFrame::showMaximized(); +} + +void MainFrame::showMinimized() +{ + _minimized = true; + writeSettings(); + QFrame::showMinimized(); +} + +bool MainFrame::eventFilter(QObject *object, QEvent *event) +{ + const QEvent::Type type = event->type(); + const QMouseEvent *const mouse_event = (QMouseEvent*)event; + int newWidth; + int newHeight; + int newLeft; + int newTop; + + if (type == QEvent::MouseMove && !isMaximized()) { + if (!(mouse_event->buttons() || Qt::NoButton)) { + if (object == _top_left) { + _startPos = TopLeft; + setCursor(Qt::SizeFDiagCursor); + } else if (object == _bottom_right) { + _startPos = BottomRight; + setCursor(Qt::SizeFDiagCursor); + } else if (object == _top_right) { + _startPos = TopRight; + setCursor(Qt::SizeBDiagCursor); + } else if (object == _bottom_left) { + _startPos = BottomLeft; + setCursor(Qt::SizeBDiagCursor); + } else if (object == _left) { + _startPos = Left; + setCursor(Qt::SizeHorCursor); + } else if (object == _right) { + _startPos = Right; + setCursor(Qt::SizeHorCursor); + } else if (object == _bottom) { + _startPos = Bottom; + setCursor(Qt::SizeVerCursor); + } else if (object == _top) { + _startPos = Top; + setCursor(Qt::SizeVerCursor); + } else { + _startPos = None; + setCursor(Qt::ArrowCursor); + } + } else if(mouse_event->buttons().testFlag(Qt::LeftButton)) { + if (_moving) { + this->move(mouse_event->globalPos() - _lastMousePosition); + } else if (!_freezing) { + switch (_startPos) { + case TopLeft: + newWidth = std::max(_dragStartGeometry.right() - mouse_event->globalX(), minimumWidth()); + newHeight = std::max(_dragStartGeometry.bottom() - mouse_event->globalY(), minimumHeight()); + newLeft = geometry().left(); + newTop = geometry().top(); + if (newWidth > minimumWidth()) + newLeft = mouse_event->globalX(); + if (newHeight > minimumHeight()) + newTop = mouse_event->globalY(); + setGeometry(newLeft, newTop, + newWidth, newHeight); + break; + case BottomLeft: + newWidth = std::max(_dragStartGeometry.right() - mouse_event->globalX(), minimumWidth()); + newHeight = std::max(mouse_event->globalY() - _dragStartGeometry.top(), minimumHeight()); + newLeft = geometry().left(); + if (newWidth > minimumWidth()) + newLeft = mouse_event->globalX(); + setGeometry(newLeft, _dragStartGeometry.top(), + newWidth, newHeight); + break; + case TopRight: + newWidth = std::max(mouse_event->globalX() - _dragStartGeometry.left(), minimumWidth()); + newHeight = std::max(_dragStartGeometry.bottom() - mouse_event->globalY(), minimumHeight()); + newTop = geometry().top(); + if (newHeight > minimumHeight()) + newTop = mouse_event->globalY(); + setGeometry(_dragStartGeometry.left(), newTop, + newWidth, newHeight); + break; + case BottomRight: + newWidth = std::max(mouse_event->globalX() - _dragStartGeometry.left(), minimumWidth()); + newHeight = std::max(mouse_event->globalY() - _dragStartGeometry.top(), minimumHeight()); + setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), + newWidth, newHeight); + break; + case Left: + newWidth = _dragStartGeometry.right() - mouse_event->globalX(); + if (newWidth > minimumWidth()) + setGeometry(mouse_event->globalX(), _dragStartGeometry.top(), + newWidth, height()); + break; + case Right: + newWidth = mouse_event->globalX() - _dragStartGeometry.left(); + if (newWidth > minimumWidth()) + setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), + newWidth, height()); + break; + case Top: + newHeight = _dragStartGeometry.bottom() - mouse_event->globalY(); + if (newHeight > minimumHeight()) + setGeometry(_dragStartGeometry.left(), mouse_event->globalY(), + width(), newHeight); + break; + case Bottom: + newHeight = mouse_event->globalY() - _dragStartGeometry.top(); + if (newHeight > minimumHeight()) + setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), + width(), newHeight); + break; + default: + break; + } + _freezing = true; + } + return true; + } + } else if (type == QEvent::MouseButtonPress) { + if (mouse_event->button() == Qt::LeftButton) + if (_titleBar->rect().contains(mouse_event->pos()) && + _startPos == None) { + _moving = true; + _lastMousePosition = mouse_event->pos() + + //QPoint(Margin, Margin) + + QPoint(geometry().left() - frameGeometry().left(), frameGeometry().right() - geometry().right()); + } + if (_startPos != None) + _draging = true; + _timer.start(50); + _dragStartGeometry = geometry(); + } else if (type == QEvent::MouseButtonRelease) { + if (mouse_event->button() == Qt::LeftButton) { + _moving = false; + _draging = false; + _timer.stop(); + } + } else if (!_draging && type == QEvent::Leave) { + _startPos = None; + setCursor(Qt::ArrowCursor); + } + + return QObject::eventFilter(object, event); +} + +void MainFrame::writeSettings() +{ + QSettings settings; + + settings.beginGroup("MainFrame"); + settings.setValue("size", size()); + settings.setValue("pos", pos() + + QPoint(geometry().left() - frameGeometry().left(), frameGeometry().right() - geometry().right())); + settings.endGroup(); +} + +void MainFrame::readSettings() +{ + QSettings settings; + QDesktopWidget* desktopWidget = QApplication::desktop(); + QRect deskRect = desktopWidget->availableGeometry(); + + settings.beginGroup("MainFrame"); + QSize size = settings.value("size", QSize(minWidth, minHeight)).toSize(); + QPoint pos = settings.value("pos", QPoint((deskRect.width() - minWidth)/2, (deskRect.height() - minHeight)/2)).toPoint(); + settings.endGroup(); + + if (size == deskRect.size()) { + _titleBar->showMaxRestore(); + } else { + resize(size); + move(pos); + } +} + +} // namespace pv diff --git a/DSView/pv/mainframe.h b/DSView/pv/mainframe.h new file mode 100644 index 00000000..65cab5a8 --- /dev/null +++ b/DSView/pv/mainframe.h @@ -0,0 +1,114 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 DSVIEW_PV_MAINFRAME_H +#define DSVIEW_PV_MAINFRAME_H + +#include "widgets/border.h" + +#include +#include +#include + +namespace pv { + +class DeviceManager; +class MainWindow; + +namespace toolbars { +class TitleBar; +} + +class MainFrame : public QFrame +{ + Q_OBJECT +public: + static const int minWidth = 800; + static const int minHeight = 680; + +public: + static const int Margin = 8; + + enum borderTypes{ + None, + TopLeft, + Left, + BottomLeft, + Bottom, + BottomRight, + Right, + TopRight, + Top + }borderTypes; + +public: + MainFrame(DeviceManager &device_manager, + const char *open_file_name = NULL); + + void showMaxRestore(); + +protected: + void changeEvent(QEvent* event); + void resizeEvent(QResizeEvent *event); + void closeEvent(QCloseEvent *event); + bool eventFilter(QObject *object, QEvent *event); + +public slots: + void unfreezing(); + void showNormal(); + void showMaximized(); + void showMinimized(); + +private: + void hide_border(); + void show_border(); + + void writeSettings(); + void readSettings(); + +private: + toolbars::TitleBar *_titleBar; + MainWindow *_mainWindow; + + QGridLayout *_layout; + widgets::Border *_left; + widgets::Border *_right; + widgets::Border *_top; + widgets::Border *_bottom; + widgets::Border *_top_left; + widgets::Border *_top_right; + widgets::Border *_bottom_left; + widgets::Border *_bottom_right; + + bool _moving; + bool _draging; + QPoint _lastMousePosition; + QRect _dragStartGeometry; + int _startPos; + QTimer _timer; + bool _freezing; + bool _minimized; +}; + +} // namespace pv + +#endif // DSVIEW_PV_MAINFRAME_H diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 2b708075..4d4ba569 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -45,6 +45,7 @@ #include #include #include +#include #include "mainwindow.h" @@ -56,11 +57,13 @@ #include "dialogs/deviceoptions.h" #include "dialogs/storeprogress.h" #include "dialogs/waitingdialog.h" +#include "dialogs/dsmessagebox.h" #include "toolbars/samplingbar.h" #include "toolbars/trigbar.h" #include "toolbars/filebar.h" #include "toolbars/logobar.h" +#include "toolbars/titlebar.h" #include "dock/triggerdock.h" #include "dock/dsotriggerdock.h" @@ -111,25 +114,19 @@ MainWindow::MainWindow(DeviceManager &device_manager, void MainWindow::setup_ui() { setObjectName(QString::fromUtf8("MainWindow")); - setMinimumHeight(680); - resize(1024, 768); - - // Set the window icon - QIcon icon; - icon.addFile(QString::fromUtf8(":/icons/logo.png"), - QSize(), QIcon::Normal, QIcon::Off); - setWindowIcon(icon); + layout()->setMargin(0); + layout()->setSpacing(0); // Setup the central widget _central_widget = new QWidget(this); _vertical_layout = new QVBoxLayout(_central_widget); - _vertical_layout->setSpacing(6); + _vertical_layout->setSpacing(0); _vertical_layout->setContentsMargins(0, 0, 0, 0); setCentralWidget(_central_widget); // Setup the sampling bar _sampling_bar = new toolbars::SamplingBar(_session, this); - _trig_bar = new toolbars::TrigBar(this); + _trig_bar = new toolbars::TrigBar(_session, this); _file_bar = new toolbars::FileBar(_session, this); _logo_bar = new toolbars::LogoBar(_session, this); @@ -146,7 +143,7 @@ void MainWindow::setup_ui() connect(_file_bar, SIGNAL(save()), this, SLOT(on_save())); connect(_file_bar, SIGNAL(on_screenShot()), this, - SLOT(on_screenShot())); + SLOT(on_screenShot()), Qt::QueuedConnection); connect(_file_bar, SIGNAL(load_session(QString)), this, SLOT(load_session(QString))); connect(_file_bar, SIGNAL(store_session(QString)), this, @@ -191,13 +188,17 @@ void MainWindow::setup_ui() SLOT(run_stop())); connect(_sampling_bar, SIGNAL(instant_stop()), this, SLOT(instant_stop())); - connect(_sampling_bar, SIGNAL(update_scale()), _view, - SLOT(update_scale()), Qt::DirectConnection); connect(_sampling_bar, SIGNAL(sample_count_changed()), _trigger_widget, SLOT(device_change())); - connect(_dso_trigger_widget, SIGNAL(set_trig_pos(quint64)), _view, - SLOT(set_trig_pos(quint64))); + connect(_sampling_bar, SIGNAL(show_calibration()), _view, + SLOT(show_calibration())); + connect(_sampling_bar, SIGNAL(hide_calibration()), _view, + SLOT(hide_calibration())); + connect(_dso_trigger_widget, SIGNAL(set_trig_pos(int)), _view, + SLOT(set_trig_pos(int))); + connect(_protocol_widget, SIGNAL(protocol_updated()), _view, SLOT(signals_changed())); + setIconSize(QSize(40,40)); addToolBar(_sampling_bar); addToolBar(_trig_bar); addToolBar(_file_bar); @@ -238,20 +239,22 @@ void MainWindow::setup_ui() connect(&_session, SIGNAL(capture_state_changed(int)), this, SLOT(capture_state_changed(int))); connect(&_session, SIGNAL(device_attach()), this, - SLOT(device_attach())); + SLOT(device_attach()), Qt::QueuedConnection); connect(&_session, SIGNAL(device_detach()), this, - SLOT(device_detach())); + SLOT(device_detach()), Qt::QueuedConnection); connect(&_session, SIGNAL(test_data_error()), this, SLOT(test_data_error())); connect(&_session, SIGNAL(malloc_error()), this, SLOT(malloc_error())); + connect(&_session, SIGNAL(hardware_connect_failed()), this, + SLOT(hardware_connect_failed())); + connect(&_session, SIGNAL(on_mode_change()), this, + SLOT(session_save())); connect(_view, SIGNAL(cursor_update()), _measure_widget, SLOT(cursor_update())); connect(_view, SIGNAL(cursor_moved()), _measure_widget, SLOT(cursor_moved())); - connect(_view, SIGNAL(mode_changed()), this, - SLOT(update_device_list())); // event filter _view->installEventFilter(this); @@ -288,23 +291,13 @@ void MainWindow::update_device_list() assert(_sampling_bar); _session.stop_capture(); - _view->show_trig_cursor(false); + _view->reload(); _trigger_widget->device_change(); #ifdef ENABLE_DECODE _protocol_widget->del_all_protocol(); #endif - _trig_bar->close_all(); - - if (_session.get_device()->dev_inst()->mode == LOGIC) { - _trig_bar->enable_protocol(true); - } else { - _trig_bar->enable_protocol(false); - } - if (_session.get_device()->dev_inst()->mode == DSO) { - _sampling_bar->enable_toggle(false); - } else { - _sampling_bar->enable_toggle(true); - } + _trig_bar->reload(); + _sampling_bar->reload(); shared_ptr selected_device = _session.get_device(); _device_manager.add_device(selected_device); @@ -319,16 +312,29 @@ void MainWindow::update_device_list() errorMessage, infoMessage)); } - if (strncmp(selected_device->dev_inst()->driver->name, "virtual", 7)) { + if (!selected_device->name().contains("virtual")) { + _file_bar->set_settings_en(true); _logo_bar->dsl_connected(true); - QString ses_name = config_path + - QString::fromUtf8(selected_device->dev_inst()->driver->name) + - QString::number(selected_device->dev_inst()->mode) + - ".dsc"; - load_session(ses_name); + #if QT_VERSION >= 0x050400 + QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); + #else + QDir dir(QStandardPaths::writableLocation(QStandardPaths::DataLocation)); + #endif + if (dir.exists()) { + QString str = dir.absolutePath() + "/"; + QString ses_name = str + + selected_device->name() + + QString::number(selected_device->dev_inst()->mode) + + ".dsc"; + load_session(ses_name); + } } else { + _file_bar->set_settings_en(false); _logo_bar->dsl_connected(false); } + _view->status_clear(); + _trigger_widget->init(); + _dso_trigger_widget->init(); } void MainWindow::reload() @@ -337,6 +343,11 @@ void MainWindow::reload() _session.reload(); } +void MainWindow::mode_changed() +{ + update_device_list(); +} + void MainWindow::load_file(QString file_name) { try { @@ -356,16 +367,17 @@ void MainWindow::load_file(QString file_name) void MainWindow::show_session_error( const QString text, const QString info_text) { - QMessageBox msg(this); - msg.setText(text); - msg.setInformativeText(info_text); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(text); + msg.mBox()->setInformativeText(info_text); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); } void MainWindow::device_attach() { + _session.get_device()->device_updated(); //_session.stop_hot_plug_proc(); if (_session.get_capture_state() == SigSession::Running) @@ -384,11 +396,15 @@ void MainWindow::device_attach() void MainWindow::device_detach() { + _session.get_device()->device_updated(); //_session.stop_hot_plug_proc(); if (_session.get_capture_state() == SigSession::Running) _session.stop_capture(); + session_save(); + _view->hide_calibration(); + struct sr_dev_driver **const drivers = sr_driver_list(); struct sr_dev_driver **driver; for (driver = drivers; *driver; driver++) @@ -412,7 +428,10 @@ void MainWindow::run_stop() switch(_session.get_capture_state()) { case SigSession::Init: case SigSession::Stopped: - _view->show_trig_cursor(false); + if (_session.get_device()->dev_inst()->mode == DSO) + _view->show_trig_cursor(true); + else + _view->show_trig_cursor(false); _view->update_sample(false); commit_trigger(false); _session.start_capture(false, @@ -429,14 +448,19 @@ void MainWindow::run_stop() void MainWindow::instant_stop() { #ifdef TEST_MODE - disconnect(&test_timer, SIGNAL(timeout()), - this, SLOT(run_stop())); - test_timer_linked = false; -#else + if (!test_timer_linked) { + connect(&test_timer, SIGNAL(timeout()), + this, SLOT(instant_stop())); + test_timer_linked = true; + } +#endif switch(_session.get_capture_state()) { case SigSession::Init: case SigSession::Stopped: - _view->show_trig_cursor(false); + if (_session.get_device()->dev_inst()->mode == DSO) + _view->show_trig_cursor(true); + else + _view->show_trig_cursor(false); _view->update_sample(true); commit_trigger(true); _session.start_capture(true, @@ -448,33 +472,40 @@ void MainWindow::instant_stop() _session.stop_capture(); break; } -#endif + } void MainWindow::test_data_error() { -#ifdef TEST_MODE - disconnect(&test_timer, SIGNAL(timeout()), - this, SLOT(run_stop())); - test_timer_linked = false; -#endif + _session.stop_capture(); - QMessageBox msg(this); - msg.setText(tr("Data Error")); - msg.setInformativeText(tr("the receive data are not consist with pre-defined test data")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Data Error")); + msg.mBox()->setInformativeText(tr("the receive data are not consist with pre-defined test data")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); } void MainWindow::malloc_error() { _session.stop_capture(); - QMessageBox msg(this); - msg.setText(tr("Malloc Error")); - msg.setInformativeText(tr("Memory is not enough for this sample!\nPlease reduce the sample depth!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Malloc Error")); + msg.mBox()->setInformativeText(tr("Memory is not enough for this sample!\nPlease reduce the sample depth!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); + msg.exec(); +} + +void MainWindow::hardware_connect_failed() +{ + _session.stop_capture(); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Hardware Connect Failed")); + msg.mBox()->setInformativeText(tr("Please check hardware connection!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); } @@ -488,52 +519,44 @@ void MainWindow::capture_state_changed(int state) _sampling_bar->enable_toggle(state != SigSession::Running); _trig_bar->enable_toggle(state != SigSession::Running); _measure_dock->widget()->setEnabled(state != SigSession::Running); - if (_session.get_device()->dev_inst()->mode == LOGIC && - state == SigSession::Stopped) { - GVariant *gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_RLE); - if (gvar != NULL) { - bool rle = g_variant_get_boolean(gvar); - g_variant_unref(gvar); - if (rle) { - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_ACTUAL_SAMPLES); - if (gvar != NULL) { - uint64_t actual_samples = g_variant_get_uint64(gvar); - g_variant_unref(gvar); - if (actual_samples != _session.get_device()->get_sample_limit()) { - show_session_error(tr("RLE Mode Warning"), - tr("Hardware buffer is full!\nActually received samples is less than setted sample depth!")); - } - } - } - } - } -#ifdef TEST_MODE - if (state == SigSession::Stopped) { - test_timer.start(100); - } -#endif } + +#ifdef TEST_MODE + if (state == SigSession::Stopped) { + test_timer.start(qrand()%1000); + } +#endif } -void MainWindow::closeEvent(QCloseEvent *event) +void MainWindow::session_save() { - QDir dir(QCoreApplication::applicationDirPath()); - if (dir.cd("res")) { - QString driver_name = _session.get_device()->dev_inst()->driver->name; + QDir dir; + #if QT_VERSION >= 0x050400 + QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + #else + QString path = QStandardPaths::writableLocation(QStandardPaths::DataLocation); + #endif + if(dir.mkpath(path)) { + dir.cd(path); + QString driver_name = _session.get_device()->name(); QString mode_name = QString::number(_session.get_device()->dev_inst()->mode); QString file_name = dir.absolutePath() + "/" + driver_name + mode_name + ".dsc"; if (strncmp(driver_name.toLocal8Bit(), "virtual", 7) && !file_name.isEmpty()) store_session(file_name); } +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + session_save(); event->accept(); } void MainWindow::on_protocol(bool visible) { #ifdef ENABLE_DECODE - if (_session.get_device()->dev_inst()->mode == LOGIC) - _protocol_dock->setVisible(visible); + _protocol_dock->setVisible(visible); #endif } @@ -548,6 +571,7 @@ void MainWindow::on_trigger(bool visible) _trigger_dock->setVisible(false); _dso_trigger_dock->setVisible(visible); } + _trig_bar->update_trig_btn(visible); } void MainWindow::commit_trigger(bool instant) @@ -583,35 +607,43 @@ void MainWindow::on_search(bool visible) void MainWindow::on_screenShot() { + const QString DIR_KEY("ScreenShotPath"); + QSettings settings; QPixmap pixmap; QDesktopWidget *desktop = QApplication::desktop(); - pixmap = QPixmap::grabWindow(desktop->winId(), pos().x(), pos().y(), frameGeometry().width(), frameGeometry().height()); + pixmap = QPixmap::grabWindow(desktop->winId(), parentWidget()->pos().x(), parentWidget()->pos().y(), + parentWidget()->frameGeometry().width(), parentWidget()->frameGeometry().height()); QString format = "png"; - QString initialPath = QDir::currentPath()+ - tr("/untitled.") + format; QString fileName = QFileDialog::getSaveFileName(this, - tr("Save As"),initialPath, + tr("Save As"),settings.value(DIR_KEY).toString(), tr("%1 Files (*.%2);;All Files (*)") .arg(format.toUpper()).arg(format)); - if (!fileName.isEmpty()) + if (!fileName.isEmpty()) { + QDir CurrentDir; + settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(fileName)); pixmap.save(fileName, format.toLatin1()); + } } void MainWindow::on_save() { using pv::dialogs::StoreProgress; + const QString DIR_KEY("SavePath"); + QSettings settings; + // Stop any currently running capture session _session.stop_capture(); // Show the dialog const QString file_name = QFileDialog::getSaveFileName( - this, tr("Save File"), "", tr("DSView Data (*.dsl)")); + this, tr("Save File"), settings.value(DIR_KEY).toString(), tr("DSView Data (*.dsl)")); if (file_name.isEmpty()) return; - + QDir CurrentDir; + settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(file_name)); StoreProgress *dlg = new StoreProgress(file_name, _session, this); dlg->run(); } @@ -620,12 +652,13 @@ bool MainWindow::load_session(QString name) { QFile sessionFile(name); if (!sessionFile.open(QIODevice::ReadOnly)) { - QMessageBox msg(this); - msg.setText(tr("File Error")); - msg.setInformativeText(tr("Couldn't open session file!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); - msg.exec(); +// dialogs::DSMessageBox msg(this); +// msg.mBox()->setText(tr("File Error")); +// msg.mBox()->setInformativeText(tr("Couldn't open session file!")); +// msg.mBox()->setStandardButtons(QMessageBox::Ok); +// msg.mBox()->setIcon(QMessageBox::Warning); +// msg.exec(); + qDebug("Warning: Couldn't open session file!"); return false; } @@ -637,11 +670,11 @@ bool MainWindow::load_session(QString name) const sr_dev_inst *const sdi = _session.get_device()->dev_inst(); if (strcmp(sdi->driver->name, sessionObj["Device"].toString().toLocal8Bit()) != 0 || sdi->mode != sessionObj["DeviceMode"].toDouble()) { - QMessageBox msg(this); - msg.setText(tr("Session Error")); - msg.setInformativeText(tr("Session File is not compatible with current device or mode!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Session Error")); + msg.mBox()->setInformativeText(tr("Session File is not compatible with current device or mode!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); return false; } @@ -655,6 +688,8 @@ bool MainWindow::load_session(QString name) for (unsigned int i = 0; i < num_opts; i++) { const struct sr_config_info *const info = sr_config_info_get(options[i]); + if (!sessionObj.contains(info->name)) + continue; if (info->datatype == SR_T_BOOL) _session.get_device()->set_config(NULL, NULL, info->key, g_variant_new_boolean(sessionObj[info->name].toDouble())); else if (info->datatype == SR_T_UINT64) @@ -694,7 +729,8 @@ bool MainWindow::load_session(QString name) if (!isEnabled) probe->enabled = false; } - _session.init_signals(); + //_session.init_signals(); + _session.reload(); // load signal setting BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { @@ -703,6 +739,7 @@ bool MainWindow::load_session(QString name) if ((s->get_index() == obj["index"].toDouble()) && (s->get_type() == obj["type"].toDouble())) { s->set_colour(QColor(obj["colour"].toString())); + s->set_name(g_strdup(obj["name"].toString().toStdString().c_str())); boost::shared_ptr logicSig; if (logicSig = dynamic_pointer_cast(s)) { @@ -712,8 +749,9 @@ bool MainWindow::load_session(QString name) boost::shared_ptr dsoSig; if (dsoSig = dynamic_pointer_cast(s)) { dsoSig->load_settings(); - dsoSig->set_zeroRate(obj["zeroPos"].toDouble()); - dsoSig->set_trigRate(obj["trigValue"].toDouble()); + dsoSig->set_zero_vrate(obj["zeroPos"].toDouble()); + dsoSig->set_trig_vrate(obj["trigValue"].toDouble()); + dsoSig->commit_settings(); } break; } @@ -731,12 +769,13 @@ bool MainWindow::store_session(QString name) { QFile sessionFile(name); if (!sessionFile.open(QIODevice::WriteOnly | QIODevice::Text)) { - QMessageBox msg(this); - msg.setText(tr("File Error")); - msg.setInformativeText(tr("Couldn't open session file to write!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); - msg.exec(); +// dialogs::DSMessageBox msg(this); +// msg.mBox()->setText(tr("File Error")); +// msg.mBox()->setInformativeText(tr("Couldn't open session file to write!")); +// msg.mBox()->setStandardButtons(QMessageBox::Ok); +// msg.mBox()->setIcon(QMessageBox::Warning); +// msg.exec(); + qDebug("Warning: Couldn't open session file to write!"); return false; } QTextStream outStream(&sessionFile); @@ -794,8 +833,8 @@ bool MainWindow::store_session(QString name) s_obj["vdiv"] = QJsonValue::fromVariant(static_cast(dsoSig->get_vDialValue())); s_obj["vfactor"] = QJsonValue::fromVariant(static_cast(dsoSig->get_factor())); s_obj["coupling"] = dsoSig->get_acCoupling(); - s_obj["trigValue"] = dsoSig->get_trigRate(); - s_obj["zeroPos"] = dsoSig->get_zeroRate(); + s_obj["trigValue"] = dsoSig->get_trig_vrate(); + s_obj["zeroPos"] = dsoSig->get_zero_vrate(); } channelVar.append(s_obj); } @@ -817,10 +856,8 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) { (void) object; - if( event->type() == QEvent::KeyPress ) { - const vector< shared_ptr > sigs( - _session.get_signals()); - + if ( event->type() == QEvent::KeyPress ) { + const vector< shared_ptr > sigs(_session.get_signals()); QKeyEvent *ke = (QKeyEvent *) event; switch(ke->key()) { case Qt::Key_S: diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index 0ae69138..a8e73564 100644 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -59,6 +59,10 @@ class MeasureDock; class SearchDock; } +namespace dialogs{ +class Calibration; +} + namespace view { class View; } @@ -82,6 +86,9 @@ private: bool eventFilter(QObject *object, QEvent *event); +public slots: + void session_save(); + private slots: void load_file(QString file_name); @@ -93,6 +100,8 @@ private slots: */ void update_device_list(); + void mode_changed(); + void reload(); void show_session_error( @@ -131,6 +140,11 @@ private slots: void device_attach(); void device_detach(); + /* + * errors + */ + void hardware_connect_failed(); + private: DeviceManager &_device_manager; diff --git a/DSView/pv/prop/binding/binding.cpp b/DSView/pv/prop/binding/binding.cpp index 95c9ca3b..95fe443f 100644 --- a/DSView/pv/prop/binding/binding.cpp +++ b/DSView/pv/prop/binding/binding.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -70,6 +70,10 @@ QWidget* Binding::get_property_form(QWidget *parent, { QWidget *const form = new QWidget(parent); QFormLayout *const layout = new QFormLayout(form); + layout->setVerticalSpacing(5); + layout->setFormAlignment(Qt::AlignLeft); + layout->setLabelAlignment(Qt::AlignLeft); + layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); form->setLayout(layout); add_properties_to_form(layout, auto_commit); return form; diff --git a/DSView/pv/prop/binding/binding.h b/DSView/pv/prop/binding/binding.h index ab7758b5..ca1462c2 100644 --- a/DSView/pv/prop/binding/binding.h +++ b/DSView/pv/prop/binding/binding.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 diff --git a/DSView/pv/prop/binding/binding_deviceoptions.cpp b/DSView/pv/prop/binding/binding_deviceoptions.cpp index c8c1e9a0..ea9a3c99 100644 --- a/DSView/pv/prop/binding/binding_deviceoptions.cpp +++ b/DSView/pv/prop/binding/binding_deviceoptions.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 diff --git a/DSView/pv/prop/binding/deviceoptions.h b/DSView/pv/prop/binding/deviceoptions.h index a4b99744..f9f8d42b 100644 --- a/DSView/pv/prop/binding/deviceoptions.h +++ b/DSView/pv/prop/binding/deviceoptions.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 diff --git a/DSView/pv/prop/bool.cpp b/DSView/pv/prop/bool.cpp index 9d7e4961..2dd84890 100644 --- a/DSView/pv/prop/bool.cpp +++ b/DSView/pv/prop/bool.cpp @@ -3,7 +3,6 @@ * DSView 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 diff --git a/DSView/pv/prop/bool.h b/DSView/pv/prop/bool.h index 3976606d..a1b3e2f6 100644 --- a/DSView/pv/prop/bool.h +++ b/DSView/pv/prop/bool.h @@ -3,7 +3,6 @@ * DSView 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 diff --git a/DSView/pv/prop/double.cpp b/DSView/pv/prop/double.cpp index 2bd4a9ff..73a174bb 100644 --- a/DSView/pv/prop/double.cpp +++ b/DSView/pv/prop/double.cpp @@ -3,7 +3,6 @@ * DSView 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 diff --git a/DSView/pv/prop/double.h b/DSView/pv/prop/double.h index e26d5d04..7eb4493d 100644 --- a/DSView/pv/prop/double.h +++ b/DSView/pv/prop/double.h @@ -3,7 +3,6 @@ * DSView 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 diff --git a/DSView/pv/prop/enum.cpp b/DSView/pv/prop/enum.cpp index 8c51f554..af4a8c9f 100644 --- a/DSView/pv/prop/enum.cpp +++ b/DSView/pv/prop/enum.cpp @@ -3,7 +3,6 @@ * DSView 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 @@ -24,6 +23,7 @@ #include #include +#include #include "enum.h" @@ -61,12 +61,14 @@ QWidget* Enum::get_widget(QWidget *parent, bool auto_commit) return NULL; _selector = new QComboBox(parent); + _selector->setSizeAdjustPolicy(QComboBox::AdjustToContents); for (unsigned int i = 0; i < _values.size(); i++) { const pair &v = _values[i]; _selector->addItem(v.second, qVariantFromValue((void*)v.first)); if (value && g_variant_compare(v.first, value) == 0) _selector->setCurrentIndex(i); } + _selector->view()->setMinimumWidth(_selector->width()+30); g_variant_unref(value); diff --git a/DSView/pv/prop/enum.h b/DSView/pv/prop/enum.h index dbeb1cf2..a223565a 100644 --- a/DSView/pv/prop/enum.h +++ b/DSView/pv/prop/enum.h @@ -3,7 +3,6 @@ * DSView 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 diff --git a/DSView/pv/prop/int.cpp b/DSView/pv/prop/int.cpp index 1c9e79cd..b3ea0c69 100644 --- a/DSView/pv/prop/int.cpp +++ b/DSView/pv/prop/int.cpp @@ -3,7 +3,6 @@ * DSView 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 diff --git a/DSView/pv/prop/int.h b/DSView/pv/prop/int.h index 776b4f98..daa4c1d3 100644 --- a/DSView/pv/prop/int.h +++ b/DSView/pv/prop/int.h @@ -3,7 +3,6 @@ * DSView 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 diff --git a/DSView/pv/prop/property.cpp b/DSView/pv/prop/property.cpp index 48ca4a2c..af793309 100644 --- a/DSView/pv/prop/property.cpp +++ b/DSView/pv/prop/property.cpp @@ -3,7 +3,6 @@ * DSView 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 diff --git a/DSView/pv/prop/property.h b/DSView/pv/prop/property.h index 6ef784d5..3a1b165f 100644 --- a/DSView/pv/prop/property.h +++ b/DSView/pv/prop/property.h @@ -3,7 +3,6 @@ * DSView 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 diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index fb547f52..a42b50e0 100644 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -41,23 +41,26 @@ #include "data/groupsnapshot.h" #include "data/decoderstack.h" #include "data/decode/decoder.h" +#include "data/decodermodel.h" +#include "data/mathstack.h" #include "view/analogsignal.h" #include "view/dsosignal.h" #include "view/logicsignal.h" #include "view/groupsignal.h" #include "view/decodetrace.h" +#include "view/mathtrace.h" #include #include #include #include -#include #include #include #include #include +#include #include #include @@ -95,13 +98,33 @@ SigSession::SigSession(DeviceManager &device_manager) : _group_cnt = 0; register_hotplug_callback(); _view_timer.stop(); - _view_timer.setSingleShot(true); + _noData_cnt = 0; _refresh_timer.stop(); _refresh_timer.setSingleShot(true); _data_lock = false; - connect(this, SIGNAL(start_timer(int)), &_view_timer, SLOT(start(int))); - //connect(&_view_timer, SIGNAL(timeout()), this, SLOT(refresh())); + _data_updated = false; + _decoder_model = new pv::data::DecoderModel(this); + + // Create snapshots & data containers + _cur_logic_snapshot.reset(new data::LogicSnapshot()); + _logic_data.reset(new data::Logic()); + _logic_data->push_snapshot(_cur_logic_snapshot); + _cur_dso_snapshot.reset(new data::DsoSnapshot()); + _dso_data.reset(new data::Dso()); + _dso_data->push_snapshot(_cur_dso_snapshot); + _cur_analog_snapshot.reset(new data::AnalogSnapshot()); + _analog_data.reset(new data::Analog()); + _analog_data->push_snapshot(_cur_analog_snapshot); + _group_data.reset(new data::Group()); + _group_cnt = 0; + + connect(&_view_timer, SIGNAL(timeout()), this, SLOT(check_update())); connect(&_refresh_timer, SIGNAL(timeout()), this, SLOT(data_unlock())); + + #ifdef TEST_MODE + _test_timer.setSingleShot(true); + connect(&_test_timer, SIGNAL(timeout()), this, SLOT(stop_capture())); + #endif } SigSession::~SigSession() @@ -131,7 +154,7 @@ void SigSession::set_device(boost::shared_ptr dev_inst) throw(Q using pv::device::Device; // Ensure we are not capturing before setting the device - stop_capture(); + //stop_capture(); if (_dev_inst) { sr_session_datafeed_callback_remove_all(); @@ -147,6 +170,8 @@ void SigSession::set_device(boost::shared_ptr dev_inst) throw(Q if (_dev_inst) { try { _dev_inst->use(this); + _cur_samplerate = _dev_inst->get_sample_rate(); + _cur_samplelimits = _dev_inst->get_sample_limit(); } catch(const QString e) { throw(e); return; @@ -175,7 +200,7 @@ void SigSession::set_file(QString name) throw(QString) } } -void SigSession::save_file(const QString name, int type){ +void SigSession::save_file(const QString name, QWidget* parent, int type){ unsigned char* data; int unit_size; uint64_t sample_count; @@ -212,8 +237,23 @@ void SigSession::save_file(const QString name, int type){ sample_count = snapshot->get_sample_count(); } - sr_session_save(name.toLocal8Bit().data(), _dev_inst->dev_inst(), - data, unit_size, sample_count); + QFuture future; + future = QtConcurrent::run([&]{ + sr_session_save(name.toLocal8Bit().data(), _dev_inst->dev_inst(), + data, unit_size, sample_count, _trigger_time.toMSecsSinceEpoch(), _trigger_pos); + }); + Qt::WindowFlags flags = Qt::CustomizeWindowHint; + QProgressDialog dlg(tr("Save Capture to File... It can take a while."), + tr("Cancel"),0,0,parent,flags); + dlg.setWindowModality(Qt::WindowModal); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + dlg.setCancelButton(NULL); + + QFutureWatcher watcher; + watcher.setFuture(future); + connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); + + dlg.exec(); } QList SigSession::getSuportedExportFormats(){ @@ -389,8 +429,7 @@ void SigSession::set_default_device(boost::function error_ // Try and find the DreamSourceLab device and select that by default BOOST_FOREACH (boost::shared_ptr dev, devices) if (dev->dev_inst() && - strncmp(dev->dev_inst()->driver->name, - "virtual", 7) != 0) { + !dev->name().contains("virtual")) { default_device = dev; break; } @@ -408,21 +447,122 @@ void SigSession::release_device(device::DevInst *dev_inst) (void)dev_inst; assert(_dev_inst.get() == dev_inst); - assert(_capture_state != Running); + assert(get_capture_state() != Running); _dev_inst = boost::shared_ptr(); //_dev_inst.reset(); } SigSession::capture_state SigSession::get_capture_state() const { - boost::lock_guard lock(_sampling_mutex); + boost::lock_guard lock(_sampling_mutex); return _capture_state; } +uint64_t SigSession::cur_samplelimits() const +{ + return _cur_samplelimits; +} + +uint64_t SigSession::cur_samplerate() const +{ + return _cur_samplerate; +} + +double SigSession::cur_sampletime() const +{ + if (_cur_samplerate == 0) + return 0; + else + return cur_samplelimits() * 1.0 / cur_samplerate(); +} + +void SigSession::set_cur_samplerate(uint64_t samplerate) +{ + assert(samplerate != 0); + _cur_samplerate = samplerate; + // sample rate for all SignalData + // Logic/Analog/Dso + if (_logic_data) + _logic_data->set_samplerate(_cur_samplerate); + if (_analog_data) + _analog_data->set_samplerate(_cur_samplerate); + if (_dso_data) + _dso_data->set_samplerate(_cur_samplerate); + // Group + if (_group_data) + _group_data->set_samplerate(_cur_samplerate); + +#ifdef ENABLE_DECODE + // DecoderStack + BOOST_FOREACH(const boost::shared_ptr d, _decode_traces) + d->decoder()->set_samplerate(_cur_samplerate); +#endif + // MathStack + BOOST_FOREACH(const boost::shared_ptr m, _math_traces) + m->get_math_stack()->set_samplerate(_cur_samplerate); +} + +void SigSession::set_cur_samplelimits(uint64_t samplelimits) +{ + assert(samplelimits != 0); + _cur_samplelimits = samplelimits; +} + + +void SigSession::capture_init() +{ + _cur_samplerate = _dev_inst->get_sample_rate(); + _cur_samplelimits = _dev_inst->get_sample_limit(); + _data_updated = false; + if (_dev_inst->dev_inst()->mode != LOGIC) + _view_timer.start(ViewTime); + else + _view_timer.stop(); + _noData_cnt = 0; + data_unlock(); + + // Init and Set sample rate for all SignalData + // Logic/Analog/Dso + if (_logic_data) { + _logic_data->init(); + _logic_data->set_samplerate(_cur_samplerate); + } + if (_analog_data) { + _analog_data->init(); + _analog_data->set_samplerate(_cur_samplerate); + } + if (_dso_data) { + _dso_data->init(); + _dso_data->set_samplerate(_cur_samplerate); + } + // Group + if (_group_data) { + _group_data->init(); + _group_data->set_samplerate(_cur_samplerate); + } +#ifdef ENABLE_DECODE + // DecoderStack + BOOST_FOREACH(const boost::shared_ptr d, _decode_traces) + { + assert(d); + d->decoder()->init(); + d->decoder()->set_samplerate(_cur_samplerate); + } +#endif + // MathStack + BOOST_FOREACH(const boost::shared_ptr m, _math_traces) + { + assert(m); + m->get_math_stack()->init(); + m->get_math_stack()->set_samplerate(_cur_samplerate); + } +} + void SigSession::start_capture(bool instant, boost::function error_handler) { stop_capture(); + capture_init(); // Check that a device instance has been selected. if (!_dev_inst) { @@ -442,20 +582,18 @@ void SigSession::start_capture(bool instant, } if (!l) { error_handler(tr("No probes enabled.")); - capture_state_changed(_capture_state); + data_updated(); + capture_state_changed(SigSession::Stopped); return; } // update setting - if (strcmp(_dev_inst->dev_inst()->driver->name, "virtual-session")) + if (_dev_inst->name() != "virtual-session") _instant = instant; else _instant = true; - if (~_instant) - _view_timer.blockSignals(false); // Begin the session - _sampling_thread.reset(new boost::thread( &SigSession::sample_thread_proc, this, _dev_inst, error_handler)); @@ -464,38 +602,43 @@ void SigSession::start_capture(bool instant, void SigSession::stop_capture() { _instant = false; +#ifdef ENABLE_DECODE + for (vector< boost::shared_ptr >::iterator i = + _decode_traces.begin(); + i != _decode_traces.end(); + i++) + (*i)->decoder()->stop_decode(); +#endif if (get_capture_state() != Running) return; sr_session_stop(); - _view_timer.blockSignals(true); // Check that sampling stopped - if (_sampling_thread.get()) - _sampling_thread->join(); - _sampling_thread.reset(); + if (_sampling_thread.get()) + _sampling_thread->join(); + _sampling_thread.reset(); } vector< boost::shared_ptr > SigSession::get_signals() { - boost::lock_guard lock(_signals_mutex); + //boost::lock_guard lock(_signals_mutex); return _signals; } vector< boost::shared_ptr > SigSession::get_group_signals() { - boost::lock_guard lock(_signals_mutex); + //boost::lock_guard lock(_signals_mutex); return _group_traces; } set< boost::shared_ptr > SigSession::get_data() const { - lock_guard lock(_signals_mutex); + //lock_guard lock(_signals_mutex); set< boost::shared_ptr > data; BOOST_FOREACH(const boost::shared_ptr sig, _signals) { assert(sig); data.insert(sig->data()); } - data.insert(_group_data); return data; } @@ -505,7 +648,7 @@ bool SigSession::get_instant() return _instant; } -void* SigSession::get_buf(int& unit_size, uint64_t &length) +const void* SigSession::get_buf(int& unit_size, uint64_t &length) { if (_dev_inst->dev_inst()->mode == LOGIC) { const deque< boost::shared_ptr > &snapshots = @@ -548,7 +691,7 @@ void* SigSession::get_buf(int& unit_size, uint64_t &length) void SigSession::set_capture_state(capture_state state) { - boost::lock_guard lock(_sampling_mutex); + boost::lock_guard lock(_sampling_mutex); _capture_state = state; data_updated(); capture_state_changed(state); @@ -572,44 +715,32 @@ void SigSession::sample_thread_proc(boost::shared_ptr dev_inst, set_capture_state(Running); dev_inst->run(); + set_capture_state(Stopped); // Confirm that SR_DF_END was received - assert(!_cur_logic_snapshot); - assert(!_cur_dso_snapshot); - assert(!_cur_analog_snapshot); + assert(_cur_logic_snapshot->last_ended()); + assert(_cur_dso_snapshot->last_ended()); + assert(_cur_analog_snapshot->last_ended()); } -void SigSession::read_sample_rate(const sr_dev_inst *const sdi) +void SigSession::check_update() { - GVariant *gvar; - uint64_t sample_rate = 0; + if (_capture_state != Running) + return; - // Read out the sample rate - if(sdi->driver) - { - 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; - } - - sample_rate = g_variant_get_uint64(gvar); - g_variant_unref(gvar); + if (_data_updated) { + data_updated(); + _data_updated = false; + _noData_cnt = 0; + #ifdef TEST_MODE + if (!_test_timer.isActive()) + _test_timer.start(qrand()%5000); + #endif + } else { + if (++_noData_cnt >= (WaitShowTime/ViewTime)) + nodata_timeout(); } - - // Set the sample rate of all data - const set< boost::shared_ptr > data_set = get_data(); - BOOST_FOREACH(boost::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() @@ -625,8 +756,10 @@ void SigSession::add_group() if (probe_index_list.size() > 1) { //_group_data.reset(new data::Group(_last_sample_rate)); - if (_group_data->get_snapshots().empty()) - _group_data->set_samplerate(_dev_inst->get_sample_rate()); +// if (_group_data->get_snapshots().empty()) +// _group_data->set_samplerate(_dev_inst->get_sample_rate()); + _group_data->init(); + _group_data->set_samplerate(_cur_samplerate); const boost::shared_ptr signal( new view::GroupSignal("New Group", _group_data, probe_index_list, _group_cnt)); @@ -696,6 +829,15 @@ void SigSession::init_signals() unsigned int dso_probe_count = 0; unsigned int analog_probe_count = 0; + if (_logic_data) + _logic_data->clear(); + if (_dso_data) + _dso_data->clear(); + if (_analog_data) + _analog_data->clear(); + if (_group_data) + _group_data->clear(); + #ifdef ENABLE_DECODE // Clear the decode traces _decode_traces.clear(); @@ -726,36 +868,14 @@ void SigSession::init_signals() } } - // Create data containers for the coming data snapshots - { - if (logic_probe_count != 0) { - _logic_data.reset(new data::Logic()); - assert(_logic_data); - } - - if (dso_probe_count != 0) { - _dso_data.reset(new data::Dso()); - assert(_dso_data); - } - - if (analog_probe_count != 0) { - _analog_data.reset(new data::Analog()); - assert(_analog_data); - } - - _group_data.reset(new data::Group()); - assert(_group_data); - _group_cnt = 0; - } - // Make the logic probe list { _group_traces.clear(); vector< boost::shared_ptr >().swap(_group_traces); - for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { - const sr_channel *const probe = - (const sr_channel *)l->data; + for (GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { + sr_channel *probe = + ( sr_channel *)l->data; assert(probe); signal.reset(); switch(probe->type) { @@ -783,10 +903,10 @@ void SigSession::init_signals() _signals.clear(); vector< boost::shared_ptr >().swap(_signals); _signals = sigs; - - signals_changed(); - data_updated(); } + + mathTraces_rebuild(); + //data_updated(); } void SigSession::reload() @@ -796,14 +916,15 @@ void SigSession::reload() if (_capture_state == Running) stop_capture(); + //refresh(0); vector< boost::shared_ptr > sigs; boost::shared_ptr signal; // Make the logic probe list { - for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { - const sr_channel *const probe = - (const sr_channel *)l->data; + for (GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { + sr_channel *probe = + (sr_channel *)l->data; assert(probe); signal.reset(); switch(probe->type) { @@ -846,28 +967,42 @@ void SigSession::reload() _signals = sigs; } - signals_changed(); + mathTraces_rebuild(); } void SigSession::refresh(int holdtime) { + boost::lock_guard lock(_data_mutex); + + _data_lock = true; + _refresh_timer.start(holdtime); + if (_logic_data) { - _logic_data->clear(); - _cur_logic_snapshot.reset(); + _logic_data->init(); + //_cur_logic_snapshot.reset(); +#ifdef ENABLE_DECODE + BOOST_FOREACH(const boost::shared_ptr d, _decode_traces) + { + assert(d); + d->decoder()->init(); + } +#endif } if (_dso_data) { - _dso_data->clear(); - _cur_dso_snapshot.reset(); + _dso_data->init(); + // MathStack + BOOST_FOREACH(const boost::shared_ptr m, _math_traces) + { + assert(m); + m->get_math_stack()->init(); + } } if (_analog_data) { - _analog_data->clear(); - _cur_analog_snapshot.reset(); + _analog_data->init(); + //_cur_analog_snapshot.reset(); } - if (strncmp(_dev_inst->dev_inst()->driver->name, "virtual", 7)) { - _data_lock = true; - _refresh_timer.start(holdtime); - } - data_updated(); + //data_updated(); + _data_updated = true; } void SigSession::data_unlock() @@ -880,6 +1015,27 @@ bool SigSession::get_data_lock() return _data_lock; } +void SigSession::feed_in_header(const sr_dev_inst *sdi) +{ + (void)sdi; + _trigger_pos = 0; + _trigger_time = QDateTime::currentDateTime(); + const int64_t secs = -cur_sampletime(); + _trigger_time = _trigger_time.addSecs(secs); + + if (_dev_inst->name() == "virtual-session") { + int64_t time; + GVariant* gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_TRIGGER_TIME); + if (gvar != NULL) { + time = g_variant_get_int64(gvar); + g_variant_unref(gvar); + if (time != 0) + _trigger_time = QDateTime::fromMSecsSinceEpoch(time); + } + } + receive_header(); +} + void SigSession::feed_in_meta(const sr_dev_inst *sdi, const sr_datafeed_meta &meta) { @@ -902,7 +1058,14 @@ void SigSession::feed_in_meta(const sr_dev_inst *sdi, void SigSession::feed_in_trigger(const ds_trigger_pos &trigger_pos) { if (_dev_inst->dev_inst()->mode != DSO) { - receive_trigger(trigger_pos.real_pos); + _trigger_pos = trigger_pos.real_pos; + receive_trigger(_trigger_pos); + if (_dev_inst->name() != "virtual-session") { + const double time = trigger_pos.real_pos * 1.0 / _cur_samplerate; + _trigger_time = QDateTime::currentDateTime(); + const int64_t secs = time - cur_sampletime(); + _trigger_time = _trigger_time.addSecs(secs); + } } else { int probe_count = 0; int probe_en_count = 0; @@ -915,16 +1078,15 @@ void SigSession::feed_in_trigger(const ds_trigger_pos &trigger_pos) probe_en_count++; } } - receive_trigger(trigger_pos.real_pos * probe_count / probe_en_count); + _trigger_pos = trigger_pos.real_pos * probe_count / probe_en_count; + receive_trigger(_trigger_pos); } } void SigSession::feed_in_logic(const sr_datafeed_logic &logic) { - boost::lock_guard lock(_data_mutex); - - if (!_logic_data) - { + //boost::lock_guard lock(_data_mutex); + if (!_logic_data || _cur_logic_snapshot->memory_failed()) { qDebug() << "Unexpected logic packet"; return; } @@ -933,47 +1095,39 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) test_data_error(); } - if (!_cur_logic_snapshot) - { - // Create a new data snapshot - _cur_logic_snapshot = boost::shared_ptr( - new data::LogicSnapshot(logic, _dev_inst->get_sample_limit(), 1)); - if (_cur_logic_snapshot->buf_null()) - { + if (_cur_logic_snapshot->last_ended()) { + _cur_logic_snapshot->first_payload(logic, _dev_inst->get_sample_limit(), 1); + if (_cur_logic_snapshot->memory_failed()) { malloc_error(); return; - } 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 if(!_cur_logic_snapshot->buf_null()) { + } else { // Append to the existing data snapshot _cur_logic_snapshot->append_payload(logic); - } else { - return; } emit receive_data(logic.length/logic.unitsize); data_received(); //data_updated(); + _data_updated = true; } void SigSession::feed_in_dso(const sr_datafeed_dso &dso) { - boost::lock_guard lock(_data_mutex); + //boost::lock_guard lock(_data_mutex); - if(!_dso_data) + if(!_dso_data || _cur_dso_snapshot->memory_failed()) { qDebug() << "Unexpected dso packet"; return; // This dso packet was not expected. } - if (!_cur_dso_snapshot) + if (_cur_dso_snapshot->last_ended()) { // reset scale of dso signal BOOST_FOREACH(const boost::shared_ptr s, _signals) @@ -984,59 +1138,56 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) dsoSig->set_scale(dsoSig->get_view_rect().height() / 256.0f); } - // Create a new data snapshot - _cur_dso_snapshot = boost::shared_ptr( - new data::DsoSnapshot(dso, _dev_inst->get_sample_limit(), get_ch_num(SR_CHANNEL_DSO), _instant)); - if (_cur_dso_snapshot->buf_null()) - { + // first payload + _cur_dso_snapshot->first_payload(dso, _dev_inst->get_sample_limit(), get_ch_num(SR_CHANNEL_DSO), _instant); + if (_cur_dso_snapshot->memory_failed()) { malloc_error(); return; - } else { - _dso_data->push_snapshot(_cur_dso_snapshot); } - } else if(!_cur_dso_snapshot->buf_null()) { + } else { // Append to the existing data snapshot _cur_dso_snapshot->append_payload(dso); - } else { - return; + } + // calculate related math results + BOOST_FOREACH(const boost::shared_ptr m, _math_traces) + { + assert(m); + if (m->enabled()) + m->get_math_stack()->calc_fft(); } + _trigger_flag = dso.trig_flag; receive_data(dso.num_samples); - data_updated(); - //if (!_instant) - // start_timer(ViewTime); + //data_updated(); + _data_updated = true; } void SigSession::feed_in_analog(const sr_datafeed_analog &analog) { - boost::lock_guard lock(_data_mutex); + //boost::lock_guard lock(_data_mutex); - if(!_analog_data) + if(!_analog_data || _cur_analog_snapshot->memory_failed()) { qDebug() << "Unexpected analog packet"; return; // This analog packet was not expected. } - if (!_cur_analog_snapshot) + if (_cur_analog_snapshot->last_ended()) { - // Create a new data snapshot - _cur_analog_snapshot = boost::shared_ptr( - new data::AnalogSnapshot(analog, _dev_inst->get_sample_limit(), get_ch_num(SR_CHANNEL_ANALOG))); - if (_cur_analog_snapshot->buf_null()) - { + // first payload + _cur_analog_snapshot->first_payload(analog, _dev_inst->get_sample_limit(), get_ch_num(SR_CHANNEL_ANALOG)); + if (_cur_analog_snapshot->memory_failed()) { + malloc_error(); return; - } else if(!_cur_analog_snapshot->buf_null()) { - _analog_data->push_snapshot(_cur_analog_snapshot); } - } else if(!_cur_analog_snapshot->buf_null()) { + } else { // Append to the existing data snapshot _cur_analog_snapshot->append_payload(analog); - } else { - return; } receive_data(analog.num_samples); - data_updated(); + //data_updated(); + _data_updated = true; } void SigSession::data_feed_in(const struct sr_dev_inst *sdi, @@ -1045,6 +1196,8 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, assert(sdi); assert(packet); + boost::lock_guard lock(_data_mutex); + if (_data_lock) return; @@ -1082,8 +1235,8 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, case SR_DF_END: { { - boost::lock_guard lock(_data_mutex); - if (_cur_logic_snapshot) { + //boost::lock_guard lock(_data_mutex); + if (!_cur_logic_snapshot->empty()) { BOOST_FOREACH(const boost::shared_ptr g, _group_traces) { assert(g); @@ -1094,17 +1247,14 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, _cur_group_snapshot.reset(); } } - _cur_logic_snapshot.reset(); - _cur_dso_snapshot.reset(); - _cur_analog_snapshot.reset(); - } + _cur_logic_snapshot->set_last_ended(true); + _cur_dso_snapshot->set_last_ended(true); + _cur_analog_snapshot->set_last_ended(true); #ifdef ENABLE_DECODE - for (vector< boost::shared_ptr >::iterator i = - _decode_traces.begin(); - i != _decode_traces.end(); - i++) - (*i)->decoder()->stop_decode(); + BOOST_FOREACH(const boost::shared_ptr d, _decode_traces) + d->frame_ended(); #endif + } frame_ended(); break; } @@ -1163,9 +1313,6 @@ void SigSession::hotplug_proc(boost::function error_handle if (_hot_detach) { qDebug("DreamSourceLab hardware detached!"); device_detach(); - _logic_data.reset(); - _dso_data.reset(); - _analog_data.reset(); _hot_detach = false; } boost::this_thread::sleep(boost::posix_time::millisec(100)); @@ -1286,6 +1433,13 @@ bool SigSession::add_decoder(srd_decoder *const dec) boost::shared_ptr d( new view::DecodeTrace(*this, decoder_stack, _decode_traces.size())); + // set view early for decode start/end region setting + BOOST_FOREACH(const boost::shared_ptr s, _signals) { + if (s->get_view()) { + d->set_view(s->get_view()); + break; + } + } if (d->create_popup()) { _decode_traces.push_back(d); ret = true; @@ -1308,7 +1462,7 @@ bool SigSession::add_decoder(srd_decoder *const dec) vector< boost::shared_ptr > SigSession::get_decode_signals() const { - lock_guard lock(_signals_mutex); + //lock_guard lock(_signals_mutex); return _decode_traces; } @@ -1383,6 +1537,71 @@ void SigSession::rst_decoder(view::DecodeTrace *signal) return; } } + +pv::data::DecoderModel* SigSession::get_decoder_model() const +{ + return _decoder_model; +} #endif +void SigSession::mathTraces_rebuild() +{ + bool has_dso_signal = false; + BOOST_FOREACH(const boost::shared_ptr s, _signals) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + has_dso_signal = true; + // check already have + std::vector< boost::shared_ptr >::iterator iter = _math_traces.begin(); + for(unsigned int i = 0; i < _math_traces.size(); i++, iter++) + if ((*iter)->get_index() == dsoSig->get_index()) + break; + // if not, rebuild + if (iter == _math_traces.end()) { + boost::shared_ptr math_stack( + new data::MathStack(*this, dsoSig->get_index())); + boost::shared_ptr math_trace( + new view::MathTrace(*this, math_stack, dsoSig->get_index())); + _math_traces.push_back(math_trace); + } + } + } + + if (!has_dso_signal) + _math_traces.clear(); + + signals_changed(); +} + +vector< boost::shared_ptr > SigSession::get_math_signals() +{ + //lock_guard lock(_signals_mutex); + return _math_traces; +} + +QDateTime SigSession::get_trigger_time() const +{ + return _trigger_time; +} + +uint64_t SigSession::get_trigger_pos() const +{ + return _trigger_pos; +} + +bool SigSession::trigd() const +{ + return _trigger_flag; +} + +void SigSession::nodata_timeout() +{ + GVariant *gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_TRIGGER_SOURCE); + if (gvar == NULL) + return; + if (g_variant_get_byte(gvar) != DSO_TRIGGER_AUTO) { + show_wait_trigger(); + } +} + } // namespace pv diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index 23ad6a90..59cf3327 100644 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -67,6 +67,7 @@ class Logic; class LogicSnapshot; class Group; class GroupSnapshot; +class DecoderModel; } namespace device { @@ -77,6 +78,7 @@ namespace view { class Signal; class GroupSignal; class DecodeTrace; +class MathTrace; } namespace decoder { @@ -90,10 +92,13 @@ class SigSession : public QObject private: static constexpr float Oversampling = 2.0f; - static const int ViewTime = 800; static const int RefreshTime = 500; bool saveFileThreadRunning = false; +public: + static const int ViewTime = 50; + static const int WaitShowTime = 500; + public: enum capture_state { Init, @@ -117,7 +122,7 @@ public: void set_file(QString name) throw(QString); - void save_file(const QString name, int type); + void save_file(const QString name, QWidget* parent, int type); void set_default_device(boost::function error_handler); void export_file(const QString name, QWidget* parent, const QString ext); @@ -126,10 +131,17 @@ public: capture_state get_capture_state() const; + uint64_t cur_samplerate() const; + uint64_t cur_samplelimits() const; + double cur_sampletime() const; + void set_cur_samplerate(uint64_t samplerate); + void set_cur_samplelimits(uint64_t samplelimits); + QDateTime get_trigger_time() const; + uint64_t get_trigger_pos() const; + void start_capture(bool instant, boost::function error_handler); - - void stop_capture(); + void capture_init(); std::set< boost::shared_ptr > get_data() const; @@ -154,6 +166,11 @@ public: void rst_decoder(view::DecodeTrace *signal); + pv::data::DecoderModel* get_decoder_model() const; + + std::vector< boost::shared_ptr > + get_math_signals(); + #endif void init_signals(); @@ -162,7 +179,7 @@ public: void del_group(); - void* get_buf(int& unit_size, uint64_t& length); + const void* get_buf(int& unit_size, uint64_t& length); void start_hotplug_proc(boost::function error_handler); void stop_hotplug_proc(); @@ -174,12 +191,13 @@ public: bool get_instant(); bool get_data_lock(); + void mathTraces_rebuild(); + + bool trigd() const; private: void set_capture_state(capture_state state); - void read_sample_rate(const sr_dev_inst *const sdi); - private: /** * Attempts to autodetect the format. Failing that @@ -225,16 +243,20 @@ private: */ boost::shared_ptr _dev_inst; - mutable boost::mutex _sampling_mutex; + mutable boost::mutex _sampling_mutex; capture_state _capture_state; bool _instant; + uint64_t _cur_samplerate; + uint64_t _cur_samplelimits; - mutable boost::mutex _signals_mutex; + //mutable boost::mutex _signals_mutex; std::vector< boost::shared_ptr > _signals; std::vector< boost::shared_ptr > _group_traces; #ifdef ENABLE_DECODE std::vector< boost::shared_ptr > _decode_traces; + pv::data::DecoderModel *_decoder_model; #endif + std::vector< boost::shared_ptr > _math_traces; mutable boost::mutex _data_mutex; boost::shared_ptr _logic_data; @@ -255,8 +277,18 @@ private: bool _hot_detach; QTimer _view_timer; + int _noData_cnt; QTimer _refresh_timer; bool _data_lock; + bool _data_updated; + + #ifdef TEST_MODE + QTimer _test_timer; + #endif + + QDateTime _trigger_time; + uint64_t _trigger_pos; + bool _trigger_flag; signals: void capture_state_changed(int state); @@ -276,6 +308,8 @@ signals: void receive_trigger(quint64 trigger_pos); + void receive_header(); + void dso_ch_changed(uint16_t num); void frame_began(); @@ -291,13 +325,26 @@ signals: void zero_adj(); void progressSaveFileValueChanged(int percent); + void decode_done(); + + void show_region(uint64_t start, uint64_t end); + + void hardware_connect_failed(); + + void show_wait_trigger(); + + void on_mode_change(); + public slots: void reload(); void refresh(int holdtime); + void stop_capture(); private slots: void cancelSaveFile(); void data_unlock(); + void check_update(); + void nodata_timeout(); private: // TODO: This should not be necessary. Multiple concurrent diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index 6d2ea359..baac25c4 100644 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -25,6 +25,8 @@ #include #include +#include + using boost::dynamic_pointer_cast; using boost::mutex; using boost::shared_ptr; @@ -58,21 +60,24 @@ StoreSession::~StoreSession() pair StoreSession::progress() const { - lock_guard lock(_mutex); + //lock_guard lock(_mutex); return make_pair(_units_stored, _unit_count); } const QString& StoreSession::error() const { - lock_guard lock(_mutex); + //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()); + set< boost::shared_ptr > data_set; + BOOST_FOREACH(const boost::shared_ptr sig, sigs) { + assert(sig); + data_set.insert(sig->data()); + } // Check we have logic data if (data_set.empty() || sigs.empty()) { @@ -158,7 +163,7 @@ void StoreSession::store_proc(shared_ptr snapshot) assert(unit_size != 0); { - lock_guard lock(_mutex); + //lock_guard lock(_mutex); _unit_count = snapshot->get_sample_count(); } @@ -183,7 +188,7 @@ void StoreSession::store_proc(shared_ptr snapshot) start_sample = end_sample; { - lock_guard lock(_mutex); + //lock_guard lock(_mutex); _units_stored = start_sample; } } diff --git a/DSView/pv/storesession.h b/DSView/pv/storesession.h index 63f8003e..0493ff84 100644 --- a/DSView/pv/storesession.h +++ b/DSView/pv/storesession.h @@ -72,7 +72,7 @@ private: boost::thread _thread; - mutable boost::mutex _mutex; + //mutable boost::mutex _mutex; uint64_t _units_stored; uint64_t _unit_count; QString _error; diff --git a/DSView/pv/toolbars/filebar.cpp b/DSView/pv/toolbars/filebar.cpp index 5562db7a..e99929fd 100644 --- a/DSView/pv/toolbars/filebar.cpp +++ b/DSView/pv/toolbars/filebar.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -26,12 +25,12 @@ #include #include -#include #include #include #include "filebar.h" #include "../device/devinst.h" +#include "../dialogs/dsmessagebox.h" #include @@ -70,7 +69,7 @@ FileBar::FileBar(SigSession &session, QWidget *parent) : _action_default->setObjectName(QString::fromUtf8("actionDefault")); connect(_action_default, SIGNAL(triggered()), this, SLOT(on_actionDefault_triggered())); - _menu_session = new QMenu(tr("Session"), parent); + _menu_session = new QMenu(tr("Settings"), parent); _menu_session->setIcon(QIcon::fromTheme("file", QIcon(":/icons/gear.png"))); _menu_session->setObjectName(QString::fromUtf8("menuSession")); @@ -96,7 +95,7 @@ FileBar::FileBar(SigSession &session, QWidget *parent) : _action_export = new QAction(this); _action_export->setText(QApplication::translate("File", "&Export...", 0)); - _action_export->setIcon(QIcon::fromTheme("file",QIcon(":/icons/instant.png"))); + _action_export->setIcon(QIcon::fromTheme("file",QIcon(":/icons/export.png"))); _action_export->setObjectName(QString::fromUtf8("actionExport")); connect(_action_export, SIGNAL(triggered()), this, SLOT(on_actionExport_triggered())); @@ -110,11 +109,7 @@ FileBar::FileBar(SigSession &session, QWidget *parent) : connect(_action_capture, SIGNAL(triggered()), this, SLOT(on_actionCapture_triggered())); _file_button.setPopupMode(QToolButton::InstantPopup); -#ifdef LANGUAGE_ZH_CN - _file_button.setIcon(QIcon(":/icons/file_cn.png")); -#else _file_button.setIcon(QIcon(":/icons/file.png")); -#endif _menu = new QMenu(this); _menu->addMenu(_menu_session); @@ -124,16 +119,24 @@ FileBar::FileBar(SigSession &session, QWidget *parent) : _menu->addAction(_action_capture); _file_button.setMenu(_menu); addWidget(&_file_button); + + _screenshot_timer.setSingleShot(true); + connect(&_screenshot_timer, SIGNAL(timeout()), this, SIGNAL(on_screenShot())); } void FileBar::on_actionOpen_triggered() { + const QString DIR_KEY("OpenPath"); + QSettings settings; // Show the dialog const QString file_name = QFileDialog::getOpenFileName( - this, tr("Open File"), "", tr( + this, tr("Open File"), settings.value(DIR_KEY).toString(), tr( "DSView Data (*.dsl);;All Files (*.*)")); - if (!file_name.isEmpty()) + if (!file_name.isEmpty()) { + QDir CurrentDir; + settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(file_name)); load_file(file_name); + } } void FileBar::session_error( @@ -147,24 +150,26 @@ void FileBar::session_error( void FileBar::show_session_error( const QString text, const QString info_text) { - QMessageBox msg(this); - msg.setText(text); - msg.setInformativeText(info_text); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(text); + msg.mBox()->setInformativeText(info_text); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); } void FileBar::on_actionExport_triggered(){ + const QString DIR_KEY("ExportPath"); + QSettings settings; int unit_size; uint64_t length; - void* buf = _session.get_buf(unit_size, length); + const void* buf = _session.get_buf(unit_size, length); if (!buf) { - QMessageBox msg(this); - msg.setText(tr("Data Export")); - msg.setInformativeText(tr("No Data to Save!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Data Export")); + msg.mBox()->setInformativeText(tr("No Data to Save!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); } else { QList supportedFormats = _session.getSuportedExportFormats(); @@ -175,13 +180,15 @@ void FileBar::on_actionExport_triggered(){ filter.append(";;"); } QString file_name = QFileDialog::getSaveFileName( - this, tr("Export Data"), "",filter,&filter); + this, tr("Export Data"), settings.value(DIR_KEY).toString(),filter,&filter); if (!file_name.isEmpty()) { QFileInfo f(file_name); QStringList list = filter.split('.').last().split(')'); QString ext = list.first(); if(f.suffix().compare(ext)) file_name+=tr(".")+ext; + QDir CurrentDir; + settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(file_name)); _session.export_file(file_name, this, ext); } } @@ -189,27 +196,31 @@ void FileBar::on_actionExport_triggered(){ void FileBar::on_actionSave_triggered() { + const QString DIR_KEY("SavePath"); + QSettings settings; //save(); int unit_size; uint64_t length; - void* buf = _session.get_buf(unit_size, length); + const void* buf = _session.get_buf(unit_size, length); if (!buf) { - QMessageBox msg(this); - msg.setText(tr("File Save")); - msg.setInformativeText(tr("No Data to Save!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("File Save")); + msg.mBox()->setInformativeText(tr("No Data to Save!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); } else { QString file_name = QFileDialog::getSaveFileName( - this, tr("Save File"), "", + this, tr("Save File"), settings.value(DIR_KEY).toString(), tr("DSView Data (*.dsl)")); if (!file_name.isEmpty()) { QFileInfo f(file_name); if(f.suffix().compare("dsl")) file_name.append(tr(".dsl")); - _session.save_file(file_name, _session.get_device()->dev_inst()->mode); + QDir CurrentDir; + settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(file_name)); + _session.save_file(file_name, this, _session.get_device()->dev_inst()->mode); } } } @@ -217,28 +228,33 @@ void FileBar::on_actionSave_triggered() void FileBar::on_actionLoad_triggered() { + const QString DIR_KEY("SessionLoadPath"); + QSettings settings; // Show the dialog const QString file_name = QFileDialog::getOpenFileName( - this, tr("Open Session"), "", tr( + this, tr("Open Session"), settings.value(DIR_KEY).toString(), tr( "DSView Session (*.dsc)")); - if (!file_name.isEmpty()) + if (!file_name.isEmpty()) { + QDir CurrentDir; + settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(file_name)); load_session(file_name); + } } void FileBar::on_actionDefault_triggered() { - QDir dir(QCoreApplication::applicationDirPath()); - if (!dir.cd("res")) { - QMessageBox msg(this); - msg.setText(tr("Session Load")); - msg.setInformativeText(tr("Cannot find default session file for this device!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + QDir dir(DS_RES_PATH); + if (!dir.exists()) { + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Session Load")); + msg.mBox()->setInformativeText(tr("Cannot find default session file for this device!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); return; } - QString driver_name = _session.get_device()->dev_inst()->driver->name; + QString driver_name = _session.get_device()->name(); QString mode_name = QString::number(_session.get_device()->dev_inst()->mode); QString file_name = dir.absolutePath() + "/" + driver_name + mode_name + ".def.dsc"; if (!file_name.isEmpty()) @@ -247,33 +263,38 @@ void FileBar::on_actionDefault_triggered() void FileBar::on_actionStore_triggered() { - QString default_name = _session.get_device()->dev_inst()->driver->name; + const QString DIR_KEY("SessionStorePath"); + QSettings settings; QString file_name = QFileDialog::getSaveFileName( - this, tr("Save Session"), default_name, + this, tr("Save Session"), settings.value(DIR_KEY).toString(), tr("DSView Session (*.dsc)")); if (!file_name.isEmpty()) { QFileInfo f(file_name); if(f.suffix().compare("dsc")) file_name.append(tr(".dsc")); + QDir CurrentDir; + settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(file_name)); store_session(file_name); } } void FileBar::on_actionCapture_triggered() { - on_screenShot(); + _file_button.close(); + QCoreApplication::sendPostedEvents(); + _screenshot_timer.start(100); } void FileBar::enable_toggle(bool enable) { _file_button.setDisabled(!enable); -#ifdef LANGUAGE_ZH_CN - _file_button.setIcon(enable ? QIcon(":/icons/file_cn.png") : - QIcon(":/icons/file_dis_cn.png")); -#else _file_button.setIcon(enable ? QIcon(":/icons/file.png") : QIcon(":/icons/file_dis.png")); -#endif +} + +void FileBar::set_settings_en(bool enable) +{ + _menu_session->setDisabled(!enable); } } // namespace toolbars diff --git a/DSView/pv/toolbars/filebar.h b/DSView/pv/toolbars/filebar.h index 6f4c2c40..ea99ac66 100644 --- a/DSView/pv/toolbars/filebar.h +++ b/DSView/pv/toolbars/filebar.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -43,6 +42,8 @@ public: void enable_toggle(bool enable); + void set_settings_en(bool enable); + private: void session_error( @@ -84,6 +85,8 @@ private: QAction *_action_export; QAction *_action_capture; + QTimer _screenshot_timer; + }; } // namespace toolbars diff --git a/DSView/pv/toolbars/logobar.cpp b/DSView/pv/toolbars/logobar.cpp index 00063406..91d52539 100644 --- a/DSView/pv/toolbars/logobar.cpp +++ b/DSView/pv/toolbars/logobar.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -25,7 +24,6 @@ #include #include -#include #include #include #include @@ -33,6 +31,7 @@ #include "logobar.h" #include "../dialogs/about.h" +#include "../dialogs/dsmessagebox.h" namespace pv { namespace toolbars { @@ -94,11 +93,11 @@ void LogoBar::session_error( void LogoBar::show_session_error( const QString text, const QString info_text) { - QMessageBox msg(this); - msg.setText(text); - msg.setInformativeText(info_text); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(text); + msg.mBox()->setInformativeText(info_text); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); } diff --git a/DSView/pv/toolbars/logobar.h b/DSView/pv/toolbars/logobar.h index 7e8ac9bc..ad486b9e 100644 --- a/DSView/pv/toolbars/logobar.h +++ b/DSView/pv/toolbars/logobar.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index 85b45603..06b324c7 100644 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -32,7 +31,7 @@ #include #include #include -#include +#include #include "samplingbar.h" @@ -40,7 +39,7 @@ #include "../device/devinst.h" #include "../dialogs/deviceoptions.h" #include "../dialogs/waitingdialog.h" -#include "../dialogs/streamoptions.h" +#include "../dialogs/dsmessagebox.h" #include "../view/dsosignal.h" using namespace boost; @@ -88,56 +87,39 @@ SamplingBar::SamplingBar(SigSession &session, QWidget *parent) : _sample_rate(this), _updating_sample_rate(false), _updating_sample_count(false), - #ifdef LANGUAGE_ZH_CN - _icon_stop(":/icons/stop_cn.png"), - _icon_start(":/icons/start_cn.png"), - _icon_instant(":/icons/instant_cn.png"), - _icon_start_dis(":/icons/start_dis_cn.png"), - _icon_instant_dis(":/icons/instant_dis_cn.png"), - #else _icon_stop(":/icons/stop.png"), _icon_start(":/icons/start.png"), _icon_instant(":/icons/instant.png"), _icon_start_dis(":/icons/start_dis.png"), _icon_instant_dis(":/icons/instant_dis.png"), - #endif _run_stop_button(this), _instant_button(this), _instant(false) { setMovable(false); + layout()->setMargin(0); + layout()->setSpacing(0); 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())); + this, SLOT(on_run_stop()), Qt::DirectConnection); connect(&_instant_button, SIGNAL(clicked()), this, SLOT(on_instant_stop())); -#ifdef LANGUAGE_ZH_CN - _configure_button.setIcon(QIcon::fromTheme("configure", - QIcon(":/icons/params_cn.png"))); -#else _configure_button.setIcon(QIcon::fromTheme("configure", QIcon(":/icons/params.png"))); -#endif + _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"); -// _sample_count.addItem(QString(text), -// qVariantFromValue(l)); -// g_free(text); - -// if (l == DefaultRecordLength) -// _sample_count.setCurrentIndex(i); -// } + _device_selector.setSizeAdjustPolicy(QComboBox::AdjustToContents); + _sample_rate.setSizeAdjustPolicy(QComboBox::AdjustToContents); _sample_count.setSizeAdjustPolicy(QComboBox::AdjustToContents); + _device_selector.setMaximumWidth(ComboBoxMaxWidth); + set_sampling(false); connect(&_sample_count, SIGNAL(currentIndexChanged(int)), this, SLOT(on_samplecount_sel(int))); @@ -148,14 +130,16 @@ SamplingBar::SamplingBar(SigSession &session, QWidget *parent) : connect(&_sample_rate, SIGNAL(currentIndexChanged(int)), this, SLOT(on_samplerate_sel(int))); - addWidget(new QLabel(tr(" "))); + QWidget *leftMargin = new QWidget(this); + leftMargin->setFixedWidth(4); + addWidget(leftMargin); addWidget(&_device_selector); addWidget(&_configure_button); addWidget(&_sample_count); addWidget(new QLabel(tr(" @ "))); addWidget(&_sample_rate); - addWidget(&_run_stop_button); - addWidget(&_instant_button); + _run_stop_action = addWidget(&_run_stop_button); + _instant_action = addWidget(&_instant_button); } void SamplingBar::set_device_list( @@ -184,6 +168,9 @@ void SamplingBar::set_device_list( _device_selector.addItem(title, qVariantFromValue((void*)id)); } + int width = _device_selector.sizeHint().width(); + _device_selector.setFixedWidth(min(width+15, _device_selector.maximumWidth())); + _device_selector.view()->setMinimumWidth(width+30); // The selected device should have been in the list assert(selected_index != -1); @@ -191,7 +178,6 @@ void SamplingBar::set_device_list( update_sample_rate_selector(); update_sample_count_selector(); - update_scale(); _updating_device_selector = false; } @@ -216,6 +202,8 @@ shared_ptr SamplingBar::get_selected_device() const void SamplingBar::on_configure() { + hide_calibration(); + int ret; shared_ptr dev_inst = get_selected_device(); assert(dev_inst); @@ -227,30 +215,44 @@ void SamplingBar::on_configure() update_sample_count_selector(); update_sample_rate_selector(); commit_sample_rate(); - } - GVariant* gvar = dev_inst->get_config(NULL, NULL, SR_CONF_ZERO); - if (gvar != NULL) { - bool zero = g_variant_get_boolean(gvar); - g_variant_unref(gvar); - if (zero) - zero_adj(); - } + GVariant* gvar; + if (dev_inst->dev_inst()->mode == DSO) { + gvar = dev_inst->get_config(NULL, NULL, SR_CONF_ZERO); + if (gvar != NULL) { + bool zero = g_variant_get_boolean(gvar); + g_variant_unref(gvar); + if (zero) { + zero_adj(); + return; + } + } - gvar = dev_inst->get_config(NULL, NULL, SR_CONF_TEST); - if (gvar != NULL) { - bool test = g_variant_get_boolean(gvar); - g_variant_unref(gvar); - if (test) { - update_sample_count_selector_value(); - update_sample_rate_selector_value(); - #ifndef TEST_MODE - _sample_count.setDisabled(true); - _sample_rate.setDisabled(true); - #endif - } else if (dev_inst->dev_inst()->mode != DSO) { - _sample_count.setDisabled(false); - _sample_rate.setDisabled(false); + gvar = dev_inst->get_config(NULL, NULL, SR_CONF_CALI); + if (gvar != NULL) { + bool cali = g_variant_get_boolean(gvar); + g_variant_unref(gvar); + if (cali) { + show_calibration(); + return; + } + } + } + gvar = dev_inst->get_config(NULL, NULL, SR_CONF_TEST); + if (gvar != NULL) { + bool test = g_variant_get_boolean(gvar); + g_variant_unref(gvar); + if (test) { + update_sample_count_selector_value(); + update_sample_rate_selector_value(); + #ifndef TEST_MODE + _sample_count.setDisabled(true); + _sample_rate.setDisabled(true); + #endif + } else if (dev_inst->dev_inst()->mode != DSO) { + _sample_count.setDisabled(false); + _sample_rate.setDisabled(false); + } } } } @@ -266,9 +268,16 @@ void SamplingBar::zero_adj() run_stop(); pv::dialogs::WaitingDialog wait(this, get_selected_device()); - wait.start(); + if (wait.start() ==QDialog::Rejected) { + BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) + { + if (dsoSig = dynamic_pointer_cast(s)) + dsoSig->commit_settings(); + } + } - run_stop(); + if (_session.get_capture_state() == pv::SigSession::Running) + run_stop(); } uint64_t SamplingBar::get_record_length() const @@ -324,36 +333,18 @@ void SamplingBar::set_sampling(bool sampling) } if (!sampling) { - g_usleep(100000); - _run_stop_button.setEnabled(true); - _instant_button.setEnabled(true); + enable_run_stop(true); + enable_instant(true); } else { -// bool running = false; -// boost::shared_ptr dev_inst = get_selected_device(); -// assert(dev_inst); -// while (!running) { -// GVariant* gvar = dev_inst->get_config(NULL, NULL, SR_CONF_STATUS); -// if (gvar != NULL) { -// running = g_variant_get_boolean(gvar); -// g_variant_unref(gvar); -// } -// g_usleep(10000); -// } - g_usleep(100000); if (_instant) - _instant_button.setEnabled(true); + enable_instant(true); else - _run_stop_button.setEnabled(true); + enable_run_stop(true); } _configure_button.setEnabled(!sampling); -#ifdef LANGUAGE_ZH_CN - _configure_button.setIcon(sampling ? QIcon(":/icons/params_dis_cn.png") : - QIcon(":/icons/params_cn.png")); -#else _configure_button.setIcon(sampling ? QIcon(":/icons/params_dis.png") : QIcon(":/icons/params.png")); -#endif } void SamplingBar::set_sample_rate(uint64_t sample_rate) @@ -428,6 +419,10 @@ void SamplingBar::update_sample_rate_selector() _sample_rate.show(); g_variant_unref(gvar_list); } + + _sample_rate.setMinimumWidth(_sample_rate.sizeHint().width()+15); + _sample_rate.view()->setMinimumWidth(_sample_rate.sizeHint().width()+30); + _updating_sample_rate = false; g_variant_unref(gvar_dict); @@ -454,14 +449,13 @@ void SamplingBar::update_sample_rate_selector_value() break; } } - update_scale(); + _updating_sample_rate = false; } void SamplingBar::commit_sample_rate() { uint64_t sample_rate = 0; - uint64_t last_sample_rate = 0; if (_updating_sample_rate) return; @@ -477,16 +471,9 @@ void SamplingBar::commit_sample_rate() if (sample_rate == 0) return; - // Get last samplerate - last_sample_rate = get_selected_device()->get_sample_rate(); - - if (last_sample_rate != sample_rate) { - // Set the samplerate - get_selected_device()->set_config(NULL, NULL, - SR_CONF_SAMPLERATE, - g_variant_new_uint64(sample_rate)); - update_scale(); - } + get_selected_device()->set_config(NULL, NULL, + SR_CONF_SAMPLERATE, + g_variant_new_uint64(sample_rate)); _updating_sample_rate = false; } @@ -503,7 +490,7 @@ void SamplingBar::on_samplecount_sel(int index) boost::shared_ptr _devInst = get_selected_device(); assert(_devInst); - if (strcmp(_devInst->dev_inst()->driver->name, "DSLogic") == 0 && _devInst->dev_inst()->mode != DSO) { + if (_devInst->name() == "DSLogic" && _devInst->dev_inst()->mode != DSO) { // Set the sample count _devInst->set_config(NULL, NULL, @@ -511,7 +498,6 @@ void SamplingBar::on_samplecount_sel(int index) g_variant_new_uint64(sample_count)); sample_count_changed(); - update_scale(); } } @@ -529,13 +515,11 @@ void SamplingBar::on_samplerate_sel(int index) // Get last samplerate //last_sample_rate = get_selected_device()->get_sample_rate(); - if (strcmp(_devInst->dev_inst()->driver->name, "DSLogic") == 0 && _devInst->dev_inst()->mode != DSO) { + if (_devInst->name() == "DSLogic" && _devInst->dev_inst()->mode != DSO) { // Set the samplerate get_selected_device()->set_config(NULL, NULL, SR_CONF_SAMPLERATE, g_variant_new_uint64(sample_rate)); - - update_scale(); } } @@ -601,6 +585,8 @@ void SamplingBar::update_sample_count_selector() _sample_count.show(); g_variant_unref(gvar_list); } + _sample_count.setMinimumWidth(_sample_count.sizeHint().width()+15); + _sample_count.view()->setMinimumWidth(_sample_count.sizeHint().width()+30); _updating_sample_count = false; g_variant_unref(gvar_dict); @@ -625,9 +611,10 @@ void SamplingBar::update_sample_count_selector_value() i).value()) _sample_count.setCurrentIndex(i); + if (samplecount != _sample_count.itemData(_sample_count.currentIndex()).value()) { + sample_count_changed(); + } _updating_sample_count = false; - sample_count_changed(); - update_scale(); } void SamplingBar::commit_sample_count() @@ -658,7 +645,6 @@ void SamplingBar::commit_sample_count() get_selected_device()->set_config(NULL, NULL, SR_CONF_LIMIT_SAMPLES, g_variant_new_uint64(sample_count)); - update_scale(); } _updating_sample_count = false; @@ -680,13 +666,20 @@ void SamplingBar::on_run_stop() bool zero = g_variant_get_boolean(gvar); g_variant_unref(gvar); if (zero) { - QMessageBox msg(this); - msg.setText(tr("Zero Adjustment")); - msg.setInformativeText(tr("Please adjust zero skew and save the result!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); - msg.exec(); - zero_adj(); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Zero Adjustment")); + msg.mBox()->setInformativeText(tr("Please adjust zero skew and save the result!")); + //msg.setStandardButtons(QMessageBox::Ok); + msg.mBox()->addButton(tr("Ok"), QMessageBox::AcceptRole); + msg.mBox()->addButton(tr("Skip"), QMessageBox::RejectRole); + msg.mBox()->setIcon(QMessageBox::Warning); + if (msg.exec()) { + zero_adj(); + } else { + dev_inst->set_config(NULL, NULL, SR_CONF_ZERO, g_variant_new_boolean(false)); + enable_run_stop(true); + enable_instant(true); + } return; } } @@ -710,16 +703,20 @@ void SamplingBar::on_instant_stop() bool zero = g_variant_get_boolean(gvar); g_variant_unref(gvar); if (zero) { - QMessageBox msg(this); - msg.setText(tr("Zero Adjustment")); - if(strcmp(dev_inst->dev_inst()->driver->name, "DSLogic") == 0) - msg.setInformativeText(tr("Please adjust zero skew and save the result!\nPlease left both of channels unconnect for zero adjustment!")); - else - msg.setInformativeText(tr("Please adjust zero skew and save the result!")); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); - msg.exec(); - zero_adj(); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Zero Adjustment")); + msg.mBox()->setInformativeText(tr("Zero adjustment program will be started. Please keep all channels out of singal input. It can take a while!")); + //msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->addButton(tr("Ok"), QMessageBox::AcceptRole); + msg.mBox()->addButton(tr("Skip"), QMessageBox::RejectRole); + msg.mBox()->setIcon(QMessageBox::Warning); + if (msg.exec()) { + zero_adj(); + } else { + dev_inst->set_config(NULL, NULL, SR_CONF_ZERO, g_variant_new_boolean(false)); + enable_run_stop(true); + enable_instant(true); + } return; } } @@ -732,6 +729,8 @@ void SamplingBar::on_device_selected() if (_updating_device_selector) return; + _session.stop_capture(); + const shared_ptr dev_inst = get_selected_device(); if (!dev_inst) return; @@ -774,13 +773,37 @@ void SamplingBar::enable_instant(bool enable) void SamplingBar::show_session_error( const QString text, const QString info_text) { - QMessageBox msg(this); - msg.setText(text); - msg.setInformativeText(info_text); - msg.setStandardButtons(QMessageBox::Ok); - msg.setIcon(QMessageBox::Warning); + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(text); + msg.mBox()->setInformativeText(info_text); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); } +void SamplingBar::reload() +{ + if (_session.get_device()->dev_inst()->mode == LOGIC) { + _icon_instant = QIcon(":/icons/instant.png"); + _icon_instant_dis = QIcon(":/icons/instant_dis.png"); + _instant_button.setIcon(_icon_instant); + _run_stop_action->setVisible(true); + _instant_action->setVisible(true); + enable_toggle(true); + } else if (_session.get_device()->dev_inst()->mode == ANALOG) { + _run_stop_action->setVisible(true); + _instant_action->setVisible(false); + enable_toggle(true); + } else if (_session.get_device()->dev_inst()->mode == DSO) { + _icon_instant = QIcon(":/icons/single.png"); + _icon_instant_dis = QIcon(":/icons/single_dis.png"); + _instant_button.setIcon(_icon_instant); + _run_stop_action->setVisible(true); + _instant_action->setVisible(true); + enable_toggle(false); + } + update(); +} + } // namespace toolbars } // namespace pv diff --git a/DSView/pv/toolbars/samplingbar.h b/DSView/pv/toolbars/samplingbar.h index 4055a1af..14e9aa94 100644 --- a/DSView/pv/toolbars/samplingbar.h +++ b/DSView/pv/toolbars/samplingbar.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -52,6 +51,7 @@ class DevInst; namespace dialogs { class deviceoptions; +class Calibration; } namespace toolbars { @@ -63,6 +63,7 @@ class SamplingBar : public QToolBar private: static const uint64_t RecordLengths[19]; static const uint64_t DefaultRecordLength; + static const int ComboBoxMaxWidth = 200; public: SamplingBar(SigSession &session, QWidget *parent); @@ -95,8 +96,9 @@ signals: void instant_stop(); void device_selected(); void device_updated(); - void update_scale(); void sample_count_changed(); + void show_calibration(); + void hide_calibration(); private: void update_sample_rate_selector(); @@ -120,6 +122,7 @@ private slots: public slots: void on_configure(); void zero_adj(); + void reload(); private: SigSession &_session; @@ -145,6 +148,8 @@ private: QIcon _icon_instant_dis; QToolButton _run_stop_button; QToolButton _instant_button; + QAction* _run_stop_action; + QAction* _instant_action; bool _instant; }; diff --git a/DSView/pv/toolbars/titlebar.cpp b/DSView/pv/toolbars/titlebar.cpp new file mode 100644 index 00000000..26237fcf --- /dev/null +++ b/DSView/pv/toolbars/titlebar.cpp @@ -0,0 +1,189 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 "titlebar.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN +#pragma comment(lib, "user32.lib") +#include +#endif + +namespace pv { +namespace toolbars { + +TitleBar::TitleBar(bool top, QWidget *parent, bool hasClose) : + QWidget(parent), + _moving(false), + _isTop(top), + _hasClose(hasClose) +{ + setObjectName("TitleBar"); + setFixedHeight(28); + + _title = new QLabel(this); + QHBoxLayout *hbox = new QHBoxLayout(this); + hbox->addWidget(_title); + + if (_isTop) { + _minimizeButton = new QToolButton(this); + _minimizeButton->setObjectName("MinimizeButton"); + _minimizeButton->setIcon(QIcon::fromTheme("titlebar", + QIcon(":/icons/minimize.png"))); + _maximizeButton = new QToolButton(this); + _maximizeButton->setObjectName("MaximizeButton"); + _maximizeButton->setIcon(QIcon::fromTheme("titlebar", + QIcon(":/icons/maximize.png"))); + + hbox->addWidget(_minimizeButton); + hbox->addWidget(_maximizeButton); + + connect(this, SIGNAL( normalShow() ), parent, SLOT(showNormal() ) ); + connect(this, SIGNAL( maximizedShow() ), parent, SLOT(showMaximized() ) ); + connect(_minimizeButton, SIGNAL( clicked() ), parent, SLOT(showMinimized() ) ); + connect(_maximizeButton, SIGNAL( clicked() ), this, SLOT(showMaxRestore() ) ); + } + + if (_isTop || _hasClose) { + _closeButton= new QToolButton(this); + _closeButton->setObjectName("CloseButton"); + _closeButton->setIcon(QIcon::fromTheme("titlebar", + QIcon(":/icons/close.png"))); + hbox->addWidget(_closeButton); + connect(_closeButton, SIGNAL( clicked() ), parent, SLOT(close() ) ); + } + + hbox->insertStretch(0, 500); + hbox->insertStretch(2, 500); + hbox->setMargin(0); + hbox->setSpacing(0); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); +} + +void TitleBar::paintEvent(QPaintEvent *) +{ + QPainter p(this); + p.setRenderHint(QPainter::Antialiasing, true); + p.setPen(QColor(48, 47, 47, 255)); + p.setBrush(QColor(48, 47, 47, 255)); + p.drawRect(rect()); + + const int xgap = 2.5; + const int xstart = 10; + p.setPen(QPen(QColor(213, 15, 37, 255), 2, Qt::SolidLine)); + p.drawLine(xstart + xgap*0, height()*0.50, xstart + xgap*0, height()*0.66); + p.drawLine(xstart + xgap*18, height()*0.34, xstart + xgap*18, height()*0.50); + + p.setPen(QPen(QColor(238, 178, 17, 255), 2, Qt::SolidLine)); + p.drawLine(xstart + xgap*2, height()*0.50, xstart + xgap*2, height()*0.83); + p.drawLine(xstart + xgap*16, height()*0.17, xstart + xgap*16, height()*0.50); + + p.setPen(QPen(QColor(17, 133, 209, 255), 2, Qt::SolidLine)); + p.drawLine(xstart + xgap*4, height()*0.50, xstart + xgap*4, height()*1.00); + p.drawLine(xstart + xgap*14, height()*0.00, xstart + xgap*14, height()*0.50); + + p.setPen(QPen(QColor(0, 153, 37, 200), 2, Qt::SolidLine)); + p.drawLine(xstart + xgap*6, height()*0.50, xstart + xgap*6, height()*0.83); + p.drawLine(xstart + xgap*12, height()*0.17, xstart + xgap*12, height()*0.50); + + p.setPen(QPen(QColor(109, 50, 156, 255), 2, Qt::SolidLine)); + p.drawLine(xstart + xgap*8, height()*0.50, xstart + xgap*8, height()*0.66); + p.drawLine(xstart + xgap*10, height()*0.34, xstart + xgap*10, height()*0.50); +} + +void TitleBar::setTitle(QString title) +{ + _title->setText(title); +} + +QPoint TitleBar::get_startPos() const +{ + return _startPos; +} + +QString TitleBar::title() const +{ + return _title->text(); +} + +void TitleBar::showMaxRestore() +{ + if (parentWidget()->isMaximized()) { + _maximizeButton->setIcon(QIcon::fromTheme("titlebar", + QIcon(":/icons/maximize.png"))); + normalShow(); + } else { + _maximizeButton->setIcon(QIcon::fromTheme("titlebar", + QIcon(":/icons/restore.png"))); + maximizedShow(); + } +} + +void TitleBar::setRestoreButton(bool max) +{ + if (!max) { + _maximizeButton->setIcon(QIcon::fromTheme("titlebar", + QIcon(":/icons/maximize.png"))); + } else { + _maximizeButton->setIcon(QIcon::fromTheme("titlebar", + QIcon(":/icons/restore.png"))); + } +} + +void TitleBar::mousePressEvent(QMouseEvent* event) +{ + if(event->button() == Qt::LeftButton && !parentWidget()->isMaximized()) { + _moving = true; + _startPos = mapToParent(event->pos()); + } +} + +void TitleBar::mouseMoveEvent(QMouseEvent *event) +{ + if(_moving && event->buttons().testFlag(Qt::LeftButton)) { + parentWidget()->move(event->globalPos() - _startPos); + } +} + +void TitleBar::mouseReleaseEvent(QMouseEvent* event) +{ + if(event->button() == Qt::LeftButton) { + _moving = false; + } +} + +void TitleBar::mouseDoubleClickEvent(QMouseEvent *event) +{ + if (_isTop) + showMaxRestore(); + QWidget::mouseDoubleClickEvent(event); +} + +} // namespace toolbars +} // namespace pv diff --git a/DSView/pv/toolbars/titlebar.h b/DSView/pv/toolbars/titlebar.h new file mode 100644 index 00000000..6004411a --- /dev/null +++ b/DSView/pv/toolbars/titlebar.h @@ -0,0 +1,71 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 DSVIEW_PV_TOOLBARS_TITLEBAR_H +#define DSVIEW_PV_TOOLBARS_TITLEBAR_H + +#include +class QLabel; +class QToolButton; + +namespace pv { +namespace toolbars { + +class TitleBar : public QWidget +{ + Q_OBJECT + +public: + TitleBar(bool top, QWidget *parent, bool hasClose = false); + void setTitle(QString title); + QPoint get_startPos() const; + QString title() const; + +signals: + void normalShow(); + void maximizedShow(); + +public slots: + void showMaxRestore(); + void setRestoreButton(bool max); + +protected: + void paintEvent(QPaintEvent *); + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); + + QLabel *_title; + QToolButton *_minimizeButton; + QToolButton *_maximizeButton; + QToolButton *_closeButton; + + bool _moving; + bool _isTop; + bool _hasClose; + QPoint _startPos; +}; + +} // namespace toolbars +} // namespace pv + +#endif // DSVIEW_PV_TOOLBARS_TITLEBAR_H diff --git a/DSView/pv/toolbars/trigbar.cpp b/DSView/pv/toolbars/trigbar.cpp index 143f9a30..d6160005 100644 --- a/DSView/pv/toolbars/trigbar.cpp +++ b/DSView/pv/toolbars/trigbar.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -22,19 +21,27 @@ #include "trigbar.h" +#include "../sigsession.h" +#include "../device/devinst.h" +#include "../dialogs/fftoptions.h" + +#include namespace pv { namespace toolbars { -TrigBar::TrigBar(QWidget *parent) : +TrigBar::TrigBar(SigSession &session, QWidget *parent) : QToolBar("Trig Bar", parent), + _session(session), _enable(true), _trig_button(this), _protocol_button(this), _measure_button(this), - _search_button(this) + _search_button(this), + _math_button(this) { setMovable(false); + setContentsMargins(0,0,0,0); connect(&_trig_button, SIGNAL(clicked()), this, SLOT(trigger_clicked())); @@ -45,22 +52,6 @@ TrigBar::TrigBar(QWidget *parent) : connect(&_search_button, SIGNAL(clicked()), this, SLOT(search_clicked())); -#ifdef LANGUAGE_ZH_CN - _trig_button.setIcon(QIcon::fromTheme("trig", - QIcon(":/icons/trigger_cn.png"))); - _trig_button.setCheckable(true); - _protocol_button.setIcon(QIcon::fromTheme("trig", - QIcon(":/icons/protocol_cn.png"))); -#ifdef ENABLE_DECODE - _protocol_button.setCheckable(true); -#endif - _measure_button.setIcon(QIcon::fromTheme("trig", - QIcon(":/icons/measure_cn.png"))); - _measure_button.setCheckable(true); - _search_button.setIcon(QIcon::fromTheme("trig", - QIcon(":/icons/search-bar_cn.png"))); - _search_button.setCheckable(true); -#else _trig_button.setIcon(QIcon::fromTheme("trig", QIcon(":/icons/trigger.png"))); _trig_button.setCheckable(true); @@ -75,12 +66,28 @@ TrigBar::TrigBar(QWidget *parent) : _search_button.setIcon(QIcon::fromTheme("trig", QIcon(":/icons/search-bar.png"))); _search_button.setCheckable(true); -#endif + _math_button.setIcon(QIcon::fromTheme("trig", + QIcon(":/icons/math.png"))); - addWidget(&_trig_button); - addWidget(&_protocol_button); - addWidget(&_measure_button); - addWidget(&_search_button); + _action_fft = new QAction(this); + _action_fft->setText(QApplication::translate( + "Math", "&FFT", 0)); + _action_fft->setIcon(QIcon::fromTheme("Math", + QIcon(":/icons/fft.png"))); + _action_fft->setObjectName(QString::fromUtf8("actionFft")); + connect(_action_fft, SIGNAL(triggered()), this, SLOT(on_actionFft_triggered())); + + _math_menu = new QMenu(this); + _math_menu->setContentsMargins(0,0,0,0); + _math_menu->addAction(_action_fft); + _math_button.setPopupMode(QToolButton::InstantPopup); + _math_button.setMenu(_math_menu); + + _trig_action = addWidget(&_trig_button); + _protocol_action = addWidget(&_protocol_button); + _measure_action = addWidget(&_measure_button); + _search_action = addWidget(&_search_button); + _math_action = addWidget(&_math_button); } void TrigBar::protocol_clicked() @@ -93,6 +100,11 @@ void TrigBar::trigger_clicked() on_trigger(_trig_button.isChecked()); } +void TrigBar::update_trig_btn(bool checked) +{ + _trig_button.setChecked(checked); +} + void TrigBar::measure_clicked() { on_measure(_measure_button.isChecked()); @@ -109,17 +121,8 @@ void TrigBar::enable_toggle(bool enable) _protocol_button.setDisabled(!enable); _measure_button.setDisabled(!enable); _search_button.setDisabled(!enable); + _math_button.setDisabled(!enable); -#ifdef LANGUAGE_ZH_CN - _trig_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/trigger_cn.png")) : - QIcon::fromTheme("trig", QIcon(":/icons/trigger_dis_cn.png"))); - _protocol_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/protocol_cn.png")) : - QIcon::fromTheme("trig", QIcon(":/icons/protocol_dis_cn.png"))); - _measure_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/measure_cn.png")) : - QIcon::fromTheme("trig", QIcon(":/icons/measure_dis_cn.png"))); - _search_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/search-bar_cn.png")) : - QIcon::fromTheme("trig", QIcon(":/icons/search-bar_dis_cn.png"))); -#else _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")) : @@ -128,19 +131,15 @@ void TrigBar::enable_toggle(bool enable) 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"))); -#endif + _math_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/math.png")) : + QIcon::fromTheme("trig", QIcon(":/icons/math_dis.png"))); } void TrigBar::enable_protocol(bool enable) { _protocol_button.setDisabled(!enable); -#ifdef LANGUAGE_ZH_CN - _protocol_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/protocol_cn.png")) : - QIcon::fromTheme("trig", QIcon(":/icons/protocol_dis_cn.png"))); -#else _protocol_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/protocol.png")) : QIcon::fromTheme("trig", QIcon(":/icons/protocol_dis.png"))); -#endif } void TrigBar::close_all() @@ -163,5 +162,37 @@ void TrigBar::close_all() } } +void TrigBar::reload() +{ + close_all(); + if (_session.get_device()->dev_inst()->mode == LOGIC) { + _trig_action->setVisible(true); + _protocol_action->setVisible(true); + _measure_action->setVisible(true); + _search_action->setVisible(true); + _math_action->setVisible(false); + } else if (_session.get_device()->dev_inst()->mode == ANALOG) { + _trig_action->setVisible(false); + _protocol_action->setVisible(false); + _measure_action->setVisible(true); + _search_action->setVisible(false); + _math_action->setVisible(false); + } else if (_session.get_device()->dev_inst()->mode == DSO) { + _trig_action->setVisible(true); + _protocol_action->setVisible(false); + _measure_action->setVisible(true); + _search_action->setVisible(false); + _math_action->setVisible(true); + } + enable_toggle(true); + update(); +} + +void TrigBar::on_actionFft_triggered() +{ + pv::dialogs::FftOptions fft_dlg(this, _session); + fft_dlg.exec(); +} + } // namespace toolbars } // namespace pv diff --git a/DSView/pv/toolbars/trigbar.h b/DSView/pv/toolbars/trigbar.h index 81e72ef2..6c2048b7 100644 --- a/DSView/pv/toolbars/trigbar.h +++ b/DSView/pv/toolbars/trigbar.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -26,19 +25,25 @@ #include #include +#include +#include namespace pv { + +class SigSession; + namespace toolbars { class TrigBar : public QToolBar { Q_OBJECT public: - explicit TrigBar(QWidget *parent = 0); + explicit TrigBar(SigSession &session, QWidget *parent = 0); void enable_toggle(bool enable); void enable_protocol(bool enable); void close_all(); + void reload(); signals: void on_protocol(bool visible); @@ -52,12 +57,26 @@ public slots: void measure_clicked(); void search_clicked(); + void update_trig_btn(bool checked); + + void on_actionFft_triggered(); + private: + SigSession& _session; bool _enable; QToolButton _trig_button; QToolButton _protocol_button; QToolButton _measure_button; QToolButton _search_button; + QToolButton _math_button; + QAction* _trig_action; + QAction* _protocol_action; + QAction* _measure_action; + QAction* _search_action; + QAction* _math_action; + + QMenu* _math_menu; + QAction* _action_fft; }; diff --git a/DSView/pv/view/analogsignal.cpp b/DSView/pv/view/analogsignal.cpp index dbef9c00..08d38c2e 100644 --- a/DSView/pv/view/analogsignal.cpp +++ b/DSView/pv/view/analogsignal.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -53,12 +53,13 @@ const float AnalogSignal::EnvelopeThreshold = 256.0f; AnalogSignal::AnalogSignal(boost::shared_ptr dev_inst, boost::shared_ptr data, - const sr_channel * const probe) : - Signal(dev_inst, probe, SR_CHANNEL_ANALOG), + sr_channel *probe) : + Signal(dev_inst, probe), _data(data) { + _typeWidth = 3; _colour = SignalColours[probe->index % countof(SignalColours)]; - _scale = _signalHeight * 1.0f / 65536; + _scale = _totalHeight * 1.0f / 65536; } AnalogSignal::~AnalogSignal() @@ -81,7 +82,7 @@ void AnalogSignal::paint_mid(QPainter &p, int left, int right) assert(_view); assert(right >= left); - const int y = get_y() + _signalHeight * 0.5; + const int y = get_y() + _totalHeight * 0.5; const double scale = _view->scale(); assert(scale > 0); const double offset = _view->offset(); @@ -91,9 +92,11 @@ void AnalogSignal::paint_mid(QPainter &p, int left, int right) if (snapshots.empty()) return; - _scale = _signalHeight * 1.0f / 65536; + _scale = _totalHeight * 1.0f / 65536; const boost::shared_ptr &snapshot = snapshots.front(); + if (snapshot->empty()) + return; if (get_index() >= (int)snapshot->get_channel_num()) return; diff --git a/DSView/pv/view/analogsignal.h b/DSView/pv/view/analogsignal.h index b241e848..12523de7 100644 --- a/DSView/pv/view/analogsignal.h +++ b/DSView/pv/view/analogsignal.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -49,7 +48,7 @@ private: public: AnalogSignal(boost::shared_ptr dev_inst, boost::shared_ptr data, - const sr_channel * const probe); + sr_channel *probe); virtual ~AnalogSignal(); diff --git a/DSView/pv/view/cursor.cpp b/DSView/pv/view/cursor.cpp index baa00faf..aaa24582 100644 --- a/DSView/pv/view/cursor.cpp +++ b/DSView/pv/view/cursor.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -60,7 +60,7 @@ Cursor::Cursor(View &view, QColor color, uint64_t index) : QRectF Cursor::get_label_rect(const QRect &rect) const { - const double samples_per_pixel = _view.session().get_device()->get_sample_rate() * _view.scale(); + const double samples_per_pixel = _view.session().cur_samplerate() * _view.scale(); const double x = _index/samples_per_pixel - (_view.offset() / _view.scale()); const QSizeF label_size( @@ -116,7 +116,7 @@ void Cursor::paint_label(QPainter &p, const QRect &rect, p.drawLine(close.left() + 2, close.bottom() - 2, close.right() - 2, close.top() + 2); p.drawText(r, Qt::AlignCenter | Qt::AlignVCenter, - Ruler::format_real_time(_index, _view.session().get_device()->get_sample_rate())); + Ruler::format_real_time(_index, _view.session().cur_samplerate())); const QRectF arrowRect = QRectF(r.bottomLeft().x(), r.bottomLeft().y(), r.width(), ArrowSize); p.drawText(arrowRect, Qt::AlignCenter | Qt::AlignVCenter, QString::number(index)); @@ -143,7 +143,7 @@ void Cursor::paint_fix_label(QPainter &p, const QRect &rect, p.setPen(Qt::white); p.drawText(r, Qt::AlignCenter | Qt::AlignVCenter, - Ruler::format_real_time(_index, _view.session().get_device()->get_sample_rate())); + Ruler::format_real_time(_index, _view.session().cur_samplerate())); const QRectF arrowRect = QRectF(r.bottomLeft().x(), r.bottomLeft().y(), r.width(), ArrowSize); p.drawText(arrowRect, Qt::AlignCenter | Qt::AlignVCenter, label); @@ -153,7 +153,7 @@ void Cursor::compute_text_size(QPainter &p, unsigned int prefix) { (void)prefix; _text_size = p.boundingRect(QRectF(), 0, - Ruler::format_real_time(_index, _view.session().get_device()->get_sample_rate())).size(); + Ruler::format_real_time(_index, _view.session().cur_samplerate())).size(); } } // namespace view diff --git a/DSView/pv/view/cursor.h b/DSView/pv/view/cursor.h index d1b284b7..b1205874 100644 --- a/DSView/pv/view/cursor.h +++ b/DSView/pv/view/cursor.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index d08627ea..d1bfe666 100644 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * Copyright (C) 2012 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 @@ -50,14 +51,11 @@ extern "C" { #include "../widgets/decodergroupbox.h" #include "../widgets/decodermenu.h" #include "../device/devinst.h" +#include "../view/cursor.h" +#include "../toolbars/titlebar.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; +using namespace boost; +using namespace std; namespace pv { namespace view { @@ -114,13 +112,22 @@ const QColor DecodeTrace::OutlineColours[16] = { QColor(0x6B, 0x23, 0x37) }; +const QString DecodeTrace::RegionStart = QT_TR_NOOP("Start"); +const QString DecodeTrace::RegionEnd = QT_TR_NOOP("End "); + DecodeTrace::DecodeTrace(pv::SigSession &session, boost::shared_ptr decoder_stack, int index) : Trace(QString::fromUtf8( decoder_stack->stack().front()->decoder()->name), index, SR_CHANNEL_DECODER), _session(session), _decoder_stack(decoder_stack), - _show_hide_mapper(this), + _decode_start(0), + _decode_end(INT64_MAX), + _start_index(0), + _end_index(0), + _start_count(0), + _end_count(0), + _progress(0), _popup_form(NULL), _popup() { @@ -132,8 +139,6 @@ DecodeTrace::DecodeTrace(pv::SigSession &session, 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))); } DecodeTrace::~DecodeTrace() @@ -169,13 +174,79 @@ 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; + const double sigY = get_y() - (_totalHeight - _view->get_signalHeight())*0.5; p.drawLine(left, sigY, right, sigY); + + // --draw decode region control + const double samples_per_pixel = _session.cur_samplerate() * _view->scale(); + const double startX = _decode_start/samples_per_pixel - (_view->offset() / _view->scale()); + const double endX = _decode_end/samples_per_pixel - (_view->offset() / _view->scale()); + const double regionY = get_y() - _totalHeight*0.5 - ControlRectWidth; + + p.setBrush(Signal::dsBlue); + p.drawLine(startX, regionY, startX, regionY + _totalHeight + ControlRectWidth); + p.drawLine(endX, regionY, endX, regionY + _totalHeight + ControlRectWidth); + const QPointF start_points[] = { + QPointF(startX-ControlRectWidth, regionY), + QPointF(startX+ControlRectWidth, regionY), + QPointF(startX, regionY+ControlRectWidth) + }; + const QPointF end_points[] = { + QPointF(endX-ControlRectWidth, regionY), + QPointF(endX+ControlRectWidth, regionY), + QPointF(endX, regionY+ControlRectWidth) + }; + p.drawPolygon(start_points, countof(start_points)); + p.drawPolygon(end_points, countof(end_points)); + + // --draw headings + const int row_height = _view->get_signalHeight(); + for (size_t i = 0; i < _cur_row_headings.size(); i++) + { + const int y = i * row_height + get_y() - _totalHeight * 0.5; + + p.setPen(QPen(Qt::NoPen)); + p.setBrush(QApplication::palette().brush(QPalette::WindowText)); + + const QRect r(left + ArrowSize * 2, y, + right - left, row_height / 2); + const QString h(_cur_row_headings[i]); + const int f = Qt::AlignLeft | Qt::AlignVCenter | + Qt::TextDontClip; + const QPointF points[] = { + QPointF(left, r.center().y() - ArrowSize), + QPointF(left + ArrowSize, r.center().y()), + QPointF(left, r.center().y() + ArrowSize) + }; + p.drawPolygon(points, countof(points)); + + // 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(DARK_FORE); + p.drawText(r, f, h); + } } void DecodeTrace::paint_mid(QPainter &p, int left, int right) { - using namespace pv::data::decode; + using namespace pv::data::decode; + + assert(_decoder_stack); + const QString err = _decoder_stack->error_message(); + if (!err.isEmpty()) + { + draw_error(p, err, left, right); + return; + } const double scale = _view->scale(); assert(scale > 0); @@ -194,139 +265,101 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right) 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) * + uint64_t end_sample = (uint64_t)max((right + pixels_offset) * samples_per_pixel, 0.0); + const uint64_t samples_decoded = _decoder_stack->samples_decoded(); + if (samples_decoded < start_sample) + return; + if (samples_decoded < end_sample) + end_sample = samples_decoded; 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; + int y = get_y() - (_totalHeight - annotation_height)*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; + BOOST_FOREACH(boost::shared_ptr dec, + _decoder_stack->stack()) { + if (dec->shown()) { + const std::map rows = _decoder_stack->get_rows_gshow(); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + if ((*i).first.decoder() == dec->decoder() && + _decoder_stack->has_annotations((*i).first)) { + if ((*i).second) { + const Row &row = (*i).first; - 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; - } + const uint64_t min_annotation = + _decoder_stack->get_min_annotation(row); + const double min_annWidth = min_annotation / samples_per_pixel; - 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); + 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, + 0, min_annWidth); + } + } else if (max_annWidth != 0){ + draw_nodetail(p, annotation_height, left, right, y, 0); + } + if (max_annWidth != 0) { + y += annotation_height; + _cur_row_headings.push_back(row.title()); + } + } + } } - } else if (max_annWidth != 0){ - draw_nodetail(p, annotation_height, left, right, y, base_colour); + } else { + draw_unshown_row(p, y, annotation_height, left, right, tr("Unshown")); + y += annotation_height; + _cur_row_headings.push_back(dec->decoder()->name); } - 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)p; + (void)left; (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::AlignBottom | - 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() { int ret = false; - _popup = new QDialog(); + _popup = new dialogs::DSDialog(); + create_popup_form(); if (QDialog::Accepted == _popup->exec()) { - BOOST_FOREACH(shared_ptr dec, + BOOST_FOREACH(boost::shared_ptr dec, _decoder_stack->stack()) { - if (dec->commit()) { - _decoder_stack->options_changed(true); + if (dec->commit() || _decoder_stack->options_changed()) { + _decoder_stack->set_options_changed(true); + _decode_start = dec->decode_start(); + _decode_end = dec->decode_end(); ret = true; } } } + delete _popup_form; + delete _popup; _popup = NULL; _popup_form = NULL; @@ -341,10 +374,16 @@ void DecodeTrace::create_popup_form() // which then goes out of scope destroying the layout and all the child // widgets. if (_popup_form) - QWidget().setLayout(_popup_form); + _popup->reload(false); + + _popup_form = new QFormLayout(); + _popup_form->setVerticalSpacing(5); + _popup_form->setFormAlignment(Qt::AlignLeft); + _popup_form->setLabelAlignment(Qt::AlignLeft); + _popup_form->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + _popup->layout()->addLayout(_popup_form); + _popup->setTitle(tr("Decoder Options")); - _popup_form = new QFormLayout(_popup); - _popup->setLayout(_popup_form); populate_popup_form(_popup, _popup_form); } @@ -361,28 +400,57 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) _probe_selectors.clear(); _decoder_forms.clear(); - const list< shared_ptr >& stack = _decoder_stack->stack(); + const list< boost::shared_ptr >& stack = _decoder_stack->stack(); - if (stack.empty()) - { + 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); + } else { + BOOST_FOREACH(boost::shared_ptr dec,stack) { + //boost::shared_ptr dec(*iter); + create_decoder_form(_decoder_stack, dec, parent, form); } form->addRow(new QLabel( tr("* Required channels"), parent)); } + // Add region combobox + _start_comboBox = new QComboBox(parent); + _end_comboBox = new QComboBox(parent); + _start_comboBox->addItem(RegionStart); + _end_comboBox->addItem(RegionEnd); + if (_view) { + int index = 1; + for(std::list::iterator i = _view->get_cursorList().begin(); + i != _view->get_cursorList().end(); i++) { + QString curCursor = tr("Cursor ")+QString::number(index); + _start_comboBox->addItem(curCursor); + _end_comboBox->addItem(curCursor); + index++; + } + } + if (_start_count > _start_comboBox->count()) + _start_index = 0; + if (_end_count > _end_comboBox->count()) + _end_index = 0; + _start_count = _start_comboBox->count(); + _end_count = _end_comboBox->count(); + + _start_comboBox->setCurrentIndex(_start_index); + _end_comboBox->setCurrentIndex(_end_index); + connect(_start_comboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(on_region_set(int))); + connect(_end_comboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(on_region_set(int))); + on_region_set(_start_index); + form->addRow(_start_comboBox, new QLabel( + tr("Decode Start From"))); + form->addRow(_end_comboBox, new QLabel( + tr("Decode End to"))); + // Add stacking button pv::widgets::DecoderMenu *const decoder_menu = new pv::widgets::DecoderMenu(parent); @@ -411,16 +479,16 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) } 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 + QPainter &p, QColor text_color, int h, int left, int right, + double samples_per_pixel, double pixels_offset, int y, + size_t base_colour, double min_annWidth) 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 size_t colour = ((base_colour + a.type()) % MaxAnnType) % countof(Colours); const QColor &fill = Colours[colour]; const QColor &outline = OutlineColours[colour]; @@ -429,7 +497,7 @@ void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, if (a.start_sample() == a.end_sample()) draw_instant(a, p, fill, outline, text_color, h, - start, y); + start, y, min_annWidth); else draw_range(a, p, fill, outline, text_color, h, start, end, y); @@ -439,23 +507,33 @@ void DecodeTrace::draw_nodetail(QPainter &p, int h, int left, int right, int y, size_t base_colour) const { + (void)base_colour; 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]; + QString info = tr("Zoom in For Detials"); + int info_left = nodetail_rect.center().x() - p.boundingRect(QRectF(), 0, info).width(); + int info_right = nodetail_rect.center().x() + p.boundingRect(QRectF(), 0, info).width(); + int height = p.boundingRect(QRectF(), 0, info).height(); - p.setPen(Qt::white); - p.setBrush(fill); - p.drawRect(nodetail_rect); - p.drawText(nodetail_rect, Qt::AlignCenter | Qt::AlignVCenter, "Zoom in for more detials"); + p.setPen(Trace::DARK_FORE); + p.drawLine(left, y, info_left, y); + p.drawLine(info_right, y, right, y); + p.drawLine(info_left, y, info_left+5, y - height/2 + 0.5); + p.drawLine(info_left, y, info_left+5, y + height/2 + 0.5); + p.drawLine(info_right, y, info_right-5, y - height/2 + 0.5); + p.drawLine(info_right, y, info_right-5, y + height/2 + 0.5); + + p.setPen(Trace::DARK_FORE); + p.drawText(nodetail_rect, Qt::AlignCenter | Qt::AlignVCenter, info); } 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 + QColor fill, QColor outline, QColor text_color, int h, double x, int y, double min_annWidth) 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 double w = min((double)p.boundingRect(QRectF(), 0, text).width(), +// 0.0) + h; + const double w = min(min_annWidth, (double)h); const QRectF rect(x - w / 2, y - h / 2, w, h); p.setPen(outline); @@ -498,7 +576,7 @@ void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p, QPointF(start + cap_width, bottom) }; - p.setPen(Qt::white); + p.setPen(DARK_BACK); p.drawConvexPolygon(pts, countof(pts)); if (annotations.empty()) @@ -536,109 +614,63 @@ void DecodeTrace::draw_error(QPainter &p, const QString &message, int left, int right) { const int y = get_y(); + const int h = get_totalHeight(); - 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()); + const QRectF text_rect(left, y - h/2 + 0.5, right - left, h); + const QRectF bounding_rect = p.boundingRect(text_rect, + Qt::AlignCenter, message); + p.setPen(Qt::red); 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(); - const int64_t sample_count = _decoder_stack->sample_count(); - 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; + if (bounding_rect.width() < text_rect.width()) + p.drawText(text_rect, Qt::AlignCenter, tr("Error: ")+message); + else + p.drawText(text_rect, Qt::AlignCenter, tr("Error: ...")); } void DecodeTrace::draw_unshown_row(QPainter &p, int y, int h, int left, - int right) + int right, QString info) { const QRectF unshown_rect(left, y - h/2 + 0.5, right - left, h); + int info_left = unshown_rect.center().x() - p.boundingRect(QRectF(), 0, info).width(); + int info_right = unshown_rect.center().x() + p.boundingRect(QRectF(), 0, info).width(); + int height = p.boundingRect(QRectF(), 0, info).height(); - p.setPen(QPen(Qt::NoPen)); - p.setBrush(QBrush(NoDecodeColour, Qt::Dense7Pattern)); - p.drawRect(unshown_rect); + p.setPen(Trace::DARK_FORE); + p.drawLine(left, y, info_left, y); + p.drawLine(info_right, y, right, y); + p.drawLine(info_left, y, info_left+5, y - height/2 + 0.5); + p.drawLine(info_left, y, info_left+5, y + height/2 + 0.5); + p.drawLine(info_right, y, info_right-5, y - height/2 + 0.5); + p.drawLine(info_right, y, info_right-5, y + height/2 + 0.5); - 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"); + p.setPen(Trace::DARK_FORE); + p.drawText(unshown_rect, Qt::AlignCenter | Qt::AlignVCenter, info); } -void DecodeTrace::create_decoder_form(int index, - shared_ptr &dec, QWidget *parent, - QFormLayout *form) +void DecodeTrace::create_decoder_form( + boost::shared_ptr &decoder_stack, + boost::shared_ptr &dec, QWidget *parent, + QFormLayout *form) { const GSList *l; - assert(dec); + 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()); + pv::widgets::DecoderGroupBox *const group = + new pv::widgets::DecoderGroupBox(decoder_stack, dec, parent); + connect(group, SIGNAL(del_stack(boost::shared_ptr&)), + this, SLOT(on_del_stack(boost::shared_ptr&))); - _show_hide_mapper.setMapping(group, index); - connect(group, SIGNAL(show_hide_decoder()), - &_show_hide_mapper, SLOT(map())); - - QFormLayout *const decoder_form = new QFormLayout; + QFormLayout *const decoder_form = new QFormLayout(); + decoder_form->setContentsMargins(0,0,0,0); + decoder_form->setVerticalSpacing(5); + decoder_form->setFormAlignment(Qt::AlignLeft); + decoder_form->setLabelAlignment(Qt::AlignLeft); + decoder_form->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); group->add_layout(decoder_form); // Add the mandatory channels @@ -672,8 +704,8 @@ void DecodeTrace::create_decoder_form(int index, } // Add the options - shared_ptr binding( - new prop::binding::DecoderOptions(_decoder_stack, dec)); + boost::shared_ptr binding( + new prop::binding::DecoderOptions(decoder_stack, dec)); binding->add_properties_to_form(decoder_form, true); _bindings.push_back(binding); @@ -683,16 +715,16 @@ void DecodeTrace::create_decoder_form(int index, } QComboBox* DecodeTrace::create_probe_selector( - QWidget *parent, const shared_ptr &dec, + QWidget *parent, const boost::shared_ptr &dec, const srd_channel *const pdch) { assert(dec); - const vector< shared_ptr > sigs(_session.get_signals()); + const vector< boost::shared_ptr > sigs(_session.get_signals()); assert(_decoder_stack); const map >::const_iterator probe_iter = + boost::shared_ptr >::const_iterator probe_iter = dec->channels().find(pdch); QComboBox *selector = new QComboBox(parent); @@ -703,7 +735,7 @@ QComboBox* DecodeTrace::create_probe_selector( selector->setCurrentIndex(0); for(size_t i = 0; i < sigs.size(); i++) { - const shared_ptr s(sigs[i]); + const boost::shared_ptr s(sigs[i]); assert(s); if (dynamic_pointer_cast(s) && s->enabled()) @@ -720,12 +752,12 @@ QComboBox* DecodeTrace::create_probe_selector( return selector; } -void DecodeTrace::commit_decoder_probes(shared_ptr &dec) +void DecodeTrace::commit_decoder_probes(boost::shared_ptr &dec) { assert(dec); - map > probe_map; - const vector< shared_ptr > sigs(_session.get_signals()); + map > probe_map; + const vector< boost::shared_ptr > sigs(_session.get_signals()); _index_list.clear(); BOOST_FOREACH(const ProbeSelector &s, _probe_selectors) @@ -737,7 +769,7 @@ void DecodeTrace::commit_decoder_probes(shared_ptr &dec) (LogicSignal*)s._combo->itemData( s._combo->currentIndex()).value(); - BOOST_FOREACH(shared_ptr sig, sigs) + BOOST_FOREACH(boost::shared_ptr sig, sigs) if(sig.get() == selection) { probe_map[s._pdch] = dynamic_pointer_cast(sig); @@ -752,7 +784,7 @@ void DecodeTrace::commit_decoder_probes(shared_ptr &dec) void DecodeTrace::commit_probes() { assert(_decoder_stack); - BOOST_FOREACH(shared_ptr dec, + BOOST_FOREACH(boost::shared_ptr dec, _decoder_stack->stack()) commit_decoder_probes(dec); @@ -761,16 +793,37 @@ void DecodeTrace::commit_probes() void DecodeTrace::on_new_decode_data() { + uint64_t real_end = min(_decoder_stack->sample_count(), _decode_end+1); + const int64_t need_sample_count = real_end - _decode_start; + if (real_end == 0) { + _progress = 0; + } else if (need_sample_count <= 0) { + _progress = 100; + } else { + const uint64_t samples_decoded = _decoder_stack->samples_decoded(); + _progress = floor(samples_decoded * 100.0 / need_sample_count); + } + decoded_progress(_progress); + if (_view && _view->session().get_capture_state() == SigSession::Stopped) _view->data_updated(); + if (_totalHeight/_view->get_signalHeight() != rows_size()) + _view->signals_changed(); +} + +int DecodeTrace::get_progress() const +{ + return _progress; } void DecodeTrace::on_decode_done() { - if (_view) { - _view->set_need_update(true); - _view->signals_changed(); - } +// if (_view) { +// _view->set_update(_viewport, true); +// _view->signals_changed(); +// } + on_new_decode_data(); + _session.decode_done(); } void DecodeTrace::on_delete() @@ -787,40 +840,43 @@ void DecodeTrace::on_stack_decoder(srd_decoder *decoder) { assert(decoder); assert(_decoder_stack); - _decoder_stack->push(shared_ptr( + _decoder_stack->push(boost::shared_ptr( new data::decode::Decoder(decoder))); //_decoder_stack->begin_decode(); create_popup_form(); } -void DecodeTrace::on_show_hide_decoder(int index) +void DecodeTrace::on_del_stack(boost::shared_ptr &dec) { - using pv::data::decode::Decoder; + assert(dec); + assert(_decoder_stack); + _decoder_stack->remove(dec); - 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); + create_popup_form(); } - int DecodeTrace::rows_size() { - return _decoder_stack->cur_rows_size(); + using pv::data::decode::Decoder; + + int size = 0; + BOOST_FOREACH(boost::shared_ptr dec, + _decoder_stack->stack()) { + if (dec->shown()) { + const std::map rows = _decoder_stack->get_rows_gshow(); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + if ((*i).first.decoder() == dec->decoder() && + _decoder_stack->has_annotations((*i).first) && + (*i).second) + size++; + } + } else { + size++; + } + } + return size == 0 ? 1 : size; } void DecodeTrace::paint_type_options(QPainter &p, int right, const QPoint pt) @@ -831,9 +887,8 @@ void DecodeTrace::paint_type_options(QPainter &p, int right, const QPoint pt) const QRectF group_index_rect = get_rect(CHNLREG, y, right); QString index_string; int last_index; - p.setPen(Qt::transparent); - p.setBrush(dsBlue); - p.drawRect(group_index_rect); + p.setPen(QPen(DARK_FORE, 1, Qt::DashLine)); + p.drawLine(group_index_rect.bottomLeft(), group_index_rect.bottomRight()); std::list::iterator i = _index_list.begin(); last_index = (*i); index_string = QString::number(last_index); @@ -846,7 +901,7 @@ void DecodeTrace::paint_type_options(QPainter &p, int right, const QPoint pt) index_string = QString::number((*i)) + "," + index_string; last_index = (*i); } - p.setPen(Qt::white); + p.setPen(DARK_FORE); p.drawText(group_index_rect, Qt::AlignRight | Qt::AlignVCenter, index_string); } @@ -863,5 +918,63 @@ QRectF DecodeTrace::get_rect(DecodeSetRegions type, int y, int right) return QRectF(0, 0, 0, 0); } +void DecodeTrace::on_region_set(int index) +{ + (void)index; + const uint64_t last_samples = _session.cur_samplelimits() - 1; + const int index1 = _start_comboBox->currentIndex(); + const int index2 = _end_comboBox->currentIndex(); + uint64_t decode_start, decode_end; + + if (index1 == 0) { + decode_start = 0; + } else { + decode_start = _view->get_cursor_samples(index1-1); + } + if (index2 == 0) { + decode_end = last_samples; + } else { + decode_end = _view->get_cursor_samples(index2-1); + } + + if (decode_start > last_samples) + decode_start = 0; + if (decode_end > last_samples) + decode_end = last_samples; + + if (decode_start > decode_end) { + uint64_t tmp = decode_start; + decode_start = decode_end; + decode_end = tmp; + } + _start_index = index1; + _end_index = index2; + + BOOST_FOREACH(boost::shared_ptr dec, + _decoder_stack->stack()) { + dec->set_decode_region(decode_start, decode_end); + } +} + +void DecodeTrace::frame_ended() +{ + const uint64_t last_samples = _session.cur_samplelimits() - 1; + if (_decode_start > last_samples) { + _decode_start = 0; + _start_index = 0; + } + if (_end_index ==0 || + _decode_end > last_samples) { + _decode_end = last_samples; + _end_index = 0; + } + BOOST_FOREACH(boost::shared_ptr dec, + _decoder_stack->stack()) { + dec->set_decode_region(_decode_start, _decode_end); + dec->commit(); + } +} + + } // namespace view } // namespace pv diff --git a/DSView/pv/view/decodetrace.h b/DSView/pv/view/decodetrace.h index 03cd6910..bf93e440 100644 --- a/DSView/pv/view/decodetrace.h +++ b/DSView/pv/view/decodetrace.h @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * Copyright (C) 2012 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 @@ -28,11 +29,11 @@ #include #include -#include #include #include +#include "../dialogs/dsdialog.h" struct srd_channel; struct srd_decoder; @@ -88,7 +89,12 @@ private: static const QColor Colours[16]; static const QColor OutlineColours[16]; - static const int DefaultFontSize = 8; + static const int DefaultFontSize = 10; + static const int ControlRectWidth = 5; + static const int MaxAnnType = 100; + + static const QString RegionStart; + static const QString RegionEnd; public: DecodeTrace(pv::SigSession &session, @@ -132,6 +138,13 @@ public: QRectF get_rect(DecodeSetRegions type, int y, int right); + /** + * decode region + **/ + void frame_ended(); + + int get_progress() const; + protected: void paint_type_options(QPainter &p, int right, const QPoint pt); @@ -143,14 +156,14 @@ private: 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; + size_t base_colour, double min_annWidth) 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; + int y, double min_annWidth) const; void draw_range(const pv::data::decode::Annotation &a, QPainter &p, QColor fill, QColor outline, QColor text_color, int h, double start, @@ -159,15 +172,12 @@ private: 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); + int right, QString info); - void create_decoder_form(int index, - boost::shared_ptr &dec, - QWidget *parent, QFormLayout *form); + void create_decoder_form(boost::shared_ptr &decoder_stack, + boost::shared_ptr &dec, + QWidget *parent, QFormLayout *form); QComboBox* create_probe_selector(QWidget *parent, const boost::shared_ptr &dec, @@ -178,6 +188,9 @@ private: void commit_probes(); +signals: + void decoded_progress(int progress); + private slots: void on_new_decode_data(); @@ -186,16 +199,21 @@ private slots: void on_probe_selected(int); void on_stack_decoder(srd_decoder *decoder); - - void on_show_hide_decoder(int index); + void on_del_stack(boost::shared_ptr &dec); void on_decode_done(); + void on_region_set(int index); + private: pv::SigSession &_session; boost::shared_ptr _decoder_stack; uint64_t _decode_start, _decode_end; + int _start_index, _end_index; + int _start_count, _end_count; + QComboBox *_start_comboBox, *_end_comboBox; + int _progress; std::list< boost::shared_ptr > _bindings; @@ -205,9 +223,8 @@ private: std::vector _cur_row_headings; - QSignalMapper _show_hide_mapper; QFormLayout *_popup_form; - QDialog *_popup; + dialogs::DSDialog *_popup; }; } // namespace view diff --git a/DSView/pv/view/devmode.cpp b/DSView/pv/view/devmode.cpp index f48c453c..6f81f27a 100644 --- a/DSView/pv/view/devmode.cpp +++ b/DSView/pv/view/devmode.cpp @@ -2,7 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2014 DreamSourceLab + * 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 @@ -35,7 +35,6 @@ #include #include #include -#include #include using boost::shared_ptr; @@ -44,45 +43,53 @@ using namespace std; namespace pv { namespace view { -DevMode::DevMode(View &parent) : - QWidget(&parent), - _view(parent), - layout(new QGridLayout(this)) +DevMode::DevMode(QWidget *parent, SigSession &session) : + QWidget(parent), + _session(session), + _layout(new QGridLayout(this)) { - setLayout(layout); + _layout->setMargin(5); + _layout->setSpacing(0); + setLayout(_layout); } void DevMode::set_device() { int index = 0; - const boost::shared_ptr dev_inst = _view.session().get_device(); + const boost::shared_ptr dev_inst = _session.get_device(); assert(dev_inst); + for(std::map::const_iterator i = _mode_button_list.begin(); + i != _mode_button_list.end(); i++) { + (*i).first->setParent(NULL); + _layout->removeWidget((*i).first); + delete (*i).first; + } _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; - boost::shared_ptr mode_button = boost::shared_ptr(new QPushButton(NULL)); - mode_button->setFlat(true); + QPushButton *mode_button = new QPushButton(this); + //mode_button->setFlat(true); + mode_button->setMinimumWidth(32); mode_button->setText(mode->name); + mode_button->setCheckable(true); _mode_button_list[mode_button] = mode; + if (dev_inst->dev_inst()->mode == _mode_button_list[mode_button]->mode) + mode_button->setChecked(true); - connect(mode_button.get(), SIGNAL(clicked()), this, SLOT(on_mode_change())); + connect(mode_button, 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); + _layout->addWidget(mode_button, index / GRID_COLS, index % GRID_COLS); + //layout->addWidget(new QWidget(), index / GRID_COLS, GRID_COLS); + _layout->setColumnStretch(GRID_COLS, 1); index++; - } - - setLayout(layout); + } update(); } @@ -94,40 +101,31 @@ void DevMode::paintEvent(QPaintEvent*) 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(); + const boost::shared_ptr dev_inst = _session.get_device(); assert(dev_inst); QPushButton *button = qobject_cast(sender()); + button->setChecked(true); + if (dev_inst->dev_inst()->mode == _mode_button_list[button]->mode) + return; - for(std::map, sr_dev_mode *>::const_iterator i = _mode_button_list.begin(); + for(std::map::const_iterator i = _mode_button_list.begin(); i != _mode_button_list.end(); i++) { - if ((*i).first.get() == button) { + if ((*i).first == button) { if (dev_inst->dev_inst()->mode != (*i).second->mode) { - _view.session().stop_capture(); + _session.stop_capture(); + _session.on_mode_change(); dev_inst->set_config(NULL, NULL, SR_CONF_DEVICE_MODE, g_variant_new_int16((*i).second->mode)); mode_changed(); + button->setChecked(true); } + } else { + (*i).first->setChecked(false); } } } diff --git a/DSView/pv/view/devmode.h b/DSView/pv/view/devmode.h index 27488805..033f55ac 100644 --- a/DSView/pv/view/devmode.h +++ b/DSView/pv/view/devmode.h @@ -2,7 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2014 DreamSourceLab + * 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 @@ -44,9 +44,9 @@ namespace device{ class DevInst; } -namespace view { +class SigSession; -class View; +namespace view { class DevMode : public QWidget { @@ -56,7 +56,7 @@ private: static const int GRID_COLS = 3; public: - DevMode(View &parent); + DevMode(QWidget *parent, SigSession &session); private: void paintEvent(QPaintEvent *event); @@ -77,10 +77,10 @@ signals: void mode_changed(); private: - View &_view; + SigSession &_session; - QGridLayout * layout; - std::map , sr_dev_mode *> _mode_button_list; + QGridLayout * _layout; + std::map _mode_button_list; QPoint _mouse_point; }; diff --git a/DSView/pv/view/dsldial.cpp b/DSView/pv/view/dsldial.cpp index 454dc620..6153964b 100644 --- a/DSView/pv/view/dsldial.cpp +++ b/DSView/pv/view/dsldial.cpp @@ -1,6 +1,28 @@ +/* + * This file is part of the DSView project. + * DSView 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 "dsldial.h" -#include +#include +#include namespace pv { namespace view { diff --git a/DSView/pv/view/dsldial.h b/DSView/pv/view/dsldial.h index ddb7ea61..392cf89e 100644 --- a/DSView/pv/view/dsldial.h +++ b/DSView/pv/view/dsldial.h @@ -1,3 +1,24 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * 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 DSVIEW_PV_VIEW_DSLDIAL_H #define DSVIEW_PV_VIEW_DSLDIAL_H diff --git a/DSView/pv/view/dsosignal.cpp b/DSView/pv/view/dsosignal.cpp index de5e0bbf..461aafc9 100644 --- a/DSView/pv/view/dsosignal.cpp +++ b/DSView/pv/view/dsosignal.cpp @@ -2,7 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -24,6 +24,7 @@ #include +#include "../../extdef.h" #include "dsosignal.h" #include "pv/data/dso.h" #include "pv/data/dsosnapshot.h" @@ -103,23 +104,15 @@ const QColor DsoSignal::SignalColours[4] = { }; const float DsoSignal::EnvelopeThreshold = 256.0f; -const double DsoSignal::TrigMargin = 0.02; - -const int DsoSignal::UpMargin = 30; -const int DsoSignal::DownMargin = 30; -const int DsoSignal::RightMargin = 30; DsoSignal::DsoSignal(boost::shared_ptr dev_inst, boost::shared_ptr data, - const sr_channel * const probe): - Signal(dev_inst, probe, SR_CHANNEL_DSO), + sr_channel *probe): + Signal(dev_inst, probe), _data(data), _scale(0), _vDialActive(false), _hDialActive(false), - //_trig_vpos(probe->index * 0.5 + 0.25), - //_zeroPos(probe->index * 0.5 + 0.25) - _trig_vpos(0.5), _autoV(false), _autoH(false), _hover_en(false), @@ -127,8 +120,7 @@ DsoSignal::DsoSignal(boost::shared_ptr dev_inst, _hover_point(QPointF(0, 0)), _hover_value(0), _ms_gear_hover(false), - _ms_show_hover(false), - _ms_show(false) + _ms_show_hover(false) { QVector vValue; QVector vUnit; @@ -149,12 +141,6 @@ DsoSignal::DsoSignal(boost::shared_ptr dev_inst, _colour = SignalColours[probe->index % countof(SignalColours)]; - for (int i = DSO_MS_BEGIN; i < DSO_MS_END; i++) - _ms_en[i] = false; - _ms_en[DSO_MS_FREQ] = true; - _ms_en[DSO_MS_VMAX] = true; - _ms_en[DSO_MS_VMIN] = true; - load_settings(); } @@ -167,10 +153,14 @@ boost::shared_ptr DsoSignal::data() const return _data; } -void DsoSignal::set_view(pv::view::View *view) +boost::shared_ptr DsoSignal::dso_data() const { - Trace::set_view(view); - update_zeroPos(); + return _data; +} + +void DsoSignal::set_viewport(pv::view::Viewport *viewport) +{ + Trace::set_viewport(viewport); const double ms_left = get_view_rect().right() - (MS_RectWidth + MS_RectMargin) * (get_index() + 1); const double ms_top = get_view_rect().top() + 5; @@ -193,10 +183,14 @@ float DsoSignal::get_scale() void DsoSignal::set_enable(bool enable) { - if ((strcmp(_dev_inst->dev_inst()->driver->name, "DSLogic") == 0) && + if (_dev_inst->name() == "DSLogic" && get_index() == 0) return; _view->session().refresh(INT_MAX); + /* + * avoid race condition for en_ch_num + * data lock need to lock usb event + */ _dev_inst->set_config(_probe, NULL, SR_CONF_DATALOCK, g_variant_new_boolean(true)); set_vDialActive(false); @@ -233,7 +227,9 @@ void DsoSignal::set_enable(bool enable) _dev_inst->set_config(_probe, NULL, SR_CONF_DATALOCK, g_variant_new_boolean(false)); - _view->session().refresh(800); + _view->session().refresh(RefreshLong); + _view->set_update(_viewport, true); + _view->update(); } bool DsoSignal::get_vDialActive() const @@ -250,14 +246,17 @@ void DsoSignal::set_vDialActive(bool active) bool DsoSignal::go_vDialPre() { if (enabled() && !_vDial->isMin()) { + if (_view->session().get_capture_state() == SigSession::Running) + _view->session().refresh(RefreshShort); const double pre_vdiv = _vDial->get_value(); _vDial->set_sel(_vDial->get_sel() - 1); _dev_inst->set_config(_probe, NULL, SR_CONF_VDIV, g_variant_new_uint64(_vDial->get_value())); if (_view->session().get_capture_state() == SigSession::Stopped) _scale *= pre_vdiv/_vDial->get_value(); - update_zeroPos(); - _view->set_need_update(true); + update_offset(); + _view->update_calibration(); + _view->set_update(_viewport, true); _view->update(); return true; } else { @@ -269,14 +268,17 @@ bool DsoSignal::go_vDialPre() bool DsoSignal::go_vDialNext() { if (enabled() && !_vDial->isMax()) { + if (_view->session().get_capture_state() == SigSession::Running) + _view->session().refresh(RefreshShort); const double pre_vdiv = _vDial->get_value(); _vDial->set_sel(_vDial->get_sel() + 1); _dev_inst->set_config(_probe, NULL, SR_CONF_VDIV, g_variant_new_uint64(_vDial->get_value())); if (_view->session().get_capture_state() == SigSession::Stopped) _scale *= pre_vdiv/_vDial->get_value(); - update_zeroPos(); - _view->set_need_update(true); + update_offset(); + _view->update_calibration(); + _view->set_update(_viewport, true); _view->update(); return true; } else { @@ -308,7 +310,7 @@ bool DsoSignal::go_hDialPre(bool setted) } else if ((_view->session().get_capture_state() == SigSession::Running || _data->get_snapshots().empty()) && !_view->session().get_instant()) { - _view->session().refresh(100); + _view->session().refresh(RefreshShort); _hDial->set_sel(_hDial->get_sel() - 1); if (!setted) { @@ -350,7 +352,7 @@ bool DsoSignal::go_hDialCur() if (ch_num == 0) return false; - _view->session().refresh(100); + _view->session().refresh(RefreshShort); uint64_t sample_limit = _view->session().get_device()->get_sample_limit(); GVariant* gvar; uint64_t max_sample_rate; @@ -384,7 +386,7 @@ bool DsoSignal::go_hDialNext(bool setted) } else if ((_view->session().get_capture_state() == SigSession::Running || _data->get_snapshots().empty()) && !_view->session().get_instant()) { - _view->session().refresh(100); + _view->session().refresh(RefreshShort); _hDial->set_sel(_hDial->get_sel() + 1); if (!setted) { @@ -435,6 +437,15 @@ bool DsoSignal::load_settings() // qDebug() << "ERROR: config_get SR_CONF_EN_CH failed."; // return false; //} + gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_DSO_BITS); + if (gvar != NULL) { + _bits = g_variant_get_byte(gvar); + g_variant_unref(gvar); + } else { + _bits = DefaultBits; + qDebug("Warning: config_get SR_CONF_DSO_BITS failed, set to %d(default).", DefaultBits); + return false; + } // -- hdiv uint64_t hdiv; @@ -463,7 +474,7 @@ bool DsoSignal::load_settings() vdiv = g_variant_get_uint64(gvar); g_variant_unref(gvar); } else { - qDebug() << "ERROR: config_get SR_CONF_TIMEBASE failed."; + qDebug() << "ERROR: config_get SR_CONF_VDIV failed."; return false; } gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_FACTOR); @@ -471,14 +482,14 @@ bool DsoSignal::load_settings() vfactor = g_variant_get_uint64(gvar); g_variant_unref(gvar); } else { - qDebug() << "ERROR: config_get SR_CONF_TIMEBASE failed."; + qDebug() << "ERROR: config_get SR_CONF_FACTOR failed."; return false; } _vDial->set_value(vdiv); _vDial->set_factor(vfactor); - _dev_inst->set_config(_probe, NULL, SR_CONF_VDIV, - g_variant_new_uint64(_vDial->get_value())); +// _dev_inst->set_config(_probe, NULL, SR_CONF_VDIV, +// g_variant_new_uint64(_vDial->get_value())); // -- coupling gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_COUPLING); @@ -490,8 +501,8 @@ bool DsoSignal::load_settings() return false; } - _dev_inst->set_config(_probe, NULL, SR_CONF_COUPLING, - g_variant_new_byte(_acCoupling)); +// _dev_inst->set_config(_probe, NULL, SR_CONF_COUPLING, +// g_variant_new_byte(_acCoupling)); // -- vpos double vpos; @@ -500,19 +511,66 @@ bool DsoSignal::load_settings() vpos = g_variant_get_double(gvar); g_variant_unref(gvar); } else { - qDebug() << "ERROR: config_get SR_CONF_COUPLING failed."; + qDebug() << "ERROR: config_get SR_CONF_VPOS failed."; + return false; + } + _zero_vrate = min(max((0.5 - vpos / (_vDial->get_value() * DS_CONF_DSO_VDIVS)), 0.0), 1.0); + if (_dev_inst->name() == "DSCope") + _zero_value = _zero_vrate * ((1 << _bits) - 1); + else + _zero_value = 0x80; + + // -- trig_value + gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_TRIGGER_VALUE); + if (gvar != NULL) { + _trig_value = g_variant_get_byte(gvar); + _trig_delta = get_trig_vrate() - _zero_vrate; + g_variant_unref(gvar); + } else { + qDebug() << "ERROR: config_get SR_CONF_TRIGGER_VALUE failed."; return false; } - _zeroPos = min(max((0.5 - vpos / (_vDial->get_value() * DS_CONF_DSO_VDIVS)), 0.0), 1.0); - _zero_off = _zeroPos * 255; if (_view) { - _view->set_need_update(true); + _view->set_update(_viewport, true); _view->update(); } return true; } +int DsoSignal::commit_settings() +{ + int ret; + // -- enable + ret = _dev_inst->set_config(_probe, NULL, SR_CONF_EN_CH, + g_variant_new_boolean(enabled())); + + // -- hdiv + ret = _dev_inst->set_config(_probe, NULL, SR_CONF_TIMEBASE, + g_variant_new_uint64(_hDial->get_value())); + + // -- vdiv + ret = _dev_inst->set_config(_probe, NULL, SR_CONF_VDIV, + g_variant_new_uint64(_vDial->get_value())); + ret = _dev_inst->set_config(_probe, NULL, SR_CONF_FACTOR, + g_variant_new_uint64(_vDial->get_factor())); + + // -- coupling + ret = _dev_inst->set_config(_probe, NULL, SR_CONF_COUPLING, + g_variant_new_byte(_acCoupling)); + + // -- vpos + double vpos_off = (0.5 - (get_zero_vpos() - UpMargin) * 1.0/get_view_rect().height()) * _vDial->get_value() * DS_CONF_DSO_VDIVS; + ret = _dev_inst->set_config(_probe, NULL, SR_CONF_VPOS, + g_variant_new_double(vpos_off)); + + // -- trig_value + _dev_inst->set_config(_probe, NULL, SR_CONF_TRIGGER_VALUE, + g_variant_new_byte(_trig_value)); + + return ret; +} + uint64_t DsoSignal::get_vDialValue() const { return _vDial->get_value(); @@ -549,82 +607,88 @@ void DsoSignal::set_acCoupling(uint8_t coupling) int DsoSignal::get_trig_vpos() const { - return _trig_vpos * get_view_rect().height() + UpMargin; + return get_trig_vrate() * get_view_rect().height() + UpMargin; } -double DsoSignal::get_trigRate() const +double DsoSignal::get_trig_vrate() const { - return _trig_vpos; + if (_dev_inst->name() == "DSLogic") + return (_trig_value - (1 << (_bits - 1)))* 1.0 / ((1 << _bits) - 1.0) + _zero_vrate; + else + return _trig_value * 1.0 / ((1 << _bits) - 1.0); } -void DsoSignal::set_trig_vpos(int pos) +void DsoSignal::set_trig_vpos(int pos, bool delta_change) { assert(_view); - int trig_value; if (enabled()) { - double delta = min((double)max(pos - UpMargin, 0), get_view_rect().height()) * 1.0 / get_view_rect().height(); - bool isDSCope = (strcmp(_dev_inst->dev_inst()->driver->name, "DSCope") == 0); - if (isDSCope) { - _trig_vpos = min(max(delta, 0+TrigMargin), 1-TrigMargin); - trig_value = delta * 255; - } else { - delta = delta - _zeroPos; + double delta = min(max(pos - UpMargin, 0), get_view_rect().height()) * 1.0 / get_view_rect().height(); + if (_dev_inst->name() == "DSLogic") { + delta = delta - _zero_vrate; delta = min(delta, 0.5); delta = max(delta, -0.5); - _trig_vpos = min(max(_zeroPos + delta, 0+TrigMargin), 1-TrigMargin); - trig_value = (delta * 255.0f + 0x80); + _trig_value = delta * ((1 << _bits) -1) + (1 << (_bits - 1)); + } else { + _trig_value = delta * ((1 << _bits) -1) + 0.5; } + int margin = TrigMargin; + _trig_value = std::min(std::max(_trig_value, margin), ((1 << _bits) - margin - 1)); + if (delta_change) + _trig_delta = get_trig_vrate() - _zero_vrate; _dev_inst->set_config(_probe, NULL, SR_CONF_TRIGGER_VALUE, - g_variant_new_byte(trig_value)); + g_variant_new_byte(_trig_value)); } } -void DsoSignal::set_trigRate(double rate) +void DsoSignal::set_trig_vrate(double rate) { - int trig_value; double delta = rate; - bool isDSCope = (strcmp(_dev_inst->dev_inst()->driver->name, "DSCope") == 0); - if (isDSCope) { - _trig_vpos = min(max(delta, 0+TrigMargin), 1-TrigMargin); - trig_value = delta * 255; - } else { - delta = delta - _zeroPos; + if (_dev_inst->name() == "DSLogic") { + delta = delta - _zero_vrate; delta = min(delta, 0.5); delta = max(delta, -0.5); - _trig_vpos = min(max(_zeroPos + delta, 0+TrigMargin), 1-TrigMargin); - trig_value = (delta * 255.0f + 0x80); + _trig_value = delta * ((1 << _bits) - 1) + (1 << (_bits - 1)); + } else { + _trig_value = delta * ((1 << _bits) - 1) + 0.5; } + _trig_delta = get_trig_vrate() - _zero_vrate; _dev_inst->set_config(_probe, NULL, SR_CONF_TRIGGER_VALUE, - g_variant_new_byte(trig_value)); + g_variant_new_byte(_trig_value)); } -int DsoSignal::get_zeroPos() +int DsoSignal::get_zero_vpos() { - return _zeroPos * get_view_rect().height() + UpMargin; + return _zero_vrate * get_view_rect().height() + UpMargin; } -double DsoSignal::get_zeroRate() +double DsoSignal::get_zero_vrate() { - return _zeroPos; + return _zero_vrate; } -void DsoSignal::set_zeroPos(int pos) +double DsoSignal::get_zero_value() +{ + return _zero_value; +} + +void DsoSignal::set_zero_vpos(int pos) { if (enabled()) { - double delta = _trig_vpos - _zeroPos; - set_trig_vpos(get_trig_vpos() + pos - get_zeroPos()); - _zeroPos = min((double)max(pos - UpMargin, 0), get_view_rect().height()) * 1.0 / get_view_rect().height(); - _trig_vpos = min(max(_zeroPos + delta, 0+TrigMargin), 1-TrigMargin); - - update_zeroPos(); + double delta = _trig_delta* get_view_rect().height(); + _zero_vrate = min(max(pos - UpMargin, 0), get_view_rect().height()) * 1.0 / get_view_rect().height(); + set_trig_vpos(get_zero_vpos() + delta, false); + update_offset(); } } -void DsoSignal::set_zeroRate(double rate) +void DsoSignal::set_zero_vrate(double rate) { - _zeroPos = rate; - _zero_off = rate * 255; - update_zeroPos(); + _zero_vrate = rate; + if (_dev_inst->name() == "DSCope") + _zero_value = _zero_vrate * ((1 << _bits) - 1); + else + _zero_value = 0x80; + update_offset(); } void DsoSignal::set_factor(uint64_t factor) @@ -644,7 +708,7 @@ void DsoSignal::set_factor(uint64_t factor) _dev_inst->set_config(_probe, NULL, SR_CONF_FACTOR, g_variant_new_uint64(factor)); _vDial->set_factor(factor); - _view->set_need_update(true); + _view->set_update(_viewport, true); _view->update(); } } @@ -667,13 +731,13 @@ uint64_t DsoSignal::get_factor() void DsoSignal::set_ms_show(bool show) { - _ms_show = show; - _view->set_need_update(true); + _probe->ms_show = show; + _view->set_update(_viewport, true); } bool DsoSignal::get_ms_show() const { - return _ms_show; + return _probe->ms_show; } bool DsoSignal::get_ms_show_hover() const @@ -691,7 +755,7 @@ void DsoSignal::set_ms_en(int index, bool en) assert(index > DSO_MS_BEGIN); assert(index < DSO_MS_END); - _ms_en[index] = en; + _probe->ms_en[index] = en; } bool DsoSignal::get_ms_en(int index) const @@ -699,7 +763,7 @@ bool DsoSignal::get_ms_en(int index) const assert(index > DSO_MS_BEGIN); assert(index < DSO_MS_END); - return _ms_en[index]; + return _probe->ms_en[index]; } QString DsoSignal::get_ms_string(int index) const @@ -719,22 +783,19 @@ QString DsoSignal::get_ms_string(int index) const } } -void DsoSignal::update_zeroPos() +void DsoSignal::update_offset() { - if (strcmp(_dev_inst->dev_inst()->driver->name, "DSCope") == 0) { - //double vpos_off = (0.5 - _zeroPos) * _vDial->get_value() * DS_CONF_DSO_VDIVS; - double vpos_off = (0.5 - (get_zeroPos() - UpMargin) * 1.0/get_view_rect().height()) * _vDial->get_value() * DS_CONF_DSO_VDIVS; - _dev_inst->set_config(_probe, NULL, SR_CONF_VPOS, - g_variant_new_double(vpos_off)); - } + double vpos_off = (0.5 - _zero_vrate) * _vDial->get_value() * DS_CONF_DSO_VDIVS; + _dev_inst->set_config(_probe, NULL, SR_CONF_VPOS, + g_variant_new_double(vpos_off)); } -QRectF DsoSignal::get_view_rect() const +QRect DsoSignal::get_view_rect() const { - assert(_view); - return QRectF(0, UpMargin, - _view->viewport()->width() - RightMargin, - _view->viewport()->height() - UpMargin - DownMargin); + assert(_viewport); + return QRect(0, UpMargin, + _viewport->width() - RightMargin, + _viewport->height() - UpMargin - DownMargin); } void DsoSignal::paint_back(QPainter &p, int left, int right) @@ -745,7 +806,9 @@ void DsoSignal::paint_back(QPainter &p, int left, int right) const int height = get_view_rect().height(); const int width = right - left; - p.setPen(Qt::NoPen); + QPen solidPen(Signal::dsFore); + solidPen.setStyle(Qt::SolidLine); + p.setPen(solidPen); p.setBrush(Trace::dsBack); p.drawRect(left, UpMargin, width, height); @@ -772,13 +835,14 @@ void DsoSignal::paint_back(QPainter &p, int left, int right) 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); + QPen dashPen(Signal::dsFore); + dashPen.setStyle(Qt::DashLine); + p.setPen(dashPen); const double spanY =height * 1.0 / DS_CONF_DSO_VDIVS; for (i = 1; i <= DS_CONF_DSO_VDIVS; i++) { const double posY = spanY * i + UpMargin; - p.drawLine(left, posY, right, posY); + if (i != DS_CONF_DSO_VDIVS) + p.drawLine(left, posY, right, posY); const double miniSpanY = spanY / 5; for (j = 1; j < 5; j++) { p.drawLine(width / 2.0f - 5, posY - miniSpanY * j, @@ -788,8 +852,8 @@ void DsoSignal::paint_back(QPainter &p, int left, int right) const double spanX = width * 1.0 / DS_CONF_DSO_HDIVS; for (i = 1; i <= DS_CONF_DSO_HDIVS; i++) { const double posX = spanX * i; - p.drawLine(posX, UpMargin, - posX, height + UpMargin); + if (i != DS_CONF_DSO_HDIVS) + 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 - 5, @@ -808,22 +872,22 @@ void DsoSignal::paint_mid(QPainter &p, int left, int right) const int height = get_view_rect().height(); const int width = right - left; - const int y = get_zeroPos() + height * 0.5; + const int y = get_zero_vpos() + height * 0.5; const double scale = _view->scale(); assert(scale > 0); const double offset = _view->offset(); - paint_measure(p); - const deque< boost::shared_ptr > &snapshots = _data->get_snapshots(); if (snapshots.empty()) return; const boost::shared_ptr &snapshot = snapshots.front(); + if (snapshot->empty()) + return; const uint16_t number_channels = snapshot->get_channel_num(); - if ((strcmp(_dev_inst->dev_inst()->driver->name, "DSLogic") == 0) && + if (_dev_inst->name() == "DSLogic" && (unsigned int)get_index() >= number_channels) return; @@ -862,7 +926,7 @@ void DsoSignal::paint_fore(QPainter &p, int left, int right) QPen pen(Signal::dsGray); pen.setStyle(Qt::DotLine); p.setPen(pen); - p.drawLine(left, get_zeroPos(), right, get_zeroPos()); + p.drawLine(left, get_zero_vpos(), right, get_zero_vpos()); if(enabled()) { const QPointF mouse_point = _view->hover_point(); @@ -884,7 +948,7 @@ void DsoSignal::paint_fore(QPainter &p, int left, int right) // paint the trig voltage int trigp = get_trig_vpos(); - float t_vol = (_zeroPos - _trig_vpos) * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS; + float t_vol = (_zero_vrate - get_trig_vrate()) * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS; QString t_vol_s = (_vDial->get_value() >= 500) ? QString::number(t_vol/1000.0f, 'f', 2)+"V" : QString::number(t_vol, 'f', 2)+"mV"; int vol_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, Qt::AlignLeft | Qt::AlignTop, t_vol_s).width(); @@ -899,6 +963,9 @@ void DsoSignal::paint_fore(QPainter &p, int left, int right) // Paint the text p.setPen(Qt::white); p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "T"); + + // Paint measure + paint_measure(p); } } @@ -933,10 +1000,10 @@ void DsoSignal::paint_trace(QPainter &p, float top = get_view_rect().top(); float bottom = get_view_rect().bottom(); - float zeroP = _zeroPos * get_view_rect().height() + top;; - if (strcmp(_dev_inst->dev_inst()->driver->name, "DSCope") == 0 && + float zeroP = _zero_vrate * get_view_rect().height() + top;; + if (_dev_inst->name() == "DSCope" && _view->session().get_capture_state() == SigSession::Running) - _zero_off = _zeroPos * 255; + _zero_value = _zero_vrate * ((1 << _bits) - 1); float x = (start / samples_per_pixel - pixels_offset) + left; double pixels_per_sample = 1.0/samples_per_pixel; uint8_t offset; @@ -947,14 +1014,14 @@ void DsoSignal::paint_trace(QPainter &p, //offset = samples[(sample - start)*num_channels]; offset = samples[sample]; - const float y = min(max(top, zeroP + (offset - _zero_off) * _scale), bottom); + const float y = min(max(top, zeroP + (offset - _zero_value) * _scale), bottom); *point++ = QPointF(x, y); x += pixels_per_sample; //*point++ = QPointF(x, top + offset); } p.drawPolyline(points, point - points); - p.eraseRect(get_view_rect().right(), get_view_rect().top(), + p.eraseRect(get_view_rect().right()+1, get_view_rect().top(), _view->viewport()->width() - get_view_rect().width(), get_view_rect().height()); //delete[] samples; @@ -989,10 +1056,10 @@ void DsoSignal::paint_envelope(QPainter &p, QRectF *rect = rects; float top = get_view_rect().top(); float bottom = get_view_rect().bottom(); - float zeroP = _zeroPos * get_view_rect().height() + top; - if (strcmp(_dev_inst->dev_inst()->driver->name, "DSCope") == 0 && + float zeroP = _zero_vrate * get_view_rect().height() + top; + if (_dev_inst->name() == "DSCope" && _view->session().get_capture_state() == SigSession::Running) - _zero_off = _zeroPos * 255; + _zero_value = _zero_vrate * ((1 << _bits) - 1); for(uint64_t sample = 0; sample < e.length-1; sample++) { const float x = ((e.scale * sample + e.start) / samples_per_pixel - pixels_offset) + left; @@ -1001,8 +1068,8 @@ void DsoSignal::paint_envelope(QPainter &p, // We overlap this sample with the next so that vertical // gaps do not appear during steep rising or falling edges - const float b = min(max(top, ((max(s->max, (s+1)->min) - _zero_off) * _scale + zeroP)), bottom); - const float t = min(max(top, ((min(s->min, (s+1)->max) - _zero_off) * _scale + zeroP)), bottom); + const float b = min(max(top, ((max(s->max, (s+1)->min) - _zero_value) * _scale + zeroP)), bottom); + const float t = min(max(top, ((min(s->min, (s+1)->max) - _zero_value) * _scale + zeroP)), bottom); float h = b - t; if(h >= 0.0f && h <= 1.0f) @@ -1066,23 +1133,23 @@ void DsoSignal::paint_type_options(QPainter &p, int right, const QPoint pt) return; } - p.setPen(Qt::white); + p.setPen(Qt::transparent); p.setBrush((enabled() && (factor == 100)) ? (x100_rect.contains(pt) ? _colour.darker() : _colour) : (x100_rect.contains(pt) ? _colour.darker() : dsDisable)); p.drawRect(x100_rect); - p.drawText(x100_rect, Qt::AlignCenter | Qt::AlignVCenter, "x100"); - p.setBrush((enabled() && (factor == 10)) ? (x10_rect.contains(pt) ? _colour.darker() : _colour) : (x10_rect.contains(pt) ? _colour.darker() : dsDisable)); p.drawRect(x10_rect); - p.drawText(x10_rect, Qt::AlignCenter | Qt::AlignVCenter, "x10"); - p.setBrush((enabled() && (factor == 1)) ? (x1_rect.contains(pt) ? _colour.darker() : _colour) : (x1_rect.contains(pt) ? _colour.darker() : dsDisable)); p.drawRect(x1_rect); + + p.setPen(Qt::white); + p.drawText(x100_rect, Qt::AlignCenter | Qt::AlignVCenter, "x100"); + p.drawText(x10_rect, Qt::AlignCenter | Qt::AlignVCenter, "x10"); p.drawText(x1_rect, Qt::AlignCenter | Qt::AlignVCenter, "x1"); } bool DsoSignal::mouse_double_click(int right, const QPoint pt) { - int y = get_zeroPos(); + int y = get_zero_vpos(); const QRectF label_rect = Trace::get_rect("label", y, right); if (label_rect.contains(pt)) { this->auto_set(); @@ -1095,7 +1162,7 @@ bool DsoSignal::mouse_press(int right, const QPoint pt) { int y = get_y(); bool setted = false; - const vector< boost::shared_ptr > traces(_view->get_traces()); + const vector< boost::shared_ptr > traces(_view->get_traces(ALL_VIEW)); const QRectF vDec_rect = get_rect(DSO_VDEC, y, right); const QRectF vInc_rect = get_rect(DSO_VINC, y, right); const QRectF hDec_rect = get_rect(DSO_HDEC, y, right); @@ -1107,7 +1174,7 @@ bool DsoSignal::mouse_press(int right, const QPoint pt) const QRectF x100_rect = get_rect(DSO_X100, y, right); if (chEn_rect.contains(pt)) { - if (strcmp(_dev_inst->dev_inst()->driver->name, "virtual-session") && + if (_dev_inst->name() != "virtual-session" && !_view->session().get_data_lock()) set_enable(!enabled()); return true; @@ -1132,12 +1199,12 @@ bool DsoSignal::mouse_press(int right, const QPoint pt) setted = true; } } - } else if (strcmp(_dev_inst->dev_inst()->driver->name, "virtual-session") && + } else if (_dev_inst->name() != "virtual-session" && acdc_rect.contains(pt)) { - if (strcmp(_view->session().get_device()->dev_inst()->driver->name, "DSLogic") == 0) + if (_dev_inst->name() == "DSLogic") set_acCoupling((get_acCoupling()+1)%2); else - set_acCoupling((get_acCoupling()+1)%3); + set_acCoupling((get_acCoupling()+1)%2); } else if (x1_rect.contains(pt)) { set_factor(1); } else if (x10_rect.contains(pt)) { @@ -1156,25 +1223,25 @@ bool DsoSignal::mouse_wheel(int right, const QPoint pt, const int shift) { int y = get_y(); const vector< boost::shared_ptr > traces( - _view->get_traces()); + _view->get_traces(ALL_VIEW)); bool setted = false; const QRectF vDial_rect = get_rect(DSO_VDIAL, y, right); const QRectF hDial_rect = get_rect(DSO_HDIAL, y, right); if (vDial_rect.contains(pt)) { - if (shift > 1.0) + if (shift > 0.5) go_vDialNext(); - else if (shift < -1.0) + else if (shift < -0.5) go_vDialPre(); return true; } else if (hDial_rect.contains(pt)) { boost::shared_ptr dsoSig; BOOST_FOREACH(const boost::shared_ptr t, traces) { if (dsoSig = dynamic_pointer_cast(t)) { - if (shift > 1.0) { + if (shift > 0.5) { dsoSig->go_hDialNext(setted); setted = true; - } else if (shift < -1.0) { + } else if (shift < -0.5) { dsoSig->go_hDialPre(setted); setted = true; } @@ -1261,8 +1328,8 @@ void DsoSignal::paint_measure(QPainter &p) _min = (index == 0) ? status.ch0_min : status.ch1_min; const uint64_t period = (index == 0) ? status.ch0_period : status.ch1_period; const uint32_t count = (index == 0) ? status.ch0_pcnt : status.ch1_pcnt; - double value_max = (_zero_off - _min) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); - double value_min = (_zero_off - _max) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); + double value_max = (_zero_value - _min) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); + double value_min = (_zero_value - _max) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); double value_p2p = value_max - value_min; _period = (count == 0) ? period * 10.0 : period * 10.0 / count; const int channel_count = _view->session().get_ch_num(SR_CHANNEL_DSO); @@ -1277,26 +1344,26 @@ void DsoSignal::paint_measure(QPainter &p) abs(_period) > 1000 ? QString::number(1000000/_period, 'f', 2) + "kHz" : QString::number(1000/_period, 'f', 2) + "MHz"); _ms_string[DSO_MS_VP2P] = "Vp-p: " + (abs(value_p2p) > 1000 ? QString::number(value_p2p/1000.0, 'f', 2) + "V" : QString::number(value_p2p, 'f', 2) + "mV"); - if (_ms_show && _ms_en[DSO_MS_VRMS]) { + if (_probe->ms_show && _probe->ms_en[DSO_MS_VRMS]) { const deque< boost::shared_ptr > &snapshots = _data->get_snapshots(); if (!snapshots.empty()) { const boost::shared_ptr &snapshot = snapshots.front(); - const double vrms = snapshot->cal_vrms(_zero_off, get_index()); + const double vrms = snapshot->cal_vrms(_zero_value, get_index()); const double value_vrms = vrms * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); _ms_string[DSO_MS_VRMS] = "Vrms: " + (abs(value_vrms) > 1000 ? QString::number(value_vrms/1000.0, 'f', 2) + "V" : QString::number(value_vrms, 'f', 2) + "mV"); } } - if (_ms_show && _ms_en[DSO_MS_VMEA]) { + if (_probe->ms_show && _probe->ms_en[DSO_MS_VMEA]) { const deque< boost::shared_ptr > &snapshots = _data->get_snapshots(); if (!snapshots.empty()) { const boost::shared_ptr &snapshot = snapshots.front(); const double vmean = snapshot->cal_vmean(get_index()); - const double value_vmean = (_zero_off - vmean) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); + const double value_vmean = (_zero_value - vmean) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); _ms_string[DSO_MS_VMEA] = "Vmean: " + (abs(value_vmean) > 1000 ? QString::number(value_vmean/1000.0, 'f', 2) + "V" : QString::number(value_vmean, 'f', 2) + "mV"); } } @@ -1322,7 +1389,7 @@ void DsoSignal::paint_measure(QPainter &p) p.setBrush(measure_colour); p.drawRoundedRect(_ms_rect[DSO_MS_BEGIN], MS_RectRad, MS_RectRad); const QPixmap gear_pix(":/icons/settings.png"); - const QPixmap show_pix(_ms_show ? ":/icons/shown.png" : ":/icons/hidden.png"); + const QPixmap show_pix(_probe->ms_show ? ":/icons/shown.png" : ":/icons/hidden.png"); if (_ms_gear_hover) { p.setBrush(back_colour); p.drawRoundedRect(_ms_gear_rect, MS_RectRad, MS_RectRad); @@ -1335,11 +1402,11 @@ void DsoSignal::paint_measure(QPainter &p) p.setPen(Qt::white); p.drawText(_ms_rect[DSO_MS_BEGIN], Qt::AlignCenter | Qt::AlignVCenter, "CH"+QString::number(index)); - if (_ms_show) { + if (_probe->ms_show) { p.setBrush(back_colour); int j = DSO_MS_BEGIN+1; for (int i=DSO_MS_BEGIN+1; ims_en[i]) { p.setPen(_colour); p.drawText(_ms_rect[j], Qt::AlignLeft | Qt::AlignVCenter, _ms_string[i]); p.setPen(Qt::NoPen); @@ -1363,7 +1430,7 @@ void DsoSignal::paint_measure(QPainter &p) bool setted = false; if (_autoH) { - const vector< boost::shared_ptr > traces(_view->get_traces()); + const vector< boost::shared_ptr > traces(_view->get_traces(ALL_VIEW)); const double upPeriod = get_hDialValue() * DS_CONF_DSO_HDIVS * 0.8; const double dnPeriod = get_hDialValue() * DS_CONF_DSO_HDIVS * 0.2; if (_period > upPeriod) { @@ -1386,7 +1453,7 @@ void DsoSignal::paint_measure(QPainter &p) } } } - _view->update(); + //_view->update(); } void DsoSignal::auto_set() @@ -1404,18 +1471,18 @@ bool DsoSignal::measure(const QPointF &p) { if (_ms_gear_rect.contains(QPoint(p.x(), p.y()))) { _ms_gear_hover = true; - _view->set_need_update(true); + _view->set_update(_viewport, true); return false; } else if (_ms_gear_hover) { - _view->set_need_update(true); + _view->set_update(_viewport, true); _ms_gear_hover = false; } if (_ms_show_rect.contains(QPoint(p.x(), p.y()))) { _ms_show_hover = true; - _view->set_need_update(true); + _view->set_update(_viewport, true); return false; } else if (_ms_show_hover){ - _view->set_need_update(true); + _view->set_update(_viewport, true); _ms_show_hover = false; } @@ -1434,7 +1501,7 @@ bool DsoSignal::measure(const QPointF &p) const boost::shared_ptr &snapshot = snapshots.front(); - if (snapshot->buf_null()) + if (snapshot->empty()) return false; const double scale = _view->scale(); @@ -1462,17 +1529,17 @@ bool DsoSignal::measure(const QPointF &p) const uint8_t cur_sample = *snapshot->get_samples(_hover_index, _hover_index, get_index()); const uint8_t nxt_sample = *snapshot->get_samples(nxt_index, nxt_index, get_index()); - _hover_value = (_zero_off - cur_sample) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); + _hover_value = (_zero_value - cur_sample) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); float top = get_view_rect().top(); float bottom = get_view_rect().bottom(); - float zeroP = _zeroPos * get_view_rect().height() + top; + float zeroP = _zero_vrate * get_view_rect().height() + top; float pre_x = (pre_index / samples_per_pixel - pixels_offset); - const float pre_y = min(max(top, zeroP + (pre_sample - _zero_off)* _scale), bottom); + const float pre_y = min(max(top, zeroP + (pre_sample - _zero_value)* _scale), bottom); float x = (_hover_index / samples_per_pixel - pixels_offset); - const float y = min(max(top, zeroP + (cur_sample - _zero_off)* _scale), bottom); + const float y = min(max(top, zeroP + (cur_sample - _zero_value)* _scale), bottom); float nxt_x = (nxt_index / samples_per_pixel - pixels_offset); - const float nxt_y = min(max(top, zeroP + (nxt_sample - _zero_off)* _scale), bottom); + const float nxt_y = min(max(top, zeroP + (nxt_sample - _zero_value)* _scale), bottom); const QRectF slope_rect = QRectF(QPointF(pre_x - 10, pre_y - 10), QPointF(nxt_x + 10, nxt_y + 10)); if (abs(y-p.y()) < 20 || slope_rect.contains(p)) { _hover_point = QPointF(x, y); diff --git a/DSView/pv/view/dsosignal.h b/DSView/pv/view/dsosignal.h index a2669d8a..790bd61c 100644 --- a/DSView/pv/view/dsosignal.h +++ b/DSView/pv/view/dsosignal.h @@ -2,7 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -43,7 +43,6 @@ class DsoSignal : public Signal private: static const QColor SignalColours[4]; static const float EnvelopeThreshold; - static const double TrigMargin; static const int HitCursorMargin = 3; static const uint64_t vDialValueCount = 8; @@ -58,23 +57,16 @@ private: static const uint64_t hDialValue[hDialValueCount]; static const QString hDialUnit[hDialUnitCount]; - static const int UpMargin; - static const int DownMargin; - static const int RightMargin; + static const int UpMargin = 30; + static const int DownMargin = 0; + static const int RightMargin = 30; + + static const uint8_t DefaultBits = 8; + static const int TrigMargin = 16; + static const int RefreshShort = 200; + static const int RefreshLong = 800; public: - enum DSO_MEASURE_TYPE { - DSO_MS_BEGIN = 0, - DSO_MS_FREQ, - DSO_MS_PERD, - DSO_MS_VMAX, - DSO_MS_VMIN, - DSO_MS_VRMS, - DSO_MS_VMEA, - DSO_MS_VP2P, - DSO_MS_END, - }; - enum DsoSetRegions { DSO_NONE = -1, DSO_VDIAL, @@ -100,12 +92,13 @@ private: public: DsoSignal(boost::shared_ptr dev_inst, boost::shared_ptr data, - const sr_channel * const probe); + sr_channel *probe); virtual ~DsoSignal(); boost::shared_ptr data() const; - void set_view(pv::view::View *view); + boost::shared_ptr dso_data() const; + void set_viewport(pv::view::Viewport *viewport); void set_scale(float scale); float get_scale(); @@ -129,14 +122,15 @@ public: uint16_t get_hDialSel() const; uint8_t get_acCoupling() const; void set_acCoupling(uint8_t coupling); - void set_trig_vpos(int pos); + void set_trig_vpos(int pos, bool delta_change); int get_trig_vpos() const; - void set_trigRate(double rate); - double get_trigRate() const; + void set_trig_vrate(double rate); + double get_trig_vrate() const; void set_factor(uint64_t factor); uint64_t get_factor(); bool load_settings(); + int commit_settings(); /** * @@ -152,14 +146,15 @@ public: /** * Gets the mid-Y position of this signal. */ - int get_zeroPos(); - double get_zeroRate(); + int get_zero_vpos(); + double get_zero_vrate(); + double get_zero_value(); /** * Sets the mid-Y position of this signal. */ - void set_zeroPos(int pos); - void set_zeroRate(double rate); - void update_zeroPos(); + void set_zero_vpos(int pos); + void set_zero_vrate(double rate); + void update_offset(); /** * Paints the background layer of the trace with a QPainter @@ -187,7 +182,7 @@ public: const std::vector< std::pair > cur_edges() const; - QRectF get_view_rect() const; + QRect get_view_rect() const; QRectF get_trig_rect(int left, int right) const; @@ -234,10 +229,12 @@ private: bool _vDialActive; bool _hDialActive; uint8_t _acCoupling; + uint8_t _bits; - double _trig_vpos; - double _zeroPos; - float _zero_off; + int _trig_value; + double _trig_delta; + double _zero_vrate; + float _zero_value; uint8_t _max; uint8_t _min; diff --git a/DSView/pv/view/groupsignal.cpp b/DSView/pv/view/groupsignal.cpp index d5402acb..b48eefe5 100644 --- a/DSView/pv/view/groupsignal.cpp +++ b/DSView/pv/view/groupsignal.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -51,7 +50,7 @@ GroupSignal::GroupSignal(QString name, boost::shared_ptr data, _data(data) { _colour = SignalColours[probe_index_list.front() % countof(SignalColours)]; - _scale = _signalHeight * 1.0f / std::pow(2.0, static_cast(probe_index_list.size())); + _scale = _totalHeight * 1.0f / std::pow(2.0, static_cast(probe_index_list.size())); } GroupSignal::~GroupSignal() @@ -79,12 +78,12 @@ void GroupSignal::paint_mid(QPainter &p, int left, int right) assert(_view); assert(right >= left); - const int y = get_y() + _signalHeight * 0.5; + const int y = get_y() + _totalHeight * 0.5; const double scale = _view->scale(); assert(scale > 0); const double offset = _view->offset(); - _scale = _signalHeight * 1.0f / std::pow(2.0, static_cast(_index_list.size())); + _scale = _totalHeight * 1.0f / std::pow(2.0, static_cast(_index_list.size())); const deque< boost::shared_ptr > &snapshots = _data->get_snapshots(); @@ -204,9 +203,8 @@ void GroupSignal::paint_type_options(QPainter &p, int right, const QPoint pt) const QRectF group_index_rect = get_rect(CHNLREG, y, right); QString index_string; int last_index; - p.setPen(Qt::transparent); - p.setBrush(dsBlue); - p.drawRect(group_index_rect); + p.setPen(QPen(DARK_FORE, 1, Qt::DashLine)); + p.drawLine(group_index_rect.bottomLeft(), group_index_rect.bottomRight()); std::list::iterator i = _index_list.begin(); last_index = (*i); index_string = QString::number(last_index); @@ -219,7 +217,7 @@ void GroupSignal::paint_type_options(QPainter &p, int right, const QPoint pt) index_string = QString::number((*i)) + "," + index_string; last_index = (*i); } - p.setPen(Qt::white); + p.setPen(DARK_FORE); p.drawText(group_index_rect, Qt::AlignRight | Qt::AlignVCenter, index_string); } diff --git a/DSView/pv/view/groupsignal.h b/DSView/pv/view/groupsignal.h index 0aa18282..711382ca 100644 --- a/DSView/pv/view/groupsignal.h +++ b/DSView/pv/view/groupsignal.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 diff --git a/DSView/pv/view/header.cpp b/DSView/pv/view/header.cpp index e6d20c37..6e5e430e 100644 --- a/DSView/pv/view/header.cpp +++ b/DSView/pv/view/header.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -24,6 +24,7 @@ #include "header.h" #include "view.h" +#include "../../extdef.h" #include "trace.h" #include "dsosignal.h" #include "logicsignal.h" @@ -45,7 +46,6 @@ #include #include #include -#include using namespace boost; using namespace std; @@ -95,7 +95,7 @@ boost::shared_ptr Header::get_mTrace( { const int w = width(); const vector< boost::shared_ptr > traces( - _view.get_traces()); + _view.get_traces(ALL_VIEW)); BOOST_FOREACH(const boost::shared_ptr t, traces) { @@ -115,14 +115,14 @@ void Header::paintEvent(QPaintEvent*) QStyleOption o; o.initFrom(this); QPainter painter(this); + //painter.setRenderHint(QPainter::Antialiasing); style()->drawPrimitive(QStyle::PE_Widget, &o, &painter, this); + //painter.begin(this); + const int w = width(); const vector< boost::shared_ptr > traces( - _view.get_traces()); - - //QPainter painter(this); - //painter.setRenderHint(QPainter::Antialiasing); + _view.get_traces(ALL_VIEW)); const bool dragging = !_drag_traces.empty(); BOOST_FOREACH(const boost::shared_ptr t, traces) @@ -139,7 +139,7 @@ void Header::mouseDoubleClickEvent(QMouseEvent *event) assert(event); const vector< boost::shared_ptr > traces( - _view.get_traces()); + _view.get_traces(ALL_VIEW)); if (event->button() & Qt::LeftButton) { _mouse_down_point = event->pos(); @@ -163,7 +163,7 @@ void Header::mousePressEvent(QMouseEvent *event) assert(event); const vector< boost::shared_ptr > traces( - _view.get_traces()); + _view.get_traces(ALL_VIEW)); int action; const bool instant = _view.session().get_instant(); if (instant && _view.session().get_capture_state() == SigSession::Running) @@ -198,7 +198,7 @@ void Header::mousePressEvent(QMouseEvent *event) // Add the Trace to the drag list if (event->button() & Qt::LeftButton) { - _drag_traces.push_back(make_pair(mTrace, mTrace->get_zeroPos())); + _drag_traces.push_back(make_pair(mTrace, mTrace->get_zero_vpos())); } } mTrace->set_old_v_offset(mTrace->get_v_offset()); @@ -231,7 +231,7 @@ void Header::mouseReleaseEvent(QMouseEvent *event) if (action == Trace::COLOR && _colorFlag) { _context_trace = mTrace; changeColor(event); - _view.set_need_update(true); + _view.set_all_update(true); } else if (action == Trace::NAME && _nameFlag) { _context_trace = mTrace; changeName(event); @@ -240,7 +240,7 @@ void Header::mouseReleaseEvent(QMouseEvent *event) if (_moveFlag) { //move(event); _view.signals_changed(); - _view.set_need_update(true); + _view.set_all_update(true); } _colorFlag = false; _nameFlag = false; @@ -255,9 +255,9 @@ void Header::wheelEvent(QWheelEvent *event) if (event->orientation() == Qt::Vertical) { const vector< boost::shared_ptr > traces( - _view.get_traces()); + _view.get_traces(ALL_VIEW)); // Vertical scrolling - double shift = event->delta() / 20.0; + double shift = event->delta() / 80.0; BOOST_FOREACH(const boost::shared_ptr t, traces) if (t->mouse_wheel(width(), event->pos(), shift)) break; @@ -315,7 +315,7 @@ void Header::mouseMoveEvent(QMouseEvent *event) } else { boost::shared_ptr dsoSig; if (dsoSig = dynamic_pointer_cast(sig)) { - dsoSig->set_zeroPos(y); + dsoSig->set_zero_vpos(y); dsoSig->select(false); traces_moved(); } diff --git a/DSView/pv/view/header.h b/DSView/pv/view/header.h index 89d637ef..6d11b2fd 100644 --- a/DSView/pv/view/header.h +++ b/DSView/pv/view/header.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 diff --git a/DSView/pv/view/logicsignal.cpp b/DSView/pv/view/logicsignal.cpp index 3ae1c9dd..e5d543b8 100644 --- a/DSView/pv/view/logicsignal.cpp +++ b/DSView/pv/view/logicsignal.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -23,6 +23,8 @@ #include +#include + #include #include "logicsignal.h" @@ -44,41 +46,25 @@ const QColor LogicSignal::EdgeColour(0x80, 0x80, 0x80); const QColor LogicSignal::HighColour(0x00, 0xC0, 0x00); const QColor LogicSignal::LowColour(0xC0, 0x00, 0x00); -const QColor LogicSignal::SignalColours[8] = { - QColor(0x16, 0x19, 0x1A), // Black - QColor(0x8F, 0x52, 0x02), // Brown - QColor(0xCC, 0x00, 0x00), // Red - QColor(0xF5, 0x79, 0x00), // Orange - QColor(0xED, 0xD4, 0x00), // Yellow - QColor(0x73, 0xD2, 0x16), // Green - QColor(0x34, 0x65, 0xA4), // Blue - QColor(0x75, 0x50, 0x7B), // Violet -// QColor(17, 133, 209), -// QColor(17, 133, 209), -// QColor(17, 133, 209), -// QColor(17, 133, 209), -// QColor(17, 133, 209), -// QColor(17, 133, 209), -// QColor(17, 133, 209), -// QColor(17, 133, 209), -}; +const QColor LogicSignal::DEFAULT_COLOR = QColor(150, 150, 150, 255); const int LogicSignal::StateHeight = 12; const int LogicSignal::StateRound = 5; LogicSignal::LogicSignal(boost::shared_ptr dev_inst, boost::shared_ptr data, - const sr_channel * const probe) : - Signal(dev_inst, probe, SR_CHANNEL_LOGIC), + sr_channel *probe) : + Signal(dev_inst, probe), _data(data), _trig(NONTRIG) { - _colour = SignalColours[probe->index % countof(SignalColours)]; + //_colour = PROBE_COLORS[probe->index % countof(PROBE_COLORS)]; + _colour = DEFAULT_COLOR; } LogicSignal::LogicSignal(boost::shared_ptr s, boost::shared_ptr data, - const sr_channel * const probe) : + sr_channel *probe) : Signal(*s.get(), probe), _data(data), _trig(s->get_trig()) @@ -148,33 +134,28 @@ void LogicSignal::paint_mid(QPainter &p, int left, int right) assert(_view); assert(right >= left); - const int y = get_y() + _signalHeight * 0.5; + const int y = get_y() + _totalHeight * 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 high_offset = y - _totalHeight + 0.5f; const float low_offset = y + 0.5f; const deque< boost::shared_ptr > &snapshots = _data->get_snapshots(); - if (snapshots.empty()) + double samplerate = _data->samplerate(); + if (snapshots.empty() || samplerate == 0) return; const boost::shared_ptr &snapshot = snapshots.front(); - if (snapshot->buf_null()) + if (snapshot->empty()) return; - double samplerate = _data->samplerate(); - - // Show sample rate as 1Hz when it is unknown - if (samplerate == 0.0) - samplerate = 1.0; - const double pixels_offset = offset / scale; const double start_time = _data->get_start_time(); - const int64_t last_sample = snapshot->get_sample_count() - 1; + const int64_t last_sample = snapshot->get_sample_count() - 1; const double samples_per_pixel = samplerate * scale; const double start = samplerate * (offset - start_time); const double end = start + samples_per_pixel * (right - left); @@ -249,35 +230,37 @@ void LogicSignal::paint_type_options(QPainter &p, int right, const QPoint pt) const QRectF lowTrig_rect = get_rect(LOWTRIG, y, right); const QRectF edgeTrig_rect = get_rect(EDGTRIG, y, right); - p.setPen(Qt::transparent); - p.setBrush(posTrig_rect.contains(pt) ? dsYellow.darker() : - (_trig == POSTRIG) ? dsYellow : dsBlue); + p.setPen(Qt::NoPen); + p.setBrush(posTrig_rect.contains(pt) ? dsBlue.lighter() : + (_trig == POSTRIG) ? dsBlue : DARK_BACK); p.drawRect(posTrig_rect); - p.setBrush(higTrig_rect.contains(pt) ? dsYellow.darker() : - (_trig == HIGTRIG) ? dsYellow : dsBlue); + p.setBrush(higTrig_rect.contains(pt) ? dsBlue.lighter() : + (_trig == HIGTRIG) ? dsBlue : DARK_BACK); p.drawRect(higTrig_rect); - p.setBrush(negTrig_rect.contains(pt) ? dsYellow.darker() : - (_trig == NEGTRIG) ? dsYellow : dsBlue); + p.setBrush(negTrig_rect.contains(pt) ? dsBlue.lighter() : + (_trig == NEGTRIG) ? dsBlue : DARK_BACK); p.drawRect(negTrig_rect); - p.setBrush(lowTrig_rect.contains(pt) ? dsYellow.darker() : - (_trig == LOWTRIG) ? dsYellow : dsBlue); + p.setBrush(lowTrig_rect.contains(pt) ? dsBlue.lighter() : + (_trig == LOWTRIG) ? dsBlue : DARK_BACK); p.drawRect(lowTrig_rect); - p.setBrush(edgeTrig_rect.contains(pt) ? dsYellow.darker() : - (_trig == EDGTRIG) ? dsYellow : dsBlue); + p.setBrush(edgeTrig_rect.contains(pt) ? dsBlue.lighter() : + (_trig == EDGTRIG) ? dsBlue : DARK_BACK); p.drawRect(edgeTrig_rect); - p.setPen(QPen(Qt::blue, 1, Qt::DotLine)); + p.setPen(QPen(DARK_FORE, 1, Qt::DashLine)); 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.drawLine(posTrig_rect.right(), posTrig_rect.top(), +// posTrig_rect.right(), posTrig_rect.bottom()); +// p.drawLine(higTrig_rect.right(), higTrig_rect.top(), +// higTrig_rect.right(), higTrig_rect.bottom()); +// p.drawLine(negTrig_rect.right(), negTrig_rect.top(), +// negTrig_rect.right(), negTrig_rect.bottom()); +// p.drawLine(lowTrig_rect.right(), lowTrig_rect.top(), +// lowTrig_rect.right(), lowTrig_rect.bottom()); + p.drawLine(posTrig_rect.left(), posTrig_rect.bottom(), + edgeTrig_rect.right(), edgeTrig_rect.bottom()); - p.setPen(QPen(Qt::white, 2, Qt::SolidLine)); + p.setPen(QPen(DARK_FORE, 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); @@ -314,7 +297,7 @@ void LogicSignal::paint_type_options(QPainter &p, int right, const QPoint pt) bool LogicSignal::measure(const QPointF &p, uint64_t &index0, uint64_t &index1, uint64_t &index2) const { const float gap = abs(p.y() - get_y()); - if (gap < get_signalHeight() * 0.5) { + if (gap < get_totalHeight() * 0.5) { const deque< boost::shared_ptr > &snapshots = _data->get_snapshots(); if (snapshots.empty()) @@ -322,7 +305,7 @@ bool LogicSignal::measure(const QPointF &p, uint64_t &index0, uint64_t &index1, const boost::shared_ptr &snapshot = snapshots.front(); - if (snapshot->buf_null()) + if (snapshot->empty()) return false; uint64_t index = _data->samplerate() * (_view->offset() - _data->get_start_time() + p.x() * _view->scale()); @@ -359,7 +342,7 @@ bool LogicSignal::edges(const QPointF &p, uint64_t start, uint64_t &rising, uint { uint64_t index, end; const float gap = abs(p.y() - get_y()); - if (gap < get_signalHeight() * 0.5) { + if (gap < get_totalHeight() * 0.5) { const deque< boost::shared_ptr > &snapshots = _data->get_snapshots(); if (snapshots.empty()) @@ -367,7 +350,7 @@ bool LogicSignal::edges(const QPointF &p, uint64_t start, uint64_t &rising, uint const boost::shared_ptr &snapshot = snapshots.front(); - if (snapshot->buf_null()) + if (snapshot->empty()) return false; end = _data->samplerate() * (_view->offset() - _data->get_start_time() + p.x() * _view->scale()); diff --git a/DSView/pv/view/logicsignal.h b/DSView/pv/view/logicsignal.h index 5f4ba7d1..32f00683 100644 --- a/DSView/pv/view/logicsignal.h +++ b/DSView/pv/view/logicsignal.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -48,7 +48,7 @@ private: static const QColor HighColour; static const QColor LowColour; - static const QColor SignalColours[8]; + static const QColor DEFAULT_COLOR; static const int StateHeight; static const int StateRound; @@ -65,11 +65,11 @@ private: public: LogicSignal(boost::shared_ptr dev_inst, boost::shared_ptr data, - const sr_channel * const probe); + sr_channel *probe); LogicSignal(boost::shared_ptr s, boost::shared_ptr data, - const sr_channel * const probe); + sr_channel *probe); virtual ~LogicSignal(); diff --git a/DSView/pv/view/mathtrace.cpp b/DSView/pv/view/mathtrace.cpp new file mode 100644 index 00000000..0b6b6f4c --- /dev/null +++ b/DSView/pv/view/mathtrace.cpp @@ -0,0 +1,487 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2016 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 "mathtrace.h" + +#include +#include + +#include +#include + +#include "../sigsession.h" +#include "../data/dso.h" +#include "../data/dsosnapshot.h" +#include "../view/dsosignal.h" +#include "../view/viewport.h" +#include "../device/devinst.h" + +#include "../data/mathstack.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace view { + +const int MathTrace::UpMargin = 0; +const int MathTrace::DownMargin = 0; +const int MathTrace::RightMargin = 30; +const QString MathTrace::FFT_ViewMode[2] = { + "Linear RMS", + "DBV RMS" +}; + +const QString MathTrace::FreqPrefixes[9] = + {"", "", "", "", "K", "M", "G", "T", "P"}; +const int MathTrace::FirstSIPrefixPower = -9; +const int MathTrace::LastSIPrefixPower = 15; +const int MathTrace::Pricision = 2; +const int MathTrace::FreqMinorDivNum = 10; +const int MathTrace::TickHeight = 15; +const int MathTrace::VolDivNum = 5; + +const int MathTrace::DbvRanges[4] = { + 100, + 120, + 150, + 200, +}; + +const int MathTrace::HoverPointSize = 3; +const double MathTrace::VerticalRate = 1.0 / 2000.0; + +MathTrace::MathTrace(pv::SigSession &session, + boost::shared_ptr math_stack, int index) : + Trace("FFT("+QString::number(index)+")", index, SR_CHANNEL_FFT), + _session(session), + _math_stack(math_stack), + _enable(false), + _view_mode(0), + _hover_en(false), + _scale(1), + _offset(0) +{ + const vector< boost::shared_ptr > sigs(_session.get_signals()); + for(size_t i = 0; i < sigs.size(); i++) { + const boost::shared_ptr s(sigs[i]); + assert(s); + if (dynamic_pointer_cast(s) && index == s->get_index()) + _colour = s->get_colour(); + } +} + +MathTrace::~MathTrace() +{ + +} + +bool MathTrace::enabled() const +{ + return _enable; +} + +void MathTrace::set_enable(bool enable) +{ + _enable = enable; +} + +int MathTrace::view_mode() const +{ + return _view_mode; +} + +void MathTrace::set_view_mode(int mode) +{ + assert(mode < sizeof(FFT_ViewMode)/sizeof(FFT_ViewMode[0])); + _view_mode = mode; +} + +std::vector MathTrace::get_view_modes_support() +{ + std::vector modes; + for (unsigned int i = 0; i < sizeof(FFT_ViewMode)/sizeof(FFT_ViewMode[0]); i++) { + modes.push_back(FFT_ViewMode[i]); + } + return modes; +} + +const boost::shared_ptr& MathTrace::get_math_stack() const +{ + return _math_stack; +} + +void MathTrace::init_zoom() +{ + _scale = 1; + _offset = 0; +} + +void MathTrace::zoom(double steps, int offset) +{ + if (!_view) + return; + + const int width = get_view_rect().width(); + double pre_offset = _offset + _scale*offset/width; + _scale *= std::pow(3.0/2.0, -steps); + _scale = max(min(_scale, 1.0), 100.0/_math_stack->get_sample_num()); + _offset = pre_offset - _scale*offset/width; + _offset = max(min(_offset, 1-_scale), 0.0); + + _view->set_update(_viewport, true); + _view->update(); +} + +void MathTrace::set_offset(double delta) +{ + int width = get_view_rect().width(); + _offset = _offset + (delta*_scale / width); + _offset = max(min(_offset, 1-_scale), 0.0); + + _view->set_update(_viewport, true); + _view->update(); +} + +double MathTrace::get_offset() const +{ + return _offset; +} + +void MathTrace::set_scale(double scale) +{ + _scale = max(min(scale, 1.0), 100.0/_math_stack->get_sample_num()); + + _view->set_update(_viewport, true); + _view->update(); +} + +double MathTrace::get_scale() const +{ + return _scale; +} + +void MathTrace::set_dbv_range(int range) +{ + _dbv_range = range; +} + +int MathTrace::dbv_range() const +{ + return _dbv_range; +} + +std::vector MathTrace::get_dbv_ranges() +{ + std::vector range; + for (unsigned int i = 0; i < sizeof(DbvRanges)/sizeof(DbvRanges[0]); i++) { + range.push_back(DbvRanges[i]); + } + return range; +} + +QString MathTrace::format_freq(double freq, unsigned precision) +{ + if (freq <= 0) { + return "0Hz"; + } else { + const int order = floor(log10f(freq)); + assert(order >= FirstSIPrefixPower); + assert(order <= LastSIPrefixPower); + const int prefix = floor((order - FirstSIPrefixPower)/ 3.0f); + const double divider = pow(10.0, max(prefix * 3.0 + FirstSIPrefixPower, 0.0)); + + QString s; + QTextStream ts(&s); + ts.setRealNumberPrecision(precision); + ts << fixed << freq / divider << + FreqPrefixes[prefix] << "Hz"; + return s; + } +} + +bool MathTrace::measure(const QPoint &p) +{ + _hover_en = false; + if(!_view || !enabled()) + return false; + + const QRect window = get_view_rect(); + if (!window.contains(p)) + return false; + + const std::vector samples(_math_stack->get_fft_spectrum()); + if(samples.empty()) + return false; + + const unsigned int full_size = (_math_stack->get_sample_num()/2); + const double view_off = full_size * _offset; + const double view_size = full_size*_scale; + const double sample_per_pixels = view_size/window.width(); + _hover_index = std::round(p.x() * sample_per_pixels + view_off); + + if (_hover_index < full_size) + _hover_en = true; + + //_view->set_update(_viewport, true); + _view->update(); + return true; +} + + +void MathTrace::paint_back(QPainter &p, int left, int right) +{ + if(!_view) + return; + + const int height = get_view_rect().height(); + const int width = right - left; + + QPen solidPen(Signal::dsFore); + solidPen.setStyle(Qt::SolidLine); + p.setPen(solidPen); + p.setBrush(Trace::dsBack); + p.drawRect(left, UpMargin, width, height); +} + +void MathTrace::paint_mid(QPainter &p, int left, int right) +{ + if(!_view) + return; + assert(right >= left); + + if (enabled()) { + const std::vector samples(_math_stack->get_fft_spectrum()); + if(samples.empty()) + return; + + QColor trace_colour = _colour; + trace_colour.setAlpha(150); + p.setPen(trace_colour); + + const int full_size = (_math_stack->get_sample_num()/2); + const double view_off = full_size * _offset; + const int view_start = floor(view_off); + const int view_size = full_size*_scale; + QPointF *points = new QPointF[samples.size()]; + QPointF *point = points; + + const bool dc_ignored = _math_stack->dc_ignored(); + const double height = get_view_rect().height(); + const double width = right - left; + const double pixels_per_sample = width/view_size; + + double vdiv = 0; + double vfactor = 0; + BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + if(dsoSig->get_index() == _math_stack->get_index()) { + vdiv = dsoSig->get_vDialValue(); + vfactor = dsoSig->get_factor(); + break; + } + } + } + if (_view_mode == 0) { + _vmin = 0; + _vmax = (vdiv*DS_CONF_DSO_HDIVS*vfactor)*VerticalRate; + } else { + _vmax = 20*log10((vdiv*DS_CONF_DSO_HDIVS*vfactor)*VerticalRate); + _vmin = _vmax - _dbv_range; + } + + //const double max_value = *std::max_element(dc_ignored ? ++samples.begin() : samples.begin(), samples.end()); + //const double min_value = *std::min_element(dc_ignored ? ++samples.begin() : samples.begin(), samples.end()); + //_vmax = (_view_mode == 0) ? max_value : 20*log10(max_value); + //_vmin = (_view_mode == 0) ? min_value : 20*log10(min_value); + const double scale = height / (_vmax - _vmin); + + double x = (view_start-view_off)*pixels_per_sample; + uint64_t sample = view_start; + if (dc_ignored && sample == 0) { + sample++; + x += pixels_per_sample; + } + double min_mag = pow(10.0, _vmin/20); + do{ + double mag = samples[sample]; + if (_view_mode != 0) { + if (mag < min_mag) + mag = _vmin; + else + mag = 20*log10(mag); + } + const double y = height - (scale * (mag - _vmin)); + *point++ = QPointF(x, y); + x += pixels_per_sample; + sample++; + }while(x= left); + + (void)left; + (void)right; + const int text_height = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, "8").height(); + const double width = get_view_rect().width(); + const double height = get_view_rect().height(); + double blank_top = 0; + double blank_right = width; + + // horizontal ruler + const double NyFreq = _session.get_device()->get_sample_rate() / (2.0 * _math_stack->get_sample_interval()); + const double deltaFreq = _session.get_device()->get_sample_rate() * 1.0 / + (_math_stack->get_sample_num() * _math_stack->get_sample_interval()); + const double FreqRange = NyFreq * _scale; + const double FreqOffset = NyFreq * _offset; + + const int order = (int)floor(log10(FreqRange)); + const double multiplier = (pow(10.0, order) == FreqRange) ? FreqRange/10 : pow(10.0, order); + const double freq_per_pixel = FreqRange / width; + + p.setPen(Trace::DARK_FORE); + p.setBrush(Qt::NoBrush); + double tick_freq = multiplier * (int)floor(FreqOffset / multiplier); + int division = (int)round(tick_freq * FreqMinorDivNum / multiplier); + double x = (tick_freq - FreqOffset) / freq_per_pixel; + do{ + if (division%FreqMinorDivNum == 0) { + QString freq_str = format_freq(tick_freq); + double typical_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, freq_str).width() + 10; + p.drawLine(x, 1, x, TickHeight); + if (x > typical_width/2 && (width-x) > typical_width/2) + p.drawText(x-typical_width/2, TickHeight, typical_width, text_height, + AlignCenter | AlignTop | TextDontClip, freq_str); + } else { + p.drawLine(x, 1, x, TickHeight/2); + } + tick_freq += multiplier/FreqMinorDivNum; + division++; + x = (tick_freq - FreqOffset) / freq_per_pixel; + } while(x < width); + blank_top = max(blank_top, (double)TickHeight + text_height); + + // delta Frequency + QString freq_str = QString::fromWCharArray(L" \u0394") + "Freq: " + format_freq(deltaFreq,4); + p.drawText(0, 0, width, get_view_rect().height(), + AlignRight | AlignBottom | TextDontClip, freq_str); + double delta_left = width-p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, freq_str).width(); + blank_right = min(delta_left, blank_right); + + // Vertical ruler + const double vRange = _vmax - _vmin; + const double vOffset = _vmin; + const double vol_per_tick = vRange / VolDivNum; + + p.setPen(Trace::DARK_FORE); + p.setBrush(Qt::NoBrush); + double tick_vol = vol_per_tick + vOffset; + double y = height - height / VolDivNum; + const QString unit = (_view_mode == 0) ? "" : "dbv"; + do{ + if (y > text_height && y < (height - text_height)) { + QString vol_str = QString::number(tick_vol, 'f', Pricision) + unit; + double vol_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, vol_str).width(); + p.drawLine(width, y, width-TickHeight/2, y); + p.drawText(width-TickHeight-vol_width, y-text_height/2, vol_width, text_height, + AlignCenter | AlignTop | TextDontClip, vol_str); + blank_right = min(width-TickHeight-vol_width, blank_right); + } + tick_vol += vol_per_tick; + y -= height / VolDivNum; + } while(y > 0); + + // Hover measure + if (_hover_en) { + const std::vector samples(_math_stack->get_fft_spectrum()); + if(samples.empty()) + return; + const int full_size = (_math_stack->get_sample_num()/2); + const double view_off = full_size * _offset; + const int view_size = full_size*_scale; + const double scale = height / (_vmax - _vmin); + const double pixels_per_sample = width/view_size; + double x = (_hover_index-view_off)*pixels_per_sample; + double min_mag = pow(10.0, _vmin/20); + _hover_value = samples[_hover_index]; + if (_view_mode != 0) { + if (_hover_value < min_mag) + _hover_value = _vmin; + else + _hover_value = 20*log10(_hover_value); + } + const double y = height - (scale * (_hover_value - _vmin)); + _hover_point = QPointF(x, y); + + p.setPen(QPen(Trace::DARK_FORE, 1, Qt::DashLine)); + p.setBrush(Qt::NoBrush); + p.drawLine(_hover_point.x(), 0, _hover_point.x(), height); + + QString hover_str = QString::number(_hover_value, 'f', 4) + unit + "@" + format_freq(deltaFreq * _hover_index, 4); + const int hover_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, hover_str).width(); + const int hover_height = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, hover_str).height(); + QRectF hover_rect(_hover_point.x(), _hover_point.y()-hover_height, hover_width, hover_height); + if (hover_rect.right() > blank_right) + hover_rect.moveRight(min(_hover_point.x(), blank_right)); + if (hover_rect.top() < blank_top) + hover_rect.moveTop(max(_hover_point.y(), blank_top)); + if (hover_rect.top() > 0) + p.drawText(hover_rect, AlignCenter | AlignTop | TextDontClip, hover_str); + + p.setPen(Qt::NoPen); + p.setBrush(Trace::DARK_FORE); + p.drawEllipse(_hover_point, HoverPointSize, HoverPointSize); + } +} + +void MathTrace::paint_type_options(QPainter &p, int right, const QPoint pt) +{ + (void)p; + (void)pt; + (void)right; +} + +QRect MathTrace::get_view_rect() const +{ + assert(_viewport); + return QRect(0, UpMargin, + _viewport->width() - RightMargin, + _viewport->height() - UpMargin - DownMargin); +} + +} // namespace view +} // namespace pv diff --git a/DSView/pv/view/mathtrace.h b/DSView/pv/view/mathtrace.h new file mode 100644 index 00000000..7bb39783 --- /dev/null +++ b/DSView/pv/view/mathtrace.h @@ -0,0 +1,156 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2016 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 DSVIEW_PV_VIEW_MATHTRACE_H +#define DSVIEW_PV_VIEW_MATHTRACE_H + +#include "trace.h" + +#include +#include + +#include + +struct srd_channel; + +namespace pv { + +class SigSession; + +namespace data{ +class MathStack; +} + +namespace view { + +class MathTrace : public Trace +{ + Q_OBJECT + +private: + static const int UpMargin; + static const int DownMargin; + static const int RightMargin; + static const QString FFT_ViewMode[2]; + + static const QString FreqPrefixes[9]; + static const int FirstSIPrefixPower; + static const int LastSIPrefixPower; + static const int Pricision; + static const int FreqMinorDivNum; + static const int TickHeight; + static const int VolDivNum; + + static const int DbvRanges[4]; + + static const int HoverPointSize; + + static const double VerticalRate; + +public: + MathTrace(pv::SigSession &session, + boost::shared_ptr math_stack, int index); + ~MathTrace(); + + bool enabled() const; + void set_enable(bool enable); + + void init_zoom(); + void zoom(double steps, int offset); + bool zoom_hit() const; + void set_zoom_hit(bool hit); + + void set_offset(double delta); + double get_offset() const; + + void set_scale(double scale); + double get_scale() const; + + void set_dbv_range(int range); + int dbv_range() const; + std::vector get_dbv_ranges(); + + int view_mode() const; + void set_view_mode(int mode); + std::vector get_view_modes_support(); + + const boost::shared_ptr& get_math_stack() const; + + static QString format_freq(double freq, unsigned precision = Pricision); + + bool measure(const QPoint &p); + + /** + * 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); + + QRect get_view_rect() const; + +protected: + void paint_type_options(QPainter &p, int right, const QPoint pt); + +private: + +private slots: + +private: + pv::SigSession &_session; + boost::shared_ptr _math_stack; + + bool _enable; + int _view_mode; + + double _vmax; + double _vmin; + int _dbv_range; + + uint64_t _hover_index; + bool _hover_en; + QPointF _hover_point; + double _hover_value; + + double _scale; + double _offset; +}; + +} // namespace view +} // namespace pv + +#endif // DSVIEW_PV_VIEW_FFTTRACE_H diff --git a/DSView/pv/view/ruler.cpp b/DSView/pv/view/ruler.cpp index 0a3b8015..c14af957 100644 --- a/DSView/pv/view/ruler.cpp +++ b/DSView/pv/view/ruler.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -77,6 +77,7 @@ const QColor Ruler::dsBlue = QColor(17, 133, 209, 255); const QColor Ruler::dsYellow = QColor(238, 178, 17, 255); const QColor Ruler::dsRed = QColor(213, 15, 37, 255); const QColor Ruler::dsGreen = QColor(0, 153, 37, 255); +const QColor Ruler::RULER_COLOR = QColor(255, 255, 255, 255); const QColor Ruler::HitColor = dsYellow; const QColor Ruler::WarnColor = dsRed; @@ -108,7 +109,7 @@ QString Ruler::format_freq(double period, unsigned precision) QString s; QTextStream ts(&s); ts.setRealNumberPrecision(precision); - ts << fixed << forcesign << 1 / (period * multiplier) << + ts << fixed << 1 / (period * multiplier) << FreqPrefixes[prefix] << "Hz"; return s; } @@ -181,6 +182,7 @@ void Ruler::paintEvent(QPaintEvent*) QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this); + //p.begin(this); //QPainter p(this); //p.setRenderHint(QPainter::Antialiasing); @@ -204,7 +206,7 @@ void Ruler::mouseMoveEvent(QMouseEvent *e) if (_grabbed_marker) { _grabbed_marker->set_index((_view.offset() + - _view.hover_point().x() * _view.scale()) * _view.session().get_device()->get_sample_rate()); + _view.hover_point().x() * _view.scale()) * _view.session().cur_samplerate()); } update(); @@ -263,7 +265,7 @@ void Ruler::mouseReleaseEvent(QMouseEvent *event) _cursor_sel_visible = true; } else { int overCursor; - uint64_t index = (_view.offset() + (_cursor_sel_x + 0.5) * _view.scale()) * _view.session().get_device()->get_sample_rate(); + uint64_t index = (_view.offset() + (_cursor_sel_x + 0.5) * _view.scale()) * _view.session().cur_samplerate(); overCursor = in_cursor_sel_rect(event->pos()); if (overCursor == 0) { _view.add_cursor(CursorColor[_view.get_cursorList().size() % 8], index); @@ -424,14 +426,15 @@ void Ruler::draw_logic_tick_mark(QPainter &p) const double SpacingIncrement = 32.0; const double MinValueSpacing = 16.0; const int ValueMargin = 5; - - const double abs_min_period = 10.0 / _view.session().get_device()->get_sample_rate(); + const double abs_min_period = 10.0 / _view.session().cur_samplerate(); double min_width = SpacingIncrement; double typical_width; double tick_period = 0; + double scale = _view.scale(); + double offset = _view.offset(); - const uint64_t cur_period_scale = ceil((_view.scale() * min_width) / abs_min_period); + const uint64_t cur_period_scale = ceil((scale * min_width) / abs_min_period); // Find tick spacing, and number formatting that does not cause // value to collide. @@ -440,25 +443,25 @@ void Ruler::draw_logic_tick_mark(QPainter &p) } else { _min_period = cur_period_scale * abs_min_period; } - const int order = (int)floorf(log10f(_view.scale() * _view.get_view_width())); + const int order = (int)floorf(log10f(scale * _view.get_view_width())); //const double order_decimal = pow(10, order); const unsigned int prefix = (order - FirstSIPrefixPower) / 3; _cur_prefix = prefix; assert(prefix < countof(SIPrefixes)); typical_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, - AlignLeft | AlignTop, format_time(_view.offset(), + AlignLeft | AlignTop, format_time(offset, prefix)).width() + MinValueSpacing; do { tick_period += _min_period; - } while(typical_width > tick_period / _view.scale()); + } while(typical_width > tick_period / scale); const int text_height = p.boundingRect(0, 0, INT_MAX, INT_MAX, AlignLeft | AlignTop, "8").height(); // Draw the tick marks - p.setPen(dsBlue); + p.setPen(Trace::DARK_FORE); const double minor_tick_period = tick_period / MinPeriodScale; const int minor_order = (int)floorf(log10f(minor_tick_period)); @@ -467,9 +470,9 @@ void Ruler::draw_logic_tick_mark(QPainter &p) assert(minor_prefix < countof(SIPrefixes)); const double first_major_division = - floor(_view.offset() / tick_period); + floor(offset / tick_period); const double first_minor_division = - floor(_view.offset() / minor_tick_period + 1); + floor(offset / minor_tick_period + 1); const double t0 = first_major_division * tick_period; int division = (int)round(first_minor_division - @@ -489,7 +492,7 @@ void Ruler::draw_logic_tick_mark(QPainter &p) const double t = t0 + division * minor_tick_period; const double major_t = t0 + floor(division / MinPeriodScale) * tick_period; - x = (t - _view.offset()) / _view.scale(); + x = (t - offset) / scale; if (division % MinPeriodScale == 0) { @@ -503,13 +506,13 @@ void Ruler::draw_logic_tick_mark(QPainter &p) else { // Draw a minor tick - if (minor_tick_period / _view.scale() > 2 * typical_width) + if (minor_tick_period / scale > 2 * typical_width) p.drawText(x, 2 * ValueMargin, 0, text_height, 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.1 * inc_text_width || - tick_period / _view.scale() > _view.get_view_width()) + //else if ((tick_period / scale > width() / 4) && (minor_tick_period / scale > inc_text_width)) + else if (minor_tick_period / scale > 1.1 * inc_text_width || + tick_period / scale > _view.get_view_width()) p.drawText(x, 2 * ValueMargin, 0, minor_tick_y1 + ValueMargin, AlignCenter | AlignTop | TextDontClip, format_time(t - major_t, minor_prefix)); @@ -548,7 +551,7 @@ void Ruler::draw_hover_mark(QPainter &p) return; p.setPen(QPen(Qt::NoPen)); - p.setBrush(dsBlue); + p.setBrush(RULER_COLOR); const int b = height() - 1; const QPointF points[] = { diff --git a/DSView/pv/view/ruler.h b/DSView/pv/view/ruler.h index c22d8cce..41f415a6 100644 --- a/DSView/pv/view/ruler.h +++ b/DSView/pv/view/ruler.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -54,6 +54,7 @@ private: static const QColor dsYellow; static const QColor dsRed; static const QColor dsGreen; + static const QColor RULER_COLOR; public: static const QColor CursorColor[8]; diff --git a/DSView/pv/view/selectableitem.cpp b/DSView/pv/view/selectableitem.cpp index 2b4b4059..1c4d987e 100644 --- a/DSView/pv/view/selectableitem.cpp +++ b/DSView/pv/view/selectableitem.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2013 Joel Holdsworth - * Copyright (C) 2014 DreamSourceLab + * 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 diff --git a/DSView/pv/view/selectableitem.h b/DSView/pv/view/selectableitem.h index 28004a2d..de9998a9 100644 --- a/DSView/pv/view/selectableitem.h +++ b/DSView/pv/view/selectableitem.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2013 Joel Holdsworth - * Copyright (C) 2014 DreamSourceLab + * 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 diff --git a/DSView/pv/view/signal.cpp b/DSView/pv/view/signal.cpp index e4cba490..b61b8d70 100644 --- a/DSView/pv/view/signal.cpp +++ b/DSView/pv/view/signal.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -35,14 +35,14 @@ namespace pv { namespace view { Signal::Signal(boost::shared_ptr dev_inst, - const sr_channel *const probe, int type) : - Trace(probe->name, probe->index, type), + sr_channel *probe) : + Trace(probe->name, probe->index, probe->type), _dev_inst(dev_inst), _probe(probe) { } -Signal::Signal(const Signal &s, const sr_channel * const probe) : +Signal::Signal(const Signal &s, sr_channel *probe) : Trace((const Trace &)s), _dev_inst(s._dev_inst), _probe(probe) @@ -54,11 +54,23 @@ bool Signal::enabled() const return _probe->enabled; } +void Signal::set_name(QString name) +{ + Trace::set_name(name); + g_free(_probe->name); + _probe->name = g_strdup(name.toLocal8Bit().data()); +} + void Signal::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)); } +boost::shared_ptr Signal::get_device() const +{ + return _dev_inst; +} + } // namespace view } // namespace pv diff --git a/DSView/pv/view/signal.h b/DSView/pv/view/signal.h index 3ad90f44..82e17e92 100644 --- a/DSView/pv/view/signal.h +++ b/DSView/pv/view/signal.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -57,12 +57,12 @@ private: protected: Signal(boost::shared_ptr dev_inst, - const sr_channel * const probe, int type); + sr_channel * const probe); /** * Copy constructor */ - Signal(const Signal &s, const sr_channel * const probe); + Signal(const Signal &s, sr_channel * const probe); public: virtual boost::shared_ptr data() const = 0; @@ -74,6 +74,11 @@ public: */ bool enabled() const; + /** + * Sets the name of the signal. + */ + void set_name(QString name); + /** * Paints the signal label into a QGLWidget. * @param p the QPainter to paint into. @@ -84,6 +89,8 @@ public: */ //virtual void paint_label(QPainter &p, int right, bool hover, int action); + boost::shared_ptr get_device() const; + protected: /** @@ -97,7 +104,7 @@ protected: protected: boost::shared_ptr _dev_inst; - const sr_channel *const _probe; + sr_channel *const _probe; }; } // namespace view diff --git a/DSView/pv/view/timemarker.cpp b/DSView/pv/view/timemarker.cpp index 34a0e7d7..d6eb74f9 100644 --- a/DSView/pv/view/timemarker.cpp +++ b/DSView/pv/view/timemarker.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -70,8 +70,10 @@ void TimeMarker::set_index(uint64_t index) void TimeMarker::paint(QPainter &p, const QRect &rect, const bool highlight) { - const double samples_per_pixel = _view.session().get_device()->get_sample_rate() * _view.scale(); - const double x = _index/samples_per_pixel - (_view.offset() / _view.scale()); + const uint64_t sample_rate = _view.session().cur_samplerate(); + const double scale = _view.scale(); + const double samples_per_pixel = sample_rate * scale; + const double x = _index/samples_per_pixel - (_view.offset() / scale); p.setPen((_grabbed | highlight) ? QPen(_colour.lighter(), 2, Qt::DashLine) : QPen(_colour, 1, Qt::DashLine)); p.drawLine(QPointF(x, rect.top()), QPointF(x, rect.bottom())); } diff --git a/DSView/pv/view/timemarker.h b/DSView/pv/view/timemarker.h index b6de934f..71ee4cfe 100644 --- a/DSView/pv/view/timemarker.h +++ b/DSView/pv/view/timemarker.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 diff --git a/DSView/pv/view/trace.cpp b/DSView/pv/view/trace.cpp index 92b4f210..aec3700b 100644 --- a/DSView/pv/view/trace.cpp +++ b/DSView/pv/view/trace.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2013 Joel Holdsworth - * Copyright (C) 2014 DreamSourceLab + * 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 @@ -43,13 +43,37 @@ 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, 60); -const QColor Trace::dsBack = QColor(0x16, 0x18, 0x23, 180); +const QColor Trace::dsBack = QColor(0x16, 0x18, 0x23, 200); 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 QColor Trace::DARK_BACK = QColor(48, 47, 47, 255); +const QColor Trace::DARK_FORE = QColor(150, 150, 150, 255); +const QColor Trace::DARK_HIGHLIGHT = QColor(32, 32, 32, 255); +const QColor Trace::DARK_BLUE = QColor(17, 133, 209, 255); + +const QColor Trace::PROBE_COLORS[8] = { + QColor(0x50, 0x50, 0x50), // Black + QColor(0x8F, 0x52, 0x02), // Brown + QColor(0xCC, 0x00, 0x00), // Red + QColor(0xF5, 0x79, 0x00), // Orange + QColor(0xED, 0xD4, 0x00), // Yellow + QColor(0x73, 0xD2, 0x16), // Green + QColor(0x34, 0x65, 0xA4), // Blue + QColor(0x75, 0x50, 0x7B), // Violet +// QColor(17, 133, 209), +// QColor(17, 133, 209), +// QColor(17, 133, 209), +// QColor(17, 133, 209), +// QColor(17, 133, 209), +// QColor(17, 133, 209), +// QColor(17, 133, 209), +// QColor(17, 133, 209), +}; + const QPen Trace::AxisPen(QColor(128, 128, 128, 64)); const int Trace::LabelHitPadding = 2; @@ -59,7 +83,8 @@ Trace::Trace(QString name, uint16_t index, int type) : _v_offset(INT_MAX), _type(type), _sec_index(0), - _signalHeight(30) + _totalHeight(30), + _typeWidth(SquareNum) { _index_list.push_back(index); } @@ -71,7 +96,8 @@ Trace::Trace(QString name, std::list index_list, int type, int sec_index) : _type(type), _index_list(index_list), _sec_index(sec_index), - _signalHeight(30) + _totalHeight(30), + _typeWidth(SquareNum) { } @@ -84,7 +110,8 @@ Trace::Trace(const Trace &t) : _index_list(t._index_list), _sec_index(t._sec_index), _old_v_offset(t._old_v_offset), - _signalHeight(t._signalHeight), + _totalHeight(t._totalHeight), + _typeWidth(t._typeWidth), _text_size(t._text_size) { } @@ -162,19 +189,19 @@ void Trace::set_old_v_offset(int v_offset) _old_v_offset = v_offset; } -int Trace::get_zeroPos() +int Trace::get_zero_vpos() { - return _v_offset - _view->v_offset(); + return _v_offset; } -int Trace::get_signalHeight() const +int Trace::get_totalHeight() const { - return _signalHeight; + return _totalHeight; } -void Trace::set_signalHeight(int height) +void Trace::set_totalHeight(int height) { - _signalHeight = height; + _totalHeight = height; } void Trace::set_view(pv::view::View *view) @@ -183,6 +210,22 @@ void Trace::set_view(pv::view::View *view) _view = view; } +pv::view::View* Trace::get_view() const +{ + return _view; +} + +void Trace::set_viewport(pv::view::Viewport *viewport) +{ + assert(viewport); + _viewport = viewport; +} + +pv::view::Viewport* Trace::get_viewport() const +{ + return _viewport; +} + void Trace::paint_back(QPainter &p, int left, int right) { QPen pen(Signal::dsGray); @@ -208,21 +251,24 @@ void Trace::paint_fore(QPainter &p, int left, int right) void Trace::paint_label(QPainter &p, int right, const QPoint pt) { + if (_type == SR_CHANNEL_FFT && !enabled()) + return; + 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); + const QRectF label_rect = get_rect("label", get_zero_vpos(), right); - p.setRenderHint(QPainter::Antialiasing); + //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.setPen(enabled() ? DARK_FORE: dsDisable); p.drawText(name_rect, Qt::AlignLeft | Qt::AlignVCenter, _name); // Paint the trigButton @@ -233,22 +279,20 @@ void Trace::paint_label(QPainter &p, int right, const QPoint pt) const QPointF points[] = { label_rect.topLeft(), label_rect.topRight(), - QPointF(right, get_zeroPos()), + QPointF(right, get_zero_vpos()), label_rect.bottomRight(), label_rect.bottomLeft() }; p.setPen(Qt::transparent); - if (_type == SR_CHANNEL_DSO) + if (_type == SR_CHANNEL_DSO || _type == SR_CHANNEL_FFT) { p.setBrush((label_rect.contains(pt) || selected()) ? _colour.darker() : _colour); - else - p.setBrush((label_rect.contains(pt) || 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); + p.drawPolygon(points, countof(points)); + } else { + QColor color = PROBE_COLORS[*_index_list.begin() % countof(PROBE_COLORS)]; + p.setBrush((label_rect.contains(pt) || selected()) ? color.lighter() : color); + p.drawPolygon(points, countof(points)); + } // Paint the text p.setPen(Qt::white); @@ -258,6 +302,8 @@ void Trace::paint_label(QPainter &p, int right, const QPoint pt) p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "A"); else if (_type == SR_CHANNEL_DECODER) p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "D"); + else if (_type == SR_CHANNEL_FFT) + p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "M"); else p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, QString::number(_index_list.front())); } @@ -296,7 +342,7 @@ 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 label = get_rect("label", get_zeroPos(), right); + const QRectF label = get_rect("label", get_zero_vpos(), right); if (color.contains(point) && enabled()) return COLOR; @@ -321,39 +367,15 @@ void Trace::compute_text_size(QPainter &p) 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 - return QRectF( - 2, - y - SquareWidth / 2, - SquareWidth, SquareWidth); -} - -QRectF Trace::get_view_rect() const +QRect Trace::get_view_rect() const { assert(_view); - return QRectF(0, 0, _view->viewport()->width(), _view->viewport()->height()); + return QRect(0, 0, _view->viewport()->width(), _view->viewport()->height()); } int Trace::get_y() const { - return _v_offset - _view->v_offset(); + return _v_offset; } QColor Trace::get_text_colour() const @@ -380,12 +402,12 @@ int Trace::rows_size() int Trace::get_leftWidth() const { - return SquareWidth + Margin; + return SquareWidth/2 + Margin; } int Trace::get_rightWidth() const { - return 2 * Margin + SquareNum * SquareWidth + 1.5 * SquareWidth; + return 2 * Margin + _typeWidth * SquareWidth + 1.5 * SquareWidth; } int Trace::get_headerHeight() const @@ -393,5 +415,34 @@ int Trace::get_headerHeight() const return SquareWidth; } +QRectF Trace::get_rect(const char *s, int y, int right) const +{ + const QSizeF color_size(get_leftWidth() - Margin, 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 - label_size.height() / 2, + label_size.width(), label_size.height()); + else if (!strcmp(s, "color")) + return QRectF( + 2, + y - color_size.height() / 2, + color_size.width(), color_size.height()); + else + return QRectF( + 2, + y - SquareWidth / 2, + SquareWidth, SquareWidth); +} + } // namespace view } // namespace pv diff --git a/DSView/pv/view/trace.h b/DSView/pv/view/trace.h index ef3d31f3..1f3a4c41 100644 --- a/DSView/pv/view/trace.h +++ b/DSView/pv/view/trace.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2013 Joel Holdsworth - * Copyright (C) 2014 DreamSourceLab + * 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 @@ -31,6 +31,8 @@ #include +#include + #include "selectableitem.h" #include "dsldial.h" @@ -40,6 +42,7 @@ namespace pv { namespace view { class View; +class Viewport; class Trace : public SelectableItem { @@ -70,6 +73,13 @@ public: static const QColor dsLightRed; static const QPen SignalAxisPen; + static const QColor DARK_BACK; + static const QColor DARK_FORE; + static const QColor DARK_HIGHLIGHT; + static const QColor DARK_BLUE; + + static const QColor PROBE_COLORS[8]; + protected: Trace(QString name, uint16_t index, int type); Trace(QString name, std::list index_list, int type, int sec_index); @@ -127,12 +137,12 @@ public: /** * Gets the height of this signal. */ - int get_signalHeight() const; + int get_totalHeight() const; /** * Sets the height of this signal. */ - void set_signalHeight(int height); + void set_totalHeight(int height); /** * Geom @@ -151,7 +161,7 @@ public: */ void set_old_v_offset(int v_offset); - virtual int get_zeroPos(); + virtual int get_zero_vpos(); /** * Returns true if the trace is visible and enabled. @@ -159,6 +169,9 @@ public: virtual bool enabled() const = 0; virtual void set_view(pv::view::View *view); + pv::view::View* get_view() const; + virtual void set_viewport(pv::view::Viewport *viewport); + pv::view::Viewport* get_viewport() const; /** * Paints the background layer of the trace with a QPainter @@ -224,11 +237,11 @@ public: * area. * @return Returns the rectangle of the signal label. */ - QRectF get_rect(const char *s, int y, int right); + QRectF get_rect(const char *s, int y, int right) const; virtual int rows_size(); - virtual QRectF get_view_rect() const; + virtual QRect get_view_rect() const; virtual bool mouse_double_click(int right, const QPoint pt); @@ -283,6 +296,7 @@ signals: protected: pv::view::View *_view; + pv::view::Viewport *_viewport; QString _name; QColor _colour; @@ -291,7 +305,8 @@ protected: std::list _index_list; int _sec_index; int _old_v_offset; - int _signalHeight; + int _totalHeight; + int _typeWidth; QSizeF _text_size; }; diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp index 3965524b..4a6f0d2e 100644 --- a/DSView/pv/view/view.cpp +++ b/DSView/pv/view/view.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -41,11 +41,13 @@ #include "dsosignal.h" #include "view.h" #include "viewport.h" +#include "mathtrace.h" #include "../device/devinst.h" #include "pv/sigsession.h" #include "pv/data/logic.h" #include "pv/data/logicsnapshot.h" +#include "pv/dialogs/calibration.h" using namespace boost; using namespace std; @@ -68,25 +70,19 @@ const QColor View::CursorAreaColour(220, 231, 243); const QSizeF View::LabelPadding(4, 4); View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget *parent) : - QAbstractScrollArea(parent), + QScrollArea(parent), _session(session), _sampling_bar(sampling_bar), - _viewport(new Viewport(*this)), - _ruler(new Ruler(*this)), - _header(new Header(*this)), - _devmode(new DevMode(*this)), - _scale(1e-8), + _scale(1e-5), _preScale(1e-6), _maxscale(1e9), _minscale(1e-15), _offset(0), _preOffset(0), - _v_offset(0), _updating_scroll(false), - _need_update(false), _show_cursors(false), - _trig_pos(0), - _hover_point(-1, -1) + _hover_point(-1, -1), + _dso_auto(true) { setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); @@ -95,32 +91,96 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(v_scroll_value_changed(int))); - setViewportMargins(headerWidth(), RulerHeight, 0, 0); - setViewport(_viewport); + // trace viewport map + _trace_view_map[SR_CHANNEL_LOGIC] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_GROUP] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_DECODER] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_ANALOG] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_DSO] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_FFT] = FFT_VIEW; - connect(&_session, SIGNAL(signals_changed()), - this, SLOT(signals_changed())); - connect(&_session, SIGNAL(data_updated()), - this, SLOT(data_updated())); - connect(&_session, SIGNAL(receive_trigger(quint64)), - this, SLOT(set_trig_pos(quint64))); + _active_viewport = NULL; + _ruler = new Ruler(*this); + _header = new Header(*this); + _devmode = new DevMode(this, session); + + setViewportMargins(headerWidth(), RulerHeight, 0, 0); + //setViewport(_viewport); + + // windows splitter + _time_viewport = new Viewport(*this, TIME_VIEW); + _time_viewport->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + _time_viewport->setMinimumHeight(100); + connect(_time_viewport, SIGNAL(measure_updated()), + this, SLOT(on_measure_updated())); + _fft_viewport = new Viewport(*this, FFT_VIEW); + _fft_viewport->setVisible(false); + _fft_viewport->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + _fft_viewport->setMinimumHeight(100); + connect(_fft_viewport, SIGNAL(measure_updated()), + this, SLOT(on_measure_updated())); + + _vsplitter = new QSplitter(this); + _vsplitter->setOrientation(Qt::Vertical); + _vsplitter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + + _viewport_list.push_back(_time_viewport); + _vsplitter->addWidget(_time_viewport); + _vsplitter->setCollapsible(0, false); + _vsplitter->setStretchFactor(0, 2); + _viewport_list.push_back(_fft_viewport); + _vsplitter->addWidget(_fft_viewport); + _vsplitter->setCollapsible(1, false); + _vsplitter->setStretchFactor(1, 1); + + _viewcenter = new QWidget(this); + _viewcenter->setContentsMargins(0,0,0,0); + QGridLayout* layout = new QGridLayout(_viewcenter); + layout->setSpacing(0); + layout->setContentsMargins(0,0,0,0); + _viewcenter->setLayout(layout); + layout->addWidget(_vsplitter, 0, 0); + _viewbottom = new widgets::ViewStatus(this); + _viewbottom->setFixedHeight(StatusHeight); + layout->addWidget(_viewbottom, 1, 0); + setViewport(_viewcenter); + connect(_vsplitter, SIGNAL(splitterMoved(int,int)), + this, SLOT(splitterMoved(int, int))); connect(&_session, SIGNAL(device_setted()), _devmode, SLOT(set_device())); + connect(&_session, SIGNAL(signals_changed()), + this, SLOT(signals_changed()), Qt::DirectConnection); + connect(&_session, SIGNAL(data_updated()), + this, SLOT(data_updated())); + connect(&_session, SIGNAL(receive_header()), + this, SLOT(receive_header())); + connect(&_session, SIGNAL(receive_trigger(quint64)), + this, SLOT(receive_trigger(quint64))); + connect(&_session, SIGNAL(frame_ended()), + this, SLOT(receive_end())); + connect(&_session, SIGNAL(frame_began()), + this, SLOT(frame_began())); + connect(&_session, SIGNAL(show_region(uint64_t,uint64_t)), + this, SLOT(show_region(uint64_t, uint64_t))); + connect(&_session, SIGNAL(show_wait_trigger()), + _time_viewport, SLOT(show_wait_trigger())); + connect(_devmode, SIGNAL(mode_changed()), - this, SIGNAL(mode_changed())); + parent, SLOT(mode_changed()), Qt::DirectConnection); connect(_header, SIGNAL(traces_moved()), this, SLOT(on_traces_moved())); connect(_header, SIGNAL(header_updated()), this, SLOT(header_updated())); - _viewport->installEventFilter(this); + _time_viewport->installEventFilter(this); + _fft_viewport->installEventFilter(this); _ruler->installEventFilter(this); _header->installEventFilter(this); _devmode->installEventFilter(this); - _viewport->setObjectName(tr("ViewArea_viewport")); + _viewcenter->setObjectName(tr("ViewArea_center")); _ruler->setObjectName(tr("ViewArea_ruler")); _header->setObjectName(tr("ViewArea_header")); @@ -129,6 +189,9 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget _show_search_cursor = false; _search_pos = 0; _search_cursor = new Cursor(*this, Trace::dsLightBlue, _search_pos); + + _cali = new pv::dialogs::Calibration(this); + _cali->hide(); } SigSession& View::session() @@ -146,11 +209,6 @@ double View::offset() const return _offset; } -int View::v_offset() const -{ - return _v_offset; -} - double View::get_minscale() const { return _minscale; @@ -166,14 +224,15 @@ void View::zoom(double steps) zoom(steps, get_view_width() / 2); } -void View::set_need_update(bool need_update) +void View::set_update(Viewport *viewport, bool need_update) { - _need_update = need_update; + viewport->set_need_update(need_update); } -bool View::need_update() const +void View::set_all_update(bool need_update) { - return _need_update; + BOOST_FOREACH(Viewport *viewport, _viewport_list) + viewport->set_need_update(need_update); } void View::update_sample(bool instant) @@ -190,14 +249,20 @@ void View::update_sample(bool instant) void View::set_sample_rate(uint64_t sample_rate, bool force) { - if (_session.get_capture_state() != pv::SigSession::Stopped || force) + if (_session.get_capture_state() != pv::SigSession::Stopped || force) { _sampling_bar->set_sample_rate(sample_rate); + _session.set_cur_samplerate(_session.get_device()->get_sample_rate()); + } } void View::set_sample_limit(uint64_t sample_limit, bool force) { - if (_session.get_capture_state() != pv::SigSession::Stopped || force) + if (_session.get_capture_state() != pv::SigSession::Stopped || force) { _sampling_bar->set_sample_limit(sample_limit); + const uint64_t final_limit = _session.get_device()->get_sample_limit(); + _trig_cursor->set_index(_trig_cursor->index() * 1.0 / _session.cur_samplelimits() * final_limit); + _session.set_cur_samplelimits(final_limit); + } } void View::zoom(double steps, int offset) @@ -233,7 +298,7 @@ void View::zoom(double steps, int offset) if (_scale != _preScale || _offset != _preOffset) { _header->update(); _ruler->update(); - _viewport->update(); + viewport_update(); update_scroll(); } //} @@ -253,7 +318,7 @@ void View::set_scale_offset(double scale, double offset) update_scroll(); _header->update(); _ruler->update(); - _viewport->update(); + viewport_update(); } //} } @@ -267,25 +332,36 @@ void View::set_preScale_preOffset() set_scale_offset(_preScale, _preOffset); } -vector< boost::shared_ptr > View::get_traces() const +vector< boost::shared_ptr > View::get_traces(int type) { const vector< boost::shared_ptr > sigs(_session.get_signals()); const vector< boost::shared_ptr > groups(_session.get_group_signals()); #ifdef ENABLE_DECODE const vector< boost::shared_ptr > decode_sigs( _session.get_decode_signals()); - vector< boost::shared_ptr > traces( - sigs.size() + groups.size() + decode_sigs.size()); -#else - vector< boost::shared_ptr > traces(sigs.size() + groups.size()); #endif + const vector< boost::shared_ptr > maths(_session.get_math_signals()); - vector< boost::shared_ptr >::iterator i = traces.begin(); - i = copy(sigs.begin(), sigs.end(), i); + vector< boost::shared_ptr > traces; + BOOST_FOREACH(boost::shared_ptr t, sigs) { + if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) + traces.push_back(t); + } #ifdef ENABLE_DECODE - i = copy(decode_sigs.begin(), decode_sigs.end(), i); + BOOST_FOREACH(boost::shared_ptr t, decode_sigs) { + if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) + traces.push_back(t); + } #endif - i = copy(groups.begin(), groups.end(), i); + BOOST_FOREACH(boost::shared_ptr t, groups) { + if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) + traces.push_back(t); + } + + BOOST_FOREACH(boost::shared_ptr t, maths) { + if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) + traces.push_back(t); + } stable_sort(traces.begin(), traces.end(), compare_trace_v_offsets); return traces; @@ -321,49 +397,92 @@ void View::show_cursors(bool show) { _show_cursors = show; _ruler->update(); - _viewport->update(); + viewport_update(); } void View::show_trig_cursor(bool show) { _show_trig_cursor = show; _ruler->update(); - _viewport->update(); + viewport_update(); } void View::show_search_cursor(bool show) { _show_search_cursor = show; _ruler->update(); - _viewport->update(); + viewport_update(); } -void View::set_trig_pos(quint64 trig_pos) +void View::status_clear() { - const double time = trig_pos * 1.0 / _session.get_device()->get_sample_rate(); - _trig_pos = trig_pos; + _viewbottom->clear(); +} + +void View::receive_header() +{ + status_clear(); +} + +void View::frame_began() +{ + if (_session.get_device()->dev_inst()->mode == LOGIC) + _viewbottom->set_trig_time(_session.get_trigger_time()); +} + +void View::receive_end() +{ + if (_session.get_device()->dev_inst()->mode == LOGIC) { + GVariant *gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_RLE); + if (gvar != NULL) { + bool rle = g_variant_get_boolean(gvar); + g_variant_unref(gvar); + if (rle) { + gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_ACTUAL_SAMPLES); + if (gvar != NULL) { + uint64_t actual_samples = g_variant_get_uint64(gvar); + g_variant_unref(gvar); + if (actual_samples != _session.cur_samplelimits()) { + _viewbottom->set_rle_depth(actual_samples); + } + } + } + } + } + _time_viewport->unshow_wait_trigger(); +} + +void View::receive_trigger(quint64 trig_pos) +{ + const double time = trig_pos * 1.0 / _session.cur_samplerate(); _trig_cursor->set_index(trig_pos); - _show_trig_cursor = true; - set_scale_offset(_scale, time - _scale * get_view_width() / 2); + if (ds_trigger_get_en() || + _session.get_device()->name() == "virtual-session" || + _session.get_device()->dev_inst()->mode == DSO) { + _show_trig_cursor = true; + set_scale_offset(_scale, time - _scale * get_view_width() / 2); + } + _ruler->update(); - _viewport->update(); + viewport_update(); +} + +void View::set_trig_pos(int percent) +{ + uint64_t index = _session.cur_samplelimits() * percent / 100; + receive_trigger(index); } void View::set_search_pos(uint64_t search_pos) { //assert(search_pos >= 0); - const double time = search_pos * 1.0 / _session.get_device()->get_sample_rate(); + const double time = search_pos * 1.0 / _session.cur_samplerate(); _search_pos = search_pos; _search_cursor->set_index(search_pos); set_scale_offset(_scale, time - _scale * get_view_width() / 2); _ruler->update(); - _viewport->update(); -} - -uint64_t View::get_trig_pos() -{ - return _trig_pos; + viewport_update(); } uint64_t View::get_search_pos() @@ -371,14 +490,14 @@ uint64_t View::get_search_pos() return _search_pos; } -const QPointF& View::hover_point() const +const QPoint& View::hover_point() const { return _hover_point; } void View::normalize_layout() { - const vector< boost::shared_ptr > traces(get_traces()); + const vector< boost::shared_ptr > traces(get_traces(ALL_VIEW)); int v_min = INT_MAX; BOOST_FOREACH(const boost::shared_ptr t, traces) @@ -388,7 +507,7 @@ void View::normalize_layout() BOOST_FOREACH(boost::shared_ptr t, traces) t->set_v_offset(t->get_v_offset() + delta); - verticalScrollBar()->setSliderPosition(_v_offset + delta); + verticalScrollBar()->setSliderPosition(delta); v_scroll_value_changed(verticalScrollBar()->sliderPosition()); } @@ -415,9 +534,9 @@ void View::get_scroll_layout(double &length, double &offset) const void View::update_scroll() { - assert(_viewport); + assert(_viewcenter); - const QSize areaSize = _viewport->size(); + const QSize areaSize = _viewcenter->size(); // Set the horizontal scroll bar double length = 0, offset = 0; @@ -441,89 +560,146 @@ void View::update_scroll() // Set the vertical scrollbar verticalScrollBar()->setPageStep(areaSize.height()); - verticalScrollBar()->setRange(0, - _viewport->get_total_height() - areaSize.height()); + verticalScrollBar()->setRange(0,0); } -void View::update_scale() +void View::update_scale_offset() { - const uint64_t sample_rate = _session.get_device()->get_sample_rate(); + const uint64_t sample_rate = _session.cur_samplerate(); assert(sample_rate > 0); if (_session.get_device()->dev_inst()->mode != DSO) { - _scale = (1.0 / sample_rate) / WellPixelsPerSample; - _maxscale = _session.get_device()->get_sample_time() / (get_view_width() * MaxViewRate); + //_scale = (1.0 / sample_rate) / WellPixelsPerSample; + _maxscale = _session.cur_sampletime() / (get_view_width() * MaxViewRate); + _minscale = (1.0 / sample_rate) / MaxPixelsPerSample; } else { _scale = _session.get_device()->get_time_base() * 10.0 / get_view_width() * std::pow(10.0, -9.0); _maxscale = 1e9; + _minscale = 1e-15; } - _minscale = (1.0 / sample_rate) / MaxPixelsPerSample; - _offset = 0; + + _scale = max(min(_scale, _maxscale), _minscale); + _offset = max(min(_offset, get_max_offset()), get_min_offset()); + _preScale = _scale; _preOffset = _offset; - _trig_cursor->set_index(_trig_pos); + //_trig_cursor->set_index(_session.get_trigger_pos()); _ruler->update(); - _viewport->update(); + viewport_update(); } void View::signals_changed() { int total_rows = 0; uint8_t max_height = MaxHeightUnit; - const vector< boost::shared_ptr > traces(get_traces()); - BOOST_FOREACH(const boost::shared_ptr t, traces) - { - assert(t); - if (dynamic_pointer_cast(t) || - t->enabled()) - total_rows += t->rows_size(); + vector< boost::shared_ptr > time_traces; + vector< boost::shared_ptr > fft_traces; + int bits = 8; + + BOOST_FOREACH(const boost::shared_ptr t, get_traces(ALL_VIEW)) { + if (_trace_view_map[t->get_type()] == TIME_VIEW) + time_traces.push_back(t); + else if (_trace_view_map[t->get_type()] == FFT_VIEW) + if (t->enabled()) + fft_traces.push_back(t); } - const double height = (_viewport->height() - - horizontalScrollBar()->height() - - 2 * SignalMargin * traces.size()) * 1.0 / total_rows; - - if (_session.get_device()->dev_inst()->mode == LOGIC) { - GVariant* gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_MAX_HEIGHT_VALUE); - if (gvar != NULL) { - max_height = (g_variant_get_byte(gvar) + 1) * MaxHeightUnit; - g_variant_unref(gvar); + if (!fft_traces.empty()) { + if (!_fft_viewport->isVisible()) { + _fft_viewport->setVisible(true); + _fft_viewport->clear_measure(); + _viewport_list.push_back(_fft_viewport); + _vsplitter->refresh(); + } + BOOST_FOREACH(boost::shared_ptr t, fft_traces) { + t->set_view(this); + t->set_viewport(_fft_viewport); + t->set_totalHeight(_fft_viewport->height()); + t->set_v_offset(_fft_viewport->geometry().bottom()); } - _signalHeight = (int)((height <= 0) ? 1 : (height >= max_height) ? max_height : height); } else { - _signalHeight = (int)((height <= 0) ? 1 : height); - } - _spanY = _signalHeight + 2 * SignalMargin; - int next_v_offset = SignalMargin; - BOOST_FOREACH(boost::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; - } + _fft_viewport->setVisible(false); + _vsplitter->refresh(); + + // Find the decoder in the stack + std::list< Viewport *>::iterator iter = _viewport_list.begin(); + for(unsigned int i = 0; i < _viewport_list.size(); i++, iter++) + if ((*iter) == _fft_viewport) + break; + // Delete the element + if (iter != _viewport_list.end()) + _viewport_list.erase(iter); + } + + if (!time_traces.empty() && _time_viewport) { + BOOST_FOREACH(const boost::shared_ptr t, time_traces) { + assert(t); + if (dynamic_pointer_cast(t) || + t->enabled()) + total_rows += t->rows_size(); + } + + const double height = (_time_viewport->height() + - 2 * SignalMargin * time_traces.size()) * 1.0 / total_rows; + + if (_session.get_device()->dev_inst()->mode == LOGIC) { + GVariant* gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_MAX_HEIGHT_VALUE); + if (gvar != NULL) { + max_height = (g_variant_get_byte(gvar) + 1) * MaxHeightUnit; + g_variant_unref(gvar); + } + _signalHeight = (int)((height <= 0) ? 1 : (height >= max_height) ? max_height : height); + } else if (_session.get_device()->dev_inst()->mode == DSO) { + _signalHeight = (_header->height() + - horizontalScrollBar()->height() + - 2 * SignalMargin * time_traces.size()) * 1.0 / total_rows; + } else { + _signalHeight = (int)((height <= 0) ? 1 : height); + } + _spanY = _signalHeight + 2 * SignalMargin; + int next_v_offset = SignalMargin; + BOOST_FOREACH(boost::shared_ptr t, time_traces) { + t->set_view(this); + t->set_viewport(_time_viewport); + const double traceHeight = _signalHeight*t->rows_size(); + t->set_totalHeight((int)traceHeight); + t->set_v_offset(next_v_offset + 0.5 * traceHeight + SignalMargin); + next_v_offset += traceHeight + 2 * SignalMargin; + + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(t)) { + GVariant *gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_DSO_BITS); + if (gvar != NULL) { + bits = g_variant_get_byte(gvar); + g_variant_unref(gvar); + } + dsoSig->set_scale(dsoSig->get_view_rect().height() * 1.0f / (1 << bits)); + } + } + _time_viewport->clear_measure(); + } - _viewport->clear_measure(); header_updated(); normalize_layout(); + update_scale_offset(); + data_updated(); } bool View::eventFilter(QObject *object, QEvent *event) { const QEvent::Type type = event->type(); if (type == QEvent::MouseMove) { - const QMouseEvent *const mouse_event = (QMouseEvent*)event; - if (object == _ruler || object == _viewport) { + if (object == _ruler || object == _time_viewport || object == _fft_viewport) { //_hover_point = QPoint(mouse_event->x(), 0); double cur_periods = (mouse_event->pos().x() * _scale + _offset) / _ruler->get_min_period(); - double integer_x = (round(cur_periods) * _ruler->get_min_period() - _offset ) / _scale; + int integer_x = (round(cur_periods) * _ruler->get_min_period() - _offset ) / _scale; double cur_deviate_x = qAbs(mouse_event->pos().x() - integer_x); if (cur_deviate_x < 10) - _hover_point = QPointF(integer_x, mouse_event->pos().y()); + _hover_point = QPoint(integer_x, mouse_event->pos().y()); else _hover_point = mouse_event->pos(); } else if (object == _header) @@ -532,7 +708,6 @@ bool View::eventFilter(QObject *object, QEvent *event) _hover_point = QPoint(-1, -1); hover_point_changed(); - } else if (type == QEvent::Leave) { _hover_point = QPoint(-1, -1); hover_point_changed(); @@ -567,7 +742,7 @@ int View::headerWidth() QFont font = QApplication::font(); QFontMetrics fm(font); - const vector< boost::shared_ptr > traces(get_traces()); + const vector< boost::shared_ptr > traces(get_traces(ALL_VIEW)); if (!traces.empty()){ BOOST_FOREACH(const boost::shared_ptr t, traces) { maxNameWidth = max(fm.boundingRect(t->get_name()).width(), maxNameWidth); @@ -585,22 +760,24 @@ int View::headerWidth() void View::resizeEvent(QResizeEvent*) { + setViewportMargins(headerWidth(), RulerHeight, 0, 0); update_margins(); update_scroll(); + signals_changed(); if (_session.get_device()->dev_inst()->mode == DSO) _scale = _session.get_device()->get_time_base() * std::pow(10.0, -9.0) * DS_CONF_DSO_HDIVS / get_view_width(); if (_session.get_device()->dev_inst()->mode != DSO) - _maxscale = _session.get_device()->get_sample_time() / (get_view_width() * MaxViewRate); + _maxscale = _session.cur_sampletime() / (get_view_width() * MaxViewRate); else _maxscale = 1e9; _scale = min(_scale, _maxscale); - signals_changed(); _ruler->update(); _header->header_resize(); - _need_update = true; + set_update(_time_viewport, true); + set_update(_fft_viewport, true); } void View::h_scroll_value_changed(int value) @@ -623,15 +800,15 @@ void View::h_scroll_value_changed(int value) if (_offset != _preOffset) { _ruler->update(); - _viewport->update(); + viewport_update(); } } void View::v_scroll_value_changed(int value) { - _v_offset = value; + (void)value; _header->update(); - _viewport->update(); + viewport_update(); } void View::data_updated() @@ -643,18 +820,20 @@ void View::data_updated() update_scroll(); // Repaint the view - _need_update = true; - _viewport->update(); + _time_viewport->unshow_wait_trigger(); + set_update(_time_viewport, true); + set_update(_fft_viewport, true); + viewport_update(); } void View::update_margins() { - _ruler->setGeometry(_viewport->x(), 0, - get_view_width(), _viewport->y()); - _header->setGeometry(0, _viewport->y(), - _viewport->x(), _viewport->height()); + _ruler->setGeometry(_viewcenter->x(), 0, + get_view_width(), _viewcenter->y()); + _header->setGeometry(0, _viewcenter->y(), + _viewcenter->x(), _viewcenter->height()); _devmode->setGeometry(0, 0, - _viewport->x(), _viewport->y()); + _viewcenter->x(), _viewcenter->y()); } void View::header_updated() @@ -665,21 +844,21 @@ void View::header_updated() // Update the scroll bars update_scroll(); - _viewport->update(); + viewport_update(); _header->update(); } void View::marker_time_changed() { _ruler->update(); - _viewport->update(); + viewport_update(); } void View::on_traces_moved() { update_scroll(); - _need_update = true; - _viewport->update(); + set_update(_time_viewport, true); + viewport_update(); //traces_moved(); } @@ -729,17 +908,26 @@ void View::set_cursor_middle(int index) list::iterator i = _cursorList.begin(); while (index-- != 0) i++; - set_scale_offset(_scale, (*i)->index() * 1.0 / _session.get_device()->get_sample_rate() - _scale * get_view_width() / 2); + set_scale_offset(_scale, (*i)->index() * 1.0 / _session.cur_samplerate() - _scale * get_view_width() / 2); } -Viewport * View::get_viewport() +void View::on_measure_updated() { - return _viewport; + _active_viewport = dynamic_cast(sender()); + measure_updated(); +} + +QString View::get_measure(QString option) +{ + if (_active_viewport) { + return _active_viewport->get_measure(option); + } + return "#####"; } QString View::get_cm_time(int index) { - return _ruler->format_real_time(get_cursor_samples(index), _session.get_device()->get_sample_rate()); + return _ruler->format_real_time(get_cursor_samples(index), _session.cur_samplerate()); } QString View::get_cm_delta(int index1, int index2) @@ -750,7 +938,7 @@ QString View::get_cm_delta(int index1, int index2) uint64_t samples1 = get_cursor_samples(index1); uint64_t samples2 = get_cursor_samples(index2); uint64_t delta_sample = (samples1 > samples2) ? samples1 - samples2 : samples2 - samples1; - return _ruler->format_real_time(delta_sample, _session.get_device()->get_sample_rate()); + return _ruler->format_real_time(delta_sample, _session.cur_samplerate()); } uint64_t View::get_cursor_samples(int index) @@ -774,13 +962,29 @@ void View::on_cursor_moved() void View::set_measure_en(int enable) { - _viewport->set_measure_en(enable); + BOOST_FOREACH(Viewport *viewport, _viewport_list) + viewport->set_measure_en(enable); } void View::on_state_changed(bool stop) { - if (stop) - _viewport->stop_trigger_timer(); + if (stop) { + BOOST_FOREACH(Viewport *viewport, _viewport_list) + viewport->stop_trigger_timer(); + } + update_scale_offset(); +} + +QRect View::get_view_rect() +{ + if (_session.get_device()->dev_inst()->mode == DSO) { + const vector< boost::shared_ptr > sigs(_session.get_signals()); + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + return s->get_view_rect(); + } + } else { + return _viewcenter->rect(); + } } int View::get_view_width() @@ -789,10 +993,10 @@ int View::get_view_width() if (_session.get_device()->dev_inst()->mode == DSO) { const vector< boost::shared_ptr > sigs(_session.get_signals()); BOOST_FOREACH(const boost::shared_ptr s, sigs) { - view_width = max((double)view_width, s->get_view_rect().width()); + view_width = max(view_width, s->get_view_rect().width()); } } else { - view_width = _viewport->width(); + view_width = _viewcenter->width(); } return view_width; @@ -804,10 +1008,10 @@ int View::get_view_height() if (_session.get_device()->dev_inst()->mode == DSO) { const vector< boost::shared_ptr > sigs(_session.get_signals()); BOOST_FOREACH(const boost::shared_ptr s, sigs) { - view_height = max((double)view_height, s->get_view_rect().height()); + view_height = max(view_height, s->get_view_rect().height()); } } else { - view_height = _viewport->width(); + view_height = _viewcenter->height(); } return view_height; @@ -824,5 +1028,63 @@ double View::get_max_offset() - _scale * (get_view_width() * MaxViewRate); } +// -- calibration dialog +void View::show_calibration() +{ + _cali->set_device(_session.get_device()); + _cali->show(); +} + +void View::hide_calibration() +{ + _cali->hide(); +} + +void View::update_calibration() +{ + if (_cali->isVisible()) { + _cali->set_device(_session.get_device()); + } +} + +void View::show_region(uint64_t start, uint64_t end) +{ + assert(start <= end); + const double ideal_scale = (end-start) * 2.0 / _session.cur_samplerate() / get_view_width(); + const double new_scale = max(min(ideal_scale, _maxscale), _minscale); + const double new_off = (start + end) * 0.5 / _session.cur_samplerate() - new_scale * get_view_width() / 2; + set_scale_offset(new_scale, new_off); +} + +void View::viewport_update() +{ + _viewcenter->update(); + BOOST_FOREACH(Viewport *viewport, _viewport_list) + viewport->update(); +} + +void View::splitterMoved(int pos, int index) +{ + (void)pos; + (void)index; + signals_changed(); +} + +void View::reload() +{ + show_trig_cursor(false); + + /* + * if headerwidth not change, viewport height will not be updated + * lead to a wrong signal height + */ + if (_session.get_device()->dev_inst()->mode == LOGIC) + _viewbottom->setFixedHeight(StatusHeight); + else + _viewbottom->setFixedHeight(10); + + +} + } // namespace view } // namespace pv diff --git a/DSView/pv/view/view.h b/DSView/pv/view/view.h index c3f6ac72..4132257c 100644 --- a/DSView/pv/view/view.h +++ b/DSView/pv/view/view.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -32,13 +32,18 @@ #include #include -#include +#include #include +#include +#include +#include "../../extdef.h" #include "../toolbars/samplingbar.h" #include "../data/signaldata.h" +#include "../view/viewport.h" #include "cursor.h" #include "signal.h" +#include "../widgets/viewstatus.h" namespace pv { @@ -56,7 +61,7 @@ class Ruler; class Trace; class Viewport; -class View : public QAbstractScrollArea { +class View : public QScrollArea { Q_OBJECT private: @@ -79,6 +84,8 @@ public: static constexpr double MaxViewRate = 1.0; static const int MaxPixelsPerSample = 100; + static const int StatusHeight = 20; + public: explicit View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget *parent = 0); @@ -110,7 +117,7 @@ public: void set_scale_offset(double scale, double offset); void set_preScale_preOffset(); - std::vector< boost::shared_ptr > get_traces() const; + std::vector< boost::shared_ptr > get_traces(int type); /** * Returns true if cursors are displayed. false otherwise. @@ -132,7 +139,7 @@ public: */ void show_cursors(bool show = true); - const QPointF& hover_point() const; + const QPoint& hover_point() const; void normalize_layout(); @@ -151,10 +158,8 @@ public: Cursor* get_trig_cursor(); Cursor* get_search_cursor(); - //void set_trig_pos(uint64_t trig_pos); void set_search_pos(uint64_t search_pos); - uint64_t get_trig_pos(); uint64_t get_search_pos(); /* @@ -163,11 +168,10 @@ public: double get_minscale() const; double get_maxscale() const; - void set_need_update(bool need_update); - bool need_update() const; + void set_update(Viewport *viewport, bool need_update); + void set_all_update(bool need_update); uint64_t get_cursor_samples(int index); - Viewport * get_viewport(); QString get_cm_time(int index); QString get_cm_delta(int index1, int index2); @@ -175,6 +179,7 @@ public: void on_state_changed(bool stop); + QRect get_view_rect(); int get_view_width(); int get_view_height(); @@ -184,6 +189,10 @@ public: void set_sample_limit(uint64_t sample_limit, bool force = false); + QString get_measure(QString option); + + void viewport_update(); + signals: void hover_point_changed(); @@ -193,7 +202,7 @@ signals: void cursor_moved(); - void mode_changed(); + void measure_updated(); private: void get_scroll_layout(double &length, double &offset) const; @@ -214,10 +223,16 @@ private: void resizeEvent(QResizeEvent *e); public slots: + void reload(); void set_measure_en(int enable); void signals_changed(); void data_updated(); - void update_scale(); + void update_scale_offset(); + void show_region(uint64_t start, uint64_t end); + // -- calibration + void update_calibration(); + void hide_calibration(); + void status_clear(); private slots: @@ -230,14 +245,34 @@ private slots: void header_updated(); - void set_trig_pos(quint64 trig_pos); + void receive_header(); + + void receive_trigger(quint64 trig_pos); + void set_trig_pos(int percent); + + void receive_end(); + + void frame_began(); + + // calibration for oscilloscope + void show_calibration(); + void on_measure_updated(); + + void splitterMoved(int pos, int index); private: SigSession &_session; pv::toolbars::SamplingBar *_sampling_bar; - Viewport *_viewport; + QWidget *_viewcenter; + widgets::ViewStatus *_viewbottom; + QSplitter *_vsplitter; + Viewport * _time_viewport; + Viewport * _fft_viewport; + Viewport *_active_viewport; + std::list _viewport_list; + std::map _trace_view_map; Ruler *_ruler; Header *_header; DevMode *_devmode; @@ -255,10 +290,7 @@ private: int _spanY; int _signalHeight; - int _v_offset; - bool _updating_scroll; - - bool _need_update; + bool _updating_scroll; bool _show_cursors; @@ -266,12 +298,13 @@ private: Cursor *_trig_cursor; bool _show_trig_cursor; - uint64_t _trig_pos; Cursor *_search_cursor; bool _show_search_cursor; uint64_t _search_pos; - QPointF _hover_point; + QPoint _hover_point; + dialogs::Calibration *_cali; + bool _dso_auto; }; } // namespace view diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index dfa94970..92fdaae1 100644 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -21,18 +21,19 @@ */ -#include "view.h" #include "viewport.h" #include "ruler.h" #include "signal.h" #include "dsosignal.h" #include "logicsignal.h" +#include "mathtrace.h" #include "../device/devinst.h" #include "../data/logic.h" #include "../data/logicsnapshot.h" #include "../sigsession.h" #include "../dialogs/dsomeasure.h" +#include "decodetrace.h" #include #include @@ -51,12 +52,13 @@ namespace view { const double Viewport::DragDamping = 1.05; const double Viewport::MinorDragRateUp = 10; -Viewport::Viewport(View &parent) : - QWidget(&parent), - _view(parent), +Viewport::Viewport(View &parent, View_type type) : + QWidget(&parent), + _view(parent), + _type(type), + _need_update(false), _total_receive_len(0), - _zoom_rect_visible(false), - _measure_shown(false), + _action_type(NO_ACTION), _measure_type(NO_MEASURE), _cur_sample(0), _nxt_sample(1), @@ -65,10 +67,9 @@ Viewport::Viewport(View &parent) : _cur_midY(0), _hover_index(0), _hover_hit(false), - _dso_xm(false), - _dso_xm_stage(0), - _dso_ym(false), - _dso_ym_done(false) + _dso_xm_valid(false), + _dso_ym_valid(false), + _waiting_trig(0) { setMouseTracking(true); setAutoFillBackground(true); @@ -102,10 +103,10 @@ int Viewport::get_total_height() const { int h = 0; - const vector< boost::shared_ptr > traces(_view.get_traces()); + const vector< boost::shared_ptr > traces(_view.get_traces(_type)); BOOST_FOREACH(const boost::shared_ptr t, traces) { assert(t); - h += (int)(t->get_signalHeight()); + h += (int)(t->get_totalHeight()); } h += 2 * View::SignalMargin; @@ -128,11 +129,14 @@ void Viewport::paintEvent(QPaintEvent *event) QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this); - const vector< boost::shared_ptr > traces(_view.get_traces()); + //p.begin(this); + const vector< boost::shared_ptr > traces(_view.get_traces(_type)); BOOST_FOREACH(const boost::shared_ptr t, traces) { assert(t); t->paint_back(p, 0, _view.get_view_width()); + if (t->enabled() && _view.session().get_device()->dev_inst()->mode == DSO) + break; } p.setRenderHint(QPainter::Antialiasing, false); @@ -147,9 +151,11 @@ void Viewport::paintEvent(QPaintEvent *event) break; case SigSession::Running: - p.setRenderHint(QPainter::Antialiasing); - paintProgress(p); - p.setRenderHint(QPainter::Antialiasing, false); + if (_type == TIME_VIEW) { + p.setRenderHint(QPainter::Antialiasing); + paintProgress(p); + p.setRenderHint(QPainter::Antialiasing, false); + } break; } } else { @@ -172,11 +178,13 @@ void Viewport::paintEvent(QPaintEvent *event) void Viewport::paintSignals(QPainter &p) { - const vector< boost::shared_ptr > traces(_view.get_traces()); + if (_view.session().get_data_lock()) + return; + const vector< boost::shared_ptr > traces(_view.get_traces(_type)); if (_view.scale() != _curScale || _view.offset() != _curOffset || _view.get_signalHeight() != _curSignalHeight || - _view.need_update()) { + _need_update) { _curScale = _view.scale(); _curOffset = _view.offset(); _curSignalHeight = _view.get_signalHeight(); @@ -190,18 +198,17 @@ void Viewport::paintSignals(QPainter &p) { assert(t); if (t->enabled()) - t->paint_mid(dbp, 0, _view.get_view_width()); + t->paint_mid(dbp, 0, t->get_view_rect().width()); } - - _view.set_need_update(false); + _need_update = false; } p.drawPixmap(0, 0, pixmap); // plot cursors - if (_view.cursors_shown()) { + if (_view.cursors_shown() && _type == TIME_VIEW) { list::iterator i = _view.get_cursorList().begin(); double cursorX; - const double samples_per_pixel = _view.session().get_device()->get_sample_rate() * _view.scale(); + const double samples_per_pixel = _view.session().cur_samplerate() * _view.scale(); while (i != _view.get_cursorList().end()) { cursorX = (*i)->index()/samples_per_pixel - (_view.offset() / _view.scale()); if (rect().contains(_view.hover_point().x(), _view.hover_point().y()) && @@ -212,23 +219,56 @@ void Viewport::paintSignals(QPainter &p) i++; } } - if (_view.trig_cursor_shown()) { - _view.get_trig_cursor()->paint(p, rect(), 0); - } - if (_view.search_cursor_shown()) { - _view.get_search_cursor()->paint(p, rect(), 0); - } - // plot zoom rect - if (_zoom_rect_visible) { - p.setPen(Qt::NoPen); - p.setBrush(Trace::dsLightBlue); - p.drawRect(_zoom_rect); - } + if (_type == TIME_VIEW) { + if (_view.trig_cursor_shown()) { + _view.get_trig_cursor()->paint(p, rect(), 0); + } + if (_view.search_cursor_shown()) { + _view.get_search_cursor()->paint(p, rect(), 0); + } - //plot measure arrow - if (_measure_shown) { + // plot zoom rect + if (_action_type == LOGIC_ZOOM) { + p.setPen(Qt::NoPen); + p.setBrush(Trace::dsLightBlue); + p.drawRect(QRectF(_mouse_down_point, _mouse_point)); + } + + //plot measure arrow paintMeasure(p); + + //plot trigger information + if (_view.session().get_device()->dev_inst()->mode == DSO && + _view.session().get_capture_state() == SigSession::Running) { + uint8_t type; + bool roll = false; + QString type_str=""; + GVariant *gvar = _view.session().get_device()->get_config(NULL, NULL, SR_CONF_ROLL); + if (gvar != NULL) { + roll = g_variant_get_boolean(gvar); + g_variant_unref(gvar); + } + gvar = _view.session().get_device()->get_config(NULL, NULL, SR_CONF_TRIGGER_SOURCE); + if (gvar != NULL) { + type = g_variant_get_byte(gvar); + g_variant_unref(gvar); + if (type == DSO_TRIGGER_AUTO && roll) { + type_str = "Auto(Roll)"; + } else if (type == DSO_TRIGGER_AUTO && !_view.session().trigd()) { + type_str = "Auto"; + } else if (_waiting_trig > 0) { + type_str = "Waiting Trig"; + for (int i = 1; i < _waiting_trig; i++) + if (i % (WaitLoopTime / SigSession::ViewTime) == 0) + type_str += "."; + } else { + type_str = "Trig'd"; + } + } + p.setPen(Trace::DARK_FORE); + p.drawText(_view.get_view_rect(), Qt::AlignLeft | Qt::AlignTop, type_str); + } } } @@ -236,7 +276,8 @@ void Viewport::paintProgress(QPainter &p) { using pv::view::Signal; - const uint64_t _total_sample_len = _view.session().get_device()->get_sample_limit(); + const uint64_t _total_sample_len = _view.session().cur_samplelimits(); + double progress = -(_total_receive_len * 1.0 / _total_sample_len * 360 * 16); int captured_progress = 0; @@ -320,10 +361,12 @@ void Viewport::paintProgress(QPainter &p) sr_status status; if (sr_status_get(_view.session().get_device()->dev_inst(), &status, SR_STATUS_TRIG_BEGIN, SR_STATUS_TRIG_END) == SR_OK){ const bool triggred = status.trig_hit & 0x01; - const uint32_t captured_cnt = (status.captured_cnt0 + + uint32_t captured_cnt = (status.captured_cnt0 + (status.captured_cnt1 << 8) + (status.captured_cnt2 << 16) + (status.captured_cnt3 << 24)); + if (_view.session().get_device()->dev_inst()->mode == DSO) + captured_cnt = captured_cnt * _view.session().get_signals().size() / _view.session().get_ch_num(SR_CHANNEL_DSO); if (triggred) captured_progress = (_total_sample_len - captured_cnt) * 100.0 / _total_sample_len; else @@ -369,30 +412,10 @@ void Viewport::mousePressEvent(QMouseEvent *event) _mouse_down_point = event->pos(); _mouse_down_offset = _view.offset(); - _measure_shown = _dso_xm || _dso_ym; - //_dso_xm = false; _drag_strength = 0; - _time.start(); - - if (event->buttons() & Qt::LeftButton) { - if (_view.cursors_shown()) { - list::iterator i = _view.get_cursorList().begin(); - double cursorX; - const double samples_per_pixel = _view.session().get_device()->get_sample_rate() * _view.scale(); - while (i != _view.get_cursorList().end()) { - cursorX = (*i)->index()/samples_per_pixel - (_view.offset() / _view.scale()); - if ((*i)->grabbed()) { - _view.get_ruler()->rel_grabbed_cursor(); - } else if (qAbs(cursorX - event->pos().x()) <= HitCursorMargin) { - _view.get_ruler()->set_grabbed_cursor(*i); - _measure_type = LOGIC_CURS; - break; - } - i++; - } - - } + _time.restart(); + if (event->button() == Qt::LeftButton) { const vector< boost::shared_ptr > sigs(_view.session().get_signals()); BOOST_FOREACH(const boost::shared_ptr s, sigs) { assert(s); @@ -400,10 +423,7 @@ void Viewport::mousePressEvent(QMouseEvent *event) continue; boost::shared_ptr dsoSig; if (dsoSig = dynamic_pointer_cast(s)) { - if (dsoSig->get_trig_rect(0, _view.get_view_width()).contains(_mouse_point)) { - _drag_sig = s; - break; - } else if (dsoSig->get_ms_show_hover()) { + if (dsoSig->get_ms_show_hover()) { dsoSig->set_ms_show(!dsoSig->get_ms_show()); break; } else if (dsoSig->get_ms_gear_hover()) { @@ -414,51 +434,20 @@ void Viewport::mousePressEvent(QMouseEvent *event) } } - if (_measure_type == LOGIC_FREQ) - _measure_type = NO_MEASURE; - update(); } - if (_hover_hit && (event->buttons() & Qt::RightButton)) { - _view.add_cursor(view::Ruler::CursorColor[_view.get_cursorList().size() % 8], _hover_index); - _view.show_cursors(true); - _hover_hit = false; - } else if (_hover_hit && (event->buttons() & Qt::LeftButton)) { - _dso_ym = true; - _dso_ym_done = false; - _dso_ym_sig_index = _hover_sig_index; - _dso_ym_sig_value = _hover_sig_value; - _dso_ym_index = _hover_index; - _dso_ym_start = event->pos().y(); - } else if (_dso_ym && !_dso_ym_done && (event->buttons() & Qt::LeftButton)) { - _dso_ym_end = event->pos().y(); - _dso_ym_done = true; - } else if (_dso_ym && !_dso_ym_done && (event->buttons() & Qt::RightButton)) { - _dso_ym = false; - _dso_ym_done = false; - } else if (_dso_xm && _dso_xm_stage < DsoMeasureStages && (event->buttons() & Qt::RightButton)) { - _dso_xm = false; - _measure_shown = _dso_ym; - _dso_xm_stage = 0; - _measure_type = NO_MEASURE; - _mm_width = "#####"; - _mm_period = "#####"; - _mm_freq = "#####"; - _mm_duty = "#####"; - mouse_measure(); - } else if (event->buttons() & Qt::LeftButton) { - if (_dso_xm_stage > 0 && _dso_xm_stage < DsoMeasureStages) { - const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); - const double scale = _view.scale(); - const double samples_per_pixel = sample_rate * scale; - _dso_xm_index[_dso_xm_stage] = event->pos().x() * samples_per_pixel + _view.offset() * sample_rate; - for(int i = _dso_xm_stage; i > 0; i--) { - const uint64_t max_index = max(_dso_xm_index[i-1], _dso_xm_index[i]); - _dso_xm_index[i-1] = min(_dso_xm_index[i-1], _dso_xm_index[i]); - _dso_xm_index[i] = max_index; + if (_action_type == NO_ACTION && + event->button() == Qt::RightButton && + _view.session().get_capture_state() == SigSession::Stopped) { + if (_view.session().get_device()->dev_inst()->mode == LOGIC) { + _action_type = LOGIC_ZOOM; + } else if (_view.session().get_device()->dev_inst()->mode == DSO) { + if (_hover_hit) { + uint64_t index = (_view.offset() + (event->pos().x() + 0.5) * _view.scale()) * _view.session().cur_samplerate(); + _view.add_cursor(view::Ruler::CursorColor[_view.get_cursorList().size() % 8], index); + _view.show_cursors(true); } - _dso_xm_stage = (_dso_xm_stage + 1) % (DsoMeasureStages + 1); } } } @@ -467,45 +456,105 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) { assert(event); _hover_hit = false; - if (!_dso_xm && (_dso_ym_done || !_dso_ym) && - event->buttons() & Qt::RightButton) { - _zoom_rect = QRectF(_mouse_down_point, event->pos()); - _zoom_rect_visible = true; - } if (event->buttons() & Qt::LeftButton) { - if (_drag_sig) { - boost::shared_ptr dsoSig; - if (dsoSig = dynamic_pointer_cast(_drag_sig)) - dsoSig->set_trig_vpos(event->pos().y()); - } else { + if (_type == TIME_VIEW) { _view.set_scale_offset(_view.scale(), _mouse_down_offset + (_mouse_down_point - event->pos()).x() * _view.scale()); _drag_strength = (_mouse_down_point - event->pos()).x(); - //measure(); + } else if (_type == FFT_VIEW) { + BOOST_FOREACH(const boost::shared_ptr t, _view.session().get_math_signals()) { + assert(t); + if(t->enabled()) { + double delta = (_mouse_point - event->pos()).x(); + t->set_offset(delta); + break; + } + } } } - 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) { - const double cur_time = _view.offset() + _view.hover_point().x() * _view.scale(); - const double pos = cur_time * sample_rate; - const double pos_delta = pos - (uint64_t)pos; - if ( pos_delta < 0.5) - grabbed_marker->set_index((uint64_t)floor(pos)); - else - grabbed_marker->set_index((uint64_t)ceil(pos)); + if (_type == TIME_VIEW) { + if (!(event->buttons() || Qt::NoButton)) { + if (_action_type == DSO_TRIG_MOVE) { + if (_drag_sig) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(_drag_sig)) + dsoSig->set_trig_vpos(event->pos().y(), true); + } + } + + if (_action_type == CURS_MOVE) { + uint64_t sample_rate = _view.session().cur_samplerate(); + TimeMarker* grabbed_marker = _view.get_ruler()->get_grabbed_cursor(); + if (_view.cursors_shown() && grabbed_marker) { + int curX = _view.hover_point().x(); + uint64_t index0 = 0, index1 = 0, index2 = 0; + bool logic = false; + const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + assert(s); + boost::shared_ptr logicSig; + boost::shared_ptr dsoSig; + if ((_view.session().get_device()->dev_inst()->mode == LOGIC) && + (logicSig = dynamic_pointer_cast(s))) { + if (logicSig->measure(event->pos(), index0, index1, index2)) { + logic = true; + break; + } + } + if ((_view.session().get_device()->dev_inst()->mode == DSO) && + (dsoSig = dynamic_pointer_cast(s))) { + curX = min(dsoSig->get_view_rect().right(), curX); + break; + } + } + + const double cur_time = _view.offset() + curX * _view.scale(); + const double pos = cur_time * sample_rate; + const double pos_delta = pos - (uint64_t)pos; + const double samples_per_pixel = sample_rate * _view.scale(); + const double index_offset = _view.offset() / _view.scale(); + const double curP = index0 / samples_per_pixel - index_offset; + const double curN = index1 / samples_per_pixel - index_offset; + if (logic && (curX - curP < SnapMinSpace || curN - curX < SnapMinSpace)) { + if (curX - curP < curN - curX) + grabbed_marker->set_index(index0); + else + grabbed_marker->set_index(index1); + } else if ( pos_delta < 0.5) { + grabbed_marker->set_index((uint64_t)floor(pos)); + } else { + grabbed_marker->set_index((uint64_t)ceil(pos)); + } + } + } + + if (_action_type == DSO_XM_STEP1 || _action_type == DSO_XM_STEP2) { + BOOST_FOREACH(const boost::shared_ptr s, _view.session().get_signals()) { + assert(s); + if (!s->get_view_rect().contains(event->pos())) { + _dso_xm_valid = false; + _mm_width = "#####"; + _mm_period = "#####"; + _mm_freq = "#####"; + _mm_duty = "#####"; + _action_type = NO_ACTION; + } + break; + } + } + + if (_action_type == DSO_YM) + _dso_ym_end = event->pos().y(); } - if (_dso_ym && !_dso_ym_done) - _dso_ym_end = event->pos().y(); - measure(); } _mouse_point = event->pos(); + + measure(); update(); } @@ -513,57 +562,194 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) { assert(event); - if (_zoom_rect_visible) { - _zoom_rect_visible = false; - const double newOffset = _view.offset() + (min(event->pos().x(), _mouse_down_point.x()) + 0.5) * _view.scale(); - const double newScale = max(min(_view.scale() * abs(event->pos().x() - _mouse_down_point.x()) / _view.get_view_width(), - _view.get_maxscale()), _view.get_minscale()); - if (newScale != _view.scale()) - _view.set_scale_offset(newScale, newOffset); - } + if (_type == TIME_VIEW) { + if ((_action_type == NO_ACTION) && + (event->button() == Qt::LeftButton)) { + // priority 0 + if (_action_type == NO_ACTION && _view.cursors_shown()) { + list::iterator i = _view.get_cursorList().begin(); + double cursorX; + const double samples_per_pixel = _view.session().cur_samplerate() * _view.scale(); + while (i != _view.get_cursorList().end()) { + cursorX = (*i)->index()/samples_per_pixel - (_view.offset() / _view.scale()); + if ((*i)->grabbed()) { + _view.get_ruler()->rel_grabbed_cursor(); + } else if (qAbs(cursorX - event->pos().x()) <= HitCursorMargin) { + _view.get_ruler()->set_grabbed_cursor(*i); + _action_type = CURS_MOVE; + break; + } + i++; + } + } - if(_drag_sig) - _drag_sig.reset(); + if (_view.session().get_device()->dev_inst()->mode == LOGIC && + _view.session().get_capture_state() == SigSession::Stopped) { + // priority 1 + if (_action_type == NO_ACTION) { + const double strength = _drag_strength*DragTimerInterval*1.0/_time.elapsed(); + if (_time.elapsed() < 200 && + abs(_drag_strength) < MinorDragOffsetUp && + abs(strength) > MinorDragRateUp) { + _drag_timer.start(DragTimerInterval); + _action_type = LOGIC_MOVE; + } else if (_time.elapsed() < 200 && + abs(strength) > DragTimerInterval) { + _drag_strength = strength * 5; + _drag_timer.start(DragTimerInterval); + _action_type = LOGIC_MOVE; + } + } - if ((_measure_type != LOGIC_MOVE && _measure_type != LOGIC_CURS) && - _view.session().get_device()->dev_inst()->mode == LOGIC && - _mouse_down_point.x() == event->pos().x() && - event->button() & Qt::LeftButton) { - if (_measure_type == LOGIC_EDGE) { - _measure_type = NO_MEASURE; - _measure_shown = false; + // priority 2 + if (_action_type == NO_ACTION) { + if (_mouse_down_point.x() == event->pos().x()) { + const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + assert(s); + if (abs(event->pos().y() - s->get_y()) < _view.get_signalHeight()) { + _action_type = LOGIC_EDGE; + _edge_start = (_view.offset() + (event->pos().x() + 0.5) * _view.scale()) * _view.session().cur_samplerate(); + break; + } + } + } + } + } else if (_view.session().get_device()->dev_inst()->mode == DSO) { + // priority 0 + if (_action_type == NO_ACTION && _hover_hit) { + _action_type = DSO_YM; + _dso_ym_valid = true; + _dso_ym_sig_index = _hover_sig_index; + _dso_ym_sig_value = _hover_sig_value; + _dso_ym_index = _hover_index; + _dso_ym_start = event->pos().y(); + } + + // priority 1 + if (_action_type == NO_ACTION) { + const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + assert(s); + if (!s->enabled()) + continue; + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + if (dsoSig->get_trig_rect(0, _view.get_view_width()).contains(_mouse_point)) { + _drag_sig = s; + _action_type = DSO_TRIG_MOVE; + break; + } + } + } + } + } + } else if (_action_type == DSO_YM) { + if (event->button() == Qt::LeftButton) { + _dso_ym_end = event->pos().y(); + _action_type = NO_ACTION; + } else if (event->button() == Qt::RightButton) { + _action_type = NO_ACTION; + _dso_ym_valid = false; + } + } else if (_action_type == DSO_TRIG_MOVE) { + if (event->button() == Qt::LeftButton) { + _drag_sig.reset(); + _action_type = NO_ACTION; + } + } else if (_action_type == DSO_XM_STEP0) { + if (event->button() == Qt::LeftButton) { + _action_type = DSO_XM_STEP1; + _dso_xm_valid = true; + } + } else if (_action_type == DSO_XM_STEP1) { + if (event->button() == Qt::LeftButton) { + const uint64_t sample_rate = _view.session().cur_samplerate(); + const double scale = _view.scale(); + const double samples_per_pixel = sample_rate * scale; + + _dso_xm_index[1] = event->pos().x() * samples_per_pixel + _view.offset() * sample_rate; + const uint64_t max_index = max(_dso_xm_index[0], _dso_xm_index[1]); + _dso_xm_index[0] = min(_dso_xm_index[0], _dso_xm_index[1]); + _dso_xm_index[1] = max_index; + + _action_type = DSO_XM_STEP2; + } else if (event->button() == Qt::RightButton) { + _action_type = NO_ACTION; + _dso_xm_valid = false; + _mm_width = "#####"; + _mm_period = "#####"; + _mm_freq = "#####"; + _mm_duty = "#####"; + measure_updated(); + } + } else if (_action_type == DSO_XM_STEP2) { + if (event->button() == Qt::LeftButton) { + const uint64_t sample_rate = _view.session().cur_samplerate(); + const double scale = _view.scale(); + const double samples_per_pixel = sample_rate * scale; + _dso_xm_index[2] = event->pos().x() * samples_per_pixel + _view.offset() * sample_rate; + uint64_t max_index = max(_dso_xm_index[1], _dso_xm_index[2]); + _dso_xm_index[1] = min(_dso_xm_index[1], _dso_xm_index[2]); + _dso_xm_index[2] = max_index; + + max_index = max(_dso_xm_index[0], _dso_xm_index[1]); + _dso_xm_index[0] = min(_dso_xm_index[0], _dso_xm_index[1]); + _dso_xm_index[1] = max_index; + + _action_type = NO_ACTION; + } else if (event->button() == Qt::RightButton) { + _action_type = NO_ACTION; + _dso_xm_valid = false; + _mm_width = "#####"; + _mm_period = "#####"; + _mm_freq = "#####"; + _mm_duty = "#####"; + measure_updated(); + } + } else if (_action_type == CURS_MOVE) { + _action_type = NO_ACTION; + if (_view.cursors_shown()) { + list::iterator i = _view.get_cursorList().begin(); + while (i != _view.get_cursorList().end()) { + if ((*i)->grabbed()) { + _view.get_ruler()->rel_grabbed_cursor(); + } + i++; + } + } + } else if (_action_type == LOGIC_EDGE) { + _action_type = NO_ACTION; _edge_rising = 0; _edge_falling = 0; - } else { - _measure_type = LOGIC_EDGE; - _edge_start = (_view.offset() + (event->pos().x() + 0.5) * _view.scale()) * _view.session().get_device()->get_sample_rate(); + } else if (_action_type == LOGIC_MOVE) { + if (_mouse_down_point == event->pos()) { + _drag_strength = 0; + _drag_timer.stop(); + _action_type = NO_ACTION; + } else { + const double strength = _drag_strength*DragTimerInterval*1.0/_time.elapsed(); + if (_time.elapsed() < 200 && + abs(_drag_strength) < MinorDragOffsetUp && + abs(strength) > MinorDragRateUp) { + _drag_timer.start(DragTimerInterval); + } else if (_time.elapsed() < 200 && + abs(strength) > DragTimerInterval) { + _drag_strength = strength * 5; + _drag_timer.start(DragTimerInterval); + } + } + } else if (_action_type == LOGIC_ZOOM) { + if (event->pos().x() != _mouse_down_point.x()) { + const double newOffset = _view.offset() + (min(event->pos().x(), _mouse_down_point.x()) + 0.5) * _view.scale(); + const double newScale = max(min(_view.scale() * abs(event->pos().x() - _mouse_down_point.x()) / _view.get_view_width(), + _view.get_maxscale()), _view.get_minscale()); + if (newScale != _view.scale()) + _view.set_scale_offset(newScale, newOffset); + } + _action_type = NO_ACTION; } } - - if (_view.session().get_device()->dev_inst()->mode == LOGIC && - (_measure_type == NO_MEASURE || _measure_type == LOGIC_MOVE)) { - const double strength = _drag_strength*DragTimerInterval*1.0/_time.elapsed(); - if (_time.elapsed() < 200 && - abs(_drag_strength) < MinorDragOffsetUp && - abs(strength) > MinorDragRateUp) { - _drag_strength = _drag_strength; - _drag_timer.start(DragTimerInterval); - _measure_type = LOGIC_MOVE; - } else if (_time.elapsed() < 200 && - abs(strength) > DragTimerInterval) { - _drag_strength = strength * 5; - _drag_timer.start(DragTimerInterval); - _measure_type = LOGIC_MOVE; - } else { - _drag_strength = 0; - _drag_timer.stop(); - _measure_type = NO_MEASURE; - } - } - - if (!_view.get_ruler()->get_grabbed_cursor() && _measure_type == LOGIC_CURS) - _measure_type = NO_MEASURE; - update(); } @@ -572,41 +758,44 @@ void Viewport::mouseDoubleClickEvent(QMouseEvent *event) assert (event); (void)event; - if (_view.session().get_device()->dev_inst()->mode == LOGIC) { - if (event->button() & Qt::RightButton) { + if (_view.session().get_device()->dev_inst()->mode == LOGIC && + _view.session().get_capture_state() == SigSession::Stopped) { + if (event->button() == Qt::RightButton) { if (_view.scale() == _view.get_maxscale()) _view.set_preScale_preOffset(); else _view.set_scale_offset(_view.get_maxscale(), 0); - } else if (event->button() & Qt::LeftButton) { - uint64_t index = (_view.offset() + (event->pos().x() + 0.5) * _view.scale()) * _view.session().get_device()->get_sample_rate(); + } else if (event->button() == Qt::LeftButton) { + uint64_t index = (_view.offset() + (event->pos().x() + 0.5) * _view.scale()) * _view.session().cur_samplerate(); _view.add_cursor(view::Ruler::CursorColor[_view.get_cursorList().size() % 8], index); _view.show_cursors(true); } update(); } else if (_view.session().get_device()->dev_inst()->mode == DSO && _view.session().get_capture_state() != SigSession::Init && - event->button() & Qt::LeftButton) { - if (_dso_xm_stage == 0) { - uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); - double scale = _view.scale(); - const double samples_per_pixel = sample_rate * scale; - _dso_xm_index[0] = event->pos().x() * samples_per_pixel + - _view.offset() * sample_rate;; - _dso_xm_stage = 1; - _dso_xm_y = event->pos().y(); - _dso_xm = true; - _measure_type = DSO_FREQ; - _measure_shown = true; - } else if (_dso_xm_stage == DsoMeasureStages) { - _dso_xm = false; - _measure_shown = _dso_ym; - _dso_xm_stage = 0; + event->button() == Qt::LeftButton) { + if (_dso_xm_valid) { + _dso_xm_valid = false; + _action_type = NO_ACTION; _mm_width = "#####"; _mm_period = "#####"; _mm_freq = "#####"; _mm_duty = "#####"; - mouse_measure(); + measure_updated(); + } else if (_action_type == NO_ACTION) { + BOOST_FOREACH(const boost::shared_ptr s, _view.session().get_signals()) { + assert(s); + if (s->get_view_rect().contains(event->pos())) { + uint64_t sample_rate = _view.session().cur_samplerate(); + double scale = _view.scale(); + const double samples_per_pixel = sample_rate * scale; + _dso_xm_index[0] = event->pos().x() * samples_per_pixel + + _view.offset() * sample_rate; + _dso_xm_y = event->pos().y(); + _action_type = DSO_XM_STEP0; + } + break; + } } } } @@ -615,29 +804,56 @@ void Viewport::wheelEvent(QWheelEvent *event) { assert(event); - if (event->orientation() == Qt::Vertical) { - // Vertical scrolling is interpreted as zooming in/out - const double offset = event->x(); - _view.zoom(event->delta() / 80, offset); - } else if (event->orientation() == Qt::Horizontal) { - // Horizontal scrolling is interpreted as moving left/right - _view.set_scale_offset(_view.scale(), - event->delta() * _view.scale() - + _view.offset()); - } + if (_type == FFT_VIEW) { + BOOST_FOREACH(const boost::shared_ptr t, _view.session().get_math_signals()) { + assert(t); + if(t->enabled()) { + t->zoom(event->delta() / 80, event->x()); + break; + } + } + } else if (_type == TIME_VIEW){ + if (event->orientation() == Qt::Vertical) { + // Vertical scrolling is interpreted as zooming in/out + const double offset = event->x(); + _view.zoom(event->delta() / 80, offset); + } else if (event->orientation() == Qt::Horizontal) { + // Horizontal scrolling is interpreted as moving left/right + _view.set_scale_offset(_view.scale(), + event->delta() * _view.scale() + + _view.offset()); + } + } measure(); } void Viewport::leaveEvent(QEvent *) { - _measure_shown = _dso_xm || _dso_ym; _mouse_point = QPoint(-1, -1); //_view.show_cursors(false); - if (_measure_type == LOGIC_EDGE || _measure_type == LOGIC_MOVE) { - _measure_type = NO_MEASURE; - _measure_shown = false; + + if (_action_type == LOGIC_EDGE) { + _edge_rising = 0; + _edge_falling = 0; + _action_type = NO_ACTION; + } else if (_action_type == LOGIC_MOVE) { + _drag_strength = 0; + _drag_timer.stop(); + _action_type = NO_ACTION; + } else if (_action_type == DSO_XM_STEP1 || _action_type == DSO_XM_STEP2) { + _dso_xm_valid = false; + _mm_width = "#####"; + _mm_period = "#####"; + _mm_freq = "#####"; + _mm_duty = "#####"; + _action_type = NO_ACTION; + } else if (_action_type == DSO_YM) { + _dso_ym_valid = false; + _action_type = NO_ACTION; } + + measure(); update(); } @@ -653,8 +869,8 @@ void Viewport::set_receive_len(quint64 length) start_trigger_timer(333); } else { stop_trigger_timer(); - if (_total_receive_len + length > _view.session().get_device()->get_sample_limit()) - _total_receive_len = _view.session().get_device()->get_sample_limit(); + if (_total_receive_len + length > _view.session().cur_samplelimits()) + _total_receive_len = _view.session().cur_samplelimits(); else _total_receive_len += length; } @@ -669,73 +885,83 @@ void Viewport::clear_measure() void Viewport::measure() { - if ((_view.session().get_device()->dev_inst()->mode == LOGIC && - _view.session().get_capture_state() == SigSession::Running) || - _drag_strength != 0) - return; - _measure_shown = _dso_xm || _dso_ym; - const 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); - boost::shared_ptr logicSig; - boost::shared_ptr dsoSig; - if (logicSig = dynamic_pointer_cast(s)) { - if (_measure_type != LOGIC_EDGE && - logicSig->measure(_view.hover_point(), _cur_sample, _nxt_sample, _thd_sample)) { - _measure_shown = true; - _measure_type = LOGIC_FREQ; + if (_view.session().get_data_lock()) + return; + _measure_type = NO_MEASURE; + if (_type == TIME_VIEW) { + const uint64_t sample_rate = _view.session().cur_samplerate(); + const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + assert(s); + boost::shared_ptr logicSig; + boost::shared_ptr dsoSig; + if (logicSig = dynamic_pointer_cast(s)) { + if (_action_type == NO_ACTION) { + if (logicSig->measure(_mouse_point, _cur_sample, _nxt_sample, _thd_sample)) { + _measure_type = LOGIC_FREQ; - _mm_width = _view.get_ruler()->format_real_time(_nxt_sample - _cur_sample, sample_rate); - _mm_period = _thd_sample != 0 ? _view.get_ruler()->format_real_time(_thd_sample - _cur_sample, sample_rate) : "#####"; - _mm_freq = _thd_sample != 0 ? _view.get_ruler()->format_real_freq(_thd_sample - _cur_sample, sample_rate) : "#####"; + _mm_width = _view.get_ruler()->format_real_time(_nxt_sample - _cur_sample, sample_rate); + _mm_period = _thd_sample != 0 ? _view.get_ruler()->format_real_time(_thd_sample - _cur_sample, sample_rate) : "#####"; + _mm_freq = _thd_sample != 0 ? _view.get_ruler()->format_real_freq(_thd_sample - _cur_sample, sample_rate) : "#####"; - const double pixels_offset = _view.offset() / _view.scale(); - const double samples_per_pixel = sample_rate * _view.scale(); - _cur_preX = _cur_sample / samples_per_pixel - pixels_offset; - _cur_aftX = _nxt_sample / samples_per_pixel - pixels_offset; - _cur_thdX = _thd_sample / samples_per_pixel - pixels_offset; - _cur_midY = logicSig->get_y(); + const double pixels_offset = _view.offset() / _view.scale(); + const double samples_per_pixel = sample_rate * _view.scale(); + _cur_preX = _cur_sample / samples_per_pixel - pixels_offset; + _cur_aftX = _nxt_sample / samples_per_pixel - pixels_offset; + _cur_thdX = _thd_sample / samples_per_pixel - pixels_offset; + _cur_midY = logicSig->get_y(); - _mm_duty = _thd_sample != 0 ? QString::number((_nxt_sample - _cur_sample) * 100.0 / (_thd_sample - _cur_sample), 'f', 2)+"%" : - "#####"; - mouse_measure(); - break; - } else if (_measure_type == LOGIC_EDGE && - logicSig->edges(_view.hover_point(), _edge_start, _edge_rising, _edge_falling)) { - _measure_shown = true; + _mm_duty = _thd_sample != 0 ? QString::number((_nxt_sample - _cur_sample) * 100.0 / (_thd_sample - _cur_sample), 'f', 2)+"%" : + "#####"; + break; + } else { + _measure_type = NO_MEASURE; + _mm_width = "#####"; + _mm_period = "#####"; + _mm_freq = "#####"; + _mm_duty = "#####"; + } + } else if (_action_type == LOGIC_EDGE) { + if (logicSig->edges(_view.hover_point(), _edge_start, _edge_rising, _edge_falling)) { + const double pixels_offset = _view.offset() / _view.scale(); + const double samples_per_pixel = sample_rate * _view.scale(); + _cur_preX = _edge_start / samples_per_pixel - pixels_offset; + _cur_aftX = _view.hover_point().x(); + _cur_midY = logicSig->get_y() - logicSig->get_totalHeight()/2 - 5; - const double pixels_offset = _view.offset() / _view.scale(); - const double samples_per_pixel = sample_rate * _view.scale(); - _cur_preX = _edge_start / samples_per_pixel - pixels_offset; - _cur_aftX = _view.hover_point().x(); - _cur_midY = logicSig->get_y() - logicSig->get_signalHeight()/2 - 5; + _em_rising = tr("Rising: ") + QString::number(_edge_rising); + _em_falling = tr("Falling: ") + QString::number(_edge_falling); + _em_edges = tr("Edges: ") + QString::number(_edge_rising + _edge_falling); - _em_rising = "Rising: " + QString::number(_edge_rising); - _em_falling = "Falling: " + QString::number(_edge_falling); - _em_edges = "Edges: " + QString::number(_edge_rising + _edge_falling); - - break; - } else { - _mm_width = "#####"; - _mm_period = "#####"; - _mm_freq = "#####"; - _mm_duty = "#####"; + break; + } + } + } else if (dsoSig = dynamic_pointer_cast(s)) { + if (_measure_en && dsoSig->measure(_view.hover_point())) { + _measure_type = DSO_VALUE; + break; + } else { + _measure_type = NO_MEASURE; + } } - mouse_measure(); - } else if (dsoSig = dynamic_pointer_cast(s)) { - if (_measure_en && dsoSig->measure(_view.hover_point())) { - _measure_shown = true; - _measure_type = DSO_FREQ; + } + } else if (_type == FFT_VIEW) { + BOOST_FOREACH(const boost::shared_ptr t, _view.session().get_math_signals()) { + assert(t); + if(t->enabled()) { + t->measure(_mouse_point); } } } + + measure_updated(); } void Viewport::paintMeasure(QPainter &p) { _hover_hit = false; - if (_measure_type == LOGIC_FREQ) { + if (_action_type == NO_ACTION && + _measure_type == LOGIC_FREQ) { p.setPen(QColor(17, 133, 209, 255)); p.drawLine(QLineF(_cur_preX, _cur_midY, _cur_aftX, _cur_midY)); p.drawLine(QLineF(_cur_preX, _cur_midY, _cur_preX + 2, _cur_midY - 2)); @@ -788,45 +1014,11 @@ void Viewport::paintMeasure(QPainter &p) p.drawText(measure4_rect, Qt::AlignRight | Qt::AlignVCenter, tr("Duty Cycle: ") + _mm_duty); } - } else if (_measure_type == LOGIC_EDGE) { - p.setPen(QColor(17, 133, 209, 255)); + } - p.drawLine(QLineF(_cur_preX, _cur_midY-5, _cur_preX, _cur_midY+5)); - p.drawLine(QLineF(_cur_aftX, _cur_midY-5, _cur_aftX, _cur_midY+5)); - p.drawLine(QLineF(_cur_preX, _cur_midY, _cur_aftX, _cur_midY)); - - int typical_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, - Qt::AlignLeft | Qt::AlignTop, _em_edges).width(); - typical_width = max(typical_width, p.boundingRect(0, 0, INT_MAX, INT_MAX, - Qt::AlignLeft | Qt::AlignTop, _em_rising).width()); - typical_width = max(typical_width, p.boundingRect(0, 0, INT_MAX, INT_MAX, - Qt::AlignLeft | Qt::AlignTop, _em_falling).width()); - - typical_width = typical_width + 30; - - const double width = _view.get_view_width(); - const double height = _view.viewport()->height(); - const double left = _view.hover_point().x(); - const double top = _view.hover_point().y(); - const double right = left + typical_width; - const double bottom = top + 60; - QPointF org_pos = QPointF(right > width ? left - typical_width : left, bottom > height ? top - 80 : top); - QRectF measure_rect = QRectF(org_pos.x(), org_pos.y(), (double)typical_width, 60.0); - QRectF measure1_rect = QRectF(org_pos.x(), org_pos.y(), (double)typical_width, 20.0); - QRectF measure2_rect = QRectF(org_pos.x(), org_pos.y()+20, (double)typical_width, 20.0); - QRectF measure3_rect = QRectF(org_pos.x(), org_pos.y()+40, (double)typical_width, 20.0); - - p.setPen(Qt::NoPen); - p.setBrush(QColor(17, 133, 209, 150)); - p.drawRect(measure_rect); - - p.setPen(Qt::black); - p.drawText(measure1_rect, Qt::AlignRight | Qt::AlignVCenter, _em_edges); - p.drawText(measure2_rect, Qt::AlignRight | Qt::AlignVCenter, _em_rising); - p.drawText(measure3_rect, Qt::AlignRight | Qt::AlignVCenter, _em_falling); - - } else if (_measure_type == DSO_FREQ) { - const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + if (_action_type == NO_ACTION && + _measure_type == DSO_VALUE) { BOOST_FOREACH(const boost::shared_ptr s, sigs) { boost::shared_ptr dsoSig; if (dsoSig = dynamic_pointer_cast(s)) { @@ -883,132 +1075,177 @@ void Viewport::paintMeasure(QPainter &p) } } } + } - // -- vertical value - if (_dso_ym) { - BOOST_FOREACH(const boost::shared_ptr s, sigs) { - boost::shared_ptr dsoSig; - if (dsoSig = dynamic_pointer_cast(s)) { - if (dsoSig->get_index() == _dso_ym_sig_index) { - p.setPen(QPen(dsoSig->get_colour(), 1, Qt::DotLine)); - const int text_height = p.boundingRect(0, 0, INT_MAX, INT_MAX, - Qt::AlignLeft | Qt::AlignTop, "W").height(); - const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); - const double x = (_dso_ym_index / (sample_rate * _view.scale())) - - _view.offset() /_view.scale(); - p.drawLine(x-10, _dso_ym_start, - x+10, _dso_ym_start); - p.drawLine(x, _dso_ym_start, - x, _dso_ym_end); - p.drawLine(0, _dso_ym_end, - _view.get_view_width(), _dso_ym_end); + if (_dso_ym_valid) { + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + if (dsoSig->get_index() == _dso_ym_sig_index) { + p.setPen(QPen(dsoSig->get_colour(), 1, Qt::DotLine)); + const int text_height = p.boundingRect(0, 0, INT_MAX, INT_MAX, + Qt::AlignLeft | Qt::AlignTop, "W").height(); + const uint64_t sample_rate = _view.session().cur_samplerate(); + const double x = (_dso_ym_index / (sample_rate * _view.scale())) - + _view.offset() /_view.scale(); + p.drawLine(x-10, _dso_ym_start, + x+10, _dso_ym_start); + p.drawLine(x, _dso_ym_start, + x, _dso_ym_end); + p.drawLine(0, _dso_ym_end, + _view.get_view_width(), _dso_ym_end); - // -- vertical delta value - double hrate = (_dso_ym_start - _dso_ym_end) * 1.0f / _view.get_view_height(); - double value = hrate * dsoSig->get_vDialValue() * dsoSig->get_factor() * DS_CONF_DSO_VDIVS; - QString value_str = abs(value) > 1000 ? QString::number(value/1000.0, 'f', 2) + "V" : QString::number(value, 'f', 2) + "mV"; - int value_rect_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, - Qt::AlignLeft | Qt::AlignVCenter, value_str).width(); - p.drawText(QRect(x+10, abs(_dso_ym_start+_dso_ym_end)/2, value_rect_width, text_height), - value_str); + // -- vertical delta value + double hrate = (_dso_ym_start - _dso_ym_end) * 1.0f / _view.get_view_height(); + double value = hrate * dsoSig->get_vDialValue() * dsoSig->get_factor() * DS_CONF_DSO_VDIVS; + QString value_str = abs(value) > 1000 ? QString::number(value/1000.0, 'f', 2) + "V" : QString::number(value, 'f', 2) + "mV"; + int value_rect_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + Qt::AlignLeft | Qt::AlignVCenter, value_str).width(); + p.drawText(QRect(x+10, abs(_dso_ym_start+_dso_ym_end)/2, value_rect_width, text_height), + value_str); - // -- start value - value_str = abs(_dso_ym_sig_value) > 1000 ? QString::number(_dso_ym_sig_value/1000.0, 'f', 2) + "V" : QString::number(_dso_ym_sig_value, 'f', 2) + "mV"; - value_rect_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, - Qt::AlignLeft | Qt::AlignVCenter, value_str).width(); - int str_y = value > 0 ? _dso_ym_start : _dso_ym_start - text_height; - p.drawText(QRect(x-0.5*value_rect_width, str_y, value_rect_width, text_height), - value_str); + // -- start value + value_str = abs(_dso_ym_sig_value) > 1000 ? QString::number(_dso_ym_sig_value/1000.0, 'f', 2) + "V" : QString::number(_dso_ym_sig_value, 'f', 2) + "mV"; + value_rect_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + Qt::AlignLeft | Qt::AlignVCenter, value_str).width(); + int str_y = value > 0 ? _dso_ym_start : _dso_ym_start - text_height; + p.drawText(QRect(x-0.5*value_rect_width, str_y, value_rect_width, text_height), + value_str); - // -- end value - double end_value = _dso_ym_sig_value + value; - value_str = abs(end_value) > 1000 ? QString::number(end_value/1000.0, 'f', 2) + "V" : QString::number(end_value, 'f', 2) + "mV"; - value_rect_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, - Qt::AlignLeft | Qt::AlignVCenter, value_str).width(); - str_y = value > 0 ? _dso_ym_end-text_height : _dso_ym_end; - p.drawText(QRect(x-0.5*value_rect_width, str_y, value_rect_width, text_height), - value_str); - break; - } + // -- end value + double end_value = _dso_ym_sig_value + value; + value_str = abs(end_value) > 1000 ? QString::number(end_value/1000.0, 'f', 2) + "V" : QString::number(end_value, 'f', 2) + "mV"; + value_rect_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + Qt::AlignLeft | Qt::AlignVCenter, value_str).width(); + str_y = value > 0 ? _dso_ym_end-text_height : _dso_ym_end; + p.drawText(QRect(x-0.5*value_rect_width, str_y, value_rect_width, text_height), + value_str); + break; } } } + } - // -- width/period/frequency/duty - if (_dso_xm) { - p.setPen(QPen(Qt::red, 1, Qt::DotLine)); - int measure_line_count = 6; - const int text_height = p.boundingRect(0, 0, INT_MAX, INT_MAX, - Qt::AlignLeft | Qt::AlignTop, "W").height(); - const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); - QLineF *line; - QLineF *const measure_lines = new QLineF[measure_line_count]; - line = measure_lines; - double x[DsoMeasureStages]; - for (int i = 0; i < _dso_xm_stage; i++) { - x[i] = (_dso_xm_index[i] / (sample_rate * _view.scale())) - - _view.offset() /_view.scale(); - } - measure_line_count = 0; - if (_dso_xm_stage > 0) { - *line++ = QLineF(x[0], _dso_xm_y - 10, - x[0], _dso_xm_y + 10); - measure_line_count += 1; - } - if (_dso_xm_stage > 1) { - *line++ = QLineF(x[1], _dso_xm_y - 10, - x[1], _dso_xm_y + 10); - *line++ = QLineF(x[0], _dso_xm_y, - x[1], _dso_xm_y); - _mm_width = _view.get_ruler()->format_real_time(_dso_xm_index[1] - _dso_xm_index[0], sample_rate); + if (_dso_xm_valid) { + p.setPen(QPen(Qt::red, 1, Qt::DotLine)); + int measure_line_count = 6; + const int text_height = p.boundingRect(0, 0, INT_MAX, INT_MAX, + Qt::AlignLeft | Qt::AlignTop, "W").height(); + const uint64_t sample_rate = _view.session().cur_samplerate(); + QLineF *line; + QLineF *const measure_lines = new QLineF[measure_line_count]; + line = measure_lines; + double x[DsoMeasureStages]; + int dso_xm_stage = 0; + if (_action_type == DSO_XM_STEP1) + dso_xm_stage = 1; + else if(_action_type == DSO_XM_STEP2) + dso_xm_stage = 2; + else + dso_xm_stage = 3; - // -- width show - const QString w_ctr = "W="+_mm_width; - int w_rect_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, - Qt::AlignLeft | Qt::AlignVCenter, w_ctr).width(); - p.drawText(QRect(x[0]+10, _dso_xm_y - text_height, w_rect_width, text_height), w_ctr); - measure_line_count += 2; - } - if (_dso_xm_stage > 2) { - *line++ = QLineF(x[0], _dso_xm_y + 20, - x[0], _dso_xm_y + 40); - *line++ = QLineF(x[0], _dso_xm_y + 30, - x[2], _dso_xm_y + 30); - *line++ = QLineF(x[2], _dso_xm_y + 20, - x[2], _dso_xm_y + 40); - _mm_period = _view.get_ruler()->format_real_time(_dso_xm_index[2] - _dso_xm_index[0], sample_rate); - _mm_freq = _view.get_ruler()->format_real_freq(_dso_xm_index[2] - _dso_xm_index[0], sample_rate); - _mm_duty = QString::number((_dso_xm_index[1] - _dso_xm_index[0]) * 100.0 / (_dso_xm_index[2] - _dso_xm_index[0]), 'f', 2)+"%"; - - // -- period show - const QString p_ctr = "P="+_mm_period; - int p_rect_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, - Qt::AlignLeft | Qt::AlignVCenter, p_ctr).width(); - p.drawText(QRect(x[0]+10, _dso_xm_y + 30 - text_height, p_rect_width, text_height), p_ctr); - - // -- frequency show - const QString f_ctr = "F="+_mm_freq; - int f_rect_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, - Qt::AlignLeft | Qt::AlignVCenter, f_ctr).width(); - p.drawText(QRect(x[0]+20 + p_rect_width, _dso_xm_y + 30 - text_height, f_rect_width, text_height), f_ctr); - - // -- duty show - const QString d_ctr = "D="+_mm_duty; - int d_rect_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, - Qt::AlignLeft | Qt::AlignVCenter, d_ctr).width(); - p.drawText(QRect(x[1]+10, _dso_xm_y - 0.5*text_height, d_rect_width, text_height), d_ctr); - - measure_line_count += 3; - } - p.drawLines(measure_lines, measure_line_count); - if (_dso_xm_stage < DsoMeasureStages) { - p.drawLine(x[_dso_xm_stage-1], _dso_xm_y, - _mouse_point.x(), _dso_xm_y); - p.drawLine(_mouse_point.x(), 0, - _mouse_point.x(), _view.get_viewport()->height()); - } - mouse_measure(); + for (int i = 0; i < dso_xm_stage; i++) { + x[i] = (_dso_xm_index[i] / (sample_rate * _view.scale())) - + _view.offset() /_view.scale(); } + measure_line_count = 0; + if (dso_xm_stage > 0) { + *line++ = QLineF(x[0], _dso_xm_y - 10, + x[0], _dso_xm_y + 10); + measure_line_count += 1; + } + if (dso_xm_stage > 1) { + *line++ = QLineF(x[1], _dso_xm_y - 10, + x[1], _dso_xm_y + 10); + *line++ = QLineF(x[0], _dso_xm_y, + x[1], _dso_xm_y); + _mm_width = _view.get_ruler()->format_real_time(_dso_xm_index[1] - _dso_xm_index[0], sample_rate); + + // -- width show + const QString w_ctr = "W="+_mm_width; + int w_rect_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + Qt::AlignLeft | Qt::AlignVCenter, w_ctr).width(); + p.drawText(QRect(x[0]+10, _dso_xm_y - text_height, w_rect_width, text_height), w_ctr); + measure_line_count += 2; + } + if (dso_xm_stage > 2) { + *line++ = QLineF(x[0], _dso_xm_y + 20, + x[0], _dso_xm_y + 40); + *line++ = QLineF(x[0], _dso_xm_y + 30, + x[2], _dso_xm_y + 30); + *line++ = QLineF(x[2], _dso_xm_y + 20, + x[2], _dso_xm_y + 40); + _mm_period = _view.get_ruler()->format_real_time(_dso_xm_index[2] - _dso_xm_index[0], sample_rate); + _mm_freq = _view.get_ruler()->format_real_freq(_dso_xm_index[2] - _dso_xm_index[0], sample_rate); + _mm_duty = QString::number((_dso_xm_index[1] - _dso_xm_index[0]) * 100.0 / (_dso_xm_index[2] - _dso_xm_index[0]), 'f', 2)+"%"; + + // -- period show + const QString p_ctr = "P="+_mm_period; + int p_rect_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + Qt::AlignLeft | Qt::AlignVCenter, p_ctr).width(); + p.drawText(QRect(x[0]+10, _dso_xm_y + 30 - text_height, p_rect_width, text_height), p_ctr); + + // -- frequency show + const QString f_ctr = "F="+_mm_freq; + int f_rect_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + Qt::AlignLeft | Qt::AlignVCenter, f_ctr).width(); + p.drawText(QRect(x[0]+20 + p_rect_width, _dso_xm_y + 30 - text_height, f_rect_width, text_height), f_ctr); + + // -- duty show + const QString d_ctr = "D="+_mm_duty; + int d_rect_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + Qt::AlignLeft | Qt::AlignVCenter, d_ctr).width(); + p.drawText(QRect(x[1]+10, _dso_xm_y - 0.5*text_height, d_rect_width, text_height), d_ctr); + + measure_line_count += 3; + } + p.drawLines(measure_lines, measure_line_count); + if (dso_xm_stage < DsoMeasureStages) { + p.drawLine(x[dso_xm_stage-1], _dso_xm_y, + _mouse_point.x(), _dso_xm_y); + p.drawLine(_mouse_point.x(), 0, + _mouse_point.x(), height()); + } + measure_updated(); + } + + if (_action_type == LOGIC_EDGE) { + p.setPen(QColor(17, 133, 209, 255)); + + p.drawLine(QLineF(_cur_preX, _cur_midY-5, _cur_preX, _cur_midY+5)); + p.drawLine(QLineF(_cur_aftX, _cur_midY-5, _cur_aftX, _cur_midY+5)); + p.drawLine(QLineF(_cur_preX, _cur_midY, _cur_aftX, _cur_midY)); + + int typical_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + Qt::AlignLeft | Qt::AlignTop, _em_edges).width(); + typical_width = max(typical_width, p.boundingRect(0, 0, INT_MAX, INT_MAX, + Qt::AlignLeft | Qt::AlignTop, _em_rising).width()); + typical_width = max(typical_width, p.boundingRect(0, 0, INT_MAX, INT_MAX, + Qt::AlignLeft | Qt::AlignTop, _em_falling).width()); + + typical_width = typical_width + 30; + + const double width = _view.get_view_width(); + const double height = _view.viewport()->height(); + const double left = _view.hover_point().x(); + const double top = _view.hover_point().y(); + const double right = left + typical_width; + const double bottom = top + 60; + QPointF org_pos = QPointF(right > width ? left - typical_width : left, bottom > height ? top - 80 : top); + QRectF measure_rect = QRectF(org_pos.x(), org_pos.y(), (double)typical_width, 60.0); + QRectF measure1_rect = QRectF(org_pos.x(), org_pos.y(), (double)typical_width, 20.0); + QRectF measure2_rect = QRectF(org_pos.x(), org_pos.y()+20, (double)typical_width, 20.0); + QRectF measure3_rect = QRectF(org_pos.x(), org_pos.y()+40, (double)typical_width, 20.0); + + p.setPen(Qt::NoPen); + p.setBrush(QColor(17, 133, 209, 150)); + p.drawRect(measure_rect); + + p.setPen(Qt::black); + p.drawText(measure1_rect, Qt::AlignRight | Qt::AlignVCenter, _em_edges); + p.drawText(measure2_rect, Qt::AlignRight | Qt::AlignVCenter, _em_rising); + p.drawText(measure3_rect, Qt::AlignRight | Qt::AlignVCenter, _em_falling); + } } @@ -1067,10 +1304,35 @@ void Viewport::on_drag_timer() _drag_strength /= DragDamping; if (_drag_strength != 0) _drag_timer.start(DragTimerInterval); - } else { + } else if (offset == _view.get_max_offset() || + offset == _view.get_min_offset()) { + _drag_strength = 0; + _drag_timer.stop(); + _action_type = NO_ACTION; + }else if (_action_type == NO_ACTION){ + _drag_strength = 0; _drag_timer.stop(); } } +void Viewport::set_need_update(bool update) +{ + _need_update = update; +} + +void Viewport::show_wait_trigger() +{ + _waiting_trig %= (WaitLoopTime / SigSession::ViewTime) * 4; + _waiting_trig++; + update(); +} + +void Viewport::unshow_wait_trigger() +{ + _waiting_trig = 0; + update(); +} + + } // namespace view } // namespace pv diff --git a/DSView/pv/view/viewport.h b/DSView/pv/view/viewport.h index 40a15bbc..588dbda0 100644 --- a/DSView/pv/view/viewport.h +++ b/DSView/pv/view/viewport.h @@ -3,7 +3,7 @@ * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -30,8 +30,12 @@ #include #include #include + #include +#include "../../extdef.h" +#include "../view/view.h" + class QPainter; class QPaintEvent; class SigSession; @@ -54,17 +58,33 @@ public: static const int DsoMeasureStages = 3; static const double MinorDragRateUp; static const double DragDamping; + static const int SnapMinSpace = 10; + static const int WaitLoopTime = 400; + enum ActionType { + NO_ACTION, + + CURS_MOVE, + + LOGIC_EDGE, + LOGIC_MOVE, + LOGIC_ZOOM, + + DSO_XM_STEP0, + DSO_XM_STEP1, + DSO_XM_STEP2, + DSO_YM, + DSO_TRIG_MOVE + }; + enum MeasureType { NO_MEASURE, LOGIC_FREQ, - LOGIC_EDGE, - LOGIC_MOVE, - LOGIC_CURS, - DSO_FREQ + LOGIC_EDGE_CNT, + DSO_VALUE }; public: - explicit Viewport(View &parent); + explicit Viewport(View &parent, View_type type); int get_total_height() const; @@ -79,6 +99,8 @@ public: void clear_measure(); + void set_need_update(bool update); + protected: void paintEvent(QPaintEvent *event); @@ -102,11 +124,17 @@ private slots: void on_drag_timer(); void set_receive_len(quint64 length); +public slots: + void show_wait_trigger(); + void unshow_wait_trigger(); + signals: - void mouse_measure(); + void measure_updated(); private: View &_view; + View_type _type; + bool _need_update; uint64_t _total_receive_len; QPoint _mouse_point; @@ -118,11 +146,8 @@ private: QPixmap pixmap; - bool _zoom_rect_visible; - QRectF _zoom_rect; - bool _measure_en; - bool _measure_shown; + ActionType _action_type; MeasureType _measure_type; uint64_t _cur_sample; uint64_t _nxt_sample; @@ -158,18 +183,18 @@ private: QTimer _drag_timer; int _drag_strength; - bool _dso_xm; - int _dso_xm_stage; + bool _dso_xm_valid; int _dso_xm_y; uint64_t _dso_xm_index[DsoMeasureStages]; - bool _dso_ym; - bool _dso_ym_done; + bool _dso_ym_valid; uint16_t _dso_ym_sig_index; double _dso_ym_sig_value; uint64_t _dso_ym_index; int _dso_ym_start; int _dso_ym_end; + + int _waiting_trig; }; } // namespace view diff --git a/DSView/pv/widgets/border.cpp b/DSView/pv/widgets/border.cpp new file mode 100644 index 00000000..3196d188 --- /dev/null +++ b/DSView/pv/widgets/border.cpp @@ -0,0 +1,107 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 "border.h" +#include "../mainframe.h" + +#include +#include +#include + +namespace pv { +namespace widgets { + +Border::Border(int type, QWidget *parent) : + QWidget(parent), + _type(type) +{ + setAttribute(Qt::WA_TranslucentBackground); + setMouseTracking(true); +} + +void Border::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + painter.setPen(Qt::NoPen); + painter.setRenderHint(QPainter::Antialiasing, true); + QLinearGradient linearGrad(QPointF(width(), height()), QPointF(0, 0)); + linearGrad.setColorAt(0, QColor(48, 47, 47, 255)); + linearGrad.setColorAt(0.25, QColor(48, 47, 47, 255)); + linearGrad.setColorAt(0.5, QColor(48, 47, 47, 255)); + linearGrad.setColorAt(0.75, QColor(48, 47, 47, 100)); + linearGrad.setColorAt(1, QColor(48, 47, 47, 10)); + + QRadialGradient radialGrad(QPointF(0, 0), width()); + radialGrad.setColorAt(0, QColor(48, 47, 47, 255)); + radialGrad.setColorAt(0.25, QColor(48, 47, 47, 255)); + radialGrad.setColorAt(0.5, QColor(48, 47, 47, 255)); + radialGrad.setColorAt(0.75, QColor(48, 47, 47, 100)); + radialGrad.setColorAt(1, QColor(48, 47, 47, 10)); + + if (_type == pv::MainFrame::TopLeft) { + QRectF rectangle(0, 0, width()*2, height()*2); + radialGrad.setCenter(QPointF(width(), height())); + radialGrad.setFocalPoint(QPointF(width(), height())); + painter.setBrush(QBrush(radialGrad)); + painter.drawPie(rectangle, 90 * 16, 180 * 16); + } else if (_type == pv::MainFrame::TopRight) { + QRectF rectangle(-width(), 0, width()*2, height()*2); + radialGrad.setCenter(QPointF(0, height())); + radialGrad.setFocalPoint(QPointF(0, height())); + painter.setBrush(QBrush(radialGrad)); + painter.drawPie(rectangle, 0 * 16, 90 * 16); + } else if (_type == pv::MainFrame::BottomLeft) { + QRectF rectangle(0, -height(), width()*2, height()*2); + radialGrad.setCenter(QPointF(width(), 0)); + radialGrad.setFocalPoint(QPointF(width(), 0)); + painter.setBrush(QBrush(radialGrad)); + painter.drawPie(rectangle, 180 * 16, 270 * 16); + } else if (_type == pv::MainFrame::BottomRight) { + QRectF rectangle(-width(), -height(), width()*2, height()*2); + radialGrad.setCenter(QPointF(0, 0)); + radialGrad.setFocalPoint(QPointF(0, 0)); + painter.setBrush(QBrush(radialGrad)); + painter.drawPie(rectangle, 270 * 16, 360 * 16); + } else if (_type == pv::MainFrame::Top) { + linearGrad.setStart(QPointF(0, height())); + linearGrad.setFinalStop(QPointF(0, 0)); + painter.setBrush(QBrush(linearGrad)); + painter.drawRect(rect()); + } else if (_type == pv::MainFrame::Bottom) { + linearGrad.setStart(QPointF(0, 0)); + linearGrad.setFinalStop(QPointF(0, height())); + painter.setBrush(QBrush(linearGrad)); + painter.drawRect(rect()); + } else if (_type == pv::MainFrame::Left) { + linearGrad.setStart(QPointF(width(), 0)); + linearGrad.setFinalStop(QPointF(0, 0)); + painter.setBrush(QBrush(linearGrad)); + painter.drawRect(rect()); + } else if (_type == pv::MainFrame::Right) { + linearGrad.setStart(QPointF(0, 0)); + linearGrad.setFinalStop(QPointF(width(), 0)); + painter.setBrush(QBrush(linearGrad)); + painter.drawRect(rect()); + } +} + +} // namespace widgets +} // namespace pv diff --git a/DSView/pv/widgets/border.h b/DSView/pv/widgets/border.h new file mode 100644 index 00000000..970ac42f --- /dev/null +++ b/DSView/pv/widgets/border.h @@ -0,0 +1,46 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 DSVIEW_PV_WIDGETS_BORDER_H +#define DSVIEW_PV_WIDGETS_BORDER_H + +#include + +namespace pv { +namespace widgets { + +class Border : public QWidget +{ + Q_OBJECT +public: + explicit Border(int type, QWidget *parent = 0); + +protected: + void paintEvent(QPaintEvent *); + +private: + int _type; +}; + +} // namespace widgets +} // namespace pv + +#endif // DSVIEW_PV_WIDGETS_BORDER_H diff --git a/DSView/pv/widgets/decodergroupbox.cpp b/DSView/pv/widgets/decodergroupbox.cpp index 3b4ec20a..1b802e38 100644 --- a/DSView/pv/widgets/decodergroupbox.cpp +++ b/DSView/pv/widgets/decodergroupbox.cpp @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * Copyright (C) 2013 Joel Holdsworth + * Copyright (C) 2016 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 @@ -17,52 +18,139 @@ * 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 "decodergroupbox.h" +#include "../data/decoderstack.h" +#include "../data/decode/decoder.h" +#include "../data/decode/row.h" #include #include #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/shown.png"), QString(), this) +DecoderGroupBox::DecoderGroupBox(boost::shared_ptr &decoder_stack, + boost::shared_ptr &dec, + QWidget *parent) : + QWidget(parent), + _decoder_stack(decoder_stack), + _dec(dec), + _layout(new QGridLayout(this)) { _layout->setContentsMargins(0, 0, 0, 0); - setLayout(_layout); + _layout->setVerticalSpacing(5); + setLayout(_layout); - _layout->addWidget(new QLabel(QString("

%1

").arg(title)), - 0, 0); + _layout->addWidget(new QLabel(QString("

%1

").arg(_dec->decoder()->name), this), + 0, 0); _layout->setColumnStretch(0, 1); - QHBoxLayout *const toolbar = new QHBoxLayout; - _layout->addLayout(toolbar, 0, 1); + const srd_decoder *const d = _dec->decoder(); + assert(d); + const bool have_probes = (d->channels || d->opt_channels) != 0; + if (!have_probes) { + _del_button = new QPushButton(QIcon(":/icons/del.png"), QString(), this); + _layout->addWidget(_del_button, 0, 1); + connect(_del_button, SIGNAL(clicked()), this, SLOT(on_del_stack())); + } - _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); + _index = 0; + BOOST_FOREACH(boost::shared_ptr dec, + _decoder_stack->stack()) { + if (dec == _dec) + break; + _index++; + } + _show_button = new QPushButton(QIcon(_dec->shown() ? + ":/icons/shown.png" : + ":/icons/hidden.png"), QString(), this); + _show_button->setProperty("index", -1); + connect(_show_button, SIGNAL(clicked()), + this, SLOT(tog_icon())); + _layout->addWidget(_show_button, 0, 2); + + + // add row show/hide + int index = 0; + const std::map rows = _decoder_stack->get_rows_gshow(); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + if ((*i).first.decoder() == _dec->decoder()) { + QPushButton *show_button = new QPushButton(QIcon((*i).second ? + ":/icons/shown.png" : + ":/icons/hidden.png"), QString(), this); + show_button->setProperty("index", index); + connect(show_button, SIGNAL(clicked()), this, SLOT(tog_icon())); + _row_show_button.push_back(show_button); + _layout->addWidget(new QLabel((*i).first.title(), this), _row_show_button.size(), 0); + _layout->addWidget(show_button, _row_show_button.size(), 2); + } + index++; + } +} + +DecoderGroupBox::~DecoderGroupBox() +{ } void DecoderGroupBox::add_layout(QLayout *layout) { assert(layout); - _layout->addLayout(layout, 1, 0, 1, 2); + _layout->addLayout(layout, _row_show_button.size()+1, 0, 1, 3); } -void DecoderGroupBox::set_decoder_visible(bool visible) +void DecoderGroupBox::tog_icon() { - _show_hide_button.setIcon(QIcon(visible ? - ":/icons/shown.png" : - ":/icons/hidden.png")); + QPushButton *sc = dynamic_cast(sender()); + QVariant id = sc->property("index"); + int index = id.toInt(); + if (index == -1) { + int i = _index; + BOOST_FOREACH(boost::shared_ptr dec, + _decoder_stack->stack()) { + if (i-- == 0) { + dec->show(!dec->shown()); + sc->setIcon(QIcon(dec->shown() ? ":/icons/shown.png" : + ":/icons/hidden.png")); + break; + } + } + } else { + std::map rows = _decoder_stack->get_rows_gshow(); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + if (index-- == 0) { + _decoder_stack->set_rows_gshow((*i).first, !(*i).second); + //rows[(*i).first] = !(*i).second; + sc->setIcon(QIcon(rows[(*i).first] ? ":/icons/hidden.png" : + ":/icons/shown.png")); + break; + } + } + } +} + +void DecoderGroupBox::on_del_stack() +{ + int i = _index; + BOOST_FOREACH(boost::shared_ptr dec, + _decoder_stack->stack()) { + if (i-- == 0) { + del_stack(dec); + break; + } + } } } // widgets diff --git a/DSView/pv/widgets/decodergroupbox.h b/DSView/pv/widgets/decodergroupbox.h index 07878ae2..b83eef1c 100644 --- a/DSView/pv/widgets/decodergroupbox.h +++ b/DSView/pv/widgets/decodergroupbox.h @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * Copyright (C) 2013 Joel Holdsworth + * Copyright (C) 2016 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 @@ -22,11 +23,19 @@ #define DSVIEW_PV_WIDGETS_DECODERGROUPBOX_H #include - -class QGridLayout; -class QToolBar; +#include +#include +#include namespace pv { + +namespace data{ +class DecoderStack; +namespace decode{ +class Decoder; +} +} + namespace widgets { class DecoderGroupBox : public QWidget @@ -34,18 +43,30 @@ class DecoderGroupBox : public QWidget Q_OBJECT public: - DecoderGroupBox(QString title, QWidget *parent = NULL); - + DecoderGroupBox(boost::shared_ptr &decoder_stack, + boost::shared_ptr &dec, + QWidget *parent = NULL); + ~DecoderGroupBox(); void add_layout(QLayout *layout); - void set_decoder_visible(bool visible); - signals: void show_hide_decoder(); + void show_hide_row(); + void del_stack(boost::shared_ptr &_dec); + +private slots: + void tog_icon(); + void on_del_stack(); private: - QGridLayout *const _layout; - QPushButton _show_hide_button; + boost::shared_ptr &_decoder_stack; + boost::shared_ptr &_dec; + int _index; + + QGridLayout *const _layout; + QPushButton *_del_button; + QPushButton *_show_button; + std::list _row_show_button; }; } // widgets diff --git a/DSView/pv/widgets/fakelineedit.cpp b/DSView/pv/widgets/fakelineedit.cpp index 84e0c278..d8a2930a 100644 --- a/DSView/pv/widgets/fakelineedit.cpp +++ b/DSView/pv/widgets/fakelineedit.cpp @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 diff --git a/DSView/pv/widgets/fakelineedit.h b/DSView/pv/widgets/fakelineedit.h index a274f990..071c59e4 100644 --- a/DSView/pv/widgets/fakelineedit.h +++ b/DSView/pv/widgets/fakelineedit.h @@ -2,8 +2,7 @@ * This file is part of the DSView project. * DSView is based on PulseView. * - * Copyright (C) 2012 Joel Holdsworth - * Copyright (C) 2013 DreamSourceLab + * 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 diff --git a/DSView/pv/widgets/viewstatus.cpp b/DSView/pv/widgets/viewstatus.cpp new file mode 100644 index 00000000..2b57a6c9 --- /dev/null +++ b/DSView/pv/widgets/viewstatus.cpp @@ -0,0 +1,66 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 "viewstatus.h" + +#include +#include +#include + +#include "../view/trace.h" + +namespace pv { +namespace widgets { + +ViewStatus::ViewStatus(QWidget *parent) : QWidget(parent) +{ +} + +void ViewStatus::paintEvent(QPaintEvent *) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); + + p.setPen(pv::view::Trace::DARK_FORE); + p.drawText(this->rect(), Qt::AlignLeft | Qt::AlignVCenter, _rle_depth); + p.drawText(this->rect(), Qt::AlignRight | Qt::AlignVCenter, _trig_time); +} + +void ViewStatus::clear() +{ + _trig_time.clear(); + _rle_depth.clear(); +} + +void ViewStatus::set_trig_time(QDateTime time) +{ + _trig_time = tr("Trigger Time: ") + time.toString("yyyy-MM-dd hh:mm:ss ddd"); +} + +void ViewStatus::set_rle_depth(uint64_t depth) +{ + _rle_depth = tr("RLE FULL: ") + QString::number(depth) + tr(" Samples Captured!"); +} + +} // namespace widgets +} // namespace pv diff --git a/DSView/pv/widgets/viewstatus.h b/DSView/pv/widgets/viewstatus.h new file mode 100644 index 00000000..58078d0d --- /dev/null +++ b/DSView/pv/widgets/viewstatus.h @@ -0,0 +1,58 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 DSVIEW_PV_WIDGETS_VIEWSTATUS_H +#define DSVIEW_PV_WIDGETS_VIEWSTATUS_H + +#include +#include +#include "QDateTime" + +namespace pv { + +class SigSession; + +namespace widgets { + +class ViewStatus : public QWidget +{ + Q_OBJECT +public: + explicit ViewStatus(QWidget *parent = 0); + + void paintEvent(QPaintEvent *); + +signals: + +public slots: + void clear(); + void set_trig_time(QDateTime time); + void set_rle_depth(uint64_t depth); + +private: + QString _trig_time; + QString _rle_depth; +}; + +} // namespace widgets +} // namespace pv + +#endif // DSVIEW_PV_WIDGETS_VIEWSTATUS_H diff --git a/DSView/res/DSCope.bin b/DSView/res/DSCope.bin old mode 100644 new mode 100755 index 505dbb74..e56e9a42 Binary files a/DSView/res/DSCope.bin and b/DSView/res/DSCope.bin differ diff --git a/DSView/res/DSCope.fw b/DSView/res/DSCope.fw old mode 100644 new mode 100755 index 28b5af07..030486b2 Binary files a/DSView/res/DSCope.fw and b/DSView/res/DSCope.fw differ diff --git a/DSView/res/DSCope1.def.dsc b/DSView/res/DSCope1.def.dsc old mode 100644 new mode 100755 index 12412f65..ea6deb45 --- a/DSView/res/DSCope1.def.dsc +++ b/DSView/res/DSCope1.def.dsc @@ -1,40 +1,40 @@ -{ - "Device": "DSCope", - "DeviceMode": 1, - "Horizontal trigger position": "0", - "Operation Mode": "Normal", - "Sample count": "1048576", - "Sample rate": "100000000", - "Time base": "10000", - "Trigger hold off": "0", - "Trigger slope": "0", - "Trigger source": "0", - "channel": [ - { - "colour": "#eeb211", - "coupling": 0, - "enabled": true, - "index": 0, - "name": "0", - "strigger": 0, - "trigValue": 0.5, - "type": 10001, - "vdiv": 1000, - "vfactor": 1, - "zeroPos": 0.5 - }, - { - "colour": "#009925", - "coupling": 0, - "enabled": true, - "index": 1, - "name": "1", - "strigger": 0, - "trigValue": 0.5, - "type": 10001, - "vdiv": 1000, - "vfactor": 1, - "zeroPos": 0.5 - } - ] -} +{ + "Device": "DSCope", + "DeviceMode": 1, + "Horizontal trigger position": "0", + "Operation Mode": "Normal", + "Sample count": "1048576", + "Sample rate": "100000000", + "Time base": "10000", + "Trigger channel": "0", + "Trigger hold off": "0", + "Trigger margin": "8", + "Trigger slope": "0", + "Trigger source": "0", + "channel": [ + { + "colour": "#eeb211", + "coupling": 0, + "enabled": true, + "index": 0, + "name": "0", + "trigValue": 0.50196078431372548, + "type": 10001, + "vdiv": 1000, + "vfactor": 1, + "zeroPos": 0.5 + }, + { + "colour": "#009925", + "coupling": 0, + "enabled": true, + "index": 1, + "name": "1", + "trigValue": 0.50196078431372548, + "type": 10001, + "vdiv": 1000, + "vfactor": 1, + "zeroPos": 0.5 + } + ] +} diff --git a/DSView/res/DSCope1.dsc b/DSView/res/DSCope1.dsc deleted file mode 100644 index 12412f65..00000000 --- a/DSView/res/DSCope1.dsc +++ /dev/null @@ -1,40 +0,0 @@ -{ - "Device": "DSCope", - "DeviceMode": 1, - "Horizontal trigger position": "0", - "Operation Mode": "Normal", - "Sample count": "1048576", - "Sample rate": "100000000", - "Time base": "10000", - "Trigger hold off": "0", - "Trigger slope": "0", - "Trigger source": "0", - "channel": [ - { - "colour": "#eeb211", - "coupling": 0, - "enabled": true, - "index": 0, - "name": "0", - "strigger": 0, - "trigValue": 0.5, - "type": 10001, - "vdiv": 1000, - "vfactor": 1, - "zeroPos": 0.5 - }, - { - "colour": "#009925", - "coupling": 0, - "enabled": true, - "index": 1, - "name": "1", - "strigger": 0, - "trigValue": 0.5, - "type": 10001, - "vdiv": 1000, - "vfactor": 1, - "zeroPos": 0.5 - } - ] -} diff --git a/DSView/res/DSCope20.bin b/DSView/res/DSCope20.bin new file mode 100755 index 00000000..ffd960cb Binary files /dev/null and b/DSView/res/DSCope20.bin differ diff --git a/DSView/res/DSCope20.fw b/DSView/res/DSCope20.fw new file mode 100755 index 00000000..5071e785 Binary files /dev/null and b/DSView/res/DSCope20.fw differ diff --git a/DSView/res/DSLogic.fw b/DSView/res/DSLogic.fw old mode 100644 new mode 100755 index 44090609..f32f92a7 Binary files a/DSView/res/DSLogic.fw and b/DSView/res/DSLogic.fw differ diff --git a/DSView/res/DSLogic0.def.dsc b/DSView/res/DSLogic0.def.dsc old mode 100644 new mode 100755 index 780b982f..83ecadd3 --- a/DSView/res/DSLogic0.def.dsc +++ b/DSView/res/DSLogic0.def.dsc @@ -1,268 +1,272 @@ -{ - "Device": "DSLogic", - "DeviceMode": 0, - "Filter Targets": "None", - "Horizontal trigger position": "0", - "Operation Mode": "Normal", - "Sample count": "16777216", - "Sample rate": "100000000", - "Threshold Level": 1, - "Trigger hold off": "0", - "Trigger slope": "0", - "Trigger source": "0", - "Using Clock Negedge": 0, - "Using External Clock": 0, - "channel": [ - { - "colour": "#16191a", - "enabled": true, - "index": 0, - "name": "0", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#8f5202", - "enabled": true, - "index": 1, - "name": "1", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#cc0000", - "enabled": true, - "index": 2, - "name": "2", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#f57900", - "enabled": true, - "index": 3, - "name": "3", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#edd400", - "enabled": true, - "index": 4, - "name": "4", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#73d216", - "enabled": true, - "index": 5, - "name": "5", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#3465a4", - "enabled": true, - "index": 6, - "name": "6", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#75507b", - "enabled": true, - "index": 7, - "name": "7", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#16191a", - "enabled": true, - "index": 8, - "name": "8", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#8f5202", - "enabled": true, - "index": 9, - "name": "9", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#cc0000", - "enabled": true, - "index": 10, - "name": "10", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#f57900", - "enabled": true, - "index": 11, - "name": "11", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#edd400", - "enabled": true, - "index": 12, - "name": "12", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#73d216", - "enabled": true, - "index": 13, - "name": "13", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#3465a4", - "enabled": true, - "index": 14, - "name": "14", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#75507b", - "enabled": true, - "index": 15, - "name": "15", - "strigger": 0, - "type": 10000 - } - ], - "trigger": { - "triggerChannel": 0, - "triggerClock": "X X X X X X X X X X X X X X X X", - "triggerCount00": 1, - "triggerCount01": 1, - "triggerCount010": 1, - "triggerCount011": 1, - "triggerCount012": 1, - "triggerCount013": 1, - "triggerCount014": 1, - "triggerCount015": 1, - "triggerCount02": 1, - "triggerCount03": 1, - "triggerCount04": 1, - "triggerCount05": 1, - "triggerCount06": 1, - "triggerCount07": 1, - "triggerCount08": 1, - "triggerCount09": 1, - "triggerCount10": 1, - "triggerCount11": 1, - "triggerCount110": 1, - "triggerCount111": 1, - "triggerCount112": 1, - "triggerCount113": 1, - "triggerCount114": 1, - "triggerCount115": 1, - "triggerCount12": 1, - "triggerCount13": 1, - "triggerCount14": 1, - "triggerCount15": 1, - "triggerCount16": 1, - "triggerCount17": 1, - "triggerCount18": 1, - "triggerCount19": 1, - "triggerData": "X X X X X X X X X X X X X X X X", - "triggerInv00": 0, - "triggerInv01": 0, - "triggerInv010": 0, - "triggerInv011": 0, - "triggerInv012": 0, - "triggerInv013": 0, - "triggerInv014": 0, - "triggerInv015": 0, - "triggerInv02": 0, - "triggerInv03": 0, - "triggerInv04": 0, - "triggerInv05": 0, - "triggerInv06": 0, - "triggerInv07": 0, - "triggerInv08": 0, - "triggerInv09": 0, - "triggerInv10": 0, - "triggerInv11": 0, - "triggerInv110": 0, - "triggerInv111": 0, - "triggerInv112": 0, - "triggerInv113": 0, - "triggerInv114": 0, - "triggerInv115": 0, - "triggerInv12": 0, - "triggerInv13": 0, - "triggerInv14": 0, - "triggerInv15": 0, - "triggerInv16": 0, - "triggerInv17": 0, - "triggerInv18": 0, - "triggerInv19": 0, - "triggerLogic0": 1, - "triggerLogic1": 1, - "triggerLogic10": 1, - "triggerLogic11": 1, - "triggerLogic12": 1, - "triggerLogic13": 1, - "triggerLogic14": 1, - "triggerLogic15": 1, - "triggerLogic2": 1, - "triggerLogic3": 1, - "triggerLogic4": 1, - "triggerLogic5": 1, - "triggerLogic6": 1, - "triggerLogic7": 1, - "triggerLogic8": 1, - "triggerLogic9": 1, - "triggerMode": 0, - "triggerPos": 0, - "triggerSerial": 0, - "triggerStages": 0, - "triggerStart": "X X X X X X X X X X X X X X X X", - "triggerStop": "X X X X X X X X X X X X X X X X", - "triggerValue00": "X X X X X X X X X X X X X X X X", - "triggerValue01": "X X X X X X X X X X X X X X X X", - "triggerValue010": "X X X X X X X X X X X X X X X X", - "triggerValue011": "X X X X X X X X X X X X X X X X", - "triggerValue012": "X X X X X X X X X X X X X X X X", - "triggerValue013": "X X X X X X X X X X X X X X X X", - "triggerValue014": "X X X X X X X X X X X X X X X X", - "triggerValue015": "X X X X X X X X X X X X X X X X", - "triggerValue02": "X X X X X X X X X X X X X X X X", - "triggerValue03": "X X X X X X X X X X X X X X X X", - "triggerValue04": "X X X X X X X X X X X X X X X X", - "triggerValue05": "X X X X X X X X X X X X X X X X", - "triggerValue06": "X X X X X X X X X X X X X X X X", - "triggerValue07": "X X X X X X X X X X X X X X X X", - "triggerValue08": "X X X X X X X X X X X X X X X X", - "triggerValue09": "X X X X X X X X X X X X X X X X", - "triggerValue10": "X X X X X X X X X X X X X X X X", - "triggerValue11": "X X X X X X X X X X X X X X X X", - "triggerValue110": "X X X X X X X X X X X X X X X X", - "triggerValue111": "X X X X X X X X X X X X X X X X", - "triggerValue112": "X X X X X X X X X X X X X X X X", - "triggerValue113": "X X X X X X X X X X X X X X X X", - "triggerValue114": "X X X X X X X X X X X X X X X X", - "triggerValue115": "X X X X X X X X X X X X X X X X", - "triggerValue12": "X X X X X X X X X X X X X X X X", - "triggerValue13": "X X X X X X X X X X X X X X X X", - "triggerValue14": "X X X X X X X X X X X X X X X X", - "triggerValue15": "X X X X X X X X X X X X X X X X", - "triggerValue16": "X X X X X X X X X X X X X X X X", - "triggerValue17": "X X X X X X X X X X X X X X X X", - "triggerValue18": "X X X X X X X X X X X X X X X X", - "triggerValue19": "X X X X X X X X X X X X X X X X" - } -} +{ + "Channel Mode": "Use Channels 0~15 (Max 100MHz)", + "Device": "DSLogic", + "DeviceMode": 0, + "Filter Targets": "None", + "Horizontal trigger position": "0", + "Operation Mode": "Buffer Mode", + "Sample count": "1048576", + "Sample rate": "1000000", + "Threshold Level": 1, + "Trigger channel": "0", + "Trigger hold off": "0", + "Trigger margin": "8", + "Trigger slope": "0", + "Trigger source": "0", + "Using Clock Negedge": 0, + "Using External Clock": 0, + "channel": [ + { + "colour": "#969696", + "enabled": true, + "index": 0, + "name": "0", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 1, + "name": "1", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 2, + "name": "2", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 3, + "name": "3", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 4, + "name": "4", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 5, + "name": "5", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 6, + "name": "6", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 7, + "name": "7", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 8, + "name": "8", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 9, + "name": "9", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 10, + "name": "10", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 11, + "name": "11", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 12, + "name": "12", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 13, + "name": "13", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 14, + "name": "14", + "strigger": 0, + "type": 10000 + }, + { + "colour": "#969696", + "enabled": true, + "index": 15, + "name": "15", + "strigger": 0, + "type": 10000 + } + ], + "trigger": { + "triggerChannel": 0, + "triggerClock": "X X X X X X X X X X X X X X X X", + "triggerCount00": 1, + "triggerCount01": 1, + "triggerCount010": 1, + "triggerCount011": 1, + "triggerCount012": 1, + "triggerCount013": 1, + "triggerCount014": 1, + "triggerCount015": 1, + "triggerCount02": 1, + "triggerCount03": 1, + "triggerCount04": 1, + "triggerCount05": 1, + "triggerCount06": 1, + "triggerCount07": 1, + "triggerCount08": 1, + "triggerCount09": 1, + "triggerCount10": 1, + "triggerCount11": 1, + "triggerCount110": 1, + "triggerCount111": 1, + "triggerCount112": 1, + "triggerCount113": 1, + "triggerCount114": 1, + "triggerCount115": 1, + "triggerCount12": 1, + "triggerCount13": 1, + "triggerCount14": 1, + "triggerCount15": 1, + "triggerCount16": 1, + "triggerCount17": 1, + "triggerCount18": 1, + "triggerCount19": 1, + "triggerData": "X X X X X X X X X X X X X X X X", + "triggerInv00": 0, + "triggerInv01": 0, + "triggerInv010": 0, + "triggerInv011": 0, + "triggerInv012": 0, + "triggerInv013": 0, + "triggerInv014": 0, + "triggerInv015": 0, + "triggerInv02": 0, + "triggerInv03": 0, + "triggerInv04": 0, + "triggerInv05": 0, + "triggerInv06": 0, + "triggerInv07": 0, + "triggerInv08": 0, + "triggerInv09": 0, + "triggerInv10": 0, + "triggerInv11": 0, + "triggerInv110": 0, + "triggerInv111": 0, + "triggerInv112": 0, + "triggerInv113": 0, + "triggerInv114": 0, + "triggerInv115": 0, + "triggerInv12": 0, + "triggerInv13": 0, + "triggerInv14": 0, + "triggerInv15": 0, + "triggerInv16": 0, + "triggerInv17": 0, + "triggerInv18": 0, + "triggerInv19": 0, + "triggerLogic0": 1, + "triggerLogic1": 1, + "triggerLogic10": 1, + "triggerLogic11": 1, + "triggerLogic12": 1, + "triggerLogic13": 1, + "triggerLogic14": 1, + "triggerLogic15": 1, + "triggerLogic2": 1, + "triggerLogic3": 1, + "triggerLogic4": 1, + "triggerLogic5": 1, + "triggerLogic6": 1, + "triggerLogic7": 1, + "triggerLogic8": 1, + "triggerLogic9": 1, + "triggerMode": 0, + "triggerPos": 1, + "triggerSerial": 0, + "triggerStages": 0, + "triggerStart": "X X X X X X X X X X X X X X X X", + "triggerStop": "X X X X X X X X X X X X X X X X", + "triggerValue00": "X X X X X X X X X X X X X X X X", + "triggerValue01": "X X X X X X X X X X X X X X X X", + "triggerValue010": "X X X X X X X X X X X X X X X X", + "triggerValue011": "X X X X X X X X X X X X X X X X", + "triggerValue012": "X X X X X X X X X X X X X X X X", + "triggerValue013": "X X X X X X X X X X X X X X X X", + "triggerValue014": "X X X X X X X X X X X X X X X X", + "triggerValue015": "X X X X X X X X X X X X X X X X", + "triggerValue02": "X X X X X X X X X X X X X X X X", + "triggerValue03": "X X X X X X X X X X X X X X X X", + "triggerValue04": "X X X X X X X X X X X X X X X X", + "triggerValue05": "X X X X X X X X X X X X X X X X", + "triggerValue06": "X X X X X X X X X X X X X X X X", + "triggerValue07": "X X X X X X X X X X X X X X X X", + "triggerValue08": "X X X X X X X X X X X X X X X X", + "triggerValue09": "X X X X X X X X X X X X X X X X", + "triggerValue10": "X X X X X X X X X X X X X X X X", + "triggerValue11": "X X X X X X X X X X X X X X X X", + "triggerValue110": "X X X X X X X X X X X X X X X X", + "triggerValue111": "X X X X X X X X X X X X X X X X", + "triggerValue112": "X X X X X X X X X X X X X X X X", + "triggerValue113": "X X X X X X X X X X X X X X X X", + "triggerValue114": "X X X X X X X X X X X X X X X X", + "triggerValue115": "X X X X X X X X X X X X X X X X", + "triggerValue12": "X X X X X X X X X X X X X X X X", + "triggerValue13": "X X X X X X X X X X X X X X X X", + "triggerValue14": "X X X X X X X X X X X X X X X X", + "triggerValue15": "X X X X X X X X X X X X X X X X", + "triggerValue16": "X X X X X X X X X X X X X X X X", + "triggerValue17": "X X X X X X X X X X X X X X X X", + "triggerValue18": "X X X X X X X X X X X X X X X X", + "triggerValue19": "X X X X X X X X X X X X X X X X", + "triggerVcnt": 1 + } +} diff --git a/DSView/res/DSLogic0.dsc b/DSView/res/DSLogic0.dsc deleted file mode 100644 index 780b982f..00000000 --- a/DSView/res/DSLogic0.dsc +++ /dev/null @@ -1,268 +0,0 @@ -{ - "Device": "DSLogic", - "DeviceMode": 0, - "Filter Targets": "None", - "Horizontal trigger position": "0", - "Operation Mode": "Normal", - "Sample count": "16777216", - "Sample rate": "100000000", - "Threshold Level": 1, - "Trigger hold off": "0", - "Trigger slope": "0", - "Trigger source": "0", - "Using Clock Negedge": 0, - "Using External Clock": 0, - "channel": [ - { - "colour": "#16191a", - "enabled": true, - "index": 0, - "name": "0", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#8f5202", - "enabled": true, - "index": 1, - "name": "1", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#cc0000", - "enabled": true, - "index": 2, - "name": "2", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#f57900", - "enabled": true, - "index": 3, - "name": "3", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#edd400", - "enabled": true, - "index": 4, - "name": "4", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#73d216", - "enabled": true, - "index": 5, - "name": "5", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#3465a4", - "enabled": true, - "index": 6, - "name": "6", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#75507b", - "enabled": true, - "index": 7, - "name": "7", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#16191a", - "enabled": true, - "index": 8, - "name": "8", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#8f5202", - "enabled": true, - "index": 9, - "name": "9", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#cc0000", - "enabled": true, - "index": 10, - "name": "10", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#f57900", - "enabled": true, - "index": 11, - "name": "11", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#edd400", - "enabled": true, - "index": 12, - "name": "12", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#73d216", - "enabled": true, - "index": 13, - "name": "13", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#3465a4", - "enabled": true, - "index": 14, - "name": "14", - "strigger": 0, - "type": 10000 - }, - { - "colour": "#75507b", - "enabled": true, - "index": 15, - "name": "15", - "strigger": 0, - "type": 10000 - } - ], - "trigger": { - "triggerChannel": 0, - "triggerClock": "X X X X X X X X X X X X X X X X", - "triggerCount00": 1, - "triggerCount01": 1, - "triggerCount010": 1, - "triggerCount011": 1, - "triggerCount012": 1, - "triggerCount013": 1, - "triggerCount014": 1, - "triggerCount015": 1, - "triggerCount02": 1, - "triggerCount03": 1, - "triggerCount04": 1, - "triggerCount05": 1, - "triggerCount06": 1, - "triggerCount07": 1, - "triggerCount08": 1, - "triggerCount09": 1, - "triggerCount10": 1, - "triggerCount11": 1, - "triggerCount110": 1, - "triggerCount111": 1, - "triggerCount112": 1, - "triggerCount113": 1, - "triggerCount114": 1, - "triggerCount115": 1, - "triggerCount12": 1, - "triggerCount13": 1, - "triggerCount14": 1, - "triggerCount15": 1, - "triggerCount16": 1, - "triggerCount17": 1, - "triggerCount18": 1, - "triggerCount19": 1, - "triggerData": "X X X X X X X X X X X X X X X X", - "triggerInv00": 0, - "triggerInv01": 0, - "triggerInv010": 0, - "triggerInv011": 0, - "triggerInv012": 0, - "triggerInv013": 0, - "triggerInv014": 0, - "triggerInv015": 0, - "triggerInv02": 0, - "triggerInv03": 0, - "triggerInv04": 0, - "triggerInv05": 0, - "triggerInv06": 0, - "triggerInv07": 0, - "triggerInv08": 0, - "triggerInv09": 0, - "triggerInv10": 0, - "triggerInv11": 0, - "triggerInv110": 0, - "triggerInv111": 0, - "triggerInv112": 0, - "triggerInv113": 0, - "triggerInv114": 0, - "triggerInv115": 0, - "triggerInv12": 0, - "triggerInv13": 0, - "triggerInv14": 0, - "triggerInv15": 0, - "triggerInv16": 0, - "triggerInv17": 0, - "triggerInv18": 0, - "triggerInv19": 0, - "triggerLogic0": 1, - "triggerLogic1": 1, - "triggerLogic10": 1, - "triggerLogic11": 1, - "triggerLogic12": 1, - "triggerLogic13": 1, - "triggerLogic14": 1, - "triggerLogic15": 1, - "triggerLogic2": 1, - "triggerLogic3": 1, - "triggerLogic4": 1, - "triggerLogic5": 1, - "triggerLogic6": 1, - "triggerLogic7": 1, - "triggerLogic8": 1, - "triggerLogic9": 1, - "triggerMode": 0, - "triggerPos": 0, - "triggerSerial": 0, - "triggerStages": 0, - "triggerStart": "X X X X X X X X X X X X X X X X", - "triggerStop": "X X X X X X X X X X X X X X X X", - "triggerValue00": "X X X X X X X X X X X X X X X X", - "triggerValue01": "X X X X X X X X X X X X X X X X", - "triggerValue010": "X X X X X X X X X X X X X X X X", - "triggerValue011": "X X X X X X X X X X X X X X X X", - "triggerValue012": "X X X X X X X X X X X X X X X X", - "triggerValue013": "X X X X X X X X X X X X X X X X", - "triggerValue014": "X X X X X X X X X X X X X X X X", - "triggerValue015": "X X X X X X X X X X X X X X X X", - "triggerValue02": "X X X X X X X X X X X X X X X X", - "triggerValue03": "X X X X X X X X X X X X X X X X", - "triggerValue04": "X X X X X X X X X X X X X X X X", - "triggerValue05": "X X X X X X X X X X X X X X X X", - "triggerValue06": "X X X X X X X X X X X X X X X X", - "triggerValue07": "X X X X X X X X X X X X X X X X", - "triggerValue08": "X X X X X X X X X X X X X X X X", - "triggerValue09": "X X X X X X X X X X X X X X X X", - "triggerValue10": "X X X X X X X X X X X X X X X X", - "triggerValue11": "X X X X X X X X X X X X X X X X", - "triggerValue110": "X X X X X X X X X X X X X X X X", - "triggerValue111": "X X X X X X X X X X X X X X X X", - "triggerValue112": "X X X X X X X X X X X X X X X X", - "triggerValue113": "X X X X X X X X X X X X X X X X", - "triggerValue114": "X X X X X X X X X X X X X X X X", - "triggerValue115": "X X X X X X X X X X X X X X X X", - "triggerValue12": "X X X X X X X X X X X X X X X X", - "triggerValue13": "X X X X X X X X X X X X X X X X", - "triggerValue14": "X X X X X X X X X X X X X X X X", - "triggerValue15": "X X X X X X X X X X X X X X X X", - "triggerValue16": "X X X X X X X X X X X X X X X X", - "triggerValue17": "X X X X X X X X X X X X X X X X", - "triggerValue18": "X X X X X X X X X X X X X X X X", - "triggerValue19": "X X X X X X X X X X X X X X X X" - } -} diff --git a/DSView/res/DSLogic1.def.dsc b/DSView/res/DSLogic1.def.dsc old mode 100644 new mode 100755 index 06a4a02f..75ab6ead --- a/DSView/res/DSLogic1.def.dsc +++ b/DSView/res/DSLogic1.def.dsc @@ -1,13 +1,15 @@ -{ +{ + "Channel Mode": "Use Channels 0~15 (Max 100MHz)", "Device": "DSLogic", "DeviceMode": 1, "Filter Targets": "None", - "Horizontal trigger position": "0", - "Operation Mode": "Normal", + "Horizontal trigger position": "1", + "Operation Mode": "Buffer Mode", "Sample count": "1048576", "Sample rate": "100000000", "Threshold Level": "1.8/2.5/3.3V Level", "Trigger hold off": "0", + "Trigger margin": "8", "Trigger slope": "0", "Trigger source": "0", "Using Clock Negedge": 0, @@ -19,7 +21,6 @@ "enabled": true, "index": 0, "name": "0", - "strigger": 0, "trigValue": 0.5, "type": 10001, "vdiv": 1000, @@ -32,7 +33,6 @@ "enabled": true, "index": 1, "name": "1", - "strigger": 0, "trigValue": 0.5, "type": 10001, "vdiv": 1000, diff --git a/DSView/res/DSLogic1.dsc b/DSView/res/DSLogic1.dsc deleted file mode 100644 index 06a4a02f..00000000 --- a/DSView/res/DSLogic1.dsc +++ /dev/null @@ -1,43 +0,0 @@ -{ - "Device": "DSLogic", - "DeviceMode": 1, - "Filter Targets": "None", - "Horizontal trigger position": "0", - "Operation Mode": "Normal", - "Sample count": "1048576", - "Sample rate": "100000000", - "Threshold Level": "1.8/2.5/3.3V Level", - "Trigger hold off": "0", - "Trigger slope": "0", - "Trigger source": "0", - "Using Clock Negedge": 0, - "Using External Clock": 0, - "channel": [ - { - "colour": "#eeb211", - "coupling": 0, - "enabled": true, - "index": 0, - "name": "0", - "strigger": 0, - "trigValue": 0.5, - "type": 10001, - "vdiv": 1000, - "vfactor": 1, - "zeroPos": 0.5 - }, - { - "colour": "#009925", - "coupling": 0, - "enabled": true, - "index": 1, - "name": "1", - "strigger": 0, - "trigValue": 0.5, - "type": 10001, - "vdiv": 1000, - "vfactor": 1, - "zeroPos": 0.5 - } - ] -} diff --git a/DSView/res/DSLogic2.def.dsc b/DSView/res/DSLogic2.def.dsc old mode 100644 new mode 100755 index 7858fcad..2d9155b8 --- a/DSView/res/DSLogic2.def.dsc +++ b/DSView/res/DSLogic2.def.dsc @@ -1,89 +1,82 @@ -{ - "Device": "DSLogic", - "DeviceMode": 2, - "Filter Targets": "None", - "Horizontal trigger position": "0", - "Operation Mode": "Normal", - "Sample count": "16777216", - "Sample rate": "100000000", - "Threshold Level": "1.8/2.5/3.3V Level", - "Trigger hold off": "0", - "Trigger slope": "0", - "Trigger source": "0", - "Using Clock Negedge": 0, - "Using External Clock": 0, - "channel": [ - { - "colour": "#1185d1", - "enabled": true, - "index": 0, - "name": "0", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#eeb211", - "enabled": true, - "index": 1, - "name": "1", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#d50f25", - "enabled": true, - "index": 2, - "name": "2", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#009925", - "enabled": true, - "index": 3, - "name": "3", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#1185d1", - "enabled": true, - "index": 4, - "name": "4", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#eeb211", - "enabled": true, - "index": 5, - "name": "5", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#d50f25", - "enabled": true, - "index": 6, - "name": "6", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#009925", - "enabled": true, - "index": 7, - "name": "7", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#1185d1", - "enabled": true, - "index": 8, - "name": "8", - "strigger": 0, - "type": 10002 - } - ] -} +{ + "Channel Mode": "Use Channels 0~15 (Max 10MHz)", + "Device": "DSLogic", + "DeviceMode": 2, + "Filter Targets": "None", + "Horizontal trigger position": "0", + "Operation Mode": "Stream Mode", + "Sample count": "1048576", + "Sample rate": "1000000", + "Threshold Level": "1.8/2.5/3.3V Level", + "Trigger hold off": "0", + "Trigger margin": "8", + "Trigger slope": "0", + "Trigger source": "0", + "Using Clock Negedge": 0, + "Using External Clock": 0, + "channel": [ + { + "colour": "#1185d1", + "enabled": true, + "index": 0, + "name": "0", + "type": 10002 + }, + { + "colour": "#eeb211", + "enabled": true, + "index": 1, + "name": "1", + "type": 10002 + }, + { + "colour": "#d50f25", + "enabled": true, + "index": 2, + "name": "2", + "type": 10002 + }, + { + "colour": "#009925", + "enabled": true, + "index": 3, + "name": "3", + "type": 10002 + }, + { + "colour": "#1185d1", + "enabled": true, + "index": 4, + "name": "4", + "type": 10002 + }, + { + "colour": "#eeb211", + "enabled": true, + "index": 5, + "name": "5", + "type": 10002 + }, + { + "colour": "#d50f25", + "enabled": true, + "index": 6, + "name": "6", + "type": 10002 + }, + { + "colour": "#009925", + "enabled": true, + "index": 7, + "name": "7", + "type": 10002 + }, + { + "colour": "#1185d1", + "enabled": true, + "index": 8, + "name": "8", + "type": 10002 + } + ] +} diff --git a/DSView/res/DSLogic2.dsc b/DSView/res/DSLogic2.dsc deleted file mode 100644 index 7858fcad..00000000 --- a/DSView/res/DSLogic2.dsc +++ /dev/null @@ -1,89 +0,0 @@ -{ - "Device": "DSLogic", - "DeviceMode": 2, - "Filter Targets": "None", - "Horizontal trigger position": "0", - "Operation Mode": "Normal", - "Sample count": "16777216", - "Sample rate": "100000000", - "Threshold Level": "1.8/2.5/3.3V Level", - "Trigger hold off": "0", - "Trigger slope": "0", - "Trigger source": "0", - "Using Clock Negedge": 0, - "Using External Clock": 0, - "channel": [ - { - "colour": "#1185d1", - "enabled": true, - "index": 0, - "name": "0", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#eeb211", - "enabled": true, - "index": 1, - "name": "1", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#d50f25", - "enabled": true, - "index": 2, - "name": "2", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#009925", - "enabled": true, - "index": 3, - "name": "3", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#1185d1", - "enabled": true, - "index": 4, - "name": "4", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#eeb211", - "enabled": true, - "index": 5, - "name": "5", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#d50f25", - "enabled": true, - "index": 6, - "name": "6", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#009925", - "enabled": true, - "index": 7, - "name": "7", - "strigger": 0, - "type": 10002 - }, - { - "colour": "#1185d1", - "enabled": true, - "index": 8, - "name": "8", - "strigger": 0, - "type": 10002 - } - ] -} diff --git a/DSView/res/DSLogic33.bin b/DSView/res/DSLogic33.bin old mode 100644 new mode 100755 index 849cd1df..cac82619 Binary files a/DSView/res/DSLogic33.bin and b/DSView/res/DSLogic33.bin differ diff --git a/DSView/res/DSLogic50.bin b/DSView/res/DSLogic50.bin old mode 100644 new mode 100755 index afb8b0ae..50bef232 Binary files a/DSView/res/DSLogic50.bin and b/DSView/res/DSLogic50.bin differ diff --git a/DSView/res/DSLogicPro.bin b/DSView/res/DSLogicPro.bin old mode 100644 new mode 100755 index c2bfdfae..9074fd57 Binary files a/DSView/res/DSLogicPro.bin and b/DSView/res/DSLogicPro.bin differ diff --git a/DSView/res/DSLogicPro.fw b/DSView/res/DSLogicPro.fw old mode 100644 new mode 100755 index 65beceb7..22924c2b Binary files a/DSView/res/DSLogicPro.fw and b/DSView/res/DSLogicPro.fw differ diff --git a/DSView/stylesheet.qss b/DSView/stylesheet.qss index c901688c..5751426e 100644 --- a/DSView/stylesheet.qss +++ b/DSView/stylesheet.qss @@ -261,4 +261,24 @@ QSlider::add-page:horizontal{ border-radius: 4px; } +/* <<< QTableView */ +QHeaderView::section { + background-color: #646464; + padding: 4px; + font-size: 14pt; + border-style: none; + border-bottom: 1px solid #fffff8; + border-right: 1px solid #fffff8; +} + +QHeaderView::section:horizontal +{ + border-top: 1px solid #fffff8; +} + +QHeaderView::section:vertical +{ + border-left: 1px solid #fffff8; +} + /* <<< QDockWidget */ diff --git a/INSTALL b/INSTALL index 1ac01f09..283ff32c 100644 --- a/INSTALL +++ b/INSTALL @@ -1,78 +1,89 @@ -------------------------------------------------------------------------------- -INSTALL -------------------------------------------------------------------------------- - -Requirements ------------- - - git - - gcc (>= 4.0) - - g++ - - make - - libtool - - autoconf >= 2.63 - - automake >= 1.11 - - cmake >= 2.6 - - Qt >= 5.0 - - libtool - - libglib >= 2.32.0 - - libzip >= 0.10 - - libusb-1.0 >= 1.0.16 - On FreeBSD, this is an integral part of the FreeBSD libc, not an extra package/library. - This is part of the standard OpenBSD install (not an extra package), apparently. - - libboost >= 1.42 (including the following libs): - - libboost-system - - libboost-thread - - pkg-config >= 0.22 - This is part of the standard OpenBSD install (not an extra package), apparently. - - check >= 0.9.4 (optional, only needed to run unit tests) - -Building and installing ------------------------ - -Step1: Installing the requirements: - -please check your respective distro's package manager tool if you use other distros -Debian/Ubuntu: - $ sudo apt-get install git-core gcc g++ make cmake autoconf automake libtool pkg-config \ - libglib2.0-dev libzip-dev libudev-dev libusb-1.0-0-dev \ - python3-dev qt5-default libboost-dev libboost-test-dev libboost-thread-dev libboost-system-dev libboost-filesystem-dev check - -Fedora (18, 19): - $ sudo yum install git gcc g++ make cmake autoconf automake libtool pkgconfig glib2-devel \ - libzip-devel libudev-devel libusb1-devel \ - python3-devel qt-devel boost-devel check - -Arch: - $ pacman -S git gcc make cmake autoconf autoconf-archive automake libtool \ - pkg-config glib2 glibmm libzip libusb check - python boost qt5 qt5-base qt5-svg - -Step2: Get the DSView source code - - $ git clone git://github.com/DreamSourceLab/DSView - -Step3: Building - - $ cd libsigrok4DSL - $ ./autogen.sh - $ ./configure - $ make - $ sudo make install - $ cd .. - - $ git clone git://sigrok.org/libsigrokdecode - $ cd libsigrokdecode - $ ./autogen.sh - $ ./configure - $ make - $ sudo make install - $ cd .. - - $ cd DSView - $ cmake . - $ make - $ sudo make install - -See the following wiki page for more (OS-specific) instructions: - - http://sigrok.org/wiki/Building +------------------------------------------------------------------------------- +INSTALL +------------------------------------------------------------------------------- + +Requirements +------------ + - git + - gcc (>= 4.0) + - g++ + - make + - libtool + - autoconf >= 2.63 + - automake >= 1.11 + - cmake >= 2.6 + - Qt >= 5.0 + - libtool + - libglib >= 2.32.0 + - libzip >= 0.10 + - libusb-1.0 >= 1.0.16 + On FreeBSD, this is an integral part of the FreeBSD libc, not an extra package/library. + This is part of the standard OpenBSD install (not an extra package), apparently. + - libboost >= 1.42 (including the following libs): + - libboost-system + - libboost-thread + - pkg-config >= 0.22 + This is part of the standard OpenBSD install (not an extra package), apparently. + - check >= 0.9.4 (optional, only needed to run unit tests) + - libfftw3 >= 3.3 + +Building and installing +----------------------- +Step1: Get the DSView source code + + $ git clone git://github.com/DreamSourceLab/DSView + + +Step2: Installing the requirements: + +please check your respective distro's package manager tool if you use other distros +Debian/Ubuntu: + $ sudo apt-get install git-core build-essential cmake autoconf automake libtool pkg-config \ + libglib2.0-dev libzip-dev libudev-dev libusb-1.0-0-dev \ + python3-dev qt5-default libboost-dev libboost-test-dev libboost-thread-dev libboost-system-dev libboost-filesystem-dev check libfftw3-dev + +Fedora (18, 19): + $ sudo yum install git gcc g++ make cmake autoconf automake libtool pkgconfig glib2-devel \ + libzip-devel libudev-devel libusb1-devel \ + python3-devel qt-devel boost-devel check libfftw3-devel + +Arch: + $ pacman -S git gcc make cmake autoconf autoconf-archive automake libtool \ + pkg-config glib2 glibmm libzip libusb check + python boost qt5 qt5-base qt5-svg libfftw3 + + +Step3: Building + + $ cd libsigrok4DSL + $ ./autogen.sh + $ ./configure + $ make + $ sudo make install + $ cd .. + + $ cd libsigrokdecode4DSL + $ ./autogen.sh + $ ./configure + $ make + $ sudo make install + $ cd .. + + $ cd DSView + $ cmake . + +/* + * If this step fails, + * make sure that your pkg-config is properly configured + * to find the libsigrok and libsigrokdecode libraries + * (It's not by default in Fedora 23). + * To do this add "export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig" + * to your ~/.bashrc and reload it `. ~/.bashrc`. + */ + + $ make + $ sudo make install + +See the following wiki page for more (OS-specific) instructions: + + http://sigrok.org/wiki/Building diff --git a/NEWS b/NEWS index 7dd920f8..d13ac34f 100644 --- a/NEWS +++ b/NEWS @@ -50,14 +50,14 @@ * Improve measure function @ LA mode * Add duty cycle measure @ LA mode * Fix out of range issue @ LA mode - * Add export funtion, support csv/vcd/gnuplot/zip @ LA mode; and csv @ DSO mode + * Add export function, support csv/vcd/gnuplot/zip @ LA mode; and csv @ DSO mode * Add x1/x10/x100 probe options @ DSO mode * Add measure function @ DSO mode * Add voltage display of trigger value @ DSO mode * Fix wave disappear issue @ DSO mode * Fix trigger issue @ DSO stream mode * Fix data repeat when set trigger @ LA stream mode - * Keep channel settings when reload occured @ LA mode + * Keep channel settings when reload occurred @ LA mode * Fix decoder issue when capture part of data @ LA mode * Fix stack decoder add issue @ LA mode * Fix other bugs @@ -84,14 +84,14 @@ * Improve measure function @ LA mode * Add duty cycle measure @ LA mode * Fix out of range issue @ LA mode - * Add export funtion, support csv/vcd/gnuplot/zip @ LA mode; and csv @ DSO mode + * Add export function, support csv/vcd/gnuplot/zip @ LA mode; and csv @ DSO mode * Add x1/x10/x100 probe options @ DSO mode * Add measure function @ DSO mode * Add voltage display of trigger value @ DSO mode * Fix wave disappear issue @ DSO mode * Fix trigger issue @ DSO stream mode * Fix data repeat when set trigger @ LA stream mode - * Keep channel settings when reload occured @ LA mode + * Keep channel settings when reload occurred @ LA mode * Fix decoder issue when capture part of data @ LA mode * Fix stack decoder add issue @ LA mode * Fix other bugsnalyzer mode diff --git a/libsigrok4DSL/hardware/DSL/command.c b/libsigrok4DSL/hardware/DSL/command.c index accf2f15..b23e852e 100644 --- a/libsigrok4DSL/hardware/DSL/command.c +++ b/libsigrok4DSL/hardware/DSL/command.c @@ -234,19 +234,19 @@ SR_PRIV int command_get_status(libusb_device_handle *devhdl, return SR_OK; } -SR_PRIV int command_vth(libusb_device_handle *devhdl, double vth) +SR_PRIV int command_wr_reg(libusb_device_handle *devhdl, uint8_t value, uint8_t addr) { int ret; - uint8_t cmd; + uint16_t cmd; - cmd = vth/5.0 * 255; + cmd = value + (addr << 8); /* Send the control command. */ ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR | - LIBUSB_ENDPOINT_OUT, CMD_VTH, 0x0000, 0x0000, + LIBUSB_ENDPOINT_OUT, CMD_WR_REG, 0x0000, 0x0000, (unsigned char *)&cmd, sizeof(cmd), 3000); if (ret < 0) { - sr_err("Unable to send VTH command: %s.", - libusb_error_name(ret)); + sr_err("Unable to write REG @ address %d : %s.", + addr, libusb_error_name(ret)); return SR_ERR; } @@ -276,7 +276,7 @@ SR_PRIV int command_rd_nvm(libusb_device_handle *devhdl, unsigned char *ctx, uin int ret; struct cmd_nvm_info nvm_info; - assert(len <= 8); + assert(len <= 32); nvm_info.addr = addr; nvm_info.len = len; @@ -305,3 +305,22 @@ SR_PRIV int command_rd_nvm(libusb_device_handle *devhdl, unsigned char *ctx, uin return SR_OK; } + +SR_PRIV int command_get_fpga_done(libusb_device_handle *devhdl, + uint8_t *fpga_done) +{ + int ret; + + ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_ENDPOINT_IN, CMD_FPGA_DONE, 0x0000, 0x0000, + fpga_done, 1, 3000); + + if (ret < 0) { + sr_err("Unable to get fpga done info: %s.", + libusb_error_name(ret)); + return SR_ERR; + } + + return SR_OK; +} + diff --git a/libsigrok4DSL/hardware/DSL/command.h b/libsigrok4DSL/hardware/DSL/command.h index 5f9735a0..352fafb2 100644 --- a/libsigrok4DSL/hardware/DSL/command.h +++ b/libsigrok4DSL/hardware/DSL/command.h @@ -33,10 +33,11 @@ #define CMD_CONTROL 0xb5 #define CMD_STATUS 0xb6 #define CMD_STATUS_INFO 0xb7 -#define CMD_VTH 0xb8 +#define CMD_WR_REG 0xb8 #define CMD_WR_NVM 0xb9 #define CMD_RD_NVM 0xba #define CMD_RD_NVM_PRE 0xbb +#define CMD_FPGA_DONE 0xbc #define CMD_START_FLAGS_MODE_POS 4 #define CMD_START_FLAGS_WIDE_POS 5 @@ -55,6 +56,10 @@ #define CMD_STATUS_CNT 32 +#define VTH_ADDR 0x78 +#define EEWP_ADDR 0x70 +#define COMB_ADDR 0x68 + #pragma pack(push, 1) struct version_info { @@ -98,22 +103,38 @@ struct cmd_status_info { struct cmd_zero_info { uint8_t zero_addr; - uint8_t vpos_l; - uint8_t vpos_h; - uint8_t voff_l; - uint8_t voff_h; - uint8_t vcntr_l; - uint8_t vcntr_h; - uint8_t adc_off; + uint8_t voff0; + uint8_t voff1; + uint8_t voff2; + uint8_t voff3; + uint8_t voff4; + uint8_t voff5; + uint8_t voff6; + uint8_t voff7; + uint8_t voff8; + uint8_t voff9; + uint8_t voff10; + uint8_t voff11; + uint8_t voff12; + uint8_t voff13; + uint8_t voff14; + uint8_t voff15; + uint8_t diff0; + uint8_t diff1; + uint8_t trans0; + uint8_t trans1; }; -struct cmd_comb_info { - uint8_t comb_addr; - uint8_t comb0_low_off; - uint8_t comb0_hig_off; - uint8_t comb1_low_off; - uint8_t comb1_hig_off; - uint8_t comb_sign; +struct cmd_vga_info { + uint8_t vga_addr; + uint16_t vga0; + uint16_t vga1; + uint16_t vga2; + uint16_t vga3; + uint16_t vga4; + uint16_t vga5; + uint16_t vga6; + uint16_t vga7; }; struct cmd_nvm_info { @@ -140,9 +161,11 @@ SR_PRIV int command_get_status(libusb_device_handle *devhdl, unsigned char *status, int begin, int end); -SR_PRIV int command_vth(libusb_device_handle *devhdl, double vth); +SR_PRIV int command_wr_reg(libusb_device_handle *devhdl, uint8_t value, uint8_t addr); SR_PRIV int command_wr_nvm(libusb_device_handle *devhdl, unsigned char *ctx, uint8_t len); SR_PRIV int command_rd_nvm(libusb_device_handle *devhdl, unsigned char *ctx, uint8_t addr, uint8_t len); +SR_PRIV int command_get_fpga_done(libusb_device_handle *devhdl, + uint8_t *fpga_done); #endif diff --git a/libsigrok4DSL/hardware/DSL/dscope.c b/libsigrok4DSL/hardware/DSL/dscope.c index 26191168..bd7481ae 100644 --- a/libsigrok4DSL/hardware/DSL/dscope.c +++ b/libsigrok4DSL/hardware/DSL/dscope.c @@ -89,8 +89,10 @@ static const int32_t sessions[] = { SR_CONF_TIMEBASE, SR_CONF_TRIGGER_SLOPE, SR_CONF_TRIGGER_SOURCE, + SR_CONF_TRIGGER_CHANNEL, SR_CONF_HORIZ_TRIGGERPOS, SR_CONF_TRIGGER_HOLDOFF, + SR_CONF_TRIGGER_MARGIN, }; static const char *probe_names[] = { @@ -139,8 +141,7 @@ static const uint64_t samplecounts[] = { SR_MB(32), }; -static const uint8_t zero_base_addr = 0x80; -static const uint8_t comb_base_addr = 0xB0; +static const uint8_t zero_base_addr = 0x40; SR_PRIV struct sr_dev_driver DSCope_driver_info; static struct sr_dev_driver *di = &DSCope_driver_info; @@ -149,8 +150,51 @@ extern struct ds_trigger *trigger; gboolean mstatus_valid = FALSE; struct sr_status mstatus; -struct cmd_zero_info zero_info; -struct cmd_comb_info comb_info; + +static const uint64_t DSCOPE_DEFAULT_VGAIN[] = { + DSCOPE_DEFAULT_VGAIN0, + DSCOPE_DEFAULT_VGAIN1, + DSCOPE_DEFAULT_VGAIN2, + DSCOPE_DEFAULT_VGAIN3, + DSCOPE_DEFAULT_VGAIN4, + DSCOPE_DEFAULT_VGAIN5, + DSCOPE_DEFAULT_VGAIN6, + DSCOPE_DEFAULT_VGAIN7, +}; + +static const uint64_t DSCOPE20_DEFAULT_VGAIN[] = { + DSCOPE20_DEFAULT_VGAIN0, + DSCOPE20_DEFAULT_VGAIN1, + DSCOPE20_DEFAULT_VGAIN2, + DSCOPE20_DEFAULT_VGAIN3, + DSCOPE20_DEFAULT_VGAIN4, + DSCOPE20_DEFAULT_VGAIN5, + DSCOPE20_DEFAULT_VGAIN6, + DSCOPE20_DEFAULT_VGAIN7, +}; + +struct DSL_vga DSCope_vga[] = { + {10, DSCOPE_DEFAULT_VGAIN0, DSCOPE_DEFAULT_VGAIN0, DSCOPE_DEFAULT_VOFF, DSCOPE_DEFAULT_VOFF}, + {20, DSCOPE_DEFAULT_VGAIN1, DSCOPE_DEFAULT_VGAIN1, DSCOPE_DEFAULT_VOFF, DSCOPE_DEFAULT_VOFF}, + {50, DSCOPE_DEFAULT_VGAIN2, DSCOPE_DEFAULT_VGAIN2, DSCOPE_DEFAULT_VOFF, DSCOPE_DEFAULT_VOFF}, + {100, DSCOPE_DEFAULT_VGAIN3, DSCOPE_DEFAULT_VGAIN3, DSCOPE_DEFAULT_VOFF, DSCOPE_DEFAULT_VOFF}, + {200, DSCOPE_DEFAULT_VGAIN4, DSCOPE_DEFAULT_VGAIN4, DSCOPE_DEFAULT_VOFF, DSCOPE_DEFAULT_VOFF}, + {500, DSCOPE_DEFAULT_VGAIN5, DSCOPE_DEFAULT_VGAIN5, DSCOPE_DEFAULT_VOFF, DSCOPE_DEFAULT_VOFF}, + {1000,DSCOPE_DEFAULT_VGAIN6, DSCOPE_DEFAULT_VGAIN6, DSCOPE_DEFAULT_VOFF, DSCOPE_DEFAULT_VOFF}, + {2000,DSCOPE_DEFAULT_VGAIN7, DSCOPE_DEFAULT_VGAIN7, DSCOPE_DEFAULT_VOFF, DSCOPE_DEFAULT_VOFF}, + {0, 0, 0, 0}, +}; +struct DSL_vga DSCope20_vga[] = { + {10, DSCOPE20_DEFAULT_VGAIN0, DSCOPE20_DEFAULT_VGAIN0, DSCOPE20_DEFAULT_VOFF, CALI_VOFF_RANGE-DSCOPE20_DEFAULT_VOFF}, + {20, DSCOPE20_DEFAULT_VGAIN1, DSCOPE20_DEFAULT_VGAIN1, DSCOPE20_DEFAULT_VOFF, CALI_VOFF_RANGE-DSCOPE20_DEFAULT_VOFF}, + {50, DSCOPE20_DEFAULT_VGAIN2, DSCOPE20_DEFAULT_VGAIN2, DSCOPE20_DEFAULT_VOFF, CALI_VOFF_RANGE-DSCOPE20_DEFAULT_VOFF}, + {100, DSCOPE20_DEFAULT_VGAIN3, DSCOPE20_DEFAULT_VGAIN3, DSCOPE20_DEFAULT_VOFF, CALI_VOFF_RANGE-DSCOPE20_DEFAULT_VOFF}, + {200, DSCOPE20_DEFAULT_VGAIN4, DSCOPE20_DEFAULT_VGAIN4, DSCOPE20_DEFAULT_VOFF, CALI_VOFF_RANGE-DSCOPE20_DEFAULT_VOFF}, + {500, DSCOPE20_DEFAULT_VGAIN5, DSCOPE20_DEFAULT_VGAIN5, DSCOPE20_DEFAULT_VOFF, CALI_VOFF_RANGE-DSCOPE20_DEFAULT_VOFF}, + {1000,DSCOPE20_DEFAULT_VGAIN6, DSCOPE20_DEFAULT_VGAIN6, DSCOPE20_DEFAULT_VOFF, CALI_VOFF_RANGE-DSCOPE20_DEFAULT_VOFF}, + {2000,DSCOPE20_DEFAULT_VGAIN7, DSCOPE20_DEFAULT_VGAIN7, DSCOPE20_DEFAULT_VOFF, CALI_VOFF_RANGE-DSCOPE20_DEFAULT_VOFF}, + {0, 0, 0, 0}, +}; /** * Check the USB configuration to determine if this is an DSCope device. @@ -162,7 +206,7 @@ static gboolean check_conf_profile(libusb_device *dev) { struct libusb_device_descriptor des; struct libusb_device_handle *hdl; - gboolean ret; + gboolean ret; unsigned char strdesc[64]; hdl = NULL; @@ -184,7 +228,7 @@ static gboolean check_conf_profile(libusb_device *dev) if (libusb_get_string_descriptor_ascii(hdl, des.iProduct, strdesc, sizeof(strdesc)) < 0) break; - if (strncmp((const char *)strdesc, "DSCope", 6)) + if (strncmp((const char *)strdesc, "USB-based Instrument", 20)) break; /* If we made it here, it must be an DSCope. */ @@ -196,6 +240,20 @@ static gboolean check_conf_profile(libusb_device *dev) return ret; } +static int en_ch_num(const struct sr_dev_inst *sdi) +{ + GSList *l; + int channel_en_cnt = 0; + + for (l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + channel_en_cnt += probe->enabled; + } + channel_en_cnt += (channel_en_cnt == 0); + + return channel_en_cnt; +} + static int fpga_setting(const struct sr_dev_inst *sdi) { struct DSL_context *devc; @@ -206,9 +264,6 @@ static int fpga_setting(const struct sr_dev_inst *sdi) int transferred; int result; int i; - int channel_en_cnt = 0; - int channel_cnt = 0; - GSList *l; devc = sdi->priv; usb = sdi->conn; @@ -244,26 +299,19 @@ static int fpga_setting(const struct sr_dev_inst *sdi) //setting.trig_logic3_header = 0x2310ffff; setting.end_sync = 0xfa5afa5a; - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - channel_en_cnt += probe->enabled; - channel_cnt++; - } - if (channel_en_cnt == 0) - channel_en_cnt = 1; //setting.mode = (test_mode ? 0x8000 : 0x0000) + trigger->trigger_en + (sdi->mode << 4); setting.mode = ((devc->op_mode == SR_OP_INTERNAL_TEST) << 15) + ((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) + (devc->clock_edge << 2) + + ((sdi->mode == DSO) << 4) + (devc->clock_type << 1) + (devc->clock_edge << 2) + (((devc->cur_samplerate == SR_MHZ(200) && sdi->mode != DSO) || (sdi->mode == ANALOG)) << 5) + ((devc->cur_samplerate == SR_MHZ(400)) << 6) + ((sdi->mode == ANALOG) << 7) + ((devc->filter == SR_FILTER_1T) << 8) + - (devc->instant << 9) + (devc->zero << 10); - setting.divider = devc->zero ? 0x1 : (uint32_t)ceil(DSCOPE_MAX_SAMPLERATE * 1.0 / devc->cur_samplerate / channel_en_cnt); - setting.count = (uint32_t)(devc->limit_samples / (channel_cnt / channel_en_cnt)); + (devc->instant << 9); + setting.divider = (uint32_t)ceil(DSCOPE_MAX_SAMPLERATE * 1.0 / devc->cur_samplerate / en_ch_num(sdi)); + setting.count = (uint32_t)(devc->limit_samples / (g_slist_length(sdi->channels) / en_ch_num(sdi))); setting.trig_pos = (uint32_t)(trigger->trigger_pos / 100.0 * devc->limit_samples); setting.trig_glb = trigger->trigger_stages; setting.trig_adp = setting.count - setting.trig_pos - 1; @@ -350,7 +398,7 @@ static int fpga_config(struct libusb_device_handle *hdl, const char *filename) struct stat f_stat; sr_info("Configure FPGA using %s", filename); - if ((fw = g_fopen(filename, "rb")) == NULL) { + if ((fw = fopen(filename, "rb")) == NULL) { sr_err("Unable to open FPGA bit file %s for reading: %s", filename, strerror(errno)); return SR_ERR; @@ -394,6 +442,7 @@ static int fpga_config(struct libusb_device_handle *hdl, const char *filename) offset += chunksize; } fclose(fw); + g_free(buf); if (result == SR_OK) sr_info("FPGA configure done"); @@ -592,6 +641,10 @@ static struct DSL_context *DSCope_dev_new(void) devc->trigger_hrate = 0; devc->zero = FALSE; devc->data_lock = FALSE; + devc->cali = FALSE; + devc->dso_bits = 8; + devc->trigger_margin = 8; + devc->trigger_channel = 0; return devc; } @@ -606,6 +659,78 @@ static int init(struct sr_context *sr_ctx) return std_hw_init(sr_ctx, di, LOG_PREFIX); } + +static struct DSL_vga* get_vga_ptr(struct sr_dev_inst *sdi) +{ + struct DSL_vga *vga_ptr = NULL; + if (strcmp(sdi->model, "DSCope") == 0) + vga_ptr = DSCope_vga; + else if (strcmp(sdi->model, "DSCope20") == 0) + vga_ptr = DSCope20_vga; + + return vga_ptr; +} + +static uint16_t get_default_trans(struct sr_dev_inst *sdi) +{ + uint16_t trans = 1; + if (strcmp(sdi->model, "DSCope") == 0) + trans = DSCOPE_DEFAULT_TRANS; + else if (strcmp(sdi->model, "DSCope20") == 0) + trans = DSCOPE20_DEFAULT_TRANS; + + return trans; +} + +static uint16_t get_default_voff(struct sr_dev_inst *sdi, int ch_index) +{ + uint16_t voff = 0; + if (strcmp(sdi->model, "DSCope") == 0) + voff = DSCOPE_DEFAULT_VOFF; + else if (strcmp(sdi->model, "DSCope20") == 0) + if (ch_index == 1) + voff = CALI_VOFF_RANGE - DSCOPE20_DEFAULT_VOFF; + else + voff = DSCOPE20_DEFAULT_VOFF; + + return voff; +} + +static uint64_t get_default_vgain(struct sr_dev_inst *sdi, int num) +{ + uint64_t vgain = 0; + if (strcmp(sdi->model, "DSCope") == 0) { + assert(num < sizeof(DSCOPE_DEFAULT_VGAIN)); + vgain = DSCOPE_DEFAULT_VGAIN[num]; + } + else if (strcmp(sdi->model, "DSCope20") == 0) { + assert(num < sizeof(DSCOPE20_DEFAULT_VGAIN)); + vgain = DSCOPE20_DEFAULT_VGAIN[num]; + } + + return vgain; +} + +static int probe_init(struct sr_dev_inst *sdi) +{ + int i; + GList *l; + for (l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + if (sdi->mode == DSO) { + probe->vdiv = 1000; + probe->vfactor = 1; + probe->vpos = 0; + probe->coupling = SR_DC_COUPLING; + probe->trig_value = 0x80; + probe->vpos_trans = get_default_trans(sdi); + probe->ms_show = TRUE; + for (i = DSO_MS_BEGIN; i < DSO_MS_END; i++) + probe->ms_en[i] = default_ms_en[i]; + } + } +} + static int set_probes(struct sr_dev_inst *sdi, int num_probes) { uint16_t j; @@ -615,15 +740,9 @@ static int set_probes(struct sr_dev_inst *sdi, int num_probes) 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; - if (sdi->mode == DSO) { - probe->vdiv = 1000; - probe->vfactor = 1; - probe->vpos = 0; - probe->coupling = SR_DC_COUPLING; - probe->trig_value = 0x80; - } sdi->channels = g_slist_append(sdi->channels, probe); } + probe_init(sdi); return SR_OK; } @@ -731,10 +850,10 @@ static GSList *scan(GSList *options) return NULL; devc = DSCope_dev_new(); - devc->profile = prof; - sdi->priv = devc; - drvc->instances = g_slist_append(drvc->instances, sdi); - devices = g_slist_append(devices, sdi); + devc->profile = prof; + sdi->priv = devc; + drvc->instances = g_slist_append(drvc->instances, sdi); + //devices = g_slist_append(devices, sdi); if (check_conf_profile(devlist[i])) { /* Already has the firmware, so fix the new address. */ @@ -743,11 +862,13 @@ static GSList *scan(GSList *options) sdi->inst_type = SR_INST_USB; sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]), libusb_get_device_address(devlist[i]), NULL); + /* only report device after firmware is ready */ + devices = g_slist_append(devices, sdi); } else { - char *firmware = malloc(strlen(config_path)+strlen(prof->firmware)+1); + char *firmware = malloc(strlen(DS_RES_PATH)+strlen(prof->firmware)+1); if (firmware == NULL) return NULL; - strcpy(firmware, config_path); + strcpy(firmware, DS_RES_PATH); strcat(firmware, prof->firmware); if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION, firmware) == SR_OK) @@ -756,6 +877,7 @@ static GSList *scan(GSList *options) else sr_err("Firmware upload failed for " "device %d.", devcnt); + g_free(firmware); sdi->inst_type = SR_INST_USB; sdi->conn = sr_usb_dev_inst_new (libusb_get_bus_number(devlist[i]), 0xff, NULL); @@ -785,88 +907,106 @@ static GSList *dev_mode_list(const struct sr_dev_inst *sdi) return l; } +static uint64_t dso_vga(struct sr_dev_inst *sdi, struct sr_channel* ch) +{ + int i; + struct DSL_vga *vga_ptr = get_vga_ptr(sdi); + for (i = 0; vga_ptr && (vga_ptr+i)->key; i++) { + if ((vga_ptr+i)->key == ch->vdiv) + return (ch->index == 0) ? (vga_ptr+i)->vgain0 : (vga_ptr+i)->vgain1; + } + + return 0; +} + +static uint64_t dso_voff(struct sr_dev_inst *sdi, struct sr_channel* ch) +{ + int i; + struct DSL_vga *vga_ptr = get_vga_ptr(sdi); + for (i = 0; vga_ptr && (vga_ptr+i)->key; i++) { + if ((vga_ptr+i)->key == ch->vdiv) + return (ch->index == 0) ? (vga_ptr+i)->voff0 : (vga_ptr+i)->voff1; + } + return 0; +} + +static uint64_t dso_vpos(struct sr_dev_inst *sdi, struct sr_channel* ch) +{ + uint64_t vpos; + int vpos_coarse, vpos_fine; + int trans_coarse, trans_fine; + struct DSL_context *devc = sdi->priv; + const double voltage = (devc->zero && devc->zero_comb == -1) ? 0 : ch->vpos; + if (strcmp(sdi->model, "DSCope") == 0) { + trans_coarse = (ch->vpos_trans & 0xFF00) >> 8; + trans_fine = (ch->vpos_trans & 0x00FF); + if (ch->vdiv < 500) { + vpos_coarse = floor(-voltage*DSCOPE_TRANS_CMULTI/trans_coarse + 0.5); + vpos_fine = floor((voltage + vpos_coarse*trans_coarse/DSCOPE_TRANS_CMULTI)*1000.0/trans_fine + 0.5); + } else { + vpos_coarse = floor(-voltage/trans_coarse + 0.5); + vpos_fine = floor((voltage + vpos_coarse*trans_coarse)*DSCOPE_TRANS_FMULTI/trans_fine + 0.5); + } + //vpos = (vpos_coarse << 16) + vpos_fine; + } else if (strcmp(sdi->model, "DSCope20") == 0) { + vpos = ((ch->vdiv*5.0) - voltage)/(ch->vdiv*10.0)*ch->vpos_trans; + } + + const uint64_t voff = dso_voff(sdi, ch); + if (strcmp(sdi->model, "DSCope") == 0) + return ((vpos_coarse+DSCOPE_CONSTANT_BIAS+(voff>>10)) << 16)+vpos_fine+(voff&0x03ff); + else if (strcmp(sdi->model, "DSCope20") == 0) + return vpos+voff; + else + return 0; +} + static uint64_t dso_cmd_gen(struct sr_dev_inst *sdi, struct sr_channel* ch, int id) { struct DSL_context *devc; uint64_t cmd = 0; - int channel_cnt = 0; - uint16_t vpos_coarse; - uint16_t vpos_fine; - gboolean vpos_coarse_neg; - gboolean vpos_fine_neg; + uint64_t vpos; GSList *l; const int ch_bit = 7; - devc = sdi->priv; switch (id) { case SR_CONF_EN_CH: case SR_CONF_COUPLING: - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - channel_cnt += probe->enabled; - } - if (channel_cnt == 1) { + if (devc->zero || en_ch_num(sdi) == 2) { + cmd += 0x0E00; + //cmd += 0x000; + } else if (en_ch_num(sdi) == 1) { if (((ch->index == 0) && ch->enabled) || ((ch->index == 1) && !ch->enabled)) cmd += 0x1600; else if (((ch->index == 1) && ch->enabled) || ((ch->index == 0) && !ch->enabled)) cmd += 0x1A00; - } else if (channel_cnt == 2) { - cmd += 0x0E00; - //cmd += 0x000; } else { return 0x0; } cmd += ch->index << ch_bit; - if (ch->coupling == SR_GND_COUPLING) - cmd &= 0xFFFFFDFF; - else if (ch->coupling == SR_DC_COUPLING) + if (devc->zero || ch->coupling == SR_DC_COUPLING) cmd += 0x100; + else if (ch->coupling == SR_GND_COUPLING) + cmd &= 0xFFFFFDFF; break; case SR_CONF_VDIV: case SR_CONF_TIMEBASE: cmd += 0x8; cmd += ch->index << ch_bit; - // --VDBS - switch(ch->vdiv){ - case 5: cmd += 0x170000; break; - case 10: cmd += 0x162800; break; - case 20: cmd += 0x14D000; break; - case 50: cmd += 0x12E800; break; - case 100: cmd += 0x118000; break; - case 200: cmd += 0x101800; break; - case 500: cmd += 0x2E800; break; - case 1000: cmd += 0x18000; break; - case 2000: cmd += 0x01800; break; - case 5000: cmd += 0x00000; break; - default: cmd += 0x0; break; - } + // --VGAIN + cmd += dso_vga(sdi, ch); break; case SR_CONF_VPOS: cmd += 0x10; cmd += ch->index << ch_bit; - if (ch->vdiv < 500) { - vpos_coarse_neg = (ch->vpos < 0); - vpos_coarse = (uint16_t)(abs(ch->vpos)/(2*VPOS_STEP) + 0.5) * 4; - vpos_fine_neg = vpos_coarse_neg ^ ((abs(ch->vpos) < vpos_coarse*0.5*VPOS_STEP)); - vpos_fine = (uint16_t)(abs((abs(ch->vpos) - vpos_coarse*0.5*VPOS_STEP))/(2*VPOS_MINISTEP) + 0.5); - } else { - vpos_coarse_neg = (ch->vpos < 0); - vpos_coarse = (uint16_t)(abs(ch->vpos)/(20*VPOS_STEP) + 0.5) * 4; - vpos_fine_neg = vpos_coarse_neg ^ ((abs(ch->vpos) < vpos_coarse*5*VPOS_STEP)); - vpos_fine = (uint16_t)(abs((abs(ch->vpos) - vpos_coarse*5*VPOS_STEP))/(20*VPOS_MINISTEP) + 0.5); - } - cmd += (vpos_fine_neg << 31) + (vpos_fine << 20) + - (vpos_coarse_neg << 19) + (vpos_coarse << 8); + vpos = dso_vpos(sdi, ch); + cmd += (vpos << 8); break; case SR_CONF_SAMPLERATE: - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - channel_cnt += probe->enabled; - } cmd += 0x18; - uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(DSCOPE_MAX_SAMPLERATE * 1.0 / devc->cur_samplerate / channel_cnt); + uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(DSCOPE_MAX_SAMPLERATE * 1.0 / devc->cur_samplerate / en_ch_num(sdi)); cmd += divider << 8; break; case SR_CONF_HORIZ_TRIGGERPOS: @@ -879,7 +1019,7 @@ static uint64_t dso_cmd_gen(struct sr_dev_inst *sdi, struct sr_channel* ch, int break; case SR_CONF_TRIGGER_SOURCE: cmd += 0x30; - cmd += devc->trigger_source << 8; + cmd += devc->zero ? 0x0 : devc->trigger_source << 8; break; case SR_CONF_TRIGGER_VALUE: cmd += 0x38; @@ -888,27 +1028,9 @@ static uint64_t dso_cmd_gen(struct sr_dev_inst *sdi, struct sr_channel* ch, int cmd += probe->trig_value << (8 * (probe->index + 1)); } break; - case SR_CONF_ZERO_SET: + case SR_CONF_TRIGGER_MARGIN: cmd += 0x40; - cmd += ch->index << ch_bit; - cmd += ((uint64_t)zero_info.vpos_l << 8); - cmd += ((uint64_t)(zero_info.vpos_h & 0x3) << 16); - cmd += ((uint64_t)zero_info.voff_l << 24); - cmd += ((uint64_t)(zero_info.voff_h & 0x3) << 32); - cmd += ((uint64_t)zero_info.vcntr_l << 40); - cmd += ((uint64_t)(zero_info.vcntr_h & 0x3) << 48); - cmd += ((uint64_t)zero_info.adc_off << 56); - break; - case SR_CONF_COMB_SET: - cmd += 0x48; - cmd += ((uint64_t)comb_info.comb0_low_off << 8); - cmd += ((uint64_t)comb_info.comb0_hig_off << 16); - cmd += ((uint64_t)comb_info.comb1_low_off << 24); - cmd += ((uint64_t)comb_info.comb1_hig_off << 32); - cmd += ((uint64_t)comb_info.comb_sign << 40); - break; - case SR_CONF_ZERO_OVER: - cmd += 0x50; + cmd += ((uint64_t)devc->trigger_margin << 8); break; case SR_CONF_TRIGGER_HOLDOFF: cmd += 0x58; @@ -918,214 +1040,74 @@ static uint64_t dso_cmd_gen(struct sr_dev_inst *sdi, struct sr_channel* ch, int cmd = 0xa5a5a500; break; default: - cmd = 0x00000000; + cmd = 0xFFFFFFFF; } return cmd; } -static int dev_open(struct sr_dev_inst *sdi) +static gboolean dso_load_eep(struct sr_dev_inst *sdi, struct sr_channel *probe, gboolean fpga_done) { - struct sr_usb_dev_inst *usb; - struct DSL_context *devc; - int ret; - int64_t timediff_us, timediff_ms; - - devc = sdi->priv; - usb = sdi->conn; - - /* - * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS - * milliseconds for the FX2 to renumerate. - */ - ret = SR_ERR; - if (devc->fw_updated > 0) { - sr_info("Waiting for device to reset."); - /* Takes >= 300ms for the FX2 to be gone from the USB bus. */ - g_usleep(300 * 1000); - timediff_ms = 0; - while (timediff_ms < MAX_RENUM_DELAY_MS) { - if ((ret = DSCope_dev_open(sdi)) == SR_OK) - break; - g_usleep(100 * 1000); - - timediff_us = g_get_monotonic_time() - devc->fw_updated; - timediff_ms = timediff_us / 1000; - sr_spew("Waited %" PRIi64 "ms.", timediff_ms); - } - if (ret != SR_OK) { - sr_err("Device failed to renumerate."); - return SR_ERR; - } - sr_info("Device came back after %" PRIi64 "ms.", timediff_ms); - } else { - sr_info("Firmware upload was not needed."); - ret = DSCope_dev_open(sdi); - } - - if (ret != SR_OK) { - sr_err("Unable to open device."); - return SR_ERR; - } - - ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE); - if (ret != 0) { - switch(ret) { - case LIBUSB_ERROR_BUSY: - sr_err("Unable to claim USB interface. Another " - "program or driver has already claimed it."); - break; - case LIBUSB_ERROR_NO_DEVICE: - sr_err("Device has been disconnected."); - break; - default: - sr_err("Unable to claim interface: %s.", - libusb_error_name(ret)); - break; - } - - return SR_ERR; - } - - if ((ret = command_fpga_config(usb->devhdl)) != SR_OK) { - sr_err("Send FPGA configure command failed!"); + int ret, i; + struct sr_usb_dev_inst *usb = sdi->conn; + struct cmd_zero_info zero_info; + uint8_t dst_addr = (zero_base_addr + + probe->index * (sizeof(struct cmd_zero_info) + sizeof(struct cmd_vga_info))); + zero_info.zero_addr = dst_addr; + if ((ret = command_rd_nvm(usb->devhdl, (unsigned char *)&zero_info, zero_info.zero_addr, sizeof(struct cmd_zero_info))) != SR_OK) { + return FALSE; + sr_err("%s: Send Get Zero command failed!", __func__); } else { - /* Takes >= 10ms for the FX2 to be ready for FPGA configure. */ - g_usleep(10 * 1000); - char *fpga_bit = malloc(strlen(config_path)+strlen(devc->profile->fpga_bit33)+1); - if (fpga_bit == NULL) - return SR_ERR_MALLOC; - strcpy(fpga_bit, config_path); - strcat(fpga_bit, devc->profile->fpga_bit33); - ret = fpga_config(usb->devhdl, fpga_bit); - if (ret != SR_OK) { - sr_err("Configure FPGA failed!"); - } - } - - if (sdi->mode == DSO) { - 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_COUPLING)); - if (ret != SR_OK) { - sr_err("DSO set coupling of channel %d command failed!", probe->index); - return ret; - } - 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, probe, SR_CONF_VPOS)); - 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_SAMPLERATE)); - if (ret != SR_OK) { - sr_err("Set Sample Rate command failed!"); - return ret; - } - 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, NULL, SR_CONF_TRIGGER_HOLDOFF)); - if (ret != SR_OK) { - sr_err("Set Trigger Holdoff Time command failed!"); - return ret; - } - 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, 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, NULL, SR_CONF_TRIGGER_VALUE)); - if (ret != SR_OK) { - sr_err("Set Trigger Value command failed!"); - return ret; - } - } - - GSList *l; - for(l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - zero_info.zero_addr = (zero_base_addr + probe->index * sizeof(struct cmd_zero_info)); - if ((ret = command_rd_nvm(usb->devhdl, (unsigned char *)&zero_info, zero_info.zero_addr, sizeof(struct cmd_zero_info))) != SR_OK) { - sr_err("Send Get Zero command failed!"); + if (zero_info.zero_addr == dst_addr) { + uint8_t* voff_ptr = &zero_info.zero_addr + 1; + struct DSL_vga *vga_ptr = get_vga_ptr(sdi); + for (i = 0; vga_ptr && (vga_ptr+i)->key; i++) { + if (probe->index == 0) + (vga_ptr+i)->voff0 = (*(voff_ptr + 2*i+1) << 8) + *(voff_ptr + 2*i); + else + (vga_ptr+i)->voff1 = (*(voff_ptr + 2*i+1) << 8) + *(voff_ptr + 2*i); + } + if (i != 0) { + probe->comb_diff_top = *(voff_ptr + 2*i); + probe->comb_diff_bom = *(voff_ptr + 2*i + 1); + probe->vpos_trans = *(voff_ptr + 2*i + 2) + (*(voff_ptr + 2*i + 3) << 8); + if (!fpga_done) { + const double slope = (probe->comb_diff_bom - probe->comb_diff_top)/(2.0*255.0); + for (i = 0; i < 256; i++) { + ret = command_wr_reg(usb->devhdl, i, COMB_ADDR + probe->index*2); + int value = i+i*slope+probe->comb_diff_top*0.5+0.5; + value = (value < 0) ? 0 : + (value > 255) ? 255 : value; + ret = command_wr_reg(usb->devhdl, value, COMB_ADDR + probe->index*2 + 1); + } + } + } } else { - if (zero_info.zero_addr == (zero_base_addr + probe->index * sizeof(struct cmd_zero_info))) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe, SR_CONF_ZERO_SET)); - if (ret != SR_OK) { - sr_err("Set Zero command failed!"); - return ret; - } - } else { - devc->zero = TRUE; - sr_info("Zero have not been setted!"); - } + return FALSE; } } - comb_info.comb_addr = comb_base_addr; - if ((ret = command_rd_nvm(usb->devhdl, (unsigned char *)&comb_info, comb_info.comb_addr, sizeof(struct cmd_comb_info))) != SR_OK) { - sr_err("Send Get Comb Command Failed!"); + struct cmd_vga_info vga_info; + vga_info.vga_addr = dst_addr + sizeof(struct cmd_zero_info); + if ((ret = command_rd_nvm(usb->devhdl, (unsigned char *)&vga_info, vga_info.vga_addr, sizeof(struct cmd_vga_info))) != SR_OK) { + return FALSE; + sr_err("%s: Send Get Zero command failed!", __func__); } else { - if (comb_info.comb_addr == comb_base_addr) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_COMB_SET)); - if (ret != SR_OK) { - sr_err("Set Comb command failed!"); - return ret; - } + if (vga_info.vga_addr == dst_addr + sizeof(struct cmd_zero_info)) { + uint16_t* vgain_ptr = &vga_info.vga0; + struct DSL_vga *vga_ptr = get_vga_ptr(sdi); + for (i = 0; vga_ptr && (vga_ptr+i)->key; i++) { + if (probe->index == 0) + (vga_ptr+i)->vgain0 = *(vgain_ptr + i) << 8; + else + (vga_ptr+i)->vgain1 = *(vgain_ptr + i) << 8; + } } else { - devc->zero = TRUE; - sr_info("Comb have not been setted!"); + return FALSE; } } - return SR_OK; -} - -static int dev_close(struct sr_dev_inst *sdi) -{ - struct sr_usb_dev_inst *usb; - - usb = sdi->conn; - if (usb->devhdl == NULL) - return SR_ERR; - - sr_info("DSCope: Closing device %d on %d.%d interface %d.", - sdi->index, usb->bus, usb->address, USB_INTERFACE); - libusb_release_interface(usb->devhdl, USB_INTERFACE); - libusb_close(usb->devhdl); - usb->devhdl = NULL; - sdi->status = SR_ST_INACTIVE; - - return SR_OK; -} - -static int cleanup(void) -{ - int ret; - struct drv_context *drvc; - - if (!(drvc = di->priv)) - return SR_OK; - - ret = dev_clear(); - - g_free(drvc); - di->priv = NULL; - - return ret; + return TRUE; } static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, @@ -1134,22 +1116,24 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, { struct DSL_context *devc; struct sr_usb_dev_inst *usb; - char str[128]; + char str[128]; + int i; + struct DSL_vga *vga_ptr; (void)cg; - switch (id) { + switch (id) { case SR_CONF_CONN: - if (!sdi || !sdi->conn) + if (!sdi || !sdi->conn) return SR_ERR_ARG; - usb = sdi->conn; - if (usb->address == 255) - /* Device still needs to re-enumerate after firmware - * upload, so we don't know its (future) address. */ + usb = sdi->conn; + if (usb->address == 255) + /* Device still needs to re-enumerate after firmware + * upload, so we don't know its (future) address. */ return SR_ERR; - snprintf(str, 128, "%d.%d", usb->bus, usb->address); + snprintf(str, 128, "%d.%d", usb->bus, usb->address); *data = g_variant_new_string(str); - break; + break; case SR_CONF_LIMIT_SAMPLES: if (!sdi) return SR_ERR; @@ -1157,11 +1141,11 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, *data = g_variant_new_uint64(devc->limit_samples); break; case SR_CONF_SAMPLERATE: - if (!sdi) + if (!sdi) return SR_ERR; - devc = sdi->priv; - *data = g_variant_new_uint64(devc->cur_samplerate); - break; + devc = sdi->priv; + *data = g_variant_new_uint64(devc->cur_samplerate); + break; case SR_CONF_CLOCK_TYPE: if (!sdi) return SR_ERR; @@ -1245,7 +1229,13 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, if (!sdi) return SR_ERR; devc = sdi->priv; - *data = g_variant_new_byte(devc->trigger_source); + *data = g_variant_new_byte(devc->trigger_source&0x0f); + break; + case SR_CONF_TRIGGER_CHANNEL: + if (!sdi) + return SR_ERR; + devc = sdi->priv; + *data = g_variant_new_byte(devc->trigger_source>>4); break; case SR_CONF_TRIGGER_VALUE: if (!ch) @@ -1256,7 +1246,11 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, if (!sdi) return SR_ERR; devc = sdi->priv; - *data = g_variant_new_byte(devc->trigger_hrate); + if (sdi->mode == DSO) { + *data = g_variant_new_byte(devc->trigger_hrate); + } else { + *data = g_variant_new_byte(devc->trigger_hpos); + } break; case SR_CONF_TRIGGER_HOLDOFF: if (!sdi) @@ -1264,16 +1258,29 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, devc = sdi->priv; *data = g_variant_new_uint64(devc->trigger_holdoff); break; + case SR_CONF_TRIGGER_MARGIN: + if (!sdi) + return SR_ERR; + devc = sdi->priv; + *data = g_variant_new_byte(devc->trigger_margin); + break; case SR_CONF_ZERO: if (!sdi) return SR_ERR; devc = sdi->priv; *data = g_variant_new_boolean(devc->zero); break; - case SR_CONF_STREAM: + case SR_CONF_CALI: if (!sdi) return SR_ERR; - *data = g_variant_new_boolean(FALSE); + devc = sdi->priv; + *data = g_variant_new_boolean(devc->cali); + break; + case SR_CONF_ROLL: + if (!sdi) + return SR_ERR; + devc = sdi->priv; + *data = g_variant_new_boolean(devc->roll); break; case SR_CONF_TEST: if (!sdi) @@ -1305,9 +1312,66 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, return SR_ERR; *data = g_variant_new_uint64(DSCOPE_MAX_DEPTH); break; + case SR_CONF_VGAIN: + if (!sdi || !ch) + return SR_ERR; + *data = g_variant_new_uint64(dso_vga(sdi, ch)>>8); + break; + case SR_CONF_VGAIN_DEFAULT: + if (!sdi || !ch) + return SR_ERR; + vga_ptr = get_vga_ptr(sdi); + for (i = 0; vga_ptr && (vga_ptr+i)->key; i++) { + if ((vga_ptr+i)->key == ch->vdiv) + break; + } + *data = g_variant_new_uint64(get_default_vgain(sdi, i)>>8); + break; + case SR_CONF_VGAIN_RANGE: + if (!sdi) + return SR_ERR; + vga_ptr = get_vga_ptr(sdi); + for (i = 0; vga_ptr && (vga_ptr+i)->key; i++) { + if ((vga_ptr+i)->key == ch->vdiv) + break; + } + uint16_t vgain_default= (get_default_vgain(sdi, i)>>8) & 0x0FFF; + *data = g_variant_new_uint16(min(CALI_VGAIN_RANGE, vgain_default*2)); + break; + case SR_CONF_VOFF: + if (!sdi || !ch) + return SR_ERR; + uint16_t voff = dso_voff(sdi, ch); + uint16_t voff_default = get_default_voff(sdi, ch->index); + if (strcmp(sdi->model, "DSCope") == 0) { + int voff_skew_coarse = (voff >> 10) - (voff_default >> 10); + int voff_skew_fine = (voff & 0x03ff) - (voff_default & 0x03ff); + double trans_coarse = (ch->vdiv < 500) ? (ch->vpos_trans >> 8)/DSCOPE_TRANS_CMULTI : (ch->vpos_trans >> 8); + double trans_fine = (ch->vdiv < 500) ? (ch->vpos_trans & 0x00ff) / 1000.0 : (ch->vpos_trans & 0x00ff) / DSCOPE_TRANS_FMULTI; + double voff_rate = (voff_skew_coarse*trans_coarse - voff_skew_fine*trans_fine) / ch->vdiv; + voff = (voff_rate * 0.5 + 0.5) * CALI_VOFF_RANGE; + } + *data = g_variant_new_uint16(voff); + break; + case SR_CONF_VOFF_DEFAULT: + if (!sdi || !ch) + return SR_ERR; + *data = g_variant_new_uint16(get_default_voff(sdi, ch->index)); + break; + case SR_CONF_VOFF_RANGE: + if (!sdi) + return SR_ERR; + *data = g_variant_new_uint16(CALI_VOFF_RANGE); + break; + case SR_CONF_DSO_BITS: + if (!sdi) + return SR_ERR; + devc = sdi->priv; + *data = g_variant_new_byte(devc->dso_bits); + break; default: return SR_ERR_NA; - } + } return SR_OK; } @@ -1320,55 +1384,45 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, const char *stropt; int ret, num_probes; struct sr_usb_dev_inst *usb; + struct drv_context *drvc; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR; - devc = sdi->priv; + drvc = di->priv; + devc = sdi->priv; usb = sdi->conn; + ret = SR_OK; if (id == SR_CONF_SAMPLERATE) { - devc->cur_samplerate = g_variant_get_uint64(data); + devc->cur_samplerate = g_variant_get_uint64(data); if (sdi->mode == LOGIC) { if (devc->cur_samplerate >= SR_MHZ(200)) { adjust_probes(sdi, SR_MHZ(1600)/devc->cur_samplerate); } 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)); } - } else if (id == SR_CONF_CLOCK_TYPE) { devc->clock_type = g_variant_get_boolean(data); - ret = SR_OK; } else if (id == SR_CONF_CLOCK_EDGE) { devc->clock_edge = g_variant_get_boolean(data); - ret = SR_OK; } else if (id == SR_CONF_INSTANT) { devc->instant = g_variant_get_boolean(data); - int num_probes = 0; - GSList *l; - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - num_probes += probe->enabled; - } - if (num_probes != 0) { + if (en_ch_num(sdi) != 0) { if (devc->instant) - devc->limit_samples = DSCOPE_INSTANT_DEPTH / num_probes; + devc->limit_samples = DSCOPE_INSTANT_DEPTH / en_ch_num(sdi); else - devc->limit_samples = DSCOPE_MAX_DEPTH / num_probes; + devc->limit_samples = DSCOPE_MAX_DEPTH / en_ch_num(sdi); } - ret = SR_OK; } else if (id == SR_CONF_LIMIT_SAMPLES) { - devc->limit_samples = g_variant_get_uint64(data); - ret = SR_OK; + devc->limit_samples = g_variant_get_uint64(data); } else if (id == SR_CONF_DEVICE_MODE) { sdi->mode = g_variant_get_int16(data); - ret = SR_OK; if (sdi->mode == LOGIC) { num_probes = devc->profile->dev_caps & DEV_CAPS_16BIT ? 16 : 8; } else if (sdi->mode == DSO) { @@ -1392,7 +1446,6 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, sr_dbg("%s: setting mode to %d", __func__, sdi->mode); } else if (id == SR_CONF_OPERATION_MODE) { stropt = g_variant_get_string(data, NULL); - ret = SR_OK; if (!strcmp(stropt, opmodes[SR_OP_BUFFER])) { devc->op_mode = SR_OP_BUFFER; } else if (!strcmp(stropt, opmodes[SR_OP_INTERNAL_TEST])) { @@ -1408,7 +1461,6 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, __func__, devc->op_mode); } 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])) { @@ -1422,12 +1474,12 @@ static int config_set(int id, GVariant *data, 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_bit33); + //sprintf(filename,"%s%s",DS_RES_PATH,devc->profile->fpga_bit33); //const char *fpga_bit = filename; - char *fpga_bit = malloc(strlen(config_path)+strlen(devc->profile->fpga_bit33)+1); + char *fpga_bit = malloc(strlen(DS_RES_PATH)+strlen(devc->profile->fpga_bit33)+1); if (fpga_bit == NULL) return SR_ERR_MALLOC; - strcpy(fpga_bit, config_path); + strcpy(fpga_bit, DS_RES_PATH); strcat(fpga_bit, devc->profile->fpga_bit33); ret = fpga_config(usb->devhdl, fpga_bit); if (ret != SR_OK) { @@ -1438,7 +1490,6 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, __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])) { @@ -1453,24 +1504,20 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, if (sdi->mode == DSO) { ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, ch, SR_CONF_EN_CH)); - uint16_t channel_cnt = 0; - GSList *l; - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - channel_cnt += probe->enabled; - } - if (channel_cnt != 0) + if (en_ch_num(sdi) != 0) { ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_SAMPLERATE)); + } } if (ret == SR_OK) sr_dbg("%s: setting ENABLE of channel %d to %d", __func__, ch->index, ch->enabled); else - sr_dbg("%s: setting ENABLE of channel %d to %d", + sr_dbg("%s: setting ENABLE of channel %d to %d failed", __func__, ch->index, ch->enabled); } else if (id == SR_CONF_DATALOCK) { + while(libusb_try_lock_events(drvc->sr_ctx->libusb_ctx)); devc->data_lock = g_variant_get_boolean(data); - ret = SR_OK; + libusb_unlock_events(drvc->sr_ctx->libusb_ctx); } else if (id == SR_CONF_VDIV) { ch->vdiv = g_variant_get_uint64(data); if (sdi->mode == DSO) { @@ -1520,10 +1567,17 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, sr_dbg("%s: setting DSO Trigger Slope to %d failed", __func__, devc->trigger_slope); } 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, NULL, SR_CONF_TRIGGER_SOURCE)); - } + devc->trigger_source = (devc->trigger_source & 0xf0) + (g_variant_get_byte(data) & 0x0f); + 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", + __func__, devc->trigger_source); + else + sr_dbg("%s: setting DSO Trigger Source to %d failed", + __func__, devc->trigger_source); + } else if (id == SR_CONF_TRIGGER_CHANNEL) { + devc->trigger_source = (g_variant_get_byte(data) << 4) + (devc->trigger_source & 0x0f); + 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", __func__, devc->trigger_source); @@ -1542,18 +1596,14 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, sr_dbg("%s: setting DSO Trigger Value to %d failed", __func__, ch->index, ch->trig_value); } else if (id == SR_CONF_HORIZ_TRIGGERPOS) { - uint16_t channel_cnt = 0; - GSList *l; - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - channel_cnt += probe->enabled; - } devc->trigger_hrate = g_variant_get_byte(data); - devc->trigger_hpos = devc->trigger_hrate * channel_cnt * devc->limit_samples / 200.0; - if (sdi->mode == DSO) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_HORIZ_TRIGGERPOS)); - } - if (ret == SR_OK) + //devc->trigger_hpos = devc->trigger_hrate * en_ch_num(sdi) * devc->limit_samples / 200.0; + /* + * devc->trigger_hpos should be updated before each acquisition + * because the samplelimits may changed + */ + devc->trigger_hpos = devc->trigger_hrate * en_ch_num(sdi) * devc->limit_samples / 200.0; + if ((ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_HORIZ_TRIGGERPOS))) == SR_OK) sr_dbg("%s: setting DSO Horiz Trigger Position to %d", __func__, devc->trigger_hpos); else @@ -1570,64 +1620,175 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, else sr_dbg("%s: setting Trigger Holdoff Time to %d failed", __func__, devc->trigger_holdoff); + } else if (id == SR_CONF_TRIGGER_MARGIN) { + devc->trigger_margin = g_variant_get_byte(data); + if (sdi->mode == DSO) { + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_TRIGGER_MARGIN)); + } + if (ret == SR_OK) + sr_dbg("%s: setting Trigger Margin to %d", + __func__, devc->trigger_margin); + else + sr_dbg("%s: setting Trigger Margin to %d failed", + __func__, devc->trigger_margin); } else if (id == SR_CONF_ZERO) { devc->zero = g_variant_get_boolean(data); - } else if (id == SR_CONF_ZERO_SET) { + if (devc->zero) { + devc->zero_stage = -1; + devc->zero_pcnt = 0; + devc->zero_comb = -1; + GList *l; + int i; + struct DSL_vga *vga_ptr = get_vga_ptr(sdi); + for(l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + probe->vpos_trans = get_default_trans(sdi); + } + for (i = 0; vga_ptr && (vga_ptr+i)->key; i++) { + (vga_ptr+i)->vgain0 = get_default_vgain(sdi, i); + (vga_ptr+i)->vgain1 = get_default_vgain(sdi, i); + (vga_ptr+i)->voff0 = get_default_voff(sdi, 0); + (vga_ptr+i)->voff1 = get_default_voff(sdi, 1); + } + } + } else if (id == SR_CONF_CALI) { + devc->cali = g_variant_get_boolean(data); + } else if (id == SR_CONF_ZERO_LOAD) { GSList *l; for(l = sdi->channels; l; l = l->next) { struct sr_channel *probe = (struct sr_channel *)l->data; - zero_info.zero_addr = zero_base_addr + probe->index * sizeof(struct cmd_zero_info); - zero_info.vpos_l = (probe->index == 0) ? mstatus.ch0_vpos_mid : mstatus.ch1_vpos_mid; - zero_info.vpos_h = (probe->index == 0) ? mstatus.ch0_vpos_mid >> 8 : mstatus.ch1_vpos_mid >> 8; - zero_info.voff_l = (probe->index == 0) ? mstatus.ch0_voff_mid : mstatus.ch1_voff_mid; - zero_info.voff_h = (probe->index == 0) ? mstatus.ch0_voff_mid >> 8 : mstatus.ch1_voff_mid >> 8; - zero_info.vcntr_l = (probe->index == 0) ? mstatus.ch0_vcntr : mstatus.ch1_vcntr; - zero_info.vcntr_h = (probe->index == 0) ? mstatus.ch0_vcntr >> 8 : mstatus.ch1_vcntr >> 8; - zero_info.adc_off = (probe->index == 0) ? mstatus.ch0_adc_off + (mstatus.ch0_adc_sign << 7) : mstatus.ch1_adc_off + (mstatus.ch1_adc_sign << 7); - ret = command_wr_nvm(usb->devhdl, (unsigned char *)&zero_info, sizeof(struct cmd_zero_info)); - if (ret != SR_OK) - sr_err("DSO channel %d Set Zero command failed!", probe->index); + if (!dso_load_eep(sdi, probe, FALSE)) { + config_set(SR_CONF_ZERO, g_variant_new_boolean(TRUE), sdi, NULL, NULL); + sr_info("Zero have not been setted!"); + break; + } } - comb_info.comb_addr = comb_base_addr; - comb_info.comb0_low_off = mstatus.comb0_off; - comb_info.comb0_hig_off = mstatus.comb0_off >> 8; - comb_info.comb1_low_off = mstatus.comb1_off; - comb_info.comb1_hig_off = mstatus.comb1_off >> 8; - comb_info.comb_sign = mstatus.comb_sign; - ret = command_wr_nvm(usb->devhdl, (unsigned char *)&comb_info, sizeof(struct cmd_comb_info)); - if (ret != SR_OK) - sr_err("DSO Set Comb command failed!"); - else - devc->zero = FALSE; - } else { - ret = SR_ERR_NA; - } + } else if (id == SR_CONF_ZERO_SET) { + GSList *l; + struct cmd_zero_info zero_info; + struct cmd_vga_info vga_info; + for(l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + zero_info.zero_addr = zero_base_addr + + probe->index * (sizeof(struct cmd_zero_info) + sizeof(struct cmd_vga_info)); + int i; + struct DSL_vga *vga_ptr = get_vga_ptr(sdi); + uint8_t *voff_ptr = &zero_info.zero_addr + 1; + for (i = 0; vga_ptr && (vga_ptr+i)->key; i++) { + *(voff_ptr+2*i) = ((probe->index == 0) ? (vga_ptr+i)->voff0 : (vga_ptr+i)->voff1) & 0x00ff; + *(voff_ptr+2*i+1) = ((probe->index == 0) ? (vga_ptr+i)->voff0 : (vga_ptr+i)->voff1) >> 8; + } + if (i != 0) { + *(voff_ptr+2*i) = probe->comb_diff_top; + *(voff_ptr+2*i+1) = probe->comb_diff_bom; + *(voff_ptr+2*i+2) = (probe->vpos_trans&0x00FF); + *(voff_ptr+2*i+3) = (probe->vpos_trans>>8); - return ret; + vga_info.vga_addr = zero_info.zero_addr + sizeof(struct cmd_zero_info); + uint16_t *vgain_ptr = &vga_info.vga0; + for (i=0; vga_ptr && (vga_ptr+i)->key; i++){ + *(vgain_ptr+i) = ((probe->index == 0) ? (vga_ptr+i)->vgain0 : (vga_ptr+i)->vgain1) >> 8; + } + ret = command_wr_reg(usb->devhdl, 0, EEWP_ADDR); + if (ret == SR_OK) + ret = command_wr_nvm(usb->devhdl, (unsigned char *)&zero_info, sizeof(struct cmd_zero_info)); + if (ret == SR_OK) + ret = command_wr_nvm(usb->devhdl, (unsigned char *)&vga_info, sizeof(struct cmd_vga_info)); + if (ret == SR_OK) + ret = command_wr_reg(usb->devhdl, 1, EEWP_ADDR); + if (ret != SR_OK) + sr_err("DSO channel %d Set Zero command failed!", probe->index); + + const double slope = (probe->comb_diff_bom - probe->comb_diff_top)/(2.0*255.0); + for (i = 0; i < 256; i++) { + ret = command_wr_reg(usb->devhdl, i, COMB_ADDR + probe->index*2); + int value = i+i*slope+probe->comb_diff_top*0.5+0.5; + value = (value < 0) ? 0 : + (value > 255) ? 255 : value; + ret = command_wr_reg(usb->devhdl, value, COMB_ADDR + probe->index*2 + 1); + } + } + } + } else if (id == SR_CONF_VOCM) { + const uint8_t vocm = g_variant_get_byte(data); + ret = command_wr_reg(usb->devhdl, vocm, COMB_ADDR+4); + } else if (id == SR_CONF_VGAIN) { + const uint64_t vgain = g_variant_get_uint64(data) << 8; + int i; + struct DSL_vga *vga_ptr = get_vga_ptr(sdi); + for (i = 0; vga_ptr && (vga_ptr+i)->key; i++) { + if ((vga_ptr+i)->key == ch->vdiv) + if (ch->index == 0) + (vga_ptr+i)->vgain0 = vgain; + else if (ch->index == 1) + (vga_ptr+i)->vgain1 = vgain; + } + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, ch, SR_CONF_VDIV)); + if (ret == SR_OK) + sr_dbg("%s: setting VDIV of channel %d to %d mv", + __func__, ch->index, ch->vdiv); + else + sr_dbg("%s: setting VDIV of channel %d to %d mv failed", + __func__, ch->index, ch->vdiv); + } else if (id == SR_CONF_VOFF) { + uint16_t voff = g_variant_get_uint16(data); + if (strcmp(sdi->model, "DSCope") == 0) { + double voltage_off = (2.0 * voff / CALI_VOFF_RANGE - 1) * ch->vdiv; + double trans_coarse = (ch->vdiv < 500) ? (ch->vpos_trans >> 8)/DSCOPE_TRANS_CMULTI : (ch->vpos_trans >> 8); + double trans_fine = (ch->vdiv < 500) ? (ch->vpos_trans & 0x00ff) / 1000.0 : (ch->vpos_trans & 0x00ff) / DSCOPE_TRANS_FMULTI; + + uint16_t default_voff = get_default_voff(sdi, ch->index); + int voff_coarse = floor(voltage_off / trans_coarse + 0.5); + int voff_fine = floor(-(voltage_off - voff_coarse*trans_coarse)/trans_fine + 0.5); + voff_coarse = (default_voff >> 10) + voff_coarse; + voff_fine = (default_voff&0x03ff) + voff_fine; + voff = (voff_coarse << 10) + voff_fine; + } + int i; + struct DSL_vga *vga_ptr = get_vga_ptr(sdi); + for (i = 0; vga_ptr && (vga_ptr+i)->key; i++) { + if ((vga_ptr+i)->key == ch->vdiv) + if (ch->index == 0) + (vga_ptr+i)->voff0 = voff; + else if (ch->index == 1) + (vga_ptr+i)->voff1 = voff; + } + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, ch, SR_CONF_VPOS)); + if (ret == SR_OK) + sr_dbg("%s: setting VPOS of channel %d to %lf mv", + __func__, ch->index, ch->vpos); + else + sr_dbg("%s: setting VPOS of channel %d to %lf mv failed", + __func__, ch->index, ch->vpos); + }else { + ret = SR_ERR_NA; + } + + return ret; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { - GVariant *gvar; - GVariantBuilder gvb; + GVariant *gvar; + GVariantBuilder gvb; - (void)sdi; + (void)sdi; (void)cg; - switch (key) { + switch (key) { case SR_CONF_SCAN_OPTIONS: // *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, // hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t)); *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"), hwopts, ARRAY_SIZE(hwopts)*sizeof(int32_t), TRUE, NULL, NULL); - break; + break; case SR_CONF_DEVICE_OPTIONS: // *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, // hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"), hwcaps, ARRAY_SIZE(hwcaps)*sizeof(int32_t), TRUE, NULL, NULL); - break; + break; case SR_CONF_DEVICE_CONFIGS: // *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, // hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); @@ -1639,14 +1800,14 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, sessions, ARRAY_SIZE(sessions)*sizeof(int32_t), TRUE, NULL, NULL); break; case SR_CONF_SAMPLERATE: - g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); + 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; + *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"), @@ -1656,7 +1817,7 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, break; case SR_CONF_TRIGGER_TYPE: *data = g_variant_new_string(TRIGGER_TYPE); - break; + break; case SR_CONF_OPERATION_MODE: *data = g_variant_new_strv(opmodes, opmodes_show_count); break; @@ -1666,63 +1827,385 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, case SR_CONF_FILTER: *data = g_variant_new_strv(filters, ARRAY_SIZE(filters)); break; - default: + default: return SR_ERR_NA; - } + } return SR_OK; } -static void abort_acquisition(struct DSL_context *devc) +static int dso_init(const struct sr_dev_inst *sdi) +{ + int ret, i; + GSList *l; + struct sr_usb_dev_inst *usb = sdi->conn; + + 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_COUPLING)); + if (ret != SR_OK) { + sr_err("DSO set coupling of channel %d command failed!", probe->index); + return ret; + } + 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, probe, SR_CONF_VPOS)); + if (ret != SR_OK) { + sr_err("Set VPOS of channel %d command failed!", probe->index); + return ret; + } + } + + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_SAMPLERATE)); + if (ret != SR_OK) { + sr_err("Set Sample Rate command failed!"); + return ret; + } + 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, NULL, SR_CONF_TRIGGER_HOLDOFF)); + if (ret != SR_OK) { + sr_err("Set Trigger Holdoff Time command failed!"); + return ret; + } + 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, 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, NULL, SR_CONF_TRIGGER_VALUE)); + if (ret != SR_OK) { + sr_err("Set Trigger Value command failed!"); + return ret; + } + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_TRIGGER_MARGIN)); + if (ret != SR_OK) { + sr_err("Set Trigger Margin command failed!"); + return ret; + } + return ret; +} + +static int dso_zero(struct sr_dev_inst *sdi, struct sr_status mstatus) +{ + struct DSL_context *devc = sdi->priv; + struct sr_usb_dev_inst *usb = sdi->conn; + GSList *l; + int ret, i; + static double vpos_back[2]; + static uint64_t vdiv_back[2]; + struct DSL_vga *vga_ptr = get_vga_ptr(sdi); + struct sr_channel *probe0, *probe1; + for(l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + if (probe->index == 0) + probe0 = probe; + if (probe->index == 1) + probe1 = probe; + } + + if (devc->zero_stage == -1) { + // initialize before zero adjustment + if (dso_init(sdi) == SR_OK) + devc->zero_stage = 0; + } else if ((vga_ptr+devc->zero_stage)->key == 0) { + ret = SR_OK; + if (strcmp(sdi->model, "DSCope20") == 0) { + if (devc->zero_pcnt == 0) { + devc->zero_comb = 0; + vpos_back[0] = probe0->vpos; + probe0->vpos = (vga_ptr+devc->zero_stage-1)->key * -4.8; + vdiv_back[0] = probe0->vdiv; + probe0->vdiv = (vga_ptr+devc->zero_stage-1)->key; + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe0, SR_CONF_VPOS)); + } else if (devc->zero_pcnt == 4) { + const double voff = 255*0.98 - (mstatus.ch0_max + mstatus.ch0_min) / 2.0; + if (abs(voff) < 0.5) { + probe0->vpos = vpos_back[0]; + } else { + probe0->vpos_trans += voff; + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe0, SR_CONF_VPOS)); + devc->zero_pcnt = 1; + } + } else if (devc->zero_pcnt == 5) { + devc->zero_comb = 0; + vpos_back[1] = probe1->vpos; + probe1->vpos = (vga_ptr+devc->zero_stage-1)->key * -4.8; + vdiv_back[1] = probe1->vdiv; + probe1->vdiv = (vga_ptr+devc->zero_stage-1)->key; + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe1, SR_CONF_VPOS)); + } else if (devc->zero_pcnt == 9) { + const double voff = 255*0.98 - (mstatus.ch1_max + mstatus.ch1_min) / 2.0; + if (abs(voff) < 0.5) { + probe1->vpos = vpos_back[1]; + } else { + probe1->vpos_trans += voff; + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe1, SR_CONF_VPOS)); + devc->zero_pcnt = 6; + } + } + } + + if (devc->zero_pcnt == 10) { + ret = command_wr_reg(usb->devhdl, 0b1101, COMB_ADDR+6); + devc->zero_comb = 0; + vpos_back[0] = probe0->vpos; + probe0->vpos = (vga_ptr+devc->zero_stage-1)->key * 4.5; + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe0, SR_CONF_VPOS)); + } else if (devc->zero_pcnt == 15) { + probe0->comb_diff_top = (mstatus.ch0_max - mstatus.ch1_max) + + (mstatus.ch0_min - mstatus.ch1_min); + probe0->vpos = (vga_ptr+devc->zero_stage-1)->key * -4.5; + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe0, SR_CONF_VPOS)); + } else if (devc->zero_pcnt == 20) { + probe0->comb_diff_bom = (mstatus.ch0_max - mstatus.ch1_max) + + (mstatus.ch0_min - mstatus.ch1_min); + probe0->vpos = vpos_back[0]; + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe0, SR_CONF_VPOS)); + } + + if (devc->zero_pcnt == 25) { + ret = command_wr_reg(usb->devhdl, 0b1110, COMB_ADDR+6); + devc->zero_comb = 1; + vpos_back[1] = probe1->vpos; + probe1->vpos = (vga_ptr+devc->zero_stage-1)->key * 4.5; + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe1, SR_CONF_VPOS)); + } else if (devc->zero_pcnt == 30) { + probe1->comb_diff_top = (mstatus.ch1_max - mstatus.ch0_max) + + (mstatus.ch1_min - mstatus.ch0_min); + probe1->vpos = (vga_ptr+devc->zero_stage-1)->key * -4.5; + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe1, SR_CONF_VPOS)); + } else if (devc->zero_pcnt == 35) { + probe1->comb_diff_bom = (mstatus.ch1_max - mstatus.ch0_max) + + (mstatus.ch1_min - mstatus.ch0_min); + probe1->vpos = vpos_back[1]; + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe1, SR_CONF_VPOS)); + } + + if (devc->zero_pcnt == 40) { + if (strcmp(sdi->model, "DSCope20") == 0) { + probe0->vdiv = vdiv_back[0]; + probe1->vdiv = vdiv_back[1]; + } + ret = command_wr_reg(usb->devhdl, 0b0011, COMB_ADDR+6); + devc->zero = FALSE; + dso_init(sdi); + } + + if (ret == SR_OK) + devc->zero_pcnt++; + } else { + if (devc->zero_pcnt == 0) { + for(l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + uint64_t vdiv_back = probe->vdiv; + probe->vdiv = (vga_ptr+devc->zero_stage)->key; + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe, SR_CONF_VDIV)); + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe, SR_CONF_VPOS)); + probe->vdiv = vdiv_back; + } + } + + if (devc->zero_pcnt == 4) { + const double voff0 = 255/2.0 - (mstatus.ch0_max + mstatus.ch0_min)/2.0; + const double voff1 = 255/2.0 - (mstatus.ch1_max + mstatus.ch1_min)/2.0; + if (abs(voff0) < 0.5 && abs(voff1) < 0.5) { + devc->zero_stage++; + } else { + if (strcmp(sdi->model, "DSCope") == 0) { + for(l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + double trans_coarse = ((vga_ptr+devc->zero_stage)->key < 500) ? (probe->vpos_trans >> 8)/DSCOPE_TRANS_CMULTI : (probe->vpos_trans >> 8); + double trans_fine = ((vga_ptr+devc->zero_stage)->key < 500) ? (probe->vpos_trans & 0x00ff) / 1000.0 : (probe->vpos_trans & 0x00ff) / DSCOPE_TRANS_FMULTI; + + double voltage_off = ((probe->index == 0) ? voff0 : voff1) * (vga_ptr+devc->zero_stage)->key * 10 / 255.0; + uint16_t last_voff = ((probe->index == 0) ? (vga_ptr+devc->zero_stage)->voff0 : (vga_ptr+devc->zero_stage)->voff1); + int voff_coarse = floor(voltage_off / trans_coarse + 0.5); + int voff_fine = floor(-(voltage_off - voff_coarse*trans_coarse)/trans_fine + 0.5); + voff_coarse = (last_voff >> 10) + voff_coarse; + voff_fine = (last_voff&0x03ff) + voff_fine; + if (probe->index == 0) + (vga_ptr+devc->zero_stage)->voff0 = (voff_coarse << 10) + voff_fine; + else if (probe->index == 1) + (vga_ptr+devc->zero_stage)->voff1 = (voff_coarse << 10) + voff_fine; + } + } else if (strcmp(sdi->model, "DSCope20") == 0) { + (vga_ptr+devc->zero_stage)->voff0 += voff0; + (vga_ptr+devc->zero_stage)->voff1 += voff1; + } + } + devc->zero_pcnt = 0; + } else { + devc->zero_pcnt++; + } + } + + return ret; +} + +static int dev_open(struct sr_dev_inst *sdi) +{ + struct sr_usb_dev_inst *usb; + struct DSL_context *devc; + int ret; + int64_t timediff_us, timediff_ms; + uint8_t fpga_done; + GSList *l; + gboolean zeroed; + + devc = sdi->priv; + usb = sdi->conn; + + /* + * If the firmware was recently uploaded, no dev_open operation should be called. + * Just wait for renumerate -> detach -> attach + */ + ret = SR_ERR; + if (devc->fw_updated > 0) { + return SR_ERR; + } else { + sr_info("%s: Firmware upload was not needed.", __func__); + ret = DSCope_dev_open(sdi); + } + + if (ret != SR_OK) { + sr_err("%s: Unable to open device.", __func__); + return SR_ERR; + } + + ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE); + if (ret != 0) { + switch(ret) { + case LIBUSB_ERROR_BUSY: + sr_err("%s: Unable to claim USB interface. Another " + "program or driver has already claimed it.", __func__); + break; + case LIBUSB_ERROR_NO_DEVICE: + sr_err("%s: Device has been disconnected.", __func__); + break; + default: + sr_err("%s: Unable to claim interface: %s.", + __func__, libusb_error_name(ret)); + break; + } + + return SR_ERR; + } + + ret = command_get_fpga_done(usb->devhdl, &fpga_done); + if (ret != SR_OK) { + sr_err("Failed to get fpga done infos."); + return SR_ERR; + } + + if (fpga_done == 0) { + if ((ret = command_fpga_config(usb->devhdl)) != SR_OK) { + sr_err("%s: Send FPGA configure command failed!", __func__); + } else { + /* Takes >= 10ms for the FX2 to be ready for FPGA configure. */ + g_usleep(10 * 1000); + char *fpga_bit = malloc(strlen(DS_RES_PATH)+strlen(devc->profile->fpga_bit33)+1); + if (fpga_bit == NULL) + return SR_ERR_MALLOC; + strcpy(fpga_bit, DS_RES_PATH); + strcat(fpga_bit, devc->profile->fpga_bit33); + ret = fpga_config(usb->devhdl, fpga_bit); + if (ret != SR_OK) { + sr_err("%s: Configure FPGA failed!", __func__); + } + g_free(fpga_bit); + } + } + + // load zero informations + if (sdi->mode == DSO) { + for(l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + zeroed = dso_load_eep(sdi, probe, fpga_done); + if (!zeroed) + break; + } + if (!zeroed) { + config_set(SR_CONF_ZERO, g_variant_new_boolean(TRUE), sdi, NULL, NULL); + sr_info("Zero have not been setted!"); + } + if (fpga_done == 0) + dso_init(sdi); + } + + return SR_OK; +} + +static int dev_close(struct sr_dev_inst *sdi) +{ + struct sr_usb_dev_inst *usb; + + usb = sdi->conn; + if (usb->devhdl == NULL) + return SR_ERR; + + sr_info("DSCope: Closing device %d on %d.%d interface %d.", + sdi->index, usb->bus, usb->address, USB_INTERFACE); + libusb_release_interface(usb->devhdl, USB_INTERFACE); + libusb_close(usb->devhdl); + usb->devhdl = NULL; + sdi->status = SR_ST_INACTIVE; + + return SR_OK; +} + +static int cleanup(void) +{ + int ret; + struct drv_context *drvc; + + if (!(drvc = di->priv)) + return SR_OK; + + ret = dev_clear(); + + g_free(drvc); + di->priv = NULL; + + return ret; +} + +static void remove_sources(struct DSL_context *devc) { int i; - int ret; - struct sr_usb_dev_inst *usb; - - devc->num_samples = -1; - - sr_info("%s: Stopping", __func__); - - /* Stop GPIF acquisition */ - usb = ((struct sr_dev_inst *)devc->cb_data)->conn; - if ((ret = command_stop_acquisition (usb->devhdl)) != SR_OK) - sr_err("Stop DSCope acquisition failed!"); - else - sr_info("Stop DSCope acquisition!"); - - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen((struct sr_dev_inst *)devc->cb_data, NULL, SR_CONF_ZERO_OVER)); - if (ret != SR_OK) - sr_err("DSO zero over command failed!"); - - /* Cancel exist transfers */ - if (devc->num_transfers) - for (i = devc->num_transfers - 1; i >= 0; i--) { - if (devc->transfers[i]) - libusb_cancel_transfer(devc->transfers[i]); - } + sr_err("%s: remove fds from polling", __func__); + /* Remove fds from polling. */ + for (i = 0; devc->usbfd[i] != -1; i++) + sr_source_remove(devc->usbfd[i]); + g_free(devc->usbfd); } static void finish_acquisition(struct DSL_context *devc) { struct sr_datafeed_packet packet; - int i, ret; - struct sr_usb_dev_inst *usb; - sr_err("finish acquisition: send SR_DF_END packet"); + sr_err("%s: send SR_DF_END packet", __func__); /* Terminate session. */ packet.type = SR_DF_END; sr_session_send(devc->cb_data, &packet); - - sr_err("finish acquisition: remove fds from polling"); - /* Remove fds from polling. */ - for (i = 0; devc->usbfd[i] != -1; i++) - sr_source_remove(devc->usbfd[i]); - g_free(devc->usbfd); if (devc->num_transfers != 0) { devc->num_transfers = 0; g_free(devc->transfers); } + + devc->status = DSL_FINISH; } static void free_transfer(struct libusb_transfer *transfer) @@ -1730,7 +2213,7 @@ static void free_transfer(struct libusb_transfer *transfer) struct DSL_context *devc; unsigned int i; - devc = transfer->user_data; + devc = transfer->user_data; g_free(transfer->buffer); transfer->buffer = NULL; @@ -1778,47 +2261,37 @@ static struct sr_config * new_config(int key, GVariant *data) static void receive_transfer(struct libusb_transfer *transfer) { - gboolean packet_has_error = FALSE; + gboolean packet_has_error = FALSE; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; struct sr_datafeed_dso dso; struct sr_datafeed_analog analog; - struct sr_datafeed_meta meta; - struct DSL_context *devc; - int trigger_offset, i, sample_width, cur_sample_count; + + int trigger_offset, i; int trigger_offset_bytes; - uint8_t *cur_buf; - //GTimeVal cur_time; - //g_get_current_time(&cur_time); - //sr_info("receive_transfer: current time %d sec %d usec", cur_time.tv_sec, cur_time.tv_usec); + const uint8_t *cur_buf = transfer->buffer; + struct DSL_context *devc = transfer->user_data; + struct sr_dev_inst *sdi = devc->cb_data; + const int sample_width = 2; + int cur_sample_count = transfer->actual_length / sample_width; - - devc = transfer->user_data; - - /* - * If acquisition has already ended, just free any queued up - * transfer that come in. - */ - if (devc->num_samples == -1) { - free_transfer(transfer); + if (devc->data_lock) { + resubmit_transfer(transfer); return; } + if (devc->abort) + devc->status = DSL_STOP; + sr_info("receive_transfer(): status %d; timeout %d; received %d bytes.", transfer->status, transfer->timeout, transfer->actual_length); - /* Save incoming transfer before reusing the transfer struct. */ - cur_buf = transfer->buffer; - sample_width = 2; - cur_sample_count = transfer->actual_length / sample_width; - switch (transfer->status) { case LIBUSB_TRANSFER_NO_DEVICE: - //abort_acquisition(devc); - free_transfer(transfer); + case LIBUSB_TRANSFER_CANCELLED: devc->status = DSL_ERROR; - return; + break; case LIBUSB_TRANSFER_COMPLETED: case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */ break; @@ -1827,30 +2300,20 @@ static void receive_transfer(struct libusb_transfer *transfer) break; } - if (transfer->actual_length == 0 || - packet_has_error || - devc->data_lock) { + if (devc->status == DSL_DATA && + (transfer->actual_length == 0 || + packet_has_error)) { devc->empty_transfer_count++; if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) { - /* - * The FX2 gave up. End the acquisition, the frontend - * will work out that the samplecount is short. - */ - //abort_acquisition(devc); - free_transfer(transfer); devc->status = DSL_ERROR; - } else { - resubmit_transfer(transfer); } - return; } else { devc->empty_transfer_count = 0; } trigger_offset = 0; - if (devc->trigger_stage >= 0) { + if (devc->status == DSL_DATA && devc->trigger_stage >= 0) { for (i = 0; i < cur_sample_count; i++) { - const uint16_t cur_sample = devc->sample_wide ? *((const uint16_t*)cur_buf + i) : *((const uint8_t*)cur_buf + i); @@ -1872,7 +2335,7 @@ static void receive_transfer(struct libusb_transfer *transfer) */ packet.type = SR_DF_TRIGGER; packet.payload = NULL; - sr_session_send(devc->cb_data, &packet); + sr_session_send(sdi, &packet); /* * Send the samples that triggered it, @@ -1883,7 +2346,7 @@ static void receive_transfer(struct libusb_transfer *transfer) logic.unitsize = sizeof(*devc->trigger_buffer); logic.length = devc->trigger_stage * logic.unitsize; logic.data = devc->trigger_buffer; - sr_session_send(devc->cb_data, &packet); + sr_session_send(sdi, &packet); devc->trigger_stage = TRIGGER_FIRED; break; @@ -1905,32 +2368,21 @@ static void receive_transfer(struct libusb_transfer *transfer) } } - if (devc->trigger_stage == TRIGGER_FIRED) { + if (devc->status == DSL_DATA && devc->trigger_stage == TRIGGER_FIRED) { /* Send the incoming transfer to the session bus. */ trigger_offset_bytes = trigger_offset * sample_width; // check packet type - if ((*(struct sr_dev_inst *)(devc->cb_data)).mode == LOGIC) { + if (sdi->mode == LOGIC) { packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = transfer->actual_length - trigger_offset_bytes; logic.unitsize = sample_width; logic.data_error = 0; logic.data = cur_buf + trigger_offset_bytes; - } else if ((*(struct sr_dev_inst *)(devc->cb_data)).mode == DSO) { - uint16_t channel_cnt = 0; - uint16_t channel_en_cnt = 0; - GSList *l; - struct sr_dev_inst *sdi = devc->cb_data; - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - channel_cnt++; - channel_en_cnt += probe->enabled; - } - if (channel_en_cnt == 0) - channel_en_cnt = 1; - + } else if (sdi->mode == DSO) { if (!devc->instant) { - const uint32_t mstatus_offset = devc->limit_samples / (channel_cnt/channel_en_cnt); + const uint32_t mstatus_offset = devc->limit_samples / (g_slist_length(sdi->channels)/en_ch_num(sdi)); + mstatus.pkt_id = *((const uint16_t*)cur_buf + mstatus_offset); mstatus.ch0_max = *((const uint8_t*)cur_buf + mstatus_offset*2 + 1*2); mstatus.ch0_min = *((const uint8_t*)cur_buf + mstatus_offset*2 + 3); mstatus.ch0_period = *((const uint32_t*)cur_buf + mstatus_offset/2 + 2/2); @@ -1943,52 +2395,42 @@ static void receive_transfer(struct libusb_transfer *transfer) mstatus.ch1_pcnt = *((const uint32_t*)cur_buf + mstatus_offset/2 + 14/2); mstatus.vlen = *((const uint32_t*)cur_buf + mstatus_offset/2 + 16/2) & 0x7fffffff; mstatus.stream_mode = *((const uint32_t*)cur_buf + mstatus_offset/2 + 16/2) & 0x80000000; - mstatus.sample_divider = *((const uint32_t*)cur_buf + mstatus_offset/2 + 18/2) & 0x7fffffff; + mstatus.sample_divider = *((const uint32_t*)cur_buf + mstatus_offset/2 + 18/2) & 0x0fffffff; mstatus.sample_divider_tog = *((const uint32_t*)cur_buf + mstatus_offset/2 + 18/2) & 0x80000000; - mstatus.zeroing = (*((const uint16_t*)cur_buf + mstatus_offset + 128) & 0x8000) != 0; - mstatus.ch0_vpos_mid = *((const uint16_t*)cur_buf + mstatus_offset + 128) & 0x7fff; - mstatus.ch0_voff_mid = *((const uint16_t*)cur_buf + mstatus_offset + 129); - mstatus.ch0_vcntr = *((const uint16_t*)cur_buf + mstatus_offset + 130); - mstatus.ch0_adc_off = *((const uint8_t*)cur_buf + mstatus_offset*2 + 131*2); - mstatus.ch0_adc_sign = *((const uint8_t*)cur_buf + mstatus_offset*2 + 131*2+1); - mstatus.ch1_vpos_mid = *((const uint16_t*)cur_buf + mstatus_offset + 132); - mstatus.ch1_voff_mid = *((const uint16_t*)cur_buf + mstatus_offset + 133); - mstatus.ch1_vcntr = *((const uint16_t*)cur_buf + mstatus_offset + 134); - mstatus.ch1_adc_off = *((const uint8_t*)cur_buf + mstatus_offset*2 + 135*2); - mstatus.ch1_adc_sign = *((const uint8_t*)cur_buf + mstatus_offset*2 + 135*2+1); - mstatus.comb0_off = *((const uint16_t*)cur_buf + mstatus_offset + 136); - mstatus.comb1_off = *((const uint16_t*)cur_buf + mstatus_offset + 137); - mstatus.comb_sign = *((const uint8_t*)cur_buf + mstatus_offset*2 + 138*2); + mstatus.trig_flag = *((const uint32_t*)cur_buf + mstatus_offset/2 + 18/2) & 0x40000000; } else { mstatus.vlen = instant_buffer_size; } - const uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(DSCOPE_MAX_SAMPLERATE * 1.0 / devc->cur_samplerate / channel_en_cnt); - if ((mstatus.sample_divider == divider && - mstatus.vlen != 0 && - mstatus.vlen <= (transfer->actual_length - 512) / sample_width) || + const uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(DSCOPE_MAX_SAMPLERATE * 1.0 / devc->cur_samplerate / en_ch_num(sdi)); + if ((mstatus.pkt_id == DSO_PKTID && + mstatus.sample_divider == divider && + mstatus.vlen != 0 && + mstatus.vlen <= (transfer->actual_length - 512) / sample_width) || devc->instant) { - mstatus_valid = devc->instant ? FALSE : TRUE; + devc->roll = (mstatus.stream_mode != 0); + devc->mstatus_valid = TRUE; packet.type = SR_DF_DSO; packet.payload = &dso; - dso.probes = (*(struct sr_dev_inst *)(devc->cb_data)).channels; + dso.probes = sdi->channels; //dso.num_samples = (transfer->actual_length - 512) / sample_width; - cur_sample_count = 2 * mstatus.vlen / channel_en_cnt ; + cur_sample_count = 2 * mstatus.vlen / en_ch_num(sdi) ; dso.num_samples = cur_sample_count; dso.mq = SR_MQ_VOLTAGE; dso.unit = SR_UNIT_VOLT; dso.mqflags = SR_MQFLAG_AC; - dso.samplerate_tog = mstatus.sample_divider_tog; + dso.samplerate_tog = (mstatus.sample_divider_tog != 0); + dso.trig_flag = (mstatus.trig_flag != 0); dso.data = cur_buf + trigger_offset_bytes; } else { packet.type = SR_DF_ABANDON; - mstatus_valid = FALSE; + devc->mstatus_valid = FALSE; } } else { packet.type = SR_DF_ANALOG; packet.payload = &analog; - analog.probes = (*(struct sr_dev_inst *)(devc->cb_data)).channels; - analog.num_samples = transfer->actual_length / sample_width; + analog.probes = sdi->channels; + analog.num_samples = (transfer->actual_length / sample_width)/g_slist_length(analog.probes); analog.mq = SR_MQ_VOLTAGE; analog.unit = SR_UNIT_VOLT; analog.mqflags = SR_MQFLAG_AC; @@ -2013,6 +2455,7 @@ static void receive_transfer(struct libusb_transfer *transfer) } if (cur_sample != test_sample_value) { logic.data_error = 1; + sr_err("exp: %d; act: %d", test_sample_value, cur_sample); break; } test_sample_value++; @@ -2037,26 +2480,21 @@ static void receive_transfer(struct libusb_transfer *transfer) /* send data to session bus */ if (packet.type != SR_DF_ABANDON) - sr_session_send(devc->cb_data, &packet); + sr_session_send(sdi, &packet); } devc->num_samples += cur_sample_count; - if (((*(struct sr_dev_inst *)(devc->cb_data)).mode == LOGIC || devc->instant) && + if ((sdi->mode == LOGIC || devc->instant) && devc->limit_samples && (unsigned int)devc->num_samples >= devc->limit_samples) { - //abort_acquisition(devc); - free_transfer(transfer); devc->status = DSL_STOP; - return; } - } else { - /* - * TODO: Buffer pre-trigger data in capture - * ratio-sized buffer. - */ } - resubmit_transfer(transfer); + if (devc->status == DSL_DATA) + resubmit_transfer(transfer); + else + free_transfer(transfer); } static unsigned int to_bytes_per_ms(struct DSL_context *devc) @@ -2131,31 +2569,23 @@ static int dev_transfer_start(const struct sr_dev_inst *sdi) #else num_transfers = buffer_cnt; #endif - uint16_t channel_en_cnt = 0; - uint16_t channel_cnt = 0; - GSList *l; - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - channel_en_cnt += probe->enabled; - channel_cnt++; - } + if (devc->instant) - dso_buffer_size = instant_buffer_size * channel_cnt; + dso_buffer_size = instant_buffer_size * g_slist_length(sdi->channels); else - dso_buffer_size = devc->limit_samples * channel_en_cnt + 512; + dso_buffer_size = devc->limit_samples * en_ch_num(sdi) + 512; size = (sdi->mode == ANALOG) ? cons_buffer_size : ((sdi->mode == DSO) ? dso_buffer_size : buffer_size); devc->submitted_transfers = 0; devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers); if (!devc->transfers) { - sr_err("USB transfers malloc failed."); + sr_err("%s: USB transfers malloc failed.", __func__); return SR_ERR_MALLOC; } - devc->num_transfers = num_transfers; for (i = 0; i < num_transfers; i++) { if (!(buf = g_try_malloc(size))) { - sr_err("USB transfer buffer malloc failed."); + sr_err("%s: USB transfer buffer malloc failed.", __func__); return SR_ERR_MALLOC; } transfer = libusb_alloc_transfer(0); @@ -2163,15 +2593,17 @@ static int dev_transfer_start(const struct sr_dev_inst *sdi) 6 | LIBUSB_ENDPOINT_IN, buf, size, receive_transfer, devc, 0); if ((ret = libusb_submit_transfer(transfer)) != 0) { - sr_err("Failed to submit transfer: %s.", - libusb_error_name(ret)); + sr_err("%s: Failed to submit transfer: %s.", + __func__, libusb_error_name(ret)); libusb_free_transfer(transfer); g_free(buf); - abort_acquisition(devc); + devc->status = DSL_ERROR; + devc->abort = TRUE; return SR_ERR; } devc->transfers[i] = transfer; devc->submitted_transfers++; + devc->num_transfers++; } devc->status = DSL_DATA; @@ -2186,22 +2618,40 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) struct timeval tv; struct drv_context *drvc; struct DSL_context *devc; + struct sr_usb_dev_inst *usb; + int i; + int ret; (void)fd; (void)revents; drvc = di->priv; devc = sdi->priv; - - if (devc->num_samples != -1 && - (devc->status == DSL_STOP || devc->status == DSL_ERROR)) { - sr_info("%s: Stopping", __func__); - abort_acquisition(devc); - } + usb = sdi->conn; tv.tv_sec = tv.tv_usec = 0; libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv, &completed); + if (devc->zero) { + dso_zero(sdi, mstatus); + } + + if (devc->status == DSL_FINISH) { + if (libusb_try_lock_events(drvc->sr_ctx->libusb_ctx) == 0) { + if (libusb_event_handling_ok(drvc->sr_ctx->libusb_ctx)) { + /* Stop GPIF acquisition */ + usb = ((struct sr_dev_inst *)devc->cb_data)->conn; + if ((ret = command_stop_acquisition (usb->devhdl)) != SR_OK) + sr_err("%s: Sent acquisition stop command failed!", __func__); + else + sr_info("%s: Sent acquisition stop command!", __func__); + + remove_sources(devc); + } + libusb_unlock_events(drvc->sr_ctx->libusb_ctx); + } + } + return TRUE; } @@ -2209,67 +2659,42 @@ static void receive_trigger_pos(struct libusb_transfer *transfer) { struct DSL_context *devc; struct sr_datafeed_packet packet; - struct sr_datafeed_logic logic; - struct sr_datafeed_dso dso; - struct sr_datafeed_analog analog; struct ds_trigger_pos *trigger_pos; + const struct sr_dev_inst *sdi; int ret; devc = transfer->user_data; - sr_info("receive_trigger_pos(): status %d; timeout %d; received %d bytes.", - transfer->status, transfer->timeout, transfer->actual_length); - - if (devc->num_samples == -1) { - free_transfer(transfer); - return; - } - + sdi = devc->cb_data; trigger_pos = (struct ds_trigger_pos *)transfer->buffer; - switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: + devc->status = DSL_ERROR; + if (transfer->status == LIBUSB_TRANSFER_COMPLETED && + trigger_pos->check_id == TRIG_CHECKID) { + sr_info("receive_trigger_pos(): status %d; timeout %d; received %d bytes.", + transfer->status, transfer->timeout, transfer->actual_length); if (transfer->actual_length == sizeof(struct ds_trigger_pos)) { packet.type = SR_DF_TRIGGER; packet.payload = trigger_pos; - sr_session_send(devc->cb_data, &packet); + sr_session_send(sdi, &packet); devc->status = DSL_TRIGGERED; - free_transfer(transfer); devc->num_transfers = 0; devc->empty_transfer_count = 0; - } else { - free_transfer(transfer); - devc->status = DSL_ERROR; } - break; - case LIBUSB_TRANSFER_TIMED_OUT: - devc->empty_transfer_count++; - if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) { - /* - * The FX2 gave up. End the acquisition, the frontend - * will work out that the samplecount is short. - */ - //abort_acquisition(devc); - free_transfer(transfer); - devc->status = DSL_ERROR; - } else { - resubmit_transfer(transfer); - } - break; - case LIBUSB_TRANSFER_CANCELLED: - resubmit_transfer(transfer); - break; - default: - //abort_acquisition(devc); - free_transfer(transfer); - devc->status = DSL_ERROR; - break; } if (devc->status == DSL_TRIGGERED) { + // successfull + free_transfer(transfer); if ((ret = dev_transfer_start(devc->cb_data)) != SR_OK) { sr_err("%s: could not start data transfer" "(%d)%d", __func__, ret, errno); } + } else if (devc->status == DSL_START) { + // retry + resubmit_transfer(transfer); + } else { + // failed + free_transfer(transfer); } } @@ -2283,9 +2708,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) const struct libusb_pollfd **lupfd; unsigned int i; int ret; - int transferred; - struct sr_datafeed_packet packet; - int header_transferred; test_init = 1; @@ -2303,57 +2725,82 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) devc->status = DSL_INIT; devc->num_transfers = 0; devc->submitted_transfers = 0; + test_sample_value = 0; + devc->abort = FALSE; /* Configures devc->trigger_* and devc->sample_wide */ if (configure_probes(sdi) != SR_OK) { - sr_err("Failed to configure probes."); + sr_err("%s: Failed to configure probes.", __func__); return SR_ERR; } /* Stop Previous GPIF acquisition */ if ((ret = command_stop_acquisition (usb->devhdl)) != SR_OK) { - sr_err("Stop DSCope acquisition failed!"); - abort_acquisition(devc); + sr_err("%s: Stop DSCope acquisition failed!", __func__); return ret; } else { - sr_info("Stop Previous DSCope acquisition!"); + sr_info("%s: Stop Previous DSCope acquisition!", __func__); } /* Setting FPGA before acquisition start*/ if ((ret = command_fpga_setting(usb->devhdl, sizeof(struct DSL_setting) / sizeof(uint16_t))) != SR_OK) { - sr_err("Send FPGA setting command failed!"); + sr_err("%s: Send FPGA setting command failed!", __func__); } else { if ((ret = fpga_setting(sdi)) != SR_OK) { - sr_err("Configure FPGA failed!"); - abort_acquisition(devc); + sr_err("%s: Configure FPGA failed!", __func__); return ret; } } -// if (sdi->mode == DSO) { -// 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_COUPLING)); -// if (ret != SR_OK) { -// sr_err("Set COUPLING of channel %d command failed!", probe->index); -// return ret; -// } -// ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe, SR_CONF_VPOS)); -// if (ret != SR_OK) { -// sr_err("Set VDIV of channel %d command failed!", probe->index); -// return ret; -// } -// } -// } - - if ((ret = command_start_acquisition (usb->devhdl, - devc->cur_samplerate, devc->sample_wide, (sdi->mode == LOGIC))) != SR_OK) { - abort_acquisition(devc); - return ret; + if (devc->zero && devc->zero_stage == -1) { + // initialize before zero adjustment + if ((ret = dso_init(sdi)) == SR_OK) { + devc->zero_stage = 0; + } else { + sr_err("%s: DSO zero initialization failed!", __func__); + return ret; + } + devc->zero_stage = 0; } - test_sample_value = 0; + /* + * settings must be updated before acquisition + */ + if (sdi->mode == DSO) { + devc->trigger_hpos = devc->trigger_hrate * en_ch_num(sdi) * devc->limit_samples / 200.0; + if ((ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_HORIZ_TRIGGERPOS))) == SR_OK) + sr_dbg("%s: setting DSO Horiz Trigger Position to %d", + __func__, devc->trigger_hpos); + else + sr_dbg("%s: setting DSO Horiz Trigger Position to %d failed", + __func__, devc->trigger_hpos); + } + + /* poll trigger status transfer*/ + if (!(trigger_pos = g_try_malloc0(sizeof(struct ds_trigger_pos)))) { + sr_err("%s: USB trigger_pos buffer malloc failed.", __func__); + return SR_ERR_MALLOC; + } + devc->transfers = g_try_malloc0(sizeof(*devc->transfers)); + if (!devc->transfers) { + sr_err("%s: USB trigger_pos transfer malloc failed.", __func__); + return SR_ERR_MALLOC; + } + transfer = libusb_alloc_transfer(0); + libusb_fill_bulk_transfer(transfer, usb->devhdl, + 6 | LIBUSB_ENDPOINT_IN, trigger_pos, sizeof(struct ds_trigger_pos), + receive_trigger_pos, devc, 0); + if ((ret = libusb_submit_transfer(transfer)) != 0) { + sr_err("%s: Failed to submit trigger_pos transfer: %s.", + __func__, libusb_error_name(ret)); + libusb_free_transfer(transfer); + g_free(trigger_pos); + return SR_ERR; + } else { + devc->num_transfers++; + devc->transfers[0] = transfer; + devc->submitted_transfers++; + } /* setup callback function for data transfer */ lupfd = libusb_get_pollfds(drvc->sr_ctx->libusb_ctx); @@ -2362,41 +2809,21 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) return SR_ERR; for (i = 0; lupfd[i]; i++) { sr_source_add(lupfd[i]->fd, lupfd[i]->events, - get_timeout(devc), receive_data, sdi); - devc->usbfd[i] = lupfd[i]->fd; + get_timeout(devc), receive_data, sdi); + devc->usbfd[i] = lupfd[i]->fd; } devc->usbfd[i] = -1; free(lupfd); - - /* poll trigger status transfer*/ - if (!(trigger_pos = g_try_malloc0(sizeof(struct ds_trigger_pos)))) { - sr_err("USB trigger_pos buffer malloc failed."); - return SR_ERR_MALLOC; - } - devc->transfers = g_try_malloc0(sizeof(*devc->transfers)); - if (!devc->transfers) { - sr_err("USB trigger_pos transfer malloc failed."); - return SR_ERR_MALLOC; - } - devc->num_transfers = 1; - transfer = libusb_alloc_transfer(0); - libusb_fill_bulk_transfer(transfer, usb->devhdl, - 6 | LIBUSB_ENDPOINT_IN, trigger_pos, sizeof(struct ds_trigger_pos), - receive_trigger_pos, devc, 0); - if ((ret = libusb_submit_transfer(transfer)) != 0) { - sr_err("Failed to submit trigger_pos transfer: %s.", - libusb_error_name(ret)); - libusb_free_transfer(transfer); - g_free(trigger_pos); - abort_acquisition(devc); - return SR_ERR; - } - devc->transfers[0] = transfer; - devc->submitted_transfers++; devc->status = DSL_START; - mstatus_valid = FALSE; - mstatus.zeroing = devc->zero; + devc->mstatus_valid = FALSE; + if ((ret = command_start_acquisition (usb->devhdl, + devc->cur_samplerate, devc->sample_wide, (sdi->mode == LOGIC))) != SR_OK) { + devc->status = DSL_ERROR; + devc->abort = TRUE; + return ret; + } + /* Send header packet to the session bus. */ //std_session_send_df_header(cb_data, LOG_PREFIX); std_session_send_df_header(sdi, LOG_PREFIX); @@ -2408,12 +2835,18 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { (void)cb_data; + struct drv_context *drvc; struct DSL_context *devc; + struct sr_usb_dev_inst *usb; + drvc = di->priv; devc = sdi->priv; - devc->status = DSL_STOP; + usb = sdi->conn; - //abort_acquisition(sdi->priv); + if (!devc->abort) { + devc->abort = TRUE; + command_wr_reg(usb->devhdl, 3, EEWP_ADDR); + } return SR_OK; } @@ -2440,23 +2873,22 @@ static int dev_test(struct sr_dev_inst *sdi) static int dev_status_get(struct sr_dev_inst *sdi, struct sr_status *status, int begin, int end) { - (void)begin; - (void)end; + int ret = SR_ERR; if (sdi) { struct DSL_context *devc; + struct sr_usb_dev_inst *usb; + devc = sdi->priv; - if (mstatus_valid) { + usb = sdi->conn; + if (devc->status == DSL_START) { + ret = command_get_status(usb->devhdl, (unsigned char*)status, begin, end); + } else if (devc->mstatus_valid) { *status = mstatus; - if (devc->zero) - return SR_ERR; - else - return SR_OK; - } else { - return SR_ERR; + ret = SR_OK; } - } else { - return SR_ERR; } + + return ret; } SR_PRIV struct sr_dev_driver DSCope_driver_info = { diff --git a/libsigrok4DSL/hardware/DSL/dsl.h b/libsigrok4DSL/hardware/DSL/dsl.h index 2a693e70..4916367f 100644 --- a/libsigrok4DSL/hardware/DSL/dsl.h +++ b/libsigrok4DSL/hardware/DSL/dsl.h @@ -2,7 +2,7 @@ * This file is part of the libsigrok project. * * Copyright (C) 2013 Bert Vermeulen - * Copyright (C) 2013 DreamSourceLab + * 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 @@ -78,6 +78,54 @@ #define DSCOPE_MAX_SAMPLERATE SR_MHZ(200) #define DSCOPE_INSTANT_DEPTH SR_MB(32) +/* + * for DSCope device + * trans: x << 8 + y + * x = vpos(coarse), each step(1024 total) indicate x(mv) at 1/20 attenuation, and x/10(mv) at 1/2 attenuation + * y = voff(fine), each step(1024 total) indicate y/100(mv) at 1/20 attenuation, adn y/1000(mv) at 1/2 attenuation + * voff: x << 10 + y + * x = vpos(coarse) default bias + * y = voff(fine) default bias + * the final offset: x+DSCOPE_CONSTANT_BIAS->vpos(coarse); y->voff(fine) + */ +#define DSCOPE_DEFAULT_TRANS (129<<8)+167 +#define DSCOPE_DEFAULT_VOFF (32<<10)+558 +#define DSCOPE_CONSTANT_BIAS 160 +#define DSCOPE_TRANS_CMULTI 10 +#define DSCOPE_TRANS_FMULTI 100.0 +#define DSCOPE_DEFAULT_VGAIN0 0x162400 +#define DSCOPE_DEFAULT_VGAIN1 0x14C000 +#define DSCOPE_DEFAULT_VGAIN2 0x12E800 +#define DSCOPE_DEFAULT_VGAIN3 0x118000 +#define DSCOPE_DEFAULT_VGAIN4 0x102400 +#define DSCOPE_DEFAULT_VGAIN5 0x2E800 +#define DSCOPE_DEFAULT_VGAIN6 0x18000 +#define DSCOPE_DEFAULT_VGAIN7 0x02400 + +/* + * for DSCope20 device + * trans: the whole windows offset map to the offset pwm(1024 total) + * voff: offset pwm constant bias to balance circuit offset + */ +#define DSCOPE20_DEFAULT_TRANS 920 +#define DSCOPE20_DEFAULT_VOFF 45 +#define DSCOPE20_DEFAULT_VGAIN0 0x1DA800 +#define DSCOPE20_DEFAULT_VGAIN1 0x1A7200 +#define DSCOPE20_DEFAULT_VGAIN2 0x164200 +#define DSCOPE20_DEFAULT_VGAIN3 0x131800 +#define DSCOPE20_DEFAULT_VGAIN4 0xBD000 +#define DSCOPE20_DEFAULT_VGAIN5 0x7AD00 +#define DSCOPE20_DEFAULT_VGAIN6 0x48800 +#define DSCOPE20_DEFAULT_VGAIN7 0x12000 + +#define CALI_VGAIN_RANGE 100 +#define CALI_VOFF_RANGE (1024-DSCOPE20_DEFAULT_TRANS) + +#define DSO_AUTOTRIG_THRESHOLD 16 + +#define TRIG_CHECKID 0xa500005a +#define DSO_PKTID 0xa500 + struct DSL_profile { uint16_t vid; uint16_t pid; @@ -113,7 +161,7 @@ static const struct DSL_profile supported_DSLogic[3] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; -static const struct DSL_profile supported_DSCope[2] = { +static const struct DSL_profile supported_DSCope[3] = { /* * DSCope */ @@ -123,9 +171,26 @@ static const struct DSL_profile supported_DSCope[2] = { "DSCope.bin", DEV_CAPS_16BIT}, + {0x2A0E, 0x0004, NULL, "DSCope20", NULL, + "DSCope20.fw", + "DSCope20.bin", + "DSCope20.bin", + DEV_CAPS_16BIT}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; +static const gboolean default_ms_en[DSO_MS_END - DSO_MS_BEGIN] = { + FALSE, /* DSO_MS_BEGIN */ + TRUE, /* DSO_MS_FREQ */ + FALSE, /* DSO_MS_PERD */ + TRUE, /* DSO_MS_VMAX */ + TRUE, /* DSO_MS_VMIN */ + FALSE, /* DSO_MS_VRMS */ + FALSE, /* DSO_MS_VMEA */ + FALSE, /* DSO_MS_VP2P */ + FALSE, /* DSO_MS_END */ +}; enum { DSL_ERROR = -1, @@ -135,6 +200,7 @@ enum { DSL_TRIGGERED = 3, DSL_DATA = 4, DSL_STOP = 5, + DSL_FINISH = 6, }; struct DSL_context { @@ -161,6 +227,7 @@ struct DSL_context { uint16_t op_mode; uint16_t ch_mode; uint16_t samplerates_size; + uint16_t samplecounts_size; uint16_t th_level; double vth; uint16_t filter; @@ -170,14 +237,22 @@ struct DSL_context { uint16_t trigger_buffer[NUM_TRIGGER_STAGES]; uint64_t timebase; uint8_t max_height; + uint8_t trigger_channel; uint8_t trigger_slope; uint8_t trigger_source; uint8_t trigger_hrate; uint32_t trigger_hpos; uint32_t trigger_holdoff; + uint8_t trigger_margin; gboolean zero; + gboolean cali; + int zero_stage; + int zero_pcnt; + int zero_comb; gboolean stream; + gboolean roll; gboolean data_lock; + uint8_t dso_bits; int num_samples; int submitted_transfers; @@ -193,6 +268,7 @@ struct DSL_context { int status; gboolean mstatus_valid; + gboolean abort; }; struct DSL_setting { @@ -254,4 +330,12 @@ struct DSL_setting { uint32_t end_sync; }; +struct DSL_vga { + int key; + uint64_t vgain0; + uint64_t vgain1; + uint16_t voff0; + uint16_t voff1; +}; + #endif diff --git a/libsigrok4DSL/hardware/DSL/dslogic.c b/libsigrok4DSL/hardware/DSL/dslogic.c index 2250da53..973a2667 100644 --- a/libsigrok4DSL/hardware/DSL/dslogic.c +++ b/libsigrok4DSL/hardware/DSL/dslogic.c @@ -134,33 +134,36 @@ static const int32_t hwoptions_pro[] = { }; static const int32_t sessions[] = { + SR_CONF_OPERATION_MODE, + SR_CONF_CHANNEL_MODE, SR_CONF_SAMPLERATE, SR_CONF_LIMIT_SAMPLES, SR_CONF_CLOCK_TYPE, SR_CONF_CLOCK_EDGE, - SR_CONF_OPERATION_MODE, - SR_CONF_CHANNEL_MODE, SR_CONF_THRESHOLD, SR_CONF_FILTER, SR_CONF_TRIGGER_SLOPE, SR_CONF_TRIGGER_SOURCE, SR_CONF_HORIZ_TRIGGERPOS, SR_CONF_TRIGGER_HOLDOFF, + SR_CONF_TRIGGER_MARGIN, }; static const int32_t sessions_pro[] = { + SR_CONF_OPERATION_MODE, + SR_CONF_CHANNEL_MODE, SR_CONF_SAMPLERATE, SR_CONF_LIMIT_SAMPLES, SR_CONF_CLOCK_TYPE, SR_CONF_CLOCK_EDGE, - SR_CONF_OPERATION_MODE, - SR_CONF_CHANNEL_MODE, SR_CONF_VTH, SR_CONF_FILTER, SR_CONF_TRIGGER_SLOPE, SR_CONF_TRIGGER_SOURCE, + SR_CONF_TRIGGER_CHANNEL, SR_CONF_HORIZ_TRIGGERPOS, SR_CONF_TRIGGER_HOLDOFF, + SR_CONF_TRIGGER_MARGIN, }; static const int32_t ch_sessions[] = { @@ -236,7 +239,6 @@ static const uint64_t samplecounts[] = { }; static const uint8_t zero_base_addr = 0x80; -static const uint8_t comb_base_addr = 0xB0; SR_PRIV struct sr_dev_driver DSLogic_driver_info; static struct sr_dev_driver *di = &DSLogic_driver_info; @@ -244,8 +246,6 @@ static struct sr_dev_driver *di = &DSLogic_driver_info; extern struct ds_trigger *trigger; struct sr_status mstatus; -struct cmd_zero_info zero_info; -struct cmd_comb_info comb_info; /** * Check the USB configuration to determine if this is an DSLogic device. @@ -279,7 +279,7 @@ static gboolean check_conf_profile(libusb_device *dev) if (libusb_get_string_descriptor_ascii(hdl, des.iProduct, strdesc, sizeof(strdesc)) < 0) break; - if (strncmp((const char *)strdesc, "DSLogic", 7)) + if (strncmp((const char *)strdesc, "USB-based Instrument", 20)) break; /* If we made it here, it must be an DSLogic. */ @@ -291,6 +291,20 @@ static gboolean check_conf_profile(libusb_device *dev) return ret; } +static int en_ch_num(const struct sr_dev_inst *sdi) +{ + GSList *l; + int channel_en_cnt = 0; + + for (l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + channel_en_cnt += probe->enabled; + } + channel_en_cnt += (channel_en_cnt == 0); + + return channel_en_cnt; +} + static int fpga_setting(const struct sr_dev_inst *sdi) { struct DSL_context *devc; @@ -339,14 +353,6 @@ static int fpga_setting(const struct sr_dev_inst *sdi) //setting.trig_logic3_header = 0x2310ffff; setting.end_sync = 0xfa5afa5a; - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - channel_en_cnt += probe->enabled; - channel_cnt++; - } - if (channel_en_cnt == 0) - channel_en_cnt = 1; - devc->rle_mode = FALSE; if (sdi->mode == LOGIC && !devc->stream && @@ -360,18 +366,21 @@ static int fpga_setting(const struct sr_dev_inst *sdi) ((devc->stream) << 12) + ((trigger->trigger_mode == SERIAL_TRIGGER) << 11) + trigger->trigger_en + - ((sdi->mode > 0) << 4) + (devc->clock_type << 1) + (devc->clock_edge << 2) + + ((sdi->mode == DSO) << 4) + (devc->clock_type << 1) + (devc->clock_edge << 2) + (devc->rle_mode << 3) + ((((devc->cur_samplerate == (2 * DSLOGIC_MAX_LOGIC_SAMPLERATE)) && sdi->mode != DSO) || (sdi->mode == ANALOG)) << 5) + ((devc->cur_samplerate == (4 * DSLOGIC_MAX_LOGIC_SAMPLERATE)) << 6) + ((sdi->mode == ANALOG) << 7) + ((devc->filter == SR_FILTER_1T) << 8) + - (devc->instant << 9) + (devc->zero << 10); - if (sdi->mode == DSO) - setting.divider = devc->zero ? 0x1 : (uint32_t)ceil(DSLOGIC_MAX_DSO_SAMPLERATE * 1.0 / devc->cur_samplerate / channel_en_cnt); - else - setting.divider = devc->zero ? 0x1 : (uint32_t)ceil(DSLOGIC_MAX_LOGIC_SAMPLERATE * 1.0 / devc->cur_samplerate); - setting.count = (sdi->mode == DSO) ? (uint32_t)(devc->limit_samples / (channel_cnt / channel_en_cnt)) : (uint32_t)(devc->limit_samples); + (devc->instant << 9); + + setting.divider = (sdi->mode == DSO) ? (uint32_t)ceil(DSLOGIC_MAX_DSO_SAMPLERATE * 1.0 / devc->cur_samplerate / en_ch_num(sdi)) : + (uint32_t)ceil(DSLOGIC_MAX_LOGIC_SAMPLERATE * 1.0 / devc->cur_samplerate); + + // analog: 16bits, but sample with half mode(0-7 valid only) + setting.count = (sdi->mode == DSO) ? (uint32_t)(devc->limit_samples / (g_slist_length(sdi->channels) / en_ch_num(sdi))) : + (sdi->mode == ANALOG) ? (uint32_t)(devc->limit_samples * g_slist_length(sdi->channels) * 4) : + (uint32_t)(devc->limit_samples); setting.trig_pos = (uint32_t)(trigger->trigger_pos / 100.0 * devc->limit_samples); setting.trig_glb = trigger->trigger_stages; setting.trig_adp = setting.count - setting.trig_pos - 1; @@ -393,8 +402,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] = 0xff; - setting.trig_mask1[i] = 0xff; + setting.trig_mask0[i] = 0xffff; + setting.trig_mask1[i] = 0xffff; setting.trig_value0[i] = 0; setting.trig_value1[i] = 0; @@ -430,7 +439,7 @@ static int fpga_setting(const struct sr_dev_inst *sdi) result = SR_OK; ret = libusb_bulk_transfer(hdl, 2 | LIBUSB_ENDPOINT_OUT, &setting, sizeof(struct DSL_setting), - &transferred, 3000); + &transferred, 1000); if (ret < 0) { sr_err("Unable to setting FPGA of DSLogic: %s.", @@ -458,7 +467,7 @@ static int fpga_config(struct libusb_device_handle *hdl, const char *filename) struct stat f_stat; sr_info("Configure FPGA using %s", filename); - if ((fw = g_fopen(filename, "rb")) == NULL) { + if ((fw = fopen(filename, "rb")) == NULL) { sr_err("Unable to open FPGA bit file %s for reading: %s", filename, strerror(errno)); return SR_ERR; @@ -688,6 +697,7 @@ static struct DSL_context *DSLogic_dev_new(void) devc->op_mode = SR_OP_BUFFER; devc->ch_mode = 0; devc->samplerates_size = 14; + devc->samplecounts_size = ARRAY_SIZE(samplecounts); devc->th_level = SR_TH_3V3; devc->vth = 1.0; devc->filter = SR_FILTER_NONE; @@ -701,7 +711,10 @@ static struct DSL_context *DSLogic_dev_new(void) devc->stream = FALSE; devc->mstatus_valid = FALSE; devc->data_lock = FALSE; - devc->max_height = 1; + devc->max_height = 0; + devc->dso_bits = 8; + devc->trigger_margin = 8; + devc->trigger_channel = 0; return devc; } @@ -716,6 +729,25 @@ static int init(struct sr_context *sr_ctx) return std_hw_init(sr_ctx, di, LOG_PREFIX); } +static int probe_init(struct sr_dev_inst *sdi) +{ + int i; + GList *l; + for (l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + if (sdi->mode == DSO) { + probe->vdiv = 1000; + probe->vfactor = 1; + probe->vpos = 0; + probe->coupling = SR_DC_COUPLING; + probe->trig_value = 0x80; + probe->ms_show = TRUE; + for (i = DSO_MS_BEGIN; i < DSO_MS_END; i++) + probe->ms_en[i] = default_ms_en[i]; + } + } +} + static int set_probes(struct sr_dev_inst *sdi, int num_probes) { uint16_t j; @@ -725,15 +757,9 @@ static int set_probes(struct sr_dev_inst *sdi, int num_probes) 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; - if (sdi->mode == DSO) { - probe->vdiv = 1000; - probe->vfactor = 1; - probe->vpos = 0; - probe->coupling = SR_DC_COUPLING; - probe->trig_value = 0x80; - } sdi->channels = g_slist_append(sdi->channels, probe); } + probe_init(sdi); return SR_OK; } @@ -845,7 +871,7 @@ static GSList *scan(GSList *options) devc->profile = prof; sdi->priv = devc; drvc->instances = g_slist_append(drvc->instances, sdi); - devices = g_slist_append(devices, sdi); + //devices = g_slist_append(devices, sdi); if (check_conf_profile(devlist[i])) { /* Already has the firmware, so fix the new address. */ @@ -854,13 +880,15 @@ static GSList *scan(GSList *options) sdi->inst_type = SR_INST_USB; sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]), libusb_get_device_address(devlist[i]), NULL); + /* only report device after firmware is ready */ + devices = g_slist_append(devices, sdi); } else { char *firmware; - if (!(firmware = g_try_malloc(strlen(config_path)+strlen(prof->firmware)+1))) { + if (!(firmware = g_try_malloc(strlen(DS_RES_PATH)+strlen(prof->firmware)+1))) { sr_err("Firmware path malloc error!"); return NULL; } - strcpy(firmware, config_path); + strcpy(firmware, DS_RES_PATH); strcat(firmware, prof->firmware); if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION, firmware) == SR_OK) @@ -903,13 +931,13 @@ static GSList *dev_mode_list(const struct sr_dev_inst *sdi) return l; } -static uint64_t dso_cmd_gen(struct sr_dev_inst *sdi, struct sr_channel* ch, int id) +static uint64_t dso_cmd_gen(const struct sr_dev_inst *sdi, struct sr_channel* ch, int id) { struct DSL_context *devc; uint64_t cmd = 0; int channel_cnt = 0; GSList *l; - const int ch_bit = 7; + struct sr_channel *en_probe; devc = sdi->priv; @@ -920,14 +948,18 @@ static uint64_t dso_cmd_gen(struct sr_dev_inst *sdi, struct sr_channel* ch, int case SR_CONF_COUPLING: for (l = sdi->channels; l; l = l->next) { struct sr_channel *probe = (struct sr_channel *)l->data; - if (probe->enabled) + if (probe->enabled) { channel_cnt += probe->index + 0x1; + en_probe = probe; + } } if (channel_cnt == 0) return 0x0; // --VDBS - switch(ch->vdiv){ + if (channel_cnt != 1) + en_probe = ch; + switch(en_probe->vdiv){ case 5: cmd += 0x247000; break; case 10: cmd += 0x23D000; break; case 20: cmd += 0x22F000; break; @@ -978,7 +1010,7 @@ static uint64_t dso_cmd_gen(struct sr_dev_inst *sdi, struct sr_channel* ch, int channel_cnt += probe->enabled; } cmd += 0x18; - uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(DSLOGIC_MAX_DSO_SAMPLERATE * 1.0 / devc->cur_samplerate / channel_cnt); + uint32_t divider = (uint32_t)ceil(DSLOGIC_MAX_DSO_SAMPLERATE * 1.0 / devc->cur_samplerate / channel_cnt); cmd += divider << 8; break; case SR_CONF_HORIZ_TRIGGERPOS: @@ -1000,27 +1032,9 @@ static uint64_t dso_cmd_gen(struct sr_dev_inst *sdi, struct sr_channel* ch, int cmd += probe->trig_value << (8 * (probe->index + 1)); } break; - case SR_CONF_ZERO_SET: + case SR_CONF_TRIGGER_MARGIN: cmd += 0x40; - cmd += ch->index << ch_bit; - cmd += ((uint64_t)zero_info.vpos_l << 8); - cmd += ((uint64_t)(zero_info.vpos_h & 0x3) << 16); - cmd += ((uint64_t)zero_info.voff_l << 24); - cmd += ((uint64_t)(zero_info.voff_h & 0x3) << 32); - cmd += ((uint64_t)zero_info.vcntr_l << 40); - cmd += ((uint64_t)(zero_info.vcntr_h & 0x3) << 48); - cmd += ((uint64_t)zero_info.adc_off << 56); - break; - case SR_CONF_COMB_SET: - cmd += 0x48; - cmd += ((uint64_t)comb_info.comb0_low_off << 8); - cmd += ((uint64_t)comb_info.comb0_hig_off << 16); - cmd += ((uint64_t)comb_info.comb1_low_off << 24); - cmd += ((uint64_t)comb_info.comb1_hig_off << 32); - cmd += ((uint64_t)comb_info.comb_sign << 40); - break; - case SR_CONF_ZERO_OVER: - cmd += 0x50; + cmd += ((uint64_t)devc->trigger_margin << 8); break; case SR_CONF_TRIGGER_HOLDOFF: cmd += 0x58; @@ -1030,149 +1044,69 @@ static uint64_t dso_cmd_gen(struct sr_dev_inst *sdi, struct sr_channel* ch, int cmd = 0xa5a5a500; break; default: - cmd = 0x00000000; + cmd = 0xFFFFFFFF; } return cmd; } -static int dev_open(struct sr_dev_inst *sdi) +static int dso_init(const struct sr_dev_inst *sdi, gboolean from_eep) { - struct sr_usb_dev_inst *usb; - struct DSL_context *devc; + int ret, i; GSList *l; - int ret; - int64_t timediff_us, timediff_ms; + struct sr_usb_dev_inst *usb = sdi->conn; + gboolean zeroed = FALSE; - devc = sdi->priv; - usb = sdi->conn; - - /* - * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS - * milliseconds for the FX2 to renumerate. - */ - ret = SR_ERR; - if (devc->fw_updated > 0) { - sr_info("Waiting for device to reset."); - /* Takes >= 300ms for the FX2 to be gone from the USB bus. */ - g_usleep(300 * 1000); - timediff_ms = 0; - while (timediff_ms < MAX_RENUM_DELAY_MS) { - if ((ret = DSLogic_dev_open(sdi)) == SR_OK) - break; - g_usleep(100 * 1000); - - timediff_us = g_get_monotonic_time() - devc->fw_updated; - timediff_ms = timediff_us / 1000; - sr_spew("Waited %" PRIi64 "ms.", timediff_ms); - } + 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_COUPLING)); if (ret != SR_OK) { - sr_err("Device failed to renumerate."); - return SR_ERR; + sr_err("DSO set coupling of channel %d command failed!", probe->index); + return ret; + } + 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; } - sr_info("Device came back after %" PRIi64 "ms.", timediff_ms); - } else { - sr_info("Firmware upload was not needed."); - ret = DSLogic_dev_open(sdi); } + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_SAMPLERATE)); if (ret != SR_OK) { - sr_err("Unable to open device."); - return SR_ERR; - } - - ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE); - if (ret != 0) { - switch(ret) { - case LIBUSB_ERROR_BUSY: - sr_err("Unable to claim USB interface. Another " - "program or driver has already claimed it."); - break; - case LIBUSB_ERROR_NO_DEVICE: - sr_err("Device has been disconnected."); - break; - default: - sr_err("Unable to claim interface: %s.", - libusb_error_name(ret)); - break; - } - - return SR_ERR; - } - - if (devc->fw_updated > 0) { - 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 *fpga_bit; - if (!(fpga_bit = g_try_malloc(strlen(config_path)+strlen(devc->profile->fpga_bit33)+1))) { - sr_err("fpag_bit path malloc error!"); - return SR_ERR_MALLOC; - } - strcpy(fpga_bit, config_path); - switch(devc->th_level) { - case SR_TH_3V3: - strcat(fpga_bit, devc->profile->fpga_bit33);; - break; - case SR_TH_5V0: - strcat(fpga_bit, devc->profile->fpga_bit50);; - break; - default: - return SR_ERR; - } - ret = fpga_config(usb->devhdl, fpga_bit); - if (ret != SR_OK) { - sr_err("Configure FPGA failed!"); - } - g_free(fpga_bit); - } + sr_err("Set Sample Rate command failed!"); + return ret; } - - ret = command_vth(usb->devhdl, devc->vth); - if (ret == SR_OK) - sr_dbg("%s: setting threshold voltage to %d", - __func__, devc->vth); - else - sr_dbg("%s: setting threshold voltage to %d failed", - __func__, devc->vth); - - return SR_OK; -} - -static int dev_close(struct sr_dev_inst *sdi) -{ - struct sr_usb_dev_inst *usb; - - usb = sdi->conn; - if (usb->devhdl == NULL) - return SR_ERR; - - sr_info("DSLogic: Closing device %d on %d.%d interface %d.", - sdi->index, usb->bus, usb->address, USB_INTERFACE); - libusb_release_interface(usb->devhdl, USB_INTERFACE); - libusb_close(usb->devhdl); - usb->devhdl = NULL; - sdi->status = SR_ST_INACTIVE; - - return SR_OK; -} - -static int cleanup(void) -{ - int ret; - struct drv_context *drvc; - - if (!(drvc = di->priv)) - return SR_OK; - - ret = dev_clear(); - - g_free(drvc); - di->priv = NULL; - - return ret; + 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, NULL, SR_CONF_TRIGGER_HOLDOFF)); + if (ret != SR_OK) { + sr_err("Set Trigger Holdoff Time command failed!"); + return ret; + } + 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, 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, NULL, SR_CONF_TRIGGER_VALUE)); + if (ret != SR_OK) { + sr_err("Set Trigger Value command failed!"); + return ret; + } + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_TRIGGER_MARGIN)); + if (ret != SR_OK) { + sr_err("Set Trigger Margin command failed!"); + return ret; + } + return ret; } static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, @@ -1338,7 +1272,13 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, if (!sdi) return SR_ERR; devc = sdi->priv; - *data = g_variant_new_byte(devc->trigger_source); + *data = g_variant_new_byte(devc->trigger_source&0x0f); + break; + case SR_CONF_TRIGGER_CHANNEL: + if (!sdi) + return SR_ERR; + devc = sdi->priv; + *data = g_variant_new_byte(devc->trigger_source>>4); break; case SR_CONF_TRIGGER_VALUE: if (!ch) @@ -1361,6 +1301,12 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, devc = sdi->priv; *data = g_variant_new_uint64(devc->trigger_holdoff); break; + case SR_CONF_TRIGGER_MARGIN: + if (!sdi) + return SR_ERR; + devc = sdi->priv; + *data = g_variant_new_byte(devc->trigger_margin); + break; case SR_CONF_ZERO: if (!sdi) return SR_ERR; @@ -1376,6 +1322,12 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, devc = sdi->priv; *data = g_variant_new_boolean(devc->stream); break; + case SR_CONF_ROLL: + if (!sdi) + return SR_ERR; + devc = sdi->priv; + *data = g_variant_new_boolean(devc->roll); + break; case SR_CONF_MAX_DSO_SAMPLERATE: if (!sdi) return SR_ERR; @@ -1403,11 +1355,11 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, devc = sdi->priv; *data = g_variant_new_uint64(DSLOGIC_MAX_LOGIC_DEPTH*ceil(samplerates[devc->samplerates_size-1] * 1.0 / DSLOGIC_MAX_LOGIC_SAMPLERATE)); break; - case SR_CONF_STATUS: + case SR_CONF_DSO_BITS: if (!sdi) return SR_ERR; devc = sdi->priv; - *data = g_variant_new_boolean(devc->status != DSL_INIT); + *data = g_variant_new_byte(devc->dso_bits); break; default: return SR_ERR_NA; @@ -1425,15 +1377,18 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, int ret, num_probes; struct sr_usb_dev_inst *usb; int i; + struct drv_context *drvc; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR; + drvc = di->priv; devc = sdi->priv; usb = sdi->conn; + ret = SR_OK; if (id == SR_CONF_SAMPLERATE) { devc->cur_samplerate = g_variant_get_uint64(data); if(sdi->mode == DSO) { @@ -1441,141 +1396,54 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_SAMPLERATE)); } else { devc->sample_wide = (devc->cur_samplerate <= DSLOGIC_MAX_LOGIC_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_CLOCK_EDGE) { devc->clock_edge = g_variant_get_boolean(data); - ret = SR_OK; } else if (id == SR_CONF_RLE) { devc->rle_mode = g_variant_get_boolean(data); - ret = SR_OK; } else if (id == SR_CONF_INSTANT) { if (sdi->mode == DSO) { devc->instant = g_variant_get_boolean(data); - int num_probes = 0; - GSList *l; - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - num_probes += probe->enabled; - } - if (num_probes != 0) { + if (en_ch_num(sdi) != 0) { if (devc->instant) - devc->limit_samples = DSLOGIC_INSTANT_DEPTH / num_probes; + devc->limit_samples = DSLOGIC_INSTANT_DEPTH / en_ch_num(sdi); else - devc->limit_samples = DSLOGIC_MAX_DSO_DEPTH / num_probes; + devc->limit_samples = DSLOGIC_MAX_DSO_DEPTH / en_ch_num(sdi); } } - 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) { sdi->mode = g_variant_get_int16(data); - ret = SR_OK; if (sdi->mode == LOGIC) { num_probes = devc->profile->dev_caps & DEV_CAPS_16BIT ? 16 : 8; + devc->samplecounts_size = ARRAY_SIZE(samplecounts); } 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, NULL, SR_CONF_DSO_SYNC)); if (ret != SR_OK) sr_dbg("%s: DSO configuration sync failed", __func__); devc->cur_samplerate = DSLOGIC_MAX_DSO_SAMPLERATE / num_probes; devc->limit_samples = DSLOGIC_MAX_DSO_DEPTH / num_probes; + devc->samplerates_size = 15; + devc->samplecounts_size = ARRAY_SIZE(samplecounts); } else if (sdi->mode == ANALOG){ num_probes = devc->profile->dev_caps & DEV_CAPS_16BIT ? MAX_ANALOG_PROBES_NUM : 1; + devc->op_mode = SR_OP_STREAM; + devc->stream = TRUE; + devc->samplerates_size = 10; + devc->samplecounts_size = 15; } sr_dev_probes_free(sdi); set_probes(sdi, num_probes); sr_dbg("%s: setting mode to %d", __func__, sdi->mode); if (sdi->mode == DSO) { - GList *l; - for(l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - zero_info.zero_addr = (zero_base_addr + probe->index * sizeof(struct cmd_zero_info)); - if ((ret = command_rd_nvm(usb->devhdl, (unsigned char *)&zero_info, zero_info.zero_addr, sizeof(struct cmd_zero_info))) != SR_OK) { - sr_err("Send Get Zero command failed!"); - } else { - if (zero_info.zero_addr == (zero_base_addr + probe->index * sizeof(struct cmd_zero_info))) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe, SR_CONF_ZERO_SET)); - if (ret != SR_OK) { - sr_err("Set Zero command failed!"); - return ret; - } - } else { - devc->zero = TRUE; - sr_info("Zero have not been setted!"); - } - } - } - - comb_info.comb_addr = comb_base_addr; - if ((ret = command_rd_nvm(usb->devhdl, (unsigned char *)&comb_info, comb_info.comb_addr, sizeof(struct cmd_comb_info))) != SR_OK) { - sr_err("Send Get Comb Command Failed!"); - } else { - if (comb_info.comb_addr == comb_base_addr) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_COMB_SET)); - if (ret != SR_OK) { - sr_err("Set Comb command failed!"); - return ret; - } - } else { - devc->zero = TRUE; - sr_info("Comb have not been setted!"); - } - } - - 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_COUPLING)); - if (ret != SR_OK) { - sr_err("Set Coupling command failed!"); - return ret; - } - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe, SR_CONF_VDIV)); - if (ret != SR_OK) { - sr_dbg("%s: Initial setting for DSO mode failed", __func__); - return ret; - } - } - - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_SAMPLERATE)); - if (ret != SR_OK) { - sr_err("Set Sample Rate command failed!"); - return ret; - } - 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, NULL, SR_CONF_TRIGGER_HOLDOFF)); - if (ret != SR_OK) { - sr_err("Set Trigger Holdoff Time command failed!"); - return ret; - } - 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, 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, NULL, SR_CONF_TRIGGER_VALUE)); - if (ret != SR_OK) { - sr_err("Set Trigger Value command failed!"); - return ret; - } + dso_init(sdi, 0); } } else if (id == SR_CONF_OPERATION_MODE) { stropt = g_variant_get_string(data, NULL); - ret = SR_OK; if (sdi->mode == LOGIC) { if (!strcmp(stropt, opmodes[SR_OP_BUFFER]) && (devc->op_mode != SR_OP_BUFFER)) { devc->op_mode = SR_OP_BUFFER; @@ -1623,12 +1491,16 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, devc->cur_samplerate = samplerates[devc->samplerates_size-1]; devc->sample_wide = (devc->cur_samplerate <= DSLOGIC_MAX_DSO_SAMPLERATE); } + } else if (sdi->mode == ANALOG) { + devc->op_mode = SR_OP_STREAM; + devc->stream = TRUE; + devc->samplerates_size = 10; + devc->samplecounts_size = 15; } sr_dbg("%s: setting pattern to %d", __func__, devc->op_mode); } else if (id == SR_CONF_CHANNEL_MODE) { stropt = g_variant_get_string(data, NULL); - ret = SR_OK; if (sdi->mode == LOGIC) { if (devc->stream) { for (i = 0; i < ARRAY_SIZE(stream_ch_modes); i++) @@ -1656,7 +1528,6 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, __func__, devc->ch_mode); } 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])) { @@ -1671,11 +1542,11 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, /* Takes >= 10ms for the FX2 to be ready for FPGA configure. */ g_usleep(10 * 1000); char *fpga_bit; - if (!(fpga_bit = g_try_malloc(strlen(config_path)+strlen(devc->profile->fpga_bit33)+1))) { + if (!(fpga_bit = g_try_malloc(strlen(DS_RES_PATH)+strlen(devc->profile->fpga_bit33)+1))) { sr_err("fpag_bit path malloc error!"); return SR_ERR_MALLOC; } - strcpy(fpga_bit, config_path); + strcpy(fpga_bit, DS_RES_PATH); switch(devc->th_level) { case SR_TH_3V3: strcat(fpga_bit, devc->profile->fpga_bit33);; @@ -1697,16 +1568,15 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, __func__, devc->th_level); } else if (id == SR_CONF_VTH) { devc->vth = g_variant_get_double(data); - ret = command_vth(usb->devhdl, devc->vth); - if (ret == SR_OK) - sr_dbg("%s: setting threshold voltage to %d", + if ((ret = command_wr_reg(usb->devhdl, (uint8_t)(devc->vth/5.0*255), VTH_ADDR)) == SR_OK) { + sr_err("%s: setting threshold voltage to %f", __func__, devc->vth); - else - sr_dbg("%s: setting threshold voltage to %d failed", + } else { + sr_info("%s: setting threshold voltage to %f failed", __func__, devc->vth); + } } 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])) { @@ -1714,11 +1584,10 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, } else { ret = SR_ERR; } - sr_dbg("%s: setting threshold to %d", - __func__, devc->th_level); + sr_dbg("%s: setting filter to %d", + __func__, devc->filter); } else if (id == SR_CONF_MAX_HEIGHT) { stropt = g_variant_get_string(data, NULL); - ret = SR_OK; for (i = 0; i < ARRAY_SIZE(maxHeights); i++) { if (!strcmp(stropt, maxHeights[i])) { devc->max_height = i; @@ -1747,8 +1616,9 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, sr_dbg("%s: setting ENABLE of channel %d to %d", __func__, ch->index, ch->enabled); } else if (id == SR_CONF_DATALOCK) { + while(libusb_try_lock_events(drvc->sr_ctx->libusb_ctx)); devc->data_lock = g_variant_get_boolean(data); - ret = SR_OK; + libusb_unlock_events(drvc->sr_ctx->libusb_ctx); } else if (id == SR_CONF_VDIV) { ch->vdiv = g_variant_get_uint64(data); if (sdi->mode == DSO) { @@ -1762,10 +1632,14 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, __func__, ch->index, ch->vdiv); } else if (id == SR_CONF_FACTOR) { ch->vfactor = g_variant_get_uint64(data); - ret = SR_OK; + sr_dbg("%s: setting Factor of channel %d to %d", __func__, + ch->index, ch->vfactor); + } else if (id == SR_CONF_VPOS) { + ch->vpos = g_variant_get_double(data); + sr_dbg("%s: setting VPOS of channel %d to %lf", __func__, + ch->index, ch->vpos); } else if (id == SR_CONF_TIMEBASE) { devc->timebase = g_variant_get_uint64(data); - ret = SR_OK; } else if (id == SR_CONF_COUPLING) { ch->coupling = g_variant_get_byte(data); if (ch->coupling == SR_GND_COUPLING) @@ -1814,26 +1688,22 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, __func__, ch->index, ch->trig_value); } else if (id == SR_CONF_HORIZ_TRIGGERPOS) { if (sdi->mode == DSO) { - uint16_t channel_cnt = 0; - GSList *l; - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - channel_cnt += probe->enabled; - } devc->trigger_hrate = g_variant_get_byte(data); - devc->trigger_hpos = devc->trigger_hrate * channel_cnt * devc->limit_samples / 200.0; + //devc->trigger_hpos = devc->trigger_hrate * en_ch_num(sdi) * devc->limit_samples / 200.0; + /* + * devc->trigger_hpos should be updated before each acquisition + * because the samplelimits may changed + */ + devc->trigger_hpos = devc->trigger_hrate * en_ch_num(sdi) * devc->limit_samples / 200.0; + if ((ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_HORIZ_TRIGGERPOS))) == SR_OK) + sr_dbg("%s: setting DSO Horiz Trigger Position to %d", + __func__, devc->trigger_hpos); + else + sr_dbg("%s: setting DSO Horiz Trigger Position to %d failed", + __func__, devc->trigger_hpos); } else { devc->trigger_hpos = g_variant_get_byte(data) * devc->limit_samples / 100.0; } - if (sdi->mode == DSO) { - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_HORIZ_TRIGGERPOS)); - } - if (ret == SR_OK) - sr_dbg("%s: setting DSO Horiz Trigger Position to %d", - __func__, devc->trigger_hpos); - else - sr_dbg("%s: setting DSO Horiz Trigger Position to %d failed", - __func__, devc->trigger_hpos); } else if (id == SR_CONF_TRIGGER_HOLDOFF) { devc->trigger_holdoff = g_variant_get_uint64(data); if (sdi->mode == DSO) { @@ -1845,30 +1715,17 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, else sr_dbg("%s: setting Trigger Holdoff Time to %d failed", __func__, devc->trigger_holdoff); - } else if (id == SR_CONF_ZERO) { - devc->zero = g_variant_get_boolean(data); - ret = SR_OK; - } else if (id == SR_CONF_ZERO_SET) { - GSList *l; - for(l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - zero_info.zero_addr = zero_base_addr + probe->index * sizeof(struct cmd_zero_info); - zero_info.adc_off = (probe->index == 0) ? mstatus.ch0_adc_off + (mstatus.ch0_adc_sign << 7) : mstatus.ch1_adc_off + (mstatus.ch1_adc_sign << 7); - ret = command_wr_nvm(usb->devhdl, (unsigned char *)&zero_info, sizeof(struct cmd_zero_info)); - if (ret != SR_OK) - sr_err("DSO channel %d Set Zero command failed!", probe->index); + } else if (id == SR_CONF_TRIGGER_MARGIN) { + devc->trigger_margin = g_variant_get_byte(data); + if (sdi->mode == DSO) { + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_TRIGGER_MARGIN)); } - comb_info.comb_addr = comb_base_addr; - comb_info.comb0_low_off = mstatus.comb0_off; - comb_info.comb0_hig_off = mstatus.comb0_off >> 8; - comb_info.comb1_low_off = mstatus.comb1_off; - comb_info.comb1_hig_off = mstatus.comb1_off >> 8; - comb_info.comb_sign = mstatus.comb_sign; - ret = command_wr_nvm(usb->devhdl, (unsigned char *)&comb_info, sizeof(struct cmd_comb_info)); - if (ret != SR_OK) - sr_err("DSO Set Comb command failed!"); + if (ret == SR_OK) + sr_dbg("%s: setting Trigger Margin to %d", + __func__, devc->trigger_margin); else - devc->zero = FALSE; + sr_dbg("%s: setting Trigger Margin to %d failed", + __func__, devc->trigger_margin); } else if (id == SR_CONF_STREAM) { devc->stream = g_variant_get_boolean(data); } else { @@ -1932,7 +1789,7 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, 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); + samplecounts, devc->samplecounts_size*sizeof(uint64_t), TRUE, NULL, NULL); g_variant_builder_add(&gvb, "{sv}", "samplecounts", gvar); *data = g_variant_builder_end(&gvb); break; @@ -1959,63 +1816,169 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, case SR_CONF_MAX_HEIGHT: *data = g_variant_new_strv(maxHeights, ARRAY_SIZE(maxHeights)); break; - default: + default: return SR_ERR_NA; - } + } return SR_OK; } -static void abort_acquisition(struct DSL_context *devc) +static int dev_open(struct sr_dev_inst *sdi) +{ + struct sr_usb_dev_inst *usb; + struct DSL_context *devc; + GSList *l; + int ret; + int64_t timediff_us, timediff_ms; + uint8_t fpga_done; + + devc = sdi->priv; + usb = sdi->conn; + + /* + * If the firmware was recently uploaded, no dev_open operation should be called. + * Just wait for renumerate -> detach -> attach + */ + ret = SR_ERR; + if (devc->fw_updated > 0) { + return SR_ERR; + } else { + sr_info("%s: Firmware upload was not needed.", __func__); + ret = DSLogic_dev_open(sdi); + } + + if (ret != SR_OK) { + sr_err("%s: Unable to open device.", __func__); + return SR_ERR; + } + + ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE); + if (ret != 0) { + switch(ret) { + case LIBUSB_ERROR_BUSY: + sr_err("%s: Unable to claim USB interface. Another " + "program or driver has already claimed it.", __func__); + break; + case LIBUSB_ERROR_NO_DEVICE: + sr_err("%s: Device has been disconnected.", __func__); + break; + default: + sr_err("%s: Unable to claim interface: %s.", + __func__, libusb_error_name(ret)); + break; + } + + return SR_ERR; + } + + ret = command_get_fpga_done(usb->devhdl, &fpga_done); + if (ret != SR_OK) { + sr_err("Failed to get fpga done infos."); + return SR_ERR; + } + + if (fpga_done == 0) { + if ((ret = command_fpga_config(usb->devhdl)) != SR_OK) { + sr_err("%s: Send FPGA configure command failed!", __func__); + } else { + /* Takes >= 10ms for the FX2 to be ready for FPGA configure. */ + g_usleep(10 * 1000); + char *fpga_bit; + if (!(fpga_bit = g_try_malloc(strlen(DS_RES_PATH)+strlen(devc->profile->fpga_bit33)+1))) { + sr_err("fpag_bit path malloc error!"); + return SR_ERR_MALLOC; + } + strcpy(fpga_bit, DS_RES_PATH); + switch(devc->th_level) { + case SR_TH_3V3: + strcat(fpga_bit, devc->profile->fpga_bit33);; + break; + case SR_TH_5V0: + strcat(fpga_bit, devc->profile->fpga_bit50);; + break; + default: + return SR_ERR; + } + ret = fpga_config(usb->devhdl, fpga_bit); + if (ret != SR_OK) { + sr_err("%s: Configure FPGA failed!", __func__); + } + g_free(fpga_bit); + + if ((ret = command_wr_reg(usb->devhdl, (uint8_t)(devc->vth/5.0*255), VTH_ADDR)) == SR_OK) { + sr_err("%s: setting threshold voltage to %f", + __func__, devc->vth); + } else { + sr_info("%s: setting threshold voltage to %f failed", + __func__, devc->vth); + } + } + } + + return SR_OK; +} + +static int dev_close(struct sr_dev_inst *sdi) +{ + struct sr_usb_dev_inst *usb; + struct DSL_context *devc; + + usb = sdi->conn; + if (usb->devhdl == NULL) + return SR_ERR; + devc = sdi->priv; + + sr_info("DSLogic: Closing device %d on %d.%d interface %d.", + sdi->index, usb->bus, usb->address, USB_INTERFACE); + libusb_release_interface(usb->devhdl, USB_INTERFACE); + libusb_close(usb->devhdl); + usb->devhdl = NULL; + sdi->status = SR_ST_INACTIVE; + + return SR_OK; +} + +static int cleanup(void) +{ + int ret; + struct drv_context *drvc; + + if (!(drvc = di->priv)) + return SR_OK; + + ret = dev_clear(); + + g_free(drvc); + di->priv = NULL; + + return ret; +} + +static void remove_sources(struct DSL_context *devc) { int i; - int ret; - struct sr_usb_dev_inst *usb; - - devc->num_samples = -1; - - sr_info("%s: Stopping", __func__); - - /* Stop GPIF acquisition */ - usb = ((struct sr_dev_inst *)devc->cb_data)->conn; - if ((ret = command_stop_acquisition (usb->devhdl)) != SR_OK) - sr_err("Stop DSLogic acquisition failed!"); - else - sr_info("Stop DSLogic acquisition!"); - - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen((struct sr_dev_inst *)devc->cb_data, NULL, SR_CONF_ZERO_OVER)); - if (ret != SR_OK) - sr_err("DSO zero over command failed!"); - - /* Cancel exist transfers */ - if (devc->num_transfers) - for (i = devc->num_transfers - 1; i >= 0; i--) { - if (devc->transfers[i]) - libusb_cancel_transfer(devc->transfers[i]); - } + sr_err("%s: remove fds from polling", __func__); + /* Remove fds from polling. */ + for (i = 0; devc->usbfd[i] != -1; i++) + sr_source_remove(devc->usbfd[i]); + g_free(devc->usbfd); } static void finish_acquisition(struct DSL_context *devc) { struct sr_datafeed_packet packet; - int i, ret; - struct sr_usb_dev_inst *usb; - sr_err("finish acquisition: send SR_DF_END packet"); + sr_err("%s: send SR_DF_END packet", __func__); /* Terminate session. */ packet.type = SR_DF_END; sr_session_send(devc->cb_data, &packet); - - sr_err("finish acquisition: remove fds from polling"); - /* Remove fds from polling. */ - for (i = 0; devc->usbfd[i] != -1; i++) - sr_source_remove(devc->usbfd[i]); - g_free(devc->usbfd); if (devc->num_transfers != 0) { devc->num_transfers = 0; g_free(devc->transfers); } + + devc->status = DSL_FINISH; } static void free_transfer(struct libusb_transfer *transfer) @@ -2023,7 +1986,7 @@ static void free_transfer(struct libusb_transfer *transfer) struct DSL_context *devc; unsigned int i; - devc = transfer->user_data; + devc = transfer->user_data; g_free(transfer->buffer); transfer->buffer = NULL; @@ -2062,42 +2025,32 @@ static void receive_transfer(struct libusb_transfer *transfer) struct sr_datafeed_logic logic; struct sr_datafeed_dso dso; struct sr_datafeed_analog analog; - struct DSL_context *devc; - int trigger_offset, i, sample_width, cur_sample_count; - int trigger_offset_bytes; - uint8_t *cur_buf; - //GTimeVal cur_time; - //g_get_current_time(&cur_time); - //sr_info("receive_transfer: current time %d sec %d usec", cur_time.tv_sec, cur_time.tv_usec); + int trigger_offset, i; + int trigger_offset_bytes; - - devc = transfer->user_data; - - /* - * If acquisition has already ended, just free any queued up - * transfer that come in. - */ - if (devc->num_samples == -1) { - free_transfer(transfer); + const uint8_t *cur_buf = transfer->buffer; + struct DSL_context *devc = transfer->user_data; + struct sr_dev_inst *sdi = devc->cb_data; + const int sample_width = (devc->sample_wide) ? 2 : 1; + int cur_sample_count = transfer->actual_length / sample_width; + + if (devc->data_lock) { + resubmit_transfer(transfer); return; } - //sr_info("receive_transfer(): status %d; timeout %d; received %d bytes.", - // transfer->status, transfer->timeout, transfer->actual_length); + if (devc->abort) + devc->status = DSL_STOP; - /* Save incoming transfer before reusing the transfer struct. */ - cur_buf = transfer->buffer; - - sample_width = (devc->sample_wide) ? 2 : 1; - cur_sample_count = transfer->actual_length / sample_width; + sr_info("receive_transfer(): status %d; timeout %d; received %d bytes.", + transfer->status, transfer->timeout, transfer->actual_length); switch (transfer->status) { case LIBUSB_TRANSFER_NO_DEVICE: - //abort_acquisition(devc); - free_transfer(transfer); + case LIBUSB_TRANSFER_CANCELLED: devc->status = DSL_ERROR; - return; + break; case LIBUSB_TRANSFER_COMPLETED: case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */ break; @@ -2106,30 +2059,20 @@ static void receive_transfer(struct libusb_transfer *transfer) break; } - if (transfer->actual_length == 0 || - packet_has_error || - devc->data_lock) { + if (devc->status == DSL_DATA && + (transfer->actual_length == 0 || + packet_has_error)) { devc->empty_transfer_count++; if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) { - /* - * The FX2 gave up. End the acquisition, the frontend - * will work out that the samplecount is short. - */ - //abort_acquisition(devc); - free_transfer(transfer); devc->status = DSL_ERROR; - } else { - resubmit_transfer(transfer); } - return; } else { devc->empty_transfer_count = 0; } trigger_offset = 0; - if (devc->trigger_stage >= 0) { + if (devc->status == DSL_DATA && devc->trigger_stage >= 0) { for (i = 0; i < cur_sample_count; i++) { - const uint16_t cur_sample = devc->sample_wide ? *((const uint16_t*)cur_buf + i) : *((const uint8_t*)cur_buf + i); @@ -2151,7 +2094,7 @@ static void receive_transfer(struct libusb_transfer *transfer) */ packet.type = SR_DF_TRIGGER; packet.payload = NULL; - sr_session_send(devc->cb_data, &packet); + sr_session_send(sdi, &packet); /* * Send the samples that triggered it, @@ -2162,7 +2105,7 @@ static void receive_transfer(struct libusb_transfer *transfer) logic.unitsize = sizeof(*devc->trigger_buffer); logic.length = devc->trigger_stage * logic.unitsize; logic.data = devc->trigger_buffer; - sr_session_send(devc->cb_data, &packet); + sr_session_send(sdi, &packet); devc->trigger_stage = TRIGGER_FIRED; break; @@ -2184,81 +2127,70 @@ static void receive_transfer(struct libusb_transfer *transfer) } } - if (devc->trigger_stage == TRIGGER_FIRED) { + if (devc->status == DSL_DATA && devc->trigger_stage == TRIGGER_FIRED) { /* Send the incoming transfer to the session bus. */ trigger_offset_bytes = trigger_offset * sample_width; - if ((*(struct sr_dev_inst *)(devc->cb_data)).mode == LOGIC) { + // check packet type + if (sdi->mode == LOGIC) { packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = transfer->actual_length - trigger_offset_bytes; logic.unitsize = sample_width; logic.data_error = 0; logic.data = cur_buf + trigger_offset_bytes; - } else if ((*(struct sr_dev_inst *)(devc->cb_data)).mode == DSO) { - uint16_t channel_cnt = 0; - uint16_t channel_en_cnt = 0; - GSList *l; - struct sr_dev_inst *sdi = devc->cb_data; - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - channel_cnt ++; - channel_en_cnt += probe->enabled; - } - if (channel_en_cnt == 0) - channel_en_cnt = 1; - + } else if (sdi->mode == DSO) { if (!devc->instant) { - const uint32_t mstatus_offset = devc->limit_samples / (channel_cnt/channel_en_cnt); + const uint32_t mstatus_offset = devc->limit_samples / (g_slist_length(sdi->channels)/en_ch_num(sdi)); + mstatus.pkt_id = *((const uint16_t*)cur_buf + mstatus_offset); mstatus.ch0_max = *((const uint8_t*)cur_buf + mstatus_offset*2 + 1*2); mstatus.ch0_min = *((const uint8_t*)cur_buf + mstatus_offset*2 + 3); mstatus.ch0_period = *((const uint32_t*)cur_buf + mstatus_offset/2 + 2/2); - mstatus.ch0_period += *((const uint32_t*)cur_buf + mstatus_offset/2 + 4/2) << 32; + mstatus.ch0_period += ((uint64_t)*((const uint32_t*)cur_buf + mstatus_offset/2 + 4/2)) << 32; mstatus.ch0_pcnt = *((const uint32_t*)cur_buf + mstatus_offset/2 + 6/2); mstatus.ch1_max = *((const uint8_t*)cur_buf + mstatus_offset*2 + 9*2); mstatus.ch1_min = *((const uint8_t*)cur_buf + mstatus_offset*2 + 19); mstatus.ch1_period = *((const uint32_t*)cur_buf + mstatus_offset/2 + 10/2); - mstatus.ch1_period += *((const uint32_t*)cur_buf + mstatus_offset/2 + 12/2) << 32; + mstatus.ch1_period += ((uint64_t)*((const uint32_t*)cur_buf + mstatus_offset/2 + 12/2)) << 32; mstatus.ch1_pcnt = *((const uint32_t*)cur_buf + mstatus_offset/2 + 14/2); mstatus.vlen = *((const uint32_t*)cur_buf + mstatus_offset/2 + 16/2) & 0x7fffffff; mstatus.stream_mode = *((const uint32_t*)cur_buf + mstatus_offset/2 + 16/2) & 0x80000000; - mstatus.sample_divider = *((const uint32_t*)cur_buf + mstatus_offset/2 + 18/2) & 0x7fffffff; + mstatus.sample_divider = *((const uint32_t*)cur_buf + mstatus_offset/2 + 18/2) & 0x0fffffff; mstatus.sample_divider_tog = *((const uint32_t*)cur_buf + mstatus_offset/2 + 18/2) & 0x80000000; - mstatus.zeroing = (*((const uint16_t*)cur_buf + mstatus_offset + 128) & 0x8000) != 0; - mstatus.ch0_adc_off = *((const uint8_t*)cur_buf + mstatus_offset*2 + 131*2); - mstatus.ch0_adc_sign = *((const uint8_t*)cur_buf + mstatus_offset*2 + 131*2+1); - mstatus.ch1_adc_off = *((const uint8_t*)cur_buf + mstatus_offset*2 + 135*2); - mstatus.ch1_adc_sign = *((const uint8_t*)cur_buf + mstatus_offset*2 + 135*2+1); - mstatus.comb0_off = *((const uint16_t*)cur_buf + mstatus_offset + 136); - mstatus.comb1_off = *((const uint16_t*)cur_buf + mstatus_offset + 137); - mstatus.comb_sign = *((const uint8_t*)cur_buf + mstatus_offset*2 + 138*2); + mstatus.trig_flag = *((const uint32_t*)cur_buf + mstatus_offset/2 + 18/2) & 0x40000000; } else { mstatus.vlen = instant_buffer_size; } - const uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(DSLOGIC_MAX_DSO_SAMPLERATE * 1.0 / devc->cur_samplerate / channel_en_cnt); - if ((mstatus.sample_divider == divider && - mstatus.vlen != 0 && - mstatus.vlen <= (transfer->actual_length - 512) / sample_width) || + + const uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(DSCOPE_MAX_SAMPLERATE * 1.0 / devc->cur_samplerate / en_ch_num(sdi)); + if ((mstatus.pkt_id == DSO_PKTID && + mstatus.sample_divider == divider && + mstatus.vlen != 0 && + mstatus.vlen <= (transfer->actual_length - 512) / sample_width) || devc->instant) { - devc->mstatus_valid = devc->instant ? FALSE : TRUE; + devc->roll = (mstatus.stream_mode != 0); + devc->mstatus_valid = TRUE; packet.type = SR_DF_DSO; packet.payload = &dso; - dso.probes = (*(struct sr_dev_inst *)(devc->cb_data)).channels; + dso.probes = sdi->channels; //dso.num_samples = (transfer->actual_length - 512) / sample_width; - cur_sample_count = 2 * mstatus.vlen / channel_en_cnt ; + cur_sample_count = 2 * mstatus.vlen / en_ch_num(sdi) ; dso.num_samples = cur_sample_count; dso.mq = SR_MQ_VOLTAGE; dso.unit = SR_UNIT_VOLT; dso.mqflags = SR_MQFLAG_AC; - dso.samplerate_tog = mstatus.sample_divider_tog; + dso.samplerate_tog = (mstatus.sample_divider_tog != 0); + dso.trig_flag = (mstatus.trig_flag != 0); dso.data = cur_buf + trigger_offset_bytes; } else { + packet.type = SR_DF_ABANDON; devc->mstatus_valid = FALSE; } } else { packet.type = SR_DF_ANALOG; packet.payload = &analog; - analog.probes = (*(struct sr_dev_inst *)(devc->cb_data)).channels; - analog.num_samples = (transfer->actual_length / sample_width)/g_slist_length(analog.probes); + analog.probes = sdi->channels; + cur_sample_count = transfer->actual_length / (sample_width * g_slist_length(analog.probes)); + analog.num_samples = cur_sample_count; analog.mq = SR_MQ_VOLTAGE; analog.unit = SR_UNIT_VOLT; analog.mqflags = SR_MQFLAG_AC; @@ -2308,26 +2240,22 @@ static void receive_transfer(struct libusb_transfer *transfer) } /* send data to session bus */ - sr_session_send(devc->cb_data, &packet); + if (packet.type != SR_DF_ABANDON) + sr_session_send(sdi, &packet); } devc->num_samples += cur_sample_count; - if (((*(struct sr_dev_inst *)(devc->cb_data)).mode == LOGIC || devc->instant) && + if ((sdi->mode != DSO || devc->instant) && devc->limit_samples && (unsigned int)devc->num_samples >= devc->actual_samples) { - //abort_acquisition(devc); - free_transfer(transfer); devc->status = DSL_STOP; - return; } - } else { - /* - * TODO: Buffer pre-trigger data in capture - * ratio-sized buffer. - */ } - resubmit_transfer(transfer); + if (devc->status == DSL_DATA) + resubmit_transfer(transfer); + else + free_transfer(transfer); } static unsigned int to_bytes_per_ms(struct DSL_context *devc) @@ -2335,7 +2263,7 @@ static unsigned int to_bytes_per_ms(struct DSL_context *devc) if (devc->cur_samplerate > SR_MHZ(100)) return SR_MHZ(100) / 1000 * (devc->sample_wide ? 2 : 1); else - return devc->cur_samplerate / 1000 * (devc->sample_wide ? 2 : 1); + return devc->cur_samplerate / 1000 * (devc->sample_wide ? 2 : 1) ; } static size_t get_buffer_size(struct DSL_context *devc) @@ -2379,7 +2307,7 @@ static int dev_transfer_start(const struct sr_dev_inst *sdi) struct DSL_context *devc; struct sr_usb_dev_inst *usb; struct libusb_transfer *transfer; - unsigned int i, timeout, num_transfers; + unsigned int i, num_transfers; int ret; unsigned char *buf; size_t size; @@ -2388,34 +2316,26 @@ static int dev_transfer_start(const struct sr_dev_inst *sdi) devc = sdi->priv; usb = sdi->conn; - uint16_t channel_en_cnt = 0; - uint16_t channel_cnt = 0; - GSList *l; - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - channel_en_cnt += probe->enabled; - channel_cnt++; - } if (devc->instant) - dso_buffer_size = instant_buffer_size * channel_cnt; + dso_buffer_size = instant_buffer_size * g_slist_length(sdi->channels); else - dso_buffer_size = devc->limit_samples * channel_en_cnt + 512; + dso_buffer_size = devc->limit_samples * en_ch_num(sdi) + 512; num_transfers = 1; - size = (sdi->mode == ANALOG) ? cons_buffer_size : ((sdi->mode == DSO) ? dso_buffer_size : get_buffer_size(devc)); + size = (sdi->mode == DSO) ? dso_buffer_size : + (devc->op_mode == SR_OP_STREAM) ? get_buffer_size(devc) : instant_buffer_size; devc->submitted_transfers = 0; devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers); if (!devc->transfers) { - sr_err("USB transfers malloc failed."); + sr_err("%s: USB transfers malloc failed.", __func__); return SR_ERR_MALLOC; } - devc->num_transfers = num_transfers; for (i = 0; i < num_transfers; i++) { if (!(buf = g_try_malloc(size))) { - sr_err("USB transfer buffer malloc failed."); + sr_err("%s: USB transfer buffer malloc failed.", __func__); return SR_ERR_MALLOC; } transfer = libusb_alloc_transfer(0); @@ -2423,15 +2343,17 @@ static int dev_transfer_start(const struct sr_dev_inst *sdi) 6 | LIBUSB_ENDPOINT_IN, buf, size, receive_transfer, devc, 0); if ((ret = libusb_submit_transfer(transfer)) != 0) { - sr_err("Failed to submit transfer: %s.", - libusb_error_name(ret)); + sr_err("%s: Failed to submit transfer: %s.", + __func__, libusb_error_name(ret)); libusb_free_transfer(transfer); g_free(buf); - abort_acquisition(devc); + devc->status = DSL_ERROR; + devc->abort = TRUE; return SR_ERR; } devc->transfers[i] = transfer; devc->submitted_transfers++; + devc->num_transfers++; } devc->status = DSL_DATA; @@ -2439,28 +2361,43 @@ static int dev_transfer_start(const struct sr_dev_inst *sdi) return SR_OK; } + static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) { int completed = 0; struct timeval tv; struct drv_context *drvc; struct DSL_context *devc; + struct sr_usb_dev_inst *usb; + int i; + int ret; (void)fd; (void)revents; drvc = di->priv; devc = sdi->priv; - - if (devc->num_samples != -1 && - (devc->status == DSL_STOP || devc->status == DSL_ERROR)) { - sr_info("%s: Stopping", __func__); - abort_acquisition(devc); - } + usb = sdi->conn; tv.tv_sec = tv.tv_usec = 0; libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv, &completed); + if (devc->status == DSL_FINISH) { + if (libusb_try_lock_events(drvc->sr_ctx->libusb_ctx) == 0) { + if (libusb_event_handling_ok(drvc->sr_ctx->libusb_ctx)) { + /* Stop GPIF acquisition */ + usb = ((struct sr_dev_inst *)devc->cb_data)->conn; + if ((ret = command_stop_acquisition (usb->devhdl)) != SR_OK) + sr_err("%s: Sent acquisition stop command failed!", __func__); + else + sr_info("%s: Sent acquisition stop command!", __func__); + + remove_sources(devc); + } + libusb_unlock_events(drvc->sr_ctx->libusb_ctx); + } + } + return TRUE; } @@ -2468,75 +2405,43 @@ static void receive_trigger_pos(struct libusb_transfer *transfer) { struct DSL_context *devc; struct sr_datafeed_packet packet; - struct sr_datafeed_logic logic; - struct sr_datafeed_dso dso; - struct sr_datafeed_analog analog; struct ds_trigger_pos *trigger_pos; + const struct sr_dev_inst *sdi; int ret; devc = transfer->user_data; - sr_info("receive_trigger_pos(): status %d; timeout %d; received %d bytes.", - transfer->status, transfer->timeout, transfer->actual_length); - - if (devc->num_samples == -1) { - free_transfer(transfer); - return; - } - + sdi = devc->cb_data; trigger_pos = (struct ds_trigger_pos *)transfer->buffer; - switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: + devc->status = DSL_ERROR; + if (transfer->status == LIBUSB_TRANSFER_COMPLETED && + trigger_pos->check_id == TRIG_CHECKID) { + sr_info("receive_trigger_pos(): status %d; timeout %d; received %d bytes.", + transfer->status, transfer->timeout, transfer->actual_length); if (transfer->actual_length == sizeof(struct ds_trigger_pos)) { - if (devc->stream || trigger_pos->remain_cnt < devc->limit_samples) { - if (!devc->stream) + if (sdi->mode != LOGIC || devc->stream || trigger_pos->remain_cnt < devc->limit_samples) { + if (sdi->mode == LOGIC && !devc->stream) devc->actual_samples = (devc->limit_samples - ceil(devc->cur_samplerate * 1.0 / DSLOGIC_MAX_LOGIC_SAMPLERATE) * (trigger_pos->remain_cnt)); - packet.type = SR_DF_TRIGGER; packet.payload = trigger_pos; - sr_session_send(devc->cb_data, &packet); + sr_session_send(sdi, &packet); devc->status = DSL_TRIGGERED; - free_transfer(transfer); devc->num_transfers = 0; devc->empty_transfer_count = 0; - } else { - free_transfer(transfer); - devc->status = DSL_ERROR; } - } else { - free_transfer(transfer); - devc->status = DSL_ERROR; } - break; - case LIBUSB_TRANSFER_TIMED_OUT: - devc->empty_transfer_count++; - if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) { - /* - * The FX2 gave up. End the acquisition, the frontend - * will work out that the samplecount is short. - */ - //abort_acquisition(devc); - free_transfer(transfer); - devc->status = DSL_ERROR; - } else { - resubmit_transfer(transfer); - } - break; - case LIBUSB_TRANSFER_CANCELLED: - resubmit_transfer(transfer); - break; - default: - //abort_acquisition(devc); - free_transfer(transfer); - devc->status = DSL_ERROR; - break; } if (devc->status == DSL_TRIGGERED) { + // successfull + free_transfer(transfer); if ((ret = dev_transfer_start(devc->cb_data)) != SR_OK) { sr_err("%s: could not start data transfer" "(%d)%d", __func__, ret, errno); } + } else { + // failed + free_transfer(transfer); } } @@ -2571,57 +2476,71 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) devc->num_transfers = 0; devc->submitted_transfers = 0; devc->actual_samples = devc->limit_samples; + test_sample_value = 0; + devc->abort = FALSE; /* Configures devc->trigger_* and devc->sample_wide */ if (configure_probes(sdi) != SR_OK) { - sr_err("Failed to configure probes."); + sr_err("%s: Failed to configure probes.", __func__); return SR_ERR; } /* Stop Previous GPIF acquisition */ if ((ret = command_stop_acquisition (usb->devhdl)) != SR_OK) { - sr_err("Stop DSLogic acquisition failed!"); - abort_acquisition(devc); + sr_err("%s: Stop DSLogic acquisition failed!", __func__); return ret; } else { - sr_info("Stop Previous DSLogic acquisition!"); + sr_info("%s: Stop Previous DSLogic acquisition!", __func__); } /* Setting FPGA before acquisition start*/ if ((ret = command_fpga_setting(usb->devhdl, sizeof(struct DSL_setting) / sizeof(uint16_t))) != SR_OK) { - sr_err("Send FPGA setting command failed!"); + sr_err("%s: Send FPGA setting command failed!", __func__); } else { if ((ret = fpga_setting(sdi)) != SR_OK) { - sr_err("Configure FPGA failed!"); - abort_acquisition(devc); + sr_err("%s: Configure FPGA failed!", __func__); return ret; } } + /* + * settings must be updated before acquisition + */ if (sdi->mode == DSO) { - GList *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_COUPLING)); - if (ret != SR_OK) { - sr_err("Set Coupling command failed!"); - return ret; - } - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, probe, SR_CONF_VDIV)); - if (ret != SR_OK) { - sr_dbg("%s: Initial setting for DSO mode failed", __func__); - return ret; - } - } + devc->trigger_hpos = devc->trigger_hrate * en_ch_num(sdi) * devc->limit_samples / 200.0; + if ((ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_HORIZ_TRIGGERPOS))) == SR_OK) + sr_dbg("%s: setting DSO Horiz Trigger Position to %d", + __func__, devc->trigger_hpos); + else + sr_dbg("%s: setting DSO Horiz Trigger Position to %d failed", + __func__, devc->trigger_hpos); } - if ((ret = command_start_acquisition (usb->devhdl, - devc->cur_samplerate, 1, (sdi->mode == LOGIC))) != SR_OK) { - abort_acquisition(devc); - return ret; + /* poll trigger status transfer*/ + if (!(trigger_pos = g_try_malloc0(sizeof(struct ds_trigger_pos)))) { + sr_err("%s: USB trigger_pos buffer malloc failed.", __func__); + return SR_ERR_MALLOC; + } + devc->transfers = g_try_malloc0(sizeof(*devc->transfers)); + if (!devc->transfers) { + sr_err("%s: USB trigger_pos transfer malloc failed.", __func__); + return SR_ERR_MALLOC; + } + transfer = libusb_alloc_transfer(0); + libusb_fill_bulk_transfer(transfer, usb->devhdl, + 6 | LIBUSB_ENDPOINT_IN, trigger_pos, sizeof(struct ds_trigger_pos), + receive_trigger_pos, devc, 0); + if ((ret = libusb_submit_transfer(transfer)) != 0) { + sr_err("%s: Failed to submit trigger_pos transfer: %s.", + __func__, libusb_error_name(ret)); + libusb_free_transfer(transfer); + g_free(trigger_pos); + return SR_ERR; + } else { + devc->num_transfers++; + devc->transfers[0] = transfer; + devc->submitted_transfers++; } - - test_sample_value = 0; /* setup callback function for data transfer */ lupfd = libusb_get_pollfds(drvc->sr_ctx->libusb_ctx); @@ -2630,40 +2549,21 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) return SR_ERR; for (i = 0; lupfd[i]; i++) { sr_source_add(lupfd[i]->fd, lupfd[i]->events, - get_timeout(devc), receive_data, sdi); - devc->usbfd[i] = lupfd[i]->fd; + get_timeout(devc), receive_data, sdi); + devc->usbfd[i] = lupfd[i]->fd; } devc->usbfd[i] = -1; free(lupfd); - - /* poll trigger status transfer*/ - if (!(trigger_pos = g_try_malloc0(sizeof(struct ds_trigger_pos)))) { - sr_err("USB trigger_pos buffer malloc failed."); - return SR_ERR_MALLOC; - } - devc->transfers = g_try_malloc0(sizeof(*devc->transfers)); - if (!devc->transfers) { - sr_err("USB trigger_pos transfer malloc failed."); - return SR_ERR_MALLOC; - } - devc->num_transfers = 1; - transfer = libusb_alloc_transfer(0); - libusb_fill_bulk_transfer(transfer, usb->devhdl, - 6 | LIBUSB_ENDPOINT_IN, trigger_pos, sizeof(struct ds_trigger_pos), - receive_trigger_pos, devc, 0); - if ((ret = libusb_submit_transfer(transfer)) != 0) { - sr_err("Failed to submit trigger_pos transfer: %s.", - libusb_error_name(ret)); - libusb_free_transfer(transfer); - g_free(trigger_pos); - abort_acquisition(devc); - return SR_ERR; - } - devc->transfers[0] = transfer; - devc->submitted_transfers++; devc->status = DSL_START; devc->mstatus_valid = FALSE; + if ((ret = command_start_acquisition (usb->devhdl, + devc->cur_samplerate, devc->sample_wide, (sdi->mode == LOGIC))) != SR_OK) { + devc->status = DSL_ERROR; + devc->abort = TRUE; + return ret; + } + /* Send header packet to the session bus. */ //std_session_send_df_header(cb_data, LOG_PREFIX); std_session_send_df_header(sdi, LOG_PREFIX); @@ -2676,12 +2576,15 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) (void)cb_data; struct DSL_context *devc; + struct sr_usb_dev_inst *usb; devc = sdi->priv; - devc->status = DSL_STOP; + usb = sdi->conn; - sr_info("%s: Stopping", __func__); - //abort_acquisition(sdi->priv); + if (!devc->abort) { + devc->abort = TRUE; + command_wr_reg(usb->devhdl, 3, EEWP_ADDR); + } return SR_OK; } @@ -2706,30 +2609,22 @@ static int dev_test(struct sr_dev_inst *sdi) static int dev_status_get(struct sr_dev_inst *sdi, struct sr_status *status, int begin, int end) { + int ret = SR_ERR; if (sdi) { - struct sr_usb_dev_inst *usb; - int ret = SR_ERR; struct DSL_context *devc; + struct sr_usb_dev_inst *usb; devc = sdi->priv; usb = sdi->conn; - if (sdi->mode == DSO) { - if (devc->mstatus_valid) { - *status = mstatus; - if (devc->zero) - return SR_ERR; - else - return SR_OK; - } - } else { - if (devc->status == DSL_START) - ret = command_get_status(usb->devhdl, (unsigned char*)status, begin, end); + if (devc->status == DSL_START) { + ret = command_get_status(usb->devhdl, (unsigned char*)status, begin, end); + } else if (devc->mstatus_valid) { + *status = mstatus; + ret = SR_OK; } - - return ret; - } else { - return SR_ERR; } + + return ret; } SR_PRIV struct sr_dev_driver DSLogic_driver_info = { diff --git a/libsigrok4DSL/hardware/demo/demo.c b/libsigrok4DSL/hardware/demo/demo.c index a31467a5..03e8d2cf 100644 --- a/libsigrok4DSL/hardware/demo/demo.c +++ b/libsigrok4DSL/hardware/demo/demo.c @@ -48,7 +48,8 @@ /* The size of chunks to send through the session bus. */ /* TODO: Should be configurable. */ -#define BUFSIZE 1024*1024 +#define BUFSIZE 512*1024 +#define DSO_BUFSIZE 10*1024 #define PERIOD 4000 @@ -99,6 +100,7 @@ struct dev_context { GIOChannel *channel; uint64_t cur_samplerate; uint64_t limit_samples; + uint64_t limit_samples_show; uint64_t limit_msec; uint8_t sample_generator; uint64_t samples_counter; @@ -109,6 +111,7 @@ struct dev_context { gboolean instant; gboolean data_lock; uint8_t max_height; + uint8_t dso_bits; uint16_t *buf; uint64_t pre_index; @@ -118,6 +121,8 @@ struct dev_context { uint16_t trigger_mask; uint16_t trigger_value; uint16_t trigger_edge; + uint8_t trigger_slope; + uint8_t trigger_source; }; static const int hwcaps[] = { @@ -141,7 +146,7 @@ static const int32_t sessions[] = { SR_CONF_PATTERN_MODE, }; -static const int const_dc = 50; +static const int const_dc = 1.95 / 10 * 255; static const int sinx[] = { 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 18, 20, 21, 23, 24, 26, 27, 28, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40, 41, 41, 42, 43, 44, 45, 45, 46, 47, 47, @@ -247,6 +252,9 @@ static const uint64_t samplerates[] = { // SR_MB(4), // SR_MB(8), // SR_MB(16), +// SR_MB(32), +// SR_MB(64), +// SR_MB(128), //}; static const uint64_t samplecounts[] = { @@ -270,11 +278,24 @@ static const uint64_t samplecounts[] = { /* We name the probes 0-7 on our demo driver. */ static const char *probe_names[NUM_PROBES + 1] = { - "Channel 0", "Channel 1", "Channel 2", "Channel 3", - "Channel 4", "Channel 5", "Channel 6", "Channel 7", - "Channel 8", "Channel 9", "Channel 10", "Channel 11", - "Channel 12", "Channel 13", "Channel 14", "Channel 15", + "CH0", "CH1", "CH2", "CH3", + "CH4", "CH5", "CH6", "CH7", + "CH8", "CH9", "CH10", "CH11", + "CH12", "CH13", "CH14", "CH15", NULL, + +}; + +static const gboolean default_ms_en[DSO_MS_END - DSO_MS_BEGIN] = { + FALSE, /* DSO_MS_BEGIN */ + TRUE, /* DSO_MS_FREQ */ + FALSE, /* DSO_MS_PERD */ + TRUE, /* DSO_MS_VMAX */ + TRUE, /* DSO_MS_VMIN */ + FALSE, /* DSO_MS_VRMS */ + FALSE, /* DSO_MS_VMEA */ + FALSE, /* DSO_MS_VP2P */ + FALSE, /* DSO_MS_END */ }; /* Private, per-device-instance driver context. */ @@ -315,7 +336,7 @@ static GSList *hw_scan(GSList *options) devices = NULL; - sdi = sr_dev_inst_new(LOGIC, 0, SR_ST_ACTIVE, DEMONAME, NULL, NULL); + sdi = sr_dev_inst_new(LOGIC, 0, SR_ST_INITIALIZING, DEMONAME, NULL, NULL); if (!sdi) { sr_err("Device instance creation failed."); return NULL; @@ -333,11 +354,13 @@ static GSList *hw_scan(GSList *options) devc->sdi = sdi; devc->cur_samplerate = SR_MHZ(1); devc->limit_samples = SR_MB(1); + devc->limit_samples_show = devc->limit_samples; devc->limit_msec = 0; devc->sample_generator = PATTERN_SINE; - devc->timebase = 200; + devc->timebase = 500; devc->data_lock = FALSE; - devc->max_height = 1; + devc->max_height = 0; + devc->dso_bits = 8; sdi->priv = devc; @@ -387,20 +410,39 @@ static GSList *hw_dev_mode_list(const struct sr_dev_inst *sdi) static int hw_dev_open(struct sr_dev_inst *sdi) { - (void)sdi; + //(void)sdi; + struct dev_context *const devc = sdi->priv; - sdi->status = SR_ST_ACTIVE; + sdi->status = SR_ST_ACTIVE; + + if (pipe(devc->pipe_fds)) { + /* TODO: Better error message. */ + sr_err("%s: pipe() failed", __func__); + return SR_ERR; + } + devc->channel = g_io_channel_unix_new(devc->pipe_fds[0]); + g_io_channel_set_flags(devc->channel, G_IO_FLAG_NONBLOCK, NULL); + /* Set channel encoding to binary (default is UTF-8). */ + g_io_channel_set_encoding(devc->channel, NULL, NULL); + /* Make channels to unbuffered. */ + g_io_channel_set_buffered(devc->channel, FALSE); return SR_OK; } static int hw_dev_close(struct sr_dev_inst *sdi) { - (void)sdi; + //(void)sdi; + struct dev_context *const devc = sdi->priv; + if (sdi->status == SR_ST_ACTIVE && devc->channel) { + g_io_channel_shutdown(devc->channel, FALSE, NULL); + g_io_channel_unref(devc->channel); + devc->channel = NULL; + } sdi->status = SR_ST_INACTIVE; - return SR_OK; + return SR_OK; } static int hw_cleanup(void) @@ -429,6 +471,20 @@ static int hw_cleanup(void) return ret; } +static int en_ch_num(const struct sr_dev_inst *sdi) +{ + GSList *l; + int channel_en_cnt = 0; + + for (l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + channel_en_cnt += probe->enabled; + } + channel_en_cnt += (channel_en_cnt == 0); + + return channel_en_cnt; +} + 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) @@ -442,7 +498,7 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, *data = g_variant_new_uint64(devc->cur_samplerate); break; case SR_CONF_LIMIT_SAMPLES: - *data = g_variant_new_uint64(devc->limit_samples); + *data = g_variant_new_uint64(devc->limit_samples_show); break; case SR_CONF_LIMIT_MSEC: *data = g_variant_new_uint64(devc->limit_msec); @@ -480,6 +536,9 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, case SR_CONF_COUPLING: *data = g_variant_new_byte(ch->coupling); break; + case SR_CONF_TRIGGER_VALUE: + *data = g_variant_new_byte(ch->trig_value); + break; case SR_CONF_EN_CH: *data = g_variant_new_uint64(ch->enabled); break; @@ -501,6 +560,9 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, case SR_CONF_RLE_SAMPLELIMITS: *data = g_variant_new_uint64(DEMO_MAX_LOGIC_DEPTH); break; + case SR_CONF_DSO_BITS: + *data = g_variant_new_byte(devc->dso_bits); + break; default: return SR_ERR_NA; } @@ -512,7 +574,7 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, struct sr_channel *ch, const struct sr_channel_group *cg) { - uint16_t i; + uint16_t i, j; int ret; const char *stropt; struct sr_channel *probe; @@ -533,14 +595,19 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, devc->cur_samplerate); ret = SR_OK; } else if (id == SR_CONF_LIMIT_SAMPLES) { - devc->limit_msec = 0; - devc->limit_samples = g_variant_get_uint64(data); + devc->limit_msec = 0; + devc->limit_samples = g_variant_get_uint64(data); + devc->limit_samples_show = devc->limit_samples; + if (sdi->mode == DSO && en_ch_num(sdi) == 1) { + devc->limit_samples /= 2; + } sr_dbg("%s: setting limit_samples to %" PRIu64, __func__, devc->limit_samples); ret = SR_OK; } else if (id == SR_CONF_LIMIT_MSEC) { devc->limit_msec = g_variant_get_uint64(data); devc->limit_samples = 0; + devc->limit_samples_show = devc->limit_samples; sr_dbg("%s: setting limit_msec to %" PRIu64, __func__, devc->limit_msec); ret = SR_OK; @@ -556,6 +623,9 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, else sdi->channels = g_slist_append(sdi->channels, probe); } + devc->cur_samplerate = SR_MHZ(1); + devc->limit_samples = SR_MB(1); + devc->limit_samples_show = devc->limit_samples; } else if (sdi->mode == DSO) { sr_dev_probes_free(sdi); for (i = 0; i < DEMO_MAX_DSO_PROBES_NUM; i++) { @@ -569,10 +639,14 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, probe->trig_value = 0x80; probe->vpos = (probe->index == 0 ? 0.5 : -0.5)*probe->vdiv; sdi->channels = g_slist_append(sdi->channels, probe); + probe->ms_show = TRUE; + for (j = DSO_MS_BEGIN; j < DSO_MS_END; j++) + probe->ms_en[j] = default_ms_en[j]; } } devc->cur_samplerate = DEMO_MAX_DSO_SAMPLERATE / DEMO_MAX_DSO_PROBES_NUM; devc->limit_samples = DEMO_MAX_DSO_DEPTH / DEMO_MAX_DSO_PROBES_NUM; + devc->limit_samples_show = devc->limit_samples; } else if (sdi->mode == ANALOG) { sr_dev_probes_free(sdi); for (i = 0; i < DS_MAX_ANALOG_PROBES_NUM; i++) { @@ -584,6 +658,7 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, } devc->cur_samplerate = SR_HZ(100); devc->limit_samples = SR_KB(1); + devc->limit_samples_show = devc->limit_samples; } else { ret = SR_ERR; } @@ -626,6 +701,8 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, ret = SR_OK; } else if (id == SR_CONF_TRIGGER_HOLDOFF) { ret = SR_OK; + } else if (id == SR_CONF_TRIGGER_MARGIN) { + ret = SR_OK; } 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__, @@ -649,7 +726,7 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, ch->index, ch->vfactor); ret = SR_OK; } else if (id == SR_CONF_VPOS) { - ch->vpos = g_variant_get_double(data); + //ch->vpos = g_variant_get_double(data); sr_dbg("%s: setting VPOS of channel %d to %lf", __func__, ch->index, ch->vpos); ret = SR_OK; @@ -663,6 +740,21 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, sr_dbg("%s: setting AC COUPLING of channel %d to %d", __func__, ch->index, ch->coupling); ret = SR_OK; + } else if (id == SR_CONF_TRIGGER_SOURCE) { + devc->trigger_source = g_variant_get_byte(data); + sr_dbg("%s: setting Trigger Source to %d", + __func__, devc->trigger_source); + ret = SR_OK; + } else if (id == SR_CONF_TRIGGER_SLOPE) { + devc->trigger_slope = g_variant_get_byte(data); + sr_dbg("%s: setting Trigger Slope to %d", + __func__, devc->trigger_slope); + ret = SR_OK; + } else if (id == SR_CONF_TRIGGER_VALUE) { + ch->trig_value = g_variant_get_byte(data); + sr_dbg("%s: setting channel %d Trigger Value to %d", + __func__, ch->index, ch->trig_value); + ret = SR_OK; } else { ret = SR_ERR_NA; } @@ -766,7 +858,7 @@ static void samples_generator(uint16_t *buf, uint64_t size, } else if (sdi->mode != DSO) { start_rand = rand()%len; for (i = 0; i < size; i++) { - index = (i/g_slist_length(sdi->channels)+start_rand)%len; + index = (i/10/g_slist_length(sdi->channels)+start_rand)%len; *(buf + i) = (uint16_t)(((const_dc+pre_buf[index]) << 8) + (const_dc+pre_buf[index])); } } else { @@ -784,7 +876,8 @@ static void samples_generator(uint16_t *buf, uint64_t size, for (l = sdi->channels; l; l = l->next) { start_rand = devc->pre_index == 0 ? rand()%len : 0; probe = (struct sr_channel *)l->data; - offset = ceil((0.5 - (probe->vpos/probe->vdiv/10.0)) * 255); + //offset = ceil((0.5 - (probe->vpos/probe->vdiv/10.0)) * 255); + offset = 128; pre0_i = devc->pre_index; pre1_i = devc->pre_index; for (i = devc->pre_index; i < devc->pre_index + size; i++) { @@ -839,7 +932,7 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) struct sr_datafeed_logic logic; struct sr_datafeed_dso dso; struct sr_datafeed_analog analog; - static uint64_t samples_to_send, expected_samplenum, sending_now; + static uint64_t samples_to_send = 0, expected_samplenum, sending_now; int64_t time, elapsed; static uint16_t last_sample = 0; uint16_t cur_sample; @@ -856,19 +949,22 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) /* Of those, how many do we still have to send? */ //samples_to_send = (expected_samplenum - devc->samples_counter) / CONST_LEN * CONST_LEN; //samples_to_send = expected_samplenum / CONST_LEN * CONST_LEN; - samples_to_send = ceil(elapsed / 1000000.0 * devc->cur_samplerate); + samples_to_send += ceil(elapsed / 1000000.0 * devc->cur_samplerate); if (devc->limit_samples) { - if ((sdi->mode == DSO && !devc->instant) || sdi->mode == ANALOG) + if (sdi->mode == DSO && !devc->instant) samples_to_send = MIN(samples_to_send, devc->limit_samples - devc->pre_index); + else if (sdi->mode == ANALOG) + samples_to_send = MIN(samples_to_send * g_slist_length(sdi->channels), + devc->limit_samples - devc->pre_index); else samples_to_send = MIN(samples_to_send, devc->limit_samples - devc->samples_counter); } - while (samples_to_send > 0) { - sending_now = MIN(samples_to_send, BUFSIZE); + if (samples_to_send > 0 && !devc->stop) { + sending_now = MIN(samples_to_send, (sdi->mode == DSO ) ? DSO_BUFSIZE : BUFSIZE); samples_generator(devc->buf, sending_now, sdi, devc); if (devc->trigger_stage != 0) { @@ -926,6 +1022,8 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) dso.num_samples = sending_now; else dso.num_samples = devc->samples_counter; + if (en_ch_num(sdi) == 1) + dso.num_samples *= 2; dso.mq = SR_MQ_VOLTAGE; dso.unit = SR_UNIT_VOLT; dso.mqflags = SR_MQFLAG_AC; @@ -943,8 +1041,7 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) if (sdi->mode == DSO && !devc->instant) { devc->pre_index += sending_now; - if (sdi->mode == DSO && !devc->instant && - devc->pre_index >= devc->limit_samples) + if (devc->pre_index >= devc->limit_samples) devc->pre_index = 0; } @@ -955,12 +1052,10 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) devc->mstatus.captured_cnt1 = devc->samples_counter >> 8; devc->mstatus.captured_cnt2 = devc->samples_counter >> 16; devc->mstatus.captured_cnt3 = devc->samples_counter >> 32; - } else { - break; } } - if ((sdi->mode == LOGIC || devc->instant) && devc->limit_samples && + if ((sdi->mode != DSO || devc->instant) && devc->limit_samples && devc->samples_counter >= devc->limit_samples) { sr_info("Requested number of samples reached."); hw_dev_acquisition_stop(sdi, NULL); @@ -1011,30 +1106,15 @@ static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi, * They are kept here because it provides a convenient way of setting * up a timeout-based polling mechanism. */ - if (pipe(devc->pipe_fds)) { - /* TODO: Better error message. */ - sr_err("%s: pipe() failed", __func__); - return SR_ERR; - } - - devc->channel = g_io_channel_unix_new(devc->pipe_fds[0]); - - g_io_channel_set_flags(devc->channel, G_IO_FLAG_NONBLOCK, NULL); - - /* Set channel encoding to binary (default is UTF-8). */ - g_io_channel_set_encoding(devc->channel, NULL, NULL); - - /* Make channels to unbuffered. */ - g_io_channel_set_buffered(devc->channel, FALSE); sr_session_source_add_channel(devc->channel, G_IO_IN | G_IO_ERR, - 100, receive_data, sdi); + (sdi->mode == DSO) ? 50 : 10, receive_data, sdi); /* Send header packet to the session bus. */ //std_session_send_df_header(cb_data, LOG_PREFIX); std_session_send_df_header(sdi, LOG_PREFIX); - if (!(devc->buf = g_try_malloc(BUFSIZE*sizeof(uint16_t)))) { + if (!(devc->buf = g_try_malloc(((sdi->mode == DSO ) ? DSO_BUFSIZE : BUFSIZE)*sizeof(uint16_t)))) { sr_err("buf for receive_data malloc failed."); return FALSE; } @@ -1047,18 +1127,18 @@ static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi, static int hw_dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { - struct dev_context *const devc = sdi->priv; - struct sr_datafeed_packet packet; + (void)cb_data; - (void)cb_data; + struct dev_context *const devc = sdi->priv; + struct sr_datafeed_packet packet; + if (devc->stop) + return SR_OK; - sr_dbg("Stopping aquisition."); + sr_dbg("Stopping acquisition."); devc->stop = TRUE; + sr_session_source_remove_channel(devc->channel); - g_io_channel_shutdown(devc->channel, FALSE, NULL); - g_io_channel_unref(devc->channel); - devc->channel = NULL; g_free(devc->buf); diff --git a/libsigrok4DSL/hwdriver.c b/libsigrok4DSL/hwdriver.c index 4e437dfd..15f3eb4f 100644 --- a/libsigrok4DSL/hwdriver.c +++ b/libsigrok4DSL/hwdriver.c @@ -49,7 +49,6 @@ * * @{ */ - static struct sr_config_info sr_config_info_data[] = { {SR_CONF_CONN, SR_T_CHAR, "conn", "Connection", "Connection", NULL}, @@ -77,10 +76,14 @@ static struct sr_config_info sr_config_info_data[] = { "Trigger slope", "Trigger slope", NULL}, {SR_CONF_TRIGGER_SOURCE, SR_T_UINT8, "triggersource", "Trigger source", "Trigger source", NULL}, + {SR_CONF_TRIGGER_CHANNEL, SR_T_UINT8, "triggerchannel", + "Trigger channel", "Trigger channel", NULL}, {SR_CONF_HORIZ_TRIGGERPOS, SR_T_UINT8, "horiz_triggerpos", "Horizontal trigger position", "Horizontal trigger position", NULL}, {SR_CONF_TRIGGER_HOLDOFF, SR_T_UINT64, "triggerholdoff", "Trigger hold off", "Trigger hold off", NULL}, + {SR_CONF_TRIGGER_MARGIN, SR_T_UINT8, "triggermargin", + "Trigger margin", "Trigger margin", NULL}, {SR_CONF_BUFFERSIZE, SR_T_UINT64, "buffersize", "Buffer size", "Buffer size", NULL}, {SR_CONF_TIMEBASE, SR_T_UINT64, "timebase", diff --git a/libsigrok4DSL/libsigrok.h b/libsigrok4DSL/libsigrok.h index e55adbb0..c40428bb 100644 --- a/libsigrok4DSL/libsigrok.h +++ b/libsigrok4DSL/libsigrok.h @@ -111,6 +111,8 @@ enum { #define DS_CONF_DSO_HDIVS 10 #define DS_CONF_DSO_VDIVS 10 +#define DS_RES_PATH "/usr/local/share/DSView/res/" + /** libsigrok loglevels. */ enum { SR_LOG_NONE = 0, /**< Output no messages at all. */ @@ -286,6 +288,18 @@ enum { SR_MQFLAG_SPL_PCT_OVER_ALARM = 0x10000, }; +enum DSO_MEASURE_TYPE { + DSO_MS_BEGIN = 0, + DSO_MS_FREQ, + DSO_MS_PERD, + DSO_MS_VMAX, + DSO_MS_VMIN, + DSO_MS_VRMS, + DSO_MS_VMEA, + DSO_MS_VP2P, + DSO_MS_END, +}; + struct sr_context; struct sr_datafeed_packet { @@ -325,6 +339,8 @@ struct sr_datafeed_dso { uint64_t mqflags; /** samplerate different from last packet */ gboolean samplerate_tog; + /** trig flag */ + gboolean trig_flag; /** The analog value(s). The data is interleaved according to * the probes list. */ void *data; @@ -549,6 +565,7 @@ enum { SR_CHANNEL_ANALOG, SR_CHANNEL_GROUP, SR_CHANNEL_DECODER, + SR_CHANNEL_FFT, }; enum { @@ -560,17 +577,20 @@ enum { struct sr_channel { /* The index field will go: use g_slist_length(sdi->channels) instead. */ uint16_t index; - int type; + int type; gboolean enabled; char *name; char *trigger; uint64_t vdiv; uint16_t vfactor; double vpos; + uint16_t vpos_trans; uint8_t coupling; uint8_t trig_value; - uint16_t vpos_mid; - uint16_t voff_mid; + int8_t comb_diff_top; + int8_t comb_diff_bom; + gboolean ms_show; + gboolean ms_en[DSO_MS_END - DSO_MS_BEGIN]; }; /** Structure for groups of channels that have common properties. */ @@ -628,22 +648,9 @@ struct sr_status { gboolean stream_mode; uint32_t sample_divider; gboolean sample_divider_tog; + gboolean trig_flag; - gboolean zeroing; - uint16_t ch0_vpos_mid; - uint16_t ch0_voff_mid; - uint16_t ch0_vcntr; - uint16_t ch1_vpos_mid; - uint16_t ch1_voff_mid; - uint16_t ch1_vcntr; - uint8_t ch0_adc_off; - uint8_t ch1_adc_off; - gboolean ch0_adc_sign; - gboolean ch1_adc_sign; - - uint16_t comb0_off; - uint16_t comb1_off; - uint8_t comb_sign; + uint16_t pkt_id; }; enum { @@ -730,6 +737,9 @@ enum { /** Trigger source. */ SR_CONF_TRIGGER_SOURCE, + /** Trigger channel */ + SR_CONF_TRIGGER_CHANNEL, + /** Trigger Value. */ SR_CONF_TRIGGER_VALUE, @@ -739,6 +749,9 @@ enum { /** Trigger hold off time */ SR_CONF_TRIGGER_HOLDOFF, + /** Trigger Margin */ + SR_CONF_TRIGGER_MARGIN, + /** Buffer size. */ SR_CONF_BUFFERSIZE, @@ -751,11 +764,17 @@ enum { /** DSO configure sync */ SR_CONF_DSO_SYNC, + /** DSO vertical resolution*/ + SR_CONF_DSO_BITS, + /** Zero */ SR_CONF_ZERO_SET, + SR_CONF_ZERO_LOAD, SR_CONF_COMB_SET, SR_CONF_ZERO, SR_CONF_ZERO_OVER, + SR_CONF_VOCM, + SR_CONF_CALI, /** status for dso channel */ SR_CONF_STATUS_PERIOD, @@ -766,6 +785,9 @@ enum { /** Stream */ SR_CONF_STREAM, + /** DSO Roll */ + SR_CONF_ROLL, + /** Test */ SR_CONF_TEST, @@ -777,6 +799,13 @@ enum { /** Vertical offset */ SR_CONF_VOFF, + SR_CONF_VOFF_DEFAULT, + SR_CONF_VOFF_RANGE, + + /** VGain */ + SR_CONF_VGAIN, + SR_CONF_VGAIN_DEFAULT, + SR_CONF_VGAIN_RANGE, /** Coupling for dso channel. */ SR_CONF_COUPLING, @@ -867,6 +896,16 @@ enum { */ SR_CONF_LIMIT_SAMPLES, + /** + * Absolute time record for session driver + */ + SR_CONF_TRIGGER_TIME, + + /** + * Trigger position for session driver + */ + SR_CONF_TRIGGER_POS, + /** * The actual sample count received */ @@ -978,8 +1017,6 @@ enum { SR_GND_COUPLING = 2, }; -extern char config_path[256]; - struct sr_dev_mode { char *name; int mode; @@ -1050,7 +1087,7 @@ struct sr_session { * an async fashion. We need to make sure the session is stopped from * within the session thread itself. */ -// GMutex stop_mutex; + GMutex stop_mutex; gboolean abort_session; }; @@ -1087,10 +1124,11 @@ struct ds_trigger { }; struct ds_trigger_pos { + uint32_t check_id; uint32_t real_pos; uint32_t ram_saddr; uint32_t remain_cnt; - unsigned char first_block[500]; + unsigned char first_block[496]; }; #include "proto.h" diff --git a/libsigrok4DSL/proto.h b/libsigrok4DSL/proto.h index fe9b1d95..223f1ec0 100644 --- a/libsigrok4DSL/proto.h +++ b/libsigrok4DSL/proto.h @@ -111,7 +111,7 @@ SR_API int sr_session_start(void); 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); + unsigned char *buf, int unitsize, uint64_t samples, int64_t trig_time, uint64_t trig_pos); 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, @@ -181,6 +181,7 @@ SR_API int ds_trigger_set_stage(uint16_t stages); SR_API int ds_trigger_set_pos(uint16_t position); SR_API uint16_t ds_trigger_get_pos(); SR_API int ds_trigger_set_en(uint16_t enable); +SR_API uint16_t ds_trigger_get_en(); SR_API int ds_trigger_set_mode(uint16_t mode); #endif diff --git a/libsigrok4DSL/session.c b/libsigrok4DSL/session.c index 7fb110d9..87746adb 100644 --- a/libsigrok4DSL/session.c +++ b/libsigrok4DSL/session.c @@ -86,7 +86,7 @@ SR_API struct sr_session *sr_session_new(void) session->source_timeout = -1; session->running = FALSE; session->abort_session = FALSE; -// g_mutex_init(&session->stop_mutex); + g_mutex_init(&session->stop_mutex); return session; } @@ -121,7 +121,7 @@ SR_API int sr_session_destroy(void) /* TODO: Error checks needed? */ -// g_mutex_clear(&session->stop_mutex); + g_mutex_clear(&session->stop_mutex); g_free(session); session = NULL; @@ -325,13 +325,13 @@ static int sr_session_iteration(gboolean block) * we check the flag after processing every source, not * just once per main event loop. */ - //g_mutex_lock(&session->stop_mutex); + g_mutex_lock(&session->stop_mutex); if (session->abort_session) { sr_session_stop_sync(); /* But once is enough. */ session->abort_session = FALSE; } - //g_mutex_unlock(&session->stop_mutex); + g_mutex_unlock(&session->stop_mutex); } return SR_OK; @@ -414,6 +414,10 @@ SR_API int sr_session_run(void) sr_session_iteration(TRUE); } + g_mutex_lock(&session->stop_mutex); + session->running = FALSE; + session->abort_session = FALSE; + g_mutex_unlock(&session->stop_mutex); return SR_OK; } @@ -447,7 +451,6 @@ SR_PRIV int sr_session_stop_sync(void) sdi->driver->dev_acquisition_stop(sdi, NULL); } } - session->running = FALSE; return SR_OK; } @@ -472,9 +475,10 @@ SR_API int sr_session_stop(void) return SR_ERR_BUG; } -// g_mutex_lock(&session->stop_mutex); - session->abort_session = TRUE; -// g_mutex_unlock(&session->stop_mutex); + g_mutex_lock(&session->stop_mutex); + if (session->running) + session->abort_session = TRUE; + g_mutex_unlock(&session->stop_mutex); return SR_OK; } @@ -722,29 +726,37 @@ static int _sr_session_source_remove(gintptr poll_object) if (old == session->num_sources) return SR_OK; - session->num_sources -= 1; + session->num_sources -= 1; - if (old != session->num_sources) { - memmove(&session->pollfds[old], &session->pollfds[old+1], - (session->num_sources - old) * sizeof(GPollFD)); - memmove(&session->sources[old], &session->sources[old+1], - (session->num_sources - old) * sizeof(struct source)); - } + if (session->num_sources == 0) { + session->source_timeout = -1; + g_free(session->pollfds); + g_free(session->sources); + session->pollfds = NULL; + session->sources = NULL; + } else { + if (old != session->num_sources) { + memmove(&session->pollfds[old], &session->pollfds[old+1], + (session->num_sources - old) * sizeof(GPollFD)); + memmove(&session->sources[old], &session->sources[old+1], + (session->num_sources - old) * sizeof(struct source)); + } - new_pollfds = g_try_realloc(session->pollfds, sizeof(GPollFD) * session->num_sources); - if (!new_pollfds && session->num_sources > 0) { - sr_err("%s: new_pollfds malloc failed", __func__); - return SR_ERR_MALLOC; - } + new_pollfds = g_try_realloc(session->pollfds, sizeof(GPollFD) * session->num_sources); + if (!new_pollfds && session->num_sources > 0) { + sr_err("%s: new_pollfds malloc failed", __func__); + return SR_ERR_MALLOC; + } - new_sources = g_try_realloc(session->sources, sizeof(struct source) * session->num_sources); - if (!new_sources && session->num_sources > 0) { - sr_err("%s: new_sources malloc failed", __func__); - return SR_ERR_MALLOC; - } + new_sources = g_try_realloc(session->sources, sizeof(struct source) * session->num_sources); + if (!new_sources && session->num_sources > 0) { + sr_err("%s: new_sources malloc failed", __func__); + return SR_ERR_MALLOC; + } - session->pollfds = new_pollfds; - session->sources = new_sources; + session->pollfds = new_pollfds; + session->sources = new_sources; + } return SR_OK; } diff --git a/libsigrok4DSL/session_driver.c b/libsigrok4DSL/session_driver.c index fa1d0c0f..d61435ff 100644 --- a/libsigrok4DSL/session_driver.c +++ b/libsigrok4DSL/session_driver.c @@ -52,6 +52,8 @@ struct session_vdev { int bytes_read; uint64_t samplerate; uint64_t total_samples; + int64_t trig_time; + uint64_t trig_pos; int unitsize; int num_probes; uint64_t timebase; @@ -171,6 +173,8 @@ static int dev_open(struct sr_dev_inst *sdi) sr_err("%s: vdev->buf malloc failed", __func__); return SR_ERR_MALLOC; } + vdev->trig_pos = 0; + vdev->trig_time = 0; dev_insts = g_slist_append(dev_insts, sdi); @@ -211,6 +215,13 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, } else return SR_ERR; break; + case SR_CONF_TRIGGER_TIME: + if (sdi) { + vdev = sdi->priv; + *data = g_variant_new_int64(vdev->trig_time); + } else + return SR_ERR; + break; case SR_CONF_TIMEBASE: if (sdi) { vdev = sdi->priv; @@ -258,6 +269,9 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, return SR_ERR; *data = g_variant_new_uint64(vdev->total_samples); break; + case SR_CONF_RLE_SAMPLELIMITS: + *data = g_variant_new_uint64(UINT64_MAX); + break; default: return SR_ERR_ARG; } @@ -299,7 +313,15 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, samplecounts[0] = vdev->total_samples; sr_info("Setting limit samples to %" PRIu64 ".", vdev->total_samples); break; - case SR_CONF_CAPTURE_NUM_PROBES: + case SR_CONF_TRIGGER_TIME: + vdev->trig_time = g_variant_get_int64(data); + sr_info("Setting trigger time to %" PRId64 ".", vdev->trig_time); + break; + case SR_CONF_TRIGGER_POS: + vdev->trig_pos = g_variant_get_uint64(data); + sr_info("Setting trigger position to %" PRIu64 ".", vdev->trig_pos); + break; + case SR_CONF_CAPTURE_NUM_PROBES: vdev->num_probes = g_variant_get_uint64(data); break; case SR_CONF_EN_CH: @@ -407,6 +429,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, { struct zip_stat zs; struct session_vdev *vdev; + struct sr_datafeed_packet packet; int ret; vdev = sdi->priv; @@ -435,6 +458,15 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, /* Send header packet to the session bus. */ std_session_send_df_header(sdi, LOG_PREFIX); + /* Send trigger packet to the session bus */ + if (vdev->trig_pos != 0) { + struct ds_trigger_pos session_trigger; + session_trigger.real_pos = vdev->trig_pos; + packet.type = SR_DF_TRIGGER; + packet.payload = &session_trigger; + sr_session_send(sdi, &packet); + } + /* freewheeling source */ sr_session_source_add(-1, 0, 0, receive_data, sdi); diff --git a/libsigrok4DSL/session_file.c b/libsigrok4DSL/session_file.c index aa77128d..bf5b27c5 100644 --- a/libsigrok4DSL/session_file.c +++ b/libsigrok4DSL/session_file.c @@ -125,6 +125,7 @@ SR_API int sr_session_load(const char *filename) uint16_t probenum; uint64_t tmp_u64, total_probes, enabled_probes; uint16_t p; + int64_t tmp_64; char **sections, **keys, *metafile, *val, s[11]; char probename[SR_MAX_PROBENAME_LEN + 1]; int mode = LOGIC; @@ -205,10 +206,18 @@ SR_API int sr_session_load(const char *filename) tmp_u64 = strtoull(val, NULL, 10); sdi->driver->config_set(SR_CONF_LIMIT_SAMPLES, g_variant_new_uint64(tmp_u64), sdi, NULL, NULL); - } else if (!strcmp(keys[j], "hDiv")) { + } else if (!strcmp(keys[j], "hDiv")) { tmp_u64 = strtoull(val, NULL, 10); sdi->driver->config_set(SR_CONF_TIMEBASE, g_variant_new_uint64(tmp_u64), sdi, NULL, NULL); + } else if (!strcmp(keys[j], "trigger time")) { + tmp_64 = strtoll(val, NULL, 10); + sdi->driver->config_set(SR_CONF_TRIGGER_TIME, + g_variant_new_int64(tmp_64), sdi, NULL, NULL); + } else if (!strcmp(keys[j], "trigger pos")) { + tmp_u64 = strtoull(val, NULL, 10); + sdi->driver->config_set(SR_CONF_TRIGGER_POS, + 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, @@ -331,7 +340,7 @@ SR_API int sr_session_load(const char *filename) * upon other errors. */ SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, - unsigned char *buf, int unitsize, int units) + unsigned char *buf, int unitsize, uint64_t samples, int64_t trig_time, uint64_t trig_pos) { GSList *l; GVariant *gvar; @@ -373,7 +382,7 @@ SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, /* metadata */ fprintf(meta, "capturefile = data\n"); fprintf(meta, "unitsize = %d\n", unitsize); - fprintf(meta, "total samples = %d\n", units); + fprintf(meta, "total samples = %llu\n", samples); fprintf(meta, "total probes = %d\n", g_slist_length(sdi->channels)); if (sr_config_get(sdi->driver, sdi, NULL, NULL, SR_CONF_SAMPLERATE, &gvar) == SR_OK) { @@ -386,9 +395,13 @@ SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, if (sdi->mode == DSO && sr_config_get(sdi->driver, sdi, NULL, NULL, SR_CONF_TIMEBASE, &gvar) == SR_OK) { timeBase = g_variant_get_uint64(gvar); - fprintf(meta, "hDiv = %d\n", timeBase); + fprintf(meta, "hDiv = %llu\n", timeBase); g_variant_unref(gvar); + } else if (sdi->mode == LOGIC) { + fprintf(meta, "trigger time = %lld\n", trig_time); } + fprintf(meta, "trigger pos = %llu\n", trig_pos); + probecnt = 1; for (l = sdi->channels; l; l = l->next) { probe = l->data; @@ -405,13 +418,13 @@ SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, fprintf(meta, " vPos%d = %lf\n", probe->index, probe->vpos); if (sr_status_get(sdi, &status, 0, 0) == SR_OK) { if (probe->index == 0) { - fprintf(meta, " period%d = %d\n", probe->index, status.ch0_period); - fprintf(meta, " pcnt%d = %d\n", probe->index, status.ch0_pcnt); + fprintf(meta, " period%d = %llu\n", probe->index, status.ch0_period); + fprintf(meta, " pcnt%d = %lu\n", probe->index, status.ch0_pcnt); fprintf(meta, " max%d = %d\n", probe->index, status.ch0_max); fprintf(meta, " min%d = %d\n", probe->index, status.ch0_min); } else { - fprintf(meta, " period%d = %d\n", probe->index, status.ch1_period); - fprintf(meta, " pcnt%d = %d\n", probe->index, status.ch1_pcnt); + fprintf(meta, " period%d = %llu\n", probe->index, status.ch1_period); + fprintf(meta, " pcnt%d = %lu\n", probe->index, status.ch1_pcnt); fprintf(meta, " max%d = %d\n", probe->index, status.ch1_max); fprintf(meta, " min%d = %d\n", probe->index, status.ch1_min); } @@ -422,7 +435,7 @@ SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, } if (!(logicsrc = zip_source_buffer(zipfile, buf, - units * unitsize, FALSE))) + samples * unitsize, FALSE))) return SR_ERR; snprintf(rawname, 15, "data"); if (zip_add(zipfile, rawname, logicsrc) == -1) @@ -544,7 +557,7 @@ SR_API int sr_session_save_init(const char *filename, uint64_t samplerate, * @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. + * @param samples The number of samples. * * @retval SR_OK Success * @retval SR_ERR_ARG Invalid arguments diff --git a/libsigrok4DSL/trigger.c b/libsigrok4DSL/trigger.c index c3350c95..0f572640 100644 --- a/libsigrok4DSL/trigger.c +++ b/libsigrok4DSL/trigger.c @@ -34,7 +34,7 @@ * @{ */ -struct ds_trigger *trigger; +struct ds_trigger *trigger = NULL; /** * recovery trigger to initial status. @@ -77,7 +77,7 @@ SR_API int ds_trigger_destroy(void) { if (trigger) g_free(trigger); - + trigger = NULL; return SR_OK; } @@ -207,6 +207,19 @@ SR_API int ds_trigger_set_en(uint16_t enable) return SR_OK; } +/** + * get trigger en + * + * @return SR_OK upon success. + */ +SR_API uint16_t ds_trigger_get_en() +{ + if (trigger == NULL) + return 0; + else + return trigger->trigger_en; +} + /** * set trigger mode * diff --git a/libsigrokdecode4DSL/.gitignore b/libsigrokdecode4DSL/.gitignore new file mode 100644 index 00000000..f6eb0b8c --- /dev/null +++ b/libsigrokdecode4DSL/.gitignore @@ -0,0 +1,38 @@ +# autotools cruft +/INSTALL +/Makefile.in +/aclocal.m4 +/autom4te.cache/ +/autostuff/ +/configure +/configure.lineno +/m4/libtool.m4 +/m4/lt*.m4 + +# Editor/IDE cruft +*.kate-swp +*~ +/*.kdev4 +/Makefile.am.user + +# Configure/build cruft +*.[ao] +*.l[ao] +.deps/ +.dirstamp +.libs/ +/ChangeLog +/Makefile +/config.* +/libsigrokdecode-*.tar.* +/libsigrokdecode.pc +/libtool +/version.h +__pycache__/ +stamp-h? + +# Files generated by the testsuite +/test-suite.log +/tests/*.log +/tests/*.trs +/tests/main diff --git a/libsigrokdecode4DSL/AUTHORS b/libsigrokdecode4DSL/AUTHORS new file mode 100644 index 00000000..28c1b20e --- /dev/null +++ b/libsigrokdecode4DSL/AUTHORS @@ -0,0 +1,7 @@ +------------------------------------------------------------------------------- +AUTHORS +------------------------------------------------------------------------------- + +Please check the source code files and/or git history and/or ChangeLog for +a list of all authors and contributors. + diff --git a/libsigrokdecode4DSL/COPYING b/libsigrokdecode4DSL/COPYING new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/libsigrokdecode4DSL/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/libsigrokdecode4DSL/Doxyfile b/libsigrokdecode4DSL/Doxyfile new file mode 100644 index 00000000..a53ec1d9 --- /dev/null +++ b/libsigrokdecode4DSL/Doxyfile @@ -0,0 +1,2318 @@ +# Doxyfile 1.8.6 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "libsigrokdecode" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = "unreleased development snapshot" + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "sigrok protocol decoding library" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = contrib/sigrok-logo-notext.png + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = doxy + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = YES + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. Do not use file names with spaces, bibtex cannot handle them. See +# also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = . + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = config.h libsigrokdecode-internal.h exception.c \ + module_sigrokdecode.c type_decoder.c type_logic.c \ + util.c + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +# Ignore the following files and directories (see also EXCLUDE above): +# - config.h: Non-public stuff, the file doesn't get installed. +# - libsigrokdecode-internal.h: Non-public stuff, the file isn't installed. +# - decoders/*: The decoders themselves don't contain public API. +# - exception.c: No public API stuff in there currently. +# - module_sigrokdecode.c: No public API stuff in there currently. +# - type_decoder.c: No public API stuff in there currently. +# - tyoe_logic.c: No public API stuff in there currently. +# - util.c: No public API stuff in there currently. +# - tests/*: Unit tests, no public API stuff in there. +# - doxy/*: Potentially already generated docs, should not be scanned. +# +EXCLUDE_PATTERNS = */decoders/* */tests/* */doxy/* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html-api + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- +# defined cascading style sheet that is included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet file to the output directory. For an example +# see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = YES + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 1 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /