├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── Makefile.am ├── README.md ├── appimage ├── .gitignore ├── default.desktop └── default.png ├── configure.ac ├── deploy_linux.sh ├── deploy_macos.sh ├── deploy_windows.sh ├── env.cfg ├── include └── xavna ├── libxavna ├── CMakeLists.txt ├── Makefile.am ├── README.md ├── calibration.C ├── common.H ├── common_types.h ├── include │ ├── calibration.H │ ├── common.H │ ├── platform_abstraction.H │ ├── workarounds.H │ ├── xavna.h │ ├── xavna_cpp.H │ └── xavna_generic.H ├── platform_abstraction.C ├── platform_abstraction_windows.C ├── xavna.C ├── xavna_cpp.C └── xavna_mock_ui │ ├── .gitignore │ ├── CMakeLists.txt │ ├── xavna_mock.C │ ├── xavna_mock_ui.C │ ├── xavna_mock_ui.H │ ├── xavna_mock_ui.pro │ ├── xavna_mock_ui_dialog.C │ ├── xavna_mock_ui_dialog.H │ ├── xavna_mock_ui_dialog.ui │ └── xavna_mock_ui_global.h ├── pictures ├── antenna.png ├── coax.png └── ttf.png ├── run ├── ug1101.pdf ├── vna_diagtool ├── main.cpp ├── mainwindow.C ├── mainwindow.H ├── mainwindow.ui └── vna_diagtool.pro ├── vna_gtk ├── common_types.h ├── configure.ac ├── graph_view.H ├── polar_view.H ├── vna.glade ├── vna_main.C ├── vna_ui_core.C ├── vna_ui_core.H └── xavna_mock.glade └── vna_qt ├── .gitignore ├── CMakeLists.txt ├── add.svg ├── calibrationfinetunedialog.C ├── calibrationfinetunedialog.H ├── calibrationfinetunedialog.ui ├── calkitsettings.C ├── calkitsettings.H ├── calkitsettingsdialog.C ├── calkitsettingsdialog.H ├── calkitsettingsdialog.ui ├── calkitsettingswidget.ui ├── configureviewdialog.C ├── configureviewdialog.H ├── configureviewdialog.ui ├── dtfwindow.C ├── dtfwindow.H ├── dtfwindow.ui ├── edit-redo-symbolic.svg ├── emblem-ok-symbolic.svg ├── firmwareupdatedialog.C ├── firmwareupdatedialog.H ├── firmwareupdatedialog.ui ├── firmwareupdater.C ├── firmwareupdater.H ├── frequencydialog.C ├── frequencydialog.H ├── frequencydialog.ui ├── graphlimitsdialog.ui ├── graphpanel.C ├── graphpanel.H ├── graphpanel.ui ├── impedancedisplay.C ├── impedancedisplay.H ├── impedancedisplay.ui ├── languages ├── vna_qt_zh.qm └── vna_qt_zh.ts ├── main.C ├── mainwindow.C ├── mainwindow.H ├── mainwindow.ui ├── markerslider.C ├── markerslider.H ├── markerslider.ui ├── networkview.C ├── networkview.H ├── polarview.C ├── polarview.H ├── resources.qrc ├── touchstone.C ├── touchstone.H ├── utility.H ├── vna_qt.pro ├── xfce-wm-close.svg ├── xfce-wm-maximize.svg └── xfce-wm-unmaximize.svg /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.dll 3 | /lib_mock/* 4 | build-*/* 5 | */build-*/* 6 | cal/* 7 | *.pro.user* 8 | *.a 9 | lib/*.so 10 | pcb/*.png 11 | pcb/*/*.png 12 | *.tar.gz 13 | vhdl/spiflash.* 14 | /Makefile 15 | /xavna_windows/* 16 | /xavna-src/* 17 | /*.zip 18 | /*.tar.gz 19 | libtool 20 | *.AppImage 21 | 22 | */.deps/* 23 | */.libs/* 24 | *.lo 25 | *.la 26 | Makefile.Debug 27 | Makefile.Release 28 | .qmake.* 29 | qrc_resources.cpp 30 | *.svf.gz 31 | vna_qt/release 32 | *_plugin_import.cpp 33 | moc_*.cpp 34 | moc_*.h 35 | ui_*.h 36 | *.exe 37 | *.o 38 | Makefile 39 | Makefile.in 40 | /ar-lib 41 | /mdate-sh 42 | /py-compile 43 | /test-driver 44 | /ylwrap 45 | 46 | # http://www.gnu.org/software/autoconf 47 | 48 | /autom4te.cache 49 | /autoscan.log 50 | /autoscan-*.log 51 | /aclocal.m4 52 | /compile 53 | /config.guess 54 | /config.h.in 55 | /config.sub 56 | /configure 57 | /configure.scan 58 | /depcomp 59 | /install-sh 60 | /missing 61 | /stamp-h1 62 | 63 | # https://www.gnu.org/software/libtool/ 64 | 65 | /ltmain.sh 66 | 67 | # http://www.gnu.org/software/texinfo 68 | 69 | /texinfo.tex 70 | 71 | # http://www.gnu.org/software/m4/ 72 | 73 | m4/libtool.m4 74 | m4/ltoptions.m4 75 | m4/ltsugar.m4 76 | m4/ltversion.m4 77 | m4/lt~obsolete.m4 78 | autom4te.cache 79 | 80 | 81 | 82 | pcb/*_out/* 83 | *.pcb.bak* 84 | pcb/*.raw 85 | pcb/*.fft 86 | pcb/*.net 87 | pcb/*.png 88 | pcb/.* 89 | pcb/*.bom.csv 90 | pcb/#*# 91 | *.log 92 | 93 | 94 | # http://www.gnu.org/software/automake 95 | /ar-lib 96 | /mdate-sh 97 | /py-compile 98 | /test-driver 99 | /ylwrap 100 | # http://www.gnu.org/software/autoconf 101 | /autom4te.cache 102 | /autoscan.log 103 | /autoscan-*.log 104 | /aclocal.m4 105 | /compile 106 | /config.guess 107 | /config.h.in 108 | /config.sub 109 | /config.status 110 | /config.log 111 | /configure 112 | /configure.scan 113 | /depcomp 114 | /install-sh 115 | /missing 116 | /stamp-h1 117 | # https://www.gnu.org/software/libtool/ 118 | /ltmain.sh 119 | # http://www.gnu.org/software/texinfo 120 | /texinfo.tex 121 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Minimum CMake required 2 | cmake_minimum_required(VERSION 3.5) 3 | 4 | if(WIN32) 5 | if(${CMAKE_VERSION} VERSION_LESS "3.8") 6 | message(WARNING "Your current cmake version is ${CMAKE_VERSION} which does not support setting the toolset architecture to x64. This may cause \"compiler out of heap space\" errors when building. Consider upgrading your cmake to > 3.8 and using the flag -Thost=x64 when running cmake.") 7 | else() 8 | if(NOT CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE OR NOT "${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}" STREQUAL "x64") 9 | message(WARNING "Your current cmake generator is set to use 32 bit toolset architecture. This may cause \"compiler out of heap space\" errors when building. Consider using the flag -Thost=x64 when running cmake.") 10 | endif() 11 | endif() 12 | endif() 13 | 14 | # Project 15 | project(nanovna_qt C CXX) 16 | 17 | set(xaVNA_VERSION_MAJOR 0) 18 | set(xaVNA_VERSION_MINOR 1) 19 | set(xaVNA_VERSION_STRING ${xaVNA_VERSION_MAJOR}.${xaVNA_VERSION_MINOR}) 20 | 21 | # Set C++11 as standard for the whole project 22 | set(CMAKE_CXX_STANDARD 11) 23 | 24 | if(UNIX) 25 | set(CMAKE_CXX_FLAGS "-O2 ${CMAKE_CXX_FLAGS}") 26 | set(CMAKE_CXX_FLAGS_DEBUG "-O2 -g ${CMAKE_CXX_FLAGS}") 27 | endif() 28 | 29 | if(NOT LIB_INSTALL_DIR) 30 | set(LIB_INSTALL_DIR lib) 31 | endif() 32 | 33 | if(NOT BIN_INSTALL_DIR) 34 | set(BIN_INSTALL_DIR bin) 35 | endif() 36 | 37 | # Set version 38 | add_definitions(-DVERSION=\"${xaVNA_VERSION_STRING}\") 39 | add_definitions(-DEIGEN_DONT_VECTORIZE -DEIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT) 40 | 41 | # CMake policies 42 | cmake_policy(SET CMP0022 NEW) 43 | 44 | # Find includes in corresponding build directories 45 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 46 | 47 | # Position independent code 48 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 49 | 50 | # Local Include 51 | include_directories(include) 52 | 53 | # ============================================================================== 54 | # Eigen3 55 | # ============================================================================== 56 | find_package(Eigen3 REQUIRED) 57 | if(EIGEN3_FOUND) 58 | message(STATUS " eigen3 version: ${EIGEN3_VERSION}") 59 | message(STATUS " eigen3 includes: ${EIGEN3_INCLUDE_DIR}") 60 | include_directories(${EIGEN3_INCLUDE_DIR}) 61 | endif() 62 | 63 | # ============================================================================== 64 | # FFTW3 65 | # ============================================================================== 66 | find_package(FFTW3 REQUIRED) 67 | if(FFTW3_FOUND) 68 | message(STATUS "Found FFTW3 (${FFTW3_VERSION})") 69 | message(STATUS " fftw3 includes: ${FFTW3_INCLUDE_DIRS}") 70 | message(STATUS " fftw3 libraries: ${FFTW3_LIBRARIES}") 71 | include_directories(${FFTW3_INCLUDE_DIR}) 72 | endif() 73 | 74 | # ============================================================================== 75 | # QT5 Charts (and QT5 subdependences) 76 | # ============================================================================== 77 | find_package(Qt5 COMPONENTS Core Gui Widgets Charts REQUIRED) 78 | if(Qt5Charts_FOUND) 79 | message(STATUS "Found QT5 version: ${Qt5_VERSION}") 80 | message(STATUS " qt5 charts dir: ${Qt5Charts_DIR}") 81 | endif() 82 | 83 | # ============================================================================== 84 | # xaVNA subprojects 85 | # ============================================================================== 86 | add_subdirectory(libxavna) 87 | add_subdirectory(libxavna/xavna_mock_ui) 88 | add_subdirectory(vna_qt) 89 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 --install 2 | 3 | SUBDIRS = libxavna 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NanoVNA-QT 2 | PC GUI software for NanoVNA V2 series (V2 Plus4/V2 Plus4 Pro). 3 | 4 | - Supports hardware versions listed here: https://nanorfe.com/nanovna-v2.html 5 | - https://www.tindie.com/products/hcxqsgroup/nanovna-v2/ 6 | 7 | 8 | NanoVNA V2配套的PC软件,可用于实时网络分析和测量。 9 | 10 | 11 | # Downloads / 下载 12 | https://nanorfe.com/nanovna-v2-software.html 13 | 14 | 15 | # Screenshots / 截图 16 | 17 | ##### Open circuited coax stub / 开路同轴电缆 18 | 19 | 20 | 21 | ##### Antenna / 天线 22 | 23 | 24 | 25 | ##### Time to fault / 障碍距离 26 | 27 | 28 | 29 | 30 | # 编译 / Building the software 31 | 32 | __Linux系统下编译 / Building on Linux__ 33 | 34 | 编译 libxavna: 35 | ```bash 36 | sudo apt-get install automake libtool make g++ libeigen3-dev libfftw3-dev 37 | cd /PATH/TO/NanoVNA-QT 38 | autoreconf --install 39 | ./configure 40 | make 41 | cd libxavna/xavna_mock_ui/ 42 | /PATH/TO/qmake 43 | make 44 | ``` 45 | 46 | 编译 QT 界面: 47 | ```bash 48 | sudo apt-get install libqt5charts5-dev 49 | cd /PATH/TO/NanoVNA-QT 50 | cd vna_qt 51 | /PATH/TO/qmake 52 | make 53 | export QT=/PATH/TO/QT # optional, e.g. ~/qt/5.10.1/gcc_64 54 | ../run ./vna_qt 55 | ``` 56 | 57 | __Mac系统下编译 / Building on mac os__ 58 | 59 | MacPorts: 60 | ```bash 61 | sudo port install NanoVNA-QT 62 | # result in /Applications/MacPorts/NanoVNA-QT.app 63 | ``` 64 | 65 | Homebrew: 66 | ```bash 67 | brew install automake libtool make eigen fftw 68 | cd /PATH/TO/NanoVNA-QT 69 | ./deploy_macos.sh 70 | # result is in ./vna_qt/vna_qt.app 71 | ``` 72 | 73 | __Linux系统下编译Windows目标 / Cross-compile for windows (from Linux)__ 74 | 75 | Prerequisites: 76 | ```bash 77 | sudo apt-get install python make autoconf automake autopoint bison flex gperf intltool libtool libtool-bin lzip ruby unzip p7zip-full libgdk-pixbuf2.0-dev libssl-dev libeigen3-dev fftw3-dev mingw-w64 78 | ``` 79 | 80 | 下载与编译 MXE: 81 | ```bash 82 | cd ~/ 83 | git clone https://github.com/mxe/mxe.git 84 | cd mxe 85 | echo "MXE_TARGETS := i686-w64-mingw32.shared" >> settings.mk 86 | export QT_MXE_ARCH=386 87 | make qt5 qtcharts cc eigen fftw pthreads 88 | ``` 89 | 90 | 编译 Application: 91 | ```bash 92 | cd ~/ 93 | git clone https://github.com/nanovna/NanoVNA-QT.git 94 | cd NanoVNA-QT 95 | export PATH="~/mxe/usr/bin:$PATH" 96 | ./deploy_windows.sh 97 | # Result is in ./vna_qt_windows.zip 98 | ``` 99 | 100 | Tested on a fresh install of Ubuntu 18.04 LTS. 101 | -------------------------------------------------------------------------------- /appimage/.gitignore: -------------------------------------------------------------------------------- 1 | doc/ 2 | lib/ 3 | plugins/ 4 | translations/ 5 | qt.conf 6 | vna_qt 7 | AppRun 8 | .DirIcon 9 | -------------------------------------------------------------------------------- /appimage/default.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=NanoVNA QT GUI 4 | Exec=AppRun %F 5 | Icon=default 6 | Comment=GUI for NanoVNA V2 7 | Terminal=false 8 | Categories=Science; 9 | -------------------------------------------------------------------------------- /appimage/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanovna-v2/NanoVNA-QT/0aa6ee4e68ade0285755f06c2eab240e2d0beea1/appimage/default.png -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(vna, version-0.1, 54525305+nanovna@users.noreply.github.com) 2 | AM_INIT_AUTOMAKE([-Wall -Werror foreign]) 3 | m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) 4 | AC_PROG_CXX 5 | AC_LANG(C++) 6 | AC_CONFIG_MACRO_DIR([m4]) 7 | #AC_CONFIG_HEADERS([libxavna/include/xavna.h]) 8 | AC_CONFIG_FILES([ 9 | Makefile 10 | libxavna/Makefile 11 | ]) 12 | LT_INIT([win32-dll]) 13 | AC_CANONICAL_HOST 14 | 15 | is_windows=no 16 | case "${host_os}" in 17 | cygwin*|mingw*) 18 | is_windows=yes 19 | ;; 20 | linux-androideabi) 21 | is_android=yes 22 | ;; 23 | esac 24 | 25 | AM_CONDITIONAL([WINDOWS], [test "$is_windows" = "yes"]) 26 | AM_CONDITIONAL([ANDROID], [test "$is_android" = "yes"]) 27 | 28 | AC_CHECK_HEADER(eigen3/Eigen/Dense) 29 | if test "$ac_cv_header_eigen3_Eigen_Dense" == no 30 | then 31 | AC_MSG_ERROR([eigen3 not installed (eigen3/Eigen/Dense include not found)]) 32 | fi 33 | 34 | 35 | AC_CHECK_HEADER(fftw3.h) 36 | if test "$ac_cv_header_fftw3_h" == no 37 | then 38 | AC_MSG_ERROR([fftw3 not installed (fftw3.h include not found)]) 39 | fi 40 | 41 | 42 | 43 | #if test -z $CXXFLAGS; then 44 | # CXXFLAGS='-O2 -std=c++0x -fPIC -fwrapv -fno-delete-null-pointer-checks -funsigned-char -fno-strict-aliasing -Wno-pmf-conversions' 45 | #fi 46 | 47 | #AC_SUBST(OBJECTS) 48 | #OBJECTS="lib/libxavna.so" 49 | 50 | 51 | 52 | #AC_SUBST(EXTRA_LIBRARIES) 53 | #AC_SUBST(EXTRA_SOURCES) 54 | 55 | #AC_ARG_VAR([QMAKE], [Path to qmake]) 56 | 57 | #AC_ARG_WITH([qt_gui], 58 | #[AS_HELP_STRING([--with-qt-gui], 59 | #[Build QT GUI @<:@default=yes@:>@])], 60 | #[], 61 | #[with_qt_gui=yes]) 62 | 63 | 64 | #if test "$with_qt_gui" == "yes" 65 | #then 66 | #AC_CHECK_PROG([QMAKE], [qmake], [qmake]) 67 | #OBJECTS+=" vna_qt/vna_qt" 68 | #fi 69 | 70 | AC_OUTPUT 71 | -------------------------------------------------------------------------------- /deploy_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # please edit env.cfg and set the correct paths before running 4 | 5 | cd "$(dirname $0)" 6 | . env.cfg 7 | if [ ! -e "$QT" ]; then 8 | echo "please edit env.cfg and set \$QT" 9 | exit 1 10 | fi 11 | if [ ! -e "$LINUXDEPLOYQT" ]; then 12 | echo "please edit env.cfg and set \$LINUXDEPLOYQT" 13 | exit 1 14 | fi 15 | QMAKE="$QT/bin/qmake" 16 | 17 | autoreconf --install 18 | ./configure 19 | make -j$(nproc) 20 | 21 | pushd libxavna/xavna_mock_ui 22 | $QMAKE 23 | make -j$(nproc) 24 | popd 25 | 26 | pushd vna_qt 27 | $QMAKE 28 | make -j$(nproc) 29 | popd 30 | 31 | export LD_LIBRARY_PATH="$(pwd)/libxavna/.libs:$(pwd)/libxavna/xavna_mock_ui:$QT/lib" 32 | cp -a vna_qt/vna_qt appimage/ 33 | rm -rf appimage/lib appimage/plugins 34 | "$LINUXDEPLOYQT" appimage/vna_qt -qmake="$QMAKE" -appimage 35 | 36 | -------------------------------------------------------------------------------- /deploy_macos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(dirname $0)" 4 | . env.cfg 5 | if [ ! -e "$QT" ]; then 6 | echo "please edit env.cfg and set \$QT" 7 | exit 1 8 | fi 9 | QMAKE="$QT/bin/qmake" 10 | 11 | autoreconf --install 12 | ./configure 13 | make -j8 14 | 15 | pushd libxavna/xavna_mock_ui 16 | $QMAKE 17 | make -j8 18 | popd 19 | 20 | pushd vna_qt 21 | rm -rf *.app 22 | $QMAKE 23 | make -j8 24 | "$QT"/bin/macdeployqt vna_qt.app -libpath=../libxavna/xavna_mock_ui 25 | cp -a ../libxavna/.libs/libxavna.0.dylib vna_qt.app/Contents/Frameworks 26 | 27 | pushd vna_qt.app/Contents 28 | install_name_tool -add_rpath "@executable_path/../Frameworks" MacOS/vna_qt 29 | install_name_tool -change libxavna_mock_ui.1.dylib @executable_path/../Frameworks/libxavna_mock_ui.1.dylib MacOS/vna_qt 30 | install_name_tool -change /usr/local/lib/libxavna.0.dylib @executable_path/../Frameworks/libxavna.0.dylib MacOS/vna_qt 31 | install_name_tool -change /usr/local/lib/libxavna.0.dylib @executable_path/../Frameworks/libxavna.0.dylib Frameworks/libxavna_mock_ui.1.dylib 32 | popd 33 | 34 | rm -rf dmg_contents ../NanoVNA_QT_MacOS.dmg tmp.dmg 35 | mkdir dmg_contents 36 | cp -a vna_qt.app dmg_contents/ 37 | 38 | hdiutil create tmp.dmg -ov -volname "NanoVNA QT GUI" -fs HFS+ -srcfolder dmg_contents 39 | hdiutil convert tmp.dmg -format UDZO -o ../NanoVNA_QT_MacOS.dmg 40 | 41 | -------------------------------------------------------------------------------- /deploy_windows.sh: -------------------------------------------------------------------------------- 1 | MXE=~/mxe 2 | export PATH="$MXE/usr/bin:$PATH" 3 | HOST="i686-w64-mingw32.shared" 4 | QMAKE="$HOST-qmake-qt5" 5 | 6 | autoreconf --install 7 | ./configure --host "$HOST" CXXFLAGS=-O2 8 | make -j8 9 | 10 | pushd libxavna/xavna_mock_ui 11 | "$QMAKE" 12 | make -j8 13 | popd 14 | 15 | pushd vna_qt 16 | "$QMAKE" 17 | make -j8 18 | for x in Qt5Charts Qt5Core Qt5Gui Qt5Widgets Qt5Svg; do 19 | cp "$MXE/usr/$HOST/qt5/bin/$x.dll" release/ 20 | done 21 | mkdir -p release/platforms 22 | mkdir -p release/styles 23 | mkdir -p release/imageformats 24 | mkdir -p release/iconengines 25 | 26 | for x in platforms/qwindows styles/qwindowsvistastyle \ 27 | imageformats/qsvg iconengines/qsvgicon; do 28 | cp "$MXE/usr/$HOST/qt5/plugins/$x.dll" release/"$x".dll 29 | done; 30 | 31 | for x in libgcc_s_sjlj-1 libstdc++-6 libpcre2-16-0 zlib1 libharfbuzz-0 \ 32 | libpng16-16 libfreetype-6 libglib-2.0-0 libbz2 libintl-8 libpcre-1\ 33 | libiconv-2 libwinpthread-1 libjasper libjpeg-9 libmng-2 libtiff-5\ 34 | libwebp-7 libwebpdemux-2 liblcms2-2 liblzma-5 libfftw3-3 libzstd; do 35 | cp "$MXE/usr/$HOST/bin/$x.dll" release/ 36 | done 37 | cp ../libxavna/.libs/libxavna-0.dll release/ 38 | cp ../libxavna/xavna_mock_ui/release/xavna_mock_ui.dll release/ 39 | rm release/*.cpp release/*.o release/*.h 40 | rm ../*.zip 41 | zip -r ../vna_qt_windows.zip release 42 | -------------------------------------------------------------------------------- /env.cfg: -------------------------------------------------------------------------------- 1 | 2 | # path to a qt build, e.g. ~/qt/5.10.1/gcc_64 3 | QT=/usr 4 | 5 | # path to a linuxdeployqt binary, e.g. ~/linuxdeployqt-continuous-x86_64.AppImage 6 | LINUXDEPLOYQT=/persist/linuxdeployqt-continuous-x86_64.AppImage 7 | 8 | -------------------------------------------------------------------------------- /include/xavna: -------------------------------------------------------------------------------- 1 | ../libxavna/include -------------------------------------------------------------------------------- /libxavna/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(libxavna_SRC xavna.C 3 | xavna_cpp.C 4 | calibration.C) 5 | 6 | if(WIN32) 7 | list(APPEND libxavna_SRC platform_abstraction_windows.C) 8 | else() 9 | list(APPEND libxavna_SRC platform_abstraction.C) 10 | endif() 11 | 12 | add_library(xavna SHARED ${libxavna_SRC}) 13 | 14 | set_target_properties(xavna PROPERTIES 15 | VERSION ${xaVNA_VERSION_STRING} 16 | SOVERSION ${xaVNA_VERSION_MAJOR}) 17 | 18 | target_link_libraries(xavna ${xa_LIBRARIES}) 19 | 20 | # Declare destinations 21 | install(TARGETS xavna 22 | LIBRARY DESTINATION ${LIB_INSTALL_DIR} 23 | ARCHIVE DESTINATION ${LIB_INSTALL_DIR}) 24 | -------------------------------------------------------------------------------- /libxavna/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I../include -O2 -std=c++0x -fPIC -fwrapv -fno-delete-null-pointer-checks -funsigned-char -fno-strict-aliasing -Wno-pmf-conversions 2 | AM_LDFLAGS = -no-undefined 3 | lib_LTLIBRARIES = libxavna.la 4 | libxavna_la_SOURCES = xavna.C xavna_cpp.C calibration.C 5 | 6 | 7 | AM_CPPFLAGS += -DEIGEN_DONT_VECTORIZE -DEIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT 8 | 9 | if !ANDROID 10 | AM_LDFLAGS += -lpthread 11 | endif 12 | 13 | if WINDOWS 14 | libxavna_la_SOURCES += platform_abstraction_windows.C 15 | else 16 | libxavna_la_SOURCES += platform_abstraction.C 17 | endif 18 | -------------------------------------------------------------------------------- /libxavna/README.md: -------------------------------------------------------------------------------- 1 | # libxavna 2 | C and C++ library for accessing xaVNA or NanoVNA V2 hardware. There is only one library (.so or .dll), but several headers you can include, one for each api. 3 | 4 | # C api 5 | The C api allows low level access to the hardware; typical usage is: 6 | 1. Open the device 7 | 2. Set parameters (frequency, signal generator power, etc) 8 | 3. Read values 9 | 4. Repeat (2) and (3) as needed. 10 | 5. Close device 11 | 12 | Note that the hardware is continuously sending data through the FIFO interface, so any time that you aren't reading it it is being queued up, meaning stale data can surface. The recommended usage pattern is to continuously read values in a loop, possibly in a background thread. 13 | ```c 14 | #include 15 | 16 | // dev: path to the serial device 17 | // returns: handle to the opened device, or NULL if failed; check errno 18 | void* xavna_open(const char* dev); 19 | 20 | // Returns true if dev is a T/R VNA, otherwise false 21 | bool xavna_is_tr(void* dev); 22 | 23 | // Set the RF frequency and attenuation. 24 | // freq_khz: frequency in kHz 25 | // atten: attenuation in dB (positive integer) of signal generator 26 | // port: which port to output the signal on 27 | // nWait: number of data samples to skip after changing settings 28 | // returns: 0 if success; -1 if failure 29 | int xavna_set_params(void* dev, int freq_khz, int atten, int port, int nWait=20); 30 | 31 | // read vector values from device; applicable for T/R VNA only 32 | // out_values: array of size 4 holding the following values (in order): 33 | // reflection real, reflection imag, 34 | // thru real, thru imag 35 | // n_samples: number of samples to average over; typical 50 36 | // returns: number of samples read, or -1 if failure 37 | int xavna_read_values(void* dev, double* out_values, int n_samples); 38 | 39 | // read vector values from device; applicable for both T/R and full two port 40 | // out_values: array of size 8 holding the following values (in order): 41 | // port 1 out real, port 1 out imag, 42 | // port 1 in real, port 1 in imag 43 | // port 2 out real, port 2 out imag, 44 | // port 2 in real, port 2 in imag 45 | // n_samples: number of samples to average over; typical 50 46 | // returns: number of samples read, or -1 if failure 47 | int xavna_read_values_raw(void* dev, double* out_values, int n_samples); 48 | 49 | // close device handle 50 | void xavna_close(void* dev); 51 | ``` 52 | 53 | # C++ api 54 | The C++ api provides a more convenient callback based interface, with frequency sweep and background data reading taken care of. 55 | The typical usage is: 56 | 1. Instantiate VNADevice 57 | 2. Set callbacks and sweep parameters (start frequency, step frequency, number of points) 58 | 3. open() 59 | 4. startScan() 60 | 5. close() 61 | 6. delete VNADevice 62 | 63 | ```c++ 64 | #include 65 | 66 | namespace xaxaxa { 67 | class VNADevice { 68 | public: 69 | // frequency sweep parameters; do NOT change while background thread is running 70 | double startFreqHz=200e6; // start frequency in Hz 71 | double stepFreqHz=25e6; // step frequency in Hz 72 | int nPoints=50; // how many frequency points 73 | int nValues=50; // how many values to average over 74 | bool tr = true; // whether to measure with only port 1 signal gen enabled 75 | 76 | // rf parameters 77 | int attenuation1, attenuation2; 78 | 79 | // called by background thread when a single frequency measurement is done 80 | function frequencyCompletedCallback; 81 | 82 | // called by background thread when a complete sweep of all frequencies is done 83 | function& vals)> sweepCompletedCallback; 84 | 85 | // called by background thread when an error occurs 86 | function backgroundErrorCallback; 87 | 88 | 89 | VNADevice(); 90 | ~VNADevice(); 91 | 92 | // find all xaVNA devices present 93 | static vector findDevices(); 94 | 95 | // open a vna device 96 | // dev: path to the serial device; if empty, it will be selected automatically 97 | void open(string dev); 98 | 99 | // start the frequency sweep background thread, which repeatedly performs 100 | // scans until it is stopped using stopScan() 101 | void startScan(); 102 | 103 | // stop the background thread 104 | void stopScan(); 105 | 106 | // close the vna device 107 | void close(); 108 | 109 | // return the frequency in Hz at an array index 110 | double freqAt(int i) { 111 | return startFreqHz+i*stepFreqHz; 112 | } 113 | }; 114 | } 115 | ``` 116 | 117 | -------------------------------------------------------------------------------- /libxavna/common.H: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | using namespace Eigen; 7 | 8 | template array, N> operator*(const array, N>& a, double b) { 9 | array, N> res; 10 | for(int i=0;i freeNodes, vector forcedNodes, vector > forcedNodeValues) { 31 | assert(freeNodes.size() == forcedNodes.size()); 32 | assert(forcedNodes.size() == forcedNodeValues.size()); 33 | 34 | for(int i=0;i<(int)freeNodes.size();i++) { 35 | // create a self-loop of gain 1 on the free node 36 | // the self-loop allows the free node to take on any value with no incoming edge 37 | sfg(freeNodes[i], freeNodes[i]) = 1.; 38 | 39 | // create an edge from the forced node to the free node with value -1 40 | sfg(freeNodes[i], forcedNodes[i]) = -1.; 41 | // add an excitation on the free node with the value of the forced node value 42 | excitation(forcedNodes[i]) = forcedNodeValues[i]; 43 | 44 | // the self-loop of gain 1 on the free node enforces all the incoming edges must sum to 0, 45 | // because otherwise the feedback will cause the value to blow up; 46 | // the effect of this constraint is that the forced node must in the end have a value 47 | // equal to the forced value 48 | } 49 | return solveSFG(sfg, excitation); 50 | } 51 | 52 | 53 | -------------------------------------------------------------------------------- /libxavna/common_types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | typedef unsigned long ul; 5 | typedef unsigned int ui; 6 | typedef long long ll; 7 | typedef unsigned long long ull; 8 | typedef uint64_t u64; 9 | typedef uint32_t u32; 10 | typedef uint16_t u16; 11 | typedef uint8_t u8; 12 | typedef int8_t s8; 13 | 14 | -------------------------------------------------------------------------------- /libxavna/include/calibration.H: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "common.H" 10 | using namespace std; 11 | using namespace Eigen; 12 | 13 | 14 | namespace xaxaxa { 15 | 16 | class VNACalibration 17 | { 18 | public: 19 | // return the name of this calibration type 20 | virtual string name() const=0; 21 | 22 | // return the descriptive name of this calibration type 23 | virtual string description() const=0; 24 | 25 | // return the detailed description of this calibration type 26 | virtual string helpText() const=0; 27 | 28 | // get a list of calibration standards required (name/desc pair) 29 | virtual vector > getRequiredStandards() const=0; 30 | 31 | // given the measurements for each of the calibration standards, compute the coefficients. 32 | // for one port calibration standards (open, short, etc) the calStdModels entry should have 33 | // the value at 0,0 (S11) 34 | virtual MatrixXcd computeCoefficients(const vector& measurements, 35 | const vector& calStdModels) const=0; 36 | 37 | // given cal coefficients and a raw value, compute S parameters 38 | virtual VNACalibratedValue computeValue(MatrixXcd coeffs, VNARawValue val) const=0; 39 | }; 40 | 41 | // system global list of calibration types (auto-populated on library init) 42 | extern vector calibrationTypes; 43 | 44 | // system global map from calibration standard names to ideal S parameters 45 | // (auto-populated on library init) 46 | extern map idealCalStds; 47 | 48 | class CalibrationEngine { 49 | public: 50 | CalibrationEngine(int nPorts); 51 | 52 | // returns how many equations have been added so far 53 | int nEquations(); 54 | 55 | // returns how many error coefficients there are 56 | int nCoeffs(); 57 | 58 | // returns how many equations are required for calibration 59 | int nEquationsRequired(); 60 | 61 | 62 | // clear all added equations 63 | void clearEquations(); 64 | 65 | // add equations for when a fully known cal standard has been measured 66 | void addFullEquation(const MatrixXcd& actualSParams, const MatrixXcd& measuredSParams); 67 | 68 | // add equations for when Sjn is known, for all j, and one n 69 | void addOnePortEquation(const MatrixXcd& actualSParams, const MatrixXcd& measuredSParams, int n); 70 | 71 | // adds one equation that fixes a error term to 1; this is currently the vna to dut port 1 transmission factor 72 | void addNormalizingEquation(); 73 | 74 | 75 | // compute calibration coefficients given equations added 76 | MatrixXcd computeCoefficients(); 77 | 78 | // given coefficients and measured S parameters, compute actual S parameters 79 | static MatrixXcd computeSParams(const MatrixXcd& coeffs, const MatrixXcd& measuredSParams); 80 | 81 | 82 | // private: 83 | int _nPorts, _nEquations; 84 | MatrixXcd _equations; 85 | VectorXcd _rhs; 86 | }; 87 | 88 | } 89 | 90 | 91 | // given the measured raw values for short, open, and load, compute the 3 calibration coefficients 92 | inline array, 3> SOL_compute_coefficients(complex sc, complex oc, complex load) { 93 | complex a=load, b=oc, c=sc; 94 | complex cal_X, cal_Y, cal_Z; 95 | cal_Z=(2.*a-b-c)/(b-c); 96 | cal_X=a-c*(1.-cal_Z); 97 | cal_Y=a/cal_X; 98 | 99 | return {cal_X, cal_Y, cal_Z}; 100 | /*CalibrationEngine ce(1); 101 | ce.addFullEquation(-1., sc); 102 | ce.addFullEquation(1., oc); 103 | ce.addFullEquation(0., load); 104 | ce.addNormalizingEquation(); 105 | MatrixXcd res = ce.computeCoefficients(); 106 | */ 107 | } 108 | // given the calibration coefficients and a raw value, compute the reflection coefficient 109 | inline complex SOL_compute_reflection(const array, 3>& coeffs, complex raw) { 110 | auto cal_X = coeffs[0]; 111 | auto cal_Y = coeffs[1]; 112 | auto cal_Z = coeffs[2]; 113 | 114 | return (cal_X*cal_Y-raw)/(raw*cal_Z-cal_X); 115 | } 116 | 117 | // given the cal coefficients and a reflection coefficient, compute d(refl)/d(raw) 118 | inline complex SOL_compute_sensitivity(const array, 3>& coeffs, complex refl) { 119 | auto X = coeffs[0]; 120 | auto Y = coeffs[1]; 121 | auto Z = coeffs[2]; 122 | auto raw = X*(Y+refl)/(refl*Z+1.); 123 | return -X*(Y*Z-1.) / ((Z*raw-X)*(Z*raw-X)); 124 | } 125 | 126 | // S: s11, s12, s21, s22; refl: reflection coefficient 127 | // computes reflection coefficient looking into port 1 of S, with port 2 of S connected to a load refl 128 | inline complex cascade_reflection(const array, 4>& S, complex refl) { 129 | complex s11=S[0]; 130 | complex s12=S[1]; 131 | complex s21=S[2]; 132 | complex s22=S[3]; 133 | return s11 + s12*s21*refl/(1.-s22*refl); 134 | } 135 | 136 | 137 | -------------------------------------------------------------------------------- /libxavna/include/common.H: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | using namespace Eigen; 7 | using namespace std; 8 | 9 | 10 | //EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix2cd); 11 | 12 | 13 | namespace xaxaxa { 14 | using VNARawValue = Matrix2cd; 15 | using VNACalibratedValue = Matrix2cd; 16 | inline Matrix2cd mirror(Matrix2cd a) { 17 | complex tmp; 18 | tmp = a(0,0); 19 | a(0,0) = a(1,1); 20 | a(1,1) = tmp; 21 | tmp = a(0,1); 22 | a(0,1) = a(1,0); 23 | a(1,0) = tmp; 24 | return a; 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /libxavna/include/platform_abstraction.H: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | 6 | // functions with platform specific implementation go here 7 | 8 | vector xavna_find_devices(); 9 | int xavna_open_serial(const char* path); 10 | void xavna_drainfd(int fd); 11 | bool xavna_detect_autosweep(int fd); 12 | -------------------------------------------------------------------------------- /libxavna/include/workarounds.H: -------------------------------------------------------------------------------- 1 | #ifdef ANDROID_WORKAROUNDS 2 | 3 | #define pthread_cancel(x) /**/ 4 | #define to_string(x) my_to_string(x) 5 | 6 | inline string my_to_string(int x) { 7 | char buf[32]; 8 | snprintf(buf,32,"%d",x); 9 | return buf; 10 | } 11 | inline string my_to_string(double x) { 12 | char buf[32]; 13 | snprintf(buf,32,"%lf",x); 14 | return buf; 15 | } 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /libxavna/include/xavna.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern "C" { 4 | struct autoSweepDataPoint { 5 | // indexed by [port][real_or_imag] 6 | double forward[2][2], reverse[2][2]; 7 | int freqIndex; 8 | }; 9 | 10 | // dev: path to the serial device 11 | // returns: handle to the opened device, or NULL if failed; check errno 12 | void* xavna_open(const char* dev); 13 | 14 | // Returns true if dev is a T/R VNA, otherwise false 15 | bool xavna_is_tr(void* dev); 16 | 17 | // Returns true if dev uses the autosweep protocol 18 | bool xavna_is_autosweep(void* dev); 19 | 20 | // Set the RF frequency and attenuation. 21 | // freq_khz: frequency in kHz 22 | // atten: attenuation in dB (positive integer) of signal generator 23 | // port: which port to output the signal on 24 | // nWait: number of data samples to skip after changing settings 25 | // returns: 0 if success; -1 if failure 26 | int xavna_set_params(void* dev, int freq_khz, int atten, int port, int nWait=20); 27 | 28 | // Set the sweep parameters. Only applicable to autosweep devices (see xavna_is_autosweep) 29 | // sweepStartHz: start frequency in Hz 30 | // sweepStepHz: step frequency in Hz 31 | // sweepPoints: number of frequency points 32 | // nValues: number of values to output for each frequency point 33 | // returns: 0 if success; -1 if failure 34 | int xavna_set_autosweep(void* dev, double sweepStartHz, double sweepStepHz, int sweepPoints, int nValues=1); 35 | 36 | // read vector values from device; applicable for T/R VNA only 37 | // out_values: array of size 4 holding the following values (in order): 38 | // reflection real, reflection imag, 39 | // thru real, thru imag 40 | // n_samples: number of samples to average over; typical 50 41 | // returns: number of samples read, or -1 if failure 42 | int xavna_read_values(void* dev, double* out_values, int n_samples); 43 | 44 | // read vector values from device; applicable for both T/R and full two port 45 | // out_values: array of size 8 holding the following values (in order): 46 | // port 1 out real, port 1 out imag, 47 | // port 1 in real, port 1 in imag 48 | // port 2 out real, port 2 out imag, 49 | // port 2 in real, port 2 in imag 50 | // n_samples: number of samples to average over; typical 50 51 | // returns: number of samples read, or -1 if failure 52 | int xavna_read_values_raw(void* dev, double* out_values, int n_samples); 53 | 54 | // read vector values from device; applicable for both T/R and full two port autosweep devices 55 | // out_values: array of autoSweepDataPoint structures, one for each returned data point 56 | // n_values: size of the out_values array 57 | // returns: n_values, or -1 if failure 58 | int xavna_read_autosweep(void* dev, autoSweepDataPoint* out_values, int n_values); 59 | 60 | // close device handle 61 | void xavna_close(void* dev); 62 | } 63 | 64 | -------------------------------------------------------------------------------- /libxavna/include/xavna_cpp.H: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "common.H" 8 | 9 | using namespace std; 10 | 11 | namespace xaxaxa { 12 | class VNADevice { 13 | public: 14 | // frequency sweep parameters; do NOT change while background thread is running 15 | double startFreqHz=200e6; // start frequency in Hz 16 | double stepFreqHz=25e6; // step frequency in Hz 17 | int nPoints=50; // how many frequency points 18 | int nValues=30; // how many values to average over 19 | int nWait=20; // how many values to skip after changing frequency 20 | bool disableReference = false; // if true, do not divide by reference value 21 | bool forceTR = false; // if device is full two port vna, force T/R mode 22 | bool swapPorts = false; // only supported on full two port vna 23 | 24 | // rf parameters 25 | int attenuation1=25, attenuation2=25; 26 | 27 | // called by background thread when a single frequency measurement is done 28 | function frequencyCompletedCallback; 29 | 30 | 31 | // called by background thread when a complete sweep of all frequencies is done 32 | function& vals)> sweepCompletedCallback; 33 | 34 | // called by background thread when an error occurs 35 | function backgroundErrorCallback; 36 | 37 | 38 | VNADevice(); 39 | ~VNADevice(); 40 | 41 | // find all xaVNA devices present 42 | static vector findDevices(); 43 | 44 | // returns the device handle as returned by xavna_open(), or NULL 45 | void* device(); 46 | 47 | // open a vna device 48 | // dev: path to the serial device; if empty, it will be selected automatically 49 | void open(string dev); 50 | 51 | // returns whether the device is a T/R vna 52 | bool isTR(); 53 | 54 | // returns whether the device uses the autosweep protocol 55 | bool isAutoSweep(); 56 | 57 | // returns true if either device is a T/R vna or forceTR is true 58 | bool isTRMode(); 59 | 60 | // start the frequency sweep background thread, which repeatedly performs 61 | // scans until it is stopped using stopScan() 62 | void startScan(); 63 | 64 | // stop the background thread 65 | void stopScan(); 66 | 67 | // whether the background thread is running 68 | bool isScanning(); 69 | 70 | // close the vna device 71 | void close(); 72 | 73 | // wait for one full measurement, and call cb with results 74 | void takeMeasurement(function& vals)> cb); 75 | 76 | // return the frequency in Hz at an array index 77 | double freqAt(int i) { 78 | return startFreqHz+i*stepFreqHz; 79 | } 80 | 81 | // return highest power output in dBm 82 | int maxPower() const { 83 | return 10; 84 | } 85 | 86 | 87 | // diagnostics 88 | 89 | // called by background thread after frequencyCompletedCallback(); provides signal values 90 | // directly from hardware 91 | function, 4> >& values)> frequencyCompletedCallback2_; 92 | 93 | 94 | // internal variables 95 | void* _dev=NULL; 96 | pthread_t _pth; 97 | bool _threadRunning=false; 98 | bool _shouldExit=false; 99 | bool _lastDeviceIsAutosweep=false; 100 | volatile uint32_t _measurementCnt=0; 101 | function& vals)> _cb; 102 | volatile function& vals)>* _cb_; 103 | 104 | // internal methods 105 | void* _mainThread(); 106 | void* _runAutoSweep(); 107 | }; 108 | } 109 | 110 | -------------------------------------------------------------------------------- /libxavna/include/xavna_generic.H: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xavna.h" 3 | 4 | using namespace std; 5 | class xavna_generic { 6 | public: 7 | virtual bool is_tr()=0; 8 | virtual bool is_autosweep()=0; 9 | virtual int set_params(int freq_khz, int atten, int port, int nWait)=0; 10 | virtual int set_autosweep(double sweepStartHz, double sweepStepHz, int sweepPoints, int nValues=1)=0; 11 | virtual int set_if_freq(int freq_khz)=0; 12 | virtual int read_values(double* out_values, int n_samples)=0; 13 | virtual int read_values_raw(double* out_values, int n_samples)=0; 14 | virtual int read_autosweep(autoSweepDataPoint* out_values, int n_values)=0; 15 | virtual ~xavna_generic() {} 16 | }; 17 | 18 | typedef function xavna_constructor; 19 | 20 | 21 | -------------------------------------------------------------------------------- /libxavna/platform_abstraction.C: -------------------------------------------------------------------------------- 1 | #include "include/platform_abstraction.H" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | // disable SIGHUP and SIGPIPE 16 | void xavna_disableSignals() { 17 | struct sigaction sa; 18 | 19 | sa.sa_handler = SIG_IGN; 20 | sigemptyset(&sa.sa_mask); 21 | sa.sa_flags = SA_RESTART; // Restart system calls if interrupted by handler 22 | sigaction(SIGHUP, &sa, NULL); 23 | sigaction(SIGPIPE, &sa, NULL); 24 | 25 | sa.sa_handler = SIG_DFL; 26 | sigaction(SIGCONT, &sa, NULL); 27 | sigaction(SIGTSTP, &sa, NULL); 28 | sigaction(SIGTTIN, &sa, NULL); 29 | sigaction(SIGTTOU, &sa, NULL); 30 | } 31 | 32 | vector xavna_find_devices() { 33 | vector ret; 34 | DIR *dir; 35 | struct dirent *ent; 36 | if ((dir = opendir ("/dev")) == NULL) 37 | throw runtime_error("xavna_find_devices: could not list /dev: " + 38 | string(strerror(errno))); 39 | 40 | /* print all the files and directories within directory */ 41 | while ((ent = readdir (dir)) != NULL) { 42 | string name = ent->d_name; 43 | if(name.find("ttyACM")==0) 44 | ret.push_back("/dev/"+name); 45 | if(name.find("cu.usbmodem")==0) 46 | ret.push_back("/dev/"+name); 47 | } 48 | closedir (dir); 49 | return ret; 50 | } 51 | 52 | int xavna_open_serial(const char* path) { 53 | xavna_disableSignals(); 54 | int fd = open(path,O_RDWR); 55 | if(fd<0) return fd; 56 | struct termios tc; 57 | /* Set TTY mode. */ 58 | if (tcgetattr(fd, &tc) < 0) { 59 | perror("tcgetattr"); 60 | return fd; 61 | } 62 | /*tc.c_iflag &= ~(INLCR|IGNCR|ICRNL|IGNBRK|IUCLC|INPCK|ISTRIP|IXON|IXOFF|IXANY); 63 | tc.c_oflag &= ~OPOST; 64 | tc.c_cflag &= ~(CSIZE|CSTOPB|PARENB|PARODD|CRTSCTS); 65 | tc.c_cflag |= CS8 | CREAD | CLOCAL; 66 | tc.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|ISIG|IEXTEN);*/ 67 | 68 | tc.c_iflag = 0; 69 | tc.c_oflag = 0; 70 | tc.c_lflag = 0; 71 | tc.c_cflag = CS8 | CREAD | CLOCAL; 72 | tc.c_cc[VMIN] = 1; 73 | tc.c_cc[VTIME] = 0; 74 | tcsetattr(fd, TCSANOW, &tc); 75 | return fd; 76 | } 77 | 78 | void xavna_drainfd(int fd) { 79 | pollfd pfd; 80 | pfd.fd = fd; 81 | pfd.events = POLLIN; 82 | while(poll(&pfd,1,0)>0) { 83 | #ifndef __APPLE__ 84 | if(pfd.revents & POLLRDHUP) break; 85 | #endif 86 | if(pfd.revents & POLLERR) break; 87 | if(pfd.revents & POLLHUP) break; 88 | if(pfd.revents & POLLNVAL) break; 89 | if(!(pfd.revents & POLLIN)) continue; 90 | char buf[4096]; 91 | if(read(fd,buf,sizeof(buf)) <= 0) break; 92 | } 93 | } 94 | 95 | 96 | bool xavna_detect_autosweep(int fd) { 97 | pollfd pfd; 98 | pfd.fd = fd; 99 | pfd.events = POLLIN; 100 | if(poll(&pfd,1,100) == 0) { 101 | // no data was received => autosweep device 102 | return true; 103 | } 104 | return false; 105 | } 106 | -------------------------------------------------------------------------------- /libxavna/platform_abstraction_windows.C: -------------------------------------------------------------------------------- 1 | #include "include/platform_abstraction.H" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | vector xavna_find_devices() { 11 | vector ret; 12 | for(int i=0;i<256;i++) 13 | { 14 | char buf[256]; 15 | snprintf(buf, sizeof(buf), "\\\\.\\COM%i", i); 16 | 17 | HANDLE h = CreateFile(buf, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); 18 | if(h == INVALID_HANDLE_VALUE) { 19 | DWORD err = GetLastError(); 20 | if(err == ERROR_SHARING_VIOLATION || err == ERROR_ACCESS_DENIED || 21 | err == ERROR_GEN_FAILURE || err == ERROR_SEM_TIMEOUT) { 22 | ret.push_back(buf); 23 | } 24 | } else { 25 | ret.push_back(buf); 26 | CloseHandle(h); 27 | } 28 | } 29 | return ret; 30 | } 31 | 32 | int xavna_open_serial(const char* path) { 33 | HANDLE hComm; 34 | hComm = CreateFile(path, //port name 35 | GENERIC_READ | GENERIC_WRITE, //Read/Write 36 | 0, // No Sharing 37 | NULL, // No Security 38 | OPEN_EXISTING,// Open existing port only 39 | 0, // Non Overlapped I/O 40 | NULL); // Null for Comm Devices 41 | 42 | if (hComm == INVALID_HANDLE_VALUE) { 43 | fprintf(stderr, "Error in opening serial port"); 44 | return -1; 45 | } 46 | DCB dcbSerialParams = { 0 }; // Initializing DCB structure 47 | dcbSerialParams.DCBlength = sizeof(dcbSerialParams); 48 | 49 | GetCommState(hComm, &dcbSerialParams); 50 | dcbSerialParams.fOutX = FALSE; 51 | dcbSerialParams.fInX = FALSE; 52 | dcbSerialParams.fParity = FALSE; 53 | dcbSerialParams.fNull = FALSE; 54 | dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE; 55 | dcbSerialParams.fAbortOnError = FALSE; 56 | dcbSerialParams.Parity = NOPARITY; 57 | SetCommState(hComm, &dcbSerialParams); 58 | 59 | return _open_osfhandle((intptr_t)hComm, 0); 60 | } 61 | 62 | void xavna_drainfd(int fd) { 63 | HANDLE hComm = (HANDLE) _get_osfhandle(fd); 64 | COMMTIMEOUTS comTimeOut = {}; 65 | comTimeOut.ReadIntervalTimeout = MAXDWORD; 66 | comTimeOut.ReadTotalTimeoutMultiplier = MAXDWORD; 67 | comTimeOut.ReadTotalTimeoutConstant = 1; 68 | SetCommTimeouts(hComm,&comTimeOut); 69 | 70 | char buf[1024]; 71 | read(fd, buf, sizeof(buf)); 72 | 73 | comTimeOut.ReadTotalTimeoutConstant = 200; 74 | SetCommTimeouts(hComm,&comTimeOut); 75 | } 76 | 77 | bool xavna_detect_autosweep(int fd) { 78 | bool ret = true; 79 | HANDLE hComm = (HANDLE) _get_osfhandle(fd); 80 | COMMTIMEOUTS comTimeOut = {}; 81 | comTimeOut.ReadIntervalTimeout = MAXDWORD; 82 | comTimeOut.ReadTotalTimeoutMultiplier = MAXDWORD; 83 | comTimeOut.ReadTotalTimeoutConstant = 300; 84 | SetCommTimeouts(hComm,&comTimeOut); 85 | 86 | char buf[128]; 87 | if(read(fd, buf, sizeof(buf)) > 0) { 88 | ret = false; 89 | } 90 | // no data was received => autosweep device 91 | 92 | comTimeOut.ReadTotalTimeoutConstant = 200; 93 | SetCommTimeouts(hComm,&comTimeOut); 94 | return ret; 95 | } 96 | -------------------------------------------------------------------------------- /libxavna/xavna_mock_ui/.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | *.so.* 3 | -------------------------------------------------------------------------------- /libxavna/xavna_mock_ui/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_definitions(-DXAVNA_MOCK_UI_LIBRARY) 3 | 4 | include_directories(${Qt5Charts_INCLUDE_DIRS}) 5 | 6 | # Instruct CMake to run moc automatically when needed 7 | set(CMAKE_AUTOMOC ON) 8 | # Create code from a list of Qt designer ui files 9 | set(CMAKE_AUTOUIC ON) 10 | 11 | set(xavna_mock_ui_SRCS 12 | xavna_mock_ui.C 13 | xavna_mock.C 14 | xavna_mock_ui_dialog.C) 15 | 16 | set(xavna_mock_ui_FRMS 17 | xavna_mock_ui_dialog.ui) 18 | 19 | set(xavna_mock_ui_HDRS 20 | xavna_mock_ui.H 21 | xavna_mock_ui_dialog.H 22 | xavna_mock_ui_global.h 23 | ../include/calibration.H) 24 | 25 | add_library(xavna_mock_ui SHARED ${xavna_mock_ui_SRCS} ${xavna_mock_ui_FRMS} ${xavna_mock_ui_HDRS}) 26 | 27 | set_target_properties(xavna_mock_ui PROPERTIES 28 | VERSION ${xaVNA_VERSION_STRING} 29 | SOVERSION ${xaVNA_VERSION_MAJOR}) 30 | 31 | target_link_libraries(xavna_mock_ui Qt5::Core Qt5::Widgets Qt5::Gui xavna) 32 | 33 | # Declare destinations 34 | install(TARGETS xavna_mock_ui 35 | LIBRARY DESTINATION ${LIB_INSTALL_DIR} 36 | ARCHIVE DESTINATION ${LIB_INSTALL_DIR}) 37 | -------------------------------------------------------------------------------- /libxavna/xavna_mock_ui/xavna_mock_ui.C: -------------------------------------------------------------------------------- 1 | #include "xavna_mock_ui.H" 2 | #include "xavna_mock_ui_dialog.H" 3 | #include 4 | #include 5 | #include 6 | 7 | QApplication* app; 8 | pthread_t pth; 9 | 10 | void* thread1(void*) { 11 | //app->exec(); 12 | while(true) { 13 | usleep(100000); 14 | QApplication::processEvents(); 15 | } 16 | } 17 | 18 | char tmp[10] = ""; 19 | char* tmp1[] = {tmp}; 20 | int argc1=1; 21 | 22 | xavna_mock_ui::xavna_mock_ui() { 23 | bool createApp = (QCoreApplication::instance()==NULL); 24 | if(createApp) { 25 | fprintf(stderr,"NO QAPPLICATION FOUND; STARTING QAPPLICATION IN BACKGROUND THREAD\n"); 26 | fflush(stderr); 27 | app = new QApplication(argc1,tmp1); 28 | } 29 | 30 | xavna_mock_ui_dialog* wnd=new xavna_mock_ui_dialog(); 31 | this->wnd = wnd; 32 | wnd->show(); 33 | if(createApp) { 34 | QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection); 35 | app->exec(); 36 | pthread_create(&pth, NULL, &thread1, NULL); 37 | } 38 | } 39 | 40 | xavna_mock_ui::~xavna_mock_ui() { 41 | xavna_mock_ui_dialog* wnd = (xavna_mock_ui_dialog*)this->wnd; 42 | wnd->close(); 43 | } 44 | 45 | void xavna_mock_ui::set_cb(const xavna_ui_changed_cb& cb) { 46 | xavna_mock_ui_dialog* wnd = (xavna_mock_ui_dialog*)this->wnd; 47 | wnd->cb = cb; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /libxavna/xavna_mock_ui/xavna_mock_ui.H: -------------------------------------------------------------------------------- 1 | #ifndef XAVNA_MOCK_UI_H 2 | #define XAVNA_MOCK_UI_H 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | typedef function xavna_ui_changed_cb; 9 | 10 | class xavna_mock_ui 11 | { 12 | void* wnd=NULL; 13 | public: 14 | xavna_mock_ui(); 15 | ~xavna_mock_ui(); 16 | void set_cb(const xavna_ui_changed_cb &cb); 17 | }; 18 | 19 | #endif // XAVNA_MOCK_UI_H 20 | -------------------------------------------------------------------------------- /libxavna/xavna_mock_ui/xavna_mock_ui.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2018-02-15T07:40:00 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += widgets 8 | CONFIG += shared 9 | 10 | QMAKE_CXXFLAGS += -Wextra -std=c++11 -I/usr/local/include -I../../include 11 | QMAKE_CXXFLAGS += -DEIGEN_DONT_VECTORIZE -DEIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT 12 | android: QMAKE_CXXFLAGS += -DANDROID_WORKAROUNDS 13 | 14 | TARGET = xavna_mock_ui 15 | TEMPLATE = lib 16 | 17 | DEFINES += XAVNA_MOCK_UI_LIBRARY 18 | 19 | # The following define makes your compiler emit warnings if you use 20 | # any feature of Qt which as been marked as deprecated (the exact warnings 21 | # depend on your compiler). Please consult the documentation of the 22 | # deprecated API in order to know how to port your code away from it. 23 | DEFINES += QT_DEPRECATED_WARNINGS 24 | 25 | # You can also make your code fail to compile if you use deprecated APIs. 26 | # In order to do so, uncomment the following line. 27 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 28 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 29 | 30 | SOURCES += xavna_mock_ui.C \ 31 | xavna_mock.C \ 32 | xavna_mock_ui_dialog.C 33 | 34 | HEADERS += xavna_mock_ui.H\ 35 | xavna_mock_ui_dialog.H \ 36 | xavna_mock_ui_global.h \ 37 | ../include/calibration.H 38 | 39 | unix { 40 | target.path = /usr/lib 41 | INSTALLS += target 42 | } 43 | 44 | FORMS += \ 45 | xavna_mock_ui_dialog.ui 46 | 47 | LIBS += -L$$PWD/../.libs/ -lxavna 48 | !android: LIBS += -lpthread 49 | -------------------------------------------------------------------------------- /libxavna/xavna_mock_ui/xavna_mock_ui_dialog.C: -------------------------------------------------------------------------------- 1 | #include "xavna_mock_ui_dialog.H" 2 | #include "ui_xavna_mock_ui_dialog.h" 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | using namespace std; 9 | inline string ssprintf(int maxLen, const char* fmt, ...) { 10 | string tmp(maxLen, '\0'); 11 | va_list args; 12 | va_start(args, fmt); 13 | vsnprintf((char*)tmp.data(), maxLen, fmt, args); 14 | va_end(args); 15 | return tmp; 16 | } 17 | 18 | xavna_mock_ui_dialog::xavna_mock_ui_dialog(QWidget *parent) : 19 | QMainWindow(parent), 20 | ui(new Ui::xavna_mock_ui_dialog) 21 | { 22 | ui->setupUi(this); 23 | 24 | for(auto& btn:ui->buttonGroup->buttons()) { 25 | connect(btn, SIGNAL(clicked()), SLOT(cb_changed())); 26 | } 27 | this->setWindowFlags(Qt::WindowStaysOnTopHint); 28 | cb = [](string,double,double){}; 29 | } 30 | 31 | xavna_mock_ui_dialog::~xavna_mock_ui_dialog() { 32 | delete ui; 33 | } 34 | 35 | void xavna_mock_ui_dialog::cb_changed() { 36 | this->cb(ui->buttonGroup->checkedButton()->text().toStdString(), ui->slider1->value(), ui->slider2->value()); 37 | } 38 | 39 | void set_text(QLabel* l, string text) { 40 | QString tmp = QString::fromStdString(text); 41 | l->setText(tmp); 42 | } 43 | void xavna_mock_ui_dialog::on_slider1_valueChanged(int value) { 44 | set_text(ui->l_slider1, to_string(value)); 45 | cb_changed(); 46 | } 47 | void xavna_mock_ui_dialog::on_slider2_valueChanged(int value) { 48 | set_text(ui->l_slider2, to_string(value)); 49 | cb_changed(); 50 | } 51 | 52 | -------------------------------------------------------------------------------- /libxavna/xavna_mock_ui/xavna_mock_ui_dialog.H: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include "xavna_mock_ui.H" 6 | namespace Ui { 7 | class xavna_mock_ui_dialog; 8 | } 9 | 10 | class xavna_mock_ui_dialog : public QMainWindow 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit xavna_mock_ui_dialog(QWidget *parent = 0); 16 | ~xavna_mock_ui_dialog(); 17 | xavna_ui_changed_cb cb; 18 | 19 | private slots: 20 | void cb_changed(); 21 | 22 | 23 | void on_slider2_valueChanged(int value); 24 | 25 | void on_slider1_valueChanged(int value); 26 | 27 | private: 28 | Ui::xavna_mock_ui_dialog *ui; 29 | }; 30 | 31 | #endif // MAINWINDOW_H 32 | -------------------------------------------------------------------------------- /libxavna/xavna_mock_ui/xavna_mock_ui_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | xavna_mock_ui_dialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 259 10 | 271 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 20 21 | 21 22 | 171 23 | 185 24 | 25 | 26 | 27 | 28 | 29 | 30 | short 31 | 32 | 33 | true 34 | 35 | 36 | buttonGroup 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 0 46 | 47 | 48 | Qt::AlignCenter 49 | 50 | 51 | 52 | 53 | 54 | 55 | 0 56 | 57 | 58 | Qt::AlignCenter 59 | 60 | 61 | 62 | 63 | 64 | 65 | Cable 1 length (mm) 66 | 67 | 68 | 500 69 | 70 | 71 | Qt::Vertical 72 | 73 | 74 | false 75 | 76 | 77 | false 78 | 79 | 80 | QSlider::NoTicks 81 | 82 | 83 | 84 | 85 | 86 | 87 | Cable 2 length (mm) 88 | 89 | 90 | 500 91 | 92 | 93 | Qt::Vertical 94 | 95 | 96 | false 97 | 98 | 99 | false 100 | 101 | 102 | QSlider::NoTicks 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | open 112 | 113 | 114 | buttonGroup 115 | 116 | 117 | 118 | 119 | 120 | 121 | load 122 | 123 | 124 | buttonGroup 125 | 126 | 127 | 128 | 129 | 130 | 131 | thru-1cm 132 | 133 | 134 | buttonGroup 135 | 136 | 137 | 138 | 139 | 140 | 141 | thru-5cm 142 | 143 | 144 | buttonGroup 145 | 146 | 147 | 148 | 149 | 150 | 151 | stub-5cm 152 | 153 | 154 | buttonGroup 155 | 156 | 157 | 158 | 159 | 160 | 161 | stub-12cm 162 | 163 | 164 | buttonGroup 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 0 175 | 0 176 | 259 177 | 20 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /libxavna/xavna_mock_ui/xavna_mock_ui_global.h: -------------------------------------------------------------------------------- 1 | #ifndef XAVNA_MOCK_UI_GLOBAL_H 2 | #define XAVNA_MOCK_UI_GLOBAL_H 3 | 4 | #include 5 | 6 | #if defined(XAVNA_MOCK_UI_LIBRARY) 7 | # define XAVNA_MOCK_UISHARED_EXPORT Q_DECL_EXPORT 8 | #else 9 | # define XAVNA_MOCK_UISHARED_EXPORT Q_DECL_IMPORT 10 | #endif 11 | 12 | #endif // XAVNA_MOCK_UI_GLOBAL_H 13 | -------------------------------------------------------------------------------- /pictures/antenna.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanovna-v2/NanoVNA-QT/0aa6ee4e68ade0285755f06c2eab240e2d0beea1/pictures/antenna.png -------------------------------------------------------------------------------- /pictures/coax.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanovna-v2/NanoVNA-QT/0aa6ee4e68ade0285755f06c2eab240e2d0beea1/pictures/coax.png -------------------------------------------------------------------------------- /pictures/ttf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanovna-v2/NanoVNA-QT/0aa6ee4e68ade0285755f06c2eab240e2d0beea1/pictures/ttf.png -------------------------------------------------------------------------------- /run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | LIBDIR="$(dirname $0)" 3 | LD_LIBRARY_PATH="$LIBDIR/libxavna/.libs:$LIBDIR/libxavna/xavna_mock_ui" "$@" 4 | -------------------------------------------------------------------------------- /ug1101.pdf: -------------------------------------------------------------------------------- 1 | Latest user guide is at https://nanorfe.com/nanovna-v2-user-manual.html -------------------------------------------------------------------------------- /vna_diagtool/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.H" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | a.setStyle("fusion"); 8 | MainWindow w; 9 | w.show(); 10 | 11 | return a.exec(); 12 | } 13 | -------------------------------------------------------------------------------- /vna_diagtool/mainwindow.C: -------------------------------------------------------------------------------- 1 | #define _USE_MATH_DEFINES 2 | #include "mainwindow.H" 3 | #include "ui_mainwindow.h" 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | using namespace xaxaxa; 16 | using namespace std; 17 | 18 | MainWindow::MainWindow(QWidget *parent) : 19 | QMainWindow(parent), 20 | ui(new Ui::MainWindow) 21 | { 22 | ui->setupUi(this); 23 | vna = new VNADevice(); 24 | vna->startFreqHz = 35e6; 25 | vna->nPoints = 100; 26 | rawValues.resize(vna->nPoints); 27 | series.resize(4); 28 | 29 | setCallbacks(); 30 | 31 | // reference refl thru 32 | vector colors {Qt::blue, Qt::green, Qt::yellow, Qt::red}; 33 | 34 | 35 | 36 | chart = new QChart(); 37 | chartView = new QChartView(); 38 | ui->w_content->layout()->addWidget(chartView); 39 | 40 | chartView->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); 41 | chartView->setRenderHint(QPainter::Antialiasing); 42 | chartView->setChart(chart); 43 | chartView->setStyleSheet("background-color:#000"); 44 | 45 | 46 | 47 | axisX = new QValueAxis; 48 | axisX->setTickCount(10); 49 | axisX->setLabelsAngle(-90); 50 | axisX->setMin(freqAt(0)); 51 | axisX->setMax(freqAt(vna->nPoints-1)); 52 | chart->addAxis(axisX, Qt::AlignBottom); 53 | 54 | 55 | axisY = new QValueAxis; 56 | axisY->setTickCount(12); 57 | //axisY->setLinePenColor(Qt::red); 58 | axisY->setMin(-80); 59 | axisY->setMax(30); 60 | chart->addAxis(axisY, Qt::AlignLeft); 61 | 62 | for(int i=0;i<(int)series.size();i++) { 63 | series[i] = new QLineSeries(); 64 | series[i]->setPen(QPen(colors.at(i), 2.)); 65 | //series[i]->setUseOpenGL(true); 66 | chart->addSeries(series[i]); 67 | chart->legend()->hide(); 68 | chart->layout()->setContentsMargins(0, 0, 0, 0); 69 | chart->setBackgroundRoundness(0); 70 | //chart->setBackgroundBrush(Qt::red); 71 | //chart->setMargins(QMargins(0,0,0,0)); 72 | series[i]->attachAxis(axisX); 73 | series[i]->attachAxis(axisY); 74 | for(int j=0;jnPoints;j++) { 75 | series[i]->append(freqAt(j), 0); 76 | } 77 | } 78 | } 79 | 80 | double MainWindow::freqAt(int i) { 81 | return vna->freqAt(i)/1e6; 82 | } 83 | 84 | void MainWindow::populateDevicesMenu() { 85 | ui->menuDevice->clear(); 86 | 87 | vector devices; 88 | try { 89 | devices = vna->findDevices(); 90 | for(string dev:devices) { 91 | QAction* action = new QAction(qs(" " + dev)); 92 | connect(action, &QAction::triggered, [this,dev](){ 93 | this->openDevice(dev); 94 | }); 95 | ui->menuDevice->addAction(action); 96 | } 97 | } catch(exception& ex) { 98 | cerr << ex.what() << endl; 99 | } 100 | if(devices.empty()) { 101 | QAction* action = new QAction(" No devices found; check dmesg or device manager"); 102 | action->setEnabled(false); 103 | ui->menuDevice->addAction(action); 104 | } 105 | } 106 | 107 | 108 | void MainWindow::openDevice(string dev) { 109 | try { 110 | vna->open(dev); 111 | vna->startScan(); 112 | } catch(exception& ex) { 113 | QMessageBox::critical(this,"Exception",ex.what()); 114 | } 115 | } 116 | 117 | void MainWindow::setCallbacks() { 118 | vna->frequencyCompletedCallback = [this](int freqIndex, VNARawValue val) { 119 | }; 120 | vna->sweepCompletedCallback = [this](const vector&) { 121 | }; 122 | vna->frequencyCompletedCallback2_ = [this](int freqIndex, const vector, 4> >& values) { 123 | this->rawValues[freqIndex] = values; 124 | QMetaObject::invokeMethod(this, "updateViews", Qt::QueuedConnection, Q_ARG(int, freqIndex)); 125 | }; 126 | 127 | vna->backgroundErrorCallback = [this](const exception& exc) { 128 | fprintf(stderr,"background thread error: %s\n",exc.what()); 129 | QString msg = exc.what(); 130 | QMetaObject::invokeMethod(this, "handleBackgroundError", Qt::QueuedConnection, Q_ARG(QString, msg)); 131 | }; 132 | } 133 | 134 | 135 | void MainWindow::updateViews(int freqIndex) { 136 | 137 | fflush(stderr); 138 | if(freqIndex >= (int)rawValues.size()) return; 139 | 140 | int exIndex = excitation; 141 | 142 | double offset = 0; //-193; 143 | double y = dB(norm(rawValues.at(freqIndex)[exIndex][0])) + offset; 144 | series[0]->replace(freqIndex, series[0]->at(freqIndex).x(), y); 145 | printf("%f %f\n", series[0]->at(freqIndex).x(), y); 146 | 147 | y = dB(norm(rawValues.at(freqIndex)[exIndex][1])) + offset; 148 | series[1]->replace(freqIndex, series[0]->at(freqIndex).x(), y); 149 | 150 | y = dB(norm(rawValues.at(freqIndex)[exIndex][2])) + offset; 151 | series[2]->replace(freqIndex, series[0]->at(freqIndex).x(), y); 152 | 153 | y = dB(norm(rawValues.at(freqIndex)[exIndex][3])) + offset; 154 | series[3]->replace(freqIndex, series[0]->at(freqIndex).x(), y); 155 | } 156 | 157 | void MainWindow::handleBackgroundError(QString msg) { 158 | vna->close(); 159 | QMessageBox::critical(this, "Error", msg); 160 | } 161 | 162 | void MainWindow::on_menuDevice_aboutToShow() { 163 | populateDevicesMenu(); 164 | } 165 | 166 | MainWindow::~MainWindow() 167 | { 168 | vna->stopScan(); 169 | vna->close(); 170 | delete vna; 171 | delete ui; 172 | } 173 | 174 | inline string ssprintf(int maxLen, const char* fmt, ...) { 175 | string tmp(maxLen, '\0'); 176 | va_list args; 177 | va_start(args, fmt); 178 | int len = vsnprintf((char*)tmp.data(), maxLen, fmt, args); 179 | va_end(args); 180 | tmp.resize(len); 181 | return tmp; 182 | } 183 | void MainWindow::on_slider_valueChanged(int value) { 184 | vna->attenuation1 = vna->attenuation2 = vna->maxPower() - value; 185 | ui->label->setText(qs(ssprintf(32, "%d dBm", value))); 186 | } 187 | 188 | void MainWindow::on_r_port1_clicked() { 189 | excitation = 0; 190 | } 191 | 192 | void MainWindow::on_r_port2_clicked() { 193 | excitation = 1; 194 | } 195 | -------------------------------------------------------------------------------- /vna_diagtool/mainwindow.H: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | namespace Ui { 8 | class MainWindow; 9 | } 10 | 11 | namespace QtCharts { 12 | class QChartView; 13 | class QChart; 14 | class QValueAxis; 15 | class QLineSeries; 16 | } 17 | namespace xaxaxa { 18 | class VNADevice; 19 | class VNACalibration; 20 | } 21 | class QTimer; 22 | class MarkerSlider; 23 | class QTextStream; 24 | 25 | using namespace QtCharts; 26 | using namespace xaxaxa; 27 | using namespace std; 28 | 29 | class MainWindow : public QMainWindow 30 | { 31 | Q_OBJECT 32 | 33 | public: 34 | explicit MainWindow(QWidget *parent = 0); 35 | ~MainWindow(); 36 | 37 | void populateDevicesMenu(); 38 | void openDevice(string dev); 39 | double freqAt(int i); 40 | void setCallbacks(); 41 | public slots: 42 | void updateViews(int freqIndex); 43 | void handleBackgroundError(QString msg); 44 | void on_menuDevice_aboutToShow(); 45 | private slots: 46 | void on_slider_valueChanged(int value); 47 | 48 | void on_r_port1_clicked(); 49 | 50 | void on_r_port2_clicked(); 51 | 52 | private: 53 | Ui::MainWindow *ui; 54 | VNADevice* vna=NULL; 55 | int excitation=0; 56 | 57 | vector, 4> > > rawValues; 58 | 59 | 60 | QChart* chart; 61 | QChartView* chartView; 62 | vector series; 63 | QValueAxis* axisX; 64 | QValueAxis* axisY; 65 | }; 66 | 67 | inline QString qs(const string& s) { 68 | return QString::fromStdString(s); 69 | } 70 | 71 | inline double dB(double power) { 72 | return log10(power)*10; 73 | } 74 | 75 | #endif // MAINWINDOW_H 76 | -------------------------------------------------------------------------------- /vna_diagtool/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 726 10 | 449 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 0 23 | 0 24 | 25 | 26 | 27 | 28 | 0 29 | 30 | 31 | 32 | 33 | 34 | 100 35 | 0 36 | 37 | 38 | 39 | -20 dBm 40 | 41 | 42 | 43 | 44 | 45 | 46 | -30 47 | 48 | 49 | 10 50 | 51 | 52 | -20 53 | 54 | 55 | Qt::Horizontal 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 0 67 | 0 68 | 69 | 70 | 71 | 72 | 0 73 | 74 | 75 | 0 76 | 77 | 78 | 79 | 80 | 81 | 100 82 | 0 83 | 84 | 85 | 86 | Excitation 87 | 88 | 89 | 90 | 91 | 92 | 93 | Port 1 94 | 95 | 96 | true 97 | 98 | 99 | 100 | 101 | 102 | 103 | Port 2 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 0 115 | 116 | 117 | 0 118 | 119 | 120 | 0 121 | 122 | 123 | 0 124 | 125 | 126 | 0 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 0 137 | 0 138 | 726 139 | 22 140 | 141 | 142 | 143 | 144 | Device 145 | 146 | 147 | 148 | 149 | 150 | 151 | true 152 | 153 | 154 | true 155 | 156 | 157 | Port 1 excitation 158 | 159 | 160 | 161 | 162 | true 163 | 164 | 165 | Port 2 excitation 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /vna_diagtool/vna_diagtool.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2018-04-26T10:12:14 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui charts 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = vna_diagtool 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which has been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | 26 | SOURCES += \ 27 | main.cpp \ 28 | mainwindow.C 29 | 30 | HEADERS += \ 31 | mainwindow.H 32 | 33 | FORMS += \ 34 | mainwindow.ui 35 | 36 | INCLUDEPATH += $$PWD/../include /usr/local/include 37 | DEPENDPATH += $$PWD/../include 38 | 39 | win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../libxavna/xavna_mock_ui/release/ -lxavna_mock_ui 40 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../libxavna/xavna_mock_ui/debug/ -lxavna_mock_ui 41 | else:unix: LIBS += -L$$PWD/../libxavna/xavna_mock_ui/ -lxavna_mock_ui 42 | 43 | LIBS += -L$$PWD/../libxavna/.libs/ -L/usr/local/lib/ -lxavna 44 | android: LIBS += -L$$PWD/../lib 45 | 46 | -------------------------------------------------------------------------------- /vna_gtk/common_types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef unsigned long ul; 6 | typedef unsigned int ui; 7 | typedef long long ll; 8 | typedef unsigned long long ull; 9 | typedef uint64_t u64; 10 | typedef uint32_t u32; 11 | typedef uint16_t u16; 12 | typedef uint8_t u8; 13 | typedef int8_t s8; 14 | 15 | -------------------------------------------------------------------------------- /vna_gtk/configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(vna, version-0.1, private0x01@gmail.com) 2 | 3 | if test -z $CXXFLAGS; then 4 | CXXFLAGS='-O2 -std=c++0x -fPIC -fwrapv -fno-delete-null-pointer-checks -funsigned-char -fno-strict-aliasing -Wno-pmf-conversions' 5 | fi 6 | 7 | AC_PROG_CXX 8 | AC_LANG(C++) 9 | 10 | AC_SUBST(EXTRA_LIBRARIES) 11 | AC_SUBST(EXTRA_SOURCES) 12 | 13 | PKG_CHECK_MODULES([GTK], [gtkmm-3.0]) 14 | PKG_CHECK_MODULES([FFTW], [fftw3]) 15 | 16 | AC_OUTPUT(Makefile) 17 | -------------------------------------------------------------------------------- /vna_gtk/graph_view.H: -------------------------------------------------------------------------------- 1 | /* 2 | * polarView.C 3 | * 4 | * Copyright 2012 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19 | * MA 02110-1301, USA. 20 | * 21 | * 22 | */ 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | using namespace std; 31 | using namespace Gdk; 32 | using namespace Gtk; 33 | //using namespace ::Cairo; 34 | namespace xaxaxa 35 | { 36 | class GraphView: public Gtk::DrawingArea 37 | { 38 | public: 39 | vector > lines; 40 | vector colors; // colors must have the same length as lines 41 | double minValue=0.; 42 | double maxValue=1.; 43 | double hgridMin=0.; 44 | double hgridSpacing=10.; 45 | 46 | double w,h; 47 | vector selectedPoints; 48 | 49 | double ptX(int index, int totalPoints) { 50 | return index*(w-1)/(totalPoints-1); 51 | } 52 | double ptY(double val) { 53 | return (maxValue-val)*(h-1)/(maxValue-minValue); 54 | } 55 | void do_draw(const ::Cairo::RefPtr< ::Cairo::Context>& gc) 56 | { 57 | w=get_allocation().get_width(); 58 | h=get_allocation().get_height(); 59 | 60 | gc->set_source_rgb(0.5, 0.5, 0.5); 61 | for(double y=hgridMin; ymove_to(0, ptY(y)); 63 | gc->line_to(w, ptY(y)); 64 | gc->stroke(); 65 | } 66 | 67 | for(int i=0;i<(int)lines.size();i++) { 68 | const vector& points = lines[i]; 69 | if(points.size() == 0) continue; 70 | int pts=(int)points.size(); 71 | 72 | uint32_t color = colors[i]; 73 | gc->set_source_rgb(double((color>>16)&0xFF)/255, 74 | double((color>>8)&0xFF)/255,double((color)&0xFF)/255); 75 | 76 | gc->move_to(ptX(0, pts), ptY(points[0])); 77 | for(int j=1;jmove_to(ptX(j, pts), ptY(points[j])); 81 | continue; 82 | } 83 | gc->line_to(ptX(j, pts), ptY(points[j])); 84 | } 85 | gc->stroke(); 86 | } 87 | 88 | gc->set_source_rgb(0.5, 0.5, 0.5); 89 | for(int i=0;i<(int)selectedPoints.size();i++) 90 | draw_point(gc,ptX(selectedPoints[i], (int)lines[i].size()),ptY(lines[i][selectedPoints[i]]),3); 91 | } 92 | void draw_point(const ::Cairo::RefPtr< ::Cairo::Context>& gc, double x, double y, double size) { 93 | gc->arc(x, y, size, 0.0, 2 * M_PI); 94 | gc->stroke(); 95 | } 96 | virtual bool on_motion_notify_event(GdkEventMotion* event) 97 | { 98 | Gtk::DrawingArea::on_motion_notify_event(event); 99 | 100 | return false; 101 | } 102 | virtual bool on_button_press_event(GdkEventButton* event) 103 | { 104 | Gtk::DrawingArea::on_button_press_event(event); 105 | return false; 106 | } 107 | virtual bool on_button_release_event(GdkEventButton* event) 108 | { 109 | Gtk::DrawingArea::on_button_release_event(event); 110 | return false; 111 | } 112 | void do_draw(GdkEventExpose* evt=NULL) 113 | { 114 | Glib::RefPtr window = get_window(); 115 | if(window) 116 | { 117 | ::Cairo::RefPtr< ::Cairo::Context> ctx = window->create_cairo_context(); 118 | if(evt) 119 | { 120 | ctx->rectangle(evt->area.x, evt->area.y, evt->area.width, evt->area.height); 121 | ctx->clip(); 122 | } 123 | do_draw(ctx); 124 | } 125 | } 126 | virtual bool on_expose_event(GdkEventExpose* evt) 127 | { 128 | printf("on_expose_event\n"); 129 | do_draw(evt); 130 | return false; 131 | } 132 | virtual bool on_draw(const ::Cairo::RefPtr<::Cairo::Context>& cr) { 133 | do_draw(cr); 134 | return false; 135 | } 136 | GraphView(): Gtk::DrawingArea() 137 | { 138 | set_app_paintable(true); 139 | set_double_buffered(true); 140 | set_redraw_on_allocate(true); 141 | set_events(get_events()|EXPOSURE_MASK|POINTER_MOTION_MASK|BUTTON_MOTION_MASK|BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK); 142 | } 143 | }; 144 | } 145 | 146 | -------------------------------------------------------------------------------- /vna_gtk/polar_view.H: -------------------------------------------------------------------------------- 1 | /* 2 | * polarView.C 3 | * 4 | * Copyright 2012 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19 | * MA 02110-1301, USA. 20 | * 21 | * 22 | */ 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | using namespace std; 31 | using namespace Gdk; 32 | using namespace Gtk; 33 | //using namespace ::Cairo; 34 | namespace xaxaxa 35 | { 36 | class PolarView: public Gtk::DrawingArea 37 | { 38 | public: 39 | vector > points; 40 | double scale=1.; 41 | double margin=10; // pixels 42 | 43 | double w,h; 44 | double r,centerX,centerY; 45 | int selectedPoint=0; 46 | bool persistence = false; 47 | //ARGB 48 | uint32_t cursorColor = 0xffffff00; 49 | 50 | ::Cairo::RefPtr< ::Cairo::ImageSurface > img; 51 | 52 | 53 | double ptX(double x) { 54 | return centerX+x/scale*r; 55 | } 56 | double ptY(double y) { 57 | return centerY-y/scale*r; 58 | } 59 | void draw_grid(const ::Cairo::RefPtr< ::Cairo::Context>& gc) { 60 | w=get_allocation().get_width(); 61 | h=get_allocation().get_height(); 62 | 63 | // calculate position and radius of smith chart 64 | centerX=w/2; 65 | centerY=h/2; 66 | r=w/2; 67 | if(h/2set_line_width(2.0); 72 | gc->arc(centerX, centerY, r, 0.0, 2 * M_PI); 73 | gc->stroke(); 74 | 75 | gc->set_line_width(1.0); 76 | gc->set_source_rgb(.2,.2,.2); 77 | 78 | // draw constant resistance circles 79 | for(int i=1;i<4;i++) { 80 | gc->arc(centerX+r-r/4*i, centerY, r/4*i, 0.0, 2 * M_PI); 81 | gc->stroke(); 82 | } 83 | 84 | // draw constant reactance circles 85 | gc->save(); 86 | gc->arc(centerX, centerY, r, 0.0, 2 * M_PI); 87 | gc->clip(); 88 | int n=1; 89 | for(int i=1;i<4;i++) { 90 | gc->arc(centerX+r, centerY+r/2*n, r/2*n, 0.0, 2 * M_PI); 91 | gc->stroke(); 92 | gc->arc(centerX+r, centerY-r/2*n, r/2*n, 0.0, 2 * M_PI); 93 | gc->stroke(); 94 | n*=2; 95 | } 96 | gc->restore(); 97 | 98 | // draw center line 99 | gc->move_to(centerX-r,centerY); 100 | gc->line_to(centerX+r,centerY); 101 | gc->stroke(); 102 | } 103 | void draw_chart(const ::Cairo::RefPtr< ::Cairo::Context>& gc) 104 | { 105 | if(points.size()==0) return; 106 | for(int i=1;i<(int)points.size();i++) { 107 | if(isnan(points[i-1].real()) || isnan(points[i].real())) continue; 108 | gc->move_to(ptX(points[i-1].real()), ptY(points[i-1].imag())); 109 | gc->line_to(ptX(points[i].real()), ptY(points[i].imag())); 110 | gc->stroke(); 111 | } 112 | } 113 | void do_draw(const ::Cairo::RefPtr< ::Cairo::Context>& gc) { 114 | draw_grid(gc); 115 | if(persistence) { 116 | if(img) { 117 | gc->set_source(img, 0, 0); 118 | gc->paint(); 119 | } 120 | } else { 121 | gc->set_line_width(2.0); 122 | gc->set_source_rgb(0,0,1); 123 | draw_chart(gc); 124 | } 125 | gc->set_line_width(2.0); 126 | uint32_t c = cursorColor; 127 | gc->set_source_rgba(double((c>>16)&0xFF)/255, double((c>>8)&0xFF)/255, 128 | double((c)&0xFF)/255, double((c>>24)&0xFF)/255); 129 | draw_point(gc,points[selectedPoint].real(),points[selectedPoint].imag(),3); 130 | } 131 | void draw_point(const ::Cairo::RefPtr< ::Cairo::Context>& gc, double re, double im, double size) { 132 | double pointX=centerX+re/scale*r; 133 | double pointY=centerY-im/scale*r; 134 | gc->arc(pointX, pointY, size, 0.0, 2 * M_PI); 135 | gc->stroke(); 136 | } 137 | virtual bool on_motion_notify_event(GdkEventMotion* event) 138 | { 139 | Gtk::DrawingArea::on_motion_notify_event(event); 140 | 141 | return false; 142 | } 143 | virtual bool on_button_press_event(GdkEventButton* event) 144 | { 145 | Gtk::DrawingArea::on_button_press_event(event); 146 | return false; 147 | } 148 | virtual bool on_button_release_event(GdkEventButton* event) 149 | { 150 | Gtk::DrawingArea::on_button_release_event(event); 151 | return false; 152 | } 153 | void do_draw(GdkEventExpose* evt=NULL) 154 | { 155 | Glib::RefPtr window = get_window(); 156 | if(window) 157 | { 158 | ::Cairo::RefPtr< ::Cairo::Context> ctx = window->create_cairo_context(); 159 | if(evt) 160 | { 161 | ctx->rectangle(evt->area.x, evt->area.y, evt->area.width, evt->area.height); 162 | ctx->clip(); 163 | } 164 | do_draw(ctx); 165 | } 166 | } 167 | void clearPersistence() { 168 | int w=(int)get_allocation().get_width(); 169 | int h=(int)get_allocation().get_height(); 170 | img=::Cairo::ImageSurface::create(::Cairo::FORMAT_ARGB32,w,h); 171 | } 172 | void commitTrace() { 173 | if(!persistence) return; 174 | int w=(int)get_allocation().get_width(); 175 | int h=(int)get_allocation().get_height(); 176 | if(!img || img->get_width()!=w || img->get_height()!=h) 177 | clearPersistence(); 178 | ::Cairo::RefPtr< ::Cairo::Context > imgCtx = ::Cairo::Context::create(img); 179 | imgCtx->set_line_width(2.0); 180 | imgCtx->set_source_rgba(0,0,1, 1); 181 | draw_chart(imgCtx); 182 | } 183 | virtual bool on_expose_event(GdkEventExpose* evt) 184 | { 185 | printf("on_expose_event\n"); 186 | do_draw(evt); 187 | return false; 188 | } 189 | virtual bool on_draw(const ::Cairo::RefPtr<::Cairo::Context>& cr) { 190 | do_draw(cr); 191 | return false; 192 | } 193 | PolarView(): Gtk::DrawingArea() 194 | { 195 | set_app_paintable(true); 196 | set_double_buffered(true); 197 | set_redraw_on_allocate(true); 198 | set_events(get_events()|EXPOSURE_MASK|POINTER_MOTION_MASK|BUTTON_MOTION_MASK|BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK); 199 | } 200 | }; 201 | } 202 | 203 | -------------------------------------------------------------------------------- /vna_gtk/vna_ui_core.H: -------------------------------------------------------------------------------- 1 | #define TOKEN_TO_STRING(TOK) # TOK 2 | using namespace std; 3 | 4 | typedef array,2> complex2; 5 | static const int reflIndex=0, thruIndex=1; 6 | 7 | 8 | // to be implemented by ui code 9 | // pop up an info dialog with msg 10 | void alert(string msg); 11 | // update the ith point on the graph 12 | void updateGraph(int i, complex2 values); 13 | // update the ith point on the time domain graph 14 | void updateTimeGraph(int i, complex2 values); 15 | // called whenever a full frequency sweep is done 16 | void sweepCompleted(); 17 | 18 | 19 | // exported functions 20 | extern double Z0; 21 | 22 | extern void* xavna_dev; 23 | extern int nPoints; // how many frequency points; do not modify; call resizeVectors() 24 | extern int startFreq; // start frequency in kHz 25 | extern int freqStep; // frequency step in kHz 26 | extern bool use_cal; // whether calibration is in effect; do not modify 27 | extern bool refreshThreadShouldExit; // set to true to cause refreshThread to exit 28 | 29 | 30 | static const int timeScale=3; 31 | static const int nCal = 4; 32 | static const double freqMultiplier=0.001; 33 | 34 | // indexed by CAL_* constants 35 | extern array, 4> calibrationReferences; 36 | 37 | // you must call this function from a secondary thread (non UI thread) 38 | // to perform continuous refresh 39 | // make sure xavna_dev is initialized before calling 40 | void* refreshThread(void* v); 41 | // take a measurement over the complete frequency range 42 | void takeMeasurement(function)> cb); 43 | // using 4 measurements (short, open, load, thru) apply calibration to the graph 44 | void applySOLT(); 45 | // disable calibration 46 | void clearCalibration(); 47 | string saveCalibration(); 48 | bool loadCalibration(char* data, int size); 49 | // change nPoints to n; do not call when refreshThread is running 50 | void resizeVectors(int n); 51 | 52 | vector > extract(vector in, int i); 53 | 54 | 55 | enum { 56 | CAL_SHORT=0, 57 | CAL_OPEN, 58 | CAL_LOAD, 59 | CAL_THRU 60 | }; 61 | 62 | 63 | 64 | // convenience functions 65 | 66 | // freq is in Hz, Z is in ohms 67 | inline double capacitance_inductance(double freq, double Z) { 68 | if(Z>0) return Z/(2*M_PI*freq); 69 | return 1./(2*Z*M_PI*freq); 70 | } 71 | // freq is in Hz, Y is in mhos 72 | inline double capacitance_inductance_Y(double freq, double Y) { 73 | if(Y<0) return -1./(2*Y*M_PI*freq); 74 | return -Y/(2*M_PI*freq); 75 | } 76 | inline double si_scale(double val) { 77 | double val2 = fabs(val); 78 | if(val2>1e12) return val*1e-12; 79 | if(val2>1e9) return val*1e-9; 80 | if(val2>1e6) return val*1e-6; 81 | if(val2>1e3) return val*1e-3; 82 | if(val2>1e0) return val; 83 | if(val2>1e-3) return val*1e3; 84 | if(val2>1e-6) return val*1e6; 85 | if(val2>1e-9) return val*1e9; 86 | if(val2>1e-12) return val*1e12; 87 | return val*1e15; 88 | } 89 | inline const char* si_unit(double val) { 90 | val = fabs(val); 91 | if(val>1e12) return "T"; 92 | if(val>1e9) return "G"; 93 | if(val>1e6) return "M"; 94 | if(val>1e3) return "k"; 95 | if(val>1e0) return ""; 96 | if(val>1e-3) return "m"; 97 | if(val>1e-6) return "u"; 98 | if(val>1e-9) return "n"; 99 | if(val>1e-12) return "p"; 100 | return "f"; 101 | } 102 | inline string ssprintf(int maxLen, const char* fmt, ...) { 103 | string tmp(maxLen, '\0'); 104 | va_list args; 105 | va_start(args, fmt); 106 | vsnprintf((char*)tmp.data(), maxLen, fmt, args); 107 | va_end(args); 108 | return tmp; 109 | } 110 | 111 | 112 | inline double dB(double power) { 113 | return log10(power)*10; 114 | } 115 | inline double gauss(double x, double m, double s) { 116 | static const double inv_sqrt_2pi = 0.3989422804014327; 117 | double a = (x - m) / s; 118 | return inv_sqrt_2pi / s * std::exp(-0.5d * a * a); 119 | } 120 | 121 | inline int timePoints() { 122 | //return (nPoints*3-1); 123 | return nPoints*timeScale; 124 | } 125 | 126 | // returns MHz 127 | inline double freqAt(int i) { 128 | return (startFreq+i*freqStep)*freqMultiplier; 129 | } 130 | // returns ns 131 | inline double timeAt(int i) { 132 | double fs=double(freqStep)*freqMultiplier; // MHz 133 | double totalTime = 1000./fs/2; // ns 134 | return double(i)*totalTime/double(timePoints())/2; 135 | } 136 | 137 | -------------------------------------------------------------------------------- /vna_qt/.gitignore: -------------------------------------------------------------------------------- 1 | vna_qt 2 | *-deployment-settings.json 3 | 4 | -------------------------------------------------------------------------------- /vna_qt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | include_directories(${Qt5Charts_INCLUDE_DIRS}) 3 | 4 | # Instruct CMake to run moc automatically when needed 5 | set(CMAKE_AUTOMOC ON) 6 | # Create code from a list of Qt designer ui files 7 | set(CMAKE_AUTOUIC ON) 8 | 9 | set(vna_qt_SRCS 10 | polarview.C 11 | mainwindow.C 12 | main.C 13 | markerslider.C 14 | impedancedisplay.C 15 | frequencydialog.C 16 | graphpanel.C 17 | configureviewdialog.C 18 | touchstone.C 19 | calkitsettingsdialog.C 20 | calkitsettings.C 21 | networkview.C 22 | dtfwindow.C) 23 | 24 | set(vna_qt_FRMS 25 | mainwindow.ui 26 | markerslider.ui 27 | impedancedisplay.ui 28 | frequencydialog.ui 29 | graphpanel.ui 30 | configureviewdialog.ui 31 | calkitsettingsdialog.ui 32 | calkitsettingswidget.ui 33 | dtfwindow.ui 34 | graphlimitsdialog.ui) 35 | 36 | set(vna_qt_HDRS 37 | polarview.H 38 | mainwindow.H 39 | markerslider.H 40 | impedancedisplay.H 41 | utility.H 42 | frequencydialog.H 43 | graphpanel.H 44 | configureviewdialog.H 45 | touchstone.H 46 | calkitsettingsdialog.H 47 | calkitsettings.H 48 | networkview.H 49 | dtfwindow.H) 50 | 51 | 52 | add_executable(vna_qt ${vna_qt_SRCS} ${vna_qt_FRMS} ${vna_qt_HDRS}) 53 | 54 | target_link_libraries(vna_qt Qt5::Charts ${FFTW3_LIBRARIES} xavna xavna_mock_ui) 55 | 56 | # Install destinations 57 | install(TARGETS vna_qt RUNTIME DESTINATION ${BIN_INSTALL_DIR}) 58 | -------------------------------------------------------------------------------- /vna_qt/add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | 51 | 52 | 53 | Olivier Fourdan 54 | 55 | 56 | 57 | 58 | 59 | 64 | 67 | 71 | 76 | 81 | 82 | 87 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /vna_qt/calibrationfinetunedialog.C: -------------------------------------------------------------------------------- 1 | #include "calibrationfinetunedialog.H" 2 | #include "ui_calibrationfinetunedialog.h" 3 | #include "utility.H" 4 | 5 | CalibrationFineTuneDialog::CalibrationFineTuneDialog(QWidget *parent) : 6 | QDialog(parent), 7 | ui(new Ui::CalibrationFineTuneDialog) 8 | { 9 | ui->setupUi(this); 10 | } 11 | 12 | CalibrationFineTuneDialog::~CalibrationFineTuneDialog() 13 | { 14 | delete ui; 15 | } 16 | 17 | void CalibrationFineTuneDialog::init(const VNACalibration *cal, const vector > &calStdModels, double startFreqHz, double stepFreqHz) { 18 | this->cal = cal; 19 | this->origModels = calStdModels; 20 | this->startFreqHz = startFreqHz; 21 | this->stepFreqHz = stepFreqHz; 22 | calStds = cal->getRequiredStandards(); 23 | calStdShortIndex.clear(); 24 | calStdOpenIndex.clear(); 25 | calStdLoadIndex.clear(); 26 | int i = 0; 27 | for(auto calstd: cal->getRequiredStandards()) { 28 | string name = calstd[0]; 29 | if(name.size() > 5 && name.substr(0, 5) == "short") 30 | calStdShortIndex.push_back(i); 31 | if(name.size() > 4 && name.substr(0, 4) == "open") 32 | calStdOpenIndex.push_back(i); 33 | if(name.size() > 4 && name.substr(0, 4) == "load") 34 | calStdLoadIndex.push_back(i); 35 | i++; 36 | } 37 | } 38 | 39 | void CalibrationFineTuneDialog::toSettings(CalKitSettings &cks) { 40 | for(auto i: calStdLoadIndex) 41 | saveModel(cks, i); 42 | for(auto i: calStdOpenIndex) 43 | saveModel(cks, i); 44 | for(auto i: calStdShortIndex) 45 | saveModel(cks, i); 46 | } 47 | 48 | void CalibrationFineTuneDialog::saveModel(CalKitSettings &cks, int modelIndex) { 49 | int nPoints = (int) newModels.size(); 50 | string name = calStds.at(modelIndex)[0]; 51 | 52 | cks.calKitNames[name]; // create the entry if it doesn't exist 53 | 54 | auto& values = cks.calKitModels[name].values; 55 | values.clear(); 56 | for(int i=0; is_short->value()) * 1e-14; 77 | double offsOpen = double(ui->s_open->value()) * 1e-14; 78 | 79 | // imaginary component of S11 @ 1GHz 80 | double parasitic = double(ui->s_load->value()) * 1e-5; 81 | complex s11Load = {0., parasitic}; 82 | complex ZLoad = -50.*(s11Load+1.)/(s11Load-1.); 83 | complex YLoad = 1./ZLoad; 84 | // series inductance 85 | double ind = capacitance_inductance(1e9, ZLoad.imag()); 86 | // shunt capacitance 87 | double cap = capacitance_inductance_Y(1e9, YLoad.imag()); 88 | 89 | ui->t_short->setText(qs(ssprintf(32, "%.2fps", offsShort*1e12))); 90 | ui->t_open->setText(qs(ssprintf(32, "%.2fps", offsOpen*1e12))); 91 | if(parasitic > 0) 92 | ui->t_load->setText(qs(ssprintf(32, "%.0fpH", ind*1e12))); 93 | else 94 | ui->t_load->setText(qs(ssprintf(32, "%.0ffF", -cap*1e15))); 95 | 96 | for(int i: calStdShortIndex) 97 | addLengthOffset(i, offsShort); 98 | for(int i: calStdOpenIndex) 99 | addLengthOffset(i, offsOpen); 100 | for(int i: calStdLoadIndex) 101 | addParasitic(i, parasitic); 102 | modelsChanged(); 103 | } 104 | 105 | void CalibrationFineTuneDialog::addLengthOffset(int modelIndex, double offset) { 106 | for(size_t i=0; is_short->setValue(0); 123 | } 124 | void CalibrationFineTuneDialog::on_b_r_open_clicked() { 125 | ui->s_open->setValue(0); 126 | } 127 | void CalibrationFineTuneDialog::on_b_r_load_clicked() { 128 | ui->s_load->setValue(0); 129 | } 130 | -------------------------------------------------------------------------------- /vna_qt/calibrationfinetunedialog.H: -------------------------------------------------------------------------------- 1 | #ifndef CALIBRATIONFINETUNEDIALOG_H 2 | #define CALIBRATIONFINETUNEDIALOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "calkitsettings.H" 11 | using namespace std; 12 | using namespace xaxaxa; 13 | 14 | namespace Ui { 15 | class CalibrationFineTuneDialog; 16 | } 17 | 18 | class CalibrationFineTuneDialog : public QDialog 19 | { 20 | Q_OBJECT 21 | 22 | public: 23 | // holds the original models supplied to the init() function. 24 | vector > origModels; 25 | 26 | // holds the current adjusted models when modelsChanged() is called or after dialog is closed. 27 | vector > newModels; 28 | 29 | // called when the user makes an adjustment. 30 | function modelsChanged; 31 | 32 | explicit CalibrationFineTuneDialog(QWidget *parent = nullptr); 33 | ~CalibrationFineTuneDialog(); 34 | 35 | 36 | // calStdModels: indexed by [freqIndex][modelIndex], 37 | // where modelIndex is the index of the calibration standard corresponding to cal->getRequiredStandards() 38 | void init(const VNACalibration* cal, const vector >& calStdModels, double startFreqHz, double stepFreqHz); 39 | 40 | // update cal kit settings with adjusted parameters 41 | void toSettings(CalKitSettings& cks); 42 | void saveModel(CalKitSettings& cks, int modelIndex); 43 | 44 | private slots: 45 | void on_s_short_valueChanged(int value); 46 | void on_s_open_valueChanged(int value); 47 | 48 | void on_b_r_short_clicked(); 49 | 50 | void on_b_r_open_clicked(); 51 | 52 | void on_s_load_valueChanged(int value); 53 | 54 | void on_b_r_load_clicked(); 55 | 56 | private: 57 | Ui::CalibrationFineTuneDialog *ui; 58 | const VNACalibration* cal; 59 | double startFreqHz; 60 | double stepFreqHz; 61 | 62 | // list of all indices of origModels that are short, open, and load 63 | vector calStdShortIndex, calStdOpenIndex, calStdLoadIndex; 64 | 65 | vector > calStds; 66 | 67 | void updateModels(); 68 | void addLengthOffset(int modelIndex, double offset); 69 | // parasitic is the imaginary component of S11 @ 1GHz 70 | void addParasitic(int modelIndex, double parasitic); 71 | }; 72 | 73 | #endif // CALIBRATIONFINETUNEDIALOG_H 74 | -------------------------------------------------------------------------------- /vna_qt/calkitsettings.C: -------------------------------------------------------------------------------- 1 | #include "calkitsettings.H" 2 | #include 3 | 4 | QDataStream &operator<<(QDataStream &out, const complex &myObj) { 5 | const double* val = reinterpret_cast(&myObj); 6 | out << val[0]; 7 | out << val[1]; 8 | return out; 9 | } 10 | 11 | QDataStream &operator>>(QDataStream &in, complex &myObj) { 12 | double* val = reinterpret_cast(&myObj); 13 | in >> val[0]; 14 | in >> val[1]; 15 | return in; 16 | } 17 | 18 | 19 | QDataStream &operator<<(QDataStream &out, const string &myObj) { 20 | int sz = (int)myObj.length(); 21 | out << sz; 22 | out.writeRawData(myObj.data(), sz); 23 | return out; 24 | } 25 | 26 | QDataStream &operator>>(QDataStream &in, string &myObj) { 27 | int sz = 0; 28 | in >> sz; 29 | myObj.resize(sz); 30 | if(in.readRawData(&myObj[0], sz) != sz) 31 | throw runtime_error("short read from QDataStream"); 32 | return in; 33 | } 34 | 35 | 36 | QDataStream &operator<<(QDataStream &out, const MatrixXcd &myObj) { 37 | out << (int)myObj.rows(); 38 | out << (int)myObj.cols(); 39 | for(int i=0; i<(myObj.cols()*myObj.rows()); i++) 40 | out << myObj(i); 41 | return out; 42 | } 43 | 44 | QDataStream &operator>>(QDataStream &in, MatrixXcd &myObj) { 45 | int rows,cols; 46 | in >> rows; 47 | in >> cols; 48 | if(rows<0 || cols<0 || rows>1024 || cols>1024) { 49 | fprintf(stderr, "warning: matrix not deserialized because of invalid size %d x %d\n", rows,cols); 50 | return in; 51 | } 52 | myObj.resize(rows,cols); 53 | for(int i=0; i<(myObj.cols()*myObj.rows()); i++) 54 | in >> myObj(i); 55 | return in; 56 | } 57 | 58 | template 59 | QDataStream &operator<<(QDataStream &out, const map &m); 60 | template 61 | QDataStream &operator>>(QDataStream &in, map &m); 62 | 63 | 64 | template 65 | QDataStream &operator<<(QDataStream &out, const map &m) { 66 | int sz = m.size(); 67 | out << sz; 68 | for(auto it=m.begin(); it!=m.end(); it++) { 69 | out << (*it).first; 70 | out << (*it).second; 71 | } 72 | return out; 73 | } 74 | template 75 | QDataStream &operator>>(QDataStream &in, map &m) { 76 | int sz = 0; 77 | in >> sz; 78 | m.clear(); 79 | if(sz<0 || sz > 1024*1024) { 80 | fprintf(stderr, "warning: map not deserialized because of invalid length %d\n", sz); 81 | return in; 82 | } 83 | for(int i=0;i> key; 86 | in >> m[key]; 87 | } 88 | return in; 89 | } 90 | 91 | QDataStream &operator<<(QDataStream &out, const SParamSeries &myObj) { 92 | out << myObj.values; 93 | return out; 94 | } 95 | 96 | QDataStream &operator>>(QDataStream &in, SParamSeries &myObj) { 97 | in >> myObj.values; 98 | return in; 99 | } 100 | 101 | 102 | QDataStream &operator<<(QDataStream &out, const CalKitSettings &myObj) { 103 | out << myObj.calKitModels; 104 | out << myObj.calKitNames; 105 | return out; 106 | } 107 | 108 | QDataStream &operator>>(QDataStream &in, CalKitSettings &myObj) { 109 | in >> myObj.calKitModels; 110 | in >> myObj.calKitNames; 111 | return in; 112 | } 113 | 114 | 115 | 116 | 117 | void serialize(ostream &out, const SParamSeries &obj) { 118 | 119 | } 120 | 121 | void deserialize(istream &in, SParamSeries &obj) { 122 | 123 | } 124 | 125 | void serialize(ostream &out, const CalKitSettings &obj) { 126 | 127 | } 128 | 129 | void deserialize(istream &in, CalKitSettings &obj) { 130 | 131 | } 132 | -------------------------------------------------------------------------------- /vna_qt/calkitsettings.H: -------------------------------------------------------------------------------- 1 | #ifndef CALKITSETTINGS_H 2 | #define CALKITSETTINGS_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "touchstone.H" 9 | using namespace std; 10 | using namespace xaxaxa; 11 | 12 | // the in-memory structure that holds the calibration kit settings 13 | struct CalKitSettings { 14 | // if any given cal kit type is not present here, it should be assumed 15 | // to use ideal parameters 16 | map calKitModels; 17 | map calKitNames; 18 | }; 19 | #ifdef Q_DECLARE_METATYPE 20 | Q_DECLARE_METATYPE(CalKitSettings); 21 | #endif 22 | 23 | class QDataStream; 24 | 25 | // binary serializers for QSettings 26 | 27 | QDataStream &operator<<(QDataStream &out, const complex &myObj); 28 | QDataStream &operator>>(QDataStream &in, complex &myObj); 29 | 30 | QDataStream &operator<<(QDataStream &out, const string &myObj); 31 | QDataStream &operator>>(QDataStream &in, string &myObj); 32 | 33 | QDataStream &operator<<(QDataStream &out, const MatrixXcd &myObj); 34 | QDataStream &operator>>(QDataStream &in, MatrixXcd &myObj); 35 | 36 | QDataStream &operator<<(QDataStream &out, const SParamSeries &myObj); 37 | QDataStream &operator>>(QDataStream &in, SParamSeries &myObj); 38 | 39 | QDataStream &operator<<(QDataStream &out, const CalKitSettings &myObj); 40 | QDataStream &operator>>(QDataStream &in, CalKitSettings &myObj); 41 | 42 | // text serializers 43 | void serialize(ostream& out, const SParamSeries& obj); 44 | void deserialize(istream& in, SParamSeries& obj); 45 | 46 | void serialize(ostream& out, const CalKitSettings& obj); 47 | void deserialize(istream &in, CalKitSettings &obj); 48 | 49 | #endif // CALKITSETTINGS_H 50 | -------------------------------------------------------------------------------- /vna_qt/calkitsettingsdialog.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "calkitsettingsdialog.H" 8 | #include "ui_calkitsettingsdialog.h" 9 | #include "ui_calkitsettingswidget.h" 10 | #include "utility.H" 11 | #include "touchstone.H" 12 | 13 | using namespace xaxaxa; 14 | using namespace std; 15 | 16 | CalKitSettingsDialog::CalKitSettingsDialog(QWidget *parent) : 17 | QDialog(parent), 18 | ui(new Ui::CalKitSettingsDialog) 19 | { 20 | ui->setupUi(this); 21 | } 22 | 23 | CalKitSettingsDialog::~CalKitSettingsDialog() 24 | { 25 | delete ui; 26 | } 27 | 28 | void CalKitSettingsDialog::fromSettings(const CalKitSettings &settings) { 29 | info.clear(); 30 | map calStdDesc; 31 | for(const VNACalibration* cal: calibrationTypes) { 32 | for(auto tmp:cal->getRequiredStandards()) { 33 | calStdDesc[tmp[0]] = tmp[1]; 34 | } 35 | } 36 | 37 | QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); 38 | //layout->setMargin(0); 39 | delete ui->w_content->layout(); 40 | ui->w_content->setLayout(layout); 41 | 42 | for(auto& item:idealCalStds) { 43 | string name = item.first; 44 | string desc = name; 45 | auto& inf = info[name]; 46 | if(calStdDesc.find(name) != calStdDesc.end()) 47 | desc = calStdDesc[name]; 48 | 49 | Ui::CalKitSettingsWidget& ui1 = inf.ui; 50 | QWidget* w = new QWidget(); 51 | ui1.setupUi(w); 52 | layout->addWidget(w); 53 | 54 | ui1.l_desc->setText(qs(desc)); 55 | 56 | auto it = settings.calKitModels.find(name); 57 | if(it != settings.calKitModels.end() && (*it).second.values.size() != 0) { 58 | ui1.r_s_param->setChecked(true); 59 | const SParamSeries& series = (*it).second; 60 | inf.data = series; 61 | inf.useIdeal = false; 62 | auto it2 = settings.calKitNames.find(name); 63 | if(it2 != settings.calKitNames.end()) 64 | inf.fileName = (*it2).second; 65 | ui1.l_status->setText(generateLabel(inf)); 66 | } else { 67 | inf.useIdeal = true; 68 | ui1.l_status->setText(""); 69 | } 70 | 71 | connect(ui1.r_ideal, &QRadioButton::clicked, [this, name](){ 72 | auto& inf = info[name]; 73 | inf.useIdeal = true; 74 | inf.ui.l_status->setText(""); 75 | }); 76 | 77 | connect(ui1.r_s_param, &QRadioButton::clicked, [this, name](){ 78 | auto& inf = info[name]; 79 | QString fileName = QFileDialog::getOpenFileName(this, 80 | tr("Open S parameters file"), "", 81 | tr("S parameters (*.s1p *.s2p);;All Files (*)")); 82 | if (fileName.isEmpty()) goto fail; 83 | { 84 | QFile file(fileName); 85 | if (!file.open(QIODevice::ReadOnly)) { 86 | QMessageBox::warning(this, tr("Unable to open file"), file.errorString()); 87 | goto fail; 88 | } 89 | { 90 | QTextStream stream(&file); 91 | string data = stream.readAll().toStdString(); 92 | 93 | SParamSeries series; 94 | int nPorts; 95 | try { 96 | QFileInfo fileInfo(fileName); 97 | parseTouchstone(data,nPorts,series.values); 98 | inf.useIdeal = false; 99 | inf.data = series; 100 | inf.fileName = fileName.toStdString(); 101 | inf.ui.l_status->setText(generateLabel(inf)); 102 | } catch(exception& ex) { 103 | QMessageBox::warning(this, tr("Error parsing S parameter file"), ex.what()); 104 | goto fail; 105 | } 106 | } 107 | } 108 | return; 109 | fail: 110 | // revert radiobutton state 111 | inf.ui.r_ideal->setChecked(inf.useIdeal); 112 | }); 113 | } 114 | } 115 | 116 | void CalKitSettingsDialog::toSettings(CalKitSettings &settings) { 117 | settings.calKitModels.clear(); 118 | settings.calKitNames.clear(); 119 | for(auto& item:idealCalStds) { 120 | string name = item.first; 121 | auto it = info.find(name); 122 | if(it == info.end()) continue; 123 | if(!(*it).second.useIdeal) { 124 | settings.calKitModels[name] = (*it).second.data; 125 | settings.calKitNames[name] = (*it).second.fileName; 126 | } 127 | } 128 | } 129 | 130 | QString CalKitSettingsDialog::generateLabel(const CalKitSettingsDialog::calKitInfo &inf) { 131 | QString status; 132 | status = qs(inf.fileName); 133 | if(status == "") 134 | status = ""; 135 | 136 | status = status.toHtmlEscaped(); 137 | 138 | double startFreqHz = inf.data.values.begin()->first; 139 | double stopFreqHz = inf.data.values.rbegin()->first; 140 | status = "
" + status
141 |             + qs(ssprintf(256, "\n   %8.3f MHz - %8.3f MHz, %d points
", 142 | startFreqHz*1e-6, stopFreqHz*1e-6, (int)inf.data.values.size())); 143 | return status; 144 | } 145 | -------------------------------------------------------------------------------- /vna_qt/calkitsettingsdialog.H: -------------------------------------------------------------------------------- 1 | #ifndef CALKITSETTINGSDIALOG_H 2 | #define CALKITSETTINGSDIALOG_H 3 | 4 | #include 5 | #include "calkitsettings.H" 6 | #include "ui_calkitsettingswidget.h" 7 | namespace Ui { 8 | class CalKitSettingsDialog; 9 | } 10 | 11 | class CalKitSettingsDialog : public QDialog 12 | { 13 | Q_OBJECT 14 | 15 | struct calKitInfo { 16 | Ui::CalKitSettingsWidget ui; 17 | string fileName; 18 | SParamSeries data; 19 | bool useIdeal; 20 | }; 21 | public: 22 | explicit CalKitSettingsDialog(QWidget *parent = 0); 23 | ~CalKitSettingsDialog(); 24 | 25 | void fromSettings(const CalKitSettings& settings); 26 | void toSettings(CalKitSettings& settings); 27 | 28 | QString generateLabel(const calKitInfo& inf); 29 | map info; 30 | private: 31 | Ui::CalKitSettingsDialog *ui; 32 | }; 33 | 34 | #endif // CALKITSETTINGSDIALOG_H 35 | -------------------------------------------------------------------------------- /vna_qt/calkitsettingsdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CalKitSettingsDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 772 10 | 511 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | 21 | 0 22 | 0 23 | 24 | 25 | 26 | 27 | 12 28 | 29 | 30 | 31 | Calibration kit parameters 32 | 33 | 34 | 35 | 36 | 37 | 38 | 1 39 | 40 | 41 | true 42 | 43 | 44 | 45 | 46 | 0 47 | 0 48 | 752 49 | 16 50 | 51 | 52 | 53 | 54 | 0 55 | 0 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | Qt::Horizontal 65 | 66 | 67 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | buttonBox 77 | accepted() 78 | CalKitSettingsDialog 79 | accept() 80 | 81 | 82 | 248 83 | 254 84 | 85 | 86 | 157 87 | 274 88 | 89 | 90 | 91 | 92 | buttonBox 93 | rejected() 94 | CalKitSettingsDialog 95 | reject() 96 | 97 | 98 | 316 99 | 260 100 | 101 | 102 | 286 103 | 274 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /vna_qt/calkitsettingswidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CalKitSettingsWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 611 10 | 45 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | 21 | 0 22 | 45 23 | 24 | 25 | 26 | Form 27 | 28 | 29 | 30 | 0 31 | 32 | 33 | 0 34 | 35 | 36 | 0 37 | 38 | 39 | 0 40 | 41 | 42 | 43 | 44 | 45 | 0 46 | 0 47 | 48 | 49 | 50 | 51 | 130 52 | 0 53 | 54 | 55 | 56 | Open (port 1) 57 | 58 | 59 | 5 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 0 68 | 0 69 | 70 | 71 | 72 | Ideal 73 | 74 | 75 | true 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 0 84 | 0 85 | 86 | 87 | 88 | S-Parameter 89 | 90 | 91 | 92 | 93 | 94 | 95 | color: #0066aa; font-family: Monospace 96 | 97 | 98 | aaaaa<br />sssss 99 | 100 | 101 | Qt::RichText 102 | 103 | 104 | 8 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /vna_qt/configureviewdialog.C: -------------------------------------------------------------------------------- 1 | #include "configureviewdialog.H" 2 | #include "ui_configureviewdialog.h" 3 | 4 | ConfigureViewDialog::ConfigureViewDialog(QWidget *parent) : 5 | QDialog(parent), 6 | ui(new Ui::ConfigureViewDialog) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | ConfigureViewDialog::~ConfigureViewDialog() 12 | { 13 | delete ui; 14 | } 15 | -------------------------------------------------------------------------------- /vna_qt/configureviewdialog.H: -------------------------------------------------------------------------------- 1 | #ifndef CONFIGUREVIEWDIALOG_H 2 | #define CONFIGUREVIEWDIALOG_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class ConfigureViewDialog; 8 | } 9 | 10 | class ConfigureViewDialog : public QDialog 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit ConfigureViewDialog(QWidget *parent = 0); 16 | ~ConfigureViewDialog(); 17 | 18 | private: 19 | Ui::ConfigureViewDialog *ui; 20 | }; 21 | 22 | #endif // CONFIGUREVIEWDIALOG_H 23 | -------------------------------------------------------------------------------- /vna_qt/dtfwindow.C: -------------------------------------------------------------------------------- 1 | #define _USE_MATH_DEFINES 2 | #include "dtfwindow.H" 3 | #include "ui_dtfwindow.h" 4 | #include "graphpanel.H" 5 | #include "utility.H" 6 | #include 7 | #include 8 | #include 9 | 10 | DTFWindow::DTFWindow(QWidget *parent) : 11 | QMainWindow(parent), 12 | ui(new Ui::DTFWindow) 13 | { 14 | ui->setupUi(this); 15 | nv.init(ui->w_bottom->layout()); 16 | nv.xAxisValueStr = [](double val) { 17 | return ssprintf(32, "%.3lf ns", val); 18 | }; 19 | 20 | GraphPanel* gp = nv.createGraphView(false, false); 21 | gp->maximizeButton()->hide(); 22 | ui->w_graph->layout()->addWidget(gp); 23 | 24 | nv.addMarker(false); 25 | } 26 | 27 | DTFWindow::~DTFWindow() 28 | { 29 | delete ui; 30 | } 31 | 32 | inline double gauss(double x, double m, double s) { 33 | static const double inv_sqrt_2pi = 0.3989422804014327; 34 | double a = (x - m) / s; 35 | return inv_sqrt_2pi / s * std::exp(-0.5 * a * a); 36 | } 37 | 38 | void DTFWindow::initFFT(int sz) { 39 | fft_in = (complex*) fftw_malloc(sizeof(complex) * sz); 40 | fft_out = (complex*) fftw_malloc(sizeof(complex) * sz); 41 | fft_window = (complex*) fftw_malloc(sizeof(complex) * sz); 42 | p = fftw_plan_dft_1d(sz, (fftw_complex*)fft_in, (fftw_complex*)fft_out, FFTW_BACKWARD, 0); 43 | 44 | /*double raisedCosineWidth = 0.1; 45 | for(int i=0; i 0.5) x = 1. - x; 48 | if(x > raisedCosineWidth) fft_window[i] = 1.; 49 | else { 50 | double tmp = -cos(x*M_PI/raisedCosineWidth); 51 | fft_window[i] = (tmp + 1) * 0.5; 52 | } 53 | }*/ 54 | for(int i=0;i &freqDomainValues) { 84 | int sz = (int)freqDomainValues.size(); 85 | assert(sz == (int)nv.values.size()); 86 | for(int row=0;row<2;row++) 87 | for(int col=0;col<2;col++) { 88 | for(int i=0;i 5 | #include 6 | #include "networkview.H" 7 | 8 | namespace Ui { 9 | class DTFWindow; 10 | } 11 | 12 | class DTFWindow : public QMainWindow 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | NetworkView nv; 18 | fftw_plan p; 19 | complex* fft_in = nullptr; 20 | complex* fft_out = nullptr; 21 | complex* fft_window = nullptr; 22 | 23 | double timeScale = 1e9; 24 | explicit DTFWindow(QWidget *parent = 0); 25 | ~DTFWindow(); 26 | 27 | void initFFT(int sz); 28 | void deinitFFT(); 29 | void updateSweepParams(double stepFreqHz, int nPoints); 30 | void updateValues(const vector& freqDomainValues); 31 | signals: 32 | void hidden(); 33 | protected: 34 | void closeEvent(QCloseEvent *event); 35 | private: 36 | Ui::DTFWindow *ui; 37 | }; 38 | 39 | #endif // DTFWINDOW_H 40 | -------------------------------------------------------------------------------- /vna_qt/dtfwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | DTFWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 600 10 | 400 11 | 12 | 13 | 14 | Time to fault 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 0 23 | 0 24 | 25 | 26 | 27 | 28 | 0 29 | 30 | 31 | 0 32 | 33 | 34 | 0 35 | 36 | 37 | 0 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 0 47 | 0 48 | 49 | 50 | 51 | 52 | 0 53 | 10 54 | 55 | 56 | 57 | 58 | 0 59 | 60 | 61 | 0 62 | 63 | 64 | 0 65 | 66 | 67 | 0 68 | 69 | 70 | 0 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 0 81 | 0 82 | 600 83 | 20 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /vna_qt/edit-redo-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /vna_qt/emblem-ok-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /vna_qt/firmwareupdatedialog.C: -------------------------------------------------------------------------------- 1 | #include "firmwareupdatedialog.H" 2 | #include "ui_firmwareupdatedialog.h" 3 | #include "firmwareupdater.H" 4 | #include "utility.H" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | FirmwareUpdateDialog::FirmwareUpdateDialog(QWidget *parent) : 12 | QDialog(parent), 13 | ui(new Ui::FirmwareUpdateDialog) 14 | { 15 | ui->setupUi(this); 16 | } 17 | 18 | FirmwareUpdateDialog::~FirmwareUpdateDialog() 19 | { 20 | delete ui; 21 | } 22 | 23 | void FirmwareUpdateDialog::beginUploadFirmware(string dev, string file) { 24 | ui->buttonBox->setDisabled(true); 25 | 26 | /*_fd = ::open(file.c_str(), O_RDONLY); 27 | if(_fd < 0) 28 | throw runtime_error(strerror(errno));*/ 29 | 30 | filePtr = fopen(file.c_str(), "rb"); 31 | if(filePtr == nullptr) 32 | throw runtime_error(strerror(errno)); 33 | 34 | 35 | updater = new FirmwareUpdater(); 36 | updater->open(dev.c_str()); 37 | updater->beginUploadFirmware(0x08004000, [this](uint8_t* buf, int len) { 38 | //return int(::read(_fd, buf, size_t(len))); 39 | return int(fread(buf, 1, size_t(len), this->filePtr)); 40 | }, 41 | [this](int progress){ 42 | QMetaObject::invokeMethod(this, "updateProgress", Qt::QueuedConnection, Q_ARG(int, progress)); 43 | }); 44 | } 45 | 46 | void FirmwareUpdateDialog::updateProgress(int progress) { 47 | if(progress == -1) { 48 | auto ex = updater->endUploadFirmware(); 49 | if(ex == nullptr) 50 | updater->reboot(); 51 | 52 | updater->close(); 53 | delete updater; 54 | updater = nullptr; 55 | 56 | fclose(filePtr); 57 | 58 | if(ex != nullptr) { 59 | QString msg = "An error occurred during firmware update:\n\n"; 60 | msg += ex->what(); 61 | msg += "\n\nPlease retry the update.\nYou can re-enter DFU mode by holding down the JOG LEFT button and power cycling the device."; 62 | QMessageBox::critical(this, "Error", msg); 63 | this->accept(); 64 | } else { 65 | ui->l_progress->setText("Done\n" + ui->l_progress->text()); 66 | ui->buttonBox->setDisabled(false); 67 | } 68 | return; 69 | } 70 | string msg; 71 | if(progress < 1024) 72 | msg = ssprintf(128, "%d bytes", progress); 73 | else msg = ssprintf(128, "%d KiB", progress/1024); 74 | ui->l_progress->setText(qs(msg)); 75 | } 76 | -------------------------------------------------------------------------------- /vna_qt/firmwareupdatedialog.H: -------------------------------------------------------------------------------- 1 | #ifndef FIRMWAREUPDATEDIALOG_H 2 | #define FIRMWAREUPDATEDIALOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | namespace Ui { 10 | class FirmwareUpdateDialog; 11 | } 12 | class FirmwareUpdater; 13 | class FirmwareUpdateDialog : public QDialog 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit FirmwareUpdateDialog(QWidget *parent = nullptr); 19 | ~FirmwareUpdateDialog(); 20 | 21 | void beginUploadFirmware(string dev, string file); 22 | 23 | public slots: 24 | void updateProgress(int progress); 25 | 26 | private: 27 | Ui::FirmwareUpdateDialog *ui; 28 | FirmwareUpdater* updater = nullptr; 29 | //int _fd = -1; 30 | FILE* filePtr = nullptr; 31 | }; 32 | 33 | #endif // FIRMWAREUPDATEDIALOG_H 34 | -------------------------------------------------------------------------------- /vna_qt/firmwareupdatedialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | FirmwareUpdateDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 388 10 | 186 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | Qt::Horizontal 21 | 22 | 23 | QDialogButtonBox::Ok 24 | 25 | 26 | 27 | 28 | 29 | 30 | 0 KiB 31 | 32 | 33 | 34 | 35 | 36 | 37 | Uploading firmware... 38 | 39 | 40 | 41 | 42 | 43 | 44 | If the firmware update is interrupted, you can re-enter DFU mode by holding down the JOG LEFT button while power cycling the device. 45 | 46 | 47 | true 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | buttonBox 57 | accepted() 58 | FirmwareUpdateDialog 59 | accept() 60 | 61 | 62 | 248 63 | 254 64 | 65 | 66 | 157 67 | 274 68 | 69 | 70 | 71 | 72 | buttonBox 73 | rejected() 74 | FirmwareUpdateDialog 75 | reject() 76 | 77 | 78 | 316 79 | 260 80 | 81 | 82 | 286 83 | 274 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /vna_qt/firmwareupdater.C: -------------------------------------------------------------------------------- 1 | #include "firmwareupdater.H" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // this dependency can be removed if you provide implementations 9 | // of qToLittleEndian() and qFromLittleEndian() 10 | #include 11 | 12 | static int writeAll(int fd, const void* buf, int len) { 13 | const uint8_t* buf1 = static_cast (buf); 14 | int off = 0; 15 | while(off& reader, 62 | const function& cb) { 63 | // set flash write address 64 | checkError(writeRegister32(0xe0, dstAddr)); 65 | 66 | this->_cb = cb; 67 | this->_reader = reader; 68 | checkError(pthread_create(&_pth, nullptr, &_flashThread, this)); 69 | } 70 | 71 | exception* FirmwareUpdater::endUploadFirmware() { 72 | if(!_reader) 73 | throw logic_error("endUploadFirmware called without a prior beginUploadFirmware"); 74 | _reader = nullptr; 75 | void* ret; 76 | checkError(pthread_join(_pth, &ret)); 77 | return static_cast(ret); 78 | } 79 | 80 | void FirmwareUpdater::setUserArgument(uint32_t arg) { 81 | checkError(writeRegister32(0xe8, arg)); 82 | } 83 | 84 | void FirmwareUpdater::reboot() { 85 | checkError(writeRegister(0xef, 0x5e)); 86 | } 87 | 88 | int FirmwareUpdater::readRegister(uint8_t addr) { 89 | uint8_t buf[] = { 90 | 0x10, addr 91 | }; 92 | if(writeAll(ttyFD,buf,sizeof(buf)) != int(sizeof(buf))) 93 | return -1; 94 | 95 | uint8_t rBuf[1]; 96 | if(read(ttyFD, rBuf, 1) != 1) 97 | return -1; 98 | return rBuf[0]; 99 | } 100 | 101 | int FirmwareUpdater::writeRegister(uint8_t addr, uint8_t val) { 102 | uint8_t buf[] = { 103 | 0x20, addr, val 104 | }; 105 | return (writeAll(ttyFD,buf,sizeof(buf)) == int(sizeof(buf))) ? 0 : -1; 106 | } 107 | 108 | int FirmwareUpdater::writeRegister32(uint8_t addr, uint32_t val) { 109 | uint8_t buf[] = { 110 | 0x22, addr, 0,0,0,0 111 | }; 112 | qToLittleEndian(val, buf + 2); 113 | return (writeAll(ttyFD,buf,sizeof(buf)) == int(sizeof(buf))) ? 0 : -1; 114 | } 115 | 116 | int FirmwareUpdater::_sendBytes(const uint8_t* data, int len) { 117 | if(len > 255) 118 | throw out_of_range("FirmwareUpdater::_sendBytes can not send > 255 bytes"); 119 | 120 | // cmd: write FIFO 0xe4 121 | string cmd = "\x28\xe4"; 122 | cmd += char(uint8_t(len)); 123 | cmd.append(reinterpret_cast(data), size_t(len)); 124 | // cmd: echo version 125 | cmd += 0x0d; 126 | int totalLen = int(cmd.length()); 127 | if(writeAll(ttyFD, cmd.data(), totalLen) != totalLen) 128 | return -1; 129 | return 0; 130 | } 131 | 132 | int FirmwareUpdater::_waitSend() { 133 | uint8_t buf; 134 | auto tmp = read(ttyFD, &buf, 1); 135 | if(tmp == 0) 136 | errno = EPIPE; 137 | if(tmp <= 0) 138 | return -1; 139 | return 0; 140 | } 141 | 142 | void* FirmwareUpdater::_flashThread(void* v) { 143 | FirmwareUpdater* t = static_cast(v); 144 | return t->flashThread(); 145 | } 146 | 147 | 148 | void* FirmwareUpdater::flashThread() { 149 | constexpr int bufSize = 255; 150 | uint8_t buf[bufSize]; 151 | int outstanding = 0; 152 | int progress = 0; 153 | auto lastNotify = time(nullptr); 154 | 155 | while(true) { 156 | auto br = _reader(buf, bufSize); 157 | if(br < 0) 158 | goto fail; 159 | if(br == 0) { 160 | if(progress < 1024) { 161 | auto ex = new runtime_error("EOF reading from file at " + to_string(progress) + " bytes"); 162 | _cb(-1); 163 | return ex; 164 | } 165 | break; 166 | } 167 | progress += br; 168 | 169 | int res = _sendBytes(buf, int(br)); 170 | if(res < 0) 171 | goto fail; 172 | 173 | auto t = time(nullptr); 174 | if(t - lastNotify >= 1) { 175 | lastNotify = t; 176 | _cb(progress); 177 | } 178 | 179 | outstanding++; 180 | if(outstanding > 5) { 181 | if(_waitSend() < 0) 182 | goto fail; 183 | outstanding--; 184 | } 185 | } 186 | if(progress == 0) { 187 | auto ex = new runtime_error("Read 0 bytes from file!"); 188 | _cb(-1); 189 | return ex; 190 | } 191 | _cb(progress); 192 | while(outstanding > 0) { 193 | if(_waitSend() < 0) 194 | goto fail; 195 | outstanding--; 196 | } 197 | _cb(-1); 198 | return nullptr; 199 | fail: 200 | auto ex = new runtime_error(strerror(errno)); 201 | _cb(-1); 202 | return ex; 203 | } 204 | -------------------------------------------------------------------------------- /vna_qt/firmwareupdater.H: -------------------------------------------------------------------------------- 1 | #ifndef FIRMWAREUPDATER_H 2 | #define FIRMWAREUPDATER_H 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | class FirmwareUpdater 9 | { 10 | public: 11 | FirmwareUpdater(); 12 | ~FirmwareUpdater(); 13 | 14 | // open a tty device. Throws logic_error if device is not in DFU mode. 15 | void open(const char *dev); 16 | void close(); 17 | 18 | // upload firmware asynchronously. 19 | // reader is a function that will read up to len bytes into buf, similar to read(2). 20 | // cb is called at a set interval to indicate progress. 21 | // progress is bytes sent. When cb is called with progress = -1, the operation is complete, 22 | // and you can call endUploadFirmware() from another thread to check for errors. 23 | void beginUploadFirmware(uint32_t dstAddr, 24 | const function& reader, 25 | const function& cb); 26 | 27 | // returns the first exception encountered during firmware upload, if any. 28 | // if return value is non-null, the user must call delete on it. 29 | exception* endUploadFirmware(); 30 | 31 | // sets the argument passed to the user application upon reboot 32 | void setUserArgument(uint32_t arg); 33 | 34 | // reboot the device 35 | void reboot(); 36 | 37 | // returns -1 on error 38 | int readRegister(uint8_t addr); 39 | int writeRegister(uint8_t addr, uint8_t val); 40 | int writeRegister32(uint8_t addr, uint32_t val); 41 | 42 | 43 | // internal functions 44 | int ttyFD = -1; 45 | int _sendBytes(const uint8_t* data, int len); 46 | int _waitSend(); 47 | 48 | private: 49 | function _cb; 50 | function _reader; 51 | pthread_t _pth; 52 | static void* _flashThread(void* v); 53 | void* flashThread(); 54 | }; 55 | 56 | #endif // FIRMWAREUPDATER_H 57 | -------------------------------------------------------------------------------- /vna_qt/frequencydialog.C: -------------------------------------------------------------------------------- 1 | #include "utility.H" 2 | #include "frequencydialog.H" 3 | #include "ui_frequencydialog.h" 4 | #include 5 | #include 6 | 7 | using namespace xaxaxa; 8 | FrequencyDialog::FrequencyDialog(QWidget *parent) : 9 | QDialog(parent), 10 | ui(new Ui::FrequencyDialog) 11 | { 12 | ui->setupUi(this); 13 | ui->w_advanced->setVisible(false); 14 | this->resize(this->width(),0); 15 | this->setWindowTitle("Sweep Parameters"); 16 | } 17 | 18 | FrequencyDialog::~FrequencyDialog() 19 | { 20 | delete ui; 21 | } 22 | 23 | void FrequencyDialog::fromVNA(const VNADevice &dev) { 24 | ui->t_start->setValue(dev.startFreqHz*1e-6); 25 | ui->t_stop->setValue(dev.startFreqHz*1e-6 + dev.stepFreqHz*1e-6 *(dev.nPoints - 1)); 26 | ui->t_points->setValue(dev.nPoints); 27 | ui->slider_power->setRange(dev.maxPower()-40, dev.maxPower()); 28 | ui->slider_power->setValue(dev.maxPower() - dev.attenuation1); 29 | ui->t_nValues->setText(qs(ssprintf(32, "%d", dev.nValues))); 30 | ui->t_nWait->setText(qs(ssprintf(32, "%d", dev.nWait))); 31 | emit on_slider_power_valueChanged(ui->slider_power->value()); 32 | } 33 | 34 | bool floatEq(double a, double b, double maxError=1e-9) { 35 | double err = abs(a/b - 1.); 36 | return err <= maxError; 37 | } 38 | bool FrequencyDialog::toVNA(VNADevice &dev) { 39 | double oldStartFreq = dev.startFreqHz; 40 | double oldStepFreq = dev.stepFreqHz; 41 | int oldNPoints = dev.nPoints; 42 | dev.startFreqHz = ui->t_start->value()*1e6; 43 | double stopFreqHz = ui->t_stop->value()*1e6; 44 | 45 | if(stopFreqHz <= dev.startFreqHz){ //sanity check 46 | stopFreqHz=dev.startFreqHz + 1e6; 47 | QMessageBox::critical(this, "Error","Invalid Stop Frequency"); 48 | } 49 | 50 | dev.nPoints = ui->t_points->value(); 51 | dev.stepFreqHz=(stopFreqHz - dev.startFreqHz)/(dev.nPoints - 1); //-1 to not skip the last step 52 | 53 | dev.attenuation1 = dev.attenuation2 = dev.maxPower() - ui->slider_power->value(); 54 | dev.nValues = atoi(ui->t_nValues->text().toUtf8().data()); 55 | dev.nWait = atoi(ui->t_nWait->text().toUtf8().data()); 56 | if(!floatEq(dev.startFreqHz, oldStartFreq)) 57 | return true; 58 | if(!floatEq(dev.stepFreqHz, oldStepFreq)) 59 | return true; 60 | if(dev.nPoints != oldNPoints) 61 | return true; 62 | return false; 63 | } 64 | 65 | void FrequencyDialog::updateLabels() { 66 | double stepSize = ( ui->t_stop->value() - ui->t_start->value()) / ui->t_points->value(); 67 | 68 | if(!std::isnan(stepSize) && stepSize>0) 69 | ui->l_end->setText(qs(ssprintf(32, "%.6f", stepSize))); 70 | } 71 | 72 | void FrequencyDialog::on_slider_power_valueChanged(int value) { 73 | ui->l_power->setText(qs(ssprintf(32, "%d dBm", value))); 74 | } 75 | 76 | void FrequencyDialog::on_t_start_valueChanged(const QString &) { 77 | updateLabels(); 78 | } 79 | 80 | void FrequencyDialog::on_t_stop_valueChanged(const QString &) { 81 | updateLabels(); 82 | } 83 | 84 | void FrequencyDialog::on_t_points_valueChanged(const QString &) { 85 | updateLabels(); 86 | } 87 | 88 | void FrequencyDialog::on_c_advanced_stateChanged(int) { 89 | ui->w_advanced->setVisible(ui->c_advanced->isChecked()); 90 | } 91 | -------------------------------------------------------------------------------- /vna_qt/frequencydialog.H: -------------------------------------------------------------------------------- 1 | #ifndef FREQUENCYDIALOG_H 2 | #define FREQUENCYDIALOG_H 3 | 4 | #include 5 | #include 6 | 7 | namespace Ui { 8 | class FrequencyDialog; 9 | } 10 | namespace xaxaxa { 11 | class VNADevice; 12 | } 13 | using namespace xaxaxa; 14 | class FrequencyDialog : public QDialog 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | explicit FrequencyDialog(QWidget *parent = 0); 20 | ~FrequencyDialog(); 21 | 22 | // populate the UI with parameters from dev 23 | void fromVNA(const VNADevice& dev); 24 | 25 | // update dev with parameters from the UI 26 | // returns true if frequency parameters were changed, false otherwise 27 | bool toVNA(VNADevice& dev); 28 | 29 | void updateLabels(); 30 | 31 | private slots: 32 | void on_slider_power_valueChanged(int value); 33 | void on_t_start_valueChanged(const QString &arg1); 34 | void on_t_stop_valueChanged(const QString &arg1); 35 | void on_t_points_valueChanged(const QString &arg1); 36 | 37 | void on_c_advanced_stateChanged(int); 38 | 39 | private: 40 | Ui::FrequencyDialog *ui; 41 | }; 42 | 43 | #endif // FREQUENCYDIALOG_H 44 | -------------------------------------------------------------------------------- /vna_qt/graphlimitsdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | GraphLimitsDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 273 10 | 181 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Graph limits setup 23 | 24 | 25 | true 26 | 27 | 28 | 29 | 30 | 31 | 32 | Min 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | dB 47 | 48 | 49 | 5 50 | 51 | 52 | 53 | 54 | 55 | 56 | Max 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | dB 71 | 72 | 73 | 5 74 | 75 | 76 | 77 | 78 | 79 | 80 | Divisions 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 5 98 | 99 | 100 | 101 | 102 | 103 | 104 | Qt::Horizontal 105 | 106 | 107 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | buttonBox 119 | accepted() 120 | GraphLimitsDialog 121 | accept() 122 | 123 | 124 | 136 125 | 158 126 | 127 | 128 | 136 129 | 90 130 | 131 | 132 | 133 | 134 | buttonBox 135 | rejected() 136 | GraphLimitsDialog 137 | reject() 138 | 139 | 140 | 136 141 | 158 142 | 143 | 144 | 136 145 | 90 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /vna_qt/graphpanel.C: -------------------------------------------------------------------------------- 1 | #include "utility.H" 2 | #include "graphpanel.H" 3 | #include "ui_graphpanel.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace QtCharts; 12 | GraphPanel::GraphPanel(QWidget *parent) : 13 | QWidget(parent), 14 | ui(new Ui::GraphPanel) 15 | { 16 | ui->setupUi(this); 17 | 18 | chart = new QChart(); 19 | chartView = new QChartView(); 20 | this->layout()->addWidget(chartView); 21 | 22 | chartView->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); 23 | chartView->setRenderHint(QPainter::Antialiasing); 24 | chartView->setChart(chart); 25 | chartView->setStyleSheet("background-color:#000"); 26 | 27 | 28 | 29 | axisX = new QValueAxis; 30 | axisX->setTickCount(10); 31 | axisX->setLabelsAngle(-90); 32 | chart->addAxis(axisX, Qt::AlignBottom); 33 | 34 | 35 | 36 | series.resize(2); 37 | axisY.resize(2); 38 | for(int i=0;i<(int)series.size();i++) { 39 | axisY[i] = new QValueAxis; 40 | axisY[i]->setTickCount(12); 41 | axisY[i]->setLinePenColor(i==0?Qt::red:Qt::blue); 42 | axisY[i]->setMin(-80); 43 | axisY[i]->setMax(30); 44 | chart->addAxis(axisY[i], i==0?Qt::AlignLeft:Qt::AlignRight); 45 | 46 | series[i] = new QLineSeries(); 47 | series[i]->setPen(QPen(axisY[i]->linePenColor(), 2.)); 48 | chart->addSeries(series[i]); 49 | chart->legend()->hide(); 50 | chart->layout()->setContentsMargins(0, 0, 0, 0); 51 | chart->setBackgroundRoundness(0); 52 | //chart->setBackgroundBrush(Qt::red); 53 | //chart->setMargins(QMargins(0,0,0,0)); 54 | series[i]->attachAxis(axisX); 55 | series[i]->attachAxis(axisY[i]); 56 | } 57 | } 58 | 59 | GraphPanel::~GraphPanel() 60 | { 61 | delete ui; 62 | } 63 | 64 | void GraphPanel::populateComboBox(int index, const vector &items) { 65 | QComboBox* combo = comboBox(index); 66 | combo->clear(); 67 | for(string item:items) { 68 | combo->addItem(qs(item)); 69 | } 70 | } 71 | 72 | QComboBox *GraphPanel::comboBox(int index) { 73 | if(index == 0) return ui->d1; 74 | return ui->d2; 75 | } 76 | 77 | QPushButton *GraphPanel::maximizeButton() { 78 | return ui->b_maximize; 79 | } 80 | 81 | void GraphPanel::on_d1_currentIndexChanged(int index) { 82 | emit comboBoxSelectionChanged(0,index); 83 | } 84 | 85 | void GraphPanel::on_d2_currentIndexChanged(int index) { 86 | emit comboBoxSelectionChanged(1,index); 87 | } 88 | -------------------------------------------------------------------------------- /vna_qt/graphpanel.H: -------------------------------------------------------------------------------- 1 | #ifndef GRAPHPANEL_H 2 | #define GRAPHPANEL_H 3 | 4 | #include 5 | #include 6 | 7 | namespace Ui { 8 | class GraphPanel; 9 | } 10 | namespace QtCharts { 11 | class QChartView; 12 | class QChart; 13 | class QValueAxis; 14 | class QLineSeries; 15 | } 16 | class QComboBox; 17 | class QPushButton; 18 | 19 | using namespace QtCharts; 20 | using namespace std; 21 | class GraphPanel : public QWidget 22 | { 23 | Q_OBJECT 24 | 25 | public: 26 | explicit GraphPanel(QWidget *parent = 0); 27 | ~GraphPanel(); 28 | 29 | QChart* chart; 30 | QChartView* chartView; 31 | vector series; 32 | QValueAxis* axisX; 33 | vector axisY; 34 | 35 | // combo box 0 is the leftmost one; 1 is the rightmost one 36 | void populateComboBox(int index, const vector& items); 37 | QComboBox* comboBox(int index); 38 | QPushButton* maximizeButton(); 39 | 40 | signals: 41 | void comboBoxSelectionChanged(int index, int selection); 42 | 43 | private slots: 44 | void on_d1_currentIndexChanged(int index); 45 | void on_d2_currentIndexChanged(int index); 46 | 47 | private: 48 | Ui::GraphPanel *ui; 49 | }; 50 | 51 | #endif // GRAPHPANEL_H 52 | -------------------------------------------------------------------------------- /vna_qt/graphpanel.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | GraphPanel 4 | 5 | 6 | 7 | 0 8 | 0 9 | 500 10 | 323 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | Form 21 | 22 | 23 | 24 | 0 25 | 26 | 27 | 0 28 | 29 | 30 | 0 31 | 32 | 33 | 0 34 | 35 | 36 | 0 37 | 38 | 39 | 40 | 41 | 42 | 0 43 | 0 44 | 45 | 46 | 47 | 48 | 5 49 | 50 | 51 | 5 52 | 53 | 54 | 55 | 56 | color: red 57 | 58 | 59 | 60 | |S11| 61 | 62 | 63 | 64 | 65 | |S22| 66 | 67 | 68 | 69 | 70 | |S12| 71 | 72 | 73 | 74 | 75 | |S21| 76 | 77 | 78 | 79 | 80 | arg(S11) 81 | 82 | 83 | 84 | 85 | arg(S22) 86 | 87 | 88 | 89 | 90 | arg(S12) 91 | 92 | 93 | 94 | 95 | arg(S21) 96 | 97 | 98 | 99 | 100 | GroupDelay(S11) 101 | 102 | 103 | 104 | 105 | GroupDelay(S22) 106 | 107 | 108 | 109 | 110 | GroupDelay(S12) 111 | 112 | 113 | 114 | 115 | GroupDelay(S21) 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | color: blue 124 | 125 | 126 | 127 | aaaaa 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 0 137 | 0 138 | 139 | 140 | 141 | maximize 142 | 143 | 144 | 145 | 146 | 147 | 148 | :/icons/maximize:/icons/maximize 149 | 150 | 151 | true 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /vna_qt/impedancedisplay.C: -------------------------------------------------------------------------------- 1 | #include "utility.H" 2 | #include "impedancedisplay.H" 3 | #include "ui_impedancedisplay.h" 4 | 5 | 6 | ImpedanceDisplay::ImpedanceDisplay(QWidget *parent) : 7 | QWidget(parent), 8 | ui(new Ui::ImpedanceDisplay) 9 | { 10 | ui->setupUi(this); 11 | } 12 | 13 | ImpedanceDisplay::~ImpedanceDisplay() 14 | { 15 | delete ui; 16 | } 17 | 18 | void ImpedanceDisplay::setValue(complex s11, double freqHz, double z0) { 19 | complex Z = -z0*(s11+1.)/(s11-1.); 20 | complex Y = -(s11-1.)/(z0*(s11+1.)); 21 | 22 | ui->l_impedance->setText(qs(ssprintf(127, " %.2f\n%s j%.2f", Z.real(), Z.imag()>=0 ? "+" : "-", fabs(Z.imag())))); 23 | ui->l_admittance->setText(qs(ssprintf(127, " %.4f\n%s j%.4f", Y.real(), Y.imag()>=0 ? "+" : "-", fabs(Y.imag())))); 24 | ui->l_s_admittance->setText(qs(ssprintf(127, " %.4f\n%s j%.4f", 1./Z.real(), Z.imag()>=0 ? "+" : "-", fabs(1./Z.imag())))); 25 | ui->l_p_impedance->setText(qs(ssprintf(127, " %.2f\n|| j%.2f", 1./Y.real(), 1./Y.imag()))); 26 | 27 | double value = capacitance_inductance(freqHz, Z.imag()); 28 | ui->l_series->setText(qs(ssprintf(127, "%.2f Ω\n%.2f %s%s", Z.real(), fabs(si_scale(value)), si_unit(value), value>0?"H":"F"))); 29 | 30 | value = capacitance_inductance_Y(freqHz, Y.imag()); 31 | ui->l_parallel->setText(qs(ssprintf(127, "%.2f Ω\n%.2f %s%s", 1./Y.real(), fabs(si_scale(value)), si_unit(value), value>0?"H":"F"))); 32 | } 33 | 34 | void ImpedanceDisplay::clearValue() { 35 | QString p = "-"; 36 | ui->l_impedance->setText(p); 37 | ui->l_admittance->setText(p); 38 | ui->l_s_admittance->setText(p); 39 | ui->l_p_impedance->setText(p); 40 | ui->l_series->setText(p); 41 | ui->l_parallel->setText(p); 42 | } 43 | -------------------------------------------------------------------------------- /vna_qt/impedancedisplay.H: -------------------------------------------------------------------------------- 1 | #ifndef IMPEDANCEDISPLAY_H 2 | #define IMPEDANCEDISPLAY_H 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | namespace Ui { 9 | class ImpedanceDisplay; 10 | } 11 | 12 | class ImpedanceDisplay : public QWidget 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit ImpedanceDisplay(QWidget *parent = 0); 18 | ~ImpedanceDisplay(); 19 | 20 | void setValue(complex s11, double freqHz, double z0=50.); 21 | void clearValue(); 22 | 23 | private: 24 | Ui::ImpedanceDisplay *ui; 25 | }; 26 | 27 | #endif // IMPEDANCEDISPLAY_H 28 | -------------------------------------------------------------------------------- /vna_qt/languages/vna_qt_zh.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanovna-v2/NanoVNA-QT/0aa6ee4e68ade0285755f06c2eab240e2d0beea1/vna_qt/languages/vna_qt_zh.qm -------------------------------------------------------------------------------- /vna_qt/main.C: -------------------------------------------------------------------------------- 1 | #include "mainwindow.H" 2 | #include "calkitsettings.H" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | qRegisterMetaType("string"); 11 | qRegisterMetaType("CalKitSettings"); 12 | qRegisterMetaTypeStreamOperators("CalKitSettings"); 13 | 14 | QCoreApplication::setApplicationName("NanoVNA QT GUI"); 15 | 16 | QApplication app(argc, argv); 17 | app.setStyle("fusion"); 18 | 19 | 20 | QTranslator qtTranslator; 21 | qtTranslator.load("qt_" + QLocale::system().name(), 22 | QLibraryInfo::location(QLibraryInfo::TranslationsPath)); 23 | app.installTranslator(&qtTranslator); 24 | 25 | QTranslator myappTranslator; 26 | myappTranslator.load("languages/vna_qt_" + QLocale::system().name()); 27 | fprintf(stderr, "%s\n", QLocale::system().name().toStdString().c_str()); 28 | app.installTranslator(&myappTranslator); 29 | 30 | 31 | MainWindow* w = new MainWindow(); 32 | w->show(); 33 | 34 | return app.exec(); 35 | } 36 | -------------------------------------------------------------------------------- /vna_qt/markerslider.C: -------------------------------------------------------------------------------- 1 | #include "markerslider.H" 2 | #include "ui_markerslider.h" 3 | 4 | MarkerSlider::MarkerSlider(QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::MarkerSlider) 7 | { 8 | ui->setupUi(this); 9 | labels = {ui->l1, ui->l2, ui->l3, ui->l4}; 10 | } 11 | 12 | MarkerSlider::~MarkerSlider() 13 | { 14 | delete ui; 15 | } 16 | 17 | void MarkerSlider::setLabelText(int index, string text) { 18 | labels.at(index)->setText(QString::fromStdString(text)); 19 | labels.at(index)->setVisible(text!=""); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /vna_qt/markerslider.H: -------------------------------------------------------------------------------- 1 | #ifndef MARKERSLIDER_H 2 | #define MARKERSLIDER_H 3 | 4 | #include 5 | #include 6 | 7 | namespace Ui { 8 | class MarkerSlider; 9 | } 10 | class QLabel; 11 | 12 | using namespace std; 13 | 14 | class MarkerSlider : public QWidget 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | int id = -1; 20 | vector labels; 21 | explicit MarkerSlider(QWidget *parent = 0); 22 | ~MarkerSlider(); 23 | 24 | void setLabelText(int index, string text); 25 | 26 | public: 27 | Ui::MarkerSlider *ui; 28 | }; 29 | 30 | #endif // MARKERSLIDER_H 31 | -------------------------------------------------------------------------------- /vna_qt/markerslider.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MarkerSlider 4 | 5 | 6 | 7 | 0 8 | 0 9 | 634 10 | 32 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | Form 21 | 22 | 23 | 24 | 3 25 | 26 | 27 | 0 28 | 29 | 30 | 0 31 | 32 | 33 | 34 | 35 | 36 | 0 37 | 0 38 | 39 | 40 | 41 | 42 | 32 43 | 0 44 | 45 | 46 | 47 | 48 | 32 49 | 16777215 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | :/icons/add:/icons/add 58 | 59 | 60 | 61 | 12 62 | 16 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 32 72 | 0 73 | 74 | 75 | 76 | Marker id 77 | 78 | 79 | 1 80 | 81 | 82 | Qt::AlignCenter 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 0 91 | 0 92 | 93 | 94 | 95 | 96 | 110 97 | 0 98 | 99 | 100 | 101 | Show/hide marker 102 | 103 | 104 | 1000.00 MHz 105 | 106 | 107 | true 108 | 109 | 110 | true 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 80 119 | 0 120 | 121 | 122 | 123 | color: red; font-weight: bold 124 | 125 | 126 | -100.1 Ω 127 | 128 | 129 | Qt::AlignCenter 130 | 131 | 132 | 0 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 80 141 | 0 142 | 143 | 144 | 145 | color: blue; font-weight: bold 146 | 147 | 148 | TextLabel1 149 | 150 | 151 | Qt::AlignCenter 152 | 153 | 154 | 0 155 | 156 | 157 | 158 | 159 | 160 | 161 | Qt::Horizontal 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 80 170 | 0 171 | 172 | 173 | 174 | color: red; font-weight: bold 175 | 176 | 177 | TextLabel 178 | 179 | 180 | Qt::AlignCenter 181 | 182 | 183 | 5 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 80 192 | 0 193 | 194 | 195 | 196 | color: blue; font-weight: bold 197 | 198 | 199 | TextLabel 200 | 201 | 202 | Qt::AlignCenter 203 | 204 | 205 | 5 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /vna_qt/networkview.H: -------------------------------------------------------------------------------- 1 | #ifndef NETWORKVIEW_H 2 | #define NETWORKVIEW_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace QtCharts { 9 | class QChartView; 10 | class QChart; 11 | class QValueAxis; 12 | } 13 | 14 | class QTimer; 15 | class MarkerSlider; 16 | class QTextStream; 17 | class GraphPanel; 18 | 19 | using namespace QtCharts; 20 | using namespace xaxaxa; 21 | using namespace std; 22 | 23 | struct SParamViewSource { 24 | int row,col; // which S parameter are we viewing 25 | enum Types { 26 | UNDEFINED=0, 27 | // view must be QLineSeries: 28 | TYPE_MAG=1, // display the magnitude of Snn 29 | TYPE_PHASE, // display the phase of Snn 30 | TYPE_GRPDELAY, // group delay calculated from change in phase 31 | TYPE_SWR, // standing wave ratio 32 | TYPE_Z_RE, // real part of series equivalent impedance 33 | TYPE_Z_IM, // imaginary part of series equivalent impedance 34 | TYPE_Z_MAG, // magnitude of series equivalent impedance 35 | TYPE_Z_CAP, // capacitance (in pF), series equivalent 36 | TYPE_Z_IND, // inductance (in nH), series equivalent 37 | TYPE_Y_RE, // real part of parallel equivalent admittance, mS 38 | TYPE_Y_IM, // imaginary part of parallel equivalent admittance, mS 39 | TYPE_Y_MAG, // magnitude of parallel equivalent admittance, mS 40 | TYPE_Y_CAP, // capacitance (in pF), parallel equivalent 41 | TYPE_Y_IND, // inductance (in nH), parallel equivalent 42 | // view must be PolarView: 43 | TYPE_COMPLEX, 44 | _LAST 45 | } type; 46 | }; 47 | 48 | // a UI view of one S parameter vs frequency 49 | struct SParamView { 50 | SParamViewSource src; 51 | QObject* view; // either PolarView or QLineSeries depending on src.type 52 | QValueAxis* yAxis; // NULL if view is not QLineSeries 53 | 54 | // these are not applicable for PolarView 55 | vector markerViews; // a QScatterSeries for each marker if view is a QLineSeries 56 | function addMarker; // this function must add a new object to markerViews 57 | }; 58 | 59 | struct Marker { 60 | int freqIndex; 61 | MarkerSlider* ms; 62 | bool enabled; 63 | }; 64 | 65 | 66 | /* 67 | helper class for displaying data about a linear network; 68 | this is not a widget, but a set of functions to update views from S parameter data. 69 | views (graphs, polar views) are user defined by adding items to ->views; 70 | includes slider/marker management. 71 | 72 | usage: 73 | 1. instantiate NetworkView 74 | 2. call init() 75 | 3. (optional) set graphLimits, xAxisValueStr, etc 76 | 4. add views (graphs, polar views, etc) 77 | 5. call addMarker(false); note: no new views may be added after a marker is added. 78 | 6. call update*() as needed 79 | */ 80 | class NetworkView: public QObject 81 | { 82 | Q_OBJECT 83 | public: 84 | QLayout* sliderContainer; 85 | vector values; 86 | double xAxisStart = 0., xAxisStep = 1.; 87 | // called to convert a x value to a display string on the slider widget 88 | function xAxisValueStr; 89 | // array of UI views of the data; each view has a source (describing what data to display) and a widget 90 | // (where to display the data on 91 | vector views; 92 | // array of axis to update when frequency sweep params are changed 93 | vector xAxis; 94 | // user-added markers 95 | vector markers; 96 | // min, max, and division count of the y axis of the graph, indexed by SParamViewSource::Types 97 | vector > graphLimits; 98 | 99 | static const vector > defaultGraphLimits; 100 | 101 | 102 | NetworkView(); 103 | 104 | void init(QLayout* sliderContainer); 105 | void clear(); 106 | 107 | double xAxisAt(int i) { 108 | return i*xAxisStep + xAxisStart; 109 | } 110 | GraphPanel* createGraphView(bool freqDomain=true, bool tr=true); 111 | void updateXAxis(double start, double step, int cnt); 112 | // update a single point on all views in this->views 113 | void updateViews(int freqIndex=-1); 114 | // update a single point on a view, or all points on a view (if freqIndex is -1) 115 | void updateView(int viewIndex, int freqIndex=-1); 116 | void updateMarkerViews(int marker=-1); 117 | void updateBottomLabels(int marker=-1); 118 | void updateYAxis(int viewIndex=-1); 119 | int addMarker(bool removable); 120 | 121 | QPointF _computeChartPoint(int viewIndex, int freqIndex); 122 | signals: 123 | void markerChanged(int marker, int newIndex); 124 | }; 125 | 126 | #endif // NETWORKVIEW_H 127 | -------------------------------------------------------------------------------- /vna_qt/polarview.C: -------------------------------------------------------------------------------- 1 | #define _USE_MATH_DEFINES 2 | #include "polarview.H" 3 | #include 4 | #include 5 | #include 6 | #include 7 | PolarView::PolarView(QWidget *parent) : QWidget(parent) 8 | { 9 | 10 | } 11 | 12 | double PolarView::radius() { 13 | double r=this->width()/2; 14 | if(this->height()/2. height()/2.; 15 | r -= margin; 16 | return r; 17 | } 18 | 19 | QPointF PolarView::val_to_point(QPointF center, double r, complex val) { 20 | return QPointF(center.x()+val.real()/scale*r, 21 | center.y()-val.imag()/scale*r); 22 | } 23 | 24 | void PolarView::draw_grid(QPainter &painter) { 25 | QPointF center(this->width()/2,this->height()/2); 26 | double r=radius(); 27 | 28 | // draw outer circle 29 | painter.setPen(QPen(Qt::black, 2.0)); 30 | painter.drawEllipse(center,r,r); 31 | 32 | painter.setPen(QPen(QColor(50,50,50), 1.0)); 33 | 34 | // draw constant resistance circles 35 | for(int i=1;i<4;i++) { 36 | painter.drawEllipse(center+QPointF(r-r/4*i,0),r/4*i,r/4*i); 37 | } 38 | 39 | // draw constant reactance circles 40 | painter.save(); 41 | QPainterPath path; 42 | path.addEllipse(center,r,r); 43 | painter.setClipPath(path); 44 | int n=1; 45 | for(int i=1;i<4;i++) { 46 | painter.drawEllipse(center+QPointF(r,r/2*n), r/2*n, r/2*n); 47 | painter.drawEllipse(center+QPointF(r,-r/2*n), r/2*n, r/2*n); 48 | n*=2; 49 | } 50 | painter.restore(); 51 | 52 | // draw center line 53 | painter.drawLine(center-QPointF(r,0), center+QPointF(r,0)); 54 | } 55 | 56 | void PolarView::draw_chart(QPainter &painter) { 57 | if(points.size()==0) return; 58 | QPointF center(this->width()/2,this->height()/2); 59 | double r=radius(); 60 | for(int i=1;i<(int)points.size();i++) { 61 | if(std::isnan(points[i-1].real()) || std::isnan(points[i].real())) continue; 62 | painter.drawLine(val_to_point(center,r,points[i-1]), 63 | val_to_point(center,r,points[i])); 64 | } 65 | } 66 | 67 | void PolarView::draw_full(QPainter &painter) { 68 | painter.setRenderHints(QPainter::Antialiasing); 69 | painter.fillRect(rect(),Qt::white); 70 | draw_grid(painter); 71 | if(persistence) { 72 | painter.drawImage(0,0,image); 73 | } else { 74 | painter.setPen(QPen(Qt::blue, 2.0)); 75 | draw_chart(painter); 76 | } 77 | for(Marker marker:markers) { 78 | if(marker.index<0) continue; 79 | painter.setPen(QPen(QColor(marker.color), 2.0)); 80 | draw_point(painter,points.at(marker.index),3); 81 | } 82 | } 83 | 84 | void PolarView::draw_point(QPainter &painter, complex pt, double size) { 85 | QPointF center(this->width()/2,this->height()/2); 86 | double r=radius(); 87 | painter.drawEllipse(val_to_point(center,r,pt), size, size); 88 | } 89 | 90 | void PolarView::clearPersistence() { 91 | image=QImage(this->size(),QImage::Format_ARGB32); 92 | } 93 | 94 | void PolarView::commitTrace() { 95 | 96 | } 97 | 98 | void PolarView::paintEvent(QPaintEvent *) { 99 | QPainter painter(this); 100 | draw_full(painter); 101 | } 102 | -------------------------------------------------------------------------------- /vna_qt/polarview.H: -------------------------------------------------------------------------------- 1 | #ifndef POLARVIEW_H 2 | #define POLARVIEW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | 11 | class QPainter; 12 | 13 | class PolarView : public QWidget 14 | { 15 | Q_OBJECT 16 | public: 17 | struct Marker { 18 | uint32_t color; // rgb 19 | int index; 20 | }; 21 | vector > points; 22 | vector markers; 23 | double scale=1.; 24 | double margin=10; // pixels 25 | bool persistence = false; 26 | 27 | explicit PolarView(QWidget *parent = 0); 28 | 29 | double radius(); 30 | QPointF val_to_point(QPointF center, double r, complex val); 31 | void draw_grid(QPainter& painter); 32 | void draw_chart(QPainter& painter); 33 | void draw_full(QPainter& painter); 34 | void draw_point(QPainter& painter, complex pt, double size); 35 | 36 | void clearPersistence(); 37 | void commitTrace(); 38 | 39 | protected: 40 | QImage image; 41 | void paintEvent(QPaintEvent *event) override; 42 | signals: 43 | 44 | public slots: 45 | }; 46 | 47 | #endif // POLARVIEW_H 48 | -------------------------------------------------------------------------------- /vna_qt/resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | edit-redo-symbolic.svg 4 | emblem-ok-symbolic.svg 5 | add.svg 6 | xfce-wm-close.svg 7 | xfce-wm-maximize.svg 8 | xfce-wm-unmaximize.svg 9 | 10 | 11 | -------------------------------------------------------------------------------- /vna_qt/touchstone.C: -------------------------------------------------------------------------------- 1 | #define _USE_MATH_DEFINES 2 | #include "touchstone.H" 3 | #include "utility.H" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | 13 | 14 | string serializeTouchstone(vector > data, double startFreqHz, double stepFreqHz) { 15 | scopedCLocale _locale; // use standard number formatting 16 | string res; 17 | res += "# MHz S MA R 50\n"; 18 | saprintf(res,"! freq S11 \n"); 19 | for(int i=0;i<(int)data.size();i++) { 20 | double freqHz = startFreqHz + i*stepFreqHz; 21 | double freqMHz = freqHz*1e-6; 22 | complex val = data[i]; 23 | double c = 180./M_PI; 24 | saprintf(res,"%8.6f %8.5f %7.2f\n", 25 | freqMHz, abs(val), arg(val)*c); 26 | } 27 | return res; 28 | } 29 | 30 | string serializeTouchstone(vector data, double startFreqHz, double stepFreqHz) { 31 | scopedCLocale _locale; // use standard number formatting 32 | string res; 33 | res += "# MHz S MA R 50\n"; 34 | saprintf(res,"! freq S11 S21 S12 S22 \n"); 35 | for(int i=0;i<(int)data.size();i++) { 36 | double freqHz = startFreqHz + i*stepFreqHz; 37 | double freqMHz = freqHz*1e-6; 38 | Matrix2cd val = data[i]; 39 | double c = 180./M_PI; 40 | saprintf(res,"%8.6f %8.5f %7.2f %8.5f %7.2f %8.5f %7.2f %8.5f %7.2f\n", 41 | freqMHz, 42 | abs(val(0,0)), arg(val(0,0))*c, 43 | abs(val(1,0)), arg(val(1,0))*c, 44 | abs(val(0,1)), arg(val(0,1))*c, 45 | abs(val(1,1)), arg(val(1,1))*c); 46 | } 47 | return res; 48 | } 49 | 50 | 51 | void parseTouchstone(string data, int& nPorts, map &results) { 52 | scopedCLocale _locale; // use standard number formatting 53 | istringstream iss(data); 54 | string line; 55 | 56 | double freqMultiplier = 1e9; //GHz by default 57 | char format = 'd'; // d: db-angle; m: mag-angle; r: real-imag 58 | results.clear(); 59 | while (getline(iss, line)) { 60 | // if part (or all) of the line is commented out, remove the comment 61 | int i; 62 | if((i=line.find('!')) != -1) { 63 | line.resize(i); 64 | } 65 | trim(line); 66 | if(line.size() == 0) continue; 67 | // option line 68 | if(startsWith(line, "#")) { 69 | string tmp = line.substr(1); 70 | trim(tmp); 71 | 72 | // to lower case 73 | std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower); 74 | 75 | vector args = split(tmp, ' '); 76 | int state=0; 77 | for(int i=0; i<(int)args.size(); i++) { 78 | if(args[i].size() == 0) continue; 79 | 80 | // expecting impedance value 81 | if(state == 1) { 82 | if(args[i] != "50") throw logic_error("only 50 ohm impedance S parameter files supported: " + line); 83 | state = 0; 84 | continue; 85 | } 86 | if(args[i] == "ghz") freqMultiplier = 1e9; 87 | else if(args[i] == "mhz") freqMultiplier = 1e6; 88 | else if(args[i] == "khz") freqMultiplier = 1e3; 89 | else if(args[i] == "hz") freqMultiplier = 1.; 90 | else if(args[i] == "s") ; 91 | else if(args[i] == "db") format = 'd'; 92 | else if(args[i] == "ma") format = 'm'; 93 | else if(args[i] == "ri") format = 'r'; 94 | else if(args[i] == "r") state = 1; 95 | else { 96 | throw logic_error("unknown keyword \"" + args[i] + "\" in option line: " + line); 97 | } 98 | } 99 | continue; 100 | } 101 | 102 | // data line 103 | i = line.find(' '); 104 | if(i < 0) throw logic_error("bad line in S parameter file: " + line); 105 | string valuesStr = line.substr(i + 1); 106 | 107 | // calculate frequency 108 | double freq = atof(line.substr(0,i).c_str()) * freqMultiplier; 109 | 110 | // set the function for parsing the S parameter values depending on format 111 | function(double a, double b)> processValue; 112 | switch(format) { 113 | case 'd': // db-angle 114 | processValue = [](double a, double b){ 115 | return polar(pow(10., a/20.), b*M_PI/180.); 116 | }; 117 | break; 118 | case 'm': // mag-angle 119 | processValue = [](double a, double b){ 120 | return polar(a, b*M_PI/180.); 121 | }; 122 | break; 123 | case 'r': // real-imag 124 | processValue = [](double a, double b){ 125 | return complex(a,b); 126 | }; 127 | break; 128 | default: assert(false); 129 | } 130 | 131 | // parse the S parameter values 132 | double values[8]; // s11a, s11b, s21a, s21b, s12a, s12b, s22a, s22b; 133 | int ret = sscanf(valuesStr.c_str(), "%lf %lf %lf %lf %lf %lf %lf %lf", 134 | &values[0], &values[1], &values[2], &values[3], 135 | &values[4], &values[5], &values[6], &values[7]); 136 | if(results.size() == 0) { 137 | if(ret == 2) nPorts = 1; 138 | else if(ret == 8) nPorts = 2; 139 | else throw logic_error("bad data line in S parameter file: " + line); 140 | } 141 | Matrix2cd tmp; 142 | if(nPorts == 1) { 143 | if(ret != 2) throw logic_error("bad data line in S parameter file: " + line); 144 | tmp << processValue(values[0], values[1]), 0., 0., 0.; 145 | } else if(nPorts == 2) { 146 | if(ret != 8) throw logic_error("bad data line in S parameter file: " + line); 147 | tmp << processValue(values[0], values[1]), processValue(values[4], values[5]), 148 | processValue(values[2], values[3]), processValue(values[6], values[7]); 149 | } else assert(false); 150 | results[freq] = tmp; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /vna_qt/touchstone.H: -------------------------------------------------------------------------------- 1 | #ifndef TOUCHSTONE_H 2 | #define TOUCHSTONE_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | using namespace Eigen; 10 | 11 | class SParamSeries { 12 | public: 13 | // map from frequency (in Hz) to value 14 | map values; 15 | MatrixXcd interpolate(double freqHz) { 16 | assert(!values.empty()); 17 | 18 | // find the item just right of freqHz 19 | auto it2 = values.lower_bound(freqHz); 20 | 21 | // if there is none, return the last value 22 | if(it2 == values.end()) return (*values.rbegin()).second; 23 | 24 | // if it is the first value, return the first value 25 | if(it2 == values.begin()) return (*it2).second; 26 | 27 | // otherwise interpolate 28 | auto it1 = it2; 29 | it2--; 30 | double freq1 = (*it1).first, freq2 = (*it2).first; 31 | MatrixXcd val1 = (*it1).second, val2 = (*it2).second; 32 | double scale = 1./(freq2-freq1); 33 | return val1*((freq2 - freqHz)*scale) + val2*((freqHz - freq1)*scale); 34 | } 35 | }; 36 | 37 | string serializeTouchstone(vector > data, double startFreqHz, double stepFreqHz); 38 | string serializeTouchstone(vector data, double startFreqHz, double stepFreqHz); 39 | void parseTouchstone(string data, int &nPorts, map& results); 40 | 41 | #endif // TOUCHSTONE_H 42 | -------------------------------------------------------------------------------- /vna_qt/utility.H: -------------------------------------------------------------------------------- 1 | #ifndef UTILITY_H 2 | #define UTILITY_H 3 | #define _USE_MATH_DEFINES 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | #if __cplusplus < 201103L 16 | #error This library needs at least a C++11 compliant compiler 17 | #endif 18 | 19 | using namespace std; 20 | 21 | // when this class is instantiated, the program locale is set to C 22 | class scopedCLocale { 23 | public: 24 | bool _shouldRevert = true; 25 | scopedCLocale() { 26 | if(strcmp("C", setlocale(LC_ALL, NULL)) == 0) 27 | _shouldRevert = false; 28 | setlocale(LC_ALL, "C"); 29 | } 30 | ~scopedCLocale() { 31 | if(_shouldRevert) 32 | setlocale(LC_ALL, ""); 33 | } 34 | }; 35 | 36 | 37 | inline QString qs(const string& s) { 38 | return QString::fromStdString(s); 39 | } 40 | inline double dB(double power) { 41 | if(power == 0.) return -300; 42 | return log10(power)*10; 43 | } 44 | 45 | inline double swr(double power) { 46 | float d = powf(10,(abs(dB(power)))/20); 47 | return (double)fmin(11.0,(d+1)/(d-1)); 48 | } 49 | 50 | // freq is in Hz, Z is in ohms. 51 | // if return value is positive, it is in henries; 52 | // if return value is negative, it is in farads. 53 | inline double capacitance_inductance(double freq, double Z) { 54 | if(Z>0) return Z/(2*M_PI*freq); 55 | return 1./(2*Z*M_PI*freq); 56 | } 57 | // freq is in Hz, Y is in mhos 58 | // if return value is positive, it is in henries; 59 | // if return value is negative, it is in farads. 60 | inline double capacitance_inductance_Y(double freq, double Y) { 61 | if(Y<0) return -1./(2*Y*M_PI*freq); 62 | return -Y/(2*M_PI*freq); 63 | } 64 | inline double si_scale(double val) { 65 | double val2 = fabs(val); 66 | if(val2>1e12) return val*1e-12; 67 | if(val2>1e9) return val*1e-9; 68 | if(val2>1e6) return val*1e-6; 69 | if(val2>1e3) return val*1e-3; 70 | if(val2>1e0) return val; 71 | if(val2>1e-3) return val*1e3; 72 | if(val2>1e-6) return val*1e6; 73 | if(val2>1e-9) return val*1e9; 74 | if(val2>1e-12) return val*1e12; 75 | return val*1e15; 76 | } 77 | inline const char* si_unit(double val) { 78 | val = fabs(val); 79 | if(val>1e12) return "T"; 80 | if(val>1e9) return "G"; 81 | if(val>1e6) return "M"; 82 | if(val>1e3) return "k"; 83 | if(val>1e0) return ""; 84 | if(val>1e-3) return "m"; 85 | if(val>1e-6) return "u"; 86 | if(val>1e-9) return "n"; 87 | if(val>1e-12) return "p"; 88 | return "f"; 89 | } 90 | inline string ssprintf(int maxLen, const char* fmt, ...) { 91 | string tmp(maxLen, '\0'); 92 | va_list args; 93 | va_start(args, fmt); 94 | int len = vsnprintf((char*)tmp.data(), maxLen, fmt, args); 95 | va_end(args); 96 | tmp.resize(len); 97 | return tmp; 98 | } 99 | 100 | // append to dst 101 | inline int saprintf(string& dst, const char* fmt, ...) { 102 | int bytesToAllocate=32; 103 | int originalLen=dst.length(); 104 | while(true) { 105 | dst.resize(originalLen+bytesToAllocate); 106 | va_list args; 107 | va_start(args, fmt); 108 | // ONLY WORKS WITH C++11!!!!!!!! 109 | // .data() does not guarantee enough space for the null byte before c++11 110 | int len = vsnprintf((char*)dst.data()+originalLen, bytesToAllocate+1, fmt, args); 111 | va_end(args); 112 | if(len>=0 && len <= bytesToAllocate) { 113 | dst.resize(originalLen+len); 114 | return len; 115 | } 116 | if(len<=0) bytesToAllocate*=2; 117 | else bytesToAllocate = len; 118 | } 119 | } 120 | 121 | inline string sstrftime(const char *format, const struct tm &tm) { 122 | char buf[256] = {0}; 123 | strftime(buf, 256, format, &tm); 124 | return buf; 125 | } 126 | 127 | 128 | // trim from start (in place) 129 | static inline void ltrim(std::string &s) { 130 | s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { 131 | return !isspace(ch); 132 | })); 133 | } 134 | 135 | // trim from end (in place) 136 | static inline void rtrim(std::string &s) { 137 | s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { 138 | return !isspace(ch); 139 | }).base(), s.end()); 140 | } 141 | 142 | // trim from both ends (in place) 143 | static inline void trim(std::string &s) { 144 | ltrim(s); 145 | rtrim(s); 146 | } 147 | 148 | static inline bool startsWith(string s, string sub) { 149 | if(sub.length() > s.length()) return false; 150 | return s.substr(0, sub.length()) == sub; 151 | } 152 | 153 | template 154 | inline void split(const std::string &s, char delim, Out result) { 155 | std::stringstream ss(s); 156 | std::string item; 157 | while (std::getline(ss, item, delim)) { 158 | *(result++) = item; 159 | } 160 | } 161 | 162 | inline std::vector split(const std::string &s, char delim) { 163 | std::vector elems; 164 | split(s, delim, std::back_inserter(elems)); 165 | return elems; 166 | } 167 | 168 | #endif // UTILITY_H 169 | -------------------------------------------------------------------------------- /vna_qt/vna_qt.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2017-12-16T02:35:03 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui charts 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | 12 | #CONFIG += static 13 | #CONFIG -= import_plugins 14 | 15 | QT += svg 16 | QTPLUGIN.iconengines += svgicon 17 | QTPLUGIN.imageformats += svg 18 | 19 | #QMAKE_LFLAGS += --static -lexpat -lz -lXext -lXau -lbsd -lXdmcp 20 | #QMAKE_LFLAGS += -L../lib -lxavna 21 | QMAKE_CXXFLAGS += -Wextra -std=c++11 22 | QMAKE_CXXFLAGS += -DEIGEN_DONT_VECTORIZE -DEIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT 23 | android: QMAKE_CXXFLAGS += -I../android_include -DANDROID_WORKAROUNDS 24 | 25 | TARGET = vna_qt 26 | TEMPLATE = app 27 | 28 | # The following define makes your compiler emit warnings if you use 29 | # any feature of Qt which as been marked as deprecated (the exact warnings 30 | # depend on your compiler). Please consult the documentation of the 31 | # deprecated API in order to know how to port your code away from it. 32 | DEFINES += QT_DEPRECATED_WARNINGS 33 | 34 | # You can also make your code fail to compile if you use deprecated APIs. 35 | # In order to do so, uncomment the following line. 36 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 37 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 38 | 39 | 40 | SOURCES +=\ 41 | polarview.C \ 42 | mainwindow.C \ 43 | main.C \ 44 | markerslider.C \ 45 | impedancedisplay.C \ 46 | frequencydialog.C \ 47 | graphpanel.C \ 48 | configureviewdialog.C \ 49 | touchstone.C \ 50 | calkitsettingsdialog.C \ 51 | calkitsettings.C \ 52 | networkview.C \ 53 | dtfwindow.C \ 54 | calibrationfinetunedialog.C \ 55 | firmwareupdater.C \ 56 | firmwareupdatedialog.C 57 | 58 | HEADERS += \ 59 | polarview.H \ 60 | mainwindow.H \ 61 | markerslider.H \ 62 | impedancedisplay.H \ 63 | utility.H \ 64 | frequencydialog.H \ 65 | graphpanel.H \ 66 | configureviewdialog.H \ 67 | touchstone.H \ 68 | calkitsettingsdialog.H \ 69 | calkitsettings.H \ 70 | networkview.H \ 71 | dtfwindow.H \ 72 | calibrationfinetunedialog.H \ 73 | firmwareupdater.H \ 74 | firmwareupdatedialog.H 75 | 76 | FORMS += mainwindow.ui \ 77 | markerslider.ui \ 78 | impedancedisplay.ui \ 79 | frequencydialog.ui \ 80 | graphpanel.ui \ 81 | configureviewdialog.ui \ 82 | calkitsettingsdialog.ui \ 83 | calkitsettingswidget.ui \ 84 | dtfwindow.ui \ 85 | graphlimitsdialog.ui \ 86 | calibrationfinetunedialog.ui \ 87 | firmwareupdatedialog.ui 88 | 89 | TRANSLATIONS = languages/vna_qt_zh.ts 90 | DISTFILES += languages/vna_qt_zh.ts 91 | 92 | RESOURCES += \ 93 | resources.qrc 94 | 95 | LIBS += -L$$PWD/../libxavna/.libs/ -L/usr/local/lib/ -lxavna -lfftw3 -lpthread 96 | android: LIBS += -L$$PWD/../lib 97 | 98 | win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../libxavna/xavna_mock_ui/release/ -lxavna_mock_ui 99 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../libxavna/xavna_mock_ui/debug/ -lxavna_mock_ui 100 | else:unix: LIBS += -L$$PWD/../libxavna/xavna_mock_ui/ -lxavna_mock_ui 101 | 102 | INCLUDEPATH += $$PWD/../include /usr/local/include 103 | DEPENDPATH += $$PWD/../include 104 | 105 | #INCLUDEPATH += ../libxavna/xavna_mock_ui 106 | #PRE_TARGETDEPS += ../libxavna/xavna_mock_ui/libxavna_mock_ui.so 107 | 108 | contains(ANDROID_TARGET_ARCH,armeabi-v7a) { 109 | ANDROID_EXTRA_LIBS = \ 110 | /persist/vna/vna_qt/../libxavna/.libs/libxavna.so \ 111 | $$PWD/../libxavna/xavna_mock_ui/libxavna_mock_ui.so 112 | } 113 | -------------------------------------------------------------------------------- /vna_qt/xfce-wm-close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | Title 51 | 52 | 53 | Olivier Fourdan 54 | 55 | 56 | 57 | 58 | 59 | 64 | 67 | 71 | 76 | 81 | 82 | 87 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /vna_qt/xfce-wm-maximize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | Title 51 | 52 | 53 | Olivier Fourdan 54 | 55 | 56 | 57 | 58 | 59 | 64 | 68 | 73 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /vna_qt/xfce-wm-unmaximize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | Title 51 | 52 | 53 | Olivier Fourdan 54 | 55 | 56 | 57 | 58 | 59 | 64 | 68 | 73 | 78 | 83 | 84 | 85 | 86 | --------------------------------------------------------------------------------